diff --git a/packages/iconify/src/render/bg.ts b/packages/iconify/src/render/bg.ts index f3c43b3..55b9f64 100644 --- a/packages/iconify/src/render/bg.ts +++ b/packages/iconify/src/render/bg.ts @@ -1,5 +1,6 @@ import type { FullIconifyIcon } from '@iconify/utils/lib/icon'; import { iconToSVG } from '@iconify/utils/lib/svg/build'; +import { iconToHTML } from '@iconify/utils/lib/svg/html'; import { elementDataProperty, IconifyElement, @@ -7,7 +8,6 @@ import { IconifyElementData, } from '../scanner/config'; import { applyClasses, iconClasses } from './classes'; -import { generateHTML } from './html'; import { applyStyle } from './style'; const commonProps: Record = { @@ -58,12 +58,11 @@ export function renderBackground( const oldData = element[elementDataProperty]; // Generate SVG - const svgAttribs: Record = { + const html = iconToHTML(renderData.body, { ...renderAttribs, - }; - svgAttribs.width = iconData.width.toString(); - svgAttribs.height = iconData.height.toString(); - const html = generateHTML(svgAttribs, renderData.body); + width: iconData.width + '', + height: iconData.height + '', + }); // Add classes const classesToAdd = iconClasses(props.icon); diff --git a/packages/iconify/src/render/html.ts b/packages/iconify/src/render/html.ts deleted file mode 100644 index 51537f6..0000000 --- a/packages/iconify/src/render/html.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Generate HTML - */ -export function generateHTML( - props: Record, - body: string -): string { - let renderAttribsHTML = ''; - for (const attr in props) { - renderAttribsHTML += ' ' + attr + '="' + props[attr] + '"'; - } - return ( - '' + - body + - '' - ); -} diff --git a/packages/iconify/src/render/svg.ts b/packages/iconify/src/render/svg.ts index f7ec7e8..149a8b5 100644 --- a/packages/iconify/src/render/svg.ts +++ b/packages/iconify/src/render/svg.ts @@ -1,6 +1,7 @@ import type { FullIconifyIcon } from '@iconify/utils/lib/icon'; import { iconToSVG } from '@iconify/utils/lib/svg/build'; import { replaceIDs } from '@iconify/utils/lib/svg/id'; +import { iconToHTML } from '@iconify/utils/lib/svg/html'; import { elementDataProperty, IconifyElement, @@ -8,7 +9,6 @@ import { IconifyElementData, } from '../scanner/config'; import { applyClasses, iconClasses } from './classes'; -import { generateHTML } from './html'; import { applyStyle } from './style'; /** @@ -34,14 +34,11 @@ export function renderInlineSVG( const oldData = element[elementDataProperty]; // Generate SVG - const html = generateHTML( - { - 'aria-hidden': 'true', - 'role': 'img', - ...renderData.attributes, - }, - replaceIDs(renderData.body) - ); + const html = iconToHTML(replaceIDs(renderData.body), { + 'aria-hidden': 'true', + 'role': 'img', + ...renderData.attributes, + }); span.innerHTML = html; // Get SVG element diff --git a/packages/iconify/tests/element-props-test.ts b/packages/iconify/tests/element-props-test.ts index d61cba2..986dd11 100644 --- a/packages/iconify/tests/element-props-test.ts +++ b/packages/iconify/tests/element-props-test.ts @@ -27,6 +27,10 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + // Value is null because that is what getAttribute() returns, but type and value are not + // checked because it does not actually matter. In render it compares to string, any other + // value is considered to be automatic mode + mode: null, }); // More complex name @@ -42,6 +46,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); expect(propsChanged(props1, props2)).toBe(true); @@ -58,6 +63,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); expect(propsChanged(props1, props3)).toBe(true); expect(propsChanged(props2, props3)).toBe(true); @@ -88,6 +94,7 @@ describe('Testing element properties', () => { ...defaults, inline: false, }, + mode: null, }); // Inline: set via attribute @@ -100,6 +107,7 @@ describe('Testing element properties', () => { ...defaults, inline: true, }, + mode: null, }); expect(propsChanged(props1Block, props2Inline)).toBe(true); @@ -113,6 +121,7 @@ describe('Testing element properties', () => { ...defaults, inline: false, }, + mode: null, }); expect(propsChanged(props1Block, props3Block)).toBe(false); @@ -127,6 +136,7 @@ describe('Testing element properties', () => { ...defaults, inline: true, }, + mode: null, }); expect(propsChanged(props1Block, props4Inline)).toBe(true); expect(propsChanged(props2Inline, props4Inline)).toBe(false); @@ -140,6 +150,7 @@ describe('Testing element properties', () => { ...defaults, inline: false, }, + mode: null, }); // Inline: set via attribute, overriding class @@ -152,6 +163,7 @@ describe('Testing element properties', () => { ...defaults, inline: true, }, + mode: null, }); // Block: set via attribute, overriding class @@ -164,6 +176,7 @@ describe('Testing element properties', () => { ...defaults, inline: false, }, + mode: null, }); }); @@ -188,6 +201,7 @@ describe('Testing element properties', () => { width: null, height: null, }, + mode: null, }); // Set width @@ -200,6 +214,7 @@ describe('Testing element properties', () => { width: '200', height: null, }, + mode: null, }); // Set height @@ -212,6 +227,7 @@ describe('Testing element properties', () => { width: '200', height: '1em', }, + mode: null, }); // Empty width @@ -224,6 +240,7 @@ describe('Testing element properties', () => { width: null, height: '1em', }, + mode: null, }); }); @@ -247,6 +264,7 @@ describe('Testing element properties', () => { ...defaults, rotate: 0, }, + mode: null, }); // 90deg @@ -258,6 +276,7 @@ describe('Testing element properties', () => { ...defaults, rotate: 1, }, + mode: null, }); // 180deg @@ -269,6 +288,7 @@ describe('Testing element properties', () => { ...defaults, rotate: 2, }, + mode: null, }); // 270deg @@ -280,6 +300,7 @@ describe('Testing element properties', () => { ...defaults, rotate: 3, }, + mode: null, }); // 270deg @@ -291,6 +312,7 @@ describe('Testing element properties', () => { ...defaults, rotate: 3, }, + mode: null, }); // Invalid values or 0 deg @@ -301,6 +323,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); element.setAttribute('data-rotate', '360deg'); @@ -310,6 +333,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); element.setAttribute('data-rotate', 'true'); @@ -319,6 +343,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); element.setAttribute('data-rotate', '-100%'); @@ -328,6 +353,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); }); @@ -352,6 +378,7 @@ describe('Testing element properties', () => { hFlip: false, vFlip: false, }, + mode: null, }); // Horizontal @@ -363,6 +390,7 @@ describe('Testing element properties', () => { ...defaults, hFlip: true, }, + mode: null, }); // Both @@ -375,6 +403,7 @@ describe('Testing element properties', () => { hFlip: true, vFlip: true, }, + mode: null, }); // Vertical @@ -387,6 +416,7 @@ describe('Testing element properties', () => { ...defaults, vFlip: true, }, + mode: null, }); // Overwriting shorthand attr @@ -398,6 +428,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); // Both @@ -411,6 +442,7 @@ describe('Testing element properties', () => { hFlip: true, vFlip: true, }, + mode: null, }); // None @@ -422,6 +454,7 @@ describe('Testing element properties', () => { customisations: { ...defaults, }, + mode: null, }); }); @@ -447,6 +480,7 @@ describe('Testing element properties', () => { vAlign: 'middle', slice: false, }, + mode: null, }); // Horizontal @@ -458,6 +492,7 @@ describe('Testing element properties', () => { ...defaults, hAlign: 'left', }, + mode: null, }); element.setAttribute('data-align', 'right,meet'); @@ -468,6 +503,7 @@ describe('Testing element properties', () => { ...defaults, hAlign: 'right', }, + mode: null, }); // Vertical, slice @@ -480,6 +516,7 @@ describe('Testing element properties', () => { vAlign: 'top', slice: true, }, + mode: null, }); // Overrides, spaces @@ -495,6 +532,7 @@ describe('Testing element properties', () => { hAlign: 'right', slice: true, }, + mode: null, }); }); }); diff --git a/packages/iconify/tests/observing-changes-test.ts b/packages/iconify/tests/observing-changes-test.ts index 2a0236b..3d3907c 100644 --- a/packages/iconify/tests/observing-changes-test.ts +++ b/packages/iconify/tests/observing-changes-test.ts @@ -62,7 +62,7 @@ describe('Observing DOM changes', () => { // Check HTML expect(document.body.innerHTML).toBe( - `` + `` ); const svg = document.body.childNodes[0] as SVGSVGElement; const svgData = svg[elementDataProperty]; @@ -77,7 +77,7 @@ describe('Observing DOM changes', () => { () => document.body.innerHTML.indexOf('transform=') !== -1 ); expect(document.body.innerHTML).toBe( - `` + `` ); }); @@ -142,7 +142,7 @@ describe('Observing DOM changes', () => { // Check HTML expect(document.body.innerHTML).toBe( - `` + `` ); const svg = document.body.childNodes[0] as SVGSVGElement; const svgData = svg[elementDataProperty]; @@ -157,7 +157,7 @@ describe('Observing DOM changes', () => { // SVG should not have been replaced yet, but data should match new icon expect(document.body.innerHTML).toBe( - `` + `` ); expect(document.body.childNodes[0]).toBe(svg); expect(svgData.status).toBe('loading'); @@ -172,7 +172,7 @@ describe('Observing DOM changes', () => { ); expect(document.body.innerHTML).toBe( - `` + `` ); }); @@ -285,7 +285,7 @@ describe('Observing DOM changes', () => { ); expect(document.body.innerHTML).toBe( - `` + `` ); }); }); diff --git a/packages/iconify/tests/re-render-node-test.ts b/packages/iconify/tests/re-render-node-test.ts index 2d5b404..09dbf31 100644 --- a/packages/iconify/tests/re-render-node-test.ts +++ b/packages/iconify/tests/re-render-node-test.ts @@ -77,7 +77,7 @@ describe('Testing re-rendering nodes', () => { width: 24, height: 24, }, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -94,7 +94,7 @@ describe('Testing re-rendering nodes', () => { height: 32, }; }, - '' + '' ); const data = svg[elementDataProperty]; @@ -113,7 +113,7 @@ describe('Testing re-rendering nodes', () => { const svg = await testIcon( '', iconData, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -125,7 +125,7 @@ describe('Testing re-rendering nodes', () => { return iconData; }, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -137,7 +137,7 @@ describe('Testing re-rendering nodes', () => { return iconData; }, - '' + '' ); const data = svg[elementDataProperty]; @@ -156,7 +156,7 @@ describe('Testing re-rendering nodes', () => { const svg = await testIcon( '', iconData, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -168,7 +168,7 @@ describe('Testing re-rendering nodes', () => { return iconData; }, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -180,7 +180,7 @@ describe('Testing re-rendering nodes', () => { return iconData; }, - '' + '' ); const data = svg[elementDataProperty]; @@ -197,7 +197,7 @@ describe('Testing re-rendering nodes', () => { width: 24, height: 24, }, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -214,7 +214,7 @@ describe('Testing re-rendering nodes', () => { height: 32, }; }, - '', + '', (svg) => { const data = svg[elementDataProperty]; expect(data.status).toBe('loaded'); @@ -229,7 +229,7 @@ describe('Testing re-rendering nodes', () => { body: '', }; }, - '' + '' ); const data = svg[elementDataProperty]; diff --git a/packages/iconify/tests/render-bg-test.ts b/packages/iconify/tests/render-bg-test.ts index 87e8789..a77beb5 100644 --- a/packages/iconify/tests/render-bg-test.ts +++ b/packages/iconify/tests/render-bg-test.ts @@ -59,7 +59,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; @@ -76,7 +76,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; @@ -96,7 +96,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; @@ -113,7 +113,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; @@ -130,7 +130,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; @@ -154,7 +154,7 @@ describe('Testing rendering nodes as background', () => { width: 24, height: 24, }, - `` + `` ); const data = svg[elementDataProperty]; diff --git a/packages/iconify/tests/render-node-test.ts b/packages/iconify/tests/render-node-test.ts index 37eda4f..e708790 100644 --- a/packages/iconify/tests/render-node-test.ts +++ b/packages/iconify/tests/render-node-test.ts @@ -47,7 +47,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; @@ -64,7 +64,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; @@ -81,7 +81,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; @@ -98,7 +98,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; @@ -115,7 +115,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; @@ -136,7 +136,7 @@ describe('Testing rendering nodes', () => { width: 24, height: 24, }, - '' + '' ); const data = svg[elementDataProperty]; diff --git a/packages/iconify/tests/scan-dom-test.ts b/packages/iconify/tests/scan-dom-test.ts index d22e6e2..3f54967 100644 --- a/packages/iconify/tests/scan-dom-test.ts +++ b/packages/iconify/tests/scan-dom-test.ts @@ -51,7 +51,7 @@ describe('Scanning DOM', () => { // Check HTML expect(document.body.innerHTML).toBe( - `` + `` ); const svg = document.body.childNodes[0]; const svgData = svg[elementDataProperty]; @@ -110,7 +110,7 @@ describe('Scanning DOM', () => { // Check HTML expect(document.body.innerHTML).toBe( - `` + `` ); const svg = document.body.childNodes[0]; const svgData = svg[elementDataProperty]; diff --git a/packages/utils/package.json b/packages/utils/package.json index f23e1e1..225e02e 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -187,6 +187,10 @@ "require": "./lib/svg/encode-svg-for-css.cjs", "import": "./lib/svg/encode-svg-for-css.mjs" }, + "./lib/svg/html": { + "require": "./lib/svg/html.cjs", + "import": "./lib/svg/html.mjs" + }, "./lib/svg/id": { "require": "./lib/svg/id.cjs", "import": "./lib/svg/id.mjs" diff --git a/packages/utils/src/svg/html.ts b/packages/utils/src/svg/html.ts new file mode 100644 index 0000000..b8a4de3 --- /dev/null +++ b/packages/utils/src/svg/html.ts @@ -0,0 +1,22 @@ +/** + * Generate + */ +export function iconToHTML( + body: string, + attributes: Record +): string { + let renderAttribsHTML = + body.indexOf('xlink:') === -1 + ? '' + : ' xmlns:xlink="http://www.w3.org/1999/xlink"'; + for (const attr in attributes) { + renderAttribsHTML += ' ' + attr + '="' + attributes[attr] + '"'; + } + return ( + '' + + body + + '' + ); +} diff --git a/packages/utils/tests/svg-build-test.ts b/packages/utils/tests/svg-build-test.ts index ce4b8e7..1fb2363 100644 --- a/packages/utils/tests/svg-build-test.ts +++ b/packages/utils/tests/svg-build-test.ts @@ -4,6 +4,7 @@ import type { FullIconifyIcon } from '../lib/icon'; import { fullIcon, iconDefaults } from '../lib/icon'; import type { FullIconCustomisations } from '../lib/customisations'; import { defaults, mergeCustomisations } from '../lib/customisations'; +import { iconToHTML } from '../lib/svg/html'; describe('Testing iconToSVG', () => { test('Empty icon', () => { @@ -21,6 +22,12 @@ describe('Testing iconToSVG', () => { const result = iconToSVG(icon, custom); expect(result).toEqual(expected); + + // Test HTML + const html = iconToHTML(result.body, result.attributes); + expect(html).toBe( + '' + ); }); test('Auto size, inline, body', () => { @@ -44,6 +51,20 @@ describe('Testing iconToSVG', () => { const result = iconToSVG(icon, custom); expect(result).toEqual(expected); + + // Test HTML + const htmlProps: Record = { + 'aria-hidden': 'true', + 'role': 'img', + ...result.attributes, + }; + if (result.inline) { + htmlProps['style'] = 'vertical-align: -0.125em;'; + } + const html = iconToHTML(result.body, htmlProps); + expect(html).toBe( + '' + ); }); test('Auto size, inline, body', () => {