aural-ui 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +456 -0
  3. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +1327 -0
  4. package/dist/components/aspect-ratio/index.tsx +10 -0
  5. package/dist/components/aspect-ratio/meta.ts +8 -0
  6. package/dist/components/avatar/Avatar.stories.tsx +645 -0
  7. package/dist/components/avatar/index.tsx +50 -0
  8. package/dist/components/avatar/meta.ts +8 -0
  9. package/dist/components/badge/Badge.stories.tsx +169 -0
  10. package/dist/components/badge/index.tsx +28 -0
  11. package/dist/components/badge/meta.ts +6 -0
  12. package/dist/components/banner/Banner.stories.tsx +475 -0
  13. package/dist/components/banner/index.tsx +256 -0
  14. package/dist/components/banner/meta.ts +36 -0
  15. package/dist/components/button/Button.stories.tsx +74 -0
  16. package/dist/components/button/index.tsx +158 -0
  17. package/dist/components/button/meta.ts +33 -0
  18. package/dist/components/card/Card.stories.tsx +377 -0
  19. package/dist/components/card/index.tsx +85 -0
  20. package/dist/components/card/meta.ts +14 -0
  21. package/dist/components/char-count/CharCount.stories.tsx +334 -0
  22. package/dist/components/char-count/index.tsx +51 -0
  23. package/dist/components/char-count/meta.ts +13 -0
  24. package/dist/components/checkbox/Checkbox.stories.tsx +209 -0
  25. package/dist/components/checkbox/index.tsx +34 -0
  26. package/dist/components/checkbox/meta.ts +19 -0
  27. package/dist/components/chip/Chip.stories.tsx +207 -0
  28. package/dist/components/chip/index.tsx +92 -0
  29. package/dist/components/chip/meta.ts +17 -0
  30. package/dist/components/circular-loader/CircularLoader.stories.tsx +741 -0
  31. package/dist/components/circular-loader/index.tsx +138 -0
  32. package/dist/components/circular-loader/meta.ts +11 -0
  33. package/dist/components/collapsible/Collapsible.stories.tsx +319 -0
  34. package/dist/components/collapsible/index.tsx +158 -0
  35. package/dist/components/collapsible/meta.ts +22 -0
  36. package/dist/components/command/Command.stories.tsx +996 -0
  37. package/dist/components/command/index.tsx +324 -0
  38. package/dist/components/command/meta.ts +18 -0
  39. package/dist/components/dialog/Dialog.stories.tsx +963 -0
  40. package/dist/components/dialog/index.tsx +250 -0
  41. package/dist/components/dialog/meta.ts +28 -0
  42. package/dist/components/divider/Divider.stories.tsx +633 -0
  43. package/dist/components/divider/index.tsx +181 -0
  44. package/dist/components/divider/meta.ts +12 -0
  45. package/dist/components/dot-loader/DotLoader.stories.tsx +352 -0
  46. package/dist/components/dot-loader/index.tsx +78 -0
  47. package/dist/components/dot-loader/meta.ts +14 -0
  48. package/dist/components/dropdown/Dropdown.stories.tsx +1210 -0
  49. package/dist/components/dropdown/index.tsx +479 -0
  50. package/dist/components/dropdown/meta.ts +21 -0
  51. package/dist/components/form/Form.stories.tsx +320 -0
  52. package/dist/components/form/index.tsx +183 -0
  53. package/dist/components/form/meta.ts +11 -0
  54. package/dist/components/helper-text/HelperText.stories.tsx +254 -0
  55. package/dist/components/helper-text/index.tsx +102 -0
  56. package/dist/components/helper-text/meta.ts +18 -0
  57. package/dist/components/hover-card/HoverCard.stories.tsx +1328 -0
  58. package/dist/components/hover-card/index.tsx +42 -0
  59. package/dist/components/hover-card/meta.ts +12 -0
  60. package/dist/components/icon-button/IconButton.stories.tsx +252 -0
  61. package/dist/components/icon-button/index.tsx +130 -0
  62. package/dist/components/icon-button/meta.ts +20 -0
  63. package/dist/components/if-else/if-else.stories.tsx +100 -0
  64. package/dist/components/if-else/index.tsx +56 -0
  65. package/dist/components/if-else/meta.ts +6 -0
  66. package/dist/components/index.ts +70 -0
  67. package/dist/components/input/Input.stories.tsx +431 -0
  68. package/dist/components/input/index.tsx +487 -0
  69. package/dist/components/input/meta.ts +28 -0
  70. package/dist/components/label/Label.stories.tsx +200 -0
  71. package/dist/components/label/index.tsx +43 -0
  72. package/dist/components/label/meta.ts +14 -0
  73. package/dist/components/list/List.stories.tsx +963 -0
  74. package/dist/components/list/index.tsx +567 -0
  75. package/dist/components/list/meta.ts +24 -0
  76. package/dist/components/marquee/Marquee.stories.tsx +819 -0
  77. package/dist/components/marquee/index.tsx +107 -0
  78. package/dist/components/marquee/meta.ts +6 -0
  79. package/dist/components/overlay/Overlay.stories.tsx +954 -0
  80. package/dist/components/overlay/index.tsx +58 -0
  81. package/dist/components/overlay/meta.ts +10 -0
  82. package/dist/components/pagination/Pagination.stories.tsx +354 -0
  83. package/dist/components/pagination/index.tsx +455 -0
  84. package/dist/components/pagination/meta.ts +29 -0
  85. package/dist/components/popover/Popover.stories.tsx +1037 -0
  86. package/dist/components/popover/index.tsx +67 -0
  87. package/dist/components/popover/meta.ts +12 -0
  88. package/dist/components/radio/Radio.stories.tsx +146 -0
  89. package/dist/components/radio/index.tsx +41 -0
  90. package/dist/components/radio/meta.ts +19 -0
  91. package/dist/components/resizable/Resizable.stories.tsx +866 -0
  92. package/dist/components/resizable/index.tsx +55 -0
  93. package/dist/components/resizable/meta.ts +12 -0
  94. package/dist/components/scroll-area/ScrollArea.stories.tsx +1104 -0
  95. package/dist/components/scroll-area/index.tsx +55 -0
  96. package/dist/components/scroll-area/meta.ts +8 -0
  97. package/dist/components/search/Search.stories.tsx +678 -0
  98. package/dist/components/search/index.tsx +141 -0
  99. package/dist/components/search/meta.ts +6 -0
  100. package/dist/components/select/Select.stories.tsx +962 -0
  101. package/dist/components/select/index.tsx +512 -0
  102. package/dist/components/select/meta.ts +40 -0
  103. package/dist/components/sheet/Sheet.stories.tsx +1060 -0
  104. package/dist/components/sheet/index.tsx +440 -0
  105. package/dist/components/sheet/meta.ts +38 -0
  106. package/dist/components/skelton/Skelton.stories.tsx +859 -0
  107. package/dist/components/skelton/index.tsx +17 -0
  108. package/dist/components/skelton/meta.ts +6 -0
  109. package/dist/components/slider/Slider.stories.tsx +876 -0
  110. package/dist/components/slider/index.tsx +156 -0
  111. package/dist/components/slider/meta.ts +29 -0
  112. package/dist/components/stepper/Stepper.stories.tsx +639 -0
  113. package/dist/components/stepper/index.tsx +650 -0
  114. package/dist/components/stepper/meta.ts +19 -0
  115. package/dist/components/switch/Switch.stories.tsx +85 -0
  116. package/dist/components/switch/index.tsx +37 -0
  117. package/dist/components/switch/meta.ts +24 -0
  118. package/dist/components/switch-case/SwitchCase.stories.tsx +209 -0
  119. package/dist/components/switch-case/index.tsx +89 -0
  120. package/dist/components/switch-case/meta.ts +6 -0
  121. package/dist/components/table/Table.stories.tsx +1095 -0
  122. package/dist/components/table/index.tsx +113 -0
  123. package/dist/components/table/meta.ts +20 -0
  124. package/dist/components/tabs/Tabs.stories.tsx +1379 -0
  125. package/dist/components/tabs/index.tsx +186 -0
  126. package/dist/components/tabs/meta.ts +25 -0
  127. package/dist/components/tag/Tag.stories.tsx +625 -0
  128. package/dist/components/tag/index.tsx +320 -0
  129. package/dist/components/tag/meta.ts +52 -0
  130. package/dist/components/textarea/TextArea.stories.tsx +723 -0
  131. package/dist/components/textarea/index.tsx +480 -0
  132. package/dist/components/textarea/meta.ts +23 -0
  133. package/dist/components/toast/Toast.stories.tsx +1427 -0
  134. package/dist/components/toast/index.tsx +26 -0
  135. package/dist/components/toast/meta.ts +19 -0
  136. package/dist/components/toggle/Toggle.stories.tsx +1093 -0
  137. package/dist/components/toggle/index.tsx +44 -0
  138. package/dist/components/toggle/meta.ts +19 -0
  139. package/dist/components/tooltip/Tooltip.stories.tsx +1548 -0
  140. package/dist/components/tooltip/index.tsx +304 -0
  141. package/dist/components/tooltip/meta.ts +21 -0
  142. package/dist/components/typography/Typography.stories.tsx +197 -0
  143. package/dist/components/typography/index.tsx +184 -0
  144. package/dist/components/typography/meta.ts +38 -0
  145. package/dist/fonts/LabGrotesque-Regular.ttf +0 -0
  146. package/dist/fonts/LabGrotesqueTRIAL-Bold.otf +0 -0
  147. package/dist/fonts/LabGrotesqueTRIAL-Light.otf +0 -0
  148. package/dist/fonts/LabGrotesqueTRIAL-Medium.otf +0 -0
  149. package/dist/fonts/LabGrotesqueTRIAL-Regular.otf +0 -0
  150. package/dist/fonts/PPSupplySans-Regular (1).otf +0 -0
  151. package/dist/fonts/PPSupplySans-Regular.otf +0 -0
  152. package/dist/fonts/PPSupplySans-Ultralight.otf +0 -0
  153. package/dist/hooks/index.ts +3 -0
  154. package/dist/hooks/use-previous/UsePrevious.stories.tsx +997 -0
  155. package/dist/hooks/use-previous/index.ts +15 -0
  156. package/dist/hooks/use-previous/meta.ts +6 -0
  157. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +983 -0
  158. package/dist/hooks/use-standalone-pagination/index.ts +146 -0
  159. package/dist/hooks/use-standalone-pagination/meta.ts +6 -0
  160. package/dist/icons/Icons.stories.tsx +29 -0
  161. package/dist/icons/alert-icon/AlertIcon.stories.tsx +991 -0
  162. package/dist/icons/alert-icon/index.tsx +48 -0
  163. package/dist/icons/alert-icon/meta.ts +8 -0
  164. package/dist/icons/all-icons.tsx +738 -0
  165. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +1031 -0
  166. package/dist/icons/angle-down-icon/index.tsx +25 -0
  167. package/dist/icons/angle-down-icon/meta.ts +8 -0
  168. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +1080 -0
  169. package/dist/icons/arrow-box-left-icon/index.tsx +24 -0
  170. package/dist/icons/arrow-box-left-icon/meta.ts +8 -0
  171. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +1151 -0
  172. package/dist/icons/arrow-right-icon/index.tsx +26 -0
  173. package/dist/icons/arrow-right-icon/meta.ts +8 -0
  174. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +1273 -0
  175. package/dist/icons/arrow-right-up-icon/index.tsx +24 -0
  176. package/dist/icons/arrow-right-up-icon/meta.ts +8 -0
  177. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +670 -0
  178. package/dist/icons/art-board-icon/index.tsx +24 -0
  179. package/dist/icons/art-board-icon/meta.ts +7 -0
  180. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +1244 -0
  181. package/dist/icons/audio-bar-icon/index.tsx +19 -0
  182. package/dist/icons/audio-bar-icon/meta.ts +8 -0
  183. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +1239 -0
  184. package/dist/icons/bubble-check-icon/index.tsx +24 -0
  185. package/dist/icons/bubble-check-icon/meta.ts +8 -0
  186. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +1228 -0
  187. package/dist/icons/bubble-crossed-icon/index.tsx +24 -0
  188. package/dist/icons/bubble-crossed-icon/meta.ts +8 -0
  189. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +912 -0
  190. package/dist/icons/bubble-sparkle-icon/index.tsx +26 -0
  191. package/dist/icons/bubble-sparkle-icon/meta.ts +8 -0
  192. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +1021 -0
  193. package/dist/icons/chevron-double-left-icon/index.tsx +34 -0
  194. package/dist/icons/chevron-double-left-icon/meta.ts +8 -0
  195. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +1021 -0
  196. package/dist/icons/chevron-double-right-icon/index.tsx +34 -0
  197. package/dist/icons/chevron-double-right-icon/meta.ts +8 -0
  198. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +1001 -0
  199. package/dist/icons/chevron-down-icon/index.tsx +27 -0
  200. package/dist/icons/chevron-down-icon/meta.ts +8 -0
  201. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +1029 -0
  202. package/dist/icons/chevron-left-icon/index.tsx +27 -0
  203. package/dist/icons/chevron-left-icon/meta.ts +8 -0
  204. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +1021 -0
  205. package/dist/icons/chevron-right-icon/index.tsx +27 -0
  206. package/dist/icons/chevron-right-icon/meta.ts +8 -0
  207. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +1036 -0
  208. package/dist/icons/chevron-up-icon/index.tsx +27 -0
  209. package/dist/icons/chevron-up-icon/meta.ts +8 -0
  210. package/dist/icons/command-icon/CommandIcon.stories.tsx +1098 -0
  211. package/dist/icons/command-icon/index.tsx +24 -0
  212. package/dist/icons/command-icon/meta.ts +8 -0
  213. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +1061 -0
  214. package/dist/icons/cross-circle-icon/index.tsx +23 -0
  215. package/dist/icons/cross-circle-icon/meta.ts +8 -0
  216. package/dist/icons/cross-icon/CrossIcon.stories.tsx +1027 -0
  217. package/dist/icons/cross-icon/index.tsx +24 -0
  218. package/dist/icons/cross-icon/meta.ts +8 -0
  219. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +1092 -0
  220. package/dist/icons/edit-big-icon/index.tsx +22 -0
  221. package/dist/icons/edit-big-icon/meta.ts +8 -0
  222. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +1090 -0
  223. package/dist/icons/eye-close-icon/index.tsx +26 -0
  224. package/dist/icons/eye-close-icon/meta.ts +8 -0
  225. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +1098 -0
  226. package/dist/icons/eye-open-icon/index.tsx +24 -0
  227. package/dist/icons/eye-open-icon/meta.ts +8 -0
  228. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +1071 -0
  229. package/dist/icons/feature-shine-icon/index.tsx +29 -0
  230. package/dist/icons/feature-shine-icon/meta.ts +8 -0
  231. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +1115 -0
  232. package/dist/icons/file-chart-icon/index.tsx +24 -0
  233. package/dist/icons/file-chart-icon/meta.ts +8 -0
  234. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +668 -0
  235. package/dist/icons/file-text-icon/index.tsx +24 -0
  236. package/dist/icons/file-text-icon/meta.ts +8 -0
  237. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +1239 -0
  238. package/dist/icons/grip-vertical-icon/index.tsx +28 -0
  239. package/dist/icons/grip-vertical-icon/meta.ts +8 -0
  240. package/dist/icons/image-icon/ImageIcon.stories.tsx +1181 -0
  241. package/dist/icons/image-icon/index.tsx +24 -0
  242. package/dist/icons/image-icon/meta.ts +8 -0
  243. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +1248 -0
  244. package/dist/icons/import-folder-icon/index.tsx +22 -0
  245. package/dist/icons/import-folder-icon/meta.ts +8 -0
  246. package/dist/icons/index.ts +46 -0
  247. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +1272 -0
  248. package/dist/icons/light-bulb-simple-icon/index.tsx +24 -0
  249. package/dist/icons/light-bulb-simple-icon/meta.ts +8 -0
  250. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +1245 -0
  251. package/dist/icons/magic-book-icon/index.tsx +32 -0
  252. package/dist/icons/magic-book-icon/meta.ts +8 -0
  253. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +1251 -0
  254. package/dist/icons/maintenance-icon/index.tsx +23 -0
  255. package/dist/icons/maintenance-icon/meta.ts +8 -0
  256. package/dist/icons/message-icon/MessageIcon.stories.tsx +595 -0
  257. package/dist/icons/message-icon/index.tsx +30 -0
  258. package/dist/icons/message-icon/meta.ts +8 -0
  259. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +1245 -0
  260. package/dist/icons/move-horizontal-icon/index.tsx +23 -0
  261. package/dist/icons/move-horizontal-icon/meta.ts +8 -0
  262. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +1196 -0
  263. package/dist/icons/move-vertical-icon/index.tsx +23 -0
  264. package/dist/icons/move-vertical-icon/meta.ts +8 -0
  265. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +1167 -0
  266. package/dist/icons/page-search-icon/index.tsx +21 -0
  267. package/dist/icons/page-search-icon/meta.ts +8 -0
  268. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +1131 -0
  269. package/dist/icons/pencil-icon/index.tsx +21 -0
  270. package/dist/icons/pencil-icon/meta.ts +8 -0
  271. package/dist/icons/plus-icon/PlusIcon.stories.tsx +1151 -0
  272. package/dist/icons/plus-icon/index.tsx +24 -0
  273. package/dist/icons/plus-icon/meta.ts +8 -0
  274. package/dist/icons/search-icon/SearchIcon.stories.tsx +1181 -0
  275. package/dist/icons/search-icon/index.tsx +24 -0
  276. package/dist/icons/search-icon/meta.ts +8 -0
  277. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +1167 -0
  278. package/dist/icons/site-logo-icon/index.tsx +79 -0
  279. package/dist/icons/site-logo-icon/meta.ts +8 -0
  280. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +637 -0
  281. package/dist/icons/spinner-gradient-icon/index.tsx +53 -0
  282. package/dist/icons/spinner-gradient-icon/meta.ts +8 -0
  283. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +644 -0
  284. package/dist/icons/spinner-solid-icon/index.tsx +59 -0
  285. package/dist/icons/spinner-solid-icon/meta.ts +8 -0
  286. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +736 -0
  287. package/dist/icons/spinner-solid-neutral-icon/index.tsx +53 -0
  288. package/dist/icons/spinner-solid-neutral-icon/meta.ts +8 -0
  289. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +1204 -0
  290. package/dist/icons/tick-circle-icon/index.tsx +23 -0
  291. package/dist/icons/tick-circle-icon/meta.ts +8 -0
  292. package/dist/icons/tick-icon/TickIcon.stories.tsx +1340 -0
  293. package/dist/icons/tick-icon/index.tsx +24 -0
  294. package/dist/icons/tick-icon/meta.ts +8 -0
  295. package/dist/icons/trash-icon/TrashIcon.stories.tsx +996 -0
  296. package/dist/icons/trash-icon/index.tsx +24 -0
  297. package/dist/icons/trash-icon/meta.ts +8 -0
  298. package/dist/icons/upload-icon/UploadIcon.stories.tsx +947 -0
  299. package/dist/icons/upload-icon/index.tsx +24 -0
  300. package/dist/icons/upload-icon/meta.ts +8 -0
  301. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +1045 -0
  302. package/dist/icons/vertical-menu-icon/index.tsx +27 -0
  303. package/dist/icons/vertical-menu-icon/meta.ts +8 -0
  304. package/dist/index.d.ts +6 -0
  305. package/dist/index.js +206 -0
  306. package/dist/lib/utils.ts +6 -0
  307. package/dist/styles/aural-theme.css +1008 -0
  308. package/package.json +142 -0
