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,1095 @@
1
+ import React from "react"
2
+ import { Badge } from "@components/badge"
3
+ import { Button } from "@components/button"
4
+ import { Checkbox } from "@components/checkbox"
5
+ import {
6
+ ChevronDownIcon,
7
+ ChevronUpIcon,
8
+ EditBigIcon,
9
+ EyeOpenIcon,
10
+ TrashIcon,
11
+ VerticalMenuIcon,
12
+ } from "@icons/index"
13
+ import type { Meta, StoryObj } from "@storybook/react"
14
+
15
+ import {
16
+ Table,
17
+ TableBody,
18
+ TableCaption,
19
+ TableCell,
20
+ TableFooter,
21
+ TableHead,
22
+ TableHeader,
23
+ TableRow,
24
+ } from "."
25
+
26
+ const meta: Meta<typeof Table> = {
27
+ title: "Components/UI/Table",
28
+ component: Table,
29
+ parameters: {
30
+ layout: "fullscreen",
31
+ backgrounds: {
32
+ default: "dark",
33
+ values: [
34
+ { name: "dark", value: "#0a0a0a" },
35
+ { name: "light", value: "#ffffff" },
36
+ ],
37
+ },
38
+ docs: {
39
+ description: {
40
+ component: `
41
+ # Table Component
42
+
43
+ A comprehensive table component system built with semantic HTML elements and design system integration.
44
+
45
+ ## Components
46
+
47
+ ### Core Components
48
+ - **Table**: Root table wrapper with overflow handling
49
+ - **TableHeader**: Table header (\`<thead>\`) element
50
+ - **TableBody**: Table body (\`<tbody>\`) element
51
+ - **TableFooter**: Table footer (\`<tfoot>\`) element
52
+ - **TableRow**: Table row (\`<tr>\`) with hover and selection states
53
+ - **TableHead**: Table header cell (\`<th>\`) with design system styling
54
+ - **TableCell**: Table data cell (\`<td>\`) with consistent typography
55
+ - **TableCaption**: Table caption with tertiary label styling
56
+
57
+ ## Features
58
+
59
+ - **Responsive Design**: Horizontal scroll on smaller screens
60
+ - **Interactive Rows**: Hover effects and selection states
61
+ - **Checkbox Integration**: Built-in support for row selection
62
+ - **Typography System**: Consistent text styling with design tokens
63
+ - **Semantic HTML**: Proper table structure for accessibility
64
+ - **Design System**: Integrated with FM design tokens
65
+ - **Customizable**: All components accept className for customization
66
+ - **Data Slots**: Component identification with data-slot attributes
67
+
68
+ ## Styling
69
+
70
+ ### Table Structure
71
+ - **Background**: \`bg-fm-surface-primary\` - Primary surface background
72
+ - **Container**: Responsive overflow with \`overflow-x-auto\`
73
+ - **Layout**: Full width with \`w-full\`
74
+
75
+ ### TableHead Styling
76
+ - **Typography**: Brand font with small leading
77
+ - **Color**: \`text-fm-tertiary\` - Tertiary text color
78
+ - **Text**: Uppercase, left-aligned, nowrap
79
+ - **Size**: \`--text-fm-sm\` design token
80
+ - **Padding**: \`p-4\` consistent spacing
81
+
82
+ ### TableCell Styling
83
+ - **Typography**: Text font with medium leading
84
+ - **Color**: \`text-fm-primary\` - Primary text color
85
+ - **Text**: Left-aligned, nowrap
86
+ - **Size**: \`--text-fm-md\` design token
87
+ - **Padding**: \`p-4\` consistent spacing
88
+
89
+ ### TableRow Interactions
90
+ - **Hover**: \`hover:bg-fm-surface-frosted/30\` - Subtle frosted effect
91
+ - **Selected**: \`data-[state=selected]:bg-fm-surface-frosted/50\` - Stronger selection state
92
+ - **Transition**: Smooth color transitions
93
+
94
+ ### Checkbox Integration
95
+ - **Positioning**: Automatic translation for alignment
96
+ - **Padding**: Reduced right padding for checkbox columns
97
+ - **Accessibility**: Proper role attributes maintained
98
+
99
+ ## Usage Examples
100
+
101
+ ### Basic Table
102
+ \`\`\`tsx
103
+ <Table>
104
+ <TableHeader>
105
+ <TableRow>
106
+ <TableHead>Name</TableHead>
107
+ <TableHead>Email</TableHead>
108
+ <TableHead>Role</TableHead>
109
+ </TableRow>
110
+ </TableHeader>
111
+ <TableBody>
112
+ <TableRow>
113
+ <TableCell>John Doe</TableCell>
114
+ <TableCell>john@example.com</TableCell>
115
+ <TableCell>Admin</TableCell>
116
+ </TableRow>
117
+ </TableBody>
118
+ </Table>
119
+ \`\`\`
120
+
121
+ ### With Selection
122
+ \`\`\`tsx
123
+ <Table>
124
+ <TableHeader>
125
+ <TableRow>
126
+ <TableHead>
127
+ <Checkbox />
128
+ </TableHead>
129
+ <TableHead>Name</TableHead>
130
+ <TableHead>Status</TableHead>
131
+ </TableRow>
132
+ </TableHeader>
133
+ <TableBody>
134
+ <TableRow data-state="selected">
135
+ <TableCell>
136
+ <Checkbox checked />
137
+ </TableCell>
138
+ <TableCell>Selected Row</TableCell>
139
+ <TableCell>Active</TableCell>
140
+ </TableRow>
141
+ </TableBody>
142
+ </Table>
143
+ \`\`\`
144
+
145
+ ### With Actions
146
+ \`\`\`tsx
147
+ <Table>
148
+ <TableBody>
149
+ <TableRow>
150
+ <TableCell>Data</TableCell>
151
+ <TableCell>
152
+ <div className="flex gap-2">
153
+ <Button size="sm" variant="ghost">Edit</Button>
154
+ <Button size="sm" variant="ghost">Delete</Button>
155
+ </div>
156
+ </TableCell>
157
+ </TableRow>
158
+ </TableBody>
159
+ </Table>
160
+ \`\`\`
161
+
162
+ ### With Caption and Footer
163
+ \`\`\`tsx
164
+ <Table>
165
+ <TableCaption>User management table</TableCaption>
166
+ <TableHeader>
167
+ <TableRow>
168
+ <TableHead>Name</TableHead>
169
+ <TableHead>Count</TableHead>
170
+ </TableRow>
171
+ </TableHeader>
172
+ <TableBody>
173
+ <TableRow>
174
+ <TableCell>Users</TableCell>
175
+ <TableCell>150</TableCell>
176
+ </TableRow>
177
+ </TableBody>
178
+ <TableFooter>
179
+ <TableRow>
180
+ <TableCell>Total</TableCell>
181
+ <TableCell>150</TableCell>
182
+ </TableRow>
183
+ </TableFooter>
184
+ </Table>
185
+ \`\`\`
186
+
187
+ ## Accessibility
188
+
189
+ - **Semantic HTML**: Proper table structure with thead, tbody, tfoot
190
+ - **ARIA Support**: Compatible with screen readers
191
+ - **Keyboard Navigation**: Standard table navigation
192
+ - **Role Attributes**: Proper checkbox roles maintained
193
+ - **Focus Management**: Consistent focus indicators
194
+ - **Screen Reader**: Table structure announced properly
195
+
196
+ ## Design Tokens
197
+
198
+ ### Typography
199
+ - \`font-fm-brand\`: Header typography
200
+ - \`font-fm-text\`: Cell typography
201
+ - \`leading-fm-sm\`: Small line height for headers
202
+ - \`leading-fm-md\`: Medium line height for cells
203
+ - \`leading-fm-xs\`: Extra small line height for captions
204
+
205
+ ### Colors
206
+ - \`text-fm-tertiary\`: Header text color
207
+ - \`text-fm-primary\`: Cell text color
208
+ - \`text-fm-label-tertiary\`: Caption text color
209
+ - \`bg-fm-surface-primary\`: Table background
210
+ - \`bg-fm-surface-frosted\`: Hover and selection states
211
+
212
+ ### Sizing
213
+ - \`--text-fm-sm\`: Header font size
214
+ - \`--text-fm-md\`: Cell font size
215
+ - \`--text-fm-xs\`: Caption font size
216
+
217
+ ## Best Practices
218
+
219
+ 1. **Always use TableHeader for headers** - Semantic structure
220
+ 2. **Include TableCaption for complex tables** - Accessibility
221
+ 3. **Use data-state="selected" for selection** - Consistent styling
222
+ 4. **Wrap interactive elements properly** - Button integration
223
+ 5. **Consider responsive behavior** - Horizontal scroll handling
224
+ 6. **Maintain consistent spacing** - Use default padding
225
+ 7. **Follow typography hierarchy** - Headers vs cells distinction
226
+ `,
227
+ },
228
+ },
229
+ },
230
+ tags: ["autodocs"],
231
+ argTypes: {
232
+ className: {
233
+ control: "text",
234
+ description: "Additional CSS classes for the table",
235
+ },
236
+ },
237
+ }
238
+
239
+ export default meta
240
+ type Story = StoryObj<typeof Table>
241
+
242
+ // Sample data for stories
243
+ const sampleUsers = [
244
+ {
245
+ id: 1,
246
+ name: "John Doe",
247
+ email: "john.doe@example.com",
248
+ role: "Admin",
249
+ status: "Active",
250
+ lastSeen: "2 minutes ago",
251
+ avatar: "JD",
252
+ },
253
+ {
254
+ id: 2,
255
+ name: "Jane Smith",
256
+ email: "jane.smith@example.com",
257
+ role: "Editor",
258
+ status: "Active",
259
+ lastSeen: "1 hour ago",
260
+ avatar: "JS",
261
+ },
262
+ {
263
+ id: 3,
264
+ name: "Bob Johnson",
265
+ email: "bob.johnson@example.com",
266
+ role: "Viewer",
267
+ status: "Inactive",
268
+ lastSeen: "3 days ago",
269
+ avatar: "BJ",
270
+ },
271
+ {
272
+ id: 4,
273
+ name: "Alice Brown",
274
+ email: "alice.brown@example.com",
275
+ role: "Editor",
276
+ status: "Active",
277
+ lastSeen: "30 minutes ago",
278
+ avatar: "AB",
279
+ },
280
+ {
281
+ id: 5,
282
+ name: "Charlie Wilson",
283
+ email: "charlie.wilson@example.com",
284
+ role: "Admin",
285
+ status: "Active",
286
+ lastSeen: "Just now",
287
+ avatar: "CW",
288
+ },
289
+ ]
290
+
291
+ const sampleProjects = [
292
+ {
293
+ id: 1,
294
+ name: "Website Redesign",
295
+ status: "In Progress",
296
+ priority: "High",
297
+ assignee: "John Doe",
298
+ dueDate: "Dec 15, 2024",
299
+ progress: 75,
300
+ },
301
+ {
302
+ id: 2,
303
+ name: "Mobile App",
304
+ status: "Planning",
305
+ priority: "Medium",
306
+ assignee: "Jane Smith",
307
+ dueDate: "Jan 20, 2025",
308
+ progress: 25,
309
+ },
310
+ {
311
+ id: 3,
312
+ name: "API Integration",
313
+ status: "Completed",
314
+ priority: "High",
315
+ assignee: "Bob Johnson",
316
+ dueDate: "Nov 30, 2024",
317
+ progress: 100,
318
+ },
319
+ {
320
+ id: 4,
321
+ name: "Documentation",
322
+ status: "In Progress",
323
+ priority: "Low",
324
+ assignee: "Alice Brown",
325
+ dueDate: "Dec 31, 2024",
326
+ progress: 50,
327
+ },
328
+ ]
329
+
330
+ // 1. Basic Table
331
+ export const Basic: Story = {
332
+ render: () => (
333
+ <div className="p-8">
334
+ <Table>
335
+ <TableHeader>
336
+ <TableRow>
337
+ <TableHead>Name</TableHead>
338
+ <TableHead>Email</TableHead>
339
+ <TableHead>Role</TableHead>
340
+ <TableHead>Status</TableHead>
341
+ </TableRow>
342
+ </TableHeader>
343
+ <TableBody>
344
+ {sampleUsers.slice(0, 3).map((user) => (
345
+ <TableRow key={user.id}>
346
+ <TableCell>{user.name}</TableCell>
347
+ <TableCell>{user.email}</TableCell>
348
+ <TableCell>{user.role}</TableCell>
349
+ <TableCell>
350
+ <Badge
351
+ color={user.status === "Active" ? "positive" : "neutral"}
352
+ >
353
+ {user.status}
354
+ </Badge>
355
+ </TableCell>
356
+ </TableRow>
357
+ ))}
358
+ </TableBody>
359
+ </Table>
360
+ </div>
361
+ ),
362
+ parameters: {
363
+ docs: {
364
+ description: {
365
+ story:
366
+ "Basic table structure with headers and data cells. Shows proper typography hierarchy and spacing.",
367
+ },
368
+ },
369
+ },
370
+ }
371
+
372
+ // 2. With Selection
373
+ export const WithSelection: Story = {
374
+ render: () => {
375
+ const [selectedRows, setSelectedRows] = React.useState<number[]>([2])
376
+ const [selectAll, setSelectAll] = React.useState(false)
377
+
378
+ const handleSelectAll = () => {
379
+ if (selectAll) {
380
+ setSelectedRows([])
381
+ } else {
382
+ setSelectedRows(sampleUsers.map((user) => user.id))
383
+ }
384
+ setSelectAll(!selectAll)
385
+ }
386
+
387
+ const handleSelectRow = (id: number) => {
388
+ setSelectedRows((prev) =>
389
+ prev.includes(id) ? prev.filter((rowId) => rowId !== id) : [...prev, id]
390
+ )
391
+ }
392
+
393
+ return (
394
+ <div className="p-8">
395
+ <Table>
396
+ <TableHeader>
397
+ <TableRow>
398
+ <TableHead>
399
+ <Checkbox checked={selectAll} onChange={handleSelectAll} />
400
+ </TableHead>
401
+ <TableHead>User</TableHead>
402
+ <TableHead>Email</TableHead>
403
+ <TableHead>Role</TableHead>
404
+ <TableHead>Status</TableHead>
405
+ <TableHead>Last Seen</TableHead>
406
+ </TableRow>
407
+ </TableHeader>
408
+ <TableBody>
409
+ {sampleUsers.map((user) => (
410
+ <TableRow
411
+ key={user.id}
412
+ data-state={
413
+ selectedRows.includes(user.id) ? "selected" : undefined
414
+ }
415
+ >
416
+ <TableCell>
417
+ <Checkbox
418
+ checked={selectedRows.includes(user.id)}
419
+ onChange={() => handleSelectRow(user.id)}
420
+ />
421
+ </TableCell>
422
+ <TableCell>
423
+ <div className="flex items-center gap-3">
424
+ <div className="bg-fm-surface-secondary text-fm-primary flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium">
425
+ {user.avatar}
426
+ </div>
427
+ <span>{user.name}</span>
428
+ </div>
429
+ </TableCell>
430
+ <TableCell className="text-fm-secondary">
431
+ {user.email}
432
+ </TableCell>
433
+ <TableCell>{user.role}</TableCell>
434
+ <TableCell>
435
+ <Badge
436
+ color={user.status === "Active" ? "positive" : "neutral"}
437
+ >
438
+ {user.status}
439
+ </Badge>
440
+ </TableCell>
441
+ <TableCell className="text-fm-tertiary">
442
+ {user.lastSeen}
443
+ </TableCell>
444
+ </TableRow>
445
+ ))}
446
+ </TableBody>
447
+ </Table>
448
+
449
+ <div className="text-fm-secondary mt-4 text-sm">
450
+ {selectedRows.length > 0 && (
451
+ <p>
452
+ {selectedRows.length} row{selectedRows.length !== 1 ? "s" : ""}{" "}
453
+ selected
454
+ </p>
455
+ )}
456
+ </div>
457
+ </div>
458
+ )
459
+ },
460
+ parameters: {
461
+ docs: {
462
+ description: {
463
+ story:
464
+ "Table with row selection functionality. Shows selected state styling and checkbox integration.",
465
+ },
466
+ },
467
+ },
468
+ }
469
+
470
+ // 3. With Actions
471
+ export const WithActions: Story = {
472
+ render: () => (
473
+ <div className="p-8">
474
+ <Table>
475
+ <TableHeader>
476
+ <TableRow>
477
+ <TableHead>Project</TableHead>
478
+ <TableHead>Status</TableHead>
479
+ <TableHead>Priority</TableHead>
480
+ <TableHead>Assignee</TableHead>
481
+ <TableHead>Due Date</TableHead>
482
+ <TableHead>Progress</TableHead>
483
+ <TableHead className="text-right">Actions</TableHead>
484
+ </TableRow>
485
+ </TableHeader>
486
+ <TableBody>
487
+ {sampleProjects.map((project) => (
488
+ <TableRow key={project.id}>
489
+ <TableCell className="font-medium">{project.name}</TableCell>
490
+ <TableCell>
491
+ <Badge
492
+ color={
493
+ project.status === "Completed"
494
+ ? "positive"
495
+ : project.status === "In Progress"
496
+ ? "warning"
497
+ : "neutral"
498
+ }
499
+ >
500
+ {project.status}
501
+ </Badge>
502
+ </TableCell>
503
+ <TableCell>
504
+ <Badge
505
+ color={
506
+ project.priority === "High"
507
+ ? "negative"
508
+ : project.priority === "Medium"
509
+ ? "warning"
510
+ : "neutral"
511
+ }
512
+ >
513
+ {project.priority}
514
+ </Badge>
515
+ </TableCell>
516
+ <TableCell>{project.assignee}</TableCell>
517
+ <TableCell className="text-fm-secondary">
518
+ {project.dueDate}
519
+ </TableCell>
520
+ <TableCell>
521
+ <div className="flex items-center gap-2">
522
+ <div className="bg-fm-surface-secondary h-2 w-20 rounded-full">
523
+ <div
524
+ className="bg-fm-primary-600 h-2 rounded-full"
525
+ style={{ width: `${project.progress}%` }}
526
+ />
527
+ </div>
528
+ <span className="text-fm-tertiary text-sm">
529
+ {project.progress}%
530
+ </span>
531
+ </div>
532
+ </TableCell>
533
+ <TableCell>
534
+ <div className="flex items-center justify-end gap-2">
535
+ <Button size="sm" variant="text">
536
+ <EyeOpenIcon className="h-4 w-4" />
537
+ </Button>
538
+ <Button size="sm" variant="text">
539
+ <EditBigIcon className="h-4 w-4" />
540
+ </Button>
541
+ <Button size="sm" variant="text">
542
+ <TrashIcon className="h-4 w-4" />
543
+ </Button>
544
+ <Button size="sm" variant="text">
545
+ <VerticalMenuIcon className="h-4 w-4" />
546
+ </Button>
547
+ </div>
548
+ </TableCell>
549
+ </TableRow>
550
+ ))}
551
+ </TableBody>
552
+ </Table>
553
+ </div>
554
+ ),
555
+ parameters: {
556
+ docs: {
557
+ description: {
558
+ story:
559
+ "Table with action buttons and rich content including progress bars, badges, and button groups.",
560
+ },
561
+ },
562
+ },
563
+ }
564
+
565
+ // 4. With Footer and Caption
566
+ export const WithFooterAndCaption: Story = {
567
+ render: () => {
568
+ const totalUsers = sampleUsers.length
569
+ const activeUsers = sampleUsers.filter(
570
+ (user) => user.status === "Active"
571
+ ).length
572
+ const inactiveUsers = totalUsers - activeUsers
573
+
574
+ return (
575
+ <div className="p-8">
576
+ <Table>
577
+ <TableCaption>User statistics and management overview</TableCaption>
578
+ <TableHeader>
579
+ <TableRow>
580
+ <TableHead>Metric</TableHead>
581
+ <TableHead className="text-right">Count</TableHead>
582
+ <TableHead className="text-right">Percentage</TableHead>
583
+ </TableRow>
584
+ </TableHeader>
585
+ <TableBody>
586
+ <TableRow>
587
+ <TableCell>Active Users</TableCell>
588
+ <TableCell className="text-right font-medium">
589
+ {activeUsers}
590
+ </TableCell>
591
+ <TableCell className="text-right">
592
+ {Math.round((activeUsers / totalUsers) * 100)}%
593
+ </TableCell>
594
+ </TableRow>
595
+ <TableRow>
596
+ <TableCell>Inactive Users</TableCell>
597
+ <TableCell className="text-right font-medium">
598
+ {inactiveUsers}
599
+ </TableCell>
600
+ <TableCell className="text-right">
601
+ {Math.round((inactiveUsers / totalUsers) * 100)}%
602
+ </TableCell>
603
+ </TableRow>
604
+ <TableRow>
605
+ <TableCell>Admins</TableCell>
606
+ <TableCell className="text-right font-medium">
607
+ {sampleUsers.filter((user) => user.role === "Admin").length}
608
+ </TableCell>
609
+ <TableCell className="text-right">
610
+ {Math.round(
611
+ (sampleUsers.filter((user) => user.role === "Admin").length /
612
+ totalUsers) *
613
+ 100
614
+ )}
615
+ %
616
+ </TableCell>
617
+ </TableRow>
618
+ <TableRow>
619
+ <TableCell>Editors</TableCell>
620
+ <TableCell className="text-right font-medium">
621
+ {sampleUsers.filter((user) => user.role === "Editor").length}
622
+ </TableCell>
623
+ <TableCell className="text-right">
624
+ {Math.round(
625
+ (sampleUsers.filter((user) => user.role === "Editor").length /
626
+ totalUsers) *
627
+ 100
628
+ )}
629
+ %
630
+ </TableCell>
631
+ </TableRow>
632
+ </TableBody>
633
+ <TableFooter>
634
+ <TableRow>
635
+ <TableCell className="font-bold">Total Users</TableCell>
636
+ <TableCell className="text-right font-bold">
637
+ {totalUsers}
638
+ </TableCell>
639
+ <TableCell className="text-right font-bold">100%</TableCell>
640
+ </TableRow>
641
+ </TableFooter>
642
+ </Table>
643
+ </div>
644
+ )
645
+ },
646
+ parameters: {
647
+ docs: {
648
+ description: {
649
+ story:
650
+ "Table with caption and footer sections. Shows proper semantic structure for complex data tables.",
651
+ },
652
+ },
653
+ },
654
+ }
655
+
656
+ // 5. Sortable Table
657
+ export const SortableTable: Story = {
658
+ render: () => {
659
+ const [sortField, setSortField] = React.useState<string | null>(null)
660
+ const [sortDirection, setSortDirection] = React.useState<"asc" | "desc">(
661
+ "asc"
662
+ )
663
+
664
+ const sortedUsers = React.useMemo(() => {
665
+ if (!sortField) return sampleUsers
666
+
667
+ return [...sampleUsers].sort((a, b) => {
668
+ const aValue = a[sortField as keyof typeof a]
669
+ const bValue = b[sortField as keyof typeof b]
670
+
671
+ if (aValue < bValue) return sortDirection === "asc" ? -1 : 1
672
+ if (aValue > bValue) return sortDirection === "asc" ? 1 : -1
673
+ return 0
674
+ })
675
+ }, [sortField, sortDirection])
676
+
677
+ const handleSort = (field: string) => {
678
+ if (sortField === field) {
679
+ setSortDirection(sortDirection === "asc" ? "desc" : "asc")
680
+ } else {
681
+ setSortField(field)
682
+ setSortDirection("asc")
683
+ }
684
+ }
685
+
686
+ const SortableHeader = ({
687
+ field,
688
+ children,
689
+ }: {
690
+ field: string
691
+ children: React.ReactNode
692
+ }) => (
693
+ <TableHead>
694
+ <button
695
+ className="hover:text-fm-primary flex items-center gap-2 transition-colors"
696
+ onClick={() => handleSort(field)}
697
+ >
698
+ {children}
699
+ {sortField === field &&
700
+ (sortDirection === "asc" ? (
701
+ <ChevronUpIcon className="h-4 w-4" />
702
+ ) : (
703
+ <ChevronDownIcon className="h-4 w-4" />
704
+ ))}
705
+ </button>
706
+ </TableHead>
707
+ )
708
+
709
+ return (
710
+ <div className="p-8">
711
+ <Table>
712
+ <TableHeader>
713
+ <TableRow>
714
+ <SortableHeader field="name">Name</SortableHeader>
715
+ <SortableHeader field="email">Email</SortableHeader>
716
+ <SortableHeader field="role">Role</SortableHeader>
717
+ <SortableHeader field="status">Status</SortableHeader>
718
+ <TableHead>Last Seen</TableHead>
719
+ </TableRow>
720
+ </TableHeader>
721
+ <TableBody>
722
+ {sortedUsers.map((user) => (
723
+ <TableRow key={user.id}>
724
+ <TableCell>
725
+ <div className="flex items-center gap-3">
726
+ <div className="bg-fm-surface-secondary text-fm-primary flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium">
727
+ {user.avatar}
728
+ </div>
729
+ <span className="font-medium">{user.name}</span>
730
+ </div>
731
+ </TableCell>
732
+ <TableCell className="text-fm-secondary">
733
+ {user.email}
734
+ </TableCell>
735
+ <TableCell>{user.role}</TableCell>
736
+ <TableCell>
737
+ <Badge
738
+ color={user.status === "Active" ? "positive" : "neutral"}
739
+ >
740
+ {user.status}
741
+ </Badge>
742
+ </TableCell>
743
+ <TableCell className="text-fm-tertiary">
744
+ {user.lastSeen}
745
+ </TableCell>
746
+ </TableRow>
747
+ ))}
748
+ </TableBody>
749
+ </Table>
750
+
751
+ <div className="text-fm-secondary mt-4 text-sm">
752
+ {sortField && (
753
+ <p>
754
+ Sorted by {sortField} (
755
+ {sortDirection === "asc" ? "ascending" : "descending"})
756
+ </p>
757
+ )}
758
+ </div>
759
+ </div>
760
+ )
761
+ },
762
+ parameters: {
763
+ docs: {
764
+ description: {
765
+ story:
766
+ "Interactive sortable table with clickable column headers and sort indicators.",
767
+ },
768
+ },
769
+ },
770
+ }
771
+
772
+ // 6. Responsive Table
773
+ export const ResponsiveTable: Story = {
774
+ render: () => (
775
+ <div className="p-8">
776
+ <div className="mb-4">
777
+ <h3 className="mb-2 text-lg font-medium text-white">
778
+ Responsive Table
779
+ </h3>
780
+ <p className="text-fm-secondary text-sm">
781
+ Resize your browser or view on mobile to see horizontal scrolling
782
+ behavior
783
+ </p>
784
+ </div>
785
+
786
+ <Table>
787
+ <TableHeader>
788
+ <TableRow>
789
+ <TableHead>ID</TableHead>
790
+ <TableHead>Full Name</TableHead>
791
+ <TableHead>Email Address</TableHead>
792
+ <TableHead>Role</TableHead>
793
+ <TableHead>Department</TableHead>
794
+ <TableHead>Status</TableHead>
795
+ <TableHead>Created Date</TableHead>
796
+ <TableHead>Last Activity</TableHead>
797
+ <TableHead>Actions</TableHead>
798
+ </TableRow>
799
+ </TableHeader>
800
+ <TableBody>
801
+ {sampleUsers.map((user) => (
802
+ <TableRow key={user.id}>
803
+ <TableCell className="font-mono">
804
+ #{user.id.toString().padStart(3, "0")}
805
+ </TableCell>
806
+ <TableCell className="font-medium">{user.name}</TableCell>
807
+ <TableCell className="text-fm-secondary">{user.email}</TableCell>
808
+ <TableCell>{user.role}</TableCell>
809
+ <TableCell>Engineering</TableCell>
810
+ <TableCell>
811
+ <Badge
812
+ color={user.status === "Active" ? "positive" : "neutral"}
813
+ >
814
+ {user.status}
815
+ </Badge>
816
+ </TableCell>
817
+ <TableCell>Nov 15, 2024</TableCell>
818
+ <TableCell className="text-fm-tertiary">
819
+ {user.lastSeen}
820
+ </TableCell>
821
+ <TableCell>
822
+ <div className="flex gap-1">
823
+ <Button size="sm" variant="text">
824
+ <EditBigIcon className="h-4 w-4" />
825
+ </Button>
826
+ <Button size="sm" variant="text">
827
+ <TrashIcon className="h-4 w-4" />
828
+ </Button>
829
+ </div>
830
+ </TableCell>
831
+ </TableRow>
832
+ ))}
833
+ </TableBody>
834
+ </Table>
835
+ </div>
836
+ ),
837
+ parameters: {
838
+ docs: {
839
+ description: {
840
+ story:
841
+ "Table with many columns demonstrating responsive horizontal scrolling behavior.",
842
+ },
843
+ },
844
+ },
845
+ }
846
+
847
+ // 7. Empty State
848
+ export const EmptyState: Story = {
849
+ render: () => (
850
+ <div className="p-8">
851
+ <Table>
852
+ <TableHeader>
853
+ <TableRow>
854
+ <TableHead>Name</TableHead>
855
+ <TableHead>Email</TableHead>
856
+ <TableHead>Role</TableHead>
857
+ <TableHead>Status</TableHead>
858
+ </TableRow>
859
+ </TableHeader>
860
+ <TableBody>
861
+ <TableRow>
862
+ <TableCell colSpan={4}>
863
+ <div className="flex flex-col items-center justify-center py-12 text-center">
864
+ <div className="bg-fm-surface-secondary mb-4 rounded-full p-3">
865
+ <EyeOpenIcon className="text-fm-tertiary h-6 w-6" />
866
+ </div>
867
+ <h3 className="text-fm-primary mb-2 text-lg font-medium">
868
+ No users found
869
+ </h3>
870
+ <p className="text-fm-secondary mb-4">
871
+ Get started by adding your first user to the system.
872
+ </p>
873
+ <Button>Add User</Button>
874
+ </div>
875
+ </TableCell>
876
+ </TableRow>
877
+ </TableBody>
878
+ </Table>
879
+ </div>
880
+ ),
881
+ parameters: {
882
+ docs: {
883
+ description: {
884
+ story:
885
+ "Table with empty state design using colspan for centered content.",
886
+ },
887
+ },
888
+ },
889
+ }
890
+
891
+ // 8. Dense Table
892
+ export const DenseTable: Story = {
893
+ render: () => (
894
+ <div className="p-8">
895
+ <Table>
896
+ <TableHeader>
897
+ <TableRow>
898
+ <TableHead className="py-2">Name</TableHead>
899
+ <TableHead className="py-2">Email</TableHead>
900
+ <TableHead className="py-2">Role</TableHead>
901
+ <TableHead className="py-2">Status</TableHead>
902
+ </TableRow>
903
+ </TableHeader>
904
+ <TableBody>
905
+ {sampleUsers.map((user) => (
906
+ <TableRow key={user.id}>
907
+ <TableCell className="py-2">{user.name}</TableCell>
908
+ <TableCell className="text-fm-secondary py-2">
909
+ {user.email}
910
+ </TableCell>
911
+ <TableCell className="py-2">{user.role}</TableCell>
912
+ <TableCell className="py-2">
913
+ <Badge
914
+ color={user.status === "Active" ? "positive" : "neutral"}
915
+ >
916
+ {user.status}
917
+ </Badge>
918
+ </TableCell>
919
+ </TableRow>
920
+ ))}
921
+ </TableBody>
922
+ </Table>
923
+ </div>
924
+ ),
925
+ parameters: {
926
+ docs: {
927
+ description: {
928
+ story: "Compact table with reduced padding for dense data display.",
929
+ },
930
+ },
931
+ },
932
+ }
933
+
934
+ // 9. Complete Showcase
935
+ export const CompleteShowcase: Story = {
936
+ render: () => {
937
+ const [selectedRows] = React.useState<number[]>([])
938
+ const [currentPage, setCurrentPage] = React.useState(1)
939
+ const itemsPerPage = 3
940
+
941
+ const paginatedData = sampleUsers.slice(
942
+ (currentPage - 1) * itemsPerPage,
943
+ currentPage * itemsPerPage
944
+ )
945
+
946
+ const totalPages = Math.ceil(sampleUsers.length / itemsPerPage)
947
+
948
+ return (
949
+ <div className="space-y-6 p-8">
950
+ <div className="flex items-center justify-between">
951
+ <div>
952
+ <h2 className="text-xl font-bold text-white">User Management</h2>
953
+ <p className="text-fm-secondary">
954
+ Manage your team members and their permissions
955
+ </p>
956
+ </div>
957
+ <Button>Add User</Button>
958
+ </div>
959
+
960
+ <Table>
961
+ <TableCaption>
962
+ A list of all users in your organization with their current status
963
+ and roles
964
+ </TableCaption>
965
+ <TableHeader>
966
+ <TableRow>
967
+ <TableHead>
968
+ <Checkbox />
969
+ </TableHead>
970
+ <TableHead>User</TableHead>
971
+ <TableHead>Role</TableHead>
972
+ <TableHead>Status</TableHead>
973
+ <TableHead>Last Activity</TableHead>
974
+ <TableHead className="text-right">Actions</TableHead>
975
+ </TableRow>
976
+ </TableHeader>
977
+ <TableBody>
978
+ {paginatedData.map((user) => (
979
+ <TableRow
980
+ key={user.id}
981
+ data-state={
982
+ selectedRows.includes(user.id) ? "selected" : undefined
983
+ }
984
+ >
985
+ <TableCell>
986
+ <Checkbox />
987
+ </TableCell>
988
+ <TableCell>
989
+ <div className="flex items-center gap-3">
990
+ <div className="bg-fm-surface-secondary text-fm-primary flex h-10 w-10 items-center justify-center rounded-full text-sm font-medium">
991
+ {user.avatar}
992
+ </div>
993
+ <div>
994
+ <div className="text-fm-primary font-medium">
995
+ {user.name}
996
+ </div>
997
+ <div className="text-fm-secondary text-sm">
998
+ {user.email}
999
+ </div>
1000
+ </div>
1001
+ </div>
1002
+ </TableCell>
1003
+ <TableCell>
1004
+ <Badge color="info">{user.role}</Badge>
1005
+ </TableCell>
1006
+ <TableCell>
1007
+ <div className="flex items-center gap-2">
1008
+ <div
1009
+ className={`h-2 w-2 rounded-full ${
1010
+ user.status === "Active"
1011
+ ? "bg-green-500"
1012
+ : "bg-gray-400"
1013
+ }`}
1014
+ />
1015
+ <span
1016
+ className={
1017
+ user.status === "Active"
1018
+ ? "text-green-400"
1019
+ : "text-fm-tertiary"
1020
+ }
1021
+ >
1022
+ {user.status}
1023
+ </span>
1024
+ </div>
1025
+ </TableCell>
1026
+ <TableCell className="text-fm-tertiary">
1027
+ {user.lastSeen}
1028
+ </TableCell>
1029
+ <TableCell>
1030
+ <div className="flex items-center justify-end gap-2">
1031
+ <Button size="sm" variant="text">
1032
+ <EyeOpenIcon className="h-4 w-4" />
1033
+ </Button>
1034
+ <Button size="sm" variant="text">
1035
+ <EditBigIcon className="h-4 w-4" />
1036
+ </Button>
1037
+ <Button
1038
+ size="sm"
1039
+ variant="text"
1040
+ className="text-red-400 hover:text-red-300"
1041
+ >
1042
+ <TrashIcon className="h-4 w-4" />
1043
+ </Button>
1044
+ </div>
1045
+ </TableCell>
1046
+ </TableRow>
1047
+ ))}
1048
+ </TableBody>
1049
+ <TableFooter>
1050
+ <TableRow>
1051
+ <TableCell colSpan={6}>
1052
+ <div className="flex items-center justify-between">
1053
+ <div className="text-fm-secondary text-sm">
1054
+ Showing {(currentPage - 1) * itemsPerPage + 1} to{" "}
1055
+ {Math.min(currentPage * itemsPerPage, sampleUsers.length)}{" "}
1056
+ of {sampleUsers.length} users
1057
+ </div>
1058
+ <div className="flex gap-2">
1059
+ <Button
1060
+ size="sm"
1061
+ variant="outline"
1062
+ disabled={currentPage === 1}
1063
+ onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
1064
+ >
1065
+ Previous
1066
+ </Button>
1067
+ <Button
1068
+ size="sm"
1069
+ variant="outline"
1070
+ disabled={currentPage === totalPages}
1071
+ onClick={() =>
1072
+ setCurrentPage((p) => Math.min(totalPages, p + 1))
1073
+ }
1074
+ >
1075
+ Next
1076
+ </Button>
1077
+ </div>
1078
+ </div>
1079
+ </TableCell>
1080
+ </TableRow>
1081
+ </TableFooter>
1082
+ </Table>
1083
+ </div>
1084
+ )
1085
+ },
1086
+ parameters: {
1087
+ layout: "fullscreen",
1088
+ docs: {
1089
+ description: {
1090
+ story:
1091
+ "Complete table implementation with all features: selection, actions, pagination, and proper semantic structure.",
1092
+ },
1093
+ },
1094
+ },
1095
+ }