All files / web/styled-system/css cva.mjs

11.49% Statements 10/87
100% Branches 0/0
0% Functions 0/4
11.49% Lines 10/87

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 881x 1x 1x 1x             1x 1x                                                                                                       1x 1x                                 1x 1x          
import { compact, mergeProps, memo, splitProps, uniq } from '../helpers.mjs';
import { css, mergeCss } from './css.mjs';
 
const defaults = (conf) => ({
  base: {},
  variants: {},
  defaultVariants: {},
  compoundVariants: [],
  ...conf,
})
 
export function cva(config) {
  const { base, variants, defaultVariants, compoundVariants } = defaults(config)
  const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })

  function resolve(props = {}) {
    const computedVariants = getVariantProps(props)
    let variantCss = { ...base }
    for (const [key, value] of Object.entries(computedVariants)) {
      if (variants[key]?.[value]) {
        variantCss = mergeCss(variantCss, variants[key][value])
      }
    }
    const compoundVariantCss = getCompoundVariantCss(compoundVariants, computedVariants)
    return mergeCss(variantCss, compoundVariantCss)
  }

  function merge(__cva) {
    const override = defaults(__cva.config)
    const variantKeys = uniq(__cva.variantKeys, Object.keys(variants))
    return cva({
      base: mergeCss(base, override.base),
      variants: Object.fromEntries(
        variantKeys.map((key) => [key, mergeCss(variants[key], override.variants[key])]),
      ),
      defaultVariants: mergeProps(defaultVariants, override.defaultVariants),
      compoundVariants: [...compoundVariants, ...override.compoundVariants],
    })
  }

  function cvaFn(props) {
    return css(resolve(props))
  }

  const variantKeys = Object.keys(variants)

  function splitVariantProps(props) {
    return splitProps(props, variantKeys)
  }

  const variantMap = Object.fromEntries(Object.entries(variants).map(([key, value]) => [key, Object.keys(value)]))

  return Object.assign(memo(cvaFn), {
    __cva__: true,
    variantMap,
    variantKeys,
    raw: resolve,
    config,
    merge,
    splitVariantProps,
    getVariantProps
  })
}
 
export function getCompoundVariantCss(compoundVariants, variantMap) {
  let result = {}
  compoundVariants.forEach((compoundVariant) => {
    const isMatching = Object.entries(compoundVariant).every(([key, value]) => {
      if (key === 'css') return true

      const values = Array.isArray(value) ? value : [value]
      return values.some((value) => variantMap[key] === value)
    })

    if (isMatching) {
      result = mergeCss(result, compoundVariant.css)
    }
  })

  return result
}
 
export function assertCompoundVariant(name, compoundVariants, variants, prop) {
  if (compoundVariants.length > 0 && typeof variants?.[prop] === 'object') {
    throw new Error(`[recipe:${name}:${prop}] Conditions are not supported when using compound variants.`)
  }
}