@aceshooting/lyra-ui 0.1.2 → 0.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/README.md +2 -8
- package/custom-elements.json +3745 -2953
- package/dist/components/chart/bar-chart.js +17 -4
- package/dist/components/chart/box-plot.d.ts +8 -1
- package/dist/components/chart/box-plot.js +40 -4
- package/dist/components/chart/box-plot.styles.js +4 -0
- package/dist/components/chart/bubble-chart.d.ts +1 -2
- package/dist/components/chart/bubble-chart.js +17 -4
- package/dist/components/chart/chart-loader.d.ts +21 -4
- package/dist/components/chart/chart-loader.js +39 -12
- package/dist/components/chart/chart.d.ts +9 -3
- package/dist/components/chart/chart.js +42 -21
- package/dist/components/chart/doughnut-chart.d.ts +1 -2
- package/dist/components/chart/doughnut-chart.js +17 -4
- package/dist/components/chart/histogram-bin.js +12 -2
- package/dist/components/chart/histogram.d.ts +2 -2
- package/dist/components/chart/histogram.js +16 -2
- package/dist/components/chart/line-chart.js +17 -4
- package/dist/components/chart/pie-chart.d.ts +1 -2
- package/dist/components/chart/pie-chart.js +17 -4
- package/dist/components/chart/polar-area-chart.d.ts +1 -2
- package/dist/components/chart/polar-area-chart.js +17 -4
- package/dist/components/chart/radar-chart.d.ts +1 -2
- package/dist/components/chart/radar-chart.js +17 -4
- package/dist/components/chart/scatter-chart.js +17 -4
- package/dist/components/combobox/combobox.js +3 -4
- package/dist/components/combobox/combobox.stories.d.ts +6 -0
- package/dist/components/combobox/combobox.stories.js +27 -0
- package/dist/components/combobox/combobox.styles.js +2 -2
- package/dist/components/date-picker/date-input.stories.d.ts +5 -0
- package/dist/components/date-picker/date-input.stories.js +12 -0
- package/dist/components/date-picker/date-input.styles.js +2 -2
- package/dist/components/date-picker/date-picker.stories.d.ts +6 -0
- package/dist/components/date-picker/date-picker.stories.js +13 -0
- package/dist/components/empty/empty.d.ts +1 -1
- package/dist/components/empty/empty.js +1 -1
- package/dist/components/export-button/export-button.d.ts +2 -2
- package/dist/components/export-button/export-button.js +2 -2
- package/dist/components/file-input/accept.d.ts +1 -2
- package/dist/components/file-input/accept.js +1 -2
- package/dist/components/file-input/file-input.d.ts +2 -2
- package/dist/components/file-input/file-input.js +2 -2
- package/dist/components/flag/flag.stories.d.ts +5 -0
- package/dist/components/flag/flag.stories.js +17 -0
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/gauge/gauge.d.ts +1 -1
- package/dist/components/gauge/gauge.js +1 -1
- package/dist/components/graph/graph.d.ts +33 -4
- package/dist/components/graph/graph.js +146 -30
- package/dist/components/heatmap/calendar-grid.d.ts +31 -0
- package/dist/components/heatmap/calendar-grid.js +52 -0
- package/dist/components/heatmap/heatmap-scale.d.ts +8 -0
- package/dist/components/heatmap/heatmap-scale.js +21 -0
- package/dist/components/heatmap/heatmap.d.ts +19 -0
- package/dist/components/heatmap/heatmap.js +133 -20
- package/dist/components/heatmap/heatmap.styles.js +4 -0
- package/dist/components/map/map.d.ts +15 -0
- package/dist/components/map/map.js +89 -7
- package/dist/components/playback/playback.d.ts +2 -2
- package/dist/components/playback/playback.js +2 -2
- package/dist/components/skeleton/skeleton.d.ts +2 -2
- package/dist/components/skeleton/skeleton.js +2 -2
- package/dist/components/sparkline/sparkline.stories.d.ts +7 -0
- package/dist/components/sparkline/sparkline.stories.js +17 -0
- package/dist/components/stat/stat.d.ts +1 -1
- package/dist/components/stat/stat.js +6 -7
- package/dist/components/table/table.d.ts +1 -2
- package/dist/components/table/table.js +1 -2
- package/dist/components/table/table.styles.js +2 -3
- package/dist/components/time-range/time-range.js +4 -4
- package/dist/components/toast/toast.stories.d.ts +5 -0
- package/dist/components/toast/toast.stories.js +32 -0
- package/dist/components/tree/tree-node.d.ts +2 -2
- package/dist/components/tree/tree-node.js +2 -2
- package/dist/internal/form-associated.js +1 -2
- package/dist/internal/icons.js +1 -1
- package/dist/internal/tokens.styles.js +3 -3
- package/llms-full.txt +59 -83
- package/llms.txt +1 -2
- package/package.json +4 -1
|
@@ -6,9 +6,22 @@ import { defineElement } from '../../internal/prefix.js';
|
|
|
6
6
|
* @customElement lyra-bar-chart
|
|
7
7
|
*/
|
|
8
8
|
export class LyraBarChart extends LyraChart {
|
|
9
|
-
constructor() {
|
|
10
|
-
super(...arguments);
|
|
11
|
-
this.type = 'bar';
|
|
12
|
-
}
|
|
13
9
|
}
|
|
10
|
+
// `type` is locked read-only rather than a settable class field with just a
|
|
11
|
+
// default value — `LyraChart` declares it as a plain (decorator-managed)
|
|
12
|
+
// class field, and TypeScript forbids a subclass from re-declaring a base
|
|
13
|
+
// field as a getter/setter pair via ordinary class syntax (TS2611) — so the
|
|
14
|
+
// accessor pair is installed directly on the prototype instead, which is
|
|
15
|
+
// runtime-equivalent (same shadowing semantics as a class-syntax override)
|
|
16
|
+
// without tripping that check.
|
|
17
|
+
Object.defineProperty(LyraBarChart.prototype, 'type', {
|
|
18
|
+
configurable: true,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get() {
|
|
21
|
+
return 'bar';
|
|
22
|
+
},
|
|
23
|
+
set(_v) {
|
|
24
|
+
/* locked to 'bar'; direct writes are ignored */
|
|
25
|
+
},
|
|
26
|
+
});
|
|
14
27
|
defineElement('bar-chart', LyraBarChart);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
2
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
import '../skeleton/skeleton.js';
|
|
3
4
|
export interface BoxPlotPoint {
|
|
4
5
|
min: number;
|
|
5
6
|
q1: number;
|
|
@@ -15,7 +16,7 @@ export interface BoxPlotSeries {
|
|
|
15
16
|
/**
|
|
16
17
|
* `<lyra-box-plot>` — a box-and-whisker chart from precomputed five-number
|
|
17
18
|
* summaries (no raw sample data is shipped to the browser). Beyond Web
|
|
18
|
-
* Awesome's chart set —
|
|
19
|
+
* Awesome's chart set — useful for summarizing distributions.
|
|
19
20
|
*
|
|
20
21
|
* @customElement lyra-box-plot
|
|
21
22
|
* @csspart base, canvas
|
|
@@ -28,6 +29,12 @@ export declare class LyraBoxPlot extends LyraElement {
|
|
|
28
29
|
height: string;
|
|
29
30
|
yLabel: string;
|
|
30
31
|
beginAtZero: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* True until the lazy-loaded `chart.js` + `@sgratzl/chartjs-chart-boxplot`
|
|
34
|
+
* peer dependencies have settled (success or failure) — mirrors
|
|
35
|
+
* `LyraChart`'s `loading` state.
|
|
36
|
+
*/
|
|
37
|
+
private loading;
|
|
31
38
|
private canvasEl?;
|
|
32
39
|
private chart?;
|
|
33
40
|
private chartJsModule?;
|
|
@@ -5,11 +5,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html } from 'lit';
|
|
8
|
-
import { property, query } from 'lit/decorators.js';
|
|
8
|
+
import { property, query, state } from 'lit/decorators.js';
|
|
9
9
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
10
|
import { defineElement } from '../../internal/prefix.js';
|
|
11
11
|
import { loadChartJs } from './chart-loader.js';
|
|
12
12
|
import { styles } from './box-plot.styles.js';
|
|
13
|
+
import '../skeleton/skeleton.js';
|
|
13
14
|
let boxPlotPlugin;
|
|
14
15
|
/**
|
|
15
16
|
* Lazily loads `@sgratzl/chartjs-chart-boxplot` and registers its controller
|
|
@@ -36,7 +37,7 @@ function loadBoxPlotPlugin() {
|
|
|
36
37
|
/**
|
|
37
38
|
* `<lyra-box-plot>` — a box-and-whisker chart from precomputed five-number
|
|
38
39
|
* summaries (no raw sample data is shipped to the browser). Beyond Web
|
|
39
|
-
* Awesome's chart set —
|
|
40
|
+
* Awesome's chart set — useful for summarizing distributions.
|
|
40
41
|
*
|
|
41
42
|
* @customElement lyra-box-plot
|
|
42
43
|
* @csspart base, canvas
|
|
@@ -50,6 +51,12 @@ export class LyraBoxPlot extends LyraElement {
|
|
|
50
51
|
this.height = '280px';
|
|
51
52
|
this.yLabel = '';
|
|
52
53
|
this.beginAtZero = true;
|
|
54
|
+
/**
|
|
55
|
+
* True until the lazy-loaded `chart.js` + `@sgratzl/chartjs-chart-boxplot`
|
|
56
|
+
* peer dependencies have settled (success or failure) — mirrors
|
|
57
|
+
* `LyraChart`'s `loading` state.
|
|
58
|
+
*/
|
|
59
|
+
this.loading = true;
|
|
53
60
|
}
|
|
54
61
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
55
62
|
connectedCallback() {
|
|
@@ -64,6 +71,7 @@ export class LyraBoxPlot extends LyraElement {
|
|
|
64
71
|
// established pattern in `LyraChart.connectedCallback()` — instead of
|
|
65
72
|
// unconditionally re-awaiting the already-cached `loadChartJs()` promise.
|
|
66
73
|
async onBoxPlotPluginLoaded(boxMod) {
|
|
74
|
+
this.loading = false;
|
|
67
75
|
if (!boxMod)
|
|
68
76
|
return;
|
|
69
77
|
this.chartJsModule = (await loadChartJs()) ?? undefined;
|
|
@@ -75,6 +83,10 @@ export class LyraBoxPlot extends LyraElement {
|
|
|
75
83
|
this.chart = undefined;
|
|
76
84
|
}
|
|
77
85
|
updated(changed) {
|
|
86
|
+
if (this.loading)
|
|
87
|
+
this.setAttribute('aria-busy', 'true');
|
|
88
|
+
else
|
|
89
|
+
this.removeAttribute('aria-busy');
|
|
78
90
|
// `--lyra-chart-height` is read by `:host`'s `block-size` in
|
|
79
91
|
// `chart.styles.ts` (shared with `lyra-chart`). Custom properties only
|
|
80
92
|
// cascade downward (host -> shadow tree), so this must be set on the
|
|
@@ -106,13 +118,34 @@ export class LyraBoxPlot extends LyraElement {
|
|
|
106
118
|
},
|
|
107
119
|
};
|
|
108
120
|
}
|
|
121
|
+
// Mirrors `LyraChart.draw()`'s reuse-existing-instance-when-possible
|
|
122
|
+
// pattern: an update that doesn't need a new Chart.js instance (e.g. a
|
|
123
|
+
// bare `height` change, or new `boxes`/`labels` data) mutates the existing
|
|
124
|
+
// chart and does an incremental `.update('none')` instead of tearing down
|
|
125
|
+
// and rebuilding the whole canvas/instance on every reactive update. Unlike
|
|
126
|
+
// `LyraChart`, `LyraBoxPlot` has no raw `config` passthrough that could
|
|
127
|
+
// change the effective Chart.js type out from under `this.type`, so
|
|
128
|
+
// reusing whenever a chart already exists is always safe here.
|
|
109
129
|
draw() {
|
|
110
130
|
if (!this.chartJsModule || !this.canvasEl)
|
|
111
131
|
return;
|
|
112
|
-
this.
|
|
113
|
-
|
|
132
|
+
const config = this.buildConfig();
|
|
133
|
+
if (this.chart) {
|
|
134
|
+
this.chart.data = config.data;
|
|
135
|
+
this.chart.options = config.options ?? {};
|
|
136
|
+
this.chart.update('none');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.chart = new this.chartJsModule.Chart(this.canvasEl, config);
|
|
114
140
|
}
|
|
115
141
|
render() {
|
|
142
|
+
if (this.loading) {
|
|
143
|
+
return html `
|
|
144
|
+
<div part="base">
|
|
145
|
+
<lyra-skeleton variant="rect"></lyra-skeleton>
|
|
146
|
+
</div>
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
116
149
|
const label = this.boxes.map((b) => b.label).join(', ') || 'Box plot';
|
|
117
150
|
return html `
|
|
118
151
|
<div part="base">
|
|
@@ -139,6 +172,9 @@ __decorate([
|
|
|
139
172
|
__decorate([
|
|
140
173
|
property({ type: Boolean, attribute: 'begin-at-zero' })
|
|
141
174
|
], LyraBoxPlot.prototype, "beginAtZero", void 0);
|
|
175
|
+
__decorate([
|
|
176
|
+
state()
|
|
177
|
+
], LyraBoxPlot.prototype, "loading", void 0);
|
|
142
178
|
__decorate([
|
|
143
179
|
query('canvas')
|
|
144
180
|
], LyraBoxPlot.prototype, "canvasEl", void 0);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
|
-
import type { LyraChartType } from './chart.js';
|
|
3
2
|
/**
|
|
4
3
|
* `<lyra-bubble-chart>` — `<lyra-chart>` with `type` locked to `"bubble"`. Feed
|
|
5
4
|
* points via `Series.points`, each needing an `x`/`y`/`r` (radius) triple —
|
|
@@ -10,7 +9,7 @@ import type { LyraChartType } from './chart.js';
|
|
|
10
9
|
* @customElement lyra-bubble-chart
|
|
11
10
|
*/
|
|
12
11
|
export declare class LyraBubbleChart extends LyraChart {
|
|
13
|
-
type:
|
|
12
|
+
type: 'bubble';
|
|
14
13
|
}
|
|
15
14
|
declare global {
|
|
16
15
|
interface HTMLElementTagNameMap {
|
|
@@ -10,9 +10,22 @@ import { defineElement } from '../../internal/prefix.js';
|
|
|
10
10
|
* @customElement lyra-bubble-chart
|
|
11
11
|
*/
|
|
12
12
|
export class LyraBubbleChart extends LyraChart {
|
|
13
|
-
constructor() {
|
|
14
|
-
super(...arguments);
|
|
15
|
-
this.type = 'bubble';
|
|
16
|
-
}
|
|
17
13
|
}
|
|
14
|
+
// `type` is locked read-only rather than a settable class field with just a
|
|
15
|
+
// default value — `LyraChart` declares it as a plain (decorator-managed)
|
|
16
|
+
// class field, and TypeScript forbids a subclass from re-declaring a base
|
|
17
|
+
// field as a getter/setter pair via ordinary class syntax (TS2611) — so the
|
|
18
|
+
// accessor pair is installed directly on the prototype instead, which is
|
|
19
|
+
// runtime-equivalent (same shadowing semantics as a class-syntax override)
|
|
20
|
+
// without tripping that check.
|
|
21
|
+
Object.defineProperty(LyraBubbleChart.prototype, 'type', {
|
|
22
|
+
configurable: true,
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get() {
|
|
25
|
+
return 'bubble';
|
|
26
|
+
},
|
|
27
|
+
set(_v) {
|
|
28
|
+
/* locked to 'bubble'; direct writes are ignored */
|
|
29
|
+
},
|
|
30
|
+
});
|
|
18
31
|
defineElement('bubble-chart', LyraBubbleChart);
|
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import type * as ChartJsModule from 'chart.js';
|
|
2
|
+
import type ZoomPlugin from 'chartjs-plugin-zoom';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Independently loads the mandatory `chart.js` peer dependency and the
|
|
5
|
+
* opt-in `chartjs-plugin-zoom` peer dependency, so a partial install
|
|
6
|
+
* (`chart.js` only, which `peerDependenciesMeta` marks as a valid
|
|
7
|
+
* combination) degrades to "charts render, zoom is inert" instead of every
|
|
8
|
+
* chart breaking. Exported (in addition to `loadChartJs()` below) so both
|
|
9
|
+
* failure paths — and the real caught error each one logs — are directly
|
|
10
|
+
* testable without needing to actually uninstall either package.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadChartAndZoom(importChart?: () => Promise<typeof ChartJsModule>, importZoom?: () => Promise<{
|
|
13
|
+
default: typeof ZoomPlugin;
|
|
14
|
+
}>): Promise<{
|
|
15
|
+
mod: typeof ChartJsModule;
|
|
16
|
+
zoomPlugin: typeof ZoomPlugin | undefined;
|
|
17
|
+
} | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Lazily loads the optional peer dependency `chart.js` (+ `chartjs-plugin-zoom`,
|
|
20
|
+
* loaded independently — see `loadChartAndZoom()`) once per page, registering
|
|
21
|
+
* only the tree-shaken subset this library uses. Resolves to `null` if
|
|
22
|
+
* chart.js isn't installed; still resolves the real module (with zoom simply
|
|
23
|
+
* unregistered) if only `chartjs-plugin-zoom` is missing.
|
|
7
24
|
*/
|
|
8
25
|
export declare function loadChartJs(): Promise<typeof ChartJsModule | null>;
|
|
@@ -1,25 +1,52 @@
|
|
|
1
1
|
let chartJs;
|
|
2
2
|
let registered = false;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Independently loads the mandatory `chart.js` peer dependency and the
|
|
5
|
+
* opt-in `chartjs-plugin-zoom` peer dependency, so a partial install
|
|
6
|
+
* (`chart.js` only, which `peerDependenciesMeta` marks as a valid
|
|
7
|
+
* combination) degrades to "charts render, zoom is inert" instead of every
|
|
8
|
+
* chart breaking. Exported (in addition to `loadChartJs()` below) so both
|
|
9
|
+
* failure paths — and the real caught error each one logs — are directly
|
|
10
|
+
* testable without needing to actually uninstall either package.
|
|
11
|
+
*/
|
|
12
|
+
export async function loadChartAndZoom(importChart = () => import('chart.js'), importZoom = () => import('chartjs-plugin-zoom')) {
|
|
13
|
+
let mod;
|
|
14
|
+
try {
|
|
15
|
+
mod = await importChart();
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
console.warn('<lyra-chart> needs the optional peer dependency `chart.js` — install it with `pnpm add chart.js`:', err);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
let zoomPlugin;
|
|
22
|
+
try {
|
|
23
|
+
zoomPlugin = (await importZoom()).default;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.warn('<lyra-chart> zoom support needs the optional peer dependency `chartjs-plugin-zoom` — ' +
|
|
27
|
+
'charts still render without it, but the `zoom` attribute has no effect until it is ' +
|
|
28
|
+
'installed with `pnpm add chartjs-plugin-zoom`:', err);
|
|
29
|
+
}
|
|
30
|
+
return { mod, zoomPlugin };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Lazily loads the optional peer dependency `chart.js` (+ `chartjs-plugin-zoom`,
|
|
34
|
+
* loaded independently — see `loadChartAndZoom()`) once per page, registering
|
|
35
|
+
* only the tree-shaken subset this library uses. Resolves to `null` if
|
|
36
|
+
* chart.js isn't installed; still resolves the real module (with zoom simply
|
|
37
|
+
* unregistered) if only `chartjs-plugin-zoom` is missing.
|
|
8
38
|
*/
|
|
9
39
|
export function loadChartJs() {
|
|
10
40
|
if (!chartJs) {
|
|
11
|
-
chartJs =
|
|
12
|
-
|
|
41
|
+
chartJs = loadChartAndZoom().then((result) => {
|
|
42
|
+
if (!result)
|
|
43
|
+
return null;
|
|
44
|
+
const { mod, zoomPlugin } = result;
|
|
13
45
|
if (!registered) {
|
|
14
|
-
mod.Chart.register(mod.LineController, mod.BarController, mod.ScatterController, mod.DoughnutController, mod.PieController, mod.RadarController, mod.PolarAreaController, mod.BubbleController, mod.LineElement, mod.PointElement, mod.BarElement, mod.ArcElement, mod.LinearScale, mod.CategoryScale, mod.RadialLinearScale, mod.Filler, mod.Tooltip, mod.Legend,
|
|
46
|
+
mod.Chart.register(mod.LineController, mod.BarController, mod.ScatterController, mod.DoughnutController, mod.PieController, mod.RadarController, mod.PolarAreaController, mod.BubbleController, mod.LineElement, mod.PointElement, mod.BarElement, mod.ArcElement, mod.LinearScale, mod.CategoryScale, mod.RadialLinearScale, mod.Filler, mod.Tooltip, mod.Legend, ...(zoomPlugin ? [zoomPlugin] : []));
|
|
15
47
|
registered = true;
|
|
16
48
|
}
|
|
17
49
|
return mod;
|
|
18
|
-
})
|
|
19
|
-
.catch(() => {
|
|
20
|
-
console.warn('<lyra-chart> needs the optional peer dependencies `chart.js` and ' +
|
|
21
|
-
'`chartjs-plugin-zoom` — install them with `pnpm add chart.js chartjs-plugin-zoom`.');
|
|
22
|
-
return null;
|
|
23
50
|
});
|
|
24
51
|
}
|
|
25
52
|
return chartJs;
|
|
@@ -20,12 +20,12 @@ export interface Series {
|
|
|
20
20
|
pointRadius?: number;
|
|
21
21
|
type?: 'line' | 'bar';
|
|
22
22
|
}
|
|
23
|
-
export type LyraChartType = 'line' | 'bar' | 'scatter';
|
|
23
|
+
export type LyraChartType = 'line' | 'bar' | 'scatter' | 'pie' | 'doughnut' | 'radar' | 'polarArea' | 'bubble';
|
|
24
24
|
/**
|
|
25
25
|
* `<lyra-chart>` — the core Chart.js wrapper every other `lyra-*-chart` tag
|
|
26
26
|
* subclasses. Requires the optional peer deps `chart.js` + `chartjs-plugin-zoom`.
|
|
27
27
|
*
|
|
28
|
-
* **API mirror note
|
|
28
|
+
* **API mirror note:** the real `wa-chart` docs page
|
|
29
29
|
* (https://webawesome.com/docs/components/chart/) documents a `config:
|
|
30
30
|
* ChartJS['config']` property alongside its simplified attributes — "a
|
|
31
31
|
* flexible wrapper around Chart.js" supporting *both* simplified attributes
|
|
@@ -73,11 +73,17 @@ export declare class LyraChart extends LyraElement {
|
|
|
73
73
|
private chart?;
|
|
74
74
|
private chartJsModule?;
|
|
75
75
|
private builtType?;
|
|
76
|
-
private onThemeChange;
|
|
77
76
|
connectedCallback(): void;
|
|
78
77
|
disconnectedCallback(): void;
|
|
79
78
|
protected updated(changed: PropertyValues): void;
|
|
80
79
|
private seriesToDataset;
|
|
80
|
+
/**
|
|
81
|
+
* Builds `options.scales` for the effective chart type: no scale at all for
|
|
82
|
+
* pie/doughnut (a proportional-area chart has no axis), the single radial
|
|
83
|
+
* `r` scale Chart.js v4 uses for radar/polarArea, and the cartesian
|
|
84
|
+
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type.
|
|
85
|
+
*/
|
|
86
|
+
private buildScales;
|
|
81
87
|
private buildConfig;
|
|
82
88
|
private draw;
|
|
83
89
|
/** Reset any active zoom/pan back to the original view. */
|
|
@@ -23,12 +23,18 @@ import '../skeleton/skeleton.js';
|
|
|
23
23
|
function isPlainObject(value) {
|
|
24
24
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
25
25
|
}
|
|
26
|
+
// Keys that would let a JSON-sourced `config` (e.g. parsed from an API
|
|
27
|
+
// response) reach up through the merge and mutate `Object.prototype` —
|
|
28
|
+
// skipped unconditionally regardless of `base`'s own shape.
|
|
29
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
26
30
|
function deepMerge(base, override) {
|
|
27
31
|
if (!isPlainObject(base) || !isPlainObject(override)) {
|
|
28
32
|
return (override === undefined ? base : override);
|
|
29
33
|
}
|
|
30
34
|
const result = { ...base };
|
|
31
35
|
for (const key of Object.keys(override)) {
|
|
36
|
+
if (UNSAFE_KEYS.has(key))
|
|
37
|
+
continue;
|
|
32
38
|
result[key] = deepMerge(base[key], override[key]);
|
|
33
39
|
}
|
|
34
40
|
return result;
|
|
@@ -37,7 +43,7 @@ function deepMerge(base, override) {
|
|
|
37
43
|
* `<lyra-chart>` — the core Chart.js wrapper every other `lyra-*-chart` tag
|
|
38
44
|
* subclasses. Requires the optional peer deps `chart.js` + `chartjs-plugin-zoom`.
|
|
39
45
|
*
|
|
40
|
-
* **API mirror note
|
|
46
|
+
* **API mirror note:** the real `wa-chart` docs page
|
|
41
47
|
* (https://webawesome.com/docs/components/chart/) documents a `config:
|
|
42
48
|
* ChartJS['config']` property alongside its simplified attributes — "a
|
|
43
49
|
* flexible wrapper around Chart.js" supporting *both* simplified attributes
|
|
@@ -73,12 +79,10 @@ export class LyraChart extends LyraElement {
|
|
|
73
79
|
/** True until the lazy-loaded `chart.js` peer dependency has settled (success or failure). */
|
|
74
80
|
this.loading = true;
|
|
75
81
|
this.zoomed = false;
|
|
76
|
-
this.onThemeChange = () => this.draw();
|
|
77
82
|
}
|
|
78
83
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
79
84
|
connectedCallback() {
|
|
80
85
|
super.connectedCallback();
|
|
81
|
-
window.addEventListener('lyra-theme', this.onThemeChange);
|
|
82
86
|
void loadChartJs().then((mod) => {
|
|
83
87
|
this.loading = false;
|
|
84
88
|
if (!mod)
|
|
@@ -89,7 +93,6 @@ export class LyraChart extends LyraElement {
|
|
|
89
93
|
}
|
|
90
94
|
disconnectedCallback() {
|
|
91
95
|
super.disconnectedCallback();
|
|
92
|
-
window.removeEventListener('lyra-theme', this.onThemeChange);
|
|
93
96
|
this.chart?.destroy();
|
|
94
97
|
this.chart = undefined;
|
|
95
98
|
}
|
|
@@ -127,8 +130,41 @@ export class LyraChart extends LyraElement {
|
|
|
127
130
|
tooltip: s.noTooltip ? { enabled: false } : undefined,
|
|
128
131
|
};
|
|
129
132
|
}
|
|
130
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Builds `options.scales` for the effective chart type: no scale at all for
|
|
135
|
+
* pie/doughnut (a proportional-area chart has no axis), the single radial
|
|
136
|
+
* `r` scale Chart.js v4 uses for radar/polarArea, and the cartesian
|
|
137
|
+
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type.
|
|
138
|
+
*/
|
|
139
|
+
buildScales() {
|
|
140
|
+
if (this.type === 'pie' || this.type === 'doughnut')
|
|
141
|
+
return {};
|
|
142
|
+
if (this.type === 'radar' || this.type === 'polarArea') {
|
|
143
|
+
return {
|
|
144
|
+
r: {
|
|
145
|
+
beginAtZero: this.beginAtZero,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
131
149
|
const hasY2 = this.datasets.some((s) => s.axis === 'y2');
|
|
150
|
+
return {
|
|
151
|
+
x: {
|
|
152
|
+
type: this.type === 'scatter' ? 'linear' : 'category',
|
|
153
|
+
title: { display: !!this.xLabel, text: this.xLabel },
|
|
154
|
+
},
|
|
155
|
+
y: { beginAtZero: this.beginAtZero, title: { display: !!this.yLabel, text: this.yLabel } },
|
|
156
|
+
...(hasY2
|
|
157
|
+
? {
|
|
158
|
+
y2: {
|
|
159
|
+
position: 'right',
|
|
160
|
+
grid: { drawOnChartArea: false },
|
|
161
|
+
title: { display: !!this.y2Label, text: this.y2Label },
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
: {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
buildConfig() {
|
|
132
168
|
const generated = {
|
|
133
169
|
type: this.type,
|
|
134
170
|
data: {
|
|
@@ -158,22 +194,7 @@ export class LyraChart extends LyraElement {
|
|
|
158
194
|
}
|
|
159
195
|
: undefined,
|
|
160
196
|
},
|
|
161
|
-
scales:
|
|
162
|
-
x: {
|
|
163
|
-
type: this.type === 'scatter' ? 'linear' : 'category',
|
|
164
|
-
title: { display: !!this.xLabel, text: this.xLabel },
|
|
165
|
-
},
|
|
166
|
-
y: { beginAtZero: this.beginAtZero, title: { display: !!this.yLabel, text: this.yLabel } },
|
|
167
|
-
...(hasY2
|
|
168
|
-
? {
|
|
169
|
-
y2: {
|
|
170
|
-
position: 'right',
|
|
171
|
-
grid: { drawOnChartArea: false },
|
|
172
|
-
title: { display: !!this.y2Label, text: this.y2Label },
|
|
173
|
-
},
|
|
174
|
-
}
|
|
175
|
-
: {}),
|
|
176
|
-
},
|
|
197
|
+
scales: this.buildScales(),
|
|
177
198
|
},
|
|
178
199
|
};
|
|
179
200
|
if (!this.config)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
|
-
import type { LyraChartType } from './chart.js';
|
|
3
2
|
/**
|
|
4
3
|
* `<lyra-doughnut-chart>` — `<lyra-chart>` with `type` locked to `"doughnut"`.
|
|
5
4
|
*
|
|
6
5
|
* @customElement lyra-doughnut-chart
|
|
7
6
|
*/
|
|
8
7
|
export declare class LyraDoughnutChart extends LyraChart {
|
|
9
|
-
type:
|
|
8
|
+
type: 'doughnut';
|
|
10
9
|
}
|
|
11
10
|
declare global {
|
|
12
11
|
interface HTMLElementTagNameMap {
|
|
@@ -6,9 +6,22 @@ import { defineElement } from '../../internal/prefix.js';
|
|
|
6
6
|
* @customElement lyra-doughnut-chart
|
|
7
7
|
*/
|
|
8
8
|
export class LyraDoughnutChart extends LyraChart {
|
|
9
|
-
constructor() {
|
|
10
|
-
super(...arguments);
|
|
11
|
-
this.type = 'doughnut';
|
|
12
|
-
}
|
|
13
9
|
}
|
|
10
|
+
// `type` is locked read-only rather than a settable class field with just a
|
|
11
|
+
// default value — `LyraChart` declares it as a plain (decorator-managed)
|
|
12
|
+
// class field, and TypeScript forbids a subclass from re-declaring a base
|
|
13
|
+
// field as a getter/setter pair via ordinary class syntax (TS2611) — so the
|
|
14
|
+
// accessor pair is installed directly on the prototype instead, which is
|
|
15
|
+
// runtime-equivalent (same shadowing semantics as a class-syntax override)
|
|
16
|
+
// without tripping that check.
|
|
17
|
+
Object.defineProperty(LyraDoughnutChart.prototype, 'type', {
|
|
18
|
+
configurable: true,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get() {
|
|
21
|
+
return 'doughnut';
|
|
22
|
+
},
|
|
23
|
+
set(_v) {
|
|
24
|
+
/* locked to 'doughnut'; direct writes are ignored */
|
|
25
|
+
},
|
|
26
|
+
});
|
|
14
27
|
defineElement('doughnut-chart', LyraDoughnutChart);
|
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
export function binValues(values, binCount) {
|
|
3
3
|
if (values.length === 0 || binCount <= 0)
|
|
4
4
|
return [];
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// Spreading `values` as call arguments (`Math.min(...values)`) throws
|
|
6
|
+
// `RangeError: Maximum call stack size exceeded` once `values` is large
|
|
7
|
+
// enough to overflow the engine's argument-list limit — reduce manually
|
|
8
|
+
// instead so an arbitrarily large sample never crashes.
|
|
9
|
+
let lo = values[0];
|
|
10
|
+
let hi = values[0];
|
|
11
|
+
for (const v of values) {
|
|
12
|
+
if (v < lo)
|
|
13
|
+
lo = v;
|
|
14
|
+
if (v > hi)
|
|
15
|
+
hi = v;
|
|
16
|
+
}
|
|
7
17
|
const span = hi - lo || 1;
|
|
8
18
|
const width = span / binCount;
|
|
9
19
|
const buckets = Array.from({ length: binCount }, (_, i) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
2
|
/**
|
|
3
3
|
* `<lyra-histogram>` — bins `values` into `bins` equal-width buckets and
|
|
4
|
-
* renders them as a bar chart.
|
|
5
|
-
*
|
|
4
|
+
* renders them as a bar chart. Chart.js has no built-in histogram
|
|
5
|
+
* controller; this composes `binValues()` with the plain `bar` type.
|
|
6
6
|
*
|
|
7
7
|
* @customElement lyra-histogram
|
|
8
8
|
*/
|
|
@@ -12,8 +12,8 @@ import { binValues } from './histogram-bin.js';
|
|
|
12
12
|
import { styles } from './histogram.styles.js';
|
|
13
13
|
/**
|
|
14
14
|
* `<lyra-histogram>` — bins `values` into `bins` equal-width buckets and
|
|
15
|
-
* renders them as a bar chart.
|
|
16
|
-
*
|
|
15
|
+
* renders them as a bar chart. Chart.js has no built-in histogram
|
|
16
|
+
* controller; this composes `binValues()` with the plain `bar` type.
|
|
17
17
|
*
|
|
18
18
|
* @customElement lyra-histogram
|
|
19
19
|
*/
|
|
@@ -67,4 +67,18 @@ Object.defineProperty(LyraHistogram.prototype, 'datasets', {
|
|
|
67
67
|
/* derived from `values`/`bins`; direct writes are ignored */
|
|
68
68
|
},
|
|
69
69
|
});
|
|
70
|
+
// `type` is locked to `'bar'` the same way — the field initializer above is
|
|
71
|
+
// just a default value, not an enforced lock, so without this a `type="line"`
|
|
72
|
+
// attribute (or `el.type = 'line'`) would silently turn a histogram into a
|
|
73
|
+
// line chart of its own bucket counts.
|
|
74
|
+
Object.defineProperty(LyraHistogram.prototype, 'type', {
|
|
75
|
+
configurable: true,
|
|
76
|
+
enumerable: true,
|
|
77
|
+
get() {
|
|
78
|
+
return 'bar';
|
|
79
|
+
},
|
|
80
|
+
set(_v) {
|
|
81
|
+
/* locked to 'bar'; direct writes are ignored */
|
|
82
|
+
},
|
|
83
|
+
});
|
|
70
84
|
defineElement('histogram', LyraHistogram);
|
|
@@ -6,9 +6,22 @@ import { defineElement } from '../../internal/prefix.js';
|
|
|
6
6
|
* @customElement lyra-line-chart
|
|
7
7
|
*/
|
|
8
8
|
export class LyraLineChart extends LyraChart {
|
|
9
|
-
constructor() {
|
|
10
|
-
super(...arguments);
|
|
11
|
-
this.type = 'line';
|
|
12
|
-
}
|
|
13
9
|
}
|
|
10
|
+
// `type` is locked read-only rather than a settable class field with just a
|
|
11
|
+
// default value — `LyraChart` declares it as a plain (decorator-managed)
|
|
12
|
+
// class field, and TypeScript forbids a subclass from re-declaring a base
|
|
13
|
+
// field as a getter/setter pair via ordinary class syntax (TS2611) — so the
|
|
14
|
+
// accessor pair is installed directly on the prototype instead, which is
|
|
15
|
+
// runtime-equivalent (same shadowing semantics as a class-syntax override)
|
|
16
|
+
// without tripping that check.
|
|
17
|
+
Object.defineProperty(LyraLineChart.prototype, 'type', {
|
|
18
|
+
configurable: true,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get() {
|
|
21
|
+
return 'line';
|
|
22
|
+
},
|
|
23
|
+
set(_v) {
|
|
24
|
+
/* locked to 'line'; direct writes are ignored */
|
|
25
|
+
},
|
|
26
|
+
});
|
|
14
27
|
defineElement('line-chart', LyraLineChart);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
|
-
import type { LyraChartType } from './chart.js';
|
|
3
2
|
/**
|
|
4
3
|
* `<lyra-pie-chart>` — `<lyra-chart>` with `type` locked to `"pie"`. Single-series:
|
|
5
4
|
* one `Series` with `data: number[]` and `color: string[]` as the slice palette.
|
|
@@ -7,7 +6,7 @@ import type { LyraChartType } from './chart.js';
|
|
|
7
6
|
* @customElement lyra-pie-chart
|
|
8
7
|
*/
|
|
9
8
|
export declare class LyraPieChart extends LyraChart {
|
|
10
|
-
type:
|
|
9
|
+
type: 'pie';
|
|
11
10
|
}
|
|
12
11
|
declare global {
|
|
13
12
|
interface HTMLElementTagNameMap {
|
|
@@ -7,9 +7,22 @@ import { defineElement } from '../../internal/prefix.js';
|
|
|
7
7
|
* @customElement lyra-pie-chart
|
|
8
8
|
*/
|
|
9
9
|
export class LyraPieChart extends LyraChart {
|
|
10
|
-
constructor() {
|
|
11
|
-
super(...arguments);
|
|
12
|
-
this.type = 'pie';
|
|
13
|
-
}
|
|
14
10
|
}
|
|
11
|
+
// `type` is locked read-only rather than a settable class field with just a
|
|
12
|
+
// default value — `LyraChart` declares it as a plain (decorator-managed)
|
|
13
|
+
// class field, and TypeScript forbids a subclass from re-declaring a base
|
|
14
|
+
// field as a getter/setter pair via ordinary class syntax (TS2611) — so the
|
|
15
|
+
// accessor pair is installed directly on the prototype instead, which is
|
|
16
|
+
// runtime-equivalent (same shadowing semantics as a class-syntax override)
|
|
17
|
+
// without tripping that check.
|
|
18
|
+
Object.defineProperty(LyraPieChart.prototype, 'type', {
|
|
19
|
+
configurable: true,
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get() {
|
|
22
|
+
return 'pie';
|
|
23
|
+
},
|
|
24
|
+
set(_v) {
|
|
25
|
+
/* locked to 'pie'; direct writes are ignored */
|
|
26
|
+
},
|
|
27
|
+
});
|
|
15
28
|
defineElement('pie-chart', LyraPieChart);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
|
-
import type { LyraChartType } from './chart.js';
|
|
3
2
|
/**
|
|
4
3
|
* `<lyra-polar-area-chart>` — `<lyra-chart>` with `type` locked to `"polarArea"`.
|
|
5
4
|
*
|
|
6
5
|
* @customElement lyra-polar-area-chart
|
|
7
6
|
*/
|
|
8
7
|
export declare class LyraPolarAreaChart extends LyraChart {
|
|
9
|
-
type:
|
|
8
|
+
type: 'polarArea';
|
|
10
9
|
}
|
|
11
10
|
declare global {
|
|
12
11
|
interface HTMLElementTagNameMap {
|