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,524 +1,355 @@
1
+ ---
2
+ title: Core Concepts
3
+ description: The fundamental concepts and philosophy behind NativeDocument - observables, elements, reactivity, and component patterns
4
+ ---
5
+
1
6
  # Core Concepts
2
7
 
3
- This guide covers the fundamental concepts and philosophy behind NativeDocument. Understanding these principles will help you build better applications and make the most of the framework's capabilities.
8
+ This guide covers the fundamental concepts and philosophy behind NativeDocument.
9
+
10
+ ---
4
11
 
5
12
  ## Philosophy
6
13
 
7
- NativeDocument was designed with several core principles in mind:
14
+ ### Native-First
8
15
 
9
- ### Native-First Approach
10
- Unlike frameworks that abstract away the DOM, NativeDocument embraces it. Every element you create is a real DOM node, and every interaction happens through native browser APIs. This means:
16
+ NativeDocument embraces the DOM rather than abstracting it away. Every element you create is a real DOM node, and every interaction uses native browser APIs:
11
17
 
12
18
  - No virtual DOM overhead
13
- - Direct access to all browser features
14
- - Familiar debugging experience
19
+ - Direct access to all browser APIs
20
+ - Familiar debugging in DevTools
15
21
  - Better performance for DOM-heavy applications
16
22
 
17
23
  ### Reactive by Design
18
- Reactivity is built into the core of NativeDocument through observables. When data changes, the UI updates automatically without manual DOM manipulation:
19
24
 
20
- ```javascript
21
- const { Div } = NativeDocument.elements;
22
- const { Observable } = NativeDocument;
25
+ Reactivity is built into the core through observables. When data changes, the UI updates automatically:
23
26
 
27
+ ```javascript
24
28
  const message = Observable('Hello World');
25
29
  const display = Div(message);
26
30
 
27
- // UI updates automatically
28
- message.set('Hello NativeDocument!');
31
+ message.set('Hello NativeDocument!'); // UI updates automatically
29
32
  ```
30
33
 
31
34
  ### Zero Build Requirement
32
- While you can use build tools, NativeDocument works perfectly without them. Load it from a CDN and start building immediately:
35
+
36
+ NativeDocument works without a build step - load from CDN and start immediately:
33
37
 
34
38
  ```html
35
39
  <script src="https://cdn.jsdelivr.net/gh/afrocodeur/native-document@latest/dist/native-document.min.js"></script>
36
40
  <script>
37
- // Start building immediately
38
- const { Div } = NativeDocument.elements;
39
- // Your app here
41
+ const { Div, Button } = NativeDocument.elements;
42
+ const { Observable } = NativeDocument;
40
43
  </script>
41
44
  ```
42
45
 
43
- ## Core Architecture
46
+ For production, use the CLI for optimal bundle size via tree-shaking:
47
+
48
+ ```bash
49
+ nd create MyApp
50
+ ```
44
51
 
45
- ### Observables - The Reactive Foundation
52
+ ---
46
53
 
47
- Observables are the heart of NativeDocument's reactivity system. They wrap values and notify subscribers when changes occur.
54
+ ## Observables
55
+
56
+ Observables wrap values and notify the UI when they change. They are the reactive foundation of NativeDocument.
48
57
 
49
- #### Basic Observable
50
58
  ```javascript
59
+ import { Observable } from 'native-document';
60
+
51
61
  const count = Observable(0);
52
62
 
53
- // Subscribe to changes
54
- count.subscribe(newValue => {
55
- console.log('Count changed to:', newValue);
56
- });
63
+ count.set(5); // triggers update
64
+ count.$value = 5; // same thing
65
+ count.set(v => v + 1); // function form
57
66
 
58
- // Update the value
59
- count.set(5); // Logs: "Count changed to: 5"
67
+ count.val(); // read current value
68
+ count.$value; // same
60
69
  ```
61
70
 
62
- #### Observable Objects
71
+ ### Object observables
72
+
63
73
  ```javascript
64
74
  const user = Observable({ name: 'John', age: 25 });
65
75
 
66
- // Access values
67
- console.log(user.val().name); // "John"
68
- console.log(user.$value.name); // "John" (proxy syntax)
69
-
70
- // Update object - replaces entire value
71
76
  user.set({ ...user.val(), name: 'Jane' });
