Skip to content

Commit

Permalink
ensure DEFAULT is taken into account for matchVariant (#9603)
Browse files Browse the repository at this point in the history
This means that if you define your `matchVariant` as:

```js
matchVariant('foo', (value) => '.foo-${value} &')
```

Then you can't use `foo:underline`, if you want to be able to use
`foo:underline` then you have to define a `DEFAULT` value:

```js
matchVariant('foo', (value) => '.foo-${value} &', {
  values: {
    DEFAULT: 'bar'
  }
})
```

Now `foo:underline` will generate `.foo-bar &` as a selector!
  • Loading branch information
RobinMalfait committed Oct 18, 2022
1 parent 24fc365 commit ddb9b4d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/lib/generateRules.js
Expand Up @@ -145,7 +145,7 @@ function applyVariant(variant, matches, context) {
}

/** @type {{modifier: string | null, value: string | null}} */
let args = { modifier: null, value: null }
let args = { modifier: null, value: sharedState.NONE }

// Retrieve "modifier"
{
Expand Down
17 changes: 13 additions & 4 deletions src/lib/setupContextUtils.js
Expand Up @@ -577,6 +577,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')

for (let [key, value] of Object.entries(options?.values ?? {})) {
if (key === 'DEFAULT') continue

api.addVariant(
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
({ args, container }) =>
Expand All @@ -594,13 +596,20 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
)
}

let hasDefault = 'DEFAULT' in (options?.values ?? {})

api.addVariant(
variant,
({ args, container }) =>
variantFn(
args.value,
({ args, container }) => {
if (args.value === sharedState.NONE && !hasDefault) {
return null
}

return variantFn(
args.value === sharedState.NONE ? options.values.DEFAULT : args.value,
modifiersEnabled ? { modifier: args.modifier, container } : { container }
),
)
},
{
...options,
id,
Expand Down
2 changes: 2 additions & 0 deletions src/lib/sharedState.js
Expand Up @@ -8,6 +8,8 @@ export const contextSourcesMap = new Map()
export const sourceHashMap = new Map()
export const NOT_ON_DEMAND = new String('*')

export const NONE = Symbol('__NONE__')

export function resolveDebug(debug) {
if (debug === undefined) {
return false
Expand Down
132 changes: 132 additions & 0 deletions tests/match-variants.test.js
Expand Up @@ -656,3 +656,135 @@ it('should guarantee that we are not passing values from other variants to the w
`)
})
})

it('should default to the DEFAULT value for variants', () => {
let config = {
content: [
{
raw: html`
<div>
<div class="foo:underline"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
plugins: [
({ matchVariant }) => {
matchVariant('foo', (value) => `.foo${value} &`, {
values: {
DEFAULT: '.bar',
},
})
},
],
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.foo.bar .foo\:underline {
text-decoration-line: underline;
}
`)
})
})

it('should not generate anything if the matchVariant does not have a DEFAULT value configured', () => {
let config = {
content: [
{
raw: html`
<div>
<div class="foo:underline"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
plugins: [
({ matchVariant }) => {
matchVariant('foo', (value) => `.foo${value} &`)
},
],
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css``)
})
})

it('should be possible to use `null` as a DEFAULT value', () => {
let config = {
content: [
{
raw: html`
<div>
<div class="foo:underline"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
plugins: [
({ matchVariant }) => {
matchVariant('foo', (value) => `.foo${value === null ? '-good' : '-bad'} &`, {
values: { DEFAULT: null },
})
},
],
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.foo-good .foo\:underline {
text-decoration-line: underline;
}
`)
})
})

it('should be possible to use `undefined` as a DEFAULT value', () => {
let config = {
content: [
{
raw: html`
<div>
<div class="foo:underline"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
plugins: [
({ matchVariant }) => {
matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, {
values: { DEFAULT: undefined },
})
},
],
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.foo-good .foo\:underline {
text-decoration-line: underline;
}
`)
})
})

0 comments on commit ddb9b4d

Please sign in to comment.