UNPKG

tss-react

Version:

Type safe CSS-in-JS API heavily inspired by react-jss

142 lines (141 loc) 7.15 kB
"use client"; /* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useMemo } from "react"; import { objectFromEntries } from "./tools/polyfills/Object.fromEntries"; import { objectKeys } from "./tools/objectKeys"; import { createUseCssAndCx } from "./cssAndCx"; import { getDependencyArrayRef } from "./tools/getDependencyArrayRef"; import { typeGuard } from "./tools/typeGuard"; import { assert } from "./tools/assert"; import { mergeClasses } from "./mergeClasses"; import { createContext, useContext } from "react"; import { useMuiThemeStyleOverridesPlugin } from "./mui/themeStyleOverridesPlugin"; // @ts-expect-error: It's not declared but it's there. import { __unsafe_useEmotionCache } from "@emotion/react"; const useContextualCache = __unsafe_useEmotionCache; let counter = 0; export function createMakeStyles(params) { const { useTheme, cache: cacheProvidedAtInception } = params; const { useCache } = createUseCache({ cacheProvidedAtInception }); const { useCssAndCx } = createUseCssAndCx({ useCache }); /** returns useStyle. */ function makeStyles(params) { const { name: nameOrWrappedName, uniqId = `${counter++}` } = params !== null && params !== void 0 ? params : {}; const name = typeof nameOrWrappedName !== "object" ? nameOrWrappedName : Object.keys(nameOrWrappedName)[0]; return function (cssObjectByRuleNameOrGetCssObjectByRuleName) { const getCssObjectByRuleName = typeof cssObjectByRuleNameOrGetCssObjectByRuleName === "function" ? cssObjectByRuleNameOrGetCssObjectByRuleName : () => cssObjectByRuleNameOrGetCssObjectByRuleName; return function useStyles(params, muiStyleOverridesParams) { const theme = useTheme(); let { css, cx } = useCssAndCx(); const cache = useCache(); let classes = useMemo(() => { const refClassesCache = {}; const refClasses = typeof Proxy !== "undefined" && new Proxy({}, { "get": (_target, propertyKey) => { if (typeof propertyKey === "symbol") { assert(false); } return (refClassesCache[propertyKey] = `${cache.key}-${uniqId}${name !== undefined ? `-${name}` : ""}-${propertyKey}-ref`); } }); const cssObjectByRuleName = getCssObjectByRuleName(theme, params, refClasses || {}); const classes = objectFromEntries(objectKeys(cssObjectByRuleName).map(ruleName => { const cssObject = cssObjectByRuleName[ruleName]; if (!cssObject.label) { cssObject.label = `${name !== undefined ? `${name}-` : ""}${ruleName}`; } return [ ruleName, `${css(cssObject)}${typeGuard(ruleName, ruleName in refClassesCache) ? ` ${refClassesCache[ruleName]}` : ""}` ]; })); objectKeys(refClassesCache).forEach(ruleName => { if (ruleName in classes) { return; } classes[ruleName] = refClassesCache[ruleName]; }); return classes; }, [cache, css, cx, theme, getDependencyArrayRef(params)]); { const propsClasses = muiStyleOverridesParams === null || muiStyleOverridesParams === void 0 ? void 0 : muiStyleOverridesParams.props.classes; classes = useMemo(() => mergeClasses(classes, propsClasses, cx), [classes, getDependencyArrayRef(propsClasses), cx]); } { const pluginResultWrap = useMuiThemeStyleOverridesPlugin({ classes, css, cx, "name": name !== null && name !== void 0 ? name : "makeStyle no name", "idOfUseStyles": uniqId, muiStyleOverridesParams, // NOTE: If it's not a Mui Theme the plugin is resilient, it will not crash "theme": theme }); if (pluginResultWrap.classes !== undefined) { classes = pluginResultWrap.classes; } if (pluginResultWrap.css !== undefined) { css = pluginResultWrap.css; } if (pluginResultWrap.cx !== undefined) { cx = pluginResultWrap.cx; } } return { classes, theme, css, cx }; }; }; } function useStyles() { const theme = useTheme(); const { css, cx } = useCssAndCx(); return { theme, css, cx }; } return { makeStyles, useStyles }; } const reactContext = createContext(undefined); export function TssCacheProvider(props) { const { children, value } = props; return (React.createElement(reactContext.Provider, { value: value }, children)); } export const { createUseCache } = (() => { function useCacheProvidedByProvider() { const cacheExplicitlyProvidedForTss = useContext(reactContext); return cacheExplicitlyProvidedForTss; } function createUseCache(params) { const { cacheProvidedAtInception } = params; function useCache() { var _a; const contextualCache = useContextualCache(); const cacheExplicitlyProvidedForTss = useCacheProvidedByProvider(); const cacheToBeUsed = (_a = cacheProvidedAtInception !== null && cacheProvidedAtInception !== void 0 ? cacheProvidedAtInception : cacheExplicitlyProvidedForTss) !== null && _a !== void 0 ? _a : contextualCache; if (cacheToBeUsed === null) { throw new Error([ "In order to get SSR working with tss-react you need to explicitly provide an Emotion cache.", "MUI users be aware: This is not an error strictly related to tss-react, with or without tss-react,", "MUI needs an Emotion cache to be provided for SSR to work.", "Here is the MUI documentation related to SSR setup: https://mui.com/material-ui/guides/server-rendering/", "TSS provides helper that makes the process of setting up SSR easier: https://docs.tss-react.dev/ssr" ].join("\n")); } return cacheToBeUsed; } return { useCache }; } return { createUseCache }; })();