juxscript 1.1.266 → 1.1.269
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.
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
declare class PageState {
|
|
2
2
|
private _registry;
|
|
3
3
|
private _proxy;
|
|
4
|
+
static readonly WIRE_EVENTS: readonly ["blur", "focus", "click", "dblclick", "change", "input", "keydown", "keyup", "keypress", "mouseenter", "mouseleave", "submit"];
|
|
4
5
|
constructor();
|
|
5
6
|
private _createComponentProxy;
|
|
6
|
-
/**
|
|
7
|
-
* Register a component with pageState.
|
|
8
|
-
* Called automatically by jux components on creation.
|
|
9
|
-
*/
|
|
10
7
|
private _register;
|
|
11
8
|
private _wireEvent;
|
|
9
|
+
private _findElement;
|
|
12
10
|
private _unregister;
|
|
13
|
-
/**
|
|
14
|
-
* Notify all reactive blocks that depend on this key
|
|
15
|
-
*/
|
|
16
11
|
private _notify;
|
|
17
|
-
/**
|
|
18
|
-
* Create a reactive block that re-runs when its dependencies change.
|
|
19
|
-
*
|
|
20
|
-
* Usage:
|
|
21
|
-
* pageState.__watch(() => {
|
|
22
|
-
* if (pageState['input1'].value === 'blueberry') {
|
|
23
|
-
* pageState['input2'].value = 'raspberry';
|
|
24
|
-
* }
|
|
25
|
-
* });
|
|
26
|
-
*/
|
|
27
12
|
private _watch;
|
|
28
13
|
getProxy(): Record<string, any>;
|
|
29
|
-
__notify(depKey: string): void;
|
|
30
14
|
}
|
|
31
15
|
export declare const pageState: Record<string, any>;
|
|
32
16
|
export { PageState };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageState.d.ts","sourceRoot":"","sources":["../../../lib/state/pageState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pageState.d.ts","sourceRoot":"","sources":["../../../lib/state/pageState.ts"],"names":[],"mappings":"AAeA,cAAM,SAAS;IACX,OAAO,CAAC,SAAS,CAA0C;IAC3D,OAAO,CAAC,MAAM,CAAsB;IAEpC,MAAM,CAAC,QAAQ,CAAC,WAAW,2IAOhB;;IA2BX,OAAO,CAAC,qBAAqB;IAyD7B,OAAO,CAAC,SAAS;IA6CjB,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,OAAO;IAqBf,OAAO,CAAC,MAAM;IAcd,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAGlC;AAID,eAAO,MAAM,SAAS,qBAAuB,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Tracks which reactive block is currently running so we can record dependencies
|
|
2
2
|
let activeReaction = null;
|
|
3
3
|
const reactionDeps = new Map();
|
|
4
|
+
let notifyQueue = [];
|
|
5
|
+
let isNotifying = false;
|
|
4
6
|
class PageState {
|
|
5
7
|
constructor() {
|
|
6
8
|
this._registry = new Map();
|
|
@@ -19,11 +21,9 @@ class PageState {
|
|
|
19
21
|
const entry = this._registry.get(id);
|
|
20
22
|
if (!entry)
|
|
21
23
|
return undefined;
|
|
22
|
-
// Return a proxy for the component's state slice
|
|
23
24
|
return this._createComponentProxy(id, entry);
|
|
24
25
|
},
|
|
25
26
|
set: (_, id, value) => {
|
|
26
|
-
// pageState['input1'] = someComponent — register it
|
|
27
27
|
if (value && typeof value === 'object' && value.id) {
|
|
28
28
|
this._register(value);
|
|
29
29
|
return true;
|
|
@@ -36,27 +36,22 @@ class PageState {
|
|
|
36
36
|
return new Proxy({}, {
|
|
37
37
|
get: (_, prop) => {
|
|
38
38
|
const depKey = `${id}.${prop}`;
|
|
39
|
-
// Track dependency if inside a reactive block
|
|
40
39
|
if (activeReaction) {
|
|
41
40
|
if (!reactionDeps.has(activeReaction)) {
|
|
42
41
|
reactionDeps.set(activeReaction, new Set());
|
|
43
42
|
}
|
|
44
43
|
reactionDeps.get(activeReaction).add(depKey);
|
|
45
44
|
}
|
|
46
|
-
// Event flags (blur, focus, hover, etc.)
|
|
47
45
|
if (prop in entry.events) {
|
|
48
46
|
return entry.events[prop];
|
|
49
47
|
}
|
|
50
|
-
// Component props (value, disabled, checked, etc.)
|
|
51
48
|
if (prop in entry.props) {
|
|
52
49
|
return entry.props[prop];
|
|
53
50
|
}
|
|
54
|
-
// ✅ Expose component methods directly (refresh, fetch, etc.)
|
|
55
51
|
const comp = entry.component;
|
|
56
52
|
if (typeof comp[prop] === 'function') {
|
|
57
53
|
return comp[prop].bind(comp);
|
|
58
54
|
}
|
|
59
|
-
// Fallback: try getter pattern
|
|
60
55
|
const getterName = `get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
61
56
|
if (typeof comp[getterName] === 'function') {
|
|
62
57
|
return comp[getterName]();
|
|
@@ -68,7 +63,6 @@ class PageState {
|
|
|
68
63
|
},
|
|
69
64
|
set: (_, prop, value) => {
|
|
70
65
|
const depKey = `${id}.${prop}`;
|
|
71
|
-
// Update component via fluent API or setter
|
|
72
66
|
const comp = entry.component;
|
|
73
67
|
const setterName = `set${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
74
68
|
if (typeof comp[setterName] === 'function') {
|
|
@@ -77,18 +71,12 @@ class PageState {
|
|
|
77
71
|
else if (typeof comp[prop] === 'function') {
|
|
78
72
|
comp[prop](value);
|
|
79
73
|
}
|
|
80
|
-
// Update tracked props
|
|
81
74
|
entry.props[prop] = value;
|
|
82
|
-
// Notify listeners
|
|
83
75
|
this._notify(depKey);
|
|
84
76
|
return true;
|
|
85
77
|
}
|
|
86
78
|
});
|
|
87
79
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Register a component with pageState.
|
|
90
|
-
* Called automatically by jux components on creation.
|
|
91
|
-
*/
|
|
92
80
|
_register(component) {
|
|
93
81
|
const id = component.id;
|
|
94
82
|
if (!id)
|
|
@@ -99,7 +87,6 @@ class PageState {
|
|
|
99
87
|
events: {},
|
|
100
88
|
listeners: new Map()
|
|
101
89
|
};
|
|
102
|
-
// Seed initial props from component
|
|
103
90
|
if (component.getValue)
|
|
104
91
|
entry.props.value = component.getValue();
|
|
105
92
|
if (component.getValues)
|
|
@@ -115,7 +102,6 @@ class PageState {
|
|
|
115
102
|
}
|
|
116
103
|
entry.props.id = id;
|
|
117
104
|
this._registry.set(id, entry);
|
|
118
|
-
// Wire component onChange to update pageState
|
|
119
105
|
if (typeof component.onChange === 'function') {
|
|
120
106
|
const originalOnChange = component._onChange;
|
|
121
107
|
component.onChange((val, e) => {
|
|
@@ -123,6 +109,10 @@ class PageState {
|
|
|
123
109
|
entry.props.values = val;
|
|
124
110
|
this._notify(`${id}.values`);
|
|
125
111
|
}
|
|
112
|
+
else if (typeof val === 'boolean') {
|
|
113
|
+
entry.props.checked = val;
|
|
114
|
+
this._notify(`${id}.checked`);
|
|
115
|
+
}
|
|
126
116
|
else {
|
|
127
117
|
entry.props.value = val;
|
|
128
118
|
this._notify(`${id}.value`);
|
|
@@ -131,51 +121,75 @@ class PageState {
|
|
|
131
121
|
originalOnChange(val, e);
|
|
132
122
|
});
|
|
133
123
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
124
|
+
for (const eventName of PageState.WIRE_EVENTS) {
|
|
125
|
+
this._wireEvent(id, entry, eventName);
|
|
126
|
+
}
|
|
137
127
|
}
|
|
138
128
|
_wireEvent(id, entry, eventName) {
|
|
139
129
|
entry.events[eventName] = false;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (!el || !(el instanceof HTMLElement))
|
|
130
|
+
const el = this._findElement(entry.component);
|
|
131
|
+
if (!el)
|
|
143
132
|
return;
|
|
144
|
-
el.addEventListener(eventName, () => {
|
|
133
|
+
el.addEventListener(eventName, (e) => {
|
|
145
134
|
entry.events[eventName] = true;
|
|
135
|
+
if ((eventName === 'input' || eventName === 'change') && el instanceof HTMLInputElement) {
|
|
136
|
+
entry.props.value = el.value;
|
|
137
|
+
}
|
|
138
|
+
if ((eventName === 'input' || eventName === 'change') && el instanceof HTMLSelectElement) {
|
|
139
|
+
entry.props.value = el.value;
|
|
140
|
+
}
|
|
146
141
|
this._notify(`${id}.${eventName}`);
|
|
147
|
-
// Reset after reactions run
|
|
148
142
|
queueMicrotask(() => {
|
|
149
143
|
entry.events[eventName] = false;
|
|
150
144
|
});
|
|
151
145
|
});
|
|
152
146
|
}
|
|
147
|
+
_findElement(component) {
|
|
148
|
+
if (component._element instanceof HTMLElement)
|
|
149
|
+
return component._element;
|
|
150
|
+
if (typeof component.getElement === 'function') {
|
|
151
|
+
const el = component.getElement();
|
|
152
|
+
if (el instanceof HTMLElement)
|
|
153
|
+
return el;
|
|
154
|
+
}
|
|
155
|
+
if (component._wrapper instanceof HTMLElement) {
|
|
156
|
+
const input = component._wrapper.querySelector('input, select, textarea, button');
|
|
157
|
+
if (input)
|
|
158
|
+
return input;
|
|
159
|
+
return component._wrapper;
|
|
160
|
+
}
|
|
161
|
+
if (component.id && typeof document !== 'undefined') {
|
|
162
|
+
const el = document.getElementById(component.id);
|
|
163
|
+
if (el)
|
|
164
|
+
return el;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
153
168
|
_unregister(id) {
|
|
154
169
|
this._registry.delete(id);
|
|
155
170
|
}
|
|
156
|
-
/**
|
|
157
|
-
* Notify all reactive blocks that depend on this key
|
|
158
|
-
*/
|
|
159
171
|
_notify(depKey) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
notifyQueue.push(depKey);
|
|
173
|
+
// Prevent re-entrant notification loops
|
|
174
|
+
if (isNotifying)
|
|
175
|
+
return;
|
|
176
|
+
isNotifying = true;
|
|
177
|
+
try {
|
|
178
|
+
while (notifyQueue.length > 0) {
|
|
179
|
+
const key = notifyQueue.shift();
|
|
180
|
+
for (const [reaction, deps] of reactionDeps.entries()) {
|
|
181
|
+
if (deps.has(key)) {
|
|
182
|
+
reaction();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
163
185
|
}
|
|
164
186
|
}
|
|
187
|
+
finally {
|
|
188
|
+
isNotifying = false;
|
|
189
|
+
}
|
|
165
190
|
}
|
|
166
|
-
/**
|
|
167
|
-
* Create a reactive block that re-runs when its dependencies change.
|
|
168
|
-
*
|
|
169
|
-
* Usage:
|
|
170
|
-
* pageState.__watch(() => {
|
|
171
|
-
* if (pageState['input1'].value === 'blueberry') {
|
|
172
|
-
* pageState['input2'].value = 'raspberry';
|
|
173
|
-
* }
|
|
174
|
-
* });
|
|
175
|
-
*/
|
|
176
191
|
_watch(fn) {
|
|
177
192
|
const reaction = () => {
|
|
178
|
-
// Clear old deps, track new ones during execution
|
|
179
193
|
reactionDeps.set(reaction, new Set());
|
|
180
194
|
activeReaction = reaction;
|
|
181
195
|
try {
|
|
@@ -185,20 +199,20 @@ class PageState {
|
|
|
185
199
|
activeReaction = null;
|
|
186
200
|
}
|
|
187
201
|
};
|
|
188
|
-
// Run once immediately to collect initial dependencies
|
|
189
202
|
reaction();
|
|
190
203
|
}
|
|
191
204
|
getProxy() {
|
|
192
205
|
return this._proxy;
|
|
193
206
|
}
|
|
194
|
-
__notify(depKey) {
|
|
195
|
-
for (const [reaction, deps] of reactionDeps.entries()) {
|
|
196
|
-
if (deps.has(depKey)) {
|
|
197
|
-
reaction();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
207
|
}
|
|
208
|
+
PageState.WIRE_EVENTS = [
|
|
209
|
+
'blur', 'focus',
|
|
210
|
+
'click', 'dblclick',
|
|
211
|
+
'change', 'input',
|
|
212
|
+
'keydown', 'keyup', 'keypress',
|
|
213
|
+
'mouseenter', 'mouseleave',
|
|
214
|
+
'submit'
|
|
215
|
+
];
|
|
202
216
|
// Singleton
|
|
203
217
|
const _instance = new PageState();
|
|
204
218
|
export const pageState = _instance.getProxy();
|