juxscript 1.0.19 → 1.0.20
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/lib/components/alert.ts +124 -128
- package/lib/components/areachart.ts +169 -287
- package/lib/components/areachartsmooth.ts +2 -2
- package/lib/components/badge.ts +63 -72
- package/lib/components/barchart.ts +120 -48
- package/lib/components/button.ts +92 -60
- package/lib/components/card.ts +97 -121
- package/lib/components/chart-types.ts +159 -0
- package/lib/components/chart-utils.ts +160 -0
- package/lib/components/chart.ts +628 -48
- package/lib/components/checkbox.ts +137 -51
- package/lib/components/code.ts +89 -75
- package/lib/components/container.ts +1 -1
- package/lib/components/datepicker.ts +93 -78
- package/lib/components/dialog.ts +163 -130
- package/lib/components/divider.ts +111 -193
- package/lib/components/docs-data.json +697 -274
- package/lib/components/doughnutchart.ts +125 -57
- package/lib/components/dropdown.ts +172 -85
- package/lib/components/element.ts +66 -61
- package/lib/components/fileupload.ts +142 -171
- package/lib/components/heading.ts +64 -21
- package/lib/components/hero.ts +109 -34
- package/lib/components/icon.ts +247 -0
- package/lib/components/icons.ts +174 -0
- package/lib/components/include.ts +77 -2
- package/lib/components/input.ts +105 -53
- package/lib/components/list.ts +120 -79
- package/lib/components/menu.ts +97 -2
- package/lib/components/modal.ts +144 -63
- package/lib/components/nav.ts +153 -52
- package/lib/components/paragraph.ts +54 -91
- package/lib/components/progress.ts +83 -107
- package/lib/components/radio.ts +151 -52
- package/lib/components/select.ts +110 -102
- package/lib/components/sidebar.ts +148 -105
- package/lib/components/switch.ts +124 -125
- package/lib/components/table.ts +214 -137
- package/lib/components/tabs.ts +194 -113
- package/lib/components/theme-toggle.ts +38 -7
- package/lib/components/tooltip.ts +207 -47
- package/lib/jux.ts +24 -5
- package/package.json +1 -2
package/lib/components/tabs.ts
CHANGED
|
@@ -1,62 +1,52 @@
|
|
|
1
1
|
import { getOrCreateContainer } from './helpers.js';
|
|
2
|
+
import { State } from '../reactivity/state.js';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
-
* Tab configuration
|
|
5
|
-
*/
|
|
6
4
|
export interface Tab {
|
|
7
5
|
id: string;
|
|
8
6
|
label: string;
|
|
9
|
-
content: string |
|
|
7
|
+
content: string | HTMLElement;
|
|
8
|
+
icon?: string;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
/**
|
|
13
|
-
* Tabs component options
|
|
14
|
-
*/
|
|
15
11
|
export interface TabsOptions {
|
|
16
12
|
tabs?: Tab[];
|
|
17
13
|
activeTab?: string;
|
|
14
|
+
variant?: 'default' | 'pills' | 'underline';
|
|
18
15
|
style?: string;
|
|
19
16
|
class?: string;
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
/**
|
|
23
|
-
* Tabs component state
|
|
24
|
-
*/
|
|
25
19
|
type TabsState = {
|
|
26
20
|
tabs: Tab[];
|
|
27
21
|
activeTab: string;
|
|
22
|
+
variant: string;
|
|
28
23
|
style: string;
|
|
29
24
|
class: string;
|
|
30
25
|
};
|
|
31
26
|
|
|
32
|
-
/**
|
|
33
|
-
* Tabs component
|
|
34
|
-
*
|
|
35
|
-
* Usage:
|
|
36
|
-
* const tabs = jux.tabs('myTabs', {
|
|
37
|
-
* tabs: [
|
|
38
|
-
* { id: 'tab1', label: 'Tab 1', content: 'Content 1' },
|
|
39
|
-
* { id: 'tab2', label: 'Tab 2', content: 'Content 2' }
|
|
40
|
-
* ]
|
|
41
|
-
* });
|
|
42
|
-
* tabs.render();
|
|
43
|
-
*/
|
|
44
27
|
export class Tabs {
|
|
45
28
|
state: TabsState;
|
|
46
29
|
container: HTMLElement | null = null;
|
|
47
30
|
_id: string;
|
|
48
31
|
id: string;
|
|
49
32
|
|
|
33
|
+
// CRITICAL: Store bind/sync instructions for deferred wiring
|
|
34
|
+
private _bindings: Array<{ event: string, handler: Function }> = [];
|
|
35
|
+
private _syncBindings: Array<{
|
|
36
|
+
property: string,
|
|
37
|
+
stateObj: State<any>,
|
|
38
|
+
toState?: Function,
|
|
39
|
+
toComponent?: Function
|
|
40
|
+
}> = [];
|
|
41
|
+
|
|
50
42
|
constructor(id: string, options: TabsOptions = {}) {
|
|
51
43
|
this._id = id;
|
|
52
44
|
this.id = id;
|
|
53
45
|
|
|
54
|
-
const tabs = options.tabs ?? [];
|
|
55
|
-
const activeTab = options.activeTab ?? (tabs.length > 0 ? tabs[0].id : '');
|
|
56
|
-
|
|
57
46
|
this.state = {
|
|
58
|
-
tabs,
|
|
59
|
-
activeTab,
|
|
47
|
+
tabs: options.tabs ?? [],
|
|
48
|
+
activeTab: options.activeTab ?? (options.tabs?.[0]?.id ?? ''),
|
|
49
|
+
variant: options.variant ?? 'default',
|
|
60
50
|
style: options.style ?? '',
|
|
61
51
|
class: options.class ?? ''
|
|
62
52
|
};
|
|
@@ -78,6 +68,12 @@ export class Tabs {
|
|
|
78
68
|
|
|
79
69
|
activeTab(value: string): this {
|
|
80
70
|
this.state.activeTab = value;
|
|
71
|
+
this._updateActiveTab();
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
variant(value: 'default' | 'pills' | 'underline'): this {
|
|
76
|
+
this.state.variant = value;
|
|
81
77
|
return this;
|
|
82
78
|
}
|
|
83
79
|
|
|
@@ -91,143 +87,228 @@ export class Tabs {
|
|
|
91
87
|
return this;
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
bind(event: string, handler: Function): this {
|
|
91
|
+
this._bindings.push({ event, handler });
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
if (!
|
|
95
|
+
sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
|
|
96
|
+
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
97
|
+
throw new Error(`Tabs.sync: Expected a State object for property "${property}"`);
|
|
98
|
+
}
|
|
99
|
+
this._syncBindings.push({ property, stateObj, toState, toComponent });
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
100
102
|
|
|
103
|
+
private _updateActiveTab(): void {
|
|
104
|
+
if (!this.container) return;
|
|
101
105
|
const wrapper = this.container.querySelector(`#${this._id}`);
|
|
102
106
|
if (!wrapper) return;
|
|
103
107
|
|
|
104
|
-
this.state.activeTab = tabId;
|
|
105
|
-
|
|
106
108
|
// Update tab buttons
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (this.state.tabs[index]?.id === tabId) {
|
|
110
|
-
btn.classList.add('jux-tab-button-active');
|
|
111
|
-
} else {
|
|
112
|
-
btn.classList.remove('jux-tab-button-active');
|
|
113
|
-
}
|
|
109
|
+
wrapper.querySelectorAll('.jux-tab-button').forEach(btn => {
|
|
110
|
+
btn.classList.toggle('active', btn.getAttribute('data-tab-id') === this.state.activeTab);
|
|
114
111
|
});
|
|
115
112
|
|
|
116
113
|
// Update tab panels
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const panelId = panel.getAttribute('data-tab-id');
|
|
120
|
-
if (panelId === tabId) {
|
|
121
|
-
panel.classList.add('jux-tab-panel-active');
|
|
122
|
-
} else {
|
|
123
|
-
panel.classList.remove('jux-tab-panel-active');
|
|
124
|
-
}
|
|
114
|
+
wrapper.querySelectorAll('.jux-tab-panel').forEach(panel => {
|
|
115
|
+
panel.classList.toggle('active', panel.getAttribute('data-tab-id') === this.state.activeTab);
|
|
125
116
|
});
|
|
126
117
|
}
|
|
127
118
|
|
|
128
|
-
/* -------------------------
|
|
129
|
-
* Render
|
|
130
|
-
* ------------------------- */
|
|
131
|
-
|
|
132
119
|
render(targetId?: string): this {
|
|
120
|
+
// === 1. SETUP: Get or create container ===
|
|
133
121
|
let container: HTMLElement;
|
|
134
|
-
|
|
135
122
|
if (targetId) {
|
|
136
123
|
const target = document.querySelector(targetId);
|
|
137
124
|
if (!target || !(target instanceof HTMLElement)) {
|
|
138
|
-
throw new Error(`Tabs: Target
|
|
125
|
+
throw new Error(`Tabs: Target "${targetId}" not found`);
|
|
139
126
|
}
|
|
140
127
|
container = target;
|
|
141
128
|
} else {
|
|
142
129
|
container = getOrCreateContainer(this._id);
|
|
143
130
|
}
|
|
144
|
-
|
|
145
131
|
this.container = container;
|
|
146
|
-
const { tabs, activeTab, style, class: className } = this.state;
|
|
147
132
|
|
|
133
|
+
// === 2. PREPARE: Destructure state and check sync flags ===
|
|
134
|
+
const { tabs, activeTab, variant, style, class: className } = this.state;
|
|
135
|
+
const hasActiveTabSync = this._syncBindings.some(b => b.property === 'activeTab');
|
|
136
|
+
|
|
137
|
+
// === 3. BUILD: Create DOM elements ===
|
|
148
138
|
const wrapper = document.createElement('div');
|
|
149
|
-
wrapper.className =
|
|
139
|
+
wrapper.className = `jux-tabs jux-tabs-${variant}`;
|
|
150
140
|
wrapper.id = this._id;
|
|
141
|
+
if (className) wrapper.className += ` ${className}`;
|
|
142
|
+
if (style) wrapper.setAttribute('style', style);
|
|
151
143
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
144
|
+
const tabList = document.createElement('div');
|
|
145
|
+
tabList.className = 'jux-tabs-list';
|
|
155
146
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Tab headers
|
|
161
|
-
const tabHeaders = document.createElement('div');
|
|
162
|
-
tabHeaders.className = 'jux-tabs-header';
|
|
163
|
-
|
|
164
|
-
tabs.forEach(tab => {
|
|
165
|
-
const tabBtn = document.createElement('button');
|
|
166
|
-
tabBtn.className = 'jux-tab-button';
|
|
167
|
-
tabBtn.textContent = tab.label;
|
|
147
|
+
const tabPanels = document.createElement('div');
|
|
148
|
+
tabPanels.className = 'jux-tabs-panels';
|
|
168
149
|
|
|
150
|
+
tabs.forEach((tab, index) => {
|
|
151
|
+
// Tab button
|
|
152
|
+
const tabButton = document.createElement('button');
|
|
153
|
+
tabButton.className = 'jux-tabs-button';
|
|
154
|
+
tabButton.setAttribute('data-tab', tab.id);
|
|
155
|
+
if (tab.id === activeTab) tabButton.classList.add('jux-tabs-button-active');
|
|
156
|
+
tabButton.textContent = tab.label;
|
|
157
|
+
tabList.appendChild(tabButton);
|
|
158
|
+
|
|
159
|
+
// Tab panel
|
|
160
|
+
const tabPanel = document.createElement('div');
|
|
161
|
+
tabPanel.className = 'jux-tabs-panel';
|
|
162
|
+
tabPanel.setAttribute('data-tab', tab.id);
|
|
169
163
|
if (tab.id === activeTab) {
|
|
170
|
-
|
|
164
|
+
tabPanel.classList.add('jux-tabs-panel-active');
|
|
165
|
+
} else {
|
|
166
|
+
tabPanel.style.display = 'none';
|
|
167
|
+
}
|
|
168
|
+
if (typeof tab.content === 'string') {
|
|
169
|
+
tabPanel.innerHTML = tab.content;
|
|
170
|
+
} else {
|
|
171
|
+
tabPanel.appendChild(tab.content);
|
|
171
172
|
}
|
|
173
|
+
tabPanels.appendChild(tabPanel);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
wrapper.appendChild(tabList);
|
|
177
|
+
wrapper.appendChild(tabPanels);
|
|
172
178
|
|
|
173
|
-
|
|
179
|
+
// === 4. WIRE: Attach event listeners and sync bindings ===
|
|
174
180
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
// Default tab switching behavior (only if NOT using sync)
|
|
182
|
+
if (!hasActiveTabSync) {
|
|
183
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
184
|
+
button.addEventListener('click', () => {
|
|
185
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
186
|
+
this.state.activeTab = tabId;
|
|
187
|
+
this._switchTab(tabId, wrapper);
|
|
188
|
+
});
|
|
178
189
|
});
|
|
179
|
-
}
|
|
190
|
+
}
|
|
180
191
|
|
|
181
|
-
|
|
192
|
+
// Wire custom bindings from .bind() calls
|
|
193
|
+
this._bindings.forEach(({ event, handler }) => {
|
|
194
|
+
wrapper.addEventListener(event, handler as EventListener);
|
|
195
|
+
});
|
|
182
196
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
197
|
+
// Wire sync bindings from .sync() calls
|
|
198
|
+
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
199
|
+
if (property === 'activeTab') {
|
|
200
|
+
const transformToState = toState || ((v: any) => String(v));
|
|
201
|
+
const transformToComponent = toComponent || ((v: any) => String(v));
|
|
202
|
+
|
|
203
|
+
let isUpdating = false;
|
|
204
|
+
|
|
205
|
+
// State → Component
|
|
206
|
+
stateObj.subscribe((val: any) => {
|
|
207
|
+
if (isUpdating) return;
|
|
208
|
+
const transformed = transformToComponent(val);
|
|
209
|
+
this.state.activeTab = transformed;
|
|
210
|
+
this._switchTab(transformed, wrapper);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Component → State (tab clicks)
|
|
214
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
215
|
+
button.addEventListener('click', () => {
|
|
216
|
+
if (isUpdating) return;
|
|
217
|
+
isUpdating = true;
|
|
218
|
+
|
|
219
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
220
|
+
this.state.activeTab = tabId;
|
|
221
|
+
this._switchTab(tabId, wrapper);
|
|
222
|
+
|
|
223
|
+
const transformed = transformToState(tabId);
|
|
224
|
+
stateObj.set(transformed);
|
|
225
|
+
|
|
226
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else if (property === 'tabs') {
|
|
231
|
+
const transformToComponent = toComponent || ((v: any) => v);
|
|
232
|
+
|
|
233
|
+
stateObj.subscribe((val: any) => {
|
|
234
|
+
const transformed = transformToComponent(val);
|
|
235
|
+
this.state.tabs = transformed;
|
|
236
|
+
|
|
237
|
+
// Re-render tabs
|
|
238
|
+
tabList.innerHTML = '';
|
|
239
|
+
tabPanels.innerHTML = '';
|
|
240
|
+
|
|
241
|
+
transformed.forEach((tab: any) => {
|
|
242
|
+
const tabButton = document.createElement('button');
|
|
243
|
+
tabButton.className = 'jux-tabs-button';
|
|
244
|
+
tabButton.setAttribute('data-tab', tab.id);
|
|
245
|
+
if (tab.id === this.state.activeTab) tabButton.classList.add('jux-tabs-button-active');
|
|
246
|
+
tabButton.textContent = tab.label;
|
|
247
|
+
tabList.appendChild(tabButton);
|
|
248
|
+
|
|
249
|
+
const tabPanel = document.createElement('div');
|
|
250
|
+
tabPanel.className = 'jux-tabs-panel';
|
|
251
|
+
tabPanel.setAttribute('data-tab', tab.id);
|
|
252
|
+
if (tab.id === this.state.activeTab) {
|
|
253
|
+
tabPanel.classList.add('jux-tabs-panel-active');
|
|
254
|
+
} else {
|
|
255
|
+
tabPanel.style.display = 'none';
|
|
256
|
+
}
|
|
257
|
+
if (typeof tab.content === 'string') {
|
|
258
|
+
tabPanel.innerHTML = tab.content;
|
|
259
|
+
} else {
|
|
260
|
+
tabPanel.appendChild(tab.content);
|
|
261
|
+
}
|
|
262
|
+
tabPanels.appendChild(tabPanel);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Re-wire click handlers
|
|
266
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
267
|
+
button.addEventListener('click', () => {
|
|
268
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
269
|
+
this.state.activeTab = tabId;
|
|
270
|
+
this._switchTab(tabId, wrapper);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
});
|
|
186
276
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
277
|
+
// === 5. RENDER: Append to DOM and finalize ===
|
|
278
|
+
container.appendChild(wrapper);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
191
281
|
|
|
192
|
-
|
|
193
|
-
|
|
282
|
+
private _switchTab(tabId: string, wrapper: HTMLElement): void {
|
|
283
|
+
// Update buttons
|
|
284
|
+
wrapper.querySelectorAll('.jux-tabs-button').forEach(btn => {
|
|
285
|
+
if (btn.getAttribute('data-tab') === tabId) {
|
|
286
|
+
btn.classList.add('jux-tabs-button-active');
|
|
287
|
+
} else {
|
|
288
|
+
btn.classList.remove('jux-tabs-button-active');
|
|
194
289
|
}
|
|
290
|
+
});
|
|
195
291
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
292
|
+
// Update panels
|
|
293
|
+
wrapper.querySelectorAll('.jux-tabs-panel').forEach(panel => {
|
|
294
|
+
if (panel.getAttribute('data-tab') === tabId) {
|
|
295
|
+
panel.classList.add('jux-tabs-panel-active');
|
|
296
|
+
(panel as HTMLElement).style.display = 'block';
|
|
199
297
|
} else {
|
|
200
|
-
panel.
|
|
298
|
+
panel.classList.remove('jux-tabs-panel-active');
|
|
299
|
+
(panel as HTMLElement).style.display = 'none';
|
|
201
300
|
}
|
|
202
|
-
|
|
203
|
-
tabPanels.appendChild(panel);
|
|
204
301
|
});
|
|
205
|
-
|
|
206
|
-
wrapper.appendChild(tabPanels);
|
|
207
|
-
container.appendChild(wrapper);
|
|
208
|
-
|
|
209
|
-
return this;
|
|
210
302
|
}
|
|
211
303
|
|
|
212
|
-
/**
|
|
213
|
-
* Render to another Jux component's container
|
|
214
|
-
*/
|
|
215
304
|
renderTo(juxComponent: any): this {
|
|
216
|
-
if (!juxComponent
|
|
217
|
-
throw new Error('Tabs.renderTo: Invalid component
|
|
305
|
+
if (!juxComponent?._id) {
|
|
306
|
+
throw new Error('Tabs.renderTo: Invalid component');
|
|
218
307
|
}
|
|
219
|
-
|
|
220
|
-
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
221
|
-
throw new Error('Tabs.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
308
|
return this.render(`#${juxComponent._id}`);
|
|
225
309
|
}
|
|
226
310
|
}
|
|
227
311
|
|
|
228
|
-
/**
|
|
229
|
-
* Factory helper
|
|
230
|
-
*/
|
|
231
312
|
export function tabs(id: string, options: TabsOptions = {}): Tabs {
|
|
232
313
|
return new Tabs(id, options);
|
|
233
314
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getOrCreateContainer } from './helpers.js';
|
|
2
2
|
import { ErrorHandler } from './error-handler.js';
|
|
3
|
+
import { renderIcon } from './icons.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Theme configuration
|
|
@@ -237,10 +238,23 @@ export class ThemeToggle {
|
|
|
237
238
|
// Update button variant
|
|
238
239
|
if (this.state.variant === 'button' || this.state.variant === 'cycle') {
|
|
239
240
|
const button = toggle.querySelector('button');
|
|
240
|
-
if (button) {
|
|
241
|
-
button.innerHTML =
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
if (button && currentTheme.icon) {
|
|
242
|
+
button.innerHTML = '';
|
|
243
|
+
const iconElement = renderIcon(currentTheme.icon);
|
|
244
|
+
button.appendChild(iconElement);
|
|
245
|
+
|
|
246
|
+
if (this.state.showLabel) {
|
|
247
|
+
const labelSpan = document.createElement('span');
|
|
248
|
+
labelSpan.textContent = ` ${currentTheme.label}`;
|
|
249
|
+
button.appendChild(labelSpan);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Trigger Lucide rendering
|
|
253
|
+
requestAnimationFrame(() => {
|
|
254
|
+
if ((window as any).lucide) {
|
|
255
|
+
(window as any).lucide.createIcons();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
244
258
|
}
|
|
245
259
|
}
|
|
246
260
|
|
|
@@ -295,9 +309,18 @@ export class ThemeToggle {
|
|
|
295
309
|
button.type = 'button';
|
|
296
310
|
button.setAttribute('aria-label', 'Toggle theme');
|
|
297
311
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
312
|
+
if (theme?.icon) {
|
|
313
|
+
const iconElement = renderIcon(theme.icon);
|
|
314
|
+
button.appendChild(iconElement);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (showLabel) {
|
|
318
|
+
const labelSpan = document.createElement('span');
|
|
319
|
+
labelSpan.textContent = ` ${theme?.label || currentTheme}`;
|
|
320
|
+
button.appendChild(labelSpan);
|
|
321
|
+
} else if (!theme?.icon) {
|
|
322
|
+
button.textContent = theme?.label || currentTheme;
|
|
323
|
+
}
|
|
301
324
|
|
|
302
325
|
button.addEventListener('click', () => {
|
|
303
326
|
this.cycleTheme();
|
|
@@ -334,6 +357,14 @@ export class ThemeToggle {
|
|
|
334
357
|
}
|
|
335
358
|
|
|
336
359
|
container.appendChild(wrapper);
|
|
360
|
+
|
|
361
|
+
// Trigger Lucide icon rendering
|
|
362
|
+
requestAnimationFrame(() => {
|
|
363
|
+
if ((window as any).lucide) {
|
|
364
|
+
(window as any).lucide.createIcons();
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
337
368
|
return this;
|
|
338
369
|
}
|
|
339
370
|
|