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.
Files changed (76) hide show
  1. package/bin/cli.js +121 -72
  2. package/lib/components/alert.ts +143 -92
  3. package/lib/components/badge.ts +93 -94
  4. package/lib/components/base/BaseComponent.ts +397 -0
  5. package/lib/components/base/FormInput.ts +322 -0
  6. package/lib/components/button.ts +40 -131
  7. package/lib/components/card.ts +57 -79
  8. package/lib/components/charts/areachart.ts +315 -0
  9. package/lib/components/charts/barchart.ts +421 -0
  10. package/lib/components/charts/doughnutchart.ts +263 -0
  11. package/lib/components/charts/lib/BaseChart.ts +402 -0
  12. package/lib/components/{chart-types.ts → charts/lib/chart-types.ts} +1 -1
  13. package/lib/components/{chart-utils.ts → charts/lib/chart-utils.ts} +1 -1
  14. package/lib/components/{chart.ts → charts/lib/chart.ts} +3 -3
  15. package/lib/components/checkbox.ts +255 -204
  16. package/lib/components/code.ts +31 -78
  17. package/lib/components/container.ts +113 -130
  18. package/lib/components/data.ts +37 -5
  19. package/lib/components/datepicker.ts +180 -147
  20. package/lib/components/dialog.ts +218 -221
  21. package/lib/components/divider.ts +63 -87
  22. package/lib/components/docs-data.json +498 -2404
  23. package/lib/components/dropdown.ts +191 -236
  24. package/lib/components/element.ts +196 -145
  25. package/lib/components/fileupload.ts +253 -167
  26. package/lib/components/guard.ts +92 -0
  27. package/lib/components/heading.ts +31 -97
  28. package/lib/components/helpers.ts +13 -6
  29. package/lib/components/hero.ts +51 -114
  30. package/lib/components/icon.ts +33 -120
  31. package/lib/components/icons.ts +2 -1
  32. package/lib/components/include.ts +76 -3
  33. package/lib/components/input.ts +155 -407
  34. package/lib/components/kpicard.ts +16 -16
  35. package/lib/components/list.ts +358 -261
  36. package/lib/components/loading.ts +142 -211
  37. package/lib/components/menu.ts +63 -152
  38. package/lib/components/modal.ts +42 -129
  39. package/lib/components/nav.ts +79 -101
  40. package/lib/components/paragraph.ts +38 -102
  41. package/lib/components/progress.ts +108 -166
  42. package/lib/components/radio.ts +283 -234
  43. package/lib/components/script.ts +19 -87
  44. package/lib/components/select.ts +189 -199
  45. package/lib/components/sidebar.ts +110 -141
  46. package/lib/components/style.ts +19 -82
  47. package/lib/components/switch.ts +254 -183
  48. package/lib/components/table.ts +1078 -208
  49. package/lib/components/tabs.ts +42 -106
  50. package/lib/components/theme-toggle.ts +73 -165
  51. package/lib/components/tooltip.ts +85 -316
  52. package/lib/components/write.ts +108 -127
  53. package/lib/jux.ts +67 -41
  54. package/machinery/build.js +466 -0
  55. package/machinery/compiler.js +354 -105
  56. package/machinery/server.js +23 -100
  57. package/machinery/watcher.js +153 -130
  58. package/package.json +1 -1
  59. package/presets/base.css +1166 -0
  60. package/presets/notion.css +2 -1975
  61. package/lib/adapters/base-adapter.js +0 -35
  62. package/lib/adapters/index.js +0 -33
  63. package/lib/adapters/mysql-adapter.js +0 -65
  64. package/lib/adapters/postgres-adapter.js +0 -70
  65. package/lib/adapters/sqlite-adapter.js +0 -56
  66. package/lib/components/areachart.ts +0 -1128
  67. package/lib/components/areachartsmooth.ts +0 -1380
  68. package/lib/components/barchart.ts +0 -1322
  69. package/lib/components/doughnutchart.ts +0 -1259
  70. package/lib/components/footer.ts +0 -165
  71. package/lib/components/header.ts +0 -187
  72. package/lib/components/layout.ts +0 -239
  73. package/lib/components/main.ts +0 -137
  74. package/lib/layouts/default.jux +0 -8
  75. package/lib/layouts/figma.jux +0 -0
  76. /package/lib/{themes → components/charts/lib}/charts.js +0 -0
