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.
Files changed (141) hide show
  1. package/bin/cli.js +161 -293
  2. package/docs/v2comps/HEADLESS.md +83 -0
  3. package/docs/v2comps/ISOMORPHISM.md +10 -0
  4. package/juxconfig.example.js +63 -58
  5. package/lib/componentsv2/base/BaseEngine.js +258 -0
  6. package/lib/componentsv2/base/BaseEngine.js.map +1 -0
  7. package/lib/componentsv2/base/BaseEngine.ts +303 -0
  8. package/lib/componentsv2/base/BaseSkin.js +108 -0
  9. package/lib/componentsv2/base/BaseSkin.js.map +1 -0
  10. package/lib/componentsv2/base/BaseSkin.ts +137 -0
  11. package/lib/componentsv2/base/GlobalBus.js +56 -0
  12. package/lib/componentsv2/base/GlobalBus.js.map +1 -0
  13. package/lib/componentsv2/base/GlobalBus.ts +60 -0
  14. package/lib/componentsv2/base/State.js +68 -0
  15. package/lib/componentsv2/base/State.js.map +1 -0
  16. package/lib/componentsv2/base/State.ts +62 -0
  17. package/lib/componentsv2/grid/component.js +41 -0
  18. package/lib/componentsv2/grid/component.js.map +1 -0
  19. package/lib/componentsv2/grid/component.ts +67 -0
  20. package/lib/componentsv2/grid/engine.js +73 -0
  21. package/lib/componentsv2/grid/engine.js.map +1 -0
  22. package/lib/componentsv2/grid/engine.ts +110 -0
  23. package/lib/componentsv2/grid/skin.js +95 -0
  24. package/lib/componentsv2/grid/skin.js.map +1 -0
  25. package/lib/componentsv2/grid/skin.ts +105 -0
  26. package/lib/componentsv2/grid/structure.css +58 -0
  27. package/lib/componentsv2/index.js +218 -0
  28. package/lib/componentsv2/index.js.map +1 -0
  29. package/lib/componentsv2/index.ts +253 -0
  30. package/lib/componentsv2/input/component.js +21 -0
  31. package/lib/componentsv2/input/component.js.map +1 -0
  32. package/lib/componentsv2/input/component.ts +28 -0
  33. package/lib/componentsv2/input/engine.js +50 -0
  34. package/lib/componentsv2/input/engine.js.map +1 -0
  35. package/lib/componentsv2/input/engine.ts +76 -0
  36. package/lib/componentsv2/input/skin.js +91 -0
  37. package/lib/componentsv2/input/skin.js.map +1 -0
  38. package/lib/componentsv2/input/skin.ts +91 -0
  39. package/lib/componentsv2/input/structure.css +47 -0
  40. package/lib/componentsv2/list/component.js +83 -0
  41. package/lib/componentsv2/list/component.js.map +1 -0
  42. package/lib/componentsv2/list/component.ts +97 -0
  43. package/lib/componentsv2/list/engine.js +261 -0
  44. package/lib/componentsv2/list/engine.js.map +1 -0
  45. package/lib/componentsv2/list/engine.ts +345 -0
  46. package/lib/componentsv2/list/skin.js +343 -0
  47. package/lib/componentsv2/list/skin.js.map +1 -0
  48. package/lib/componentsv2/list/skin.ts +367 -0
  49. package/lib/componentsv2/list/structure.css +359 -0
  50. package/lib/componentsv2/plugins/ClientSQLitePlugin.js +130 -0
  51. package/lib/componentsv2/plugins/ClientSQLitePlugin.js.map +1 -0
  52. package/lib/componentsv2/plugins/ClientSQLitePlugin.ts +154 -0
  53. package/lib/componentsv2/plugins/IndexedDBPlugin.js +75 -0
  54. package/lib/componentsv2/plugins/IndexedDBPlugin.js.map +1 -0
  55. package/lib/componentsv2/plugins/IndexedDBPlugin.ts +96 -0
  56. package/lib/componentsv2/plugins/LocalStoragePlugin.js +65 -0
  57. package/lib/componentsv2/plugins/LocalStoragePlugin.js.map +1 -0
  58. package/lib/componentsv2/plugins/LocalStoragePlugin.ts +86 -0
  59. package/lib/componentsv2/plugins/ServerSQLitePlugin.js +70 -0
  60. package/lib/componentsv2/plugins/ServerSQLitePlugin.js.map +1 -0
  61. package/lib/componentsv2/plugins/ServerSQLitePlugin.ts +99 -0
  62. package/lib/componentsv2/stubs/ComponentComposition.ts.stub +32 -0
  63. package/lib/componentsv2/stubs/ComponentEngine.ts.stub +36 -0
  64. package/lib/componentsv2/stubs/ComponentSkin.ts.stub +34 -0
  65. package/lib/componentsv2/stubs/ComponentStructure.css.stub +13 -0
  66. package/lib/componentsv2/tools/CreateSkin.js +62 -0
  67. package/lib/componentsv2/tools/DocSpam.js +134 -0
  68. package/lib/componentsv2/tools/FluencyAudit.js +141 -0
  69. package/lib/componentsv2/tools/OptionsAudit.js +177 -0
  70. package/lib/componentsv2/tools/Scaffold.js +140 -0
  71. package/lib/utils/fetch.js +428 -0
  72. package/lib/utils/fetch.js.map +1 -0
  73. package/machinery/build.js +2 -1
  74. package/machinery/compiler.js +200 -37
  75. package/machinery/config.js +93 -6
  76. package/machinery/diagnose.js +72 -0
  77. package/machinery/jux-module-pattern.md +118 -0
  78. package/machinery/server.js +23 -7
  79. package/machinery/verifier.js +143 -0
  80. package/machinery/watcher.js +53 -64
  81. package/package.json +11 -2
  82. package/lib/components/alert.ts +0 -200
  83. package/lib/components/app.ts +0 -258
  84. package/lib/components/badge.ts +0 -101
  85. package/lib/components/base/BaseComponent.ts +0 -417
  86. package/lib/components/base/FormInput.ts +0 -227
  87. package/lib/components/button.ts +0 -178
  88. package/lib/components/card.ts +0 -173
  89. package/lib/components/chart.ts +0 -231
  90. package/lib/components/checkbox.ts +0 -242
  91. package/lib/components/code.ts +0 -123
  92. package/lib/components/container.ts +0 -140
  93. package/lib/components/data.ts +0 -135
  94. package/lib/components/datepicker.ts +0 -234
  95. package/lib/components/dialog.ts +0 -172
  96. package/lib/components/divider.ts +0 -100
  97. package/lib/components/dropdown.ts +0 -186
  98. package/lib/components/element.ts +0 -267
  99. package/lib/components/error-handler.ts +0 -285
  100. package/lib/components/fileupload.ts +0 -309
  101. package/lib/components/grid.ts +0 -291
  102. package/lib/components/guard.ts +0 -92
  103. package/lib/components/heading.ts +0 -96
  104. package/lib/components/helpers.ts +0 -41
  105. package/lib/components/hero.ts +0 -224
  106. package/lib/components/icon.ts +0 -160
  107. package/lib/components/icons.ts +0 -175
  108. package/lib/components/include.ts +0 -440
  109. package/lib/components/input.ts +0 -457
  110. package/lib/components/list.ts +0 -419
  111. package/lib/components/loading.ts +0 -100
  112. package/lib/components/menu.ts +0 -260
  113. package/lib/components/modal.ts +0 -239
  114. package/lib/components/nav.ts +0 -257
  115. package/lib/components/paragraph.ts +0 -97
  116. package/lib/components/progress.ts +0 -139
  117. package/lib/components/radio.ts +0 -278
  118. package/lib/components/req.ts +0 -302
  119. package/lib/components/script.ts +0 -43
  120. package/lib/components/select.ts +0 -252
  121. package/lib/components/sidebar.ts +0 -167
  122. package/lib/components/style.ts +0 -43
  123. package/lib/components/switch.ts +0 -246
  124. package/lib/components/table.ts +0 -1249
  125. package/lib/components/tabs.ts +0 -250
  126. package/lib/components/theme-toggle.ts +0 -300
  127. package/lib/components/token-calculator.ts +0 -313
  128. package/lib/components/tooltip.ts +0 -144
  129. package/lib/components/view.ts +0 -190
  130. package/lib/components/write.ts +0 -272
  131. package/lib/jux.ts +0 -365
  132. package/lib/layouts/default.css +0 -260
  133. package/lib/layouts/figma.css +0 -334
  134. package/lib/reactivity/state.ts +0 -78
  135. package/machinery/bundleAssets.js +0 -0
  136. package/machinery/bundleJux.js +0 -0
  137. package/machinery/bundleVendors.js +0 -0
  138. package/presets/default/all.jux +0 -343
  139. package/presets/default/index.jux +0 -90
  140. package/presets/default/layout.jux +0 -57
  141. 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
+ }