@fanvue/ui 0.1.0-alpha.2 → 1.0.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 (221) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/Alert/Alert.cjs +72 -0
  3. package/dist/cjs/components/Alert/Alert.cjs.map +1 -0
  4. package/dist/cjs/components/Avatar/Avatar.cjs +162 -0
  5. package/dist/cjs/components/Avatar/Avatar.cjs.map +1 -0
  6. package/dist/cjs/components/Badge/Badge.cjs +99 -0
  7. package/dist/cjs/components/Badge/Badge.cjs.map +1 -0
  8. package/dist/cjs/components/Button/Button.cjs +172 -0
  9. package/dist/cjs/components/Button/Button.cjs.map +1 -0
  10. package/dist/cjs/components/Checkbox/Checkbox.cjs +157 -0
  11. package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -0
  12. package/dist/cjs/components/Chip/Chip.cjs +92 -0
  13. package/dist/cjs/components/Chip/Chip.cjs.map +1 -0
  14. package/dist/cjs/components/Count/Count.cjs +56 -0
  15. package/dist/cjs/components/Count/Count.cjs.map +1 -0
  16. package/dist/cjs/components/DatePicker/DatePicker.cjs +133 -0
  17. package/dist/cjs/components/DatePicker/DatePicker.cjs.map +1 -0
  18. package/dist/cjs/components/Divider/Divider.cjs +69 -0
  19. package/dist/cjs/components/Divider/Divider.cjs.map +1 -0
  20. package/dist/cjs/components/IconButton/IconButton.cjs +92 -0
  21. package/dist/cjs/components/IconButton/IconButton.cjs.map +1 -0
  22. package/dist/cjs/components/Icons/ArrowRightIcon.cjs +47 -0
  23. package/dist/cjs/components/Icons/ArrowRightIcon.cjs.map +1 -0
  24. package/dist/cjs/components/Icons/ArrowUpRightIcon.cjs +47 -0
  25. package/dist/cjs/components/Icons/ArrowUpRightIcon.cjs.map +1 -0
  26. package/dist/cjs/components/Icons/CheckCircleIcon.cjs +47 -0
  27. package/dist/cjs/components/Icons/CheckCircleIcon.cjs.map +1 -0
  28. package/dist/cjs/components/Icons/CheckIcon.cjs +49 -0
  29. package/dist/cjs/components/Icons/CheckIcon.cjs.map +1 -0
  30. package/dist/cjs/components/Icons/ChevronLeftIcon.cjs +49 -0
  31. package/dist/cjs/components/Icons/ChevronLeftIcon.cjs.map +1 -0
  32. package/dist/cjs/components/Icons/ChevronRightIcon.cjs +49 -0
  33. package/dist/cjs/components/Icons/ChevronRightIcon.cjs.map +1 -0
  34. package/dist/cjs/components/Icons/CloseIcon.cjs +46 -0
  35. package/dist/cjs/components/Icons/CloseIcon.cjs.map +1 -0
  36. package/dist/cjs/components/Icons/CrossIcon.cjs +40 -0
  37. package/dist/cjs/components/Icons/CrossIcon.cjs.map +1 -0
  38. package/dist/cjs/components/Icons/CrownIcon.cjs +40 -0
  39. package/dist/cjs/components/Icons/CrownIcon.cjs.map +1 -0
  40. package/dist/cjs/components/Icons/ErrorCircleIcon.cjs +47 -0
  41. package/dist/cjs/components/Icons/ErrorCircleIcon.cjs.map +1 -0
  42. package/dist/cjs/components/Icons/ErrorIcon.cjs +30 -0
  43. package/dist/cjs/components/Icons/ErrorIcon.cjs.map +1 -0
  44. package/dist/cjs/components/Icons/FireIcon.cjs +47 -0
  45. package/dist/cjs/components/Icons/FireIcon.cjs.map +1 -0
  46. package/dist/cjs/components/Icons/HomeIcon.cjs +40 -0
  47. package/dist/cjs/components/Icons/HomeIcon.cjs.map +1 -0
  48. package/dist/cjs/components/Icons/InfoCircleIcon.cjs +47 -0
  49. package/dist/cjs/components/Icons/InfoCircleIcon.cjs.map +1 -0
  50. package/dist/cjs/components/Icons/InfoIcon.cjs +30 -0
  51. package/dist/cjs/components/Icons/InfoIcon.cjs.map +1 -0
  52. package/dist/cjs/components/Icons/MicrophoneIcon.cjs +31 -0
  53. package/dist/cjs/components/Icons/MicrophoneIcon.cjs.map +1 -0
  54. package/dist/cjs/components/Icons/MinusIcon.cjs +40 -0
  55. package/dist/cjs/components/Icons/MinusIcon.cjs.map +1 -0
  56. package/dist/cjs/components/Icons/PlusIcon.cjs +40 -0
  57. package/dist/cjs/components/Icons/PlusIcon.cjs.map +1 -0
  58. package/dist/cjs/components/Icons/SpinnerIcon.cjs +43 -0
  59. package/dist/cjs/components/Icons/SpinnerIcon.cjs.map +1 -0
  60. package/dist/cjs/components/Icons/StopIcon.cjs +22 -0
  61. package/dist/cjs/components/Icons/StopIcon.cjs.map +1 -0
  62. package/dist/cjs/components/Icons/SuccessIcon.cjs +30 -0
  63. package/dist/cjs/components/Icons/SuccessIcon.cjs.map +1 -0
  64. package/dist/cjs/components/Icons/VipBadgeIcon.cjs +97 -0
  65. package/dist/cjs/components/Icons/VipBadgeIcon.cjs.map +1 -0
  66. package/dist/cjs/components/Icons/WarningIcon.cjs +30 -0
  67. package/dist/cjs/components/Icons/WarningIcon.cjs.map +1 -0
  68. package/dist/cjs/components/Icons/WarningTriangleIcon.cjs +47 -0
  69. package/dist/cjs/components/Icons/WarningTriangleIcon.cjs.map +1 -0
  70. package/dist/cjs/components/Logo/Logo.cjs +182 -0
  71. package/dist/cjs/components/Logo/Logo.cjs.map +1 -0
  72. package/dist/cjs/components/Pagination/Pagination.cjs +144 -0
  73. package/dist/cjs/components/Pagination/Pagination.cjs.map +1 -0
  74. package/dist/cjs/components/Pill/Pill.cjs +69 -0
  75. package/dist/cjs/components/Pill/Pill.cjs.map +1 -0
  76. package/dist/cjs/components/ProgressBar/ProgressBar.cjs +112 -0
  77. package/dist/cjs/components/ProgressBar/ProgressBar.cjs.map +1 -0
  78. package/dist/cjs/components/Radio/Radio.cjs +74 -0
  79. package/dist/cjs/components/Radio/Radio.cjs.map +1 -0
  80. package/dist/cjs/components/RadioGroup/RadioGroup.cjs +30 -0
  81. package/dist/cjs/components/RadioGroup/RadioGroup.cjs.map +1 -0
  82. package/dist/cjs/components/Slider/Slider.cjs +96 -0
  83. package/dist/cjs/components/Slider/Slider.cjs.map +1 -0
  84. package/dist/cjs/components/Slider/SliderLayout.cjs +31 -0
  85. package/dist/cjs/components/Slider/SliderLayout.cjs.map +1 -0
  86. package/dist/cjs/components/Slider/SliderThumb.cjs +87 -0
  87. package/dist/cjs/components/Slider/SliderThumb.cjs.map +1 -0
  88. package/dist/cjs/components/Snackbar/Snackbar.cjs +215 -0
  89. package/dist/cjs/components/Snackbar/Snackbar.cjs.map +1 -0
  90. package/dist/cjs/components/Switch/Switch.cjs +57 -0
  91. package/dist/cjs/components/Switch/Switch.cjs.map +1 -0
  92. package/dist/cjs/components/SwitchField/SwitchField.cjs +103 -0
  93. package/dist/cjs/components/SwitchField/SwitchField.cjs.map +1 -0
  94. package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs +110 -0
  95. package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs.map +1 -0
  96. package/dist/cjs/components/Tabs/Tabs.cjs +24 -0
  97. package/dist/cjs/components/Tabs/Tabs.cjs.map +1 -0
  98. package/dist/cjs/components/Tabs/TabsContent.cjs +36 -0
  99. package/dist/cjs/components/Tabs/TabsContent.cjs.map +1 -0
  100. package/dist/cjs/components/Tabs/TabsList.cjs +42 -0
  101. package/dist/cjs/components/Tabs/TabsList.cjs.map +1 -0
  102. package/dist/cjs/components/Tabs/TabsTrigger.cjs +50 -0
  103. package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -0
  104. package/dist/cjs/components/Toast/Toast.cjs +128 -0
  105. package/dist/cjs/components/Toast/Toast.cjs.map +1 -0
  106. package/dist/cjs/index.cjs +111 -0
  107. package/dist/cjs/index.cjs.map +1 -0
  108. package/dist/cjs/utils/cn.cjs +10 -0
  109. package/dist/cjs/utils/cn.cjs.map +1 -0
  110. package/dist/components/Alert/Alert.mjs +55 -0
  111. package/dist/components/Alert/Alert.mjs.map +1 -0
  112. package/dist/components/Avatar/Avatar.mjs +144 -0
  113. package/dist/components/Avatar/Avatar.mjs.map +1 -0
  114. package/dist/components/Badge/Badge.mjs +82 -0
  115. package/dist/components/Badge/Badge.mjs.map +1 -0
  116. package/dist/components/Button/Button.mjs +155 -0
  117. package/dist/components/Button/Button.mjs.map +1 -0
  118. package/dist/components/Checkbox/Checkbox.mjs +139 -0
  119. package/dist/components/Checkbox/Checkbox.mjs.map +1 -0
  120. package/dist/components/Chip/Chip.mjs +75 -0
  121. package/dist/components/Chip/Chip.mjs.map +1 -0
  122. package/dist/components/Count/Count.mjs +39 -0
  123. package/dist/components/Count/Count.mjs.map +1 -0
  124. package/dist/components/DatePicker/DatePicker.mjs +133 -0
  125. package/dist/components/DatePicker/DatePicker.mjs.map +1 -0
  126. package/dist/components/Divider/Divider.mjs +51 -0
  127. package/dist/components/Divider/Divider.mjs.map +1 -0
  128. package/dist/components/IconButton/IconButton.mjs +75 -0
  129. package/dist/components/IconButton/IconButton.mjs.map +1 -0
  130. package/dist/components/Icons/ArrowRightIcon.mjs +30 -0
  131. package/dist/components/Icons/ArrowRightIcon.mjs.map +1 -0
  132. package/dist/components/Icons/ArrowUpRightIcon.mjs +30 -0
  133. package/dist/components/Icons/ArrowUpRightIcon.mjs.map +1 -0
  134. package/dist/components/Icons/CheckCircleIcon.mjs +30 -0
  135. package/dist/components/Icons/CheckCircleIcon.mjs.map +1 -0
  136. package/dist/components/Icons/CheckIcon.mjs +32 -0
  137. package/dist/components/Icons/CheckIcon.mjs.map +1 -0
  138. package/dist/components/Icons/ChevronLeftIcon.mjs +32 -0
  139. package/dist/components/Icons/ChevronLeftIcon.mjs.map +1 -0
  140. package/dist/components/Icons/ChevronRightIcon.mjs +32 -0
  141. package/dist/components/Icons/ChevronRightIcon.mjs.map +1 -0
  142. package/dist/components/Icons/CloseIcon.mjs +29 -0
  143. package/dist/components/Icons/CloseIcon.mjs.map +1 -0
  144. package/dist/components/Icons/CrossIcon.mjs +23 -0
  145. package/dist/components/Icons/CrossIcon.mjs.map +1 -0
  146. package/dist/components/Icons/CrownIcon.mjs +23 -0
  147. package/dist/components/Icons/CrownIcon.mjs.map +1 -0
  148. package/dist/components/Icons/ErrorCircleIcon.mjs +30 -0
  149. package/dist/components/Icons/ErrorCircleIcon.mjs.map +1 -0
  150. package/dist/components/Icons/ErrorIcon.mjs +30 -0
  151. package/dist/components/Icons/ErrorIcon.mjs.map +1 -0
  152. package/dist/components/Icons/FireIcon.mjs +30 -0
  153. package/dist/components/Icons/FireIcon.mjs.map +1 -0
  154. package/dist/components/Icons/HomeIcon.mjs +23 -0
  155. package/dist/components/Icons/HomeIcon.mjs.map +1 -0
  156. package/dist/components/Icons/InfoCircleIcon.mjs +30 -0
  157. package/dist/components/Icons/InfoCircleIcon.mjs.map +1 -0
  158. package/dist/components/Icons/InfoIcon.mjs +30 -0
  159. package/dist/components/Icons/InfoIcon.mjs.map +1 -0
  160. package/dist/components/Icons/MicrophoneIcon.mjs +31 -0
  161. package/dist/components/Icons/MicrophoneIcon.mjs.map +1 -0
  162. package/dist/components/Icons/MinusIcon.mjs +23 -0
  163. package/dist/components/Icons/MinusIcon.mjs.map +1 -0
  164. package/dist/components/Icons/PlusIcon.mjs +23 -0
  165. package/dist/components/Icons/PlusIcon.mjs.map +1 -0
  166. package/dist/components/Icons/SpinnerIcon.mjs +26 -0
  167. package/dist/components/Icons/SpinnerIcon.mjs.map +1 -0
  168. package/dist/components/Icons/StopIcon.mjs +22 -0
  169. package/dist/components/Icons/StopIcon.mjs.map +1 -0
  170. package/dist/components/Icons/SuccessIcon.mjs +30 -0
  171. package/dist/components/Icons/SuccessIcon.mjs.map +1 -0
  172. package/dist/components/Icons/VipBadgeIcon.mjs +80 -0
  173. package/dist/components/Icons/VipBadgeIcon.mjs.map +1 -0
  174. package/dist/components/Icons/WarningIcon.mjs +30 -0
  175. package/dist/components/Icons/WarningIcon.mjs.map +1 -0
  176. package/dist/components/Icons/WarningTriangleIcon.mjs +30 -0
  177. package/dist/components/Icons/WarningTriangleIcon.mjs.map +1 -0
  178. package/dist/components/Logo/Logo.mjs +165 -0
  179. package/dist/components/Logo/Logo.mjs.map +1 -0
  180. package/dist/components/Pagination/Pagination.mjs +127 -0
  181. package/dist/components/Pagination/Pagination.mjs.map +1 -0
  182. package/dist/components/Pill/Pill.mjs +52 -0
  183. package/dist/components/Pill/Pill.mjs.map +1 -0
  184. package/dist/components/ProgressBar/ProgressBar.mjs +95 -0
  185. package/dist/components/ProgressBar/ProgressBar.mjs.map +1 -0
  186. package/dist/components/Radio/Radio.mjs +56 -0
  187. package/dist/components/Radio/Radio.mjs.map +1 -0
  188. package/dist/components/RadioGroup/RadioGroup.mjs +12 -0
  189. package/dist/components/RadioGroup/RadioGroup.mjs.map +1 -0
  190. package/dist/components/Slider/Slider.mjs +78 -0
  191. package/dist/components/Slider/Slider.mjs.map +1 -0
  192. package/dist/components/Slider/SliderLayout.mjs +31 -0
  193. package/dist/components/Slider/SliderLayout.mjs.map +1 -0
  194. package/dist/components/Slider/SliderThumb.mjs +69 -0
  195. package/dist/components/Slider/SliderThumb.mjs.map +1 -0
  196. package/dist/components/Snackbar/Snackbar.mjs +198 -0
  197. package/dist/components/Snackbar/Snackbar.mjs.map +1 -0
  198. package/dist/components/Switch/Switch.mjs +39 -0
  199. package/dist/components/Switch/Switch.mjs.map +1 -0
  200. package/dist/components/SwitchField/SwitchField.mjs +86 -0
  201. package/dist/components/SwitchField/SwitchField.mjs.map +1 -0
  202. package/dist/components/SwitchToggle/SwitchToggle.mjs +93 -0
  203. package/dist/components/SwitchToggle/SwitchToggle.mjs.map +1 -0
  204. package/dist/components/Tabs/Tabs.mjs +7 -0
  205. package/dist/components/Tabs/Tabs.mjs.map +1 -0
  206. package/dist/components/Tabs/TabsContent.mjs +18 -0
  207. package/dist/components/Tabs/TabsContent.mjs.map +1 -0
  208. package/dist/components/Tabs/TabsList.mjs +24 -0
  209. package/dist/components/Tabs/TabsList.mjs.map +1 -0
  210. package/dist/components/Tabs/TabsTrigger.mjs +32 -0
  211. package/dist/components/Tabs/TabsTrigger.mjs.map +1 -0
  212. package/dist/components/Toast/Toast.mjs +110 -0
  213. package/dist/components/Toast/Toast.mjs.map +1 -0
  214. package/dist/index.d.ts +30 -0
  215. package/dist/index.mjs +107 -10507
  216. package/dist/index.mjs.map +1 -1
  217. package/dist/utils/cn.mjs +10 -0
  218. package/dist/utils/cn.mjs.map +1 -0
  219. package/package.json +10 -4
  220. package/dist/index.cjs +0 -2
  221. package/dist/index.cjs.map +0 -1
