native-document 1.0.91 → 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.
Files changed (68) hide show
  1. package/dist/native-document.components.min.js +1168 -138
  2. package/dist/native-document.dev.js +792 -217
  3. package/dist/native-document.dev.js.map +1 -1
  4. package/dist/native-document.devtools.min.js +1 -1
  5. package/dist/native-document.min.js +1 -1
  6. package/docs/advanced-components.md +814 -0
  7. package/docs/anchor.md +71 -11
  8. package/docs/cache.md +888 -0
  9. package/docs/conditional-rendering.md +91 -1
  10. package/docs/core-concepts.md +9 -2
  11. package/docs/elements.md +127 -2
  12. package/docs/extending-native-document-element.md +7 -1
  13. package/docs/filters.md +1216 -0
  14. package/docs/getting-started.md +12 -3
  15. package/docs/lifecycle-events.md +10 -2
  16. package/docs/list-rendering.md +453 -54
  17. package/docs/memory-management.md +9 -7
  18. package/docs/native-document-element.md +30 -9
  19. package/docs/native-fetch.md +744 -0
  20. package/docs/observables.md +135 -6
  21. package/docs/routing.md +7 -1
  22. package/docs/state-management.md +7 -1
  23. package/docs/validation.md +8 -1
  24. package/eslint.config.js +3 -3
  25. package/package.json +3 -2
  26. package/readme.md +53 -14
  27. package/src/components/$traits/HasItems.js +42 -1
  28. package/src/components/BaseComponent.js +4 -1
  29. package/src/components/accordion/Accordion.js +112 -8
  30. package/src/components/accordion/AccordionItem.js +93 -4
  31. package/src/components/alert/Alert.js +164 -4
  32. package/src/components/avatar/Avatar.js +236 -22
  33. package/src/components/menu/index.js +1 -2
  34. package/src/core/data/ObservableArray.js +120 -2
  35. package/src/core/data/ObservableChecker.js +50 -0
  36. package/src/core/data/ObservableItem.js +223 -80
  37. package/src/core/data/ObservableWhen.js +36 -6
  38. package/src/core/data/observable-helpers/array.js +12 -3
  39. package/src/core/data/observable-helpers/computed.js +17 -4
  40. package/src/core/data/observable-helpers/object.js +19 -3
  41. package/src/core/elements/control/for-each-array.js +21 -3
  42. package/src/core/elements/control/for-each.js +17 -5
  43. package/src/core/elements/control/show-if.js +31 -15
  44. package/src/core/elements/control/show-when.js +23 -0
  45. package/src/core/elements/control/switch.js +40 -10
  46. package/src/core/utils/cache.js +5 -0
  47. package/src/core/utils/memoize.js +25 -16
  48. package/src/core/utils/prototypes.js +3 -2
  49. package/src/core/wrappers/AttributesWrapper.js +1 -1
  50. package/src/core/wrappers/NDElement.js +41 -1
  51. package/src/core/wrappers/NdPrototype.js +4 -0
  52. package/src/core/wrappers/TemplateCloner.js +13 -10
  53. package/src/core/wrappers/prototypes/bind-class-extensions.js +1 -1
  54. package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -0
  55. package/src/router/Route.js +9 -4
  56. package/src/router/Router.js +28 -9
  57. package/src/router/errors/RouterError.js +0 -1
  58. package/types/control-flow.d.ts +9 -6
  59. package/types/elements.d.ts +6 -3
  60. package/types/filters/index.d.ts +4 -0
  61. package/types/nd-element.d.ts +5 -238
  62. package/types/observable.d.ts +9 -3
  63. package/types/router.d.ts +5 -1
  64. package/types/template-cloner.ts +1 -0
  65. package/types/validator.ts +11 -1
  66. package/utils.d.ts +2 -1
  67. package/utils.js +4 -4
  68. 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$1 = {};
4
+ let DebugManager = {};
5
5
 
