@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 +71 -0
- package/dist/index.d.mts +509 -0
- package/dist/index.mjs +286 -0
- package/package.json +33 -0
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
|
package/dist/index.d.mts
ADDED
|
@@ -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
|
+
}
|