@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.
Files changed (176) hide show
  1. package/README.md +35 -9
  2. package/dist/alert.d.ts +9 -0
  3. package/dist/alert.d.ts.map +1 -0
  4. package/dist/alert.js +27 -0
  5. package/dist/alert.js.map +1 -0
  6. package/dist/app-shell.d.ts +9 -0
  7. package/dist/app-shell.d.ts.map +1 -0
  8. package/dist/app-shell.js +6 -0
  9. package/dist/app-shell.js.map +1 -0
  10. package/dist/badge.d.ts +10 -0
  11. package/dist/badge.d.ts.map +1 -0
  12. package/dist/badge.js +19 -0
  13. package/dist/badge.js.map +1 -0
  14. package/dist/button.d.ts +12 -0
  15. package/dist/button.d.ts.map +1 -0
  16. package/dist/button.js +32 -0
  17. package/dist/button.js.map +1 -0
  18. package/dist/card.d.ts +9 -0
  19. package/dist/card.d.ts.map +1 -0
  20. package/dist/card.js +18 -0
  21. package/dist/card.js.map +1 -0
  22. package/dist/checkbox.d.ts +5 -0
  23. package/dist/checkbox.d.ts.map +1 -0
  24. package/dist/checkbox.js +11 -0
  25. package/dist/checkbox.js.map +1 -0
  26. package/dist/checkmark.d.ts +11 -0
  27. package/dist/checkmark.d.ts.map +1 -0
  28. package/dist/checkmark.js +12 -0
  29. package/dist/checkmark.js.map +1 -0
  30. package/dist/confirm-dialog.d.ts +17 -0
  31. package/dist/confirm-dialog.d.ts.map +1 -0
  32. package/dist/confirm-dialog.js +18 -0
  33. package/dist/confirm-dialog.js.map +1 -0
  34. package/dist/data-table.d.ts +33 -0
  35. package/dist/data-table.d.ts.map +1 -0
  36. package/dist/data-table.js +40 -0
  37. package/dist/data-table.js.map +1 -0
  38. package/dist/detail-panel.d.ts +11 -0
  39. package/dist/detail-panel.d.ts.map +1 -0
  40. package/dist/detail-panel.js +6 -0
  41. package/dist/detail-panel.js.map +1 -0
  42. package/dist/dialog.d.ts +14 -0
  43. package/dist/dialog.d.ts.map +1 -0
  44. package/dist/dialog.js +27 -0
  45. package/dist/dialog.js.map +1 -0
  46. package/dist/drawer.d.ts +30 -0
  47. package/dist/drawer.d.ts.map +1 -0
  48. package/dist/drawer.js +35 -0
  49. package/dist/drawer.js.map +1 -0
  50. package/dist/field.d.ts +26 -0
  51. package/dist/field.d.ts.map +1 -0
  52. package/dist/field.js +75 -0
  53. package/dist/field.js.map +1 -0
  54. package/dist/form-submit.d.ts +16 -0
  55. package/dist/form-submit.d.ts.map +1 -0
  56. package/dist/form-submit.js +15 -0
  57. package/dist/form-submit.js.map +1 -0
  58. package/dist/form.d.ts +26 -0
  59. package/dist/form.d.ts.map +1 -0
  60. package/dist/form.js +66 -0
  61. package/dist/form.js.map +1 -0
  62. package/dist/index.d.ts +37 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +37 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/input.d.ts +4 -0
  67. package/dist/input.d.ts.map +1 -0
  68. package/dist/input.js +10 -0
  69. package/dist/input.js.map +1 -0
  70. package/dist/label.d.ts +6 -0
  71. package/dist/label.d.ts.map +1 -0
  72. package/dist/label.js +12 -0
  73. package/dist/label.js.map +1 -0
  74. package/dist/layout.d.ts +22 -0
  75. package/dist/layout.d.ts.map +1 -0
  76. package/dist/layout.js +36 -0
  77. package/dist/layout.js.map +1 -0
  78. package/dist/live-pulse.d.ts +7 -0
  79. package/dist/live-pulse.d.ts.map +1 -0
  80. package/dist/live-pulse.js +7 -0
  81. package/dist/live-pulse.js.map +1 -0
  82. package/dist/option-cards.d.ts +15 -0
  83. package/dist/option-cards.d.ts.map +1 -0
  84. package/dist/option-cards.js +9 -0
  85. package/dist/option-cards.js.map +1 -0
  86. package/dist/page-header.d.ts +9 -0
  87. package/dist/page-header.d.ts.map +1 -0
  88. package/dist/page-header.js +6 -0
  89. package/dist/page-header.js.map +1 -0
  90. package/dist/progress-bar.d.ts +16 -0
  91. package/dist/progress-bar.d.ts.map +1 -0
  92. package/dist/progress-bar.js +16 -0
  93. package/dist/progress-bar.js.map +1 -0
  94. package/dist/secret-field.d.ts +22 -0
  95. package/dist/secret-field.d.ts.map +1 -0
  96. package/dist/secret-field.js +26 -0
  97. package/dist/secret-field.js.map +1 -0
  98. package/dist/select.d.ts +14 -0
  99. package/dist/select.d.ts.map +1 -0
  100. package/dist/select.js +31 -0
  101. package/dist/select.js.map +1 -0
  102. package/dist/separator.d.ts +5 -0
  103. package/dist/separator.d.ts.map +1 -0
  104. package/dist/separator.js +10 -0
  105. package/dist/separator.js.map +1 -0
  106. package/dist/skeleton.d.ts +3 -0
  107. package/dist/skeleton.d.ts.map +1 -0
  108. package/dist/skeleton.js +8 -0
  109. package/dist/skeleton.js.map +1 -0
  110. package/dist/sonner.d.ts +8 -0
  111. package/dist/sonner.d.ts.map +1 -0
  112. package/dist/sonner.js +20 -0
  113. package/dist/sonner.js.map +1 -0
  114. package/dist/status-dot.d.ts +13 -0
  115. package/dist/status-dot.d.ts.map +1 -0
  116. package/dist/status-dot.js +20 -0
  117. package/dist/status-dot.js.map +1 -0
  118. package/dist/switch.d.ts +5 -0
  119. package/dist/switch.d.ts.map +1 -0
  120. package/dist/switch.js +10 -0
  121. package/dist/switch.js.map +1 -0
  122. package/dist/table.d.ts +11 -0
  123. package/dist/table.d.ts.map +1 -0
  124. package/dist/table.js +28 -0
  125. package/dist/table.js.map +1 -0
  126. package/dist/tabs.d.ts +8 -0
  127. package/dist/tabs.d.ts.map +1 -0
  128. package/dist/tabs.js +15 -0
  129. package/dist/tabs.js.map +1 -0
  130. package/dist/textarea.d.ts +4 -0
  131. package/dist/textarea.d.ts.map +1 -0
  132. package/dist/textarea.js +10 -0
  133. package/dist/textarea.js.map +1 -0
  134. package/dist/typography.d.ts +22 -0
  135. package/dist/typography.d.ts.map +1 -0
  136. package/dist/typography.js +39 -0
  137. package/dist/typography.js.map +1 -0
  138. package/dist/use-validated-form.d.ts +10 -0
  139. package/dist/use-validated-form.d.ts.map +1 -0
  140. package/dist/use-validated-form.js +20 -0
  141. package/dist/use-validated-form.js.map +1 -0
  142. package/dist/utils.d.ts +8 -0
  143. package/dist/utils.d.ts.map +1 -0
  144. package/dist/utils.js +12 -0
  145. package/dist/utils.js.map +1 -0
  146. package/dist/wizard-steps.d.ts +8 -0
  147. package/dist/wizard-steps.d.ts.map +1 -0
  148. package/dist/wizard-steps.js +7 -0
  149. package/dist/wizard-steps.js.map +1 -0
  150. package/package.json +23 -3
  151. package/src/alert.tsx +1 -0
  152. package/src/badge.tsx +1 -0
  153. package/src/button.tsx +1 -0
  154. package/src/card.tsx +1 -0
  155. package/src/checkbox.tsx +1 -0
  156. package/src/checkmark.tsx +34 -0
  157. package/src/dialog.tsx +1 -0
  158. package/src/drawer.tsx +140 -0
  159. package/src/field.tsx +1 -0
  160. package/src/form.tsx +1 -0
  161. package/src/index.ts +16 -0
  162. package/src/input.tsx +1 -0
  163. package/src/label.tsx +1 -0
  164. package/src/live-pulse.tsx +2 -8
  165. package/src/progress-bar.tsx +45 -0
  166. package/src/select.tsx +1 -0
  167. package/src/separator.tsx +1 -0
  168. package/src/skeleton.tsx +1 -0
  169. package/src/sonner.tsx +1 -0
  170. package/src/status-dot.tsx +42 -0
  171. package/src/styles.css +15 -0
  172. package/src/switch.tsx +1 -0
  173. package/src/table.tsx +1 -0
  174. package/src/tabs.tsx +1 -0
  175. package/src/textarea.tsx +1 -0
  176. 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"}
