@nadicodeai/ui 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/AGENTS.md +2 -0
  2. package/dist/components/brand-icons/apple.d.ts +18 -0
  3. package/dist/components/brand-icons/apple.d.ts.map +1 -0
  4. package/dist/components/brand-icons/apple.js +22 -0
  5. package/dist/components/brand-icons/brand-icon.d.ts +22 -0
  6. package/dist/components/brand-icons/brand-icon.d.ts.map +1 -0
  7. package/dist/components/brand-icons/brand-icon.js +26 -0
  8. package/dist/components/brand-icons/linux.d.ts +18 -0
  9. package/dist/components/brand-icons/linux.d.ts.map +1 -0
  10. package/dist/components/brand-icons/linux.js +25 -0
  11. package/dist/components/brand-icons/windows.d.ts +18 -0
  12. package/dist/components/brand-icons/windows.d.ts.map +1 -0
  13. package/dist/components/brand-icons/windows.js +22 -0
  14. package/dist/components/brand-icons.d.ts +5 -0
  15. package/dist/components/brand-icons.d.ts.map +1 -0
  16. package/dist/components/brand-icons.js +10 -0
  17. package/dist/components/button.js +1 -1
  18. package/dist/components/card-marketing.js +2 -2
  19. package/dist/components/card.d.ts +4 -3
  20. package/dist/components/card.d.ts.map +1 -1
  21. package/dist/components/card.js +12 -2
  22. package/dist/components/chart-breakdown-table.js +1 -1
  23. package/dist/components/chart-bullet-bar.d.ts +18 -2
  24. package/dist/components/chart-bullet-bar.d.ts.map +1 -1
  25. package/dist/components/chart-bullet-bar.js +62 -9
  26. package/dist/components/chart-date-range-control.d.ts +11 -1
  27. package/dist/components/chart-date-range-control.d.ts.map +1 -1
  28. package/dist/components/chart-date-range-control.js +13 -3
  29. package/dist/components/chart-entity-colors.d.ts +7 -1
  30. package/dist/components/chart-entity-colors.d.ts.map +1 -1
  31. package/dist/components/chart-entity-colors.js +7 -1
  32. package/dist/components/chart-kpi-stat.d.ts.map +1 -1
  33. package/dist/components/chart-kpi-stat.js +1 -1
  34. package/dist/components/chart-time-series.d.ts.map +1 -1
  35. package/dist/components/chart-time-series.js +62 -4
  36. package/dist/components/chart.js +2 -2
  37. package/dist/components/code-editor-mockup.js +1 -1
  38. package/dist/components/nav-bar.js +1 -1
  39. package/dist/components/radio-group.d.ts +1 -1
  40. package/dist/components/radio-group.d.ts.map +1 -1
  41. package/dist/components/radio-group.js +2 -2
  42. package/dist/components/theme-mode-switcher.d.ts +10 -3
  43. package/dist/components/theme-mode-switcher.d.ts.map +1 -1
  44. package/dist/components/theme-mode-switcher.js +14 -7
  45. package/dist/eslint/index.js +91 -0
  46. package/dist/eslint/rules/jsx-class-utility.js +231 -0
  47. package/dist/eslint/rules/no-deprecated-zod-api.js +156 -0
  48. package/dist/eslint/rules/no-design-system-src-import.js +11 -0
  49. package/dist/eslint/rules/no-invalid-token-utility.js +46 -0
  50. package/dist/eslint/rules/no-native-visible-control.js +86 -0
  51. package/dist/eslint/rules/no-raw-color-utility.js +109 -0
  52. package/dist/eslint/rules/no-raw-focus-ring-width.js +30 -0
  53. package/dist/eslint/rules/no-raw-logo-import.js +41 -0
  54. package/dist/eslint/rules/no-shadcn-appearance-override.js +191 -0
  55. package/dist/eslint/rules/no-token-category-bypass.js +53 -0
  56. package/dist/eslint/rules/no-ui-src-import.js +10 -0
  57. package/dist/eslint/rules/no-unpinned-vercel-functions-import.js +100 -0
  58. package/dist/eslint/rules/src-import-boundary.js +207 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +1 -0
  62. package/docs/consuming-cross-repo.md +23 -0
  63. package/docs/contract.md +10 -0
  64. package/package.json +9 -3
package/AGENTS.md CHANGED
@@ -8,6 +8,7 @@ The `@nadicodeai/ui` npm workspace: the shared NadicodeAI React UI package on br
8
8
  | --- | --- |
9
9
  | `npm run dev -w @nadicodeai/ui` | Watch `src/` and incrementally refresh `dist/` for local website or app iteration |
10
10
  | `npm run build:fast -w @nadicodeai/ui` | One-shot incremental `dist/` refresh after a prior full build |
11
+ | `npm run generate:brand-icons -w @nadicodeai/ui` | Re-emit `src/components/brand-icons/` after editing the allow-list in `scripts/build-brand-icons.mjs`; never part of the build |
11
12
  | `npm run build -w @nadicodeai/ui` | Emit the consumable `dist/` surface before packing or app builds |
12
13
  | `npm pack --dry-run -w @nadicodeai/ui` | Verify exactly what npm consumers receive after surface, export, CSS, docs, or skill changes |
13
14
  | `npm run lint -w @nadicodeai/ui` / `npm run typecheck -w @nadicodeai/ui` | ESLint / `tsc --noEmit` |
@@ -19,6 +20,7 @@ The `@nadicodeai/ui` npm workspace: the shared NadicodeAI React UI package on br
19
20
  | --- | --- |
20
21
  | Shared design-language terms | `../../design-system/CONTEXT.md` |
21
22
  | Package invariants, component admission, section vocabulary, consumer boundary | `docs/contract.md` |
