@ds-mo/ui 0.2.4 → 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 (356) hide show
  1. package/dist/components/ds-accordion.d.ts +11 -0
  2. package/dist/components/ds-accordion.js +2 -0
  3. package/dist/components/ds-accordion.js.map +1 -0
  4. package/dist/components/ds-badge.d.ts +11 -0
  5. package/dist/components/ds-badge.js +2 -0
  6. package/dist/components/ds-badge.js.map +1 -0
  7. package/dist/components/ds-banner.d.ts +11 -0
  8. package/dist/components/ds-banner.js +2 -0
  9. package/dist/components/ds-banner.js.map +1 -0
  10. package/dist/components/ds-breadcrumb.d.ts +11 -0
  11. package/dist/components/ds-breadcrumb.js +2 -0
  12. package/dist/components/ds-breadcrumb.js.map +1 -0
  13. package/dist/components/ds-button.d.ts +11 -0
  14. package/dist/components/ds-button.js +2 -0
  15. package/dist/components/ds-button.js.map +1 -0
  16. package/dist/components/ds-card.d.ts +11 -0
  17. package/dist/components/ds-card.js +2 -0
  18. package/dist/components/ds-card.js.map +1 -0
  19. package/dist/components/ds-checkbox.d.ts +11 -0
  20. package/dist/components/ds-checkbox.js +2 -0
  21. package/dist/components/ds-checkbox.js.map +1 -0
  22. package/dist/components/ds-divider.d.ts +11 -0
  23. package/dist/components/ds-divider.js +2 -0
  24. package/dist/components/ds-divider.js.map +1 -0
  25. package/dist/components/ds-empty-state.d.ts +11 -0
  26. package/dist/components/ds-empty-state.js +2 -0
  27. package/dist/components/ds-empty-state.js.map +1 -0
  28. package/dist/components/ds-fade.d.ts +11 -0
  29. package/dist/components/ds-fade.js +2 -0
  30. package/dist/components/ds-fade.js.map +1 -0
  31. package/dist/components/ds-field.d.ts +11 -0
  32. package/dist/components/ds-field.js +2 -0
  33. package/dist/components/ds-field.js.map +1 -0
  34. package/dist/components/ds-header.d.ts +11 -0
  35. package/dist/components/ds-header.js +2 -0
  36. package/dist/components/ds-header.js.map +1 -0
  37. package/dist/components/ds-input.d.ts +11 -0
  38. package/dist/components/ds-input.js +2 -0
  39. package/dist/components/ds-input.js.map +1 -0
  40. package/dist/components/ds-loader.d.ts +11 -0
  41. package/dist/components/ds-loader.js +2 -0
  42. package/dist/components/ds-loader.js.map +1 -0
  43. package/dist/components/ds-menu.d.ts +11 -0
  44. package/dist/components/ds-menu.js +2 -0
  45. package/dist/components/ds-menu.js.map +1 -0
  46. package/dist/components/ds-modal.d.ts +11 -0
  47. package/dist/components/ds-modal.js +2 -0
  48. package/dist/components/ds-modal.js.map +1 -0
  49. package/dist/components/ds-pagination.d.ts +11 -0
  50. package/dist/components/ds-pagination.js +2 -0
  51. package/dist/components/ds-pagination.js.map +1 -0
  52. package/dist/components/ds-radio-group.d.ts +11 -0
  53. package/dist/components/ds-radio-group.js +2 -0
  54. package/dist/components/ds-radio-group.js.map +1 -0
  55. package/dist/components/ds-scrollbar.d.ts +11 -0
  56. package/dist/components/ds-scrollbar.js +2 -0
  57. package/dist/components/ds-scrollbar.js.map +1 -0
  58. package/dist/components/ds-sidebar.d.ts +11 -0
  59. package/dist/components/ds-sidebar.js +2 -0
  60. package/dist/components/ds-sidebar.js.map +1 -0
  61. package/dist/components/ds-skeleton.d.ts +11 -0
  62. package/dist/components/ds-skeleton.js +2 -0
  63. package/dist/components/ds-skeleton.js.map +1 -0
  64. package/dist/components/ds-slider.d.ts +11 -0
  65. package/dist/components/ds-slider.js +2 -0
  66. package/dist/components/ds-slider.js.map +1 -0
  67. package/dist/components/ds-surface.d.ts +11 -0
  68. package/dist/components/ds-surface.js +2 -0
  69. package/dist/components/ds-surface.js.map +1 -0
  70. package/dist/components/ds-tab-group.d.ts +11 -0
  71. package/dist/components/ds-tab-group.js +2 -0
  72. package/dist/components/ds-tab-group.js.map +1 -0
  73. package/dist/components/ds-table.d.ts +11 -0
  74. package/dist/components/ds-table.js +2 -0
  75. package/dist/components/ds-table.js.map +1 -0
  76. package/dist/components/ds-tag.d.ts +11 -0
  77. package/dist/components/ds-tag.js +2 -0
  78. package/dist/components/ds-tag.js.map +1 -0
  79. package/dist/components/ds-text.d.ts +11 -0
  80. package/dist/components/ds-text.js +2 -0
  81. package/dist/components/ds-text.js.map +1 -0
  82. package/dist/components/ds-toast-provider.d.ts +11 -0
  83. package/dist/components/ds-toast-provider.js +2 -0
  84. package/dist/components/ds-toast-provider.js.map +1 -0
  85. package/dist/components/ds-toggle.d.ts +11 -0
  86. package/dist/components/ds-toggle.js +2 -0
  87. package/dist/components/ds-toggle.js.map +1 -0
  88. package/dist/components/ds-tooltip.d.ts +11 -0
  89. package/dist/components/ds-tooltip.js +2 -0
  90. package/dist/components/ds-tooltip.js.map +1 -0
  91. package/dist/components/index.d.ts +33 -0
  92. package/dist/components/index.js +2 -0
  93. package/dist/components/index.js.map +1 -0
  94. package/dist/components/p-BcuUR5Ao.js +2 -0
  95. package/dist/components/p-BcuUR5Ao.js.map +1 -0
  96. package/dist/types/.stencil/Accordion/Accordion.d.ts +28 -0
  97. package/dist/types/.stencil/Badge/Badge.d.ts +8 -0
  98. package/dist/types/.stencil/Badge/index.d.ts +2 -0
  99. package/dist/types/.stencil/Banner/Banner.d.ts +29 -0
  100. package/dist/types/.stencil/Breadcrumb/Breadcrumb.d.ts +16 -0
  101. package/dist/types/.stencil/Button/Button.d.ts +38 -0
  102. package/dist/types/.stencil/Button/index.d.ts +2 -0
  103. package/dist/types/.stencil/Card/Card.d.ts +8 -0
  104. package/dist/types/.stencil/Checkbox/Checkbox.d.ts +13 -0
  105. package/dist/types/.stencil/Checkbox/index.d.ts +2 -0
  106. package/dist/types/.stencil/Divider/Divider.d.ts +7 -0
  107. package/dist/types/.stencil/Divider/index.d.ts +2 -0
  108. package/dist/types/.stencil/EmptyState/EmptyState.d.ts +7 -0
  109. package/dist/types/.stencil/Fade/Fade.d.ts +10 -0
  110. package/dist/types/.stencil/Fade/index.d.ts +2 -0
  111. package/dist/types/.stencil/Field/Field.d.ts +8 -0
  112. package/dist/types/.stencil/Header/Header.d.ts +7 -0
  113. package/dist/types/.stencil/Input/Input.d.ts +26 -0
  114. package/dist/types/.stencil/Input/index.d.ts +2 -0
  115. package/dist/types/.stencil/Loader/Loader.d.ts +12 -0
  116. package/dist/types/.stencil/Loader/index.d.ts +2 -0
  117. package/dist/types/.stencil/Menu/Menu.d.ts +60 -0
  118. package/dist/types/.stencil/Modal/Modal.d.ts +31 -0
  119. package/dist/types/.stencil/Pagination/Pagination.d.ts +11 -0
  120. package/dist/types/.stencil/RadioGroup/RadioGroup.d.ts +21 -0
  121. package/dist/types/.stencil/RadioGroup/index.d.ts +2 -0
  122. package/dist/types/.stencil/Scrollbar/Scrollbar.d.ts +27 -0
  123. package/dist/types/.stencil/Sidebar/Sidebar.d.ts +29 -0
  124. package/dist/types/.stencil/Skeleton/Skeleton.d.ts +16 -0
  125. package/dist/types/.stencil/Skeleton/index.d.ts +2 -0
  126. package/dist/types/.stencil/Slider/Slider.d.ts +18 -0
  127. package/dist/types/.stencil/Slider/index.d.ts +2 -0
  128. package/dist/types/.stencil/Surface/Surface.d.ts +22 -0
  129. package/dist/types/.stencil/TabGroup/TabGroup.d.ts +29 -0
  130. package/dist/types/.stencil/Table/Table.d.ts +50 -0
  131. package/dist/types/.stencil/Tag/Tag.d.ts +32 -0
  132. package/dist/types/.stencil/Tag/index.d.ts +2 -0
  133. package/dist/types/.stencil/Text/Text.d.ts +22 -0
  134. package/dist/types/.stencil/Text/index.d.ts +2 -0
  135. package/dist/types/.stencil/Toast/Toast.d.ts +15 -0
  136. package/dist/types/.stencil/Toast/toast-service.d.ts +24 -0
  137. package/dist/types/.stencil/Toggle/Toggle.d.ts +10 -0
  138. package/dist/types/.stencil/Toggle/index.d.ts +2 -0
  139. package/dist/types/.stencil/Tooltip/Tooltip.d.ts +36 -0
  140. package/dist/types/components.d.ts +2024 -0
  141. package/dist/types/stencil-public-runtime.d.ts +1860 -0
  142. package/package.json +33 -29
  143. package/src/angular/angular-component-lib/utils.ts +65 -0
  144. package/src/angular/index.ts +35 -0
  145. package/src/angular/proxies.ts +819 -0
  146. package/dist/index.css +0 -2
  147. package/dist/index.d.ts +0 -969
  148. package/dist/index.js +0 -2492
  149. package/dist/index.js.map +0 -1
  150. package/dist/r/accordion.json +0 -79
  151. package/dist/r/badge.json +0 -69
  152. package/dist/r/banner.json +0 -90
  153. package/dist/r/breadcrumb.json +0 -70
  154. package/dist/r/button-group.json +0 -65
  155. package/dist/r/button.json +0 -137
  156. package/dist/r/card.json +0 -82
  157. package/dist/r/checkbox.json +0 -91
  158. package/dist/r/divider.json +0 -57
  159. package/dist/r/empty-state.json +0 -69
  160. package/dist/r/error-boundary.json +0 -66
  161. package/dist/r/fade.json +0 -65
  162. package/dist/r/field.json +0 -71
  163. package/dist/r/header.json +0 -67
  164. package/dist/r/input.json +0 -77
  165. package/dist/r/loader.json +0 -54
  166. package/dist/r/menu.json +0 -130
  167. package/dist/r/modal.json +0 -93
  168. package/dist/r/pagination.json +0 -80
  169. package/dist/r/radio.json +0 -85
  170. package/dist/r/registry.json +0 -1600
  171. package/dist/r/scrollbar.json +0 -68
  172. package/dist/r/select.json +0 -93
  173. package/dist/r/sidebar.json +0 -105
  174. package/dist/r/skeleton.json +0 -72
  175. package/dist/r/slider.json +0 -87
  176. package/dist/r/surface.json +0 -97
  177. package/dist/r/tab-group.json +0 -72
  178. package/dist/r/tab.json +0 -71
  179. package/dist/r/table.json +0 -110
  180. package/dist/r/tag.json +0 -110
  181. package/dist/r/text.json +0 -94
  182. package/dist/r/toast.json +0 -77
  183. package/dist/r/toggle-button-group.json +0 -65
  184. package/dist/r/toggle-button.json +0 -94
  185. package/dist/r/toggle.json +0 -65
  186. package/dist/r/tooltip.json +0 -86
  187. package/src/components/Accordion/Accordion.module.css +0 -66
  188. package/src/components/Accordion/Accordion.stories.tsx +0 -95
  189. package/src/components/Accordion/Accordion.tsx +0 -122
  190. package/src/components/Accordion/index.ts +0 -2
  191. package/src/components/Badge/Badge.module.css +0 -6
  192. package/src/components/Badge/Badge.stories.tsx +0 -99
  193. package/src/components/Badge/Badge.tsx +0 -23
  194. package/src/components/Badge/index.ts +0 -2
  195. package/src/components/Banner/Banner.module.css +0 -67
  196. package/src/components/Banner/Banner.stories.tsx +0 -81
  197. package/src/components/Banner/Banner.tsx +0 -109
  198. package/src/components/Banner/index.ts +0 -2
  199. package/src/components/Breadcrumb/Breadcrumb.module.css +0 -46
  200. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -72
  201. package/src/components/Breadcrumb/Breadcrumb.tsx +0 -68
  202. package/src/components/Breadcrumb/index.ts +0 -2
  203. package/src/components/Button/Button.mdx +0 -143
  204. package/src/components/Button/Button.module.css +0 -343
  205. package/src/components/Button/Button.stories.tsx +0 -575
  206. package/src/components/Button/Button.tsx +0 -201
  207. package/src/components/Button/index.ts +0 -10
  208. package/src/components/ButtonGroup/ButtonGroup.module.css +0 -157
  209. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -384
  210. package/src/components/ButtonGroup/ButtonGroup.tsx +0 -122
  211. package/src/components/ButtonGroup/index.ts +0 -2
  212. package/src/components/Card/Card.module.css +0 -36
  213. package/src/components/Card/Card.stories.tsx +0 -78
  214. package/src/components/Card/Card.tsx +0 -53
  215. package/src/components/Card/index.ts +0 -2
  216. package/src/components/Checkbox/Checkbox.module.css +0 -47
  217. package/src/components/Checkbox/Checkbox.stories.tsx +0 -129
  218. package/src/components/Checkbox/Checkbox.tsx +0 -68
  219. package/src/components/Checkbox/index.ts +0 -2
  220. package/src/components/Divider/Divider.module.css +0 -19
  221. package/src/components/Divider/Divider.stories.tsx +0 -55
  222. package/src/components/Divider/Divider.tsx +0 -28
  223. package/src/components/Divider/index.ts +0 -2
  224. package/src/components/EmptyState/EmptyState.module.css +0 -8
  225. package/src/components/EmptyState/EmptyState.stories.tsx +0 -53
  226. package/src/components/EmptyState/EmptyState.tsx +0 -31
  227. package/src/components/EmptyState/index.ts +0 -2
  228. package/src/components/ErrorBoundary/ErrorBoundary.module.css +0 -18
  229. package/src/components/ErrorBoundary/ErrorBoundary.stories.tsx +0 -38
  230. package/src/components/ErrorBoundary/ErrorBoundary.tsx +0 -50
  231. package/src/components/ErrorBoundary/index.ts +0 -2
  232. package/src/components/Fade/Fade.module.css +0 -31
  233. package/src/components/Fade/Fade.stories.tsx +0 -35
  234. package/src/components/Fade/Fade.tsx +0 -33
  235. package/src/components/Fade/index.ts +0 -2
  236. package/src/components/Field/Field.module.css +0 -5
  237. package/src/components/Field/Field.stories.tsx +0 -111
  238. package/src/components/Field/Field.tsx +0 -22
  239. package/src/components/Field/index.ts +0 -2
  240. package/src/components/Header/Header.module.css +0 -33
  241. package/src/components/Header/Header.stories.tsx +0 -52
  242. package/src/components/Header/Header.tsx +0 -42
  243. package/src/components/Header/index.ts +0 -2
  244. package/src/components/Input/Input.module.css +0 -71
  245. package/src/components/Input/Input.stories.tsx +0 -135
  246. package/src/components/Input/Input.tsx +0 -76
  247. package/src/components/Input/index.ts +0 -2
  248. package/src/components/LabelWrap/LabelWrap.module.css +0 -34
  249. package/src/components/LabelWrap/LabelWrap.tsx +0 -32
  250. package/src/components/LabelWrap/index.ts +0 -1
  251. package/src/components/Loader/Loader.module.css +0 -9
  252. package/src/components/Loader/Loader.stories.tsx +0 -44
  253. package/src/components/Loader/Loader.tsx +0 -43
  254. package/src/components/Loader/index.ts +0 -2
  255. package/src/components/Menu/DestructiveMenuItem.module.css +0 -57
  256. package/src/components/Menu/DestructiveMenuItem.tsx +0 -64
  257. package/src/components/Menu/Menu.module.css +0 -49
  258. package/src/components/Menu/Menu.stories.tsx +0 -129
  259. package/src/components/Menu/Menu.tsx +0 -269
  260. package/src/components/Menu/MenuItem.module.css +0 -84
  261. package/src/components/Menu/MenuItem.tsx +0 -101
  262. package/src/components/Menu/index.ts +0 -6
  263. package/src/components/Modal/Modal.module.css +0 -67
  264. package/src/components/Modal/Modal.stories.tsx +0 -71
  265. package/src/components/Modal/Modal.tsx +0 -122
  266. package/src/components/Modal/index.ts +0 -2
  267. package/src/components/Pagination/Pagination.module.css +0 -64
  268. package/src/components/Pagination/Pagination.stories.tsx +0 -51
  269. package/src/components/Pagination/Pagination.tsx +0 -103
  270. package/src/components/Pagination/index.ts +0 -2
  271. package/src/components/Radio/Radio.module.css +0 -61
  272. package/src/components/Radio/Radio.stories.tsx +0 -101
  273. package/src/components/Radio/Radio.tsx +0 -108
  274. package/src/components/Radio/index.ts +0 -2
  275. package/src/components/Scrollbar/Scrollbar.module.css +0 -81
  276. package/src/components/Scrollbar/Scrollbar.stories.tsx +0 -46
  277. package/src/components/Scrollbar/Scrollbar.tsx +0 -187
  278. package/src/components/Scrollbar/index.ts +0 -2
  279. package/src/components/Select/Select.module.css +0 -31
  280. package/src/components/Select/Select.stories.tsx +0 -59
  281. package/src/components/Select/Select.tsx +0 -92
  282. package/src/components/Select/index.ts +0 -2
  283. package/src/components/Sidebar/Sidebar.module.css +0 -161
  284. package/src/components/Sidebar/Sidebar.stories.tsx +0 -125
  285. package/src/components/Sidebar/Sidebar.tsx +0 -129
  286. package/src/components/Sidebar/SidebarItem.tsx +0 -57
  287. package/src/components/Sidebar/SidebarSection.tsx +0 -42
  288. package/src/components/Sidebar/index.ts +0 -6
  289. package/src/components/Skeleton/Skeleton.module.css +0 -53
  290. package/src/components/Skeleton/Skeleton.stories.tsx +0 -89
  291. package/src/components/Skeleton/Skeleton.tsx +0 -66
  292. package/src/components/Skeleton/index.ts +0 -2
  293. package/src/components/Slider/Slider.module.css +0 -62
  294. package/src/components/Slider/Slider.stories.tsx +0 -120
  295. package/src/components/Slider/Slider.tsx +0 -74
  296. package/src/components/Slider/index.ts +0 -2
  297. package/src/components/Surface/Surface.module.css +0 -222
  298. package/src/components/Surface/Surface.stories.tsx +0 -213
  299. package/src/components/Surface/Surface.tsx +0 -219
  300. package/src/components/Surface/index.ts +0 -12
  301. package/src/components/Tab/Tab.module.css +0 -66
  302. package/src/components/Tab/Tab.stories.tsx +0 -103
  303. package/src/components/Tab/Tab.tsx +0 -41
  304. package/src/components/Tab/index.ts +0 -2
  305. package/src/components/TabGroup/TabGroup.module.css +0 -26
  306. package/src/components/TabGroup/TabGroup.stories.tsx +0 -60
  307. package/src/components/TabGroup/TabGroup.tsx +0 -83
  308. package/src/components/TabGroup/index.ts +0 -2
  309. package/src/components/Table/Table.module.css +0 -130
  310. package/src/components/Table/Table.stories.tsx +0 -111
  311. package/src/components/Table/Table.tsx +0 -226
  312. package/src/components/Table/index.ts +0 -11
  313. package/src/components/Tag/Tag.module.css +0 -270
  314. package/src/components/Tag/Tag.stories.tsx +0 -399
  315. package/src/components/Tag/Tag.tsx +0 -162
  316. package/src/components/Tag/index.ts +0 -2
  317. package/src/components/Text/Text.module.css +0 -166
  318. package/src/components/Text/Text.stories.tsx +0 -212
  319. package/src/components/Text/Text.tsx +0 -181
  320. package/src/components/Text/index.ts +0 -13
  321. package/src/components/Toast/Toast.module.css +0 -91
  322. package/src/components/Toast/Toast.stories.tsx +0 -66
  323. package/src/components/Toast/Toast.tsx +0 -182
  324. package/src/components/Toast/index.ts +0 -8
  325. package/src/components/Toggle/Toggle.module.css +0 -87
  326. package/src/components/Toggle/Toggle.stories.tsx +0 -85
  327. package/src/components/Toggle/Toggle.tsx +0 -52
  328. package/src/components/Toggle/index.ts +0 -2
  329. package/src/components/ToggleButton/ToggleButton.module.css +0 -172
  330. package/src/components/ToggleButton/ToggleButton.stories.tsx +0 -299
  331. package/src/components/ToggleButton/ToggleButton.tsx +0 -118
  332. package/src/components/ToggleButton/index.ts +0 -2
  333. package/src/components/ToggleButtonGroup/ToggleButtonGroup.module.css +0 -163
  334. package/src/components/ToggleButtonGroup/ToggleButtonGroup.stories.tsx +0 -341
  335. package/src/components/ToggleButtonGroup/ToggleButtonGroup.tsx +0 -111
  336. package/src/components/ToggleButtonGroup/index.ts +0 -2
  337. package/src/components/Tooltip/Tooltip.module.css +0 -45
  338. package/src/components/Tooltip/Tooltip.stories.tsx +0 -46
  339. package/src/components/Tooltip/Tooltip.tsx +0 -224
  340. package/src/components/Tooltip/index.ts +0 -2
  341. package/src/css-modules.d.ts +0 -4
  342. package/src/docs/ColorUsage.mdx +0 -195
  343. package/src/docs/ElevationUsage.mdx +0 -95
  344. package/src/docs/Introduction.mdx +0 -97
  345. package/src/docs/OpticalSizing.mdx +0 -178
  346. package/src/docs/TypographyUsage.mdx +0 -121
  347. package/src/index.ts +0 -154
  348. package/src/stories/Colors.stories.tsx +0 -528
  349. package/src/stories/Dimensions.stories.tsx +0 -200
  350. package/src/stories/Effects.stories.tsx +0 -231
  351. package/src/stories/Icons.stories.tsx +0 -159
  352. package/src/stories/Typography.stories.tsx +0 -157
  353. package/src/types/icons.ts +0 -15
  354. package/src/types/index.ts +0 -1
  355. package/src/utils/cn.ts +0 -6
  356. package/src/utils/css-tokens.ts +0 -22
