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
@@ -1,336 +1,487 @@
1
+ ---
2
+ title: NDElement
3
+ description: The NDElement wrapper enhances native HTML elements with fluent event handling, lifecycle hooks, transitions, and DOM utilities
4
+ ---
5
+
1
6
  # NDElement
2
7
 
3
- `NDElement` is a wrapper class that enhances native HTML elements with utility methods and simplified event handlers. It enables fluent DOM manipulation while preserving access to the underlying HTML element.
8
+ `NDElement` is a wrapper class that enhances native HTML elements with fluent event handling, lifecycle hooks, transitions, and DOM utilities - while preserving full access to the underlying native element.
4
9
 
5
10
  ## Accessing NDElement
6
11
 
7
- Every HTML element created with NativeDocument automatically has an `nd` property that returns an `NDElement` instance:
12
+ Every element created with NativeDocument automatically has an `nd` property that returns its `NDElement` instance:
8
13
 
9
14
  ```javascript
10
- const element = Div("Hello World");
15
+ const element = Div('Hello World');
11
16
  const ndElement = element.nd; // NDElement instance
12
17
 
13
- // Or directly with method chaining
14
- Div("Hello").nd.onClick(() => console.log("Clicked!"));
18
+ // Chain directly
19
+ Div('Hello').nd.onClick(() => console.log('Clicked!'));
15
20
  ```
16
21
 
17
- ## Constructor
22
+ Once you call `.nd`, subsequent methods chain directly, no need to repeat `.nd`:
18
23
 
19
24
  ```javascript
20
- new NDElement(element)
25
+ Button('Interactive')
26
+ .nd
27
+ .onClick(e => console.log('Clicked'))
28
+ .onMouseEnter(e => e.target.style.background = 'blue')
29
+ .onMouseLeave(e => e.target.style.background = '')
30
+ .mounted(el => console.log('Button mounted'));
21
31
  ```
22
32
 
23
- **Parameters:**
24
- - `element`: The HTML element to wrap
25
-
26
33
  ## Properties
27
34
 
28
35
  ### `$element`
29
36
  The encapsulated native HTML element.
30
37
 
31
38
  ```javascript
32
- const div = Div("Content");
39
+ const div = Div('Content');
33
40
  const htmlElement = div.nd.$element; // Native HTMLDivElement
34
41
  ```
35
42
 
36
43
  ### `$observer`
37
- Lifecycle observer (used internally for DOM monitoring).
44
+ Lifecycle observer, used internally for DOM monitoring.
38
45
 
39
- ## Event Handling Methods
46
+ ---
40
47
 
41
- NDElement automatically generates methods for all standard DOM events with multiple variants:
48
+ ## Event Handling
42
49
 
43
- ### Basic Events
50
+ ### Auto-generated event methods
51
+
52
+ NDElement generates methods for all standard DOM events in four variants:
44
53
 
45
54
  ```javascript
46
- // Standard event
55
+ // Standard
47
56
  element.nd.onClick(callback)
48
- element.nd.onMouseOver(callback)
49
- element.nd.onKeyDown(callback)
50
57
 
51
- // Examples
52
- Button("Click me").nd.onClick(e => console.log("Button clicked!"));
53
- Input().nd.onInput(e => console.log("Input changed:", e.target.value));
54
- ```
58
+ // Prevents default behavior
59
+ element.nd.onPreventClick(callback)
60
+
61
+ // Stops event propagation
62
+ element.nd.onStopClick(callback)
55
63
 
56
- ### Prevention Variants
64
+ // Both preventDefault() and stopPropagation()
65
+ element.nd.onPreventStopClick(callback)
66
+ ```
57
67
 
58
68
  ```javascript
