@pantoken/utils 0.1.0

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 ADDED
@@ -0,0 +1,71 @@
1
+ # @pantoken/utils
2
+
3
+ Shared, upstream-free helpers used across the pantoken packages: the token reference resolver
4
+ (with `light-dark()` handling), the two token regexes, kebab→camel case, hex-colour parsing, the
5
+ drift/reference-integrity checks, and the generic token→utility-class emitters. Depends only on
6
+ `@pantoken/model` (types) and [`arkregex`](https://www.npmjs.com/package/arkregex), so any package can
7
+ use it without pulling the GitHub-only upstream token source.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm i @pantoken/utils
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { makeResolver, resolveTokens } from "@pantoken/utils";
19
+ import { tokens } from "@pantoken/tokens";
20
+
21
+ // Expand var(--x) chains to concrete leaf values, collapsing light-dark() to one branch.
22
+ const resolve = makeResolver(tokens, { mode: "light" });
23
+ resolve("var(--instui-color-background-base)"); // → "#ffffff"
24
+
25
+ // Or resolve every token at once, keyed by name.
26
+ const byName = resolveTokens(tokens, { mode: "dark" });
27
+ ```
28
+
29
+ ## API
30
+
31
+ - **`makeResolver(base, { mode?, overrides? })`** — build a resolver that expands `var(--x)`
32
+ references to concrete leaf values against `base` (plus `overrides`, which win on name
33
+ collisions). With `mode` (`"light"` / `"dark"`) it collapses `light-dark()` to that branch;
34
+ without, it keeps `light-dark()` intact. Replaces the per-package resolver that used to be
35
+ copy-pasted across the formats and renderers.
36
+ - **`resolveTokens(base, opts)`** — `makeResolver` applied to every token, returned as a
37
+ `name → resolved` `Map`.
38
+ - **`camelCase(kebab)`** — `color-background-brand` → `colorBackgroundBrand`.
39
+ - **`parseHexColor(hex)`** — parse `#rgb` / `#rrggbb` / `#rrggbbaa` to `{ r, g, b, a }` (`r`/`g`/`b`
40
+ 0–255, `a` 0–1), or `undefined` for a non-hex string.
41
+ - **`unknownReferences(text, ir)`** — drift check: the `--instui-*` names in `text` the IR doesn't
42
+ define (sorted; empty means no drift). Use for outputs that _reference_ tokens defined elsewhere,
43
+ such as the docusaurus, vitepress, bootstrap, and shadcn bridges.
44
+ - **`danglingReferences(css)`** — self-containment check: the `--instui-*` names referenced via
45
+ `var()` that the same stylesheet never defines. Use for self-contained stylesheets (`css`,
46
+ `pendo`).
47
+ - **`extractInstuiRefs(text)` / `tokenNames(ir)`** — the primitives the two checks build on,
48
+ exposed for custom assertions.
49
+ - **`colorUtilitiesCss(names, options?)`** — the semantic-colour utility emitter:
50
+ `.<prefix>-bg-<name>` / `-fg-` / `-border-` from `--instui-color-<family>-<name>`, one per token.
51
+ - **`tokenUtilitiesCss(groups, options?)`** — the generic token→class emitter: one class per token,
52
+ applied to its CSS property (the `--instui-` tail is the class name). Both emitters carry no
53
+ InstUI-look opinion — the caller supplies the names. `@pantoken/components` feeds them a curated
54
+ _semantic_ allowlist; `@pantoken/plugin-primitives` feeds the raw palette. `options.prefix` sets the
55
+ class prefix; any falsy value drops it.
56
+ - **`VAR_RE` / `LIGHT_DARK_RE`** — the two token regexes, built with `arkregex`'s `regex()` so
57
+ their capture groups are typed on `.exec()` / `.matchAll()`. They're real `RegExp` instances.
58
+ - **`Mode`, `ResolveOptions`, `Rgba`, `UtilityOptions`, `ColorUtilityNames`, `TokenUtilityGroup`** —
59
+ the supporting types.
60
+
61
+ For value fidelity (an emitted, resolved value equals the IR's resolved value), compare against
62
+ `resolveTokens(ir, { mode })` directly — see `@pantoken/scss`'s test.
63
+
64
+ ## Related
65
+
66
+ - Types come from `@pantoken/model`.
67
+ - `@pantoken/plugin-kit` re-exports `makeResolver` and `resolveTokens` for plugin authors.
68
+
69
+ ## License
70
+
71
+ MIT
@@ -0,0 +1,509 @@
1
+ import { Token } from "@pantoken/model";
2
+
3
+ //#region src/index.d.ts
4
+ /** The colour mode to collapse `light-dark()` to. */
5
+ type Mode = "light" | "dark";
6
+ /** A `var(--custom-prop)` reference (optional fallback); capture group 1 is the property name. */
7
+ declare const VAR_RE: import("arkregex").Regex<`${string}var(--${string}${string})${string}` | `${string}var( ${string}--${string}${string})${string}` | `${string}var(
8
+ ${string}--${string}${string})${string}` | `${string}var(\t${string}--${string}${string})${string}`, {
9
+ captures: [`--${string}`];
10
+ flags: "g";
11
+ }>;
12
+ /** A `light-dark(<light>, <dark>)` value; capture groups 1 and 2 are the two branches. */
13
+ declare const LIGHT_DARK_RE: import("arkregex").Regex<`light-dark(${string},${string})` | `light-dark( ${string}${string},${string})` | `light-dark(
14
+ ${string}${string},${string})` | `light-dark(\t${string}${string},${string})` | `light-dark(${string} ${string},${string})` | `light-dark(${string}
15
+ ${string},${string})` | `light-dark(${string}\t${string},${string})` | `light-dark( ${string}${string} ${string},${string})` | `light-dark( ${string}${string}
16
+ ${string},${string})` | `light-dark( ${string}${string}\t${string},${string})` | `light-dark(
17
+ ${string}${string} ${string},${string})` | `light-dark(
18
+ ${string}${string}
19
+ ${string},${string})` | `light-dark(
20
+ ${string}${string}\t${string},${string})` | `light-dark(\t${string}${string} ${string},${string})` | `light-dark(\t${string}${string}
21
+ ${string},${string})` | `light-dark(\t${string}${string}\t${string},${string})` | `light-dark(${string}, ${string}${string})` | `light-dark(${string},
22
+ ${string}${string})` | `light-dark(${string},\t${string}${string})` | `light-dark( ${string}${string}, ${string}${string})` | `light-dark( ${string}${string},
23
+ ${string}${string})` | `light-dark( ${string}${string},\t${string}${string})` | `light-dark(
24
+ ${string}${string}, ${string}${string})` | `light-dark(
25
+ ${string}${string},
26
+ ${string}${string})` | `light-dark(
27
+ ${string}${string},\t${string}${string})` | `light-dark(\t${string}${string}, ${string}${string})` | `light-dark(\t${string}${string},
28
+ ${string}${string})` | `light-dark(\t${string}${string},\t${string}${string})` | `light-dark(${string} ${string}, ${string}${string})` | `light-dark(${string} ${string},
29
+ ${string}${string})` | `light-dark(${string} ${string},\t${string}${string})` | `light-dark(${string}
30
+ ${string}, ${string}${string})` | `light-dark(${string}
31
+ ${string},
32
+ ${string}${string})` | `light-dark(${string}
33
+ ${string},\t${string}${string})` | `light-dark(${string}\t${string}, ${string}${string})` | `light-dark(${string}\t${string},
34
+ ${string}${string})` | `light-dark(${string}\t${string},\t${string}${string})` | `light-dark( ${string}${string} ${string}, ${string}${string})` | `light-dark( ${string}${string} ${string},
35
+ ${string}${string})` | `light-dark( ${string}${string} ${string},\t${string}${string})` | `light-dark( ${string}${string}
36
+ ${string}, ${string}${string})` | `light-dark( ${string}${string}
37
+ ${string},
38
+ ${string}${string})` | `light-dark( ${string}${string}
39
+ ${string},\t${string}${string})` | `light-dark( ${string}${string}\t${string}, ${string}${string})` | `light-dark( ${string}${string}\t${string},
40
+ ${string}${string})` | `light-dark( ${string}${string}\t${string},\t${string}${string})` | `light-dark(
41
+ ${string}${string} ${string}, ${string}${string})` | `light-dark(
42
+ ${string}${string} ${string},
43
+ ${string}${string})` | `light-dark(
44
+ ${string}${string} ${string},\t${string}${string})` | `light-dark(
45
+ ${string}${string}
46
+ ${string}, ${string}${string})` | `light-dark(
47
+ ${string}${string}
48
+ ${string},
49
+ ${string}${string})` | `light-dark(
50
+ ${string}${string}
51
+ ${string},\t${string}${string})` | `light-dark(
52
+ ${string}${string}\t${string}, ${string}${string})` | `light-dark(
53
+ ${string}${string}\t${string},
54
+ ${string}${string})` | `light-dark(
55
+ ${string}${string}\t${string},\t${string}${string})` | `light-dark(\t${string}${string} ${string}, ${string}${string})` | `light-dark(\t${string}${string} ${string},
56
+ ${string}${string})` | `light-dark(\t${string}${string} ${string},\t${string}${string})` | `light-dark(\t${string}${string}
57
+ ${string}, ${string}${string})` | `light-dark(\t${string}${string}
58
+ ${string},
59
+ ${string}${string})` | `light-dark(\t${string}${string}
60
+ ${string},\t${string}${string})` | `light-dark(\t${string}${string}\t${string}, ${string}${string})` | `light-dark(\t${string}${string}\t${string},
61
+ ${string}${string})` | `light-dark(\t${string}${string}\t${string},\t${string}${string})` | `light-dark(${string},${string} ${string})` | `light-dark(${string},${string}
62
+ ${string})` | `light-dark(${string},${string}\t${string})` | `light-dark( ${string}${string},${string} ${string})` | `light-dark( ${string}${string},${string}
63
+ ${string})` | `light-dark( ${string}${string},${string}\t${string})` | `light-dark(
64
+ ${string}${string},${string} ${string})` | `light-dark(
65
+ ${string}${string},${string}
66
+ ${string})` | `light-dark(
67
+ ${string}${string},${string}\t${string})` | `light-dark(\t${string}${string},${string} ${string})` | `light-dark(\t${string}${string},${string}
68
+ ${string})` | `light-dark(\t${string}${string},${string}\t${string})` | `light-dark(${string} ${string},${string} ${string})` | `light-dark(${string} ${string},${string}
69
+ ${string})` | `light-dark(${string} ${string},${string}\t${string})` | `light-dark(${string}
70
+ ${string},${string} ${string})` | `light-dark(${string}
71
+ ${string},${string}
72
+ ${string})` | `light-dark(${string}
73
+ ${string},${string}\t${string})` | `light-dark(${string}\t${string},${string} ${string})` | `light-dark(${string}\t${string},${string}
74
+ ${string})` | `light-dark(${string}\t${string},${string}\t${string})` | `light-dark( ${string}${string} ${string},${string} ${string})` | `light-dark( ${string}${string} ${string},${string}
75
+ ${string})` | `light-dark( ${string}${string} ${string},${string}\t${string})` | `light-dark( ${string}${string}
76
+ ${string},${string} ${string})` | `light-dark( ${string}${string}
77
+ ${string},${string}
78
+ ${string})` | `light-dark( ${string}${string}
79
+ ${string},${string}\t${string})` | `light-dark( ${string}${string}\t${string},${string} ${string})` | `light-dark( ${string}${string}\t${string},${string}
80
+ ${string})` | `light-dark( ${string}${string}\t${string},${string}\t${string})` | `light-dark(
81
+ ${string}${string} ${string},${string} ${string})` | `light-dark(
82
+ ${string}${string} ${string},${string}
83
+ ${string})` | `light-dark(
84
+ ${string}${string} ${string},${string}\t${string})` | `light-dark(
85
+ ${string}${string}
86
+ ${string},${string} ${string})` | `light-dark(
87
+ ${string}${string}
88
+ ${string},${string}
89
+ ${string})` | `light-dark(
90
+ ${string}${string}
91
+ ${string},${string}\t${string})` | `light-dark(
92
+ ${string}${string}\t${string},${string} ${string})` | `light-dark(
93
+ ${string}${string}\t${string},${string}
94
+ ${string})` | `light-dark(
95
+ ${string}${string}\t${string},${string}\t${string})` | `light-dark(\t${string}${string} ${string},${string} ${string})` | `light-dark(\t${string}${string} ${string},${string}
96
+ ${string})` | `light-dark(\t${string}${string} ${string},${string}\t${string})` | `light-dark(\t${string}${string}
97
+ ${string},${string} ${string})` | `light-dark(\t${string}${string}
98
+ ${string},${string}
99
+ ${string})` | `light-dark(\t${string}${string}
100
+ ${string},${string}\t${string})` | `light-dark(\t${string}${string}\t${string},${string} ${string})` | `light-dark(\t${string}${string}\t${string},${string}
101
+ ${string})` | `light-dark(\t${string}${string}\t${string},${string}\t${string})` | `light-dark(${string}, ${string}${string} ${string})` | `light-dark(${string}, ${string}${string}
102
+ ${string})` | `light-dark(${string}, ${string}${string}\t${string})` | `light-dark(${string},
103
+ ${string}${string} ${string})` | `light-dark(${string},
104
+ ${string}${string}
105
+ ${string})` | `light-dark(${string},
106
+ ${string}${string}\t${string})` | `light-dark(${string},\t${string}${string} ${string})` | `light-dark(${string},\t${string}${string}
107
+ ${string})` | `light-dark(${string},\t${string}${string}\t${string})` | `light-dark( ${string}${string}, ${string}${string} ${string})` | `light-dark( ${string}${string}, ${string}${string}
108
+ ${string})` | `light-dark( ${string}${string}, ${string}${string}\t${string})` | `light-dark( ${string}${string},
109
+ ${string}${string} ${string})` | `light-dark( ${string}${string},
110
+ ${string}${string}
111
+ ${string})` | `light-dark( ${string}${string},
112
+ ${string}${string}\t${string})` | `light-dark( ${string}${string},\t${string}${string} ${string})` | `light-dark( ${string}${string},\t${string}${string}
113
+ ${string})` | `light-dark( ${string}${string},\t${string}${string}\t${string})` | `light-dark(
114
+ ${string}${string}, ${string}${string} ${string})` | `light-dark(
115
+ ${string}${string}, ${string}${string}
116
+ ${string})` | `light-dark(
117
+ ${string}${string}, ${string}${string}\t${string})` | `light-dark(
118
+ ${string}${string},
119
+ ${string}${string} ${string})` | `light-dark(
120
+ ${string}${string},
121
+ ${string}${string}
122
+ ${string})` | `light-dark(
123
+ ${string}${string},
124
+ ${string}${string}\t${string})` | `light-dark(
125
+ ${string}${string},\t${string}${string} ${string})` | `light-dark(
126
+ ${string}${string},\t${string}${string}
127
+ ${string})` | `light-dark(
128
+ ${string}${string},\t${string}${string}\t${string})` | `light-dark(\t${string}${string}, ${string}${string} ${string})` | `light-dark(\t${string}${string}, ${string}${string}
129
+ ${string})` | `light-dark(\t${string}${string}, ${string}${string}\t${string})` | `light-dark(\t${string}${string},
130
+ ${string}${string} ${string})` | `light-dark(\t${string}${string},
131
+ ${string}${string}
132
+ ${string})` | `light-dark(\t${string}${string},
133
+ ${string}${string}\t${string})` | `light-dark(\t${string}${string},\t${string}${string} ${string})` | `light-dark(\t${string}${string},\t${string}${string}
134
+ ${string})` | `light-dark(\t${string}${string},\t${string}${string}\t${string})` | `light-dark(${string} ${string}, ${string}${string} ${string})` | `light-dark(${string} ${string}, ${string}${string}
135
+ ${string})` | `light-dark(${string} ${string}, ${string}${string}\t${string})` | `light-dark(${string} ${string},
136
+ ${string}${string} ${string})` | `light-dark(${string} ${string},
137
+ ${string}${string}
138
+ ${string})` | `light-dark(${string} ${string},
139
+ ${string}${string}\t${string})` | `light-dark(${string} ${string},\t${string}${string} ${string})` | `light-dark(${string} ${string},\t${string}${string}
140
+ ${string})` | `light-dark(${string} ${string},\t${string}${string}\t${string})` | `light-dark(${string}
141
+ ${string}, ${string}${string} ${string})` | `light-dark(${string}
142
+ ${string}, ${string}${string}
143
+ ${string})` | `light-dark(${string}
144
+ ${string}, ${string}${string}\t${string})` | `light-dark(${string}
145
+ ${string},
146
+ ${string}${string} ${string})` | `light-dark(${string}
147
+ ${string},
148
+ ${string}${string}
149
+ ${string})` | `light-dark(${string}
150
+ ${string},
151
+ ${string}${string}\t${string})` | `light-dark(${string}
152
+ ${string},\t${string}${string} ${string})` | `light-dark(${string}
153
+ ${string},\t${string}${string}
154
+ ${string})` | `light-dark(${string}
155
+ ${string},\t${string}${string}\t${string})` | `light-dark(${string}\t${string}, ${string}${string} ${string})` | `light-dark(${string}\t${string}, ${string}${string}
156
+ ${string})` | `light-dark(${string}\t${string}, ${string}${string}\t${string})` | `light-dark(${string}\t${string},
157
+ ${string}${string} ${string})` | `light-dark(${string}\t${string},
158
+ ${string}${string}
159
+ ${string})` | `light-dark(${string}\t${string},
160
+ ${string}${string}\t${string})` | `light-dark(${string}\t${string},\t${string}${string} ${string})` | `light-dark(${string}\t${string},\t${string}${string}
161
+ ${string})` | `light-dark(${string}\t${string},\t${string}${string}\t${string})` | `light-dark( ${string}${string} ${string}, ${string}${string} ${string})` | `light-dark( ${string}${string} ${string}, ${string}${string}
162
+ ${string})` | `light-dark( ${string}${string} ${string}, ${string}${string}\t${string})` | `light-dark( ${string}${string} ${string},
163
+ ${string}${string} ${string})` | `light-dark( ${string}${string} ${string},
164
+ ${string}${string}
165
+ ${string})` | `light-dark( ${string}${string} ${string},
166
+ ${string}${string}\t${string})` | `light-dark( ${string}${string} ${string},\t${string}${string} ${string})` | `light-dark( ${string}${string} ${string},\t${string}${string}
167
+ ${string})` | `light-dark( ${string}${string} ${string},\t${string}${string}\t${string})` | `light-dark( ${string}${string}
168
+ ${string}, ${string}${string} ${string})` | `light-dark( ${string}${string}
169
+ ${string}, ${string}${string}
170
+ ${string})` | `light-dark( ${string}${string}
171
+ ${string}, ${string}${string}\t${string})` | `light-dark( ${string}${string}
172
+ ${string},
173
+ ${string}${string} ${string})` | `light-dark( ${string}${string}
174
+ ${string},
175
+ ${string}${string}
176
+ ${string})` | `light-dark( ${string}${string}
177
+ ${string},
178
+ ${string}${string}\t${string})` | `light-dark( ${string}${string}
179
+ ${string},\t${string}${string} ${string})` | `light-dark( ${string}${string}
180
+ ${string},\t${string}${string}
181
+ ${string})` | `light-dark( ${string}${string}
182
+ ${string},\t${string}${string}\t${string})` | `light-dark( ${string}${string}\t${string}, ${string}${string} ${string})` | `light-dark( ${string}${string}\t${string}, ${string}${string}
183
+ ${string})` | `light-dark( ${string}${string}\t${string}, ${string}${string}\t${string})` | `light-dark( ${string}${string}\t${string},
184
+ ${string}${string} ${string})` | `light-dark( ${string}${string}\t${string},
185
+ ${string}${string}
186
+ ${string})` | `light-dark( ${string}${string}\t${string},
187
+ ${string}${string}\t${string})` | `light-dark( ${string}${string}\t${string},\t${string}${string} ${string})` | `light-dark( ${string}${string}\t${string},\t${string}${string}
188
+ ${string})` | `light-dark( ${string}${string}\t${string},\t${string}${string}\t${string})` | `light-dark(
189
+ ${string}${string} ${string}, ${string}${string} ${string})` | `light-dark(
190
+ ${string}${string} ${string}, ${string}${string}
191
+ ${string})` | `light-dark(
192
+ ${string}${string} ${string}, ${string}${string}\t${string})` | `light-dark(
193
+ ${string}${string} ${string},
194
+ ${string}${string} ${string})` | `light-dark(
195
+ ${string}${string} ${string},
196
+ ${string}${string}
197
+ ${string})` | `light-dark(
198
+ ${string}${string} ${string},
199
+ ${string}${string}\t${string})` | `light-dark(
200
+ ${string}${string} ${string},\t${string}${string} ${string})` | `light-dark(
201
+ ${string}${string} ${string},\t${string}${string}
202
+ ${string})` | `light-dark(
203
+ ${string}${string} ${string},\t${string}${string}\t${string})` | `light-dark(
204
+ ${string}${string}
205
+ ${string}, ${string}${string} ${string})` | `light-dark(
206
+ ${string}${string}
207
+ ${string}, ${string}${string}
208
+ ${string})` | `light-dark(
209
+ ${string}${string}
210
+ ${string}, ${string}${string}\t${string})` | `light-dark(
211
+ ${string}${string}
212
+ ${string},
213
+ ${string}${string} ${string})` | `light-dark(
214
+ ${string}${string}
215
+ ${string},
216
+ ${string}${string}
217
+ ${string})` | `light-dark(
218
+ ${string}${string}
219
+ ${string},
220
+ ${string}${string}\t${string})` | `light-dark(
221
+ ${string}${string}
222
+ ${string},\t${string}${string} ${string})` | `light-dark(
223
+ ${string}${string}
224
+ ${string},\t${string}${string}
225
+ ${string})` | `light-dark(
226
+ ${string}${string}
227
+ ${string},\t${string}${string}\t${string})` | `light-dark(
228
+ ${string}${string}\t${string}, ${string}${string} ${string})` | `light-dark(
229
+ ${string}${string}\t${string}, ${string}${string}
230
+ ${string})` | `light-dark(
231
+ ${string}${string}\t${string}, ${string}${string}\t${string})` | `light-dark(
232
+ ${string}${string}\t${string},
233
+ ${string}${string} ${string})` | `light-dark(
234
+ ${string}${string}\t${string},
235
+ ${string}${string}
236
+ ${string})` | `light-dark(
237
+ ${string}${string}\t${string},
238
+ ${string}${string}\t${string})` | `light-dark(
239
+ ${string}${string}\t${string},\t${string}${string} ${string})` | `light-dark(
240
+ ${string}${string}\t${string},\t${string}${string}
241
+ ${string})` | `light-dark(
242
+ ${string}${string}\t${string},\t${string}${string}\t${string})` | `light-dark(\t${string}${string} ${string}, ${string}${string} ${string})` | `light-dark(\t${string}${string} ${string}, ${string}${string}
243
+ ${string})` | `light-dark(\t${string}${string} ${string}, ${string}${string}\t${string})` | `light-dark(\t${string}${string} ${string},
244
+ ${string}${string} ${string})` | `light-dark(\t${string}${string} ${string},
245
+ ${string}${string}
246
+ ${string})` | `light-dark(\t${string}${string} ${string},
247
+ ${string}${string}\t${string})` | `light-dark(\t${string}${string} ${string},\t${string}${string} ${string})` | `light-dark(\t${string}${string} ${string},\t${string}${string}
248
+ ${string})` | `light-dark(\t${string}${string} ${string},\t${string}${string}\t${string})` | `light-dark(\t${string}${string}
249
+ ${string}, ${string}${string} ${string})` | `light-dark(\t${string}${string}
250
+ ${string}, ${string}${string}
251
+ ${string})` | `light-dark(\t${string}${string}
252
+ ${string}, ${string}${string}\t${string})` | `light-dark(\t${string}${string}
253
+ ${string},
254
+ ${string}${string} ${string})` | `light-dark(\t${string}${string}
255
+ ${string},
256
+ ${string}${string}
257
+ ${string})` | `light-dark(\t${string}${string}
258
+ ${string},
259
+ ${string}${string}\t${string})` | `light-dark(\t${string}${string}
260
+ ${string},\t${string}${string} ${string})` | `light-dark(\t${string}${string}
261
+ ${string},\t${string}${string}
262
+ ${string})` | `light-dark(\t${string}${string}
263
+ ${string},\t${string}${string}\t${string})` | `light-dark(\t${string}${string}\t${string}, ${string}${string} ${string})` | `light-dark(\t${string}${string}\t${string}, ${string}${string}
264
+ ${string})` | `light-dark(\t${string}${string}\t${string}, ${string}${string}\t${string})` | `light-dark(\t${string}${string}\t${string},
265
+ ${string}${string} ${string})` | `light-dark(\t${string}${string}\t${string},
266
+ ${string}${string}
267
+ ${string})` | `light-dark(\t${string}${string}\t${string},
268
+ ${string}${string}\t${string})` | `light-dark(\t${string}${string}\t${string},\t${string}${string} ${string})` | `light-dark(\t${string}${string}\t${string},\t${string}${string}
269
+ ${string})` | `light-dark(\t${string}${string}\t${string},\t${string}${string}\t${string})`, {
270
+ captures: [string, string];
271
+ }>;
272
+ /** Options for {@link makeResolver}. */
273
+ interface ResolveOptions {
274
+ /** Collapse `light-dark()` to this branch; omit to keep `light-dark()` intact. */
275
+ mode?: Mode;
276
+ /** Tokens that override the base set (win on name collisions, e.g. a caller's IR over a theme). */
277
+ overrides?: readonly Token[];
278
+ }
279
+ /**
280
+ * Build a resolver that expands `var(--x)` references to concrete leaf values against `base` (plus
281
+ * any `overrides`). With `mode` it collapses `light-dark()` to that branch; without, it leaves
282
+ * `light-dark()` in place.
283
+ *
284
+ * @param base - The token set to resolve references against.
285
+ * @param options - {@link ResolveOptions}.
286
+ * @returns A function that resolves a value string.
287
+ *
288
+ * @example Expand a reference chain to its concrete leaf
289
+ * ```ts
290
+ * import { makeResolver } from "@pantoken/utils";
291
+ * import type { Token } from "@pantoken/model";
292
+ *
293
+ * const ir: Token[] = [
294
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
295
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
296
+ * ];
297
+ *
298
+ * const resolve = makeResolver(ir);
299
+ * resolve("var(--instui-brand)"); // → "#0374B5"
300
+ * ```
301
+ *
302
+ * @example Collapse light-dark() with a mode, or keep it without one
303
+ * ```ts
304
+ * import { makeResolver } from "@pantoken/utils";
305
+ * import type { Token } from "@pantoken/model";
306
+ *
307
+ * const ir: Token[] = [
308
+ * { name: "--instui-bg", syntax: "*", inherits: true, value: "light-dark(#fff, #000)" },
309
+ * ];
310
+ *
311
+ * makeResolver(ir)("var(--instui-bg)"); // → "light-dark(#fff, #000)"
312
+ * makeResolver(ir, { mode: "light" })("var(--instui-bg)"); // → "#fff"
313
+ * makeResolver(ir, { mode: "dark" })("var(--instui-bg)"); // → "#000"
314
+ * ```
315
+ *
316
+ * @example Layer overrides that win on name collisions
317
+ * ```ts
318
+ * import { makeResolver } from "@pantoken/utils";
319
+ * import type { Token } from "@pantoken/model";
320
+ *
321
+ * const ir: Token[] = [
322
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
323
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
324
+ * ];
325
+ * const overrides: Token[] = [
326
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#000" },
327
+ * ];
328
+ *
329
+ * makeResolver(ir, { overrides })("var(--instui-brand)"); // → "#000"
330
+ * ```
331
+ */
332
+ declare function makeResolver(base: readonly Token[], options?: ResolveOptions): (value: string) => string;
333
+ /**
334
+ * Resolve every token's value against the set (see {@link makeResolver}), keyed by name.
335
+ *
336
+ * @example Resolve a whole IR to a name → value map
337
+ * ```ts
338
+ * import { resolveTokens } from "@pantoken/utils";
339
+ * import type { Token } from "@pantoken/model";
340
+ *
341
+ * const ir: Token[] = [
342
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
343
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
344
+ * { name: "--instui-bg", syntax: "*", inherits: true, value: "light-dark(#fff, #000)" },
345
+ * ];
346
+ *
347
+ * const byName = resolveTokens(ir, { mode: "dark" });
348
+ * byName.get("--instui-brand"); // → "#0374B5"
349
+ * byName.get("--instui-bg"); // → "#000"
350
+ * ```
351
+ */
352
+ declare function resolveTokens(base: readonly Token[], options?: ResolveOptions): Map<string, string>;
353
+ /**
354
+ * Convert a kebab-case string to camelCase (`color-background-brand` → `colorBackgroundBrand`).
355
+ *
356
+ * @example
357
+ * ```ts
358
+ * import { camelCase } from "@pantoken/utils";
359
+ *
360
+ * camelCase("color-background-brand"); // → "colorBackgroundBrand"
361
+ * ```
362
+ */
363
+ declare function camelCase(kebab: string): string;
364
+ /** An RGBA colour: `r`/`g`/`b` are 0–255 integers, `a` is 0–1 (defaults to 1). */
365
+ interface Rgba {
366
+ r: number;
367
+ g: number;
368
+ b: number;
369
+ a: number;
370
+ }
371
+ /**
372
+ * Parse `#rgb`, `#rrggbb`, or `#rrggbbaa` to {@link Rgba}; returns `undefined` otherwise.
373
+ *
374
+ * @example
375
+ * ```ts
376
+ * import { parseHexColor } from "@pantoken/utils";
377
+ *
378
+ * parseHexColor("#fff"); // → { r: 255, g: 255, b: 255, a: 1 }
379
+ * parseHexColor("#0374B5"); // → { r: 3, g: 116, b: 181, a: 1 }
380
+ * parseHexColor("#00000080"); // → { r: 0, g: 0, b: 0, a: 0.5019… }
381
+ * parseHexColor("nope"); // → undefined
382
+ * ```
383
+ */
384
+ declare function parseHexColor(hex: string): Rgba | undefined;
385
+ /**
386
+ * Every `--instui-*` custom-property name that appears anywhere in `text`.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * import { extractInstuiRefs } from "@pantoken/utils";
391
+ *
392
+ * extractInstuiRefs(".b { color: var(--instui-color-text-base); }");
393
+ * // → Set { "--instui-color-text-base" }
394
+ * ```
395
+ */
396
+ declare function extractInstuiRefs(text: string): Set<string>;
397
+ /**
398
+ * The set of token names an IR defines.
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * import { tokenNames } from "@pantoken/utils";
403
+ * import type { Token } from "@pantoken/model";
404
+ *
405
+ * const ir: Token[] = [
406
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
407
+ * ];
408
+ * tokenNames(ir); // → Set { "--instui-leaf" }
409
+ * ```
410
+ */
411
+ declare function tokenNames(ir: readonly Token[]): Set<string>;
412
+ /**
413
+ * Drift check: `--instui-*` names in `text` that the IR doesn't define (sorted; empty means no
414
+ * drift). Use for outputs that *reference* tokens defined elsewhere — e.g. the docusaurus/vitepress
415
+ * bridges, whose `var(--instui-*)` targets must all be real tokens.
416
+ *
417
+ * @param text - The generated output.
418
+ * @param ir - The source token IR.
419
+ * @returns The unknown token names.
420
+ *
421
+ * @example
422
+ * ```ts
423
+ * import { unknownReferences } from "@pantoken/utils";
424
+ * import type { Token } from "@pantoken/model";
425
+ *
426
+ * const ir: Token[] = [
427
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
428
+ * ];
429
+ *
430
+ * unknownReferences("--x: var(--instui-leaf); --y: var(--instui-gone);", ir);
431
+ * // → ["--instui-gone"]
432
+ * unknownReferences("--x: var(--instui-leaf);", ir); // → [] (no drift)
433
+ * ```
434
+ */
435
+ declare function unknownReferences(text: string, ir: readonly Token[]): string[];
436
+ /**
437
+ * Self-containment check: `--instui-*` names referenced via `var()` in a stylesheet that it never
438
+ * defines (as an `@property` registration or a `--x:` declaration). Sorted; empty means every
439
+ * reference resolves within the same output. Use for self-contained stylesheets (css, pendo).
440
+ *
441
+ * @param css - The generated stylesheet.
442
+ * @returns The dangling reference names.
443
+ *
444
+ * @example
445
+ * ```ts
446
+ * import { danglingReferences } from "@pantoken/utils";
447
+ *
448
+ * // Self-contained: the referenced property is also defined here.
449
+ * danglingReferences("@property --instui-a {} .b { color: var(--instui-a); }"); // → []
450
+ *
451
+ * // Dangling: `--instui-b` is referenced but never defined.
452
+ * danglingReferences(
453
+ * ":root { --instui-a: red; } .b { color: var(--instui-a); background: var(--instui-b); }",
454
+ * ); // → ["--instui-b"]
455
+ * ```
456
+ */
457
+ declare function danglingReferences(css: string): string[];
458
+ /** Options shared by the utility-class emitters. */
459
+ interface UtilityOptions {
460
+ /**
461
+ * The class prefix. Any truthy string namespaces every class (`"instui"` → `.instui-bg-…`); any
462
+ * falsy value (`null`/`undefined`/`""`) drops the prefix entirely (`.bg-…`).
463
+ */
464
+ prefix?: string | null;
465
+ }
466
+ /** The semantic colour token names (without the `--instui-color-<family>-` prefix) per family. */
467
+ interface ColorUtilityNames {
468
+ background: readonly string[];
469
+ text: readonly string[];
470
+ stroke: readonly string[];
471
+ }
472
+ /**
473
+ * Build the semantic-colour utility stylesheet: `.<prefix>-bg-<name>` (background),
474
+ * `.<prefix>-fg-<name>` (text colour), `.<prefix>-border-<name>` (border colour), one per semantic
475
+ * colour token. Overrides are therefore only ever token-valid — no primitives, no arbitrary hex. Pass
476
+ * the token names per family (e.g. from `@pantoken/tokens`).
477
+ *
478
+ * @param names - {@link ColorUtilityNames}.
479
+ * @param options - {@link UtilityOptions}.
480
+ * @returns The CSS string.
481
+ *
482
+ * @demo self:color-utilities
483
+ */
484
+ declare function colorUtilitiesCss(names: ColorUtilityNames, options?: UtilityOptions): string;
485
+ /** A set of tokens that all map to one CSS property (e.g. every `--instui-font-weight-*` → `font-weight`). */
486
+ interface TokenUtilityGroup {
487
+ /** The CSS property the tokens set (e.g. `"font-weight"`, `"border-radius"`, `"box-shadow"`). */
488
+ property: string;
489
+ /** Full token names (e.g. `"--instui-font-weight-body-strong"`); the `--instui-` tail becomes the class. */
490
+ tokens: readonly string[];
491
+ }
492
+ /**
493
+ * Build token-driven utility classes: one class per token, applying it to its natural CSS property. The
494
+ * token's `--instui-` tail is the class name, so `--instui-font-weight-body-strong` under property
495
+ * `font-weight` yields
496
+ * `.<prefix>-font-weight-body-strong { font-weight: var(--instui-font-weight-body-strong); }`. Use it for
497
+ * every "one token → one property" family (font-family/weight, line-height, border-radius, border-width,
498
+ * opacity, box-shadow). Colour and spacing keep their own builders — one token maps to several
499
+ * properties there. Pass the token names per property (e.g. filtered from `@pantoken/tokens`).
500
+ *
501
+ * @param groups - one {@link TokenUtilityGroup} per CSS property.
502
+ * @param options - {@link UtilityOptions}.
503
+ * @returns The CSS string.
504
+ *
505
+ * @demo self:token-utilities
506
+ */
507
+ declare function tokenUtilitiesCss(groups: readonly TokenUtilityGroup[], options?: UtilityOptions): string;
508
+ //#endregion
509
+ export { ColorUtilityNames, LIGHT_DARK_RE, Mode, ResolveOptions, Rgba, TokenUtilityGroup, UtilityOptions, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, extractInstuiRefs, makeResolver, parseHexColor, resolveTokens, tokenNames, tokenUtilitiesCss, unknownReferences };
package/dist/index.mjs ADDED
@@ -0,0 +1,286 @@
1
+ import { regex } from "arkregex";
2
+ //#region src/index.ts
3
+ /**
4
+ * `@pantoken/utils` — shared, upstream-free helpers used across the pantoken packages: the token
5
+ * reference resolver (with `light-dark()` handling), the two token regexes (typed via `arkregex`),
6
+ * kebab→camel case, hex-colour parsing, and the generic token→utility-class emitters
7
+ * ({@link colorUtilitiesCss}, {@link tokenUtilitiesCss}) that both `@pantoken/components` (semantic
8
+ * tier) and `@pantoken/plugin-primitives` (raw-palette tier) build on. Depends only on
9
+ * `@pantoken/model` (types) + `arkregex`, so any package can use it without pulling the GitHub-only
10
+ * upstream.
11
+ *
12
+ * @module
13
+ * @beta
14
+ */
15
+ const VAR_SOURCE = "var\\(\\s*(--[\\w-]+)[^)]*\\)";
16
+ const LIGHT_DARK_SOURCE = "^light-dark\\(\\s*(.+?)\\s*,\\s*(.+?)\\s*\\)$";
17
+ /** A `var(--custom-prop)` reference (optional fallback); capture group 1 is the property name. */
18
+ const VAR_RE = regex(VAR_SOURCE, "g");
19
+ /** A `light-dark(<light>, <dark>)` value; capture groups 1 and 2 are the two branches. */
20
+ const LIGHT_DARK_RE = regex(LIGHT_DARK_SOURCE);
21
+ const MAX_DEPTH = 12;
22
+ /**
23
+ * Build a resolver that expands `var(--x)` references to concrete leaf values against `base` (plus
24
+ * any `overrides`). With `mode` it collapses `light-dark()` to that branch; without, it leaves
25
+ * `light-dark()` in place.
26
+ *
27
+ * @param base - The token set to resolve references against.
28
+ * @param options - {@link ResolveOptions}.
29
+ * @returns A function that resolves a value string.
30
+ *
31
+ * @example Expand a reference chain to its concrete leaf
32
+ * ```ts
33
+ * import { makeResolver } from "@pantoken/utils";
34
+ * import type { Token } from "@pantoken/model";
35
+ *
36
+ * const ir: Token[] = [
37
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
38
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
39
+ * ];
40
+ *
41
+ * const resolve = makeResolver(ir);
42
+ * resolve("var(--instui-brand)"); // → "#0374B5"
43
+ * ```
44
+ *
45
+ * @example Collapse light-dark() with a mode, or keep it without one
46
+ * ```ts
47
+ * import { makeResolver } from "@pantoken/utils";
48
+ * import type { Token } from "@pantoken/model";
49
+ *
50
+ * const ir: Token[] = [
51
+ * { name: "--instui-bg", syntax: "*", inherits: true, value: "light-dark(#fff, #000)" },
52
+ * ];
53
+ *
54
+ * makeResolver(ir)("var(--instui-bg)"); // → "light-dark(#fff, #000)"
55
+ * makeResolver(ir, { mode: "light" })("var(--instui-bg)"); // → "#fff"
56
+ * makeResolver(ir, { mode: "dark" })("var(--instui-bg)"); // → "#000"
57
+ * ```
58
+ *
59
+ * @example Layer overrides that win on name collisions
60
+ * ```ts
61
+ * import { makeResolver } from "@pantoken/utils";
62
+ * import type { Token } from "@pantoken/model";
63
+ *
64
+ * const ir: Token[] = [
65
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
66
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
67
+ * ];
68
+ * const overrides: Token[] = [
69
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#000" },
70
+ * ];
71
+ *
72
+ * makeResolver(ir, { overrides })("var(--instui-brand)"); // → "#000"
73
+ * ```
74
+ */
75
+ function makeResolver(base, options = {}) {
76
+ const map = new Map(base.map((t) => [t.name, t.value]));
77
+ for (const t of options.overrides ?? []) map.set(t.name, t.value);
78
+ const pickMode = (value) => {
79
+ if (!options.mode) return value;
80
+ const m = LIGHT_DARK_RE.exec(value.trim());
81
+ return m ? options.mode === "light" ? m[1] : m[2] : value;
82
+ };
83
+ const expand = (value, depth) => {
84
+ const picked = pickMode(value);
85
+ if (depth >= MAX_DEPTH || !picked.includes("var(")) return picked;
86
+ return picked.replace(new RegExp(VAR_SOURCE, "g"), (whole, name) => {
87
+ const inner = map.get(name);
88
+ return inner === void 0 ? whole : expand(inner, depth + 1);
89
+ });
90
+ };
91
+ return (value) => expand(value, 0);
92
+ }
93
+ /**
94
+ * Resolve every token's value against the set (see {@link makeResolver}), keyed by name.
95
+ *
96
+ * @example Resolve a whole IR to a name → value map
97
+ * ```ts
98
+ * import { resolveTokens } from "@pantoken/utils";
99
+ * import type { Token } from "@pantoken/model";
100
+ *
101
+ * const ir: Token[] = [
102
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
103
+ * { name: "--instui-brand", syntax: "*", inherits: true, value: "var(--instui-leaf)" },
104
+ * { name: "--instui-bg", syntax: "*", inherits: true, value: "light-dark(#fff, #000)" },
105
+ * ];
106
+ *
107
+ * const byName = resolveTokens(ir, { mode: "dark" });
108
+ * byName.get("--instui-brand"); // → "#0374B5"
109
+ * byName.get("--instui-bg"); // → "#000"
110
+ * ```
111
+ */
112
+ function resolveTokens(base, options = {}) {
113
+ const resolve = makeResolver(base, options);
114
+ return new Map(base.map((t) => [t.name, resolve(t.value)]));
115
+ }
116
+ /**
117
+ * Convert a kebab-case string to camelCase (`color-background-brand` → `colorBackgroundBrand`).
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { camelCase } from "@pantoken/utils";
122
+ *
123
+ * camelCase("color-background-brand"); // → "colorBackgroundBrand"
124
+ * ```
125
+ */
126
+ function camelCase(kebab) {
127
+ return kebab.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
128
+ }
129
+ /**
130
+ * Parse `#rgb`, `#rrggbb`, or `#rrggbbaa` to {@link Rgba}; returns `undefined` otherwise.
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * import { parseHexColor } from "@pantoken/utils";
135
+ *
136
+ * parseHexColor("#fff"); // → { r: 255, g: 255, b: 255, a: 1 }
137
+ * parseHexColor("#0374B5"); // → { r: 3, g: 116, b: 181, a: 1 }
138
+ * parseHexColor("#00000080"); // → { r: 0, g: 0, b: 0, a: 0.5019… }
139
+ * parseHexColor("nope"); // → undefined
140
+ * ```
141
+ */
142
+ function parseHexColor(hex) {
143
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(hex.trim());
144
+ if (!m) return void 0;
145
+ let h = m[1];
146
+ if (h.length === 3) h = h.replace(/(.)/g, "$1$1");
147
+ return {
148
+ r: Number.parseInt(h.slice(0, 2), 16),
149
+ g: Number.parseInt(h.slice(2, 4), 16),
150
+ b: Number.parseInt(h.slice(4, 6), 16),
151
+ a: h.length === 8 ? Number.parseInt(h.slice(6, 8), 16) / 255 : 1
152
+ };
153
+ }
154
+ /**
155
+ * Every `--instui-*` custom-property name that appears anywhere in `text`.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * import { extractInstuiRefs } from "@pantoken/utils";
160
+ *
161
+ * extractInstuiRefs(".b { color: var(--instui-color-text-base); }");
162
+ * // → Set { "--instui-color-text-base" }
163
+ * ```
164
+ */
165
+ function extractInstuiRefs(text) {
166
+ return new Set([...text.matchAll(/--instui-[\w-]+/g)].map((m) => m[0]));
167
+ }
168
+ /**
169
+ * The set of token names an IR defines.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * import { tokenNames } from "@pantoken/utils";
174
+ * import type { Token } from "@pantoken/model";
175
+ *
176
+ * const ir: Token[] = [
177
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
178
+ * ];
179
+ * tokenNames(ir); // → Set { "--instui-leaf" }
180
+ * ```
181
+ */
182
+ function tokenNames(ir) {
183
+ return new Set(ir.map((t) => t.name));
184
+ }
185
+ /**
186
+ * Drift check: `--instui-*` names in `text` that the IR doesn't define (sorted; empty means no
187
+ * drift). Use for outputs that *reference* tokens defined elsewhere — e.g. the docusaurus/vitepress
188
+ * bridges, whose `var(--instui-*)` targets must all be real tokens.
189
+ *
190
+ * @param text - The generated output.
191
+ * @param ir - The source token IR.
192
+ * @returns The unknown token names.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * import { unknownReferences } from "@pantoken/utils";
197
+ * import type { Token } from "@pantoken/model";
198
+ *
199
+ * const ir: Token[] = [
200
+ * { name: "--instui-leaf", syntax: "<color>", inherits: true, value: "#0374B5" },
201
+ * ];
202
+ *
203
+ * unknownReferences("--x: var(--instui-leaf); --y: var(--instui-gone);", ir);
204
+ * // → ["--instui-gone"]
205
+ * unknownReferences("--x: var(--instui-leaf);", ir); // → [] (no drift)
206
+ * ```
207
+ */
208
+ function unknownReferences(text, ir) {
209
+ const names = tokenNames(ir);
210
+ return [...extractInstuiRefs(text)].filter((name) => !names.has(name)).sort();
211
+ }
212
+ /**
213
+ * Self-containment check: `--instui-*` names referenced via `var()` in a stylesheet that it never
214
+ * defines (as an `@property` registration or a `--x:` declaration). Sorted; empty means every
215
+ * reference resolves within the same output. Use for self-contained stylesheets (css, pendo).
216
+ *
217
+ * @param css - The generated stylesheet.
218
+ * @returns The dangling reference names.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * import { danglingReferences } from "@pantoken/utils";
223
+ *
224
+ * // Self-contained: the referenced property is also defined here.
225
+ * danglingReferences("@property --instui-a {} .b { color: var(--instui-a); }"); // → []
226
+ *
227
+ * // Dangling: `--instui-b` is referenced but never defined.
228
+ * danglingReferences(
229
+ * ":root { --instui-a: red; } .b { color: var(--instui-a); background: var(--instui-b); }",
230
+ * ); // → ["--instui-b"]
231
+ * ```
232
+ */
233
+ function danglingReferences(css) {
234
+ const referenced = new Set([...css.matchAll(/var\(\s*(--instui-[\w-]+)/g)].map((m) => m[1]));
235
+ const defined = /* @__PURE__ */ new Set();
236
+ for (const m of css.matchAll(/@property\s+(--instui-[\w-]+)/g)) defined.add(m[1]);
237
+ for (const m of css.matchAll(/(--instui-[\w-]+)\s*:/g)) defined.add(m[1]);
238
+ return [...referenced].filter((name) => !defined.has(name)).sort();
239
+ }
240
+ /**
241
+ * Build the semantic-colour utility stylesheet: `.<prefix>-bg-<name>` (background),
242
+ * `.<prefix>-fg-<name>` (text colour), `.<prefix>-border-<name>` (border colour), one per semantic
243
+ * colour token. Overrides are therefore only ever token-valid — no primitives, no arbitrary hex. Pass
244
+ * the token names per family (e.g. from `@pantoken/tokens`).
245
+ *
246
+ * @param names - {@link ColorUtilityNames}.
247
+ * @param options - {@link UtilityOptions}.
248
+ * @returns The CSS string.
249
+ *
250
+ * @demo self:color-utilities
251
+ */
252
+ function colorUtilitiesCss(names, options = {}) {
253
+ const prefix = options.prefix || "";
254
+ const p = prefix ? `${prefix}-` : "";
255
+ const emit = (family, util, prop, list) => list.map((n) => `.${p}${util}-${n} { ${prop}: var(--instui-color-${family}-${n}); }`).join("\n");
256
+ return `/* InstUI semantic colour utilities (@pantoken/utils) — prefix: ${prefix} */\n${[
257
+ emit("background", "bg", "background", names.background),
258
+ emit("text", "fg", "color", names.text),
259
+ emit("stroke", "border", "border-color", names.stroke)
260
+ ].join("\n")}\n`;
261
+ }
262
+ /**
263
+ * Build token-driven utility classes: one class per token, applying it to its natural CSS property. The
264
+ * token's `--instui-` tail is the class name, so `--instui-font-weight-body-strong` under property
265
+ * `font-weight` yields
266
+ * `.<prefix>-font-weight-body-strong { font-weight: var(--instui-font-weight-body-strong); }`. Use it for
267
+ * every "one token → one property" family (font-family/weight, line-height, border-radius, border-width,
268
+ * opacity, box-shadow). Colour and spacing keep their own builders — one token maps to several
269
+ * properties there. Pass the token names per property (e.g. filtered from `@pantoken/tokens`).
270
+ *
271
+ * @param groups - one {@link TokenUtilityGroup} per CSS property.
272
+ * @param options - {@link UtilityOptions}.
273
+ * @returns The CSS string.
274
+ *
275
+ * @demo self:token-utilities
276
+ */
277
+ function tokenUtilitiesCss(groups, options = {}) {
278
+ const prefix = options.prefix || "";
279
+ const p = prefix ? `${prefix}-` : "";
280
+ return `/* InstUI token utilities (@pantoken/utils) — prefix: ${prefix} */\n${groups.flatMap(({ property, tokens }) => tokens.map((token) => {
281
+ const name = token.replace(/^--instui-/, "");
282
+ return `.${p}${name} { ${property}: var(${token}); }`;
283
+ })).join("\n")}\n`;
284
+ }
285
+ //#endregion
286
+ export { LIGHT_DARK_RE, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, extractInstuiRefs, makeResolver, parseHexColor, resolveTokens, tokenNames, tokenUtilitiesCss, unknownReferences };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@pantoken/utils",
3
+ "version": "0.1.0",
4
+ "description": "Shared pantoken helpers: token reference resolver, typed regexes (arkregex), name-case, and hex-colour parsing.",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "exports": {
11
+ ".": "./dist/index.mjs",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "dependencies": {
18
+ "arkregex": "^0.0.8",
19
+ "@pantoken/model": "0.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^24.13.3",
23
+ "typescript": "^6.0.3",
24
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.4",
25
+ "vite-plus": "0.2.4"
26
+ },
27
+ "scripts": {
28
+ "build": "vp pack",
29
+ "dev": "vp pack --watch",
30
+ "test": "vp test",
31
+ "check": "vp check"
32
+ }
33
+ }