UNPKG

@dash-ui/react

Version:

React components and hooks for dash-ui

1 lines 8.36 kB
{"version":3,"file":"index.mjs","sources":["../../src/index.tsx"],"sourcesContent":["import type {\n DashThemes,\n DashTokens,\n Falsy,\n StyleCallback,\n StyleObject,\n Styles,\n StyleValue,\n} from \"@dash-ui/styles\";\nimport { compileStyles } from \"@dash-ui/styles\";\nimport useLayoutEffect from \"@react-hook/passive-layout-effect\";\nimport * as React from \"react\";\n\nconst IS_BROWSER = typeof document !== \"undefined\";\nconst useInsertionEffect =\n typeof React.useInsertionEffect === \"function\"\n ? React.useInsertionEffect\n : useLayoutEffect;\n\n/**\n * A component for creating an inline `<style>` tag that is unmounted when\n * the component unmounts.\n *\n * @param root0\n * @param root0.css\n * @param root0.styles\n */\nexport function Inline<Tokens extends DashTokens, Themes extends DashThemes>({\n styles,\n css: input,\n}: InlineProps<Tokens, Themes>): JSX.Element | null {\n const css = styles.one(input).css();\n\n return !css ? null : (\n // We don't want data-cache, data-dash props here because\n // we don't want this to be moved into the head of the document\n // during SSR hydration\n <style\n dangerouslySetInnerHTML={{ __html: css }}\n nonce={styles.dash.sheet.nonce ? styles.dash.sheet.nonce : void 0}\n />\n );\n}\n\nexport interface InlineProps<\n Tokens extends DashTokens,\n Themes extends DashThemes\n> {\n /**\n * A Dash `styles` instance\n */\n styles: Styles<Tokens, Themes>;\n /**\n * The CSS you want to inline in the DOM.\n *\n * @example\n * const Component => <Inline css={({color}) => `html { color: ${color.text}; }`}/>\n */\n css: string | StyleCallback<Tokens, Themes> | StyleObject;\n}\n\n/**\n * A hook for inserting transient global styles into the DOM. These styles\n * will be injected when the hook mounts and flushed when the hook unmounts.\n *\n * @param styles - A Dash `styles` instance\n * @param value - Global CSS to inject into the DOM and flush when the hook unmounts\n * @param deps - A dependency array that will force the hook to re-insert global styles\n * @example\n * const Component = () => {\n * const [userFontSize, setUserFontSize] = React.useState('100%')\n *\n * useGlobal(\n * `\n * html {\n * font-size: ${userFontSize};\n * }\n * `,\n * [userFontSize]\n * )\n * }\n */\nexport function useGlobal<Tokens extends DashTokens, Themes extends DashThemes>(\n styles: Styles<Tokens, Themes>,\n value:\n | string\n | StyleCallback<Tokens, Themes>\n | StyleObject\n | null\n | 0\n | undefined\n | false,\n deps?: React.DependencyList\n): void {\n // inserts global styles into the dom and cleans up its\n // styles when the component is unmounted\n useInsertionEffect(\n () => (value ? styles.insertGlobal(value) : noop),\n (deps = deps && deps.concat(styles))\n );\n\n if (!IS_BROWSER && value) {\n styles.insertGlobal(value);\n }\n}\n\n/**\n * A hook for inserting transient CSS tokens into the DOM. These tokens\n * will be injected when the hook mounts and flushed when the hook unmounts.\n *\n * @param styles - A Dash `styles` instance\n * @param value - CSS tokens to inject into the DOM and flush when the hook unmounts\n * @param deps - A dependency array that will force the hook to re-insert tokens\n * @example\n * const Component = () => {\n * const [userFontSize, setUserFontSize] = React.useState('100%')\n *\n * useTokens(\n * styles,\n * {fontSize: userFontSize},\n * [userFontSize]\n * )\n * }\n */\nexport function useTokens<Tokens extends DashTokens, Themes extends DashThemes>(\n styles: Styles<Tokens, Themes>,\n value: Parameters<Styles<Tokens, Themes>[\"insertTokens\"]>[0] | Falsy,\n deps?: React.DependencyList\n): void {\n useInsertionEffect(\n () => (value ? styles.insertTokens(value) : noop),\n (deps = deps && deps.concat(styles))\n );\n\n if (!IS_BROWSER && value) {\n styles.insertTokens(value);\n }\n}\n\n/**\n * A hook for inserting transient CSS theme tokens into the DOM. These tokens\n * will be injected when the hook mounts and flushed when the hook unmounts.\n *\n * @param styles - A Dash `styles` instance\n * @param value - Themes to inject into the DOM and flush when the hook unmounts\n * @param deps - A dependency array that will force the hook to re-insert themes\n * @example\n * const Component = () => {\n * const [color, setColor] = React.useState('aliceblue')\n *\n * useThemes(\n * styles,\n * {\n * dark: {color}\n * },\n * [color]\n * )\n * }\n */\nexport function useThemes<Tokens extends DashTokens, Themes extends DashThemes>(\n styles: Styles<Tokens, Themes>,\n value: Parameters<Styles<Tokens, Themes>[\"insertThemes\"]>[0] | Falsy,\n deps?: React.DependencyList\n): void {\n useInsertionEffect(\n () => (value ? styles.insertThemes(value) : noop),\n (deps = deps && deps.concat(styles))\n );\n\n if (!IS_BROWSER && value) {\n styles.insertThemes(value);\n }\n}\n\n/**\n * A hook for performantly and reliably inserting CSS into the DOM in React 18 using the\n * `useInsertionEffect` hook.\n *\n * @param styles - A Dash `styles` instance\n * @param classNames - A map of class names to CSS generators\n * @see https://github.com/reactwg/react-18/discussions/110\n * @example\n * ```tsx\n * const classes = useCSS(styles, {\n * root: styles.one({ display: 'flex' })\n * })\n *\n * return <div className={classes.root}/>\n * ```\n */\nexport function useCSS<\n ClassNames extends string,\n Tokens extends DashTokens,\n Themes extends DashThemes\n>(\n styles: Styles<Tokens, Themes>,\n classNames: ClassNamesStyleMap<ClassNames, Tokens, Themes>\n): UseCSSResult<ClassNames> {\n function insertClasses(): void {\n for (const className in classNames) {\n const style = classNames[className];\n\n if (typeof style === \"function\" && \"css\" in style) {\n style();\n } else {\n styles.cls(style);\n }\n }\n }\n\n useInsertionEffect(insertClasses);\n\n if (!IS_BROWSER) {\n insertClasses();\n }\n\n const classes = {} as Record<ClassNames, string>;\n\n for (const className in classNames) {\n const style = classNames[className];\n classes[className] =\n styles.dash.key +\n \"-\" +\n styles.hash(\n typeof style === \"function\" && \"css\" in style\n ? style.css()\n : compileStyles(style, styles.tokens)\n );\n }\n\n return classes;\n}\n\nexport type ClassNamesStyleMap<\n ClassNames extends string,\n Tokens extends DashTokens,\n Themes extends DashThemes\n> = Record<\n ClassNames,\n | {\n (): string;\n css(): string;\n }\n | StyleValue<Tokens, Themes>\n>;\n\nexport type UseCSSResult<ClassNames extends string> = Record<\n ClassNames,\n string\n>;\n\nfunction noop(): void {}\n"],"names":["Inline","styles","css","input","one","__reactCreateElement__","dangerouslySetInnerHTML","__html","nonce","dash","sheet","useGlobal","value","deps","useInsertionEffect","insertGlobal","noop","concat","IS_BROWSER","useTokens","insertTokens","useThemes","insertThemes","useCSS","classNames","insertClasses","className","style","cls","classes","key","hash","compileStyles","tokens","document","React","useLayoutEffect"],"mappings":"AA2BO,SAASA,KAGoC,IAHyBC,OAC3EA,EACAC,IAAKC,KAECD,EAAMD,EAAOG,IAAID,GAAOD,MAE9B,OAAQA,EAING,WACEC,wBAAyB,CAAEC,OAAQL,GACnCM,MAAOP,EAAOQ,KAAKC,MAAMF,MAAQP,EAAOQ,KAAKC,MAAMF,WAAQ,IANjD,KAiDT,SAASG,EACdV,EACAW,EAQAC,GAIAC,EACE,IAAOF,EAAQX,EAAOc,aAAaH,GAASI,EAC3CH,EAAOA,GAAQA,EAAKI,OAAOhB,KAGzBiB,GAAcN,GACjBX,EAAOc,aAAaH,GAsBjB,SAASO,EACdlB,EACAW,EACAC,GAEAC,EACE,IAAOF,EAAQX,EAAOmB,aAAaR,GAASI,EAC3CH,EAAOA,GAAQA,EAAKI,OAAOhB,KAGzBiB,GAAcN,GACjBX,EAAOmB,aAAaR,GAwBjB,SAASS,EACdpB,EACAW,EACAC,GAEAC,EACE,IAAOF,EAAQX,EAAOqB,aAAaV,GAASI,EAC3CH,EAAOA,GAAQA,EAAKI,OAAOhB,KAGzBiB,GAAcN,GACjBX,EAAOqB,aAAaV,GAoBjB,SAASW,EAKdtB,EACAuB,GAEA,SAASC,IACP,IAAK,IAAMC,KAAaF,EAAY,CAClC,IAAMG,EAAQH,EAAWE,GAEJ,mBAAVC,GAAwB,QAASA,EAC1CA,IAEA1B,EAAO2B,IAAID,IAKjBb,EAAmBW,GAEdP,GACHO,IAGF,IAAMI,EAAU,GAEhB,IAAK,IAAMH,KAAaF,EAAY,CAClC,IAAMG,EAAQH,EAAWE,GACzBG,EAAQH,GACNzB,EAAOQ,KAAKqB,IACZ,IACA7B,EAAO8B,KACY,mBAAVJ,GAAwB,QAASA,EACpCA,EAAMzB,MACN8B,EAAcL,EAAO1B,EAAOgC,SAItC,OAAOJ,EAqBT,SAASb,oJA9OHE,EAAiC,oBAAbgB,SACpBpB,EACgC,mBAA7BqB,EAAMrB,mBACTqB,EAAMrB,mBACNsB"}