# All files / src/hooks useTheme.ts

95.45% Statements 21/22
93.75% Branches 15/16
100% Functions 5/5
100% Lines 20/20

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

    462x

    462x
    2574x

    2574x
    2574x

    2552x
    440x
    2112x

    1254x

    1254x
    1254x

    858x

    462x

    2574x

    22x
    22x
    22x
    2112x

    22x

    22x

     import { useMemo } from 'react'
    import themeConfig from '../theme.json'

    type ThemeValue = string | number | Record<string, unknown> | unknown[]

    /** Convert a nested theme config object into a flat map of CSS custom properties */
    function flattenTheme(
      obj: Record<string, ThemeValue>,
      prefix = '--'
    ): Record<string, string> {
      const result: Record<string, string> = {}

      for (const [key, value] of Object.entries(obj)) {
        const cssKey = `${prefix}${camelToKebab(key)}`

        Iif (value === null || value === undefined) continue
        if (Array.isArray(value)) continue // skip arrays (e.g. nestedBulletSymbols)

        if (typeof value === 'object') {
          Object.assign(result, flattenTheme(value as Record<string, ThemeValue>, `${cssKey}-`))
        } else if (typeof value === 'number') {
          // Numbers that look like px values get 'px' suffix; ratios/weights don't
          // These are unitless values; everything else gets 'px'
          const isUnitless = /weight|lineHeight|opacity/i.test(key) ||
            cssKey.includes('line-height') ||
            cssKey.includes('font-weight')
          const needsPx = !isUnitless
          result[cssKey] = needsPx ? `${value}px` : String(value)
        } else {
          result[cssKey] = String(value)
        }
      }

      return result
    }

    function camelToKebab(str: string): string {
      return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
    }

    export function useEditorTheme() {
      const { cssVars, styleString } = useMemo(() => {
        const vars = flattenTheme(themeConfig as Record<string, ThemeValue>)
        const str = Object.entries(vars)
          .map(([k, v]) => `${k}: ${v};`)
          .join('\n')
        return { cssVars: vars, styleString: str }
      }, [])

      return { themeConfig, cssVars, styleString }
    }