juxscript 1.1.25 → 1.1.26
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.
|
@@ -37,6 +37,7 @@ export declare abstract class BaseComponent<TState extends BaseState = BaseState
|
|
|
37
37
|
}>;
|
|
38
38
|
protected _triggerHandlers: Map<string, Function>;
|
|
39
39
|
protected _callbackHandlers: Map<string, Function>;
|
|
40
|
+
protected _isUpdatingSync: boolean;
|
|
40
41
|
constructor(id: string, initialState: TState);
|
|
41
42
|
protected abstract getTriggerEvents(): readonly string[];
|
|
42
43
|
protected abstract getCallbackEvents(): readonly string[];
|
|
@@ -49,8 +50,8 @@ export declare abstract class BaseComponent<TState extends BaseState = BaseState
|
|
|
49
50
|
*/
|
|
50
51
|
update(prop: string, value: any): void;
|
|
51
52
|
/**
|
|
52
|
-
* ✨
|
|
53
|
-
*
|
|
53
|
+
* ✨ Notify external State<T> objects when component state changes
|
|
54
|
+
* Prevents infinite loops with guard flag
|
|
54
55
|
*/
|
|
55
56
|
protected _notifySyncedState(prop: string, value: any): void;
|
|
56
57
|
/**
|
|
@@ -144,8 +145,7 @@ export declare abstract class BaseComponent<TState extends BaseState = BaseState
|
|
|
144
145
|
protected _setupContainer(targetId?: string): HTMLElement;
|
|
145
146
|
protected _wireStandardEvents(element: HTMLElement): void;
|
|
146
147
|
/**
|
|
147
|
-
*
|
|
148
|
-
* if it exists on the component
|
|
148
|
+
* Wire sync subscriptions with guard flag
|
|
149
149
|
*/
|
|
150
150
|
protected _wireAllSyncs(): void;
|
|
151
151
|
renderTo(juxComponent: any): this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAGlD;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;;;;;GAQG;AACH,8BAAsB,aAAa,CAAC,MAAM,SAAS,SAAS,GAAG,SAAS;IAEpE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,WAAW,GAAG,IAAI,CAAQ;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IAGX,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAM;IACtE,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,OAAO,CAAC,EAAE,QAAQ,CAAC;QACnB,WAAW,CAAC,EAAE,QAAQ,CAAA;KACzB,CAAC,CAAM;IACR,SAAS,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAa;IAC9D,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAa;
|
|
1
|
+
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ export class BaseComponent {
|
|
|
16
16
|
this._syncBindings = [];
|
|
17
17
|
this._triggerHandlers = new Map();
|
|
18
18
|
this._callbackHandlers = new Map();
|
|
19
|
+
this._isUpdatingSync = false; // ✅ Guard flag
|
|
19
20
|
this._id = id;
|
|
20
21
|
this.id = id;
|
|
21
22
|
const stateWithDefaults = {
|
|
@@ -27,7 +28,6 @@ export class BaseComponent {
|
|
|
27
28
|
attributes: {},
|
|
28
29
|
...initialState
|
|
29
30
|
};
|
|
30
|
-
// ✨ REACTIVE PROXY: Intercept state changes to trigger view updates automatically
|
|
31
31
|
this.state = new Proxy(stateWithDefaults, {
|
|
32
32
|
set: (target, prop, value) => {
|
|
33
33
|
const key = prop;
|
|
@@ -35,8 +35,10 @@ export class BaseComponent {
|
|
|
35
35
|
target[key] = value;
|
|
36
36
|
// 1️⃣ Update DOM via update()
|
|
37
37
|
this.update(prop, value);
|
|
38
|
-
// 2️⃣ ✨
|
|
39
|
-
this.
|
|
38
|
+
// 2️⃣ ✨ Notify synced State<T> objects (with guard)
|
|
39
|
+
if (!this._isUpdatingSync) {
|
|
40
|
+
this._notifySyncedState(prop, value);
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
return true;
|
|
42
44
|
}
|
|
@@ -81,18 +83,23 @@ export class BaseComponent {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
/**
|
|
84
|
-
* ✨
|
|
85
|
-
*
|
|
86
|
+
* ✨ Notify external State<T> objects when component state changes
|
|
87
|
+
* Prevents infinite loops with guard flag
|
|
86
88
|
*/
|
|
87
89
|
_notifySyncedState(prop, value) {
|
|
88
90
|
const syncBinding = this._syncBindings.find(b => b.property === prop);
|
|
89
91
|
if (syncBinding) {
|
|
90
92
|
const { stateObj, toState } = syncBinding;
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
// Set guard flag to prevent recursion
|
|
94
|
+
this._isUpdatingSync = true;
|
|
95
|
+
try {
|
|
96
|
+
const transformedValue = toState ? toState(value) : value;
|
|
97
|
+
stateObj.set(transformedValue);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
// Always clear guard flag
|
|
101
|
+
this._isUpdatingSync = false;
|
|
102
|
+
}
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
/* ═════════════════════════════════════════════════════════════════
|
|
@@ -357,22 +364,26 @@ export class BaseComponent {
|
|
|
357
364
|
});
|
|
358
365
|
}
|
|
359
366
|
/**
|
|
360
|
-
*
|
|
361
|
-
* if it exists on the component
|
|
367
|
+
* Wire sync subscriptions with guard flag
|
|
362
368
|
*/
|
|
363
369
|
_wireAllSyncs() {
|
|
364
370
|
this._syncBindings.forEach(({ property, stateObj, toComponent }) => {
|
|
365
371
|
const transform = toComponent || ((v) => v);
|
|
366
|
-
// Check if component has a method matching the property name
|
|
367
372
|
const method = this[property];
|
|
368
373
|
if (typeof method === 'function') {
|
|
369
374
|
// Set initial value
|
|
370
375
|
const initialValue = transform(stateObj.value);
|
|
376
|
+
this._isUpdatingSync = true; // ✅ Guard during initial set
|
|
371
377
|
method.call(this, initialValue);
|
|
372
|
-
|
|
378
|
+
this._isUpdatingSync = false;
|
|
379
|
+
// Subscribe to changes with guard
|
|
373
380
|
stateObj.subscribe((val) => {
|
|
381
|
+
if (this._isUpdatingSync)
|
|
382
|
+
return; // ✅ Skip if updating
|
|
374
383
|
const transformed = transform(val);
|
|
384
|
+
this._isUpdatingSync = true;
|
|
375
385
|
method.call(this, transformed);
|
|
386
|
+
this._isUpdatingSync = false;
|
|
376
387
|
});
|
|
377
388
|
}
|
|
378
389
|
else {
|
|
@@ -40,6 +40,7 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
40
40
|
}> = [];
|
|
41
41
|
protected _triggerHandlers: Map<string, Function> = new Map();
|
|
42
42
|
protected _callbackHandlers: Map<string, Function> = new Map();
|
|
43
|
+
protected _isUpdatingSync: boolean = false; // ✅ Guard flag
|
|
43
44
|
|
|
44
45
|
constructor(id: string, initialState: TState) {
|
|
45
46
|
this._id = id;
|
|
@@ -55,7 +56,6 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
55
56
|
...initialState
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
// ✨ REACTIVE PROXY: Intercept state changes to trigger view updates automatically
|
|
59
59
|
this.state = new Proxy(stateWithDefaults, {
|
|
60
60
|
set: (target, prop, value) => {
|
|
61
61
|
const key = prop as keyof TState;
|
|
@@ -65,8 +65,10 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
65
65
|
// 1️⃣ Update DOM via update()
|
|
66
66
|
this.update(prop as string, value);
|
|
67
67
|
|
|
68
|
-
// 2️⃣ ✨
|
|
69
|
-
this.
|
|
68
|
+
// 2️⃣ ✨ Notify synced State<T> objects (with guard)
|
|
69
|
+
if (!this._isUpdatingSync) {
|
|
70
|
+
this._notifySyncedState(prop as string, value);
|
|
71
|
+
}
|
|
70
72
|
}
|
|
71
73
|
return true;
|
|
72
74
|
}
|
|
@@ -125,8 +127,8 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
/**
|
|
128
|
-
* ✨
|
|
129
|
-
*
|
|
130
|
+
* ✨ Notify external State<T> objects when component state changes
|
|
131
|
+
* Prevents infinite loops with guard flag
|
|
130
132
|
*/
|
|
131
133
|
protected _notifySyncedState(prop: string, value: any): void {
|
|
132
134
|
const syncBinding = this._syncBindings.find(b => b.property === prop);
|
|
@@ -134,12 +136,16 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
134
136
|
if (syncBinding) {
|
|
135
137
|
const { stateObj, toState } = syncBinding;
|
|
136
138
|
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
+
// Set guard flag to prevent recursion
|
|
140
|
+
this._isUpdatingSync = true;
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
try {
|
|
143
|
+
const transformedValue = toState ? toState(value) : value;
|
|
144
|
+
stateObj.set(transformedValue);
|
|
145
|
+
} finally {
|
|
146
|
+
// Always clear guard flag
|
|
147
|
+
this._isUpdatingSync = false;
|
|
148
|
+
}
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
|
|
@@ -437,25 +443,29 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
437
443
|
}
|
|
438
444
|
|
|
439
445
|
/**
|
|
440
|
-
*
|
|
441
|
-
* if it exists on the component
|
|
446
|
+
* Wire sync subscriptions with guard flag
|
|
442
447
|
*/
|
|
443
448
|
protected _wireAllSyncs(): void {
|
|
444
449
|
this._syncBindings.forEach(({ property, stateObj, toComponent }) => {
|
|
445
450
|
const transform = toComponent || ((v: any) => v);
|
|
446
451
|
|
|
447
|
-
// Check if component has a method matching the property name
|
|
448
452
|
const method = (this as any)[property];
|
|
449
453
|
|
|
450
454
|
if (typeof method === 'function') {
|
|
451
455
|
// Set initial value
|
|
452
456
|
const initialValue = transform(stateObj.value);
|
|
457
|
+
this._isUpdatingSync = true; // ✅ Guard during initial set
|
|
453
458
|
method.call(this, initialValue);
|
|
459
|
+
this._isUpdatingSync = false;
|
|
454
460
|
|
|
455
|
-
// Subscribe to changes
|
|
461
|
+
// Subscribe to changes with guard
|
|
456
462
|
stateObj.subscribe((val: any) => {
|
|
463
|
+
if (this._isUpdatingSync) return; // ✅ Skip if updating
|
|
464
|
+
|
|
457
465
|
const transformed = transform(val);
|
|
466
|
+
this._isUpdatingSync = true;
|
|
458
467
|
method.call(this, transformed);
|
|
468
|
+
this._isUpdatingSync = false;
|
|
459
469
|
});
|
|
460
470
|
} else {
|
|
461
471
|
console.warn(
|