--- // @ts-ignore virtual module import icons, { config } from "virtual:astro-icon"; // @ts-ignore generated by typegen import type { Icon } from "virtual:astro-icon"; import { getIconData, iconToSVG } from "@iconify/utils"; import type { HTMLAttributes } from "astro/types"; import { cache } from "./cache.js"; import type { IconifyIconBuildResult } from "@iconify/utils/lib/svg/build.js"; interface Props extends HTMLAttributes<"svg"> { name: Icon; "is:inline"?: boolean; title?: string; desc?: string; size?: number | string; width?: number | string; height?: number | string; } class AstroIconError extends Error { public hint: string = ''; constructor(message: string) { super(message); } } const req = Astro.request; const { name = "", title, desc, "is:inline": inline = false, ...props } = Astro.props; const map = cache.get(req) ?? new Map(); const i = map.get(name) ?? 0; map.set(name, i + 1); cache.set(req, map); const { include = {} } = config; const sets = Object.keys(include); const includeSymbol = !inline && i === 0; let [setName, iconName] = (name as string).split(":"); if (!setName && iconName) { const err = new AstroIconError(`Invalid "name" provided!`); if (import.meta.env.DEV) { err.hint = `The provided value of "${name}" is invalid.\n\nDid you forget the icon set name? If you were attemping to reference a local icon, use the icon's name directly. (ie. "${iconName}")`; } throw err; } // No iconName, assume local icon reference if (!iconName) { // Assign the provided setName to the iconName iconName = setName; setName = "local"; // Check if the local icon set exists if (!icons[setName]) { const err = new AstroIconError('Unable to load the "local" icon set!'); if (import.meta.env.DEV) { err.hint = 'It looks like the "local" set was not loaded.\n\nDid you forget to create the icon directory or to update your config?'; } throw err; } // Check if the icon is missing from the local collection if (!(iconName in icons[setName].icons)) { const err = new AstroIconError(`Unable to locate "${name}" icon!`); if (import.meta.env.DEV) { err.hint = `The icon named "${iconName}" was not found in your local icon directory.\n\nDid you forget to configure your icon directory or make a typo?`; } throw err; } } const collection = icons[setName]; // Iconify collection not configured correctly if (!collection) { const err = new AstroIconError(`Unable to locate the "${setName}" icon set!`); if (import.meta.env.DEV) { if (sets.includes(setName)) { err.hint = `It looks like the "${setName}" set was not loaded.\n\nDid you install the "@iconify-json/${setName}" dependency?`; } else { err.hint = `It looks like the "${setName}" set is not included in your configuration.\n\nDo you need to add the "${setName}" set?`; } } throw err; } const iconData = getIconData(collection, iconName ?? setName); // Missing icon from the icon collection if (!iconData) { const err = new AstroIconError(`Unable to locate "${name}" icon!`); if (import.meta.env.DEV) { const [maybeStar] = include[setName]; if (maybeStar === "*" || include[setName].includes(iconName)) { err.hint = `The "${setName}" set does not include an icon named "${iconName}".\n\nIs this a typo?`; } else { err.hint = `The "${setName}" set is not configured to include an icon named "${iconName}".\n\nDo you need to add it to your configuration?`; } } throw err; } const id = `ai:${collection.prefix}:${iconName ?? setName}`; if (props.size) { props.width = props.size; props.height = props.size; delete props.size; } const renderData = iconToSVG(iconData); const normalizedProps = { ...renderData.attributes as Partial, ...props }; const normalizedBody = renderData.body; const { viewBox } = normalizedProps; if (includeSymbol) { delete normalizedProps.viewBox; } --- {title && {title}} {desc && {desc}} { inline ? ( ) : ( {includeSymbol && } ) }