@fanvue/ui 0.1.0-alpha.3 → 1.1.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 (222) hide show
  1. package/README.md +30 -8
  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 +55 -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 +46 -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 +38 -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 +29 -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 +41 -61
  215. package/dist/index.mjs +107 -10507
  216. package/dist/index.mjs.map +1 -1
  217. package/dist/styles/theme.css +1 -1
  218. package/dist/utils/cn.mjs +10 -0
  219. package/dist/utils/cn.mjs.map +1 -0
  220. package/package.json +15 -4
  221. package/dist/index.cjs +0 -2
  222. package/dist/index.cjs.map +0 -1
@@ -0,0 +1,82 @@
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 badgeVariants = {
7
+ variant: {
8
+ default: "bg-neutral-100 text-neutral-400",
9
+ dark: "bg-background-800 text-body-300 dark:text-body-white-solid-constant",
10
+ success: "bg-neutral-100 text-neutral-400",
11
+ warning: "bg-neutral-100 text-neutral-400",
12
+ error: "bg-neutral-100 text-neutral-400",
13
+ special: "bg-neutral-100 text-neutral-400",
14
+ info: "bg-neutral-100 text-neutral-400",
15
+ online: "bg-background-200 text-brand-green-500",
16
+ brand: "bg-brand-green-500 text-body-black-solid-constant",
17
+ pink: "bg-brand-pink-500 text-body-black-solid-constant",
18
+ brandLight: "bg-brand-green-50 text-body-black-solid-constant",
19
+ pinkLight: "bg-brand-pink-50 text-body-black-solid-constant"
20
+ },
21
+ dotColor: {
22
+ default: "bg-body-black-solid-constant",
23
+ dark: "bg-body-300 dark:bg-body-white-solid-constant",
24
+ success: "bg-success-500",
25
+ warning: "bg-warning-500",
26
+ error: "bg-error-500",
27
+ special: "bg-special-500",
28
+ info: "bg-info-500",
29
+ online: "bg-brand-green-500",
30
+ brand: "bg-body-black-solid-constant",
31
+ pink: "bg-body-black-solid-constant",
32
+ brandLight: "bg-body-black-solid-constant",
33
+ pinkLight: "bg-body-black-solid-constant"
34
+ }
35
+ };
36
+ const Badge = React.forwardRef(
37
+ ({
38
+ className,
39
+ variant = "default",
40
+ leftDot = true,
41
+ leftIcon,
42
+ rightIcon,
43
+ asChild = false,
44
+ children,
45
+ ...props
46
+ }, ref) => {
47
+ const Comp = asChild ? Slot : "span";
48
+ return /* @__PURE__ */ jsxs(
49
+ Comp,
50
+ {
51
+ ref,
52
+ "data-testid": "badge",
53
+ className: cn(
54
+ // Base styles
55
+ "typography-caption-semibold inline-flex h-5 items-center gap-2 rounded-full px-2",
56
+ // Variant styles
57
+ badgeVariants.variant[variant],
58
+ // Manual CSS overrides
59
+ className
60
+ ),
61
+ ...props,
62
+ children: [
63
+ leftIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: leftIcon }),
64
+ leftDot && /* @__PURE__ */ jsx(
65
+ "span",
66
+ {
67
+ className: cn("size-1 shrink-0 rounded-full", badgeVariants.dotColor[variant]),
68
+ "aria-hidden": "true"
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsx(Slottable, { children }),
72
+ rightIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: rightIcon })
73
+ ]
74
+ }
75
+ );
76
+ }
77
+ );
78
+ Badge.displayName = "Badge";
79
+ export {
80
+ Badge
81
+ };
82
+ //# sourceMappingURL=Badge.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Badge.mjs","sources":["../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst badgeVariants = {\n variant: {\n default: \"bg-neutral-100 text-neutral-400\",\n dark: \"bg-background-800 text-body-300 dark:text-body-white-solid-constant\",\n success: \"bg-neutral-100 text-neutral-400\",\n warning: \"bg-neutral-100 text-neutral-400\",\n error: \"bg-neutral-100 text-neutral-400\",\n special: \"bg-neutral-100 text-neutral-400\",\n info: \"bg-neutral-100 text-neutral-400\",\n online: \"bg-background-200 text-brand-green-500\",\n brand: \"bg-brand-green-500 text-body-black-solid-constant\",\n pink: \"bg-brand-pink-500 text-body-black-solid-constant\",\n brandLight: \"bg-brand-green-50 text-body-black-solid-constant\",\n pinkLight: \"bg-brand-pink-50 text-body-black-solid-constant\",\n },\n dotColor: {\n default: \"bg-body-black-solid-constant\",\n dark: \"bg-body-300 dark:bg-body-white-solid-constant\",\n success: \"bg-success-500\",\n warning: \"bg-warning-500\",\n error: \"bg-error-500\",\n special: \"bg-special-500\",\n info: \"bg-info-500\",\n online: \"bg-brand-green-500\",\n brand: \"bg-body-black-solid-constant\",\n pink: \"bg-body-black-solid-constant\",\n brandLight: \"bg-body-black-solid-constant\",\n pinkLight: \"bg-body-black-solid-constant\",\n },\n} as const;\n\nexport type BadgeVariant =\n | \"default\"\n | \"dark\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"special\"\n | \"info\"\n | \"online\"\n | \"brand\"\n | \"pink\"\n | \"brandLight\"\n | \"pinkLight\";\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual style variant of the badge */\n variant?: BadgeVariant;\n /** Show left status indicator dot */\n leftDot?: boolean;\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 Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n className,\n variant = \"default\",\n leftDot = true,\n leftIcon,\n rightIcon,\n asChild = false,\n children,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"badge\"\n className={cn(\n // Base styles\n \"typography-caption-semibold inline-flex h-5 items-center gap-2 rounded-full px-2\",\n // Variant styles\n badgeVariants.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 {leftDot && (\n <span\n className={cn(\"size-1 shrink-0 rounded-full\", badgeVariants.dotColor[variant])}\n aria-hidden=\"true\"\n />\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\nBadge.displayName = \"Badge\";\n"],"names":[],"mappings":";;;;;AAIA,MAAM,gBAAgB;AAAA,EACpB,SAAS;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EAAA;AAAA,EAEb,UAAU;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EAAA;AAEf;AA6BO,MAAM,QAAQ,MAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,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,cAAc,QAAQ,OAAO;AAAA;AAAA,UAE7B;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,gCACE,QAAA,EAAK,WAAU,QAAO,eAAY,QAChC,UAAA,UACH;AAAA,UAED,WACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW,GAAG,gCAAgC,cAAc,SAAS,OAAO,CAAC;AAAA,cAC7E,eAAY;AAAA,YAAA;AAAA,UAAA;AAAA,UAGhB,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,MAAM,cAAc;"}
@@ -0,0 +1,155 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ import { SpinnerIcon } from "../Icons/SpinnerIcon.mjs";
7
+ const SIZE_CLASSES = {
8
+ "48": "h-12 px-4 py-3 typography-button-large",
9
+ "40": "h-10 px-4 py-2 typography-button-small",
10
+ "32": "h-8 px-3 py-2 typography-body-2-semibold",
11
+ "24": "h-6 px-0 py-1 typography-body-2-semibold"
12
+ };
13
+ const ICON_SIZE_CLASS = {
14
+ "48": "size-5",
15
+ "40": "size-5",
16
+ "32": "size-4",
17
+ "24": "size-3.5"
18
+ };
19
+ const VARIANT_CLASSES = {
20
+ primary: "bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant",
21
+ secondary: "border-body-100 border border-1 border-body-100 bg-transparent text-body-100 hover:bg-brand-green-50",
22
+ tertiary: "bg-transparent text-body-100 hover:bg-brand-green-50",
23
+ link: "bg-transparent text-body-100 underline decoration-solid hover:bg-brand-green-50",
24
+ brand: "bg-brand-green-500 text-body-black-solid-constant hover:bg-brand-pink-500",
25
+ destructive: "bg-error-500 text-body-white-solid-constant hover:bg-background-solid dark:hover:bg-background-white-solid-constant dark:hover:text-error-500",
26
+ white: "bg-background-white-solid-constant text-body-black-solid-constant hover:bg-brand-green-500",
27
+ tertiaryDestructive: "bg-transparent text-error-500 hover:bg-error-50",
28
+ text: "bg-transparent text-body-100 hover:underline"
29
+ };
30
+ function getTextContent(node) {
31
+ if (typeof node === "string") return node;
32
+ if (typeof node === "number") return String(node);
33
+ if (React.isValidElement(node)) {
34
+ return getTextContent(node.props.children);
35
+ }
36
+ if (Array.isArray(node)) {
37
+ const text = node.map(getTextContent).filter(Boolean).join("");
38
+ return text || void 0;
39
+ }
40
+ return void 0;
41
+ }
42
+ const LoadingSpinner = ({ size }) => {
43
+ return /* @__PURE__ */ jsx("span", { className: "animate-spin", "aria-hidden": "true", children: /* @__PURE__ */ jsx(SpinnerIcon, { className: ICON_SIZE_CLASS[size], children: /* @__PURE__ */ jsx("title", { children: "Loading" }) }) });
44
+ };
45
+ function renderContent({
46
+ loading,
47
+ asChild,
48
+ children,
49
+ size,
50
+ leftIcon,
51
+ rightIcon,
52
+ iconSizeClass,
53
+ discount,
54
+ price
55
+ }) {
56
+ if (loading) {
57
+ if (asChild && React.isValidElement(children)) {
58
+ return React.cloneElement(
59
+ children,
60
+ void 0,
61
+ /* @__PURE__ */ jsx(LoadingSpinner, { size })
62
+ );
63
+ }
64
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
65
+ /* @__PURE__ */ jsx(LoadingSpinner, { size }),
66
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children })
67
+ ] });
68
+ }
69
+ if (asChild) return children;
70
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ leftIcon && /* @__PURE__ */ jsx(
72
+ "span",
73
+ {
74
+ className: cn("flex shrink-0 items-center justify-center", iconSizeClass),
75
+ "aria-hidden": "true",
76
+ children: leftIcon
77
+ }
78
+ ),
79
+ children,
80
+ rightIcon && /* @__PURE__ */ jsx(
81
+ "span",
82
+ {
83
+ className: cn("flex shrink-0 items-center justify-center", iconSizeClass),
84
+ "aria-hidden": "true",
85
+ children: rightIcon
86
+ }
87
+ ),
88
+ discount != null && /* @__PURE__ */ jsx("span", { className: "typography-body-1-regular line-through", "aria-hidden": "true", children: discount }),
89
+ price != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: price })
90
+ ] });
91
+ }
92
+ const Button = React.forwardRef(
93
+ ({
94
+ className,
95
+ variant = "primary",
96
+ size = "48",
97
+ leftIcon,
98
+ rightIcon,
99
+ loading = false,
100
+ asChild = false,
101
+ disabled,
102
+ children,
103
+ discount,
104
+ price,
105
+ ...props
106
+ }, ref) => {
107
+ const Comp = asChild ? Slot : "button";
108
+ const isDisabled = disabled || loading;
109
+ const iconSizeClass = ICON_SIZE_CLASS[size];
110
+ const buttonSpecificProps = !asChild ? { "data-testid": "button", disabled: isDisabled } : isDisabled ? { "aria-disabled": true } : {};
111
+ const loadingLabelProps = loading && asChild ? { "aria-label": getTextContent(children) } : {};
112
+ const content = renderContent({
113
+ loading,
114
+ asChild,
115
+ children,
116
+ size,
117
+ leftIcon,
118
+ rightIcon,
119
+ iconSizeClass,
120
+ discount,
121
+ price
122
+ });
123
+ return /* @__PURE__ */ jsx(
124
+ Comp,
125
+ {
126
+ ref,
127
+ ...buttonSpecificProps,
128
+ "aria-busy": loading,
129
+ ...loadingLabelProps,
130
+ className: cn(
131
+ // Base styles
132
+ "inline-flex cursor-pointer items-center justify-center gap-2 rounded-full transition-colors",
133
+ // Focus ring
134
+ "focus:shadow-focus focus-visible:outline-none",
135
+ // Disabled state
136
+ "disabled:pointer-events-none disabled:opacity-50",
137
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50",
138
+ // Size styles
139
+ SIZE_CLASSES[size],
140
+ // Variant styles
141
+ VARIANT_CLASSES[variant],
142
+ // Manual CSS overrides
143
+ className
144
+ ),
145
+ ...props,
146
+ children: content
147
+ }
148
+ );
149
+ }
150
+ );
151
+ Button.displayName = "Button";
152
+ export {
153
+ Button
154
+ };
155
+ //# sourceMappingURL=Button.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.mjs","sources":["../../../src/components/Button/Button.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\n\nexport type ButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"link\"\n | \"brand\"\n | \"destructive\"\n | \"white\"\n | \"tertiaryDestructive\"\n | \"text\";\n\nexport type ButtonSize = \"48\" | \"40\" | \"32\" | \"24\";\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the button */\n variant?: ButtonVariant;\n /** Size of the button in pixels */\n size?: ButtonSize;\n /** Left icon element */\n leftIcon?: React.ReactNode;\n /** Right icon element */\n rightIcon?: React.ReactNode;\n /** Show loading spinner */\n loading?: boolean;\n /** Render as a different element using Radix Slot */\n asChild?: boolean;\n /** Old price shown with strikethrough before the current price */\n discount?: string;\n /** Current price shown inside the button after the label/icons */\n price?: string;\n}\n\nconst SIZE_CLASSES: Record<ButtonSize, string> = {\n \"48\": \"h-12 px-4 py-3 typography-button-large\",\n \"40\": \"h-10 px-4 py-2 typography-button-small\",\n \"32\": \"h-8 px-3 py-2 typography-body-2-semibold\",\n \"24\": \"h-6 px-0 py-1 typography-body-2-semibold\",\n};\n\nconst ICON_SIZE_CLASS: Record<ButtonSize, string> = {\n \"48\": \"size-5\",\n \"40\": \"size-5\",\n \"32\": \"size-4\",\n \"24\": \"size-3.5\",\n};\n\nconst VARIANT_CLASSES: Record<ButtonVariant, string> = {\n primary:\n \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant\",\n secondary:\n \"border-body-100 border border-1 border-body-100 bg-transparent text-body-100 hover:bg-brand-green-50\",\n tertiary: \"bg-transparent text-body-100 hover:bg-brand-green-50\",\n link: \"bg-transparent text-body-100 underline decoration-solid hover:bg-brand-green-50\",\n brand: \"bg-brand-green-500 text-body-black-solid-constant hover:bg-brand-pink-500\",\n destructive:\n \"bg-error-500 text-body-white-solid-constant hover:bg-background-solid dark:hover:bg-background-white-solid-constant dark:hover:text-error-500\",\n white:\n \"bg-background-white-solid-constant text-body-black-solid-constant hover:bg-brand-green-500\",\n tertiaryDestructive: \"bg-transparent text-error-500 hover:bg-error-50\",\n text: \"bg-transparent text-body-100 hover:underline\",\n};\n\n/** Recursively extract text content from React nodes for accessible labels */\nfunction getTextContent(node: React.ReactNode): string | undefined {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\") return String(node);\n if (React.isValidElement(node)) {\n return getTextContent((node.props as { children?: React.ReactNode }).children);\n }\n if (Array.isArray(node)) {\n const text = node.map(getTextContent).filter(Boolean).join(\"\");\n return text || undefined;\n }\n return undefined;\n}\n\nconst LoadingSpinner = ({ size }: { size: ButtonSize }) => {\n return (\n <span className=\"animate-spin\" aria-hidden=\"true\">\n <SpinnerIcon className={ICON_SIZE_CLASS[size]}>\n <title>Loading</title>\n </SpinnerIcon>\n </span>\n );\n};\n\nfunction renderContent({\n loading,\n asChild,\n children,\n size,\n leftIcon,\n rightIcon,\n iconSizeClass,\n discount,\n price,\n}: {\n loading: boolean;\n asChild: boolean;\n children: React.ReactNode;\n size: ButtonSize;\n leftIcon: React.ReactNode;\n rightIcon: React.ReactNode;\n iconSizeClass: string;\n discount?: string;\n price?: string;\n}) {\n if (loading) {\n // When asChild, clone the child element with spinner content instead of\n // wrapping in sr-only span (which would nest interactive elements)\n if (asChild && React.isValidElement(children)) {\n return React.cloneElement(\n children as React.ReactElement<{ children?: React.ReactNode }>,\n undefined,\n <LoadingSpinner size={size} />,\n );\n }\n return (\n <>\n <LoadingSpinner size={size} />\n <span className=\"sr-only\">{children}</span>\n </>\n );\n }\n\n if (asChild) return children;\n\n return (\n <>\n {leftIcon && (\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeClass)}\n aria-hidden=\"true\"\n >\n {leftIcon}\n </span>\n )}\n {children}\n {rightIcon && (\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeClass)}\n aria-hidden=\"true\"\n >\n {rightIcon}\n </span>\n )}\n {discount != null && (\n <span className=\"typography-body-1-regular line-through\" aria-hidden=\"true\">\n {discount}\n </span>\n )}\n {price != null && <span aria-hidden=\"true\">{price}</span>}\n </>\n );\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant = \"primary\",\n size = \"48\",\n leftIcon,\n rightIcon,\n loading = false,\n asChild = false,\n disabled,\n children,\n discount,\n price,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"button\";\n const isDisabled = disabled || loading;\n const iconSizeClass = ICON_SIZE_CLASS[size];\n\n const buttonSpecificProps = !asChild\n ? { \"data-testid\": \"button\", disabled: isDisabled }\n : isDisabled\n ? { \"aria-disabled\": true }\n : {};\n\n // When asChild + loading, extract text from children for aria-label since we\n // can't wrap element children in an sr-only span (creates invalid nested markup)\n const loadingLabelProps = loading && asChild ? { \"aria-label\": getTextContent(children) } : {};\n\n const content = renderContent({\n loading,\n asChild,\n children,\n size,\n leftIcon,\n rightIcon,\n iconSizeClass,\n discount,\n price,\n });\n\n return (\n <Comp\n ref={ref}\n {...buttonSpecificProps}\n aria-busy={loading}\n {...loadingLabelProps}\n className={cn(\n // Base styles\n \"inline-flex cursor-pointer items-center justify-center gap-2 rounded-full transition-colors\",\n // Focus ring\n \"focus:shadow-focus focus-visible:outline-none\",\n // Disabled state\n \"disabled:pointer-events-none disabled:opacity-50\",\n \"aria-disabled:pointer-events-none aria-disabled:opacity-50\",\n // Size styles\n SIZE_CLASSES[size],\n // Variant styles\n VARIANT_CLASSES[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n {content}\n </Comp>\n );\n },\n);\n\nButton.displayName = \"Button\";\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ import { CheckIcon } from "../Icons/CheckIcon.mjs";
7
+ import { MinusIcon } from "../Icons/MinusIcon.mjs";
8
+ const Checkbox = React.forwardRef(
9
+ ({ className, size = "default", label, helperText, disabled, name, ...props }, ref) => {
10
+ const id = React.useId();
11
+ const helperTextId = helperText ? `${id}-helper` : void 0;
12
+ const hasLabel = Boolean(label || helperText);
13
+ const inputRef = React.useRef(null);
14
+ React.useImperativeHandle(ref, () => inputRef.current);
15
+ const handleCheckedChange = (value) => {
16
+ const checked = value === true;
17
+ if (inputRef.current) {
18
+ inputRef.current.checked = checked;
19
+ inputRef.current.dispatchEvent(new Event("change", { bubbles: true }));
20
+ }
21
+ props.onCheckedChange?.(value);
22
+ };
23
+ const checkboxElement = /* @__PURE__ */ jsxs(
24
+ "span",
25
+ {
26
+ className: cn(
27
+ "relative inline-flex size-5 shrink-0",
28
+ // Alignment when used with label
29
+ label && (helperText ? "mt-1" : "mt-0.5")
30
+ ),
31
+ children: [
32
+ /* @__PURE__ */ jsx(
33
+ "input",
34
+ {
35
+ ref: inputRef,
36
+ type: "checkbox",
37
+ name,
38
+ disabled,
39
+ "aria-hidden": true,
40
+ tabIndex: -1,
41
+ onChange: () => {
42
+ },
43
+ className: "pointer-events-none absolute size-px overflow-hidden opacity-0",
44
+ style: { clip: "rect(0,0,0,0)" }
45
+ }
46
+ ),
47
+ /* @__PURE__ */ jsx(
48
+ CheckboxPrimitive.Root,
49
+ {
50
+ id,
51
+ disabled,
52
+ "aria-describedby": helperTextId,
53
+ "data-testid": "checkbox",
54
+ ...props,
55
+ onCheckedChange: handleCheckedChange,
56
+ className: cn(
57
+ // Base styles
58
+ "flex size-5 items-center justify-center rounded border-2",
59
+ "transition-[border-color,background-color,color,box-shadow] duration-150",
60
+ // Default state
61
+ "border-body-100 bg-transparent text-transparent",
62
+ // Checked state
63
+ "data-[state=checked]:border-body-100 data-[state=checked]:bg-body-100 data-[state=checked]:text-body-300",
64
+ // Indeterminate state
65
+ "data-[state=indeterminate]:border-body-100 data-[state=indeterminate]:bg-body-100 data-[state=indeterminate]:text-body-300",
66
+ // Hover state
67
+ "hover:ring-2 hover:ring-brand-green-500 group-hover:ring-2 group-hover:ring-brand-green-500",
68
+ // Focus state
69
+ "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",
70
+ // Disabled state
71
+ "disabled:cursor-not-allowed disabled:border-disabled-400 disabled:ring-0 disabled:group-hover:ring-0",
72
+ "disabled:data-[state=checked]:border-disabled-400 disabled:data-[state=checked]:bg-disabled-400 disabled:data-[state=checked]:text-disabled-100",
73
+ !hasLabel && className
74
+ ),
75
+ children: /* @__PURE__ */ jsx(
76
+ CheckboxPrimitive.Indicator,
77
+ {
78
+ forceMount: true,
79
+ className: cn(
80
+ "flex size-3 items-center justify-center text-body-300",
81
+ "data-[state=unchecked]:invisible"
82
+ ),
83
+ children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {})
84
+ }
85
+ )
86
+ }
87
+ )
88
+ ]
89
+ }
90
+ );
91
+ if (!hasLabel) {
92
+ return checkboxElement;
93
+ }
94
+ return /* @__PURE__ */ jsxs(
95
+ "div",
96
+ {
97
+ className: cn(
98
+ "inline-flex flex-col gap-0.5",
99
+ disabled && "is-disabled cursor-not-allowed",
100
+ className
101
+ ),
102
+ children: [
103
+ /* @__PURE__ */ jsxs("div", { className: "group inline-flex items-start gap-2", children: [
104
+ checkboxElement,
105
+ label && /* @__PURE__ */ jsx(
106
+ "label",
107
+ {
108
+ htmlFor: id,
109
+ className: cn(
110
+ "cursor-pointer select-none text-body-100",
111
+ "group-has-disabled:cursor-not-allowed group-has-disabled:text-disabled-100",
112
+ size === "small" ? "typography-body-2-semibold" : "typography-body-1-semibold"
113
+ ),
114
+ children: label
115
+ }
116
+ )
117
+ ] }),
118
+ helperText && /* @__PURE__ */ jsx(
119
+ "span",
120
+ {
121
+ id: helperTextId,
122
+ className: cn(
123
+ "ml-7 text-body-200",
124
+ "in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-disabled-100",
125
+ size === "small" ? "typography-caption-regular" : "typography-body-2-regular"
126
+ ),
127
+ children: helperText
128
+ }
129
+ )
130
+ ]
131
+ }
132
+ );
133
+ }
134
+ );
135
+ Checkbox.displayName = "Checkbox";
136
+ export {
137
+ Checkbox
138
+ };
139
+ //# sourceMappingURL=Checkbox.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.mjs","sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { MinusIcon } from \"../Icons/MinusIcon\";\n\nexport type CheckboxSize = \"default\" | \"small\";\n\nexport interface CheckboxProps\n extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, \"asChild\"> {\n /** Size variant for label and helper text */\n size?: CheckboxSize;\n /** Label text displayed next to the checkbox */\n label?: string;\n /** Helper text displayed below the label */\n helperText?: string;\n}\n\n/**\n * The ref type is intentionally `HTMLInputElement` (not `HTMLButtonElement`) for form library\n * compatibility. Libraries like react-hook-form call `register()` which expects an `HTMLInputElement`\n * ref. A hidden `<input>` is synced to the Radix checkbox state via `useImperativeHandle`.\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, size = \"default\", label, helperText, disabled, name, ...props }, ref) => {\n const id = React.useId();\n const helperTextId = helperText ? `${id}-helper` : undefined;\n const hasLabel = Boolean(label || helperText);\n\n // Hidden input for form library compatibility (e.g. react-hook-form register)\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const handleCheckedChange = (value: boolean | \"indeterminate\") => {\n const checked = value === true;\n if (inputRef.current) {\n inputRef.current.checked = checked;\n inputRef.current.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n props.onCheckedChange?.(value);\n };\n\n const checkboxElement = (\n <span\n className={cn(\n \"relative inline-flex size-5 shrink-0\",\n // Alignment when used with label\n label && (helperText ? \"mt-1\" : \"mt-0.5\"),\n )}\n >\n <input\n ref={inputRef}\n type=\"checkbox\"\n name={name}\n disabled={disabled}\n aria-hidden\n tabIndex={-1}\n onChange={() => {}}\n className=\"pointer-events-none absolute size-px overflow-hidden opacity-0\"\n style={{ clip: \"rect(0,0,0,0)\" }}\n />\n <CheckboxPrimitive.Root\n id={id}\n disabled={disabled}\n aria-describedby={helperTextId}\n data-testid=\"checkbox\"\n {...props}\n onCheckedChange={handleCheckedChange}\n className={cn(\n // Base styles\n \"flex size-5 items-center justify-center rounded border-2\",\n \"transition-[border-color,background-color,color,box-shadow] duration-150\",\n // Default state\n \"border-body-100 bg-transparent text-transparent\",\n // Checked state\n \"data-[state=checked]:border-body-100 data-[state=checked]:bg-body-100 data-[state=checked]:text-body-300\",\n // Indeterminate state\n \"data-[state=indeterminate]:border-body-100 data-[state=indeterminate]:bg-body-100 data-[state=indeterminate]:text-body-300\",\n // Hover state\n \"hover:ring-2 hover:ring-brand-green-500 group-hover:ring-2 group-hover:ring-brand-green-500\",\n // Focus state\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 // Disabled state\n \"disabled:cursor-not-allowed disabled:border-disabled-400 disabled:ring-0 disabled:group-hover:ring-0\",\n \"disabled:data-[state=checked]:border-disabled-400 disabled:data-[state=checked]:bg-disabled-400 disabled:data-[state=checked]:text-disabled-100\",\n !hasLabel && className,\n )}\n >\n <CheckboxPrimitive.Indicator\n forceMount\n className={cn(\n \"flex size-3 items-center justify-center text-body-300\",\n \"data-[state=unchecked]:invisible\",\n )}\n >\n {props.checked === \"indeterminate\" ? <MinusIcon /> : <CheckIcon />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n </span>\n );\n\n if (!hasLabel) {\n return checkboxElement;\n }\n\n return (\n <div\n className={cn(\n \"inline-flex flex-col gap-0.5\",\n disabled && \"is-disabled cursor-not-allowed\",\n className,\n )}\n >\n <div className=\"group inline-flex items-start gap-2\">\n {checkboxElement}\n {label && (\n <label\n htmlFor={id}\n className={cn(\n \"cursor-pointer select-none text-body-100\",\n \"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 </div>\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"ml-7 text-body-200\",\n \"in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-disabled-100\",\n size === \"small\" ? \"typography-caption-regular\" : \"typography-body-2-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n );\n },\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"names":[],"mappings":";;;;;;;AAuBO,MAAM,WAAW,MAAM;AAAA,EAC5B,CAAC,EAAE,WAAW,OAAO,WAAW,OAAO,YAAY,UAAU,MAAM,GAAG,MAAA,GAAS,QAAQ;AACrF,UAAM,KAAK,MAAM,MAAA;AACjB,UAAM,eAAe,aAAa,GAAG,EAAE,YAAY;AACnD,UAAM,WAAW,QAAQ,SAAS,UAAU;AAG5C,UAAM,WAAW,MAAM,OAAyB,IAAI;AACpD,UAAM,oBAAoB,KAAK,MAAM,SAAS,OAA2B;AAEzE,UAAM,sBAAsB,CAAC,UAAqC;AAChE,YAAM,UAAU,UAAU;AAC1B,UAAI,SAAS,SAAS;AACpB,iBAAS,QAAQ,UAAU;AAC3B,iBAAS,QAAQ,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAA,CAAM,CAAC;AAAA,MACvE;AACA,YAAM,kBAAkB,KAAK;AAAA,IAC/B;AAEA,UAAM,kBACJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA;AAAA,UAEA,UAAU,aAAa,SAAS;AAAA,QAAA;AAAA,QAGlC,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA,eAAW;AAAA,cACX,UAAU;AAAA,cACV,UAAU,MAAM;AAAA,cAAC;AAAA,cACjB,WAAU;AAAA,cACV,OAAO,EAAE,MAAM,gBAAA;AAAA,YAAgB;AAAA,UAAA;AAAA,UAEjC;AAAA,YAAC,kBAAkB;AAAA,YAAlB;AAAA,cACC;AAAA,cACA;AAAA,cACA,oBAAkB;AAAA,cAClB,eAAY;AAAA,cACX,GAAG;AAAA,cACJ,iBAAiB;AAAA,cACjB,WAAW;AAAA;AAAA,gBAET;AAAA,gBACA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA,gBACA;AAAA,gBACA,CAAC,YAAY;AAAA,cAAA;AAAA,cAGf,UAAA;AAAA,gBAAC,kBAAkB;AAAA,gBAAlB;AAAA,kBACC,YAAU;AAAA,kBACV,WAAW;AAAA,oBACT;AAAA,oBACA;AAAA,kBAAA;AAAA,kBAGD,gBAAM,YAAY,sCAAmB,WAAA,EAAU,wBAAM,WAAA,CAAA,CAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,YAClE;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAAA;AAIJ,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QAAA;AAAA,QAGF,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,uCACZ,UAAA;AAAA,YAAA;AAAA,YACA,SACC;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,kBACA,SAAS,UAAU,+BAA+B;AAAA,gBAAA;AAAA,gBAGnD,UAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,GAEJ;AAAA,UACC,cACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,IAAI;AAAA,cACJ,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,SAAS,UAAU,+BAA+B;AAAA,cAAA;AAAA,cAGnD,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,SAAS,cAAc;"}
@@ -0,0 +1,75 @@
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 Chip = React.forwardRef(
7
+ ({
8
+ className,
9
+ variant = "rounded",
10
+ size = "32",
11
+ selected = false,
12
+ disabled = false,
13
+ leftDot = false,
14
+ leftIcon,
15
+ rightIcon,
16
+ notificationLabel,
17
+ onClick,
18
+ asChild = false,
19
+ children,
20
+ ...props
21
+ }, ref) => {
22
+ const isInteractive = !!onClick && !asChild;
23
+ const Comp = asChild ? Slot : isInteractive ? "button" : "span";
24
+ const isDark = variant === "dark";
25
+ return /* @__PURE__ */ jsxs(
26
+ Comp,
27
+ {
28
+ ref,
29
+ "data-testid": "chip",
30
+ className: cn(
31
+ "typography-caption-semibold relative inline-flex items-center gap-2 px-3 transition-colors",
32
+ // Shape
33
+ variant === "square" ? "rounded-lg" : "rounded-full",
34
+ // Size
35
+ size === "32" && "h-8 py-1",
36
+ size === "40" && "h-10 py-2.5",
37
+ // Variant colors
38
+ isDark && "bg-background-800 text-body-white-solid-constant",
39
+ !isDark && selected && "bg-brand-green-50 text-neutral-400",
40
+ !isDark && !selected && "bg-neutral-100 text-neutral-400",
41
+ // Hover
42
+ isInteractive && !disabled && !isDark && selected && "hover:bg-brand-green-500 hover:text-body-black-solid-constant",
43
+ isInteractive && !disabled && !isDark && !selected && "hover:bg-hover-400",
44
+ // Focus
45
+ "focus-visible:shadow-focus-ring focus-visible:outline-none",
46
+ // Disabled
47
+ disabled && isDark && "pointer-events-none opacity-50",
48
+ disabled && !isDark && "pointer-events-none text-neutral-300",
49
+ className
50
+ ),
51
+ ...isInteractive && {
52
+ type: "button",
53
+ disabled,
54
+ "aria-pressed": selected,
55
+ onClick
56
+ },
57
+ ...!isInteractive && disabled && { "aria-disabled": true },
58
+ ...selected && { "data-selected": "" },
59
+ ...props,
60
+ children: [
61
+ leftDot && /* @__PURE__ */ jsx("span", { className: "size-2 shrink-0 rounded-full bg-current", "aria-hidden": "true" }),
62
+ leftIcon && /* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center", "aria-hidden": "true", children: leftIcon }),
63
+ /* @__PURE__ */ jsx(Slottable, { children }),
64
+ rightIcon && /* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center", "aria-hidden": "true", children: rightIcon }),
65
+ notificationLabel && /* @__PURE__ */ jsx("span", { className: "typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300", children: notificationLabel })
66
+ ]
67
+ }
68
+ );
69
+ }
70
+ );
71
+ Chip.displayName = "Chip";
72
+ export {
73
+ Chip
74
+ };
75
+ //# sourceMappingURL=Chip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chip.mjs","sources":["../../../src/components/Chip/Chip.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport type ChipVariant = \"rounded\" | \"square\" | \"dark\";\nexport type ChipSize = \"32\" | \"40\";\n\nexport interface ChipProps extends React.HTMLAttributes<HTMLElement> {\n /** Visual shape variant of the chip */\n variant?: ChipVariant;\n /** Size of the chip */\n size?: ChipSize;\n /** Whether the chip is in a selected state */\n selected?: boolean;\n /** Whether the chip is disabled */\n disabled?: boolean;\n /** Show left status dot */\n leftDot?: boolean;\n /** Left icon element */\n leftIcon?: React.ReactNode;\n /** Right icon element */\n rightIcon?: React.ReactNode;\n /** Notification badge content (e.g., \"99+\"). Passed as a string for i18n support. */\n notificationLabel?: string;\n /** Click handler — when provided, the chip renders as a `<button>` for accessibility */\n onClick?: React.MouseEventHandler<HTMLElement>;\n /** Render as a different element using Radix Slot */\n asChild?: boolean;\n}\n\nexport const Chip = React.forwardRef<HTMLButtonElement, ChipProps>(\n (\n {\n className,\n variant = \"rounded\",\n size = \"32\",\n selected = false,\n disabled = false,\n leftDot = false,\n leftIcon,\n rightIcon,\n notificationLabel,\n onClick,\n asChild = false,\n children,\n ...props\n },\n ref,\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Variant-heavy UI component\n ) => {\n const isInteractive = !!onClick && !asChild;\n const Comp = asChild ? Slot : isInteractive ? \"button\" : \"span\";\n const isDark = variant === \"dark\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"chip\"\n className={cn(\n \"typography-caption-semibold relative inline-flex items-center gap-2 px-3 transition-colors\",\n // Shape\n variant === \"square\" ? \"rounded-lg\" : \"rounded-full\",\n // Size\n size === \"32\" && \"h-8 py-1\",\n size === \"40\" && \"h-10 py-2.5\",\n // Variant colors\n isDark && \"bg-background-800 text-body-white-solid-constant\",\n !isDark && selected && \"bg-brand-green-50 text-neutral-400\",\n !isDark && !selected && \"bg-neutral-100 text-neutral-400\",\n // Hover\n isInteractive &&\n !disabled &&\n !isDark &&\n selected &&\n \"hover:bg-brand-green-500 hover:text-body-black-solid-constant\",\n isInteractive && !disabled && !isDark && !selected && \"hover:bg-hover-400\",\n // Focus\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled\n disabled && isDark && \"pointer-events-none opacity-50\",\n disabled && !isDark && \"pointer-events-none text-neutral-300\",\n className,\n )}\n {...(isInteractive && {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": selected,\n onClick,\n })}\n {...(!isInteractive && disabled && { \"aria-disabled\": true })}\n {...(selected && { \"data-selected\": \"\" })}\n {...props}\n >\n {leftDot && <span className=\"size-2 shrink-0 rounded-full bg-current\" aria-hidden=\"true\" />}\n {leftIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n {notificationLabel && (\n <span className=\"typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300\">\n {notificationLabel}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nChip.displayName = \"Chip\";\n"],"names":[],"mappings":";;;;;AA8BO,MAAM,OAAO,MAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QAEG;AACH,UAAM,gBAAgB,CAAC,CAAC,WAAW,CAAC;AACpC,UAAM,OAAO,UAAU,OAAO,gBAAgB,WAAW;AACzD,UAAM,SAAS,YAAY;AAE3B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA;AAAA,UAEA,YAAY,WAAW,eAAe;AAAA;AAAA,UAEtC,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA;AAAA,UAEjB,UAAU;AAAA,UACV,CAAC,UAAU,YAAY;AAAA,UACvB,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAExB,iBACE,CAAC,YACD,CAAC,UACD,YACA;AAAA,UACF,iBAAiB,CAAC,YAAY,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAEtD;AAAA;AAAA,UAEA,YAAY,UAAU;AAAA,UACtB,YAAY,CAAC,UAAU;AAAA,UACvB;AAAA,QAAA;AAAA,QAED,GAAI,iBAAiB;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAAA,QAED,GAAI,CAAC,iBAAiB,YAAY,EAAE,iBAAiB,KAAA;AAAA,QACrD,GAAI,YAAY,EAAE,iBAAiB,GAAA;AAAA,QACnC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,WAAW,oBAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QAAO;AAAA,UACxF,YACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,UACH;AAAA,UAEF,oBAAC,aAAW,UAAS;AAAA,UACpB,aACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,WACH;AAAA,UAED,qBACC,oBAAC,QAAA,EAAK,WAAU,iJACb,UAAA,kBAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import * as React from "react";
5
+ import { cn } from "../../utils/cn.mjs";
6
+ function getDisplayValue(value, max) {
7
+ return value > max ? `${max}+` : value.toString();
8
+ }
9
+ const Count = React.forwardRef(
10
+ ({ className, variant = "default", value = 0, max = 99, asChild = false, children, ...props }, ref) => {
11
+ if (value === 0 && !children) {
12
+ return null;
13
+ }
14
+ const Comp = asChild ? Slot : "span";
15
+ return /* @__PURE__ */ jsx(
16
+ Comp,
17
+ {
18
+ ref,
19
+ className: cn(
20
+ "typography-caption-semibold inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 tabular-nums leading-none",
21
+ variant === "default" && "bg-error-500 text-body-white-solid-constant",
22
+ variant === "brand" && "bg-brand-green-500 text-body-black-solid-constant",
23
+ variant === "pink" && "bg-brand-pink-500 text-body-black-solid-constant",
24
+ variant === "info" && "bg-info-500 text-body-white-solid-constant",
25
+ variant === "success" && "bg-success-500 text-body-white-solid-constant",
26
+ variant === "warning" && "bg-warning-500 text-body-black-solid-constant",
27
+ className
28
+ ),
29
+ ...props,
30
+ children: children ?? getDisplayValue(value, max)
31
+ }
32
+ );
33
+ }
34
+ );
35
+ Count.displayName = "Count";
36
+ export {
37
+ Count
38
+ };
39
+ //# sourceMappingURL=Count.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Count.mjs","sources":["../../../src/components/Count/Count.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport type CountVariant = \"default\" | \"brand\" | \"pink\" | \"info\" | \"success\" | \"warning\";\n\nfunction getDisplayValue(value: number, max: number): string {\n return value > max ? `${max}+` : value.toString();\n}\n\nexport interface CountProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual style variant of the count */\n variant?: CountVariant;\n /** The count value to display */\n value?: number;\n /** Maximum value to display before showing overflow (e.g., \"99+\") */\n max?: number;\n /** Render as a different element using Radix Slot */\n asChild?: boolean;\n}\n\nexport const Count = React.forwardRef<HTMLSpanElement, CountProps>(\n (\n { className, variant = \"default\", value = 0, max = 99, asChild = false, children, ...props },\n ref,\n ) => {\n if (value === 0 && !children) {\n return null;\n }\n\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n className={cn(\n \"typography-caption-semibold inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 tabular-nums leading-none\",\n variant === \"default\" && \"bg-error-500 text-body-white-solid-constant\",\n variant === \"brand\" && \"bg-brand-green-500 text-body-black-solid-constant\",\n variant === \"pink\" && \"bg-brand-pink-500 text-body-black-solid-constant\",\n variant === \"info\" && \"bg-info-500 text-body-white-solid-constant\",\n variant === \"success\" && \"bg-success-500 text-body-white-solid-constant\",\n variant === \"warning\" && \"bg-warning-500 text-body-black-solid-constant\",\n className,\n )}\n {...props}\n >\n {children ?? getDisplayValue(value, max)}\n </Comp>\n );\n },\n);\n\nCount.displayName = \"Count\";\n"],"names":[],"mappings":";;;;;AAMA,SAAS,gBAAgB,OAAe,KAAqB;AAC3D,SAAO,QAAQ,MAAM,GAAG,GAAG,MAAM,MAAM,SAAA;AACzC;AAaO,MAAM,QAAQ,MAAM;AAAA,EACzB,CACE,EAAE,WAAW,UAAU,WAAW,QAAQ,GAAG,MAAM,IAAI,UAAU,OAAO,UAAU,GAAG,MAAA,GACrF,QACG;AACH,QAAI,UAAU,KAAK,CAAC,UAAU;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,UAAU,OAAO;AAE9B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,YAAY,aAAa;AAAA,UACzB,YAAY,WAAW;AAAA,UACvB,YAAY,UAAU;AAAA,UACtB,YAAY,UAAU;AAAA,UACtB,YAAY,aAAa;AAAA,UACzB,YAAY,aAAa;AAAA,UACzB;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA,YAAY,gBAAgB,OAAO,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAG7C;AACF;AAEA,MAAM,cAAc;"}