juxscript 1.1.254 → 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.
@@ -1,23 +1,33 @@
1
+ interface TagOptions {
2
+ content?: string;
3
+ class?: string;
4
+ style?: string;
5
+ [key: string]: any;
6
+ }
1
7
  declare class Tag {
2
8
  id: string;
3
- content: string;
4
- options: Record<string, any>;
5
9
  tagName: string;
6
- constructor(data: any);
7
- modify(): this;
8
- render(): HTMLElement;
10
+ opts: TagOptions;
11
+ private _element;
12
+ constructor(id: string, tagName: string, options?: TagOptions);
13
+ content(value: string): this;
14
+ class(value: string): this;
15
+ style(value: string): this;
16
+ render(target?: string | HTMLElement): this;
17
+ getElement(): HTMLElement | null;
9
18
  }
10
- export declare function tag(data: any): Tag;
11
- export declare function div(data?: any): Tag;
12
- export declare function span(data?: any): Tag;
13
- export declare function p(data?: any): Tag;
14
- export declare function code(data?: any): Tag;
15
- export declare function pre(data?: any): Tag;
16
- export declare function h1(data?: any): Tag;
17
- export declare function h2(data?: any): Tag;
18
- export declare function h3(data?: any): Tag;
19
- export declare function h4(data?: any): Tag;
20
- export declare function h5(data?: any): Tag;
21
- export declare function h6(data?: any): Tag;
19
+ export declare function tag(id: string, tagName: string, options?: TagOptions): Tag;
20
+ export declare function div(id: string, options?: TagOptions): Tag;
21
+ export declare function span(id: string, options?: TagOptions): Tag;
22
+ export declare function p(id: string, options?: TagOptions): Tag;
23
+ export declare function code(id: string, options?: TagOptions): Tag;
24
+ export declare function pre(id: string, options?: TagOptions): Tag;
25
+ export declare function h1(id: string, options?: TagOptions): Tag;
26
+ export declare function h2(id: string, options?: TagOptions): Tag;
27
+ export declare function h3(id: string, options?: TagOptions): Tag;
28
+ export declare function h4(id: string, options?: TagOptions): Tag;
29
+ export declare function h5(id: string, options?: TagOptions): Tag;
30
+ export declare function h6(id: string, options?: TagOptions): Tag;
31
+ export { Tag, TagOptions };
22
32
  export default tag;
23
33
  //# sourceMappingURL=tag.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../lib/components/tag.ts"],"names":[],"mappings":"AAEA,cAAM,GAAG;IACL,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;gBAEJ,IAAI,EAAE,GAAG;IAOrB,MAAM;IAIN,MAAM;CAWT;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,GAAG,OAI5B;AAED,wBAAgB,GAAG,CAAC,IAAI,GAAE,GAAQ,OAA8C;AAChF,wBAAgB,IAAI,CAAC,IAAI,GAAE,GAAQ,OAA+C;AAClF,wBAAgB,CAAC,CAAC,IAAI,GAAE,GAAQ,OAA4C;AAC5E,wBAAgB,IAAI,CAAC,IAAI,GAAE,GAAQ,OAA+C;AAClF,wBAAgB,GAAG,CAAC,IAAI,GAAE,GAAQ,OAA8C;AAChF,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAC9E,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAC9E,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAC9E,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAC9E,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAC9E,wBAAgB,EAAE,CAAC,IAAI,GAAE,GAAQ,OAA6C;AAE9E,eAAe,GAAG,CAAC"}
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,40 +1,56 @@
1
1
  import generateId from '../utils/idgen.js';
