@nadicodeai/ui 0.19.2 → 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.
- package/AGENTS.md +3 -1
- package/README.md +0 -2
- package/dist/components/brand-icons/apple.d.ts +18 -0
- package/dist/components/brand-icons/apple.d.ts.map +1 -0
- package/dist/components/brand-icons/apple.js +22 -0
- package/dist/components/brand-icons/brand-icon.d.ts +22 -0
- package/dist/components/brand-icons/brand-icon.d.ts.map +1 -0
- package/dist/components/brand-icons/brand-icon.js +26 -0
- package/dist/components/brand-icons/linux.d.ts +18 -0
- package/dist/components/brand-icons/linux.d.ts.map +1 -0
- package/dist/components/brand-icons/linux.js +25 -0
- package/dist/components/brand-icons/windows.d.ts +18 -0
- package/dist/components/brand-icons/windows.d.ts.map +1 -0
- package/dist/components/brand-icons/windows.js +22 -0
- package/dist/components/brand-icons.d.ts +5 -0
- package/dist/components/brand-icons.d.ts.map +1 -0
- package/dist/components/brand-icons.js +10 -0
- package/dist/components/button.js +1 -1
- package/dist/components/card-marketing.js +2 -2
- package/dist/components/card.d.ts +4 -3
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +12 -2
- package/dist/components/chart-breakdown-table.js +1 -1
- package/dist/components/chart-bullet-bar.d.ts +18 -2
- package/dist/components/chart-bullet-bar.d.ts.map +1 -1
- package/dist/components/chart-bullet-bar.js +62 -9
- package/dist/components/chart-date-range-control.d.ts +11 -1
- package/dist/components/chart-date-range-control.d.ts.map +1 -1
- package/dist/components/chart-date-range-control.js +13 -3
- package/dist/components/chart-entity-colors.d.ts +7 -1
- package/dist/components/chart-entity-colors.d.ts.map +1 -1
- package/dist/components/chart-entity-colors.js +7 -1
- package/dist/components/chart-kpi-stat.d.ts.map +1 -1
- package/dist/components/chart-kpi-stat.js +1 -1
- package/dist/components/chart-time-series.d.ts.map +1 -1
- package/dist/components/chart-time-series.js +62 -4
- package/dist/components/chart.js +2 -2
- package/dist/components/code-editor-mockup.js +1 -1
- package/dist/components/nav-bar.js +1 -1
- package/dist/components/radio-group.d.ts +1 -1
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +2 -2
- package/dist/components/theme-mode-switcher.d.ts +10 -3
- package/dist/components/theme-mode-switcher.d.ts.map +1 -1
- package/dist/components/theme-mode-switcher.js +14 -7
- package/dist/eslint/index.js +91 -0
- package/dist/eslint/rules/jsx-class-utility.js +231 -0
- package/dist/eslint/rules/no-deprecated-zod-api.js +156 -0
- package/dist/eslint/rules/no-design-system-src-import.js +11 -0
- package/dist/eslint/rules/no-invalid-token-utility.js +46 -0
- package/dist/eslint/rules/no-native-visible-control.js +86 -0
- package/dist/eslint/rules/no-raw-color-utility.js +109 -0
- package/dist/eslint/rules/no-raw-focus-ring-width.js +30 -0
- package/dist/eslint/rules/no-raw-logo-import.js +41 -0
- package/dist/eslint/rules/no-shadcn-appearance-override.js +191 -0
- package/dist/eslint/rules/no-token-category-bypass.js +53 -0
- package/dist/eslint/rules/no-ui-src-import.js +10 -0
- package/dist/eslint/rules/no-unpinned-vercel-functions-import.js +100 -0
- package/dist/eslint/rules/src-import-boundary.js +207 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/docs/agents/nadicodeai-ui.md +0 -2
- package/docs/consuming-cross-repo.md +31 -3
- package/docs/contract.md +11 -1
- package/llms.txt +0 -1
- package/package.json +9 -3
- package/skills/nadicodeai-ui/SKILL.md +1 -1
- package/docs/migration/nadia-consumer-readiness.md +0 -180
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 |
|
|
@@ -29,5 +31,5 @@ The `@nadicodeai/ui` npm workspace: the shared NadicodeAI React UI package on br
|
|
|
29
31
|
| Website page assembly | `../../website/AGENTS.md` |
|
|
30
32
|
| Portal screens | `../../portal/AGENTS.md` |
|
|
31
33
|
| User-visible UI work | `../../skills/nadicodeai-product-design/SKILL.md`, loaded after this rulebook |
|
|
32
|
-
|
|
|
34
|
+
| TUI semantics | `docs/terminal-tui-semantics.md` |
|
|
33
35
|
| Docs shipped to package consumers | `docs/contract.md` owns invariants, `docs/consuming-cross-repo.md` owns setup, and `llms.txt`, `docs/agents/nadicodeai-ui.md`, `docs/migration/`, and `skills/nadicodeai-ui/SKILL.md` map to those owners while documenting their own component or workflow surface |
|
package/README.md
CHANGED
|
@@ -177,8 +177,6 @@ The npm package includes agent-facing files on purpose. Agents should read:
|
|
|
177
177
|
- `docs/contract.md` for the package contract
|
|
178
178
|
- `llms.txt` for a concise import/setup index
|
|
179
179
|
- `docs/agents/nadicodeai-ui.md` for detailed usage and maintenance guidance
|
|
180
|
-
- `docs/migration/nadia-consumer-readiness.md` for consumer migration order
|
|
181
|
-
and readiness gates
|
|
182
180
|
- `skills/nadicodeai-ui/SKILL.md` when the agent runtime supports skills
|
|
183
181
|
|
|
184
182
|
These files are packaged through npm `files`; they are not runtime module
|
|
@@ -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]:
|
|
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-
|
|
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-
|
|
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
|
-
|
|
3
|
-
|
|
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.
|
|
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;
|
|
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"}
|
package/dist/components/card.js
CHANGED
|
@@ -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 (
|
|
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-
|
|
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
|
-
|
|
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
|
|
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-
|
|
6
|
-
over: "text-(--nc-
|
|
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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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;
|
|
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:
|
|
60
|
-
}), _jsxs(Popover, { open: open, onOpenChange: handleOpenChange, children: [_jsx(PopoverTrigger, { render: _jsxs(Button, { size: "sm", variant:
|
|
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 };
|