juxscript 1.1.4 → 1.1.6
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/index.d.ts +10 -10
- package/index.d.ts.map +1 -0
- package/lib/components/alert.d.ts +32 -0
- package/lib/components/alert.d.ts.map +1 -0
- package/lib/components/alert.js +153 -0
- package/lib/components/alert.ts +200 -0
- package/lib/components/app.d.ts +89 -0
- package/lib/components/app.d.ts.map +1 -0
- package/lib/components/app.js +175 -0
- package/lib/components/app.ts +247 -0
- package/lib/components/badge.d.ts +27 -0
- package/lib/components/badge.d.ts.map +1 -0
- package/lib/components/badge.js +70 -0
- package/lib/components/badge.ts +101 -0
- package/lib/components/base/BaseComponent.d.ts +142 -0
- package/lib/components/base/BaseComponent.d.ts.map +1 -0
- package/lib/components/base/BaseComponent.js +363 -0
- package/lib/components/base/BaseComponent.ts +421 -0
- package/lib/components/base/FormInput.d.ts +73 -0
- package/lib/components/base/FormInput.d.ts.map +1 -0
- package/lib/components/base/FormInput.js +163 -0
- package/lib/components/base/FormInput.ts +227 -0
- package/lib/components/button.d.ts +48 -0
- package/lib/components/button.d.ts.map +1 -0
- package/lib/components/button.js +121 -0
- package/lib/components/button.ts +178 -0
- package/lib/components/card.d.ts +34 -0
- package/lib/components/card.d.ts.map +1 -0
- package/lib/components/card.js +127 -0
- package/lib/components/card.ts +173 -0
- package/lib/components/chart.d.ts +45 -0
- package/lib/components/chart.d.ts.map +1 -0
- package/lib/components/chart.js +186 -0
- package/lib/components/chart.ts +231 -0
- package/lib/components/checkbox.d.ts +31 -0
- package/lib/components/checkbox.d.ts.map +1 -0
- package/lib/components/checkbox.js +185 -0
- package/lib/components/checkbox.ts +242 -0
- package/lib/components/code.d.ts +24 -0
- package/lib/components/code.d.ts.map +1 -0
- package/lib/components/code.js +88 -0
- package/lib/components/code.ts +123 -0
- package/lib/components/container.d.ts +42 -0
- package/lib/components/container.d.ts.map +1 -0
- package/lib/components/container.js +93 -0
- package/lib/components/container.ts +140 -0
- package/lib/components/data.d.ts +36 -0
- package/lib/components/data.d.ts.map +1 -0
- package/lib/components/data.js +110 -0
- package/lib/components/data.ts +135 -0
- package/lib/components/datepicker.d.ts +38 -0
- package/lib/components/datepicker.d.ts.map +1 -0
- package/lib/components/datepicker.js +177 -0
- package/lib/components/datepicker.ts +234 -0
- package/lib/components/dialog.d.ts +38 -0
- package/lib/components/dialog.d.ts.map +1 -0
- package/lib/components/dialog.js +126 -0
- package/lib/components/dialog.ts +172 -0
- package/lib/components/divider.d.ts +30 -0
- package/lib/components/divider.d.ts.map +1 -0
- package/lib/components/divider.js +69 -0
- package/lib/components/divider.ts +100 -0
- package/lib/components/dropdown.d.ts +39 -0
- package/lib/components/dropdown.d.ts.map +1 -0
- package/lib/components/dropdown.js +133 -0
- package/lib/components/dropdown.ts +186 -0
- package/lib/components/element.d.ts +50 -0
- package/lib/components/element.d.ts.map +1 -0
- package/lib/components/element.js +206 -0
- package/lib/components/element.ts +267 -0
- package/lib/components/fileupload.d.ts +40 -0
- package/lib/components/fileupload.d.ts.map +1 -0
- package/lib/components/fileupload.js +241 -0
- package/lib/components/fileupload.ts +309 -0
- package/lib/components/grid.d.ts +87 -0
- package/lib/components/grid.d.ts.map +1 -0
- package/lib/components/grid.js +205 -0
- package/lib/components/grid.ts +291 -0
- package/lib/components/guard.d.ts +41 -0
- package/lib/components/guard.d.ts.map +1 -0
- package/lib/components/guard.js +56 -0
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.d.ts +24 -0
- package/lib/components/heading.d.ts.map +1 -0
- package/lib/components/heading.js +67 -0
- package/lib/components/heading.ts +96 -0
- package/lib/components/helpers.d.ts +9 -0
- package/lib/components/helpers.d.ts.map +1 -0
- package/lib/components/helpers.js +30 -0
- package/lib/components/helpers.ts +41 -0
- package/lib/components/hero.d.ts +45 -0
- package/lib/components/hero.d.ts.map +1 -0
- package/lib/components/hero.js +165 -0
- package/lib/components/hero.ts +224 -0
- package/lib/components/icon.d.ts +35 -0
- package/lib/components/icon.d.ts.map +1 -0
- package/lib/components/icon.js +132 -0
- package/lib/components/icon.ts +178 -0
- package/lib/components/icons.d.ts +25 -0
- package/lib/components/icons.d.ts.map +1 -0
- package/lib/components/icons.js +440 -0
- package/lib/components/icons.ts +464 -0
- package/lib/components/include.d.ts +120 -0
- package/lib/components/include.d.ts.map +1 -0
- package/lib/components/include.js +350 -0
- package/lib/components/include.ts +410 -0
- package/lib/components/input.d.ts +83 -0
- package/lib/components/input.d.ts.map +1 -0
- package/lib/components/input.js +348 -0
- package/lib/components/input.ts +457 -0
- package/lib/components/list.d.ts +82 -0
- package/lib/components/list.d.ts.map +1 -0
- package/lib/components/list.js +311 -0
- package/lib/components/list.ts +419 -0
- package/lib/components/loading.d.ts +24 -0
- package/lib/components/loading.d.ts.map +1 -0
- package/lib/components/loading.js +73 -0
- package/lib/components/loading.ts +100 -0
- package/lib/components/menu.d.ts +37 -0
- package/lib/components/menu.d.ts.map +1 -0
- package/lib/components/menu.js +202 -0
- package/lib/components/menu.ts +275 -0
- package/lib/components/modal.d.ts +51 -0
- package/lib/components/modal.d.ts.map +1 -0
- package/lib/components/modal.js +227 -0
- package/lib/components/modal.ts +284 -0
- package/lib/components/nav.d.ts +45 -0
- package/lib/components/nav.d.ts.map +1 -0
- package/lib/components/nav.js +190 -0
- package/lib/components/nav.ts +257 -0
- package/lib/components/paragraph.d.ts +21 -0
- package/lib/components/paragraph.d.ts.map +1 -0
- package/lib/components/paragraph.js +70 -0
- package/lib/components/paragraph.ts +97 -0
- package/lib/components/progress.d.ts +39 -0
- package/lib/components/progress.d.ts.map +1 -0
- package/lib/components/progress.js +113 -0
- package/lib/components/progress.ts +159 -0
- package/lib/components/radio.d.ts +41 -0
- package/lib/components/radio.d.ts.map +1 -0
- package/lib/components/radio.js +203 -0
- package/lib/components/radio.ts +278 -0
- package/lib/components/req.d.ts +155 -0
- package/lib/components/req.d.ts.map +1 -0
- package/lib/components/req.js +253 -0
- package/lib/components/req.ts +303 -0
- package/lib/components/script.d.ts +14 -0
- package/lib/components/script.d.ts.map +1 -0
- package/lib/components/script.js +33 -0
- package/lib/components/script.ts +41 -0
- package/lib/components/select.d.ts +40 -0
- package/lib/components/select.d.ts.map +1 -0
- package/lib/components/select.js +183 -0
- package/lib/components/select.ts +252 -0
- package/lib/components/sidebar.d.ts +48 -0
- package/lib/components/sidebar.d.ts.map +1 -0
- package/lib/components/sidebar.js +207 -0
- package/lib/components/sidebar.ts +275 -0
- package/lib/components/style.d.ts +14 -0
- package/lib/components/style.d.ts.map +1 -0
- package/lib/components/style.js +33 -0
- package/lib/components/style.ts +41 -0
- package/lib/components/switch.d.ts +32 -0
- package/lib/components/switch.d.ts.map +1 -0
- package/lib/components/switch.js +186 -0
- package/lib/components/switch.ts +246 -0
- package/lib/components/table.d.ts +137 -0
- package/lib/components/table.d.ts.map +1 -0
- package/lib/components/table.js +1045 -0
- package/lib/components/table.ts +1249 -0
- package/lib/components/tabs.d.ts +36 -0
- package/lib/components/tabs.d.ts.map +1 -0
- package/lib/components/tabs.js +198 -0
- package/lib/components/tabs.ts +250 -0
- package/lib/components/theme-toggle.d.ts +44 -0
- package/lib/components/theme-toggle.d.ts.map +1 -0
- package/lib/components/theme-toggle.js +215 -0
- package/lib/components/theme-toggle.ts +293 -0
- package/lib/components/tooltip.d.ts +30 -0
- package/lib/components/tooltip.d.ts.map +1 -0
- package/lib/components/tooltip.js +109 -0
- package/lib/components/tooltip.ts +144 -0
- package/lib/components/view.d.ts +48 -0
- package/lib/components/view.d.ts.map +1 -0
- package/lib/components/view.js +149 -0
- package/lib/components/view.ts +190 -0
- package/lib/components/write.d.ts +107 -0
- package/lib/components/write.d.ts.map +1 -0
- package/lib/components/write.js +222 -0
- package/lib/components/write.ts +272 -0
- package/lib/layouts/default.css +260 -0
- package/lib/layouts/figma.css +334 -0
- package/lib/reactivity/state.d.ts +36 -0
- package/lib/reactivity/state.d.ts.map +1 -0
- package/lib/reactivity/state.js +67 -0
- package/lib/reactivity/state.ts +78 -0
- package/lib/utils/fetch.d.ts +176 -0
- package/lib/utils/fetch.d.ts.map +1 -0
- package/lib/utils/fetch.js +427 -0
- package/lib/utils/fetch.ts +553 -0
- package/machinery/compiler3.js +78 -0
- package/machinery/doc-generator.js +136 -0
- package/machinery/imports.js +155 -0
- package/machinery/ts-shim.js +46 -0
- package/package.json +9 -15
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { State } from '../../reactivity/state.js';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for all JUX components
|
|
4
|
+
* Provides common storage, event routing, and lifecycle methods
|
|
5
|
+
*
|
|
6
|
+
* Children must provide:
|
|
7
|
+
* - TRIGGER_EVENTS constant (readonly string[])
|
|
8
|
+
* - CALLBACK_EVENTS constant (readonly string[])
|
|
9
|
+
* - render() implementation
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class BaseComponent<TState extends Record<string, any>> {
|
|
12
|
+
state: TState;
|
|
13
|
+
container: HTMLElement | null;
|
|
14
|
+
_id: string;
|
|
15
|
+
id: string;
|
|
16
|
+
protected _bindings: Array<{
|
|
17
|
+
event: string;
|
|
18
|
+
handler: Function;
|
|
19
|
+
}>;
|
|
20
|
+
protected _syncBindings: Array<{
|
|
21
|
+
property: string;
|
|
22
|
+
stateObj: State<any>;
|
|
23
|
+
toState?: Function;
|
|
24
|
+
toComponent?: Function;
|
|
25
|
+
}>;
|
|
26
|
+
protected _triggerHandlers: Map<string, Function>;
|
|
27
|
+
protected _callbackHandlers: Map<string, Function>;
|
|
28
|
+
constructor(id: string, initialState: TState);
|
|
29
|
+
protected abstract getTriggerEvents(): readonly string[];
|
|
30
|
+
protected abstract getCallbackEvents(): readonly string[];
|
|
31
|
+
abstract render(targetId?: string): this;
|
|
32
|
+
/**
|
|
33
|
+
* Set component style
|
|
34
|
+
*/
|
|
35
|
+
style(value: string): this;
|
|
36
|
+
/**
|
|
37
|
+
* Set component class
|
|
38
|
+
*/
|
|
39
|
+
class(value: string): this;
|
|
40
|
+
/**
|
|
41
|
+
* Add a CSS class to the component
|
|
42
|
+
*/
|
|
43
|
+
addClass(value: string): this;
|
|
44
|
+
/**
|
|
45
|
+
* Remove a CSS class from the component
|
|
46
|
+
*/
|
|
47
|
+
removeClass(value: string): this;
|
|
48
|
+
/**
|
|
49
|
+
* Toggle a CSS class on the component
|
|
50
|
+
*/
|
|
51
|
+
toggleClass(value: string): this;
|
|
52
|
+
/**
|
|
53
|
+
* Set component visibility
|
|
54
|
+
*/
|
|
55
|
+
visible(value: boolean): this;
|
|
56
|
+
/**
|
|
57
|
+
* Show the component
|
|
58
|
+
*/
|
|
59
|
+
show(): this;
|
|
60
|
+
/**
|
|
61
|
+
* Hide the component
|
|
62
|
+
*/
|
|
63
|
+
hide(): this;
|
|
64
|
+
/**
|
|
65
|
+
* Toggle component visibility
|
|
66
|
+
*/
|
|
67
|
+
toggleVisibility(): this;
|
|
68
|
+
/**
|
|
69
|
+
* Set a single HTML attribute
|
|
70
|
+
*/
|
|
71
|
+
attr(name: string, value: string): this;
|
|
72
|
+
/**
|
|
73
|
+
* Set multiple HTML attributes
|
|
74
|
+
*/
|
|
75
|
+
attrs(attributes: Record<string, string>): this;
|
|
76
|
+
/**
|
|
77
|
+
* Remove an HTML attribute
|
|
78
|
+
*/
|
|
79
|
+
removeAttr(name: string): this;
|
|
80
|
+
/**
|
|
81
|
+
* Set disabled state for interactive elements
|
|
82
|
+
*/
|
|
83
|
+
disabled(value: boolean): this;
|
|
84
|
+
/**
|
|
85
|
+
* Enable the component
|
|
86
|
+
*/
|
|
87
|
+
enable(): this;
|
|
88
|
+
/**
|
|
89
|
+
* Disable the component
|
|
90
|
+
*/
|
|
91
|
+
disable(): this;
|
|
92
|
+
/**
|
|
93
|
+
* Set loading state
|
|
94
|
+
*/
|
|
95
|
+
loading(value: boolean): this;
|
|
96
|
+
/**
|
|
97
|
+
* Focus the first focusable element in the component
|
|
98
|
+
*/
|
|
99
|
+
focus(): this;
|
|
100
|
+
/**
|
|
101
|
+
* Blur the currently focused element in the component
|
|
102
|
+
*/
|
|
103
|
+
blur(): this;
|
|
104
|
+
/**
|
|
105
|
+
* Remove the component from the DOM
|
|
106
|
+
*/
|
|
107
|
+
remove(): this;
|
|
108
|
+
bind(event: string, handler: Function): this;
|
|
109
|
+
/**
|
|
110
|
+
* Sync a component property with a State object
|
|
111
|
+
* @param property - The property to sync
|
|
112
|
+
* @param stateObj - The State object to sync with
|
|
113
|
+
* @param toStateOrTransform - Either toState function OR a simple transform function
|
|
114
|
+
* @param toComponent - Optional toComponent function (if toState was provided)
|
|
115
|
+
*/
|
|
116
|
+
sync(property: string, stateObj: State<any>, toStateOrTransform?: Function, toComponent?: Function): this;
|
|
117
|
+
protected _isTriggerEvent(event: string): boolean;
|
|
118
|
+
protected _isCallbackEvent(event: string): boolean;
|
|
119
|
+
protected _triggerCallback(eventName: string, ...args: any[]): void;
|
|
120
|
+
protected _setupContainer(targetId?: string): HTMLElement;
|
|
121
|
+
protected _wireStandardEvents(element: HTMLElement): void;
|
|
122
|
+
/**
|
|
123
|
+
* Automatically wire ALL sync bindings by calling the corresponding method
|
|
124
|
+
* if it exists on the component
|
|
125
|
+
*/
|
|
126
|
+
protected _wireAllSyncs(): void;
|
|
127
|
+
renderTo(juxComponent: any): this;
|
|
128
|
+
/**
|
|
129
|
+
* ✅ Read-only accessor for component state
|
|
130
|
+
* Provides clear separation between setters (fluent methods) and getters
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* const myCard = card('example')
|
|
134
|
+
* .title('Hello') // ✅ SETTER (fluent)
|
|
135
|
+
* .content('World'); // ✅ SETTER (fluent)
|
|
136
|
+
*
|
|
137
|
+
* console.log(myCard.props.title); // ✅ GETTER: 'Hello'
|
|
138
|
+
* console.log(myCard.props.content); // ✅ GETTER: 'World'
|
|
139
|
+
*/
|
|
140
|
+
get props(): Readonly<TState>;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=BaseComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { getOrCreateContainer } from '../helpers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for all JUX components
|
|
4
|
+
* Provides common storage, event routing, and lifecycle methods
|
|
5
|
+
*
|
|
6
|
+
* Children must provide:
|
|
7
|
+
* - TRIGGER_EVENTS constant (readonly string[])
|
|
8
|
+
* - CALLBACK_EVENTS constant (readonly string[])
|
|
9
|
+
* - render() implementation
|
|
10
|
+
*/
|
|
11
|
+
export class BaseComponent {
|
|
12
|
+
constructor(id, initialState) {
|
|
13
|
+
this.container = null;
|
|
14
|
+
// Event & sync storage (populated by bind() and sync())
|
|
15
|
+
this._bindings = [];
|
|
16
|
+
this._syncBindings = [];
|
|
17
|
+
this._triggerHandlers = new Map();
|
|
18
|
+
this._callbackHandlers = new Map();
|
|
19
|
+
this._id = id;
|
|
20
|
+
this.id = id;
|
|
21
|
+
this.state = initialState;
|
|
22
|
+
}
|
|
23
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
24
|
+
* COMMON FLUENT API (Inherited by all components)
|
|
25
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
26
|
+
/**
|
|
27
|
+
* Set component style
|
|
28
|
+
*/
|
|
29
|
+
style(value) {
|
|
30
|
+
this.state.style = value;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set component class
|
|
35
|
+
*/
|
|
36
|
+
class(value) {
|
|
37
|
+
this.state.class = value;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
41
|
+
* CSS CLASS MANAGEMENT
|
|
42
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
43
|
+
/**
|
|
44
|
+
* Add a CSS class to the component
|
|
45
|
+
*/
|
|
46
|
+
addClass(value) {
|
|
47
|
+
const current = this.state.class || '';
|
|
48
|
+
const classes = current.split(' ').filter((c) => c);
|
|
49
|
+
if (!classes.includes(value)) {
|
|
50
|
+
classes.push(value);
|
|
51
|
+
this.state.class = classes.join(' ');
|
|
52
|
+
if (this.container)
|
|
53
|
+
this.container.classList.add(value);
|
|
54
|
+
}
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Remove a CSS class from the component
|
|
59
|
+
*/
|
|
60
|
+
removeClass(value) {
|
|
61
|
+
const current = this.state.class || '';
|
|
62
|
+
const classes = current.split(' ').filter((c) => c && c !== value);
|
|
63
|
+
this.state.class = classes.join(' ');
|
|
64
|
+
if (this.container)
|
|
65
|
+
this.container.classList.remove(value);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Toggle a CSS class on the component
|
|
70
|
+
*/
|
|
71
|
+
toggleClass(value) {
|
|
72
|
+
const current = this.state.class || '';
|
|
73
|
+
const hasClass = current.split(' ').includes(value);
|
|
74
|
+
return hasClass ? this.removeClass(value) : this.addClass(value);
|
|
75
|
+
}
|
|
76
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
77
|
+
* VISIBILITY CONTROL
|
|
78
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
79
|
+
/**
|
|
80
|
+
* Set component visibility
|
|
81
|
+
*/
|
|
82
|
+
visible(value) {
|
|
83
|
+
this.state.visible = value;
|
|
84
|
+
if (this.container) {
|
|
85
|
+
// Find the actual component wrapper, not the parent container
|
|
86
|
+
const wrapper = this.container.querySelector(`#${this._id}`);
|
|
87
|
+
if (wrapper) {
|
|
88
|
+
wrapper.style.display = value ? '' : 'none';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Show the component
|
|
95
|
+
*/
|
|
96
|
+
show() {
|
|
97
|
+
return this.visible(true);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Hide the component
|
|
101
|
+
*/
|
|
102
|
+
hide() {
|
|
103
|
+
return this.visible(false);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Toggle component visibility
|
|
107
|
+
*/
|
|
108
|
+
toggleVisibility() {
|
|
109
|
+
const isVisible = this.state.visible ?? true;
|
|
110
|
+
return this.visible(!isVisible);
|
|
111
|
+
}
|
|
112
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
113
|
+
* ATTRIBUTE MANAGEMENT
|
|
114
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
115
|
+
/**
|
|
116
|
+
* Set a single HTML attribute
|
|
117
|
+
*/
|
|
118
|
+
attr(name, value) {
|
|
119
|
+
const attrs = this.state.attributes || {};
|
|
120
|
+
this.state.attributes = { ...attrs, [name]: value };
|
|
121
|
+
if (this.container)
|
|
122
|
+
this.container.setAttribute(name, value);
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Set multiple HTML attributes
|
|
127
|
+
*/
|
|
128
|
+
attrs(attributes) {
|
|
129
|
+
Object.entries(attributes).forEach(([name, value]) => {
|
|
130
|
+
this.attr(name, value);
|
|
131
|
+
});
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Remove an HTML attribute
|
|
136
|
+
*/
|
|
137
|
+
removeAttr(name) {
|
|
138
|
+
const attrs = this.state.attributes || {};
|
|
139
|
+
delete attrs[name];
|
|
140
|
+
if (this.container)
|
|
141
|
+
this.container.removeAttribute(name);
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
145
|
+
* DISABLED STATE
|
|
146
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
147
|
+
/**
|
|
148
|
+
* Set disabled state for interactive elements
|
|
149
|
+
*/
|
|
150
|
+
disabled(value) {
|
|
151
|
+
this.state.disabled = value;
|
|
152
|
+
if (this.container) {
|
|
153
|
+
const inputs = this.container.querySelectorAll('input, button, select, textarea');
|
|
154
|
+
inputs.forEach(el => {
|
|
155
|
+
el.disabled = value;
|
|
156
|
+
});
|
|
157
|
+
this.container.setAttribute('aria-disabled', String(value));
|
|
158
|
+
}
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Enable the component
|
|
163
|
+
*/
|
|
164
|
+
enable() {
|
|
165
|
+
return this.disabled(false);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Disable the component
|
|
169
|
+
*/
|
|
170
|
+
disable() {
|
|
171
|
+
return this.disabled(true);
|
|
172
|
+
}
|
|
173
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
174
|
+
* LOADING STATE
|
|
175
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
176
|
+
/**
|
|
177
|
+
* Set loading state
|
|
178
|
+
*/
|
|
179
|
+
loading(value) {
|
|
180
|
+
this.state.loading = value;
|
|
181
|
+
if (this.container) {
|
|
182
|
+
if (value) {
|
|
183
|
+
this.container.classList.add('jux-loading');
|
|
184
|
+
this.container.setAttribute('aria-busy', 'true');
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
this.container.classList.remove('jux-loading');
|
|
188
|
+
this.container.removeAttribute('aria-busy');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
194
|
+
* FOCUS MANAGEMENT
|
|
195
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
196
|
+
/**
|
|
197
|
+
* Focus the first focusable element in the component
|
|
198
|
+
*/
|
|
199
|
+
focus() {
|
|
200
|
+
if (this.container) {
|
|
201
|
+
const focusable = this.container.querySelector('input, button, select, textarea, [tabindex]');
|
|
202
|
+
if (focusable)
|
|
203
|
+
focusable.focus();
|
|
204
|
+
}
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Blur the currently focused element in the component
|
|
209
|
+
*/
|
|
210
|
+
blur() {
|
|
211
|
+
if (this.container) {
|
|
212
|
+
const focused = this.container.querySelector(':focus');
|
|
213
|
+
if (focused)
|
|
214
|
+
focused.blur();
|
|
215
|
+
}
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
219
|
+
* DOM MANIPULATION
|
|
220
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
221
|
+
/**
|
|
222
|
+
* Remove the component from the DOM
|
|
223
|
+
*/
|
|
224
|
+
remove() {
|
|
225
|
+
if (this.container) {
|
|
226
|
+
this.container.remove();
|
|
227
|
+
this.container = null;
|
|
228
|
+
}
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
232
|
+
* EVENT BINDING (Shared logic)
|
|
233
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
234
|
+
bind(event, handler) {
|
|
235
|
+
if (this._isTriggerEvent(event)) {
|
|
236
|
+
this._triggerHandlers.set(event, handler);
|
|
237
|
+
}
|
|
238
|
+
else if (this._isCallbackEvent(event)) {
|
|
239
|
+
this._callbackHandlers.set(event, handler);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this._bindings.push({ event, handler });
|
|
243
|
+
}
|
|
244
|
+
return this;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Sync a component property with a State object
|
|
248
|
+
* @param property - The property to sync
|
|
249
|
+
* @param stateObj - The State object to sync with
|
|
250
|
+
* @param toStateOrTransform - Either toState function OR a simple transform function
|
|
251
|
+
* @param toComponent - Optional toComponent function (if toState was provided)
|
|
252
|
+
*/
|
|
253
|
+
sync(property, stateObj, toStateOrTransform, toComponent) {
|
|
254
|
+
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
255
|
+
throw new Error(`${this.constructor.name}.sync: Expected a State object for property "${property}"`);
|
|
256
|
+
}
|
|
257
|
+
// If only 3 args provided, treat the function as toComponent (the common case)
|
|
258
|
+
const actualToState = (toComponent !== undefined) ? toStateOrTransform : undefined;
|
|
259
|
+
const actualToComponent = (toComponent !== undefined) ? toComponent : toStateOrTransform;
|
|
260
|
+
this._syncBindings.push({
|
|
261
|
+
property,
|
|
262
|
+
stateObj,
|
|
263
|
+
toState: actualToState,
|
|
264
|
+
toComponent: actualToComponent
|
|
265
|
+
});
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
_isTriggerEvent(event) {
|
|
269
|
+
return this.getTriggerEvents().includes(event);
|
|
270
|
+
}
|
|
271
|
+
_isCallbackEvent(event) {
|
|
272
|
+
return this.getCallbackEvents().includes(event);
|
|
273
|
+
}
|
|
274
|
+
_triggerCallback(eventName, ...args) {
|
|
275
|
+
if (this._callbackHandlers.has(eventName)) {
|
|
276
|
+
const handler = this._callbackHandlers.get(eventName);
|
|
277
|
+
handler(...args);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
console.warn(`🔍 No handler found for "${eventName}"`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
284
|
+
* COMMON RENDER HELPERS
|
|
285
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
286
|
+
_setupContainer(targetId) {
|
|
287
|
+
let container;
|
|
288
|
+
if (targetId) {
|
|
289
|
+
// Strip leading # if present
|
|
290
|
+
const id = targetId.startsWith('#') ? targetId.slice(1) : targetId;
|
|
291
|
+
const target = document.getElementById(id);
|
|
292
|
+
if (target) {
|
|
293
|
+
container = target;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
// Gracefully create the container instead of throwing
|
|
297
|
+
console.warn(`[Jux] Target "${targetId}" not found, creating it with graceful fallback`);
|
|
298
|
+
container = getOrCreateContainer(id);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
container = getOrCreateContainer(this._id);
|
|
303
|
+
}
|
|
304
|
+
// Add universal component class for DOM inspection
|
|
305
|
+
// container.classList.add('jux-component');
|
|
306
|
+
this.container = container;
|
|
307
|
+
return container;
|
|
308
|
+
}
|
|
309
|
+
_wireStandardEvents(element) {
|
|
310
|
+
this._bindings.forEach(({ event, handler }) => {
|
|
311
|
+
element.addEventListener(event, handler);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Automatically wire ALL sync bindings by calling the corresponding method
|
|
316
|
+
* if it exists on the component
|
|
317
|
+
*/
|
|
318
|
+
_wireAllSyncs() {
|
|
319
|
+
this._syncBindings.forEach(({ property, stateObj, toComponent }) => {
|
|
320
|
+
const transform = toComponent || ((v) => v);
|
|
321
|
+
// Check if component has a method matching the property name
|
|
322
|
+
const method = this[property];
|
|
323
|
+
if (typeof method === 'function') {
|
|
324
|
+
// Set initial value
|
|
325
|
+
const initialValue = transform(stateObj.value);
|
|
326
|
+
method.call(this, initialValue);
|
|
327
|
+
// Subscribe to changes
|
|
328
|
+
stateObj.subscribe((val) => {
|
|
329
|
+
const transformed = transform(val);
|
|
330
|
+
method.call(this, transformed);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
console.warn(`[Jux] ${this.constructor.name}.sync('${property}'): ` +
|
|
335
|
+
`No method .${property}() found. Property will not be synced.`);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
renderTo(juxComponent) {
|
|
340
|
+
if (!juxComponent?._id) {
|
|
341
|
+
throw new Error(`${this.constructor.name}.renderTo: Invalid component`);
|
|
342
|
+
}
|
|
343
|
+
return this.render(`#${juxComponent._id}`);
|
|
344
|
+
}
|
|
345
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
346
|
+
* PROPS ACCESSOR - Read-only access to component state
|
|
347
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
348
|
+
/**
|
|
349
|
+
* ✅ Read-only accessor for component state
|
|
350
|
+
* Provides clear separation between setters (fluent methods) and getters
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* const myCard = card('example')
|
|
354
|
+
* .title('Hello') // ✅ SETTER (fluent)
|
|
355
|
+
* .content('World'); // ✅ SETTER (fluent)
|
|
356
|
+
*
|
|
357
|
+
* console.log(myCard.props.title); // ✅ GETTER: 'Hello'
|
|
358
|
+
* console.log(myCard.props.content); // ✅ GETTER: 'World'
|
|
359
|
+
*/
|
|
360
|
+
get props() {
|
|
361
|
+
return this.state;
|
|
362
|
+
}
|
|
363
|
+
}
|