juxscript 1.1.270 → 1.1.273
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/components/input.d.ts +2 -0
- package/dist/lib/components/input.d.ts.map +1 -1
- package/dist/lib/components/input.js +13 -0
- package/dist/lib/components/tag.d.ts +8 -1
- package/dist/lib/components/tag.d.ts.map +1 -1
- package/dist/lib/components/tag.js +17 -3
- package/dist/lib/state/pageState.d.ts +2 -1
- package/dist/lib/state/pageState.d.ts.map +1 -1
- package/dist/lib/state/pageState.js +65 -5
- package/machinery/serve.js +18 -14
- package/package.json +1 -1
|
@@ -35,7 +35,9 @@ declare class Input {
|
|
|
35
35
|
class(value: string): this;
|
|
36
36
|
onChange(fn: (value: string, event: Event) => void): this;
|
|
37
37
|
getValue(): string;
|
|
38
|
+
getFiles(): FileList | null;
|
|
38
39
|
setValue(val: string): this;
|
|
40
|
+
setContent(val: string): this;
|
|
39
41
|
render(target?: string | HTMLElement): this;
|
|
40
42
|
}
|
|
41
43
|
export declare function input(id: string, options?: InputOptions): Input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../lib/components/input.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElK,UAAU,YAAY;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,cAAM,KAAK;IACP,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,SAAS,CAAwD;gBAE7D,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB;IASlD,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAC5B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAChC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACzB,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAE1B,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAKzD,QAAQ,IAAI,MAAM;IAIlB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM3B,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../lib/components/input.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElK,UAAU,YAAY;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,cAAM,KAAK;IACP,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,SAAS,CAAwD;gBAE7D,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB;IASlD,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAC5B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAChC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACzB,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,QAAQ,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IACrC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAE1B,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAKzD,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,QAAQ,GAAG,IAAI;IAI3B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM3B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;CAqDvC;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK,CAKnE;AAED,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -31,12 +31,18 @@ class Input {
|
|
|
31
31
|
getValue() {
|
|
32
32
|
return this._element?.value ?? this.options.value ?? '';
|
|
33
33
|
}
|
|
34
|
+
getFiles() {
|
|
35
|
+
return this._element?.files ?? null;
|
|
36
|
+
}
|
|
34
37
|
setValue(val) {
|
|
35
38
|
if (this._element)
|
|
36
39
|
this._element.value = val;
|
|
37
40
|
this.options.value = val;
|
|
38
41
|
return this;
|
|
39
42
|
}
|
|
43
|
+
setContent(val) {
|
|
44
|
+
return this.setValue(val);
|
|
45
|
+
}
|
|
40
46
|
render(target) {
|
|
41
47
|
const wrapper = document.createElement('div');
|
|
42
48
|
wrapper.className = 'jux-input';
|
|
@@ -82,6 +88,13 @@ class Input {
|
|
|
82
88
|
if (this._onChange)
|
|
83
89
|
this._onChange(input.value, e);
|
|
84
90
|
});
|
|
91
|
+
// For file inputs, also listen to 'change'
|
|
92
|
+
if (this.options.type === 'file') {
|
|
93
|
+
input.addEventListener('change', (e) => {
|
|
94
|
+
if (this._onChange)
|
|
95
|
+
this._onChange(input.value, e);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
85
98
|
wrapper.appendChild(input);
|
|
86
99
|
this._element = input;
|
|
87
100
|
this._wrapper = wrapper;
|
|
@@ -13,8 +13,15 @@ declare class Tag {
|
|
|
13
13
|
content(value: string): this;
|
|
14
14
|
class(value: string): this;
|
|
15
15
|
style(value: string): this;
|
|
16
|
-
|
|
16
|
+
getValue(): string;
|
|
17
|
+
getContent(): string;
|
|
18
|
+
setValue(val: string): this;
|
|
19
|
+
setContent(val: string): this;
|
|
20
|
+
setClass(val: string): this;
|
|
21
|
+
setStyle(val: string): this;
|
|
22
|
+
setInnerHTML(val: string): this;
|
|
17
23
|
getElement(): HTMLElement | null;
|
|
24
|
+
render(target?: string | HTMLElement): this;
|
|
18
25
|
}
|
|
19
26
|
export declare function tag(id: string, tagName: string, options?: TagOptions): Tag;
|
|
20
27
|
export declare function div(id: string, options?: TagOptions): Tag;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../lib/components/tag.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../lib/components/tag.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,cAAM,GAAG;IACL,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe;IAOjE,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC5B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAG1B,QAAQ,IAAI,MAAM;IAClB,UAAU,IAAI,MAAM;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC3B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC3B,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAE/B,UAAU,IAAI,WAAW,GAAG,IAAI;IAEhC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;CAqBvC;AAED,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAKxE;AAED,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAqC;AAC7F,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAsC;AAC/F,wBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAmC;AACzF,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAsC;AAC/F,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAqC;AAC7F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAC3F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAC3F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAC3F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAC3F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAC3F,wBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAAoC;AAE3F,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AAC3B,eAAe,GAAG,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import generateId from '../utils/idgen.js';
|
|
2
|
+
import { pageState } from '../state/pageState.js';
|
|
2
3
|
class Tag {
|
|
3
4
|
constructor(id, tagName, options = {}) {
|
|
4
5
|
this._element = null;
|
|
@@ -9,9 +10,23 @@ class Tag {
|
|
|
9
10
|
// Fluent API
|
|
10
11
|
content(value) { this.opts.content = value; if (this._element)
|
|
11
12
|
this._element.textContent = value; return this; }
|
|
12
|
-
class(value) { this.opts.class = value;
|
|
13
|
+
class(value) { this.opts.class = value; if (this._element)
|
|
14
|
+
this._element.className = value; return this; }
|
|
13
15
|
style(value) { this.opts.style = value; if (this._element)
|
|
14
16
|
this._element.setAttribute('style', value); return this; }
|
|
17
|
+
// Getters/Setters for pageState integration
|
|
18
|
+
getValue() { return this._element?.textContent ?? this.opts.content ?? ''; }
|
|
19
|
+
getContent() { return this._element?.textContent ?? this.opts.content ?? ''; }
|
|
20
|
+
setValue(val) { this.opts.content = val; if (this._element)
|
|
21
|
+
this._element.textContent = val; return this; }
|
|
22
|
+
setContent(val) { return this.setValue(val); }
|
|
23
|
+
setClass(val) { this.opts.class = val; if (this._element)
|
|
24
|
+
this._element.className = val; return this; }
|
|
25
|
+
setStyle(val) { this.opts.style = val; if (this._element)
|
|
26
|
+
this._element.setAttribute('style', val); return this; }
|
|
27
|
+
setInnerHTML(val) { if (this._element)
|
|
28
|
+
this._element.innerHTML = val; return this; }
|
|
29
|
+
getElement() { return this._element; }
|
|
15
30
|
render(target) {
|
|
16
31
|
const el = document.createElement(this.tagName);
|
|
17
32
|
el.id = this.id;
|
|
@@ -21,7 +36,6 @@ class Tag {
|
|
|
21
36
|
el.className = this.opts.class;
|
|
22
37
|
if (this.opts.style)
|
|
23
38
|
el.setAttribute('style', this.opts.style);
|
|
24
|
-
// Apply any extra attributes
|
|
25
39
|
for (const [key, value] of Object.entries(this.opts)) {
|
|
26
40
|
if (['content', 'class', 'style'].includes(key))
|
|
27
41
|
continue;
|
|
@@ -34,11 +48,11 @@ class Tag {
|
|
|
34
48
|
container?.appendChild(el);
|
|
35
49
|
return this;
|
|
36
50
|
}
|
|
37
|
-
getElement() { return this._element; }
|
|
38
51
|
}
|
|
39
52
|
export function tag(id, tagName, options = {}) {
|
|
40
53
|
const t = new Tag(id, tagName, options);
|
|
41
54
|
t.render();
|
|
55
|
+
pageState.__register(t);
|
|
42
56
|
return t;
|
|
43
57
|
}
|
|
44
58
|
export function div(id, options = {}) { return tag(id, 'div', options); }
|
|
@@ -1,12 +1,13 @@
|
|
|
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
|
+
static readonly WIRE_EVENTS: readonly ["blur", "focus", "click", "dblclick", "change", "input", "keydown", "keyup", "keypress", "mouseenter", "mouseleave", "mousedown", "mouseup", "submit"];
|
|
5
5
|
constructor();
|
|
6
6
|
private _createComponentProxy;
|
|
7
7
|
private _register;
|
|
8
8
|
private _wireEvent;
|
|
9
9
|
private _findElement;
|
|
10
|
+
private _wireStateFlag;
|
|
10
11
|
private _unregister;
|
|
11
12
|
private _notify;
|
|
12
13
|
private _watch;
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,mKAQhB;;IA2BX,OAAO,CAAC,qBAAqB;IAoF7B,OAAO,CAAC,SAAS;IA+DjB,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,cAAc;IAuBtB,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"}
|
|
@@ -42,16 +42,27 @@ class PageState {
|
|
|
42
42
|
}
|
|
43
43
|
reactionDeps.get(activeReaction).add(depKey);
|
|
44
44
|
}
|
|
45
|
+
// Event flags
|
|
45
46
|
if (prop in entry.events) {
|
|
46
47
|
return entry.events[prop];
|
|
47
48
|
}
|
|
49
|
+
// Component props
|
|
48
50
|
if (prop in entry.props) {
|
|
49
51
|
return entry.props[prop];
|
|
50
52
|
}
|
|
53
|
+
// Special: files for file inputs
|
|
54
|
+
if (prop === 'files') {
|
|
55
|
+
const comp = entry.component;
|
|
56
|
+
if (typeof comp.getFiles === 'function') {
|
|
57
|
+
return comp.getFiles();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Component methods
|
|
51
61
|
const comp = entry.component;
|
|
52
62
|
if (typeof comp[prop] === 'function') {
|
|
53
63
|
return comp[prop].bind(comp);
|
|
54
64
|
}
|
|
65
|
+
// Getter pattern
|
|
55
66
|
const getterName = `get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
56
67
|
if (typeof comp[getterName] === 'function') {
|
|
57
68
|
return comp[getterName]();
|
|
@@ -64,14 +75,29 @@ class PageState {
|
|
|
64
75
|
set: (_, prop, value) => {
|
|
65
76
|
const depKey = `${id}.${prop}`;
|
|
66
77
|
const comp = entry.component;
|
|
78
|
+
// Try setXxx first (e.g. setValue, setContent, setClass)
|
|
67
79
|
const setterName = `set${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
68
80
|
if (typeof comp[setterName] === 'function') {
|
|
69
81
|
comp[setterName](value);
|
|
70
82
|
}
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
// Fallback: direct DOM manipulation for known props
|
|
84
|
+
else if (prop === 'content' || prop === 'value') {
|
|
85
|
+
if (typeof comp.setValue === 'function') {
|
|
86
|
+
comp.setValue(value);
|
|
87
|
+
}
|
|
88
|
+
else if (typeof comp.setContent === 'function') {
|
|
89
|
+
comp.setContent(value);
|
|
90
|
+
}
|
|
73
91
|
}
|
|
92
|
+
else if (prop === 'innerHTML') {
|
|
93
|
+
if (typeof comp.setInnerHTML === 'function') {
|
|
94
|
+
comp.setInnerHTML(value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Don't call fluent methods as setters — they return `this`
|
|
98
|
+
// Update tracked props
|
|
74
99
|
entry.props[prop] = value;
|
|
100
|
+
// Notify listeners
|
|
75
101
|
this._notify(depKey);
|
|
76
102
|
return true;
|
|
77
103
|
}
|
|
@@ -81,14 +107,30 @@ class PageState {
|
|
|
81
107
|
const id = component.id;
|
|
82
108
|
if (!id)
|
|
83
109
|
return;
|
|
110
|
+
// Check if already registered — preserve event listeners
|
|
111
|
+
const existing = this._registry.get(id);
|
|
112
|
+
if (existing) {
|
|
113
|
+
// Update component reference and re-seed props
|
|
114
|
+
existing.component = component;
|
|
115
|
+
if (component.getValue)
|
|
116
|
+
existing.props.value = component.getValue();
|
|
117
|
+
if (component.getContent)
|
|
118
|
+
existing.props.content = component.getContent();
|
|
119
|
+
if (component.getValues)
|
|
120
|
+
existing.props.values = component.getValues();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
84
123
|
const entry = {
|
|
85
124
|
component,
|
|
86
125
|
props: {},
|
|
87
126
|
events: {},
|
|
88
127
|
listeners: new Map()
|
|
89
128
|
};
|
|
129
|
+
// Seed initial props
|
|
90
130
|
if (component.getValue)
|
|
91
131
|
entry.props.value = component.getValue();
|
|
132
|
+
if (component.getContent)
|
|
133
|
+
entry.props.content = component.getContent();
|
|
92
134
|
if (component.getValues)
|
|
93
135
|
entry.props.values = component.getValues();
|
|
94
136
|
if (component.opts || component.options) {
|
|
@@ -102,8 +144,8 @@ class PageState {
|
|
|
102
144
|
}
|
|
103
145
|
entry.props.id = id;
|
|
104
146
|
this._registry.set(id, entry);
|
|
147
|
+
// Wire onChange — use internal callback pattern, don't replace
|
|
105
148
|
if (typeof component.onChange === 'function') {
|
|
106
|
-
const originalOnChange = component._onChange;
|
|
107
149
|
component.onChange((val, e) => {
|
|
108
150
|
if (Array.isArray(val)) {
|
|
109
151
|
entry.props.values = val;
|
|
@@ -117,13 +159,16 @@ class PageState {
|
|
|
117
159
|
entry.props.value = val;
|
|
118
160
|
this._notify(`${id}.value`);
|
|
119
161
|
}
|
|
120
|
-
if (originalOnChange)
|
|
121
|
-
originalOnChange(val, e);
|
|
122
162
|
});
|
|
123
163
|
}
|
|
164
|
+
// Wire DOM events
|
|
124
165
|
for (const eventName of PageState.WIRE_EVENTS) {
|
|
125
166
|
this._wireEvent(id, entry, eventName);
|
|
126
167
|
}
|
|
168
|
+
// Wire composite state flags: hover, active, focused
|
|
169
|
+
this._wireStateFlag(id, entry, 'hover', 'mouseenter', 'mouseleave');
|
|
170
|
+
this._wireStateFlag(id, entry, 'active', 'mousedown', 'mouseup');
|
|
171
|
+
this._wireStateFlag(id, entry, 'focused', 'focus', 'blur');
|
|
127
172
|
}
|
|
128
173
|
_wireEvent(id, entry, eventName) {
|
|
129
174
|
entry.events[eventName] = false;
|
|
@@ -165,6 +210,20 @@ class PageState {
|
|
|
165
210
|
}
|
|
166
211
|
return null;
|
|
167
212
|
}
|
|
213
|
+
_wireStateFlag(id, entry, flagName, onEvent, offEvent) {
|
|
214
|
+
entry.events[flagName] = false;
|
|
215
|
+
const el = this._findElement(entry.component);
|
|
216
|
+
if (!el)
|
|
217
|
+
return;
|
|
218
|
+
el.addEventListener(onEvent, () => {
|
|
219
|
+
entry.events[flagName] = true;
|
|
220
|
+
this._notify(`${id}.${flagName}`);
|
|
221
|
+
});
|
|
222
|
+
el.addEventListener(offEvent, () => {
|
|
223
|
+
entry.events[flagName] = false;
|
|
224
|
+
this._notify(`${id}.${flagName}`);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
168
227
|
_unregister(id) {
|
|
169
228
|
this._registry.delete(id);
|
|
170
229
|
}
|
|
@@ -211,6 +270,7 @@ PageState.WIRE_EVENTS = [
|
|
|
211
270
|
'change', 'input',
|
|
212
271
|
'keydown', 'keyup', 'keypress',
|
|
213
272
|
'mouseenter', 'mouseleave',
|
|
273
|
+
'mousedown', 'mouseup',
|
|
214
274
|
'submit'
|
|
215
275
|
];
|
|
216
276
|
// Singleton
|
package/machinery/serve.js
CHANGED
|
@@ -114,14 +114,16 @@ const FRUITS = ['mango', 'blueberry', 'raspberry', 'kiwi', 'pineapple', 'strawbe
|
|
|
114
114
|
app.get('/api/test', (req, res) => {
|
|
115
115
|
res.json({
|
|
116
116
|
randomFruit: FRUITS[Math.floor(Math.random() * FRUITS.length)],
|
|
117
|
-
|
|
118
|
-
{ id: 1, name: '
|
|
119
|
-
{ id: 2, name: '
|
|
120
|
-
{ id: 3, name: '
|
|
117
|
+
growers: [
|
|
118
|
+
{ id: 1, name: 'Berry Bliss Farm', region: 'Pacific Northwest', specialty: 'blueberry' },
|
|
119
|
+
{ id: 2, name: 'Tropical Sun Orchard', region: 'Hawaii', specialty: 'mango' },
|
|
120
|
+
{ id: 3, name: 'Bramble & Vine', region: 'Willamette Valley', specialty: 'raspberry' }
|
|
121
121
|
],
|
|
122
|
-
|
|
123
|
-
{ id: 1,
|
|
124
|
-
{ id: 2,
|
|
122
|
+
harvests: [
|
|
123
|
+
{ id: 1, fruit: 'blueberry', lbs: 1200, growerId: 1, season: 'summer' },
|
|
124
|
+
{ id: 2, fruit: 'raspberry', lbs: 800, growerId: 3, season: 'summer' },
|
|
125
|
+
{ id: 3, fruit: 'mango', lbs: 2400, growerId: 2, season: 'spring' },
|
|
126
|
+
{ id: 4, fruit: 'strawberry', lbs: 1600, growerId: 1, season: 'spring' }
|
|
125
127
|
],
|
|
126
128
|
timestamp: new Date().toISOString()
|
|
127
129
|
});
|
|
@@ -146,14 +148,16 @@ app.get('/api/test', (req, res) => {
|
|
|
146
148
|
|
|
147
149
|
res.json({
|
|
148
150
|
randomFruit,
|
|
149
|
-
|
|
150
|
-
{ id: 1, name: '
|
|
151
|
-
{ id: 2, name: '
|
|
152
|
-
{ id: 3, name: '
|
|
151
|
+
growers: [
|
|
152
|
+
{ id: 1, name: 'Berry Bliss Farm', region: 'Pacific Northwest', specialty: 'blueberry' },
|
|
153
|
+
{ id: 2, name: 'Tropical Sun Orchard', region: 'Hawaii', specialty: 'mango' },
|
|
154
|
+
{ id: 3, name: 'Bramble & Vine', region: 'Willamette Valley', specialty: 'raspberry' }
|
|
153
155
|
],
|
|
154
|
-
|
|
155
|
-
{ id: 1,
|
|
156
|
-
{ id: 2,
|
|
156
|
+
harvests: [
|
|
157
|
+
{ id: 1, fruit: 'blueberry', lbs: 1200, growerId: 1, season: 'summer' },
|
|
158
|
+
{ id: 2, fruit: 'raspberry', lbs: 800, growerId: 3, season: 'summer' },
|
|
159
|
+
{ id: 3, fruit: 'mango', lbs: 2400, growerId: 2, season: 'spring' },
|
|
160
|
+
{ id: 4, fruit: 'strawberry', lbs: 1600, growerId: 1, season: 'spring' }
|
|
157
161
|
],
|
|
158
162
|
timestamp: new Date().toISOString()
|
|
159
163
|
});
|