@@ -0,0 +1,487 @@
1
+ import React, {
2
+ forwardRef,
3
+ ForwardRefExoticComponent,
4
+ ReactNode,
5
+ RefAttributes,
6
+ useState,
7
+ } from "react"
8
+ import CharCount from "@components/char-count"
9
+ import HelperText from "@components/helper-text"
10
+ import { Else, If, IfElse } from "@components/if-else"
11
+ import { Label } from "@components/label"
12
+ import { EyeCloseIcon } from "@icons/eye-close-icon"
13
+ import { EyeOpenIcon } from "@icons/eye-open-icon"
14
+ import { cn } from "@lib/utils"
15
+ import { cva } from "class-variance-authority"
16
+
17
+ interface InputComponent
18
+ extends ForwardRefExoticComponent<
19
+ InputProps & RefAttributes<HTMLInputElement>
20
+ > {
21
+ Root: typeof InputRoot
22
+ Label: typeof InputLabel
23
+ Wrapper: typeof InputWrapper
24
+ StartIcon: typeof StartIcon
25
+ EndIcon: typeof EndIcon
26
+ PasswordToggle: typeof PasswordToggle
27
+ Base: typeof InputBase
28
+ HelperText: typeof HelperText
29
+ CharCount: typeof CharCount
30
+ }
31
+
32
+ // CVA for input variants
33
+ export const inputVariants = cva(
34
+ // Base styles
35
+ "block w-full focus:outline-none transition-all duration-200 border-solid tracking-wide placeholder:text-fm-placeholder font-fm-text text-fm-primary",
36
+ {
37
+ variants: {
38
+ variant: {
39
+ default: "border-fm-divider-primary focus:border-fm-divider-contrast ",
40
+ error: "border-fm-divider-negative focus:border-fm-divider-negative",
41
+ warning: "border-fm-divider-warning focus:border-fm-divider-warning",
42
+ success: "border-fm-divider-positive focus:border-fm-divider-positive",
43
+ },
44
+ decoration: {
45
+ underline: "border-b h-11 leading-fm-xl [font-size:var(--text-fm-xl)]",
46
+ outline:
47
+ "border rounded-fm-s h-12 leading-fm-md [font-size:var(--text-fm-md)] px-3 py-4",
48
+ filled:
49
+ "h-10 rounded-fm-s bg-fm-surface-frosted/20 border leading-fm-md [font-size:var(--text-fm-md)] px-4",
50
+ },
51
+ state: {
52
+ default: "",
53
+ focused: "",
54
+ disabled:
55
+ "border-fm-divider-tertiary !text-fm-inactive cursor-not-allowed",
56
+ },
57
+ },
58
+
59
+ defaultVariants: {
60
+ variant: "default",
61
+ state: "default",
62
+ decoration: "underline",
63
+ },
64
+ }
65
+ )
66
+
67
+ // Types
68
+ type InputVariant = "default" | "error" | "warning" | "success"
69
+ type InputDecoration = "underline" | "outline" | "filled"
70
+ type InputProps = {
71
+ label?: ReactNode
72
+ helperText?: ReactNode
73
+ placeholder?: string
74
+ variant?: InputVariant
75
+ disabled?: boolean
76
+ decoration?: InputDecoration
77
+ type?: string
78
+ required?: boolean
79
+ fullWidth?: boolean
80
+ className?: string
81
+ value?: string | number
82
+ defaultValue?: string | number
83
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
84
+ onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void
85
+ onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void
86
+ startIcon?: ReactNode
87
+ endIcon?: ReactNode
88
+ id?: string
89
+ name?: string
90
+ maxLength?: number
91
+ min?: number
92
+ max?: number
93
+ unstyled?: boolean
94
+ classes?: {
95
+ root?: string
96
+ label?: string
97
+ wrapper?: string
98
+ startIcon?: string
99
+ endIcon?: string
100
+ passwordToggle?: string
101
+ helperText?: string
102
+ characterCounter?: string
103
+ input?: string
104
+ }
105
+ }
106
+
107
+ // Sub-components for atomic design pattern
108
+ const InputRoot = forwardRef<
109
+ HTMLDivElement,
110
+ React.PropsWithChildren<{ className?: string; fullWidth?: boolean }>
111
+ >(({ children, className = "", fullWidth = false }, ref) => (
112
+ <div
113
+ ref={ref}
114
+ className={cn(
115
+ {
116
+ "w-full": fullWidth,
117
+ },
118
+ className
119
+ )}
120
+ >
121
+ {children}
122
+ </div>
123
+ ))
124
+ InputRoot.displayName = "InputRoot"
125
+
126
+ const InputLabel = forwardRef<
127
+ HTMLLabelElement,
128
+ {
129
+ htmlFor?: string
130
+ className?: string
131
+ children: ReactNode
132
+ disabled?: boolean
133
+ required?: boolean
134
+ }
135
+ >((props, ref) => {
136
+ return <Label ref={ref} {...props} />
137
+ })
138
+ InputLabel.displayName = "InputLabel"
139
+
140
+ const InputWrapper = forwardRef<
141
+ HTMLDivElement,
142
+ React.PropsWithChildren<{ className?: string }>
143
+ >(({ children, className = "" }, ref) => (
144
+ <div ref={ref} className={cn("relative mt-1", className)}>
145
+ {children}
146
+ </div>
147
+ ))
148
+ InputWrapper.displayName = "InputWrapper"
149
+
150
+ const StartIcon = forwardRef<
151
+ HTMLDivElement,
152
+ React.PropsWithChildren<{ className?: string }>
153
+ >(({ children, className = "" }, ref) => (
154
+ <div
155
+ ref={ref}
156
+ className={cn(
157
+ "pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3",
158
+ className
159
+ )}
160
+ >
161
+ {children}
162
+ </div>
163
+ ))
164
+ StartIcon.displayName = "StartIcon"
165
+
166
+ const EndIcon = forwardRef<
167
+ HTMLDivElement,
168
+ React.PropsWithChildren<{ className?: string }>
169
+ >(({ children, className = "" }, ref) => (
170
+ <div
171
+ ref={ref}
172
+ className={cn(
173
+ "absolute inset-y-0 right-0 flex items-center pr-3",
174
+ className
175
+ )}
176
+ >
177
+ {children}
178
+ </div>
179
+ ))
180
+ EndIcon.displayName = "EndIcon"
181
+
182
+ const PasswordToggle = forwardRef<
183
+ HTMLButtonElement,
184
+ {
185
+ isVisible: boolean
186
+ onToggle: () => void
187
+ className?: string
188
+ }
189
+ >(({ isVisible, onToggle, className = "" }, ref) => (
190
+ <button
191
+ ref={ref}
192
+ type="button"
193
+ onClick={onToggle}
194
+ className={cn(
195
+ "text-fm-primary hover:text-fm-primary/90 h-full focus:outline-none",
196
+ className
197
+ )}
198
+ >
199
+ <IfElse condition={isVisible}>
200
+ <If>
201
+ <EyeCloseIcon />
202
+ </If>
203
+ <Else>
204
+ <EyeOpenIcon />
205
+ </Else>
206
+ </IfElse>
207
+ </button>
208
+ ))
209
+
210
+ // InputBase component - Core input functionality without any wrapper elements
211
+ const InputBase = forwardRef<
212
+ HTMLInputElement,
213
+ {
214
+ variant?: InputVariant
215
+ decoration?: InputDecoration
216
+ disabled?: boolean
217
+ className?: string
218
+ unstyled?: boolean
219
+ type?: string
220
+ placeholder?: string
221
+ value?: string | number
222
+ defaultValue?: string | number
223
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
224
+ onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void
225
+ onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void
226
+ id?: string
227
+ name?: string
228
+ required?: boolean
229
+ maxLength?: number
230
+ startIcon?: boolean // Indicates if start icon spacing should be applied
231
+ endIcon?: boolean // Indicates if end icon spacing should be applied
232
+ } & Omit<
233
+ React.InputHTMLAttributes<HTMLInputElement>,
234
+ "onChange" | "onBlur" | "onFocus" | "defaultValue"
235
+ >
236
+ >(
237
+ (
238
+ {
239
+ variant = "default",
240
+ decoration = "underline",
241
+ disabled = false,
242
+ className = "",
243
+ unstyled = false,
244
+ type = "text",
245
+ placeholder = "",
246
+ value,
247
+ defaultValue,
248
+ onChange,
249
+ onBlur,
250
+ onFocus,
251
+ id,
252
+ name,
253
+ required = false,
254
+ maxLength,
255
+ startIcon = false,
256
+ endIcon = false,
257
+ ...props
258
+ },
259
+ ref
260
+ ) => {
261
+ const [isFocused, setIsFocused] = useState(false)
262
+
263
+ // Handle focus state
264
+ const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
265
+ setIsFocused(true)
266
+ if (onFocus) onFocus(e)
267
+ }
268
+
269
+ // Handle blur state
270
+ const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
271
+ setIsFocused(false)
272
+ if (onBlur) onBlur(e)
273
+ }
274
+
275
+ // Handle input change
276
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
277
+ if (onChange) onChange(e)
278
+ }
279
+
280
+ // Determine focus state
281
+ const state = disabled ? "disabled" : isFocused ? "focused" : "default"
282
+
283
+ // Apply styles only if not unstyled
284
+ const inputClassName = unstyled
285
+ ? className
286
+ : inputVariants({
287
+ variant,
288
+ state,
289
+ decoration,
290
+ className: cn(
291
+ {
292
+ "pl-10": startIcon,
293
+ "pr-10": endIcon,
294
+ },
295
+ className
296
+ ),
297
+ })
298
+
299
+ return (
300
+ <input
301
+ ref={ref}
302
+ type={type}
303
+ id={id}
304
+ name={name}
305
+ className={inputClassName}
306
+ placeholder={placeholder}
307
+ disabled={disabled}
308
+ value={value}
309
+ defaultValue={defaultValue}
310
+ onChange={handleChange}
311
+ onFocus={handleFocus}
312
+ onBlur={handleBlur}
313
+ required={required}
314
+ maxLength={maxLength}
315
+ {...props}
316
+ />
317
+ )
318
+ }
319
+ )
320
+ InputBase.displayName = "InputBase"
321
+
322
+ // Main Input component
323
+ const Input = forwardRef<HTMLInputElement, InputProps>(
324
+ (
325
+ {
326
+ label,
327
+ helperText,
328
+ placeholder = "",
329
+ variant = "default",
330
+ disabled = false,
331
+ type = "text",
332
+ required = false,
333
+ fullWidth = false,
334
+ className = "",
335
+ value,
336
+ defaultValue,
337
+ onChange,
338
+ onBlur,
339
+ onFocus,
340
+ startIcon,
341
+ endIcon,
342
+ id,
343
+ name,
344
+ maxLength,
345
+ decoration,
346
+ unstyled = false,
347
+ classes = {},
348
+ ...props
349
+ },
350
+ ref
351
+ ) => {
352
+ const [inputValue, setInputValue] = useState(value || defaultValue || "")
353
+ const [isPasswordVisible, setIsPasswordVisible] = useState(false)
354
+
355
+ // Handle input change
356
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
357
+ // Only update internal state if component is uncontrolled (no value prop)
358
+ if (value === undefined) {
359
+ setInputValue(e.target.value)
360
+ }
361
+ if (onChange) onChange(e)
362
+ }
363
+
364
+ // Toggle password visibility
365
+ const togglePasswordVisibility = () => {
366
+ setIsPasswordVisible(!isPasswordVisible)
367
+ }
368
+
369
+ // Determine input type for password fields
370
+ const inputType = type === "password" && isPasswordVisible ? "text" : type
371
+
372
+ // Determine which value to use for character count
373
+ const currentValue = value !== undefined ? value : inputValue
374
+ const currentLength = String(currentValue).length || 0
375
+
376
+ return (
377
+ <InputRoot fullWidth={fullWidth} className={cn(className, classes.root)}>
378
+ <div className="flex items-center justify-between gap-2">
379
+ {/* Label */}
380
+ <If condition={!!label}>
381
+ <InputLabel
382
+ htmlFor={id || name}
383
+ disabled={disabled}
384
+ required={required}
385
+ className={cn("flex-1", classes.label)}
386
+ >
387
+ {label}
388
+ </InputLabel>
389
+ </If>
390
+ <If condition={!!maxLength}>
391
+ <CharCount
392
+ currentLength={currentLength}
393
+ maxLength={maxLength || 0}
394
+ className={cn(classes.characterCounter)}
395
+ />
396
+ </If>
397
+ </div>
398
+
399
+ {/* Input wrapper for icons */}
400
+ <InputWrapper className={cn(classes.wrapper)}>
401
+ {/* Start icon */}
402
+ <If condition={!!startIcon}>
403
+ <StartIcon className={classes.startIcon}>{startIcon}</StartIcon>
404
+ </If>
405
+
406
+ {/* Input element using InputBase */}
407
+ <InputBase
408
+ ref={ref}
409
+ type={inputType}
410
+ id={id || name}
411
+ name={name}
412
+ variant={variant}
413
+ decoration={decoration}
414
+ disabled={disabled}
415
+ placeholder={placeholder}
416
+ value={value !== undefined ? value : inputValue}
417
+ defaultValue={value === undefined ? defaultValue : undefined}
418
+ onChange={handleChange}
419
+ onFocus={onFocus}
420
+ onBlur={onBlur}
421
+ required={required}
422
+ maxLength={maxLength}
423
+ startIcon={!!startIcon}
424
+ endIcon={!!(endIcon || type === "password")}
425
+ unstyled={unstyled}
426
+ className={unstyled ? className : classes.input}
427
+ {...props}
428
+ />
429
+
430
+ {/* End icon or password toggle */}
431
+ <If condition={!!endIcon || type === "password"}>
432
+ <EndIcon className={cn(classes.endIcon)}>
433
+ <IfElse condition={type === "password"}>
434
+ <If>
435
+ <PasswordToggle
436
+ isVisible={isPasswordVisible}
437
+ onToggle={togglePasswordVisibility}
438
+ className={cn(
439
+ { "pointer-events-none": disabled },
440
+ classes.passwordToggle
441
+ )}
442
+ />
443
+ </If>
444
+ <Else>{endIcon}</Else>
445
+ </IfElse>
446
+ </EndIcon>
447
+ </If>
448
+ </InputWrapper>
449
+
450
+ {/* Helper text */}
451
+ <If condition={!!helperText}>
452
+ <HelperText
453
+ variant={variant}
454
+ disabled={disabled}
455
+ className={cn(classes.helperText)}
456
+ >
457
+ {helperText}
458
+ </HelperText>
459
+ </If>
460
+ </InputRoot>
461
+ )
462
+ }
463
+ ) as InputComponent
464
+ Input.displayName = "Input"
465
+
466
+ // Compose Input with its sub-components
467
+ Input.Root = InputRoot
468
+ Input.Label = InputLabel
469
+ Input.Wrapper = InputWrapper
470
+ Input.StartIcon = StartIcon
471
+ Input.EndIcon = EndIcon
472
+ Input.PasswordToggle = PasswordToggle
473
+ Input.Base = InputBase
474
+ Input.HelperText = HelperText
475
+ Input.CharCount = CharCount
476
+
477
+ export default Input
478
+ export {
479
+ InputRoot,
480
+ InputLabel,
481
+ InputWrapper,
482
+ StartIcon,
483
+ EndIcon,
484
+ PasswordToggle,
485
+ InputBase,
486
+ }
487
+ export type { InputProps, InputVariant, InputComponent }
@@ -0,0 +1,28 @@
1
+ export const meta = {
2
+ dependencies: {},
3
+ devDependencies: {},
4
+ internalDependencies: [
5
+ "char-count",
6
+ "helper-text",
7
+ "if-else",
8
+ "label",
9
+ "eye-close-icon",
10
+ "eye-open-icon",
11
+ ],
12
+ tokens: [
13
+ "--color-fm-divider-contrast",
14
+ "--color-fm-divider-negative",
15
+ "--color-fm-divider-positive",
16
+ "--color-fm-divider-primary",
17
+ "--color-fm-divider-tertiary",
18
+ "--color-fm-divider-warning",
19
+ "--color-fm-inactive",
20
+ "--color-fm-placeholder",
21
+ "--color-fm-primary",
22
+ "--color-fm-surface-frosted",
23
+ "--leading-fm-md",
24
+ "--leading-fm-xl",
25
+ "--radius-fm-s",
26
+ "--text-fm-md",
27
+ ],
28
+ }
@@ -0,0 +1,200 @@
1
+ import React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+
4
+ import Label from "."
5
+
6
+ const meta: Meta<typeof Label> = {
7
+ title: "Components/UI/Label",
8
+ component: Label,
9
+ parameters: {
10
+ layout: "centered",
11
+ },
12
+ tags: ["autodocs"],
13
+ argTypes: {
14
+ children: {
15
+ control: "text",
16
+ description: "The content of the label",
17
+ },
18
+ htmlFor: {
19
+ control: "text",
20
+ description: "The ID of the form control this label is associated with",
21
+ },
22
+ disabled: {
23
+ control: "boolean",
24
+ description: "Whether the label is disabled",
25
+ },
26
+ required: {
27
+ control: "boolean",
28
+ description: "Whether to show the required indicator (*)",
29
+ },
30
+ className: {
31
+ control: "text",
32
+ description: "Additional CSS classes to apply",
33
+ },
34
+ },
35
+ }
36
+
37
+ export default meta
38
+ type Story = StoryObj<typeof meta>
39
+
40
+ export const Default: Story = {
41
+ args: {
42
+ children: "Label Text",
43
+ htmlFor: "example-input",
44
+ disabled: false,
45
+ required: false,
46
+ },
47
+ }
48
+
49
+ export const Required: Story = {
50
+ args: {
51
+ ...Default.args,
52
+ required: true,
53
+ children: "Required Label",
54
+ },
55
+ }
56
+
57
+ export const Disabled: Story = {
58
+ args: {
59
+ ...Default.args,
60
+ disabled: true,
61
+ children: "Disabled Label",
62
+ },
63
+ }
64
+
65
+ export const WithCustomClass: Story = {
66
+ args: {
67
+ ...Default.args,
68
+ className: "text-blue-500 font-bold",
69
+ children: "Styled Label",
70
+ },
71
+ }
72
+
73
+ // Example showing label with an input
74
+ export const WithInput: Story = {
75
+ render: (args) => (
76
+ <div className="space-y-2">
77
+ <Label htmlFor="example-input" {...args}>
78
+ {args.children}
79
+ </Label>
80
+ <input
81
+ id="example-input"
82
+ type="text"
83
+ className="w-full rounded-md border border-gray-300 p-2"
84
+ placeholder="Enter text here"
85
+ disabled={args.disabled}
86
+ required={args.required}
87
+ />
88
+ </div>
89
+ ),
90
+ args: {
91
+ ...Default.args,
92
+ children: "Email Address",
93
+ },
94
+ }
95
+
96
+ // Example showing multiple labels with different states
97
+ export const LabelExamples: Story = {
98
+ render: () => (
99
+ <div className="w-64 space-y-4">
100
+ <div className="space-y-2">
101
+ <Label htmlFor="username">Username</Label>
102
+ <input
103
+ id="username"
104
+ type="text"
105
+ className="w-full rounded-md border border-gray-300 p-2"
106
+ placeholder="Enter username"
107
+ />
108
+ </div>
109
+
110
+ <div className="space-y-2">
111
+ <Label htmlFor="email" required>
112
+ Email
113
+ </Label>
114
+ <input
115
+ id="email"
116
+ type="email"
117
+ className="w-full rounded-md border border-gray-300 p-2"
118
+ placeholder="Enter email"
119
+ required
120
+ />
121
+ </div>
122
+
123
+ <div className="space-y-2">
124
+ <Label htmlFor="disabled-field" disabled>
125
+ Disabled Field
126
+ </Label>
127
+ <input
128
+ id="disabled-field"
129
+ type="text"
130
+ className="w-full rounded-md border border-gray-200 bg-gray-100 p-2 text-gray-400"
131
+ placeholder="Disabled"
132
+ disabled
133
+ />
134
+ </div>
135
+ </div>
136
+ ),
137
+ }
138
+
139
+ // Example showing form layout
140
+ export const FormLayout: Story = {
141
+ render: () => (
142
+ <div className="mx-auto max-w-md rounded-xl bg-white p-4 shadow-md">
143
+ <form className="space-y-4">
144
+ <h2 className="mb-4 text-xl font-semibold">Contact Information</h2>
145
+
146
+ <div className="space-y-2">
147
+ <Label htmlFor="form-name" required>
148
+ Full Name
149
+ </Label>
150
+ <input
151
+ id="form-name"
152
+ type="text"
153
+ className="w-full rounded-md border border-gray-300 p-2"
154
+ placeholder="John Doe"
155
+ required
156
+ />
157
+ </div>
158
+
159
+ <div className="space-y-2">
160
+ <Label htmlFor="form-email" required>
161
+ Email Address
162
+ </Label>
163
+ <input
164
+ id="form-email"
165
+ type="email"
166
+ className="w-full rounded-md border border-gray-300 p-2"
167
+ placeholder="john@example.com"
168
+ required
169
+ />
170
+ </div>
171
+
172
+ <div className="space-y-2">
173
+ <Label htmlFor="form-phone">Phone Number</Label>
174
+ <input
175
+ id="form-phone"
176
+ type="tel"
177
+ className="w-full rounded-md border border-gray-300 p-2"
178
+ placeholder="+1 (555) 123-4567"
179
+ />
180
+ </div>
181
+
182
+ <div className="space-y-2">
183
+ <Label htmlFor="form-message">Message</Label>
184
+ <textarea
185
+ id="form-message"
186
+ className="h-32 w-full rounded-md border border-gray-300 p-2"
187
+ placeholder="Your message here..."
188
+ />
189
+ </div>
190
+
191
+ <button
192
+ type="submit"
193
+ className="rounded-md bg-blue-500 px-4 py-2 text-white transition-colors hover:bg-blue-600"
194
+ >
195
+ Submit
196
+ </button>
197
+ </form>
198
+ </div>
199
+ ),
200
+ }