@gravionlabs/helix-ui 22.2.6 → 22.2.7
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/README.md +18 -1
- package/chart/package.json +4 -0
- package/core.css +4082 -0
- package/fesm2022/gravionlabs-helix-ui-chart.mjs +446 -0
- package/fesm2022/gravionlabs-helix-ui-chart.mjs.map +1 -0
- package/fesm2022/gravionlabs-helix-ui.mjs +369 -465
- package/fesm2022/gravionlabs-helix-ui.mjs.map +1 -1
- package/package.json +6 -1
- package/styles.css +34 -0
- package/types/gravionlabs-helix-ui-chart.d.ts +134 -0
- package/types/gravionlabs-helix-ui.d.ts +136 -139
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { isPlatformBrowser } from "@angular/common";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, InjectionToken, NgZone, PLATFORM_ID, afterNextRender, effect, inject, input, numberAttribute, output, untracked, viewChild } from "@angular/core";
|
|
4
|
+
const HX_CHART_LOADER = new InjectionToken("HX_CHART_LOADER", {
|
|
5
|
+
providedIn: "root",
|
|
6
|
+
factory: () => () => import("chart.js/auto")
|
|
7
|
+
});
|
|
8
|
+
const PALETTE = [
|
|
9
|
+
"--h-primary-color",
|
|
10
|
+
"--h-orange-500",
|
|
11
|
+
"--h-green-500",
|
|
12
|
+
"--h-purple-500",
|
|
13
|
+
"--h-sky-500",
|
|
14
|
+
"--h-red-500",
|
|
15
|
+
"--h-yellow-500",
|
|
16
|
+
"--h-teal-500"
|
|
17
|
+
];
|
|
18
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
function merge(defaults, overrides) {
|
|
20
|
+
const out = { ...defaults };
|
|
21
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
22
|
+
const base = out[key];
|
|
23
|
+
out[key] = isObject(base) && isObject(value) ? merge(base, value) : value;
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
var HxChart = class HxChart {
|
|
28
|
+
#host = inject(ElementRef).nativeElement;
|
|
29
|
+
#zone = inject(NgZone);
|
|
30
|
+
#loader = inject(HX_CHART_LOADER);
|
|
31
|
+
#platform = inject(PLATFORM_ID);
|
|
32
|
+
canvas = viewChild.required("canvas", ...ngDevMode ? [{ debugName: "canvas" }] : /* istanbul ignore next */ []);
|
|
33
|
+
type = input("bar", ...ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []);
|
|
34
|
+
data = input({}, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
|
|
35
|
+
options = input({}, ...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
|
|
36
|
+
plugins = input([], ...ngDevMode ? [{ debugName: "plugins" }] : /* istanbul ignore next */ []);
|
|
37
|
+
width = input(...ngDevMode ? [void 0, { debugName: "width" }] : /* istanbul ignore next */ []);
|
|
38
|
+
height = input(...ngDevMode ? [void 0, { debugName: "height" }] : /* istanbul ignore next */ []);
|
|
39
|
+
responsive = input(true, {
|
|
40
|
+
...ngDevMode ? { debugName: "responsive" } : /* istanbul ignore next */ {},
|
|
41
|
+
transform: (v) => v !== false && v !== "false"
|
|
42
|
+
});
|
|
43
|
+
ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
44
|
+
ariaLabelledBy = input(...ngDevMode ? [void 0, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []);
|
|
45
|
+
themeDelay = input(50, {
|
|
46
|
+
...ngDevMode ? { debugName: "themeDelay" } : /* istanbul ignore next */ {},
|
|
47
|
+
transform: numberAttribute
|
|
48
|
+
});
|
|
49
|
+
dataSelect = output();
|
|
50
|
+
#chart;
|
|
51
|
+
#chartType;
|
|
52
|
+
#ready = false;
|
|
53
|
+
#loading = false;
|
|
54
|
+
#observer;
|
|
55
|
+
#timer;
|
|
56
|
+
constructor() {
|
|
57
|
+
afterNextRender(() => {
|
|
58
|
+
this.#ready = true;
|
|
59
|
+
this.#render();
|
|
60
|
+
this.#watchTheme();
|
|
61
|
+
});
|
|
62
|
+
effect(() => {
|
|
63
|
+
this.type();
|
|
64
|
+
this.data();
|
|
65
|
+
this.options();
|
|
66
|
+
this.plugins();
|
|
67
|
+
this.responsive();
|
|
68
|
+
this.width();
|
|
69
|
+
this.height();
|
|
70
|
+
untracked(() => {
|
|
71
|
+
if (this.#ready) this.#render();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
inject(DestroyRef).onDestroy(() => {
|
|
75
|
+
clearTimeout(this.#timer);
|
|
76
|
+
this.#observer?.disconnect();
|
|
77
|
+
this.#chart?.destroy();
|
|
78
|
+
this.#chart = void 0;
|
|
79
|
+
this.#ready = false;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
get chart() {
|
|
83
|
+
return this.#chart;
|
|
84
|
+
}
|
|
85
|
+
refresh() {
|
|
86
|
+
if (this.#chart) {
|
|
87
|
+
this.#apply(this.#chart);
|
|
88
|
+
this.#chart.update();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
onClick(event) {
|
|
92
|
+
const chart = this.#chart;
|
|
93
|
+
if (!chart) return;
|
|
94
|
+
const element = chart.getElementsAtEventForMode(event, "nearest", { intersect: true }, false);
|
|
95
|
+
const dataset = chart.getElementsAtEventForMode(event, "dataset", { intersect: true }, false);
|
|
96
|
+
if (element?.[0] && dataset) this.dataSelect.emit({
|
|
97
|
+
originalEvent: event,
|
|
98
|
+
element: element[0],
|
|
99
|
+
dataset
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async #render() {
|
|
103
|
+
if (!isPlatformBrowser(this.#platform)) return;
|
|
104
|
+
const type = this.type();
|
|
105
|
+
if (this.#chart && this.#chartType === type) {
|
|
106
|
+
this.#apply(this.#chart);
|
|
107
|
+
this.#chart.update();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (this.#loading) return;
|
|
111
|
+
this.#loading = true;
|
|
112
|
+
try {
|
|
113
|
+
const module = await this.#loader();
|
|
114
|
+
if (!this.#ready) return;
|
|
115
|
+
this.#chart?.destroy();
|
|
116
|
+
const Chart = module.default;
|
|
117
|
+
this.#zone.runOutsideAngular(() => {
|
|
118
|
+
this.#chart = new Chart(this.canvas().nativeElement, {
|
|
119
|
+
type: this.type(),
|
|
120
|
+
data: this.#themedData(),
|
|
121
|
+
options: this.#themedOptions(),
|
|
122
|
+
plugins: [...this.plugins()]
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
this.#chartType = this.type();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("hx-chart: chart.js could not be loaded. Is the peer dependency \"chart.js\" installed?", error);
|
|
128
|
+
return;
|
|
129
|
+
} finally {
|
|
130
|
+
this.#loading = false;
|
|
131
|
+
}
|
|
132
|
+
if (this.#chart && this.#chartType !== this.type()) await this.#render();
|
|
133
|
+
}
|
|
134
|
+
#apply(chart) {
|
|
135
|
+
chart.data = this.#themedData();
|
|
136
|
+
chart.options = this.#themedOptions();
|
|
137
|
+
}
|
|
138
|
+
#token(name) {
|
|
139
|
+
return getComputedStyle(this.#host).getPropertyValue(name).trim();
|
|
140
|
+
}
|
|
141
|
+
#themedData() {
|
|
142
|
+
const data = this.data();
|
|
143
|
+
const datasets = data.datasets;
|
|
144
|
+
if (!Array.isArray(datasets)) return data;
|
|
145
|
+
const palette = PALETTE.map((name) => this.#token(name)).filter(Boolean);
|
|
146
|
+
if (palette.length === 0) return data;
|
|
147
|
+
const perPoint = [
|
|
148
|
+
"pie",
|
|
149
|
+
"doughnut",
|
|
150
|
+
"polarArea"
|
|
151
|
+
].includes(this.type());
|
|
152
|
+
return {
|
|
153
|
+
...data,
|
|
154
|
+
datasets: datasets.map((dataset, i) => {
|
|
155
|
+
if (!isObject(dataset)) return dataset;
|
|
156
|
+
const color = palette[i % palette.length];
|
|
157
|
+
const count = Array.isArray(dataset.data) ? dataset.data.length : 0;
|
|
158
|
+
const points = Array.from({ length: count }, (_, n) => palette[n % palette.length]);
|
|
159
|
+
const filled = this.type() === "line" || this.type() === "radar";
|
|
160
|
+
return {
|
|
161
|
+
...dataset,
|
|
162
|
+
backgroundColor: dataset.backgroundColor ?? (perPoint ? points : filled ? `color-mix(in srgb, ${color}, transparent 80%)` : color),
|
|
163
|
+
borderColor: dataset.borderColor ?? (perPoint ? this.#token("--h-content-background") : color)
|
|
164
|
+
};
|
|
165
|
+
})
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
#themedOptions() {
|
|
169
|
+
const text = this.#token("--h-text-color");
|
|
170
|
+
const muted = this.#token("--h-text-muted-color");
|
|
171
|
+
const grid = this.#token("--h-content-border-color");
|
|
172
|
+
const axis = {
|
|
173
|
+
ticks: { color: muted },
|
|
174
|
+
grid: { color: grid },
|
|
175
|
+
border: { color: grid }
|
|
176
|
+
};
|
|
177
|
+
const radial = {
|
|
178
|
+
ticks: {
|
|
179
|
+
color: muted,
|
|
180
|
+
backdropColor: "transparent"
|
|
181
|
+
},
|
|
182
|
+
grid: { color: grid },
|
|
183
|
+
angleLines: { color: grid },
|
|
184
|
+
pointLabels: { color: text }
|
|
185
|
+
};
|
|
186
|
+
const type = this.type();
|
|
187
|
+
const scales = type === "radar" || type === "polarArea" ? { r: radial } : type === "pie" || type === "doughnut" ? {} : {
|
|
188
|
+
x: axis,
|
|
189
|
+
y: axis
|
|
190
|
+
};
|
|
191
|
+
return merge({
|
|
192
|
+
responsive: this.responsive(),
|
|
193
|
+
maintainAspectRatio: !(this.height() || this.width()),
|
|
194
|
+
color: muted,
|
|
195
|
+
borderColor: grid,
|
|
196
|
+
plugins: { legend: { labels: { color: text } } },
|
|
197
|
+
scales
|
|
198
|
+
}, this.options());
|
|
199
|
+
}
|
|
200
|
+
#watchTheme() {
|
|
201
|
+
if (typeof MutationObserver === "undefined") return;
|
|
202
|
+
this.#observer = new MutationObserver(() => {
|
|
203
|
+
clearTimeout(this.#timer);
|
|
204
|
+
this.#timer = setTimeout(() => this.refresh(), this.themeDelay());
|
|
205
|
+
});
|
|
206
|
+
this.#observer.observe(document.documentElement, {
|
|
207
|
+
attributes: true,
|
|
208
|
+
attributeFilter: [
|
|
209
|
+
"class",
|
|
210
|
+
"style",
|
|
211
|
+
"data-theme"
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
216
|
+
minVersion: "12.0.0",
|
|
217
|
+
version: "22.2.1",
|
|
218
|
+
ngImport: i0,
|
|
219
|
+
type: HxChart,
|
|
220
|
+
deps: [],
|
|
221
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
222
|
+
});
|
|
223
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
224
|
+
minVersion: "17.2.0",
|
|
225
|
+
version: "22.2.1",
|
|
226
|
+
type: HxChart,
|
|
227
|
+
isStandalone: true,
|
|
228
|
+
selector: "hx-chart",
|
|
229
|
+
inputs: {
|
|
230
|
+
type: {
|
|
231
|
+
classPropertyName: "type",
|
|
232
|
+
publicName: "type",
|
|
233
|
+
isSignal: true,
|
|
234
|
+
isRequired: false,
|
|
235
|
+
transformFunction: null
|
|
236
|
+
},
|
|
237
|
+
data: {
|
|
238
|
+
classPropertyName: "data",
|
|
239
|
+
publicName: "data",
|
|
240
|
+
isSignal: true,
|
|
241
|
+
isRequired: false,
|
|
242
|
+
transformFunction: null
|
|
243
|
+
},
|
|
244
|
+
options: {
|
|
245
|
+
classPropertyName: "options",
|
|
246
|
+
publicName: "options",
|
|
247
|
+
isSignal: true,
|
|
248
|
+
isRequired: false,
|
|
249
|
+
transformFunction: null
|
|
250
|
+
},
|
|
251
|
+
plugins: {
|
|
252
|
+
classPropertyName: "plugins",
|
|
253
|
+
publicName: "plugins",
|
|
254
|
+
isSignal: true,
|
|
255
|
+
isRequired: false,
|
|
256
|
+
transformFunction: null
|
|
257
|
+
},
|
|
258
|
+
width: {
|
|
259
|
+
classPropertyName: "width",
|
|
260
|
+
publicName: "width",
|
|
261
|
+
isSignal: true,
|
|
262
|
+
isRequired: false,
|
|
263
|
+
transformFunction: null
|
|
264
|
+
},
|
|
265
|
+
height: {
|
|
266
|
+
classPropertyName: "height",
|
|
267
|
+
publicName: "height",
|
|
268
|
+
isSignal: true,
|
|
269
|
+
isRequired: false,
|
|
270
|
+
transformFunction: null
|
|
271
|
+
},
|
|
272
|
+
responsive: {
|
|
273
|
+
classPropertyName: "responsive",
|
|
274
|
+
publicName: "responsive",
|
|
275
|
+
isSignal: true,
|
|
276
|
+
isRequired: false,
|
|
277
|
+
transformFunction: null
|
|
278
|
+
},
|
|
279
|
+
ariaLabel: {
|
|
280
|
+
classPropertyName: "ariaLabel",
|
|
281
|
+
publicName: "ariaLabel",
|
|
282
|
+
isSignal: true,
|
|
283
|
+
isRequired: false,
|
|
284
|
+
transformFunction: null
|
|
285
|
+
},
|
|
286
|
+
ariaLabelledBy: {
|
|
287
|
+
classPropertyName: "ariaLabelledBy",
|
|
288
|
+
publicName: "ariaLabelledBy",
|
|
289
|
+
isSignal: true,
|
|
290
|
+
isRequired: false,
|
|
291
|
+
transformFunction: null
|
|
292
|
+
},
|
|
293
|
+
themeDelay: {
|
|
294
|
+
classPropertyName: "themeDelay",
|
|
295
|
+
publicName: "themeDelay",
|
|
296
|
+
isSignal: true,
|
|
297
|
+
isRequired: false,
|
|
298
|
+
transformFunction: null
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
outputs: { dataSelect: "dataSelect" },
|
|
302
|
+
host: { classAttribute: "hx-chart" },
|
|
303
|
+
viewQueries: [{
|
|
304
|
+
propertyName: "canvas",
|
|
305
|
+
first: true,
|
|
306
|
+
predicate: ["canvas"],
|
|
307
|
+
descendants: true,
|
|
308
|
+
isSignal: true
|
|
309
|
+
}],
|
|
310
|
+
ngImport: i0,
|
|
311
|
+
template: `
|
|
312
|
+
<div class="hx-chart-frame" [style.width]="width() ?? null" [style.height]="height() ?? null">
|
|
313
|
+
<canvas
|
|
314
|
+
#canvas
|
|
315
|
+
class="hx-chart-canvas"
|
|
316
|
+
role="img"
|
|
317
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
318
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
319
|
+
(click)="onClick($event)"
|
|
320
|
+
><ng-content select="[hxChartFallback]" /></canvas>
|
|
321
|
+
</div>
|
|
322
|
+
`,
|
|
323
|
+
isInline: true,
|
|
324
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
328
|
+
minVersion: "12.0.0",
|
|
329
|
+
version: "22.2.1",
|
|
330
|
+
ngImport: i0,
|
|
331
|
+
type: HxChart,
|
|
332
|
+
decorators: [{
|
|
333
|
+
type: Component,
|
|
334
|
+
args: [{
|
|
335
|
+
selector: "hx-chart",
|
|
336
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
337
|
+
host: { class: "hx-chart" },
|
|
338
|
+
template: `
|
|
339
|
+
<div class="hx-chart-frame" [style.width]="width() ?? null" [style.height]="height() ?? null">
|
|
340
|
+
<canvas
|
|
341
|
+
#canvas
|
|
342
|
+
class="hx-chart-canvas"
|
|
343
|
+
role="img"
|
|
344
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
345
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
346
|
+
(click)="onClick($event)"
|
|
347
|
+
><ng-content select="[hxChartFallback]" /></canvas>
|
|
348
|
+
</div>
|
|
349
|
+
`
|
|
350
|
+
}]
|
|
351
|
+
}],
|
|
352
|
+
ctorParameters: () => [],
|
|
353
|
+
propDecorators: {
|
|
354
|
+
canvas: [{
|
|
355
|
+
type: i0.ViewChild,
|
|
356
|
+
args: ["canvas", { isSignal: true }]
|
|
357
|
+
}],
|
|
358
|
+
type: [{
|
|
359
|
+
type: i0.Input,
|
|
360
|
+
args: [{
|
|
361
|
+
isSignal: true,
|
|
362
|
+
alias: "type",
|
|
363
|
+
required: false
|
|
364
|
+
}]
|
|
365
|
+
}],
|
|
366
|
+
data: [{
|
|
367
|
+
type: i0.Input,
|
|
368
|
+
args: [{
|
|
369
|
+
isSignal: true,
|
|
370
|
+
alias: "data",
|
|
371
|
+
required: false
|
|
372
|
+
}]
|
|
373
|
+
}],
|
|
374
|
+
options: [{
|
|
375
|
+
type: i0.Input,
|
|
376
|
+
args: [{
|
|
377
|
+
isSignal: true,
|
|
378
|
+
alias: "options",
|
|
379
|
+
required: false
|
|
380
|
+
}]
|
|
381
|
+
}],
|
|
382
|
+
plugins: [{
|
|
383
|
+
type: i0.Input,
|
|
384
|
+
args: [{
|
|
385
|
+
isSignal: true,
|
|
386
|
+
alias: "plugins",
|
|
387
|
+
required: false
|
|
388
|
+
}]
|
|
389
|
+
}],
|
|
390
|
+
width: [{
|
|
391
|
+
type: i0.Input,
|
|
392
|
+
args: [{
|
|
393
|
+
isSignal: true,
|
|
394
|
+
alias: "width",
|
|
395
|
+
required: false
|
|
396
|
+
}]
|
|
397
|
+
}],
|
|
398
|
+
height: [{
|
|
399
|
+
type: i0.Input,
|
|
400
|
+
args: [{
|
|
401
|
+
isSignal: true,
|
|
402
|
+
alias: "height",
|
|
403
|
+
required: false
|
|
404
|
+
}]
|
|
405
|
+
}],
|
|
406
|
+
responsive: [{
|
|
407
|
+
type: i0.Input,
|
|
408
|
+
args: [{
|
|
409
|
+
isSignal: true,
|
|
410
|
+
alias: "responsive",
|
|
411
|
+
required: false
|
|
412
|
+
}]
|
|
413
|
+
}],
|
|
414
|
+
ariaLabel: [{
|
|
415
|
+
type: i0.Input,
|
|
416
|
+
args: [{
|
|
417
|
+
isSignal: true,
|
|
418
|
+
alias: "ariaLabel",
|
|
419
|
+
required: false
|
|
420
|
+
}]
|
|
421
|
+
}],
|
|
422
|
+
ariaLabelledBy: [{
|
|
423
|
+
type: i0.Input,
|
|
424
|
+
args: [{
|
|
425
|
+
isSignal: true,
|
|
426
|
+
alias: "ariaLabelledBy",
|
|
427
|
+
required: false
|
|
428
|
+
}]
|
|
429
|
+
}],
|
|
430
|
+
themeDelay: [{
|
|
431
|
+
type: i0.Input,
|
|
432
|
+
args: [{
|
|
433
|
+
isSignal: true,
|
|
434
|
+
alias: "themeDelay",
|
|
435
|
+
required: false
|
|
436
|
+
}]
|
|
437
|
+
}],
|
|
438
|
+
dataSelect: [{
|
|
439
|
+
type: i0.Output,
|
|
440
|
+
args: ["dataSelect"]
|
|
441
|
+
}]
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
export { HX_CHART_LOADER, HxChart };
|
|
445
|
+
|
|
446
|
+
//# sourceMappingURL=gravionlabs-helix-ui-chart.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gravionlabs-helix-ui-chart.mjs","names":[],"sources":["../../../projects/ui/chart/chart.ts"],"sourcesContent":["import { isPlatformBrowser } from '@angular/common';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n effect,\n InjectionToken,\n inject,\n input,\n NgZone,\n numberAttribute,\n output,\n PLATFORM_ID,\n untracked,\n viewChild,\n} from '@angular/core';\n\nexport type HxChartType =\n | 'bar'\n | 'line'\n | 'scatter'\n | 'bubble'\n | 'pie'\n | 'doughnut'\n | 'polarArea'\n | 'radar';\n\n/** What `(dataSelect)` carries: the click and what chart.js found under it. */\nexport interface HxChartSelectEvent {\n originalEvent: Event;\n /** The nearest element under the pointer (chart.js `{ datasetIndex, index, element }`). */\n element: unknown;\n /** The elements of that dataset. */\n dataset: unknown[];\n}\n\n/** The part of chart.js this component uses; the real module is `chart.js/auto`. */\nexport interface HxChartModule {\n default: new (canvas: HTMLCanvasElement, config: unknown) => HxChartInstance;\n}\n\nexport interface HxChartInstance {\n data: unknown;\n options: unknown;\n update(mode?: string): void;\n destroy(): void;\n getElementsAtEventForMode(\n event: Event,\n mode: string,\n options: object,\n useFinalPosition: boolean,\n ): unknown[];\n}\n\n/**\n * Loads chart.js. The default is a dynamic `import('chart.js/auto')`, so chart.js is only fetched by apps that show\n * a chart; provide another function to register a smaller set of chart.js parts or to replace it in tests.\n */\nexport const HX_CHART_LOADER = new InjectionToken<() => Promise<HxChartModule>>('HX_CHART_LOADER', {\n providedIn: 'root',\n factory: () => () => import('chart.js/auto') as unknown as Promise<HxChartModule>,\n});\n\n/** Colours of the datasets that do not set their own, as tokens in the order they are used. */\nconst PALETTE = [\n '--h-primary-color',\n '--h-orange-500',\n '--h-green-500',\n '--h-purple-500',\n '--h-sky-500',\n '--h-red-500',\n '--h-yellow-500',\n '--h-teal-500',\n];\n\ntype Json = Record<string, unknown>;\n\n/** The parts of chart.js data and datasets that are read here; everything else is passed on untouched. */\ninterface ChartDataLike extends Json {\n datasets?: unknown;\n}\ninterface DatasetLike extends Json {\n data?: unknown;\n backgroundColor?: unknown;\n borderColor?: unknown;\n}\n\nconst isObject = (value: unknown): value is Json =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** `defaults` underneath, `overrides` on top; objects merge, everything else is replaced. */\nfunction merge(defaults: Json, overrides: Json): Json {\n const out: Json = { ...defaults };\n for (const [key, value] of Object.entries(overrides)) {\n const base = out[key];\n out[key] = isObject(base) && isObject(value) ? merge(base, value) : value;\n }\n return out;\n}\n\n/**\n * A chart.js chart whose colours, grid and font come from the Helix tokens.\n *\n * ```html\n * <hx-chart type=\"bar\" [data]=\"data\" [options]=\"options\" height=\"20rem\" ariaLabel=\"Sales per month\">\n * <table hxChartFallback>…the same numbers as text…</table>\n * </hx-chart>\n * ```\n *\n * chart.js is an optional peer dependency, loaded with a dynamic import (see `HX_CHART_LOADER`) the first time a\n * chart is shown. Datasets without colours get the Helix palette; text, grid and legend colours come from\n * `--h-text-muted-color` and `--h-content-border-color` of the element. Your `options` win over these defaults.\n * The chart is redrawn when `class` or `style` of `<html>` change (dark mode, the primary colour).\n *\n * The canvas is an `img` named by `ariaLabel` / `ariaLabelledBy`; content marked `hxChartFallback` becomes the\n * canvas fallback content, which assistive technology reads: put the numbers there as text or as a table.\n */\n@Component({\n selector: 'hx-chart',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'hx-chart' },\n template: `\n <div class=\"hx-chart-frame\" [style.width]=\"width() ?? null\" [style.height]=\"height() ?? null\">\n <canvas\n #canvas\n class=\"hx-chart-canvas\"\n role=\"img\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n (click)=\"onClick($event)\"\n ><ng-content select=\"[hxChartFallback]\" /></canvas>\n </div>\n `,\n})\nexport class HxChart {\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n readonly #zone = inject(NgZone);\n readonly #loader = inject(HX_CHART_LOADER);\n readonly #platform = inject(PLATFORM_ID);\n private readonly canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n readonly type = input<HxChartType>('bar');\n /** chart.js data: `{ labels, datasets }`. Pass a new object to update the chart. */\n readonly data = input<ChartDataLike>({});\n /** chart.js options, on top of the token defaults. Pass a new object to update the chart. */\n readonly options = input<Json>({});\n /** Extra chart.js plugins for this chart. */\n readonly plugins = input<readonly unknown[]>([]);\n /** CSS width of the frame, e.g. `30rem`; the chart fills its container by default. */\n readonly width = input<string>();\n /** CSS height of the frame; without it chart.js keeps its aspect ratio. */\n readonly height = input<string>();\n /** Resize with the container. */\n readonly responsive = input(true, { transform: (v: unknown) => v !== false && v !== 'false' });\n readonly ariaLabel = input<string>();\n readonly ariaLabelledBy = input<string>();\n /** Delay of a redraw after the theme changed, in ms; the style change is usually followed by more. */\n readonly themeDelay = input(50, { transform: numberAttribute });\n\n /** A data point or dataset was clicked. */\n readonly dataSelect = output<HxChartSelectEvent>();\n\n #chart: HxChartInstance | undefined;\n #chartType: HxChartType | undefined;\n #ready = false;\n #loading = false;\n #observer: MutationObserver | undefined;\n #timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n afterNextRender(() => {\n this.#ready = true;\n void this.#render();\n this.#watchTheme();\n });\n effect(() => {\n this.type();\n this.data();\n this.options();\n this.plugins();\n this.responsive();\n this.width();\n this.height();\n untracked(() => {\n if (this.#ready) void this.#render();\n });\n });\n inject(DestroyRef).onDestroy(() => {\n clearTimeout(this.#timer);\n this.#observer?.disconnect();\n this.#chart?.destroy();\n this.#chart = undefined;\n this.#ready = false;\n });\n }\n\n /** The chart.js instance, once it exists; `undefined` before chart.js has loaded. */\n get chart(): HxChartInstance | undefined {\n return this.#chart;\n }\n\n /** Redraws the chart, e.g. after the theme changed in a way the component cannot see. */\n refresh(): void {\n if (this.#chart) {\n this.#apply(this.#chart);\n this.#chart.update();\n }\n }\n\n protected onClick(event: MouseEvent): void {\n const chart = this.#chart;\n if (!chart) return;\n const element = chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, false);\n const dataset = chart.getElementsAtEventForMode(event, 'dataset', { intersect: true }, false);\n if (element?.[0] && dataset)\n this.dataSelect.emit({ originalEvent: event, element: element[0], dataset });\n }\n\n async #render(): Promise<void> {\n if (!isPlatformBrowser(this.#platform)) return;\n const type = this.type();\n if (this.#chart && this.#chartType === type) {\n this.#apply(this.#chart);\n this.#chart.update();\n return;\n }\n if (this.#loading) return;\n this.#loading = true;\n try {\n const module = await this.#loader();\n if (!this.#ready) return; // destroyed while chart.js loaded\n this.#chart?.destroy();\n const Chart = module.default;\n this.#zone.runOutsideAngular(() => {\n this.#chart = new Chart(this.canvas().nativeElement, {\n type: this.type(),\n data: this.#themedData(),\n options: this.#themedOptions(),\n plugins: [...this.plugins()],\n });\n });\n this.#chartType = this.type();\n } catch (error) {\n console.error(\n 'hx-chart: chart.js could not be loaded. Is the peer dependency \"chart.js\" installed?',\n error,\n );\n return;\n } finally {\n this.#loading = false;\n }\n // inputs may have changed while chart.js loaded\n if (this.#chart && this.#chartType !== this.type()) await this.#render();\n }\n\n #apply(chart: HxChartInstance): void {\n chart.data = this.#themedData();\n chart.options = this.#themedOptions();\n }\n\n #token(name: string): string {\n return getComputedStyle(this.#host).getPropertyValue(name).trim();\n }\n\n /** The datasets with palette colours where they set none. The input is not changed. */\n #themedData(): Json {\n const data = this.data();\n const datasets = data.datasets;\n if (!Array.isArray(datasets)) return data;\n const palette = PALETTE.map((name) => this.#token(name)).filter(Boolean);\n if (palette.length === 0) return data;\n const perPoint = ['pie', 'doughnut', 'polarArea'].includes(this.type());\n return {\n ...data,\n datasets: datasets.map((dataset: DatasetLike, i: number) => {\n if (!isObject(dataset)) return dataset;\n const color = palette[i % palette.length];\n const count = Array.isArray(dataset.data) ? dataset.data.length : 0;\n const points = Array.from({ length: count }, (_, n) => palette[n % palette.length]);\n const filled = this.type() === 'line' || this.type() === 'radar';\n return {\n ...dataset,\n backgroundColor:\n dataset.backgroundColor ??\n (perPoint ? points : filled ? `color-mix(in srgb, ${color}, transparent 80%)` : color),\n borderColor:\n dataset.borderColor ?? (perPoint ? this.#token('--h-content-background') : color),\n };\n }),\n };\n }\n\n #themedOptions(): Json {\n const text = this.#token('--h-text-color');\n const muted = this.#token('--h-text-muted-color');\n const grid = this.#token('--h-content-border-color');\n const axis = { ticks: { color: muted }, grid: { color: grid }, border: { color: grid } };\n const radial = {\n ticks: { color: muted, backdropColor: 'transparent' },\n grid: { color: grid },\n angleLines: { color: grid },\n pointLabels: { color: text },\n };\n const type = this.type();\n const scales =\n type === 'radar' || type === 'polarArea'\n ? { r: radial }\n : type === 'pie' || type === 'doughnut'\n ? {}\n : { x: axis, y: axis };\n const defaults: Json = {\n responsive: this.responsive(),\n maintainAspectRatio: !(this.height() || this.width()),\n color: muted,\n borderColor: grid,\n plugins: { legend: { labels: { color: text } } },\n scales,\n };\n return merge(defaults, this.options());\n }\n\n #watchTheme(): void {\n if (typeof MutationObserver === 'undefined') return;\n this.#observer = new MutationObserver(() => {\n clearTimeout(this.#timer);\n this.#timer = setTimeout(() => this.refresh(), this.themeDelay());\n });\n this.#observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class', 'style', 'data-theme'],\n });\n }\n}\n"],"mappings":"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"}
|