Enable optimize universal defaults by default (#5635)
* enabled `optimizeUniversalDefaults` by default
This PR is done in a way so that the default is set to `true`, but you
can still disable it if it causes issues. In this case we do appreciate
an issue in that case 😅.
* update tests to use optimized universal selector
* update integration tests
* add dedicated tests for the optimized universal selector
* improve minimumImpactSelector algorithm
I think I cracked the algorithm, but I will probably need another pair
of eyes on the subject.
The current implementation works like this:
Prerequisites:
- The selector should already have been parsed using the selectorParser
from 'postcss-selector-parser'.
Algorithm:
1. Remove all of the pseudo classes from the list of nodes.
1.1. We do want to keep pseudo elements (E.g.: `::before`, `::first-line`, ...)
1.2. We do want to keep pseudo classes that contain nodes (E.g.:
`:not(...)`)
2. Reverse the list of nodes.
This will make it easier to search from the end to the start. For
example `.group:hover .group-hover` should result in `.group-hover`
not `.group`.
2.1. Find the index of the best match (class, id, attribute), and
convert the node if required. (E.g.: `span#app` -> `#app` => `[id="app"]`)
2.2. Remove the rest of the selector that is not important anymore
2.3. Re-join the left-over nodes together
* update tests using new algorithm
* also look for `tag` types
* take `tag` into account
* simplify logic
* add test to prove `rest.reverse()` in first case is required
In case we don't find a match (idx === -1), we use `rest.reverse()`.
However, it looks like you can just use `nodes` instead.
This is not entirely true, because the `rest` variable will contain only
the nodes that are not pseudo elements.
`*:hover` would result in `*:hover` instead of just `*`
* replace all nodes after > with a single universal selector
This commit is contained in:
parent
7b94feaef3
commit
b661614265
11 changed files with 298 additions and 107 deletions
|
|
@ -21,10 +21,9 @@ describe('Build command', () => {
|
|||
// `-i` is omitted, therefore the default `@tailwind base; @tailwind
|
||||
// components; @tailwind utilities` is used. However `preflight` is
|
||||
// disabled. I still want to verify that the `base` got included.
|
||||
expect(contents).toContain('*')
|
||||
expect(contents).toContain('::before')
|
||||
expect(contents).toContain('::after')
|
||||
expect(contents).toContain('--tw-shadow')
|
||||
expect(contents).toContain('--tw-ring-offset-shadow: 0 0 #0000')
|
||||
expect(contents).toContain('--tw-ring-shadow: 0 0 #0000')
|
||||
expect(contents).toContain('--tw-shadow: 0 0 #0000')
|
||||
|
||||
// Verify `utilities` output is correct
|
||||
expect(contents).toIncludeCss(
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
import chalk from 'chalk'
|
||||
import log from './util/log'
|
||||
|
||||
const featureFlags = {
|
||||
let defaults = {
|
||||
optimizeUniversalDefaults: true,
|
||||
}
|
||||
|
||||
let featureFlags = {
|
||||
future: [],
|
||||
experimental: ['optimizeUniversalDefaults'],
|
||||
}
|
||||
|
||||
export function flagEnabled(config, flag) {
|
||||
if (featureFlags.future.includes(flag)) {
|
||||
return config.future === 'all' || (config?.future?.[flag] ?? false)
|
||||
return config.future === 'all' || (config?.future?.[flag] ?? defaults[flag] ?? false)
|
||||
}
|
||||
|
||||
if (featureFlags.experimental.includes(flag)) {
|
||||
return config.experimental === 'all' || (config?.experimental?.[flag] ?? false)
|
||||
return (
|
||||
config.experimental === 'all' || (config?.experimental?.[flag] ?? defaults[flag] ?? false)
|
||||
)
|
||||
}
|
||||
|
||||
return false
|
||||
|
|
@ -34,7 +40,7 @@ export function issueFlagNotices(config) {
|
|||
}
|
||||
|
||||
if (experimentalFlagsEnabled(config).length > 0) {
|
||||
const changes = experimentalFlagsEnabled(config)
|
||||
let changes = experimentalFlagsEnabled(config)
|
||||
.map((s) => chalk.yellow(s))
|
||||
.join(', ')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,60 +2,56 @@ import postcss from 'postcss'
|
|||
import selectorParser from 'postcss-selector-parser'
|
||||
import { flagEnabled } from '../featureFlags'
|
||||
|
||||
function isPseudoElement(n) {
|
||||
if (n.type !== 'pseudo') {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
n.value.startsWith('::') ||
|
||||
[':before', ':after', ':first-line', ':first-letter'].includes(n.value)
|
||||
)
|
||||
let getNode = {
|
||||
id(node) {
|
||||
return selectorParser.attribute({
|
||||
attribute: 'id',
|
||||
operator: '=',
|
||||
value: node.value,
|
||||
quoteMark: '"',
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
function minimumImpactSelector(nodes) {
|
||||
let rest = nodes
|
||||
// Keep all pseudo & combinator types (:not([hidden]) ~ :not([hidden]))
|
||||
.filter((n) => n.type === 'pseudo' || n.type === 'combinator')
|
||||
// Remove leading pseudo's (:hover, :focus, ...)
|
||||
.filter((n, idx, all) => {
|
||||
// Keep pseudo elements
|
||||
if (isPseudoElement(n)) return true
|
||||
.filter((node) => {
|
||||
// Keep non-pseudo nodes
|
||||
if (node.type !== 'pseudo') return true
|
||||
|
||||
if (idx === 0 && n.type === 'pseudo') return false
|
||||
if (idx > 0 && n.type === 'pseudo' && all[idx - 1].type === 'pseudo') return false
|
||||
// Keep pseudo nodes that have subnodes
|
||||
// E.g.: `:not()` contains subnodes inside the parentheses
|
||||
if (node.nodes.length > 0) return true
|
||||
|
||||
return true
|
||||
// Keep pseudo `elements`
|
||||
// This implicitly means that we ignore pseudo `classes`
|
||||
return (
|
||||
node.value.startsWith('::') ||
|
||||
[':before', ':after', ':first-line', ':first-letter'].includes(node.value)
|
||||
)
|
||||
})
|
||||
.reverse()
|
||||
|
||||
let [bestNode] = nodes
|
||||
let searchFor = new Set(['tag', 'class', 'id', 'attribute'])
|
||||
|
||||
for (let [type, getNode = (n) => n] of [
|
||||
['class'],
|
||||
[
|
||||
'id',
|
||||
(n) =>
|
||||
selectorParser.attribute({
|
||||
attribute: 'id',
|
||||
operator: '=',
|
||||
value: n.value,
|
||||
quoteMark: '"',
|
||||
}),
|
||||
],
|
||||
['attribute'],
|
||||
]) {
|
||||
let match = nodes.find((n) => n.type === type)
|
||||
let splitPointIdx = rest.findIndex((n) => searchFor.has(n.type))
|
||||
if (splitPointIdx === -1) return rest.reverse().join('').trim()
|
||||
|
||||
if (match) {
|
||||
bestNode = getNode(match)
|
||||
break
|
||||
}
|
||||
let node = rest[splitPointIdx]
|
||||
let bestNode = getNode[node.type] ? getNode[node.type](node) : node
|
||||
|
||||
rest = rest.slice(0, splitPointIdx)
|
||||
|
||||
let combinatorIdx = rest.findIndex((n) => n.type === 'combinator' && n.value === '>')
|
||||
if (combinatorIdx !== -1) {
|
||||
rest.splice(0, combinatorIdx)
|
||||
rest.unshift(selectorParser.universal())
|
||||
}
|
||||
|
||||
return [bestNode, ...rest].join('').trim()
|
||||
return [bestNode, ...rest.reverse()].join('').trim()
|
||||
}
|
||||
|
||||
let elementSelectorParser = selectorParser((selectors) => {
|
||||
export let elementSelectorParser = selectorParser((selectors) => {
|
||||
return selectors.map((s) => {
|
||||
let nodes = s.split((n) => n.type === 'combinator' && n.value === ' ').pop()
|
||||
return minimumImpactSelector(nodes)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
*,
|
||||
::before,
|
||||
::after {
|
||||
.translate-x-5,
|
||||
.-translate-x-4,
|
||||
.translate-y-6,
|
||||
.-translate-x-3,
|
||||
.rotate-3,
|
||||
.skew-y-12,
|
||||
.skew-x-12,
|
||||
.scale-95,
|
||||
.transform {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -11,12 +17,36 @@
|
|||
--tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))
|
||||
rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y))
|
||||
scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.snap-x {
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
}
|
||||
|
||||
.divide-x-2 > *,
|
||||
.divide-y-4 > *,
|
||||
.divide-x-0 > *,
|
||||
.divide-y-0 > *,
|
||||
.border,
|
||||
.border-2,
|
||||
.border-x-4,
|
||||
.border-y-4,
|
||||
.border-t,
|
||||
.border-b-4 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.shadow,
|
||||
.shadow-md,
|
||||
.shadow-lg {
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
.ring,
|
||||
.ring-4 {
|
||||
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
|
|
@ -24,6 +54,18 @@
|
|||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
.blur-md,
|
||||
.brightness-150,
|
||||
.contrast-50,
|
||||
.drop-shadow-md,
|
||||
.grayscale,
|
||||
.hue-rotate-60,
|
||||
.invert,
|
||||
.saturate-200,
|
||||
.sepia,
|
||||
.filter {
|
||||
--tw-blur: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-brightness: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-contrast: var(--tw-empty, /*!*/ /*!*/);
|
||||
|
|
@ -35,6 +77,18 @@
|
|||
--tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale)
|
||||
var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
||||
.backdrop-blur-lg,
|
||||
.backdrop-brightness-50,
|
||||
.backdrop-contrast-0,
|
||||
.backdrop-grayscale,
|
||||
.backdrop-hue-rotate-90,
|
||||
.backdrop-invert,
|
||||
.backdrop-opacity-75,
|
||||
.backdrop-saturate-150,
|
||||
.backdrop-sepia,
|
||||
.backdrop-filter {
|
||||
--tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/);
|
||||
|
|
@ -351,10 +405,10 @@
|
|||
.columns-md {
|
||||
columns: 28rem;
|
||||
}
|
||||
.break-before-page {
|
||||
.break-before-page {
|
||||
break-before: page;
|
||||
}
|
||||
.break-inside-avoid-column {
|
||||
.break-inside-avoid-column {
|
||||
break-inside: avoid-column;
|
||||
}
|
||||
.break-after-auto {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ test('experimental universal selector improvements (child selectors: divide-y)',
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
.divide-y > :not([hidden]) ~ :not([hidden]) {
|
||||
.divide-y > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ test('experimental universal selector improvements (hover:divide-y)', () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
.hover\\:divide-y > :not([hidden]) ~ :not([hidden]) {
|
||||
.hover\\:divide-y > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ test('experimental universal selector improvements (#app important)', () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
.divide-y > :not([hidden]) ~ :not([hidden]) {
|
||||
.divide-y > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,9 +126,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.scale-50,
|
||||
.transform,
|
||||
.hover\:scale-75 {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -139,9 +139,18 @@
|
|||
--tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))
|
||||
rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y))
|
||||
scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.shadow-sm,
|
||||
.shadow-md,
|
||||
.hover\:shadow-lg,
|
||||
.md\:shadow-sm {
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
.focus\:ring-2 {
|
||||
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
|
|
|
|||
|
|
@ -41,9 +41,7 @@ it('should be possible to matchComponents', () => {
|
|||
|
||||
return run('@tailwind base; @tailwind components; @tailwind utilities', config).then((result) => {
|
||||
return expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.shadow {
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
|
|
|
|||
29
tests/minimum-impact-selector.test.js
Normal file
29
tests/minimum-impact-selector.test.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { elementSelectorParser } from '../src/lib/resolveDefaultsAtRules'
|
||||
|
||||
it.each`
|
||||
before | after
|
||||
${'*'} | ${'*'}
|
||||
${'*:hover'} | ${'*'}
|
||||
${'* > *'} | ${'* > *'}
|
||||
${'.foo'} | ${'.foo'}
|
||||
${'.foo:hover'} | ${'.foo'}
|
||||
${'.foo:focus:hover'} | ${'.foo'}
|
||||
${'li:first-child'} | ${'li'}
|
||||
${'li:before'} | ${'li:before'}
|
||||
${'li::before'} | ${'li::before'}
|
||||
${'#app .foo'} | ${'.foo'}
|
||||
${'#app'} | ${'[id=app]'}
|
||||
${'#app.other'} | ${'.other'}
|
||||
${'input[type="text"]'} | ${'[type="text"]'}
|
||||
${'input[type="text"].foo'} | ${'.foo'}
|
||||
${'.group .group\\:foo'} | ${'.group\\:foo'}
|
||||
${'.group:hover .group-hover\\:foo'} | ${'.group-hover\\:foo'}
|
||||
${'.owl > * + *'} | ${'.owl > *'}
|
||||
${'.owl > :not([hidden]) + :not([hidden])'} | ${'.owl > *'}
|
||||
${'.group:hover .group-hover\\:owl > :not([hidden]) + :not([hidden])'} | ${'.group-hover\\:owl > *'}
|
||||
${'.peer:first-child ~ .peer-first\\:shadow-md'} | ${'.peer-first\\:shadow-md'}
|
||||
${'.whats ~ .next > span:hover'} | ${'span'}
|
||||
${'.foo .bar ~ .baz > .next > span > article:hover'} | ${'article'}
|
||||
`('should generate "$after" from "$before"', ({ before, after }) => {
|
||||
expect(elementSelectorParser.transformSync(before).join(', ')).toEqual(after)
|
||||
})
|
||||
|
|
@ -8,9 +8,7 @@ it('should add the divide styles for divide-y and a default border color', () =>
|
|||
|
||||
return run('@tailwind base; @tailwind utilities;', config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.divide-y > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -32,9 +30,7 @@ it('should add the divide styles for divide-x and a default border color', () =>
|
|||
|
||||
return run('@tailwind base; @tailwind utilities;', config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.divide-x > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -56,9 +52,7 @@ it('should add the divide styles for divide-y-reverse and a default border color
|
|||
|
||||
return run('@tailwind base; @tailwind utilities;', config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.divide-y-reverse > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -78,9 +72,7 @@ it('should add the divide styles for divide-x-reverse and a default border color
|
|||
|
||||
return run('@tailwind base; @tailwind utilities;', config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.divide-x-reverse > * {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -100,9 +92,8 @@ it('should only inject the base styles once if we use divide and border at the s
|
|||
|
||||
return run('@tailwind base; @tailwind utilities;', config).then((result) => {
|
||||
expect(result.css).toMatchCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.divide-y > *,
|
||||
.border-r {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ test('basic utilities', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.rotate-3,
|
||||
.skew-y-6,
|
||||
.scale-x-110 {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -61,9 +61,9 @@ test('with pseudo-class variants', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.hover\\:scale-x-110,
|
||||
.focus\\:rotate-3,
|
||||
.hover\\:focus\\:skew-y-6 {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -106,9 +106,8 @@ test('with pseudo-element variants', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.before\\:scale-x-110::before,
|
||||
.after\\:rotate-3::after {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -149,9 +148,8 @@ test('with multi-class variants', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.group-hover\\:scale-x-110,
|
||||
.peer-focus\\:rotate-3 {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -192,9 +190,8 @@ test('with multi-class pseudo-element variants', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.group-hover\\:before\\:scale-x-110::before,
|
||||
.peer-focus\\:after\\:rotate-3::after {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -241,9 +238,8 @@ test('with multi-class pseudo-element and pseudo-class variants', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.group-hover\\:hover\\:before\\:scale-x-110::before,
|
||||
.peer-focus\\:focus\\:after\\:rotate-3::after {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -327,9 +323,17 @@ test('with apply', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.foo,
|
||||
.bar::before,
|
||||
.baz::before,
|
||||
span,
|
||||
.media-queries,
|
||||
.a,
|
||||
.b,
|
||||
.c,
|
||||
.a::before,
|
||||
.b::after,
|
||||
.recursive {
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
|
|
@ -480,9 +484,8 @@ test('with borders', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.border,
|
||||
.md\\:border-2 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
|
@ -517,12 +520,14 @@ test('with shadows', async () => {
|
|||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
.shadow,
|
||||
.md\\:shadow-xl {
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
.ring-1 {
|
||||
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,110 @@
|
|||
*,
|
||||
::before,
|
||||
::after {
|
||||
.first\:shadow-md,
|
||||
.last\:shadow-md,
|
||||
.only\:shadow-md,
|
||||
.odd\:shadow-md:nth-child(odd),
|
||||
.even\:shadow-md:nth-child(even),
|
||||
.first-of-type\:shadow-md,
|
||||
.last-of-type\:shadow-md,
|
||||
.only-of-type\:shadow-md,
|
||||
.visited\:shadow-md,
|
||||
.target\:shadow-md,
|
||||
.default\:shadow-md,
|
||||
.checked\:shadow-md,
|
||||
.indeterminate\:shadow-md,
|
||||
.placeholder-shown\:shadow-md,
|
||||
.autofill\:shadow-md,
|
||||
.required\:shadow-md,
|
||||
.valid\:shadow-md,
|
||||
.invalid\:shadow-md,
|
||||
.in-range\:shadow-md,
|
||||
.out-of-range\:shadow-md,
|
||||
.read-only\:shadow-md,
|
||||
.empty\:shadow-md,
|
||||
.focus-within\:shadow-md,
|
||||
.hover\:shadow-md,
|
||||
.focus\:shadow-md,
|
||||
.focus\:hover\:shadow-md,
|
||||
.focus-visible\:shadow-md,
|
||||
.active\:shadow-md,
|
||||
.disabled\:shadow-md,
|
||||
.group-first\:shadow-md,
|
||||
.group-last\:shadow-md,
|
||||
.group-only\:shadow-md,
|
||||
.group-odd\:shadow-md,
|
||||
.group-even\:shadow-md,
|
||||
.group-first-of-type\:shadow-md,
|
||||
.group-last-of-type\:shadow-md,
|
||||
.group-only-of-type\:shadow-md,
|
||||
.group-visited\:shadow-md,
|
||||
.group-target\:shadow-md,
|
||||
.group-default\:shadow-md,
|
||||
.group-checked\:shadow-md,
|
||||
.group-indeterminate\:shadow-md,
|
||||
.group-placeholder-shown\:shadow-md,
|
||||
.group-autofill\:shadow-md,
|
||||
.group-required\:shadow-md,
|
||||
.group-valid\:shadow-md,
|
||||
.group-invalid\:shadow-md,
|
||||
.group-in-range\:shadow-md,
|
||||
.group-out-of-range\:shadow-md,
|
||||
.group-read-only\:shadow-md,
|
||||
.group-empty\:shadow-md,
|
||||
.group-focus-within\:shadow-md,
|
||||
.group-hover\:shadow-md,
|
||||
.group-focus\:shadow-md,
|
||||
.group-focus\:group-hover\:shadow-md,
|
||||
.group-focus-visible\:shadow-md,
|
||||
.group-active\:shadow-md,
|
||||
.group-disabled\:shadow-md,
|
||||
.group-disabled\:group-focus\:group-hover\:shadow-md,
|
||||
.group-disabled\:group-focus\:group-hover\:first\:shadow-md,
|
||||
.peer-first\:shadow-md,
|
||||
.peer-last\:shadow-md,
|
||||
.peer-only\:shadow-md,
|
||||
.peer-odd\:shadow-md,
|
||||
.peer-even\:shadow-md,
|
||||
.peer-first-of-type\:shadow-md,
|
||||
.peer-last-of-type\:shadow-md,
|
||||
.peer-only-of-type\:shadow-md,
|
||||
.peer-visited\:shadow-md,
|
||||
.peer-target\:shadow-md,
|
||||
.peer-default\:shadow-md,
|
||||
.peer-checked\:shadow-md,
|
||||
.peer-indeterminate\:shadow-md,
|
||||
.peer-placeholder-shown\:shadow-md,
|
||||
.peer-autofill\:shadow-md,
|
||||
.peer-required\:shadow-md,
|
||||
.peer-valid\:shadow-md,
|
||||
.peer-invalid\:shadow-md,
|
||||
.peer-in-range\:shadow-md,
|
||||
.peer-out-of-range\:shadow-md,
|
||||
.peer-read-only\:shadow-md,
|
||||
.peer-empty\:shadow-md,
|
||||
.peer-focus-within\:shadow-md,
|
||||
.peer-hover\:shadow-md,
|
||||
.peer-focus\:shadow-md,
|
||||
.peer-focus\:peer-hover\:shadow-md,
|
||||
.peer-focus-visible\:shadow-md,
|
||||
.peer-active\:shadow-md,
|
||||
.peer-disabled\:shadow-md,
|
||||
.peer-disabled\:peer-focus\:peer-hover\:shadow-md,
|
||||
.peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md,
|
||||
.ltr\:shadow-md,
|
||||
.rtl\:shadow-md,
|
||||
.motion-safe\:shadow-md,
|
||||
.motion-reduce\:shadow-md,
|
||||
.dark\:shadow-md,
|
||||
.dark\:group-disabled\:group-focus\:group-hover\:shadow-md,
|
||||
.dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md,
|
||||
.sm\:shadow-md,
|
||||
.sm\:active\:shadow-md,
|
||||
.md\:shadow-md,
|
||||
.md\:group-focus\:shadow-md,
|
||||
.lg\:shadow-md,
|
||||
.lg\:dark\:shadow-md,
|
||||
.xl\:shadow-md,
|
||||
.\32xl\:shadow-md,
|
||||
.\32xl\:dark\:motion-safe\:focus-within\:shadow-md {
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue