UNPKG

@chakra-ui/react

Version:

Responsive and accessible React UI components built with React and Emotion

124 lines (121 loc) 4 kB
"use strict"; import { compact } from '../utils/compact.js'; import { cx } from '../utils/cx.js'; import { mapEntries } from '../utils/entries.js'; import { memo } from '../utils/memo.js'; import { mergeWith } from '../utils/merge.js'; import { omit } from '../utils/omit.js'; import { splitProps } from '../utils/split-props.js'; import { uniq } from '../utils/uniq.js'; import { createCssFn } from './css.js'; import { EMPTY_OBJECT } from './singleton.js'; const defaults = (conf) => ({ base: EMPTY_OBJECT, variants: EMPTY_OBJECT, defaultVariants: EMPTY_OBJECT, compoundVariants: [], ...conf }); function createRecipeFn(options) { const { css, conditions, normalize, layers } = options; function cva(config = {}) { const defaultsConfig = defaults(config); const { base, defaultVariants, compoundVariants } = defaultsConfig; const variants = mapEntries(defaultsConfig.variants, (key, obj) => [ key, mapEntries(obj, (optionKey, styles) => [optionKey, normalize(styles)]) ]); const getVariantCss = createCssFn({ conditions, normalize, transform(prop, value) { return variants[prop]?.[value]; } }); const resolve = memo(function resolve2(props = {}) { const variantSelections = normalize({ ...defaultVariants, ...compact(props) }); let variantCss = { ...normalize(base) }; mergeWith(variantCss, getVariantCss(variantSelections)); const compoundVariantCss = getCompoundVariantCss( compoundVariants, variantSelections ); return layers.wrap("recipes", css(variantCss, compoundVariantCss)); }); const variantKeys = Object.keys(variants); const splitVariantProps = (props) => { const restProps = omit(props, ["recipe"]); const [recipeProps, localProps] = splitProps(restProps, variantKeys); const hasColorPalette = variantKeys.includes("colorPalette"); const hasOrientation = variantKeys.includes("orientation"); if (!hasColorPalette) { recipeProps.colorPalette = props.colorPalette || defaultVariants.colorPalette; } if (hasOrientation) { localProps.orientation = props.orientation; } return [recipeProps, localProps]; }; const variantMap = mapEntries(variants, (key, value) => [ key, Object.keys(value) ]); const cvaFn = memo(function cvaFn2(props) { return css(resolve(props)); }); return Object.assign(cvaFn, { className: config.className, __cva__: true, variantMap, variantKeys, raw: resolve, config, splitVariantProps, merge(other) { return cva(mergeCva(this, other)); } }); } function getCompoundVariantCss(cvs, vm) { let result = EMPTY_OBJECT; cvs.forEach((cv) => { const isMatching = Object.entries(cv).every(([key, value]) => { if (key === "css") return true; const values = Array.isArray(value) ? value : [value]; return values.some((value2) => vm[key] === value2); }); if (isMatching) { result = css(result, cv.css); } }); return result; } return cva; } const toRecipeConfig = (cva) => (cva?.__cva__ ? cva.config : cva) ?? EMPTY_OBJECT; function mergeCva(cvaA, cvaB) { const a = defaults(toRecipeConfig(cvaA)); const b = defaults(toRecipeConfig(cvaB)); const variantKeys = uniq(Object.keys(a.variants), Object.keys(b.variants)); const base = mergeWith({}, a.base, b.base); const variants = Object.fromEntries( variantKeys.map((key) => [ key, mergeWith({}, a.variants[key], b.variants[key]) ]) ); const defaultVariants = mergeWith({}, a.defaultVariants, b.defaultVariants); const compoundVariants = [...a.compoundVariants, ...b.compoundVariants]; const className = cx(a.className, b.className); return { className, base, variants, defaultVariants, compoundVariants }; } export { createRecipeFn };