mirror of
https://github.com/iconify/iconify.git
synced 2024-11-09 14:50:56 +00:00
feat(utils): support removing width and height attributes in generated icon
This commit is contained in:
parent
a3732f627a
commit
d3f52d44fa
@ -1,5 +1,5 @@
|
||||
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
|
||||
import { iconToSVG } from '../svg/build';
|
||||
import { iconToSVG, isUnsetKeyword } from '../svg/build';
|
||||
import { getIconData } from '../icon-set/get-icon';
|
||||
import { mergeIconProps } from './utils';
|
||||
import createDebugger from 'debug';
|
||||
@ -39,26 +39,40 @@ export async function searchForIcon(
|
||||
return { ...restAttributes };
|
||||
},
|
||||
(props) => {
|
||||
if (
|
||||
typeof props.width === 'undefined' ||
|
||||
props.width === null
|
||||
) {
|
||||
if (typeof scale === 'number') {
|
||||
props.width = `${scale}em`;
|
||||
} else {
|
||||
props.width = width;
|
||||
// Check if value has 'unset' keyword
|
||||
const check = (
|
||||
prop: 'width' | 'height',
|
||||
defaultValue: string | undefined
|
||||
) => {
|
||||
const propValue = props[prop];
|
||||
let value: string | undefined;
|
||||
|
||||
if (!isUnsetKeyword(propValue)) {
|
||||
if (propValue) {
|
||||
// Do not change it
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof scale === 'number') {
|
||||
// Scale icon, unless scale is 0
|
||||
if (scale) {
|
||||
value = `${scale}em`;
|
||||
}
|
||||
} else {
|
||||
// Use result from iconToSVG()
|
||||
value = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
typeof props.height === 'undefined' ||
|
||||
props.height === null
|
||||
) {
|
||||
if (typeof scale === 'number') {
|
||||
props.height = `${scale}em`;
|
||||
|
||||
// Change / unset
|
||||
if (!value) {
|
||||
delete props[prop];
|
||||
} else {
|
||||
props.height = height;
|
||||
props[prop] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
check('width', width);
|
||||
check('height', height);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { Awaitable } from '@antfu/utils';
|
||||
import { isUnsetKeyword } from '../svg/build';
|
||||
import type { IconifyLoaderOptions } from './types';
|
||||
|
||||
const svgWidthRegex = /width\s*=\s*["'](\w+)["']/;
|
||||
@ -12,27 +13,40 @@ function configureSvgSize(
|
||||
): [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 check = (prop: 'width' | 'height', regex: RegExp): boolean => {
|
||||
const result = regex.exec(svgNode);
|
||||
const w = result != null;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
const propValue = props[prop];
|
||||
let value: string | undefined;
|
||||
|
||||
return [w, h];
|
||||
if (!isUnsetKeyword(propValue)) {
|
||||
if (propValue) {
|
||||
// Do not change it
|
||||
return w;
|
||||
}
|
||||
|
||||
if (typeof scale === 'number') {
|
||||
// Scale icon, unless scale is 0
|
||||
if (scale) {
|
||||
value = `${scale}em`;
|
||||
}
|
||||
} else if (result) {
|
||||
// Use result from iconToSVG()
|
||||
value = result[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Change / unset
|
||||
if (!value) {
|
||||
delete props[prop];
|
||||
return false;
|
||||
}
|
||||
props[prop] = value;
|
||||
return true;
|
||||
};
|
||||
|
||||
return [check('width', svgWidthRegex), check('height', svgHeightRegex)];
|
||||
}
|
||||
|
||||
export async function mergeIconProps(
|
||||
|
@ -11,8 +11,8 @@ import { calculateSize } from './size';
|
||||
export interface IconifyIconBuildResult {
|
||||
attributes: {
|
||||
// Attributes for <svg>
|
||||
width: string;
|
||||
height: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
viewBox: string;
|
||||
};
|
||||
|
||||
@ -30,6 +30,12 @@ interface ViewBox {
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if value should be unset. Allows multiple keywords
|
||||
*/
|
||||
export const isUnsetKeyword = (value: unknown) =>
|
||||
value === 'unset' || value === 'undefined' || value === 'none';
|
||||
|
||||
/**
|
||||
* Get SVG attributes and content from icon + customisations
|
||||
*
|
||||
@ -194,22 +200,28 @@ export function iconToSVG(
|
||||
: customisationsHeight;
|
||||
}
|
||||
|
||||
// Result
|
||||
const result: IconifyIconBuildResult = {
|
||||
attributes: {
|
||||
width: width.toString(),
|
||||
height: height.toString(),
|
||||
viewBox:
|
||||
box.left.toString() +
|
||||
' ' +
|
||||
box.top.toString() +
|
||||
' ' +
|
||||
boxWidth.toString() +
|
||||
' ' +
|
||||
boxHeight.toString(),
|
||||
},
|
||||
// Attributes for result
|
||||
const attributes = {} as IconifyIconBuildResult['attributes'];
|
||||
|
||||
const setAttr = (prop: 'width' | 'height', value: string | number) => {
|
||||
if (!isUnsetKeyword(value)) {
|
||||
attributes[prop] = value.toString();
|
||||
}
|
||||
};
|
||||
setAttr('width', width);
|
||||
setAttr('height', height);
|
||||
|
||||
attributes.viewBox =
|
||||
box.left.toString() +
|
||||
' ' +
|
||||
box.top.toString() +
|
||||
' ' +
|
||||
boxWidth.toString() +
|
||||
' ' +
|
||||
boxHeight.toString();
|
||||
|
||||
return {
|
||||
attributes,
|
||||
body,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -86,4 +86,40 @@ describe('Testing loadIcon with @iconify-json/flat-color-icons>', () => {
|
||||
expect(result && result.includes('width="1.2em"')).toBeTruthy();
|
||||
expect(result && result.includes('height="1.2em"')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('loadIcon with unset width', async () => {
|
||||
const result = await loadNodeIcon('flat-color-icons', 'up-right', {
|
||||
customizations: {
|
||||
additionalProps: {
|
||||
width: 'unset',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
expect(result && result.includes('width="')).toBeFalsy();
|
||||
expect(result && result.includes('height="1em"')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('loadIcon with 0 scale', async () => {
|
||||
const result = await loadNodeIcon('flat-color-icons', 'up-right', {
|
||||
scale: 0,
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
expect(result && result.includes('width="')).toBeFalsy();
|
||||
expect(result && result.includes('height="')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('loadIcon with 0 scale and custom height', async () => {
|
||||
const result = await loadNodeIcon('flat-color-icons', 'up-right', {
|
||||
scale: 0,
|
||||
customizations: {
|
||||
additionalProps: {
|
||||
height: '1em',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
expect(result && result.includes('width="')).toBeFalsy();
|
||||
expect(result && result.includes('height="1em"')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -99,6 +99,51 @@ describe('Testing iconToSVG', () => {
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
test('Unset height', () => {
|
||||
const custom: IconifyIconCustomisations = {
|
||||
// Testing 'unset' keyword
|
||||
height: 'unset',
|
||||
width: 'auto',
|
||||
};
|
||||
const icon: IconifyIcon = {
|
||||
width: 20,
|
||||
height: 16,
|
||||
body: '<path d="..." />',
|
||||
};
|
||||
const expected: IconifyIconBuildResult = {
|
||||
attributes: {
|
||||
width: '20',
|
||||
viewBox: '0 0 20 16',
|
||||
},
|
||||
body: '<path d="..." />',
|
||||
};
|
||||
|
||||
const result = iconToSVG(icon, custom);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
test('Unset size', () => {
|
||||
const custom: IconifyIconCustomisations = {
|
||||
// Testing 'undefined' and 'none' keywords
|
||||
width: 'undefined',
|
||||
height: 'none',
|
||||
};
|
||||
const icon: IconifyIcon = {
|
||||
width: 20,
|
||||
height: 16,
|
||||
body: '<path d="..." />',
|
||||
};
|
||||
const expected: IconifyIconBuildResult = {
|
||||
attributes: {
|
||||
viewBox: '0 0 20 16',
|
||||
},
|
||||
body: '<path d="..." />',
|
||||
};
|
||||
|
||||
const result = iconToSVG(icon, custom);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
test('Rotation', () => {
|
||||
const custom: IconifyIconCustomisations = {
|
||||
height: '40px',
|
||||
|
Loading…
Reference in New Issue
Block a user