UNPKG

@workday/canvas-kit-react

Version:

The parent module that contains all Workday Canvas Kit React components

150 lines (149 loc) • 6.95 kB
// refactor for v5 /// <reference types="@types/node" /> import { useTheme as useEmotionTheme } from '@emotion/react'; import { defaultCanvasTheme, } from './index'; import { cssVar } from '@workday/canvas-kit-styling'; import { base } from '@workday/canvas-tokens-web'; /** * We can adjust the shift but this should get us close enough until we clean up the algorithm to determine the colors. */ const shiftColor = (color, value) => { return `oklch(from ${color} calc(l ${value > 0 ? '+' : '-'} ${Math.abs(value) / 1000}) c h)`; }; const generatePalette = (key, palette) => { const colorPalette = palette === null || palette === void 0 ? void 0 : palette[key]; if (colorPalette) { const defaultPalette = defaultCanvasTheme.palette[key]; return { lightest: colorPalette.lightest || (colorPalette.main && shiftColor(colorPalette.main, 400)) || defaultPalette.lightest, lighter: colorPalette.lighter || (colorPalette.main && shiftColor(colorPalette.main, 150)) || defaultPalette.lighter, light: colorPalette.light || (colorPalette.main && shiftColor(colorPalette.main, 100)) || defaultPalette.light, main: colorPalette.main || defaultPalette.main, dark: colorPalette.dark || (colorPalette.main && shiftColor(colorPalette.main, -100)) || defaultPalette.dark, darkest: colorPalette.darkest || (colorPalette.main && shiftColor(colorPalette.main, -200)) || defaultPalette.darkest, contrast: colorPalette.contrast || cssVar(base.neutral0), }; } return defaultCanvasTheme.palette[key]; }; const generateTheme = (theme) => { var _a, _b, _c, _d, _e, _f, _g, _h; return { palette: { primary: generatePalette('primary', (_a = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _a === void 0 ? void 0 : _a.palette), alert: generatePalette('alert', (_b = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _b === void 0 ? void 0 : _b.palette), error: generatePalette('error', (_c = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _c === void 0 ? void 0 : _c.palette), success: generatePalette('success', (_d = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _d === void 0 ? void 0 : _d.palette), neutral: generatePalette('neutral', (_e = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _e === void 0 ? void 0 : _e.palette), common: { ...defaultCanvasTheme.palette.common, ...(_g = (_f = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _f === void 0 ? void 0 : _f.palette) === null || _g === void 0 ? void 0 : _g.common }, }, breakpoints: defaultCanvasTheme.breakpoints, direction: ((_h = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _h === void 0 ? void 0 : _h.direction) || defaultCanvasTheme.direction, }; }; const getFilledTheme = (theme) => { return { ...defaultCanvasTheme, ...theme, canvas: generateTheme(theme), }; }; /** * Function to get the correct theme object for `styled` and class components * or to be used outside component. * @param {Object=} theme - The theme object with the Canvas Kit theme. * It should be namespaced within this variable under the `canvas` key. * Value of `canvas` property is any partial or full theme object to overwtite default theme. * * @returns An object containing updated or default Canvas Kit theme under `canvas` key. * * The passed partial theme object will be merged with the default Canvas theme * (using memoized createCanvasTheme()) to establish any missing fields that have * not been defined by the consumer's theme object. * * If theme is not passed, the function will try to retrieve it from the window object. * If window theme is not found, it will return the default Canvas theme. * * @example * import {getTheme} from '@workday/canvas-kit-react/common'; * * const theme = getTheme(); * const {up, down} = theme.canvas.breakpoints; * const small = down('m'); // Returns '@media (max-width: 768px)' * const medium = up('m'); // Returns '@media (min-width: 768px)' * * const styles = { * [small]: { * margin: space.m * }, * [medium]: { * margin: space.l * } * } */ export function getTheme(theme) { var _a, _b; if (theme === null || theme === void 0 ? void 0 : theme.canvas) { return getFilledTheme(theme); } const windowTheme = typeof window !== 'undefined' && ((_b = (_a = window === null || window === void 0 ? void 0 : window.workday) === null || _a === void 0 ? void 0 : _a.canvas) === null || _b === void 0 ? void 0 : _b.theme); if (windowTheme) { return getFilledTheme({ canvas: windowTheme }); } return { canvas: defaultCanvasTheme }; } /** * Hook function to get the correct theme object for functional components. * @param {Object=} theme - The theme object with the Canvas Kit theme. * It should be namespaced within this variable under the `canvas` key. * Value of `canvas` property is any partial or full theme object to overwtite default theme. * * @returns An object containing updated or default Canvas Kit theme under `canvas` key. * * NOTE: If theme is not passed, the function will try to pull the theme from ThemeContext. * If that does not work, it will try to retrieve it from the window object. * As a last resort, it will return the default Canvas theme. * * The resulting theme will be merged with the default Canvas theme * (using memoized createCanvasTheme()) to establish any missing fields that have * not been defined by the consumer's theme object. * * Providing the default theme here is currently a work around for when no * ThemeProvider or context exists. * Tracked on https://github.com/emotion-js/emotion/issues/1193. * * @example * export const ErrorMessage = () => { * const theme = useTheme(); * return ( * <Subtext size="large" color={theme.canvas.palette.error.main}> * ); * } */ export function useTheme(theme) { if (!theme) { try { // eslint-disable-next-line react-hooks/rules-of-hooks const contextTheme = useEmotionTheme(); if (contextTheme === null || contextTheme === void 0 ? void 0 : contextTheme.canvas) { return getFilledTheme(contextTheme); } } catch (e) { if (process.env.NODE_ENV === 'development') { console.warn('useTheme: Context not supported or invalid. Please consider using `getTheme` function instead for `styled` or class components.'); } } } return getTheme(theme); }