mirror of
https://github.com/iconify/iconify.git
synced 2024-11-10 07:11:00 +00:00
chore: add icons customizations
This commit is contained in:
parent
2d06165da3
commit
c281ebf7f1
@ -48,9 +48,11 @@ export { stringToColor, compareColors, colorToString } from './colors/index';
|
||||
export type {
|
||||
CustomIconLoader,
|
||||
CustomCollections,
|
||||
IconCustomizer,
|
||||
IconCustomizations,
|
||||
InlineCollection,
|
||||
} from './loader/types';
|
||||
export { tryInstallPkg } from './loader/utils';
|
||||
export { tryInstallPkg, mergeIconProps } from './loader/utils';
|
||||
export { FileSystemIconLoader } from './loader/loaders';
|
||||
export { getCustomIcon } from './loader/custom';
|
||||
export { loadCollection, searchForIcon } from './loader/modern';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Awaitable } from '@antfu/utils';
|
||||
import createDebugger from 'debug';
|
||||
import type { CustomIconLoader, InlineCollection } from './types';
|
||||
import type { CustomIconLoader, IconCustomizations, InlineCollection } from './types';
|
||||
import { mergeIconProps } from './utils';
|
||||
|
||||
const debug = createDebugger('@iconify-loader:custom');
|
||||
|
||||
@ -11,7 +11,7 @@ export async function getCustomIcon(
|
||||
custom: CustomIconLoader | InlineCollection,
|
||||
collection: string,
|
||||
icon: string,
|
||||
transform?: (svg: string) => Awaitable<string>
|
||||
iconsCustomizations?: IconCustomizations,
|
||||
): Promise<string | undefined> {
|
||||
let result: string | undefined | null;
|
||||
|
||||
@ -26,10 +26,18 @@ export async function getCustomIcon(
|
||||
|
||||
if (result) {
|
||||
if (!result.startsWith('<svg ')) {
|
||||
console.warn(
|
||||
`Custom icon "${icon}" in "${collection}" is not a valid SVG`
|
||||
);
|
||||
console.warn(`Custom icon "${icon}" in "${collection}" is not a valid SVG`)
|
||||
return result
|
||||
}
|
||||
return transform ? await transform(result) : result;
|
||||
const { transform, additionalProps = {}, iconCustomizer } = iconsCustomizations || {}
|
||||
return await mergeIconProps(
|
||||
transform ? await transform(result) : result,
|
||||
collection,
|
||||
icon,
|
||||
additionalProps,
|
||||
undefined,
|
||||
iconCustomizer
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ export function FileSystemIconLoader(
|
||||
`${dir}/${camelize(name)}.svg`,
|
||||
`${dir}/${pascalize(name)}.svg`,
|
||||
];
|
||||
let stat: Stats;
|
||||
for (const path of paths) {
|
||||
let stat: Stats;
|
||||
try {
|
||||
stat = await fs.lstat(path);
|
||||
} catch (err) {
|
||||
|
@ -3,11 +3,11 @@ import type { IconifyJSON } from '@iconify/types';
|
||||
import type { FullIconifyIcon } from '../icon';
|
||||
import { iconToSVG } from '../svg/build';
|
||||
import { getIconData } from '../icon-set/get-icon';
|
||||
import { tryInstallPkg } from './utils';
|
||||
import { mergeIconProps, tryInstallPkg } from './utils';
|
||||
import createDebugger from 'debug';
|
||||
import { isPackageExists, resolveModule } from 'local-pkg';
|
||||
import { defaults as DefaultIconCustomizations } from '../customisations';
|
||||
import type { FullIconCustomisations } from '../customisations';
|
||||
import type { IconCustomizations } from './types';
|
||||
|
||||
const debug = createDebugger('@iconify-loader:icon');
|
||||
const debugModern = createDebugger('@iconify-loader:modern');
|
||||
@ -51,13 +51,14 @@ export async function loadCollection(name: string, autoInstall = false): Promise
|
||||
}
|
||||
}
|
||||
|
||||
export function searchForIcon(
|
||||
export async function searchForIcon(
|
||||
iconSet: IconifyJSON,
|
||||
collection: string,
|
||||
ids: string[],
|
||||
customize?: (defaultCustomizations: FullIconCustomisations) => FullIconCustomisations
|
||||
): string | null {
|
||||
iconCustomizactions?: IconCustomizations,
|
||||
): Promise<string | undefined> {
|
||||
let iconData: FullIconifyIcon | null;
|
||||
const { customize, additionalProps = {}, iconCustomizer } = iconCustomizactions || {}
|
||||
for (const id of ids) {
|
||||
iconData = getIconData(iconSet, id, true);
|
||||
if (iconData) {
|
||||
@ -67,8 +68,14 @@ export function searchForIcon(
|
||||
iconData,
|
||||
typeof customize === 'function' ? customize(defaultCustomizations) : defaultCustomizations
|
||||
);
|
||||
return `<svg ${Object.entries(attributes).map(i => `${i[0]}="${i[1]}"`).join(' ')}>${body}</svg>`;
|
||||
return await mergeIconProps(
|
||||
`<svg>${body}</svg>`,
|
||||
collection,
|
||||
id,
|
||||
additionalProps,
|
||||
() => attributes,
|
||||
iconCustomizer,
|
||||
)
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,10 +1,52 @@
|
||||
import type { Awaitable } from '@antfu/utils';
|
||||
import type { FullIconCustomisations } from '../customisations';
|
||||
|
||||
/**
|
||||
* Custom icon loader, used by getCustomIcon()
|
||||
* Custom icon loader, used by `getCustomIcon`.
|
||||
*/
|
||||
export type CustomIconLoader = (name: string) => Awaitable<string | undefined>;
|
||||
|
||||
/**
|
||||
* Custom icon customizer, it will allow to customize all icons on a collection or individual icons.
|
||||
*/
|
||||
export type IconCustomizer = (collection: string, icon: string, props: Record<string, string>) => Awaitable<void>;
|
||||
|
||||
/**
|
||||
* Icon customizations: will be applied to all resolved icons.
|
||||
*
|
||||
* For each loaded icon, the customizations will be applied in this order:
|
||||
* - apply `transform` to raw `svg`, if provided
|
||||
* - apply `customize` with default customizations, if provided
|
||||
* - apply `iconCustomizer` with `customize` customizations, if provided
|
||||
* - apply `additionalProps` with `iconCustomizer` customizations, if provided
|
||||
*/
|
||||
export type IconCustomizations = {
|
||||
/**
|
||||
* Transform raw `svg`.
|
||||
*
|
||||
* @param svg The loaded `svg`
|
||||
* @return The transformed `svg`.
|
||||
*/
|
||||
transform?: (svg: string) => Awaitable<string>
|
||||
/**
|
||||
* Change default icon customizations values.
|
||||
*
|
||||
* @param defaultCustomizations Default icon customisations values.
|
||||
* @return The modified icon customisations values.
|
||||
*/
|
||||
customize?: (defaultCustomizations: FullIconCustomisations) => FullIconCustomisations
|
||||
/**
|
||||
* Custom icon customizer.
|
||||
*/
|
||||
iconCustomizer?: IconCustomizer
|
||||
/**
|
||||
* Additional icon properties.
|
||||
*
|
||||
* All properties without value will not be applied.
|
||||
*/
|
||||
additionalProps?: Record<string, string | undefined>
|
||||
};
|
||||
|
||||
/**
|
||||
* List of icons as object. Key is icon name, value is icon data or callback (can be async) to get icon data
|
||||
*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { installPackage } from '@antfu/install-pkg';
|
||||
import { sleep } from '@antfu/utils';
|
||||
import { Awaitable, sleep } from '@antfu/utils';
|
||||
import { cyan, yellow } from 'kolorist';
|
||||
import type { IconCustomizer } from './types';
|
||||
|
||||
const warned = new Set<string>();
|
||||
|
||||
@ -14,6 +15,25 @@ export function warnOnce(msg: string): void {
|
||||
let pending: Promise<void> | undefined;
|
||||
const tasks: Record<string, Promise<void> | undefined> = {};
|
||||
|
||||
export async function mergeIconProps(
|
||||
svg: string,
|
||||
collection: string,
|
||||
icon: string,
|
||||
additionalProps: Record<string, string | undefined>,
|
||||
propsProvider?: () => Awaitable<Record<string, string>>,
|
||||
iconCustomizer?: IconCustomizer,
|
||||
): Promise<string> {
|
||||
const props: Record<string, string> = await propsProvider?.() ?? {}
|
||||
await iconCustomizer?.(collection, icon, props)
|
||||
Object.keys(additionalProps).forEach((p) => {
|
||||
const v = additionalProps[p]
|
||||
if (v !== undefined && v !== null)
|
||||
props[p] = v
|
||||
})
|
||||
const replacement = svg.startsWith('<svg ') ? '<svg ' : '<svg'
|
||||
return svg.replace(replacement, `${replacement}${Object.keys(props).map(p => `${p}="${props[p]}"`).join(' ')}`)
|
||||
}
|
||||
|
||||
export async function tryInstallPkg(name: string): Promise<void | undefined> {
|
||||
if (pending) {
|
||||
await pending;
|
||||
|
@ -16,9 +16,12 @@ describe('Testing getCustomIcon', () => {
|
||||
() => svg,
|
||||
'a',
|
||||
'b',
|
||||
(icon) => {
|
||||
return icon.replace('<svg ', '<svg width="1em" height="1em" ');
|
||||
{
|
||||
transform(icon) {
|
||||
return icon.replace('<svg ', '<svg width="1em" height="1em" ');
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
expect(result && result.indexOf('width="1em"') > -1).toBeTruthy();
|
||||
expect(result && result.indexOf('height="1em"') > -1).toBeTruthy();
|
||||
|
Loading…
Reference in New Issue
Block a user