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.
Files changed (108) hide show
  1. package/.vitepress/config.js +166 -0
  2. package/CHANGELOG.md +153 -0
  3. package/components.js +2 -1
  4. package/dist/native-document.components.min.js +495 -228
  5. package/dist/native-document.dev.js +7 -0
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/docs/advanced-components.md +213 -608
  9. package/docs/anchor.md +173 -312
  10. package/docs/cache.md +95 -803
  11. package/docs/cli.md +179 -0
  12. package/docs/components/accordion.md +172 -0
  13. package/docs/components/alert.md +99 -0
  14. package/docs/components/avatar.md +160 -0
  15. package/docs/components/badge.md +102 -0
  16. package/docs/components/breadcrumb.md +89 -0
  17. package/docs/components/button.md +183 -0
  18. package/docs/components/card.md +69 -0
  19. package/docs/components/context-menu.md +118 -0
  20. package/docs/components/data-table.md +345 -0
  21. package/docs/components/dropdown.md +214 -0
  22. package/docs/components/form/autocomplete-field.md +81 -0
  23. package/docs/components/form/checkbox-field.md +41 -0
  24. package/docs/components/form/checkbox-group-field.md +54 -0
  25. package/docs/components/form/color-field.md +64 -0
  26. package/docs/components/form/date-field.md +92 -0
  27. package/docs/components/form/field-collection.md +63 -0
  28. package/docs/components/form/file-field.md +203 -0
  29. package/docs/components/form/form-control.md +87 -0
  30. package/docs/components/form/image-field.md +90 -0
  31. package/docs/components/form/index.md +115 -0
  32. package/docs/components/form/number-field.md +65 -0
  33. package/docs/components/form/radio-field.md +51 -0
  34. package/docs/components/form/select-field.md +123 -0
  35. package/docs/components/form/slider.md +136 -0
  36. package/docs/components/form/string-field.md +134 -0
  37. package/docs/components/form/textarea-field.md +65 -0
  38. package/docs/components/form-fields.md +372 -0
  39. package/docs/components/getting-started.md +264 -0
  40. package/docs/components/index.md +337 -0
  41. package/docs/components/layout.md +279 -0
  42. package/docs/components/list.md +73 -0
  43. package/docs/components/menu.md +215 -0
  44. package/docs/components/modal.md +156 -0
  45. package/docs/components/pagination.md +95 -0
  46. package/docs/components/popover.md +131 -0
  47. package/docs/components/progress.md +111 -0
  48. package/docs/components/shortcut-manager.md +221 -0
  49. package/docs/components/simple-table.md +107 -0
  50. package/docs/components/skeleton.md +155 -0
  51. package/docs/components/spinner.md +100 -0
  52. package/docs/components/splitter.md +133 -0
  53. package/docs/components/stepper.md +163 -0
  54. package/docs/components/switch.md +113 -0
  55. package/docs/components/tabs.md +153 -0
  56. package/docs/components/toast.md +119 -0
  57. package/docs/components/tooltip.md +151 -0
  58. package/docs/components/traits.md +261 -0
  59. package/docs/conditional-rendering.md +170 -588
  60. package/docs/contributing.md +300 -25
  61. package/docs/core-concepts.md +205 -374
  62. package/docs/elements.md +251 -367
  63. package/docs/extending-native-document-element.md +192 -207
  64. package/docs/filters.md +153 -1122
  65. package/docs/getting-started.md +193 -267
  66. package/docs/i18n.md +241 -0
  67. package/docs/index.md +76 -0
  68. package/docs/lifecycle-events.md +143 -75
  69. package/docs/list-rendering.md +227 -852
  70. package/docs/memory-management.md +134 -47
  71. package/docs/native-document-element.md +337 -186
  72. package/docs/native-fetch.md +99 -630
  73. package/docs/observable-resource.md +364 -0
  74. package/docs/observables.md +592 -526
  75. package/docs/routing.md +244 -653
  76. package/docs/state-management.md +134 -241
  77. package/docs/svg-elements.md +231 -0
  78. package/docs/theming.md +409 -0
  79. package/docs/tutorials/.gitkeep +0 -0
  80. package/docs/validation.md +95 -97
  81. package/docs/vitepress-conventions.md +219 -0
  82. package/package.json +34 -13
  83. package/readme.md +269 -89
  84. package/src/components/card/Card.js +93 -39
  85. package/src/components/card/index.js +1 -1
  86. package/src/components/list/HasListItem.js +171 -0
  87. package/src/components/list/List.js +41 -107
  88. package/src/components/list/ListDivider.js +39 -0
  89. package/src/components/list/ListGroup.js +76 -59
  90. package/src/components/list/ListItem.js +117 -69
  91. package/src/components/list/index.js +3 -1
  92. package/src/components/list/types/ListItem.d.ts +45 -34
  93. package/src/components/spacer/Spacer.js +1 -1
  94. package/src/core/data/ObservableResource.js +5 -0
  95. package/src/core/data/observable-helpers/observable.prototypes.js +2 -0
  96. package/src/ui/components/card/CardRender.js +133 -0
  97. package/src/ui/components/card/card.css +169 -0
  98. package/src/ui/components/contextmenu/ContextmenuRender.js +1 -1
  99. package/src/ui/components/list/ListRender.js +18 -0
  100. package/src/ui/components/list/divider/ListDividerRender.js +10 -0
  101. package/src/ui/components/list/divider/list-divider.css +12 -0
  102. package/src/ui/components/list/group/ListGroupRender.js +61 -0
  103. package/src/ui/components/list/group/list-group.css +62 -0
  104. package/src/ui/components/list/item/ListItemRender.js +238 -0
  105. package/src/ui/components/list/item/list-item.css +191 -0
  106. package/src/ui/components/list/list.css +24 -0
  107. package/src/ui/components/spacer/SpacerRender.js +10 -0
  108. package/src/ui/index.js +8 -0
