mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-12-05 03:54:35 +01:00
refactor: Convert icon manager into class
This commit is contained in:
@@ -23,66 +23,100 @@ export const unknownIcon: IconifyIcon = {
|
|||||||
width: 80,
|
width: 80,
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconsStore = new Map<string, IconifyJSON>();
|
class IconManager {
|
||||||
const loaderStore = new Map<string, AsyncIconLoader['loader']>();
|
private iconsStore = new Map<string, IconifyJSON>();
|
||||||
|
private loaderStore = new Map<string, AsyncIconLoader['loader']>();
|
||||||
|
|
||||||
export const registerIconPacks = (iconLoaders: IconLoader[]) => {
|
registerIconPacks(iconLoaders: IconLoader[]): void {
|
||||||
for (const iconLoader of iconLoaders) {
|
for (const iconLoader of iconLoaders) {
|
||||||
if (!iconLoader.name) {
|
if (!iconLoader.name) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid icon loader. Must have a "name" property with non-empty string value.'
|
'Invalid icon loader. Must have a "name" property with non-empty string value.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
log.debug('Registering icon pack:', iconLoader.name);
|
log.debug('Registering icon pack:', iconLoader.name);
|
||||||
if ('loader' in iconLoader) {
|
if ('loader' in iconLoader) {
|
||||||
loaderStore.set(iconLoader.name, iconLoader.loader);
|
this.loaderStore.set(iconLoader.name, iconLoader.loader);
|
||||||
} else if ('icons' in iconLoader) {
|
} else if ('icons' in iconLoader) {
|
||||||
iconsStore.set(iconLoader.name, iconLoader.icons);
|
this.iconsStore.set(iconLoader.name, iconLoader.icons);
|
||||||
} else {
|
} else {
|
||||||
log.error('Invalid icon loader:', iconLoader);
|
log.error('Invalid icon loader:', iconLoader);
|
||||||
throw new Error('Invalid icon loader. Must have either "icons" or "loader" property.');
|
throw new Error('Invalid icon loader. Must have either "icons" or "loader" property.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const getRegisteredIconData = async (iconName: string, fallbackPrefix?: string) => {
|
private async getRegisteredIconData(
|
||||||
const data = stringToIcon(iconName, true, fallbackPrefix !== undefined);
|
iconName: string,
|
||||||
if (!data) {
|
fallbackPrefix?: string
|
||||||
throw new Error(`Invalid icon name: ${iconName}`);
|
): Promise<ExtendedIconifyIcon> {
|
||||||
}
|
const data = stringToIcon(iconName, true, fallbackPrefix !== undefined);
|
||||||
const prefix = data.prefix || fallbackPrefix;
|
if (!data) {
|
||||||
if (!prefix) {
|
throw new Error(`Invalid icon name: ${iconName}`);
|
||||||
throw new Error(`Icon name must contain a prefix: ${iconName}`);
|
|
||||||
}
|
|
||||||
let icons = iconsStore.get(prefix);
|
|
||||||
if (!icons) {
|
|
||||||
const loader = loaderStore.get(prefix);
|
|
||||||
if (!loader) {
|
|
||||||
throw new Error(`Icon set not found: ${data.prefix}`);
|
|
||||||
}
|
}
|
||||||
|
const prefix = data.prefix || fallbackPrefix;
|
||||||
|
if (!prefix) {
|
||||||
|
throw new Error(`Icon name must contain a prefix: ${iconName}`);
|
||||||
|
}
|
||||||
|
let icons = this.iconsStore.get(prefix);
|
||||||
|
if (!icons) {
|
||||||
|
const loader = this.loaderStore.get(prefix);
|
||||||
|
if (!loader) {
|
||||||
|
throw new Error(`Icon set not found: ${data.prefix}`);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const loaded = await loader();
|
||||||
|
icons = { ...loaded, prefix };
|
||||||
|
this.iconsStore.set(prefix, icons);
|
||||||
|
} catch (e) {
|
||||||
|
log.error(e);
|
||||||
|
throw new Error(`Failed to load icon set: ${data.prefix}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const iconData = getIconData(icons, data.name);
|
||||||
|
if (!iconData) {
|
||||||
|
throw new Error(`Icon not found: ${iconName}`);
|
||||||
|
}
|
||||||
|
return iconData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isIconAvailable(iconName: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const loaded = await loader();
|
await this.getRegisteredIconData(iconName);
|
||||||
icons = { ...loaded, prefix };
|
return true;
|
||||||
iconsStore.set(prefix, icons);
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getIconSVG(
|
||||||
|
iconName: string,
|
||||||
|
customisations?: IconifyIconCustomisations & { fallbackPrefix?: string },
|
||||||
|
extraAttributes?: Record<string, string>
|
||||||
|
): Promise<string> {
|
||||||
|
let iconData: ExtendedIconifyIcon;
|
||||||
|
try {
|
||||||
|
iconData = await this.getRegisteredIconData(iconName, customisations?.fallbackPrefix);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
throw new Error(`Failed to load icon set: ${data.prefix}`);
|
iconData = unknownIcon;
|
||||||
}
|
}
|
||||||
|
const renderData = iconToSVG(iconData, customisations);
|
||||||
|
const svg = iconToHTML(replaceIDs(renderData.body), {
|
||||||
|
...renderData.attributes,
|
||||||
|
...extraAttributes,
|
||||||
|
});
|
||||||
|
return sanitizeText(svg, getConfig());
|
||||||
}
|
}
|
||||||
const iconData = getIconData(icons, data.name);
|
}
|
||||||
if (!iconData) {
|
|
||||||
throw new Error(`Icon not found: ${iconName}`);
|
|
||||||
}
|
|
||||||
return iconData;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const globalIconManager = new IconManager();
|
||||||
|
|
||||||
|
// Export the singleton instance methods for backward compatibility
|
||||||
|
export const registerIconPacks = (iconLoaders: IconLoader[]) =>
|
||||||
|
globalIconManager.registerIconPacks(iconLoaders);
|
||||||
export const isIconAvailable = async (iconName: string) => {
|
export const isIconAvailable = async (iconName: string) => {
|
||||||
try {
|
return await globalIconManager.isIconAvailable(iconName);
|
||||||
await getRegisteredIconData(iconName);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getIconSVG = async (
|
export const getIconSVG = async (
|
||||||
@@ -90,17 +124,5 @@ export const getIconSVG = async (
|
|||||||
customisations?: IconifyIconCustomisations & { fallbackPrefix?: string },
|
customisations?: IconifyIconCustomisations & { fallbackPrefix?: string },
|
||||||
extraAttributes?: Record<string, string>
|
extraAttributes?: Record<string, string>
|
||||||
) => {
|
) => {
|
||||||
let iconData: ExtendedIconifyIcon;
|
return await globalIconManager.getIconSVG(iconName, customisations, extraAttributes);
|
||||||
try {
|
|
||||||
iconData = await getRegisteredIconData(iconName, customisations?.fallbackPrefix);
|
|
||||||
} catch (e) {
|
|
||||||
log.error(e);
|
|
||||||
iconData = unknownIcon;
|
|
||||||
}
|
|
||||||
const renderData = iconToSVG(iconData, customisations);
|
|
||||||
const svg = iconToHTML(replaceIDs(renderData.body), {
|
|
||||||
...renderData.attributes,
|
|
||||||
...extraAttributes,
|
|
||||||
});
|
|
||||||
return sanitizeText(svg, getConfig());
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user