@hex-core/components 1.3.0 → 1.4.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 (186) hide show
  1. package/README.md +183 -9
  2. package/dist/accordion.d.ts +13 -0
  3. package/dist/accordion.js +62 -0
  4. package/dist/accordion.js.map +1 -0
  5. package/dist/alert-dialog.d.ts +34 -0
  6. package/dist/alert-dialog.js +125 -0
  7. package/dist/alert-dialog.js.map +1 -0
  8. package/dist/alert.d.ts +17 -0
  9. package/dist/alert.js +54 -0
  10. package/dist/alert.js.map +1 -0
  11. package/dist/aspect-ratio.d.ts +7 -0
  12. package/dist/aspect-ratio.js +8 -0
  13. package/dist/aspect-ratio.js.map +1 -0
  14. package/dist/avatar.d.ts +11 -0
  15. package/dist/avatar.js +44 -0
  16. package/dist/avatar.js.map +1 -0
  17. package/dist/badge.d.ts +22 -0
  18. package/dist/badge.js +36 -0
  19. package/dist/badge.js.map +1 -0
  20. package/dist/breadcrumb.d.ts +27 -0
  21. package/dist/breadcrumb.js +120 -0
  22. package/dist/breadcrumb.js.map +1 -0
  23. package/dist/button-variants-Bx6gCUFp.d.ts +19 -0
  24. package/dist/button.d.ts +13 -0
  25. package/dist/button.js +113 -0
  26. package/dist/button.js.map +1 -0
  27. package/dist/calendar.d.ts +17 -0
  28. package/dist/calendar.js +126 -0
  29. package/dist/calendar.js.map +1 -0
  30. package/dist/card.d.ts +16 -0
  31. package/dist/card.js +68 -0
  32. package/dist/card.js.map +1 -0
  33. package/dist/checkbox.d.ts +11 -0
  34. package/dist/checkbox.js +65 -0
  35. package/dist/checkbox.js.map +1 -0
  36. package/dist/cluster.d.ts +34 -0
  37. package/dist/cluster.js +50 -0
  38. package/dist/cluster.js.map +1 -0
  39. package/dist/collapsible.d.ts +11 -0
  40. package/dist/collapsible.js +10 -0
  41. package/dist/collapsible.js.map +1 -0
  42. package/dist/color-picker.d.ts +44 -0
  43. package/dist/color-picker.js +321 -0
  44. package/dist/color-picker.js.map +1 -0
  45. package/dist/combobox.d.ts +45 -0
  46. package/dist/combobox.js +226 -0
  47. package/dist/combobox.js.map +1 -0
  48. package/dist/command.d.ts +111 -0
  49. package/dist/command.js +232 -0
  50. package/dist/command.js.map +1 -0
  51. package/dist/container.d.ts +41 -0
  52. package/dist/container.js +39 -0
  53. package/dist/container.js.map +1 -0
  54. package/dist/context-menu.d.ts +37 -0
  55. package/dist/context-menu.js +130 -0
  56. package/dist/context-menu.js.map +1 -0
  57. package/dist/data-table.d.ts +33 -0
  58. package/dist/data-table.js +103 -0
  59. package/dist/data-table.js.map +1 -0
  60. package/dist/date-picker.d.ts +43 -0
  61. package/dist/date-picker.js +221 -0
  62. package/dist/date-picker.js.map +1 -0
  63. package/dist/dialog.d.ts +46 -0
  64. package/dist/dialog.js +125 -0
  65. package/dist/dialog.js.map +1 -0
  66. package/dist/drawer.d.ts +41 -0
  67. package/dist/drawer.js +82 -0
  68. package/dist/drawer.js.map +1 -0
  69. package/dist/dropdown-menu.d.ts +39 -0
  70. package/dist/dropdown-menu.js +133 -0
  71. package/dist/dropdown-menu.js.map +1 -0
  72. package/dist/dropzone.d.ts +54 -0
  73. package/dist/dropzone.js +194 -0
  74. package/dist/dropzone.js.map +1 -0
  75. package/dist/file-tree.d.ts +53 -0
  76. package/dist/file-tree.js +322 -0
  77. package/dist/file-tree.js.map +1 -0
  78. package/dist/form.d.ts +45 -0
  79. package/dist/form.js +114 -0
  80. package/dist/form.js.map +1 -0
  81. package/dist/grid.d.ts +50 -0
  82. package/dist/grid.js +58 -0
  83. package/dist/grid.js.map +1 -0
  84. package/dist/hover-card.d.ts +11 -0
  85. package/dist/hover-card.js +34 -0
  86. package/dist/hover-card.js.map +1 -0
  87. package/dist/index.d.ts +98 -1564
  88. package/dist/index.js +527 -5536
  89. package/dist/index.js.map +1 -1
  90. package/dist/input-otp.d.ts +19 -0
  91. package/dist/input-otp.js +71 -0
  92. package/dist/input-otp.js.map +1 -0
  93. package/dist/input.d.ts +6 -0
  94. package/dist/input.js +40 -0
  95. package/dist/input.js.map +1 -0
  96. package/dist/label.d.ts +11 -0
  97. package/dist/label.js +22 -0
  98. package/dist/label.js.map +1 -0
  99. package/dist/menubar.d.ts +35 -0
  100. package/dist/menubar.js +106 -0
  101. package/dist/menubar.js.map +1 -0
  102. package/dist/multi-combobox.d.ts +51 -0
  103. package/dist/multi-combobox.js +258 -0
  104. package/dist/multi-combobox.js.map +1 -0
  105. package/dist/navigation-menu.d.ts +23 -0
  106. package/dist/navigation-menu.js +108 -0
  107. package/dist/navigation-menu.js.map +1 -0
  108. package/dist/pagination.d.ts +40 -0
  109. package/dist/pagination.js +195 -0
  110. package/dist/pagination.js.map +1 -0
  111. package/dist/popover.d.ts +13 -0
  112. package/dist/popover.js +35 -0
  113. package/dist/popover.js.map +1 -0
  114. package/dist/progress.d.ts +10 -0
  115. package/dist/progress.js +38 -0
  116. package/dist/progress.js.map +1 -0
  117. package/dist/radio-group.d.ts +9 -0
  118. package/dist/radio-group.js +44 -0
  119. package/dist/radio-group.js.map +1 -0
  120. package/dist/resizable.d.ts +28 -0
  121. package/dist/resizable.js +66 -0
  122. package/dist/resizable.js.map +1 -0
  123. package/dist/schemas.d.ts +121 -0
  124. package/dist/schemas.js +4643 -0
  125. package/dist/schemas.js.map +1 -0
  126. package/dist/scroll-area.d.ts +18 -0
  127. package/dist/scroll-area.js +55 -0
  128. package/dist/scroll-area.js.map +1 -0
  129. package/dist/select.d.ts +21 -0
  130. package/dist/select.js +136 -0
  131. package/dist/select.js.map +1 -0
  132. package/dist/separator.d.ts +11 -0
  133. package/dist/separator.js +29 -0
  134. package/dist/separator.js.map +1 -0
  135. package/dist/sheet.d.ts +39 -0
  136. package/dist/sheet.js +140 -0
  137. package/dist/sheet.js.map +1 -0
  138. package/dist/sidebar.d.ts +75 -0
  139. package/dist/sidebar.js +201 -0
  140. package/dist/sidebar.js.map +1 -0
  141. package/dist/skeleton.d.ts +11 -0
  142. package/dist/skeleton.js +21 -0
  143. package/dist/skeleton.js.map +1 -0
  144. package/dist/slider.d.ts +20 -0
  145. package/dist/slider.js +55 -0
  146. package/dist/slider.js.map +1 -0
  147. package/dist/sonner.d.ts +14 -0
  148. package/dist/sonner.js +27 -0
  149. package/dist/sonner.js.map +1 -0
  150. package/dist/spacer.d.ts +38 -0
  151. package/dist/spacer.js +43 -0
  152. package/dist/spacer.js.map +1 -0
  153. package/dist/stack.d.ts +34 -0
  154. package/dist/stack.js +49 -0
  155. package/dist/stack.js.map +1 -0
  156. package/dist/stepper.d.ts +48 -0
  157. package/dist/stepper.js +226 -0
  158. package/dist/stepper.js.map +1 -0
  159. package/dist/switch.d.ts +11 -0
  160. package/dist/switch.js +47 -0
  161. package/dist/switch.js.map +1 -0
  162. package/dist/table.d.ts +24 -0
  163. package/dist/table.js +85 -0
  164. package/dist/table.js.map +1 -0
  165. package/dist/tabs.d.ts +13 -0
  166. package/dist/tabs.js +57 -0
  167. package/dist/tabs.js.map +1 -0
  168. package/dist/textarea.d.ts +10 -0
  169. package/dist/textarea.js +36 -0
  170. package/dist/textarea.js.map +1 -0
  171. package/dist/time-picker.d.ts +34 -0
  172. package/dist/time-picker.js +50 -0
  173. package/dist/time-picker.js.map +1 -0
  174. package/dist/timeline.d.ts +42 -0
  175. package/dist/timeline.js +84 -0
  176. package/dist/timeline.js.map +1 -0
  177. package/dist/toggle-group.d.ts +17 -0
  178. package/dist/toggle-group.js +83 -0
  179. package/dist/toggle-group.js.map +1 -0
  180. package/dist/toggle.d.ts +19 -0
  181. package/dist/toggle.js +49 -0
  182. package/dist/toggle.js.map +1 -0
  183. package/dist/tooltip.d.ts +13 -0
  184. package/dist/tooltip.js +33 -0
  185. package/dist/tooltip.js.map +1 -0
  186. package/package.json +68 -16
