@zedtech/zedkit-ui 0.1.0 → 0.2.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/README.md +35 -9
- package/dist/alert.d.ts +9 -0
- package/dist/alert.d.ts.map +1 -0
- package/dist/alert.js +27 -0
- package/dist/alert.js.map +1 -0
- package/dist/app-shell.d.ts +9 -0
- package/dist/app-shell.d.ts.map +1 -0
- package/dist/app-shell.js +6 -0
- package/dist/app-shell.js.map +1 -0
- package/dist/badge.d.ts +10 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +19 -0
- package/dist/badge.js.map +1 -0
- package/dist/button.d.ts +12 -0
- package/dist/button.d.ts.map +1 -0
- package/dist/button.js +32 -0
- package/dist/button.js.map +1 -0
- package/dist/card.d.ts +9 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +18 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.d.ts +5 -0
- package/dist/checkbox.d.ts.map +1 -0
- package/dist/checkbox.js +11 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/checkmark.d.ts +11 -0
- package/dist/checkmark.d.ts.map +1 -0
- package/dist/checkmark.js +12 -0
- package/dist/checkmark.js.map +1 -0
- package/dist/confirm-dialog.d.ts +17 -0
- package/dist/confirm-dialog.d.ts.map +1 -0
- package/dist/confirm-dialog.js +18 -0
- package/dist/confirm-dialog.js.map +1 -0
- package/dist/data-table.d.ts +33 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +40 -0
- package/dist/data-table.js.map +1 -0
- package/dist/detail-panel.d.ts +11 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +6 -0
- package/dist/detail-panel.js.map +1 -0
- package/dist/dialog.d.ts +14 -0
- package/dist/dialog.d.ts.map +1 -0
- package/dist/dialog.js +27 -0
- package/dist/dialog.js.map +1 -0
- package/dist/drawer.d.ts +30 -0
- package/dist/drawer.d.ts.map +1 -0
- package/dist/drawer.js +35 -0
- package/dist/drawer.js.map +1 -0
- package/dist/field.d.ts +26 -0
- package/dist/field.d.ts.map +1 -0
- package/dist/field.js +75 -0
- package/dist/field.js.map +1 -0
- package/dist/form-submit.d.ts +16 -0
- package/dist/form-submit.d.ts.map +1 -0
- package/dist/form-submit.js +15 -0
- package/dist/form-submit.js.map +1 -0
- package/dist/form.d.ts +26 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +66 -0
- package/dist/form.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +4 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +10 -0
- package/dist/input.js.map +1 -0
- package/dist/label.d.ts +6 -0
- package/dist/label.d.ts.map +1 -0
- package/dist/label.js +12 -0
- package/dist/label.js.map +1 -0
- package/dist/layout.d.ts +22 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +36 -0
- package/dist/layout.js.map +1 -0
- package/dist/live-pulse.d.ts +7 -0
- package/dist/live-pulse.d.ts.map +1 -0
- package/dist/live-pulse.js +7 -0
- package/dist/live-pulse.js.map +1 -0
- package/dist/option-cards.d.ts +15 -0
- package/dist/option-cards.d.ts.map +1 -0
- package/dist/option-cards.js +9 -0
- package/dist/option-cards.js.map +1 -0
- package/dist/page-header.d.ts +9 -0
- package/dist/page-header.d.ts.map +1 -0
- package/dist/page-header.js +6 -0
- package/dist/page-header.js.map +1 -0
- package/dist/progress-bar.d.ts +16 -0
- package/dist/progress-bar.d.ts.map +1 -0
- package/dist/progress-bar.js +16 -0
- package/dist/progress-bar.js.map +1 -0
- package/dist/secret-field.d.ts +22 -0
- package/dist/secret-field.d.ts.map +1 -0
- package/dist/secret-field.js +26 -0
- package/dist/secret-field.js.map +1 -0
- package/dist/select.d.ts +14 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +31 -0
- package/dist/select.js.map +1 -0
- package/dist/separator.d.ts +5 -0
- package/dist/separator.d.ts.map +1 -0
- package/dist/separator.js +10 -0
- package/dist/separator.js.map +1 -0
- package/dist/skeleton.d.ts +3 -0
- package/dist/skeleton.d.ts.map +1 -0
- package/dist/skeleton.js +8 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/sonner.d.ts +8 -0
- package/dist/sonner.d.ts.map +1 -0
- package/dist/sonner.js +20 -0
- package/dist/sonner.js.map +1 -0
- package/dist/status-dot.d.ts +13 -0
- package/dist/status-dot.d.ts.map +1 -0
- package/dist/status-dot.js +20 -0
- package/dist/status-dot.js.map +1 -0
- package/dist/switch.d.ts +5 -0
- package/dist/switch.d.ts.map +1 -0
- package/dist/switch.js +10 -0
- package/dist/switch.js.map +1 -0
- package/dist/table.d.ts +11 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +28 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.d.ts +8 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +15 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.d.ts +4 -0
- package/dist/textarea.d.ts.map +1 -0
- package/dist/textarea.js +10 -0
- package/dist/textarea.js.map +1 -0
- package/dist/typography.d.ts +22 -0
- package/dist/typography.d.ts.map +1 -0
- package/dist/typography.js +39 -0
- package/dist/typography.js.map +1 -0
- package/dist/use-validated-form.d.ts +10 -0
- package/dist/use-validated-form.d.ts.map +1 -0
- package/dist/use-validated-form.js +20 -0
- package/dist/use-validated-form.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +12 -0
- package/dist/utils.js.map +1 -0
- package/dist/wizard-steps.d.ts +8 -0
- package/dist/wizard-steps.d.ts.map +1 -0
- package/dist/wizard-steps.js +7 -0
- package/dist/wizard-steps.js.map +1 -0
- package/package.json +23 -3
- package/src/alert.tsx +1 -0
- package/src/badge.tsx +1 -0
- package/src/button.tsx +1 -0
- package/src/card.tsx +1 -0
- package/src/checkbox.tsx +1 -0
- package/src/checkmark.tsx +34 -0
- package/src/dialog.tsx +1 -0
- package/src/drawer.tsx +140 -0
- package/src/field.tsx +1 -0
- package/src/form.tsx +1 -0
- package/src/index.ts +16 -0
- package/src/input.tsx +1 -0
- package/src/label.tsx +1 -0
- package/src/live-pulse.tsx +2 -8
- package/src/progress-bar.tsx +45 -0
- package/src/select.tsx +1 -0
- package/src/separator.tsx +1 -0
- package/src/skeleton.tsx +1 -0
- package/src/sonner.tsx +1 -0
- package/src/status-dot.tsx +42 -0
- package/src/styles.css +15 -0
- package/src/switch.tsx +1 -0
- package/src/table.tsx +1 -0
- package/src/tabs.tsx +1 -0
- package/src/textarea.tsx +1 -0
- package/src/utils.ts +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2
|
+
import { type FieldValues, type UseFormProps, type UseFormReturn } from "react-hook-form";
|
|
3
|
+
/**
|
|
4
|
+
* Validated form in one call: the zod schema is the single source of
|
|
5
|
+
* truth (in a real app it lives in the shared contracts package next
|
|
6
|
+
* to the API validators) and the resolver wiring stays inside the
|
|
7
|
+
* kit, so consumers never import the resolver library directly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useValidatedForm<TFieldValues extends FieldValues>(schema: Parameters<typeof zodResolver>[0], options?: Omit<UseFormProps<TFieldValues, any>, "resolver">): UseFormReturn<TFieldValues, any, TFieldValues>;
|
|
10
|
+
//# sourceMappingURL=use-validated-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-validated-form.d.ts","sourceRoot":"","sources":["../src/use-validated-form.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,SAAS,WAAW,EAC/D,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAEzC,OAAO,GAAE,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,UAAU,CAAM,GAE9D,aAAa,CAAC,YAAY,EAAE,GAAG,EAAE,YAAY,CAAC,CAOhD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
3
|
+
import { useForm, } from "react-hook-form";
|
|
4
|
+
/**
|
|
5
|
+
* Validated form in one call: the zod schema is the single source of
|
|
6
|
+
* truth (in a real app it lives in the shared contracts package next
|
|
7
|
+
* to the API validators) and the resolver wiring stays inside the
|
|
8
|
+
* kit, so consumers never import the resolver library directly.
|
|
9
|
+
*/
|
|
10
|
+
export function useValidatedForm(schema,
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors useForm's own context type (any)
|
|
12
|
+
options = {}) {
|
|
13
|
+
// The resolver is exact for this schema, but react-hook-form's
|
|
14
|
+
// Resolver is invariant in its options type, so a schema-typed
|
|
15
|
+
// resolver cannot flow through the generic untouched (same
|
|
16
|
+
// upstream-invariance situation as the data-table columns).
|
|
17
|
+
const resolver = zodResolver(schema);
|
|
18
|
+
return useForm({ ...options, resolver });
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=use-validated-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-validated-form.js","sourceRoot":"","sources":["../src/use-validated-form.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EACL,OAAO,GAKR,MAAM,iBAAiB,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAyC;AACzC,0GAA0G;AAC1G,UAA6D,EAAE;IAG/D,+DAA+D;IAC/D,+DAA+D;IAC/D,2DAA2D;IAC3D,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAA2B,CAAC;IAC/D,OAAO,OAAO,CAAe,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ClassValue } from "clsx";
|
|
2
|
+
/**
|
|
3
|
+
* Merges class names, with tailwind-merge resolving conflicting
|
|
4
|
+
* Tailwind utilities (last one wins). Every component takes an
|
|
5
|
+
* optional className that flows through here.
|
|
6
|
+
*/
|
|
7
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAElD"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Derived from shadcn/ui (utils (cn)) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
/**
|
|
5
|
+
* Merges class names, with tailwind-merge resolving conflicting
|
|
6
|
+
* Tailwind utilities (last one wins). Every component takes an
|
|
7
|
+
* optional className that flows through here.
|
|
8
|
+
*/
|
|
9
|
+
export function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,gKAAgK;AAChK,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,EAAE,CAAC,GAAG,MAAoB;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface WizardStepsProps {
|
|
2
|
+
steps: string[];
|
|
3
|
+
/** 0-based index of the current step. */
|
|
4
|
+
current: number;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function WizardSteps({ steps, current, className }: WizardStepsProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=wizard-steps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard-steps.d.ts","sourceRoot":"","sources":["../src/wizard-steps.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,+BA4B1E"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CheckIcon } from "lucide-react";
|
|
3
|
+
import { cn } from "./utils.js";
|
|
4
|
+
export function WizardSteps({ steps, current, className }) {
|
|
5
|
+
return (_jsx("ol", { className: cn("flex flex-wrap items-center gap-x-3 gap-y-2", className), "aria-label": "Progress", children: steps.map((step, index) => (_jsxs("li", { "aria-current": index === current ? "step" : undefined, className: "flex items-center gap-2 text-sm", children: [_jsx("span", { "aria-hidden": true, className: cn("flex size-6 items-center justify-center rounded-full border text-xs font-medium", index < current && "border-primary bg-primary text-primary-foreground", index === current && "border-primary text-primary", index > current && "text-muted-foreground"), children: index < current ? _jsx(CheckIcon, { className: "size-3.5" }) : index + 1 }), _jsx("span", { className: cn(index === current ? "font-medium" : "text-muted-foreground"), children: step }), index < steps.length - 1 ? (_jsx("span", { "aria-hidden": true, className: "ml-1 h-px w-6 bg-border" })) : null] }, step))) }));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=wizard-steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard-steps.js","sourceRoot":"","sources":["../src/wizard-steps.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAShC,MAAM,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAoB;IACzE,OAAO,CACL,aAAI,SAAS,EAAE,EAAE,CAAC,6CAA6C,EAAE,SAAS,CAAC,gBAAa,UAAU,YAC/F,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,8BAEgB,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAC,iCAAiC,aAE3C,oCAEE,SAAS,EAAE,EAAE,CACX,iFAAiF,EACjF,KAAK,GAAG,OAAO,IAAI,mDAAmD,EACtE,KAAK,KAAK,OAAO,IAAI,6BAA6B,EAClD,KAAK,GAAG,OAAO,IAAI,uBAAuB,CAC3C,YAEA,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,KAAC,SAAS,IAAC,SAAS,EAAC,UAAU,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAC5D,EACP,eAAM,SAAS,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,uBAAuB,CAAC,YAAG,IAAI,GAAQ,EAC9F,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC1B,oCAAkB,SAAS,EAAC,yBAAyB,GAAG,CACzD,CAAC,CAAC,CAAC,IAAI,KAlBH,IAAI,CAmBN,CACN,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zedtech/zedkit-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
7
7
|
},
|
|
8
|
-
"description": "
|
|
8
|
+
"description": "Ship a calm admin UI fast: dark/light design tokens plus accessible building blocks (data tables, forms, dialogs, toasts).",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"react",
|
|
11
|
+
"react-components",
|
|
12
|
+
"ui-kit",
|
|
13
|
+
"design-system",
|
|
14
|
+
"admin",
|
|
15
|
+
"dashboard",
|
|
16
|
+
"tailwindcss",
|
|
17
|
+
"tailwind-v4",
|
|
18
|
+
"radix-ui",
|
|
19
|
+
"shadcn",
|
|
20
|
+
"dark-mode",
|
|
21
|
+
"accessible",
|
|
22
|
+
"nextjs"
|
|
23
|
+
],
|
|
24
|
+
"homepage": "https://github.com/zedtech-fr/zedkit/tree/main/packages/ui",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/zedtech-fr/zedkit/issues"
|
|
27
|
+
},
|
|
9
28
|
"license": "MIT",
|
|
10
29
|
"repository": {
|
|
11
30
|
"type": "git",
|
|
@@ -58,6 +77,7 @@
|
|
|
58
77
|
"react-hook-form": "7.91.0",
|
|
59
78
|
"sonner": "2.0.8",
|
|
60
79
|
"tailwind-merge": "3.7.0",
|
|
80
|
+
"vaul": "1.1.2",
|
|
61
81
|
"zod": "4.6.7"
|
|
62
82
|
},
|
|
63
83
|
"devDependencies": {
|
|
@@ -72,7 +92,7 @@
|
|
|
72
92
|
"typescript": "5.9.3",
|
|
73
93
|
"vitest": "2.1.9",
|
|
74
94
|
"vitest-axe": "0.1.0",
|
|
75
|
-
"@zedtech/zedkit-core": "0.
|
|
95
|
+
"@zedtech/zedkit-core": "0.1.1"
|
|
76
96
|
},
|
|
77
97
|
"scripts": {
|
|
78
98
|
"build": "tsc -p tsconfig.json",
|
package/src/alert.tsx
CHANGED
package/src/badge.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Derived from shadcn/ui (badge) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
4
|
import { cn } from "./utils.js";
|
package/src/button.tsx
CHANGED
package/src/card.tsx
CHANGED
package/src/checkbox.tsx
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { cn } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
export interface CheckmarkProps {
|
|
4
|
+
/** Accessible name; omitted means decorative (pair with visible text). */
|
|
5
|
+
label?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Success check that draws itself once (static full check under
|
|
11
|
+
* reduced motion — see `zk-check-draw` in styles.css).
|
|
12
|
+
*/
|
|
13
|
+
export function Checkmark({ label, className }: CheckmarkProps) {
|
|
14
|
+
return (
|
|
15
|
+
<svg
|
|
16
|
+
viewBox="0 0 16 16"
|
|
17
|
+
fill="none"
|
|
18
|
+
{...(label === undefined
|
|
19
|
+
? { "aria-hidden": true as const }
|
|
20
|
+
: { role: "img" as const, "aria-label": label })}
|
|
21
|
+
className={cn("size-4 text-success", className)}
|
|
22
|
+
>
|
|
23
|
+
<circle cx="8" cy="8" r="7" stroke="currentColor" strokeWidth="1.5" />
|
|
24
|
+
<path
|
|
25
|
+
d="M5.5 8.2 7.2 9.9 10.6 6.3"
|
|
26
|
+
stroke="currentColor"
|
|
27
|
+
strokeWidth="1.8"
|
|
28
|
+
strokeLinecap="round"
|
|
29
|
+
strokeLinejoin="round"
|
|
30
|
+
className="[stroke-dasharray:8] motion-safe:animate-[zk-check-draw_0.45s_ease-out_forwards]"
|
|
31
|
+
/>
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
}
|
package/src/dialog.tsx
CHANGED
package/src/drawer.tsx
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Derived from shadcn/ui (drawer) — see Provenance in packages/ui/README.md. Adapted: direction-aware
|
|
2
|
+
// positioning via data variants (vaul sets data-vaul-drawer-direction on the content), drag handle and
|
|
3
|
+
// close left to the consumer to compose, ref-as-prop (React 19). Vaul injects its own base CSS
|
|
4
|
+
// (drag transitions, open/close keyframes) at import; the kit adds no drawer CSS.
|
|
5
|
+
"use client";
|
|
6
|
+
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { Drawer as DrawerPrimitive } from "vaul";
|
|
9
|
+
import { cn } from "./utils.js";
|
|
10
|
+
|
|
11
|
+
const Drawer = DrawerPrimitive.Root;
|
|
12
|
+
const DrawerTrigger = DrawerPrimitive.Trigger;
|
|
13
|
+
const DrawerClose = DrawerPrimitive.Close;
|
|
14
|
+
const DrawerPortal = DrawerPrimitive.Portal;
|
|
15
|
+
|
|
16
|
+
function DrawerOverlay({
|
|
17
|
+
className,
|
|
18
|
+
ref,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay> & {
|
|
21
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
22
|
+
}) {
|
|
23
|
+
return (
|
|
24
|
+
<DrawerPrimitive.Overlay
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("fixed inset-0 z-50 bg-overlay/80", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function DrawerContent({
|
|
33
|
+
className,
|
|
34
|
+
children,
|
|
35
|
+
ref,
|
|
36
|
+
modal = true,
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content> & {
|
|
39
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
40
|
+
/**
|
|
41
|
+
* Mirror of the `Drawer` root `modal` prop: `false` renders no
|
|
42
|
+
* overlay so the background stays interactive. Defaults to `true`.
|
|
43
|
+
*/
|
|
44
|
+
modal?: boolean;
|
|
45
|
+
}) {
|
|
46
|
+
return (
|
|
47
|
+
<DrawerPortal>
|
|
48
|
+
{modal ? <DrawerOverlay /> : null}
|
|
49
|
+
<DrawerPrimitive.Content
|
|
50
|
+
ref={ref}
|
|
51
|
+
className={cn(
|
|
52
|
+
"fixed z-50 flex flex-col border bg-background",
|
|
53
|
+
"data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:max-h-[96dvh] data-[vaul-drawer-direction=bottom]:rounded-t-xl",
|
|
54
|
+
"data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:max-h-[96dvh] data-[vaul-drawer-direction=top]:rounded-b-xl",
|
|
55
|
+
"data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-full data-[vaul-drawer-direction=right]:sm:max-w-md",
|
|
56
|
+
"data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-full data-[vaul-drawer-direction=left]:sm:max-w-md",
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
{children}
|
|
62
|
+
</DrawerPrimitive.Content>
|
|
63
|
+
</DrawerPortal>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function DrawerHandle({
|
|
68
|
+
className,
|
|
69
|
+
ref,
|
|
70
|
+
...props
|
|
71
|
+
}: React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Handle> & {
|
|
72
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
73
|
+
}) {
|
|
74
|
+
return (
|
|
75
|
+
<DrawerPrimitive.Handle
|
|
76
|
+
ref={ref}
|
|
77
|
+
className={cn("mx-auto mt-4 h-1.5 w-12 shrink-0 rounded-full bg-muted", className)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function DrawerHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
className={cn("flex flex-col gap-1.5 p-4 text-center sm:text-left", className)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function DrawerFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
93
|
+
return <div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function DrawerTitle({
|
|
97
|
+
className,
|
|
98
|
+
ref,
|
|
99
|
+
...props
|
|
100
|
+
}: React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title> & {
|
|
101
|
+
ref?: React.Ref<HTMLHeadingElement>;
|
|
102
|
+
}) {
|
|
103
|
+
return (
|
|
104
|
+
<DrawerPrimitive.Title
|
|
105
|
+
ref={ref}
|
|
106
|
+
className={cn("text-lg leading-none font-semibold tracking-tight", className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function DrawerDescription({
|
|
113
|
+
className,
|
|
114
|
+
ref,
|
|
115
|
+
...props
|
|
116
|
+
}: React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description> & {
|
|
117
|
+
ref?: React.Ref<HTMLParagraphElement>;
|
|
118
|
+
}) {
|
|
119
|
+
return (
|
|
120
|
+
<DrawerPrimitive.Description
|
|
121
|
+
ref={ref}
|
|
122
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
Drawer,
|
|
130
|
+
DrawerClose,
|
|
131
|
+
DrawerContent,
|
|
132
|
+
DrawerDescription,
|
|
133
|
+
DrawerFooter,
|
|
134
|
+
DrawerHandle,
|
|
135
|
+
DrawerHeader,
|
|
136
|
+
DrawerOverlay,
|
|
137
|
+
DrawerPortal,
|
|
138
|
+
DrawerTitle,
|
|
139
|
+
DrawerTrigger,
|
|
140
|
+
};
|
package/src/field.tsx
CHANGED
package/src/form.tsx
CHANGED
package/src/index.ts
CHANGED
|
@@ -24,6 +24,19 @@ export {
|
|
|
24
24
|
DialogTrigger,
|
|
25
25
|
} from "./dialog.js";
|
|
26
26
|
export { DetailPanel, type DetailItem, type DetailPanelProps } from "./detail-panel.js";
|
|
27
|
+
export {
|
|
28
|
+
Drawer,
|
|
29
|
+
DrawerClose,
|
|
30
|
+
DrawerContent,
|
|
31
|
+
DrawerDescription,
|
|
32
|
+
DrawerFooter,
|
|
33
|
+
DrawerHandle,
|
|
34
|
+
DrawerHeader,
|
|
35
|
+
DrawerOverlay,
|
|
36
|
+
DrawerPortal,
|
|
37
|
+
DrawerTitle,
|
|
38
|
+
DrawerTrigger,
|
|
39
|
+
} from "./drawer.js";
|
|
27
40
|
export {
|
|
28
41
|
Field,
|
|
29
42
|
FieldContent,
|
|
@@ -52,6 +65,9 @@ export { Input } from "./input.js";
|
|
|
52
65
|
export { Label } from "./label.js";
|
|
53
66
|
export { Section, Stack, stackVariants, type SectionProps, type StackProps } from "./layout.js";
|
|
54
67
|
export { LivePulse, type LivePulseProps } from "./live-pulse.js";
|
|
68
|
+
export { StatusDot, type StatusDotProps, type StatusDotTone } from "./status-dot.js";
|
|
69
|
+
export { ProgressBar, type ProgressBarProps } from "./progress-bar.js";
|
|
70
|
+
export { Checkmark, type CheckmarkProps } from "./checkmark.js";
|
|
55
71
|
export { OptionCards, type OptionCard, type OptionCardsProps } from "./option-cards.js";
|
|
56
72
|
export { PageHeader, type PageHeaderProps } from "./page-header.js";
|
|
57
73
|
export { SecretField, type SecretFieldProps } from "./secret-field.js";
|
package/src/input.tsx
CHANGED
package/src/label.tsx
CHANGED
package/src/live-pulse.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StatusDot } from "./status-dot.js";
|
|
1
2
|
import { cn } from "./utils.js";
|
|
2
3
|
|
|
3
4
|
export interface LivePulseProps {
|
|
@@ -13,14 +14,7 @@ export function LivePulse({ active = true, label = "Live", className }: LivePuls
|
|
|
13
14
|
aria-label={active ? label : "Idle"}
|
|
14
15
|
className={cn("inline-flex items-center gap-1.5 text-xs text-muted-foreground", className)}
|
|
15
16
|
>
|
|
16
|
-
<
|
|
17
|
-
{active ? (
|
|
18
|
-
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-success opacity-60" />
|
|
19
|
-
) : null}
|
|
20
|
-
<span
|
|
21
|
-
className={cn("relative inline-flex size-2 rounded-full", active ? "bg-success" : "bg-muted-foreground/40")}
|
|
22
|
-
/>
|
|
23
|
-
</span>
|
|
17
|
+
<StatusDot tone={active ? "success" : "idle"} pulse={active} />
|
|
24
18
|
{active ? label : "Idle"}
|
|
25
19
|
</span>
|
|
26
20
|
);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cn } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
export interface ProgressBarProps {
|
|
4
|
+
/** Current value, clamped to 0..max (`NaN` reads as empty). */
|
|
5
|
+
value: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
/** Accessible name (kept screen-only — pair with visible text). */
|
|
8
|
+
label: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const SEGMENTS = 10;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Determinate progress as filled segments (exact value stays in
|
|
16
|
+
* `aria-valuenow`). No animation, so nothing to disable for reduced
|
|
17
|
+
* motion. Announce the operation with visible text (e.g. StatusLabel)
|
|
18
|
+
* next to it — the label here stays screen-only.
|
|
19
|
+
*/
|
|
20
|
+
export function ProgressBar({ value, max = 100, label, className }: ProgressBarProps) {
|
|
21
|
+
const safeMax = Number.isFinite(max) && max > 0 ? max : 100;
|
|
22
|
+
const safeValue = Number.isFinite(value) ? Math.min(Math.max(value, 0), safeMax) : 0;
|
|
23
|
+
const filled = Math.round((safeValue / safeMax) * SEGMENTS);
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
role="progressbar"
|
|
27
|
+
aria-label={label}
|
|
28
|
+
aria-valuemin={0}
|
|
29
|
+
aria-valuemax={safeMax}
|
|
30
|
+
aria-valuenow={Math.round(safeValue)}
|
|
31
|
+
className={cn("flex w-full gap-0.5", className)}
|
|
32
|
+
>
|
|
33
|
+
{Array.from({ length: SEGMENTS }, (_, index) => (
|
|
34
|
+
<span
|
|
35
|
+
key={index}
|
|
36
|
+
aria-hidden
|
|
37
|
+
className={cn(
|
|
38
|
+
"h-1.5 flex-1 rounded-full motion-safe:transition-colors",
|
|
39
|
+
index < filled ? "bg-primary" : "bg-muted",
|
|
40
|
+
)}
|
|
41
|
+
/>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
package/src/select.tsx
CHANGED
package/src/separator.tsx
CHANGED
package/src/skeleton.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Derived from shadcn/ui (skeleton) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
|
|
1
2
|
import { cn } from "./utils.js";
|
|
2
3
|
|
|
3
4
|
function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
package/src/sonner.tsx
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cn } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
export type StatusDotTone = "active" | "idle" | "success" | "warning" | "danger";
|
|
4
|
+
|
|
5
|
+
export interface StatusDotProps {
|
|
6
|
+
tone?: StatusDotTone;
|
|
7
|
+
/** Override the default ping (ongoing tones ping, others stay static). */
|
|
8
|
+
pulse?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const TONE_COLOR: Record<StatusDotTone, string> = {
|
|
13
|
+
active: "bg-primary",
|
|
14
|
+
idle: "bg-muted-foreground/40",
|
|
15
|
+
success: "bg-success",
|
|
16
|
+
warning: "bg-warning",
|
|
17
|
+
danger: "bg-destructive",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const PING_TONES: ReadonlySet<StatusDotTone> = new Set(["active", "warning", "danger"]);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Decorative status dot: pings for ongoing tones (motion-safe), static
|
|
24
|
+
* otherwise. Pair with visible text (e.g. StatusLabel) — never alone.
|
|
25
|
+
*/
|
|
26
|
+
export function StatusDot({ tone = "active", pulse, className }: StatusDotProps) {
|
|
27
|
+
const color = TONE_COLOR[tone];
|
|
28
|
+
const ping = pulse ?? PING_TONES.has(tone);
|
|
29
|
+
return (
|
|
30
|
+
<span aria-hidden className={cn("relative flex size-2", className)}>
|
|
31
|
+
{ping ? (
|
|
32
|
+
<span
|
|
33
|
+
className={cn(
|
|
34
|
+
"absolute inline-flex h-full w-full rounded-full opacity-60 motion-safe:animate-ping",
|
|
35
|
+
color,
|
|
36
|
+
)}
|
|
37
|
+
/>
|
|
38
|
+
) : null}
|
|
39
|
+
<span className={cn("relative inline-flex size-2 rounded-full", color)} />
|
|
40
|
+
</span>
|
|
41
|
+
);
|
|
42
|
+
}
|
package/src/styles.css
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* Derived from shadcn/ui (theme) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it. */
|
|
1
2
|
@import "tailwindcss";
|
|
2
3
|
|
|
3
4
|
/*
|
|
@@ -115,3 +116,17 @@
|
|
|
115
116
|
ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
116
117
|
}
|
|
117
118
|
}
|
|
119
|
+
|
|
120
|
+
/*
|
|
121
|
+
* Kit-authored motion (not shadcn): one draw-on keyframe for the
|
|
122
|
+
* Checkmark state icon. The path carries the animation only under
|
|
123
|
+
* `motion-safe:`, so reduced motion shows the static full check.
|
|
124
|
+
*/
|
|
125
|
+
@keyframes zk-check-draw {
|
|
126
|
+
from {
|
|
127
|
+
stroke-dashoffset: 8;
|
|
128
|
+
}
|
|
129
|
+
to {
|
|
130
|
+
stroke-dashoffset: 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
package/src/switch.tsx
CHANGED
package/src/table.tsx
CHANGED
package/src/tabs.tsx
CHANGED
package/src/textarea.tsx
CHANGED
package/src/utils.ts
CHANGED