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
package/lib/components/icon.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { State } from '../reactivity/state.js';
|
|
1
|
+
import { BaseComponent } from './base/BaseComponent.js';
|
|
3
2
|
import { renderIcon, renderEmoji } from './icons.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
// Event definitions
|
|
5
|
+
const TRIGGER_EVENTS = [] as const;
|
|
6
|
+
const CALLBACK_EVENTS = [] as const;
|
|
7
|
+
|
|
8
8
|
export interface IconOptions {
|
|
9
9
|
value: string;
|
|
10
10
|
size?: string;
|
|
@@ -14,9 +14,6 @@ export interface IconOptions {
|
|
|
14
14
|
class?: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* Icon component state
|
|
19
|
-
*/
|
|
20
17
|
type IconState = {
|
|
21
18
|
value: string;
|
|
22
19
|
size: string;
|
|
@@ -26,54 +23,31 @@ type IconState = {
|
|
|
26
23
|
class: string;
|
|
27
24
|
};
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
* Icon component - Render an icon from emoji, icon name, or image path
|
|
31
|
-
*
|
|
32
|
-
* Usage:
|
|
33
|
-
* // Render Lucide icon from emoji
|
|
34
|
-
* jux.icon('myIcon', { value: '🚀' }).render('#container');
|
|
35
|
-
*
|
|
36
|
-
* // Render Lucide icon from name
|
|
37
|
-
* jux.icon('myIcon', { value: 'rocket', size: '32px', color: 'red' }).render('#container');
|
|
38
|
-
*
|
|
39
|
-
* // Render image icon
|
|
40
|
-
* jux.icon('myIcon', { value: '/path/icon.png' }).render('#container');
|
|
41
|
-
*
|
|
42
|
-
* // Force emoji rendering (skip conversion)
|
|
43
|
-
* jux.icon('myIcon', { value: '🚀', useEmoji: true }).render('#container');
|
|
44
|
-
*/
|
|
45
|
-
export class Icon {
|
|
46
|
-
state: IconState;
|
|
47
|
-
container: HTMLElement | null = null;
|
|
48
|
-
_id: string;
|
|
49
|
-
id: string;
|
|
50
|
-
|
|
51
|
-
// CRITICAL: Store bind/sync instructions for deferred wiring
|
|
52
|
-
private _bindings: Array<{ event: string, handler: Function }> = [];
|
|
53
|
-
private _syncBindings: Array<{
|
|
54
|
-
property: string,
|
|
55
|
-
stateObj: State<any>,
|
|
56
|
-
toState?: Function,
|
|
57
|
-
toComponent?: Function
|
|
58
|
-
}> = [];
|
|
59
|
-
|
|
26
|
+
export class Icon extends BaseComponent<IconState> {
|
|
60
27
|
constructor(id: string, options: IconOptions) {
|
|
61
|
-
|
|
62
|
-
this.id = id;
|
|
63
|
-
|
|
64
|
-
this.state = {
|
|
28
|
+
super(id, {
|
|
65
29
|
value: options.value,
|
|
66
30
|
size: options.size ?? '24px',
|
|
67
31
|
color: options.color ?? '',
|
|
68
32
|
useEmoji: options.useEmoji ?? false,
|
|
69
33
|
style: options.style ?? '',
|
|
70
34
|
class: options.class ?? ''
|
|
71
|
-
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected getTriggerEvents(): readonly string[] {
|
|
39
|
+
return TRIGGER_EVENTS;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected getCallbackEvents(): readonly string[] {
|
|
43
|
+
return CALLBACK_EVENTS;
|
|
72
44
|
}
|
|
73
45
|
|
|
74
|
-
/*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
46
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
47
|
+
* FLUENT API
|
|
48
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
49
|
+
|
|
50
|
+
// ✅ Inherited from BaseComponent
|
|
77
51
|
|
|
78
52
|
value(value: string): this {
|
|
79
53
|
this.state.value = value;
|
|
@@ -95,51 +69,15 @@ export class Icon {
|
|
|
95
69
|
return this;
|
|
96
70
|
}
|
|
97
71
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
class(value: string): this {
|
|
104
|
-
this.state.class = value;
|
|
105
|
-
return this;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
bind(event: string, handler: Function): this {
|
|
109
|
-
this._bindings.push({ event, handler });
|
|
110
|
-
return this;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
|
|
114
|
-
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
115
|
-
throw new Error(`Icon.sync: Expected a State object for property "${property}"`);
|
|
116
|
-
}
|
|
117
|
-
this._syncBindings.push({ property, stateObj, toState, toComponent });
|
|
118
|
-
return this;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* -------------------------
|
|
122
|
-
* Render (5-Step Pattern)
|
|
123
|
-
* ------------------------- */
|
|
72
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
73
|
+
* RENDER
|
|
74
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
124
75
|
|
|
125
76
|
render(targetId?: string): this {
|
|
126
|
-
|
|
127
|
-
let container: HTMLElement;
|
|
128
|
-
if (targetId) {
|
|
129
|
-
const target = document.querySelector(targetId);
|
|
130
|
-
if (!target || !(target instanceof HTMLElement)) {
|
|
131
|
-
throw new Error(`Icon: Target element "${targetId}" not found`);
|
|
132
|
-
}
|
|
133
|
-
container = target;
|
|
134
|
-
} else {
|
|
135
|
-
container = getOrCreateContainer(this._id);
|
|
136
|
-
}
|
|
137
|
-
this.container = container;
|
|
77
|
+
const container = this._setupContainer(targetId);
|
|
138
78
|
|
|
139
|
-
// === 2. PREPARE: Destructure state ===
|
|
140
79
|
const { value, size, color, useEmoji, style, class: className } = this.state;
|
|
141
80
|
|
|
142
|
-
// === 3. BUILD: Create DOM elements ===
|
|
143
81
|
const wrapper = document.createElement('span');
|
|
144
82
|
wrapper.className = 'jux-icon';
|
|
145
83
|
wrapper.id = this._id;
|
|
@@ -153,23 +91,17 @@ export class Icon {
|
|
|
153
91
|
|
|
154
92
|
wrapper.appendChild(iconElement);
|
|
155
93
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// Wire custom bindings from .bind() calls
|
|
159
|
-
this._bindings.forEach(({ event, handler }) => {
|
|
160
|
-
wrapper.addEventListener(event, handler as EventListener);
|
|
161
|
-
});
|
|
94
|
+
this._wireStandardEvents(wrapper);
|
|
162
95
|
|
|
163
|
-
// Wire sync bindings
|
|
96
|
+
// Wire sync bindings
|
|
164
97
|
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
165
98
|
if (property === 'value') {
|
|
166
|
-
const
|
|
99
|
+
const transform = toComponent || ((v: any) => String(v));
|
|
167
100
|
|
|
168
101
|
stateObj.subscribe((val: any) => {
|
|
169
|
-
const transformed =
|
|
102
|
+
const transformed = transform(val);
|
|
170
103
|
this.state.value = transformed;
|
|
171
104
|
|
|
172
|
-
// Re-render icon
|
|
173
105
|
wrapper.innerHTML = '';
|
|
174
106
|
const newIcon = this.state.useEmoji ? renderEmoji(transformed) : renderIcon(transformed);
|
|
175
107
|
newIcon.style.width = this.state.size;
|
|
@@ -185,10 +117,10 @@ export class Icon {
|
|
|
185
117
|
});
|
|
186
118
|
}
|
|
187
119
|
else if (property === 'size') {
|
|
188
|
-
const
|
|
120
|
+
const transform = toComponent || ((v: any) => String(v));
|
|
189
121
|
|
|
190
122
|
stateObj.subscribe((val: any) => {
|
|
191
|
-
const transformed =
|
|
123
|
+
const transformed = transform(val);
|
|
192
124
|
const icon = wrapper.querySelector('img, svg, span');
|
|
193
125
|
if (icon instanceof HTMLElement) {
|
|
194
126
|
icon.style.width = transformed;
|
|
@@ -198,10 +130,10 @@ export class Icon {
|
|
|
198
130
|
});
|
|
199
131
|
}
|
|
200
132
|
else if (property === 'color') {
|
|
201
|
-
const
|
|
133
|
+
const transform = toComponent || ((v: any) => String(v));
|
|
202
134
|
|
|
203
135
|
stateObj.subscribe((val: any) => {
|
|
204
|
-
const transformed =
|
|
136
|
+
const transformed = transform(val);
|
|
205
137
|
const icon = wrapper.querySelector('img, svg, span');
|
|
206
138
|
if (icon instanceof HTMLElement) {
|
|
207
139
|
icon.style.color = transformed;
|
|
@@ -211,7 +143,6 @@ export class Icon {
|
|
|
211
143
|
}
|
|
212
144
|
});
|
|
213
145
|
|
|
214
|
-
// === 5. RENDER: Append to DOM and finalize ===
|
|
215
146
|
container.appendChild(wrapper);
|
|
216
147
|
|
|
217
148
|
requestAnimationFrame(() => {
|
|
@@ -222,26 +153,8 @@ export class Icon {
|
|
|
222
153
|
|
|
223
154
|
return this;
|
|
224
155
|
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Render to another Jux component's container
|
|
228
|
-
*/
|
|
229
|
-
renderTo(juxComponent: any): this {
|
|
230
|
-
if (!juxComponent || typeof juxComponent !== 'object') {
|
|
231
|
-
throw new Error('Icon.renderTo: Invalid component - not an object');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
235
|
-
throw new Error('Icon.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return this.render(`#${juxComponent._id}`);
|
|
239
|
-
}
|
|
240
156
|
}
|
|
241
157
|
|
|
242
|
-
/**
|
|
243
|
-
* Factory helper
|
|
244
|
-
*/
|
|
245
158
|
export function icon(id: string, options: IconOptions): Icon {
|
|
246
159
|
return new Icon(id, options);
|
|
247
160
|
}
|
package/lib/components/icons.ts
CHANGED
|
@@ -22,6 +22,7 @@ export class Include {
|
|
|
22
22
|
private type: IncludeType;
|
|
23
23
|
private options: IncludeOptions = {};
|
|
24
24
|
private element: HTMLElement | null = null;
|
|
25
|
+
private explicitType: boolean = false; // NEW: Track if type was explicitly set
|
|
25
26
|
|
|
26
27
|
constructor(urlOrFile: string) {
|
|
27
28
|
this.url = urlOrFile;
|
|
@@ -33,11 +34,25 @@ export class Include {
|
|
|
33
34
|
* ------------------------- */
|
|
34
35
|
|
|
35
36
|
private detectType(url: string): IncludeType {
|
|
37
|
+
// Check for common script patterns in URLs (CDN, etc.)
|
|
38
|
+
if (url.includes('tailwindcss') ||
|
|
39
|
+
url.includes('jsdelivr.net/npm') ||
|
|
40
|
+
url.includes('unpkg.com') ||
|
|
41
|
+
url.includes('cdn.') ||
|
|
42
|
+
url.match(/\.(js|mjs)($|\?)/)) {
|
|
43
|
+
return 'script';
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
if (url.endsWith('.css')) return 'stylesheet';
|
|
37
|
-
if (url.endsWith('.js') || url.endsWith('.mjs')) return 'script';
|
|
38
47
|
if (url.endsWith('.json')) return 'json';
|
|
39
48
|
if (url.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)) return 'image';
|
|
40
49
|
if (url.match(/\.(woff|woff2|ttf|otf|eot)$/i)) return 'font';
|
|
50
|
+
|
|
51
|
+
// Default to script for extensionless URLs from CDN domains
|
|
52
|
+
if (!url.includes('.') || url.match(/^https?:\/\/cdn/)) {
|
|
53
|
+
return 'script';
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
return 'preload';
|
|
42
57
|
}
|
|
43
58
|
|
|
@@ -45,49 +60,93 @@ export class Include {
|
|
|
45
60
|
* Fluent Type Setters
|
|
46
61
|
* ------------------------- */
|
|
47
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Force treat as CSS stylesheet
|
|
65
|
+
* Use when URL doesn't have .css extension
|
|
66
|
+
*/
|
|
48
67
|
withCss(): this {
|
|
49
68
|
this.type = 'stylesheet';
|
|
69
|
+
this.explicitType = true; // Mark as explicit
|
|
50
70
|
return this;
|
|
51
71
|
}
|
|
52
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Force treat as JavaScript
|
|
75
|
+
* Use when URL doesn't have .js extension (CDN scripts, etc.)
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* jux.include('https://cdn.tailwindcss.com').withJs().render();
|
|
79
|
+
* jux.include('https://unpkg.com/alpine').withJs({ defer: true }).render();
|
|
80
|
+
*/
|
|
53
81
|
withJs(options?: { async?: boolean; defer?: boolean }): this {
|
|
54
82
|
this.type = 'script';
|
|
83
|
+
this.explicitType = true; // Mark as explicit
|
|
55
84
|
if (options?.async) this.options.async = true;
|
|
56
85
|
if (options?.defer) this.options.defer = true;
|
|
57
86
|
return this;
|
|
58
87
|
}
|
|
59
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Force treat as ES module
|
|
91
|
+
* Use for module scripts
|
|
92
|
+
*/
|
|
60
93
|
withModule(): this {
|
|
61
94
|
this.type = 'module';
|
|
95
|
+
this.explicitType = true; // Mark as explicit
|
|
62
96
|
return this;
|
|
63
97
|
}
|
|
64
98
|
|
|
65
99
|
withImage(): this {
|
|
66
100
|
this.type = 'image';
|
|
101
|
+
this.explicitType = true;
|
|
67
102
|
return this;
|
|
68
103
|
}
|
|
69
104
|
|
|
70
105
|
withFont(): this {
|
|
71
106
|
this.type = 'font';
|
|
107
|
+
this.explicitType = true;
|
|
72
108
|
return this;
|
|
73
109
|
}
|
|
74
110
|
|
|
75
111
|
withPreload(as?: string): this {
|
|
76
112
|
this.type = 'preload';
|
|
113
|
+
this.explicitType = true;
|
|
77
114
|
if (as) this.options.as = as;
|
|
78
115
|
return this;
|
|
79
116
|
}
|
|
80
117
|
|
|
81
118
|
withPrefetch(): this {
|
|
82
119
|
this.type = 'prefetch';
|
|
120
|
+
this.explicitType = true;
|
|
83
121
|
return this;
|
|
84
122
|
}
|
|
85
123
|
|
|
86
124
|
withJson(): this {
|
|
87
125
|
this.type = 'json';
|
|
126
|
+
this.explicitType = true;
|
|
88
127
|
return this;
|
|
89
128
|
}
|
|
90
129
|
|
|
130
|
+
/* -------------------------
|
|
131
|
+
* Convenience aliases for common patterns
|
|
132
|
+
* ------------------------- */
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Shorthand for .withJs()
|
|
136
|
+
* @example jux.include(url).asScript()
|
|
137
|
+
*/
|
|
138
|
+
asScript(options?: { async?: boolean; defer?: boolean }): this {
|
|
139
|
+
return this.withJs(options);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Shorthand for .withCss()
|
|
144
|
+
* @example jux.include(url).asStylesheet()
|
|
145
|
+
*/
|
|
146
|
+
asStylesheet(): this {
|
|
147
|
+
return this.withCss();
|
|
148
|
+
}
|
|
149
|
+
|
|
91
150
|
/* -------------------------
|
|
92
151
|
* JSON Fetching
|
|
93
152
|
* ------------------------- */
|
|
@@ -227,6 +286,10 @@ export class Include {
|
|
|
227
286
|
}
|
|
228
287
|
|
|
229
288
|
this.element = element;
|
|
289
|
+
|
|
290
|
+
// Log with type indicator
|
|
291
|
+
const typeIndicator = this.explicitType ? '(explicit)' : '(auto-detected)';
|
|
292
|
+
console.log(`✓ Include loaded as ${this.type} ${typeIndicator}: ${this.url}`);
|
|
230
293
|
} catch (error: any) {
|
|
231
294
|
ErrorHandler.captureError({
|
|
232
295
|
component: 'Include',
|
|
@@ -238,6 +301,7 @@ export class Include {
|
|
|
238
301
|
type: this.type,
|
|
239
302
|
url: this.url,
|
|
240
303
|
location: this.options.location,
|
|
304
|
+
explicitType: this.explicitType,
|
|
241
305
|
error: 'runtime_exception'
|
|
242
306
|
}
|
|
243
307
|
});
|
|
@@ -345,11 +409,20 @@ export class Include {
|
|
|
345
409
|
* Factory function - auto-detects type and renders immediately
|
|
346
410
|
*
|
|
347
411
|
* Usage:
|
|
412
|
+
* // Auto-detect (works for most cases)
|
|
348
413
|
* jux.include('styles.css');
|
|
349
414
|
* jux.include('script.js').async();
|
|
415
|
+
*
|
|
416
|
+
* // Explicit type (for extensionless URLs)
|
|
417
|
+
* jux.include('https://cdn.tailwindcss.com').withJs();
|
|
418
|
+
* jux.include('https://cdn.tailwindcss.com').asScript();
|
|
419
|
+
* jux.include('https://unpkg.com/htmx.org').withJs({ defer: true });
|
|
420
|
+
*
|
|
421
|
+
* // CDN with parameters
|
|
422
|
+
* jux.include('https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4').withJs();
|
|
423
|
+
*
|
|
424
|
+
* // Module
|
|
350
425
|
* jux.include('app.mjs').withModule();
|
|
351
|
-
* jux.include('custom.js').withJs({ async: true, defer: true });
|
|
352
|
-
* jux.include('https://cdn.com/lib.js').inHead().defer();
|
|
353
426
|
*
|
|
354
427
|
* // For JSON:
|
|
355
428
|
* const data = await jux.include('config.json').asJson();
|