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.
Files changed (68) hide show
  1. package/dist/native-document.components.min.js +1088 -65
  2. package/dist/native-document.dev.js +695 -142
  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 +124 -4
  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 +20 -2
  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
@@ -51,6 +51,14 @@ noMutationMethods.forEach((method) => {
51
51
  };
52
52
  });
53
53
 
54
+ /**
55
+ * Removes all items from the array and triggers an update.
56
+ *
57
+ * @returns {boolean} True if array was cleared, false if it was already empty
58
+ * @example
59
+ * const items = Observable.array([1, 2, 3]);
60
+ * items.clear(); // []
61
+ */
54
62
  ObservableArray.prototype.clear = function() {
55
63
  if(this.$currentValue.length === 0) {
56
64
  return;
@@ -60,19 +68,42 @@ ObservableArray.prototype.clear = function() {
60
68
  return true;
61
69
  };
62
70
 
71
+ /**
72
+ * Returns the element at the specified index in the array.
73
+ *
74
+ * @param {number} index - Zero-based index of the element to retrieve
75
+ * @returns {*} The element at the specified index
76
+ * @example
77
+ * const items = Observable.array(['a', 'b', 'c']);
78
+ * items.at(1); // 'b'
79
+ */
63
80
  ObservableArray.prototype.at = function(index) {
64
81
  return this.$currentValue[index];
65
82
  };
66
83
 
84
+
85
+ /**
86
+ * Merges multiple values into the array and triggers an update.
87
+ * Similar to push but with a different operation name.
88
+ *
89
+ * @param {Array} values - Array of values to merge
90
+ * @example
91
+ * const items = Observable.array([1, 2]);
92
+ * items.merge([3, 4]); // [1, 2, 3, 4]
93
+ */
67
94
  ObservableArray.prototype.merge = function(values) {
68
95
  this.$currentValue.push.apply(this.$currentValue, values);
69
96
  this.trigger({ action: 'merge', args: values });
70
97
  };
71
98
 
72
99
  /**
100
+ * Counts the number of elements that satisfy the provided condition.
73
101
  *
74
- * @param {Function} condition
75
- * @returns {number}
102
+ * @param {(value: *, index: number) => Boolean} condition - Function that tests each element (item, index) => boolean
103
+ * @returns {number} The count of elements that satisfy the condition
104
+ * @example
105
+ * const numbers = Observable.array([1, 2, 3, 4, 5]);
106
+ * numbers.count(n => n > 3); // 2
76
107
  */
77
108
  ObservableArray.prototype.count = function(condition) {
78
109
  let count = 0;
@@ -84,6 +115,16 @@ ObservableArray.prototype.count = function(condition) {
84
115
  return count;
85
116
  };
86
117
 
118
+ /**
119
+ * Swaps two elements at the specified indices and triggers an update.
120
+ *
121
+ * @param {number} indexA - Index of the first element
122
+ * @param {number} indexB - Index of the second element
123
+ * @returns {boolean} True if swap was successful, false if indices are out of bounds
124
+ * @example
125
+ * const items = Observable.array(['a', 'b', 'c']);
126
+ * items.swap(0, 2); // ['c', 'b', 'a']
127
+ */
87
128
  ObservableArray.prototype.swap = function(indexA, indexB) {
88
129
  const value = this.$currentValue;
89
130
  const length = value.length;
@@ -104,6 +145,15 @@ ObservableArray.prototype.swap = function(indexA, indexB) {
104
145
  return true;
105
146
  };
106
147
 
148
+ /**
149
+ * Removes the element at the specified index and triggers an update.
150
+ *
151
+ * @param {number} index - Index of the element to remove
152
+ * @returns {Array} Array containing the removed element, or empty array if index is invalid
153
+ * @example
154
+ * const items = Observable.array(['a', 'b', 'c']);
155
+ * items.remove(1); // ['b'] - Array is now ['a', 'c']
156
+ */
107
157
  ObservableArray.prototype.remove = function(index) {
108
158
  const deleted = this.$currentValue.splice(index, 1);
109
159
  if(deleted.length === 0) {
@@ -113,20 +163,60 @@ ObservableArray.prototype.remove = function(index) {
113
163
  return deleted;
114
164
  };
115
165
 
166
+ /**
167
+ * Removes the first occurrence of the specified item from the array.
168
+ *
169
+ * @param {*} item - The item to remove
170
+ * @returns {Array} Array containing the removed element, or empty array if item not found
171
+ * @example
172
+ * const items = Observable.array(['a', 'b', 'c']);
173
+ * items.removeItem('b'); // ['b'] - Array is now ['a', 'c']
174
+ */
116
175
  ObservableArray.prototype.removeItem = function(item) {
117
176
  const indexOfItem = this.$currentValue.indexOf(item);
177
+ if(indexOfItem === -1) {
178
+ return [];
179
+ }
118
180
  return this.remove(indexOfItem);
119
181
  };
120
182
 
183
+ /**
184
+ * Checks if the array is empty.
185
+ *
186
+ * @returns {boolean} True if array has no elements
187
+ * @example
188
+ * const items = Observable.array([]);
189
+ * items.isEmpty(); // true
190
+ */
121
191
  ObservableArray.prototype.isEmpty = function() {
122
192
  return this.$currentValue.length === 0;
123
193
  };
124
194
 
195
+ /**
196
+ * Triggers a populate operation with the current array, iteration count, and callback.
197
+ * Used internally for rendering optimizations.
198
+ *
199
+ * @param {number} iteration - Iteration count for rendering
200
+ * @param {Function} callback - Callback function for rendering items
201
+ */
125
202
  ObservableArray.prototype.populateAndRender = function(iteration, callback) {
126
203
  this.trigger({ action: 'populate', args: [this.$currentValue, iteration, callback] });
127
204
  };
128
205
 
129
206
 
207
+ /**
208
+ * Creates a filtered view of the array based on predicates.
209
+ * The filtered array updates automatically when source data or predicates change.
210
+ *
211
+ * @param {Object} predicates - Object mapping property names to filter conditions or functions
212
+ * @returns {ObservableArray} A new observable array containing filtered items
213
+ * @example
214
+ * const users = Observable.array([
215
+ * { name: 'John', age: 25 },
216
+ * { name: 'Jane', age: 30 }
217
+ * ]);
218
+ * const adults = users.where({ age: (val) => val >= 18 });
219
+ */
130
220
  ObservableArray.prototype.where = function(predicates) {
131
221
  const sourceArray = this;
132
222
  const observableDependencies = [sourceArray];
@@ -175,6 +265,20 @@ ObservableArray.prototype.where = function(predicates) {
175
265
  return viewArray;
176
266
  };
177
267
 
268
+ /**
269
+ * Creates a filtered view where at least one of the specified fields matches the filter.
270
+ *
271
+ * @param {Array<string>} fields - Array of field names to check
272
+ * @param {FilterResult} filter - Filter condition with callback and dependencies
273
+ * @returns {ObservableArray} A new observable array containing filtered items
274
+ * @example
275
+ * const products = Observable.array([
276
+ * { name: 'Apple', category: 'Fruit' },
277
+ * { name: 'Carrot', category: 'Vegetable' }
278
+ * ]);
279
+ * const searchTerm = Observable('App');
280
+ * const filtered = products.whereSome(['name', 'category'], match(searchTerm));
281
+ */
178
282
  ObservableArray.prototype.whereSome = function(fields, filter) {
179
283
  return this.where({
180
284
  _: {
@@ -184,6 +288,20 @@ ObservableArray.prototype.whereSome = function(fields, filter) {
184
288
  });
185
289
  };
186
290
 
291
+ /**
292
+ * Creates a filtered view where all specified fields match the filter.
293
+ *
294
+ * @param {Array<string>} fields - Array of field names to check
295
+ * @param {FilterResult} filter - Filter condition with callback and dependencies
296
+ * @returns {ObservableArray} A new observable array containing filtered items
297
+ * @example
298
+ * const items = Observable.array([
299
+ * { status: 'active', verified: true },
300
+ * { status: 'active', verified: false }
301
+ * ]);
302
+ * const activeFilter = equals('active');
303
+ * const filtered = items.whereEvery(['status', 'verified'], activeFilter);
304
+ */
187
305
  ObservableArray.prototype.whereEvery = function(fields, filter) {
188
306
  return this.where({
189
307
  _: {
@@ -12,6 +12,16 @@ export default function ObservableChecker($observable, $checker) {
12
12
 
13
13
  ObservableChecker.prototype.__$isObservableChecker = true;
14
14
 
15
+ /**
16
+ * Subscribes to changes in the checked/transformed value.
17
+ *
18
+ * @param {Function} callback - Function called with the transformed value when observable changes
19
+ * @returns {Function} Unsubscribe function
20
+ * @example
21
+ * const count = Observable(5);
22
+ * const doubled = count.check(n => n * 2);
23
+ * doubled.subscribe(value => console.log(value)); // Logs: 10
24
+ */
15
25
  ObservableChecker.prototype.subscribe = function(callback) {
16
26
  const unSubscribe = this.observable.subscribe((value) => {
17
27
  callback && callback(this.checker(value));
@@ -20,22 +30,62 @@ ObservableChecker.prototype.subscribe = function(callback) {
20
30
  return unSubscribe;
21
31
  };
22
32
 
33
+ /**
34
+ * Creates a new ObservableChecker by applying another transformation.
35
+ * Allows chaining transformations.
36
+ *
37
+ * @param {(value: *) => *} callback - Transformation function to apply to the current checked value
38
+ * @returns {ObservableChecker} New ObservableChecker with chained transformation
39
+ * @example
40
+ * const count = Observable(5);
41
+ * const result = count.check(n => n * 2).check(n => n + 1);
42
+ * result.val(); // 11
43
+ */
23
44
  ObservableChecker.prototype.check = function(callback) {
24
45
  return this.observable.check(() => callback(this.val()));
25
46
  }
26
47
 
48
+ /**
49
+ * Gets the current transformed/checked value.
50
+ *
51
+ * @returns {*} The result of applying the checker function to the observable's current value
52
+ * @example
53
+ * const count = Observable(5);
54
+ * const doubled = count.check(n => n * 2);
55
+ * doubled.val(); // 10
56
+ */
27
57
  ObservableChecker.prototype.val = function() {
28
58
  return this.checker && this.checker(this.observable.val());
29
59
  }
30
60
 
61
+ /**
62
+ * Sets the value of the underlying observable (not the transformed value).
63
+ *
64
+ * @param {*} value - New value for the underlying observable
65
+ * @example
66
+ * const count = Observable(5);
67
+ * const doubled = count.check(n => n * 2);
68
+ * doubled.set(10); // Sets count to 10, doubled.val() returns 20
69
+ */
31
70
  ObservableChecker.prototype.set = function(value) {
32
71
  return this.observable.set(value);
33
72
  };
34
73
 
74
+ /**
75
+ * Manually triggers the underlying observable to notify subscribers.
76
+ *
77
+ * @example
78
+ * const count = Observable(5);
79
+ * const doubled = count.check(n => n * 2);
80
+ * doubled.trigger(); // Notifies all subscribers
81
+ */
35
82
  ObservableChecker.prototype.trigger = function() {
36
83
  return this.observable.trigger();
37
84
  };
38
85
 
86
+ /**
87
+ * Cleans up the underlying observable and all its subscriptions.
88
+ */
39
89
  ObservableChecker.prototype.cleanup = function() {
40
90
  return this.observable.cleanup();
41
91
  };
@@ -53,6 +53,16 @@ ObservableItem.prototype.__$isObservable = true;
53
53
  const DEFAULT_OPERATIONS = {};
54
54
  const noneTrigger = function() {};
55
55
 
56
+ /**
57
+ * Intercepts and transforms values before they are set on the observable.
58
+ * The interceptor can modify the value or return undefined to use the original value.
59
+ *
60
+ * @param {(value) => any} callback - Interceptor function that receives (newValue, currentValue) and returns the transformed value or undefined
61
+ * @returns {ObservableItem} The observable instance for chaining
62
+ * @example
63
+ * const count = Observable(0);
64
+ * count.intercept((newVal, oldVal) => Math.max(0, newVal)); // Prevent negative values
65
+ */
56
66
  ObservableItem.prototype.intercept = function(callback) {
57
67
  this.$interceptor = callback;
58
68
  this.set = this.$setWithInterceptor;
@@ -184,6 +194,16 @@ ObservableItem.prototype.disconnectAll = function() {
184
194
  this.trigger = noneTrigger;
185
195
  };
186
196
 
197
+ /**
198
+ * Registers a cleanup callback that will be executed when the observable is cleaned up.
199
+ * Useful for disposing resources, removing event listeners, or other cleanup tasks.
200
+ *
201
+ * @param {Function} callback - Cleanup function to execute on observable disposal
202
+ * @example
203
+ * const obs = Observable(0);
204
+ * obs.onCleanup(() => console.log('Cleaned up!'));
205
+ * obs.cleanup(); // Logs: "Cleaned up!"
206
+ */
187
207
  ObservableItem.prototype.onCleanup = function(callback) {
188
208
  this.$cleanupListeners = this.$cleanupListeners ?? [];
189
209
  this.$cleanupListeners.push(callback);
@@ -228,6 +248,17 @@ ObservableItem.prototype.subscribe = function(callback) {
228
248
  }
229
249
  };
230
250
 
251
+ /**
252
+ * Watches for a specific value and executes callback when the observable equals that value.
253
+ * Creates a watcher that only triggers when the observable changes to the specified value.
254
+ *
255
+ * @param {*} value - The value to watch for
256
+ * @param {(value) => void|ObservableItem} callback - Callback function or observable to set when value matches
257
+ * @example
258
+ * const status = Observable('idle');
259
+ * status.on('loading', () => console.log('Started loading'));
260
+ * status.on('error', isError); // Set another observable
261
+ */
231
262
  ObservableItem.prototype.on = function(value, callback) {
232
263
  this.$watchers = this.$watchers ?? new Map();
233
264
 
@@ -257,8 +288,16 @@ ObservableItem.prototype.on = function(value, callback) {
257
288
  };
258
289
 
259
290
  /**
260
- * @param {*} value
261
- * @param {Function} callback - if omitted, removes all watchers for this value
291
+ * Removes a watcher for a specific value. If no callback is provided, removes all watchers for that value.
292
+ *
293
+ * @param {*} value - The value to stop watching
294
+ * @param {Function} [callback] - Specific callback to remove. If omitted, removes all watchers for this value
295
+ * @example
296
+ * const status = Observable('idle');
297
+ * const handler = () => console.log('Loading');
298
+ * status.on('loading', handler);
299
+ * status.off('loading', handler); // Remove specific handler
300
+ * status.off('loading'); // Remove all handlers for 'loading'
262
301
  */
263
302
  ObservableItem.prototype.off = function(value, callback) {
264
303
  if(!this.$watchers) return;
@@ -278,11 +317,20 @@ ObservableItem.prototype.off = function(value, callback) {
278
317
  }
279
318
  else if(watchValueList.length === 0) {
280
319
  this.$watchers?.delete(value);
281
- watchValueList = null;
282
320
  }
283
321
  this.assocTrigger();
284
322
  };
285
323
 
324
+ /**
325
+ * Subscribes to the observable but automatically unsubscribes after the first time the predicate matches.
326
+ *
327
+ * @param {(value) => Boolean|any} predicate - Value to match or function that returns true when condition is met
328
+ * @param {(value) => void} callback - Callback to execute when predicate matches, receives the matched value
329
+ * @example
330
+ * const status = Observable('loading');
331
+ * status.once('ready', (val) => console.log('Ready!'));
332
+ * status.once(val => val === 'error', (val) => console.log('Error occurred'));
333
+ */
286
334
  ObservableItem.prototype.once = function(predicate, callback) {
287
335
  const fn = typeof predicate === 'function' ? predicate : (v) => v === predicate;
288
336
 
@@ -320,15 +368,50 @@ ObservableItem.prototype.check = function(callback) {
320
368
  return new ObservableChecker(this, callback)
321
369
  };
322
370
 
371
+ /**
372
+ * Gets a property value from the observable's current value.
373
+ * If the property is an observable, returns its value.
374
+ *
375
+ * @param {string|number} key - Property key to retrieve
376
+ * @returns {*} The value of the property, unwrapped if it's an observable
377
+ * @example
378
+ * const user = Observable({ name: 'John', age: Observable(25) });
379
+ * user.get('name'); // 'John'
380
+ * user.get('age'); // 25 (unwrapped from observable)
381
+ */
323
382
  ObservableItem.prototype.get = function(key) {
324
383
  const item = this.$currentValue[key];
325
384
  return Validator.isObservable(item) ? item.val() : item;
326
385
  };
327
386
 
387
+ /**
388
+ * Creates an ObservableWhen that represents whether the observable equals a specific value.
389
+ * Returns an object that can be subscribed to and will emit true/false.
390
+ *
391
+ * @param {*} value - The value to compare against
392
+ * @returns {ObservableWhen} An ObservableWhen instance that tracks when the observable equals the value
393
+ * @example
394
+ * const status = Observable('idle');
395
+ * const isLoading = status.when('loading');
396
+ * isLoading.subscribe(active => console.log('Loading:', active));
397
+ * status.set('loading'); // Logs: "Loading: true"
398
+ */
328
399
  ObservableItem.prototype.when = function(value) {
329
400
  return new ObservableWhen(this, value);
330
401
  };
331
402
 
403
+ /**
404
+ * Compares the observable's current value with another value or observable.
405
+ *
406
+ * @param {*|ObservableItem} other - Value or observable to compare against
407
+ * @returns {boolean} True if values are equal
408
+ * @example
409
+ * const a = Observable(5);
410
+ * const b = Observable(5);
411
+ * a.equals(5); // true
412
+ * a.equals(b); // true
413
+ * a.equals(10); // false
414
+ */
332
415
  ObservableItem.prototype.equals = function(other) {
333
416
  if(Validator.isObservable(other)) {
334
417
  return this.$currentValue === other.$currentValue;
@@ -336,14 +419,41 @@ ObservableItem.prototype.equals = function(other) {
336
419
  return this.$currentValue === other;
337
420
  };
338
421
 
422
+ /**
423
+ * Converts the observable's current value to a boolean.
424
+ *
425
+ * @returns {boolean} The boolean representation of the current value
426
+ * @example
427
+ * const count = Observable(0);
428
+ * count.toBool(); // false
429
+ * count.set(5);
430
+ * count.toBool(); // true
431
+ */
339
432
  ObservableItem.prototype.toBool = function() {
340
433
  return !!this.$currentValue;
341
434
  };
342
435
 
436
+ /**
437
+ * Toggles the boolean value of the observable (false becomes true, true becomes false).
438
+ *
439
+ * @example
440
+ * const isOpen = Observable(false);
441
+ * isOpen.toggle(); // Now true
442
+ * isOpen.toggle(); // Now false
443
+ */
343
444
  ObservableItem.prototype.toggle = function() {
344
445
  this.set(!this.$currentValue);
345
446
  };
346
447
 
448
+ /**
449
+ * Resets the observable to its initial value.
450
+ * Only works if the observable was created with { reset: true } config.
451
+ *
452
+ * @example
453
+ * const count = Observable(0, { reset: true });
454
+ * count.set(10);
455
+ * count.reset(); // Back to 0
456
+ */
347
457
  ObservableItem.prototype.reset = function() {
348
458
  if(!this.configs?.reset) {
349
459
  return;
@@ -356,11 +466,21 @@ ObservableItem.prototype.reset = function() {
356
466
  this.set(resetValue)
357
467
  };
358
468
 
359
-
469
+ /**
470
+ * Returns a string representation of the observable's current value.
471
+ *
472
+ * @returns {string} String representation of the current value
473
+ */
360
474
  ObservableItem.prototype.toString = function() {
361
475
  return String(this.$currentValue);
362
476
  };
363
477
 
478
+ /**
479
+ * Returns the primitive value of the observable (its current value).
480
+ * Called automatically in type coercion contexts.
481
+ *
482
+ * @returns {*} The current value of the observable
483
+ */
364
484
  ObservableItem.prototype.valueOf = function() {
365
485
  return this.$currentValue;
366
486
  };
@@ -1,4 +1,11 @@
1
1
 
2
+ /**
3
+ * Creates an ObservableWhen that tracks whether an observable equals a specific value.
4
+ *
5
+ * @param {ObservableItem} observer - The observable to watch
6
+ * @param {*} value - The value to compare against
7
+ * @class ObservableWhen
8
+ */
2
9
  export const ObservableWhen = function(observer, value) {
3
10
  this.$target = value;
4
11
  this.$observer = observer;
@@ -6,18 +13,41 @@ export const ObservableWhen = function(observer, value) {
6
13
 
7
14
  ObservableWhen.prototype.__$isObservableWhen = true;
8
15
 
16
+ /**
17
+ * Subscribes to changes in the match status (true when observable equals target value).
18
+ *
19
+ * @param {Function} callback - Function called with boolean indicating if values match
20
+ * @returns {Function} Unsubscribe function
21
+ * @example
22
+ * const status = Observable('idle');
23
+ * const isLoading = status.when('loading');
24
+ * isLoading.subscribe(active => console.log('Loading:', active));
25
+ */
9
26
  ObservableWhen.prototype.subscribe = function(callback) {
10
27
  return this.$observer.on(this.$target, callback);
11
28
  };
12
29
 
30
+ /**
31
+ * Returns true if the observable's current value equals the target value.
32
+ *
33
+ * @returns {boolean} True if observable value matches target value
34
+ */
13
35
  ObservableWhen.prototype.val = function() {
14
36
  return this.$observer.$currentValue === this.$target;
15
37
  };
16
38
 
17
- ObservableWhen.prototype.isMath = function() {
18
- return this.$observer.$currentValue === this.$target;
19
- };
39
+ /**
40
+ * Returns true if the observable's current value equals the target value.
41
+ * Alias for val().
42
+ *
43
+ * @returns {boolean} True if observable value matches target value
44
+ */
45
+ ObservableWhen.prototype.isMatch = ObservableWhen.prototype.val;
20
46
 
21
- ObservableWhen.prototype.isActive = function() {
22
- return this.$observer.$currentValue === this.$target;
23
- };
47
+ /**
48
+ * Returns true if the observable's current value equals the target value.
49
+ * Alias for val().
50
+ *
51
+ * @returns {boolean} True if observable value matches target value
52
+ */
53
+ ObservableWhen.prototype.isActive = ObservableWhen.prototype.val;
@@ -3,10 +3,19 @@ import ObservableArray from "../ObservableArray";
3
3
 
4
4
 
5
5
  /**
6
+ * Creates an observable array with reactive array methods.
7
+ * All mutations trigger updates automatically.
6
8
  *
7
- * @param {Array} target
8
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
9
- * @returns {ObservableArray}
9
+ * @param {Array} [target=[]] - Initial array value
10
+ * @param {Object|null} [configs=null] - Configuration options
11
+ * // @param {boolean} [configs.propagation=true] - Whether to propagate changes to parent observables
12
+ * // @param {boolean} [configs.deep=false] - Whether to make nested objects observable
13
+ * @param {boolean} [configs.reset=false] - Whether to store initial value for reset()
14
+ * @returns {ObservableArray} An observable array with reactive methods
15
+ * @example
16
+ * const items = Observable.array([1, 2, 3]);
17
+ * items.push(4); // Triggers update
18
+ * items.subscribe((arr) => console.log(arr));
10
19
  */
11
20
  Observable.array = function(target = [], configs = null) {
12
21
  return new ObservableArray(target, configs);
@@ -6,11 +6,24 @@ import PluginsManager from "../../utils/plugins-manager";
6
6
  import {nextTick} from "../../utils/helpers";
7
7
 
8
8
  /**
9
+ * Creates a computed observable that automatically updates when its dependencies change.
10
+ * The callback is re-executed whenever any dependency observable changes.
9
11
  *
10
- * @param {Function} callback
11
- * @param {Array|Function} dependencies
12
- * @returns {ObservableItem}
13
- */
12
+ * @param {Function} callback - Function that returns the computed value
13
+ * @param {Array<ObservableItem|ObservableChecker|ObservableProxy>|Function} [dependencies=[]] - Array of observables to watch, or batch function
14
+ * @returns {ObservableItem} A new observable that updates automatically
15
+ * @example
16
+ * const firstName = Observable('John');
17
+ * const lastName = Observable('Doe');
18
+ * const fullName = Observable.computed(
19
+ * () => `${firstName.val()} ${lastName.val()}`,
20
+ * [firstName, lastName]
21
+ * );
22
+ *
23
+ * // With batch function
24
+ * const batch = Observable.batch(() => { ... });
25
+ * const computed = Observable.computed(() => { ... }, batch);
26
+ */
14
27
  Observable.computed = function(callback, dependencies = []) {
15
28
  const initialValue = callback();
16
29
  const observable = new ObservableItem(initialValue);
@@ -40,10 +40,26 @@ const ObservableGet = function(target, property) {
40
40
  };
41
41
 
42
42
  /**
43
+ * Creates an observable proxy for an object where each property becomes an observable.
44
+ * Properties can be accessed directly or via getter methods.
43
45
  *
44
- * @param {Object} initialValue
45
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
46
- * @returns {Proxy}
46
+ * @param {Object} initialValue - Initial object value
47
+ * @param {Object|null} [configs=null] - Configuration options
48
+ * // @param {boolean} [configs.propagation=true] - Whether changes propagate to parent
49
+ * @param {boolean} [configs.deep=false] - Whether to make nested objects observable
50
+ * @param {boolean} [configs.reset=false] - Whether to enable reset() method
51
+ * @returns {ObservableProxy} A proxy where each property is an observable
52
+ * @example
53
+ * const user = Observable.init({
54
+ * name: 'John',
55
+ * age: 25,
56
+ * address: { city: 'NYC' }
57
+ * }, { deep: true });
58
+ *
59
+ * user.name.val(); // 'John'
60
+ * user.name.set('Jane');
61
+ * user.name = 'Jane X'
62
+ * user.age.subscribe(val => console.log('Age:', val));
47
63
  */
48
64
  Observable.init = function(initialValue, configs = null) {
49
65
  const data = {};
@@ -4,8 +4,26 @@ import Validator from "../../utils/validator";
4
4
  import { ElementCreator } from "../../wrappers/ElementCreator";
5
5
  import NativeDocumentError from "../../errors/NativeDocumentError";
6
6
 
7
+ /**
8
+ * Renders items from an ObservableArray with optimized array-specific updates.
9
+ * Provides index observables and handles array mutations efficiently.
10
+ *
11
+ * @param {ObservableArray} data - ObservableArray to iterate over
12
+ * @param {Function} callback - Function that renders each item (item, indexObservable) => ValidChild
13
+ * @param {Object} [configs={}] - Configuration options
14
+ * @param {boolean} [configs.shouldKeepItemsInCache] - Whether to cache rendered items
15
+ * @param {boolean} [configs.isParentUniqueChild] - When it's the only child of the parent
16
+ * @returns {AnchorDocumentFragment} Fragment managing the list rendering
17
+ * @example
18
+ * const items = Observable.array([1, 2, 3]);
19
+ * ForEachArray(items, (item, index) =>
20
+ * Div({}, `Item ${item} at index ${index.val()}`)
21
+ * );
22
+ *
23
+ * items.push(4); // Automatically updates DOM
24
+ */
7
25
  export function ForEachArray(data, callback, configs = {}) {
8
- const element = Anchor('ForEach Array');
26
+ const element = Anchor('ForEach Array', configs.isParentUniqueChild);
9
27
  const blockEnd = element.endElement();
10
28
  const blockStart = element.startElement();
11
29
 
@@ -180,7 +198,7 @@ export function ForEachArray(data, callback, configs = {}) {
180
198
  elementBeforeFirst = firstChildRemoved?.previousSibling;
181
199
 
182
200
  for(let i = 0; i < deleted.length; i++) {
183
- firstItem(deleted[i], garbageFragment);
201
+ removeByItem(deleted[i], garbageFragment);
184
202
  }
185
203
  }
186
204
  } else {