@@ -1,288 +1,285 @@
1
- import { getOrCreateContainer } from './helpers.js';
2
- import { State } from '../reactivity/state.js';
1
+ import { BaseComponent } from './base/BaseComponent.js';
2
+
3
+ // Event definitions
4
+ const TRIGGER_EVENTS = [] as const;
5
+ const CALLBACK_EVENTS = ['confirm', 'cancel'] as const;
3
6
 
4
7
  export interface DialogOptions {
5
8
  title?: string;
6
- content?: string;
7
- showClose?: boolean;
8
- modal?: boolean;
9
- width?: string;
9
+ message?: string;
10
+ confirmText?: string;
11
+ cancelText?: string;
12
+ variant?: 'default' | 'danger' | 'warning';
10
13
  style?: string;
11
14
  class?: string;
12
15
  }
13
16
 
14
17
  type DialogState = {
15
18
  title: string;
16
- content: string;
17
- showClose: boolean;
18
- modal: boolean;
19
- width: string;
20
- style: string;
21
- class: string;
22
- isOpen: boolean;
23
- open: boolean;
24
19
  message: string;
25
- type: string;
26
20
  confirmText: string;
27
21
  cancelText: string;
28
- onConfirm?: Function;
29
- onCancel?: Function;
22
+ variant: string;
23
+ open: boolean;
24
+ style: string;
25
+ class: string;
30
26
  };
31
27
 
