Skip to content

Commit

Permalink
Implement the supports variant (#9453)
Browse files Browse the repository at this point in the history
* implement a `supports` variant

* update changelog

* use `--tw` instead of `--tw-empty`
  • Loading branch information
RobinMalfait committed Oct 4, 2022
1 parent 22cd14e commit 7677c59
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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

Expand Down
32 changes: 32 additions & 0 deletions src/corePlugins.js
Expand Up @@ -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 }) => {
Expand Down Expand Up @@ -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)')
Expand Down
1 change: 1 addition & 0 deletions src/lib/setupContextUtils.js
Expand Up @@ -655,6 +655,7 @@ function resolvePlugins(context, root) {
variantPlugins['pseudoClassVariants'],
]
let afterVariants = [
variantPlugins['supportsVariants'],
variantPlugins['directionVariants'],
variantPlugins['reducedMotionVariants'],
variantPlugins['prefersContrastVariants'],
Expand Down
92 changes: 92 additions & 0 deletions tests/arbitrary-variants.test.js
Expand Up @@ -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;
}
}
`)
})
})

0 comments on commit 7677c59

Please sign in to comment.