package/docs/elements.md CHANGED
@@ -1,512 +1,396 @@
1
+ ---
2
+ title: Elements
3
+ description: Create reactive HTML elements with a declarative syntax - every HTML element has a corresponding function in NativeDocument
4
+ ---
5
+
1
6
  # Elements
2
7
 
3
- NativeDocument provides a simple and intuitive way to create HTML elements with a declarative syntax. Every HTML element has a corresponding function that creates reactive DOM elements.
8
+ NativeDocument provides a simple and intuitive way to create HTML elements with a declarative syntax. Every HTML element has a corresponding function that creates a reactive DOM element.
4
9
 
5
10
  ## Basic Element Creation
6
11
 
7
12
  ```javascript
8
- // Simple elements with attributes
9
- const title = H1({ class: "main-title" }, "Welcome to my app");
10
- const description = P({ class: "description" }, "This is a paragraph");
13
+ // With attributes
14
+ const title = H1({ class: 'main-title' }, 'Welcome to my app');
15
+ const description = P({ class: 'description' }, 'This is a paragraph');
11
16
 
12
- // Elements without attributes (attributes omitted)
13
- const simpleTitle = H1("Welcome to my app");
14
- const simplePara = P("This is a paragraph");
15
- const container = Div("Content here");
17
+ // Without attributes
18
+ const simpleTitle = H1('Welcome to my app');
19
+ const simplePara = P('This is a paragraph');
20
+ const container = Div('Content here');
16
21
 
17
- // Elements without content
22
+ // Self-closing elements
18
23
  const separator = Hr();
19
- const lineBreak = Br();
24
+ const lineBreak = Br();
20
25
  ```
21
26
 
22
27
  ## Element Structure
23
28
 
24
29
  All element functions follow the same pattern:
30
+
25
31
  ```javascript
26
32
  ElementName(attributes, children)
27
33
  // or
28
34
  ElementName(children) // attributes are optional
29
35
  ```
30
36
 
31
- - **attributes**: Object with HTML attributes (optional, can be `null` or omitted)
32
- - **children**: Content inside the element (text, number, observable, other elements, or arrays)
37
+ - **attributes** - object with HTML attributes (optional, can be `null` or omitted)
38
+ - **children** - text, number, observable, other elements, closures (no-param functions), or an array of any of these. Closures are accepted as-is - no need to call them if they take no parameters.
33
39
 
34
40
  ## Working with Attributes
35
41
 
36
42
  ```javascript
37
43
  // Static attributes
38
- const link = Link({
39
- href: "/about",
40
- class: "nav-link",
41
- id: "about-link"
42
- }, "About Us");
44
+ const link = Link({
45
+ href: '/about',
46
+ class: 'nav-link',
47
+ id: 'about-link'
48
+ }, 'About Us');
43
49
 
44
50
  // Boolean attributes
45
- const input = Input({
46
- type: "checkbox",
47
- checked: true,
48
- disabled: false
51
+ const checkbox = Input({
52
+ type: 'checkbox',
53
+ checked: true,
54
+ disabled: false
49
55
  });
50
56
 
51
57
  // Data attributes
52
- const element = Div({
53
- "data-id": "123",
54
- "data-category": "important"
55
- }, "Content");
58
+ const card = Div({
59
+ 'data-id': '123',
60
+ 'data-category': 'important'
61
+ }, 'Content');
56
62
  ```
