nuvox 0.1.2 → 0.1.4

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/CHANGELOG.md CHANGED
@@ -3,6 +3,123 @@
3
3
  All notable changes to this project are documented here.
4
4
  Format loosely follows [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
+ ## [0.1.4]
7
+
8
+ ### Fixed
9
+ - The `[data-nuvox-portal]` exemption added in 0.1.3 fixed a nested
10
+ overlay closing its own container, but was too broad: it exempted
11
+ a click inside ANY portal, including one belonging to a completely
12
+ unrelated SIBLING overlay that merely shares a common enclosing
13
+ overlay. Two `DropdownMenu`s both living inside the same `Popover`
14
+ are siblings of each other, not nested in each other — opening one
15
+ while the other was open left both on screen at once, only closing
16
+ on a re-click or a selection. `useClickOutside` now walks the real
17
+ relationship instead of doing a blanket portal check: it follows
18
+ "which portal contains this click" → "whose trigger opened that
19
+ portal" → "is that trigger contained in my own refs, or itself
20
+ inside another portal" (repeating for arbitrarily deep nesting) —
21
+ which correctly tells "genuinely nested inside me" apart from
22
+ "elsewhere inside a shared ancestor," however many levels deep.
23
+ `ThemedPortal` now tracks each portal's own anchor element for this
24
+ to walk. See the "Sibling overlays" and first two "Nested overlay"
25
+ cases in `tests/nested-overlays.test.tsx`.
26
+ - A `DropdownMenu` (or `Select`/`Combobox`/`ColorPicker`) nested
27
+ inside an open `Popover` rendered BEHIND it: each component's CSS
28
+ sets a fixed z-index tier (`Popover` 1060, `DropdownMenu`/`Select`/
29
+ `Combobox` 1050, `Tooltip` 1100, `Toast` 1200, ...), correct for
30
+ independent, non-nested overlays but backwards for this one
31
+ relationship — the nested overlay needs to paint above its own
32
+ container regardless of which tier either belongs to. `ThemedPortal`
33
+ now detects when an overlay's own trigger sits inside another,
34
+ already-open overlay's portaled content, and in that case only,
35
+ assigns it an inline z-index above the shared 1150 base (below
36
+ `Toast`'s 1200, which stays on top of everything as a global
37
+ notification regardless of nesting) via `position: relative` on the
38
+ portal wrapper itself — not the component's own CSS class, so
39
+ ordinary non-nested overlays are completely untouched. Verified safe
40
+ for `Popover`/`DropdownMenu` specifically: both position their
41
+ content with inline `position: fixed` (`useFloatingPosition`), which
42
+ isn't affected by an ancestor's `position: relative` — only
43
+ `transform`/`filter`/etc. would change a fixed descendant's
44
+ containing block. Not verified against every possible pairing (e.g.
45
+ a `position: absolute` `Tooltip` ending up as the nested one) — this
46
+ covers the reported and tested composition, not every combination.
47
+
48
+ ## [0.1.3]
49
+
50
+ ### Fixed
51
+ - `neobrutalism`'s `warning.light` token (`#fef3c7`) was byte-identical
52
+ to the theme's own `background` — every warning `Alert`, and anything
53
+ else drawing from that token, rendered invisibly against the page.
54
+ Now `#fde68a`, one step further into the same warm-amber family.
55
+ - `neobrutalism`'s `Rating` stars had no visible outline once filled:
56
+ the star icon's stroke and fill both come from `color`, so a filled
57
+ star's outline was purple-on-purple, not the black border every
58
+ other surface in this theme gets. Scoped override forces a black
59
+ stroke on all three star states (`neobrutalism` only).
60
+ - `gradient`'s `text`/`textMuted` were still `light` theme's values,
61
+ measured at 2.79:1 and a barely-there 1.32:1 against the theme's own
62
+ background gradient's darker stop — anything rendered directly on
63
+ the page background (as `Timeline`/`Pagination`/`Tabs` are, per this
64
+ library's own docs examples, with no wrapping surface assumed) was
65
+ close to unreadable. Darkened both — see the measured before/after
66
+ in the new `tests/theme-text-contrast.test.ts`. `textMuted` still
67
+ can't clear full AA (4.5:1) against the gradient's darkest point
68
+ with a single flat color; this is the best available compromise,
69
+ not a complete fix.
70
+ - `glass`'s `border` (`rgba(255,255,255,0.35)`) composited to literal
71
+ `#ffffff` against a plain white backdrop — a 1.0:1 ratio, i.e.
72
+ actually invisible (reported as `Progress`'s track outline
73
+ vanishing). Retinted to a neutral slate that stays visible against
74
+ both a plain white and a plain black fallback backdrop, since most
75
+ consumers won't add the "rich background" this theme's own
76
+ description says it needs.
77
+ - `Slider`'s value-label bubble (`showValueLabel`) had no space
78
+ reserved for it above the track and could overflow into the field's
79
+ own `label` text above it — most visible with a thumb near 0%.
80
+ `getRootClasses` (internal, not part of the public API surface) now
81
+ takes `showValueLabel` and adds a modifier class that reserves the
82
+ room the bubble actually needs.
83
+ - Nesting one dismissible overlay inside another (e.g. a `DropdownMenu`
84
+ inside a `Popover`) broke: every overlay portals its content to
85
+ `document.body` via `ThemedPortal`, as a DOM sibling of wherever it
86
+ was rendered rather than a descendant, so a click inside the nested
87
+ one registered as "outside" the outer one's own refs and closed it
88
+ before the click could register. `useClickOutside` now ignores
89
+ clicks inside any `[data-nuvox-portal]` node, fixing every
90
+ `Popover`/`DropdownMenu`/`Select`/`Combobox`/`ContextMenu`/
91
+ `CommandPalette` pairing at once instead of one at a time. See
92
+ `tests/nested-overlays.test.tsx`.
93
+ - `Carousel`'s `CarouselPrevious`/`CarouselNext` centered against the
94
+ whole `.nx-carousel` box (viewport + indicators + anything else
95
+ below it), not the viewport alone — correct only by coincidence when
96
+ the viewport was tall relative to everything else in the box.
97
+ `.nx-carousel` is now a CSS grid with the viewport pinned to its own
98
+ grid cell, which becomes the containing block for a same-cell
99
+ absolutely-positioned item (CSS Grid §10.1). This holds regardless
100
+ of `CarouselIndicators`' height or the viewport's own height, so an
101
+ explicit height is no longer required for correct centering (still
102
+ good practice for layout stability, just not load-bearing anymore).
103
+ Wrapping the buttons in your own `<div>` is still unsupported, for a
104
+ different reason than before: a plain wrapper isn't a positioning
105
+ context, so the buttons fall through to `.nx-carousel` regardless of
106
+ the grid fix.
107
+ - `docs-site`'s live "Controlled" `Carousel` demo and `carousel.mdx`'s
108
+ guidance both still reflected the pre-fix structure/requirements;
109
+ updated to match the fix above.
110
+
111
+ ### Added
112
+ - `tests/nested-overlays.test.tsx` — regression coverage for the
113
+ overlay-nesting fix above: fails against the old `useClickOutside`,
114
+ passes against the new one.
115
+ - `tests/theme-text-contrast.test.ts` — checks `text`/`textMuted`
116
+ against `background` for every theme, including gradient stops
117
+ extracted from non-solid backgrounds. `outline-text-contrast.test.ts`
118
+ only ever checked the outline-button `color-mix()` blend and
119
+ explicitly skipped non-solid backgrounds — a real coverage gap; this
120
+ is what would have caught the `gradient` regression above before it
121
+ shipped.
122
+
6
123
  ## [0.1.2]
7
124
 
8
125
  ### Fixed
@@ -270,7 +270,17 @@ var glass = defineTheme({
270
270
  background: "transparent",
271
271
  surface: "rgba(255,255,255,0.55)",
272
272
  surfaceRaised: "rgba(255,255,255,0.75)",
273
- border: "rgba(255,255,255,0.35)",
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)",
274
284
  borderFocus: "#9ca3af",
275
285
  text: "#111827",
276
286
  textMuted: "rgba(17,24,39,0.65)",
@@ -404,7 +414,13 @@ var neobrutalism = defineTheme({
404
414
  surface: "#ffffff",
405
415
  surfaceRaised: "#ffffff",
406
416
  border: "#000000",
407
- borderFocus: "#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" }
408
424
  },
409
425
  radius: { sm: "4px", md: "6px", lg: "8px", xl: "10px", "2xl": "12px", full: "9999px" },
410
426
  shadow: {
@@ -468,7 +484,24 @@ var gradient = defineTheme({
468
484
  surface: "linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,255,255,0.75))",
469
485
  surfaceRaised: "#ffffff",
470
486
  border: "rgba(118,75,162,0.25)",
471
- borderFocus: "#764ba2"
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"
472
505
  },
473
506
  radius: { sm: "12px", md: "18px", lg: "24px", xl: "32px", "2xl": "40px", full: "9999px" },
474
507
  shadow: {
@@ -1123,4 +1156,4 @@ export {
1123
1156
  getSortAriaProps,
1124
1157
  getSelectAllState
1125
1158
  };
1126
- //# sourceMappingURL=chunk-3F7OVF4J.js.map
1159
+ //# sourceMappingURL=chunk-KKRVJF3Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tokens/contract.ts","../src/tokens/themes/light.ts","../src/tokens/themes/dark.ts","../src/tokens/themes/glass.ts","../src/tokens/themes/dark-glass.ts","../src/tokens/themes/minimalism.ts","../src/tokens/themes/brutalism.ts","../src/tokens/themes/neobrutalism.ts","../src/tokens/themes/cyberpunk.ts","../src/tokens/themes/gradient.ts","../src/tokens/themes/material.ts","../src/tokens/themes/skeuomorphism.ts","../src/tokens/registry.ts","../src/tokens/accents/indigo.ts","../src/tokens/accents/violet.ts","../src/tokens/accents/teal.ts","../src/tokens/accents/rose.ts","../src/tokens/accents/amber.ts","../src/tokens/accents/emerald.ts","../src/tokens/accents/copper.ts","../src/tokens/accents/graphite.ts","../src/tokens/accents/magenta.ts","../src/tokens/accents.ts","../src/core/field.ts","../src/core/colorpicker.ts","../src/core/table.ts"],"sourcesContent":["// ============================================================\n// TOKEN CONTRACT\n//\n// This is the single most important file in the foundation.\n//\n// Every theme (light, dark, glass, cyberpunk, whatever comes\n// next) must produce an object that satisfies ThemeTokens.\n// TypeScript enforces this at compile time via `defineTheme()`\n// below — leave out a single key and the build fails with a\n// clear error naming the missing key.\n//\n// In the old codebase, themes were hand-written CSS files.\n// Nothing checked that cyberpunk.css defined every variable\n// brutalism.css did. A missing token didn't error — it just\n// silently fell back to nothing, and you only found out by\n// looking at the rendered page.\n//\n// Here, themes are TypeScript objects. CSS is *generated* from\n// them (see generate-css.ts), never hand-authored. There is\n// exactly one source of truth per theme, and it cannot be\n// incomplete.\n// ============================================================\n\n// ============================================================\n// A theme controls SHAPE, not brand color: radius, shadow style,\n// motion curves, border treatment, glass/gradient/glow effects,\n// and the neutral/semantic palette needed for legibility (a dark\n// theme's background/text MUST differ from light's — that's a\n// contrast requirement, not a brand choice). It does NOT define\n// `color.brand` — that's a separate, orthogonal axis (see\n// accents.ts) that a consumer picks independently of which theme\n// is active, and can override per-component exactly like `theme`\n// can. success/danger/warning/info stay theme-defined (their\n// exact shade can differ per theme for contrast, but their\n// meaning — green reads as success, red as danger — must not be\n// user-customizable away from that).\n// ============================================================\n\nexport interface ColorScale {\n 50: string; 100: string; 200: string; 300: string; 400: string;\n 500: string; 600: string; 700: string; 800: string; 900: string;\n}\n\nexport interface SemanticColor {\n light: string;\n subtle: string;\n base: string;\n dark: string;\n deeper: string;\n}\n\nexport interface ThemeTokens {\n meta: {\n name: string;\n label: string;\n /** Short description of the visual identity — kept out of CSS, used in docs/registry UI. */\n description: string;\n };\n\n color: {\n neutral: ColorScale & { 0: string; 950: string };\n success: SemanticColor;\n danger: SemanticColor;\n warning: SemanticColor;\n info: SemanticColor;\n /** Page/app background, not component surface. */\n background: string;\n /** Default component surface (card, input, modal body). */\n surface: string;\n /** Elevated surface (popover, dropdown, tooltip). */\n surfaceRaised: string;\n border: string;\n borderFocus: string;\n text: string;\n textMuted: string;\n textInverse: string;\n };\n\n radius: {\n sm: string; md: string; lg: string; xl: string; \"2xl\": string; full: string;\n };\n\n spacing: {\n xs: string; sm: string; md: string; lg: string; xl: string; \"2xl\": string;\n };\n\n typography: {\n fontSans: string;\n fontMono: string;\n sizeXs: string; sizeSm: string; sizeMd: string; sizeLg: string; sizeXl: string;\n weightNormal: string; weightMedium: string; weightBold: string;\n lineHeightTight: string; lineHeightNormal: string;\n };\n\n shadow: {\n xs: string; sm: string; md: string; lg: string; xl: string; \"2xl\": string;\n inner: string;\n };\n\n elevation: {\n /** z-index steps — must be consistent across every portal-based component. */\n dropdown: number;\n popover: number;\n modal: number;\n toast: number;\n tooltip: number;\n };\n\n motion: {\n durationFast: string;\n durationNormal: string;\n durationSlow: string;\n easeStandard: string;\n easeEmphasized: string;\n /** Set to '0.01ms' by a reduced-motion-aware theme variant if needed. */\n durationInstant: string;\n };\n\n border: {\n widthThin: string;\n widthMedium: string;\n widthThick: string;\n style: string;\n };\n\n effects: {\n /**\n * CSS `backdrop-filter: blur()` amount, e.g. \"16px\" or \"0px\".\n * Every non-glass theme sets this to \"0px\" — an explicit zero,\n * not an absent field, so `defineTheme`'s completeness check\n * still catches an accidentally-forgotten theme. Translucent\n * `color.surface`/`color.border` values (glass, dark-glass) are\n * only actually visible as \"glass\" when something behind them\n * is blurred; without this, a translucent white surface over a\n * plain page background is indistinguishable from opaque white.\n */\n backdropBlur: string;\n };\n}\n\n/**\n * Identity function with a strict parameter type.\n * Its only job is to make an incomplete theme a compile error\n * at the call site, with TypeScript naming the exact missing key.\n */\nexport function defineTheme(tokens: ThemeTokens): ThemeTokens {\n return tokens;\n}\n\n/** Every top-level and nested key path, used by the completeness test. */\nexport const TOKEN_CATEGORIES = [\n \"meta\", \"color\", \"radius\", \"spacing\", \"typography\", \"shadow\", \"elevation\", \"motion\", \"border\", \"effects\",\n] as const;\n\n/**\n * Every required leaf path, hardcoded independently of any\n * theme instance. This is deliberately NOT derived from\n * whichever theme happens to register first — that would make\n * the very first theme registered the unverified \"trust me\"\n * reference. Every path listed here corresponds 1:1 to a field\n * in ThemeTokens; if you add a field to the contract, add its\n * path here too (a mismatch here is caught by\n * registry.test.ts's cross-check against `light`).\n */\nexport const REQUIRED_TOKEN_PATHS = [\n \"meta.name\", \"meta.label\", \"meta.description\",\n ...[\"0\", \"50\", \"100\", \"200\", \"300\", \"400\", \"500\", \"600\", \"700\", \"800\", \"900\", \"950\"].map((k) => `color.neutral.${k}`),\n ...([\"success\", \"danger\", \"warning\", \"info\"] as const).flatMap((c) =>\n [\"light\", \"subtle\", \"base\", \"dark\", \"deeper\"].map((k) => `color.${c}.${k}`)\n ),\n \"color.background\", \"color.surface\", \"color.surfaceRaised\", \"color.border\", \"color.borderFocus\",\n \"color.text\", \"color.textMuted\", \"color.textInverse\",\n \"radius.sm\", \"radius.md\", \"radius.lg\", \"radius.xl\", \"radius.2xl\", \"radius.full\",\n \"spacing.xs\", \"spacing.sm\", \"spacing.md\", \"spacing.lg\", \"spacing.xl\", \"spacing.2xl\",\n \"typography.fontSans\", \"typography.fontMono\",\n \"typography.sizeXs\", \"typography.sizeSm\", \"typography.sizeMd\", \"typography.sizeLg\", \"typography.sizeXl\",\n \"typography.weightNormal\", \"typography.weightMedium\", \"typography.weightBold\",\n \"typography.lineHeightTight\", \"typography.lineHeightNormal\",\n \"shadow.xs\", \"shadow.sm\", \"shadow.md\", \"shadow.lg\", \"shadow.xl\", \"shadow.2xl\", \"shadow.inner\",\n \"elevation.dropdown\", \"elevation.popover\", \"elevation.modal\", \"elevation.toast\", \"elevation.tooltip\",\n \"motion.durationFast\", \"motion.durationNormal\", \"motion.durationSlow\",\n \"motion.easeStandard\", \"motion.easeEmphasized\", \"motion.durationInstant\",\n \"border.widthThin\", \"border.widthMedium\", \"border.widthThick\", \"border.style\",\n \"effects.backdropBlur\",\n] as const;\n\nfunction getAtPath(obj: unknown, path: string): unknown {\n return path.split(\".\").reduce<unknown>((acc, key) => {\n if (acc === null || typeof acc !== \"object\") return undefined;\n return (acc as Record<string, unknown>)[key];\n }, obj);\n}\n\n/** Returns every required path that is missing or empty on the given theme-like object. */\nexport function findMissingTokenPaths(theme: unknown): string[] {\n return REQUIRED_TOKEN_PATHS.filter((path) => {\n const value = getAtPath(theme, path);\n return value === null || value === undefined || value === \"\";\n });\n}\n","import { defineTheme } from \"../contract\";\n\nexport const light = defineTheme({\n meta: {\n name: \"light\",\n label: \"Light\",\n description: \"Default, neutral, high-legibility surface.\",\n },\n color: {\n neutral: {\n 0: \"#ffffff\", 50: \"#f9fafb\", 100: \"#f3f4f6\", 200: \"#e5e7eb\", 300: \"#d1d5db\",\n 400: \"#9ca3af\", 500: \"#6b7280\", 600: \"#4b5563\", 700: \"#374151\", 800: \"#1f2937\",\n 900: \"#111827\", 950: \"#030712\",\n },\n success: { light: \"#d1fae5\", subtle: \"#a7f3d0\", base: \"#10b981\", dark: \"#059669\", deeper: \"#064e3b\" },\n danger: { light: \"#fee2e2\", subtle: \"#fecaca\", base: \"#ef4444\", dark: \"#dc2626\", deeper: \"#7f1d1d\" },\n warning: { light: \"#fef3c7\", subtle: \"#fde68a\", base: \"#f59e0b\", dark: \"#d97706\", deeper: \"#78350f\" },\n info: { light: \"#dbeafe\", subtle: \"#bfdbfe\", base: \"#3b82f6\", dark: \"#2563eb\", deeper: \"#1e3a5f\" },\n background: \"#ffffff\",\n surface: \"#ffffff\",\n surfaceRaised: \"#ffffff\",\n border: \"#e5e7eb\",\n // Neutral, not brand-tied — the actual focus-ring color\n // interactive components use is the picked accent\n // (--color-brand-500/600), not this. This exists for\n // non-branded emphasis borders.\n borderFocus: \"#9ca3af\",\n text: \"#111827\",\n textMuted: \"#6b7280\",\n textInverse: \"#ffffff\",\n },\n radius: { sm: \"6px\", md: \"10px\", lg: \"14px\", xl: \"18px\", \"2xl\": \"24px\", full: \"9999px\" },\n spacing: { xs: \"4px\", sm: \"8px\", md: \"12px\", lg: \"16px\", xl: \"24px\", \"2xl\": \"32px\" },\n typography: {\n fontSans: \"'Inter', system-ui, sans-serif\",\n fontMono: \"'JetBrains Mono', monospace\",\n sizeXs: \"12px\", sizeSm: \"14px\", sizeMd: \"16px\", sizeLg: \"18px\", sizeXl: \"22px\",\n weightNormal: \"400\", weightMedium: \"500\", weightBold: \"700\",\n lineHeightTight: \"1.2\", lineHeightNormal: \"1.5\",\n },\n shadow: {\n xs: \"0 1px 2px rgba(0,0,0,0.05)\",\n sm: \"0 2px 6px rgba(0,0,0,0.06)\",\n md: \"0 4px 12px rgba(0,0,0,0.08)\",\n lg: \"0 10px 24px rgba(0,0,0,0.10)\",\n xl: \"0 20px 40px rgba(0,0,0,0.12)\",\n \"2xl\": \"0 28px 56px rgba(0,0,0,0.16)\",\n inner: \"inset 0 1px 2px rgba(0,0,0,0.05)\",\n },\n elevation: { dropdown: 1000, popover: 1100, modal: 1200, toast: 1300, tooltip: 1400 },\n motion: {\n durationFast: \"120ms\", durationNormal: \"200ms\", durationSlow: \"320ms\",\n easeStandard: \"cubic-bezier(0.4, 0, 0.2, 1)\", easeEmphasized: \"cubic-bezier(0.2, 0, 0, 1)\",\n durationInstant: \"0ms\",\n },\n border: { widthThin: \"1px\", widthMedium: \"1.5px\", widthThick: \"2px\", style: \"solid\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\n\nexport const dark = defineTheme({\n meta: {\n name: \"dark\",\n label: \"Dark\",\n description: \"Low-glare surface for extended use.\",\n },\n color: {\n neutral: {\n 0: \"#030712\", 50: \"#111827\", 100: \"#1f2937\", 200: \"#374151\", 300: \"#4b5563\",\n 400: \"#6b7280\", 500: \"#9ca3af\", 600: \"#d1d5db\", 700: \"#e5e7eb\", 800: \"#f3f4f6\",\n 900: \"#f9fafb\", 950: \"#ffffff\",\n },\n success: { light: \"#064e3b\", subtle: \"#065f46\", base: \"#34d399\", dark: \"#6ee7b7\", deeper: \"#d1fae5\" },\n danger: { light: \"#7f1d1d\", subtle: \"#991b1b\", base: \"#f87171\", dark: \"#fca5a5\", deeper: \"#fee2e2\" },\n warning: { light: \"#78350f\", subtle: \"#92400e\", base: \"#fbbf24\", dark: \"#fcd34d\", deeper: \"#fef3c7\" },\n info: { light: \"#1e3a5f\", subtle: \"#1e40af\", base: \"#60a5fa\", dark: \"#93c5fd\", deeper: \"#dbeafe\" },\n background: \"#0b0f19\",\n surface: \"#131826\",\n surfaceRaised: \"#1c2333\",\n border: \"#2a3143\",\n borderFocus: \"#6b7280\",\n text: \"#f3f4f6\",\n textMuted: \"#9ca3af\",\n textInverse: \"#111827\",\n },\n radius: { sm: \"6px\", md: \"10px\", lg: \"14px\", xl: \"18px\", \"2xl\": \"24px\", full: \"9999px\" },\n spacing: { xs: \"4px\", sm: \"8px\", md: \"12px\", lg: \"16px\", xl: \"24px\", \"2xl\": \"32px\" },\n typography: {\n fontSans: \"'Inter', system-ui, sans-serif\",\n fontMono: \"'JetBrains Mono', monospace\",\n sizeXs: \"12px\", sizeSm: \"14px\", sizeMd: \"16px\", sizeLg: \"18px\", sizeXl: \"22px\",\n weightNormal: \"400\", weightMedium: \"500\", weightBold: \"700\",\n lineHeightTight: \"1.2\", lineHeightNormal: \"1.5\",\n },\n shadow: {\n xs: \"0 1px 2px rgba(0,0,0,0.4)\",\n sm: \"0 2px 6px rgba(0,0,0,0.45)\",\n md: \"0 4px 12px rgba(0,0,0,0.5)\",\n lg: \"0 10px 24px rgba(0,0,0,0.55)\",\n xl: \"0 20px 40px rgba(0,0,0,0.6)\",\n \"2xl\": \"0 28px 56px rgba(0,0,0,0.65)\",\n inner: \"inset 0 1px 2px rgba(0,0,0,0.4)\",\n },\n elevation: { dropdown: 1000, popover: 1100, modal: 1200, toast: 1300, tooltip: 1400 },\n motion: {\n durationFast: \"120ms\", durationNormal: \"200ms\", durationSlow: \"320ms\",\n easeStandard: \"cubic-bezier(0.4, 0, 0.2, 1)\", easeEmphasized: \"cubic-bezier(0.2, 0, 0, 1)\",\n durationInstant: \"0ms\",\n },\n border: { widthThin: \"1px\", widthMedium: \"1.5px\", widthThick: \"2px\", style: \"solid\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\n\nexport const glass = defineTheme({\n meta: {\n name: \"glass\",\n label: \"Glass\",\n description: \"Translucent, softly rounded, floating surfaces. Needs a rich background behind it.\",\n },\n color: {\n neutral: {\n 0: \"#ffffff\", 50: \"#f9fafb\", 100: \"#f3f4f6\", 200: \"#e5e7eb\", 300: \"#d1d5db\",\n 400: \"#9ca3af\", 500: \"#6b7280\", 600: \"#4b5563\", 700: \"#374151\", 800: \"#1f2937\",\n 900: \"#111827\", 950: \"#030712\",\n },\n success: { light: \"#d1fae5\", subtle: \"#a7f3d0\", base: \"#10b981\", dark: \"#059669\", deeper: \"#064e3b\" },\n danger: { light: \"#fee2e2\", subtle: \"#fecaca\", base: \"#ef4444\", dark: \"#dc2626\", deeper: \"#7f1d1d\" },\n warning: { light: \"#fef3c7\", subtle: \"#fde68a\", base: \"#f59e0b\", dark: \"#d97706\", deeper: \"#78350f\" },\n info: { light: \"#dbeafe\", subtle: \"#bfdbfe\", base: \"#3b82f6\", dark: \"#2563eb\", deeper: \"#1e3a5f\" },\n background: \"transparent\",\n surface: \"rgba(255,255,255,0.55)\",\n surfaceRaised: \"rgba(255,255,255,0.75)\",\n // Was rgba(255,255,255,0.35) — translucent WHITE. Composited on\n // a plain white page (the theme's own meta.description admits it\n // \"needs a rich background behind it,\" but most consumers won't\n // add one), that resolves to literal #ffffff — a 1.0:1 contrast\n // ratio, i.e. actually invisible, which is the reported vanished\n // Progress-track border. A neutral slate tint stays visible\n // against both a plain white AND a plain black fallback backdrop\n // (measured ~2.1-2.3:1 either way) — short of full 3:1 UI-contrast\n // on both extremes at once, but a large improvement over 1.0, and\n // still reads as a soft glass edge over an actual rich backdrop.\n border: \"rgba(100,116,139,0.6)\",\n borderFocus: \"#9ca3af\",\n text: \"#111827\",\n textMuted: \"rgba(17,24,39,0.65)\",\n textInverse: \"#ffffff\",\n },\n // Notably rounder than light/dark — this is a shape difference, not just color.\n radius: { sm: \"10px\", md: \"16px\", lg: \"22px\", xl: \"28px\", \"2xl\": \"36px\", full: \"9999px\" },\n spacing: { xs: \"4px\", sm: \"8px\", md: \"12px\", lg: \"16px\", xl: \"24px\", \"2xl\": \"32px\" },\n typography: {\n fontSans: \"'Inter', system-ui, sans-serif\",\n fontMono: \"'JetBrains Mono', monospace\",\n sizeXs: \"12px\", sizeSm: \"14px\", sizeMd: \"16px\", sizeLg: \"18px\", sizeXl: \"22px\",\n weightNormal: \"400\", weightMedium: \"500\", weightBold: \"700\",\n lineHeightTight: \"1.2\", lineHeightNormal: \"1.5\",\n },\n shadow: {\n xs: \"0 2px 8px rgba(0,0,0,0.06)\",\n sm: \"0 4px 16px rgba(0,0,0,0.08)\",\n md: \"0 8px 32px rgba(0,0,0,0.10)\",\n lg: \"0 16px 48px rgba(0,0,0,0.12)\",\n xl: \"0 24px 64px rgba(0,0,0,0.14)\",\n \"2xl\": \"0 32px 80px rgba(0,0,0,0.18)\",\n inner: \"inset 0 1px 0 rgba(255,255,255,0.4)\",\n },\n elevation: { dropdown: 1000, popover: 1100, modal: 1200, toast: 1300, tooltip: 1400 },\n motion: {\n // Slightly slower/softer than light/dark — matches \"everything floats\".\n durationFast: \"160ms\", durationNormal: \"260ms\", durationSlow: \"400ms\",\n easeStandard: \"cubic-bezier(0.25, 0.1, 0.25, 1)\", easeEmphasized: \"cubic-bezier(0.16, 1, 0.3, 1)\",\n durationInstant: \"0ms\",\n },\n border: { widthThin: \"1px\", widthMedium: \"1px\", widthThick: \"1.5px\", style: \"solid\" },\n effects: { backdropBlur: \"16px\" },\n});","import { defineTheme } from \"../contract\";\nimport { dark } from \"./dark\";\n\nexport const darkGlass = defineTheme({\n ...dark,\n meta: {\n name: \"dark-glass\",\n label: \"Dark Glass\",\n description: \"Translucent glass panels floating over a dark background.\",\n },\n color: {\n ...dark.color,\n background: \"#05070d\",\n surface: \"rgba(255,255,255,0.06)\",\n surfaceRaised: \"rgba(255,255,255,0.10)\",\n border: \"rgba(255,255,255,0.12)\",\n },\n radius: { sm: \"10px\", md: \"16px\", lg: \"22px\", xl: \"28px\", \"2xl\": \"36px\", full: \"9999px\" },\n shadow: {\n xs: \"0 2px 8px rgba(0,0,0,0.5)\", sm: \"0 4px 16px rgba(0,0,0,0.55)\", md: \"0 8px 32px rgba(0,0,0,0.6)\",\n lg: \"0 16px 48px rgba(0,0,0,0.65)\", xl: \"0 24px 64px rgba(0,0,0,0.7)\", \"2xl\": \"0 32px 80px rgba(0,0,0,0.75)\",\n inner: \"inset 0 1px 0 rgba(255,255,255,0.08)\",\n },\n motion: { ...dark.motion, durationFast: \"160ms\", durationNormal: \"260ms\", durationSlow: \"400ms\" },\n effects: { backdropBlur: \"18px\" },\n});\n","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const minimalism = defineTheme({\n ...light,\n meta: {\n name: \"minimalism\",\n label: \"Minimalism\",\n description: \"Reduced to essentials — thin borders, flat surfaces, no shadow, tight radius.\",\n },\n color: {\n ...light.color,\n border: \"#e2e2e2\", surface: \"#ffffff\", surfaceRaised: \"#ffffff\",\n },\n radius: { sm: \"2px\", md: \"3px\", lg: \"4px\", xl: \"6px\", \"2xl\": \"8px\", full: \"9999px\" },\n shadow: { xs: \"none\", sm: \"none\", md: \"none\", lg: \"none\", xl: \"none\", \"2xl\": \"none\", inner: \"none\" },\n border: { widthThin: \"1px\", widthMedium: \"1px\", widthThick: \"1px\", style: \"solid\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const brutalism = defineTheme({\n ...light,\n meta: {\n name: \"brutalism\",\n label: \"Brutalism\",\n description: \"Raw, unstyled web aesthetic — square corners, zero shadow, monospace type.\",\n },\n color: {\n ...light.color,\n background: \"#ffffff\", surface: \"#ffffff\", surfaceRaised: \"#ffffff\",\n border: \"#000000\", borderFocus: \"#ff0000\", text: \"#000000\",\n },\n radius: { sm: \"0px\", md: \"0px\", lg: \"0px\", xl: \"0px\", \"2xl\": \"0px\", full: \"0px\" },\n typography: { ...light.typography, fontSans: \"'Courier New', monospace\", fontMono: \"'Courier New', monospace\" },\n shadow: { xs: \"none\", sm: \"none\", md: \"none\", lg: \"none\", xl: \"none\", \"2xl\": \"none\", inner: \"none\" },\n border: { widthThin: \"1px\", widthMedium: \"2px\", widthThick: \"3px\", style: \"solid\" },\n motion: { ...light.motion, durationFast: \"0ms\", durationNormal: \"0ms\", durationSlow: \"0ms\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const neobrutalism = defineTheme({\n ...light,\n meta: {\n name: \"neobrutalism\",\n label: \"Neo Brutalism\",\n description: \"Bold black borders, flat offset shadows, saturated color blocks.\",\n },\n color: {\n ...light.color,\n background: \"#fef3c7\", surface: \"#ffffff\", surfaceRaised: \"#ffffff\",\n border: \"#000000\", borderFocus: \"#000000\",\n // light.color.warning.light (#fef3c7) is identical to this\n // theme's own background — every warning Alert/Badge/etc. was\n // rendering invisibly on the page. Bumped to the next step in\n // the same warm-amber family (matches light.color.warning.subtle)\n // so it stays on-theme but is actually visible against the page.\n warning: { ...light.color.warning, light: \"#fde68a\" },\n },\n radius: { sm: \"4px\", md: \"6px\", lg: \"8px\", xl: \"10px\", \"2xl\": \"12px\", full: \"9999px\" },\n shadow: {\n xs: \"2px 2px 0 #000000\", sm: \"3px 3px 0 #000000\", md: \"4px 4px 0 #000000\",\n lg: \"6px 6px 0 #000000\", xl: \"8px 8px 0 #000000\", \"2xl\": \"10px 10px 0 #000000\",\n inner: \"inset 2px 2px 0 #000000\",\n },\n border: { widthThin: \"2px\", widthMedium: \"3px\", widthThick: \"4px\", style: \"solid\" },\n motion: { ...light.motion, durationFast: \"80ms\", durationNormal: \"140ms\", durationSlow: \"200ms\", easeStandard: \"linear\", easeEmphasized: \"linear\" },\n effects: { backdropBlur: \"0px\" },\n});","import { defineTheme } from \"../contract\";\nimport { dark } from \"./dark\";\n\nexport const cyberpunk = defineTheme({\n ...dark,\n meta: {\n name: \"cyberpunk\",\n label: \"Cyberpunk\",\n description: \"Neon-on-black, glowing edges, high-saturation magenta/cyan accents.\",\n },\n color: {\n ...dark.color,\n background: \"#0a0014\", surface: \"#12001f\", surfaceRaised: \"#1a0230\",\n border: \"#ff2bd6\", borderFocus: \"#00f0ff\", text: \"#e8faff\", textMuted: \"#9a8cc9\",\n },\n radius: { sm: \"2px\", md: \"4px\", lg: \"6px\", xl: \"8px\", \"2xl\": \"10px\", full: \"9999px\" },\n shadow: {\n xs: \"0 0 6px rgba(255,43,214,0.5)\", sm: \"0 0 12px rgba(255,43,214,0.55)\",\n md: \"0 0 20px rgba(0,240,255,0.5)\", lg: \"0 0 32px rgba(0,240,255,0.55)\",\n xl: \"0 0 48px rgba(255,43,214,0.6)\", \"2xl\": \"0 0 64px rgba(0,240,255,0.65)\",\n inner: \"inset 0 0 8px rgba(255,43,214,0.4)\",\n },\n border: { widthThin: \"1px\", widthMedium: \"1.5px\", widthThick: \"2px\", style: \"solid\" },\n motion: { ...dark.motion, easeStandard: \"cubic-bezier(0.83,0,0.17,1)\", easeEmphasized: \"cubic-bezier(0.9,0,0.1,1)\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const gradient = defineTheme({\n ...light,\n meta: {\n name: \"gradient\",\n label: \"Gradient\",\n description: \"Vibrant, colorful transitions across surfaces and accents.\",\n },\n color: {\n ...light.color,\n background: \"linear-gradient(135deg, #667eea 0%, #764ba2 100%)\",\n surface: \"linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,255,255,0.75))\",\n surfaceRaised: \"#ffffff\",\n border: \"rgba(118,75,162,0.25)\",\n borderFocus: \"#764ba2\",\n // text/textMuted were still light theme's values (#111827 /\n // #6b7280) — fine on the near-white `surface`, but components\n // that render straight on `background` (Timeline, Pagination,\n // Tabs — all used with no wrapping surface in this library's own\n // docs examples) sat directly on the purple gradient instead.\n // Measured contrast against the gradient's darker stop\n // (#764ba2): text 2.79:1, textMuted a barely-there 1.32:1 — the\n // reported \"nearly invisible\" text. Darkened both; textMuted\n // still can't clear 4.5:1 against the darkest point of this\n // specific gradient with a single flat color (nothing dark\n // enough to do that stays legible as \"muted\" against the near-\n // white surface too), so this is the best available compromise\n // within a single global text/textMuted pair, not a full fix —\n // worth knowing if it still reads as low-contrast on the\n // darkest corner of the gradient.\n text: \"#000000\",\n textMuted: \"#2e2440\",\n },\n radius: { sm: \"12px\", md: \"18px\", lg: \"24px\", xl: \"32px\", \"2xl\": \"40px\", full: \"9999px\" },\n shadow: {\n xs: \"0 2px 10px rgba(118,75,162,0.15)\", sm: \"0 4px 20px rgba(118,75,162,0.18)\",\n md: \"0 8px 30px rgba(118,75,162,0.22)\", lg: \"0 16px 40px rgba(118,75,162,0.26)\",\n xl: \"0 24px 56px rgba(118,75,162,0.3)\", \"2xl\": \"0 32px 72px rgba(118,75,162,0.35)\",\n inner: \"inset 0 1px 0 rgba(255,255,255,0.5)\",\n },\n motion: { ...light.motion, durationNormal: \"240ms\", durationSlow: \"380ms\" },\n effects: { backdropBlur: \"0px\" },\n});","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const material = defineTheme({\n ...light,\n meta: {\n name: \"material\",\n label: \"Material\",\n description: \"Google Material Design-inspired elevation shadows and motion curves.\",\n },\n color: {\n ...light.color,\n surface: \"#ffffff\", background: \"#fafafa\",\n },\n radius: { sm: \"4px\", md: \"8px\", lg: \"12px\", xl: \"16px\", \"2xl\": \"28px\", full: \"9999px\" },\n typography: { ...light.typography, fontSans: \"'Roboto', system-ui, sans-serif\" },\n shadow: {\n xs: \"0 1px 2px rgba(0,0,0,0.24)\",\n sm: \"0 1px 4px rgba(0,0,0,0.2), 0 1px 2px rgba(0,0,0,0.12)\",\n md: \"0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)\",\n lg: \"0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)\",\n xl: \"0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)\",\n \"2xl\": \"0 19px 38px rgba(0,0,0,0.3), 0 15px 12px rgba(0,0,0,0.22)\",\n inner: \"inset 0 1px 2px rgba(0,0,0,0.12)\",\n },\n motion: { ...light.motion, easeStandard: \"cubic-bezier(0.4,0,0.2,1)\", easeEmphasized: \"cubic-bezier(0.0,0,0.2,1)\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import { defineTheme } from \"../contract\";\nimport { light } from \"./light\";\n\nexport const skeuomorphism = defineTheme({\n ...light,\n meta: {\n name: \"skeuomorphism\",\n label: \"Skeuomorphism\",\n description: \"Realistic depth — soft embossed surfaces mimicking physical material.\",\n },\n color: {\n ...light.color,\n background: \"#e8e4da\", surface: \"#f0ece2\", surfaceRaised: \"#f7f4ec\",\n border: \"#c9c2b0\", text: \"#3a3226\",\n },\n radius: { sm: \"8px\", md: \"12px\", lg: \"18px\", xl: \"24px\", \"2xl\": \"32px\", full: \"9999px\" },\n shadow: {\n xs: \"inset 0 1px 1px rgba(255,255,255,0.8), 0 1px 3px rgba(58,50,38,0.25)\",\n sm: \"inset 0 1px 1px rgba(255,255,255,0.8), 0 2px 6px rgba(58,50,38,0.28)\",\n md: \"inset 0 1px 1px rgba(255,255,255,0.8), 0 4px 10px rgba(58,50,38,0.3)\",\n lg: \"inset 0 1px 1px rgba(255,255,255,0.8), 0 8px 18px rgba(58,50,38,0.32)\",\n xl: \"inset 0 1px 1px rgba(255,255,255,0.8), 0 14px 28px rgba(58,50,38,0.35)\",\n \"2xl\": \"inset 0 1px 1px rgba(255,255,255,0.8), 0 20px 40px rgba(58,50,38,0.38)\",\n inner: \"inset 0 2px 4px rgba(58,50,38,0.3)\",\n },\n motion: { ...light.motion, durationNormal: \"220ms\", easeStandard: \"cubic-bezier(0.34,1.56,0.64,1)\" },\n effects: { backdropBlur: \"0px\" },\n});\n","import type { ThemeTokens } from \"./contract\";\nimport { findMissingTokenPaths } from \"./contract\";\nimport { light } from \"./themes/light\";\nimport { dark } from \"./themes/dark\";\nimport { glass } from \"./themes/glass\";\nimport { darkGlass } from \"./themes/dark-glass\";\nimport { minimalism } from \"./themes/minimalism\";\nimport { brutalism } from \"./themes/brutalism\";\nimport { neobrutalism } from \"./themes/neobrutalism\";\nimport { cyberpunk } from \"./themes/cyberpunk\";\nimport { gradient } from \"./themes/gradient\";\nimport { material } from \"./themes/material\";\nimport { skeuomorphism } from \"./themes/skeuomorphism\";\n\nconst registry = new Map<string, ThemeTokens>();\n\n/**\n * Checks the theme against REQUIRED_TOKEN_PATHS — a fixed list\n * hardcoded in contract.ts, not derived from whichever theme\n * happens to register first. This is the runtime safety net for\n * themes that bypass the TypeScript-level defineTheme() check\n * (e.g. loaded from JSON at runtime rather than authored as a\n * .ts file in this repo). A theme that fails this throws\n * immediately on registration, not silently at render time on\n * whichever component hits the missing key first.\n */\nfunction assertComplete(theme: ThemeTokens): void {\n const missing = findMissingTokenPaths(theme);\n if (missing.length > 0) {\n throw new Error(\n `Theme \"${theme.meta?.name ?? \"unknown\"}\" is missing/empty required token(s): ${missing.join(\", \")}`\n );\n }\n}\n\nexport function registerTheme(theme: ThemeTokens): void {\n assertComplete(theme);\n registry.set(theme.meta.name, theme);\n}\n\nexport function getTheme(name: string): ThemeTokens | undefined {\n return registry.get(name);\n}\n\nexport function listThemes(): ThemeTokens[] {\n return Array.from(registry.values());\n}\n\n// Built-in themes register on import. Third-party/future themes\n// (Cyberpunk, Neo Brutal, Aurora, ...) call registerTheme() the\n// same way from wherever they're defined — no other file needs\n// to change.\nregisterTheme(light);\nregisterTheme(dark);\nregisterTheme(glass);\nregisterTheme(darkGlass);\nregisterTheme(minimalism);\nregisterTheme(brutalism);\nregisterTheme(neobrutalism);\nregisterTheme(cyberpunk);\nregisterTheme(gradient);\nregisterTheme(material);\nregisterTheme(skeuomorphism);\n","import type { AccentDefinition } from \"../accents\";\n\nexport const indigo: AccentDefinition = {\n name: \"indigo\",\n label: \"Indigo\",\n scale: {\n 50: \"#f0f4ff\", 100: \"#e0e8ff\", 200: \"#c7d5fe\", 300: \"#a5b4fc\", 400: \"#818cf8\",\n 500: \"#6366f1\", 600: \"#4f46e5\", 700: \"#4338ca\", 800: \"#3730a3\", 900: \"#312e81\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const violet: AccentDefinition = {\n name: \"violet\",\n label: \"Violet\",\n scale: {\n 50: \"#faf5ff\", 100: \"#f3e8ff\", 200: \"#e9d5ff\", 300: \"#d8b4fe\", 400: \"#c084fc\",\n 500: \"#a855f7\", 600: \"#9333ea\", 700: \"#7e22ce\", 800: \"#6b21a8\", 900: \"#581c87\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const teal: AccentDefinition = {\n name: \"teal\",\n label: \"Teal\",\n scale: {\n 50: \"#f0fdfa\", 100: \"#ccfbf1\", 200: \"#99f6e4\", 300: \"#5eead4\", 400: \"#2dd4bf\",\n 500: \"#14b8a6\", 600: \"#0d9488\", 700: \"#0f766e\", 800: \"#115e59\", 900: \"#134e4a\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const rose: AccentDefinition = {\n name: \"rose\",\n label: \"Rose\",\n scale: {\n 50: \"#fff1f2\", 100: \"#ffe4e6\", 200: \"#fecdd3\", 300: \"#fda4af\", 400: \"#fb7185\",\n 500: \"#f43f5e\", 600: \"#e11d48\", 700: \"#be123c\", 800: \"#9f1239\", 900: \"#881337\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const amber: AccentDefinition = {\n name: \"amber\",\n label: \"Amber\",\n scale: {\n 50: \"#fffbeb\", 100: \"#fef3c7\", 200: \"#fde68a\", 300: \"#fcd34d\", 400: \"#fbbf24\",\n 500: \"#f59e0b\", 600: \"#d97706\", 700: \"#b45309\", 800: \"#92400e\", 900: \"#78350f\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const emerald: AccentDefinition = {\n name: \"emerald\",\n label: \"Emerald\",\n scale: {\n 50: \"#ecfdf5\", 100: \"#d1fae5\", 200: \"#a7f3d0\", 300: \"#6ee7b7\", 400: \"#34d399\",\n 500: \"#10b981\", 600: \"#059669\", 700: \"#047857\", 800: \"#065f46\", 900: \"#064e3b\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const copper: AccentDefinition = {\n name: \"copper\",\n label: \"Copper\",\n scale: {\n 50: \"#fdf6ec\", 100: \"#faebd2\", 200: \"#f3d3a0\", 300: \"#e9b56b\",\n 400: \"#d99a45\", 500: \"#b9752c\", 600: \"#9c5d24\", 700: \"#7d4a1f\", 800: \"#623a1c\", 900: \"#4e2f19\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const graphite: AccentDefinition = {\n name: \"graphite\",\n label: \"Graphite\",\n scale: {\n 50: \"#fafafa\", 100: \"#f0f0f0\", 200: \"#e0e0e0\", 300: \"#c7c7c7\", 400: \"#a3a3a3\",\n 500: \"#525252\", 600: \"#404040\", 700: \"#262626\", 800: \"#171717\", 900: \"#0a0a0a\",\n },\n};\n","import type { AccentDefinition } from \"../accents\";\n\nexport const magenta: AccentDefinition = {\n name: \"magenta\",\n label: \"Magenta\",\n scale: {\n 50: \"#ffe0fb\", 100: \"#ffb3f5\", 200: \"#ff80ee\", 300: \"#ff4de6\", 400: \"#ff26e0\",\n 500: \"#ff00d9\", 600: \"#e600c4\", 700: \"#cc00af\", 800: \"#b3009a\", 900: \"#800070\",\n },\n};\n","import type { ColorScale } from \"./contract\";\n\n// ============================================================\n// ACCENT COLORS\n//\n// This is the axis a consumer actually picks their brand color\n// from — completely independent of which theme (shape/structure)\n// is active. \"Our brand is teal\" should work whether the app is\n// using the light theme, the cyberpunk theme, or any other —\n// the theme still controls radius/shadow/motion/glass-or-not,\n// the accent controls hue.\n//\n// Mirrors tokens/registry.ts's shape deliberately (registerX /\n// getX / listX) so the two systems are learned once, not twice.\n// ============================================================\n\nexport interface AccentDefinition {\n name: string;\n label: string;\n scale: ColorScale;\n}\n\nconst registry = new Map<string, AccentDefinition>();\n\nfunction assertCompleteScale(def: AccentDefinition): void {\n const missing = ([\"50\", \"100\", \"200\", \"300\", \"400\", \"500\", \"600\", \"700\", \"800\", \"900\"] as const).filter(\n (k) => !def.scale[k as unknown as keyof ColorScale]\n );\n if (missing.length > 0) {\n throw new Error(`Accent \"${def.name}\" is missing scale step(s): ${missing.join(\", \")}`);\n }\n}\n\nexport function registerAccent(def: AccentDefinition): void {\n assertCompleteScale(def);\n registry.set(def.name, def);\n}\n\nexport function getAccent(name: string): AccentDefinition | undefined {\n return registry.get(name);\n}\n\nexport function listAccents(): AccentDefinition[] {\n return Array.from(registry.values());\n}\n\n// Built-in accents register on import. A consumer's own custom\n// brand accent registers the same way — registerAccent() with a\n// name/label/scale, called from wherever they define it.\nimport { indigo } from \"./accents/indigo\";\nimport { violet } from \"./accents/violet\";\nimport { teal } from \"./accents/teal\";\nimport { rose } from \"./accents/rose\";\nimport { amber } from \"./accents/amber\";\nimport { emerald } from \"./accents/emerald\";\nimport { copper } from \"./accents/copper\";\nimport { graphite } from \"./accents/graphite\";\nimport { magenta } from \"./accents/magenta\";\n\nregisterAccent(indigo);\nregisterAccent(violet);\nregisterAccent(teal);\nregisterAccent(rose);\nregisterAccent(amber);\nregisterAccent(emerald);\nregisterAccent(copper);\nregisterAccent(graphite);\nregisterAccent(magenta);\n\nexport const DEFAULT_ACCENT = \"indigo\";\n","import type { Size } from \"./types\";\n\n// ============================================================\n// Category B (form/input primitives) shared shape.\n//\n// BUILDING-COMPONENTS.md's Category B note: \"Standard props every\n// component in this category should share: value/defaultValue,\n// onChange, disabled, error (or invalid), placeholder where\n// applicable. Decide this shape once, here, rather than letting\n// Input and NumberInput drift (the old color/radius drift, one\n// category up).\" This module is that one decision, applied by\n// every field-based component (Input, Textarea, Checkbox, Radio,\n// Toggle, and any future one) instead of each re-deriving it.\n// ============================================================\n\nexport interface FieldProps {\n disabled?: boolean;\n required?: boolean;\n /** Whether the field is in an invalid/error state. */\n error?: boolean;\n size?: Size;\n}\n\nexport interface FieldState {\n isDisabled: boolean;\n isRequired: boolean;\n isInvalid: boolean;\n size: Size;\n}\n\nexport function resolveFieldState(props: FieldProps): FieldState {\n return {\n // ?? throughout, never || (CONTRACT.md Rule 3) — `error={false}`\n // or `disabled={false}` must not be silently discarded.\n isDisabled: props.disabled ?? false,\n isRequired: props.required ?? false,\n isInvalid: props.error ?? false,\n size: props.size ?? \"md\",\n };\n}\n\n/**\n * Category B's accessibility baseline (BUILDING-COMPONENTS.md):\n * aria-invalid and aria-describedby (for an error/helper message)\n * on every field component, not just the ones an author happened\n * to remember.\n */\nexport function getFieldAriaProps(state: FieldState, describedBy?: string) {\n return {\n \"aria-invalid\": state.isInvalid ? (true as const) : undefined,\n \"aria-required\": state.isRequired ? (true as const) : undefined,\n \"aria-describedby\": describedBy,\n };\n}\n","import { resolveFieldState, getFieldAriaProps, type FieldProps, type FieldState } from \"./field\";\n\n// ============================================================\n// COLOR PICKER — pure core (Category D: Input's field shape +\n// Popover, with the popover panel composing a preset swatch grid and\n// a custom saturation/hue panel — see react/ColorPicker.tsx's own\n// header for why both, rather than the native <input type=\"color\">\n// an earlier version of this file used). This module owns the field\n// concerns: hex normalization/parsing (now including `rgb(...)`/\n// `hsl(...)` function-notation strings, since the field can display\n// either depending on which format tab is active) and swatch/dial\n// classes and ARIA — the same split datepicker.ts draws between\n// \"field concerns\" and the grid widget's own math (there, Calendar's;\n// here, the swatch grid's and the custom panel's).\n// ============================================================\n\nexport type ColorPickerVariant = \"both\" | \"presets\" | \"custom\";\n\nexport interface ColorPickerCoreProps extends FieldProps {\n /** Preset swatches offered in the popover, as hex strings. Defaults to DEFAULT_PRESETS. */\n presets?: string[];\n /**\n * Which part(s) of the popover to show. `\"both\"` (default) is the\n * preset grid plus the custom saturation/hue panel underneath it.\n * `\"presets\"` shows only the grid — a fixed palette with no\n * arbitrary-color escape hatch. `\"custom\"` shows only the\n * saturation/hue panel — no preset shortcuts at all.\n */\n variant?: ColorPickerVariant;\n}\n\nexport interface ColorPickerState extends FieldState {\n presets: string[];\n variant: ColorPickerVariant;\n}\n\nexport const DEFAULT_PRESETS: string[] = [\n \"#ef4444\",\n \"#f97316\",\n \"#f59e0b\",\n \"#eab308\",\n \"#84cc16\",\n \"#22c55e\",\n \"#10b981\",\n \"#14b8a6\",\n \"#06b6d4\",\n \"#3b82f6\",\n \"#6366f1\",\n \"#8b5cf6\",\n \"#a855f7\",\n \"#d946ef\",\n \"#ec4899\",\n \"#6b7280\",\n \"#171717\",\n \"#ffffff\",\n];\n\nexport function resolveColorPickerState(props: ColorPickerCoreProps): ColorPickerState {\n return {\n ...resolveFieldState(props),\n presets: props.presets ?? DEFAULT_PRESETS,\n variant: props.variant ?? \"both\",\n };\n}\n\n// --- hex parsing / normalization -----------------------------------\n\nconst HEX_RE = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\n/** Whether `text` is a recognizable 3- or 6-digit hex color, with or without a leading `#`. */\nexport function isValidHex(text: string): boolean {\n return HEX_RE.test(text.trim());\n}\n\n/**\n * Normalizes any accepted hex input (`\"f00\"`, `\"#f00\"`, `\"ff0000\"`,\n * `\"#FF0000\"`) into a canonical lowercase `#rrggbb` string, or `null`\n * if it isn't a valid hex color at all. The single source of truth\n * every call site (typed-text commit, swatch click, the native color\n * input's own onChange) normalizes through, the same role\n * isDateSelectable/isTimeSelectable play for their fields.\n */\nexport function normalizeHex(text: string): string | null {\n const trimmed = text.trim();\n const match = trimmed.match(HEX_RE);\n if (!match) return null;\n let hex = match[1].toLowerCase();\n if (hex.length === 3) {\n hex = hex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return `#${hex}`;\n}\n\n/** Whether two hex strings (however formatted) represent the same color. */\nexport function isSameColor(a: string | null | undefined, b: string | null | undefined): boolean {\n if (!a || !b) return a === b;\n const na = normalizeHex(a);\n const nb = normalizeHex(b);\n return na !== null && na === nb;\n}\n\n/** Rough perceived-lightness check, used only to decide a checkmark's contrast color on a selected swatch — not a color-science API. */\nexport function isLightColor(hex: string): boolean {\n const normalized = normalizeHex(hex);\n if (!normalized) return true;\n const r = parseInt(normalized.slice(1, 3), 16);\n const g = parseInt(normalized.slice(3, 5), 16);\n const b = parseInt(normalized.slice(5, 7), 16);\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma > 0.6;\n}\n\n// --- classes ------------------------------------------------------\n\nexport function getSwatchClasses(input: { isSelected: boolean; isActive: boolean }): string {\n return [\n \"nx-colorpicker__swatch-option\",\n input.isSelected && \"nx-colorpicker__swatch-option--selected\",\n input.isActive && \"nx-colorpicker__swatch-option--active\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n// --- ARIA -----------------------------------------------------\n\nexport function getSwatchGridAriaProps(label: string) {\n return { role: \"listbox\" as const, \"aria-label\": label };\n}\n\nexport function getSwatchAriaProps(input: { isSelected: boolean; isFocusable: boolean; label: string }) {\n return {\n role: \"option\" as const,\n \"aria-selected\": input.isSelected,\n \"aria-label\": input.label,\n tabIndex: input.isFocusable ? 0 : -1,\n };\n}\n\nexport function getFieldTriggerAriaProps(state: FieldState, describedBy?: string) {\n return getFieldAriaProps(state, describedBy);\n}\n\n// --- custom panel: color space conversions --------------------------\n// The typed hex field and preset grid only ever need hex in/out, but\n// the custom panel (saturation/value area + hue slider + RGB/HSL\n// fields) needs to move between hex, RGB, HSV, and HSL freely. HSV\n// drives the SV area/hue slider (the natural space for a \"pick a hue,\n// then a shade of it\" 2D control); RGB/HSL are only ever produced for\n// display in their own format tab and round-tripped back through hex\n// on edit, so hex stays the single canonical value ColorPicker's\n// public onChange emits (Rule 10 — the public shape doesn't change).\n\nexport interface RGB {\n r: number;\n g: number;\n b: number;\n}\n\nexport interface HSV {\n h: number;\n s: number;\n v: number;\n}\n\nexport interface HSL {\n h: number;\n s: number;\n l: number;\n}\n\nexport type ColorFormat = \"hex\" | \"rgb\" | \"hsl\";\n\nexport const COLOR_FORMATS: ColorFormat[] = [\"hex\", \"rgb\", \"hsl\"];\n\nfunction clampNum(n: number, min: number, max: number): number {\n return Math.min(Math.max(n, min), max);\n}\n\n/** Hex (any accepted shape, see `normalizeHex`) to 0-255 RGB channels, or `null` if not a valid hex color. */\nexport function hexToRgb(hex: string): RGB | null {\n const normalized = normalizeHex(hex);\n if (!normalized) return null;\n return {\n r: parseInt(normalized.slice(1, 3), 16),\n g: parseInt(normalized.slice(3, 5), 16),\n b: parseInt(normalized.slice(5, 7), 16),\n };\n}/** 0-255 RGB channels (rounded, clamped) to canonical lowercase `#rrggbb`. */\nexport function rgbToHex({ r, g, b }: RGB): string {\n const channel = (n: number) => clampNum(Math.round(n), 0, 255).toString(16).padStart(2, \"0\");\n return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\n/** 0-255 RGB to HSV (`h` in 0-360, `s`/`v` in 0-100). */\nexport function rgbToHsv({ r, g, b }: RGB): HSV {\n const rn = r / 255,\n gn = g / 255,\n bn = b / 255;\n const max = Math.max(rn, gn, bn),\n min = Math.min(rn, gn, bn);\n const d = max - min;\n let h = 0;\n if (d !== 0) {\n if (max === rn) h = ((gn - bn) / d) % 6;\n else if (max === gn) h = (bn - rn) / d + 2;\n else h = (rn - gn) / d + 4;\n h *= 60;\n if (h < 0) h += 360;\n }\n const s = max === 0 ? 0 : d / max;\n return { h, s: s * 100, v: max * 100 };\n}\n\n/** HSV (`h` in 0-360, `s`/`v` in 0-100) to 0-255 RGB. */\nexport function hsvToRgb({ h, s, v }: HSV): RGB {\n const s1 = clampNum(s, 0, 100) / 100;\n const v1 = clampNum(v, 0, 100) / 100;\n const hh = (((h % 360) + 360) % 360) / 60;\n const c = v1 * s1;\n const x = c * (1 - Math.abs((hh % 2) - 1));\n const m = v1 - c;\n let [r1, g1, b1] = [0, 0, 0];\n if (hh < 1) [r1, g1, b1] = [c, x, 0];\n else if (hh < 2) [r1, g1, b1] = [x, c, 0];\n else if (hh < 3) [r1, g1, b1] = [0, c, x];\n else if (hh < 4) [r1, g1, b1] = [0, x, c];\n else if (hh < 5) [r1, g1, b1] = [x, 0, c];\n else [r1, g1, b1] = [c, 0, x];\n return { r: (r1 + m) * 255, g: (g1 + m) * 255, b: (b1 + m) * 255 };\n}\n\n/** 0-255 RGB to HSL (`h` in 0-360, `s`/`l` in 0-100). */\nexport function rgbToHsl({ r, g, b }: RGB): HSL {\n const rn = r / 255,\n gn = g / 255,\n bn = b / 255;\n const max = Math.max(rn, gn, bn),\n min = Math.min(rn, gn, bn);\n const l = (max + min) / 2;\n const d = max - min;\n let h = 0,\n s = 0;\n if (d !== 0) {\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n if (max === rn) h = ((gn - bn) / d) % 6;\n else if (max === gn) h = (bn - rn) / d + 2;\n else h = (rn - gn) / d + 4;\n h *= 60;\n if (h < 0) h += 360;\n }\n return { h, s: s * 100, l: l * 100 };\n}\n\n/** HSL (`h` in 0-360, `s`/`l` in 0-100) to 0-255 RGB. */\nexport function hslToRgb({ h, s, l }: HSL): RGB {\n const s1 = clampNum(s, 0, 100) / 100;\n const l1 = clampNum(l, 0, 100) / 100;\n const c = (1 - Math.abs(2 * l1 - 1)) * s1;\n const hh = (((h % 360) + 360) % 360) / 60;\n const x = c * (1 - Math.abs((hh % 2) - 1));\n const m = l1 - c / 2;\n let [r1, g1, b1] = [0, 0, 0];\n if (hh < 1) [r1, g1, b1] = [c, x, 0];\n else if (hh < 2) [r1, g1, b1] = [x, c, 0];\n else if (hh < 3) [r1, g1, b1] = [0, c, x];\n else if (hh < 4) [r1, g1, b1] = [0, x, c];\n else if (hh < 5) [r1, g1, b1] = [x, 0, c];\n else [r1, g1, b1] = [c, 0, x];\n return { r: (r1 + m) * 255, g: (g1 + m) * 255, b: (b1 + m) * 255 };\n}\n\n/** Hex to HSV, or `null` if not a valid hex color — the SV-area/hue-slider's read side. */\nexport function hexToHsv(hex: string): HSV | null {\n const rgb = hexToRgb(hex);\n return rgb ? rgbToHsv(rgb) : null;\n}\n\n/** HSV to canonical hex — the SV-area/hue-slider's write side. */\nexport function hsvToHex(hsv: HSV): string {\n return rgbToHex(hsvToRgb(hsv));\n}\n\n/** HSL to canonical hex — the HSL format tab's write side. */\nexport function hslToHex(hsl: HSL): string {\n return rgbToHex(hslToRgb(hsl));\n}\n\n// --- typed-field text: parsing whichever format is on screen, and\n// producing that format back out --------------------------------\n// The field's displayed text now follows whichever format tab is\n// active in the custom panel (hex/rgb/hsl) rather than always\n// showing hex, so it needs to accept typed `rgb(...)`/`hsla(...)`\n// text back, not just hex — otherwise a person editing the field\n// while \"RGB\" is selected would have their own format rejected.\n\nconst RGB_FUNCTION_RE = /^rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*[\\d.]+\\s*)?\\)$/i;\nconst HSL_FUNCTION_RE = /^hsla?\\(\\s*(-?\\d{1,3})\\s*,\\s*(\\d{1,3})%\\s*,\\s*(\\d{1,3})%\\s*(?:,\\s*[\\d.]+\\s*)?\\)$/i;\n\n/** Parses hex OR `rgb(a)(...)`/`hsl(a)(...)` function-notation text into normalized hex, or `null` if it's none of those. */\nexport function parseColorInput(text: string): string | null {\n const trimmed = text.trim();\n const hex = normalizeHex(trimmed);\n if (hex) return hex;\n\n const rgbMatch = trimmed.match(RGB_FUNCTION_RE);\n if (rgbMatch) {\n const [, r, g, b] = rgbMatch;\n return rgbToHex({ r: clampNum(Number(r), 0, 255), g: clampNum(Number(g), 0, 255), b: clampNum(Number(b), 0, 255) });\n }\n\n const hslMatch = trimmed.match(HSL_FUNCTION_RE);\n if (hslMatch) {\n const [, h, s, l] = hslMatch;\n return hslToHex({ h: clampNum(Number(h), 0, 360), s: clampNum(Number(s), 0, 100), l: clampNum(Number(l), 0, 100) });\n }\n\n return null;\n}\n\n/** Renders hex as text in the given format — the field's display-side counterpart to `parseColorInput`, so what's shown always matches whichever format tab is currently active. */\nexport function formatColorValue(hex: string, format: ColorFormat): string {\n if (format === \"hex\") return hex;\n const rgb = hexToRgb(hex);\n if (!rgb) return hex;\n if (format === \"rgb\") return `rgb(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)})`;\n const hsl = rgbToHsl(rgb);\n return `hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%)`;\n}\n\n/** Arrow-key deltas for the 2D saturation/value area (Shift for a larger step) — Home/End/PageUp/PageDown aren't meaningful on a 2D surface, so only the four arrows are handled, same spirit as Slider's own keyboard set restricted to what the control actually has. */\nexport function getSvKeyboardDelta(key: string, coarse: boolean): { ds: number; dv: number } | null {\n const step = coarse ? 10 : 2;\n switch (key) {\n case \"ArrowLeft\":\n return { ds: -step, dv: 0 };\n case \"ArrowRight\":\n return { ds: step, dv: 0 };\n case \"ArrowUp\":\n return { ds: 0, dv: step };\n case \"ArrowDown\":\n return { ds: 0, dv: -step };\n default:\n return null;\n }\n}\n\n/** Clamps a saturation or value percentage into 0-100. Exported so the SV area's pointer/keyboard handlers share one clamp rather than each re-deriving it. */\nexport function clampPercent(n: number): number {\n return clampNum(n, 0, 100);\n}\n\n// --- custom panel: classes / ARIA -----------------------------------\n\nexport function getFormatTabClasses(isActive: boolean): string {\n return [\"nx-colorpicker__format-tab\", isActive && \"nx-colorpicker__format-tab--active\"].filter(Boolean).join(\" \");\n}\n\nexport function getFormatTablistAriaProps(label: string) {\n return { role: \"tablist\" as const, \"aria-label\": label };\n}\n\nexport function getFormatTabAriaProps(isActive: boolean) {\n return { role: \"tab\" as const, \"aria-selected\": isActive, tabIndex: isActive ? 0 : -1 };\n}\n\nexport function getSvThumbAriaProps(saturation: number, value: number) {\n return {\n role: \"slider\" as const,\n \"aria-label\": \"Color saturation and brightness\",\n \"aria-valuetext\": `Saturation ${Math.round(saturation)}%, brightness ${Math.round(value)}%`,\n tabIndex: 0,\n };\n}","import type { Size } from \"./types\";\n\n// ============================================================\n// TABLE — pure core (Category F: complex/stateful).\n//\n// Per BUILDING-COMPONENTS.md's own note for this component: \"sort\n// state should be lifted to props the consumer can control, not\n// trapped inside the component\" — the same controlled-value shape\n// Input/Slider/NumberInput already use. Table itself holds no sort\n// or selection state; TableHead's `sortDirection` is a prop the\n// consumer supplies, and getNextSortDirection is exported so the\n// consumer's onSort handler doesn't have to reinvent the standard\n// asc → desc → unsorted cycle. Row SELECTION is intentionally not\n// modeled here at all — TableRow just renders whatever `selected`\n// boolean it's given, and a table with checkboxes composes the real\n// Checkbox component (Rule 12) rather than Table reimplementing a\n// second one. getSelectAllState is the one piece of selection logic\n// that's genuinely shared/non-trivial (the tri-state \"select all\"\n// checkbox's own state, computed from a count) — pulled out here so\n// it's unit-tested the same way everything else pure is.\n// ============================================================\n\nexport interface TableCoreProps {\n size?: Size;\n /** Alternating row background. Default false. */\n striped?: boolean;\n /** Borders around every cell, not just horizontal row rules. Default false. */\n bordered?: boolean;\n /** Keeps the header visible while the body scrolls — only has something to stick within if an ancestor bounds the table's height (e.g. a wrapping div with max-height). Default false. */\n stickyHeader?: boolean;\n}\n\nexport interface TableState {\n size: Size;\n striped: boolean;\n bordered: boolean;\n stickyHeader: boolean;\n}\n\nexport function resolveTableState(props: TableCoreProps): TableState {\n return {\n size: props.size ?? \"md\",\n striped: props.striped ?? false,\n bordered: props.bordered ?? false,\n stickyHeader: props.stickyHeader ?? false,\n };\n}\n\nexport function getWrapperClasses(className?: string): string {\n return [\"nx-table-wrapper\", className].filter(Boolean).join(\" \");\n}\n\nexport function getTableClasses(state: TableState, className?: string): string {\n return [\n \"nx-table\",\n `nx-table--${state.size}`,\n state.striped && \"nx-table--striped\",\n state.bordered && \"nx-table--bordered\",\n state.stickyHeader && \"nx-table--sticky-header\",\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function getRowClasses(selected: boolean, clickable: boolean, className?: string): string {\n return [\n \"nx-table__row\",\n selected && \"nx-table__row--selected\",\n clickable && \"nx-table__row--clickable\",\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function getHeadCellClasses(sortable: boolean, className?: string): string {\n return [\"nx-table__head-cell\", sortable && \"nx-table__head-cell--sortable\", className].filter(Boolean).join(\" \");\n}\n\nexport function getCellClasses(className?: string): string {\n return [\"nx-table__cell\", className].filter(Boolean).join(\" \");\n}\n\n// --- Sorting ----------------------------------------------------\n\nexport type SortDirection = \"asc\" | \"desc\" | null;\n\n/** The conventional 3-state cycle a sortable header click steps through: unsorted → asc → desc → unsorted. */\nexport function getNextSortDirection(current: SortDirection): SortDirection {\n if (current === null) return \"asc\";\n if (current === \"asc\") return \"desc\";\n return null;\n}\n\nexport function getSortAriaProps(direction: SortDirection) {\n return {\n \"aria-sort\":\n direction === \"asc\" ? (\"ascending\" as const) : direction === \"desc\" ? (\"descending\" as const) : (\"none\" as const),\n };\n}\n\n// --- Selection ----------------------------------------------------\n\nexport type SelectAllState = \"none\" | \"some\" | \"all\";\n\n/** The tri-state a \"select all\" header checkbox should show, computed from how many of the total rows are currently selected. */\nexport function getSelectAllState(totalCount: number, selectedCount: number): SelectAllState {\n if (totalCount <= 0 || selectedCount <= 0) return \"none\";\n if (selectedCount >= totalCount) return \"all\";\n return \"some\";\n}"],"mappings":"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","names":["registry"]}
package/dist/index.cjs CHANGED
@@ -328,7 +328,17 @@ var glass = defineTheme({
328
328
  background: "transparent",
329
329
  surface: "rgba(255,255,255,0.55)",
330
330
  surfaceRaised: "rgba(255,255,255,0.75)",
331
- border: "rgba(255,255,255,0.35)",
331
+ // Was rgba(255,255,255,0.35) — translucent WHITE. Composited on
332
+ // a plain white page (the theme's own meta.description admits it
333
+ // "needs a rich background behind it," but most consumers won't
334
+ // add one), that resolves to literal #ffffff — a 1.0:1 contrast
335
+ // ratio, i.e. actually invisible, which is the reported vanished
336
+ // Progress-track border. A neutral slate tint stays visible
337
+ // against both a plain white AND a plain black fallback backdrop
338
+ // (measured ~2.1-2.3:1 either way) — short of full 3:1 UI-contrast
339
+ // on both extremes at once, but a large improvement over 1.0, and
340
+ // still reads as a soft glass edge over an actual rich backdrop.
341
+ border: "rgba(100,116,139,0.6)",
332
342
  borderFocus: "#9ca3af",
333
343
  text: "#111827",
334
344
  textMuted: "rgba(17,24,39,0.65)",
@@ -462,7 +472,13 @@ var neobrutalism = defineTheme({
462
472
  surface: "#ffffff",
463
473
  surfaceRaised: "#ffffff",
464
474
  border: "#000000",
465
- borderFocus: "#000000"
475
+ borderFocus: "#000000",
476
+ // light.color.warning.light (#fef3c7) is identical to this
477
+ // theme's own background — every warning Alert/Badge/etc. was
478
+ // rendering invisibly on the page. Bumped to the next step in
479
+ // the same warm-amber family (matches light.color.warning.subtle)
480
+ // so it stays on-theme but is actually visible against the page.
481
+ warning: { ...light.color.warning, light: "#fde68a" }
466
482
  },
467
483
  radius: { sm: "4px", md: "6px", lg: "8px", xl: "10px", "2xl": "12px", full: "9999px" },
468
484
  shadow: {
@@ -526,7 +542,24 @@ var gradient = defineTheme({
526
542
  surface: "linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,255,255,0.75))",
527
543
  surfaceRaised: "#ffffff",
528
544
  border: "rgba(118,75,162,0.25)",
529
- borderFocus: "#764ba2"
545
+ borderFocus: "#764ba2",
546
+ // text/textMuted were still light theme's values (#111827 /
547
+ // #6b7280) — fine on the near-white `surface`, but components
548
+ // that render straight on `background` (Timeline, Pagination,
549
+ // Tabs — all used with no wrapping surface in this library's own
550
+ // docs examples) sat directly on the purple gradient instead.
551
+ // Measured contrast against the gradient's darker stop
552
+ // (#764ba2): text 2.79:1, textMuted a barely-there 1.32:1 — the
553
+ // reported "nearly invisible" text. Darkened both; textMuted
554
+ // still can't clear 4.5:1 against the darkest point of this
555
+ // specific gradient with a single flat color (nothing dark
556
+ // enough to do that stays legible as "muted" against the near-
557
+ // white surface too), so this is the best available compromise
558
+ // within a single global text/textMuted pair, not a full fix —
559
+ // worth knowing if it still reads as low-contrast on the
560
+ // darkest corner of the gradient.
561
+ text: "#000000",
562
+ textMuted: "#2e2440"
530
563
  },
531
564
  radius: { sm: "12px", md: "18px", lg: "24px", xl: "32px", "2xl": "40px", full: "9999px" },
532
565
  shadow: {