From 78c099669b499876ccfad526db789bfd5ebec941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Thu, 17 Mar 2022 12:48:49 +0100 Subject: [PATCH] feat(utils): return used props applied to the svg --- packages/utils/src/loader/types.ts | 4 +- packages/utils/src/loader/utils.ts | 84 +++++++++----------- packages/utils/tests/get-custom-icon-test.ts | 18 ++++- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/packages/utils/src/loader/types.ts b/packages/utils/src/loader/types.ts index 2a00ee1..237d0ca 100644 --- a/packages/utils/src/loader/types.ts +++ b/packages/utils/src/loader/types.ts @@ -142,7 +142,9 @@ export type IconifyLoaderOptions = { autoInstall?: boolean; /** - * Holder to return the properties added to the svg. + * Holder to include the properties added to the svg. + * + * If you need that properties just add an empty object here, usefull for example when using it on `CSS`. */ usedProps?: Record; }; diff --git a/packages/utils/src/loader/utils.ts b/packages/utils/src/loader/utils.ts index 35a7a59..9b7a260 100644 --- a/packages/utils/src/loader/utils.ts +++ b/packages/utils/src/loader/utils.ts @@ -1,39 +1,39 @@ import type { Awaitable } from '@antfu/utils'; import type { IconifyLoaderOptions } from './types'; -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec -/* -const svgWidthRegex = /(width\s*=\s*["'](\w+)["'])/d -const svgHeightRegex = /(height\s*=\s*["'](\w+)["'])/d +const svgWidthRegex = /width\s*=\s*["'](\w+)["']/; +const svgHeightRegex = /height\s*=\s*["'](\w+)["']/; -function configureSvgSize(svg: string, props: Record, scale: number) { - if (props.width && props.height) { - return; +function configureSvgSize( + svg: string, + props: Record, + scale?: number +): [boolean, boolean] { + const svgNode = svg.slice(0, svg.indexOf('>')); + + let result = svgWidthRegex.exec(svgNode); + const w = result != null; + if (typeof props.width === 'undefined' || props.width === null) { + if (typeof scale === 'number') { + props.width = `${scale}em`; + } else if (result) { + props.width = result[1]; + } } - const svgNode = svg.slice(0, svg.indexOf('>')) - let height: string | undefined - let width: string | undefined - - let result = svgWidthRegex.exec(svgNode) - if (result) { - - } - if (!width) { - width = props.widht ?? `${scale}em` - } - - result = svgHeightRegex.exec(svgNode) - if (result) { - - } - if (!height) { - height = props.height ?? `${scale}em` + result = svgHeightRegex.exec(svgNode); + const h = result != null; + if (typeof props.height === 'undefined' || props.height === null) { + if (typeof scale === 'number') { + props.height = `${scale}em`; + } else if (result) { + props.height = result[1]; + } } + return [w, h]; } -*/ export async function mergeIconProps( svg: string, collection: string, @@ -45,19 +45,6 @@ export async function mergeIconProps( const { additionalProps = {}, iconCustomizer } = options?.customizations ?? {}; const props: Record = (await propsProvider?.()) ?? {}; - if ( - !svg.includes(' width=') && - !svg.includes(' height=') && - typeof scale === 'number' - ) { - if ( - (typeof props.width === 'undefined' || props.width === null) && - (typeof props.height === 'undefined' || props.height === null) - ) { - props.width = `${scale}em`; - props.height = `${scale}em`; - } - } await iconCustomizer?.(collection, icon, props); Object.keys(additionalProps).forEach((p) => { @@ -65,12 +52,7 @@ export async function mergeIconProps( if (v !== undefined && v !== null) props[p] = v; }); - const addUsedProps = options && options.usedProps; - // we need to parse the svg if we need to also return used props - // and there are no width nor height in the props - // if (addUsedProps) { - // if (typeof props.width === 'undefined' || props.width === null) - // } + const [widthOnSvg, heightOnSvg] = configureSvgSize(svg, props, scale); // add xml namespaces if necessary if (addXmlNs) { @@ -91,7 +73,12 @@ export async function mergeIconProps( svg = svg.replace( ' `${p}="${props[p]}"`) + .map((p) => + (p === 'width' && widthOnSvg) || (p === 'height' && heightOnSvg) + ? null + : `${p}="${props[p]}"` + ) + .filter((p) => p != null) .join(' ')}` ); @@ -107,8 +94,8 @@ export async function mergeIconProps( } } - if (addUsedProps) { - options!.usedProps = Object.keys(props).reduce((acc, k) => { + if (options && options.usedProps) { + options.usedProps = Object.keys(props).reduce((acc, k) => { if (k) { switch (k) { case 'scale': @@ -122,6 +109,7 @@ export async function mergeIconProps( } return acc; }, {} as Record); + console.log(options.usedProps); } return svg; diff --git a/packages/utils/tests/get-custom-icon-test.ts b/packages/utils/tests/get-custom-icon-test.ts index 7e4e906..2ac2e34 100644 --- a/packages/utils/tests/get-custom-icon-test.ts +++ b/packages/utils/tests/get-custom-icon-test.ts @@ -1,5 +1,6 @@ import { promises as fs } from 'fs'; import { getCustomIcon } from '../lib'; +import { IconifyLoaderOptions } from '../src'; const fixturesDir = './tests/fixtures'; @@ -10,10 +11,15 @@ describe('Testing getCustomIcon', () => { expect(svg).toEqual(result); }); - test('CustomIconLoader with transform', async () => { + test("CustomIconLoader with transform: scale/width/height shouldn't take effect", async () => { const svg = await fs.readFile(fixturesDir + '/circle.svg', 'utf8'); - const result = await getCustomIcon(() => svg, 'a', 'b', { + const options: IconifyLoaderOptions = { + scale: 2, customizations: { + additionalProps: { + width: '4em', + height: '4em', + }, transform(icon) { return icon.replace( ' { ); }, }, - }); + usedProps: {}, + }; + const result = await getCustomIcon(() => svg, 'a', 'b', options); expect(result && result.indexOf('width="1em"') > -1).toBeTruthy(); expect(result && result.indexOf('height="1em"') > -1).toBeTruthy(); + expect(options.usedProps).toHaveProperty('width'); + expect(options.usedProps).toHaveProperty('height'); + expect(options.usedProps.width).toEqual('4em'); + expect(options.usedProps.height).toEqual('4em'); }); test('Icon with XML heading', async () => {