@shipfox/react-ui 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/.storybook/preview.tsx +1 -1
  2. package/.turbo/turbo-build.log +2 -2
  3. package/.turbo/turbo-check.log +3 -3
  4. package/.turbo/turbo-type.log +1 -1
  5. package/CHANGELOG.md +17 -0
  6. package/dist/components/alert/alert.d.ts +18 -0
  7. package/dist/components/alert/alert.d.ts.map +1 -0
  8. package/dist/components/alert/alert.js +123 -0
  9. package/dist/components/alert/alert.js.map +1 -0
  10. package/dist/components/alert/alert.stories.js +112 -0
  11. package/dist/components/alert/alert.stories.js.map +1 -0
  12. package/dist/components/alert/index.d.ts +2 -0
  13. package/dist/components/alert/index.d.ts.map +1 -0
  14. package/dist/components/alert/index.js +3 -0
  15. package/dist/components/alert/index.js.map +1 -0
  16. package/dist/components/avatar/avatar-group.d.ts +18 -0
  17. package/dist/components/avatar/avatar-group.d.ts.map +1 -0
  18. package/dist/components/avatar/avatar-group.js +132 -0
  19. package/dist/components/avatar/avatar-group.js.map +1 -0
  20. package/dist/components/avatar/avatar.d.ts +24 -0
  21. package/dist/components/avatar/avatar.d.ts.map +1 -0
  22. package/dist/components/avatar/avatar.js +165 -0
  23. package/dist/components/avatar/avatar.js.map +1 -0
  24. package/dist/components/avatar/avatar.stories.js +267 -0
  25. package/dist/components/avatar/avatar.stories.js.map +1 -0
  26. package/dist/components/avatar/index.d.ts +3 -0
  27. package/dist/components/avatar/index.d.ts.map +1 -0
  28. package/dist/components/avatar/index.js +4 -0
  29. package/dist/components/avatar/index.js.map +1 -0
  30. package/dist/components/badge/badge.d.ts +48 -0
  31. package/dist/components/badge/badge.d.ts.map +1 -0
  32. package/dist/components/badge/badge.js +72 -0
  33. package/dist/components/badge/badge.js.map +1 -0
  34. package/dist/components/badge/badge.stories.js +802 -0
  35. package/dist/components/badge/badge.stories.js.map +1 -0
  36. package/dist/components/badge/icon-badge.d.ts +9 -0
  37. package/dist/components/badge/icon-badge.d.ts.map +1 -0
  38. package/dist/components/badge/icon-badge.js +32 -0
  39. package/dist/components/badge/icon-badge.js.map +1 -0
  40. package/dist/components/badge/index.d.ts +5 -0
  41. package/dist/components/badge/index.d.ts.map +1 -0
  42. package/dist/components/badge/index.js +6 -0
  43. package/dist/components/badge/index.js.map +1 -0
  44. package/dist/components/badge/status-badge.d.ts +9 -0
  45. package/dist/components/badge/status-badge.d.ts.map +1 -0
  46. package/dist/components/badge/status-badge.js +29 -0
  47. package/dist/components/badge/status-badge.js.map +1 -0
  48. package/dist/components/badge/user-badge.d.ts +8 -0
  49. package/dist/components/badge/user-badge.d.ts.map +1 -0
  50. package/dist/components/badge/user-badge.js +24 -0
  51. package/dist/components/badge/user-badge.js.map +1 -0
  52. package/dist/components/{button.d.ts → button/button.d.ts} +1 -1
  53. package/dist/components/button/button.d.ts.map +1 -0
  54. package/dist/components/{button.js → button/button.js} +2 -2
  55. package/dist/components/button/button.js.map +1 -0
  56. package/dist/components/{button.stories.js → button/button.stories.js} +1 -1
  57. package/dist/components/button/button.stories.js.map +1 -0
  58. package/dist/components/button/index.d.ts +2 -0
  59. package/dist/components/button/index.d.ts.map +1 -0
  60. package/dist/components/button/index.js +3 -0
  61. package/dist/components/button/index.js.map +1 -0
  62. package/dist/components/checkbox/checkbox-label.d.ts +14 -0
  63. package/dist/components/checkbox/checkbox-label.d.ts.map +1 -0
  64. package/dist/components/checkbox/checkbox-label.js +82 -0
  65. package/dist/components/checkbox/checkbox-label.js.map +1 -0
  66. package/dist/components/checkbox/checkbox-links.d.ts +18 -0
  67. package/dist/components/checkbox/checkbox-links.d.ts.map +1 -0
  68. package/dist/components/checkbox/checkbox-links.js +58 -0
  69. package/dist/components/checkbox/checkbox-links.js.map +1 -0
  70. package/dist/components/checkbox/checkbox.d.ts +9 -0
  71. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  72. package/dist/components/checkbox/checkbox.js +49 -0
  73. package/dist/components/checkbox/checkbox.js.map +1 -0
  74. package/dist/components/checkbox/checkbox.stories.js +566 -0
  75. package/dist/components/checkbox/checkbox.stories.js.map +1 -0
  76. package/dist/components/checkbox/index.d.ts +4 -0
  77. package/dist/components/checkbox/index.d.ts.map +1 -0
  78. package/dist/components/checkbox/index.js +5 -0
  79. package/dist/components/checkbox/index.js.map +1 -0
  80. package/dist/components/code-block/code-block-footer.d.ts +26 -0
  81. package/dist/components/code-block/code-block-footer.d.ts.map +1 -0
  82. package/dist/components/code-block/code-block-footer.js +86 -0
  83. package/dist/components/code-block/code-block-footer.js.map +1 -0
  84. package/dist/components/code-block/code-block.d.ts +50 -0
  85. package/dist/components/code-block/code-block.d.ts.map +1 -0
  86. package/dist/components/code-block/code-block.js +142 -0
  87. package/dist/components/code-block/code-block.js.map +1 -0
  88. package/dist/components/code-block/code-block.stories.js +341 -0
  89. package/dist/components/code-block/code-block.stories.js.map +1 -0
  90. package/dist/components/code-block/code-content.d.ts +11 -0
  91. package/dist/components/code-block/code-content.d.ts.map +1 -0
  92. package/dist/components/code-block/code-content.js +29 -0
  93. package/dist/components/code-block/code-content.js.map +1 -0
  94. package/dist/components/code-block/code-copy-button.d.ts +11 -0
  95. package/dist/components/code-block/code-copy-button.d.ts.map +1 -0
  96. package/dist/components/code-block/code-copy-button.js +49 -0
  97. package/dist/components/code-block/code-copy-button.js.map +1 -0
  98. package/dist/components/code-block/code-tabs.d.ts +16 -0
  99. package/dist/components/code-block/code-tabs.d.ts.map +1 -0
  100. package/dist/components/code-block/code-tabs.js +98 -0
  101. package/dist/components/code-block/code-tabs.js.map +1 -0
  102. package/dist/components/code-block/index.d.ts +4 -0
  103. package/dist/components/code-block/index.d.ts.map +1 -0
  104. package/dist/components/code-block/index.js +5 -0
  105. package/dist/components/code-block/index.js.map +1 -0
  106. package/dist/components/dynamic-item/dynamic-item.d.ts +13 -0
  107. package/dist/components/dynamic-item/dynamic-item.d.ts.map +1 -0
  108. package/dist/components/dynamic-item/dynamic-item.js +43 -0
  109. package/dist/components/dynamic-item/dynamic-item.js.map +1 -0
  110. package/dist/components/dynamic-item/dynamic-item.stories.js +375 -0
  111. package/dist/components/dynamic-item/dynamic-item.stories.js.map +1 -0
  112. package/dist/components/dynamic-item/index.d.ts +2 -0
  113. package/dist/components/dynamic-item/index.d.ts.map +1 -0
  114. package/dist/components/dynamic-item/index.js +3 -0
  115. package/dist/components/dynamic-item/index.js.map +1 -0
  116. package/dist/components/icon/custom/index.d.ts +3 -0
  117. package/dist/components/icon/custom/index.d.ts.map +1 -1
  118. package/dist/components/icon/custom/index.js +3 -0
  119. package/dist/components/icon/custom/index.js.map +1 -1
  120. package/dist/components/icon/custom/shipfox-logo.d.ts +8 -0
  121. package/dist/components/icon/custom/shipfox-logo.d.ts.map +1 -0
  122. package/dist/components/icon/custom/shipfox-logo.js +22 -0
  123. package/dist/components/icon/custom/shipfox-logo.js.map +1 -0
  124. package/dist/components/icon/custom/slack-logo.d.ts +6 -0
  125. package/dist/components/icon/custom/slack-logo.d.ts.map +1 -0
  126. package/dist/components/icon/custom/slack-logo.js +34 -0
  127. package/dist/components/icon/custom/slack-logo.js.map +1 -0
  128. package/dist/components/icon/custom/stripe-logo.d.ts +8 -0
  129. package/dist/components/icon/custom/stripe-logo.d.ts.map +1 -0
  130. package/dist/components/icon/custom/stripe-logo.js +24 -0
  131. package/dist/components/icon/custom/stripe-logo.js.map +1 -0
  132. package/dist/components/icon/icon.d.ts +13 -1
  133. package/dist/components/icon/icon.d.ts.map +1 -1
  134. package/dist/components/icon/icon.js +15 -3
  135. package/dist/components/icon/icon.js.map +1 -1
  136. package/dist/components/icon/icon.stories.js +6 -3
  137. package/dist/components/icon/icon.stories.js.map +1 -1
  138. package/dist/components/index.d.ts +12 -1
  139. package/dist/components/index.d.ts.map +1 -1
  140. package/dist/components/index.js +13 -2
  141. package/dist/components/index.js.map +1 -1
  142. package/dist/components/inline-tips/index.d.ts +2 -0
  143. package/dist/components/inline-tips/index.d.ts.map +1 -0
  144. package/dist/components/inline-tips/index.js +3 -0
  145. package/dist/components/inline-tips/index.js.map +1 -0
  146. package/dist/components/inline-tips/inline-tips.d.ts +19 -0
  147. package/dist/components/inline-tips/inline-tips.d.ts.map +1 -0
  148. package/dist/components/inline-tips/inline-tips.js +98 -0
  149. package/dist/components/inline-tips/inline-tips.js.map +1 -0
  150. package/dist/components/inline-tips/inline-tips.stories.js +214 -0
  151. package/dist/components/inline-tips/inline-tips.stories.js.map +1 -0
  152. package/dist/components/input/index.d.ts +2 -0
  153. package/dist/components/input/index.d.ts.map +1 -0
  154. package/dist/components/input/index.js +3 -0
  155. package/dist/components/input/index.js.map +1 -0
  156. package/dist/components/input/input.d.ts.map +1 -0
  157. package/dist/components/{input.js → input/input.js} +2 -2
  158. package/dist/components/input/input.js.map +1 -0
  159. package/dist/components/{input.stories.js → input/input.stories.js} +1 -1
  160. package/dist/components/input/input.stories.js.map +1 -0
  161. package/dist/components/item/index.d.ts +2 -0
  162. package/dist/components/item/index.d.ts.map +1 -0
  163. package/dist/components/item/index.js +3 -0
  164. package/dist/components/item/index.js.map +1 -0
  165. package/dist/components/item/item.d.ts +32 -0
  166. package/dist/components/item/item.d.ts.map +1 -0
  167. package/dist/components/item/item.js +120 -0
  168. package/dist/components/item/item.js.map +1 -0
  169. package/dist/components/item/item.stories.js +232 -0
  170. package/dist/components/item/item.stories.js.map +1 -0
  171. package/dist/components/label/index.d.ts +2 -0
  172. package/dist/components/label/index.d.ts.map +1 -0
  173. package/dist/components/label/index.js +3 -0
  174. package/dist/components/label/index.js.map +1 -0
  175. package/dist/components/label/label.d.ts +7 -0
  176. package/dist/components/label/label.d.ts.map +1 -0
  177. package/dist/components/label/label.js +13 -0
  178. package/dist/components/label/label.js.map +1 -0
  179. package/dist/components/label/label.stories.js +105 -0
  180. package/dist/components/label/label.stories.js.map +1 -0
  181. package/dist/components/moving-border/moving-border.d.ts +9 -0
  182. package/dist/components/moving-border/moving-border.d.ts.map +1 -0
  183. package/dist/components/moving-border/moving-border.js +54 -0
  184. package/dist/components/moving-border/moving-border.js.map +1 -0
  185. package/dist/components/textarea/textarea.js +1 -1
  186. package/dist/components/textarea/textarea.js.map +1 -1
  187. package/dist/components/theme/index.d.ts +2 -0
  188. package/dist/components/theme/index.d.ts.map +1 -0
  189. package/dist/components/theme/index.js +3 -0
  190. package/dist/components/theme/index.js.map +1 -0
  191. package/dist/components/{theme-provider.d.ts → theme/theme-provider.d.ts} +1 -1
  192. package/dist/components/theme/theme-provider.d.ts.map +1 -0
  193. package/dist/components/{theme-provider.js → theme/theme-provider.js} +1 -1
  194. package/dist/components/theme/theme-provider.js.map +1 -0
  195. package/dist/components/toast/index.d.ts +3 -0
  196. package/dist/components/toast/index.d.ts.map +1 -0
  197. package/dist/components/toast/index.js +4 -0
  198. package/dist/components/toast/index.js.map +1 -0
  199. package/dist/components/toast/toast-custom.d.ts +19 -0
  200. package/dist/components/toast/toast-custom.d.ts.map +1 -0
  201. package/dist/components/toast/toast-custom.js +134 -0
  202. package/dist/components/toast/toast-custom.js.map +1 -0
  203. package/dist/components/toast/toast.d.ts +5 -0
  204. package/dist/components/toast/toast.d.ts.map +1 -0
  205. package/dist/components/toast/toast.js +40 -0
  206. package/dist/components/toast/toast.js.map +1 -0
  207. package/dist/components/toast/toast.stories.js +326 -0
  208. package/dist/components/toast/toast.stories.js.map +1 -0
  209. package/dist/components/tooltip/index.d.ts +2 -0
  210. package/dist/components/tooltip/index.d.ts.map +1 -0
  211. package/dist/components/tooltip/index.js +3 -0
  212. package/dist/components/tooltip/index.js.map +1 -0
  213. package/dist/components/tooltip/tooltip.d.ts +20 -0
  214. package/dist/components/tooltip/tooltip.d.ts.map +1 -0
  215. package/dist/components/tooltip/tooltip.js +98 -0
  216. package/dist/components/tooltip/tooltip.js.map +1 -0
  217. package/dist/components/tooltip/tooltip.stories.js +560 -0
  218. package/dist/components/tooltip/tooltip.stories.js.map +1 -0
  219. package/dist/hooks/index.d.ts +3 -0
  220. package/dist/hooks/index.d.ts.map +1 -1
  221. package/dist/hooks/index.js +3 -0
  222. package/dist/hooks/index.js.map +1 -1
  223. package/dist/hooks/useResolvedTheme.d.ts +2 -0
  224. package/dist/hooks/useResolvedTheme.d.ts.map +1 -0
  225. package/dist/hooks/useResolvedTheme.js +24 -0
  226. package/dist/hooks/useResolvedTheme.js.map +1 -0
  227. package/dist/hooks/useShikiHighlight.d.ts +28 -0
  228. package/dist/hooks/useShikiHighlight.d.ts.map +1 -0
  229. package/dist/hooks/useShikiHighlight.js +106 -0
  230. package/dist/hooks/useShikiHighlight.js.map +1 -0
  231. package/dist/hooks/useShikiStyleInjection.d.ts +2 -0
  232. package/dist/hooks/useShikiStyleInjection.d.ts.map +1 -0
  233. package/dist/hooks/useShikiStyleInjection.js +34 -0
  234. package/dist/hooks/useShikiStyleInjection.js.map +1 -0
  235. package/dist/utils/avatar.d.ts +3 -0
  236. package/dist/utils/avatar.d.ts.map +1 -0
  237. package/dist/utils/avatar.js +32 -0
  238. package/dist/utils/avatar.js.map +1 -0
  239. package/dist/utils/index.d.ts +1 -0
  240. package/dist/utils/index.d.ts.map +1 -1
  241. package/dist/utils/index.js +1 -0
  242. package/dist/utils/index.js.map +1 -1
  243. package/index.css +130 -7
  244. package/package.json +7 -4
  245. package/src/assets/illustration-1.svg +92 -0
  246. package/src/assets/illustration-2.svg +14 -0
  247. package/src/assets/illustration-gradient.svg +7049 -0
  248. package/src/components/alert/alert.stories.tsx +77 -0
  249. package/src/components/alert/alert.tsx +144 -0
  250. package/src/components/alert/index.ts +1 -0
  251. package/src/components/avatar/avatar-group.tsx +186 -0
  252. package/src/components/avatar/avatar.stories.tsx +179 -0
  253. package/src/components/avatar/avatar.tsx +219 -0
  254. package/src/components/avatar/index.ts +2 -0
  255. package/src/components/badge/badge.stories.tsx +468 -0
  256. package/src/components/badge/badge.tsx +147 -0
  257. package/src/components/badge/icon-badge.tsx +43 -0
  258. package/src/components/badge/index.ts +4 -0
  259. package/src/components/badge/status-badge.tsx +43 -0
  260. package/src/components/badge/user-badge.tsx +34 -0
  261. package/src/components/{button.tsx → button/button.tsx} +1 -1
  262. package/src/components/button/index.ts +1 -0
  263. package/src/components/checkbox/checkbox-label.tsx +125 -0
  264. package/src/components/checkbox/checkbox-links.tsx +90 -0
  265. package/src/components/checkbox/checkbox.stories.tsx +375 -0
  266. package/src/components/checkbox/checkbox.tsx +71 -0
  267. package/src/components/checkbox/index.ts +3 -0
  268. package/src/components/code-block/code-block-footer.tsx +173 -0
  269. package/src/components/code-block/code-block.stories.tsx +323 -0
  270. package/src/components/code-block/code-block.tsx +283 -0
  271. package/src/components/code-block/code-content.tsx +60 -0
  272. package/src/components/code-block/code-copy-button.tsx +73 -0
  273. package/src/components/code-block/code-tabs.tsx +170 -0
  274. package/src/components/code-block/index.ts +3 -0
  275. package/src/components/dynamic-item/dynamic-item.stories.tsx +261 -0
  276. package/src/components/dynamic-item/dynamic-item.tsx +68 -0
  277. package/src/components/dynamic-item/index.ts +1 -0
  278. package/src/components/icon/custom/index.ts +3 -0
  279. package/src/components/icon/custom/shipfox-logo.tsx +20 -0
  280. package/src/components/icon/custom/slack-logo.tsx +35 -0
  281. package/src/components/icon/custom/stripe-logo.tsx +27 -0
  282. package/src/components/icon/icon.stories.tsx +3 -1
  283. package/src/components/icon/icon.tsx +29 -1
  284. package/src/components/index.ts +12 -1
  285. package/src/components/inline-tips/index.ts +1 -0
  286. package/src/components/inline-tips/inline-tips.stories.tsx +126 -0
  287. package/src/components/inline-tips/inline-tips.tsx +132 -0
  288. package/src/components/input/index.ts +1 -0
  289. package/src/components/{input.tsx → input/input.tsx} +1 -1
  290. package/src/components/item/index.ts +1 -0
  291. package/src/components/item/item.stories.tsx +150 -0
  292. package/src/components/item/item.tsx +182 -0
  293. package/src/components/label/index.ts +1 -0
  294. package/src/components/label/label.stories.tsx +67 -0
  295. package/src/components/label/label.tsx +15 -0
  296. package/src/components/moving-border/moving-border.tsx +67 -0
  297. package/src/components/textarea/textarea.tsx +1 -1
  298. package/src/components/theme/index.ts +1 -0
  299. package/src/components/toast/index.ts +2 -0
  300. package/src/components/toast/toast-custom.tsx +154 -0
  301. package/src/components/toast/toast.stories.tsx +369 -0
  302. package/src/components/toast/toast.tsx +41 -0
  303. package/src/components/tooltip/index.ts +1 -0
  304. package/src/components/tooltip/tooltip.stories.tsx +284 -0
  305. package/src/components/tooltip/tooltip.tsx +121 -0
  306. package/src/hooks/index.ts +3 -0
  307. package/src/hooks/useResolvedTheme.ts +34 -0
  308. package/src/hooks/useShikiHighlight.ts +140 -0
  309. package/src/hooks/useShikiStyleInjection.ts +34 -0
  310. package/src/utils/avatar.ts +27 -0
  311. package/src/utils/index.ts +1 -0
  312. package/dist/components/button.d.ts.map +0 -1
  313. package/dist/components/button.js.map +0 -1
  314. package/dist/components/button.stories.js.map +0 -1
  315. package/dist/components/input.d.ts.map +0 -1
  316. package/dist/components/input.js.map +0 -1
  317. package/dist/components/input.stories.js.map +0 -1
  318. package/dist/components/theme-provider.d.ts.map +0 -1
  319. package/dist/components/theme-provider.js.map +0 -1
  320. /package/dist/components/{input.d.ts → input/input.d.ts} +0 -0
  321. /package/src/components/{button.stories.tsx → button/button.stories.tsx} +0 -0
  322. /package/src/components/{input.stories.tsx → input/input.stories.tsx} +0 -0
  323. /package/src/components/{theme-provider.tsx → theme/theme-provider.tsx} +0 -0
