Support alpha values for theme() function (#8416)
* Fix typo * Support alpha modifier for theme color values * Eliminate redundant object creation in resolveFunctionKeys Building an object of N keys incrementally using Object.reduce + splat results in N intermediate objects. We should just create one object and assign each key. * Switch to inline theme values in theme fn in config * Add test case And fix typos that were definitely not there * Update changelog
This commit is contained in:
parent
22f9dc8895
commit
50bed74cdc
8 changed files with 542 additions and 35 deletions
|
|
@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Add `matchVariant` API ([#8310](https://github.com/tailwindlabs/tailwindcss/pull/8310))
|
||||
- Add `prefers-contrast` media query variants ([#8410](https://github.com/tailwindlabs/tailwindcss/pull/8410))
|
||||
- Experimental support for variant grouping ([#8405](https://github.com/tailwindlabs/tailwindcss/pull/8405))
|
||||
- Add opacity support when referencing colors with `theme` function ([#8416](https://github.com/tailwindlabs/tailwindcss/pull/8416))
|
||||
|
||||
## [3.0.24] - 2022-04-12
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import parseValue from 'postcss-value-parser'
|
|||
import { normalizeScreens } from '../util/normalizeScreens'
|
||||
import buildMediaQuery from '../util/buildMediaQuery'
|
||||
import { toPath } from '../util/toPath'
|
||||
import { withAlphaValue } from '../util/withAlphaVariable'
|
||||
|
||||
function isObject(input) {
|
||||
return typeof input === 'object' && input !== null
|
||||
|
|
@ -37,7 +38,7 @@ function listKeys(obj) {
|
|||
return list(Object.keys(obj))
|
||||
}
|
||||
|
||||
function validatePath(config, path, defaultValue) {
|
||||
function validatePath(config, path, defaultValue, themeOpts = {}) {
|
||||
const pathString = Array.isArray(path)
|
||||
? pathToString(path)
|
||||
: path.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
|
||||
|
|
@ -114,7 +115,7 @@ function validatePath(config, path, defaultValue) {
|
|||
|
||||
return {
|
||||
isValid: true,
|
||||
value: transformThemeValue(themeSection)(value),
|
||||
value: transformThemeValue(themeSection)(value, themeOpts),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,16 +161,29 @@ let nodeTypePropertyMap = {
|
|||
export default function ({ tailwindConfig: config }) {
|
||||
let functions = {
|
||||
theme: (node, path, ...defaultValue) => {
|
||||
const { isValid, value, error } = validatePath(
|
||||
let matches = path.match(/^([^\/\s]+)(?:\s*\/\s*([^\/\s]+))$/)
|
||||
let alpha = undefined
|
||||
|
||||
if (matches) {
|
||||
path = matches[1]
|
||||
alpha = matches[2]
|
||||
}
|
||||
|
||||
let { isValid, value, error } = validatePath(
|
||||
config,
|
||||
path,
|
||||
defaultValue.length ? defaultValue : undefined
|
||||
defaultValue.length ? defaultValue : undefined,
|
||||
{ opacityValue: alpha }
|
||||
)
|
||||
|
||||
if (!isValid) {
|
||||
throw node.error(error)
|
||||
}
|
||||
|
||||
if (alpha !== undefined) {
|
||||
value = withAlphaValue(value, alpha, value)
|
||||
}
|
||||
|
||||
return value
|
||||
},
|
||||
screen: (node, screen) => {
|
||||
|
|
|
|||
|
|
@ -221,16 +221,25 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|||
return context.tailwindConfig.prefix + identifier
|
||||
}
|
||||
|
||||
function resolveThemeValue(path, defaultValue, opts = {}) {
|
||||
const [pathRoot, ...subPaths] = toPath(path)
|
||||
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
||||
return transformThemeValue(pathRoot)(value, opts)
|
||||
}
|
||||
|
||||
const theme = Object.assign(
|
||||
(path, defaultValue = undefined) => resolveThemeValue(path, defaultValue),
|
||||
{
|
||||
withAlpha: (path, opacityValue) => resolveThemeValue(path, undefined, { opacityValue }),
|
||||
}
|
||||
)
|
||||
|
||||
let api = {
|
||||
postcss,
|
||||
prefix: applyConfiguredPrefix,
|
||||
e: escapeClassName,
|
||||
config: getConfigValue,
|
||||
theme(path, defaultValue) {
|
||||
const [pathRoot, ...subPaths] = toPath(path)
|
||||
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
||||
return transformThemeValue(pathRoot)(value)
|
||||
},
|
||||
theme,
|
||||
corePlugins: (path) => {
|
||||
if (Array.isArray(tailwindConfig.corePlugins)) {
|
||||
return tailwindConfig.corePlugins.includes(path)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { toPath } from './toPath'
|
|||
import { normalizeConfig } from './normalizeConfig'
|
||||
import isPlainObject from './isPlainObject'
|
||||
import { cloneDeep } from './cloneDeep'
|
||||
import { withAlphaValue } from './withAlphaVariable'
|
||||
|
||||
function isFunction(input) {
|
||||
return typeof input === 'function'
|
||||
|
|
@ -164,40 +165,81 @@ function mergeExtensions({ extend, ...theme }) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} key
|
||||
* @return {Iterable<string[] & {alpha: string | undefined}>}
|
||||
*/
|
||||
function* toPaths(key) {
|
||||
let path = toPath(key)
|
||||
|
||||
if (path.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
yield path
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
return
|
||||
}
|
||||
|
||||
let pattern = /^(.*?)\s*\/\s*([^/]+)$/
|
||||
let matches = key.match(pattern)
|
||||
|
||||
if (matches !== null) {
|
||||
let [, prefix, alpha] = matches
|
||||
|
||||
let newPath = toPath(prefix)
|
||||
newPath.alpha = alpha
|
||||
|
||||
yield newPath
|
||||
}
|
||||
}
|
||||
|
||||
function resolveFunctionKeys(object) {
|
||||
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
|
||||
|
||||
const resolvePath = (key, defaultValue) => {
|
||||
const path = toPath(key)
|
||||
for (const path of toPaths(key)) {
|
||||
let index = 0
|
||||
let val = object
|
||||
|
||||
let index = 0
|
||||
let val = object
|
||||
while (val !== undefined && val !== null && index < path.length) {
|
||||
val = val[path[index++]]
|
||||
|
||||
while (val !== undefined && val !== null && index < path.length) {
|
||||
val = val[path[index++]]
|
||||
val = isFunction(val) ? val(resolvePath, configUtils) : val
|
||||
let shouldResolveAsFn =
|
||||
isFunction(val) && (path.alpha === undefined || index < path.length - 1)
|
||||
|
||||
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val
|
||||
}
|
||||
|
||||
if (val !== undefined) {
|
||||
if (path.alpha !== undefined) {
|
||||
return withAlphaValue(val, path.alpha)
|
||||
}
|
||||
|
||||
if (isPlainObject(val)) {
|
||||
return cloneDeep(val)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
if (val === undefined) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
if (isPlainObject(val)) {
|
||||
return cloneDeep(val)
|
||||
}
|
||||
|
||||
return val
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
resolvePath.theme = resolvePath
|
||||
// colors.red.500/50
|
||||
|
||||
for (let key in configUtils) {
|
||||
resolvePath[key] = configUtils[key]
|
||||
}
|
||||
Object.assign(resolvePath, {
|
||||
theme: resolvePath,
|
||||
...configUtils,
|
||||
})
|
||||
|
||||
return Object.keys(object).reduce((resolved, key) => {
|
||||
return {
|
||||
...resolved,
|
||||
[key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key],
|
||||
}
|
||||
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key]
|
||||
|
||||
return resolved
|
||||
}, {})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
|
||||
*
|
||||
* Example:
|
||||
* a -> ['a]
|
||||
* a -> ['a']
|
||||
* a.b.c -> ['a', 'b', 'c']
|
||||
* a[b].c -> ['a', 'b', 'c']
|
||||
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
|
||||
|
|
|
|||
|
|
@ -44,8 +44,10 @@ export default function transformThemeValue(themeSection) {
|
|||
}
|
||||
}
|
||||
|
||||
return (value) => {
|
||||
if (typeof value === 'function') value = value({})
|
||||
return (value, opts = {}) => {
|
||||
if (typeof value === 'function') {
|
||||
value = value(opts)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
import postcss from 'postcss'
|
||||
import plugin from '../src/lib/evaluateTailwindFunctions'
|
||||
import tailwind from '../src/index'
|
||||
import { css } from './util/run'
|
||||
|
||||
function run(input, opts = {}) {
|
||||
return postcss([plugin({ tailwindConfig: opts })]).process(input, { from: undefined })
|
||||
}
|
||||
|
||||
function runFull(input, config) {
|
||||
return postcss([tailwind(config)]).process(input, { from: undefined })
|
||||
}
|
||||
|
||||
test('it looks up values in the theme using dot notation', () => {
|
||||
let input = css`
|
||||
.banana {
|
||||
|
|
@ -817,3 +822,205 @@ test('screen arguments can be quoted', () => {
|
|||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (1)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: rgb(59 130 246 / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (2)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: rgb(59 130 246 / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (3)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: rgb(59 130 246 / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (4)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: hsl(217 91% 60% / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: {
|
||||
blue: { 500: 'hsl(217, 91%, 60%)' },
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (5)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: hsl(217 91% 60% / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: {
|
||||
blue: { 500: 'hsl(217, 91%, 60%)' },
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (6)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: hsl(217 91% 60% / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
colors: {
|
||||
blue: { 500: 'hsl(217, 91%, 60%)' },
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (7)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: rgb(var(--foo) / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return runFull(input, {
|
||||
theme: {
|
||||
colors: ({ rgb }) => ({
|
||||
blue: {
|
||||
500: rgb('--foo'),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function can extract alpha values for colors (8)', () => {
|
||||
let input = css`
|
||||
.foo {
|
||||
color: theme(colors.blue.500 / theme(opacity.myalpha));
|
||||
}
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.foo {
|
||||
color: rgb(var(--foo) / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
return runFull(input, {
|
||||
theme: {
|
||||
colors: ({ rgb }) => ({
|
||||
blue: {
|
||||
500: rgb('--foo'),
|
||||
},
|
||||
}),
|
||||
|
||||
opacity: {
|
||||
myalpha: '50%',
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -427,3 +427,235 @@ it('the hsl helper throws when not passing custom properties', () => {
|
|||
'The hsl() helper requires a custom property name to be passed as the first argument.'
|
||||
)
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (1)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: rgb(59 130 246 / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / 50%'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (2)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: rgb(59 130 246 / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / 0.5'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (3)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: rgb(59 130 246 / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: '#3b82f6' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / var(--my-alpha)'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (4)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: hsl(217 91% 60% / 50%);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / 50%'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (5)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: hsl(217 91% 60% / 0.5);
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / 0.5'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (6)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: hsl(217 91% 60% / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: { blue: { 500: 'hsl(217, 91%, 60%)' } },
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / var(--my-alpha)'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function in JS can apply alpha values to colors (7)', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: rgb(var(--foo) / var(--my-alpha));
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: ({ rgb }) => ({
|
||||
blue: {
|
||||
500: rgb('--foo'),
|
||||
},
|
||||
}),
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / var(--my-alpha)'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('Theme function prefers existing values in config', () => {
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
let output = css`
|
||||
.text-foo {
|
||||
color: purple;
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
content: [{ raw: html`text-foo` }],
|
||||
corePlugins: { textOpacity: false },
|
||||
theme: {
|
||||
colors: {
|
||||
blue: {
|
||||
'500 / 50%': 'purple',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
textColor: ({ theme }) => ({
|
||||
foo: theme('colors.blue.500 / 50%'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).then((result) => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue