diff --git a/packages/@tailwindcss-upgrade/src/template/candidates.ts b/packages/@tailwindcss-upgrade/src/template/candidates.ts index 5e0ec6eaa..e4849a6be 100644 --- a/packages/@tailwindcss-upgrade/src/template/candidates.ts +++ b/packages/@tailwindcss-upgrade/src/template/candidates.ts @@ -31,13 +31,6 @@ export function printCandidate(designSystem: DesignSystem, candidate: Candidate) let base: string = '' - // Handle negative - if (candidate.kind === 'static' || candidate.kind === 'functional') { - if (candidate.negative) { - base += '-' - } - } - // Handle static if (candidate.kind === 'static') { base += candidate.root diff --git a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap index ac0a70fa6..d96b027f3 100644 --- a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap +++ b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap @@ -36,6 +36,8 @@ exports[`getClassList 1`] = ` "-bottom-80", "-bottom-9", "-bottom-96", + "-bottom-full", + "-bottom-px", "-col-end-1", "-col-end-10", "-col-end-11", @@ -96,6 +98,8 @@ exports[`getClassList 1`] = ` "-end-80", "-end-9", "-end-96", + "-end-full", + "-end-px", "-indent-0", "-indent-0.5", "-indent-1", @@ -130,6 +134,7 @@ exports[`getClassList 1`] = ` "-indent-80", "-indent-9", "-indent-96", + "-indent-px", "-inset-0", "-inset-0.5", "-inset-1", @@ -164,6 +169,8 @@ exports[`getClassList 1`] = ` "-inset-80", "-inset-9", "-inset-96", + "-inset-full", + "-inset-px", "-inset-x-0", "-inset-x-0.5", "-inset-x-1", @@ -198,6 +205,8 @@ exports[`getClassList 1`] = ` "-inset-x-80", "-inset-x-9", "-inset-x-96", + "-inset-x-full", + "-inset-x-px", "-inset-y-0", "-inset-y-0.5", "-inset-y-1", @@ -232,6 +241,8 @@ exports[`getClassList 1`] = ` "-inset-y-80", "-inset-y-9", "-inset-y-96", + "-inset-y-full", + "-inset-y-px", "-left-0", "-left-0.5", "-left-1", @@ -266,6 +277,8 @@ exports[`getClassList 1`] = ` "-left-80", "-left-9", "-left-96", + "-left-full", + "-left-px", "-m-0", "-m-0.5", "-m-1", @@ -300,6 +313,7 @@ exports[`getClassList 1`] = ` "-m-80", "-m-9", "-m-96", + "-m-px", "-mb-0", "-mb-0.5", "-mb-1", @@ -334,6 +348,7 @@ exports[`getClassList 1`] = ` "-mb-80", "-mb-9", "-mb-96", + "-mb-px", "-me-0", "-me-0.5", "-me-1", @@ -368,6 +383,7 @@ exports[`getClassList 1`] = ` "-me-80", "-me-9", "-me-96", + "-me-px", "-ml-0", "-ml-0.5", "-ml-1", @@ -402,6 +418,7 @@ exports[`getClassList 1`] = ` "-ml-80", "-ml-9", "-ml-96", + "-ml-px", "-mr-0", "-mr-0.5", "-mr-1", @@ -436,6 +453,7 @@ exports[`getClassList 1`] = ` "-mr-80", "-mr-9", "-mr-96", + "-mr-px", "-ms-0", "-ms-0.5", "-ms-1", @@ -470,6 +488,7 @@ exports[`getClassList 1`] = ` "-ms-80", "-ms-9", "-ms-96", + "-ms-px", "-mt-0", "-mt-0.5", "-mt-1", @@ -504,6 +523,7 @@ exports[`getClassList 1`] = ` "-mt-80", "-mt-9", "-mt-96", + "-mt-px", "-mx-0", "-mx-0.5", "-mx-1", @@ -538,6 +558,7 @@ exports[`getClassList 1`] = ` "-mx-80", "-mx-9", "-mx-96", + "-mx-px", "-my-0", "-my-0.5", "-my-1", @@ -572,6 +593,7 @@ exports[`getClassList 1`] = ` "-my-80", "-my-9", "-my-96", + "-my-px", "-order-1", "-order-10", "-order-11", @@ -618,6 +640,8 @@ exports[`getClassList 1`] = ` "-right-80", "-right-9", "-right-96", + "-right-full", + "-right-px", "-rotate-0", "-rotate-1", "-rotate-12", @@ -758,6 +782,7 @@ exports[`getClassList 1`] = ` "-scroll-m-80", "-scroll-m-9", "-scroll-m-96", + "-scroll-m-px", "-scroll-mb-0", "-scroll-mb-0.5", "-scroll-mb-1", @@ -792,6 +817,7 @@ exports[`getClassList 1`] = ` "-scroll-mb-80", "-scroll-mb-9", "-scroll-mb-96", + "-scroll-mb-px", "-scroll-me-0", "-scroll-me-0.5", "-scroll-me-1", @@ -826,6 +852,7 @@ exports[`getClassList 1`] = ` "-scroll-me-80", "-scroll-me-9", "-scroll-me-96", + "-scroll-me-px", "-scroll-ml-0", "-scroll-ml-0.5", "-scroll-ml-1", @@ -860,6 +887,7 @@ exports[`getClassList 1`] = ` "-scroll-ml-80", "-scroll-ml-9", "-scroll-ml-96", + "-scroll-ml-px", "-scroll-mr-0", "-scroll-mr-0.5", "-scroll-mr-1", @@ -894,6 +922,7 @@ exports[`getClassList 1`] = ` "-scroll-mr-80", "-scroll-mr-9", "-scroll-mr-96", + "-scroll-mr-px", "-scroll-ms-0", "-scroll-ms-0.5", "-scroll-ms-1", @@ -928,6 +957,7 @@ exports[`getClassList 1`] = ` "-scroll-ms-80", "-scroll-ms-9", "-scroll-ms-96", + "-scroll-ms-px", "-scroll-mt-0", "-scroll-mt-0.5", "-scroll-mt-1", @@ -962,6 +992,7 @@ exports[`getClassList 1`] = ` "-scroll-mt-80", "-scroll-mt-9", "-scroll-mt-96", + "-scroll-mt-px", "-scroll-mx-0", "-scroll-mx-0.5", "-scroll-mx-1", @@ -996,6 +1027,7 @@ exports[`getClassList 1`] = ` "-scroll-mx-80", "-scroll-mx-9", "-scroll-mx-96", + "-scroll-mx-px", "-scroll-my-0", "-scroll-my-0.5", "-scroll-my-1", @@ -1030,6 +1062,7 @@ exports[`getClassList 1`] = ` "-scroll-my-80", "-scroll-my-9", "-scroll-my-96", + "-scroll-my-px", "-skew-0", "-skew-1", "-skew-12", @@ -1082,6 +1115,7 @@ exports[`getClassList 1`] = ` "-space-x-80", "-space-x-9", "-space-x-96", + "-space-x-px", "-space-y-0", "-space-y-0.5", "-space-y-1", @@ -1116,6 +1150,7 @@ exports[`getClassList 1`] = ` "-space-y-80", "-space-y-9", "-space-y-96", + "-space-y-px", "-start-0", "-start-0.5", "-start-1", @@ -1150,6 +1185,8 @@ exports[`getClassList 1`] = ` "-start-80", "-start-9", "-start-96", + "-start-full", + "-start-px", "-top-0", "-top-0.5", "-top-1", @@ -1184,6 +1221,8 @@ exports[`getClassList 1`] = ` "-top-80", "-top-9", "-top-96", + "-top-full", + "-top-px", "-translate-0", "-translate-0.5", "-translate-1", @@ -1218,6 +1257,8 @@ exports[`getClassList 1`] = ` "-translate-80", "-translate-9", "-translate-96", + "-translate-full", + "-translate-px", "-translate-x-0", "-translate-x-0.5", "-translate-x-1", @@ -1252,6 +1293,8 @@ exports[`getClassList 1`] = ` "-translate-x-80", "-translate-x-9", "-translate-x-96", + "-translate-x-full", + "-translate-x-px", "-translate-y-0", "-translate-y-0.5", "-translate-y-1", @@ -1286,6 +1329,8 @@ exports[`getClassList 1`] = ` "-translate-y-80", "-translate-y-9", "-translate-y-96", + "-translate-y-full", + "-translate-y-px", "-translate-z-0", "-translate-z-0.5", "-translate-z-1", @@ -1320,6 +1365,7 @@ exports[`getClassList 1`] = ` "-translate-z-80", "-translate-z-9", "-translate-z-96", + "-translate-z-px", "-underline-offset-0", "-underline-offset-1", "-underline-offset-2", diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index 9837e3471..570a34249 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -41,7 +41,6 @@ it('should parse a simple utility', () => { { "important": false, "kind": "static", - "negative": false, "raw": "flex", "root": "flex", "variants": [], @@ -59,7 +58,6 @@ it('should parse a simple utility that should be important', () => { { "important": true, "kind": "static", - "negative": false, "raw": "flex!", "root": "flex", "variants": [], @@ -70,7 +68,7 @@ it('should parse a simple utility that should be important', () => { it('should parse a simple utility that can be negative', () => { let utilities = new Utilities() - utilities.functional('translate-x', () => []) + utilities.functional('-translate-x', () => []) expect(run('-translate-x-4', { utilities })).toMatchInlineSnapshot(` [ @@ -78,9 +76,8 @@ it('should parse a simple utility that can be negative', () => { "important": false, "kind": "functional", "modifier": null, - "negative": true, "raw": "-translate-x-4", - "root": "translate-x", + "root": "-translate-x", "value": { "fraction": null, "kind": "named", @@ -104,7 +101,6 @@ it('should parse a simple utility with a variant', () => { { "important": false, "kind": "static", - "negative": false, "raw": "hover:flex", "root": "flex", "variants": [ @@ -131,7 +127,6 @@ it('should parse a simple utility with stacked variants', () => { { "important": false, "kind": "static", - "negative": false, "raw": "focus:hover:flex", "root": "flex", "variants": [ @@ -158,7 +153,6 @@ it('should parse a simple utility with an arbitrary variant', () => { { "important": false, "kind": "static", - "negative": false, "raw": "[&_p]:flex", "root": "flex", "variants": [ @@ -185,7 +179,6 @@ it('should parse a simple utility with a parameterized variant', () => { { "important": false, "kind": "static", - "negative": false, "raw": "data-[disabled]:flex", "root": "flex", "variants": [ @@ -216,7 +209,6 @@ it('should parse compound variants with an arbitrary value as an arbitrary varia { "important": false, "kind": "static", - "negative": false, "raw": "group-[&_p]/parent-name:flex", "root": "flex", "variants": [ @@ -253,7 +245,6 @@ it('should parse a simple utility with a parameterized variant and a modifier', { "important": false, "kind": "static", - "negative": false, "raw": "group-aria-[disabled]/parent-name:flex", "root": "flex", "variants": [ @@ -294,7 +285,6 @@ it('should parse compound group with itself group-group-*', () => { { "important": false, "kind": "static", - "negative": false, "raw": "group-group-group-hover/parent-name:flex", "root": "flex", "variants": [ @@ -335,7 +325,6 @@ it('should parse a simple utility with an arbitrary media variant', () => { { "important": false, "kind": "static", - "negative": false, "raw": "[@media(width>=123px)]:flex", "root": "flex", "variants": [ @@ -370,7 +359,6 @@ it('should parse a utility with a modifier', () => { "kind": "named", "value": "50", }, - "negative": false, "raw": "bg-red-500/50", "root": "bg", "value": { @@ -397,7 +385,6 @@ it('should parse a utility with an arbitrary modifier', () => { "kind": "arbitrary", "value": "50%", }, - "negative": false, "raw": "bg-red-500/[50%]", "root": "bg", "value": { @@ -424,7 +411,6 @@ it('should parse a utility with a modifier that is important', () => { "kind": "named", "value": "50", }, - "negative": false, "raw": "bg-red-500/50!", "root": "bg", "value": { @@ -454,7 +440,6 @@ it('should parse a utility with a modifier and a variant', () => { "kind": "named", "value": "50", }, - "negative": false, "raw": "hover:bg-red-500/50", "root": "bg", "value": { @@ -513,7 +498,6 @@ it('should parse a utility with an arbitrary value', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[#0088cc]", "root": "bg", "value": { @@ -537,7 +521,6 @@ it('should parse a utility with an arbitrary value including a typehint', () => "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[color:var(--value)]", "root": "bg", "value": { @@ -564,7 +547,6 @@ it('should parse a utility with an arbitrary value with a modifier', () => { "kind": "named", "value": "50", }, - "negative": false, "raw": "bg-[#0088cc]/50", "root": "bg", "value": { @@ -591,7 +573,6 @@ it('should parse a utility with an arbitrary value with an arbitrary modifier', "kind": "arbitrary", "value": "50%", }, - "negative": false, "raw": "bg-[#0088cc]/[50%]", "root": "bg", "value": { @@ -615,7 +596,6 @@ it('should parse a utility with an arbitrary value that is important', () => { "important": true, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[#0088cc]!", "root": "bg", "value": { @@ -639,7 +619,6 @@ it('should parse a utility with an implicit variable as the arbitrary value', () "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[var(--value)]", "root": "bg", "value": { @@ -663,7 +642,6 @@ it('should parse a utility with an implicit variable as the arbitrary value that "important": true, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[var(--value)]!", "root": "bg", "value": { @@ -687,7 +665,6 @@ it('should parse a utility with an explicit variable as the arbitrary value', () "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[var(--value)]", "root": "bg", "value": { @@ -711,7 +688,6 @@ it('should parse a utility with an explicit variable as the arbitrary value that "important": true, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[var(--value)]!", "root": "bg", "value": { @@ -768,7 +744,6 @@ it('should parse a utility with an implicit variable as the modifier', () => { "kind": "arbitrary", "value": "var(--value)", }, - "negative": false, "raw": "bg-red-500/[var(--value)]", "root": "bg", "value": { @@ -795,7 +770,6 @@ it('should parse a utility with an implicit variable as the modifier that is imp "kind": "arbitrary", "value": "var(--value)", }, - "negative": false, "raw": "bg-red-500/[var(--value)]!", "root": "bg", "value": { @@ -822,7 +796,6 @@ it('should parse a utility with an explicit variable as the modifier', () => { "kind": "arbitrary", "value": "var(--value)", }, - "negative": false, "raw": "bg-red-500/[var(--value)]", "root": "bg", "value": { @@ -849,7 +822,6 @@ it('should parse a utility with an explicit variable as the modifier that is imp "kind": "arbitrary", "value": "var(--value)", }, - "negative": false, "raw": "bg-red-500/[var(--value)]!", "root": "bg", "value": { @@ -875,7 +847,6 @@ it('should parse a static variant starting with @', () => { { "important": false, "kind": "static", - "negative": false, "raw": "@lg:flex", "root": "flex", "variants": [ @@ -901,7 +872,6 @@ it('should parse a functional variant with a modifier', () => { { "important": false, "kind": "static", - "negative": false, "raw": "foo-bar/50:flex", "root": "flex", "variants": [ @@ -935,7 +905,6 @@ it('should parse a functional variant starting with @', () => { { "important": false, "kind": "static", - "negative": false, "raw": "@lg:flex", "root": "flex", "variants": [ @@ -966,7 +935,6 @@ it('should parse a functional variant starting with @ and a modifier', () => { { "important": false, "kind": "static", - "negative": false, "raw": "@lg/name:flex", "root": "flex", "variants": [ @@ -998,7 +966,6 @@ it('should replace `_` with ` `', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "content-["hello_world"]", "root": "content", "value": { @@ -1022,7 +989,6 @@ it('should not replace `\\_` with ` ` (when it is escaped)', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "content-["hello\\_world"]", "root": "content", "value": { @@ -1047,7 +1013,6 @@ it('should not replace `_` inside of `url()`', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "bg-[no-repeat_url(https://example.com/some_page)]", "root": "bg", "value": { @@ -1072,7 +1037,6 @@ it('should not replace `_` in the first argument to `var()`', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "ml-[var(--spacing-1_5,_var(--spacing-2_5,_1rem))]", "root": "ml", "value": { @@ -1097,7 +1061,6 @@ it('should not replace `_` in the first argument to `theme()`', () => { "important": false, "kind": "functional", "modifier": null, - "negative": false, "raw": "ml-[theme(--spacing-1_5,_theme(--spacing-2_5,_1rem))]", "root": "ml", "value": { @@ -1272,7 +1235,6 @@ it('should parse a variant containing an arbitrary string with unbalanced parens { "important": false, "kind": "static", - "negative": false, "raw": "string-['}[("\\'']:flex", "root": "flex", "variants": [ @@ -1307,7 +1269,6 @@ it('should parse candidates with a prefix', () => { { "important": false, "kind": "static", - "negative": false, "raw": "tw:flex", "root": "flex", "variants": [], @@ -1319,7 +1280,6 @@ it('should parse candidates with a prefix', () => { { "important": false, "kind": "static", - "negative": false, "raw": "tw:hover:flex", "root": "flex", "variants": [ diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index 91d6e1bb6..669ef4f7c 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -183,7 +183,6 @@ export type Candidate = kind: 'static' root: string variants: Variant[] - negative: boolean important: boolean raw: string } @@ -203,7 +202,6 @@ export type Candidate = value: ArbitraryUtilityValue | NamedUtilityValue | null modifier: ArbitraryModifier | NamedModifier | null variants: Variant[] - negative: boolean important: boolean raw: string } @@ -240,7 +238,6 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter } let important = false - let negative = false // Candidates that end with an exclamation mark are the important version with // higher specificity of the non-important candidate, e.g. `mx-4!`. @@ -255,13 +252,6 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter base = base.slice(1) } - // Candidates that start with a dash are the negative versions of another - // candidate, e.g. `-mx-4`. - if (base[0] === '-') { - negative = true - base = base.slice(1) - } - // Check for an exact match of a static utility first as long as it does not // look like an arbitrary value. if (designSystem.utilities.has(base, 'static') && !base.includes('[')) { @@ -269,7 +259,6 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter kind: 'static', root: base, variants: parsedCandidateVariants, - negative, important, raw: input, } @@ -384,7 +373,6 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter modifier: modifierSegment === null ? null : parseModifier(modifierSegment), value: null, variants: parsedCandidateVariants, - negative, important, raw: input, } diff --git a/packages/tailwindcss/src/compat/plugin-api.ts b/packages/tailwindcss/src/compat/plugin-api.ts index e348da5c0..9afb93140 100644 --- a/packages/tailwindcss/src/compat/plugin-api.ts +++ b/packages/tailwindcss/src/compat/plugin-api.ts @@ -4,7 +4,7 @@ import type { Candidate, CandidateModifier, NamedUtilityValue } from '../candida import { substituteFunctions } from '../css-functions' import * as CSS from '../css-parser' import type { DesignSystem } from '../design-system' -import { withAlpha, withNegative } from '../utilities' +import { withAlpha } from '../utilities' import { inferDataType } from '../utils/infer-data-type' import { segment } from '../utils/segment' import { toKeyPath } from '../utils/to-key-path' @@ -228,8 +228,7 @@ export function buildPluginApi( ) } - designSystem.utilities.static(name.slice(1), (candidate) => { - if (candidate.negative) return + designSystem.utilities.static(name.slice(1), () => { let ast = objectToAst(css) substituteAtApply(ast, designSystem) return ast @@ -251,112 +250,117 @@ export function buildPluginApi( ) } - function compileFn(candidate: Extract) { - // A negative utility was provided but is unsupported - if (!options?.supportsNegativeValues && candidate.negative) return - - // Throw out any candidate whose value is not a supported type - if (candidate.value?.kind === 'arbitrary' && types.length > 0 && !types.includes('any')) { - // The candidate has an explicit data type but it's not in the list - // of supported types by this utility. For example, a `scrollbar` - // utility that is only used to change the scrollbar color but is - // used with a `length` value: `scrollbar-[length:var(--whatever)]` - if (candidate.value.dataType && !types.includes(candidate.value.dataType)) { - return - } - - // The candidate does not have an explicit data type and the value - // cannot be inferred as one of the supported types. For example, a - // `scrollbar` utility that is only used to change the scrollbar - // color but is used with a `length` value: `scrollbar-[33px]` + function compileFn({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + // Throw out any candidate whose value is not a supported type if ( - !candidate.value.dataType && - !inferDataType(candidate.value.value, types as any[]) + candidate.value?.kind === 'arbitrary' && + types.length > 0 && + !types.includes('any') ) { - return - } - } + // The candidate has an explicit data type but it's not in the list + // of supported types by this utility. For example, a `scrollbar` + // utility that is only used to change the scrollbar color but is + // used with a `length` value: `scrollbar-[length:var(--whatever)]` + if (candidate.value.dataType && !types.includes(candidate.value.dataType)) { + return + } - let isColor = types.includes('color') - - // Resolve the candidate value - let value: string | null = null - let ignoreModifier = false - - { - let values = options?.values ?? {} - - if (isColor) { - // Color utilities implicitly support `inherit`, `transparent`, and `currentColor` - // for backwards compatibility but still allow them to be overridden - values = Object.assign( - { - inherit: 'inherit', - transparent: 'transparent', - current: 'currentColor', - }, - values, - ) + // The candidate does not have an explicit data type and the value + // cannot be inferred as one of the supported types. For example, a + // `scrollbar` utility that is only used to change the scrollbar + // color but is used with a `length` value: `scrollbar-[33px]` + if ( + !candidate.value.dataType && + !inferDataType(candidate.value.value, types as any[]) + ) { + return + } } - if (!candidate.value) { - value = values.DEFAULT ?? null - } else if (candidate.value.kind === 'arbitrary') { - value = candidate.value.value - } else if (candidate.value.fraction && values[candidate.value.fraction]) { - value = values[candidate.value.fraction] - ignoreModifier = true - } else if (values[candidate.value.value]) { - value = values[candidate.value.value] - } else if (values.__BARE_VALUE__) { - value = values.__BARE_VALUE__(candidate.value) ?? null - ignoreModifier = (candidate.value.fraction !== null && value?.includes('/')) ?? false + let isColor = types.includes('color') + + // Resolve the candidate value + let value: string | null = null + let ignoreModifier = false + + { + let values = options?.values ?? {} + + if (isColor) { + // Color utilities implicitly support `inherit`, `transparent`, and `currentColor` + // for backwards compatibility but still allow them to be overridden + values = Object.assign( + { + inherit: 'inherit', + transparent: 'transparent', + current: 'currentColor', + }, + values, + ) + } + + if (!candidate.value) { + value = values.DEFAULT ?? null + } else if (candidate.value.kind === 'arbitrary') { + value = candidate.value.value + } else if (candidate.value.fraction && values[candidate.value.fraction]) { + value = values[candidate.value.fraction] + ignoreModifier = true + } else if (values[candidate.value.value]) { + value = values[candidate.value.value] + } else if (values.__BARE_VALUE__) { + value = values.__BARE_VALUE__(candidate.value) ?? null + ignoreModifier = + (candidate.value.fraction !== null && value?.includes('/')) ?? false + } } - } - if (value === null) return + if (value === null) return - // Resolve the modifier value - let modifier: string | null + // Resolve the modifier value + let modifier: string | null - { - let modifiers = options?.modifiers ?? null + { + let modifiers = options?.modifiers ?? null - if (!candidate.modifier) { - modifier = null - } else if (modifiers === 'any' || candidate.modifier.kind === 'arbitrary') { - modifier = candidate.modifier.value - } else if (modifiers?.[candidate.modifier.value]) { - modifier = modifiers[candidate.modifier.value] - } else if (isColor && !Number.isNaN(Number(candidate.modifier.value))) { - modifier = `${candidate.modifier.value}%` - } else { - modifier = null + if (!candidate.modifier) { + modifier = null + } else if (modifiers === 'any' || candidate.modifier.kind === 'arbitrary') { + modifier = candidate.modifier.value + } else if (modifiers?.[candidate.modifier.value]) { + modifier = modifiers[candidate.modifier.value] + } else if (isColor && !Number.isNaN(Number(candidate.modifier.value))) { + modifier = `${candidate.modifier.value}%` + } else { + modifier = null + } } - } - // A modifier was provided but is invalid - if (candidate.modifier && modifier === null && !ignoreModifier) { - // For arbitrary values, return `null` to avoid falling through to the next utility - return candidate.value?.kind === 'arbitrary' ? null : undefined - } + // A modifier was provided but is invalid + if (candidate.modifier && modifier === null && !ignoreModifier) { + // For arbitrary values, return `null` to avoid falling through to the next utility + return candidate.value?.kind === 'arbitrary' ? null : undefined + } - if (isColor && modifier !== null) { - value = withAlpha(value, modifier) - } + if (isColor && modifier !== null) { + value = withAlpha(value, modifier) + } - if (candidate.negative) { - value = withNegative(value, candidate) - } + if (negative) { + value = `calc(${value} * -1)` + } - let ast = objectToAst(fn(value, { modifier })) - substituteAtApply(ast, designSystem) - return ast + let ast = objectToAst(fn(value, { modifier })) + substituteAtApply(ast, designSystem) + return ast + } } - designSystem.utilities.functional(name, compileFn, { - types, - }) + if (options?.supportsNegativeValues) { + designSystem.utilities.functional(`-${name}`, compileFn({ negative: true }), { types }) + } + designSystem.utilities.functional(name, compileFn({ negative: false }), { types }) designSystem.utilities.suggest(name, () => { let values = options?.values ?? {} diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 40663f488..04e9bb99d 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -161,10 +161,7 @@ async function parseCss( } customUtilities.push((designSystem) => { - designSystem.utilities.static(name, (candidate) => { - if (candidate.negative) return - return structuredClone(node.nodes) - }) + designSystem.utilities.static(name, () => structuredClone(node.nodes)) }) return diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index 2248f507d..96ceea6b5 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -133,16 +133,6 @@ export function asColor(value: string, modifier: CandidateModifier | null): stri return withAlpha(value, `${modifier.value}%`) } -/** - * Negate a numeric value — literals get simplified by Lightning CSS. - */ -export function withNegative( - value: string, - candidate: Extract, -) { - return candidate.negative ? `calc(${value} * -1)` : value -} - /** * Finds a color in the theme under one of the given theme keys that matches * `candidateValue`. @@ -232,9 +222,7 @@ export function createUtilities(theme: Theme) { * Register a static utility class like `justify-center`. */ function staticUtility(className: string, declarations: ([string, string] | (() => AstNode))[]) { - utilities.static(className, (candidate) => { - if (candidate.negative) return - + utilities.static(className, () => { return declarations.map((node) => { return typeof node === 'function' ? node() : decl(node[0], node[1]) }) @@ -256,62 +244,64 @@ export function createUtilities(theme: Theme) { * user's theme. */ function functionalUtility(classRoot: string, desc: UtilityDescription) { - utilities.functional(classRoot, (candidate) => { - // If the class candidate has a negative prefix (like `-mx-2`) but this - // utility doesn't support negative values (like the `width` utility), - // don't generate any rules. - if (candidate.negative && !desc.supportsNegative) return + function handleFunctionalUtility({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + let value: string | null = null - let value: string | null = null + if (!candidate.value) { + if (candidate.modifier) return - if (!candidate.value) { - if (candidate.modifier) return + // If the candidate has no value segment (like `rounded`), use the + // `defaultValue` (for candidates like `grow` that have no theme + // values) or a bare theme value (like `--radius` for `rounded`). No + // utility will ever support both of these. + value = + desc.defaultValue !== undefined + ? desc.defaultValue + : theme.resolve(null, desc.themeKeys ?? []) + } else if (candidate.value.kind === 'arbitrary') { + if (candidate.modifier) return + value = candidate.value.value + } else { + value = theme.resolve( + candidate.value.fraction ?? candidate.value.value, + desc.themeKeys ?? [], + ) - // If the candidate has no value segment (like `rounded`), use the - // `defaultValue` (for candidates like `grow` that have no theme values) - // or a bare theme value (like `--radius` for `rounded`). No utility - // will ever support both of these. - value = - desc.defaultValue !== undefined - ? desc.defaultValue - : theme.resolve(null, desc.themeKeys ?? []) - } else if (candidate.value.kind === 'arbitrary') { - if (candidate.modifier) return - value = candidate.value.value - } else { - value = theme.resolve( - candidate.value.fraction ?? candidate.value.value, - desc.themeKeys ?? [], - ) + // Automatically handle things like `w-1/2` without requiring `1/2` to + // exist as a theme value. + if (value === null && desc.supportsFractions && candidate.value.fraction) { + let [lhs, rhs] = segment(candidate.value.fraction, '/') + if (!isPositiveInteger(lhs) || !isPositiveInteger(rhs)) return + value = `calc(${candidate.value.fraction} * 100%)` + } - // Automatically handle things like `w-1/2` without requiring `1/2` to - // exist as a theme value. - if (value === null && desc.supportsFractions && candidate.value.fraction) { - let [lhs, rhs] = segment(candidate.value.fraction, '/') - if (!isPositiveInteger(lhs) || !isPositiveInteger(rhs)) return - value = `calc(${candidate.value.fraction} * 100%)` + // If there is still no value but the utility supports bare values, + // then use the bare candidate value as the value. + if (value === null && negative && desc.handleNegativeBareValue) { + value = desc.handleNegativeBareValue(candidate.value) + if (!value?.includes('/') && candidate.modifier) return + if (value !== null) return desc.handle(value) + } + + if (value === null && desc.handleBareValue) { + value = desc.handleBareValue(candidate.value) + if (!value?.includes('/') && candidate.modifier) return + } } - // If there is still no value but the utility supports bare values, then - // use the bare candidate value as the value. - if (value === null && candidate.negative && desc.handleNegativeBareValue) { - value = desc.handleNegativeBareValue(candidate.value) - if (!value?.includes('/') && candidate.modifier) return - if (value !== null) return desc.handle(value) - } + // If there is no value, don't generate any rules. + if (value === null) return - if (value === null && desc.handleBareValue) { - value = desc.handleBareValue(candidate.value) - if (!value?.includes('/') && candidate.modifier) return - } + // Negate the value if the candidate has a negative prefix. + return desc.handle(negative ? `calc(${value} * -1)` : value) } + } - // If there is no value, don't generate any rules. - if (value === null) return - - // Negate the value if the candidate has a negative prefix. - return desc.handle(withNegative(value, candidate)) - }) + if (desc.supportsNegative) { + utilities.functional(`-${classRoot}`, handleFunctionalUtility({ negative: true })) + } + utilities.functional(classRoot, handleFunctionalUtility({ negative: false })) suggest(classRoot, () => [ { @@ -337,10 +327,6 @@ export function createUtilities(theme: Theme) { // `bg-red-500`, otherwise they would be static utilities. if (!candidate.value) return - // Color utilities never support negative values as there's no sensible - // way to negate a color. - if (candidate.negative) return - // Find the actual CSS value that the candidate value maps to. let value: string | null = null @@ -381,10 +367,10 @@ export function createUtilities(theme: Theme) { supportsFractions?: boolean } = {}, ) { - utilities.static(`${name}-px`, (candidate) => { - if (!supportsNegative && candidate.negative) return - return handle(candidate.negative ? '-1px' : '1px') - }) + if (supportsNegative) { + utilities.static(`-${name}-px`, () => handle('-1px')) + } + utilities.static(`${name}-px`, () => handle('1px')) let themeKeys = ([] as ThemeKey[]).concat(themeNamespace, '--spacing') functionalUtility(name, { themeKeys, @@ -515,10 +501,8 @@ export function createUtilities(theme: Theme) { ['left', 'left'], ] as const) { staticUtility(`${name}-auto`, [[property, 'auto']]) - utilities.static(`${name}-full`, (candidate) => { - let value = candidate.negative ? '-100%' : '100%' - return [decl(property, value)] - }) + staticUtility(`${name}-full`, [[property, '100%']]) + staticUtility(`-${name}-full`, [[property, '-100%']]) spacingUtility(name, '--inset', (value) => [decl(property, value)], { supportsNegative: true, supportsFractions: true, @@ -917,8 +901,6 @@ export function createUtilities(theme: Theme) { // generate `flex: 1`. Our `functionalUtility` helper can't handle two properties // using the same namespace, so we handle this one manually. utilities.functional('flex', (candidate) => { - if (candidate.negative) return - if (!candidate.value) { if (candidate.modifier) return return [decl('display', 'flex')] @@ -1087,16 +1069,18 @@ export function createUtilities(theme: Theme) { * @css `translate` */ staticUtility('translate-none', [['translate', 'none']]) - utilities.static('translate-full', (candidate) => { - let value = candidate.negative ? '-100%' : '100%' - - return [ - translateProperties(), - decl('--tw-translate-x', value), - decl('--tw-translate-y', value), - decl('translate', 'var(--tw-translate-x) var(--tw-translate-y)'), - ] - }) + staticUtility('-translate-full', [ + translateProperties, + ['--tw-translate-x', '-100%'], + ['--tw-translate-y', '-100%'], + ['translate', 'var(--tw-translate-x) var(--tw-translate-y)'], + ]) + staticUtility('translate-full', [ + translateProperties, + ['--tw-translate-x', '100%'], + ['--tw-translate-y', '100%'], + ['translate', 'var(--tw-translate-x) var(--tw-translate-y)'], + ]) spacingUtility( 'translate', @@ -1111,19 +1095,29 @@ export function createUtilities(theme: Theme) { ) for (let axis of ['x', 'y']) { - let handle = (value: string) => [ - translateProperties(), - decl(`--tw-translate-${axis}`, value), - decl('translate', `var(--tw-translate-x) var(--tw-translate-y)`), - ] - - spacingUtility(`translate-${axis}`, ['--translate'], (value) => handle(value), { - supportsNegative: true, - supportsFractions: true, - }) - utilities.static(`translate-${axis}-full`, (candidate) => { - return handle(candidate.negative ? '-100%' : '100%') - }) + staticUtility(`-translate-${axis}-full`, [ + translateProperties, + [`--tw-translate-${axis}`, '-100%'], + ['translate', `var(--tw-translate-x) var(--tw-translate-y)`], + ]) + staticUtility(`translate-${axis}-full`, [ + translateProperties, + [`--tw-translate-${axis}`, '100%'], + ['translate', `var(--tw-translate-x) var(--tw-translate-y)`], + ]) + spacingUtility( + `translate-${axis}`, + ['--translate'], + (value) => [ + translateProperties(), + decl(`--tw-translate-${axis}`, value), + decl('translate', `var(--tw-translate-x) var(--tw-translate-y)`), + ], + { + supportsNegative: true, + supportsFractions: true, + }, + ) } spacingUtility( @@ -1138,13 +1132,16 @@ export function createUtilities(theme: Theme) { supportsNegative: true, }, ) - utilities.static(`translate-z-px`, (candidate) => { - return [ - translateProperties(), - decl(`--tw-translate-z`, candidate.negative ? '-1px' : '1px'), - decl('translate', 'var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)'), - ] - }) + staticUtility(`-translate-z-px`, [ + translateProperties, + [`--tw-translate-z`, '-1px'], + ['translate', 'var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)'], + ]) + staticUtility(`translate-z-px`, [ + translateProperties, + [`--tw-translate-z`, '1px'], + ['translate', 'var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)'], + ]) staticUtility('translate-3d', [ translateProperties, @@ -1162,29 +1159,33 @@ export function createUtilities(theme: Theme) { * @css `scale` */ staticUtility('scale-none', [['scale', 'none']]) - utilities.functional('scale', (candidate) => { - if (!candidate.value || candidate.modifier) return + function handleScale({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + if (!candidate.value || candidate.modifier) return - let value - if (candidate.value.kind === 'arbitrary') { - value = candidate.value.value - return [decl('scale', value)] - } else { - value = theme.resolve(candidate.value.value, ['--scale']) - if (!value && isPositiveInteger(candidate.value.value)) { - value = `${candidate.value.value}%` + let value + if (candidate.value.kind === 'arbitrary') { + value = candidate.value.value + return [decl('scale', value)] + } else { + value = theme.resolve(candidate.value.value, ['--scale']) + if (!value && isPositiveInteger(candidate.value.value)) { + value = `${candidate.value.value}%` + } + if (!value) return } - if (!value) return + value = negative ? `calc(${value} * -1)` : value + return [ + scaleProperties(), + decl('--tw-scale-x', value), + decl('--tw-scale-y', value), + decl('--tw-scale-z', value), + decl('scale', `var(--tw-scale-x) var(--tw-scale-y)`), + ] } - value = withNegative(value, candidate) - return [ - scaleProperties(), - decl('--tw-scale-x', value), - decl('--tw-scale-y', value), - decl('--tw-scale-z', value), - decl('scale', `var(--tw-scale-x) var(--tw-scale-y)`), - ] - }) + } + utilities.functional('-scale', handleScale({ negative: true })) + utilities.functional('scale', handleScale({ negative: false })) suggest('scale', () => [ { @@ -1240,28 +1241,33 @@ export function createUtilities(theme: Theme) { * `rotate-[1_2_3_45deg]` => `rotate: 1 2 3 45deg` */ staticUtility('rotate-none', [['rotate', 'none']]) - utilities.functional('rotate', (candidate) => { - if (!candidate.value || candidate.modifier) return - let value - if (candidate.value.kind === 'arbitrary') { - value = candidate.value.value - let type = candidate.value.dataType ?? inferDataType(value, ['angle', 'vector']) - if (type === 'vector') { - return [decl('rotate', `${value} var(--tw-rotate)`)] - } else if (type !== 'angle') { - return [decl('rotate', value)] + function handleRotate({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + if (!candidate.value || candidate.modifier) return + + let value + if (candidate.value.kind === 'arbitrary') { + value = candidate.value.value + let type = candidate.value.dataType ?? inferDataType(value, ['angle', 'vector']) + if (type === 'vector') { + return [decl('rotate', `${value} var(--tw-rotate)`)] + } else if (type !== 'angle') { + return [decl('rotate', value)] + } + } else { + value = theme.resolve(candidate.value.value, ['--rotate']) + if (!value && isPositiveInteger(candidate.value.value)) { + value = `${candidate.value.value}deg` + } + if (!value) return } - } else { - value = theme.resolve(candidate.value.value, ['--rotate']) - if (!value && isPositiveInteger(candidate.value.value)) { - value = `${candidate.value.value}deg` - } - if (!value) return + return [decl('rotate', negative ? `calc(${value} * -1)` : value)] } - value = withNegative(value, candidate) - return [decl('rotate', value)] - }) + } + + utilities.functional('-rotate', handleRotate({ negative: true })) + utilities.functional('rotate', handleRotate({ negative: false })) suggest('rotate', () => [ { @@ -1396,7 +1402,7 @@ export function createUtilities(theme: Theme) { * @css `transform` */ utilities.functional('transform', (candidate) => { - if (candidate.negative || candidate.modifier) return + if (candidate.modifier) return let value: string | null = null if (!candidate.value) { @@ -2000,8 +2006,6 @@ export function createUtilities(theme: Theme) { function borderSideUtility(classRoot: string, desc: BorderDescription) { utilities.functional(classRoot, (candidate) => { - if (candidate.negative) return - if (!candidate.value) { if (candidate.modifier) return let value = theme.get(['--default-border-width']) ?? '1px' @@ -2271,72 +2275,82 @@ export function createUtilities(theme: Theme) { ]) } - utilities.functional('bg-linear', (candidate) => { - if (!candidate.value || candidate.modifier) return + function handleBgLinear({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + if (!candidate.value || candidate.modifier) return - let value = candidate.value.value + let value = candidate.value.value - if (candidate.value.kind === 'arbitrary') { - let type = candidate.value.dataType ?? inferDataType(value, ['angle']) + if (candidate.value.kind === 'arbitrary') { + let type = candidate.value.dataType ?? inferDataType(value, ['angle']) - switch (type) { - case 'angle': { - value = withNegative(value, candidate) + switch (type) { + case 'angle': { + value = negative ? `calc(${value} * -1)` : `${value}` - return [ - decl('--tw-gradient-position', `${value},`), - decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), - ] + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), + ] + } + default: { + if (negative) return + + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), + ] + } } - default: { - if (candidate.negative) return + } else { + if (!isPositiveInteger(value)) return - return [ - decl('--tw-gradient-position', `${value},`), - decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), - ] - } + value = negative ? `calc(${value}deg * -1)` : `${value}deg` + + return [ + decl('--tw-gradient-position', `${value} in oklch,`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops))`), + ] } - } else { - if (!isPositiveInteger(value)) return - - value = withNegative(`${value}deg`, candidate) - - return [ - decl('--tw-gradient-position', `${value} in oklch,`), - decl('background-image', `linear-gradient(var(--tw-gradient-stops))`), - ] } - }) + } - utilities.functional('bg-conic', (candidate) => { - if (candidate.modifier) return + utilities.functional('-bg-linear', handleBgLinear({ negative: true })) + utilities.functional('bg-linear', handleBgLinear({ negative: false })) - if (!candidate.value) { - return [ - decl('--tw-gradient-position', `in oklch,`), - decl('background-image', `conic-gradient(var(--tw-gradient-stops))`), - ] + function handleBgConic({ negative }: { negative: boolean }) { + return (candidate: Extract) => { + if (candidate.modifier) return + + if (!candidate.value) { + return [ + decl('--tw-gradient-position', `in oklch,`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops))`), + ] + } + + let value = candidate.value.value + + if (candidate.value.kind === 'arbitrary') { + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops,${value}))`), + ] + } else { + if (!isPositiveInteger(value)) return + + value = negative ? `calc(${value} * -1)` : `${value}deg` + + return [ + decl('--tw-gradient-position', `from ${value} in oklch,`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops))`), + ] + } } + } - let value = candidate.value.value - - if (candidate.value.kind === 'arbitrary') { - return [ - decl('--tw-gradient-position', `${value},`), - decl('background-image', `conic-gradient(var(--tw-gradient-stops,${value}))`), - ] - } else { - if (!isPositiveInteger(value)) return - - value = withNegative(`${value}deg`, candidate) - - return [ - decl('--tw-gradient-position', `from ${value} in oklch,`), - decl('background-image', `conic-gradient(var(--tw-gradient-stops))`), - ] - } - }) + utilities.functional('-bg-conic', handleBgConic({ negative: true })) + utilities.functional('bg-conic', handleBgConic({ negative: false })) utilities.functional('bg-radial', (candidate) => { if (candidate.modifier) return @@ -2358,7 +2372,7 @@ export function createUtilities(theme: Theme) { }) utilities.functional('bg', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return // Arbitrary values if (candidate.value.kind === 'arbitrary') { @@ -2452,7 +2466,7 @@ export function createUtilities(theme: Theme) { function gradientStopUtility(classRoot: string, desc: GradientStopDescription) { utilities.functional(classRoot, (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return // Arbitrary values if (candidate.value.kind === 'arbitrary') { @@ -2601,7 +2615,7 @@ export function createUtilities(theme: Theme) { staticUtility('fill-none', [['fill', 'none']]) utilities.functional('fill', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return if (candidate.value.kind === 'arbitrary') { let value = asColor(candidate.value.value, candidate.modifier) @@ -2625,7 +2639,7 @@ export function createUtilities(theme: Theme) { staticUtility('stroke-none', [['stroke', 'none']]) utilities.functional('stroke', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return if (candidate.value.kind === 'arbitrary') { let value: string | null = candidate.value.value @@ -2738,7 +2752,7 @@ export function createUtilities(theme: Theme) { }) utilities.functional('font', (candidate) => { - if (candidate.negative || !candidate.value || candidate.modifier) return + if (!candidate.value || candidate.modifier) return if (candidate.value.kind === 'arbitrary') { let value = candidate.value.value @@ -2872,7 +2886,7 @@ export function createUtilities(theme: Theme) { staticUtility('decoration-from-font', [['text-decoration-thickness', 'from-font']]) utilities.functional('decoration', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return if (candidate.value.kind === 'arbitrary') { let value: string | null = candidate.value.value @@ -2988,7 +3002,7 @@ export function createUtilities(theme: Theme) { } utilities.functional('filter', (candidate) => { - if (candidate.negative || candidate.modifier) return + if (candidate.modifier) return if (candidate.value === null) { return [filterProperties(), decl('filter', cssFilterValue)] @@ -3005,7 +3019,7 @@ export function createUtilities(theme: Theme) { }) utilities.functional('backdrop-filter', (candidate) => { - if (candidate.negative || candidate.modifier) return + if (candidate.modifier) return if (candidate.value === null) { return [ @@ -3460,9 +3474,6 @@ export function createUtilities(theme: Theme) { staticUtility('duration-initial', [transitionDurationProperty, ['--tw-duration', 'initial']]) utilities.functional('duration', (candidate) => { - // This utility doesn't support negative values. - if (candidate.negative) return - // This utility doesn't support modifiers. if (candidate.modifier) return @@ -3739,8 +3750,6 @@ export function createUtilities(theme: Theme) { ]) utilities.functional('outline', (candidate) => { - if (candidate.negative) return - if (candidate.value === null) { if (candidate.modifier) return return [ @@ -3871,7 +3880,7 @@ export function createUtilities(theme: Theme) { ]) utilities.functional('text', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return if (candidate.value.kind === 'arbitrary') { let value: string | null = candidate.value.value @@ -4007,8 +4016,6 @@ export function createUtilities(theme: Theme) { staticUtility('shadow-initial', [boxShadowProperties, ['--tw-shadow-color', 'initial']]) utilities.functional('shadow', (candidate) => { - if (candidate.negative) return - if (!candidate.value) { let value = theme.get(['--shadow']) if (value === null) return @@ -4101,8 +4108,6 @@ export function createUtilities(theme: Theme) { ]) utilities.functional('inset-shadow', (candidate) => { - if (candidate.negative) return - if (!candidate.value) { let value = theme.get(['--inset-shadow']) if (value === null) return @@ -4197,8 +4202,6 @@ export function createUtilities(theme: Theme) { return `var(--tw-ring-inset,) 0 0 0 calc(${value} + var(--tw-ring-offset-width)) var(--tw-ring-color, ${defaultRingColor})` } utilities.functional('ring', (candidate) => { - if (candidate.negative) return - if (!candidate.value) { if (candidate.modifier) return let value = theme.get(['--default-ring-width']) ?? '1px' @@ -4273,8 +4276,6 @@ export function createUtilities(theme: Theme) { return `inset 0 0 0 ${value} var(--tw-inset-ring-color, currentColor)` } utilities.functional('inset-ring', (candidate) => { - if (candidate.negative) return - if (!candidate.value) { if (candidate.modifier) return return [ @@ -4347,7 +4348,7 @@ export function createUtilities(theme: Theme) { let ringOffsetShadowValue = 'var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)' utilities.functional('ring-offset', (candidate) => { - if (candidate.negative || !candidate.value) return + if (!candidate.value) return if (candidate.value.kind === 'arbitrary') { let value: string | null = candidate.value.value @@ -4411,8 +4412,6 @@ export function createUtilities(theme: Theme) { ]) utilities.functional('@container', (candidate) => { - if (candidate.negative) return - let value: string | null = null if (candidate.value === null) { value = 'inline-size'