@@ -1,384 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import React from 'react';
3
- import { ButtonGroup } from './ButtonGroup';
4
- import { Button } from '@/components/Button';
5
- import type { ButtonContrast, ButtonIntent } from '@/components/Button';
6
- import type { IconComponent } from '@/types/icons';
7
-
8
- const PlaceholderIcon: IconComponent = ({ size = 20 }) => (
9
- <svg width={size} height={size} viewBox="0 0 20 20" fill="currentColor">
10
- <circle cx="10" cy="10" r="6" />
11
- </svg>
12
- );
13
-
14
- interface PlaygroundArgs {
15
- variant: 'primary' | 'secondary';
16
- elevation: 'elevated' | 'flat' | 'none' | 'floating';
17
- intent: ButtonIntent;
18
- contrast: ButtonContrast;
19
- size: 'xs' | 'sm' | 'md' | 'lg';
20
- rounded: boolean;
21
- showIcon: boolean;
22
- }
23
-
24
- const meta: Meta<typeof ButtonGroup> = {
25
- title: 'Primitives (Reviewed)/ButtonGroup',
26
- component: ButtonGroup,
27
- args: {
28
- variant: 'primary',
29
- elevation: 'elevated',
30
- intent: 'brand',
31
- contrast: 'bold',
32
- size: 'md',
33
- rounded: false,
34
- showIcon: false,
35
- } as PlaygroundArgs,
36
- argTypes: {
37
- variant: { control: 'select', options: ['primary', 'secondary'] },
38
- elevation: { control: 'select', options: ['elevated', 'flat', 'none', 'floating'] },
39
- intent: { control: 'select', options: ['none', 'neutral', 'brand', 'ai', 'negative', 'warning', 'caution', 'positive'] },
40
- contrast: { control: 'select', options: ['strong', 'bold', 'medium', 'faint'] },
41
- size: { control: 'select', options: ['lg', 'md', 'sm', 'xs'] },
42
- rounded: { control: 'boolean' },
43
- showIcon: { control: 'boolean' },
44
- } as Record<string, unknown>,
45
- };
46
-
47
- export default meta;
48
- type Story = StoryObj<typeof ButtonGroup>;
49
-
50
- // ─── Shared layout helpers ────────────────────────────────────────────────────
51
-
52
- const col: React.CSSProperties = { display: 'flex', flexDirection: 'column', gap: 16, alignItems: 'flex-start' };
53
- const row: React.CSSProperties = { display: 'flex', gap: 16, alignItems: 'center' };
54
- const lbl: React.CSSProperties = { fontSize: 10, fontFamily: 'monospace', color: '#888', minWidth: 120, flexShrink: 0 };
55
- const section = (text: string) => (
56
- <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.05em', textTransform: 'uppercase', color: '#555', marginTop: 4 }}>
57
- {text}
58
- </div>
59
- );
60
- const divider = <hr style={{ border: 'none', borderTop: '1px solid #e0e0e0', margin: '4px 0 12px' }} />;
61
-
62
- // ─── Playground ──────────────────────────────────────────────────────────────
63
-
64
- export const Playground: Story = {
65
- render: (args) => {
66
- const a = args as unknown as PlaygroundArgs;
67
- const labels = ['First', 'Second', 'Third'];
68
- return (
69
- <ButtonGroup>
70
- {labels.map(label => (
71
- <Button
72
- key={label}
73
- variant={a.variant}
74
- elevation={a.elevation}
75
- intent={a.intent}
76
- contrast={a.contrast}
77
- size={a.size}
78
- rounded={a.rounded}
79
- icon={a.showIcon ? PlaceholderIcon : undefined}
80
- label={label}
81
- />
82
- ))}
83
- </ButtonGroup>
84
- );
85
- },
86
- };
87
-
88
- // ─── Matrix ───────────────────────────────────────────────────────────────────
89
-
90
- export const Matrix: Story = {
91
- parameters: { layout: 'padded' },
92
- render: () => (
93
- <div style={{ ...col, fontFamily: 'sans-serif', gap: 0 }}>
94
-
95
- {/* ── Variants & elevation ── */}
96
- {section('Elevation — full-height vs short divider')}
97
- {divider}
98
- <div style={col}>
99
- <div style={row}>
100
- <span style={lbl}>secondary / flat</span>
101
- <ButtonGroup>
102
- <Button variant="secondary" elevation="flat" label="Day" />
103
- <Button variant="secondary" elevation="flat" label="Week" />
104
- <Button variant="secondary" elevation="flat" label="Month" />
105
- </ButtonGroup>
106
- </div>
107
- <div style={row}>
108
- <span style={lbl}>secondary / elevated</span>
109
- <ButtonGroup>
110
- <Button variant="secondary" elevation="elevated" label="Day" />
111
- <Button variant="secondary" elevation="elevated" label="Week" />
112
- <Button variant="secondary" elevation="elevated" label="Month" />
113
- </ButtonGroup>
114
- </div>
115
- <div style={row}>
116
- <span style={lbl}>primary / none intent</span>
117
- <ButtonGroup>
118
- <Button variant="primary" intent="none" label="Day" />
119
- <Button variant="primary" intent="none" label="Week" />
120
- <Button variant="primary" intent="none" label="Month" />
121
- </ButtonGroup>
122
- </div>
123
- <div style={row}>
124
- <span style={lbl}>secondary / none ↓ short</span>
125
- <ButtonGroup>
126
- <Button variant="secondary" elevation="none" label="Day" />
127
- <Button variant="secondary" elevation="none" label="Week" />
128
- <Button variant="secondary" elevation="none" label="Month" />
129
- </ButtonGroup>
130
- </div>
131
- </div>
132
-
133
- {/* ── Ghost: short divider at each size ── */}
134
- {section('Ghost (elevation=none) — short divider scales with size')}
135
- {divider}
136
- <div style={col}>
137
- {(['lg', 'md', 'sm', 'xs'] as const).map(size => (
138
- <div key={size} style={row}>
139
- <span style={lbl}>{size}</span>
140
- <ButtonGroup>
141
- <Button variant="secondary" elevation="none" size={size} label="One" />
142
- <Button variant="secondary" elevation="none" size={size} label="Two" />
143
- <Button variant="secondary" elevation="none" size={size} label="Three" />
144
- </ButtonGroup>
145
- </div>
146
- ))}
147
- </div>
148
-
149
- {/* ── Primary intents ── */}
150
- {section('Primary — homogeneous intent + contrast (on-bg divider)')}
151
- {divider}
152
- <div style={col}>
153
- {([
154
- { intent: 'brand', contrast: 'bold' },
155
- { intent: 'negative', contrast: 'bold' },
156
- { intent: 'positive', contrast: 'bold' },
157
- { intent: 'brand', contrast: 'medium' },
158
- { intent: 'brand', contrast: 'faint' },
159
- ] as { intent: ButtonIntent; contrast: ButtonContrast }[]).map(({ intent, contrast }) => (
160
- <div key={`${intent}-${contrast}`} style={row}>
161
- <span style={lbl}>{intent} / {contrast}</span>
162
- <ButtonGroup>
163
- <Button variant="primary" intent={intent} contrast={contrast} label="Save" />
164
- <Button variant="primary" intent={intent} contrast={contrast} label="Copy" />
165
- <Button variant="primary" intent={intent} contrast={contrast} label="Export" />
166
- </ButtonGroup>
167
- </div>
168
- ))}
169
- </div>
170
-
171
- {/* ── Sizes ── */}
172
- {section('Sizes — secondary / flat')}
173
- {divider}
174
- <div style={col}>
175
- {(['lg', 'md', 'sm', 'xs'] as const).map(size => (
176
- <div key={size} style={row}>
177
- <span style={lbl}>{size}</span>
178
- <ButtonGroup>
179
- <Button variant="secondary" size={size} label="One" />
180
- <Button variant="secondary" size={size} label="Two" />
181
- <Button variant="secondary" size={size} label="Three" />
182
- </ButtonGroup>
183
- </div>
184
- ))}
185
- </div>
186
-
187
- {/* ── With Icons ── */}
188
- {section('With Icons')}
189
- {divider}
190
- <div style={col}>
191
- <div style={row}>
192
- <span style={lbl}>icon + label</span>
193
- <ButtonGroup>
194
- <Button variant="secondary" icon={PlaceholderIcon} label="Grid" />
195
- <Button variant="secondary" icon={PlaceholderIcon} label="List" />
196
- <Button variant="secondary" icon={PlaceholderIcon} label="Table" />
197
- </ButtonGroup>
198
- </div>
199
- <div style={row}>
200
- <span style={lbl}>icon only</span>
201
- <ButtonGroup>
202
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="Grid" />
203
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="List" />
204
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="Table" />
205
- </ButtonGroup>
206
- </div>
207
- <div style={row}>
208
- <span style={lbl}>ghost icon</span>
209
- <ButtonGroup>
210
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="Grid" />
211
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="List" />
212
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="Table" />
213
- </ButtonGroup>
214
- </div>
215
- </div>
216
-
217
- {/* ── Rounded ── */}
218
- {section('Rounded — outer pill padding, inner base padding')}
219
- {divider}
220
- <div style={col}>
221
- <div style={row}>
222
- <span style={lbl}>secondary / flat</span>
223
- <ButtonGroup>
224
- <Button variant="secondary" label="Day" rounded />
225
- <Button variant="secondary" label="Week" rounded />
226
- <Button variant="secondary" label="Month" rounded />
227
- </ButtonGroup>
228
- </div>
229
- <div style={row}>
230
- <span style={lbl}>ghost</span>
231
- <ButtonGroup>
232
- <Button variant="secondary" elevation="none" label="Day" rounded />
233
- <Button variant="secondary" elevation="none" label="Week" rounded />
234
- <Button variant="secondary" elevation="none" label="Month" rounded />
235
- </ButtonGroup>
236
- </div>
237
- <div style={row}>
238
- <span style={lbl}>icon + label</span>
239
- <ButtonGroup>
240
- <Button variant="secondary" icon={PlaceholderIcon} label="Grid" rounded />
241
- <Button variant="secondary" icon={PlaceholderIcon} label="List" rounded />
242
- <Button variant="secondary" icon={PlaceholderIcon} label="Table" rounded />
243
- </ButtonGroup>
244
- </div>
245
- <div style={row}>
246
- <span style={lbl}>icon only</span>
247
- <ButtonGroup>
248
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="Grid" />
249
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="List" />
250
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="Table" />
251
- </ButtonGroup>
252
- </div>
253
- {(['lg', 'md', 'sm'] as const).map(size => (
254
- <div key={size} style={row}>
255
- <span style={lbl}>rounded {size}</span>
256
- <ButtonGroup>
257
- <Button variant="secondary" size={size} label="One" rounded />
258
- <Button variant="secondary" size={size} label="Two" rounded />
259
- <Button variant="secondary" size={size} label="Three" rounded />
260
- </ButtonGroup>
261
- </div>
262
- ))}
263
- </div>
264
-
265
- {/* ── States ── */}
266
- {section('States')}
267
- {divider}
268
- <div style={col}>
269
- <div style={row}>
270
- <span style={lbl}>with inactive</span>
271
- <ButtonGroup>
272
- <Button variant="secondary" label="One" />
273
- <Button variant="secondary" label="Two" inactive />
274
- <Button variant="secondary" label="Three" />
275
- </ButtonGroup>
276
- </div>
277
- <div style={row}>
278
- <span style={lbl}>two items</span>
279
- <ButtonGroup>
280
- <Button variant="secondary" label="Left" />
281
- <Button variant="secondary" label="Right" />
282
- </ButtonGroup>
283
- </div>
284
- </div>
285
-
286
- </div>
287
- ),
288
- };
289
-
290
- // ─── Individual stories ───────────────────────────────────────────────────────
291
-
292
- export const Secondary: Story = {
293
- render: () => (
294
- <ButtonGroup>
295
- <Button variant="secondary" label="Day" />
296
- <Button variant="secondary" label="Week" />
297
- <Button variant="secondary" label="Month" />
298
- </ButtonGroup>
299
- ),
300
- };
301
-
302
- export const Ghost: Story = {
303
- render: () => (
304
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12, alignItems: 'flex-start' }}>
305
- {(['lg', 'md', 'sm', 'xs'] as const).map(size => (
306
- <ButtonGroup key={size}>
307
- <Button variant="secondary" elevation="none" size={size} label="Grid" />
308
- <Button variant="secondary" elevation="none" size={size} label="List" />
309
- <Button variant="secondary" elevation="none" size={size} label="Table" />
310
- </ButtonGroup>
311
- ))}
312
- </div>
313
- ),
314
- };
315
-
316
- export const PrimaryIntents: Story = {
317
- render: () => (
318
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12, alignItems: 'flex-start' }}>
319
- <ButtonGroup>
320
- <Button variant="primary" intent="brand" label="Save" />
321
- <Button variant="primary" intent="brand" label="Duplicate" />
322
- <Button variant="primary" intent="brand" label="Export" />
323
- </ButtonGroup>
324
- <ButtonGroup>
325
- <Button variant="primary" intent="negative" label="Delete" />
326
- <Button variant="primary" intent="negative" label="Archive" />
327
- </ButtonGroup>
328
- <ButtonGroup>
329
- <Button variant="primary" intent="brand" contrast="medium" label="Save" />
330
- <Button variant="primary" intent="brand" contrast="medium" label="Duplicate" />
331
- <Button variant="primary" intent="brand" contrast="medium" label="Export" />
332
- </ButtonGroup>
333
- <ButtonGroup>
334
- <Button variant="primary" intent="brand" contrast="faint" label="Save" />
335
- <Button variant="primary" intent="brand" contrast="faint" label="Duplicate" />
336
- <Button variant="primary" intent="brand" contrast="faint" label="Export" />
337
- </ButtonGroup>
338
- </div>
339
- ),
340
- };
341
-
342
- export const Rounded: Story = {
343
- render: () => (
344
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12, alignItems: 'flex-start' }}>
345
- <ButtonGroup>
346
- <Button variant="secondary" label="Day" rounded />
347
- <Button variant="secondary" label="Week" rounded />
348
- <Button variant="secondary" label="Month" rounded />
349
- </ButtonGroup>
350
- <ButtonGroup>
351
- <Button variant="secondary" elevation="none" label="Day" rounded />
352
- <Button variant="secondary" elevation="none" label="Week" rounded />
353
- <Button variant="secondary" elevation="none" label="Month" rounded />
354
- </ButtonGroup>
355
- <ButtonGroup>
356
- <Button variant="secondary" icon={PlaceholderIcon} label="Grid" rounded />
357
- <Button variant="secondary" icon={PlaceholderIcon} label="List" rounded />
358
- <Button variant="secondary" icon={PlaceholderIcon} label="Table" rounded />
359
- </ButtonGroup>
360
- <ButtonGroup>
361
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="Grid" />
362
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="List" />
363
- <Button variant="secondary" icon={PlaceholderIcon} rounded aria-label="Table" />
364
- </ButtonGroup>
365
- </div>
366
- ),
367
- };
368
-
369
- export const IconOnly: Story = {
370
- render: () => (
371
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12, alignItems: 'flex-start' }}>
372
- <ButtonGroup>
373
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="Grid view" />
374
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="List view" />
375
- <Button variant="secondary" icon={PlaceholderIcon} aria-label="Table view" />
376
- </ButtonGroup>
377
- <ButtonGroup>
378
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="Grid view" />
379
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="List view" />
380
- <Button variant="secondary" elevation="none" icon={PlaceholderIcon} aria-label="Table view" />
381
- </ButtonGroup>
382
- </div>
383
- ),
384
- };
@@ -1,122 +0,0 @@
1
- import React from 'react';
2
- import { cn } from '@/utils/cn';
3
- import styles from './ButtonGroup.module.css';
4
-
5
- export interface ButtonGroupProps {
6
- children: React.ReactNode;
7
- className?: string;
8
- }
9
-
10
- /**
11
- * Renders Button children flush side-by-side with a 1px divider between them.
12
- * Outer corners keep the button's own border-radius; inner corners are flattened.
13
- *
14
- * Individual button chrome (shadow/border) is suppressed — the group container
15
- * carries the elevation so it wraps the whole control as one visual unit.
16
- *
17
- * Divider behaviour by variant:
18
- * secondary / primary+none — full-height color-border-tertiary line
19
- * primary (with intent) — color-border-tertiary-on-{contrast}-background
20
- * ghost (secondary+none) — short centred line (icon/text height)
21
- *
22
- * Rounded groups: outer edges keep pill padding; inner edges revert to base padding.
23
- * Mix of intents is only valid when variant="secondary"; primary groups must be
24
- * homogeneous (same intent + contrast on all items).
25
- */
26
- export const ButtonGroup = ({ children, className }: ButtonGroupProps) => {
27
- const items = React.Children.toArray(children).filter(React.isValidElement);
28
- const count = items.length;
29
-
30
- // Read elevation + rounded from first child to drive the group container style.
31
- const firstEl = items[0] as React.ReactElement<Record<string, unknown>> | undefined;
32
- const firstProps = firstEl?.props as { variant?: string; elevation?: string; rounded?: boolean } | undefined;
33
- const firstVariant = firstProps?.variant ?? 'secondary';
34
- const firstElevation = firstProps?.elevation ?? (firstVariant === 'primary' ? 'none' : 'flat');
35
- const groupRounded = !!firstProps?.rounded;
36
- const groupElevKey = firstElevation.charAt(0).toUpperCase() + firstElevation.slice(1);
37
-
38
- return (
39
- <div
40
- className={cn(
41
- styles.group,
42
- (styles as Record<string, string>)[`group${groupElevKey}`],
43
- groupRounded && styles.groupRounded,
44
- className,
45
- )}
46
- role="group"
47
- >
48
- {items.map((child, i) => {
49
- const el = child as React.ReactElement<Record<string, unknown>>;
50
- const p = el.props as {
51
- className?: string;
52
- variant?: string;
53
- elevation?: string;
54
- size?: string;
55
- intent?: string;
56
- contrast?: string;
57
- rounded?: boolean;
58
- icon?: unknown;
59
- label?: unknown;
60
- };
61
-
62
- const isFirst = i === 0;
63
- const isLast = i === count - 1;
64
- const isMid = !isFirst && !isLast;
65
-
66
- const variant = p.variant ?? 'secondary';
67
- const size = (p.size ?? 'md') as 'xs' | 'sm' | 'md' | 'lg';
68
- const contrast = p.contrast ?? 'bold';
69
- const intent = p.intent ?? 'brand';
70
- const isRounded = !!p.rounded;
71
- const isIconOnly = !!p.icon && !p.label;
72
- // Ghost: secondary button with elevation='none' (replaces old tertiary variant)
73
- const isGhost = variant === 'secondary' && (p.elevation ?? 'flat') === 'none';
74
- const isPrimary = variant === 'primary' && intent !== 'none';
75
-
76
- // Contrast class suffix — capitalised first letter
77
- const contrastKey = contrast.charAt(0).toUpperCase() + contrast.slice(1);
78
-
79
- // Size suffix for rounded padding correction — uppercase
80
- // XS rounded has no extra padding in Button so needs no correction
81
- const sizeKey = size.toUpperCase() as 'MD' | 'SM' | 'LG' | 'XS';
82
- const needsRoundedCorrection = isRounded && !isIconOnly && size !== 'xs';
83
-
84
- // Divider injected as a separate element so it's never affected by
85
- // the adjacent button's opacity (e.g. disabled state).
86
- const dividerClasses = cn(
87
- styles.divider,
88
- isGhost && styles.dividerGhost,
89
- isGhost && size === 'xs' && styles.dividerGhostXS,
90
- isGhost && size === 'sm' && styles.dividerGhostSM,
91
- isGhost && size === 'lg' && styles.dividerGhostLG,
92
- isPrimary && (styles as Record<string, string>)[`divider${contrastKey}`],
93
- );
94
-
95
- return (
96
- <React.Fragment key={i}>
97
- {i > 0 && <div className={dividerClasses} aria-hidden="true" />}
98
- {React.cloneElement(el, {
99
- className: cn(
100
- p.className,
101
- styles.item,
102
- isFirst && styles.first,
103
- isLast && styles.last,
104
- isMid && styles.middle,
105
-
106
- // Ghost (secondary+elevation=none): ::after overlay gets 4px radius treatment
107
- isGhost && styles.itemShort,
108
-
109
- // Rounded: revert inner-edge padding to base (non-pill) value
110
- needsRoundedCorrection && isFirst && (styles as Record<string, string>)[`roundedFirst${sizeKey}`],
111
- needsRoundedCorrection && isLast && (styles as Record<string, string>)[`roundedLast${sizeKey}`],
112
- needsRoundedCorrection && isMid && (styles as Record<string, string>)[`roundedMid${sizeKey}`],
113
- ),
114
- })}
115
- </React.Fragment>
116
- );
117
- })}
118
- </div>
119
- );
120
- };
121
-
122
- ButtonGroup.displayName = 'ButtonGroup';
@@ -1,2 +0,0 @@
1
- export { ButtonGroup } from './ButtonGroup';
2
- export type { ButtonGroupProps } from './ButtonGroup';
@@ -1,36 +0,0 @@
1
- /**
2
- * Card — structured container with optional header/footer.
3
- * Uses TokoMo tokens directly (not built on Surface).
4
- */
5
-
6
- .card {
7
- box-sizing: border-box;
8
- background-color: var(--color-background-primary);
9
- overflow: hidden;
10
- }
11
-
12
- /* Elevation */
13
- .elevationFlat { box-shadow: var(--effect-elevation-elevated-none); }
14
- .elevationElevated { box-shadow: var(--effect-elevation-elevated-sm); }
15
- .elevationFloating { box-shadow: var(--effect-elevation-elevated-floating); }
16
-
17
- /* Radius */
18
- .radiusSm { border-radius: var(--dimension-radius-075); }
19
- .radiusMd { border-radius: var(--dimension-radius-100); }
20
- .radiusLg { border-radius: var(--dimension-radius-125); }
21
- .radiusXl { border-radius: var(--dimension-radius-175); }
22
-
23
- /* Sections */
24
- .header {
25
- padding: var(--dimension-space-150) var(--dimension-space-200);
26
- border-bottom: var(--dimension-stroke-width-015) solid var(--color-border-primary);
27
- }
28
-
29
- .body {
30
- padding: var(--dimension-space-200);
31
- }
32
-
33
- .footer {
34
- padding: var(--dimension-space-150) var(--dimension-space-200);
35
- border-top: var(--dimension-stroke-width-015) solid var(--color-border-primary);
36
- }
@@ -1,78 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Card } from './Card';
3
-
4
- const meta: Meta<typeof Card> = {
5
- title: 'Components/Card',
6
- component: Card,
7
- argTypes: {
8
- elevation: {
9
- control: 'select',
10
- options: ['flat', 'elevated', 'floating'],
11
- },
12
- radius: {
13
- control: 'select',
14
- options: ['sm', 'md', 'lg', 'xl'],
15
- },
16
- },
17
- };
18
-
19
- export default meta;
20
- type Story = StoryObj<typeof Card>;
21
-
22
- export const Default: Story = {
23
- args: {
24
- children: 'Card body content goes here.',
25
- style: { width: 360 },
26
- },
27
- };
28
-
29
- export const WithHeader: Story = {
30
- args: {
31
- header: <strong>Account Settings</strong>,
32
- children: 'Form fields and content go here.',
33
- style: { width: 360 },
34
- },
35
- };
36
-
37
- export const WithHeaderAndFooter: Story = {
38
- args: {
39
- header: <strong>Edit Profile</strong>,
40
- children: (
41
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
42
- <div>Name: Zain Adeel</div>
43
- <div>Email: zain@example.com</div>
44
- </div>
45
- ),
46
- footer: (
47
- <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
48
- <button>Cancel</button>
49
- <button>Save</button>
50
- </div>
51
- ),
52
- style: { width: 360 },
53
- },
54
- };
55
-
56
- export const Elevations: Story = {
57
- render: () => (
58
- <div style={{ display: 'flex', gap: 24, padding: 24 }}>
59
- {(['flat', 'elevated', 'floating'] as const).map(elevation => (
60
- <Card key={elevation} elevation={elevation} style={{ width: 200 }}>
61
- {elevation}
62
- </Card>
63
- ))}
64
- </div>
65
- ),
66
- };
67
-
68
- export const Radii: Story = {
69
- render: () => (
70
- <div style={{ display: 'flex', gap: 24, padding: 24 }}>
71
- {(['sm', 'md', 'lg', 'xl'] as const).map(radius => (
72
- <Card key={radius} radius={radius} style={{ width: 160 }}>
73
- radius: {radius}
74
- </Card>
75
- ))}
76
- </div>
77
- ),
78
- };
@@ -1,53 +0,0 @@
1
- import React, { forwardRef } from 'react';
2
- import styles from './Card.module.css';
3
- import { cn } from '@/utils/cn';
4
-
5
- export type CardElevation = 'flat' | 'elevated' | 'floating';
6
- export type CardRadius = 'sm' | 'md' | 'lg' | 'xl';
7
-
8
- export interface CardProps {
9
- children: React.ReactNode;
10
- /** Optional header content — rendered with a bottom divider. */
11
- header?: React.ReactNode;
12
- /** Optional footer content — rendered with a top divider. */
13
- footer?: React.ReactNode;
14
- /** Elevation level. Defaults to 'elevated'. */
15
- elevation?: CardElevation;
16
- /** Corner radius. Defaults to 'lg'. */
17
- radius?: CardRadius;
18
- /** Additional CSS classes. */
19
- className?: string;
20
- /** Inline styles. */
21
- style?: React.CSSProperties;
22
- }
23
-
24
- const elevationClassMap: Record<CardElevation, string> = {
25
- flat: styles.elevationFlat,
26
- elevated: styles.elevationElevated,
27
- floating: styles.elevationFloating,
28
- };
29
-
30
- const radiusClassMap: Record<CardRadius, string> = {
31
- sm: styles.radiusSm,
32
- md: styles.radiusMd,
33
- lg: styles.radiusLg,
34
- xl: styles.radiusXl,
35
- };
36
-
37
- export const Card = forwardRef<HTMLDivElement, CardProps>(
38
- ({ children, header, footer, elevation = 'elevated', radius = 'lg', className, style }, ref) => {
39
- return (
40
- <div
41
- ref={ref}
42
- className={cn(styles.card, elevationClassMap[elevation], radiusClassMap[radius], className)}
43
- style={style}
44
- >
45
- {header && <div className={styles.header}>{header}</div>}
46
- <div className={styles.body}>{children}</div>
47
- {footer && <div className={styles.footer}>{footer}</div>}
48
- </div>
49
- );
50
- }
51
- );
52
-
53
- Card.displayName = 'Card';