@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
112 lines (109 loc) • 4.57 kB
JavaScript
export class ThemeService {
constructor(api) {
this.unsubscribe = () => { };
this.onThemeChanged = () => {
let currentTheme = this.api.themeApi.getCurrentThemeObject();
currentTheme = this.mapOsTheme(currentTheme);
this.applyNewThemeVariables(currentTheme);
// this needs to be called after variables are set
// as it may show the warning for a custom/runtime theme
this.showMissingThemeFiles(currentTheme);
};
this.api = api;
this.subscribe();
if (!this.styleSheetObject) {
this.styleSheetObject = new CSSStyleSheet();
// ts does not know about adoptedStyleSheets
document.adoptedStyleSheets = [
...(document.adoptedStyleSheets ?? []),
this.styleSheetObject,
];
}
}
destroy() {
this.api = null;
this.unsubscribe();
document.adoptedStyleSheets = [...document.adoptedStyleSheets].filter((sheet) => sheet !== this.styleSheetObject);
}
subscribe() {
const themeChangedUnsubscribe = this.api.eventApi.on('ThemeChanged', this.onThemeChanged);
const prefferedColorSchemeUnsubscribe = this.attachPrefferedColorSchemeListener();
this.unsubscribe = () => {
themeChangedUnsubscribe();
prefferedColorSchemeUnsubscribe();
};
}
applyNewThemeVariables(theme) {
const variables = theme.CSSVariables;
if (!variables || Object.keys(variables).length === 0) {
return;
}
let str = `html.${this.api.themeApi.internalApi.getThemeClassName(theme.Name)} {
--ab-theme-loaded: ab--theme-${theme.Name};
`;
for (const [key, value] of Object.entries(variables)) {
if (key.includes('--')) {
str += `${key}: ${value};`;
}
}
str += '}';
this.styleSheetObject.replaceSync(str);
}
showMissingThemeFiles(theme) {
// run time defined theme
// because it may be an empty theme
if (theme.Source === 'User') {
return;
}
const themeName = theme.Name;
const adaptable = this.api.internalApi.getAdaptableInstance();
const logger = adaptable.logger;
const documentElement = document.documentElement;
const computedDocumentStyle = getComputedStyle(documentElement);
const [abLoaded, abThemeLoaded] = ['--ab-loaded', '--ab-theme-loaded'].map((variable) => {
let val = computedDocumentStyle.getPropertyValue(variable);
if (typeof val === 'string' && val.trim) {
val = val.trim();
}
return val;
});
if (abLoaded !== '777') {
logger.consoleError('Please import Adaptable styles from "@adaptabletools/adaptable/index.css"');
}
const isCustomUserTheme = !this.api.themeApi.internalApi.isSystemTheme(themeName);
if (!isCustomUserTheme && abThemeLoaded !== themeName) {
logger.consoleWarn(`Theme "${themeName}" doesn't seem to be loaded! Make sure you import the css file for the "${themeName}" theme!
If it's an AdapTable system theme, try
import "@adaptabletools/adaptable/themes/${themeName}.css"`);
}
}
// prefers-color-scheme
getDOMPrefferedColorScheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
mapOsTheme(theme) {
theme = typeof theme === 'string' ? this.api.themeApi.getThemeByName(theme) : theme;
if ((typeof theme === 'string' && theme === 'os') ||
(typeof theme === 'object' && theme.Name === 'os')) {
return this.api.themeApi.getThemeByName(this.getDOMPrefferedColorScheme());
}
return theme;
}
attachPrefferedColorSchemeListener() {
const handlePrefferedColorSchemeChange = () => {
// we need to reapply the theme
const currentTheme = this.api.themeApi.getCurrentThemeObject();
if (currentTheme.Name === 'os') {
this.api.themeApi.applyCurrentTheme();
}
};
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', handlePrefferedColorSchemeChange);
return () => {
window
.matchMedia('(prefers-color-scheme: dark)')
.removeEventListener('change', handlePrefferedColorSchemeChange);
};
}
}