native-document 1.0.166 → 1.0.169
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 +187 -0
- package/components.js +4 -1
- package/dist/native-document.components.min.js +593 -300
- package/dist/native-document.dev.js +99 -75
- 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/icons.md +321 -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/form/field/types/FileField.js +3 -3
- package/src/components/icon/Icon.js +107 -0
- package/src/components/icon/icon-getters.js +142 -0
- package/src/components/icon/icons.js +171 -0
- package/src/components/icon/index.js +17 -0
- package/src/components/icon/types/Icon.d.ts +191 -0
- package/src/components/index.d.ts +6 -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/List.d.ts +45 -32
- package/src/components/list/types/ListDivider.ts +16 -0
- package/src/components/list/types/ListGroup.d.ts +51 -29
- package/src/components/list/types/ListItem.d.ts +40 -30
- 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/core/elements/content-formatter.js +16 -2
- package/src/core/elements/form.js +1 -1
- package/src/core/elements/img.js +1 -1
- package/src/core/elements/medias.js +2 -2
- package/src/core/elements/meta-data.js +1 -1
- package/src/core/wrappers/AttributesWrapper.js +37 -22
- package/src/core/wrappers/ElementCreator.js +9 -16
- package/src/core/wrappers/HtmlElementWrapper.js +26 -7
- package/src/core/wrappers/NDElement.js +12 -1
- package/src/core/wrappers/prototypes/attributes-extensions.js +24 -24
- package/src/core/wrappers/prototypes/nd-element-extensions.js +1 -8
- 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/icon/material/MaterialIconRender.js +71 -0
- package/src/ui/components/icon/material/material.css +15 -0
- package/src/ui/components/icon/material/material.map.js +170 -0
- package/src/ui/components/icon/phosphor/PhosphorIconRender.js +71 -0
- package/src/ui/components/icon/phosphor/phosphor.css +17 -0
- package/src/ui/components/icon/phosphor/phosphor.map.js +165 -0
- package/src/ui/components/icon/tabler/TablerIconRender.js +59 -0
- package/src/ui/components/icon/tabler/tabler.css +14 -0
- package/src/ui/components/icon/tabler/tabler.map.js +165 -0
- 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 +13 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Skeleton
|
|
3
|
+
description: Placeholder that mimics content shape while loading
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skeleton
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Skeleton } from 'native-document/components';
|
|
10
|
+
|
|
11
|
+
Skeleton(props?)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
A placeholder that mimics the shape of content while it loads.
|
|
15
|
+
|
|
16
|
+
## Default Renderer
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
import { SkeletonRender } from 'native-document/ui';
|
|
20
|
+
|
|
21
|
+
Skeleton.use(SkeletonRender);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## `$description`
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
{
|
|
28
|
+
type: 'rect', // 'rect' | 'circle' | 'text' | 'avatar' | 'image'
|
|
29
|
+
variant: 'pulse', // 'pulse' | 'wave'
|
|
30
|
+
borderRadiusType: 'rounded',
|
|
31
|
+
lines: null, // number - for text type
|
|
32
|
+
width: null,
|
|
33
|
+
height: null,
|
|
34
|
+
loading: null, // Observable<boolean>
|
|
35
|
+
repeat: null, // number - repeat N times
|
|
36
|
+
props: {} // HTML attributes for the root element
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Methods
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
// Type
|
|
44
|
+
.rect()
|
|
45
|
+
.circle()
|
|
46
|
+
.text(lines?)
|
|
47
|
+
.avatar()
|
|
48
|
+
.image()
|
|
49
|
+
|
|
50
|
+
// Animation
|
|
51
|
+
.pulse()
|
|
52
|
+
.wave()
|
|
53
|
+
|
|
54
|
+
// Size
|
|
55
|
+
.width(200)
|
|
56
|
+
.height(100)
|
|
57
|
+
.size(width, height)
|
|
58
|
+
|
|
59
|
+
// Shape
|
|
60
|
+
.rounded()
|
|
61
|
+
.pill()
|
|
62
|
+
.smooth()
|
|
63
|
+
|
|
64
|
+
// Options
|
|
65
|
+
.lines(3)
|
|
66
|
+
.repeat(4)
|
|
67
|
+
.loading(isLoading)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Built-in Presets
|
|
71
|
+
|
|
72
|
+
Skeleton ships with four ready-to-use presets:
|
|
73
|
+
|
|
74
|
+
### `Skeleton.card(type?)`
|
|
75
|
+
|
|
76
|
+
A card with an image area and text lines below:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
Skeleton.card()
|
|
80
|
+
Skeleton.card('featured') // adds type as extra CSS class
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `Skeleton.list(items?)`
|
|
84
|
+
|
|
85
|
+
A list of rows with avatar and text lines. Default: 3 items:
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
Skeleton.list()
|
|
89
|
+
Skeleton.list(5)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `Skeleton.table(rows?, cols?)`
|
|
93
|
+
|
|
94
|
+
A table with a header row and data rows. Default: 5 rows, 4 cols:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
Skeleton.table()
|
|
98
|
+
Skeleton.table(10, 6)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `Skeleton.paragraph(lines?)`
|
|
102
|
+
|
|
103
|
+
A block of text lines. Default: 3 lines:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
Skeleton.paragraph()
|
|
107
|
+
Skeleton.paragraph(5)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Custom Presets
|
|
113
|
+
|
|
114
|
+
Register your own reusable shapes with `Skeleton.preset()` or `Skeleton.presets()`:
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
Skeleton.preset('userRow', (skeleton) => {
|
|
118
|
+
return skeleton.avatar().circle().size(40, 40);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Register multiple at once
|
|
122
|
+
Skeleton.presets({
|
|
123
|
+
title: (s) => s.rect().width(200).height(24).rounded(),
|
|
124
|
+
avatar: (s) => s.circle().size(48, 48),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Usage
|
|
128
|
+
Skeleton.userRow()
|
|
129
|
+
Skeleton.title()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Example
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
ShowIf(isLoading, () =>
|
|
136
|
+
VStack([
|
|
137
|
+
Skeleton().avatar().circle().size(48, 48),
|
|
138
|
+
Skeleton().text(3)
|
|
139
|
+
]).spacing(8)
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Theming
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
:root {
|
|
149
|
+
--skeleton-color: var(--gray-lite-4);
|
|
150
|
+
--skeleton-highlight: var(--gray-lite-5);
|
|
151
|
+
--skeleton-radius: var(--radius-button);
|
|
152
|
+
--skeleton-wave-duration: 1.6s;
|
|
153
|
+
--skeleton-pulse-duration: 1.2s;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spinner
|
|
3
|
+
description: Loading indicator with multiple types, sizes, and overlay support
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Spinner
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Spinner } from 'native-document/components';
|
|
10
|
+
|
|
11
|
+
Spinner(props?)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
A loading indicator.
|
|
15
|
+
|
|
16
|
+
## Default Renderer
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
import { SpinnerRender } from 'native-document/ui';
|
|
20
|
+
|
|
21
|
+
Spinner.use(SpinnerRender);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## `$description`
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
{
|
|
28
|
+
type: 'circle', // 'circle' | 'dots' | 'bars' | 'pulse' | 'ring'
|
|
29
|
+
variant: 'primary',
|
|
30
|
+
color: null,
|
|
31
|
+
size: 'small', // 'xs' | 'small' | 'medium' | 'large'
|
|
32
|
+
label: null,
|
|
33
|
+
labelPosition: null, // 'top' | 'bottom' | 'left' | 'right'
|
|
34
|
+
overlay: null,
|
|
35
|
+
backdrop: null,
|
|
36
|
+
fullScreenOverlay: null,
|
|
37
|
+
speed: 'normal', // 'slow' | 'normal' | 'fast'
|
|
38
|
+
props: {} // HTML attributes for the root element
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Methods
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Type
|
|
46
|
+
.circle()
|
|
47
|
+
.dots()
|
|
48
|
+
.bars()
|
|
49
|
+
.pulse()
|
|
50
|
+
.ring()
|
|
51
|
+
|
|
52
|
+
// Size
|
|
53
|
+
.extraSmall()
|
|
54
|
+
.small()
|
|
55
|
+
.medium()
|
|
56
|
+
.large()
|
|
57
|
+
|
|
58
|
+
// Style
|
|
59
|
+
.primary()
|
|
60
|
+
.color('#3b82f6')
|
|
61
|
+
.speed('fast')
|
|
62
|
+
|
|
63
|
+
// Label
|
|
64
|
+
.label('Loading...')
|
|
65
|
+
.labelPosition('bottom')
|
|
66
|
+
|
|
67
|
+
// Overlay
|
|
68
|
+
.overlay()
|
|
69
|
+
.fullScreenOverlay()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Example
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
ShowIf(isLoading, () => Spinner().large().label('Loading...'))
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Theming
|
|
81
|
+
|
|
82
|
+
```css
|
|
83
|
+
:root {
|
|
84
|
+
--spinner-size-extra-small: 16px;
|
|
85
|
+
--spinner-size-small: 24px;
|
|
86
|
+
--spinner-size-medium: 36px;
|
|
87
|
+
--spinner-size-large: 48px;
|
|
88
|
+
--spinner-size-extra-large: 64px;
|
|
89
|
+
--spinner-speed-slow: 1.2s;
|
|
90
|
+
--spinner-speed-normal: 0.8s;
|
|
91
|
+
--spinner-speed-fast: 0.4s;
|
|
92
|
+
--spinner-thickness: 3px;
|
|
93
|
+
--spinner-color: var(--color-primary);
|
|
94
|
+
--spinner-color-primary: var(--color-primary);
|
|
95
|
+
--spinner-color-secondary: var(--color-secondary-text);
|
|
96
|
+
--spinner-color-success: var(--color-success);
|
|
97
|
+
--spinner-color-danger: var(--color-danger);
|
|
98
|
+
--spinner-color-warning: var(--color-warning);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Splitter
|
|
3
|
+
description: Resizable split panel layout with horizontal and vertical orientations
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Splitter
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Splitter, SplitterPanel, SplitterGutter } from 'native-document/components';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Default Renderer
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
import { SplitterRender, SplitterPanelRender, SplitterGutterRender } from 'native-document/ui';
|
|
16
|
+
|
|
17
|
+
Splitter.use(SplitterRender);
|
|
18
|
+
SplitterPanel.use(SplitterPanelRender);
|
|
19
|
+
SplitterGutter.use(SplitterGutterRender);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## `Splitter`
|
|
25
|
+
|
|
26
|
+
### Methods
|
|
27
|
+
|
|
28
|
+
| Method | Parameters | Description |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `.horizontal()` | - | Side-by-side layout (default) |
|
|
31
|
+
| `.vertical()` | - | Stacked layout |
|
|
32
|
+
| `.gutterSize(px)` | `px: number` | Width of the drag handle in px |
|
|
33
|
+
| `.panel(content, options?, props?)` | `content: NdChild`, `options?: object` | Add a panel inline |
|
|
34
|
+
| `.panels(panels)` | `panels: SplitterPanel[]` | Add multiple panels at once |
|
|
35
|
+
| `.dynamic()` | - | Enable dynamic panel management (add/remove at runtime) |
|
|
36
|
+
| `.removePanel(panel)` | `panel: SplitterPanel` | Remove a panel dynamically |
|
|
37
|
+
| `.onResize(handler)` | `handler: (sizes) => void` | Fires on every resize |
|
|
38
|
+
| `.onPanelAdd(handler)` | `handler: (panel) => void` | Fires when a panel is added dynamically |
|
|
39
|
+
| `.onPanelRemove(handler)` | `handler: (panel) => void` | Fires when a panel is removed dynamically |
|
|
40
|
+
|
|
41
|
+
The inline `options` object for `.panel(content, options)` accepts the same properties as `SplitterPanel` methods: `size`, `minSize`, `maxSize`, `collapsible`.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## `SplitterPanel`
|
|
46
|
+
|
|
47
|
+
| Method | Parameters | Description |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `.content(element)` | `element: NdChild` | Panel content |
|
|
50
|
+
| `.size(value)` | `value: string \| number` | Initial size (`'30%'`, `300`) |
|
|
51
|
+
| `.minSize(px)` | `px: number` | Minimum size in px |
|
|
52
|
+
| `.maxSize(px)` | `px: number` | Maximum size in px |
|
|
53
|
+
| `.collapsible(enabled?)` | `enabled?: boolean` | Allow collapsing to 0 |
|
|
54
|
+
| `.collapsed(val?)` | `val?: boolean` | Start collapsed |
|
|
55
|
+
| `.resizable(enabled?)` | `enabled?: boolean` | Enable/disable resize for this panel |
|
|
56
|
+
| `.fixed()` | - | Panel is not resizable and keeps its size |
|
|
57
|
+
| `.data(data)` | `data: *` | Attach metadata to the panel |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## `SplitterGutter`
|
|
62
|
+
|
|
63
|
+
The drag handle between panels. No extra methods - its appearance is controlled entirely by the renderer.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Dynamic panels
|
|
68
|
+
|
|
69
|
+
Use `.dynamic()` to add or remove panels at runtime. Track a panel reference to remove it later:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const sidebar = SplitterPanel(SidebarContent)
|
|
73
|
+
.size('25%')
|
|
74
|
+
.minSize(150)
|
|
75
|
+
.collapsible();
|
|
76
|
+
|
|
77
|
+
const splitter = Splitter()
|
|
78
|
+
.dynamic()
|
|
79
|
+
.panel(sidebar)
|
|
80
|
+
.panel(SplitterPanel(MainContent).size('75%'))
|
|
81
|
+
.onPanelAdd((panel) => console.log('Panel added'))
|
|
82
|
+
.onPanelRemove((panel) => console.log('Panel removed'));
|
|
83
|
+
|
|
84
|
+
// Remove the sidebar later
|
|
85
|
+
Button('Hide sidebar').nd.onClick(() => splitter.removePanel(sidebar))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Example
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
Splitter()
|
|
94
|
+
.horizontal()
|
|
95
|
+
.gutterSize(4)
|
|
96
|
+
.panel(
|
|
97
|
+
SplitterPanel(FileExplorer)
|
|
98
|
+
.size('20%')
|
|
99
|
+
.minSize(150)
|
|
100
|
+
.collapsible()
|
|
101
|
+
)
|
|
102
|
+
.panel(
|
|
103
|
+
SplitterPanel(
|
|
104
|
+
Splitter()
|
|
105
|
+
.vertical()
|
|
106
|
+
.panel(CodeEditor, { size: '70%' })
|
|
107
|
+
.panel(Terminal, { size: '30%', minSize: 100 })
|
|
108
|
+
).size('80%')
|
|
109
|
+
)
|
|
110
|
+
.onResize((sizes) => savePanelSizes(sizes))
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Theming
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
:root {
|
|
120
|
+
--splitter-gutter-size: 1px;
|
|
121
|
+
--splitter-gutter-hit-area: 8px;
|
|
122
|
+
--splitter-gutter-color: var(--gray-lite-3);
|
|
123
|
+
--splitter-gutter-handle-size: 32px;
|
|
124
|
+
--splitter-gutter-handle-color: var(--gray-lite-2);
|
|
125
|
+
--splitter-gutter-handle-color-hover: var(--color-primary);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Next Steps
|
|
132
|
+
|
|
133
|
+
- **[Layout](./layout.md)** - Stack-based layout components
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Stepper
|
|
3
|
+
description: Multi-step wizard component with validation, navigation, and custom renderers
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Stepper
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Stepper, StepperStep } from 'native-document/components';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Default Renderer
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
import { StepperRender, StepperStepRender } from 'native-document/ui';
|
|
16
|
+
|
|
17
|
+
Stepper.use(StepperRender);
|
|
18
|
+
StepperStep.use(StepperStepRender);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## `Stepper`
|
|
24
|
+
|
|
25
|
+
### Configuration
|
|
26
|
+
|
|
27
|
+
| Method | Parameters | Description |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `.step(step)` | `step: StepperStep` | Add a step |
|
|
30
|
+
| `.data(data)` | `data: *` | Initial data passed to all steps |
|
|
31
|
+
| `.currentStep(obs)` | `obs: Observable<number>` | Bind the current step index to an observable |
|
|
32
|
+
| `.linear(enabled?)` | `enabled?: boolean` | Steps must complete in order (default) |
|
|
33
|
+
| `.nonLinear()` | - | Can jump to any step freely |
|
|
34
|
+
| `.editable(enabled?)` | `enabled?: boolean` | Allow returning to completed steps |
|
|
35
|
+
| `.horizontal()` | - | Horizontal layout (default) |
|
|
36
|
+
| `.vertical()` | - | Vertical layout |
|
|
37
|
+
| `.alternativeLabel(enabled?)` | `enabled?: boolean` | Labels below the indicators |
|
|
38
|
+
| `.showNumbers(enabled?)` | `enabled?: boolean` | Show step numbers in indicators |
|
|
39
|
+
| `.showConnector(enabled?)` | `enabled?: boolean` | Show connector line between steps |
|
|
40
|
+
|
|
41
|
+
### Navigation position
|
|
42
|
+
|
|
43
|
+
| Method | Description |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `.navigationAtBottom()` | Navigation buttons at the bottom, horizontal layout |
|
|
46
|
+
| `.navigationAtTop()` | Navigation buttons at the top, horizontal layout |
|
|
47
|
+
| `.navigationAtLeading()` | Navigation buttons on the leading side, vertical layout |
|
|
48
|
+
|
|
49
|
+
### Navigation methods
|
|
50
|
+
|
|
51
|
+
| Method | Parameters | Description |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `await stepper.next()` | - | Validates current step, then advances |
|
|
54
|
+
| `stepper.previous()` | - | Go to previous step |
|
|
55
|
+
| `await stepper.goToStep(index)` | `index: number` | Jump to a step (0-indexed) |
|
|
56
|
+
| `stepper.reset()` | - | Reset to step 0 |
|
|
57
|
+
|
|
58
|
+
### Events
|
|
59
|
+
|
|
60
|
+
| Method | Parameters | Description |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `.onStepChange(handler)` | `handler: (current, previous) => void` | Fires on every step change |
|
|
63
|
+
| `.onNext(handler)` | `handler: (step, index) => void` | Fires when advancing |
|
|
64
|
+
| `.onPrevious(handler)` | `handler: (step, index) => void` | Fires when going back |
|
|
65
|
+
| `.onComplete(handler)` | `handler: (data) => void` | Fires when last step is completed |
|
|
66
|
+
| `.onReset(handler)` | `handler: () => void` | Fires on reset |
|
|
67
|
+
|
|
68
|
+
### Custom renderers
|
|
69
|
+
|
|
70
|
+
| Method | Parameters | Description |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `.renderStepIndicator(fn)` | `fn: ($step) => NdChild` | Custom step indicator (circle/icon) |
|
|
73
|
+
| `.renderStepIndicatorConnector(fn)` | `fn: ($step) => NdChild` | Custom connector between indicators |
|
|
74
|
+
| `.renderContent(fn)` | `fn: ($step) => NdChild` | Custom step content wrapper |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## `StepperStep`
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
StepperStep(title)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Method | Parameters | Description |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `.description(text)` | `text: string` | Subtitle below the step title |
|
|
87
|
+
| `.icon(element)` | `element: NdChild` | Icon displayed in the indicator |
|
|
88
|
+
| `.content(element)` | `element: NdChild` | Step body content |
|
|
89
|
+
| `.key(key)` | `key: string` | Unique identifier for this step |
|
|
90
|
+
| `.optional()` | - | Mark step as optional (can be skipped) |
|
|
91
|
+
| `.disabled(val)` | `val: boolean \| Observable<boolean>` | Disable the step |
|
|
92
|
+
| `.visibility(val)` | `val: boolean \| Observable<boolean>` | Show or hide the step reactively |
|
|
93
|
+
| `.validator(fn)` | `fn: () => boolean \| Promise<boolean>` | Validation function - must return `true` to advance |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Example
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const refs = {};
|
|
101
|
+
|
|
102
|
+
const wizard = Stepper()
|
|
103
|
+
.linear()
|
|
104
|
+
.step(
|
|
105
|
+
StepperStep('Account')
|
|
106
|
+
.content(AccountForm().nd.refSelf(refs, 'accountForm'))
|
|
107
|
+
.validator(async () => refs.accountForm.validate())
|
|
108
|
+
)
|
|
109
|
+
.step(
|
|
110
|
+
StepperStep('Profile')
|
|
111
|
+
.description('Tell us about yourself')
|
|
112
|
+
.content(ProfileForm)
|
|
113
|
+
.optional()
|
|
114
|
+
)
|
|
115
|
+
.step(
|
|
116
|
+
StepperStep('Done')
|
|
117
|
+
.icon(CheckIcon)
|
|
118
|
+
.content(SuccessPanel)
|
|
119
|
+
)
|
|
120
|
+
.navigationAtBottom()
|
|
121
|
+
.onComplete(async (data) => {
|
|
122
|
+
await registerUser(data);
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
document.body.appendChild(wizard);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Theming
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
:root {
|
|
135
|
+
--stepper-connector-color: var(--gray-lite-3);
|
|
136
|
+
--stepper-connector-color-active: var(--color-primary);
|
|
137
|
+
--stepper-connector-color-completed: var(--color-success);
|
|
138
|
+
--stepper-connector-thickness: 2px;
|
|
139
|
+
--step-indicator-size: 32px;
|
|
140
|
+
--step-indicator-bg: var(--gray-lite-4);
|
|
141
|
+
--step-indicator-bg-active: var(--color-primary);
|
|
142
|
+
--step-indicator-bg-completed: var(--color-success);
|
|
143
|
+
--step-indicator-bg-error: var(--color-danger);
|
|
144
|
+
--step-indicator-color: var(--gray);
|
|
145
|
+
--step-indicator-color-active: var(--white);
|
|
146
|
+
--step-indicator-font-size: var(--hint-size);
|
|
147
|
+
--step-indicator-font-weight: 600;
|
|
148
|
+
--step-label-size: var(--hint-size);
|
|
149
|
+
--step-label-color: var(--gray);
|
|
150
|
+
--step-label-color-active: var(--text-color);
|
|
151
|
+
--step-label-weight: 500;
|
|
152
|
+
--step-description-size: var(--note-size);
|
|
153
|
+
--step-description-color: var(--gray);
|
|
154
|
+
--stepper-content-padding: var(--space-comfortable) 0;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Next Steps
|
|
161
|
+
|
|
162
|
+
- **[Components Overview](./index.md)** - BaseComponent philosophy
|
|
163
|
+
- **[FormControl](./form/form-control.md)** - Form validation with steps
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Switch
|
|
3
|
+
description: Toggle switch component with two-way binding, variants, icons, and inner labels
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Switch
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
import { Switch } from 'native-document/components';
|
|
10
|
+
|
|
11
|
+
Switch(props?)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Default Renderer
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
import { SwitchRender } from 'native-document/ui';
|
|
18
|
+
|
|
19
|
+
Switch.use(SwitchRender);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## `$description`
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
{
|
|
26
|
+
value: Observable(false),
|
|
27
|
+
label: null,
|
|
28
|
+
labelPosition: Observable('right'), // 'left' | 'right' | 'top' | 'bottom'
|
|
29
|
+
variant: Observable('primary'),
|
|
30
|
+
outline: false,
|
|
31
|
+
disabled: false,
|
|
32
|
+
loading: false,
|
|
33
|
+
readonly: false,
|
|
34
|
+
onIcon: null,
|
|
35
|
+
offIcon: null,
|
|
36
|
+
innerOnLabel: null,
|
|
37
|
+
innerOffLabel: null,
|
|
38
|
+
props: {} // HTML attributes for the root element
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Methods
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Binding
|
|
46
|
+
.model(Observable(false))
|
|
47
|
+
|
|
48
|
+
// Label
|
|
49
|
+
.label('Enable notifications')
|
|
50
|
+
.labelPosition('left') // 'left' | 'right' | 'top' | 'bottom'
|
|
51
|
+
|
|
52
|
+
// Inner labels (inside the toggle)
|
|
53
|
+
.innerLabel('Yes', 'No')
|
|
54
|
+
|
|
55
|
+
// Icons
|
|
56
|
+
.icon(SunIcon, MoonIcon) // onIcon, offIcon
|
|
57
|
+
|
|
58
|
+
// Variants
|
|
59
|
+
.primary()
|
|
60
|
+
.success()
|
|
61
|
+
.danger()
|
|
62
|
+
.warning()
|
|
63
|
+
.ghost()
|
|
64
|
+
.outline()
|
|
65
|
+
|
|
66
|
+
// State
|
|
67
|
+
.disabled(Observable(false))
|
|
68
|
+
.loading(Observable(false))
|
|
69
|
+
.readonly(true)
|
|
70
|
+
|
|
71
|
+
// Programmatic
|
|
72
|
+
.toggle()
|
|
73
|
+
.on()
|
|
74
|
+
.off()
|
|
75
|
+
|
|
76
|
+
// Events
|
|
77
|
+
.onChange((value) => console.log('Changed:', value))
|
|
78
|
+
.onOn(() => console.log('Switched on'))
|
|
79
|
+
.onOff(() => console.log('Switched off'))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Example
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
const darkMode = Observable(false);
|
|
86
|
+
|
|
87
|
+
Switch()
|
|
88
|
+
.model(darkMode)
|
|
89
|
+
.label('Dark mode')
|
|
90
|
+
.icon(SunIcon, MoonIcon)
|
|
91
|
+
.innerLabel('On', 'Off')
|
|
92
|
+
.onChange((value) => applyTheme(value ? 'dark' : 'light'))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Theming
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
:root {
|
|
101
|
+
--switch-width: 44px;
|
|
102
|
+
--switch-height: 24px;
|
|
103
|
+
--switch-thumb-size: 18px;
|
|
104
|
+
--switch-thumb-offset: 3px;
|
|
105
|
+
--switch-border-width: 0px;
|
|
106
|
+
--switch-track-bg: var(--gray-lite-3);
|
|
107
|
+
--switch-track-bg-active: var(--color-primary);
|
|
108
|
+
--switch-thumb-bg: var(--background);
|
|
109
|
+
--switch-thumb-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
110
|
+
--switch-transition: 0.2s ease;
|
|
111
|
+
--switch-label-gap: var(--space-cozy);
|
|
112
|
+
}
|
|
113
|
+
```
|