juxscript 1.0.20 → 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 +143 -92
- package/lib/components/badge.ts +93 -94
- package/lib/components/base/BaseComponent.ts +397 -0
- package/lib/components/base/FormInput.ts +322 -0
- package/lib/components/button.ts +40 -131
- package/lib/components/card.ts +57 -79
- 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/{chart-types.ts → charts/lib/chart-types.ts} +1 -1
- package/lib/components/{chart-utils.ts → charts/lib/chart-utils.ts} +1 -1
- package/lib/components/{chart.ts → charts/lib/chart.ts} +3 -3
- package/lib/components/checkbox.ts +255 -204
- package/lib/components/code.ts +31 -78
- package/lib/components/container.ts +113 -130
- package/lib/components/data.ts +37 -5
- package/lib/components/datepicker.ts +180 -147
- package/lib/components/dialog.ts +218 -221
- package/lib/components/divider.ts +63 -87
- package/lib/components/docs-data.json +498 -2404
- package/lib/components/dropdown.ts +191 -236
- package/lib/components/element.ts +196 -145
- package/lib/components/fileupload.ts +253 -167
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.ts +31 -97
- package/lib/components/helpers.ts +13 -6
- package/lib/components/hero.ts +51 -114
- package/lib/components/icon.ts +33 -120
- package/lib/components/icons.ts +2 -1
- package/lib/components/include.ts +76 -3
- package/lib/components/input.ts +155 -407
- package/lib/components/kpicard.ts +16 -16
- package/lib/components/list.ts +358 -261
- package/lib/components/loading.ts +142 -211
- package/lib/components/menu.ts +63 -152
- package/lib/components/modal.ts +42 -129
- package/lib/components/nav.ts +79 -101
- package/lib/components/paragraph.ts +38 -102
- package/lib/components/progress.ts +108 -166
- package/lib/components/radio.ts +283 -234
- package/lib/components/script.ts +19 -87
- package/lib/components/select.ts +189 -199
- package/lib/components/sidebar.ts +110 -141
- package/lib/components/style.ts +19 -82
- package/lib/components/switch.ts +254 -183
- package/lib/components/table.ts +1078 -208
- package/lib/components/tabs.ts +42 -106
- package/lib/components/theme-toggle.ts +73 -165
- package/lib/components/tooltip.ts +85 -316
- package/lib/components/write.ts +108 -127
- package/lib/jux.ts +67 -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 -1
- 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 -1128
- package/lib/components/areachartsmooth.ts +0 -1380
- package/lib/components/barchart.ts +0 -1322
- package/lib/components/doughnutchart.ts +0 -1259
- 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
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
+
|
|
3
|
+
// Event definitions
|
|
4
|
+
const TRIGGER_EVENTS = [] as const;
|
|
5
|
+
const CALLBACK_EVENTS = ['toggle'] as const;
|
|
3
6
|
|
|
4
7
|
export interface SidebarOptions {
|
|
5
8
|
position?: 'left' | 'right';
|
|
@@ -19,33 +22,40 @@ type SidebarState = {
|
|
|
19
22
|
class: string;
|
|
20
23
|
};
|
|
21
24
|
|
|
22
|
-
export class Sidebar {
|
|
23
|
-
|
|
24
|
-
container: HTMLElement | null = null;
|
|
25
|
-
_id: string;
|
|
26
|
-
id: string;
|
|
27
|
-
|
|
28
|
-
private _bindings: Array<{ event: string, handler: Function }> = [];
|
|
29
|
-
private _syncBindings: Array<{ property: string, stateObj: State<any>, transform?: Function }> = [];
|
|
25
|
+
export class Sidebar extends BaseComponent<SidebarState> {
|
|
26
|
+
private _sidebar: HTMLElement | null = null;
|
|
30
27
|
|
|
31
28
|
constructor(id: string, options: SidebarOptions = {}) {
|
|
32
|
-
|
|
33
|
-
this.id = id;
|
|
34
|
-
|
|
35
|
-
this.state = {
|
|
29
|
+
super(id, {
|
|
36
30
|
position: options.position ?? 'left',
|
|
37
|
-
width: options.width ??
|
|
31
|
+
width: options.width ?? '',
|
|
38
32
|
collapsible: options.collapsible ?? true,
|
|
39
33
|
collapsed: options.collapsed ?? false,
|
|
40
34
|
style: options.style ?? '',
|
|
41
35
|
class: options.class ?? ''
|
|
42
|
-
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected getTriggerEvents(): readonly string[] {
|
|
40
|
+
return TRIGGER_EVENTS;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
protected getCallbackEvents(): readonly string[] {
|
|
44
|
+
return CALLBACK_EVENTS;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
48
|
+
* FLUENT API
|
|
49
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
48
50
|
|
|
51
|
+
// ✅ Inherited from BaseComponent:
|
|
52
|
+
// - style(), class()
|
|
53
|
+
// - bind(), sync(), renderTo()
|
|
54
|
+
// - addClass(), removeClass(), toggleClass()
|
|
55
|
+
// - visible(), show(), hide()
|
|
56
|
+
// - attr(), attrs(), removeAttr()
|
|
57
|
+
// - disabled(), enable(), disable()
|
|
58
|
+
// - loading(), focus(), blur(), remove()
|
|
49
59
|
|
|
50
60
|
width(value: string): this {
|
|
51
61
|
this.state.width = value;
|
|
@@ -68,59 +78,29 @@ export class Sidebar {
|
|
|
68
78
|
return this;
|
|
69
79
|
}
|
|
70
80
|
|
|
71
|
-
style(value: string): this {
|
|
72
|
-
this.state.style = value;
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
class(value: string): this {
|
|
77
|
-
this.state.class = value;
|
|
78
|
-
return this;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
bind(event: string, handler: Function): this {
|
|
82
|
-
this._bindings.push({ event, handler });
|
|
83
|
-
return this;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
sync(property: string, stateObj: State<any>, transform?: Function): this {
|
|
87
|
-
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
88
|
-
throw new Error(`Sidebar.sync: Expected a State object for property "${property}"`);
|
|
89
|
-
}
|
|
90
|
-
this._syncBindings.push({ property, stateObj, transform });
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
81
|
toggle(): void {
|
|
95
82
|
this.state.collapsed = !this.state.collapsed;
|
|
96
83
|
this._updateCollapsedState();
|
|
84
|
+
// 🎯 Fire the toggle callback event
|
|
85
|
+
this._triggerCallback('toggle', this.state.collapsed);
|
|
97
86
|
}
|
|
98
87
|
|
|
99
88
|
private _updateCollapsedState(): void {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
sidebar.classList.toggle('jux-sidebar-collapsed', this.state.collapsed);
|
|
89
|
+
if (this._sidebar) {
|
|
90
|
+
this._sidebar.classList.toggle('jux-sidebar-collapsed', this.state.collapsed);
|
|
103
91
|
}
|
|
104
92
|
}
|
|
105
93
|
|
|
94
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
95
|
+
* RENDER
|
|
96
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
97
|
+
|
|
106
98
|
render(targetId?: string): this {
|
|
107
|
-
|
|
108
|
-
let container: HTMLElement;
|
|
109
|
-
if (targetId) {
|
|
110
|
-
const target = document.querySelector(targetId);
|
|
111
|
-
if (!target || !(target instanceof HTMLElement)) {
|
|
112
|
-
throw new Error(`Sidebar: Target element "${targetId}" not found`);
|
|
113
|
-
}
|
|
114
|
-
container = target;
|
|
115
|
-
} else {
|
|
116
|
-
container = getOrCreateContainer(this._id);
|
|
117
|
-
}
|
|
118
|
-
this.container = container;
|
|
99
|
+
const container = this._setupContainer(targetId);
|
|
119
100
|
|
|
120
|
-
// === 2. PREPARE: Destructure state ===
|
|
121
101
|
const { position, width, collapsible, collapsed, style, class: className } = this.state;
|
|
122
102
|
|
|
123
|
-
//
|
|
103
|
+
// Build sidebar element
|
|
124
104
|
const sidebar = document.createElement('aside');
|
|
125
105
|
sidebar.className = `jux-sidebar jux-sidebar-${position}`;
|
|
126
106
|
sidebar.id = this._id;
|
|
@@ -144,14 +124,12 @@ export class Sidebar {
|
|
|
144
124
|
toggleBtn.addEventListener('click', () => {
|
|
145
125
|
this.toggle();
|
|
146
126
|
|
|
147
|
-
// Update button icon and title
|
|
148
127
|
const isCollapsed = this.state.collapsed;
|
|
149
128
|
toggleBtn.innerHTML = isCollapsed
|
|
150
129
|
? (position === 'left' ? '▶' : '◀')
|
|
151
130
|
: (position === 'left' ? '◀' : '▶');
|
|
152
131
|
toggleBtn.setAttribute('title', isCollapsed ? 'Expand sidebar' : 'Collapse sidebar');
|
|
153
132
|
|
|
154
|
-
// Animate width change
|
|
155
133
|
if (width) {
|
|
156
134
|
sidebar.style.width = isCollapsed ? '60px' : width;
|
|
157
135
|
}
|
|
@@ -160,26 +138,25 @@ export class Sidebar {
|
|
|
160
138
|
sidebar.appendChild(toggleBtn);
|
|
161
139
|
}
|
|
162
140
|
|
|
163
|
-
//
|
|
141
|
+
// Wire events using inherited method
|
|
142
|
+
this._wireStandardEvents(sidebar);
|
|
164
143
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this._syncBindings.forEach(({ property, stateObj, transform }) => {
|
|
170
|
-
stateObj.subscribe((val: any) => {
|
|
171
|
-
const transformed = transform ? transform(val) : val;
|
|
144
|
+
// Wire sync bindings for 'collapsed' property
|
|
145
|
+
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
146
|
+
if (property === 'collapsed') {
|
|
147
|
+
const transform = toComponent || ((v: any) => v);
|
|
172
148
|
|
|
173
|
-
|
|
149
|
+
stateObj.subscribe((val: any) => {
|
|
150
|
+
const transformed = transform(val);
|
|
174
151
|
const isCollapsed = Boolean(transformed);
|
|
175
152
|
this.state.collapsed = isCollapsed;
|
|
176
153
|
this._updateCollapsedState();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
179
156
|
});
|
|
180
157
|
|
|
181
|
-
// === 5. RENDER: Append to DOM ===
|
|
182
158
|
container.appendChild(sidebar);
|
|
159
|
+
this._sidebar = sidebar;
|
|
183
160
|
this._injectDefaultStyles();
|
|
184
161
|
|
|
185
162
|
return this;
|
|
@@ -192,75 +169,67 @@ export class Sidebar {
|
|
|
192
169
|
const style = document.createElement('style');
|
|
193
170
|
style.id = styleId;
|
|
194
171
|
style.textContent = `
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
.jux-sidebar-right {
|
|
205
|
-
border-right: none;
|
|
206
|
-
border-left: 1px solid #e5e7eb;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.jux-sidebar-toggle {
|
|
210
|
-
position: absolute;
|
|
211
|
-
bottom: 20px;
|
|
212
|
-
right: 20px;
|
|
213
|
-
width: 32px;
|
|
214
|
-
height: 32px;
|
|
215
|
-
border: none;
|
|
216
|
-
background: #3b82f6;
|
|
217
|
-
color: white;
|
|
218
|
-
border-radius: 6px;
|
|
219
|
-
cursor: pointer;
|
|
220
|
-
font-size: 14px;
|
|
221
|
-
display: flex;
|
|
222
|
-
align-items: center;
|
|
223
|
-
justify-content: center;
|
|
224
|
-
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
225
|
-
z-index: 100;
|
|
226
|
-
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.jux-sidebar-toggle:hover {
|
|
230
|
-
background: #2563eb;
|
|
231
|
-
transform: scale(1.05);
|
|
232
|
-
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.jux-sidebar-toggle:active {
|
|
236
|
-
transform: scale(0.95);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.jux-sidebar-collapsed {
|
|
240
|
-
width: 60px !important;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/* Smooth fade for content */
|
|
244
|
-
.jux-sidebar-collapsed > *:not(.jux-sidebar-toggle) {
|
|
245
|
-
opacity: 0;
|
|
246
|
-
pointer-events: none;
|
|
247
|
-
transition: opacity 0.2s ease-out;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.jux-sidebar > *:not(.jux-sidebar-toggle) {
|
|
251
|
-
opacity: 1;
|
|
252
|
-
pointer-events: auto;
|
|
253
|
-
transition: opacity 0.3s ease-in 0.1s;
|
|
254
|
-
}
|
|
255
|
-
`;
|
|
256
|
-
document.head.appendChild(style);
|
|
257
|
-
}
|
|
172
|
+
.jux-sidebar {
|
|
173
|
+
position: relative;
|
|
174
|
+
height: 100vh;
|
|
175
|
+
background: #f9fafb;
|
|
176
|
+
border-right: 1px solid #e5e7eb;
|
|
177
|
+
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
}
|
|
258
180
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
181
|
+
.jux-sidebar-right {
|
|
182
|
+
border-right: none;
|
|
183
|
+
border-left: 1px solid #e5e7eb;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.jux-sidebar-toggle {
|
|
187
|
+
position: absolute;
|
|
188
|
+
bottom: 20px;
|
|
189
|
+
right: 20px;
|
|
190
|
+
width: 32px;
|
|
191
|
+
height: 32px;
|
|
192
|
+
border: none;
|
|
193
|
+
background: #3b82f6;
|
|
194
|
+
color: white;
|
|
195
|
+
border-radius: 6px;
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
font-size: 14px;
|
|
198
|
+
display: flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
202
|
+
z-index: 100;
|
|
203
|
+
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.jux-sidebar-toggle:hover {
|
|
207
|
+
background: #2563eb;
|
|
208
|
+
transform: scale(1.05);
|
|
209
|
+
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.jux-sidebar-toggle:active {
|
|
213
|
+
transform: scale(0.95);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.jux-sidebar-collapsed {
|
|
217
|
+
width: 60px !important;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.jux-sidebar-collapsed > *:not(.jux-sidebar-toggle) {
|
|
221
|
+
opacity: 0;
|
|
222
|
+
pointer-events: none;
|
|
223
|
+
transition: opacity 0.2s ease-out;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.jux-sidebar > *:not(.jux-sidebar-toggle) {
|
|
227
|
+
opacity: 1;
|
|
228
|
+
pointer-events: auto;
|
|
229
|
+
transition: opacity 0.3s ease-in 0.1s;
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
document.head.appendChild(style);
|
|
264
233
|
}
|
|
265
234
|
}
|
|
266
235
|
|
package/lib/components/style.ts
CHANGED
|
@@ -6,101 +6,38 @@ import { ErrorHandler } from './error-handler.js';
|
|
|
6
6
|
* Auto-renders when created or modified
|
|
7
7
|
*/
|
|
8
8
|
export class Style {
|
|
9
|
-
private
|
|
10
|
-
private
|
|
9
|
+
private _id: string;
|
|
10
|
+
private css: string;
|
|
11
11
|
|
|
12
|
-
constructor(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (content) {
|
|
17
|
-
this.render();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Set inline CSS content
|
|
23
|
-
*/
|
|
24
|
-
content(css: string): this {
|
|
25
|
-
this._content = css;
|
|
26
|
-
this.render();
|
|
27
|
-
return this;
|
|
12
|
+
constructor(css: string, id?: string) {
|
|
13
|
+
// ID only for deduplication, auto-generate if not provided
|
|
14
|
+
this._id = id || `jux-style-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
15
|
+
this.css = css;
|
|
28
16
|
}
|
|
29
17
|
|
|
30
|
-
/**
|
|
31
|
-
* Append CSS to existing content
|
|
32
|
-
*/
|
|
33
|
-
append(css: string): this {
|
|
34
|
-
this._content += '\n' + css;
|
|
35
|
-
this.render();
|
|
36
|
-
return this;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Prepend CSS to existing content
|
|
41
|
-
*/
|
|
42
|
-
prepend(css: string): this {
|
|
43
|
-
this._content = css + '\n' + this._content;
|
|
44
|
-
this.render();
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Render the inline style element
|
|
50
|
-
*/
|
|
51
18
|
render(): this {
|
|
52
|
-
if
|
|
19
|
+
// Check if style with this ID already exists
|
|
20
|
+
if (document.getElementById(this._id)) {
|
|
53
21
|
return this;
|
|
54
22
|
}
|
|
55
23
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Create <style> element for inline CSS
|
|
61
|
-
const style = document.createElement('style');
|
|
62
|
-
style.textContent = this._content;
|
|
63
|
-
document.head.appendChild(style);
|
|
64
|
-
this._element = style;
|
|
65
|
-
|
|
66
|
-
console.log('✓ Inline styles rendered');
|
|
67
|
-
} catch (error: any) {
|
|
68
|
-
ErrorHandler.captureError({
|
|
69
|
-
component: 'Style',
|
|
70
|
-
method: 'render',
|
|
71
|
-
message: error.message,
|
|
72
|
-
stack: error.stack,
|
|
73
|
-
timestamp: new Date(),
|
|
74
|
-
context: {
|
|
75
|
-
type: 'inline',
|
|
76
|
-
error: 'runtime_exception'
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
24
|
+
const style = document.createElement('style');
|
|
25
|
+
style.id = this._id;
|
|
26
|
+
style.textContent = this.css;
|
|
27
|
+
document.head.appendChild(style);
|
|
80
28
|
|
|
81
29
|
return this;
|
|
82
30
|
}
|
|
83
31
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (this._element && this._element.parentNode) {
|
|
89
|
-
this._element.parentNode.removeChild(this._element);
|
|
90
|
-
this._element = null;
|
|
32
|
+
remove(): void {
|
|
33
|
+
const existing = document.getElementById(this._id);
|
|
34
|
+
if (existing) {
|
|
35
|
+
existing.remove();
|
|
91
36
|
}
|
|
92
|
-
return this;
|
|
93
37
|
}
|
|
94
38
|
}
|
|
95
39
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* Usage:
|
|
100
|
-
* jux.style('body { margin: 0; }');
|
|
101
|
-
* jux.style().content('.highlight { color: red; }');
|
|
102
|
-
* jux.style('h1 { font-size: 2rem; }').append('h2 { font-size: 1.5rem; }');
|
|
103
|
-
*/
|
|
104
|
-
export function style(content: string = ''): Style {
|
|
105
|
-
return new Style(content);
|
|
40
|
+
// ✅ ID is optional
|
|
41
|
+
export function style(css: string, id?: string): Style {
|
|
42
|
+
return new Style(css, id);
|
|
106
43
|
}
|