2
2
  class Tag {
3
- constructor(data) {
4
- this.id = generateId();
5
- this.content = data.content || '';
6
- this.options = data.options || {};
7
- this.tagName = data.tagName || 'div';
3
+ constructor(id, tagName, options = {}) {
4
+ this._element = null;
5
+ this.id = id || generateId();
6
+ this.tagName = tagName;
7
+ this.opts = options;
8
8
  }
9
- modify() {
10
- return this;
11
- }
12
- render() {
9
+ // Fluent API
10
+ content(value) { this.opts.content = value; if (this._element)
11
+ this._element.textContent = value; return this; }
12
+ class(value) { this.opts.class = value; return this; }
13
+ style(value) { this.opts.style = value; if (this._element)
14
+ this._element.setAttribute('style', value); return this; }
15
+ render(target) {
13
16
  const el = document.createElement(this.tagName);
14
17
  el.id = this.id;
15
- el.textContent = this.content;
16
- for (const [key, value] of Object.entries(this.options)) {
18
+ if (this.opts.content)
19
+ el.textContent = this.opts.content;
20
+ if (this.opts.class)
21
+ el.className = this.opts.class;
22
+ if (this.opts.style)
23
+ el.setAttribute('style', this.opts.style);
24
+ // Apply any extra attributes
25
+ for (const [key, value] of Object.entries(this.opts)) {
26
+ if (['content', 'class', 'style'].includes(key))
27
+ continue;
17
28
  el.setAttribute(key, String(value));
18
29
  }
19
- const app = document.getElementById('app');
20
- app?.appendChild(el);
21
- return el;
30
+ this._element = el;
31
+ const container = target
32
+ ? (typeof target === 'string' ? document.getElementById(target) || document.querySelector(target) : target)
33
+ : document.getElementById('app');
34
+ container?.appendChild(el);
35
+ return this;
22
36
  }
37
+ getElement() { return this._element; }
23
38
  }
24
- export function tag(data) {
25
- const t = new Tag(data);
39
+ export function tag(id, tagName, options = {}) {
40
+ const t = new Tag(id, tagName, options);
26
41
  t.render();
27
42
  return t;
28
43
  }
29
- export function div(data = {}) { return tag({ ...data, tagName: 'div' }); }
30
- export function span(data = {}) { return tag({ ...data, tagName: 'span' }); }
31
- export function p(data = {}) { return tag({ ...data, tagName: 'p' }); }
32
- export function code(data = {}) { return tag({ ...data, tagName: 'code' }); }
33
- export function pre(data = {}) { return tag({ ...data, tagName: 'pre' }); }
34
- export function h1(data = {}) { return tag({ ...data, tagName: 'h1' }); }
35
- export function h2(data = {}) { return tag({ ...data, tagName: 'h2' }); }
36
- export function h3(data = {}) { return tag({ ...data, tagName: 'h3' }); }
37
- export function h4(data = {}) { return tag({ ...data, tagName: 'h4' }); }
38
- export function h5(data = {}) { return tag({ ...data, tagName: 'h5' }); }
39
- export function h6(data = {}) { return tag({ ...data, tagName: 'h6' }); }
44
+ export function div(id, options = {}) { return tag(id, 'div', options); }
45
+ export function span(id, options = {}) { return tag(id, 'span', options); }
46
+ export function p(id, options = {}) { return tag(id, 'p', options); }
47
+ export function code(id, options = {}) { return tag(id, 'code', options); }
48
+ export function pre(id, options = {}) { return tag(id, 'pre', options); }
49
+ export function h1(id, options = {}) { return tag(id, 'h1', options); }
50
+ export function h2(id, options = {}) { return tag(id, 'h2', options); }
51
+ export function h3(id, options = {}) { return tag(id, 'h3', options); }
52
+ export function h4(id, options = {}) { return tag(id, 'h4', options); }
53
+ export function h5(id, options = {}) { return tag(id, 'h5', options); }
54
+ export function h6(id, options = {}) { return tag(id, 'h6', options); }
55
+ export { Tag };
40
56
  export default tag;
@@ -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
@@ -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;AAEnE,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;CAaf,CAAA"}
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, h2, h3, h4, h5, h6,
11
- p,
12
- span,
13
- pre,
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.254",
3
+ "version": "1.1.256",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./dist/lib/index.js",