77
+ user.set(data => ({ ...data, name: 'Jane' }));
72
78
 
73
- // This won't trigger reactivity (common mistake)
74
- // user.name = 'Jane'; // Wrong!
79
+ // user.name = 'Jane' -- wrong, won't trigger update
75
80
  ```
76
81
 
77
- #### Observable Arrays
82
+ For per-property reactivity:
83
+
84
+ ```javascript
85
+ const user = Observable.object({ name: 'John', age: 25 });
86
+ user.name.set('Jane'); // only name updates
87
+ user.$value; // { name: 'Jane', age: 25 }
88
+ ```
89
+
90
+ ### Array observables
91
+
78
92
  ```javascript
79
93
  const todos = Observable.array([]);
80
94
 
81
- // Array methods trigger reactivity
82
- todos.push({ text: 'Learn NativeDocument', done: false });
83
- todos.pop();
95
+ todos.push({ id: 1, text: 'Buy milk', done: false });
96
+ todos.splice(0, 1);
84
97
  todos.sort((a, b) => a.text.localeCompare(b.text));
85
-
86
- // Access like normal array
87
- console.log(todos.val().length);
88
98
  ```
89
99
 
90
- #### Computed Observables
100
+ ### Computed observables
101
+
102
+ The callback receives dependency values as arguments in order:
103
+
91
104
  ```javascript
92
105
  const firstName = Observable('John');
93
- const lastName = Observable('Doe');
106
+ const lastName = Observable('Doe');
94
107
 
