@dynamic-icon/svelte 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -1,15 +1,35 @@
1
1
  # @dynamic-icon/svelte
2
2
 
3
- Renders icons from database records. Knows nothing about any icon library: sources are registered with
4
- [`@dynamic-icon/svelte-config`](../svelte-config) (a peer dependency, so there is exactly one registry).
3
+ Svelte 5 component that renders icons from database records. It knows nothing about any icon library: you register
4
+ sources once with `configureIcons` (backed by the framework-free [`@dynamic-icon/core`](../core), installed automatically).
5
+
6
+ ```ts
7
+ // app root, once (identically on server and client)
8
+ import { configureIcons } from '@dynamic-icon/svelte';
9
+ import CarFront from 'lucide-svelte/icons/car-front';
10
+
11
+ configureIcons({ sources: { lucide: { 'car-front': CarFront } }, fallback: CircleHelp });
12
+ ```
5
13
 
6
14
  ```svelte
7
15
  <DynamicIcon {...record.icon} size={24} class="text-primary" />
8
16
  ```
9
17
 
10
- Props: `webType`, `webRef`, `color`, `media`, `scale`, `size` (px or CSS length), `strokeWidth`, `class`, `fallback` (snippet).
18
+ Props: `webType`, `webRef`, `color`, `media`, `scale`, `size`, `strokeWidth`, `class`, `fallback` (snippet).
19
+
20
+ | Prop | Notes |
21
+ | --- | --- |
22
+ | `webType` / `webRef` | `image`, `emoji`, `markup`, a font type (`material`, `font-awesome`, `remix`) or a configured source. |
23
+ | `color` | A CSS colour (`#fff`, `rgb()`, `oklch()`, `var()`, `red`) goes in `style`; anything else is added as classes. |
24
+ | `size` | px for numbers; a plain CSS length for strings (`1.5rem`). Invalid values (including `24px;...`) use the default size. |
25
+ | `scale` | Multiplies a numeric `size`, rounded. Ignored if not a positive finite number. |
26
+ | `fallback` | Snippet shown when unresolved; wins over `configureIcons({ fallback })`. |
27
+
28
+ - Only `image` and `markup` icons get a wrapper `<span>`; everything else is a single element. All icons are `aria-hidden`
29
+ (decorative): put meaning in adjacent text, or give the parent an `aria-label`.
30
+ - `markup` renders only through your `sanitize` function; without one it shows the fallback. `image` uses `loading="lazy"`.
31
+ - Icon components receive `size`, `strokeWidth`, `class`, `style` (CSS colours only) and `aria-hidden`; `lucide-svelte` icons
32
+ accept these as-is. Custom icons should spread rest props onto their root `<svg>`.
11
33
 
12
- - `color` is a CSS colour (`#fff`, `rgb()`, `var()`, `red`) applied via `style`, or otherwise a utility class.
13
- - `scale` multiplies a numeric `size` and rounds it; string sizes are used as-is.
14
- - Only `image` and `markup` icons get a wrapper `<span>` (they need a sized box); everything else renders one element.
15
- - Install both packages; the host app calls `configureIcons()` once. See the config package.
34
+ AI-readable docs: [`llms.txt`](./llms.txt) and [`llms-full.txt`](./llms-full.txt), shipped in the npm package, e.g.
35
+ `https://unpkg.com/@dynamic-icon/svelte/llms-full.txt` once published.
@@ -9,7 +9,7 @@
9
9
  * `class` and `color` land on the rendered element; `image`/`markup` get a sized wrapper to carry them.
10
10
  */
11
11
  import type { IconProps } from './types.js';
12
- import { getIconConfig, resolveIcon } from '@dynamic-icon/svelte-config';
12
+ import { getIconConfig, resolveIcon } from './config.js';
13
13
  import { boxSize, boxStyle, classes, colorStyle, textStyle } from './utils.js';
14
14
 
15
15
  const config = getIconConfig();
@@ -34,7 +34,8 @@
34
34
 
