juxscript 1.0.62 → 1.0.64
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/bin/cli.js +161 -293
- package/docs/v2comps/HEADLESS.md +83 -0
- package/docs/v2comps/ISOMORPHISM.md +10 -0
- package/juxconfig.example.js +63 -58
- package/lib/componentsv2/base/BaseEngine.js +258 -0
- package/lib/componentsv2/base/BaseEngine.js.map +1 -0
- package/lib/componentsv2/base/BaseEngine.ts +303 -0
- package/lib/componentsv2/base/BaseSkin.js +108 -0
- package/lib/componentsv2/base/BaseSkin.js.map +1 -0
- package/lib/componentsv2/base/BaseSkin.ts +137 -0
- package/lib/componentsv2/base/GlobalBus.js +56 -0
- package/lib/componentsv2/base/GlobalBus.js.map +1 -0
- package/lib/componentsv2/base/GlobalBus.ts +60 -0
- package/lib/componentsv2/base/State.js +68 -0
- package/lib/componentsv2/base/State.js.map +1 -0
- package/lib/componentsv2/base/State.ts +62 -0
- package/lib/componentsv2/grid/component.js +41 -0
- package/lib/componentsv2/grid/component.js.map +1 -0
- package/lib/componentsv2/grid/component.ts +67 -0
- package/lib/componentsv2/grid/engine.js +73 -0
- package/lib/componentsv2/grid/engine.js.map +1 -0
- package/lib/componentsv2/grid/engine.ts +110 -0
- package/lib/componentsv2/grid/skin.js +95 -0
- package/lib/componentsv2/grid/skin.js.map +1 -0
- package/lib/componentsv2/grid/skin.ts +105 -0
- package/lib/componentsv2/grid/structure.css +58 -0
- package/lib/componentsv2/index.js +218 -0
- package/lib/componentsv2/index.js.map +1 -0
- package/lib/componentsv2/index.ts +253 -0
- package/lib/componentsv2/input/component.js +21 -0
- package/lib/componentsv2/input/component.js.map +1 -0
- package/lib/componentsv2/input/component.ts +28 -0
- package/lib/componentsv2/input/engine.js +50 -0
- package/lib/componentsv2/input/engine.js.map +1 -0
- package/lib/componentsv2/input/engine.ts +76 -0
- package/lib/componentsv2/input/skin.js +91 -0
- package/lib/componentsv2/input/skin.js.map +1 -0
- package/lib/componentsv2/input/skin.ts +91 -0
- package/lib/componentsv2/input/structure.css +47 -0
- package/lib/componentsv2/list/component.js +83 -0
- package/lib/componentsv2/list/component.js.map +1 -0
- package/lib/componentsv2/list/component.ts +97 -0
- package/lib/componentsv2/list/engine.js +261 -0
- package/lib/componentsv2/list/engine.js.map +1 -0
- package/lib/componentsv2/list/engine.ts +345 -0
- package/lib/componentsv2/list/skin.js +343 -0
- package/lib/componentsv2/list/skin.js.map +1 -0
- package/lib/componentsv2/list/skin.ts +367 -0
- package/lib/componentsv2/list/structure.css +359 -0
- package/lib/componentsv2/plugins/ClientSQLitePlugin.js +130 -0
- package/lib/componentsv2/plugins/ClientSQLitePlugin.js.map +1 -0
- package/lib/componentsv2/plugins/ClientSQLitePlugin.ts +154 -0
- package/lib/componentsv2/plugins/IndexedDBPlugin.js +75 -0
- package/lib/componentsv2/plugins/IndexedDBPlugin.js.map +1 -0
- package/lib/componentsv2/plugins/IndexedDBPlugin.ts +96 -0
- package/lib/componentsv2/plugins/LocalStoragePlugin.js +65 -0
- package/lib/componentsv2/plugins/LocalStoragePlugin.js.map +1 -0
- package/lib/componentsv2/plugins/LocalStoragePlugin.ts +86 -0
- package/lib/componentsv2/plugins/ServerSQLitePlugin.js +70 -0
- package/lib/componentsv2/plugins/ServerSQLitePlugin.js.map +1 -0
- package/lib/componentsv2/plugins/ServerSQLitePlugin.ts +99 -0
- package/lib/componentsv2/stubs/ComponentComposition.ts.stub +32 -0
- package/lib/componentsv2/stubs/ComponentEngine.ts.stub +36 -0
- package/lib/componentsv2/stubs/ComponentSkin.ts.stub +34 -0
- package/lib/componentsv2/stubs/ComponentStructure.css.stub +13 -0
- package/lib/componentsv2/tools/CreateSkin.js +62 -0
- package/lib/componentsv2/tools/DocSpam.js +134 -0
- package/lib/componentsv2/tools/FluencyAudit.js +141 -0
- package/lib/componentsv2/tools/OptionsAudit.js +177 -0
- package/lib/componentsv2/tools/Scaffold.js +140 -0
- package/lib/utils/fetch.js +428 -0
- package/lib/utils/fetch.js.map +1 -0
- package/machinery/build.js +2 -1
- package/machinery/compiler.js +200 -37
- package/machinery/config.js +93 -6
- package/machinery/diagnose.js +72 -0
- package/machinery/jux-module-pattern.md +118 -0
- package/machinery/server.js +23 -7
- package/machinery/verifier.js +143 -0
- package/machinery/watcher.js +53 -64
- package/package.json +11 -2
- package/lib/components/alert.ts +0 -200
- package/lib/components/app.ts +0 -258
- package/lib/components/badge.ts +0 -101
- package/lib/components/base/BaseComponent.ts +0 -417
- package/lib/components/base/FormInput.ts +0 -227
- package/lib/components/button.ts +0 -178
- package/lib/components/card.ts +0 -173
- package/lib/components/chart.ts +0 -231
- package/lib/components/checkbox.ts +0 -242
- package/lib/components/code.ts +0 -123
- package/lib/components/container.ts +0 -140
- package/lib/components/data.ts +0 -135
- package/lib/components/datepicker.ts +0 -234
- package/lib/components/dialog.ts +0 -172
- package/lib/components/divider.ts +0 -100
- package/lib/components/dropdown.ts +0 -186
- package/lib/components/element.ts +0 -267
- package/lib/components/error-handler.ts +0 -285
- package/lib/components/fileupload.ts +0 -309
- package/lib/components/grid.ts +0 -291
- package/lib/components/guard.ts +0 -92
- package/lib/components/heading.ts +0 -96
- package/lib/components/helpers.ts +0 -41
- package/lib/components/hero.ts +0 -224
- package/lib/components/icon.ts +0 -160
- package/lib/components/icons.ts +0 -175
- package/lib/components/include.ts +0 -440
- package/lib/components/input.ts +0 -457
- package/lib/components/list.ts +0 -419
- package/lib/components/loading.ts +0 -100
- package/lib/components/menu.ts +0 -260
- package/lib/components/modal.ts +0 -239
- package/lib/components/nav.ts +0 -257
- package/lib/components/paragraph.ts +0 -97
- package/lib/components/progress.ts +0 -139
- package/lib/components/radio.ts +0 -278
- package/lib/components/req.ts +0 -302
- package/lib/components/script.ts +0 -43
- package/lib/components/select.ts +0 -252
- package/lib/components/sidebar.ts +0 -167
- package/lib/components/style.ts +0 -43
- package/lib/components/switch.ts +0 -246
- package/lib/components/table.ts +0 -1249
- package/lib/components/tabs.ts +0 -250
- package/lib/components/theme-toggle.ts +0 -300
- package/lib/components/token-calculator.ts +0 -313
- package/lib/components/tooltip.ts +0 -144
- package/lib/components/view.ts +0 -190
- package/lib/components/write.ts +0 -272
- package/lib/jux.ts +0 -365
- package/lib/layouts/default.css +0 -260
- package/lib/layouts/figma.css +0 -334
- package/lib/reactivity/state.ts +0 -78
- package/machinery/bundleAssets.js +0 -0
- package/machinery/bundleJux.js +0 -0
- package/machinery/bundleVendors.js +0 -0
- package/presets/default/all.jux +0 -343
- package/presets/default/index.jux +0 -90
- package/presets/default/layout.jux +0 -57
- package/presets/default/style.css +0 -1612
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB Plugin
|
|
3
|
+
* Asynchronous persistence for larger datasets.
|
|
4
|
+
*/
|
|
5
|
+
export const IndexedDBPlugin = (config) => ({
|
|
6
|
+
name: 'indexed-db-persist',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
targetEnv: 'client',
|
|
9
|
+
install: (engine) => {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
const initialState = engine.state[config.bindTo];
|
|
12
|
+
if (initialState !== undefined && !Array.isArray(initialState)) {
|
|
13
|
+
console.error(`[IndexedDBPlugin] 🛑 Configuration Error: bindTo='${config.bindTo}' is not an Array. This plugin is designed for List/Collection data.`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
let db = null;
|
|
17
|
+
const request = indexedDB.open(config.dbName, 1);
|
|
18
|
+
// 1. Schema Setup
|
|
19
|
+
request.onupgradeneeded = (e) => {
|
|
20
|
+
const d = e.target.result;
|
|
21
|
+
if (!d.objectStoreNames.contains(config.storeName)) {
|
|
22
|
+
d.createObjectStore(config.storeName);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
// 2. IO Operations
|
|
26
|
+
const save = (data) => {
|
|
27
|
+
if (!db)
|
|
28
|
+
return;
|
|
29
|
+
const tx = db.transaction([config.storeName], 'readwrite');
|
|
30
|
+
const store = tx.objectStore(config.storeName);
|
|
31
|
+
store.put(data, 'state_snapshot'); // Storing entire bound state as one blob for simplicity
|
|
32
|
+
};
|
|
33
|
+
const load = () => {
|
|
34
|
+
if (!db)
|
|
35
|
+
return;
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
if (typeof engine.loading === 'function')
|
|
38
|
+
engine.loading(true);
|
|
39
|
+
const tx = db.transaction([config.storeName], 'readonly');
|
|
40
|
+
const store = tx.objectStore(config.storeName);
|
|
41
|
+
const req = store.get('state_snapshot');
|
|
42
|
+
req.onsuccess = () => {
|
|
43
|
+
if (req.result) {
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
engine.updateState({ [config.bindTo]: req.result });
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
if (engine.emit)
|
|
48
|
+
engine.emit('plugin:hydrated', { source: 'IndexedDB' });
|
|
49
|
+
}
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
if (typeof engine.loading === 'function')
|
|
52
|
+
engine.loading(false);
|
|
53
|
+
};
|
|
54
|
+
req.onerror = () => {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
if (typeof engine.loading === 'function')
|
|
57
|
+
engine.loading(false);
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
// 3. Initialization
|
|
61
|
+
request.onsuccess = (e) => {
|
|
62
|
+
db = e.target.result;
|
|
63
|
+
if (config.autoLoad) {
|
|
64
|
+
load();
|
|
65
|
+
}
|
|
66
|
+
// Auto-save subscription (debounced slightly in real world, direct here)
|
|
67
|
+
engine.subscribe((state) => {
|
|
68
|
+
if (db)
|
|
69
|
+
save(state[config.bindTo]);
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
request.onerror = (e) => console.error('[IndexedDBPlugin] Open Error', e);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=IndexedDBPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexedDBPlugin.js","sourceRoot":"","sources":["IndexedDBPlugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { JuxServiceContract, BaseEngine } from '../base/BaseEngine.js';
|
|
2
|
+
|
|
3
|
+
export interface IndexedDBConfig {
|
|
4
|
+
dbName: string;
|
|
5
|
+
storeName: string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* State Binding: The property key on the Engine's state to persist.
|
|
9
|
+
* e.g., 'items'
|
|
10
|
+
*/
|
|
11
|
+
bindTo: string;
|
|
12
|
+
|
|
13
|
+
/** If true, loads data immediately on install */
|
|
14
|
+
autoLoad?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* IndexedDB Plugin
|
|
19
|
+
* Asynchronous persistence for larger datasets.
|
|
20
|
+
*/
|
|
21
|
+
export const IndexedDBPlugin = (config: IndexedDBConfig): JuxServiceContract<BaseEngine<any>> => ({
|
|
22
|
+
name: 'indexed-db-persist',
|
|
23
|
+
version: '1.0.0',
|
|
24
|
+
targetEnv: 'client',
|
|
25
|
+
|
|
26
|
+
install: (engine) => {
|
|
27
|
+
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
const initialState = engine.state[config.bindTo];
|
|
30
|
+
if (initialState !== undefined && !Array.isArray(initialState)) {
|
|
31
|
+
console.error(`[IndexedDBPlugin] 🛑 Configuration Error: bindTo='${config.bindTo}' is not an Array. This plugin is designed for List/Collection data.`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let db: IDBDatabase | null = null;
|
|
36
|
+
const request = indexedDB.open(config.dbName, 1);
|
|
37
|
+
|
|
38
|
+
// 1. Schema Setup
|
|
39
|
+
request.onupgradeneeded = (e: any) => {
|
|
40
|
+
const d = e.target.result;
|
|
41
|
+
if (!d.objectStoreNames.contains(config.storeName)) {
|
|
42
|
+
d.createObjectStore(config.storeName);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// 2. IO Operations
|
|
47
|
+
const save = (data: any) => {
|
|
48
|
+
if (!db) return;
|
|
49
|
+
const tx = db.transaction([config.storeName], 'readwrite');
|
|
50
|
+
const store = tx.objectStore(config.storeName);
|
|
51
|
+
store.put(data, 'state_snapshot'); // Storing entire bound state as one blob for simplicity
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const load = () => {
|
|
55
|
+
if (!db) return;
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
if (typeof engine.loading === 'function') engine.loading(true);
|
|
58
|
+
|
|
59
|
+
const tx = db.transaction([config.storeName], 'readonly');
|
|
60
|
+
const store = tx.objectStore(config.storeName);
|
|
61
|
+
const req = store.get('state_snapshot');
|
|
62
|
+
|
|
63
|
+
req.onsuccess = () => {
|
|
64
|
+
if (req.result) {
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
engine.updateState({ [config.bindTo]: req.result });
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
if (engine.emit) engine.emit('plugin:hydrated', { source: 'IndexedDB' });
|
|
69
|
+
}
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
if (typeof engine.loading === 'function') engine.loading(false);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
req.onerror = () => {
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
if (typeof engine.loading === 'function') engine.loading(false);
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// 3. Initialization
|
|
81
|
+
request.onsuccess = (e: any) => {
|
|
82
|
+
db = e.target.result;
|
|
83
|
+
|
|
84
|
+
if (config.autoLoad) {
|
|
85
|
+
load();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Auto-save subscription (debounced slightly in real world, direct here)
|
|
89
|
+
engine.subscribe((state) => {
|
|
90
|
+
if (db) save(state[config.bindTo]);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
request.onerror = (e) => console.error('[IndexedDBPlugin] Open Error', e);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalStorage Plugin
|
|
3
|
+
* Persists a slice of Engine State to Browser LocalStorage.
|
|
4
|
+
*/
|
|
5
|
+
export const LocalStoragePlugin = (config) => ({
|
|
6
|
+
name: 'local-storage-persist',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
targetEnv: 'client',
|
|
9
|
+
install: (engine) => {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
const initialState = engine.state[config.bindTo];
|
|
12
|
+
if (initialState !== undefined && !Array.isArray(initialState)) {
|
|
13
|
+
console.error(`[LocalStoragePlugin] 🛑 Configuration Error: bindTo='${config.bindTo}' is not an Array. This plugin is designed for List/Collection data.`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const storageKey = `jux:${config.key}`;
|
|
17
|
+
// 1. Hydrate (Load from Storage)
|
|
18
|
+
const load = () => {
|
|
19
|
+
try {
|
|
20
|
+
const raw = localStorage.getItem(storageKey);
|
|
21
|
+
if (raw) {
|
|
22
|
+
const data = JSON.parse(raw);
|
|
23
|
+
// @ts-ignore - Generic update
|
|
24
|
+
engine.updateState({ [config.bindTo]: data });
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
if (engine.emit)
|
|
27
|
+
engine.emit('plugin:hydrated', { source: 'localStorage', count: Array.isArray(data) ? data.length : 1 });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
console.error('[LocalStoragePlugin] Load Failed', e);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
// 2. Persist (Save to Storage)
|
|
35
|
+
const save = (state) => {
|
|
36
|
+
try {
|
|
37
|
+
const value = state[config.bindTo];
|
|
38
|
+
localStorage.setItem(storageKey, JSON.stringify(value));
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.error('[LocalStoragePlugin] Save Failed', e);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Logic
|
|
45
|
+
if (config.clearOnInstall) {
|
|
46
|
+
localStorage.removeItem(storageKey);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
load();
|
|
50
|
+
}
|
|
51
|
+
if (config.autoSave !== false) {
|
|
52
|
+
engine.subscribe((state) => save(state));
|
|
53
|
+
}
|
|
54
|
+
// Expose manual triggers
|
|
55
|
+
engine.on('storage:save', () => save(engine.state));
|
|
56
|
+
engine.on('storage:load', load);
|
|
57
|
+
engine.on('storage:clear', () => {
|
|
58
|
+
localStorage.removeItem(storageKey);
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
if (engine.emit)
|
|
61
|
+
engine.emit('plugin:cleared', { source: 'localStorage' });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=LocalStoragePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalStoragePlugin.js","sourceRoot":"","sources":["LocalStoragePlugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { JuxServiceContract, BaseEngine } from '../base/BaseEngine.js';
|
|
2
|
+
|
|
3
|
+
export interface LocalStorageConfig {
|
|
4
|
+
/** Unique key for storage (e.g. 'my-app-list-v1') */
|
|
5
|
+
key: string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* State Binding: The property key on the Engine's state to persist.
|
|
9
|
+
* e.g., 'items' for a ListEngine.
|
|
10
|
+
*/
|
|
11
|
+
bindTo: string;
|
|
12
|
+
|
|
13
|
+
/** If true, clears storage on install (fresh start) */
|
|
14
|
+
clearOnInstall?: boolean;
|
|
15
|
+
|
|
16
|
+
/** If true, automatically saves to storage when state changes */
|
|
17
|
+
autoSave?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* LocalStorage Plugin
|
|
22
|
+
* Persists a slice of Engine State to Browser LocalStorage.
|
|
23
|
+
*/
|
|
24
|
+
export const LocalStoragePlugin = (config: LocalStorageConfig): JuxServiceContract<BaseEngine<any>> => ({
|
|
25
|
+
name: 'local-storage-persist',
|
|
26
|
+
version: '1.0.0',
|
|
27
|
+
targetEnv: 'client',
|
|
28
|
+
|
|
29
|
+
install: (engine) => {
|
|
30
|
+
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
const initialState = engine.state[config.bindTo];
|
|
33
|
+
if (initialState !== undefined && !Array.isArray(initialState)) {
|
|
34
|
+
console.error(`[LocalStoragePlugin] 🛑 Configuration Error: bindTo='${config.bindTo}' is not an Array. This plugin is designed for List/Collection data.`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const storageKey = `jux:${config.key}`;
|
|
39
|
+
|
|
40
|
+
// 1. Hydrate (Load from Storage)
|
|
41
|
+
const load = () => {
|
|
42
|
+
try {
|
|
43
|
+
const raw = localStorage.getItem(storageKey);
|
|
44
|
+
if (raw) {
|
|
45
|
+
const data = JSON.parse(raw);
|
|
46
|
+
// @ts-ignore - Generic update
|
|
47
|
+
engine.updateState({ [config.bindTo]: data });
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
if (engine.emit) engine.emit('plugin:hydrated', { source: 'localStorage', count: Array.isArray(data) ? data.length : 1 });
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error('[LocalStoragePlugin] Load Failed', e);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// 2. Persist (Save to Storage)
|
|
57
|
+
const save = (state: any) => {
|
|
58
|
+
try {
|
|
59
|
+
const value = state[config.bindTo];
|
|
60
|
+
localStorage.setItem(storageKey, JSON.stringify(value));
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error('[LocalStoragePlugin] Save Failed', e);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Logic
|
|
67
|
+
if (config.clearOnInstall) {
|
|
68
|
+
localStorage.removeItem(storageKey);
|
|
69
|
+
} else {
|
|
70
|
+
load();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (config.autoSave !== false) {
|
|
74
|
+
engine.subscribe((state) => save(state));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Expose manual triggers
|
|
78
|
+
engine.on('storage:save', () => save(engine.state));
|
|
79
|
+
engine.on('storage:load', load);
|
|
80
|
+
engine.on('storage:clear', () => {
|
|
81
|
+
localStorage.removeItem(storageKey);
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
if (engine.emit) engine.emit('plugin:cleared', { source: 'localStorage' });
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-Side SQLite Plugin
|
|
3
|
+
* Decoupled Service that injects SQL capabilities and binds data to ANY Engine state.
|
|
4
|
+
*/
|
|
5
|
+
export const ServerSQLitePlugin = (config) => ({
|
|
6
|
+
name: 'server-sqlite-driver',
|
|
7
|
+
version: '2.0.0',
|
|
8
|
+
targetEnv: 'server',
|
|
9
|
+
install: (engine) => {
|
|
10
|
+
// 1. Expose SQL Capability (Mixin)
|
|
11
|
+
// Adds a .query() method to the engine instance
|
|
12
|
+
Object.assign(engine, {
|
|
13
|
+
query: (sql, params = []) => {
|
|
14
|
+
if (!config.database || typeof config.database.prepare !== 'function') {
|
|
15
|
+
throw new Error('Invalid Database Driver provided to ServerSQLitePlugin.');
|
|
16
|
+
}
|
|
17
|
+
const stmt = config.database.prepare(sql);
|
|
18
|
+
const rows = stmt.all(params);
|
|
19
|
+
// Emit audit event for queries
|
|
20
|
+
// @ts-ignore - access protected emit
|
|
21
|
+
if (typeof engine.emit === 'function')
|
|
22
|
+
engine.emit('sql:query', { sql, rows: rows.length });
|
|
23
|
+
return rows;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
// 2. Hydration Logic
|
|
27
|
+
const hydrate = () => {
|
|
28
|
+
if (!config.query)
|
|
29
|
+
return;
|
|
30
|
+
try {
|
|
31
|
+
// Use the newly injected capability
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
const rows = engine.query(config.query);
|
|
34
|
+
if (config.bindTo) {
|
|
35
|
+
const data = config.mapRow ? rows.map(config.mapRow) : rows;
|
|
36
|
+
// Generic State Update (Decoupled from ListEngine)
|
|
37
|
+
// @ts-ignore - access protected updateState
|
|
38
|
+
if (typeof engine.updateState === 'function') {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
engine.updateState({ [config.bindTo]: data });
|
|
41
|
+
}
|
|
42
|
+
// Optional: Update loading state if the engine supports it
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
if (typeof engine.loading === 'function')
|
|
45
|
+
engine.loading(false);
|
|
46
|
+
// Emit data event for loose coupling
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
if (typeof engine.emit === 'function')
|
|
49
|
+
engine.emit('plugin:data', { source: 'sqlite', count: data.length });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
console.error('[ServerSQLitePlugin] Hydration Error:', err.message);
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
if (typeof engine.loading === 'function')
|
|
56
|
+
engine.loading(false);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
// 3. Auto-Start
|
|
60
|
+
if (config.autoLoad) {
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
if (typeof engine.loading === 'function')
|
|
63
|
+
engine.loading(true);
|
|
64
|
+
hydrate();
|
|
65
|
+
}
|
|
66
|
+
// 4. Listen for Reload Signal
|
|
67
|
+
engine.on('db:reload', hydrate);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=ServerSQLitePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerSQLitePlugin.js","sourceRoot":"","sources":["ServerSQLitePlugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { JuxServiceContract, BaseEngine } from '../base/BaseEngine.js';
|
|
2
|
+
|
|
3
|
+
export interface ServerSQLiteConfig {
|
|
4
|
+
/** The Database Driver Instance (e.g. better-sqlite3) */
|
|
5
|
+
database: any;
|
|
6
|
+
|
|
7
|
+
/** Optional: SQL Query to fetch data automatically */
|
|
8
|
+
query?: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* State Binding: The property key on the Engine's state to populate.
|
|
12
|
+
* e.g., 'items' for a ListEngine, or 'rows' for a GridEngine.
|
|
13
|
+
*/
|
|
14
|
+
bindTo?: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Transformation Strategy:
|
|
18
|
+
* Converts a raw DB row into the shape expected by the Engine's state.
|
|
19
|
+
*/
|
|
20
|
+
mapRow?: (row: any) => any;
|
|
21
|
+
|
|
22
|
+
/** If true, runs the query immediately on install */
|
|
23
|
+
autoLoad?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Server-Side SQLite Plugin
|
|
28
|
+
* Decoupled Service that injects SQL capabilities and binds data to ANY Engine state.
|
|
29
|
+
*/
|
|
30
|
+
export const ServerSQLitePlugin = (config: ServerSQLiteConfig): JuxServiceContract<BaseEngine<any>> => ({
|
|
31
|
+
name: 'server-sqlite-driver',
|
|
32
|
+
version: '2.0.0',
|
|
33
|
+
targetEnv: 'server',
|
|
34
|
+
|
|
35
|
+
install: (engine) => {
|
|
36
|
+
// 1. Expose SQL Capability (Mixin)
|
|
37
|
+
// Adds a .query() method to the engine instance
|
|
38
|
+
Object.assign(engine, {
|
|
39
|
+
query: (sql: string, params: any[] = []) => {
|
|
40
|
+
if (!config.database || typeof config.database.prepare !== 'function') {
|
|
41
|
+
throw new Error('Invalid Database Driver provided to ServerSQLitePlugin.');
|
|
42
|
+
}
|
|
43
|
+
const stmt = config.database.prepare(sql);
|
|
44
|
+
const rows = stmt.all(params);
|
|
45
|
+
|
|
46
|
+
// Emit audit event for queries
|
|
47
|
+
// @ts-ignore - access protected emit
|
|
48
|
+
if (typeof engine.emit === 'function') engine.emit('sql:query', { sql, rows: rows.length });
|
|
49
|
+
|
|
50
|
+
return rows;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// 2. Hydration Logic
|
|
55
|
+
const hydrate = () => {
|
|
56
|
+
if (!config.query) return;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Use the newly injected capability
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
const rows = engine.query(config.query);
|
|
62
|
+
|
|
63
|
+
if (config.bindTo) {
|
|
64
|
+
const data = config.mapRow ? rows.map(config.mapRow) : rows;
|
|
65
|
+
|
|
66
|
+
// Generic State Update (Decoupled from ListEngine)
|
|
67
|
+
// @ts-ignore - access protected updateState
|
|
68
|
+
if (typeof engine.updateState === 'function') {
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
engine.updateState({ [config.bindTo]: data });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Optional: Update loading state if the engine supports it
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
if (typeof engine.loading === 'function') engine.loading(false);
|
|
76
|
+
|
|
77
|
+
// Emit data event for loose coupling
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
if (typeof engine.emit === 'function') engine.emit('plugin:data', { source: 'sqlite', count: data.length });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
} catch (err: any) {
|
|
83
|
+
console.error('[ServerSQLitePlugin] Hydration Error:', err.message);
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
if (typeof engine.loading === 'function') engine.loading(false);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// 3. Auto-Start
|
|
90
|
+
if (config.autoLoad) {
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
if (typeof engine.loading === 'function') engine.loading(true);
|
|
93
|
+
hydrate();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 4. Listen for Reload Signal
|
|
97
|
+
engine.on('db:reload', hydrate);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { [% ComponentName %]Engine, [% ComponentName %]Options } from './engine.js';
|
|
2
|
+
import { [% ComponentName %]Skin } from './skin.js';
|
|
3
|
+
|
|
4
|
+
export type [% ComponentName %]Component = [% ComponentName %]Engine & {
|
|
5
|
+
render: (targetId: string | HTMLElement) => [% ComponentName %]Component;
|
|
6
|
+
injectCSS: (id: string, cssContent: string) => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function [% ComponentName %](id: string, options: [% ComponentName %]Options = {}): [% ComponentName %]Component {
|
|
10
|
+
const engine = new [% ComponentName %]Engine(id, options);
|
|
11
|
+
|
|
12
|
+
if (typeof window !== 'undefined') {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
window.juxEngines = window.juxEngines || {};
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
window.juxEngines[id] = engine;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const skin = new [% ComponentName %]Skin(engine);
|
|
20
|
+
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
engine.render = (targetId: string | HTMLElement) => {
|
|
23
|
+
const target = typeof targetId === 'string' ? document.getElementById(targetId) : targetId;
|
|
24
|
+
if (target) skin.renderSkin(target);
|
|
25
|
+
return engine as [% ComponentName %]Component;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
engine.injectCSS = (id, css) => skin.injectCSS(id, css);
|
|
30
|
+
|
|
31
|
+
return engine as [% ComponentName %]Component;
|
|
32
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseEngine, BaseState } from '../base/BaseEngine.js';
|
|
2
|
+
|
|
3
|
+
export interface [% ComponentName %]State extends BaseState {
|
|
4
|
+
// TODO: Define your state properties
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface [% ComponentName %]Options {
|
|
9
|
+
// TODO: Define configuration options
|
|
10
|
+
text?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class [% ComponentName %]Engine extends BaseEngine<[% ComponentName %]State, [% ComponentName %]Options> {
|
|
14
|
+
constructor(id: string, options: [% ComponentName %]Options = {}) {
|
|
15
|
+
super(id, options);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected prepareState(id: string, options: [% ComponentName %]Options): [% ComponentName %]State {
|
|
19
|
+
return {
|
|
20
|
+
id,
|
|
21
|
+
classes: ['jux-[% component-name %]'],
|
|
22
|
+
visible: true,
|
|
23
|
+
disabled: false,
|
|
24
|
+
loading: false,
|
|
25
|
+
attributes: {},
|
|
26
|
+
text: options.text || 'Hello World'
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Example Mutator
|
|
31
|
+
setText(value: string): this {
|
|
32
|
+
this.updateState({ text: value });
|
|
33
|
+
this.emit('textChange', { value });
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BaseSkin } from '../base/BaseSkin.js';
|
|
2
|
+
import { [% ComponentName %]Engine, [% ComponentName %]State } from './engine.js';
|
|
3
|
+
|
|
4
|
+
export class [% ComponentName %]Skin extends BaseSkin<[% ComponentName %]State, [% ComponentName %]Engine> {
|
|
5
|
+
constructor(engine: [% ComponentName %]Engine) {
|
|
6
|
+
super(engine);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Define the structural CSS for this component.
|
|
11
|
+
*/
|
|
12
|
+
protected get structureCss(): string {
|
|
13
|
+
return new URL('./structure.css', import.meta.url).href;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected bindEvents(root: HTMLElement): void {
|
|
17
|
+
// TODO: Bind DOM events to Engine methods
|
|
18
|
+
root.addEventListener('click', () => {
|
|
19
|
+
console.log('[% ComponentName %] clicked');
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected updateSkin(state: [% ComponentName %]State): void {
|
|
24
|
+
if (!this.root) return;
|
|
25
|
+
this.applySkinAttributes(this.root, state);
|
|
26
|
+
|
|
27
|
+
// TODO: Render state to DOM
|
|
28
|
+
this.root.textContent = state.text;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected createRoot(): HTMLElement {
|
|
32
|
+
return document.createElement('div');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.jux-[% component-name %] {
|
|
2
|
+
display: block;
|
|
3
|
+
padding: var(--space-md);
|
|
4
|
+
border: 1px solid var(--color-border);
|
|
5
|
+
border-radius: var(--radius-sm);
|
|
6
|
+
background-color: var(--color-surface-base);
|
|
7
|
+
color: var(--color-text-primary);
|
|
8
|
+
transition: all var(--transition-fast);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.jux-[% component-name %]:hover {
|
|
12
|
+
background-color: var(--color-surface-hover);
|
|
13
|
+
}
|