2
0
mirror of https://github.com/iconify/iconify.git synced 2024-11-09 23:00:56 +00:00

feat(utils): return used props applied to the svg

This commit is contained in:
Joaquín Sánchez Jiménez 2022-03-17 12:48:49 +01:00
parent e4f2ddd531
commit 78c099669b
3 changed files with 54 additions and 52 deletions

View File

@ -142,7 +142,9 @@ export type IconifyLoaderOptions = {
autoInstall?: boolean; 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<string, string>; usedProps?: Record<string, string>;
}; };

View File

@ -1,39 +1,39 @@
import type { Awaitable } from '@antfu/utils'; import type { Awaitable } from '@antfu/utils';
import type { IconifyLoaderOptions } from './types'; 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+)["']/;
/* const svgHeightRegex = /height\s*=\s*["'](\w+)["']/;
const svgWidthRegex = /(width\s*=\s*["'](\w+)["'])/d
const svgHeightRegex = /(height\s*=\s*["'](\w+)["'])/d
function configureSvgSize(svg: string, props: Record<string, string>, scale: number) { function configureSvgSize(
if (props.width && props.height) { svg: string,
return; props: Record<string, string>,
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('>')) result = svgHeightRegex.exec(svgNode);
let height: string | undefined const h = result != null;
let width: string | undefined if (typeof props.height === 'undefined' || props.height === null) {
if (typeof scale === 'number') {
let result = svgWidthRegex.exec(svgNode) props.height = `${scale}em`;
if (result) { } else if (result) {
props.height = result[1];
} }
if (!width) {
width = props.widht ?? `${scale}em`
}
result = svgHeightRegex.exec(svgNode)
if (result) {
}
if (!height) {
height = props.height ?? `${scale}em`
} }
return [w, h];
} }
*/
export async function mergeIconProps( export async function mergeIconProps(
svg: string, svg: string,
collection: string, collection: string,
@ -45,19 +45,6 @@ export async function mergeIconProps(
const { additionalProps = {}, iconCustomizer } = const { additionalProps = {}, iconCustomizer } =
options?.customizations ?? {}; options?.customizations ?? {};
const props: Record<string, string> = (await propsProvider?.()) ?? {}; const props: Record<string, string> = (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); await iconCustomizer?.(collection, icon, props);
Object.keys(additionalProps).forEach((p) => { Object.keys(additionalProps).forEach((p) => {
@ -65,12 +52,7 @@ export async function mergeIconProps(
if (v !== undefined && v !== null) props[p] = v; if (v !== undefined && v !== null) props[p] = v;
}); });
const addUsedProps = options && options.usedProps; const [widthOnSvg, heightOnSvg] = configureSvgSize(svg, props, scale);
// 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)
// }
// add xml namespaces if necessary // add xml namespaces if necessary
if (addXmlNs) { if (addXmlNs) {
@ -91,7 +73,12 @@ export async function mergeIconProps(
svg = svg.replace( svg = svg.replace(
'<svg ', '<svg ',
`<svg ${Object.keys(props) `<svg ${Object.keys(props)
.map((p) => `${p}="${props[p]}"`) .map((p) =>
(p === 'width' && widthOnSvg) || (p === 'height' && heightOnSvg)
? null
: `${p}="${props[p]}"`
)
.filter((p) => p != null)
.join(' ')}` .join(' ')}`
); );
@ -107,8 +94,8 @@ export async function mergeIconProps(
} }
} }
if (addUsedProps) { if (options && options.usedProps) {
options!.usedProps = Object.keys(props).reduce((acc, k) => { options.usedProps = Object.keys(props).reduce((acc, k) => {
if (k) { if (k) {
switch (k) { switch (k) {
case 'scale': case 'scale':
@ -122,6 +109,7 @@ export async function mergeIconProps(
} }
return acc; return acc;
}, {} as Record<string, string>); }, {} as Record<string, string>);
console.log(options.usedProps);
} }
return svg; return svg;

View File

@ -1,5 +1,6 @@
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { getCustomIcon } from '../lib'; import { getCustomIcon } from '../lib';
import { IconifyLoaderOptions } from '../src';
const fixturesDir = './tests/fixtures'; const fixturesDir = './tests/fixtures';
@ -10,10 +11,15 @@ describe('Testing getCustomIcon', () => {
expect(svg).toEqual(result); 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 svg = await fs.readFile(fixturesDir + '/circle.svg', 'utf8');
const result = await getCustomIcon(() => svg, 'a', 'b', { const options: IconifyLoaderOptions = {
scale: 2,
customizations: { customizations: {
additionalProps: {
width: '4em',
height: '4em',
},
transform(icon) { transform(icon) {
return icon.replace( return icon.replace(
'<svg ', '<svg ',
@ -21,9 +27,15 @@ describe('Testing getCustomIcon', () => {
); );
}, },
}, },
}); usedProps: {},
};
const result = await getCustomIcon(() => svg, 'a', 'b', options);
expect(result && result.indexOf('width="1em"') > -1).toBeTruthy(); expect(result && result.indexOf('width="1em"') > -1).toBeTruthy();
expect(result && result.indexOf('height="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 () => { test('Icon with XML heading', async () => {