32
- export class Dialog {
33
- state: DialogState;
34
- container: HTMLElement | null = null;
35
- _id: string;
36
- id: string;
37
-
38
- // CRITICAL: Store bind/sync instructions for deferred wiring
39
- private _bindings: Array<{ event: string, handler: Function }> = [];
40
- private _syncBindings: Array<{
41
- property: string,
42
- stateObj: State<any>,
43
- toState?: Function,
44
- toComponent?: Function
45
- }> = [];
28
+ export class Dialog extends BaseComponent<DialogState> {
29
+ private _dialog: HTMLElement | null = null;
30
+ private _overlay: HTMLElement | null = null;
46
31
 
47
32
  constructor(id: string, options: DialogOptions = {}) {
48
- this._id = id;
49
- this.id = id;
50
-
51
- this.state = {
52
- title: options.title ?? '',
53
- content: options.content ?? '',
54
- showClose: options.showClose ?? true,
55
- modal: options.modal ?? true,
56
- width: options.width ?? '500px',
57
- style: options.style ?? '',
58
- class: options.class ?? '',
59
- isOpen: false,
33
+ super(id, {
34
+ title: options.title ?? 'Confirm',
35
+ message: options.message ?? 'Are you sure?',
36
+ confirmText: options.confirmText ?? 'Confirm',
37
+ cancelText: options.cancelText ?? 'Cancel',
38
+ variant: options.variant ?? 'default',
60
39
  open: false,
61
- message: '',
62
- type: 'info',
63
- confirmText: 'OK',
64
- cancelText: 'Cancel'
65
- };
40
+ style: options.style ?? '',
41
+ class: options.class ?? ''
42
+ });
66
43
  }
67
44
 
68
- /* -------------------------
69
- * Fluent API
70
- * ------------------------- */
71
-
72
- title(value: string): this {
73
- this.state.title = value;
74
- return this;
45
+ protected getTriggerEvents(): readonly string[] {
46
+ return TRIGGER_EVENTS;
75
47
  }
76
48
 
77
- content(value: string): this {
78
- this.state.content = value;
79
- return this;
49
+ protected getCallbackEvents(): readonly string[] {
50
+ return CALLBACK_EVENTS;
80
51
  }
81
52
 
82
- showClose(value: boolean): this {
83
- this.state.showClose = value;
84
- return this;
85
- }
53
+ /* ═════════════════════════════════════════════════════════════════
54
+ * FLUENT API
55
+ * ═════════════════════════════════════════════════════════════════ */
86
56
 
87
- modal(value: boolean): this {
88
- this.state.modal = value;
57
+ title(value: string): this {
58
+ this.state.title = value;
89
59
  return this;
90
60
  }
91
61
 
92
- width(value: string): this {
93
- this.state.width = value;
62
+ message(value: string): this {
63
+ this.state.message = value;
94
64
  return this;
95
65
  }
96
66
 
97
- style(value: string): this {
98
- this.state.style = value;
67
+ confirmText(value: string): this {
68
+ this.state.confirmText = value;
99
69
  return this;
100
70
  }
101
71
 
102
- class(value: string): this {
103
- this.state.class = value;
72
+ cancelText(value: string): this {
73
+ this.state.cancelText = value;
104
74
  return this;
105
75
  }
106
76
 
107
- bind(event: string, handler: Function): this {
108
- this._bindings.push({ event, handler });
77
+ variant(value: 'default' | 'danger' | 'warning'): this {
78
+ this.state.variant = value;
109
79
  return this;
110
80
  }
111
81
 
112
- sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
113
- if (!stateObj || typeof stateObj.subscribe !== 'function') {
114
- throw new Error(`Dialog.sync: Expected a State object for property "${property}"`);
82
+ open(): this {
83
+ this.state.open = true;
84
+ if (this._overlay) {
85
+ this._overlay.style.display = 'flex';
115
86
  }
116
- this._syncBindings.push({ property, stateObj, toState, toComponent });
117
87
  return this;
118
88
  }
119
89
 
120
- /* -------------------------
121
- * Methods
122
- * ------------------------- */
123
-
124
- open(): void {
125
- this.state.isOpen = true;
126
- const dialog = document.getElementById(this._id);
127
- if (dialog) {
128
- dialog.style.display = 'flex';
129
- }
130
- }
131
-
132
- close(): void {
133
- this.state.isOpen = false;
134
- const dialog = document.getElementById(this._id);
135
- if (dialog) {
136
- dialog.style.display = 'none';
90
+ close(): this {
91
+ this.state.open = false;
92
+ if (this._overlay) {
93
+ this._overlay.style.display = 'none';
137
94
  }
95
+ return this;
138
96
  }
139
97
 
140
- /* -------------------------
141
- * Render
142
- * ------------------------- */
98
+ /* ═════════════════════════════════════════════════════════════════
99
+ * RENDER
100
+ * ═════════════════════════════════════════════════════════════════ */
143
101
 
144
102
  render(targetId?: string): this {
145
- // === 1. SETUP: Get or create container ===
146
- let container: HTMLElement;
147
- if (targetId) {
148
- const target = document.querySelector(targetId);
149
- if (!target || !(target instanceof HTMLElement)) {
150
- throw new Error(`Dialog: Target "${targetId}" not found`);
151
- }
152
- container = target;
153
- } else {
154
- container = getOrCreateContainer(this._id);
155
- }
156
- this.container = container;
157
-
158
- // === 2. PREPARE: Destructure state and check sync flags ===
159
- const { open, title, message, type, confirmText, cancelText, onConfirm, onCancel, style, class: className } = this.state;
160
- const hasOpenSync = this._syncBindings.some(b => b.property === 'open');
103
+ const { title, message, confirmText, cancelText, variant, style, class: className } = this.state;
161
104
 
162
- // === 3. BUILD: Create DOM elements ===
105
+ // Overlay
163
106
  const overlay = document.createElement('div');
164
107
  overlay.className = 'jux-dialog-overlay';
165
- overlay.id = this._id;
166
- overlay.style.display = open ? 'flex' : 'none';
167
- if (className) overlay.className += ` ${className}`;
168
- if (style) overlay.setAttribute('style', style);
108
+ overlay.style.display = 'none';
109
+ this._overlay = overlay;
169
110
 
111
+ // Dialog
170
112
  const dialog = document.createElement('div');
171
- dialog.className = `jux-dialog jux-dialog-${type}`;
172
-
173
- if (title) {
174
- const header = document.createElement('div');
175
- header.className = 'jux-dialog-header';
176
- header.textContent = title;
177
- dialog.appendChild(header);
178
- }
179
-
180
- const body = document.createElement('div');
181
- body.className = 'jux-dialog-body';
182
- body.textContent = message;
183
- dialog.appendChild(body);
184
-
185
- const footer = document.createElement('div');
186
- footer.className = 'jux-dialog-footer';
113
+ dialog.className = `jux-dialog jux-dialog-${variant}`;
114
+ dialog.id = this._id;
115
+ if (className) dialog.className += ` ${className}`;
116
+ if (style) dialog.setAttribute('style', style);
117
+ this._dialog = dialog;
118
+
119
+ // Title
120
+ const titleEl = document.createElement('div');
121
+ titleEl.className = 'jux-dialog-title';
122
+ titleEl.textContent = title;
123
+ dialog.appendChild(titleEl);
124
+
125
+ // Message
126
+ const messageEl = document.createElement('div');
127
+ messageEl.className = 'jux-dialog-message';
128
+ messageEl.textContent = message;
129
+ dialog.appendChild(messageEl);
130
+
131
+ // Actions
132
+ const actions = document.createElement('div');
133
+ actions.className = 'jux-dialog-actions';
134
+
135
+ const cancelBtn = document.createElement('button');
136
+ cancelBtn.className = 'jux-dialog-button jux-dialog-button-cancel';
137
+ cancelBtn.textContent = cancelText;
138
+ cancelBtn.addEventListener('click', () => {
139
+ this._triggerCallback('cancel');
140
+ this.close();
141
+ });
187
142
 
188
- const cancelButton = document.createElement('button');
189
- cancelButton.className = 'jux-dialog-button jux-dialog-button-cancel';
190
- cancelButton.textContent = cancelText;
143
+ const confirmBtn = document.createElement('button');
144
+ confirmBtn.className = `jux-dialog-button jux-dialog-button-confirm jux-dialog-button-${variant}`;
145
+ confirmBtn.textContent = confirmText;
146
+ confirmBtn.addEventListener('click', () => {
147
+ this._triggerCallback('confirm');
148
+ this.close();
149
+ });
191
150
 
192
- const confirmButton = document.createElement('button');
193
- confirmButton.className = 'jux-dialog-button jux-dialog-button-confirm';
194
- confirmButton.textContent = confirmText;
151
+ actions.appendChild(cancelBtn);
152
+ actions.appendChild(confirmBtn);
153
+ dialog.appendChild(actions);
195
154
 
196
- footer.appendChild(cancelButton);
197
- footer.appendChild(confirmButton);
198
- dialog.appendChild(footer);
155
+ // Close on overlay click
156
+ overlay.addEventListener('click', (e) => {
157
+ if (e.target === overlay) {
158
+ this._triggerCallback('cancel');
159
+ this.close();
160
+ }
161
+ });
199
162
 
200
163
  overlay.appendChild(dialog);
164
+ document.body.appendChild(overlay);
201
165
 
202
- // === 4. WIRE: Attach event listeners and sync bindings ===
203
-
204
- // Default button behavior (only if NOT using sync)
205
- if (!hasOpenSync) {
206
- cancelButton.addEventListener('click', () => {
207
- this.state.open = false;
208
- overlay.style.display = 'none';
209
- if (onCancel) onCancel();
210
- });
211
-
212
- confirmButton.addEventListener('click', () => {
213
- this.state.open = false;
214
- overlay.style.display = 'none';
215
- if (onConfirm) onConfirm();
216
- });
217
- }
218
-
219
- // Wire custom bindings from .bind() calls
220
- this._bindings.forEach(({ event, handler }) => {
221
- overlay.addEventListener(event, handler as EventListener);
222
- });
223
-
224
- // Wire sync bindings from .sync() calls
225
- this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
226
- if (property === 'open') {
227
- const transformToState = toState || ((v: any) => Boolean(v));
228
- const transformToComponent = toComponent || ((v: any) => Boolean(v));
229
-
230
- let isUpdating = false;
231
-
232
- // State → Component
233
- stateObj.subscribe((val: any) => {
234
- if (isUpdating) return;
235
- const transformed = transformToComponent(val);
236
- this.state.open = transformed;
237
- overlay.style.display = transformed ? 'flex' : 'none';
238
- });
239
-
240
- // Component → State (button clicks)
241
- cancelButton.addEventListener('click', () => {
242
- if (isUpdating) return;
243
- isUpdating = true;
244
-
245
- this.state.open = false;
246
- overlay.style.display = 'none';
247
- if (onCancel) onCancel();
248
- stateObj.set(transformToState(false));
249
-
250
- setTimeout(() => { isUpdating = false; }, 0);
251
- });
252
-
253
- confirmButton.addEventListener('click', () => {
254
- if (isUpdating) return;
255
- isUpdating = true;
256
-
257
- this.state.open = false;
258
- overlay.style.display = 'none';
259
- if (onConfirm) onConfirm();
260
- stateObj.set(transformToState(false));
261
-
262
- setTimeout(() => { isUpdating = false; }, 0);
263
- });
264
- }
265
- else if (property === 'message') {
266
- const transformToComponent = toComponent || ((v: any) => String(v));
267
-
268
- stateObj.subscribe((val: any) => {
269
- const transformed = transformToComponent(val);
270
- body.textContent = transformed;
271
- this.state.message = transformed;
272
- });
273
- }
274
- });
166
+ this._injectDialogStyles();
275
167
 
276
- // === 5. RENDER: Append to DOM and finalize ===
277
- container.appendChild(overlay);
278
168
  return this;
279
169
  }
280
170
 
281
- renderTo(juxComponent: any): this {
282
- if (!juxComponent?._id) {
283
- throw new Error('Dialog.renderTo: Invalid component');
171
+ private _injectDialogStyles(): void {
172
+ const styleId = 'jux-dialog-styles';
173
+ if (document.getElementById(styleId)) return;
174
+
175
+ const style = document.createElement('style');
176
+ style.id = styleId;
177
+ style.textContent = `
178
+ .jux-dialog-overlay {
179
+ position: fixed;
180
+ top: 0;
181
+ left: 0;
182
+ right: 0;
183
+ bottom: 0;
184
+ background: rgba(0, 0, 0, 0.5);
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: center;
188
+ z-index: 10000;
189
+ animation: jux-dialog-fade 0.2s;
190
+ }
191
+
192
+ @keyframes jux-dialog-fade {
193
+ from { opacity: 0; }
194
+ to { opacity: 1; }
195
+ }
196
+
197
+ .jux-dialog {
198
+ background: white;
199
+ border-radius: 12px;
200
+ padding: 24px;
201
+ max-width: 400px;
202
+ width: 90%;
203
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
204
+ animation: jux-dialog-slide 0.3s;
205
+ }
206
+
207
+ @keyframes jux-dialog-slide {
208
+ from {
209
+ opacity: 0;
210
+ transform: translateY(-20px);
211
+ }
212
+ to {
213
+ opacity: 1;
214
+ transform: translateY(0);
284
215
  }
285
- return this.render(`#${juxComponent._id}`);
216
+ }
217
+
218
+ .jux-dialog-title {
219
+ font-size: 20px;
220
+ font-weight: 600;
221
+ margin-bottom: 12px;
222
+ color: #1f2937;
223
+ }
224
+
225
+ .jux-dialog-message {
226
+ font-size: 14px;
227
+ color: #6b7280;
228
+ margin-bottom: 24px;
229
+ line-height: 1.5;
230
+ }
231
+
232
+ .jux-dialog-actions {
233
+ display: flex;
234
+ gap: 12px;
235
+ justify-content: flex-end;
236
+ }
237
+
238
+ .jux-dialog-button {
239
+ padding: 8px 16px;
240
+ border-radius: 6px;
241
+ font-size: 14px;
242
+ font-weight: 500;
243
+ cursor: pointer;
244
+ transition: all 0.2s;
245
+ border: none;
246
+ }
247
+
248
+ .jux-dialog-button-cancel {
249
+ background: #f3f4f6;
250
+ color: #374151;
251
+ }
252
+
253
+ .jux-dialog-button-cancel:hover {
254
+ background: #e5e7eb;
255
+ }
256
+
257
+ .jux-dialog-button-confirm {
258
+ background: #3b82f6;
259
+ color: white;
260
+ }
261
+
262
+ .jux-dialog-button-confirm:hover {
263
+ background: #2563eb;
264
+ }
265
+
266
+ .jux-dialog-button-danger {
267
+ background: #ef4444;
268
+ }
269
+
270
+ .jux-dialog-button-danger:hover {
271
+ background: #dc2626;
272
+ }
273
+
274
+ .jux-dialog-button-warning {
275
+ background: #f59e0b;
276
+ }
277
+
278
+ .jux-dialog-button-warning:hover {
279
+ background: #d97706;
280
+ }
281
+ `;
282
+ document.head.appendChild(style);
286
283
  }
287
284
  }
288
285