59
- // Prevents default behavior
60
- element.nd.onPreventClick(callback) // preventDefault()
61
- element.nd.onPreventSubmit(callback)
69
+ // Standard usage
70
+ Button('Submit').nd.onClick(e => console.log('Clicked'));
71
+ Input().nd.onInput(e => console.log('Value:', e.target.value));
72
+
73
+ // Prevent default
74
+ Link({ href: '/page' })
75
+ .nd
76
+ .onPreventClick(e => {
77
+ router.push('/page');
78
+ });
62
79
 
63
- // Example
64
- Link({ href: "/page" }).nd.onPreventClick(e => {
65
- // Link won't navigate, custom behavior
66
- router.push("/page");
67
- });
80
+ // Stop propagation
81
+ Div([
82
+ Button('Child').nd.onStopClick(e => console.log("Won't bubble"))
83
+ ]).nd.onClick(() => console.log('Never called'));
84
+
85
+ // Prevent + stop
86
+ Form().nd.onPreventStopSubmit(handleFormSubmit);
68
87
  ```
69
88
 
70
- ### Propagation Stop Variants
89
+ ### Supported events
90
+
91
+ **Mouse:** `Click`, `DblClick`, `MouseDown`, `MouseEnter`, `MouseLeave`, `MouseMove`, `MouseOut`, `MouseOver`, `MouseUp`, `Wheel`
92
+
93
+ **Keyboard:** `KeyDown`, `KeyPress`, `KeyUp`
94
+
95
+ **Form:** `Blur`, `Change`, `Focus`, `Input`, `Invalid`, `Reset`, `Search`, `Select`, `Submit`
96
+
97
+ **Drag & Drop:** `Drag`, `DragEnd`, `DragEnter`, `DragLeave`, `DragOver`, `DragStart`, `Drop`
98
+
99
+ **Media:** `Abort`, `CanPlay`, `CanPlayThrough`, `DurationChange`, `Emptied`, `Ended`, `LoadedData`, `LoadedMetadata`, `LoadStart`, `Pause`, `Play`, `Playing`, `Progress`, `RateChange`, `Seeked`, `Seeking`, `Stalled`, `Suspend`, `TimeUpdate`, `VolumeChange`, `Waiting`
100
+
101
+ **Window:** `AfterPrint`, `BeforePrint`, `BeforeUnload`, `Error`, `HashChange`, `Load`, `Offline`, `Online`, `PageHide`, `PageShow`, `Resize`, `Scroll`, `Unload`
102
+
103
+ ### `.on(name, callback, options)` - Generic event
104
+
105
+ Registers any DOM event. Uses `AbortController` internally - listeners are **automatically removed when the element is unmounted**, no manual cleanup needed:
71
106
 
72
107
  ```javascript
73
- // Stops event propagation
74
- element.nd.onStopClick(callback) // stopPropagation()
75
- element.nd.onStopKeyDown(callback)
108
+ element.nd.on('scroll', callback, { passive: true })
109
+ element.nd.on('customEvent', callback)
110
+ ```
76
111
 
77
- // Example
78
- Div([
79
- Button("Child").nd.onStopClick(e => {
80
- console.log("Child clicked - won't bubble up");
81
- })
82
- ]).nd.onClick(() => console.log("This won't be called"));
112
+ ### `.off(name, callback)` - Remove a specific listener
113
+
114
+ ```javascript
115
+ const handler = e => console.log(e);
116
+
117
+ element.nd.on('click', handler);
118
+ element.nd.off('click', handler);
83
119
  ```
84
120
 
85
- ### Combined Variants
121
+ ### `.once(name, callback)` - One-time listener
122
+
123
+ Fires once then removes itself automatically:
86
124
 
87
125
  ```javascript
