@sigx/lynx-icons 0.4.1 → 0.4.2
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/dist/Icon.d.ts +22 -1
- package/dist/Icon.js +41 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/types.d.ts +58 -0
- package/package.json +4 -4
package/dist/Icon.d.ts
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import { type Define } from '@sigx/lynx';
|
|
2
2
|
import '@sigx/lynx-icons/__font-face.css';
|
|
3
|
-
|
|
3
|
+
import type { IconColorResolver, IconPropsExtensions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Injectable for the active theme's color resolver. Receives the full
|
|
6
|
+
* `<Icon>` props (including theme-augmented fields like daisy's
|
|
7
|
+
* `variant`) and returns a CSS color value to substitute into the SVG
|
|
8
|
+
* `fill=`, or `undefined` to fall through.
|
|
9
|
+
*
|
|
10
|
+
* Themes provide this via `defineProvide(useIconColorResolver, …)` from
|
|
11
|
+
* inside a provider component (e.g. daisy's `<ThemeProvider>`). Core
|
|
12
|
+
* `<Icon>` has no concept of named variants — it just asks the resolver
|
|
13
|
+
* for a color.
|
|
14
|
+
*/
|
|
15
|
+
export declare const useIconColorResolver: import("@sigx/runtime-core").InjectableFunction<IconColorResolver | null>;
|
|
16
|
+
export type IconProps = Define.Prop<'set', string, true> & Define.Prop<'name', string, true> & Define.Prop<'size', number, false> & Define.Prop<'color', string, false> & Define.Prop<'class', string, false>
|
|
17
|
+
/**
|
|
18
|
+
* Augmentation point — theme packages declaration-merge into
|
|
19
|
+
* `IconPropsExtensions` to add their own typed props (e.g. daisy
|
|
20
|
+
* adds `variant?: DaisyColor`). Core declares no specific
|
|
21
|
+
* extensions, so without a theme installed, no extra props exist
|
|
22
|
+
* and the type system rejects `<Icon variant="…">` at compile time.
|
|
23
|
+
*/
|
|
24
|
+
& IconPropsExtensions;
|
|
4
25
|
export declare function sanitizeColor(color: string): string;
|
|
5
26
|
export declare function inlineSvg(template: string, color: string): string;
|
|
6
27
|
/**
|
package/dist/Icon.js
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
-
import { component } from '@sigx/lynx';
|
|
2
|
+
import { component, defineInjectable } from '@sigx/lynx';
|
|
3
3
|
import { codepoints } from '@sigx/lynx-icons/__codepoints';
|
|
4
4
|
import { svgs } from '@sigx/lynx-icons/__svgs';
|
|
5
5
|
import '@sigx/lynx-icons/__font-face.css';
|
|
6
6
|
import { lookupGlyph } from './registry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Injectable for the active theme's color resolver. Receives the full
|
|
9
|
+
* `<Icon>` props (including theme-augmented fields like daisy's
|
|
10
|
+
* `variant`) and returns a CSS color value to substitute into the SVG
|
|
11
|
+
* `fill=`, or `undefined` to fall through.
|
|
12
|
+
*
|
|
13
|
+
* Themes provide this via `defineProvide(useIconColorResolver, …)` from
|
|
14
|
+
* inside a provider component (e.g. daisy's `<ThemeProvider>`). Core
|
|
15
|
+
* `<Icon>` has no concept of named variants — it just asks the resolver
|
|
16
|
+
* for a color.
|
|
17
|
+
*/
|
|
18
|
+
export const useIconColorResolver = defineInjectable(() => null);
|
|
7
19
|
/**
|
|
8
20
|
* Match a conservative subset of valid CSS color formats:
|
|
9
21
|
* - `currentColor` and named colors (`red`, `dodgerblue`, `transparent` …)
|
|
10
22
|
* - `#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa`
|
|
11
23
|
* - `rgb(...)` / `rgba(...)` / `hsl(...)` / `hsla(...)` with digits, dots,
|
|
12
24
|
* commas, percent signs, and whitespace inside the parens
|
|
25
|
+
* - `var(--name)` referencing a CSS custom property — the only way to
|
|
26
|
+
* plumb theme tokens (`var(--color-primary)`) into the SVG `fill=`
|
|
27
|
+
* attribute, since Lynx's `<svg content=…>` parses the SVG string as
|
|
28
|
+
* a standalone fragment that doesn't inherit `color` from the host
|
|
29
|
+
* element (so `fill="currentColor"` + a host-level class is a no-op).
|
|
13
30
|
*
|
|
14
31
|
* Anything else (quotes, angle brackets, ampersands, arbitrary HTML) falls
|
|
15
32
|
* back to `currentColor`. The `color` prop ends up substituted directly into
|
|
@@ -17,7 +34,7 @@ import { lookupGlyph } from './registry.js';
|
|
|
17
34
|
* value like `red" stroke="…` would break out of the `fill=""` attribute.
|
|
18
35
|
* Allow-list, not escape-list — keeps the surface area provably small.
|
|
19
36
|
*/
|
|
20
|
-
const SAFE_COLOR_RE = /^(?:currentColor|[a-zA-Z]+|#[0-9a-fA-F]{3,8}|(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s]+\))$/;
|
|
37
|
+
const SAFE_COLOR_RE = /^(?:currentColor|[a-zA-Z]+|#[0-9a-fA-F]{3,8}|(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s]+\)|var\(\s*--[\w-]+\s*\))$/;
|
|
21
38
|
export function sanitizeColor(color) {
|
|
22
39
|
return SAFE_COLOR_RE.test(color) ? color : 'currentColor';
|
|
23
40
|
}
|
|
@@ -48,14 +65,34 @@ export function inlineSvg(template, color) {
|
|
|
48
65
|
* ```
|
|
49
66
|
*/
|
|
50
67
|
export const Icon = component(({ props }) => {
|
|
68
|
+
// Resolve the active theme's color resolver once at setup. The
|
|
69
|
+
// resolver itself is a stable function reference; it reads the
|
|
70
|
+
// theme-augmented props (e.g. `props.variant` for daisy) and any
|
|
71
|
+
// reactive theme state (e.g. `theme.name`) on each call.
|
|
72
|
+
const resolveColor = useIconColorResolver();
|
|
51
73
|
return () => {
|
|
52
74
|
const size = props.size ?? 16;
|
|
53
75
|
const set = props.set;
|
|
54
76
|
const name = props.name;
|
|
55
77
|
const sizeStyle = { width: size, height: size };
|
|
78
|
+
// Resolution order: explicit `props.color` wins → then the
|
|
79
|
+
// theme resolver's return (driven by augmented props like
|
|
80
|
+
// `variant`) → finally `currentColor`. Substituted directly
|
|
81
|
+
// into the SVG `fill=` attribute by `inlineSvg`; class is not
|
|
82
|
+
// used to convey color because Lynx's `<svg content=…>` parses
|
|
83
|
+
// the SVG string in isolation and doesn't inherit host CSS
|
|
84
|
+
// `color`.
|
|
85
|
+
//
|
|
86
|
+
// `props` is cast to the unknown-record shape the resolver
|
|
87
|
+
// signature expects — at compile time the augmented fields are
|
|
88
|
+
// typed correctly inside the resolver itself (where the theme
|
|
89
|
+
// package's augmentation is in scope).
|
|
90
|
+
const themeColor = resolveColor
|
|
91
|
+
? resolveColor(props)
|
|
92
|
+
: undefined;
|
|
93
|
+
const color = props.color ?? themeColor ?? 'currentColor';
|
|
56
94
|
const glyph = lookupGlyph(codepoints, svgs, set, name);
|
|
57
95
|
if (glyph?.svg) {
|
|
58
|
-
const color = props.color ?? 'currentColor';
|
|
59
96
|
return (_jsx("svg", { content: inlineSvg(glyph.svg.svg, color), class: props.class, style: sizeStyle }));
|
|
60
97
|
}
|
|
61
98
|
if (glyph?.codepoint !== undefined) {
|
|
@@ -65,9 +102,8 @@ export const Icon = component(({ props }) => {
|
|
|
65
102
|
lineHeight: `${size}px`,
|
|
66
103
|
width: size,
|
|
67
104
|
height: size,
|
|
105
|
+
color,
|
|
68
106
|
};
|
|
69
|
-
if (props.color)
|
|
70
|
-
textStyle.color = props.color;
|
|
71
107
|
return (_jsx("text", { class: props.class, style: textStyle, children: String.fromCodePoint(glyph.codepoint) }));
|
|
72
108
|
}
|
|
73
109
|
return _jsx("view", { class: props.class, style: sizeStyle });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Icon } from './Icon.js';
|
|
1
|
+
export { Icon, useIconColorResolver } from './Icon.js';
|
|
2
2
|
export type { IconProps } from './Icon.js';
|
|
3
3
|
export { defineIconSet } from './defineIconSet.js';
|
|
4
|
-
export type { GlyphData, GlyphSvg, IconAdapter, IconSetDef } from './types.js';
|
|
4
|
+
export type { GlyphData, GlyphSvg, IconAdapter, IconColorResolver, IconPropsExtensions, IconSetDef, IconSpec, } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Icon } from './Icon.js';
|
|
1
|
+
export { Icon, useIconColorResolver } from './Icon.js';
|
|
2
2
|
export { defineIconSet } from './defineIconSet.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Augmentation point for theme / extension packages. Declaration-merge
|
|
3
|
+
* into this interface to add fields that `<Icon>` accepts beyond the
|
|
4
|
+
* core props. The pinned components in adapter packages and the daisy
|
|
5
|
+
* navigation primitives inherit the augmentation automatically via
|
|
6
|
+
* intersection.
|
|
7
|
+
*
|
|
8
|
+
* `@sigx/lynx-icons` deliberately knows nothing about themes — the
|
|
9
|
+
* extension shape is up to whatever theme is installed. Daisy adds a
|
|
10
|
+
* `variant?: DaisyColor` field; a custom theme could add anything else
|
|
11
|
+
* (`tone?: 'muted' | 'loud'`, `tint?: number`, …) and provide its own
|
|
12
|
+
* resolver.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // In a theme package:
|
|
17
|
+
* declare module '@sigx/lynx-icons' {
|
|
18
|
+
* interface IconPropsExtensions {
|
|
19
|
+
* variant?: 'primary' | 'secondary' | 'accent';
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface IconPropsExtensions {
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Function form provided to `useIconColorResolver`. Receives the full
|
|
28
|
+
* `<Icon>` props (including whatever fields the active theme augmented
|
|
29
|
+
* onto `IconPropsExtensions`) and returns a **CSS color value**
|
|
30
|
+
* substituted into the rendered SVG's `fill=` attribute. Return
|
|
31
|
+
* `undefined` to fall through to `props.color` / `currentColor`.
|
|
32
|
+
*
|
|
33
|
+
* Color rather than class: Lynx's `<svg content=…>` parses the inline
|
|
34
|
+
* SVG markup as a standalone fragment that doesn't inherit `color` CSS
|
|
35
|
+
* from the host element. Substituting the value into the markup is the
|
|
36
|
+
* only reliable way to make theme tokens show through.
|
|
37
|
+
*
|
|
38
|
+
* Props rather than a single variant string: the core has no opinion on
|
|
39
|
+
* how a theme keys its colors. A theme picks whichever augmented field
|
|
40
|
+
* (or combination) makes sense and reads it from `props` itself.
|
|
41
|
+
*/
|
|
42
|
+
export type IconColorResolver = (props: Readonly<Record<string, unknown>>) => string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Lightweight `{ set, name }` reference to an icon in a registered set —
|
|
45
|
+
* the canonical "data" form a consumer can pass to a UI primitive that
|
|
46
|
+
* accepts an icon (e.g. `<Tabs.Screen icon={{ set: 'lucide', name: 'map' }}>`).
|
|
47
|
+
*
|
|
48
|
+
* The receiving component (e.g. `<NavTabBar>`, `<NavHeader>`) is responsible
|
|
49
|
+
* for turning the spec into rendered JSX — typically by composing
|
|
50
|
+
* `<Icon set={spec.set} name={spec.name} color="currentColor" size={…}>`
|
|
51
|
+
* with theme-aware wrapping. Consumers who want full control (custom
|
|
52
|
+
* color, third-party component, size override) pass JSX directly instead
|
|
53
|
+
* of a spec.
|
|
54
|
+
*/
|
|
55
|
+
export interface IconSpec {
|
|
56
|
+
readonly set: string;
|
|
57
|
+
readonly name: string;
|
|
58
|
+
}
|
|
1
59
|
/**
|
|
2
60
|
* Per-glyph vector data. Used by SVG-mode rendering.
|
|
3
61
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigx/lynx-icons",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Icon component and registry for sigx-lynx — works with adapter packages like @sigx/lynx-icons-fa-free and @sigx/lynx-icons-lucide.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"LICENSE"
|
|
36
36
|
],
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@sigx/lynx": "^0.4.
|
|
38
|
+
"@sigx/lynx": "^0.4.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
41
|
+
"@typescript/native-preview": "7.0.0-dev.20260521.1",
|
|
42
42
|
"typescript": "^6.0.3",
|
|
43
|
-
"@sigx/lynx": "^0.4.
|
|
43
|
+
"@sigx/lynx": "^0.4.2"
|
|
44
44
|
},
|
|
45
45
|
"author": "Andreas Ekdahl",
|
|
46
46
|
"license": "MIT",
|