juxscript 1.1.2 → 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/machinery/config.js +93 -6
- package/machinery/serve.js +255 -0
- package/machinery/watcher.js +49 -161
- 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/server.js +0 -166
- package/machinery/ts-shim.js +0 -46
- package/machinery/validators/file-validator.js +0 -123
package/lib/components/list.ts
DELETED
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
import { renderIcon } from './icons.js';
|
|
3
|
-
|
|
4
|
-
// Event definitions
|
|
5
|
-
const TRIGGER_EVENTS = [] as const;
|
|
6
|
-
const CALLBACK_EVENTS = ['itemClick', 'itemDoubleClick', 'selectionChange'] as const;
|
|
7
|
-
|
|
8
|
-
export interface ListItem {
|
|
9
|
-
id?: string;
|
|
10
|
-
icon?: string;
|
|
11
|
-
title?: string;
|
|
12
|
-
body?: string;
|
|
13
|
-
type?: 'success' | 'warning' | 'error' | 'info' | 'default' | string;
|
|
14
|
-
metadata?: string;
|
|
15
|
-
itemClass?: string;
|
|
16
|
-
disabled?: boolean;
|
|
17
|
-
selected?: boolean;
|
|
18
|
-
data?: any; // Arbitrary data attached to item
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ListOptions {
|
|
22
|
-
items?: (ListItem | string)[]; // ✅ Allow string or ListItem
|
|
23
|
-
header?: string;
|
|
24
|
-
gap?: string;
|
|
25
|
-
direction?: 'vertical' | 'horizontal';
|
|
26
|
-
selectable?: boolean;
|
|
27
|
-
multiSelect?: boolean;
|
|
28
|
-
selectedIndex?: number | null;
|
|
29
|
-
selectedIndices?: number[];
|
|
30
|
-
onItemClick?: (item: ListItem, index: number, e: Event) => void;
|
|
31
|
-
onItemDoubleClick?: (item: ListItem, index: number, e: Event) => void;
|
|
32
|
-
onSelectionChange?: (selectedItems: ListItem[], selectedIndices: number[]) => void;
|
|
33
|
-
ordered?: boolean;
|
|
34
|
-
striped?: boolean;
|
|
35
|
-
hoverable?: boolean;
|
|
36
|
-
bordered?: boolean;
|
|
37
|
-
style?: string;
|
|
38
|
-
class?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
type ListState = {
|
|
42
|
-
items: ListItem[];
|
|
43
|
-
header: string;
|
|
44
|
-
gap: string;
|
|
45
|
-
direction: string;
|
|
46
|
-
selectable: boolean;
|
|
47
|
-
multiSelect: boolean;
|
|
48
|
-
selectedIndex: number | null;
|
|
49
|
-
selectedIndices: number[];
|
|
50
|
-
ordered: boolean;
|
|
51
|
-
striped: boolean;
|
|
52
|
-
hoverable: boolean;
|
|
53
|
-
bordered: boolean;
|
|
54
|
-
style: string;
|
|
55
|
-
class: string;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export class List extends BaseComponent<ListState> {
|
|
59
|
-
private _onItemClick: ((item: ListItem, index: number, e: Event) => void) | null = null;
|
|
60
|
-
private _onItemDoubleClick: ((item: ListItem, index: number, e: Event) => void) | null = null;
|
|
61
|
-
private _onSelectionChange: ((selectedItems: ListItem[], selectedIndices: number[]) => void) | null = null;
|
|
62
|
-
private _listElement: HTMLElement | null = null;
|
|
63
|
-
|
|
64
|
-
constructor(id: string, options: ListOptions = {}) {
|
|
65
|
-
// ✅ Normalize items - convert strings to ListItem objects
|
|
66
|
-
const normalizedItems = (options.items ?? []).map(item =>
|
|
67
|
-
typeof item === 'string' ? { title: item } : item
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
super(id, {
|
|
71
|
-
items: normalizedItems,
|
|
72
|
-
header: options.header ?? '',
|
|
73
|
-
gap: options.gap ?? '0.5rem',
|
|
74
|
-
direction: options.direction ?? 'vertical',
|
|
75
|
-
selectable: options.selectable ?? false,
|
|
76
|
-
multiSelect: options.multiSelect ?? false,
|
|
77
|
-
selectedIndex: options.selectedIndex ?? null,
|
|
78
|
-
selectedIndices: options.selectedIndices ?? [],
|
|
79
|
-
ordered: options.ordered ?? false,
|
|
80
|
-
striped: options.striped ?? false,
|
|
81
|
-
hoverable: options.hoverable ?? true,
|
|
82
|
-
bordered: options.bordered ?? false,
|
|
83
|
-
style: options.style ?? '',
|
|
84
|
-
class: options.class ?? ''
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
this._onItemClick = options.onItemClick ?? null;
|
|
88
|
-
this._onItemDoubleClick = options.onItemDoubleClick ?? null;
|
|
89
|
-
this._onSelectionChange = options.onSelectionChange ?? null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
protected getTriggerEvents(): readonly string[] {
|
|
93
|
-
return TRIGGER_EVENTS;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
protected getCallbackEvents(): readonly string[] {
|
|
97
|
-
return CALLBACK_EVENTS;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
101
|
-
* FLUENT API
|
|
102
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
103
|
-
|
|
104
|
-
// ✅ Inherited from BaseComponent
|
|
105
|
-
|
|
106
|
-
items(value: (ListItem | string)[]): this {
|
|
107
|
-
// ✅ Normalize items when setting via fluent API
|
|
108
|
-
this.state.items = value.map(item =>
|
|
109
|
-
typeof item === 'string' ? { title: item } : item
|
|
110
|
-
);
|
|
111
|
-
this._updateList();
|
|
112
|
-
return this;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
addItem(value: ListItem | string): this {
|
|
116
|
-
// ✅ Normalize single item
|
|
117
|
-
const normalizedItem = typeof value === 'string' ? { title: value } : value;
|
|
118
|
-
this.state.items = [...this.state.items, normalizedItem];
|
|
119
|
-
this._updateList();
|
|
120
|
-
return this;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
removeItem(index: number): this {
|
|
124
|
-
this.state.items = this.state.items.filter((_, i) => i !== index);
|
|
125
|
-
this._updateList();
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
updateItem(index: number, updates: Partial<ListItem>): this {
|
|
130
|
-
this.state.items = this.state.items.map((item, i) =>
|
|
131
|
-
i === index ? { ...item, ...updates } : item
|
|
132
|
-
);
|
|
133
|
-
this._updateList();
|
|
134
|
-
return this;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
clearItems(): this {
|
|
138
|
-
this.state.items = [];
|
|
139
|
-
this._updateList();
|
|
140
|
-
return this;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
itemClass(className: string): this {
|
|
144
|
-
this.state.items = this.state.items.map(item => ({
|
|
145
|
-
...item,
|
|
146
|
-
itemClass: className
|
|
147
|
-
}));
|
|
148
|
-
this._updateList();
|
|
149
|
-
return this;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
ordered(value: boolean): this {
|
|
153
|
-
this.state.ordered = value;
|
|
154
|
-
return this;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
selectable(value: boolean): this {
|
|
158
|
-
this.state.selectable = value;
|
|
159
|
-
return this;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
multiSelect(value: boolean): this {
|
|
163
|
-
this.state.multiSelect = value;
|
|
164
|
-
return this;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
striped(value: boolean): this {
|
|
168
|
-
this.state.striped = value;
|
|
169
|
-
return this;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
hoverable(value: boolean): this {
|
|
173
|
-
this.state.hoverable = value;
|
|
174
|
-
return this;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
bordered(value: boolean): this {
|
|
178
|
-
this.state.bordered = value;
|
|
179
|
-
return this;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
selectItem(index: number): this {
|
|
183
|
-
if (!this.state.selectable) return this;
|
|
184
|
-
|
|
185
|
-
if (this.state.multiSelect) {
|
|
186
|
-
if (!this.state.selectedIndices.includes(index)) {
|
|
187
|
-
this.state.selectedIndices = [...this.state.selectedIndices, index];
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
this.state.selectedIndex = index;
|
|
191
|
-
this.state.selectedIndices = [index];
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
this._updateSelection();
|
|
195
|
-
this._triggerSelectionChange();
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
deselectItem(index: number): this {
|
|
200
|
-
if (!this.state.selectable) return this;
|
|
201
|
-
|
|
202
|
-
if (this.state.multiSelect) {
|
|
203
|
-
this.state.selectedIndices = this.state.selectedIndices.filter(i => i !== index);
|
|
204
|
-
} else {
|
|
205
|
-
this.state.selectedIndex = null;
|
|
206
|
-
this.state.selectedIndices = [];
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
this._updateSelection();
|
|
210
|
-
this._triggerSelectionChange();
|
|
211
|
-
return this;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
clearSelection(): this {
|
|
215
|
-
this.state.selectedIndex = null;
|
|
216
|
-
this.state.selectedIndices = [];
|
|
217
|
-
this._updateSelection();
|
|
218
|
-
this._triggerSelectionChange();
|
|
219
|
-
return this;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
getSelectedItems(): ListItem[] {
|
|
223
|
-
return this.state.selectedIndices.map(i => this.state.items[i]).filter(Boolean);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
getSelectedIndices(): number[] {
|
|
227
|
-
return this.state.selectedIndices;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
231
|
-
* PRIVATE HELPERS
|
|
232
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
233
|
-
|
|
234
|
-
private _updateList(): void {
|
|
235
|
-
if (!this._listElement) return;
|
|
236
|
-
this._listElement.innerHTML = '';
|
|
237
|
-
this._renderItems(this._listElement);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
private _updateSelection(): void {
|
|
241
|
-
if (!this._listElement) return;
|
|
242
|
-
const items = this._listElement.querySelectorAll('.jux-list-item');
|
|
243
|
-
items.forEach((el, index) => {
|
|
244
|
-
const isSelected = this.state.selectedIndices.includes(index);
|
|
245
|
-
el.classList.toggle('jux-list-item-selected', isSelected);
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
private _triggerSelectionChange(): void {
|
|
250
|
-
const selectedItems = this.getSelectedItems();
|
|
251
|
-
const selectedIndices = this.getSelectedIndices();
|
|
252
|
-
|
|
253
|
-
if (this._onSelectionChange) {
|
|
254
|
-
this._onSelectionChange(selectedItems, selectedIndices);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// 🎯 Fire the selectionChange callback event
|
|
258
|
-
this._triggerCallback('selectionChange', { items: selectedItems, indices: selectedIndices });
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
private _renderItems(list: HTMLElement): void {
|
|
262
|
-
const { items, selectable, hoverable, striped, bordered } = this.state;
|
|
263
|
-
|
|
264
|
-
items.forEach((item, index) => {
|
|
265
|
-
const li = document.createElement('li');
|
|
266
|
-
li.className = 'jux-list-item';
|
|
267
|
-
|
|
268
|
-
if (item.itemClass) li.className += ` ${item.itemClass}`;
|
|
269
|
-
if (item.type && item.type !== 'default') li.classList.add(`jux-list-item-${item.type}`);
|
|
270
|
-
if (item.disabled) li.classList.add('jux-list-item-disabled');
|
|
271
|
-
if (this.state.selectedIndices.includes(index)) li.classList.add('jux-list-item-selected');
|
|
272
|
-
if (hoverable && !item.disabled) li.classList.add('jux-list-item-hoverable');
|
|
273
|
-
if (striped && index % 2 === 1) li.classList.add('jux-list-item-striped');
|
|
274
|
-
if (bordered) li.classList.add('jux-list-item-bordered');
|
|
275
|
-
|
|
276
|
-
// Content container
|
|
277
|
-
const content = document.createElement('div');
|
|
278
|
-
content.className = 'jux-list-item-content';
|
|
279
|
-
|
|
280
|
-
// Icon
|
|
281
|
-
if (item.icon) {
|
|
282
|
-
const iconEl = document.createElement('span');
|
|
283
|
-
iconEl.className = 'jux-list-item-icon';
|
|
284
|
-
iconEl.appendChild(renderIcon(item.icon));
|
|
285
|
-
content.appendChild(iconEl);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Text content
|
|
289
|
-
const textContainer = document.createElement('div');
|
|
290
|
-
textContainer.className = 'jux-list-item-text';
|
|
291
|
-
|
|
292
|
-
if (item.title) {
|
|
293
|
-
const titleEl = document.createElement('div');
|
|
294
|
-
titleEl.className = 'jux-list-item-title';
|
|
295
|
-
titleEl.textContent = item.title;
|
|
296
|
-
textContainer.appendChild(titleEl);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (item.body) {
|
|
300
|
-
const bodyEl = document.createElement('div');
|
|
301
|
-
bodyEl.className = 'jux-list-item-body';
|
|
302
|
-
bodyEl.textContent = item.body;
|
|
303
|
-
textContainer.appendChild(bodyEl);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
content.appendChild(textContainer);
|
|
307
|
-
|
|
308
|
-
// Metadata
|
|
309
|
-
if (item.metadata) {
|
|
310
|
-
const metaEl = document.createElement('div');
|
|
311
|
-
metaEl.className = 'jux-list-item-metadata';
|
|
312
|
-
metaEl.textContent = item.metadata;
|
|
313
|
-
content.appendChild(metaEl);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
li.appendChild(content);
|
|
317
|
-
|
|
318
|
-
// Click handlers
|
|
319
|
-
if (!item.disabled) {
|
|
320
|
-
li.addEventListener('click', (e) => {
|
|
321
|
-
if (selectable) {
|
|
322
|
-
if (this.state.selectedIndices.includes(index)) {
|
|
323
|
-
this.deselectItem(index);
|
|
324
|
-
} else {
|
|
325
|
-
if (!this.state.multiSelect) {
|
|
326
|
-
this.clearSelection();
|
|
327
|
-
}
|
|
328
|
-
this.selectItem(index);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (this._onItemClick) {
|
|
333
|
-
this._onItemClick(item, index, e);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// 🎯 Fire the itemClick callback event
|
|
337
|
-
this._triggerCallback('itemClick', { item, index, event: e });
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
li.addEventListener('dblclick', (e) => {
|
|
341
|
-
if (this._onItemDoubleClick) {
|
|
342
|
-
this._onItemDoubleClick(item, index, e);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// 🎯 Fire the itemDoubleClick callback event
|
|
346
|
-
this._triggerCallback('itemDoubleClick', { item, index, event: e });
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
list.appendChild(li);
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
355
|
-
* RENDER
|
|
356
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
357
|
-
|
|
358
|
-
render(targetId?: string): this {
|
|
359
|
-
const container = this._setupContainer(targetId);
|
|
360
|
-
|
|
361
|
-
const { header, ordered, style, class: className } = this.state;
|
|
362
|
-
|
|
363
|
-
const wrapper = document.createElement('div');
|
|
364
|
-
wrapper.className = 'jux-list-wrapper';
|
|
365
|
-
wrapper.id = `${this._id}-wrapper`;
|
|
366
|
-
|
|
367
|
-
// Header
|
|
368
|
-
if (header) {
|
|
369
|
-
const headerEl = document.createElement('div');
|
|
370
|
-
headerEl.className = 'jux-list-header';
|
|
371
|
-
headerEl.textContent = header;
|
|
372
|
-
wrapper.appendChild(headerEl);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// List
|
|
376
|
-
const list = document.createElement(ordered ? 'ol' : 'ul') as HTMLOListElement | HTMLUListElement;
|
|
377
|
-
list.className = `jux-list ${ordered ? 'jux-list-ordered' : 'jux-list-unordered'}`;
|
|
378
|
-
list.id = this._id;
|
|
379
|
-
if (className) list.className += ` ${className}`;
|
|
380
|
-
if (style) list.setAttribute('style', style);
|
|
381
|
-
|
|
382
|
-
this._listElement = list;
|
|
383
|
-
this._renderItems(list);
|
|
384
|
-
|
|
385
|
-
wrapper.appendChild(list);
|
|
386
|
-
|
|
387
|
-
this._wireStandardEvents(list);
|
|
388
|
-
|
|
389
|
-
// Wire sync bindings
|
|
390
|
-
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
391
|
-
if (property === 'items') {
|
|
392
|
-
const transform = toComponent || ((v: any) => v);
|
|
393
|
-
|
|
394
|
-
stateObj.subscribe((val: any) => {
|
|
395
|
-
const transformed = transform(val);
|
|
396
|
-
this.state.items = transformed;
|
|
397
|
-
this._updateList();
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
else if (property === 'selectedIndices') {
|
|
401
|
-
const transform = toComponent || ((v: any) => v);
|
|
402
|
-
|
|
403
|
-
stateObj.subscribe((val: any) => {
|
|
404
|
-
const transformed = transform(val);
|
|
405
|
-
this.state.selectedIndices = transformed;
|
|
406
|
-
this._updateSelection();
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
container.appendChild(wrapper);
|
|
412
|
-
|
|
413
|
-
return this;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export function list(id: string, options: ListOptions = {}): List {
|
|
418
|
-
return new List(id, options);
|
|
419
|
-
}
|
|
@@ -1,100 +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 LoadingOptions {
|
|
8
|
-
variant?: 'spinner' | 'dots' | 'pulse';
|
|
9
|
-
size?: 'sm' | 'md' | 'lg';
|
|
10
|
-
style?: string;
|
|
11
|
-
class?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type LoadingState = {
|
|
15
|
-
variant: string;
|
|
16
|
-
size: string;
|
|
17
|
-
style: string;
|
|
18
|
-
class: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export class Loading extends BaseComponent<LoadingState> {
|
|
22
|
-
constructor(id: string, options: LoadingOptions = {}) {
|
|
23
|
-
super(id, {
|
|
24
|
-
variant: options.variant ?? 'spinner',
|
|
25
|
-
size: options.size ?? 'md',
|
|
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
|
-
// - style(), class()
|
|
45
|
-
// - bind(), sync(), renderTo()
|
|
46
|
-
// - visible(), show(), hide()
|
|
47
|
-
|
|
48
|
-
variant(value: 'spinner' | 'dots' | 'pulse'): this {
|
|
49
|
-
this.state.variant = value;
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
size(value: 'sm' | 'md' | 'lg'): this {
|
|
54
|
-
this.state.size = value;
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
59
|
-
* RENDER
|
|
60
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
61
|
-
|
|
62
|
-
render(targetId?: string): this {
|
|
63
|
-
const container = this._setupContainer(targetId);
|
|
64
|
-
|
|
65
|
-
const { variant, size, style, class: className } = this.state;
|
|
66
|
-
|
|
67
|
-
const loading = document.createElement('div');
|
|
68
|
-
loading.className = `jux-loading jux-loading-${variant} jux-loading-${size}`;
|
|
69
|
-
loading.id = this._id;
|
|
70
|
-
if (className) loading.className += ` ${className}`;
|
|
71
|
-
if (style) loading.setAttribute('style', style);
|
|
72
|
-
|
|
73
|
-
// Build variant-specific content
|
|
74
|
-
if (variant === 'spinner') {
|
|
75
|
-
const spinner = document.createElement('div');
|
|
76
|
-
spinner.className = 'jux-loading-spinner';
|
|
77
|
-
loading.appendChild(spinner);
|
|
78
|
-
} else if (variant === 'dots') {
|
|
79
|
-
for (let i = 0; i < 3; i++) {
|
|
80
|
-
const dot = document.createElement('div');
|
|
81
|
-
dot.className = 'jux-loading-dot';
|
|
82
|
-
loading.appendChild(dot);
|
|
83
|
-
}
|
|
84
|
-
} else if (variant === 'pulse') {
|
|
85
|
-
const pulse = document.createElement('div');
|
|
86
|
-
pulse.className = 'jux-loading-pulse';
|
|
87
|
-
loading.appendChild(pulse);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this._wireStandardEvents(loading);
|
|
91
|
-
|
|
92
|
-
container.appendChild(loading);
|
|
93
|
-
|
|
94
|
-
return this;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function loading(id: string, options: LoadingOptions = {}): Loading {
|
|
99
|
-
return new Loading(id, options);
|
|
100
|
-
}
|