@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,72 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
- "name": "tab-group",
4
- "title": "TabGroup",
5
- "description": "Tab orchestrator that wraps Tab components with an animated sliding indicator and active state management.",
6
- "type": "registry:ui",
7
- "meta": {
8
- "library": "@compomo/ui",
9
- "distribution": "npm",
10
- "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/tab-group",
11
- "consumption": {
12
- "install": "npm install @compomo/ui @ds-mo/tokens",
13
- "cssSetup": "Import tokens CSS at your app entry point: import '@ds-mo/tokens/css';\nThis provides all var(--color-*), var(--dimension-*), var(--effect-*), and var(--typography-*) custom properties.\nFor dark mode, set data-theme=\"dark\" on <html>.",
14
- "import": "import { TabGroup } from '@compomo/ui';",
15
- "cssImport": "import '@compomo/ui/css';",
16
- "typeImport": "import type { TabGroupProps, TabGroupTab } from '@compomo/ui';",
17
- "internalDependencies": [
18
- {
19
- "component": "Tab",
20
- "note": "Used internally by TabGroup. No action needed — it's bundled in @compomo/ui."
21
- }
22
- ],
23
- "peerDependencies": {
24
- "required": [
25
- "react >=17",
26
- "react-dom >=17",
27
- "@ds-mo/tokens >=0.1.0"
28
- ],
29
- "optional": []
30
- }
31
- },
32
- "props": {
33
- "tabs": {
34
- "type": "TabGroupTab[]",
35
- "required": true
36
- },
37
- "activeIndex": {
38
- "type": "number",
39
- "default": "0"
40
- },
41
- "onTabChange": {
42
- "type": "(index: number) => void"
43
- }
44
- },
45
- "exports": [
46
- "TabGroup"
47
- ],
48
- "types": [
49
- "TabGroupProps",
50
- "TabGroupTab"
51
- ]
52
- },
53
- "dependencies": [
54
- "@compomo/ui",
55
- "@ds-mo/tokens"
56
- ],
57
- "registryDependencies": [
58
- "tab"
59
- ],
60
- "files": [
61
- {
62
- "path": "src/components/TabGroup/TabGroup.module.css",
63
- "content": ".tabGroup {\n display: flex;\n flex-direction: column;\n position: relative;\n}\n\n.tabsRow {\n display: flex;\n gap: var(--dimension-space-025);\n}\n\n.track {\n height: 2px;\n background-color: var(--color-border-secondary);\n position: relative;\n}\n\n.indicator {\n position: absolute;\n bottom: 0;\n height: 2px;\n background-color: var(--color-foreground-primary);\n border-radius: 1px;\n transition: transform var(--effect-motion-short-3), width var(--effect-motion-short-3);\n will-change: transform, width;\n}\n",
64
- "type": "registry:ui"
65
- },
66
- {
67
- "path": "src/components/TabGroup/TabGroup.tsx",
68
- "content": "import React, { forwardRef, useRef, useEffect, useState, useCallback } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Tab } from '@/components/Tab';\nimport styles from './TabGroup.module.css';\n\nexport interface TabGroupTab {\n label: string;\n id?: string;\n}\n\nexport interface TabGroupProps {\n /** Tab definitions. */\n tabs: TabGroupTab[];\n /** Index of the active tab. */\n activeIndex?: number;\n /** Called when a tab is clicked. */\n onTabChange?: (index: number) => void;\n className?: string;\n}\n\nexport const TabGroup = forwardRef<HTMLDivElement, TabGroupProps>(\n ({ tabs, activeIndex = 0, onTabChange, className }, ref) => {\n const tabsRef = useRef<(HTMLButtonElement | null)[]>([]);\n const [indicator, setIndicator] = useState({ left: 0, width: 0 });\n\n const updateIndicator = useCallback(() => {\n const el = tabsRef.current[activeIndex];\n if (el) {\n const parent = el.parentElement;\n if (parent) {\n setIndicator({\n left: el.offsetLeft,\n width: el.offsetWidth,\n });\n }\n }\n }, [activeIndex]);\n\n useEffect(() => {\n updateIndicator();\n }, [updateIndicator]);\n\n // Recalculate on resize\n useEffect(() => {\n const observer = new ResizeObserver(updateIndicator);\n const container = tabsRef.current[0]?.parentElement;\n if (container) observer.observe(container);\n return () => observer.disconnect();\n }, [updateIndicator]);\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n className={cn(styles.tabGroup, className)}\n >\n <div className={styles.tabsRow}>\n {tabs.map((tab, i) => (\n <Tab\n key={tab.id ?? i}\n ref={el => { tabsRef.current[i] = el; }}\n id={tab.id}\n label={tab.label}\n isSelected={i === activeIndex}\n onClick={() => onTabChange?.(i)}\n />\n ))}\n </div>\n <div className={styles.track}>\n <div\n className={styles.indicator}\n style={{\n transform: `translateX(${indicator.left}px)`,\n width: indicator.width,\n }}\n />\n </div>\n </div>\n );\n }\n);\n\nTabGroup.displayName = 'TabGroup';\n",
69
- "type": "registry:ui"
70
- }
71
- ]
72
- }
package/dist/r/tab.json DELETED
@@ -1,71 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
- "name": "tab",
4
- "title": "Tab",
5
- "description": "Individual tab button with selected state and hover overlay.",
6
- "type": "registry:ui",
7
- "meta": {
8
- "library": "@compomo/ui",
9
- "distribution": "npm",
10
- "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/tab",
11
- "consumption": {
12
- "install": "npm install @compomo/ui @ds-mo/tokens",
13
- "cssSetup": "Import tokens CSS at your app entry point: import '@ds-mo/tokens/css';\nThis provides all var(--color-*), var(--dimension-*), var(--effect-*), and var(--typography-*) custom properties.\nFor dark mode, set data-theme=\"dark\" on <html>.",
14
- "import": "import { Tab } from '@compomo/ui';",
15
- "cssImport": "import '@compomo/ui/css';",
16
- "typeImport": "import type { TabProps } from '@compomo/ui';",
17
- "internalDependencies": [
18
- {
19
- "component": "Text",
20
- "note": "Used internally by Tab. No action needed — it's bundled in @compomo/ui."
21
- }
22
- ],
23
- "peerDependencies": {
24
- "required": [
25
- "react >=17",
26
- "react-dom >=17",
27
- "@ds-mo/tokens >=0.1.0"
28
- ],
29
- "optional": []
30
- }
31
- },
32
- "props": {
33
- "label": {
34
- "type": "string",
35
- "required": true
36
- },
37
- "isSelected": {
38
- "type": "boolean",
39
- "default": "false"
40
- },
41
- "onClick": {
42
- "type": "() => void"
43
- }
44
- },
45
- "exports": [
46
- "Tab"
47
- ],
48
- "types": [
49
- "TabProps"
50
- ]
51
- },
52
- "dependencies": [
53
- "@compomo/ui",
54
- "@ds-mo/tokens"
55
- ],
56
- "registryDependencies": [
57
- "text"
58
- ],
59
- "files": [
60
- {
61
- "path": "src/components/Tab/Tab.module.css",
62
- "content": "/* ==========================================================================\n Tab — hover/pressed via direct background-color, no pseudo-element overlay.\n ========================================================================== */\n\n.tab {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-075);\n background-color: transparent;\n border: none;\n border-radius: var(--dimension-radius-075);\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n color: var(--color-foreground-secondary);\n position: relative;\n will-change: color;\n transition: color var(--effect-motion-short-2),\n background-color var(--effect-motion-short-2);\n flex-shrink: 0;\n height: var(--dimension-size-400);\n box-sizing: border-box;\n\n /* Interaction — ghost defaults */\n --_hover-bg: var(--color-interaction-hover);\n --_pressed-bg: var(--color-interaction-pressed);\n}\n\n.tab:hover { background-color: var(--_hover-bg); }\n.tab:active { background-color: var(--_pressed-bg); }\n\n.tabSelected { color: var(--color-foreground-primary); }\n\n/* ==========================================================================\n Background context — parent surface awareness\n ========================================================================== */\n\n.onMedium {\n --_hover-bg: var(--color-interaction-on-medium-background-hover);\n --_pressed-bg: var(--color-interaction-on-medium-background-pressed);\n}\n\n.onBold {\n --_hover-bg: var(--color-interaction-on-bold-background-hover);\n --_pressed-bg: var(--color-interaction-on-bold-background-pressed);\n color: var(--color-foreground-on-bold-background-secondary);\n}\n\n.onBold.tabSelected { color: var(--color-foreground-on-bold-background-primary); }\n\n.onStrong {\n --_hover-bg: var(--color-interaction-on-strong-background-hover);\n --_pressed-bg: var(--color-interaction-on-strong-background-pressed);\n color: var(--color-foreground-on-bold-background-secondary);\n}\n\n.onStrong.tabSelected { color: var(--color-foreground-on-bold-background-primary); }\n\n.onAlwaysDark {\n --_hover-bg: var(--color-always-dark-interaction-hover);\n --_pressed-bg: var(--color-always-dark-interaction-pressed);\n color: var(--color-always-dark-foreground-secondary);\n}\n\n.onAlwaysDark.tabSelected { color: var(--color-always-dark-foreground-primary); }\n",
63
- "type": "registry:ui"
64
- },
65
- {
66
- "path": "src/components/Tab/Tab.tsx",
67
- "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './Tab.module.css';\n\nexport type TabBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';\n\nexport interface TabProps {\n id?: string;\n label: string;\n isSelected?: boolean;\n /** Parent surface context. Adjusts hover tokens and fg for tabs on colored backgrounds. */\n background?: TabBackground;\n onClick?: () => void;\n className?: string;\n}\n\nexport const Tab = forwardRef<HTMLButtonElement, TabProps>(\n ({ id, label, isSelected = false, background, onClick, className }, ref) => {\n const bgClass = background && background !== 'faint'\n ? styles[background === 'always-dark' ? 'onAlwaysDark' : `on${background.charAt(0).toUpperCase() + background.slice(1)}`]\n : undefined;\n return (\n <button\n ref={ref}\n id={id}\n className={cn(styles.tab, isSelected && styles.tabSelected, bgClass, className)}\n onClick={onClick}\n type=\"button\"\n aria-selected={isSelected}\n role=\"tab\"\n >\n <Text variant={isSelected ? 'text-body-medium-emphasis' : 'text-body-medium'} as=\"span\">\n {label}\n </Text>\n </button>\n );\n }\n);\n\nTab.displayName = 'Tab';\n",
68
- "type": "registry:ui"
69
- }
70
- ]
71
- }
package/dist/r/table.json DELETED
@@ -1,110 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
- "name": "table",
4
- "title": "Table",
5
- "description": "Data table with CSS grid layout, sorting, pagination, loading skeleton, row selection, and custom cell rendering.",
6
- "type": "registry:ui",
7
- "meta": {
8
- "library": "@compomo/ui",
9
- "distribution": "npm",
10
- "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/table",
11
- "consumption": {
12
- "install": "npm install @compomo/ui @ds-mo/tokens",
13
- "cssSetup": "Import tokens CSS at your app entry point: import '@ds-mo/tokens/css';\nThis provides all var(--color-*), var(--dimension-*), var(--effect-*), and var(--typography-*) custom properties.\nFor dark mode, set data-theme=\"dark\" on <html>.",
14
- "import": "import { Table } from '@compomo/ui';",
15
- "cssImport": "import '@compomo/ui/css';",
16
- "typeImport": "import type { TableProps, TableColumn, SortState, SortDirection, CellType, FilterValue, FilterState, PaginationState } from '@compomo/ui';",
17
- "internalDependencies": [
18
- {
19
- "component": "Text",
20
- "note": "Used internally by Table. No action needed — it's bundled in @compomo/ui."
21
- },
22
- {
23
- "component": "Surface",
24
- "note": "Used internally by Table. No action needed — it's bundled in @compomo/ui."
25
- },
26
- {
27
- "component": "Skeleton",
28
- "note": "Used internally by Table. No action needed — it's bundled in @compomo/ui."
29
- }
30
- ],
31
- "peerDependencies": {
32
- "required": [
33
- "react >=17",
34
- "react-dom >=17",
35
- "@ds-mo/tokens >=0.1.0"
36
- ],
37
- "optional": []
38
- }
39
- },
40
- "props": {
41
- "columns": {
42
- "type": "TableColumn<T>[]",
43
- "required": true
44
- },
45
- "data": {
46
- "type": "T[]",
47
- "required": true
48
- },
49
- "sortState": {
50
- "type": "SortState"
51
- },
52
- "onSort": {
53
- "type": "(columnId: string) => void"
54
- },
55
- "onRowClick": {
56
- "type": "(row: T, rowIndex: number) => void"
57
- },
58
- "selectedRows": {
59
- "type": "Set<number>"
60
- },
61
- "loading": {
62
- "type": "boolean"
63
- },
64
- "pagination": {
65
- "type": "PaginationState"
66
- },
67
- "onPaginationChange": {
68
- "type": "(pageIndex: number, pageSize: number) => void"
69
- },
70
- "emptyMessage": {
71
- "type": "string",
72
- "default": "'No results found.'"
73
- }
74
- },
75
- "exports": [
76
- "Table"
77
- ],
78
- "types": [
79
- "TableProps",
80
- "TableColumn",
81
- "SortState",
82
- "SortDirection",
83
- "CellType",
84
- "FilterValue",
85
- "FilterState",
86
- "PaginationState"
87
- ]
88
- },
89
- "dependencies": [
90
- "@compomo/ui",
91
- "@ds-mo/tokens"
92
- ],
93
- "registryDependencies": [
94
- "text",
95
- "surface",
96
- "skeleton"
97
- ],
98
- "files": [
99
- {
100
- "path": "src/components/Table/Table.module.css",
101
- "content": ".tableWrapper {\n display: flex;\n flex-direction: column;\n width: 100%;\n overflow: hidden;\n border-radius: var(--dimension-radius-075);\n}\n\n.tableScroll {\n overflow-x: auto;\n width: 100%;\n}\n\n.table {\n display: grid;\n width: 100%;\n min-width: max-content;\n}\n\n.headerRow {\n display: contents;\n}\n\n.headerCell {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-075) var(--dimension-space-100);\n background-color: var(--color-background-secondary);\n border-bottom: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n -webkit-user-select: none;\n user-select: none;\n position: sticky;\n top: 0;\n z-index: 2;\n}\n\n.headerCell.sortable {\n cursor: pointer;\n}\n\n.headerCell.sortable:hover {\n background-color: var(--color-background-translucent);\n}\n\n.sortIndicator {\n font-size: 12px;\n color: var(--color-foreground-secondary);\n}\n\n.row {\n display: contents;\n}\n\n.row:hover .cell {\n background-color: var(--color-interaction-hover);\n}\n\n.rowSelected .cell {\n background-color: var(--color-background-faint-brand);\n}\n\n.rowClickable {\n cursor: pointer;\n}\n\n.cell {\n display: flex;\n align-items: center;\n padding: var(--dimension-space-075) var(--dimension-space-100);\n border-bottom: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n min-height: var(--dimension-size-500);\n background-color: var(--color-background-primary);\n transition: background-color var(--effect-motion-short-2);\n}\n\n.alignRight { justify-content: flex-end; text-align: right; }\n.alignCenter { justify-content: center; text-align: center; }\n\n.emptyRow {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-400);\n background-color: var(--color-background-primary);\n}\n\n.skeleton {\n height: 14px;\n width: 60%;\n background-color: var(--color-background-translucent);\n border-radius: var(--dimension-radius-050);\n animation: shimmer 1.5s infinite;\n}\n\n@keyframes shimmer {\n 0% { opacity: 0.5; }\n 50% { opacity: 1; }\n 100% { opacity: 0.5; }\n}\n\n.pagination {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-100);\n border-top: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n background-color: var(--color-background-primary);\n}\n\n.pageButton {\n display: flex;\n align-items: center;\n padding: var(--dimension-space-050) var(--dimension-space-100);\n background-color: transparent;\n border: none;\n border-radius: var(--dimension-radius-075);\n cursor: pointer;\n transition: background-color var(--effect-motion-short-2);\n}\n\n.pageButton:hover:not(:disabled) {\n background-color: var(--color-interaction-hover);\n}\n\n.pageButton:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n",
102
- "type": "registry:ui"
103
- },
104
- {
105
- "path": "src/components/Table/Table.tsx",
106
- "content": "import React, { useMemo, useState, useCallback } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './Table.module.css';\n\nexport type SortDirection = 'asc' | 'desc';\nexport type CellType = 'string' | 'numbers' | 'tag' | 'checkbox' | 'button' | 'spacer' | 'image' | 'icon' | 'empty';\nexport type FilterValue = string | number | Array<string | number> | undefined;\nexport type FilterState = Record<string, FilterValue>;\n\nexport interface SortState {\n columnId: string;\n direction: SortDirection;\n}\n\nexport interface PaginationState {\n pageIndex: number;\n pageSize: number;\n}\n\nexport interface TableColumn<T = unknown> {\n id: string;\n header: string | React.ReactNode;\n accessorKey?: string;\n accessor?: (row: T) => unknown;\n sortable?: boolean;\n align?: 'left' | 'right' | 'center';\n width?: string | number;\n minWidth?: string | number;\n maxWidth?: string | number;\n renderCell?: (row: T, rowIndex: number) => React.ReactNode;\n cellType?: CellType;\n hide?: boolean;\n pinned?: 'left' | 'right';\n}\n\nexport interface TableProps<T = unknown> {\n columns: TableColumn<T>[];\n data: T[];\n sortState?: SortState;\n onSort?: (columnId: string) => void;\n className?: string;\n onRowClick?: (row: T, rowIndex: number) => void;\n selectedRows?: Set<number>;\n loading?: boolean;\n pagination?: PaginationState;\n onPaginationChange?: (pageIndex: number, pageSize: number) => void;\n emptyMessage?: string;\n}\n\nfunction getColumnValue<T>(column: TableColumn<T>, row: T): unknown {\n if (column.accessorKey) return (row as Record<string, unknown>)[column.accessorKey];\n if (column.accessor) return column.accessor(row);\n return undefined;\n}\n\nfunction compareValues(a: unknown, b: unknown, direction: SortDirection): number {\n const mult = direction === 'asc' ? 1 : -1;\n if (a == null && b == null) return 0;\n if (a == null) return mult;\n if (b == null) return -mult;\n if (typeof a === 'number' && typeof b === 'number') return (a - b) * mult;\n return String(a).localeCompare(String(b)) * mult;\n}\n\nexport function Table<T>({\n columns,\n data,\n sortState,\n onSort,\n className,\n onRowClick,\n selectedRows,\n loading = false,\n pagination,\n onPaginationChange,\n emptyMessage = 'No results found.',\n}: TableProps<T>) {\n const visibleColumns = useMemo(() => columns.filter(c => !c.hide), [columns]);\n\n const gridTemplateColumns = useMemo(() =>\n visibleColumns.map(col => {\n if (col.width) return typeof col.width === 'number' ? `${col.width}px` : col.width;\n return 'minmax(120px, 1fr)';\n }).join(' '),\n [visibleColumns]\n );\n\n const sortedData = useMemo(() => {\n if (!sortState) return data;\n const col = columns.find(c => c.id === sortState.columnId);\n if (!col) return data;\n return [...data].sort((a, b) =>\n compareValues(getColumnValue(col, a), getColumnValue(col, b), sortState.direction)\n );\n }, [data, columns, sortState]);\n\n const pagedData = useMemo(() => {\n if (!pagination) return sortedData;\n const start = pagination.pageIndex * pagination.pageSize;\n return sortedData.slice(start, start + pagination.pageSize);\n }, [sortedData, pagination]);\n\n const totalPages = pagination ? Math.ceil(sortedData.length / pagination.pageSize) : 1;\n const isEmpty = !loading && pagedData.length === 0;\n\n const handleSort = (columnId: string) => {\n if (onSort) onSort(columnId);\n };\n\n return (\n <div className={cn(styles.tableWrapper, className)}>\n <div className={styles.tableScroll}>\n <div className={styles.table} style={{ gridTemplateColumns }} role=\"table\">\n {/* Header */}\n <div className={styles.headerRow} role=\"row\">\n {visibleColumns.map(col => (\n <div\n key={col.id}\n className={cn(\n styles.headerCell,\n col.sortable && styles.sortable,\n col.align === 'right' && styles.alignRight,\n col.align === 'center' && styles.alignCenter\n )}\n role=\"columnheader\"\n onClick={() => col.sortable && handleSort(col.id)}\n style={col.minWidth ? { minWidth: typeof col.minWidth === 'number' ? `${col.minWidth}px` : col.minWidth } : undefined}\n >\n {typeof col.header === 'string' ? (\n <Text variant=\"text-body-small-emphasis\" as=\"span\" color=\"secondary\">\n {col.header}\n </Text>\n ) : col.header}\n {sortState?.columnId === col.id && (\n <span className={styles.sortIndicator} aria-hidden>\n {sortState.direction === 'asc' ? '\\u2191' : '\\u2193'}\n </span>\n )}\n </div>\n ))}\n </div>\n\n {/* Loading skeleton */}\n {loading && Array.from({ length: 5 }).map((_, i) => (\n <div key={`skeleton-${i}`} className={styles.row} role=\"row\">\n {visibleColumns.map(col => (\n <div key={col.id} className={styles.cell} role=\"cell\">\n <div className={styles.skeleton} />\n </div>\n ))}\n </div>\n ))}\n\n {/* Empty state */}\n {isEmpty && (\n <div className={styles.emptyRow} style={{ gridColumn: `1 / -1` }}>\n <Text variant=\"text-body-medium\" as=\"p\" color=\"secondary\">{emptyMessage}</Text>\n </div>\n )}\n\n {/* Data rows */}\n {!loading && pagedData.map((row, rowIndex) => {\n const isSelected = selectedRows?.has(rowIndex);\n return (\n <div\n key={rowIndex}\n className={cn(\n styles.row,\n isSelected && styles.rowSelected,\n onRowClick && styles.rowClickable\n )}\n role=\"row\"\n onClick={() => onRowClick?.(row, rowIndex)}\n >\n {visibleColumns.map(col => (\n <div\n key={col.id}\n className={cn(\n styles.cell,\n col.align === 'right' && styles.alignRight,\n col.align === 'center' && styles.alignCenter\n )}\n role=\"cell\"\n >\n {col.renderCell\n ? col.renderCell(row, rowIndex)\n : <Text variant=\"text-body-medium\" as=\"span\" lineTruncation={1}>{String(getColumnValue(col, row) ?? '')}</Text>\n }\n </div>\n ))}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Pagination */}\n {pagination && onPaginationChange && totalPages > 1 && (\n <div className={styles.pagination}>\n <button\n className={styles.pageButton}\n disabled={pagination.pageIndex === 0}\n onClick={() => onPaginationChange(pagination.pageIndex - 1, pagination.pageSize)}\n type=\"button\"\n >\n <Text variant=\"text-body-small\" as=\"span\">Previous</Text>\n </button>\n <Text variant=\"text-body-small\" as=\"span\" color=\"secondary\">\n {`Page ${pagination.pageIndex + 1} of ${totalPages}`}\n </Text>\n <button\n className={styles.pageButton}\n disabled={pagination.pageIndex >= totalPages - 1}\n onClick={() => onPaginationChange(pagination.pageIndex + 1, pagination.pageSize)}\n type=\"button\"\n >\n <Text variant=\"text-body-small\" as=\"span\">Next</Text>\n </button>\n </div>\n )}\n </div>\n );\n}\n\nTable.displayName = 'Table';\n",
107
- "type": "registry:ui"
108
- }
109
- ]
110
- }
package/dist/r/tag.json DELETED
@@ -1,110 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
- "name": "tag",
4
- "title": "Tag",
5
- "description": "Semantic label with intent coloring, removable chip, pressable filter-chip mode, and icon support.",
6
- "type": "registry:ui",
7
- "meta": {
8
- "library": "@compomo/ui",
9
- "distribution": "npm",
10
- "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/tag",
11
- "consumption": {
12
- "install": "npm install @compomo/ui @ds-mo/tokens @ds-mo/icons",
13
- "cssSetup": "Import tokens CSS at your app entry point: import '@ds-mo/tokens/css';\nThis provides all var(--color-*), var(--dimension-*), var(--effect-*), and var(--typography-*) custom properties.\nFor dark mode, set data-theme=\"dark\" on <html>.",
14
- "import": "import { Tag } from '@compomo/ui';",
15
- "cssImport": "import '@compomo/ui/css';",
16
- "typeImport": "import type { TagProps, TagIntent, TagContrast, TagElevation, TagSize } from '@compomo/ui';",
17
- "iconImport": "import { IconName } from '@ds-mo/icons'; // Tree-shakeable, import only what you need",
18
- "internalDependencies": [
19
- {
20
- "component": "Text",
21
- "note": "Used internally by Tag. No action needed — it's bundled in @compomo/ui."
22
- }
23
- ],
24
- "peerDependencies": {
25
- "required": [
26
- "react >=17",
27
- "react-dom >=17",
28
- "@ds-mo/tokens >=0.1.0"
29
- ],
30
- "optional": [
31
- "@ds-mo/icons >=0.1.0 (for icon props)"
32
- ]
33
- }
34
- },
35
- "props": {
36
- "label": {
37
- "type": "string",
38
- "required": true
39
- },
40
- "intent": {
41
- "type": "'neutral' | 'brand' | 'ai' | 'negative' | 'warning' | 'caution' | 'positive'",
42
- "default": "'neutral'"
43
- },
44
- "contrast": {
45
- "type": "'strong' | 'bold' | 'medium' | 'faint'",
46
- "default": "'faint'"
47
- },
48
- "size": {
49
- "type": "'md' | 'sm' | 'xs'",
50
- "default": "'md'"
51
- },
52
- "rounded": {
53
- "type": "boolean"
54
- },
55
- "icon": {
56
- "type": "IconComponent"
57
- },
58
- "removable": {
59
- "type": "boolean"
60
- },
61
- "onRemove": {
62
- "type": "() => void"
63
- },
64
- "pressed": {
65
- "type": "boolean",
66
- "description": "For filter-chip behavior."
67
- },
68
- "onPressedChange": {
69
- "type": "(pressed: boolean) => void"
70
- },
71
- "onClick": {
72
- "type": "() => void",
73
- "description": "Makes tag clickable."
74
- },
75
- "inactive": {
76
- "type": "boolean"
77
- }
78
- },
79
- "exports": [
80
- "Tag"
81
- ],
82
- "types": [
83
- "TagProps",
84
- "TagIntent",
85
- "TagContrast",
86
- "TagElevation",
87
- "TagSize"
88
- ]
89
- },
90
- "dependencies": [
91
- "@compomo/ui",
92
- "@ds-mo/tokens",
93
- "@ds-mo/icons"
94
- ],
95
- "registryDependencies": [
96
- "text"
97
- ],
98
- "files": [
99
- {
100
- "path": "src/components/Tag/Tag.module.css",
101
- "content": "/* ==========================================================================\n Tag — hover/pressed via direct background-color + color-mix().\n No pseudo-element overlays.\n ========================================================================== */\n\n.tag {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--dimension-radius-050);\n box-sizing: border-box;\n color: var(--color-foreground-primary);\n position: relative;\n\n /* Interaction — ghost defaults */\n --_hover-bg: var(--color-interaction-hover);\n --_pressed-bg: var(--color-interaction-pressed);\n}\n\n/* ==========================================================================\n Sizes\n md 28px — no size-350 token, expressed as 7/2 × base\n sm 20px — size-250\n xs 12px — size-150\n ========================================================================== */\n\n.sizeMd { height: calc(var(--dimension-size-base) * 7 / 2); padding: 0 var(--dimension-space-075); gap: 0; }\n.sizeSm { height: var(--dimension-size-250); padding: 0 var(--dimension-space-050); gap: 0; }\n.sizeXs { height: var(--dimension-size-150); padding: 0 var(--dimension-space-012); gap: 0; }\n\n/* ==========================================================================\n Rounded\n ========================================================================== */\n\n.rounded { border-radius: var(--dimension-radius-half); }\n\n/*\n * Pill padding correction — add space-050 to sides that have no content anchor.\n * Applied by Tag.tsx based on whether a leading icon or trailing remove is present:\n * no leading icon → roundedLeft{Size} (left side is bare label text)\n * no trailing icon → roundedRight{Size} (right side is bare label text)\n * Placed after size rules so same-specificity cascade wins correctly.\n */\n\n/* MD — base: space-075 */\n.roundedLeftMD { padding-left: calc(var(--dimension-space-075) + var(--dimension-space-050)); }\n.roundedRightMD { padding-right: calc(var(--dimension-space-075) + var(--dimension-space-050)); }\n\n/* SM — base: space-050 */\n.roundedLeftSM { padding-left: calc(var(--dimension-space-050) + var(--dimension-space-050)); }\n.roundedRightSM { padding-right: calc(var(--dimension-space-050) + var(--dimension-space-050)); }\n\n/* XS — base: space-012 (1px) */\n.roundedLeftXS { padding-left: calc(var(--dimension-space-012) + var(--dimension-space-050)); }\n.roundedRightXS { padding-right: calc(var(--dimension-space-012) + var(--dimension-space-050)); }\n\n/*\n * Icon-edge padding correction — when an icon (leading or remove) sits on a\n * side, that side's padding should match the top/bottom optical gap:\n * (height − icon_size) / 2\n *\n * md: (28 − 20) / 2 = 4px → space-050\n * sm: (20 − 16) / 2 = 2px → space-025\n * xs: (12 − 12) / 2 = 0px → 0\n *\n * Applied by Tag.tsx: iconLeft when Icon present, iconRight when removable.\n * Placed after size + rounded rules so same-specificity cascade wins.\n */\n.iconLeftMD { padding-left: var(--dimension-space-050); }\n.iconRightMD { padding-right: var(--dimension-space-050); }\n\n.iconLeftSM { padding-left: var(--dimension-space-025); }\n.iconRightSM { padding-right: var(--dimension-space-025); }\n\n.iconLeftXS { padding-left: 0; }\n.iconRightXS { padding-right: 0; }\n\n/* ==========================================================================\n Background context — parent surface awareness\n ========================================================================== */\n\n.onMedium {\n --_hover-bg: var(--color-interaction-on-medium-background-hover);\n --_pressed-bg: var(--color-interaction-on-medium-background-pressed);\n}\n\n.onBold {\n --_hover-bg: var(--color-interaction-on-bold-background-hover);\n --_pressed-bg: var(--color-interaction-on-bold-background-pressed);\n}\n\n.onStrong {\n --_hover-bg: var(--color-interaction-on-strong-background-hover);\n --_pressed-bg: var(--color-interaction-on-strong-background-pressed);\n}\n\n.onAlwaysDark {\n --_hover-bg: var(--color-always-dark-interaction-hover);\n --_pressed-bg: var(--color-always-dark-interaction-pressed);\n}\n\n/* ==========================================================================\n Elevation\n none — filled intent bg, no border, no shadow (default)\n flat — transparent bg + intent-coloured border ring\n elevated — filled intent bg + elevated shadow\n ========================================================================== */\n\n/* elevationNone — no extra chrome needed, intent+contrast classes handle fill */\n\n.elevationFlat {\n background-color: transparent !important;\n box-shadow: inset 0 0 0 var(--dimension-stroke-width-015) currentColor;\n}\n\n/* Flat: no background — use on-surface fg tokens matched to the contrast level.\n The border ring is currentColor so it follows text color automatically.\n 3-class specificity beats the 2-class intent+contrast filled rules above. */\n\n.elevationFlat.intentNeutral.contrastBold { color: var(--color-foreground-bold-neutral); }\n.elevationFlat.intentBrand.contrastBold { color: var(--color-foreground-bold-brand); }\n.elevationFlat.intentAi.contrastBold { color: var(--color-foreground-bold-ai); }\n.elevationFlat.intentNegative.contrastBold { color: var(--color-foreground-bold-negative); }\n.elevationFlat.intentWarning.contrastBold { color: var(--color-foreground-bold-warning); }\n.elevationFlat.intentCaution.contrastBold { color: var(--color-foreground-bold-caution); }\n.elevationFlat.intentPositive.contrastBold { color: var(--color-foreground-bold-positive); }\n\n.elevationFlat.intentNeutral.contrastStrong { color: var(--color-foreground-strong-neutral); }\n.elevationFlat.intentBrand.contrastStrong { color: var(--color-foreground-strong-brand); }\n.elevationFlat.intentAi.contrastStrong { color: var(--color-foreground-strong-ai); }\n.elevationFlat.intentNegative.contrastStrong { color: var(--color-foreground-strong-negative); }\n.elevationFlat.intentWarning.contrastStrong { color: var(--color-foreground-strong-warning); }\n.elevationFlat.intentCaution.contrastStrong { color: var(--color-foreground-strong-caution); }\n.elevationFlat.intentPositive.contrastStrong { color: var(--color-foreground-strong-positive); }\n\n.elevationFlat.intentNeutral.contrastMedium { color: var(--color-foreground-medium-neutral); }\n.elevationFlat.intentBrand.contrastMedium { color: var(--color-foreground-medium-brand); }\n.elevationFlat.intentAi.contrastMedium { color: var(--color-foreground-medium-ai); }\n.elevationFlat.intentNegative.contrastMedium { color: var(--color-foreground-medium-negative); }\n.elevationFlat.intentWarning.contrastMedium { color: var(--color-foreground-medium-warning); }\n.elevationFlat.intentCaution.contrastMedium { color: var(--color-foreground-medium-caution); }\n.elevationFlat.intentPositive.contrastMedium { color: var(--color-foreground-medium-positive); }\n\n.elevationFlat.intentNeutral.contrastFaint { color: var(--color-foreground-faint-neutral); }\n.elevationFlat.intentBrand.contrastFaint { color: var(--color-foreground-faint-brand); }\n.elevationFlat.intentAi.contrastFaint { color: var(--color-foreground-faint-ai); }\n.elevationFlat.intentNegative.contrastFaint { color: var(--color-foreground-faint-negative); }\n.elevationFlat.intentWarning.contrastFaint { color: var(--color-foreground-faint-warning); }\n.elevationFlat.intentCaution.contrastFaint { color: var(--color-foreground-faint-caution); }\n.elevationFlat.intentPositive.contrastFaint { color: var(--color-foreground-faint-positive); }\n\n.elevationElevated { box-shadow: var(--effect-elevation-elevated-sm); }\n\n/* ==========================================================================\n Intent + contrast — strong\n ========================================================================== */\n\n.intentNeutral.contrastStrong { background-color: var(--color-background-strong-neutral); color: var(--color-foreground-medium-neutral); }\n.intentBrand.contrastStrong { background-color: var(--color-background-strong-brand); color: var(--color-foreground-medium-brand); }\n.intentAi.contrastStrong { background-color: var(--color-background-strong-ai); color: var(--color-foreground-medium-ai); }\n.intentNegative.contrastStrong { background-color: var(--color-background-strong-negative); color: var(--color-foreground-medium-negative); }\n.intentWarning.contrastStrong { background-color: var(--color-background-strong-warning); color: var(--color-foreground-medium-warning); }\n.intentCaution.contrastStrong { background-color: var(--color-background-strong-caution); color: var(--color-foreground-medium-caution); }\n.intentPositive.contrastStrong { background-color: var(--color-background-strong-positive); color: var(--color-foreground-medium-positive); }\n\n/* ==========================================================================\n Intent + contrast — bold\n ========================================================================== */\n\n.intentNeutral.contrastBold { background-color: var(--color-background-bold-neutral); color: var(--color-foreground-on-bold-background-primary); }\n.intentBrand.contrastBold { background-color: var(--color-background-bold-brand); color: var(--color-foreground-on-bold-background-primary); }\n.intentAi.contrastBold { background-color: var(--color-background-bold-ai); color: var(--color-foreground-on-bold-background-primary); }\n.intentNegative.contrastBold { background-color: var(--color-background-bold-negative); color: var(--color-foreground-on-bold-background-primary); }\n.intentWarning.contrastBold { background-color: var(--color-background-bold-warning); color: var(--color-foreground-on-bold-background-primary); }\n.intentCaution.contrastBold { background-color: var(--color-background-bold-caution); color: var(--color-foreground-on-bold-background-primary); }\n.intentPositive.contrastBold { background-color: var(--color-background-bold-positive); color: var(--color-foreground-on-bold-background-primary); }\n\n/* ==========================================================================\n Intent + contrast — medium\n ========================================================================== */\n\n.intentNeutral.contrastMedium { background-color: var(--color-background-medium-neutral); color: var(--color-foreground-strong-neutral); }\n.intentBrand.contrastMedium { background-color: var(--color-background-medium-brand); color: var(--color-foreground-strong-brand); }\n.intentAi.contrastMedium { background-color: var(--color-background-medium-ai); color: var(--color-foreground-strong-ai); }\n.intentNegative.contrastMedium { background-color: var(--color-background-medium-negative); color: var(--color-foreground-strong-negative); }\n.intentWarning.contrastMedium { background-color: var(--color-background-medium-warning); color: var(--color-foreground-strong-warning); }\n.intentCaution.contrastMedium { background-color: var(--color-background-medium-caution); color: var(--color-foreground-strong-caution); }\n.intentPositive.contrastMedium { background-color: var(--color-background-medium-positive); color: var(--color-foreground-strong-positive); }\n\n/* ==========================================================================\n Intent + contrast — faint\n ========================================================================== */\n\n.intentNeutral.contrastFaint { background-color: var(--color-background-faint-neutral); color: var(--color-foreground-bold-neutral); }\n.intentBrand.contrastFaint { background-color: var(--color-background-faint-brand); color: var(--color-foreground-bold-brand); }\n.intentAi.contrastFaint { background-color: var(--color-background-faint-ai); color: var(--color-foreground-bold-ai); }\n.intentNegative.contrastFaint { background-color: var(--color-background-faint-negative); color: var(--color-foreground-bold-negative); }\n.intentWarning.contrastFaint { background-color: var(--color-background-faint-warning); color: var(--color-foreground-bold-warning); }\n.intentCaution.contrastFaint { background-color: var(--color-background-faint-caution); color: var(--color-foreground-bold-caution); }\n.intentPositive.contrastFaint { background-color: var(--color-background-faint-positive); color: var(--color-foreground-bold-positive); }\n\n/* ==========================================================================\n Interactive (clickable / filter-chip)\n ========================================================================== */\n\n.interactive {\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n outline: none;\n}\n\n.interactive:hover { background-color: var(--_hover-bg); }\n.interactive:active { background-color: var(--_pressed-bg); }\n\n.interactive:focus-visible {\n outline: var(--dimension-stroke-width-025) solid var(--color-interaction-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n/* ==========================================================================\n Pressed / selected (filter-chip active state)\n Always brand — same language as ToggleButton\n ========================================================================== */\n\n.tag.pressed {\n background-color: var(--color-background-faint-brand) !important;\n color: var(--color-foreground-bold-brand) !important;\n border-color: transparent !important;\n}\n\n/* ==========================================================================\n Remove button — keeps ::before overlay for its own isolated hit area\n ========================================================================== */\n\n.removable { gap: var(--dimension-space-025); }\n.sizeXs.removable { gap: 0; }\n\n.removeButton {\n padding: 0; margin: 0; border: none; background: none;\n display: flex; align-items: center; justify-content: center;\n cursor: pointer; color: inherit; flex-shrink: 0;\n position: relative; border-radius: var(--dimension-radius-050);\n}\n\n.removeButton::before {\n content: ''; position: absolute; inset: -2px;\n border-radius: var(--dimension-radius-025);\n background-color: transparent;\n transition: var(--effect-transition-interaction-background-short-2);\n pointer-events: none;\n}\n\n.removeButton:hover::before { background-color: var(--color-interaction-hover); }\n.removeButton:active::before { background-color: var(--color-interaction-pressed); }\n\n/* SM — 1px gap, inset -1px → 18×18 hover area */\n.sizeSm .removeButton::before { inset: -1px; border-radius: 3px; }\n\n/* XS — flush, inset 0 → 12×12 hover area matching tag radius */\n.sizeXs .removeButton::before { inset: 0; border-radius: var(--dimension-radius-050); }\n\n.rounded .removeButton,\n.rounded .removeButton::before { border-radius: var(--dimension-radius-half); }\n\n/* ==========================================================================\n Disabled\n ========================================================================== */\n\n.inactive { opacity: 0.5; pointer-events: none; cursor: not-allowed; }\n",
102
- "type": "registry:ui"
103
- },
104
- {
105
- "path": "src/components/Tag/Tag.tsx",
106
- "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport { LabelWrap } from '@/components/LabelWrap';\nimport { Cross } from '@ds-mo/icons';\nimport type { IconComponent } from '@/types/icons';\nimport styles from './Tag.module.css';\n\nexport type TagIntent = 'neutral' | 'brand' | 'ai' | 'negative' | 'warning' | 'caution' | 'positive';\nexport type TagContrast = 'strong' | 'bold' | 'medium' | 'faint';\nexport type TagElevation = 'none' | 'flat' | 'elevated';\nexport type TagSize = 'md' | 'sm' | 'xs';\nexport type TagBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';\n\nexport interface TagProps {\n label: string;\n intent?: TagIntent;\n contrast?: TagContrast;\n /**\n * Visual chrome level.\n * none — filled with intent bg, no border, no shadow [default]\n * flat — transparent bg + intent-coloured border ring\n * elevated — filled with intent bg + elevated shadow\n */\n elevation?: TagElevation;\n size?: TagSize;\n rounded?: boolean;\n /** Leading icon component. */\n icon?: IconComponent;\n removable?: boolean;\n onRemove?: () => void;\n /** Override the default Cross remove icon. */\n removeIcon?: IconComponent;\n maxWidth?: string | number;\n inactive?: boolean;\n /** Parent surface context. Adjusts hover tokens for tags on colored backgrounds. */\n background?: TagBackground;\n /** Makes the tag clickable. Pair with pressed/onPressedChange for filter-chip behaviour. */\n onClick?: () => void;\n pressed?: boolean;\n onPressedChange?: (pressed: boolean) => void;\n className?: string;\n}\n\nconst ICON_SIZE: Record<TagSize, number> = { md: 20, sm: 16, xs: 12 };\n\nconst TEXT_STYLE_MAP: Record<TagSize, string> = {\n md: 'text-body-medium',\n sm: 'text-body-small',\n xs: 'text-caption',\n};\n\nexport const Tag = forwardRef<HTMLDivElement, TagProps>(\n (\n {\n label,\n intent = 'neutral',\n contrast = 'faint',\n elevation = 'none',\n size = 'md',\n rounded = false,\n icon: Icon,\n removable = false,\n onRemove,\n removeIcon: RemoveIcon,\n maxWidth,\n inactive = false,\n background,\n onClick,\n pressed,\n onPressedChange,\n className,\n },\n ref\n ) => {\n const isInteractive = !!onClick || !!onPressedChange;\n const hasRemove = removable && !!onRemove;\n const iconSize = ICON_SIZE[size];\n const textStyle = TEXT_STYLE_MAP[size];\n const elevKey = elevation.charAt(0).toUpperCase() + elevation.slice(1);\n const sizeKey = size.toUpperCase() as 'MD' | 'SM' | 'XS';\n\n const classes = cn(\n styles.tag,\n styles[`intent${intent.charAt(0).toUpperCase() + intent.slice(1)}`],\n styles[`contrast${contrast.charAt(0).toUpperCase() + contrast.slice(1)}`],\n styles[`elevation${elevKey}`],\n styles[`size${size.charAt(0).toUpperCase() + size.slice(1)}`],\n rounded && styles.rounded,\n // Pill padding correction — extra space-050 on bare sides (no content anchor)\n rounded && !Icon && (styles as Record<string, string>)[`roundedLeft${sizeKey}`],\n rounded && !hasRemove && (styles as Record<string, string>)[`roundedRight${sizeKey}`],\n // Icon-edge correction — reduce padding to (height − icon) / 2 on icon sides\n !!Icon && (styles as Record<string, string>)[`iconLeft${sizeKey}`],\n hasRemove && (styles as Record<string, string>)[`iconRight${sizeKey}`],\n removable && styles.removable,\n isInteractive && styles.interactive,\n background && background !== 'faint' && styles[\n background === 'always-dark' ? 'onAlwaysDark'\n : `on${background.charAt(0).toUpperCase() + background.slice(1)}`\n ],\n inactive && styles.inactive,\n pressed && styles.pressed,\n className,\n );\n\n const style = maxWidth != null\n ? { maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth }\n : undefined;\n\n const handleInteract = isInteractive && !inactive\n ? () => {\n onPressedChange?.(!pressed);\n onClick?.();\n }\n : undefined;\n\n const handleKeyDown = isInteractive && !inactive\n ? (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onPressedChange?.(!pressed);\n onClick?.();\n }\n }\n : undefined;\n\n return (\n <div\n ref={ref}\n className={classes}\n style={style}\n onClick={handleInteract}\n onKeyDown={handleKeyDown}\n role={isInteractive ? 'button' : undefined}\n tabIndex={isInteractive && !inactive ? 0 : undefined}\n aria-pressed={onPressedChange != null ? pressed : undefined}\n aria-disabled={inactive || undefined}\n >\n {Icon && <Icon size={iconSize} />}\n <LabelWrap size={size}>\n <Text variant={textStyle as never} as=\"span\" color=\"inherit\">\n {label}\n </Text>\n </LabelWrap>\n {removable && onRemove && (\n <button\n type=\"button\"\n className={styles.removeButton}\n onClick={(e) => { e.stopPropagation(); onRemove(); }}\n aria-label={`Remove ${label}`}\n tabIndex={-1}\n >\n {RemoveIcon ? <RemoveIcon size={iconSize} /> : <Cross size={iconSize} />}\n </button>\n )}\n </div>\n );\n }\n);\n\nTag.displayName = 'Tag';\n",
107
- "type": "registry:ui"
108
- }
109
- ]
110
- }
package/dist/r/text.json DELETED
@@ -1,94 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
- "name": "text",
4
- "title": "Text",
5
- "description": "Typography primitive supporting all design-system text variants, colors, truncation, and wrapping.",
6
- "type": "registry:ui",
7
- "meta": {
8
- "library": "@compomo/ui",
9
- "distribution": "npm",
10
- "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/text",
11
- "consumption": {
12
- "install": "npm install @compomo/ui @ds-mo/tokens",
13
- "cssSetup": "Import tokens CSS at your app entry point: import '@ds-mo/tokens/css';\nThis provides all var(--color-*), var(--dimension-*), var(--effect-*), and var(--typography-*) custom properties.\nFor dark mode, set data-theme=\"dark\" on <html>.",
14
- "import": "import { Text } from '@compomo/ui';",
15
- "cssImport": "import '@compomo/ui/css';",
16
- "typeImport": "import type { TextProps, TextVariant, TextStyle, TextColor, TextColorToken, TextDecoration, TextAlign, LineTruncation, TextWrap, TextElement } from '@compomo/ui';",
17
- "peerDependencies": {
18
- "required": [
19
- "react >=17",
20
- "react-dom >=17",
21
- "@ds-mo/tokens >=0.1.0"
22
- ],
23
- "optional": []
24
- }
25
- },
26
- "props": {
27
- "variant": {
28
- "type": "TextVariant",
29
- "default": "'text-body-medium'",
30
- "description": "Typography variant from design tokens."
31
- },
32
- "children": {
33
- "type": "React.ReactNode",
34
- "required": true
35
- },
36
- "color": {
37
- "type": "TextColor",
38
- "description": "Token-based text color."
39
- },
40
- "as": {
41
- "type": "'p' | 'span' | 'div' | 'label' | 'h1'-'h6'",
42
- "default": "'p'"
43
- },
44
- "lineTruncation": {
45
- "type": "1 | 2 | 3 | 4 | 5 | \"none\"",
46
- "default": "'none'"
47
- },
48
- "decoration": {
49
- "type": "'none' | 'underline' | 'dotted-underline'"
50
- },
51
- "italic": {
52
- "type": "boolean"
53
- },
54
- "align": {
55
- "type": "'left' | 'center' | 'right'"
56
- },
57
- "wrap": {
58
- "type": "'wrap' | 'nowrap' | 'balance' | 'pretty'"
59
- }
60
- },
61
- "exports": [
62
- "Text"
63
- ],
64
- "types": [
65
- "TextProps",
66
- "TextVariant",
67
- "TextStyle",
68
- "TextColor",
69
- "TextColorToken",
70
- "TextDecoration",
71
- "TextAlign",
72
- "LineTruncation",
73
- "TextWrap",
74
- "TextElement"
75
- ]
76
- },
77
- "dependencies": [
78
- "@compomo/ui",
79
- "@ds-mo/tokens"
80
- ],
81
- "registryDependencies": [],
82
- "files": [
83
- {
84
- "path": "src/components/Text/Text.module.css",
85
- "content": ".text {\n margin: 0;\n}\n\n/* ============================================\n LINE TRUNCATION\n ============================================ */\n\n.truncate1Line {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.truncate2Lines {\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n\n.truncate3Lines {\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n\n.truncate4Lines {\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n\n.truncate5Lines {\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 5;\n -webkit-box-orient: vertical;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n\n.noTruncation {\n word-break: break-word;\n white-space: normal;\n}\n\n.wrapNowrap {\n white-space: nowrap;\n word-break: normal;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.wrapBalance {\n text-wrap: balance;\n}\n\n.wrapPretty {\n text-wrap: pretty;\n}\n\n/* ============================================\n TEXT COLOR - Semantic Tokens\n ============================================ */\n\n.colorPrimary {\n color: var(--color-foreground-primary);\n}\n\n.colorSecondary {\n color: var(--color-foreground-secondary);\n}\n\n.colorTertiary {\n color: var(--color-foreground-tertiary);\n}\n\n.colorBrand {\n color: var(--color-foreground-bold-brand);\n}\n\n.colorNegative {\n color: var(--color-foreground-bold-negative);\n}\n\n.colorPositive {\n color: var(--color-foreground-bold-positive);\n}\n\n.colorWarning {\n color: var(--color-foreground-bold-warning);\n}\n\n.colorCaution {\n color: var(--color-foreground-bold-caution);\n}\n\n.colorAi {\n color: var(--color-foreground-bold-ai);\n}\n\n.colorOnStrong {\n color: var(--color-foreground-on-strong-background-primary);\n}\n\n.colorOnBold {\n color: var(--color-foreground-on-bold-background-primary);\n}\n\n.colorInherit {\n color: inherit;\n}\n\n/* ============================================\n TEXT DECORATION\n ============================================ */\n\n.decorationNone {\n text-decoration: none;\n}\n\n.decorationUnderline {\n text-decoration: underline;\n text-underline-offset: 2px;\n text-decoration-thickness: 1px;\n}\n\n.decorationDottedUnderline {\n text-decoration: underline dotted;\n text-underline-offset: 2px;\n text-decoration-thickness: 1px;\n}\n\n/* ============================================\n FONT STYLE\n ============================================ */\n\n.italic {\n font-style: italic;\n}\n\n/* ============================================\n TEXT ALIGNMENT\n ============================================ */\n\n.alignLeft {\n text-align: left;\n}\n\n.alignCenter {\n text-align: center;\n}\n\n.alignRight {\n text-align: right;\n}\n",
86
- "type": "registry:ui"
87
- },
88
- {
89
- "path": "src/components/Text/Text.tsx",
90
- "content": "import React, { forwardRef } from 'react';\nimport styles from './Text.module.css';\n\n/**\n * Text variant options.\n * Each variant maps to a TokoMo typography class with predefined font-size, line-height,\n * font-weight, and letter-spacing.\n */\nexport type TextVariant =\n | 'text-display-medium'\n | 'text-display-small'\n | 'text-title-large'\n | 'text-title-medium'\n | 'text-title-small'\n | 'text-body-large'\n | 'text-body-large-emphasis'\n | 'text-body-medium'\n | 'text-body-medium-emphasis'\n | 'text-body-small'\n | 'text-body-small-emphasis'\n | 'text-caption'\n | 'text-caption-emphasis';\n\n/** @deprecated Use `TextVariant` instead. */\nexport type TextStyle = TextVariant;\n\n/**\n * Semantic color tokens for text.\n * Maps to TokoMo --color-foreground-* CSS custom properties.\n */\nexport type TextColorToken =\n | 'primary'\n | 'secondary'\n | 'tertiary'\n | 'brand'\n | 'negative'\n | 'positive'\n | 'warning'\n | 'caution'\n | 'ai'\n | 'on-strong'\n | 'on-bold'\n | 'inherit';\n\n/** Text color — semantic token or CSS variable escape hatch. */\nexport type TextColor = TextColorToken | `var(--${string})`;\n\nexport type TextDecoration = 'none' | 'underline' | 'dotted-underline';\nexport type TextAlign = 'left' | 'center' | 'right';\nexport type LineTruncation = 1 | 2 | 3 | 4 | 5 | 'none';\nexport type TextWrap = 'wrap' | 'nowrap' | 'balance' | 'pretty';\nexport type TextElement = 'p' | 'span' | 'div' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n\nexport interface TextProps {\n /** Typography variant. Maps to a TokoMo typography class. Defaults to 'text-body-medium'. */\n variant?: TextVariant;\n children: React.ReactNode;\n\n // Appearance\n color?: TextColor;\n decoration?: TextDecoration;\n italic?: boolean;\n align?: TextAlign;\n\n // Truncation / wrap\n /** Max lines before ellipsis. Ignored when wrap is 'nowrap'. Defaults to 'none'. */\n lineTruncation?: LineTruncation;\n /** 'nowrap' = single line, truncates with ellipsis when constrained. */\n wrap?: TextWrap;\n\n // Semantic HTML\n as?: TextElement;\n id?: string;\n htmlFor?: string;\n\n // Escape hatches\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst colorClassMap: Record<TextColorToken, string> = {\n primary: styles.colorPrimary,\n secondary: styles.colorSecondary,\n tertiary: styles.colorTertiary,\n brand: styles.colorBrand,\n negative: styles.colorNegative,\n positive: styles.colorPositive,\n warning: styles.colorWarning,\n caution: styles.colorCaution,\n ai: styles.colorAi,\n 'on-strong': styles.colorOnStrong,\n 'on-bold': styles.colorOnBold,\n inherit: styles.colorInherit,\n};\n\nconst decorationClassMap: Record<TextDecoration, string> = {\n none: styles.decorationNone,\n underline: styles.decorationUnderline,\n 'dotted-underline': styles.decorationDottedUnderline,\n};\n\nconst alignClassMap: Record<TextAlign, string> = {\n left: styles.alignLeft,\n center: styles.alignCenter,\n right: styles.alignRight,\n};\n\nconst truncationClassMap: Record<LineTruncation, string> = {\n 1: styles.truncate1Line,\n 2: styles.truncate2Lines,\n 3: styles.truncate3Lines,\n 4: styles.truncate4Lines,\n 5: styles.truncate5Lines,\n none: styles.noTruncation,\n};\n\nconst isCustomColor = (color: TextColor): color is `var(--${string})` =>\n color.startsWith('var(--');\n\nexport const Text = forwardRef<HTMLElement, TextProps>(\n (\n {\n variant = 'text-body-medium',\n children,\n color,\n decoration,\n italic,\n align,\n lineTruncation = 'none',\n wrap,\n as: Component = 'p',\n id,\n htmlFor,\n className = '',\n style,\n },\n ref\n ) => {\n const wrapClass =\n wrap === 'nowrap' ? styles.wrapNowrap\n : wrap === 'balance' ? styles.wrapBalance\n : wrap === 'pretty' ? styles.wrapPretty\n : '';\n const truncationClass =\n wrap === 'nowrap' ? '' : truncationClassMap[lineTruncation];\n\n const classes = [\n variant,\n styles.text,\n wrapClass,\n truncationClass,\n color && !isCustomColor(color) ? colorClassMap[color] : '',\n decoration ? decorationClassMap[decoration] : '',\n italic ? styles.italic : '',\n align ? alignClassMap[align] : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const computedStyle: React.CSSProperties = {\n ...style,\n ...(color && isCustomColor(color) ? { color } : {}),\n };\n\n const props: React.HTMLAttributes<HTMLElement> & { htmlFor?: string } = {\n className: classes,\n style: Object.keys(computedStyle).length > 0 ? computedStyle : undefined,\n ...(id ? { id } : {}),\n ...(Component === 'label' && htmlFor ? { htmlFor } : {}),\n };\n\n return (\n <Component ref={ref as React.Ref<never>} {...props}>\n {children}\n </Component>\n );\n }\n);\n\nText.displayName = 'Text';\n",
91
- "type": "registry:ui"
92
- }
93
- ]
94
- }