nuvox 0.1.4 → 0.1.6

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.
@@ -0,0 +1,2457 @@
1
+ // src/tokens/contract.ts
2
+ function defineTheme(tokens) {
3
+ return tokens;
4
+ }
5
+ var TOKEN_CATEGORIES = [
6
+ "meta",
7
+ "color",
8
+ "radius",
9
+ "spacing",
10
+ "typography",
11
+ "shadow",
12
+ "elevation",
13
+ "motion",
14
+ "border",
15
+ "effects"
16
+ ];
17
+ var REQUIRED_TOKEN_PATHS = [
18
+ "meta.name",
19
+ "meta.label",
20
+ "meta.description",
21
+ ...["0", "50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"].map((k) => `color.neutral.${k}`),
22
+ ...["success", "danger", "warning", "info"].flatMap(
23
+ (c) => ["light", "subtle", "base", "dark", "deeper"].map((k) => `color.${c}.${k}`)
24
+ ),
25
+ "color.background",
26
+ "color.surface",
27
+ "color.surfaceRaised",
28
+ "color.border",
29
+ "color.borderFocus",
30
+ "color.text",
31
+ "color.textMuted",
32
+ "color.textInverse",
33
+ "radius.sm",
34
+ "radius.md",
35
+ "radius.lg",
36
+ "radius.xl",
37
+ "radius.2xl",
38
+ "radius.full",
39
+ "spacing.xs",
40
+ "spacing.sm",
41
+ "spacing.md",
42
+ "spacing.lg",
43
+ "spacing.xl",
44
+ "spacing.2xl",
45
+ "typography.fontSans",
46
+ "typography.fontMono",
47
+ "typography.sizeXs",
48
+ "typography.sizeSm",
49
+ "typography.sizeMd",
50
+ "typography.sizeLg",
51
+ "typography.sizeXl",
52
+ "typography.weightNormal",
53
+ "typography.weightMedium",
54
+ "typography.weightBold",
55
+ "typography.lineHeightTight",
56
+ "typography.lineHeightNormal",
57
+ "shadow.xs",
58
+ "shadow.sm",
59
+ "shadow.md",
60
+ "shadow.lg",
61
+ "shadow.xl",
62
+ "shadow.2xl",
63
+ "shadow.inner",
64
+ "elevation.dropdown",
65
+ "elevation.popover",
66
+ "elevation.modal",
67
+ "elevation.toast",
68
+ "elevation.tooltip",
69
+ "motion.durationFast",
70
+ "motion.durationNormal",
71
+ "motion.durationSlow",
72
+ "motion.easeStandard",
73
+ "motion.easeEmphasized",
74
+ "motion.durationInstant",
75
+ "border.widthThin",
76
+ "border.widthMedium",
77
+ "border.widthThick",
78
+ "border.style",
79
+ "effects.backdropBlur"
80
+ ];
81
+ function getAtPath(obj, path) {
82
+ return path.split(".").reduce((acc, key) => {
83
+ if (acc === null || typeof acc !== "object") return void 0;
84
+ return acc[key];
85
+ }, obj);
86
+ }
87
+ function findMissingTokenPaths(theme) {
88
+ return REQUIRED_TOKEN_PATHS.filter((path) => {
89
+ const value = getAtPath(theme, path);
90
+ return value === null || value === void 0 || value === "";
91
+ });
92
+ }
93
+
94
+ // src/tokens/themes/light.ts
95
+ var light = defineTheme({
96
+ meta: {
97
+ name: "light",
98
+ label: "Light",
99
+ description: "Default, neutral, high-legibility surface."
100
+ },
101
+ color: {
102
+ neutral: {
103
+ 0: "#ffffff",
104
+ 50: "#f9fafb",
105
+ 100: "#f3f4f6",
106
+ 200: "#e5e7eb",
107
+ 300: "#d1d5db",
108
+ 400: "#9ca3af",
109
+ 500: "#6b7280",
110
+ 600: "#4b5563",
111
+ 700: "#374151",
112
+ 800: "#1f2937",
113
+ 900: "#111827",
114
+ 950: "#030712"
115
+ },
116
+ success: { light: "#d1fae5", subtle: "#a7f3d0", base: "#10b981", dark: "#059669", deeper: "#064e3b" },
117
+ danger: { light: "#fee2e2", subtle: "#fecaca", base: "#ef4444", dark: "#dc2626", deeper: "#7f1d1d" },
118
+ warning: { light: "#fef3c7", subtle: "#fde68a", base: "#f59e0b", dark: "#d97706", deeper: "#78350f" },
119
+ info: { light: "#dbeafe", subtle: "#bfdbfe", base: "#3b82f6", dark: "#2563eb", deeper: "#1e3a5f" },
120
+ background: "#ffffff",
121
+ surface: "#ffffff",
122
+ surfaceRaised: "#ffffff",
123
+ border: "#e5e7eb",
124
+ // Neutral, not brand-tied — the actual focus-ring color
125
+ // interactive components use is the picked accent
126
+ // (--color-brand-500/600), not this. This exists for
127
+ // non-branded emphasis borders.
128
+ borderFocus: "#9ca3af",
129
+ text: "#111827",
130
+ textMuted: "#6b7280",
131
+ textInverse: "#ffffff"
132
+ },
133
+ radius: { sm: "6px", md: "10px", lg: "14px", xl: "18px", "2xl": "24px", full: "9999px" },
134
+ spacing: { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px", "2xl": "32px" },
135
+ typography: {
136
+ fontSans: "'Inter', system-ui, sans-serif",
137
+ fontMono: "'JetBrains Mono', monospace",
138
+ sizeXs: "12px",
139
+ sizeSm: "14px",
140
+ sizeMd: "16px",
141
+ sizeLg: "18px",
142
+ sizeXl: "22px",
143
+ weightNormal: "400",
144
+ weightMedium: "500",
145
+ weightBold: "700",
146
+ lineHeightTight: "1.2",
147
+ lineHeightNormal: "1.5"
148
+ },
149
+ shadow: {
150
+ xs: "0 1px 2px rgba(0,0,0,0.05)",
151
+ sm: "0 2px 6px rgba(0,0,0,0.06)",
152
+ md: "0 4px 12px rgba(0,0,0,0.08)",
153
+ lg: "0 10px 24px rgba(0,0,0,0.10)",
154
+ xl: "0 20px 40px rgba(0,0,0,0.12)",
155
+ "2xl": "0 28px 56px rgba(0,0,0,0.16)",
156
+ inner: "inset 0 1px 2px rgba(0,0,0,0.05)"
157
+ },
158
+ elevation: { dropdown: 1050, popover: 1060, modal: 1e3, toast: 1200, tooltip: 1100 },
159
+ motion: {
160
+ durationFast: "120ms",
161
+ durationNormal: "200ms",
162
+ durationSlow: "320ms",
163
+ easeStandard: "cubic-bezier(0.4, 0, 0.2, 1)",
164
+ easeEmphasized: "cubic-bezier(0.2, 0, 0, 1)",
165
+ durationInstant: "0ms"
166
+ },
167
+ border: { widthThin: "1px", widthMedium: "1.5px", widthThick: "2px", style: "solid" },
168
+ effects: { backdropBlur: "0px" }
169
+ });
170
+
171
+ // src/tokens/themes/dark.ts
172
+ var dark = defineTheme({
173
+ meta: {
174
+ name: "dark",
175
+ label: "Dark",
176
+ description: "Low-glare surface for extended use."
177
+ },
178
+ color: {
179
+ neutral: {
180
+ 0: "#030712",
181
+ 50: "#111827",
182
+ 100: "#1f2937",
183
+ 200: "#374151",
184
+ 300: "#4b5563",
185
+ 400: "#6b7280",
186
+ 500: "#9ca3af",
187
+ 600: "#d1d5db",
188
+ 700: "#e5e7eb",
189
+ 800: "#f3f4f6",
190
+ 900: "#f9fafb",
191
+ 950: "#ffffff"
192
+ },
193
+ success: { light: "#064e3b", subtle: "#065f46", base: "#34d399", dark: "#6ee7b7", deeper: "#d1fae5" },
194
+ danger: { light: "#7f1d1d", subtle: "#991b1b", base: "#f87171", dark: "#fca5a5", deeper: "#fee2e2" },
195
+ warning: { light: "#78350f", subtle: "#92400e", base: "#fbbf24", dark: "#fcd34d", deeper: "#fef3c7" },
196
+ info: { light: "#1e3a5f", subtle: "#1e40af", base: "#60a5fa", dark: "#93c5fd", deeper: "#dbeafe" },
197
+ background: "#0b0f19",
198
+ surface: "#131826",
199
+ surfaceRaised: "#1c2333",
200
+ border: "#2a3143",
201
+ borderFocus: "#6b7280",
202
+ text: "#f3f4f6",
203
+ textMuted: "#9ca3af",
204
+ textInverse: "#111827"
205
+ },
206
+ radius: { sm: "6px", md: "10px", lg: "14px", xl: "18px", "2xl": "24px", full: "9999px" },
207
+ spacing: { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px", "2xl": "32px" },
208
+ typography: {
209
+ fontSans: "'Inter', system-ui, sans-serif",
210
+ fontMono: "'JetBrains Mono', monospace",
211
+ sizeXs: "12px",
212
+ sizeSm: "14px",
213
+ sizeMd: "16px",
214
+ sizeLg: "18px",
215
+ sizeXl: "22px",
216
+ weightNormal: "400",
217
+ weightMedium: "500",
218
+ weightBold: "700",
219
+ lineHeightTight: "1.2",
220
+ lineHeightNormal: "1.5"
221
+ },
222
+ shadow: {
223
+ xs: "0 1px 2px rgba(0,0,0,0.4)",
224
+ sm: "0 2px 6px rgba(0,0,0,0.45)",
225
+ md: "0 4px 12px rgba(0,0,0,0.5)",
226
+ lg: "0 10px 24px rgba(0,0,0,0.55)",
227
+ xl: "0 20px 40px rgba(0,0,0,0.6)",
228
+ "2xl": "0 28px 56px rgba(0,0,0,0.65)",
229
+ inner: "inset 0 1px 2px rgba(0,0,0,0.4)"
230
+ },
231
+ elevation: { dropdown: 1050, popover: 1060, modal: 1e3, toast: 1200, tooltip: 1100 },
232
+ motion: {
233
+ durationFast: "120ms",
234
+ durationNormal: "200ms",
235
+ durationSlow: "320ms",
236
+ easeStandard: "cubic-bezier(0.4, 0, 0.2, 1)",
237
+ easeEmphasized: "cubic-bezier(0.2, 0, 0, 1)",
238
+ durationInstant: "0ms"
239
+ },
240
+ border: { widthThin: "1px", widthMedium: "1.5px", widthThick: "2px", style: "solid" },
241
+ effects: { backdropBlur: "0px" }
242
+ });
243
+
244
+ // src/tokens/themes/glass.ts
245
+ var glass = defineTheme({
246
+ meta: {
247
+ name: "glass",
248
+ label: "Glass",
249
+ description: "Translucent, softly rounded, floating surfaces. Needs a rich background behind it."
250
+ },
251
+ color: {
252
+ neutral: {
253
+ 0: "#ffffff",
254
+ 50: "#f9fafb",
255
+ 100: "#f3f4f6",
256
+ 200: "#e5e7eb",
257
+ 300: "#d1d5db",
258
+ 400: "#9ca3af",
259
+ 500: "#6b7280",
260
+ 600: "#4b5563",
261
+ 700: "#374151",
262
+ 800: "#1f2937",
263
+ 900: "#111827",
264
+ 950: "#030712"
265
+ },
266
+ success: { light: "#d1fae5", subtle: "#a7f3d0", base: "#10b981", dark: "#059669", deeper: "#064e3b" },
267
+ danger: { light: "#fee2e2", subtle: "#fecaca", base: "#ef4444", dark: "#dc2626", deeper: "#7f1d1d" },
268
+ warning: { light: "#fef3c7", subtle: "#fde68a", base: "#f59e0b", dark: "#d97706", deeper: "#78350f" },
269
+ info: { light: "#dbeafe", subtle: "#bfdbfe", base: "#3b82f6", dark: "#2563eb", deeper: "#1e3a5f" },
270
+ background: "transparent",
271
+ surface: "rgba(255,255,255,0.55)",
272
+ surfaceRaised: "rgba(255,255,255,0.75)",
273
+ // Was rgba(255,255,255,0.35) — translucent WHITE. Composited on
274
+ // a plain white page (the theme's own meta.description admits it
275
+ // "needs a rich background behind it," but most consumers won't
276
+ // add one), that resolves to literal #ffffff — a 1.0:1 contrast
277
+ // ratio, i.e. actually invisible, which is the reported vanished
278
+ // Progress-track border. A neutral slate tint stays visible
279
+ // against both a plain white AND a plain black fallback backdrop
280
+ // (measured ~2.1-2.3:1 either way) — short of full 3:1 UI-contrast
281
+ // on both extremes at once, but a large improvement over 1.0, and
282
+ // still reads as a soft glass edge over an actual rich backdrop.
283
+ border: "rgba(100,116,139,0.6)",
284
+ borderFocus: "#9ca3af",
285
+ text: "#111827",
286
+ textMuted: "rgba(17,24,39,0.65)",
287
+ textInverse: "#ffffff"
288
+ },
289
+ // Notably rounder than light/dark — this is a shape difference, not just color.
290
+ radius: { sm: "10px", md: "16px", lg: "22px", xl: "28px", "2xl": "36px", full: "9999px" },
291
+ spacing: { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px", "2xl": "32px" },
292
+ typography: {
293
+ fontSans: "'Inter', system-ui, sans-serif",
294
+ fontMono: "'JetBrains Mono', monospace",
295
+ sizeXs: "12px",
296
+ sizeSm: "14px",
297
+ sizeMd: "16px",
298
+ sizeLg: "18px",
299
+ sizeXl: "22px",
300
+ weightNormal: "400",
301
+ weightMedium: "500",
302
+ weightBold: "700",
303
+ lineHeightTight: "1.2",
304
+ lineHeightNormal: "1.5"
305
+ },
306
+ shadow: {
307
+ xs: "0 2px 8px rgba(0,0,0,0.06)",
308
+ sm: "0 4px 16px rgba(0,0,0,0.08)",
309
+ md: "0 8px 32px rgba(0,0,0,0.10)",
310
+ lg: "0 16px 48px rgba(0,0,0,0.12)",
311
+ xl: "0 24px 64px rgba(0,0,0,0.14)",
312
+ "2xl": "0 32px 80px rgba(0,0,0,0.18)",
313
+ inner: "inset 0 1px 0 rgba(255,255,255,0.4)"
314
+ },
315
+ elevation: { dropdown: 1050, popover: 1060, modal: 1e3, toast: 1200, tooltip: 1100 },
316
+ motion: {
317
+ // Slightly slower/softer than light/dark — matches "everything floats".
318
+ durationFast: "160ms",
319
+ durationNormal: "260ms",
320
+ durationSlow: "400ms",
321
+ easeStandard: "cubic-bezier(0.25, 0.1, 0.25, 1)",
322
+ easeEmphasized: "cubic-bezier(0.16, 1, 0.3, 1)",
323
+ durationInstant: "0ms"
324
+ },
325
+ border: { widthThin: "1px", widthMedium: "1px", widthThick: "1.5px", style: "solid" },
326
+ effects: { backdropBlur: "16px" }
327
+ });
328
+
329
+ // src/tokens/themes/dark-glass.ts
330
+ var darkGlass = defineTheme({
331
+ ...dark,
332
+ meta: {
333
+ name: "dark-glass",
334
+ label: "Dark Glass",
335
+ description: "Translucent glass panels floating over a dark background."
336
+ },
337
+ color: {
338
+ ...dark.color,
339
+ background: "#05070d",
340
+ surface: "rgba(255,255,255,0.06)",
341
+ surfaceRaised: "rgba(255,255,255,0.10)",
342
+ border: "rgba(255,255,255,0.12)"
343
+ },
344
+ radius: { sm: "10px", md: "16px", lg: "22px", xl: "28px", "2xl": "36px", full: "9999px" },
345
+ shadow: {
346
+ xs: "0 2px 8px rgba(0,0,0,0.5)",
347
+ sm: "0 4px 16px rgba(0,0,0,0.55)",
348
+ md: "0 8px 32px rgba(0,0,0,0.6)",
349
+ lg: "0 16px 48px rgba(0,0,0,0.65)",
350
+ xl: "0 24px 64px rgba(0,0,0,0.7)",
351
+ "2xl": "0 32px 80px rgba(0,0,0,0.75)",
352
+ inner: "inset 0 1px 0 rgba(255,255,255,0.08)"
353
+ },
354
+ motion: { ...dark.motion, durationFast: "160ms", durationNormal: "260ms", durationSlow: "400ms" },
355
+ effects: { backdropBlur: "18px" }
356
+ });
357
+
358
+ // src/tokens/themes/minimalism.ts
359
+ var minimalism = defineTheme({
360
+ ...light,
361
+ meta: {
362
+ name: "minimalism",
363
+ label: "Minimalism",
364
+ description: "Reduced to essentials \u2014 thin borders, flat surfaces, no shadow, tight radius."
365
+ },
366
+ color: {
367
+ ...light.color,
368
+ border: "#e2e2e2",
369
+ surface: "#ffffff",
370
+ surfaceRaised: "#ffffff"
371
+ },
372
+ radius: { sm: "2px", md: "3px", lg: "4px", xl: "6px", "2xl": "8px", full: "9999px" },
373
+ shadow: { xs: "none", sm: "none", md: "none", lg: "none", xl: "none", "2xl": "none", inner: "none" },
374
+ border: { widthThin: "1px", widthMedium: "1px", widthThick: "1px", style: "solid" },
375
+ effects: { backdropBlur: "0px" }
376
+ });
377
+
378
+ // src/tokens/themes/brutalism.ts
379
+ var brutalism = defineTheme({
380
+ ...light,
381
+ meta: {
382
+ name: "brutalism",
383
+ label: "Brutalism",
384
+ description: "Raw, unstyled web aesthetic \u2014 square corners, zero shadow, monospace type."
385
+ },
386
+ color: {
387
+ ...light.color,
388
+ background: "#ffffff",
389
+ surface: "#ffffff",
390
+ surfaceRaised: "#ffffff",
391
+ border: "#000000",
392
+ borderFocus: "#ff0000",
393
+ text: "#000000"
394
+ },
395
+ radius: { sm: "0px", md: "0px", lg: "0px", xl: "0px", "2xl": "0px", full: "0px" },
396
+ typography: { ...light.typography, fontSans: "'Courier New', monospace", fontMono: "'Courier New', monospace" },
397
+ shadow: { xs: "none", sm: "none", md: "none", lg: "none", xl: "none", "2xl": "none", inner: "none" },
398
+ border: { widthThin: "1px", widthMedium: "2px", widthThick: "3px", style: "solid" },
399
+ motion: { ...light.motion, durationFast: "0ms", durationNormal: "0ms", durationSlow: "0ms" },
400
+ effects: { backdropBlur: "0px" }
401
+ });
402
+
403
+ // src/tokens/themes/neobrutalism.ts
404
+ var neobrutalism = defineTheme({
405
+ ...light,
406
+ meta: {
407
+ name: "neobrutalism",
408
+ label: "Neo Brutalism",
409
+ description: "Bold black borders, flat offset shadows, saturated color blocks."
410
+ },
411
+ color: {
412
+ ...light.color,
413
+ background: "#fef3c7",
414
+ surface: "#ffffff",
415
+ surfaceRaised: "#ffffff",
416
+ border: "#000000",
417
+ borderFocus: "#000000",
418
+ // light.color.warning.light (#fef3c7) is identical to this
419
+ // theme's own background — every warning Alert/Badge/etc. was
420
+ // rendering invisibly on the page. Bumped to the next step in
421
+ // the same warm-amber family (matches light.color.warning.subtle)
422
+ // so it stays on-theme but is actually visible against the page.
423
+ warning: { ...light.color.warning, light: "#fde68a" }
424
+ },
425
+ radius: { sm: "4px", md: "6px", lg: "8px", xl: "10px", "2xl": "12px", full: "9999px" },
426
+ shadow: {
427
+ xs: "2px 2px 0 #000000",
428
+ sm: "3px 3px 0 #000000",
429
+ md: "4px 4px 0 #000000",
430
+ lg: "6px 6px 0 #000000",
431
+ xl: "8px 8px 0 #000000",
432
+ "2xl": "10px 10px 0 #000000",
433
+ inner: "inset 2px 2px 0 #000000"
434
+ },
435
+ border: { widthThin: "2px", widthMedium: "3px", widthThick: "4px", style: "solid" },
436
+ motion: { ...light.motion, durationFast: "80ms", durationNormal: "140ms", durationSlow: "200ms", easeStandard: "linear", easeEmphasized: "linear" },
437
+ effects: { backdropBlur: "0px" }
438
+ });
439
+
440
+ // src/tokens/themes/cyberpunk.ts
441
+ var cyberpunk = defineTheme({
442
+ ...dark,
443
+ meta: {
444
+ name: "cyberpunk",
445
+ label: "Cyberpunk",
446
+ description: "Neon-on-black, glowing edges, high-saturation magenta/cyan accents."
447
+ },
448
+ color: {
449
+ ...dark.color,
450
+ background: "#0a0014",
451
+ surface: "#12001f",
452
+ surfaceRaised: "#1a0230",
453
+ border: "#ff2bd6",
454
+ borderFocus: "#00f0ff",
455
+ text: "#e8faff",
456
+ textMuted: "#9a8cc9"
457
+ },
458
+ radius: { sm: "2px", md: "4px", lg: "6px", xl: "8px", "2xl": "10px", full: "9999px" },
459
+ shadow: {
460
+ xs: "0 0 6px rgba(255,43,214,0.5)",
461
+ sm: "0 0 12px rgba(255,43,214,0.55)",
462
+ md: "0 0 20px rgba(0,240,255,0.5)",
463
+ lg: "0 0 32px rgba(0,240,255,0.55)",
464
+ xl: "0 0 48px rgba(255,43,214,0.6)",
465
+ "2xl": "0 0 64px rgba(0,240,255,0.65)",
466
+ inner: "inset 0 0 8px rgba(255,43,214,0.4)"
467
+ },
468
+ border: { widthThin: "1px", widthMedium: "1.5px", widthThick: "2px", style: "solid" },
469
+ motion: { ...dark.motion, easeStandard: "cubic-bezier(0.83,0,0.17,1)", easeEmphasized: "cubic-bezier(0.9,0,0.1,1)" },
470
+ effects: { backdropBlur: "0px" }
471
+ });
472
+
473
+ // src/tokens/themes/gradient.ts
474
+ var gradient = defineTheme({
475
+ ...light,
476
+ meta: {
477
+ name: "gradient",
478
+ label: "Gradient",
479
+ description: "Vibrant, colorful transitions across surfaces and accents."
480
+ },
481
+ color: {
482
+ ...light.color,
483
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
484
+ surface: "linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,255,255,0.75))",
485
+ surfaceRaised: "#ffffff",
486
+ border: "rgba(118,75,162,0.25)",
487
+ borderFocus: "#764ba2",
488
+ // text/textMuted were still light theme's values (#111827 /
489
+ // #6b7280) — fine on the near-white `surface`, but components
490
+ // that render straight on `background` (Timeline, Pagination,
491
+ // Tabs — all used with no wrapping surface in this library's own
492
+ // docs examples) sat directly on the purple gradient instead.
493
+ // Measured contrast against the gradient's darker stop
494
+ // (#764ba2): text 2.79:1, textMuted a barely-there 1.32:1 — the
495
+ // reported "nearly invisible" text. Darkened both; textMuted
496
+ // still can't clear 4.5:1 against the darkest point of this
497
+ // specific gradient with a single flat color (nothing dark
498
+ // enough to do that stays legible as "muted" against the near-
499
+ // white surface too), so this is the best available compromise
500
+ // within a single global text/textMuted pair, not a full fix —
501
+ // worth knowing if it still reads as low-contrast on the
502
+ // darkest corner of the gradient.
503
+ text: "#000000",
504
+ textMuted: "#2e2440"
505
+ },
506
+ radius: { sm: "12px", md: "18px", lg: "24px", xl: "32px", "2xl": "40px", full: "9999px" },
507
+ shadow: {
508
+ xs: "0 2px 10px rgba(118,75,162,0.15)",
509
+ sm: "0 4px 20px rgba(118,75,162,0.18)",
510
+ md: "0 8px 30px rgba(118,75,162,0.22)",
511
+ lg: "0 16px 40px rgba(118,75,162,0.26)",
512
+ xl: "0 24px 56px rgba(118,75,162,0.3)",
513
+ "2xl": "0 32px 72px rgba(118,75,162,0.35)",
514
+ inner: "inset 0 1px 0 rgba(255,255,255,0.5)"
515
+ },
516
+ motion: { ...light.motion, durationNormal: "240ms", durationSlow: "380ms" },
517
+ effects: { backdropBlur: "0px" }
518
+ });
519
+
520
+ // src/tokens/themes/material.ts
521
+ var material = defineTheme({
522
+ ...light,
523
+ meta: {
524
+ name: "material",
525
+ label: "Material",
526
+ description: "Google Material Design-inspired elevation shadows and motion curves."
527
+ },
528
+ color: {
529
+ ...light.color,
530
+ surface: "#ffffff",
531
+ background: "#fafafa"
532
+ },
533
+ radius: { sm: "4px", md: "8px", lg: "12px", xl: "16px", "2xl": "28px", full: "9999px" },
534
+ typography: { ...light.typography, fontSans: "'Roboto', system-ui, sans-serif" },
535
+ shadow: {
536
+ xs: "0 1px 2px rgba(0,0,0,0.24)",
537
+ sm: "0 1px 4px rgba(0,0,0,0.2), 0 1px 2px rgba(0,0,0,0.12)",
538
+ md: "0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)",
539
+ lg: "0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)",
540
+ xl: "0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)",
541
+ "2xl": "0 19px 38px rgba(0,0,0,0.3), 0 15px 12px rgba(0,0,0,0.22)",
542
+ inner: "inset 0 1px 2px rgba(0,0,0,0.12)"
543
+ },
544
+ motion: { ...light.motion, easeStandard: "cubic-bezier(0.4,0,0.2,1)", easeEmphasized: "cubic-bezier(0.0,0,0.2,1)" },
545
+ effects: { backdropBlur: "0px" }
546
+ });
547
+
548
+ // src/tokens/themes/skeuomorphism.ts
549
+ var skeuomorphism = defineTheme({
550
+ ...light,
551
+ meta: {
552
+ name: "skeuomorphism",
553
+ label: "Skeuomorphism",
554
+ description: "Realistic depth \u2014 soft embossed surfaces mimicking physical material."
555
+ },
556
+ color: {
557
+ ...light.color,
558
+ background: "#e8e4da",
559
+ surface: "#f0ece2",
560
+ surfaceRaised: "#f7f4ec",
561
+ border: "#c9c2b0",
562
+ text: "#3a3226"
563
+ },
564
+ radius: { sm: "8px", md: "12px", lg: "18px", xl: "24px", "2xl": "32px", full: "9999px" },
565
+ shadow: {
566
+ xs: "inset 0 1px 1px rgba(255,255,255,0.8), 0 1px 3px rgba(58,50,38,0.25)",
567
+ sm: "inset 0 1px 1px rgba(255,255,255,0.8), 0 2px 6px rgba(58,50,38,0.28)",
568
+ md: "inset 0 1px 1px rgba(255,255,255,0.8), 0 4px 10px rgba(58,50,38,0.3)",
569
+ lg: "inset 0 1px 1px rgba(255,255,255,0.8), 0 8px 18px rgba(58,50,38,0.32)",
570
+ xl: "inset 0 1px 1px rgba(255,255,255,0.8), 0 14px 28px rgba(58,50,38,0.35)",
571
+ "2xl": "inset 0 1px 1px rgba(255,255,255,0.8), 0 20px 40px rgba(58,50,38,0.38)",
572
+ inner: "inset 0 2px 4px rgba(58,50,38,0.3)"
573
+ },
574
+ motion: { ...light.motion, durationNormal: "220ms", easeStandard: "cubic-bezier(0.34,1.56,0.64,1)" },
575
+ effects: { backdropBlur: "0px" }
576
+ });
577
+
578
+ // src/tokens/registry.ts
579
+ var registry = /* @__PURE__ */ new Map();
580
+ function assertComplete(theme) {
581
+ const missing = findMissingTokenPaths(theme);
582
+ if (missing.length > 0) {
583
+ throw new Error(
584
+ `Theme "${theme.meta?.name ?? "unknown"}" is missing/empty required token(s): ${missing.join(", ")}`
585
+ );
586
+ }
587
+ }
588
+ function registerTheme(theme) {
589
+ assertComplete(theme);
590
+ registry.set(theme.meta.name, theme);
591
+ }
592
+ function getTheme(name) {
593
+ return registry.get(name);
594
+ }
595
+ function listThemes() {
596
+ return Array.from(registry.values());
597
+ }
598
+ registerTheme(light);
599
+ registerTheme(dark);
600
+ registerTheme(glass);
601
+ registerTheme(darkGlass);
602
+ registerTheme(minimalism);
603
+ registerTheme(brutalism);
604
+ registerTheme(neobrutalism);
605
+ registerTheme(cyberpunk);
606
+ registerTheme(gradient);
607
+ registerTheme(material);
608
+ registerTheme(skeuomorphism);
609
+
610
+ // src/tokens/accents/indigo.ts
611
+ var indigo = {
612
+ name: "indigo",
613
+ label: "Indigo",
614
+ scale: {
615
+ 50: "#f0f4ff",
616
+ 100: "#e0e8ff",
617
+ 200: "#c7d5fe",
618
+ 300: "#a5b4fc",
619
+ 400: "#818cf8",
620
+ 500: "#6366f1",
621
+ 600: "#4f46e5",
622
+ 700: "#4338ca",
623
+ 800: "#3730a3",
624
+ 900: "#312e81"
625
+ }
626
+ };
627
+
628
+ // src/tokens/accents/violet.ts
629
+ var violet = {
630
+ name: "violet",
631
+ label: "Violet",
632
+ scale: {
633
+ 50: "#faf5ff",
634
+ 100: "#f3e8ff",
635
+ 200: "#e9d5ff",
636
+ 300: "#d8b4fe",
637
+ 400: "#c084fc",
638
+ 500: "#a855f7",
639
+ 600: "#9333ea",
640
+ 700: "#7e22ce",
641
+ 800: "#6b21a8",
642
+ 900: "#581c87"
643
+ }
644
+ };
645
+
646
+ // src/tokens/accents/teal.ts
647
+ var teal = {
648
+ name: "teal",
649
+ label: "Teal",
650
+ scale: {
651
+ 50: "#f0fdfa",
652
+ 100: "#ccfbf1",
653
+ 200: "#99f6e4",
654
+ 300: "#5eead4",
655
+ 400: "#2dd4bf",
656
+ 500: "#14b8a6",
657
+ 600: "#0d9488",
658
+ 700: "#0f766e",
659
+ 800: "#115e59",
660
+ 900: "#134e4a"
661
+ }
662
+ };
663
+
664
+ // src/tokens/accents/rose.ts
665
+ var rose = {
666
+ name: "rose",
667
+ label: "Rose",
668
+ scale: {
669
+ 50: "#fff1f2",
670
+ 100: "#ffe4e6",
671
+ 200: "#fecdd3",
672
+ 300: "#fda4af",
673
+ 400: "#fb7185",
674
+ 500: "#f43f5e",
675
+ 600: "#e11d48",
676
+ 700: "#be123c",
677
+ 800: "#9f1239",
678
+ 900: "#881337"
679
+ }
680
+ };
681
+
682
+ // src/tokens/accents/amber.ts
683
+ var amber = {
684
+ name: "amber",
685
+ label: "Amber",
686
+ scale: {
687
+ 50: "#fffbeb",
688
+ 100: "#fef3c7",
689
+ 200: "#fde68a",
690
+ 300: "#fcd34d",
691
+ 400: "#fbbf24",
692
+ 500: "#f59e0b",
693
+ 600: "#d97706",
694
+ 700: "#b45309",
695
+ 800: "#92400e",
696
+ 900: "#78350f"
697
+ }
698
+ };
699
+
700
+ // src/tokens/accents/emerald.ts
701
+ var emerald = {
702
+ name: "emerald",
703
+ label: "Emerald",
704
+ scale: {
705
+ 50: "#ecfdf5",
706
+ 100: "#d1fae5",
707
+ 200: "#a7f3d0",
708
+ 300: "#6ee7b7",
709
+ 400: "#34d399",
710
+ 500: "#10b981",
711
+ 600: "#059669",
712
+ 700: "#047857",
713
+ 800: "#065f46",
714
+ 900: "#064e3b"
715
+ }
716
+ };
717
+
718
+ // src/tokens/accents/copper.ts
719
+ var copper = {
720
+ name: "copper",
721
+ label: "Copper",
722
+ scale: {
723
+ 50: "#fdf6ec",
724
+ 100: "#faebd2",
725
+ 200: "#f3d3a0",
726
+ 300: "#e9b56b",
727
+ 400: "#d99a45",
728
+ 500: "#b9752c",
729
+ 600: "#9c5d24",
730
+ 700: "#7d4a1f",
731
+ 800: "#623a1c",
732
+ 900: "#4e2f19"
733
+ }
734
+ };
735
+
736
+ // src/tokens/accents/graphite.ts
737
+ var graphite = {
738
+ name: "graphite",
739
+ label: "Graphite",
740
+ scale: {
741
+ 50: "#fafafa",
742
+ 100: "#f0f0f0",
743
+ 200: "#e0e0e0",
744
+ 300: "#c7c7c7",
745
+ 400: "#a3a3a3",
746
+ 500: "#525252",
747
+ 600: "#404040",
748
+ 700: "#262626",
749
+ 800: "#171717",
750
+ 900: "#0a0a0a"
751
+ }
752
+ };
753
+
754
+ // src/tokens/accents/magenta.ts
755
+ var magenta = {
756
+ name: "magenta",
757
+ label: "Magenta",
758
+ scale: {
759
+ 50: "#ffe0fb",
760
+ 100: "#ffb3f5",
761
+ 200: "#ff80ee",
762
+ 300: "#ff4de6",
763
+ 400: "#ff26e0",
764
+ 500: "#ff00d9",
765
+ 600: "#e600c4",
766
+ 700: "#cc00af",
767
+ 800: "#b3009a",
768
+ 900: "#800070"
769
+ }
770
+ };
771
+
772
+ // src/tokens/accents.ts
773
+ var registry2 = /* @__PURE__ */ new Map();
774
+ function assertCompleteScale(def) {
775
+ const missing = ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900"].filter(
776
+ (k) => !def.scale[k]
777
+ );
778
+ if (missing.length > 0) {
779
+ throw new Error(`Accent "${def.name}" is missing scale step(s): ${missing.join(", ")}`);
780
+ }
781
+ }
782
+ function registerAccent(def) {
783
+ assertCompleteScale(def);
784
+ registry2.set(def.name, def);
785
+ }
786
+ function getAccent(name) {
787
+ return registry2.get(name);
788
+ }
789
+ function listAccents() {
790
+ return Array.from(registry2.values());
791
+ }
792
+ registerAccent(indigo);
793
+ registerAccent(violet);
794
+ registerAccent(teal);
795
+ registerAccent(rose);
796
+ registerAccent(amber);
797
+ registerAccent(emerald);
798
+ registerAccent(copper);
799
+ registerAccent(graphite);
800
+ registerAccent(magenta);
801
+ var DEFAULT_ACCENT = "indigo";
802
+
803
+ // src/core/field.ts
804
+ function resolveFieldState(props) {
805
+ return {
806
+ // ?? throughout, never || (CONTRACT.md Rule 3) — `error={false}`
807
+ // or `disabled={false}` must not be silently discarded.
808
+ isDisabled: props.disabled ?? false,
809
+ isRequired: props.required ?? false,
810
+ isInvalid: props.error ?? false,
811
+ size: props.size ?? "md"
812
+ };
813
+ }
814
+ function getFieldAriaProps(state, describedBy) {
815
+ return {
816
+ "aria-invalid": state.isInvalid ? true : void 0,
817
+ "aria-required": state.isRequired ? true : void 0,
818
+ "aria-describedby": describedBy
819
+ };
820
+ }
821
+
822
+ // src/core/colorpicker.ts
823
+ var DEFAULT_PRESETS = [
824
+ "#ef4444",
825
+ "#f97316",
826
+ "#f59e0b",
827
+ "#eab308",
828
+ "#84cc16",
829
+ "#22c55e",
830
+ "#10b981",
831
+ "#14b8a6",
832
+ "#06b6d4",
833
+ "#3b82f6",
834
+ "#6366f1",
835
+ "#8b5cf6",
836
+ "#a855f7",
837
+ "#d946ef",
838
+ "#ec4899",
839
+ "#6b7280",
840
+ "#171717",
841
+ "#ffffff"
842
+ ];
843
+ function resolveColorPickerState(props) {
844
+ return {
845
+ ...resolveFieldState(props),
846
+ presets: props.presets ?? DEFAULT_PRESETS,
847
+ variant: props.variant ?? "both"
848
+ };
849
+ }
850
+ var HEX_RE = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;
851
+ function normalizeHex(text) {
852
+ const trimmed = text.trim();
853
+ const match = trimmed.match(HEX_RE);
854
+ if (!match) return null;
855
+ let hex = match[1].toLowerCase();
856
+ if (hex.length === 3) {
857
+ hex = hex.split("").map((c) => c + c).join("");
858
+ }
859
+ return `#${hex}`;
860
+ }
861
+ function isSameColor(a, b) {
862
+ if (!a || !b) return a === b;
863
+ const na = normalizeHex(a);
864
+ const nb = normalizeHex(b);
865
+ return na !== null && na === nb;
866
+ }
867
+ function getSwatchClasses(input) {
868
+ return [
869
+ "nx-colorpicker__swatch-option",
870
+ input.isSelected && "nx-colorpicker__swatch-option--selected",
871
+ input.isActive && "nx-colorpicker__swatch-option--active"
872
+ ].filter(Boolean).join(" ");
873
+ }
874
+ function getSwatchGridAriaProps(label) {
875
+ return { role: "listbox", "aria-label": label };
876
+ }
877
+ function getSwatchAriaProps(input) {
878
+ return {
879
+ role: "option",
880
+ "aria-selected": input.isSelected,
881
+ "aria-label": input.label,
882
+ tabIndex: input.isFocusable ? 0 : -1
883
+ };
884
+ }
885
+ function getFieldTriggerAriaProps(state, describedBy) {
886
+ return getFieldAriaProps(state, describedBy);
887
+ }
888
+ var COLOR_FORMATS = ["hex", "rgb", "hsl"];
889
+ function clampNum(n, min, max) {
890
+ return Math.min(Math.max(n, min), max);
891
+ }
892
+ function hexToRgb(hex) {
893
+ const normalized = normalizeHex(hex);
894
+ if (!normalized) return null;
895
+ return {
896
+ r: parseInt(normalized.slice(1, 3), 16),
897
+ g: parseInt(normalized.slice(3, 5), 16),
898
+ b: parseInt(normalized.slice(5, 7), 16)
899
+ };
900
+ }
901
+ function rgbToHex({ r, g, b }) {
902
+ const channel = (n) => clampNum(Math.round(n), 0, 255).toString(16).padStart(2, "0");
903
+ return `#${channel(r)}${channel(g)}${channel(b)}`;
904
+ }
905
+ function rgbToHsv({ r, g, b }) {
906
+ const rn = r / 255, gn = g / 255, bn = b / 255;
907
+ const max = Math.max(rn, gn, bn), min = Math.min(rn, gn, bn);
908
+ const d = max - min;
909
+ let h = 0;
910
+ if (d !== 0) {
911
+ if (max === rn) h = (gn - bn) / d % 6;
912
+ else if (max === gn) h = (bn - rn) / d + 2;
913
+ else h = (rn - gn) / d + 4;
914
+ h *= 60;
915
+ if (h < 0) h += 360;
916
+ }
917
+ const s = max === 0 ? 0 : d / max;
918
+ return { h, s: s * 100, v: max * 100 };
919
+ }
920
+ function hsvToRgb({ h, s, v }) {
921
+ const s1 = clampNum(s, 0, 100) / 100;
922
+ const v1 = clampNum(v, 0, 100) / 100;
923
+ const hh = (h % 360 + 360) % 360 / 60;
924
+ const c = v1 * s1;
925
+ const x = c * (1 - Math.abs(hh % 2 - 1));
926
+ const m = v1 - c;
927
+ let [r1, g1, b1] = [0, 0, 0];
928
+ if (hh < 1) [r1, g1, b1] = [c, x, 0];
929
+ else if (hh < 2) [r1, g1, b1] = [x, c, 0];
930
+ else if (hh < 3) [r1, g1, b1] = [0, c, x];
931
+ else if (hh < 4) [r1, g1, b1] = [0, x, c];
932
+ else if (hh < 5) [r1, g1, b1] = [x, 0, c];
933
+ else [r1, g1, b1] = [c, 0, x];
934
+ return { r: (r1 + m) * 255, g: (g1 + m) * 255, b: (b1 + m) * 255 };
935
+ }
936
+ function rgbToHsl({ r, g, b }) {
937
+ const rn = r / 255, gn = g / 255, bn = b / 255;
938
+ const max = Math.max(rn, gn, bn), min = Math.min(rn, gn, bn);
939
+ const l = (max + min) / 2;
940
+ const d = max - min;
941
+ let h = 0, s = 0;
942
+ if (d !== 0) {
943
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
944
+ if (max === rn) h = (gn - bn) / d % 6;
945
+ else if (max === gn) h = (bn - rn) / d + 2;
946
+ else h = (rn - gn) / d + 4;
947
+ h *= 60;
948
+ if (h < 0) h += 360;
949
+ }
950
+ return { h, s: s * 100, l: l * 100 };
951
+ }
952
+ function hslToRgb({ h, s, l }) {
953
+ const s1 = clampNum(s, 0, 100) / 100;
954
+ const l1 = clampNum(l, 0, 100) / 100;
955
+ const c = (1 - Math.abs(2 * l1 - 1)) * s1;
956
+ const hh = (h % 360 + 360) % 360 / 60;
957
+ const x = c * (1 - Math.abs(hh % 2 - 1));
958
+ const m = l1 - c / 2;
959
+ let [r1, g1, b1] = [0, 0, 0];
960
+ if (hh < 1) [r1, g1, b1] = [c, x, 0];
961
+ else if (hh < 2) [r1, g1, b1] = [x, c, 0];
962
+ else if (hh < 3) [r1, g1, b1] = [0, c, x];
963
+ else if (hh < 4) [r1, g1, b1] = [0, x, c];
964
+ else if (hh < 5) [r1, g1, b1] = [x, 0, c];
965
+ else [r1, g1, b1] = [c, 0, x];
966
+ return { r: (r1 + m) * 255, g: (g1 + m) * 255, b: (b1 + m) * 255 };
967
+ }
968
+ function hexToHsv(hex) {
969
+ const rgb = hexToRgb(hex);
970
+ return rgb ? rgbToHsv(rgb) : null;
971
+ }
972
+ function hsvToHex(hsv) {
973
+ return rgbToHex(hsvToRgb(hsv));
974
+ }
975
+ function hslToHex(hsl) {
976
+ return rgbToHex(hslToRgb(hsl));
977
+ }
978
+ var RGB_FUNCTION_RE = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*[\d.]+\s*)?\)$/i;
979
+ var HSL_FUNCTION_RE = /^hsla?\(\s*(-?\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*(?:,\s*[\d.]+\s*)?\)$/i;
980
+ function parseColorInput(text) {
981
+ const trimmed = text.trim();
982
+ const hex = normalizeHex(trimmed);
983
+ if (hex) return hex;
984
+ const rgbMatch = trimmed.match(RGB_FUNCTION_RE);
985
+ if (rgbMatch) {
986
+ const [, r, g, b] = rgbMatch;
987
+ return rgbToHex({ r: clampNum(Number(r), 0, 255), g: clampNum(Number(g), 0, 255), b: clampNum(Number(b), 0, 255) });
988
+ }
989
+ const hslMatch = trimmed.match(HSL_FUNCTION_RE);
990
+ if (hslMatch) {
991
+ const [, h, s, l] = hslMatch;
992
+ return hslToHex({ h: clampNum(Number(h), 0, 360), s: clampNum(Number(s), 0, 100), l: clampNum(Number(l), 0, 100) });
993
+ }
994
+ return null;
995
+ }
996
+ function formatColorValue(hex, format) {
997
+ if (format === "hex") return hex;
998
+ const rgb = hexToRgb(hex);
999
+ if (!rgb) return hex;
1000
+ if (format === "rgb") return `rgb(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)})`;
1001
+ const hsl = rgbToHsl(rgb);
1002
+ return `hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%)`;
1003
+ }
1004
+ function getSvKeyboardDelta(key, coarse) {
1005
+ const step = coarse ? 10 : 2;
1006
+ switch (key) {
1007
+ case "ArrowLeft":
1008
+ return { ds: -step, dv: 0 };
1009
+ case "ArrowRight":
1010
+ return { ds: step, dv: 0 };
1011
+ case "ArrowUp":
1012
+ return { ds: 0, dv: step };
1013
+ case "ArrowDown":
1014
+ return { ds: 0, dv: -step };
1015
+ default:
1016
+ return null;
1017
+ }
1018
+ }
1019
+ function clampPercent(n) {
1020
+ return clampNum(n, 0, 100);
1021
+ }
1022
+ function getFormatTabClasses(isActive) {
1023
+ return ["nx-colorpicker__format-tab", isActive && "nx-colorpicker__format-tab--active"].filter(Boolean).join(" ");
1024
+ }
1025
+ function getFormatTablistAriaProps(label) {
1026
+ return { role: "tablist", "aria-label": label };
1027
+ }
1028
+ function getFormatTabAriaProps(isActive) {
1029
+ return { role: "tab", "aria-selected": isActive, tabIndex: isActive ? 0 : -1 };
1030
+ }
1031
+ function getSvThumbAriaProps(saturation, value) {
1032
+ return {
1033
+ role: "slider",
1034
+ "aria-label": "Color saturation and brightness",
1035
+ "aria-valuetext": `Saturation ${Math.round(saturation)}%, brightness ${Math.round(value)}%`,
1036
+ tabIndex: 0
1037
+ };
1038
+ }
1039
+
1040
+ // src/core/table.ts
1041
+ function resolveTableState(props) {
1042
+ return {
1043
+ size: props.size ?? "md",
1044
+ striped: props.striped ?? false,
1045
+ bordered: props.bordered ?? false,
1046
+ stickyHeader: props.stickyHeader ?? false
1047
+ };
1048
+ }
1049
+ function getWrapperClasses(className) {
1050
+ return ["nx-table-wrapper", className].filter(Boolean).join(" ");
1051
+ }
1052
+ function getTableClasses(state, className) {
1053
+ return [
1054
+ "nx-table",
1055
+ `nx-table--${state.size}`,
1056
+ state.striped && "nx-table--striped",
1057
+ state.bordered && "nx-table--bordered",
1058
+ state.stickyHeader && "nx-table--sticky-header",
1059
+ className
1060
+ ].filter(Boolean).join(" ");
1061
+ }
1062
+ function getRowClasses(selected, clickable, className) {
1063
+ return [
1064
+ "nx-table__row",
1065
+ selected && "nx-table__row--selected",
1066
+ clickable && "nx-table__row--clickable",
1067
+ className
1068
+ ].filter(Boolean).join(" ");
1069
+ }
1070
+ function getHeadCellClasses(sortable, className) {
1071
+ return ["nx-table__head-cell", sortable && "nx-table__head-cell--sortable", className].filter(Boolean).join(" ");
1072
+ }
1073
+ function getCellClasses(className) {
1074
+ return ["nx-table__cell", className].filter(Boolean).join(" ");
1075
+ }
1076
+ function getNextSortDirection(current) {
1077
+ if (current === null) return "asc";
1078
+ if (current === "asc") return "desc";
1079
+ return null;
1080
+ }
1081
+ function getSortAriaProps(direction) {
1082
+ return {
1083
+ "aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none"
1084
+ };
1085
+ }
1086
+ function getSelectAllState(totalCount, selectedCount) {
1087
+ if (totalCount <= 0 || selectedCount <= 0) return "none";
1088
+ if (selectedCount >= totalCount) return "all";
1089
+ return "some";
1090
+ }
1091
+
1092
+ // src/core/kanban.ts
1093
+ var DRAG_START_THRESHOLD_PX = 4;
1094
+ function resolveKanbanState(props) {
1095
+ return { compact: props.compact ?? false };
1096
+ }
1097
+ function getBoardClasses(state, className) {
1098
+ return ["nx-kanban", state.compact && "nx-kanban--compact", className].filter(Boolean).join(" ");
1099
+ }
1100
+ function getColumnClasses(isDropTarget, isDragging, className) {
1101
+ return [
1102
+ "nx-kanban__column",
1103
+ isDropTarget && "nx-kanban__column--drop-target",
1104
+ isDragging && "nx-kanban__column--dragging",
1105
+ className
1106
+ ].filter(Boolean).join(" ");
1107
+ }
1108
+ function getColumnCountClasses(overLimit) {
1109
+ return ["nx-kanban__column-count", overLimit && "nx-kanban__column-count--over-limit"].filter(Boolean).join(" ");
1110
+ }
1111
+ function getCardWrapperClasses(opts, className) {
1112
+ return [
1113
+ "nx-kanban__card",
1114
+ opts.isPointerDragging && "nx-kanban__card--dragging",
1115
+ opts.isPickedUp && "nx-kanban__card--picked-up",
1116
+ opts.disabled && "nx-kanban__card--disabled",
1117
+ className
1118
+ ].filter(Boolean).join(" ");
1119
+ }
1120
+ function findCardLocation(value, cardId) {
1121
+ for (const column of value.columns) {
1122
+ const index = column.cardIds.indexOf(cardId);
1123
+ if (index !== -1) return { columnId: column.id, index };
1124
+ }
1125
+ return null;
1126
+ }
1127
+ function removeCard(value, cardId) {
1128
+ const location = findCardLocation(value, cardId);
1129
+ if (!location) return value;
1130
+ return {
1131
+ columns: value.columns.map(
1132
+ (column) => column.id === location.columnId ? { ...column, cardIds: column.cardIds.filter((id) => id !== cardId) } : column
1133
+ )
1134
+ };
1135
+ }
1136
+ function moveCard(value, target) {
1137
+ const location = findCardLocation(value, target.cardId);
1138
+ const destExists = value.columns.some((column) => column.id === target.toColumnId);
1139
+ if (!location || !destExists) return value;
1140
+ const withoutCard = value.columns.map(
1141
+ (column) => column.cardIds.includes(target.cardId) ? { ...column, cardIds: column.cardIds.filter((id) => id !== target.cardId) } : column
1142
+ );
1143
+ return {
1144
+ columns: withoutCard.map((column) => {
1145
+ if (column.id !== target.toColumnId) return column;
1146
+ const clampedIndex = Math.max(0, Math.min(target.toIndex, column.cardIds.length));
1147
+ const cardIds = [...column.cardIds];
1148
+ cardIds.splice(clampedIndex, 0, target.cardId);
1149
+ return { ...column, cardIds };
1150
+ })
1151
+ };
1152
+ }
1153
+ function getAdjacentColumnId(value, columnId, direction) {
1154
+ const index = value.columns.findIndex((column) => column.id === columnId);
1155
+ if (index === -1) return null;
1156
+ return value.columns[index + direction]?.id ?? null;
1157
+ }
1158
+ function getKeyboardMoveTarget(value, cardId, direction) {
1159
+ const location = findCardLocation(value, cardId);
1160
+ if (!location) return null;
1161
+ const column = value.columns.find((c) => c.id === location.columnId);
1162
+ if (!column) return null;
1163
+ if (direction === "up" || direction === "down") {
1164
+ const toIndex2 = direction === "up" ? location.index - 1 : location.index + 1;
1165
+ if (toIndex2 < 0 || toIndex2 > column.cardIds.length - 1) return null;
1166
+ return { cardId, toColumnId: location.columnId, toIndex: toIndex2 };
1167
+ }
1168
+ const adjacentColumnId = getAdjacentColumnId(value, location.columnId, direction === "prev" ? -1 : 1);
1169
+ if (!adjacentColumnId) return null;
1170
+ const destColumn = value.columns.find((c) => c.id === adjacentColumnId);
1171
+ if (!destColumn) return null;
1172
+ const toIndex = Math.min(location.index, destColumn.cardIds.length);
1173
+ return { cardId, toColumnId: adjacentColumnId, toIndex };
1174
+ }
1175
+ function computeDropIndex(pointerY, cardRects) {
1176
+ for (let i = 0; i < cardRects.length; i++) {
1177
+ const midpoint = (cardRects[i].top + cardRects[i].bottom) / 2;
1178
+ if (pointerY < midpoint) return i;
1179
+ }
1180
+ return cardRects.length;
1181
+ }
1182
+ function computeDropColumn(pointerX, pointerY, columns) {
1183
+ for (const column of columns) {
1184
+ if (pointerX >= column.left && pointerX <= column.right && pointerY >= column.top && pointerY <= column.bottom) {
1185
+ return column.id;
1186
+ }
1187
+ }
1188
+ return null;
1189
+ }
1190
+ function moveColumn(value, target) {
1191
+ const fromIndex = value.columns.findIndex((c) => c.id === target.columnId);
1192
+ if (fromIndex === -1) return value;
1193
+ const columns = [...value.columns];
1194
+ const [moved] = columns.splice(fromIndex, 1);
1195
+ const clampedIndex = Math.max(0, Math.min(target.toIndex, columns.length));
1196
+ columns.splice(clampedIndex, 0, moved);
1197
+ return { columns };
1198
+ }
1199
+ function removeColumn(value, columnId) {
1200
+ if (!value.columns.some((c) => c.id === columnId)) return value;
1201
+ return { columns: value.columns.filter((c) => c.id !== columnId) };
1202
+ }
1203
+ function getColumnKeyboardMoveTarget(value, columnId, direction) {
1204
+ const fromIndex = value.columns.findIndex((c) => c.id === columnId);
1205
+ if (fromIndex === -1) return null;
1206
+ const toIndex = direction === "prev" ? fromIndex - 1 : fromIndex + 1;
1207
+ if (toIndex < 0 || toIndex > value.columns.length - 1) return null;
1208
+ return { columnId, toIndex };
1209
+ }
1210
+ function computeColumnDropIndex(pointerX, columnRects) {
1211
+ for (let i = 0; i < columnRects.length; i++) {
1212
+ const midpoint = (columnRects[i].left + columnRects[i].right) / 2;
1213
+ if (pointerX < midpoint) return i;
1214
+ }
1215
+ return columnRects.length;
1216
+ }
1217
+
1218
+ // src/core/code-highlight.ts
1219
+ function tokenizeFlat(source, grammar) {
1220
+ const tokens = [];
1221
+ const n = source.length;
1222
+ let i = 0;
1223
+ outer: while (i < n) {
1224
+ for (const rule of grammar.rules) {
1225
+ if (rule.pattern) {
1226
+ rule.pattern.lastIndex = i;
1227
+ const m = rule.pattern.exec(source);
1228
+ if (m && m.index === i && m[0].length > 0) {
1229
+ tokens.push({ type: rule.type, content: m[0] });
1230
+ i += m[0].length;
1231
+ continue outer;
1232
+ }
1233
+ } else if (rule.match) {
1234
+ const result = rule.match(source, i, tokens);
1235
+ if (result && result.length > 0) {
1236
+ tokens.push(...result.tokens);
1237
+ i += result.length;
1238
+ continue outer;
1239
+ }
1240
+ }
1241
+ }
1242
+ const ch = source[i];
1243
+ const last = tokens[tokens.length - 1];
1244
+ if (last && last.type === "plain") last.content += ch;
1245
+ else tokens.push({ type: "plain", content: ch });
1246
+ i++;
1247
+ }
1248
+ return tokens;
1249
+ }
1250
+ function splitIntoLines(tokens) {
1251
+ const lines = [[]];
1252
+ for (const tok of tokens) {
1253
+ const parts = tok.content.split("\n");
1254
+ parts.forEach((part, idx) => {
1255
+ if (part.length > 0) lines[lines.length - 1].push({ type: tok.type, content: part });
1256
+ if (idx < parts.length - 1) lines.push([]);
1257
+ });
1258
+ }
1259
+ return lines;
1260
+ }
1261
+ var KEYWORD = (words) => new RegExp(`\\b(?:${words})\\b`, "y");
1262
+ function matchTemplateLiteral(source, start, jsGrammar2) {
1263
+ if (source[start] !== "`") return null;
1264
+ const tokens = [{ type: "string", content: "`" }];
1265
+ let i = start + 1;
1266
+ let buf = "";
1267
+ const flush = () => {
1268
+ if (buf) {
1269
+ tokens.push({ type: "string", content: buf });
1270
+ buf = "";
1271
+ }
1272
+ };
1273
+ while (i < source.length) {
1274
+ const ch = source[i];
1275
+ if (ch === "\\" && i + 1 < source.length) {
1276
+ buf += ch + source[i + 1];
1277
+ i += 2;
1278
+ continue;
1279
+ }
1280
+ if (ch === "`") {
1281
+ flush();
1282
+ tokens.push({ type: "string", content: "`" });
1283
+ i++;
1284
+ return { length: i - start, tokens };
1285
+ }
1286
+ if (ch === "$" && source[i + 1] === "{") {
1287
+ flush();
1288
+ tokens.push({ type: "punctuation", content: "${" });
1289
+ i += 2;
1290
+ const exprStart = i;
1291
+ let depth = 1;
1292
+ while (i < source.length && depth > 0) {
1293
+ if (source[i] === "{") depth++;
1294
+ else if (source[i] === "}") depth--;
1295
+ if (depth > 0) i++;
1296
+ }
1297
+ const exprSource = source.slice(exprStart, i);
1298
+ tokens.push(...tokenizeFlat(exprSource, jsGrammar2));
1299
+ if (i < source.length) {
1300
+ tokens.push({ type: "punctuation", content: "}" });
1301
+ i++;
1302
+ }
1303
+ continue;
1304
+ }
1305
+ buf += ch;
1306
+ i++;
1307
+ }
1308
+ flush();
1309
+ return { length: i - start, tokens };
1310
+ }
1311
+ var REGEX_EXPRESSION_KEYWORDS = /* @__PURE__ */ new Set([
1312
+ "return",
1313
+ "typeof",
1314
+ "instanceof",
1315
+ "in",
1316
+ "of",
1317
+ "new",
1318
+ "delete",
1319
+ "void",
1320
+ "throw",
1321
+ "case",
1322
+ "do",
1323
+ "else",
1324
+ "yield",
1325
+ "await"
1326
+ ]);
1327
+ function matchRegexLiteral(source, start) {
1328
+ if (source[start] !== "/" || source[start + 1] === "/" || source[start + 1] === "*") return null;
1329
+ let j = start - 1;
1330
+ while (j >= 0 && /\s/.test(source[j])) j--;
1331
+ if (j >= 0) {
1332
+ const prevChar = source[j];
1333
+ const looksLikeValueEnd = /[)\]}\w$]/.test(prevChar) || prevChar === '"' || prevChar === "'" || prevChar === "`";
1334
+ if (looksLikeValueEnd) {
1335
+ const wordBefore = source.slice(0, j + 1).match(/([A-Za-z_$][\w$]*)$/)?.[1];
1336
+ if (!(wordBefore && REGEX_EXPRESSION_KEYWORDS.has(wordBefore))) return null;
1337
+ }
1338
+ }
1339
+ let i = start + 1;
1340
+ let inClass = false;
1341
+ while (i < source.length) {
1342
+ const ch = source[i];
1343
+ if (ch === "\\") {
1344
+ i += 2;
1345
+ continue;
1346
+ }
1347
+ if (ch === "\n") return null;
1348
+ if (ch === "[") inClass = true;
1349
+ else if (ch === "]") inClass = false;
1350
+ else if (ch === "/" && !inClass) {
1351
+ i++;
1352
+ break;
1353
+ }
1354
+ i++;
1355
+ }
1356
+ if (source[i - 1] !== "/") return null;
1357
+ while (i < source.length && /[a-z]/i.test(source[i])) i++;
1358
+ return { length: i - start, tokens: [{ type: "regex", content: source.slice(start, i) }] };
1359
+ }
1360
+ function buildJsGrammar(withTags) {
1361
+ const grammar = { rules: [] };
1362
+ const rules = grammar.rules;
1363
+ if (withTags) {
1364
+ rules.push({ type: "tag", pattern: /<\/?[A-Za-z][\w.-]*/y });
1365
+ }
1366
+ rules.push(
1367
+ { type: "comment", pattern: /\/\/[^\n]*|\/\*[\s\S]*?\*\//y },
1368
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/y },
1369
+ { type: "custom-template", match: (src, idx) => matchTemplateLiteral(src, idx, grammar) },
1370
+ { type: "custom-regex", match: (src, idx) => matchRegexLiteral(src, idx) },
1371
+ { type: "decorator", pattern: /@[A-Za-z_$][\w$]*/y },
1372
+ { type: "boolean", pattern: KEYWORD("true|false|null|undefined") },
1373
+ {
1374
+ type: "keyword",
1375
+ pattern: KEYWORD(
1376
+ "const|let|var|function|return|if|else|for|while|do|switch|case|default|break|continue|class|extends|super|new|this|typeof|instanceof|in|of|try|catch|finally|throw|async|await|yield|import|export|from|as|void|delete|static|get|set|interface|type|enum|implements|public|private|protected|readonly|namespace|declare|abstract|is|keyof|infer|satisfies"
1377
+ )
1378
+ },
1379
+ {
1380
+ type: "builtin",
1381
+ pattern: KEYWORD(
1382
+ "console|Math|JSON|Promise|Array|Object|Map|Set|WeakMap|WeakSet|String|Number|Boolean|Symbol|Error|Date|RegExp|Reflect|Proxy|globalThis|Infinity|NaN|BigInt|fetch|localStorage|sessionStorage"
1383
+ )
1384
+ },
1385
+ { type: "number", pattern: /\b0[xX][0-9a-fA-F]+\b|\b\d+\.?\d*(?:[eE][+-]?\d+)?n?\b/y },
1386
+ { type: "function", pattern: /[A-Za-z_$][\w$]*(?=\s*\()/y },
1387
+ { type: "punctuation", pattern: /[{}()[\];,.:?]/y }
1388
+ );
1389
+ return grammar;
1390
+ }
1391
+ var jsGrammar = buildJsGrammar(false);
1392
+ var jsxGrammar = buildJsGrammar(true);
1393
+ var jsonGrammar = {
1394
+ rules: [
1395
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"/y },
1396
+ { type: "boolean", pattern: KEYWORD("true|false|null") },
1397
+ { type: "number", pattern: /-?\b\d+\.?\d*(?:[eE][+-]?\d+)?\b/y },
1398
+ { type: "punctuation", pattern: /[{}[\]:,]/y }
1399
+ ]
1400
+ };
1401
+ var cssGrammar = {
1402
+ rules: [
1403
+ { type: "comment", pattern: /\/\*[\s\S]*?\*\//y },
1404
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/y },
1405
+ { type: "keyword", pattern: /!important\b/y },
1406
+ { type: "atrule", pattern: /@[a-zA-Z-]+/y },
1407
+ // Custom-property declarations/usage (--brand-color, var(--x)) —
1408
+ // checked before the generic hex-color/selector rules below.
1409
+ { type: "variable", pattern: /--[a-zA-Z_][\w-]*/y },
1410
+ { type: "function", pattern: /\b(?:var|calc|rgba?|hsla?|clamp|minmax|repeat|url|translate[XYZ]?|rotate[XYZ]?|scale[XYZ]?|linear-gradient|radial-gradient)(?=\()/y },
1411
+ // Pseudo-classes/elements (:hover, ::before) before the plain ":" punctuation.
1412
+ { type: "pseudo", pattern: /::?[a-zA-Z-]+/y },
1413
+ // Hex colors before the generic "#name" id-selector pattern below.
1414
+ { type: "builtin", pattern: /#[0-9a-fA-F]{3,8}\b/y },
1415
+ { type: "selector", pattern: /[.#][a-zA-Z_-][\w-]*/y },
1416
+ { type: "property", pattern: /[a-zA-Z-]+(?=\s*:)/y },
1417
+ { type: "number", pattern: /-?\d+\.?\d*(?:px|em|rem|%|vh|vw|s|ms|deg|fr)?\b/y },
1418
+ { type: "punctuation", pattern: /[{}:;,()]/y }
1419
+ ]
1420
+ };
1421
+ var htmlGrammar = {
1422
+ rules: [
1423
+ { type: "comment", pattern: /<!--[\s\S]*?-->/y },
1424
+ { type: "keyword", pattern: /<!DOCTYPE[^>]*>/iy },
1425
+ { type: "tag", pattern: /<\/?[a-zA-Z][\w:-]*/y },
1426
+ { type: "attrName", pattern: /[a-zA-Z-]+(?=\s*=)/y },
1427
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/y },
1428
+ { type: "builtin", pattern: /&[a-zA-Z#0-9]+;/y },
1429
+ { type: "punctuation", pattern: /[<>=/]/y }
1430
+ ]
1431
+ };
1432
+ var bashGrammar = {
1433
+ rules: [
1434
+ { type: "comment", pattern: /#[^\n]*/y },
1435
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"|'[^'\n]*'/y },
1436
+ { type: "variable", pattern: /\$\{?\w+\}?/y },
1437
+ {
1438
+ type: "keyword",
1439
+ pattern: KEYWORD(
1440
+ "if|then|else|elif|fi|for|do|done|while|case|esac|function|return|exit|export|local|echo|cd|sudo|npm|yarn|pnpm|git|mkdir|rm|cp|mv|cat|grep|sed|awk"
1441
+ )
1442
+ },
1443
+ { type: "number", pattern: /\b\d+\b/y },
1444
+ { type: "function", pattern: /(?<=^|\s)--?[a-zA-Z][\w-]*/y },
1445
+ { type: "punctuation", pattern: /[|&;()]/y }
1446
+ ]
1447
+ };
1448
+ var pythonGrammar = {
1449
+ rules: [
1450
+ { type: "comment", pattern: /#[^\n]*/y },
1451
+ { type: "decorator", pattern: /@[A-Za-z_][\w.]*/y },
1452
+ {
1453
+ // f/r/b/u string prefixes (f"...", rb'...', etc.) before plain strings.
1454
+ type: "string",
1455
+ pattern: /[rRbBfFuU]{0,2}(?:"""[\s\S]*?"""|'''[\s\S]*?'''|"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*')/y
1456
+ },
1457
+ { type: "boolean", pattern: KEYWORD("True|False|None") },
1458
+ {
1459
+ type: "keyword",
1460
+ pattern: KEYWORD(
1461
+ "def|return|if|elif|else|for|while|in|not|and|or|is|import|from|as|class|try|except|finally|raise|with|lambda|yield|pass|break|continue|global|nonlocal|assert|del|async|await|self"
1462
+ )
1463
+ },
1464
+ { type: "builtin", pattern: KEYWORD("print|len|range|str|int|float|list|dict|set|tuple|type|isinstance|super|open|input|enumerate|zip|map|filter|sorted|sum|min|max|any|all") },
1465
+ { type: "number", pattern: /\b\d+\.?\d*\b/y },
1466
+ { type: "function", pattern: /[A-Za-z_]\w*(?=\s*\()/y },
1467
+ { type: "punctuation", pattern: /[:,.()[\]{}]/y }
1468
+ ]
1469
+ };
1470
+ var markdownGrammar = {
1471
+ rules: [
1472
+ { type: "comment", pattern: /```[\s\S]*?```/y },
1473
+ { type: "keyword", pattern: /^#{1,6}[^\n]*/my },
1474
+ { type: "punctuation", pattern: /^(?:-{3,}|\*{3,}|_{3,})$/my },
1475
+ { type: "function", pattern: /`[^`\n]+`/y },
1476
+ { type: "builtin", pattern: /\*\*[^*\n]+\*\*/y },
1477
+ { type: "variable", pattern: /~~[^~\n]+~~/y },
1478
+ { type: "string", pattern: /\*[^*\n]+\*/y },
1479
+ { type: "tag", pattern: /!?\[[^\]\n]*\]\([^)\n]*\)/y },
1480
+ { type: "punctuation", pattern: /^[-*+]\s|^\d+\.\s/my }
1481
+ ]
1482
+ };
1483
+ var yamlGrammar = {
1484
+ rules: [
1485
+ { type: "comment", pattern: /#[^\n]*/y },
1486
+ { type: "property", pattern: /^[ \t]*[\w.-]+(?=\s*:)/my },
1487
+ { type: "string", pattern: /"(?:[^"\\\n]|\\.)*"|'[^'\n]*'/y },
1488
+ { type: "boolean", pattern: KEYWORD("true|false|null|yes|no|on|off|True|False|Null") },
1489
+ { type: "number", pattern: /-?\b\d+\.?\d*\b/y },
1490
+ { type: "variable", pattern: /[&*][\w-]+/y },
1491
+ { type: "punctuation", pattern: /[:\-[\]{},]/y }
1492
+ ]
1493
+ };
1494
+ var sqlGrammar = {
1495
+ rules: [
1496
+ { type: "comment", pattern: /--[^\n]*|\/\*[\s\S]*?\*\//y },
1497
+ { type: "string", pattern: /'(?:[^'\\\n]|\\.)*'/y },
1498
+ {
1499
+ type: "keyword",
1500
+ pattern: new RegExp(
1501
+ "\\b(?:SELECT|FROM|WHERE|INSERT|INTO|VALUES|UPDATE|SET|DELETE|CREATE|TABLE|ALTER|DROP|JOIN|INNER|LEFT|RIGHT|OUTER|ON|GROUP|BY|ORDER|HAVING|LIMIT|OFFSET|AS|AND|OR|NOT|NULL|IS|IN|LIKE|BETWEEN|DISTINCT|UNION|ALL|EXISTS|CASE|WHEN|THEN|ELSE|END|PRIMARY|KEY|FOREIGN|REFERENCES|DEFAULT|CONSTRAINT|INDEX|VIEW|WITH)\\b",
1502
+ "iy"
1503
+ )
1504
+ },
1505
+ { type: "number", pattern: /\b\d+\.?\d*\b/y },
1506
+ { type: "function", pattern: /\b[A-Za-z_]\w*(?=\s*\()/y },
1507
+ { type: "punctuation", pattern: /[(),;.*=<>!]/y }
1508
+ ]
1509
+ };
1510
+ var GRAMMARS = {
1511
+ javascript: jsGrammar,
1512
+ typescript: jsGrammar,
1513
+ jsx: jsxGrammar,
1514
+ tsx: jsxGrammar,
1515
+ json: jsonGrammar,
1516
+ css: cssGrammar,
1517
+ html: htmlGrammar,
1518
+ bash: bashGrammar,
1519
+ python: pythonGrammar,
1520
+ markdown: markdownGrammar,
1521
+ yaml: yamlGrammar,
1522
+ sql: sqlGrammar
1523
+ };
1524
+ var ALIASES = {
1525
+ js: "javascript",
1526
+ mjs: "javascript",
1527
+ cjs: "javascript",
1528
+ ts: "typescript",
1529
+ sh: "bash",
1530
+ shell: "bash",
1531
+ zsh: "bash",
1532
+ py: "python",
1533
+ md: "markdown",
1534
+ htm: "html",
1535
+ yml: "yaml"
1536
+ };
1537
+ var LANGUAGE_LABELS = {
1538
+ javascript: "JavaScript",
1539
+ typescript: "TypeScript",
1540
+ jsx: "JSX",
1541
+ tsx: "TSX",
1542
+ json: "JSON",
1543
+ css: "CSS",
1544
+ html: "HTML",
1545
+ bash: "Shell",
1546
+ python: "Python",
1547
+ markdown: "Markdown",
1548
+ yaml: "YAML",
1549
+ sql: "SQL",
1550
+ plaintext: "Plain text"
1551
+ };
1552
+ function normalizeLanguage(language) {
1553
+ const lower = language.trim().toLowerCase();
1554
+ return ALIASES[lower] ?? lower;
1555
+ }
1556
+ var nuvoxHighlight = (code, language) => {
1557
+ const key = normalizeLanguage(language ?? "plaintext");
1558
+ const grammar = GRAMMARS[key];
1559
+ if (!grammar) return splitIntoLines([{ type: "plain", content: code }]);
1560
+ try {
1561
+ return splitIntoLines(tokenizeFlat(code, grammar));
1562
+ } catch {
1563
+ return splitIntoLines([{ type: "plain", content: code }]);
1564
+ }
1565
+ };
1566
+
1567
+ // src/core/rich-text.ts
1568
+ var MARK_TAGS = {
1569
+ bold: "STRONG",
1570
+ italic: "EM",
1571
+ underline: "U",
1572
+ strike: "S",
1573
+ code: "CODE"
1574
+ };
1575
+ var BLOCK_TAGS = {
1576
+ paragraph: "P",
1577
+ h1: "H1",
1578
+ h2: "H2",
1579
+ h3: "H3",
1580
+ blockquote: "BLOCKQUOTE",
1581
+ bulletList: "UL",
1582
+ orderedList: "OL"
1583
+ };
1584
+ var BLOCK_TAG_NAMES = /* @__PURE__ */ new Set(["P", "H1", "H2", "H3", "BLOCKQUOTE", "DIV"]);
1585
+ function isMark(command) {
1586
+ return command in MARK_TAGS;
1587
+ }
1588
+ function isBlock(command) {
1589
+ return command in BLOCK_TAGS;
1590
+ }
1591
+ function isCommandActive(ancestorTags, command) {
1592
+ if (command === "link") return ancestorTags.includes("A");
1593
+ if (command === "unlink") return false;
1594
+ if (isMark(command)) return ancestorTags.includes(MARK_TAGS[command]);
1595
+ if (isBlock(command)) return ancestorTags.includes(BLOCK_TAGS[command]);
1596
+ return false;
1597
+ }
1598
+ function closestWithinRoot(node, tag, root) {
1599
+ let n = node;
1600
+ while (n && n !== root) {
1601
+ if (n.nodeType === Node.ELEMENT_NODE && n.tagName === tag) return n;
1602
+ n = n.parentNode;
1603
+ }
1604
+ return null;
1605
+ }
1606
+ function closestBlock(node, root) {
1607
+ let n = node && node.nodeType === Node.ELEMENT_NODE ? node : node?.parentNode ?? null;
1608
+ while (n && n !== root) {
1609
+ if (n.nodeType === Node.ELEMENT_NODE && BLOCK_TAG_NAMES.has(n.tagName)) return n;
1610
+ n = n.parentNode;
1611
+ }
1612
+ return null;
1613
+ }
1614
+ function unwrapElement(el) {
1615
+ const parent = el.parentNode;
1616
+ if (!parent) return;
1617
+ while (el.firstChild) parent.insertBefore(el.firstChild, el);
1618
+ parent.removeChild(el);
1619
+ }
1620
+ function replaceTag(el, tag) {
1621
+ const next = document.createElement(tag);
1622
+ while (el.firstChild) next.appendChild(el.firstChild);
1623
+ el.parentNode?.replaceChild(next, el);
1624
+ return next;
1625
+ }
1626
+ function selectNodeContents(node, collapseToEnd = false) {
1627
+ const sel = window.getSelection();
1628
+ if (!sel) return;
1629
+ const range = document.createRange();
1630
+ range.selectNodeContents(node);
1631
+ if (collapseToEnd) range.collapse(false);
1632
+ sel.removeAllRanges();
1633
+ sel.addRange(range);
1634
+ }
1635
+ var ZERO_WIDTH_SPACE = "\u200B";
1636
+ function selectAtMarker(sel, marker, offset) {
1637
+ const range = document.createRange();
1638
+ range.setStart(marker, offset);
1639
+ range.collapse(true);
1640
+ sel.removeAllRanges();
1641
+ sel.addRange(range);
1642
+ }
1643
+ function togglePendingMark(root, tag) {
1644
+ const sel = window.getSelection();
1645
+ if (!sel || sel.rangeCount === 0) return;
1646
+ const range = sel.getRangeAt(0);
1647
+ const existing = closestWithinRoot(range.startContainer, tag, root);
1648
+ if (existing) {
1649
+ const marker2 = document.createTextNode(ZERO_WIDTH_SPACE);
1650
+ existing.parentNode?.insertBefore(marker2, existing.nextSibling);
1651
+ selectAtMarker(sel, marker2, 1);
1652
+ return;
1653
+ }
1654
+ const wrapper = document.createElement(tag);
1655
+ const marker = document.createTextNode(ZERO_WIDTH_SPACE);
1656
+ wrapper.appendChild(marker);
1657
+ range.insertNode(wrapper);
1658
+ selectAtMarker(sel, marker, 1);
1659
+ }
1660
+ function toggleMark(root, tag) {
1661
+ const sel = window.getSelection();
1662
+ if (!sel || sel.rangeCount === 0) return;
1663
+ if (sel.isCollapsed) {
1664
+ togglePendingMark(root, tag);
1665
+ return;
1666
+ }
1667
+ const range = sel.getRangeAt(0);
1668
+ const existing = closestWithinRoot(range.commonAncestorContainer, tag, root);
1669
+ if (existing) {
1670
+ unwrapElement(existing);
1671
+ return;
1672
+ }
1673
+ const wrapper = document.createElement(tag);
1674
+ wrapper.appendChild(range.extractContents());
1675
+ range.insertNode(wrapper);
1676
+ selectNodeContents(wrapper);
1677
+ }
1678
+ function restoreSelection(range) {
1679
+ const sel = window.getSelection();
1680
+ if (!sel) return;
1681
+ sel.removeAllRanges();
1682
+ sel.addRange(range);
1683
+ }
1684
+ function stripEmptyMarkers(root) {
1685
+ const isRootFocused = typeof document !== "undefined" && root.contains(document.activeElement);
1686
+ const sel = isRootFocused ? window.getSelection() : null;
1687
+ const caretNode = sel && sel.rangeCount > 0 ? sel.getRangeAt(0).startContainer : null;
1688
+ const candidateTags = [...Object.values(MARK_TAGS), "SPAN"];
1689
+ let changed = false;
1690
+ for (const tag of candidateTags) {
1691
+ for (const el of Array.from(root.getElementsByTagName(tag))) {
1692
+ if (el.textContent === ZERO_WIDTH_SPACE && !(caretNode && el.contains(caretNode))) {
1693
+ el.remove();
1694
+ changed = true;
1695
+ }
1696
+ }
1697
+ }
1698
+ return changed;
1699
+ }
1700
+ function setBlockTag(root, targetTag) {
1701
+ const sel = window.getSelection();
1702
+ if (!sel || sel.rangeCount === 0) return;
1703
+ const block = closestBlock(sel.getRangeAt(0).startContainer, root);
1704
+ if (!block) return;
1705
+ const next = replaceTag(block, block.tagName === targetTag ? "P" : targetTag);
1706
+ selectNodeContents(next, true);
1707
+ }
1708
+ function toggleList(root, listTag) {
1709
+ const sel = window.getSelection();
1710
+ if (!sel || sel.rangeCount === 0) return;
1711
+ const range = sel.getRangeAt(0);
1712
+ const li = closestWithinRoot(range.startContainer, "LI", root);
1713
+ if (li && li.parentElement?.tagName === listTag) {
1714
+ const list2 = li.parentElement;
1715
+ const p = document.createElement("P");
1716
+ while (li.firstChild) p.appendChild(li.firstChild);
1717
+ list2.parentNode?.replaceChild(p, list2);
1718
+ selectNodeContents(p, true);
1719
+ return;
1720
+ }
1721
+ const block = closestBlock(range.startContainer, root);
1722
+ if (!block) return;
1723
+ const list = document.createElement(listTag);
1724
+ const item = document.createElement("LI");
1725
+ while (block.firstChild) item.appendChild(block.firstChild);
1726
+ list.appendChild(item);
1727
+ block.parentNode?.replaceChild(list, block);
1728
+ selectNodeContents(item, true);
1729
+ }
1730
+ function setLink(root, url) {
1731
+ const sel = window.getSelection();
1732
+ if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
1733
+ const range = sel.getRangeAt(0);
1734
+ const existing = closestWithinRoot(range.commonAncestorContainer, "A", root);
1735
+ if (existing) {
1736
+ existing.setAttribute("href", url);
1737
+ return;
1738
+ }
1739
+ const a = document.createElement("A");
1740
+ a.setAttribute("href", url);
1741
+ a.setAttribute("rel", "noopener noreferrer");
1742
+ a.appendChild(range.extractContents());
1743
+ range.insertNode(a);
1744
+ selectNodeContents(a);
1745
+ }
1746
+ function unlink(root) {
1747
+ const sel = window.getSelection();
1748
+ if (!sel || sel.rangeCount === 0) return;
1749
+ const a = closestWithinRoot(sel.getRangeAt(0).commonAncestorContainer, "A", root);
1750
+ if (a) unwrapElement(a);
1751
+ }
1752
+ function findStyledSpanWithinRoot(node, property, root) {
1753
+ let n = node;
1754
+ while (n && n !== root) {
1755
+ if (n.nodeType === Node.ELEMENT_NODE) {
1756
+ const el = n;
1757
+ if (el.tagName === "SPAN" && el.style.getPropertyValue(property)) return el;
1758
+ }
1759
+ n = n.parentNode;
1760
+ }
1761
+ return null;
1762
+ }
1763
+ function setInlineStyle(root, property, value) {
1764
+ const sel = window.getSelection();
1765
+ if (!sel || sel.rangeCount === 0) return;
1766
+ const range = sel.getRangeAt(0);
1767
+ if (sel.isCollapsed) {
1768
+ const existing2 = findStyledSpanWithinRoot(range.startContainer, property, root);
1769
+ if (existing2) {
1770
+ existing2.style.setProperty(property, value);
1771
+ return;
1772
+ }
1773
+ const wrapper2 = document.createElement("span");
1774
+ wrapper2.style.setProperty(property, value);
1775
+ const marker = document.createTextNode(ZERO_WIDTH_SPACE);
1776
+ wrapper2.appendChild(marker);
1777
+ range.insertNode(wrapper2);
1778
+ selectAtMarker(sel, marker, 1);
1779
+ return;
1780
+ }
1781
+ const existing = findStyledSpanWithinRoot(range.commonAncestorContainer, property, root);
1782
+ if (existing) {
1783
+ existing.style.setProperty(property, value);
1784
+ return;
1785
+ }
1786
+ const wrapper = document.createElement("span");
1787
+ wrapper.style.setProperty(property, value);
1788
+ wrapper.appendChild(range.extractContents());
1789
+ range.insertNode(wrapper);
1790
+ selectNodeContents(wrapper);
1791
+ }
1792
+ function clearInlineStyle(root, property) {
1793
+ const sel = window.getSelection();
1794
+ if (!sel || sel.rangeCount === 0) return;
1795
+ const el = findStyledSpanWithinRoot(sel.getRangeAt(0).commonAncestorContainer, property, root);
1796
+ if (!el) return;
1797
+ el.style.removeProperty(property);
1798
+ if (!el.getAttribute("style")) unwrapElement(el);
1799
+ }
1800
+ function execRichTextCommand(root, command, value) {
1801
+ if (isMark(command)) toggleMark(root, MARK_TAGS[command]);
1802
+ else if (command === "bulletList") toggleList(root, "UL");
1803
+ else if (command === "orderedList") toggleList(root, "OL");
1804
+ else if (isBlock(command)) setBlockTag(root, BLOCK_TAGS[command]);
1805
+ else if (command === "link" && value) setLink(root, value);
1806
+ else if (command === "unlink") unlink(root);
1807
+ else if (command === "textColor" && value) setInlineStyle(root, "color", value);
1808
+ else if (command === "clearTextColor") clearInlineStyle(root, "color");
1809
+ else if (command === "highlight" && value) setInlineStyle(root, "background-color", value);
1810
+ else if (command === "clearHighlight") clearInlineStyle(root, "background-color");
1811
+ }
1812
+ function getActiveCommands(root) {
1813
+ const result = /* @__PURE__ */ new Set();
1814
+ if (typeof window === "undefined") return result;
1815
+ const sel = window.getSelection();
1816
+ if (!sel || sel.rangeCount === 0) return result;
1817
+ const tags = [];
1818
+ let node = sel.anchorNode;
1819
+ while (node && node !== root) {
1820
+ if (node.nodeType === Node.ELEMENT_NODE) tags.push(node.tagName);
1821
+ node = node.parentNode;
1822
+ }
1823
+ const commands = [...Object.keys(MARK_TAGS), ...Object.keys(BLOCK_TAGS), "link"];
1824
+ for (const command of commands) {
1825
+ if (isCommandActive(tags, command)) result.add(command);
1826
+ }
1827
+ return result;
1828
+ }
1829
+ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
1830
+ "P",
1831
+ "BR",
1832
+ "STRONG",
1833
+ "B",
1834
+ "EM",
1835
+ "I",
1836
+ "U",
1837
+ "S",
1838
+ "STRIKE",
1839
+ "CODE",
1840
+ "A",
1841
+ "H1",
1842
+ "H2",
1843
+ "H3",
1844
+ "BLOCKQUOTE",
1845
+ "UL",
1846
+ "OL",
1847
+ "LI",
1848
+ "SPAN"
1849
+ ]);
1850
+ var ALLOWED_ATTRS = {
1851
+ A: ["href"],
1852
+ SPAN: ["style"]
1853
+ };
1854
+ var ALLOWED_STYLE_PROPS = /* @__PURE__ */ new Set(["color", "background-color"]);
1855
+ var SAFE_COLOR_VALUE = /^(#[0-9a-fA-F]{3,8}|rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)|hsl\([^();]*\)|hsla\([^();]*\)|[a-zA-Z]+)$/;
1856
+ function sanitizeStyleAttr(value) {
1857
+ const out = [];
1858
+ for (const decl of value.split(";")) {
1859
+ const colon = decl.indexOf(":");
1860
+ if (colon === -1) continue;
1861
+ const prop = decl.slice(0, colon).trim().toLowerCase();
1862
+ const val = decl.slice(colon + 1).trim();
1863
+ if (ALLOWED_STYLE_PROPS.has(prop) && SAFE_COLOR_VALUE.test(val)) {
1864
+ out.push(`${prop}: ${val}`);
1865
+ }
1866
+ }
1867
+ return out.join("; ");
1868
+ }
1869
+ var STRIP_ENTIRELY = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "IFRAME", "OBJECT", "EMBED"]);
1870
+ function sanitizeElement(el) {
1871
+ for (const child of Array.from(el.childNodes)) {
1872
+ if (child.nodeType === Node.TEXT_NODE) continue;
1873
+ if (child.nodeType !== Node.ELEMENT_NODE) {
1874
+ child.parentNode?.removeChild(child);
1875
+ continue;
1876
+ }
1877
+ const childEl = child;
1878
+ if (STRIP_ENTIRELY.has(childEl.tagName)) {
1879
+ childEl.parentNode?.removeChild(childEl);
1880
+ continue;
1881
+ }
1882
+ if (!ALLOWED_TAGS.has(childEl.tagName)) {
1883
+ sanitizeElement(childEl);
1884
+ const parent = childEl.parentNode;
1885
+ while (childEl.firstChild) parent?.insertBefore(childEl.firstChild, childEl);
1886
+ parent?.removeChild(childEl);
1887
+ continue;
1888
+ }
1889
+ const allowedAttrs = ALLOWED_ATTRS[childEl.tagName] ?? [];
1890
+ for (const attr of Array.from(childEl.attributes)) {
1891
+ const name = attr.name.toLowerCase();
1892
+ if (!allowedAttrs.includes(name)) {
1893
+ childEl.removeAttribute(attr.name);
1894
+ continue;
1895
+ }
1896
+ if (name === "style") {
1897
+ const cleaned = sanitizeStyleAttr(attr.value);
1898
+ if (cleaned) childEl.setAttribute("style", cleaned);
1899
+ else childEl.removeAttribute("style");
1900
+ }
1901
+ }
1902
+ if (childEl.tagName === "A") {
1903
+ const href = childEl.getAttribute("href") ?? "";
1904
+ const safe = /^https?:\/\//i.test(href) || href.startsWith("/") || href.startsWith("#") || href.startsWith("mailto:");
1905
+ if (!safe) childEl.removeAttribute("href");
1906
+ childEl.setAttribute("rel", "noopener noreferrer");
1907
+ childEl.setAttribute("target", "_blank");
1908
+ }
1909
+ sanitizeElement(childEl);
1910
+ }
1911
+ }
1912
+ function sanitizeHtml(html) {
1913
+ if (typeof DOMParser === "undefined") return "";
1914
+ const doc = new DOMParser().parseFromString(html, "text/html");
1915
+ sanitizeElement(doc.body);
1916
+ return doc.body.innerHTML;
1917
+ }
1918
+ var HISTORY_LIMIT = 100;
1919
+ function createHistory() {
1920
+ return { past: [], future: [] };
1921
+ }
1922
+ function pushHistory(history, previousValue) {
1923
+ return { past: [...history.past, previousValue].slice(-HISTORY_LIMIT), future: [] };
1924
+ }
1925
+ function undoHistory(history, currentValue) {
1926
+ if (history.past.length === 0) return null;
1927
+ const value = history.past[history.past.length - 1];
1928
+ return {
1929
+ history: { past: history.past.slice(0, -1), future: [currentValue, ...history.future] },
1930
+ value
1931
+ };
1932
+ }
1933
+ function redoHistory(history, currentValue) {
1934
+ if (history.future.length === 0) return null;
1935
+ const value = history.future[0];
1936
+ return {
1937
+ history: { past: [...history.past, currentValue], future: history.future.slice(1) },
1938
+ value
1939
+ };
1940
+ }
1941
+ function resolveRichTextEditorState(props) {
1942
+ return {
1943
+ isDisabled: props.disabled ?? false,
1944
+ isReadOnly: props.readOnly ?? false,
1945
+ placeholder: props.placeholder ?? "",
1946
+ size: props.size ?? "md"
1947
+ };
1948
+ }
1949
+ function getRichTextEditorClasses(state) {
1950
+ return [
1951
+ "nx-rich-text",
1952
+ `nx-rich-text--${state.size}`,
1953
+ state.isDisabled && "nx-rich-text--disabled",
1954
+ state.isReadOnly && "nx-rich-text--readonly"
1955
+ ].filter(Boolean).join(" ");
1956
+ }
1957
+
1958
+ // src/core/gallery.ts
1959
+ function resolveGalleryState(props) {
1960
+ return {
1961
+ layout: props.layout ?? "grid",
1962
+ columns: props.columns ?? 3,
1963
+ gap: props.gap,
1964
+ targetRowHeight: props.targetRowHeight ?? 220
1965
+ };
1966
+ }
1967
+ function getGalleryClasses(state, className) {
1968
+ return ["nx-gallery", `nx-gallery--${state.layout}`, className].filter(Boolean).join(" ");
1969
+ }
1970
+ function getGalleryStyle(state) {
1971
+ const style = {};
1972
+ if (state.gap) style.gap = state.gap;
1973
+ if (state.layout === "grid" || state.layout === "masonry") {
1974
+ style["--nx-gallery-columns"] = String(state.columns);
1975
+ }
1976
+ return style;
1977
+ }
1978
+ function aspectRatioFromDims(width, height) {
1979
+ if (!width || !height || width <= 0 || height <= 0) return 1;
1980
+ return width / height;
1981
+ }
1982
+ function computeJustifiedRows(aspectRatios, containerWidth, targetRowHeight, gap) {
1983
+ if (aspectRatios.length === 0 || containerWidth <= 0 || targetRowHeight <= 0) return [];
1984
+ const rows = [];
1985
+ let rowIndices = [];
1986
+ let rowNaturalWidths = [];
1987
+ let rowWidthSum = 0;
1988
+ function flushRow(scale) {
1989
+ if (rowIndices.length === 0) return;
1990
+ const gapsWidth = gap * (rowIndices.length - 1);
1991
+ const availableWidth = containerWidth - gapsWidth;
1992
+ const naturalTotal = rowWidthSum;
1993
+ const scaleFactor = scale ? availableWidth / naturalTotal : 1;
1994
+ rows.push({
1995
+ indices: rowIndices,
1996
+ height: targetRowHeight * scaleFactor,
1997
+ widths: rowNaturalWidths.map((w) => w * scaleFactor)
1998
+ });
1999
+ rowIndices = [];
2000
+ rowNaturalWidths = [];
2001
+ rowWidthSum = 0;
2002
+ }
2003
+ for (let i = 0; i < aspectRatios.length; i++) {
2004
+ const naturalWidth = aspectRatios[i] * targetRowHeight;
2005
+ const gapsWidth = gap * rowIndices.length;
2006
+ if (rowIndices.length > 0 && rowWidthSum + naturalWidth + gapsWidth > containerWidth) {
2007
+ flushRow(true);
2008
+ }
2009
+ rowIndices.push(i);
2010
+ rowNaturalWidths.push(naturalWidth);
2011
+ rowWidthSum += naturalWidth;
2012
+ }
2013
+ const finalGapsWidth = gap * (rowIndices.length - 1);
2014
+ const overflows = rowWidthSum + finalGapsWidth > containerWidth;
2015
+ flushRow(overflows);
2016
+ return rows;
2017
+ }
2018
+
2019
+ // src/core/slider.ts
2020
+ function isRangeValue(value) {
2021
+ return Array.isArray(value);
2022
+ }
2023
+ function toThumbs(value) {
2024
+ return isRangeValue(value) ? [value[0], value[1]] : [value];
2025
+ }
2026
+ function fromThumbs(thumbs, like) {
2027
+ return isRangeValue(like) ? [thumbs[0], thumbs[1]] : thumbs[0];
2028
+ }
2029
+ function resolveSliderState(props) {
2030
+ return {
2031
+ // ?? not || (CONTRACT.md Rule 3) — an explicit min={0} must not
2032
+ // be discarded (it already is the default, but a future
2033
+ // negative-range default would make this the exact bug Rule 3
2034
+ // guards against).
2035
+ min: props.min ?? 0,
2036
+ max: props.max ?? 100,
2037
+ step: props.step ?? 1,
2038
+ isDisabled: props.disabled ?? false,
2039
+ size: props.size ?? "md"
2040
+ };
2041
+ }
2042
+ function clampAndSnap(value, state) {
2043
+ const { min, max, step } = state;
2044
+ const clamped = Math.min(Math.max(value, min), max);
2045
+ if (step <= 0) return clamped;
2046
+ const steps = Math.round((clamped - min) / step);
2047
+ const snapped = min + steps * step;
2048
+ return Math.min(Math.max(snapped, min), max);
2049
+ }
2050
+ function valueToPercent(value, min, max) {
2051
+ if (max === min) return 0;
2052
+ return (value - min) / (max - min) * 100;
2053
+ }
2054
+ function percentToValue(percent, min, max) {
2055
+ return min + percent / 100 * (max - min);
2056
+ }
2057
+ function clampRangeThumb(thumbs, index, next, minGap = 0) {
2058
+ if (index === 0) return Math.min(next, thumbs[1] - minGap);
2059
+ return Math.max(next, thumbs[0] + minGap);
2060
+ }
2061
+ function nearestThumbIndex(thumbs, targetValue) {
2062
+ const distLow = Math.abs(thumbs[0] - targetValue);
2063
+ const distHigh = Math.abs(thumbs[1] - targetValue);
2064
+ return distHigh < distLow ? 1 : 0;
2065
+ }
2066
+ var STEP_KEYS_UP = /* @__PURE__ */ new Set(["ArrowRight", "ArrowUp"]);
2067
+ var STEP_KEYS_DOWN = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowDown"]);
2068
+ function getKeyboardValue(key, current, state) {
2069
+ const bigStep = Math.min(state.step * 10, state.max - state.min);
2070
+ if (STEP_KEYS_UP.has(key)) return clampAndSnap(current + state.step, state);
2071
+ if (STEP_KEYS_DOWN.has(key)) return clampAndSnap(current - state.step, state);
2072
+ if (key === "PageUp") return clampAndSnap(current + bigStep, state);
2073
+ if (key === "PageDown") return clampAndSnap(current - bigStep, state);
2074
+ if (key === "Home") return state.min;
2075
+ if (key === "End") return state.max;
2076
+ return null;
2077
+ }
2078
+ function getRootClasses(state, isRange, showValueLabel, className) {
2079
+ return [
2080
+ "nx-slider",
2081
+ `nx-slider--${state.size}`,
2082
+ isRange && "nx-slider--range",
2083
+ state.isDisabled && "nx-slider--disabled",
2084
+ // The value-label bubble floats above the thumb (see
2085
+ // Slider.css) — with no room reserved for it, it overflows
2086
+ // .nx-slider's own box and lands on whatever's above it in
2087
+ // .nx-field, which for a slider with a `label` is the label
2088
+ // text itself. This adds the top margin the bubble actually
2089
+ // needs instead of relying on .nx-field's generic 4px gap.
2090
+ showValueLabel && "nx-slider--with-value-label",
2091
+ className
2092
+ ].filter(Boolean).join(" ");
2093
+ }
2094
+ function getThumbAriaProps(input) {
2095
+ return {
2096
+ role: "slider",
2097
+ "aria-valuemin": input.min,
2098
+ "aria-valuemax": input.max,
2099
+ "aria-valuenow": input.value,
2100
+ "aria-valuetext": input.valueText,
2101
+ "aria-orientation": "horizontal",
2102
+ "aria-disabled": input.isDisabled || void 0,
2103
+ "aria-labelledby": input.labelledBy,
2104
+ tabIndex: input.isDisabled ? -1 : 0
2105
+ };
2106
+ }
2107
+
2108
+ // src/core/media.ts
2109
+ var PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
2110
+ function formatMediaTime(seconds) {
2111
+ if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
2112
+ const total = Math.floor(seconds);
2113
+ const h = Math.floor(total / 3600);
2114
+ const m = Math.floor(total % 3600 / 60);
2115
+ const s = total % 60;
2116
+ const paddedS = String(s).padStart(2, "0");
2117
+ if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${paddedS}`;
2118
+ return `${m}:${paddedS}`;
2119
+ }
2120
+ function clampVolume(volume) {
2121
+ return clampAndSnap(volume, { min: 0, max: 1, step: 0 });
2122
+ }
2123
+ function positionToTime(clientX, trackRect, duration) {
2124
+ if (trackRect.width <= 0 || !Number.isFinite(duration) || duration <= 0) return 0;
2125
+ const rawPercent = (clientX - trackRect.left) / trackRect.width * 100;
2126
+ const percent = clampAndSnap(rawPercent, { min: 0, max: 100, step: 0 });
2127
+ return percentToValue(percent, 0, duration);
2128
+ }
2129
+ function positionToRatio(clientX, trackRect) {
2130
+ return clampVolume(positionToTime(clientX, trackRect, 1));
2131
+ }
2132
+ function getBufferedPercent(bufferedEnd, duration) {
2133
+ if (!Number.isFinite(duration) || duration <= 0) return 0;
2134
+ return clampAndSnap(bufferedEnd / duration * 100, { min: 0, max: 100, step: 0 });
2135
+ }
2136
+ function getProgressPercent(currentTime, duration) {
2137
+ return getBufferedPercent(currentTime, duration);
2138
+ }
2139
+ function recoverDuration(media, restoreTo, onDuration, giveUpMs = 4e3, pollMs = 100) {
2140
+ function isKnown(duration) {
2141
+ return Number.isFinite(duration) && duration > 0;
2142
+ }
2143
+ if (isKnown(media.duration)) {
2144
+ onDuration(media.duration);
2145
+ return () => {
2146
+ };
2147
+ }
2148
+ let settled = false;
2149
+ let pollHandle;
2150
+ let giveUpHandle;
2151
+ function cleanup() {
2152
+ media.removeEventListener("timeupdate", handleResolved);
2153
+ media.removeEventListener("seeked", handleResolved);
2154
+ media.removeEventListener("durationchange", handleResolved);
2155
+ media.removeEventListener("error", handleError);
2156
+ if (pollHandle !== void 0) clearInterval(pollHandle);
2157
+ if (giveUpHandle !== void 0) clearTimeout(giveUpHandle);
2158
+ }
2159
+ function finish(resolvedDuration, restore) {
2160
+ if (settled) return;
2161
+ settled = true;
2162
+ cleanup();
2163
+ if (restore) media.currentTime = restoreTo;
2164
+ onDuration(resolvedDuration);
2165
+ }
2166
+ function handleResolved() {
2167
+ if (isKnown(media.duration)) finish(media.duration, true);
2168
+ }
2169
+ function handleError() {
2170
+ finish(0, false);
2171
+ }
2172
+ media.addEventListener("timeupdate", handleResolved);
2173
+ media.addEventListener("seeked", handleResolved);
2174
+ media.addEventListener("durationchange", handleResolved);
2175
+ media.addEventListener("error", handleError);
2176
+ pollHandle = setInterval(() => {
2177
+ if (isKnown(media.duration)) finish(media.duration, true);
2178
+ }, pollMs);
2179
+ giveUpHandle = setTimeout(() => finish(0, false), giveUpMs);
2180
+ media.currentTime = 1e101;
2181
+ return cleanup;
2182
+ }
2183
+ function getSeekAriaProps(currentTime, duration) {
2184
+ return {
2185
+ role: "slider",
2186
+ "aria-label": "Seek",
2187
+ "aria-valuemin": 0,
2188
+ "aria-valuemax": Math.max(duration, 0),
2189
+ "aria-valuenow": Math.min(Math.max(currentTime, 0), Math.max(duration, 0)),
2190
+ "aria-valuetext": formatMediaTime(currentTime)
2191
+ };
2192
+ }
2193
+ function getVolumeAriaProps(volume, muted) {
2194
+ const pct = Math.round(clampVolume(volume) * 100);
2195
+ return {
2196
+ role: "slider",
2197
+ "aria-label": "Volume",
2198
+ "aria-valuemin": 0,
2199
+ "aria-valuemax": 100,
2200
+ "aria-valuenow": muted ? 0 : pct,
2201
+ "aria-valuetext": muted ? "Muted" : `${pct}%`
2202
+ };
2203
+ }
2204
+ function getPlayButtonAriaProps(isPlaying) {
2205
+ return { "aria-label": isPlaying ? "Pause" : "Play" };
2206
+ }
2207
+ function getMuteButtonAriaProps(isMuted) {
2208
+ return { "aria-label": isMuted ? "Unmute" : "Mute", "aria-pressed": isMuted };
2209
+ }
2210
+ function isEffectivelyMuted(volume, muted) {
2211
+ return muted || volume <= 0;
2212
+ }
2213
+ var SKIP_SECONDS = 10;
2214
+ var LABELED_SKIP_SECONDS = [5, 10, 15, 30];
2215
+ function hasLabeledSkipIcon(seconds) {
2216
+ return LABELED_SKIP_SECONDS.includes(seconds);
2217
+ }
2218
+ function resolveSkipSeconds(skipSeconds) {
2219
+ if (skipSeconds === void 0) return SKIP_SECONDS;
2220
+ if (!Number.isFinite(skipSeconds) || skipSeconds <= 0) return SKIP_SECONDS;
2221
+ return skipSeconds;
2222
+ }
2223
+ function skipTime(currentTime, duration, deltaSeconds) {
2224
+ const max = Number.isFinite(duration) && duration > 0 ? duration : Infinity;
2225
+ return Math.min(Math.max(currentTime + deltaSeconds, 0), max);
2226
+ }
2227
+ function getSkipButtonAriaProps(deltaSeconds) {
2228
+ return { "aria-label": deltaSeconds < 0 ? `Back ${Math.abs(deltaSeconds)} seconds` : `Forward ${deltaSeconds} seconds` };
2229
+ }
2230
+ function resolveMediaTransport(props) {
2231
+ const showNext = props.onNext !== void 0;
2232
+ const showPrevious = props.onPrevious !== void 0;
2233
+ return {
2234
+ skipSeconds: resolveSkipSeconds(props.skipSeconds),
2235
+ showNext,
2236
+ showPrevious,
2237
+ nextDisabled: showNext && (props.hasNext ?? true) === false,
2238
+ previousDisabled: showPrevious && (props.hasPrevious ?? true) === false
2239
+ };
2240
+ }
2241
+ function getTrackButtonAriaProps(direction) {
2242
+ return { "aria-label": direction === "next" ? "Next track" : "Previous track" };
2243
+ }
2244
+ function getMediaKeyAction(key) {
2245
+ switch (key) {
2246
+ case " ":
2247
+ case "Spacebar":
2248
+ return "toggle-play";
2249
+ case "ArrowLeft":
2250
+ return "seek-back";
2251
+ case "ArrowRight":
2252
+ return "seek-forward";
2253
+ case "ArrowUp":
2254
+ return "volume-up";
2255
+ case "ArrowDown":
2256
+ return "volume-down";
2257
+ default:
2258
+ return null;
2259
+ }
2260
+ }
2261
+
2262
+ // src/core/pdf-viewer.ts
2263
+ function resolvePdfViewerState(props) {
2264
+ return {
2265
+ initialPage: props.initialPage ?? 1,
2266
+ initialScale: props.initialScale ?? "auto",
2267
+ minScale: props.minScale ?? 0.5,
2268
+ maxScale: props.maxScale ?? 3,
2269
+ scaleStep: props.scaleStep ?? 0.25
2270
+ };
2271
+ }
2272
+ function getPdfViewerClasses(className) {
2273
+ return ["nx-pdf-viewer", className].filter(Boolean).join(" ");
2274
+ }
2275
+ function clampPage(page) {
2276
+ return Math.max(Math.round(page), 1);
2277
+ }
2278
+ function clampScale(scale, min, max) {
2279
+ return Math.min(Math.max(scale, min), max);
2280
+ }
2281
+ function resolveZoomBase(scale, fitScale) {
2282
+ return scale === "auto" ? fitScale : scale;
2283
+ }
2284
+ function zoomIn(scale, step, max, fitScale = 1) {
2285
+ return clampScale(resolveZoomBase(scale, fitScale) + step, 0, max);
2286
+ }
2287
+ function zoomOut(scale, step, min, fitScale = 1) {
2288
+ return clampScale(resolveZoomBase(scale, fitScale) - step, min, Infinity);
2289
+ }
2290
+ function isZoomAtMin(scale, min) {
2291
+ return scale !== "auto" && scale <= min;
2292
+ }
2293
+ function isZoomAtMax(scale, max) {
2294
+ return scale !== "auto" && scale >= max;
2295
+ }
2296
+ function estimateFitScale(iframeWidthPx, pageWidthPt = 612) {
2297
+ if (iframeWidthPx <= 0 || pageWidthPt <= 0) return 1;
2298
+ const pageWidthPx = pageWidthPt * (96 / 72);
2299
+ return iframeWidthPx / pageWidthPx;
2300
+ }
2301
+ function formatZoomPercent(scale) {
2302
+ return scale === "auto" ? "Fit" : `${Math.round(scale * 100)}%`;
2303
+ }
2304
+ function buildPdfSrc(src, page, scale) {
2305
+ const base = src.split("#")[0];
2306
+ const zoomParam = scale === "auto" ? "page-width" : Math.round(scale * 100);
2307
+ return `${base}#page=${clampPage(page)}&zoom=${zoomParam}`;
2308
+ }
2309
+
2310
+ export {
2311
+ defineTheme,
2312
+ TOKEN_CATEGORIES,
2313
+ REQUIRED_TOKEN_PATHS,
2314
+ findMissingTokenPaths,
2315
+ light,
2316
+ dark,
2317
+ glass,
2318
+ darkGlass,
2319
+ minimalism,
2320
+ brutalism,
2321
+ neobrutalism,
2322
+ cyberpunk,
2323
+ gradient,
2324
+ material,
2325
+ skeuomorphism,
2326
+ registerTheme,
2327
+ getTheme,
2328
+ listThemes,
2329
+ indigo,
2330
+ violet,
2331
+ teal,
2332
+ rose,
2333
+ amber,
2334
+ emerald,
2335
+ copper,
2336
+ graphite,
2337
+ magenta,
2338
+ registerAccent,
2339
+ getAccent,
2340
+ listAccents,
2341
+ DEFAULT_ACCENT,
2342
+ resolveFieldState,
2343
+ getFieldAriaProps,
2344
+ DEFAULT_PRESETS,
2345
+ resolveColorPickerState,
2346
+ normalizeHex,
2347
+ isSameColor,
2348
+ getSwatchClasses,
2349
+ getSwatchGridAriaProps,
2350
+ getSwatchAriaProps,
2351
+ getFieldTriggerAriaProps,
2352
+ COLOR_FORMATS,
2353
+ hexToRgb,
2354
+ rgbToHex,
2355
+ rgbToHsl,
2356
+ hexToHsv,
2357
+ hsvToHex,
2358
+ hslToHex,
2359
+ parseColorInput,
2360
+ formatColorValue,
2361
+ getSvKeyboardDelta,
2362
+ clampPercent,
2363
+ getFormatTabClasses,
2364
+ getFormatTablistAriaProps,
2365
+ getFormatTabAriaProps,
2366
+ getSvThumbAriaProps,
2367
+ resolveTableState,
2368
+ getWrapperClasses,
2369
+ getTableClasses,
2370
+ getRowClasses,
2371
+ getHeadCellClasses,
2372
+ getCellClasses,
2373
+ getNextSortDirection,
2374
+ getSortAriaProps,
2375
+ getSelectAllState,
2376
+ DRAG_START_THRESHOLD_PX,
2377
+ resolveKanbanState,
2378
+ getBoardClasses,
2379
+ getColumnClasses,
2380
+ getColumnCountClasses,
2381
+ getCardWrapperClasses,
2382
+ findCardLocation,
2383
+ removeCard,
2384
+ moveCard,
2385
+ getAdjacentColumnId,
2386
+ getKeyboardMoveTarget,
2387
+ computeDropIndex,
2388
+ computeDropColumn,
2389
+ moveColumn,
2390
+ removeColumn,
2391
+ getColumnKeyboardMoveTarget,
2392
+ computeColumnDropIndex,
2393
+ LANGUAGE_LABELS,
2394
+ normalizeLanguage,
2395
+ nuvoxHighlight,
2396
+ restoreSelection,
2397
+ stripEmptyMarkers,
2398
+ execRichTextCommand,
2399
+ getActiveCommands,
2400
+ sanitizeHtml,
2401
+ createHistory,
2402
+ pushHistory,
2403
+ undoHistory,
2404
+ redoHistory,
2405
+ resolveRichTextEditorState,
2406
+ getRichTextEditorClasses,
2407
+ resolveGalleryState,
2408
+ getGalleryClasses,
2409
+ getGalleryStyle,
2410
+ aspectRatioFromDims,
2411
+ computeJustifiedRows,
2412
+ isRangeValue,
2413
+ toThumbs,
2414
+ fromThumbs,
2415
+ resolveSliderState,
2416
+ clampAndSnap,
2417
+ valueToPercent,
2418
+ percentToValue,
2419
+ clampRangeThumb,
2420
+ nearestThumbIndex,
2421
+ getKeyboardValue,
2422
+ getRootClasses,
2423
+ getThumbAriaProps,
2424
+ PLAYBACK_RATES,
2425
+ formatMediaTime,
2426
+ clampVolume,
2427
+ positionToTime,
2428
+ positionToRatio,
2429
+ getBufferedPercent,
2430
+ getProgressPercent,
2431
+ recoverDuration,
2432
+ getSeekAriaProps,
2433
+ getVolumeAriaProps,
2434
+ getPlayButtonAriaProps,
2435
+ getMuteButtonAriaProps,
2436
+ isEffectivelyMuted,
2437
+ SKIP_SECONDS,
2438
+ LABELED_SKIP_SECONDS,
2439
+ hasLabeledSkipIcon,
2440
+ resolveSkipSeconds,
2441
+ skipTime,
2442
+ getSkipButtonAriaProps,
2443
+ resolveMediaTransport,
2444
+ getTrackButtonAriaProps,
2445
+ getMediaKeyAction,
2446
+ resolvePdfViewerState,
2447
+ getPdfViewerClasses,
2448
+ clampPage,
2449
+ zoomIn,
2450
+ zoomOut,
2451
+ isZoomAtMin,
2452
+ isZoomAtMax,
2453
+ estimateFitScale,
2454
+ formatZoomPercent,
2455
+ buildPdfSrc
2456
+ };
2457
+ //# sourceMappingURL=chunk-HAMPWL7I.js.map