88
- // Combines preventDefault() and stopPropagation()
89
- element.nd.onPreventStopSubmit(callback)
90
- element.nd.onPreventStopClick(callback)
126
+ element.nd.once('click', () => console.log('First click only'));
127
+ ```
91
128
 
92
- // Example
93
- Form().nd.onPreventStopSubmit(e => {
94
- // Prevents submission AND stops propagation
95
- handleFormSubmit(e);
96
- });
129
+ ### `.emit(name, detail?)` - Dispatch a custom event
130
+
131
+ ```javascript
132
+ element.nd.emit('my-event', { value: 42 });
133
+
134
+ // Listen for it on a parent
135
+ parent.nd.on('my-event', e => console.log(e.detail.value)); // 42
97
136
  ```
98
137
 
99
- ### Supported Events List
138
+ ---
139
+
140
+ ## Attribute Methods
100
141
 
101
- All standard DOM events are supported with the 4 variants:
142
+ ### `.attr(name, value)` - Set a single attribute
102
143
 
103
- **Mouse:** Click, DblClick, MouseDown, MouseEnter, MouseLeave, MouseMove, MouseOut, MouseOver, MouseUp, Wheel
144
+ Accepts a plain value or an observable:
145
+
146
+ ```javascript
147
+ element.nd.attr('aria-label', 'Close button');
148
+ element.nd.attr('aria-expanded', isOpen); // reactive
149
+ ```
104
150
 
105
- **Keyboard:** KeyDown, KeyPress, KeyUp
151
+ ### `.attrs(attrs)` - Set multiple attributes
106
152
 
107
- **Form:** Blur, Change, Focus, Input, Invalid, Reset, Search, Select, Submit
153
+ ```javascript
154
+ element.nd.attrs({
155
+ 'aria-label': 'Close',
156
+ 'aria-expanded': isOpen,
157
+ 'data-id': '123'
158
+ });
159
+ ```
108
160
 
109
- **Drag & Drop:** Drag, DragEnd, DragEnter, DragLeave, DragOver, DragStart, Drop
161
+ ### `.class(classes)` - Bind class object
110
162
 
111
- **Media:** Abort, CanPlay, CanPlayThrough, DurationChange, Emptied, Ended, LoadedData, LoadedMetadata, LoadStart, Pause, Play, Playing, Progress, RateChange, Seeked, Seeking, Stalled, Suspend, TimeUpdate, VolumeChange, Waiting
163
+ ```javascript
164
+ element.nd.class({
165
+ 'active': isActive,
166
+ 'disabled': isDisabled,
167
+ 'hidden': isVisible.isFalsy()
168
+ });
169
+ ```
112
170
 
113
- **Window:** AfterPrint, BeforePrint, BeforeUnload, Error, HashChange, Load, Offline, Online, PageHide, PageShow, Resize, Scroll, Unload
171
+ ### `.style(style)` - Bind style object
172
+
173
+ ```javascript
174
+ element.nd.style({
175
+ color: theme.format(t => t === 'dark' ? '#fff' : '#333'),
176
+ opacity: isVisible.format(v => v ? 1 : 0.5)
177
+ });
178
+ ```
179
+
180
+ ---
114
181
 
115
182
  ## Utility Methods
116
183
 
117
- ### `ref(target, name)`
118
- Assigns the HTML element to a property of a target object.
184
+ ### `ref(target, name)` / `refSelf(target, name)`
185
+
186
+ Both store a reference on a target object but store different things:
187
+
188
+ - **`ref(target, name)`** - stores the **native HTML element** (`this.$element`) - use for direct DOM access
189
+ - **`refSelf(target, name)`** - stores the **`NDElement` instance** (`this`) - use to keep calling `.nd` methods
119
190
 
120
191
  ```javascript
121
192
  const refs = {};
122
- Div("Content").nd.ref(refs, 'contentDiv');
123
- console.log(refs.contentDiv); // HTMLDivElement
193
+
194
+ Div([
195
+ Input({ type: 'text' }).nd.ref(refs, 'nameInput'), // refs.nameInput -> HTMLInputElement
196
+ Input({ type: 'text' }).nd.refSelf(refs, 'emailInput'), // refs.emailInput -> NDElement instance
197
+
198
+ Button('Actions')
199
+ .nd
200
+ .onClick(() => {
201
+ refs.nameInput.focus(); // native DOM method
202
+ refs.emailInput.onInput(e => console.log(e.target.value)); // nd method
203
+ })
204
+ ]);
124
205
  ```
125
206
 
126
207
  ### `htmlElement()` / `node()`
127
- Returns the native HTML element (alias for `$element`).
208
+
209
+ Returns the native HTML element, both are aliases for `$element`:
128
210
 
129
211
  ```javascript
