UNPKG

@workday/canvas-kit-react

Version:

The parent module that contains all Workday Canvas Kit React components

100 lines (99 loc) 10.6 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { CacheProvider, ThemeProvider } from '@emotion/react'; import * as React from 'react'; import { createStyles, getCache } from '@workday/canvas-kit-styling'; import { base, brand, system } from '@workday/canvas-tokens-web'; import { defaultCanvasTheme, getTheme, isNumericalTheme, resolveThemingScope, useTheme, } from './theming'; import { hasExplicitSemanticPalette, writeBrandScopeSemantic, writeNumericalTheme, writeSemanticTheme, } from './theming/brandScope'; import { sanaCanvasProviderTheme } from './theming/sanaTheme'; /** * Context for providing brand CSS variables to popup containers. * This carries the resolved CSS variable style map from CanvasProvider * to usePopupStack for proper popup theming, regardless of whether * a numerical or legacy theme is used. */ export const CanvasBrandStyleContext = React.createContext({}); /** * If you wish to reset the theme to the default, apply this class on the CanvasProvider. */ export const defaultBranding = createStyles({ name: "3z3im2", styles: "--cnvs-brand-common-alert-inner:var(--cnvs-base-palette-amber-400);--cnvs-brand-common-alert-outer:var(--cnvs-base-palette-amber-500);--cnvs-brand-common-error-inner:var(--cnvs-base-palette-red-500);--cnvs-brand-common-focus-outline:var(--cnvs-base-palette-blue-500);--cnvs-brand-neutral-accent:var(--cnvs-base-palette-neutral-0);--cnvs-brand-neutral-darkest:var(--cnvs-base-palette-slate-800);--cnvs-brand-neutral-dark:var(--cnvs-base-palette-slate-700);--cnvs-brand-neutral-base:var(--cnvs-base-palette-slate-600);--cnvs-brand-neutral-light:var(--cnvs-base-palette-slate-200);--cnvs-brand-neutral-lighter:var(--cnvs-base-palette-slate-50);--cnvs-brand-neutral-lightest:var(--cnvs-base-palette-slate-25);--cnvs-brand-success-accent:var(--cnvs-base-palette-neutral-0);--cnvs-brand-success-darkest:var(--cnvs-base-palette-green-800);--cnvs-brand-success-dark:var(--cnvs-base-palette-green-700);--cnvs-brand-success-base:var(--cnvs-base-palette-green-600);--cnvs-brand-success-light:var(--cnvs-base-palette-green-200);--cnvs-brand-success-lighter:var(--cnvs-base-palette-green-50);--cnvs-brand-success-lightest:var(--cnvs-base-palette-green-25);--cnvs-brand-error-accent:var(--cnvs-base-palette-neutral-0);--cnvs-brand-error-darkest:var(--cnvs-base-palette-red-800);--cnvs-brand-error-dark:var(--cnvs-base-palette-red-700);--cnvs-brand-error-base:var(--cnvs-base-palette-red-600);--cnvs-brand-error-light:var(--cnvs-base-palette-red-200);--cnvs-brand-error-lighter:var(--cnvs-base-palette-red-50);--cnvs-brand-error-lightest:var(--cnvs-base-palette-red-25);--cnvs-brand-alert-accent:var(--cnvs-base-palette-neutral-900);--cnvs-brand-alert-darkest:var(--cnvs-base-palette-amber-600);--cnvs-brand-alert-dark:var(--cnvs-base-palette-amber-500);--cnvs-brand-alert-base:var(--cnvs-base-palette-amber-400);--cnvs-brand-alert-light:var(--cnvs-base-palette-amber-200);--cnvs-brand-alert-lighter:var(--cnvs-base-palette-amber-50);--cnvs-brand-alert-lightest:var(--cnvs-base-palette-amber-25);--cnvs-brand-primary-accent:var(--cnvs-base-palette-neutral-0);--cnvs-brand-primary-darkest:var(--cnvs-base-palette-blue-800);--cnvs-brand-primary-dark:var(--cnvs-base-palette-blue-700);--cnvs-brand-primary-base:var(--cnvs-base-palette-blue-600);--cnvs-brand-primary-light:var(--cnvs-base-palette-blue-200);--cnvs-brand-primary-lighter:var(--cnvs-base-palette-blue-50);--cnvs-brand-primary-lightest:var(--cnvs-base-palette-blue-25);--cnvs-brand-gradient-primary:linear-gradient(90deg, var(--cnvs-brand-primary-base) 0%, var(--cnvs-brand-primary-dark) 100%);--cnvs-sys-color-brand-focus-primary:var(--cnvs-brand-common-focus-outline);--cnvs-sys-color-brand-border-primary:var(--cnvs-brand-common-focus-outline);--cnvs-sys-color-brand-accent-primary:var(--cnvs-brand-primary-base);--cnvs-sys-color-brand-accent-action:var(--cnvs-brand-primary-base);--cnvs-sys-color-brand-accent-critical:var(--cnvs-brand-error-base);--cnvs-sys-color-brand-accent-caution:var(--cnvs-brand-alert-base);--cnvs-sys-color-brand-accent-positive:var(--cnvs-brand-success-base);--cnvs-sys-color-brand-fg-primary-default:var(--cnvs-brand-primary-base);--cnvs-sys-color-brand-fg-primary-strong:var(--cnvs-brand-primary-dark);--cnvs-sys-color-brand-fg-critical-default:var(--cnvs-brand-error-base);--cnvs-sys-color-brand-fg-critical-strong:var(--cnvs-brand-error-dark);--cnvs-sys-color-brand-fg-caution-default:var(--cnvs-brand-alert-darkest);--cnvs-sys-color-brand-fg-caution-strong:var(--cnvs-brand-alert-darkest);--cnvs-sys-color-brand-fg-positive-default:var(--cnvs-brand-success-base);--cnvs-sys-color-brand-fg-positive-strong:var(--cnvs-brand-success-dark);--cnvs-sys-color-brand-fg-selected:var(--cnvs-brand-primary-dark);--cnvs-sys-color-brand-focus-critical:var(--cnvs-brand-error-dark);--cnvs-sys-color-brand-border-critical:var(--cnvs-brand-error-base);--cnvs-sys-color-brand-focus-caution-inner:var(--cnvs-brand-common-alert-inner);--cnvs-sys-color-brand-focus-caution-outer:var(--cnvs-brand-alert-dark);--cnvs-sys-color-brand-border-caution:var(--cnvs-brand-alert-dark);--cnvs-sys-color-brand-surface-primary-default:var(--cnvs-brand-primary-lightest);--cnvs-sys-color-brand-surface-primary-strong:var(--cnvs-brand-primary-lighter);--cnvs-sys-color-brand-surface-critical-default:var(--cnvs-brand-error-lightest);--cnvs-sys-color-brand-surface-critical-strong:var(--cnvs-brand-error-lighter);--cnvs-sys-color-brand-surface-caution-default:var(--cnvs-brand-alert-lightest);--cnvs-sys-color-brand-surface-caution-strong:var(--cnvs-brand-alert-lighter);--cnvs-sys-color-brand-surface-positive-default:var(--cnvs-brand-success-lightest);--cnvs-sys-color-brand-surface-positive-strong:var(--cnvs-brand-success-lighter);--cnvs-sys-color-brand-surface-selected:var(--cnvs-brand-primary-lighter);" }); /** Pure function — safe to call outside React hooks (e.g. usePopupStack). */ export function canvasThemeToCssVars(theme, elemProps, options) { var _a, _b; const className = elemProps.className || ''; const style = { ...(elemProps.style || {}) }; const scope = (_a = options === null || options === void 0 ? void 0 : options.themeScope) !== null && _a !== void 0 ? _a : resolveThemingScope(theme); if (!theme) { return { ...elemProps, className, style }; } if (isNumericalTheme(theme)) { writeNumericalTheme(theme, style, scope); } else if (!hasExplicitSemanticPalette(theme)) { // `{canvas: {}}` — no inline overrides; global CSS (e.g. Sana) cascades through. } else if (scope === 'brand') { writeBrandScopeSemantic(theme, style); } else { const filledTheme = (_b = options === null || options === void 0 ? void 0 : options.filledSemanticTheme) !== null && _b !== void 0 ? _b : getTheme(theme); writeSemanticTheme(filledTheme.canvas.palette, style, { writeAll: true }); } return { ...elemProps, className, style }; } export const useCanvasThemeToCssVars = ( /** * @deprecated ⚠️ `theme` is deprecated. In previous versions of Canvas Kit, we allowed teams to pass a theme object, this supported [Emotion's theming](https://emotion.sh/docs/theming). Now that we're shifting to a global theming approach based on CSS variables, we advise to no longer using the theme prop. For more information, view our [Theming Docs](https://workday.github.io/canvas-kit/?path=/docs/features-theming-overview--docs#-preferred-approach-v14). */ theme, elemProps, themeScope) => { const filledTheme = useTheme(isNumericalTheme(theme) ? undefined : theme); const resolvedScope = themeScope !== null && themeScope !== void 0 ? themeScope : resolveThemingScope(theme); return canvasThemeToCssVars(theme, elemProps, { themeScope: resolvedScope, filledSemanticTheme: !isNumericalTheme(theme) && resolvedScope === 'full' ? filledTheme : undefined, }); }; export const CanvasProvider = ({ children, theme, themeScope, ...props }) => { var _a; // Add console warning for unnecessary sanaCanvasProviderTheme usage React.useEffect(() => { if (process.env.NODE_ENV !== 'production') { if (theme === sanaCanvasProviderTheme && typeof document !== 'undefined' && document.documentElement.getAttribute('data-theme') === 'sana-canvas') { console.warn('Canvas Kit: You are passing sanaCanvasProviderTheme to CanvasProvider but ' + 'data-theme="sana-canvas" is already set on <html>. The theme prop is not needed ' + 'in this case and can be removed. Keep sanaCanvasProviderTheme when you cannot ' + 'control <html> (embedded apps / microfrontends) so popups still get Sana brand ' + 'variables. See: ' + 'https://workday.github.io/canvas-kit/?path=/docs/features-theming-overview--docs'); } } }, [theme]); // Computed className/style win over consumer props — do not re-spread `props` over them. const { className, style, ...elemProps } = useCanvasThemeToCssVars(theme, props, themeScope); const cache = getCache(); // Read parent context to support nested scoped providers const parentBrandStyle = React.useContext(CanvasBrandStyleContext); // Popup forwarding only needs CSS custom properties (not consumer layout styles). const mergedBrandStyle = React.useMemo(() => { const merged = {}; for (const [key, value] of Object.entries({ ...parentBrandStyle, ...style })) { if (key.startsWith('--') && typeof value === 'string') { // @ts-ignore - CSS custom property key merged[key] = value; } } return merged; }, [parentBrandStyle, style]); const emotionTheme = theme ? isNumericalTheme(theme) ? { canvas: defaultCanvasTheme } : theme : undefined; const content = (_jsx("div", { dir: isNumericalTheme(theme) ? theme.direction || defaultCanvasTheme.direction : ((_a = theme === null || theme === void 0 ? void 0 : theme.canvas) === null || _a === void 0 ? void 0 : _a.direction) || defaultCanvasTheme.direction, className: className, ...elemProps, style: style, children: children })); const wrappedContent = (_jsx(CanvasBrandStyleContext.Provider, { value: mergedBrandStyle, children: content })); return (_jsx(CacheProvider, { value: cache, children: emotionTheme ? (_jsx(ThemeProvider, { theme: emotionTheme, children: wrappedContent })) : (wrappedContent) })); };