diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d009df35983..865e232c1cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Include variable in output for bare utilities like `rounded` ([#13836](https://github.com/tailwindlabs/tailwindcss/pull/13836)) - Preserve list semantics for `ul`, `li`, and `menu` by default ([#13815](https://github.com/tailwindlabs/tailwindcss/pull/13815)) +### Fixed + +- Support combining arbitrary shadows without a color with shadow color utilities ([#13876](https://github.com/tailwindlabs/tailwindcss/pull/13876)) + ## [4.0.0-alpha.16] - 2024-06-07 ### Fixed diff --git a/packages/tailwindcss/src/utilities.test.ts b/packages/tailwindcss/src/utilities.test.ts index 36ad89a5c78b..e6d9d5bd6425 100644 --- a/packages/tailwindcss/src/utilities.test.ts +++ b/packages/tailwindcss/src/utilities.test.ts @@ -12019,7 +12019,7 @@ test('shadow', () => { .shadow-\\[10px_10px\\] { --tw-shadow: 10px 10px; - --tw-shadow-colored: 10px 10px; + --tw-shadow-colored: 10px 10px var(--tw-shadow-color); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } @@ -12271,7 +12271,7 @@ test('inset-shadow', () => { .inset-shadow-\\[10px_10px\\] { --tw-inset-shadow: inset 10px 10px; - --tw-inset-shadow-colored: inset 10px 10px; + --tw-inset-shadow-colored: inset 10px 10px var(--tw-inset-shadow-color); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } diff --git a/packages/tailwindcss/src/utils/replace-shadow-colors.test.ts b/packages/tailwindcss/src/utils/replace-shadow-colors.test.ts index 23895596c8d1..175273d80cd3 100644 --- a/packages/tailwindcss/src/utils/replace-shadow-colors.test.ts +++ b/packages/tailwindcss/src/utils/replace-shadow-colors.test.ts @@ -3,23 +3,35 @@ import { replaceShadowColors } from './replace-shadow-colors' const table = [ { - input: ['var(--my-shadow)'], + input: 'var(--my-shadow)', output: 'var(--my-shadow)', }, { - input: ['1px var(--my-shadow)'], + input: '1px var(--my-shadow)', output: '1px var(--my-shadow)', }, { - input: ['1px 1px var(--my-color)'], + input: '1px 1px var(--my-color)', output: '1px 1px var(--tw-shadow-color)', }, { - input: ['0 0 0 var(--my-color)'], + input: '0 0 0 var(--my-color)', output: '0 0 0 var(--tw-shadow-color)', }, { - input: ['var(--my-shadow)', '1px 1px var(--my-color)', '0 0 1px var(--my-color)'], + input: '1px 2px', + output: '1px 2px var(--tw-shadow-color)', + }, + { + input: '1px 2px 3px', + output: '1px 2px 3px var(--tw-shadow-color)', + }, + { + input: '1px 2px 3px 4px', + output: '1px 2px 3px 4px var(--tw-shadow-color)', + }, + { + input: ['var(--my-shadow)', '1px 1px var(--my-color)', '0 0 1px var(--my-color)'].join(', '), output: [ 'var(--my-shadow)', '1px 1px var(--tw-shadow-color)', @@ -29,9 +41,9 @@ const table = [ ] it.each(table)( - 'should be possible to get the names for an animation: $output', + 'should replace the color of box-shadow $input with $output', ({ input, output }) => { - let parsed = replaceShadowColors(input.join(', '), 'var(--tw-shadow-color)') + let parsed = replaceShadowColors(input, 'var(--tw-shadow-color)') expect(parsed).toEqual(output) }, ) diff --git a/packages/tailwindcss/src/utils/replace-shadow-colors.ts b/packages/tailwindcss/src/utils/replace-shadow-colors.ts index e758955be22b..cf6976d11596 100644 --- a/packages/tailwindcss/src/utils/replace-shadow-colors.ts +++ b/packages/tailwindcss/src/utils/replace-shadow-colors.ts @@ -27,10 +27,18 @@ export function replaceShadowColors(input: string, replacement: string): string } } - // Only replace if we found an x-offset, y-offset, and color, otherwise we - // may be replacing the wrong part of the box-shadow. - if (offsetX !== null && offsetY !== null && color !== null) { + // If the x and y offsets were not detected, the shadow is either invalid or + // using a variable to represent more than one field in the shadow value, so + // we can't know what to replace. + if (offsetX === null || offsetY === null) continue + + if (color !== null) { + // If a color was found, replace the color. input = input.replace(color, replacement) + } else { + // If no color was found, assume the shadow is relying on the browser + // default shadow color and append the replacement color. + input = `${input} ${replacement}` } } diff --git a/packages/tailwindcss/tests/ui.spec.ts b/packages/tailwindcss/tests/ui.spec.ts index 90e64d30edcb..3c65279b0892 100644 --- a/packages/tailwindcss/tests/ui.spec.ts +++ b/packages/tailwindcss/tests/ui.spec.ts @@ -166,6 +166,7 @@ test('shadow colors', async ({ page }) => { html`
+ `, ) @@ -187,6 +188,15 @@ test('shadow colors', async ({ page }) => { 'rgb(239, 68, 68) 0px 20px 25px -5px, rgb(239, 68, 68) 0px 8px 10px -6px', ].join(', '), ) + expect(await getPropertyValue('#z', 'box-shadow')).toEqual( + [ + 'rgba(0, 0, 0, 0) 0px 0px 0px 0px', + 'rgba(0, 0, 0, 0) 0px 0px 0px 0px', + 'rgba(0, 0, 0, 0) 0px 0px 0px 0px', + 'rgba(0, 0, 0, 0) 0px 0px 0px 0px', + 'rgb(239, 68, 68) 0px 2px 4px 0px', + ].join(', '), + ) }) test('outline style is optional', async ({ page }) => {