35
35
  {#if Comp}
36
36
  <Comp
37
- size={boxSize(size, scale)}
37
+ aria-hidden="true"
38
+ size={boxSize(size, scale, config.size)}
38
39
  {strokeWidth}
39
40
  class={classes(color, className)}
40
41
  style={colorStyle(color)}
@@ -42,28 +43,31 @@
42
43
  {:else if webType === 'image' && media?.link}
43
44
  <span
44
45
  class={classes(color, className, 'u-icon')}
45
- style={boxStyle(boxSize(size, scale), color)}
46
- role="presentation"
46
+ style={boxStyle(boxSize(size, scale, config.size), color)}
47
+ aria-hidden="true"
47
48
  >
48
49
  <img src={media.link} alt={media.caption ?? ''} loading="lazy" decoding="async" />
49
50
  </span>
50
51
  {:else if webType === 'markup' && webRef && config.sanitize}
51
52
  <span
52
53
  class={classes(color, className, 'u-icon u-markup')}
53
- style={boxStyle(boxSize(size, scale), color)}
54
- role="presentation"
54
+ style={boxStyle(boxSize(size, scale, config.size), color)}
55
+ aria-hidden="true"
55
56
  >
56
57
  {@html config.sanitize(webRef)}
57
58
  </span>
58
59
  {:else if webType === 'emoji' && webRef}
59
- <span class={classes(color, className)} style={textStyle(boxSize(size, scale), color)}>{webRef}</span>
60
+ <span aria-hidden="true" class={classes(color, className)} style={textStyle(boxSize(size, scale, config.size), color)}
61
+ >{webRef}</span
62
+ >
60
63
  {:else if webType && webRef && config.fontTypes.has(webType)}
61
- <i class={classes(color, className, webRef)} style={textStyle(boxSize(size, scale), color)}></i>
64
+ <i aria-hidden="true" class={classes(color, className, webRef)} style={textStyle(boxSize(size, scale, config.size), color)}></i>
62
65
  {:else if fallback}
63
66
  {@render fallback()}
64
67
  {:else if Fallback}
65
68
  <Fallback
66
- size={boxSize(size, scale)}
69
+ aria-hidden="true"
70
+ size={boxSize(size, scale, config.size)}
67
71
  {strokeWidth}
68
72
  class={classes(color, className)}
69
73
  style={colorStyle(color)}
@@ -0,0 +1,8 @@
1
+ import type { ResolvedIconConfig } from "@dynamic-icon/core";
2
+ import type { IconComponent, IconConfig } from "./types.js";
3
+ /** Sets the icon configuration. Call once at app start, identically on server and client. */
4
+ export declare const configureIcons: (config: IconConfig) => void;
5
+ /** Resolves a component for `webType`/`webRef`, or `undefined`. Usable outside components. */
6
+ export declare const resolveIcon: (webType: string | undefined, webRef: string | undefined) => IconComponent | undefined;
7
+ /** @internal Read by `DynamicIcon` once per instance. */
8
+ export declare const getIconConfig: () => ResolvedIconConfig<IconComponent>;
package/dist/config.js ADDED
@@ -0,0 +1,9 @@
1
+ // Typed entry points over the framework-free registry in @dynamic-icon/core.
2
+ // This is the only place that fixes the registry's component type to `IconComponent`.
3
+ import { configureIcons as configure, getIconConfig as getConfig, resolveIcon as resolve } from "@dynamic-icon/core";
4
+ /** Sets the icon configuration. Call once at app start, identically on server and client. */
5
+ export const configureIcons = (config) => configure(config);
6
+ /** Resolves a component for `webType`/`webRef`, or `undefined`. Usable outside components. */
7
+ export const resolveIcon = (webType, webRef) => resolve(webType, webRef);
8
+ /** @internal Read by `DynamicIcon` once per instance. */
9
+ export const getIconConfig = () => getConfig();
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as DynamicIcon } from "./DynamicIcon.svelte";
2
- export type { IconEntry, IconMedia, IconProps } from "./types.js";
2
+ export { configureIcons, resolveIcon } from "./config.js";
3
+ export type { IconComponent, IconComponentProps, IconConfig, IconEntry, IconMedia, IconProps, IconSource } from "./types.js";
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export { default as DynamicIcon } from "./DynamicIcon.svelte";
2
+ export { configureIcons, resolveIcon } from "./config.js";
package/dist/types.d.ts CHANGED
@@ -1,4 +1,22 @@
1
- import type { Snippet } from "svelte";
1
+ import type { Component, ComponentType, Snippet, SvelteComponent } from "svelte";
2
+ import type { IconConfig as CoreIconConfig, IconSource as CoreIconSource } from "@dynamic-icon/core";
3
+ /** Props `DynamicIcon` passes to every icon component. `lucide-svelte` icons already accept them. */
4
+ export interface IconComponentProps {
5
+ size?: number | string;
6
+ strokeWidth?: number;
7
+ class?: string;
8
+ /** Only set when `color` is a CSS colour. */
9
+ style?: string;
10
+ "aria-hidden"?: "true";
11
+ }
12
+ /**
13
+ * Any Svelte component usable as an icon (Svelte 5 or legacy class-based, e.g. `lucide-svelte`).
14
+ * Props are `any` on purpose: library icons declare their own prop types, which are never exactly
15
+ * `IconComponentProps`. Custom icons should accept those props and spread the rest onto their root element.
16
+ */
17
+ export type IconComponent = Component<any, any, any> | ComponentType<SvelteComponent<any, any, any>>;
18
+ export type IconSource = CoreIconSource<IconComponent>;
19
+ export type IconConfig = CoreIconConfig<IconComponent>;
2
20
  /** Media attached to an `image` icon. Structurally compatible with CMS file objects. */
