juxscript 1.0.62 → 1.0.63
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,76 @@
|
|
|
1
|
+
import { BaseEngine, BaseState } from '../base/BaseEngine.js';
|
|
2
|
+
|
|
3
|
+
export interface InputState extends BaseState {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string | null;
|
|
6
|
+
placeholder: string;
|
|
7
|
+
type: 'text' | 'number' | 'password' | 'email';
|
|
8
|
+
error: string | null;
|
|
9
|
+
readonly: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface InputOptions {
|
|
13
|
+
value?: string | number;
|
|
14
|
+
label?: string;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
type?: 'text' | 'number' | 'password' | 'email';
|
|
17
|
+
readonly?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class InputEngine extends BaseEngine<InputState, InputOptions> {
|
|
21
|
+
|
|
22
|
+
constructor(id: string, options: InputOptions = {}) {
|
|
23
|
+
super(id, options);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
protected prepareState(id: string, options: InputOptions): InputState {
|
|
27
|
+
return {
|
|
28
|
+
id,
|
|
29
|
+
classes: ['jux-input-wrapper'],
|
|
30
|
+
visible: true,
|
|
31
|
+
disabled: false,
|
|
32
|
+
loading: false,
|
|
33
|
+
attributes: {},
|
|
34
|
+
value: options.value !== undefined ? String(options.value) : '',
|
|
35
|
+
label: options.label || null,
|
|
36
|
+
placeholder: options.placeholder || '',
|
|
37
|
+
type: options.type || 'text',
|
|
38
|
+
error: null,
|
|
39
|
+
readonly: options.readonly || false
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- Mutators ---
|
|
44
|
+
|
|
45
|
+
setValue(value: string | number): this {
|
|
46
|
+
this.updateState({ value: String(value) });
|
|
47
|
+
this.emit('change', { value });
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setLabel(label: string): this {
|
|
52
|
+
this.updateState({ label });
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setPlaceholder(text: string): this {
|
|
57
|
+
this.updateState({ placeholder: text });
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setError(message: string | null): this {
|
|
62
|
+
this.updateState({ error: message });
|
|
63
|
+
this.emit('validation', { valid: !message, error: message });
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setType(type: 'text' | 'number' | 'password' | 'email'): this {
|
|
68
|
+
this.updateState({ type });
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setReadonly(readonly: boolean): this {
|
|
73
|
+
this.updateState({ readonly });
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _InputSkin_labelEl, _InputSkin_inputEl, _InputSkin_errorEl;
|
|
13
|
+
import { BaseSkin } from '../base/BaseSkin.js';
|
|
14
|
+
export class InputSkin extends BaseSkin {
|
|
15
|
+
constructor(engine) {
|
|
16
|
+
super(engine);
|
|
17
|
+
_InputSkin_labelEl.set(this, null);
|
|
18
|
+
_InputSkin_inputEl.set(this, null);
|
|
19
|
+
_InputSkin_errorEl.set(this, null);
|
|
20
|
+
// Default aesthetic theme could be injected here
|
|
21
|
+
}
|
|
22
|
+
get structureCss() {
|
|
23
|
+
return new URL('./structure.css', import.meta.url).href;
|
|
24
|
+
}
|
|
25
|
+
createRoot() {
|
|
26
|
+
return document.createElement('div');
|
|
27
|
+
}
|
|
28
|
+
bindEvents(root) {
|
|
29
|
+
// We bind directly to the input element created in updateSkin
|
|
30
|
+
// delegation is tricky since we rebuild parts, but input is stable inside root usually.
|
|
31
|
+
root.addEventListener('input', (e) => {
|
|
32
|
+
const target = e.target;
|
|
33
|
+
if (target === __classPrivateFieldGet(this, _InputSkin_inputEl, "f")) {
|
|
34
|
+
this.engine.setValue(target.value);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
updateSkin(state) {
|
|
39
|
+
if (!this.root)
|
|
40
|
+
return;
|
|
41
|
+
this.applySkinAttributes(this.root, state);
|
|
42
|
+
// Ensure DOM Structure
|
|
43
|
+
if (!__classPrivateFieldGet(this, _InputSkin_inputEl, "f")) {
|
|
44
|
+
this.root.innerHTML = ''; // Reset
|
|
45
|
+
// 1. Label
|
|
46
|
+
__classPrivateFieldSet(this, _InputSkin_labelEl, document.createElement('label'), "f");
|
|
47
|
+
__classPrivateFieldGet(this, _InputSkin_labelEl, "f").className = 'jux-input-label';
|
|
48
|
+
__classPrivateFieldGet(this, _InputSkin_labelEl, "f").htmlFor = `input-${state.id}`;
|
|
49
|
+
this.root.appendChild(__classPrivateFieldGet(this, _InputSkin_labelEl, "f"));
|
|
50
|
+
// 2. Input
|
|
51
|
+
__classPrivateFieldSet(this, _InputSkin_inputEl, document.createElement('input'), "f");
|
|
52
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").id = `input-${state.id}`;
|
|
53
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").className = 'jux-input-control';
|
|
54
|
+
this.root.appendChild(__classPrivateFieldGet(this, _InputSkin_inputEl, "f"));
|
|
55
|
+
// 3. Error
|
|
56
|
+
__classPrivateFieldSet(this, _InputSkin_errorEl, document.createElement('div'), "f");
|
|
57
|
+
__classPrivateFieldGet(this, _InputSkin_errorEl, "f").className = 'jux-input-error';
|
|
58
|
+
this.root.appendChild(__classPrivateFieldGet(this, _InputSkin_errorEl, "f"));
|
|
59
|
+
}
|
|
60
|
+
// Apply State
|
|
61
|
+
this.root.className = state.classes.join(' ');
|
|
62
|
+
if (state.label) {
|
|
63
|
+
__classPrivateFieldGet(this, _InputSkin_labelEl, "f").textContent = state.label;
|
|
64
|
+
__classPrivateFieldGet(this, _InputSkin_labelEl, "f").style.display = 'block';
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
__classPrivateFieldGet(this, _InputSkin_labelEl, "f").style.display = 'none';
|
|
68
|
+
}
|
|
69
|
+
// Only update value if different to prevent cursor jumps
|
|
70
|
+
if (__classPrivateFieldGet(this, _InputSkin_inputEl, "f").value !== state.value) {
|
|
71
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").value = state.value;
|
|
72
|
+
}
|
|
73
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").type = state.type;
|
|
74
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").placeholder = state.placeholder;
|
|
75
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").disabled = state.disabled || state.loading;
|
|
76
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").readOnly = state.readonly;
|
|
77
|
+
if (state.error) {
|
|
78
|
+
__classPrivateFieldGet(this, _InputSkin_errorEl, "f").textContent = state.error;
|
|
79
|
+
__classPrivateFieldGet(this, _InputSkin_errorEl, "f").style.display = 'block';
|
|
80
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").setAttribute('aria-invalid', 'true');
|
|
81
|
+
this.root.classList.add('has-error');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
__classPrivateFieldGet(this, _InputSkin_errorEl, "f").style.display = 'none';
|
|
85
|
+
__classPrivateFieldGet(this, _InputSkin_inputEl, "f").removeAttribute('aria-invalid');
|
|
86
|
+
this.root.classList.remove('has-error');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
_InputSkin_labelEl = new WeakMap(), _InputSkin_inputEl = new WeakMap(), _InputSkin_errorEl = new WeakMap();
|
|
91
|
+
//# sourceMappingURL=skin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skin.js","sourceRoot":"","sources":["skin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { BaseSkin } from '../base/BaseSkin.js';
|
|
2
|
+
import { InputEngine, InputState } from './engine.js';
|
|
3
|
+
|
|
4
|
+
export class InputSkin extends BaseSkin<InputState, InputEngine> {
|
|
5
|
+
|
|
6
|
+
#labelEl: HTMLLabelElement | null = null;
|
|
7
|
+
#inputEl: HTMLInputElement | null = null;
|
|
8
|
+
#errorEl: HTMLElement | null = null;
|
|
9
|
+
|
|
10
|
+
constructor(engine: InputEngine) {
|
|
11
|
+
super(engine);
|
|
12
|
+
// Default aesthetic theme could be injected here
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected get structureCss(): string {
|
|
16
|
+
return new URL('./structure.css', import.meta.url).href;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected createRoot(): HTMLElement {
|
|
20
|
+
return document.createElement('div');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected bindEvents(root: HTMLElement): void {
|
|
24
|
+
// We bind directly to the input element created in updateSkin
|
|
25
|
+
// delegation is tricky since we rebuild parts, but input is stable inside root usually.
|
|
26
|
+
root.addEventListener('input', (e) => {
|
|
27
|
+
const target = e.target as HTMLInputElement;
|
|
28
|
+
if (target === this.#inputEl) {
|
|
29
|
+
this.engine.setValue(target.value);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected updateSkin(state: InputState): void {
|
|
35
|
+
if (!this.root) return;
|
|
36
|
+
this.applySkinAttributes(this.root, state);
|
|
37
|
+
|
|
38
|
+
// Ensure DOM Structure
|
|
39
|
+
if (!this.#inputEl) {
|
|
40
|
+
this.root.innerHTML = ''; // Reset
|
|
41
|
+
|
|
42
|
+
// 1. Label
|
|
43
|
+
this.#labelEl = document.createElement('label');
|
|
44
|
+
this.#labelEl.className = 'jux-input-label';
|
|
45
|
+
this.#labelEl.htmlFor = `input-${state.id}`;
|
|
46
|
+
this.root.appendChild(this.#labelEl);
|
|
47
|
+
|
|
48
|
+
// 2. Input
|
|
49
|
+
this.#inputEl = document.createElement('input');
|
|
50
|
+
this.#inputEl.id = `input-${state.id}`;
|
|
51
|
+
this.#inputEl.className = 'jux-input-control';
|
|
52
|
+
this.root.appendChild(this.#inputEl);
|
|
53
|
+
|
|
54
|
+
// 3. Error
|
|
55
|
+
this.#errorEl = document.createElement('div');
|
|
56
|
+
this.#errorEl.className = 'jux-input-error';
|
|
57
|
+
this.root.appendChild(this.#errorEl);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Apply State
|
|
61
|
+
this.root.className = state.classes.join(' ');
|
|
62
|
+
|
|
63
|
+
if (state.label) {
|
|
64
|
+
this.#labelEl!.textContent = state.label;
|
|
65
|
+
this.#labelEl!.style.display = 'block';
|
|
66
|
+
} else {
|
|
67
|
+
this.#labelEl!.style.display = 'none';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Only update value if different to prevent cursor jumps
|
|
71
|
+
if (this.#inputEl!.value !== state.value) {
|
|
72
|
+
this.#inputEl!.value = state.value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.#inputEl!.type = state.type;
|
|
76
|
+
this.#inputEl!.placeholder = state.placeholder;
|
|
77
|
+
this.#inputEl!.disabled = state.disabled || state.loading;
|
|
78
|
+
this.#inputEl!.readOnly = state.readonly;
|
|
79
|
+
|
|
80
|
+
if (state.error) {
|
|
81
|
+
this.#errorEl!.textContent = state.error;
|
|
82
|
+
this.#errorEl!.style.display = 'block';
|
|
83
|
+
this.#inputEl!.setAttribute('aria-invalid', 'true');
|
|
84
|
+
this.root.classList.add('has-error');
|
|
85
|
+
} else {
|
|
86
|
+
this.#errorEl!.style.display = 'none';
|
|
87
|
+
this.#inputEl!.removeAttribute('aria-invalid');
|
|
88
|
+
this.root.classList.remove('has-error');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
.jux-input-wrapper {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 4px; /* Space between label and input */
|
|
5
|
+
font-family: inherit;
|
|
6
|
+
width: 100%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.jux-input-label {
|
|
10
|
+
font-size: 0.85rem;
|
|
11
|
+
font-weight: 500;
|
|
12
|
+
color: #444;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.jux-input-control {
|
|
16
|
+
padding: 8px 12px;
|
|
17
|
+
border: 1px solid #ccc;
|
|
18
|
+
border-radius: 4px;
|
|
19
|
+
font-size: 1rem;
|
|
20
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.jux-input-control:focus {
|
|
24
|
+
outline: none;
|
|
25
|
+
border-color: #007bff;
|
|
26
|
+
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.jux-input-control:disabled {
|
|
30
|
+
background-color: #f5f5f5;
|
|
31
|
+
cursor: not-allowed;
|
|
32
|
+
opacity: 0.7;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.jux-input-error {
|
|
36
|
+
font-size: 0.75rem;
|
|
37
|
+
color: #dc3545;
|
|
38
|
+
min-height: 1.2em; /* Prevent layout jump */
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Error State Overrides */
|
|
42
|
+
.jux-input-wrapper.has-error .jux-input-control {
|
|
43
|
+
border-color: #dc3545;
|
|
44
|
+
}
|
|
45
|
+
.jux-input-wrapper.has-error .jux-input-label {
|
|
46
|
+
color: #dc3545;
|
|
47
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ListEngine } from './engine.js';
|
|
2
|
+
import { ListSkin } from './skin.js';
|
|
3
|
+
/**
|
|
4
|
+
* Factory Function
|
|
5
|
+
* usage: jux.list('my-list', { items: ['A', 'B'] }).render('app')
|
|
6
|
+
*
|
|
7
|
+
* Strategy: FUNCTIONAL COMPOSITION
|
|
8
|
+
* We instantiate the pure Logic (Engine) and the View (Skin).
|
|
9
|
+
* We augment the Engine instance with a function, .render(), that delegates to the Skin method, renderSkin().
|
|
10
|
+
* This keeps the Engine class pure/headless, while offering a convenient API.
|
|
11
|
+
*/
|
|
12
|
+
export function List(id, options = {}) {
|
|
13
|
+
// 1. Create the Logic
|
|
14
|
+
const engine = new ListEngine(id, options);
|
|
15
|
+
// Registration (Debug/Introspection)
|
|
16
|
+
if (typeof window !== 'undefined') {
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
window.juxEngines = window.juxEngines || {};
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
window.juxEngines[id] = engine;
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
window.juxEnginesKeys = Object.keys(window.juxEngines);
|
|
23
|
+
}
|
|
24
|
+
// 2. Create the View (wired to the engine)
|
|
25
|
+
const skin = new ListSkin(engine);
|
|
26
|
+
// 3. Augment the Engine with Render capability
|
|
27
|
+
// @ts-ignore - Dynamic augmentation
|
|
28
|
+
engine.render = (targetId) => {
|
|
29
|
+
const target = typeof targetId === 'string'
|
|
30
|
+
? document.getElementById(targetId)
|
|
31
|
+
: targetId;
|
|
32
|
+
if (target) {
|
|
33
|
+
skin.renderSkin(target);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.warn(`Jux List: Target ${targetId} not found.`);
|
|
37
|
+
}
|
|
38
|
+
return engine; // Maintain Fluent Chain
|
|
39
|
+
};
|
|
40
|
+
// 4. Augment with Styling & UI capability
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
engine.injectCSS = (id, cssContent) => skin.injectCSS(id, cssContent);
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
engine.enableSearch = (enabled = true) => { skin.enableSearch(enabled); return engine; };
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
engine.enableAdd = (enabled = true) => { skin.enableAdd(enabled); return engine; };
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
engine.enableDelete = (enabled = true) => { skin.enableDelete(enabled); return engine; };
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
engine.enableEdit = (enabled = true) => { skin.enableEdit(enabled); return engine; };
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
engine.enableMove = (enabled = true) => { skin.enableMove(enabled); return engine; };
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
engine.enableSort = (enabled = true) => { skin.enableSort(enabled); return engine; };
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
engine.knobs = (features) => {
|
|
57
|
+
features.forEach(k => {
|
|
58
|
+
switch (k) {
|
|
59
|
+
case 'add':
|
|
60
|
+
skin.enableAdd(true);
|
|
61
|
+
break;
|
|
62
|
+
case 'edit':
|
|
63
|
+
skin.enableEdit(true);
|
|
64
|
+
break;
|
|
65
|
+
case 'move':
|
|
66
|
+
skin.enableMove(true);
|
|
67
|
+
break;
|
|
68
|
+
case 'search':
|
|
69
|
+
skin.enableSearch(true);
|
|
70
|
+
break;
|
|
71
|
+
case 'delete':
|
|
72
|
+
skin.enableDelete(true);
|
|
73
|
+
break;
|
|
74
|
+
case 'sort':
|
|
75
|
+
skin.enableSort(true);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return engine;
|
|
80
|
+
};
|
|
81
|
+
return engine;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ListEngine, ListOptions } from './engine.js';
|
|
2
|
+
import { ListSkin } from './skin.js';
|
|
3
|
+
import { JuxServiceContract } from '../base/BaseEngine.js';
|
|
4
|
+
|
|
5
|
+
export type ListKnob = 'add' | 'edit' | 'move' | 'search' | 'delete' | 'sort';
|
|
6
|
+
|
|
7
|
+
// Define the Component Type (Engine + Render Capability)
|
|
8
|
+
export type ListComponent = ListEngine & {
|
|
9
|
+
render: (targetId: string | HTMLElement) => ListComponent;
|
|
10
|
+
injectCSS: (id: string, cssContent: string) => void;
|
|
11
|
+
// New UI Capabilities
|
|
12
|
+
enableSearch: (enabled?: boolean) => ListComponent;
|
|
13
|
+
enableAdd: (enabled?: boolean) => ListComponent;
|
|
14
|
+
enableDelete: (enabled?: boolean) => ListComponent;
|
|
15
|
+
enableEdit: (enabled?: boolean) => ListComponent;
|
|
16
|
+
enableMove: (enabled?: boolean) => ListComponent;
|
|
17
|
+
enableSort: (enabled?: boolean) => ListComponent;
|
|
18
|
+
enableNoItems: (message?: string) => ListComponent;
|
|
19
|
+
knobs: (features: ListKnob[]) => ListComponent;
|
|
20
|
+
// Extensions
|
|
21
|
+
addPlugin: (plugin: JuxServiceContract<ListEngine>) => ListComponent;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Factory Function
|
|
26
|
+
* usage: jux.list('my-list', { items: ['A', 'B'] }).render('app')
|
|
27
|
+
*
|
|
28
|
+
* Strategy: FUNCTIONAL COMPOSITION
|
|
29
|
+
* We instantiate the pure Logic (Engine) and the View (Skin).
|
|
30
|
+
* We augment the Engine instance with a function, .render(), that delegates to the Skin method, renderSkin().
|
|
31
|
+
* This keeps the Engine class pure/headless, while offering a convenient API.
|
|
32
|
+
*/
|
|
33
|
+
export function List(id: string, options: ListOptions = {}): ListComponent {
|
|
34
|
+
// 1. Create the Logic
|
|
35
|
+
const engine = new ListEngine(id, options);
|
|
36
|
+
|
|
37
|
+
// Registration (Debug/Introspection)
|
|
38
|
+
if (typeof window !== 'undefined') {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
window.juxEngines = window.juxEngines || {};
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
window.juxEngines[id] = engine;
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
window.juxEnginesKeys = Object.keys(window.juxEngines);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 2. Create the View (wired to the engine)
|
|
48
|
+
const skin = new ListSkin(engine);
|
|
49
|
+
|
|
50
|
+
// 3. Augment the Engine with Render capability
|
|
51
|
+
// @ts-ignore - Dynamic augmentation
|
|
52
|
+
engine.render = (targetId: string | HTMLElement) => {
|
|
53
|
+
const target = typeof targetId === 'string'
|
|
54
|
+
? document.getElementById(targetId)
|
|
55
|
+
: targetId;
|
|
56
|
+
|
|
57
|
+
if (target) {
|
|
58
|
+
skin.renderSkin(target);
|
|
59
|
+
} else {
|
|
60
|
+
console.warn(`Jux List: Target ${targetId} not found.`);
|
|
61
|
+
}
|
|
62
|
+
return engine as ListComponent; // Maintain Fluent Chain
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// 4. Augment with Styling & UI capability
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
engine.injectCSS = (id: string, cssContent: string) => skin.injectCSS(id, cssContent);
|
|
68
|
+
// @ts-ignore
|
|
69
|
+
engine.enableSearch = (enabled = true) => { skin.enableSearch(enabled); return engine; };
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
engine.enableAdd = (enabled = true) => { skin.enableAdd(enabled); return engine; };
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
engine.enableDelete = (enabled = true) => { skin.enableDelete(enabled); return engine; };
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
engine.enableEdit = (enabled = true) => { skin.enableEdit(enabled); return engine; };
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
engine.enableMove = (enabled = true) => { skin.enableMove(enabled); return engine; };
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
engine.enableSort = (enabled = true) => { skin.enableSort(enabled); return engine; };
|
|
80
|
+
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
engine.knobs = (features: ListKnob[]) => {
|
|
83
|
+
features.forEach(k => {
|
|
84
|
+
switch (k) {
|
|
85
|
+
case 'add': skin.enableAdd(true); break;
|
|
86
|
+
case 'edit': skin.enableEdit(true); break;
|
|
87
|
+
case 'move': skin.enableMove(true); break;
|
|
88
|
+
case 'search': skin.enableSearch(true); break;
|
|
89
|
+
case 'delete': skin.enableDelete(true); break;
|
|
90
|
+
case 'sort': skin.enableSort(true); break;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return engine;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return engine as ListComponent;
|
|
97
|
+
}
|