Home / Function/ resolveValueFunction() — tailwindcss Function Reference

resolveValueFunction() — tailwindcss Function Reference

Architecture documentation for the resolveValueFunction() function in utilities.ts from the tailwindcss codebase.

Entity Profile

Dependency Diagram

graph TD
  84f8ccf2_2af5_fa7c_53f2_954b21183738["resolveValueFunction()"]
  5c9381d6_815c_d899_eaab_849d755be47e["createCssUtility()"]
  5c9381d6_815c_d899_eaab_849d755be47e -->|calls| 84f8ccf2_2af5_fa7c_53f2_954b21183738
  0638028e_f2f7_8e77_2f19_1bd2ce4b2d6a["parse()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| 0638028e_f2f7_8e77_2f19_1bd2ce4b2d6a
  fb0edc12_e3ff_ec56_83b9_8cf4f1b5f8e5["resolve()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| fb0edc12_e3ff_ec56_83b9_8cf4f1b5f8e5
  50b26c27_6fae_3a51_c382_756098b9ce8a["resolveWith()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| 50b26c27_6fae_3a51_c382_756098b9ce8a
  1cdf00e9_c049_9259_0b0d_59a06c397532["inferDataType()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| 1cdf00e9_c049_9259_0b0d_59a06c397532
  2a20ea29_c850_cd61_5600_aeebbe3dda66["segment()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| 2a20ea29_c850_cd61_5600_aeebbe3dda66
  559275a8_927e_3002_3298_4cbb685cc92a["isPositiveInteger()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| 559275a8_927e_3002_3298_4cbb685cc92a
  c12acffb_80f9_0b95_b1a6_e663fbaca197["isValidSpacingMultiplier()"]
  84f8ccf2_2af5_fa7c_53f2_954b21183738 -->|calls| c12acffb_80f9_0b95_b1a6_e663fbaca197
  style 84f8ccf2_2af5_fa7c_53f2_954b21183738 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

packages/tailwindcss/src/utilities.ts lines 6303–6445

function resolveValueFunction(
  value: NonNullable<
    | Extract<Candidate, { kind: 'functional' }>['value']
    | Extract<Candidate, { kind: 'functional' }>['modifier']
  >,
  fn: ValueParser.ValueFunctionNode,
  designSystem: DesignSystem,
): { nodes: ValueParser.ValueAstNode[]; ratio?: boolean } | undefined {
  for (let arg of fn.nodes) {
    // Resolve literal value, e.g.: `--modifier('closest-side')`
    if (
      value.kind === 'named' &&
      arg.kind === 'word' &&
      // Should be wreapped in quotes
      (arg.value[0] === "'" || arg.value[0] === '"') &&
      arg.value[arg.value.length - 1] === arg.value[0] &&
      // Values should match
      arg.value.slice(1, -1) === value.value
    ) {
      return { nodes: ValueParser.parse(value.value) }
    }

    // Resolving theme value, e.g.: `--value(--color)`
    else if (
      value.kind === 'named' &&
      arg.kind === 'word' &&
      arg.value[0] === '-' &&
      arg.value[1] === '-'
    ) {
      let themeKey = arg.value as `--${string}`

      // Resolve the theme value, e.g.: `--value(--color)`
      if (themeKey.endsWith('-*')) {
        // Without `-*` postfix
        themeKey = themeKey.slice(0, -2) as `--${string}`

        let resolved = designSystem.theme.resolve(value.value, [themeKey])
        if (resolved) return { nodes: ValueParser.parse(resolved) }
      }

      // Split `--text-*--line-height` into `--text` and `--line-height`
      else {
        let nestedKeys = themeKey.split('-*') as `--${string}`[]
        if (nestedKeys.length <= 1) continue

        // Resolve theme values with nested keys, e.g.: `--value(--text-*--line-height)`
        let themeKeys = [nestedKeys.shift()!]
        let resolved = designSystem.theme.resolveWith(value.value, themeKeys, nestedKeys)
        if (resolved) {
          let [, options = {}] = resolved

          // Resolve the value from the `options`
          {
            let resolved = options[nestedKeys.pop()!]
            if (resolved) return { nodes: ValueParser.parse(resolved) }
          }
        }
      }
    }

    // Bare value, e.g.: `--value(integer)`
    else if (value.kind === 'named' && arg.kind === 'word') {
      // Limit the bare value types, to prevent new syntax that we
      // don't want to support. E.g.: `text-#000` is something we
      // don't want to support, but could be built this way.
      if (!BARE_VALUE_DATA_TYPES.includes(arg.value)) {
        continue
      }

      let resolved = arg.value === 'ratio' && 'fraction' in value ? value.fraction : value.value
      if (!resolved) continue

      let type = inferDataType(resolved, [arg.value as any])
      if (type === null) continue

      // Ratio must be a valid fraction, e.g.: <integer>/<integer>
      if (type === 'ratio') {
        let [lhs, rhs] = segment(resolved, '/').map(Number)
        if (!isPositiveInteger(lhs) || !isPositiveInteger(rhs)) continue
      }

      // Non-integer numbers should be a valid multiplier,
      // e.g.: `1.5`
      else if (type === 'number' && !isValidSpacingMultiplier(resolved)) {
        continue
      }

      // Percentages must be an integer, e.g.: `50%`
      else if (type === 'percentage' && !isPositiveInteger(resolved.slice(0, -1))) {
        continue
      }

      if (type === 'ratio') {
        let [lhs, rhs] = segment(resolved, '/')
        return { nodes: ValueParser.parse(`${lhs.trim()} / ${rhs.trim()}`), ratio: true }
      }

      return { nodes: ValueParser.parse(resolved), ratio: false }
    }

    // Arbitrary value, e.g.: `--value([integer])`
    else if (
      value.kind === 'arbitrary' &&
      arg.kind === 'word' &&
      arg.value[0] === '[' &&
      arg.value[arg.value.length - 1] === ']'
    ) {
      let dataType = arg.value.slice(1, -1)

      // Allow any data type, e.g.: `--value([*])`
      if (dataType === '*') {
        return { nodes: ValueParser.parse(value.value) }
      }

      // The forced arbitrary value hint must match the expected
      // data type.
      //
      // ```css
      // @utility tab-* {
      //   tab-size: --value([integer]);
      // }
      // ```
      //
      // Given a candidate like `tab-(color:var(--my-value))`,
      // should not match because `color` and `integer` don't
      // match.
      if ('dataType' in value && value.dataType && value.dataType !== dataType) {
        continue
      }

      // Use the provided data type hint
      if ('dataType' in value && value.dataType) {
        return { nodes: ValueParser.parse(value.value) }
      }

      // No data type hint provided, so we have to infer it
      let type = inferDataType(value.value, [dataType as any])
      if (type !== null) {
        return { nodes: ValueParser.parse(value.value) }
      }
    }
  }
}

Subdomains

Called By

Frequently Asked Questions

What does resolveValueFunction() do?
resolveValueFunction() is a function in the tailwindcss codebase.
What does resolveValueFunction() call?
resolveValueFunction() calls 7 function(s): inferDataType, isPositiveInteger, isValidSpacingMultiplier, parse, resolve, resolveWith, segment.
What calls resolveValueFunction()?
resolveValueFunction() is called by 1 function(s): createCssUtility.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free