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
|
@@ -1,92 +1,73 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { FormInput, FormInputState } from './base/FormInput.js';
|
|
2
|
+
import { renderIcon } from './icons.js';
|
|
3
|
+
|
|
4
|
+
// Event definitions
|
|
5
|
+
const TRIGGER_EVENTS = [] as const;
|
|
6
|
+
const CALLBACK_EVENTS = ['change'] as const;
|
|
3
7
|
|
|
4
|
-
/**
|
|
5
|
-
* DatePicker component options
|
|
6
|
-
*/
|
|
7
8
|
export interface DatePickerOptions {
|
|
8
9
|
value?: string;
|
|
9
|
-
|
|
10
|
-
max?: string;
|
|
10
|
+
label?: string;
|
|
11
11
|
placeholder?: string;
|
|
12
|
+
required?: boolean;
|
|
12
13
|
disabled?: boolean;
|
|
13
14
|
name?: string;
|
|
14
|
-
|
|
15
|
+
min?: string;
|
|
16
|
+
max?: string;
|
|
15
17
|
style?: string;
|
|
16
18
|
class?: string;
|
|
19
|
+
onValidate?: (value: string) => boolean | string;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
* DatePicker component state
|
|
21
|
-
*/
|
|
22
|
-
type DatePickerState = {
|
|
22
|
+
interface DatePickerState extends FormInputState {
|
|
23
23
|
value: string;
|
|
24
|
-
min: string;
|
|
25
|
-
max: string;
|
|
26
24
|
placeholder: string;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class: string;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* DatePicker component - Calendar input
|
|
35
|
-
*
|
|
36
|
-
* Usage:
|
|
37
|
-
* jux.datepicker('start-date', {
|
|
38
|
-
* placeholder: 'Select date',
|
|
39
|
-
* value: '2024-01-15',
|
|
40
|
-
* onChange: (date) => console.log(date)
|
|
41
|
-
* }).render('#form');
|
|
42
|
-
*
|
|
43
|
-
* // Two-way binding
|
|
44
|
-
* const dateState = state('2024-01-15');
|
|
45
|
-
* jux.datepicker('date').bind(dateState).render('#form');
|
|
46
|
-
*/
|
|
47
|
-
export class DatePicker {
|
|
48
|
-
state: DatePickerState;
|
|
49
|
-
container: HTMLElement | null = null;
|
|
50
|
-
_id: string;
|
|
51
|
-
id: string;
|
|
52
|
-
private _onChange?: (value: string) => void;
|
|
53
|
-
private _boundState?: State<string>;
|
|
25
|
+
min?: string;
|
|
26
|
+
max?: string;
|
|
27
|
+
}
|
|
54
28
|
|
|
29
|
+
export class DatePicker extends FormInput<DatePickerState> {
|
|
55
30
|
constructor(id: string, options: DatePickerOptions = {}) {
|
|
56
|
-
|
|
57
|
-
this.id = id;
|
|
58
|
-
this._onChange = options.onChange;
|
|
59
|
-
|
|
60
|
-
this.state = {
|
|
31
|
+
super(id, {
|
|
61
32
|
value: options.value ?? '',
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
33
|
+
placeholder: options.placeholder ?? 'Select a date',
|
|
34
|
+
label: options.label ?? '',
|
|
35
|
+
required: options.required ?? false,
|
|
65
36
|
disabled: options.disabled ?? false,
|
|
66
37
|
name: options.name ?? id,
|
|
38
|
+
min: options.min,
|
|
39
|
+
max: options.max,
|
|
67
40
|
style: options.style ?? '',
|
|
68
|
-
class: options.class ?? ''
|
|
69
|
-
|
|
70
|
-
|
|
41
|
+
class: options.class ?? '',
|
|
42
|
+
errorMessage: undefined
|
|
43
|
+
});
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
45
|
+
if (options.onValidate) {
|
|
46
|
+
this._onValidate = options.onValidate;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
75
49
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this._updateElement();
|
|
79
|
-
return this;
|
|
50
|
+
protected getTriggerEvents(): readonly string[] {
|
|
51
|
+
return TRIGGER_EVENTS;
|
|
80
52
|
}
|
|
81
53
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return this;
|
|
54
|
+
protected getCallbackEvents(): readonly string[] {
|
|
55
|
+
return CALLBACK_EVENTS;
|
|
85
56
|
}
|
|
86
57
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
58
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
59
|
+
* FLUENT API
|
|
60
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
61
|
+
|
|
62
|
+
// ✅ Inherited from FormInput/BaseComponent:
|
|
63
|
+
// - label(), required(), name(), onValidate()
|
|
64
|
+
// - validate(), isValid()
|
|
65
|
+
// - style(), class()
|
|
66
|
+
// - bind(), sync(), renderTo()
|
|
67
|
+
// - disabled(), enable(), disable()
|
|
68
|
+
|
|
69
|
+
value(value: string): this {
|
|
70
|
+
return this.setValue(value);
|
|
90
71
|
}
|
|
91
72
|
|
|
92
73
|
placeholder(value: string): this {
|
|
@@ -94,130 +75,197 @@ export class DatePicker {
|
|
|
94
75
|
return this;
|
|
95
76
|
}
|
|
96
77
|
|
|
97
|
-
|
|
98
|
-
this.state.
|
|
99
|
-
this._updateElement();
|
|
78
|
+
min(value: string): this {
|
|
79
|
+
this.state.min = value;
|
|
100
80
|
return this;
|
|
101
81
|
}
|
|
102
82
|
|
|
103
|
-
|
|
104
|
-
this.state.
|
|
83
|
+
max(value: string): this {
|
|
84
|
+
this.state.max = value;
|
|
105
85
|
return this;
|
|
106
86
|
}
|
|
107
87
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
88
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
89
|
+
* FORM INPUT IMPLEMENTATION
|
|
90
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
112
91
|
|
|
113
|
-
|
|
114
|
-
this.state.
|
|
115
|
-
return this;
|
|
92
|
+
getValue(): string {
|
|
93
|
+
return this.state.value;
|
|
116
94
|
}
|
|
117
95
|
|
|
118
|
-
|
|
119
|
-
this.
|
|
96
|
+
setValue(value: string): this {
|
|
97
|
+
this.state.value = value;
|
|
98
|
+
if (this._inputElement) {
|
|
99
|
+
(this._inputElement as HTMLInputElement).value = value;
|
|
100
|
+
}
|
|
120
101
|
return this;
|
|
121
102
|
}
|
|
122
103
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
this._boundState = stateObj;
|
|
128
|
-
|
|
129
|
-
stateObj.subscribe((val) => {
|
|
130
|
-
this.state.value = val;
|
|
131
|
-
this._updateElement();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
this.onChange((value) => stateObj.set(value));
|
|
135
|
-
|
|
136
|
-
return this;
|
|
104
|
+
getDate(): Date | null {
|
|
105
|
+
if (!this.state.value) return null;
|
|
106
|
+
const date = new Date(this.state.value);
|
|
107
|
+
return isNaN(date.getTime()) ? null : date;
|
|
137
108
|
}
|
|
138
109
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
* ------------------------- */
|
|
110
|
+
protected _validateValue(value: string): boolean | string {
|
|
111
|
+
const { required, min, max } = this.state;
|
|
142
112
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (input) {
|
|
146
|
-
input.value = this.state.value;
|
|
147
|
-
input.disabled = this.state.disabled;
|
|
113
|
+
if (required && !value) {
|
|
114
|
+
return 'Please select a date';
|
|
148
115
|
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
getValue(): string {
|
|
152
|
-
return this.state.value;
|
|
153
|
-
}
|
|
154
116
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
117
|
+
if (value) {
|
|
118
|
+
const date = new Date(value);
|
|
158
119
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
120
|
+
if (isNaN(date.getTime())) {
|
|
121
|
+
return 'Invalid date';
|
|
122
|
+
}
|
|
162
123
|
|
|
163
|
-
|
|
164
|
-
|
|
124
|
+
if (min) {
|
|
125
|
+
const minDate = new Date(min);
|
|
126
|
+
if (date < minDate) {
|
|
127
|
+
return `Date must be on or after ${min}`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
165
130
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
131
|
+
if (max) {
|
|
132
|
+
const maxDate = new Date(max);
|
|
133
|
+
if (date > maxDate) {
|
|
134
|
+
return `Date must be on or before ${max}`;
|
|
135
|
+
}
|
|
170
136
|
}
|
|
171
|
-
container = target;
|
|
172
|
-
} else {
|
|
173
|
-
container = getOrCreateContainer(this._id);
|
|
174
137
|
}
|
|
175
138
|
|
|
176
|
-
this.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
wrapper.id = this._id;
|
|
182
|
-
|
|
183
|
-
if (className) {
|
|
184
|
-
wrapper.className += ` ${className}`;
|
|
139
|
+
if (this._onValidate) {
|
|
140
|
+
const result = this._onValidate(value);
|
|
141
|
+
if (result !== true) {
|
|
142
|
+
return result || 'Invalid date';
|
|
143
|
+
}
|
|
185
144
|
}
|
|
186
145
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
protected _buildInputElement(): HTMLElement {
|
|
150
|
+
const { value, placeholder, required, disabled, name, min, max } = this.state;
|
|
190
151
|
|
|
191
152
|
const input = document.createElement('input');
|
|
192
153
|
input.type = 'date';
|
|
193
|
-
input.className = 'jux-datepicker-input';
|
|
154
|
+
input.className = 'jux-input-element jux-datepicker-input';
|
|
194
155
|
input.id = `${this._id}-input`;
|
|
195
156
|
input.name = name;
|
|
196
157
|
input.value = value;
|
|
158
|
+
input.placeholder = placeholder;
|
|
159
|
+
input.required = required;
|
|
197
160
|
input.disabled = disabled;
|
|
198
161
|
|
|
199
162
|
if (min) input.min = min;
|
|
200
163
|
if (max) input.max = max;
|
|
201
|
-
if (placeholder) input.setAttribute('placeholder', placeholder);
|
|
202
164
|
|
|
203
|
-
input
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
165
|
+
return input;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
169
|
+
* RENDER
|
|
170
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
171
|
+
|
|
172
|
+
render(targetId?: string): this {
|
|
173
|
+
const container = this._setupContainer(targetId);
|
|
174
|
+
|
|
175
|
+
const { style, class: className } = this.state;
|
|
176
|
+
|
|
177
|
+
// Build wrapper
|
|
178
|
+
const wrapper = document.createElement('div');
|
|
179
|
+
wrapper.className = 'jux-input jux-datepicker';
|
|
180
|
+
wrapper.id = this._id;
|
|
181
|
+
if (className) wrapper.className += ` ${className}`;
|
|
182
|
+
if (style) wrapper.setAttribute('style', style);
|
|
183
|
+
|
|
184
|
+
// Label
|
|
185
|
+
if (this.state.label) {
|
|
186
|
+
wrapper.appendChild(this._renderLabel());
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Input container
|
|
190
|
+
const inputContainer = document.createElement('div');
|
|
191
|
+
inputContainer.className = 'jux-input-container jux-datepicker-container';
|
|
192
|
+
|
|
193
|
+
// Calendar icon
|
|
194
|
+
const iconEl = document.createElement('span');
|
|
195
|
+
iconEl.className = 'jux-input-icon';
|
|
196
|
+
iconEl.appendChild(renderIcon('calendar'));
|
|
197
|
+
inputContainer.appendChild(iconEl);
|
|
198
|
+
|
|
199
|
+
// Date input
|
|
200
|
+
const inputEl = this._buildInputElement();
|
|
201
|
+
this._inputElement = inputEl;
|
|
202
|
+
inputContainer.appendChild(inputEl);
|
|
203
|
+
wrapper.appendChild(inputContainer);
|
|
204
|
+
|
|
205
|
+
// Error element
|
|
206
|
+
wrapper.appendChild(this._renderError());
|
|
207
|
+
|
|
208
|
+
// Wire events
|
|
209
|
+
this._wireStandardEvents(wrapper);
|
|
210
|
+
this._wireFormSync(inputEl, 'change');
|
|
211
|
+
|
|
212
|
+
// 🎯 Fire change event when date changes
|
|
213
|
+
inputEl.addEventListener('change', () => {
|
|
214
|
+
const input = inputEl as HTMLInputElement;
|
|
215
|
+
this._triggerCallback('change', input.value);
|
|
209
216
|
});
|
|
210
217
|
|
|
211
|
-
|
|
218
|
+
// Sync label changes
|
|
219
|
+
const labelSync = this._syncBindings.find(b => b.property === 'label');
|
|
220
|
+
if (labelSync) {
|
|
221
|
+
const transform = labelSync.toComponent || ((v: any) => String(v));
|
|
222
|
+
labelSync.stateObj.subscribe((val: any) => {
|
|
223
|
+
this.label(transform(val));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
212
227
|
container.appendChild(wrapper);
|
|
228
|
+
this._injectDatePickerStyles();
|
|
229
|
+
this._injectFormStyles();
|
|
230
|
+
|
|
231
|
+
requestAnimationFrame(() => {
|
|
232
|
+
if ((window as any).lucide) {
|
|
233
|
+
(window as any).lucide.createIcons();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
213
237
|
return this;
|
|
214
238
|
}
|
|
215
239
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
240
|
+
private _injectDatePickerStyles(): void {
|
|
241
|
+
const styleId = 'jux-datepicker-styles';
|
|
242
|
+
if (document.getElementById(styleId)) return;
|
|
243
|
+
|
|
244
|
+
const style = document.createElement('style');
|
|
245
|
+
style.id = styleId;
|
|
246
|
+
style.textContent = `
|
|
247
|
+
.jux-datepicker-container {
|
|
248
|
+
position: relative;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.jux-datepicker-container .jux-input-icon {
|
|
252
|
+
pointer-events: none;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.jux-datepicker-input {
|
|
256
|
+
padding-left: 40px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.jux-datepicker-input::-webkit-calendar-picker-indicator {
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
opacity: 0;
|
|
262
|
+
position: absolute;
|
|
263
|
+
right: 0;
|
|
264
|
+
width: 100%;
|
|
265
|
+
height: 100%;
|
|
266
|
+
}
|
|
267
|
+
`;
|
|
268
|
+
document.head.appendChild(style);
|
|
221
269
|
}
|
|
222
270
|
}
|
|
223
271
|
|