juxscript 1.1.2 → 1.1.4
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/machinery/build3.js +7 -91
- package/machinery/compiler3.js +3 -209
- package/machinery/config.js +93 -6
- package/machinery/serve.js +255 -0
- package/machinery/watcher.js +49 -161
- package/package.json +19 -5
- package/lib/components/alert.ts +0 -200
- package/lib/components/app.ts +0 -247
- package/lib/components/badge.ts +0 -101
- package/lib/components/base/BaseComponent.ts +0 -421
- package/lib/components/base/FormInput.ts +0 -227
- package/lib/components/button.ts +0 -178
- package/lib/components/card.ts +0 -173
- package/lib/components/chart.ts +0 -231
- package/lib/components/checkbox.ts +0 -242
- package/lib/components/code.ts +0 -123
- package/lib/components/container.ts +0 -140
- package/lib/components/data.ts +0 -135
- package/lib/components/datepicker.ts +0 -234
- package/lib/components/dialog.ts +0 -172
- package/lib/components/divider.ts +0 -100
- package/lib/components/dropdown.ts +0 -186
- package/lib/components/element.ts +0 -267
- package/lib/components/fileupload.ts +0 -309
- package/lib/components/grid.ts +0 -291
- package/lib/components/guard.ts +0 -92
- package/lib/components/heading.ts +0 -96
- package/lib/components/helpers.ts +0 -41
- package/lib/components/hero.ts +0 -224
- package/lib/components/icon.ts +0 -178
- package/lib/components/icons.ts +0 -464
- package/lib/components/include.ts +0 -410
- package/lib/components/input.ts +0 -457
- package/lib/components/list.ts +0 -419
- package/lib/components/loading.ts +0 -100
- package/lib/components/menu.ts +0 -275
- package/lib/components/modal.ts +0 -284
- package/lib/components/nav.ts +0 -257
- package/lib/components/paragraph.ts +0 -97
- package/lib/components/progress.ts +0 -159
- package/lib/components/radio.ts +0 -278
- package/lib/components/req.ts +0 -303
- package/lib/components/script.ts +0 -41
- package/lib/components/select.ts +0 -252
- package/lib/components/sidebar.ts +0 -275
- package/lib/components/style.ts +0 -41
- package/lib/components/switch.ts +0 -246
- package/lib/components/table.ts +0 -1249
- package/lib/components/tabs.ts +0 -250
- package/lib/components/theme-toggle.ts +0 -293
- package/lib/components/tooltip.ts +0 -144
- package/lib/components/view.ts +0 -190
- package/lib/components/write.ts +0 -272
- package/lib/layouts/default.css +0 -260
- package/lib/layouts/figma.css +0 -334
- package/lib/reactivity/state.ts +0 -78
- package/lib/utils/fetch.ts +0 -553
- package/machinery/ast.js +0 -347
- package/machinery/build.js +0 -466
- package/machinery/bundleAssets.js +0 -0
- package/machinery/bundleJux.js +0 -0
- package/machinery/bundleVendors.js +0 -0
- package/machinery/doc-generator.js +0 -136
- package/machinery/imports.js +0 -155
- package/machinery/server.js +0 -166
- package/machinery/ts-shim.js +0 -46
- package/machinery/validators/file-validator.js +0 -123
package/lib/components/button.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
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 = ['click'] as const; // ✅ Button fires click events
|
|
7
|
-
|
|
8
|
-
export interface ButtonOptions {
|
|
9
|
-
label?: string;
|
|
10
|
-
icon?: string;
|
|
11
|
-
variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'link' | string;
|
|
12
|
-
size?: 'small' | 'medium' | 'large';
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
loading?: boolean;
|
|
15
|
-
iconPosition?: 'left' | 'right';
|
|
16
|
-
fullWidth?: boolean;
|
|
17
|
-
type?: 'button' | 'submit' | 'reset';
|
|
18
|
-
style?: string;
|
|
19
|
-
class?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type ButtonState = {
|
|
23
|
-
label: string;
|
|
24
|
-
icon: string;
|
|
25
|
-
variant: string;
|
|
26
|
-
size: string;
|
|
27
|
-
disabled: boolean;
|
|
28
|
-
loading: boolean;
|
|
29
|
-
iconPosition: string;
|
|
30
|
-
fullWidth: boolean;
|
|
31
|
-
type: 'button' | 'submit' | 'reset';
|
|
32
|
-
style: string;
|
|
33
|
-
class: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export class Button extends BaseComponent<ButtonState> {
|
|
37
|
-
private _buttonElement: HTMLButtonElement | null = null; // ✅ Store button reference
|
|
38
|
-
|
|
39
|
-
constructor(id: string, options?: ButtonOptions) {
|
|
40
|
-
const opts = options || {};
|
|
41
|
-
|
|
42
|
-
super(id, {
|
|
43
|
-
label: opts.label ?? 'Button',
|
|
44
|
-
icon: opts.icon ?? '',
|
|
45
|
-
variant: opts.variant ?? 'primary',
|
|
46
|
-
size: opts.size ?? 'medium',
|
|
47
|
-
disabled: opts.disabled ?? false,
|
|
48
|
-
loading: opts.loading ?? false,
|
|
49
|
-
iconPosition: opts.iconPosition ?? 'left',
|
|
50
|
-
fullWidth: opts.fullWidth ?? false,
|
|
51
|
-
type: opts.type ?? 'button',
|
|
52
|
-
style: opts.style ?? '',
|
|
53
|
-
class: opts.class ?? ''
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
protected getTriggerEvents(): readonly string[] {
|
|
58
|
-
return TRIGGER_EVENTS;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected getCallbackEvents(): readonly string[] {
|
|
62
|
-
return CALLBACK_EVENTS;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
66
|
-
* FLUENT API
|
|
67
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
68
|
-
|
|
69
|
-
// ✅ Inherited from BaseComponent
|
|
70
|
-
|
|
71
|
-
label(value: string): this {
|
|
72
|
-
this.state.label = value;
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
icon(value: string): this {
|
|
77
|
-
this.state.icon = value;
|
|
78
|
-
return this;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
variant(value: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'link' | string): this {
|
|
82
|
-
this.state.variant = value;
|
|
83
|
-
return this;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
size(value: 'small' | 'medium' | 'large'): this {
|
|
87
|
-
this.state.size = value;
|
|
88
|
-
return this;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
iconPosition(value: 'left' | 'right'): this {
|
|
92
|
-
this.state.iconPosition = value;
|
|
93
|
-
return this;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
fullWidth(value: boolean): this {
|
|
97
|
-
this.state.fullWidth = value;
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
type(value: 'button' | 'submit' | 'reset'): this {
|
|
102
|
-
this.state.type = value;
|
|
103
|
-
return this;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
107
|
-
* RENDER
|
|
108
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Override visible() to update the actual button element
|
|
112
|
-
*/
|
|
113
|
-
visible(value: boolean): this {
|
|
114
|
-
(this.state as any).visible = value;
|
|
115
|
-
|
|
116
|
-
// Update the button element directly, not the container
|
|
117
|
-
if (this._buttonElement) {
|
|
118
|
-
this._buttonElement.style.display = value ? '' : 'none';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return this;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
render(targetId?: string): this {
|
|
125
|
-
const container = this._setupContainer(targetId);
|
|
126
|
-
const { label, variant, size, disabled, icon, iconPosition, loading, style, class: className } = this.state;
|
|
127
|
-
|
|
128
|
-
const button = document.createElement('button');
|
|
129
|
-
this._buttonElement = button; // ✅ Store reference
|
|
130
|
-
button.className = `jux-button jux-button-${variant} jux-button-${size}`;
|
|
131
|
-
button.id = this._id;
|
|
132
|
-
button.disabled = disabled || loading;
|
|
133
|
-
|
|
134
|
-
if (className) button.className += ` ${className}`;
|
|
135
|
-
if (style) button.setAttribute('style', style);
|
|
136
|
-
|
|
137
|
-
if (icon && iconPosition === 'left') {
|
|
138
|
-
const iconEl = document.createElement('span');
|
|
139
|
-
iconEl.className = 'jux-button-icon';
|
|
140
|
-
iconEl.appendChild(renderIcon(icon));
|
|
141
|
-
button.appendChild(iconEl);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const textEl = document.createElement('span');
|
|
145
|
-
textEl.textContent = loading ? 'Loading...' : label;
|
|
146
|
-
button.appendChild(textEl);
|
|
147
|
-
|
|
148
|
-
if (icon && iconPosition === 'right') {
|
|
149
|
-
const iconEl = document.createElement('span');
|
|
150
|
-
iconEl.className = 'jux-button-icon';
|
|
151
|
-
iconEl.appendChild(renderIcon(icon));
|
|
152
|
-
button.appendChild(iconEl);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
button.addEventListener('click', (e) => {
|
|
156
|
-
if (!disabled && !loading) {
|
|
157
|
-
this._triggerCallback('click', e);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
this._wireStandardEvents(button);
|
|
162
|
-
this._wireAllSyncs();
|
|
163
|
-
|
|
164
|
-
container.appendChild(button);
|
|
165
|
-
|
|
166
|
-
requestAnimationFrame(() => {
|
|
167
|
-
if ((window as any).lucide) {
|
|
168
|
-
(window as any).lucide.createIcons();
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
return this;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export function button(id: string, options?: ButtonOptions): Button {
|
|
177
|
-
return new Button(id, options);
|
|
178
|
-
}
|
package/lib/components/card.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
import { renderIcon } from './icons.js';
|
|
3
|
-
|
|
4
|
-
// Event definitions - Card is display-only, no interactive events
|
|
5
|
-
const TRIGGER_EVENTS = [] as const;
|
|
6
|
-
const CALLBACK_EVENTS = ['click'] as const; // ✅ Can be clicked for navigation/selection
|
|
7
|
-
|
|
8
|
-
export interface CardOptions {
|
|
9
|
-
title?: string;
|
|
10
|
-
content?: string;
|
|
11
|
-
footer?: string;
|
|
12
|
-
variant?: string;
|
|
13
|
-
hoverable?: boolean;
|
|
14
|
-
icon?: string;
|
|
15
|
-
style?: string;
|
|
16
|
-
class?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type CardState = {
|
|
20
|
-
title: string;
|
|
21
|
-
content: string;
|
|
22
|
-
footer: string;
|
|
23
|
-
variant: string;
|
|
24
|
-
hoverable: boolean;
|
|
25
|
-
icon: string;
|
|
26
|
-
style: string;
|
|
27
|
-
class: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export class Card extends BaseComponent<CardState> {
|
|
31
|
-
constructor(id: string, options: CardOptions = {}) {
|
|
32
|
-
super(id, {
|
|
33
|
-
title: options.title ?? '',
|
|
34
|
-
content: options.content ?? '',
|
|
35
|
-
footer: options.footer ?? '',
|
|
36
|
-
variant: options.variant ?? 'default',
|
|
37
|
-
hoverable: options.hoverable ?? false,
|
|
38
|
-
icon: options.icon ?? '',
|
|
39
|
-
style: options.style ?? '',
|
|
40
|
-
class: options.class ?? ''
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
protected getTriggerEvents(): readonly string[] {
|
|
45
|
-
return TRIGGER_EVENTS;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
protected getCallbackEvents(): readonly string[] {
|
|
49
|
-
return CALLBACK_EVENTS;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
53
|
-
* FLUENT API
|
|
54
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
55
|
-
|
|
56
|
-
// ✅ Inherited from BaseComponent
|
|
57
|
-
|
|
58
|
-
title(value: string): this {
|
|
59
|
-
this.state.title = value;
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
content(value: string): this {
|
|
64
|
-
this.state.content = value;
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
footer(value: string): this {
|
|
69
|
-
this.state.footer = value;
|
|
70
|
-
return this;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
icon(value: string): this {
|
|
74
|
-
this.state.icon = value;
|
|
75
|
-
return this;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
79
|
-
* RENDER
|
|
80
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
81
|
-
|
|
82
|
-
render(targetId?: string): this {
|
|
83
|
-
const container = this._setupContainer(targetId);
|
|
84
|
-
|
|
85
|
-
const { title, content, footer, variant, hoverable, icon, style, class: className } = this.state;
|
|
86
|
-
|
|
87
|
-
const card = document.createElement('div');
|
|
88
|
-
card.className = `jux-card jux-card-${variant}`;
|
|
89
|
-
card.id = this._id;
|
|
90
|
-
if (hoverable) card.classList.add('jux-card-hoverable');
|
|
91
|
-
if (className) card.className += ` ${className}`;
|
|
92
|
-
if (style) card.setAttribute('style', style);
|
|
93
|
-
|
|
94
|
-
if (title || icon) {
|
|
95
|
-
const header = document.createElement('div');
|
|
96
|
-
header.className = 'jux-card-header';
|
|
97
|
-
|
|
98
|
-
if (icon) {
|
|
99
|
-
const iconEl = document.createElement('span');
|
|
100
|
-
iconEl.className = 'jux-card-icon';
|
|
101
|
-
iconEl.appendChild(renderIcon(icon));
|
|
102
|
-
header.appendChild(iconEl);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (title) {
|
|
106
|
-
const titleEl = document.createElement('span');
|
|
107
|
-
titleEl.className = 'jux-card-title';
|
|
108
|
-
titleEl.textContent = title;
|
|
109
|
-
header.appendChild(titleEl);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
card.appendChild(header);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const body = document.createElement('div');
|
|
116
|
-
body.className = 'jux-card-body';
|
|
117
|
-
body.innerHTML = content;
|
|
118
|
-
card.appendChild(body);
|
|
119
|
-
|
|
120
|
-
if (footer) {
|
|
121
|
-
const footerEl = document.createElement('div');
|
|
122
|
-
footerEl.className = 'jux-card-footer';
|
|
123
|
-
footerEl.innerHTML = footer;
|
|
124
|
-
card.appendChild(footerEl);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
this._wireStandardEvents(card);
|
|
128
|
-
|
|
129
|
-
// Wire sync bindings
|
|
130
|
-
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
131
|
-
if (property === 'title') {
|
|
132
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
133
|
-
|
|
134
|
-
stateObj.subscribe((val: any) => {
|
|
135
|
-
const transformed = transform(val);
|
|
136
|
-
const header = card.querySelector('.jux-card-header');
|
|
137
|
-
if (header) {
|
|
138
|
-
header.textContent = transformed;
|
|
139
|
-
}
|
|
140
|
-
this.state.title = transformed;
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
else if (property === 'content') {
|
|
144
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
145
|
-
|
|
146
|
-
stateObj.subscribe((val: any) => {
|
|
147
|
-
const transformed = transform(val);
|
|
148
|
-
body.innerHTML = transformed;
|
|
149
|
-
this.state.content = transformed;
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
else if (property === 'footer') {
|
|
153
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
154
|
-
|
|
155
|
-
stateObj.subscribe((val: any) => {
|
|
156
|
-
const transformed = transform(val);
|
|
157
|
-
const footerEl = card.querySelector('.jux-card-footer');
|
|
158
|
-
if (footerEl) {
|
|
159
|
-
footerEl.innerHTML = transformed;
|
|
160
|
-
}
|
|
161
|
-
this.state.footer = transformed;
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
container.appendChild(card);
|
|
167
|
-
return this;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function card(id: string, options: CardOptions = {}): Card {
|
|
172
|
-
return new Card(id, options);
|
|
173
|
-
}
|
package/lib/components/chart.ts
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
import { Chart, ChartConfiguration, ChartType, ChartOptions, ChartData } from 'chart.js/auto';
|
|
3
|
-
|
|
4
|
-
// filepath: /Users/timkerr/newprojects2025/compile-sqljs/packages/jux/lib/components/chart.ts
|
|
5
|
-
|
|
6
|
-
export interface ChartState {
|
|
7
|
-
type: ChartType;
|
|
8
|
-
data: ChartData;
|
|
9
|
-
options: ChartOptions;
|
|
10
|
-
style?: string;
|
|
11
|
-
class?: string;
|
|
12
|
-
visible?: boolean;
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
loading?: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Chart component using Chart.js
|
|
19
|
-
* Provides fluent API for creating and configuring charts
|
|
20
|
-
*/
|
|
21
|
-
export class ChartComponent extends BaseComponent<ChartState> {
|
|
22
|
-
private static readonly TRIGGER_EVENTS: readonly string[] = [];
|
|
23
|
-
private static readonly CALLBACK_EVENTS: readonly string[] = ['render', 'update', 'destroy'];
|
|
24
|
-
private chartInstance: Chart | null = null;
|
|
25
|
-
|
|
26
|
-
constructor(id: string, type: ChartType = 'bar', options?: Partial<ChartState>) {
|
|
27
|
-
super(id, {
|
|
28
|
-
type,
|
|
29
|
-
data: { datasets: [] },
|
|
30
|
-
options: {},
|
|
31
|
-
...options
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected getTriggerEvents(): readonly string[] {
|
|
36
|
-
return ChartComponent.TRIGGER_EVENTS;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
protected getCallbackEvents(): readonly string[] {
|
|
40
|
-
return ChartComponent.CALLBACK_EVENTS;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
44
|
-
* CHART TYPE
|
|
45
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
46
|
-
|
|
47
|
-
type(value: ChartType): this {
|
|
48
|
-
this.state.type = value;
|
|
49
|
-
if (this.chartInstance) {
|
|
50
|
-
// Destroy and recreate chart with new type
|
|
51
|
-
const canvas = this.chartInstance.canvas;
|
|
52
|
-
this.chartInstance.destroy();
|
|
53
|
-
const config: ChartConfiguration = {
|
|
54
|
-
type: this.state.type,
|
|
55
|
-
data: this.state.data,
|
|
56
|
-
options: this.state.options
|
|
57
|
-
};
|
|
58
|
-
this.chartInstance = new Chart(canvas, config);
|
|
59
|
-
}
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
64
|
-
* DATA CONFIGURATION
|
|
65
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
66
|
-
|
|
67
|
-
data(value: ChartData): this {
|
|
68
|
-
this.state.data = value;
|
|
69
|
-
if (this.chartInstance) {
|
|
70
|
-
this.chartInstance.data = value;
|
|
71
|
-
this.chartInstance.update();
|
|
72
|
-
}
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
labels(value: string[]): this {
|
|
77
|
-
this.state.data.labels = value;
|
|
78
|
-
if (this.chartInstance) {
|
|
79
|
-
this.chartInstance.data.labels = value;
|
|
80
|
-
this.chartInstance.update();
|
|
81
|
-
}
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
datasets(value: any[]): this {
|
|
86
|
-
this.state.data.datasets = value;
|
|
87
|
-
if (this.chartInstance) {
|
|
88
|
-
this.chartInstance.data.datasets = value;
|
|
89
|
-
this.chartInstance.update();
|
|
90
|
-
}
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
addDataset(dataset: any): this {
|
|
95
|
-
this.state.data.datasets.push(dataset);
|
|
96
|
-
if (this.chartInstance) {
|
|
97
|
-
this.chartInstance.data.datasets.push(dataset);
|
|
98
|
-
this.chartInstance.update();
|
|
99
|
-
}
|
|
100
|
-
return this;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
104
|
-
* OPTIONS CONFIGURATION
|
|
105
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
106
|
-
|
|
107
|
-
options(value: ChartOptions): this {
|
|
108
|
-
this.state.options = { ...this.state.options, ...value };
|
|
109
|
-
if (this.chartInstance) {
|
|
110
|
-
this.chartInstance.options = this.state.options;
|
|
111
|
-
this.chartInstance.update();
|
|
112
|
-
}
|
|
113
|
-
return this;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
responsive(value: boolean = true): this {
|
|
117
|
-
return this.options({ responsive: value });
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
maintainAspectRatio(value: boolean = true): this {
|
|
121
|
-
return this.options({ maintainAspectRatio: value });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
title(text: string, display: boolean = true): this {
|
|
125
|
-
return this.options({
|
|
126
|
-
plugins: {
|
|
127
|
-
...this.state.options.plugins,
|
|
128
|
-
title: { display, text }
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
legend(display: boolean = true, position: 'top' | 'bottom' | 'left' | 'right' = 'top'): this {
|
|
134
|
-
return this.options({
|
|
135
|
-
plugins: {
|
|
136
|
-
...this.state.options.plugins,
|
|
137
|
-
legend: { display, position }
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
tooltip(enabled: boolean = true): this {
|
|
143
|
-
return this.options({
|
|
144
|
-
plugins: {
|
|
145
|
-
...this.state.options.plugins,
|
|
146
|
-
tooltip: { enabled }
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
152
|
-
* CHART OPERATIONS
|
|
153
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
154
|
-
|
|
155
|
-
update(mode?: 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'default'): this {
|
|
156
|
-
if (this.chartInstance) {
|
|
157
|
-
this.chartInstance.update(mode);
|
|
158
|
-
this._triggerCallback('update', this.chartInstance);
|
|
159
|
-
}
|
|
160
|
-
return this;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
reset(): this {
|
|
164
|
-
if (this.chartInstance) {
|
|
165
|
-
this.chartInstance.reset();
|
|
166
|
-
}
|
|
167
|
-
return this;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
destroy(): this {
|
|
171
|
-
if (this.chartInstance) {
|
|
172
|
-
this.chartInstance.destroy();
|
|
173
|
-
this.chartInstance = null;
|
|
174
|
-
this._triggerCallback('destroy');
|
|
175
|
-
}
|
|
176
|
-
return this;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
getChart(): Chart | null {
|
|
180
|
-
return this.chartInstance;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
184
|
-
* RENDER
|
|
185
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
186
|
-
|
|
187
|
-
render(targetId?: string): this {
|
|
188
|
-
const container = this._setupContainer(targetId);
|
|
189
|
-
|
|
190
|
-
// Destroy existing chart
|
|
191
|
-
if (this.chartInstance) {
|
|
192
|
-
this.chartInstance.destroy();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Clear container and create canvas
|
|
196
|
-
container.innerHTML = '';
|
|
197
|
-
const canvas = document.createElement('canvas');
|
|
198
|
-
canvas.id = `${this._id}-canvas`;
|
|
199
|
-
|
|
200
|
-
// Apply styles and classes
|
|
201
|
-
if (this.state.style) container.setAttribute('style', this.state.style);
|
|
202
|
-
if (this.state.class) container.className = this.state.class;
|
|
203
|
-
if (this.state.visible === false) container.style.display = 'none';
|
|
204
|
-
|
|
205
|
-
container.appendChild(canvas);
|
|
206
|
-
|
|
207
|
-
// Create Chart.js instance
|
|
208
|
-
const config: ChartConfiguration = {
|
|
209
|
-
type: this.state.type,
|
|
210
|
-
data: this.state.data,
|
|
211
|
-
options: this.state.options
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
this.chartInstance = new Chart(canvas, config);
|
|
215
|
-
|
|
216
|
-
// Wire events and syncs
|
|
217
|
-
this._wireStandardEvents(container);
|
|
218
|
-
this._wireAllSyncs();
|
|
219
|
-
|
|
220
|
-
this._triggerCallback('render', this.chartInstance);
|
|
221
|
-
|
|
222
|
-
return this;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Factory function for creating chart components
|
|
228
|
-
*/
|
|
229
|
-
export function chart(id: string, type: ChartType = 'bar', options?: Partial<ChartState>): ChartComponent {
|
|
230
|
-
return new ChartComponent(id, type, options);
|
|
231
|
-
}
|