@ds-mo/ui 0.1.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 (213) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/index.css +1 -0
  4. package/dist/index.d.ts +969 -0
  5. package/dist/index.js +2623 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/r/accordion.json +79 -0
  8. package/dist/r/badge.json +69 -0
  9. package/dist/r/banner.json +90 -0
  10. package/dist/r/breadcrumb.json +70 -0
  11. package/dist/r/button-group.json +65 -0
  12. package/dist/r/button.json +137 -0
  13. package/dist/r/card.json +82 -0
  14. package/dist/r/checkbox.json +91 -0
  15. package/dist/r/divider.json +57 -0
  16. package/dist/r/empty-state.json +69 -0
  17. package/dist/r/error-boundary.json +66 -0
  18. package/dist/r/fade.json +65 -0
  19. package/dist/r/field.json +71 -0
  20. package/dist/r/header.json +67 -0
  21. package/dist/r/input.json +77 -0
  22. package/dist/r/loader.json +54 -0
  23. package/dist/r/menu.json +130 -0
  24. package/dist/r/modal.json +93 -0
  25. package/dist/r/pagination.json +80 -0
  26. package/dist/r/radio.json +85 -0
  27. package/dist/r/registry.json +1600 -0
  28. package/dist/r/scrollbar.json +68 -0
  29. package/dist/r/select.json +93 -0
  30. package/dist/r/sidebar.json +105 -0
  31. package/dist/r/skeleton.json +72 -0
  32. package/dist/r/slider.json +87 -0
  33. package/dist/r/surface.json +97 -0
  34. package/dist/r/tab-group.json +72 -0
  35. package/dist/r/tab.json +71 -0
  36. package/dist/r/table.json +110 -0
  37. package/dist/r/tag.json +110 -0
  38. package/dist/r/text.json +94 -0
  39. package/dist/r/toast.json +77 -0
  40. package/dist/r/toggle-button-group.json +65 -0
  41. package/dist/r/toggle-button.json +94 -0
  42. package/dist/r/toggle.json +65 -0
  43. package/dist/r/tooltip.json +86 -0
  44. package/package.json +80 -0
  45. package/src/components/Accordion/Accordion.module.css +66 -0
  46. package/src/components/Accordion/Accordion.stories.tsx +95 -0
  47. package/src/components/Accordion/Accordion.tsx +122 -0
  48. package/src/components/Accordion/index.ts +2 -0
  49. package/src/components/Badge/Badge.module.css +6 -0
  50. package/src/components/Badge/Badge.stories.tsx +99 -0
  51. package/src/components/Badge/Badge.tsx +23 -0
  52. package/src/components/Badge/index.ts +2 -0
  53. package/src/components/Banner/Banner.module.css +67 -0
  54. package/src/components/Banner/Banner.stories.tsx +81 -0
  55. package/src/components/Banner/Banner.tsx +109 -0
  56. package/src/components/Banner/index.ts +2 -0
  57. package/src/components/Breadcrumb/Breadcrumb.module.css +46 -0
  58. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +72 -0
  59. package/src/components/Breadcrumb/Breadcrumb.tsx +68 -0
  60. package/src/components/Breadcrumb/index.ts +2 -0
  61. package/src/components/Button/Button.module.css +343 -0
  62. package/src/components/Button/Button.stories.tsx +575 -0
  63. package/src/components/Button/Button.tsx +201 -0
  64. package/src/components/Button/index.ts +10 -0
  65. package/src/components/ButtonGroup/ButtonGroup.module.css +157 -0
  66. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +384 -0
  67. package/src/components/ButtonGroup/ButtonGroup.tsx +122 -0
  68. package/src/components/ButtonGroup/index.ts +2 -0
  69. package/src/components/Card/Card.module.css +36 -0
  70. package/src/components/Card/Card.stories.tsx +78 -0
  71. package/src/components/Card/Card.tsx +53 -0
  72. package/src/components/Card/index.ts +2 -0
  73. package/src/components/Checkbox/Checkbox.module.css +47 -0
  74. package/src/components/Checkbox/Checkbox.stories.tsx +129 -0
  75. package/src/components/Checkbox/Checkbox.tsx +68 -0
  76. package/src/components/Checkbox/index.ts +2 -0
  77. package/src/components/Divider/Divider.module.css +19 -0
  78. package/src/components/Divider/Divider.stories.tsx +55 -0
  79. package/src/components/Divider/Divider.tsx +28 -0
  80. package/src/components/Divider/index.ts +2 -0
  81. package/src/components/EmptyState/EmptyState.module.css +8 -0
  82. package/src/components/EmptyState/EmptyState.stories.tsx +53 -0
  83. package/src/components/EmptyState/EmptyState.tsx +31 -0
  84. package/src/components/EmptyState/index.ts +2 -0
  85. package/src/components/ErrorBoundary/ErrorBoundary.module.css +18 -0
  86. package/src/components/ErrorBoundary/ErrorBoundary.stories.tsx +38 -0
  87. package/src/components/ErrorBoundary/ErrorBoundary.tsx +50 -0
  88. package/src/components/ErrorBoundary/index.ts +2 -0
  89. package/src/components/Fade/Fade.module.css +31 -0
  90. package/src/components/Fade/Fade.stories.tsx +35 -0
  91. package/src/components/Fade/Fade.tsx +33 -0
  92. package/src/components/Fade/index.ts +2 -0
  93. package/src/components/Field/Field.module.css +5 -0
  94. package/src/components/Field/Field.stories.tsx +111 -0
  95. package/src/components/Field/Field.tsx +22 -0
  96. package/src/components/Field/index.ts +2 -0
  97. package/src/components/Header/Header.module.css +33 -0
  98. package/src/components/Header/Header.stories.tsx +52 -0
  99. package/src/components/Header/Header.tsx +42 -0
  100. package/src/components/Header/index.ts +2 -0
  101. package/src/components/Input/Input.module.css +71 -0
  102. package/src/components/Input/Input.stories.tsx +135 -0
  103. package/src/components/Input/Input.tsx +76 -0
  104. package/src/components/Input/index.ts +2 -0
  105. package/src/components/LabelWrap/LabelWrap.module.css +34 -0
  106. package/src/components/LabelWrap/LabelWrap.tsx +32 -0
  107. package/src/components/LabelWrap/index.ts +1 -0
  108. package/src/components/Loader/Loader.module.css +9 -0
  109. package/src/components/Loader/Loader.stories.tsx +44 -0
  110. package/src/components/Loader/Loader.tsx +43 -0
  111. package/src/components/Loader/index.ts +2 -0
  112. package/src/components/Menu/DestructiveMenuItem.module.css +57 -0
  113. package/src/components/Menu/DestructiveMenuItem.tsx +64 -0
  114. package/src/components/Menu/Menu.module.css +49 -0
  115. package/src/components/Menu/Menu.stories.tsx +129 -0
  116. package/src/components/Menu/Menu.tsx +269 -0
  117. package/src/components/Menu/MenuItem.module.css +84 -0
  118. package/src/components/Menu/MenuItem.tsx +101 -0
  119. package/src/components/Menu/index.ts +6 -0
  120. package/src/components/Modal/Modal.module.css +67 -0
  121. package/src/components/Modal/Modal.stories.tsx +71 -0
  122. package/src/components/Modal/Modal.tsx +122 -0
  123. package/src/components/Modal/index.ts +2 -0
  124. package/src/components/Pagination/Pagination.module.css +64 -0
  125. package/src/components/Pagination/Pagination.stories.tsx +51 -0
  126. package/src/components/Pagination/Pagination.tsx +103 -0
  127. package/src/components/Pagination/index.ts +2 -0
  128. package/src/components/Radio/Radio.module.css +61 -0
  129. package/src/components/Radio/Radio.stories.tsx +101 -0
  130. package/src/components/Radio/Radio.tsx +108 -0
  131. package/src/components/Radio/index.ts +2 -0
  132. package/src/components/Scrollbar/Scrollbar.module.css +81 -0
  133. package/src/components/Scrollbar/Scrollbar.stories.tsx +46 -0
  134. package/src/components/Scrollbar/Scrollbar.tsx +187 -0
  135. package/src/components/Scrollbar/index.ts +2 -0
  136. package/src/components/Select/Select.module.css +31 -0
  137. package/src/components/Select/Select.stories.tsx +59 -0
  138. package/src/components/Select/Select.tsx +92 -0
  139. package/src/components/Select/index.ts +2 -0
  140. package/src/components/Sidebar/Sidebar.module.css +161 -0
  141. package/src/components/Sidebar/Sidebar.stories.tsx +125 -0
  142. package/src/components/Sidebar/Sidebar.tsx +129 -0
  143. package/src/components/Sidebar/SidebarItem.tsx +57 -0
  144. package/src/components/Sidebar/SidebarSection.tsx +42 -0
  145. package/src/components/Sidebar/index.ts +6 -0
  146. package/src/components/Skeleton/Skeleton.module.css +53 -0
  147. package/src/components/Skeleton/Skeleton.stories.tsx +89 -0
  148. package/src/components/Skeleton/Skeleton.tsx +66 -0
  149. package/src/components/Skeleton/index.ts +2 -0
  150. package/src/components/Slider/Slider.module.css +62 -0
  151. package/src/components/Slider/Slider.stories.tsx +120 -0
  152. package/src/components/Slider/Slider.tsx +74 -0
  153. package/src/components/Slider/index.ts +2 -0
  154. package/src/components/Surface/Surface.module.css +222 -0
  155. package/src/components/Surface/Surface.stories.tsx +213 -0
  156. package/src/components/Surface/Surface.tsx +219 -0
  157. package/src/components/Surface/index.ts +12 -0
  158. package/src/components/Tab/Tab.module.css +66 -0
  159. package/src/components/Tab/Tab.stories.tsx +103 -0
  160. package/src/components/Tab/Tab.tsx +41 -0
  161. package/src/components/Tab/index.ts +2 -0
  162. package/src/components/TabGroup/TabGroup.module.css +26 -0
  163. package/src/components/TabGroup/TabGroup.stories.tsx +60 -0
  164. package/src/components/TabGroup/TabGroup.tsx +83 -0
  165. package/src/components/TabGroup/index.ts +2 -0
  166. package/src/components/Table/Table.module.css +130 -0
  167. package/src/components/Table/Table.stories.tsx +111 -0
  168. package/src/components/Table/Table.tsx +226 -0
  169. package/src/components/Table/index.ts +11 -0
  170. package/src/components/Tag/Tag.module.css +270 -0
  171. package/src/components/Tag/Tag.stories.tsx +399 -0
  172. package/src/components/Tag/Tag.tsx +162 -0
  173. package/src/components/Tag/index.ts +2 -0
  174. package/src/components/Text/Text.module.css +166 -0
  175. package/src/components/Text/Text.stories.tsx +212 -0
  176. package/src/components/Text/Text.tsx +181 -0
  177. package/src/components/Text/index.ts +13 -0
  178. package/src/components/Toast/Toast.module.css +91 -0
  179. package/src/components/Toast/Toast.stories.tsx +66 -0
  180. package/src/components/Toast/Toast.tsx +182 -0
  181. package/src/components/Toast/index.ts +8 -0
  182. package/src/components/Toggle/Toggle.module.css +87 -0
  183. package/src/components/Toggle/Toggle.stories.tsx +85 -0
  184. package/src/components/Toggle/Toggle.tsx +52 -0
  185. package/src/components/Toggle/index.ts +2 -0
  186. package/src/components/ToggleButton/ToggleButton.module.css +172 -0
  187. package/src/components/ToggleButton/ToggleButton.stories.tsx +299 -0
  188. package/src/components/ToggleButton/ToggleButton.tsx +118 -0
  189. package/src/components/ToggleButton/index.ts +2 -0
  190. package/src/components/ToggleButtonGroup/ToggleButtonGroup.module.css +163 -0
  191. package/src/components/ToggleButtonGroup/ToggleButtonGroup.stories.tsx +341 -0
  192. package/src/components/ToggleButtonGroup/ToggleButtonGroup.tsx +111 -0
  193. package/src/components/ToggleButtonGroup/index.ts +2 -0
  194. package/src/components/Tooltip/Tooltip.module.css +45 -0
  195. package/src/components/Tooltip/Tooltip.stories.tsx +46 -0
  196. package/src/components/Tooltip/Tooltip.tsx +224 -0
  197. package/src/components/Tooltip/index.ts +2 -0
  198. package/src/css-modules.d.ts +4 -0
  199. package/src/docs/ColorUsage.mdx +195 -0
  200. package/src/docs/ElevationUsage.mdx +95 -0
  201. package/src/docs/Introduction.mdx +97 -0
  202. package/src/docs/OpticalSizing.mdx +178 -0
  203. package/src/docs/TypographyUsage.mdx +121 -0
  204. package/src/index.ts +154 -0
  205. package/src/stories/Colors.stories.tsx +528 -0
  206. package/src/stories/Dimensions.stories.tsx +200 -0
  207. package/src/stories/Effects.stories.tsx +231 -0
  208. package/src/stories/Icons.stories.tsx +159 -0
  209. package/src/stories/Typography.stories.tsx +157 -0
  210. package/src/types/icons.ts +15 -0
  211. package/src/types/index.ts +1 -0
  212. package/src/utils/cn.ts +6 -0
  213. package/src/utils/css-tokens.ts +22 -0
