@twobirds/microcomponents 0.1.16 → 0.1.18
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/MC.d.ts.map +1 -1
- package/dist/MC.js +2 -5
- package/dist/MC.min.js +2 -5
- package/dist/MC.ts +336 -346
- package/dist/elements.d.ts.map +1 -1
- package/dist/elements.ts +90 -90
- package/dist/formValues.d.ts.map +1 -1
- package/dist/formValues.js +0 -1
- package/dist/formValues.min.js +1 -1
- package/dist/formValues.ts +165 -171
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.ts +100 -100
- package/dist/microcomponents.min.js +1 -1
- package/dist/observables.d.ts.map +1 -1
- package/dist/observables.js +3 -9
- package/dist/observables.min.js +1 -1
- package/dist/observables.ts +287 -325
- package/package.json +1 -1
package/dist/observables.ts
CHANGED
|
@@ -5,169 +5,151 @@ import { LooseObject, debounce, deepEqual, flattenObject, copyGettersSetters } f
|
|
|
5
5
|
import { DC, HTMLMcElement, trigger } from './MC.js';
|
|
6
6
|
|
|
7
7
|
function isObservableObject(value: any): boolean {
|
|
8
|
-
|
|
8
|
+
return value != null && typeof value === 'object';
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
type Callback = (value: any) => void;
|
|
12
12
|
|
|
13
13
|
function getPlaceholders(target: HTMLElement): string[] {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// extract {} and return result
|
|
42
|
-
return [...placeholders].map((placeholder) => placeholder.replace(/[\{\}]/g, ''));
|
|
14
|
+
let placeholders: Set<string> = new Set(),
|
|
15
|
+
regEx = /\{[^\{\}]*\}/g;
|
|
16
|
+
|
|
17
|
+
// scan attributes
|
|
18
|
+
(target.getAttributeNames ? target.getAttributeNames() : [])
|
|
19
|
+
.filter((attr) => target.getAttribute(attr)?.match(regEx)) // extract placeholder(s)
|
|
20
|
+
.forEach((attr) => {
|
|
21
|
+
let placeholders: Set<string> = new Set(target.getAttribute(attr)?.match(regEx));
|
|
22
|
+
placeholders.forEach((placeholder) => placeholders.add(placeholder.replace(/[\{\}]/g, '')));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// scan children text nodes
|
|
26
|
+
[...target.childNodes]
|
|
27
|
+
.filter((childNode) => {
|
|
28
|
+
return (
|
|
29
|
+
// is text node and has placeholders
|
|
30
|
+
childNode.nodeType === 3 && ((childNode as any).nodeValue || '').match(regEx)
|
|
31
|
+
);
|
|
32
|
+
})
|
|
33
|
+
.forEach((childNode) => {
|
|
34
|
+
((childNode as any).nodeValue || '').match(regEx).forEach((placeholder: string) => {
|
|
35
|
+
placeholders.add(placeholder.replace(/[\{\}]/g, ''));
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// extract {} and return result
|
|
40
|
+
return [...placeholders].map((placeholder) => placeholder.replace(/[\{\}]/g, ''));
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
const inputs = [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement];
|
|
46
44
|
|
|
47
45
|
class Placeholders extends DC {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
) {
|
|
131
|
-
target.style.display = 'none';
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
onData(ev: CustomEvent) {
|
|
137
|
-
let data: LooseObject = {};
|
|
138
|
-
Object.keys(ev.detail.data).forEach((key) => {
|
|
139
|
-
if (this.data.hasOwnProperty(key)) data[key] = ev.detail.data[key];
|
|
140
|
-
});
|
|
141
|
-
//console.log( 'Placeholder onData', ev, data );
|
|
142
|
-
if (JSON.stringify(data) !== JSON.stringify(this.data)) Object.assign(this.data, data); // will trigger callbacks
|
|
143
|
-
}
|
|
46
|
+
data: LooseObject = {};
|
|
47
|
+
oldDisplay?: string = '';
|
|
48
|
+
|
|
49
|
+
constructor(target: HTMLElement) {
|
|
50
|
+
super(target);
|
|
51
|
+
getPlaceholders(target).forEach((property) => (this.data[property] = ''));
|
|
52
|
+
observe(this);
|
|
53
|
+
this.#attachCallbacks();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#attachCallbacks() {
|
|
57
|
+
let target = this.target,
|
|
58
|
+
hide: boolean = false;
|
|
59
|
+
|
|
60
|
+
// scan attributes
|
|
61
|
+
(target.getAttributeNames ? target.getAttributeNames() : [])
|
|
62
|
+
.filter((attr: string) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g)) // extract placeholder(s)
|
|
63
|
+
.forEach((attr: string) => {
|
|
64
|
+
let placeholders: Set<string> = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
|
|
65
|
+
// attach callback
|
|
66
|
+
this.data.observe(
|
|
67
|
+
((template: string) => (data: LooseObject) => {
|
|
68
|
+
let result: string = template;
|
|
69
|
+
placeholders.forEach((placeholder) => {
|
|
70
|
+
result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
|
|
71
|
+
});
|
|
72
|
+
target.setAttribute(attr, result);
|
|
73
|
+
})(target.getAttribute(attr))
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// scan children text nodes
|
|
78
|
+
[...target.childNodes]
|
|
79
|
+
.filter((childNode) => {
|
|
80
|
+
return (
|
|
81
|
+
// is text node and has placeholders
|
|
82
|
+
childNode.nodeType === 3 && ((childNode as Node).nodeValue || '').match(/\{[^\{\}]*\}/g)
|
|
83
|
+
);
|
|
84
|
+
})
|
|
85
|
+
.forEach((childNode) => {
|
|
86
|
+
hide = true;
|
|
87
|
+
let placeholders: Set<string> = new Set(childNode.nodeValue.match(/\{[^\{\}]*\}/g));
|
|
88
|
+
|
|
89
|
+
// attach callback
|
|
90
|
+
this.data.observe(
|
|
91
|
+
((template: string) => (data: LooseObject) => {
|
|
92
|
+
let result: string = template;
|
|
93
|
+
placeholders.forEach((placeholder) => {
|
|
94
|
+
result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (this.oldDisplay) {
|
|
98
|
+
target.style = this.oldDisplay;
|
|
99
|
+
} else {
|
|
100
|
+
target.removeAttribute('style');
|
|
101
|
+
}
|
|
102
|
+
delete this.oldDisplay;
|
|
103
|
+
|
|
104
|
+
childNode.nodeValue = result;
|
|
105
|
+
})(childNode.nodeValue)
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// hide for now
|
|
109
|
+
this.oldDisplay = target.getAttribute('style') || ''; // TBD allow null to indicate there was no old style attribute
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
hide &&
|
|
113
|
+
!inputs.includes((target as any).constructor) &&
|
|
114
|
+
target.tagName !== 'FIELDSET'
|
|
115
|
+
) {
|
|
116
|
+
target.style.display = 'none';
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
onData(ev: CustomEvent) {
|
|
122
|
+
let data: LooseObject = {};
|
|
123
|
+
Object.keys(ev.detail.data).forEach((key) => {
|
|
124
|
+
if (this.data.hasOwnProperty(key)) data[key] = ev.detail.data[key];
|
|
125
|
+
});
|
|
126
|
+
if (JSON.stringify(data) !== JSON.stringify(this.data)) Object.assign(this.data, data); // will trigger callbacks
|
|
127
|
+
}
|
|
144
128
|
}
|
|
145
129
|
|
|
146
130
|
function getPlaceholderElements(
|
|
147
|
-
|
|
131
|
+
target: HTMLElement | DocumentFragment | ShadowRoot
|
|
148
132
|
): HTMLElement[] {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return elements as HTMLElement[];
|
|
133
|
+
let elements: Array<Node> = [target]
|
|
134
|
+
.concat([...(target.querySelectorAll('*') as unknown as HTMLElement[])])
|
|
135
|
+
.filter((e) => !!getPlaceholders(e as HTMLElement).length)
|
|
136
|
+
.filter((e) => (e as HTMLElement)?.tagName !== 'STYLE')
|
|
137
|
+
.reverse(); // to start with inner elements
|
|
138
|
+
return elements as HTMLElement[];
|
|
156
139
|
}
|
|
157
140
|
|
|
158
141
|
function makePlaceholders(element: HTMLElement | DocumentFragment | ShadowRoot): void {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
});
|
|
142
|
+
getPlaceholderElements(element).forEach((e: HTMLElement) => {
|
|
143
|
+
if ((e as HTMLMcElement)?._mc?._placeholders) return;
|
|
144
|
+
DC.add(e, '_placeholders', new Placeholders(e));
|
|
145
|
+
});
|
|
164
146
|
}
|
|
165
147
|
|
|
166
148
|
export type Observable = {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
149
|
+
observe: (cb: Callback) => void;
|
|
150
|
+
notify: () => void;
|
|
151
|
+
bind: (target: HTMLElement | DocumentFragment | ShadowRoot) => void;
|
|
152
|
+
callbacks: Array<Function>;
|
|
171
153
|
};
|
|
172
154
|
|
|
173
155
|
type Class<T> = new (...args: any[]) => T;
|
|
@@ -177,192 +159,172 @@ const classRepo: LooseObject = {};
|
|
|
177
159
|
|
|
178
160
|
// creates a new observable class wrapper
|
|
179
161
|
function makeObservable(val: any): Class<typeof val> {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
(classRepo as any)[ConstructorName] = ObservableClass;
|
|
270
|
-
|
|
271
|
-
// console.log( 'classRepo:', classRepo );
|
|
272
|
-
|
|
273
|
-
return ObservableClass;
|
|
162
|
+
const Constructor = val.constructor,
|
|
163
|
+
ConstructorName: string = Constructor.name;
|
|
164
|
+
|
|
165
|
+
let ObservableClass = class extends Constructor {
|
|
166
|
+
#notify: boolean = true;
|
|
167
|
+
#callbacks: Array<Function> = [];
|
|
168
|
+
|
|
169
|
+
constructor(val: any) {
|
|
170
|
+
super(val);
|
|
171
|
+
(this.constructor as LooseObject).callbacks = [];
|
|
172
|
+
if (isObservableObject(val)) {
|
|
173
|
+
// you cannot bind native values to the dom
|
|
174
|
+
Object.getOwnPropertyNames(val).forEach((key) => {
|
|
175
|
+
this[key] = val[key];
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get callbacks(): Array<Function> {
|
|
181
|
+
return this.#callbacks;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
set callbacks(callbacks: Array<Function>) {
|
|
185
|
+
this.#callbacks = callbacks;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
observe(callback: Function) {
|
|
189
|
+
this.#callbacks.push(callback);
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
bind(target: HTMLElement | DocumentFragment | ShadowRoot) {
|
|
194
|
+
const iso = isObservableObject(this.valueOf());
|
|
195
|
+
|
|
196
|
+
if (iso) {
|
|
197
|
+
makePlaceholders(target);
|
|
198
|
+
const placeholders: unknown = [target, ...target.querySelectorAll('[data-mc]')].filter(
|
|
199
|
+
(e) => !!(e as LooseObject)?._mc?._placeholders
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const func = function callback(data: LooseObject) {
|
|
203
|
+
// avoid bubbling for speed
|
|
204
|
+
let flattenedData = flattenObject(data);
|
|
205
|
+
(placeholders as Node[]).forEach((node) => {
|
|
206
|
+
// console.log('trigger callback', e);
|
|
207
|
+
if (!node) return;
|
|
208
|
+
trigger(node as HTMLMcElement, 'data', flattenedData);
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
(this as any).#callbacks.push(func);
|
|
212
|
+
this.notify();
|
|
213
|
+
} else {
|
|
214
|
+
console.warn(
|
|
215
|
+
'IGNORED - cannot bind a non-Object to the dom, IS:',
|
|
216
|
+
typeof this.valueOf(),
|
|
217
|
+
this
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
notify(notify?: boolean) {
|
|
225
|
+
let data =
|
|
226
|
+
isObservableObject(this.valueOf()) && this.valueOf() instanceof Array === false
|
|
227
|
+
? structuredClone(Object.assign({}, this))
|
|
228
|
+
: this.valueOf();
|
|
229
|
+
|
|
230
|
+
if (notify !== undefined) {
|
|
231
|
+
this.#notify = notify;
|
|
232
|
+
// return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (this.#notify) {
|
|
236
|
+
(this as any).#callbacks.forEach((f: Function) => {
|
|
237
|
+
f(data);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return this;
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
(classRepo as any)[ConstructorName] = ObservableClass;
|
|
246
|
+
|
|
247
|
+
return ObservableClass;
|
|
274
248
|
}
|
|
275
249
|
|
|
276
250
|
function getConstructor(val: any): Class<typeof val> {
|
|
277
|
-
|
|
278
|
-
|
|
251
|
+
let key: string = val.constructor.name;
|
|
252
|
+
return classRepo[key] || makeObservable(val);
|
|
279
253
|
}
|
|
280
254
|
|
|
281
255
|
export const observe = (target: LooseObject, propertyName?: string): LooseObject => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
o,
|
|
357
|
-
'- CANNOT BECOME:',
|
|
358
|
-
typeof val
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
target[key] = val; // replace old property with proxy (observable)
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
return target;
|
|
256
|
+
let keys = !propertyName ? [...Object.getOwnPropertyNames(target)] : [propertyName];
|
|
257
|
+
|
|
258
|
+
keys.forEach((key) => {
|
|
259
|
+
if (
|
|
260
|
+
target.hasOwnProperty(key) &&
|
|
261
|
+
typeof target[key] !== 'function' &&
|
|
262
|
+
!target?.[key]?.constructor?.prototype?.observe
|
|
263
|
+
) {
|
|
264
|
+
if (key[0] === '_' || target?.[key] === undefined) return target;
|
|
265
|
+
let val: any = target[key];
|
|
266
|
+
|
|
267
|
+
let o = new (getConstructor(val) as Class<typeof val>)(val);
|
|
268
|
+
|
|
269
|
+
let debouncedNotify: Function = debounce(function debouncedNotify() {
|
|
270
|
+
o.notify();
|
|
271
|
+
}, 0);
|
|
272
|
+
|
|
273
|
+
Object.defineProperty(target, key, {
|
|
274
|
+
enumerable: true,
|
|
275
|
+
get() {
|
|
276
|
+
if (isObservableObject(o.valueOf())) {
|
|
277
|
+
let check = structuredClone(Object.assign({}, o));
|
|
278
|
+
setTimeout(function checkChanges() {
|
|
279
|
+
let state = structuredClone(Object.assign({}, o));
|
|
280
|
+
if (!deepEqual(state, check)) {
|
|
281
|
+
debouncedNotify();
|
|
282
|
+
}
|
|
283
|
+
}, 0);
|
|
284
|
+
}
|
|
285
|
+
return o;
|
|
286
|
+
},
|
|
287
|
+
set(val: any) {
|
|
288
|
+
if (typeof val === typeof o.valueOf()) {
|
|
289
|
+
let iso = isObservableObject(o.valueOf()) && o.valueOf() instanceof Array === false;
|
|
290
|
+
if (iso) {
|
|
291
|
+
// is observable object
|
|
292
|
+
if (o?.constructor?.prototype?.observe === undefined) {
|
|
293
|
+
// not observed yet
|
|
294
|
+
o = new (getConstructor(val) as Class<typeof val>)(
|
|
295
|
+
structuredClone(Object.assign({}, val))
|
|
296
|
+
);
|
|
297
|
+
copyGettersSetters(val, o);
|
|
298
|
+
//o.seal();
|
|
299
|
+
}
|
|
300
|
+
Object.assign(o, val); // mixin set object into observable object
|
|
301
|
+
o.notify(); // dont test, just assume "changed" status
|
|
302
|
+
} else {
|
|
303
|
+
// simple native var
|
|
304
|
+
let old = o.valueOf(),
|
|
305
|
+
callbacks = (o as Observable).callbacks;
|
|
306
|
+
|
|
307
|
+
if (val !== old) {
|
|
308
|
+
o = new (getConstructor(val) as Class<typeof val>)(val);
|
|
309
|
+
(o as Observable).callbacks = callbacks;
|
|
310
|
+
debouncedNotify();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
// set type is not stored type
|
|
315
|
+
console.warn(
|
|
316
|
+
'IGNORED - cannot change observable types, IS:',
|
|
317
|
+
typeof o.valueOf(),
|
|
318
|
+
o,
|
|
319
|
+
'- CANNOT BECOME:',
|
|
320
|
+
typeof val
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
target[key] = val; // replace old property with proxy (observable)
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return target;
|
|
368
330
|
};
|