#
zhou zhou
1 天以前 4259deb19122a4807d50c99ed4a95405ebe4a47c
rsf-design/src/utils/ui/iconify-loader.js
@@ -0,0 +1,163 @@
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
}