native-document 1.0.166 → 1.0.168
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/.vitepress/config.js +166 -0
- package/CHANGELOG.md +153 -0
- package/components.js +2 -1
- package/dist/native-document.components.min.js +495 -228
- package/dist/native-document.dev.js +7 -0
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/advanced-components.md +213 -608
- package/docs/anchor.md +173 -312
- package/docs/cache.md +95 -803
- package/docs/cli.md +179 -0
- package/docs/components/accordion.md +172 -0
- package/docs/components/alert.md +99 -0
- package/docs/components/avatar.md +160 -0
- package/docs/components/badge.md +102 -0
- package/docs/components/breadcrumb.md +89 -0
- package/docs/components/button.md +183 -0
- package/docs/components/card.md +69 -0
- package/docs/components/context-menu.md +118 -0
- package/docs/components/data-table.md +345 -0
- package/docs/components/dropdown.md +214 -0
- package/docs/components/form/autocomplete-field.md +81 -0
- package/docs/components/form/checkbox-field.md +41 -0
- package/docs/components/form/checkbox-group-field.md +54 -0
- package/docs/components/form/color-field.md +64 -0
- package/docs/components/form/date-field.md +92 -0
- package/docs/components/form/field-collection.md +63 -0
- package/docs/components/form/file-field.md +203 -0
- package/docs/components/form/form-control.md +87 -0
- package/docs/components/form/image-field.md +90 -0
- package/docs/components/form/index.md +115 -0
- package/docs/components/form/number-field.md +65 -0
- package/docs/components/form/radio-field.md +51 -0
- package/docs/components/form/select-field.md +123 -0
- package/docs/components/form/slider.md +136 -0
- package/docs/components/form/string-field.md +134 -0
- package/docs/components/form/textarea-field.md +65 -0
- package/docs/components/form-fields.md +372 -0
- package/docs/components/getting-started.md +264 -0
- package/docs/components/index.md +337 -0
- package/docs/components/layout.md +279 -0
- package/docs/components/list.md +73 -0
- package/docs/components/menu.md +215 -0
- package/docs/components/modal.md +156 -0
- package/docs/components/pagination.md +95 -0
- package/docs/components/popover.md +131 -0
- package/docs/components/progress.md +111 -0
- package/docs/components/shortcut-manager.md +221 -0
- package/docs/components/simple-table.md +107 -0
- package/docs/components/skeleton.md +155 -0
- package/docs/components/spinner.md +100 -0
- package/docs/components/splitter.md +133 -0
- package/docs/components/stepper.md +163 -0
- package/docs/components/switch.md +113 -0
- package/docs/components/tabs.md +153 -0
- package/docs/components/toast.md +119 -0
- package/docs/components/tooltip.md +151 -0
- package/docs/components/traits.md +261 -0
- package/docs/conditional-rendering.md +170 -588
- package/docs/contributing.md +300 -25
- package/docs/core-concepts.md +205 -374
- package/docs/elements.md +251 -367
- package/docs/extending-native-document-element.md +192 -207
- package/docs/filters.md +153 -1122
- package/docs/getting-started.md +193 -267
- package/docs/i18n.md +241 -0
- package/docs/index.md +76 -0
- package/docs/lifecycle-events.md +143 -75
- package/docs/list-rendering.md +227 -852
- package/docs/memory-management.md +134 -47
- package/docs/native-document-element.md +337 -186
- package/docs/native-fetch.md +99 -630
- package/docs/observable-resource.md +364 -0
- package/docs/observables.md +592 -526
- package/docs/routing.md +244 -653
- package/docs/state-management.md +134 -241
- package/docs/svg-elements.md +231 -0
- package/docs/theming.md +409 -0
- package/docs/tutorials/.gitkeep +0 -0
- package/docs/validation.md +95 -97
- package/docs/vitepress-conventions.md +219 -0
- package/package.json +34 -13
- package/readme.md +269 -89
- package/src/components/card/Card.js +93 -39
- package/src/components/card/index.js +1 -1
- package/src/components/list/HasListItem.js +171 -0
- package/src/components/list/List.js +41 -107
- package/src/components/list/ListDivider.js +39 -0
- package/src/components/list/ListGroup.js +76 -59
- package/src/components/list/ListItem.js +117 -69
- package/src/components/list/index.js +3 -1
- package/src/components/list/types/ListItem.d.ts +45 -34
- package/src/components/spacer/Spacer.js +1 -1
- package/src/core/data/ObservableResource.js +5 -0
- package/src/core/data/observable-helpers/observable.prototypes.js +2 -0
- package/src/ui/components/card/CardRender.js +133 -0
- package/src/ui/components/card/card.css +169 -0
- package/src/ui/components/contextmenu/ContextmenuRender.js +1 -1
- package/src/ui/components/list/ListRender.js +18 -0
- package/src/ui/components/list/divider/ListDividerRender.js +10 -0
- package/src/ui/components/list/divider/list-divider.css +12 -0
- package/src/ui/components/list/group/ListGroupRender.js +61 -0
- package/src/ui/components/list/group/list-group.css +62 -0
- package/src/ui/components/list/item/ListItemRender.js +238 -0
- package/src/ui/components/list/item/list-item.css +191 -0
- package/src/ui/components/list/list.css +24 -0
- package/src/ui/components/spacer/SpacerRender.js +10 -0
- package/src/ui/index.js +8 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Breadcrumb
|
|
3
|
+
description: Breadcrumb navigation component with custom separators and click handlers
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Breadcrumb
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Breadcrumb } from 'native-document/components';
|
|
10
|
+
|
|
11
|
+
Breadcrumb(props?)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Default Renderer
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
import { BreadcrumbRender } from 'native-document/ui';
|
|
18
|
+
|
|
19
|
+
Breadcrumb.use(BreadcrumbRender);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Methods
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
// Add items
|
|
26
|
+
.item(label, href?, value?)
|
|
27
|
+
.items([{ label, href, value }, ...])
|
|
28
|
+
.removeItem(index)
|
|
29
|
+
|
|
30
|
+
// Bind to an observable array
|
|
31
|
+
.bind(Observable.array([...]))
|
|
32
|
+
|
|
33
|
+
// Separator
|
|
34
|
+
.separator('/')
|
|
35
|
+
.separator(ChevronIcon)
|
|
36
|
+
.renderSeparator(($description) => Span(' > '))
|
|
37
|
+
|
|
38
|
+
// Events
|
|
39
|
+
.onItemClick((item, index) => Router.push(item.href))
|
|
40
|
+
|
|
41
|
+
// Custom renderers
|
|
42
|
+
.renderItem(($item) => Link({ href: $item.href }, $item.label))
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Example
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
Breadcrumb()
|
|
49
|
+
.item('Home', '/')
|
|
50
|
+
.item('Products', '/products')
|
|
51
|
+
.item('Laptops', '/products/laptops')
|
|
52
|
+
.item('MacBook Pro') // current - no href
|
|
53
|
+
.separator('/')
|
|
54
|
+
.onItemClick((item) => {
|
|
55
|
+
if (item.href) {
|
|
56
|
+
Router.push(item.href);
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Reactive Binding
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const crumbs = Observable.array([
|
|
65
|
+
{ label: 'Home', href: '/' },
|
|
66
|
+
{ label: 'Products', href: '/products' }
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
Breadcrumb().bind(crumbs).separator(ChevronRight)
|
|
70
|
+
|
|
71
|
+
// Update dynamically
|
|
72
|
+
crumbs.push({ label: 'Laptops', href: '/products/laptops' });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Theming
|
|
78
|
+
|
|
79
|
+
```css
|
|
80
|
+
:root {
|
|
81
|
+
--breadcrumb-font-size: var(--description-size);
|
|
82
|
+
--breadcrumb-color: var(--gray);
|
|
83
|
+
--breadcrumb-color-active: var(--text-color);
|
|
84
|
+
--breadcrumb-color-hover: var(--color-primary);
|
|
85
|
+
--breadcrumb-separator-color: var(--gray-lite-2);
|
|
86
|
+
--breadcrumb-separator: '/';
|
|
87
|
+
--breadcrumb-gap: var(--space-cozy);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Button
|
|
3
|
+
description: Headless Button component with variants, sizes, loading state, icons, and presets
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Button
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Button } from 'native-document/components';
|
|
10
|
+
|
|
11
|
+
Button(label, props?)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Default Renderer
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
import { ButtonRender } from 'native-document/ui';
|
|
18
|
+
import { SpinnerRender } from 'native-document/ui';
|
|
19
|
+
|
|
20
|
+
Button.use(ButtonRender);
|
|
21
|
+
Spinner.use(SpinnerRender); // required - loading state is rendered as a spinner
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## `$description`
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
{
|
|
28
|
+
label: 'Submit',
|
|
29
|
+
type: null, // 'button' | 'submit' | 'reset'
|
|
30
|
+
variant: null,
|
|
31
|
+
size: null, // 'small' | 'medium' | 'large'
|
|
32
|
+
icon: null, // DOM element
|
|
33
|
+
iconPosition: 'leading', // 'leading' | 'trailing' | 'top' | 'bottom'
|
|
34
|
+
iconOnly: false,
|
|
35
|
+
loading: null, // Observable<boolean>
|
|
36
|
+
disabled: null, // Observable<boolean>
|
|
37
|
+
outline: false,
|
|
38
|
+
block: false,
|
|
39
|
+
borderRadiusType: null, // 'rounded' | 'pill' | 'circle' | 'smooth'
|
|
40
|
+
props: {} // HTML attributes for the root element
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Methods
|
|
45
|
+
|
|
46
|
+
### Variants
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
.primary()
|
|
50
|
+
.secondary()
|
|
51
|
+
.danger()
|
|
52
|
+
.success()
|
|
53
|
+
.warning()
|
|
54
|
+
.ghost()
|
|
55
|
+
.link()
|
|
56
|
+
.outline()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Size
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
.small()
|
|
63
|
+
.medium()
|
|
64
|
+
.large()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Shape
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
.rounded()
|
|
71
|
+
.pill()
|
|
72
|
+
.circle()
|
|
73
|
+
.smooth()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Icon
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
.icon(element, position?)
|
|
80
|
+
.iconAtLeading()
|
|
81
|
+
.iconAtTrailing()
|
|
82
|
+
.iconAtTop()
|
|
83
|
+
.iconAtBottom()
|
|
84
|
+
.iconOnly()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### State
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
.loading(observable | true)
|
|
91
|
+
.disabled(observable | true)
|
|
92
|
+
.block()
|
|
93
|
+
.type('submit')
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Example
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const isLoading = Observable(false);
|
|
100
|
+
|
|
101
|
+
Button('Save Changes')
|
|
102
|
+
.primary()
|
|
103
|
+
.large()
|
|
104
|
+
.rounded()
|
|
105
|
+
.loading(isLoading)
|
|
106
|
+
.icon(SaveIcon)
|
|
107
|
+
.nd
|
|
108
|
+
.onClick(async () => {
|
|
109
|
+
isLoading.set(true);
|
|
110
|
+
await save();
|
|
111
|
+
isLoading.set(false);
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Presets
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
Button.preset('save', (label, props) => {
|
|
119
|
+
return Button(label || 'Save', props).primary();
|
|
120
|
+
});
|
|
121
|
+
Button.preset('cancel', (label, props) => {
|
|
122
|
+
return Button(label || 'Cancel', props).ghost();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
Button.save()
|
|
126
|
+
Button.cancel('Go back')
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Custom Renderer Example
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
Button.use(($description) => {
|
|
133
|
+
return NativeButton({
|
|
134
|
+
type: $description.type || 'button',
|
|
135
|
+
class: buildClasses($description),
|
|
136
|
+
disabled: $description.disabled,
|
|
137
|
+
...$description.props
|
|
138
|
+
}, [
|
|
139
|
+
ShowIf($description.loading, () => Spinner()),
|
|
140
|
+
ShowIf($description.icon && $description.iconPosition === 'leading', () => $description.icon),
|
|
141
|
+
ShowIf(!$description.iconOnly, $description.label),
|
|
142
|
+
ShowIf($description.icon && $description.iconPosition === 'trailing', () => $description.icon),
|
|
143
|
+
]);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Theming
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
:root {
|
|
153
|
+
--btn-height-small: 28px;
|
|
154
|
+
--btn-height-medium: 36px;
|
|
155
|
+
--btn-height-large: 44px;
|
|
156
|
+
--btn-padding-small: 0 var(--space-cozy-comfortable);
|
|
157
|
+
--btn-padding-medium: 0 var(--space-comfortable);
|
|
158
|
+
--btn-padding-large: 0 var(--space-relaxed);
|
|
159
|
+
--btn-font-size-small: var(--note-size);
|
|
160
|
+
--btn-font-size-medium: var(--description-size);
|
|
161
|
+
--btn-font-size-large: var(--text-size);
|
|
162
|
+
--btn-icon-size-small: 14px;
|
|
163
|
+
--btn-icon-size-medium: 16px;
|
|
164
|
+
--btn-icon-size-large: 18px;
|
|
165
|
+
--btn-loader-size: 14px;
|
|
166
|
+
--btn-gap: var(--space-cozy);
|
|
167
|
+
--btn-font-weight: 500;
|
|
168
|
+
--btn-transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
|
|
169
|
+
--btn-disabled-opacity: 0.45;
|
|
170
|
+
--btn-color-primary: var(--color-primary);
|
|
171
|
+
--btn-color-primary-hover: var(--color-primary-hover);
|
|
172
|
+
--btn-color-secondary: var(--color-secondary);
|
|
173
|
+
--btn-color-secondary-hover: var(--color-secondary-hover);
|
|
174
|
+
--btn-color-danger: var(--color-danger);
|
|
175
|
+
--btn-color-danger-hover: var(--color-danger-hover);
|
|
176
|
+
--btn-color-success: var(--color-success);
|
|
177
|
+
--btn-color-success-hover: var(--color-success-hover);
|
|
178
|
+
--btn-color-warning: var(--color-warning);
|
|
179
|
+
--btn-color-warning-hover: var(--color-warning-hover);
|
|
180
|
+
--btn-color-info: var(--color-info);
|
|
181
|
+
--btn-color-info-hover: var(--color-info-hover);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Card
|
|
3
|
+
description: Versatile content container with optional image, header, footer, and actions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Card
|
|
7
|
+
|
|
8
|
+
> **Status: coming soon.** The `Card` API is fully defined but the default renderer is not yet implemented. You can use `Card` today by providing your own renderer via `Card.use()`.
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import { Card } from 'native-document/components';
|
|
12
|
+
|
|
13
|
+
Card(props?)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Custom Renderer
|
|
17
|
+
|
|
18
|
+
Until the default renderer ships, register your own:
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
import { Div, Img, H3, P, Button, HStack } from 'native-document/elements';
|
|
22
|
+
|
|
23
|
+
Card.use(($d, instance) => {
|
|
24
|
+
return Div({ class: `card ${$d.variant ?? ''}` }, [
|
|
25
|
+
$d.image ? Img({ src: $d.image.src, class: `card-image card-image-${$d.image.position}` }) : null,
|
|
26
|
+
Div({ class: 'card-body' }, [
|
|
27
|
+
$d.title ? H3({ class: 'card-title' }, $d.title) : null,
|
|
28
|
+
$d.subtitle ? P({ class: 'card-subtitle' }, $d.subtitle) : null,
|
|
29
|
+
$d.content ? Div({ class: 'card-content' }, $d.content) : null,
|
|
30
|
+
]),
|
|
31
|
+
$d.actions?.length ? HStack({ class: 'card-footer' },
|
|
32
|
+
$d.actions.map(a => Button(a.label).nd.onClick(a.callback))
|
|
33
|
+
) : null,
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Methods
|
|
39
|
+
|
|
40
|
+
| Method | Parameters | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `.title(element)` | `element: NdChild` | Card title |
|
|
43
|
+
| `.subtitle(element)` | `element: NdChild` | Card subtitle |
|
|
44
|
+
| `.image(src, position?)` | `src: string`, `position?: 'top' \| 'bottom' \| 'left' \| 'right'` | Card image. Default position: `'top'` |
|
|
45
|
+
| `.content(element)` | `element: NdChild` | Card body content |
|
|
46
|
+
| `.action(label, callback)` | `label: NdChild`, `callback: () => void` | Add a footer action button |
|
|
47
|
+
| `.clearActions()` | - | Remove all action buttons |
|
|
48
|
+
| `.variant(name)` | `name: string` | CSS variant class |
|
|
49
|
+
| `.elevated()` | - | Shorthand for `.variant('elevated')` |
|
|
50
|
+
| `.outlined()` | - | Shorthand for `.variant('outlined')` |
|
|
51
|
+
| `.flat()` | - | Shorthand for `.variant('flat')` |
|
|
52
|
+
| `.horizontal()` | - | Horizontal layout (image on the left) |
|
|
53
|
+
| `.clickable(handler)` | `handler: (event) => void` | Make the entire card clickable |
|
|
54
|
+
| `.hoverable()` | - | Add hover effect |
|
|
55
|
+
| `.loading(val?)` | `val?: boolean \| Observable<boolean>` | Show loading state |
|
|
56
|
+
| `.onClick(handler)` | `handler: (event) => void` | Click event |
|
|
57
|
+
| `.onHover(handler)` | `handler: (event) => void` | Hover event |
|
|
58
|
+
| `.renderImage(fn)` | `fn: ($d, instance) => NdChild` | Custom image renderer |
|
|
59
|
+
| `.renderHeader(fn)` | `fn: ($d, instance) => NdChild` | Custom header renderer |
|
|
60
|
+
| `.renderContent(fn)` | `fn: ($d, instance) => NdChild` | Custom content renderer |
|
|
61
|
+
| `.renderFooter(fn)` | `fn: ($d, instance) => NdChild` | Custom footer renderer |
|
|
62
|
+
| `.layout(fn)` | `fn: ($d, instance) => NdChild` | Fully custom layout |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Next Steps
|
|
67
|
+
|
|
68
|
+
- **[Components Overview](./index.md)** - BaseComponent and renderer pattern
|
|
69
|
+
- **[Getting Started](./getting-started.md)** - Register default renderers
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Context Menu
|
|
3
|
+
description: Right-click context menu with trigger binding, items, groups, and dividers
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context Menu
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { ContextMenu, ContextMenuGroup, ContextMenuItem } from 'native-document/components';
|
|
10
|
+
import { Menu, MenuGroup, MenuItem, MenuDivider, MenuLink } from 'native-document/components';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`ContextMenu.use()` takes two arguments - a renderer and a handler. The handler wires the right-click behavior to any element, making `.nd.contextMenu()` available on all elements.
|
|
14
|
+
|
|
15
|
+
## Default Renderer
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import {
|
|
19
|
+
ContextMenuRender, contextMenuHandler,
|
|
20
|
+
MenuRender, MenuGroupRender, MenuItemRender,
|
|
21
|
+
MenuDividerRender, MenuLinkRender
|
|
22
|
+
} from 'native-document/ui';
|
|
23
|
+
|
|
24
|
+
Menu.use(MenuRender);
|
|
25
|
+
MenuGroup.use(MenuGroupRender);
|
|
26
|
+
MenuItem.use(MenuItemRender);
|
|
27
|
+
MenuDivider.use(MenuDividerRender);
|
|
28
|
+
MenuLink.use(MenuLinkRender);
|
|
29
|
+
ContextMenu.use(ContextMenuRender, contextMenuHandler);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Building a Context Menu
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const tableContextMenu = ContextMenu()
|
|
36
|
+
.menu((menu) => {
|
|
37
|
+
menu
|
|
38
|
+
.item('Edit', { action: (data) => openEdit(data) })
|
|
39
|
+
.item('Duplicate', { action: (data) => duplicate(data) })
|
|
40
|
+
.divider()
|
|
41
|
+
// pass a function to get the MenuItem instance for fluent configuration
|
|
42
|
+
.item('Delete', (item) => {
|
|
43
|
+
item
|
|
44
|
+
.action((data) => deleteRow(data))
|
|
45
|
+
.icon(TrashIcon)
|
|
46
|
+
.shortcut('+Delete')
|
|
47
|
+
.danger()
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Attach to any element, pass contextual data
|
|
52
|
+
TableRow(item)
|
|
53
|
+
.nd.contextMenu(tableContextMenu, item)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Methods
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
.menu((menu) => { menu.item(...) })
|
|
60
|
+
.position(x, y)
|
|
61
|
+
.show()
|
|
62
|
+
.hide()
|
|
63
|
+
.trigger(element)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## `ContextMenuItem`
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
ContextMenuItem()
|
|
70
|
+
.label('Edit')
|
|
71
|
+
.icon(EditIcon)
|
|
72
|
+
.action((data) => openEditor(data))
|
|
73
|
+
.shortcut('+E') // short convention: + = meta/ctrl, ++ = meta+alt
|
|
74
|
+
.disabled(false)
|
|
75
|
+
.danger()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Shortcut convention
|
|
79
|
+
|
|
80
|
+
| Syntax | Meaning |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `'+S'` | Ctrl/Cmd + S |
|
|
83
|
+
| `'++S'` | Ctrl/Cmd + Alt + S |
|
|
84
|
+
| `'+Shift+S'` | Ctrl/Cmd + Shift + S |
|
|
85
|
+
| `'Ctrl+S'` | Standard form |
|
|
86
|
+
| `'Cmd+Shift+S'` | Standard form |
|
|
87
|
+
|
|
88
|
+
Shortcuts are displayed automatically per OS - Mac uses symbols (`⌘ S`), Windows uses labels (`Ctrl+S`).
|
|
89
|
+
|
|
90
|
+
See **[ShortcutManager](./shortcut-manager.md)** for the full reference.
|
|
91
|
+
|
|
92
|
+
## `ContextMenuGroup`
|
|
93
|
+
|
|
94
|
+
Groups items under a label:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
ContextMenuGroup('File actions')
|
|
98
|
+
.item('New', handler)
|
|
99
|
+
.item('Open', handler)
|
|
100
|
+
.divider()
|
|
101
|
+
.item('Save', handler)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Theming
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
:root {
|
|
110
|
+
--context-menu-bg: var(--background);
|
|
111
|
+
--context-menu-border: var(--gray-lite-3);
|
|
112
|
+
--context-menu-radius: var(--radius-card);
|
|
113
|
+
--context-menu-shadow: var(--shadow-lg);
|
|
114
|
+
--context-menu-z-index: 99999;
|
|
115
|
+
--context-menu-min-width: 180px;
|
|
116
|
+
--context-menu-animation-duration: 0.12s;
|
|
117
|
+
}
|
|
118
|
+
```
|