@sken-ds/icons 0.3.1 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog-C0MX2DSN.js","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["/**\n * Sken icon catalog (ADR-0011).\n *\n * The icon family is Sken-owned. The set of semantic names is curated\n * here, the mapping from each name to a vendor SVG is curated here,\n * and the consumer never sees the vendor. To swap the vendor (or to\n * use a custom SVG), this file is the only place that changes.\n *\n * Vendor-agnostic by construction. The catalog is a `Record` of\n * semantic names to `IconAsset` records. The asset records point\n * to SVG strings imported as `?raw` from any path: a vendor\n * package (`@phosphor-icons/core/...`), a Figma export, an\n * internally drawn icon, a third-party set, or a mix of all of\n * the above. The Web Component API (`<SkenIcon name=\"...\" weight=\"...\" />`)\n * is the same regardless of where the SVG came from. Replacing the\n * vendor is an import-path swap in the `REGISTRY` literal below;\n * no consumer code moves.\n *\n * Bundle-cost note (revised 2026-07-28). The icon registry is\n * intentionally **runtime-based**, not tree-shakeable. The consumer\n * API is `<SkenIcon name=\"...\" weight=\"...\" />` where the `name`\n * arrives at runtime (it is an HTML attribute the user can type).\n * Rollup cannot statically resolve which case of the switch will\n * run, so the bundler keeps all 48 SVG strings (~21 KB raw,\n * ~5 KB gzip) in the primitive's bundle. Earlier versions of this\n * comment claimed that the per-case import structure was\n * tree-shakeable; that was wrong, and the inaccuracy was\n * introduced when the per-weight imports were added in this round.\n *\n * Why runtime and not build-time. The two real options for an icon\n * library are:\n *\n * - **Per-icon module** (Radix Icons, Lucide, Heroicons):\n * `<SkenCheckIcon />` imported from `@sken-ds/icons/check`. This\n * IS tree-shakeable but it forces the consumer to learn one\n * import per icon, and it makes a runtime-driven API\n * (`<sken-icon name=\"check\">`) impossible without lazy loading.\n * Sken is a design system; its API stability is worth more\n * than the per-icon bundle saving. The curated catalog is\n * small (16 names × 3 weights = 48 SVGs) and the runtime\n * cost (~5 KB gzip) is in the same league as `floating-ui`\n * or a `date-fns` locale.\n *\n * - **Runtime registry** (this file): one primitive, one\n * `getSkenIconSvg(name, weight)` lookup, 48 static imports.\n * Vendor-agnostic, name-agnostic, theme-agnostic. The\n * consumer writes the same `<SkenIcon name=\"...\" />` they\n * would have written anyway. The implementation can change\n * to per-icon modules in a future iteration without touching\n * the consumer surface.\n *\n * The decision is documented in the Status note of ADR-0011\n * (\"Runtime registry: why the icon catalog is not tree-shakeable\",\n * added 2026-07-28).\n *\n * Naming convention: the semantic name is a Sken decision, not a\n * Phosphor decision. We use `calendar` (not `ph-calendar`), `user`\n * (not `ph-user`), and so on. The vendor class is internal.\n *\n * Weight convention: Sken exposes three weights — `regular`,\n * `filled`, `emphasis` — to match the 95% of UI usage outlined\n * in the Icon weights section of ADR-0011. Phosphor offers six\n * (`thin`, `light`, `regular`, `bold`, `fill`, `duotone`); the\n * other three are not exposed because the Legrand Care brand does\n * not need them and exposing them would force the consumer to know\n * Phosphor's vocabulary. The mapping is:\n *\n * Sken weight → Phosphor subpath\n * `regular` → `regular/`\n * `filled` → `fill/`\n * `emphasis` → `bold/`\n *\n * Adding a new icon:\n * 1. Pick a semantic name (e.g. `user` for a generic avatar\n * icon, not `ph-user`). If the icon represents a new\n * concept, add the literal to `SkenIconName` below.\n * 2. Add three imports (one per weight) pointing to the\n * chosen SVG. The path is whatever the team decides: a\n * vendor subpath, an internal asset folder, a Figma\n * export, etc. Vite's `?raw` query makes any of these\n * work the same.\n * 3. Add a row to the `REGISTRY` literal mapping the name\n * to `{ regular, filled, emphasis }`. TypeScript will\n * catch a missing weight or a typo in the property name.\n */\n// regular/ — default weight, used for most UI\nimport ArrowLeftRegularSvg from '@phosphor-icons/core/regular/arrow-left.svg?raw'\nimport ArrowRightRegularSvg from '@phosphor-icons/core/regular/arrow-right.svg?raw'\nimport BellRegularSvg from '@phosphor-icons/core/regular/bell.svg?raw'\nimport CalendarRegularSvg from '@phosphor-icons/core/regular/calendar.svg?raw'\nimport CaretDownRegularSvg from '@phosphor-icons/core/regular/caret-down.svg?raw'\nimport CheckRegularSvg from '@phosphor-icons/core/regular/check.svg?raw'\nimport ClockCounterClockwiseRegularSvg from '@phosphor-icons/core/regular/clock-counter-clockwise.svg?raw'\nimport EyeRegularSvg from '@phosphor-icons/core/regular/eye.svg?raw'\nimport EyeSlashRegularSvg from '@phosphor-icons/core/regular/eye-slash.svg?raw'\nimport GearRegularSvg from '@phosphor-icons/core/regular/gear.svg?raw'\nimport InfoRegularSvg from '@phosphor-icons/core/regular/info.svg?raw'\nimport MagnifyingGlassRegularSvg from '@phosphor-icons/core/regular/magnifying-glass.svg?raw'\nimport MinusRegularSvg from '@phosphor-icons/core/regular/minus.svg?raw'\nimport PlusRegularSvg from '@phosphor-icons/core/regular/plus.svg?raw'\nimport SpinnerRegularSvg from '@phosphor-icons/core/regular/spinner.svg?raw'\nimport TrashRegularSvg from '@phosphor-icons/core/regular/trash.svg?raw'\nimport UserRegularSvg from '@phosphor-icons/core/regular/user.svg?raw'\nimport WarningRegularSvg from '@phosphor-icons/core/regular/warning.svg?raw'\nimport XRegularSvg from '@phosphor-icons/core/regular/x.svg?raw'\n// fill/ — filled weight, used for active/selected/alert states\nimport ArrowLeftFillSvg from '@phosphor-icons/core/fill/arrow-left-fill.svg?raw'\nimport ArrowRightFillSvg from '@phosphor-icons/core/fill/arrow-right-fill.svg?raw'\nimport BellFillSvg from '@phosphor-icons/core/fill/bell-fill.svg?raw'\nimport CalendarFillSvg from '@phosphor-icons/core/fill/calendar-fill.svg?raw'\nimport CaretDownFillSvg from '@phosphor-icons/core/fill/caret-down-fill.svg?raw'\nimport CheckFillSvg from '@phosphor-icons/core/fill/check-fill.svg?raw'\nimport ClockCounterClockwiseFillSvg from '@phosphor-icons/core/fill/clock-counter-clockwise-fill.svg?raw'\nimport EyeFillSvg from '@phosphor-icons/core/fill/eye-fill.svg?raw'\nimport EyeSlashFillSvg from '@phosphor-icons/core/fill/eye-slash-fill.svg?raw'\nimport GearFillSvg from '@phosphor-icons/core/fill/gear-fill.svg?raw'\nimport InfoFillSvg from '@phosphor-icons/core/fill/info-fill.svg?raw'\nimport MagnifyingGlassFillSvg from '@phosphor-icons/core/fill/magnifying-glass-fill.svg?raw'\nimport MinusFillSvg from '@phosphor-icons/core/fill/minus-fill.svg?raw'\nimport PlusFillSvg from '@phosphor-icons/core/fill/plus-fill.svg?raw'\nimport SpinnerFillSvg from '@phosphor-icons/core/fill/spinner-fill.svg?raw'\nimport TrashFillSvg from '@phosphor-icons/core/fill/trash-fill.svg?raw'\nimport UserFillSvg from '@phosphor-icons/core/fill/user-fill.svg?raw'\nimport WarningFillSvg from '@phosphor-icons/core/fill/warning-fill.svg?raw'\nimport XFillSvg from '@phosphor-icons/core/fill/x-fill.svg?raw'\n// bold/ — emphasis weight, used for primary actions or visually loud UI\nimport ArrowLeftBoldSvg from '@phosphor-icons/core/bold/arrow-left-bold.svg?raw'\nimport ArrowRightBoldSvg from '@phosphor-icons/core/bold/arrow-right-bold.svg?raw'\nimport BellBoldSvg from '@phosphor-icons/core/bold/bell-bold.svg?raw'\nimport CalendarBoldSvg from '@phosphor-icons/core/bold/calendar-bold.svg?raw'\nimport CaretDownBoldSvg from '@phosphor-icons/core/bold/caret-down-bold.svg?raw'\nimport CheckBoldSvg from '@phosphor-icons/core/bold/check-bold.svg?raw'\nimport ClockCounterClockwiseBoldSvg from '@phosphor-icons/core/bold/clock-counter-clockwise-bold.svg?raw'\nimport EyeBoldSvg from '@phosphor-icons/core/bold/eye-bold.svg?raw'\nimport EyeSlashBoldSvg from '@phosphor-icons/core/bold/eye-slash-bold.svg?raw'\nimport GearBoldSvg from '@phosphor-icons/core/bold/gear-bold.svg?raw'\nimport InfoBoldSvg from '@phosphor-icons/core/bold/info-bold.svg?raw'\nimport MagnifyingGlassBoldSvg from '@phosphor-icons/core/bold/magnifying-glass-bold.svg?raw'\nimport MinusBoldSvg from '@phosphor-icons/core/bold/minus-bold.svg?raw'\nimport PlusBoldSvg from '@phosphor-icons/core/bold/plus-bold.svg?raw'\nimport SpinnerBoldSvg from '@phosphor-icons/core/bold/spinner-bold.svg?raw'\nimport TrashBoldSvg from '@phosphor-icons/core/bold/trash-bold.svg?raw'\nimport UserBoldSvg from '@phosphor-icons/core/bold/user-bold.svg?raw'\nimport WarningBoldSvg from '@phosphor-icons/core/bold/warning-bold.svg?raw'\nimport XBoldSvg from '@phosphor-icons/core/bold/x-bold.svg?raw'\n\n/**\n * Sken icon names. The literal type that the SkenIcon primitive\n * accepts. Adding a new icon means adding a literal here AND a\n * row in the `REGISTRY` below — TS will catch the missing row.\n */\nexport type SkenIconName =\n | 'calendar'\n | 'user'\n | 'trash'\n | 'chevron-down'\n | 'search'\n | 'close'\n | 'eye'\n | 'eye-slash'\n | 'warning'\n | 'check'\n | 'history'\n | 'gear'\n | 'plus'\n | 'minus'\n | 'arrow-left'\n | 'arrow-right'\n | 'info'\n | 'bell'\n | 'spinner'\n\n/**\n * SkenIcon size tokens. The literal type that the SkenIcon\n * primitive accepts. Maps 1:1 to the icon-size token scale.\n */\nexport type SkenIconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * SkenIcon color tokens. The literal type that the SkenIcon\n * primitive accepts. Maps 1:1 to the icon-color token scale.\n * `'current'` is a CSS keyword (currentColor) that inherits the\n * consumer's text color — it is intentionally not a token, because\n * it is a value the consumer controls, not a Sken value.\n */\nexport type SkenIconColor =\n 'current' | 'default' | 'muted' | 'primary' | 'danger' | 'success' | 'warning' | 'info'\n\n/**\n * SkenIcon weights. The Sken-facing set of three semantic weights\n * exposed via the public API.\n *\n * - `regular` — outline weight, default. Most UI uses this.\n * - `filled` — solid weight, used for active / selected / alert\n * states (matches the Legrand Care brand guidance\n * to keep weight vocabulary simple).\n * - `emphasis` — bold weight, used for primary actions or visually\n * loud UI. Mapped to Phosphor's `bold/` subpath.\n *\n * The name `weight` (not `variant`) is deliberate: `variant` is\n * already used in Sken for component variants (e.g.\n * `<SkenButton variant=\"primary\">`); reusing it for icons would\n * overload one word with two meanings and complicate the contract\n * over time.\n */\nexport type SkenIconWeight = 'regular' | 'filled' | 'emphasis'\n\n/**\n * One icon's worth of SVG strings, one per weight. The three\n * SVG paths can come from any source (vendor, internal asset,\n * Figma export, third-party set). `IconAsset` is the internal\n * shape; the consumer never imports this type — they go through\n * `SkenIconName` and `getSkenIconSvg(name, weight)`.\n */\ninterface IconAsset {\n regular: string\n filled: string\n emphasis: string\n}\n\n/**\n * The catalog. A Record from each semantic name to its three\n * SVGs. This is the only place a vendor swap touches: change the\n * import paths at the top of the file and the asset values here,\n * nothing else moves. The Web Component API stays the same.\n */\nconst REGISTRY: Record<SkenIconName, IconAsset> = {\n 'arrow-left': {\n regular: ArrowLeftRegularSvg,\n filled: ArrowLeftFillSvg,\n emphasis: ArrowLeftBoldSvg,\n },\n 'arrow-right': {\n regular: ArrowRightRegularSvg,\n filled: ArrowRightFillSvg,\n emphasis: ArrowRightBoldSvg,\n },\n bell: {\n regular: BellRegularSvg,\n filled: BellFillSvg,\n emphasis: BellBoldSvg,\n },\n calendar: {\n regular: CalendarRegularSvg,\n filled: CalendarFillSvg,\n emphasis: CalendarBoldSvg,\n },\n 'chevron-down': {\n regular: CaretDownRegularSvg,\n filled: CaretDownFillSvg,\n emphasis: CaretDownBoldSvg,\n },\n check: {\n regular: CheckRegularSvg,\n filled: CheckFillSvg,\n emphasis: CheckBoldSvg,\n },\n close: {\n regular: XRegularSvg,\n filled: XFillSvg,\n emphasis: XBoldSvg,\n },\n eye: {\n regular: EyeRegularSvg,\n filled: EyeFillSvg,\n emphasis: EyeBoldSvg,\n },\n 'eye-slash': {\n regular: EyeSlashRegularSvg,\n filled: EyeSlashFillSvg,\n emphasis: EyeSlashBoldSvg,\n },\n gear: {\n regular: GearRegularSvg,\n filled: GearFillSvg,\n emphasis: GearBoldSvg,\n },\n history: {\n regular: ClockCounterClockwiseRegularSvg,\n filled: ClockCounterClockwiseFillSvg,\n emphasis: ClockCounterClockwiseBoldSvg,\n },\n info: {\n regular: InfoRegularSvg,\n filled: InfoFillSvg,\n emphasis: InfoBoldSvg,\n },\n minus: {\n regular: MinusRegularSvg,\n filled: MinusFillSvg,\n emphasis: MinusBoldSvg,\n },\n plus: {\n regular: PlusRegularSvg,\n filled: PlusFillSvg,\n emphasis: PlusBoldSvg,\n },\n search: {\n regular: MagnifyingGlassRegularSvg,\n filled: MagnifyingGlassFillSvg,\n emphasis: MagnifyingGlassBoldSvg,\n },\n spinner: {\n regular: SpinnerRegularSvg,\n filled: SpinnerFillSvg,\n emphasis: SpinnerBoldSvg,\n },\n trash: {\n regular: TrashRegularSvg,\n filled: TrashFillSvg,\n emphasis: TrashBoldSvg,\n },\n user: {\n regular: UserRegularSvg,\n filled: UserFillSvg,\n emphasis: UserBoldSvg,\n },\n warning: {\n regular: WarningRegularSvg,\n filled: WarningFillSvg,\n emphasis: WarningBoldSvg,\n },\n}\n\n/**\n * Get the vendor SVG for a Sken icon name and weight. Returns the\n * `regular` weight by default. Runtime-based: the `name` arrives\n * at runtime (an HTML attribute the consumer sets), so Rollup\n * cannot statically resolve which case of the switch runs, and\n * the full 48-SVG catalog ships in the primitive's bundle\n * (~21 KB raw, ~5 KB gzip). See the file-level \"Bundle-cost note\"\n * for the rationale and the future per-icon-module escape hatch.\n *\n * The body is a single Record lookup, not a 16-case switch.\n * Replacing the vendor (Phosphor today, internal SVGs tomorrow,\n * a third-party set the day after) is a change to the `REGISTRY`\n * literal above and to the imports at the top of the file. The\n * Web Component API does not change.\n */\nexport function getSkenIconSvg(name: SkenIconName, weight: SkenIconWeight = 'regular'): string {\n return REGISTRY[name][weight]\n}\n\n/**\n * True if the given name is a known Sken icon. The SkenIcon\n * primitive uses this to throw `SkenIconError: icon \"x\" not in\n * catalog` for unknown names, rather than render a broken icon\n * (which is what the vendor-based primitives used to do).\n */\nexport function isSkenIconName(name: string): name is SkenIconName {\n return (\n name === 'calendar' ||\n name === 'user' ||\n name === 'trash' ||\n name === 'chevron-down' ||\n name === 'search' ||\n name === 'close' ||\n name === 'eye' ||\n name === 'eye-slash' ||\n name === 'warning' ||\n name === 'check' ||\n name === 'history' ||\n name === 'gear' ||\n name === 'plus' ||\n name === 'minus' ||\n name === 'arrow-left' ||\n name === 'arrow-right' ||\n name === 'info' ||\n name === 'bell' ||\n name === 'spinner'\n )\n}\n"],"mappings":";;AAkOA,IAAM,IAA4C;CAChD,cAAc;EACZ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,eAAe;EACb,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,UAAU;EACR,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,gBAAgB;EACd,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,KAAK;EACH,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,aAAa;EACX,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,QAAQ;EACN,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;AACF;AAiBA,SAAgB,EAAe,GAAoB,IAAyB,WAAmB;CAC7F,OAAO,EAAS,EAAK,CAAC;AACxB;AAQA,SAAgB,EAAe,GAAoC;CACjE,OACE,MAAS,cACT,MAAS,UACT,MAAS,WACT,MAAS,kBACT,MAAS,YACT,MAAS,WACT,MAAS,SACT,MAAS,eACT,MAAS,aACT,MAAS,WACT,MAAS,aACT,MAAS,UACT,MAAS,UACT,MAAS,WACT,MAAS,gBACT,MAAS,iBACT,MAAS,UACT,MAAS,UACT,MAAS;AAEb"}
|
|
1
|
+
{"version":3,"file":"catalog-C0MX2DSN.js","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["/**\n * Sken icon catalog (ADR-0011).\n *\n * The icon family is Sken-owned. The set of semantic names is curated\n * here, the mapping from each name to a vendor SVG is curated here,\n * and the consumer never sees the vendor. To swap the vendor (or to\n * use a custom SVG), this file is the only place that changes.\n *\n * Vendor-agnostic by construction. The catalog is a `Record` of\n * semantic names to `IconAsset` records. The asset records point\n * to SVG strings imported as `?raw` from any path: a vendor\n * package (`@phosphor-icons/core/...`), a Figma export, an\n * internally drawn icon, a third-party set, or a mix of all of\n * the above. The Web Component API (`<SkenIcon name=\"...\" weight=\"...\" />`)\n * is the same regardless of where the SVG came from. Replacing the\n * vendor is an import-path swap in the `REGISTRY` literal below;\n * no consumer code moves.\n *\n * Bundle-cost note (revised 2026-07-28). The icon registry is\n * intentionally **runtime-based**, not tree-shakeable. The consumer\n * API is `<SkenIcon name=\"...\" weight=\"...\" />` where the `name`\n * arrives at runtime (it is an HTML attribute the user can type).\n * Rollup cannot statically resolve which case of the switch will\n * run, so the bundler keeps all 48 SVG strings (~21 KB raw,\n * ~5 KB gzip) in the primitive's bundle. Earlier versions of this\n * comment claimed that the per-case import structure was\n * tree-shakeable; that was wrong, and the inaccuracy was\n * introduced when the per-weight imports were added in this round.\n *\n * Why runtime and not build-time. The two real options for an icon\n * library are:\n *\n * - **Per-icon module** (Radix Icons, Lucide, Heroicons):\n * `<SkenCheckIcon />` imported from `@sken-ds/icons/check`. This\n * IS tree-shakeable but it forces the consumer to learn one\n * import per icon, and it makes a runtime-driven API\n * (`<sken-icon name=\"check\">`) impossible without lazy loading.\n * Sken is a design system; its API stability is worth more\n * than the per-icon bundle saving. The curated catalog is\n * small (16 names × 3 weights = 48 SVGs) and the runtime\n * cost (~5 KB gzip) is in the same league as `floating-ui`\n * or a `date-fns` locale.\n *\n * - **Runtime registry** (this file): one primitive, one\n * `getSkenIconSvg(name, weight)` lookup, 48 static imports.\n * Vendor-agnostic, name-agnostic, theme-agnostic. The\n * consumer writes the same `<SkenIcon name=\"...\" />` they\n * would have written anyway. The implementation can change\n * to per-icon modules in a future iteration without touching\n * the consumer surface.\n *\n * The decision is documented in the Status note of ADR-0011\n * (\"Runtime registry: why the icon catalog is not tree-shakeable\",\n * added 2026-07-28).\n *\n * Naming convention: the semantic name is a Sken decision, not a\n * Phosphor decision. We use `calendar` (not `ph-calendar`), `user`\n * (not `ph-user`), and so on. The vendor class is internal.\n *\n * Weight convention: Sken exposes three weights — `regular`,\n * `filled`, `emphasis` — to match the 95% of UI usage outlined\n * in the Icon weights section of ADR-0011. Phosphor offers six\n * (`thin`, `light`, `regular`, `bold`, `fill`, `duotone`); the\n * other three are not exposed because the Legrand Care brand does\n * not need them and exposing them would force the consumer to know\n * Phosphor's vocabulary. The mapping is:\n *\n * Sken weight → Phosphor subpath\n * `regular` → `regular/`\n * `filled` → `fill/`\n * `emphasis` → `bold/`\n *\n * Adding a new icon:\n * 1. Pick a semantic name (e.g. `user` for a generic avatar\n * icon, not `ph-user`). If the icon represents a new\n * concept, add the literal to `SkenIconName` below.\n * 2. Add three imports (one per weight) pointing to the\n * chosen SVG. The path is whatever the team decides: a\n * vendor subpath, an internal asset folder, a Figma\n * export, etc. Vite's `?raw` query makes any of these\n * work the same.\n * 3. Add a row to the `REGISTRY` literal mapping the name\n * to `{ regular, filled, emphasis }`. TypeScript will\n * catch a missing weight or a typo in the property name.\n */\n// regular/ — default weight, used for most UI\nimport ArrowLeftRegularSvg from '@phosphor-icons/core/regular/arrow-left.svg?raw'\nimport ArrowRightRegularSvg from '@phosphor-icons/core/regular/arrow-right.svg?raw'\nimport BellRegularSvg from '@phosphor-icons/core/regular/bell.svg?raw'\nimport CalendarRegularSvg from '@phosphor-icons/core/regular/calendar.svg?raw'\nimport CaretDownRegularSvg from '@phosphor-icons/core/regular/caret-down.svg?raw'\nimport CheckRegularSvg from '@phosphor-icons/core/regular/check.svg?raw'\nimport ClockCounterClockwiseRegularSvg from '@phosphor-icons/core/regular/clock-counter-clockwise.svg?raw'\nimport EyeSlashRegularSvg from '@phosphor-icons/core/regular/eye-slash.svg?raw'\nimport EyeRegularSvg from '@phosphor-icons/core/regular/eye.svg?raw'\nimport GearRegularSvg from '@phosphor-icons/core/regular/gear.svg?raw'\nimport InfoRegularSvg from '@phosphor-icons/core/regular/info.svg?raw'\nimport MagnifyingGlassRegularSvg from '@phosphor-icons/core/regular/magnifying-glass.svg?raw'\nimport MinusRegularSvg from '@phosphor-icons/core/regular/minus.svg?raw'\nimport PlusRegularSvg from '@phosphor-icons/core/regular/plus.svg?raw'\nimport SpinnerRegularSvg from '@phosphor-icons/core/regular/spinner.svg?raw'\nimport TrashRegularSvg from '@phosphor-icons/core/regular/trash.svg?raw'\nimport UserRegularSvg from '@phosphor-icons/core/regular/user.svg?raw'\nimport WarningRegularSvg from '@phosphor-icons/core/regular/warning.svg?raw'\nimport XRegularSvg from '@phosphor-icons/core/regular/x.svg?raw'\n// fill/ — filled weight, used for active/selected/alert states\nimport ArrowLeftFillSvg from '@phosphor-icons/core/fill/arrow-left-fill.svg?raw'\nimport ArrowRightFillSvg from '@phosphor-icons/core/fill/arrow-right-fill.svg?raw'\nimport BellFillSvg from '@phosphor-icons/core/fill/bell-fill.svg?raw'\nimport CalendarFillSvg from '@phosphor-icons/core/fill/calendar-fill.svg?raw'\nimport CaretDownFillSvg from '@phosphor-icons/core/fill/caret-down-fill.svg?raw'\nimport CheckFillSvg from '@phosphor-icons/core/fill/check-fill.svg?raw'\nimport ClockCounterClockwiseFillSvg from '@phosphor-icons/core/fill/clock-counter-clockwise-fill.svg?raw'\nimport EyeFillSvg from '@phosphor-icons/core/fill/eye-fill.svg?raw'\nimport EyeSlashFillSvg from '@phosphor-icons/core/fill/eye-slash-fill.svg?raw'\nimport GearFillSvg from '@phosphor-icons/core/fill/gear-fill.svg?raw'\nimport InfoFillSvg from '@phosphor-icons/core/fill/info-fill.svg?raw'\nimport MagnifyingGlassFillSvg from '@phosphor-icons/core/fill/magnifying-glass-fill.svg?raw'\nimport MinusFillSvg from '@phosphor-icons/core/fill/minus-fill.svg?raw'\nimport PlusFillSvg from '@phosphor-icons/core/fill/plus-fill.svg?raw'\nimport SpinnerFillSvg from '@phosphor-icons/core/fill/spinner-fill.svg?raw'\nimport TrashFillSvg from '@phosphor-icons/core/fill/trash-fill.svg?raw'\nimport UserFillSvg from '@phosphor-icons/core/fill/user-fill.svg?raw'\nimport WarningFillSvg from '@phosphor-icons/core/fill/warning-fill.svg?raw'\nimport XFillSvg from '@phosphor-icons/core/fill/x-fill.svg?raw'\n// bold/ — emphasis weight, used for primary actions or visually loud UI\nimport ArrowLeftBoldSvg from '@phosphor-icons/core/bold/arrow-left-bold.svg?raw'\nimport ArrowRightBoldSvg from '@phosphor-icons/core/bold/arrow-right-bold.svg?raw'\nimport BellBoldSvg from '@phosphor-icons/core/bold/bell-bold.svg?raw'\nimport CalendarBoldSvg from '@phosphor-icons/core/bold/calendar-bold.svg?raw'\nimport CaretDownBoldSvg from '@phosphor-icons/core/bold/caret-down-bold.svg?raw'\nimport CheckBoldSvg from '@phosphor-icons/core/bold/check-bold.svg?raw'\nimport ClockCounterClockwiseBoldSvg from '@phosphor-icons/core/bold/clock-counter-clockwise-bold.svg?raw'\nimport EyeBoldSvg from '@phosphor-icons/core/bold/eye-bold.svg?raw'\nimport EyeSlashBoldSvg from '@phosphor-icons/core/bold/eye-slash-bold.svg?raw'\nimport GearBoldSvg from '@phosphor-icons/core/bold/gear-bold.svg?raw'\nimport InfoBoldSvg from '@phosphor-icons/core/bold/info-bold.svg?raw'\nimport MagnifyingGlassBoldSvg from '@phosphor-icons/core/bold/magnifying-glass-bold.svg?raw'\nimport MinusBoldSvg from '@phosphor-icons/core/bold/minus-bold.svg?raw'\nimport PlusBoldSvg from '@phosphor-icons/core/bold/plus-bold.svg?raw'\nimport SpinnerBoldSvg from '@phosphor-icons/core/bold/spinner-bold.svg?raw'\nimport TrashBoldSvg from '@phosphor-icons/core/bold/trash-bold.svg?raw'\nimport UserBoldSvg from '@phosphor-icons/core/bold/user-bold.svg?raw'\nimport WarningBoldSvg from '@phosphor-icons/core/bold/warning-bold.svg?raw'\nimport XBoldSvg from '@phosphor-icons/core/bold/x-bold.svg?raw'\n\n/**\n * Sken icon names. The literal type that the SkenIcon primitive\n * accepts. Adding a new icon means adding a literal here AND a\n * row in the `REGISTRY` below — TS will catch the missing row.\n */\nexport type SkenIconName =\n | 'calendar'\n | 'user'\n | 'trash'\n | 'chevron-down'\n | 'search'\n | 'close'\n | 'eye'\n | 'eye-slash'\n | 'warning'\n | 'check'\n | 'history'\n | 'gear'\n | 'plus'\n | 'minus'\n | 'arrow-left'\n | 'arrow-right'\n | 'info'\n | 'bell'\n | 'spinner'\n\n/**\n * SkenIcon size tokens. The literal type that the SkenIcon\n * primitive accepts. Maps 1:1 to the icon-size token scale.\n */\nexport type SkenIconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * SkenIcon color tokens. The literal type that the SkenIcon\n * primitive accepts. Maps 1:1 to the icon-color token scale.\n * `'current'` is a CSS keyword (currentColor) that inherits the\n * consumer's text color — it is intentionally not a token, because\n * it is a value the consumer controls, not a Sken value.\n */\nexport type SkenIconColor =\n 'current' | 'default' | 'muted' | 'primary' | 'danger' | 'success' | 'warning' | 'info'\n\n/**\n * SkenIcon weights. The Sken-facing set of three semantic weights\n * exposed via the public API.\n *\n * - `regular` — outline weight, default. Most UI uses this.\n * - `filled` — solid weight, used for active / selected / alert\n * states (matches the Legrand Care brand guidance\n * to keep weight vocabulary simple).\n * - `emphasis` — bold weight, used for primary actions or visually\n * loud UI. Mapped to Phosphor's `bold/` subpath.\n *\n * The name `weight` (not `variant`) is deliberate: `variant` is\n * already used in Sken for component variants (e.g.\n * `<SkenButton variant=\"primary\">`); reusing it for icons would\n * overload one word with two meanings and complicate the contract\n * over time.\n */\nexport type SkenIconWeight = 'regular' | 'filled' | 'emphasis'\n\n/**\n * One icon's worth of SVG strings, one per weight. The three\n * SVG paths can come from any source (vendor, internal asset,\n * Figma export, third-party set). `IconAsset` is the internal\n * shape; the consumer never imports this type — they go through\n * `SkenIconName` and `getSkenIconSvg(name, weight)`.\n */\ninterface IconAsset {\n regular: string\n filled: string\n emphasis: string\n}\n\n/**\n * The catalog. A Record from each semantic name to its three\n * SVGs. This is the only place a vendor swap touches: change the\n * import paths at the top of the file and the asset values here,\n * nothing else moves. The Web Component API stays the same.\n */\nconst REGISTRY: Record<SkenIconName, IconAsset> = {\n 'arrow-left': {\n regular: ArrowLeftRegularSvg,\n filled: ArrowLeftFillSvg,\n emphasis: ArrowLeftBoldSvg,\n },\n 'arrow-right': {\n regular: ArrowRightRegularSvg,\n filled: ArrowRightFillSvg,\n emphasis: ArrowRightBoldSvg,\n },\n bell: {\n regular: BellRegularSvg,\n filled: BellFillSvg,\n emphasis: BellBoldSvg,\n },\n calendar: {\n regular: CalendarRegularSvg,\n filled: CalendarFillSvg,\n emphasis: CalendarBoldSvg,\n },\n 'chevron-down': {\n regular: CaretDownRegularSvg,\n filled: CaretDownFillSvg,\n emphasis: CaretDownBoldSvg,\n },\n check: {\n regular: CheckRegularSvg,\n filled: CheckFillSvg,\n emphasis: CheckBoldSvg,\n },\n close: {\n regular: XRegularSvg,\n filled: XFillSvg,\n emphasis: XBoldSvg,\n },\n eye: {\n regular: EyeRegularSvg,\n filled: EyeFillSvg,\n emphasis: EyeBoldSvg,\n },\n 'eye-slash': {\n regular: EyeSlashRegularSvg,\n filled: EyeSlashFillSvg,\n emphasis: EyeSlashBoldSvg,\n },\n gear: {\n regular: GearRegularSvg,\n filled: GearFillSvg,\n emphasis: GearBoldSvg,\n },\n history: {\n regular: ClockCounterClockwiseRegularSvg,\n filled: ClockCounterClockwiseFillSvg,\n emphasis: ClockCounterClockwiseBoldSvg,\n },\n info: {\n regular: InfoRegularSvg,\n filled: InfoFillSvg,\n emphasis: InfoBoldSvg,\n },\n minus: {\n regular: MinusRegularSvg,\n filled: MinusFillSvg,\n emphasis: MinusBoldSvg,\n },\n plus: {\n regular: PlusRegularSvg,\n filled: PlusFillSvg,\n emphasis: PlusBoldSvg,\n },\n search: {\n regular: MagnifyingGlassRegularSvg,\n filled: MagnifyingGlassFillSvg,\n emphasis: MagnifyingGlassBoldSvg,\n },\n spinner: {\n regular: SpinnerRegularSvg,\n filled: SpinnerFillSvg,\n emphasis: SpinnerBoldSvg,\n },\n trash: {\n regular: TrashRegularSvg,\n filled: TrashFillSvg,\n emphasis: TrashBoldSvg,\n },\n user: {\n regular: UserRegularSvg,\n filled: UserFillSvg,\n emphasis: UserBoldSvg,\n },\n warning: {\n regular: WarningRegularSvg,\n filled: WarningFillSvg,\n emphasis: WarningBoldSvg,\n },\n}\n\n/**\n * Get the vendor SVG for a Sken icon name and weight. Returns the\n * `regular` weight by default. Runtime-based: the `name` arrives\n * at runtime (an HTML attribute the consumer sets), so Rollup\n * cannot statically resolve which case of the switch runs, and\n * the full 48-SVG catalog ships in the primitive's bundle\n * (~21 KB raw, ~5 KB gzip). See the file-level \"Bundle-cost note\"\n * for the rationale and the future per-icon-module escape hatch.\n *\n * The body is a single Record lookup, not a 16-case switch.\n * Replacing the vendor (Phosphor today, internal SVGs tomorrow,\n * a third-party set the day after) is a change to the `REGISTRY`\n * literal above and to the imports at the top of the file. The\n * Web Component API does not change.\n */\nexport function getSkenIconSvg(name: SkenIconName, weight: SkenIconWeight = 'regular'): string {\n return REGISTRY[name][weight]\n}\n\n/**\n * True if the given name is a known Sken icon. The SkenIcon\n * primitive uses this to throw `SkenIconError: icon \"x\" not in\n * catalog` for unknown names, rather than render a broken icon\n * (which is what the vendor-based primitives used to do).\n */\nexport function isSkenIconName(name: string): name is SkenIconName {\n return (\n name === 'calendar' ||\n name === 'user' ||\n name === 'trash' ||\n name === 'chevron-down' ||\n name === 'search' ||\n name === 'close' ||\n name === 'eye' ||\n name === 'eye-slash' ||\n name === 'warning' ||\n name === 'check' ||\n name === 'history' ||\n name === 'gear' ||\n name === 'plus' ||\n name === 'minus' ||\n name === 'arrow-left' ||\n name === 'arrow-right' ||\n name === 'info' ||\n name === 'bell' ||\n name === 'spinner'\n )\n}\n"],"mappings":";;AAkOA,IAAM,IAA4C;CAChD,cAAc;EACZ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,eAAe;EACb,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,UAAU;EACR,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,gBAAgB;EACd,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,KAAK;EACH,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,aAAa;EACX,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,QAAQ;EACN,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,OAAO;EACL,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,MAAM;EACJ,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;CACA,SAAS;EACP,SAAS;EACT,QAAQ;EACR,UAAU;CACZ;AACF;AAiBA,SAAgB,EAAe,GAAoB,IAAyB,WAAmB;CAC7F,OAAO,EAAS,EAAK,CAAC;AACxB;AAQA,SAAgB,EAAe,GAAoC;CACjE,OACE,MAAS,cACT,MAAS,UACT,MAAS,WACT,MAAS,kBACT,MAAS,YACT,MAAS,WACT,MAAS,SACT,MAAS,eACT,MAAS,aACT,MAAS,WACT,MAAS,aACT,MAAS,UACT,MAAS,UACT,MAAS,WACT,MAAS,gBACT,MAAS,iBACT,MAAS,UACT,MAAS,UACT,MAAS;AAEb"}
|
package/dist/sken-icon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sken-icon.d.ts","sourceRoot":"","sources":["../src/sken-icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAA;AAE3C,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,cAAc,CAAA;AAErB,qBACa,QAAS,SAAQ,UAAU;IACtC,kEAAkE;IAElE,IAAI,EAAE,YAAY,CAAU;IAE5B,gEAAgE;IAEhE,IAAI,EAAE,YAAY,CAAO;IAEzB;;;;OAIG;IAEH,KAAK,EAAE,aAAa,CAAY;IAEhC;;;;;;;;;;;OAWG;IAEH,MAAM,EAAE,cAAc,CAAY;IAElC;;;;OAIG;IAEH,UAAU,UAAO;IAEjB;;;;OAIG;IAEH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAO;IAE/B,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"sken-icon.d.ts","sourceRoot":"","sources":["../src/sken-icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAA;AAE3C,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,cAAc,CAAA;AAErB,qBACa,QAAS,SAAQ,UAAU;IACtC,kEAAkE;IAElE,IAAI,EAAE,YAAY,CAAU;IAE5B,gEAAgE;IAEhE,IAAI,EAAE,YAAY,CAAO;IAEzB;;;;OAIG;IAEH,KAAK,EAAE,aAAa,CAAY;IAEhC;;;;;;;;;;;OAWG;IAEH,MAAM,EAAE,cAAc,CAAY;IAElC;;;;OAIG;IAEH,UAAU,UAAO;IAEjB;;;;OAIG;IAEH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAO;IAE/B,MAAM,CAAC,MAAM,0BAyFZ;cAEkB,MAAM;CAwB1B;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAA;KACtB;CACF"}
|
package/dist/sken-icon.js
CHANGED
|
@@ -86,8 +86,12 @@ var c = class extends n {
|
|
|
86
86
|
spins. We honour prefers-reduced-motion at the host level
|
|
87
87
|
(a global opt-out for users who do not want animation). */
|
|
88
88
|
@keyframes sken-icon-spin {
|
|
89
|
-
from {
|
|
90
|
-
|
|
89
|
+
from {
|
|
90
|
+
transform: rotate(0deg);
|
|
91
|
+
}
|
|
92
|
+
to {
|
|
93
|
+
transform: rotate(360deg);
|
|
94
|
+
}
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
:host([name='spinner']) .sken-icon-svg {
|
package/dist/sken-icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sken-icon.js","names":[],"sources":["../src/sken-icon.ts"],"sourcesContent":["/**\n * <sken-icon> — Sken icon primitive (ADR-0011).\n *\n * The single public surface for icons. The consumer passes a\n * `name` from the Sken catalog; the primitive looks up the\n * vendor SVG in the catalog and renders it inline. The\n * consumer never imports a vendor name.\n *\n * Three design rules from ADR-0011:\n *\n * 1. Sken owns the icon set. The vendor (Phosphor) is\n * internal. New icons are added to\n * `packages/icons/src/catalog.ts`; the consumer does not\n * move.\n *\n * 2. Size and color come from Sken tokens. Not from vendor\n * CSS classes. `font-size: var(--sken-icon-size-md)` is\n * applied via the host element; `color: var(--sken-icon-color-default)`\n * via the SVG. Both are overridable by the consumer via\n * `size` and `color` props.\n *\n * 2b. Weight is a vendor-shape choice, not a token. The\n * consumer passes `weight=\"regular\" | \"filled\" | \"emphasis\"`\n * and the primitive picks the right vendor subpath. The\n * mapping (`emphasis` → `bold/`, etc.) is internal. This\n * split keeps design tokens for what the brand varies\n * (size, color) and props for what the resource is\n * (regular vs filled drawing).\n *\n * 3. A11y is per-icon. By default an icon is decorative and\n * gets `aria-hidden=\"true\"`. If the icon conveys meaning,\n * the consumer sets `aria-label` and the primitive\n * switches to role=\"img\" and emits a `<title>` for\n * assistive tech. The two states are mutually exclusive at\n * the type level.\n *\n * 4. The bundle cost is intentional. The catalog is\n * runtime-based: every `<SkenIcon>` instance ships the full\n * curated catalog (16 icons × 3 weights = 48 SVGs, ~5 KB\n * gzip). This is a deliberate trade-off — API stability and\n * vendor-agnosticity over per-icon bundle optimisation. See\n * the file-level Bundle-cost note in `catalog.ts` and the\n * Status note \"Runtime registry\" in ADR-0011.\n *\n * The SVG is rendered as `innerHTML` on a `<div>` host. The\n * string comes from the catalog (a Sken-owned JS module) and\n * is therefore a known constant. Vite does not bundle raw\n * SVGs as assets in this path; the SVG text becomes a JS\n * string that the consumer's HTML parser interprets. The\n * only security risk would be if a future contributor\n * modified the catalog to include untrusted content, which\n * the file's leading comment forbids.\n */\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport {\n getSkenIconSvg,\n isSkenIconName,\n type SkenIconColor,\n type SkenIconName,\n type SkenIconSize,\n type SkenIconWeight,\n} from './catalog.js'\n\n@customElement('sken-icon')\nexport class SkenIcon extends LitElement {\n /** The semantic icon name. Must be a key of the ICONS catalog. */\n @property({ reflect: true })\n name: SkenIconName = 'check'\n\n /** The icon size. Maps 1:1 to the --sken-icon-size-* tokens. */\n @property({ reflect: true })\n size: SkenIconSize = 'md'\n\n /**\n * The icon color. 'current' inherits the consumer's text color\n * (the default — icons usually follow text colour). The other\n * values map to the --sken-icon-color-* tokens.\n */\n @property({ reflect: true })\n color: SkenIconColor = 'current'\n\n /**\n * The icon weight. Maps to a Phosphor subpath:\n * `regular` → `regular/` (default — outline, most UI)\n * `filled` → `fill/` (solid, active / selected / alert)\n * `emphasis` → `bold/` (visually loud, primary actions)\n *\n * The vocabulary is Sken's, not Phosphor's. The name `weight`\n * is deliberate: `variant` is reserved in Sken for component\n * variants (e.g. `<SkenButton variant=\"primary\">`) and reusing\n * it for icons would overload one word with two meanings.\n * See the Icon weights section of ADR-0011 for the rationale.\n */\n @property({ reflect: true })\n weight: SkenIconWeight = 'regular'\n\n /**\n * When true (the default), the icon is decorative and gets\n * aria-hidden=\"true\". Set to false and provide `ariaLabel` to\n * make the icon meaningful to assistive tech.\n */\n @property({ reflect: true, type: Boolean })\n decorative = true\n\n /**\n * Accessible label for the icon. Only used when `decorative`\n * is false. When set, the primitive emits role=\"img\" and a\n * <title> child for screen readers.\n */\n @property({ attribute: 'aria-label' })\n ariaLabel: string | null = null\n\n static styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n line-height: 1;\n /* Size: defaults to md. The size attribute on the host\n overrides via the inline style set in render(). */\n font-size: var(--sken-icon-size-md);\n width: 1em;\n height: 1em;\n }\n\n :host([size='xs']) {\n font-size: var(--sken-icon-size-xs);\n }\n :host([size='sm']) {\n font-size: var(--sken-icon-size-sm);\n }\n :host([size='md']) {\n font-size: var(--sken-icon-size-md);\n }\n :host([size='lg']) {\n font-size: var(--sken-icon-size-lg);\n }\n :host([size='xl']) {\n font-size: var(--sken-icon-size-xl);\n }\n\n :host([color='current']) {\n color: inherit;\n }\n :host([color='default']) {\n color: var(--sken-icon-color-default);\n }\n :host([color='muted']) {\n color: var(--sken-icon-color-muted);\n }\n :host([color='primary']) {\n color: var(--sken-icon-color-primary);\n }\n :host([color='danger']) {\n color: var(--sken-icon-color-danger);\n }\n :host([color='success']) {\n color: var(--sken-icon-color-success);\n }\n :host([color='warning']) {\n color: var(--sken-icon-color-warning);\n }\n :host([color='info']) {\n color: var(--sken-icon-color-info);\n }\n\n .sken-icon-svg {\n width: 1em;\n height: 1em;\n display: block;\n fill: currentColor;\n }\n\n /* The spinner is the only icon in the curated catalog with\n an intrinsic motion. The animation lives in the icon's\n own stylesheet (not the consumer's, not the datatable's)\n because the rotation is part of what the name \"spinner\"\n *means* — a static spinner would be a different icon. The\n consumer does not opt in: any <sken-icon name=\"spinner\">\n spins. We honour prefers-reduced-motion at the host level\n (a global opt-out for users who do not want animation). */\n @keyframes sken-icon-spin {\n from {
|
|
1
|
+
{"version":3,"file":"sken-icon.js","names":[],"sources":["../src/sken-icon.ts"],"sourcesContent":["/**\n * <sken-icon> — Sken icon primitive (ADR-0011).\n *\n * The single public surface for icons. The consumer passes a\n * `name` from the Sken catalog; the primitive looks up the\n * vendor SVG in the catalog and renders it inline. The\n * consumer never imports a vendor name.\n *\n * Three design rules from ADR-0011:\n *\n * 1. Sken owns the icon set. The vendor (Phosphor) is\n * internal. New icons are added to\n * `packages/icons/src/catalog.ts`; the consumer does not\n * move.\n *\n * 2. Size and color come from Sken tokens. Not from vendor\n * CSS classes. `font-size: var(--sken-icon-size-md)` is\n * applied via the host element; `color: var(--sken-icon-color-default)`\n * via the SVG. Both are overridable by the consumer via\n * `size` and `color` props.\n *\n * 2b. Weight is a vendor-shape choice, not a token. The\n * consumer passes `weight=\"regular\" | \"filled\" | \"emphasis\"`\n * and the primitive picks the right vendor subpath. The\n * mapping (`emphasis` → `bold/`, etc.) is internal. This\n * split keeps design tokens for what the brand varies\n * (size, color) and props for what the resource is\n * (regular vs filled drawing).\n *\n * 3. A11y is per-icon. By default an icon is decorative and\n * gets `aria-hidden=\"true\"`. If the icon conveys meaning,\n * the consumer sets `aria-label` and the primitive\n * switches to role=\"img\" and emits a `<title>` for\n * assistive tech. The two states are mutually exclusive at\n * the type level.\n *\n * 4. The bundle cost is intentional. The catalog is\n * runtime-based: every `<SkenIcon>` instance ships the full\n * curated catalog (16 icons × 3 weights = 48 SVGs, ~5 KB\n * gzip). This is a deliberate trade-off — API stability and\n * vendor-agnosticity over per-icon bundle optimisation. See\n * the file-level Bundle-cost note in `catalog.ts` and the\n * Status note \"Runtime registry\" in ADR-0011.\n *\n * The SVG is rendered as `innerHTML` on a `<div>` host. The\n * string comes from the catalog (a Sken-owned JS module) and\n * is therefore a known constant. Vite does not bundle raw\n * SVGs as assets in this path; the SVG text becomes a JS\n * string that the consumer's HTML parser interprets. The\n * only security risk would be if a future contributor\n * modified the catalog to include untrusted content, which\n * the file's leading comment forbids.\n */\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport {\n getSkenIconSvg,\n isSkenIconName,\n type SkenIconColor,\n type SkenIconName,\n type SkenIconSize,\n type SkenIconWeight,\n} from './catalog.js'\n\n@customElement('sken-icon')\nexport class SkenIcon extends LitElement {\n /** The semantic icon name. Must be a key of the ICONS catalog. */\n @property({ reflect: true })\n name: SkenIconName = 'check'\n\n /** The icon size. Maps 1:1 to the --sken-icon-size-* tokens. */\n @property({ reflect: true })\n size: SkenIconSize = 'md'\n\n /**\n * The icon color. 'current' inherits the consumer's text color\n * (the default — icons usually follow text colour). The other\n * values map to the --sken-icon-color-* tokens.\n */\n @property({ reflect: true })\n color: SkenIconColor = 'current'\n\n /**\n * The icon weight. Maps to a Phosphor subpath:\n * `regular` → `regular/` (default — outline, most UI)\n * `filled` → `fill/` (solid, active / selected / alert)\n * `emphasis` → `bold/` (visually loud, primary actions)\n *\n * The vocabulary is Sken's, not Phosphor's. The name `weight`\n * is deliberate: `variant` is reserved in Sken for component\n * variants (e.g. `<SkenButton variant=\"primary\">`) and reusing\n * it for icons would overload one word with two meanings.\n * See the Icon weights section of ADR-0011 for the rationale.\n */\n @property({ reflect: true })\n weight: SkenIconWeight = 'regular'\n\n /**\n * When true (the default), the icon is decorative and gets\n * aria-hidden=\"true\". Set to false and provide `ariaLabel` to\n * make the icon meaningful to assistive tech.\n */\n @property({ reflect: true, type: Boolean })\n decorative = true\n\n /**\n * Accessible label for the icon. Only used when `decorative`\n * is false. When set, the primitive emits role=\"img\" and a\n * <title> child for screen readers.\n */\n @property({ attribute: 'aria-label' })\n ariaLabel: string | null = null\n\n static styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n line-height: 1;\n /* Size: defaults to md. The size attribute on the host\n overrides via the inline style set in render(). */\n font-size: var(--sken-icon-size-md);\n width: 1em;\n height: 1em;\n }\n\n :host([size='xs']) {\n font-size: var(--sken-icon-size-xs);\n }\n :host([size='sm']) {\n font-size: var(--sken-icon-size-sm);\n }\n :host([size='md']) {\n font-size: var(--sken-icon-size-md);\n }\n :host([size='lg']) {\n font-size: var(--sken-icon-size-lg);\n }\n :host([size='xl']) {\n font-size: var(--sken-icon-size-xl);\n }\n\n :host([color='current']) {\n color: inherit;\n }\n :host([color='default']) {\n color: var(--sken-icon-color-default);\n }\n :host([color='muted']) {\n color: var(--sken-icon-color-muted);\n }\n :host([color='primary']) {\n color: var(--sken-icon-color-primary);\n }\n :host([color='danger']) {\n color: var(--sken-icon-color-danger);\n }\n :host([color='success']) {\n color: var(--sken-icon-color-success);\n }\n :host([color='warning']) {\n color: var(--sken-icon-color-warning);\n }\n :host([color='info']) {\n color: var(--sken-icon-color-info);\n }\n\n .sken-icon-svg {\n width: 1em;\n height: 1em;\n display: block;\n fill: currentColor;\n }\n\n /* The spinner is the only icon in the curated catalog with\n an intrinsic motion. The animation lives in the icon's\n own stylesheet (not the consumer's, not the datatable's)\n because the rotation is part of what the name \"spinner\"\n *means* — a static spinner would be a different icon. The\n consumer does not opt in: any <sken-icon name=\"spinner\">\n spins. We honour prefers-reduced-motion at the host level\n (a global opt-out for users who do not want animation). */\n @keyframes sken-icon-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n\n :host([name='spinner']) .sken-icon-svg {\n animation: sken-icon-spin 1s linear infinite;\n transform-origin: 50% 50%;\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host([name='spinner']) .sken-icon-svg {\n animation: none;\n }\n }\n `\n\n protected override render() {\n if (!isSkenIconName(this.name)) {\n // SkenIconError: name not in catalog. Render a visible\n // (but aria-hidden) empty box with a console warning so\n // the developer catches the typo at runtime, not as a\n // visual regression in production.\n console.warn(`[sken-icon] icon \"${this.name}\" not in catalog`)\n return html`<span class=\"sken-icon-svg\" aria-hidden=\"true\"></span>`\n }\n const raw = getSkenIconSvg(this.name, this.weight)\n if (this.decorative || !this.ariaLabel) {\n // Decorative icon: the screen reader skips it. The\n // <div> exists only as a vehicle for the innerHTML.\n return html` <div class=\"sken-icon-svg\" aria-hidden=\"true\" .innerHTML=${raw}></div> `\n }\n // Meaningful icon: role=\"img\" + <title> for screen readers.\n return html`\n <div\n class=\"sken-icon-svg\"\n role=\"img\"\n .innerHTML=${`${raw}<title>${this.ariaLabel}</title>`}\n ></div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-icon': SkenIcon\n }\n}\n"],"mappings":";;;;;;;;;;;;AAiEO,IAAM,IAAN,cAAuB,EAAW;;EA8CZ,aA3CN,KAAA,OAAA,SAIA,KAAA,OAAA,MAQE,KAAA,QAAA,WAeE,KAAA,SAAA,WAQZ,KAAA,aAAA,IAQc,KAAA,YAAA;;;EAEX,KAAA,SAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FnB,SAA4B;EAC1B,IAAI,CAAC,EAAe,KAAK,IAAI,GAM3B,OADA,QAAQ,KAAK,qBAAqB,KAAK,KAAK,iBAAiB,GACtD,CAAI;EAEb,IAAM,IAAM,EAAe,KAAK,MAAM,KAAK,MAAM;EAOjD,OANI,KAAK,cAAc,CAAC,KAAK,YAGpB,CAAI,6DAA6D,EAAI,YAGvE,CAAI;;;;qBAIM,GAAG,EAAI,SAAS,KAAK,UAAU,UAAU;;;CAG5D;AACF;AAjKG,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAI1B,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAQ1B,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,SAAA,KAAA,CAAA,GAe1B,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GAQ1B,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GAQzC,EAAA,CAAA,EAAS,EAAE,WAAW,aAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GA9CtC,IAAA,EAAA,CAAA,EAAc,WAAW,CAAA,GAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sken-ds/icons",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"access": "public"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@phosphor-icons/core": "^2.1.1",
|
|
31
31
|
"lit": "^3.3.3",
|
|
32
|
-
"@sken-ds/contracts": "0.3.
|
|
32
|
+
"@sken-ds/contracts": "0.3.8"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@microsoft/api-extractor": "^7.58.12",
|