juxscript 1.1.265 → 1.1.268

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.
@@ -24,6 +24,11 @@ declare class Data {
24
24
  getLoading(): boolean;
25
25
  getError(): string | null;
26
26
  setValue(val: any): this;
27
+ /**
28
+ * Re-fetch the data and notify pageState.
29
+ * Triggers all watchers that depend on this data's value.
30
+ */
31
+ refresh(): Promise<any>;
27
32
  fetch(urlOverride?: string): Promise<any>;
28
33
  }
29
34
  /**
@@ -46,7 +51,7 @@ declare class Data {
46
51
  * await manual.fetch(); // fetch later
47
52
  *
48
53
  * // Re-fetch
49
- * await pageState['api'].component.fetch();
54
+ * await pageState['api'].refresh();
50
55
  */
51
56
  export declare function data(id: string, options?: DataOptions): Promise<Data>;
52
57
  export { Data, DataOptions };
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../lib/components/data.ts"],"names":[],"mappings":"AAGA,UAAU,WAAW;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,cAAM,IAAI;IACN,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAAuC;gBAE5C,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB;IAMjD,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACxB,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,IAAI;IAC1C,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAC5C,IAAI,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IACtB,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAEtC,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMxC,QAAQ,IAAI,GAAG;IACf,UAAU,IAAI,OAAO;IACrB,QAAQ,IAAI,MAAM,GAAG,IAAI;IAEzB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAMlB,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CA+DlD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/E;AAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../lib/components/data.ts"],"names":[],"mappings":"AAGA,UAAU,WAAW;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,cAAM,IAAI;IACN,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAAuC;gBAE5C,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB;IAMjD,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACxB,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,IAAI;IAC1C,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAC5C,IAAI,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IACtB,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAEtC,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMxC,QAAQ,IAAI,GAAG;IACf,UAAU,IAAI,OAAO;IACrB,QAAQ,IAAI,MAAM,GAAG,IAAI;IAEzB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAMxB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC;IAQvB,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CA+DlD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/E;AAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC"}
@@ -29,6 +29,17 @@ class Data {
29
29
  this._onChange(val);
30
30
  return this;
31
31
  }
