UNPKG

css-vars-hook

Version:

css-vars-hook contains React hooks to set and manipulate CSS custom properties from React component.

1 lines 17.3 kB
{"version":3,"file":"index.umd.cjs","sources":["../src/lib/RootTheme/RootContext.ts","../src/lib/RootTheme/useRootThemePublic.ts","../src/lib/utils.ts","../src/lib/RootTheme/useRootTheme.ts","../src/lib/RootTheme/RootThemeProvider.tsx","../src/lib/LocalTheme/LocalRoot.tsx","../src/lib/LocalTheme/useLocalTheme.tsx"],"sourcesContent":["import type {Context} from 'react';\nimport {useContext, createContext} from 'react';\n\nimport type {Theme} from '@/lib/ThemeType.ts';\n\nimport type {HookInterface} from './HookInterfaceType';\n\nexport const RootContext = createContext({\n setTheme: () => {},\n getTheme: () => ({}),\n setVariable: () => {},\n getVariable: () => '',\n removeVariable: () => {},\n} as HookInterface<Theme>);\n\nexport const useRootContext = <TTheme extends Theme>() =>\n useContext<HookInterface<TTheme>>(\n RootContext as unknown as Context<HookInterface<TTheme>>\n );\n","import type {Theme} from '@/lib/ThemeType.ts';\n\nimport {useRootContext} from './RootContext';\n\n/**\n * @public\n * React hook to apply multiple CSS variables to theme root and manipulate them.\n * `ThemeType` is defined on project level.\n * @see ThemeType\n * @see https://github.com/morewings/css-vars-hook#type-safety\n */\nexport const useRootThemePublic = <TTheme extends Theme>() => {\n const {setTheme, getTheme, setVariable, getVariable, removeVariable} =\n useRootContext<TTheme>();\n return {\n /** Effect to apply new theme to the application */\n setTheme,\n /** Get current theme */\n getTheme,\n /** Effect to set new variable value within active theme */\n setVariable,\n /** Get variable value within active theme */\n getVariable,\n /** Effect to remove variable within active theme */\n removeVariable,\n };\n};\n","import type {MutableRefObject, CSSProperties} from 'react';\n\nimport type {UnitType, Theme} from '@/lib/ThemeType.ts';\n\nconst normalizeUnit = (unit: UnitType) => {\n if (typeof unit === 'string') {\n return unit;\n }\n return `${unit}`;\n};\n\n/**\n * Add `--` prefix to property names in theme object in order to make it applicable to DOM node\n */\nexport const createStyleObject = (theme: Theme): CSSProperties => {\n const keys = Object.keys(theme);\n const result: Record<string, UnitType> = {};\n keys.forEach(key => {\n result[`--${key}`] = theme[key];\n });\n return result;\n};\n\n/**\n * Add `--` prefix to property names in theme object in order to make it applicable to DOM node\n */\nexport const createStyleString = (theme: Theme) => {\n const keys = Object.keys(theme);\n let result = '';\n keys.forEach(key => {\n result = `${result}--${key}:${theme[key]};`;\n });\n return result;\n};\n\n/**\n * Set CSS theme at the provided DOM node\n */\nexport const setCSSTheme = (element: HTMLElement) => (theme: Theme) => {\n const style = createStyleString(theme);\n element?.setAttribute('style', style);\n};\n\n/**\n * Set CSS variable at the provided DOM node\n */\nexport const setCSSVariable =\n (element: HTMLElement) => (variableName: string, value: UnitType) => {\n element.style.setProperty(`--${variableName}`, normalizeUnit(value));\n };\n\n/**\n * Remove CSS variable from the provided DOM node\n */\nexport const removeCSSVariable =\n (ref: MutableRefObject<HTMLElement>) => (variableName: string) => {\n const element = ref.current;\n element?.style?.removeProperty?.(`--${variableName}`);\n };\n\n/**\n * Get CSS variable value at the provided DOM node\n */\nexport const getCSSVariable =\n (ref: MutableRefObject<HTMLElement>) => (variableName: string) => {\n const element = ref.current;\n return element?.style?.getPropertyValue?.(`--${variableName}`);\n };\n\n/**\n * Set new theme be replacing `style` attribute content\n */\nexport const setRootTheme = (id: string) => (theme: Theme) => {\n const root = document.getElementById(id)!;\n const style = createStyleString(theme);\n root?.setAttribute('style', style);\n};\n\n/**\n * Set CSS variable on theme root element\n */\nexport const setRootVariable =\n (id: string) => (variableName: string, value: UnitType) => {\n const root = document.getElementById(id)!;\n root?.style?.setProperty?.(`--${variableName}`, normalizeUnit(value));\n };\n\n/**\n * Get CSS variable on theme root element\n */\nexport const getRootVariable =\n (id: string) =>\n (variableName: string): string => {\n const root = document.getElementById(id)!;\n return root?.style?.getPropertyValue?.(`--${variableName}`);\n };\n\n/**\n * Remove CSS variable from theme root element\n */\nexport const removeRootVariable = (id: string) => (variableName: string) => {\n const root = document.getElementById(id)!;\n root?.style?.removeProperty?.(`--${variableName}`);\n};\n","import {useCallback, useMemo, useRef} from 'react';\nimport type {CSSProperties} from 'react';\n\nimport type {UnitType, Theme} from '@/lib/ThemeType.ts';\n\nimport {\n createStyleObject,\n getRootVariable,\n removeRootVariable,\n setRootVariable,\n setRootTheme,\n} from '../utils';\nimport type {HookInterface} from './HookInterfaceType';\n\n/**\n * @private\n * Logic for root theme handling such as updates and CSS style creation\n */\nexport const useRootTheme = <TTheme extends Theme>(\n theme: TTheme,\n id: string\n): HookInterface<TTheme> & {style: CSSProperties} => {\n const themeRef = useRef(theme);\n\n const setTheme = useCallback(\n (nextTheme: TTheme) => {\n setRootTheme(id)(nextTheme);\n themeRef.current = nextTheme;\n },\n [id]\n );\n\n const getTheme = useCallback(() => themeRef.current, []);\n\n const getVariable = useCallback(\n (variableName: string) => getRootVariable(id)(variableName),\n [id]\n );\n const setVariable = useCallback(\n (variableName: string, value: UnitType) => {\n setRootVariable(id)(variableName, value);\n themeRef.current = {\n ...themeRef.current,\n [variableName]: value,\n };\n },\n [id]\n );\n\n const removeVariable = useCallback(\n (variableName: string) => {\n removeRootVariable(id)(variableName);\n const nextTheme = {...themeRef.current};\n delete nextTheme[variableName];\n themeRef.current = nextTheme;\n },\n [id]\n );\n\n // eslint-disable-next-line react-hooks/refs\n const style = useMemo(() => createStyleObject(themeRef.current), []);\n\n return {\n /** Effect to apply new theme to the application */\n setTheme,\n /** CSSProperties object to apply to container div */\n style,\n /** Get current theme */\n getTheme,\n /** Get variable value within active theme */\n getVariable,\n /** Effect to set new variable value within active theme */\n setVariable,\n /** Effect to remove variable within active theme */\n removeVariable,\n };\n};\n","import type {FC, ReactNode} from 'react';\nimport {useMemo, useEffect, useId} from 'react';\n\nimport type {Theme} from '@/lib/ThemeType.ts';\n\nimport type {DataAttributes, LibraryProps} from '../NativeProps';\nimport {RootContext} from './RootContext';\nimport {useRootTheme} from './useRootTheme';\n\n/**\n * @public\n */\nexport type RootThemeProviderProps = DataAttributes &\n LibraryProps & {children: ReactNode; theme: Theme};\n\n/**\n * @public\n * Root theme context provider also creates div to contain CSS properties.\n * `ThemeType` is declared globally.\n * @see ThemeType\n * @see https://github.com/morewings/css-vars-hook#type-safety\n */\nexport const RootThemeProvider: FC<RootThemeProviderProps> = ({\n children,\n theme,\n className,\n id,\n ...nativeProps\n}) => {\n const backupId = useId();\n const rootId = id ? id : backupId;\n const {setTheme, style, getTheme, getVariable, setVariable, removeVariable} =\n useRootTheme(theme, rootId);\n\n const {Provider} = RootContext;\n\n const actions = useMemo(\n () => ({setTheme, getTheme, getVariable, setVariable, removeVariable}),\n [setTheme, getTheme, getVariable, setVariable, removeVariable]\n );\n\n useEffect(() => {\n setTheme(theme);\n }, [theme, setTheme]);\n\n return (\n <Provider value={actions}>\n <div {...nativeProps} id={rootId} className={className} style={style}>\n {children}\n </div>\n </Provider>\n );\n};\n","import type {HTMLAttributes, ReactNode, ElementType} from 'react';\nimport {forwardRef, useEffect, useMemo} from 'react';\n\nimport {createStyleObject} from '@/lib/utils';\nimport type {DataAttributes, LibraryProps} from '@/lib/NativeProps';\nimport type {Theme} from '@/lib/ThemeType.ts';\n\n/**\n * @public\n */\nexport type LocalRootProps = DataAttributes &\n LibraryProps &\n HTMLAttributes<HTMLElement> & {\n children?: ReactNode;\n /** Choose which HTMLElement to render as a root. `div` is the default value. */\n as?: ElementType;\n /** Apply the initial theme. */\n theme?: Theme;\n /** Provide a theme setter function. */\n setTheme?: (arg0: Theme) => void;\n };\n\nexport const LocalRoot = forwardRef<HTMLElement, LocalRootProps>((props, ref) => {\n // This is needed to fix an error introduced in version 0.6.14.\n // Props were not transported to returned HTMLElement.\n const {\n children,\n as: Component = 'div',\n theme = {},\n setTheme = () => {},\n ...restProps\n } = props;\n\n const initialStyle = useMemo(() => createStyleObject(theme), [theme]);\n\n useEffect(() => {\n setTheme(theme);\n }, [theme, setTheme]);\n\n return (\n <Component ref={ref} style={initialStyle} {...restProps}>\n {children}\n </Component>\n );\n});\n\nLocalRoot.displayName = 'LocalRoot';\n","import {useCallback, useRef, useMemo} from 'react';\n\nimport {setCSSVariable, setCSSTheme} from '@/lib/utils';\nimport type {UnitType, Theme} from '@/lib/ThemeType.ts';\n\nimport type {LocalRootProps} from './LocalRoot';\nimport {LocalRoot} from './LocalRoot';\n\n/**\n * @public\n * React hook to apply multiple CSS variables to a generated local root element (LocalRoot) and manipulate them.\n * Theme type is inferred from the provided theme parameter.\n * @example\n * const {setTheme, getTheme, LocalRoot, getVariable, setVariable} = useLocalTheme();\n * const setThemeIvory = () => {\n * setTheme({foo: 'ivory'});\n * console.log('full theme', getTheme()) // => {foo: 'ivory'};\n * console.log('foo value', getVariable('foo')) // => 'ivory';\n *};\n * return <LocalRoot theme={{foo: 'bar'}} className=\"demo-local\">//...\n */\nexport const useLocalTheme = <TElement extends HTMLElement>() => {\n const themeRef = useRef<Theme>({});\n const elementRef = useRef<TElement>(null);\n\n const setTheme = useCallback((nextTheme: Theme) => {\n setCSSTheme(elementRef.current!)(nextTheme);\n\n themeRef.current = nextTheme;\n }, []);\n\n const getTheme = useCallback(() => themeRef.current, []);\n\n const getVariable = useCallback(\n (variableName: string) => themeRef.current?.[variableName],\n []\n );\n\n const setVariable = useCallback((variableName: string, variableValue: UnitType) => {\n setCSSVariable(elementRef.current!)(variableName, variableValue);\n themeRef.current = {...themeRef.current, [variableName]: variableValue};\n }, []);\n\n const MemoRoot = useMemo(\n () =>\n // eslint-disable-next-line react/display-name\n ({children, ...restProps}: Omit<LocalRootProps, 'setTheme'>) => (\n <LocalRoot {...restProps} setTheme={setTheme} ref={elementRef}>\n {children}\n </LocalRoot>\n ),\n [setTheme]\n );\n\n return {\n /** Effect to apply new theme to LocalRoot */\n setTheme,\n /** Get the current theme set for LocalRoot */\n getTheme,\n /** Wrapper component which creates a DOM node to store theme data */\n LocalRoot: MemoRoot,\n /** React Mutable Ref object attached to LocalRoot */\n ref: elementRef,\n /** Get variable value within the LocalRoot theme */\n getVariable,\n /** Effect to set new variable value within LocalRoot theme */\n setVariable,\n };\n};\n"],"names":["RootContext","createContext","useRootContext","useContext","useRootThemePublic","setTheme","getTheme","setVariable","getVariable","removeVariable","normalizeUnit","unit","createStyleObject","theme","keys","result","key","createStyleString","setCSSTheme","element","style","setCSSVariable","variableName","value","setRootTheme","id","root","setRootVariable","getRootVariable","removeRootVariable","useRootTheme","themeRef","useRef","useCallback","nextTheme","useMemo","RootThemeProvider","children","className","nativeProps","backupId","useId","rootId","Provider","actions","useEffect","jsx","LocalRoot","forwardRef","props","ref","Component","restProps","initialStyle","useLocalTheme","elementRef","variableValue","MemoRoot"],"mappings":"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"}