juxscript 1.1.263 → 1.1.265

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.
@@ -0,0 +1,53 @@
1
+ interface DataOptions {
2
+ url?: string;
3
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
4
+ headers?: Record<string, string>;
5
+ body?: any;
6
+ transform?: (raw: any) => any;
7
+ auto?: boolean;
8
+ }
9
+ declare class Data {
10
+ id: string;
11
+ options: DataOptions;
12
+ private _value;
13
+ private _loading;
14
+ private _error;
15
+ private _onChange;
16
+ constructor(id: string, options?: DataOptions);
17
+ url(value: string): this;
18
+ method(value: DataOptions['method']): this;
19
+ headers(value: Record<string, string>): this;
20
+ body(value: any): this;
21
+ transform(fn: (raw: any) => any): this;
22
+ onChange(fn: (value: any) => void): this;
23
+ getValue(): any;
24
+ getLoading(): boolean;
25
+ getError(): string | null;
26
+ setValue(val: any): this;
27
+ fetch(urlOverride?: string): Promise<any>;
28
+ }
29
+ /**
30
+ * Create a data source that integrates with pageState.
31
+ *
32
+ * @example
33
+ * // Auto-fetch on creation
34
+ * const api = await jux.data('api', { url: '/api/test' });
35
+ * // pageState['api'].value → { users: [...], posts: [...] }
36
+ *
37
+ * // With transform
38
+ * const users = await jux.data('users', {
39
+ * url: '/api/test',
40
+ * transform: raw => raw.users
41
+ * });
42
+ * // pageState['users'].value → [{ id: 1, name: 'Alice' }, ...]
43
+ *
44
+ * // Manual fetch
45
+ * const manual = jux.data('manual', { url: '/api/test', auto: false });
46
+ * await manual.fetch(); // fetch later
47
+ *
48
+ * // Re-fetch
49
+ * await pageState['api'].component.fetch();
50
+ */
51
+ export declare function data(id: string, options?: DataOptions): Promise<Data>;
52
+ export { Data, DataOptions };
53
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,119 @@
1
+ import generateId from '../utils/idgen.js';
2
+ import { pageState } from '../state/pageState.js';
3
+ class Data {
4
+ constructor(id, options = {}) {
5
+ this._value = null;
6
+ this._loading = false;
7
+ this._error = null;
8
+ this._onChange = null;
9
+ this.id = id || generateId();
10
+ this.options = { method: 'GET', auto: true, ...options };
11
+ }
12
+ // Fluent API
13
+ url(value) { this.options.url = value; return this; }
14
+ method(value) { this.options.method = value; return this; }
15
+ headers(value) { this.options.headers = value; return this; }
16
+ body(value) { this.options.body = value; return this; }
17
+ transform(fn) { this.options.transform = fn; return this; }
18
+ onChange(fn) {
19
+ this._onChange = fn;
20
+ return this;
21
+ }
22
+ // Getters for pageState integration
23
+ getValue() { return this._value; }
24
+ getLoading() { return this._loading; }
25
+ getError() { return this._error; }
26
+ setValue(val) {
27
+ this._value = val;
28
+ if (this._onChange)
29
+ this._onChange(val);
30
+ return this;
31
+ }
32
+ async fetch(urlOverride) {
33
+ const fetchUrl = urlOverride || this.options.url;
34
+ if (!fetchUrl) {
35
+ this._error = 'No URL provided';
36
+ return null;
37
+ }
38
+ this._loading = true;
39
+ this._error = null;
40
+ // Notify pageState of loading change
41
+ if (pageState.__notify) {
42
+ pageState.__notify(`${this.id}.loading`);
43
+ }
44
+ try {
45
+ const fetchOptions = {
46
+ method: this.options.method,
47
+ headers: this.options.headers,
48
+ };
49
+ if (this.options.body && this.options.method !== 'GET') {
50
+ fetchOptions.body = typeof this.options.body === 'string'
51
+ ? this.options.body
52
+ : JSON.stringify(this.options.body);
53
+ if (!this.options.headers?.['Content-Type']) {
54
+ fetchOptions.headers = {
55
+ 'Content-Type': 'application/json',
56
+ ...fetchOptions.headers
57
+ };
58
+ }
59
+ }
60
+ const res = await globalThis.fetch(fetchUrl, fetchOptions);
61
+ if (!res.ok) {
62
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
63
+ }
64
+ const contentType = res.headers.get('content-type') || '';
65
+ let raw;
66
+ if (contentType.includes('application/json')) {
67
+ raw = await res.json();
68
+ }
69
+ else {
70
+ raw = await res.text();
71
+ }
72
+ this._value = this.options.transform ? this.options.transform(raw) : raw;
73
+ this._loading = false;
74
+ this._error = null;
75
+ if (this._onChange)
76
+ this._onChange(this._value);
77
+ return this._value;
78
+ }
79
+ catch (err) {
80
+ this._loading = false;
81
+ this._error = err.message || 'Fetch failed';
82
+ console.error(`❌ jux.data('${this.id}') fetch error:`, err.message);
83
+ return null;
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * Create a data source that integrates with pageState.
89
+ *
90
+ * @example
91
+ * // Auto-fetch on creation
92
+ * const api = await jux.data('api', { url: '/api/test' });
93
+ * // pageState['api'].value → { users: [...], posts: [...] }
94
+ *
95
+ * // With transform
96
+ * const users = await jux.data('users', {
97
+ * url: '/api/test',
98
+ * transform: raw => raw.users
99
+ * });
100
+ * // pageState['users'].value → [{ id: 1, name: 'Alice' }, ...]
101
+ *
102
+ * // Manual fetch
103
+ * const manual = jux.data('manual', { url: '/api/test', auto: false });
104
+ * await manual.fetch(); // fetch later
105
+ *
106
+ * // Re-fetch
107
+ * await pageState['api'].component.fetch();
108
+ */
109
+ export async function data(id, options = {}) {
110
+ const d = new Data(id, options);
111
+ pageState.__register(d);
112
+ if (options.auto !== false && options.url) {
113
+ await d.fetch();
114
+ // Re-register after fetch so pageState has the value
115
+ pageState.__register(d);
116
+ }
117
+ return d;
118
+ }
119
+ export { Data };
@@ -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 { data } from "./components/data.js";
7
8
  import { pageState } from "./state/pageState.js";
8
9
  export declare const jux: {
9
10
  tag: typeof tag;
@@ -23,6 +24,7 @@ export declare const jux: {
23
24
  radio: typeof radio;
24
25
  checkbox: typeof checkbox;
25
26
  checkboxGroup: typeof checkboxGroup;
27
+ data: typeof data;
26
28
  };
27
29
  export { pageState };
28
30
  //# 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;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;CAaf,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,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,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;CAcf,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
package/dist/lib/index.js 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 { data } from "./components/data.js";
7
8
  import { pageState } from "./state/pageState.js";
8
9
  export const jux = {
9
10
  tag,
@@ -17,8 +18,8 @@ export const jux = {
17
18
  select,
18
19
  radio,
19
20
  checkbox,
20
- checkboxGroup
21
+ checkboxGroup,
22
+ data
21
23
  };
22
24
  export { pageState };
23
- // Convenience: also put watch on jux
24
25
  jux.watch = pageState.__watch;
@@ -26,6 +26,7 @@ declare class PageState {
26
26
  */
27
27
  private _watch;
28
28
  getProxy(): Record<string, any>;
29
+ __notify(depKey: string): void;
29
30
  }
30
31
  export declare const pageState: Record<string, any>;
31
32
  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;;IA4BpC,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;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":"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"}
@@ -12,6 +12,8 @@ class PageState {
12
12
  return this._watch.bind(this);
13
13
  if (id === '__unregister')
14
14
  return this._unregister.bind(this);
15
+ if (id === '__notify')
16
+ return this._notify.bind(this);
15
17
  if (id === '__keys')
16
18
  return () => Array.from(this._registry.keys());
17
19
  const entry = this._registry.get(id);
@@ -186,6 +188,13 @@ class PageState {
186
188
  getProxy() {
187
189
  return this._proxy;
188
190
  }
191
+ __notify(depKey) {
192
+ for (const [reaction, deps] of reactionDeps.entries()) {
193
+ if (deps.has(depKey)) {
194
+ reaction();
195
+ }
196
+ }
197
+ }
189
198
  }
190
199
  // Singleton
191
200
  const _instance = new PageState();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.263",
3
+ "version": "1.1.265",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "./dist/lib/index.js",