UNPKG

@hakuna-matata-ui/system

Version:
125 lines (102 loc) 3.23 kB
import { useColorMode } from "@hakuna-matata-ui/color-mode" import { SystemStyleObject } from "@hakuna-matata-ui/styled-system" import { Dict, filterUndefined, mergeWith, runIfFn, StringOrNumber, } from "@hakuna-matata-ui/utils" import { useMemo, useRef } from "react" import isEqual from "react-fast-compare" import { useTheme } from "./providers" import { ThemingProps } from "./system.types" import { omitThemingProps } from "./system.utils" export function useChakra<T extends Dict = Dict>() { const colorModeResult = useColorMode() const theme = useTheme() as T return { ...colorModeResult, theme } } // inspired from ./css.ts : resolveTokenValue const resolveTokenValue = <T extends StringOrNumber>( theme: Dict, tokenValue: T, fallbackValue: any, ) => { if (tokenValue == null) return tokenValue const getValue = (val: T) => theme.__cssMap?.[val]?.value return getValue(tokenValue) ?? getValue(fallbackValue) ?? fallbackValue } export function useToken<T extends StringOrNumber>( scale: string, token: T | T[], fallback?: T | T[], ) { const theme = useTheme() if (Array.isArray(token)) { let fallbackArr: T[] = [] if (fallback) { fallbackArr = Array.isArray(fallback) ? fallback : [fallback] } return token.map((token, index) => { const path = `${scale}.${token}` return resolveTokenValue(theme, path, fallbackArr[index] ?? token) }) } const path = `${scale}.${token}` return resolveTokenValue(theme, path, fallback) } export function useProps<P extends ThemingProps>( themeKey: string, props: P, isMulti: true, ): { styles: Record<string, SystemStyleObject> props: Omit<P, keyof ThemingProps> } export function useProps<P extends ThemingProps>( themeKey: string, props?: P, isMulti?: boolean, ): { styles: SystemStyleObject props: Omit<P, keyof ThemingProps> } export function useProps(themeKey: string, props: Dict) { const { theme, colorMode } = useChakra() const styleConfig = (props.styleConfig || theme.components?.[themeKey]) as | Dict | undefined const defaultProps = styleConfig?.defaultProps ?? {} const propsWithDefault = { ...defaultProps, ...filterUndefined(props) } const stylesRef = useRef<Dict>({}) const mergedProps = mergeWith({}, propsWithDefault, { theme, colorMode }) const memoizedStyles = useMemo(() => { if (styleConfig) { const baseStyles = runIfFn(styleConfig.baseStyle ?? {}, mergedProps) const variants = runIfFn( styleConfig.variants?.[mergedProps.variant as string] ?? {}, mergedProps, ) const sizes = runIfFn( styleConfig.sizes?.[mergedProps.size as string] ?? {}, mergedProps, ) const styles = mergeWith(baseStyles, sizes, variants) if (styleConfig.parts) { styleConfig.parts.forEach((part: string) => { styles[part] = styles[part] ?? {} }) } const isStyleEqual = isEqual(stylesRef.current, styles) if (!isStyleEqual) { stylesRef.current = styles } } return stylesRef.current }, [styleConfig, mergedProps]) return { styles: memoizedStyles, props: omitThemingProps(propsWithDefault), } }