@atlaskit/tokens
Version:
Design tokens are the single source of truth to name and store design decisions.
111 lines (105 loc) • 5.04 kB
JavaScript
import { fg } from '@atlaskit/platform-feature-flags';
import getGlobalTheme from './get-global-theme';
import { themeStateDefaults } from './theme-config';
import configurePage from './utils/configure-page';
import { findMissingCustomStyleElements } from './utils/custom-theme-loading-utils';
import { getThemeOverridePreferences } from './utils/get-theme-override-preferences';
import { getThemePreferences } from './utils/get-theme-preferences';
import { isValidBrandHex } from './utils/is-valid-brand-hex';
import { loadAndAppendThemeCss } from './utils/theme-loading';
/**
* Sets the theme globally at runtime. This updates the `data-theme` and `data-color-mode` attributes on your page's <html> tag.
*
* @param {Object<string, string>} themeState The themes and color mode that should be applied.
* @param {string} themeState.colorMode Determines which color theme is applied. If set to `auto`, the theme applied will be determined by the OS setting.
* @param {string} themeState.contrastMode The contrast mode theme to be applied. If set to `auto`, the theme applied will be determined by the OS setting.set to `auto`, the theme applied will be determined by the OS setting.
* @param {string} themeState.dark The color theme to be applied when the color mode resolves to 'dark'.
* @param {string} themeState.light The color theme to be applied when the color mode resolves to 'light'.
* @param {string} themeState.motion The motion theme to be applied.
* @param {string} themeState.shape The shape theme to be applied.
* @param {string} themeState.spacing The spacing theme to be applied.
* @param {string} themeState.typography The typography theme to be applied.
* @param {Object} themeState.UNSAFE_themeOptions The custom branding options to be used for custom theme generation
* @param {function} themeLoader Callback function used to override the default theme loading functionality.
*
* @returns A Promise of an unbind function, that can be used to stop listening for changes to system theme.
*
* @example
* ```
* setGlobalTheme({colorMode: 'auto', light: 'light', dark: 'dark', spacing: 'spacing'});
* ```
*/
const setGlobalTheme = async (nextThemeState = {}, themeLoader) => {
let {
colorMode = themeStateDefaults['colorMode'],
contrastMode = themeStateDefaults['contrastMode'],
dark = themeStateDefaults['dark'],
light = themeStateDefaults['light'],
shape = themeStateDefaults['shape'](),
spacing = themeStateDefaults['spacing'],
typography = themeStateDefaults['typography'],
motion = themeStateDefaults['motion'](),
UNSAFE_themeOptions = themeStateDefaults['UNSAFE_themeOptions']
} = typeof nextThemeState === 'function' ? nextThemeState({
...themeStateDefaults,
typography: themeStateDefaults['typography'],
shape: themeStateDefaults['shape'](),
motion: themeStateDefaults['motion'](),
...getGlobalTheme()
}) : nextThemeState;
// CLEANUP: Remove. This blocks application of increased contrast themes
// without the feature flag enabled.
if (!fg('platform_increased-contrast-themes')) {
if (light === 'light-increased-contrast') {
light = 'light';
}
if (dark === 'dark-increased-contrast') {
dark = 'dark';
}
}
const themeState = {
colorMode,
contrastMode,
dark,
light,
shape,
spacing,
typography,
motion,
UNSAFE_themeOptions: themeLoader ? undefined : UNSAFE_themeOptions
};
// Determine what to load and loading strategy
let themePreferences = getThemePreferences(themeState);
const loadingStrategy = themeLoader ? themeLoader : loadAndAppendThemeCss;
// Load standard themes
const loadingTasks = themePreferences.map(async themeId => await loadingStrategy(themeId));
// Load custom themes if needed
if (!themeLoader && UNSAFE_themeOptions && isValidBrandHex(UNSAFE_themeOptions === null || UNSAFE_themeOptions === void 0 ? void 0 : UNSAFE_themeOptions.brandColor)) {
const mode = colorMode || themeStateDefaults['colorMode'];
const attrOfMissingCustomStyles = findMissingCustomStyleElements(UNSAFE_themeOptions, mode);
if (attrOfMissingCustomStyles.length > 0) {
// Load custom theme styles
loadingTasks.push((async () => {
const {
loadAndAppendCustomThemeCss
} = await import( /* webpackChunkName: "@atlaskit-internal_atlassian-custom-theme" */
'./custom-theme');
loadAndAppendCustomThemeCss({
colorMode: attrOfMissingCustomStyles.length === 2 ? 'auto' :
// only load the missing custom theme styles
attrOfMissingCustomStyles[0],
UNSAFE_themeOptions
});
})());
}
}
await Promise.all(loadingTasks);
// Load override themes after standard themes
const themeOverridePreferences = getThemeOverridePreferences(themeState);
for (const themeId of themeOverridePreferences) {
await loadingStrategy(themeId);
}
const autoUnbind = configurePage(themeState);
return autoUnbind;
};
export default setGlobalTheme;