130
- const div = Div("Hello");
131
- const htmlElement = div.nd.htmlElement(); // HTMLDivElement
132
- const node = div.nd.node(); // Same thing, alias
212
+ const div = Div('Hello');
213
+ div.nd.htmlElement(); // HTMLDivElement
214
+ div.nd.node(); // same
133
215
  ```
134
216
 
135
217
  ### `remove()`
136
- Removes the element and cleans up its internal references.
218
+
219
+ Removes the element from the DOM and cleans up its internal references:
137
220
 
138
221
  ```javascript
139
- const element = Div("To be removed");
140
- element.nd.remove(); // Element removed and cleaned
222
+ const element = Div('Temporary');
223
+ element.nd.remove();
141
224
  ```
142
225
 
143
226
  ### `unmountChildren()`
144
- Unmounts all child elements and cleans up their references.
227
+
228
+ Unmounts all child elements and cleans up their references:
145
229
 
146
230
  ```javascript
147
- const container = Div([
148
- Div("Child 1"),
149
- Div("Child 2")
150
- ]);
151
- container.nd.unmountChildren(); // Children cleaned up
231
+ const container = Div([Div('Child 1'), Div('Child 2')]);
232
+ container.nd.unmountChildren();
152
233
  ```
153
234
 
154
- ## Lifecycle Management
235
+ ### `ghostDom(element)`
236
+
237
+ Appends an element to an internal `DocumentFragment` attached to the component. When the component is inserted into the DOM, both the main element and the ghost elements are injected together - but the user only interacts with the main element.
155
238
 
156
- ### `lifecycle(states)`
157
- Configures lifecycle callbacks.
239
+ This is primarily useful when building components that need a companion element in the DOM. For example, a `Button` that controls a `Dropdown`: the button is the returned element, the dropdown lives in the ghost DOM. Both are rendered, but only the button is exposed to the parent:
158
240
 
159
241
  ```javascript
160
- element.nd.lifecycle({
161
- mounted: (element) => console.log("Element added to DOM"),
162
- unmounted: (element) => console.log("Element removed from DOM")
163
- });
242
+ function DropdownButton(label, items) {
243
+ const isOpen = Observable(false);
244
+
245
+ const dropdown = Div({ class: 'dropdown' }, [
246
+ ShowIf(isOpen, () => Ul(items.map(item => Li(item))))
247
+ ]);
248
+
249
+ return Button(label)
250
+ .nd
251
+ .onClick(() => isOpen.toggle())
252
+ .ghostDom(dropdown); // dropdown is injected into DOM alongside the button
253
+ // but the parent only receives the button
254
+ }
255
+
256
+ // Usage - the parent only works with the button
257
+ const btn = DropdownButton('Options', ['Edit', 'Delete']);
258
+ document.body.appendChild(btn);
259
+ ```
260
+
261
+ ### `attach(methodName, bindingHydrator)`
262
+
263
+ Attaches a template binding hydrator to the element. Used internally by the `useCache` and `useSingleton` rendering systems:
264
+
265
+ ```javascript
266
+ element.nd.attach('onClick', bindingHydrator);
164
267
  ```
165
268
 
269
+ See [Advanced Components](./advanced-components.md) for practical usage.
270
+
271
+ ---
272
+
273
+ ## Lifecycle Management
274
+
166
275
  ### `mounted(callback)`
167
- Shortcut to define only the mount callback.
276
+
277
+ Fires when the element is added to the DOM:
168
278
 
169
279
  ```javascript