package/dist/card.js ADDED
@@ -0,0 +1,68 @@
1
+ import * as React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/card/card.tsx
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ var Card = React.forwardRef(
11
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ ref,
15
+ className: cn(
16
+ "rounded-lg border border-foreground/[0.08] bg-card text-card-foreground",
17
+ "shadow-sm transition-all duration-[var(--duration-normal,200ms)] ease-out",
18
+ "hover:shadow-md",
19
+ className
20
+ ),
21
+ ...props
22
+ }
23
+ )
24
+ );
25
+ Card.displayName = "Card";
26
+ var CardHeader = React.forwardRef(
27
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
28
+ "div",
29
+ {
30
+ ref,
31
+ className: cn("flex flex-col space-y-1.5 p-[var(--space-6,1.5rem)]", className),
32
+ ...props
33
+ }
34
+ )
35
+ );
36
+ CardHeader.displayName = "CardHeader";
37
+ var CardTitle = React.forwardRef(
38
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
39
+ "h3",
40
+ {
41
+ ref,
42
+ className: cn("text-2xl font-semibold leading-none tracking-tight", className),
43
+ ...props
44
+ }
45
+ )
46
+ );
47
+ CardTitle.displayName = "CardTitle";
48
+ var CardDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
49
+ CardDescription.displayName = "CardDescription";
50
+ var CardContent = React.forwardRef(
51
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-[var(--space-6,1.5rem)] pt-0", className), ...props })
52
+ );
53
+ CardContent.displayName = "CardContent";
54
+ var CardFooter = React.forwardRef(
55
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
56
+ "div",
57
+ {
58
+ ref,
59
+ className: cn("flex items-center p-[var(--space-6,1.5rem)] pt-0", className),
60
+ ...props
61
+ }
62
+ )
63
+ );
64
+ CardFooter.displayName = "CardFooter";
65
+
66
+ export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
67
+ //# sourceMappingURL=card.js.map
68
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/card/card.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACHA,IAAM,IAAA,GAAa,KAAA,CAAA,UAAA;AAAA,EAClB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACzB,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,yEAAA;AAAA,QACA,2EAAA;AAAA,QACA,iBAAA;AAAA,QACA;AAAA,OACD;AAAA,MACC,GAAG;AAAA;AAAA;AAGP;AACA,IAAA,CAAK,WAAA,GAAc,MAAA;AAGnB,IAAM,UAAA,GAAmB,KAAA,CAAA,UAAA;AAAA,EACxB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACzB,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,qDAAA,EAAuD,SAAS,CAAA;AAAA,MAC7E,GAAG;AAAA;AAAA;AAGP;AACA,UAAA,CAAW,WAAA,GAAc,YAAA;AAGzB,IAAM,SAAA,GAAkB,KAAA,CAAA,UAAA;AAAA,EACvB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACzB,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,oDAAA,EAAsD,SAAS,CAAA;AAAA,MAC5E,GAAG;AAAA;AAAA;AAGP;AACA,SAAA,CAAU,WAAA,GAAc,WAAA;AAGxB,IAAM,kBAAwB,KAAA,CAAA,UAAA,CAG5B,CAAC,EAAE,SAAA,EAAW,GAAG,OAAM,EAAG,GAAA,yBAC1B,GAAA,EAAA,EAAE,GAAA,EAAU,WAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA,EAAI,GAAG,OAAO,CACnF;AACD,eAAA,CAAgB,WAAA,GAAc,iBAAA;AAG9B,IAAM,WAAA,GAAoB,KAAA,CAAA,UAAA;AAAA,EACzB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACzB,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAU,WAAW,EAAA,CAAG,gCAAA,EAAkC,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO;AAExF;AACA,WAAA,CAAY,WAAA,GAAc,aAAA;AAG1B,IAAM,UAAA,GAAmB,KAAA,CAAA,UAAA;AAAA,EACxB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACzB,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,kDAAA,EAAoD,SAAS,CAAA;AAAA,MAC1E,GAAG;AAAA;AAAA;AAGP;AACA,UAAA,CAAW,WAAA,GAAc,YAAA","file":"card.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n// Card consumes tokens --space-6, --space-4, --duration-normal.\n// Fallbacks match Tailwind defaults for consumers without a theme loaded.\n\n/** A container card with subtle shadow and border. */\nconst Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"rounded-lg border border-foreground/[0.08] bg-card text-card-foreground\",\n\t\t\t\t\"shadow-sm transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\"hover:shadow-md\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nCard.displayName = \"Card\";\n\n/** The header section of a Card. */\nconst CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={cn(\"flex flex-col space-y-1.5 p-[var(--space-6,1.5rem)]\", className)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nCardHeader.displayName = \"CardHeader\";\n\n/** The title element inside a CardHeader. */\nconst CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<h3\n\t\t\tref={ref}\n\t\t\tclassName={cn(\"text-2xl font-semibold leading-none tracking-tight\", className)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nCardTitle.displayName = \"CardTitle\";\n\n/** A description element inside a CardHeader. */\nconst CardDescription = React.forwardRef<\n\tHTMLParagraphElement,\n\tReact.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n\t<p ref={ref} className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n));\nCardDescription.displayName = \"CardDescription\";\n\n/** The main content area of a Card. */\nconst CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div ref={ref} className={cn(\"p-[var(--space-6,1.5rem)] pt-0\", className)} {...props} />\n\t),\n);\nCardContent.displayName = \"CardContent\";\n\n/** The footer section of a Card. */\nconst CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={cn(\"flex items-center p-[var(--space-6,1.5rem)] pt-0\", className)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nCardFooter.displayName = \"CardFooter\";\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };\n"]}
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
+
4
+ /**
5
+ * An accessible checkbox component built on Radix UI.
6
+ * Supports checked, unchecked, and indeterminate states with smooth animations.
7
+ */
8
+ type CheckboxProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;
9
+ declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
10
+
11
+ export { Checkbox, type CheckboxProps };
@@ -0,0 +1,65 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+ var Checkbox = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
12
+ CheckboxPrimitive.Root,
13
+ {
14
+ ref,
15
+ className: cn(
16
+ "group h-4 w-4 shrink-0 rounded-sm border border-input",
17
+ "transition-all duration-[var(--duration-normal,200ms)] ease-out",
18
+ "shadow-sm inset-ring-1 inset-ring-foreground/[0.06]",
19
+ "hover:border-ring/50 hover:shadow-md",
20
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
21
+ "disabled:cursor-not-allowed disabled:opacity-50",
22
+ "data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground",
23
+ "data-[state=indeterminate]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:text-primary-foreground",
24
+ className
25
+ ),
26
+ ...props,
27
+ children: /* @__PURE__ */ jsxs(CheckboxPrimitive.Indicator, { className: cn("flex items-center justify-center text-current"), children: [
28
+ /* @__PURE__ */ jsx(
29
+ "svg",
30
+ {
31
+ xmlns: "http://www.w3.org/2000/svg",
32
+ viewBox: "0 0 24 24",
33
+ fill: "none",
34
+ stroke: "currentColor",
35
+ strokeWidth: "3",
36
+ strokeLinecap: "round",
37
+ strokeLinejoin: "round",
38
+ className: "hidden h-3.5 w-3.5 group-data-[state=checked]:block",
39
+ "aria-hidden": "true",
40
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
41
+ }
42
+ ),
43
+ /* @__PURE__ */ jsx(
44
+ "svg",
45
+ {
46
+ xmlns: "http://www.w3.org/2000/svg",
47
+ viewBox: "0 0 24 24",
48
+ fill: "none",
49
+ stroke: "currentColor",
50
+ strokeWidth: "3",
51
+ strokeLinecap: "round",
52
+ strokeLinejoin: "round",
53
+ className: "hidden h-3.5 w-3.5 group-data-[state=indeterminate]:block",
54
+ "aria-hidden": "true",
55
+ children: /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
56
+ }
57
+ )
58
+ ] })
59
+ }
60
+ ));
61
+ Checkbox.displayName = "Checkbox";
62
+
63
+ export { Checkbox };
64
+ //# sourceMappingURL=checkbox.js.map
65
+ //# sourceMappingURL=checkbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/primitives/checkbox/checkbox.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACEA,IAAM,QAAA,GAAiB,iBAGrB,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAAmB,iBAAA,CAAA,IAAA;AAAA,EAAlB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACV,uDAAA;AAAA,MACA,iEAAA;AAAA,MACA,qDAAA;AAAA,MACA,sCAAA;AAAA,MACA,qGAAA;AAAA,MACA,iDAAA;AAAA,MACA,kHAAA;AAAA,MACA,oIAAA;AAAA,MACA;AAAA,KACD;AAAA,IACC,GAAG,KAAA;AAAA,IAEJ,+BAAmB,iBAAA,CAAA,SAAA,EAAlB,EAA4B,SAAA,EAAW,EAAA,CAAG,+CAA+C,CAAA,EAGzF,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACA,KAAA,EAAM,4BAAA;AAAA,UACN,OAAA,EAAQ,WAAA;AAAA,UACR,IAAA,EAAK,MAAA;AAAA,UACL,MAAA,EAAO,cAAA;AAAA,UACP,WAAA,EAAY,GAAA;AAAA,UACZ,aAAA,EAAc,OAAA;AAAA,UACd,cAAA,EAAe,OAAA;AAAA,UACf,SAAA,EAAU,qDAAA;AAAA,UACV,aAAA,EAAY,MAAA;AAAA,UAEZ,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAS,MAAA,EAAO,gBAAA,EAAiB;AAAA;AAAA,OACnC;AAAA,sBACA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACA,KAAA,EAAM,4BAAA;AAAA,UACN,OAAA,EAAQ,WAAA;AAAA,UACR,IAAA,EAAK,MAAA;AAAA,UACL,MAAA,EAAO,cAAA;AAAA,UACP,WAAA,EAAY,GAAA;AAAA,UACZ,aAAA,EAAc,OAAA;AAAA,UACd,cAAA,EAAe,OAAA;AAAA,UACf,SAAA,EAAU,2DAAA;AAAA,UACV,aAAA,EAAY,MAAA;AAAA,UAEZ,QAAA,kBAAA,GAAA,CAAC,UAAK,EAAA,EAAG,GAAA,EAAI,IAAG,IAAA,EAAK,EAAA,EAAG,IAAA,EAAK,EAAA,EAAG,IAAA,EAAK;AAAA;AAAA;AACtC,KAAA,EACD;AAAA;AACD,CACA;AACD,QAAA,CAAS,WAAA,GAAc,UAAA","file":"checkbox.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * An accessible checkbox component built on Radix UI.\n * Supports checked, unchecked, and indeterminate states with smooth animations.\n */\nexport type CheckboxProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;\n\nconst Checkbox = React.forwardRef<\n\tReact.ComponentRef<typeof CheckboxPrimitive.Root>,\n\tCheckboxProps\n>(({ className, ...props }, ref) => (\n\t<CheckboxPrimitive.Root\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"group h-4 w-4 shrink-0 rounded-sm border border-input\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\"hover:border-ring/50 hover:shadow-md\",\n\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\"data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground\",\n\t\t\t\"data-[state=indeterminate]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:text-primary-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t<CheckboxPrimitive.Indicator className={cn(\"flex items-center justify-center text-current\")}>\n\t\t\t{/* ✓ when checked; dash when indeterminate. The Root has `group`, so each icon\n\t\t\t shows only when the Root's data-state matches. */}\n\t\t\t<svg\n\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"3\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tclassName=\"hidden h-3.5 w-3.5 group-data-[state=checked]:block\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t>\n\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t</svg>\n\t\t\t<svg\n\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"3\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tclassName=\"hidden h-3.5 w-3.5 group-data-[state=indeterminate]:block\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t>\n\t\t\t\t<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n\t\t\t</svg>\n\t\t</CheckboxPrimitive.Indicator>\n\t</CheckboxPrimitive.Root>\n));\nCheckbox.displayName = \"Checkbox\";\n\nexport { Checkbox };\n"]}
@@ -0,0 +1,34 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+ import * as React from 'react';
5
+
6
+ /**
7
+ * CVA variants for Cluster — horizontal flex flow with wrap.
8
+ * `gap` and `justify` pull from shared layout-variant maps; `align` adds
9
+ * `baseline` (text-baseline alignment for mixed-size siblings).
10
+ */
11
+ declare const clusterVariants: (props?: ({
12
+ gap?: "sm" | "lg" | "md" | "xl" | "xs" | null | undefined;
13
+ align?: "center" | "start" | "end" | "stretch" | "baseline" | null | undefined;
14
+ justify?: "center" | "start" | "end" | "between" | null | undefined;
15
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
16
+ /** Props for the Cluster component. */
17
+ interface ClusterProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof clusterVariants> {
18
+ }
19
+ /**
20
+ * Horizontal flex flow with wrap. Children flow left-to-right and wrap to next line as needed.
21
+ * @param props - Cluster props including `gap`, `align`, and `justify` variant keys.
22
+ * @returns A flex row that wraps with consistent gap.
23
+ * @example
24
+ * ```tsx
25
+ * <Cluster gap="sm">
26
+ * <Badge>react</Badge>
27
+ * <Badge>typescript</Badge>
28
+ * <Badge>tailwind</Badge>
29
+ * </Cluster>
30
+ * ```
31
+ */
32
+ declare function Cluster({ className, gap, align, justify, ...props }: ClusterProps): react_jsx_runtime.JSX.Element;
33
+
34
+ export { Cluster, type ClusterProps, clusterVariants };
@@ -0,0 +1,50 @@
1
+ import { cva } from 'class-variance-authority';
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/primitives/cluster/cluster.tsx
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+
11
+ // src/primitives/_shared/layout-variants.ts
12
+ var gapVariants = {
13
+ xs: "gap-[var(--gap-xs,0.25rem)]",
14
+ sm: "gap-[var(--gap-sm,0.5rem)]",
15
+ md: "gap-[var(--gap-md,1rem)]",
16
+ lg: "gap-[var(--gap-lg,1.5rem)]",
17
+ xl: "gap-[var(--gap-xl,2rem)]"
18
+ };
19
+ var justifyVariants = {
20
+ start: "justify-start",
21
+ center: "justify-center",
22
+ end: "justify-end",
23
+ between: "justify-between"
24
+ };
25
+ var clusterAlignVariants = {
26
+ start: "items-start",
27
+ center: "items-center",
28
+ end: "items-end",
29
+ stretch: "items-stretch",
30
+ baseline: "items-baseline"
31
+ };
32
+ var clusterVariants = cva("flex flex-wrap", {
33
+ variants: {
34
+ gap: gapVariants,
35
+ align: clusterAlignVariants,
36
+ justify: justifyVariants
37
+ },
38
+ defaultVariants: {
39
+ gap: "md",
40
+ align: "center",
41
+ justify: "start"
42
+ }
43
+ });
44
+ function Cluster({ className, gap, align, justify, ...props }) {
45
+ return /* @__PURE__ */ jsx("div", { className: cn(clusterVariants({ gap, align, justify }), className), ...props });
46
+ }
47
+
48
+ export { Cluster, clusterVariants };
49
+ //# sourceMappingURL=cluster.js.map
50
+ //# sourceMappingURL=cluster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/primitives/_shared/layout-variants.ts","../src/primitives/cluster/cluster.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;;;ACCO,IAAM,WAAA,GAAc;AAAA,EAC1B,EAAA,EAAI,6BAAA;AAAA,EACJ,EAAA,EAAI,4BAAA;AAAA,EACJ,EAAA,EAAI,0BAAA;AAAA,EACJ,EAAA,EAAI,4BAAA;AAAA,EACJ,EAAA,EAAI;AACL,CAAA;AAGO,IAAM,eAAA,GAAkB;AAAA,EAC9B,KAAA,EAAO,eAAA;AAAA,EACP,MAAA,EAAQ,gBAAA;AAAA,EACR,GAAA,EAAK,aAAA;AAAA,EACL,OAAA,EAAS;AACV,CAAA;AAWO,IAAM,oBAAA,GAAuB;AAAA,EACnC,KAAA,EAAO,aAAA;AAAA,EACP,MAAA,EAAQ,cAAA;AAAA,EACR,GAAA,EAAK,WAAA;AAAA,EACL,OAAA,EAAS,eAAA;AAAA,EACT,QAAA,EAAU;AACX,CAAA;AC5BA,IAAM,eAAA,GAAkB,IAAI,gBAAA,EAAkB;AAAA,EAC7C,QAAA,EAAU;AAAA,IACT,GAAA,EAAK,WAAA;AAAA,IACL,KAAA,EAAO,oBAAA;AAAA,IACP,OAAA,EAAS;AAAA,GACV;AAAA,EACA,eAAA,EAAiB;AAAA,IAChB,GAAA,EAAK,IAAA;AAAA,IACL,KAAA,EAAO,QAAA;AAAA,IACP,OAAA,EAAS;AAAA;AAEX,CAAC;AAoBD,SAAS,OAAA,CAAQ,EAAE,SAAA,EAAW,GAAA,EAAK,OAAO,OAAA,EAAS,GAAG,OAAM,EAAiB;AAC5E,EAAA,uBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,gBAAgB,EAAE,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AAEtF","file":"cluster.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","/**\n * Single source of truth for layout-primitive CVA variant maps.\n *\n * Stack, Cluster, Grid all share `gap` and `justify` value sets; align values\n * differ slightly (`stretch` for column-like flows, `baseline` for row flows).\n * Centralizing the maps here keeps token names and Tailwind classes in one\n * file — when the gap scale changes (renamed token, new step, etc.), all\n * three components update together.\n */\n\n/** Gap scale bound to `--gap-*` tokens. Used by Stack, Cluster, Grid. */\nexport const gapVariants = {\n\txs: \"gap-[var(--gap-xs,0.25rem)]\",\n\tsm: \"gap-[var(--gap-sm,0.5rem)]\",\n\tmd: \"gap-[var(--gap-md,1rem)]\",\n\tlg: \"gap-[var(--gap-lg,1.5rem)]\",\n\txl: \"gap-[var(--gap-xl,2rem)]\",\n} as const;\n\n/** `justify-content` values shared by Stack and Cluster. */\nexport const justifyVariants = {\n\tstart: \"justify-start\",\n\tcenter: \"justify-center\",\n\tend: \"justify-end\",\n\tbetween: \"justify-between\",\n} as const;\n\n/** Cross-axis `align-items` values for vertical/grid flows (column-like). */\nexport const flexAlignVariants = {\n\tstart: \"items-start\",\n\tcenter: \"items-center\",\n\tend: \"items-end\",\n\tstretch: \"items-stretch\",\n} as const;\n\n/** Cross-axis `align-items` values for horizontal flows. Includes `baseline`. */\nexport const clusterAlignVariants = {\n\tstart: \"items-start\",\n\tcenter: \"items-center\",\n\tend: \"items-end\",\n\tstretch: \"items-stretch\",\n\tbaseline: \"items-baseline\",\n} as const;\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport {\n\tclusterAlignVariants,\n\tgapVariants,\n\tjustifyVariants,\n} from \"../_shared/layout-variants.js\";\n\n/**\n * CVA variants for Cluster — horizontal flex flow with wrap.\n * `gap` and `justify` pull from shared layout-variant maps; `align` adds\n * `baseline` (text-baseline alignment for mixed-size siblings).\n */\nconst clusterVariants = cva(\"flex flex-wrap\", {\n\tvariants: {\n\t\tgap: gapVariants,\n\t\talign: clusterAlignVariants,\n\t\tjustify: justifyVariants,\n\t},\n\tdefaultVariants: {\n\t\tgap: \"md\",\n\t\talign: \"center\",\n\t\tjustify: \"start\",\n\t},\n});\n\n/** Props for the Cluster component. */\nexport interface ClusterProps\n\textends React.HTMLAttributes<HTMLDivElement>,\n\t\tVariantProps<typeof clusterVariants> {}\n\n/**\n * Horizontal flex flow with wrap. Children flow left-to-right and wrap to next line as needed.\n * @param props - Cluster props including `gap`, `align`, and `justify` variant keys.\n * @returns A flex row that wraps with consistent gap.\n * @example\n * ```tsx\n * <Cluster gap=\"sm\">\n * <Badge>react</Badge>\n * <Badge>typescript</Badge>\n * <Badge>tailwind</Badge>\n * </Cluster>\n * ```\n */\nfunction Cluster({ className, gap, align, justify, ...props }: ClusterProps) {\n\treturn (\n\t\t<div className={cn(clusterVariants({ gap, align, justify }), className)} {...props} />\n\t);\n}\n\nexport { Cluster, clusterVariants };\n"]}
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
3
+
4
+ /** Root container controlling the expanded state of the content. */
5
+ declare const Collapsible: React.ForwardRefExoticComponent<CollapsiblePrimitive.CollapsibleProps & React.RefAttributes<HTMLDivElement>>;
6
+ /** The element that toggles the Collapsible open/closed. */
7
+ declare const CollapsibleTrigger: React.ForwardRefExoticComponent<CollapsiblePrimitive.CollapsibleTriggerProps & React.RefAttributes<HTMLButtonElement>>;
8
+ /** The collapsible content shown/hidden by the trigger. */
9
+ declare const CollapsibleContent: React.ForwardRefExoticComponent<CollapsiblePrimitive.CollapsibleContentProps & React.RefAttributes<HTMLDivElement>>;
10
+
11
+ export { Collapsible, CollapsibleContent, CollapsibleTrigger };
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
3
+
4
+ var Collapsible = CollapsiblePrimitive.Root;
5
+ var CollapsibleTrigger2 = CollapsiblePrimitive.CollapsibleTrigger;
6
+ var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
7
+
8
+ export { Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger };
9
+ //# sourceMappingURL=collapsible.js.map
10
+ //# sourceMappingURL=collapsible.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/collapsible/collapsible.tsx"],"names":["CollapsibleTrigger","CollapsibleContent"],"mappings":";;AAKA,IAAM,WAAA,GAAmC,oBAAA,CAAA;AAGzC,IAAMA,mBAAAA,GAA0C,oBAAA,CAAA;AAGhD,IAAMC,mBAAAA,GAA0C,oBAAA,CAAA","file":"collapsible.js","sourcesContent":["\"use client\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\n\n/** Root container controlling the expanded state of the content. */\nconst Collapsible = CollapsiblePrimitive.Root;\n\n/** The element that toggles the Collapsible open/closed. */\nconst CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;\n\n/** The collapsible content shown/hidden by the trigger. */\nconst CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent };\n"]}
@@ -0,0 +1,44 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /** Props for the ColorPicker component. */
4
+ interface ColorPickerProps {
5
+ /**
6
+ * Current color as an HSL triplet string (`"<H> <S>% <L>%"`, e.g. `"240 5.9% 10%"`).
7
+ * Match the format used by `@hex-core/tokens`; round-trip safe.
8
+ */
9
+ value: string;
10
+ /**
11
+ * Called with the next HSL triplet whenever the user drags a slider or commits a valid hex value.
12
+ * Not called for invalid hex input — the picker keeps the prior value until the input parses cleanly.
13
+ */
14
+ onChange: (value: string) => void;
15
+ /**
16
+ * Disable interaction. Native `disabled` attribute is set on the trigger so the
17
+ * popover doesn't open via mouse or keyboard activation. Tab focus still lands
18
+ * on the trigger per browser defaults; if you want to fully remove it from the
19
+ * tab order, wrap in a parent that handles `tabIndex` accordingly.
20
+ */
21
+ disabled?: boolean;
22
+ /** Accessible name for the trigger button (defaults to "Pick color"). */
23
+ "aria-label"?: string;
24
+ /** Additional class names merged onto the trigger. */
25
+ className?: string;
26
+ }
27
+ /**
28
+ * HSL-native color picker. Edits an HSL triplet directly via three sliders
29
+ * (H/S/L), with a hex input as a display adapter.
30
+ *
31
+ * Round-trip safe: triplet → hex → triplet preserves the slider state because
32
+ * sliders are the source of truth and hex updates them only when valid.
33
+ *
34
+ * @param props - Controlled component; `value` and `onChange` are required.
35
+ * @returns A trigger button that opens a popover with H/S/L sliders + hex input.
36
+ * @example
37
+ * ```tsx
38
+ * const [color, setColor] = React.useState("240 5.9% 10%");
39
+ * <ColorPicker value={color} onChange={setColor} aria-label="Primary color" />
40
+ * ```
41
+ */
42
+ declare function ColorPicker({ value, onChange, disabled, "aria-label": ariaLabel, className, }: ColorPickerProps): react_jsx_runtime.JSX.Element;
43
+
44
+ export { ColorPicker, type ColorPickerProps };
@@ -0,0 +1,321 @@
1
+ "use client";
2
+ import * as React5 from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+ import * as LabelPrimitive from '@radix-ui/react-label';
7
+ import { cva } from 'class-variance-authority';
8
+ import * as SliderPrimitive from '@radix-ui/react-slider';
9
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
10
+
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+
15
+ // src/lib/color.ts
16
+ function parseHslTriplet(triplet) {
17
+ const parts = triplet.trim().split(/\s+/);
18
+ return {
19
+ h: Number.parseFloat(parts[0]) || 0,
20
+ s: Number.parseFloat(parts[1]) || 0,
21
+ l: Number.parseFloat(parts[2]) || 0
22
+ };
23
+ }
24
+ function formatHslTriplet({ h, s, l }) {
25
+ const round = (n) => Math.abs(n - Math.round(n)) < 1e-6 ? `${Math.round(n)}` : n.toFixed(1);
26
+ return `${Math.round(h)} ${round(s)}% ${round(l)}%`;
27
+ }
28
+ function hslToRgb(h, s, l) {
29
+ const sN = s / 100;
30
+ const lN = l / 100;
31
+ const k = (n) => (n + h / 30) % 12;
32
+ const a = sN * Math.min(lN, 1 - lN);
33
+ const f = (n) => lN - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));
34
+ return {
35
+ r: Math.round(255 * f(0)),
36
+ g: Math.round(255 * f(8)),
37
+ b: Math.round(255 * f(4))
38
+ };
39
+ }
40
+ function rgbToHsl(r, g, b) {
41
+ const rN = r / 255;
42
+ const gN = g / 255;
43
+ const bN = b / 255;
44
+ const max = Math.max(rN, gN, bN);
45
+ const min = Math.min(rN, gN, bN);
46
+ let h = 0;
47
+ let s = 0;
48
+ const l = (max + min) / 2;
49
+ if (max !== min) {
50
+ const d = max - min;
51
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
52
+ if (max === rN) h = (gN - bN) / d + (gN < bN ? 6 : 0);
53
+ else if (max === gN) h = (bN - rN) / d + 2;
54
+ else h = (rN - gN) / d + 4;
55
+ h /= 6;
56
+ }
57
+ return { h: h * 360, s: s * 100, l: l * 100 };
58
+ }
59
+ function hslTripletToHex(triplet) {
60
+ const { h, s, l } = parseHslTriplet(triplet);
61
+ const { r, g, b } = hslToRgb(h, s, l);
62
+ const toHex = (n) => n.toString(16).padStart(2, "0");
63
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
64
+ }
65
+ function hexToHslTriplet(hex) {
66
+ const clean = hex.trim().replace(/^#/, "");
67
+ let normalized;
68
+ if (/^[0-9a-fA-F]{3}$/.test(clean)) {
69
+ normalized = clean.split("").map((c) => c + c).join("");
70
+ } else if (/^[0-9a-fA-F]{6}$/.test(clean)) {
71
+ normalized = clean;
72
+ } else {
73
+ return null;
74
+ }
75
+ const r = Number.parseInt(normalized.slice(0, 2), 16);
76
+ const g = Number.parseInt(normalized.slice(2, 4), 16);
77
+ const b = Number.parseInt(normalized.slice(4, 6), 16);
78
+ return formatHslTriplet(rgbToHsl(r, g, b));
79
+ }
80
+ var Input = React5.forwardRef(
81
+ ({ className, type, ...props }, ref) => {
82
+ return /* @__PURE__ */ jsx(
83
+ "input",
84
+ {
85
+ type,
86
+ className: cn(
87
+ "flex h-[var(--control-height-md,2.5rem)] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm",
88
+ "transition-all duration-[var(--duration-normal,200ms)] ease-out",
89
+ // inset-ring gives a self-borne edge so the input field is visible on flat
90
+ // surfaces (token border alone is too low-contrast on bg-background=white).
91
+ "shadow-sm inset-ring-1 inset-ring-foreground/[0.06]",
92
+ "file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground",
93
+ "placeholder:text-muted-foreground",
94
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
95
+ "focus-visible:shadow-md focus-visible:border-ring/50",
96
+ "hover:border-ring/30 hover:shadow-md",
97
+ "disabled:cursor-not-allowed disabled:opacity-50",
98
+ className
99
+ ),
100
+ ref,
101
+ ...props
102
+ }
103
+ );
104
+ }
105
+ );
106
+ Input.displayName = "Input";
107
+ var labelVariants = cva(
108
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
109
+ );
110
+ var Label = React5.forwardRef(
111
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props })
112
+ );
113
+ Label.displayName = "Label";
114
+ var Slider = React5.forwardRef(({ className, thumbLabels, ...props }, ref) => {
115
+ const values = props.value ?? props.defaultValue ?? [0];
116
+ const rootLabel = props["aria-label"];
117
+ const rootLabelledBy = props["aria-labelledby"];
118
+ if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production" && thumbLabels && thumbLabels.length !== values.length) {
119
+ console.warn(
120
+ `Slider: thumbLabels.length (${thumbLabels.length}) does not match value.length (${values.length}). Missing labels fall back to indexed names; extra labels are ignored.`
121
+ );
122
+ }
123
+ return /* @__PURE__ */ jsxs(
124
+ SliderPrimitive.Root,
125
+ {
126
+ ref,
127
+ className: cn("relative flex w-full touch-none select-none items-center", className),
128
+ ...props,
129
+ children: [
130
+ /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-2 w-full grow overflow-hidden rounded-full border border-foreground/[0.08] bg-secondary", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary" }) }),
131
+ values.map((_, i) => {
132
+ const explicit = thumbLabels?.[i];
133
+ const fallback = values.length === 1 ? rootLabel : rootLabel ? `${rootLabel} (${i + 1} of ${values.length})` : void 0;
134
+ return /* @__PURE__ */ jsx(
135
+ SliderPrimitive.Thumb,
136
+ {
137
+ "aria-label": explicit ?? fallback,
138
+ "aria-labelledby": explicit || fallback ? void 0 : rootLabelledBy,
139
+ className: cn(
140
+ "block h-5 w-5 rounded-full border-2 border-primary bg-background",
141
+ "transition-all duration-[var(--duration-normal,200ms)] ease-out shadow-md",
142
+ "hover:shadow-lg hover:scale-110",
143
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
144
+ "disabled:pointer-events-none disabled:opacity-50"
145
+ )
146
+ },
147
+ i
148
+ );
149
+ })
150
+ ]
151
+ }
152
+ );
153
+ });
154
+ Slider.displayName = "Slider";
155
+ var Popover = PopoverPrimitive.Root;
156
+ var PopoverTrigger = PopoverPrimitive.Trigger;
157
+ var PopoverContent = React5.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
158
+ PopoverPrimitive.Content,
159
+ {
160
+ ref,
161
+ align,
162
+ sideOffset,
163
+ className: cn(
164
+ "z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none",
165
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
166
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
167
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
168
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
169
+ className
170
+ ),
171
+ ...props
172
+ }
173
+ ) }));
174
+ PopoverContent.displayName = "PopoverContent";
175
+ var INTEGER_EPSILON = 1e-6;
176
+ var looksInteger = (n) => Math.abs(n - Math.round(n)) < INTEGER_EPSILON;
177
+ function ColorPicker({
178
+ value,
179
+ onChange,
180
+ disabled,
181
+ "aria-label": ariaLabel = "Pick color",
182
+ className
183
+ }) {
184
+ const hsl = React5.useMemo(() => parseHslTriplet(value), [value]);
185
+ const hex = React5.useMemo(() => hslTripletToHex(value), [value]);
186
+ const update = React5.useCallback(
187
+ (patch) => {
188
+ onChange(formatHslTriplet({ ...hsl, ...patch }));
189
+ },
190
+ [hsl, onChange]
191
+ );
192
+ const hexInputRef = React5.useRef(null);
193
+ const [hexBuffer, setHexBuffer] = React5.useState(hex);
194
+ React5.useEffect(() => {
195
+ if (typeof document === "undefined" || document.activeElement !== hexInputRef.current) {
196
+ setHexBuffer(hex);
197
+ }
198
+ }, [hex]);
199
+ const handleHexChange = (e) => {
200
+ const next = e.target.value;
201
+ setHexBuffer(next);
202
+ const triplet = hexToHslTriplet(next);
203
+ if (triplet !== null) onChange(triplet);
204
+ };
205
+ const hexId = React5.useId();
206
+ return /* @__PURE__ */ jsxs(Popover, { children: [
207
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
208
+ "button",
209
+ {
210
+ type: "button",
211
+ disabled,
212
+ "aria-label": ariaLabel,
213
+ className: cn(
214
+ "inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm shadow-sm",
215
+ "transition-all duration-[var(--duration-normal,200ms)] ease-out",
216
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
217
+ "hover:shadow-md disabled:pointer-events-none disabled:opacity-50",
218
+ className
219
+ ),
220
+ children: [
221
+ /* @__PURE__ */ jsx(
222
+ "span",
223
+ {
224
+ "aria-hidden": "true",
225
+ className: "h-5 w-5 rounded-sm border border-border",
226
+ style: { backgroundColor: `hsl(${value})` }
227
+ }
228
+ ),
229
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs uppercase", children: hex })
230
+ ]
231
+ }
232
+ ) }),
233
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-72 p-4", align: "start", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
234
+ /* @__PURE__ */ jsx(
235
+ SliderRow,
236
+ {
237
+ label: "Hue",
238
+ suffix: "\xB0",
239
+ value: hsl.h,
240
+ max: 360,
241
+ step: 1,
242
+ onChange: (h) => update({ h })
243
+ }
244
+ ),
245
+ /* @__PURE__ */ jsx(
246
+ SliderRow,
247
+ {
248
+ label: "Saturation",
249
+ suffix: "%",
250
+ value: hsl.s,
251
+ max: 100,
252
+ step: 0.1,
253
+ onChange: (s) => update({ s })
254
+ }
255
+ ),
256
+ /* @__PURE__ */ jsx(
257
+ SliderRow,
258
+ {
259
+ label: "Lightness",
260
+ suffix: "%",
261
+ value: hsl.l,
262
+ max: 100,
263
+ step: 0.1,
264
+ onChange: (l) => update({ l })
265
+ }
266
+ ),
267
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
268
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
269
+ /* @__PURE__ */ jsx(Label, { htmlFor: hexId, className: "text-xs", children: "Hex" }),
270
+ /* @__PURE__ */ jsx(
271
+ Input,
272
+ {
273
+ id: hexId,
274
+ ref: hexInputRef,
275
+ value: hexBuffer,
276
+ onChange: handleHexChange,
277
+ className: "font-mono text-xs uppercase",
278
+ spellCheck: false,
279
+ autoComplete: "off"
280
+ }
281
+ )
282
+ ] }),
283
+ /* @__PURE__ */ jsx(
284
+ "span",
285
+ {
286
+ "aria-hidden": "true",
287
+ className: "h-9 w-9 shrink-0 rounded-md border border-border",
288
+ style: { backgroundColor: `hsl(${value})` }
289
+ }
290
+ )
291
+ ] })
292
+ ] }) })
293
+ ] });
294
+ }
295
+ function SliderRow({ label, suffix, value, max, step, onChange }) {
296
+ const display = looksInteger(value) ? `${Math.round(value)}` : value.toFixed(1);
297
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
298
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
299
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: label }),
300
+ /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs tabular-nums text-muted-foreground", children: [
301
+ display,
302
+ suffix
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsx(
306
+ Slider,
307
+ {
308
+ value: [value],
309
+ min: 0,
310
+ max,
311
+ step,
312
+ "aria-label": label,
313
+ onValueChange: (values) => onChange(values[0] ?? 0)
314
+ }
315
+ )
316
+ ] });
317
+ }
318
+
319
+ export { ColorPicker };
320
+ //# sourceMappingURL=color-picker.js.map
321
+ //# sourceMappingURL=color-picker.js.map