@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.
- package/dist/components/ds-accordion.d.ts +11 -0
- package/dist/components/ds-accordion.js +2 -0
- package/dist/components/ds-accordion.js.map +1 -0
- package/dist/components/ds-badge.d.ts +11 -0
- package/dist/components/ds-badge.js +2 -0
- package/dist/components/ds-badge.js.map +1 -0
- package/dist/components/ds-banner.d.ts +11 -0
- package/dist/components/ds-banner.js +2 -0
- package/dist/components/ds-banner.js.map +1 -0
- package/dist/components/ds-breadcrumb.d.ts +11 -0
- package/dist/components/ds-breadcrumb.js +2 -0
- package/dist/components/ds-breadcrumb.js.map +1 -0
- package/dist/components/ds-button.d.ts +11 -0
- package/dist/components/ds-button.js +2 -0
- package/dist/components/ds-button.js.map +1 -0
- package/dist/components/ds-card.d.ts +11 -0
- package/dist/components/ds-card.js +2 -0
- package/dist/components/ds-card.js.map +1 -0
- package/dist/components/ds-checkbox.d.ts +11 -0
- package/dist/components/ds-checkbox.js +2 -0
- package/dist/components/ds-checkbox.js.map +1 -0
- package/dist/components/ds-divider.d.ts +11 -0
- package/dist/components/ds-divider.js +2 -0
- package/dist/components/ds-divider.js.map +1 -0
- package/dist/components/ds-empty-state.d.ts +11 -0
- package/dist/components/ds-empty-state.js +2 -0
- package/dist/components/ds-empty-state.js.map +1 -0
- package/dist/components/ds-fade.d.ts +11 -0
- package/dist/components/ds-fade.js +2 -0
- package/dist/components/ds-fade.js.map +1 -0
- package/dist/components/ds-field.d.ts +11 -0
- package/dist/components/ds-field.js +2 -0
- package/dist/components/ds-field.js.map +1 -0
- package/dist/components/ds-header.d.ts +11 -0
- package/dist/components/ds-header.js +2 -0
- package/dist/components/ds-header.js.map +1 -0
- package/dist/components/ds-input.d.ts +11 -0
- package/dist/components/ds-input.js +2 -0
- package/dist/components/ds-input.js.map +1 -0
- package/dist/components/ds-loader.d.ts +11 -0
- package/dist/components/ds-loader.js +2 -0
- package/dist/components/ds-loader.js.map +1 -0
- package/dist/components/ds-menu.d.ts +11 -0
- package/dist/components/ds-menu.js +2 -0
- package/dist/components/ds-menu.js.map +1 -0
- package/dist/components/ds-modal.d.ts +11 -0
- package/dist/components/ds-modal.js +2 -0
- package/dist/components/ds-modal.js.map +1 -0
- package/dist/components/ds-pagination.d.ts +11 -0
- package/dist/components/ds-pagination.js +2 -0
- package/dist/components/ds-pagination.js.map +1 -0
- package/dist/components/ds-radio-group.d.ts +11 -0
- package/dist/components/ds-radio-group.js +2 -0
- package/dist/components/ds-radio-group.js.map +1 -0
- package/dist/components/ds-scrollbar.d.ts +11 -0
- package/dist/components/ds-scrollbar.js +2 -0
- package/dist/components/ds-scrollbar.js.map +1 -0
- package/dist/components/ds-sidebar.d.ts +11 -0
- package/dist/components/ds-sidebar.js +2 -0
- package/dist/components/ds-sidebar.js.map +1 -0
- package/dist/components/ds-skeleton.d.ts +11 -0
- package/dist/components/ds-skeleton.js +2 -0
- package/dist/components/ds-skeleton.js.map +1 -0
- package/dist/components/ds-slider.d.ts +11 -0
- package/dist/components/ds-slider.js +2 -0
- package/dist/components/ds-slider.js.map +1 -0
- package/dist/components/ds-surface.d.ts +11 -0
- package/dist/components/ds-surface.js +2 -0
- package/dist/components/ds-surface.js.map +1 -0
- package/dist/components/ds-tab-group.d.ts +11 -0
- package/dist/components/ds-tab-group.js +2 -0
- package/dist/components/ds-tab-group.js.map +1 -0
- package/dist/components/ds-table.d.ts +11 -0
- package/dist/components/ds-table.js +2 -0
- package/dist/components/ds-table.js.map +1 -0
- package/dist/components/ds-tag.d.ts +11 -0
- package/dist/components/ds-tag.js +2 -0
- package/dist/components/ds-tag.js.map +1 -0
- package/dist/components/ds-text.d.ts +11 -0
- package/dist/components/ds-text.js +2 -0
- package/dist/components/ds-text.js.map +1 -0
- package/dist/components/ds-toast-provider.d.ts +11 -0
- package/dist/components/ds-toast-provider.js +2 -0
- package/dist/components/ds-toast-provider.js.map +1 -0
- package/dist/components/ds-toggle.d.ts +11 -0
- package/dist/components/ds-toggle.js +2 -0
- package/dist/components/ds-toggle.js.map +1 -0
- package/dist/components/ds-tooltip.d.ts +11 -0
- package/dist/components/ds-tooltip.js +2 -0
- package/dist/components/ds-tooltip.js.map +1 -0
- package/dist/components/index.d.ts +33 -0
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/p-BcuUR5Ao.js +2 -0
- package/dist/components/p-BcuUR5Ao.js.map +1 -0
- package/dist/types/.stencil/Accordion/Accordion.d.ts +28 -0
- package/dist/types/.stencil/Badge/Badge.d.ts +8 -0
- package/dist/types/.stencil/Badge/index.d.ts +2 -0
- package/dist/types/.stencil/Banner/Banner.d.ts +29 -0
- package/dist/types/.stencil/Breadcrumb/Breadcrumb.d.ts +16 -0
- package/dist/types/.stencil/Button/Button.d.ts +38 -0
- package/dist/types/.stencil/Button/index.d.ts +2 -0
- package/dist/types/.stencil/Card/Card.d.ts +8 -0
- package/dist/types/.stencil/Checkbox/Checkbox.d.ts +13 -0
- package/dist/types/.stencil/Checkbox/index.d.ts +2 -0
- package/dist/types/.stencil/Divider/Divider.d.ts +7 -0
- package/dist/types/.stencil/Divider/index.d.ts +2 -0
- package/dist/types/.stencil/EmptyState/EmptyState.d.ts +7 -0
- package/dist/types/.stencil/Fade/Fade.d.ts +10 -0
- package/dist/types/.stencil/Fade/index.d.ts +2 -0
- package/dist/types/.stencil/Field/Field.d.ts +8 -0
- package/dist/types/.stencil/Header/Header.d.ts +7 -0
- package/dist/types/.stencil/Input/Input.d.ts +26 -0
- package/dist/types/.stencil/Input/index.d.ts +2 -0
- package/dist/types/.stencil/Loader/Loader.d.ts +12 -0
- package/dist/types/.stencil/Loader/index.d.ts +2 -0
- package/dist/types/.stencil/Menu/Menu.d.ts +60 -0
- package/dist/types/.stencil/Modal/Modal.d.ts +31 -0
- package/dist/types/.stencil/Pagination/Pagination.d.ts +11 -0
- package/dist/types/.stencil/RadioGroup/RadioGroup.d.ts +21 -0
- package/dist/types/.stencil/RadioGroup/index.d.ts +2 -0
- package/dist/types/.stencil/Scrollbar/Scrollbar.d.ts +27 -0
- package/dist/types/.stencil/Sidebar/Sidebar.d.ts +29 -0
- package/dist/types/.stencil/Skeleton/Skeleton.d.ts +16 -0
- package/dist/types/.stencil/Skeleton/index.d.ts +2 -0
- package/dist/types/.stencil/Slider/Slider.d.ts +18 -0
- package/dist/types/.stencil/Slider/index.d.ts +2 -0
- package/dist/types/.stencil/Surface/Surface.d.ts +22 -0
- package/dist/types/.stencil/TabGroup/TabGroup.d.ts +29 -0
- package/dist/types/.stencil/Table/Table.d.ts +50 -0
- package/dist/types/.stencil/Tag/Tag.d.ts +32 -0
- package/dist/types/.stencil/Tag/index.d.ts +2 -0
- package/dist/types/.stencil/Text/Text.d.ts +22 -0
- package/dist/types/.stencil/Text/index.d.ts +2 -0
- package/dist/types/.stencil/Toast/Toast.d.ts +15 -0
- package/dist/types/.stencil/Toast/toast-service.d.ts +24 -0
- package/dist/types/.stencil/Toggle/Toggle.d.ts +10 -0
- package/dist/types/.stencil/Toggle/index.d.ts +2 -0
- package/dist/types/.stencil/Tooltip/Tooltip.d.ts +36 -0
- package/dist/types/components.d.ts +2024 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/package.json +33 -29
- package/src/angular/angular-component-lib/utils.ts +65 -0
- package/src/angular/index.ts +35 -0
- package/src/angular/proxies.ts +819 -0
- package/dist/index.css +0 -2
- package/dist/index.d.ts +0 -969
- package/dist/index.js +0 -2492
- package/dist/index.js.map +0 -1
- package/dist/r/accordion.json +0 -79
- package/dist/r/badge.json +0 -69
- package/dist/r/banner.json +0 -90
- package/dist/r/breadcrumb.json +0 -70
- package/dist/r/button-group.json +0 -65
- package/dist/r/button.json +0 -137
- package/dist/r/card.json +0 -82
- package/dist/r/checkbox.json +0 -91
- package/dist/r/divider.json +0 -57
- package/dist/r/empty-state.json +0 -69
- package/dist/r/error-boundary.json +0 -66
- package/dist/r/fade.json +0 -65
- package/dist/r/field.json +0 -71
- package/dist/r/header.json +0 -67
- package/dist/r/input.json +0 -77
- package/dist/r/loader.json +0 -54
- package/dist/r/menu.json +0 -130
- package/dist/r/modal.json +0 -93
- package/dist/r/pagination.json +0 -80
- package/dist/r/radio.json +0 -85
- package/dist/r/registry.json +0 -1600
- package/dist/r/scrollbar.json +0 -68
- package/dist/r/select.json +0 -93
- package/dist/r/sidebar.json +0 -105
- package/dist/r/skeleton.json +0 -72
- package/dist/r/slider.json +0 -87
- package/dist/r/surface.json +0 -97
- package/dist/r/tab-group.json +0 -72
- package/dist/r/tab.json +0 -71
- package/dist/r/table.json +0 -110
- package/dist/r/tag.json +0 -110
- package/dist/r/text.json +0 -94
- package/dist/r/toast.json +0 -77
- package/dist/r/toggle-button-group.json +0 -65
- package/dist/r/toggle-button.json +0 -94
- package/dist/r/toggle.json +0 -65
- package/dist/r/tooltip.json +0 -86
- package/src/components/Accordion/Accordion.module.css +0 -66
- package/src/components/Accordion/Accordion.stories.tsx +0 -95
- package/src/components/Accordion/Accordion.tsx +0 -122
- package/src/components/Accordion/index.ts +0 -2
- package/src/components/Badge/Badge.module.css +0 -6
- package/src/components/Badge/Badge.stories.tsx +0 -99
- package/src/components/Badge/Badge.tsx +0 -23
- package/src/components/Badge/index.ts +0 -2
- package/src/components/Banner/Banner.module.css +0 -67
- package/src/components/Banner/Banner.stories.tsx +0 -81
- package/src/components/Banner/Banner.tsx +0 -109
- package/src/components/Banner/index.ts +0 -2
- package/src/components/Breadcrumb/Breadcrumb.module.css +0 -46
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -72
- package/src/components/Breadcrumb/Breadcrumb.tsx +0 -68
- package/src/components/Breadcrumb/index.ts +0 -2
- package/src/components/Button/Button.mdx +0 -143
- package/src/components/Button/Button.module.css +0 -343
- package/src/components/Button/Button.stories.tsx +0 -575
- package/src/components/Button/Button.tsx +0 -201
- package/src/components/Button/index.ts +0 -10
- package/src/components/ButtonGroup/ButtonGroup.module.css +0 -157
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -384
- package/src/components/ButtonGroup/ButtonGroup.tsx +0 -122
- package/src/components/ButtonGroup/index.ts +0 -2
- package/src/components/Card/Card.module.css +0 -36
- package/src/components/Card/Card.stories.tsx +0 -78
- package/src/components/Card/Card.tsx +0 -53
- package/src/components/Card/index.ts +0 -2
- package/src/components/Checkbox/Checkbox.module.css +0 -47
- package/src/components/Checkbox/Checkbox.stories.tsx +0 -129
- package/src/components/Checkbox/Checkbox.tsx +0 -68
- package/src/components/Checkbox/index.ts +0 -2
- package/src/components/Divider/Divider.module.css +0 -19
- package/src/components/Divider/Divider.stories.tsx +0 -55
- package/src/components/Divider/Divider.tsx +0 -28
- package/src/components/Divider/index.ts +0 -2
- package/src/components/EmptyState/EmptyState.module.css +0 -8
- package/src/components/EmptyState/EmptyState.stories.tsx +0 -53
- package/src/components/EmptyState/EmptyState.tsx +0 -31
- package/src/components/EmptyState/index.ts +0 -2
- package/src/components/ErrorBoundary/ErrorBoundary.module.css +0 -18
- package/src/components/ErrorBoundary/ErrorBoundary.stories.tsx +0 -38
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +0 -50
- package/src/components/ErrorBoundary/index.ts +0 -2
- package/src/components/Fade/Fade.module.css +0 -31
- package/src/components/Fade/Fade.stories.tsx +0 -35
- package/src/components/Fade/Fade.tsx +0 -33
- package/src/components/Fade/index.ts +0 -2
- package/src/components/Field/Field.module.css +0 -5
- package/src/components/Field/Field.stories.tsx +0 -111
- package/src/components/Field/Field.tsx +0 -22
- package/src/components/Field/index.ts +0 -2
- package/src/components/Header/Header.module.css +0 -33
- package/src/components/Header/Header.stories.tsx +0 -52
- package/src/components/Header/Header.tsx +0 -42
- package/src/components/Header/index.ts +0 -2
- package/src/components/Input/Input.module.css +0 -71
- package/src/components/Input/Input.stories.tsx +0 -135
- package/src/components/Input/Input.tsx +0 -76
- package/src/components/Input/index.ts +0 -2
- package/src/components/LabelWrap/LabelWrap.module.css +0 -34
- package/src/components/LabelWrap/LabelWrap.tsx +0 -32
- package/src/components/LabelWrap/index.ts +0 -1
- package/src/components/Loader/Loader.module.css +0 -9
- package/src/components/Loader/Loader.stories.tsx +0 -44
- package/src/components/Loader/Loader.tsx +0 -43
- package/src/components/Loader/index.ts +0 -2
- package/src/components/Menu/DestructiveMenuItem.module.css +0 -57
- package/src/components/Menu/DestructiveMenuItem.tsx +0 -64
- package/src/components/Menu/Menu.module.css +0 -49
- package/src/components/Menu/Menu.stories.tsx +0 -129
- package/src/components/Menu/Menu.tsx +0 -269
- package/src/components/Menu/MenuItem.module.css +0 -84
- package/src/components/Menu/MenuItem.tsx +0 -101
- package/src/components/Menu/index.ts +0 -6
- package/src/components/Modal/Modal.module.css +0 -67
- package/src/components/Modal/Modal.stories.tsx +0 -71
- package/src/components/Modal/Modal.tsx +0 -122
- package/src/components/Modal/index.ts +0 -2
- package/src/components/Pagination/Pagination.module.css +0 -64
- package/src/components/Pagination/Pagination.stories.tsx +0 -51
- package/src/components/Pagination/Pagination.tsx +0 -103
- package/src/components/Pagination/index.ts +0 -2
- package/src/components/Radio/Radio.module.css +0 -61
- package/src/components/Radio/Radio.stories.tsx +0 -101
- package/src/components/Radio/Radio.tsx +0 -108
- package/src/components/Radio/index.ts +0 -2
- package/src/components/Scrollbar/Scrollbar.module.css +0 -81
- package/src/components/Scrollbar/Scrollbar.stories.tsx +0 -46
- package/src/components/Scrollbar/Scrollbar.tsx +0 -187
- package/src/components/Scrollbar/index.ts +0 -2
- package/src/components/Select/Select.module.css +0 -31
- package/src/components/Select/Select.stories.tsx +0 -59
- package/src/components/Select/Select.tsx +0 -92
- package/src/components/Select/index.ts +0 -2
- package/src/components/Sidebar/Sidebar.module.css +0 -161
- package/src/components/Sidebar/Sidebar.stories.tsx +0 -125
- package/src/components/Sidebar/Sidebar.tsx +0 -129
- package/src/components/Sidebar/SidebarItem.tsx +0 -57
- package/src/components/Sidebar/SidebarSection.tsx +0 -42
- package/src/components/Sidebar/index.ts +0 -6
- package/src/components/Skeleton/Skeleton.module.css +0 -53
- package/src/components/Skeleton/Skeleton.stories.tsx +0 -89
- package/src/components/Skeleton/Skeleton.tsx +0 -66
- package/src/components/Skeleton/index.ts +0 -2
- package/src/components/Slider/Slider.module.css +0 -62
- package/src/components/Slider/Slider.stories.tsx +0 -120
- package/src/components/Slider/Slider.tsx +0 -74
- package/src/components/Slider/index.ts +0 -2
- package/src/components/Surface/Surface.module.css +0 -222
- package/src/components/Surface/Surface.stories.tsx +0 -213
- package/src/components/Surface/Surface.tsx +0 -219
- package/src/components/Surface/index.ts +0 -12
- package/src/components/Tab/Tab.module.css +0 -66
- package/src/components/Tab/Tab.stories.tsx +0 -103
- package/src/components/Tab/Tab.tsx +0 -41
- package/src/components/Tab/index.ts +0 -2
- package/src/components/TabGroup/TabGroup.module.css +0 -26
- package/src/components/TabGroup/TabGroup.stories.tsx +0 -60
- package/src/components/TabGroup/TabGroup.tsx +0 -83
- package/src/components/TabGroup/index.ts +0 -2
- package/src/components/Table/Table.module.css +0 -130
- package/src/components/Table/Table.stories.tsx +0 -111
- package/src/components/Table/Table.tsx +0 -226
- package/src/components/Table/index.ts +0 -11
- package/src/components/Tag/Tag.module.css +0 -270
- package/src/components/Tag/Tag.stories.tsx +0 -399
- package/src/components/Tag/Tag.tsx +0 -162
- package/src/components/Tag/index.ts +0 -2
- package/src/components/Text/Text.module.css +0 -166
- package/src/components/Text/Text.stories.tsx +0 -212
- package/src/components/Text/Text.tsx +0 -181
- package/src/components/Text/index.ts +0 -13
- package/src/components/Toast/Toast.module.css +0 -91
- package/src/components/Toast/Toast.stories.tsx +0 -66
- package/src/components/Toast/Toast.tsx +0 -182
- package/src/components/Toast/index.ts +0 -8
- package/src/components/Toggle/Toggle.module.css +0 -87
- package/src/components/Toggle/Toggle.stories.tsx +0 -85
- package/src/components/Toggle/Toggle.tsx +0 -52
- package/src/components/Toggle/index.ts +0 -2
- package/src/components/ToggleButton/ToggleButton.module.css +0 -172
- package/src/components/ToggleButton/ToggleButton.stories.tsx +0 -299
- package/src/components/ToggleButton/ToggleButton.tsx +0 -118
- package/src/components/ToggleButton/index.ts +0 -2
- package/src/components/ToggleButtonGroup/ToggleButtonGroup.module.css +0 -163
- package/src/components/ToggleButtonGroup/ToggleButtonGroup.stories.tsx +0 -341
- package/src/components/ToggleButtonGroup/ToggleButtonGroup.tsx +0 -111
- package/src/components/ToggleButtonGroup/index.ts +0 -2
- package/src/components/Tooltip/Tooltip.module.css +0 -45
- package/src/components/Tooltip/Tooltip.stories.tsx +0 -46
- package/src/components/Tooltip/Tooltip.tsx +0 -224
- package/src/components/Tooltip/index.ts +0 -2
- package/src/css-modules.d.ts +0 -4
- package/src/docs/ColorUsage.mdx +0 -195
- package/src/docs/ElevationUsage.mdx +0 -95
- package/src/docs/Introduction.mdx +0 -97
- package/src/docs/OpticalSizing.mdx +0 -178
- package/src/docs/TypographyUsage.mdx +0 -121
- package/src/index.ts +0 -154
- package/src/stories/Colors.stories.tsx +0 -528
- package/src/stories/Dimensions.stories.tsx +0 -200
- package/src/stories/Effects.stories.tsx +0 -231
- package/src/stories/Icons.stories.tsx +0 -159
- package/src/stories/Typography.stories.tsx +0 -157
- package/src/types/icons.ts +0 -15
- package/src/types/index.ts +0 -1
- package/src/utils/cn.ts +0 -6
- package/src/utils/css-tokens.ts +0 -22
package/dist/r/input.json
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "input",
|
|
4
|
-
"title": "Input",
|
|
5
|
-
"description": "Text input supporting text, email, tel, url, search, and password types. Search type includes auto clear button.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/input",
|
|
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 { Input } from '@compomo/ui';",
|
|
15
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
16
|
-
"typeImport": "import type { InputProps } 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
|
-
"value": {
|
|
28
|
-
"type": "string",
|
|
29
|
-
"required": true
|
|
30
|
-
},
|
|
31
|
-
"onChange": {
|
|
32
|
-
"type": "(e: React.ChangeEvent<HTMLInputElement>) => void",
|
|
33
|
-
"required": true
|
|
34
|
-
},
|
|
35
|
-
"type": {
|
|
36
|
-
"type": "'text' | 'email' | 'tel' | 'url' | 'search' | 'password'",
|
|
37
|
-
"default": "'text'"
|
|
38
|
-
},
|
|
39
|
-
"placeholder": {
|
|
40
|
-
"type": "string"
|
|
41
|
-
},
|
|
42
|
-
"suffix": {
|
|
43
|
-
"type": "React.ReactNode"
|
|
44
|
-
},
|
|
45
|
-
"inactive": {
|
|
46
|
-
"type": "boolean"
|
|
47
|
-
},
|
|
48
|
-
"clearIcon": {
|
|
49
|
-
"type": "IconComponent",
|
|
50
|
-
"description": "Custom clear icon for search type."
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"exports": [
|
|
54
|
-
"Input"
|
|
55
|
-
],
|
|
56
|
-
"types": [
|
|
57
|
-
"InputProps"
|
|
58
|
-
]
|
|
59
|
-
},
|
|
60
|
-
"dependencies": [
|
|
61
|
-
"@compomo/ui",
|
|
62
|
-
"@ds-mo/tokens"
|
|
63
|
-
],
|
|
64
|
-
"registryDependencies": [],
|
|
65
|
-
"files": [
|
|
66
|
-
{
|
|
67
|
-
"path": "src/components/Input/Input.module.css",
|
|
68
|
-
"content": ".wrapper {\n width: 100%;\n height: var(--dimension-size-400);\n display: flex;\n align-items: center;\n background-color: var(--color-background-primary);\n border-radius: var(--dimension-radius-075);\n box-shadow: var(--effect-elevation-depressed-sm);\n box-sizing: border-box;\n}\n\n.wrapper:focus-within {\n box-shadow: inset 0 0 0 1.25px var(--color-foreground-bold-brand);\n}\n\n.row {\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n gap: var(--dimension-space-050);\n}\n\n.input {\n flex: 1;\n min-width: 0;\n height: 100%;\n padding: 0 var(--dimension-space-100);\n background: transparent;\n border: none;\n outline: none;\n font-family: inherit;\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n color: var(--color-foreground-primary);\n border-radius: var(--dimension-radius-075);\n -webkit-appearance: none;\n appearance: none;\n}\n\n.input:disabled { opacity: 0.5; cursor: not-allowed; }\n.input::placeholder { color: var(--color-foreground-secondary); }\n.input:focus::placeholder { color: var(--color-foreground-tertiary); }\n\n/* Hide native search clear */\n.input[type=\"search\"]::-webkit-search-cancel-button,\n.input[type=\"search\"]::-webkit-search-decoration { display: none; }\n\n.clearButton {\n flex-shrink: 0;\n margin-right: var(--dimension-space-050);\n padding: var(--dimension-space-050);\n border: none;\n background: none;\n cursor: pointer;\n color: var(--color-foreground-secondary);\n border-radius: var(--dimension-radius-050);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.clearButton:hover { background-color: var(--color-interaction-hover); }\n\n.suffix {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n flex-shrink: 0;\n margin-right: var(--dimension-space-050);\n}\n",
|
|
69
|
-
"type": "registry:ui"
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"path": "src/components/Input/Input.tsx",
|
|
73
|
-
"content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport type { IconComponent } from '@/types/icons';\nimport styles from './Input.module.css';\n\nexport type InputType = 'text' | 'email' | 'tel' | 'url' | 'search' | 'password';\n\nexport interface InputProps {\n value: string;\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n id?: string;\n placeholder?: string;\n autoFocus?: boolean;\n className?: string;\n type?: InputType;\n inactive?: boolean;\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Content rendered inside the field on the right. */\n suffix?: React.ReactNode;\n /** Icon for clear button (search type). */\n clearIcon?: IconComponent;\n 'aria-label'?: string;\n}\n\nexport const Input = forwardRef<HTMLDivElement, InputProps>(\n (\n {\n value,\n onChange,\n id,\n placeholder,\n autoFocus = false,\n className,\n type = 'text',\n inactive = false,\n onKeyDown,\n suffix,\n clearIcon: ClearIcon,\n 'aria-label': ariaLabel,\n },\n ref\n ) => {\n const showClear = type === 'search' && value.length > 0 && !inactive;\n\n const handleClear = () => {\n onChange({ target: { value: '' } } as React.ChangeEvent<HTMLInputElement>);\n };\n\n return (\n <div ref={ref} className={cn(styles.wrapper, className)}>\n <div className={styles.row}>\n <input\n type={type}\n id={id}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n className={styles.input}\n autoFocus={autoFocus}\n disabled={inactive}\n aria-label={ariaLabel}\n />\n {showClear && (\n <button type=\"button\" className={styles.clearButton} onClick={handleClear} aria-label=\"Clear\">\n {ClearIcon ? <ClearIcon size={16} /> : <span aria-hidden>×</span>}\n </button>\n )}\n {suffix && <div className={styles.suffix}>{suffix}</div>}\n </div>\n </div>\n );\n }\n);\n\nInput.displayName = 'Input';\n",
|
|
74
|
-
"type": "registry:ui"
|
|
75
|
-
}
|
|
76
|
-
]
|
|
77
|
-
}
|
package/dist/r/loader.json
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "loader",
|
|
4
|
-
"title": "Loader",
|
|
5
|
-
"description": "SVG spinner that scales proportionally. Uses currentColor for theming.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/loader",
|
|
11
|
-
"consumption": {
|
|
12
|
-
"install": "npm install @compomo/ui",
|
|
13
|
-
"import": "import { Loader } from '@compomo/ui';",
|
|
14
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
15
|
-
"typeImport": "import type { LoaderProps } from '@compomo/ui';",
|
|
16
|
-
"peerDependencies": {
|
|
17
|
-
"required": [
|
|
18
|
-
"react >=17",
|
|
19
|
-
"react-dom >=17",
|
|
20
|
-
"@ds-mo/tokens >=0.1.0"
|
|
21
|
-
],
|
|
22
|
-
"optional": []
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"props": {
|
|
26
|
-
"size": {
|
|
27
|
-
"type": "number",
|
|
28
|
-
"default": "20"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"exports": [
|
|
32
|
-
"Loader"
|
|
33
|
-
],
|
|
34
|
-
"types": [
|
|
35
|
-
"LoaderProps"
|
|
36
|
-
]
|
|
37
|
-
},
|
|
38
|
-
"dependencies": [
|
|
39
|
-
"@compomo/ui"
|
|
40
|
-
],
|
|
41
|
-
"registryDependencies": [],
|
|
42
|
-
"files": [
|
|
43
|
-
{
|
|
44
|
-
"path": "src/components/Loader/Loader.module.css",
|
|
45
|
-
"content": ".loader {\n flex-shrink: 0;\n animation: spin 0.75s linear infinite;\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n",
|
|
46
|
-
"type": "registry:ui"
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"path": "src/components/Loader/Loader.tsx",
|
|
50
|
-
"content": "import React from 'react';\nimport styles from './Loader.module.css';\n\nexport interface LoaderProps {\n /**\n * Render size in px. Designed at 16px (r=6, strokeWidth=1).\n * Stroke weight scales proportionally with size — same behaviour as icons.\n * Defaults to 20.\n */\n size?: number;\n className?: string;\n}\n\n/**\n * Placeholder spinner component. Will be replaced with a full Loader\n * component once motion/brand specs are finalised.\n *\n * Designed at 16×16 viewBox so it matches the icon grid:\n * - r=5 → 10px circle in a 16px box (3px optical padding each side)\n * - strokeWidth=1 at native size → scales to 1.25px at 20px, 1.5px at 24px\n */\nexport const Loader = ({ size = 20, className }: LoaderProps) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n className={`${styles.loader}${className ? ` ${className}` : ''}`}\n aria-hidden=\"true\"\n >\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"5\"\n stroke=\"currentColor\"\n strokeWidth=\"1\"\n strokeLinecap=\"round\"\n strokeDasharray=\"23.6 7.9\"\n />\n </svg>\n);\n\nLoader.displayName = 'Loader';\n",
|
|
51
|
-
"type": "registry:ui"
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
}
|
package/dist/r/menu.json
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "menu",
|
|
4
|
-
"title": "Menu",
|
|
5
|
-
"description": "Positioned dropdown menu with sections, item selection styles, toggle items, and destructive hold-to-confirm items.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/menu",
|
|
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 { Menu, MenuItem, DestructiveMenuItem } from '@compomo/ui';",
|
|
15
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
16
|
-
"typeImport": "import type { MenuProps, MenuSection, MenuItemData, MenuSide, MenuAlign, MenuItemProps, MenuItemSelectionStyle, DestructiveMenuItemProps } from '@compomo/ui';",
|
|
17
|
-
"internalDependencies": [
|
|
18
|
-
{
|
|
19
|
-
"component": "Surface",
|
|
20
|
-
"note": "Used internally by Menu. No action needed — it's bundled in @compomo/ui."
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"component": "Text",
|
|
24
|
-
"note": "Used internally by Menu. No action needed — it's bundled in @compomo/ui."
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"component": "Toggle",
|
|
28
|
-
"note": "Used internally by Menu. 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
|
-
"isOpen": {
|
|
42
|
-
"type": "boolean",
|
|
43
|
-
"required": true
|
|
44
|
-
},
|
|
45
|
-
"onClose": {
|
|
46
|
-
"type": "() => void",
|
|
47
|
-
"required": true
|
|
48
|
-
},
|
|
49
|
-
"anchorRef": {
|
|
50
|
-
"type": "React.RefObject<HTMLElement | null>",
|
|
51
|
-
"required": true
|
|
52
|
-
},
|
|
53
|
-
"items": {
|
|
54
|
-
"type": "MenuItemData[]",
|
|
55
|
-
"description": "Flat item list (use items or sections, not both)."
|
|
56
|
-
},
|
|
57
|
-
"sections": {
|
|
58
|
-
"type": "MenuSection[]",
|
|
59
|
-
"description": "Grouped items with optional headers."
|
|
60
|
-
},
|
|
61
|
-
"side": {
|
|
62
|
-
"type": "'top' | 'right' | 'bottom' | 'left'",
|
|
63
|
-
"default": "'bottom'"
|
|
64
|
-
},
|
|
65
|
-
"align": {
|
|
66
|
-
"type": "'start' | 'center' | 'end'",
|
|
67
|
-
"default": "'start'"
|
|
68
|
-
},
|
|
69
|
-
"matchAnchorWidth": {
|
|
70
|
-
"type": "boolean"
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
"exports": [
|
|
74
|
-
"Menu",
|
|
75
|
-
"MenuItem",
|
|
76
|
-
"DestructiveMenuItem"
|
|
77
|
-
],
|
|
78
|
-
"types": [
|
|
79
|
-
"MenuProps",
|
|
80
|
-
"MenuSection",
|
|
81
|
-
"MenuItemData",
|
|
82
|
-
"MenuSide",
|
|
83
|
-
"MenuAlign",
|
|
84
|
-
"MenuItemProps",
|
|
85
|
-
"MenuItemSelectionStyle",
|
|
86
|
-
"DestructiveMenuItemProps"
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
|
-
"dependencies": [
|
|
90
|
-
"@compomo/ui",
|
|
91
|
-
"@ds-mo/tokens"
|
|
92
|
-
],
|
|
93
|
-
"registryDependencies": [
|
|
94
|
-
"surface",
|
|
95
|
-
"text",
|
|
96
|
-
"toggle"
|
|
97
|
-
],
|
|
98
|
-
"files": [
|
|
99
|
-
{
|
|
100
|
-
"path": "src/components/Menu/Menu.tsx",
|
|
101
|
-
"content": "import React, { useState, useEffect, useLayoutEffect, useRef, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Text } from '@/components/Text';\nimport { Surface } from '@/components/Surface';\nimport { MenuItem as MenuItemComponent } from './MenuItem';\nimport { DestructiveMenuItem } from './DestructiveMenuItem';\nimport { getCssSpacePx } from '@/utils/css-tokens';\nimport type { IconComponent } from '@/types';\nimport type { MenuItemSelectionStyle } from './MenuItem';\nimport styles from './Menu.module.css';\n\nconst CLOSE_ANIMATION_MS = 220;\n\nexport type MenuSide = 'top' | 'right' | 'bottom' | 'left';\nexport type MenuAlign = 'start' | 'center' | 'end';\n\nexport interface MenuItemData {\n label: string;\n onClick: () => void;\n isSelected?: boolean;\n isDestructive?: boolean;\n isInactive?: boolean;\n intent?: 'negative';\n keepOpenOnClick?: boolean;\n holdDuration?: number;\n icon?: IconComponent;\n subtext?: string;\n showToggle?: boolean;\n toggleValue?: boolean;\n selectionStyle?: MenuItemSelectionStyle;\n}\n\nexport interface MenuSection {\n header?: string;\n items: MenuItemData[];\n}\n\nexport interface MenuProps {\n isOpen: boolean;\n onClose: () => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n items?: MenuItemData[];\n sections?: MenuSection[];\n side?: MenuSide;\n align?: MenuAlign;\n sideOffset?: number;\n alignOffset?: number;\n sideOffsetToken?: string;\n alignOffsetToken?: string;\n width?: string;\n minWidth?: string;\n maxWidth?: string;\n matchAnchorWidth?: boolean;\n matchAnchorWidthOffset?: number;\n usePortal?: boolean;\n}\n\nexport const Menu: React.FC<MenuProps> = ({\n isOpen,\n onClose,\n anchorRef,\n items,\n sections,\n side = 'bottom',\n align = 'start',\n sideOffset = 4,\n alignOffset = 0,\n sideOffsetToken,\n alignOffsetToken,\n width,\n minWidth,\n maxWidth,\n matchAnchorWidth = false,\n matchAnchorWidthOffset = 0,\n usePortal = true,\n}) => {\n const [isClosing, setIsClosing] = useState(false);\n const [shouldRender, setShouldRender] = useState(isOpen);\n const [isPositionReady, setIsPositionReady] = useState(false);\n const [position, setPosition] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const [menuSize, setMenuSize] = useState<{ width: number; height: number }>({ width: 0, height: 0 });\n const [anchorSize, setAnchorSize] = useState<{ width: number; height: number }>({ width: 0, height: 0 });\n const positionCalculatedRef = useRef(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const lastSectionsRef = useRef<MenuSection[]>([]);\n\n const menuSections: MenuSection[] = sections || (items ? [{ items }] : []);\n\n const hasItems = menuSections.some((s) => s.items.length > 0);\n if (!isClosing && menuSections.length > 0 && hasItems) {\n lastSectionsRef.current = menuSections;\n }\n const sectionsToRender = isClosing ? lastSectionsRef.current : menuSections;\n\n useEffect(() => {\n if (isOpen) {\n setShouldRender(true);\n setIsClosing(false);\n setIsPositionReady(false);\n positionCalculatedRef.current = false;\n } else if (shouldRender) {\n setIsClosing(true);\n const timer = setTimeout(() => {\n setShouldRender(false);\n setIsClosing(false);\n positionCalculatedRef.current = false;\n }, CLOSE_ANIMATION_MS);\n return () => clearTimeout(timer);\n }\n }, [isOpen, shouldRender]);\n\n useLayoutEffect(() => {\n if (!isOpen || !shouldRender || !menuRef.current) return;\n const updateSize = () => {\n if (!menuRef.current) return;\n const rect = menuRef.current.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) setMenuSize({ width: rect.width, height: rect.height });\n };\n updateSize();\n requestAnimationFrame(() => requestAnimationFrame(updateSize));\n if (typeof ResizeObserver !== 'undefined') {\n const observer = new ResizeObserver(updateSize);\n observer.observe(menuRef.current);\n return () => observer.disconnect();\n }\n }, [isOpen, shouldRender, menuSections.length]);\n\n useLayoutEffect(() => {\n if (!isOpen || !shouldRender || !anchorRef.current || !menuRef.current) return;\n const calculatePosition = () => {\n const anchor = anchorRef.current;\n const menu = menuRef.current;\n if (!anchor || !menu) return;\n const anchorRect = anchor.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const menuWidth = menuRect.width || menuSize.width || 200;\n const menuHeight = menuRect.height || menuSize.height || 160;\n setAnchorSize({ width: anchorRect.width, height: anchorRect.height });\n const gap = sideOffsetToken != null ? getCssSpacePx(sideOffsetToken, 12) : sideOffset;\n const alignOff = alignOffsetToken != null ? getCssSpacePx(alignOffsetToken, 4) : alignOffset;\n let x = 0, y = 0;\n switch (side) {\n case 'top':\n y = anchorRect.top - menuHeight - gap;\n x = align === 'start' ? anchorRect.left + alignOff : align === 'end' ? anchorRect.right - menuWidth + alignOff : anchorRect.left + anchorRect.width / 2 - menuWidth / 2 + alignOff;\n break;\n case 'bottom':\n y = anchorRect.bottom + gap;\n x = align === 'start' ? anchorRect.left + alignOff : align === 'end' ? anchorRect.right - menuWidth + alignOff : anchorRect.left + anchorRect.width / 2 - menuWidth / 2 + alignOff;\n break;\n case 'left':\n x = anchorRect.left - menuWidth - gap;\n y = align === 'start' ? anchorRect.top + alignOff : align === 'end' ? anchorRect.bottom - menuHeight + alignOff : anchorRect.top + anchorRect.height / 2 - menuHeight / 2 + alignOff;\n break;\n case 'right':\n x = anchorRect.right + gap;\n y = align === 'start' ? anchorRect.top + alignOff : align === 'end' ? anchorRect.bottom - menuHeight + alignOff : anchorRect.top + anchorRect.height / 2 - menuHeight / 2 + alignOff;\n break;\n }\n const vp = 4;\n setPosition({\n x: Math.min(Math.max(x, vp), window.innerWidth - menuWidth - vp),\n y: Math.min(Math.max(y, vp), window.innerHeight - menuHeight - vp),\n });\n positionCalculatedRef.current = true;\n setIsPositionReady(true);\n };\n if (!positionCalculatedRef.current) {\n calculatePosition();\n requestAnimationFrame(() => { if (!positionCalculatedRef.current) calculatePosition(); });\n }\n const handleScrollResize = () => calculatePosition();\n window.addEventListener('scroll', handleScrollResize, true);\n window.addEventListener('resize', handleScrollResize);\n return () => {\n window.removeEventListener('scroll', handleScrollResize, true);\n window.removeEventListener('resize', handleScrollResize);\n };\n }, [isOpen, shouldRender, anchorRef, side, align, sideOffset, alignOffset, sideOffsetToken, alignOffsetToken, menuSize.width, menuSize.height, menuSections.length, matchAnchorWidthOffset]);\n\n useEffect(() => {\n if (!isOpen || !shouldRender) return;\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (menuRef.current?.contains(target)) return;\n if (anchorRef.current?.contains(target)) return;\n onClose();\n };\n document.addEventListener('mousedown', handleClickOutside, true);\n return () => document.removeEventListener('mousedown', handleClickOutside, true);\n }, [isOpen, shouldRender, onClose, anchorRef]);\n\n useEffect(() => {\n if (!isOpen) return;\n const handleEscape = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [isOpen, onClose]);\n\n if (!shouldRender || sectionsToRender.length === 0) return null;\n\n const renderMenuItem = (item: MenuItemData, index: number) => {\n if (item.isDestructive) {\n return (\n <DestructiveMenuItem\n key={index}\n label={item.label}\n subtext={item.subtext}\n holdDuration={item.holdDuration ?? 4000}\n onClick={() => { item.onClick(); if (!item.keepOpenOnClick) onClose(); }}\n />\n );\n }\n return (\n <MenuItemComponent\n key={index}\n icon={item.icon}\n label={item.label}\n subtext={item.subtext}\n onClick={() => { if (!item.isInactive) { item.onClick(); if (!item.keepOpenOnClick) onClose(); } }}\n isSelected={item.isSelected}\n isInactive={item.isInactive}\n intent={item.intent}\n showToggle={item.showToggle}\n toggleValue={item.toggleValue}\n selectionStyle={item.selectionStyle}\n />\n );\n };\n\n const menuStyle: React.CSSProperties = {\n position: 'absolute',\n left: 0,\n top: 0,\n transform: `translate(${Math.round(position.x)}px, ${Math.round(position.y)}px)`,\n willChange: 'transform',\n zIndex: 9998,\n visibility: isPositionReady ? 'visible' : 'hidden',\n ...(matchAnchorWidth && anchorSize.width > 0 ? { width: `${anchorSize.width + matchAnchorWidthOffset}px` } : width ? { width } : {}),\n ...(minWidth ? { minWidth } : {}),\n ...(maxWidth ? { maxWidth } : {}),\n };\n\n const menuContent = (\n <div ref={menuRef} className={`${styles.menuContainer} ${isClosing ? styles.closing : ''}`} style={menuStyle} role=\"menu\" aria-label=\"Menu\">\n {sectionsToRender.map((section, sectionIndex) => (\n <Surface\n key={sectionIndex}\n as=\"div\"\n className={styles.menuSection}\n edge={sectionIndex < sectionsToRender.length - 1 ? 'bottom' : undefined}\n elevation=\"none\"\n >\n {section.header && (\n <div className={styles.sectionHeader}>\n <Text variant=\"text-body-small-emphasis\" as=\"span\" className={styles.sectionLabel}>{section.header}</Text>\n </div>\n )}\n {section.items.map((item, itemIndex) => renderMenuItem(item, itemIndex))}\n </Surface>\n ))}\n </div>\n );\n\n if (usePortal) return createPortal(menuContent, document.body);\n return menuContent;\n};\n\nMenu.displayName = 'Menu';\n",
|
|
102
|
-
"type": "registry:ui"
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
"path": "src/components/Menu/Menu.module.css",
|
|
106
|
-
"content": ".menuContainer {\n box-sizing: border-box;\n background-color: var(--color-background-primary);\n border-radius: var(--dimension-radius-125);\n box-shadow: var(--effect-elevation-elevated-floating);\n display: flex;\n flex-direction: column;\n min-width: 200px;\n max-width: 600px;\n overflow: hidden;\n animation: menuFadeIn var(--effect-motion-short-2) forwards;\n backface-visibility: hidden;\n -webkit-font-smoothing: subpixel-antialiased;\n}\n\n@keyframes menuFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.menuContainer.closing {\n animation: menuFadeOut var(--effect-motion-short-3) forwards;\n}\n\n@keyframes menuFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n.menuSection {\n padding: var(--dimension-space-050);\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n}\n\n.sectionHeader {\n padding: var(--dimension-space-050) var(--dimension-space-075);\n display: flex;\n align-items: center;\n height: var(--dimension-size-400);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.sectionLabel {\n color: var(--color-foreground-secondary);\n text-align: left;\n}\n",
|
|
107
|
-
"type": "registry:ui"
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
"path": "src/components/Menu/MenuItem.tsx",
|
|
111
|
-
"content": "import React, { forwardRef } from 'react';\nimport { Text } from '@/components/Text';\nimport { Surface } from '@/components/Surface';\nimport type { IconComponent } from '@/types';\nimport styles from './MenuItem.module.css';\n\nexport type MenuItemSelectionStyle = 'highlight' | 'radio' | 'noOverlay';\n\nexport interface MenuItemProps {\n label: string;\n onClick: () => void;\n isSelected?: boolean;\n isInactive?: boolean;\n icon?: IconComponent;\n labelColor?: 'primary' | 'secondary' | 'tertiary';\n subtext?: string;\n showToggle?: boolean;\n toggleValue?: boolean;\n intent?: 'negative';\n selectionStyle?: MenuItemSelectionStyle;\n showTrailingChevron?: boolean;\n checkIcon?: IconComponent;\n chevronIcon?: IconComponent;\n}\n\nexport const MenuItem = forwardRef<HTMLButtonElement, MenuItemProps>(\n ({\n label,\n onClick,\n isSelected = false,\n isInactive = false,\n icon: Icon,\n labelColor,\n subtext,\n showToggle = false,\n toggleValue = false,\n intent,\n selectionStyle = 'highlight',\n showTrailingChevron = false,\n checkIcon: CheckIcon,\n chevronIcon: ChevronIcon,\n }, ref) => {\n const useRadioStyle = selectionStyle === 'radio';\n const noOverlay = selectionStyle === 'noOverlay' || useRadioStyle;\n const showSelectedOverlay = isSelected && !noOverlay;\n\n return (\n <Surface\n ref={ref as React.Ref<HTMLElement>}\n as=\"button\"\n interactive={!isInactive}\n selected={showSelectedOverlay}\n radius=\"sm\"\n className={`${styles.menuItem} ${isSelected ? styles.menuItemSelected : ''} ${isInactive ? styles.menuItemInactive : ''} ${intent === 'negative' ? styles.menuItemNegative : ''} ${labelColor === 'tertiary' ? styles.menuItemLabelTertiary : ''}`}\n onClick={onClick}\n type=\"button\"\n inactive={isInactive}\n >\n {Icon && (\n <div className={styles.iconPrefix}>\n <Icon size={20} />\n </div>\n )}\n <div className={styles.content}>\n <Text\n variant={isSelected ? 'text-body-medium-emphasis' : 'text-body-medium'}\n color={labelColor}\n as=\"span\"\n className={styles.label}\n >\n {label}\n </Text>\n {subtext && (\n <Text variant=\"text-body-small\" as=\"span\" className={styles.subtext}>\n {subtext}\n </Text>\n )}\n </div>\n {showToggle && (\n <div className={styles.toggleSuffix}>\n <div className={`${styles.toggle} ${toggleValue ? styles.toggleOn : ''}`}>\n <div className={styles.toggleThumb} />\n </div>\n </div>\n )}\n {useRadioStyle && isSelected && CheckIcon && (\n <div className={styles.checkSuffix}>\n <CheckIcon size={20} />\n </div>\n )}\n {showTrailingChevron && ChevronIcon && (\n <div className={styles.chevronSuffix}>\n <ChevronIcon size={20} />\n </div>\n )}\n </Surface>\n );\n }\n);\n\nMenuItem.displayName = 'MenuItem';\n",
|
|
112
|
-
"type": "registry:ui"
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"path": "src/components/Menu/MenuItem.module.css",
|
|
116
|
-
"content": ".menuItem {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-075);\n border: none;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n text-align: left;\n width: 100%;\n min-height: var(--dimension-size-400);\n}\n\n.menuItem:has(.subtext) { align-items: flex-start; }\n\n.iconPrefix {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n color: var(--color-foreground-secondary);\n}\n\n.menuItemSelected .iconPrefix { color: var(--color-foreground-primary); }\n\n.content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-025);\n min-width: 0;\n}\n\n.label { color: var(--color-foreground-secondary); }\n.menuItem:has(.subtext) .label { color: var(--color-foreground-primary); }\n.menuItemSelected .label { color: var(--color-foreground-primary) !important; }\n.menuItemLabelTertiary .label, .menuItemLabelTertiary .iconPrefix { color: var(--color-foreground-tertiary); }\n.menuItemNegative .label { color: var(--color-foreground-bold-negative) !important; }\n\n.subtext { color: var(--color-foreground-secondary); line-height: 1.4; }\n\n.menuItemInactive { opacity: 0.5; cursor: default; pointer-events: none; }\n\n.toggleSuffix { flex-shrink: 0; display: flex; align-items: center; }\n\n.toggle {\n width: calc(var(--dimension-size-400) + var(--dimension-size-050));\n height: var(--dimension-size-250);\n background-color: var(--color-background-translucent);\n border-radius: var(--dimension-radius-125);\n position: relative;\n transition: var(--effect-transition-interaction-background-short-2);\n}\n\n.toggleOn { background-color: var(--color-background-medium-brand); }\n\n.toggleThumb {\n width: var(--dimension-size-200);\n height: var(--dimension-size-200);\n background-color: var(--color-foreground-on-bold-background-primary);\n border-radius: 50%;\n position: absolute;\n top: var(--dimension-space-025);\n left: var(--dimension-space-025);\n transition: transform var(--effect-motion-short-2);\n}\n\n.toggleOn .toggleThumb { transform: translateX(var(--dimension-offset-200)); }\n\n.checkSuffix {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n color: var(--color-foreground-primary);\n}\n\n.chevronSuffix {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n color: var(--color-foreground-secondary);\n}\n\n.menuItemSelected .chevronSuffix { color: var(--color-foreground-primary); }\n",
|
|
117
|
-
"type": "registry:ui"
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
"path": "src/components/Menu/DestructiveMenuItem.tsx",
|
|
121
|
-
"content": "import React, { forwardRef, useState, useRef, useEffect } from 'react';\nimport { Text } from '@/components/Text';\nimport styles from './DestructiveMenuItem.module.css';\n\nexport interface DestructiveMenuItemProps {\n label: string;\n onClick: () => void;\n holdDuration?: number;\n subtext?: string;\n}\n\nexport const DestructiveMenuItem = forwardRef<HTMLButtonElement, DestructiveMenuItemProps>(\n ({ label, onClick, holdDuration = 4000, subtext }, ref) => {\n const [progress, setProgress] = useState(0);\n const pressTimerRef = useRef<number | null>(null);\n const startTimeRef = useRef<number>(0);\n const animationFrameRef = useRef<number | null>(null);\n\n const resetState = () => {\n setProgress(0);\n if (pressTimerRef.current) { clearTimeout(pressTimerRef.current); pressTimerRef.current = null; }\n if (animationFrameRef.current) { cancelAnimationFrame(animationFrameRef.current); animationFrameRef.current = null; }\n };\n\n const handleMouseDown = (e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n if (holdDuration === 0) { onClick(); return; }\n startTimeRef.current = performance.now();\n const animate = () => {\n const elapsed = performance.now() - startTimeRef.current;\n const newProgress = Math.min((elapsed / holdDuration) * 100, 100);\n setProgress(newProgress);\n if (newProgress < 100) animationFrameRef.current = requestAnimationFrame(animate);\n };\n animationFrameRef.current = requestAnimationFrame(animate);\n pressTimerRef.current = window.setTimeout(() => { onClick(); resetState(); }, holdDuration);\n };\n\n const handleMouseUp = (e: React.MouseEvent) => { e.stopPropagation(); resetState(); };\n const handleMouseLeave = (e: React.MouseEvent) => { e.stopPropagation(); resetState(); };\n\n useEffect(() => () => { resetState(); }, []);\n\n return (\n <button\n ref={ref}\n className={styles.destructiveMenuItem}\n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseLeave}\n type=\"button\"\n >\n <div className={styles.progressFill} style={{ width: `${progress}%` }} />\n <div className={styles.content}>\n <Text variant=\"text-body-medium\" as=\"span\" className={styles.label}>{label}</Text>\n {subtext && <Text variant=\"text-body-small\" as=\"span\" className={styles.subtext}>{subtext}</Text>}\n </div>\n </button>\n );\n }\n);\n\nDestructiveMenuItem.displayName = 'DestructiveMenuItem';\n",
|
|
122
|
-
"type": "registry:ui"
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"path": "src/components/Menu/DestructiveMenuItem.module.css",
|
|
126
|
-
"content": ".destructiveMenuItem {\n display: flex;\n align-items: 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 text-align: left;\n width: 100%;\n min-height: var(--dimension-size-400);\n position: relative;\n transition: var(--effect-transition-interaction-background-instant);\n overflow: hidden;\n}\n\n.destructiveMenuItem:has(.subtext) { align-items: flex-start; }\n\n.progressFill {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n background-color: var(--color-background-faint-negative);\n border-radius: var(--dimension-radius-075);\n transition: width 0ms linear;\n pointer-events: none;\n z-index: 0;\n}\n\n.destructiveMenuItem::before {\n content: '';\n position: absolute;\n inset: 0;\n background-color: transparent;\n border-radius: var(--dimension-radius-075);\n transition: var(--effect-transition-interaction-background-instant);\n pointer-events: none;\n z-index: 1;\n}\n\n.content {\n position: relative;\n z-index: 2;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-025);\n min-width: 0;\n}\n\n.label { color: var(--color-foreground-bold-negative); }\n.subtext { color: var(--color-foreground-secondary); text-wrap: pretty; }\n\n.destructiveMenuItem:hover::before { background-color: var(--color-interaction-hover); }\n.destructiveMenuItem:active::before { background-color: transparent; }\n",
|
|
127
|
-
"type": "registry:ui"
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
}
|
package/dist/r/modal.json
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "modal",
|
|
4
|
-
"title": "Modal",
|
|
5
|
-
"description": "Dialog overlay with portal rendering, escape-to-close, backdrop click, focus management, and entry/exit animations.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/modal",
|
|
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 { Modal } from '@compomo/ui';",
|
|
15
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
16
|
-
"typeImport": "import type { ModalProps, ModalWidth } from '@compomo/ui';",
|
|
17
|
-
"internalDependencies": [
|
|
18
|
-
{
|
|
19
|
-
"component": "Surface",
|
|
20
|
-
"note": "Used internally by Modal. No action needed — it's bundled in @compomo/ui."
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"component": "Text",
|
|
24
|
-
"note": "Used internally by Modal. No action needed — it's bundled in @compomo/ui."
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
|
-
"peerDependencies": {
|
|
28
|
-
"required": [
|
|
29
|
-
"react >=17",
|
|
30
|
-
"react-dom >=17",
|
|
31
|
-
"@ds-mo/tokens >=0.1.0"
|
|
32
|
-
],
|
|
33
|
-
"optional": []
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"props": {
|
|
37
|
-
"isOpen": {
|
|
38
|
-
"type": "boolean",
|
|
39
|
-
"required": true
|
|
40
|
-
},
|
|
41
|
-
"onClose": {
|
|
42
|
-
"type": "() => void",
|
|
43
|
-
"required": true
|
|
44
|
-
},
|
|
45
|
-
"title": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"required": true
|
|
48
|
-
},
|
|
49
|
-
"children": {
|
|
50
|
-
"type": "React.ReactNode",
|
|
51
|
-
"required": true
|
|
52
|
-
},
|
|
53
|
-
"subtitle": {
|
|
54
|
-
"type": "React.ReactNode"
|
|
55
|
-
},
|
|
56
|
-
"footer": {
|
|
57
|
-
"type": "React.ReactNode"
|
|
58
|
-
},
|
|
59
|
-
"width": {
|
|
60
|
-
"type": "'sm' | 'md' | 'lg' | string",
|
|
61
|
-
"default": "'md'",
|
|
62
|
-
"description": "sm=400px, md=560px, lg=720px, or custom CSS value."
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
"exports": [
|
|
66
|
-
"Modal"
|
|
67
|
-
],
|
|
68
|
-
"types": [
|
|
69
|
-
"ModalProps",
|
|
70
|
-
"ModalWidth"
|
|
71
|
-
]
|
|
72
|
-
},
|
|
73
|
-
"dependencies": [
|
|
74
|
-
"@compomo/ui",
|
|
75
|
-
"@ds-mo/tokens"
|
|
76
|
-
],
|
|
77
|
-
"registryDependencies": [
|
|
78
|
-
"surface",
|
|
79
|
-
"text"
|
|
80
|
-
],
|
|
81
|
-
"files": [
|
|
82
|
-
{
|
|
83
|
-
"path": "src/components/Modal/Modal.module.css",
|
|
84
|
-
"content": ".backdrop {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-200);\n background-color: var(--color-background-shade);\n backdrop-filter: blur(var(--effect-blur-sm));\n -webkit-backdrop-filter: blur(var(--effect-blur-sm));\n animation: modalBackdropFadeIn var(--effect-motion-short-2) forwards;\n z-index: 9999;\n}\n\n.backdrop.closing {\n animation: modalBackdropFadeOut var(--effect-motion-short-3) forwards;\n}\n\n@keyframes modalBackdropFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes modalBackdropFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n.dialog {\n display: flex;\n flex-direction: column;\n max-height: calc(100vh - 32px);\n overflow: hidden;\n animation: modalDialogFadeIn var(--effect-motion-short-2) forwards;\n}\n\n.backdrop.closing .dialog {\n animation: modalDialogFadeOut var(--effect-motion-short-3) forwards;\n}\n\n@keyframes modalDialogFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes modalDialogFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n.header {\n padding: var(--dimension-space-200) var(--dimension-space-200) var(--dimension-space-100) var(--dimension-space-200);\n}\n\n.subtitle {\n margin-top: var(--dimension-space-100);\n text-wrap: balance;\n}\n\n.body {\n padding: var(--dimension-space-100) var(--dimension-space-200);\n overflow-y: auto;\n}\n\n.footer {\n padding: var(--dimension-space-100) var(--dimension-space-200) var(--dimension-space-200) var(--dimension-space-200);\n}\n",
|
|
85
|
-
"type": "registry:ui"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"path": "src/components/Modal/Modal.tsx",
|
|
89
|
-
"content": "import React, { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Surface } from '@/components/Surface';\nimport { Text } from '@/components/Text';\nimport styles from './Modal.module.css';\n\nexport type ModalWidth = 'sm' | 'md' | 'lg';\n\nconst WIDTH_MAP: Record<ModalWidth, string> = {\n sm: 'var(--dimension-modal-width-sm, 400px)',\n md: 'var(--dimension-modal-width-md, 560px)',\n lg: 'var(--dimension-modal-width-lg, 720px)',\n};\n\nconst CLOSE_ANIMATION_MS = 220;\n\nexport interface ModalProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n subtitle?: React.ReactNode;\n children: React.ReactNode;\n footer?: React.ReactNode;\n width?: ModalWidth | string;\n bodyClassName?: string;\n}\n\nexport const Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n subtitle,\n children,\n footer,\n width = 'md',\n bodyClassName,\n}) => {\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const [isClosing, setIsClosing] = useState(false);\n const [shouldRender, setShouldRender] = useState(isOpen);\n\n const resolvedWidth = useMemo(() => {\n if (width === 'sm' || width === 'md' || width === 'lg') {\n return WIDTH_MAP[width];\n }\n return width;\n }, [width]);\n\n useEffect(() => {\n if (isOpen) {\n setShouldRender(true);\n setIsClosing(false);\n } else if (shouldRender) {\n setIsClosing(true);\n const timer = setTimeout(() => {\n setShouldRender(false);\n setIsClosing(false);\n }, CLOSE_ANIMATION_MS);\n return () => clearTimeout(timer);\n }\n }, [isOpen, shouldRender]);\n\n useEffect(() => {\n if (!isOpen) return;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [isOpen, onClose]);\n\n useEffect(() => {\n if (!isOpen || !shouldRender) return;\n const id = requestAnimationFrame(() => {\n dialogRef.current?.focus();\n });\n return () => cancelAnimationFrame(id);\n }, [isOpen, shouldRender]);\n\n if (!shouldRender) return null;\n\n return createPortal(\n <div\n className={`${styles.backdrop} ${isClosing ? styles.closing : ''}`}\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n >\n <Surface\n ref={dialogRef}\n background=\"primary\"\n elevation=\"floating\"\n radius=\"var(--dimension-radius-275, 22px)\"\n className={styles.dialog}\n style={{ width: `min(${resolvedWidth}, calc(100vw - 32px))` }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className={styles.header}>\n <Text id={titleId} as=\"h2\" variant=\"text-title-small\">\n {title}\n </Text>\n {subtitle != null && (\n <div className={styles.subtitle}>{subtitle}</div>\n )}\n </div>\n <div className={`${styles.body} ${bodyClassName ?? ''}`.trim()}>\n {children}\n </div>\n {footer != null && (\n <div className={styles.footer}>{footer}</div>\n )}\n </Surface>\n </div>,\n document.body\n );\n};\n\nModal.displayName = 'Modal';\n",
|
|
90
|
-
"type": "registry:ui"
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
package/dist/r/pagination.json
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "pagination",
|
|
4
|
-
"title": "Pagination",
|
|
5
|
-
"description": "Standalone page navigation with ellipsis for large ranges, sibling count control, and keyboard-accessible buttons.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/pagination",
|
|
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 { Pagination } from '@compomo/ui';",
|
|
15
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
16
|
-
"typeImport": "import type { PaginationProps } from '@compomo/ui';",
|
|
17
|
-
"internalDependencies": [
|
|
18
|
-
{
|
|
19
|
-
"component": "Text",
|
|
20
|
-
"note": "Used internally by Pagination. 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
|
-
"page": {
|
|
34
|
-
"type": "number",
|
|
35
|
-
"required": true,
|
|
36
|
-
"description": "1-based current page."
|
|
37
|
-
},
|
|
38
|
-
"totalPages": {
|
|
39
|
-
"type": "number",
|
|
40
|
-
"required": true
|
|
41
|
-
},
|
|
42
|
-
"onPageChange": {
|
|
43
|
-
"type": "(page: number) => void",
|
|
44
|
-
"required": true
|
|
45
|
-
},
|
|
46
|
-
"siblingCount": {
|
|
47
|
-
"type": "number",
|
|
48
|
-
"default": "1"
|
|
49
|
-
},
|
|
50
|
-
"inactive": {
|
|
51
|
-
"type": "boolean"
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
"exports": [
|
|
55
|
-
"Pagination"
|
|
56
|
-
],
|
|
57
|
-
"types": [
|
|
58
|
-
"PaginationProps"
|
|
59
|
-
]
|
|
60
|
-
},
|
|
61
|
-
"dependencies": [
|
|
62
|
-
"@compomo/ui",
|
|
63
|
-
"@ds-mo/tokens"
|
|
64
|
-
],
|
|
65
|
-
"registryDependencies": [
|
|
66
|
-
"text"
|
|
67
|
-
],
|
|
68
|
-
"files": [
|
|
69
|
-
{
|
|
70
|
-
"path": "src/components/Pagination/Pagination.module.css",
|
|
71
|
-
"content": ".pagination {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-025);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.inactive {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* ─── Button ────────────────────────────────────────────────────────────────── */\n\n.button {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: var(--dimension-size-300);\n height: var(--dimension-size-300);\n padding: 0 var(--dimension-space-050);\n background: none;\n border: none;\n border-radius: var(--dimension-radius-075);\n cursor: pointer;\n color: var(--color-foreground-secondary);\n transition: background-color var(--effect-motion-short-2), color var(--effect-motion-short-2);\n}\n\n.button:hover:not(:disabled) {\n background-color: var(--color-interaction-hover);\n color: var(--color-foreground-primary);\n}\n\n.button:active:not(:disabled) {\n background-color: var(--color-interaction-pressed);\n}\n\n.button:disabled {\n cursor: not-allowed;\n opacity: 0.35;\n}\n\n.active {\n background-color: var(--color-interaction-hover);\n color: var(--color-foreground-primary);\n}\n\n/* ─── Nav arrows ────────────────────────────────────────────────────────────── */\n\n.nav {\n font-size: 18px;\n}\n\n/* ─── Ellipsis ──────────────────────────────────────────────────────────────── */\n\n.ellipsis {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: var(--dimension-size-300);\n height: var(--dimension-size-300);\n}\n",
|
|
72
|
-
"type": "registry:ui"
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"path": "src/components/Pagination/Pagination.tsx",
|
|
76
|
-
"content": "import React, { forwardRef, useMemo } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './Pagination.module.css';\n\nexport interface PaginationProps {\n /** Current page (1-based). */\n page: number;\n /** Total number of pages. */\n totalPages: number;\n /** Called when page changes. */\n onPageChange: (page: number) => void;\n /** Max page buttons visible (excluding prev/next). */\n siblingCount?: number;\n /** Disables all interaction. */\n inactive?: boolean;\n className?: string;\n}\n\nfunction buildRange(start: number, end: number): (number | 'ellipsis')[] {\n const items: (number | 'ellipsis')[] = [];\n for (let i = start; i <= end; i++) items.push(i);\n return items;\n}\n\nfunction buildPages(page: number, totalPages: number, siblings: number): (number | 'ellipsis')[] {\n const totalSlots = siblings * 2 + 5; // siblings + boundaries + ellipses + current\n\n if (totalPages <= totalSlots) return buildRange(1, totalPages);\n\n const leftSibling = Math.max(page - siblings, 2);\n const rightSibling = Math.min(page + siblings, totalPages - 1);\n\n const showLeftEllipsis = leftSibling > 2;\n const showRightEllipsis = rightSibling < totalPages - 1;\n\n if (!showLeftEllipsis && showRightEllipsis) {\n const left = buildRange(1, siblings * 2 + 3);\n return [...left, 'ellipsis', totalPages];\n }\n\n if (showLeftEllipsis && !showRightEllipsis) {\n const right = buildRange(totalPages - (siblings * 2 + 2), totalPages);\n return [1, 'ellipsis', ...right];\n }\n\n return [1, 'ellipsis', ...buildRange(leftSibling, rightSibling), 'ellipsis', totalPages];\n}\n\nexport const Pagination = forwardRef<HTMLElement, PaginationProps>(\n ({ page, totalPages, onPageChange, siblingCount = 1, inactive = false, className }, ref) => {\n const pages = useMemo(() => buildPages(page, totalPages, siblingCount), [page, totalPages, siblingCount]);\n\n if (totalPages <= 1) return null;\n\n return (\n <nav ref={ref} aria-label=\"Pagination\" className={cn(styles.pagination, inactive && styles.inactive, className)}>\n <button\n type=\"button\"\n className={cn(styles.button, styles.nav)}\n disabled={page <= 1 || inactive}\n onClick={() => onPageChange(page - 1)}\n aria-label=\"Previous page\"\n >\n <Text variant=\"text-body-small\" as=\"span\" color=\"inherit\">‹</Text>\n </button>\n\n {pages.map((item, i) =>\n item === 'ellipsis' ? (\n <span key={`e${i}`} className={styles.ellipsis}>\n <Text variant=\"text-body-small\" as=\"span\" color=\"tertiary\">…</Text>\n </span>\n ) : (\n <button\n key={item}\n type=\"button\"\n className={cn(styles.button, item === page && styles.active)}\n onClick={() => onPageChange(item)}\n aria-current={item === page ? 'page' : undefined}\n disabled={inactive}\n >\n <Text variant={item === page ? 'text-body-small-emphasis' : 'text-body-small'} as=\"span\" color=\"inherit\">\n {item}\n </Text>\n </button>\n )\n )}\n\n <button\n type=\"button\"\n className={cn(styles.button, styles.nav)}\n disabled={page >= totalPages || inactive}\n onClick={() => onPageChange(page + 1)}\n aria-label=\"Next page\"\n >\n <Text variant=\"text-body-small\" as=\"span\" color=\"inherit\">›</Text>\n </button>\n </nav>\n );\n }\n);\n\nPagination.displayName = 'Pagination';\n",
|
|
77
|
-
"type": "registry:ui"
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}
|
package/dist/r/radio.json
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
-
"name": "radio",
|
|
4
|
-
"title": "RadioGroup",
|
|
5
|
-
"description": "Radio selection group with vertical/horizontal layout, per-option inactive, and keyboard navigation.",
|
|
6
|
-
"type": "registry:ui",
|
|
7
|
-
"meta": {
|
|
8
|
-
"library": "@compomo/ui",
|
|
9
|
-
"distribution": "npm",
|
|
10
|
-
"storybook": "https://zainadeel.github.io/CompoMo/?path=/story/radio",
|
|
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 { RadioGroup, RadioItem } from '@compomo/ui';",
|
|
15
|
-
"cssImport": "import '@compomo/ui/css';",
|
|
16
|
-
"typeImport": "import type { RadioGroupProps, RadioItemProps, RadioOption } from '@compomo/ui';",
|
|
17
|
-
"internalDependencies": [
|
|
18
|
-
{
|
|
19
|
-
"component": "Text",
|
|
20
|
-
"note": "Used internally by RadioGroup. 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
|
-
"value": {
|
|
34
|
-
"type": "string",
|
|
35
|
-
"required": true
|
|
36
|
-
},
|
|
37
|
-
"onChange": {
|
|
38
|
-
"type": "(value: string) => void",
|
|
39
|
-
"required": true
|
|
40
|
-
},
|
|
41
|
-
"options": {
|
|
42
|
-
"type": "RadioOption[]",
|
|
43
|
-
"required": true
|
|
44
|
-
},
|
|
45
|
-
"direction": {
|
|
46
|
-
"type": "'vertical' | 'horizontal'",
|
|
47
|
-
"default": "'vertical'"
|
|
48
|
-
},
|
|
49
|
-
"inactive": {
|
|
50
|
-
"type": "boolean"
|
|
51
|
-
},
|
|
52
|
-
"aria-label": {
|
|
53
|
-
"type": "string"
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
"exports": [
|
|
57
|
-
"RadioGroup",
|
|
58
|
-
"RadioItem"
|
|
59
|
-
],
|
|
60
|
-
"types": [
|
|
61
|
-
"RadioGroupProps",
|
|
62
|
-
"RadioItemProps",
|
|
63
|
-
"RadioOption"
|
|
64
|
-
]
|
|
65
|
-
},
|
|
66
|
-
"dependencies": [
|
|
67
|
-
"@compomo/ui",
|
|
68
|
-
"@ds-mo/tokens"
|
|
69
|
-
],
|
|
70
|
-
"registryDependencies": [
|
|
71
|
-
"text"
|
|
72
|
-
],
|
|
73
|
-
"files": [
|
|
74
|
-
{
|
|
75
|
-
"path": "src/components/Radio/Radio.module.css",
|
|
76
|
-
"content": ".group {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-025);\n}\n\n.horizontal {\n flex-direction: row;\n gap: var(--dimension-space-100);\n}\n\n/* ─── Radio item ────────────────────────────────────────────────────────────── */\n\n.radio {\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.radio:hover { background-color: var(--color-interaction-hover); }\n.radio: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/* ─── Circle indicator ──────────────────────────────────────────────────────── */\n\n.circle {\n width: 20px;\n height: 20px;\n border: 1.5px solid var(--color-foreground-secondary);\n border-radius: var(--dimension-radius-half);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all var(--effect-motion-short-2);\n box-sizing: border-box;\n}\n\n.circleChecked {\n border-color: var(--color-foreground-primary);\n}\n\n.dot {\n width: 10px;\n height: 10px;\n border-radius: var(--dimension-radius-half);\n background-color: var(--color-foreground-primary);\n}\n",
|
|
77
|
-
"type": "registry:ui"
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"path": "src/components/Radio/Radio.tsx",
|
|
81
|
-
"content": "import React, { forwardRef } from 'react';\nimport { cn } from '@/utils/cn';\nimport { Text } from '@/components/Text';\nimport styles from './Radio.module.css';\n\nexport interface RadioOption {\n label: string;\n value: string;\n inactive?: boolean;\n}\n\nexport interface RadioGroupProps {\n /** Currently selected value. */\n value: string;\n /** Called when selection changes. */\n onChange: (value: string) => void;\n /** Radio options to render. */\n options: RadioOption[];\n /** Group label for accessibility. */\n 'aria-label'?: string;\n /** Layout direction. */\n direction?: 'vertical' | 'horizontal';\n /** Disables the entire group. */\n inactive?: boolean;\n className?: string;\n}\n\nexport const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(\n (\n {\n value,\n onChange,\n options,\n 'aria-label': ariaLabel,\n direction = 'vertical',\n inactive = false,\n className,\n },\n ref\n ) => (\n <div\n ref={ref}\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(\n styles.group,\n direction === 'horizontal' && styles.horizontal,\n className\n )}\n >\n {options.map(opt => (\n <RadioItem\n key={opt.value}\n label={opt.label}\n checked={value === opt.value}\n inactive={inactive || opt.inactive}\n onChange={() => onChange(opt.value)}\n />\n ))}\n </div>\n )\n);\n\nRadioGroup.displayName = 'RadioGroup';\n\n/* ─── Individual Radio Item ─────────────────────────────────────────────────── */\n\nexport interface RadioItemProps {\n label: string;\n checked?: boolean;\n onChange?: () => void;\n inactive?: boolean;\n className?: string;\n}\n\nexport const RadioItem = forwardRef<HTMLDivElement, RadioItemProps>(\n ({ label, checked = false, onChange, inactive = false, className }, ref) => {\n const handleClick = () => {\n if (!inactive && !checked) onChange?.();\n };\n\n return (\n <div\n ref={ref}\n role=\"radio\"\n aria-checked={checked}\n tabIndex={inactive ? -1 : 0}\n className={cn(styles.radio, inactive && styles.inactive, className)}\n onClick={handleClick}\n onKeyDown={e => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n handleClick();\n }\n }}\n >\n <span className={cn(styles.circle, checked && styles.circleChecked)}>\n {checked && <span className={styles.dot} />}\n </span>\n <Text variant=\"text-body-medium\" as=\"span\" color=\"inherit\">\n {label}\n </Text>\n </div>\n );\n }\n);\n\nRadioItem.displayName = 'RadioItem';\n",
|
|
82
|
-
"type": "registry:ui"
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
}
|