native-document 1.0.251 → 1.0.253

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.251",
3
+ "version": "1.0.253",
4
4
  "description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
5
5
  "author": "AfroCodeur <https://github.com/afrocodeur>",
6
6
  "license": "MIT",
@@ -525,19 +525,23 @@ ObservableArray.prototype.isNotEmpty = function () {
525
525
  };
526
526
 
527
527
  ObservableArray.prototype.fnPush = function (item) {
528
- return this.push(item);
528
+ const self = this;
529
+ return () => self.push(item);
529
530
  };
530
531
 
531
532
  ObservableArray.prototype.fnRemove = function (item) {
532
- return () => this.removeItem(item);
533
+ const self = this;
534
+ return () => self.removeItem(item);
533
535
  };
534
536
 
535
537
  ObservableArray.prototype.fnRemoveAt = function (index) {
536
- return () => this.remove(index);
538
+ const self = this;
539
+ return () => self.remove(index);
537
540
  };
538
541
 
539
542
  ObservableArray.prototype.fnClear = function () {
540
- return () => this.clear();
543
+ const self = this;
544
+ return () => self.clear();
541
545
  };
542
546
 
543
547
  ObservableArray.prototype.rawValue = function () {
@@ -678,23 +678,82 @@ ObservableItem.prototype.sync = function(targetObservable) {
678
678
  };
679
679
  };
680
680
 
681
+ /**
682
+ * Subscribes to the observable and re-runs the callback whenever the value changes.
683
+ * The callback can mutate $currentValue directly or return a new value to set.
684
+ * A lock prevents re-entrant calls caused by mutations inside the callback.
685
+ *
686
+ * @param {(current: *, operations: *) => *|void} fn - Callback receiving the current value and
687
+ * the triggering operation. If a value is returned, it is applied via .set().
688
+ * If nothing is returned, no set is performed.
689
+ * @param {boolean} [autoCall=true] - If true, the callback is called immediately upon registration.
690
+ * @returns {this}
691
+ *
692
+ * @example
693
+ * // Mutate directly
694
+ * $items.watch((current) => {
695
+ * if(!current.find(i => i.day === 'mon')) {
696
+ * current.push({ day: 'mon', enabled: false });
697
+ * }
698
+ * });
699
+ *
700
+ * @example
701
+ * // Return a new value
702
+ * $items.watch((current) => {
703
+ * return DAYS.map(day =>
704
+ * current.find(i => i.day === day) ?? { day, enabled: false }
705
+ * );
706
+ * });
707
+ *
708
+ * @example
709
+ * // Disable auto-call
710
+ * $items.watch((current) => { ... }, false);
711
+ */
712
+ ObservableItem.prototype.watch = function(fn, autoCall = true) {
713
+ let locked = false;
714
+
715
+ const handler = (value, prev, operations) => {
716
+ if(locked) return;
717
+ locked = true;
718
+ try {
719
+ const result = fn(this.$currentValue, operations);
720
+ if(result !== undefined) {
721
+ this.set(result);
722
+ }
723
+ }
724
+ finally {
725
+ locked = false;
726
+ }
727
+ };
728
+
729
+ this.subscribe(handler);
730
+ autoCall && handler(this.$currentValue, null, null);
731
+
732
+ return this;
733
+ };
734
+
681
735
 
682
736
  ObservableItem.prototype.fnSet = function(value) {
683
- return () => this.set(value);
737
+ const self = this;
738
+ return () => self.set(value);
684
739
  };
685
740
 
686
741
  ObservableItem.prototype.fnToggle = function() {
687
- return () => this.toggle();
742
+ const self = this;
743
+ return () => self.toggle();
688
744
  };
689
745
 
690
746
  ObservableItem.prototype.fnSetTrue = function() {
691
- return () => this.set(true);
747
+ const self = this;
748
+ return () => self.set(true);
692
749
  };
693
750
 
694
751
  ObservableItem.prototype.fnSetFalse = function() {
695
- return () => this.set(false);
752
+ const self = this;
753
+ return () => self.set(false);
696
754
  };
697
755
 
698
756
  ObservableItem.prototype.fnReset = function() {
699
- return () => this.reset();
757
+ const self = this;
758
+ return () => self.reset();
700
759
  };
@@ -271,7 +271,8 @@ export const StoreFactory = function() {
271
271
  */
272
272
  follow(name) {
273
273
  const { observer: originalObserver, subscribers } = $getStoreOrThrow('follow', name);
274
- const observerFollower = $createObservable(originalObserver.val());
274
+ const value = originalObserver.val();
275
+ const observerFollower = $createObservable(Array.isArray(value) ? [...value] : value);
275
276
 
276
277
  const onStoreChange = $synchroProtectedFollower(originalObserver, observerFollower, name,'follow');
277
278
 
@@ -90,6 +90,8 @@ export interface ObservableItem<T = any> {
90
90
  get(key: string | number): any;
91
91
  when(value: T): ObservableWhen<T>;
92
92
 
93
+ watch(fn: (current: this['$currentValue'], operations: ObservableOperation | null) => typeof this['$currentValue'] | void, autoCall?: boolean): this;
94
+
93
95
  persist(key: string, options?: {
94
96
  get?: (value: any) => T;
95
97
  set?: (value: T) => any;