@bryntum/chart-angular-thin 7.2.3 → 7.3.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/bundles/bryntum-chart-angular-thin.umd.js +150 -29
- package/bundles/bryntum-chart-angular-thin.umd.js.map +1 -1
- package/esm2015/lib/bryntum-chart.component.js +61 -21
- package/esm2015/lib/chart.module.js +5 -4
- package/esm2015/lib/shadowdom.helper.js +82 -0
- package/fesm2015/bryntum-chart-angular-thin.js +145 -24
- package/fesm2015/bryntum-chart-angular-thin.js.map +1 -1
- package/lib/bryntum-chart.component.d.ts +91 -147
- package/lib/chart.module.d.ts +2 -1
- package/lib/shadowdom.helper.d.ts +3 -0
- package/package.json +1 -1
- package/src/lib/bryntum-chart.component.ts +147 -155
- package/src/lib/bryntum-theme-combo.component.ts +128 -0
- package/src/lib/chart.module.ts +2 -1
- package/src/lib/shadowdom.helper.ts +91 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular wrapper for Bryntum Theme combo
|
|
3
|
+
*/
|
|
4
|
+
import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
|
|
5
|
+
import { BrowserHelper, Combo, DomHelper, Store, StoreConfig } from '@bryntum/core-thin';
|
|
6
|
+
import { initThemeInShadowRoots, registerShadowRoot, unregisterShadowRoot } from './shadowdom.helper';
|
|
7
|
+
|
|
8
|
+
const defaultThemes: Record<string, string> = {
|
|
9
|
+
'material3-light' : 'Material3 Light',
|
|
10
|
+
'material3-dark' : 'Material3 Dark',
|
|
11
|
+
'stockholm-light' : 'Stockholm Light',
|
|
12
|
+
'stockholm-dark' : 'Stockholm Dark',
|
|
13
|
+
'svalbard-light' : 'Svalbard Light',
|
|
14
|
+
'svalbard-dark' : 'Svalbard Dark',
|
|
15
|
+
'visby-light' : 'Visby Light',
|
|
16
|
+
'visby-dark' : 'Visby Dark',
|
|
17
|
+
'fluent2-light' : 'Fluent2 Light',
|
|
18
|
+
'fluent2-dark' : 'Fluent2 Dark',
|
|
19
|
+
'high-contrast-light' : 'High Contrast Light',
|
|
20
|
+
'high-contrast-dark' : 'High Contrast Dark'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const syncedProps = ['store', 'label', 'width'] as const;
|
|
24
|
+
|
|
25
|
+
export type BryntumThemeComboProps = {
|
|
26
|
+
store?: Store | StoreConfig | object;
|
|
27
|
+
label?: string;
|
|
28
|
+
width?: string | number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
@Component({
|
|
32
|
+
selector : 'bryntum-theme-combo',
|
|
33
|
+
template : ''
|
|
34
|
+
})
|
|
35
|
+
export class BryntumThemeComboComponent implements OnInit, OnChanges, OnDestroy {
|
|
36
|
+
|
|
37
|
+
private elementRef: ElementRef;
|
|
38
|
+
private combo!: Combo;
|
|
39
|
+
|
|
40
|
+
@Input() store?: Store | StoreConfig | object;
|
|
41
|
+
@Input() label?: string;
|
|
42
|
+
@Input() width?: string | number;
|
|
43
|
+
|
|
44
|
+
constructor(element: ElementRef) {
|
|
45
|
+
this.elementRef = element;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Initializes the component and creates the Bryntum Combo widget
|
|
50
|
+
*/
|
|
51
|
+
ngOnInit(): void {
|
|
52
|
+
const shadowRoot = this.elementRef.nativeElement.getRootNode();
|
|
53
|
+
if (shadowRoot instanceof ShadowRoot) {
|
|
54
|
+
registerShadowRoot(shadowRoot);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.combo = new Combo({
|
|
58
|
+
appendTo : this.elementRef.nativeElement,
|
|
59
|
+
...(this.store ? { store : this.store } : { items : defaultThemes }),
|
|
60
|
+
label : this.label ?? 'Theme',
|
|
61
|
+
width : this.width ?? '16em',
|
|
62
|
+
value : 'material3-light',
|
|
63
|
+
editable : false,
|
|
64
|
+
labelPosition : 'before',
|
|
65
|
+
ref : 'themeCombo',
|
|
66
|
+
listeners : {
|
|
67
|
+
change({ value }) {
|
|
68
|
+
DomHelper.setTheme(value).then(context => {
|
|
69
|
+
if (context) {
|
|
70
|
+
// Remove all b-theme-* classes — don't rely on context.prev which may
|
|
71
|
+
// be stale (CSS vars unreadable in Angular ViewEncapsulation.ShadowDom)
|
|
72
|
+
Array.from(document.body.classList)
|
|
73
|
+
.filter(cls => cls.startsWith('b-theme-'))
|
|
74
|
+
.forEach(cls => document.body.classList.remove(cls));
|
|
75
|
+
document.body.classList.add(`b-theme-${context.theme}`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Apply theme from URL search param (?theme=xxx), detect from loaded CSS, or read from link href
|
|
83
|
+
const
|
|
84
|
+
themeLink = document.querySelector<HTMLLinkElement>('link[data-bryntum-theme]'),
|
|
85
|
+
themeFromHref = themeLink ? new URL(themeLink.href).pathname.split('/').pop()?.replace('.css', '') : '',
|
|
86
|
+
theme = BrowserHelper.searchParam('theme') || DomHelper.getThemeInfo()?.filename || themeFromHref;
|
|
87
|
+
|
|
88
|
+
if (theme) {
|
|
89
|
+
this.combo.value = theme;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`Set: .b-theme-${this.combo.value as string}`);
|
|
93
|
+
// Always set the initial body class — even when theme detection falls back to the
|
|
94
|
+
// combo's default value (CSS vars may be unreadable in shadow DOM contexts)
|
|
95
|
+
document.body.classList.add(`b-theme-${this.combo.value as string}`);
|
|
96
|
+
|
|
97
|
+
initThemeInShadowRoots();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Responds to Input property changes and updates the Combo widget accordingly
|
|
102
|
+
*/
|
|
103
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
104
|
+
const { combo } = this;
|
|
105
|
+
if (!combo) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const prop of syncedProps) {
|
|
109
|
+
if (prop in changes) {
|
|
110
|
+
(combo as any)[prop] = changes[prop].currentValue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Destroys the component and the underlying Combo widget
|
|
117
|
+
*/
|
|
118
|
+
ngOnDestroy(): void {
|
|
119
|
+
const shadowRoot = this.elementRef.nativeElement.getRootNode();
|
|
120
|
+
if (shadowRoot instanceof ShadowRoot) {
|
|
121
|
+
unregisterShadowRoot(shadowRoot);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (this.combo) {
|
|
125
|
+
this.combo.destroy();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
package/src/lib/chart.module.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Angular Bryntum Chart Shared module
|
|
3
3
|
*/
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
4
5
|
import { NgModule } from '@angular/core';
|
|
5
6
|
|
|
6
7
|
import { BryntumChartComponent } from './bryntum-chart.component';
|
|
@@ -10,7 +11,7 @@ import { BryntumChartComponent } from './bryntum-chart.component';
|
|
|
10
11
|
|
|
11
12
|
BryntumChartComponent
|
|
12
13
|
],
|
|
13
|
-
imports : [],
|
|
14
|
+
imports : [CommonModule],
|
|
14
15
|
exports : [
|
|
15
16
|
|
|
16
17
|
BryntumChartComponent
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { GlobalEvents } from '@bryntum/core-thin';
|
|
2
|
+
|
|
3
|
+
// Module-level registry of all open shadow roots that host Bryntum widgets.
|
|
4
|
+
// Populated lazily by collectOpenShadowRoots() the first time it is called, and
|
|
5
|
+
// kept up to date via registerShadowRoot / unregisterShadowRoot.
|
|
6
|
+
const openShadowRoots = new Set<ShadowRoot>();
|
|
7
|
+
|
|
8
|
+
// Walks the DOM tree starting from `root` and collects every open shadow root found.
|
|
9
|
+
// Results are cached in openShadowRoots after the first traversal so subsequent calls
|
|
10
|
+
// are O(1). Recursive so nested shadow roots are also discovered.
|
|
11
|
+
function collectOpenShadowRoots(root : Document | ShadowRoot = document) : ShadowRoot[] {
|
|
12
|
+
if (openShadowRoots.size > 0) {
|
|
13
|
+
return Array.from(openShadowRoots);
|
|
14
|
+
}
|
|
15
|
+
const roots : ShadowRoot[] = [];
|
|
16
|
+
Array.from(root.querySelectorAll('*')).forEach(el => {
|
|
17
|
+
if ((el as Element & { shadowRoot? : ShadowRoot }).shadowRoot) {
|
|
18
|
+
roots.push((el as any).shadowRoot);
|
|
19
|
+
roots.push(...collectOpenShadowRoots((el as any).shadowRoot));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
roots.forEach(r => openShadowRoots.add(r));
|
|
23
|
+
return roots;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Updates the href and data-bryntum-theme attribute of every theme <link> inside all
|
|
27
|
+
// registered shadow roots to mirror the new head link after a theme change.
|
|
28
|
+
function syncThemeToShadowRoots(headLink : HTMLLinkElement) : void {
|
|
29
|
+
const href = headLink.href;
|
|
30
|
+
const themeAttr = headLink.getAttribute('data-bryntum-theme') ?? '';
|
|
31
|
+
|
|
32
|
+
collectOpenShadowRoots().forEach(shadowRoot => {
|
|
33
|
+
Array.from(shadowRoot.querySelectorAll<HTMLLinkElement>('link[data-bryntum-theme]')).forEach(link => {
|
|
34
|
+
link.setAttribute('data-bryntum-theme', themeAttr);
|
|
35
|
+
link.href = href;
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Adds a shadow root to the registry so it is included in theme sync operations.
|
|
41
|
+
// Called by BryntumThemeComboComponent.ngOnInit when it detects it is inside a shadow root.
|
|
42
|
+
export function registerShadowRoot(shadowRoot : ShadowRoot) : void {
|
|
43
|
+
openShadowRoots.add(shadowRoot);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Removes a shadow root from the registry.
|
|
47
|
+
// Called by BryntumThemeComboComponent.ngOnDestroy to clean up on component teardown.
|
|
48
|
+
export function unregisterShadowRoot(shadowRoot : ShadowRoot) : void {
|
|
49
|
+
openShadowRoots.delete(shadowRoot);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Injects a clone of each document.head theme <link> into every registered shadow root
|
|
53
|
+
// that does not already have one. This is required because CSS from document.head does
|
|
54
|
+
// not cascade into shadow DOM, so Bryntum theme styles would be absent without this.
|
|
55
|
+
// Safe to call multiple times — the presence check prevents duplicate injection.
|
|
56
|
+
export function initThemeInShadowRoots() : void {
|
|
57
|
+
const headThemeLinks = Array.from(document.head.querySelectorAll<HTMLLinkElement>('link[data-bryntum-theme]'));
|
|
58
|
+
|
|
59
|
+
if (!headThemeLinks.length) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
collectOpenShadowRoots().forEach(shadowRoot => {
|
|
64
|
+
if (shadowRoot.querySelector('link[data-bryntum-theme]')) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
headThemeLinks.forEach(headLink => {
|
|
69
|
+
if (!headLink.href) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Clone the head link to preserve all attributes, then ensure absolute href
|
|
73
|
+
const clone = headLink.cloneNode() as HTMLLinkElement;
|
|
74
|
+
clone.href = headLink.href;
|
|
75
|
+
shadowRoot.appendChild(clone);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Listens for Bryntum's internal theme-change event and keeps every shadow root's
|
|
81
|
+
// theme link in sync with the new document.head link. Fires after the old <link>s
|
|
82
|
+
// are removed and the new one is fully loaded in document.head.
|
|
83
|
+
// @ts-ignore - ion() is public but not present on GlobalEventsSingleton typings
|
|
84
|
+
GlobalEvents.ion({
|
|
85
|
+
theme() : void {
|
|
86
|
+
const link = document.head.querySelector<HTMLLinkElement>('link[data-bryntum-theme]');
|
|
87
|
+
if (link?.href) {
|
|
88
|
+
syncThemeToShadowRoots(link);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|