{"version":3,"file":"icon-registry.cjs","sources":["../../src/icon-registry/icon-aliases.ts","../../src/icon-registry/resolve-icon-name.ts","../../src/icon-registry/resolve-icon-node.ts","../../src/icon-registry/search-icon-names.ts"],"sourcesContent":["/**\n * RuleCMS-owned name aliases. A name that has ever been persisted is never\n * deleted — only aliased here to the current Lucide kebab name.\n *\n * Seeded from Lucide's own rename shims (shape-first convention). Extend on\n * every upstream lucide-static sync; the sync job should fail when an upstream\n * icon disappears without an alias.\n */\nexport const ICON_NAME_ALIASES: Record<string, string> = {\n  'alert-circle': 'circle-alert',\n  'alert-octagon': 'octagon-alert',\n  'alert-triangle': 'triangle-alert',\n  'arrow-down-circle': 'circle-arrow-down',\n  'arrow-left-circle': 'circle-arrow-left',\n  'arrow-right-circle': 'circle-arrow-right',\n  'arrow-up-circle': 'circle-arrow-up',\n  'check-circle': 'circle-check',\n  'check-circle-2': 'circle-check-big',\n  'divide-circle': 'circle-divide',\n  // Renamed twice upstream: help-circle -> circle-help -> circle-question-mark.\n  // Both historical spellings have to land on the current name.\n  'help-circle': 'circle-question-mark',\n  'circle-help': 'circle-question-mark',\n  'minus-circle': 'circle-minus',\n  'pause-circle': 'circle-pause',\n  'plus-circle': 'circle-plus',\n  'stop-circle': 'circle-stop',\n  'x-circle': 'circle-x',\n  'x-octagon': 'octagon-x',\n  'x-square': 'square-x',\n};\n","import { ICON_NAME_ALIASES } from './icon-aliases';\n\n/**\n * Normalize a persisted RuleCMS icon name to the current Lucide kebab key.\n * Empty / non-string input yields null.\n */\nexport const resolveIconName = (name: unknown): string | null => {\n  if (typeof name !== 'string') return null;\n  const trimmed = name.trim();\n  if (!trimmed) return null;\n\n  // Authors may paste PascalCase from Lucide docs; normalize to kebab.\n  const kebab = trimmed\n    .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n    .replace(/[\\s_]+/g, '-')\n    .toLowerCase();\n\n  return ICON_NAME_ALIASES[kebab] ?? kebab;\n};\n","import iconNodes from 'lucide-static/icon-nodes.json';\nimport type { IconAttributeValue, IconNode } from '@source-components-react/types';\nimport { resolveIconName } from './resolve-icon-name';\n\nconst registry = iconNodes as Record<string, IconNode>;\n\n/**\n * Geometry lookup for a persisted icon name.\n *\n * Registry-side only: the render path never calls this. Published payloads\n * carry geometry inline on the attribute (see `buildIconAttributeValue`), so\n * customer pages never load this module or the ~722 KB of JSON behind it.\n */\nexport const resolveIconNode = (name: unknown): IconNode | null => {\n  const resolvedName = resolveIconName(name);\n  if (!resolvedName) return null;\n  return registry[resolvedName] ?? null;\n};\n\n/**\n * Build the value the composer persists when an author picks an icon.\n *\n * Geometry is stamped at selection rather than at publish so that every\n * surface — composer canvas, dev-environment host apps, staging and\n * production — renders from the same attribute with no registry present.\n * `name` travels alongside so a later sync can re-resolve stale geometry.\n */\nexport const buildIconAttributeValue = (name: unknown): IconAttributeValue | null => {\n  const resolvedName = resolveIconName(name);\n  if (!resolvedName) return null;\n\n  const iconNode = registry[resolvedName];\n  if (!iconNode) return null;\n\n  return { name: resolvedName, iconNode };\n};\n\nexport const isKnownIconName = (name: unknown): boolean => {\n  const resolved = resolveIconName(name);\n  return resolved != null && resolved in registry;\n};\n\nexport const listIconNames = (): string[] => Object.keys(registry);\n","import tags from 'lucide-static/tags.json';\nimport { listIconNames } from './resolve-icon-node';\n\nconst tagsByName = tags as Record<string, string[]>;\n\n/**\n * Rank buckets, best first. Name matches beat tag matches because an author\n * typing \"rocket\" wants the icon called rocket, not everything tagged with it.\n * An exact tag beats a partial one so searching \"link\" is not buried under\n * everything tagged \"linkedin\".\n */\nconst NAME_PREFIX = 0;\nconst NAME_SUBSTRING = 1;\nconst TAG_EXACT = 2;\nconst TAG_PARTIAL = 3;\n\nconst rank = (name: string, query: string): number => {\n  if (name.startsWith(query)) return NAME_PREFIX;\n  if (name.includes(query)) return NAME_SUBSTRING;\n\n  const tags = tagsByName[name];\n  if (!tags) return -1;\n  if (tags.some((tag) => tag === query)) return TAG_EXACT;\n  if (tags.some((tag) => tag.includes(query))) return TAG_PARTIAL;\n  return -1;\n};\n\n/**\n * Search icons by name and by Lucide's published tag index.\n *\n * Tag search is why the picker is worth changing: today's name-only list\n * cannot answer \"launch\" with `rocket`. An empty query returns every name so\n * the picker can show a browsable default.\n */\nexport const searchIconNames = (query: unknown, limit?: number): string[] => {\n  const names = listIconNames();\n  const normalized = typeof query === 'string' ? query.trim().toLowerCase() : '';\n\n  if (!normalized) {\n    return typeof limit === 'number' ? names.slice(0, limit) : names;\n  }\n\n  const matched = names\n    .map((name) => ({ name, rank: rank(name, normalized) }))\n    .filter((entry) => entry.rank >= 0)\n    .sort((a, b) => a.rank - b.rank || a.name.localeCompare(b.name))\n    .map((entry) => entry.name);\n\n  return typeof limit === 'number' ? matched.slice(0, limit) : matched;\n};\n\n/** The tags Lucide publishes for an icon; empty when the name is unknown. */\nexport const getIconTags = (name: string): string[] => tagsByName[name] ?? [];\n"],"names":["ICON_NAME_ALIASES","resolveIconName","name","trimmed","trim","kebab","replace","toLowerCase","registry","iconNodes","listIconNames","Object","keys","tagsByName","tags","rank","query","startsWith","includes","some","tag","resolvedName","iconNode","resolved","limit","names","normalized","slice","matched","map","filter","entry","sort","a","b","localeCompare"],"mappings":"iGAQO,MAAMA,EAA4C,CACvD,eAAgB,eAChB,gBAAiB,gBACjB,iBAAkB,iBAClB,oBAAqB,oBACrB,oBAAqB,oBACrB,qBAAsB,qBACtB,kBAAmB,kBACnB,eAAgB,eAChB,iBAAkB,mBAClB,gBAAiB,gBAGjB,cAAe,uBACf,cAAe,uBACf,eAAgB,eAChB,eAAgB,eAChB,cAAe,cACf,cAAe,cACf,WAAY,WACZ,YAAa,YACb,WAAY,YCvBDC,EAAmBC,IAC9B,GAAoB,iBAATA,EAAmB,OAAO,KACrC,MAAMC,EAAUD,EAAKE,OACrB,IAAKD,EAAS,OAAO,KAGrB,MAAME,EAAQF,EACXG,QAAQ,qBAAsB,SAC9BA,QAAQ,UAAW,KACnBC,cAEH,OAAOP,EAAkBK,IAAUA,GCb/BG,EAAWC,EAsCJC,EAAgB,IAAgBC,OAAOC,KAAKJ,GCvCnDK,EAAaC,EAabC,EAAO,CAACb,EAAcc,KAC1B,GAAId,EAAKe,WAAWD,GAAQ,OANV,EAOlB,GAAId,EAAKgB,SAASF,GAAQ,OANL,EAQrB,MAAMF,EAAOD,EAAWX,GACxB,OAAKY,EACDA,EAAKK,KAAMC,GAAQA,IAAQJ,GATf,EAUZF,EAAKK,KAAMC,GAAQA,EAAIF,SAASF,IATlB,GAUX,GAHW,+DDMoBd,IACtC,MAAMmB,EAAepB,EAAgBC,GACrC,IAAKmB,EAAc,OAAO,KAE1B,MAAMC,EAAWd,EAASa,GAC1B,OAAKC,EAEE,CAAEpB,KAAMmB,EAAcC,YAFP,0BCoBIpB,GAA2BW,EAAWX,IAAS,2BDf3CA,IAC9B,MAAMqB,EAAWtB,EAAgBC,GACjC,OAAmB,MAAZqB,GAAoBA,KAAYf,6EA1BTN,IAC9B,MAAMmB,EAAepB,EAAgBC,GACrC,OAAKmB,EACEb,EAASa,IAAiB,KADP,8BCmBG,CAACL,EAAgBQ,KAC9C,MAAMC,EAAQf,IACRgB,EAA8B,iBAAVV,EAAqBA,EAAMZ,OAAOG,cAAgB,GAE5E,IAAKmB,EACH,MAAwB,iBAAVF,EAAqBC,EAAME,MAAM,EAAGH,GAASC,EAG7D,MAAMG,EAAUH,EACbI,IAAK3B,IAAI,CAAQA,OAAMa,KAAMA,EAAKb,EAAMwB,MACxCI,OAAQC,GAAUA,EAAMhB,MAAQ,GAChCiB,KAAK,CAACC,EAAGC,IAAMD,EAAElB,KAAOmB,EAAEnB,MAAQkB,EAAE/B,KAAKiC,cAAcD,EAAEhC,OACzD2B,IAAKE,GAAUA,EAAM7B,MAExB,MAAwB,iBAAVsB,EAAqBI,EAAQD,MAAM,EAAGH,GAASI"}