32
+ /**
33
+ * Re-fetch the data and notify pageState.
34
+ * Triggers all watchers that depend on this data's value.
35
+ */
36
+ async refresh() {
37
+ const result = await this.fetch();
38
+ // Notify pageState so watchers re-run
39
+ pageState.__notify(`${this.id}.value`);
40
+ pageState.__notify(`${this.id}.loading`);
41
+ return result;
42
+ }
32
43
  async fetch(urlOverride) {
33
44
  const fetchUrl = urlOverride || this.options.url;
34
45
  if (!fetchUrl) {
@@ -104,14 +115,14 @@ class Data {
104
115
  * await manual.fetch(); // fetch later
105
116
  *
106
117
  * // Re-fetch
107
- * await pageState['api'].component.fetch();
118
+ * await pageState['api'].refresh();
108
119
  */
109
120
  export async function data(id, options = {}) {
110
121
  const d = new Data(id, options);
111
122
  pageState.__register(d);
112
123
  if (options.auto !== false && options.url) {
113
124
  await d.fetch();
114
- // Re-register after fetch so pageState has the value
125
+ // Re-register so pageState picks up the fetched value
115
126
  pageState.__register(d);
116
127
  }
117
128
  return d;
@@ -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":"AAaA,cAAM,SAAS;IACX,OAAO,CAAC,SAAS,CAA0C;IAC3D,OAAO,CAAC,MAAM,CAAsB;;IA6BpC,OAAO,CAAC,qBAAqB;IA4D7B;;;OAGG;IACH,OAAO,CAAC,SAAS;IA4CjB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,OAAO;IAQf;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM;IAgBd,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAI/B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAOjC;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":"AAaA,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;IAQf,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"}
@@ -19,11 +19,9 @@ class PageState {
19
19
  const entry = this._registry.get(id);
20
20
  if (!entry)
21
21
  return undefined;
22
- // Return a proxy for the component's state slice
23
22
  return this._createComponentProxy(id, entry);
24
23
  },
25
24
  set: (_, id, value) => {
26
- // pageState['input1'] = someComponent — register it
27
25
  if (value && typeof value === 'object' && value.id) {
28
26
  this._register(value);
29
27
  return true;
@@ -36,36 +34,33 @@ class PageState {
36
34
  return new Proxy({}, {
37
35
  get: (_, prop) => {
38
36
  const depKey = `${id}.${prop}`;
39
- // Track dependency if inside a reactive block
40
37
  if (activeReaction) {
41
38
  if (!reactionDeps.has(activeReaction)) {
42
39
  reactionDeps.set(activeReaction, new Set());
43
40
  }
44
41
  reactionDeps.get(activeReaction).add(depKey);
45
42
  }
46
- // Event flags (blur, focus, hover, etc.)
47
43
  if (prop in entry.events) {
48
44
  return entry.events[prop];
49
45
  }
50
- // Component props (value, disabled, checked, etc.)
51
46
  if (prop in entry.props) {
52
47
  return entry.props[prop];
53
48
  }
54
- // Fallback to component method/property
55
49
  const comp = entry.component;
56
- if (prop === 'component')
57
- return comp;
58
- if (typeof comp[`get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`] === 'function') {
59
- return comp[`get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`]();
50
+ if (typeof comp[prop] === 'function') {
51
+ return comp[prop].bind(comp);
52
+ }
53
+ const getterName = `get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
54
+ if (typeof comp[getterName] === 'function') {
55
+ return comp[getterName]();
60
56
  }
61
57
  if (prop in comp) {
62
- return typeof comp[prop] === 'function' ? comp[prop].bind(comp) : comp[prop];
58
+ return comp[prop];
63
59
  }
64
60
  return undefined;
65
61
  },
66
62
  set: (_, prop, value) => {
67
63
  const depKey = `${id}.${prop}`;
68
- // Update component via fluent API or setter
69
64
  const comp = entry.component;
70
65
  const setterName = `set${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
71
66
  if (typeof comp[setterName] === 'function') {
@@ -74,18 +69,12 @@ class PageState {
74
69
  else if (typeof comp[prop] === 'function') {
75
70
  comp[prop](value);
76
71
  }
77
- // Update tracked props
78
72
  entry.props[prop] = value;
79
- // Notify listeners
80
73
  this._notify(depKey);
81
74
  return true;
82
75
  }
83
76
  });
84
77
  }
85
- /**
86
- * Register a component with pageState.
87
- * Called automatically by jux components on creation.
88
- */
89
78
  _register(component) {
90
79
  const id = component.id;
91
80
  if (!id)
@@ -96,7 +85,6 @@ class PageState {
96
85
  events: {},
97
86
  listeners: new Map()
98
87
  };
99
- // Seed initial props from component
100
88
  if (component.getValue)
101
89
  entry.props.value = component.getValue();
102
90
  if (component.getValues)
@@ -112,7 +100,6 @@ class PageState {
112
100
  }
113
101
  entry.props.id = id;
114
102
  this._registry.set(id, entry);
115
- // Wire component onChange to update pageState
116
103
  if (typeof component.onChange === 'function') {
117
104
  const originalOnChange = component._onChange;
118
105
  component.onChange((val, e) => {
@@ -120,6 +107,10 @@ class PageState {
120
107
  entry.props.values = val;
121
108
  this._notify(`${id}.values`);
122
109
  }
110
+ else if (typeof val === 'boolean') {
111
+ entry.props.checked = val;
112
+ this._notify(`${id}.checked`);
113
+ }
123
114
  else {
124
115
  entry.props.value = val;
125
116
  this._notify(`${id}.value`);
@@ -128,31 +119,53 @@ class PageState {
128
119
  originalOnChange(val, e);
129
120
  });
130
121
  }
131
- // Wire common DOM events as boolean flags
132
- this._wireEvent(id, entry, 'blur');
133
- this._wireEvent(id, entry, 'focus');
122
+ for (const eventName of PageState.WIRE_EVENTS) {
123
+ this._wireEvent(id, entry, eventName);
124
+ }
134
125
  }
135
126
  _wireEvent(id, entry, eventName) {
136
127
  entry.events[eventName] = false;
137
- // Find the DOM element
138
- const el = entry.component._element || entry.component.getElement?.();
139
- if (!el || !(el instanceof HTMLElement))
128
+ const el = this._findElement(entry.component);
129
+ if (!el)
140
130
  return;
141
- el.addEventListener(eventName, () => {
131
+ el.addEventListener(eventName, (e) => {
142
132
  entry.events[eventName] = true;
133
+ if ((eventName === 'input' || eventName === 'change') && el instanceof HTMLInputElement) {
134
+ entry.props.value = el.value;
135
+ }
136
+ if ((eventName === 'input' || eventName === 'change') && el instanceof HTMLSelectElement) {
137
+ entry.props.value = el.value;
138
+ }
143
139
  this._notify(`${id}.${eventName}`);
144
- // Reset after reactions run
145
140
  queueMicrotask(() => {
146
141
  entry.events[eventName] = false;
147
142
  });
148
143
  });
149
144
  }
145
+ _findElement(component) {
146
+ if (component._element instanceof HTMLElement)
147
+ return component._element;
148
+ if (typeof component.getElement === 'function') {
149
+ const el = component.getElement();
150
+ if (el instanceof HTMLElement)
151
+ return el;
152
+ }
153
+ if (component._wrapper instanceof HTMLElement) {
154
+ const input = component._wrapper.querySelector('input, select, textarea, button');
155
+ if (input)
156
+ return input;
157
+ return component._wrapper;
158
+ }
159
+ if (component.id && typeof document !== 'undefined') {
160
+ const el = document.getElementById(component.id);
161
+ if (el)
162
+ return el;
163
+ }
164
+ return null;
165
+ }
150
166
  _unregister(id) {
151
167
  this._registry.delete(id);
152
168
  }
153
- /**
154
- * Notify all reactive blocks that depend on this key
155
- */
156
169
  _notify(depKey) {
157
170
  for (const [reaction, deps] of reactionDeps.entries()) {
158
171
  if (deps.has(depKey)) {
@@ -160,19 +173,8 @@ class PageState {
160
173
  }
161
174
  }
162
175
  }
163
- /**
164
- * Create a reactive block that re-runs when its dependencies change.
165
- *
166
- * Usage:
167
- * pageState.__watch(() => {
168
- * if (pageState['input1'].value === 'blueberry') {
169
- * pageState['input2'].value = 'raspberry';
170
- * }
171
- * });
172
- */
173
176
  _watch(fn) {
174
177
  const reaction = () => {
175
- // Clear old deps, track new ones during execution
176
178
  reactionDeps.set(reaction, new Set());
177
179
  activeReaction = reaction;
178
180
  try {
@@ -182,20 +184,20 @@ class PageState {
182
184
  activeReaction = null;
183
185
  }
184
186
  };
185
- // Run once immediately to collect initial dependencies
186
187
  reaction();
187
188
  }
188
189
  getProxy() {
189
190
  return this._proxy;
190
191
  }
191
- __notify(depKey) {
192
- for (const [reaction, deps] of reactionDeps.entries()) {
193
- if (deps.has(depKey)) {
194
- reaction();
195
- }
196
- }
197
- }
198
192
  }
193
+ PageState.WIRE_EVENTS = [
194
+ 'blur', 'focus',
195
+ 'click', 'dblclick',
196
+ 'change', 'input',
197
+ 'keydown', 'keyup', 'keypress',
198
+ 'mouseenter', 'mouseleave',
199
+ 'submit'
200
+ ];
199
201
  // Singleton
200
202
  const _instance = new PageState();
201
203
  export const pageState = _instance.getProxy();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.265",
3
+ "version": "1.1.268",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./dist/lib/index.js",