doom-design-system 0.4.16 → 0.4.17
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/.agent/skills/doom/components/drawer.md +32 -2
- package/.agent/skills/doom/components/modal.md +17 -9
- package/.agent/skills/doom/components/sheet.md +41 -16
- package/.agent/skills/doom/components/table.md +18 -17
- package/dist/components/Combobox/Combobox.js +1 -1
- package/dist/components/Combobox/Combobox.module.css +34 -18
- package/dist/components/Drawer/Drawer.d.ts +21 -2
- package/dist/components/Drawer/Drawer.js +24 -2
- package/dist/components/Modal/Modal.d.ts +9 -4
- package/dist/components/Modal/Modal.js +10 -4
- package/dist/components/Modal/index.d.ts +1 -1
- package/dist/components/Modal/index.js +1 -1
- package/dist/components/Select/Select.module.css +12 -12
- package/dist/components/Sheet/Sheet.d.ts +21 -2
- package/dist/components/Sheet/Sheet.js +24 -2
- package/dist/components/Table/Table.d.ts +2 -1
- package/dist/components/Table/Table.js +3 -2
- package/dist/components/Table/Table.module.css +3 -0
- package/dist/components/Text/Text.module.css +10 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -12,13 +12,15 @@ import { Drawer } from "doom-design-system";
|
|
|
12
12
|
| ---------- | ---------------------- | ----------- | ------------------- |
|
|
13
13
|
| `isOpen` | `boolean` | required | Controls visibility |
|
|
14
14
|
| `onClose` | `() => void` | required | Close callback |
|
|
15
|
-
| `title` | `
|
|
15
|
+
| `title` | `ReactNode` | — | Header title |
|
|
16
16
|
| `side` | `"left" \| "right"` | `"right"` | Slide direction |
|
|
17
17
|
| `children` | `ReactNode` | required | Drawer content |
|
|
18
18
|
| `footer` | `ReactNode` | — | Footer content |
|
|
19
19
|
| `variant` | `"default" \| "solid"` | `"default"` | Visual style |
|
|
20
20
|
|
|
21
|
-
## Usage
|
|
21
|
+
## Usage Patterns
|
|
22
|
+
|
|
23
|
+
### Shorthand API (simple drawers)
|
|
22
24
|
|
|
23
25
|
```tsx
|
|
24
26
|
<Drawer
|
|
@@ -31,9 +33,37 @@ import { Drawer } from "doom-design-system";
|
|
|
31
33
|
</Drawer>
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
### Composition API (custom layouts)
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Drawer isOpen={isOpen} onClose={onClose} side="right">
|
|
40
|
+
<Drawer.Header>
|
|
41
|
+
<Text variant="h3">Custom Title</Text>
|
|
42
|
+
</Drawer.Header>
|
|
43
|
+
<Drawer.Body>
|
|
44
|
+
<Stack gap={4}>{/* Custom content */}</Stack>
|
|
45
|
+
</Drawer.Body>
|
|
46
|
+
<Drawer.Footer>
|
|
47
|
+
<Button variant="ghost" onClick={onClose}>
|
|
48
|
+
Cancel
|
|
49
|
+
</Button>
|
|
50
|
+
<Button onClick={handleSave}>Save</Button>
|
|
51
|
+
</Drawer.Footer>
|
|
52
|
+
</Drawer>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Sub-components
|
|
56
|
+
|
|
57
|
+
| Component | Description |
|
|
58
|
+
| --------------- | ------------------------ |
|
|
59
|
+
| `Drawer.Header` | Header with close button |
|
|
60
|
+
| `Drawer.Body` | Scrollable content area |
|
|
61
|
+
| `Drawer.Footer` | Action buttons area |
|
|
62
|
+
|
|
34
63
|
## Guidelines
|
|
35
64
|
|
|
36
65
|
- Use for side panels, settings, or detail views.
|
|
37
66
|
- `side="left"` for navigation drawers, `side="right"` for actions/details.
|
|
38
67
|
- Closes on Escape key and overlay click.
|
|
39
68
|
- Use `variant="solid"` for high-emphasis content.
|
|
69
|
+
- Use composition API when you need custom header content (icons, badges, etc.).
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Import
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
import { Modal
|
|
6
|
+
import { Modal } from "doom-design-system";
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## Props
|
|
@@ -18,7 +18,7 @@ import { Modal, ModalHeader, ModalBody, ModalFooter } from "doom-design-system";
|
|
|
18
18
|
|
|
19
19
|
## Usage Patterns
|
|
20
20
|
|
|
21
|
-
### Shorthand API (
|
|
21
|
+
### Shorthand API (simple modals)
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
<Modal
|
|
@@ -38,24 +38,32 @@ import { Modal, ModalHeader, ModalBody, ModalFooter } from "doom-design-system";
|
|
|
38
38
|
</Modal>
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
### Composition API (
|
|
41
|
+
### Composition API (custom layouts)
|
|
42
42
|
|
|
43
43
|
```tsx
|
|
44
44
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
45
|
-
<
|
|
45
|
+
<Modal.Header>
|
|
46
46
|
<Text variant="h3">Custom Title</Text>
|
|
47
|
-
</
|
|
48
|
-
<
|
|
47
|
+
</Modal.Header>
|
|
48
|
+
<Modal.Body>
|
|
49
49
|
<Stack gap={4}>
|
|
50
50
|
<Text>Custom body content...</Text>
|
|
51
51
|
</Stack>
|
|
52
|
-
</
|
|
53
|
-
<
|
|
52
|
+
</Modal.Body>
|
|
53
|
+
<Modal.Footer>
|
|
54
54
|
<Button onClick={onClose}>Close</Button>
|
|
55
|
-
</
|
|
55
|
+
</Modal.Footer>
|
|
56
56
|
</Modal>
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
## Sub-components
|
|
60
|
+
|
|
61
|
+
| Component | Description |
|
|
62
|
+
| -------------- | ------------------------ |
|
|
63
|
+
| `Modal.Header` | Header with close button |
|
|
64
|
+
| `Modal.Body` | Scrollable content area |
|
|
65
|
+
| `Modal.Footer` | Action buttons area |
|
|
66
|
+
|
|
59
67
|
## Guidelines
|
|
60
68
|
|
|
61
69
|
- Use `variant="solid"` for high-impact announcements or critical alerts.
|
|
@@ -12,35 +12,60 @@ import { Sheet } from "doom-design-system";
|
|
|
12
12
|
| ---------- | ---------------------- | ----------- | ------------------- |
|
|
13
13
|
| `isOpen` | `boolean` | required | Controls visibility |
|
|
14
14
|
| `onClose` | `() => void` | required | Close callback |
|
|
15
|
-
| `title` | `
|
|
15
|
+
| `title` | `ReactNode` | — | Header title |
|
|
16
16
|
| `children` | `ReactNode` | required | Sheet content |
|
|
17
17
|
| `footer` | `ReactNode` | — | Footer content |
|
|
18
18
|
| `variant` | `"default" \| "solid"` | `"default"` | Visual style |
|
|
19
19
|
|
|
20
|
-
## Usage
|
|
20
|
+
## Usage Patterns
|
|
21
|
+
|
|
22
|
+
### Shorthand API (simple sheets)
|
|
21
23
|
|
|
22
24
|
```tsx
|
|
23
25
|
<Sheet
|
|
24
26
|
isOpen={isOpen}
|
|
25
27
|
onClose={() => setIsOpen(false)}
|
|
26
|
-
title="
|
|
27
|
-
footer={
|
|
28
|
-
<Flex gap={2}>
|
|
29
|
-
<Button variant="ghost" onClick={reset}>
|
|
30
|
-
Reset
|
|
31
|
-
</Button>
|
|
32
|
-
<Button onClick={apply}>Apply</Button>
|
|
33
|
-
</Flex>
|
|
34
|
-
}
|
|
28
|
+
title="Options"
|
|
29
|
+
footer={<Button onClick={handleConfirm}>Confirm</Button>}
|
|
35
30
|
>
|
|
36
|
-
<
|
|
31
|
+
<RadioGroup options={options} />
|
|
32
|
+
</Sheet>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Composition API (custom layouts)
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<Sheet isOpen={isOpen} onClose={onClose}>
|
|
39
|
+
<Sheet.Header>
|
|
40
|
+
<Flex align="center" gap={2}>
|
|
41
|
+
<Icon name="settings" />
|
|
42
|
+
<Text variant="h4">Advanced Options</Text>
|
|
43
|
+
</Flex>
|
|
44
|
+
</Sheet.Header>
|
|
45
|
+
<Sheet.Body>
|
|
46
|
+
<Stack gap={4}>{/* Custom content */}</Stack>
|
|
47
|
+
</Sheet.Body>
|
|
48
|
+
<Sheet.Footer>
|
|
49
|
+
<Button variant="ghost" onClick={onClose}>
|
|
50
|
+
Cancel
|
|
51
|
+
</Button>
|
|
52
|
+
<Button onClick={handleSave}>Apply</Button>
|
|
53
|
+
</Sheet.Footer>
|
|
37
54
|
</Sheet>
|
|
38
55
|
```
|
|
39
56
|
|
|
57
|
+
## Sub-components
|
|
58
|
+
|
|
59
|
+
| Component | Description |
|
|
60
|
+
| -------------- | ----------------------- |
|
|
61
|
+
| `Sheet.Header` | Header with drag handle |
|
|
62
|
+
| `Sheet.Body` | Scrollable content area |
|
|
63
|
+
| `Sheet.Footer` | Action buttons area |
|
|
64
|
+
|
|
40
65
|
## Guidelines
|
|
41
66
|
|
|
42
|
-
-
|
|
43
|
-
- Supports drag-to-dismiss gesture (
|
|
67
|
+
- Use for bottom sheets on mobile or compact overlays.
|
|
68
|
+
- Supports drag-to-dismiss gesture (drag down 150px+ to close).
|
|
44
69
|
- Closes on Escape key and overlay click.
|
|
45
|
-
- Use for
|
|
46
|
-
-
|
|
70
|
+
- Use `variant="solid"` for high-emphasis content.
|
|
71
|
+
- Use composition API when you need custom header content.
|
|
@@ -9,23 +9,24 @@ import { ColumnDef } from "@tanstack/react-table";
|
|
|
9
9
|
|
|
10
10
|
## Props
|
|
11
11
|
|
|
12
|
-
| Prop | Type | Default | Description
|
|
13
|
-
| ------------------------- | -------------------------------------- | ------------ |
|
|
14
|
-
| `data` | `T[]` | required | Array of row data
|
|
15
|
-
| `columns` | `ColumnDef<T>[]` | required | TanStack column definitions
|
|
16
|
-
| `enablePagination` | `boolean` | `true` | Enable pagination controls
|
|
17
|
-
| `enableFiltering` | `boolean` | `true` | Enable global search
|
|
18
|
-
| `enableColumnFilters` | `boolean` | `true` | Enable per-column filters
|
|
19
|
-
| `enableSorting` | `boolean` | `true` | Enable column sorting
|
|
20
|
-
| `enableVirtualization` | `boolean` | `false` | Virtualize rows for large datasets
|
|
21
|
-
| `enableAdvancedFiltering` | `boolean` | `false` | Enable FilterBuilder UI
|
|
22
|
-
| `pageSize` | `number` | `10` | Default rows per page
|
|
23
|
-
| `height` | `string \| number` | — | Fixed height (
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
| ------------------------- | -------------------------------------- | ------------ | ---------------------------------------------- |
|
|
14
|
+
| `data` | `T[]` | required | Array of row data |
|
|
15
|
+
| `columns` | `ColumnDef<T>[]` | required | TanStack column definitions |
|
|
16
|
+
| `enablePagination` | `boolean` | `true` | Enable pagination controls |
|
|
17
|
+
| `enableFiltering` | `boolean` | `true` | Enable global search |
|
|
18
|
+
| `enableColumnFilters` | `boolean` | `true` | Enable per-column filters |
|
|
19
|
+
| `enableSorting` | `boolean` | `true` | Enable column sorting |
|
|
20
|
+
| `enableVirtualization` | `boolean` | `false` | Virtualize rows for large datasets |
|
|
21
|
+
| `enableAdvancedFiltering` | `boolean` | `false` | Enable FilterBuilder UI |
|
|
22
|
+
| `pageSize` | `number` | `10` | Default rows per page |
|
|
23
|
+
| `height` | `string \| number` | — | Fixed height (scrolls body with sticky header) |
|
|
24
|
+
| `maxHeight` | `string \| number` | — | Max height (scrolls body with sticky header) |
|
|
25
|
+
| `variant` | `"default" \| "flat"` | `"default"` | Visual style |
|
|
26
|
+
| `density` | `"compact" \| "standard" \| "relaxed"` | `"standard"` | Row padding |
|
|
27
|
+
| `striped` | `boolean` | `false` | Alternating row colors |
|
|
28
|
+
| `filters` | `FilterConfig[]` | — | Filter definitions for advanced filtering |
|
|
29
|
+
| `toolbarContent` | `ReactNode` | — | Custom toolbar content |
|
|
29
30
|
|
|
30
31
|
## Column Definition
|
|
31
32
|
|
|
@@ -201,7 +201,7 @@ export function Combobox({ options, value, onChange, placeholder = "Select...",
|
|
|
201
201
|
if (inline) {
|
|
202
202
|
return dropdownContent;
|
|
203
203
|
}
|
|
204
|
-
return (_jsx(Popover, { content: dropdownContent, isOpen: isOpen, placement: "bottom-start", trigger: _jsxs("button", { className: clsx(styles.trigger, styles[size], hasValue && styles.hasValue, disabled && styles.disabled, className), disabled: disabled, type: "button", onClick: handleOpen, children: [_jsx(Text, { as: "span", className: styles.triggerText, children: displayText }), _jsxs("span", { className: styles.triggerIcons, children: [hasValue && !disabled && (_jsx("span", { className: styles.clearButton, role: "button", tabIndex: 0, onClick: handleClear, onKeyDown: (e) => {
|
|
204
|
+
return (_jsx(Popover, { content: dropdownContent, isOpen: isOpen, placement: "bottom-start", trigger: _jsxs("button", { "aria-expanded": isOpen, className: clsx(styles.trigger, styles[size], hasValue && styles.hasValue, disabled && styles.disabled, className), disabled: disabled, type: "button", onClick: handleOpen, children: [_jsx(Text, { as: "span", className: styles.triggerText, children: displayText }), _jsxs("span", { className: styles.triggerIcons, children: [hasValue && !disabled && (_jsx("span", { className: styles.clearButton, role: "button", tabIndex: 0, onClick: handleClear, onKeyDown: (e) => {
|
|
205
205
|
if (e.key === "Enter") {
|
|
206
206
|
handleClear(e);
|
|
207
207
|
}
|
|
@@ -8,15 +8,24 @@
|
|
|
8
8
|
align-items: center;
|
|
9
9
|
justify-content: space-between;
|
|
10
10
|
width: 100%;
|
|
11
|
-
padding: var(--spacing-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
padding: var(--spacing-md) var(--spacing-lg);
|
|
12
|
+
background: var(--card-bg);
|
|
13
|
+
font-size: var(--text-base);
|
|
14
|
+
font-weight: var(--font-bold);
|
|
15
|
+
text-transform: uppercase;
|
|
16
|
+
letter-spacing: 0.05em;
|
|
14
17
|
text-align: left;
|
|
15
18
|
cursor: pointer;
|
|
19
|
+
min-height: var(--size-lg);
|
|
16
20
|
transition: all var(--duration-fast) var(--ease-in-out);
|
|
17
21
|
}
|
|
22
|
+
.trigger:hover {
|
|
23
|
+
transform: translate(-2px, -2px);
|
|
24
|
+
box-shadow: 6px 6px 0px 0px var(--shadow-base);
|
|
25
|
+
}
|
|
18
26
|
.trigger.sm {
|
|
19
|
-
padding: var(--spacing-
|
|
27
|
+
padding: var(--spacing-sm) var(--spacing-md);
|
|
28
|
+
min-height: var(--size-md);
|
|
20
29
|
font-size: var(--text-xs);
|
|
21
30
|
}
|
|
22
31
|
.trigger.hasValue {
|
|
@@ -78,6 +87,9 @@
|
|
|
78
87
|
max-width: 320px;
|
|
79
88
|
padding: 0;
|
|
80
89
|
overflow: hidden;
|
|
90
|
+
border: var(--border-width) solid var(--primary);
|
|
91
|
+
border-radius: var(--radius);
|
|
92
|
+
background: var(--card-bg);
|
|
81
93
|
}
|
|
82
94
|
|
|
83
95
|
.searchWrapper {
|
|
@@ -119,6 +131,10 @@
|
|
|
119
131
|
max-height: 240px;
|
|
120
132
|
overflow-y: auto;
|
|
121
133
|
padding: var(--spacing-xs);
|
|
134
|
+
padding-bottom: var(--spacing-sm);
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: column;
|
|
137
|
+
gap: var(--spacing-xs);
|
|
122
138
|
}
|
|
123
139
|
.optionsList::-webkit-scrollbar {
|
|
124
140
|
width: 6px;
|
|
@@ -128,7 +144,7 @@
|
|
|
128
144
|
}
|
|
129
145
|
.optionsList::-webkit-scrollbar-thumb {
|
|
130
146
|
background: var(--border);
|
|
131
|
-
border-radius:
|
|
147
|
+
border-radius: var(--radius-sm);
|
|
132
148
|
}
|
|
133
149
|
.optionsList::-webkit-scrollbar-thumb:hover {
|
|
134
150
|
background: var(--muted-foreground);
|
|
@@ -139,31 +155,31 @@
|
|
|
139
155
|
align-items: center;
|
|
140
156
|
gap: var(--spacing-sm);
|
|
141
157
|
width: 100%;
|
|
142
|
-
padding: var(--spacing-
|
|
143
|
-
margin-bottom: 2px;
|
|
158
|
+
padding: var(--spacing-sm) var(--spacing-md);
|
|
144
159
|
border: none;
|
|
145
|
-
border-radius: var(--radius-
|
|
146
|
-
background: transparent;
|
|
147
|
-
border-radius: var(--radius-sm);
|
|
160
|
+
border-radius: calc(var(--radius) - 2px);
|
|
148
161
|
background: transparent;
|
|
149
162
|
text-align: left;
|
|
150
163
|
color: var(--foreground);
|
|
151
164
|
cursor: pointer;
|
|
165
|
+
font-size: var(--text-base);
|
|
166
|
+
font-weight: var(--font-regular);
|
|
152
167
|
transition: all var(--duration-fast) var(--ease-in-out);
|
|
168
|
+
user-select: none;
|
|
153
169
|
}
|
|
154
170
|
.option:hover {
|
|
155
|
-
background: var(--
|
|
171
|
+
background-color: color-mix(in srgb, var(--primary), transparent 85%);
|
|
172
|
+
color: color-mix(in srgb, var(--primary), var(--foreground) 25%);
|
|
156
173
|
}
|
|
157
174
|
.option.selected {
|
|
158
|
-
background:
|
|
159
|
-
color: var(--primary);
|
|
160
|
-
font-weight:
|
|
175
|
+
background: var(--primary);
|
|
176
|
+
color: var(--primary-foreground);
|
|
177
|
+
font-weight: var(--font-bold);
|
|
161
178
|
}
|
|
162
179
|
.option.selected:hover {
|
|
163
|
-
background:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
margin-bottom: 0;
|
|
180
|
+
background-color: var(--primary);
|
|
181
|
+
color: var(--primary-foreground);
|
|
182
|
+
filter: brightness(1.1);
|
|
167
183
|
}
|
|
168
184
|
|
|
169
185
|
.optionLabel {
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
interface DrawerHeaderProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
className?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function DrawerHeader({ children, className, id }: DrawerHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function DrawerBody({ children, className, }: {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function DrawerFooter({ children, className, }: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
2
16
|
interface DrawerProps {
|
|
3
17
|
isOpen: boolean;
|
|
4
18
|
onClose: () => void;
|
|
5
|
-
title?:
|
|
19
|
+
title?: React.ReactNode;
|
|
6
20
|
side?: "left" | "right";
|
|
7
21
|
children: React.ReactNode;
|
|
8
22
|
footer?: React.ReactNode;
|
|
9
23
|
className?: string;
|
|
10
24
|
variant?: "default" | "solid";
|
|
11
25
|
}
|
|
12
|
-
|
|
26
|
+
declare function DrawerInternal({ isOpen, onClose, title, side, children, footer, className, variant, }: DrawerProps): React.ReactPortal | null;
|
|
27
|
+
export declare const Drawer: typeof DrawerInternal & {
|
|
28
|
+
Header: typeof DrawerHeader;
|
|
29
|
+
Body: typeof DrawerBody;
|
|
30
|
+
Footer: typeof DrawerFooter;
|
|
31
|
+
};
|
|
13
32
|
export {};
|
|
@@ -5,8 +5,24 @@ import { X } from "lucide-react";
|
|
|
5
5
|
import React, { useEffect, useState } from "react";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
7
7
|
import { Button } from "../Button/Button.js";
|
|
8
|
+
import { Flex } from "../Layout/Layout.js";
|
|
8
9
|
import styles from "./Drawer.module.css";
|
|
9
|
-
|
|
10
|
+
// Context for composition API
|
|
11
|
+
const DrawerContext = React.createContext({
|
|
12
|
+
onClose: () => { },
|
|
13
|
+
variant: "default",
|
|
14
|
+
});
|
|
15
|
+
export function DrawerHeader({ children, className, id }) {
|
|
16
|
+
const { onClose, titleId } = React.useContext(DrawerContext);
|
|
17
|
+
return (_jsxs(Flex, { align: "center", className: clsx(styles.header, className), justify: "space-between", children: [_jsx("div", { className: styles.headerContent, id: id || titleId, children: children }), _jsx(Button, { "aria-label": "Close drawer", size: "sm", variant: "danger", onClick: onClose, children: _jsx(X, { size: 24 }) })] }));
|
|
18
|
+
}
|
|
19
|
+
export function DrawerBody({ children, className, }) {
|
|
20
|
+
return _jsx("div", { className: clsx(styles.content, className), children: children });
|
|
21
|
+
}
|
|
22
|
+
export function DrawerFooter({ children, className, }) {
|
|
23
|
+
return (_jsx(Flex, { align: "center", className: clsx(styles.footer, className), gap: 4, justify: "flex-end", children: children }));
|
|
24
|
+
}
|
|
25
|
+
function DrawerInternal({ isOpen, onClose, title, side = "right", children, footer, className, variant = "default", }) {
|
|
10
26
|
const reactId = React.useId();
|
|
11
27
|
const titleId = `drawer-title-${reactId}`;
|
|
12
28
|
const [mounted, setMounted] = useState(false);
|
|
@@ -36,5 +52,11 @@ export function Drawer({ isOpen, onClose, title, side = "right", children, foote
|
|
|
36
52
|
if (!mounted) {
|
|
37
53
|
return null;
|
|
38
54
|
}
|
|
39
|
-
return createPortal(_jsxs(
|
|
55
|
+
return createPortal(_jsxs(DrawerContext.Provider, { value: { onClose, titleId, variant }, children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.overlay, isOpen && styles.isOpen), onClick: onClose }), _jsx("div", { "aria-label": !title ? "Drawer" : undefined, "aria-labelledby": title ? titleId : undefined, "aria-modal": "true", className: clsx(styles.panel, styles[side], styles[variant], isOpen && styles.isOpen, className), role: "dialog", children: title ? (_jsxs(_Fragment, { children: [_jsx(DrawerHeader, { children: title }), _jsx(DrawerBody, { children: children }), footer && _jsx(DrawerFooter, { children: footer })] })) : (children) })] }), document.body);
|
|
40
56
|
}
|
|
57
|
+
// Namespace export pattern (like Chart)
|
|
58
|
+
export const Drawer = Object.assign(DrawerInternal, {
|
|
59
|
+
Header: DrawerHeader,
|
|
60
|
+
Body: DrawerBody,
|
|
61
|
+
Footer: DrawerFooter,
|
|
62
|
+
});
|
|
@@ -12,14 +12,19 @@ interface ModalHeaderProps {
|
|
|
12
12
|
className?: string;
|
|
13
13
|
id?: string;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
declare function ModalHeader({ children, className, id }: ModalHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare function ModalBody({ children, className, }: {
|
|
17
17
|
children: React.ReactNode;
|
|
18
18
|
className?: string;
|
|
19
19
|
}): import("react/jsx-runtime").JSX.Element;
|
|
20
|
-
|
|
20
|
+
declare function ModalFooter({ children, className, }: {
|
|
21
21
|
children: React.ReactNode;
|
|
22
22
|
className?: string;
|
|
23
23
|
}): import("react/jsx-runtime").JSX.Element;
|
|
24
|
-
|
|
24
|
+
declare function ModalInternal({ isOpen, onClose, title, children, footer, className, style, variant, ...props }: ModalProps): React.ReactPortal | null;
|
|
25
|
+
export declare const Modal: typeof ModalInternal & {
|
|
26
|
+
Header: typeof ModalHeader;
|
|
27
|
+
Body: typeof ModalBody;
|
|
28
|
+
Footer: typeof ModalFooter;
|
|
29
|
+
};
|
|
25
30
|
export {};
|
|
@@ -23,17 +23,17 @@ const ModalContext = React.createContext({
|
|
|
23
23
|
onClose: () => { },
|
|
24
24
|
variant: "default",
|
|
25
25
|
});
|
|
26
|
-
|
|
26
|
+
function ModalHeader({ children, className, id }) {
|
|
27
27
|
const { onClose, titleId } = React.useContext(ModalContext);
|
|
28
28
|
return (_jsxs(Flex, { align: "center", className: clsx(styles.header, className), justify: "space-between", children: [_jsx("div", { className: styles.headerContent, id: id || titleId, children: children }), _jsx(Button, { "aria-label": "Close modal", className: styles.closeButton, size: "sm", variant: "danger", onClick: onClose, children: _jsx(X, { size: 20, strokeWidth: 2.5 }) })] }));
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
function ModalBody({ children, className, }) {
|
|
31
31
|
return _jsx("div", { className: clsx(styles.body, className), children: children });
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
function ModalFooter({ children, className, }) {
|
|
34
34
|
return (_jsx(Flex, { align: "center", className: clsx(styles.footer, className), gap: 4, justify: "flex-end", children: children }));
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
function ModalInternal(_a) {
|
|
37
37
|
var { isOpen, onClose, title, children, footer, className, style, variant = "default" } = _a, props = __rest(_a, ["isOpen", "onClose", "title", "children", "footer", "className", "style", "variant"]);
|
|
38
38
|
const overlayRef = useRef(null);
|
|
39
39
|
const reactId = useId();
|
|
@@ -71,3 +71,9 @@ export function Modal(_a) {
|
|
|
71
71
|
return createPortal(_jsx(ModalContext.Provider, { value: { onClose, titleId, variant }, children: _jsx("div", { ref: overlayRef, className: clsx(styles.overlay, isOpen && styles.isOpen, className), style: style, onClick: handleOverlayClick, children: _jsx("div", { className: styles.contentContainer, children: _jsx("div", Object.assign({ "aria-label": props["aria-label"] ||
|
|
72
72
|
(!title && !props["aria-labelledby"] ? "Modal Window" : undefined), "aria-labelledby": title ? titleId : props["aria-labelledby"], "aria-modal": "true", role: "dialog" }, props, { children: _jsx(Card, { className: clsx(styles.modalCard, styles[variant]), style: { padding: 0, overflow: "hidden" }, children: title ? (_jsxs(_Fragment, { children: [_jsx(ModalHeader, { children: title }), _jsxs(Stack, { className: styles.modalContent, gap: 0, children: [_jsx(ModalBody, { children: children }), footer && _jsx(ModalFooter, { children: footer })] })] })) : (children) }) })) }) }) }), document.body);
|
|
73
73
|
}
|
|
74
|
+
// Namespace export pattern (like Chart)
|
|
75
|
+
export const Modal = Object.assign(ModalInternal, {
|
|
76
|
+
Header: ModalHeader,
|
|
77
|
+
Body: ModalBody,
|
|
78
|
+
Footer: ModalFooter,
|
|
79
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { Modal } from "./Modal";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { Modal } from "./Modal.js";
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
width: 100%;
|
|
10
10
|
background: var(--card-bg);
|
|
11
11
|
color: var(--foreground);
|
|
12
|
-
padding:
|
|
12
|
+
padding: var(--spacing-md) var(--spacing-lg);
|
|
13
13
|
font-size: var(--text-base);
|
|
14
14
|
cursor: pointer;
|
|
15
15
|
display: flex;
|
|
16
16
|
justify-content: space-between;
|
|
17
17
|
align-items: center;
|
|
18
|
-
font-weight:
|
|
18
|
+
font-weight: var(--font-bold);
|
|
19
19
|
text-transform: uppercase;
|
|
20
20
|
letter-spacing: 0.05em;
|
|
21
|
-
min-height:
|
|
21
|
+
min-height: var(--size-lg);
|
|
22
22
|
border: var(--border-width) solid var(--card-border);
|
|
23
23
|
border-radius: var(--radius);
|
|
24
24
|
box-shadow: var(--shadow-hard);
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
outline: none;
|
|
40
40
|
}
|
|
41
41
|
.trigger.sm {
|
|
42
|
-
padding:
|
|
43
|
-
min-height:
|
|
44
|
-
font-size:
|
|
42
|
+
padding: var(--spacing-sm) var(--spacing-md);
|
|
43
|
+
min-height: var(--size-md);
|
|
44
|
+
font-size: var(--text-xs);
|
|
45
45
|
text-transform: uppercase;
|
|
46
46
|
letter-spacing: 0.05em;
|
|
47
47
|
}
|
|
@@ -56,23 +56,23 @@
|
|
|
56
56
|
overflow-y: auto;
|
|
57
57
|
display: flex;
|
|
58
58
|
flex-direction: column;
|
|
59
|
-
gap:
|
|
60
|
-
padding:
|
|
59
|
+
gap: var(--spacing-xs);
|
|
60
|
+
padding: var(--spacing-xs);
|
|
61
61
|
margin: 0;
|
|
62
62
|
list-style: none;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
.optionItem {
|
|
66
66
|
text-align: left;
|
|
67
|
-
padding:
|
|
67
|
+
padding: var(--spacing-md) var(--spacing-lg);
|
|
68
68
|
background: transparent;
|
|
69
69
|
border: none;
|
|
70
70
|
border-radius: calc(var(--radius) - 2px);
|
|
71
71
|
color: var(--foreground);
|
|
72
72
|
cursor: pointer;
|
|
73
73
|
font-size: var(--text-base);
|
|
74
|
-
font-weight:
|
|
75
|
-
transition: all
|
|
74
|
+
font-weight: var(--font-regular);
|
|
75
|
+
transition: all var(--duration-fast) var(--ease-in-out);
|
|
76
76
|
width: 100%;
|
|
77
77
|
display: flex;
|
|
78
78
|
align-items: center;
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
.optionItem.selected {
|
|
91
91
|
background: var(--primary);
|
|
92
92
|
color: var(--primary-foreground);
|
|
93
|
-
font-weight:
|
|
93
|
+
font-weight: var(--font-bold);
|
|
94
94
|
}
|
|
95
95
|
.optionItem.selected:hover {
|
|
96
96
|
background-color: var(--primary);
|
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
interface SheetHeaderProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
className?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function SheetHeader({ children, className, id }: SheetHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function SheetBody({ children, className, }: {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function SheetFooter({ children, className, }: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
2
16
|
interface SheetProps {
|
|
3
17
|
isOpen: boolean;
|
|
4
18
|
onClose: () => void;
|
|
5
|
-
title?:
|
|
19
|
+
title?: React.ReactNode;
|
|
6
20
|
children: React.ReactNode;
|
|
7
21
|
footer?: React.ReactNode;
|
|
8
22
|
variant?: "default" | "solid";
|
|
9
23
|
className?: string;
|
|
10
24
|
}
|
|
11
|
-
|
|
25
|
+
declare function SheetInternal({ isOpen, onClose, title, children, footer, variant, className, }: SheetProps): React.ReactPortal | null;
|
|
26
|
+
export declare const Sheet: typeof SheetInternal & {
|
|
27
|
+
Header: typeof SheetHeader;
|
|
28
|
+
Body: typeof SheetBody;
|
|
29
|
+
Footer: typeof SheetFooter;
|
|
30
|
+
};
|
|
12
31
|
export {};
|
|
@@ -7,7 +7,23 @@ import { createPortal } from "react-dom";
|
|
|
7
7
|
import { Button } from "../Button/Button.js";
|
|
8
8
|
import { Flex } from "../Layout/Layout.js";
|
|
9
9
|
import styles from "./Sheet.module.css";
|
|
10
|
-
|
|
10
|
+
// Context for composition API
|
|
11
|
+
const SheetContext = React.createContext({
|
|
12
|
+
onClose: () => { },
|
|
13
|
+
variant: "default",
|
|
14
|
+
handlePointerDown: () => { },
|
|
15
|
+
});
|
|
16
|
+
export function SheetHeader({ children, className, id }) {
|
|
17
|
+
const { onClose, titleId, handlePointerDown } = React.useContext(SheetContext);
|
|
18
|
+
return (_jsxs("div", { className: clsx(styles.header, className), onPointerDown: handlePointerDown, children: [_jsx("div", { className: styles.handleBar }), _jsxs(Flex, { align: "center", className: styles.headerBody, justify: "space-between", children: [_jsx("div", { className: styles.headerContent, id: id || titleId, children: children }), _jsx(Button, { "aria-label": "Close sheet", size: "sm", variant: "danger", onClick: onClose, children: _jsx(X, { size: 24 }) })] })] }));
|
|
19
|
+
}
|
|
20
|
+
export function SheetBody({ children, className, }) {
|
|
21
|
+
return _jsx("div", { className: clsx(styles.content, className), children: children });
|
|
22
|
+
}
|
|
23
|
+
export function SheetFooter({ children, className, }) {
|
|
24
|
+
return (_jsx(Flex, { align: "center", className: clsx(styles.footer, className), gap: 4, justify: "flex-end", children: children }));
|
|
25
|
+
}
|
|
26
|
+
function SheetInternal({ isOpen, onClose, title, children, footer, variant = "default", className, }) {
|
|
11
27
|
const reactId = React.useId();
|
|
12
28
|
const titleId = `sheet-title-${reactId}`;
|
|
13
29
|
const [mounted, setMounted] = useState(false);
|
|
@@ -100,5 +116,11 @@ export function Sheet({ isOpen, onClose, title, children, footer, variant = "def
|
|
|
100
116
|
if (!mounted) {
|
|
101
117
|
return null;
|
|
102
118
|
}
|
|
103
|
-
return createPortal(_jsxs(
|
|
119
|
+
return createPortal(_jsxs(SheetContext.Provider, { value: { onClose, titleId, variant, handlePointerDown }, children: [_jsx("div", { "aria-hidden": "true", className: clsx(styles.overlay, isOpen && styles.isOpen), onClick: onClose }), _jsx("div", { ref: panelRef, "aria-label": !title ? "Sheet" : undefined, "aria-labelledby": title ? titleId : undefined, "aria-modal": "true", className: clsx(styles.panel, styles[variant], isOpen && styles.isOpen, className), role: "dialog", children: title ? (_jsxs(_Fragment, { children: [_jsx(SheetHeader, { children: title }), _jsx(SheetBody, { children: children }), footer && _jsx(SheetFooter, { children: footer })] })) : (children) })] }), document.body);
|
|
104
120
|
}
|
|
121
|
+
// Namespace export pattern (like Chart)
|
|
122
|
+
export const Sheet = Object.assign(SheetInternal, {
|
|
123
|
+
Header: SheetHeader,
|
|
124
|
+
Body: SheetBody,
|
|
125
|
+
Footer: SheetFooter,
|
|
126
|
+
});
|