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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
var NativeDocument = (function (exports) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
let DebugManager
|
|
4
|
+
let DebugManager = {};
|
|
5
5
|
|
|
6
6
|
{
|
|
7
|
-
DebugManager
|
|
7
|
+
DebugManager = {
|
|
8
8
|
enabled: false,
|
|
9
9
|
|
|
10
10
|
enable() {
|
|
@@ -35,7 +35,7 @@ var NativeDocument = (function (exports) {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
}
|
|
38
|
-
var DebugManager = DebugManager
|
|
38
|
+
var DebugManager$1 = DebugManager;
|
|
39
39
|
|
|
40
40
|
const MemoryManager = (function() {
|
|
41
41
|
|
|
@@ -84,7 +84,7 @@ var NativeDocument = (function (exports) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
if (cleanedCount > 0) {
|
|
87
|
-
DebugManager.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
|
|
87
|
+
DebugManager$1.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
};
|
|
@@ -113,6 +113,16 @@ var NativeDocument = (function (exports) {
|
|
|
113
113
|
|
|
114
114
|
ObservableChecker.prototype.__$isObservableChecker = true;
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Subscribes to changes in the checked/transformed value.
|
|
118
|
+
*
|
|
119
|
+
* @param {Function} callback - Function called with the transformed value when observable changes
|
|
120
|
+
* @returns {Function} Unsubscribe function
|
|
121
|
+
* @example
|
|
122
|
+
* const count = Observable(5);
|
|
123
|
+
* const doubled = count.check(n => n * 2);
|
|
124
|
+
* doubled.subscribe(value => console.log(value)); // Logs: 10
|
|
125
|
+
*/
|
|
116
126
|
ObservableChecker.prototype.subscribe = function(callback) {
|
|
117
127
|
const unSubscribe = this.observable.subscribe((value) => {
|
|
118
128
|
callback && callback(this.checker(value));
|
|
@@ -121,30 +131,70 @@ var NativeDocument = (function (exports) {
|
|
|
121
131
|
return unSubscribe;
|
|
122
132
|
};
|
|
123
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Creates a new ObservableChecker by applying another transformation.
|
|
136
|
+
* Allows chaining transformations.
|
|
137
|
+
*
|
|
138
|
+
* @param {(value: *) => *} callback - Transformation function to apply to the current checked value
|
|
139
|
+
* @returns {ObservableChecker} New ObservableChecker with chained transformation
|
|
140
|
+
* @example
|
|
141
|
+
* const count = Observable(5);
|
|
142
|
+
* const result = count.check(n => n * 2).check(n => n + 1);
|
|
143
|
+
* result.val(); // 11
|
|
144
|
+
*/
|
|
124
145
|
ObservableChecker.prototype.check = function(callback) {
|
|
125
146
|
return this.observable.check(() => callback(this.val()));
|
|
126
147
|
};
|
|
127
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Gets the current transformed/checked value.
|
|
151
|
+
*
|
|
152
|
+
* @returns {*} The result of applying the checker function to the observable's current value
|
|
153
|
+
* @example
|
|
154
|
+
* const count = Observable(5);
|
|
155
|
+
* const doubled = count.check(n => n * 2);
|
|
156
|
+
* doubled.val(); // 10
|
|
157
|
+
*/
|
|
128
158
|
ObservableChecker.prototype.val = function() {
|
|
129
159
|
return this.checker && this.checker(this.observable.val());
|
|
130
160
|
};
|
|
131
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Sets the value of the underlying observable (not the transformed value).
|
|
164
|
+
*
|
|
165
|
+
* @param {*} value - New value for the underlying observable
|
|
166
|
+
* @example
|
|
167
|
+
* const count = Observable(5);
|
|
168
|
+
* const doubled = count.check(n => n * 2);
|
|
169
|
+
* doubled.set(10); // Sets count to 10, doubled.val() returns 20
|
|
170
|
+
*/
|
|
132
171
|
ObservableChecker.prototype.set = function(value) {
|
|
133
172
|
return this.observable.set(value);
|
|
134
173
|
};
|
|
135
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Manually triggers the underlying observable to notify subscribers.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* const count = Observable(5);
|
|
180
|
+
* const doubled = count.check(n => n * 2);
|
|
181
|
+
* doubled.trigger(); // Notifies all subscribers
|
|
182
|
+
*/
|
|
136
183
|
ObservableChecker.prototype.trigger = function() {
|
|
137
184
|
return this.observable.trigger();
|
|
138
185
|
};
|
|
139
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Cleans up the underlying observable and all its subscriptions.
|
|
189
|
+
*/
|
|
140
190
|
ObservableChecker.prototype.cleanup = function() {
|
|
141
191
|
return this.observable.cleanup();
|
|
142
192
|
};
|
|
143
193
|
|
|
144
|
-
let PluginsManager
|
|
194
|
+
let PluginsManager = null;
|
|
145
195
|
|
|
146
196
|
{
|
|
147
|
-
PluginsManager
|
|
197
|
+
PluginsManager = (function() {
|
|
148
198
|
|
|
149
199
|
const $plugins = new Map();
|
|
150
200
|
const $pluginByEvents = new Map();
|
|
@@ -210,7 +260,7 @@ var NativeDocument = (function (exports) {
|
|
|
210
260
|
try{
|
|
211
261
|
callback.call(plugin, ...data);
|
|
212
262
|
} catch (error) {
|
|
213
|
-
DebugManager.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventName}`, error);
|
|
263
|
+
DebugManager$1.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventName}`, error);
|
|
214
264
|
}
|
|
215
265
|
}
|
|
216
266
|
}
|
|
@@ -219,8 +269,15 @@ var NativeDocument = (function (exports) {
|
|
|
219
269
|
}());
|
|
220
270
|
}
|
|
221
271
|
|
|
222
|
-
var PluginsManager = PluginsManager
|
|
272
|
+
var PluginsManager$1 = PluginsManager;
|
|
223
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Creates an ObservableWhen that tracks whether an observable equals a specific value.
|
|
276
|
+
*
|
|
277
|
+
* @param {ObservableItem} observer - The observable to watch
|
|
278
|
+
* @param {*} value - The value to compare against
|
|
279
|
+
* @class ObservableWhen
|
|
280
|
+
*/
|
|
224
281
|
const ObservableWhen = function(observer, value) {
|
|
225
282
|
this.$target = value;
|
|
226
283
|
this.$observer = observer;
|
|
@@ -228,21 +285,44 @@ var NativeDocument = (function (exports) {
|
|
|
228
285
|
|
|
229
286
|
ObservableWhen.prototype.__$isObservableWhen = true;
|
|
230
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Subscribes to changes in the match status (true when observable equals target value).
|
|
290
|
+
*
|
|
291
|
+
* @param {Function} callback - Function called with boolean indicating if values match
|
|
292
|
+
* @returns {Function} Unsubscribe function
|
|
293
|
+
* @example
|
|
294
|
+
* const status = Observable('idle');
|
|
295
|
+
* const isLoading = status.when('loading');
|
|
296
|
+
* isLoading.subscribe(active => console.log('Loading:', active));
|
|
297
|
+
*/
|
|
231
298
|
ObservableWhen.prototype.subscribe = function(callback) {
|
|
232
299
|
return this.$observer.on(this.$target, callback);
|
|
233
300
|
};
|
|
234
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Returns true if the observable's current value equals the target value.
|
|
304
|
+
*
|
|
305
|
+
* @returns {boolean} True if observable value matches target value
|
|
306
|
+
*/
|
|
235
307
|
ObservableWhen.prototype.val = function() {
|
|
236
308
|
return this.$observer.$currentValue === this.$target;
|
|
237
309
|
};
|
|
238
310
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Returns true if the observable's current value equals the target value.
|
|
313
|
+
* Alias for val().
|
|
314
|
+
*
|
|
315
|
+
* @returns {boolean} True if observable value matches target value
|
|
316
|
+
*/
|
|
317
|
+
ObservableWhen.prototype.isMatch = ObservableWhen.prototype.val;
|
|
242
318
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Returns true if the observable's current value equals the target value.
|
|
321
|
+
* Alias for val().
|
|
322
|
+
*
|
|
323
|
+
* @returns {boolean} True if observable value matches target value
|
|
324
|
+
*/
|
|
325
|
+
ObservableWhen.prototype.isActive = ObservableWhen.prototype.val;
|
|
246
326
|
|
|
247
327
|
const nextTick = function(fn) {
|
|
248
328
|
let pending = false;
|
|
@@ -343,7 +423,7 @@ var NativeDocument = (function (exports) {
|
|
|
343
423
|
}
|
|
344
424
|
}
|
|
345
425
|
{
|
|
346
|
-
PluginsManager.emit('CreateObservable', this);
|
|
426
|
+
PluginsManager$1.emit('CreateObservable', this);
|
|
347
427
|
}
|
|
348
428
|
}
|
|
349
429
|
|
|
@@ -360,6 +440,16 @@ var NativeDocument = (function (exports) {
|
|
|
360
440
|
ObservableItem.prototype.__$isObservable = true;
|
|
361
441
|
const noneTrigger = function() {};
|
|
362
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Intercepts and transforms values before they are set on the observable.
|
|
445
|
+
* The interceptor can modify the value or return undefined to use the original value.
|
|
446
|
+
*
|
|
447
|
+
* @param {(value) => any} callback - Interceptor function that receives (newValue, currentValue) and returns the transformed value or undefined
|
|
448
|
+
* @returns {ObservableItem} The observable instance for chaining
|
|
449
|
+
* @example
|
|
450
|
+
* const count = Observable(0);
|
|
451
|
+
* count.intercept((newVal, oldVal) => Math.max(0, newVal)); // Prevent negative values
|
|
452
|
+
*/
|
|
363
453
|
ObservableItem.prototype.intercept = function(callback) {
|
|
364
454
|
this.$interceptor = callback;
|
|
365
455
|
this.set = this.$setWithInterceptor;
|
|
@@ -437,12 +527,12 @@ var NativeDocument = (function (exports) {
|
|
|
437
527
|
this.$previousValue = this.$currentValue;
|
|
438
528
|
this.$currentValue = newValue;
|
|
439
529
|
{
|
|
440
|
-
PluginsManager.emit('ObservableBeforeChange', this);
|
|
530
|
+
PluginsManager$1.emit('ObservableBeforeChange', this);
|
|
441
531
|
}
|
|
442
532
|
this.trigger();
|
|
443
533
|
this.$previousValue = null;
|
|
444
534
|
{
|
|
445
|
-
PluginsManager.emit('ObservableAfterChange', this);
|
|
535
|
+
PluginsManager$1.emit('ObservableAfterChange', this);
|
|
446
536
|
}
|
|
447
537
|
};
|
|
448
538
|
|
|
@@ -491,6 +581,16 @@ var NativeDocument = (function (exports) {
|
|
|
491
581
|
this.trigger = noneTrigger;
|
|
492
582
|
};
|
|
493
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Registers a cleanup callback that will be executed when the observable is cleaned up.
|
|
586
|
+
* Useful for disposing resources, removing event listeners, or other cleanup tasks.
|
|
587
|
+
*
|
|
588
|
+
* @param {Function} callback - Cleanup function to execute on observable disposal
|
|
589
|
+
* @example
|
|
590
|
+
* const obs = Observable(0);
|
|
591
|
+
* obs.onCleanup(() => console.log('Cleaned up!'));
|
|
592
|
+
* obs.cleanup(); // Logs: "Cleaned up!"
|
|
593
|
+
*/
|
|
494
594
|
ObservableItem.prototype.onCleanup = function(callback) {
|
|
495
595
|
this.$cleanupListeners = this.$cleanupListeners ?? [];
|
|
496
596
|
this.$cleanupListeners.push(callback);
|
|
@@ -519,7 +619,7 @@ var NativeDocument = (function (exports) {
|
|
|
519
619
|
ObservableItem.prototype.subscribe = function(callback) {
|
|
520
620
|
{
|
|
521
621
|
if (this.$isCleanedUp) {
|
|
522
|
-
DebugManager.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
|
|
622
|
+
DebugManager$1.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
|
|
523
623
|
return;
|
|
524
624
|
}
|
|
525
625
|
if (typeof callback !== 'function') {
|
|
@@ -531,10 +631,21 @@ var NativeDocument = (function (exports) {
|
|
|
531
631
|
this.$listeners.push(callback);
|
|
532
632
|
this.assocTrigger();
|
|
533
633
|
{
|
|
534
|
-
PluginsManager.emit('ObservableSubscribe', this);
|
|
634
|
+
PluginsManager$1.emit('ObservableSubscribe', this);
|
|
535
635
|
}
|
|
536
636
|
};
|
|
537
637
|
|
|
638
|
+
/**
|
|
639
|
+
* Watches for a specific value and executes callback when the observable equals that value.
|
|
640
|
+
* Creates a watcher that only triggers when the observable changes to the specified value.
|
|
641
|
+
*
|
|
642
|
+
* @param {*} value - The value to watch for
|
|
643
|
+
* @param {(value) => void|ObservableItem} callback - Callback function or observable to set when value matches
|
|
644
|
+
* @example
|
|
645
|
+
* const status = Observable('idle');
|
|
646
|
+
* status.on('loading', () => console.log('Started loading'));
|
|
647
|
+
* status.on('error', isError); // Set another observable
|
|
648
|
+
*/
|
|
538
649
|
ObservableItem.prototype.on = function(value, callback) {
|
|
539
650
|
this.$watchers = this.$watchers ?? new Map();
|
|
540
651
|
|
|
@@ -564,8 +675,16 @@ var NativeDocument = (function (exports) {
|
|
|
564
675
|
};
|
|
565
676
|
|
|
566
677
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
678
|
+
* Removes a watcher for a specific value. If no callback is provided, removes all watchers for that value.
|
|
679
|
+
*
|
|
680
|
+
* @param {*} value - The value to stop watching
|
|
681
|
+
* @param {Function} [callback] - Specific callback to remove. If omitted, removes all watchers for this value
|
|
682
|
+
* @example
|
|
683
|
+
* const status = Observable('idle');
|
|
684
|
+
* const handler = () => console.log('Loading');
|
|
685
|
+
* status.on('loading', handler);
|
|
686
|
+
* status.off('loading', handler); // Remove specific handler
|
|
687
|
+
* status.off('loading'); // Remove all handlers for 'loading'
|
|
569
688
|
*/
|
|
570
689
|
ObservableItem.prototype.off = function(value, callback) {
|
|
571
690
|
if(!this.$watchers) return;
|
|
@@ -585,11 +704,20 @@ var NativeDocument = (function (exports) {
|
|
|
585
704
|
}
|
|
586
705
|
else if(watchValueList.length === 0) {
|
|
587
706
|
this.$watchers?.delete(value);
|
|
588
|
-
watchValueList = null;
|
|
589
707
|
}
|
|
590
708
|
this.assocTrigger();
|
|
591
709
|
};
|
|
592
710
|
|
|
711
|
+
/**
|
|
712
|
+
* Subscribes to the observable but automatically unsubscribes after the first time the predicate matches.
|
|
713
|
+
*
|
|
714
|
+
* @param {(value) => Boolean|any} predicate - Value to match or function that returns true when condition is met
|
|
715
|
+
* @param {(value) => void} callback - Callback to execute when predicate matches, receives the matched value
|
|
716
|
+
* @example
|
|
717
|
+
* const status = Observable('loading');
|
|
718
|
+
* status.once('ready', (val) => console.log('Ready!'));
|
|
719
|
+
* status.once(val => val === 'error', (val) => console.log('Error occurred'));
|
|
720
|
+
*/
|
|
593
721
|
ObservableItem.prototype.once = function(predicate, callback) {
|
|
594
722
|
const fn = typeof predicate === 'function' ? predicate : (v) => v === predicate;
|
|
595
723
|
|
|
@@ -614,7 +742,7 @@ var NativeDocument = (function (exports) {
|
|
|
614
742
|
}
|
|
615
743
|
this.assocTrigger();
|
|
616
744
|
{
|
|
617
|
-
PluginsManager.emit('ObservableUnsubscribe', this);
|
|
745
|
+
PluginsManager$1.emit('ObservableUnsubscribe', this);
|
|
618
746
|
}
|
|
619
747
|
};
|
|
620
748
|
|
|
@@ -627,15 +755,50 @@ var NativeDocument = (function (exports) {
|
|
|
627
755
|
return new ObservableChecker(this, callback)
|
|
628
756
|
};
|
|
629
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Gets a property value from the observable's current value.
|
|
760
|
+
* If the property is an observable, returns its value.
|
|
761
|
+
*
|
|
762
|
+
* @param {string|number} key - Property key to retrieve
|
|
763
|
+
* @returns {*} The value of the property, unwrapped if it's an observable
|
|
764
|
+
* @example
|
|
765
|
+
* const user = Observable({ name: 'John', age: Observable(25) });
|
|
766
|
+
* user.get('name'); // 'John'
|
|
767
|
+
* user.get('age'); // 25 (unwrapped from observable)
|
|
768
|
+
*/
|
|
630
769
|
ObservableItem.prototype.get = function(key) {
|
|
631
770
|
const item = this.$currentValue[key];
|
|
632
771
|
return Validator.isObservable(item) ? item.val() : item;
|
|
633
772
|
};
|
|
634
773
|
|
|
774
|
+
/**
|
|
775
|
+
* Creates an ObservableWhen that represents whether the observable equals a specific value.
|
|
776
|
+
* Returns an object that can be subscribed to and will emit true/false.
|
|
777
|
+
*
|
|
778
|
+
* @param {*} value - The value to compare against
|
|
779
|
+
* @returns {ObservableWhen} An ObservableWhen instance that tracks when the observable equals the value
|
|
780
|
+
* @example
|
|
781
|
+
* const status = Observable('idle');
|
|
782
|
+
* const isLoading = status.when('loading');
|
|
783
|
+
* isLoading.subscribe(active => console.log('Loading:', active));
|
|
784
|
+
* status.set('loading'); // Logs: "Loading: true"
|
|
785
|
+
*/
|
|
635
786
|
ObservableItem.prototype.when = function(value) {
|
|
636
787
|
return new ObservableWhen(this, value);
|
|
637
788
|
};
|
|
638
789
|
|
|
790
|
+
/**
|
|
791
|
+
* Compares the observable's current value with another value or observable.
|
|
792
|
+
*
|
|
793
|
+
* @param {*|ObservableItem} other - Value or observable to compare against
|
|
794
|
+
* @returns {boolean} True if values are equal
|
|
795
|
+
* @example
|
|
796
|
+
* const a = Observable(5);
|
|
797
|
+
* const b = Observable(5);
|
|
798
|
+
* a.equals(5); // true
|
|
799
|
+
* a.equals(b); // true
|
|
800
|
+
* a.equals(10); // false
|
|
801
|
+
*/
|
|
639
802
|
ObservableItem.prototype.equals = function(other) {
|
|
640
803
|
if(Validator.isObservable(other)) {
|
|
641
804
|
return this.$currentValue === other.$currentValue;
|
|
@@ -643,14 +806,41 @@ var NativeDocument = (function (exports) {
|
|
|
643
806
|
return this.$currentValue === other;
|
|
644
807
|
};
|
|
645
808
|
|
|
809
|
+
/**
|
|
810
|
+
* Converts the observable's current value to a boolean.
|
|
811
|
+
*
|
|
812
|
+
* @returns {boolean} The boolean representation of the current value
|
|
813
|
+
* @example
|
|
814
|
+
* const count = Observable(0);
|
|
815
|
+
* count.toBool(); // false
|
|
816
|
+
* count.set(5);
|
|
817
|
+
* count.toBool(); // true
|
|
818
|
+
*/
|
|
646
819
|
ObservableItem.prototype.toBool = function() {
|
|
647
820
|
return !!this.$currentValue;
|
|
648
821
|
};
|
|
649
822
|
|
|
823
|
+
/**
|
|
824
|
+
* Toggles the boolean value of the observable (false becomes true, true becomes false).
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* const isOpen = Observable(false);
|
|
828
|
+
* isOpen.toggle(); // Now true
|
|
829
|
+
* isOpen.toggle(); // Now false
|
|
830
|
+
*/
|
|
650
831
|
ObservableItem.prototype.toggle = function() {
|
|
651
832
|
this.set(!this.$currentValue);
|
|
652
833
|
};
|
|
653
834
|
|
|
835
|
+
/**
|
|
836
|
+
* Resets the observable to its initial value.
|
|
837
|
+
* Only works if the observable was created with { reset: true } config.
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* const count = Observable(0, { reset: true });
|
|
841
|
+
* count.set(10);
|
|
842
|
+
* count.reset(); // Back to 0
|
|
843
|
+
*/
|
|
654
844
|
ObservableItem.prototype.reset = function() {
|
|
655
845
|
if(!this.configs?.reset) {
|
|
656
846
|
return;
|
|
@@ -663,11 +853,21 @@ var NativeDocument = (function (exports) {
|
|
|
663
853
|
this.set(resetValue);
|
|
664
854
|
};
|
|
665
855
|
|
|
666
|
-
|
|
856
|
+
/**
|
|
857
|
+
* Returns a string representation of the observable's current value.
|
|
858
|
+
*
|
|
859
|
+
* @returns {string} String representation of the current value
|
|
860
|
+
*/
|
|
667
861
|
ObservableItem.prototype.toString = function() {
|
|
668
862
|
return String(this.$currentValue);
|
|
669
863
|
};
|
|
670
864
|
|
|
865
|
+
/**
|
|
866
|
+
* Returns the primitive value of the observable (its current value).
|
|
867
|
+
* Called automatically in type coercion contexts.
|
|
868
|
+
*
|
|
869
|
+
* @returns {*} The current value of the observable
|
|
870
|
+
*/
|
|
671
871
|
ObservableItem.prototype.valueOf = function() {
|
|
672
872
|
return this.$currentValue;
|
|
673
873
|
};
|
|
@@ -779,7 +979,7 @@ var NativeDocument = (function (exports) {
|
|
|
779
979
|
this.$element = element;
|
|
780
980
|
this.$observer = null;
|
|
781
981
|
{
|
|
782
|
-
PluginsManager.emit('NDElementCreated', element, this);
|
|
982
|
+
PluginsManager$1.emit('NDElementCreated', element, this);
|
|
783
983
|
}
|
|
784
984
|
}
|
|
785
985
|
|
|
@@ -875,12 +1075,35 @@ var NativeDocument = (function (exports) {
|
|
|
875
1075
|
return this.shadow('closed', style);
|
|
876
1076
|
};
|
|
877
1077
|
|
|
1078
|
+
/**
|
|
1079
|
+
* Attaches a template binding to the element by hydrating it with the specified method.
|
|
1080
|
+
*
|
|
1081
|
+
* @param {string} methodName - Name of the hydration method to call
|
|
1082
|
+
* @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
|
|
1083
|
+
* @returns {HTMLElement} The underlying HTML element
|
|
1084
|
+
* @example
|
|
1085
|
+
* const onClick = $binder.attach((event, data) => console.log(data));
|
|
1086
|
+
* element.nd.attach('onClick', onClick);
|
|
1087
|
+
*/
|
|
878
1088
|
NDElement.prototype.attach = function(methodName, bindingHydrator) {
|
|
879
1089
|
bindingHydrator.$hydrate(this.$element, methodName);
|
|
880
1090
|
return this.$element;
|
|
881
1091
|
};
|
|
882
1092
|
|
|
883
|
-
|
|
1093
|
+
/**
|
|
1094
|
+
* Extends the current NDElement instance with custom methods.
|
|
1095
|
+
* Methods are bound to the instance and available for chaining.
|
|
1096
|
+
*
|
|
1097
|
+
* @param {Object} methods - Object containing method definitions
|
|
1098
|
+
* @returns {this} The NDElement instance with added methods for chaining
|
|
1099
|
+
* @example
|
|
1100
|
+
* element.nd.with({
|
|
1101
|
+
* highlight() {
|
|
1102
|
+
* this.$element.style.background = 'yellow';
|
|
1103
|
+
* return this;
|
|
1104
|
+
* }
|
|
1105
|
+
* }).highlight().onClick(() => console.log('Clicked'));
|
|
1106
|
+
*/
|
|
884
1107
|
NDElement.prototype.with = function(methods) {
|
|
885
1108
|
if (!methods || typeof methods !== 'object') {
|
|
886
1109
|
throw new NativeDocumentError('extend() requires an object of methods');
|
|
@@ -900,7 +1123,7 @@ var NativeDocument = (function (exports) {
|
|
|
900
1123
|
}
|
|
901
1124
|
{
|
|
902
1125
|
if (this[name] && !this.$localExtensions.has(name)) {
|
|
903
|
-
DebugManager.warn('NDElement.extend', `Method "${name}" already exists and will be overwritten`);
|
|
1126
|
+
DebugManager$1.warn('NDElement.extend', `Method "${name}" already exists and will be overwritten`);
|
|
904
1127
|
}
|
|
905
1128
|
this.$localExtensions.set(name, method);
|
|
906
1129
|
}
|
|
@@ -911,6 +1134,23 @@ var NativeDocument = (function (exports) {
|
|
|
911
1134
|
return this;
|
|
912
1135
|
};
|
|
913
1136
|
|
|
1137
|
+
/**
|
|
1138
|
+
* Extends the NDElement prototype with new methods available to all NDElement instances.
|
|
1139
|
+
* Use this to add global methods to all NDElements.
|
|
1140
|
+
*
|
|
1141
|
+
* @param {Object} methods - Object containing method definitions to add to prototype
|
|
1142
|
+
* @returns {typeof NDElement} The NDElement constructor
|
|
1143
|
+
* @throws {NativeDocumentError} If methods is not an object or contains non-function values
|
|
1144
|
+
* @example
|
|
1145
|
+
* NDElement.extend({
|
|
1146
|
+
* fadeIn() {
|
|
1147
|
+
* this.$element.style.opacity = '1';
|
|
1148
|
+
* return this;
|
|
1149
|
+
* }
|
|
1150
|
+
* });
|
|
1151
|
+
* // Now all NDElements have .fadeIn() method
|
|
1152
|
+
* Div().nd.fadeIn();
|
|
1153
|
+
*/
|
|
914
1154
|
NDElement.extend = function(methods) {
|
|
915
1155
|
if (!methods || typeof methods !== 'object') {
|
|
916
1156
|
throw new NativeDocumentError('NDElement.extend() requires an object of methods');
|
|
@@ -934,23 +1174,23 @@ var NativeDocument = (function (exports) {
|
|
|
934
1174
|
const method = methods[name];
|
|
935
1175
|
|
|
936
1176
|
if (typeof method !== 'function') {
|
|
937
|
-
DebugManager.warn('NDElement.extend', `"${name}" is not a function, skipping`);
|
|
1177
|
+
DebugManager$1.warn('NDElement.extend', `"${name}" is not a function, skipping`);
|
|
938
1178
|
continue;
|
|
939
1179
|
}
|
|
940
1180
|
|
|
941
1181
|
if (protectedMethods.has(name)) {
|
|
942
|
-
DebugManager.error('NDElement.extend', `Cannot override protected method "${name}"`);
|
|
1182
|
+
DebugManager$1.error('NDElement.extend', `Cannot override protected method "${name}"`);
|
|
943
1183
|
throw new NativeDocumentError(`Cannot override protected method "${name}"`);
|
|
944
1184
|
}
|
|
945
1185
|
|
|
946
1186
|
if (NDElement.prototype[name]) {
|
|
947
|
-
DebugManager.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
|
|
1187
|
+
DebugManager$1.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
|
|
948
1188
|
}
|
|
949
1189
|
|
|
950
1190
|
NDElement.prototype[name] = method;
|
|
951
1191
|
}
|
|
952
1192
|
{
|
|
953
|
-
PluginsManager.emit('NDElementExtended', methods);
|
|
1193
|
+
PluginsManager$1.emit('NDElementExtended', methods);
|
|
954
1194
|
}
|
|
955
1195
|
|
|
956
1196
|
return NDElement;
|
|
@@ -1103,7 +1343,7 @@ var NativeDocument = (function (exports) {
|
|
|
1103
1343
|
const foundReserved = Object.keys(attributes).filter(key => reserved.includes(key));
|
|
1104
1344
|
|
|
1105
1345
|
if (foundReserved.length > 0) {
|
|
1106
|
-
DebugManager.warn('Validator', `Reserved attributes found: ${foundReserved.join(', ')}`);
|
|
1346
|
+
DebugManager$1.warn('Validator', `Reserved attributes found: ${foundReserved.join(', ')}`);
|
|
1107
1347
|
}
|
|
1108
1348
|
|
|
1109
1349
|
return attributes;
|
|
@@ -1151,7 +1391,7 @@ var NativeDocument = (function (exports) {
|
|
|
1151
1391
|
anchorFragment.appendChild = function(child, before = null) {
|
|
1152
1392
|
const parent = anchorEnd.parentNode;
|
|
1153
1393
|
if(!parent) {
|
|
1154
|
-
DebugManager.error('Anchor', 'Anchor : parent not found', child);
|
|
1394
|
+
DebugManager$1.error('Anchor', 'Anchor : parent not found', child);
|
|
1155
1395
|
return;
|
|
1156
1396
|
}
|
|
1157
1397
|
before = before ?? anchorEnd;
|
|
@@ -1379,7 +1619,7 @@ var NativeDocument = (function (exports) {
|
|
|
1379
1619
|
continue;
|
|
1380
1620
|
}
|
|
1381
1621
|
if(value.__$isObservableWhen) {
|
|
1382
|
-
element.classes.toggle(className, value.
|
|
1622
|
+
element.classes.toggle(className, value.isActive());
|
|
1383
1623
|
value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
1384
1624
|
continue;
|
|
1385
1625
|
}
|
|
@@ -1525,6 +1765,8 @@ var NativeDocument = (function (exports) {
|
|
|
1525
1765
|
return ElementCreator.createObservableNode(null, this);
|
|
1526
1766
|
};
|
|
1527
1767
|
|
|
1768
|
+
ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
|
|
1769
|
+
|
|
1528
1770
|
NDElement.prototype.toNdElement = function () {
|
|
1529
1771
|
return this.$element ?? this.$build?.() ?? this.build?.() ?? null;
|
|
1530
1772
|
};
|
|
@@ -1542,7 +1784,7 @@ var NativeDocument = (function (exports) {
|
|
|
1542
1784
|
Function.prototype.toNdElement = function () {
|
|
1543
1785
|
const child = this;
|
|
1544
1786
|
{
|
|
1545
|
-
PluginsManager.emit('BeforeProcessComponent', child);
|
|
1787
|
+
PluginsManager$1.emit('BeforeProcessComponent', child);
|
|
1546
1788
|
}
|
|
1547
1789
|
return ElementCreator.getChild(child());
|
|
1548
1790
|
};
|
|
@@ -1648,14 +1890,14 @@ var NativeDocument = (function (exports) {
|
|
|
1648
1890
|
processChildren(children, parent) {
|
|
1649
1891
|
if(children === null) return;
|
|
1650
1892
|
{
|
|
1651
|
-
PluginsManager.emit('BeforeProcessChildren', parent);
|
|
1893
|
+
PluginsManager$1.emit('BeforeProcessChildren', parent);
|
|
1652
1894
|
}
|
|
1653
1895
|
let child = this.getChild(children);
|
|
1654
1896
|
if(child) {
|
|
1655
1897
|
parent.appendChild(child);
|
|
1656
1898
|
}
|
|
1657
1899
|
{
|
|
1658
|
-
PluginsManager.emit('AfterProcessChildren', parent);
|
|
1900
|
+
PluginsManager$1.emit('AfterProcessChildren', parent);
|
|
1659
1901
|
}
|
|
1660
1902
|
},
|
|
1661
1903
|
getChild(child) {
|
|
@@ -1871,6 +2113,10 @@ var NativeDocument = (function (exports) {
|
|
|
1871
2113
|
_stop(this.$element, eventName, callback);
|
|
1872
2114
|
return this;
|
|
1873
2115
|
};
|
|
2116
|
+
NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
|
|
2117
|
+
_preventStop(this.$element, eventName, callback);
|
|
2118
|
+
return this;
|
|
2119
|
+
};
|
|
1874
2120
|
});
|
|
1875
2121
|
|
|
1876
2122
|
EVENTS_WITH_PREVENT.forEach(eventSourceName => {
|
|
@@ -1904,6 +2150,16 @@ var NativeDocument = (function (exports) {
|
|
|
1904
2150
|
return this;
|
|
1905
2151
|
};
|
|
1906
2152
|
|
|
2153
|
+
const _preventStop = function(element, eventName, callback) {
|
|
2154
|
+
const handler = (event) => {
|
|
2155
|
+
event.stopPropagation();
|
|
2156
|
+
event.preventDefault();
|
|
2157
|
+
callback && callback.call(element, event);
|
|
2158
|
+
};
|
|
2159
|
+
element.addEventListener(eventName, handler);
|
|
2160
|
+
return this;
|
|
2161
|
+
};
|
|
2162
|
+
|
|
1907
2163
|
|
|
1908
2164
|
|
|
1909
2165
|
// ----------------------------------------------------------------
|
|
@@ -2176,7 +2432,12 @@ var NativeDocument = (function (exports) {
|
|
|
2176
2432
|
|
|
2177
2433
|
const applyBindingTreePath = (root, target, data, path) => {
|
|
2178
2434
|
if(path.fn) {
|
|
2179
|
-
path.fn
|
|
2435
|
+
if(typeof path.fn === 'string') {
|
|
2436
|
+
ElementCreator.bindTextNode(target, data[0][path.fn]);
|
|
2437
|
+
}
|
|
2438
|
+
else {
|
|
2439
|
+
path.fn(data, target, root);
|
|
2440
|
+
}
|
|
2180
2441
|
}
|
|
2181
2442
|
if(path.children) {
|
|
2182
2443
|
for(let i = 0, length = path.children.length; i < length; i++) {
|
|
@@ -2202,15 +2463,16 @@ var NativeDocument = (function (exports) {
|
|
|
2202
2463
|
if(bindDingData && bindDingData.value) {
|
|
2203
2464
|
currentPath.fn = bindDingData.value;
|
|
2204
2465
|
const textNode = node.cloneNode();
|
|
2466
|
+
if(typeof bindDingData.value === 'string') {
|
|
2467
|
+
ElementCreator.bindTextNode(textNode, data[0][bindDingData.value]);
|
|
2468
|
+
return textNode;
|
|
2469
|
+
}
|
|
2205
2470
|
bindDingData.value(data, textNode);
|
|
2206
2471
|
return textNode;
|
|
2207
2472
|
}
|
|
2208
2473
|
return node.cloneNode(true);
|
|
2209
2474
|
}
|
|
2210
|
-
const nodeCloned = node.cloneNode(
|
|
2211
|
-
if(node.fullCloneNode) {
|
|
2212
|
-
return nodeCloned;
|
|
2213
|
-
}
|
|
2475
|
+
const nodeCloned = node.cloneNode();
|
|
2214
2476
|
if(bindDingData) {
|
|
2215
2477
|
bindAttributes(nodeCloned, bindDingData, data);
|
|
2216
2478
|
bindAttachMethods(nodeCloned, bindDingData, data);
|
|
@@ -2275,12 +2537,9 @@ var NativeDocument = (function (exports) {
|
|
|
2275
2537
|
};
|
|
2276
2538
|
this.value = (callbackOrProperty) => {
|
|
2277
2539
|
if(typeof callbackOrProperty !== 'function') {
|
|
2278
|
-
return createBinding(
|
|
2279
|
-
const firstArgument = data[0];
|
|
2280
|
-
ElementCreator.bindTextNode(textNode, firstArgument[callbackOrProperty]);
|
|
2281
|
-
}, 'value');
|
|
2540
|
+
return createBinding(callbackOrProperty, 'value');
|
|
2282
2541
|
}
|
|
2283
|
-
return createBinding(
|
|
2542
|
+
return createBinding((data, textNode) => {
|
|
2284
2543
|
ElementCreator.bindTextNode(textNode, callbackOrProperty(...data));
|
|
2285
2544
|
}, 'value');
|
|
2286
2545
|
};
|
|
@@ -2382,13 +2641,14 @@ var NativeDocument = (function (exports) {
|
|
|
2382
2641
|
};
|
|
2383
2642
|
|
|
2384
2643
|
Function.prototype.errorBoundary = function(callback) {
|
|
2385
|
-
|
|
2644
|
+
const handler = (...args) => {
|
|
2386
2645
|
try {
|
|
2387
2646
|
return this.apply(this, args);
|
|
2388
2647
|
} catch(e) {
|
|
2389
|
-
return callback(e);
|
|
2648
|
+
return callback(e, {caller: handler, args: args });
|
|
2390
2649
|
}
|
|
2391
2650
|
};
|
|
2651
|
+
return handler;
|
|
2392
2652
|
};
|
|
2393
2653
|
|
|
2394
2654
|
String.prototype.use = function(args) {
|
|
@@ -2460,12 +2720,13 @@ var NativeDocument = (function (exports) {
|
|
|
2460
2720
|
};
|
|
2461
2721
|
};
|
|
2462
2722
|
|
|
2463
|
-
const once = (fn) => {
|
|
2723
|
+
const once$1 = (fn) => {
|
|
2464
2724
|
let result = null;
|
|
2465
2725
|
return (...args) => {
|
|
2466
|
-
if(result
|
|
2467
|
-
result
|
|
2726
|
+
if(result) {
|
|
2727
|
+
return result;
|
|
2468
2728
|
}
|
|
2729
|
+
result = fn(...args);
|
|
2469
2730
|
return result;
|
|
2470
2731
|
};
|
|
2471
2732
|
};
|
|
@@ -2474,22 +2735,26 @@ var NativeDocument = (function (exports) {
|
|
|
2474
2735
|
let target = null;
|
|
2475
2736
|
return new Proxy({}, {
|
|
2476
2737
|
get: (_, key) => {
|
|
2477
|
-
if(target
|
|
2478
|
-
target
|
|
2738
|
+
if(target) {
|
|
2739
|
+
return target[key];
|
|
2479
2740
|
}
|
|
2741
|
+
target = fn();
|
|
2480
2742
|
return target[key];
|
|
2481
2743
|
}
|
|
2482
2744
|
});
|
|
2483
2745
|
};
|
|
2484
2746
|
|
|
2485
|
-
const memoize = (fn) => {
|
|
2747
|
+
const memoize$1 = (fn) => {
|
|
2486
2748
|
const cache = new Map();
|
|
2487
2749
|
return (...args) => {
|
|
2488
2750
|
const [key, ...rest] = args;
|
|
2489
|
-
|
|
2490
|
-
|
|
2751
|
+
const cached = cache.get(key);
|
|
2752
|
+
if(cached) {
|
|
2753
|
+
return cached;
|
|
2491
2754
|
}
|
|
2492
|
-
|
|
2755
|
+
const result = fn(...rest);
|
|
2756
|
+
cache.set(key, result);
|
|
2757
|
+
return result;
|
|
2493
2758
|
};
|
|
2494
2759
|
};
|
|
2495
2760
|
|
|
@@ -2497,17 +2762,21 @@ var NativeDocument = (function (exports) {
|
|
|
2497
2762
|
const cache = new Map();
|
|
2498
2763
|
return new Proxy({}, {
|
|
2499
2764
|
get: (_, key) => {
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2765
|
+
const cached = cache.get(key);
|
|
2766
|
+
if(cached) {
|
|
2767
|
+
return cached;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
if(fn.length > 0) {
|
|
2771
|
+
return (...args) => {
|
|
2772
|
+
const result = fn(...args, key);
|
|
2773
|
+
cache.set(key, result);
|
|
2774
|
+
return result;
|
|
2507
2775
|
}
|
|
2508
|
-
cache.set(key, fn());
|
|
2509
2776
|
}
|
|
2510
|
-
|
|
2777
|
+
const result = fn(key);
|
|
2778
|
+
cache.set(key, result);
|
|
2779
|
+
return result;
|
|
2511
2780
|
}
|
|
2512
2781
|
});
|
|
2513
2782
|
};
|
|
@@ -2880,7 +3149,7 @@ var NativeDocument = (function (exports) {
|
|
|
2880
3149
|
|
|
2881
3150
|
ObservableItem.call(this, target, configs);
|
|
2882
3151
|
{
|
|
2883
|
-
PluginsManager.emit('CreateObservableArray', this);
|
|
3152
|
+
PluginsManager$1.emit('CreateObservableArray', this);
|
|
2884
3153
|
}
|
|
2885
3154
|
};
|
|
2886
3155
|
|
|
@@ -2909,6 +3178,14 @@ var NativeDocument = (function (exports) {
|
|
|
2909
3178
|
};
|
|
2910
3179
|
});
|
|
2911
3180
|
|
|
3181
|
+
/**
|
|
3182
|
+
* Removes all items from the array and triggers an update.
|
|
3183
|
+
*
|
|
3184
|
+
* @returns {boolean} True if array was cleared, false if it was already empty
|
|
3185
|
+
* @example
|
|
3186
|
+
* const items = Observable.array([1, 2, 3]);
|
|
3187
|
+
* items.clear(); // []
|
|
3188
|
+
*/
|
|
2912
3189
|
ObservableArray.prototype.clear = function() {
|
|
2913
3190
|
if(this.$currentValue.length === 0) {
|
|
2914
3191
|
return;
|
|
@@ -2918,19 +3195,42 @@ var NativeDocument = (function (exports) {
|
|
|
2918
3195
|
return true;
|
|
2919
3196
|
};
|
|
2920
3197
|
|
|
3198
|
+
/**
|
|
3199
|
+
* Returns the element at the specified index in the array.
|
|
3200
|
+
*
|
|
3201
|
+
* @param {number} index - Zero-based index of the element to retrieve
|
|
3202
|
+
* @returns {*} The element at the specified index
|
|
3203
|
+
* @example
|
|
3204
|
+
* const items = Observable.array(['a', 'b', 'c']);
|
|
3205
|
+
* items.at(1); // 'b'
|
|
3206
|
+
*/
|
|
2921
3207
|
ObservableArray.prototype.at = function(index) {
|
|
2922
3208
|
return this.$currentValue[index];
|
|
2923
3209
|
};
|
|
2924
3210
|
|
|
3211
|
+
|
|
3212
|
+
/**
|
|
3213
|
+
* Merges multiple values into the array and triggers an update.
|
|
3214
|
+
* Similar to push but with a different operation name.
|
|
3215
|
+
*
|
|
3216
|
+
* @param {Array} values - Array of values to merge
|
|
3217
|
+
* @example
|
|
3218
|
+
* const items = Observable.array([1, 2]);
|
|
3219
|
+
* items.merge([3, 4]); // [1, 2, 3, 4]
|
|
3220
|
+
*/
|
|
2925
3221
|
ObservableArray.prototype.merge = function(values) {
|
|
2926
3222
|
this.$currentValue.push.apply(this.$currentValue, values);
|
|
2927
3223
|
this.trigger({ action: 'merge', args: values });
|
|
2928
3224
|
};
|
|
2929
3225
|
|
|
2930
3226
|
/**
|
|
3227
|
+
* Counts the number of elements that satisfy the provided condition.
|
|
2931
3228
|
*
|
|
2932
|
-
* @param {
|
|
2933
|
-
* @returns {number}
|
|
3229
|
+
* @param {(value: *, index: number) => Boolean} condition - Function that tests each element (item, index) => boolean
|
|
3230
|
+
* @returns {number} The count of elements that satisfy the condition
|
|
3231
|
+
* @example
|
|
3232
|
+
* const numbers = Observable.array([1, 2, 3, 4, 5]);
|
|
3233
|
+
* numbers.count(n => n > 3); // 2
|
|
2934
3234
|
*/
|
|
2935
3235
|
ObservableArray.prototype.count = function(condition) {
|
|
2936
3236
|
let count = 0;
|
|
@@ -2942,6 +3242,16 @@ var NativeDocument = (function (exports) {
|
|
|
2942
3242
|
return count;
|
|
2943
3243
|
};
|
|
2944
3244
|
|
|
3245
|
+
/**
|
|
3246
|
+
* Swaps two elements at the specified indices and triggers an update.
|
|
3247
|
+
*
|
|
3248
|
+
* @param {number} indexA - Index of the first element
|
|
3249
|
+
* @param {number} indexB - Index of the second element
|
|
3250
|
+
* @returns {boolean} True if swap was successful, false if indices are out of bounds
|
|
3251
|
+
* @example
|
|
3252
|
+
* const items = Observable.array(['a', 'b', 'c']);
|
|
3253
|
+
* items.swap(0, 2); // ['c', 'b', 'a']
|
|
3254
|
+
*/
|
|
2945
3255
|
ObservableArray.prototype.swap = function(indexA, indexB) {
|
|
2946
3256
|
const value = this.$currentValue;
|
|
2947
3257
|
const length = value.length;
|
|
@@ -2962,6 +3272,15 @@ var NativeDocument = (function (exports) {
|
|
|
2962
3272
|
return true;
|
|
2963
3273
|
};
|
|
2964
3274
|
|
|
3275
|
+
/**
|
|
3276
|
+
* Removes the element at the specified index and triggers an update.
|
|
3277
|
+
*
|
|
3278
|
+
* @param {number} index - Index of the element to remove
|
|
3279
|
+
* @returns {Array} Array containing the removed element, or empty array if index is invalid
|
|
3280
|
+
* @example
|
|
3281
|
+
* const items = Observable.array(['a', 'b', 'c']);
|
|
3282
|
+
* items.remove(1); // ['b'] - Array is now ['a', 'c']
|
|
3283
|
+
*/
|
|
2965
3284
|
ObservableArray.prototype.remove = function(index) {
|
|
2966
3285
|
const deleted = this.$currentValue.splice(index, 1);
|
|
2967
3286
|
if(deleted.length === 0) {
|
|
@@ -2971,20 +3290,60 @@ var NativeDocument = (function (exports) {
|
|
|
2971
3290
|
return deleted;
|
|
2972
3291
|
};
|
|
2973
3292
|
|
|
3293
|
+
/**
|
|
3294
|
+
* Removes the first occurrence of the specified item from the array.
|
|
3295
|
+
*
|
|
3296
|
+
* @param {*} item - The item to remove
|
|
3297
|
+
* @returns {Array} Array containing the removed element, or empty array if item not found
|
|
3298
|
+
* @example
|
|
3299
|
+
* const items = Observable.array(['a', 'b', 'c']);
|
|
3300
|
+
* items.removeItem('b'); // ['b'] - Array is now ['a', 'c']
|
|
3301
|
+
*/
|
|
2974
3302
|
ObservableArray.prototype.removeItem = function(item) {
|
|
2975
3303
|
const indexOfItem = this.$currentValue.indexOf(item);
|
|
3304
|
+
if(indexOfItem === -1) {
|
|
3305
|
+
return [];
|
|
3306
|
+
}
|
|
2976
3307
|
return this.remove(indexOfItem);
|
|
2977
3308
|
};
|
|
2978
3309
|
|
|
3310
|
+
/**
|
|
3311
|
+
* Checks if the array is empty.
|
|
3312
|
+
*
|
|
3313
|
+
* @returns {boolean} True if array has no elements
|
|
3314
|
+
* @example
|
|
3315
|
+
* const items = Observable.array([]);
|
|
3316
|
+
* items.isEmpty(); // true
|
|
3317
|
+
*/
|
|
2979
3318
|
ObservableArray.prototype.isEmpty = function() {
|
|
2980
3319
|
return this.$currentValue.length === 0;
|
|
2981
3320
|
};
|
|
2982
3321
|
|
|
3322
|
+
/**
|
|
3323
|
+
* Triggers a populate operation with the current array, iteration count, and callback.
|
|
3324
|
+
* Used internally for rendering optimizations.
|
|
3325
|
+
*
|
|
3326
|
+
* @param {number} iteration - Iteration count for rendering
|
|
3327
|
+
* @param {Function} callback - Callback function for rendering items
|
|
3328
|
+
*/
|
|
2983
3329
|
ObservableArray.prototype.populateAndRender = function(iteration, callback) {
|
|
2984
3330
|
this.trigger({ action: 'populate', args: [this.$currentValue, iteration, callback] });
|
|
2985
3331
|
};
|
|
2986
3332
|
|
|
2987
3333
|
|
|
3334
|
+
/**
|
|
3335
|
+
* Creates a filtered view of the array based on predicates.
|
|
3336
|
+
* The filtered array updates automatically when source data or predicates change.
|
|
3337
|
+
*
|
|
3338
|
+
* @param {Object} predicates - Object mapping property names to filter conditions or functions
|
|
3339
|
+
* @returns {ObservableArray} A new observable array containing filtered items
|
|
3340
|
+
* @example
|
|
3341
|
+
* const users = Observable.array([
|
|
3342
|
+
* { name: 'John', age: 25 },
|
|
3343
|
+
* { name: 'Jane', age: 30 }
|
|
3344
|
+
* ]);
|
|
3345
|
+
* const adults = users.where({ age: (val) => val >= 18 });
|
|
3346
|
+
*/
|
|
2988
3347
|
ObservableArray.prototype.where = function(predicates) {
|
|
2989
3348
|
const sourceArray = this;
|
|
2990
3349
|
const observableDependencies = [sourceArray];
|
|
@@ -3033,6 +3392,20 @@ var NativeDocument = (function (exports) {
|
|
|
3033
3392
|
return viewArray;
|
|
3034
3393
|
};
|
|
3035
3394
|
|
|
3395
|
+
/**
|
|
3396
|
+
* Creates a filtered view where at least one of the specified fields matches the filter.
|
|
3397
|
+
*
|
|
3398
|
+
* @param {Array<string>} fields - Array of field names to check
|
|
3399
|
+
* @param {FilterResult} filter - Filter condition with callback and dependencies
|
|
3400
|
+
* @returns {ObservableArray} A new observable array containing filtered items
|
|
3401
|
+
* @example
|
|
3402
|
+
* const products = Observable.array([
|
|
3403
|
+
* { name: 'Apple', category: 'Fruit' },
|
|
3404
|
+
* { name: 'Carrot', category: 'Vegetable' }
|
|
3405
|
+
* ]);
|
|
3406
|
+
* const searchTerm = Observable('App');
|
|
3407
|
+
* const filtered = products.whereSome(['name', 'category'], match(searchTerm));
|
|
3408
|
+
*/
|
|
3036
3409
|
ObservableArray.prototype.whereSome = function(fields, filter) {
|
|
3037
3410
|
return this.where({
|
|
3038
3411
|
_: {
|
|
@@ -3042,6 +3415,20 @@ var NativeDocument = (function (exports) {
|
|
|
3042
3415
|
});
|
|
3043
3416
|
};
|
|
3044
3417
|
|
|
3418
|
+
/**
|
|
3419
|
+
* Creates a filtered view where all specified fields match the filter.
|
|
3420
|
+
*
|
|
3421
|
+
* @param {Array<string>} fields - Array of field names to check
|
|
3422
|
+
* @param {FilterResult} filter - Filter condition with callback and dependencies
|
|
3423
|
+
* @returns {ObservableArray} A new observable array containing filtered items
|
|
3424
|
+
* @example
|
|
3425
|
+
* const items = Observable.array([
|
|
3426
|
+
* { status: 'active', verified: true },
|
|
3427
|
+
* { status: 'active', verified: false }
|
|
3428
|
+
* ]);
|
|
3429
|
+
* const activeFilter = equals('active');
|
|
3430
|
+
* const filtered = items.whereEvery(['status', 'verified'], activeFilter);
|
|
3431
|
+
*/
|
|
3045
3432
|
ObservableArray.prototype.whereEvery = function(fields, filter) {
|
|
3046
3433
|
return this.where({
|
|
3047
3434
|
_: {
|
|
@@ -3052,10 +3439,19 @@ var NativeDocument = (function (exports) {
|
|
|
3052
3439
|
};
|
|
3053
3440
|
|
|
3054
3441
|
/**
|
|
3442
|
+
* Creates an observable array with reactive array methods.
|
|
3443
|
+
* All mutations trigger updates automatically.
|
|
3055
3444
|
*
|
|
3056
|
-
* @param {Array} target
|
|
3057
|
-
* @param {
|
|
3058
|
-
* @
|
|
3445
|
+
* @param {Array} [target=[]] - Initial array value
|
|
3446
|
+
* @param {Object|null} [configs=null] - Configuration options
|
|
3447
|
+
* // @param {boolean} [configs.propagation=true] - Whether to propagate changes to parent observables
|
|
3448
|
+
* // @param {boolean} [configs.deep=false] - Whether to make nested objects observable
|
|
3449
|
+
* @param {boolean} [configs.reset=false] - Whether to store initial value for reset()
|
|
3450
|
+
* @returns {ObservableArray} An observable array with reactive methods
|
|
3451
|
+
* @example
|
|
3452
|
+
* const items = Observable.array([1, 2, 3]);
|
|
3453
|
+
* items.push(4); // Triggers update
|
|
3454
|
+
* items.subscribe((arr) => console.log(arr));
|
|
3059
3455
|
*/
|
|
3060
3456
|
Observable.array = function(target = [], configs = null) {
|
|
3061
3457
|
return new ObservableArray(target, configs);
|
|
@@ -3120,10 +3516,26 @@ var NativeDocument = (function (exports) {
|
|
|
3120
3516
|
};
|
|
3121
3517
|
|
|
3122
3518
|
/**
|
|
3519
|
+
* Creates an observable proxy for an object where each property becomes an observable.
|
|
3520
|
+
* Properties can be accessed directly or via getter methods.
|
|
3123
3521
|
*
|
|
3124
|
-
* @param {Object} initialValue
|
|
3125
|
-
* @param {
|
|
3126
|
-
* @
|
|
3522
|
+
* @param {Object} initialValue - Initial object value
|
|
3523
|
+
* @param {Object|null} [configs=null] - Configuration options
|
|
3524
|
+
* // @param {boolean} [configs.propagation=true] - Whether changes propagate to parent
|
|
3525
|
+
* @param {boolean} [configs.deep=false] - Whether to make nested objects observable
|
|
3526
|
+
* @param {boolean} [configs.reset=false] - Whether to enable reset() method
|
|
3527
|
+
* @returns {ObservableProxy} A proxy where each property is an observable
|
|
3528
|
+
* @example
|
|
3529
|
+
* const user = Observable.init({
|
|
3530
|
+
* name: 'John',
|
|
3531
|
+
* age: 25,
|
|
3532
|
+
* address: { city: 'NYC' }
|
|
3533
|
+
* }, { deep: true });
|
|
3534
|
+
*
|
|
3535
|
+
* user.name.val(); // 'John'
|
|
3536
|
+
* user.name.set('Jane');
|
|
3537
|
+
* user.name = 'Jane X'
|
|
3538
|
+
* user.age.subscribe(val => console.log('Age:', val));
|
|
3127
3539
|
*/
|
|
3128
3540
|
Observable.init = function(initialValue, configs = null) {
|
|
3129
3541
|
const data = {};
|
|
@@ -3271,17 +3683,30 @@ var NativeDocument = (function (exports) {
|
|
|
3271
3683
|
Observable.json = Observable.init;
|
|
3272
3684
|
|
|
3273
3685
|
/**
|
|
3686
|
+
* Creates a computed observable that automatically updates when its dependencies change.
|
|
3687
|
+
* The callback is re-executed whenever any dependency observable changes.
|
|
3274
3688
|
*
|
|
3275
|
-
* @param {Function} callback
|
|
3276
|
-
* @param {Array|Function} dependencies
|
|
3277
|
-
* @returns {ObservableItem}
|
|
3278
|
-
|
|
3689
|
+
* @param {Function} callback - Function that returns the computed value
|
|
3690
|
+
* @param {Array<ObservableItem|ObservableChecker|ObservableProxy>|Function} [dependencies=[]] - Array of observables to watch, or batch function
|
|
3691
|
+
* @returns {ObservableItem} A new observable that updates automatically
|
|
3692
|
+
* @example
|
|
3693
|
+
* const firstName = Observable('John');
|
|
3694
|
+
* const lastName = Observable('Doe');
|
|
3695
|
+
* const fullName = Observable.computed(
|
|
3696
|
+
* () => `${firstName.val()} ${lastName.val()}`,
|
|
3697
|
+
* [firstName, lastName]
|
|
3698
|
+
* );
|
|
3699
|
+
*
|
|
3700
|
+
* // With batch function
|
|
3701
|
+
* const batch = Observable.batch(() => { ... });
|
|
3702
|
+
* const computed = Observable.computed(() => { ... }, batch);
|
|
3703
|
+
*/
|
|
3279
3704
|
Observable.computed = function(callback, dependencies = []) {
|
|
3280
3705
|
const initialValue = callback();
|
|
3281
3706
|
const observable = new ObservableItem(initialValue);
|
|
3282
3707
|
const updatedValue = nextTick(() => observable.set(callback()));
|
|
3283
3708
|
{
|
|
3284
|
-
PluginsManager.emit('CreateObservableComputed', observable, dependencies);
|
|
3709
|
+
PluginsManager$1.emit('CreateObservableComputed', observable, dependencies);
|
|
3285
3710
|
}
|
|
3286
3711
|
|
|
3287
3712
|
if(Validator.isFunction(dependencies)) {
|
|
@@ -3379,12 +3804,24 @@ var NativeDocument = (function (exports) {
|
|
|
3379
3804
|
}());
|
|
3380
3805
|
|
|
3381
3806
|
/**
|
|
3807
|
+
* Renders a list of items from an observable array or object, automatically updating when data changes.
|
|
3808
|
+
* Efficiently manages DOM updates by tracking items with keys.
|
|
3382
3809
|
*
|
|
3383
|
-
* @param {Array|Object
|
|
3384
|
-
* @param {Function} callback
|
|
3385
|
-
* @param {
|
|
3386
|
-
* @param {{
|
|
3387
|
-
* @
|
|
3810
|
+
* @param {ObservableItem<Array|Object>} data - Observable containing array or object to iterate over
|
|
3811
|
+
* @param {Function} callback - Function that renders each item (item, index) => ValidChild
|
|
3812
|
+
* @param {string|Function} [key] - Property name or function to generate unique keys for items
|
|
3813
|
+
* @param {Object} [options={}] - Configuration options
|
|
3814
|
+
* @param {boolean} [options.shouldKeepItemsInCache=false] - Whether to cache rendered items
|
|
3815
|
+
* @returns {AnchorDocumentFragment} Fragment managing the list rendering
|
|
3816
|
+
* @example
|
|
3817
|
+
* const users = Observable([
|
|
3818
|
+
* { id: 1, name: 'John' },
|
|
3819
|
+
* { id: 2, name: 'Jane' }
|
|
3820
|
+
* ]);
|
|
3821
|
+
* ForEach(users, (user) => Div({}, user.name), 'id');
|
|
3822
|
+
*
|
|
3823
|
+
* // With function key
|
|
3824
|
+
* ForEach(items, (item) => Div({}, item), (item) => item.id);
|
|
3388
3825
|
*/
|
|
3389
3826
|
function ForEach(data, callback, key, { shouldKeepItemsInCache = false } = {}) {
|
|
3390
3827
|
const element = Anchor('ForEach');
|
|
@@ -3441,7 +3878,7 @@ var NativeDocument = (function (exports) {
|
|
|
3441
3878
|
}
|
|
3442
3879
|
cache.set(keyId, { keyId, isNew: true, child: new WeakRef(child), indexObserver});
|
|
3443
3880
|
} catch (e) {
|
|
3444
|
-
DebugManager.error('ForEach', `Error creating element for key ${keyId}` , e);
|
|
3881
|
+
DebugManager$1.error('ForEach', `Error creating element for key ${keyId}` , e);
|
|
3445
3882
|
throw e;
|
|
3446
3883
|
}
|
|
3447
3884
|
return keyId;
|
|
@@ -3523,8 +3960,26 @@ var NativeDocument = (function (exports) {
|
|
|
3523
3960
|
return element;
|
|
3524
3961
|
}
|
|
3525
3962
|
|
|
3963
|
+
/**
|
|
3964
|
+
* Renders items from an ObservableArray with optimized array-specific updates.
|
|
3965
|
+
* Provides index observables and handles array mutations efficiently.
|
|
3966
|
+
*
|
|
3967
|
+
* @param {ObservableArray} data - ObservableArray to iterate over
|
|
3968
|
+
* @param {Function} callback - Function that renders each item (item, indexObservable) => ValidChild
|
|
3969
|
+
* @param {Object} [configs={}] - Configuration options
|
|
3970
|
+
* @param {boolean} [configs.shouldKeepItemsInCache] - Whether to cache rendered items
|
|
3971
|
+
* @param {boolean} [configs.isParentUniqueChild] - When it's the only child of the parent
|
|
3972
|
+
* @returns {AnchorDocumentFragment} Fragment managing the list rendering
|
|
3973
|
+
* @example
|
|
3974
|
+
* const items = Observable.array([1, 2, 3]);
|
|
3975
|
+
* ForEachArray(items, (item, index) =>
|
|
3976
|
+
* Div({}, `Item ${item} at index ${index.val()}`)
|
|
3977
|
+
* );
|
|
3978
|
+
*
|
|
3979
|
+
* items.push(4); // Automatically updates DOM
|
|
3980
|
+
*/
|
|
3526
3981
|
function ForEachArray(data, callback, configs = {}) {
|
|
3527
|
-
const element = Anchor('ForEach Array');
|
|
3982
|
+
const element = Anchor('ForEach Array', configs.isParentUniqueChild);
|
|
3528
3983
|
const blockEnd = element.endElement();
|
|
3529
3984
|
const blockStart = element.startElement();
|
|
3530
3985
|
|
|
@@ -3699,7 +4154,7 @@ var NativeDocument = (function (exports) {
|
|
|
3699
4154
|
elementBeforeFirst = firstChildRemoved?.previousSibling;
|
|
3700
4155
|
|
|
3701
4156
|
for(let i = 0; i < deleted.length; i++) {
|
|
3702
|
-
|
|
4157
|
+
removeByItem(deleted[i], garbageFragment);
|
|
3703
4158
|
}
|
|
3704
4159
|
}
|
|
3705
4160
|
} else {
|
|
@@ -3778,16 +4233,22 @@ var NativeDocument = (function (exports) {
|
|
|
3778
4233
|
}
|
|
3779
4234
|
|
|
3780
4235
|
/**
|
|
3781
|
-
*
|
|
4236
|
+
* Conditionally shows an element based on an observable condition.
|
|
4237
|
+
* The element is mounted/unmounted from the DOM as the condition changes.
|
|
3782
4238
|
*
|
|
3783
|
-
* @param {ObservableItem
|
|
3784
|
-
* @param {
|
|
3785
|
-
* @param {{
|
|
3786
|
-
* @
|
|
4239
|
+
* @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
|
|
4240
|
+
* @param {ValidChild} child - Element or content to show/hide
|
|
4241
|
+
* @param {Object} [options={}] - Configuration options
|
|
4242
|
+
* @param {string|null} [options.comment=null] - Comment for debugging
|
|
4243
|
+
* @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
|
|
4244
|
+
* @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
|
|
4245
|
+
* @example
|
|
4246
|
+
* const isVisible = Observable(false);
|
|
4247
|
+
* ShowIf(isVisible, Div({}, 'Hello World'));
|
|
3787
4248
|
*/
|
|
3788
4249
|
const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
|
|
3789
4250
|
if(!(Validator.isObservable(condition)) && !Validator.isObservableWhenResult(condition)) {
|
|
3790
|
-
return DebugManager.warn('ShowIf', "ShowIf : condition must be an Observable / "+comment, condition);
|
|
4251
|
+
return DebugManager$1.warn('ShowIf', "ShowIf : condition must be an Observable / "+comment, condition);
|
|
3791
4252
|
}
|
|
3792
4253
|
const element = Anchor('Show if : '+(comment || ''));
|
|
3793
4254
|
|
|
@@ -3820,11 +4281,18 @@ var NativeDocument = (function (exports) {
|
|
|
3820
4281
|
};
|
|
3821
4282
|
|
|
3822
4283
|
/**
|
|
3823
|
-
*
|
|
3824
|
-
*
|
|
3825
|
-
*
|
|
3826
|
-
* @param {
|
|
3827
|
-
* @
|
|
4284
|
+
* Conditionally hides an element when the observable condition is true.
|
|
4285
|
+
* Inverse of ShowIf - element is shown when condition is false.
|
|
4286
|
+
*
|
|
4287
|
+
* @param {ObservableItem<boolean>|ObservableChecker<boolean>} condition - Observable condition to watch
|
|
4288
|
+
* @param {ValidChild} child - Element or content to show/hide
|
|
4289
|
+
* @param {Object} [configs] - Configuration options
|
|
4290
|
+
* @param {string|null} [configs.comment] - Comment for debugging
|
|
4291
|
+
* @param {boolean} [configs.shouldKeepInCache] - Whether to cache element when hidden
|
|
4292
|
+
* @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
|
|
4293
|
+
* @example
|
|
4294
|
+
* const hasError = Observable(false);
|
|
4295
|
+
* HideIf(hasError, Div({}, 'Content'));
|
|
3828
4296
|
*/
|
|
3829
4297
|
const HideIf = function(condition, child, configs) {
|
|
3830
4298
|
const hideCondition = Observable(!condition.val());
|
|
@@ -3834,17 +4302,43 @@ var NativeDocument = (function (exports) {
|
|
|
3834
4302
|
};
|
|
3835
4303
|
|
|
3836
4304
|
/**
|
|
3837
|
-
*
|
|
4305
|
+
* Conditionally hides an element when the observable condition is false.
|
|
4306
|
+
* Same as ShowIf - element is shown when condition is true.
|
|
3838
4307
|
*
|
|
3839
|
-
* @param {ObservableItem
|
|
3840
|
-
* @param {
|
|
3841
|
-
* @param {
|
|
3842
|
-
* @
|
|
4308
|
+
* @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
|
|
4309
|
+
* @param {ValidChild} child - Element or content to show/hide
|
|
4310
|
+
* @param {Object} [configs] - Configuration options
|
|
4311
|
+
* @param {string|null} [configs.comment] - Comment for debugging
|
|
4312
|
+
* @param {boolean} [configs.shouldKeepInCache] - Whether to cache element when hidden
|
|
4313
|
+
* @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
|
|
3843
4314
|
*/
|
|
3844
4315
|
const HideIfNot = function(condition, child, configs) {
|
|
3845
4316
|
return ShowIf(condition, child, configs);
|
|
3846
4317
|
};
|
|
3847
4318
|
|
|
4319
|
+
/**
|
|
4320
|
+
* Shows content when an observable equals a specific value.
|
|
4321
|
+
* Can be called with 2 or 3 arguments.
|
|
4322
|
+
*
|
|
4323
|
+
* @overload
|
|
4324
|
+
* @param {ObservableWhen} observerWhenResult - Result from observable.when(value)
|
|
4325
|
+
* @param {ValidChild} view - Content to show when condition matches
|
|
4326
|
+
* @returns {AnchorDocumentFragment}
|
|
4327
|
+
*
|
|
4328
|
+
* @overload
|
|
4329
|
+
* @param {ObservableItem} observer - Observable to watch
|
|
4330
|
+
* @param {*} target - Value to match
|
|
4331
|
+
* @param {ValidChild} view - Content to show when observable equals target
|
|
4332
|
+
* @returns {AnchorDocumentFragment}
|
|
4333
|
+
*
|
|
4334
|
+
* @example
|
|
4335
|
+
* // 2 arguments
|
|
4336
|
+
* const status = Observable('idle');
|
|
4337
|
+
* ShowWhen(status.when('loading'), LoadingSpinner());
|
|
4338
|
+
*
|
|
4339
|
+
* // 3 arguments
|
|
4340
|
+
* ShowWhen(status, 'loading', LoadingSpinner());
|
|
4341
|
+
*/
|
|
3848
4342
|
const ShowWhen = function() {
|
|
3849
4343
|
if(arguments.length === 2) {
|
|
3850
4344
|
const [observer, target] = arguments;
|
|
@@ -3874,11 +4368,24 @@ var NativeDocument = (function (exports) {
|
|
|
3874
4368
|
};
|
|
3875
4369
|
|
|
3876
4370
|
/**
|
|
4371
|
+
* Displays different content based on the current value of an observable.
|
|
4372
|
+
* Like a switch statement for UI - shows the content corresponding to current value.
|
|
3877
4373
|
*
|
|
3878
|
-
* @param {ObservableItem|ObservableChecker} $condition
|
|
3879
|
-
* @param {
|
|
3880
|
-
* @param {
|
|
3881
|
-
* @returns {
|
|
4374
|
+
* @param {ObservableItem|ObservableChecker} $condition - Observable to watch
|
|
4375
|
+
* @param {Object<string|number, ValidChild>} values - Map of values to their corresponding content
|
|
4376
|
+
* @param {boolean} [shouldKeepInCache=true] - Whether to cache rendered views
|
|
4377
|
+
* @returns {AnchorDocumentFragment & {add: Function, remove: Function}} Fragment with dynamic methods
|
|
4378
|
+
* @example
|
|
4379
|
+
* const status = Observable('idle');
|
|
4380
|
+
* const view = Match(status, {
|
|
4381
|
+
* idle: Div({}, 'Ready'),
|
|
4382
|
+
* loading: Div({}, 'Loading...'),
|
|
4383
|
+
* error: Div({}, 'Error occurred')
|
|
4384
|
+
* });
|
|
4385
|
+
*
|
|
4386
|
+
* // Dynamic addition
|
|
4387
|
+
* view.add('success', Div({}, 'Success!'));
|
|
4388
|
+
* view.remove('idle');
|
|
3882
4389
|
*/
|
|
3883
4390
|
const Match = function($condition, values, shouldKeepInCache = true) {
|
|
3884
4391
|
|
|
@@ -3935,11 +4442,19 @@ var NativeDocument = (function (exports) {
|
|
|
3935
4442
|
|
|
3936
4443
|
|
|
3937
4444
|
/**
|
|
4445
|
+
* Displays one of two views based on a boolean observable condition.
|
|
4446
|
+
* Simplified version of Match for true/false cases.
|
|
3938
4447
|
*
|
|
3939
|
-
* @param {ObservableItem
|
|
3940
|
-
* @param {
|
|
3941
|
-
* @param {
|
|
3942
|
-
* @returns {
|
|
4448
|
+
* @param {ObservableItem<boolean>|ObservableChecker<boolean>} $condition - Boolean observable to watch
|
|
4449
|
+
* @param {ValidChild} onTrue - Content to show when condition is true
|
|
4450
|
+
* @param {ValidChild} onFalse - Content to show when condition is false
|
|
4451
|
+
* @returns {AnchorDocumentFragment} Fragment managing the conditional content
|
|
4452
|
+
* @example
|
|
4453
|
+
* const isLoggedIn = Observable(false);
|
|
4454
|
+
* Switch(isLoggedIn,
|
|
4455
|
+
* Div({}, 'Welcome back!'),
|
|
4456
|
+
* Div({}, 'Please login')
|
|
4457
|
+
* );
|
|
3943
4458
|
*/
|
|
3944
4459
|
const Switch = function ($condition, onTrue, onFalse) {
|
|
3945
4460
|
if(!Validator.isObservable($condition)) {
|
|
@@ -3953,9 +4468,15 @@ var NativeDocument = (function (exports) {
|
|
|
3953
4468
|
};
|
|
3954
4469
|
|
|
3955
4470
|
/**
|
|
4471
|
+
* Provides a fluent API for conditional rendering with show/otherwise pattern.
|
|
3956
4472
|
*
|
|
3957
|
-
* @param {ObservableItem
|
|
3958
|
-
* @returns {{show: Function, otherwise:
|
|
4473
|
+
* @param {ObservableItem<boolean>|ObservableChecker<boolean>} $condition - Boolean observable to watch
|
|
4474
|
+
* @returns {{show: Function, otherwise: Function}} Object with fluent methods
|
|
4475
|
+
* @example
|
|
4476
|
+
* const isLoading = Observable(false);
|
|
4477
|
+
* When(isLoading)
|
|
4478
|
+
* .show(LoadingSpinner())
|
|
4479
|
+
* .otherwise(Content());
|
|
3959
4480
|
*/
|
|
3960
4481
|
const When = function($condition) {
|
|
3961
4482
|
if(!Validator.isObservable($condition)) {
|
|
@@ -3973,6 +4494,9 @@ var NativeDocument = (function (exports) {
|
|
|
3973
4494
|
otherwise(onFalse) {
|
|
3974
4495
|
$onFalse = onFalse;
|
|
3975
4496
|
return Switch($condition, $onTrue, $onFalse);
|
|
4497
|
+
},
|
|
4498
|
+
toNdElement() {
|
|
4499
|
+
return Switch($condition, $onTrue, $onFalse);
|
|
3976
4500
|
}
|
|
3977
4501
|
}
|
|
3978
4502
|
};
|
|
@@ -4312,11 +4836,16 @@ var NativeDocument = (function (exports) {
|
|
|
4312
4836
|
};
|
|
4313
4837
|
|
|
4314
4838
|
/**
|
|
4839
|
+
* Creates a new Route instance.
|
|
4315
4840
|
*
|
|
4316
|
-
* @param {string} $path
|
|
4317
|
-
* @param {Function} $component
|
|
4318
|
-
* @param {
|
|
4319
|
-
* @
|
|
4841
|
+
* @param {string} $path - URL pattern with optional parameters (e.g., '/user/{id:number}')
|
|
4842
|
+
* @param {Function} $component - Component function that returns HTMLElement or DocumentFragment
|
|
4843
|
+
* @param {Object} [$options={}] - Route configuration options
|
|
4844
|
+
* @param {string} [$options.name] - Unique name for the route (used for navigation)
|
|
4845
|
+
* @param {Function[]} [$options.middlewares] - Array of middleware functions
|
|
4846
|
+
* @param {boolean} [$options.shouldRebuild] - Whether to rebuild component on each navigation
|
|
4847
|
+
* @param {Object} [$options.with] - Custom parameter validation patterns
|
|
4848
|
+
* @param {Function} [$options.layout] - Layout component wrapper function
|
|
4320
4849
|
*/
|
|
4321
4850
|
function Route($path, $component, $options = {}) {
|
|
4322
4851
|
|
|
@@ -4415,7 +4944,6 @@ var NativeDocument = (function (exports) {
|
|
|
4415
4944
|
super(message);
|
|
4416
4945
|
this.context = context;
|
|
4417
4946
|
}
|
|
4418
|
-
|
|
4419
4947
|
}
|
|
4420
4948
|
|
|
4421
4949
|
const RouteGroupHelper = {
|
|
@@ -4574,7 +5102,7 @@ var NativeDocument = (function (exports) {
|
|
|
4574
5102
|
window.history.pushState({ name: route.name(), params, path}, route.name() || path , path);
|
|
4575
5103
|
this.handleRouteChange(route, params, query, path);
|
|
4576
5104
|
} catch (e) {
|
|
4577
|
-
DebugManager.error('HistoryRouter', 'Error in pushState', e);
|
|
5105
|
+
DebugManager$1.error('HistoryRouter', 'Error in pushState', e);
|
|
4578
5106
|
}
|
|
4579
5107
|
};
|
|
4580
5108
|
/**
|
|
@@ -4587,7 +5115,7 @@ var NativeDocument = (function (exports) {
|
|
|
4587
5115
|
window.history.replaceState({ name: route.name(), params, path}, route.name() || path , path);
|
|
4588
5116
|
this.handleRouteChange(route, params, {}, path);
|
|
4589
5117
|
} catch(e) {
|
|
4590
|
-
DebugManager.error('HistoryRouter', 'Error in replaceState', e);
|
|
5118
|
+
DebugManager$1.error('HistoryRouter', 'Error in replaceState', e);
|
|
4591
5119
|
}
|
|
4592
5120
|
};
|
|
4593
5121
|
this.forward = function() {
|
|
@@ -4614,7 +5142,7 @@ var NativeDocument = (function (exports) {
|
|
|
4614
5142
|
}
|
|
4615
5143
|
this.handleRouteChange(route, params, query, path);
|
|
4616
5144
|
} catch(e) {
|
|
4617
|
-
DebugManager.error('HistoryRouter', 'Error in popstate event', e);
|
|
5145
|
+
DebugManager$1.error('HistoryRouter', 'Error in popstate event', e);
|
|
4618
5146
|
}
|
|
4619
5147
|
});
|
|
4620
5148
|
const { route, params, query, path } = this.resolve(defaultPath || (window.location.pathname+window.location.search));
|
|
@@ -4811,7 +5339,7 @@ var NativeDocument = (function (exports) {
|
|
|
4811
5339
|
/**
|
|
4812
5340
|
*
|
|
4813
5341
|
* @param {{mode: 'memory'|'history'|'hash'}} $options
|
|
4814
|
-
* @
|
|
5342
|
+
* @class
|
|
4815
5343
|
*/
|
|
4816
5344
|
function Router($options = {}) {
|
|
4817
5345
|
|
|
@@ -4839,7 +5367,7 @@ var NativeDocument = (function (exports) {
|
|
|
4839
5367
|
listener(request);
|
|
4840
5368
|
next && next(request);
|
|
4841
5369
|
} catch (e) {
|
|
4842
|
-
DebugManager.warn('Route Listener', 'Error in listener:', e);
|
|
5370
|
+
DebugManager$1.warn('Route Listener', 'Error in listener:', e);
|
|
4843
5371
|
}
|
|
4844
5372
|
}
|
|
4845
5373
|
};
|
|
@@ -4869,11 +5397,20 @@ var NativeDocument = (function (exports) {
|
|
|
4869
5397
|
};
|
|
4870
5398
|
|
|
4871
5399
|
/**
|
|
5400
|
+
* Groups routes under a common path prefix with shared options.
|
|
4872
5401
|
*
|
|
4873
|
-
* @param {string} suffix
|
|
4874
|
-
* @param {
|
|
4875
|
-
* @param {Function}
|
|
4876
|
-
* @
|
|
5402
|
+
* @param {string} suffix - Path prefix to prepend to all routes in the group
|
|
5403
|
+
* @param {Object} options - Group configuration options
|
|
5404
|
+
* @param {Function[]} [options.middlewares] - Middlewares applied to all routes in group
|
|
5405
|
+
* @param {string} [options.name] - Name prefix for all routes in group
|
|
5406
|
+
* @param {Function} [options.layout] - Layout component for all routes in group
|
|
5407
|
+
* @param {Function} callback - Function that defines routes within the group
|
|
5408
|
+
* @returns {this} Router instance for chaining
|
|
5409
|
+
* @example
|
|
5410
|
+
* router.group('/admin', { middlewares: [authMiddleware], layout: AdminLayout }, () => {
|
|
5411
|
+
* router.add('/users', UsersPage, { name: 'users' });
|
|
5412
|
+
* router.add('/settings', SettingsPage, { name: 'settings' });
|
|
5413
|
+
* });
|
|
4877
5414
|
*/
|
|
4878
5415
|
this.group = function(suffix, options, callback) {
|
|
4879
5416
|
if(!Validator.isFunction(callback)) {
|
|
@@ -4991,14 +5528,24 @@ var NativeDocument = (function (exports) {
|
|
|
4991
5528
|
Router.routers = {};
|
|
4992
5529
|
|
|
4993
5530
|
/**
|
|
5531
|
+
* Creates and initializes a new router instance.
|
|
4994
5532
|
*
|
|
4995
|
-
* @param {
|
|
4996
|
-
* @param {
|
|
4997
|
-
* @param {
|
|
5533
|
+
* @param {Object} options - Router configuration
|
|
5534
|
+
* @param {'memory'|'history'|'hash'} options.mode - Routing mode
|
|
5535
|
+
* @param {string} [options.name] - Router name for multi-router apps
|
|
5536
|
+
* @param {string} [options.entry] - Initial route path
|
|
5537
|
+
* @param {Function} callback - Setup function that receives the router instance
|
|
5538
|
+
* @returns {Router} The configured router instance with mount() method
|
|
5539
|
+
* @example
|
|
5540
|
+
* const router = Router.create({ mode: 'history' }, (r) => {
|
|
5541
|
+
* r.add('/home', HomePage, { name: 'home' });
|
|
5542
|
+
* r.add('/about', AboutPage, { name: 'about' });
|
|
5543
|
+
* });
|
|
5544
|
+
* router.mount('#app');
|
|
4998
5545
|
*/
|
|
4999
5546
|
Router.create = function(options, callback) {
|
|
5000
5547
|
if(!Validator.isFunction(callback)) {
|
|
5001
|
-
DebugManager.error('Router', 'Callback must be a function'
|
|
5548
|
+
DebugManager$1.error('Router', 'Callback must be a function');
|
|
5002
5549
|
throw new RouterError('Callback must be a function');
|
|
5003
5550
|
}
|
|
5004
5551
|
const router = new Router(options);
|
|
@@ -5165,16 +5712,22 @@ var NativeDocument = (function (exports) {
|
|
|
5165
5712
|
};
|
|
5166
5713
|
}
|
|
5167
5714
|
|
|
5168
|
-
const
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5715
|
+
const once = fn => autoOnce(fn);
|
|
5716
|
+
const singleton = fn => once$1(fn);
|
|
5717
|
+
const memoize = fn => autoMemoize(fn);
|
|
5718
|
+
|
|
5719
|
+
var cache = /*#__PURE__*/Object.freeze({
|
|
5720
|
+
__proto__: null,
|
|
5721
|
+
memoize: memoize,
|
|
5722
|
+
once: once,
|
|
5723
|
+
singleton: singleton
|
|
5724
|
+
});
|
|
5172
5725
|
|
|
5173
5726
|
var utils = /*#__PURE__*/Object.freeze({
|
|
5174
5727
|
__proto__: null,
|
|
5175
|
-
|
|
5728
|
+
Cache: cache,
|
|
5176
5729
|
NativeFetch: NativeFetch,
|
|
5177
|
-
|
|
5730
|
+
filters: index
|
|
5178
5731
|
});
|
|
5179
5732
|
|
|
5180
5733
|
exports.$ = $;
|
|
@@ -5182,7 +5735,7 @@ var NativeDocument = (function (exports) {
|
|
|
5182
5735
|
exports.HtmlElementWrapper = HtmlElementWrapper;
|
|
5183
5736
|
exports.NDElement = NDElement;
|
|
5184
5737
|
exports.Observable = Observable;
|
|
5185
|
-
exports.PluginsManager = PluginsManager;
|
|
5738
|
+
exports.PluginsManager = PluginsManager$1;
|
|
5186
5739
|
exports.SingletonView = SingletonView;
|
|
5187
5740
|
exports.Store = Store;
|
|
5188
5741
|
exports.TemplateCloner = TemplateCloner;
|
|
@@ -5193,10 +5746,10 @@ var NativeDocument = (function (exports) {
|
|
|
5193
5746
|
exports.createTextNode = createTextNode;
|
|
5194
5747
|
exports.cssPropertyAccumulator = cssPropertyAccumulator;
|
|
5195
5748
|
exports.elements = elements;
|
|
5196
|
-
exports.memoize = memoize;
|
|
5749
|
+
exports.memoize = memoize$1;
|
|
5197
5750
|
exports.normalizeComponentArgs = normalizeComponentArgs;
|
|
5198
5751
|
exports.obs = obs;
|
|
5199
|
-
exports.once = once;
|
|
5752
|
+
exports.once = once$1;
|
|
5200
5753
|
exports.router = router;
|
|
5201
5754
|
exports.useCache = useCache;
|
|
5202
5755
|
exports.useSingleton = useSingleton;
|