juxscript 1.0.18 → 1.0.20
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/lib/components/alert.ts +124 -128
- package/lib/components/areachart.ts +169 -287
- package/lib/components/areachartsmooth.ts +2 -2
- package/lib/components/badge.ts +63 -72
- package/lib/components/barchart.ts +120 -48
- package/lib/components/button.ts +99 -101
- package/lib/components/card.ts +97 -121
- package/lib/components/chart-types.ts +159 -0
- package/lib/components/chart-utils.ts +160 -0
- package/lib/components/chart.ts +628 -48
- package/lib/components/checkbox.ts +137 -51
- package/lib/components/code.ts +89 -75
- package/lib/components/container.ts +1 -1
- package/lib/components/datepicker.ts +93 -78
- package/lib/components/dialog.ts +163 -130
- package/lib/components/divider.ts +111 -193
- package/lib/components/docs-data.json +711 -264
- package/lib/components/doughnutchart.ts +125 -57
- package/lib/components/dropdown.ts +172 -85
- package/lib/components/element.ts +66 -61
- package/lib/components/fileupload.ts +142 -171
- package/lib/components/heading.ts +64 -21
- package/lib/components/hero.ts +109 -34
- package/lib/components/icon.ts +247 -0
- package/lib/components/icons.ts +174 -0
- package/lib/components/include.ts +77 -2
- package/lib/components/input.ts +174 -125
- package/lib/components/list.ts +120 -79
- package/lib/components/menu.ts +97 -2
- package/lib/components/modal.ts +144 -63
- package/lib/components/nav.ts +153 -52
- package/lib/components/paragraph.ts +78 -28
- package/lib/components/progress.ts +83 -107
- package/lib/components/radio.ts +151 -52
- package/lib/components/select.ts +110 -102
- package/lib/components/sidebar.ts +148 -105
- package/lib/components/switch.ts +124 -125
- package/lib/components/table.ts +214 -137
- package/lib/components/tabs.ts +194 -113
- package/lib/components/theme-toggle.ts +38 -7
- package/lib/components/tooltip.ts +207 -47
- package/lib/jux.ts +24 -5
- package/lib/reactivity/state.ts +13 -299
- package/package.json +1 -2
package/lib/components/badge.ts
CHANGED
|
@@ -1,87 +1,64 @@
|
|
|
1
1
|
import { getOrCreateContainer } from './helpers.js';
|
|
2
|
+
import { State } from '../reactivity/state.js';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
-
* Badge component options
|
|
5
|
-
*/
|
|
6
4
|
export interface BadgeOptions {
|
|
7
5
|
text?: string;
|
|
8
|
-
variant?: '
|
|
9
|
-
size?: 'sm' | 'md' | 'lg';
|
|
10
|
-
pill?: boolean;
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';
|
|
7
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
11
8
|
style?: string;
|
|
12
9
|
class?: string;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
|
-
/**
|
|
16
|
-
* Badge component state
|
|
17
|
-
*/
|
|
18
12
|
type BadgeState = {
|
|
19
13
|
text: string;
|
|
20
14
|
variant: string;
|
|
21
15
|
size: string;
|
|
22
|
-
pill: boolean;
|
|
23
16
|
style: string;
|
|
24
17
|
class: string;
|
|
25
18
|
};
|
|
26
19
|
|
|
27
|
-
/**
|
|
28
|
-
* Badge component - Status indicators, counts, labels
|
|
29
|
-
*
|
|
30
|
-
* Usage:
|
|
31
|
-
* jux.badge('status', {
|
|
32
|
-
* text: 'Active',
|
|
33
|
-
* variant: 'success',
|
|
34
|
-
* pill: true
|
|
35
|
-
* }).render('#card');
|
|
36
|
-
*
|
|
37
|
-
* jux.badge('count', { text: '5' }).render('#notifications');
|
|
38
|
-
*/
|
|
39
20
|
export class Badge {
|
|
40
21
|
state: BadgeState;
|
|
41
22
|
container: HTMLElement | null = null;
|
|
42
23
|
_id: string;
|
|
43
24
|
id: string;
|
|
44
25
|
|
|
26
|
+
private _bindings: Array<{ event: string, handler: Function }> = [];
|
|
27
|
+
private _syncBindings: Array<{
|
|
28
|
+
property: string,
|
|
29
|
+
stateObj: State<any>,
|
|
30
|
+
toState?: Function,
|
|
31
|
+
toComponent?: Function
|
|
32
|
+
}> = [];
|
|
33
|
+
|
|
45
34
|
constructor(id: string, options: BadgeOptions = {}) {
|
|
46
35
|
this._id = id;
|
|
47
36
|
this.id = id;
|
|
48
37
|
|
|
49
38
|
this.state = {
|
|
50
39
|
text: options.text ?? '',
|
|
51
|
-
variant: options.variant ?? '
|
|
40
|
+
variant: options.variant ?? 'primary',
|
|
52
41
|
size: options.size ?? 'md',
|
|
53
|
-
pill: options.pill ?? false,
|
|
54
42
|
style: options.style ?? '',
|
|
55
43
|
class: options.class ?? ''
|
|
56
44
|
};
|
|
57
45
|
}
|
|
58
46
|
|
|
59
|
-
/* -------------------------
|
|
60
|
-
* Fluent API
|
|
61
|
-
* ------------------------- */
|
|
62
|
-
|
|
63
47
|
text(value: string): this {
|
|
64
48
|
this.state.text = value;
|
|
65
|
-
this._updateElement();
|
|
66
49
|
return this;
|
|
67
50
|
}
|
|
68
51
|
|
|
69
|
-
variant(value: '
|
|
52
|
+
variant(value: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'): this {
|
|
70
53
|
this.state.variant = value;
|
|
71
|
-
this._updateElement();
|
|
72
54
|
return this;
|
|
73
55
|
}
|
|
74
56
|
|
|
75
|
-
size(value: 'sm' | 'md' | 'lg'): this {
|
|
57
|
+
size(value: 'xs' | 'sm' | 'md' | 'lg' | 'xl'): this {
|
|
76
58
|
this.state.size = value;
|
|
77
59
|
return this;
|
|
78
60
|
}
|
|
79
61
|
|
|
80
|
-
pill(value: boolean): this {
|
|
81
|
-
this.state.pill = value;
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
62
|
style(value: string): this {
|
|
86
63
|
this.state.style = value;
|
|
87
64
|
return this;
|
|
@@ -92,61 +69,75 @@ export class Badge {
|
|
|
92
69
|
return this;
|
|
93
70
|
}
|
|
94
71
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
private _updateElement(): void {
|
|
100
|
-
const element = document.getElementById(this._id);
|
|
101
|
-
if (element) {
|
|
102
|
-
element.textContent = this.state.text;
|
|
103
|
-
element.className = `jux-badge jux-badge-${this.state.variant} jux-badge-${this.state.size}`;
|
|
104
|
-
if (this.state.pill) {
|
|
105
|
-
element.classList.add('jux-badge-pill');
|
|
106
|
-
}
|
|
107
|
-
if (this.state.class) {
|
|
108
|
-
element.className += ` ${this.state.class}`;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
72
|
+
bind(event: string, handler: Function): this {
|
|
73
|
+
this._bindings.push({ event, handler });
|
|
74
|
+
return this;
|
|
111
75
|
}
|
|
112
76
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
77
|
+
sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
|
|
78
|
+
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
79
|
+
throw new Error(`Badge.sync: Expected a State object for property "${property}"`);
|
|
80
|
+
}
|
|
81
|
+
this._syncBindings.push({ property, stateObj, toState, toComponent });
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
116
84
|
|
|
117
85
|
render(targetId?: string): this {
|
|
86
|
+
// === 1. SETUP: Get or create container ===
|
|
118
87
|
let container: HTMLElement;
|
|
119
|
-
|
|
120
88
|
if (targetId) {
|
|
121
89
|
const target = document.querySelector(targetId);
|
|
122
90
|
if (!target || !(target instanceof HTMLElement)) {
|
|
123
|
-
throw new Error(`Badge: Target
|
|
91
|
+
throw new Error(`Badge: Target "${targetId}" not found`);
|
|
124
92
|
}
|
|
125
93
|
container = target;
|
|
126
94
|
} else {
|
|
127
95
|
container = getOrCreateContainer(this._id);
|
|
128
96
|
}
|
|
129
|
-
|
|
130
97
|
this.container = container;
|
|
131
|
-
const { text, variant, size, pill, style, class: className } = this.state;
|
|
132
98
|
|
|
99
|
+
// === 2. PREPARE: Destructure state ===
|
|
100
|
+
const { text, variant, size, style, class: className } = this.state;
|
|
101
|
+
|
|
102
|
+
// === 3. BUILD: Create DOM elements ===
|
|
133
103
|
const badge = document.createElement('span');
|
|
134
104
|
badge.className = `jux-badge jux-badge-${variant} jux-badge-${size}`;
|
|
135
105
|
badge.id = this._id;
|
|
136
106
|
badge.textContent = text;
|
|
107
|
+
if (className) badge.className += ` ${className}`;
|
|
108
|
+
if (style) badge.setAttribute('style', style);
|
|
109
|
+
|
|
110
|
+
// === 4. WIRE: Attach event listeners and sync bindings ===
|
|
111
|
+
|
|
112
|
+
// Wire custom bindings from .bind() calls
|
|
113
|
+
this._bindings.forEach(({ event, handler }) => {
|
|
114
|
+
badge.addEventListener(event, handler as EventListener);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Wire sync bindings from .sync() calls
|
|
118
|
+
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
119
|
+
if (property === 'text') {
|
|
120
|
+
const transformToComponent = toComponent || ((v: any) => String(v));
|
|
121
|
+
|
|
122
|
+
stateObj.subscribe((val: any) => {
|
|
123
|
+
const transformed = transformToComponent(val);
|
|
124
|
+
badge.textContent = transformed;
|
|
125
|
+
this.state.text = transformed;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else if (property === 'variant') {
|
|
129
|
+
const transformToComponent = toComponent || ((v: any) => String(v));
|
|
130
|
+
|
|
131
|
+
stateObj.subscribe((val: any) => {
|
|
132
|
+
const transformed = transformToComponent(val);
|
|
133
|
+
badge.classList.remove(`jux-badge-${this.state.variant}`);
|
|
134
|
+
this.state.variant = transformed;
|
|
135
|
+
badge.classList.add(`jux-badge-${transformed}`);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
badge.classList.add('jux-badge-pill');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (className) {
|
|
143
|
-
badge.className += ` ${className}`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (style) {
|
|
147
|
-
badge.setAttribute('style', style);
|
|
148
|
-
}
|
|
149
|
-
|
|
140
|
+
// === 5. RENDER: Append to DOM and finalize ===
|
|
150
141
|
container.appendChild(badge);
|
|
151
142
|
return this;
|
|
152
143
|
}
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { getOrCreateContainer } from './helpers.js';
|
|
2
2
|
import { State } from '../reactivity/state.js';
|
|
3
|
+
import {
|
|
4
|
+
ChartDataPoint,
|
|
5
|
+
BarAreaChartOptions,
|
|
6
|
+
BarAreaChartState,
|
|
7
|
+
ChartTheme,
|
|
8
|
+
ChartStyleMode,
|
|
9
|
+
ChartOrientation,
|
|
10
|
+
ChartDirection,
|
|
11
|
+
LegendOrientation,
|
|
12
|
+
ChartPropertyMapping,
|
|
13
|
+
ChartStateObject
|
|
14
|
+
} from './chart-types.js';
|
|
15
|
+
import {
|
|
16
|
+
lightenColor,
|
|
17
|
+
getThemeConfig,
|
|
18
|
+
createLegend,
|
|
19
|
+
createDataTable,
|
|
20
|
+
applyThemeStyles
|
|
21
|
+
} from './chart-utils.js';
|
|
3
22
|
import {
|
|
4
23
|
googleTheme,
|
|
5
24
|
seriesaTheme,
|
|
@@ -384,6 +403,105 @@ export class BarChart {
|
|
|
384
403
|
return this;
|
|
385
404
|
}
|
|
386
405
|
|
|
406
|
+
/* -------------------------
|
|
407
|
+
* Reactivity Support
|
|
408
|
+
* ------------------------- */
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Sync a single property to a state object
|
|
412
|
+
*/
|
|
413
|
+
sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
|
|
414
|
+
const transform = toComponent || ((v: any) => v);
|
|
415
|
+
|
|
416
|
+
stateObj.subscribe((val: any) => {
|
|
417
|
+
const transformed = transform(val);
|
|
418
|
+
|
|
419
|
+
// Map property to correct method
|
|
420
|
+
switch (property) {
|
|
421
|
+
case 'data': this.data(transformed); break;
|
|
422
|
+
case 'title': this.title(transformed); break;
|
|
423
|
+
case 'subtitle': this.subtitle(transformed); break;
|
|
424
|
+
case 'width': this.width(transformed); break;
|
|
425
|
+
case 'height': this.height(transformed); break;
|
|
426
|
+
case 'theme': this.theme(transformed); break;
|
|
427
|
+
case 'styleMode': this.styleMode(transformed); break;
|
|
428
|
+
case 'borderRadius': this.borderRadius(transformed); break;
|
|
429
|
+
case 'showTicksX': this.showTicksX(transformed); break;
|
|
430
|
+
case 'showTicksY': this.showTicksY(transformed); break;
|
|
431
|
+
case 'showLegend': this.showLegend(transformed); break;
|
|
432
|
+
case 'showDataLabels': this.showDataLabels(transformed); break;
|
|
433
|
+
case 'showDataTable': this.showDataTable(transformed); break;
|
|
434
|
+
case 'animate': this.animate(transformed); break;
|
|
435
|
+
case 'animationDuration': this.animationDuration(transformed); break;
|
|
436
|
+
case 'legendOrientation': this.legendOrientation(transformed); break;
|
|
437
|
+
case 'chartOrientation': this.chartOrientation(transformed); break;
|
|
438
|
+
case 'chartDirection': this.chartDirection(transformed); break;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
return this;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Sync multiple properties from a state object
|
|
447
|
+
*/
|
|
448
|
+
syncState(stateObject: ChartStateObject, mapping?: ChartPropertyMapping): this {
|
|
449
|
+
// Default mapping: camelCase state names to method names
|
|
450
|
+
const defaultMapping: ChartPropertyMapping = {
|
|
451
|
+
chartType: 'type', // Not used in bar chart, ignored
|
|
452
|
+
chartTheme: 'theme',
|
|
453
|
+
chartStyleMode: 'styleMode',
|
|
454
|
+
borderRadius: 'borderRadius',
|
|
455
|
+
chartTitle: 'title',
|
|
456
|
+
chartWidth: 'width',
|
|
457
|
+
chartHeight: 'height',
|
|
458
|
+
showTicksX: 'showTicksX',
|
|
459
|
+
showTicksY: 'showTicksY',
|
|
460
|
+
showLegend: 'showLegend',
|
|
461
|
+
showDataTable: 'showDataTable',
|
|
462
|
+
showDataLabels: 'showDataLabels',
|
|
463
|
+
animate: 'animate',
|
|
464
|
+
animationDuration: 'animationDuration',
|
|
465
|
+
legendOrientation: 'legendOrientation',
|
|
466
|
+
chartOrientation: 'chartOrientation',
|
|
467
|
+
chartDirection: 'chartDirection'
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const finalMapping = { ...defaultMapping, ...mapping };
|
|
471
|
+
|
|
472
|
+
// Iterate through state object and bind each property
|
|
473
|
+
Object.entries(stateObject).forEach(([key, stateObj]) => {
|
|
474
|
+
if (!stateObj || typeof stateObj.subscribe !== 'function') {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const methodOrFunction = finalMapping[key];
|
|
479
|
+
|
|
480
|
+
if (!methodOrFunction) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (typeof methodOrFunction === 'function') {
|
|
485
|
+
// Custom function mapping
|
|
486
|
+
stateObj.subscribe(methodOrFunction);
|
|
487
|
+
} else {
|
|
488
|
+
// String mapping to method name
|
|
489
|
+
const methodName = methodOrFunction as keyof this;
|
|
490
|
+
const method = this[methodName];
|
|
491
|
+
|
|
492
|
+
if (typeof method !== 'function') {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
stateObj.subscribe((val: any) => {
|
|
497
|
+
(method as Function).call(this, val);
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
return this;
|
|
503
|
+
}
|
|
504
|
+
|
|
387
505
|
/* -------------------------
|
|
388
506
|
* Update chart
|
|
389
507
|
* ------------------------- */
|
|
@@ -1049,59 +1167,13 @@ export class BarChart {
|
|
|
1049
1167
|
}
|
|
1050
1168
|
|
|
1051
1169
|
private _applyTheme(themeName: string): void {
|
|
1052
|
-
const
|
|
1053
|
-
google: googleTheme,
|
|
1054
|
-
seriesa: seriesaTheme,
|
|
1055
|
-
hr: hrTheme,
|
|
1056
|
-
figma: figmaTheme,
|
|
1057
|
-
notion: notionTheme,
|
|
1058
|
-
chalk: chalkTheme,
|
|
1059
|
-
mint: mintTheme
|
|
1060
|
-
};
|
|
1061
|
-
|
|
1062
|
-
const theme = themes[themeName];
|
|
1170
|
+
const theme = getThemeConfig(themeName as ChartTheme);
|
|
1063
1171
|
if (!theme) return;
|
|
1064
1172
|
|
|
1065
1173
|
// Apply colors
|
|
1066
1174
|
this.state.colors = theme.colors;
|
|
1067
1175
|
|
|
1068
|
-
|
|
1069
|
-
const baseStyleId = 'jux-barchart-base-styles';
|
|
1070
|
-
if (!document.getElementById(baseStyleId)) {
|
|
1071
|
-
const style = document.createElement('style');
|
|
1072
|
-
style.id = baseStyleId;
|
|
1073
|
-
style.textContent = this._getBaseStyles();
|
|
1074
|
-
document.head.appendChild(style);
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
// Inject font (once per theme)
|
|
1078
|
-
if (theme.font && !document.querySelector(`link[href="${theme.font}"]`)) {
|
|
1079
|
-
const link = document.createElement('link');
|
|
1080
|
-
link.rel = 'stylesheet';
|
|
1081
|
-
link.href = theme.font;
|
|
1082
|
-
document.head.appendChild(link);
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
// Apply theme-specific styles
|
|
1086
|
-
const styleId = `jux-barchart-theme-${themeName}`;
|
|
1087
|
-
let styleElement = document.getElementById(styleId) as HTMLStyleElement;
|
|
1088
|
-
|
|
1089
|
-
if (!styleElement) {
|
|
1090
|
-
styleElement = document.createElement('style');
|
|
1091
|
-
styleElement.id = styleId;
|
|
1092
|
-
document.head.appendChild(styleElement);
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
// Generate CSS with theme variables
|
|
1096
|
-
const variablesCSS = Object.entries(theme.variables)
|
|
1097
|
-
.map(([key, value]) => ` ${key}: ${value};`)
|
|
1098
|
-
.join('\n');
|
|
1099
|
-
|
|
1100
|
-
styleElement.textContent = `
|
|
1101
|
-
.jux-barchart.theme-${themeName} {
|
|
1102
|
-
${variablesCSS}
|
|
1103
|
-
}
|
|
1104
|
-
`;
|
|
1176
|
+
applyThemeStyles(themeName as ChartTheme, 'jux-barchart', this._getBaseStyles());
|
|
1105
1177
|
}
|
|
1106
1178
|
|
|
1107
1179
|
private _applyThemeToWrapper(wrapper: HTMLElement): void {
|