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:
parent
e4f2ddd531
commit
78c099669b
@ -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>;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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 () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user