57
63
 
58
- ## Reactive Attributes with Observables
64
+ ## Reactive Attributes
65
+
66
+ Pass an observable directly as an attribute value - it updates automatically when the observable changes:
59
67
 
60
68
  ```javascript
61
69
  const isVisible = Observable(true);
62
- const userName = Observable("Guest");
63
- const theme = Observable("dark");
70
+ const userName = Observable('Guest');
71
+ const theme = Observable('dark');
64
72
 
65
- // Reactive attributes
66
73
  const greeting = Div({
67
- class: theme, // Updates when theme changes
68
- hidden: isVisible.check(val => !val) // Hide when isVisible is false
69
- }, ['Hello ', userName, '!']); // Reactive text content
74
+ class: theme,
75
+ hidden: isVisible.isFalsy()
76
+ }, ['Hello ', userName, '!']);
70
77
 
71
78
  // Reactive styles
72
79
  const box = Div({
73
- style: {
74
- backgroundColor: theme.check(t => t === "dark" ? "#333" : "#fff"),
75
- color: theme.check(t => t === "dark" ? "#fff" : "#333")
76
- }
77
- }, "Themed content");
80
+ style: {
81
+ backgroundColor: theme.is('dark').check(v => v ? '#333' : '#fff'),
82
+ color: theme.is('dark').check(v => v ? '#fff' : '#333')
83
+ }
84
+ }, 'Themed content');
85
+ ```
86
+
87
+ ## Conditional Classes
88
+
89
+ ```javascript
90
+ const isActive = Observable(false);
91
+ const count = Observable(0);
92
+
93
+ const item = Div({
94
+ class: {
95
+ 'item': true, // always present
96
+ 'active': isActive, // present when isActive is true
97
+ 'highlighted': count.check(c => c > 5) // present when count > 5
98
+ }
99
+ }, 'List item');
78
100
  ```
79
101
 
80
102
  ## Children and Content
81
103
 
82
104
  ```javascript
83
- // Text content (no attributes needed)
84
- const simple = P("Simple text");
105
+ // Single text child
106
+ const simple = P('Simple text');
85
107
 
86
- // Single child element
87
- const wrapper = Div({ class: "wrapper" },
88
- P("Wrapped paragraph")
89
- );
108
+ // Single element child
109
+ const wrapper = Div({ class: 'wrapper' }, P('Wrapped paragraph'));
90
110
 
91
111
  // Multiple children as array
92
- const list = Div({ class: "item-list" }, [
93
- P("First item"),
94
- P("Second item"),
95
- P("Third item")
112
+ const list = Div({ class: 'item-list' }, [
113
+ P('First item'),
114
+ P('Second item'),
115
+ P('Third item')
96
116
  ]);
97
117
 
98
118
  // Mixed content
99
119
  const mixed = Div([
100
- H2("Title"),
101
- "Some text between elements",
102
- P("A paragraph"),
103
- Button("Click me")
120
+ H2('Title'),
121
+ 'Some text between elements',
122
+ P('A paragraph'),
123
+ Button('Click me')
104
124
  ]);
105
125
  ```
106
126
 
107
- ## Event Handling with .nd API
127
+ ## Event Handling with the `.nd` API
108
128
 
109
- The `.nd` (NativeDocument) API provides a fluent interface for adding functionality to elements.
129
+ The `.nd` API provides a fluent interface for events, lifecycle, and DOM utilities:
110
130
 
