@ui0/util 0.0.0-stage → 0.0.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/dist/index.js ADDED
@@ -0,0 +1,2164 @@
1
+ // src/array/array.ts
2
+ /**
3
+ * Omit values from arr based on values list and return new array with this values
4
+ * @param {T[]} arr
5
+ * @param {T[]} omitted
6
+ * @return {T[]}
7
+ */
8
+ function arrayOmit(arr, omitted) {
9
+ const _omitted = omitted || [];
10
+ const copy = arr ? [...arr] : [];
11
+ const out = copy || [];
12
+ _omitted.forEach((o) => {
13
+ const pos = copy.indexOf(o);
14
+ if (pos > -1) copy.splice(pos, 1);
15
+ });
16
+ return out;
17
+ }
18
+ /**
19
+ * Omit values from arr based on values list
20
+ * Mutable version of arrayOmit
21
+ * @param {T[]} arr
22
+ * @param {T[]} omitted
23
+
24
+ */
25
+ function arrayOmitArray(arr = [], omitted) {
26
+ const _omitted = omitted || [];
27
+ const copy = [...arr];
28
+ _omitted.forEach((o) => {
29
+ const pos = copy.indexOf(o);
30
+ if (pos > -1) copy.splice(pos, 1);
31
+ });
32
+ }
33
+ /**
34
+ * Make this array items unique
35
+ * [1,2,3,3,2,5] => [1,2,3,5]
36
+ * @param {T[]} arr
37
+ * @return {T[]}
38
+ */
39
+ function toUnique(arr) {
40
+ return [...new Set(arr)];
41
+ }
42
+ /**
43
+ * Return the last element of an array.
44
+ *
45
+ * @param arr - the array to read
46
+ * @returns the last item, or `undefined` for an empty array
47
+ */
48
+ function getLastItemFromArray(arr) {
49
+ return arr[arr.length - 1];
50
+ }
51
+ /**
52
+ * Pick element with offset from item's position in arr
53
+ * Next item - +1
54
+ * Prev item - -1
55
+ * returns same item if not found
56
+ * @param {T[]} arr
57
+ * @param {T} item
58
+ * @param {number} offset
59
+ * @return {T}
60
+ */
61
+ function arrayPickFromItemOffset(arr, item, offset) {
62
+ if (arr.length < 2) return item;
63
+ if (offset < 0 && arr[0] === item) return item;
64
+ if (offset > 0 && arr[arr.length - offset] === item) return item;
65
+ for (let i = 1; i < arr.length; i++) if (arr[i] === item) return arr[i + offset];
66
+ return item;
67
+ }
68
+ /**
69
+ * Pick the element `offset` positions after `item`.
70
+ *
71
+ * Thin wrapper over {@link arrayPickFromItemOffset} with a positive offset;
72
+ * out-of-range offsets and unknown items return `item` itself.
73
+ *
74
+ * @param arr - the array to walk
75
+ * @param item - the anchor element
76
+ * @param offset - how many positions to move forward, defaults to `1`
77
+ * @returns the neighbor element, or `item`
78
+ */
79
+ function arrayPickNext(arr, item, offset = 1) {
80
+ return arrayPickFromItemOffset(arr, item, offset);
81
+ }
82
+ /**
83
+ * Pick the element `offset` positions before `item`.
84
+ *
85
+ * Thin wrapper over {@link arrayPickFromItemOffset} with a negative offset;
86
+ * out-of-range offsets and unknown items return `item` itself.
87
+ *
88
+ * @param arr - the array to walk
89
+ * @param item - the anchor element
90
+ * @param offset - how many positions to move back, defaults to `1`
91
+ * @returns the neighbor element, or `item`
92
+ */
93
+ function arrayPickPrev(arr, item, offset = 1) {
94
+ return arrayPickFromItemOffset(arr, item, -offset);
95
+ }
96
+ /**
97
+ * get item from array when iterating over length
98
+ * getItemByOverflowIndex([0,1,2,3], 8) // => 1 ([0,1,2,3], 6) => 3
99
+ *
100
+ * @param {T[]} arr
101
+ * @param {number} index
102
+ * @param offset takes inc/dec by offset value,
103
+ * @default 1
104
+ * @return {T}
105
+ */
106
+ function getItemByOverflowIndex(arr, index, offset = 1) {
107
+ if (index > arr.length - offset) return arr[index % arr.length];
108
+ return arr[Math.abs(index)];
109
+ }
110
+ /**
111
+ * Coerce every element of an array to a number.
112
+ *
113
+ * Nullish entries become `0`; non-numeric strings coerce to `NaN`.
114
+ *
115
+ * @param arr - the source array
116
+ * @returns a parallel array of numbers
117
+ */
118
+ function arrayToNumberArray(arr) {
119
+ return arr.reduce((prev, next) => [...prev, +(next ?? 0)], []);
120
+ }
121
+ /**
122
+ * Compare two arrays item by item, recursing into nested arrays.
123
+ *
124
+ * @param a - the first array
125
+ * @param b - the second array
126
+ * @returns `true` when the lengths match and every pair is `===` (nested
127
+ * arrays compared recursively)
128
+ */
129
+ function arrayIsEqual(a, b) {
130
+ if (a === b) return true;
131
+ if (a.length !== b.length) return false;
132
+ return a.every((item, index) => {
133
+ const other = b[index];
134
+ return Array.isArray(item) && Array.isArray(other) ? arrayIsEqual(item, other) : item === other;
135
+ });
136
+ }
137
+ /**
138
+ * insert `items` to array at specific `index`
139
+ * delete `deleteCount` items from `index`
140
+ * @param arr
141
+ * @param index
142
+ * @param items
143
+ * @param deleteCount
144
+ */
145
+ function arrayInsertAtIndex(arr, index, items, deleteCount = 0) {
146
+ const safeIndex = Math.max(0, Math.min(index, arr.length));
147
+ arr.splice(safeIndex, deleteCount, ...items);
148
+ }
149
+ /**
150
+ * Type guard: value is an array.
151
+ *
152
+ * @param value - the value to check
153
+ * @returns `true` when `value` is an array
154
+ */
155
+ function isArray(value) {
156
+ return Array.isArray(value);
157
+ }
158
+ // src/object/objectPickKeys.ts
159
+ /**
160
+ * Pick keys from object to new object with key-value
161
+ *
162
+ * @param {T} obj
163
+ * @param keys
164
+ * @example objectPickKeys({key1: true, key2: 0, key3: 'str'}, 'key2', 'key3') // {key2: 0, key3: 'str'}
165
+ * @return {{[P in keyof T]?: any}}
166
+ */
167
+ function objectPickKeys(obj, ...keys) {
168
+ return keys.reduce((acc, key) => {
169
+ if (obj.hasOwnProperty(key)) acc[key] = obj[key];
170
+ return acc;
171
+ }, {});
172
+ }
173
+ // src/object/objectOmitKeys.ts
174
+ /**
175
+ * Opposite to objectPickKeys
176
+ * Return new object without selected keys
177
+ * @param {T} obj
178
+ * @param {P} args
179
+ * @example objectOmitKeys({key1: true, key2: 0, key3: 'str'}, 'key2', 'key3') // {key1: true}
180
+ * @return {{[P in keyof T]?: any}}
181
+ */
182
+ function objectOmitKeys(obj, ...args) {
183
+ const out = Object.assign({}, obj);
184
+ args.forEach((arg) => {
185
+ delete out[arg];
186
+ });
187
+ return out;
188
+ }
189
+ // src/primitives.ts
190
+ /**
191
+ * Replace `undefined` with `false`, keeping any other value as-is.
192
+ *
193
+ * @param x - the value to guard
194
+ * @returns `x`, or `false` when `x` is `undefined`
195
+ */
196
+ function notUndefined(x) {
197
+ return x !== void 0 ? x : false;
198
+ }
199
+ /**
200
+ * Type guard: value is a function (anything callable).
201
+ *
202
+ * @param fn - the value to check
203
+ * @returns `true` when `fn` is callable
204
+ */
205
+ const isFunction = (fn) => typeof fn === "function";
206
+ /**
207
+ * Type guard: value is a symbol.
208
+ *
209
+ * @param s - the value to check
210
+ * @returns `true` when `s` is a symbol
211
+ */
212
+ const isSymbol = (s) => typeof s === "symbol";
213
+ // src/object/isObject.ts
214
+ /**
215
+ * Type guard: value is an object (not `null`, not an array).
216
+ *
217
+ * @param v - the value to check
218
+ * @returns `true` for non-null, non-array objects
219
+ */
220
+ function isObject(v) {
221
+ return typeof v === "object" && v !== null && !Array.isArray(v);
222
+ }
223
+ // src/object/objectMerge.ts
224
+ /**
225
+ * Objects customizable deep merging
226
+ * @param {Record<string, any>} to
227
+ * @param {Record<string, any>} from
228
+ * @param {{replaceNonObjectIfObject: boolean}} options
229
+ * @return {Record<string, any>}
230
+ */
231
+ function objectMerge(to, from, options = {}) {
232
+ const result = { ...to };
233
+ const { overwrite = true, replaceNonObjectIfObject = false, mergeFunctions = false } = options;
234
+ if (!isObject(to) || !isObject(from)) return overwrite ? {
235
+ ...result,
236
+ ...from
237
+ } : result;
238
+ for (const key in from) if (key in to) {
239
+ if (mergeFunctions && isFunction(from[key])) result[key] = isFunction(to[key]) ? (...arg) => {
240
+ to[key](...arg);
241
+ return from[key](...arg);
242
+ } : overwrite ? from[key] : to[key];
243
+ else if (isObject(from[key]) && isObject(to[key])) result[key] = objectMerge(to[key], from[key], options);
244
+ else if (replaceNonObjectIfObject && isObject(from[key])) result[key] = from[key];
245
+ else result[key] = overwrite ? from[key] : to[key];
246
+ } else result[key] = from[key];
247
+ return result;
248
+ }
249
+ // src/string/string.ts
250
+ const hyphenateExpr = /\B([A-Z])/g;
251
+ /**
252
+ * Convert CaseWordAAA to 'case-word-a-a-a'
253
+ * @param {string} str
254
+ * @return {string}
255
+ */
256
+ function hyphenate(str) {
257
+ return str.replace(hyphenateExpr, "-$1").toLowerCase();
258
+ }
259
+ /**
260
+ * Converts `is-name` to 'isName'
261
+ * @param s
262
+ */
263
+ function toCamelCase(s = "") {
264
+ return s.replace(/-./g, (x) => x[1].toUpperCase());
265
+ }
266
+ /**
267
+ * Converts string to kebab-case (including spaces).
268
+ * @example
269
+ * toKebabCase('Hello World') => 'hello-world'
270
+ * toKebabCase('camelCase') => 'camel-case'
271
+ */
272
+ function toKebabCase(str) {
273
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase().replace(/^-+|-+$/g, "");
274
+ }
275
+ /**
276
+ * Convert a kebab-case string to PascalCase (`'is-name'` → `'IsName'`).
277
+ *
278
+ * @param s - the kebab-case input
279
+ * @returns the PascalCase string
280
+ */
281
+ function toPascalCase(s = "") {
282
+ const r = s.replace(/-./g, (x) => x[1].toUpperCase());
283
+ return r ? r[0].toUpperCase() + r.substring(1) : r;
284
+ }
285
+ /**
286
+ * Kebab-case a string, collapsing uppercase runs as whole words.
287
+ *
288
+ * Unlike {@link toKebabCase} (which only splits on lower→upper edges),
289
+ * consecutive capitals collapse together: `'FOOBar'` → `'foo-bar'`,
290
+ * `'XMLHttpRequest'` → `'xml-http-request'`.
291
+ *
292
+ * @param str - the string to kebab-case
293
+ * @returns the kebab-cased string
294
+ */
295
+ function kebabize(str) {
296
+ return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs) => (ofs ? "-" : "") + s.toLowerCase());
297
+ }
298
+ /**
299
+ * Remove vowels form word
300
+ * @param {string} str
301
+ * @example removeVowels('hello world') // hll wrld
302
+ * @return {string}
303
+ */
304
+ function removeVowels(str) {
305
+ return str.replace(/[aoeyui]/g, "");
306
+ }
307
+ /**
308
+ * returns filename from a path
309
+ * @param {string} name
310
+ * @example extractFileName('/some/path/to/file.txt') // file.txt
311
+ * @return {string | undefined}
312
+ */
313
+ function extractFileName(name) {
314
+ return name.split(/(\\|\/)/g).pop();
315
+ }
316
+ /**
317
+ * Return the directory part of a path — everything before the file name.
318
+ *
319
+ * @param file - the path to split
320
+ * @returns the trailing-slash directory, or `''` when the path has none
321
+ */
322
+ function extractFileDir(file) {
323
+ return file.replace(extractFileName(file) || "", "");
324
+ }
325
+ /**
326
+ * process pack/icon?value=123 to {params: {value: 123}, res: ['pack', 'icon']}
327
+ * @param query
328
+ */
329
+ function parseQueryString(query) {
330
+ if (!query) return {
331
+ params: {},
332
+ res: [""]
333
+ };
334
+ const paramsOut = {};
335
+ const [res, params] = query.split("?");
336
+ const resources = res.split("/").toReversed();
337
+ if (params) params.split("&").forEach((item) => {
338
+ const [param, value] = item.split("=");
339
+ paramsOut[param] = value;
340
+ if (value === void 0) paramsOut[param] = true;
341
+ else if (value.indexOf(",") > 1) paramsOut[param] = value.split(",");
342
+ if (value === "false") paramsOut[param] = false;
343
+ else if (!isNaN(+value)) paramsOut[param] = +value;
344
+ });
345
+ return {
346
+ params: paramsOut,
347
+ res: resources
348
+ };
349
+ }
350
+ /**
351
+ * convert 'some content here' to 'sch'
352
+ * @param {string} str
353
+ * @return {string}
354
+ */
355
+ function stringToFirstLetters(str) {
356
+ return str.split(" ").reduce((x, i) => x ? x + (i.length && i[0] || "") : i[0], "");
357
+ }
358
+ /**
359
+ * Generate random string (a-z 0-9) with specific len
360
+ *
361
+ * @param {number} len 6 by default
362
+ * @default 6
363
+ * @return {string}
364
+ */
365
+ function genRandomString(len = 6) {
366
+ let out = "";
367
+ while (out.length < len) out += Math.random().toString(36).replace("0.", "");
368
+ return out.substring(0, len);
369
+ }
370
+ /**
371
+ * Typed String.split() wrapper
372
+ * @param input
373
+ * @param separator
374
+ */
375
+ function splitString(input, separator) {
376
+ if (Array.isArray(input)) return input;
377
+ return input.split(separator).map((item) => item.trim());
378
+ }
379
+ /**
380
+ * typeof guard
381
+ */
382
+ function isString(v) {
383
+ return typeof v === "string";
384
+ }
385
+ // src/vue/findFrameworkInstance.ts
386
+ /**
387
+ * retrieve instance of a any framework plugin from vue instance if exists
388
+ * @param app
389
+ * @param name
390
+ */
391
+ function findFrameworkInstance(app, name) {
392
+ if (name in app.config.globalProperties) {
393
+ const instance = app.config.globalProperties[name];
394
+ if (instance) return instance;
395
+ }
396
+ }
397
+ // src/vue/mergeCssModulesStyles.ts
398
+ /**
399
+ * Merge two CSS-module class maps, the second winning on key conflicts.
400
+ *
401
+ * Mirrors how a component's own local `$style` overrides the class map
402
+ * shipped by a contract.
403
+ *
404
+ * @param $from - the base map (e.g. the contract's shipped classes)
405
+ * @param $to - the overriding map (e.g. the component's local `$style`)
406
+ * @returns the merged class map
407
+ */
408
+ function mergeCssModulesStyles($from = {}, $to = {}) {
409
+ return {
410
+ ...$from,
411
+ ...$to
412
+ };
413
+ }
414
+ // src/number/number.ts
415
+ /**
416
+ * Floor the mantissa of a number's scientific notation after shifting its
417
+ * exponent by `-exp`, then shift the exponent back.
418
+ *
419
+ * Operates on the printed `toString()` digits rather than on decimal
420
+ * places: `decimalAdjust(0, 2.7)` → `2`, `decimalAdjust(2, 123.456)` →
421
+ * `100`. A non-integer `exp` or a non-numeric `value` yields `NaN`.
422
+ *
423
+ * @param exp - the decimal exponent shift (integer)
424
+ * @param value - the number to adjust
425
+ * @returns the adjusted number
426
+ */
427
+ function decimalAdjust(exp, value) {
428
+ value = Number(value);
429
+ if (exp % 1 !== 0 || Number.isNaN(value)) return NaN;
430
+ else if (exp === 0) return Math.floor(value);
431
+ const [magnitude, exponent = 0] = value.toString().split("e");
432
+ const [newMagnitude, newExponent = 0] = Math.floor(+`${magnitude}e${+exponent - exp}`).toString().split("e");
433
+ return Number(`${newMagnitude}e${+newExponent + exp}`);
434
+ }
435
+ /**
436
+ * Extract the exponent of a number's scientific-notation form.
437
+ *
438
+ * `123.456` → `2` (`1.23456e+2`), `0.00123` → `-3` (`1.23e-3`).
439
+ *
440
+ * @param num - the number to inspect
441
+ * @returns the decimal exponent as a signed number
442
+ */
443
+ function exponentialToNumber(num) {
444
+ const x = (+num).toExponential();
445
+ const minus = x.split("e-");
446
+ const plus = x.split("e+");
447
+ if (minus[1] !== void 0) return -minus[1];
448
+ if (plus[1] !== void 0) return +plus[1];
449
+ return 0;
450
+ }
451
+ /**
452
+ * Tell floats from integers.
453
+ *
454
+ * @param n - the number to check
455
+ * @returns `true` when `n` has a non-zero fractional part
456
+ */
457
+ function isFloat(n) {
458
+ return n % 1 !== 0;
459
+ }
460
+ /**
461
+ * Count the digits after the decimal point.
462
+ *
463
+ * @param int - the (float) number to inspect
464
+ * @returns the number of fractional digits; `0` for integers
465
+ */
466
+ function getFloatDigitsCount(int) {
467
+ if (int % 1 !== 0) return int.toString().split(".")[1].length;
468
+ return 0;
469
+ }
470
+ /**
471
+ * Type guard: value is a number or a string coercible to one.
472
+ *
473
+ * Coercion follows `+v` — numeric strings pass, non-numeric ones don't.
474
+ *
475
+ * @param v - the value to check
476
+ * @returns `true` when `v` is a string/number and `+v` is not `NaN`
477
+ */
478
+ function isNumberish(v) {
479
+ return (typeof v === "string" || typeof v === "number") && !Number.isNaN(+v);
480
+ }
481
+ /**
482
+ * Strict numeric-validity check: real, finite, non-`NaN` numbers — and
483
+ * numeric strings that aren't blank.
484
+ *
485
+ * @param val - the value to check
486
+ * @returns `true` only for genuine numeric values
487
+ */
488
+ function isValidNumber(val) {
489
+ return typeof val === "number" && val - val === 0 || typeof val === "string" && Number.isFinite(+val) && val.trim() !== "";
490
+ }
491
+ /**
492
+ * Coerce a number-ish value with `+val`.
493
+ *
494
+ * @param val - the value to coerce; `undefined` falls back to `def`
495
+ * @param def - the default for `undefined`, defaults to `0`
496
+ * @returns the coerced number, `def` for `undefined`, or `NaN` when `val`
497
+ * coerces to `NaN` (no validation is applied)
498
+ */
499
+ function numberCast(val, def = 0) {
500
+ return +(val ?? def);
501
+ }
502
+ /**
503
+ * Clamp a number into the inclusive `[min, max]` range.
504
+ *
505
+ * @param value - the number to clamp
506
+ * @param min - the lower bound
507
+ * @param max - the upper bound
508
+ * @returns the bounded value
509
+ */
510
+ function clamp(value, min, max) {
511
+ return Math.min(Math.max(value, min), max);
512
+ }
513
+ // src/css/parseCssTime.ts
514
+ /**
515
+ * Parse a CSS time literal into milliseconds.
516
+ *
517
+ * Accepts the two CSS time units: `<number>s` and `<number>ms`. Anything
518
+ * that doesn't match the `value + unit` shape — unitless numbers, other
519
+ * units, arbitrary strings — returns `0`, mirroring an unset duration.
520
+ *
521
+ * @param cssTime - a CSS time literal, e.g. `'300ms'`, `'2.5s'`
522
+ * @returns the time in milliseconds (`'2.5s'` → `2500`), or `0` when invalid
523
+ */
524
+ function parseCssTime(cssTime) {
525
+ const match = cssTime.match(/^([\d.]+)(s|ms)$/);
526
+ if (!match) return 0;
527
+ const value = parseFloat(match[1]);
528
+ return match[2] === "s" ? value * 1e3 : value;
529
+ }
530
+ // src/css/toUnits.ts
531
+ /**
532
+ * Append a CSS unit to a unitless value.
533
+ *
534
+ * Numbers and numeric strings get `units` appended (`20` → `'20px'`,
535
+ * `'2.5'` → `'2.5px'`). Anything else — strings that already carry a unit
536
+ * or a keyword (`'20em'`, `'auto'`), `undefined` — returns an empty string;
537
+ * use {@link tryToUnits} when the original value should survive.
538
+ *
539
+ * @param val - a number or a numeric string
540
+ * @param units - the unit to append, defaults to `'px'`
541
+ * @returns the value with the unit attached, or `''` when `val` is not
542
+ * unitless-numeric
543
+ */
544
+ function toUnits(val, units = "px") {
545
+ if (typeof val === "number") return val + units;
546
+ else if (typeof val === "string") {
547
+ if (val === +val + "") return val + units;
548
+ }
549
+ return "";
550
+ }
551
+ // src/css/tryToUnits.ts
552
+ /**
553
+ * Like {@link toUnits}, but passes non-numeric values through untouched.
554
+ *
555
+ * Numberish input gets the unit appended (`20` → `'20px'`); strings that
556
+ * already read as CSS (`'20em'`, `'auto'`) are returned as-is; `undefined`
557
+ * collapses to `'0'` so an omitted value never leaks into a style
558
+ * declaration.
559
+ *
560
+ * @param val - a number, a numeric string, or any other CSS value
561
+ * @param units - the unit for numberish input, defaults to `'px'`
562
+ * @returns the unit-bearing value, the original string, or `'0'`
563
+ */
564
+ function tryToUnits(val, units = "px") {
565
+ return isNumberish(val) ? toUnits(val, units) : val ?? "0";
566
+ }
567
+ // src/css/objectToCss.ts
568
+ /**
569
+ * Serialize a style object into an inline CSS declaration string.
570
+ *
571
+ * camelCase keys are kebab-cased (`zIndex` → `z-index`, an initial capital
572
+ * becomes a vendor prefix: `WebkitBackdropFilter` → `-webkit-backdrop-filter`),
573
+ * each pair becomes `key:value;` and pairs are concatenated without
574
+ * separators — the result targets a single `style` attribute or a css-in-js
575
+ * template, not pretty printing.
576
+ *
577
+ * @param obj - the style object (`StyleList` / any plain record)
578
+ * @returns the declaration string, e.g. `'width:20px;z-index:2;'`
579
+ */
580
+ function objectToCss(obj) {
581
+ return Object.entries(obj).map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase())}:${v};`).join("");
582
+ }
583
+ // src/css/parseUnits.ts
584
+ /**
585
+ * convert 123px to {value: 123, units: 'px'}
586
+ * @param {string} str
587
+ * @return {{units: string, value: number}}
588
+ */
589
+ function parseUnits(str = "") {
590
+ const result = /-?\d*\.?\d+/.exec(str);
591
+ if (result && result[0]) {
592
+ const value = +result[0];
593
+ const units = str.replace(result[0], "");
594
+ return {
595
+ value,
596
+ units,
597
+ calc: value + units
598
+ };
599
+ } else return {
600
+ value: 0,
601
+ units: "px",
602
+ calc: ""
603
+ };
604
+ }
605
+ // src/console.ts
606
+ /**
607
+ * Build the error a composable throws when it is called outside of a
608
+ * component's setup or lifecycle hooks.
609
+ *
610
+ * @param funcName - the composable's name for the message
611
+ * @returns the ready `Error` instance
612
+ */
613
+ function newErrorForSetupCall(funcName) {
614
+ return /* @__PURE__ */ new Error(`${funcName} must be called from the setup or lifecycle hook methods.`);
615
+ }
616
+ /**
617
+ * Build a core-prefixed framework error (`[core]: <msg>`).
618
+ *
619
+ * @param msg - the error detail
620
+ * @returns the ready `Error` instance
621
+ */
622
+ function newFrameworkError(msg) {
623
+ return /* @__PURE__ */ new Error(`[core]: ${msg}`);
624
+ }
625
+ /**
626
+ * Build the error thrown when an app is requested by a name nothing
627
+ * registered under.
628
+ *
629
+ * @param data - the missing app's name
630
+ * @returns the ready `Error` instance
631
+ */
632
+ function newErrorAppNotFound(data) {
633
+ return /* @__PURE__ */ new Error(`App ${data} not found.`);
634
+ }
635
+ /**
636
+ * Build the error thrown when an app name is registered twice.
637
+ *
638
+ * @param data - the duplicated app's name
639
+ * @returns the ready `Error` instance
640
+ */
641
+ function newErrorAppExists(data) {
642
+ return /* @__PURE__ */ new Error(`App ${data} already exists. Please, provide unique name for each app.`);
643
+ }
644
+ /**
645
+ * Build the error `useApp` throws when no app context is active.
646
+ *
647
+ * @returns the ready `Error` instance
648
+ */
649
+ function newErrorUseAppCall() {
650
+ return /* @__PURE__ */ new Error(`useApp must be called inside any app.
651
+ use data in <app data></app>`);
652
+ }
653
+ // src/hash.ts
654
+ const K = [
655
+ 1116352408,
656
+ 1899447441,
657
+ 3049323471,
658
+ 3921009573,
659
+ 961987163,
660
+ 1508970993,
661
+ 2453635748,
662
+ 2870763221,
663
+ 3624381080,
664
+ 310598401,
665
+ 607225278,
666
+ 1426881987,
667
+ 1925078388,
668
+ 2162078206,
669
+ 2614888103,
670
+ 3248222580,
671
+ 3835390401,
672
+ 4022224774,
673
+ 264347078,
674
+ 604807628,
675
+ 770255983,
676
+ 1249150122,
677
+ 1555081692,
678
+ 1996064986,
679
+ 2554220882,
680
+ 2821834349,
681
+ 2952996808,
682
+ 3210313671,
683
+ 3336571891,
684
+ 3584528711,
685
+ 113926993,
686
+ 338241895,
687
+ 666307205,
688
+ 773529912,
689
+ 1294757372,
690
+ 1396182291,
691
+ 1695183700,
692
+ 1986661051,
693
+ 2177026350,
694
+ 2456956037,
695
+ 2730485921,
696
+ 2820302411,
697
+ 3259730800,
698
+ 3345764771,
699
+ 3516065817,
700
+ 3600352804,
701
+ 4094571909,
702
+ 275423344,
703
+ 430227734,
704
+ 506948616,
705
+ 659060556,
706
+ 883997877,
707
+ 958139571,
708
+ 1322822218,
709
+ 1537002063,
710
+ 1747873779,
711
+ 1955562222,
712
+ 2024104815,
713
+ 2227730452,
714
+ 2361852424,
715
+ 2428436474,
716
+ 2756734187,
717
+ 3204031479,
718
+ 3329325298
719
+ ];
720
+ function rotr(x, n) {
721
+ return x >>> n | x << 32 - n;
722
+ }
723
+ /**
724
+ * SHA-256 of a string as a lowercase hex digest.
725
+ *
726
+ * Pure JS implementation (FIPS 180-4) — runs identically in the browser
727
+ * and in Node, so generated class-name hashes can be computed at runtime
728
+ * on either side without `node:crypto`.
729
+ *
730
+ * @param message - the string to hash (UTF-8 encoded)
731
+ * @returns the 64-character hex digest
732
+ */
733
+ function sha256hex(message) {
734
+ const bytes = new TextEncoder().encode(message);
735
+ const bitLen = bytes.length * 8;
736
+ const padded = new Uint8Array((bytes.length + 8 >> 6) + 1 << 6);
737
+ padded.set(bytes);
738
+ padded[bytes.length] = 128;
739
+ const view = new DataView(padded.buffer);
740
+ view.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
741
+ view.setUint32(padded.length - 4, bitLen >>> 0);
742
+ let h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762;
743
+ let h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225;
744
+ const w = /* @__PURE__ */ new Uint32Array(64);
745
+ for (let block = 0; block < padded.length; block += 64) {
746
+ for (let t = 0; t < 16; t++) w[t] = view.getUint32(block + t * 4);
747
+ for (let t = 16; t < 64; t++) {
748
+ const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ w[t - 15] >>> 3;
749
+ const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ w[t - 2] >>> 10;
750
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1 | 0;
751
+ }
752
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
753
+ for (let t = 0; t < 64; t++) {
754
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
755
+ const ch = e & f ^ ~e & g;
756
+ const t1 = h + S1 + ch + K[t] + w[t] | 0;
757
+ const t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + (a & b ^ a & c ^ b & c) | 0;
758
+ h = g;
759
+ g = f;
760
+ f = e;
761
+ e = d + t1 | 0;
762
+ d = c;
763
+ c = b;
764
+ b = a;
765
+ a = t1 + t2 | 0;
766
+ }
767
+ h0 = h0 + a | 0;
768
+ h1 = h1 + b | 0;
769
+ h2 = h2 + c | 0;
770
+ h3 = h3 + d | 0;
771
+ h4 = h4 + e | 0;
772
+ h5 = h5 + f | 0;
773
+ h6 = h6 + g | 0;
774
+ h7 = h7 + h | 0;
775
+ }
776
+ return [
777
+ h0,
778
+ h1,
779
+ h2,
780
+ h3,
781
+ h4,
782
+ h5,
783
+ h6,
784
+ h7
785
+ ].map((x) => (x >>> 0).toString(16).padStart(8, "0")).join("");
786
+ }
787
+ // src/color/hexToRgb.ts
788
+ /**
789
+ * Parse a CSS hex color into an sRGB triple.
790
+ *
791
+ * Accepts the long (`#rrggbb`) and short (`#rgb`) forms, with or without
792
+ * the leading `#`.
793
+ *
794
+ * @param hex - the hex literal, e.g. `'#16e3c5'`, `'f00'`
795
+ * @returns `[r, g, b]` with integer channels 0-255
796
+ */
797
+ function hexToRgb(hex) {
798
+ hex = hex.replace("#", "");
799
+ if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
800
+ const num = parseInt(hex, 16);
801
+ return [
802
+ num >> 16 & 255,
803
+ num >> 8 & 255,
804
+ num & 255
805
+ ];
806
+ }
807
+ // src/color/parseRgbString.ts
808
+ /**
809
+ * Extract the RGB channels from an `rgb()` / `rgba()` string.
810
+ *
811
+ * Handles the legacy comma syntax (`rgb(1, 2, 3)`) and the modern space
812
+ * syntax with alpha (`rgb(1 2 3 / .5)`); the alpha component is dropped.
813
+ *
814
+ * @param s - the CSS color function string
815
+ * @returns `[r, g, b]` as parsed (fractional for decimals/percentages)
816
+ */
817
+ function parseRgbString(s) {
818
+ const parts = s.match(/rgba?\(([^)]+)\)/)[1].replace(/\//g, " ").split(/[\s,]+/).filter(Boolean).map((x) => parseFloat(x));
819
+ return [
820
+ parts[0],
821
+ parts[1],
822
+ parts[2]
823
+ ];
824
+ }
825
+ // src/color/namedColors.ts
826
+ /**
827
+ * The CSS named colors (CSS Color Module Level 4) as sRGB triples,
828
+ * keyed by lowercase name.
829
+ */
830
+ const NAMED_COLORS = {
831
+ aliceblue: [
832
+ 240,
833
+ 248,
834
+ 255
835
+ ],
836
+ antiquewhite: [
837
+ 250,
838
+ 235,
839
+ 215
840
+ ],
841
+ aqua: [
842
+ 0,
843
+ 255,
844
+ 255
845
+ ],
846
+ aquamarine: [
847
+ 127,
848
+ 255,
849
+ 212
850
+ ],
851
+ azure: [
852
+ 240,
853
+ 255,
854
+ 255
855
+ ],
856
+ beige: [
857
+ 245,
858
+ 245,
859
+ 220
860
+ ],
861
+ bisque: [
862
+ 255,
863
+ 228,
864
+ 196
865
+ ],
866
+ black: [
867
+ 0,
868
+ 0,
869
+ 0
870
+ ],
871
+ blanchedalmond: [
872
+ 255,
873
+ 235,
874
+ 205
875
+ ],
876
+ blue: [
877
+ 0,
878
+ 0,
879
+ 255
880
+ ],
881
+ blueviolet: [
882
+ 138,
883
+ 43,
884
+ 226
885
+ ],
886
+ brown: [
887
+ 165,
888
+ 42,
889
+ 42
890
+ ],
891
+ burlywood: [
892
+ 222,
893
+ 184,
894
+ 135
895
+ ],
896
+ cadetblue: [
897
+ 95,
898
+ 158,
899
+ 160
900
+ ],
901
+ chartreuse: [
902
+ 127,
903
+ 255,
904
+ 0
905
+ ],
906
+ chocolate: [
907
+ 210,
908
+ 105,
909
+ 30
910
+ ],
911
+ coral: [
912
+ 255,
913
+ 127,
914
+ 80
915
+ ],
916
+ cornflowerblue: [
917
+ 100,
918
+ 149,
919
+ 237
920
+ ],
921
+ cornsilk: [
922
+ 255,
923
+ 248,
924
+ 220
925
+ ],
926
+ crimson: [
927
+ 220,
928
+ 20,
929
+ 60
930
+ ],
931
+ cyan: [
932
+ 0,
933
+ 255,
934
+ 255
935
+ ],
936
+ darkblue: [
937
+ 0,
938
+ 0,
939
+ 139
940
+ ],
941
+ darkcyan: [
942
+ 0,
943
+ 139,
944
+ 139
945
+ ],
946
+ darkgoldenrod: [
947
+ 184,
948
+ 134,
949
+ 11
950
+ ],
951
+ darkgray: [
952
+ 169,
953
+ 169,
954
+ 169
955
+ ],
956
+ darkgreen: [
957
+ 0,
958
+ 100,
959
+ 0
960
+ ],
961
+ darkgrey: [
962
+ 169,
963
+ 169,
964
+ 169
965
+ ],
966
+ darkkhaki: [
967
+ 189,
968
+ 183,
969
+ 107
970
+ ],
971
+ darkmagenta: [
972
+ 139,
973
+ 0,
974
+ 139
975
+ ],
976
+ darkolivegreen: [
977
+ 85,
978
+ 107,
979
+ 47
980
+ ],
981
+ darkorange: [
982
+ 255,
983
+ 140,
984
+ 0
985
+ ],
986
+ darkorchid: [
987
+ 153,
988
+ 50,
989
+ 204
990
+ ],
991
+ darkred: [
992
+ 139,
993
+ 0,
994
+ 0
995
+ ],
996
+ darksalmon: [
997
+ 233,
998
+ 150,
999
+ 122
1000
+ ],
1001
+ darkseagreen: [
1002
+ 143,
1003
+ 188,
1004
+ 143
1005
+ ],
1006
+ darkslateblue: [
1007
+ 72,
1008
+ 61,
1009
+ 139
1010
+ ],
1011
+ darkslategray: [
1012
+ 47,
1013
+ 79,
1014
+ 79
1015
+ ],
1016
+ darkslategrey: [
1017
+ 47,
1018
+ 79,
1019
+ 79
1020
+ ],
1021
+ darkturquoise: [
1022
+ 0,
1023
+ 206,
1024
+ 209
1025
+ ],
1026
+ darkviolet: [
1027
+ 148,
1028
+ 0,
1029
+ 211
1030
+ ],
1031
+ deeppink: [
1032
+ 255,
1033
+ 20,
1034
+ 147
1035
+ ],
1036
+ deepskyblue: [
1037
+ 0,
1038
+ 191,
1039
+ 255
1040
+ ],
1041
+ dimgray: [
1042
+ 105,
1043
+ 105,
1044
+ 105
1045
+ ],
1046
+ dimgrey: [
1047
+ 105,
1048
+ 105,
1049
+ 105
1050
+ ],
1051
+ dodgerblue: [
1052
+ 30,
1053
+ 144,
1054
+ 255
1055
+ ],
1056
+ firebrick: [
1057
+ 178,
1058
+ 34,
1059
+ 34
1060
+ ],
1061
+ floralwhite: [
1062
+ 255,
1063
+ 250,
1064
+ 240
1065
+ ],
1066
+ forestgreen: [
1067
+ 34,
1068
+ 139,
1069
+ 34
1070
+ ],
1071
+ fuchsia: [
1072
+ 255,
1073
+ 0,
1074
+ 255
1075
+ ],
1076
+ gainsboro: [
1077
+ 220,
1078
+ 220,
1079
+ 220
1080
+ ],
1081
+ ghostwhite: [
1082
+ 248,
1083
+ 248,
1084
+ 255
1085
+ ],
1086
+ gold: [
1087
+ 255,
1088
+ 215,
1089
+ 0
1090
+ ],
1091
+ goldenrod: [
1092
+ 218,
1093
+ 165,
1094
+ 32
1095
+ ],
1096
+ gray: [
1097
+ 128,
1098
+ 128,
1099
+ 128
1100
+ ],
1101
+ green: [
1102
+ 0,
1103
+ 128,
1104
+ 0
1105
+ ],
1106
+ greenyellow: [
1107
+ 173,
1108
+ 255,
1109
+ 47
1110
+ ],
1111
+ grey: [
1112
+ 128,
1113
+ 128,
1114
+ 128
1115
+ ],
1116
+ honeydew: [
1117
+ 240,
1118
+ 255,
1119
+ 240
1120
+ ],
1121
+ hotpink: [
1122
+ 255,
1123
+ 105,
1124
+ 180
1125
+ ],
1126
+ indianred: [
1127
+ 205,
1128
+ 92,
1129
+ 92
1130
+ ],
1131
+ indigo: [
1132
+ 75,
1133
+ 0,
1134
+ 130
1135
+ ],
1136
+ ivory: [
1137
+ 255,
1138
+ 255,
1139
+ 240
1140
+ ],
1141
+ khaki: [
1142
+ 240,
1143
+ 230,
1144
+ 140
1145
+ ],
1146
+ lavender: [
1147
+ 230,
1148
+ 230,
1149
+ 250
1150
+ ],
1151
+ lavenderblush: [
1152
+ 255,
1153
+ 240,
1154
+ 245
1155
+ ],
1156
+ lawngreen: [
1157
+ 124,
1158
+ 252,
1159
+ 0
1160
+ ],
1161
+ lemonchiffon: [
1162
+ 255,
1163
+ 250,
1164
+ 205
1165
+ ],
1166
+ lightblue: [
1167
+ 173,
1168
+ 216,
1169
+ 230
1170
+ ],
1171
+ lightcoral: [
1172
+ 240,
1173
+ 128,
1174
+ 128
1175
+ ],
1176
+ lightcyan: [
1177
+ 224,
1178
+ 255,
1179
+ 255
1180
+ ],
1181
+ lightgoldenrodyellow: [
1182
+ 250,
1183
+ 250,
1184
+ 210
1185
+ ],
1186
+ lightgray: [
1187
+ 211,
1188
+ 211,
1189
+ 211
1190
+ ],
1191
+ lightgreen: [
1192
+ 144,
1193
+ 238,
1194
+ 144
1195
+ ],
1196
+ lightgrey: [
1197
+ 211,
1198
+ 211,
1199
+ 211
1200
+ ],
1201
+ lightpink: [
1202
+ 255,
1203
+ 182,
1204
+ 193
1205
+ ],
1206
+ lightsalmon: [
1207
+ 255,
1208
+ 160,
1209
+ 122
1210
+ ],
1211
+ lightseagreen: [
1212
+ 32,
1213
+ 178,
1214
+ 170
1215
+ ],
1216
+ lightskyblue: [
1217
+ 135,
1218
+ 206,
1219
+ 250
1220
+ ],
1221
+ lightslategray: [
1222
+ 119,
1223
+ 136,
1224
+ 153
1225
+ ],
1226
+ lightslategrey: [
1227
+ 119,
1228
+ 136,
1229
+ 153
1230
+ ],
1231
+ lightsteelblue: [
1232
+ 176,
1233
+ 196,
1234
+ 222
1235
+ ],
1236
+ lightyellow: [
1237
+ 255,
1238
+ 255,
1239
+ 224
1240
+ ],
1241
+ lime: [
1242
+ 0,
1243
+ 255,
1244
+ 0
1245
+ ],
1246
+ limegreen: [
1247
+ 50,
1248
+ 205,
1249
+ 50
1250
+ ],
1251
+ linen: [
1252
+ 250,
1253
+ 240,
1254
+ 230
1255
+ ],
1256
+ magenta: [
1257
+ 255,
1258
+ 0,
1259
+ 255
1260
+ ],
1261
+ maroon: [
1262
+ 128,
1263
+ 0,
1264
+ 0
1265
+ ],
1266
+ mediumaquamarine: [
1267
+ 102,
1268
+ 205,
1269
+ 170
1270
+ ],
1271
+ mediumblue: [
1272
+ 0,
1273
+ 0,
1274
+ 205
1275
+ ],
1276
+ mediumorchid: [
1277
+ 186,
1278
+ 85,
1279
+ 211
1280
+ ],
1281
+ mediumpurple: [
1282
+ 147,
1283
+ 112,
1284
+ 219
1285
+ ],
1286
+ mediumseagreen: [
1287
+ 60,
1288
+ 179,
1289
+ 113
1290
+ ],
1291
+ mediumslateblue: [
1292
+ 123,
1293
+ 104,
1294
+ 238
1295
+ ],
1296
+ mediumspringgreen: [
1297
+ 0,
1298
+ 250,
1299
+ 154
1300
+ ],
1301
+ mediumturquoise: [
1302
+ 72,
1303
+ 209,
1304
+ 204
1305
+ ],
1306
+ mediumvioletred: [
1307
+ 199,
1308
+ 21,
1309
+ 133
1310
+ ],
1311
+ midnightblue: [
1312
+ 25,
1313
+ 25,
1314
+ 112
1315
+ ],
1316
+ mintcream: [
1317
+ 245,
1318
+ 255,
1319
+ 250
1320
+ ],
1321
+ mistyrose: [
1322
+ 255,
1323
+ 228,
1324
+ 225
1325
+ ],
1326
+ moccasin: [
1327
+ 255,
1328
+ 228,
1329
+ 181
1330
+ ],
1331
+ navajowhite: [
1332
+ 255,
1333
+ 222,
1334
+ 173
1335
+ ],
1336
+ navy: [
1337
+ 0,
1338
+ 0,
1339
+ 128
1340
+ ],
1341
+ oldlace: [
1342
+ 253,
1343
+ 245,
1344
+ 230
1345
+ ],
1346
+ olive: [
1347
+ 128,
1348
+ 128,
1349
+ 0
1350
+ ],
1351
+ olivedrab: [
1352
+ 107,
1353
+ 142,
1354
+ 35
1355
+ ],
1356
+ orange: [
1357
+ 255,
1358
+ 165,
1359
+ 0
1360
+ ],
1361
+ orangered: [
1362
+ 255,
1363
+ 69,
1364
+ 0
1365
+ ],
1366
+ orchid: [
1367
+ 218,
1368
+ 112,
1369
+ 214
1370
+ ],
1371
+ palegoldenrod: [
1372
+ 238,
1373
+ 232,
1374
+ 170
1375
+ ],
1376
+ palegreen: [
1377
+ 152,
1378
+ 251,
1379
+ 152
1380
+ ],
1381
+ paleturquoise: [
1382
+ 175,
1383
+ 238,
1384
+ 238
1385
+ ],
1386
+ palevioletred: [
1387
+ 219,
1388
+ 112,
1389
+ 147
1390
+ ],
1391
+ papayawhip: [
1392
+ 255,
1393
+ 239,
1394
+ 213
1395
+ ],
1396
+ peachpuff: [
1397
+ 255,
1398
+ 218,
1399
+ 185
1400
+ ],
1401
+ peru: [
1402
+ 205,
1403
+ 133,
1404
+ 63
1405
+ ],
1406
+ pink: [
1407
+ 255,
1408
+ 192,
1409
+ 203
1410
+ ],
1411
+ plum: [
1412
+ 221,
1413
+ 160,
1414
+ 221
1415
+ ],
1416
+ powderblue: [
1417
+ 176,
1418
+ 224,
1419
+ 230
1420
+ ],
1421
+ purple: [
1422
+ 128,
1423
+ 0,
1424
+ 128
1425
+ ],
1426
+ rebeccapurple: [
1427
+ 102,
1428
+ 51,
1429
+ 153
1430
+ ],
1431
+ red: [
1432
+ 255,
1433
+ 0,
1434
+ 0
1435
+ ],
1436
+ rosybrown: [
1437
+ 188,
1438
+ 143,
1439
+ 143
1440
+ ],
1441
+ royalblue: [
1442
+ 65,
1443
+ 105,
1444
+ 225
1445
+ ],
1446
+ saddlebrown: [
1447
+ 139,
1448
+ 69,
1449
+ 19
1450
+ ],
1451
+ salmon: [
1452
+ 250,
1453
+ 128,
1454
+ 114
1455
+ ],
1456
+ sandybrown: [
1457
+ 244,
1458
+ 164,
1459
+ 96
1460
+ ],
1461
+ seagreen: [
1462
+ 46,
1463
+ 139,
1464
+ 87
1465
+ ],
1466
+ seashell: [
1467
+ 255,
1468
+ 245,
1469
+ 238
1470
+ ],
1471
+ sienna: [
1472
+ 160,
1473
+ 82,
1474
+ 45
1475
+ ],
1476
+ silver: [
1477
+ 192,
1478
+ 192,
1479
+ 192
1480
+ ],
1481
+ skyblue: [
1482
+ 135,
1483
+ 206,
1484
+ 235
1485
+ ],
1486
+ slateblue: [
1487
+ 106,
1488
+ 90,
1489
+ 205
1490
+ ],
1491
+ slategray: [
1492
+ 112,
1493
+ 128,
1494
+ 144
1495
+ ],
1496
+ slategrey: [
1497
+ 112,
1498
+ 128,
1499
+ 144
1500
+ ],
1501
+ snow: [
1502
+ 255,
1503
+ 250,
1504
+ 250
1505
+ ],
1506
+ springgreen: [
1507
+ 0,
1508
+ 255,
1509
+ 127
1510
+ ],
1511
+ steelblue: [
1512
+ 70,
1513
+ 130,
1514
+ 180
1515
+ ],
1516
+ tan: [
1517
+ 210,
1518
+ 180,
1519
+ 140
1520
+ ],
1521
+ teal: [
1522
+ 0,
1523
+ 128,
1524
+ 128
1525
+ ],
1526
+ thistle: [
1527
+ 216,
1528
+ 191,
1529
+ 216
1530
+ ],
1531
+ tomato: [
1532
+ 255,
1533
+ 99,
1534
+ 71
1535
+ ],
1536
+ turquoise: [
1537
+ 64,
1538
+ 224,
1539
+ 208
1540
+ ],
1541
+ violet: [
1542
+ 238,
1543
+ 130,
1544
+ 238
1545
+ ],
1546
+ wheat: [
1547
+ 245,
1548
+ 222,
1549
+ 179
1550
+ ],
1551
+ white: [
1552
+ 255,
1553
+ 255,
1554
+ 255
1555
+ ],
1556
+ whitesmoke: [
1557
+ 245,
1558
+ 245,
1559
+ 245
1560
+ ],
1561
+ yellow: [
1562
+ 255,
1563
+ 255,
1564
+ 0
1565
+ ],
1566
+ yellowgreen: [
1567
+ 154,
1568
+ 205,
1569
+ 50
1570
+ ]
1571
+ };
1572
+ // src/color/isLiteralColor.ts
1573
+ /**
1574
+ * Tell literal CSS colors from palette references.
1575
+ *
1576
+ * Literal means the string is a color by itself: `#hex`, `rgb(...)` /
1577
+ * `rgba(...)`, or a CSS named color (case-insensitive) — as opposed to
1578
+ * theme references like `'brand-l2'`.
1579
+ *
1580
+ * @param s - the color string to classify
1581
+ * @returns `true` when `s` is directly usable as a CSS color value
1582
+ */
1583
+ function isLiteralColor(s) {
1584
+ return s.startsWith("#") || s.startsWith("rgb") || s.toLowerCase() in NAMED_COLORS;
1585
+ }
1586
+ // src/color/toRgb.ts
1587
+ /**
1588
+ * Resolve any literal CSS color string to an sRGB triple.
1589
+ *
1590
+ * Dispatches on the format: `#hex` → {@link hexToRgb}, `rgb(...)` →
1591
+ * {@link parseRgbString}, anything else is looked up among the CSS named
1592
+ * colors (case-insensitive). Theme references are rejected.
1593
+ *
1594
+ * @param color - a literal color string
1595
+ * @returns the sRGB triple
1596
+ * @throws when `color` is not a literal color (e.g. a palette reference)
1597
+ */
1598
+ function toRgb(color) {
1599
+ if (!isLiteralColor(color)) throw new Error("unknown literal color format: " + color);
1600
+ if (color.startsWith("#")) return hexToRgb(color);
1601
+ if (color.startsWith("rgb")) return parseRgbString(color);
1602
+ return NAMED_COLORS[color.toLowerCase()];
1603
+ }
1604
+ // src/color/rgbToHsl.ts
1605
+ /**
1606
+ * Convert an sRGB triple to HSL.
1607
+ *
1608
+ * @param rgb - the color (channels 0-255)
1609
+ * @returns `[hue 0-360, saturation 0-100, lightness 0-100]` (fractional)
1610
+ */
1611
+ function rgbToHsl([r, g, b]) {
1612
+ r /= 255;
1613
+ g /= 255;
1614
+ b /= 255;
1615
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
1616
+ let h = 0, s;
1617
+ const l = (max + min) / 2;
1618
+ if (max === min) h = s = 0;
1619
+ else {
1620
+ const d = max - min;
1621
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
1622
+ switch (max) {
1623
+ case r:
1624
+ h = (g - b) / d + (g < b ? 6 : 0);
1625
+ break;
1626
+ case g:
1627
+ h = (b - r) / d + 2;
1628
+ break;
1629
+ case b: h = (r - g) / d + 4;
1630
+ }
1631
+ h /= 6;
1632
+ }
1633
+ return [
1634
+ h * 360,
1635
+ s * 100,
1636
+ l * 100
1637
+ ];
1638
+ }
1639
+ // src/color/hslToRgb.ts
1640
+ /**
1641
+ * Convert an HSL triple to a fractional sRGB triple.
1642
+ *
1643
+ * @param hsl - `[hue 0-360, saturation 0-100, lightness 0-100]`
1644
+ * @returns fractional sRGB channels (0-255, not rounded)
1645
+ */
1646
+ function hslToRgb([h, s, l]) {
1647
+ h /= 360;
1648
+ s /= 100;
1649
+ l /= 100;
1650
+ let r, g, b;
1651
+ if (s === 0) r = g = b = l;
1652
+ else {
1653
+ const hue2rgb = (p, q, t) => {
1654
+ if (t < 0) t += 1;
1655
+ if (t > 1) t -= 1;
1656
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
1657
+ if (t < 1 / 2) return q;
1658
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
1659
+ return p;
1660
+ };
1661
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
1662
+ const p = 2 * l - q;
1663
+ r = hue2rgb(p, q, h + 1 / 3);
1664
+ g = hue2rgb(p, q, h);
1665
+ b = hue2rgb(p, q, h - 1 / 3);
1666
+ }
1667
+ return [
1668
+ r * 255,
1669
+ g * 255,
1670
+ b * 255
1671
+ ];
1672
+ }
1673
+ // src/color/withLightnessHsl.ts
1674
+ /**
1675
+ * Rebuild a color with a new HSL lightness, keeping hue and saturation.
1676
+ *
1677
+ * @param rgb - the source color (sRGB triple)
1678
+ * @param l - the target lightness, percent 0-100
1679
+ * @returns the recolored sRGB triple (fractional channels)
1680
+ */
1681
+ function withLightnessHsl(rgb, l) {
1682
+ const [h, s] = rgbToHsl(rgb);
1683
+ return hslToRgb([
1684
+ h,
1685
+ s,
1686
+ l
1687
+ ]);
1688
+ }
1689
+ // src/color/lightnessOfHsl.ts
1690
+ /**
1691
+ * Read the HSL lightness (percent, 0-100) of an sRGB color.
1692
+ *
1693
+ * @param rgb - the color to measure (sRGB triple)
1694
+ * @returns the lightness percentage (fractional)
1695
+ */
1696
+ function lightnessOfHsl(rgb) {
1697
+ return rgbToHsl(rgb)[2];
1698
+ }
1699
+ // src/color/srgbToLinear.ts
1700
+ /**
1701
+ * Decode one gamma-encoded sRGB channel to linear light.
1702
+ *
1703
+ * @param v - the sRGB channel, 0-255
1704
+ * @returns the linear-light value (0-1)
1705
+ */
1706
+ function srgbToLinear(v) {
1707
+ v /= 255;
1708
+ return v <= .04045 ? v / 12.92 : ((v + .055) / 1.055) ** 2.4;
1709
+ }
1710
+ // src/color/linearToSrgb.ts
1711
+ /**
1712
+ * Gamma-encode one linear-light channel to sRGB.
1713
+ *
1714
+ * @param v - the linear channel, nominally 0-1
1715
+ * @returns the sRGB channel, 0-255, clamped to the gamut
1716
+ */
1717
+ function linearToSrgb(v) {
1718
+ const s = v <= .0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - .055;
1719
+ return Math.min(255, Math.max(0, s * 255));
1720
+ }
1721
+ // src/color/linearRgbToOklab.ts
1722
+ /**
1723
+ * Convert a linear-light sRGB triple to OKLab.
1724
+ *
1725
+ * Björn Ottosson's LMS-based transform; the input must be linear (run
1726
+ * {@link srgbToLinear} over gamma-encoded channels first).
1727
+ *
1728
+ * @param rgb - linear sRGB channels (0-1)
1729
+ * @returns `[L, a, b]` OKLab coordinates
1730
+ */
1731
+ function linearRgbToOklab([r, g, b]) {
1732
+ const l = .4122214708 * r + .5363325363 * g + .0514459929 * b;
1733
+ const m = .2119034982 * r + .6806995451 * g + .1073969566 * b;
1734
+ const s = .0883024619 * r + .2817188376 * g + .6299787005 * b;
1735
+ const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
1736
+ return [
1737
+ .2104542553 * l_ + .793617785 * m_ - .0040720468 * s_,
1738
+ 1.9779984951 * l_ - 2.428592205 * m_ + .4505937099 * s_,
1739
+ .0259040371 * l_ + .7827717662 * m_ - .808675766 * s_
1740
+ ];
1741
+ }
1742
+ // src/color/oklabToLinearRgb.ts
1743
+ /**
1744
+ * Convert OKLab coordinates back to a linear-light sRGB triple.
1745
+ *
1746
+ * Inverse of {@link linearRgbToOklab}; run {@link linearToSrgb} over the
1747
+ * result to get gamma-encoded channels.
1748
+ *
1749
+ * @param L - OKLab lightness
1750
+ * @param a - green-red opponent channel
1751
+ * @param b - blue-yellow opponent channel
1752
+ * @returns linear sRGB channels (0-1)
1753
+ */
1754
+ function oklabToLinearRgb([L, a, b]) {
1755
+ const l_ = L + .3963377774 * a + .2158037573 * b;
1756
+ const m_ = L - .1055613458 * a - .0638541728 * b;
1757
+ const s_ = L - .0894841775 * a - 1.291485548 * b;
1758
+ const l = l_ ** 3, m = m_ ** 3, s = s_ ** 3;
1759
+ return [
1760
+ 4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
1761
+ -1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
1762
+ -.0041960863 * l - .7034186147 * m + 1.707614701 * s
1763
+ ];
1764
+ }
1765
+ // src/color/rgbToOklch.ts
1766
+ /**
1767
+ * Convert an sRGB triple to OKLCH (via linear sRGB + OKLab).
1768
+ *
1769
+ * @param rgb - the color (channels 0-255)
1770
+ * @returns `[L 0-100, C, H degrees]` (fractional)
1771
+ */
1772
+ function rgbToOklch(rgb) {
1773
+ const [L, a, b] = linearRgbToOklab(rgb.map(srgbToLinear));
1774
+ return [
1775
+ L * 100,
1776
+ Math.sqrt(a * a + b * b),
1777
+ Math.atan2(b, a) * (180 / Math.PI)
1778
+ ];
1779
+ }
1780
+ // src/color/oklchToRgb.ts
1781
+ /**
1782
+ * Convert OKLCH coordinates to a gamma-encoded sRGB triple.
1783
+ *
1784
+ * @param L100 - lightness in percent (0-100)
1785
+ * @param C - chroma
1786
+ * @param H - hue in degrees
1787
+ * @returns the sRGB triple (channels 0-255, fractional)
1788
+ */
1789
+ function oklchToRgb([L100, C, H]) {
1790
+ const hRad = H * (Math.PI / 180);
1791
+ return oklabToLinearRgb([
1792
+ L100 / 100,
1793
+ C * Math.cos(hRad),
1794
+ C * Math.sin(hRad)
1795
+ ]).map(linearToSrgb);
1796
+ }
1797
+ // src/color/withLightnessOklch.ts
1798
+ /**
1799
+ * Rebuild a color with a new OKLCH lightness, keeping chroma and hue.
1800
+ *
1801
+ * @param rgb - the source color (sRGB triple)
1802
+ * @param l - the target lightness, percent 0-100
1803
+ * @returns the recolored sRGB triple (fractional channels)
1804
+ */
1805
+ function withLightnessOklch(rgb, l) {
1806
+ const [, C, H] = rgbToOklch(rgb);
1807
+ return oklchToRgb([
1808
+ l,
1809
+ C,
1810
+ H
1811
+ ]);
1812
+ }
1813
+ // src/color/lightnessOfOklch.ts
1814
+ /**
1815
+ * Read the OKLCH lightness (percent, 0-100) of an sRGB color.
1816
+ *
1817
+ * @param rgb - the color to measure (sRGB triple)
1818
+ * @returns the OKLCH L dimension (fractional)
1819
+ */
1820
+ function lightnessOfOklch(rgb) {
1821
+ return rgbToOklch(rgb)[0];
1822
+ }
1823
+ // src/color/spaces.ts
1824
+ /**
1825
+ * The color spaces the ramp math (`lighten` / `darken`) can run in.
1826
+ *
1827
+ * `oklch` is perceptually uniform — a ramp looks evenly spaced regardless
1828
+ * of hue; `hsl` is the legacy (cheaper) path.
1829
+ */
1830
+ const SPACES = {
1831
+ hsl: {
1832
+ lightnessOf: lightnessOfHsl,
1833
+ withLightness: withLightnessHsl
1834
+ },
1835
+ oklch: {
1836
+ lightnessOf: lightnessOfOklch,
1837
+ withLightness: withLightnessOklch
1838
+ }
1839
+ };
1840
+ // src/color/lighten.ts
1841
+ /**
1842
+ * Lighten a color by `step` steps of a `steps`-step ramp.
1843
+ *
1844
+ * Scales the color's lightness up toward 100 percent proportionally
1845
+ * (`l -> l + (100 - l) * (step / steps)`) in the given color space;
1846
+ * `oklch` keeps ramps perceptually even, `hsl` is the legacy path.
1847
+ *
1848
+ * @param rgb - the color to lighten (sRGB triple)
1849
+ * @param step - how many steps up the ramp (1-based)
1850
+ * @param steps - the total number of ramp steps
1851
+ * @param space - the color space the lightness math runs in
1852
+ * @returns the lightened color (fractional channels)
1853
+ */
1854
+ function lighten(rgb, step, steps, space = "hsl") {
1855
+ const { lightnessOf, withLightness } = SPACES[space];
1856
+ const l0 = lightnessOf(rgb);
1857
+ return withLightness(rgb, l0 + (100 - l0) * (step / steps));
1858
+ }
1859
+ // src/color/darken.ts
1860
+ /**
1861
+ * Darken a color by `step` steps of a `steps`-step ramp.
1862
+ *
1863
+ * Scales the color's lightness down proportionally
1864
+ * (`l -> l * (1 - step / steps)`) in the given color space; `oklch` keeps
1865
+ * ramps perceptually even, `hsl` is the legacy path.
1866
+ *
1867
+ * @param rgb - the color to darken (sRGB triple)
1868
+ * @param step - how many steps down the ramp (1-based)
1869
+ * @param steps - the total number of ramp steps
1870
+ * @param space - the color space the lightness math runs in
1871
+ * @returns the darkened color (fractional channels)
1872
+ */
1873
+ function darken(rgb, step, steps, space = "hsl") {
1874
+ const { lightnessOf, withLightness } = SPACES[space];
1875
+ return withLightness(rgb, lightnessOf(rgb) * (1 - step / steps));
1876
+ }
1877
+ // src/color/blend.ts
1878
+ /**
1879
+ * Mix two sRGB colors by a depth percentage.
1880
+ *
1881
+ * Linear interpolation per channel: `depthPercent` of 0 returns `rgb1`
1882
+ * untouched, 100 returns `rgb2`; the channels stay fractional (not
1883
+ * rounded).
1884
+ *
1885
+ * @param rgb1 - the base color (sRGB triple, channels 0-255)
1886
+ * @param rgb2 - the color blended in
1887
+ * @param depthPercent - blend weight of `rgb2`, 0-100
1888
+ * @returns the mixed color as a fractional sRGB triple
1889
+ */
1890
+ function blend(rgb1, rgb2, depthPercent) {
1891
+ const t = depthPercent / 100;
1892
+ return [
1893
+ 0,
1894
+ 1,
1895
+ 2
1896
+ ].map((i) => rgb1[i] * (1 - t) + rgb2[i] * t);
1897
+ }
1898
+ // src/props/castAnyPropToBoolean.ts
1899
+ /**
1900
+ * Coerces an arbitrary prop value to a boolean the way presence-classes
1901
+ * expect it: an empty string means "present" (`true`), an empty array means
1902
+ * "absent" (`false`), anything else falls through to the default truthiness
1903
+ * rules.
1904
+ * @param value - the prop value
1905
+ * @returns the boolean presence of the value
1906
+ */
1907
+ function castAnyPropToBoolean(value) {
1908
+ if (typeof value === "string" && value === "") return true;
1909
+ if (typeof value === "object" && value instanceof Array && !value.length) return false;
1910
+ return !!value;
1911
+ }
1912
+ // src/props/namesToClassNames.ts
1913
+ /**
1914
+ * Builds a `{ [className]: true }` record from a list of state names,
1915
+ * keeping only the names whose prop value is "on" (defined, not `false`
1916
+ * and not a function).
1917
+ * @param names - space-separated string, list, or map of state names
1918
+ * @param props - the props to test each name against
1919
+ * @param className - prefix joined with `_` to each name; empty = bare name
1920
+ * @param debug - log the inputs before computing
1921
+ * @returns record of `className_name -> true` for the active names
1922
+ */
1923
+ function namesToClassNames(names, props = {}, className = "state", debug = false) {
1924
+ debug && console.log("names to classname", names, props, className);
1925
+ const out = {};
1926
+ let list = [];
1927
+ if (typeof names === "object") list = names instanceof Array ? names : Object.keys(names || []);
1928
+ else list = names.split(" ");
1929
+ list.forEach((item) => {
1930
+ const cn = className ? `${className}_${item}` : item;
1931
+ if (props[item] !== void 0 && props[item] !== false && typeof props[item] !== "function") out[cn] = true;
1932
+ });
1933
+ return out;
1934
+ }
1935
+ // src/props/propValueToClass.ts
1936
+ /**
1937
+ * Converts a prop value to a class via a value -> class alias record: the
1938
+ * alias may be a single class name or a list of class names.
1939
+ * @param propValue - the prop's value token
1940
+ * @param values - record of value token -> class alias (string or string[])
1941
+ * @returns `{ className: true }` for the aliased class(es), `{}` when the
1942
+ * value has no alias or the alias is neither a string nor a list
1943
+ */
1944
+ function propValueToClass(propValue, values) {
1945
+ if (!values[propValue]) return {};
1946
+ if (typeof values[propValue] === "string") return { [values[propValue]]: true };
1947
+ if (typeof values[propValue] === "object" && values[propValue] instanceof Array) return values[propValue].reduce((acc, cur) => ({
1948
+ ...acc,
1949
+ [cur]: true
1950
+ }), {});
1951
+ return {};
1952
+ }
1953
+ // src/props/propValueToClasses.ts
1954
+ /**
1955
+ * Converts a prop value to class names via a value -> class alias record:
1956
+ * the alias may be a single class name or a list of class names.
1957
+ * @param propValue - the prop's value token
1958
+ * @param values - record of value token -> class alias (string or string[])
1959
+ * @returns the aliased class name list, `[]` when the value has no alias or
1960
+ * the alias is neither a string nor a list
1961
+ */
1962
+ function propValueToClasses(propValue, values) {
1963
+ if (!values[propValue]) return [];
1964
+ if (typeof values[propValue] === "string") return [values[propValue]];
1965
+ if (typeof values[propValue] === "object" && values[propValue] instanceof Array) return values[propValue];
1966
+ return [];
1967
+ }
1968
+ // src/props/propsToCssModuleClass.ts
1969
+ /**
1970
+ * Converts prop names and values to css-module classes, returned as a
1971
+ * `{ [className]: boolean }` record (a `false` entry means the prop is off
1972
+ * but the class slot is still reported).
1973
+ *
1974
+ * A picked entry is either a bare prop name - the prop's own class is keyed
1975
+ * by the css module and the value's tokens add their own module classes - or
1976
+ * a `[propName, modifiers]` tuple that maps the value's tokens onto modifier
1977
+ * classes via {@link propValueToClass}.
1978
+ * @param props - the instance props
1979
+ * @param picked - the props to map (bare names or `[name, modifiers]` tuples)
1980
+ * @param cssModule - the css-module class map
1981
+ * @returns record of class name -> on/off flag
1982
+ */
1983
+ function propsToCssModuleClass(props, picked, cssModule) {
1984
+ let out = {};
1985
+ function getRootClassBoolean(field) {
1986
+ let out = void 0;
1987
+ if (props[field] !== void 0) out = castAnyPropToBoolean(props[field]);
1988
+ return out;
1989
+ }
1990
+ picked.forEach((pickedProp) => {
1991
+ if (typeof pickedProp === "string") {
1992
+ const cn = cssModule[pickedProp];
1993
+ const value = props[pickedProp];
1994
+ if (value !== void 0 && cn) {
1995
+ if (typeof value === "boolean") out[cn] = value;
1996
+ if (typeof value === "string" || typeof value === "number" || typeof value === "object" && value instanceof Array) {
1997
+ out[cn] = true;
1998
+ let arr = [];
1999
+ if (typeof value === "string" || typeof value === "number") arr = value.toString().split(" ");
2000
+ if (value instanceof Array) arr = value;
2001
+ arr.forEach((val) => {
2002
+ const modifierName = cssModule[val];
2003
+ if (modifierName) out[modifierName] = true;
2004
+ });
2005
+ }
2006
+ }
2007
+ }
2008
+ if (typeof pickedProp === "object" && pickedProp instanceof Array && pickedProp.length === 2) {
2009
+ const _pickedProp = pickedProp[0];
2010
+ const _pickedPropValue = pickedProp[1];
2011
+ const _pickedPropClassName = cssModule[_pickedProp];
2012
+ const value = getRootClassBoolean(_pickedProp);
2013
+ if (typeof props[_pickedProp] === "string" || typeof props[_pickedProp] === "number" || typeof props[_pickedProp] === "boolean" || typeof props[_pickedProp] === "object" && props[_pickedProp] instanceof Array) {
2014
+ let classValues = [];
2015
+ if (props[_pickedProp] instanceof Array && props[_pickedProp].length) classValues = props[_pickedProp];
2016
+ if (typeof props[_pickedProp] === "string" || typeof props[_pickedProp] === "number") classValues = String(props[_pickedProp]).split(" ");
2017
+ if (typeof props[_pickedProp] === "boolean" && props[_pickedProp] || props[_pickedProp] === "") classValues = ["true"];
2018
+ let outClassValues = {};
2019
+ classValues.forEach((val) => {
2020
+ if (val !== void 0 && val.trim()) outClassValues = {
2021
+ ...outClassValues,
2022
+ ...propValueToClass(val, _pickedPropValue)
2023
+ };
2024
+ });
2025
+ out = {
2026
+ ...out,
2027
+ ...outClassValues
2028
+ };
2029
+ }
2030
+ if (_pickedPropClassName) out = {
2031
+ ...out,
2032
+ [_pickedPropClassName]: value || false
2033
+ };
2034
+ }
2035
+ });
2036
+ return out;
2037
+ }
2038
+ // src/props/propsToCssModuleClassNext.ts
2039
+ /**
2040
+ * Converts prop names and values to a flat list of css-module classes -
2041
+ * the array form of {@link propsToCssModuleClass}: same mapping rules, but
2042
+ * only the "on" classes are collected (no `false` entries) and an extra
2043
+ * class can be prepended via `options.extraClass`.
2044
+ * @param props - the instance props
2045
+ * @param picked - the props to map (bare names or `[name, modifiers]` tuples)
2046
+ * @param cssModule - the css-module class map
2047
+ * @param options - `extraClass` is prepended to the result when given
2048
+ * @returns the resolved class name list
2049
+ */
2050
+ function propsToCssModuleClassNext(props, picked, cssModule, options) {
2051
+ let out = [];
2052
+ const { extraClass = void 0 } = options || {};
2053
+ if (extraClass) out.push(extraClass);
2054
+ function getRootClassBoolean(field) {
2055
+ let out = void 0;
2056
+ if (props[field] !== void 0) out = castAnyPropToBoolean(props[field]);
2057
+ return out;
2058
+ }
2059
+ picked.forEach((pickedProp) => {
2060
+ if (typeof pickedProp === "string") {
2061
+ const cn = cssModule[pickedProp];
2062
+ const value = props[pickedProp];
2063
+ if (value !== void 0 && cn) {
2064
+ if (typeof value === "boolean" && value) out.push(cn);
2065
+ if (typeof value === "string" || typeof value === "number" || typeof value === "object" && value instanceof Array) {
2066
+ out.push(cn);
2067
+ let arr = [];
2068
+ if (typeof value === "string" || typeof value === "number") arr = value.toString().split(" ");
2069
+ if (value instanceof Array) arr = value;
2070
+ arr.forEach((val) => {
2071
+ const modifierName = cssModule[val];
2072
+ if (modifierName) out.push(modifierName);
2073
+ });
2074
+ }
2075
+ }
2076
+ }
2077
+ if (typeof pickedProp === "object" && pickedProp instanceof Array && pickedProp.length === 2) {
2078
+ const _pickedProp = pickedProp[0];
2079
+ const _pickedPropValue = pickedProp[1];
2080
+ const _pickedPropClassName = cssModule[_pickedProp];
2081
+ const value = getRootClassBoolean(_pickedProp);
2082
+ if (typeof props[_pickedProp] === "string" || typeof props[_pickedProp] === "number" || typeof props[_pickedProp] === "boolean" || typeof props[_pickedProp] === "object" && props[_pickedProp] instanceof Array) {
2083
+ let classValues = [];
2084
+ if (props[_pickedProp] instanceof Array && props[_pickedProp].length) classValues = props[_pickedProp];
2085
+ if (typeof props[_pickedProp] === "string" || typeof props[_pickedProp] === "number") classValues = String(props[_pickedProp]).split(" ");
2086
+ if (typeof props[_pickedProp] === "boolean" && props[_pickedProp] || props[_pickedProp] === "") classValues = ["true"];
2087
+ let outClassValues = [];
2088
+ classValues.forEach((val) => {
2089
+ if (val !== void 0 && val.trim()) outClassValues = [...outClassValues, ...propValueToClasses(val, _pickedPropValue)];
2090
+ });
2091
+ out = [...out, ...outClassValues];
2092
+ }
2093
+ if (_pickedPropClassName && !!value) out.push(_pickedPropClassName);
2094
+ }
2095
+ });
2096
+ return out;
2097
+ }
2098
+ // src/browser-check.ts
2099
+ const isBrowser = typeof window !== "undefined";
2100
+ function safetyWindow() {
2101
+ return window && typeof window !== "undefined" ? window : {};
2102
+ }
2103
+ function safetyDocument() {
2104
+ return typeof document !== "undefined" ? document : {};
2105
+ }
2106
+ // src/container/record-container.ts
2107
+ var RecordContainer = class {
2108
+ records;
2109
+ counter = 0;
2110
+ options;
2111
+ constructor(options = {}) {
2112
+ this.records = {};
2113
+ this.options = options;
2114
+ }
2115
+ /** Returns the item with the highest remaining ID, or undefined when empty. */
2116
+ get last() {
2117
+ let lastId = -1;
2118
+ for (const key in this.records) if (Object.hasOwn(this.records, key)) lastId = Math.max(lastId, Number(key));
2119
+ if (lastId === -1) return void 0;
2120
+ return this.records[lastId];
2121
+ }
2122
+ /** Returns a shallow snapshot; item objects retain their original references. */
2123
+ get raw() {
2124
+ return { ...this.records };
2125
+ }
2126
+ get items() {
2127
+ return Object.values(this.records);
2128
+ }
2129
+ get length() {
2130
+ return Object.keys(this.records).length;
2131
+ }
2132
+ clear() {
2133
+ for (const i in this.records) delete this.records[i];
2134
+ }
2135
+ /** Validates and transforms an item before allocating its ID; returns -1 on rejection. */
2136
+ add(item) {
2137
+ if (this.options.onBeforeChange) {
2138
+ if (!this.options.onBeforeChange(item)) return -1;
2139
+ }
2140
+ const value = this.options.onChange ? this.options.onChange(item) : item;
2141
+ const id = this.counter++;
2142
+ this.records[id] = value;
2143
+ return id;
2144
+ }
2145
+ remove(id) {
2146
+ delete this.records[id];
2147
+ }
2148
+ getItemById(id) {
2149
+ return this.records[id];
2150
+ }
2151
+ };
2152
+ // src/dom/getClientHeight.ts
2153
+ function getClientHeight() {
2154
+ if (isBrowser) return window.innerHeight;
2155
+ else return 0;
2156
+ }
2157
+ // src/dom/getClientWidth.ts
2158
+ function getClientWidth() {
2159
+ if (isBrowser) return window.innerWidth;
2160
+ else return 0;
2161
+ }
2162
+ export { NAMED_COLORS, RecordContainer, SPACES, arrayInsertAtIndex, arrayIsEqual, arrayOmit, arrayOmitArray, arrayPickFromItemOffset, arrayPickNext, arrayPickPrev, arrayToNumberArray, blend, castAnyPropToBoolean, clamp, darken, decimalAdjust, exponentialToNumber, extractFileDir, extractFileName, findFrameworkInstance, genRandomString, getClientHeight, getClientWidth, getFloatDigitsCount, getItemByOverflowIndex, getLastItemFromArray, hexToRgb, hslToRgb, hyphenate, isArray, isBrowser, isFloat, isFunction, isLiteralColor, isNumberish, isObject, isString, isSymbol, isValidNumber, kebabize, lighten, lightnessOfHsl, lightnessOfOklch, linearRgbToOklab, linearToSrgb, mergeCssModulesStyles, namesToClassNames, newErrorAppExists, newErrorAppNotFound, newErrorForSetupCall, newErrorUseAppCall, newFrameworkError, notUndefined, numberCast, objectMerge, objectOmitKeys, objectPickKeys, objectToCss, oklabToLinearRgb, oklchToRgb, parseCssTime, parseQueryString, parseRgbString, parseUnits, propValueToClass, propValueToClasses, propsToCssModuleClass, propsToCssModuleClassNext, removeVowels, rgbToHsl, rgbToOklch, safetyDocument, safetyWindow, sha256hex, splitString, srgbToLinear, stringToFirstLetters, toCamelCase, toKebabCase, toPascalCase, toRgb, toUnique, toUnits, tryToUnits, withLightnessHsl, withLightnessOklch };
2163
+
2164
+ //# sourceMappingURL=index.js.map