@shipfox/react-ui 0.3.0 → 0.5.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 (314) hide show
  1. package/.storybook/main.ts +20 -10
  2. package/.storybook/preview.tsx +1 -1
  3. package/.storybook/vitest.setup.ts +4 -0
  4. package/.turbo/turbo-build.log +2 -2
  5. package/.turbo/turbo-check.log +2 -2
  6. package/.turbo/turbo-type.log +1 -1
  7. package/CHANGELOG.md +18 -0
  8. package/README.md +40 -1
  9. package/argos.config.ts +33 -0
  10. package/dist/components/alert/alert.d.ts +2 -2
  11. package/dist/components/alert/alert.js +3 -3
  12. package/dist/components/alert/alert.js.map +1 -1
  13. package/dist/components/alert/alert.stories.js +2 -2
  14. package/dist/components/alert/alert.stories.js.map +1 -1
  15. package/dist/components/avatar/avatar-group.js +3 -3
  16. package/dist/components/avatar/avatar-group.js.map +1 -1
  17. package/dist/components/avatar/avatar.d.ts +4 -1
  18. package/dist/components/avatar/avatar.d.ts.map +1 -1
  19. package/dist/components/avatar/avatar.js +7 -8
  20. package/dist/components/avatar/avatar.js.map +1 -1
  21. package/dist/components/avatar/avatar.stories.js +15 -3
  22. package/dist/components/avatar/avatar.stories.js.map +1 -1
  23. package/dist/components/badge/badge.d.ts +48 -0
  24. package/dist/components/badge/badge.d.ts.map +1 -0
  25. package/dist/components/badge/badge.js +72 -0
  26. package/dist/components/badge/badge.js.map +1 -0
  27. package/dist/components/badge/badge.stories.js +802 -0
  28. package/dist/components/badge/badge.stories.js.map +1 -0
  29. package/dist/components/badge/icon-badge.d.ts +9 -0
  30. package/dist/components/badge/icon-badge.d.ts.map +1 -0
  31. package/dist/components/badge/icon-badge.js +32 -0
  32. package/dist/components/badge/icon-badge.js.map +1 -0
  33. package/dist/components/badge/index.d.ts +5 -0
  34. package/dist/components/badge/index.d.ts.map +1 -0
  35. package/dist/components/badge/index.js +6 -0
  36. package/dist/components/badge/index.js.map +1 -0
  37. package/dist/components/badge/status-badge.d.ts +9 -0
  38. package/dist/components/badge/status-badge.d.ts.map +1 -0
  39. package/dist/components/badge/status-badge.js +29 -0
  40. package/dist/components/badge/status-badge.js.map +1 -0
  41. package/dist/components/badge/user-badge.d.ts +8 -0
  42. package/dist/components/badge/user-badge.d.ts.map +1 -0
  43. package/dist/components/badge/user-badge.js +24 -0
  44. package/dist/components/badge/user-badge.js.map +1 -0
  45. package/dist/components/button/button-link.d.ts +14 -0
  46. package/dist/components/button/button-link.d.ts.map +1 -0
  47. package/dist/components/button/button-link.js +63 -0
  48. package/dist/components/button/button-link.js.map +1 -0
  49. package/dist/components/button/button-link.stories.js +127 -0
  50. package/dist/components/button/button-link.stories.js.map +1 -0
  51. package/dist/components/{button.d.ts → button/button.d.ts} +2 -2
  52. package/dist/components/button/button.d.ts.map +1 -0
  53. package/dist/components/{button.js → button/button.js} +9 -8
  54. package/dist/components/button/button.js.map +1 -0
  55. package/dist/components/{button.stories.js → button/button.stories.js} +2 -14
  56. package/dist/components/button/button.stories.js.map +1 -0
  57. package/dist/components/button/icon-button.d.ts +14 -0
  58. package/dist/components/button/icon-button.d.ts.map +1 -0
  59. package/dist/components/button/icon-button.js +53 -0
  60. package/dist/components/button/icon-button.js.map +1 -0
  61. package/dist/components/button/icon-button.stories.js +254 -0
  62. package/dist/components/button/icon-button.stories.js.map +1 -0
  63. package/dist/components/button/index.d.ts +4 -0
  64. package/dist/components/button/index.d.ts.map +1 -0
  65. package/dist/components/button/index.js +5 -0
  66. package/dist/components/button/index.js.map +1 -0
  67. package/dist/components/checkbox/checkbox-label.d.ts +14 -0
  68. package/dist/components/checkbox/checkbox-label.d.ts.map +1 -0
  69. package/dist/components/checkbox/checkbox-label.js +82 -0
  70. package/dist/components/checkbox/checkbox-label.js.map +1 -0
  71. package/dist/components/checkbox/checkbox-links.d.ts +18 -0
  72. package/dist/components/checkbox/checkbox-links.d.ts.map +1 -0
  73. package/dist/components/checkbox/checkbox-links.js +58 -0
  74. package/dist/components/checkbox/checkbox-links.js.map +1 -0
  75. package/dist/components/checkbox/checkbox.d.ts +9 -0
  76. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  77. package/dist/components/checkbox/checkbox.js +49 -0
  78. package/dist/components/checkbox/checkbox.js.map +1 -0
  79. package/dist/components/checkbox/checkbox.stories.js +566 -0
  80. package/dist/components/checkbox/checkbox.stories.js.map +1 -0
  81. package/dist/components/checkbox/index.d.ts +4 -0
  82. package/dist/components/checkbox/index.d.ts.map +1 -0
  83. package/dist/components/checkbox/index.js +5 -0
  84. package/dist/components/checkbox/index.js.map +1 -0
  85. package/dist/components/code-block/code-block-footer.d.ts +26 -0
  86. package/dist/components/code-block/code-block-footer.d.ts.map +1 -0
  87. package/dist/components/code-block/code-block-footer.js +86 -0
  88. package/dist/components/code-block/code-block-footer.js.map +1 -0
  89. package/dist/components/code-block/code-block.d.ts +50 -0
  90. package/dist/components/code-block/code-block.d.ts.map +1 -0
  91. package/dist/components/code-block/code-block.js +142 -0
  92. package/dist/components/code-block/code-block.js.map +1 -0
  93. package/dist/components/code-block/code-block.stories.js +341 -0
  94. package/dist/components/code-block/code-block.stories.js.map +1 -0
  95. package/dist/components/code-block/code-content.d.ts +11 -0
  96. package/dist/components/code-block/code-content.d.ts.map +1 -0
  97. package/dist/components/code-block/code-content.js +29 -0
  98. package/dist/components/code-block/code-content.js.map +1 -0
  99. package/dist/components/code-block/code-copy-button.d.ts +11 -0
  100. package/dist/components/code-block/code-copy-button.d.ts.map +1 -0
  101. package/dist/components/code-block/code-copy-button.js +49 -0
  102. package/dist/components/code-block/code-copy-button.js.map +1 -0
  103. package/dist/components/code-block/code-tabs.d.ts +16 -0
  104. package/dist/components/code-block/code-tabs.d.ts.map +1 -0
  105. package/dist/components/code-block/code-tabs.js +98 -0
  106. package/dist/components/code-block/code-tabs.js.map +1 -0
  107. package/dist/components/code-block/index.d.ts +4 -0
  108. package/dist/components/code-block/index.d.ts.map +1 -0
  109. package/dist/components/code-block/index.js +5 -0
  110. package/dist/components/code-block/index.js.map +1 -0
  111. package/dist/components/dynamic-item/dynamic-item.d.ts +13 -0
  112. package/dist/components/dynamic-item/dynamic-item.d.ts.map +1 -0
  113. package/dist/components/dynamic-item/dynamic-item.js +43 -0
  114. package/dist/components/dynamic-item/dynamic-item.js.map +1 -0
  115. package/dist/components/dynamic-item/dynamic-item.stories.js +375 -0
  116. package/dist/components/dynamic-item/dynamic-item.stories.js.map +1 -0
  117. package/dist/components/dynamic-item/index.d.ts +2 -0
  118. package/dist/components/dynamic-item/index.d.ts.map +1 -0
  119. package/dist/components/dynamic-item/index.js +3 -0
  120. package/dist/components/dynamic-item/index.js.map +1 -0
  121. package/dist/components/icon/custom/index.d.ts +2 -0
  122. package/dist/components/icon/custom/index.d.ts.map +1 -1
  123. package/dist/components/icon/custom/index.js +2 -0
  124. package/dist/components/icon/custom/index.js.map +1 -1
  125. package/dist/components/icon/custom/slack-logo.d.ts +6 -0
  126. package/dist/components/icon/custom/slack-logo.d.ts.map +1 -0
  127. package/dist/components/icon/custom/slack-logo.js +34 -0
  128. package/dist/components/icon/custom/slack-logo.js.map +1 -0
  129. package/dist/components/icon/custom/stripe-logo.d.ts +8 -0
  130. package/dist/components/icon/custom/stripe-logo.d.ts.map +1 -0
  131. package/dist/components/icon/custom/stripe-logo.js +24 -0
  132. package/dist/components/icon/custom/stripe-logo.js.map +1 -0
  133. package/dist/components/icon/icon.d.ts +13 -2
  134. package/dist/components/icon/icon.d.ts.map +1 -1
  135. package/dist/components/icon/icon.js +14 -3
  136. package/dist/components/icon/icon.js.map +1 -1
  137. package/dist/components/icon/icon.stories.js +6 -3
  138. package/dist/components/icon/icon.stories.js.map +1 -1
  139. package/dist/components/index.d.ts +9 -1
  140. package/dist/components/index.d.ts.map +1 -1
  141. package/dist/components/index.js +10 -2
  142. package/dist/components/index.js.map +1 -1
  143. package/dist/components/inline-tips/inline-tips.d.ts +1 -1
  144. package/dist/components/inline-tips/inline-tips.d.ts.map +1 -1
  145. package/dist/components/inline-tips/inline-tips.js +1 -1
  146. package/dist/components/inline-tips/inline-tips.js.map +1 -1
  147. package/dist/components/inline-tips/inline-tips.stories.js +5 -5
  148. package/dist/components/inline-tips/inline-tips.stories.js.map +1 -1
  149. package/dist/components/input/index.d.ts +2 -0
  150. package/dist/components/input/index.d.ts.map +1 -0
  151. package/dist/components/input/index.js +3 -0
  152. package/dist/components/input/index.js.map +1 -0
  153. package/dist/components/input/input.d.ts.map +1 -0
  154. package/dist/components/{input.js → input/input.js} +2 -2
  155. package/dist/components/input/input.js.map +1 -0
  156. package/dist/components/{input.stories.js → input/input.stories.js} +1 -1
  157. package/dist/components/input/input.stories.js.map +1 -0
  158. package/dist/components/item/index.d.ts +2 -0
  159. package/dist/components/item/index.d.ts.map +1 -0
  160. package/dist/components/item/index.js +3 -0
  161. package/dist/components/item/index.js.map +1 -0
  162. package/dist/components/item/item.d.ts +32 -0
  163. package/dist/components/item/item.d.ts.map +1 -0
  164. package/dist/components/item/item.js +120 -0
  165. package/dist/components/item/item.js.map +1 -0
  166. package/dist/components/item/item.stories.js +232 -0
  167. package/dist/components/item/item.stories.js.map +1 -0
  168. package/dist/components/label/index.d.ts +2 -0
  169. package/dist/components/label/index.d.ts.map +1 -0
  170. package/dist/components/label/index.js +3 -0
  171. package/dist/components/label/index.js.map +1 -0
  172. package/dist/components/label/label.d.ts +7 -0
  173. package/dist/components/label/label.d.ts.map +1 -0
  174. package/dist/components/label/label.js +13 -0
  175. package/dist/components/label/label.js.map +1 -0
  176. package/dist/components/label/label.stories.js +105 -0
  177. package/dist/components/label/label.stories.js.map +1 -0
  178. package/dist/components/moving-border/moving-border.d.ts +9 -0
  179. package/dist/components/moving-border/moving-border.d.ts.map +1 -0
  180. package/dist/components/moving-border/moving-border.js +54 -0
  181. package/dist/components/moving-border/moving-border.js.map +1 -0
  182. package/dist/components/textarea/textarea.js +1 -1
  183. package/dist/components/textarea/textarea.js.map +1 -1
  184. package/dist/components/theme/index.d.ts +2 -0
  185. package/dist/components/theme/index.d.ts.map +1 -0
  186. package/dist/components/theme/index.js +3 -0
  187. package/dist/components/theme/index.js.map +1 -0
  188. package/dist/components/{theme-provider.d.ts → theme/theme-provider.d.ts} +1 -1
  189. package/dist/components/theme/theme-provider.d.ts.map +1 -0
  190. package/dist/components/{theme-provider.js → theme/theme-provider.js} +1 -1
  191. package/dist/components/theme/theme-provider.js.map +1 -0
  192. package/dist/components/toast/index.d.ts +3 -0
  193. package/dist/components/toast/index.d.ts.map +1 -0
  194. package/dist/components/toast/index.js +4 -0
  195. package/dist/components/toast/index.js.map +1 -0
  196. package/dist/components/toast/toast-custom.d.ts +19 -0
  197. package/dist/components/toast/toast-custom.d.ts.map +1 -0
  198. package/dist/components/toast/toast-custom.js +134 -0
  199. package/dist/components/toast/toast-custom.js.map +1 -0
  200. package/dist/components/toast/toast.d.ts +5 -0
  201. package/dist/components/toast/toast.d.ts.map +1 -0
  202. package/dist/components/toast/toast.js +40 -0
  203. package/dist/components/toast/toast.js.map +1 -0
  204. package/dist/components/toast/toast.stories.js +326 -0
  205. package/dist/components/toast/toast.stories.js.map +1 -0
  206. package/dist/components/tooltip/index.d.ts +2 -0
  207. package/dist/components/tooltip/index.d.ts.map +1 -0
  208. package/dist/components/tooltip/index.js +3 -0
  209. package/dist/components/tooltip/index.js.map +1 -0
  210. package/dist/components/tooltip/tooltip.d.ts +18 -5
  211. package/dist/components/tooltip/tooltip.d.ts.map +1 -1
  212. package/dist/components/tooltip/tooltip.js +63 -3
  213. package/dist/components/tooltip/tooltip.js.map +1 -1
  214. package/dist/components/tooltip/tooltip.stories.js +560 -0
  215. package/dist/components/tooltip/tooltip.stories.js.map +1 -0
  216. package/dist/hooks/index.d.ts +3 -0
  217. package/dist/hooks/index.d.ts.map +1 -1
  218. package/dist/hooks/index.js +3 -0
  219. package/dist/hooks/index.js.map +1 -1
  220. package/dist/hooks/useResolvedTheme.d.ts +2 -0
  221. package/dist/hooks/useResolvedTheme.d.ts.map +1 -0
  222. package/dist/hooks/useResolvedTheme.js +24 -0
  223. package/dist/hooks/useResolvedTheme.js.map +1 -0
  224. package/dist/hooks/useShikiHighlight.d.ts +28 -0
  225. package/dist/hooks/useShikiHighlight.d.ts.map +1 -0
  226. package/dist/hooks/useShikiHighlight.js +106 -0
  227. package/dist/hooks/useShikiHighlight.js.map +1 -0
  228. package/dist/hooks/useShikiStyleInjection.d.ts +2 -0
  229. package/dist/hooks/useShikiStyleInjection.d.ts.map +1 -0
  230. package/dist/hooks/useShikiStyleInjection.js +34 -0
  231. package/dist/hooks/useShikiStyleInjection.js.map +1 -0
  232. package/dist/onboarding/sign-in.stories.js +93 -0
  233. package/dist/onboarding/sign-in.stories.js.map +1 -0
  234. package/index.css +130 -12
  235. package/package.json +14 -3
  236. package/src/assets/illustration-1.svg +92 -0
  237. package/src/assets/illustration-2.svg +14 -0
  238. package/src/assets/illustration-gradient.svg +7049 -0
  239. package/src/components/alert/alert.stories.tsx +2 -2
  240. package/src/components/alert/alert.tsx +3 -3
  241. package/src/components/avatar/avatar-group.tsx +3 -3
  242. package/src/components/avatar/avatar.stories.tsx +9 -2
  243. package/src/components/avatar/avatar.tsx +10 -6
  244. package/src/components/badge/badge.stories.tsx +468 -0
  245. package/src/components/badge/badge.tsx +147 -0
  246. package/src/components/badge/icon-badge.tsx +43 -0
  247. package/src/components/badge/index.ts +4 -0
  248. package/src/components/badge/status-badge.tsx +43 -0
  249. package/src/components/badge/user-badge.tsx +34 -0
  250. package/src/components/button/button-link.stories.tsx +86 -0
  251. package/src/components/button/button-link.tsx +76 -0
  252. package/src/components/{button.stories.tsx → button/button.stories.tsx} +1 -7
  253. package/src/components/{button.tsx → button/button.tsx} +9 -7
  254. package/src/components/button/icon-button.stories.tsx +182 -0
  255. package/src/components/button/icon-button.tsx +69 -0
  256. package/src/components/button/index.ts +3 -0
  257. package/src/components/checkbox/checkbox-label.tsx +125 -0
  258. package/src/components/checkbox/checkbox-links.tsx +90 -0
  259. package/src/components/checkbox/checkbox.stories.tsx +375 -0
  260. package/src/components/checkbox/checkbox.tsx +71 -0
  261. package/src/components/checkbox/index.ts +3 -0
  262. package/src/components/code-block/code-block-footer.tsx +173 -0
  263. package/src/components/code-block/code-block.stories.tsx +323 -0
  264. package/src/components/code-block/code-block.tsx +283 -0
  265. package/src/components/code-block/code-content.tsx +63 -0
  266. package/src/components/code-block/code-copy-button.tsx +73 -0
  267. package/src/components/code-block/code-tabs.tsx +170 -0
  268. package/src/components/code-block/index.ts +3 -0
  269. package/src/components/dynamic-item/dynamic-item.stories.tsx +261 -0
  270. package/src/components/dynamic-item/dynamic-item.tsx +68 -0
  271. package/src/components/dynamic-item/index.ts +1 -0
  272. package/src/components/icon/custom/index.ts +2 -0
  273. package/src/components/icon/custom/slack-logo.tsx +35 -0
  274. package/src/components/icon/custom/stripe-logo.tsx +27 -0
  275. package/src/components/icon/icon.stories.tsx +3 -1
  276. package/src/components/icon/icon.tsx +23 -1
  277. package/src/components/index.ts +9 -1
  278. package/src/components/inline-tips/inline-tips.stories.tsx +3 -3
  279. package/src/components/inline-tips/inline-tips.tsx +2 -2
  280. package/src/components/input/index.ts +1 -0
  281. package/src/components/{input.tsx → input/input.tsx} +1 -1
  282. package/src/components/item/index.ts +1 -0
  283. package/src/components/item/item.stories.tsx +150 -0
  284. package/src/components/item/item.tsx +182 -0
  285. package/src/components/label/index.ts +1 -0
  286. package/src/components/label/label.stories.tsx +67 -0
  287. package/src/components/label/label.tsx +15 -0
  288. package/src/components/moving-border/moving-border.tsx +67 -0
  289. package/src/components/textarea/textarea.tsx +1 -1
  290. package/src/components/theme/index.ts +1 -0
  291. package/src/components/toast/index.ts +2 -0
  292. package/src/components/toast/toast-custom.tsx +154 -0
  293. package/src/components/toast/toast.stories.tsx +369 -0
  294. package/src/components/toast/toast.tsx +41 -0
  295. package/src/components/tooltip/index.ts +1 -0
  296. package/src/components/tooltip/tooltip.stories.tsx +284 -0
  297. package/src/components/tooltip/tooltip.tsx +79 -10
  298. package/src/hooks/index.ts +3 -0
  299. package/src/hooks/useResolvedTheme.ts +34 -0
  300. package/src/hooks/useShikiHighlight.ts +140 -0
  301. package/src/hooks/useShikiStyleInjection.ts +34 -0
  302. package/src/onboarding/sign-in.stories.tsx +73 -0
  303. package/vitest.config.ts +30 -3
  304. package/dist/components/button.d.ts.map +0 -1
  305. package/dist/components/button.js.map +0 -1
  306. package/dist/components/button.stories.js.map +0 -1
  307. package/dist/components/input.d.ts.map +0 -1
  308. package/dist/components/input.js.map +0 -1
  309. package/dist/components/input.stories.js.map +0 -1
  310. package/dist/components/theme-provider.d.ts.map +0 -1
  311. package/dist/components/theme-provider.js.map +0 -1
  312. /package/dist/components/{input.d.ts → input/input.d.ts} +0 -0
  313. /package/src/components/{input.stories.tsx → input/input.stories.tsx} +0 -0
  314. /package/src/components/{theme-provider.tsx → theme/theme-provider.tsx} +0 -0