@@ -0,0 +1,82 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "card",
4
+ "title": "Card",
5
+ "description": "Content container with header, body, and footer sections. Supports elevation and radius presets.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/card",
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 { Card } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { CardProps, CardElevation, CardRadius } from '@compomo/ui';",
17
+ "internalDependencies": [
18
+ {
19
+ "component": "Surface",
20
+ "note": "Used internally by Card. 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
+ "children": {
34
+ "type": "React.ReactNode",
35
+ "required": true
36
+ },
37
+ "header": {
38
+ "type": "React.ReactNode",
39
+ "description": "Rendered with a bottom divider."
40
+ },
41
+ "footer": {
42
+ "type": "React.ReactNode",
43
+ "description": "Rendered with a top divider."
44
+ },
45
+ "elevation": {
46
+ "type": "'flat' | 'elevated' | 'floating'",
47
+ "default": "'elevated'"
48
+ },
49
+ "radius": {
50
+ "type": "'sm' | 'md' | 'lg' | 'xl'",
51
+ "default": "'lg'"
52
+ }
53
+ },
54
+ "exports": [
55
+ "Card"
56
+ ],
57
+ "types": [
58
+ "CardProps",
59
+ "CardElevation",
60
+ "CardRadius"
61
+ ]
62
+ },
63
+ "dependencies": [
64
+ "@compomo/ui",
65
+ "@ds-mo/tokens"
66
+ ],
67
+ "registryDependencies": [
68
+ "surface"
69
+ ],
70
+ "files": [
71
+ {
72
+ "path": "src/components/Card/Card.module.css",
73
+ "content": "/**\n * Card — structured container with optional header/footer.\n * Uses TokoMo tokens directly (not built on Surface).\n */\n\n.card {\n box-sizing: border-box;\n background-color: var(--color-background-primary);\n overflow: hidden;\n}\n\n/* Elevation */\n.elevationFlat { box-shadow: var(--effect-elevation-elevated-none); }\n.elevationElevated { box-shadow: var(--effect-elevation-elevated-sm); }\n.elevationFloating { box-shadow: var(--effect-elevation-elevated-floating); }\n\n/* Radius */\n.radiusSm { border-radius: var(--dimension-radius-075); }\n.radiusMd { border-radius: var(--dimension-radius-100); }\n.radiusLg { border-radius: var(--dimension-radius-125); }\n.radiusXl { border-radius: var(--dimension-radius-175); }\n\n/* Sections */\n.header {\n padding: var(--dimension-space-150) var(--dimension-space-200);\n border-bottom: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n}\n\n.body {\n padding: var(--dimension-space-200);\n}\n\n.footer {\n padding: var(--dimension-space-150) var(--dimension-space-200);\n border-top: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n}\n",
74
+ "type": "registry:ui"
75
+ },
76
+ {
77
+ "path": "src/components/Card/Card.tsx",
78
+ "content": "import React, { forwardRef } from 'react';\nimport styles from './Card.module.css';\nimport { cn } from '@/utils/cn';\n\nexport type CardElevation = 'flat' | 'elevated' | 'floating';\nexport type CardRadius = 'sm' | 'md' | 'lg' | 'xl';\n\nexport interface CardProps {\n children: React.ReactNode;\n /** Optional header content — rendered with a bottom divider. */\n header?: React.ReactNode;\n /** Optional footer content — rendered with a top divider. */\n footer?: React.ReactNode;\n /** Elevation level. Defaults to 'elevated'. */\n elevation?: CardElevation;\n /** Corner radius. Defaults to 'lg'. */\n radius?: CardRadius;\n /** Additional CSS classes. */\n className?: string;\n /** Inline styles. */\n style?: React.CSSProperties;\n}\n\nconst elevationClassMap: Record<CardElevation, string> = {\n flat: styles.elevationFlat,\n elevated: styles.elevationElevated,\n floating: styles.elevationFloating,\n};\n\nconst radiusClassMap: Record<CardRadius, string> = {\n sm: styles.radiusSm,\n md: styles.radiusMd,\n lg: styles.radiusLg,\n xl: styles.radiusXl,\n};\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(\n ({ children, header, footer, elevation = 'elevated', radius = 'lg', className, style }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(styles.card, elevationClassMap[elevation], radiusClassMap[radius], className)}\n style={style}\n >\n {header && <div className={styles.header}>{header}</div>}\n <div className={styles.body}>{children}</div>\n {footer && <div className={styles.footer}>{footer}</div>}\n </div>\n );\n }\n);\n\nCard.displayName = 'Card';\n",
79
+ "type": "registry:ui"
80
+ }
81
+ ]
82
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "checkbox",
4
+ "title": "Checkbox",
5
+ "description": "Three-state checkbox (checked, unchecked, indeterminate) with keyboard support and custom icon slots.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/checkbox",
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 { Checkbox } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { CheckboxProps } 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 Checkbox. 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
+ "checked": {
41
+ "type": "boolean",
42
+ "default": "false"
43
+ },
44
+ "indeterminate": {
45
+ "type": "boolean",
46
+ "default": "false"
47
+ },
48
+ "onChange": {
49
+ "type": "(checked: boolean) => void"
50
+ },
51
+ "inactive": {
52
+ "type": "boolean"
53
+ },
54
+ "checkedIcon": {
55
+ "type": "IconComponent"
56
+ },
57
+ "uncheckedIcon": {
58
+ "type": "IconComponent"
59
+ },
60
+ "indeterminateIcon": {
61
+ "type": "IconComponent"
62
+ }
63
+ },
64
+ "exports": [
65
+ "Checkbox"
66
+ ],
67
+ "types": [
68
+ "CheckboxProps"
69
+ ]
70
+ },
71
+ "dependencies": [
72
+ "@compomo/ui",
73
+ "@ds-mo/tokens",
74
+ "@ds-mo/icons"
75
+ ],
76
+ "registryDependencies": [
77
+ "text"
78
+ ],
79
+ "files": [
80
+ {
81
+ "path": "src/components/Checkbox/Checkbox.module.css",
82
+ "content": ".checkbox {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-075);\n height: var(--dimension-size-400);\n box-sizing: border-box;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n border-radius: var(--dimension-radius-075);\n transition: background-color var(--effect-motion-short-2);\n}\n\n.checkbox:hover { background-color: var(--color-interaction-hover); }\n.checkbox:active { background-color: var(--color-interaction-pressed); }\n\n.inactive {\n cursor: not-allowed;\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* Fallback checkbox box (when no icon components provided) */\n.box {\n width: 20px;\n height: 20px;\n border: 1.5px solid var(--color-foreground-secondary);\n border-radius: var(--dimension-radius-050);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all var(--effect-motion-short-2);\n}\n\n.boxChecked {\n background-color: var(--color-foreground-primary);\n border-color: var(--color-foreground-primary);\n}\n\n.checkmark {\n color: var(--color-foreground-on-bold-background-primary);\n font-size: 14px;\n line-height: 1;\n font-weight: 700;\n}\n",
83
+ "type": "registry:ui"
84
+ },
85
+ {
86
+ "path": "src/components/Checkbox/Checkbox.tsx",
87
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport type { IconComponent } from '@/types/icons';\nimport styles from './Checkbox.module.css';\n\nexport interface CheckboxProps {\n label: string;\n checked?: boolean;\n indeterminate?: boolean;\n onChange?: (checked: boolean) => void;\n inactive?: boolean;\n className?: string;\n /** Icon for checked state. */\n checkedIcon?: IconComponent;\n /** Icon for unchecked state. */\n uncheckedIcon?: IconComponent;\n /** Icon for indeterminate state. */\n indeterminateIcon?: IconComponent;\n}\n\nexport const Checkbox = forwardRef<HTMLDivElement, CheckboxProps>(\n (\n {\n label,\n checked = false,\n indeterminate = false,\n onChange,\n inactive = false,\n className,\n checkedIcon: CheckedIcon,\n uncheckedIcon: UncheckedIcon,\n indeterminateIcon: IndeterminateIcon,\n },\n ref\n ) => {\n const handleClick = () => {\n if (!inactive) onChange?.(!checked);\n };\n\n const iconColor = indeterminate || checked ? 'var(--color-foreground-primary)' : 'var(--color-foreground-secondary)';\n const Icon = indeterminate ? IndeterminateIcon : checked ? CheckedIcon : UncheckedIcon;\n\n return (\n <div\n ref={ref}\n role=\"checkbox\"\n aria-checked={indeterminate ? 'mixed' : checked}\n aria-inactive={inactive}\n tabIndex={inactive ? -1 : 0}\n className={cn(styles.checkbox, inactive && styles.inactive, className)}\n onClick={handleClick}\n onKeyDown={e => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); handleClick(); } }}\n >\n {Icon ? <Icon size={20} color={iconColor} /> : (\n <span className={cn(styles.box, (checked || indeterminate) && styles.boxChecked)}>\n {(checked || indeterminate) && <span className={styles.checkmark}>{indeterminate ? '−' : '✓'}</span>}\n </span>\n )}\n <Text variant=\"text-body-medium\" as=\"span\" color=\"inherit\">\n {label}\n </Text>\n </div>\n );\n }\n);\n\nCheckbox.displayName = 'Checkbox';\n",
88
+ "type": "registry:ui"
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "divider",
4
+ "title": "Divider",
5
+ "description": "Horizontal or vertical separator line using design tokens.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/divider",
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 { Divider } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { DividerProps, DividerOrientation } 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
+ "orientation": {
28
+ "type": "'horizontal' | 'vertical'",
29
+ "default": "'horizontal'"
30
+ }
31
+ },
32
+ "exports": [
33
+ "Divider"
34
+ ],
35
+ "types": [
36
+ "DividerProps",
37
+ "DividerOrientation"
38
+ ]
39
+ },
40
+ "dependencies": [
41
+ "@compomo/ui",
42
+ "@ds-mo/tokens"
43
+ ],
44
+ "registryDependencies": [],
45
+ "files": [
46
+ {
47
+ "path": "src/components/Divider/Divider.module.css",
48
+ "content": ".divider {\n border: none;\n margin: 0;\n flex-shrink: 0;\n background-color: var(--color-border-secondary);\n}\n\n/* Horizontal (default) */\n.divider:not(.vertical) {\n width: 100%;\n height: 1px;\n}\n\n/* Vertical */\n.vertical {\n width: 1px;\n height: 100%;\n align-self: stretch;\n}\n",
49
+ "type": "registry:ui"
50
+ },
51
+ {
52
+ "path": "src/components/Divider/Divider.tsx",
53
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport styles from './Divider.module.css';\n\nexport type DividerOrientation = 'horizontal' | 'vertical';\n\nexport interface DividerProps {\n /** Direction of the divider line. */\n orientation?: DividerOrientation;\n className?: string;\n}\n\nexport const Divider = forwardRef<HTMLHRElement, DividerProps>(\n ({ orientation = 'horizontal', className }, ref) => (\n <hr\n ref={ref}\n role=\"separator\"\n aria-orientation={orientation}\n className={cn(\n styles.divider,\n orientation === 'vertical' && styles.vertical,\n className\n )}\n />\n )\n);\n\nDivider.displayName = 'Divider';\n",
54
+ "type": "registry:ui"
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "empty-state",
4
+ "title": "EmptyState",
5
+ "description": "Centered placeholder for empty content, no results, or no access states.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/empty-state",
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 { EmptyState } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { EmptyStateProps, EmptyStateType } from '@compomo/ui';",
17
+ "internalDependencies": [
18
+ {
19
+ "component": "Text",
20
+ "note": "Used internally by EmptyState. 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
+ "type": {
34
+ "type": "'no-content' | 'no-results' | 'no-results-filter' | 'no-access'",
35
+ "default": "'no-content'"
36
+ },
37
+ "message": {
38
+ "type": "string",
39
+ "description": "Overrides default message."
40
+ }
41
+ },
42
+ "exports": [
43
+ "EmptyState"
44
+ ],
45
+ "types": [
46
+ "EmptyStateProps",
47
+ "EmptyStateType"
48
+ ]
49
+ },
50
+ "dependencies": [
51
+ "@compomo/ui",
52
+ "@ds-mo/tokens"
53
+ ],
54
+ "registryDependencies": [
55
+ "text"
56
+ ],
57
+ "files": [
58
+ {
59
+ "path": "src/components/EmptyState/EmptyState.module.css",
60
+ "content": ".emptyState {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 400px;\n width: 100%;\n}\n",
61
+ "type": "registry:ui"
62
+ },
63
+ {
64
+ "path": "src/components/EmptyState/EmptyState.tsx",
65
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './EmptyState.module.css';\n\nexport type EmptyStateType = 'no-content' | 'no-results' | 'no-results-filter' | 'no-access';\n\nconst defaultMessages: Record<EmptyStateType, string> = {\n 'no-content': 'No page contents to display.',\n 'no-results': 'No results found.',\n 'no-results-filter': 'No results found. Please update search criteria.',\n 'no-access': \"You don't have access to this page.\",\n};\n\nexport interface EmptyStateProps {\n type?: EmptyStateType;\n message?: string;\n className?: string;\n}\n\nexport const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(\n ({ type = 'no-content', message, className }, ref) => (\n <div ref={ref} className={cn(styles.emptyState, className)}>\n <Text variant=\"text-body-medium\" as=\"p\" color=\"secondary\">\n {message || defaultMessages[type]}\n </Text>\n </div>\n )\n);\n\nEmptyState.displayName = 'EmptyState';\n",
66
+ "type": "registry:ui"
67
+ }
68
+ ]
69
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "error-boundary",
4
+ "title": "ErrorBoundary",
5
+ "description": "React error boundary with fallback UI and console logging.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/error-boundary",
11
+ "consumption": {
12
+ "install": "npm install @compomo/ui",
13
+ "import": "import { ErrorBoundary } from '@compomo/ui';",
14
+ "cssImport": "import '@compomo/ui/css';",
15
+ "typeImport": "import type { ErrorBoundaryProps } from '@compomo/ui';",
16
+ "internalDependencies": [
17
+ {
18
+ "component": "EmptyState",
19
+ "note": "Used internally by ErrorBoundary. No action needed — it's bundled in @compomo/ui."
20
+ }
21
+ ],
22
+ "peerDependencies": {
23
+ "required": [
24
+ "react >=17",
25
+ "react-dom >=17",
26
+ "@ds-mo/tokens >=0.1.0"
27
+ ],
28
+ "optional": []
29
+ }
30
+ },
31
+ "props": {
32
+ "children": {
33
+ "type": "React.ReactNode",
34
+ "required": true
35
+ },
36
+ "fallback": {
37
+ "type": "React.ReactNode",
38
+ "description": "Custom error UI."
39
+ }
40
+ },
41
+ "exports": [
42
+ "ErrorBoundary"
43
+ ],
44
+ "types": [
45
+ "ErrorBoundaryProps"
46
+ ]
47
+ },
48
+ "dependencies": [
49
+ "@compomo/ui"
50
+ ],
51
+ "registryDependencies": [
52
+ "empty-state"
53
+ ],
54
+ "files": [
55
+ {
56
+ "path": "src/components/ErrorBoundary/ErrorBoundary.module.css",
57
+ "content": ".errorBoundary {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 400px;\n padding: var(--dimension-space-400);\n gap: var(--dimension-space-200);\n}\n\n.errorDetails {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--dimension-space-200);\n max-width: 600px;\n text-align: center;\n}\n",
58
+ "type": "registry:ui"
59
+ },
60
+ {
61
+ "path": "src/components/ErrorBoundary/ErrorBoundary.tsx",
62
+ "content": "import React, { Component, ReactNode } from 'react';\nimport { EmptyState } from '@/components/EmptyState';\nimport { Text } from '@/components/Text';\nimport styles from './ErrorBoundary.module.css';\n\nexport interface ErrorBoundaryProps {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error };\n }\n\n override componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n console.error('ErrorBoundary caught an error:', error, errorInfo);\n }\n\n handleReset = () => {\n this.setState({ hasError: false, error: null });\n };\n\n override render() {\n if (this.state.hasError) {\n if (this.props.fallback) return this.props.fallback;\n return (\n <div className={styles.errorBoundary}>\n <EmptyState type=\"no-content\" />\n <div className={styles.errorDetails}>\n <Text variant=\"text-body-small\" as=\"p\" color=\"secondary\">\n Something went wrong. Please refresh the page.\n </Text>\n </div>\n </div>\n );\n }\n return this.props.children;\n }\n}\n",
63
+ "type": "registry:ui"
64
+ }
65
+ ]
66
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "fade",
4
+ "title": "Fade",
5
+ "description": "Decorative gradient overlay for scroll edges.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/fade",
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 { Fade } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { FadeProps, FadeSide } 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
+ "side": {
28
+ "type": "'top' | 'bottom' | 'left' | 'right'",
29
+ "required": true
30
+ },
31
+ "height": {
32
+ "type": "string",
33
+ "required": true
34
+ },
35
+ "background": {
36
+ "type": "string",
37
+ "default": "'var(--color-background-secondary)'"
38
+ }
39
+ },
40
+ "exports": [
41
+ "Fade"
42
+ ],
43
+ "types": [
44
+ "FadeProps",
45
+ "FadeSide"
46
+ ]
47
+ },
48
+ "dependencies": [
49
+ "@compomo/ui",
50
+ "@ds-mo/tokens"
51
+ ],
52
+ "registryDependencies": [],
53
+ "files": [
54
+ {
55
+ "path": "src/components/Fade/Fade.module.css",
56
+ "content": ".fade {\n position: absolute;\n pointer-events: none;\n z-index: 10;\n transform: translateZ(0);\n backface-visibility: hidden;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fade { transition: none; }\n}\n\n.fadeTop {\n top: 0; left: 0; right: 0;\n background: linear-gradient(to bottom, var(--background) 0%, var(--background) 50%, transparent 100%);\n}\n\n.fadeBottom {\n bottom: 0; left: 0; right: 0;\n background: linear-gradient(to top, var(--background) 0%, transparent 100%);\n}\n\n.fadeLeft {\n top: 0; bottom: 0; left: 0;\n background: linear-gradient(to right, var(--background) 0%, transparent 100%);\n}\n\n.fadeRight {\n top: 0; bottom: 0; right: 0;\n background: linear-gradient(to left, var(--background) 0%, transparent 100%);\n}\n",
57
+ "type": "registry:ui"
58
+ },
59
+ {
60
+ "path": "src/components/Fade/Fade.tsx",
61
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport styles from './Fade.module.css';\n\nexport type FadeSide = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface FadeProps {\n side: FadeSide;\n height: string;\n background?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst sideClassMap: Record<FadeSide, string> = {\n top: 'fadeTop',\n bottom: 'fadeBottom',\n left: 'fadeLeft',\n right: 'fadeRight',\n};\n\nexport const Fade = forwardRef<HTMLDivElement, FadeProps>(\n ({ side, height, background = 'var(--color-background-secondary)', className, style = {} }, ref) => (\n <div\n ref={ref}\n className={cn(styles.fade, styles[sideClassMap[side]], className)}\n style={{ ...style, height, '--background': background } as React.CSSProperties}\n aria-hidden=\"true\"\n />\n )\n);\n\nFade.displayName = 'Fade';\n",
62
+ "type": "registry:ui"
63
+ }
64
+ ]
65
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "field",
4
+ "title": "Field",
5
+ "description": "Simple label wrapper that links to child input via htmlFor.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/field",
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 { Field } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { FieldProps } from '@compomo/ui';",
17
+ "internalDependencies": [
18
+ {
19
+ "component": "Text",
20
+ "note": "Used internally by Field. 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
+ "children": {
38
+ "type": "React.ReactNode",
39
+ "required": true
40
+ },
41
+ "id": {
42
+ "type": "string"
43
+ }
44
+ },
45
+ "exports": [
46
+ "Field"
47
+ ],
48
+ "types": [
49
+ "FieldProps"
50
+ ]
51
+ },
52
+ "dependencies": [
53
+ "@compomo/ui",
54
+ "@ds-mo/tokens"
55
+ ],
56
+ "registryDependencies": [
57
+ "text"
58
+ ],
59
+ "files": [
60
+ {
61
+ "path": "src/components/Field/Field.module.css",
62
+ "content": ".field {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n}\n",
63
+ "type": "registry:ui"
64
+ },
65
+ {
66
+ "path": "src/components/Field/Field.tsx",
67
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './Field.module.css';\n\nexport interface FieldProps {\n label: string;\n children: React.ReactNode;\n id?: string;\n className?: string;\n}\n\nexport const Field = forwardRef<HTMLDivElement, FieldProps>(\n ({ label, children, id, className }, ref) => (\n <div ref={ref} className={cn(styles.field, className)}>\n <Text variant=\"text-body-small-emphasis\" as=\"label\" htmlFor={id}>{label}</Text>\n {children}\n </div>\n )\n);\n\nField.displayName = 'Field';\n",
68
+ "type": "registry:ui"
69
+ }
70
+ ]
71
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "header",
4
+ "title": "Header",
5
+ "description": "App header bar with background variants.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@compomo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/CompoMo/?path=/story/header",
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 { Header } from '@compomo/ui';",
15
+ "cssImport": "import '@compomo/ui/css';",
16
+ "typeImport": "import type { HeaderProps, HeaderBackground } from '@compomo/ui';",
17
+ "internalDependencies": [
18
+ {
19
+ "component": "Surface",
20
+ "note": "Used internally by Header. 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
+ "children": {
34
+ "type": "React.ReactNode"
35
+ },
36
+ "background": {
37
+ "type": "HeaderBackground"
38
+ }
39
+ },
40
+ "exports": [
41
+ "Header"
42
+ ],
43
+ "types": [
44
+ "HeaderProps",
45
+ "HeaderBackground"
46
+ ]
47
+ },
48
+ "dependencies": [
49
+ "@compomo/ui",
50
+ "@ds-mo/tokens"
51
+ ],
52
+ "registryDependencies": [
53
+ "surface"
54
+ ],
55
+ "files": [
56
+ {
57
+ "path": "src/components/Header/Header.module.css",
58
+ "content": ".header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--dimension-size-600, 48px);\n padding: 0 var(--dimension-space-100);\n flex-shrink: 0;\n gap: var(--dimension-space-100);\n}\n\n.left {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n flex-shrink: 0;\n min-width: 0;\n}\n\n.center {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--dimension-space-050);\n flex: 1;\n min-width: 0;\n}\n\n.right {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n flex-shrink: 0;\n}\n",
59
+ "type": "registry:ui"
60
+ },
61
+ {
62
+ "path": "src/components/Header/Header.tsx",
63
+ "content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Surface } from '@/components/Surface';\nimport { Text } from '@/components/Text';\nimport styles from './Header.module.css';\n\nexport type HeaderBackground = 'primary' | 'secondary' | 'transparent' | 'translucent';\n\nexport interface HeaderProps {\n title?: string;\n left?: React.ReactNode;\n center?: React.ReactNode;\n right?: React.ReactNode;\n background?: HeaderBackground;\n className?: string;\n}\n\nexport const Header = forwardRef<HTMLElement, HeaderProps>(\n ({ title, left, center, right, background = 'secondary', className }, ref) => (\n <Surface\n ref={ref}\n as=\"header\"\n background={background}\n elevation=\"none\"\n edge=\"bottom\"\n className={cn(styles.header, className)}\n >\n <div className={styles.left}>\n {left}\n {title && !center && (\n <Text variant=\"text-title-small\" as=\"h1\" lineTruncation={1}>\n {title}\n </Text>\n )}\n </div>\n {center && <div className={styles.center}>{center}</div>}\n <div className={styles.right}>{right}</div>\n </Surface>\n )\n);\n\nHeader.displayName = 'Header';\n",
64
+ "type": "registry:ui"
65
+ }
66
+ ]
67
+ }