{"version":3,"file":"ngwr-icon.mjs","sources":["../../../projects/lib/icon/tokens/icon.token.ts","../../../projects/lib/icon/icon.ts","../../../projects/lib/icon/utils/validate-icon.ts","../../../projects/lib/icon/providers/provide-wr-icons.ts","../../../projects/lib/icon/svg-icon.ts","../../../projects/lib/icon/ngwr-icon.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport type { WrIconDef } from '../interfaces';\n\n/**\n * Multi-provider token for registering icons with the icon registry.\n *\n * Use {@link provideWrIcons} instead of providing this token directly.\n *\n * @internal\n */\nexport const WR_ICONS = new InjectionToken<readonly WrIconDef[][]>('WR_ICONS');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport {\n  Component,\n  ElementRef,\n  EnvironmentInjector,\n  ViewEncapsulation,\n  computed,\n  effect,\n  inject,\n  input,\n  isDevMode,\n} from '@angular/core';\n\nimport type { WrIconDef, WrIconName } from './interfaces';\nimport { WR_ICONS } from './tokens';\n\n/**\n * Renders a registered SVG icon.\n *\n * Icons must be registered via {@link provideWrIcons} before use —\n * either at the application root or on any ancestor component.\n *\n * @example\n * ```html\n * <wr-icon name=\"home\" />\n * ```\n *\n * @see https://ngwr.dev/components/icon\n */\n@Component({\n  selector: 'wr-icon',\n  template: '',\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'wr-icon',\n    '[attr.data-icon]': 'name()',\n  },\n})\nexport class WrIcon {\n  readonly name = input.required<WrIconName>();\n\n  private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n  /**\n   * Merged view of every `WR_ICONS` multi-provider visible from this\n   * injector position — element-level first overlay, environment-level\n   * (app/lazy-route bootstrap) as the base.\n   *\n   * Angular's default `inject(WR_ICONS)` only returns the **closest**\n   * injector's contribution; if a component declares its own\n   * `provideWrIcons(...)`, the root registration is **shadowed**, not\n   * appended. That contradicts the docstring's \"each call adds to the\n   * registry\" promise and silently breaks any page that overrides while\n   * still relying on root-registered icons.\n   *\n   * We work around it by also asking the environment injector directly\n   * (`envInjector.get(WR_ICONS, null, …)`). When no element-level\n   * provider exists both calls return the same array reference and we\n   * skip the redundant pass. Otherwise we lay element on top of env so\n   * a page's local icons can override a root-registered name.\n   *\n   * One known limitation: multiple element-injector levels in between\n   * still shadow each other — but the showcase doesn't nest providers\n   * that deep, and the env+local merge fixes the dominant case.\n   */\n  private readonly iconSets: readonly (readonly WrIconDef[])[] = (() => {\n    const local = inject(WR_ICONS, { optional: true }) ?? [];\n    const env = inject(EnvironmentInjector).get(WR_ICONS, null, { optional: true }) ?? [];\n    return local === env ? local : [...env, ...local];\n  })();\n\n  private readonly registry = computed(() => {\n    const map = new Map<WrIconName, WrIconDef>();\n    for (const set of this.iconSets) {\n      for (const icon of set) {\n        map.set(icon.name, icon);\n      }\n    }\n    return map;\n  });\n\n  private readonly icon = computed(() => this.registry().get(this.name()));\n\n  constructor() {\n    effect(() => {\n      const icon = this.icon();\n      const name = this.name();\n\n      if (!icon) {\n        if (isDevMode()) {\n          throw new Error(`[NGWR] No icon named \"${name}\" is registered. Did you forget to call provideWrIcons()?`);\n        }\n        this.host.nativeElement.innerHTML = '';\n        return;\n      }\n\n      this.host.nativeElement.innerHTML = icon.data;\n    });\n  }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from '../interfaces';\n\nconst VIEW_BOX_RE = /<svg\\b[^>]*\\bviewBox\\s*=/i;\nconst SVG_ROOT_RE = /<svg\\b/i;\n\n/**\n * Dev-mode sanity check for a registered icon.\n *\n * Warns about issues that prevent correct rendering — most importantly,\n * a missing `viewBox`, which causes the SVG not to scale to the icon\n * host's size.\n *\n * Production builds drop the call entirely via `isDevMode()` tree-shaking.\n *\n * @internal\n */\nexport function validateIcon(icon: WrIconDef): void {\n  if (!SVG_ROOT_RE.test(icon.data)) {\n    // eslint-disable-next-line no-console -- dev-mode validation\n    console.warn(\n      `[NGWR] Icon \"${icon.name}\" data does not contain an <svg> root element. ` +\n        `Custom icons must be valid SVG markup.`\n    );\n    return;\n  }\n\n  if (!VIEW_BOX_RE.test(icon.data)) {\n    // eslint-disable-next-line no-console -- dev-mode validation\n    console.warn(\n      `[NGWR] Icon \"${icon.name}\" has no viewBox attribute — it won't scale ` +\n        `to the host size. Add viewBox=\"0 0 W H\" to the <svg> root.`\n    );\n  }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Provider, isDevMode } from '@angular/core';\n\nimport type { WrIconDef } from '../interfaces';\nimport { WR_ICONS } from '../tokens';\nimport { validateIcon } from '../utils';\n\n/**\n * Registers a set of icons for use by `<wr-icon>`.\n *\n * Can be called multiple times — each call adds to the registry.\n * Works at both the application root and at the component level,\n * so a feature module or a single component can bring its own icons\n * without polluting the global config.\n *\n * In dev mode, each icon is validated for common issues (missing\n * `viewBox`, malformed root). Validation is dropped from production\n * builds via `isDevMode()` tree-shaking.\n *\n * @example\n * ```ts\n * // App-level registration\n * import { home, user, cog, provideWrIcons } from 'ngwr/icon';\n *\n * export const appConfig: ApplicationConfig = {\n *   providers: [\n *     provideWrIcons([home, user, cog]),\n *   ],\n * };\n * ```\n *\n * @example\n * ```ts\n * // Component-level registration\n * import { logoGithub, logoNpm, provideWrIcons, WrIconDef } from 'ngwr/icon';\n *\n * @Component({\n *   selector: 'ngwr-header',\n *   imports: [WrIcon],\n *   providers: [provideWrIcons([logoGithub, logoNpm])],\n *   template: `<wr-icon name=\"logo-github\" />`,\n * })\n * export class HeaderComponent {}\n * ```\n */\nexport function provideWrIcons(icons: WrIconDef[]): Provider[] {\n  if (isDevMode()) {\n    for (const icon of icons) validateIcon(icon);\n  }\n  return [{ provide: WR_ICONS, useValue: icons, multi: true }];\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from './interfaces';\n\n/**\n * Wrap a raw SVG string in the {@link WrIconDef} envelope. Use this when\n * importing icons from sources that ship full `<svg>` files — Tabler,\n * Phosphor, Heroicons, Iconoir, Radix, Bootstrap Icons, your designer.\n *\n * Pair with a bundler's raw-SVG import (Vite's `?raw`, Webpack's\n * `raw-loader`, esbuild's `--loader:.svg=text`) so the SVG file becomes\n * a string at build time.\n *\n * For sets with a non-SVG shape (Lucide's IconNode tuples, Feather's\n * inner-only SVG), use the dedicated adapter under\n * `ngwr/icon/adapters/<set>` instead.\n *\n * @example\n * ```ts\n * import { svgIcon, provideWrIcons } from 'ngwr/icon';\n * // Vite: the `?raw` suffix returns the file as a string.\n * import plusSvg from '@tabler/icons/icons/plus.svg?raw';\n * import phosphorPlusSvg from '@phosphor-icons/core/assets/regular/plus.svg?raw';\n *\n * bootstrapApplication(AppComponent, {\n *   providers: [\n *     provideWrIcons([\n *       svgIcon('plus', plusSvg),\n *       svgIcon('plus-phosphor', phosphorPlusSvg),\n *     ]),\n *   ],\n * });\n * ```\n */\nexport function svgIcon(name: string, svg: string): WrIconDef {\n  return { name, data: svg };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}