111
131
  ```javascript
112
- const button = Button("Click me")
113
- .nd.onClick(() => {
114
- console.log("Button clicked!");
115
- });
116
-
117
- // With attributes and events
118
- const styledButton = Button({ class: "btn" }, "Click me")
119
- .nd.onClick(() => {
120
- console.log("Button clicked!");
121
- });
122
-
123
- // Multiple events
124
- const input = Input({ type: "text", placeholder: "Type here..." })
125
- .nd.onFocus(() => console.log("Input focused"))
126
- .nd.onBlur(() => console.log("Input blurred"))
127
- .nd.onInput(event => console.log("Input value:", event.target.value));
128
-
129
- // Or
130
- const input = Input({ type: "text", placeholder: "Type here..." })
131
- .nd.on({
132
- focus: () => console.log("Input focused"),
133
- blur: () => console.log("Input blurred"),
134
- input: event => console.log("Input value:", event.target.value)
135
- });
136
-
137
- // Prevent default behavior
132
+ const button = Button('Click me')
133
+ .nd.onClick(() => console.log('Clicked!'));
134
+
135
+ // With attributes
136
+ const styledButton = Button({ class: 'btn' }, 'Click me')
137
+ .nd.onClick(() => console.log('Clicked!'));
138
+
139
+ // Multiple events - chained
140
+ const input = Input({ type: 'text', placeholder: 'Type here...' })
141
+ .nd
142
+ .onFocus(() => console.log('Focused'))
143
+ .onBlur(() => console.log('Blurred'))
144
+ .onInput(e => console.log('Value:', e.target.value));
145
+
146
+ // Single event via .on() - name, callback, options (standard addEventListener signature)
147
+ const input2 = Input({ type: 'text' })
148
+ .nd
149
+ .on('input', e => console.log('Value:', e.target.value))
150
+ .on('focus', () => console.log('Focused'), { once: true });
151
+
152
+ // Prevent default
138
153
  const form = Form()
139
- .nd.onPreventSubmit(event => {
140
- console.log("Form submitted without page reload");
141
- // Handle form submission
142
- });
154
+ .nd.onPreventSubmit(e => {
155
+ console.log('Submitted without page reload');
156
+ });
143
157
  ```
144
158
 
145
- ## Advanced Element Composition
159
+ ## Form Elements and Two-Way Binding
146
160
 
147
- ### Extending Elements with Custom Methods
161
+ Passing an observable to `value` or `checked` creates automatic two-way binding:
148
162
 
149
- Use `.nd.with()` to add custom methods to elements:
150
163
  ```javascript
151
- const customButton = Button("Click me")
152
- .nd.with({
153
- highlight() {
154
- this.$element.style.backgroundColor = 'yellow';
155
- return this;
156
- },
157
- resetStyle() {
158
- this.$element.style.backgroundColor = '';
159
- return this;
160
- }
161
- })
162
- .highlight();
164
+ const name = Observable('');
165
+ const email = Observable('');
166
+ const isChecked = Observable(false);
163
167
 
164
- // Chain custom methods
165
- customButton.resetStyle().highlight();
168
+ const nameInput = Input({ type: 'text', value: name, placeholder: 'Your name' });
169
+ const emailInput = Input({ type: 'email', value: email, placeholder: 'Your email' });
170
+ const checkbox = Input({ type: 'checkbox', checked: isChecked });
166
171
  ```
167
172
 
168
- ### Class and Style Accumulators
173
+ ## Lifecycle Management
169
174
 
170
- Build classes and styles programmatically:
171
175
  ```javascript
172
- import { classPropertyAccumulator, cssPropertyAccumulator } from 'native-document';
176
+ const component = Div('Component content')
177
+ .nd.mounted(element => {
178
+ console.log('Mounted to DOM');
179
+ })
180
+ .nd.unmounted(element => {
181
+ console.log('Removed from DOM');
182
+ });
173
183
 
174
- // Class accumulator
175
- const classes = classPropertyAccumulator(['btn']);
176
- classes.add('primary');
177
- classes.add('large');
184
+ // Combined
185
+ const widget = Div('Widget')
186
+ .nd.lifecycle({
187
+ mounted: element => console.log('Mounted'),
188
+ unmounted: element => console.log('Unmounted')
189
+ });
190
+ ```
178
191
 
179
- const button = Button({ class: classes.value() }, "Submit");
180
- // Result: class="btn primary large"
192
+ ## Manual DOM Manipulation
181
193
 
182
- // Or with object
183
- const classObj = classPropertyAccumulator({ btn: true });
184
- classObj.add('primary', true);
185
- classObj.add('disabled', false);
186
- console.log(classObj.value()); // { btn: true, primary: true, disabled: false }
194
+ ```javascript
195
+ // Remove all children
196
+ const container = Div([P('Child 1'), P('Child 2')]);
197
+ container.nd.unmountChildren();
187
198
 
188
- // CSS accumulator
189
- const styles = cssPropertyAccumulator({ color: 'red' });
190
- styles.add('font-size', '16px');
191
- styles.add('margin', '10px');
199
+ // Remove element from DOM
200
+ const element = Div('Content');
201
+ element.nd.remove();
202
+ ```
192
203
 
193
- const element = Div({ style: styles.value() }, "Styled content");
194
- // Result: style="color: red; font-size: 16px; margin: 10px"
204
+ ## Element References
195
205
 
