@yuuvis/client-components 3.0.0 → 3.1.0
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/charts/README.md +64 -0
- package/fesm2022/yuuvis-client-components-charts.mjs +206 -0
- package/fesm2022/yuuvis-client-components-charts.mjs.map +1 -0
- package/fesm2022/yuuvis-client-components-common.mjs +58 -45
- package/fesm2022/yuuvis-client-components-common.mjs.map +1 -1
- package/fesm2022/yuuvis-client-components-table-grid.mjs +108 -0
- package/fesm2022/yuuvis-client-components-table-grid.mjs.map +1 -0
- package/lib/assets/i18n/de.json +6 -6
- package/lib/assets/i18n/en.json +6 -6
- package/package.json +20 -2
- package/table-grid/README.md +90 -0
- package/types/yuuvis-client-components-charts.d.ts +47 -0
- package/types/yuuvis-client-components-table-grid.d.ts +60 -0
package/charts/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @yuuvis/client-components/charts
|
|
2
|
+
|
|
3
|
+
Thin wrapper around [ag-charts-angular](https://www.ag-grid.com/charts/angular/quick-start/) wired into the `@yuuvis/material` design system. Charts pick up `--ymt-*` tokens (surface, text color, palette, outlines, typography) and react to light/dark/high-contrast mode changes via `ThemeService`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
The peer dependencies are optional — only consumers using this entry point need them:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install ag-charts-angular ag-charts-community
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Component, signal } from '@angular/core';
|
|
17
|
+
import { YuvChartComponent } from '@yuuvis/client-components/charts';
|
|
18
|
+
import type { AgChartOptions } from 'ag-charts-community';
|
|
19
|
+
|
|
20
|
+
@Component({
|
|
21
|
+
standalone: true,
|
|
22
|
+
imports: [YuvChartComponent],
|
|
23
|
+
template: `<yuv-chart [options]="options()"></yuv-chart>`
|
|
24
|
+
})
|
|
25
|
+
export class MyChartComponent {
|
|
26
|
+
readonly options = signal<AgChartOptions>({
|
|
27
|
+
title: { text: 'Quarterly Revenue' },
|
|
28
|
+
data: [
|
|
29
|
+
{ quarter: 'Q1', revenue: 120 },
|
|
30
|
+
{ quarter: 'Q2', revenue: 180 },
|
|
31
|
+
{ quarter: 'Q3', revenue: 150 },
|
|
32
|
+
{ quarter: 'Q4', revenue: 220 }
|
|
33
|
+
],
|
|
34
|
+
series: [{ type: 'bar', xKey: 'quarter', yKey: 'revenue' }]
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The component automatically applies a yuv-themed `AgChartTheme` derived from the active `--ymt-*` tokens. Pass an explicit `[theme]` to override.
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
| Input | Type | Notes |
|
|
44
|
+
|-----------|-----------------------------------|----------------------------------------------------------------------|
|
|
45
|
+
| `options` | `AgChartOptions` (required) | Forwarded to `<ag-charts>`. The `theme` field is overridden. |
|
|
46
|
+
| `theme` | `AgChartTheme \| string` | Override the auto-generated yuv theme. Optional. |
|
|
47
|
+
|
|
48
|
+
## Theming
|
|
49
|
+
|
|
50
|
+
`YuvChartThemeService` (provided in root) reads `--ymt-*` tokens from `document.documentElement` and rebuilds the chart theme whenever `ThemeService.mode()` or `ThemeService.currentTheme()` changes. Token map:
|
|
51
|
+
|
|
52
|
+
| `--ymt-*` token | ag-charts target |
|
|
53
|
+
|--------------------------------|-----------------------------------------------|
|
|
54
|
+
| `--ymt-surface` | `overrides.common.background.fill` |
|
|
55
|
+
| `--ymt-text-color` | titles, legend item label, axis title |
|
|
56
|
+
| `--ymt-text-color-subtle` | subtitle, axis label |
|
|
57
|
+
| `--ymt-primary` / `--ymt-success` / `--ymt-warning` / `--ymt-danger` / `--ymt-brand` | `palette.fills` |
|
|
58
|
+
| `--ymt-outline` | `palette.strokes` |
|
|
59
|
+
| `--ymt-outline-variant` | axis lines, ticks, gridlines |
|
|
60
|
+
| `--mat-sys-body-medium-font` | font family across labels/titles |
|
|
61
|
+
|
|
62
|
+
Tooltips render with the default `ag-charts-tooltip` class — host SCSS styles them with surface, outline, and corner tokens so they match the rest of the design system.
|
|
63
|
+
|
|
64
|
+
If you change tokens at runtime outside of `ThemeService` (e.g. flipping a class on `<body>`), call `YuvChartThemeService.refresh()` to rebuild.
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, DOCUMENT, signal, computed, effect, Injectable, input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { AgCharts } from 'ag-charts-angular';
|
|
4
|
+
import { ThemeService, HIGH_CONTRAST_THEME_KEY } from '@yuuvis/client-components/common';
|
|
5
|
+
|
|
6
|
+
class YuvChartThemeService {
|
|
7
|
+
#document = inject(DOCUMENT);
|
|
8
|
+
#themeService = inject(ThemeService);
|
|
9
|
+
#revision = signal(0, ...(ngDevMode ? [{ debugName: "#revision" }] : /* istanbul ignore next */ []));
|
|
10
|
+
chartTheme = computed(() => {
|
|
11
|
+
this.#revision();
|
|
12
|
+
return this.#buildTheme();
|
|
13
|
+
}, ...(ngDevMode ? [{ debugName: "chartTheme" }] : /* istanbul ignore next */ []));
|
|
14
|
+
constructor() {
|
|
15
|
+
effect((onCleanup) => {
|
|
16
|
+
this.#themeService.mode();
|
|
17
|
+
this.#themeService.currentTheme();
|
|
18
|
+
const win = this.#document.defaultView;
|
|
19
|
+
if (!win) {
|
|
20
|
+
this.#revision.update((v) => v + 1);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const id = win.requestAnimationFrame(() => this.#revision.update((v) => v + 1));
|
|
24
|
+
onCleanup(() => win.cancelAnimationFrame(id));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
refresh() {
|
|
28
|
+
this.#revision.update((v) => v + 1);
|
|
29
|
+
}
|
|
30
|
+
#buildTheme() {
|
|
31
|
+
const t = this.#tokens();
|
|
32
|
+
const isDark = this.#themeService.mode() === 'dark';
|
|
33
|
+
const isHighContrast = this.#themeService.currentTheme() === HIGH_CONTRAST_THEME_KEY;
|
|
34
|
+
const baseTheme = isDark ? 'ag-default-dark' : 'ag-default';
|
|
35
|
+
const palette = {
|
|
36
|
+
fills: [t.primary, t.success, t.warning, t.danger, t.brand].filter(Boolean),
|
|
37
|
+
strokes: [t.outline].filter(Boolean)
|
|
38
|
+
};
|
|
39
|
+
const fontFamily = t.fontFamily || 'Roboto, "Helvetica Neue", sans-serif';
|
|
40
|
+
return {
|
|
41
|
+
baseTheme,
|
|
42
|
+
palette,
|
|
43
|
+
overrides: {
|
|
44
|
+
common: {
|
|
45
|
+
background: { fill: t.surface || 'transparent' },
|
|
46
|
+
title: {
|
|
47
|
+
color: t.textColor,
|
|
48
|
+
fontFamily,
|
|
49
|
+
fontSize: 16,
|
|
50
|
+
fontWeight: 'bold'
|
|
51
|
+
},
|
|
52
|
+
subtitle: {
|
|
53
|
+
color: t.textColorSubtle,
|
|
54
|
+
fontFamily,
|
|
55
|
+
fontSize: 12
|
|
56
|
+
},
|
|
57
|
+
padding: { top: 16, right: 16, bottom: 16, left: 16 },
|
|
58
|
+
legend: {
|
|
59
|
+
item: {
|
|
60
|
+
label: {
|
|
61
|
+
color: t.textColor,
|
|
62
|
+
fontFamily,
|
|
63
|
+
fontSize: 12
|
|
64
|
+
},
|
|
65
|
+
marker: {
|
|
66
|
+
strokeWidth: isHighContrast ? 2 : 0
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
axes: {
|
|
71
|
+
number: this.#axisTheme(t, fontFamily),
|
|
72
|
+
category: this.#axisTheme(t, fontFamily),
|
|
73
|
+
time: this.#axisTheme(t, fontFamily),
|
|
74
|
+
log: this.#axisTheme(t, fontFamily)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
#axisTheme(themeToken, fontFamily) {
|
|
81
|
+
return {
|
|
82
|
+
line: { stroke: themeToken.outlineVariant },
|
|
83
|
+
tick: { stroke: themeToken.outlineVariant },
|
|
84
|
+
label: {
|
|
85
|
+
color: themeToken.textColorSubtle,
|
|
86
|
+
fontFamily,
|
|
87
|
+
fontSize: 11
|
|
88
|
+
},
|
|
89
|
+
title: {
|
|
90
|
+
color: themeToken.textColor,
|
|
91
|
+
fontFamily,
|
|
92
|
+
fontSize: 12
|
|
93
|
+
},
|
|
94
|
+
gridLine: {
|
|
95
|
+
style: [{ stroke: themeToken.outlineVariant, lineDash: [] }]
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
#tokens() {
|
|
100
|
+
const win = this.#document.defaultView;
|
|
101
|
+
const body = this.#document.body;
|
|
102
|
+
if (!win || !body) {
|
|
103
|
+
return EMPTY_TOKENS;
|
|
104
|
+
}
|
|
105
|
+
const probe = this.#document.createElement('span');
|
|
106
|
+
probe.style.position = 'absolute';
|
|
107
|
+
probe.style.visibility = 'hidden';
|
|
108
|
+
probe.style.pointerEvents = 'none';
|
|
109
|
+
body.appendChild(probe);
|
|
110
|
+
try {
|
|
111
|
+
const resolveColor = (token) => {
|
|
112
|
+
probe.style.color = '';
|
|
113
|
+
probe.style.color = `var(${token})`;
|
|
114
|
+
return win.getComputedStyle(probe).color || '';
|
|
115
|
+
};
|
|
116
|
+
const resolveProp = (token, prop) => {
|
|
117
|
+
probe.style.fontFamily = '';
|
|
118
|
+
probe.style.fontFamily = `var(${token})`;
|
|
119
|
+
return win.getComputedStyle(probe)[prop] || '';
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
surface: resolveColor('--ymt-surface'),
|
|
123
|
+
textColor: resolveColor('--ymt-text-color'),
|
|
124
|
+
textColorSubtle: resolveColor('--ymt-text-color-subtle'),
|
|
125
|
+
primary: resolveColor('--ymt-primary'),
|
|
126
|
+
brand: resolveColor('--ymt-brand'),
|
|
127
|
+
success: resolveColor('--ymt-success'),
|
|
128
|
+
warning: resolveColor('--ymt-warning'),
|
|
129
|
+
danger: resolveColor('--ymt-danger'),
|
|
130
|
+
outline: resolveColor('--ymt-outline'),
|
|
131
|
+
outlineVariant: resolveColor('--ymt-outline-variant'),
|
|
132
|
+
fontFamily: resolveProp('--mat-sys-body-medium-font', 'fontFamily')
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
body.removeChild(probe);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: YuvChartThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
140
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: YuvChartThemeService, providedIn: 'root' });
|
|
141
|
+
}
|
|
142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: YuvChartThemeService, decorators: [{
|
|
143
|
+
type: Injectable,
|
|
144
|
+
args: [{ providedIn: 'root' }]
|
|
145
|
+
}], ctorParameters: () => [] });
|
|
146
|
+
const EMPTY_TOKENS = {
|
|
147
|
+
surface: '',
|
|
148
|
+
textColor: '',
|
|
149
|
+
textColorSubtle: '',
|
|
150
|
+
primary: '',
|
|
151
|
+
brand: '',
|
|
152
|
+
success: '',
|
|
153
|
+
warning: '',
|
|
154
|
+
danger: '',
|
|
155
|
+
outline: '',
|
|
156
|
+
outlineVariant: '',
|
|
157
|
+
fontFamily: ''
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Wrapper component around AG Charts that automatically applies the
|
|
162
|
+
* application's chart theme based on the current UI theme (light, dark,
|
|
163
|
+
* high-contrast). Consumers provide standard AG Charts options and may
|
|
164
|
+
* optionally override the theme.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```html
|
|
168
|
+
* <yuv-chart [options]="chartOptions" />
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
class YuvChartComponent {
|
|
172
|
+
themeService = inject(YuvChartThemeService);
|
|
173
|
+
/** AG Charts configuration (data, series, axes, etc.). */
|
|
174
|
+
options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
175
|
+
/**
|
|
176
|
+
* Optional theme override. When provided, takes precedence over the
|
|
177
|
+
* theme resolved by {@link YuvChartThemeService} from the current UI mode.
|
|
178
|
+
*/
|
|
179
|
+
theme = input(undefined, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
180
|
+
/**
|
|
181
|
+
* Final options passed to AG Charts: the user-supplied {@link options}
|
|
182
|
+
* merged with either the explicit {@link theme} input or the theme
|
|
183
|
+
* derived from the active UI mode.
|
|
184
|
+
*/
|
|
185
|
+
mergedOptions = computed(() => {
|
|
186
|
+
const userOptions = this.options();
|
|
187
|
+
const userTheme = this.theme();
|
|
188
|
+
return {
|
|
189
|
+
...userOptions,
|
|
190
|
+
theme: userTheme ?? this.themeService.chartTheme()
|
|
191
|
+
};
|
|
192
|
+
}, ...(ngDevMode ? [{ debugName: "mergedOptions" }] : /* istanbul ignore next */ []));
|
|
193
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: YuvChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
194
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: YuvChartComponent, isStandalone: true, selector: "yuv-chart", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ag-charts [options]=\"mergedOptions()\" />\n", styles: [":host{display:block;width:100%;height:100%;min-height:200px;background:var(--ymt-surface);color:var(--ymt-text-color);border-radius:var(--ymt-corner-s);font:var(--ymt-font-body);overflow:hidden}ag-charts{display:block;width:100%;height:100%}:host ::ng-deep .ag-charts-tooltip{background:var(--ymt-surface-container);color:var(--ymt-on-surface);border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-xs);box-shadow:0 4px 12px #0000001f;font:var(--ymt-font-body-subtle);padding:var(--ymt-spacing-2xs) var(--ymt-spacing-xs)}:host ::ng-deep .ag-charts-tooltip-heading{background:var(--ymt-surface-container-high);color:var(--ymt-on-surface);border-bottom:1px solid var(--ymt-outline-variant);padding:var(--ymt-spacing-2xs) var(--ymt-spacing-xs)}\n"], dependencies: [{ kind: "component", type: AgCharts, selector: "ag-charts", inputs: ["options"], outputs: ["onChartReady"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
195
|
+
}
|
|
196
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: YuvChartComponent, decorators: [{
|
|
197
|
+
type: Component,
|
|
198
|
+
args: [{ selector: 'yuv-chart', standalone: true, imports: [AgCharts], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ag-charts [options]=\"mergedOptions()\" />\n", styles: [":host{display:block;width:100%;height:100%;min-height:200px;background:var(--ymt-surface);color:var(--ymt-text-color);border-radius:var(--ymt-corner-s);font:var(--ymt-font-body);overflow:hidden}ag-charts{display:block;width:100%;height:100%}:host ::ng-deep .ag-charts-tooltip{background:var(--ymt-surface-container);color:var(--ymt-on-surface);border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-xs);box-shadow:0 4px 12px #0000001f;font:var(--ymt-font-body-subtle);padding:var(--ymt-spacing-2xs) var(--ymt-spacing-xs)}:host ::ng-deep .ag-charts-tooltip-heading{background:var(--ymt-surface-container-high);color:var(--ymt-on-surface);border-bottom:1px solid var(--ymt-outline-variant);padding:var(--ymt-spacing-2xs) var(--ymt-spacing-xs)}\n"] }]
|
|
199
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }] } });
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Generated bundle index. Do not edit.
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
export { YuvChartComponent, YuvChartThemeService };
|
|
206
|
+
//# sourceMappingURL=yuuvis-client-components-charts.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yuuvis-client-components-charts.mjs","sources":["../../../../../libs/yuuvis/client-components/charts/src/lib/chart-theme.service.ts","../../../../../libs/yuuvis/client-components/charts/src/lib/chart.component.ts","../../../../../libs/yuuvis/client-components/charts/src/lib/chart.component.html","../../../../../libs/yuuvis/client-components/charts/src/yuuvis-client-components-charts.ts"],"sourcesContent":["import { computed, DOCUMENT, effect, inject, Injectable, signal } from '@angular/core';\nimport { HIGH_CONTRAST_THEME_KEY, ThemeService } from '@yuuvis/client-components/common';\nimport type { AgChartTheme } from 'ag-charts-community';\n\n@Injectable({ providedIn: 'root' })\nexport class YuvChartThemeService {\n readonly #document = inject(DOCUMENT);\n readonly #themeService = inject(ThemeService);\n\n readonly #revision = signal(0);\n\n readonly chartTheme = computed<AgChartTheme>(() => {\n this.#revision();\n return this.#buildTheme();\n });\n\n constructor() {\n effect((onCleanup) => {\n this.#themeService.mode();\n this.#themeService.currentTheme();\n const win = this.#document.defaultView;\n if (!win) {\n this.#revision.update((v) => v + 1);\n return;\n }\n const id = win.requestAnimationFrame(() => this.#revision.update((v) => v + 1));\n onCleanup(() => win.cancelAnimationFrame(id));\n });\n }\n\n refresh(): void {\n this.#revision.update((v) => v + 1);\n }\n\n #buildTheme(): AgChartTheme {\n const t = this.#tokens();\n const isDark = this.#themeService.mode() === 'dark';\n const isHighContrast = this.#themeService.currentTheme() === HIGH_CONTRAST_THEME_KEY;\n const baseTheme: 'ag-default' | 'ag-default-dark' = isDark ? 'ag-default-dark' : 'ag-default';\n\n const palette = {\n fills: [t.primary, t.success, t.warning, t.danger, t.brand].filter(Boolean) as string[],\n strokes: [t.outline].filter(Boolean) as string[]\n };\n\n const fontFamily = t.fontFamily || 'Roboto, \"Helvetica Neue\", sans-serif';\n\n return {\n baseTheme,\n palette,\n overrides: {\n common: {\n background: { fill: t.surface || 'transparent' },\n title: {\n color: t.textColor,\n fontFamily,\n fontSize: 16,\n fontWeight: 'bold'\n },\n subtitle: {\n color: t.textColorSubtle,\n fontFamily,\n fontSize: 12\n },\n padding: { top: 16, right: 16, bottom: 16, left: 16 },\n legend: {\n item: {\n label: {\n color: t.textColor,\n fontFamily,\n fontSize: 12\n },\n marker: {\n strokeWidth: isHighContrast ? 2 : 0\n }\n }\n },\n axes: {\n number: this.#axisTheme(t, fontFamily),\n category: this.#axisTheme(t, fontFamily),\n time: this.#axisTheme(t, fontFamily),\n log: this.#axisTheme(t, fontFamily)\n }\n }\n }\n };\n }\n\n #axisTheme(themeToken: ThemeTokens, fontFamily: string) {\n return {\n line: { stroke: themeToken.outlineVariant },\n tick: { stroke: themeToken.outlineVariant },\n label: {\n color: themeToken.textColorSubtle,\n fontFamily,\n fontSize: 11\n },\n title: {\n color: themeToken.textColor,\n fontFamily,\n fontSize: 12\n },\n gridLine: {\n style: [{ stroke: themeToken.outlineVariant, lineDash: [] }]\n }\n };\n }\n\n #tokens(): ThemeTokens {\n const win = this.#document.defaultView;\n const body = this.#document.body;\n if (!win || !body) {\n return EMPTY_TOKENS;\n }\n const probe = this.#document.createElement('span');\n probe.style.position = 'absolute';\n probe.style.visibility = 'hidden';\n probe.style.pointerEvents = 'none';\n body.appendChild(probe);\n try {\n const resolveColor = (token: string): string => {\n probe.style.color = '';\n probe.style.color = `var(${token})`;\n return win.getComputedStyle(probe).color || '';\n };\n const resolveProp = (token: string, prop: 'fontFamily'): string => {\n probe.style.fontFamily = '';\n probe.style.fontFamily = `var(${token})`;\n return win.getComputedStyle(probe)[prop] || '';\n };\n return {\n surface: resolveColor('--ymt-surface'),\n textColor: resolveColor('--ymt-text-color'),\n textColorSubtle: resolveColor('--ymt-text-color-subtle'),\n primary: resolveColor('--ymt-primary'),\n brand: resolveColor('--ymt-brand'),\n success: resolveColor('--ymt-success'),\n warning: resolveColor('--ymt-warning'),\n danger: resolveColor('--ymt-danger'),\n outline: resolveColor('--ymt-outline'),\n outlineVariant: resolveColor('--ymt-outline-variant'),\n fontFamily: resolveProp('--mat-sys-body-medium-font', 'fontFamily')\n };\n } finally {\n body.removeChild(probe);\n }\n }\n}\n\ninterface ThemeTokens {\n surface: string;\n textColor: string;\n textColorSubtle: string;\n primary: string;\n brand: string;\n success: string;\n warning: string;\n danger: string;\n outline: string;\n outlineVariant: string;\n fontFamily: string;\n}\n\nconst EMPTY_TOKENS: ThemeTokens = {\n surface: '',\n textColor: '',\n textColorSubtle: '',\n primary: '',\n brand: '',\n success: '',\n warning: '',\n danger: '',\n outline: '',\n outlineVariant: '',\n fontFamily: ''\n};\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { AgCharts } from 'ag-charts-angular';\nimport type { AgChartOptions, AgChartTheme } from 'ag-charts-community';\nimport { YuvChartThemeService } from './chart-theme.service';\nimport { YuvChartOptions } from './chart.types';\n\n/**\n * Wrapper component around AG Charts that automatically applies the\n * application's chart theme based on the current UI theme (light, dark,\n * high-contrast). Consumers provide standard AG Charts options and may\n * optionally override the theme.\n *\n * @example\n * ```html\n * <yuv-chart [options]=\"chartOptions\" />\n * ```\n */\n@Component({\n selector: 'yuv-chart',\n standalone: true,\n imports: [AgCharts],\n templateUrl: './chart.component.html',\n styleUrl: './chart.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class YuvChartComponent {\n private readonly themeService = inject(YuvChartThemeService);\n\n /** AG Charts configuration (data, series, axes, etc.). */\n readonly options = input.required<YuvChartOptions>();\n\n /**\n * Optional theme override. When provided, takes precedence over the\n * theme resolved by {@link YuvChartThemeService} from the current UI mode.\n */\n readonly theme = input<AgChartTheme | string | undefined>(undefined);\n\n /**\n * Final options passed to AG Charts: the user-supplied {@link options}\n * merged with either the explicit {@link theme} input or the theme\n * derived from the active UI mode.\n */\n protected readonly mergedOptions = computed<AgChartOptions>(() => {\n const userOptions = this.options();\n const userTheme = this.theme();\n return {\n ...userOptions,\n theme: userTheme ?? this.themeService.chartTheme()\n } as AgChartOptions;\n });\n}\n","<ag-charts [options]=\"mergedOptions()\" />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1074,7 +1074,10 @@ class ScrollButtonsDirective {
|
|
|
1074
1074
|
color: 'var(--ymt-text-color-subtle)',
|
|
1075
1075
|
width: 'var(--ymt-sizing-m)',
|
|
1076
1076
|
height: 'var(--ymt-sizing-m)',
|
|
1077
|
-
backgroundColor: 'var(--ymt-surface-hover)'
|
|
1077
|
+
backgroundColor: 'var(--ymt-surface-hover)',
|
|
1078
|
+
// Stay clickable even when wrapped in a disabled <mat-form-field>,
|
|
1079
|
+
// which sets pointer-events: none on its interior.
|
|
1080
|
+
'pointer-events': 'auto'
|
|
1078
1081
|
});
|
|
1079
1082
|
const iconEl = this.#renderer.createElement('span');
|
|
1080
1083
|
iconEl.classList.add('material-symbols-sharp');
|
|
@@ -1440,6 +1443,53 @@ class ThemeService {
|
|
|
1440
1443
|
constructor() {
|
|
1441
1444
|
this.#initializeModes();
|
|
1442
1445
|
}
|
|
1446
|
+
setMode(mode) {
|
|
1447
|
+
this.#saveSettings(this.#MODE_STORAGE_KEY, { mode });
|
|
1448
|
+
}
|
|
1449
|
+
setCustomTheme(key) {
|
|
1450
|
+
// Reset contrast to system on custom theme change
|
|
1451
|
+
const previousTheme = this.customTheme();
|
|
1452
|
+
const body = this.#document.getElementsByTagName('body')[0];
|
|
1453
|
+
if (previousTheme?.key)
|
|
1454
|
+
this.#renderer.removeClass(body, previousTheme.key);
|
|
1455
|
+
const selectedTheme = this.customThemes().find((theme) => theme.key === key);
|
|
1456
|
+
if (selectedTheme) {
|
|
1457
|
+
this.customTheme.set(selectedTheme);
|
|
1458
|
+
this.#currentTheme.set(selectedTheme.key);
|
|
1459
|
+
if (selectedTheme.key)
|
|
1460
|
+
this.#renderer.addClass(body, selectedTheme.key);
|
|
1461
|
+
// Check if custom theme has light or dark mode
|
|
1462
|
+
if ((selectedTheme.hasDarkTheme && selectedTheme.hasLightTheme) ||
|
|
1463
|
+
(!selectedTheme.hasDarkTheme && !selectedTheme.hasLightTheme)) {
|
|
1464
|
+
// If both, do nothing further with this (enable group)
|
|
1465
|
+
this.#disableMode.set(false);
|
|
1466
|
+
}
|
|
1467
|
+
else {
|
|
1468
|
+
// Else disable mode button group and set the corresponding mode active
|
|
1469
|
+
if (selectedTheme.hasDarkTheme) {
|
|
1470
|
+
this.#mode.set('dark');
|
|
1471
|
+
}
|
|
1472
|
+
else if (selectedTheme.hasLightTheme) {
|
|
1473
|
+
this.#mode.set('light');
|
|
1474
|
+
}
|
|
1475
|
+
this.#disableMode.set(true);
|
|
1476
|
+
}
|
|
1477
|
+
this.#saveSettings(this.#CUSTOM_THEME_STORAGE_KEY, { customTheme: key });
|
|
1478
|
+
}
|
|
1479
|
+
else {
|
|
1480
|
+
if (key === DEFAULT_THEME_KEY) {
|
|
1481
|
+
this.#disableMode.set(false);
|
|
1482
|
+
this.#renderer.removeClass(body, HIGH_CONTRAST_THEME_KEY);
|
|
1483
|
+
this.#deleteSettings(this.#CUSTOM_THEME_STORAGE_KEY);
|
|
1484
|
+
this.customTheme.set(DEFAULT_THEME);
|
|
1485
|
+
this.#currentTheme.set(DEFAULT_THEME_KEY);
|
|
1486
|
+
}
|
|
1487
|
+
// Default theme or no theme found
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
toggleTheme(theme) {
|
|
1491
|
+
this.#mode.set(theme);
|
|
1492
|
+
}
|
|
1443
1493
|
#saveSettings(key, settings) {
|
|
1444
1494
|
if (typeof settings === 'object') {
|
|
1445
1495
|
this.#storage.setItem(key, JSON.stringify(settings)).subscribe();
|
|
@@ -1454,16 +1504,21 @@ class ThemeService {
|
|
|
1454
1504
|
}
|
|
1455
1505
|
#checkPrefersContrast() {
|
|
1456
1506
|
const prefersHighContrast = window.matchMedia('(prefers-contrast: more)').matches;
|
|
1507
|
+
return prefersHighContrast;
|
|
1457
1508
|
}
|
|
1458
1509
|
#initializeModes() {
|
|
1459
1510
|
// Theme initialization
|
|
1460
|
-
forkJoin([
|
|
1511
|
+
forkJoin([
|
|
1512
|
+
this.#storage.getItem(this.#MODE_STORAGE_KEY),
|
|
1513
|
+
this.#storage.getItem(this.#CUSTOM_THEME_STORAGE_KEY)
|
|
1514
|
+
])
|
|
1461
1515
|
.pipe(map$1(([savedTheme, savedCustomTheme]) => {
|
|
1462
1516
|
if (savedTheme) {
|
|
1463
1517
|
try {
|
|
1464
1518
|
this.#mode.set(JSON.parse(savedTheme).mode);
|
|
1465
1519
|
}
|
|
1466
1520
|
catch (error) {
|
|
1521
|
+
console.error('Error parsing saved theme mode from storage:', error);
|
|
1467
1522
|
this.#mode.set(this.#mode());
|
|
1468
1523
|
}
|
|
1469
1524
|
}
|
|
@@ -1480,54 +1535,12 @@ class ThemeService {
|
|
|
1480
1535
|
this.setCustomTheme(customThemeKey);
|
|
1481
1536
|
}
|
|
1482
1537
|
catch (error) {
|
|
1483
|
-
|
|
1538
|
+
console.error('Error parsing saved custom theme from storage:', error);
|
|
1484
1539
|
}
|
|
1485
1540
|
}
|
|
1486
1541
|
}))
|
|
1487
1542
|
.subscribe();
|
|
1488
1543
|
}
|
|
1489
|
-
setMode(mode) {
|
|
1490
|
-
this.#saveSettings(this.#MODE_STORAGE_KEY, { mode });
|
|
1491
|
-
}
|
|
1492
|
-
setCustomTheme(key) {
|
|
1493
|
-
// Reset contrast to system on custom theme change
|
|
1494
|
-
const previousTheme = this.customTheme();
|
|
1495
|
-
const body = this.#document.getElementsByTagName('body')[0];
|
|
1496
|
-
previousTheme && previousTheme.key && this.#renderer.removeClass(body, previousTheme.key);
|
|
1497
|
-
const selectedTheme = this.customThemes().find((theme) => theme.key === key);
|
|
1498
|
-
if (selectedTheme) {
|
|
1499
|
-
this.customTheme.set(selectedTheme);
|
|
1500
|
-
this.#currentTheme.set(selectedTheme.key);
|
|
1501
|
-
selectedTheme.key && this.#renderer.addClass(body, selectedTheme.key);
|
|
1502
|
-
// Check if custom theme has light or dark mode
|
|
1503
|
-
if ((selectedTheme.hasDarkTheme && selectedTheme.hasLightTheme) || (!selectedTheme.hasDarkTheme && !selectedTheme.hasLightTheme)) {
|
|
1504
|
-
// If both, do nothing further with this (enable group)
|
|
1505
|
-
this.#disableMode.set(false);
|
|
1506
|
-
}
|
|
1507
|
-
else {
|
|
1508
|
-
// Else disable mode button group and set the corresponding mode active
|
|
1509
|
-
if (selectedTheme.hasDarkTheme) {
|
|
1510
|
-
this.#mode.set('dark');
|
|
1511
|
-
}
|
|
1512
|
-
else if (selectedTheme.hasLightTheme) {
|
|
1513
|
-
this.#mode.set('light');
|
|
1514
|
-
}
|
|
1515
|
-
this.#disableMode.set(true);
|
|
1516
|
-
}
|
|
1517
|
-
this.#saveSettings(this.#CUSTOM_THEME_STORAGE_KEY, { customTheme: key });
|
|
1518
|
-
}
|
|
1519
|
-
else {
|
|
1520
|
-
if (key === DEFAULT_THEME_KEY) {
|
|
1521
|
-
this.#disableMode.set(false);
|
|
1522
|
-
this.#renderer.removeClass(body, HIGH_CONTRAST_THEME_KEY);
|
|
1523
|
-
this.#deleteSettings(this.#CUSTOM_THEME_STORAGE_KEY);
|
|
1524
|
-
}
|
|
1525
|
-
// Default theme or no theme found
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
toggleTheme(theme) {
|
|
1529
|
-
this.#mode.set(theme);
|
|
1530
|
-
}
|
|
1531
1544
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1532
1545
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ThemeService, providedIn: 'root' });
|
|
1533
1546
|
}
|