@@ -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.1.0",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
7
7
  },
8
- "description": "Admin UI kit: design tokens, dark/light theme, shadcn/ui-based components (MIT, see THIRD_PARTY_NOTICES.md).",
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.0.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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (alert) — 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
 
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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (button) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
package/src/card.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (card) — 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
 
3
4
  import { cn } from "./utils.js";
package/src/checkbox.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (checkbox) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
@@ -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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (dialog) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (field) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import type * as React from "react";
package/src/form.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (form) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (input) — 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 { cn } from "./utils.js";
3
4
 
package/src/label.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (label) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
@@ -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
- <span className="relative flex size-2">
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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (select) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
package/src/separator.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (separator) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (sonner) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import { Toaster as Sonner, type ToasterProps } from "sonner";
@@ -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
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (switch) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
package/src/table.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (table) — 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
 
3
4
  import { cn } from "./utils.js";
package/src/tabs.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (tabs) — see Provenance in packages/ui/README.md. Tolerated exception: migrated to custom code only when customization needs it.
1
2
  "use client";
2
3
 
3
4
  import * as React from "react";
package/src/textarea.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // Derived from shadcn/ui (textarea) — 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
 
3
4
  import { cn } from "./utils.js";
package/src/utils.ts CHANGED
@@ -1,3 +1,4 @@
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.
1
2
  import { clsx, type ClassValue } from "clsx";
2
3
  import { twMerge } from "tailwind-merge";
3
4