juxscript 1.1.3 → 1.1.4
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/machinery/build3.js +7 -91
- package/machinery/compiler3.js +3 -209
- package/package.json +19 -5
- package/lib/components/alert.ts +0 -200
- package/lib/components/app.ts +0 -247
- package/lib/components/badge.ts +0 -101
- package/lib/components/base/BaseComponent.ts +0 -421
- 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/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 -178
- package/lib/components/icons.ts +0 -464
- package/lib/components/include.ts +0 -410
- 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 -275
- package/lib/components/modal.ts +0 -284
- package/lib/components/nav.ts +0 -257
- package/lib/components/paragraph.ts +0 -97
- package/lib/components/progress.ts +0 -159
- package/lib/components/radio.ts +0 -278
- package/lib/components/req.ts +0 -303
- package/lib/components/script.ts +0 -41
- package/lib/components/select.ts +0 -252
- package/lib/components/sidebar.ts +0 -275
- package/lib/components/style.ts +0 -41
- 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 -293
- package/lib/components/tooltip.ts +0 -144
- package/lib/components/view.ts +0 -190
- package/lib/components/write.ts +0 -272
- package/lib/layouts/default.css +0 -260
- package/lib/layouts/figma.css +0 -334
- package/lib/reactivity/state.ts +0 -78
- package/lib/utils/fetch.ts +0 -553
- package/machinery/ast.js +0 -347
- package/machinery/build.js +0 -466
- package/machinery/bundleAssets.js +0 -0
- package/machinery/bundleJux.js +0 -0
- package/machinery/bundleVendors.js +0 -0
- package/machinery/doc-generator.js +0 -136
- package/machinery/imports.js +0 -155
- package/machinery/ts-shim.js +0 -46
- package/machinery/validators/file-validator.js +0 -123
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { FormInput, FormInputState } from './base/FormInput.js';
|
|
2
|
-
import { renderIcon } from './icons.js';
|
|
3
|
-
|
|
4
|
-
// Event definitions
|
|
5
|
-
const TRIGGER_EVENTS = [] as const;
|
|
6
|
-
const CALLBACK_EVENTS = ['change'] as const;
|
|
7
|
-
|
|
8
|
-
export interface CheckboxOptions {
|
|
9
|
-
checked?: boolean;
|
|
10
|
-
label?: string;
|
|
11
|
-
required?: boolean;
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
name?: string;
|
|
14
|
-
value?: string;
|
|
15
|
-
style?: string;
|
|
16
|
-
class?: string;
|
|
17
|
-
onValidate?: (checked: boolean) => boolean | string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface CheckboxState extends FormInputState {
|
|
21
|
-
checked: boolean;
|
|
22
|
-
value: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class Checkbox extends FormInput<CheckboxState> {
|
|
26
|
-
constructor(id: string, options: CheckboxOptions = {}) {
|
|
27
|
-
super(id, {
|
|
28
|
-
checked: options.checked ?? false,
|
|
29
|
-
value: options.value ?? 'on',
|
|
30
|
-
label: options.label ?? '',
|
|
31
|
-
required: options.required ?? false,
|
|
32
|
-
disabled: options.disabled ?? false,
|
|
33
|
-
name: options.name ?? id,
|
|
34
|
-
style: options.style ?? '',
|
|
35
|
-
class: options.class ?? '',
|
|
36
|
-
errorMessage: undefined
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
if (options.onValidate) {
|
|
40
|
-
this._onValidate = options.onValidate;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
protected getTriggerEvents(): readonly string[] {
|
|
45
|
-
return TRIGGER_EVENTS;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
protected getCallbackEvents(): readonly string[] {
|
|
49
|
-
return CALLBACK_EVENTS;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
53
|
-
* FLUENT API
|
|
54
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
55
|
-
|
|
56
|
-
// ✅ Inherited from FormInput/BaseComponent:
|
|
57
|
-
// - label(), required(), name(), onValidate()
|
|
58
|
-
// - validate(), isValid()
|
|
59
|
-
// - style(), class()
|
|
60
|
-
// - bind(), sync(), renderTo()
|
|
61
|
-
// - disabled(), enable(), disable()
|
|
62
|
-
|
|
63
|
-
checked(value: boolean): this {
|
|
64
|
-
return this.setValue(value);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
value(value: string): this {
|
|
68
|
-
this.state.value = value;
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
73
|
-
* FORM INPUT IMPLEMENTATION
|
|
74
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
75
|
-
|
|
76
|
-
getValue(): boolean {
|
|
77
|
-
return this.state.checked;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
setValue(value: boolean): this {
|
|
81
|
-
this.state.checked = value;
|
|
82
|
-
if (this._inputElement) {
|
|
83
|
-
(this._inputElement as HTMLInputElement).checked = value;
|
|
84
|
-
}
|
|
85
|
-
return this;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
protected _validateValue(checked: boolean): boolean | string {
|
|
89
|
-
const { required } = this.state;
|
|
90
|
-
|
|
91
|
-
if (required && !checked) {
|
|
92
|
-
return 'This field must be checked';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (this._onValidate) {
|
|
96
|
-
const result = this._onValidate(checked);
|
|
97
|
-
if (result !== true) {
|
|
98
|
-
return result || 'Invalid value';
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
protected _buildInputElement(): HTMLElement {
|
|
106
|
-
const { checked, value, required, disabled, name } = this.state;
|
|
107
|
-
|
|
108
|
-
const input = document.createElement('input');
|
|
109
|
-
input.type = 'checkbox';
|
|
110
|
-
input.className = 'jux-checkbox-input';
|
|
111
|
-
input.id = `${this._id}-input`;
|
|
112
|
-
input.name = name;
|
|
113
|
-
input.value = value;
|
|
114
|
-
input.checked = checked;
|
|
115
|
-
input.required = required;
|
|
116
|
-
input.disabled = disabled;
|
|
117
|
-
|
|
118
|
-
return input;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
122
|
-
* RENDER
|
|
123
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
124
|
-
|
|
125
|
-
render(targetId?: string): this {
|
|
126
|
-
const container = this._setupContainer(targetId);
|
|
127
|
-
|
|
128
|
-
const { style, class: className } = this.state;
|
|
129
|
-
|
|
130
|
-
// Build wrapper
|
|
131
|
-
const wrapper = document.createElement('div');
|
|
132
|
-
wrapper.className = 'jux-checkbox';
|
|
133
|
-
wrapper.id = this._id;
|
|
134
|
-
if (className) wrapper.className += ` ${className}`;
|
|
135
|
-
if (style) wrapper.setAttribute('style', style);
|
|
136
|
-
|
|
137
|
-
// Checkbox container
|
|
138
|
-
const checkboxContainer = document.createElement('label');
|
|
139
|
-
checkboxContainer.className = 'jux-checkbox-container';
|
|
140
|
-
checkboxContainer.htmlFor = `${this._id}-input`;
|
|
141
|
-
|
|
142
|
-
// Input element
|
|
143
|
-
const inputEl = this._buildInputElement() as HTMLInputElement;
|
|
144
|
-
this._inputElement = inputEl;
|
|
145
|
-
checkboxContainer.appendChild(inputEl);
|
|
146
|
-
|
|
147
|
-
// Checkmark (custom styled)
|
|
148
|
-
const checkmark = document.createElement('span');
|
|
149
|
-
checkmark.className = 'jux-checkbox-checkmark';
|
|
150
|
-
checkmark.appendChild(renderIcon('check'));
|
|
151
|
-
checkboxContainer.appendChild(checkmark);
|
|
152
|
-
|
|
153
|
-
// Label text
|
|
154
|
-
if (this.state.label) {
|
|
155
|
-
const labelText = document.createElement('span');
|
|
156
|
-
labelText.className = 'jux-checkbox-label-text';
|
|
157
|
-
labelText.textContent = this.state.label;
|
|
158
|
-
if (this.state.required) {
|
|
159
|
-
const requiredSpan = document.createElement('span');
|
|
160
|
-
requiredSpan.className = 'jux-input-required';
|
|
161
|
-
requiredSpan.textContent = ' *';
|
|
162
|
-
labelText.appendChild(requiredSpan);
|
|
163
|
-
}
|
|
164
|
-
checkboxContainer.appendChild(labelText);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
wrapper.appendChild(checkboxContainer);
|
|
168
|
-
|
|
169
|
-
// Error element
|
|
170
|
-
wrapper.appendChild(this._renderError());
|
|
171
|
-
|
|
172
|
-
// Wire events
|
|
173
|
-
this._wireStandardEvents(wrapper);
|
|
174
|
-
|
|
175
|
-
// Wire checkbox-specific sync (maps 'checked' to 'value' property for consistency)
|
|
176
|
-
const valueSync = this._syncBindings.find(b => b.property === 'value' || b.property === 'checked');
|
|
177
|
-
|
|
178
|
-
if (valueSync) {
|
|
179
|
-
const { stateObj, toState, toComponent } = valueSync;
|
|
180
|
-
|
|
181
|
-
const transformToState = toState || ((v: boolean) => v);
|
|
182
|
-
const transformToComponent = toComponent || ((v: any) => Boolean(v));
|
|
183
|
-
|
|
184
|
-
let isUpdating = false;
|
|
185
|
-
|
|
186
|
-
// State → Component
|
|
187
|
-
stateObj.subscribe((val: any) => {
|
|
188
|
-
if (isUpdating) return;
|
|
189
|
-
const transformed = transformToComponent(val);
|
|
190
|
-
this.setValue(transformed);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Component → State
|
|
194
|
-
inputEl.addEventListener('change', () => {
|
|
195
|
-
if (isUpdating) return;
|
|
196
|
-
isUpdating = true;
|
|
197
|
-
|
|
198
|
-
const checked = inputEl.checked;
|
|
199
|
-
this.state.checked = checked;
|
|
200
|
-
this._clearError();
|
|
201
|
-
|
|
202
|
-
const transformed = transformToState(checked);
|
|
203
|
-
stateObj.set(transformed);
|
|
204
|
-
|
|
205
|
-
// 🎯 Fire the change callback event
|
|
206
|
-
this._triggerCallback('change', checked);
|
|
207
|
-
|
|
208
|
-
setTimeout(() => { isUpdating = false; }, 0);
|
|
209
|
-
});
|
|
210
|
-
} else {
|
|
211
|
-
// Default behavior without sync
|
|
212
|
-
inputEl.addEventListener('change', () => {
|
|
213
|
-
this.state.checked = inputEl.checked;
|
|
214
|
-
this._clearError();
|
|
215
|
-
|
|
216
|
-
// 🎯 Fire the change callback event
|
|
217
|
-
this._triggerCallback('change', inputEl.checked);
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Always add blur validation
|
|
222
|
-
inputEl.addEventListener('blur', () => {
|
|
223
|
-
this.validate();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// Sync label changes
|
|
227
|
-
const labelSync = this._syncBindings.find(b => b.property === 'label');
|
|
228
|
-
if (labelSync) {
|
|
229
|
-
const transform = labelSync.toComponent || ((v: any) => String(v));
|
|
230
|
-
labelSync.stateObj.subscribe((val: any) => {
|
|
231
|
-
this.label(transform(val));
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
container.appendChild(wrapper);
|
|
236
|
-
return this;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function checkbox(id: string, options: CheckboxOptions = {}): Checkbox {
|
|
241
|
-
return new Checkbox(id, options);
|
|
242
|
-
}
|
package/lib/components/code.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
|
|
3
|
-
// Event definitions
|
|
4
|
-
const TRIGGER_EVENTS = [] as const;
|
|
5
|
-
const CALLBACK_EVENTS = [] as const;
|
|
6
|
-
|
|
7
|
-
export interface CodeOptions {
|
|
8
|
-
code?: string;
|
|
9
|
-
language?: string;
|
|
10
|
-
style?: string;
|
|
11
|
-
class?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type CodeState = {
|
|
15
|
-
code: string;
|
|
16
|
-
language: string;
|
|
17
|
-
style: string;
|
|
18
|
-
class: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export class Code extends BaseComponent<CodeState> {
|
|
22
|
-
constructor(id: string, options: CodeOptions = {}) {
|
|
23
|
-
super(id, {
|
|
24
|
-
code: options.code ?? '',
|
|
25
|
-
language: options.language ?? 'javascript',
|
|
26
|
-
style: options.style ?? '',
|
|
27
|
-
class: options.class ?? ''
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
protected getTriggerEvents(): readonly string[] {
|
|
32
|
-
return TRIGGER_EVENTS;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected getCallbackEvents(): readonly string[] {
|
|
36
|
-
return CALLBACK_EVENTS;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
40
|
-
* FLUENT API
|
|
41
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
42
|
-
|
|
43
|
-
// ✅ Inherited from BaseComponent
|
|
44
|
-
|
|
45
|
-
code(value: string): this {
|
|
46
|
-
this.state.code = value;
|
|
47
|
-
return this;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
language(value: string): this {
|
|
51
|
-
this.state.language = value;
|
|
52
|
-
return this;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
56
|
-
* RENDER
|
|
57
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
58
|
-
|
|
59
|
-
render(targetId?: string): this {
|
|
60
|
-
const container = this._setupContainer(targetId);
|
|
61
|
-
|
|
62
|
-
const { code, language, style, class: className } = this.state;
|
|
63
|
-
|
|
64
|
-
const wrapper = document.createElement('div');
|
|
65
|
-
wrapper.className = 'jux-code';
|
|
66
|
-
wrapper.id = this._id;
|
|
67
|
-
if (className) wrapper.className += ` ${className}`;
|
|
68
|
-
if (style) wrapper.setAttribute('style', style);
|
|
69
|
-
|
|
70
|
-
const pre = document.createElement('pre');
|
|
71
|
-
const codeEl = document.createElement('code');
|
|
72
|
-
codeEl.className = `language-${language}`;
|
|
73
|
-
codeEl.textContent = code;
|
|
74
|
-
pre.appendChild(codeEl);
|
|
75
|
-
wrapper.appendChild(pre);
|
|
76
|
-
|
|
77
|
-
this._wireStandardEvents(wrapper);
|
|
78
|
-
|
|
79
|
-
// Wire sync bindings
|
|
80
|
-
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
81
|
-
if (property === 'code') {
|
|
82
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
83
|
-
|
|
84
|
-
stateObj.subscribe((val: any) => {
|
|
85
|
-
const transformed = transform(val);
|
|
86
|
-
codeEl.textContent = transformed;
|
|
87
|
-
this.state.code = transformed;
|
|
88
|
-
|
|
89
|
-
if ((window as any).Prism) {
|
|
90
|
-
(window as any).Prism.highlightElement(codeEl);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
else if (property === 'language') {
|
|
95
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
96
|
-
|
|
97
|
-
stateObj.subscribe((val: any) => {
|
|
98
|
-
const transformed = transform(val);
|
|
99
|
-
codeEl.className = `language-${transformed}`;
|
|
100
|
-
this.state.language = transformed;
|
|
101
|
-
|
|
102
|
-
if ((window as any).Prism) {
|
|
103
|
-
(window as any).Prism.highlightElement(codeEl);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
container.appendChild(wrapper);
|
|
110
|
-
|
|
111
|
-
requestAnimationFrame(() => {
|
|
112
|
-
if ((window as any).Prism) {
|
|
113
|
-
(window as any).Prism.highlightElement(codeEl);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
return this;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function code(id: string, options: CodeOptions = {}): Code {
|
|
122
|
-
return new Code(id, options);
|
|
123
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
|
|
3
|
-
// Event definitions - Container is a layout wrapper that can be clicked
|
|
4
|
-
const TRIGGER_EVENTS = [] as const;
|
|
5
|
-
const CALLBACK_EVENTS = ['click'] as const;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Container options
|
|
9
|
-
*/
|
|
10
|
-
export interface ContainerOptions {
|
|
11
|
-
class?: string;
|
|
12
|
-
style?: string;
|
|
13
|
-
direction?: 'row' | 'column';
|
|
14
|
-
gap?: string | number;
|
|
15
|
-
align?: 'start' | 'center' | 'end' | 'stretch';
|
|
16
|
-
justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Container state
|
|
21
|
-
*/
|
|
22
|
-
type ContainerState = {
|
|
23
|
-
class: string;
|
|
24
|
-
style: string;
|
|
25
|
-
direction?: 'row' | 'column';
|
|
26
|
-
gap?: string | number;
|
|
27
|
-
align?: string;
|
|
28
|
-
justify?: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Container component - a simple div container for grouping elements
|
|
33
|
-
*/
|
|
34
|
-
export class Container extends BaseComponent<ContainerState> {
|
|
35
|
-
constructor(id: string, options: ContainerOptions = {}) {
|
|
36
|
-
super(id, {
|
|
37
|
-
class: options.class ?? '',
|
|
38
|
-
style: options.style ?? '',
|
|
39
|
-
direction: options.direction,
|
|
40
|
-
gap: options.gap,
|
|
41
|
-
align: options.align,
|
|
42
|
-
justify: options.justify
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
protected getTriggerEvents(): readonly string[] {
|
|
47
|
-
return TRIGGER_EVENTS;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
protected getCallbackEvents(): readonly string[] {
|
|
51
|
-
return CALLBACK_EVENTS;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/* -------------------------
|
|
55
|
-
* Fluent API
|
|
56
|
-
* ------------------------- */
|
|
57
|
-
|
|
58
|
-
// ✅ Inherited from BaseComponent:
|
|
59
|
-
// - style(), class()
|
|
60
|
-
// - bind(), sync(), renderTo()
|
|
61
|
-
// - addClass(), removeClass(), toggleClass()
|
|
62
|
-
// - visible(), show(), hide()
|
|
63
|
-
// - attr(), attrs(), removeAttr()
|
|
64
|
-
// - disabled(), enable(), disable()
|
|
65
|
-
|
|
66
|
-
direction(value: 'row' | 'column'): this {
|
|
67
|
-
this.state.direction = value;
|
|
68
|
-
return this;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
gap(value: string | number): this {
|
|
72
|
-
this.state.gap = value;
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
align(value: 'start' | 'center' | 'end' | 'stretch'): this {
|
|
77
|
-
this.state.align = value;
|
|
78
|
-
return this;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
justify(value: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly'): this {
|
|
82
|
-
this.state.justify = value;
|
|
83
|
-
return this;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* -------------------------
|
|
87
|
-
* Render
|
|
88
|
-
* ------------------------- */
|
|
89
|
-
|
|
90
|
-
render(targetId?: string): this {
|
|
91
|
-
const container = this._setupContainer(targetId);
|
|
92
|
-
|
|
93
|
-
const { class: className, style, direction, gap, align, justify } = this.state;
|
|
94
|
-
|
|
95
|
-
const div = document.createElement('div');
|
|
96
|
-
div.id = this._id;
|
|
97
|
-
|
|
98
|
-
// Always include jux-container class, append custom classes
|
|
99
|
-
div.className = className ? `jux-container ${className}` : 'jux-container';
|
|
100
|
-
|
|
101
|
-
// Only apply flex styles if any flex properties are set
|
|
102
|
-
const usesFlexbox = direction || gap !== undefined || align || justify;
|
|
103
|
-
|
|
104
|
-
let computedStyle = style;
|
|
105
|
-
|
|
106
|
-
if (usesFlexbox) {
|
|
107
|
-
const flexStyles: string[] = ['display: flex', 'width: auto'];
|
|
108
|
-
|
|
109
|
-
if (direction) flexStyles.push(`flex-direction: ${direction}`);
|
|
110
|
-
|
|
111
|
-
if (gap !== undefined) {
|
|
112
|
-
const gapValue = typeof gap === 'number' ? `${gap}px` : gap;
|
|
113
|
-
flexStyles.push(`gap: ${gapValue}`);
|
|
114
|
-
}
|
|
115
|
-
// Only set align-items if explicitly specified
|
|
116
|
-
if (align) flexStyles.push(`align-items: ${align}`);
|
|
117
|
-
// Only set justify-content if explicitly specified
|
|
118
|
-
if (justify) flexStyles.push(`justify-content: ${justify}`);
|
|
119
|
-
|
|
120
|
-
computedStyle = `${flexStyles.join('; ')}; ${style}`.trim();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (computedStyle) {
|
|
124
|
-
div.setAttribute('style', computedStyle);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
this._wireStandardEvents(div);
|
|
128
|
-
|
|
129
|
-
container.appendChild(div);
|
|
130
|
-
|
|
131
|
-
return this;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Factory helper
|
|
137
|
-
*/
|
|
138
|
-
export function container(id: string, options: ContainerOptions = {}): Container {
|
|
139
|
-
return new Container(id, options);
|
|
140
|
-
}
|
package/lib/components/data.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Data component - SQL query execution
|
|
3
|
-
* Note: No id needed - this is a data-only component
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* const posts = jux.data('SELECT * FROM posts WHERE id = ?', [1]);
|
|
7
|
-
* await posts.execute();
|
|
8
|
-
* console.log(posts.data);
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export interface DataOptions {
|
|
12
|
-
sql: string;
|
|
13
|
-
params?: any[];
|
|
14
|
-
apiUrl?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class Data {
|
|
18
|
-
private _data: any[] = [];
|
|
19
|
-
private _executed: boolean = false;
|
|
20
|
-
private _loading: boolean = false;
|
|
21
|
-
private _sql: string;
|
|
22
|
-
private _params: any[];
|
|
23
|
-
private _apiUrl: string;
|
|
24
|
-
|
|
25
|
-
constructor(sql: string, params: any[] = [], apiUrl: string = '/api/query') {
|
|
26
|
-
this._sql = sql;
|
|
27
|
-
this._params = params;
|
|
28
|
-
this._apiUrl = apiUrl;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/* -------------------------
|
|
32
|
-
* Getters
|
|
33
|
-
* ------------------------- */
|
|
34
|
-
|
|
35
|
-
get data(): any[] {
|
|
36
|
-
return this._data;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get executed(): boolean {
|
|
40
|
-
return this._executed;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get loading(): boolean {
|
|
44
|
-
return this._loading;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
get sql(): string {
|
|
48
|
-
return this._sql;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
set sql(value: string) {
|
|
52
|
-
this._sql = value;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* -------------------------
|
|
56
|
-
* Methods
|
|
57
|
-
* ------------------------- */
|
|
58
|
-
|
|
59
|
-
async execute(): Promise<void> {
|
|
60
|
-
if (this._executed) return;
|
|
61
|
-
this._loading = true;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const response = await fetch(this._apiUrl, {
|
|
65
|
-
method: 'POST',
|
|
66
|
-
headers: {
|
|
67
|
-
'Content-Type': 'application/json'
|
|
68
|
-
},
|
|
69
|
-
body: JSON.stringify({
|
|
70
|
-
sql: this._sql,
|
|
71
|
-
params: this._params
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
if (!response.ok) {
|
|
76
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const result = await response.json();
|
|
80
|
-
this._data = result.data || [];
|
|
81
|
-
this._executed = true;
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error('Data execution error:', error);
|
|
84
|
-
this._data = [];
|
|
85
|
-
throw error;
|
|
86
|
-
} finally {
|
|
87
|
-
this._loading = false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
reset(): void {
|
|
92
|
-
this._executed = false;
|
|
93
|
-
this._data = [];
|
|
94
|
-
this._loading = false;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Remove id requirement, make it optional for caching
|
|
98
|
-
static async fetch<T = any>(url: string, options?: RequestInit): Promise<T> {
|
|
99
|
-
const response = await fetch(url, options);
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
102
|
-
}
|
|
103
|
-
return response.json();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ✅ Static methods - no ID needed
|
|
107
|
-
static async post<T = any>(url: string, body: any, options?: RequestInit): Promise<T> {
|
|
108
|
-
const response = await fetch(url, options);
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
111
|
-
}
|
|
112
|
-
return response.json();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
static async put<T = any>(url: string, body: any, options?: RequestInit): Promise<T> {
|
|
116
|
-
const response = await fetch(url, options);
|
|
117
|
-
if (!response.ok) {
|
|
118
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
119
|
-
}
|
|
120
|
-
return response.json();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
static async delete<T = any>(url: string, options?: RequestInit): Promise<T> {
|
|
124
|
-
const response = await fetch(url, options);
|
|
125
|
-
if (!response.ok) {
|
|
126
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
127
|
-
}
|
|
128
|
-
return response.json();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ✅ No ID needed - pure data fetching
|
|
133
|
-
export function data<T = any>(url: string, options?: RequestInit): Promise<T> {
|
|
134
|
-
return Data.fetch<T>(url, options);
|
|
135
|
-
}
|