| | |
| | | import { addCollection } from '@iconify/vue/offline' |
| | | import { LOCAL_ICON_COLLECTIONS } from '../../plugins/iconify.collections.js' |
| | | |
| | | const FULL_ICON_COLLECTION_LOADERS = Object.freeze({ |
| | | fluent: () => import('@iconify-json/fluent').then((module) => module.icons), |
| | | 'icon-park-outline': () => |
| | | import('@iconify-json/icon-park-outline').then((module) => module.icons), |
| | | iconamoon: () => import('@iconify-json/iconamoon').then((module) => module.icons), |
| | | ix: () => import('@iconify-json/ix').then((module) => module.icons), |
| | | 'line-md': () => import('@iconify-json/line-md').then((module) => module.icons), |
| | | ri: () => import('@iconify-json/ri').then((module) => module.icons), |
| | | solar: () => import('@iconify-json/solar').then((module) => module.icons), |
| | | 'svg-spinners': () => import('@iconify-json/svg-spinners').then((module) => module.icons), |
| | | 'system-uicons': () => import('@iconify-json/system-uicons').then((module) => module.icons), |
| | | vaadin: () => import('@iconify-json/vaadin').then((module) => module.icons) |
| | | }) |
| | | |
| | | const fullyRegisteredPrefixes = new Set() |
| | | const pendingPrefixLoads = new Map() |
| | | |
| | | function parseIconName(icon) { |
| | | if (typeof icon !== 'string') { |
| | | return null |
| | | } |
| | | |
| | | const normalizedIcon = icon.trim() |
| | | if (!normalizedIcon) { |
| | | return null |
| | | } |
| | | |
| | | const separatorIndex = normalizedIcon.indexOf(':') |
| | | if (separatorIndex <= 0 || separatorIndex >= normalizedIcon.length - 1) { |
| | | return null |
| | | } |
| | | |
| | | return { |
| | | prefix: normalizedIcon.slice(0, separatorIndex), |
| | | name: normalizedIcon.slice(separatorIndex + 1) |
| | | } |
| | | } |
| | | |
| | | function hasBundledIcon(icon) { |
| | | const parsedIcon = parseIconName(icon) |
| | | if (!parsedIcon) { |
| | | return false |
| | | } |
| | | |
| | | const collection = LOCAL_ICON_COLLECTIONS[parsedIcon.prefix] |
| | | if (!collection) { |
| | | return false |
| | | } |
| | | |
| | | return Boolean(collection.icons?.[parsedIcon.name] || collection.aliases?.[parsedIcon.name]) |
| | | } |
| | | |
| | | function loadFullIconCollection(prefix) { |
| | | if (fullyRegisteredPrefixes.has(prefix)) { |
| | | return Promise.resolve(true) |
| | | } |
| | | |
| | | const currentTask = pendingPrefixLoads.get(prefix) |
| | | if (currentTask) { |
| | | return currentTask |
| | | } |
| | | |
| | | const loader = FULL_ICON_COLLECTION_LOADERS[prefix] |
| | | if (!loader) { |
| | | return Promise.resolve(false) |
| | | } |
| | | |
| | | const loadTask = loader() |
| | | .then((collection) => { |
| | | addCollection(collection) |
| | | fullyRegisteredPrefixes.add(prefix) |
| | | pendingPrefixLoads.delete(prefix) |
| | | return true |
| | | }) |
| | | .catch((error) => { |
| | | pendingPrefixLoads.delete(prefix) |
| | | throw error |
| | | }) |
| | | |
| | | pendingPrefixLoads.set(prefix, loadTask) |
| | | return loadTask |
| | | } |
| | | |
| | | function collectRuntimeIcons(source, iconNames = new Set()) { |
| | | if (!Array.isArray(source)) { |
| | | return iconNames |
| | | } |
| | | |
| | | source.forEach((item) => { |
| | | if (!item || typeof item !== 'object') { |
| | | return |
| | | } |
| | | |
| | | const icon = item.meta?.icon || item.icon |
| | | if (typeof icon === 'string' && icon.includes(':') && !hasBundledIcon(icon)) { |
| | | iconNames.add(icon) |
| | | } |
| | | |
| | | if (Array.isArray(item.children) && item.children.length > 0) { |
| | | collectRuntimeIcons(item.children, iconNames) |
| | | } |
| | | }) |
| | | |
| | | return iconNames |
| | | } |
| | | |
| | | function scheduleIdleTask(task, delay = 0) { |
| | | const invoke = () => { |
| | | if (globalThis.requestIdleCallback) { |
| | | globalThis.requestIdleCallback(task, { timeout: 1000 }) |
| | | return |
| | | } |
| | | setTimeout(task, 0) |
| | | } |
| | | |
| | | if (delay > 0) { |
| | | setTimeout(invoke, delay) |
| | | return |
| | | } |
| | | |
| | | invoke() |
| | | } |
| | | |
| | | async function ensureIconRegistered(icon) { |
| | | const parsedIcon = parseIconName(icon) |
| | | if (!parsedIcon) { |
| | | return false |
| | | } |
| | | |
| | | if (hasBundledIcon(icon) || fullyRegisteredPrefixes.has(parsedIcon.prefix)) { |
| | | return true |
| | | } |
| | | |
| | | return loadFullIconCollection(parsedIcon.prefix) |
| | | } |
| | | |
| | | function warmRuntimeIcons(iconNames, delay = 120) { |
| | | const icons = [...new Set(Array.isArray(iconNames) ? iconNames : [])].filter(Boolean) |
| | | if (icons.length === 0) { |
| | | return |
| | | } |
| | | |
| | | scheduleIdleTask(() => { |
| | | icons.forEach((icon) => { |
| | | void ensureIconRegistered(icon) |
| | | }) |
| | | }, delay) |
| | | } |
| | | |
| | | function warmMenuIcons(menuList, delay = 120) { |
| | | warmRuntimeIcons([...collectRuntimeIcons(menuList)], delay) |
| | | } |
| | | |
| | | export { |
| | | collectRuntimeIcons, |
| | | ensureIconRegistered, |
| | | hasBundledIcon, |
| | | warmMenuIcons, |
| | | warmRuntimeIcons |
| | | } |