juxscript 1.1.262 → 1.1.264
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/data.d.ts +53 -0
- package/dist/lib/components/data.d.ts.map +1 -0
- package/dist/lib/components/data.js +119 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +3 -2
- package/dist/lib/state/pageState.d.ts +1 -0
- package/dist/lib/state/pageState.d.ts.map +1 -1
- package/dist/lib/state/pageState.js +9 -0
- package/machinery/serve.js +5 -1
- package/package.json +1 -1
|
@@ -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 };
|
package/dist/lib/index.d.ts
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 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
|
package/dist/lib/index.d.ts.map
CHANGED
|
@@ -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
|
|
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;
|
|
@@ -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;;
|
|
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/machinery/serve.js
CHANGED
|
@@ -112,7 +112,7 @@ app.get('/favicon.png', (req, res) => res.status(204).end());
|
|
|
112
112
|
app.get('/api/test', (_req, res) => {
|
|
113
113
|
const fruits = ['apple', 'banana', 'orange', 'mango', 'strawberry', 'grape', 'watermelon', 'pineapple', 'kiwi', 'peach'];
|
|
114
114
|
const randomFruit = fruits[Math.floor(Math.random() * fruits.length)];
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
res.json({
|
|
117
117
|
randomFruit,
|
|
118
118
|
users: [
|
|
@@ -142,7 +142,11 @@ app.get('/__jux_sources.json', (req, res) => {
|
|
|
142
142
|
// API ROUTES — must come BEFORE static middleware and catch-all
|
|
143
143
|
// ═══════════════════════════════════════════════════════════════
|
|
144
144
|
app.get('/api/test', (req, res) => {
|
|
145
|
+
const fruits = ['apple', 'banana', 'orange', 'mango', 'strawberry', 'grape', 'watermelon', 'pineapple', 'kiwi', 'peach'];
|
|
146
|
+
const randomFruit = fruits[Math.floor(Math.random() * fruits.length)];
|
|
147
|
+
|
|
145
148
|
res.json({
|
|
149
|
+
randomFruit,
|
|
146
150
|
users: [
|
|
147
151
|
{ id: 1, name: 'Alice', email: 'alice@example.com' },
|
|
148
152
|
{ id: 2, name: 'Bob', email: 'bob@example.com' },
|