@mortenbrudvik/waveui 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -17
- package/dist/components/input/Label.cjs +1 -1
- package/dist/components/input/Label.cjs.map +1 -1
- package/dist/components/input/Label.mjs +1 -0
- package/dist/components/input/Label.mjs.map +1 -1
- package/dist/components/portal/Portal.cjs +1 -1
- package/dist/components/portal/Portal.cjs.map +1 -1
- package/dist/components/portal/Portal.mjs +12 -11
- package/dist/components/portal/Portal.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +61 -35
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/components/typography/Text.cjs +1 -1
- package/dist/components/typography/Text.cjs.map +1 -1
- package/dist/components/typography/Text.mjs +11 -7
- package/dist/components/typography/Text.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +271 -10
- package/dist/index.d.ts +271 -10
- package/dist/index.mjs +143 -140
- package/dist/lib/brand.cjs +2 -0
- package/dist/lib/brand.cjs.map +1 -0
- package/dist/lib/brand.mjs +358 -0
- package/dist/lib/brand.mjs.map +1 -0
- package/dist/lib/cn.cjs +1 -1
- package/dist/lib/cn.cjs.map +1 -1
- package/dist/lib/cn.mjs +5 -1
- package/dist/lib/cn.mjs.map +1 -1
- package/dist/lib/tokens.cjs +3 -0
- package/dist/lib/tokens.cjs.map +1 -0
- package/dist/lib/tokens.mjs +55 -0
- package/dist/lib/tokens.mjs.map +1 -0
- package/dist/lib/waveTokens.cjs +2 -0
- package/dist/lib/waveTokens.cjs.map +1 -0
- package/dist/lib/waveTokens.mjs +24 -0
- package/dist/lib/waveTokens.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +3 -1
- package/src/styles/tokens.css +210 -10
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { warnOnce as e } from "./dev.mjs";
|
|
2
|
+
//#region src/lib/brand.ts
|
|
3
|
+
var t = [
|
|
4
|
+
10,
|
|
5
|
+
20,
|
|
6
|
+
30,
|
|
7
|
+
40,
|
|
8
|
+
50,
|
|
9
|
+
60,
|
|
10
|
+
70,
|
|
11
|
+
80,
|
|
12
|
+
90,
|
|
13
|
+
100,
|
|
14
|
+
110,
|
|
15
|
+
120,
|
|
16
|
+
130,
|
|
17
|
+
140,
|
|
18
|
+
150,
|
|
19
|
+
160
|
|
20
|
+
], n = 7, r = /* @__PURE__ */ Object.freeze({
|
|
21
|
+
10: "#061724",
|
|
22
|
+
20: "#082338",
|
|
23
|
+
30: "#0a2e4a",
|
|
24
|
+
40: "#0c3b5e",
|
|
25
|
+
50: "#0e4775",
|
|
26
|
+
60: "#0f548c",
|
|
27
|
+
70: "#115ea3",
|
|
28
|
+
80: "#0f6cbd",
|
|
29
|
+
90: "#2886de",
|
|
30
|
+
100: "#479ef5",
|
|
31
|
+
110: "#62abf5",
|
|
32
|
+
120: "#77b7f7",
|
|
33
|
+
130: "#96c6fa",
|
|
34
|
+
140: "#b4d6fa",
|
|
35
|
+
150: "#cfe4fa",
|
|
36
|
+
160: "#ebf3fc"
|
|
37
|
+
}), i = .005, a = [
|
|
38
|
+
10,
|
|
39
|
+
20,
|
|
40
|
+
30,
|
|
41
|
+
40,
|
|
42
|
+
50,
|
|
43
|
+
60,
|
|
44
|
+
70,
|
|
45
|
+
80,
|
|
46
|
+
140
|
|
47
|
+
];
|
|
48
|
+
function o(e) {
|
|
49
|
+
if (typeof e != "string") return;
|
|
50
|
+
let t = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(e);
|
|
51
|
+
if (!t) return;
|
|
52
|
+
let n = t[1].length === 3 ? t[1].replace(/./g, "$&$&") : t[1];
|
|
53
|
+
return [
|
|
54
|
+
0,
|
|
55
|
+
2,
|
|
56
|
+
4
|
|
57
|
+
].map((e) => parseInt(n.slice(e, e + 2), 16));
|
|
58
|
+
}
|
|
59
|
+
function s(e) {
|
|
60
|
+
let t = e / 255;
|
|
61
|
+
return t <= .04045 ? t / 12.92 : ((t + .055) / 1.055) ** 2.4;
|
|
62
|
+
}
|
|
63
|
+
function c(e) {
|
|
64
|
+
let t = Math.min(1, Math.max(0, e));
|
|
65
|
+
return 255 * (t <= .0031308 ? t * 12.92 : 1.055 * t ** (1 / 2.4) - .055);
|
|
66
|
+
}
|
|
67
|
+
function l([e, t, n]) {
|
|
68
|
+
return .2126 * e + .7152 * t + .0722 * n;
|
|
69
|
+
}
|
|
70
|
+
function u([e, t, n]) {
|
|
71
|
+
let r = Math.cbrt(.4122214708 * e + .5363325363 * t + .0514459929 * n), i = Math.cbrt(.2119034982 * e + .6806995451 * t + .1073969566 * n), a = Math.cbrt(.0883024619 * e + .2817188376 * t + .6299787005 * n);
|
|
72
|
+
return [
|
|
73
|
+
.2104542553 * r + .793617785 * i - .0040720468 * a,
|
|
74
|
+
1.9779984951 * r - 2.428592205 * i + .4505937099 * a,
|
|
75
|
+
.0259040371 * r + .7827717662 * i - .808675766 * a
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
function d(e, t, n) {
|
|
79
|
+
let r = t * Math.cos(n), i = t * Math.sin(n), a = (e + .3963377774 * r + .2158037573 * i) ** 3, o = (e - .1055613458 * r - .0638541728 * i) ** 3, s = (e - .0894841775 * r - 1.291485548 * i) ** 3;
|
|
80
|
+
return [
|
|
81
|
+
4.0767416621 * a - 3.3077115913 * o + .2309699292 * s,
|
|
82
|
+
-1.2684380046 * a + 2.6097574011 * o - .3413193965 * s,
|
|
83
|
+
-.0041960863 * a - .7034186147 * o + 1.707614701 * s
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
function f(e) {
|
|
87
|
+
let [, t, n] = u(e);
|
|
88
|
+
return [Math.hypot(t, n), Math.atan2(n, t)];
|
|
89
|
+
}
|
|
90
|
+
function p(e) {
|
|
91
|
+
return e.every((e) => e >= -1e-9 && e <= 1 + 1e-9);
|
|
92
|
+
}
|
|
93
|
+
function m(e, t, n) {
|
|
94
|
+
if (p(d(e, t, n))) return t;
|
|
95
|
+
let r = 0, i = t;
|
|
96
|
+
for (let t = 0; t < 32; t++) {
|
|
97
|
+
let t = (r + i) / 2;
|
|
98
|
+
p(d(e, t, n)) ? r = t : i = t;
|
|
99
|
+
}
|
|
100
|
+
return r;
|
|
101
|
+
}
|
|
102
|
+
function h(e, t, n) {
|
|
103
|
+
let r = (e) => d(e, m(e, t, n), n).map((e) => Math.min(1, Math.max(0, e))), i = 0, a = 1;
|
|
104
|
+
for (let t = 0; t < 40; t++) {
|
|
105
|
+
let t = (i + a) / 2;
|
|
106
|
+
l(r(t)) < e ? i = t : a = t;
|
|
107
|
+
}
|
|
108
|
+
return r((i + a) / 2);
|
|
109
|
+
}
|
|
110
|
+
function g(e, t, n, r) {
|
|
111
|
+
let i = e.map((e) => Math.round(c(e))), a = [
|
|
112
|
+
0,
|
|
113
|
+
-1,
|
|
114
|
+
1
|
|
115
|
+
], o = i, u = Infinity;
|
|
116
|
+
for (let e of a) for (let c of n ? [e] : a) for (let d of n ? [e] : a) {
|
|
117
|
+
let n = i.map((t, n) => Math.min(255, Math.max(0, t + [
|
|
118
|
+
e,
|
|
119
|
+
c,
|
|
120
|
+
d
|
|
121
|
+
][n]))), a = l(n.map(s)), f = Math.abs(a - t) + +(r ? a > t : a < t);
|
|
122
|
+
f < u && (o = n, u = f);
|
|
123
|
+
}
|
|
124
|
+
return `#${o.map((e) => e.toString(16).padStart(2, "0")).join("")}`;
|
|
125
|
+
}
|
|
126
|
+
var _ = "#ffffff", v = "#000000", y = "#ebebeb", b = "#107c10", x = "#383838", S = {
|
|
127
|
+
light: [
|
|
128
|
+
[
|
|
129
|
+
"primary",
|
|
130
|
+
80,
|
|
131
|
+
"subtle-selected",
|
|
132
|
+
y,
|
|
133
|
+
4.5
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
"primary",
|
|
137
|
+
80,
|
|
138
|
+
"selected",
|
|
139
|
+
160,
|
|
140
|
+
4.5
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
"primary-hover",
|
|
144
|
+
70,
|
|
145
|
+
"primary-foreground",
|
|
146
|
+
_,
|
|
147
|
+
4.5
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
"primary-pressed",
|
|
151
|
+
40,
|
|
152
|
+
"primary-foreground",
|
|
153
|
+
_,
|
|
154
|
+
4.5
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
"selected",
|
|
158
|
+
160,
|
|
159
|
+
"success",
|
|
160
|
+
b,
|
|
161
|
+
4.5
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"selected-foreground",
|
|
165
|
+
60,
|
|
166
|
+
"selected",
|
|
167
|
+
160,
|
|
168
|
+
4.5
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
"selected-foreground",
|
|
172
|
+
60,
|
|
173
|
+
"selected-hover",
|
|
174
|
+
150,
|
|
175
|
+
4.5
|
|
176
|
+
],
|
|
177
|
+
[
|
|
178
|
+
"selected-foreground",
|
|
179
|
+
60,
|
|
180
|
+
"selected-pressed",
|
|
181
|
+
140,
|
|
182
|
+
4.5
|
|
183
|
+
],
|
|
184
|
+
[
|
|
185
|
+
"selected-hover",
|
|
186
|
+
150,
|
|
187
|
+
"selected",
|
|
188
|
+
160,
|
|
189
|
+
1.15
|
|
190
|
+
],
|
|
191
|
+
[
|
|
192
|
+
"selected-pressed",
|
|
193
|
+
140,
|
|
194
|
+
"selected-hover",
|
|
195
|
+
150,
|
|
196
|
+
1.15
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
"ring",
|
|
200
|
+
80,
|
|
201
|
+
"subtle-selected",
|
|
202
|
+
y,
|
|
203
|
+
3
|
|
204
|
+
]
|
|
205
|
+
],
|
|
206
|
+
dark: [
|
|
207
|
+
[
|
|
208
|
+
"primary",
|
|
209
|
+
110,
|
|
210
|
+
"subtle-selected",
|
|
211
|
+
x,
|
|
212
|
+
4.5
|
|
213
|
+
],
|
|
214
|
+
[
|
|
215
|
+
"primary-hover",
|
|
216
|
+
120,
|
|
217
|
+
"primary-foreground",
|
|
218
|
+
v,
|
|
219
|
+
4.5
|
|
220
|
+
],
|
|
221
|
+
[
|
|
222
|
+
"primary-pressed",
|
|
223
|
+
90,
|
|
224
|
+
"primary-foreground",
|
|
225
|
+
v,
|
|
226
|
+
4.5
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
"selected",
|
|
230
|
+
20,
|
|
231
|
+
"success",
|
|
232
|
+
"#5db55d",
|
|
233
|
+
4.5
|
|
234
|
+
],
|
|
235
|
+
[
|
|
236
|
+
"selected-foreground",
|
|
237
|
+
110,
|
|
238
|
+
"selected",
|
|
239
|
+
20,
|
|
240
|
+
4.5
|
|
241
|
+
],
|
|
242
|
+
[
|
|
243
|
+
"selected-foreground",
|
|
244
|
+
110,
|
|
245
|
+
"selected-hover",
|
|
246
|
+
40,
|
|
247
|
+
4.5
|
|
248
|
+
],
|
|
249
|
+
[
|
|
250
|
+
"selected-foreground",
|
|
251
|
+
110,
|
|
252
|
+
"selected-pressed",
|
|
253
|
+
10,
|
|
254
|
+
4.5
|
|
255
|
+
],
|
|
256
|
+
[
|
|
257
|
+
"selected-hover",
|
|
258
|
+
40,
|
|
259
|
+
"selected",
|
|
260
|
+
20,
|
|
261
|
+
1.15
|
|
262
|
+
],
|
|
263
|
+
[
|
|
264
|
+
"selected-pressed",
|
|
265
|
+
10,
|
|
266
|
+
"selected-hover",
|
|
267
|
+
40,
|
|
268
|
+
1.15
|
|
269
|
+
],
|
|
270
|
+
[
|
|
271
|
+
"ring",
|
|
272
|
+
100,
|
|
273
|
+
"subtle-selected",
|
|
274
|
+
x,
|
|
275
|
+
3
|
|
276
|
+
],
|
|
277
|
+
[
|
|
278
|
+
"ring",
|
|
279
|
+
100,
|
|
280
|
+
"selected",
|
|
281
|
+
20,
|
|
282
|
+
3
|
|
283
|
+
]
|
|
284
|
+
]
|
|
285
|
+
};
|
|
286
|
+
function C(e) {
|
|
287
|
+
let t = o(e);
|
|
288
|
+
return t && l(t.map(s));
|
|
289
|
+
}
|
|
290
|
+
function w(t) {
|
|
291
|
+
for (let [n, r] of Object.entries(S)) for (let [i, a, o, s, c] of r) {
|
|
292
|
+
let r = C(t[a]), l = C(typeof s == "number" ? t[s] : s);
|
|
293
|
+
if (r === void 0 || l === void 0) continue;
|
|
294
|
+
let u = (Math.max(r, l) + .05) / (Math.min(r, l) + .05);
|
|
295
|
+
u >= c || e(`createBrandTokens:contrast:${n}:${i}:${o}`, `createBrandTokens: in the ${n} theme, \`${i}\` on \`${o}\` (stop ${a} on ${typeof s == "number" ? `stop ${s}` : s}) is ${Math.floor(u * 100) / 100}:1; needs ${c}:1.`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
var T;
|
|
299
|
+
function E() {
|
|
300
|
+
if (T) return T;
|
|
301
|
+
let e = t.map((e) => o(r[e]).map(s)), [i, a] = f(e[n]);
|
|
302
|
+
T = {
|
|
303
|
+
luminance: [],
|
|
304
|
+
chroma: [],
|
|
305
|
+
hue: []
|
|
306
|
+
};
|
|
307
|
+
for (let t of e) {
|
|
308
|
+
let [e, n] = f(t);
|
|
309
|
+
T.luminance.push(l(t)), T.chroma.push(e / i), T.hue.push(n - a);
|
|
310
|
+
}
|
|
311
|
+
return T;
|
|
312
|
+
}
|
|
313
|
+
function D(e) {
|
|
314
|
+
let n = {};
|
|
315
|
+
return t.forEach((t, r) => {
|
|
316
|
+
n[`brand${t}`] = e(t, r);
|
|
317
|
+
}), n;
|
|
318
|
+
}
|
|
319
|
+
function O([e, t, n]) {
|
|
320
|
+
let [r, o] = f([
|
|
321
|
+
s(e),
|
|
322
|
+
s(t),
|
|
323
|
+
s(n)
|
|
324
|
+
]), c = E(), l = r < i;
|
|
325
|
+
return D((e, t) => {
|
|
326
|
+
let n = c.luminance[t];
|
|
327
|
+
return g(l ? [
|
|
328
|
+
n,
|
|
329
|
+
n,
|
|
330
|
+
n
|
|
331
|
+
] : h(n, r * c.chroma[t], o + c.hue[t]), n, l, a.includes(e));
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function k(t) {
|
|
335
|
+
let n = [], i = {}, a = D((e) => {
|
|
336
|
+
let a = t[e];
|
|
337
|
+
return typeof a == "string" && o(a) ? i[e] = a : (n.push(e), i[e] = r[e]);
|
|
338
|
+
});
|
|
339
|
+
if (n.length > 0) {
|
|
340
|
+
let t = n.length > 1;
|
|
341
|
+
e("createBrandTokens:ramp", `createBrandTokens: the ramp has no #rgb or #rrggbb colour at the stop${t ? "s" : ""} ${n.join(", ")}, so the default ramp's colour${t ? "s are" : " is"} used there.`);
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
process.env.NODE_ENV !== "production" && w(i);
|
|
345
|
+
} catch {}
|
|
346
|
+
return a;
|
|
347
|
+
}
|
|
348
|
+
function A(t) {
|
|
349
|
+
if (typeof t == "object" && t) return k(t);
|
|
350
|
+
let n = o(t);
|
|
351
|
+
if (n) return O(n);
|
|
352
|
+
let i = typeof t == "string" ? `"${t.length > 32 ? `${t.slice(0, 32)}…` : t}"` : t == null ? String(t) : `a ${typeof t}`;
|
|
353
|
+
return e("createBrandTokens:seed", `createBrandTokens: the seed ${i} is not a #rgb or #rrggbb colour, so the default brand ramp is used.`), D((e) => r[e]);
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
export { S as BRAND_CONTRAST_PAIRS, r as DEFAULT_BRAND_RAMP, a as ROUNDS_DARKER, w as checkBrandRamp, A as createBrandTokens };
|
|
357
|
+
|
|
358
|
+
//# sourceMappingURL=brand.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.mjs","names":["BRAND_STOPS","SEED_INDEX","DEFAULT_BRAND_RAMP","GREY_CHROMA","ROUNDS_DARKER","parseHex","value","match","digits","offset","toLinear","channel","toEncoded","linear","luminance","r","g","b","toOklab","l","m","s","fromOklch","a","chroma","hue","lightness","chromaAndHue","rgb","inGamut","fitChroma","low","high","step","middle","colourAtLuminance","colourAt","target","toHex","rounded","offsets","best","bestRank","red","green","grey","blue","candidate","index","rank","darker","WHITE","BLACK","LIGHT_SUBTLE_SELECTED","LIGHT_SUCCESS","DARK_SUBTLE_SELECTED","BRAND_CONTRAST_PAIRS","luminanceOf","checkBrandRamp","theme","pairs","token","stop","against","colour","minimum","own","ramp","other","ratio","warnOnce","defaultShape","getDefaultShape","colours","seedChroma","seedHue","toTokens","tokens","colourOf","rampFromSeed","shape","rampFromStops","invalid","used","several","createBrandTokens","seed","shown"],"sources":["../../src/lib/brand.ts"],"sourcesContent":["/**\n * Brand ramps: `createBrandTokens` builds the 16 brand tokens from a seed colour, or takes a full\n * ramp, which it checks against the pairs the themes read from it in development. Server-safe and\n * pure: no DOM and no React; its only run-time import is the development warnings. The colour\n * maths (sRGB, linear light, OKLab and OKLCH) is small and local to it.\n */\nimport { warnOnce } from './dev';\n\n/**\n * A stop of the brand ramp, from 10 (the darkest) to 160 (the lightest) in steps of 10: the stops\n * of Fluent's `BrandVariants` and of the `--wave-brand-N` tokens.\n */\nexport type BrandStop =\n 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 | 110 | 120 | 130 | 140 | 150 | 160;\n\n/**\n * A full brand ramp: a hex colour (`#rgb` or `#rrggbb`) for each of the 16 stops, darkest first.\n * The shape of Fluent's `BrandVariants`, which `createLightTheme(brand)` and\n * `createDarkTheme(brand)` take. The themes read the light primary from stop 80 (hover 70, pressed\n * 40, focus ring 80), the light selection from stops 160, 150 and 140 with its text at 60, the\n * dark primary from stop 110 (hover 120, pressed 90, focus ring 100) and the dark selection from\n * stops 20, 40 and 10 with its text at 110. A ramp whose stops have the luminance of the default\n * ramp's keeps the contrast of the light and dark themes; the high-contrast theme reads no stop.\n */\nexport type BrandRamp = Readonly<Record<BrandStop, string>>;\n\n/**\n * The 16 brand tokens, `brand10` to `brand160`: the overrides of `--wave-brand-10` to\n * `--wave-brand-160`, in the shape `WaveProvider tokens` and `getTokenStyle` take. Where Fluent's\n * `createLightTheme(brand)` builds a whole theme from a `BrandVariants` ramp, Wave applies the\n * ramp as these tokens over its named themes; the high-contrast theme reads none of them.\n */\nexport type BrandTokens = { [K in `brand${BrandStop}`]: string };\n\nconst BRAND_STOPS: readonly BrandStop[] = [\n 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160,\n];\n\n/** The index of stop 80 in `BRAND_STOPS`: the stop a seed's chroma and hue describe. */\nconst SEED_INDEX = 7;\n\n/**\n * The default brand ramp: the fallbacks of the `--wave-brand-N` declarations of `tokens.css`\n * (Fluent's brand ramp), which a test keeps equal.\n */\nexport const DEFAULT_BRAND_RAMP: BrandRamp = /* @__PURE__ */ Object.freeze({\n 10: '#061724',\n 20: '#082338',\n 30: '#0a2e4a',\n 40: '#0c3b5e',\n 50: '#0e4775',\n 60: '#0f548c',\n 70: '#115ea3',\n 80: '#0f6cbd',\n 90: '#2886de',\n 100: '#479ef5',\n 110: '#62abf5',\n 120: '#77b7f7',\n 130: '#96c6fa',\n 140: '#b4d6fa',\n 150: '#cfe4fa',\n 160: '#ebf3fc',\n});\n\n/** Under this OKLCH chroma a seed has no visible hue, and its ramp is grey. */\nconst GREY_CHROMA = 0.005;\n\n/**\n * The stops a generated ramp rounds darker, because the themes pair them with lighter colours:\n * 10 to 80 are fills under light text, text and focus rings on light surfaces, and the dark\n * theme's selection fills under light text; 140, the light theme's pressed selection fill, must\n * stay a visible step below the hover fill at 150. The other stops round lighter: the dark\n * theme's fills under dark text, its text and focus ring on dark surfaces, and the light theme's\n * selection fills under dark text (30, 50 and 130 are read by no theme; their side is arbitrary).\n * Three stops have pairs on both sides and take the side of the thinner one: 40 rounds darker for\n * the dark selected text on it (4.81:1) against its steps above the dark selection fills at 20 and\n * 10 (1.38 and 1.56); 150 rounds lighter for its step above 140 (1.157) against its step below\n * 160 (1.163); 140 rounds darker for that step against the light selected text at 60 on it\n * (5.23:1). So the pairs whose two stops round the same way (150 and 160, 40 and 20, 10 and 40,\n * 60 and 140) can lose up to one rounding step of contrast, and each has more margin over its\n * floor (1.15 between the states of a fill, 4.5 for text) than that. A test derives the sides\n * from the pairs of tokens.css and keeps this list equal to them.\n */\nexport const ROUNDS_DARKER: readonly BrandStop[] = [10, 20, 30, 40, 50, 60, 70, 80, 140];\n\n// ---------------------------------------------------------------------------------------------\n// Colour maths\n// ---------------------------------------------------------------------------------------------\n\ntype Triple = [number, number, number];\n\n/** `#rgb` or `#rrggbb` (any case) as 8-bit channels; `undefined` for anything else. */\nfunction parseHex(value: unknown): Triple | undefined {\n if (typeof value !== 'string') return undefined;\n const match = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value);\n if (!match) return undefined;\n const digits = match[1].length === 3 ? match[1].replace(/./g, '$&$&') : match[1];\n return [0, 2, 4].map((offset) => parseInt(digits.slice(offset, offset + 2), 16)) as Triple;\n}\n\n/** An 8-bit sRGB channel in linear light (0 to 1). */\nfunction toLinear(channel: number): number {\n const value = channel / 255;\n return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n}\n\n/** A linear channel as an unrounded 8-bit sRGB value. */\nfunction toEncoded(linear: number): number {\n const value = Math.min(1, Math.max(0, linear));\n return 255 * (value <= 0.0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - 0.055);\n}\n\n/** The WCAG relative luminance of a linear colour. */\nfunction luminance([r, g, b]: Triple): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** A linear sRGB colour in OKLab (lightness, a, b). */\nfunction toOklab([r, g, b]: Triple): Triple {\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return [\n 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n ];\n}\n\n/** An OKLCH colour (hue in radians) in linear sRGB, which may lie outside the gamut. */\nfunction fromOklch(lightness: number, chroma: number, hue: number): Triple {\n const a = chroma * Math.cos(hue);\n const b = chroma * Math.sin(hue);\n const l = (lightness + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (lightness - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (lightness - 0.0894841775 * a - 1.291485548 * b) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\n/** A linear sRGB colour as OKLCH chroma and hue (radians). */\nfunction chromaAndHue(rgb: Triple): [chroma: number, hue: number] {\n const [, a, b] = toOklab(rgb);\n return [Math.hypot(a, b), Math.atan2(b, a)];\n}\n\nfunction inGamut(rgb: Triple): boolean {\n return rgb.every((channel) => channel >= -1e-9 && channel <= 1 + 1e-9);\n}\n\n/** `chroma` at this lightness and hue, reduced by bisection until the colour fits sRGB. */\nfunction fitChroma(lightness: number, chroma: number, hue: number): number {\n if (inGamut(fromOklch(lightness, chroma, hue))) return chroma;\n let low = 0;\n let high = chroma;\n for (let step = 0; step < 32; step++) {\n const middle = (low + high) / 2;\n if (inGamut(fromOklch(lightness, middle, hue))) low = middle;\n else high = middle;\n }\n return low;\n}\n\n/** The colour of this hue and (at most) this chroma whose luminance is `target`, by bisection. */\nfunction colourAtLuminance(target: number, chroma: number, hue: number): Triple {\n const colourAt = (lightness: number): Triple =>\n fromOklch(lightness, fitChroma(lightness, chroma, hue), hue).map((channel) =>\n Math.min(1, Math.max(0, channel)),\n ) as Triple;\n let low = 0;\n let high = 1;\n for (let step = 0; step < 40; step++) {\n const middle = (low + high) / 2;\n if (luminance(colourAt(middle)) < target) low = middle;\n else high = middle;\n }\n return colourAt((low + high) / 2);\n}\n\n/**\n * A linear colour as `#rrggbb`, rounded on the safe side: of the 8-bit colours at most one step\n * from it on each channel, the one nearest `target` in luminance that is no lighter (`darker`) or\n * no darker than it. So rounding never takes contrast from a stop against a colour that does not\n * round the same way (a colour of the theme, or a stop that rounds the other way); two stops that\n * round the same way lose at most one rounding step between them. A grey stays a grey.\n */\nfunction toHex(rgb: Triple, target: number, grey: boolean, darker: boolean): string {\n const rounded = rgb.map((channel) => Math.round(toEncoded(channel)));\n const offsets = [0, -1, 1];\n let best = rounded;\n let bestRank = Infinity;\n for (const red of offsets) {\n for (const green of grey ? [red] : offsets) {\n for (const blue of grey ? [red] : offsets) {\n const candidate = rounded.map((channel, index) =>\n Math.min(255, Math.max(0, channel + [red, green, blue][index])),\n );\n const value = luminance(candidate.map(toLinear) as Triple);\n // A colour past the target on the unsafe side ranks after every other (one step below\n // the rounded colour is always on the dark side, one above on the light side).\n const rank =\n Math.abs(value - target) + ((darker ? value > target : value < target) ? 1 : 0);\n if (rank < bestRank) {\n best = candidate;\n bestRank = rank;\n }\n }\n }\n }\n return `#${best.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Checking a full ramp\n// ---------------------------------------------------------------------------------------------\n\n// Colours of the light and dark themes that a checked pair reads a stop against: the values of\n// their tokens in tokens.css, which a test keeps equal.\nconst WHITE = '#ffffff';\nconst BLACK = '#000000';\nconst LIGHT_SUBTLE_SELECTED = '#ebebeb';\nconst LIGHT_SUCCESS = '#107c10';\nconst DARK_SUBTLE_SELECTED = '#383838';\nconst DARK_SUCCESS = '#5db55d';\n\n/**\n * A pair the check measures: the token that reads a stop, the stop, the token it is read against,\n * that token's colour (a colour of the theme, or the stop it reads) and the least contrast the\n * pair needs (4.5 for text, 3 for a focus ring, 1.15 between the states of a fill).\n */\ntype BrandContrastPair = readonly [\n token: string,\n stop: BrandStop,\n against: string,\n colour: string | BrandStop,\n minimum: number,\n];\n\n/**\n * Where the light and dark themes read the ramp: every `var(--wave-brand-N)` of their groups in\n * tokens.css, as the pairs the check of a full ramp measures. Of the pairs of the contrast matrix\n * that read a stop, it keeps the one theme colour that bounds each token's stop (the closest in\n * luminance at its minimum: the darkest light surface under the light primary text, the lightest\n * dark surface under the dark primary text, the lightest text on the light selection fill, the\n * darkest text on the dark one, the on-brand text of the fill states), and every pair of two stops\n * those bounds do not already decide. Tests keep it in step with tokens.css and prove that a ramp\n * that passes these pairs passes every pair of the matrix that reads a stop. High contrast reads\n * no stop.\n */\nexport const BRAND_CONTRAST_PAIRS: Readonly<\n Record<'light' | 'dark', readonly BrandContrastPair[]>\n> = {\n light: [\n ['primary', 80, 'subtle-selected', LIGHT_SUBTLE_SELECTED, 4.5],\n ['primary', 80, 'selected', 160, 4.5],\n ['primary-hover', 70, 'primary-foreground', WHITE, 4.5],\n ['primary-pressed', 40, 'primary-foreground', WHITE, 4.5],\n ['selected', 160, 'success', LIGHT_SUCCESS, 4.5],\n ['selected-foreground', 60, 'selected', 160, 4.5],\n ['selected-foreground', 60, 'selected-hover', 150, 4.5],\n ['selected-foreground', 60, 'selected-pressed', 140, 4.5],\n ['selected-hover', 150, 'selected', 160, 1.15],\n ['selected-pressed', 140, 'selected-hover', 150, 1.15],\n ['ring', 80, 'subtle-selected', LIGHT_SUBTLE_SELECTED, 3],\n ],\n dark: [\n ['primary', 110, 'subtle-selected', DARK_SUBTLE_SELECTED, 4.5],\n ['primary-hover', 120, 'primary-foreground', BLACK, 4.5],\n ['primary-pressed', 90, 'primary-foreground', BLACK, 4.5],\n ['selected', 20, 'success', DARK_SUCCESS, 4.5],\n ['selected-foreground', 110, 'selected', 20, 4.5],\n ['selected-foreground', 110, 'selected-hover', 40, 4.5],\n ['selected-foreground', 110, 'selected-pressed', 10, 4.5],\n ['selected-hover', 40, 'selected', 20, 1.15],\n ['selected-pressed', 10, 'selected-hover', 40, 1.15],\n ['ring', 100, 'subtle-selected', DARK_SUBTLE_SELECTED, 3],\n ['ring', 100, 'selected', 20, 3],\n ],\n};\n\n/** The WCAG relative luminance of a `#rgb` or `#rrggbb` colour; `undefined` for anything else. */\nfunction luminanceOf(value: unknown): number | undefined {\n const rgb = parseHex(value);\n return rgb && luminance(rgb.map(toLinear) as Triple);\n}\n\n/**\n * The development check of a full ramp (R8): warns once per pair of `BRAND_CONTRAST_PAIRS` whose\n * contrast is below its minimum, naming the theme, the tokens, the stops and the ratio (rounded\n * down, so a failing ratio never reads as its minimum). Advisory: it never throws, never changes\n * the ramp, and skips a stop that is not a hex colour.\n */\nexport function checkBrandRamp(ramp: BrandRamp): void {\n for (const [theme, pairs] of Object.entries(BRAND_CONTRAST_PAIRS)) {\n for (const [token, stop, against, colour, minimum] of pairs) {\n const own = luminanceOf(ramp[stop]);\n const other = luminanceOf(typeof colour === 'number' ? ramp[colour] : colour);\n if (own === undefined || other === undefined) continue;\n const ratio = (Math.max(own, other) + 0.05) / (Math.min(own, other) + 0.05);\n if (ratio >= minimum) continue;\n warnOnce(\n `createBrandTokens:contrast:${theme}:${token}:${against}`,\n `createBrandTokens: in the ${theme} theme, \\`${token}\\` on \\`${against}\\` (stop ${stop} on ` +\n `${typeof colour === 'number' ? `stop ${colour}` : colour}) is ` +\n `${Math.floor(ratio * 100) / 100}:1; needs ${minimum}:1.`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------\n// Ramps\n// ---------------------------------------------------------------------------------------------\n\n/**\n * The shape of the default ramp, per stop: its luminance, its chroma as a share of stop 80's, and\n * its hue's offset from stop 80's (radians). Computed on first use.\n */\nlet defaultShape: { luminance: number[]; chroma: number[]; hue: number[] } | undefined;\n\nfunction getDefaultShape(): NonNullable<typeof defaultShape> {\n if (defaultShape) return defaultShape;\n const colours = BRAND_STOPS.map(\n (stop) => (parseHex(DEFAULT_BRAND_RAMP[stop]) as Triple).map(toLinear) as Triple,\n );\n const [seedChroma, seedHue] = chromaAndHue(colours[SEED_INDEX]);\n defaultShape = { luminance: [], chroma: [], hue: [] };\n for (const colour of colours) {\n const [chroma, hue] = chromaAndHue(colour);\n defaultShape.luminance.push(luminance(colour));\n defaultShape.chroma.push(chroma / seedChroma);\n defaultShape.hue.push(hue - seedHue);\n }\n return defaultShape;\n}\n\nfunction toTokens(colourOf: (stop: BrandStop, index: number) => string): BrandTokens {\n const tokens: Partial<BrandTokens> = {};\n BRAND_STOPS.forEach((stop, index) => {\n tokens[`brand${stop}`] = colourOf(stop, index);\n });\n return tokens as BrandTokens;\n}\n\nfunction rampFromSeed([red, green, blue]: Triple): BrandTokens {\n const [chroma, hue] = chromaAndHue([toLinear(red), toLinear(green), toLinear(blue)]);\n const shape = getDefaultShape();\n const grey = chroma < GREY_CHROMA;\n return toTokens((stop, index) => {\n const target = shape.luminance[index];\n const colour: Triple = grey\n ? [target, target, target]\n : colourAtLuminance(target, chroma * shape.chroma[index], hue + shape.hue[index]);\n return toHex(colour, target, grey, ROUNDS_DARKER.includes(stop));\n });\n}\n\nfunction rampFromStops(ramp: BrandRamp): BrandTokens {\n const invalid: BrandStop[] = [];\n // The colours the tokens take, checked below: the ramp's, or the default's where it has none.\n const used = {} as Record<BrandStop, string>;\n const tokens = toTokens((stop) => {\n const value: unknown = ramp[stop];\n if (typeof value === 'string' && parseHex(value)) return (used[stop] = value);\n invalid.push(stop);\n return (used[stop] = DEFAULT_BRAND_RAMP[stop]);\n });\n if (invalid.length > 0) {\n const several = invalid.length > 1;\n warnOnce(\n 'createBrandTokens:ramp',\n `createBrandTokens: the ramp has no #rgb or #rrggbb colour at the stop${several ? 's' : ''} ` +\n `${invalid.join(', ')}, so the default ramp's colour${several ? 's are' : ' is'} used there.`,\n );\n }\n // The mode is read here as `lib/dev` reads it, written out so a bundler replaces it: a\n // production bundle then drops the check and its table. Without a bundler and without\n // `process` (an unbundled import in a browser), the read throws and the check is skipped.\n try {\n if (process.env.NODE_ENV !== 'production') checkBrandRamp(used);\n } catch {\n // No `process`: see above.\n }\n return tokens;\n}\n\n/**\n * The brand tokens of a brand colour or of a full ramp, to pass as `WaveProvider tokens` (alone or\n * spread with other overrides) or to `getTokenStyle`. Wave's counterpart of Fluent's\n * `createLightTheme(brand)` and `createDarkTheme(brand)`, which take a full `BrandVariants` ramp;\n * Wave also builds the ramp from one colour. The high-contrast theme ignores the brand: its colours\n * are fixed.\n *\n * From a seed (`#rgb` or `#rrggbb`, any case, with the `#`), each stop keeps the **luminance of the\n * default ramp's stop** and takes its hue and colourfulness from the seed: the seed's OKLCH chroma\n * and hue, shaped per stop like the default ramp (less colourful toward both ends, the hue\n * drifting a few degrees as the default's does), reduced where the colour would leave sRGB, and\n * rounded to a neighbouring 8-bit colour on the side that keeps its contrast. Contrast depends\n * only on luminance, so every text, fill, stroke and focus-ring pair of the light and dark themes\n * keeps, to within 8-bit rounding, the contrast it has with the default ramp, and stays above the\n * floor the themes are held to (4.5:1 for text, 3:1 for strokes, graphics and focus rings, 1.15:1\n * between the states of a fill), whatever the seed. The cost: the seed sets hue and\n * colourfulness, not lightness, so the primary fill (stop 80) is the seed's hue at the default's\n * lightness, and a light seed gives a darker button than itself. For a brand whose exact colours\n * matter, pass a full `BrandRamp`. The default seed `#0f6cbd` gives the default ramp, and a grey\n * seed (black, white or any grey) a grey ramp.\n *\n * A full `BrandRamp` is returned as tokens with its colours unchanged; a stop that is missing or\n * not a hex colour takes the default ramp's colour, with a development warning. In development the\n * ramp is also checked against the pairs the light and dark themes read from it (the primary\n * colour as text and as a fill under its text, the hover and pressed fills, the selection fills\n * and their text, the focus ring): each pair below its minimum (4.5:1 for text, 3:1 for the focus\n * ring, 1.15:1 between the states of a fill) logs one warning naming the theme, the tokens, the\n * stops and the ratio. The check is advisory: the ramp applies as given. Any other seed returns\n * the default ramp, with a development warning.\n *\n * Pure and server-safe; it returns a new object on each call, so compute it once (at module scope,\n * or memoised) rather than on every render.\n *\n * @example\n * const brand = createBrandTokens('#c43e00');\n * <WaveProvider tokens={brand}>…</WaveProvider>\n *\n * @example\n * <WaveProvider tokens={{ ...createBrandTokens('#c43e00'), fontFamily: 'Inter, sans-serif' }}>\n */\nexport function createBrandTokens(seed: string | BrandRamp): BrandTokens {\n if (typeof seed === 'object' && seed !== null) return rampFromStops(seed);\n const rgb = parseHex(seed);\n if (rgb) return rampFromSeed(rgb);\n // A long string is cut, so the console never holds a whole document passed by mistake.\n const shown =\n typeof seed === 'string'\n ? `\"${seed.length > 32 ? `${seed.slice(0, 32)}…` : seed}\"`\n : seed === null || seed === undefined\n ? String(seed)\n : `a ${typeof seed}`;\n warnOnce(\n 'createBrandTokens:seed',\n `createBrandTokens: the seed ${shown} is not a #rgb or #rrggbb colour, so the default brand ` +\n 'ramp is used.',\n );\n return toTokens((stop) => DEFAULT_BRAND_RAMP[stop]);\n}\n"],"mappings":"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"}
|
package/dist/lib/cn.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("clsx");var t=(0,require("tailwind-merge").extendTailwindMerge)({extend:{classGroups:{duration:[{duration:[`wave-ultra-fast`,`wave-faster`,`wave-fast`,`wave-normal`,`wave-gentle`,`wave-slow`,`wave-slower`,`wave-ultra-slow`]}]},theme:{ease:[`wave-accelerate-max`,`wave-accelerate-mid`,`wave-accelerate-min`,`wave-decelerate-max`,`wave-decelerate-mid`,`wave-decelerate-min`,`wave-easy-ease-max`,`wave-easy-ease`,`wave-linear`],text:[`caption-2`,`caption-1`,`body-1`,`body-2`,`subtitle-2`,`subtitle-1`,`title-3`,`title-2`,`title-1`,`large-title`,`display`],shadow:[`2`,`4`,`8`,`16`,`28`,`64`],font:[`wave`],animate:[`wave-spin`,`wave-spin-slow`,`wave-pulse`,`wave-indeterminate`,`wave-indeterminate-rtl`]}}});function n(...n){return t((0,e.clsx)(n))}exports.cn=n,exports.twMerge=t;
|
|
1
|
+
let e=require("clsx");var t=(0,require("tailwind-merge").extendTailwindMerge)({extend:{classGroups:{duration:[{duration:[`wave-ultra-fast`,`wave-faster`,`wave-fast`,`wave-normal`,`wave-gentle`,`wave-slow`,`wave-slower`,`wave-ultra-slow`]}]},theme:{ease:[`wave-accelerate-max`,`wave-accelerate-mid`,`wave-accelerate-min`,`wave-decelerate-max`,`wave-decelerate-mid`,`wave-decelerate-min`,`wave-easy-ease-max`,`wave-easy-ease`,`wave-linear`],text:[`caption-2`,`caption-1`,`body-1`,`body-2`,`subtitle-2`,`subtitle-1`,`title-3`,`title-2`,`title-1`,`large-title`,`display`],shadow:[`2`,`4`,`8`,`16`,`28`,`64`],font:[`wave`,`wave-mono`,`wave-numeric`],animate:[`wave-spin`,`wave-spin-slow`,`wave-pulse`,`wave-indeterminate`,`wave-indeterminate-rtl`]}}});function n(...n){return t((0,e.clsx)(n))}exports.cn=n,exports.twMerge=t;
|
|
2
2
|
//# sourceMappingURL=cn.cjs.map
|
package/dist/lib/cn.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cn.cjs","names":["extendTailwindMerge","clsx","twMerge","cn","inputs"],"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * tailwind-merge configured with the Wave theme scales, so custom utilities are grouped\n * correctly: `text-body-1` is a font size (not a text colour), `shadow-4` is a shadow size (not a\n * shadow colour), `font-wave`
|
|
1
|
+
{"version":3,"file":"cn.cjs","names":["extendTailwindMerge","clsx","twMerge","cn","inputs"],"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * tailwind-merge configured with the Wave theme scales, so custom utilities are grouped\n * correctly: `text-body-1` is a font size (not a text colour), `shadow-4` is a shadow size (not a\n * shadow colour), `font-wave` and its monospace and numeric siblings are font families (never a\n * weight or a size), `animate-wave-*` are animations, and the motion\n * tokens `duration-wave-*` and `ease-wave-*` are transition durations and timing functions.\n */\nexport const twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n duration: [\n {\n duration: [\n 'wave-ultra-fast',\n 'wave-faster',\n 'wave-fast',\n 'wave-normal',\n 'wave-gentle',\n 'wave-slow',\n 'wave-slower',\n 'wave-ultra-slow',\n ],\n },\n ],\n },\n theme: {\n ease: [\n 'wave-accelerate-max',\n 'wave-accelerate-mid',\n 'wave-accelerate-min',\n 'wave-decelerate-max',\n 'wave-decelerate-mid',\n 'wave-decelerate-min',\n 'wave-easy-ease-max',\n 'wave-easy-ease',\n 'wave-linear',\n ],\n text: [\n 'caption-2',\n 'caption-1',\n 'body-1',\n 'body-2',\n 'subtitle-2',\n 'subtitle-1',\n 'title-3',\n 'title-2',\n 'title-1',\n 'large-title',\n 'display',\n ],\n shadow: ['2', '4', '8', '16', '28', '64'],\n font: ['wave', 'wave-mono', 'wave-numeric'],\n animate: [\n 'wave-spin',\n 'wave-spin-slow',\n 'wave-pulse',\n 'wave-indeterminate',\n 'wave-indeterminate-rtl',\n ],\n },\n },\n});\n\n/**\n * Joins class names (clsx) and resolves Tailwind conflicts so the **last** class wins — pass\n * internal classes first and the consumer's `className` last.\n *\n * A later class replaces only a conflicting class **of the same variant**. Variant and state\n * classes such as the gated `not-disabled:not-aria-disabled:hover:bg-…` or `data-[selected]:bg-…`\n * are kept next to a bare `hover:bg-…`/`bg-…` and win by specificity; override them with the same\n * prefix (`not-disabled:not-aria-disabled:hover:bg-error`), the same data variant, or the important\n * modifier (`hover:bg-error!`).\n *\n * @example\n * cn('text-body-1 text-foreground', className) // className=\"text-primary\" keeps text-body-1\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":"sBAUA,IAAaE,GAAA,0BAAUF,CAAAA,CAAAA,oBAAAA,CAAoB,CACzC,OAAQ,CACN,YAAa,CACX,SAAU,CACR,CACE,SAAU,CACR,kBACA,cACA,YACA,cACA,cACA,YACA,cACA,iBACF,CACF,CACF,CACF,EACA,MAAO,CACL,KAAM,CACJ,sBACA,sBACA,sBACA,sBACA,sBACA,sBACA,qBACA,iBACA,aACF,EACA,KAAM,CACJ,YACA,YACA,SACA,SACA,aACA,aACA,UACA,UACA,UACA,cACA,SACF,EACA,OAAQ,CAAC,IAAK,IAAK,IAAK,KAAM,KAAM,IAAI,EACxC,KAAM,CAAC,OAAQ,YAAa,cAAc,EAC1C,QAAS,CACP,YACA,iBACA,aACA,qBACA,wBACF,CACF,CACF,CACF,CAAC,EAeD,SAAgBG,EAAG,GAAGC,EAA8B,CAClD,OAAOF,GAAA,EAAQD,EAAA,KAAA,CAAKG,CAAM,CAAC,CAC7B"}
|
package/dist/lib/cn.mjs
CHANGED
package/dist/lib/cn.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cn.mjs","names":["twMerge","extendTailwindMerge","cn","inputs","clsx"],"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * tailwind-merge configured with the Wave theme scales, so custom utilities are grouped\n * correctly: `text-body-1` is a font size (not a text colour), `shadow-4` is a shadow size (not a\n * shadow colour), `font-wave`
|
|
1
|
+
{"version":3,"file":"cn.mjs","names":["twMerge","extendTailwindMerge","cn","inputs","clsx"],"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * tailwind-merge configured with the Wave theme scales, so custom utilities are grouped\n * correctly: `text-body-1` is a font size (not a text colour), `shadow-4` is a shadow size (not a\n * shadow colour), `font-wave` and its monospace and numeric siblings are font families (never a\n * weight or a size), `animate-wave-*` are animations, and the motion\n * tokens `duration-wave-*` and `ease-wave-*` are transition durations and timing functions.\n */\nexport const twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n duration: [\n {\n duration: [\n 'wave-ultra-fast',\n 'wave-faster',\n 'wave-fast',\n 'wave-normal',\n 'wave-gentle',\n 'wave-slow',\n 'wave-slower',\n 'wave-ultra-slow',\n ],\n },\n ],\n },\n theme: {\n ease: [\n 'wave-accelerate-max',\n 'wave-accelerate-mid',\n 'wave-accelerate-min',\n 'wave-decelerate-max',\n 'wave-decelerate-mid',\n 'wave-decelerate-min',\n 'wave-easy-ease-max',\n 'wave-easy-ease',\n 'wave-linear',\n ],\n text: [\n 'caption-2',\n 'caption-1',\n 'body-1',\n 'body-2',\n 'subtitle-2',\n 'subtitle-1',\n 'title-3',\n 'title-2',\n 'title-1',\n 'large-title',\n 'display',\n ],\n shadow: ['2', '4', '8', '16', '28', '64'],\n font: ['wave', 'wave-mono', 'wave-numeric'],\n animate: [\n 'wave-spin',\n 'wave-spin-slow',\n 'wave-pulse',\n 'wave-indeterminate',\n 'wave-indeterminate-rtl',\n ],\n },\n },\n});\n\n/**\n * Joins class names (clsx) and resolves Tailwind conflicts so the **last** class wins — pass\n * internal classes first and the consumer's `className` last.\n *\n * A later class replaces only a conflicting class **of the same variant**. Variant and state\n * classes such as the gated `not-disabled:not-aria-disabled:hover:bg-…` or `data-[selected]:bg-…`\n * are kept next to a bare `hover:bg-…`/`bg-…` and win by specificity; override them with the same\n * prefix (`not-disabled:not-aria-disabled:hover:bg-error`), the same data variant, or the important\n * modifier (`hover:bg-error!`).\n *\n * @example\n * cn('text-body-1 text-foreground', className) // className=\"text-primary\" keeps text-body-1\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;AAUA,IAAaA,IAAUC,EAAoB,EACzC,QAAQ;CACN,aAAa,EACX,UAAU,CACR,EACE,UAAU;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,EACF,CACF,EACF;CACA,OAAO;EACL,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA,QAAQ;GAAC;GAAK;GAAK;GAAK;GAAM;GAAM;EAAI;EACxC,MAAM;GAAC;GAAQ;GAAa;EAAc;EAC1C,SAAS;GACP;GACA;GACA;GACA;GACA;EACF;CACF;AACF,EACF,CAAC;AAeD,SAAgBC,EAAG,GAAGC,GAA8B;CAClD,OAAOH,EAAQI,EAAKD,CAAM,CAAC;AAC7B"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const e=require("./dev.cjs");function t(e){return`--wave-${e.replace(/([A-Za-z])(\d)/g,`$1-$2`).replace(/[A-Z]/g,e=>`-${e}`).toLowerCase()}`}var n=/^[a-z][A-Za-z0-9]*$/,r=/[;{}]|url\(/i;function i(e){let t=[],n=``,r=0;for(;r<e.length;r++){let i=e[r];if(n){if(i===`\\`)r++;else if(i===n)n=``;else if(`
|
|
2
|
+
\r\f`.includes(i))return!1}else`"'`.includes(i)?n=i:i===`/`&&e[r+1]===`*`?r=e.indexOf(`*/`,r+2)+1||1/0:`([`.includes(i)?t.push(i===`(`?`)`:`]`):`)]!\\`.includes(i)&&t.pop()!==i&&(r=1/0)}return r===e.length&&!n&&!t.length}function a(e){let a=[];if(e==null)return{style:void 0,invalid:a};let o={},s=!0;for(let[c,l]of Object.entries(e))l!==void 0&&(n.test(c)?typeof l==`string`&&!r.test(l)&&i(l)||typeof l==`number`&&Number.isFinite(l)?(o[t(c)]=String(l).trim(),s=!1):a.push({key:c,reason:`value`}):a.push({key:c,reason:`name`}));return{style:s?void 0:o,invalid:a}}function o(t){let{style:n,invalid:r}=a(t);for(let{key:t,reason:n}of r)n===`name`?e.warnOnce(`tokens:name:${t}`,`getTokenStyle: \`${t}\` is not a token name, so it is skipped. Token names are the CSS variable in camelCase without its \`--wave-\` prefix (\`primaryForeground\` for \`--wave-primary-foreground\`).`):e.warnOnce(`tokens:value:${t}`,`getTokenStyle: the value of \`${t}\` is skipped: it must be a finite number, or CSS text with balanced quotes, brackets and comments, without \`;\`, \`{\`, \`}\` or \`url(\`, and without \`!\` or a backslash outside strings and comments.`);return n}function s(e,t){if(t===null)return{};if(t===void 0)return e;let n=Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0));return{...e,...n}}exports.collectTokenStyle=a,exports.getTokenStyle=o,exports.mergeTokenOverrides=s,exports.tokenVariable=t;
|
|
3
|
+
//# sourceMappingURL=tokens.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.cjs","names":["require_dev","tokenVariable","name","capital","TOKEN_NAME","REFUSED_TEXT","isBalancedCssText","closers","quote","index","text","char","collectTokenStyle","invalid","overrides","style","empty","key","value","getTokenStyle","reason","mergeTokenOverrides","own","parent","defined"],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design tokens in JavaScript: their names, the overrides `WaveProvider` takes and the inline\n * style that applies them. Server-safe and light enough for the provider: it imports only types\n * and the development warnings, never the list of token names (`waveTokens.ts`).\n */\nimport type * as React from 'react';\nimport { warnOnce } from './dev';\nimport type { WAVE_TOKEN_NAMES } from './waveTokens';\n\n/**\n * The name of a design token: its CSS custom property without the `--wave-` prefix, in camelCase.\n * `--wave-primary-foreground` is `primaryForeground`, `--wave-brand-80` is `brand80` and\n * `--wave-palette-red-tint` is `paletteRedTint`.\n */\nexport type WaveTokenName = (typeof WAVE_TOKEN_NAMES)[number];\n\n/** The shape of `waveTokens`: every token name mapped to the CSS value that reads the token. */\nexport type WaveTokens = { readonly [K in WaveTokenName]: string };\n\n/**\n * Token overrides: CSS values by token name, as `WaveProvider tokens` and `getTokenStyle` take\n * them. A number is written as its string (`zOverlay: 2000`); a key whose value is `undefined`\n * sets nothing.\n */\nexport type WaveTokenOverrides = { [K in WaveTokenName]?: string | number };\n\n/**\n * The inline style that applies token overrides: a React style object whose `--wave-*` custom\n * properties set the tokens, so it can be merged with other style properties.\n */\nexport type TokenStyle = React.CSSProperties & { [K in `--wave-${string}`]?: string };\n\n/**\n * The CSS custom property of a token name at the type level: `TokenVariable<'brand80'>` is\n * `'--wave-brand-80'`, by the rule of {@link tokenVariable}. It spells out the literal values of\n * `waveTokens`. It walks the name one character at a time (tail-recursive, so long names stay\n * within the compiler's depth limit): `AfterLetter` says whether the previous character was a\n * letter, `Done` holds the converted text so far.\n */\nexport type TokenVariable<\n Name extends string,\n AfterLetter extends boolean = false,\n Done extends string = '',\n> = Name extends `${infer Char}${infer Rest}`\n ? Char extends '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'\n ? TokenVariable<Rest, false, `${Done}${AfterLetter extends true ? '-' : ''}${Char}`>\n : Char extends Lowercase<Char>\n ? TokenVariable<Rest, true, `${Done}${Char}`>\n : TokenVariable<Rest, true, `${Done}-${Lowercase<Char>}`>\n : `--wave-${Done}`;\n\n/**\n * The CSS custom property of a token name: a hyphen before each capital letter and before a digit\n * run that follows a letter, lowercased, with the `--wave-` prefix. `'paletteRedTint'` gives\n * `'--wave-palette-red-tint'` and `'brand80'` gives `'--wave-brand-80'`. The name is not checked\n * against the list of tokens.\n */\nexport function tokenVariable(name: string): string {\n return `--wave-${name\n .replace(/([A-Za-z])(\\d)/g, '$1-$2')\n .replace(/[A-Z]/g, (capital) => `-${capital}`)\n .toLowerCase()}`;\n}\n\n/** A camelCase identifier: the only key shape a token name can have. */\nconst TOKEN_NAME = /^[a-z][A-Za-z0-9]*$/;\n\n/**\n * The text no token value may hold, anywhere in it. React writes a custom property's value into\n * the server-rendered `style` attribute as text, where a semicolon would end the declaration and\n * let the rest of the value declare a property of its own (and a brace could close the rule around\n * it); in the client the CSSOM refuses a value with a semicolon, so the two renders would also\n * differ. `url(`, in any case: no token takes a URL, and an unquoted one ends at its first `)`\n * whatever it holds, which the balance check below does not follow (`url(a\"b)c\")` would open a\n * string after that `)`); the check refuses the escapes that could spell it otherwise (`u\\72l(`).\n */\nconst REFUSED_TEXT = /[;{}]|url\\(/i;\n\n/**\n * Whether `text` closes everything it opens, read as the CSS tokenizer reads it: every string\n * closes on its own line (a backslash in it escapes the next character, a line break included),\n * every comment closes, and the parentheses and square brackets outside strings and comments pair\n * up and nest. In the server-rendered `style` attribute an open string, comment, parenthesis or\n * bracket would run on to the end of the attribute, so the declarations after it would be lost\n * there, while the client sets each property on its own. Refused as well, outside strings and\n * comments: a stray closer, which the client refuses in a custom property; a `!`, since the server\n * would read `!important` as the declaration's priority while the client refuses a `!` at the top\n * level (one nested in a function, as in `color-mix(in srgb, red !important, blue)`, is valid there, and refusing\n * it is deliberate: no token needs it); and a backslash, which no token needs there and which\n * could spell `url(` with an escape or, at the end, escape the semicolon after the value. One pass\n * over the text, each character read once and the stack an array, so the time grows with the\n * length alone and a long crafted value cannot stall a server render.\n */\nfunction isBalancedCssText(text: string): boolean {\n // The closers of the open parentheses and brackets, the innermost last.\n const closers: string[] = [];\n // The quote of the open string, '' outside one.\n let quote = '';\n let index = 0;\n for (; index < text.length; index++) {\n const char = text[index];\n if (quote) {\n // An escape takes the next character; a backslash at the end leaves the string open.\n if (char === '\\\\') index++;\n else if (char === quote) quote = '';\n else if ('\\n\\r\\f'.includes(char)) return false;\n } else if ('\"\\''.includes(char)) {\n quote = char;\n } else if (char === '/' && text[index + 1] === '*') {\n // A comment runs to its first `*/` and escapes nothing; one that never ends moves the index\n // past the end.\n index = text.indexOf('*/', index + 2) + 1 || Infinity;\n } else if ('(['.includes(char)) {\n closers.push(char === '(' ? ')' : ']');\n } else if (')]!\\\\'.includes(char) && closers.pop() !== char) {\n // A closer that is not the innermost one's, or a `!` or a backslash, which no opener\n // expects: the index moves past the end, which fails below.\n index = Infinity;\n }\n }\n return index === text.length && !quote && !closers.length;\n}\n\n/**\n * The custom properties of `overrides`, and the entries it skipped. Pure: it never warns, so the\n * provider can call it during render; {@link getTokenStyle} reports the skipped entries.\n *\n * `undefined` values are skipped first (they set nothing); a key that is not a camelCase\n * identifier is skipped with the reason `'name'`, and a value with the reason `'value'` unless it\n * is a finite number or a string without `;`, `{`, `}` or `url(` that closes every string,\n * comment, parenthesis and square bracket it opens and has no stray closer, `!` or backslash\n * outside strings and comments. Numbers are written as strings, and every value is trimmed with\n * JavaScript's `trim`, as React's server renderer trims a custom property's value (the client sets\n * the value as given), so both write the same text; a value that is empty after it is written as\n * `''`, for which React renders no declaration on either side. The style keeps the order of the\n * input. `style` is `undefined` when nothing is left.\n */\nexport function collectTokenStyle(overrides: WaveTokenOverrides | null | undefined): {\n style: TokenStyle | undefined;\n invalid: readonly { key: string; reason: 'name' | 'value' }[];\n} {\n const invalid: { key: string; reason: 'name' | 'value' }[] = [];\n if (overrides == null) return { style: undefined, invalid };\n const style: Record<string, string> = {};\n let empty = true;\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n if (value === undefined) continue;\n if (!TOKEN_NAME.test(key)) {\n invalid.push({ key, reason: 'name' });\n } else if (\n (typeof value === 'string' && !REFUSED_TEXT.test(value) && isBalancedCssText(value)) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n style[tokenVariable(key)] = String(value).trim();\n empty = false;\n } else {\n invalid.push({ key, reason: 'value' });\n }\n }\n return { style: empty ? undefined : (style as TokenStyle), invalid };\n}\n\n/**\n * The inline style that applies token overrides: one `--wave-*` custom property per entry, the\n * object `WaveProvider` puts on its root and its portals. Use it where no provider renders, such\n * as a Server Component's document element. Server-safe.\n *\n * Returns `undefined` for `null`, `undefined` or a map with nothing to set. An `undefined` value is\n * skipped, a number is written as its string, a string is trimmed as React's server renderer trims\n * it, and the properties keep the order of the input. A key that is not a camelCase identifier is\n * skipped with a development warning (once per key), and so is a value unless it is a finite\n * number or CSS text without `;`, `{`, `}` or `url(` whose quotes, parentheses, square brackets and\n * comments are balanced, with no `!` or backslash outside strings and comments. In a\n * server-rendered `style` attribute such a character could add a declaration of its own, an open\n * string, comment or bracket (or an escape that spells `url(` or takes the semicolon after the\n * value) would swallow the declarations after it, and `!important` would set a priority the client\n * refuses; the trimmed values that pass are read alike by the attribute and by the client. Names\n * are not checked against the list of tokens: TypeScript refuses a misspelled one, and in\n * JavaScript it sets a property nothing reads.\n *\n * @example\n * // app/layout.tsx (a Server Component)\n * <html style={getTokenStyle({ brand80: '#c43e00' })}>\n *\n * @example\n * <div style={{ ...getTokenStyle(overrides), padding: 16 }} />\n */\nexport function getTokenStyle(\n overrides: WaveTokenOverrides | null | undefined,\n): TokenStyle | undefined {\n const { style, invalid } = collectTokenStyle(overrides);\n for (const { key, reason } of invalid) {\n if (reason === 'name') {\n warnOnce(\n `tokens:name:${key}`,\n `getTokenStyle: \\`${key}\\` is not a token name, so it is skipped. Token names are the CSS ` +\n 'variable in camelCase without its `--wave-` prefix (`primaryForeground` for ' +\n '`--wave-primary-foreground`).',\n );\n } else {\n warnOnce(\n `tokens:value:${key}`,\n `getTokenStyle: the value of \\`${key}\\` is skipped: it must be a finite number, or CSS ` +\n 'text with balanced quotes, brackets and comments, without `;`, `{`, `}` or `url(`, and ' +\n 'without `!` or a backslash outside strings and comments.',\n );\n }\n }\n return style;\n}\n\n/**\n * The overrides of a nested provider: `own` merged key by key over `parent`. `undefined` inherits\n * `parent` as it is, `null` clears everything inherited, and a key whose own value is `undefined`\n * keeps the parent's value.\n */\nexport function mergeTokenOverrides(\n parent: WaveTokenOverrides,\n own: WaveTokenOverrides | null | undefined,\n): WaveTokenOverrides {\n if (own === null) return {};\n if (own === undefined) return parent;\n // Spread, never assignment, so a `__proto__` key is an own entry like any other.\n const defined = Object.fromEntries(\n Object.entries(own).filter(([, value]) => value !== undefined),\n );\n return { ...parent, ...defined };\n}\n"],"mappings":"6BAyDA,SAAgBC,EAAc,EAAsB,CAClD,MAAO,UAAUC,EACd,QAAQ,kBAAmB,OAAO,CAAC,CACnC,QAAQ,SAAW,GAAY,IAAIC,GAAS,CAAC,CAC7C,YAAY,GACjB,CAGA,IAAMC,EAAa,sBAWbC,EAAe,eAiBrB,SAASC,EAAkB,EAAuB,CAEhD,IAAMC,EAAoB,CAAC,EAEvBC,EAAQ,GACRC,EAAQ,EACZ,KAAOA,EAAQC,EAAK,OAAQ,IAAS,CACnC,IAAMC,EAAOD,EAAKD,GAClB,GAAID,EAAO,CAET,GAAIG,IAAS,KAAM,SACd,GAAIA,IAASH,EAAO,EAAQ,QAC5B,GAAI;MAAS,SAASG,CAAI,EAAG,MAAO,EAC3C,KAAW,KAAM,SAASA,CAAI,EAC5B,EAAQA,EACCA,IAAS,KAAOD,EAAKD,EAAQ,KAAO,IAG7C,EAAQC,EAAK,QAAQ,KAAMD,EAAQ,CAAC,EAAI,GAAK,IACpC,KAAK,SAASE,CAAI,EAC3BJ,EAAQ,KAAKI,IAAS,IAAM,IAAM,GAAG,EAC5B,QAAQ,SAASA,CAAI,GAAKJ,EAAQ,IAAI,IAAMI,IAGrD,EAAQ,IAEZ,CACA,OAAOF,IAAUC,EAAK,QAAU,CAACF,GAAS,CAACD,EAAQ,MACrD,CAgBA,SAAgBK,EAAkB,EAGhC,CACA,IAAMC,EAAuD,CAAC,EAC9D,GAAIC,GAAa,KAAM,MAAO,CAAE,MAAO,IAAA,GAAW,SAAQ,EAC1D,IAAMC,EAAgC,CAAC,EACnCC,EAAQ,GACZ,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQJ,CAAoC,EACxEI,IAAU,IAAA,KACTd,EAAW,KAAKa,CAAG,EAGrB,OAAOC,GAAU,UAAY,CAACb,EAAa,KAAKa,CAAK,GAAKZ,EAAkBY,CAAK,GACjF,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,GAEnD,EAAMjB,EAAcgB,CAAG,GAAK,OAAOC,CAAK,CAAC,CAAC,KAAK,EAC/C,EAAQ,IAERL,EAAQ,KAAK,CAAE,MAAK,OAAQ,OAAQ,CAAC,EARrCA,EAAQ,KAAK,CAAE,MAAK,OAAQ,MAAO,CAAC,GAWxC,MAAO,CAAE,MAAOG,EAAQ,IAAA,GAAaD,EAAsB,SAAQ,CACrE,CA2BA,SAAgBI,EACd,EACwB,CACxB,GAAM,CAAE,QAAO,WAAYP,EAAkBE,CAAS,EACtD,IAAK,GAAM,CAAE,MAAK,YAAYD,EACxBO,IAAW,OACbpB,EAAA,SACE,eAAeiB,IACf,oBAAoBA,EAAI,kLAG1B,EAEAjB,EAAA,SACE,gBAAgBiB,IAChB,iCAAiCA,EAAI,4MAGvC,EAGJ,OAAOF,CACT,CAOA,SAAgBM,EACd,EACA,EACoB,CACpB,GAAIC,IAAQ,KAAM,MAAO,CAAC,EAC1B,GAAIA,IAAQ,IAAA,GAAW,OAAOC,EAE9B,IAAMC,EAAU,OAAO,YACrB,OAAO,QAAQF,CAAG,CAAC,CAAC,QAAQ,EAAGJ,KAAWA,IAAU,IAAA,EAAS,CAC/D,EACA,MAAO,CAAE,GAAGK,EAAQ,GAAGC,CAAQ,CACjC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { warnOnce as e } from "./dev.mjs";
|
|
2
|
+
//#region src/lib/tokens.ts
|
|
3
|
+
function t(e) {
|
|
4
|
+
return `--wave-${e.replace(/([A-Za-z])(\d)/g, "$1-$2").replace(/[A-Z]/g, (e) => `-${e}`).toLowerCase()}`;
|
|
5
|
+
}
|
|
6
|
+
var n = /^[a-z][A-Za-z0-9]*$/, r = /[;{}]|url\(/i;
|
|
7
|
+
function i(e) {
|
|
8
|
+
let t = [], n = "", r = 0;
|
|
9
|
+
for (; r < e.length; r++) {
|
|
10
|
+
let i = e[r];
|
|
11
|
+
if (n) {
|
|
12
|
+
if (i === "\\") r++;
|
|
13
|
+
else if (i === n) n = "";
|
|
14
|
+
else if ("\n\r\f".includes(i)) return !1;
|
|
15
|
+
} else "\"'".includes(i) ? n = i : i === "/" && e[r + 1] === "*" ? r = e.indexOf("*/", r + 2) + 1 || Infinity : "([".includes(i) ? t.push(i === "(" ? ")" : "]") : ")]!\\".includes(i) && t.pop() !== i && (r = Infinity);
|
|
16
|
+
}
|
|
17
|
+
return r === e.length && !n && !t.length;
|
|
18
|
+
}
|
|
19
|
+
function a(e) {
|
|
20
|
+
let a = [];
|
|
21
|
+
if (e == null) return {
|
|
22
|
+
style: void 0,
|
|
23
|
+
invalid: a
|
|
24
|
+
};
|
|
25
|
+
let o = {}, s = !0;
|
|
26
|
+
for (let [c, l] of Object.entries(e)) l !== void 0 && (n.test(c) ? typeof l == "string" && !r.test(l) && i(l) || typeof l == "number" && Number.isFinite(l) ? (o[t(c)] = String(l).trim(), s = !1) : a.push({
|
|
27
|
+
key: c,
|
|
28
|
+
reason: "value"
|
|
29
|
+
}) : a.push({
|
|
30
|
+
key: c,
|
|
31
|
+
reason: "name"
|
|
32
|
+
}));
|
|
33
|
+
return {
|
|
34
|
+
style: s ? void 0 : o,
|
|
35
|
+
invalid: a
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function o(t) {
|
|
39
|
+
let { style: n, invalid: r } = a(t);
|
|
40
|
+
for (let { key: t, reason: n } of r) n === "name" ? e(`tokens:name:${t}`, `getTokenStyle: \`${t}\` is not a token name, so it is skipped. Token names are the CSS variable in camelCase without its \`--wave-\` prefix (\`primaryForeground\` for \`--wave-primary-foreground\`).`) : e(`tokens:value:${t}`, `getTokenStyle: the value of \`${t}\` is skipped: it must be a finite number, or CSS text with balanced quotes, brackets and comments, without \`;\`, \`{\`, \`}\` or \`url(\`, and without \`!\` or a backslash outside strings and comments.`);
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
function s(e, t) {
|
|
44
|
+
if (t === null) return {};
|
|
45
|
+
if (t === void 0) return e;
|
|
46
|
+
let n = Object.fromEntries(Object.entries(t).filter(([, e]) => e !== void 0));
|
|
47
|
+
return {
|
|
48
|
+
...e,
|
|
49
|
+
...n
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { a as collectTokenStyle, o as getTokenStyle, s as mergeTokenOverrides, t as tokenVariable };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=tokens.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.mjs","names":["tokenVariable","name","capital","TOKEN_NAME","REFUSED_TEXT","isBalancedCssText","closers","quote","index","text","char","collectTokenStyle","invalid","overrides","style","empty","key","value","getTokenStyle","reason","warnOnce","mergeTokenOverrides","own","parent","defined"],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design tokens in JavaScript: their names, the overrides `WaveProvider` takes and the inline\n * style that applies them. Server-safe and light enough for the provider: it imports only types\n * and the development warnings, never the list of token names (`waveTokens.ts`).\n */\nimport type * as React from 'react';\nimport { warnOnce } from './dev';\nimport type { WAVE_TOKEN_NAMES } from './waveTokens';\n\n/**\n * The name of a design token: its CSS custom property without the `--wave-` prefix, in camelCase.\n * `--wave-primary-foreground` is `primaryForeground`, `--wave-brand-80` is `brand80` and\n * `--wave-palette-red-tint` is `paletteRedTint`.\n */\nexport type WaveTokenName = (typeof WAVE_TOKEN_NAMES)[number];\n\n/** The shape of `waveTokens`: every token name mapped to the CSS value that reads the token. */\nexport type WaveTokens = { readonly [K in WaveTokenName]: string };\n\n/**\n * Token overrides: CSS values by token name, as `WaveProvider tokens` and `getTokenStyle` take\n * them. A number is written as its string (`zOverlay: 2000`); a key whose value is `undefined`\n * sets nothing.\n */\nexport type WaveTokenOverrides = { [K in WaveTokenName]?: string | number };\n\n/**\n * The inline style that applies token overrides: a React style object whose `--wave-*` custom\n * properties set the tokens, so it can be merged with other style properties.\n */\nexport type TokenStyle = React.CSSProperties & { [K in `--wave-${string}`]?: string };\n\n/**\n * The CSS custom property of a token name at the type level: `TokenVariable<'brand80'>` is\n * `'--wave-brand-80'`, by the rule of {@link tokenVariable}. It spells out the literal values of\n * `waveTokens`. It walks the name one character at a time (tail-recursive, so long names stay\n * within the compiler's depth limit): `AfterLetter` says whether the previous character was a\n * letter, `Done` holds the converted text so far.\n */\nexport type TokenVariable<\n Name extends string,\n AfterLetter extends boolean = false,\n Done extends string = '',\n> = Name extends `${infer Char}${infer Rest}`\n ? Char extends '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'\n ? TokenVariable<Rest, false, `${Done}${AfterLetter extends true ? '-' : ''}${Char}`>\n : Char extends Lowercase<Char>\n ? TokenVariable<Rest, true, `${Done}${Char}`>\n : TokenVariable<Rest, true, `${Done}-${Lowercase<Char>}`>\n : `--wave-${Done}`;\n\n/**\n * The CSS custom property of a token name: a hyphen before each capital letter and before a digit\n * run that follows a letter, lowercased, with the `--wave-` prefix. `'paletteRedTint'` gives\n * `'--wave-palette-red-tint'` and `'brand80'` gives `'--wave-brand-80'`. The name is not checked\n * against the list of tokens.\n */\nexport function tokenVariable(name: string): string {\n return `--wave-${name\n .replace(/([A-Za-z])(\\d)/g, '$1-$2')\n .replace(/[A-Z]/g, (capital) => `-${capital}`)\n .toLowerCase()}`;\n}\n\n/** A camelCase identifier: the only key shape a token name can have. */\nconst TOKEN_NAME = /^[a-z][A-Za-z0-9]*$/;\n\n/**\n * The text no token value may hold, anywhere in it. React writes a custom property's value into\n * the server-rendered `style` attribute as text, where a semicolon would end the declaration and\n * let the rest of the value declare a property of its own (and a brace could close the rule around\n * it); in the client the CSSOM refuses a value with a semicolon, so the two renders would also\n * differ. `url(`, in any case: no token takes a URL, and an unquoted one ends at its first `)`\n * whatever it holds, which the balance check below does not follow (`url(a\"b)c\")` would open a\n * string after that `)`); the check refuses the escapes that could spell it otherwise (`u\\72l(`).\n */\nconst REFUSED_TEXT = /[;{}]|url\\(/i;\n\n/**\n * Whether `text` closes everything it opens, read as the CSS tokenizer reads it: every string\n * closes on its own line (a backslash in it escapes the next character, a line break included),\n * every comment closes, and the parentheses and square brackets outside strings and comments pair\n * up and nest. In the server-rendered `style` attribute an open string, comment, parenthesis or\n * bracket would run on to the end of the attribute, so the declarations after it would be lost\n * there, while the client sets each property on its own. Refused as well, outside strings and\n * comments: a stray closer, which the client refuses in a custom property; a `!`, since the server\n * would read `!important` as the declaration's priority while the client refuses a `!` at the top\n * level (one nested in a function, as in `color-mix(in srgb, red !important, blue)`, is valid there, and refusing\n * it is deliberate: no token needs it); and a backslash, which no token needs there and which\n * could spell `url(` with an escape or, at the end, escape the semicolon after the value. One pass\n * over the text, each character read once and the stack an array, so the time grows with the\n * length alone and a long crafted value cannot stall a server render.\n */\nfunction isBalancedCssText(text: string): boolean {\n // The closers of the open parentheses and brackets, the innermost last.\n const closers: string[] = [];\n // The quote of the open string, '' outside one.\n let quote = '';\n let index = 0;\n for (; index < text.length; index++) {\n const char = text[index];\n if (quote) {\n // An escape takes the next character; a backslash at the end leaves the string open.\n if (char === '\\\\') index++;\n else if (char === quote) quote = '';\n else if ('\\n\\r\\f'.includes(char)) return false;\n } else if ('\"\\''.includes(char)) {\n quote = char;\n } else if (char === '/' && text[index + 1] === '*') {\n // A comment runs to its first `*/` and escapes nothing; one that never ends moves the index\n // past the end.\n index = text.indexOf('*/', index + 2) + 1 || Infinity;\n } else if ('(['.includes(char)) {\n closers.push(char === '(' ? ')' : ']');\n } else if (')]!\\\\'.includes(char) && closers.pop() !== char) {\n // A closer that is not the innermost one's, or a `!` or a backslash, which no opener\n // expects: the index moves past the end, which fails below.\n index = Infinity;\n }\n }\n return index === text.length && !quote && !closers.length;\n}\n\n/**\n * The custom properties of `overrides`, and the entries it skipped. Pure: it never warns, so the\n * provider can call it during render; {@link getTokenStyle} reports the skipped entries.\n *\n * `undefined` values are skipped first (they set nothing); a key that is not a camelCase\n * identifier is skipped with the reason `'name'`, and a value with the reason `'value'` unless it\n * is a finite number or a string without `;`, `{`, `}` or `url(` that closes every string,\n * comment, parenthesis and square bracket it opens and has no stray closer, `!` or backslash\n * outside strings and comments. Numbers are written as strings, and every value is trimmed with\n * JavaScript's `trim`, as React's server renderer trims a custom property's value (the client sets\n * the value as given), so both write the same text; a value that is empty after it is written as\n * `''`, for which React renders no declaration on either side. The style keeps the order of the\n * input. `style` is `undefined` when nothing is left.\n */\nexport function collectTokenStyle(overrides: WaveTokenOverrides | null | undefined): {\n style: TokenStyle | undefined;\n invalid: readonly { key: string; reason: 'name' | 'value' }[];\n} {\n const invalid: { key: string; reason: 'name' | 'value' }[] = [];\n if (overrides == null) return { style: undefined, invalid };\n const style: Record<string, string> = {};\n let empty = true;\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n if (value === undefined) continue;\n if (!TOKEN_NAME.test(key)) {\n invalid.push({ key, reason: 'name' });\n } else if (\n (typeof value === 'string' && !REFUSED_TEXT.test(value) && isBalancedCssText(value)) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n style[tokenVariable(key)] = String(value).trim();\n empty = false;\n } else {\n invalid.push({ key, reason: 'value' });\n }\n }\n return { style: empty ? undefined : (style as TokenStyle), invalid };\n}\n\n/**\n * The inline style that applies token overrides: one `--wave-*` custom property per entry, the\n * object `WaveProvider` puts on its root and its portals. Use it where no provider renders, such\n * as a Server Component's document element. Server-safe.\n *\n * Returns `undefined` for `null`, `undefined` or a map with nothing to set. An `undefined` value is\n * skipped, a number is written as its string, a string is trimmed as React's server renderer trims\n * it, and the properties keep the order of the input. A key that is not a camelCase identifier is\n * skipped with a development warning (once per key), and so is a value unless it is a finite\n * number or CSS text without `;`, `{`, `}` or `url(` whose quotes, parentheses, square brackets and\n * comments are balanced, with no `!` or backslash outside strings and comments. In a\n * server-rendered `style` attribute such a character could add a declaration of its own, an open\n * string, comment or bracket (or an escape that spells `url(` or takes the semicolon after the\n * value) would swallow the declarations after it, and `!important` would set a priority the client\n * refuses; the trimmed values that pass are read alike by the attribute and by the client. Names\n * are not checked against the list of tokens: TypeScript refuses a misspelled one, and in\n * JavaScript it sets a property nothing reads.\n *\n * @example\n * // app/layout.tsx (a Server Component)\n * <html style={getTokenStyle({ brand80: '#c43e00' })}>\n *\n * @example\n * <div style={{ ...getTokenStyle(overrides), padding: 16 }} />\n */\nexport function getTokenStyle(\n overrides: WaveTokenOverrides | null | undefined,\n): TokenStyle | undefined {\n const { style, invalid } = collectTokenStyle(overrides);\n for (const { key, reason } of invalid) {\n if (reason === 'name') {\n warnOnce(\n `tokens:name:${key}`,\n `getTokenStyle: \\`${key}\\` is not a token name, so it is skipped. Token names are the CSS ` +\n 'variable in camelCase without its `--wave-` prefix (`primaryForeground` for ' +\n '`--wave-primary-foreground`).',\n );\n } else {\n warnOnce(\n `tokens:value:${key}`,\n `getTokenStyle: the value of \\`${key}\\` is skipped: it must be a finite number, or CSS ` +\n 'text with balanced quotes, brackets and comments, without `;`, `{`, `}` or `url(`, and ' +\n 'without `!` or a backslash outside strings and comments.',\n );\n }\n }\n return style;\n}\n\n/**\n * The overrides of a nested provider: `own` merged key by key over `parent`. `undefined` inherits\n * `parent` as it is, `null` clears everything inherited, and a key whose own value is `undefined`\n * keeps the parent's value.\n */\nexport function mergeTokenOverrides(\n parent: WaveTokenOverrides,\n own: WaveTokenOverrides | null | undefined,\n): WaveTokenOverrides {\n if (own === null) return {};\n if (own === undefined) return parent;\n // Spread, never assignment, so a `__proto__` key is an own entry like any other.\n const defined = Object.fromEntries(\n Object.entries(own).filter(([, value]) => value !== undefined),\n );\n return { ...parent, ...defined };\n}\n"],"mappings":";;AAyDA,SAAgBA,EAAc,GAAsB;CAClD,OAAO,UAAUC,EACd,QAAQ,mBAAmB,OAAO,CAAC,CACnC,QAAQ,WAAW,MAAY,IAAIC,GAAS,CAAC,CAC7C,YAAY;AACjB;AAGA,IAAMC,IAAa,uBAWbC,IAAe;AAiBrB,SAASC,EAAkB,GAAuB;CAEhD,IAAMC,IAAoB,CAAC,GAEvBC,IAAQ,IACRC,IAAQ;CACZ,OAAOA,IAAQC,EAAK,QAAQ,KAAS;EACnC,IAAMC,IAAOD,EAAKD;EAClB,IAAID,GAAO;GAET,IAAIG,MAAS,MAAM;QACd,IAAIA,MAASH,GAAO,IAAQ;QAC5B,IAAI,SAAS,SAASG,CAAI,GAAG,OAAO;EAC3C,OAAO,AAAI,MAAM,SAASA,CAAI,IAC5B,IAAQA,IACCA,MAAS,OAAOD,EAAKD,IAAQ,OAAO,MAG7C,IAAQC,EAAK,QAAQ,MAAMD,IAAQ,CAAC,IAAI,KAAK,WACpC,KAAK,SAASE,CAAI,IAC3BJ,EAAQ,KAAKI,MAAS,MAAM,MAAM,GAAG,IAC5B,QAAQ,SAASA,CAAI,KAAKJ,EAAQ,IAAI,MAAMI,MAGrD,IAAQ;CAEZ;CACA,OAAOF,MAAUC,EAAK,UAAU,CAACF,KAAS,CAACD,EAAQ;AACrD;AAgBA,SAAgBK,EAAkB,GAGhC;CACA,IAAMC,IAAuD,CAAC;CAC9D,IAAIC,KAAa,MAAM,OAAO;EAAE,OAAO,KAAA;EAAW;CAAQ;CAC1D,IAAMC,IAAgC,CAAC,GACnCC,IAAQ;CACZ,KAAK,IAAM,CAACC,GAAKC,MAAU,OAAO,QAAQJ,CAAoC,GAC5E,AAAII,MAAU,KAAA,MACTd,EAAW,KAAKa,CAAG,IAGrB,OAAOC,KAAU,YAAY,CAACb,EAAa,KAAKa,CAAK,KAAKZ,EAAkBY,CAAK,KACjF,OAAOA,KAAU,YAAY,OAAO,SAASA,CAAK,KAEnD,EAAMjB,EAAcgB,CAAG,KAAK,OAAOC,CAAK,CAAC,CAAC,KAAK,GAC/C,IAAQ,MAERL,EAAQ,KAAK;EAAE;EAAK,QAAQ;CAAQ,CAAC,IARrCA,EAAQ,KAAK;EAAE;EAAK,QAAQ;CAAO,CAAC;CAWxC,OAAO;EAAE,OAAOG,IAAQ,KAAA,IAAaD;EAAsB;CAAQ;AACrE;AA2BA,SAAgBI,EACd,GACwB;CACxB,IAAM,EAAE,UAAO,eAAYP,EAAkBE,CAAS;CACtD,KAAK,IAAM,EAAE,QAAK,eAAYD,GAC5B,AAAIO,MAAW,SACbC,EACE,eAAeJ,KACf,oBAAoBA,EAAI,kLAG1B,IAEAI,EACE,gBAAgBJ,KAChB,iCAAiCA,EAAI,4MAGvC;CAGJ,OAAOF;AACT;AAOA,SAAgBO,EACd,GACA,GACoB;CACpB,IAAIC,MAAQ,MAAM,OAAO,CAAC;CAC1B,IAAIA,MAAQ,KAAA,GAAW,OAAOC;CAE9B,IAAMC,IAAU,OAAO,YACrB,OAAO,QAAQF,CAAG,CAAC,CAAC,QAAQ,GAAGL,OAAWA,MAAU,KAAA,CAAS,CAC/D;CACA,OAAO;EAAE,GAAGM;EAAQ,GAAGC;CAAQ;AACjC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./tokens.cjs");var t=`fontFamily.fontFamilyMonospace.fontFamilyNumeric.zOverlay.zToast.zTooltip.durationUltraFast.durationFaster.durationFast.durationNormal.durationGentle.durationSlow.durationSlower.durationUltraSlow.curveAccelerateMax.curveAccelerateMid.curveAccelerateMin.curveDecelerateMax.curveDecelerateMid.curveDecelerateMin.curveEasyEaseMax.curveEasyEase.curveLinear.brand10.brand20.brand30.brand40.brand50.brand60.brand70.brand80.brand90.brand100.brand110.brand120.brand130.brand140.brand150.brand160.grey2.grey4.grey6.grey8.grey10.grey12.grey14.grey16.grey20.grey24.grey26.grey30.grey34.grey38.grey40.grey44.grey50.grey60.grey68.grey74.grey78.grey82.grey86.grey88.grey90.grey92.grey94.grey96.grey98.background.foreground.card.secondary.muted.mutedForeground.mutedHover.mutedPressed.primary.primaryForeground.primaryHover.primaryPressed.destructive.destructiveForeground.error.errorForeground.subtle.subtleHover.subtlePressed.subtleSelected.selected.selectedForeground.selectedHover.selectedPressed.border.stroke.strokeHover.strokeAccessible.input.inputFilledDarker.inputFilledStroke.ring.success.successForeground.successTint.successTintForeground.warning.warningForeground.warningTint.warningTintForeground.errorTint.errorTintForeground.severe.severeForeground.severeTint.severeTintForeground.info.infoForeground.infoTint.infoTintForeground.inverted.invertedForeground.invertedBorder.track.skeleton.rating.presenceAvailable.presenceBusy.presenceAway.presenceOffline.presenceOof.presenceGlyph.backdrop.paletteRed.paletteRedForeground.paletteRedTint.paletteRedTintForeground.paletteRedBorder.palettePumpkin.palettePumpkinForeground.palettePumpkinTint.palettePumpkinTintForeground.palettePumpkinBorder.paletteGold.paletteGoldForeground.paletteGoldTint.paletteGoldTintForeground.paletteGoldBorder.paletteForest.paletteForestForeground.paletteForestTint.paletteForestTintForeground.paletteForestBorder.paletteTeal.paletteTealForeground.paletteTealTint.paletteTealTintForeground.paletteTealBorder.paletteBlue.paletteBlueForeground.paletteBlueTint.paletteBlueTintForeground.paletteBlueBorder.paletteNavy.paletteNavyForeground.paletteNavyTint.paletteNavyTintForeground.paletteNavyBorder.paletteLavender.paletteLavenderForeground.paletteLavenderTint.paletteLavenderTintForeground.paletteLavenderBorder.palettePurple.palettePurpleForeground.palettePurpleTint.palettePurpleTintForeground.palettePurpleBorder.paletteMagenta.paletteMagentaForeground.paletteMagentaTint.paletteMagentaTintForeground.paletteMagentaBorder.paletteBrown.paletteBrownForeground.paletteBrownTint.paletteBrownTintForeground.paletteBrownBorder.paletteSteel.paletteSteelForeground.paletteSteelTint.paletteSteelTintForeground.paletteSteelBorder.shadow2.shadow4.shadow8.shadow16.shadow28.shadow64.cardForeground.secondaryForeground.accent.accentForeground.inputFilledLighter`.split(`.`);function n(){return Object.freeze(Object.fromEntries(t.map(t=>[t,`var(${e.tokenVariable(t)})`])))}var r=n(),i=Object.freeze([`paletteBlue`,`palettePurple`,`paletteBrown`,`paletteTeal`,`paletteRed`,`paletteNavy`,`palettePumpkin`,`paletteSteel`,`paletteGold`,`paletteLavender`,`paletteForest`,`paletteMagenta`]);exports.WAVE_TOKEN_NAMES=t,exports.chartPalette=i,exports.waveTokens=r;
|
|
2
|
+
//# sourceMappingURL=waveTokens.cjs.map
|