95
- const fullName = Observable.computed(() => {
96
- return `${firstName.val()} ${lastName.val()}`;
108
+ const fullName = Observable.computed((first, last) => {
109
+ return `${first} ${last}`;
97
110
  }, [firstName, lastName]);
98
111
 
99
- // Updates automatically when dependencies change
100
- firstName.set('Jane'); // fullName becomes "Jane Doe"
112
+ firstName.set('Jane'); // fullName -> "Jane Doe"
101
113
  ```
102
114
 
103
- ### Elements - Building the UI
104
-
105
- Elements in NativeDocument are functions that create and return DOM nodes. They follow a consistent pattern:
106
-
107
- #### Basic Element Creation
108
- ```javascript
109
- const { Div, Button, Input } = NativeDocument.elements;
110
-
111
- // Element with no attributes or children
112
- const simpleDiv = Div();
115
+ See [Observables](./observables.md) for the full reference.
113
116
 
114
- // Element with attributes only
115
- const styledDiv = Div({ class: 'container', id: 'main' });
117
+ ---
116
118
 
117
- // Element with children only
118
- const textDiv = Div('Hello World');
119
- const arrayDiv = Div(['Hello ', 'World']);
119
+ ## Elements
120
120
 
121
- // Element with both attributes and children
122
- const fullDiv = Div({ class: 'card' }, [
123
- 'Content here'
124
- ]);
125
- ```
121
+ Elements are functions that create and return real DOM nodes:
126
122
 
127
- #### Reactive Attributes
128
123
  ```javascript
129
- const isVisible = Observable(true);
130
- const theme = Observable('dark');
131
-
132
- const element = Div({
133
- class: {
134
- 'visible': isVisible,
135
- 'dark-theme': theme.check(t => t === 'dark')
136
- },
137
- style: {
138
- opacity: isVisible.check(v => v ? 1 : 0.5)
139
- }
140
- });
141
- ```
124
+ import { Div, Button, Input, H1, P } from 'native-document/elements';
142
125
 
143
- #### Event Handling
144
- ```javascript
145
- const counter = Observable(0);
126
+ // No attributes
127
+ const simple = Div('Hello World');
146
128
 
147
- const button = Button('Click me')
148
- .nd.onClick(() => {
149
- counter.set(counter.val() + 1);
150
- });
129
+ // With attributes
130
+ const styled = Div({ class: 'card', id: 'main' }, 'Content');
151
131
 
152
- // Multiple events
153
- const input = Input()
154
- .nd.onFocus(e => console.log('Focused'))
155
- .nd.onBlur(e => console.log('Blurred'))
156
- .nd.onInput(e => console.log('Value:', e.target.value));
157
-
158
- //Or
159
- const input = Input()
160
- .nd.on({
161
- focus: e => console.log('Focused'),
162
- blur: e => console.log('Blurred'),
163
- input: e => console.log('Value:', e.target.value)
164
- })
132
+ // With reactive attributes
133
+ const isVisible = Observable(true);
134
+ const box = Div({
135
+ class: { 'hidden': isVisible.isFalsy() },
136
+ style: { opacity: isVisible.format(v => v ? 1 : 0.5) }
137
+ }, 'Content');
138
+
139
+ // Children - text, numbers, observables, elements, closures, or arrays
140
+ const mixed = Div([
141
+ H1('Title'),
142
+ 'Some text',
143
+ P(count),
144
+ () => Button('Dynamic')
145
+ ]);
165
146
  ```
166
147
 
167
- ### Lifecycle and Memory Management
168
-
169
- NativeDocument includes automatic memory management to prevent memory leaks.
148
+ ### Event handling
170
149
 
171
- #### Element Lifecycle
172
150
  ```javascript
173
- const element = Div('Content')
174
- .nd.mounted(el => {
175
- console.log('Element added to DOM');
176
- })
177
- .nd.unmounted(el => {
178
- console.log('Element removed from DOM');
151
+ Button('Click me').nd.onClick(() => console.log('Clicked'));
152
+
153
+ // Multi-line callback
154
+ Button('Submit')
155
+ .nd
156
+ .onClick(e => {
157
+ e.preventDefault();
158
+ submitForm();
179
159
  });
180
- ```
181
160
 
182
- #### Manual Cleanup
183
- For complex scenarios, you can manage cleanup manually:
161
+ // Multiple events - chain after first .nd
162
+ Input({ type: 'text' })
163
+ .nd
164
+ .onFocus(() => console.log('Focused'))
165
+ .onBlur(() => console.log('Blurred'))
166
+ .onInput(e => console.log('Value:', e.target.value));
167
+ ```
184
168
 
185
- ```javascript
186
- const observable = Observable(0);
169
+ See [Elements](./elements.md) for the full reference.
187
170
 
188
- // Manual subscription
189
- const unsubscribe = observable.subscribe(value => {
190
- console.log('Value:', value);
191
- });
192
-
193
- // Clean up when needed
194
- unsubscribe();
195
- ```
171
+ ---
196
172
 
197
173
  ## Reactivity Model
198
174
 
199
- ### Data Flow
200
- NativeDocument follows a unidirectional data flow:
175
+ Data flows in one direction:
201
176
 
202
- 1. **State Change**: An observable value is updated
203
- 2. **Notification**: All subscribers are notified
204
- 3. **DOM Update**: UI elements update automatically
205
- 4. **Event Handling**: User interactions trigger new state changes
177
+ 1. **State change** - an observable is updated
178
+ 2. **Notification** - all subscribers are notified
179
+ 3. **DOM update** - UI elements update automatically
180
+ 4. **Event handling** - user interactions trigger new state changes
206
181
 
207
182
  ```javascript
208
183
  const items = Observable.array(['Apple', 'Banana']);
209
184
 
210
- const list = ForEach(items, (item) =>
211
- Div([
212
- item,
213
- Button('Remove').nd.onClick(() => {
214
- // User action → State change -> UI update
215
- const index = items.val().indexOf(item);
216
- items.splice(index, 1);
217
- })
218
- ])
219
- );
185
+ Ul(
186
+ ForEach(items, item =>
187
+ Li([
188
+ item,
189
+ Button('Remove')
190
+ .nd.onClick(() => items.removeItem(item))
191
+ ])
192
+ )
193
+ )
220
194
  ```
221
195
 
222
- ### Reactive Chains
223
- Observables can depend on other observables, creating reactive chains:
196
+ ### Reactive chains
224
197
 
225
198
  ```javascript
226
- const price = Observable(100);
199
+ const price = Observable(100);
227
200
  const quantity = Observable(2);
228
- const discount = Observable(0.1);
201
+ const tax = Observable(0.2);
229
202
 
230
- const subtotal = Observable.computed(() => {
231
- return price.val() * quantity.val();
232
- }, [price, quantity]);
203
+ const subtotal = Observable.computed((p, q) => p * q, [price, quantity]);
204
+ const total = Observable.computed((sub, t) => sub * (1 + t), [subtotal, tax]);
233
205
 
234
- const total = Observable.computed(() => {
235
- return subtotal.val() * (1 - discount.val());
236
- }, [subtotal, discount]);
237
-
238
- // Changing any value updates the chain
239
- price.set(150); // subtotal and total update automatically
206
+ price.set(150); // subtotal and total both update
240
207
  ```
241
208
 
209
+ ---
210
+
242
211
  ## Component Patterns
243
212
 
244
- ### Functional Components
245
- Create reusable components as functions:
213
+ ### Functional components
246
214
 
247
215
  ```javascript
248
- function UserCard(user) {
216
+ function UserCard({ name, email }) {
249
217
  return Div({ class: 'user-card' }, [
250
- Div({ class: 'name' }, user.name),
251
- Div({ class: 'email' }, user.email),
252
- Button('Edit').nd.onClick(() => {
253
- // Handle edit
254
- })
218
+ Div({ class: 'name' }, name),
219
+ Div({ class: 'email' }, email),
220
+ Button('Edit').nd.onClick(() => editUser(name))
255
221
  ]);
256
222
  }
257
223
 
258
- // Usage
259
- const user = { name: 'John Doe', email: 'john@example.com' };
260
- const card = UserCard(user);
224
+ document.body.appendChild(UserCard({ name: 'John', email: 'john@example.com' }));
261
225
  ```
262
226
 
263
- ### Stateful Components
264
- Components with internal state:
227
+ ### Stateful components
265
228
 
266
229
  ```javascript
267
230
  function Counter(initialValue = 0) {
268
231
  const count = Observable(initialValue);
269
-
232
+
270
233
  return Div({ class: 'counter' }, [
271
234
  Div(['Count: ', count]),
272
- Button('-').nd.onClick(() => count.set(count.val() - 1)),
273
- Button('+').nd.onClick(() => count.set(count.val() + 1)),
235
+ Button('-').nd.onClick(() => count.$value--),
236
+ Button('+').nd.onClick(() => count.$value++),
274
237
  Button('Reset').nd.onClick(() => count.set(initialValue))
275
238
  ]);
276
239
  }
277
-
278
- // Usage
279
- const myCounter = Counter(10);
280
240
  ```
281
241
 
282
- ### Higher-Order Components
283
- Components that enhance other components:
242
+ ### Exposing methods to parent via `.nd.with()`
284
243
 
285
244
  ```javascript
286
- function withLoading(component, isLoading) {
287
- return When(isLoading.check(loading => !loading))
288
- .show(component)
289
- .otherwise(Div({ class: 'loading' }, 'Loading...'));
290
- // Or
291
-
292
- // return Switch(isLoading.check(loading => !loading),
293
- // component,
294
- // Div({ class: 'loading' }, 'Loading...')
295
- // );
245
+ function Timer() {
246
+ const count = Observable(0);
247
+ let interval = null;
248
+
249
+ return Div(['Time: ', count])
250
+ .nd.with({
251
+ start() {
252
+ if (interval) return this;
253
+ interval = setInterval(() => count.$value++, 1000);
254
+ return this;
255
+ },
256
+ stop() {
257
+ clearInterval(interval);
258
+ interval = null;
259
+ return this;
260
+ },
261
+ reset() {
262
+ this.stop();
263
+ count.set(0);
264
+ return this;
265
+ }
266
+ });
296
267
  }
297
268
 
298
- // Usage
299
- const isLoading = Observable(true);
300
- const content = Div('Main content');
301
- const wrappedContent = withLoading(content, isLoading);
269
+ const refs = {};
270
+ Div([
271
+ Timer().nd.refSelf(refs, 'timer'),
272
+ Button('Start').nd.onClick(() => refs.timer.start()),
273
+ Button('Stop').nd.onClick(() => refs.timer.stop()),
274
+ Button('Reset').nd.onClick(() => refs.timer.reset())
275
+ ]);
302
276
  ```
303
277
 
278
+ ---
279
+
304
280
  ## State Management Patterns
305
281
 
306
- ### Local State
307
- For component-specific state, use observables directly:
282
+ ### Local state
283
+
284
+ Use observables directly for component-specific state:
308
285
 
309
286
  ```javascript
310
- function TodoForm() {
311
- const text = Observable('');
312
- const isValid = Observable.computed(() => text.val().trim().length > 0, [text]);
313
-
287
+ function SearchBox(onSearch) {
288
+ const query = Observable('');
289
+ const isValid = query.isNotEmpty();
290
+
314
291
  return Div([
315
- Input({ placeholder: 'Enter todo...', value: text }),
316
- Button('Add')
292
+ Input({ placeholder: 'Search...', value: query }),
293
+ Button('Search')
317
294
  .nd.onClick(() => {
318
295
  if (isValid.val()) {
319
- // Add todo logic
320
- text.set('');
296
+ onSearch(query.val());
321
297
  }
322
298
  })
323
299
  ]);
324
300
  }
325
301
  ```
326
302
 
327
- ### Shared State
328
- For state shared between components, create a store:
303
+ ### Global state with Store
329
304
 
330
305
  ```javascript
331
- // Create a shared store
332
- const TodoStore = {
333
- todos: Observable.array([]),
334
-
335
- addTodo(text) {
336
- this.todos.push({
337
- id: Date.now(),
338
- text: text,
339
- done: false
340
- });
341
- },
342
-
343
- removeTodo(id) {
344
- const index = this.todos.val().findIndex(todo => todo.id === id);
345
- if (index !== -1) {
346
- this.todos.splice(index, 1);
347
- }
348
- }
349
- };
350
-
351
- // Use in components
352
- function TodoList() {
353
- return ForEach(TodoStore.todos, (todo) =>
354
- Div([
355
- todo.text,
356
- Button('Delete').nd.onClick(() => {
357
- TodoStore.removeTodo(todo.id);
358
- })
359
- ])
360
- );
361
- }
362
- ```
363
-
364
- ### Global State with Store
365
- For complex applications, use the built-in Store:
306
+ import { Store } from 'native-document';
366
307
 
367
- ```javascript
368
- const { Store } = NativeDocument;
308
+ Store.create('theme', 'light');
369
309
 
370
- // Create global observables
371
- const userStore = Store.create('user', { name: '', isLoggedIn: false });
372
- const themeStore = Store.create('theme', 'light');
310
+ const UserStore = Store.group('user', g => {
311
+ g.createResettable('session', { id: null, name: '', isLoggedIn: false });
312
+ });
373
313
 
374
- // Use in components
375
314
  function Header() {
376
- const user = Store.use('user');
377
- const theme = Store.use('theme');
378
-
379
- return Div({ class: theme.check(t => `theme-${t}`) }, [
380
- ShowIf(user.check(u => u.isLoggedIn),
381
- Div(['Welcome, ', user.$value.name])
315
+ const theme = Store.use('theme');
316
+ const session = UserStore.use('session');
317
+
318
+ return Div({ class: theme.format(t => `theme-${t}`) }, [
319
+ ShowIf(session.is(s => s.isLoggedIn),
320
+ () => Div(['Welcome, ', session.select(s => s.name)])
382
321
  )
383
322
  ]);
384
323
  }
385
324
  ```
386
325
 
387
- ## Error Handling
388
-
389
- ### Graceful Error Handling
390
- Wrap potentially failing operations:
326
+ ---
391
327
 
392
- ```javascript
393
- function SafeComponent() {
394
- try {
395
- return riskyOperation();
396
- } catch (error) {
397
- console.error('Component error:', error);
398
- return Div({ class: 'error' }, 'Something went wrong');
399
- }
400
- }
401
- ```
402
-
403
- ### Error Boundaries
404
- Use error boundaries for robust applications:
405
-
406
- ```javascript
407
- function withErrorBoundary(component) {
408
- return component.errorBoundary((error) => {
409
- console.error('Error caught:', error);
410
- return Div({ class: 'error-boundary' }, [
411
- 'An error occurred. Please try again.'
412
- ]);
413
- });
414
- }
415
- ```
416
-
417
- ## Performance Considerations
418
-
419
- ### Efficient Updates
420
- NativeDocument optimizes updates automatically, but you can help:
421
-
422
- ```javascript
423
- // Good: Batch related updates
424
- function updateUser(newData) {
425
- user.set({ ...user.val(), ...newData });
426
- }
427
-
428
- // Less efficient: Multiple separate updates
429
- function updateUserSeparately(name, email) {
430
- user.set({ ...user.val(), name });
431
- user.set({ ...user.val(), email });
432
- }
433
- ```
434
-
435
- ### List Rendering
436
- Use key functions for efficient list updates:
437
-
438
- ```javascript
439
- ForEach(items, (item) =>
440
- Div(['Item: ', item.name]),
441
- // Key function for efficient updates
442
- (item) => item.id
443
- );
444
- // or
445
- ForEach(items, (item) =>
446
- Div(['Item: ', item.name]),
447
- // Key property for efficient updates
448
- 'id'
449
- );
450
- ```
451
-
452
- ## Best Practices
453
-
454
- ### 1. Keep Components Small and Focused
455
- ```javascript
456
- // Good: Focused component
457
- function UserName(user) {
458
- return Div({ class: 'user-name' }, user.name);
459
- }
460
-
461
- // Less ideal: Component doing too much
462
- function UserEverything(user) {
463
- // Handles name, email, avatar, settings, etc.
464
- }
465
- ```
466
-
467
- ### 2. Use Computed Values for Derived State
468
- ```javascript
469
- // Good: Computed value
470
- const filteredItems = Observable.computed(() => {
471
- return items.val().filter(item => item.visible);
472
- }, [items]);
473
-
474
- // Less efficient: Manual filtering on each render
475
- ```
328
+ ## Error Handling
476
329
 
477
- ### 3. Separate Concerns
478
330
  ```javascript
479
- // Good: Separate data logic from UI
480
- const UserService = {
481
- async loadUser(id) {
482
- // Data loading logic
483
- }
484
- };
485
-
486
- function UserProfile(userId) {
487
- // UI rendering logic
488
- }
331
+ // Error boundary on a component function
332
+ const SafeWidget = Widget.errorBoundary((error, { caller, args }) => {
333
+ console.error('Widget error:', error);
334
+ return Div({ class: 'error' }, 'Something went wrong');
335
+ });
489
336
  ```
490
337
 
491
- ### 4. Use Meaningful Names
492
- ```javascript
493
- // Good: Clear naming
494
- const isUserLoggedIn = Observable(false);
495
- const currentUserName = Observable('');
496
-
497
- // Less clear
498
- const flag = Observable(false);
499
- const data = Observable('');
500
- ```
338
+ ---
501
339
 
502
340
  ## Next Steps
503
341
 
504
- Now that you understand NativeDocument's core concepts, explore these advanced topics:
505
-
506
- - **[Observables](observables.md)** - Reactive state management
507
- - **[Elements](elements.md)** - Creating and composing UI
508
- - **[Conditional Rendering](conditional-rendering.md)** - Dynamic content
509
- - **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
510
- - **[Routing](routing.md)** - Navigation and URL management
511
- - **[State Management](state-management.md)** - Global state patterns
512
- - **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
513
- - **[NDElement](native-document-element.md)** - Native Document Element
514
- - **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
515
- - **[Advanced Components](advanced-components.md)** - Template caching and singleton views
516
- - **[Args Validation](validation.md)** - Function Argument Validation
517
- - **[Memory Management](memory-management.md)** - Memory management
518
- - **[Anchor](anchor.md)** - Anchor
342
+ - **[Observables](./observables.md)** - Full reactive state reference
343
+ - **[Elements](./elements.md)** - Creating and composing UI
344
+ - **[Conditional Rendering](./conditional-rendering.md)** - ShowIf, Match, Switch
345
+ - **[List Rendering](./list-rendering.md)** - ForEach and dynamic lists
346
+ - **[Routing](./routing.md)** - Navigation and URL management
347
+ - **[State Management](./state-management.md)** - Global state with Store
348
+ - **[NDElement](./native-document-element.md)** - Full `.nd` API reference
349
+ - **[CLI](./cli.md)** - Project scaffolding
519
350
 
520
351
  ## Utilities
521
352
 
522
- - **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
523
- - **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
524
- - **[Filters](docs/utils/filters.md)** - Data filtering helpers
353
+ - **[Cache](./cache.md)** - Lazy initialization and singleton patterns
354
+ - **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
355
+ - **[Filters](./filters.md)** - Data filtering helpers