Bring back named opacity support for color opacity modifiers (#15009)

This PR reverts https://github.com/tailwindlabs/tailwindcss/pull/14278
to bring back support for using named opacity values in color opacity
modifiers:

```css
@theme {
  --opacity-myOpacity: 50%;
}
```

```html
<div class="bg-red-500/myOpacity"></div>
```

We briefly discuss to restructure the code so that we avoid adding a
`theme` argument to the call sites but I do still prefer the current
approach for the following reasons: The way to avoid this is to a) put
something in either the `Theme` class scope, where it feels grossly out
of place, or b) put it into the shared closure in the utilities file
which is already very large and hard to reason. Furthermore, there's a
second call site in the compile function where we would need to
duplicate the namespace lookup.

Every caller of the current `asColor` value already has access to the
`Theme` so passing that as an argument seems like the least intrusive
way.

## Test Plan

Brought back the unit tests but I also tested it with the Vite
extension:

<img width="744" alt="Screenshot 2024-11-15 at 11 15 05"
src="https://github.com/user-attachments/assets/63923b80-767e-4104-b7eb-f71fc815b51e">

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This commit is contained in:
Philipp Spiess 2024-11-15 15:43:12 +01:00 committed by GitHub
parent 953ecd2d19
commit 2a6cd94b38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 19 deletions

View File

@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Nothing yet!
### Changed
- Bring back support for color opacity modifiers to read from `--opacity-*` theme values ([#14278](https://github.com/tailwindlabs/tailwindcss/pull/14278))
## [4.0.0-alpha.34] - 2024-11-14

View File

@ -263,7 +263,7 @@ function compileBaseUtility(candidate: Candidate, designSystem: DesignSystem) {
// Assumption: If an arbitrary property has a modifier, then we assume it
// is an opacity modifier.
if (candidate.modifier) {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, designSystem.theme)
}
if (value === null) return []

View File

@ -10998,7 +10998,19 @@ test('bg', async () => {
`,
['bg-current/half', 'bg-current/custom', '[color:red]/half'],
),
).toEqual('')
).toMatchInlineSnapshot(`
".bg-current\\/custom {
background-color: color-mix(in oklch, currentColor var(--opacity-custom), transparent);
}
.bg-current\\/half {
background-color: color-mix(in oklch, currentColor var(--opacity-half), transparent);
}
.\\[color\\:red\\]\\/half {
color: color-mix(in oklch, red var(--opacity-half), transparent);
}"
`)
})
test('from', async () => {

View File

@ -124,13 +124,24 @@ export function withAlpha(value: string, alpha: string): string {
/**
* Resolve a color value + optional opacity modifier to a final color.
*/
export function asColor(value: string, modifier: CandidateModifier | null): string | null {
export function asColor(
value: string,
modifier: CandidateModifier | null,
theme: Theme,
): string | null {
if (!modifier) return value
if (modifier.kind === 'arbitrary') {
return withAlpha(value, modifier.value)
}
// Check if the modifier exists in the `opacity` theme configuration and use
// that value if so.
let alpha = theme.resolve(modifier.value, ['--opacity'])
if (alpha) {
return withAlpha(value, alpha)
}
if (!isValidOpacityValue(modifier.value)) {
return null
}
@ -182,7 +193,7 @@ function resolveThemeColor<T extends ThemeKey>(
}
}
return value ? asColor(value, candidate.modifier) : null
return value ? asColor(value, candidate.modifier, theme) : null
}
export function createUtilities(theme: Theme) {
@ -340,7 +351,7 @@ export function createUtilities(theme: Theme) {
value = candidate.value.value
// Apply an opacity modifier to the value if appropriate.
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
} else {
value = resolveThemeColor(candidate, theme, desc.themeKeys)
}
@ -2048,7 +2059,7 @@ export function createUtilities(theme: Theme) {
return [borderProperties(), ...decls]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return desc.color(value)
@ -2510,7 +2521,7 @@ export function createUtilities(theme: Theme) {
return [decl('background-image', value)]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('background-color', value)]
@ -2584,7 +2595,7 @@ export function createUtilities(theme: Theme) {
return desc.position(value)
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return desc.color(value)
@ -2721,7 +2732,7 @@ export function createUtilities(theme: Theme) {
if (!candidate.value) return
if (candidate.value.kind === 'arbitrary') {
let value = asColor(candidate.value.value, candidate.modifier)
let value = asColor(candidate.value.value, candidate.modifier, theme)
if (value === null) return
return [decl('fill', value)]
}
@ -2758,7 +2769,7 @@ export function createUtilities(theme: Theme) {
return [decl('stroke-width', value)]
}
default: {
value = asColor(candidate.value.value, candidate.modifier)
value = asColor(candidate.value.value, candidate.modifier, theme)
if (value === null) return
return [decl('stroke', value)]
@ -3002,7 +3013,7 @@ export function createUtilities(theme: Theme) {
return [decl('text-decoration-thickness', value)]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('text-decoration-color', value)]
@ -3880,7 +3891,7 @@ export function createUtilities(theme: Theme) {
]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('outline-color', value)]
@ -4017,7 +4028,7 @@ export function createUtilities(theme: Theme) {
return [decl('font-size', value)]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('color', value)]
@ -4151,7 +4162,7 @@ export function createUtilities(theme: Theme) {
switch (type) {
case 'color': {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [boxShadowProperties(), decl('--tw-shadow-color', value)]
@ -4243,7 +4254,7 @@ export function createUtilities(theme: Theme) {
switch (type) {
case 'color': {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [boxShadowProperties(), decl('--tw-inset-shadow-color', value)]
@ -4341,7 +4352,7 @@ export function createUtilities(theme: Theme) {
]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('--tw-ring-color', value)]
@ -4414,7 +4425,7 @@ export function createUtilities(theme: Theme) {
]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('--tw-inset-ring-color', value)]
@ -4478,7 +4489,7 @@ export function createUtilities(theme: Theme) {
]
}
default: {
value = asColor(value, candidate.modifier)
value = asColor(value, candidate.modifier, theme)
if (value === null) return
return [decl('--tw-ring-offset-color', value)]