juxscript 1.1.269 → 1.1.271

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.
@@ -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;CA8CvC;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK,CAKnE;AAED,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC"}
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
- render(target?: string | HTMLElement): this;
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":"AAEA,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;IAE1B,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;IAuBpC,UAAU,IAAI,WAAW,GAAG,IAAI;CACnC;AAED,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,OAIxE;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
+ {"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; return this; }
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 +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,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
+ {"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;IAoF7B,OAAO,CAAC,SAAS;IA0DjB,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"}
@@ -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
- else if (typeof comp[prop] === 'function') {
72
- comp[prop](value);
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
+ }
91
+ }
92
+ else if (prop === 'innerHTML') {
93
+ if (typeof comp.setInnerHTML === 'function') {
94
+ comp.setInnerHTML(value);
95
+ }
73
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,10 +159,9 @@ 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
  }
@@ -109,20 +109,21 @@ app.get('/favicon.png', (req, res) => res.status(204).end());
109
109
  // ═══════════════════════════════════════════════════════════════
110
110
  // API ROUTES — BEFORE static and catch-all
111
111
  // ═══════════════════════════════════════════════════════════════
112
- app.get('/api/test', (_req, res) => {
113
- const fruits = ['apple', 'banana', 'orange', 'mango', 'strawberry', 'grape', 'watermelon', 'pineapple', 'kiwi', 'peach'];
114
- const randomFruit = fruits[Math.floor(Math.random() * fruits.length)];
112
+ const FRUITS = ['mango', 'blueberry', 'raspberry', 'kiwi', 'pineapple', 'strawberry', 'banana', 'papaya', 'guava', 'dragonfruit'];
115
113
 
114
+ app.get('/api/test', (req, res) => {
116
115
  res.json({
117
- randomFruit,
118
- users: [
119
- { id: 1, name: 'Alice', email: 'alice@example.com' },
120
- { id: 2, name: 'Bob', email: 'bob@example.com' },
121
- { id: 3, name: 'Charlie', email: 'charlie@example.com' }
116
+ randomFruit: FRUITS[Math.floor(Math.random() * FRUITS.length)],
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' }
122
121
  ],
123
- posts: [
124
- { id: 1, title: 'Hello World', userId: 1 },
125
- { id: 2, title: 'Testing JUX', userId: 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' }
126
127
  ],
127
128
  timestamp: new Date().toISOString()
128
129
  });
@@ -147,14 +148,16 @@ app.get('/api/test', (req, res) => {
147
148
 
148
149
  res.json({
149
150
  randomFruit,
150
- users: [
151
- { id: 1, name: 'Alice', email: 'alice@example.com' },
152
- { id: 2, name: 'Bob', email: 'bob@example.com' },
153
- { id: 3, name: 'Charlie', email: 'charlie@example.com' }
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' }
154
155
  ],
155
- posts: [
156
- { id: 1, title: 'Hello World', userId: 1 },
157
- { id: 2, title: 'Testing JUX', userId: 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' }
158
161
  ],
159
162
  timestamp: new Date().toISOString()
160
163
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.269",
3
+ "version": "1.1.271",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./dist/lib/index.js",