native-document 1.0.92 → 1.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/native-document.components.min.js +1088 -65
- package/dist/native-document.dev.js +695 -142
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.devtools.min.js +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/advanced-components.md +814 -0
- package/docs/anchor.md +71 -11
- package/docs/cache.md +888 -0
- package/docs/conditional-rendering.md +91 -1
- package/docs/core-concepts.md +9 -2
- package/docs/elements.md +127 -2
- package/docs/extending-native-document-element.md +7 -1
- package/docs/filters.md +1216 -0
- package/docs/getting-started.md +12 -3
- package/docs/lifecycle-events.md +10 -2
- package/docs/list-rendering.md +453 -54
- package/docs/memory-management.md +9 -7
- package/docs/native-document-element.md +30 -9
- package/docs/native-fetch.md +744 -0
- package/docs/observables.md +135 -6
- package/docs/routing.md +7 -1
- package/docs/state-management.md +7 -1
- package/docs/validation.md +8 -1
- package/eslint.config.js +3 -3
- package/package.json +3 -2
- package/readme.md +53 -14
- package/src/components/$traits/HasItems.js +42 -1
- package/src/components/BaseComponent.js +4 -1
- package/src/components/accordion/Accordion.js +112 -8
- package/src/components/accordion/AccordionItem.js +93 -4
- package/src/components/alert/Alert.js +164 -4
- package/src/components/avatar/Avatar.js +236 -22
- package/src/components/menu/index.js +1 -2
- package/src/core/data/ObservableArray.js +120 -2
- package/src/core/data/ObservableChecker.js +50 -0
- package/src/core/data/ObservableItem.js +124 -4
- package/src/core/data/ObservableWhen.js +36 -6
- package/src/core/data/observable-helpers/array.js +12 -3
- package/src/core/data/observable-helpers/computed.js +17 -4
- package/src/core/data/observable-helpers/object.js +19 -3
- package/src/core/elements/control/for-each-array.js +20 -2
- package/src/core/elements/control/for-each.js +17 -5
- package/src/core/elements/control/show-if.js +31 -15
- package/src/core/elements/control/show-when.js +23 -0
- package/src/core/elements/control/switch.js +40 -10
- package/src/core/utils/cache.js +5 -0
- package/src/core/utils/memoize.js +25 -16
- package/src/core/utils/prototypes.js +3 -2
- package/src/core/wrappers/AttributesWrapper.js +1 -1
- package/src/core/wrappers/NDElement.js +41 -1
- package/src/core/wrappers/NdPrototype.js +4 -0
- package/src/core/wrappers/TemplateCloner.js +13 -10
- package/src/core/wrappers/prototypes/bind-class-extensions.js +1 -1
- package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -0
- package/src/router/Route.js +9 -4
- package/src/router/Router.js +28 -9
- package/src/router/errors/RouterError.js +0 -1
- package/types/control-flow.d.ts +9 -6
- package/types/elements.d.ts +6 -3
- package/types/filters/index.d.ts +4 -0
- package/types/nd-element.d.ts +5 -238
- package/types/observable.d.ts +9 -3
- package/types/router.d.ts +5 -1
- package/types/template-cloner.ts +1 -0
- package/types/validator.ts +11 -1
- package/utils.d.ts +2 -1
- package/utils.js +4 -4
- package/src/core/utils/service.js +0 -6
|
@@ -102,6 +102,89 @@ HideIf(condition, content)
|
|
|
102
102
|
ShowIf(condition.check(val => !val), content)
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
## ShowWhen - Observable Value Matching
|
|
106
|
+
|
|
107
|
+
`ShowWhen` is a specialized conditional function that shows content when an Observable matches a specific value. It's particularly useful for state machines and enum-based conditions.
|
|
108
|
+
|
|
109
|
+
### Basic Usage
|
|
110
|
+
```javascript
|
|
111
|
+
const status = Observable('idle');
|
|
112
|
+
|
|
113
|
+
// Show content when status equals 'loading'
|
|
114
|
+
const loadingIndicator = ShowWhen(status, 'loading',
|
|
115
|
+
Div({ class: 'spinner' }, 'Loading...')
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Show content when status equals 'success'
|
|
119
|
+
const successMessage = ShowWhen(status, 'success',
|
|
120
|
+
Div({ class: 'success' }, '✅ Success!')
|
|
121
|
+
);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Two Syntax Options
|
|
125
|
+
|
|
126
|
+
**Option 1: Three arguments (Observable, value, content)**
|
|
127
|
+
```javascript
|
|
128
|
+
const theme = Observable('light');
|
|
129
|
+
|
|
130
|
+
ShowWhen(theme, 'dark',
|
|
131
|
+
Div({ class: 'dark-mode-indicator' }, '🌙 Dark Mode')
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Option 2: Two arguments (ObservableWhen result, content)**
|
|
136
|
+
```javascript
|
|
137
|
+
const theme = Observable('light');
|
|
138
|
+
const isDark = theme.when('dark'); // Returns ObservableWhen
|
|
139
|
+
|
|
140
|
+
ShowWhen(isDark,
|
|
141
|
+
Div({ class: 'dark-mode-indicator' }, '🌙 Dark Mode')
|
|
142
|
+
);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Practical Example: Status-Based UI
|
|
146
|
+
```javascript
|
|
147
|
+
const connectionStatus = Observable('disconnected');
|
|
148
|
+
|
|
149
|
+
const StatusIndicator = Div({ class: 'status-bar' }, [
|
|
150
|
+
ShowWhen(connectionStatus, 'connecting',
|
|
151
|
+
Span({ class: 'status connecting' }, '🔄 Connecting...')
|
|
152
|
+
),
|
|
153
|
+
ShowWhen(connectionStatus, 'connected',
|
|
154
|
+
Span({ class: 'status connected' }, '✅ Connected')
|
|
155
|
+
),
|
|
156
|
+
ShowWhen(connectionStatus, 'disconnected',
|
|
157
|
+
Span({ class: 'status disconnected' }, '❌ Disconnected')
|
|
158
|
+
),
|
|
159
|
+
ShowWhen(connectionStatus, 'error',
|
|
160
|
+
Span({ class: 'status error' }, '⚠️ Connection Error')
|
|
161
|
+
)
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
// Update status
|
|
165
|
+
setTimeout(() => connectionStatus.set('connecting'), 1000);
|
|
166
|
+
setTimeout(() => connectionStatus.set('connected'), 3000);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Both can handle multiple states, but they serve different purposes:
|
|
170
|
+
```javascript
|
|
171
|
+
const phase = Observable('loading');
|
|
172
|
+
|
|
173
|
+
// ShowWhen: Multiple independent conditions
|
|
174
|
+
Div([
|
|
175
|
+
ShowWhen(phase, 'loading', LoadingSpinner()),
|
|
176
|
+
ShowWhen(phase, 'success', SuccessMessage()),
|
|
177
|
+
ShowWhen(phase, 'error', ErrorMessage())
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
// Match: Single content area that switches
|
|
181
|
+
Match(phase, {
|
|
182
|
+
loading: LoadingSpinner(),
|
|
183
|
+
success: SuccessMessage(),
|
|
184
|
+
error: ErrorMessage()
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
105
188
|
## Switch - Binary Content Switching
|
|
106
189
|
|
|
107
190
|
`Switch` efficiently toggles between exactly two pieces of content based on a boolean condition:
|
|
@@ -627,6 +710,13 @@ Now that you understand conditional rendering, explore these related topics:
|
|
|
627
710
|
- **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
|
|
628
711
|
- **[NDElement](native-document-element.md)** - Native Document Element
|
|
629
712
|
- **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
|
|
713
|
+
- **[Advanced Components](advanced-components.md)** - Template caching and singleton views
|
|
630
714
|
- **[Args Validation](validation.md)** - Function Argument Validation
|
|
631
715
|
- **[Memory Management](memory-management.md)** - Memory management
|
|
632
|
-
- **[Anchor](anchor.md)** - Anchor
|
|
716
|
+
- **[Anchor](anchor.md)** - Anchor
|
|
717
|
+
|
|
718
|
+
## Utilities
|
|
719
|
+
|
|
720
|
+
- **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
|
|
721
|
+
- **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
|
|
722
|
+
- **[Filters](docs/utils/filters.md)** - Data filtering helpers
|
package/docs/core-concepts.md
CHANGED
|
@@ -376,7 +376,7 @@ function Header() {
|
|
|
376
376
|
const user = Store.use('user');
|
|
377
377
|
const theme = Store.use('theme');
|
|
378
378
|
|
|
379
|
-
return Div({ class: `theme-${
|
|
379
|
+
return Div({ class: theme.check(t => `theme-${t}`) }, [
|
|
380
380
|
ShowIf(user.check(u => u.isLoggedIn),
|
|
381
381
|
Div(['Welcome, ', user.$value.name])
|
|
382
382
|
)
|
|
@@ -512,6 +512,13 @@ Now that you understand NativeDocument's core concepts, explore these advanced t
|
|
|
512
512
|
- **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
|
|
513
513
|
- **[NDElement](native-document-element.md)** - Native Document Element
|
|
514
514
|
- **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
|
|
515
|
+
- **[Advanced Components](advanced-components.md)** - Template caching and singleton views
|
|
515
516
|
- **[Args Validation](validation.md)** - Function Argument Validation
|
|
516
517
|
- **[Memory Management](memory-management.md)** - Memory management
|
|
517
|
-
- **[Anchor](anchor.md)** - Anchor
|
|
518
|
+
- **[Anchor](anchor.md)** - Anchor
|
|
519
|
+
|
|
520
|
+
## Utilities
|
|
521
|
+
|
|
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
|
package/docs/elements.md
CHANGED
|
@@ -66,7 +66,7 @@ const theme = Observable("dark");
|
|
|
66
66
|
const greeting = Div({
|
|
67
67
|
class: theme, // Updates when theme changes
|
|
68
68
|
hidden: isVisible.check(val => !val) // Hide when isVisible is false
|
|
69
|
-
},
|
|
69
|
+
}, ['Hello ', userName, '!']); // Reactive text content
|
|
70
70
|
|
|
71
71
|
// Reactive styles
|
|
72
72
|
const box = Div({
|
|
@@ -142,6 +142,63 @@ const form = Form()
|
|
|
142
142
|
});
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
## Advanced Element Composition
|
|
146
|
+
|
|
147
|
+
### Extending Elements with Custom Methods
|
|
148
|
+
|
|
149
|
+
Use `.nd.with()` to add custom methods to elements:
|
|
150
|
+
```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();
|
|
163
|
+
|
|
164
|
+
// Chain custom methods
|
|
165
|
+
customButton.resetStyle().highlight();
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Class and Style Accumulators
|
|
169
|
+
|
|
170
|
+
Build classes and styles programmatically:
|
|
171
|
+
```javascript
|
|
172
|
+
import { classPropertyAccumulator, cssPropertyAccumulator } from 'native-document';
|
|
173
|
+
|
|
174
|
+
// Class accumulator
|
|
175
|
+
const classes = classPropertyAccumulator(['btn']);
|
|
176
|
+
classes.add('primary');
|
|
177
|
+
classes.add('large');
|
|
178
|
+
|
|
179
|
+
const button = Button({ class: classes.value() }, "Submit");
|
|
180
|
+
// Result: class="btn primary large"
|
|
181
|
+
|
|
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 }
|
|
187
|
+
|
|
188
|
+
// CSS accumulator
|
|
189
|
+
const styles = cssPropertyAccumulator({ color: 'red' });
|
|
190
|
+
styles.add('font-size', '16px');
|
|
191
|
+
styles.add('margin', '10px');
|
|
192
|
+
|
|
193
|
+
const element = Div({ style: styles.value() }, "Styled content");
|
|
194
|
+
// Result: style="color: red; font-size: 16px; margin: 10px"
|
|
195
|
+
|
|
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
|
+
```
|
|
201
|
+
|
|
145
202
|
## Form Elements and Two-Way Binding
|
|
146
203
|
|
|
147
204
|
```javascript
|
|
@@ -214,6 +271,34 @@ const widget = Div("Widget")
|
|
|
214
271
|
unmounted: element => console.log("Widget unmounted")
|
|
215
272
|
});
|
|
216
273
|
```
|
|
274
|
+
## Manual DOM Manipulation
|
|
275
|
+
|
|
276
|
+
### Unmounting Children
|
|
277
|
+
|
|
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
|
+
]);
|
|
285
|
+
|
|
286
|
+
// Remove all children
|
|
287
|
+
container.nd.unmountChildren();
|
|
288
|
+
// container is now empty but still in DOM
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Removing Elements
|
|
292
|
+
|
|
293
|
+
Remove an element from the DOM:
|
|
294
|
+
```javascript
|
|
295
|
+
const element = Div("Content");
|
|
296
|
+
document.body.appendChild(element.nd.node());
|
|
297
|
+
|
|
298
|
+
// Remove from DOM
|
|
299
|
+
element.nd.remove();
|
|
300
|
+
// Element is detached from DOM
|
|
301
|
+
```
|
|
217
302
|
|
|
218
303
|
## Element References
|
|
219
304
|
|
|
@@ -231,6 +316,37 @@ const app = Div([
|
|
|
231
316
|
]);
|
|
232
317
|
```
|
|
233
318
|
|
|
319
|
+
## Shadow DOM
|
|
320
|
+
|
|
321
|
+
NativeDocument supports Shadow DOM for encapsulated components:
|
|
322
|
+
```javascript
|
|
323
|
+
// Open shadow DOM (inspectable)
|
|
324
|
+
const widget = Div("Widget content")
|
|
325
|
+
.nd.openShadow(`
|
|
326
|
+
:host {
|
|
327
|
+
display: block;
|
|
328
|
+
padding: 20px;
|
|
329
|
+
background: #f0f0f0;
|
|
330
|
+
}
|
|
331
|
+
p { color: blue; }
|
|
332
|
+
|
|
333
|
+
`);
|
|
334
|
+
|
|
335
|
+
// Closed shadow DOM (private)
|
|
336
|
+
const privateWidget = Div("Private content")
|
|
337
|
+
.nd.closedShadow(`
|
|
338
|
+
p { color: red; }
|
|
339
|
+
|
|
340
|
+
`);
|
|
341
|
+
|
|
342
|
+
// Manual shadow DOM with mode
|
|
343
|
+
const customWidget = Div("Custom")
|
|
344
|
+
.nd.shadow('open', `
|
|
345
|
+
/* Scoped styles */
|
|
346
|
+
|
|
347
|
+
`);
|
|
348
|
+
```
|
|
349
|
+
|
|
234
350
|
## Practical Example: Simple Button with Event
|
|
235
351
|
|
|
236
352
|
```javascript
|
|
@@ -281,6 +397,8 @@ const validateForm = () => {
|
|
|
281
397
|
|
|
282
398
|
Observable.update(errors, newErrors);
|
|
283
399
|
|
|
400
|
+
errors.set(newErrors);
|
|
401
|
+
|
|
284
402
|
return Object.values(newErrors).every(error => error === "");
|
|
285
403
|
};
|
|
286
404
|
|
|
@@ -382,6 +500,13 @@ Now that you understand NativeDocument's elements, explore these advanced topics
|
|
|
382
500
|
- **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
|
|
383
501
|
- **[NDElement](native-document-element.md)** - Native Document Element
|
|
384
502
|
- **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
|
|
503
|
+
- **[Advanced Components](advanced-components.md)** - Template caching and singleton views
|
|
385
504
|
- **[Args Validation](validation.md)** - Function Argument Validation
|
|
386
505
|
- **[Memory Management](memory-management.md)** - Memory management
|
|
387
|
-
- **[Anchor](anchor.md)** - Anchor
|
|
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
|
|
@@ -265,4 +265,10 @@ Explore these related topics to build complete applications:
|
|
|
265
265
|
|
|
266
266
|
- **[Args Validation](validation.md)** - Function Argument Validation
|
|
267
267
|
- **[Memory Management](memory-management.md)** - Memory management
|
|
268
|
-
- **[Anchor](anchor.md)** - Anchor
|
|
268
|
+
- **[Anchor](anchor.md)** - Anchor
|
|
269
|
+
|
|
270
|
+
## Utilities
|
|
271
|
+
|
|
272
|
+
- **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
|
|
273
|
+
- **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
|
|
274
|
+
- **[Filters](docs/utils/filters.md)** - Data filtering helpers
|