juxscript 1.0.19 → 1.0.21
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/bin/cli.js +121 -72
- package/lib/components/alert.ts +212 -165
- package/lib/components/badge.ts +93 -103
- package/lib/components/base/BaseComponent.ts +397 -0
- package/lib/components/base/FormInput.ts +322 -0
- package/lib/components/button.ts +63 -122
- package/lib/components/card.ts +109 -155
- package/lib/components/charts/areachart.ts +315 -0
- package/lib/components/charts/barchart.ts +421 -0
- package/lib/components/charts/doughnutchart.ts +263 -0
- package/lib/components/charts/lib/BaseChart.ts +402 -0
- package/lib/components/charts/lib/chart-types.ts +159 -0
- package/lib/components/charts/lib/chart-utils.ts +160 -0
- package/lib/components/charts/lib/chart.ts +707 -0
- package/lib/components/checkbox.ts +264 -127
- package/lib/components/code.ts +75 -108
- package/lib/components/container.ts +113 -130
- package/lib/components/data.ts +37 -5
- package/lib/components/datepicker.ts +195 -147
- package/lib/components/dialog.ts +187 -157
- package/lib/components/divider.ts +85 -191
- package/lib/components/docs-data.json +544 -2027
- package/lib/components/dropdown.ts +178 -136
- package/lib/components/element.ts +227 -171
- package/lib/components/fileupload.ts +285 -228
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.ts +46 -69
- package/lib/components/helpers.ts +13 -6
- package/lib/components/hero.ts +107 -95
- package/lib/components/icon.ts +160 -0
- package/lib/components/icons.ts +175 -0
- package/lib/components/include.ts +153 -5
- package/lib/components/input.ts +174 -374
- package/lib/components/kpicard.ts +16 -16
- package/lib/components/list.ts +378 -240
- package/lib/components/loading.ts +142 -211
- package/lib/components/menu.ts +103 -97
- package/lib/components/modal.ts +138 -144
- package/lib/components/nav.ts +169 -90
- package/lib/components/paragraph.ts +49 -150
- package/lib/components/progress.ts +118 -200
- package/lib/components/radio.ts +297 -149
- package/lib/components/script.ts +19 -87
- package/lib/components/select.ts +184 -186
- package/lib/components/sidebar.ts +152 -140
- package/lib/components/style.ts +19 -82
- package/lib/components/switch.ts +258 -188
- package/lib/components/table.ts +1117 -170
- package/lib/components/tabs.ts +162 -145
- package/lib/components/theme-toggle.ts +108 -169
- package/lib/components/tooltip.ts +86 -157
- package/lib/components/write.ts +108 -127
- package/lib/jux.ts +86 -41
- package/machinery/build.js +466 -0
- package/machinery/compiler.js +354 -105
- package/machinery/server.js +23 -100
- package/machinery/watcher.js +153 -130
- package/package.json +1 -2
- package/presets/base.css +1166 -0
- package/presets/notion.css +2 -1975
- package/lib/adapters/base-adapter.js +0 -35
- package/lib/adapters/index.js +0 -33
- package/lib/adapters/mysql-adapter.js +0 -65
- package/lib/adapters/postgres-adapter.js +0 -70
- package/lib/adapters/sqlite-adapter.js +0 -56
- package/lib/components/areachart.ts +0 -1246
- package/lib/components/areachartsmooth.ts +0 -1380
- package/lib/components/barchart.ts +0 -1250
- package/lib/components/chart.ts +0 -127
- package/lib/components/doughnutchart.ts +0 -1191
- package/lib/components/footer.ts +0 -165
- package/lib/components/header.ts +0 -187
- package/lib/components/layout.ts +0 -239
- package/lib/components/main.ts +0 -137
- package/lib/layouts/default.jux +0 -8
- package/lib/layouts/figma.jux +0 -0
- /package/lib/{themes → components/charts/lib}/charts.js +0 -0
package/lib/components/tabs.ts
CHANGED
|
@@ -1,70 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
+
|
|
3
|
+
// Event definitions
|
|
4
|
+
const TRIGGER_EVENTS = [] as const;
|
|
5
|
+
const CALLBACK_EVENTS = ['tabChange'] as const;
|
|
2
6
|
|
|
3
|
-
/**
|
|
4
|
-
* Tab configuration
|
|
5
|
-
*/
|
|
6
7
|
export interface Tab {
|
|
7
8
|
id: string;
|
|
8
9
|
label: string;
|
|
9
|
-
content: string |
|
|
10
|
+
content: string | HTMLElement;
|
|
11
|
+
icon?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
/**
|
|
13
|
-
* Tabs component options
|
|
14
|
-
*/
|
|
15
14
|
export interface TabsOptions {
|
|
16
15
|
tabs?: Tab[];
|
|
17
16
|
activeTab?: string;
|
|
17
|
+
variant?: 'default' | 'pills' | 'underline';
|
|
18
18
|
style?: string;
|
|
19
19
|
class?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Tabs component state
|
|
24
|
-
*/
|
|
25
22
|
type TabsState = {
|
|
26
23
|
tabs: Tab[];
|
|
27
24
|
activeTab: string;
|
|
25
|
+
variant: string;
|
|
28
26
|
style: string;
|
|
29
27
|
class: string;
|
|
30
28
|
};
|
|
31
29
|
|
|
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
|
-
export class Tabs {
|
|
45
|
-
state: TabsState;
|
|
46
|
-
container: HTMLElement | null = null;
|
|
47
|
-
_id: string;
|
|
48
|
-
id: string;
|
|
49
|
-
|
|
30
|
+
export class Tabs extends BaseComponent<TabsState> {
|
|
50
31
|
constructor(id: string, options: TabsOptions = {}) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const activeTab = options.activeTab ?? (tabs.length > 0 ? tabs[0].id : '');
|
|
56
|
-
|
|
57
|
-
this.state = {
|
|
58
|
-
tabs,
|
|
59
|
-
activeTab,
|
|
32
|
+
super(id, {
|
|
33
|
+
tabs: options.tabs ?? [],
|
|
34
|
+
activeTab: options.activeTab ?? (options.tabs?.[0]?.id ?? ''),
|
|
35
|
+
variant: options.variant ?? 'default',
|
|
60
36
|
style: options.style ?? '',
|
|
61
37
|
class: options.class ?? ''
|
|
62
|
-
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected getTriggerEvents(): readonly string[] {
|
|
42
|
+
return TRIGGER_EVENTS;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected getCallbackEvents(): readonly string[] {
|
|
46
|
+
return CALLBACK_EVENTS;
|
|
63
47
|
}
|
|
64
48
|
|
|
65
|
-
/*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
49
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
50
|
+
* FLUENT API
|
|
51
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
52
|
+
|
|
53
|
+
// ✅ Inherited from BaseComponent
|
|
68
54
|
|
|
69
55
|
tabs(value: Tab[]): this {
|
|
70
56
|
this.state.tabs = value;
|
|
@@ -78,156 +64,187 @@ export class Tabs {
|
|
|
78
64
|
|
|
79
65
|
activeTab(value: string): this {
|
|
80
66
|
this.state.activeTab = value;
|
|
67
|
+
this._updateActiveTab();
|
|
81
68
|
return this;
|
|
82
69
|
}
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
this.state.
|
|
86
|
-
return this;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
class(value: string): this {
|
|
90
|
-
this.state.class = value;
|
|
71
|
+
variant(value: 'default' | 'pills' | 'underline'): this {
|
|
72
|
+
this.state.variant = value;
|
|
91
73
|
return this;
|
|
92
74
|
}
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
* Helpers
|
|
96
|
-
* ------------------------- */
|
|
97
|
-
|
|
98
|
-
private _updateActiveTab(tabId: string): void {
|
|
76
|
+
private _updateActiveTab(): void {
|
|
99
77
|
if (!this.container) return;
|
|
100
|
-
|
|
101
78
|
const wrapper = this.container.querySelector(`#${this._id}`);
|
|
102
79
|
if (!wrapper) return;
|
|
103
80
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// Update tab buttons
|
|
107
|
-
const tabButtons = wrapper.querySelectorAll('.jux-tab-button');
|
|
108
|
-
tabButtons.forEach((btn, index) => {
|
|
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
|
-
}
|
|
81
|
+
wrapper.querySelectorAll('.jux-tabs-button').forEach(btn => {
|
|
82
|
+
btn.classList.toggle('jux-tabs-button-active', btn.getAttribute('data-tab') === this.state.activeTab);
|
|
114
83
|
});
|
|
115
84
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (panelId === tabId) {
|
|
121
|
-
panel.classList.add('jux-tab-panel-active');
|
|
122
|
-
} else {
|
|
123
|
-
panel.classList.remove('jux-tab-panel-active');
|
|
124
|
-
}
|
|
85
|
+
wrapper.querySelectorAll('.jux-tabs-panel').forEach(panel => {
|
|
86
|
+
const isActive = panel.getAttribute('data-tab') === this.state.activeTab;
|
|
87
|
+
panel.classList.toggle('jux-tabs-panel-active', isActive);
|
|
88
|
+
(panel as HTMLElement).style.display = isActive ? 'block' : 'none';
|
|
125
89
|
});
|
|
126
90
|
}
|
|
127
91
|
|
|
128
|
-
/*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
92
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
93
|
+
* RENDER
|
|
94
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
131
95
|
|
|
132
96
|
render(targetId?: string): this {
|
|
133
|
-
|
|
97
|
+
const container = this._setupContainer(targetId);
|
|
134
98
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (!target || !(target instanceof HTMLElement)) {
|
|
138
|
-
throw new Error(`Tabs: Target element "${targetId}" not found`);
|
|
139
|
-
}
|
|
140
|
-
container = target;
|
|
141
|
-
} else {
|
|
142
|
-
container = getOrCreateContainer(this._id);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this.container = container;
|
|
146
|
-
const { tabs, activeTab, style, class: className } = this.state;
|
|
99
|
+
const { tabs, activeTab, variant, style, class: className } = this.state;
|
|
100
|
+
const hasActiveTabSync = this._syncBindings.some(b => b.property === 'activeTab');
|
|
147
101
|
|
|
148
102
|
const wrapper = document.createElement('div');
|
|
149
|
-
wrapper.className =
|
|
103
|
+
wrapper.className = `jux-tabs jux-tabs-${variant}`;
|
|
150
104
|
wrapper.id = this._id;
|
|
105
|
+
if (className) wrapper.className += ` ${className}`;
|
|
106
|
+
if (style) wrapper.setAttribute('style', style);
|
|
151
107
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (style) {
|
|
157
|
-
wrapper.setAttribute('style', style);
|
|
158
|
-
}
|
|
108
|
+
const tabList = document.createElement('div');
|
|
109
|
+
tabList.className = 'jux-tabs-list';
|
|
159
110
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
tabHeaders.className = 'jux-tabs-header';
|
|
111
|
+
const tabPanels = document.createElement('div');
|
|
112
|
+
tabPanels.className = 'jux-tabs-panels';
|
|
163
113
|
|
|
164
114
|
tabs.forEach(tab => {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
115
|
+
const tabButton = document.createElement('button');
|
|
116
|
+
tabButton.className = 'jux-tabs-button';
|
|
117
|
+
tabButton.setAttribute('data-tab', tab.id);
|
|
118
|
+
if (tab.id === activeTab) tabButton.classList.add('jux-tabs-button-active');
|
|
119
|
+
tabButton.textContent = tab.label;
|
|
120
|
+
tabList.appendChild(tabButton);
|
|
121
|
+
|
|
122
|
+
const tabPanel = document.createElement('div');
|
|
123
|
+
tabPanel.className = 'jux-tabs-panel';
|
|
124
|
+
tabPanel.setAttribute('data-tab', tab.id);
|
|
169
125
|
if (tab.id === activeTab) {
|
|
170
|
-
|
|
126
|
+
tabPanel.classList.add('jux-tabs-panel-active');
|
|
127
|
+
} else {
|
|
128
|
+
tabPanel.style.display = 'none';
|
|
171
129
|
}
|
|
130
|
+
if (typeof tab.content === 'string') {
|
|
131
|
+
tabPanel.innerHTML = tab.content;
|
|
132
|
+
} else {
|
|
133
|
+
tabPanel.appendChild(tab.content);
|
|
134
|
+
}
|
|
135
|
+
tabPanels.appendChild(tabPanel);
|
|
136
|
+
});
|
|
172
137
|
|
|
173
|
-
|
|
138
|
+
wrapper.appendChild(tabList);
|
|
139
|
+
wrapper.appendChild(tabPanels);
|
|
174
140
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
141
|
+
if (!hasActiveTabSync) {
|
|
142
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
143
|
+
button.addEventListener('click', () => {
|
|
144
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
145
|
+
this.state.activeTab = tabId;
|
|
146
|
+
this._switchTab(tabId, wrapper);
|
|
147
|
+
});
|
|
178
148
|
});
|
|
179
|
-
}
|
|
149
|
+
}
|
|
180
150
|
|
|
181
|
-
|
|
151
|
+
this._wireStandardEvents(wrapper);
|
|
182
152
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
153
|
+
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
154
|
+
if (property === 'activeTab') {
|
|
155
|
+
const transformToState = toState || ((v: any) => String(v));
|
|
156
|
+
const transformToComponent = toComponent || ((v: any) => String(v));
|
|
186
157
|
|
|
187
|
-
|
|
188
|
-
const panel = document.createElement('div');
|
|
189
|
-
panel.className = 'jux-tab-panel';
|
|
190
|
-
panel.setAttribute('data-tab-id', tab.id);
|
|
158
|
+
let isUpdating = false;
|
|
191
159
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
160
|
+
stateObj.subscribe((val: any) => {
|
|
161
|
+
if (isUpdating) return;
|
|
162
|
+
const transformed = transformToComponent(val);
|
|
163
|
+
this.state.activeTab = transformed;
|
|
164
|
+
this._switchTab(transformed, wrapper);
|
|
165
|
+
});
|
|
195
166
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
167
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
168
|
+
button.addEventListener('click', () => {
|
|
169
|
+
if (isUpdating) return;
|
|
170
|
+
isUpdating = true;
|
|
171
|
+
|
|
172
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
173
|
+
this.state.activeTab = tabId;
|
|
174
|
+
this._switchTab(tabId, wrapper);
|
|
202
175
|
|
|
203
|
-
|
|
176
|
+
const transformed = transformToState(tabId);
|
|
177
|
+
stateObj.set(transformed);
|
|
178
|
+
|
|
179
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else if (property === 'tabs') {
|
|
184
|
+
const transform = toComponent || ((v: any) => v);
|
|
185
|
+
|
|
186
|
+
stateObj.subscribe((val: any) => {
|
|
187
|
+
const transformed = transform(val);
|
|
188
|
+
this.state.tabs = transformed;
|
|
189
|
+
|
|
190
|
+
tabList.innerHTML = '';
|
|
191
|
+
tabPanels.innerHTML = '';
|
|
192
|
+
|
|
193
|
+
transformed.forEach((tab: any) => {
|
|
194
|
+
const tabButton = document.createElement('button');
|
|
195
|
+
tabButton.className = 'jux-tabs-button';
|
|
196
|
+
tabButton.setAttribute('data-tab', tab.id);
|
|
197
|
+
if (tab.id === this.state.activeTab) tabButton.classList.add('jux-tabs-button-active');
|
|
198
|
+
tabButton.textContent = tab.label;
|
|
199
|
+
tabList.appendChild(tabButton);
|
|
200
|
+
|
|
201
|
+
const tabPanel = document.createElement('div');
|
|
202
|
+
tabPanel.className = 'jux-tabs-panel';
|
|
203
|
+
tabPanel.setAttribute('data-tab', tab.id);
|
|
204
|
+
if (tab.id === this.state.activeTab) {
|
|
205
|
+
tabPanel.classList.add('jux-tabs-panel-active');
|
|
206
|
+
} else {
|
|
207
|
+
tabPanel.style.display = 'none';
|
|
208
|
+
}
|
|
209
|
+
if (typeof tab.content === 'string') {
|
|
210
|
+
tabPanel.innerHTML = tab.content;
|
|
211
|
+
} else {
|
|
212
|
+
tabPanel.appendChild(tab.content);
|
|
213
|
+
}
|
|
214
|
+
tabPanels.appendChild(tabPanel);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(button => {
|
|
218
|
+
button.addEventListener('click', () => {
|
|
219
|
+
const tabId = button.getAttribute('data-tab')!;
|
|
220
|
+
this.state.activeTab = tabId;
|
|
221
|
+
this._switchTab(tabId, wrapper);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
204
226
|
});
|
|
205
227
|
|
|
206
|
-
wrapper.appendChild(tabPanels);
|
|
207
228
|
container.appendChild(wrapper);
|
|
208
|
-
|
|
209
229
|
return this;
|
|
210
230
|
}
|
|
211
231
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!juxComponent || typeof juxComponent !== 'object') {
|
|
217
|
-
throw new Error('Tabs.renderTo: Invalid component - not an object');
|
|
218
|
-
}
|
|
232
|
+
private _switchTab(tabId: string, wrapper: HTMLElement): void {
|
|
233
|
+
wrapper.querySelectorAll('.jux-tabs-button').forEach(btn => {
|
|
234
|
+
btn.classList.toggle('jux-tabs-button-active', btn.getAttribute('data-tab') === tabId);
|
|
235
|
+
});
|
|
219
236
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
237
|
+
wrapper.querySelectorAll('.jux-tabs-panel').forEach(panel => {
|
|
238
|
+
const isActive = panel.getAttribute('data-tab') === tabId;
|
|
239
|
+
panel.classList.toggle('jux-tabs-panel-active', isActive);
|
|
240
|
+
(panel as HTMLElement).style.display = isActive ? 'block' : 'none';
|
|
241
|
+
});
|
|
223
242
|
|
|
224
|
-
|
|
243
|
+
// 🎯 Fire the tabChange callback event
|
|
244
|
+
this._triggerCallback('tabChange', tabId);
|
|
225
245
|
}
|
|
226
246
|
}
|
|
227
247
|
|
|
228
|
-
/**
|
|
229
|
-
* Factory helper
|
|
230
|
-
*/
|
|
231
248
|
export function tabs(id: string, options: TabsOptions = {}): Tabs {
|
|
232
249
|
return new Tabs(id, options);
|
|
233
250
|
}
|