@descope/sdk-mixins
Version:
Descope JavaScript SDK mixins
175 lines (172 loc) • 12.1 kB
JavaScript
import { __classPrivateFieldGet, __classPrivateFieldSet } from 'tslib';
import { createSingletonMixin, compose } from '@descope/sdk-helpers';
import { configMixin } from '../configMixin/configMixin.js';
import { createValidateAttributesMixin } from '../createValidateAttributesMixin/createValidateAttributesMixin.js';
import { descopeUiMixin } from '../descopeUiMixin/descopeUiMixin.js';
import { initElementMixin } from '../initElementMixin.js';
import { initLifecycleMixin } from '../initLifecycleMixin.js';
import { staticResourcesMixin } from '../staticResourcesMixin/staticResourcesMixin.js';
import { DEFAULT_STYLE_ID } from './constants.js';
import { loadFont, loadDevTheme } from './helpers.js';
import { observeAttributesMixin } from '../observeAttributesMixin/observeAttributesMixin.js';
import { UI_COMPONENTS_URL_KEY } from '../descopeUiMixin/constants.js';
import { injectStyleMixin } from '../injectStyleMixin.js';
const themeValidation = (_, theme) => (theme || false) &&
theme !== 'light' &&
theme !== 'dark' &&
'Supported theme values are "light", "dark", or leave empty for using the OS theme';
const themeMixin = createSingletonMixin((superclass) => {
var _ThemeMixinClass_instances, _ThemeMixinClass_globalStyle, _ThemeMixinClass__themeResource, _ThemeMixinClass_fetchTheme, _ThemeMixinClass_themeResource_get, _ThemeMixinClass_loadGlobalStyle, _ThemeMixinClass_loadComponentsStyle, _ThemeMixinClass_getFontsConfig, _ThemeMixinClass_loadFonts, _ThemeMixinClass_applyTheme, _ThemeMixinClass_onThemeChange, _ThemeMixinClass_loadTheme, _ThemeMixinClass_toggleOsThemeChangeListener, _a;
const BaseClass = compose(createValidateAttributesMixin({ theme: themeValidation }), staticResourcesMixin, initLifecycleMixin, descopeUiMixin, configMixin, initElementMixin, observeAttributesMixin, injectStyleMixin)(superclass);
return _a = class ThemeMixinClass extends BaseClass {
constructor() {
super(...arguments);
_ThemeMixinClass_instances.add(this);
_ThemeMixinClass_globalStyle.set(this, void 0);
_ThemeMixinClass__themeResource.set(this, void 0);
_ThemeMixinClass_onThemeChange.set(this, () => {
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadTheme).call(this);
__classPrivateFieldGet(this, _ThemeMixinClass_toggleOsThemeChangeListener, "f").call(this, this.getAttribute('theme') === 'os');
});
// add or remove os theme change listener
_ThemeMixinClass_toggleOsThemeChangeListener.set(this, (listen) => {
var _b, _c, _d;
const method = listen ? 'addEventListener' : 'removeEventListener';
(_d = (_c = (_b = window
.matchMedia) === null || _b === void 0 ? void 0 : _b.call(window, '(prefers-color-scheme: dark)')) === null || _c === void 0 ? void 0 : _c[method]) === null || _d === void 0 ? void 0 : _d.call(_c, 'change', () => __classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadTheme).call(this));
});
}
get theme() {
var _b, _c;
const theme = this.getAttribute('theme');
if (theme === 'os') {
const isOsDark = window.matchMedia &&
((_c = (_b = window.matchMedia) === null || _b === void 0 ? void 0 : _b.call(window, '(prefers-color-scheme: dark)')) === null || _c === void 0 ? void 0 : _c.matches);
return isOsDark ? 'dark' : 'light';
}
return theme || 'light';
}
get styleId() {
return this.getAttribute('style-id') || DEFAULT_STYLE_ID;
}
async init() {
var _b;
await ((_b = super.init) === null || _b === void 0 ? void 0 : _b.call(this));
__classPrivateFieldGet(this, _ThemeMixinClass_onThemeChange, "f").call(this);
await Promise.all([
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadGlobalStyle).call(this),
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadComponentsStyle).call(this),
]);
this.observeAttributes(['theme'], __classPrivateFieldGet(this, _ThemeMixinClass_onThemeChange, "f"));
this.observeAttributes(['style-id'], () => {
__classPrivateFieldSet(this, _ThemeMixinClass__themeResource, null, "f");
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadFonts).call(this);
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadGlobalStyle).call(this);
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadComponentsStyle).call(this);
});
}
},
_ThemeMixinClass_globalStyle = new WeakMap(),
_ThemeMixinClass__themeResource = new WeakMap(),
_ThemeMixinClass_onThemeChange = new WeakMap(),
_ThemeMixinClass_toggleOsThemeChangeListener = new WeakMap(),
_ThemeMixinClass_instances = new WeakSet(),
_ThemeMixinClass_fetchTheme = async function _ThemeMixinClass_fetchTheme() {
try {
const { body: fetchedTheme } = await this.fetchStaticResource(`${this.styleId}.json`, 'json');
// In development mode, we sometimes want to override the UI components URL
// The override components might have a different theme, so we need to merge it with the project theme in order to see the components correctly
if (process.env.NODE_ENV === 'development') {
if (localStorage === null || localStorage === void 0 ? void 0 : localStorage.getItem(UI_COMPONENTS_URL_KEY)) {
try {
this.logger.warn('You are in DEV mode, and UI components override URL was found\ntrying to merge project theme with the default theme of the UI components');
const devTheme = await loadDevTheme();
if (devTheme) {
fetchedTheme.light.components = Object.assign(Object.assign({}, fetchedTheme.light.components), devTheme.light.components);
fetchedTheme.dark.components = Object.assign(Object.assign({}, fetchedTheme.dark.components), devTheme.dark.components);
this.logger.warn('Theme was merged successfully');
// eslint-disable-next-line no-console
console.log('%cNOTICE! This is not the theme that will be used in production!\n\nMake sure to test it without the override UI components URL!', 'color: black; background-color:yellow; font-size: x-large');
}
}
catch (e) {
this.logger.error('Failed to merge UI components theme\n', e);
}
}
}
return fetchedTheme;
}
catch (e) {
this.logger.error('Cannot fetch theme file', 'make sure that your projectId & flowId are correct');
}
return undefined;
},
_ThemeMixinClass_themeResource_get = function _ThemeMixinClass_themeResource_get() {
if (!__classPrivateFieldGet(this, _ThemeMixinClass__themeResource, "f")) {
__classPrivateFieldSet(this, _ThemeMixinClass__themeResource, __classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_fetchTheme).call(this), "f");
__classPrivateFieldGet(this, _ThemeMixinClass__themeResource, "f").then((theme) => this.logger.debug('Fetched theme', theme));
}
// eslint-disable-next-line no-underscore-dangle
return __classPrivateFieldGet(this, _ThemeMixinClass__themeResource, "f");
},
_ThemeMixinClass_loadGlobalStyle = async function _ThemeMixinClass_loadGlobalStyle() {
var _b, _c;
const theme = await __classPrivateFieldGet(this, _ThemeMixinClass_instances, "a", _ThemeMixinClass_themeResource_get);
if (!theme)
return;
if (!__classPrivateFieldGet(this, _ThemeMixinClass_globalStyle, "f")) {
__classPrivateFieldSet(this, _ThemeMixinClass_globalStyle, this.injectStyle(''), "f");
}
__classPrivateFieldGet(this, _ThemeMixinClass_globalStyle, "f").replaceSync((((_b = theme === null || theme === void 0 ? void 0 : theme.light) === null || _b === void 0 ? void 0 : _b.globals) || '') + (((_c = theme === null || theme === void 0 ? void 0 : theme.dark) === null || _c === void 0 ? void 0 : _c.globals) || ''));
},
_ThemeMixinClass_loadComponentsStyle = async function _ThemeMixinClass_loadComponentsStyle() {
var _b, _c;
const theme = await __classPrivateFieldGet(this, _ThemeMixinClass_instances, "a", _ThemeMixinClass_themeResource_get);
if (!theme)
return;
const descopeUi = await this.descopeUi;
if (descopeUi === null || descopeUi === void 0 ? void 0 : descopeUi.componentsThemeManager) {
descopeUi.componentsThemeManager.themes = {
light: (_b = theme === null || theme === void 0 ? void 0 : theme.light) === null || _b === void 0 ? void 0 : _b.components,
dark: (_c = theme === null || theme === void 0 ? void 0 : theme.dark) === null || _c === void 0 ? void 0 : _c.components,
};
}
},
_ThemeMixinClass_getFontsConfig = async function _ThemeMixinClass_getFontsConfig() {
var _b, _c;
const { projectConfig } = (await this.config) || {};
const newConfig = (_b = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.styles) === null || _b === void 0 ? void 0 : _b[this.styleId];
const oldConfig = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.cssTemplate;
const config = newConfig || oldConfig;
const fonts = (_c = config === null || config === void 0 ? void 0 : config[this.theme]) === null || _c === void 0 ? void 0 : _c.fonts;
return fonts;
},
_ThemeMixinClass_loadFonts = async function _ThemeMixinClass_loadFonts() {
const fonts = await __classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_getFontsConfig).call(this);
if (fonts) {
Object.values(fonts).forEach((font) => {
if (font.url) {
this.logger.debug(`Loading font from URL "${font.url}"`);
loadFont(font.url);
}
});
}
else {
this.logger.debug('No fonts to load');
}
},
_ThemeMixinClass_applyTheme = async function _ThemeMixinClass_applyTheme() {
this.rootElement.setAttribute('data-theme', this.theme);
const descopeUi = await this.descopeUi;
if (descopeUi === null || descopeUi === void 0 ? void 0 : descopeUi.componentsThemeManager) {
descopeUi.componentsThemeManager.currentThemeName = this.theme;
}
},
_ThemeMixinClass_loadTheme = function _ThemeMixinClass_loadTheme() {
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_loadFonts).call(this);
__classPrivateFieldGet(this, _ThemeMixinClass_instances, "m", _ThemeMixinClass_applyTheme).call(this);
},
_a;
});
export { themeMixin };
//# sourceMappingURL=themeMixin.js.map