diff --git a/plugins/postcss-alpha-function/test/basic.css b/plugins/postcss-alpha-function/test/basic.css index d68b433ed9..368c4c4f4e 100644 --- a/plugins/postcss-alpha-function/test/basic.css +++ b/plugins/postcss-alpha-function/test/basic.css @@ -80,3 +80,14 @@ color-1: alpha(from color(srgb srgb-linear 0.5 1 0) / calc(alpha / 2)); color-2: alpha(from color(var(--foo) 0.5 1 0) / calc(alpha / 2)); } + +@property --foo { + inherits: false; + initial-value: alpha(from oklch(2 1 0) / calc(alpha / 2)); +} + +@keyframes --foo { + to { + --color: alpha(from oklch(2 1 0) / calc(alpha / 2)); + } +} diff --git a/plugins/postcss-alpha-function/test/basic.expect.css b/plugins/postcss-alpha-function/test/basic.expect.css index f472717c1b..6a26556d1a 100644 --- a/plugins/postcss-alpha-function/test/basic.expect.css +++ b/plugins/postcss-alpha-function/test/basic.expect.css @@ -80,3 +80,14 @@ color-1: alpha(from color(srgb srgb-linear 0.5 1 0) / calc(alpha / 2)); color-2: alpha(from color(var(--foo) 0.5 1 0) / calc(alpha / 2)); } + +@property --foo { + inherits: false; + initial-value: oklch(from oklch(2 1 0) l c h / calc(alpha / 2)); +} + +@keyframes --foo { + to { + --color: oklch(from oklch(2 1 0) l c h / calc(alpha / 2)); + } +} diff --git a/plugins/postcss-alpha-function/test/basic.preserve-true.expect.css b/plugins/postcss-alpha-function/test/basic.preserve-true.expect.css index 8f452bbcf2..9bc69e5311 100644 --- a/plugins/postcss-alpha-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-alpha-function/test/basic.preserve-true.expect.css @@ -161,3 +161,31 @@ color-1: alpha(from color(srgb srgb-linear 0.5 1 0) / calc(alpha / 2)); color-2: alpha(from color(var(--foo) 0.5 1 0) / calc(alpha / 2)); } + +@property --foo { + inherits: false; + initial-value: oklch(from oklch(2 1 0) l c h / calc(alpha / 2)); +} + +@supports (color: alpha(from red / 1)) and (color: oklab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: alpha(from oklch(2 1 0) / calc(alpha / 2)); +} +} + +@keyframes --foo { + to { + --color: oklch(from oklch(2 1 0) l c h / calc(alpha / 2)); + } +} + +@supports (color: alpha(from red / 1)) and (color: oklab(0% 0 0%)) { + +@keyframes --foo { + to { + --color: oklch(from oklch(2 1 0) l c h / calc(alpha / 2)); + --color: alpha(from oklch(2 1 0) / calc(alpha / 2)); + } +} +} diff --git a/plugins/postcss-color-function-display-p3-linear/test/basic.css b/plugins/postcss-color-function-display-p3-linear/test/basic.css index fa359a47ee..ef5986cffd 100644 --- a/plugins/postcss-color-function-display-p3-linear/test/basic.css +++ b/plugins/postcss-color-function-display-p3-linear/test/basic.css @@ -23,3 +23,14 @@ to-clone { color: color(display-p3-linear 1 0 0); } + +@property --foo { + inherits: false; + initial-value: color(display-p3-linear 0.1 0.1 0.1); +} + +@keyframes --foo { + to { + --color: color(display-p3-linear 0.1 0.1 0.1); + } +} diff --git a/plugins/postcss-color-function-display-p3-linear/test/basic.expect.css b/plugins/postcss-color-function-display-p3-linear/test/basic.expect.css index 09376f1082..411e7b2f4b 100644 --- a/plugins/postcss-color-function-display-p3-linear/test/basic.expect.css +++ b/plugins/postcss-color-function-display-p3-linear/test/basic.expect.css @@ -23,3 +23,14 @@ to-clone { color: color(display-p3 1 0 0); } + +@property --foo { + inherits: false; + initial-value: color(display-p3 0.34919 0.34919 0.34919); +} + +@keyframes --foo { + to { + --color: color(display-p3 0.34919 0.34919 0.34919); + } +} diff --git a/plugins/postcss-color-function-display-p3-linear/test/basic.preserve-true.expect.css b/plugins/postcss-color-function-display-p3-linear/test/basic.preserve-true.expect.css index a4468a7250..629dee34e0 100644 --- a/plugins/postcss-color-function-display-p3-linear/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-function-display-p3-linear/test/basic.preserve-true.expect.css @@ -27,3 +27,31 @@ to-clone { color: color(display-p3 1 0 0); color: color(display-p3-linear 1 0 0); } + +@property --foo { + inherits: false; + initial-value: color(display-p3 0.34919 0.34919 0.34919); +} + +@supports (color: color(display-p3-linear 0 0 0)) { +@property --foo { + inherits: false; + initial-value: color(display-p3-linear 0.1 0.1 0.1); +} +} + +@keyframes --foo { + to { + --color: color(display-p3 0.34919 0.34919 0.34919); + } +} + +@supports (color: color(display-p3-linear 0 0 0)) { + +@keyframes --foo { + to { + --color: color(display-p3 0.34919 0.34919 0.34919); + --color: color(display-p3-linear 0.1 0.1 0.1); + } +} +} diff --git a/plugins/postcss-color-function-display-p3-linear/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-function-display-p3-linear/test/basic.with-cloned-rules.expect.css index d0732ee5ee..62a00a75c5 100644 --- a/plugins/postcss-color-function-display-p3-linear/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-function-display-p3-linear/test/basic.with-cloned-rules.expect.css @@ -32,3 +32,31 @@ to-clone { color: color(display-p3 1 0 0); color: color(display-p3-linear 1 0 0); } + +@property --foo { + inherits: false; + initial-value: color(display-p3 0.34919 0.34919 0.34919); +} + +@supports (color: color(display-p3-linear 0 0 0)) { +@property --foo { + inherits: false; + initial-value: color(display-p3-linear 0.1 0.1 0.1); +} +} + +@keyframes --foo { + to { + --color: color(display-p3 0.34919 0.34919 0.34919); + } +} + +@supports (color: color(display-p3-linear 0 0 0)) { + +@keyframes --foo { + to { + --color: color(display-p3 0.34919 0.34919 0.34919); + --color: color(display-p3-linear 0.1 0.1 0.1); + } +} +} diff --git a/plugins/postcss-color-function/test/basic.css b/plugins/postcss-color-function/test/basic.css index 535ce48caa..2e0981039b 100644 --- a/plugins/postcss-color-function/test/basic.css +++ b/plugins/postcss-color-function/test/basic.css @@ -221,3 +221,14 @@ to-clone { color: color(display-p3 1 0 0); } + +@property --foo { + inherits: false; + initial-value: color(display-p3 0.1 0.1 0.1); +} + +@keyframes --foo { + to { + --color: color(display-p3 0.1 0.1 0.1); + } +} diff --git a/plugins/postcss-color-function/test/basic.expect.css b/plugins/postcss-color-function/test/basic.expect.css index 90a079d816..9ab934f7de 100644 --- a/plugins/postcss-color-function/test/basic.expect.css +++ b/plugins/postcss-color-function/test/basic.expect.css @@ -221,3 +221,14 @@ to-clone { color: rgb(255, 52, 40); } + +@property --foo { + inherits: false; + initial-value: rgb(26, 26, 26); +} + +@keyframes --foo { + to { + --color: rgb(26, 26, 26); + } +} diff --git a/plugins/postcss-color-function/test/basic.preserve-true.expect.css b/plugins/postcss-color-function/test/basic.preserve-true.expect.css index e776c2a9c8..bb4fcd5938 100644 --- a/plugins/postcss-color-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-function/test/basic.preserve-true.expect.css @@ -324,3 +324,31 @@ to-clone { color: rgb(255, 52, 40); color: color(display-p3 1 0 0); } + +@property --foo { + inherits: false; + initial-value: rgb(26, 26, 26); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.1 0.1 0.1); +} +} + +@keyframes --foo { + to { + --color: rgb(26, 26, 26); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --color: rgb(26, 26, 26); + --color: color(display-p3 0.1 0.1 0.1); + } +} +} diff --git a/plugins/postcss-color-function/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-function/test/basic.with-cloned-rules.expect.css index cfd566f5ed..ac52f37af9 100644 --- a/plugins/postcss-color-function/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-function/test/basic.with-cloned-rules.expect.css @@ -329,3 +329,31 @@ to-clone { color: rgb(255, 52, 40); color: color(display-p3 1 0 0); } + +@property --foo { + inherits: false; + initial-value: rgb(26, 26, 26); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.1 0.1 0.1); +} +} + +@keyframes --foo { + to { + --color: rgb(26, 26, 26); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --color: rgb(26, 26, 26); + --color: color(display-p3 0.1 0.1 0.1); + } +} +} diff --git a/plugins/postcss-color-functional-notation/test/basic.css b/plugins/postcss-color-functional-notation/test/basic.css index ea5eab39dc..8e6f8a26f3 100644 --- a/plugins/postcss-color-functional-notation/test/basic.css +++ b/plugins/postcss-color-functional-notation/test/basic.css @@ -106,3 +106,14 @@ to-clone { color: rgb(255 0 0); } + +@property --foo { + inherits: false; + initial-value: rgb(255 0 0); +} + +@keyframes --foo { + to { + --color: rgb(255 0 0); + } +} diff --git a/plugins/postcss-color-functional-notation/test/basic.expect.css b/plugins/postcss-color-functional-notation/test/basic.expect.css index b9fff76722..7747fda78b 100644 --- a/plugins/postcss-color-functional-notation/test/basic.expect.css +++ b/plugins/postcss-color-functional-notation/test/basic.expect.css @@ -106,3 +106,14 @@ to-clone { color: rgb(255, 0, 0); } + +@property --foo { + inherits: false; + initial-value: rgb(255, 0, 0); +} + +@keyframes --foo { + to { + --color: rgb(255, 0, 0); + } +} diff --git a/plugins/postcss-color-functional-notation/test/basic.preserve-true.expect.css b/plugins/postcss-color-functional-notation/test/basic.preserve-true.expect.css index 6e1b467dd7..cea9a6ffff 100644 --- a/plugins/postcss-color-functional-notation/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-functional-notation/test/basic.preserve-true.expect.css @@ -168,3 +168,31 @@ to-clone { color: rgb(255, 0, 0); color: rgb(255 0 0); } + +@property --foo { + inherits: false; + initial-value: rgb(255, 0, 0); +} + +@supports (color: rgb(0 0 0 / 0)) { +@property --foo { + inherits: false; + initial-value: rgb(255 0 0); +} +} + +@keyframes --foo { + to { + --color: rgb(255, 0, 0); + } +} + +@supports (color: rgb(0 0 0 / 0)) { + +@keyframes --foo { + to { + --color: rgb(255, 0, 0); + --color: rgb(255 0 0); + } +} +} diff --git a/plugins/postcss-color-functional-notation/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-functional-notation/test/basic.with-cloned-rules.expect.css index 5e5a99e127..64b6dd3251 100644 --- a/plugins/postcss-color-functional-notation/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-functional-notation/test/basic.with-cloned-rules.expect.css @@ -173,3 +173,31 @@ to-clone { color: rgb(255, 0, 0); color: rgb(255 0 0); } + +@property --foo { + inherits: false; + initial-value: rgb(255, 0, 0); +} + +@supports (color: rgb(0 0 0 / 0)) { +@property --foo { + inherits: false; + initial-value: rgb(255 0 0); +} +} + +@keyframes --foo { + to { + --color: rgb(255, 0, 0); + } +} + +@supports (color: rgb(0 0 0 / 0)) { + +@keyframes --foo { + to { + --color: rgb(255, 0, 0); + --color: rgb(255 0 0); + } +} +} diff --git a/plugins/postcss-color-hex-alpha/CHANGELOG.md b/plugins/postcss-color-hex-alpha/CHANGELOG.md index 0bc47a0a7f..63d0c45e23 100644 --- a/plugins/postcss-color-hex-alpha/CHANGELOG.md +++ b/plugins/postcss-color-hex-alpha/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Color Hex Alpha +### Unreleased (patch) + +- Ignore `initial-value` in `@property` + ### 11.0.0 _January 14, 2026_ diff --git a/plugins/postcss-color-hex-alpha/dist/index.mjs b/plugins/postcss-color-hex-alpha/dist/index.mjs index db7a7f6e0b..abac5b761b 100644 --- a/plugins/postcss-color-hex-alpha/dist/index.mjs +++ b/plugins/postcss-color-hex-alpha/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";import{hasFallback as s}from"@csstools/utilities";const creator=a=>{const o=Object.assign({preserve:!1},a);return{postcssPlugin:"postcss-color-hex-alpha",Declaration(a){if(!t.test(a.value))return;if(s(a))return;const{value:l}=a,n=e(l);n.walk(e=>{if("function"===e.type&&"url"===e.value)return!1;"word"===e.type&&r.test(e.value)&&hexa2rgba(e)});const c=n.toString();c!==l&&(a.cloneBefore({value:c}),o.preserve||a.remove())}}};creator.postcss=!0;const t=/#[0-9a-f]{4}(?:[0-9a-f]{4})?\b/i,r=/^#[0-9a-f]{4}(?:[0-9a-f]{4})?$/i,a=1e5,o=/[0-9a-f]/gi;function hexa2rgba(e){const s=e.value,t=`0x${5===s.length?s.slice(1).replace(o,"$&$&"):s.slice(1)}`,[r,l,n,c]=[parseInt(t.slice(2,4),16),parseInt(t.slice(4,6),16),parseInt(t.slice(6,8),16),Math.round(parseInt(t.slice(8,10),16)/255*a)/a];e.value=`rgba(${r},${l},${n},${c})`}export{creator as default,creator as"module.exports"}; +import e from"postcss-value-parser";import{hasFallback as t}from"@csstools/utilities";const creator=a=>{const o=Object.assign({preserve:!1},a);return{postcssPlugin:"postcss-color-hex-alpha",Declaration(a){if(!r.test(a.value))return;if(t(a))return;if("atrule"===a.parent?.type&&"property"===a.parent.name.toLowerCase())return;const{value:n}=a,l=e(n);l.walk(e=>{if("function"===e.type&&"url"===e.value)return!1;"word"===e.type&&s.test(e.value)&&hexa2rgba(e)});const c=l.toString();c!==n&&(a.cloneBefore({value:c}),o.preserve||a.remove())}}};creator.postcss=!0;const r=/#[0-9a-f]{4}(?:[0-9a-f]{4})?\b/i,s=/^#[0-9a-f]{4}(?:[0-9a-f]{4})?$/i,a=1e5,o=/[0-9a-f]/gi;function hexa2rgba(e){const t=e.value,r=`0x${5===t.length?t.slice(1).replace(o,"$&$&"):t.slice(1)}`,[s,n,l,c]=[parseInt(r.slice(2,4),16),parseInt(r.slice(4,6),16),parseInt(r.slice(6,8),16),Math.round(parseInt(r.slice(8,10),16)/255*a)/a];e.value=`rgba(${s},${n},${l},${c})`}export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-color-hex-alpha/src/index.ts b/plugins/postcss-color-hex-alpha/src/index.ts index 72f5c1203f..0bd4bfaa6b 100644 --- a/plugins/postcss-color-hex-alpha/src/index.ts +++ b/plugins/postcss-color-hex-alpha/src/index.ts @@ -29,6 +29,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (decl.parent?.type === 'atrule' && decl.parent.name.toLowerCase() === 'property') { + return; + } + const { value: originalValue } = decl; // replace instances of hexa with rgba() diff --git a/plugins/postcss-color-hex-alpha/test/basic.css b/plugins/postcss-color-hex-alpha/test/basic.css index d7f0442b61..424c757feb 100644 --- a/plugins/postcss-color-hex-alpha/test/basic.css +++ b/plugins/postcss-color-hex-alpha/test/basic.css @@ -23,3 +23,14 @@ body { to-clone { color: #9823f8a9; } + +@property --foo { + inherits: false; + initial-value: #9823f8a9; +} + +@keyframes --foo { + to { + --color: #9823f8a9; + } +} diff --git a/plugins/postcss-color-hex-alpha/test/basic.expect.css b/plugins/postcss-color-hex-alpha/test/basic.expect.css index 9e3d309b63..f6ce0370f9 100644 --- a/plugins/postcss-color-hex-alpha/test/basic.expect.css +++ b/plugins/postcss-color-hex-alpha/test/basic.expect.css @@ -23,3 +23,14 @@ body { to-clone { color: rgba(152,35,248,0.66275); } + +@property --foo { + inherits: false; + initial-value: #9823f8a9; +} + +@keyframes --foo { + to { + --color: rgba(152,35,248,0.66275); + } +} diff --git a/plugins/postcss-color-hex-alpha/test/basic.preserve.expect.css b/plugins/postcss-color-hex-alpha/test/basic.preserve.expect.css index 2d7de5dbd6..4c4a3c4de7 100644 --- a/plugins/postcss-color-hex-alpha/test/basic.preserve.expect.css +++ b/plugins/postcss-color-hex-alpha/test/basic.preserve.expect.css @@ -27,3 +27,15 @@ to-clone { color: rgba(152,35,248,0.66275); color: #9823f8a9; } + +@property --foo { + inherits: false; + initial-value: #9823f8a9; +} + +@keyframes --foo { + to { + --color: rgba(152,35,248,0.66275); + --color: #9823f8a9; + } +} diff --git a/plugins/postcss-color-hex-alpha/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-hex-alpha/test/basic.with-cloned-rules.expect.css index dbb6bad428..9aa7b974a0 100644 --- a/plugins/postcss-color-hex-alpha/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-hex-alpha/test/basic.with-cloned-rules.expect.css @@ -32,3 +32,15 @@ to-clone { color: rgba(152,35,248,0.66275); color: #9823f8a9; } + +@property --foo { + inherits: false; + initial-value: #9823f8a9; +} + +@keyframes --foo { + to { + --color: rgba(152,35,248,0.66275); + --color: #9823f8a9; + } +} diff --git a/plugins/postcss-color-mix-function/test/basic.css b/plugins/postcss-color-mix-function/test/basic.css index 23890bce56..8a0b9eb770 100644 --- a/plugins/postcss-color-mix-function/test/basic.css +++ b/plugins/postcss-color-mix-function/test/basic.css @@ -182,3 +182,14 @@ .default-interpolation-space { color: color-mix(#09232c, white 50%); } + +@property --foo { + inherits: false; + initial-value: color-mix(#09232c, white 50%); +} + +@keyframes --foo { + to { + --color: color-mix(#09232c, white 50%); + } +} diff --git a/plugins/postcss-color-mix-function/test/basic.expect.css b/plugins/postcss-color-mix-function/test/basic.expect.css index d0e9dd1ee9..2969e4d4c5 100644 --- a/plugins/postcss-color-mix-function/test/basic.expect.css +++ b/plugins/postcss-color-mix-function/test/basic.expect.css @@ -188,3 +188,14 @@ .default-interpolation-space { color: rgb(123, 137, 142); } + +@property --foo { + inherits: false; + initial-value: rgb(123, 137, 142); +} + +@keyframes --foo { + to { + --color: rgb(123, 137, 142); + } +} diff --git a/plugins/postcss-color-mix-function/test/basic.preserve-true.expect.css b/plugins/postcss-color-mix-function/test/basic.preserve-true.expect.css index 4e7751a7ee..1f29d4ea57 100644 --- a/plugins/postcss-color-mix-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-mix-function/test/basic.preserve-true.expect.css @@ -269,3 +269,31 @@ color: rgb(123, 137, 142); color: color-mix(#09232c, white 50%); } + +@property --foo { + inherits: false; + initial-value: rgb(123, 137, 142); +} + +@supports (color: color-mix(red, blue)) { +@property --foo { + inherits: false; + initial-value: color-mix(#09232c, white 50%); +} +} + +@keyframes --foo { + to { + --color: rgb(123, 137, 142); + } +} + +@supports (color: color-mix(red, blue)) { + +@keyframes --foo { + to { + --color: rgb(123, 137, 142); + --color: color-mix(#09232c, white 50%); + } +} +} diff --git a/plugins/postcss-color-mix-function/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-mix-function/test/basic.with-cloned-rules.expect.css index 4e7751a7ee..1f29d4ea57 100644 --- a/plugins/postcss-color-mix-function/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-mix-function/test/basic.with-cloned-rules.expect.css @@ -269,3 +269,31 @@ color: rgb(123, 137, 142); color: color-mix(#09232c, white 50%); } + +@property --foo { + inherits: false; + initial-value: rgb(123, 137, 142); +} + +@supports (color: color-mix(red, blue)) { +@property --foo { + inherits: false; + initial-value: color-mix(#09232c, white 50%); +} +} + +@keyframes --foo { + to { + --color: rgb(123, 137, 142); + } +} + +@supports (color: color-mix(red, blue)) { + +@keyframes --foo { + to { + --color: rgb(123, 137, 142); + --color: color-mix(#09232c, white 50%); + } +} +} diff --git a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.css b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.css index 3337540a48..2b7de75b8c 100644 --- a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.css +++ b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.css @@ -19,5 +19,16 @@ } .zero-percentage { - color: color-mix(in srgb, blue 0%, yellow 0%); + color: color-mix(in srgb, blue 0%, green 0%, yellow 0%); +} + +@property --foo { + inherits: false; + initial-value: color-mix(in oklch, red, lime, green); +} + +@keyframes --foo { + to { + --color: color-mix(in oklch, red, lime, green); + } } diff --git a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.expect.css b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.expect.css index 29a6137cd6..a83122a4c4 100644 --- a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.expect.css +++ b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.expect.css @@ -21,5 +21,33 @@ } .zero-percentage { - color: color-mix(in srgb, blue 0%, yellow 0%); + color: rgba(128, 159, 64, 0); +} + +@property --foo { + inherits: false; + initial-value: rgb(164, 153, 0); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.64336 0.60238 0); +} +} + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + --color: color(display-p3 0.64336 0.60238 0); + } +} } diff --git a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.preserve-true.expect.css b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.preserve-true.expect.css index 8053aea300..c3dc0c6020 100644 --- a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.preserve-true.expect.css @@ -26,5 +26,42 @@ } .zero-percentage { - color: color-mix(in srgb, blue 0%, yellow 0%); + color: rgba(128, 159, 64, 0); + color: color-mix(in srgb, blue 0%, green 0%, yellow 0%); +} + +@property --foo { + inherits: false; + initial-value: rgb(164, 153, 0); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.64336 0.60238 0); +} +} + +@supports (color: color-mix(in lch, red)) { +@property --foo { + inherits: false; + initial-value: color-mix(in oklch, red, lime, green); +} +} + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: color-mix(in lch, red)) { + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + --color: color(display-p3 0.64336 0.60238 0); + --color: color-mix(in oklch, red, lime, green); + } +} } diff --git a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.with-cloned-rules.expect.css index 8053aea300..c3dc0c6020 100644 --- a/plugins/postcss-color-mix-variadic-function-arguments/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-mix-variadic-function-arguments/test/basic.with-cloned-rules.expect.css @@ -26,5 +26,42 @@ } .zero-percentage { - color: color-mix(in srgb, blue 0%, yellow 0%); + color: rgba(128, 159, 64, 0); + color: color-mix(in srgb, blue 0%, green 0%, yellow 0%); +} + +@property --foo { + inherits: false; + initial-value: rgb(164, 153, 0); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.64336 0.60238 0); +} +} + +@supports (color: color-mix(in lch, red)) { +@property --foo { + inherits: false; + initial-value: color-mix(in oklch, red, lime, green); +} +} + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: color-mix(in lch, red)) { + +@keyframes --foo { + to { + --color: rgb(164, 153, 0); + --color: color(display-p3 0.64336 0.60238 0); + --color: color-mix(in oklch, red, lime, green); + } +} } diff --git a/plugins/postcss-color-rebeccapurple/CHANGELOG.md b/plugins/postcss-color-rebeccapurple/CHANGELOG.md index 108ede24c3..7ede85a017 100644 --- a/plugins/postcss-color-rebeccapurple/CHANGELOG.md +++ b/plugins/postcss-color-rebeccapurple/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS RebeccaPurple +### Unreleased (patch) + +- Ignore `initial-value` in `@property` + ### 11.0.0 _January 14, 2026_ diff --git a/plugins/postcss-color-rebeccapurple/dist/index.mjs b/plugins/postcss-color-rebeccapurple/dist/index.mjs index 42a7750261..28a10602d4 100644 --- a/plugins/postcss-color-rebeccapurple/dist/index.mjs +++ b/plugins/postcss-color-rebeccapurple/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";import{hasFallback as r}from"@csstools/utilities";const s=/rebeccapurple/i,t=/^rebeccapurple$/i,creator=o=>{const c=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-color-rebeccapurple",Declaration(o){if(!s.test(o.value))return;if(r(o))return;const l=e(o.value);l.walk(e=>{"word"===e.type&&t.test(e.value)&&(e.value="#639")});const a=String(l);a!==o.value&&(o.cloneBefore({value:a}),c.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import e from"postcss-value-parser";import{hasFallback as r}from"@csstools/utilities";const t=/rebeccapurple/i,s=/^rebeccapurple$/i,creator=o=>{const a=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-color-rebeccapurple",Declaration(o){if(!t.test(o.value))return;if(r(o))return;if("atrule"===o.parent?.type&&"property"===o.parent.name.toLowerCase())return;const p=e(o.value);p.walk(e=>{"word"===e.type&&s.test(e.value)&&(e.value="#639")});const l=String(p);l!==o.value&&(o.cloneBefore({value:l}),a.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-color-rebeccapurple/src/index.ts b/plugins/postcss-color-rebeccapurple/src/index.ts index 03a8eec970..a2d7a83b7b 100644 --- a/plugins/postcss-color-rebeccapurple/src/index.ts +++ b/plugins/postcss-color-rebeccapurple/src/index.ts @@ -32,6 +32,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (decl.parent?.type === 'atrule' && decl.parent.name.toLowerCase() === 'property') { + return; + } + const valueAST = valuesParser(decl.value); valueAST.walk(node => { if (node.type === 'word' && IS_REBECCAPURPLE_REGEX.test(node.value)) { diff --git a/plugins/postcss-color-rebeccapurple/test/basic.css b/plugins/postcss-color-rebeccapurple/test/basic.css index bec8ea94c5..534a99c318 100644 --- a/plugins/postcss-color-rebeccapurple/test/basic.css +++ b/plugins/postcss-color-rebeccapurple/test/basic.css @@ -15,3 +15,14 @@ footer { to-clone { color: rebeccapurple; } + +@property --foo { + inherits: false; + initial-value: rebeccapurple; +} + +@keyframes --foo { + to { + --color: rebeccapurple; + } +} diff --git a/plugins/postcss-color-rebeccapurple/test/basic.expect.css b/plugins/postcss-color-rebeccapurple/test/basic.expect.css index abcab496d1..aaa63df3ed 100644 --- a/plugins/postcss-color-rebeccapurple/test/basic.expect.css +++ b/plugins/postcss-color-rebeccapurple/test/basic.expect.css @@ -15,3 +15,14 @@ footer { to-clone { color: #639; } + +@property --foo { + inherits: false; + initial-value: rebeccapurple; +} + +@keyframes --foo { + to { + --color: #639; + } +} diff --git a/plugins/postcss-color-rebeccapurple/test/basic.preserve-true.expect.css b/plugins/postcss-color-rebeccapurple/test/basic.preserve-true.expect.css index f9c9eef95b..b3a2ef6dda 100644 --- a/plugins/postcss-color-rebeccapurple/test/basic.preserve-true.expect.css +++ b/plugins/postcss-color-rebeccapurple/test/basic.preserve-true.expect.css @@ -19,3 +19,15 @@ to-clone { color: #639; color: rebeccapurple; } + +@property --foo { + inherits: false; + initial-value: rebeccapurple; +} + +@keyframes --foo { + to { + --color: #639; + --color: rebeccapurple; + } +} diff --git a/plugins/postcss-color-rebeccapurple/test/basic.with-cloned-rules.expect.css b/plugins/postcss-color-rebeccapurple/test/basic.with-cloned-rules.expect.css index afeaad40d5..d734458d07 100644 --- a/plugins/postcss-color-rebeccapurple/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-color-rebeccapurple/test/basic.with-cloned-rules.expect.css @@ -24,3 +24,15 @@ to-clone { color: #639; color: rebeccapurple; } + +@property --foo { + inherits: false; + initial-value: rebeccapurple; +} + +@keyframes --foo { + to { + --color: #639; + --color: rebeccapurple; + } +} diff --git a/plugins/postcss-content-alt-text/test/basic.css b/plugins/postcss-content-alt-text/test/basic.css index b6a1edb185..de968618af 100644 --- a/plugins/postcss-content-alt-text/test/basic.css +++ b/plugins/postcss-content-alt-text/test/basic.css @@ -49,3 +49,9 @@ */ content: ">" / ""; } + +@keyframes --foo { + to { + content: var(--b) / var(--a); + } +} diff --git a/plugins/postcss-content-alt-text/test/basic.expect.css b/plugins/postcss-content-alt-text/test/basic.expect.css index 7edb8dcb52..3c17e1a1da 100644 --- a/plugins/postcss-content-alt-text/test/basic.expect.css +++ b/plugins/postcss-content-alt-text/test/basic.expect.css @@ -59,3 +59,19 @@ content: ">" ; content: ">" / ""; } + +@keyframes --foo { + to { + content: var(--b) var(--a); + } +} + +@supports (content: "a" / "a") { + +@keyframes --foo { + to { + content: var(--b) var(--a); + content: var(--b) / var(--a); + } +} +} diff --git a/plugins/postcss-content-alt-text/test/basic.preserve-false.expect.css b/plugins/postcss-content-alt-text/test/basic.preserve-false.expect.css index 11857876a2..843efc0fa8 100644 --- a/plugins/postcss-content-alt-text/test/basic.preserve-false.expect.css +++ b/plugins/postcss-content-alt-text/test/basic.preserve-false.expect.css @@ -49,3 +49,9 @@ */ content: ">" ; } + +@keyframes --foo { + to { + content: var(--b) var(--a); + } +} diff --git a/plugins/postcss-content-alt-text/test/basic.strip-alt-text.expect.css b/plugins/postcss-content-alt-text/test/basic.strip-alt-text.expect.css index c72518288f..e1874ed330 100644 --- a/plugins/postcss-content-alt-text/test/basic.strip-alt-text.expect.css +++ b/plugins/postcss-content-alt-text/test/basic.strip-alt-text.expect.css @@ -59,3 +59,19 @@ content: ">" ; content: ">" / ""; } + +@keyframes --foo { + to { + content: var(--b) ; + } +} + +@supports (content: "a" / "a") { + +@keyframes --foo { + to { + content: var(--b) ; + content: var(--b) / var(--a); + } +} +} diff --git a/plugins/postcss-contrast-color-function/test/variables.css b/plugins/postcss-contrast-color-function/test/variables.css index fb27d82be7..e2c75e343b 100644 --- a/plugins/postcss-contrast-color-function/test/variables.css +++ b/plugins/postcss-contrast-color-function/test/variables.css @@ -1,3 +1,14 @@ .a { --color: contrast-color(oklch(82.06% 0.2 330.35)); } + +@property --foo { + inherits: false; + initial-value: contrast-color(green); +} + +@keyframes --foo { + to { + --foo: contrast-color(green); + } +} diff --git a/plugins/postcss-contrast-color-function/test/variables.expect.css b/plugins/postcss-contrast-color-function/test/variables.expect.css index c3abb7f377..736104ec8b 100644 --- a/plugins/postcss-contrast-color-function/test/variables.expect.css +++ b/plugins/postcss-contrast-color-function/test/variables.expect.css @@ -7,3 +7,31 @@ --color: contrast-color(oklch(82.06% 0.2 330.35)); } } + +@property --foo { + inherits: false; + initial-value: rgb(255, 255, 255); +} + +@supports (color: contrast-color(red)) { +@property --foo { + inherits: false; + initial-value: contrast-color(green); +} +} + +@keyframes --foo { + to { + --foo: rgb(255, 255, 255); + } +} + +@supports (color: contrast-color(red)) { + +@keyframes --foo { + to { + --foo: rgb(255, 255, 255); + --foo: contrast-color(green); + } +} +} diff --git a/plugins/postcss-contrast-color-function/test/variables.preserve-false.expect.css b/plugins/postcss-contrast-color-function/test/variables.preserve-false.expect.css index 5651aec305..4efc78fc68 100644 --- a/plugins/postcss-contrast-color-function/test/variables.preserve-false.expect.css +++ b/plugins/postcss-contrast-color-function/test/variables.preserve-false.expect.css @@ -1,3 +1,14 @@ .a { --color: rgb(0, 0, 0); } + +@property --foo { + inherits: false; + initial-value: rgb(255, 255, 255); +} + +@keyframes --foo { + to { + --foo: rgb(255, 255, 255); + } +} diff --git a/plugins/postcss-double-position-gradients/test/basic.css b/plugins/postcss-double-position-gradients/test/basic.css index 501e1fed42..b42451bcfd 100644 --- a/plugins/postcss-double-position-gradients/test/basic.css +++ b/plugins/postcss-double-position-gradients/test/basic.css @@ -77,3 +77,14 @@ to-clone { background: linear-gradient(90deg, black 25% 50%, blue 50% 75%); } + +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25% 50%, blue 50% 75%); +} + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25% 50%, blue 50% 75%); + } +} diff --git a/plugins/postcss-double-position-gradients/test/basic.expect.css b/plugins/postcss-double-position-gradients/test/basic.expect.css index 2b9d203b1b..5a2fefe8f1 100644 --- a/plugins/postcss-double-position-gradients/test/basic.expect.css +++ b/plugins/postcss-double-position-gradients/test/basic.expect.css @@ -118,3 +118,31 @@ to-clone { background: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); background: linear-gradient(90deg, black 25% 50%, blue 50% 75%); } + +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); +} + +@supports (background: linear-gradient(red 0%, red 0% 1%, red 2%)) { +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25% 50%, blue 50% 75%); +} +} + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); + } +} + +@supports (background: linear-gradient(red 0%, red 0% 1%, red 2%)) { + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); + --foo: linear-gradient(90deg, black 25% 50%, blue 50% 75%); + } +} +} diff --git a/plugins/postcss-double-position-gradients/test/basic.preserve.expect.css b/plugins/postcss-double-position-gradients/test/basic.preserve.expect.css index f5bbb71f9d..6ecf9cf843 100644 --- a/plugins/postcss-double-position-gradients/test/basic.preserve.expect.css +++ b/plugins/postcss-double-position-gradients/test/basic.preserve.expect.css @@ -77,3 +77,14 @@ to-clone { background: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); } + +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); +} + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); + } +} diff --git a/plugins/postcss-double-position-gradients/test/basic.with-cloned-rules.expect.css b/plugins/postcss-double-position-gradients/test/basic.with-cloned-rules.expect.css index c829894f9c..88296f8e0f 100644 --- a/plugins/postcss-double-position-gradients/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-double-position-gradients/test/basic.with-cloned-rules.expect.css @@ -123,3 +123,31 @@ to-clone { background: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); background: linear-gradient(90deg, black 25% 50%, blue 50% 75%); } + +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); +} + +@supports (background: linear-gradient(red 0%, red 0% 1%, red 2%)) { +@property --foo { + inherits: false; + initial-value: linear-gradient(90deg, black 25% 50%, blue 50% 75%); +} +} + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); + } +} + +@supports (background: linear-gradient(red 0%, red 0% 1%, red 2%)) { + +@keyframes --foo { + to { + --foo: linear-gradient(90deg, black 25%,black 50%, blue 50%, blue 75%); + --foo: linear-gradient(90deg, black 25% 50%, blue 50% 75%); + } +} +} diff --git a/plugins/postcss-exponential-functions/CHANGELOG.md b/plugins/postcss-exponential-functions/CHANGELOG.md index 8d906d0ca4..299c497ff5 100644 --- a/plugins/postcss-exponential-functions/CHANGELOG.md +++ b/plugins/postcss-exponential-functions/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Exponential Functions +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 3.0.4 _July 22, 2026_ diff --git a/plugins/postcss-exponential-functions/dist/index.mjs b/plugins/postcss-exponential-functions/dist/index.mjs index 10b296798b..7db1d5b620 100644 --- a/plugins/postcss-exponential-functions/dist/index.mjs +++ b/plugins/postcss-exponential-functions/dist/index.mjs @@ -1 +1 @@ -import{calc as e}from"@csstools/css-calc";const s=/(?{const t=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-exponential-functions",Declaration(o){if(!s.test(o.value))return;const r=e(o.value);r!==o.value&&(o.cloneBefore({value:r}),t.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{calc as e}from"@csstools/css-calc";const s=/(?{const r=Object.assign({preserve:!1},t);return{postcssPlugin:"postcss-exponential-functions",Declaration(t){if(!s.test(t.value))return;if(r.preserve&&"atrule"===t.parent?.type&&"property"===t.parent.name.toLowerCase())return;const o=e(t.value);o!==t.value&&(t.cloneBefore({value:o}),r.preserve||t.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-exponential-functions/src/index.ts b/plugins/postcss-exponential-functions/src/index.ts index 4e592ea270..d174f73f49 100644 --- a/plugins/postcss-exponential-functions/src/index.ts +++ b/plugins/postcss-exponential-functions/src/index.ts @@ -26,6 +26,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && decl.parent.name.toLowerCase() === 'property') { + return; + } + const modifiedValue = calc(decl.value); if (modifiedValue === decl.value) { return; diff --git a/plugins/postcss-exponential-functions/test/basic.css b/plugins/postcss-exponential-functions/test/basic.css index dc0a0322e6..91fc41fc59 100644 --- a/plugins/postcss-exponential-functions/test/basic.css +++ b/plugins/postcss-exponential-functions/test/basic.css @@ -194,3 +194,14 @@ --prop-003: pow-a(1, 1); --prop-004: a-pow(1, 1); } + +@property --foo { + inherits: false; + initial-value: log(exp(1)); +} + +@keyframes --foo { + to { + --foo: log(exp(1)); + } +} diff --git a/plugins/postcss-exponential-functions/test/basic.expect.css b/plugins/postcss-exponential-functions/test/basic.expect.css index 9d796bf1e8..b1b56d6f0a 100644 --- a/plugins/postcss-exponential-functions/test/basic.expect.css +++ b/plugins/postcss-exponential-functions/test/basic.expect.css @@ -194,3 +194,14 @@ --prop-003: pow-a(1, 1); --prop-004: a-pow(1, 1); } + +@property --foo { + inherits: false; + initial-value: 1; +} + +@keyframes --foo { + to { + --foo: 1; + } +} diff --git a/plugins/postcss-exponential-functions/test/basic.preserve.expect.css b/plugins/postcss-exponential-functions/test/basic.preserve.expect.css index 51458794aa..38941791ed 100644 --- a/plugins/postcss-exponential-functions/test/basic.preserve.expect.css +++ b/plugins/postcss-exponential-functions/test/basic.preserve.expect.css @@ -252,3 +252,15 @@ --prop-003: pow-a(1, 1); --prop-004: a-pow(1, 1); } + +@property --foo { + inherits: false; + initial-value: log(exp(1)); +} + +@keyframes --foo { + to { + --foo: 1; + --foo: log(exp(1)); + } +} diff --git a/plugins/postcss-gamut-mapping/CHANGELOG.md b/plugins/postcss-gamut-mapping/CHANGELOG.md index 2c7717a53d..cab53ab1de 100644 --- a/plugins/postcss-gamut-mapping/CHANGELOG.md +++ b/plugins/postcss-gamut-mapping/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes to PostCSS gamut-mapping +### Unreleased (patch) + +- Ignore `initial-value` in `@property` +- Ignore wide gamut colors in `@keyframes` + ### 3.0.10 _August 31, 2026_ diff --git a/plugins/postcss-gamut-mapping/dist/index.mjs b/plugins/postcss-gamut-mapping/dist/index.mjs index 6299b9da4e..fc54dfe8a8 100644 --- a/plugins/postcss-gamut-mapping/dist/index.mjs +++ b/plugins/postcss-gamut-mapping/dist/index.mjs @@ -1 +1 @@ -import{tokenize as e}from"@csstools/css-tokenizer";import{replaceComponentValues as o,parseCommaSeparatedListOfComponentValues as t,isFunctionNode as s,stringify as a}from"@csstools/css-parser-algorithms";import{color as n,SyntaxFlag as r,colorDataFitsRGB_Gamut as l,colorDataFitsDisplayP3_Gamut as i,serializeRGB as c}from"@csstools/css-color-parser";const p=/\bcolor-gamut\b/i;function hasConditionalAncestor(e){let o=e.parent;for(;o;)if("atrule"===o.type){if("media"===o.name.toLowerCase()&&p.test(o.params))return!0;o=o.parent}else o=o.parent;return!1}function sameProperty(e){const o=e.prop.toLowerCase(),t=[],s=e.parent?.nodes??[];for(let e=0;e({postcssPlugin:"postcss-gamut-mapping",prepare(){const p=new WeakMap,m=new WeakSet;return{postcssPlugin:"postcss-gamut-mapping",OnceExit(f,{postcss:h}){f.walkDecls(f=>{if(m.has(f))return;if(!d.test(f.value))return;if(!f.parent||hasConditionalAncestor(f))return;const g=sameProperty(f).map((p,d)=>{m.add(p);let f=!1;const h=p.value,g=o(t(e({css:h})),e=>{if(!s(e)||!u.test(e.getName()))return;const o=n(e);return!o||o.syntaxFlags.has(r.HasNoneKeywords)||l(o)?void 0:(f||i(o)||(f=!0),c(o,!0))}),v=a(g);return{isRec2020:f,matchesOriginal:v===h,modifiedValue:v,hasFallback:d>0,item:p}}),v=[];g.reverse();for(const e of g){if(e.matchesOriginal)break;v.push(e)}v.reverse(),v.forEach(({isRec2020:e,modifiedValue:o,hasFallback:t,item:s})=>{const a=s.parent;if(!a)return;const n=p.get(a)||{conditionalRules:[],propNames:new Set,lastConditionParams:{media:void 0},lastConditionalRule:void 0};p.set(a,n);const r=`(color-gamut: ${e?"rec2020":"p3"})`;if(n.lastConditionParams.media!==r&&(n.lastConditionalRule=void 0),!t){const e=s.cloneBefore({value:o});m.add(e)}if(n.lastConditionalRule){const e=s.clone();return n.lastConditionalRule.append(e),m.add(e),void s.remove()}const l=h.atRule({name:"media",params:r,source:a.source,raws:{before:"\n\n",after:"\n"}}),i=a.clone();i.removeAll(),i.raws.before="\n";const c=s.clone();i.append(c),s.remove(),m.add(c),n.lastConditionParams.media=l.params,n.lastConditionalRule=i,l.append(i),n.conditionalRules.push(l)})}),f.walk(e=>{const o=p.get(e);o&&0!==o.conditionalRules.length&&o.conditionalRules.reverse().forEach(o=>{e.after(o)})})}}}});creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{tokenize as e}from"@csstools/css-tokenizer";import{replaceComponentValues as t,parseCommaSeparatedListOfComponentValues as o,isFunctionNode as s,stringify as a}from"@csstools/css-parser-algorithms";import{color as r,SyntaxFlag as n,colorDataFitsRGB_Gamut as l,colorDataFitsDisplayP3_Gamut as i,serializeRGB as c}from"@csstools/css-color-parser";const p=/\bcolor-gamut\b/i;function hasConditionalAncestor(e){let t=e.parent;for(;t;)if("atrule"===t.type){if("media"===t.name.toLowerCase()&&p.test(t.params))return!0;t=t.parent}else t=t.parent;return!1}function sameProperty(e){const t=e.prop.toLowerCase(),o=[],s=e.parent?.nodes??[];for(let e=0;e({postcssPlugin:"postcss-gamut-mapping",prepare(){const p=new WeakMap,f=new WeakSet;return{postcssPlugin:"postcss-gamut-mapping",OnceExit(h,{postcss:g}){h.walkDecls(h=>{if(f.has(h))return;if(!u.test(h.value))return;if(!h.parent||hasConditionalAncestor(h))return;if(inKeyframes(h)||"atrule"===h.parent.type&&d.test(h.parent.name))return;const v=sameProperty(h).map((p,u)=>{f.add(p);let d=!1;const h=p.value,g=t(o(e({css:h})),e=>{if(!s(e)||!m.test(e.getName()))return;const t=r(e);return!t||t.syntaxFlags.has(n.HasNoneKeywords)||l(t)?void 0:(d||i(t)||(d=!0),c(t,!0))}),v=a(g);return{isRec2020:d,matchesOriginal:v===h,modifiedValue:v,hasFallback:u>0,item:p}}),k=[];v.reverse();for(const e of v){if(e.matchesOriginal)break;k.push(e)}k.reverse(),k.forEach(({isRec2020:e,modifiedValue:t,hasFallback:o,item:s})=>{const a=s.parent;if(!a)return;const r=p.get(a)||{conditionalRules:[],propNames:new Set,lastConditionParams:void 0,lastConditionalRule:void 0};p.set(a,r);const n=`(color-gamut: ${e?"rec2020":"p3"})`;if(r.lastConditionParams!==n&&(r.lastConditionalRule=void 0),!o){const e=s.cloneBefore({value:t});f.add(e)}if(r.lastConditionalRule){const e=s.clone();return r.lastConditionalRule.append(e),f.add(e),void s.remove()}const l=g.atRule({name:"media",params:n,source:a.source,raws:{before:"\n\n",after:"\n"}}),i=a.clone();i.removeAll(),i.raws.before="\n";const c=s.clone();i.append(c),s.remove(),f.add(c),r.lastConditionParams=l.params,r.lastConditionalRule=i,l.append(i),r.conditionalRules.push(l)})}),h.walk(e=>{const t=p.get(e);t&&0!==t.conditionalRules.length&&t.conditionalRules.reverse().forEach(t=>{e.after(t)})})}}}});creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-gamut-mapping/src/index.ts b/plugins/postcss-gamut-mapping/src/index.ts index efcac333c6..217a67d003 100644 --- a/plugins/postcss-gamut-mapping/src/index.ts +++ b/plugins/postcss-gamut-mapping/src/index.ts @@ -1,4 +1,4 @@ -import type { AtRule, Container, Declaration, Node, Plugin, PluginCreator } from 'postcss'; +import type { AtRule, Container, Declaration, Document, Node, Plugin, PluginCreator } from 'postcss'; import { hasConditionalAncestor } from './has-conditional-ancestor'; import { tokenize } from '@csstools/css-tokenizer'; import { isFunctionNode, parseCommaSeparatedListOfComponentValues, replaceComponentValues, stringify } from '@csstools/css-parser-algorithms'; @@ -10,13 +10,13 @@ export type pluginOptions = never; const HAS_WIDE_GAMUT_COLOR_FUNCTION_REGEX = /\b(?:color|lab|lch|oklab|oklch)\(/i; const HAS_WIDE_GAMUT_COLOR_NAME_REGEX = /^(?:color|lab|lch|oklab|oklch)$/i; +const IS_PROPERTY_REGEX = /^property$/i; +const IS_KEYFRAMES_REGEX = /^keyframes$/i; type State = { conditionalRules: Array, propNames: Set, - lastConditionParams: { - media: string | undefined, - }, + lastConditionParams: string | undefined, lastConditionalRule: Container | undefined, }; @@ -28,6 +28,17 @@ type Modification = { item: Declaration, }; +function inKeyframes(decl: Declaration): AtRule | void { + let parent: typeof decl.parent | Document = decl.parent; + while (parent) { + if (parent.type === 'atrule' && IS_KEYFRAMES_REGEX.test(parent.name)) { + return parent; + } + + parent = parent.parent; + } +} + const creator: PluginCreator = () => { return { @@ -52,6 +63,10 @@ const creator: PluginCreator = () => { return; } + if (inKeyframes(decl) || decl.parent.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + const declList = sameProperty(decl); const maybeModified: Array = declList.map((item, index) => { @@ -124,9 +139,7 @@ const creator: PluginCreator = () => { const state = states.get(parent) || { conditionalRules: [], propNames: new Set(), - lastConditionParams: { - media: undefined, - }, + lastConditionParams: undefined, lastConditionalRule: undefined, }; @@ -134,7 +147,7 @@ const creator: PluginCreator = () => { const condition = `(color-gamut: ${isRec2020 ? 'rec2020' : 'p3'})`; - if (state.lastConditionParams.media !== condition) { + if (state.lastConditionParams !== condition) { state.lastConditionalRule = undefined; } @@ -178,7 +191,7 @@ const creator: PluginCreator = () => { visited.add(clone); - state.lastConditionParams.media = atRule.params; + state.lastConditionParams = atRule.params; state.lastConditionalRule = parentClone; atRule.append(parentClone); diff --git a/plugins/postcss-gamut-mapping/test/basic.css b/plugins/postcss-gamut-mapping/test/basic.css index 75b4c30589..508e523c8b 100644 --- a/plugins/postcss-gamut-mapping/test/basic.css +++ b/plugins/postcss-gamut-mapping/test/basic.css @@ -144,3 +144,14 @@ background: linear-gradient(to right, rgb(180, 6, 95) 0%, color(display-p3 0.66274 0.13281 0.2732), rgb(187, 5, 34), color(display-p3 0.66744 0.1674 -0.0377), color(display-p3 0.65449 0.20282 -0.1531), color(display-p3 0.63125 0.24386 -0.1941), color(display-p3 0.59786 0.28667 -0.2143), color(display-p3 0.55449 0.32865 -0.2232), color(display-p3 0.50119 0.3681 -0.2238), color(display-p3 0.43745 0.40384 -0.2152), color(display-p3 0.36142 0.435 -0.1928) 100%); background: linear-gradient(to right in oklch, oklch(50% 50% 0deg) 0%, oklch(50% 50% 120deg) 100%) } + +@property --foo { + inherits: false; + initial-value: color(srgb 0.99 1.0001 0.99); +} + +@keyframes --foo { + to { + --foo: color(srgb 0.99 1.0001 0.99); + } +} diff --git a/plugins/postcss-gamut-mapping/test/basic.expect.css b/plugins/postcss-gamut-mapping/test/basic.expect.css index 803d406189..64f202549e 100644 --- a/plugins/postcss-gamut-mapping/test/basic.expect.css +++ b/plugins/postcss-gamut-mapping/test/basic.expect.css @@ -215,3 +215,14 @@ background: linear-gradient(to right in oklch, oklch(50% 50% 0deg) 0%, oklch(50% 50% 120deg) 100%) } } + +@property --foo { + inherits: false; + initial-value: color(srgb 0.99 1.0001 0.99); +} + +@keyframes --foo { + to { + --foo: color(srgb 0.99 1.0001 0.99); + } +} diff --git a/plugins/postcss-gradients-interpolation-method/test/basic.css b/plugins/postcss-gradients-interpolation-method/test/basic.css index 8449e1e9d4..1b7f20bb99 100644 --- a/plugins/postcss-gradients-interpolation-method/test/basic.css +++ b/plugins/postcss-gradients-interpolation-method/test/basic.css @@ -318,3 +318,14 @@ to-clone { .experimental-features-from-the-color-parser { background-image: linear-gradient(in oklab 90deg, contrast-color(pink) 25% 50%, blue 70% 75%); } + +@property --foo { + inherits: false; + initial-value: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); +} + +@keyframes --foo { + to { + --foo: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); + } +} diff --git a/plugins/postcss-gradients-interpolation-method/test/basic.expect.css b/plugins/postcss-gradients-interpolation-method/test/basic.expect.css index 8177c487ba..8e008736c2 100644 --- a/plugins/postcss-gradients-interpolation-method/test/basic.expect.css +++ b/plugins/postcss-gradients-interpolation-method/test/basic.expect.css @@ -411,3 +411,39 @@ to-clone { .experimental-features-from-the-color-parser { background-image: linear-gradient(in oklab 90deg, contrast-color(pink) 25% 50%, blue 70% 75%); } + +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} +} + +@supports (background: conic-gradient(in oklch, red 0deg, red 0deg 1deg, red 2deg)) and (color: rgb(0 0 0 / 0)) { +@property --foo { + inherits: false; + initial-value: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); +} +} + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + } +} + +@supports (background: conic-gradient(in oklch, red 0deg, red 0deg 1deg, red 2deg)) and (color: color(display-p3 0 0 0%)) and (color: rgb(0 0 0 / 0)) { + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + --foo: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); + } +} +} diff --git a/plugins/postcss-gradients-interpolation-method/test/basic.preserve-false.expect.css b/plugins/postcss-gradients-interpolation-method/test/basic.preserve-false.expect.css index 58409fd3aa..98d0ef0ddd 100644 --- a/plugins/postcss-gradients-interpolation-method/test/basic.preserve-false.expect.css +++ b/plugins/postcss-gradients-interpolation-method/test/basic.preserve-false.expect.css @@ -332,3 +332,31 @@ to-clone { .experimental-features-from-the-color-parser { background-image: linear-gradient(in oklab 90deg, contrast-color(pink) 25% 50%, blue 70% 75%); } + +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} +} + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + } +} +} diff --git a/plugins/postcss-gradients-interpolation-method/test/basic.with-cloned-rules.expect.css b/plugins/postcss-gradients-interpolation-method/test/basic.with-cloned-rules.expect.css index 00dfba1c03..a347b80390 100644 --- a/plugins/postcss-gradients-interpolation-method/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-gradients-interpolation-method/test/basic.with-cloned-rules.expect.css @@ -416,3 +416,39 @@ to-clone { .experimental-features-from-the-color-parser { background-image: linear-gradient(in oklab 90deg, contrast-color(pink) 25% 50%, blue 70% 75%); } + +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); +} +} + +@supports (background: conic-gradient(in oklch, red 0deg, red 0deg 1deg, red 2deg)) and (color: rgb(0 0 0 / 0)) { +@property --foo { + inherits: false; + initial-value: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); +} +} + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + } +} + +@supports (background: conic-gradient(in oklch, red 0deg, red 0deg 1deg, red 2deg)) and (color: color(display-p3 0 0 0%)) and (color: rgb(0 0 0 / 0)) { + +@keyframes --foo { + to { + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), rgb(157, 179, 255), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + --foo: conic-gradient(rgb(255, 150, 150) 0deg, rgb(246, 162, 100), rgb(213, 182, 78), rgb(160, 200, 109), rgb(93, 210, 163), rgb(41, 208, 217), rgb(93, 196, 254), color(display-p3 0.63036 0.6977 1.01537), rgb(207, 162, 246), rgb(241, 150, 204), rgb(255, 150, 150) 360deg); + --foo: conic-gradient(in oklch longer hue, rgb(255 150 150) 0deg, rgb(255 150 150) 360deg); + } +} +} diff --git a/plugins/postcss-hwb-function/test/basic.css b/plugins/postcss-hwb-function/test/basic.css index 2431851b72..664ebfe89b 100644 --- a/plugins/postcss-hwb-function/test/basic.css +++ b/plugins/postcss-hwb-function/test/basic.css @@ -22,3 +22,14 @@ to-clone { .test-css-color-5-interop { color-1: hwb(from hwb(50deg 20% 30%) h w b); } + +@property --foo { + inherits: false; + initial-value: hwb(50deg 20% 30%); +} + +@keyframes --foo { + to { + --foo: hwb(50deg 20% 30%); + } +} diff --git a/plugins/postcss-hwb-function/test/basic.expect.css b/plugins/postcss-hwb-function/test/basic.expect.css index 14ee65c9c7..07e1be550c 100644 --- a/plugins/postcss-hwb-function/test/basic.expect.css +++ b/plugins/postcss-hwb-function/test/basic.expect.css @@ -22,3 +22,14 @@ to-clone { .test-css-color-5-interop { color-1: hwb(from rgb(179, 157, 51) h w b); } + +@property --foo { + inherits: false; + initial-value: rgb(179, 157, 51); +} + +@keyframes --foo { + to { + --foo: rgb(179, 157, 51); + } +} diff --git a/plugins/postcss-hwb-function/test/basic.preserve-true.expect.css b/plugins/postcss-hwb-function/test/basic.preserve-true.expect.css index 00d85895b9..5d1e071991 100644 --- a/plugins/postcss-hwb-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-hwb-function/test/basic.preserve-true.expect.css @@ -38,3 +38,31 @@ to-clone { color-1: hwb(from rgb(179, 157, 51) h w b); color-1: hwb(from hwb(50deg 20% 30%) h w b); } + +@property --foo { + inherits: false; + initial-value: rgb(179, 157, 51); +} + +@supports (color: hwb(0 0% 0%)) { +@property --foo { + inherits: false; + initial-value: hwb(50deg 20% 30%); +} +} + +@keyframes --foo { + to { + --foo: rgb(179, 157, 51); + } +} + +@supports (color: hwb(0 0% 0%)) { + +@keyframes --foo { + to { + --foo: rgb(179, 157, 51); + --foo: hwb(50deg 20% 30%); + } +} +} diff --git a/plugins/postcss-hwb-function/test/basic.with-cloned-rules.expect.css b/plugins/postcss-hwb-function/test/basic.with-cloned-rules.expect.css index 6ee37ed766..42737f5ecb 100644 --- a/plugins/postcss-hwb-function/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-hwb-function/test/basic.with-cloned-rules.expect.css @@ -43,3 +43,31 @@ to-clone { color-1: hwb(from rgb(179, 157, 51) h w b); color-1: hwb(from hwb(50deg 20% 30%) h w b); } + +@property --foo { + inherits: false; + initial-value: rgb(179, 157, 51); +} + +@supports (color: hwb(0 0% 0%)) { +@property --foo { + inherits: false; + initial-value: hwb(50deg 20% 30%); +} +} + +@keyframes --foo { + to { + --foo: rgb(179, 157, 51); + } +} + +@supports (color: hwb(0 0% 0%)) { + +@keyframes --foo { + to { + --foo: rgb(179, 157, 51); + --foo: hwb(50deg 20% 30%); + } +} +} diff --git a/plugins/postcss-ic-unit/test/basic.css b/plugins/postcss-ic-unit/test/basic.css index 9e881cdb78..e2fb4191d7 100644 --- a/plugins/postcss-ic-unit/test/basic.css +++ b/plugins/postcss-ic-unit/test/basic.css @@ -12,3 +12,14 @@ to-clone { text-indent: 2ic; } + +@property --foo { + inherits: false; + initial-value: 2ic; +} + +@keyframes --foo { + to { + --foo: 2ic; + } +} diff --git a/plugins/postcss-ic-unit/test/basic.expect.css b/plugins/postcss-ic-unit/test/basic.expect.css index 8233880d1c..1ecd56cd6d 100644 --- a/plugins/postcss-ic-unit/test/basic.expect.css +++ b/plugins/postcss-ic-unit/test/basic.expect.css @@ -12,3 +12,14 @@ to-clone { text-indent: 2em; } + +@property --foo { + inherits: false; + initial-value: 2em; +} + +@keyframes --foo { + to { + --foo: 2em; + } +} diff --git a/plugins/postcss-ic-unit/test/basic.preserve-true.expect.css b/plugins/postcss-ic-unit/test/basic.preserve-true.expect.css index 38befee2dd..9b70f649e6 100644 --- a/plugins/postcss-ic-unit/test/basic.preserve-true.expect.css +++ b/plugins/postcss-ic-unit/test/basic.preserve-true.expect.css @@ -22,3 +22,31 @@ to-clone { text-indent: 2em; text-indent: 2ic; } + +@property --foo { + inherits: false; + initial-value: 2em; +} + +@supports (font-size: 1ic) { +@property --foo { + inherits: false; + initial-value: 2ic; +} +} + +@keyframes --foo { + to { + --foo: 2em; + } +} + +@supports (font-size: 1ic) { + +@keyframes --foo { + to { + --foo: 2em; + --foo: 2ic; + } +} +} diff --git a/plugins/postcss-ic-unit/test/basic.with-cloned-rules.expect.css b/plugins/postcss-ic-unit/test/basic.with-cloned-rules.expect.css index 79a43c4250..ffad22ed2d 100644 --- a/plugins/postcss-ic-unit/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-ic-unit/test/basic.with-cloned-rules.expect.css @@ -27,3 +27,31 @@ to-clone { text-indent: 2em; text-indent: 2ic; } + +@property --foo { + inherits: false; + initial-value: 2em; +} + +@supports (font-size: 1ic) { +@property --foo { + inherits: false; + initial-value: 2ic; +} +} + +@keyframes --foo { + to { + --foo: 2em; + } +} + +@supports (font-size: 1ic) { + +@keyframes --foo { + to { + --foo: 2em; + --foo: 2ic; + } +} +} diff --git a/plugins/postcss-image-function/test/basic.css b/plugins/postcss-image-function/test/basic.css index 354e37f09c..0695b49bfa 100644 --- a/plugins/postcss-image-function/test/basic.css +++ b/plugins/postcss-image-function/test/basic.css @@ -23,3 +23,14 @@ background-image: image(rgba(0, 0, 255, .5)), image(rgba(255, 0, 255, .5)), url("bg-image.png"); } } + +@property --foo { + inherits: false; + initial-value: image(red); +} + +@keyframes --foo { + to { + --foo: image(red); + } +} diff --git a/plugins/postcss-image-function/test/basic.expect.css b/plugins/postcss-image-function/test/basic.expect.css index 9ac7cfbee4..7fd99e1172 100644 --- a/plugins/postcss-image-function/test/basic.expect.css +++ b/plugins/postcss-image-function/test/basic.expect.css @@ -23,3 +23,14 @@ background-image: image(rgba(0, 0, 255, .5)), image(rgba(255, 0, 255, .5)), url("bg-image.png"); } } + +@property --foo { + inherits: false; + initial-value: linear-gradient(red,red); +} + +@keyframes --foo { + to { + --foo: linear-gradient(red,red); + } +} diff --git a/plugins/postcss-image-function/test/basic.preserve-true.expect.css b/plugins/postcss-image-function/test/basic.preserve-true.expect.css index fab696bb2f..918f25ee41 100644 --- a/plugins/postcss-image-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-image-function/test/basic.preserve-true.expect.css @@ -31,3 +31,31 @@ background-image: image(rgba(0, 0, 255, .5)), image(rgba(255, 0, 255, .5)), url("bg-image.png"); } } + +@property --foo { + inherits: false; + initial-value: linear-gradient(red,red); +} + +@supports (background-image: image(red)) { +@property --foo { + inherits: false; + initial-value: image(red); +} +} + +@keyframes --foo { + to { + --foo: linear-gradient(red,red); + } +} + +@supports (background-image: image(red)) { + +@keyframes --foo { + to { + --foo: linear-gradient(red,red); + --foo: image(red); + } +} +} diff --git a/plugins/postcss-image-set-function/CHANGELOG.md b/plugins/postcss-image-set-function/CHANGELOG.md index dde234c4c4..299ccff5d1 100644 --- a/plugins/postcss-image-set-function/CHANGELOG.md +++ b/plugins/postcss-image-set-function/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes to PostCSS image-set() Function +### Unreleased (patch) + +- Ignore `initial-value` in `@property` +- Ignore `image-set()` in `@keyframes` + ### 8.0.0 _January 14, 2026_ diff --git a/plugins/postcss-image-set-function/dist/index.mjs b/plugins/postcss-image-set-function/dist/index.mjs index 2037754c40..e57eb18e8b 100644 --- a/plugins/postcss-image-set-function/dist/index.mjs +++ b/plugins/postcss-image-set-function/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";import{hasFallback as t}from"@csstools/utilities";function isComma(e){return!!e&&"div"===e.type&&","===e.value}const n=/^(?:cross-fade|image|(?:repeating-)?(?:conic|linear|radial)-gradient|url|var)$/i;function getImage(t){return!(!t||!t.type)&&("string"===t.type?"url("+e.stringify(t)+")":!("function"!==t.type||!n.test(t.value))&&e.stringify(t))}const i=new Map([["dpcm",2.54],["dpi",1],["dppx",96],["x",96]]);function getMedia(e,t,n){if("boolean"==typeof e)return!1;const i=Math.floor(e/96*100)/100;return t.atRule({name:"media",params:`(-webkit-min-device-pixel-ratio: ${i}), (min-resolution: ${e}dpi)`,source:n.source})}function getMediaDPI(t){if(!t)return!1;if("word"!==t.type)return!1;if(!isNumericNode(t))return!1;const n=e.unit(t.value);if(!n)return!1;const r=i.get(n.unit.toLowerCase());return!!r&&Number(n.number)*r}function isNumericNode(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch{return!1}}const handleInvalidation=(e,t,n)=>{if("warn"===e.oninvalid)e.decl.warn(e.result,t,{word:String(n)});else if("throw"===e.oninvalid)throw e.decl.error(t,{word:String(n)})},processImageSet=(t,n,i)=>{const r=n.parent;if(!r)return;const o=new Map,s=n.value;for(let r=0;re-t),u=a.map(e=>o.get(e)?.atRule).filter(e=>!!e);if(!u.length)return;const l=o.get(a[0])?.value;if(!l)return;const c=u.slice(1);c.length&&r.after(c),n.cloneBefore({value:l.trim()}),i.preserve||(n.remove(),r.nodes?.length||r.remove())},r=/(?:^|[^\w-])(?:-webkit-)?image-set\(/i,o=/^(?:-webkit-)?image-set$/i,creator=n=>{const i=!("preserve"in Object(n))||Boolean(n?.preserve),s="onInvalid"in Object(n)?n?.onInvalid:"ignore";if("oninvalid"in Object(n))throw new Error('"oninvalid" was changed to "onInvalid" to match other plugins with similar options');return{postcssPlugin:"postcss-image-set-function",Declaration(n,{result:a,postcss:u}){const l=n.value;if(!r.test(l))return;if(t(n))return;let c;try{c=e(l)}catch{n.warn(a,`Failed to parse value '${l}' as an image-set function. Leaving the original value intact.`)}if(void 0===c)return;const f=[];c.walk(t=>{if("function"!==t.type)return;if(!o.test(t.value))return;let i=!1;if(e.walk(t.nodes,e=>{"function"===e.type&&o.test(e.value)&&(i=!0)}),i)return handleInvalidation({decl:n,oninvalid:s,result:a},"nested image-set functions are not allowed",e.stringify(t)),!1;const r=t.nodes.filter(e=>"comment"!==e.type&&"space"!==e.type);f.push({imageSetFunction:t,imageSetOptionNodes:r})}),processImageSet(f,n,{decl:n,oninvalid:s,preserve:i,result:a,postcss:u})}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import e from"postcss-value-parser";import{hasFallback as t}from"@csstools/utilities";function isComma(e){return!!e&&"div"===e.type&&","===e.value}const n=/^(?:cross-fade|image|(?:repeating-)?(?:conic|linear|radial)-gradient|url|var)$/i;function getImage(t){return!(!t||!t.type)&&("string"===t.type?"url("+e.stringify(t)+")":!("function"!==t.type||!n.test(t.value))&&e.stringify(t))}const r=new Map([["dpcm",2.54],["dpi",1],["dppx",96],["x",96]]);function getMedia(e,t,n){if("boolean"==typeof e)return!1;const r=Math.floor(e/96*100)/100;return t.atRule({name:"media",params:`(-webkit-min-device-pixel-ratio: ${r}), (min-resolution: ${e}dpi)`,source:n.source})}function getMediaDPI(t){if(!t)return!1;if("word"!==t.type)return!1;if(!isNumericNode(t))return!1;const n=e.unit(t.value);if(!n)return!1;const i=r.get(n.unit.toLowerCase());return!!i&&Number(n.number)*i}function isNumericNode(t){if(!t||!t.value)return!1;try{return!1!==e.unit(t.value)}catch{return!1}}const handleInvalidation=(e,t,n)=>{if("warn"===e.oninvalid)e.decl.warn(e.result,t,{word:String(n)});else if("throw"===e.oninvalid)throw e.decl.error(t,{word:String(n)})},processImageSet=(t,n,r)=>{const i=n.parent;if(!i)return;const o=new Map,a=n.value;for(let i=0;ie-t),u=s.map(e=>o.get(e)?.atRule).filter(e=>!!e);if(!u.length)return;const l=o.get(s[0])?.value;if(!l)return;const c=u.slice(1);c.length&&i.after(c),n.cloneBefore({value:l.trim()}),r.preserve||(n.remove(),i.nodes?.length||i.remove())},i=/(?:^|[^\w-])(?:-webkit-)?image-set\(/i,o=/^(?:-webkit-)?image-set$/i,a=/^property$/i,s=/^keyframes$/i;function inKeyframes(e){let t=e.parent;for(;t;){if("atrule"===t.type&&s.test(t.name))return t;t=t.parent}}const creator=n=>{const r=!("preserve"in Object(n))||Boolean(n?.preserve),s="onInvalid"in Object(n)?n?.onInvalid:"ignore";if("oninvalid"in Object(n))throw new Error('"oninvalid" was changed to "onInvalid" to match other plugins with similar options');return{postcssPlugin:"postcss-image-set-function",Declaration(n,{result:u,postcss:l}){const c=n.value;if(!i.test(c))return;if(t(n))return;if(inKeyframes(n))return;if("atrule"===n.parent?.type&&a.test(n.parent.name))return;let f;try{f=e(c)}catch{n.warn(u,`Failed to parse value '${c}' as an image-set function. Leaving the original value intact.`)}if(void 0===f)return;const p=[];f.walk(t=>{if("function"!==t.type)return;if(!o.test(t.value))return;let r=!1;if(e.walk(t.nodes,e=>{"function"===e.type&&o.test(e.value)&&(r=!0)}),r)return handleInvalidation({decl:n,oninvalid:s,result:u},"nested image-set functions are not allowed",e.stringify(t)),!1;const i=t.nodes.filter(e=>"comment"!==e.type&&"space"!==e.type);p.push({imageSetFunction:t,imageSetOptionNodes:i})}),processImageSet(p,n,{decl:n,oninvalid:s,preserve:r,result:u,postcss:l})}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-image-set-function/src/index.ts b/plugins/postcss-image-set-function/src/index.ts index 691478216c..3b7387455f 100644 --- a/plugins/postcss-image-set-function/src/index.ts +++ b/plugins/postcss-image-set-function/src/index.ts @@ -1,11 +1,13 @@ import valueParser from 'postcss-value-parser'; import { processImageSet } from './lib/process-image-set'; -import type { PluginCreator } from 'postcss'; +import type { AtRule, Declaration, Document, PluginCreator } from 'postcss'; import { handleInvalidation } from './lib/handle-invalidation'; import { hasFallback } from '@csstools/utilities'; const IMAGE_SET_VALUE_MATCH_REGEX = /(?:^|[^\w-])(?:-webkit-)?image-set\(/i; const IMAGE_SET_FUNCTION_MATCH_REGEX = /^(?:-webkit-)?image-set$/i; +const IS_PROPERTY_REGEX = /^property$/i; +const IS_KEYFRAMES_REGEX = /^keyframes$/i; /** postcss-image-set-function plugin options */ export type pluginOptions = { @@ -20,6 +22,17 @@ export type pluginOptions = { onInvalid?: 'warn' | 'throw' | 'ignore' | false }; +function inKeyframes(decl: Declaration): AtRule | void { + let parent: typeof decl.parent | Document = decl.parent; + while (parent) { + if (parent.type === 'atrule' && IS_KEYFRAMES_REGEX.test(parent.name)) { + return parent; + } + + parent = parent.parent; + } +} + const creator: PluginCreator = (opts?: pluginOptions) => { // prepare options const preserve = 'preserve' in Object(opts) ? Boolean(opts?.preserve) : true; @@ -43,6 +56,14 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (inKeyframes(decl)) { + return; + } + + if (decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + let valueAST; try { diff --git a/plugins/postcss-image-set-function/test/basic.css b/plugins/postcss-image-set-function/test/basic.css index f43bbc5e4e..bd23639d1e 100644 --- a/plugins/postcss-image-set-function/test/basic.css +++ b/plugins/postcss-image-set-function/test/basic.css @@ -115,3 +115,14 @@ to-clone { url(img/test-2x.png) 2x ); } + +@property --foo { + inherits: false; + initial-value: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); +} + +@keyframes --foo { + to { + --foo: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); + } +} diff --git a/plugins/postcss-image-set-function/test/basic.expect.css b/plugins/postcss-image-set-function/test/basic.expect.css index 92f21be62f..4a2083d8c8 100644 --- a/plugins/postcss-image-set-function/test/basic.expect.css +++ b/plugins/postcss-image-set-function/test/basic.expect.css @@ -293,3 +293,14 @@ to-clone { background:url(img/test-2x.png); } } + +@property --foo { + inherits: false; + initial-value: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); +} + +@keyframes --foo { + to { + --foo: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); + } +} diff --git a/plugins/postcss-image-set-function/test/basic.no-preserve.expect.css b/plugins/postcss-image-set-function/test/basic.no-preserve.expect.css index 3e9032aa62..4c1e42caa8 100644 --- a/plugins/postcss-image-set-function/test/basic.no-preserve.expect.css +++ b/plugins/postcss-image-set-function/test/basic.no-preserve.expect.css @@ -224,3 +224,14 @@ to-clone { background:url(img/test-2x.png); } } + +@property --foo { + inherits: false; + initial-value: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); +} + +@keyframes --foo { + to { + --foo: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); + } +} diff --git a/plugins/postcss-image-set-function/test/basic.with-cloned-rules.expect.css b/plugins/postcss-image-set-function/test/basic.with-cloned-rules.expect.css index a2e4d820de..5651b13e89 100644 --- a/plugins/postcss-image-set-function/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-image-set-function/test/basic.with-cloned-rules.expect.css @@ -305,3 +305,14 @@ to-clone { background:url(img/test-2x.png); } } + +@property --foo { + inherits: false; + initial-value: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); +} + +@keyframes --foo { + to { + --foo: image-set(url(img-a.png) 1x, url(img-a@2x.png) 2x); + } +} diff --git a/plugins/postcss-initial/test/basic.css b/plugins/postcss-initial/test/basic.css index b515db2ae6..f640f3a370 100644 --- a/plugins/postcss-initial/test/basic.css +++ b/plugins/postcss-initial/test/basic.css @@ -24,3 +24,14 @@ .pointer-events { pointer-events: initial; } + +@property --foo { + inherits: false; + initial-value: initial; +} + +@keyframes --foo { + to { + --foo: initial; + } +} diff --git a/plugins/postcss-initial/test/basic.expect.css b/plugins/postcss-initial/test/basic.expect.css index 620538bf86..90394e44df 100644 --- a/plugins/postcss-initial/test/basic.expect.css +++ b/plugins/postcss-initial/test/basic.expect.css @@ -31,3 +31,14 @@ .pointer-events { pointer-events: initial; } + +@property --foo { + inherits: false; + initial-value: initial; +} + +@keyframes --foo { + to { + --foo: initial; + } +} diff --git a/plugins/postcss-initial/test/basic.preserve-false.expect.css b/plugins/postcss-initial/test/basic.preserve-false.expect.css index c1aaa4692e..1e9052f332 100644 --- a/plugins/postcss-initial/test/basic.preserve-false.expect.css +++ b/plugins/postcss-initial/test/basic.preserve-false.expect.css @@ -24,3 +24,14 @@ .pointer-events { pointer-events: initial; } + +@property --foo { + inherits: false; + initial-value: initial; +} + +@keyframes --foo { + to { + --foo: initial; + } +} diff --git a/plugins/postcss-lab-function/test/basic.css b/plugins/postcss-lab-function/test/basic.css index 53a1920997..0cb41423b9 100644 --- a/plugins/postcss-lab-function/test/basic.css +++ b/plugins/postcss-lab-function/test/basic.css @@ -197,3 +197,14 @@ to-clone { color-1: lab(from lab(40% 56.6 39) l a b); color-2: lch(from lch(40% 56.6 39) l c h); } + +@property --foo { + inherits: false; + initial-value: lch(60% 50 180); +} + +@keyframes --foo { + to { + --foo: lch(60% 50 180); + } +} diff --git a/plugins/postcss-lab-function/test/basic.display-p3-false.expect.css b/plugins/postcss-lab-function/test/basic.display-p3-false.expect.css index cc6bbf10f4..2c01d5e41a 100644 --- a/plugins/postcss-lab-function/test/basic.display-p3-false.expect.css +++ b/plugins/postcss-lab-function/test/basic.display-p3-false.expect.css @@ -197,3 +197,14 @@ to-clone { color-1: lab(from rgb(179, 35, 35) l a b); color-2: lch(from rgb(163, 57, 39) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 163, 142); +} + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + } +} diff --git a/plugins/postcss-lab-function/test/basic.display-p3-false.preserve-true.expect.css b/plugins/postcss-lab-function/test/basic.display-p3-false.preserve-true.expect.css index 4e46e85f37..ed0b82b367 100644 --- a/plugins/postcss-lab-function/test/basic.display-p3-false.preserve-true.expect.css +++ b/plugins/postcss-lab-function/test/basic.display-p3-false.preserve-true.expect.css @@ -298,3 +298,31 @@ to-clone { color-2: lch(from rgb(163, 57, 39) l c h); color-2: lch(from lch(40% 56.6 39) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 163, 142); +} + +@supports (color: lab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: lch(60% 50 180); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + } +} + +@supports (color: lab(0% 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + --foo: lch(60% 50 180); + } +} +} diff --git a/plugins/postcss-lab-function/test/basic.expect.css b/plugins/postcss-lab-function/test/basic.expect.css index ca9a507e73..11c1096ddc 100644 --- a/plugins/postcss-lab-function/test/basic.expect.css +++ b/plugins/postcss-lab-function/test/basic.expect.css @@ -229,3 +229,31 @@ to-clone { color-1: lab(from rgb(179, 35, 35) l a b); color-2: lch(from rgb(163, 57, 39) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 163, 142); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.17545 0.64269 0.56213); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + --foo: color(display-p3 0.17545 0.64269 0.56213); + } +} +} diff --git a/plugins/postcss-lab-function/test/basic.preserve-true.expect.css b/plugins/postcss-lab-function/test/basic.preserve-true.expect.css index 1a391aac75..422a53f9e0 100644 --- a/plugins/postcss-lab-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-lab-function/test/basic.preserve-true.expect.css @@ -330,3 +330,39 @@ to-clone { color-2: lch(from rgb(163, 57, 39) l c h); color-2: lch(from lch(40% 56.6 39) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 163, 142); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.17545 0.64269 0.56213); +} +} + +@supports (color: lab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: lch(60% 50 180); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: lab(0% 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + --foo: color(display-p3 0.17545 0.64269 0.56213); + --foo: lch(60% 50 180); + } +} +} diff --git a/plugins/postcss-lab-function/test/basic.with-cloned-rules.expect.css b/plugins/postcss-lab-function/test/basic.with-cloned-rules.expect.css index c998e46c44..af23ca2bee 100644 --- a/plugins/postcss-lab-function/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-lab-function/test/basic.with-cloned-rules.expect.css @@ -335,3 +335,39 @@ to-clone { color-2: lch(from rgb(163, 57, 39) l c h); color-2: lch(from lch(40% 56.6 39) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 163, 142); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.17545 0.64269 0.56213); +} +} + +@supports (color: lab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: lch(60% 50 180); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: lab(0% 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 163, 142); + --foo: color(display-p3 0.17545 0.64269 0.56213); + --foo: lch(60% 50 180); + } +} +} diff --git a/plugins/postcss-light-dark-function/CHANGELOG.md b/plugins/postcss-light-dark-function/CHANGELOG.md index c4f49bb3b2..bc6982e076 100644 --- a/plugins/postcss-light-dark-function/CHANGELOG.md +++ b/plugins/postcss-light-dark-function/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes to PostCSS Light Dark Function +### Unreleased (patch) + +- Ignore `initial-value` in `@property` +- Ignore `light-dark()` in `@keyframes` + ### 3.0.3 _August 15, 2026_ diff --git a/plugins/postcss-light-dark-function/dist/index.mjs b/plugins/postcss-light-dark-function/dist/index.mjs index 1445dfd072..84c80d1178 100644 --- a/plugins/postcss-light-dark-function/dist/index.mjs +++ b/plugins/postcss-light-dark-function/dist/index.mjs @@ -1 +1 @@ -import e from"@csstools/postcss-progressive-custom-properties";import{tokenize as r,isTokenIdent as t,isTokenComma as o,TokenType as s}from"@csstools/css-tokenizer";import{hasFallback as n,hasSupportsAtRuleAncestor as a}from"@csstools/utilities";import{isFunctionNode as i,isWhitespaceNode as c,isCommentNode as u,walk as l,isTokenNode as p,replaceComponentValues as f,parseCommaSeparatedListOfComponentValues as g,FunctionNode as v,TokenNode as m,WhitespaceNode as d,stringify as h}from"@csstools/css-parser-algorithms";const k="--csstools-color-scheme--light",D="initial";function toggleNameGenerator(e){return`--csstools-light-dark-toggle--${e}`}const L=/dark/i,w=/light/i;function colorSchemes(e){const o=r({css:e});let s=!1,n=!1;return o.forEach(e=>{t(e)&&(w.test(e[4].value)?s=!0:L.test(e[4].value)&&(n=!0))}),[s,n]}const C=/^light-dark$/i;function isComma(e){return p(e)&&o(e.value)}function parseLightDark(e){if(!i(e)||!C.test(e.getName()))return!1;const r=e.value.filter(e=>!c(e)&&!u(e));if(3!==r.length)return!1;let t=r[0];const o=r[1];let s=r[2];if(!t||!o||!s)return!1;if(!isComma(o))return!1;if(isComma(t)||isComma(s))return!1;if(i(t)){const e=[t];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,!0)}),[t]=e}if(i(s)){const e=[s];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,!1)}),[s]=e}return[t,s]}function recurseLightDark(e,r,t,o){if("number"!=typeof t)return;const s=parseLightDark(e);if(!s)return;let n=s[o?0:1];if(i(n)){const e=[n];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,o)}),[n]=e}r.value[t]=n}function transformLightDark(e,t){const o=new Map,n=f(g(r({css:e})),e=>{const r=parseLightDark(e);if(!r)return;const[n,a]=r,i=t();return o.set(i,`var(${k}) ${a.toString()}`),new v([s.Function,"var(",-1,-1,{value:"var"}],[s.CloseParen,")",-1,-1,void 0],[new m([s.Ident,i,-1,-1,{value:i}]),new m([s.Comma,",",-1,-1,void 0]),new d([[s.Whitespace," ",-1,-1,void 0]]),n])});return{value:h(n),toggles:o}}function newNestedRuleWithSupportsNot(e,r,t,o){const s=r({selector:"& *",source:e.source});if(!o)return{inner:s,outer:s};const n=t({name:"supports",params:"not (color: light-dark(tan, tan))",source:e.source});return n.append(s),{inner:s,outer:n}}const P=/^color-scheme$/i,N=/\blight-dark\(/i,basePlugin=e=>({postcssPlugin:"postcss-light-dark-function",prepare(){let r=0;const currentToggleNameGenerator=()=>toggleNameGenerator(r++),t=new Map;return{postcssPlugin:"postcss-light-dark-function",Declaration(r,{atRule:o,rule:s}){const i=r.parent;if(i){if(P.test(r.prop)){if(i.some(e=>"decl"===e.type&&e.prop===k))return;const[e,t]=colorSchemes(r.value);if(e&&t){r.cloneBefore({prop:k,value:D});const e=i.clone();e.removeAll(),e.append(r.clone({prop:k,value:" "}));const t=o({name:"media",params:"(prefers-color-scheme: dark)",source:i.source});return t.append(e),void i.after(t)}return t?void r.cloneBefore({prop:k,value:" "}):e?void r.cloneBefore({prop:k,value:D}):void 0}if(N.test(r.value)){if(n(r))return;if(a(r,N))return;const i=transformLightDark(r.value,currentToggleNameGenerator);if(i.value===r.value)return;for(const[e,t]of i.toggles)r.cloneBefore({prop:e,value:t});if(r.cloneBefore({value:i.value}),r.variable&&r.parent){const n=t.get(r.parent)??newNestedRuleWithSupportsNot(r,s,o,e?.preserve);for(const[e,t]of i.toggles)n.inner.append(r.clone({prop:e,value:t}));n.inner.append(r.clone({value:i.value})),t.has(r.parent)||(r.parent.append(n.outer),t.set(r.parent,n))}e?.preserve||r.remove()}}}}}});basePlugin.postcss=!0;const postcssPlugin=r=>{const t=Object.assign({enableProgressiveCustomProperties:!0,preserve:!0},r);return t.enableProgressiveCustomProperties&&t.preserve?{postcssPlugin:"postcss-light-dark-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default,postcssPlugin as"module.exports"}; +import e from"@csstools/postcss-progressive-custom-properties";import{tokenize as r,isTokenIdent as t,isTokenComma as o,TokenType as s}from"@csstools/css-tokenizer";import{hasFallback as n,hasSupportsAtRuleAncestor as a}from"@csstools/utilities";import{isFunctionNode as i,isWhitespaceNode as c,isCommentNode as u,walk as l,isTokenNode as p,replaceComponentValues as f,parseCommaSeparatedListOfComponentValues as m,FunctionNode as g,TokenNode as v,WhitespaceNode as d,stringify as h}from"@csstools/css-parser-algorithms";const k="--csstools-color-scheme--light",D="initial";function toggleNameGenerator(e){return`--csstools-light-dark-toggle--${e}`}const L=/dark/i,w=/light/i;function colorSchemes(e){const o=r({css:e});let s=!1,n=!1;return o.forEach(e=>{t(e)&&(w.test(e[4].value)?s=!0:L.test(e[4].value)&&(n=!0))}),[s,n]}const y=/^light-dark$/i;function isComma(e){return p(e)&&o(e.value)}function parseLightDark(e){if(!i(e)||!y.test(e.getName()))return!1;const r=e.value.filter(e=>!c(e)&&!u(e));if(3!==r.length)return!1;let t=r[0];const o=r[1];let s=r[2];if(!t||!o||!s)return!1;if(!isComma(o))return!1;if(isComma(t)||isComma(s))return!1;if(i(t)){const e=[t];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,!0)}),[t]=e}if(i(s)){const e=[s];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,!1)}),[s]=e}return[t,s]}function recurseLightDark(e,r,t,o){if("number"!=typeof t)return;const s=parseLightDark(e);if(!s)return;let n=s[o?0:1];if(i(n)){const e=[n];l(e,({node:e,parent:r},t)=>{recurseLightDark(e,r,t,o)}),[n]=e}r.value[t]=n}function transformLightDark(e,t){const o=new Map,n=f(m(r({css:e})),e=>{const r=parseLightDark(e);if(!r)return;const[n,a]=r,i=t();return o.set(i,`var(${k}) ${a.toString()}`),new g([s.Function,"var(",-1,-1,{value:"var"}],[s.CloseParen,")",-1,-1,void 0],[new v([s.Ident,i,-1,-1,{value:i}]),new v([s.Comma,",",-1,-1,void 0]),new d([[s.Whitespace," ",-1,-1,void 0]]),n])});return{value:h(n),toggles:o}}function newNestedRuleWithSupportsNot(e,r,t,o){const s=r({selector:"& *",source:e.source});if(!o)return{inner:s,outer:s};const n=t({name:"supports",params:"not (color: light-dark(tan, tan))",source:e.source});return n.append(s),{inner:s,outer:n}}const C=/^color-scheme$/i,P=/\blight-dark\(/i,N=/^property$/i,$=/^keyframes$/i;function inKeyframes(e){let r=e.parent;for(;r;){if("atrule"===r.type&&$.test(r.name))return r;r=r.parent}}const basePlugin=e=>({postcssPlugin:"postcss-light-dark-function",prepare(){let r=0;const currentToggleNameGenerator=()=>toggleNameGenerator(r++),t=new Map;return{postcssPlugin:"postcss-light-dark-function",Declaration(r,{atRule:o,rule:s}){const i=r.parent;if(i&&!(inKeyframes(r)||"atrule"===r.parent?.type&&N.test(r.parent.name))){if(C.test(r.prop)){if(i.some(e=>"decl"===e.type&&e.prop===k))return;const[e,t]=colorSchemes(r.value);if(e&&t){r.cloneBefore({prop:k,value:D});const e=i.clone();e.removeAll(),e.append(r.clone({prop:k,value:" "}));const t=o({name:"media",params:"(prefers-color-scheme: dark)",source:i.source});return t.append(e),void i.after(t)}return t?void r.cloneBefore({prop:k,value:" "}):e?void r.cloneBefore({prop:k,value:D}):void 0}if(P.test(r.value)){if(n(r))return;if(a(r,P))return;const i=transformLightDark(r.value,currentToggleNameGenerator);if(i.value===r.value)return;for(const[e,t]of i.toggles)r.cloneBefore({prop:e,value:t});if(r.cloneBefore({value:i.value}),r.variable&&r.parent){const n=t.get(r.parent)??newNestedRuleWithSupportsNot(r,s,o,e?.preserve);for(const[e,t]of i.toggles)n.inner.append(r.clone({prop:e,value:t}));n.inner.append(r.clone({value:i.value})),t.has(r.parent)||(r.parent.append(n.outer),t.set(r.parent,n))}e?.preserve||r.remove()}}}}}});basePlugin.postcss=!0;const postcssPlugin=r=>{const t=Object.assign({enableProgressiveCustomProperties:!0,preserve:!0},r);return t.enableProgressiveCustomProperties&&t.preserve?{postcssPlugin:"postcss-light-dark-function",plugins:[e(),basePlugin(t)]}:basePlugin(t)};postcssPlugin.postcss=!0;export{postcssPlugin as default,postcssPlugin as"module.exports"}; diff --git a/plugins/postcss-light-dark-function/src/index.ts b/plugins/postcss-light-dark-function/src/index.ts index cb0f32b995..4735b57f39 100644 --- a/plugins/postcss-light-dark-function/src/index.ts +++ b/plugins/postcss-light-dark-function/src/index.ts @@ -1,5 +1,5 @@ import postcssProgressiveCustomProperties from '@csstools/postcss-progressive-custom-properties'; -import type { ChildNode, Container, Plugin, PluginCreator, Rule } from 'postcss'; +import type { AtRule, ChildNode, Container, Declaration, Document, Plugin, PluginCreator, Rule } from 'postcss'; import { LIGHT_PROP, OFF, ON, toggleNameGenerator } from './props'; import { colorSchemes } from './color-schemes'; import { hasFallback, hasSupportsAtRuleAncestor } from '@csstools/utilities'; @@ -8,6 +8,19 @@ import { newNestedRuleWithSupportsNot } from './nested-rule'; const COLOR_SCHEME_REGEX = /^color-scheme$/i; const LIGHT_DARK_FUNCTION_REGEX = /\blight-dark\(/i; +const IS_PROPERTY_REGEX = /^property$/i; +const IS_KEYFRAMES_REGEX = /^keyframes$/i; + +function inKeyframes(decl: Declaration): AtRule | void { + let parent: typeof decl.parent | Document = decl.parent; + while (parent) { + if (parent.type === 'atrule' && IS_KEYFRAMES_REGEX.test(parent.name)) { + return parent; + } + + parent = parent.parent; + } +} const basePlugin: PluginCreator = (opts) => { return { @@ -28,6 +41,14 @@ const basePlugin: PluginCreator = (opts) => { return; } + if (inKeyframes(decl)) { + return; + } + + if (decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + if (COLOR_SCHEME_REGEX.test(decl.prop)) { if (parent.some((sibling) => sibling.type === 'decl' && sibling.prop === LIGHT_PROP)) { return; diff --git a/plugins/postcss-light-dark-function/test/basic.css b/plugins/postcss-light-dark-function/test/basic.css index ad11775e08..feb608faad 100644 --- a/plugins/postcss-light-dark-function/test/basic.css +++ b/plugins/postcss-light-dark-function/test/basic.css @@ -73,3 +73,26 @@ --theme-color: light-dark(cyan, deepskyblue); color: blue; } + +@property --foo { + inherits: false; + initial-value: light-dark(cyan, deepskyblue); +} + +@keyframes --foo { + to { + --foo: light-dark(cyan, deepskyblue); + } +} + +@keyframes --bar { + to { + color: light-dark(cyan, deepskyblue); + } +} + +@keyframes --scheme { + to { + color-scheme: dark; + } +} diff --git a/plugins/postcss-light-dark-function/test/basic.expect.css b/plugins/postcss-light-dark-function/test/basic.expect.css index 2a74767521..d127fb194a 100644 --- a/plugins/postcss-light-dark-function/test/basic.expect.css +++ b/plugins/postcss-light-dark-function/test/basic.expect.css @@ -130,3 +130,26 @@ --theme-color: light-dark(cyan, deepskyblue); } } + +@property --foo { + inherits: false; + initial-value: light-dark(cyan, deepskyblue); +} + +@keyframes --foo { + to { + --foo: light-dark(cyan, deepskyblue); + } +} + +@keyframes --bar { + to { + color: light-dark(cyan, deepskyblue); + } +} + +@keyframes --scheme { + to { + color-scheme: dark; + } +} diff --git a/plugins/postcss-light-dark-function/test/basic.preserve-false.expect.css b/plugins/postcss-light-dark-function/test/basic.preserve-false.expect.css index 569bfb866e..5ea3c14428 100644 --- a/plugins/postcss-light-dark-function/test/basic.preserve-false.expect.css +++ b/plugins/postcss-light-dark-function/test/basic.preserve-false.expect.css @@ -109,3 +109,26 @@ --theme-color: var(--csstools-light-dark-toggle--13, cyan); } } + +@property --foo { + inherits: false; + initial-value: light-dark(cyan, deepskyblue); +} + +@keyframes --foo { + to { + --foo: light-dark(cyan, deepskyblue); + } +} + +@keyframes --bar { + to { + color: light-dark(cyan, deepskyblue); + } +} + +@keyframes --scheme { + to { + color-scheme: dark; + } +} diff --git a/plugins/postcss-logical-viewport-units/CHANGELOG.md b/plugins/postcss-logical-viewport-units/CHANGELOG.md index 700361486f..3dbea9218a 100644 --- a/plugins/postcss-logical-viewport-units/CHANGELOG.md +++ b/plugins/postcss-logical-viewport-units/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Logical Viewport Units +### Unreleased (patch) + +- Better fallbacks for custom properties + ### 4.0.0 _January 14, 2026_ diff --git a/plugins/postcss-logical-viewport-units/dist/index.d.ts b/plugins/postcss-logical-viewport-units/dist/index.d.ts index a9bc2e832b..936dc1eb1b 100644 --- a/plugins/postcss-logical-viewport-units/dist/index.d.ts +++ b/plugins/postcss-logical-viewport-units/dist/index.d.ts @@ -1,8 +1,12 @@ import type { PluginCreator } from 'postcss'; -declare const creator: PluginCreator; -export default creator; -export { creator as 'module.exports' } +/** postcss-logical-viewport-units plugin options */ +export declare type basePluginOptions = { + /** Preserve the original notation. default: true */ + preserve: boolean; + /** Sets the direction for inline. default: left-to-right */ + inlineDirection?: DirectionFlow; +}; export declare enum DirectionFlow { TopToBottom = "top-to-bottom", @@ -13,10 +17,16 @@ export declare enum DirectionFlow { /** postcss-logical-viewport-units plugin options */ export declare type pluginOptions = { - /** Preserve the original notation. default: false */ + /** Preserve the original notation. default: true */ preserve?: boolean; /** Sets the direction for inline. default: left-to-right */ inlineDirection?: DirectionFlow; + /** Enable "@csstools/postcss-progressive-custom-properties". default: true */ + enableProgressiveCustomProperties?: boolean; }; +declare const postcssPlugin: PluginCreator; +export default postcssPlugin; +export { postcssPlugin as 'module.exports' } + export { } diff --git a/plugins/postcss-logical-viewport-units/dist/index.mjs b/plugins/postcss-logical-viewport-units/dist/index.mjs index c20ba24023..05593daa3d 100644 --- a/plugins/postcss-logical-viewport-units/dist/index.mjs +++ b/plugins/postcss-logical-viewport-units/dist/index.mjs @@ -1 +1 @@ -import{hasFallback as t,hasSupportsAtRuleAncestor as o}from"@csstools/utilities";import{tokenizer as e,isTokenEOF as i,isTokenDimension as r,stringify as n}from"@csstools/css-tokenizer";var s;function transform(t,o){const s=e({css:t}),c=[];let u=!1;for(;;){const t=s.nextToken();if(!t)break;if(c.push(t),i(t))break;if(!r(t))continue;const e=t[4].unit.toLowerCase();let n;"vi"===e?n=o.vi:"vb"===e&&(n=o.vb),n&&(t[1]=t[4].value.toString()+n,t[4].unit=n,u=!0)}return u?n(...c):t}!function(t){t.TopToBottom="top-to-bottom",t.BottomToTop="bottom-to-top",t.RightToLeft="right-to-left",t.LeftToRight="left-to-right"}(s||(s={}));const c=/vb|vi/i,u={test(t){if(!c.test(t))return!1;const o=e({css:t});for(;;){const t=o.nextToken();if(i(t))break;if(!r(t))continue;const e=t[4].unit.toLowerCase();if("vb"===e||"vi"===e)return!0}return!1}},a=/(?:vi|vb)\b/i,creator=e=>{const i=Object.assign({inlineDirection:s.LeftToRight,preserve:!0},e);switch(i.inlineDirection){case s.LeftToRight:case s.RightToLeft:case s.TopToBottom:case s.BottomToTop:break;default:throw new Error(`[postcss-logical-viewport-units] "inlineDirection" must be one of ${Object.values(s).join(", ")}`)}const r=[s.LeftToRight,s.RightToLeft].includes(i.inlineDirection),n={vb:"vh",vi:"vw"};return r||(n.vb="vw",n.vi="vh"),{postcssPlugin:"postcss-logical-viewport-units",Declaration(e,{atRule:r}){if(!a.test(e.value))return;if(t(e))return;if(o(e,u))return;const s=transform(e.value,n);if(s===e.value)return;if(e.cloneBefore({value:s}),!i.preserve)return void e.remove();if(!e.variable)return;const c=r({name:"supports",params:"(top: 1vi)",source:e.source}),f=e.parent;if(!f)return;const v=f.cloneAfter({nodes:[]});v.append(e),c.append(v),f.after(c)}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import t from"@csstools/postcss-progressive-custom-properties";import{hasFallback as o,hasSupportsAtRuleAncestor as e}from"@csstools/utilities";import{tokenizer as s,isTokenEOF as i,isTokenDimension as r,stringify as n}from"@csstools/css-tokenizer";var c;function transform(t,o){const e=s({css:t}),c=[];let u=!1;for(;;){const t=e.nextToken();if(!t)break;if(c.push(t),i(t))break;if(!r(t))continue;const s=o[t[4].unit.toLowerCase()];s&&(t[1]=t[4].value.toString()+s,t[4].unit=s,u=!0)}return u?n(...c):t}!function(t){t.TopToBottom="top-to-bottom",t.BottomToTop="bottom-to-top",t.RightToLeft="right-to-left",t.LeftToRight="left-to-right"}(c||(c={}));const u=/vb|vi/i,l={test(t){if(!u.test(t))return!1;const o=s({css:t});for(;;){const t=o.nextToken();if(i(t))break;if(!r(t))continue;const e=t[4].unit.toLowerCase();if("vb"===e||"vi"===e)return!0}return!1}},v=/(?:vi|vb|svi|svb|lvi|lvb)\b/i,basePlugin=t=>{const s=Object.assign({inlineDirection:c.LeftToRight},t);switch(s.inlineDirection){case c.LeftToRight:case c.RightToLeft:case c.TopToBottom:case c.BottomToTop:break;default:throw new Error(`[postcss-logical-viewport-units] "inlineDirection" must be one of ${Object.values(c).join(", ")}`)}const i=[c.LeftToRight,c.RightToLeft].includes(s.inlineDirection),r={vb:"vh",vi:"vw"};return i||(r.vb="vw",r.vi="vh"),{postcssPlugin:"postcss-logical-viewport-units",Declaration(t){if(!v.test(t.value))return;if(o(t))return;if(e(t,l))return;const i=transform(t.value,r);i!==t.value&&(t.cloneBefore({value:i}),s.preserve||t.remove())}}};basePlugin.postcss=!0;const postcssPlugin=o=>{const e=Object.assign({preserve:!0,enableProgressiveCustomProperties:!0},o);return e.enableProgressiveCustomProperties&&e.preserve?{postcssPlugin:"postcss-logical-viewport-units",plugins:[t(),basePlugin(e)]}:basePlugin(e)};postcssPlugin.postcss=!0;export{postcssPlugin as default,postcssPlugin as"module.exports"}; diff --git a/plugins/postcss-logical-viewport-units/package.json b/plugins/postcss-logical-viewport-units/package.json index ae5a5f2ed4..7c54aa558d 100644 --- a/plugins/postcss-logical-viewport-units/package.json +++ b/plugins/postcss-logical-viewport-units/package.json @@ -42,6 +42,7 @@ ], "dependencies": { "@csstools/css-tokenizer": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^5.1.2", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { diff --git a/plugins/postcss-logical-viewport-units/src/index.ts b/plugins/postcss-logical-viewport-units/src/index.ts index b89e21124c..58abf8c481 100644 --- a/plugins/postcss-logical-viewport-units/src/index.ts +++ b/plugins/postcss-logical-viewport-units/src/index.ts @@ -1,27 +1,28 @@ +import postcssProgressiveCustomProperties from '@csstools/postcss-progressive-custom-properties'; import type { PluginCreator } from 'postcss'; import { hasFallback, hasSupportsAtRuleAncestor } from '@csstools/utilities'; import { DirectionFlow } from './lib/types'; +import type { Replacements} from './transform'; import { transform } from './transform'; import { predicate } from './has-feature'; export type { DirectionFlow } from './lib/types'; /** postcss-logical-viewport-units plugin options */ -export type pluginOptions = { - /** Preserve the original notation. default: false */ - preserve?: boolean, +export type basePluginOptions = { + /** Preserve the original notation. default: true */ + preserve: boolean, /** Sets the direction for inline. default: left-to-right */ inlineDirection?: DirectionFlow, }; -const HAS_VIEWPORT_UNITS_REGEX = /(?:vi|vb)\b/i; +const HAS_VIEWPORT_UNITS_REGEX = /(?:vi|vb|svi|svb|lvi|lvb)\b/i; -const creator: PluginCreator = (opts?: pluginOptions) => { +const basePlugin: PluginCreator = (opts?: basePluginOptions) => { const options = Object.assign( // Default options { inlineDirection: DirectionFlow.LeftToRight, - preserve: true, }, // Provided options opts, @@ -39,7 +40,7 @@ const creator: PluginCreator = (opts?: pluginOptions) => { const isHorizontal = [DirectionFlow.LeftToRight, DirectionFlow.RightToLeft].includes(options.inlineDirection); - const replacements: { vi: 'vw' | 'vh', vb: 'vw' | 'vh' } = { + const replacements: Replacements = { vb: 'vh', vi: 'vw', }; @@ -51,7 +52,7 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return { postcssPlugin: 'postcss-logical-viewport-units', - Declaration(decl, { atRule }): void { + Declaration(decl): void { { if (!HAS_VIEWPORT_UNITS_REGEX.test(decl.value)) { return; @@ -78,35 +79,45 @@ const creator: PluginCreator = (opts?: pluginOptions) => { if (!options.preserve) { decl.remove(); - return; - } - - if (!decl.variable) { - return; } + }, + }; +}; - const supports = atRule({ - name: 'supports', - params: '(top: 1vi)', - source: decl.source, - }); - const parent = decl.parent; - if (!parent) { - return; - } +basePlugin.postcss = true; - const parentClone = parent.cloneAfter({ nodes: [] }); +/** postcss-logical-viewport-units plugin options */ +export type pluginOptions = { + /** Preserve the original notation. default: true */ + preserve?: boolean, + /** Sets the direction for inline. default: left-to-right */ + inlineDirection?: DirectionFlow, + /** Enable "@csstools/postcss-progressive-custom-properties". default: true */ + enableProgressiveCustomProperties?: boolean, +}; - parentClone.append(decl); - supports.append(parentClone); +const postcssPlugin: PluginCreator = (opts?: pluginOptions) => { + const options = Object.assign({ + preserve: true, + enableProgressiveCustomProperties: true, + }, opts); + + if (options.enableProgressiveCustomProperties && options.preserve) { + return { + postcssPlugin: 'postcss-logical-viewport-units', + plugins: [ + postcssProgressiveCustomProperties(), + basePlugin(options), + ], + }; + } - parent.after(supports); - }, - }; + return basePlugin(options); }; -creator.postcss = true; +postcssPlugin.postcss = true; + +export default postcssPlugin; +export { postcssPlugin as 'module.exports' }; -export default creator; -export { creator as 'module.exports' }; diff --git a/plugins/postcss-logical-viewport-units/src/transform.ts b/plugins/postcss-logical-viewport-units/src/transform.ts index 5ae8ed5c4c..99e7fa4c46 100644 --- a/plugins/postcss-logical-viewport-units/src/transform.ts +++ b/plugins/postcss-logical-viewport-units/src/transform.ts @@ -1,6 +1,11 @@ import { isTokenDimension, isTokenEOF, stringify, tokenizer } from '@csstools/css-tokenizer'; -export function transform(source: string, replacements: { vi: 'vw' | 'vh', vb: 'vw' | 'vh' }): string { +export type Replacements = { + vi: 'vw' | 'vh', + vb: 'vw' | 'vh', +}; + +export function transform(source: string, replacements: Replacements): string { const t = tokenizer({ css: source }); const tokens = []; let didTransformUnits = false; @@ -22,12 +27,7 @@ export function transform(source: string, replacements: { vi: 'vw' | 'vh', vb: ' } const unit = token[4].unit.toLowerCase(); - let replacement; - if (unit === 'vi') { - replacement = replacements.vi; - } else if (unit === 'vb') { - replacement = replacements.vb; - } + const replacement = (replacements as Record)[unit]; if (!replacement) { continue; } diff --git a/plugins/postcss-logical-viewport-units/test/_tape.mjs b/plugins/postcss-logical-viewport-units/test/_tape.mjs index 02a067a71a..02c1ce26f6 100644 --- a/plugins/postcss-logical-viewport-units/test/_tape.mjs +++ b/plugins/postcss-logical-viewport-units/test/_tape.mjs @@ -5,6 +5,12 @@ postcssTape(plugin)({ basic: { message: 'supports basic usage', }, + 'basic:preserve-false': { + message: 'supports basic usage with { preserve: false }', + options: { + preserve: false, + }, + }, 'basic:hebrew': { message: 'supports { inlineDirection: \'right-to-left\' }', options: { diff --git a/plugins/postcss-logical-viewport-units/test/basic.css b/plugins/postcss-logical-viewport-units/test/basic.css index a46d93369f..4545a3d1e5 100644 --- a/plugins/postcss-logical-viewport-units/test/basic.css +++ b/plugins/postcss-logical-viewport-units/test/basic.css @@ -14,6 +14,22 @@ left: 5vi; } +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + @supports (width: 100vb) { .vi { left: 5vi; @@ -32,3 +48,14 @@ to-clone { left: 5vi; } + +@property --foo { + inherits: false; + initial-value: 5vi; +} + +@keyframes --foo { + to { + --foo: 5vi; + } +} diff --git a/plugins/postcss-logical-viewport-units/test/basic.expect.css b/plugins/postcss-logical-viewport-units/test/basic.expect.css index e2eed35687..7279d74727 100644 --- a/plugins/postcss-logical-viewport-units/test/basic.expect.css +++ b/plugins/postcss-logical-viewport-units/test/basic.expect.css @@ -18,6 +18,22 @@ left: 5vi; } +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + @supports (width: 100vb) { .vi { left: 5vi; @@ -28,8 +44,7 @@ --var: 5vw; } -@supports (top: 1vi) { - +@supports (width: 1vi) { :root { --var: 5vi; } @@ -44,3 +59,31 @@ to-clone { left: 5vw; left: 5vi; } + +@property --foo { + inherits: false; + initial-value: 5vw; +} + +@supports (width: 1vi) { +@property --foo { + inherits: false; + initial-value: 5vi; +} +} + +@keyframes --foo { + to { + --foo: 5vw; + } +} + +@supports (width: 1vi) { + +@keyframes --foo { + to { + --foo: 5vw; + --foo: 5vi; + } +} +} diff --git a/plugins/postcss-logical-viewport-units/test/basic.hebrew.expect.css b/plugins/postcss-logical-viewport-units/test/basic.hebrew.expect.css index e2eed35687..7279d74727 100644 --- a/plugins/postcss-logical-viewport-units/test/basic.hebrew.expect.css +++ b/plugins/postcss-logical-viewport-units/test/basic.hebrew.expect.css @@ -18,6 +18,22 @@ left: 5vi; } +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + @supports (width: 100vb) { .vi { left: 5vi; @@ -28,8 +44,7 @@ --var: 5vw; } -@supports (top: 1vi) { - +@supports (width: 1vi) { :root { --var: 5vi; } @@ -44,3 +59,31 @@ to-clone { left: 5vw; left: 5vi; } + +@property --foo { + inherits: false; + initial-value: 5vw; +} + +@supports (width: 1vi) { +@property --foo { + inherits: false; + initial-value: 5vi; +} +} + +@keyframes --foo { + to { + --foo: 5vw; + } +} + +@supports (width: 1vi) { + +@keyframes --foo { + to { + --foo: 5vw; + --foo: 5vi; + } +} +} diff --git a/plugins/postcss-logical-viewport-units/test/basic.preserve-false.expect.css b/plugins/postcss-logical-viewport-units/test/basic.preserve-false.expect.css new file mode 100644 index 0000000000..a88b7970fe --- /dev/null +++ b/plugins/postcss-logical-viewport-units/test/basic.preserve-false.expect.css @@ -0,0 +1,61 @@ +.foo { + margin: 10vw 20vh; +} + +.foo { + margin: calc(10vw + 5vh); +} + +.vb { + left: 5vh; +} + +.vi { + left: 5vw; +} + +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + +@supports (width: 100vb) { + .vi { + left: 5vi; + } +} + +:root { + --var: 5vw; +} + +.fallback { + left: 5vw; + left: 5vi; +} + +to-clone { + left: 5vw; +} + +@property --foo { + inherits: false; + initial-value: 5vw; +} + +@keyframes --foo { + to { + --foo: 5vw; + } +} diff --git a/plugins/postcss-logical-viewport-units/test/basic.vertical.expect.css b/plugins/postcss-logical-viewport-units/test/basic.vertical.expect.css index c3545aeda8..b0d2fb6653 100644 --- a/plugins/postcss-logical-viewport-units/test/basic.vertical.expect.css +++ b/plugins/postcss-logical-viewport-units/test/basic.vertical.expect.css @@ -18,6 +18,22 @@ left: 5vi; } +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + @supports (width: 100vb) { .vi { left: 5vi; @@ -28,8 +44,7 @@ --var: 5vh; } -@supports (top: 1vi) { - +@supports (width: 1vi) { :root { --var: 5vi; } @@ -44,3 +59,31 @@ to-clone { left: 5vh; left: 5vi; } + +@property --foo { + inherits: false; + initial-value: 5vh; +} + +@supports (width: 1vi) { +@property --foo { + inherits: false; + initial-value: 5vi; +} +} + +@keyframes --foo { + to { + --foo: 5vh; + } +} + +@supports (width: 1vi) { + +@keyframes --foo { + to { + --foo: 5vh; + --foo: 5vi; + } +} +} diff --git a/plugins/postcss-logical-viewport-units/test/basic.with-cloned-rules.expect.css b/plugins/postcss-logical-viewport-units/test/basic.with-cloned-rules.expect.css index 535d9d0278..ab10df3c8a 100644 --- a/plugins/postcss-logical-viewport-units/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-logical-viewport-units/test/basic.with-cloned-rules.expect.css @@ -18,6 +18,22 @@ left: 5vi; } +.svb { + left: 5svb; +} + +.svi { + left: 5svi; +} + +.lvb { + left: 5lvb; +} + +.lvi { + left: 5lvi; +} + @supports (width: 100vb) { .vi { left: 5vi; @@ -28,8 +44,7 @@ --var: 5vw; } -@supports (top: 1vi) { - +@supports (width: 1vi) { :root { --var: 5vi; } @@ -49,3 +64,31 @@ to-clone { left: 5vw; left: 5vi; } + +@property --foo { + inherits: false; + initial-value: 5vw; +} + +@supports (width: 1vi) { +@property --foo { + inherits: false; + initial-value: 5vi; +} +} + +@keyframes --foo { + to { + --foo: 5vw; + } +} + +@supports (width: 1vi) { + +@keyframes --foo { + to { + --foo: 5vw; + --foo: 5vi; + } +} +} diff --git a/plugins/postcss-nested-calc/CHANGELOG.md b/plugins/postcss-nested-calc/CHANGELOG.md index a85157d2fd..9f489d9036 100644 --- a/plugins/postcss-nested-calc/CHANGELOG.md +++ b/plugins/postcss-nested-calc/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Nested Calc +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 5.0.0 _January 14, 2026_ diff --git a/plugins/postcss-nested-calc/dist/index.mjs b/plugins/postcss-nested-calc/dist/index.mjs index eb9702f53e..e62ff2a4ed 100644 --- a/plugins/postcss-nested-calc/dist/index.mjs +++ b/plugins/postcss-nested-calc/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";import{hasFallback as t}from"@csstools/utilities";const r=/calc\(/gi;const creator=s=>{const o=Object.assign({preserve:!0},s);return{postcssPlugin:"postcss-nested-calc",Declaration(s,{result:a}){if((s.value.match(r)||[]).length<2)return;if(s.variable)return;if(t(s))return;const n=s.value;let l;try{l=e(n)}catch{return void s.warn(a,`Failed to parse value '${n}'. Leaving the original value intact.`)}if(void 0===l)return;e.walk(l.nodes,t=>{t.type&&"function"===t.type&&"calc"===t.value.toLowerCase()&&e.walk(t.nodes,e=>{if(e.type&&"function"===e.type)return"calc"===e.value.toLowerCase()&&void(e.value="")})},!0);const c=String(l);c!==n&&(s.cloneBefore({value:c}),o.preserve||s.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import e from"postcss-value-parser";import{hasFallback as t}from"@csstools/utilities";const r=/calc\(/gi;const a=/^property$/i,creator=s=>{const o=Object.assign({preserve:!0},s);return{postcssPlugin:"postcss-nested-calc",Declaration(s,{result:n}){if((s.value.match(r)||[]).length<2)return;if(s.variable)return;if(t(s))return;if(o.preserve&&"atrule"===s.parent?.type&&a.test(s.parent.name))return;const l=s.value;let i;try{i=e(l)}catch{return void s.warn(n,`Failed to parse value '${l}'. Leaving the original value intact.`)}if(void 0===i)return;e.walk(i.nodes,t=>{t.type&&"function"===t.type&&"calc"===t.value.toLowerCase()&&e.walk(t.nodes,e=>{if(e.type&&"function"===e.type)return"calc"===e.value.toLowerCase()&&void(e.value="")})},!0);const c=String(i);c!==l&&(s.cloneBefore({value:c}),o.preserve||s.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-nested-calc/src/index.ts b/plugins/postcss-nested-calc/src/index.ts index 48df04427b..69d787a8ad 100644 --- a/plugins/postcss-nested-calc/src/index.ts +++ b/plugins/postcss-nested-calc/src/index.ts @@ -4,6 +4,8 @@ import type { ParsedValue } from 'postcss-value-parser'; import { numberOfCalcOccurrences } from './occurrences'; import { hasFallback } from '@csstools/utilities'; +const IS_PROPERTY_REGEX = /^property$/i; + /** postcss-nested-calc plugin options */ export type pluginOptions = { /** Preserve the original notation. default: true */ @@ -38,6 +40,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + const originalValue = decl.value; let valueAST: ParsedValue | undefined; diff --git a/plugins/postcss-nested-calc/test/basic.css b/plugins/postcss-nested-calc/test/basic.css index 21b2cfd313..a1b3c18074 100644 --- a/plugins/postcss-nested-calc/test/basic.css +++ b/plugins/postcss-nested-calc/test/basic.css @@ -49,3 +49,14 @@ to-clone { width: calc(10px + calc(2px * 2)); } + +@property --foo { + inherits: false; + initial-value: calc(10px + calc(2px * 2)); +} + +@keyframes --foo { + to { + --foo: calc(10px + calc(2px * 2)); + } +} diff --git a/plugins/postcss-nested-calc/test/basic.expect.css b/plugins/postcss-nested-calc/test/basic.expect.css index e0f7a7206c..88999b5194 100644 --- a/plugins/postcss-nested-calc/test/basic.expect.css +++ b/plugins/postcss-nested-calc/test/basic.expect.css @@ -64,3 +64,14 @@ to-clone { width: calc(10px + (2px * 2)); width: calc(10px + calc(2px * 2)); } + +@property --foo { + inherits: false; + initial-value: calc(10px + calc(2px * 2)); +} + +@keyframes --foo { + to { + --foo: calc(10px + calc(2px * 2)); + } +} diff --git a/plugins/postcss-nested-calc/test/basic.preserve-false.expect.css b/plugins/postcss-nested-calc/test/basic.preserve-false.expect.css index ff54acd286..9c30f912c7 100644 --- a/plugins/postcss-nested-calc/test/basic.preserve-false.expect.css +++ b/plugins/postcss-nested-calc/test/basic.preserve-false.expect.css @@ -49,3 +49,14 @@ to-clone { width: calc(10px + (2px * 2)); } + +@property --foo { + inherits: false; + initial-value: calc(10px + (2px * 2)); +} + +@keyframes --foo { + to { + --foo: calc(10px + calc(2px * 2)); + } +} diff --git a/plugins/postcss-nested-calc/test/basic.with-cloned-rules.expect.css b/plugins/postcss-nested-calc/test/basic.with-cloned-rules.expect.css index 24b06a4060..a232d18bb4 100644 --- a/plugins/postcss-nested-calc/test/basic.with-cloned-rules.expect.css +++ b/plugins/postcss-nested-calc/test/basic.with-cloned-rules.expect.css @@ -69,3 +69,14 @@ to-clone { width: calc(10px + (2px * 2)); width: calc(10px + calc(2px * 2)); } + +@property --foo { + inherits: false; + initial-value: calc(10px + calc(2px * 2)); +} + +@keyframes --foo { + to { + --foo: calc(10px + calc(2px * 2)); + } +} diff --git a/plugins/postcss-oklab-function/test/basic.css b/plugins/postcss-oklab-function/test/basic.css index 06dc7f32f2..505ab92d10 100644 --- a/plugins/postcss-oklab-function/test/basic.css +++ b/plugins/postcss-oklab-function/test/basic.css @@ -166,3 +166,14 @@ color-1: oklab(from oklab(40% 0.566 0.39) l a b); color-2: oklch(from oklch(40% 0.566 39deg) l c h); } + +@property --foo { + inherits: false; + initial-value: oklch(60% 0.1250 180); +} + +@keyframes --foo { + to { + --foo: oklch(60% 0.1250 180); + } +} diff --git a/plugins/postcss-oklab-function/test/basic.expect.css b/plugins/postcss-oklab-function/test/basic.expect.css index f3c775594e..deb263da87 100644 --- a/plugins/postcss-oklab-function/test/basic.expect.css +++ b/plugins/postcss-oklab-function/test/basic.expect.css @@ -201,3 +201,31 @@ color-2: oklch(from rgb(126, 37, 0) l c h); color-2: oklch(from color(display-p3 0.47553 0.14324 0) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 149, 131); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.19244 0.58461 0.51559); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + } +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + --foo: color(display-p3 0.19244 0.58461 0.51559); + } +} +} diff --git a/plugins/postcss-oklab-function/test/basic.preserve-true.display-p3-false.expect.css b/plugins/postcss-oklab-function/test/basic.preserve-true.display-p3-false.expect.css index b2b422bf0d..9808f301e8 100644 --- a/plugins/postcss-oklab-function/test/basic.preserve-true.display-p3-false.expect.css +++ b/plugins/postcss-oklab-function/test/basic.preserve-true.display-p3-false.expect.css @@ -262,3 +262,31 @@ color-2: oklch(from rgb(126, 37, 0) l c h); color-2: oklch(from oklch(40% 0.566 39deg) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 149, 131); +} + +@supports (color: oklab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: oklch(60% 0.1250 180); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + } +} + +@supports (color: oklab(0% 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + --foo: oklch(60% 0.1250 180); + } +} +} diff --git a/plugins/postcss-oklab-function/test/basic.preserve-true.expect.css b/plugins/postcss-oklab-function/test/basic.preserve-true.expect.css index 8d04e66330..1aff5a0755 100644 --- a/plugins/postcss-oklab-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-oklab-function/test/basic.preserve-true.expect.css @@ -297,3 +297,39 @@ color-2: oklch(from color(display-p3 0.47553 0.14324 0) l c h); color-2: oklch(from oklch(40% 0.566 39deg) l c h); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 149, 131); +} + +@supports (color: color(display-p3 0 0 0%)) { +@property --foo { + inherits: false; + initial-value: color(display-p3 0.19244 0.58461 0.51559); +} +} + +@supports (color: oklab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: oklch(60% 0.1250 180); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: oklab(0% 0 0%)) { + +@keyframes --foo { + to { + --foo: rgb(0, 149, 131); + --foo: color(display-p3 0.19244 0.58461 0.51559); + --foo: oklch(60% 0.1250 180); + } +} +} diff --git a/plugins/postcss-progressive-custom-properties/CHANGELOG.md b/plugins/postcss-progressive-custom-properties/CHANGELOG.md index 26585c7ea0..c15b22f5d5 100644 --- a/plugins/postcss-progressive-custom-properties/CHANGELOG.md +++ b/plugins/postcss-progressive-custom-properties/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Progressive Custom Properties +### Unreleased (patch) + +- Fix support conditions for `@property` and `@keyframes` + ### 5.1.2 _August 15, 2026_ diff --git a/plugins/postcss-progressive-custom-properties/dist/index.mjs b/plugins/postcss-progressive-custom-properties/dist/index.mjs index 8cd0074943..6d4a9996b4 100644 --- a/plugins/postcss-progressive-custom-properties/dist/index.mjs +++ b/plugins/postcss-progressive-custom-properties/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-value-parser";const r=["at","bottom","center","circle","closest-corner","closest-side","ellipse","farthest-corner","farthest-side","from","in","left","right","to","top"];function doublePositionGradients(e){const t=[],o=e.value.toLowerCase();if("function"===e.type&&("conic-gradient"===o||"linear-gradient"===o||"radial-gradient"===o||"repeating-conic-gradient"===o||"repeating-linear-gradient"===o||"repeating-radial-gradient"===o)){let o=0,a=!1,i=!1;e:for(let s=0;si.includes(e.sniff)&&(e.only_on_property??r.prop)===r.prop);let p=!1;try{e(i).walk(r=>{"function"===r.type&&o.test(r.value)&&(p=!0);try{const t=e.unit(r.value);!1!==t&&(r.dimension=t)}catch{}for(let e=0;e{e.append(r.clone())})}const creator=()=>({postcssPlugin:"postcss-progressive-custom-properties",prepare(){const e=new WeakMap;return{postcssPlugin:"postcss-progressive-custom-properties",OnceExit(r,{postcss:t}){r.walkDecls(r=>{if(!r.parent)return;const o=e.get(r.parent)||{conditionalRules:[],propNames:new Set,lastConditionParams:{support:void 0},lastConditionalRule:void 0};if(e.set(r.parent,o),r.variable){if(!o.propNames.has(r.prop))return void o.propNames.add(r.prop)}else{const e=r.prop.toLowerCase();if(!o.propNames.has(e))return void o.propNames.add(e)}if(!r.variable&&!i.test(r.value))return;if(s.test(r.value))return;if(n.test(r.value))return;const a=conditionsFromValue(r,!r.variable).support.join(" and ");if(!a)return;if(o.lastConditionParams.support!==a&&(o.lastConditionalRule=void 0),o.lastConditionalRule)return cloneDeclarations(o.lastConditionalRule,r),void r.remove();const p=[];if(a&&p.push(t.atRule({name:"supports",params:a,source:r.parent.source,raws:{before:"\n\n",after:"\n"}})),!p.length)return;for(let e=0;e{const t=e.get(r);t&&0!==t.conditionalRules.length&&t.conditionalRules.reverse().forEach(e=>{r.after(e)})})}}}});creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import e from"postcss-value-parser";const r=["at","bottom","center","circle","closest-corner","closest-side","ellipse","farthest-corner","farthest-side","from","in","left","right","to","top"];function doublePositionGradients(e){const t=[],a=e.value.toLowerCase();if("function"===e.type&&("conic-gradient"===a||"linear-gradient"===a||"radial-gradient"===a||"repeating-conic-gradient"===a||"repeating-linear-gradient"===a||"repeating-radial-gradient"===a)){let a=0,o=!1,i=!1;e:for(let s=0;si.includes(e.sniff)&&(e.only_on_property??r.prop)===r.prop);let p=!1;try{e(i).walk(r=>{"function"===r.type&&a.test(r.value)&&(p=!0);try{const t=e.unit(r.value);!1!==t&&(r.dimension=t)}catch{}for(let e=0;e{"decl"===t.type&&t.prop===r.prop||e.append(t.clone())}),void e.append(r.clone());const t=o.get(r.prop.toLowerCase());if(!t?.length)return void e.append(r.clone());const a=[r];let i=r.next();for(;i;)"decl"===i.type&&t.includes(i.prop)&&a.push(i),i=i.next();a.forEach(r=>{e.append(r.clone())})}const creator=()=>({postcssPlugin:"postcss-progressive-custom-properties",prepare(){const e=new WeakMap;return{postcssPlugin:"postcss-progressive-custom-properties",OnceExit(r,{postcss:t}){r.walkAtRules(e=>{if(!p.test(e.name))return;if(inSupports(e))return;const r=[],a={propNames:new Set},o=e.clone();if(e.walkDecls(e=>{let t=e.prop;if(e.variable||(t=e.prop.toLowerCase()),!a.propNames.has(t))return void a.propNames.add(t);if(!e.variable&&!i.test(e.value))return;if(s.test(e.value))return;if(d.test(e.value))return;const o=conditionsFromValue(e,!e.variable);o.length&&(r.push(...o),e.remove())}),!r.length)return;const n=Array.from(new Set(r)).sort().join(" and ");if(!n)return;const l=t.atRule({name:"supports",params:n,source:e.source,raws:{before:"\n\n",after:"\n"}});l.append(o),e.after(l)}),r.walkDecls(r=>{if(!r.parent)return;if(inKeyframes(r))return;const a=e.get(r.parent)||{conditionalRules:[],propNames:new Set,lastConditionParams:void 0,lastConditionalRule:void 0};if(e.set(r.parent,a),r.variable){if(!a.propNames.has(r.prop))return void a.propNames.add(r.prop)}else{const e=r.prop.toLowerCase();if(!a.propNames.has(e))return void a.propNames.add(e)}if(!(r.variable||"atrule"===r.parent.type&&n.test(r.parent.name)||i.test(r.value)))return;if(s.test(r.value))return;if(d.test(r.value))return;const o=conditionsFromValue(r,!(r.variable||"atrule"===r.parent.type&&n.test(r.parent.name))).join(" and ");if(!o)return;if(a.lastConditionParams!==o&&(a.lastConditionalRule=void 0),a.lastConditionalRule)return cloneDeclarations(a.lastConditionalRule,r),void r.remove();const p=[];if(o&&p.push(t.atRule({name:"supports",params:o,source:r.parent.source,raws:{before:"\n\n",after:"\n"}})),!p.length)return;for(let e=0;e{const t=e.get(r);t&&0!==t.conditionalRules.length&&t.conditionalRules.reverse().forEach(e=>{r.after(e)})})}}}});creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-progressive-custom-properties/scripts/font-size.mjs b/plugins/postcss-progressive-custom-properties/scripts/font-size.mjs deleted file mode 100644 index ccff0e0c09..0000000000 --- a/plugins/postcss-progressive-custom-properties/scripts/font-size.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import { matcherForValue } from './matcher-for-value.mjs'; - -export const icUnitMatchers = [ - { - 'supports': '1ic', - 'property': 'font-size', - 'sniff': 'ic', - 'matchers': [ - matcherForValue('1ic'), - ], - }, -]; diff --git a/plugins/postcss-progressive-custom-properties/scripts/matchers.mjs b/plugins/postcss-progressive-custom-properties/scripts/matchers.mjs index 266381efde..1bedeef535 100644 --- a/plugins/postcss-progressive-custom-properties/scripts/matchers.mjs +++ b/plugins/postcss-progressive-custom-properties/scripts/matchers.mjs @@ -1,7 +1,7 @@ import fs from 'node:fs/promises'; import { alphaMatchers, colorMatchers, hslMatchers, hwbMatchers, labMatchers, lchMatchers, oklabMatchers, oklchMatchers, rgbMatchers } from './color.mjs'; import { colorMixMatchers } from './color-mix.mjs'; -import { icUnitMatchers } from './font-size.mjs'; +import { icUnitMatchers, logicalUnitMatchers } from './units.mjs'; import { lightDarkMatchers } from './light-dark.mjs'; import { relativeColorSyntaxMatches } from './relative-color-syntax.mjs'; import { contrastColorMatchers } from './contrast-color.mjs'; @@ -34,6 +34,9 @@ fs.writeFile( // font-size: ...icUnitMatchers, + // width: + ...logicalUnitMatchers, + // content: ...contentMatchers, diff --git a/plugins/postcss-progressive-custom-properties/scripts/units.mjs b/plugins/postcss-progressive-custom-properties/scripts/units.mjs new file mode 100644 index 0000000000..c884485356 --- /dev/null +++ b/plugins/postcss-progressive-custom-properties/scripts/units.mjs @@ -0,0 +1,63 @@ +import { matcherForValue } from './matcher-for-value.mjs'; + +export const icUnitMatchers = [ + { + 'supports': '1ic', + 'property': 'font-size', + 'sniff': 'ic', + 'matchers': [ + matcherForValue('1ic'), + ], + }, +]; + +export const logicalUnitMatchers = [ + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'vi', + 'matchers': [ + matcherForValue('1vi'), + ], + }, + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'svi', + 'matchers': [ + matcherForValue('1svi'), + ], + }, + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'lvi', + 'matchers': [ + matcherForValue('1lvi'), + ], + }, + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'vb', + 'matchers': [ + matcherForValue('1vb'), + ], + }, + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'svb', + 'matchers': [ + matcherForValue('1svb'), + ], + }, + { + 'supports': '1vi', + 'property': 'width', + 'sniff': 'lvb', + 'matchers': [ + matcherForValue('1lvb'), + ], + }, +]; diff --git a/plugins/postcss-progressive-custom-properties/src/conditions-from-values.ts b/plugins/postcss-progressive-custom-properties/src/conditions-from-values.ts index 02f4068b20..1513d607ef 100644 --- a/plugins/postcss-progressive-custom-properties/src/conditions-from-values.ts +++ b/plugins/postcss-progressive-custom-properties/src/conditions-from-values.ts @@ -6,7 +6,7 @@ import type { Declaration } from 'postcss'; const VAR_FUNCTION_NAME_REGEX = /^var$/i; -export function conditionsFromValue(decl: Declaration, mustContainVar = false): { support: Array } { +export function conditionsFromValue(decl: Declaration, mustContainVar = false): Array { const value = decl.value; const supportConditions: Array = []; @@ -54,12 +54,8 @@ export function conditionsFromValue(decl: Declaration, mustContainVar = false): } if (mustContainVar && !hasVar) { - return { - support: [], - }; + return []; } - return { - support: Array.from(new Set(supportConditions)).sort(), - }; + return Array.from(new Set(supportConditions)).sort(); } diff --git a/plugins/postcss-progressive-custom-properties/src/index.ts b/plugins/postcss-progressive-custom-properties/src/index.ts index 25871444d8..c03a878086 100644 --- a/plugins/postcss-progressive-custom-properties/src/index.ts +++ b/plugins/postcss-progressive-custom-properties/src/index.ts @@ -1,22 +1,58 @@ -import type { ChildNode, Declaration, Plugin } from 'postcss'; +import type { ChildNode, Declaration, Document, Plugin } from 'postcss'; import { type Node, type AtRule, type PluginCreator, type Container } from 'postcss'; import { conditionsFromValue } from './conditions-from-values'; import { shorthands } from './shorthands'; const HAS_VARIABLE_FUNCTION_REGEX = /var\(/i; const IS_INITIAL_REGEX = /^initial$/i; +const IS_PROPERTY_REGEX = /^property$/i; +const IS_KEYFRAMES_REGEX = /^keyframes$/i; +const IS_SUPPORTS_REGEX = /^supports$/i; const EMPTY_OR_WHITESPACE_REGEX = /^\s*$/; type State = { conditionalRules: Array, propNames: Set, - lastConditionParams: { - support: string | undefined, - }, + lastConditionParams: string | undefined, lastConditionalRule: Container | undefined, }; +function inKeyframes(decl: Declaration): AtRule | void { + let parent: typeof decl.parent | Document = decl.parent; + while (parent) { + if (parent.type === 'atrule' && IS_KEYFRAMES_REGEX.test(parent.name)) { + return parent; + } + + parent = parent.parent; + } +} + +function inSupports(atRule: AtRule): AtRule | void { + let parent: typeof atRule.parent | Document = atRule.parent; + while (parent) { + if (parent.type === 'atrule' && IS_SUPPORTS_REGEX.test(parent.name)) { + return parent; + } + + parent = parent.parent; + } +} + function cloneDeclarations(target: Container, decl: Declaration): void { + if (target.type === 'atrule' && IS_PROPERTY_REGEX.test((target as AtRule).name)) { + decl.parent?.each((d) => { + if (d.type === 'decl' && d.prop === decl.prop) { + return; + } + + target.append(d.clone()); + }); + + target.append(decl.clone()); + return; + } + const longhands = shorthands.get(decl.prop.toLowerCase()); if (!longhands?.length) { target.append(decl.clone()); @@ -50,17 +86,100 @@ const creator: PluginCreator = () => { return { postcssPlugin: 'postcss-progressive-custom-properties', OnceExit(root, { postcss }): void { + root.walkAtRules((atRule) => { + if (!IS_KEYFRAMES_REGEX.test(atRule.name)) { + return; + } + + if (inSupports(atRule)) { + return; + } + + const conditions: Array = []; + + const state = { + propNames: new Set(), + }; + + const atRuleClone = atRule.clone(); + + atRule.walkDecls((decl) => { + let prop = decl.prop; + if (!decl.variable) { + prop = decl.prop.toLowerCase(); + } + + if (!state.propNames.has(prop)) { + state.propNames.add(prop); + return; + } + + if ( + !decl.variable && + !HAS_VARIABLE_FUNCTION_REGEX.test(decl.value) + ) { + return; + } + + if (IS_INITIAL_REGEX.test(decl.value)) { + // https://www.w3.org/TR/css-variables-1/#guaranteed-invalid + return; + } + + if (EMPTY_OR_WHITESPACE_REGEX.test(decl.value)) { // empty string value + // https://www.w3.org/TR/css-variables-1/#guaranteed-invalid + return; + } + + // if the property itself isn't a custom property, the value must contain a var() function + const mustContainVar = !decl.variable; + + const newConditions = conditionsFromValue(decl, mustContainVar); + if (!newConditions.length) { + return; + } + + conditions.push(...newConditions); + decl.remove(); + }); + + if (!conditions.length) { + return; + } + + const supportParams = Array.from(new Set(conditions)).sort().join(' and '); + if (!supportParams) { + return; + } + + const supportsRule = postcss.atRule({ + name: 'supports', + params: supportParams, + source: atRule.source, + raws: { + before: '\n\n', + after: '\n', + }, + }); + + supportsRule.append(atRuleClone); + + atRule.after(supportsRule); + }); + root.walkDecls((decl) => { if (!decl.parent) { return; } + if (inKeyframes(decl)) { + return; + } + const state = states.get(decl.parent) || { conditionalRules: [], propNames: new Set(), - lastConditionParams: { - support: undefined, - }, + lastConditionParams: undefined, lastConditionalRule: undefined, }; @@ -82,7 +201,11 @@ const creator: PluginCreator = () => { } } - if (!(decl.variable || HAS_VARIABLE_FUNCTION_REGEX.test(decl.value))) { + if ( + !decl.variable && + !(decl.parent.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) && + !HAS_VARIABLE_FUNCTION_REGEX.test(decl.value) + ) { return; } @@ -97,15 +220,15 @@ const creator: PluginCreator = () => { } // if the property itself isn't a custom property, the value must contain a var() function - const mustContainVar = !decl.variable; + const mustContainVar = !decl.variable && !(decl.parent.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)); const conditions = conditionsFromValue(decl, mustContainVar); - const supportParams = conditions.support.join(' and '); + const supportParams = conditions.join(' and '); if (!supportParams) { return; } - if (state.lastConditionParams.support !== supportParams) { + if (state.lastConditionParams !== supportParams) { state.lastConditionalRule = undefined; } @@ -151,7 +274,7 @@ const creator: PluginCreator = () => { cloneDeclarations(parentClone, decl); decl.remove(); - state.lastConditionParams.support = supportParams; + state.lastConditionParams = supportParams; state.lastConditionalRule = parentClone; innerAtRule.append(parentClone); diff --git a/plugins/postcss-progressive-custom-properties/src/matchers.ts b/plugins/postcss-progressive-custom-properties/src/matchers.ts index 21b1e6a16d..31d11f9b75 100644 --- a/plugins/postcss-progressive-custom-properties/src/matchers.ts +++ b/plugins/postcss-progressive-custom-properties/src/matchers.ts @@ -3396,6 +3396,90 @@ export const matchers = [ } ] }, + { + "supports": "1vi", + "property": "width", + "sniff": "vi", + "matchers": [ + { + "type": "word", + "value": "1vi", + "dimension": { + "unit": "vi" + } + } + ] + }, + { + "supports": "1vi", + "property": "width", + "sniff": "svi", + "matchers": [ + { + "type": "word", + "value": "1svi", + "dimension": { + "unit": "svi" + } + } + ] + }, + { + "supports": "1vi", + "property": "width", + "sniff": "lvi", + "matchers": [ + { + "type": "word", + "value": "1lvi", + "dimension": { + "unit": "lvi" + } + } + ] + }, + { + "supports": "1vi", + "property": "width", + "sniff": "vb", + "matchers": [ + { + "type": "word", + "value": "1vb", + "dimension": { + "unit": "vb" + } + } + ] + }, + { + "supports": "1vi", + "property": "width", + "sniff": "svb", + "matchers": [ + { + "type": "word", + "value": "1svb", + "dimension": { + "unit": "svb" + } + } + ] + }, + { + "supports": "1vi", + "property": "width", + "sniff": "lvb", + "matchers": [ + { + "type": "word", + "value": "1lvb", + "dimension": { + "unit": "lvb" + } + } + ] + }, { "supports": "\"a\" / \"a\"", "property": "content", diff --git a/plugins/postcss-progressive-custom-properties/test/basic.css b/plugins/postcss-progressive-custom-properties/test/basic.css index f2057b7f59..1d7eacf480 100644 --- a/plugins/postcss-progressive-custom-properties/test/basic.css +++ b/plugins/postcss-progressive-custom-properties/test/basic.css @@ -312,3 +312,70 @@ background: image(var(--green)); background-size: 100px; } + +.triple-declarations { + --alpha: red; + --alpha: color(srgb 1 0 0); + --alpha: oklch(50% 50% 0); +} + +@property --foo { + inherits: false; + initial-value: green; + initial-value: image(green) oklch(0 0 0); +} + +@keyframes --foo { + to { + background: var(--green); + background: image(var(--green)); + color: green; + color: oklch(var(--foo) 0 0); + width: 10px; + } +} + +@keyframes --bar { + from { + --alpha: green; + } + 50% { + --alpha: green; + --alpha: orange; + } + 75% { + --alpha: color(srgb 1 0 0); + } + to { + --alpha: red; + --alpha: color(srgb 1 0 0); + } + +} + +@keyframes --triple { + to { + --alpha: red; + --alpha: color(srgb 1 0 0); + --alpha: oklch(50% 50% 0); + } +} + +.logical-units { + --prop-1: 1px; + --prop-1: 2vi; + --prop-2: 1px; + --prop-2: 2via; + --prop-3: 1px; + --prop-3: 2vi(1); + --prop-4: 1px; + --prop-4: 2svi; + --prop-5: 1px; + --prop-5: 2lvi; + --prop-6: 1px; + --prop-6: 2vb; + --prop-7: 1px; + --prop-7: 2svb; + --prop-8: 1px; + --prop-8: 2lvb; +} diff --git a/plugins/postcss-progressive-custom-properties/test/basic.expect.css b/plugins/postcss-progressive-custom-properties/test/basic.expect.css index 81fca81b1e..acea08c616 100644 --- a/plugins/postcss-progressive-custom-properties/test/basic.expect.css +++ b/plugins/postcss-progressive-custom-properties/test/basic.expect.css @@ -558,3 +558,130 @@ background-size: 100px; } } + +.triple-declarations { + --alpha: red; +} + +@supports (color: color(display-p3 0 0 0%)) { +.triple-declarations { + --alpha: color(srgb 1 0 0); +} +} + +@supports (color: oklab(0% 0 0%)) { +.triple-declarations { + --alpha: oklch(50% 50% 0); +} +} + +@property --foo { + inherits: false; + initial-value: green; +} + +@supports (background-image: image(red)) and (color: oklab(0% 0 0%)) { +@property --foo { + inherits: false; + initial-value: image(green) oklch(0 0 0); +} +} + +@keyframes --foo { + to { + background: var(--green); + color: green; + width: 10px; + } +} + +@supports (background-image: image(red)) and (color: oklab(0% 0 0%)) { + +@keyframes --foo { + to { + background: var(--green); + background: image(var(--green)); + color: green; + color: oklch(var(--foo) 0 0); + width: 10px; + } +} +} + +@keyframes --bar { + from { + --alpha: green; + } + 50% { + --alpha: green; + --alpha: orange; + } + 75% { + } + to { + --alpha: red; + } + +} + +@supports (color: color(display-p3 0 0 0%)) { + +@keyframes --bar { + from { + --alpha: green; + } + 50% { + --alpha: green; + --alpha: orange; + } + 75% { + --alpha: color(srgb 1 0 0); + } + to { + --alpha: red; + --alpha: color(srgb 1 0 0); + } + +} +} + +@keyframes --triple { + to { + --alpha: red; + } +} + +@supports (color: color(display-p3 0 0 0%)) and (color: oklab(0% 0 0%)) { + +@keyframes --triple { + to { + --alpha: red; + --alpha: color(srgb 1 0 0); + --alpha: oklch(50% 50% 0); + } +} +} + +.logical-units { + --prop-1: 1px; + --prop-2: 1px; + --prop-2: 2via; + --prop-3: 1px; + --prop-3: 2vi(1); + --prop-4: 1px; + --prop-5: 1px; + --prop-6: 1px; + --prop-7: 1px; + --prop-8: 1px; +} + +@supports (width: 1vi) { +.logical-units { + --prop-1: 2vi; + --prop-4: 2svi; + --prop-5: 2lvi; + --prop-6: 2vb; + --prop-7: 2svb; + --prop-8: 2lvb; +} +} diff --git a/plugins/postcss-random-function/CHANGELOG.md b/plugins/postcss-random-function/CHANGELOG.md index 0e6a80647a..f9e4c4e0e8 100644 --- a/plugins/postcss-random-function/CHANGELOG.md +++ b/plugins/postcss-random-function/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Random Function +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 4.0.0 _July 22, 2026_ diff --git a/plugins/postcss-random-function/dist/index.mjs b/plugins/postcss-random-function/dist/index.mjs index 783390fa03..2722d0f9c9 100644 --- a/plugins/postcss-random-function/dist/index.mjs +++ b/plugins/postcss-random-function/dist/index.mjs @@ -1 +1 @@ -import{calc as e}from"@csstools/css-calc";const o=String.fromCodePoint(0);function randomCacheKeyFromPostcssDeclaration(e){let r="",t=e.parent;for(;t;){switch(t.type){case"rule":r+=o+"selector"+o+t.selector+o;break;case"atrule":"scope"===t.name&&(r+=o+"prelude"+o+t.params+o)}t=t.parent}return{propertyName:e.prop,propertyN:0,elementID:r,documentID:e.source?.input.css??e.root().toString()}}const r=/(?{const t=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-random-function",Declaration(o){if(!r.test(o.value))return;const s=e(o.value,{precision:5,toCanonicalUnits:!0,randomCaching:randomCacheKeyFromPostcssDeclaration(o)});s!==o.value&&(o.cloneBefore({value:s}),t.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{calc as e}from"@csstools/css-calc";const r=String.fromCodePoint(0);function randomCacheKeyFromPostcssDeclaration(e){let t="",o=e.parent;for(;o;){switch(o.type){case"rule":t+=r+"selector"+r+o.selector+r;break;case"atrule":"scope"===o.name&&(t+=r+"prelude"+r+o.params+r)}o=o.parent}return{propertyName:e.prop,propertyN:0,elementID:t,documentID:e.source?.input.css??e.root().toString()}}const t=/(?{const s=Object.assign({preserve:!1},r);return{postcssPlugin:"postcss-random-function",Declaration(r){if(!t.test(r.value))return;if(s.preserve&&"atrule"===r.parent?.type&&o.test(r.parent.name))return;const n=e(r.value,{precision:5,toCanonicalUnits:!0,randomCaching:randomCacheKeyFromPostcssDeclaration(r)});n!==r.value&&(r.cloneBefore({value:n}),s.preserve||r.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-random-function/src/index.ts b/plugins/postcss-random-function/src/index.ts index c0acf210a1..553718debe 100644 --- a/plugins/postcss-random-function/src/index.ts +++ b/plugins/postcss-random-function/src/index.ts @@ -9,6 +9,7 @@ export type pluginOptions = { }; const FUNCTION_CALL_REGEX = /(? = (opts?: pluginOptions) => { const options: pluginOptions = Object.assign( @@ -27,6 +28,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + const modifiedValue = calc(decl.value, { precision: 5, toCanonicalUnits: true, diff --git a/plugins/postcss-random-function/test/basic.css b/plugins/postcss-random-function/test/basic.css index 1ef6abed20..ea80ea6e11 100644 --- a/plugins/postcss-random-function/test/basic.css +++ b/plugins/postcss-random-function/test/basic.css @@ -99,3 +99,14 @@ .ignore-3 { width: random(0, 10px); } + +@property --foo { + inherits: false; + initial-value: random(0, 10); +} + +@keyframes --foo { + to { + --foo: random(0, 10); + } +} diff --git a/plugins/postcss-random-function/test/basic.expect.css b/plugins/postcss-random-function/test/basic.expect.css index 2338c772ed..398b1798ca 100644 --- a/plugins/postcss-random-function/test/basic.expect.css +++ b/plugins/postcss-random-function/test/basic.expect.css @@ -1,5 +1,5 @@ .random-1 { - z-index: 9.34135; + z-index: 2.09594; } .random-2 { @@ -7,15 +7,15 @@ } .random-3 { - z-index: 2.87044; + z-index: 0.56703; } .random-4 { - z-index: 9.07747; + z-index: 6.78979; } .random-11 { - width: 9.34135px; + width: 2.09594px; } .random-12 { @@ -23,68 +23,68 @@ } .random-13 { - width: 2.87044px; + width: 0.56703px; } .random-14 { - width: 9.07747px; + width: 6.78979px; } .random-15 { padding: 5px 5px; - margin: 9.34135px 9.34135px; - inset: 2.87044px 2.87044px; - border-top-right-radius: 9.34135px; - border-top-left-radius: 9.34135px; - border-bottom-right-radius: 2.87044px; - border-bottom-left-radius: 2.87044px; + margin: 2.09594px 2.09594px; + inset: 0.56703px 0.56703px; + border-top-right-radius: 2.09594px; + border-top-left-radius: 2.09594px; + border-bottom-right-radius: 0.56703px; + border-bottom-left-radius: 0.56703px; } .random-15 { padding: 5px 5px; - margin: 9.34135px 9.34135px; - inset: 2.87044px 2.87044px; - border-top-right-radius: 9.34135px; - border-top-left-radius: 9.34135px; - border-bottom-right-radius: 2.87044px; - border-bottom-left-radius: 2.87044px; + margin: 2.09594px 2.09594px; + inset: 0.56703px 0.56703px; + border-top-right-radius: 2.09594px; + border-top-left-radius: 2.09594px; + border-bottom-right-radius: 0.56703px; + border-bottom-left-radius: 0.56703px; } .random-15-b { padding: 5px 5px; - margin: 9.34135px 9.34135px; - inset: 2.87044px 2.87044px; - border-top-right-radius: 9.34135px; - border-top-left-radius: 9.34135px; - border-bottom-right-radius: 2.87044px; - border-bottom-left-radius: 2.87044px; + margin: 2.09594px 2.09594px; + inset: 0.56703px 0.56703px; + border-top-right-radius: 2.09594px; + border-top-left-radius: 2.09594px; + border-bottom-right-radius: 0.56703px; + border-bottom-left-radius: 0.56703px; } .random-16 { - margin: 5.0658px 5.0658px; - inset: 1.28471px 1.28471px; - border-top-right-radius: 5.0658px; - border-top-left-radius: 5.0658px; - border-bottom-right-radius: 1.28471px; - border-bottom-left-radius: 1.28471px; + margin: 2.90875px 2.90875px; + inset: 4.37511px 4.37511px; + border-top-right-radius: 2.90875px; + border-top-left-radius: 2.90875px; + border-bottom-right-radius: 4.37511px; + border-bottom-left-radius: 4.37511px; } .random-16 { - margin: 5.0658px 5.0658px; - inset: 1.28471px 1.28471px; - border-top-right-radius: 5.0658px; - border-top-left-radius: 5.0658px; - border-bottom-right-radius: 1.28471px; - border-bottom-left-radius: 1.28471px; + margin: 2.90875px 2.90875px; + inset: 4.37511px 4.37511px; + border-top-right-radius: 2.90875px; + border-top-left-radius: 2.90875px; + border-bottom-right-radius: 4.37511px; + border-bottom-left-radius: 4.37511px; } .random-16-b { - margin: 6.36903px 6.36903px; - inset: 4.64922px 4.64922px; - border-top-right-radius: 6.36903px; - border-top-left-radius: 6.36903px; - border-bottom-right-radius: 4.64922px; - border-bottom-left-radius: 4.64922px; + margin: 5.45597px 5.45597px; + inset: 7.17757px 7.17757px; + border-top-right-radius: 5.45597px; + border-top-left-radius: 5.45597px; + border-bottom-right-radius: 7.17757px; + border-bottom-left-radius: 7.17757px; } .ignore-1 { @@ -99,3 +99,14 @@ .ignore-3 { width: random(0, 10px); } + +@property --foo { + inherits: false; + initial-value: 2.09594; +} + +@keyframes --foo { + to { + --foo: 2.09594; + } +} diff --git a/plugins/postcss-random-function/test/basic.preserve-true.expect.css b/plugins/postcss-random-function/test/basic.preserve-true.expect.css index 41579f6c9a..bcc3d9384e 100644 --- a/plugins/postcss-random-function/test/basic.preserve-true.expect.css +++ b/plugins/postcss-random-function/test/basic.preserve-true.expect.css @@ -1,5 +1,5 @@ .random-1 { - z-index: 9.34135; + z-index: 2.09594; z-index: random(0, 10); } @@ -8,17 +8,17 @@ } .random-3 { - z-index: 2.87044; + z-index: 0.56703; z-index: random(--foo, 0, 10); } .random-4 { - z-index: 9.07747; + z-index: 6.78979; z-index: random(--bar, 0, 10); } .random-11 { - width: 9.34135px; + width: 2.09594px; width: random(0px, 10px); } @@ -27,108 +27,108 @@ } .random-13 { - width: 2.87044px; + width: 0.56703px; width: random(--foo, 0px, 10px); } .random-14 { - width: 9.07747px; + width: 6.78979px; width: random(--bar, 0px, 10px); } .random-15 { padding: 5px 5px; padding: random(fixed 0.5, 0px, 10px) random(fixed 0.5, 0px, 10px); - margin: 9.34135px 9.34135px; + margin: 2.09594px 2.09594px; margin: random(0px, 10px) random(0px, 10px); - inset: 2.87044px 2.87044px; + inset: 0.56703px 0.56703px; inset: random(--foo, 0px, 10px) random(--foo, 0px, 10px); - border-top-right-radius: 9.34135px; + border-top-right-radius: 2.09594px; border-top-right-radius: random(0px, 10px); - border-top-left-radius: 9.34135px; + border-top-left-radius: 2.09594px; border-top-left-radius: random(0px, 10px); - border-bottom-right-radius: 2.87044px; + border-bottom-right-radius: 0.56703px; border-bottom-right-radius: random(--foo, 0px, 10px); - border-bottom-left-radius: 2.87044px; + border-bottom-left-radius: 0.56703px; border-bottom-left-radius: random(--foo, 0px, 10px); } .random-15 { padding: 5px 5px; padding: random(fixed 0.5, 0px, 10px) random(fixed 0.5, 0px, 10px); - margin: 9.34135px 9.34135px; + margin: 2.09594px 2.09594px; margin: random(0px, 10px) random(0px, 10px); - inset: 2.87044px 2.87044px; + inset: 0.56703px 0.56703px; inset: random(--foo, 0px, 10px) random(--foo, 0px, 10px); - border-top-right-radius: 9.34135px; + border-top-right-radius: 2.09594px; border-top-right-radius: random(0px, 10px); - border-top-left-radius: 9.34135px; + border-top-left-radius: 2.09594px; border-top-left-radius: random(0px, 10px); - border-bottom-right-radius: 2.87044px; + border-bottom-right-radius: 0.56703px; border-bottom-right-radius: random(--foo, 0px, 10px); - border-bottom-left-radius: 2.87044px; + border-bottom-left-radius: 0.56703px; border-bottom-left-radius: random(--foo, 0px, 10px); } .random-15-b { padding: 5px 5px; padding: random(fixed 0.5, 0px, 10px) random(fixed 0.5, 0px, 10px); - margin: 9.34135px 9.34135px; + margin: 2.09594px 2.09594px; margin: random(0px, 10px) random(0px, 10px); - inset: 2.87044px 2.87044px; + inset: 0.56703px 0.56703px; inset: random(--foo, 0px, 10px) random(--foo, 0px, 10px); - border-top-right-radius: 9.34135px; + border-top-right-radius: 2.09594px; border-top-right-radius: random(0px, 10px); - border-top-left-radius: 9.34135px; + border-top-left-radius: 2.09594px; border-top-left-radius: random(0px, 10px); - border-bottom-right-radius: 2.87044px; + border-bottom-right-radius: 0.56703px; border-bottom-right-radius: random(--foo, 0px, 10px); - border-bottom-left-radius: 2.87044px; + border-bottom-left-radius: 0.56703px; border-bottom-left-radius: random(--foo, 0px, 10px); } .random-16 { - margin: 5.0658px 5.0658px; + margin: 2.90875px 2.90875px; margin: random(element-scoped, 0px, 10px) random(element-scoped, 0px, 10px); - inset: 1.28471px 1.28471px; + inset: 4.37511px 4.37511px; inset: random(--foo element-scoped, 0px, 10px) random(--foo element-scoped, 0px, 10px); - border-top-right-radius: 5.0658px; + border-top-right-radius: 2.90875px; border-top-right-radius: random(element-scoped, 0px, 10px); - border-top-left-radius: 5.0658px; + border-top-left-radius: 2.90875px; border-top-left-radius: random(element-scoped, 0px, 10px); - border-bottom-right-radius: 1.28471px; + border-bottom-right-radius: 4.37511px; border-bottom-right-radius: random(--foo element-scoped, 0px, 10px); - border-bottom-left-radius: 1.28471px; + border-bottom-left-radius: 4.37511px; border-bottom-left-radius: random(--foo element-scoped, 0px, 10px); } .random-16 { - margin: 5.0658px 5.0658px; + margin: 2.90875px 2.90875px; margin: random(element-scoped, 0px, 10px) random(element-scoped, 0px, 10px); - inset: 1.28471px 1.28471px; + inset: 4.37511px 4.37511px; inset: random(--foo element-scoped, 0px, 10px) random(--foo element-scoped, 0px, 10px); - border-top-right-radius: 5.0658px; + border-top-right-radius: 2.90875px; border-top-right-radius: random(element-scoped, 0px, 10px); - border-top-left-radius: 5.0658px; + border-top-left-radius: 2.90875px; border-top-left-radius: random(element-scoped, 0px, 10px); - border-bottom-right-radius: 1.28471px; + border-bottom-right-radius: 4.37511px; border-bottom-right-radius: random(--foo element-scoped, 0px, 10px); - border-bottom-left-radius: 1.28471px; + border-bottom-left-radius: 4.37511px; border-bottom-left-radius: random(--foo element-scoped, 0px, 10px); } .random-16-b { - margin: 6.36903px 6.36903px; + margin: 5.45597px 5.45597px; margin: random(element-scoped, 0px, 10px) random(element-scoped, 0px, 10px); - inset: 4.64922px 4.64922px; + inset: 7.17757px 7.17757px; inset: random(--foo element-scoped, 0px, 10px) random(--foo element-scoped, 0px, 10px); - border-top-right-radius: 6.36903px; + border-top-right-radius: 5.45597px; border-top-right-radius: random(element-scoped, 0px, 10px); - border-top-left-radius: 6.36903px; + border-top-left-radius: 5.45597px; border-top-left-radius: random(element-scoped, 0px, 10px); - border-bottom-right-radius: 4.64922px; + border-bottom-right-radius: 7.17757px; border-bottom-right-radius: random(--foo element-scoped, 0px, 10px); - border-bottom-left-radius: 4.64922px; + border-bottom-left-radius: 7.17757px; border-bottom-left-radius: random(--foo element-scoped, 0px, 10px); } @@ -144,3 +144,15 @@ .ignore-3 { width: random(0, 10px); } + +@property --foo { + inherits: false; + initial-value: random(0, 10); +} + +@keyframes --foo { + to { + --foo: 2.09594; + --foo: random(0, 10); + } +} diff --git a/plugins/postcss-relative-color-syntax/test/basic.css b/plugins/postcss-relative-color-syntax/test/basic.css index 5d0d8776e6..9ee349b801 100644 --- a/plugins/postcss-relative-color-syntax/test/basic.css +++ b/plugins/postcss-relative-color-syntax/test/basic.css @@ -112,3 +112,14 @@ .experimental-features-from-the-color-parser { color: hsla(from contrast-color(pink) h s l / alpha); } + +@property --foo { + inherits: false; + initial-value: hsla(from blue h s l / alpha); +} + +@keyframes --foo { + to { + --foo: hsla(from blue h s l / alpha); + } +} diff --git a/plugins/postcss-relative-color-syntax/test/basic.expect.css b/plugins/postcss-relative-color-syntax/test/basic.expect.css index be819329c3..19a3cd7c0a 100644 --- a/plugins/postcss-relative-color-syntax/test/basic.expect.css +++ b/plugins/postcss-relative-color-syntax/test/basic.expect.css @@ -122,3 +122,14 @@ .experimental-features-from-the-color-parser { color: hsla(from contrast-color(pink) h s l / alpha); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 0, 255); +} + +@keyframes --foo { + to { + --foo: rgb(0, 0, 255); + } +} diff --git a/plugins/postcss-relative-color-syntax/test/basic.preserve-true.expect.css b/plugins/postcss-relative-color-syntax/test/basic.preserve-true.expect.css index c7d29ab568..3daab7ae16 100644 --- a/plugins/postcss-relative-color-syntax/test/basic.preserve-true.expect.css +++ b/plugins/postcss-relative-color-syntax/test/basic.preserve-true.expect.css @@ -215,3 +215,31 @@ .experimental-features-from-the-color-parser { color: hsla(from contrast-color(pink) h s l / alpha); } + +@property --foo { + inherits: false; + initial-value: rgb(0, 0, 255); +} + +@supports (color: lab(from red l 1 1% / calc(alpha + 0.1))) { +@property --foo { + inherits: false; + initial-value: hsla(from blue h s l / alpha); +} +} + +@keyframes --foo { + to { + --foo: rgb(0, 0, 255); + } +} + +@supports (color: lab(from red l 1 1% / calc(alpha + 0.1))) { + +@keyframes --foo { + to { + --foo: rgb(0, 0, 255); + --foo: hsla(from blue h s l / alpha); + } +} +} diff --git a/plugins/postcss-sign-functions/CHANGELOG.md b/plugins/postcss-sign-functions/CHANGELOG.md index b89c9c3c15..ecf519b827 100644 --- a/plugins/postcss-sign-functions/CHANGELOG.md +++ b/plugins/postcss-sign-functions/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Sign Functions +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 2.0.4 _July 22, 2026_ diff --git a/plugins/postcss-sign-functions/dist/index.mjs b/plugins/postcss-sign-functions/dist/index.mjs index 2935435377..efc1953f4c 100644 --- a/plugins/postcss-sign-functions/dist/index.mjs +++ b/plugins/postcss-sign-functions/dist/index.mjs @@ -1 +1 @@ -import{calcFromComponentValues as e}from"@csstools/css-calc";import{tokenize as s,TokenType as o,NumberType as n}from"@csstools/css-tokenizer";import{replaceComponentValues as t,parseCommaSeparatedListOfComponentValues as a,stringify as r,isFunctionNode as i,FunctionNode as c,SimpleBlockNode as l,TokenNode as p,WhitespaceNode as u,parseListOfComponentValues as v}from"@csstools/css-parser-algorithms";const m=/(?{const n=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-sign-functions",Declaration(o){if(!m.test(o.value))return;let i;i=f.test(o.value)?t(a(s({css:o.value})),replacer):a(s({css:o.value}));const c=r(e(i,{precision:5,toCanonicalUnits:!0}));c!==o.value&&(o.cloneBefore({value:c}),n.preserve||o.remove())}}};function replacer(e){if(!i(e))return;if("abs"!==e.getName().toLowerCase())return;const[s]=t([e.value],replacer);return[new c([o.Function,"max(",-1,-1,{value:"max"}],[o.CloseParen,")",-1,-1,void 0],[new l([o.OpenParen,"(",-1,-1,void 0],[o.CloseParen,")",-1,-1,void 0],v(s.flatMap(e=>e.tokens()))),new p([o.Comma,",",-1,-1,void 0]),new u([[o.Whitespace," ",-1,-1,void 0]]),new p([o.Number,"-1",-1,-1,{value:-1,type:n.Integer,signCharacter:"-"}]),new u([[o.Whitespace," ",-1,-1,void 0]]),new p([o.Delim,"*",-1,-1,{value:"*"}]),new u([[o.Whitespace," ",-1,-1,void 0]]),new l([o.OpenParen,"(",-1,-1,void 0],[o.CloseParen,")",-1,-1,void 0],v(s.flatMap(e=>e.tokens())))])]}creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{calcFromComponentValues as e}from"@csstools/css-calc";import{tokenize as s,TokenType as r,NumberType as t}from"@csstools/css-tokenizer";import{replaceComponentValues as o,parseCommaSeparatedListOfComponentValues as n,stringify as a,isFunctionNode as i,FunctionNode as c,SimpleBlockNode as l,TokenNode as p,WhitespaceNode as u,parseListOfComponentValues as v}from"@csstools/css-parser-algorithms";const m=/(?{const t=Object.assign({preserve:!1},r);return{postcssPlugin:"postcss-sign-functions",Declaration(r){if(!m.test(r.value))return;if(t.preserve&&"atrule"===r.parent?.type&&w.test(r.parent.name))return;let i;i=f.test(r.value)?o(n(s({css:r.value})),replacer):n(s({css:r.value}));const c=a(e(i,{precision:5,toCanonicalUnits:!0}));c!==r.value&&(r.cloneBefore({value:c}),t.preserve||r.remove())}}};function replacer(e){if(!i(e))return;if("abs"!==e.getName().toLowerCase())return;const[s]=o([e.value],replacer);return[new c([r.Function,"max(",-1,-1,{value:"max"}],[r.CloseParen,")",-1,-1,void 0],[new l([r.OpenParen,"(",-1,-1,void 0],[r.CloseParen,")",-1,-1,void 0],v(s.flatMap(e=>e.tokens()))),new p([r.Comma,",",-1,-1,void 0]),new u([[r.Whitespace," ",-1,-1,void 0]]),new p([r.Number,"-1",-1,-1,{value:-1,type:t.Integer,signCharacter:"-"}]),new u([[r.Whitespace," ",-1,-1,void 0]]),new p([r.Delim,"*",-1,-1,{value:"*"}]),new u([[r.Whitespace," ",-1,-1,void 0]]),new l([r.OpenParen,"(",-1,-1,void 0],[r.CloseParen,")",-1,-1,void 0],v(s.flatMap(e=>e.tokens())))])]}creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-sign-functions/src/index.ts b/plugins/postcss-sign-functions/src/index.ts index 2a6a1cc324..3521ed6f30 100644 --- a/plugins/postcss-sign-functions/src/index.ts +++ b/plugins/postcss-sign-functions/src/index.ts @@ -12,6 +12,7 @@ export type pluginOptions = { const FUNCTION_CALL_REGEX = /(? = (opts?: pluginOptions) => { const options: pluginOptions = Object.assign( @@ -30,6 +31,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + let componentValues: Array>; if (ABS_CALL_REGEX.test(decl.value)) { componentValues = replaceComponentValues( diff --git a/plugins/postcss-sign-functions/test/basic.css b/plugins/postcss-sign-functions/test/basic.css index e0d626d331..12d94cfc3e 100644 --- a/plugins/postcss-sign-functions/test/basic.css +++ b/plugins/postcss-sign-functions/test/basic.css @@ -69,3 +69,14 @@ --foo: 10px; z-index: sign(var(--foo)); } + +@property --foo { + inherits: false; + initial-value: sign(10px); +} + +@keyframes --foo { + to { + --foo: sign(10px); + } +} diff --git a/plugins/postcss-sign-functions/test/basic.expect.css b/plugins/postcss-sign-functions/test/basic.expect.css index 2582d04039..991453db01 100644 --- a/plugins/postcss-sign-functions/test/basic.expect.css +++ b/plugins/postcss-sign-functions/test/basic.expect.css @@ -69,3 +69,14 @@ --foo: 10px; z-index: sign(var(--foo)); } + +@property --foo { + inherits: false; + initial-value: 1; +} + +@keyframes --foo { + to { + --foo: 1; + } +} diff --git a/plugins/postcss-sign-functions/test/basic.preserve-true.expect.css b/plugins/postcss-sign-functions/test/basic.preserve-true.expect.css index c9e05ecc82..626174e836 100644 --- a/plugins/postcss-sign-functions/test/basic.preserve-true.expect.css +++ b/plugins/postcss-sign-functions/test/basic.preserve-true.expect.css @@ -85,3 +85,15 @@ --foo: 10px; z-index: sign(var(--foo)); } + +@property --foo { + inherits: false; + initial-value: sign(10px); +} + +@keyframes --foo { + to { + --foo: 1; + --foo: sign(10px); + } +} diff --git a/plugins/postcss-stepped-value-functions/CHANGELOG.md b/plugins/postcss-stepped-value-functions/CHANGELOG.md index 1f639ab41a..79f7f1528a 100644 --- a/plugins/postcss-stepped-value-functions/CHANGELOG.md +++ b/plugins/postcss-stepped-value-functions/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Stepped Value Functions +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 5.0.4 _July 22, 2026_ diff --git a/plugins/postcss-stepped-value-functions/dist/index.mjs b/plugins/postcss-stepped-value-functions/dist/index.mjs index 39d996dc8a..abdaf76c7e 100644 --- a/plugins/postcss-stepped-value-functions/dist/index.mjs +++ b/plugins/postcss-stepped-value-functions/dist/index.mjs @@ -1 +1 @@ -import{calc as e}from"@csstools/css-calc";const s=/(?{const t=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-stepped-value-functions",Declaration(o){if(!s.test(o.value))return;const r=e(o.value,{precision:5,toCanonicalUnits:!0});r!==o.value&&(o.cloneBefore({value:r}),t.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{calc as e}from"@csstools/css-calc";const s=/(?{const o=Object.assign({preserve:!1},r);return{postcssPlugin:"postcss-stepped-value-functions",Declaration(r){if(!s.test(r.value))return;if(o.preserve&&"atrule"===r.parent?.type&&t.test(r.parent.name))return;const n=e(r.value,{precision:5,toCanonicalUnits:!0});n!==r.value&&(r.cloneBefore({value:n}),o.preserve||r.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-stepped-value-functions/src/index.ts b/plugins/postcss-stepped-value-functions/src/index.ts index 4be02310f5..561b57116f 100644 --- a/plugins/postcss-stepped-value-functions/src/index.ts +++ b/plugins/postcss-stepped-value-functions/src/index.ts @@ -8,6 +8,7 @@ export type pluginOptions = { }; const FUNCTION_CALL_REGEX = /(? = (opts?: pluginOptions) => { const options: pluginOptions = Object.assign( @@ -26,6 +27,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + const modifiedValue = calc(decl.value, { precision: 5, toCanonicalUnits: true, diff --git a/plugins/postcss-stepped-value-functions/test/basic.css b/plugins/postcss-stepped-value-functions/test/basic.css index 53226b9596..a306a210ce 100644 --- a/plugins/postcss-stepped-value-functions/test/basic.css +++ b/plugins/postcss-stepped-value-functions/test/basic.css @@ -67,3 +67,14 @@ font-size: round(1px); color: color-mod(calc(1 + 1), 1); } + +@property --foo { + inherits: false; + initial-value: mod(-140deg, -90deg); +} + +@keyframes --foo { + to { + --foo: mod(-140deg, -90deg); + } +} diff --git a/plugins/postcss-stepped-value-functions/test/basic.expect.css b/plugins/postcss-stepped-value-functions/test/basic.expect.css index 084ec49fc5..0afccdda35 100644 --- a/plugins/postcss-stepped-value-functions/test/basic.expect.css +++ b/plugins/postcss-stepped-value-functions/test/basic.expect.css @@ -67,3 +67,14 @@ font-size: round(1px); color: color-mod(calc(1 + 1), 1); } + +@property --foo { + inherits: false; + initial-value: -50deg; +} + +@keyframes --foo { + to { + --foo: -50deg; + } +} diff --git a/plugins/postcss-stepped-value-functions/test/basic.preserve-true.expect.css b/plugins/postcss-stepped-value-functions/test/basic.preserve-true.expect.css index f927eef278..312bb04e53 100644 --- a/plugins/postcss-stepped-value-functions/test/basic.preserve-true.expect.css +++ b/plugins/postcss-stepped-value-functions/test/basic.preserve-true.expect.css @@ -95,3 +95,15 @@ font-size: round(1px); color: color-mod(calc(1 + 1), 1); } + +@property --foo { + inherits: false; + initial-value: mod(-140deg, -90deg); +} + +@keyframes --foo { + to { + --foo: -50deg; + --foo: mod(-140deg, -90deg); + } +} diff --git a/plugins/postcss-trigonometric-functions/CHANGELOG.md b/plugins/postcss-trigonometric-functions/CHANGELOG.md index 9663f9ccb3..bedfa8b456 100644 --- a/plugins/postcss-trigonometric-functions/CHANGELOG.md +++ b/plugins/postcss-trigonometric-functions/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Trigonometric Functions +### Unreleased (patch) + +- Ignore `initial-value` in `@property` when preserving original values + ### 5.0.4 _July 22, 2026_ diff --git a/plugins/postcss-trigonometric-functions/dist/index.mjs b/plugins/postcss-trigonometric-functions/dist/index.mjs index 98e7a7e8e9..02781a25c8 100644 --- a/plugins/postcss-trigonometric-functions/dist/index.mjs +++ b/plugins/postcss-trigonometric-functions/dist/index.mjs @@ -1 +1 @@ -import{calc as s}from"@csstools/css-calc";const e=/(?{const t=Object.assign({preserve:!1},o);return{postcssPlugin:"postcss-trigonometric-functions",Declaration(o){if(!e.test(o.value))return;const n=s(o.value,{precision:5,toCanonicalUnits:!0});n!==o.value&&(o.cloneBefore({value:n}),t.preserve||o.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; +import{calc as e}from"@csstools/css-calc";const s=/(?{const o=Object.assign({preserve:!1},r);return{postcssPlugin:"postcss-trigonometric-functions",Declaration(r){if(!s.test(r.value))return;if(o.preserve&&"atrule"===r.parent?.type&&t.test(r.parent.name))return;const n=e(r.value,{precision:5,toCanonicalUnits:!0});n!==r.value&&(r.cloneBefore({value:n}),o.preserve||r.remove())}}};creator.postcss=!0;export{creator as default,creator as"module.exports"}; diff --git a/plugins/postcss-trigonometric-functions/src/index.ts b/plugins/postcss-trigonometric-functions/src/index.ts index a1a5edd058..a13b74293f 100644 --- a/plugins/postcss-trigonometric-functions/src/index.ts +++ b/plugins/postcss-trigonometric-functions/src/index.ts @@ -8,6 +8,7 @@ export type pluginOptions = { }; const FUNCTION_CALL_REGEX = /(? = (opts?: pluginOptions) => { const options: pluginOptions = Object.assign( @@ -26,6 +27,10 @@ const creator: PluginCreator = (opts?: pluginOptions) => { return; } + if (options.preserve && decl.parent?.type === 'atrule' && IS_PROPERTY_REGEX.test(decl.parent.name)) { + return; + } + const modifiedValue = calc(decl.value, { precision: 5, toCanonicalUnits: true, diff --git a/plugins/postcss-trigonometric-functions/test/basic.css b/plugins/postcss-trigonometric-functions/test/basic.css index 6c9232a95e..f497ab48dd 100644 --- a/plugins/postcss-trigonometric-functions/test/basic.css +++ b/plugins/postcss-trigonometric-functions/test/basic.css @@ -209,3 +209,14 @@ order: atan(); order: atan2(); } + +@property --foo { + inherits: false; + initial-value: sin(45deg); +} + +@keyframes --foo { + to { + --foo: sin(45deg); + } +} diff --git a/plugins/postcss-trigonometric-functions/test/basic.expect.css b/plugins/postcss-trigonometric-functions/test/basic.expect.css index 31b51a5065..8e15a4bda2 100644 --- a/plugins/postcss-trigonometric-functions/test/basic.expect.css +++ b/plugins/postcss-trigonometric-functions/test/basic.expect.css @@ -209,3 +209,14 @@ order: atan(); order: atan2(); } + +@property --foo { + inherits: false; + initial-value: 0.70711; +} + +@keyframes --foo { + to { + --foo: 0.70711; + } +} diff --git a/plugins/postcss-trigonometric-functions/test/basic.preserve-true.expect.css b/plugins/postcss-trigonometric-functions/test/basic.preserve-true.expect.css index 1184430246..8e6e710b6d 100644 --- a/plugins/postcss-trigonometric-functions/test/basic.preserve-true.expect.css +++ b/plugins/postcss-trigonometric-functions/test/basic.preserve-true.expect.css @@ -355,3 +355,15 @@ order: atan(); order: atan2(); } + +@property --foo { + inherits: false; + initial-value: sin(45deg); +} + +@keyframes --foo { + to { + --foo: 0.70711; + --foo: sin(45deg); + } +}