import { describe, expect, test } from 'vitest'
import { buildDesignSystem } from '../../design-system'
import { Theme } from '../../theme'
import { createCompatConfig } from './create-compat-config'
import { resolveConfig } from './resolve-config'
function buildCompatConfig(cssValues: Record<string, string>) {
let theme = new Theme()
for (let [key, value] of Object.entries(cssValues)) {
theme.add(key, value)
}
let design = buildDesignSystem(theme)
let { resolvedConfig } = resolveConfig(design, [
{ config: createCompatConfig(design.theme), base: '/root', reference: true, src: undefined },
])
return resolvedConfig
}
describe('theme namespace lookups', () => {
test('a namespace that only defines a bare value resolves to `{ DEFAULT: … }`, not a string', () => {
let config = buildCompatConfig({ '--text': '1rem' })
expect(config.theme?.fontSize?.DEFAULT).toBe('1rem')
expect(config.theme?.fontSize).not.toHaveProperty('0')
})
test('a bare value is kept alongside suffixed values in the same namespace', () => {
let config = buildCompatConfig({
'--text': '1rem',
'--text-sm': '0.875rem',
})
expect(config.theme?.fontSize?.DEFAULT).toBe('1rem')
expect(config.theme?.fontSize?.sm).toBe('0.875rem')
})
test('a naive spread of a theme namespace in a user config is safe', () => {
let theme = new Theme()
theme.add('--text', '1rem')
let design = buildDesignSystem(theme)
let { resolvedConfig } = resolveConfig(design, [
{
config: {
theme: {
extend: {
fontSize: ({ theme }: any) => ({ ...theme('text', {}) }),
},
},
},
base: '/root',
reference: true,
src: undefined,
},
])
expect(resolvedConfig.theme?.fontSize?.DEFAULT).toBe('1rem')
expect(resolvedConfig.theme?.fontSize).not.toHaveProperty('0')
})
test('namespace root lookups resolve to an object, key lookups resolve to the value', () => {
let theme = new Theme()
theme.add('--text', '1rem')
theme.add('--animate-spin', 'spin 1s linear infinite')
let design = buildDesignSystem(theme)
let root: unknown
let rootWithDefault: unknown
let leaf: unknown
resolveConfig(design, [
{
config: {
theme: {
extend: {
fontSize: ({ theme }: any) => {
root = theme('text')
rootWithDefault = theme('text', {})
leaf = theme('animate.spin')
return {}
},
},
},
},
base: '/root',
reference: true,
src: undefined,
},
])
expect(root).toMatchObject({ DEFAULT: '1rem' })
expect(rootWithDefault).toMatchObject({ DEFAULT: '1rem' })
expect(leaf).toBe('spin 1s linear infinite')
})
test('lookups of a specific key still resolve to the value itself', () => {
let theme = new Theme()
theme.add('--animate-spin', 'spin 1s linear infinite')
let design = buildDesignSystem(theme)
let { resolvedConfig } = resolveConfig(design, [
{
config: {
theme: {
extend: {
animation: ({ theme }: any) => ({ spin: theme('animate.spin') }),
},
},
},
base: '/root',
reference: true,
src: undefined,
},
])
expect(resolvedConfig.theme?.animation?.spin).toBe('spin 1s linear infinite')
})
})
describe('createCompatConfig namespace mappings', () => {
test('fontSize maps from CSS text namespace', () => {
let config = buildCompatConfig({ '--text-base': '1rem' })
expect(config.theme?.fontSize?.base).toBe('1rem')
})
test('boxShadow maps from CSS shadow namespace', () => {
let config = buildCompatConfig({ '--shadow-md': '0 4px 6px #000' })
expect(config.theme?.boxShadow?.md).toBe('0 4px 6px #000')
})
test('animation maps from CSS animate namespace', () => {
let config = buildCompatConfig({ '--animate-spin': 'spin 1s linear infinite' })
expect(config.theme?.animation?.spin).toBe('spin 1s linear infinite')
})
test('aspectRatio maps from CSS aspect namespace', () => {
let config = buildCompatConfig({ '--aspect-square': '1 / 1' })
expect(config.theme?.aspectRatio?.square).toBe('1 / 1')
})
test('borderRadius maps from CSS radius namespace', () => {
let config = buildCompatConfig({ '--radius-lg': '0.5rem' })
expect(config.theme?.borderRadius?.lg).toBe('0.5rem')
})
test('screens maps from CSS breakpoint namespace', () => {
let config = buildCompatConfig({ '--breakpoint-sm': '640px' })
expect(config.theme?.screens?.sm).toBe('640px')
})
test('letterSpacing maps from CSS tracking namespace', () => {
let config = buildCompatConfig({ '--tracking-wide': '0.025em' })
expect(config.theme?.letterSpacing?.wide).toBe('0.025em')
})
test('lineHeight maps from CSS leading namespace', () => {
let config = buildCompatConfig({ '--leading-relaxed': '1.75' })
expect(config.theme?.lineHeight?.relaxed).toBe('1.75')
})
test('maxWidth maps from the container namespace in the default theme', () => {
let config = buildCompatConfig({})
expect(config.theme?.maxWidth?.sm).toBe('24rem')
})
test('transitionDuration gets DEFAULT from --default-transition-duration', () => {
let config = buildCompatConfig({ '--default-transition-duration': '150ms' })
expect(config.theme?.transitionDuration?.DEFAULT).toBe('150ms')
})
test('transitionTimingFunction gets DEFAULT from --default-transition-timing-function', () => {
let config = buildCompatConfig({
'--default-transition-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)',
})
expect(config.theme?.transitionTimingFunction?.DEFAULT).toBe('cubic-bezier(0.4, 0, 0.2, 1)')
})
})