170
- Div("Content").nd.mounted(element => {
171
- console.log("Element is now in the DOM!");
172
- });
280
+ Div('Content')
281
+ .nd
282
+ .mounted(element => {
283
+ console.log('In the DOM');
284
+ });
173
285
  ```
174
286
 
175
287
  ### `unmounted(callback)`
176
- Shortcut to define only the unmount callback.
288
+
289
+ Fires when the element is removed from the DOM:
290
+
177
291
  ```javascript
178
- Div("Content").nd.unmounted(element => {
179
- console.log("Element removed from DOM!");
180
- });
292
+ Div('Content')
293
+ .nd
294
+ .unmounted(element => {
295
+ console.log('Removed from DOM');
296
+ // Only clean up external resources here (timers, websockets)
297
+ // Do NOT clean up observables unless the element is permanently destroyed
298
+ });
299
+ ```
300
+
301
+ ### `lifecycle({ mounted, unmounted })`
302
+
303
+ Configures both hooks at once:
304
+
305
+ ```javascript
306
+ Div('Content')
307
+ .nd
308
+ .lifecycle({
309
+ mounted: el => console.log('Mounted'),
310
+ unmounted: el => console.log('Unmounted')
311
+ });
181
312
  ```
182
313
 
183
314
  ### `beforeUnmount(id, callback)`
184
- Registers a callback executed before the element is removed from the DOM.
185
- Useful for exit animations or cleanup before removal.
315
+
316
+ Registers an async callback that runs before the element is removed. Useful for exit animations or data saving:
317
+
186
318
  ```javascript
187
- Div("Content").nd.beforeUnmount('my-cleanup', async () => {
188
- await saveData();
189
- });
319
+ Div('Content')
320
+ .nd
321
+ .beforeUnmount('save', async () => {
322
+ await saveData();
323
+ });
190
324
  ```
191
325
 
326
+ ---
327
+
192
328
  ## Transitions
193
329
 
194
330
  ### `transition(name)`
195
- Applies both enter and exit transitions using CSS classes.
331
+
332
+ Applies both enter and exit transitions via CSS classes:
333
+
196
334
  ```javascript
197
- Div("Content").nd.transition('fade');
198
- // On mount : adds 'fade-enter-from', then 'fade-enter-to'
335
+ Div('Content').nd.transition('fade');
336
+ // On mount: adds 'fade-enter-from', then 'fade-enter-to'
199
337
  // On unmount: adds 'fade-exit'
200
338
  ```
201
339
 
202
- ### `transitionIn(name)`
203
- Applies only the enter transition.
204
- ```javascript
205
- Div("Content").nd.transitionIn('slide');
206
- ```
340
+ ### `transitionIn(name)` / `transitionOut(name)`
341
+
342
+ Apply only the enter or exit transition:
207
343
 
208
- ### `transitionOut(name)`
209
- Applies only the exit transition.
210
344
  ```javascript
211
- Div("Content").nd.transitionOut('slide');
345
+ Div('Content')
346
+ .nd
347
+ .transitionIn('slide-down')
348
+ .transitionOut('slide-up');
212
349
  ```
213
350
 
214
351
  ### `animate(name)`
215
- Triggers a one-shot CSS animation by adding then automatically removing a class.
352
+
353
+ Triggers a one-shot CSS animation, adds the class then removes it automatically:
354
+
216
355
  ```javascript