@@ -0,0 +1,69 @@
1
+ import {Slot} from '@radix-ui/react-slot';
2
+ import {cva, type VariantProps} from 'class-variance-authority';
3
+ import {Icon, type IconName} from 'components/icon';
4
+ import type {ComponentProps} from 'react';
5
+ import {cn} from 'utils/cn';
6
+
7
+ export const iconButtonVariants = cva(
8
+ 'inline-flex items-center justify-center whitespace-nowrap transition-colors disabled:pointer-events-none shrink-0 outline-none',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ primary:
13
+ 'bg-background-button-inverted-default text-tag-neutral-icon shadow-button-inverted hover:bg-background-button-inverted-hover active:bg-background-button-inverted-pressed focus-visible:shadow-button-inverted-focus disabled:bg-background-neutral-disabled disabled:text-foreground-neutral-disabled disabled:shadow-none',
14
+ transparent:
15
+ 'bg-background-button-transparent-default text-tag-neutral-icon hover:bg-background-button-transparent-hover active:bg-background-button-transparent-pressed focus-visible:shadow-button-neutral-focus disabled:text-foreground-neutral-disabled',
16
+ },
17
+ size: {
18
+ '2xs': 'w-20 h-20 text-xs',
19
+ xs: 'w-24 h-24 text-xs',
20
+ sm: 'w-28 h-28 text-sm',
21
+ md: 'w-32 h-32 text-md',
22
+ lg: 'w-36 h-36 text-lg',
23
+ xl: 'w-40 h-40 text-xl',
24
+ },
25
+ radius: {
26
+ rounded: 'rounded-6',
27
+ full: 'rounded-full',
28
+ },
29
+ muted: {
30
+ true: 'opacity-60',
31
+ false: '',
32
+ },
33
+ },
34
+ defaultVariants: {
35
+ variant: 'primary',
36
+ size: 'md',
37
+ radius: 'rounded',
38
+ muted: false,
39
+ },
40
+ },
41
+ );
42
+
43
+ export function IconButton({
44
+ className,
45
+ variant,
46
+ size,
47
+ radius,
48
+ muted,
49
+ asChild = false,
50
+ children,
51
+ icon,
52
+ ...props
53
+ }: ComponentProps<'button'> &
54
+ VariantProps<typeof iconButtonVariants> & {
55
+ asChild?: boolean;
56
+ icon?: IconName;
57
+ }) {
58
+ const Comp = asChild ? Slot : 'button';
59
+
60
+ return (
61
+ <Comp
62
+ data-slot="icon-button"
63
+ className={cn(iconButtonVariants({variant, size, radius, muted}), className)}
64
+ {...props}
65
+ >
66
+ {icon ? <Icon name={icon} /> : children}
67
+ </Comp>
68
+ );
69
+ }
@@ -0,0 +1,3 @@
1
+ export * from './button';
2
+ export * from './button-link';
3
+ export * from './icon-button';
@@ -0,0 +1,125 @@
1
+ import {useId} from 'react';
2
+ import {cn} from 'utils/cn';
3
+ import {Icon} from '../icon/icon';
4
+ import {Label} from '../label/label';
5
+ import {Checkbox, type CheckboxProps} from './checkbox';
6
+
7
+ export type CheckboxLabelProps = Omit<CheckboxProps, 'id'> & {
8
+ id?: string;
9
+ label: string;
10
+ optional?: boolean;
11
+ description?: string;
12
+ showInfoIcon?: boolean;
13
+ border?: boolean;
14
+ className?: string;
15
+ labelClassName?: string;
16
+ descriptionClassName?: string;
17
+ };
18
+
19
+ export function CheckboxLabel({
20
+ id,
21
+ label,
22
+ optional = false,
23
+ description,
24
+ showInfoIcon = false,
25
+ border = false,
26
+ className,
27
+ labelClassName,
28
+ descriptionClassName,
29
+ ...checkboxProps
30
+ }: CheckboxLabelProps) {
31
+ const generateId = useId();
32
+ const checkboxId = id || generateId;
33
+ const isDisabled = checkboxProps.disabled ?? false;
34
+
35
+ const renderContent = (checkboxId: string) => (
36
+ <div className="flex flex-col gap-4 flex-1 min-w-0">
37
+ <div className="flex gap-4 items-center">
38
+ <Label
39
+ className={cn(
40
+ 'text-sm leading-20 overflow-hidden text-ellipsis whitespace-nowrap',
41
+ isDisabled
42
+ ? 'font-normal text-foreground-neutral-subtle'
43
+ : 'font-medium text-foreground-neutral-base',
44
+ labelClassName,
45
+ )}
46
+ htmlFor={checkboxId}
47
+ >
48
+ {label}
49
+ </Label>
50
+ {optional && (
51
+ <span className="text-sm leading-20 font-regular text-foreground-neutral-muted whitespace-nowrap">
52
+ (Optional)
53
+ </span>
54
+ )}
55
+ {showInfoIcon && (
56
+ <Icon
57
+ name="info"
58
+ className="size-16 text-foreground-neutral-muted shrink-0"
59
+ aria-hidden="true"
60
+ />
61
+ )}
62
+ </div>
63
+ {description && (
64
+ <p
65
+ className={cn(
66
+ 'text-sm leading-20',
67
+ isDisabled ? 'text-foreground-neutral-disabled' : 'text-foreground-neutral-subtle',
68
+ descriptionClassName,
69
+ )}
70
+ >
71
+ {description}
72
+ </p>
73
+ )}
74
+ </div>
75
+ );
76
+
77
+ if (border) {
78
+ return (
79
+ <Label
80
+ htmlFor={checkboxId}
81
+ className={cn(
82
+ // Base container styles with border
83
+ 'flex items-start gap-10 rounded-8 p-8 transition-all duration-100',
84
+ // Unchecked state - default
85
+ 'bg-checkbox-unchecked-bg shadow-checkbox-unchecked',
86
+ // Unchecked state - hover
87
+ 'hover:bg-checkbox-unchecked-bg-hover',
88
+ // Unchecked state - focus
89
+ 'has-data-[state=unchecked]:focus-visible:shadow-border-interactive-with-active',
90
+ // Checked state - default
91
+ 'has-data-[state=checked]:bg-background-neutral-base has-data-[state=checked]:shadow-checkbox-checked',
92
+ // Checked state - hover
93
+ 'has-data-[state=checked]:hover:bg-background-neutral-hover',
94
+ // Checked state - focus
95
+ 'has-data-[state=checked]:focus-visible:shadow-checkbox-checked-focus',
96
+ // Indeterminate state - default
97
+ 'has-data-[state=indeterminate]:bg-background-neutral-base has-data-[state=indeterminate]:shadow-checkbox-indeterminate',
98
+ // Indeterminate state - hover
99
+ 'has-data-[state=indeterminate]:hover:bg-background-neutral-hover',
100
+ // Indeterminate state - focus
101
+ 'has-data-[state=indeterminate]:focus-visible:shadow-checkbox-indeterminate-focus',
102
+ // Disabled state
103
+ isDisabled && 'opacity-50 cursor-not-allowed',
104
+ !isDisabled && 'cursor-pointer',
105
+ className,
106
+ )}
107
+ >
108
+ <span className="p-4">
109
+ <Checkbox id={checkboxId} {...checkboxProps} />
110
+ </span>
111
+ {renderContent(checkboxId)}
112
+ </Label>
113
+ );
114
+ }
115
+
116
+ // Without border variant
117
+ return (
118
+ <div className={cn('flex items-start gap-10', className)}>
119
+ <span className="p-2">
120
+ <Checkbox id={checkboxId} {...checkboxProps} />
121
+ </span>
122
+ {renderContent(checkboxId)}
123
+ </div>
124
+ );
125
+ }
@@ -0,0 +1,90 @@
1
+ import {Label} from 'components/label';
2
+ import {type ReactNode, useId} from 'react';
3
+ import {cn} from 'utils/cn';
4
+ import {Checkbox, type CheckboxProps} from './checkbox';
5
+
6
+ export type CheckboxLink = {
7
+ label: string;
8
+ href?: string;
9
+ onClick?: () => void;
10
+ };
11
+
12
+ export type CheckboxLinksProps = Omit<CheckboxProps, 'id'> & {
13
+ id?: string;
14
+ label: string;
15
+ links: CheckboxLink[];
16
+ separator?: ReactNode;
17
+ className?: string;
18
+ labelClassName?: string;
19
+ linkClassName?: string;
20
+ };
21
+
22
+ export function CheckboxLinks({
23
+ id,
24
+ label,
25
+ links,
26
+ separator,
27
+ className,
28
+ labelClassName,
29
+ linkClassName,
30
+ ...checkboxProps
31
+ }: CheckboxLinksProps) {
32
+ const generateId = useId();
33
+ const checkboxId = id || generateId;
34
+ const isDisabled = checkboxProps.disabled ?? false;
35
+ const defaultSeparator = (
36
+ <span className="size-3 rounded-full bg-foreground-neutral-muted" aria-hidden="true" />
37
+ );
38
+
39
+ return (
40
+ <div className={cn('flex gap-10 items-start', className)}>
41
+ <span className="p-2">
42
+ <Checkbox id={checkboxId} {...checkboxProps} />
43
+ </span>
44
+ <div className="flex flex-col gap-4 items-start flex-1">
45
+ <Label
46
+ htmlFor={checkboxId}
47
+ className={cn(
48
+ 'text-sm leading-20 font-medium text-foreground-neutral-base',
49
+ isDisabled && 'cursor-not-allowed opacity-50',
50
+ labelClassName,
51
+ )}
52
+ >
53
+ {label}
54
+ </Label>
55
+ <div className="flex gap-6 items-center">
56
+ {links.map((link, index) => (
57
+ <div key={link.label} className="flex gap-6 items-center">
58
+ {link.href ? (
59
+ <a
60
+ href={link.href}
61
+ onClick={link.onClick}
62
+ className={cn(
63
+ 'text-sm leading-20 font-medium text-foreground-highlight-interactive',
64
+ 'hover:text-foreground-highlight-interactive-hover',
65
+ linkClassName,
66
+ )}
67
+ >
68
+ {link.label}
69
+ </a>
70
+ ) : (
71
+ <button
72
+ type="button"
73
+ onClick={link.onClick}
74
+ className={cn(
75
+ 'text-sm leading-20 font-medium text-foreground-highlight-interactive',
76
+ 'hover:text-foreground-highlight-interactive-hover',
77
+ linkClassName,
78
+ )}
79
+ >
80
+ {link.label}
81
+ </button>
82
+ )}
83
+ {index < links.length - 1 && (separator ?? defaultSeparator)}
84
+ </div>
85
+ ))}
86
+ </div>
87
+ </div>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,375 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code, Header} from 'components/typography';
3
+ import {Checkbox, CheckboxLabel, CheckboxLinks} from '.';
4
+
5
+ const meta = {
6
+ title: 'Components/Checkbox',
7
+ component: Checkbox,
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ size: {
11
+ control: 'select',
12
+ options: ['sm', 'md', 'lg'],
13
+ },
14
+ disabled: {control: 'boolean'},
15
+ checked: {control: 'boolean'},
16
+ },
17
+ args: {
18
+ size: 'md',
19
+ disabled: false,
20
+ },
21
+ } satisfies Meta<typeof Checkbox>;
22
+
23
+ export default meta;
24
+
25
+ type Story = StoryObj<typeof meta>;
26
+
27
+ export const Default: Story = {
28
+ render: (args) => (
29
+ <div className="flex flex-col gap-32">
30
+ <div className="flex flex-col gap-16">
31
+ <Header variant="h4">Controlled Checkbox</Header>
32
+ <Code variant="label" className="text-foreground-neutral-subtle">
33
+ Use the controls below to change the checkbox state
34
+ </Code>
35
+ <Checkbox {...args} />
36
+ </div>
37
+
38
+ <div className="flex flex-col gap-32">
39
+ <Header variant="h4">All States</Header>
40
+ {(['sm', 'md', 'lg'] as const).map((size) => (
41
+ <div key={size} className="flex flex-wrap gap-16">
42
+ <Header variant="h4">Size: {size}</Header>
43
+ <div className="flex flex-col gap-8">
44
+ <Code variant="label" className="text-foreground-neutral-subtle">
45
+ Unchecked
46
+ </Code>
47
+ <Checkbox size={size} />
48
+ </div>
49
+ <div className="flex flex-col gap-8">
50
+ <Code variant="label" className="text-foreground-neutral-subtle">
51
+ Checked
52
+ </Code>
53
+ <Checkbox size={size} checked />
54
+ </div>
55
+ <div className="flex flex-col gap-8">
56
+ <Code variant="label" className="text-foreground-neutral-subtle">
57
+ Indeterminate
58
+ </Code>
59
+ <Checkbox size={size} checked="indeterminate" />
60
+ </div>
61
+ <div className="flex flex-col gap-8">
62
+ <Code variant="label" className="text-foreground-neutral-subtle">
63
+ Disabled (Unchecked)
64
+ </Code>
65
+ <Checkbox size={size} disabled />
66
+ </div>
67
+ <div className="flex flex-col gap-8">
68
+ <Code variant="label" className="text-foreground-neutral-subtle">
69
+ Disabled (Checked)
70
+ </Code>
71
+ <Checkbox size={size} checked disabled />
72
+ </div>
73
+ <div className="flex flex-col gap-8">
74
+ <Code variant="label" className="text-foreground-neutral-subtle">
75
+ Focus
76
+ </Code>
77
+ <Checkbox size={size} className="focus" />
78
+ </div>
79
+ </div>
80
+ ))}
81
+ </div>
82
+ </div>
83
+ ),
84
+ parameters: {
85
+ pseudo: {
86
+ focusVisible: '.focus',
87
+ },
88
+ },
89
+ };
90
+
91
+ export const CheckboxLabelStory: StoryObj = {
92
+ render: () => (
93
+ <div className="flex flex-col gap-32 pb-64 pt-32 px-32 bg-background-neutral-base">
94
+ <Code variant="label" className="text-foreground-neutral-subtle">
95
+ CHECKBOX LABEL - WITHOUT BORDER
96
+ </Code>
97
+ <div className="flex flex-col gap-16">
98
+ <div className="flex flex-col gap-8">
99
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
100
+ Default - Unchecked
101
+ </Code>
102
+ <CheckboxLabel
103
+ label="Label"
104
+ optional
105
+ showInfoIcon
106
+ description="The quick brown fox jumps over a lazy dog."
107
+ />
108
+ </div>
109
+ <div className="flex flex-col gap-8">
110
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
111
+ Hover - Unchecked
112
+ </Code>
113
+ <CheckboxLabel
114
+ label="Label"
115
+ optional
116
+ showInfoIcon
117
+ description="The quick brown fox jumps over a lazy dog."
118
+ className="hover"
119
+ />
120
+ </div>
121
+ <div className="flex flex-col gap-8">
122
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
123
+ Default - Checked
124
+ </Code>
125
+ <CheckboxLabel
126
+ label="Label"
127
+ optional
128
+ showInfoIcon
129
+ description="The quick brown fox jumps over a lazy dog."
130
+ checked
131
+ />
132
+ </div>
133
+ <div className="flex flex-col gap-8">
134
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
135
+ Hover - Checked
136
+ </Code>
137
+ <CheckboxLabel
138
+ label="Label"
139
+ optional
140
+ showInfoIcon
141
+ description="The quick brown fox jumps over a lazy dog."
142
+ checked
143
+ className="hover"
144
+ />
145
+ </div>
146
+ <div className="flex flex-col gap-8">
147
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
148
+ Default - Indeterminate
149
+ </Code>
150
+ <CheckboxLabel
151
+ label="Label"
152
+ optional
153
+ showInfoIcon
154
+ description="The quick brown fox jumps over a lazy dog."
155
+ checked="indeterminate"
156
+ />
157
+ </div>
158
+ <div className="flex flex-col gap-8">
159
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
160
+ Disabled - Checked
161
+ </Code>
162
+ <CheckboxLabel
163
+ label="Label"
164
+ checked
165
+ optional
166
+ showInfoIcon
167
+ description="The quick brown fox jumps over a lazy dog."
168
+ disabled
169
+ />
170
+ </div>
171
+ <div className="flex flex-col gap-8">
172
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
173
+ Disabled - Unchecked
174
+ </Code>
175
+ <CheckboxLabel
176
+ label="Label"
177
+ optional
178
+ showInfoIcon
179
+ description="The quick brown fox jumps over a lazy dog."
180
+ disabled
181
+ />
182
+ </div>
183
+ </div>
184
+
185
+ <Code variant="label" className="text-foreground-neutral-subtle mt-32">
186
+ CHECKBOX LABEL - WITH BORDER
187
+ </Code>
188
+ <div className="flex flex-col gap-16">
189
+ <div className="flex flex-col gap-8">
190
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
191
+ Default - Unchecked
192
+ </Code>
193
+ <CheckboxLabel
194
+ id="checkbox-border-default-unchecked"
195
+ label="Label"
196
+ optional
197
+ showInfoIcon
198
+ description="The quick brown fox jumps over a lazy dog."
199
+ border
200
+ />
201
+ </div>
202
+ <div className="flex flex-col gap-8">
203
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
204
+ Hover - Unchecked
205
+ </Code>
206
+ <CheckboxLabel
207
+ id="checkbox-border-hover-unchecked"
208
+ label="Label"
209
+ optional
210
+ showInfoIcon
211
+ description="The quick brown fox jumps over a lazy dog."
212
+ border
213
+ className="hover"
214
+ />
215
+ </div>
216
+ <div className="flex flex-col gap-8">
217
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
218
+ Focus - Unchecked
219
+ </Code>
220
+ <CheckboxLabel
221
+ id="checkbox-border-focus-unchecked"
222
+ label="Label"
223
+ optional
224
+ showInfoIcon
225
+ description="The quick brown fox jumps over a lazy dog."
226
+ border
227
+ className="focus"
228
+ />
229
+ </div>
230
+ <div className="flex flex-col gap-8">
231
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
232
+ Default - Checked
233
+ </Code>
234
+ <CheckboxLabel
235
+ id="checkbox-border-default-checked"
236
+ label="Label"
237
+ optional
238
+ showInfoIcon
239
+ description="The quick brown fox jumps over a lazy dog."
240
+ checked
241
+ border
242
+ />
243
+ </div>
244
+ <div className="flex flex-col gap-8">
245
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
246
+ Hover - Checked
247
+ </Code>
248
+ <CheckboxLabel
249
+ id="checkbox-border-hover-checked"
250
+ label="Label"
251
+ optional
252
+ showInfoIcon
253
+ description="The quick brown fox jumps over a lazy dog."
254
+ checked
255
+ border
256
+ className="hover"
257
+ />
258
+ </div>
259
+ <div className="flex flex-col gap-8">
260
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
261
+ Focus - Checked
262
+ </Code>
263
+ <CheckboxLabel
264
+ id="checkbox-border-focus-checked"
265
+ label="Label"
266
+ optional
267
+ showInfoIcon
268
+ description="The quick brown fox jumps over a lazy dog."
269
+ checked
270
+ border
271
+ className="focus"
272
+ />
273
+ </div>
274
+ <div className="flex flex-col gap-8">
275
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
276
+ Default - Indeterminate
277
+ </Code>
278
+ <CheckboxLabel
279
+ id="checkbox-border-default-indeterminate"
280
+ label="Label"
281
+ optional
282
+ showInfoIcon
283
+ description="The quick brown fox jumps over a lazy dog."
284
+ checked="indeterminate"
285
+ border
286
+ />
287
+ </div>
288
+ <div className="flex flex-col gap-8">
289
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
290
+ Disabled - Unchecked
291
+ </Code>
292
+ <CheckboxLabel
293
+ id="checkbox-border-disabled-unchecked"
294
+ label="Label"
295
+ optional
296
+ showInfoIcon
297
+ description="The quick brown fox jumps over a lazy dog."
298
+ disabled
299
+ border
300
+ />
301
+ </div>
302
+ <div className="flex flex-col gap-8">
303
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
304
+ Disabled - Checked
305
+ </Code>
306
+ <CheckboxLabel
307
+ id="checkbox-border-disabled-checked"
308
+ label="Label"
309
+ optional
310
+ showInfoIcon
311
+ description="The quick brown fox jumps over a lazy dog."
312
+ checked
313
+ disabled
314
+ border
315
+ />
316
+ </div>
317
+ <div className="flex flex-col gap-8">
318
+ <Code variant="label" className="text-foreground-neutral-subtle text-xs">
319
+ Disabled - Indeterminate
320
+ </Code>
321
+ <CheckboxLabel
322
+ id="checkbox-border-disabled-indeterminate"
323
+ label="Label"
324
+ optional
325
+ showInfoIcon
326
+ description="The quick brown fox jumps over a lazy dog."
327
+ checked="indeterminate"
328
+ disabled
329
+ border
330
+ />
331
+ </div>
332
+ </div>
333
+ </div>
334
+ ),
335
+ };
336
+
337
+ CheckboxLabelStory.parameters = {
338
+ pseudo: {
339
+ hover: '.hover',
340
+ focusVisible: '.focus',
341
+ },
342
+ };
343
+
344
+ export const CheckboxLinksStory: StoryObj = {
345
+ args: {
346
+ disabled: true,
347
+ },
348
+
349
+ render: () => (
350
+ <div className="flex flex-col gap-32 pb-64 pt-32 px-32 bg-background-neutral-base">
351
+ <Code variant="label" className="text-foreground-neutral-subtle">
352
+ CHECKBOX LINKS
353
+ </Code>
354
+ <div className="flex flex-col gap-16">
355
+ <CheckboxLinks
356
+ id="checkbox-links-default"
357
+ label="Accept policies"
358
+ links={[
359
+ {label: 'Terms of use', href: '#'},
360
+ {label: 'Privacy Policy', href: '#'},
361
+ ]}
362
+ />
363
+ <CheckboxLinks
364
+ id="checkbox-links-checked"
365
+ label="Accept policies"
366
+ links={[
367
+ {label: 'Terms of use', href: '#'},
368
+ {label: 'Privacy Policy', href: '#'},
369
+ ]}
370
+ checked
371
+ />
372
+ </div>
373
+ </div>
374
+ ),
375
+ };