Skip to content

Commit

Permalink
Ensure --inset-ring=* and --inset-shadow-* variables are ignored …
Browse files Browse the repository at this point in the history
…by `inset-*` utilities (#14855)

This PR fixes a issue where utilities like `inset-x-*`, `left-*`,
`top-*`, etc. mistakenly pull values from the `--inset-ring-*` and
`--inset-shadow-*` theme namespaces.

For example, the class `left-shadow-sm` currently generates this CSS:

```css
.left-shadow-sm {
  left: var(
    --inset-shadow-sm,
    inset 0 1px 1px rgb(0 0 0 / 0.05)
  );
}
```

This happens because the `--inset-ring-*` and `--inset-shadow-*`
namespaces collide with the `--inset-*` namespace.

We were already handling this manually for just the `inset-*` utilities
but didn't realize we needed to handle it for every related utility, so
this PR fixes that.

This also fixes an issue where IntelliSense would suggest classes like
`inset-x-shadow-sm` when they shouldn't actually exist.

To do this we've created this new concept of `ignoredThemeKeys` in the
relevant APIs to make sure these are filtered out at the source.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
  • Loading branch information
adamwathan and adamwathan authored Nov 1, 2024
1 parent 63b321b commit cf77420
Show file tree
Hide file tree
Showing 5 changed files with 461 additions and 177 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Detect classes in new files when using `@tailwindcss/postcss` ([#14829](https://github.com/tailwindlabs/tailwindcss/pull/14829))
- Fix crash when using `@source` containing `..` ([#14831](https://github.com/tailwindlabs/tailwindcss/pull/14831))
- Ensure instances of the same variant with different values are always sorted deterministically (e.g. `data-focus:flex` and `data-active:flex`) ([#14835](https://github.com/tailwindlabs/tailwindcss/pull/14835))
- Ensure `--inset-ring=*` and `--inset-shadow-*` variables are ignored by `inset-*` utilities ([#14855](https://github.com/tailwindlabs/tailwindcss/pull/14855))
- _Upgrade (experimental)_: Install `@tailwindcss/postcss` next to `tailwindcss` ([#14830](https://github.com/tailwindlabs/tailwindcss/pull/14830))
- _Upgrade (experimental)_: Remove whitespace around `,` separator when print arbitrary values ([#14838](https://github.com/tailwindlabs/tailwindcss/pull/14838))

Expand Down
2 changes: 2 additions & 0 deletions packages/tailwindcss/src/intellisense.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function loadDesignSystem() {
theme.add('--perspective-normal', '500px')
theme.add('--opacity-background', '0.3')
theme.add('--drop-shadow-sm', '0 1px 1px rgb(0 0 0 / 0.05)')
theme.add('--inset-shadow-sm', 'inset 0 1px 1px rgb(0 0 0 / 0.05)')
theme.add('--inset-ring-big', '100px')
return buildDesignSystem(theme)
}

Expand Down
56 changes: 40 additions & 16 deletions packages/tailwindcss/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export const enum ThemeOptions {
DEFAULT = 1 << 2,
}

function isIgnoredThemeKey(themeKey: ThemeKey, ignoredThemeKeys: ThemeKey[]) {
return ignoredThemeKeys.some(
(ignoredThemeKey) => themeKey === ignoredThemeKey || themeKey.startsWith(`${ignoredThemeKey}-`),
)
}

export class Theme {
public prefix: string | null = null

Expand Down Expand Up @@ -44,20 +50,22 @@ export class Theme {
}
}

keysInNamespaces(themeKeys: ThemeKey[]): string[] {
keysInNamespaces(themeKeys: ThemeKey[], ignoredThemeKeys: ThemeKey[] = []): string[] {
let keys: string[] = []

for (let prefix of themeKeys) {
let namespace = `${prefix}-`

for (let key of this.values.keys()) {
if (key.startsWith(namespace)) {
if (key.indexOf('--', 2) !== -1) {
continue
}
if (!key.startsWith(namespace)) continue

if (key.indexOf('--', 2) !== -1) continue

keys.push(key.slice(namespace.length))
if (isIgnoredThemeKey(key as ThemeKey, ignoredThemeKeys)) {
continue
}

keys.push(key.slice(namespace.length))
}
}

Expand Down Expand Up @@ -111,14 +119,21 @@ export class Theme {
}
}

#resolveKey(candidateValue: string | null, themeKeys: ThemeKey[]): string | null {
#resolveKey(
candidateValue: string | null,
themeKeys: ThemeKey[],
ignoredThemeKeys: ThemeKey[] = [],
): string | null {
for (let key of themeKeys) {
let themeKey =
candidateValue !== null ? escape(`${key}-${candidateValue.replaceAll('.', '_')}`) : key
candidateValue !== null
? (escape(`${key}-${candidateValue.replaceAll('.', '_')}`) as ThemeKey)
: key

if (this.values.has(themeKey)) {
return themeKey
}
if (!this.values.has(themeKey)) continue
if (isIgnoredThemeKey(themeKey, ignoredThemeKeys)) continue

return themeKey
}

return null
Expand All @@ -132,8 +147,12 @@ export class Theme {
return `var(${this.#prefixKey(themeKey)}, ${this.values.get(themeKey)?.value})`
}

resolve(candidateValue: string | null, themeKeys: ThemeKey[]): string | null {
let themeKey = this.#resolveKey(candidateValue, themeKeys)
resolve(
candidateValue: string | null,
themeKeys: ThemeKey[],
ignoredThemeKeys: ThemeKey[] = [],
): string | null {
let themeKey = this.#resolveKey(candidateValue, themeKeys, ignoredThemeKeys)

if (!themeKey) return null

Expand All @@ -146,8 +165,12 @@ export class Theme {
return this.#var(themeKey)
}

resolveValue(candidateValue: string | null, themeKeys: ThemeKey[]): string | null {
let themeKey = this.#resolveKey(candidateValue, themeKeys)
resolveValue(
candidateValue: string | null,
themeKeys: ThemeKey[],
ignoredThemeKeys: ThemeKey[] = [],
): string | null {
let themeKey = this.#resolveKey(candidateValue, themeKeys, ignoredThemeKeys)

if (!themeKey) return null

Expand All @@ -158,8 +181,9 @@ export class Theme {
candidateValue: string,
themeKeys: ThemeKey[],
nestedKeys: `--${string}`[] = [],
ignoredThemeKeys: ThemeKey[] = [],
): [string, Record<string, string>] | null {
let themeKey = this.#resolveKey(candidateValue, themeKeys)
let themeKey = this.#resolveKey(candidateValue, themeKeys, ignoredThemeKeys)

if (!themeKey) return null

Expand Down
Loading

0 comments on commit cf77420

Please sign in to comment.