Implement the supports variant (#9453)
* implement a `supports` variant * update changelog * use `--tw` instead of `--tw-empty`
This commit is contained in:
parent
22cd14e331
commit
7677c593ec
4 changed files with 126 additions and 0 deletions
|
|
@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Add `@config` support ([#9405](https://github.com/tailwindlabs/tailwindcss/pull/9405))
|
||||
- Add `fill-none` and `stroke-none` utilities by default ([#9403](https://github.com/tailwindlabs/tailwindcss/pull/9403))
|
||||
- Support `sort` function in `matchVariant` ([#9423](https://github.com/tailwindlabs/tailwindcss/pull/9423))
|
||||
- Implement the `supports` variant ([#9453](https://github.com/tailwindlabs/tailwindcss/pull/9453))
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { normalizeScreens } from './util/normalizeScreens'
|
|||
import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadowValue'
|
||||
import { removeAlphaVariables } from './util/removeAlphaVariables'
|
||||
import { flagEnabled } from './featureFlags'
|
||||
import { normalize } from './util/dataTypes'
|
||||
|
||||
export let variantPlugins = {
|
||||
pseudoElementVariants: ({ addVariant }) => {
|
||||
|
|
@ -215,6 +216,37 @@ export let variantPlugins = {
|
|||
}
|
||||
},
|
||||
|
||||
supportsVariants: ({ matchVariant, theme, config }) => {
|
||||
if (!flagEnabled(config(), 'matchVariant')) return
|
||||
|
||||
matchVariant(
|
||||
'supports',
|
||||
({ value = '' }) => {
|
||||
let check = normalize(value)
|
||||
let isRaw = /^\w*\s*\(/.test(check)
|
||||
|
||||
// Chrome has a bug where `(condtion1)or(condition2)` is not valid
|
||||
// But `(condition1) or (condition2)` is supported.
|
||||
check = isRaw ? check.replace(/\b(and|or|not)\b/g, ' $1 ') : check
|
||||
|
||||
if (isRaw) {
|
||||
return `@supports ${check}`
|
||||
}
|
||||
|
||||
if (!check.includes(':')) {
|
||||
check = `${check}: var(--tw)`
|
||||
}
|
||||
|
||||
if (!(check.startsWith('(') && check.endsWith(')'))) {
|
||||
check = `(${check})`
|
||||
}
|
||||
|
||||
return `@supports ${check} `
|
||||
},
|
||||
{ values: theme('supports') ?? {} }
|
||||
)
|
||||
},
|
||||
|
||||
orientationVariants: ({ addVariant }) => {
|
||||
addVariant('portrait', '@media (orientation: portrait)')
|
||||
addVariant('landscape', '@media (orientation: landscape)')
|
||||
|
|
|
|||
|
|
@ -655,6 +655,7 @@ function resolvePlugins(context, root) {
|
|||
variantPlugins['pseudoClassVariants'],
|
||||
]
|
||||
let afterVariants = [
|
||||
variantPlugins['supportsVariants'],
|
||||
variantPlugins['directionVariants'],
|
||||
variantPlugins['reducedMotionVariants'],
|
||||
variantPlugins['prefersContrastVariants'],
|
||||
|
|
|
|||
|
|
@ -615,3 +615,95 @@ test('classes in the same arbitrary variant should not be prefixed', () => {
|
|||
`)
|
||||
})
|
||||
})
|
||||
|
||||
it('should support supports', () => {
|
||||
let config = {
|
||||
experimental: { matchVariant: true },
|
||||
theme: {
|
||||
supports: {
|
||||
grid: 'display: grid',
|
||||
},
|
||||
},
|
||||
content: [
|
||||
{
|
||||
raw: html`
|
||||
<div>
|
||||
<!-- Property check -->
|
||||
<div class="supports-[display:grid]:grid"></div>
|
||||
<!-- Value with spaces, needs to be normalized -->
|
||||
<div class="supports-[transform-origin:5%_5%]:underline"></div>
|
||||
<!-- Selectors (raw) -->
|
||||
<div class="supports-[selector(A>B)]:underline"></div>
|
||||
<!-- 'not' check (raw) -->
|
||||
<div class="supports-[not(foo:bar)]:underline"></div>
|
||||
<!-- 'or' check (raw) -->
|
||||
<div class="supports-[(foo:bar)or(bar:baz)]:underline"></div>
|
||||
<!-- 'and' check (raw) -->
|
||||
<div class="supports-[(foo:bar)and(bar:baz)]:underline"></div>
|
||||
<!-- No value give for the property, defaulting to prop: var(--tw) -->
|
||||
<div class="supports-[container-type]:underline"></div>
|
||||
<!-- Named supports usage -->
|
||||
<div class="supports-grid:underline"></div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
@supports (display: grid) {
|
||||
.supports-grid\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (display: grid) {
|
||||
.supports-\[display\:grid\]\:grid {
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (transform-origin: 5% 5%) {
|
||||
.supports-\[transform-origin\:5\%_5\%\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports selector(A > B) {
|
||||
.supports-\[selector\(A\>B\)\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not (foo: bar) {
|
||||
.supports-\[not\(foo\:bar\)\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (foo: bar) or (bar: baz) {
|
||||
.supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (foo: bar) and (bar: baz) {
|
||||
.supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (container-type: var(--tw)) {
|
||||
.supports-\[container-type\]\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue