native-document 1.0.92 → 1.0.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/native-document.components.min.js +1088 -65
- package/dist/native-document.dev.js +695 -142
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.devtools.min.js +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/advanced-components.md +814 -0
- package/docs/anchor.md +71 -11
- package/docs/cache.md +888 -0
- package/docs/conditional-rendering.md +91 -1
- package/docs/core-concepts.md +9 -2
- package/docs/elements.md +127 -2
- package/docs/extending-native-document-element.md +7 -1
- package/docs/filters.md +1216 -0
- package/docs/getting-started.md +12 -3
- package/docs/lifecycle-events.md +10 -2
- package/docs/list-rendering.md +453 -54
- package/docs/memory-management.md +9 -7
- package/docs/native-document-element.md +30 -9
- package/docs/native-fetch.md +744 -0
- package/docs/observables.md +135 -6
- package/docs/routing.md +7 -1
- package/docs/state-management.md +7 -1
- package/docs/validation.md +8 -1
- package/elements.js +1 -0
- package/eslint.config.js +3 -3
- package/index.def.js +350 -0
- package/package.json +3 -2
- package/readme.md +53 -14
- package/src/components/$traits/HasItems.js +42 -1
- package/src/components/BaseComponent.js +4 -1
- package/src/components/accordion/Accordion.js +112 -8
- package/src/components/accordion/AccordionItem.js +93 -4
- package/src/components/alert/Alert.js +164 -4
- package/src/components/avatar/Avatar.js +236 -22
- package/src/components/menu/index.js +1 -2
- package/src/core/data/ObservableArray.js +120 -2
- package/src/core/data/ObservableChecker.js +50 -0
- package/src/core/data/ObservableItem.js +124 -4
- package/src/core/data/ObservableWhen.js +36 -6
- package/src/core/data/observable-helpers/array.js +12 -3
- package/src/core/data/observable-helpers/computed.js +17 -4
- package/src/core/data/observable-helpers/object.js +19 -3
- package/src/core/elements/content-formatter.js +138 -1
- package/src/core/elements/control/for-each-array.js +20 -2
- package/src/core/elements/control/for-each.js +17 -5
- package/src/core/elements/control/show-if.js +31 -15
- package/src/core/elements/control/show-when.js +23 -0
- package/src/core/elements/control/switch.js +40 -10
- package/src/core/elements/description-list.js +14 -0
- package/src/core/elements/form.js +188 -4
- package/src/core/elements/html5-semantics.js +44 -1
- package/src/core/elements/img.js +22 -10
- package/src/core/elements/index.js +5 -0
- package/src/core/elements/interactive.js +19 -1
- package/src/core/elements/list.js +28 -1
- package/src/core/elements/medias.js +29 -0
- package/src/core/elements/meta-data.js +34 -0
- package/src/core/elements/table.js +59 -0
- package/src/core/utils/cache.js +5 -0
- package/src/core/utils/helpers.js +7 -2
- package/src/core/utils/memoize.js +25 -16
- package/src/core/utils/prototypes.js +3 -2
- package/src/core/wrappers/AttributesWrapper.js +1 -1
- package/src/core/wrappers/HtmlElementWrapper.js +2 -2
- package/src/core/wrappers/NDElement.js +42 -2
- package/src/core/wrappers/NdPrototype.js +4 -0
- package/src/core/wrappers/TemplateCloner.js +14 -11
- package/src/core/wrappers/prototypes/bind-class-extensions.js +1 -1
- package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -0
- package/src/router/Route.js +9 -4
- package/src/router/Router.js +28 -9
- package/src/router/errors/RouterError.js +0 -1
- package/types/control-flow.d.ts +9 -6
- package/types/elements.d.ts +496 -111
- package/types/filters/index.d.ts +4 -0
- package/types/forms.d.ts +85 -48
- package/types/images.d.ts +16 -9
- package/types/nd-element.d.ts +5 -238
- package/types/observable.d.ts +9 -3
- package/types/router.d.ts +5 -1
- package/types/template-cloner.ts +1 -0
- package/types/validator.ts +11 -1
- package/utils.d.ts +2 -1
- package/utils.js +4 -4
- package/src/core/utils/service.js +0 -6
|
@@ -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 {
|
|
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
|
-
*
|
|
261
|
-
*
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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 {
|
|
9
|
-
* @
|
|
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 {
|
|
46
|
-
* @
|
|
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 = {};
|