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/alert.ts
CHANGED
|
@@ -1,94 +1,72 @@
|
|
|
1
|
-
import {
|
|
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 = ['dismiss'] as const;
|
|
2
7
|
|
|
3
|
-
/**
|
|
4
|
-
* Alert component options
|
|
5
|
-
*/
|
|
6
8
|
export interface AlertOptions {
|
|
7
9
|
message?: string;
|
|
8
|
-
|
|
9
|
-
title?: string;
|
|
10
|
+
type?: 'info' | 'success' | 'warning' | 'error';
|
|
10
11
|
dismissible?: boolean;
|
|
11
|
-
onDismiss?: () => void;
|
|
12
12
|
icon?: string;
|
|
13
13
|
style?: string;
|
|
14
14
|
class?: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* Alert component state
|
|
19
|
-
*/
|
|
20
17
|
type AlertState = {
|
|
21
18
|
message: string;
|
|
22
|
-
|
|
23
|
-
title: string;
|
|
19
|
+
type: string;
|
|
24
20
|
dismissible: boolean;
|
|
25
21
|
icon: string;
|
|
22
|
+
visible: boolean;
|
|
26
23
|
style: string;
|
|
27
24
|
class: string;
|
|
28
25
|
};
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
* Usage:
|
|
34
|
-
* jux.alert('my-alert', {
|
|
35
|
-
* variant: 'success',
|
|
36
|
-
* title: 'Success!',
|
|
37
|
-
* message: 'Your changes have been saved.',
|
|
38
|
-
* dismissible: true
|
|
39
|
-
* }).render('#app');
|
|
40
|
-
*
|
|
41
|
-
* Variants: info, success, warning, error
|
|
42
|
-
*/
|
|
43
|
-
export class Alert {
|
|
44
|
-
state: AlertState;
|
|
45
|
-
container: HTMLElement | null = null;
|
|
46
|
-
_id: string;
|
|
47
|
-
id: string;
|
|
48
|
-
private _onDismiss?: () => void;
|
|
27
|
+
export class Alert extends BaseComponent<AlertState> {
|
|
28
|
+
private _alert: HTMLElement | null = null;
|
|
49
29
|
|
|
50
30
|
constructor(id: string, options: AlertOptions = {}) {
|
|
51
|
-
|
|
52
|
-
this.id = id;
|
|
53
|
-
this._onDismiss = options.onDismiss;
|
|
54
|
-
|
|
55
|
-
// Default icons per variant
|
|
56
|
-
const defaultIcons = {
|
|
57
|
-
info: 'ℹ️',
|
|
58
|
-
success: '✅',
|
|
59
|
-
warning: '⚠️',
|
|
60
|
-
error: '❌'
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const variant = options.variant ?? 'info';
|
|
64
|
-
|
|
65
|
-
this.state = {
|
|
31
|
+
super(id, {
|
|
66
32
|
message: options.message ?? '',
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
33
|
+
type: options.type ?? 'info',
|
|
34
|
+
dismissible: options.dismissible ?? true,
|
|
35
|
+
icon: options.icon ?? '',
|
|
36
|
+
visible: true,
|
|
71
37
|
style: options.style ?? '',
|
|
72
38
|
class: options.class ?? ''
|
|
73
|
-
};
|
|
39
|
+
});
|
|
74
40
|
}
|
|
75
41
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
42
|
+
protected getTriggerEvents(): readonly string[] {
|
|
43
|
+
return TRIGGER_EVENTS;
|
|
44
|
+
}
|
|
79
45
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return this;
|
|
46
|
+
protected getCallbackEvents(): readonly string[] {
|
|
47
|
+
return CALLBACK_EVENTS;
|
|
83
48
|
}
|
|
84
49
|
|
|
85
|
-
|
|
86
|
-
|
|
50
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
51
|
+
* FLUENT API
|
|
52
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
53
|
+
|
|
54
|
+
// ✅ Inherited from BaseComponent:
|
|
55
|
+
// - style(), class()
|
|
56
|
+
// - bind(), sync(), renderTo()
|
|
57
|
+
// - addClass(), removeClass(), toggleClass()
|
|
58
|
+
// - visible(), show(), hide(), toggleVisibility()
|
|
59
|
+
// - attr(), attrs(), removeAttr()
|
|
60
|
+
// - disabled(), enable(), disable()
|
|
61
|
+
// - loading(), focus(), blur(), remove()
|
|
62
|
+
|
|
63
|
+
message(value: string): this {
|
|
64
|
+
this.state.message = value;
|
|
87
65
|
return this;
|
|
88
66
|
}
|
|
89
67
|
|
|
90
|
-
|
|
91
|
-
this.state.
|
|
68
|
+
type(value: 'info' | 'success' | 'warning' | 'error'): this {
|
|
69
|
+
this.state.type = value;
|
|
92
70
|
return this;
|
|
93
71
|
}
|
|
94
72
|
|
|
@@ -102,139 +80,208 @@ export class Alert {
|
|
|
102
80
|
return this;
|
|
103
81
|
}
|
|
104
82
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class(value: string): this {
|
|
111
|
-
this.state.class = value;
|
|
112
|
-
return this;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/* -------------------------
|
|
116
|
-
* Methods
|
|
117
|
-
* ------------------------- */
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Dismiss/remove the alert
|
|
121
|
-
*/
|
|
122
|
-
dismiss(): void {
|
|
123
|
-
const element = document.getElementById(this._id);
|
|
124
|
-
if (element) {
|
|
125
|
-
element.style.opacity = '0';
|
|
126
|
-
element.style.transform = 'translateY(-10px)';
|
|
127
|
-
setTimeout(() => {
|
|
128
|
-
element.remove();
|
|
129
|
-
if (this._onDismiss) {
|
|
130
|
-
this._onDismiss();
|
|
131
|
-
}
|
|
132
|
-
}, 200);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Auto-dismiss after delay
|
|
138
|
-
*/
|
|
139
|
-
autoDismiss(delay: number = 5000): this {
|
|
140
|
-
setTimeout(() => this.dismiss(), delay);
|
|
141
|
-
return this;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/* -------------------------
|
|
145
|
-
* Render
|
|
146
|
-
* ------------------------- */
|
|
83
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
84
|
+
* RENDER
|
|
85
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
147
86
|
|
|
148
87
|
render(targetId?: string): this {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (targetId) {
|
|
152
|
-
const target = document.querySelector(targetId);
|
|
153
|
-
if (!target || !(target instanceof HTMLElement)) {
|
|
154
|
-
throw new Error(`Alert: Target element "${targetId}" not found`);
|
|
155
|
-
}
|
|
156
|
-
container = target;
|
|
157
|
-
} else {
|
|
158
|
-
container = getOrCreateContainer(this._id);
|
|
159
|
-
}
|
|
88
|
+
const container = this._setupContainer(targetId);
|
|
160
89
|
|
|
161
|
-
|
|
162
|
-
const
|
|
90
|
+
const { message, type, dismissible, icon, style, class: className } = this.state;
|
|
91
|
+
const hasVisibleSync = this._syncBindings.some(b => b.property === 'visible');
|
|
163
92
|
|
|
93
|
+
// Build alert element
|
|
164
94
|
const alert = document.createElement('div');
|
|
165
|
-
alert.className = `jux-alert jux-alert-${
|
|
95
|
+
alert.className = `jux-alert jux-alert-${type}`;
|
|
166
96
|
alert.id = this._id;
|
|
167
|
-
alert.
|
|
168
|
-
|
|
169
|
-
if (className) {
|
|
170
|
-
alert.className += ` ${className}`;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (style) {
|
|
174
|
-
alert.setAttribute('style', style);
|
|
175
|
-
}
|
|
97
|
+
if (className) alert.className += ` ${className}`;
|
|
98
|
+
if (style) alert.setAttribute('style', style);
|
|
176
99
|
|
|
177
|
-
// Icon
|
|
178
100
|
if (icon) {
|
|
179
101
|
const iconEl = document.createElement('span');
|
|
180
102
|
iconEl.className = 'jux-alert-icon';
|
|
181
|
-
iconEl.
|
|
103
|
+
iconEl.appendChild(renderIcon(icon));
|
|
182
104
|
alert.appendChild(iconEl);
|
|
183
105
|
}
|
|
184
106
|
|
|
185
|
-
// Content
|
|
186
107
|
const content = document.createElement('div');
|
|
187
108
|
content.className = 'jux-alert-content';
|
|
109
|
+
content.textContent = message;
|
|
110
|
+
alert.appendChild(content);
|
|
188
111
|
|
|
189
|
-
if (
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
112
|
+
if (dismissible) {
|
|
113
|
+
const closeBtn = document.createElement('button');
|
|
114
|
+
closeBtn.className = 'jux-alert-close';
|
|
115
|
+
closeBtn.innerHTML = '×';
|
|
116
|
+
alert.appendChild(closeBtn);
|
|
194
117
|
}
|
|
195
118
|
|
|
196
|
-
if
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
119
|
+
// Default dismiss behavior (only if NOT using sync)
|
|
120
|
+
if (!hasVisibleSync && dismissible) {
|
|
121
|
+
const closeBtn = alert.querySelector('.jux-alert-close');
|
|
122
|
+
closeBtn?.addEventListener('click', () => {
|
|
123
|
+
// 🎯 Fire the dismiss callback event
|
|
124
|
+
this._triggerCallback('dismiss');
|
|
125
|
+
alert.remove();
|
|
126
|
+
});
|
|
201
127
|
}
|
|
202
128
|
|
|
203
|
-
|
|
129
|
+
// Wire events using inherited method
|
|
130
|
+
this._wireStandardEvents(alert);
|
|
204
131
|
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
132
|
+
// Wire sync bindings
|
|
133
|
+
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
134
|
+
if (property === 'message') {
|
|
135
|
+
const transform = toComponent || ((v: any) => String(v));
|
|
136
|
+
|
|
137
|
+
stateObj.subscribe((val: any) => {
|
|
138
|
+
const transformed = transform(val);
|
|
139
|
+
content.textContent = transformed;
|
|
140
|
+
this.state.message = transformed;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else if (property === 'type') {
|
|
144
|
+
const transform = toComponent || ((v: any) => String(v));
|
|
145
|
+
|
|
146
|
+
stateObj.subscribe((val: any) => {
|
|
147
|
+
const transformed = transform(val);
|
|
148
|
+
alert.className = `jux-alert jux-alert-${transformed}`;
|
|
149
|
+
if (className) alert.className += ` ${className}`;
|
|
150
|
+
this.state.type = transformed;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else if (property === 'visible') {
|
|
154
|
+
const transformToState = toState || ((v: any) => Boolean(v));
|
|
155
|
+
const transform = toComponent || ((v: any) => Boolean(v));
|
|
156
|
+
|
|
157
|
+
let isUpdating = false;
|
|
158
|
+
|
|
159
|
+
// State → Component
|
|
160
|
+
stateObj.subscribe((val: any) => {
|
|
161
|
+
if (isUpdating) return;
|
|
162
|
+
const transformed = transform(val);
|
|
163
|
+
alert.style.display = transformed ? 'flex' : 'none';
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Component → State (close button)
|
|
167
|
+
if (dismissible) {
|
|
168
|
+
const closeBtn = alert.querySelector('.jux-alert-close');
|
|
169
|
+
closeBtn?.addEventListener('click', () => {
|
|
170
|
+
if (isUpdating) return;
|
|
171
|
+
isUpdating = true;
|
|
172
|
+
|
|
173
|
+
alert.style.display = 'none';
|
|
174
|
+
stateObj.set(transformToState(false));
|
|
175
|
+
|
|
176
|
+
// 🎯 Fire the dismiss callback event
|
|
177
|
+
this._triggerCallback('dismiss');
|
|
178
|
+
|
|
179
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
214
184
|
|
|
215
185
|
container.appendChild(alert);
|
|
216
|
-
|
|
217
|
-
}
|
|
186
|
+
this._alert = alert;
|
|
218
187
|
|
|
219
|
-
|
|
220
|
-
* Render to another Jux component's container
|
|
221
|
-
*/
|
|
222
|
-
renderTo(juxComponent: any): this {
|
|
223
|
-
if (!juxComponent || typeof juxComponent !== 'object') {
|
|
224
|
-
throw new Error('Alert.renderTo: Invalid component - not an object');
|
|
225
|
-
}
|
|
188
|
+
this._injectAlertStyles();
|
|
226
189
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
190
|
+
requestAnimationFrame(() => {
|
|
191
|
+
if ((window as any).lucide) {
|
|
192
|
+
(window as any).lucide.createIcons();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
230
195
|
|
|
231
|
-
return this
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private _injectAlertStyles(): void {
|
|
200
|
+
const styleId = 'jux-alert-styles';
|
|
201
|
+
if (document.getElementById(styleId)) return;
|
|
202
|
+
|
|
203
|
+
const style = document.createElement('style');
|
|
204
|
+
style.id = styleId;
|
|
205
|
+
style.textContent = `
|
|
206
|
+
.jux-alert {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
gap: 12px;
|
|
210
|
+
padding: 16px;
|
|
211
|
+
border-radius: 8px;
|
|
212
|
+
margin-bottom: 12px;
|
|
213
|
+
position: relative;
|
|
214
|
+
animation: slideIn 0.3s ease-out;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@keyframes slideIn {
|
|
218
|
+
from {
|
|
219
|
+
opacity: 0;
|
|
220
|
+
transform: translateX(-20px);
|
|
221
|
+
}
|
|
222
|
+
to {
|
|
223
|
+
opacity: 1;
|
|
224
|
+
transform: translateX(0);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.jux-alert-info {
|
|
229
|
+
background: #dbeafe;
|
|
230
|
+
border-left: 4px solid #3b82f6;
|
|
231
|
+
color: #1e40af;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.jux-alert-success {
|
|
235
|
+
background: #d1fae5;
|
|
236
|
+
border-left: 4px solid #10b981;
|
|
237
|
+
color: #065f46;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.jux-alert-warning {
|
|
241
|
+
background: #fef3c7;
|
|
242
|
+
border-left: 4px solid #f59e0b;
|
|
243
|
+
color: #92400e;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.jux-alert-error {
|
|
247
|
+
background: #fee2e2;
|
|
248
|
+
border-left: 4px solid #ef4444;
|
|
249
|
+
color: #991b1b;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.jux-alert-icon {
|
|
253
|
+
flex-shrink: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.jux-alert-content {
|
|
257
|
+
flex: 1;
|
|
258
|
+
font-size: 14px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.jux-alert-close {
|
|
262
|
+
flex-shrink: 0;
|
|
263
|
+
background: transparent;
|
|
264
|
+
border: none;
|
|
265
|
+
font-size: 24px;
|
|
266
|
+
cursor: pointer;
|
|
267
|
+
opacity: 0.6;
|
|
268
|
+
transition: opacity 0.2s;
|
|
269
|
+
padding: 0;
|
|
270
|
+
width: 24px;
|
|
271
|
+
height: 24px;
|
|
272
|
+
display: flex;
|
|
273
|
+
align-items: center;
|
|
274
|
+
justify-content: center;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.jux-alert-close:hover {
|
|
278
|
+
opacity: 1;
|
|
279
|
+
}
|
|
280
|
+
`;
|
|
281
|
+
document.head.appendChild(style);
|
|
232
282
|
}
|
|
233
283
|
}
|
|
234
284
|
|
|
235
|
-
/**
|
|
236
|
-
* Factory helper
|
|
237
|
-
*/
|
|
238
285
|
export function alert(id: string, options: AlertOptions = {}): Alert {
|
|
239
286
|
return new Alert(id, options);
|
|
240
287
|
}
|