23
+ | Third-party brand marks (other companies' logos) | `docs/contract.md` "Admission Rules", then `../../docs/adr/0042-third-party-brand-marks-are-generated-identity-images.md`; the NadicodeAI logo is a different system and stays with `BrandLockup`/`BrandMark`/`BrandWordmark` |
22
24
  | React consumer installation and stylesheet setup | `docs/consuming-cross-repo.md` |
23
25
  | Token, mode, theme, cascade, and public stylesheet architecture | `../../design-system/DESIGN.md` (this package does not own a second token map) |
24
26
  | Motion behavior | `../../design-system/DESIGN.md` "Motion", `src/lib/motion.ts`, then `../../skills/nadicodeai-product-design/references/motion-craft.md` for agent procedure |
@@ -0,0 +1,18 @@
1
+ import { type BrandIconProps } from "./brand-icon";
2
+ /**
3
+ * The apple mark from the Iconify `logos` set.
4
+ *
5
+ * Drawn as one silhouette, so it paints with `currentColor` and stays
6
+ * under the semantic theme in every mode.
7
+ *
8
+ * Under forced-colors mode the mark flattens to the user's system colors. That
9
+ * loss of brand color is the correct outcome of a contrast choice the user made,
10
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
11
+ * preserves the paint.
12
+ *
13
+ * Hidden from assistive technology by default because a brand mark sits beside
14
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
15
+ * the mark stands alone.
16
+ */
17
+ export declare function AppleIcon({ size, ...props }: BrandIconProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=apple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../../src/components/brand-icons/apple.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAsB,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAgB7E"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Generated by scripts/build-brand-icons.mjs from @iconify-json/logos (CC0-1.0).
3
+ // Edit the allow-list in that script and regenerate; hand edits to brand-icons/apple.tsx are lost.
4
+ import { BRAND_ICON_SIZE, brandIconLabelling } from "./brand-icon.js";
5
+ /**
6
+ * The apple mark from the Iconify `logos` set.
7
+ *
8
+ * Drawn as one silhouette, so it paints with `currentColor` and stays
9
+ * under the semantic theme in every mode.
10
+ *
11
+ * Under forced-colors mode the mark flattens to the user's system colors. That
12
+ * loss of brand color is the correct outcome of a contrast choice the user made,
13
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
14
+ * preserves the paint.
15
+ *
16
+ * Hidden from assistive technology by default because a brand mark sits beside
17
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
18
+ * the mark stands alone.
19
+ */
20
+ export function AppleIcon({ size = BRAND_ICON_SIZE, ...props }) {
21
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 256 315", fill: "currentColor", "data-slot": "brand-icon", "data-brand": "apple", ...props, ...brandIconLabelling(props), children: _jsx("path", { d: "M213.803 167.03c.442 47.58 41.74 63.413 42.197 63.615c-.35 1.116-6.599 22.563-21.757 44.716c-13.104 19.153-26.705 38.235-48.13 38.63c-21.05.388-27.82-12.483-51.888-12.483c-24.061 0-31.582 12.088-51.51 12.871c-20.68.783-36.428-20.71-49.64-39.793c-27-39.033-47.633-110.3-19.928-158.406c13.763-23.89 38.36-39.017 65.056-39.405c20.307-.387 39.475 13.662 51.889 13.662c12.406 0 35.699-16.895 60.186-14.414c10.25.427 39.026 4.14 57.503 31.186c-1.49.923-34.335 20.044-33.978 59.822M174.24 50.199c10.98-13.29 18.369-31.79 16.353-50.199c-15.826.636-34.962 10.546-46.314 23.828c-10.173 11.763-19.082 30.589-16.678 48.633c17.64 1.365 35.66-8.964 46.64-22.262" }) }));
22
+ }
@@ -0,0 +1,22 @@
1
+ import type * as React from "react";
2
+ /** Matches the Lucide default so a brand mark drops into an icon slot unchanged. */
3
+ export declare const BRAND_ICON_SIZE = 24;
4
+ export type BrandIconProps = React.SVGProps<SVGSVGElement> & {
5
+ /** Rendered box in CSS pixels; the mark is centred inside it at its own ratio. */
6
+ size?: number;
7
+ };
8
+ /**
9
+ * A brand mark is decorative beside its text label and meaningful on its own.
10
+ * Callers declare the second case by naming the mark; everything else stays
11
+ * hidden from assistive technology rather than announcing a stray brand word.
12
+ *
13
+ * A name is the whole declaration. A bare `role="img"` says the mark matters
14
+ * without saying what it is, which exposes an image with no accessible name, so
15
+ * the mark stays hidden until a name arrives with it. An empty or blank name
16
+ * is no name, and the hidden fallback follows caller props so a spread cannot
17
+ * accidentally unhide an unnamed mark.
18
+ */
19
+ export declare function brandIconLabelling(props: BrandIconProps): {
20
+ "aria-hidden"?: true;
21
+ };
22
+ //# sourceMappingURL=brand-icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand-icon.d.ts","sourceRoot":"","sources":["../../../src/components/brand-icons/brand-icon.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAUpC,oFAAoF;AACpF,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG;IAC3D,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG;IAAE,aAAa,CAAC,EAAE,IAAI,CAAA;CAAE,CAIlF"}
@@ -0,0 +1,26 @@
1
+ // Generated by scripts/build-brand-icons.mjs from @iconify-json/logos (CC0-1.0).
2
+ // Edit the allow-list in that script and regenerate; hand edits to brand-icons/brand-icon.ts are lost.
3
+ /*
4
+ * The shared shape of every generated brand mark.
5
+ *
6
+ * Brand marks are identity images, not UI icons: they carry a third party's
7
+ * artwork verbatim and are exempt from the Lucide currentColor stroke system.
8
+ * They never stand in for a UI icon, and a UI icon never stands in for one.
9
+ */
10
+ /** Matches the Lucide default so a brand mark drops into an icon slot unchanged. */
11
+ export const BRAND_ICON_SIZE = 24;
12
+ /**
13
+ * A brand mark is decorative beside its text label and meaningful on its own.
14
+ * Callers declare the second case by naming the mark; everything else stays
15
+ * hidden from assistive technology rather than announcing a stray brand word.
16
+ *
17
+ * A name is the whole declaration. A bare `role="img"` says the mark matters
18
+ * without saying what it is, which exposes an image with no accessible name, so
19
+ * the mark stays hidden until a name arrives with it. An empty or blank name
20
+ * is no name, and the hidden fallback follows caller props so a spread cannot
21
+ * accidentally unhide an unnamed mark.
22
+ */
23
+ export function brandIconLabelling(props) {
24
+ const named = Boolean(props["aria-label"]?.trim()) || Boolean(props["aria-labelledby"]?.trim());
25
+ return named ? {} : { "aria-hidden": true };
26
+ }
@@ -0,0 +1,18 @@
1
+ import { type BrandIconProps } from "./brand-icon";
2
+ /**
3
+ * The linux-tux mark from the Iconify `logos` set.
4
+ *
5
+ * Painted in the brand's official colors. Those colors are the identity
6
+ * being shown, so they do not follow the semantic theme.
7
+ *
8
+ * Under forced-colors mode the mark flattens to the user's system colors. That
9
+ * loss of brand color is the correct outcome of a contrast choice the user made,
10
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
11
+ * preserves the paint.
12
+ *
13
+ * Hidden from assistive technology by default because a brand mark sits beside
14
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
15
+ * the mark stands alone.
16
+ */
17
+ export declare function LinuxIcon({ size, ...props }: BrandIconProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../../../src/components/brand-icons/linux.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAsB,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BA4P7E"}
@@ -0,0 +1,25 @@
1
+ // Generated by scripts/build-brand-icons.mjs from @iconify-json/logos (CC0-1.0).
2
+ // Edit the allow-list in that script and regenerate; hand edits to brand-icons/linux.tsx are lost.
3
+ "use client";
4
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ import { useId } from "react";
6
+ import { BRAND_ICON_SIZE, brandIconLabelling } from "./brand-icon.js";
7
+ /**
8
+ * The linux-tux mark from the Iconify `logos` set.
9
+ *
10
+ * Painted in the brand's official colors. Those colors are the identity
11
+ * being shown, so they do not follow the semantic theme.
12
+ *
13
+ * Under forced-colors mode the mark flattens to the user's system colors. That
14
+ * loss of brand color is the correct outcome of a contrast choice the user made,
15
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
16
+ * preserves the paint.
17
+ *
18
+ * Hidden from assistive technology by default because a brand mark sits beside
19
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
20
+ * the mark stands alone.
21
+ */
22
+ export function LinuxIcon({ size = BRAND_ICON_SIZE, ...props }) {
23
+ const scope = `brand-icon-linux-${useId().replace(/[^a-zA-Z0-9]/g, "")}`;
24
+ return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 256 295", "data-slot": "brand-icon", "data-brand": "linux", ...props, ...brandIconLabelling(props), children: [_jsxs("defs", { children: [_jsxs("linearGradient", { id: `${scope}-a`, x1: "48.548%", x2: "51.047%", y1: "115.276%", y2: "41.364%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-b`, x1: "54.407%", x2: "46.175%", y1: "2.404%", y2: "90.542%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".8" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-c`, x1: "51.86%", x2: "47.947%", y1: "88.248%", y2: "9.748%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-d`, x1: "49.925%", x2: "49.924%", y1: "85.49%", y2: "13.811%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-e`, x1: "53.901%", x2: "45.956%", y1: "3.102%", y2: "93.895%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-f`, x1: "45.593%", x2: "54.811%", y1: "5.475%", y2: "93.524%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-g`, x1: "49.984%", x2: "49.984%", y1: "89.845%", y2: "40.632%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-h`, x1: "53.505%", x2: "42.746%", y1: "99.975%", y2: "23.545%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-i`, x1: "49.841%", x2: "50.241%", y1: "13.229%", y2: "94.673%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".8" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-j`, x1: "49.927%", x2: "50.727%", y1: "37.327%", y2: "92.782%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-k`, x1: "49.876%", x2: "49.876%", y1: "2.299%", y2: "81.204%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-l`, x1: "49.833%", x2: "49.824%", y1: "2.272%", y2: "71.799%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-m`, x1: "53.467%", x2: "38.949%", y1: "48.921%", y2: "98.1%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffa63f" }), _jsx("stop", { offset: "100%", stopColor: "#ff0" })] }), _jsxs("linearGradient", { id: `${scope}-n`, x1: "52.373%", x2: "47.579%", y1: "143.009%", y2: "-64.622%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffeed7" }), _jsx("stop", { offset: "100%", stopColor: "#bdbfc2" })] }), _jsxs("linearGradient", { id: `${scope}-o`, x1: "30.581%", x2: "65.887%", y1: "34.024%", y2: "89.175%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffa63f" }), _jsx("stop", { offset: "100%", stopColor: "#ff0" })] }), _jsxs("linearGradient", { id: `${scope}-p`, x1: "59.572%", x2: "48.361%", y1: "-17.216%", y2: "66.118%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-q`, x1: "47.769%", x2: "51.373%", y1: "1.565%", y2: "104.313%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-r`, x1: "43.55%", x2: "57.114%", y1: "4.533%", y2: "92.827%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("linearGradient", { id: `${scope}-s`, x1: "49.733%", x2: "50.558%", y1: "17.609%", y2: "99.385%", children: [_jsx("stop", { offset: "0%", stopColor: "#ffa63f" }), _jsx("stop", { offset: "100%", stopColor: "#ff0" })] }), _jsxs("linearGradient", { id: `${scope}-t`, x1: "50.17%", x2: "49.68%", y1: "2.89%", y2: "94.17%", children: [_jsx("stop", { offset: "0%", stopColor: "#fff", stopOpacity: ".65" }), _jsx("stop", { offset: "100%", stopColor: "#fff", stopOpacity: "0" })] }), _jsxs("filter", { id: `${scope}-u`, width: "200%", height: "200%", x: "-50%", y: "-50%", filterUnits: "objectBoundingBox", children: [_jsx("feOffset", { in: "SourceAlpha", result: "shadowOffsetOuter1" }), _jsx("feGaussianBlur", { in: "shadowOffsetOuter1", result: "shadowBlurOuter1", stdDeviation: "6.5" })] })] }), _jsxs("g", { fill: "none", children: [_jsx("path", { fill: "#000", fillOpacity: ".2", d: "M235.125 249.359c0 17.355-52.617 31.497-117.54 31.497S.044 266.806.044 249.359c0-17.356 52.618-31.498 117.54-31.498c64.924 0 117.45 14.142 117.541 31.498", filter: `url(#${scope}-u)`, transform: "translate(10)" }), _jsx("path", { fill: "#000", d: "M63.213 215.474c-11.387-16.346-13.591-69.606 12.947-102.39C89.292 97.383 92.69 86.455 93.7 71.67c.734-16.805-11.846-66.851 35.537-70.616c48.027-3.857 45.364 43.526 45.088 68.596c-.183 21.12 15.52 33.15 26.355 49.68c19.927 30.303 18.274 82.461-3.765 110.745c-27.916 35.354-51.791 20.018-67.678 21.304c-29.752 1.745-30.762 17.54-66.024-35.905" }), _jsx("path", { fill: `url(#${scope}-a)`, d: "M169.1 122.451c8.265 7.622 29.661 41.69-4.224 62.995c-11.937 7.438 10.653 35.721 21.488 22.039c19.193-24.61 6.98-63.913-4.591-77.963c-7.714-9.917-19.651-13.774-12.672-7.07", transform: "translate(10)" }), _jsx("path", { fill: "#000", stroke: "#000", strokeWidth: ".977", d: "M176.805 117.86c13.59 11.02 38.292 49.587 2.204 74.748c-11.846 7.806 10.468 32.508 23.049 19.927c43.618-43.894-1.102-94.308-16.53-111.664c-13.774-15.151-25.987 3.49-8.723 16.989Z" }), _jsx("path", { fill: `url(#${scope}-b)`, d: "M147.245 25.02c-.459 12.581-14.325 23.51-30.946 24.52S86.639 41 87.097 28.418c.46-12.581 14.326-23.509 30.947-24.519c16.62-.918 29.66 8.54 29.201 21.12", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-c)`, d: "M107.483 54.957c.46 8.173-3.397 15.06-8.723 15.335s-10.01-6.06-10.47-14.232S91.688 41 97.014 40.725s10.01 6.06 10.468 14.233", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-d)`, d: "M117.125 55.6c.184 9.458 6.337 16.988 13.683 16.805c7.346-.184 13.131-7.99 12.948-17.54c-.184-9.458-6.336-16.988-13.683-16.804c-7.346.183-13.223 8.08-12.948 17.539", transform: "translate(10)" }), _jsx("path", { fill: "#000", d: "M133.186 57.712c-.092 5.234 2.48 9.458 5.877 9.458c3.306 0 6.153-4.224 6.245-9.366c.091-5.234-2.48-9.459-5.878-9.459c-3.397 0-6.152 4.225-6.244 9.367m-21.212.092c.459 4.316-1.194 7.989-3.582 8.356c-2.387.276-4.683-2.938-5.142-7.254s1.194-7.99 3.581-8.357c2.388-.275 4.684 2.939 5.143 7.255" }), _jsx("path", { fill: `url(#${scope}-e)`, d: "M124.564 54.773c-.276 2.939 1.102 5.326 3.03 5.51s3.765-2.112 4.04-4.959c.276-2.938-1.102-5.326-3.03-5.51c-1.928-.183-3.765 2.113-4.04 4.96", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-f)`, d: "M99.953 55.508c.276 2.388-.734 4.5-2.203 4.683c-1.47.184-2.847-1.653-3.123-4.132c-.275-2.388.735-4.5 2.204-4.683c1.47-.184 2.847 1.744 3.122 4.132", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-g)`, d: "M71.027 145.684c6.52-14.785 20.386-40.772 20.662-60.883c0-15.978 47.843-19.835 51.7-3.856c3.856 15.978 13.59 39.853 19.834 51.424c6.245 11.478 24.335 48.118 5.051 80.074c-17.356 28.284-69.973 50.69-98.073-3.856c-9.55-18.917-7.806-42.333.826-62.903", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-h)`, d: "M65.15 134.664c-5.601 10.56-17.172 38.293 11.112 53.445c30.395 16.162 30.303 49.312-6.245 33.517c-33.425-14.233-18.641-71.902-9.274-85.676c6.06-9.642 15.243-21.488 4.407-1.286", transform: "translate(10)" }), _jsx("path", { fill: "#000", stroke: "#000", strokeWidth: "1.25", d: "M79.925 122.727c-8.907 14.509-30.211 48.669-1.652 66.484c38.384 23.6 27.548 47.108-7.53 25.895c-49.404-29.568-5.97-89.257 13.774-112.03c22.59-25.529 4.316 4.683-4.592 19.65Z" }), _jsx("path", { fill: `url(#${scope}-i)`, d: "M156.428 151.285c0 16.162-15.519 37.1-42.15 36.916c-27.456.183-39.118-20.754-39.118-36.916s18.182-29.293 40.588-29.293c22.498.092 40.68 13.132 40.68 29.293", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-j)`, d: "M141.92 100.504c-.276 16.713-11.204 20.662-24.978 20.662s-23.784-2.48-24.978-20.662c0-11.387 11.203-17.998 24.978-17.998c13.774-.092 24.977 6.52 24.977 17.998", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-k)`, d: "M58.63 126.216c9-13.682 28.008-34.711 3.582 2.939c-19.835 31.038-7.346 50.965-.918 56.474c18.549 16.53 17.814 27.64 3.214 18.917c-31.314-18.641-24.794-50.047-5.878-78.33", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-l)`, d: "M188.936 131.818c-7.806-16.07-32.6-56.842 1.193-9.459c30.763 42.884 9.183 72.729 5.326 75.667c-3.856 2.939-16.804 8.908-13.04-1.469c3.858-10.377 22.958-30.028 6.52-64.74", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-m)`, stroke: "#e68c3f", strokeWidth: "6.25", d: "M51.835 258.542c-20.57-10.928-50.414 2.112-39.578-27.457c2.204-6.704-3.214-16.805.275-23.325c4.133-7.989 13.04-6.244 18.366-11.57c5.234-5.51 8.54-15.06 18.366-13.59c9.734 1.468 16.254 13.406 23.049 28.099c5.05 10.468 22.865 25.253 21.672 37.007c-1.47 17.998-21.948 21.396-42.15 10.836Z", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-n)`, d: "M201.608 189.119c-3.122 5.877-16.162 15.335-24.886 12.856c-8.815-2.388-12.856-15.795-11.111-25.988c1.653-11.386 11.111-12.03 23.05-6.336c12.855 6.336 16.712 11.662 12.947 19.468", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-o)`, stroke: "#e68c3f", strokeWidth: "6.251", d: "M194.445 253.49c15.06-18.273 48.578-14.508 25.988-39.577c-4.775-5.418-3.306-16.989-9.183-21.947c-6.887-6.061-14.509-1.102-21.488-4.224c-6.979-3.398-14.325-9.918-22.865-5.327c-8.54 4.684-9.459 16.805-10.285 32.783c-.735 11.479-11.203 30.671-5.602 41.231c8.081 16.346 29.11 14.142 43.435-2.938Z", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-p)`, d: "M187.925 229.064c23.325-34.435 5.97-34.16.092-36.823c-5.877-2.755-12.03-8.173-18.916-4.408c-6.888 3.857-7.255 13.775-7.439 26.814c-.275 9.367-8.08 25.07-3.397 33.793c5.693 10.193 19.467-4.591 29.66-19.376", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-q)`, d: "M47.06 234.023c-34.895-22.59-18.55-30.303-13.315-33.885c6.336-4.591 6.428-13.407 14.233-12.58c7.806.826 12.397 10.468 17.631 22.406c3.857 8.54 17.264 19.927 16.254 29.753c-1.285 11.57-19.743 3.948-34.803-5.694", transform: "translate(10)" }), _jsx("path", { fill: "#000", d: "M209.588 188.843c-2.755 4.776-13.958 12.306-21.396 10.285c-7.622-1.928-11.112-12.672-9.55-20.753c1.377-9.183 9.55-9.642 19.834-5.05c10.928 4.958 14.326 9.182 11.112 15.518" }), _jsx("path", { fill: `url(#${scope}-r)`, d: "M192.058 186.18c-1.745 3.306-9.091 8.54-14.234 7.163c-5.142-1.377-7.713-8.815-6.887-14.417c.735-6.336 6.244-6.704 13.223-3.581c7.53 3.49 9.918 6.428 7.898 10.835", transform: "translate(10)" }), _jsx("path", { fill: `url(#${scope}-s)`, stroke: "#e68c3f", strokeWidth: "3.75", d: "M97.107 66.344c3.673-3.398 12.58-13.774 29.477-2.939c3.122 2.02 5.693 2.204 11.662 4.775c12.03 4.96 6.336 16.897-6.52 20.937c-5.51 1.745-10.468 8.449-20.386 7.806c-8.54-.46-10.744-6.06-15.978-9.091c-9.275-5.234-10.652-12.305-5.602-16.07c5.051-3.765 6.98-5.143 7.347-5.418Z", transform: "translate(10)" }), _jsx("path", { stroke: "#e68c3f", strokeWidth: "2.5", d: "M148.43 75.986c-5.05.275-15.979 11.203-27.457 11.203s-18.366-10.652-20.11-10.652" }), _jsx("path", { fill: `url(#${scope}-t)`, d: "M102.8 65.426c1.837-1.653 7.622-6.153 15.244-1.562c1.653.919 3.306 1.929 5.693 3.306c4.867 2.847 2.48 6.98-3.398 9.55c-2.663 1.102-7.07 3.49-10.376 3.306c-3.673-.367-6.153-2.755-8.54-4.316c-4.5-2.938-4.224-5.418-2.112-7.346c1.56-1.47 3.305-2.847 3.49-2.938", transform: "translate(10)" })] })] }));
25
+ }
@@ -0,0 +1,18 @@
1
+ import { type BrandIconProps } from "./brand-icon";
2
+ /**
3
+ * The microsoft-windows-icon mark from the Iconify `logos` set.
4
+ *
5
+ * Painted in the brand's official colors. Those colors are the identity
6
+ * being shown, so they do not follow the semantic theme.
7
+ *
8
+ * Under forced-colors mode the mark flattens to the user's system colors. That
9
+ * loss of brand color is the correct outcome of a contrast choice the user made,
10
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
11
+ * preserves the paint.
12
+ *
13
+ * Hidden from assistive technology by default because a brand mark sits beside
14
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
15
+ * the mark stands alone.
16
+ */
17
+ export declare function WindowsIcon({ size, ...props }: BrandIconProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=windows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../../../src/components/brand-icons/windows.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAsB,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAkB/E"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Generated by scripts/build-brand-icons.mjs from @iconify-json/logos (CC0-1.0).
3
+ // Edit the allow-list in that script and regenerate; hand edits to brand-icons/windows.tsx are lost.
4
+ import { BRAND_ICON_SIZE, brandIconLabelling } from "./brand-icon.js";
5
+ /**
6
+ * The microsoft-windows-icon mark from the Iconify `logos` set.
7
+ *
8
+ * Painted in the brand's official colors. Those colors are the identity
9
+ * being shown, so they do not follow the semantic theme.
10
+ *
11
+ * Under forced-colors mode the mark flattens to the user's system colors. That
12
+ * loss of brand color is the correct outcome of a contrast choice the user made,
13
+ * so `forced-color-adjust` stays at its `auto` default and nothing here
14
+ * preserves the paint.
15
+ *
16
+ * Hidden from assistive technology by default because a brand mark sits beside
17
+ * the text label that names it. Pass `role="img"` with an `aria-label` when
18
+ * the mark stands alone.
19
+ */
20
+ export function WindowsIcon({ size = BRAND_ICON_SIZE, ...props }) {
21
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 256 256", "data-slot": "brand-icon", "data-brand": "windows", ...props, ...brandIconLabelling(props), children: _jsx("path", { fill: "#0078d4", d: "M0 0h121.329v121.329H0zm134.671 0H256v121.329H134.671zM0 134.671h121.329V256H0zm134.671 0H256V256H134.671z" }) }));
22
+ }
@@ -0,0 +1,5 @@
1
+ export { BRAND_ICON_SIZE, brandIconLabelling, type BrandIconProps, } from "./brand-icons/brand-icon";
2
+ export { WindowsIcon } from "./brand-icons/windows";
3
+ export { AppleIcon } from "./brand-icons/apple";
4
+ export { LinuxIcon } from "./brand-icons/linux";
5
+ //# sourceMappingURL=brand-icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand-icons.d.ts","sourceRoot":"","sources":["../../src/components/brand-icons.tsx"],"names":[],"mappings":"AAOA,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,KAAK,cAAc,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /*
2
+ * Third-party brand marks, generated by scripts/build-brand-icons.mjs.
3
+ *
4
+ * Do not edit this file or ./brand-icons/ by hand: add the brand to the
5
+ * generator's allow-list and run `npm run generate:brand-icons`.
6
+ */
7
+ export { BRAND_ICON_SIZE, brandIconLabelling, } from "./brand-icons/brand-icon.js";
8
+ export { WindowsIcon } from "./brand-icons/windows.js";
9
+ export { AppleIcon } from "./brand-icons/apple.js";
10
+ export { LinuxIcon } from "./brand-icons/linux.js";
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Button as ButtonPrimitive } from "@base-ui/react/button";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { cn } from "../lib/utils.js";
5
- const buttonVariants = cva("group/button inline-flex min-h-touch-target min-w-touch-target shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[background-color,border-color,color] duration-[var(--nc-duration-confirm)] ease-[var(--nc-ease-out-strong)] outline-none select-none focus-visible:border-ring focus-visible:ring-[length:var(--ring-width-focus)] focus-visible:ring-ring active:not-aria-[haspopup]:opacity-90 motion-reduce:transition-none disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[length:var(--ring-width-focus)] aria-invalid:ring-destructive [@media(hover:hover)_and_(pointer:fine)]:min-h-0 [@media(hover:hover)_and_(pointer:fine)]:min-w-0 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
5
+ const buttonVariants = cva("group/button inline-flex min-h-touch-target min-w-touch-target shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[background-color,border-color,color,scale] duration-[var(--nc-duration-confirm)] ease-[var(--nc-ease-out-strong)] outline-none select-none focus-visible:border-ring focus-visible:ring-[length:var(--ring-width-focus)] focus-visible:ring-ring motion-safe:active:not-aria-[haspopup]:scale-[0.97] motion-reduce:transition-none disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[length:var(--ring-width-focus)] aria-invalid:ring-destructive [@media(hover:hover)_and_(pointer:fine)]:min-h-0 [@media(hover:hover)_and_(pointer:fine)]:min-w-0 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
6
6
  variants: {
7
7
  variant: {
8
8
  default: "bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active",
@@ -21,13 +21,13 @@ import { cn } from "../lib/utils.js";
21
21
  */
22
22
  function CardMarketing({ className, size = "default", surface = "canvas", ...props }) {
23
23
  return (_jsx("div", { "data-slot": "card-marketing", "data-size": size, "data-surface": surface, className: cn("grid content-start overflow-hidden border border-border text-foreground", surface === "soft" ? "bg-[var(--nc-canvas-soft)]" : "bg-card", size === "default" && [
24
- "gap-3 rounded-[var(--nc-rounded-md)] p-6",
24
+ "gap-3 rounded-md p-6",
25
25
  // media present -> compress padding; the media insets follow (below).
26
26
  "has-[[data-slot=card-marketing-media]]:gap-3 has-[[data-slot=card-marketing-media]]:p-4",
27
27
  "[&_[data-slot=card-marketing-title]]:text-xl",
28
28
  "[&_[data-slot=card-marketing-media]]:-mx-4 [&_[data-slot=card-marketing-media]]:-mt-4 [&_[data-slot=card-marketing-media]]:mb-1",
29
29
  ], size === "lg" && [
30
- "gap-4 rounded-[var(--nc-rounded-lg)] p-8",
30
+ "gap-4 rounded-lg p-8",
31
31
  "has-[[data-slot=card-marketing-media]]:p-6",
32
32
  "[&_[data-slot=card-marketing-title]]:text-2xl",
33
33
  "[&_[data-slot=card-marketing-media]]:-mx-6 [&_[data-slot=card-marketing-media]]:-mt-6 [&_[data-slot=card-marketing-media]]:mb-1.5",
@@ -1,9 +1,10 @@
1
1
  import * as React from "react";
2
- type CardVariant = "default" | "interactive" | "borderless";
3
- declare function Card({ className, size, variant, ...props }: React.ComponentProps<"div"> & {
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ type CardVariant = "default" | "interactive" | "link" | "borderless";
4
+ declare function Card({ className, render, size, variant, ...props }: useRender.ComponentProps<"div"> & {
4
5
  size?: "default" | "sm";
5
6
  variant?: CardVariant;
6
- }): React.JSX.Element;
7
+ }): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
7
8
  declare function CardHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
8
9
  declare function CardTitle({ className, focusTarget, ...props }: React.ComponentProps<"div"> & {
9
10
  focusTarget?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/components/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,KAAK,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,CAAC;AAE5D,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,IAAgB,EAChB,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,qBAeA;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,SAAS,CAAC,EACjB,SAAS,EACT,WAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,qBAczD;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAIxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/components/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAItD,KAAK,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;AAErE,iBAAS,IAAI,CAAC,EACZ,SAAS,EACT,MAAM,EACN,IAAgB,EAChB,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IACnC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,0EAmBA;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,SAAS,CAAC,EACjB,SAAS,EACT,WAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,qBAczD;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAIxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC"}
@@ -1,7 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { mergeProps } from "@base-ui/react/merge-props";
3
+ import { useRender } from "@base-ui/react/use-render";
2
4
  import { cn } from "../lib/utils.js";
3
- function Card({ className, size = "default", variant = "default", ...props }) {
4
- return (_jsx("div", { "data-slot": "card", "data-size": size, "data-variant": variant, className: cn("group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-md border border-border bg-card py-(--card-spacing) text-sm text-card-foreground [--card-spacing:var(--spacing-nadicode-lg)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:var(--spacing-nadicode-md)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-md *:[img:last-child]:rounded-b-md", variant === "interactive" && "transition-colors group-hover:bg-accent", variant === "borderless" && "border-0", className), ...props }));
5
+ function Card({ className, render, size = "default", variant = "default", ...props }) {
6
+ return useRender({
7
+ defaultTagName: "div",
8
+ props: mergeProps({
9
+ className: cn("group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-md border border-border bg-card py-(--card-spacing) text-sm text-card-foreground [--card-spacing:var(--spacing-nadicode-lg)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:var(--spacing-nadicode-md)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-md *:[img:last-child]:rounded-b-md", variant === "interactive" && "transition-colors group-hover:bg-accent", variant === "link" &&
10
+ "nc-transition-paint hover:border-ring focus-visible:outline-none focus-visible:ring-[length:var(--ring-width-focus)] focus-visible:ring-ring", variant === "borderless" && "border-0", className),
11
+ }, props),
12
+ render,
13
+ state: { size, slot: "card", variant },
14
+ });
5
15
  }
6
16
  function CardHeader({ className, ...props }) {
7
17
  return (_jsx("div", { "data-slot": "card-header", className: cn("group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-md px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)", className), ...props }));
@@ -12,7 +12,7 @@ function defaultFormat(value) {
12
12
  return value.toLocaleString("en-US");
13
13
  }
14
14
  function BreakdownRow({ label, value, share, color, valueFormatter, ...props }) {
15
- return (_jsxs(TableRow, { ...props, children: [_jsx(TableCell, { className: "font-medium", children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { "data-slot": "breakdown-table-dot", "aria-hidden": "true", className: "size-2 shrink-0 rounded-[2px]", style: { backgroundColor: color } }), label] }) }), _jsx(TableCell, { className: "text-right font-mono tabular-nums", children: valueFormatter(value) }), _jsx(TableCell, { children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { "data-slot": "breakdown-table-bar", "aria-hidden": "true", className: "h-1.5 flex-1 overflow-hidden rounded-[2px] bg-muted", children: _jsx("span", { className: "block h-full rounded-r-[2px]", style: {
15
+ return (_jsxs(TableRow, { ...props, children: [_jsx(TableCell, { className: "font-medium", children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { "data-slot": "breakdown-table-dot", "aria-hidden": "true", className: "size-2 shrink-0 rounded-xs", style: { backgroundColor: color } }), label] }) }), _jsx(TableCell, { className: "text-right font-mono tabular-nums", children: valueFormatter(value) }), _jsx(TableCell, { children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { "data-slot": "breakdown-table-bar", "aria-hidden": "true", className: "h-1.5 flex-1 overflow-hidden rounded-xs bg-muted", children: _jsx("span", { className: "block h-full rounded-r-xs", style: {
16
16
  width: `${Number(share.toFixed(3))}%`,
17
17
  backgroundColor: color,
18
18
  } }) }), _jsx("span", { className: "w-12 text-right font-mono text-xs text-muted-foreground tabular-nums", children: formatShare(share) })] }) })] }));
@@ -10,12 +10,23 @@ import * as React from "react";
10
10
  * cap tick, never clamped away. Severity state tokens reinforce position,
11
11
  * never act as the sole signal. The current value reads at the bar tip.
12
12
  *
13
+ * Two scales, one meter owner. The default `panel` scale is the full grammar
14
+ * above. The `row` scale is the exception slot of a membership row, where the
15
+ * meter appears only past the warning rung and is therefore a warning, not a
16
+ * gauge: one line carrying a percent and a thin bar, no ticks and no tip value
17
+ * line. It drops the ticks because a row has no room to encode position, so it
18
+ * encodes register instead; it keeps the overflow segment, because an over-run
19
+ * is never clamped away at either scale.
20
+ *
13
21
  * Accessibility: `role="meter"` with a REQUIRED accessible name (`label`);
14
22
  * `aria-valuenow` clamps to the meter maximum while `aria-valuetext` conveys
15
- * the true value including overflow.
23
+ * the true value including overflow. At the `row` scale the label is the only
24
+ * place the words live — the row prints no caption — so the caller passes a
25
+ * label that reads as a sentence, not a bare noun.
16
26
  */
17
27
  type BulletBarSeverity = "ok" | "warn" | "over";
18
- declare function BulletBar({ value, max, thresholdFraction, label, valueFormatter, valueText, className, ...props }: Omit<React.ComponentProps<"div">, "children"> & {
28
+ type BulletBarSize = "panel" | "row";
29
+ declare function BulletBar({ value, max, thresholdFraction, label, size, valueFormatter, valueText, className, ...props }: Omit<React.ComponentProps<"div">, "children"> & {
19
30
  value: number;
20
31
  /** The cap (included usage / limit) the meter measures against. */
21
32
  max: number;
@@ -27,6 +38,11 @@ declare function BulletBar({ value, max, thresholdFraction, label, valueFormatte
27
38
  thresholdFraction: number;
28
39
  /** REQUIRED accessible name for the meter. */
29
40
  label: string;
41
+ /**
42
+ * `panel` (default) is the full meter grammar. `row` is the single-line
43
+ * exception-slot scale: percent plus a thin bar, no ticks, no value line.
44
+ */
45
+ size?: BulletBarSize;
30
46
  valueFormatter?: (value: number) => string;
31
47
  /** Optional override for the generated `aria-valuetext`. */
32
48
  valueText?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"chart-bullet-bar.d.ts","sourceRoot":"","sources":["../../src/components/chart-bullet-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B;;;;;;;;;;;;;;GAcG;AAEH,KAAK,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAgBhD,iBAAS,SAAS,CAAC,EACjB,KAAK,EACL,GAAG,EACH,iBAAiB,EACjB,KAAK,EACL,cAA8B,EAC9B,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,qBAsFA;AAED,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"chart-bullet-bar.d.ts","sourceRoot":"","sources":["../../src/components/chart-bullet-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,KAAK,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAChD,KAAK,aAAa,GAAG,OAAO,GAAG,KAAK,CAAC;AAuCrC,iBAAS,SAAS,CAAC,EACjB,KAAK,EACL,GAAG,EACH,iBAAiB,EACjB,KAAK,EACL,IAAc,EACd,cAA8B,EAC9B,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,qBAgJA;AAED,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,9 +1,31 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
+ /**
4
+ * The tip value is TEXT, so it takes the feedback pair's deep tone, not the
5
+ * rail tone the segments wear: `--nc-state-review` / `--nc-state-blocked` are
6
+ * fill tones (0.85 amber reads at 1.6:1 on the light canvas), while
7
+ * `--nc-warning-deep` and `--nc-error-deep` are authored light AND dark so the
8
+ * percentage stays readable in both modes — and it is loudest exactly when it
9
+ * crosses a threshold.
10
+ */
3
11
  const BULLET_BAR_VALUE_TONE = {
4
12
  ok: "text-foreground",
5
- warn: "text-(--nc-state-review)",
6
- over: "text-(--nc-state-blocked)",
13
+ warn: "text-(--nc-warning-deep)",
14
+ over: "text-(--nc-error-deep)",
15
+ };
16
+ /**
17
+ * The consumed length carries the severity too, not only the tip figure: a
18
+ * meter at its cap and a meter at 40% drew the same calm ramp fill, so the one
19
+ * state where the reader is actually blocked was legible only from a 10px
20
+ * percentage. Position stays the primary signal (the threshold and cap ticks
21
+ * do not move); the tone reinforces it, per DESIGN.md's meter grammar. These
22
+ * are the rail tones of the feedback pairs, the same register the overflow
23
+ * segment already wears.
24
+ */
25
+ const BULLET_BAR_FILL_TONE = {
26
+ ok: "bg-(--nc-chart-seq-3)",
27
+ warn: "bg-(--nc-state-review)",
28
+ over: "bg-(--nc-state-blocked)",
7
29
  };
8
30
  function percent(fraction) {
9
31
  return `${Number((fraction * 100).toFixed(3))}%`;
@@ -11,7 +33,7 @@ function percent(fraction) {
11
33
  function defaultFormat(value) {
12
34
  return value.toLocaleString("en-US");
13
35
  }
14
- function BulletBar({ value, max, thresholdFraction, label, valueFormatter = defaultFormat, valueText, className, ...props }) {
36
+ function BulletBar({ value, max, thresholdFraction, label, size = "panel", valueFormatter = defaultFormat, valueText, className, ...props }) {
15
37
  const overflow = Math.max(value - max, 0);
16
38
  const total = Math.max(value, max);
17
39
  const fillFraction = total > 0 ? Math.min(value, max) / total : 0;
@@ -19,12 +41,43 @@ function BulletBar({ value, max, thresholdFraction, label, valueFormatter = defa
19
41
  const capFraction = total > 0 ? max / total : 1;
20
42
  const thresholdTickFraction = capFraction * thresholdFraction;
21
43
  const tipFraction = fillFraction + overflowFraction;
22
- const severity = overflow > 0 ? "over" : value >= thresholdFraction * max ? "warn" : "ok";
44
+ // Reaching the cap IS the blocked state, not merely the last warning step:
45
+ // an allowance consumed to exactly 100% stops the work the same way 104%
46
+ // does, so both read as `over`. A zero cap with no value stays `ok` — an
47
+ // unconfigured meter is not an exhausted one.
48
+ const severity = overflow > 0 || (max > 0 && value >= max)
49
+ ? "over"
50
+ : max > 0 && value >= thresholdFraction * max
51
+ ? "warn"
52
+ : "ok";
23
53
  const meterValueText = valueText ??
24
54
  `${valueFormatter(value)} of ${valueFormatter(max)}${overflow > 0 ? ` (${valueFormatter(overflow)} over the cap)` : ""}`;
25
- return (_jsxs("div", { "data-slot": "bullet-bar", "data-severity": severity, className: cn("flex flex-col gap-1", className), ...props, children: [_jsxs("div", { role: "meter", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": max, "aria-valuenow": Math.min(value, max), "aria-valuetext": meterValueText, className: "relative h-3 w-full", children: [_jsx("div", { "data-slot": "bullet-bar-track", className: "absolute inset-y-0 rounded-r-[4px] bg-(--nc-chart-seq-1)", style: { left: 0, width: percent(capFraction) } }), _jsx("div", { "data-slot": "bullet-bar-fill", className: cn("absolute inset-y-0 bg-(--nc-chart-seq-3)", overflow === 0 && "rounded-r-[4px]"), style: { left: 0, width: percent(fillFraction) } }), overflow > 0 ? (_jsx("div", { "data-slot": "bullet-bar-overflow", className: "absolute inset-y-0 rounded-r-[4px] bg-(--nc-state-blocked)", style: {
26
- left: percent(fillFraction),
27
- width: percent(overflowFraction),
28
- } })) : null, _jsx("div", { "data-slot": "bullet-bar-threshold-tick", "aria-hidden": "true", className: "absolute -inset-y-0.5 w-px bg-foreground", style: { left: percent(thresholdTickFraction) } }), _jsx("div", { "data-slot": "bullet-bar-cap-tick", "aria-hidden": "true", className: "absolute -inset-y-0.5 w-px bg-foreground", style: { left: percent(capFraction) } })] }), _jsx("div", { className: "relative h-4 w-full text-xs", "aria-hidden": "true", children: _jsx("span", { "data-slot": "bullet-bar-value", className: cn("absolute font-mono whitespace-nowrap tabular-nums", tipFraction > 0.6 && "-translate-x-full", BULLET_BAR_VALUE_TONE[severity]), style: { left: percent(tipFraction) }, children: valueFormatter(value) }) })] }));
55
+ // The row scale prints this instead of the tip value: at row scale the
56
+ // reader is asking "how close to the wall", not "how many".
57
+ const consumedPercent = max > 0 ? Math.round((value / max) * 100) : 0;
58
+ const segments = (_jsxs(_Fragment, { children: [_jsx("div", { "data-slot": "bullet-bar-track",
59
+ // One step darker than the surface it sits on, in both themes: at
60
+ // `bg-muted` an empty meter on the light canvas read as a hairline
61
+ // rather than as a track with nothing in it.
62
+ className: "absolute inset-y-0 rounded-r-sm bg-muted-foreground/20", style: { left: 0, width: percent(capFraction) } }), _jsx("div", { "data-slot": "bullet-bar-fill", className: cn("absolute inset-y-0", BULLET_BAR_FILL_TONE[severity], overflow === 0 && "rounded-r-sm"), style: { left: 0, width: percent(fillFraction) } }), overflow > 0 ? (_jsx("div", { "data-slot": "bullet-bar-overflow",
63
+ // A darker step of the same error family: now that the consumed
64
+ // length is itself red at the cap, the over-run has to stay a
65
+ // DISTINCT segment (DESIGN.md), which one shared tone would erase.
66
+ className: "absolute inset-y-0 rounded-r-sm bg-(--nc-error-deep)", style: {
67
+ left: percent(fillFraction),
68
+ width: percent(overflowFraction),
69
+ } })) : null] }));
70
+ const meterAria = {
71
+ role: "meter",
72
+ "aria-label": label,
73
+ "aria-valuemin": 0,
74
+ "aria-valuemax": max,
75
+ "aria-valuenow": Math.min(value, max),
76
+ "aria-valuetext": meterValueText,
77
+ };
78
+ if (size === "row") {
79
+ return (_jsxs("div", { "data-slot": "bullet-bar", "data-severity": severity, "data-size": "row", className: cn("flex items-center gap-2", className), ...props, children: [_jsxs("span", { "data-slot": "bullet-bar-percent", "aria-hidden": "true", className: cn("font-mono text-xs tabular-nums", BULLET_BAR_VALUE_TONE[severity]), children: [consumedPercent, "%"] }), _jsx("div", { ...meterAria, className: "relative h-1 min-w-0 flex-1", children: segments })] }));
80
+ }
81
+ return (_jsxs("div", { "data-slot": "bullet-bar", "data-severity": severity, "data-size": "panel", className: cn("flex flex-col gap-1", className), ...props, children: [_jsxs("div", { ...meterAria, className: "relative h-3 w-full", children: [segments, _jsx("div", { "data-slot": "bullet-bar-threshold-tick", "aria-hidden": "true", className: "absolute -inset-y-0.5 w-px bg-foreground", style: { left: percent(thresholdTickFraction) } }), _jsx("div", { "data-slot": "bullet-bar-cap-tick", "aria-hidden": "true", className: "absolute -inset-y-0.5 w-px bg-foreground", style: { left: percent(capFraction) } })] }), _jsx("div", { className: "relative h-4 w-full text-xs", "aria-hidden": "true", children: _jsx("span", { "data-slot": "bullet-bar-value", className: cn("absolute font-mono whitespace-nowrap tabular-nums", tipFraction > 0.6 && "-translate-x-full", BULLET_BAR_VALUE_TONE[severity]), style: { left: percent(tipFraction) }, children: valueFormatter(value) }) })] }));
29
82
  }
30
83
  export { BulletBar };
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { type DateRangePreset, type DateRangeValue } from "./chart-date-range";
3
- declare function DateRangeControl({ value, onChange, label, presets, presetLabels, customLabel, className, ...props }: Omit<React.ComponentProps<"div">, "children" | "onChange"> & {
3
+ declare function DateRangeControl({ value, onChange, label, presets, presetLabels, customLabel, formatCustomValue, className, ...props }: Omit<React.ComponentProps<"div">, "children" | "onChange"> & {
4
4
  value: DateRangeValue;
5
5
  onChange: (value: DateRangeValue) => void;
6
6
  /** Accessible name for the control group. */
@@ -12,6 +12,16 @@ declare function DateRangeControl({ value, onChange, label, presets, presetLabel
12
12
  presets?: readonly DateRangePreset[];
13
13
  presetLabels?: Partial<Record<DateRangePreset, string>>;
14
14
  customLabel?: string;
15
+ /**
16
+ * Renders the selected custom window as a finished, localized label. The
17
+ * package owns no locale, so without it the trigger falls back to the ISO
18
+ * pair the codec stores — a storage format, never a label a reader should
19
+ * meet. Every locale-aware consumer passes this.
20
+ */
21
+ formatCustomValue?: (value: {
22
+ from: string;
23
+ to: string;
24
+ }) => string;
15
25
  }): React.JSX.Element;
16
26
  export { DateRangeControl };
17
27
  //# sourceMappingURL=chart-date-range-control.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-date-range-control.d.ts","sourceRoot":"","sources":["../../src/components/chart-date-range-control.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AA0BvC,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,KAAoB,EACpB,OAA4B,EAC5B,YAAY,EACZ,WAAsB,EACtB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG;IAC9D,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,qBA2EA;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"chart-date-range-control.d.ts","sourceRoot":"","sources":["../../src/components/chart-date-range-control.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAmCvC,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,KAAoB,EACpB,OAA4B,EAC5B,YAAY,EACZ,WAAsB,EACtB,iBAAiB,EACjB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG;IAC9D,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CACrE,qBAoFA;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -23,13 +23,20 @@ import { DATE_RANGE_PRESETS, formatIsoDay, parseIsoDay, } from "./chart-date-ran
23
23
  * (`DATE_RANGE_PRESETS`) is unchanged, so a URL arriving with an un-offered but
24
24
  * valid preset token still decodes; the consumer decides its fallback.
25
25
  */
26
+ // Which range the chart is showing is a selection, and this row is the only
27
+ // thing that says it. A soft neutral fill sits about 1.1:1 against the page in
28
+ // both modes, which is a state no sighted reader can find, so the selected
29
+ // preset wears the navigation-selection role: the same colour the console
30
+ // marks a chosen destination with, and the only neutral-safe token that clears
31
+ // the 3:1 a state-bearing control owes.
32
+ const SELECTED_PRESET_CLASS = "bg-(--nc-navigation-selection-bg) text-(--nc-navigation-selection-fg) hover:bg-(--nc-navigation-selection-hover) hover:text-(--nc-navigation-selection-fg)";
26
33
  const DEFAULT_PRESET_LABELS = {
27
34
  "7d": "7d",
28
35
  "14d": "14d",
29
36
  "30d": "30d",
30
37
  cycle: "This cycle",
31
38
  };
32
- function DateRangeControl({ value, onChange, label = "Date range", presets = DATE_RANGE_PRESETS, presetLabels, customLabel = "Custom", className, ...props }) {
39
+ function DateRangeControl({ value, onChange, label = "Date range", presets = DATE_RANGE_PRESETS, presetLabels, customLabel = "Custom", formatCustomValue, className, ...props }) {
33
40
  const [open, setOpen] = React.useState(false);
34
41
  const [pending, setPending] = React.useState(undefined);
35
42
  const isCustom = value.kind === "custom";
@@ -56,7 +63,10 @@ function DateRangeControl({ value, onChange, label = "Date range", presets = DAT
56
63
  }
57
64
  return (_jsxs("div", { "data-slot": "date-range-control", role: "group", "aria-label": label, className: cn("flex flex-wrap items-center gap-1", className), ...props, children: [presets.map((preset) => {
58
65
  const active = value.kind === "preset" && value.preset === preset;
59
- return (_jsx(Button, { size: "sm", variant: active ? "secondary" : "ghost", "aria-pressed": active, onClick: () => onChange({ kind: "preset", preset }), children: presetLabels?.[preset] ?? DEFAULT_PRESET_LABELS[preset] }, preset));
60
- }), _jsxs(Popover, { open: open, onOpenChange: handleOpenChange, children: [_jsx(PopoverTrigger, { render: _jsxs(Button, { size: "sm", variant: isCustom ? "secondary" : "ghost", "aria-pressed": isCustom, children: [_jsx(CalendarIcon, { "data-icon": "inline-start" }), isCustom ? `${value.from} – ${value.to}` : customLabel] }) }), _jsx(PopoverContent, { align: "start", className: "w-auto p-0", children: _jsx(Calendar, { mode: "range", numberOfMonths: 2, defaultMonth: selected?.from, selected: selected, onSelect: handleSelect }) })] })] }));
66
+ return (_jsx(Button, { size: "sm", variant: "ghost", "aria-pressed": active, className: active ? SELECTED_PRESET_CLASS : undefined, onClick: () => onChange({ kind: "preset", preset }), children: presetLabels?.[preset] ?? DEFAULT_PRESET_LABELS[preset] }, preset));
67
+ }), _jsxs(Popover, { open: open, onOpenChange: handleOpenChange, children: [_jsx(PopoverTrigger, { render: _jsxs(Button, { size: "sm", variant: "ghost", "aria-pressed": isCustom, className: isCustom ? SELECTED_PRESET_CLASS : undefined, children: [_jsx(CalendarIcon, { "data-icon": "inline-start" }), isCustom
68
+ ? (formatCustomValue?.({ from: value.from, to: value.to }) ??
69
+ `${value.from} – ${value.to}`)
70
+ : customLabel] }) }), _jsx(PopoverContent, { align: "start", className: "w-auto p-0", children: _jsx(Calendar, { mode: "range", numberOfMonths: 2, defaultMonth: selected?.from, selected: selected, onSelect: handleSelect }) })] })] }));
61
71
  }
62
72
  export { DateRangeControl };
@@ -17,8 +17,14 @@ declare const CHART_ENTITY_COLOR_TOKENS: readonly ["var(--nc-chart-1)", "var(--n
17
17
  /**
18
18
  * The neutral register for folded "everything else" entities. A muted ink
19
19
  * token, never an extra categorical hue.
20
+ *
21
+ * `--nc-muted` and not the `--muted-foreground` role: the role resolves to the
22
+ * body-text tone, which in dark is near-white (L 0.83) — as a mark it becomes
23
+ * the loudest thing in the chart, so the tail outshouts every named entity.
24
+ * `--nc-muted` is authored as a mid grey in both modes (L 0.53 light / 0.65
25
+ * dark), which is what a folded tail should read as either way.
20
26
  */
21
- declare const CHART_ENTITY_OTHER_COLOR = "var(--muted-foreground)";
27
+ declare const CHART_ENTITY_OTHER_COLOR = "var(--nc-muted)";
22
28
  type EntityColorMap = Readonly<Record<string, string>>;
23
29
  /**
24
30
  * Assigns `var(--nc-chart-1..6)` in fixed order by FIRST APPEARANCE of each