juxscript 1.1.255 → 1.1.256
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/lib/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { input } from "./components/input.js";
|
|
|
4
4
|
import { select } from "./components/select.js";
|
|
5
5
|
import { radio } from "./components/radio.js";
|
|
6
6
|
import { checkbox, checkboxGroup } from "./components/checkbox.js";
|
|
7
|
+
import { pageState } from "./state/pageState.js";
|
|
7
8
|
export declare const jux: {
|
|
8
9
|
tag: typeof tag;
|
|
9
10
|
div: typeof div;
|
|
@@ -22,5 +23,7 @@ export declare const jux: {
|
|
|
22
23
|
radio: typeof radio;
|
|
23
24
|
checkbox: typeof checkbox;
|
|
24
25
|
checkboxGroup: typeof checkboxGroup;
|
|
26
|
+
pageState: Record<string, any>;
|
|
25
27
|
};
|
|
28
|
+
export { pageState };
|
|
26
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;CAwBf,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/lib/index.js
CHANGED
|
@@ -4,17 +4,38 @@ import { input } from "./components/input.js";
|
|
|
4
4
|
import { select } from "./components/select.js";
|
|
5
5
|
import { radio } from "./components/radio.js";
|
|
6
6
|
import { checkbox, checkboxGroup } from "./components/checkbox.js";
|
|
7
|
+
import { pageState } from "./state/pageState.js";
|
|
8
|
+
// Wrap factories to auto-register into pageState
|
|
9
|
+
function tracked(factory) {
|
|
10
|
+
return ((...args) => {
|
|
11
|
+
const component = factory(...args);
|
|
12
|
+
const id = args[0]; // first arg is always id
|
|
13
|
+
if (id)
|
|
14
|
+
pageState.register(id, component);
|
|
15
|
+
return component;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
7
18
|
export const jux = {
|
|
19
|
+
// Tags
|
|
8
20
|
tag,
|
|
9
|
-
div,
|
|
10
|
-
h1
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
div: tracked(div),
|
|
22
|
+
h1: tracked(h1),
|
|
23
|
+
h2: tracked(h2),
|
|
24
|
+
h3: tracked(h3),
|
|
25
|
+
h4: tracked(h4),
|
|
26
|
+
h5: tracked(h5),
|
|
27
|
+
h6: tracked(h6),
|
|
28
|
+
p: tracked(p),
|
|
29
|
+
span: tracked(span),
|
|
30
|
+
pre: tracked(pre),
|
|
31
|
+
// Components
|
|
14
32
|
include,
|
|
15
|
-
input,
|
|
16
|
-
select,
|
|
17
|
-
radio,
|
|
18
|
-
checkbox,
|
|
19
|
-
checkboxGroup
|
|
33
|
+
input: tracked(input),
|
|
34
|
+
select: tracked(select),
|
|
35
|
+
radio: tracked(radio),
|
|
36
|
+
checkbox: tracked(checkbox),
|
|
37
|
+
checkboxGroup: tracked(checkboxGroup),
|
|
38
|
+
// State
|
|
39
|
+
pageState
|
|
20
40
|
};
|
|
41
|
+
export { pageState };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
declare class PageState {
|
|
2
|
+
private _components;
|
|
3
|
+
private _listeners;
|
|
4
|
+
private _eventListeners;
|
|
5
|
+
private _proxy;
|
|
6
|
+
constructor();
|
|
7
|
+
/**
|
|
8
|
+
* Register a component into pageState.
|
|
9
|
+
* Called automatically by jux components on creation.
|
|
10
|
+
*/
|
|
11
|
+
register(id: string, component: any): void;
|
|
12
|
+
/**
|
|
13
|
+
* Watch for property changes on any component.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* pageState.watch('input1', 'value', (newVal, oldVal) => { ... })
|
|
17
|
+
* pageState.watch('*', 'value', (key, prop, newVal) => { ... }) // wildcard
|
|
18
|
+
*/
|
|
19
|
+
watch(keyOrAll: string, prop: string, fn: (newVal: any, oldVal: any, key?: string) => void): () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Listen for ephemeral events (blur, focus, hover, etc.)
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* pageState.on('input2', 'blur', () => { pageState['input1'] = ''; })
|
|
25
|
+
* pageState.on('input1', 'focus', () => { ... })
|
|
26
|
+
*/
|
|
27
|
+
on(id: string, event: string, fn: (detail?: any) => void): () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Emit an ephemeral event (called internally by components)
|
|
30
|
+
*/
|
|
31
|
+
emit(id: string, event: string, detail?: any): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get a snapshot of all component values
|
|
34
|
+
*/
|
|
35
|
+
snapshot(): Record<string, any>;
|
|
36
|
+
/**
|
|
37
|
+
* Log current state to console
|
|
38
|
+
*/
|
|
39
|
+
dump(): void;
|
|
40
|
+
getProxy(): Record<string, any>;
|
|
41
|
+
private _notify;
|
|
42
|
+
private _wireDOMEvent;
|
|
43
|
+
private _createComponentProxy;
|
|
44
|
+
}
|
|
45
|
+
export declare const pageState: Record<string, any>;
|
|
46
|
+
export { PageState };
|
|
47
|
+
//# sourceMappingURL=pageState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageState.d.ts","sourceRoot":"","sources":["../../../lib/state/pageState.ts"],"names":[],"mappings":"AASA,cAAM,SAAS;IACX,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,eAAe,CAAoE;IAC3F,OAAO,CAAC,MAAM,CAAsB;;IA4CpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI;IAa1C;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAUvG;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI;IAqBrE;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,IAAI;IAOnD;;OAEG;IACH,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAY/B;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAI/B,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,qBAAqB;CA+ChC;AAID,eAAO,MAAM,SAAS,qBAAuB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
class PageState {
|
|
2
|
+
constructor() {
|
|
3
|
+
this._components = new Map();
|
|
4
|
+
this._listeners = new Set();
|
|
5
|
+
this._eventListeners = new Map();
|
|
6
|
+
this._proxy = new Proxy({}, {
|
|
7
|
+
get: (_target, key) => {
|
|
8
|
+
if (key === 'register')
|
|
9
|
+
return this.register.bind(this);
|
|
10
|
+
if (key === 'watch')
|
|
11
|
+
return this.watch.bind(this);
|
|
12
|
+
if (key === 'on')
|
|
13
|
+
return this.on.bind(this);
|
|
14
|
+
if (key === 'keys')
|
|
15
|
+
return () => Array.from(this._components.keys());
|
|
16
|
+
if (key === 'snapshot')
|
|
17
|
+
return () => this.snapshot();
|
|
18
|
+
if (key === 'dump')
|
|
19
|
+
return () => this.dump();
|
|
20
|
+
const component = this._components.get(key);
|
|
21
|
+
if (!component)
|
|
22
|
+
return undefined;
|
|
23
|
+
return this._createComponentProxy(key, component);
|
|
24
|
+
},
|
|
25
|
+
set: (_target, key, value) => {
|
|
26
|
+
// Allow setting entire component value shorthand
|
|
27
|
+
// pageState['input1'] = 'hello' → sets value
|
|
28
|
+
const component = this._components.get(key);
|
|
29
|
+
if (component && typeof value === 'string') {
|
|
30
|
+
const old = component.getValue?.() ?? undefined;
|
|
31
|
+
component.setValue?.(value) ?? component.value?.(value);
|
|
32
|
+
this._notify(key, 'value', value, old);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
},
|
|
37
|
+
has: (_target, key) => {
|
|
38
|
+
return this._components.has(key);
|
|
39
|
+
},
|
|
40
|
+
ownKeys: () => {
|
|
41
|
+
return Array.from(this._components.keys());
|
|
42
|
+
},
|
|
43
|
+
getOwnPropertyDescriptor: (_target, key) => {
|
|
44
|
+
if (this._components.has(key)) {
|
|
45
|
+
return { configurable: true, enumerable: true, value: this._proxy[key] };
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Register a component into pageState.
|
|
53
|
+
* Called automatically by jux components on creation.
|
|
54
|
+
*/
|
|
55
|
+
register(id, component) {
|
|
56
|
+
this._components.set(id, component);
|
|
57
|
+
// Wire up change events to auto-notify
|
|
58
|
+
if (typeof component.onChange === 'function') {
|
|
59
|
+
const originalOnChange = component._onChange;
|
|
60
|
+
component.onChange((value, event) => {
|
|
61
|
+
originalOnChange?.(value, event);
|
|
62
|
+
this._notify(id, 'value', value, undefined);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Watch for property changes on any component.
|
|
68
|
+
*
|
|
69
|
+
* Usage:
|
|
70
|
+
* pageState.watch('input1', 'value', (newVal, oldVal) => { ... })
|
|
71
|
+
* pageState.watch('*', 'value', (key, prop, newVal) => { ... }) // wildcard
|
|
72
|
+
*/
|
|
73
|
+
watch(keyOrAll, prop, fn) {
|
|
74
|
+
const listener = (key, p, value, oldValue) => {
|
|
75
|
+
if ((keyOrAll === '*' || keyOrAll === key) && (prop === '*' || prop === p)) {
|
|
76
|
+
fn(value, oldValue, key);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
this._listeners.add(listener);
|
|
80
|
+
return () => this._listeners.delete(listener);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Listen for ephemeral events (blur, focus, hover, etc.)
|
|
84
|
+
*
|
|
85
|
+
* Usage:
|
|
86
|
+
* pageState.on('input2', 'blur', () => { pageState['input1'] = ''; })
|
|
87
|
+
* pageState.on('input1', 'focus', () => { ... })
|
|
88
|
+
*/
|
|
89
|
+
on(id, event, fn) {
|
|
90
|
+
if (!this._eventListeners.has(id)) {
|
|
91
|
+
this._eventListeners.set(id, new Map());
|
|
92
|
+
}
|
|
93
|
+
const componentEvents = this._eventListeners.get(id);
|
|
94
|
+
if (!componentEvents.has(event)) {
|
|
95
|
+
componentEvents.set(event, new Set());
|
|
96
|
+
}
|
|
97
|
+
componentEvents.get(event).add(fn);
|
|
98
|
+
// Wire DOM event if component is already registered
|
|
99
|
+
const component = this._components.get(id);
|
|
100
|
+
if (component) {
|
|
101
|
+
this._wireDOMEvent(id, event, component);
|
|
102
|
+
}
|
|
103
|
+
return () => {
|
|
104
|
+
componentEvents.get(event)?.delete(fn);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Emit an ephemeral event (called internally by components)
|
|
109
|
+
*/
|
|
110
|
+
emit(id, event, detail) {
|
|
111
|
+
const listeners = this._eventListeners.get(id)?.get(event);
|
|
112
|
+
if (listeners) {
|
|
113
|
+
listeners.forEach(fn => fn(detail));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get a snapshot of all component values
|
|
118
|
+
*/
|
|
119
|
+
snapshot() {
|
|
120
|
+
const result = {};
|
|
121
|
+
for (const [id, component] of this._components) {
|
|
122
|
+
result[id] = {
|
|
123
|
+
value: component.getValue?.() ?? component.opts?.value ?? undefined,
|
|
124
|
+
type: component.opts?.type ?? component.tagName ?? 'unknown',
|
|
125
|
+
id
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Log current state to console
|
|
132
|
+
*/
|
|
133
|
+
dump() {
|
|
134
|
+
console.table(this.snapshot());
|
|
135
|
+
}
|
|
136
|
+
getProxy() {
|
|
137
|
+
return this._proxy;
|
|
138
|
+
}
|
|
139
|
+
_notify(key, prop, value, oldValue) {
|
|
140
|
+
for (const listener of this._listeners) {
|
|
141
|
+
listener(key, prop, value, oldValue);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_wireDOMEvent(id, event, component) {
|
|
145
|
+
// Find the actual DOM element
|
|
146
|
+
const el = component._element ?? component._wrapper ?? document.getElementById(id);
|
|
147
|
+
if (!el)
|
|
148
|
+
return;
|
|
149
|
+
// Avoid double-wiring
|
|
150
|
+
const wiredKey = `__jux_wired_${event}`;
|
|
151
|
+
if (el[wiredKey])
|
|
152
|
+
return;
|
|
153
|
+
el[wiredKey] = true;
|
|
154
|
+
el.addEventListener(event, (e) => {
|
|
155
|
+
this.emit(id, event, e);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
_createComponentProxy(id, component) {
|
|
159
|
+
const self = this;
|
|
160
|
+
return new Proxy({}, {
|
|
161
|
+
get(_target, prop) {
|
|
162
|
+
// Special properties
|
|
163
|
+
if (prop === 'id')
|
|
164
|
+
return id;
|
|
165
|
+
if (prop === 'value')
|
|
166
|
+
return component.getValue?.() ?? component.opts?.value ?? undefined;
|
|
167
|
+
if (prop === 'type')
|
|
168
|
+
return component.opts?.type ?? component.tagName ?? 'unknown';
|
|
169
|
+
if (prop === 'disabled')
|
|
170
|
+
return component.opts?.disabled ?? false;
|
|
171
|
+
if (prop === 'focused')
|
|
172
|
+
return document.activeElement === (component._element ?? document.getElementById(id));
|
|
173
|
+
if (prop === 'element')
|
|
174
|
+
return component._element ?? document.getElementById(id);
|
|
175
|
+
if (prop === '_component')
|
|
176
|
+
return component;
|
|
177
|
+
// Check for ephemeral event state methods
|
|
178
|
+
if (prop === 'on')
|
|
179
|
+
return (event, fn) => self.on(id, event, fn);
|
|
180
|
+
if (prop === 'watch')
|
|
181
|
+
return (p, fn) => self.watch(id, p, fn);
|
|
182
|
+
// Forward to component options
|
|
183
|
+
if (component.opts && prop in component.opts)
|
|
184
|
+
return component.opts[prop];
|
|
185
|
+
// Forward to component methods
|
|
186
|
+
if (typeof component[prop] === 'function')
|
|
187
|
+
return component[prop].bind(component);
|
|
188
|
+
return undefined;
|
|
189
|
+
},
|
|
190
|
+
set(_target, prop, value) {
|
|
191
|
+
const old = component.getValue?.() ?? component.opts?.[prop] ?? undefined;
|
|
192
|
+
if (prop === 'value') {
|
|
193
|
+
component.setValue?.(value) ?? component.value?.(value);
|
|
194
|
+
self._notify(id, 'value', value, old);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
if (prop === 'disabled') {
|
|
198
|
+
component.disabled?.(value);
|
|
199
|
+
self._notify(id, 'disabled', value, old);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (component.opts) {
|
|
203
|
+
component.opts[prop] = value;
|
|
204
|
+
self._notify(id, prop, value, old);
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Singleton
|
|
212
|
+
const _instance = new PageState();
|
|
213
|
+
export const pageState = _instance.getProxy();
|
|
214
|
+
export { PageState };
|