@@ -0,0 +1,219 @@
1
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
2
+ import {cva, type VariantProps} from 'class-variance-authority';
3
+ import type {ComponentProps, ReactNode} from 'react';
4
+ import {getInitial, getPlaceholderImageUrl} from 'utils';
5
+ import {cn} from 'utils/cn';
6
+ import {Icon, type IconName} from '../icon/icon';
7
+
8
+ export const avatarVariants = cva(
9
+ 'relative flex shrink-0 overflow-hidden bg-background-button-neutral-default text-foreground-neutral-base ring-1 ring-border-neutral-base-component ring-offset-1 ring-offset-background-neutral-base shadow-button-neutral',
10
+ {
11
+ variants: {
12
+ radius: {
13
+ full: 'rounded-full',
14
+ rounded: 'rounded-6',
15
+ },
16
+ size: {
17
+ '3xs': 'size-[18px]',
18
+ '2xs': 'size-[20px]',
19
+ xs: 'size-[24px]',
20
+ sm: 'size-[28px]',
21
+ md: 'size-[32px]',
22
+ lg: 'size-[36px]',
23
+ xl: 'size-[40px]',
24
+ '2xl': 'size-[80px]',
25
+ '3xl': 'size-[120px]',
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ radius: 'full',
30
+ size: 'md',
31
+ },
32
+ },
33
+ );
34
+
35
+ const avatarInnerVariants = cva('flex h-full w-full items-center justify-center', {
36
+ variants: {
37
+ size: {
38
+ '3xs': 'text-[10px] leading-[10px]',
39
+ '2xs': 'text-[11px] leading-[11px]',
40
+ xs: 'text-xs leading-4',
41
+ sm: 'text-xs leading-5',
42
+ md: 'text-sm leading-5',
43
+ lg: 'text-sm leading-5',
44
+ xl: 'text-base leading-6',
45
+ '2xl': 'text-2xl leading-8',
46
+ '3xl': 'text-4xl leading-[56px]',
47
+ },
48
+ },
49
+ defaultVariants: {
50
+ size: 'md',
51
+ },
52
+ });
53
+
54
+ export type AvatarContent = 'letters' | 'logo' | 'logoPlaceholder' | 'image' | 'upload';
55
+
56
+ const UPLOAD_ICON_SIZE_MAP: Record<
57
+ NonNullable<VariantProps<typeof avatarVariants>['size']>,
58
+ string
59
+ > = {
60
+ '3xs': 'size-[10px]',
61
+ '2xs': 'size-[12px]',
62
+ xs: 'size-[14px]',
63
+ sm: 'size-[16px]',
64
+ md: 'size-[18px]',
65
+ lg: 'size-[20px]',
66
+ xl: 'size-[24px]',
67
+ '2xl': 'size-[40px]',
68
+ '3xl': 'size-[60px]',
69
+ } as const;
70
+
71
+ function AvatarRoot({
72
+ className,
73
+ radius,
74
+ size,
75
+ ...props
76
+ }: ComponentProps<typeof AvatarPrimitive.Root> & VariantProps<typeof avatarVariants>) {
77
+ return (
78
+ <AvatarPrimitive.Root
79
+ data-slot="avatar"
80
+ className={cn(avatarVariants({radius, size}), className)}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+
86
+ function AvatarImage({className, ...props}: ComponentProps<typeof AvatarPrimitive.Image>) {
87
+ return (
88
+ <AvatarPrimitive.Image
89
+ data-slot="avatar-image"
90
+ className={cn('aspect-square size-full', className)}
91
+ {...props}
92
+ />
93
+ );
94
+ }
95
+
96
+ function AvatarFallback({className, ...props}: ComponentProps<typeof AvatarPrimitive.Fallback>) {
97
+ return (
98
+ <AvatarPrimitive.Fallback
99
+ data-slot="avatar-name"
100
+ className={cn('flex size-full items-center justify-center', className)}
101
+ {...props}
102
+ />
103
+ );
104
+ }
105
+
106
+ export type AvatarProps = ComponentProps<typeof AvatarPrimitive.Root> &
107
+ VariantProps<typeof avatarVariants> & {
108
+ content?: AvatarContent;
109
+ src?: string;
110
+ alt?: string;
111
+ fallback?: string;
112
+ animateOnHover?: boolean;
113
+ logoName?: IconName;
114
+ logoClassName?: string;
115
+ };
116
+
117
+ export function Avatar({
118
+ className,
119
+ radius,
120
+ size = 'md',
121
+ content = 'letters',
122
+ src,
123
+ alt,
124
+ fallback,
125
+ animateOnHover = false,
126
+ logoName = 'shipfox',
127
+ logoClassName,
128
+ ...props
129
+ }: AvatarProps) {
130
+ const innerClassName =
131
+ 'flex h-full w-full items-center justify-center rounded-inherit relative bg-background-neutral-base dark:bg-background-components-base text-foreground-neutral-subtle';
132
+
133
+ const renderContent = (): ReactNode => {
134
+ if (content === 'image') {
135
+ const imageSrc = src || getPlaceholderImageUrl(fallback);
136
+ return (
137
+ <>
138
+ <AvatarImage
139
+ src={imageSrc}
140
+ alt={alt || 'Avatar image'}
141
+ className="object-scale-down rounded-inherit"
142
+ />
143
+ <AvatarFallback className={innerClassName}>
144
+ <div
145
+ className={cn(
146
+ 'absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2',
147
+ avatarInnerVariants({size}),
148
+ )}
149
+ >
150
+ <span className="font-medium">{getInitial(fallback)}</span>
151
+ </div>
152
+ </AvatarFallback>
153
+ </>
154
+ );
155
+ }
156
+
157
+ if (content === 'logo') {
158
+ return (
159
+ <AvatarFallback className={cn(innerClassName, logoClassName ?? 'p-[15%]')}>
160
+ <Icon name={logoName} className="h-full w-full" />
161
+ </AvatarFallback>
162
+ );
163
+ }
164
+
165
+ if (content === 'logoPlaceholder') {
166
+ return (
167
+ <AvatarFallback className={cn(innerClassName, logoClassName ?? 'p-[15%]')}>
168
+ <Icon
169
+ name={logoName}
170
+ color="var(--foreground-neutral-subtle, #a1a1aa)"
171
+ className="h-full w-full opacity-50"
172
+ />
173
+ </AvatarFallback>
174
+ );
175
+ }
176
+
177
+ if (content === 'letters') {
178
+ return (
179
+ <AvatarFallback className={innerClassName}>
180
+ <div
181
+ className={cn(
182
+ 'absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2',
183
+ avatarInnerVariants({size}),
184
+ )}
185
+ >
186
+ <span className="font-medium">{getInitial(fallback)}</span>
187
+ </div>
188
+ </AvatarFallback>
189
+ );
190
+ }
191
+
192
+ if (content === 'upload') {
193
+ const iconSizeClass = UPLOAD_ICON_SIZE_MAP[size as keyof typeof UPLOAD_ICON_SIZE_MAP];
194
+ return (
195
+ <AvatarFallback className={innerClassName}>
196
+ <Icon name="imageAdd" className={cn('text-foreground-neutral-subtle', iconSizeClass)} />
197
+ </AvatarFallback>
198
+ );
199
+ }
200
+
201
+ return null;
202
+ };
203
+
204
+ return (
205
+ <AvatarRoot
206
+ className={cn(
207
+ animateOnHover ? 'hover:-translate-y-8 transition-transform duration-300 ease-out' : '',
208
+ className,
209
+ )}
210
+ radius={radius}
211
+ size={size}
212
+ {...props}
213
+ >
214
+ {renderContent()}
215
+ </AvatarRoot>
216
+ );
217
+ }
218
+
219
+ export {AvatarRoot, AvatarImage, AvatarFallback};
@@ -0,0 +1,2 @@
1
+ export * from './avatar';
2
+ export * from './avatar-group';
@@ -0,0 +1,468 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code} from 'components/typography';
3
+ import React from 'react';
4
+ import {Badge, IconBadge, StatusBadge, UserBadge} from '.';
5
+
6
+ const meta = {
7
+ title: 'Components/Badge',
8
+ component: Badge,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ tags: ['autodocs'],
13
+ } satisfies Meta<typeof Badge>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ export const AllVariants: Story = {
19
+ render: () => (
20
+ <div className="flex flex-col gap-32">
21
+ {/* STATUS BADGE */}
22
+ <div>
23
+ <Code variant="label" className="mb-16">
24
+ Status Badge
25
+ </Code>
26
+ <div className="flex gap-16">
27
+ <StatusBadge variant="neutral">Badge</StatusBadge>
28
+ <StatusBadge variant="info">Badge</StatusBadge>
29
+ <StatusBadge variant="feature">Badge</StatusBadge>
30
+ <StatusBadge variant="success" dotClassName="size-5 rounded-full">
31
+ Badge
32
+ </StatusBadge>
33
+ <StatusBadge variant="warning">Badge</StatusBadge>
34
+ <StatusBadge variant="error">Badge</StatusBadge>
35
+ </div>
36
+ </div>
37
+
38
+ {/* USER BADGE */}
39
+ <div>
40
+ <Code variant="label" className="mb-16">
41
+ User Badge
42
+ </Code>
43
+ <div className="flex gap-16">
44
+ <UserBadge
45
+ name="Thierry Abalea"
46
+ avatarSrc="https://avatars.githubusercontent.com/u/1290899?v=4"
47
+ />
48
+ <UserBadge
49
+ name="Kyle Nguyen"
50
+ avatarSrc="https://avatars.githubusercontent.com/u/89263955?v=4"
51
+ />
52
+ <UserBadge
53
+ name="Noe Charmet"
54
+ avatarSrc="https://avatars.githubusercontent.com/u/59678972?v=4"
55
+ />
56
+ </div>
57
+ </div>
58
+
59
+ {/* ICON BADGE */}
60
+ <div>
61
+ <Code variant="label" className="mb-16">
62
+ Icon Badge
63
+ </Code>
64
+ <div className="flex gap-16">
65
+ <IconBadge variant="neutral" name="homeSmile" />
66
+ <IconBadge variant="info" name="homeSmile" />
67
+ <IconBadge variant="feature" name="homeSmile" />
68
+ <IconBadge variant="success" name="homeSmile" />
69
+ <IconBadge variant="primary" name="homeSmile" />
70
+ <IconBadge variant="error" name="homeSmile" />
71
+ </div>
72
+ </div>
73
+
74
+ {/* BADGE - 2XS SIZE */}
75
+ <div>
76
+ <Code variant="label" className="mb-16">
77
+ Badge - 2XS Size
78
+ </Code>
79
+ <div className="flex flex-col gap-16">
80
+ {/* Base */}
81
+ <div className="flex gap-16">
82
+ <Badge variant="neutral" size="2xs">
83
+ Badge
84
+ </Badge>
85
+ <Badge variant="info" size="2xs">
86
+ Badge
87
+ </Badge>
88
+ <Badge variant="feature" size="2xs">
89
+ Badge
90
+ </Badge>
91
+ <Badge variant="success" size="2xs">
92
+ Badge
93
+ </Badge>
94
+ <Badge variant="warning" size="2xs">
95
+ Badge
96
+ </Badge>
97
+ <Badge variant="error" size="2xs">
98
+ Badge
99
+ </Badge>
100
+ </div>
101
+
102
+ {/* With Right Icon */}
103
+ <div className="flex gap-16">
104
+ <Badge variant="neutral" size="2xs" iconRight="close">
105
+ Badge
106
+ </Badge>
107
+ <Badge variant="info" size="2xs" iconRight="close">
108
+ Badge
109
+ </Badge>
110
+ <Badge variant="feature" size="2xs" iconRight="close">
111
+ Badge
112
+ </Badge>
113
+ <Badge variant="success" size="2xs" iconRight="close">
114
+ Badge
115
+ </Badge>
116
+ <Badge variant="warning" size="2xs" iconRight="close">
117
+ Badge
118
+ </Badge>
119
+ <Badge variant="error" size="2xs" iconRight="close">
120
+ Badge
121
+ </Badge>
122
+ </div>
123
+
124
+ {/* With Left Icon */}
125
+ <div className="flex gap-16">
126
+ <Badge variant="neutral" size="2xs" iconLeft="close">
127
+ Badge
128
+ </Badge>
129
+ <Badge variant="info" size="2xs" iconLeft="close">
130
+ Badge
131
+ </Badge>
132
+ <Badge variant="feature" size="2xs" iconLeft="close">
133
+ Badge
134
+ </Badge>
135
+ <Badge variant="success" size="2xs" iconLeft="close">
136
+ Badge
137
+ </Badge>
138
+ <Badge variant="warning" size="2xs" iconLeft="close">
139
+ Badge
140
+ </Badge>
141
+ <Badge variant="error" size="2xs" iconLeft="close">
142
+ Badge
143
+ </Badge>
144
+ </div>
145
+ </div>
146
+ </div>
147
+
148
+ {/* BADGE - XS SIZE */}
149
+ <div>
150
+ <Code variant="label" className="mb-16">
151
+ Badge - XS Size
152
+ </Code>
153
+ <div className="flex flex-col gap-16">
154
+ {/* Base */}
155
+ <div className="flex gap-16">
156
+ <Badge variant="neutral" size="xs">
157
+ Badge
158
+ </Badge>
159
+ <Badge variant="info" size="xs">
160
+ Badge
161
+ </Badge>
162
+ <Badge variant="feature" size="xs">
163
+ Badge
164
+ </Badge>
165
+ <Badge variant="success" size="xs">
166
+ Badge
167
+ </Badge>
168
+ <Badge variant="warning" size="xs">
169
+ Badge
170
+ </Badge>
171
+ <Badge variant="error" size="xs">
172
+ Badge
173
+ </Badge>
174
+ </div>
175
+
176
+ {/* With Right Icon */}
177
+ <div className="flex gap-16">
178
+ <Badge variant="neutral" size="xs" iconRight="close">
179
+ Badge
180
+ </Badge>
181
+ <Badge variant="info" size="xs" iconRight="close">
182
+ Badge
183
+ </Badge>
184
+ <Badge variant="feature" size="xs" iconRight="close">
185
+ Badge
186
+ </Badge>
187
+ <Badge variant="success" size="xs" iconRight="close">
188
+ Badge
189
+ </Badge>
190
+ <Badge variant="warning" size="xs" iconRight="close">
191
+ Badge
192
+ </Badge>
193
+ <Badge variant="error" size="xs" iconRight="close">
194
+ Badge
195
+ </Badge>
196
+ </div>
197
+
198
+ {/* With Left Icon */}
199
+ <div className="flex gap-16">
200
+ <Badge variant="neutral" size="xs" iconLeft="close">
201
+ Badge
202
+ </Badge>
203
+ <Badge variant="info" size="xs" iconLeft="close">
204
+ Badge
205
+ </Badge>
206
+ <Badge variant="feature" size="xs" iconLeft="close">
207
+ Badge
208
+ </Badge>
209
+ <Badge variant="success" size="xs" iconLeft="close">
210
+ Badge
211
+ </Badge>
212
+ <Badge variant="warning" size="xs" iconLeft="close">
213
+ Badge
214
+ </Badge>
215
+ <Badge variant="error" size="xs" iconLeft="close">
216
+ Badge
217
+ </Badge>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ {/* BADGE - ROUNDED */}
223
+ <div>
224
+ <Code variant="label" className="mb-16">
225
+ Badge - Rounded
226
+ </Code>
227
+ <div className="flex flex-col gap-16">
228
+ {/* Base - 2XS */}
229
+ <div className="flex gap-16">
230
+ <Badge variant="neutral" size="2xs" radius="rounded">
231
+ Badge
232
+ </Badge>
233
+ <Badge variant="info" size="2xs" radius="rounded">
234
+ Badge
235
+ </Badge>
236
+ <Badge variant="feature" size="2xs" radius="rounded">
237
+ Badge
238
+ </Badge>
239
+ <Badge variant="success" size="2xs" radius="rounded">
240
+ Badge
241
+ </Badge>
242
+ <Badge variant="warning" size="2xs" radius="rounded">
243
+ Badge
244
+ </Badge>
245
+ <Badge variant="error" size="2xs" radius="rounded">
246
+ Badge
247
+ </Badge>
248
+ </div>
249
+
250
+ {/* Base - XS */}
251
+ <div className="flex gap-16">
252
+ <Badge variant="neutral" size="xs" radius="rounded">
253
+ Badge
254
+ </Badge>
255
+ <Badge variant="info" size="xs" radius="rounded">
256
+ Badge
257
+ </Badge>
258
+ <Badge variant="feature" size="xs" radius="rounded">
259
+ Badge
260
+ </Badge>
261
+ <Badge variant="success" size="xs" radius="rounded">
262
+ Badge
263
+ </Badge>
264
+ <Badge variant="warning" size="xs" radius="rounded">
265
+ Badge
266
+ </Badge>
267
+ <Badge variant="error" size="xs" radius="rounded">
268
+ Badge
269
+ </Badge>
270
+ </div>
271
+
272
+ {/* With Right Icon - 2XS */}
273
+ <div className="flex gap-16">
274
+ <Badge variant="neutral" size="2xs" radius="rounded" iconRight="close">
275
+ Badge
276
+ </Badge>
277
+ <Badge variant="info" size="2xs" radius="rounded" iconRight="close">
278
+ Badge
279
+ </Badge>
280
+ <Badge variant="feature" size="2xs" radius="rounded" iconRight="close">
281
+ Badge
282
+ </Badge>
283
+ <Badge variant="success" size="2xs" radius="rounded" iconRight="close">
284
+ Badge
285
+ </Badge>
286
+ <Badge variant="warning" size="2xs" radius="rounded" iconRight="close">
287
+ Badge
288
+ </Badge>
289
+ <Badge variant="error" size="2xs" radius="rounded" iconRight="close">
290
+ Badge
291
+ </Badge>
292
+ </div>
293
+
294
+ {/* With Right Icon - XS */}
295
+ <div className="flex gap-16">
296
+ <Badge variant="neutral" size="xs" radius="rounded" iconRight="close">
297
+ Badge
298
+ </Badge>
299
+ <Badge variant="info" size="xs" radius="rounded" iconRight="close">
300
+ Badge
301
+ </Badge>
302
+ <Badge variant="feature" size="xs" radius="rounded" iconRight="close">
303
+ Badge
304
+ </Badge>
305
+ <Badge variant="success" size="xs" radius="rounded" iconRight="close">
306
+ Badge
307
+ </Badge>
308
+ <Badge variant="warning" size="xs" radius="rounded" iconRight="close">
309
+ Badge
310
+ </Badge>
311
+ <Badge variant="error" size="xs" radius="rounded" iconRight="close">
312
+ Badge
313
+ </Badge>
314
+ </div>
315
+
316
+ {/* With Left Icon - 2XS */}
317
+ <div className="flex gap-16">
318
+ <Badge variant="neutral" size="2xs" radius="rounded" iconLeft="close">
319
+ Badge
320
+ </Badge>
321
+ <Badge variant="info" size="2xs" radius="rounded" iconLeft="close">
322
+ Badge
323
+ </Badge>
324
+ <Badge variant="feature" size="2xs" radius="rounded" iconLeft="close">
325
+ Badge
326
+ </Badge>
327
+ <Badge variant="success" size="2xs" radius="rounded" iconLeft="close">
328
+ Badge
329
+ </Badge>
330
+ <Badge variant="warning" size="2xs" radius="rounded" iconLeft="close">
331
+ Badge
332
+ </Badge>
333
+ <Badge variant="error" size="2xs" radius="rounded" iconLeft="close">
334
+ Badge
335
+ </Badge>
336
+ </div>
337
+
338
+ {/* With Left Icon - XS */}
339
+ <div className="flex gap-16">
340
+ <Badge variant="neutral" size="xs" radius="rounded" iconLeft="close">
341
+ Badge
342
+ </Badge>
343
+ <Badge variant="info" size="xs" radius="rounded" iconLeft="close">
344
+ Badge
345
+ </Badge>
346
+ <Badge variant="feature" size="xs" radius="rounded" iconLeft="close">
347
+ Badge
348
+ </Badge>
349
+ <Badge variant="success" size="xs" radius="rounded" iconLeft="close">
350
+ Badge
351
+ </Badge>
352
+ <Badge variant="warning" size="xs" radius="rounded" iconLeft="close">
353
+ Badge
354
+ </Badge>
355
+ <Badge variant="error" size="xs" radius="rounded" iconLeft="close">
356
+ Badge
357
+ </Badge>
358
+ </div>
359
+ </div>
360
+ </div>
361
+
362
+ {/* BETA BADGE */}
363
+ <div>
364
+ <Code variant="label" className="mb-16">
365
+ Beta Badge
366
+ </Code>
367
+ <div className="flex gap-16">
368
+ <Badge variant="info" size="2xs" radius="rounded">
369
+ Beta
370
+ </Badge>
371
+ </div>
372
+ </div>
373
+ </div>
374
+ ),
375
+ };
376
+
377
+ // Interactive badges with click handlers
378
+ function InteractiveBadgesComponent() {
379
+ const [tags, setTags] = React.useState(['React', 'TypeScript', 'Next.js', 'Tailwind']);
380
+
381
+ const removeTag = (tagToRemove: string) => {
382
+ setTags(tags.filter((tag) => tag !== tagToRemove));
383
+ };
384
+
385
+ return (
386
+ <div className="flex flex-col gap-32">
387
+ {/* Removable tags */}
388
+ <div>
389
+ <Code variant="label" className="mb-16">
390
+ Interactive Badges - Removable Tags
391
+ </Code>
392
+ <div className="flex flex-wrap gap-8">
393
+ {tags.map((tag) => (
394
+ <Badge
395
+ key={tag}
396
+ variant="neutral"
397
+ size="xs"
398
+ radius="rounded"
399
+ iconRight="close"
400
+ onIconRightClick={() => removeTag(tag)}
401
+ iconRightAriaLabel={`Remove ${tag} tag`}
402
+ >
403
+ {tag}
404
+ </Badge>
405
+ ))}
406
+ </div>
407
+ </div>
408
+
409
+ {/* Different variants with interactive icons */}
410
+ <div>
411
+ <Code variant="label" className="mb-16">
412
+ Interactive Badges - Different Variants
413
+ </Code>
414
+ <div className="flex flex-wrap gap-8">
415
+ <Badge
416
+ variant="success"
417
+ size="xs"
418
+ iconRight="close"
419
+ onIconRightClick={() => alert('Success badge clicked!')}
420
+ iconRightAriaLabel="Remove success badge"
421
+ >
422
+ Completed
423
+ </Badge>
424
+ <Badge
425
+ variant="warning"
426
+ size="xs"
427
+ iconRight="close"
428
+ onIconRightClick={() => alert('Warning badge clicked!')}
429
+ iconRightAriaLabel="Remove warning badge"
430
+ >
431
+ Pending
432
+ </Badge>
433
+ <Badge
434
+ variant="error"
435
+ size="xs"
436
+ iconRight="close"
437
+ onIconRightClick={() => alert('Error badge clicked!')}
438
+ iconRightAriaLabel="Remove error badge"
439
+ >
440
+ Failed
441
+ </Badge>
442
+ </div>
443
+ </div>
444
+
445
+ {/* Non-interactive icons (static) */}
446
+ <div>
447
+ <Code variant="label" className="mb-16">
448
+ Static Icons (Non-interactive)
449
+ </Code>
450
+ <div className="flex flex-wrap gap-8">
451
+ <Badge variant="info" size="xs" iconLeft="info">
452
+ Information
453
+ </Badge>
454
+ <Badge variant="success" size="xs" iconLeft="check">
455
+ Verified
456
+ </Badge>
457
+ <Badge variant="feature" size="xs" iconLeft="money">
458
+ Premium
459
+ </Badge>
460
+ </div>
461
+ </div>
462
+ </div>
463
+ );
464
+ }
465
+
466
+ export const InteractiveBadges: Story = {
467
+ render: () => <InteractiveBadgesComponent />,
468
+ };