@@ -0,0 +1,52 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { Slot, Slottable } from "@radix-ui/react-slot";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ const pillVariants = {
7
+ variant: {
8
+ green: "bg-success-50 text-success-500",
9
+ grey: "bg-neutral-100 text-body-200",
10
+ blue: "bg-info-50 text-info-500",
11
+ gold: "bg-warning-50 text-warning-500",
12
+ pinkLight: "bg-brand-pink-50 text-body-100",
13
+ base: "bg-neutral-400 text-body-300",
14
+ brand: "bg-brand-green-500 text-body-black-solid-constant",
15
+ brandLight: "bg-brand-green-50 text-body-black-solid-constant",
16
+ beta: "bg-brand-pink-500 text-body-black-solid-constant",
17
+ error: "bg-error-500 text-error-50"
18
+ }
19
+ };
20
+ const Pill = React.forwardRef(
21
+ ({ className, variant = "green", leftIcon, rightIcon, asChild = false, children, ...props }, ref) => {
22
+ const Comp = asChild ? Slot : "span";
23
+ return /* @__PURE__ */ jsxs(
24
+ Comp,
25
+ {
26
+ ref,
27
+ "data-testid": "pill",
28
+ className: cn(
29
+ // Base styles
30
+ "inline-flex items-center justify-center gap-2 rounded-full px-3 py-1",
31
+ // Typography
32
+ "typography-caption-semibold",
33
+ // Variant styles
34
+ pillVariants.variant[variant],
35
+ // Manual CSS overrides
36
+ className
37
+ ),
38
+ ...props,
39
+ children: [
40
+ leftIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: leftIcon }),
41
+ /* @__PURE__ */ jsx(Slottable, { children }),
42
+ rightIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: rightIcon })
43
+ ]
44
+ }
45
+ );
46
+ }
47
+ );
48
+ Pill.displayName = "Pill";
49
+ export {
50
+ Pill
51
+ };
52
+ //# sourceMappingURL=Pill.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Pill.mjs","sources":["../../../src/components/Pill/Pill.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst pillVariants = {\n variant: {\n green: \"bg-success-50 text-success-500\",\n grey: \"bg-neutral-100 text-body-200\",\n blue: \"bg-info-50 text-info-500\",\n gold: \"bg-warning-50 text-warning-500\",\n pinkLight: \"bg-brand-pink-50 text-body-100\",\n base: \"bg-neutral-400 text-body-300\",\n brand: \"bg-brand-green-500 text-body-black-solid-constant\",\n brandLight: \"bg-brand-green-50 text-body-black-solid-constant\",\n beta: \"bg-brand-pink-500 text-body-black-solid-constant\",\n error: \"bg-error-500 text-error-50\",\n },\n} as const;\n\nexport type PillVariant = keyof typeof pillVariants.variant;\n\nexport interface PillProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual style variant of the pill */\n variant?: PillVariant;\n /** Left icon element */\n leftIcon?: React.ReactNode;\n /** Right icon element */\n rightIcon?: React.ReactNode;\n /** Render as a different element using Radix Slot */\n asChild?: boolean;\n}\n\nexport const Pill = React.forwardRef<HTMLSpanElement, PillProps>(\n (\n { className, variant = \"green\", leftIcon, rightIcon, asChild = false, children, ...props },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"pill\"\n className={cn(\n // Base styles\n \"inline-flex items-center justify-center gap-2 rounded-full px-3 py-1\",\n // Typography\n \"typography-caption-semibold\",\n // Variant styles\n pillVariants.variant[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n {leftIcon && (\n <span className=\"flex\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nPill.displayName = \"Pill\";\n"],"names":[],"mappings":";;;;;AAIA,MAAM,eAAe;AAAA,EACnB,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAEX;AAeO,MAAM,OAAO,MAAM;AAAA,EACxB,CACE,EAAE,WAAW,UAAU,SAAS,UAAU,WAAW,UAAU,OAAO,UAAU,GAAG,MAAA,GACnF,QACG;AACH,UAAM,OAAO,UAAU,OAAO;AAE9B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA;AAAA,UAET;AAAA;AAAA,UAEA;AAAA;AAAA,UAEA,aAAa,QAAQ,OAAO;AAAA;AAAA,UAE5B;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,gCACE,QAAA,EAAK,WAAU,QAAO,eAAY,QAChC,UAAA,UACH;AAAA,UAEF,oBAAC,aAAW,UAAS;AAAA,UACpB,aACC,oBAAC,QAAA,EAAK,WAAU,QAAO,eAAY,QAChC,UAAA,UAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../../utils/cn.mjs";
5
+ const TRACK_HEIGHT = {
6
+ default: "h-3",
7
+ small: "h-1.5"
8
+ };
9
+ const GAP = {
10
+ default: "gap-3",
11
+ small: "gap-1"
12
+ };
13
+ function getDefaultBarColor(value) {
14
+ if (value >= 100) return "bg-success-500";
15
+ if (value >= 40) return "bg-warning-500";
16
+ return "bg-error-500";
17
+ }
18
+ function getDefaultTextColor(value) {
19
+ if (value >= 100) return "text-success-500";
20
+ if (value >= 40) return "text-warning-500";
21
+ return "text-error-500";
22
+ }
23
+ const ProgressBar = React.forwardRef(
24
+ ({
25
+ value,
26
+ size = "default",
27
+ variant = "default",
28
+ title,
29
+ showCompletion = false,
30
+ stepsLabel,
31
+ helperLeft,
32
+ helperRight,
33
+ leftIcon,
34
+ ariaLabel,
35
+ className,
36
+ ...props
37
+ }, ref) => {
38
+ const clampedValue = Math.min(100, Math.max(0, value));
39
+ const isGeneric = variant === "generic";
40
+ const isSmall = size === "small";
41
+ const barColor = isGeneric ? "bg-brand-green-500" : getDefaultBarColor(clampedValue);
42
+ const textColor = isGeneric ? "text-brand-green-500" : getDefaultTextColor(clampedValue);
43
+ const showHeader = title != null || showCompletion || stepsLabel != null;
44
+ const showFooter = leftIcon != null || helperLeft != null || helperRight != null;
45
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex w-full flex-col", GAP[size], className), ...props, children: [
46
+ showHeader && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-end justify-between", children: [
47
+ title != null && /* @__PURE__ */ jsx("p", { className: "typography-caption-semibold text-body-100", children: title }),
48
+ showCompletion && /* @__PURE__ */ jsxs(
49
+ "span",
50
+ {
51
+ className: cn(textColor, isSmall ? "typography-heading-3" : "typography-heading-1"),
52
+ children: [
53
+ Math.round(clampedValue),
54
+ "%"
55
+ ]
56
+ }
57
+ ),
58
+ stepsLabel != null && /* @__PURE__ */ jsx("span", { className: "typography-caption-regular text-body-100", children: stepsLabel })
59
+ ] }),
60
+ /* @__PURE__ */ jsx(
61
+ "div",
62
+ {
63
+ role: "progressbar",
64
+ "aria-label": ariaLabel ?? "Progress",
65
+ "aria-valuenow": clampedValue,
66
+ "aria-valuemin": 0,
67
+ "aria-valuemax": 100,
68
+ className: cn("relative w-full rounded-full bg-neutral-100", TRACK_HEIGHT[size]),
69
+ children: /* @__PURE__ */ jsx(
70
+ "div",
71
+ {
72
+ className: cn(
73
+ "absolute inset-y-0 left-0 rounded-full transition-[width] duration-300 ease-in-out",
74
+ barColor
75
+ ),
76
+ style: { width: `${clampedValue}%` }
77
+ }
78
+ )
79
+ }
80
+ ),
81
+ showFooter && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between", children: [
82
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
83
+ leftIcon != null && /* @__PURE__ */ jsx("span", { className: "flex size-5 items-center justify-center", "aria-hidden": "true", children: leftIcon }),
84
+ helperLeft != null && /* @__PURE__ */ jsx("span", { className: "typography-caption-regular text-primary-500", children: helperLeft })
85
+ ] }),
86
+ helperRight != null && /* @__PURE__ */ jsx("span", { className: "typography-caption-regular text-primary-500", children: helperRight })
87
+ ] })
88
+ ] });
89
+ }
90
+ );
91
+ ProgressBar.displayName = "ProgressBar";
92
+ export {
93
+ ProgressBar
94
+ };
95
+ //# sourceMappingURL=ProgressBar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBar.mjs","sources":["../../../src/components/ProgressBar/ProgressBar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\n\nexport type ProgressBarSize = \"default\" | \"small\";\nexport type ProgressBarVariant = \"default\" | \"generic\";\n\nexport interface ProgressBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Current progress value (0-100) */\n value: number;\n /** Size variant - \"default\" (12px track) or \"small\" (6px track) */\n size?: ProgressBarSize;\n /** Color variant - \"default\" uses color-coded progress, \"generic\" always green */\n variant?: ProgressBarVariant;\n /** Title content shown at top left */\n title?: React.ReactNode;\n /** Show the completion percentage at top */\n showCompletion?: boolean;\n /** Steps label shown at top right (e.g. \"2/8 steps\") */\n stepsLabel?: React.ReactNode;\n /** Helper content at bottom left */\n helperLeft?: React.ReactNode;\n /** Helper content at bottom right */\n helperRight?: React.ReactNode;\n /** Icon shown at bottom left before helper text */\n leftIcon?: React.ReactNode;\n /** Accessible label for the progress bar (defaults to \"Progress\"). Use this for i18n. */\n ariaLabel?: string;\n}\n\nconst TRACK_HEIGHT: Record<ProgressBarSize, string> = {\n default: \"h-3\",\n small: \"h-1.5\",\n};\n\nconst GAP: Record<ProgressBarSize, string> = {\n default: \"gap-3\",\n small: \"gap-1\",\n};\n\nfunction getDefaultBarColor(value: number): string {\n if (value >= 100) return \"bg-success-500\";\n if (value >= 40) return \"bg-warning-500\";\n return \"bg-error-500\";\n}\n\nfunction getDefaultTextColor(value: number): string {\n if (value >= 100) return \"text-success-500\";\n if (value >= 40) return \"text-warning-500\";\n return \"text-error-500\";\n}\n\nexport const ProgressBar = React.forwardRef<HTMLDivElement, ProgressBarProps>(\n (\n {\n value,\n size = \"default\",\n variant = \"default\",\n title,\n showCompletion = false,\n stepsLabel,\n helperLeft,\n helperRight,\n leftIcon,\n ariaLabel,\n className,\n ...props\n },\n ref,\n ) => {\n const clampedValue = Math.min(100, Math.max(0, value));\n const isGeneric = variant === \"generic\";\n const isSmall = size === \"small\";\n\n const barColor = isGeneric ? \"bg-brand-green-500\" : getDefaultBarColor(clampedValue);\n const textColor = isGeneric ? \"text-brand-green-500\" : getDefaultTextColor(clampedValue);\n\n const showHeader = title != null || showCompletion || stepsLabel != null;\n const showFooter = leftIcon != null || helperLeft != null || helperRight != null;\n\n return (\n <div ref={ref} className={cn(\"flex w-full flex-col\", GAP[size], className)} {...props}>\n {showHeader && (\n <div className=\"flex w-full items-end justify-between\">\n {title != null && <p className=\"typography-caption-semibold text-body-100\">{title}</p>}\n {showCompletion && (\n <span\n className={cn(textColor, isSmall ? \"typography-heading-3\" : \"typography-heading-1\")}\n >\n {Math.round(clampedValue)}%\n </span>\n )}\n {stepsLabel != null && (\n <span className=\"typography-caption-regular text-body-100\">{stepsLabel}</span>\n )}\n </div>\n )}\n\n <div\n role=\"progressbar\"\n aria-label={ariaLabel ?? \"Progress\"}\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={100}\n className={cn(\"relative w-full rounded-full bg-neutral-100\", TRACK_HEIGHT[size])}\n >\n <div\n className={cn(\n \"absolute inset-y-0 left-0 rounded-full transition-[width] duration-300 ease-in-out\",\n barColor,\n )}\n style={{ width: `${clampedValue}%` }}\n />\n </div>\n\n {showFooter && (\n <div className=\"flex w-full items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n {leftIcon != null && (\n <span className=\"flex size-5 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n {helperLeft != null && (\n <span className=\"typography-caption-regular text-primary-500\">{helperLeft}</span>\n )}\n </div>\n {helperRight != null && (\n <span className=\"typography-caption-regular text-primary-500\">{helperRight}</span>\n )}\n </div>\n )}\n </div>\n );\n },\n);\n\nProgressBar.displayName = \"ProgressBar\";\n"],"names":[],"mappings":";;;;AA6BA,MAAM,eAAgD;AAAA,EACpD,SAAS;AAAA,EACT,OAAO;AACT;AAEA,MAAM,MAAuC;AAAA,EAC3C,SAAS;AAAA,EACT,OAAO;AACT;AAEA,SAAS,mBAAmB,OAAuB;AACjD,MAAI,SAAS,IAAK,QAAO;AACzB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO;AACT;AAEA,SAAS,oBAAoB,OAAuB;AAClD,MAAI,SAAS,IAAK,QAAO;AACzB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO;AACT;AAEO,MAAM,cAAc,MAAM;AAAA,EAC/B,CACE;AAAA,IACE;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,eAAe,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC;AACrD,UAAM,YAAY,YAAY;AAC9B,UAAM,UAAU,SAAS;AAEzB,UAAM,WAAW,YAAY,uBAAuB,mBAAmB,YAAY;AACnF,UAAM,YAAY,YAAY,yBAAyB,oBAAoB,YAAY;AAEvF,UAAM,aAAa,SAAS,QAAQ,kBAAkB,cAAc;AACpE,UAAM,aAAa,YAAY,QAAQ,cAAc,QAAQ,eAAe;AAE5E,WACE,qBAAC,OAAA,EAAI,KAAU,WAAW,GAAG,wBAAwB,IAAI,IAAI,GAAG,SAAS,GAAI,GAAG,OAC7E,UAAA;AAAA,MAAA,cACC,qBAAC,OAAA,EAAI,WAAU,yCACZ,UAAA;AAAA,QAAA,SAAS,QAAQ,oBAAC,KAAA,EAAE,WAAU,6CAA6C,UAAA,OAAM;AAAA,QACjF,kBACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,GAAG,WAAW,UAAU,yBAAyB,sBAAsB;AAAA,YAEjF,UAAA;AAAA,cAAA,KAAK,MAAM,YAAY;AAAA,cAAE;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAG7B,cAAc,QACb,oBAAC,QAAA,EAAK,WAAU,4CAA4C,UAAA,WAAA,CAAW;AAAA,MAAA,GAE3E;AAAA,MAGF;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAY,aAAa;AAAA,UACzB,iBAAe;AAAA,UACf,iBAAe;AAAA,UACf,iBAAe;AAAA,UACf,WAAW,GAAG,+CAA+C,aAAa,IAAI,CAAC;AAAA,UAE/E,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,cAAA;AAAA,cAEF,OAAO,EAAE,OAAO,GAAG,YAAY,IAAA;AAAA,YAAI;AAAA,UAAA;AAAA,QACrC;AAAA,MAAA;AAAA,MAGD,cACC,qBAAC,OAAA,EAAI,WAAU,4CACb,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,UAAA,YAAY,QACX,oBAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QACnE,UAAA,SAAA,CACH;AAAA,UAED,cAAc,QACb,oBAAC,QAAA,EAAK,WAAU,+CAA+C,UAAA,WAAA,CAAW;AAAA,QAAA,GAE9E;AAAA,QACC,eAAe,QACd,oBAAC,QAAA,EAAK,WAAU,+CAA+C,UAAA,YAAA,CAAY;AAAA,MAAA,EAAA,CAE/E;AAAA,IAAA,GAEJ;AAAA,EAEJ;AACF;AAEA,YAAY,cAAc;"}
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ const Radio = React.forwardRef(({ className, size = "default", label, helperText, id, ...props }, ref) => {
7
+ const generatedId = React.useId();
8
+ const inputId = id || generatedId;
9
+ const helperTextId = `${inputId}-helper`;
10
+ return /* @__PURE__ */ jsxs("div", { className: cn("group inline-flex items-center gap-2", className), children: [
11
+ /* @__PURE__ */ jsx(
12
+ RadioGroupPrimitive.Item,
13
+ {
14
+ ref,
15
+ id: inputId,
16
+ "data-testid": "radio",
17
+ "aria-describedby": helperText ? helperTextId : void 0,
18
+ className: cn(
19
+ "relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-body-100 bg-transparent outline-brand-purple-500 transition-colors hover:bg-brand-green-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:border-disabled-400 disabled:bg-transparent data-[state=checked]:border-body-100 data-[state=checked]:bg-transparent dark:border-body-100 dark:disabled:border-disabled-400",
20
+ helperText && "mt-1 self-start"
21
+ ),
22
+ ...props,
23
+ children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-body-100 group-has-disabled:bg-disabled-400 dark:bg-body-100 dark:group-has-disabled:bg-disabled-400" }) })
24
+ }
25
+ ),
26
+ (label || helperText) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
27
+ label && /* @__PURE__ */ jsx(
28
+ "label",
29
+ {
30
+ htmlFor: inputId,
31
+ className: cn(
32
+ "cursor-pointer select-none text-body-100 group-has-disabled:cursor-not-allowed group-has-disabled:text-disabled-100",
33
+ size === "small" ? "typography-body-2-semibold" : "typography-body-1-semibold"
34
+ ),
35
+ children: label
36
+ }
37
+ ),
38
+ helperText && /* @__PURE__ */ jsx(
39
+ "span",
40
+ {
41
+ id: helperTextId,
42
+ className: cn(
43
+ "text-body-200 group-has-disabled:cursor-not-allowed group-has-disabled:text-disabled-100",
44
+ size === "small" ? "typography-body-2-semibold" : "typography-caption-regular"
45
+ ),
46
+ children: helperText
47
+ }
48
+ )
49
+ ] })
50
+ ] });
51
+ });
52
+ Radio.displayName = "Radio";
53
+ export {
54
+ Radio
55
+ };
56
+ //# sourceMappingURL=Radio.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Radio.mjs","sources":["../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface RadioProps\n extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, \"asChild\"> {\n /** Size variant of the radio button */\n size?: \"default\" | \"small\";\n /** Label text for the radio button */\n label?: string;\n /** Optional helper text displayed below the label */\n helperText?: string;\n}\n\nexport const Radio = React.forwardRef<\n React.ComponentRef<typeof RadioGroupPrimitive.Item>,\n RadioProps\n>(({ className, size = \"default\", label, helperText, id, ...props }, ref) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n\n return (\n <div className={cn(\"group inline-flex items-center gap-2\", className)}>\n <RadioGroupPrimitive.Item\n ref={ref}\n id={inputId}\n data-testid=\"radio\"\n aria-describedby={helperText ? helperTextId : undefined}\n className={cn(\n \"relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-body-100 bg-transparent outline-brand-purple-500 transition-colors hover:bg-brand-green-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:border-disabled-400 disabled:bg-transparent data-[state=checked]:border-body-100 data-[state=checked]:bg-transparent dark:border-body-100 dark:disabled:border-disabled-400\",\n helperText && \"mt-1 self-start\",\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"size-2 rounded-full bg-body-100 group-has-disabled:bg-disabled-400 dark:bg-body-100 dark:group-has-disabled:bg-disabled-400\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n {(label || helperText) && (\n <div className=\"flex flex-col gap-0.5\">\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n \"cursor-pointer select-none text-body-100 group-has-disabled:cursor-not-allowed group-has-disabled:text-disabled-100\",\n size === \"small\" ? \"typography-body-2-semibold\" : \"typography-body-1-semibold\",\n )}\n >\n {label}\n </label>\n )}\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"text-body-200 group-has-disabled:cursor-not-allowed group-has-disabled:text-disabled-100\",\n size === \"small\" ? \"typography-body-2-semibold\" : \"typography-caption-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n )}\n </div>\n );\n});\n\nRadio.displayName = \"Radio\";\n"],"names":[],"mappings":";;;;;AAcO,MAAM,QAAQ,MAAM,WAGzB,CAAC,EAAE,WAAW,OAAO,WAAW,OAAO,YAAY,IAAI,GAAG,MAAA,GAAS,QAAQ;AAC3E,QAAM,cAAc,MAAM,MAAA;AAC1B,QAAM,UAAU,MAAM;AACtB,QAAM,eAAe,GAAG,OAAO;AAE/B,8BACG,OAAA,EAAI,WAAW,GAAG,wCAAwC,SAAS,GAClE,UAAA;AAAA,IAAA;AAAA,MAAC,oBAAoB;AAAA,MAApB;AAAA,QACC;AAAA,QACA,IAAI;AAAA,QACJ,eAAY;AAAA,QACZ,oBAAkB,aAAa,eAAe;AAAA,QAC9C,WAAW;AAAA,UACT;AAAA,UACA,cAAc;AAAA,QAAA;AAAA,QAEf,GAAG;AAAA,QAEJ,UAAA,oBAAC,oBAAoB,WAApB,EAA8B,WAAU,qDACvC,UAAA,oBAAC,QAAA,EAAK,WAAU,8HAAA,CAA8H,EAAA,CAChJ;AAAA,MAAA;AAAA,IAAA;AAAA,KAEA,SAAS,eACT,qBAAC,OAAA,EAAI,WAAU,yBACZ,UAAA;AAAA,MAAA,SACC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAW;AAAA,YACT;AAAA,YACA,SAAS,UAAU,+BAA+B;AAAA,UAAA;AAAA,UAGnD,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGJ,cACC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,WAAW;AAAA,YACT;AAAA,YACA,SAAS,UAAU,+BAA+B;AAAA,UAAA;AAAA,UAGnD,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,EAAA,CAEJ;AAAA,EAAA,GAEJ;AAEJ,CAAC;AAED,MAAM,cAAc;"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
4
+ import * as React from "react";
5
+ const RadioGroup = React.forwardRef((props, ref) => {
6
+ return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { ref, ...props });
7
+ });
8
+ RadioGroup.displayName = "RadioGroup";
9
+ export {
10
+ RadioGroup
11
+ };
12
+ //# sourceMappingURL=RadioGroup.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.mjs","sources":["../../../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport * as React from \"react\";\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>;\n\nexport const RadioGroup = React.forwardRef<\n React.ComponentRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>((props, ref) => {\n return <RadioGroupPrimitive.Root ref={ref} {...props} />;\n});\n\nRadioGroup.displayName = \"RadioGroup\";\n"],"names":[],"mappings":";;;;AAKO,MAAM,aAAa,MAAM,WAG9B,CAAC,OAAO,QAAQ;AAChB,6BAAQ,oBAAoB,MAApB,EAAyB,KAAW,GAAG,OAAO;AACxD,CAAC;AAED,WAAW,cAAc;"}
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as SliderPrimitive from "@radix-ui/react-slider";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ import { SliderLayout } from "./SliderLayout.mjs";
7
+ import { SliderThumb } from "./SliderThumb.mjs";
8
+ const Slider = React.forwardRef(
9
+ ({
10
+ className,
11
+ label,
12
+ labelPosition = "top",
13
+ minLabel,
14
+ maxLabel,
15
+ showTooltip = false,
16
+ formatTooltip,
17
+ disabled,
18
+ value,
19
+ defaultValue,
20
+ "aria-label": ariaLabel,
21
+ "aria-labelledby": ariaLabelledBy,
22
+ ...props
23
+ }, ref) => {
24
+ const labelId = React.useId();
25
+ const thumbCount = value?.length ?? defaultValue?.length ?? 1;
26
+ const resolvedLabelledBy = ariaLabelledBy ?? (label ? labelId : void 0);
27
+ const resolvedAriaLabel = !resolvedLabelledBy ? ariaLabel : void 0;
28
+ const sliderTrack = /* @__PURE__ */ jsxs(
29
+ SliderPrimitive.Root,
30
+ {
31
+ ref,
32
+ disabled,
33
+ value,
34
+ defaultValue,
35
+ "aria-label": resolvedAriaLabel,
36
+ "aria-labelledby": resolvedLabelledBy,
37
+ className: cn(
38
+ "group/slider relative flex w-full touch-none select-none items-center",
39
+ disabled && "pointer-events-none opacity-50",
40
+ className
41
+ ),
42
+ ...props,
43
+ children: [
44
+ /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-3 w-full overflow-hidden rounded-full border border-neutral-100 bg-neutral-100", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full rounded-full bg-brand-green-500" }) }),
45
+ Array.from({ length: thumbCount }, (_, i) => /* @__PURE__ */ jsx(
46
+ SliderThumb,
47
+ {
48
+ showTooltip,
49
+ formatTooltip,
50
+ index: i,
51
+ "aria-label": resolvedAriaLabel,
52
+ "aria-labelledby": resolvedLabelledBy
53
+ },
54
+ i
55
+ ))
56
+ ]
57
+ }
58
+ );
59
+ const hasLayout = Boolean(label || minLabel || maxLabel);
60
+ if (!hasLayout) return sliderTrack;
61
+ return /* @__PURE__ */ jsx(
62
+ SliderLayout,
63
+ {
64
+ label,
65
+ labelId,
66
+ labelPosition,
67
+ minLabel,
68
+ maxLabel,
69
+ children: sliderTrack
70
+ }
71
+ );
72
+ }
73
+ );
74
+ Slider.displayName = "Slider";
75
+ export {
76
+ Slider
77
+ };
78
+ //# sourceMappingURL=Slider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.mjs","sources":["../../../src/components/Slider/Slider.tsx"],"sourcesContent":["import * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { SliderLayout } from \"./SliderLayout\";\nimport { SliderThumb } from \"./SliderThumb\";\n\nexport type SliderLabelPosition = \"top\" | \"left\";\n\nexport interface SliderProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n \"asChild\" | \"children\"\n > {\n /** Label text displayed alongside the slider */\n label?: string;\n /** Position of the label relative to the slider track */\n labelPosition?: SliderLabelPosition;\n /** Text shown at the minimum end of the track */\n minLabel?: string;\n /** Text shown at the maximum end of the track */\n maxLabel?: string;\n /** Whether to show a tooltip with the current value above the thumb */\n showTooltip?: boolean;\n /** Override the displayed tooltip value (e.g. for formatting) */\n formatTooltip?: (value: number) => string;\n}\n\nexport const Slider = React.forwardRef<\n React.ComponentRef<typeof SliderPrimitive.Root>,\n SliderProps\n>(\n (\n {\n className,\n label,\n labelPosition = \"top\",\n minLabel,\n maxLabel,\n showTooltip = false,\n formatTooltip,\n disabled,\n value,\n defaultValue,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...props\n },\n ref,\n ) => {\n const labelId = React.useId();\n const thumbCount = value?.length ?? defaultValue?.length ?? 1;\n const resolvedLabelledBy = ariaLabelledBy ?? (label ? labelId : undefined);\n const resolvedAriaLabel = !resolvedLabelledBy ? ariaLabel : undefined;\n\n const sliderTrack = (\n <SliderPrimitive.Root\n ref={ref}\n disabled={disabled}\n value={value}\n defaultValue={defaultValue}\n aria-label={resolvedAriaLabel}\n aria-labelledby={resolvedLabelledBy}\n className={cn(\n \"group/slider relative flex w-full touch-none select-none items-center\",\n disabled && \"pointer-events-none opacity-50\",\n className,\n )}\n {...props}\n >\n <SliderPrimitive.Track className=\"relative h-3 w-full overflow-hidden rounded-full border border-neutral-100 bg-neutral-100\">\n <SliderPrimitive.Range className=\"absolute h-full rounded-full bg-brand-green-500\" />\n </SliderPrimitive.Track>\n\n {Array.from({ length: thumbCount }, (_, i) => (\n <SliderThumb\n // biome-ignore lint/suspicious/noArrayIndexKey: thumbs are fixed-count and never reorder\n key={i}\n showTooltip={showTooltip}\n formatTooltip={formatTooltip}\n index={i}\n aria-label={resolvedAriaLabel}\n aria-labelledby={resolvedLabelledBy}\n />\n ))}\n </SliderPrimitive.Root>\n );\n\n const hasLayout = Boolean(label || minLabel || maxLabel);\n\n if (!hasLayout) return sliderTrack;\n\n return (\n <SliderLayout\n label={label}\n labelId={labelId}\n labelPosition={labelPosition}\n minLabel={minLabel}\n maxLabel={maxLabel}\n >\n {sliderTrack}\n </SliderLayout>\n );\n },\n);\n\nSlider.displayName = \"Slider\";\n"],"names":[],"mappings":";;;;;;;AA2BO,MAAM,SAAS,MAAM;AAAA,EAI1B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,UAAU,MAAM,MAAA;AACtB,UAAM,aAAa,OAAO,UAAU,cAAc,UAAU;AAC5D,UAAM,qBAAqB,mBAAmB,QAAQ,UAAU;AAChE,UAAM,oBAAoB,CAAC,qBAAqB,YAAY;AAE5D,UAAM,cACJ;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAY;AAAA,QACZ,mBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA,oBAAC,gBAAgB,OAAhB,EAAsB,WAAU,6FAC/B,UAAA,oBAAC,gBAAgB,OAAhB,EAAsB,WAAU,kDAAA,CAAkD,EAAA,CACrF;AAAA,UAEC,MAAM,KAAK,EAAE,QAAQ,cAAc,CAAC,GAAG,MACtC;AAAA,YAAC;AAAA,YAAA;AAAA,cAGC;AAAA,cACA;AAAA,cACA,OAAO;AAAA,cACP,cAAY;AAAA,cACZ,mBAAiB;AAAA,YAAA;AAAA,YALZ;AAAA,UAAA,CAOR;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAIL,UAAM,YAAY,QAAQ,SAAS,YAAY,QAAQ;AAEvD,QAAI,CAAC,UAAW,QAAO;AAEvB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QAEC,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,OAAO,cAAc;"}
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ function SliderLayout({
4
+ label,
5
+ labelId,
6
+ labelPosition,
7
+ minLabel,
8
+ maxLabel,
9
+ children
10
+ }) {
11
+ if (labelPosition === "left") {
12
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
13
+ label && /* @__PURE__ */ jsx("span", { id: labelId, className: "typography-body-1-semibold shrink-0 text-body-100", children: label }),
14
+ minLabel && /* @__PURE__ */ jsx("span", { className: "typography-body-2-regular shrink-0 text-body-200", children: minLabel }),
15
+ children,
16
+ maxLabel && /* @__PURE__ */ jsx("span", { className: "typography-body-2-regular shrink-0 text-body-200", children: maxLabel })
17
+ ] });
18
+ }
19
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-3", children: [
20
+ label && /* @__PURE__ */ jsx("span", { id: labelId, className: "typography-body-1-semibold text-body-100", children: label }),
21
+ (minLabel || maxLabel) && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-start justify-between text-body-200 text-sm leading-[18px]", children: [
22
+ minLabel && /* @__PURE__ */ jsx("span", { children: minLabel }),
23
+ maxLabel && /* @__PURE__ */ jsx("span", { className: "ml-auto", children: maxLabel })
24
+ ] }),
25
+ children
26
+ ] });
27
+ }
28
+ export {
29
+ SliderLayout
30
+ };
31
+ //# sourceMappingURL=SliderLayout.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderLayout.mjs","sources":["../../../src/components/Slider/SliderLayout.tsx"],"sourcesContent":["import type * as React from \"react\";\nimport type { SliderLabelPosition } from \"./Slider\";\n\ninterface SliderLayoutProps {\n label?: string;\n labelId: string;\n labelPosition: SliderLabelPosition;\n minLabel?: string;\n maxLabel?: string;\n children: React.ReactNode;\n}\n\nexport function SliderLayout({\n label,\n labelId,\n labelPosition,\n minLabel,\n maxLabel,\n children,\n}: SliderLayoutProps) {\n if (labelPosition === \"left\") {\n return (\n <div className=\"flex items-center gap-3\">\n {label && (\n <span id={labelId} className=\"typography-body-1-semibold shrink-0 text-body-100\">\n {label}\n </span>\n )}\n {minLabel && (\n <span className=\"typography-body-2-regular shrink-0 text-body-200\">{minLabel}</span>\n )}\n {children}\n {maxLabel && (\n <span className=\"typography-body-2-regular shrink-0 text-body-200\">{maxLabel}</span>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"flex w-full flex-col gap-3\">\n {label && (\n <span id={labelId} className=\"typography-body-1-semibold text-body-100\">\n {label}\n </span>\n )}\n {(minLabel || maxLabel) && (\n <div className=\"flex w-full items-start justify-between text-body-200 text-sm leading-[18px]\">\n {minLabel && <span>{minLabel}</span>}\n {maxLabel && <span className=\"ml-auto\">{maxLabel}</span>}\n </div>\n )}\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;AAYO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,MAAI,kBAAkB,QAAQ;AAC5B,WACE,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,MAAA,6BACE,QAAA,EAAK,IAAI,SAAS,WAAU,qDAC1B,UAAA,OACH;AAAA,MAED,YACC,oBAAC,QAAA,EAAK,WAAU,oDAAoD,UAAA,UAAS;AAAA,MAE9E;AAAA,MACA,YACC,oBAAC,QAAA,EAAK,WAAU,oDAAoD,UAAA,SAAA,CAAS;AAAA,IAAA,GAEjF;AAAA,EAEJ;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,8BACZ,UAAA;AAAA,IAAA,6BACE,QAAA,EAAK,IAAI,SAAS,WAAU,4CAC1B,UAAA,OACH;AAAA,KAEA,YAAY,aACZ,qBAAC,OAAA,EAAI,WAAU,gFACZ,UAAA;AAAA,MAAA,YAAY,oBAAC,UAAM,UAAA,SAAA,CAAS;AAAA,MAC5B,YAAY,oBAAC,QAAA,EAAK,WAAU,WAAW,UAAA,SAAA,CAAS;AAAA,IAAA,GACnD;AAAA,IAED;AAAA,EAAA,GACH;AAEJ;"}
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as SliderPrimitive from "@radix-ui/react-slider";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ function SliderThumb({
7
+ showTooltip,
8
+ formatTooltip,
9
+ index,
10
+ "aria-label": ariaLabel,
11
+ "aria-labelledby": ariaLabelledBy
12
+ }) {
13
+ const thumbRef = React.useCallback(
14
+ (el) => {
15
+ if (!el || !showTooltip) return;
16
+ syncTooltipText(el, formatTooltip);
17
+ },
18
+ [showTooltip, formatTooltip]
19
+ );
20
+ return /* @__PURE__ */ jsxs(
21
+ SliderPrimitive.Thumb,
22
+ {
23
+ ref: thumbRef,
24
+ "data-index": index,
25
+ "aria-label": ariaLabel,
26
+ "aria-labelledby": ariaLabelledBy,
27
+ onPointerDown: (e) => {
28
+ if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);
29
+ },
30
+ onPointerMove: (e) => {
31
+ if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);
32
+ },
33
+ onKeyDown: (e) => {
34
+ if (showTooltip) {
35
+ requestAnimationFrame(() => syncTooltipText(e.currentTarget, formatTooltip));
36
+ }
37
+ },
38
+ className: cn(
39
+ "flex size-6 items-center justify-center rounded-full border border-neutral-100 bg-background-inverse-solid shadow-sm",
40
+ "transition-shadow duration-150",
41
+ "hover:ring-2 hover:ring-brand-green-500",
42
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-purple-500 focus-visible:ring-offset-2 focus-visible:ring-offset-background-inverse-solid",
43
+ "data-disabled:cursor-not-allowed"
44
+ ),
45
+ children: [
46
+ /* @__PURE__ */ jsx("span", { className: "block size-3 rounded-full bg-brand-green-500 shadow-[inset_0px_1px_2px_0px_rgba(0,0,0,0.1)]" }),
47
+ showTooltip && /* @__PURE__ */ jsx(
48
+ "span",
49
+ {
50
+ role: "tooltip",
51
+ "data-slider-tooltip": true,
52
+ className: "typography-caption-semibold pointer-events-none absolute bottom-full mb-2 rounded-3xl bg-background-solid px-2 py-1 text-background-inverse-solid shadow-sm"
53
+ }
54
+ )
55
+ ]
56
+ }
57
+ );
58
+ }
59
+ function syncTooltipText(thumb, formatTooltip) {
60
+ const raw = thumb.getAttribute("aria-valuenow");
61
+ const tooltip = thumb.querySelector("[data-slider-tooltip]");
62
+ if (raw == null || !tooltip) return;
63
+ const num = Number(raw);
64
+ tooltip.textContent = formatTooltip ? formatTooltip(num) : String(num);
65
+ }
66
+ export {
67
+ SliderThumb
68
+ };
69
+ //# sourceMappingURL=SliderThumb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderThumb.mjs","sources":["../../../src/components/Slider/SliderThumb.tsx"],"sourcesContent":["import * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\ninterface SliderThumbProps {\n showTooltip: boolean;\n formatTooltip?: (value: number) => string;\n index: number;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nexport function SliderThumb({\n showTooltip,\n formatTooltip,\n index,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n}: SliderThumbProps) {\n const thumbRef = React.useCallback(\n (el: HTMLSpanElement | null) => {\n if (!el || !showTooltip) return;\n syncTooltipText(el, formatTooltip);\n },\n [showTooltip, formatTooltip],\n );\n\n return (\n <SliderPrimitive.Thumb\n ref={thumbRef}\n data-index={index}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n onPointerDown={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onPointerMove={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onKeyDown={(e) => {\n if (showTooltip) {\n requestAnimationFrame(() => syncTooltipText(e.currentTarget, formatTooltip));\n }\n }}\n className={cn(\n \"flex size-6 items-center justify-center rounded-full border border-neutral-100 bg-background-inverse-solid shadow-sm\",\n \"transition-shadow duration-150\",\n \"hover:ring-2 hover:ring-brand-green-500\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-purple-500 focus-visible:ring-offset-2 focus-visible:ring-offset-background-inverse-solid\",\n \"data-disabled:cursor-not-allowed\",\n )}\n >\n <span className=\"block size-3 rounded-full bg-brand-green-500 shadow-[inset_0px_1px_2px_0px_rgba(0,0,0,0.1)]\" />\n\n {showTooltip && (\n <span\n role=\"tooltip\"\n data-slider-tooltip\n className=\"typography-caption-semibold pointer-events-none absolute bottom-full mb-2 rounded-3xl bg-background-solid px-2 py-1 text-background-inverse-solid shadow-sm\"\n />\n )}\n </SliderPrimitive.Thumb>\n );\n}\n\nfunction syncTooltipText(thumb: HTMLElement, formatTooltip?: (value: number) => string) {\n const raw = thumb.getAttribute(\"aria-valuenow\");\n const tooltip = thumb.querySelector<HTMLSpanElement>(\"[data-slider-tooltip]\");\n if (raw == null || !tooltip) return;\n const num = Number(raw);\n tooltip.textContent = formatTooltip ? formatTooltip(num) : String(num);\n}\n"],"names":[],"mappings":";;;;;AAYO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,mBAAmB;AACrB,GAAqB;AACnB,QAAM,WAAW,MAAM;AAAA,IACrB,CAAC,OAA+B;AAC9B,UAAI,CAAC,MAAM,CAAC,YAAa;AACzB,sBAAgB,IAAI,aAAa;AAAA,IACnC;AAAA,IACA,CAAC,aAAa,aAAa;AAAA,EAAA;AAG7B,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,KAAK;AAAA,MACL,cAAY;AAAA,MACZ,cAAY;AAAA,MACZ,mBAAiB;AAAA,MACjB,eAAe,CAAC,MAAM;AACpB,YAAI,YAAa,iBAAgB,EAAE,eAAe,aAAa;AAAA,MACjE;AAAA,MACA,eAAe,CAAC,MAAM;AACpB,YAAI,YAAa,iBAAgB,EAAE,eAAe,aAAa;AAAA,MACjE;AAAA,MACA,WAAW,CAAC,MAAM;AAChB,YAAI,aAAa;AACf,gCAAsB,MAAM,gBAAgB,EAAE,eAAe,aAAa,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,8FAAA,CAA8F;AAAA,QAE7G,eACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,uBAAmB;AAAA,YACnB,WAAU;AAAA,UAAA;AAAA,QAAA;AAAA,MACZ;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,gBAAgB,OAAoB,eAA2C;AACtF,QAAM,MAAM,MAAM,aAAa,eAAe;AAC9C,QAAM,UAAU,MAAM,cAA+B,uBAAuB;AAC5E,MAAI,OAAO,QAAQ,CAAC,QAAS;AAC7B,QAAM,MAAM,OAAO,GAAG;AACtB,UAAQ,cAAc,gBAAgB,cAAc,GAAG,IAAI,OAAO,GAAG;AACvE;"}