196
- // Or with array
197
- const styleArr = cssPropertyAccumulator('color: red; font-size: 16px');
198
- styleArr.add('margin', '10px');
199
- console.log(styleArr.value()); // "color: red; font-size: 16px; margin: 10px;"
200
- ```
206
+ `.ref()` and `.refSelf()` both store a reference on a target object, but they store different things:
201
207
 
202
- ## Form Elements and Two-Way Binding
208
+ - **`.ref(target, name)`** - stores the **native HTML element** (`this.$element`) → use when you need direct DOM access
209
+ - **`.refSelf(target, name)`** - stores the **`NDElement` instance** (`this`) → use when you need to keep calling `.nd` methods
203
210
 
204
211
  ```javascript
205
- const name = Observable("");
206
- const email = Observable("");
207
- const isChecked = Observable(false);
212
+ const refs = {};
208
213
 
209
- // Text input with two-way binding
210
- const nameInput = Input({
211
- type: "text",
212
- value: name, // Automatic two-way binding
213
- placeholder: "Enter your name"
214
- });
214
+ const app = Div([
215
+ Input({ type: 'text' })
216
+ .nd.ref(refs, 'nameInput'), // refs.nameInput → HTMLInputElement
215
217
 
216
- // Email input
217
- const emailInput = Input({
218
- type: "email",
219
- value: email,
220
- placeholder: "Enter your email"
221
- });
218
+ Input({ type: 'text' })
219
+ .nd.refSelf(refs, 'emailInput'), // refs.emailInput → NDElement instance
222
220
 
223
- // Checkbox with binding
224
- const checkbox = Input({
225
- type: "checkbox",
226
- checked: isChecked // Automatic two-way binding
227
- });
221
+ Button('Actions')
222
+ .nd.onClick(() => {
223
+ refs.nameInput.focus(); // native DOM method
224
+ refs.emailInput.onInput(e => console.log(e.target.value)); // nd method
225
+ })
226
+ ]);
228
227
  ```
229
228
 
230
- ## Conditional Classes and Styles
229
+ ## `.nd.with()` - Instance-level Custom Methods
231
230
 
232
- ```javascript
233
- const isActive = Observable(false);
234
- const count = Observable(0);
235
-
236
- // Conditional classes
237
- const item = Div({
238
- class: {
239
- "item": true, // Always present
240
- "active": isActive, // Present when isActive is true
241
- "highlighted": count.check(c => c > 5) // Present when count > 5
242
- }
243
- }, "List item");
244
-
245
- // Dynamic styles
246
- const progress = Div({
247
- style: {
248
- width: count.check(c => `${c}%`),
249
- backgroundColor: count.check(c => c > 50 ? "green" : "red")
250
- }
251
- }, "Progress bar");
252
- ```
253
-
254
- ## Lifecycle Management
231
+ Add custom methods to a single element instance without affecting other elements:
255
232
 
256
233
  ```javascript