217
- Button("Click").nd.onClick(function() {
356
+ Button('Click').nd.onClick(function() {
218
357
  this.nd.animate('bounce');
219
358
  });
220
359
  ```
221
360
 
222
- ## Practical Examples
361
+ ---
223
362
 
224
- ### Custom Event Handler
363
+ ## Extending NDElement
364
+
365
+ ### `.nd.with(methods)` - Exposing child component methods
366
+
367
+ `.with()` is designed for components that need to **expose internal control methods to their parent** without leaking their internal observables. The parent accesses these methods via `refSelf`.
368
+
369
+ A typical use case is a component like a media player or a counter that must expose `play`, `pause`, `reset` - letting the parent control it without knowing its internal state:
225
370
 
226
371
  ```javascript
227
- // Extending NDElement with a custom handler
228
- NDElement.prototype.onEnter = function(callback) {
229
- this.$element.addEventListener('keyup', e => {
230
- if (e.key === 'Enter') {
231
- callback(e);
372
+ function Counter(initialValue = 0) {
373
+ const count = Observable(initialValue); // internal - never exposed
374
+ let interval = null;
375
+
376
+ return Div({ class: 'counter' }, [
377
+ Div(['Count: ', count]),
378
+ ])
379
+ .nd
380
+ .with({
381
+ play() {
382
+ if (interval) return this;
383
+ interval = setInterval(() => count.$value++, 1000);
384
+ return this;
385
+ },
386
+ pause() {
387
+ clearInterval(interval);
388
+ interval = null;
389
+ return this;
390
+ },
391
+ reset() {
392
+ this.pause();
393
+ count.set(initialValue);
394
+ return this;
232
395
  }
233
396
  });
234
- return this;
235
- };
397
+ }
236
398
 
237
- // Usage
238
- Input({ type: 'text' })
239
- .nd.onEnter(e => console.log("Enter pressed!"));
240
- ```
399
+ // Parent controls the counter via refSelf - no internal state exposed
400
+ const refs = {};
241
401
 
242
- ### Fluent Chaining
402
+ Div([
403
+ Counter(0).nd.refSelf(refs, 'counter'),
404
+ Button('Play').nd.onClick(() => refs.counter.play()),
405
+ Button('Pause').nd.onClick(() => refs.counter.pause()),
406
+ Button('Reset').nd.onClick(() => refs.counter.reset())
407
+ ]);
408
+ ```
243
409
 
244
- ```javascript
245
- const interactiveButton = Button("Interactive")
246
- .nd.onClick(e => console.log("Clicked"))
247
- .onMouseEnter(e => e.target.style.background = "blue")
248
- .onMouseLeave(e => e.target.style.background = "")
249
- .mounted(el => console.log("Button mounted"));
410
+ > `.with()` only affects the current instance. The methods are not available on other elements.
250
411
 
251
- ```
412
+ ### `NDElement.extend(methods)` - App-wide methods
252
413
 
253
- ### Form with Event Handling
414
+ Adds methods to **all NDElement instances** via the prototype. Use for app-wide utilities:
254
415
 
255
416
  ```javascript
256
- const todoForm = Form([
257
- Input({ type: 'text', value: newTodo })
258
- .nd.onEnter(addTodo),
259
-
260
- Button({ type: 'submit' }, 'Add')
261
- ]).nd.onPreventSubmit(addTodo);
417
+ NDElement.extend({
418
+ onEnter(callback) {
419
+ this.$element.addEventListener('keyup', e => {
420
+ if (e.key === 'Enter') callback(e);
421
+ });
422
+ return this;
423
+ }
424
+ });
425
+
426
+ // Available on every element
427
+ Input().nd.onEnter(e => console.log('Enter pressed'));
262
428
  ```
263
429
 
264
- ### Generic Event Handler - `on()`
430
+ ### Protected methods
265
431
 
266
- For any DOM event:
267
- ```javascript
268
- element.nd.on('customEvent', callback, options)
432
+ The following method names **cannot be overridden** via `NDElement.extend()` - attempting to do so throws a `NativeDocumentError`:
269
433
 
270
- // Example with options
271
- element.nd.on('scroll', callback, { passive: true })
272
- ```
434
+ `constructor`, `valueOf`, `$element`, `$observer`, `ref`, `remove`, `cleanup`, `with`, `extend`, `attach`, `lifecycle`, `mounted`, `unmounted`, `unmountChildren`
273
435
 
274
- ### Reference Management
436
+ ---
275
437
 
276
- ```javascript
277
- const components = {};
438
+ ## Shadow DOM
278
439
 
279
- const app = Div([
280
- Input().nd.ref(components, 'input'),
281
- Button('Focus Input').nd.onClick(() => {
282
- components.input.focus();
283
- })
284
- ]);
440
+ ```javascript
441
+ // Open shadow DOM (inspectable in DevTools)
442
+ Div('Content')
443
+ .nd
444
+ .openShadow(`
445
+ :host { display: block; padding: 20px; }
446
+ p { color: blue; }
447
+ `);
448
+
449
+ // Closed shadow DOM (private)
450
+ Div('Content').nd.closedShadow(`p { color: red; }`);
451
+
452
+ // Manual mode
453
+ Div('Content').nd.shadow('open', `/* scoped styles */`);
285
454
  ```
286
455
 
287
- ## Integration with Observables
456
+ ---
288
457
 
289
- NDElement works seamlessly with NativeDocument's Observable system:
458
+ ## Integration with Observables
290
459
 
291
460
  ```javascript
292
461
  const isVisible = Observable(false);
293
- const message = Observable("Hello");
462
+ const message = Observable('Hello');
294
463
 
295
464
  Div([
296
- Button("Toggle").nd.onClick(() => isVisible.set(!isVisible.val())),
297
- ShowIf(isVisible, () =>
298
- P(message).nd.onClick(() =>
299
- message.set("Clicked!")
300
- )
465
+ Button('Toggle').nd.onClick(() => isVisible.toggle()),
466
+ ShowIf(isVisible, () =>
467
+ P(message).nd.onClick(() => message.set('Clicked!'))
301
468
  )
302
469
  ]);
303
470
  ```
304
471
 
305
- ## Best Practices
306
-
307
- 1. **Fluent chaining**: Use method chaining for concise syntax
308
- 2. **Cleanup**: Call `remove()` to clean up dynamic elements
309
- 3. **Extensions**: Add your own methods to the prototype for specific needs
310
- 4. **Lifecycle**: Use `mounted`/`unmounted` for initialization/cleanup
311
- 5. **References**: Use `ref()` for direct element access when needed
312
-
313
- ## Limitations
314
-
315
- - Event handlers added via .nd.onXxx() are not automatically removed.
316
- Use the native removeEventListener() on .$element if needed,
317
- or rely on .nd.remove() which cleans up the element entirely.
318
- - Access to native HTML element is still necessary for advanced APIs
319
-
320
- NDElement thus provides a practical abstraction layer while preserving the power and performance of native DOM.
321
-
472
+ ---
322
473
 
323
474
  ## Next Steps
324
475
 
325
- Explore these related topics to build complete applications:
326
-
327
- - **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
328
- - **[Args Validation](validation.md)** - Function Argument Validation
329
- - **[Memory Management](memory-management.md)** - Memory management
330
- - **[Anchor](anchor.md)** - Anchor
476
+ - **[Extending NDElement](./extending-native-document-element.md)** - Adding custom methods
477
+ - **[Lifecycle Events](./lifecycle-events.md)** - Mounted, unmounted, beforeUnmount in depth
478
+ - **[Advanced Components](./advanced-components.md)** - Template caching and singleton views
479
+ - **[Memory Management](./memory-management.md)** - Cleanup and auto-cleanup
480
+ - **[Observables](./observables.md)** - Reactive state management
481
+ - **[Anchor](./anchor.md)** - Anchor
331
482
 
332
483
  ## Utilities
333
484
 
334
- - **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
335
- - **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
336
- - **[Filters](docs/utils/filters.md)** - Data filtering helpers
485
+ - **[Cache](./cache.md)** - Lazy initialization and singleton patterns
486
+ - **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
487
+ - **[Filters](./filters.md)** - Data filtering helpers