3
21
  export interface IconMedia {
4
22
  link: string;
@@ -12,7 +30,7 @@ export interface IconEntry<T extends string = string> {
12
30
  webType?: T;
13
31
  /** Identifier within the source ('car-front'), icon-font classes, emoji, or raw markup. */
14
32
  webRef?: string;
15
- /** A Tailwind/utility class (`text-primary`) or a CSS colour (`#fff`, `rgb()`, `var()`, `red`). */
33
+ /** A utility class (`text-primary`) or a CSS colour (`#fff`, `rgb()`, `var()`, `red`). */
16
34
  color?: string;
17
35
  /** Image for the `image` type. */
18
36
  media?: IconMedia;
@@ -20,7 +38,7 @@ export interface IconEntry<T extends string = string> {
20
38
  scale?: number;
21
39
  }
22
40
  export interface IconProps<T extends string = string> extends IconEntry<T> {
23
- /** Visual size: px when a number, any CSS length when a string. */
41
+ /** px when a number, a CSS length (`1.5rem`) when a string. Invalid values fall back to the default size. */
24
42
  size?: number | string;
25
43
  class?: string;
26
44
  strokeWidth?: number;
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export declare const isCssColor: (color: string | undefined) => color is string;
2
- /** Applies the per-source `scale` to numeric sizes, rounded to avoid blurry sub-pixel rendering. */
3
- export declare const boxSize: (size: number | string, scale: number | undefined) => number | string;
2
+ /**
3
+ * Final icon size. Numbers must be finite and positive and get the per-source `scale` (rounded to avoid
4
+ * blurry sub-pixel rendering); strings must be a plain CSS length. Invalid input yields `fallback`.
5
+ */
6
+ export declare const boxSize: (size: number | string, scale: number | undefined, fallback: number) => number | string;
4
7
  /** `style` for icon components: only a CSS colour needs it. */
5
8
  export declare const colorStyle: (color: string | undefined) => string | undefined;
6
9
  /** `style` for the sized box around `image` / `markup` icons. */
package/dist/utils.js CHANGED
@@ -5,8 +5,20 @@
5
5
  */
6
6
  const CSS_COLOR = /^(?:#[\da-f]{3,8}|[a-z]+|[a-z]+(?:-[a-z]+)*\([^;{}"'<>]*\))$/i;
7
7
  export const isCssColor = (color) => color !== undefined && CSS_COLOR.test(color);
8
- /** Applies the per-source `scale` to numeric sizes, rounded to avoid blurry sub-pixel rendering. */
9
- export const boxSize = (size, scale) => typeof size === "number" && scale ? Math.round(size * scale) : size;
8
+ /** A plain CSS length. Anything else (e.g. `24px;background:url(x)`) never reaches a `style` attribute. */
9
+ const CSS_LENGTH = /^(?:\d+|\d*\.\d+)(?:px|r?em|ch|ex|vw|vh|vmin|vmax|%|pt|cm|mm|in)$/i;
10
+ /**
11
+ * Final icon size. Numbers must be finite and positive and get the per-source `scale` (rounded to avoid
12
+ * blurry sub-pixel rendering); strings must be a plain CSS length. Invalid input yields `fallback`.
13
+ */
14
+ export const boxSize = (size, scale, fallback) => {
15
+ if (typeof size === "number") {
16
+ if (!(size > 0) || !Number.isFinite(size))
17
+ return fallback;
18
+ return typeof scale === "number" && scale > 0 && Number.isFinite(scale) ? Math.round(size * scale) || 1 : size;
19
+ }
20
+ return CSS_LENGTH.test(size) ? size : fallback;
21
+ };
10
22
  const cssLength = (size) => (typeof size === "number" ? `${size}px` : size);
11
23
  const colorDecl = (color) => (isCssColor(color) ? `;color:${color}` : "");
12
24
  /** `style` for icon components: only a CSS colour needs it. */
package/llms-full.txt ADDED
@@ -0,0 +1,125 @@
1
+ # @dynamic-icon/svelte and @dynamic-icon/core: full documentation
2
+
3
+ Two packages. `@dynamic-icon/core` is a framework-free registry (pure TypeScript, zero dependencies). `@dynamic-icon/svelte`
4
+ is the Svelte 5 component plus typed re-exports. Installing the Svelte package pulls in core.
5
+
6
+ ## 1. Purpose
7
+
8
+ Render icons whose identity is stored in a database record: `{ webType: 'lucide', webRef: 'car-front', color: 'text-primary' }`.
9
+ The package resolves `webType` + `webRef` to a component (or renders an image, emoji, icon-font `<i>`, or sanitized markup).
10
+ Designed for components that render ~1,000 icons at once.
11
+
12
+ ## 2. Quick start
13
+
14
+ ```ts
15
+ // src/hooks.client.ts and src/hooks.server.ts (or one shared module imported by both): once, module scope
16
+ import { configureIcons } from '@dynamic-icon/svelte';
17
+ import CarFront from 'lucide-svelte/icons/car-front';
18
+ import House from 'lucide-svelte/icons/house';
19
+ import CircleHelp from 'lucide-svelte/icons/circle-help';
20
+
21
+ configureIcons({
22
+ sources: { lucide: { 'car-front': CarFront, house: House } },
23
+ fallback: CircleHelp
24
+ });
25
+ ```
26
+
27
+ ```svelte
28
+ <script lang="ts">
29
+ import { DynamicIcon } from '@dynamic-icon/svelte';
30
+ let { icon } = $props(); // { webType, webRef, color?, media?, scale? } from the database
31
+ </script>
32
+
33
+ <DynamicIcon {...icon} size={20} class="mr-2" />
34
+ ```
35
+
36
+ ## 3. API
37
+
38
+ ### `configureIcons(config: IconConfig): void` (from `@dynamic-icon/svelte`; generic `configureIcons<C>` in core)
39
+
40
+ | Field | Type | Default | Meaning |
41
+ | --- | --- | --- | --- |
42
+ | `sources` | `Record<webType, Record<ref, Component> \| (ref) => Component \| undefined>` | `{}` | Component sources by `webType`. Names `image`, `emoji`, `markup` are reserved and throw. |
43
+ | `fontTypes` | `string[]` | `['material','font-awesome','remix']` | `webType`s rendered as `<i class={webRef}>`. Must not collide with sources or reserved names. |
44
+ | `sanitize` | `(html: string) => string` | none | Required for `markup`. Without it, `markup` icons show the fallback. |
45
+ | `fallback` | `Component` | none | Rendered when nothing resolves (unknown icon, empty record, failed source). A per-instance `fallback` snippet wins. |
46
+ | `defaults` | `{ size?: number; strokeWidth?: number }` | `{ size: 24, strokeWidth: 2 }` | Must be positive finite numbers or it throws. |
47
+ | `onError` | `(error: unknown) => void` | `console.error` | Receives errors thrown by function sources or `sanitize`. |
48
+
49
+ Semantics: validates eagerly; on invalid input it throws and the previous configuration stays active; on success it replaces the
50
+ whole configuration (idempotent). Record sources are held by reference, never copied (lookups use `Object.hasOwn`, so
51
+ `constructor`/`__proto__` never resolve); treat them as read-only, since later mutations are visible. Function sources are used as-is (memoise them yourself if expensive).
52
+
53
+ ### `resolveIcon(webType, webRef): Component | undefined`
54
+ Same lookup the component uses, for use outside components. Never throws.
55
+
56
+ ### `<DynamicIcon />` props
57
+
58
+ | Prop | Type | Notes |
59
+ | --- | --- | --- |
60
+ | `webType` | `string` | Which renderer/source. |
61
+ | `webRef` | `string` | Identifier within the source; class string for font types; the emoji; or raw markup. |
62
+ | `color` | `string` | CSS colour (hex, keyword, `rgb()/hsl()/oklch()/var()/color-mix()`) -> inline `color:`; anything else -> appended to `class`. |
63
+ | `media` | `{ link: string; caption?: string }` | For `image`. `caption` becomes `alt`. Rendered `loading="lazy" decoding="async"`. |
64
+ | `size` | `number \| string` | px if number; plain CSS length if string. Invalid (NaN, <=0, `24px;x:y`, `calc()`) uses `defaults.size`. |
65
+ | `scale` | `number` | Multiplies numeric `size`, rounded (min 1). Ignored for strings or non-positive/non-finite values. |
66
+ | `strokeWidth` | `number` | Passed to icon components. |
67
+ | `class` | `string` | Plain string (not clsx arrays). |
68
+ | `fallback` | `Snippet` | Per-instance fallback. |
69
+
70
+ Extra record fields such as `name` are accepted and ignored, so `{...record}` spreading works.
71
+
72
+ ### Contract for icon components
73
+ They receive `size`, `strokeWidth`, `class`, `style` (only when `color` is a CSS colour) and `aria-hidden="true"`. `lucide-svelte` icons
74
+ accept these. Custom icons should spread rest props onto their root `<svg>`. Exported type `IconComponent` is intentionally
75
+ `Component<any, any, any> | ComponentType<SvelteComponent<any, any, any>>` because library icons never match one exact prop type.
76
+
77
+ ## 4. Resolution order (per instance)
78
+ 1. A configured source resolves `webType`/`webRef` -> render that component (no wrapper).
79
+ 2. `image` with `media.link` -> sized wrapper `<span>` + `<img>`.
80
+ 3. `markup` with `webRef` and a configured `sanitize` -> sized wrapper `<span>` with `{@html sanitize(webRef)}`.
81
+ 4. `emoji` -> `<span style="font-size">`.
82
+ 5. Font type -> `<i class="{webRef} ...">`.
83
+ 6. Else: per-instance `fallback` snippet, else `configureIcons({ fallback })`, else nothing.
84
+
85
+ ## 5. Security model
86
+ - DB-controlled strings reach the DOM only as: escaped text, class tokens, `<img src>`, a validated CSS colour, a validated CSS length, and (for `markup`) sanitizer output.
87
+ - `color` is only placed in `style` if it matches a strict colour grammar (no `;`, braces, quotes); otherwise it is a class token, which cannot inject declarations.
88
+ - `size` strings must match a plain CSS length; numbers must be finite and > 0.
89
+ - `markup` is never rendered unsanitized. Provide a real sanitizer (e.g. DOMPurify on the client, an SSR-capable one on the server); an identity function is unsafe.
90
+ - `media.link` is not scheme-filtered; validate image URLs upstream if they are user-supplied.
91
+ - Registry keys are looked up with `Object.hasOwn`: prototype keys cannot resolve.
92
+ - A throwing function source or sanitizer cannot crash the page: it is reported to `onError` and the icon renders as unresolved.
93
+
94
+ ## 6. SSR rules
95
+ - The configuration is app-wide data, identical for all requests, so a process-wide singleton is safe. Never mutate a source record per request (it is shared by reference). Per-request or per-tenant icon sets are not supported; use a function source that reads your own request-scoped state only if you accept that trade-off.
96
+ - Call `configureIcons` once at module scope, on both server and client, with the same config (otherwise hydration markup can differ). Do not call it inside components or per request.
97
+ - Components read the config once at instance creation; configure before the first render.
98
+ - Nothing touches `window`/`document` at import or render time.
99
+
100
+ ## 7. Performance notes
101
+ - Per icon: one registry lookup (`Object.hasOwn` + index), one `$derived`, plain string building. No `tailwind-merge`/`clsx`, no string case conversion.
102
+ - Bundle: the package imports no icon library. Only icons you list in `sources` ship. Use per-icon imports; never `import * as Icons`.
103
+ - Measured (Node, 1,000 icons): `Map.get` ~16-19 ns, `Object.hasOwn` + index ~23 ns, `globalThis[Symbol]` ~5 ns. Sources are held by reference, so the registry adds no copy of your icon data; the difference between strategies is a few ns per icon, negligible next to component instantiation.
104
+ - Only `image`/`markup` add a wrapper element. Component icons render a single element.
105
+ - Wrapper styles are scoped CSS in the component (Tailwind does not scan `node_modules`).
106
+
107
+ ## 8. Architecture
108
+ - `@dynamic-icon/core`: pure TypeScript (`lib: ES2022`, no DOM, no deps). `configureIcons`, `resolveIcon`, `getIconConfig`, generic over the component type `C`. State: one holder object at `globalThis[Symbol.for('@dynamic-icon/core@1')]`, captured per module so reads are plain property access; duplicate installs share it; the `@1` is the holder format version.
109
+ - `@dynamic-icon/svelte`: `DynamicIcon.svelte`, typed wrappers fixing `C = IconComponent`, small pure helpers (`utils.ts`). Ships `.svelte` source via `svelte-package`.
110
+ - Store choice: a global holder (not Svelte context) with sources held by reference. Context would add a `getContext` per instance, only works during component init, needs a provider around every consumer (including other libraries' components and separately mounted roots), and buys only per-request isolation that an app-wide icon set does not need. Why not Svelte context: the registry is app-wide config; context adds a lookup per instance and only works during component init. Why not per-instance props: 1,000 icons would each carry the config.
111
+ - Adding another framework: create `@dynamic-icon/<framework>` with a component calling `getIconConfig<Component>()`; reuse core and `utils` logic.
112
+
113
+ ## 9. Common mistakes
114
+ - `import * as Icons from 'lucide-svelte'` as a source: ships every icon. Register individual icons.
115
+ - Using PascalCase keys with kebab-case DB values: use a function source (`(ref) => map[toPascal(ref)]`) or kebab-case keys.
116
+ - Calling `configureIcons` in a component or per request.
117
+ - Expecting `markup` to render without `sanitize`.
118
+ - Passing `size="24px;..."` or `size="calc(...)"`: falls back to the default size.
119
+ - Expecting Tailwind conflict resolution between `color` and `class`: classes are concatenated, not merged.
120
+ - Using `webType: 'image'|'emoji'|'markup'` as a source name: throws at configure time.
121
+
122
+ ## 10. Types
123
+ `IconEntry<T extends string = string>` { name?, webType?, webRef?, color?, media?, scale? }; `IconProps<T>` adds { size?, class?, strokeWidth?, fallback? };
124
+ `IconMedia` { link, caption? }; `IconConfig`, `IconSource`, `IconComponent`, `IconComponentProps` exported from `@dynamic-icon/svelte`.
125
+ Core exports `IconConfig<C>`, `IconSource<C>`, `ResolvedIconConfig<C>`.
package/llms.txt ADDED
@@ -0,0 +1,21 @@
1
+ # @dynamic-icon/svelte
2
+
3
+ > Svelte 5 component that renders icons from database records (`{ webType: 'lucide', webRef: 'car-front' }`). Icon-library agnostic and pluggable: the app registers icon sources once with `configureIcons()`. Built for pages rendering hundreds or thousands of icons: one registry lookup and one derived value per icon, no class-merging library, no icon library imported by the package.
4
+
5
+ Key facts for code generation:
6
+ - Install `@dynamic-icon/svelte` (peer: `svelte@^5`). It depends on `@dynamic-icon/core`, a zero-dependency registry; do not install core separately.
7
+ - Call `configureIcons({ sources, fallback?, defaults?, sanitize?, fontTypes?, onError? })` exactly once, at module scope of the app root, with identical config on server and client. Never inside a component or per request.
8
+ - Register only the icons you need, with per-icon imports (`import CarFront from 'lucide-svelte/icons/car-front'`), keyed by the identifier stored in the database. Never `import * as` a whole library: it defeats tree-shaking.
9
+ - Render with `<DynamicIcon {...record.icon} size={24} class="text-primary" />`.
10
+ - Libraries that render `DynamicIcon` need no setup; only the host app configures.
11
+ - Built-in `webType`s: `image` (uses `media.link`), `emoji`, `markup` (needs `sanitize`), and icon fonts `material`, `font-awesome`, `remix` (`<i class={webRef}>`). Any other `webType` must be a configured source.
12
+
13
+ ## Docs
14
+
15
+ - [Full documentation](https://unpkg.com/@dynamic-icon/svelte/llms-full.txt): API, configuration, resolution order, security model, SSR rules, performance notes, architecture
16
+ - [Core registry](https://unpkg.com/@dynamic-icon/core/llms.txt): the framework-free registry used underneath
17
+ - [README](https://unpkg.com/@dynamic-icon/svelte/README.md): human-oriented quick start
18
+
19
+ ## Optional
20
+
21
+ - Same files via jsDelivr: https://cdn.jsdelivr.net/npm/@dynamic-icon/svelte/llms-full.txt
package/package.json CHANGED
@@ -1,13 +1,7 @@
1
1
  {
2
2
  "name": "@dynamic-icon/svelte",
3
- "version": "0.1.0",
4
- "description": "Tiny Svelte 5 component that renders database-driven icons. Sources are plugged in via @dynamic-icon/svelte-config.",
5
- "keywords": [
6
- "svelte",
7
- "svelte5",
8
- "icons",
9
- "dynamic-icon"
10
- ],
3
+ "version": "0.1.1",
4
+ "description": "Tiny Svelte 5 component that renders database-driven icons. Sources are plugged in via @dynamic-icon/core.",
11
5
  "license": "MIT",
12
6
  "type": "module",
13
7
  "sideEffects": [
@@ -21,28 +15,31 @@
21
15
  "svelte": "./dist/index.js",
22
16
  "default": "./dist/index.js"
23
17
  },
18
+ "./llms.txt": "./llms.txt",
19
+ "./llms-full.txt": "./llms-full.txt",
24
20
  "./package.json": "./package.json"
25
21
  },
26
22
  "files": [
27
23
  "dist",
28
24
  "README.md",
29
- "LICENSE"
25
+ "LICENSE",
26
+ "llms.txt",
27
+ "llms-full.txt"
30
28
  ],
31
29
  "peerDependencies": {
32
- "svelte": "^5.0.0",
33
- "@dynamic-icon/svelte-config": "^0.1.0"
30
+ "svelte": "^5.0.0"
34
31
  },
35
32
  "devDependencies": {
36
33
  "@sveltejs/package": "^2.3.0",
37
34
  "@sveltejs/vite-plugin-svelte": "^4.0.0",
38
35
  "@types/node": "^22.0.0",
39
36
  "jsdom": "^25.0.0",
37
+ "publint": "^0.2.12",
40
38
  "svelte": "^5.0.0",
41
39
  "svelte-check": "^4.0.0",
42
40
  "typescript": "^5.6.0",
43
41
  "vite": "^5.4.0",
44
- "vitest": "^2.1.0",
45
- "@dynamic-icon/svelte-config": "0.1.0"
42
+ "vitest": "^2.1.0"
46
43
  },
47
44
  "engines": {
48
45
  "node": ">=18"
@@ -50,11 +47,18 @@
50
47
  "publishConfig": {
51
48
  "access": "public"
52
49
  },
50
+ "dependencies": {
51
+ "@dynamic-icon/core": "^0.1.1"
52
+ },
53
53
  "scripts": {
54
54
  "build": "svelte-package -i src -o dist",
55
+ "prebuild": "pnpm --filter @dynamic-icon/core run build",
55
56
  "typecheck": "svelte-check --tsconfig ./tsconfig.json",
57
+ "pretypecheck": "pnpm --filter @dynamic-icon/core run build",
56
58
  "typecheck:test": "svelte-check --tsconfig ./tsconfig.test.json",
59
+ "pretypecheck:test": "pnpm --filter @dynamic-icon/core run build",
57
60
  "test": "vitest run",
58
- "test:watch": "vitest"
61
+ "test:watch": "vitest",
62
+ "lint:package": "publint"
59
63
  }
60
64
  }