257
- const component = Div("Component content")
258
- .nd.mounted(element => {
259
- console.log("Component mounted to DOM");
260
- // Initialize component
234
+ const customButton = Button('Click me')
235
+ .nd.with({
236
+ highlight() {
237
+ this.$element.style.backgroundColor = 'yellow';
238
+ return this;
239
+ },
240
+ resetStyle() {
241
+ this.$element.style.backgroundColor = '';
242
+ return this;
243
+ }
261
244
  })
262
- .nd.unmounted(element => {
263
- console.log("Component removed from DOM");
264
- // Cleanup resources
265
- });
245
+ .highlight();
266
246
 
267
- // Combined lifecycle
268
- const widget = Div("Widget")
269
- .nd.lifecycle({
270
- mounted: element => console.log("Widget mounted"),
271
- unmounted: element => console.log("Widget unmounted")
272
- });
247
+ customButton.resetStyle().highlight();
273
248
  ```
274
- ## Manual DOM Manipulation
275
249
 
276
- ### Unmounting Children
250
+ > `.nd.with()` only affects the current instance. To add methods to **all** elements, extend `NDElement.prototype` - see [Extending NDElement](./extending-native-document-element.md).
277
251
 
278
- Remove all children from an element:
279
- ```javascript
280
- const container = Div([
281
- P("Child 1"),
282
- P("Child 2"),
283
- P("Child 3")
284
- ]);
252
+ ## `.nd.attach()` - Template Binding
285
253
 
286
- // Remove all children
287
- container.nd.unmountChildren();
288
- // container is now empty but still in DOM
254
+ Attaches a template binding hydrator to the element. Used internally by the `useCache` and `useSingleton` rendering systems:
255
+
256
+ ```javascript
257
+ // methodName - the event/method name to hydrate
258
+ // bindingHydrator - a binding with a $hydrate method, or a plain function
259
+ element.nd.attach('onClick', bindingHydrator);
289
260
  ```
290
261
 
291
- ### Removing Elements
262
+ See [Advanced Components](./advanced-components.md) for practical usage with `useCache`.
263
+
264
+ ## Class and Style Accumulators
265
+
266
+ Build classes and styles programmatically before passing them to an element:
292
267
 
293
- Remove an element from the DOM:
294
268
  ```javascript
295
- const element = Div("Content");
296
- document.body.appendChild(element.nd.node());
269
+ import { classPropertyAccumulator, cssPropertyAccumulator } from 'native-document';
297
270
 
298
- // Remove from DOM
299
- element.nd.remove();
300
- // Element is detached from DOM
301
- ```
271
+ // Class accumulator
272
+ const classes = classPropertyAccumulator(['btn']);
273
+ classes.add('primary');
274
+ classes.add('large');
302
275
 
303
- ## Element References
276
+ const button = Button({ class: classes.value() }, 'Submit');
277
+ // class="btn primary large"
304
278
 
305
- ```javascript
306
- const refs = {};
279
+ // Object form
280
+ const classObj = classPropertyAccumulator({ btn: true });
281
+ classObj.add('primary', true);
282
+ classObj.add('disabled', false);
283
+ classObj.value(); // { btn: true, primary: true, disabled: false }
307
284
 
308
- const app = Div([
309
- Input({ type: "text" })
310
- .nd.ref(refs, "nameInput"), // Store reference as refs.nameInput
285
+ // CSS accumulator
286
+ const styles = cssPropertyAccumulator({ color: 'red' });
287
+ styles.add('font-size', '16px');
288
+ styles.add('margin', '10px');
311
289
 
312
- Button("Focus Input")
313
- .nd.onClick(() => {
314
- refs.nameInput.focus(); // Use the reference
315
- })
316
- ]);
290
+ const element = Div({ style: styles.value() }, 'Styled content');
291
+ // style="color: red; font-size: 16px; margin: 10px"
317
292
  ```
318
293
 
319
294
  ## Shadow DOM
320
295
 
321
- NativeDocument supports Shadow DOM for encapsulated components:
322
296
  ```javascript
323
- // Open shadow DOM (inspectable)
324
- const widget = Div("Widget content")
297
+ // Open shadow DOM (inspectable in DevTools)
298
+ const widget = Div('Widget content')
325
299
  .nd.openShadow(`
326
- :host {
327
- display: block;
328
- padding: 20px;
329
- background: #f0f0f0;
330
- }
331
- p { color: blue; }
332
-
300
+ :host { display: block; padding: 20px; }
301
+ p { color: blue; }
333
302
  `);
334
303
 
335
304
  // Closed shadow DOM (private)
336
- const privateWidget = Div("Private content")
337
- .nd.closedShadow(`
338
- p { color: red; }
339
-
340
- `);
305
+ const privateWidget = Div('Private content')
306
+ .nd.closedShadow(`p { color: red; }`);
341
307
 
342
- // Manual shadow DOM with mode
343
- const customWidget = Div("Custom")
344
- .nd.shadow('open', `
345
- /* Scoped styles */
346
-
347
- `);
348
- ```
349
-
350
- ## Practical Example: Simple Button with Event
351
-
352
- ```javascript
353
- const count = Observable(0);
354
-
355
- const incrementButton = Button({
356
- class: "btn btn-primary",
357
- type: "button"
358
- }, "Increment")
359
- .nd.onClick(() => {
360
- count.set(count.val() + 1);
361
- });
362
-
363
- const display = Div({ class: "counter-display" }, [
364
- P("Current count: "),
365
- Strong(count) // Reactive display
366
- ]);
367
-
368
- const app = Div({ class: "counter-app" }, [
369
- display,
370
- incrementButton
371
- ]);
308
+ // Manual mode
309
+ const customWidget = Div('Custom')
310
+ .nd.shadow('open', `/* scoped styles */`);
372
311
  ```
373
312
 
374
313
  ## Practical Example: Form with Validation
375
314
 
376
315
  ```javascript
377
- const formData = Observable.object({
378
- name: "",
379
- email: "",
380
- age: ""
381
- });
316
+ const formData = Observable.object({ name: '', email: '', age: '' });
317
+ const errors = Observable.object({ name: '', email: '', age: '' });
382
318
 
383
- const errors = Observable.object({
384
- name: "",
385
- email: "",
386
- age: ""
387
- });
388
-
389
- // Validation function
390
319
  const validateForm = () => {
391
320
  const data = formData.$value;
392
- const newErrors = {};
393
-
394
- newErrors.name = data.name.length < 2 ? "Name must be at least 2 characters" : "";
395
- newErrors.email = !data.email.includes("@") ? "Invalid email address" : "";
396
- newErrors.age = isNaN(data.age) || data.age < 1 ? "Age must be a valid number" : "";
397
321
 
398
- Observable.update(errors, newErrors);
322
+ errors.name.set(data.name.length < 2 ? 'Name must be at least 2 characters' : '');
323
+ errors.email.set(!data.email.includes('@') ? 'Invalid email address' : '');
324
+ errors.age.set(isNaN(data.age) || data.age < 1 ? 'Age must be a valid number' : '');
399
325
 
400
- errors.set(newErrors);
401
-
402
- return Object.values(newErrors).every(error => error === "");
326
+ return [errors.name, errors.email, errors.age].every(e => e.val() === '');
403
327
  };
404
328
 
405
- const contactForm = Form({ class: "contact-form" }, [
406
- // Name field
407
- Div({ class: "field" }, [
408
- Label("Name:"),
409
- Input({
410
- type: "text",
411
- value: formData.name,
412
- placeholder: "Enter your name"
413
- }).nd.onBlur(validateForm),
414
-
415
- ShowIf(errors.name.check(err => err !== ""),
416
- Span({ class: "error" }, errors.name)
417
- )
329
+ const contactForm = Form({ class: 'contact-form' }, [
330
+
331
+ Div({ class: 'field' }, [
332
+ Label('Name:'),
333
+ Input({ type: 'text', value: formData.name, placeholder: 'Enter your name' })
334
+ .nd.onBlur(validateForm),
335
+ ShowIf(errors.name.isTruthy(), Span({ class: 'error' }, errors.name))
418
336
  ]),
419
337
 
420
- // Email field
421
- Div({ class: "field" }, [
422
- Label("Email:"),
423
- Input({
424
- type: "email",
425
- value: formData.email,
426
- placeholder: "Enter your email"
427
- }).nd.onBlur(validateForm),
428
-
429
- ShowIf(errors.email.check(err => err !== ""),
430
- Span({ class: "error" }, errors.email)
431
- )
338
+ Div({ class: 'field' }, [
339
+ Label('Email:'),
340
+ Input({ type: 'email', value: formData.email, placeholder: 'Enter your email' })
341
+ .nd.onBlur(validateForm),
342
+ ShowIf(errors.email.isTruthy(), Span({ class: 'error' }, errors.email))
432
343
  ]),
433
344
 
434
- // Age field
435
- Div({ class: "field" }, [
436
- Label("Age:"),
437
- Input({
438
- type: "number",
439
- value: formData.age,
440
- placeholder: "Enter your age"
441
- }).nd.onBlur(validateForm),
442
-
443
- ShowIf(errors.age.check(err => err !== ""),
444
- Span({ class: "error" }, errors.age)
445
- )
345
+ Div({ class: 'field' }, [
346
+ Label('Age:'),
347
+ Input({ type: 'number', value: formData.age, placeholder: 'Enter your age' })
348
+ .nd.onBlur(validateForm),
349
+ ShowIf(errors.age.isTruthy(), Span({ class: 'error' }, errors.age))
446
350
  ]),
447
351
 
448
- // Submit button
449
- Button({
450
- type: "submit",
451
- class: "btn btn-primary"
452
- }, "Submit")
453
- ])
454
- .nd.onPreventSubmit(() => {
455
- if (validateForm()) {
456
- console.log("Form is valid!", formData.$value);
457
- // Handle successful submission
458
- } else {
459
- console.log("Form has errors");
460
- }
461
- });
352
+ Button({ type: 'submit', class: 'btn btn-primary' }, 'Submit')
353
+
354
+ ]).nd.onPreventSubmit(() => {
355
+ if (validateForm()) {
356
+ console.log('Form is valid!', formData.$value);
357
+ }
358
+ });
462
359
  ```
463
360
 
464
- ## Available Elements
361
+ ## Available HTML Elements
465
362
 
466
- NativeDocument provides functions for all standard HTML elements:
363
+ **Text:** `H1`, `H2`, `H3`, `H4`, `H5`, `H6`, `P`, `Span`, `Strong`, `Em`, `Small`, `Mark`, `BlockQuote`, `Pre`, `Code`
467
364
 
468
- **Text Elements:** `H1`, `H2`, `H3`, `H4`, `H5`, `H6`, `P`, `Span`, `Strong`, `Em`, `Small`, `Mark`
365
+ **Layout:** `Div`, `Section`, `Article`, `Aside`, `Header`, `Footer`, `Nav`, `Main`
469
366
 
470
- **Layout Elements:** `Div`, `Section`, `Article`, `Aside`, `Header`, `Footer`, `Nav`, `Main`
367
+ **Form:** `Form`, `Input`, `TextArea`, `Select`, `Option`, `Button`, `Label`, `FieldSet`, `Legend`
471
368
 
472
- **Form Elements:** `Form`, `Input`, `TextArea`, `Select`, `Option`, `Button`, `Label`, `FieldSet`, `Legend`
369
+ **List:** `Ul`, `Ol`, `Li`, `Dl`, `Dt`, `Dd`
473
370
 
474
- **List Elements:** `Ul`, `Ol`, `Li`, `Dl`, `Dt`, `Dd`
371
+ **Media:** `Img`, `Audio`, `Video`, `Canvas`
475
372
 
476
- **Media Elements:** `Img`, `Audio`, `Video`, `Canvas`, `Svg`
373
+ **Interactive:** `Link`, `Details`, `Summary`, `Dialog`
477
374
 
478
- **Interactive Elements:** `Link`, `Details`, `Summary`, `Dialog`, `Menu`
375
+ **SVG:** `Svg`, `SvgSvg`, `SvgCircle`, `SvgRect`, `SvgEllipse`, `SvgLine`, `SvgPolyline`, `SvgPolygon`, `SvgPath`, `SvgText`, `SvgTSpan`, `SvgG`, `SvgDefs`, `SvgUse`, `SvgSymbol`, `SvgClipPath`, `SvgMask`, `SvgMarker`, `SvgPattern`, `SvgImage`, `SvgLinearGradient`, `SvgRadialGradient`, `SvgStop`, `SvgFilter`, and more.
479
376
 
480
- And many more following the same naming pattern!
377
+ > For detailed SVG usage and examples, see [SVG Elements](./svg-elements.md).
481
378
 
482
379
  ## Best Practices
483
380
 
484
- 1. **Use semantic HTML elements** for better accessibility
485
- 2. **Leverage reactive attributes** with observables for dynamic UIs
486
- 3. **Group related elements** in logical containers
487
- 4. **Use the `.nd` API** for event handling and lifecycle management
488
- 5. **Validate form data** reactively for better user experience
489
- 6. **Store element references** when you need to manipulate them later
490
- 7. **Use conditional rendering** with `ShowIf` for dynamic content
381
+ 1. Use semantic HTML elements for better accessibility
382
+ 2. Leverage reactive attributes with observables for dynamic UIs
383
+ 3. Use `.nd.with()` for instance-level customization, `NDElement.prototype` for app-wide methods
384
+ 4. Store element references with `.nd.ref()` when you need direct DOM access
385
+ 5. Use `ShowIf` with `.isTruthy()` / `.isFalsy()` for clean conditional rendering
386
+ 6. Group related elements in logical containers
491
387
 
492
388
  ## Next Steps
493
389
 
494
- Now that you understand NativeDocument's elements, explore these advanced topics:
495
-
496
- - **[Conditional Rendering](conditional-rendering.md)** - Dynamic content
497
- - **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
498
- - **[Routing](routing.md)** - Navigation and URL management
499
- - **[State Management](state-management.md)** - Global state patterns
500
- - **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
501
- - **[NDElement](native-document-element.md)** - Native Document Element
502
- - **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
503
- - **[Advanced Components](advanced-components.md)** - Template caching and singleton views
504
- - **[Args Validation](validation.md)** - Function Argument Validation
505
- - **[Memory Management](memory-management.md)** - Memory management
506
- - **[Anchor](anchor.md)** - Anchor
507
-
508
- ## Utilities
509
-
510
- - **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
511
- - **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
512
- - **[Filters](docs/utils/filters.md)** - Data filtering helpers
390
+ - **[Conditional Rendering](./conditional-rendering.md)** - Dynamic content
391
+ - **[List Rendering](./list-rendering.md)** - ForEach and dynamic lists
392
+ - **[NDElement](./native-document-element.md)** - Full `.nd` API reference
393
+ - **[Extending NDElement](./extending-native-document-element.md)** - Custom methods guide
394
+ - **[SVG Elements](./svg-elements.md)** - SVG wrapper functions
395
+ - **[Advanced Components](./advanced-components.md)** - Template caching and singleton views
396
+ - **[Lifecycle Events](./lifecycle-events.md)** - Mounted, unmounted, beforeUnmount