6
6
  {
7
- DebugManager$1 = {
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$1;
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$1 = null;
194
+ let PluginsManager = null;
145
195
 
146
196
  {
147
- PluginsManager$1 = (function() {
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$1;
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
- ObservableWhen.prototype.isMath = function() {
240
- return this.$observer.$currentValue === this.$target;
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
- ObservableWhen.prototype.isActive = function() {
244
- return this.$observer.$currentValue === this.$target;
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;
@@ -326,7 +406,9 @@ var NativeDocument = (function (exports) {
326
406
 
327
407
  this.$previousValue = null;
328
408
  this.$currentValue = value;
329
- this.$isCleanedUp = false;
409
+ {
410
+ this.$isCleanedUp = false;
411
+ }
330
412
 
331
413
  this.$firstListener = null;
332
414
  this.$listeners = null;
@@ -341,7 +423,7 @@ var NativeDocument = (function (exports) {
341
423
  }
342
424
  }
343
425
  {
344
- PluginsManager.emit('CreateObservable', this);
426
+ PluginsManager$1.emit('CreateObservable', this);
345
427
  }
346
428
  }
347
429
 
@@ -356,16 +438,26 @@ var NativeDocument = (function (exports) {
356
438
  });
357
439
 
358
440
  ObservableItem.prototype.__$isObservable = true;
359
- const DEFAULT_OPERATIONS = {};
360
441
  const noneTrigger = function() {};
361
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
+ */
362
453
  ObservableItem.prototype.intercept = function(callback) {
363
454
  this.$interceptor = callback;
455
+ this.set = this.$setWithInterceptor;
364
456
  return this;
365
457
  };
366
458
 
367
459
  ObservableItem.prototype.triggerFirstListener = function(operations) {
368
- this.$firstListener(this.$currentValue, this.$previousValue, operations || {});
460
+ this.$firstListener(this.$currentValue, this.$previousValue, operations);
369
461
  };
370
462
 
371
463
  ObservableItem.prototype.triggerListeners = function(operations) {
@@ -373,33 +465,12 @@ var NativeDocument = (function (exports) {
373
465
  const $previousValue = this.$previousValue;
374
466
  const $currentValue = this.$currentValue;
375
467
 
376
- operations = operations || DEFAULT_OPERATIONS;
377
468
  for(let i = 0, length = $listeners.length; i < length; i++) {
378
469
  $listeners[i]($currentValue, $previousValue, operations);
379
470
  }
380
471
  };
381
472
 
382
- const handleWatcherCallback = function(callbacks, value) {
383
- if(typeof callbacks === "function") {
384
- callbacks(value);
385
- return;
386
- }
387
- if (callbacks.set) {
388
- callbacks.set(value);
389
- return;
390
- }
391
- for(let i = 0, length = callbacks.length; i < length; i++) {
392
- const callback = callbacks[i];
393
- callback.set ? callback.set(value) : callback(value);
394
-
395
- }
396
- };
397
-
398
- ObservableItem.prototype.triggerWatchers = function() {
399
- if(!this.$watchers) {
400
- return;
401
- }
402
-
473
+ ObservableItem.prototype.triggerWatchers = function(operations) {
403
474
  const $watchers = this.$watchers;
404
475
  const $previousValue = this.$previousValue;
405
476
  const $currentValue = this.$currentValue;
@@ -407,20 +478,20 @@ var NativeDocument = (function (exports) {
407
478
  const $currentValueCallbacks = $watchers.get($currentValue);
408
479
  const $previousValueCallbacks = $watchers.get($previousValue);
409
480
  if($currentValueCallbacks) {
410
- handleWatcherCallback($currentValueCallbacks, true);
481
+ $currentValueCallbacks(true, $previousValue, operations);
411
482
  }
412
483
  if($previousValueCallbacks) {
413
- handleWatcherCallback($previousValueCallbacks, false);
484
+ $previousValueCallbacks(false, $currentValue, operations);
414
485
  }
415
486
  };
416
487
 
417
488
  ObservableItem.prototype.triggerAll = function(operations) {
418
- this.triggerWatchers();
489
+ this.triggerWatchers(operations);
419
490
  this.triggerListeners(operations);
420
491
  };
421
492
 
422
493
  ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations) {
423
- this.triggerWatchers();
494
+ this.triggerWatchers(operations);
424
495
  this.triggerFirstListener(operations);
425
496
  };
426
497
 
@@ -448,36 +519,47 @@ var NativeDocument = (function (exports) {
448
519
  };
449
520
  ObservableItem.prototype.trigger = noneTrigger;
450
521
 
451
- /**
452
- * @param {*} data
453
- */
454
- ObservableItem.prototype.set = function(data) {
455
- let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
456
- newValue = Validator.isObservable(newValue) ? newValue.val() : newValue;
457
-
458
- if (this.$interceptor) {
459
- const result = this.$interceptor(newValue, this.$currentValue);
460
-
461
- if (result !== undefined) {
462
- newValue = result;
463
- }
464
- }
465
-
522
+ ObservableItem.prototype.$updateWithNewValue = function(newValue) {
523
+ newValue = newValue?.__$isObservable ? newValue.val() : newValue;
466
524
  if(this.$currentValue === newValue) {
467
525
  return;
468
526
  }
469
527
  this.$previousValue = this.$currentValue;
470
528
  this.$currentValue = newValue;
471
529
  {
472
- PluginsManager.emit('ObservableBeforeChange', this);
530
+ PluginsManager$1.emit('ObservableBeforeChange', this);
473
531
  }
474
532
  this.trigger();
475
533
  this.$previousValue = null;
476
534
  {
477
- PluginsManager.emit('ObservableAfterChange', this);
535
+ PluginsManager$1.emit('ObservableAfterChange', this);
478
536
  }
479
537
  };
480
538
 
539
+ /**
540
+ * @param {*} data
541
+ */
542
+ ObservableItem.prototype.$setWithInterceptor = function(data) {
543
+ let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
544
+ const result = this.$interceptor(newValue, this.$currentValue);
545
+
546
+ if (result !== undefined) {
547
+ newValue = result;
548
+ }
549
+
550
+ this.$updateWithNewValue(newValue);
551
+ };
552
+
553
+ /**
554
+ * @param {*} data
555
+ */
556
+ ObservableItem.prototype.$basicSet = function(data) {
557
+ let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
558
+ this.$updateWithNewValue(newValue);
559
+ };
560
+
561
+ ObservableItem.prototype.set = ObservableItem.prototype.$basicSet;
562
+
481
563
  ObservableItem.prototype.val = function() {
482
564
  return this.$currentValue;
483
565
  };
@@ -499,6 +581,16 @@ var NativeDocument = (function (exports) {
499
581
  this.trigger = noneTrigger;
500
582
  };
501
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
+ */
502
594
  ObservableItem.prototype.onCleanup = function(callback) {
503
595
  this.$cleanupListeners = this.$cleanupListeners ?? [];
504
596
  this.$cleanupListeners.push(callback);
@@ -513,79 +605,129 @@ var NativeDocument = (function (exports) {
513
605
  }
514
606
  MemoryManager.unregister(this.$memoryId);
515
607
  this.disconnectAll();
516
- this.$isCleanedUp = true;
608
+ {
609
+ this.$isCleanedUp = true;
610
+ }
517
611
  delete this.$value;
518
612
  };
519
613
 
520
614
  /**
521
615
  *
522
616
  * @param {Function} callback
523
- * @param {any} target
524
617
  * @returns {(function(): void)}
525
618
  */
526
- ObservableItem.prototype.subscribe = function(callback, target = null) {
527
- this.$listeners = this.$listeners ?? [];
528
- if (this.$isCleanedUp) {
529
- DebugManager.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
530
- return () => {};
531
- }
532
- if (typeof callback !== 'function') {
533
- throw new NativeDocumentError('Callback must be a function');
619
+ ObservableItem.prototype.subscribe = function(callback) {
620
+ {
621
+ if (this.$isCleanedUp) {
622
+ DebugManager$1.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
623
+ return;
624
+ }
625
+ if (typeof callback !== 'function') {
626
+ throw new NativeDocumentError('Callback must be a function');
627
+ }
534
628
  }
629
+ this.$listeners = this.$listeners ?? [];
535
630
 
536
631
  this.$listeners.push(callback);
537
632
  this.assocTrigger();
538
633
  {
539
- PluginsManager.emit('ObservableSubscribe', this, target);
634
+ PluginsManager$1.emit('ObservableSubscribe', this);
540
635
  }
541
- return () => {
542
- this.unsubscribe(callback);
543
- this.assocTrigger();
544
- {
545
- PluginsManager.emit('ObservableUnsubscribe', this);
546
- }
547
- };
548
636
  };
549
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
+ */
550
649
  ObservableItem.prototype.on = function(value, callback) {
551
650
  this.$watchers = this.$watchers ?? new Map();
552
651
 
553
652
  let watchValueList = this.$watchers.get(value);
554
653
 
654
+ if(callback.__$isObservable) {
655
+ callback = callback.set.bind(callback);
656
+ }
657
+
555
658
  if(!watchValueList) {
659
+ watchValueList = callback;
556
660
  this.$watchers.set(value, callback);
557
- } else if(!Validator.isArray(watchValueList)) {
661
+ } else if(!Validator.isArray(watchValueList.list)) {
558
662
  watchValueList = [watchValueList, callback];
559
- this.$watchers.set(value, watchValueList);
663
+ callback = (value) => {
664
+ for(let i = 0, length = watchValueList.length; i < length; i++) {
665
+ watchValueList[i](value);
666
+ }
667
+ };
668
+ callback.list = watchValueList;
669
+ this.$watchers.set(value, callback);
560
670
  } else {
561
- watchValueList.push(callback);
671
+ watchValueList.list.push(callback);
562
672
  }
563
673
 
564
674
  this.assocTrigger();
565
- return () => {
566
- const index = watchValueList.indexOf(callback);
567
- watchValueList?.splice(index, 1);
568
- if(watchValueList.size === 1) {
569
- this.$watchers.set(value, watchValueList[0]);
570
- }
571
- else if(watchValueList.size === 0) {
572
- this.$watchers?.delete(value);
573
- watchValueList = null;
574
- }
675
+ };
676
+
677
+ /**
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'
688
+ */
689
+ ObservableItem.prototype.off = function(value, callback) {
690
+ if(!this.$watchers) return;
691
+
692
+ const watchValueList = this.$watchers.get(value);
693
+ if(!watchValueList) return;
694
+
695
+ if(!callback || !Array.isArray(watchValueList.list)) {
696
+ this.$watchers?.delete(value);
575
697
  this.assocTrigger();
576
- };
698
+ return;
699
+ }
700
+ const index = watchValueList.indexOf(callback);
701
+ watchValueList?.splice(index, 1);
702
+ if(watchValueList.length === 1) {
703
+ this.$watchers.set(value, watchValueList[0]);
704
+ }
705
+ else if(watchValueList.length === 0) {
706
+ this.$watchers?.delete(value);
707
+ }
708
+ this.assocTrigger();
577
709
  };
578
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
+ */
579
721
  ObservableItem.prototype.once = function(predicate, callback) {
580
722
  const fn = typeof predicate === 'function' ? predicate : (v) => v === predicate;
581
723
 
582
- const unsub = this.subscribe((val) => {
724
+ const handler = (val) => {
583
725
  if (fn(val)) {
584
- unsub();
726
+ this.unsubscribe(handler);
585
727
  callback(val);
586
728
  }
587
- });
588
- return unsub;
729
+ };
730
+ this.subscribe(handler);
589
731
  };
590
732
 
591
733
  /**
@@ -593,11 +735,15 @@ var NativeDocument = (function (exports) {
593
735
  * @param {Function} callback
594
736
  */
595
737
  ObservableItem.prototype.unsubscribe = function(callback) {
738
+ if(!this.$listeners) return;
596
739
  const index = this.$listeners.indexOf(callback);
597
740
  if (index > -1) {
598
741
  this.$listeners.splice(index, 1);
599
742
  }
600
743
  this.assocTrigger();
744
+ {
745
+ PluginsManager$1.emit('ObservableUnsubscribe', this);
746
+ }
601
747
  };
602
748
 
603
749
  /**
@@ -609,15 +755,50 @@ var NativeDocument = (function (exports) {
609
755
  return new ObservableChecker(this, callback)
610
756
  };
611
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
+ */
612
769
  ObservableItem.prototype.get = function(key) {
613
770
  const item = this.$currentValue[key];
614
771
  return Validator.isObservable(item) ? item.val() : item;
615
772
  };
616
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
+ */
617
786
  ObservableItem.prototype.when = function(value) {
618
787
  return new ObservableWhen(this, value);
619
788
  };
620
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
+ */
621
802
  ObservableItem.prototype.equals = function(other) {
622
803
  if(Validator.isObservable(other)) {
623
804
  return this.$currentValue === other.$currentValue;
@@ -625,14 +806,41 @@ var NativeDocument = (function (exports) {
625
806
  return this.$currentValue === other;
626
807
  };
627
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
+ */
628
819
  ObservableItem.prototype.toBool = function() {
629
820
  return !!this.$currentValue;
630
821
  };
631
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
+ */
632
831
  ObservableItem.prototype.toggle = function() {
633
832
  this.set(!this.$currentValue);
634
833
  };
635
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
+ */
636
844
  ObservableItem.prototype.reset = function() {
637
845
  if(!this.configs?.reset) {
638
846
  return;
@@ -645,11 +853,25 @@ var NativeDocument = (function (exports) {
645
853
  this.set(resetValue);
646
854
  };
647
855
 
648
-
856
+ /**
857
+ * Returns a string representation of the observable's current value.
858
+ *
859
+ * @returns {string} String representation of the current value
860
+ */
649
861
  ObservableItem.prototype.toString = function() {
650
862
  return String(this.$currentValue);
651
863
  };
652
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
+ */
871
+ ObservableItem.prototype.valueOf = function() {
872
+ return this.$currentValue;
873
+ };
874
+
653
875
  const DocumentObserver = {
654
876
  mounted: new WeakMap(),
655
877
  mountedSupposedSize: 0,
@@ -757,7 +979,7 @@ var NativeDocument = (function (exports) {
757
979
  this.$element = element;
758
980
  this.$observer = null;
759
981
  {
760
- PluginsManager.emit('NDElementCreated', element, this);
982
+ PluginsManager$1.emit('NDElementCreated', element, this);
761
983
  }
762
984
  }
763
985
 
@@ -853,12 +1075,35 @@ var NativeDocument = (function (exports) {
853
1075
  return this.shadow('closed', style);
854
1076
  };
855
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
+ */
856
1088
  NDElement.prototype.attach = function(methodName, bindingHydrator) {
857
1089
  bindingHydrator.$hydrate(this.$element, methodName);
858
1090
  return this.$element;
859
1091
  };
860
1092
 
861
-
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
+ */
862
1107
  NDElement.prototype.with = function(methods) {
863
1108
  if (!methods || typeof methods !== 'object') {
864
1109
  throw new NativeDocumentError('extend() requires an object of methods');
@@ -878,7 +1123,7 @@ var NativeDocument = (function (exports) {
878
1123
  }
879
1124
  {
880
1125
  if (this[name] && !this.$localExtensions.has(name)) {
881
- 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`);
882
1127
  }
883
1128
  this.$localExtensions.set(name, method);
884
1129
  }
@@ -889,6 +1134,23 @@ var NativeDocument = (function (exports) {
889
1134
  return this;
890
1135
  };
891
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
+ */
892
1154
  NDElement.extend = function(methods) {
893
1155
  if (!methods || typeof methods !== 'object') {
894
1156
  throw new NativeDocumentError('NDElement.extend() requires an object of methods');
@@ -912,23 +1174,23 @@ var NativeDocument = (function (exports) {
912
1174
  const method = methods[name];
913
1175
 
914
1176
  if (typeof method !== 'function') {
915
- DebugManager.warn('NDElement.extend', `"${name}" is not a function, skipping`);
1177
+ DebugManager$1.warn('NDElement.extend', `"${name}" is not a function, skipping`);
916
1178
  continue;
917
1179
  }
918
1180
 
919
1181
  if (protectedMethods.has(name)) {
920
- DebugManager.error('NDElement.extend', `Cannot override protected method "${name}"`);
1182
+ DebugManager$1.error('NDElement.extend', `Cannot override protected method "${name}"`);
921
1183
  throw new NativeDocumentError(`Cannot override protected method "${name}"`);
922
1184
  }
923
1185
 
924
1186
  if (NDElement.prototype[name]) {
925
- DebugManager.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
1187
+ DebugManager$1.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
926
1188
  }
927
1189
 
928
1190
  NDElement.prototype[name] = method;
929
1191
  }
930
1192
  {
931
- PluginsManager.emit('NDElementExtended', methods);
1193
+ PluginsManager$1.emit('NDElementExtended', methods);
932
1194
  }
933
1195
 
934
1196
  return NDElement;
@@ -1081,7 +1343,7 @@ var NativeDocument = (function (exports) {
1081
1343
  const foundReserved = Object.keys(attributes).filter(key => reserved.includes(key));
1082
1344
 
1083
1345
  if (foundReserved.length > 0) {
1084
- DebugManager.warn('Validator', `Reserved attributes found: ${foundReserved.join(', ')}`);
1346
+ DebugManager$1.warn('Validator', `Reserved attributes found: ${foundReserved.join(', ')}`);
1085
1347
  }
1086
1348
 
1087
1349
  return attributes;
@@ -1129,7 +1391,7 @@ var NativeDocument = (function (exports) {
1129
1391
  anchorFragment.appendChild = function(child, before = null) {
1130
1392
  const parent = anchorEnd.parentNode;
1131
1393
  if(!parent) {
1132
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
1394
+ DebugManager$1.error('Anchor', 'Anchor : parent not found', child);
1133
1395
  return;
1134
1396
  }
1135
1397
  before = before ?? anchorEnd;
@@ -1357,7 +1619,7 @@ var NativeDocument = (function (exports) {
1357
1619
  continue;
1358
1620
  }
1359
1621
  if(value.__$isObservableWhen) {
1360
- element.classes.toggle(className, value.isMath());
1622
+ element.classes.toggle(className, value.isActive());
1361
1623
  value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
1362
1624
  continue;
1363
1625
  }
@@ -1503,6 +1765,8 @@ var NativeDocument = (function (exports) {
1503
1765
  return ElementCreator.createObservableNode(null, this);
1504
1766
  };
1505
1767
 
1768
+ ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
1769
+
1506
1770
  NDElement.prototype.toNdElement = function () {
1507
1771
  return this.$element ?? this.$build?.() ?? this.build?.() ?? null;
1508
1772
  };
@@ -1520,7 +1784,7 @@ var NativeDocument = (function (exports) {
1520
1784
  Function.prototype.toNdElement = function () {
1521
1785
  const child = this;
1522
1786
  {
1523
- PluginsManager.emit('BeforeProcessComponent', child);
1787
+ PluginsManager$1.emit('BeforeProcessComponent', child);
1524
1788
  }
1525
1789
  return ElementCreator.getChild(child());
1526
1790
  };
@@ -1626,14 +1890,14 @@ var NativeDocument = (function (exports) {
1626
1890
  processChildren(children, parent) {
1627
1891
  if(children === null) return;
1628
1892
  {
1629
- PluginsManager.emit('BeforeProcessChildren', parent);
1893
+ PluginsManager$1.emit('BeforeProcessChildren', parent);
1630
1894
  }
1631
1895
  let child = this.getChild(children);
1632
1896
  if(child) {
1633
1897
  parent.appendChild(child);
1634
1898
  }
1635
1899
  {
1636
- PluginsManager.emit('AfterProcessChildren', parent);
1900
+ PluginsManager$1.emit('AfterProcessChildren', parent);
1637
1901
  }
1638
1902
  },
1639
1903
  getChild(child) {
@@ -1849,6 +2113,10 @@ var NativeDocument = (function (exports) {
1849
2113
  _stop(this.$element, eventName, callback);
1850
2114
  return this;
1851
2115
  };
2116
+ NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
2117
+ _preventStop(this.$element, eventName, callback);
2118
+ return this;
2119
+ };
1852
2120
  });
1853
2121
 
1854
2122
  EVENTS_WITH_PREVENT.forEach(eventSourceName => {
@@ -1882,6 +2150,16 @@ var NativeDocument = (function (exports) {
1882
2150
  return this;
1883
2151
  };
1884
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
+
1885
2163
 
1886
2164
 
1887
2165
  // ----------------------------------------------------------------
@@ -2154,7 +2432,12 @@ var NativeDocument = (function (exports) {
2154
2432
 
2155
2433
  const applyBindingTreePath = (root, target, data, path) => {
2156
2434
  if(path.fn) {
2157
- path.fn(data, target, root);
2435
+ if(typeof path.fn === 'string') {
2436
+ ElementCreator.bindTextNode(target, data[0][path.fn]);
2437
+ }
2438
+ else {
2439
+ path.fn(data, target, root);
2440
+ }
2158
2441
  }
2159
2442
  if(path.children) {
2160
2443
  for(let i = 0, length = path.children.length; i < length; i++) {
@@ -2180,15 +2463,16 @@ var NativeDocument = (function (exports) {
2180
2463
  if(bindDingData && bindDingData.value) {
2181
2464
  currentPath.fn = bindDingData.value;
2182
2465
  const textNode = node.cloneNode();
2466
+ if(typeof bindDingData.value === 'string') {
2467
+ ElementCreator.bindTextNode(textNode, data[0][bindDingData.value]);
2468
+ return textNode;
2469
+ }
2183
2470
  bindDingData.value(data, textNode);
2184
2471
  return textNode;
2185
2472
  }
2186
2473
  return node.cloneNode(true);
2187
2474
  }
2188
- const nodeCloned = node.cloneNode(node.fullCloneNode);
2189
- if(node.fullCloneNode) {
2190
- return nodeCloned;
2191
- }
2475
+ const nodeCloned = node.cloneNode();
2192
2476
  if(bindDingData) {
2193
2477
  bindAttributes(nodeCloned, bindDingData, data);
2194
2478
  bindAttachMethods(nodeCloned, bindDingData, data);
@@ -2253,12 +2537,9 @@ var NativeDocument = (function (exports) {
2253
2537
  };
2254
2538
  this.value = (callbackOrProperty) => {
2255
2539
  if(typeof callbackOrProperty !== 'function') {
2256
- return createBinding(function(data, textNode) {
2257
- const firstArgument = data[0];
2258
- ElementCreator.bindTextNode(textNode, firstArgument[callbackOrProperty]);
2259
- }, 'value');
2540
+ return createBinding(callbackOrProperty, 'value');
2260
2541
  }
2261
- return createBinding(function(data, textNode) {
2542
+ return createBinding((data, textNode) => {
2262
2543
  ElementCreator.bindTextNode(textNode, callbackOrProperty(...data));
2263
2544
  }, 'value');
2264
2545
  };
@@ -2360,13 +2641,14 @@ var NativeDocument = (function (exports) {
2360
2641
  };
2361
2642
 
2362
2643
  Function.prototype.errorBoundary = function(callback) {
2363
- return (...args) => {
2644
+ const handler = (...args) => {
2364
2645
  try {
2365
2646
  return this.apply(this, args);
2366
2647
  } catch(e) {
2367
- return callback(e);
2648
+ return callback(e, {caller: handler, args: args });
2368
2649
  }
2369
2650
  };
2651
+ return handler;
2370
2652
  };
2371
2653
 
2372
2654
  String.prototype.use = function(args) {
@@ -2438,12 +2720,13 @@ var NativeDocument = (function (exports) {
2438
2720
  };
2439
2721
  };
2440
2722
 
2441
- const once = (fn) => {
2723
+ const once$1 = (fn) => {
2442
2724
  let result = null;
2443
2725
  return (...args) => {
2444
- if(result === null) {
2445
- result = fn(...args);
2726
+ if(result) {
2727
+ return result;
2446
2728
  }
2729
+ result = fn(...args);
2447
2730
  return result;
2448
2731
  };
2449
2732
  };
@@ -2452,22 +2735,26 @@ var NativeDocument = (function (exports) {
2452
2735
  let target = null;
2453
2736
  return new Proxy({}, {
2454
2737
  get: (_, key) => {
2455
- if(target === null) {
2456
- target = fn();
2738
+ if(target) {
2739
+ return target[key];
2457
2740
  }
2741
+ target = fn();
2458
2742
  return target[key];
2459
2743
  }
2460
2744
  });
2461
2745
  };
2462
2746
 
2463
- const memoize = (fn) => {
2747
+ const memoize$1 = (fn) => {
2464
2748
  const cache = new Map();
2465
2749
  return (...args) => {
2466
2750
  const [key, ...rest] = args;
2467
- if(!cache.has(key)) {
2468
- cache.set(key, fn(...rest));
2751
+ const cached = cache.get(key);
2752
+ if(cached) {
2753
+ return cached;
2469
2754
  }
2470
- return cache.get(key);
2755
+ const result = fn(...rest);
2756
+ cache.set(key, result);
2757
+ return result;
2471
2758
  };
2472
2759
  };
2473
2760
 
@@ -2475,17 +2762,21 @@ var NativeDocument = (function (exports) {
2475
2762
  const cache = new Map();
2476
2763
  return new Proxy({}, {
2477
2764
  get: (_, key) => {
2478
- if(!cache.has(key)) {
2479
- if(fn.length > 0) {
2480
- return (...args) => {
2481
- const result = fn(...args);
2482
- cache.set(key, result);
2483
- return result;
2484
- }
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;
2485
2775
  }
2486
- cache.set(key, fn());
2487
2776
  }
2488
- return cache.get(key);
2777
+ const result = fn(key);
2778
+ cache.set(key, result);
2779
+ return result;
2489
2780
  }
2490
2781
  });
2491
2782
  };
@@ -2858,7 +3149,7 @@ var NativeDocument = (function (exports) {
2858
3149
 
2859
3150
  ObservableItem.call(this, target, configs);
2860
3151
  {
2861
- PluginsManager.emit('CreateObservableArray', this);
3152
+ PluginsManager$1.emit('CreateObservableArray', this);
2862
3153
  }
2863
3154
  };
2864
3155
 
@@ -2887,6 +3178,14 @@ var NativeDocument = (function (exports) {
2887
3178
  };
2888
3179
  });
2889
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
+ */
2890
3189
  ObservableArray.prototype.clear = function() {
2891
3190
  if(this.$currentValue.length === 0) {
2892
3191
  return;
@@ -2896,19 +3195,42 @@ var NativeDocument = (function (exports) {
2896
3195
  return true;
2897
3196
  };
2898
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
+ */
2899
3207
  ObservableArray.prototype.at = function(index) {
2900
3208
  return this.$currentValue[index];
2901
3209
  };
2902
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
+ */
2903
3221
  ObservableArray.prototype.merge = function(values) {
2904
3222
  this.$currentValue.push.apply(this.$currentValue, values);
2905
3223
  this.trigger({ action: 'merge', args: values });
2906
3224
  };
2907
3225
 
2908
3226
  /**
3227
+ * Counts the number of elements that satisfy the provided condition.
2909
3228
  *
2910
- * @param {Function} condition
2911
- * @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
2912
3234
  */
2913
3235
  ObservableArray.prototype.count = function(condition) {
2914
3236
  let count = 0;
@@ -2920,6 +3242,16 @@ var NativeDocument = (function (exports) {
2920
3242
  return count;
2921
3243
  };
2922
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
+ */
2923
3255
  ObservableArray.prototype.swap = function(indexA, indexB) {
2924
3256
  const value = this.$currentValue;
2925
3257
  const length = value.length;
@@ -2940,6 +3272,15 @@ var NativeDocument = (function (exports) {
2940
3272
  return true;
2941
3273
  };
2942
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
+ */
2943
3284
  ObservableArray.prototype.remove = function(index) {
2944
3285
  const deleted = this.$currentValue.splice(index, 1);
2945
3286
  if(deleted.length === 0) {
@@ -2949,20 +3290,60 @@ var NativeDocument = (function (exports) {
2949
3290
  return deleted;
2950
3291
  };
2951
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
+ */
2952
3302
  ObservableArray.prototype.removeItem = function(item) {
2953
3303
  const indexOfItem = this.$currentValue.indexOf(item);
3304
+ if(indexOfItem === -1) {
3305
+ return [];
3306
+ }
2954
3307
  return this.remove(indexOfItem);
2955
3308
  };
2956
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
+ */
2957
3318
  ObservableArray.prototype.isEmpty = function() {
2958
3319
  return this.$currentValue.length === 0;
2959
3320
  };
2960
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
+ */
2961
3329
  ObservableArray.prototype.populateAndRender = function(iteration, callback) {
2962
3330
  this.trigger({ action: 'populate', args: [this.$currentValue, iteration, callback] });
2963
3331
  };
2964
3332
 
2965
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
+ */
2966
3347
  ObservableArray.prototype.where = function(predicates) {
2967
3348
  const sourceArray = this;
2968
3349
  const observableDependencies = [sourceArray];
@@ -3011,6 +3392,20 @@ var NativeDocument = (function (exports) {
3011
3392
  return viewArray;
3012
3393
  };
3013
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
+ */
3014
3409
  ObservableArray.prototype.whereSome = function(fields, filter) {
3015
3410
  return this.where({
3016
3411
  _: {
@@ -3020,6 +3415,20 @@ var NativeDocument = (function (exports) {
3020
3415
  });
3021
3416
  };
3022
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
+ */
3023
3432
  ObservableArray.prototype.whereEvery = function(fields, filter) {
3024
3433
  return this.where({
3025
3434
  _: {
@@ -3030,10 +3439,19 @@ var NativeDocument = (function (exports) {
3030
3439
  };
3031
3440
 
3032
3441
  /**
3442
+ * Creates an observable array with reactive array methods.
3443
+ * All mutations trigger updates automatically.
3033
3444
  *
3034
- * @param {Array} target
3035
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
3036
- * @returns {ObservableArray}
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));
3037
3455
  */
3038
3456
  Observable.array = function(target = [], configs = null) {
3039
3457
  return new ObservableArray(target, configs);
@@ -3098,10 +3516,26 @@ var NativeDocument = (function (exports) {
3098
3516
  };
3099
3517
 
3100
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.
3101
3521
  *
3102
- * @param {Object} initialValue
3103
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
3104
- * @returns {Proxy}
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));
3105
3539
  */
3106
3540
  Observable.init = function(initialValue, configs = null) {
3107
3541
  const data = {};
@@ -3249,17 +3683,30 @@ var NativeDocument = (function (exports) {
3249
3683
  Observable.json = Observable.init;
3250
3684
 
3251
3685
  /**
3686
+ * Creates a computed observable that automatically updates when its dependencies change.
3687
+ * The callback is re-executed whenever any dependency observable changes.
3252
3688
  *
3253
- * @param {Function} callback
3254
- * @param {Array|Function} dependencies
3255
- * @returns {ObservableItem}
3256
- */
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
+ */
3257
3704
  Observable.computed = function(callback, dependencies = []) {
3258
3705
  const initialValue = callback();
3259
3706
  const observable = new ObservableItem(initialValue);
3260
3707
  const updatedValue = nextTick(() => observable.set(callback()));
3261
3708
  {
3262
- PluginsManager.emit('CreateObservableComputed', observable, dependencies);
3709
+ PluginsManager$1.emit('CreateObservableComputed', observable, dependencies);
3263
3710
  }
3264
3711
 
3265
3712
  if(Validator.isFunction(dependencies)) {
@@ -3357,12 +3804,24 @@ var NativeDocument = (function (exports) {
3357
3804
  }());
3358
3805
 
3359
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.
3360
3809
  *
3361
- * @param {Array|Object|ObservableItem} data
3362
- * @param {Function} callback
3363
- * @param {?Function|?string} key
3364
- * @param {{shouldKeepItemsInCache: boolean}?} configs
3365
- * @returns {DocumentFragment}
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);
3366
3825
  */
3367
3826
  function ForEach(data, callback, key, { shouldKeepItemsInCache = false } = {}) {
3368
3827
  const element = Anchor('ForEach');
@@ -3419,7 +3878,7 @@ var NativeDocument = (function (exports) {
3419
3878
  }
3420
3879
  cache.set(keyId, { keyId, isNew: true, child: new WeakRef(child), indexObserver});
3421
3880
  } catch (e) {
3422
- DebugManager.error('ForEach', `Error creating element for key ${keyId}` , e);
3881
+ DebugManager$1.error('ForEach', `Error creating element for key ${keyId}` , e);
3423
3882
  throw e;
3424
3883
  }
3425
3884
  return keyId;
@@ -3501,8 +3960,26 @@ var NativeDocument = (function (exports) {
3501
3960
  return element;
3502
3961
  }
3503
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
+ */
3504
3981
  function ForEachArray(data, callback, configs = {}) {
3505
- const element = Anchor('ForEach Array');
3982
+ const element = Anchor('ForEach Array', configs.isParentUniqueChild);
3506
3983
  const blockEnd = element.endElement();
3507
3984
  const blockStart = element.startElement();
3508
3985
 
@@ -3677,7 +4154,7 @@ var NativeDocument = (function (exports) {
3677
4154
  elementBeforeFirst = firstChildRemoved?.previousSibling;
3678
4155
 
3679
4156
  for(let i = 0; i < deleted.length; i++) {
3680
- firstItem(deleted[i], garbageFragment);
4157
+ removeByItem(deleted[i], garbageFragment);
3681
4158
  }
3682
4159
  }
3683
4160
  } else {
@@ -3723,7 +4200,7 @@ var NativeDocument = (function (exports) {
3723
4200
  };
3724
4201
 
3725
4202
  const buildContent = (items, _, operations) => {
3726
- if(operations.action === 'clear' || !items.length) {
4203
+ if(operations?.action === 'clear' || !items.length) {
3727
4204
  if(lastNumberOfItems === 0) {
3728
4205
  return;
3729
4206
  }
@@ -3756,16 +4233,22 @@ var NativeDocument = (function (exports) {
3756
4233
  }
3757
4234
 
3758
4235
  /**
3759
- * Show the element if the condition is true
4236
+ * Conditionally shows an element based on an observable condition.
4237
+ * The element is mounted/unmounted from the DOM as the condition changes.
3760
4238
  *
3761
- * @param {ObservableItem|ObservableChecker} condition
3762
- * @param {*} child
3763
- * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
3764
- * @returns {DocumentFragment}
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'));
3765
4248
  */
3766
4249
  const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
3767
4250
  if(!(Validator.isObservable(condition)) && !Validator.isObservableWhenResult(condition)) {
3768
- 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);
3769
4252
  }
3770
4253
  const element = Anchor('Show if : '+(comment || ''));
3771
4254
 
@@ -3798,11 +4281,18 @@ var NativeDocument = (function (exports) {
3798
4281
  };
3799
4282
 
3800
4283
  /**
3801
- * Hide the element if the condition is true
3802
- * @param {ObservableItem|ObservableChecker} condition
3803
- * @param child
3804
- * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
3805
- * @returns {DocumentFragment}
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'));
3806
4296
  */
3807
4297
  const HideIf = function(condition, child, configs) {
3808
4298
  const hideCondition = Observable(!condition.val());
@@ -3812,17 +4302,43 @@ var NativeDocument = (function (exports) {
3812
4302
  };
3813
4303
 
3814
4304
  /**
3815
- * Hide the element if the condition is false
4305
+ * Conditionally hides an element when the observable condition is false.
4306
+ * Same as ShowIf - element is shown when condition is true.
3816
4307
  *
3817
- * @param {ObservableItem|ObservableChecker} condition
3818
- * @param {*} child
3819
- * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
3820
- * @returns {DocumentFragment}
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
3821
4314
  */
3822
4315
  const HideIfNot = function(condition, child, configs) {
3823
4316
  return ShowIf(condition, child, configs);
3824
4317
  };
3825
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
+ */
3826
4342
  const ShowWhen = function() {
3827
4343
  if(arguments.length === 2) {
3828
4344
  const [observer, target] = arguments;
@@ -3852,11 +4368,24 @@ var NativeDocument = (function (exports) {
3852
4368
  };
3853
4369
 
3854
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.
3855
4373
  *
3856
- * @param {ObservableItem|ObservableChecker} $condition
3857
- * @param {{[key]: *}} values
3858
- * @param {Boolean} shouldKeepInCache
3859
- * @returns {DocumentFragment}
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');
3860
4389
  */
3861
4390
  const Match = function($condition, values, shouldKeepInCache = true) {
3862
4391
 
@@ -3913,11 +4442,19 @@ var NativeDocument = (function (exports) {
3913
4442
 
3914
4443
 
3915
4444
  /**
4445
+ * Displays one of two views based on a boolean observable condition.
4446
+ * Simplified version of Match for true/false cases.
3916
4447
  *
3917
- * @param {ObservableItem|ObservableChecker} $condition
3918
- * @param {*} onTrue
3919
- * @param {*} onFalse
3920
- * @returns {DocumentFragment}
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
+ * );
3921
4458
  */
3922
4459
  const Switch = function ($condition, onTrue, onFalse) {
3923
4460
  if(!Validator.isObservable($condition)) {
@@ -3931,9 +4468,15 @@ var NativeDocument = (function (exports) {
3931
4468
  };
3932
4469
 
3933
4470
  /**
4471
+ * Provides a fluent API for conditional rendering with show/otherwise pattern.
3934
4472
  *
3935
- * @param {ObservableItem|ObservableChecker} $condition
3936
- * @returns {{show: Function, otherwise: (((*) => {}):DocumentFragment)}
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());
3937
4480
  */
3938
4481
  const When = function($condition) {
3939
4482
  if(!Validator.isObservable($condition)) {
@@ -3951,6 +4494,9 @@ var NativeDocument = (function (exports) {
3951
4494
  otherwise(onFalse) {
3952
4495
  $onFalse = onFalse;
3953
4496
  return Switch($condition, $onTrue, $onFalse);
4497
+ },
4498
+ toNdElement() {
4499
+ return Switch($condition, $onTrue, $onFalse);
3954
4500
  }
3955
4501
  }
3956
4502
  };
@@ -4290,11 +4836,16 @@ var NativeDocument = (function (exports) {
4290
4836
  };
4291
4837
 
4292
4838
  /**
4839
+ * Creates a new Route instance.
4293
4840
  *
4294
- * @param {string} $path
4295
- * @param {Function} $component
4296
- * @param {{name:?string, middlewares:Function[], shouldRebuild:Boolean, with: Object }}$options
4297
- * @class
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
4298
4849
  */
4299
4850
  function Route($path, $component, $options = {}) {
4300
4851
 
@@ -4393,7 +4944,6 @@ var NativeDocument = (function (exports) {
4393
4944
  super(message);
4394
4945
  this.context = context;
4395
4946
  }
4396
-
4397
4947
  }
4398
4948
 
4399
4949
  const RouteGroupHelper = {
@@ -4552,7 +5102,7 @@ var NativeDocument = (function (exports) {
4552
5102
  window.history.pushState({ name: route.name(), params, path}, route.name() || path , path);
4553
5103
  this.handleRouteChange(route, params, query, path);
4554
5104
  } catch (e) {
4555
- DebugManager.error('HistoryRouter', 'Error in pushState', e);
5105
+ DebugManager$1.error('HistoryRouter', 'Error in pushState', e);
4556
5106
  }
4557
5107
  };
4558
5108
  /**
@@ -4565,7 +5115,7 @@ var NativeDocument = (function (exports) {
4565
5115
  window.history.replaceState({ name: route.name(), params, path}, route.name() || path , path);
4566
5116
  this.handleRouteChange(route, params, {}, path);
4567
5117
  } catch(e) {
4568
- DebugManager.error('HistoryRouter', 'Error in replaceState', e);
5118
+ DebugManager$1.error('HistoryRouter', 'Error in replaceState', e);
4569
5119
  }
4570
5120
  };
4571
5121
  this.forward = function() {
@@ -4592,7 +5142,7 @@ var NativeDocument = (function (exports) {
4592
5142
  }
4593
5143
  this.handleRouteChange(route, params, query, path);
4594
5144
  } catch(e) {
4595
- DebugManager.error('HistoryRouter', 'Error in popstate event', e);
5145
+ DebugManager$1.error('HistoryRouter', 'Error in popstate event', e);
4596
5146
  }
4597
5147
  });
4598
5148
  const { route, params, query, path } = this.resolve(defaultPath || (window.location.pathname+window.location.search));
@@ -4789,7 +5339,7 @@ var NativeDocument = (function (exports) {
4789
5339
  /**
4790
5340
  *
4791
5341
  * @param {{mode: 'memory'|'history'|'hash'}} $options
4792
- * @constructor
5342
+ * @class
4793
5343
  */
4794
5344
  function Router($options = {}) {
4795
5345
 
@@ -4817,7 +5367,7 @@ var NativeDocument = (function (exports) {
4817
5367
  listener(request);
4818
5368
  next && next(request);
4819
5369
  } catch (e) {
4820
- DebugManager.warn('Route Listener', 'Error in listener:', e);
5370
+ DebugManager$1.warn('Route Listener', 'Error in listener:', e);
4821
5371
  }
4822
5372
  }
4823
5373
  };
@@ -4847,11 +5397,20 @@ var NativeDocument = (function (exports) {
4847
5397
  };
4848
5398
 
4849
5399
  /**
5400
+ * Groups routes under a common path prefix with shared options.
4850
5401
  *
4851
- * @param {string} suffix
4852
- * @param {{ middlewares: Function[], name: string}} options
4853
- * @param {Function} callback
4854
- * @returns {this}
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
+ * });
4855
5414
  */
4856
5415
  this.group = function(suffix, options, callback) {
4857
5416
  if(!Validator.isFunction(callback)) {
@@ -4969,14 +5528,24 @@ var NativeDocument = (function (exports) {
4969
5528
  Router.routers = {};
4970
5529
 
4971
5530
  /**
5531
+ * Creates and initializes a new router instance.
4972
5532
  *
4973
- * @param {{mode: 'memory'|'history'|'hash', name?:string, entry?: string}} options
4974
- * @param {Function} callback
4975
- * @param {Element} container
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');
4976
5545
  */
4977
5546
  Router.create = function(options, callback) {
4978
5547
  if(!Validator.isFunction(callback)) {
4979
- DebugManager.error('Router', 'Callback must be a function', e);
5548
+ DebugManager$1.error('Router', 'Callback must be a function');
4980
5549
  throw new RouterError('Callback must be a function');
4981
5550
  }
4982
5551
  const router = new Router(options);
@@ -5143,16 +5712,22 @@ var NativeDocument = (function (exports) {
5143
5712
  };
5144
5713
  }
5145
5714
 
5146
- const Service = {
5147
- once: fn => autoOnce(fn),
5148
- memoize: fn => autoMemoize(fn)
5149
- };
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
+ });
5150
5725
 
5151
5726
  var utils = /*#__PURE__*/Object.freeze({
5152
5727
  __proto__: null,
5153
- Filters: index,
5728
+ Cache: cache,
5154
5729
  NativeFetch: NativeFetch,
5155
- Service: Service
5730
+ filters: index
5156
5731
  });
5157
5732
 
5158
5733
  exports.$ = $;
@@ -5160,7 +5735,7 @@ var NativeDocument = (function (exports) {
5160
5735
  exports.HtmlElementWrapper = HtmlElementWrapper;
5161
5736
  exports.NDElement = NDElement;
5162
5737
  exports.Observable = Observable;
5163
- exports.PluginsManager = PluginsManager;
5738
+ exports.PluginsManager = PluginsManager$1;
5164
5739
  exports.SingletonView = SingletonView;
5165
5740
  exports.Store = Store;
5166
5741
  exports.TemplateCloner = TemplateCloner;
@@ -5171,10 +5746,10 @@ var NativeDocument = (function (exports) {
5171
5746
  exports.createTextNode = createTextNode;
5172
5747
  exports.cssPropertyAccumulator = cssPropertyAccumulator;
5173
5748
  exports.elements = elements;
5174
- exports.memoize = memoize;
5749
+ exports.memoize = memoize$1;
5175
5750
  exports.normalizeComponentArgs = normalizeComponentArgs;
5176
5751
  exports.obs = obs;
5177
- exports.once = once;
5752
+ exports.once = once$1;
5178
5753
  exports.router = router;
5179
5754
  exports.useCache = useCache;
5180
5755
  exports.useSingleton = useSingleton;