diff --git a/packages/postcss-logical-fallback/CHANGELOG.md b/packages/postcss-logical-fallback/CHANGELOG.md index 87e3269..77ac3aa 100644 --- a/packages/postcss-logical-fallback/CHANGELOG.md +++ b/packages/postcss-logical-fallback/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log - postcss-logical-fallback +## 1.1.0 +Remove CSS variables support + ## 1.0.3 Fix can't read filter of undefined diff --git a/packages/postcss-logical-fallback/README.md b/packages/postcss-logical-fallback/README.md index 51202a3..77fd2f1 100644 --- a/packages/postcss-logical-fallback/README.md +++ b/packages/postcss-logical-fallback/README.md @@ -30,6 +30,10 @@ Please note that the utility and functionality of this plugin may be limited whe **WARNING** Plugin is based on @supports at rule, so it has to be supported, see on [can i use](https://caniuse.com/css-featurequeries) +**WARNING** +Plugin doesn't migrates css properties with css variables due to impossibility of resolving how many values in css +variable and how to split them. + ## Usage **Step 1:** install plugin and postcss diff --git a/packages/postcss-logical-fallback/package.json b/packages/postcss-logical-fallback/package.json index 9926fc8..7ea831b 100644 --- a/packages/postcss-logical-fallback/package.json +++ b/packages/postcss-logical-fallback/package.json @@ -1,6 +1,6 @@ { "name": "postcss-logical-fallback", - "version": "1.0.3", + "version": "1.1.0", "description": "PostCSS plugin for logical fallback props", "main": "index.js", "files": [ diff --git a/packages/postcss-logical-fallback/src/decl-processors/inset-inline.ts b/packages/postcss-logical-fallback/src/decl-processors/inset-inline.ts index 620f091..fcdc51b 100644 --- a/packages/postcss-logical-fallback/src/decl-processors/inset-inline.ts +++ b/packages/postcss-logical-fallback/src/decl-processors/inset-inline.ts @@ -1,28 +1,33 @@ -import {Declaration} from "postcss"; -import {parseCssValue} from "../utils"; +import { Declaration } from 'postcss'; +import { parseCssValue } from '../utils'; +import { isCssVariable } from '../utils/is-css-variable'; const valueMap = { - ltr: { - start: 'left', - end: 'right' - }, - rtl: { - start: 'right', - end: 'left' - } -} + ltr: { + start: 'left', + end: 'right', + }, + rtl: { + start: 'right', + end: 'left', + }, +}; export const processor = (decl: Declaration, dir = 'ltr') => { - const [start, end = start] = parseCssValue(decl.value) + if (isCssVariable(decl.value)) { + return; + } - decl.cloneBefore({ - prop: valueMap[dir].start, - value: start - }) - decl.cloneBefore({ - prop: valueMap[dir].end, - value: end - }) + const [start, end = start] = parseCssValue(decl.value); - decl.remove() -} + decl.cloneBefore({ + prop: valueMap[dir].start, + value: start, + }); + decl.cloneBefore({ + prop: valueMap[dir].end, + value: end, + }); + + decl.remove(); +}; diff --git a/packages/postcss-logical-fallback/src/decl-processors/shorthand-processor.ts b/packages/postcss-logical-fallback/src/decl-processors/shorthand-processor.ts index 743d657..a0ce8c5 100644 --- a/packages/postcss-logical-fallback/src/decl-processors/shorthand-processor.ts +++ b/packages/postcss-logical-fallback/src/decl-processors/shorthand-processor.ts @@ -1,15 +1,21 @@ -import {Declaration} from "postcss"; -import {parseCssValue} from "../utils"; +import { Declaration } from 'postcss'; +import { parseCssValue } from '../utils'; +import { isCssVariable } from '../utils/is-css-variable'; + export const processor = (decl: Declaration) => { - const { prop, value } = decl - const [start, end = start] = parseCssValue(value) - decl.cloneBefore({ - prop: `${prop}-start`, - value: start, - }) - decl.cloneBefore({ - prop: `${prop}-end`, - value: end, - }) - decl.remove() -} + const { prop, value } = decl; + if (isCssVariable(value)) { + return; + } + + const [start, end = start] = parseCssValue(value); + decl.cloneBefore({ + prop: `${prop}-start`, + value: start, + }); + decl.cloneBefore({ + prop: `${prop}-end`, + value: end, + }); + decl.remove(); +}; diff --git a/packages/postcss-logical-fallback/src/index.ts b/packages/postcss-logical-fallback/src/index.ts index 3c881df..39c6516 100644 --- a/packages/postcss-logical-fallback/src/index.ts +++ b/packages/postcss-logical-fallback/src/index.ts @@ -1,155 +1,160 @@ -import {AtRule, Declaration, Root, Rule} from "postcss"; +import { AtRule, Declaration, Root, Rule } from 'postcss'; import { - cleanEmptyAtRules, - cleanEmptyRules, - isBorderDecl, - isDeclWithRtlFallback, - isFloatDecl, - isInsetDecl, - parseCssValue, - hasEmptyChildNodes, - isProcessed, - markProcessed, - markFallback -} from "./utils"; + cleanEmptyAtRules, + cleanEmptyRules, + isBorderDecl, + isDeclWithRtlFallback, + isFloatDecl, + isInsetDecl, + parseCssValue, + hasEmptyChildNodes, + isProcessed, + markProcessed, + markFallback, +} from './utils'; import { - borderRadiusProcessorPositioned, - floatProcessor, - insetBlockProcessorPositioned, - insetInlineProcessor, - insetInlineProcessorPositioned, - processor, - shorthandProcessor -} from "./decl-processors"; + borderRadiusProcessorPositioned, + floatProcessor, + insetBlockProcessorPositioned, + insetInlineProcessor, + insetInlineProcessorPositioned, + processor, + shorthandProcessor, +} from './decl-processors'; +import { isCssVariable } from './utils/is-css-variable'; /** * @type {import('postcss').PluginCreator} */ module.exports = () => { - // Work with options here - return { - postcssPlugin: 'postcss-logical-fallback', - async Once(root: Root, { AtRule }) { - const nodes = root.nodes.filter(i => !isProcessed(i) && i.type !== 'comment') - const supportsAtRules: AtRule[] = [] - - for (const check of [isInsetDecl, isBorderDecl, isFloatDecl]) { - const supports: AtRule = new AtRule({ - name: 'supports', - }) - - for (const node of nodes) { - const cloned = node.clone() - cloned.cleanRaws() - supports.append(cloned) - } - - let supportsParam = ''; - - // clean decls - supports.walkDecls(decl => { - if (!check(decl)) { - decl.remove() - } else { - if (!supportsParam) { - supportsParam = decl.toString() + // Work with options here + return { + postcssPlugin: 'postcss-logical-fallback', + async Once(root: Root, { AtRule }) { + const nodes = root.nodes.filter((i) => !isProcessed(i) && i.type !== 'comment'); + const supportsAtRules: AtRule[] = []; + + for (const check of [isInsetDecl, isBorderDecl, isFloatDecl]) { + const supports: AtRule = new AtRule({ + name: 'supports', + }); + + for (const node of nodes) { + const cloned = node.clone(); + cloned.cleanRaws(); + supports.append(cloned); + } + + let supportsParam = ''; + + // clean decls + supports.walkDecls((decl) => { + if (!check(decl) || isCssVariable(decl.value)) { + decl.remove(); + } else { + if (!supportsParam) { + supportsParam = decl.toString(); + } + markProcessed(decl); + } + }); + + supports.params = `(${supportsParam})`; + + cleanEmptyRules(supports); + cleanEmptyAtRules(supports); + + if (hasEmptyChildNodes(supports)) continue; + + supportsAtRules.push(supports); + supportsAtRules.push( + supports.clone({ + params: `not (${supportsParam})`, + }), + ); + + // clean decls + root.walkDecls((decl) => { + if (check(decl)) { + decl.remove(); + } + }); + + cleanEmptyRules(root); + cleanEmptyAtRules(root); } - markProcessed(decl) - } - }) - - supports.params = `(${supportsParam})` - - cleanEmptyRules(supports) - cleanEmptyAtRules(supports) - - if (hasEmptyChildNodes(supports)) continue - - supportsAtRules.push(supports) - supportsAtRules.push(supports.clone({ - params: `not (${supportsParam})` - })) - - // clean decls - root.walkDecls(decl => { - if (check(decl)) { - decl.remove() - } - }) - - cleanEmptyRules(root) - cleanEmptyAtRules(root) - } - - for (const supports of supportsAtRules) { - root.append(supports) - markProcessed(supports) - } - - }, - async Rule(rule: Rule) { - if (isProcessed(rule)) { - return - } - - if (rule.some(i => i.type === 'decl' && isDeclWithRtlFallback(i))) { - const cloned = rule.clone({ - selectors: rule.selectors.map(s => `[dir="rtl"] ${s}`) - }) - - cloned.walkDecls(decl => { - if (isDeclWithRtlFallback(decl)) { - const [start, end = start] = parseCssValue(decl.value) - const cloned = decl.clone({ - prop: decl.prop, - }) - - if (!(decl.prop === 'inset-inline' && start === end)) { - markFallback(cloned) - decl.parent?.insertBefore(decl, cloned) + + for (const supports of supportsAtRules) { + root.append(supports); + markProcessed(supports); + } + }, + async Rule(rule: Rule) { + if (isProcessed(rule)) { + return; + } + + if (rule.some((i) => i.type === 'decl' && isDeclWithRtlFallback(i))) { + const cloned = rule.clone({ + selectors: rule.selectors.map((s) => `[dir="rtl"] ${s}`), + }); + + cloned.walkDecls((decl) => { + if (isDeclWithRtlFallback(decl)) { + const [start, end = start] = parseCssValue(decl.value); + const cloned = decl.clone({ + prop: decl.prop, + }); + + if (!(decl.prop === 'inset-inline' && start === end)) { + markFallback(cloned); + decl.parent?.insertBefore(decl, cloned); + } + } + decl.remove(); + }); + + const insetInlineStart = cloned.nodes.find( + (i) => i.type === 'decl' && i.prop === 'inset-inline-start', + ) as Declaration | undefined; + const insetInlineEnd = cloned.nodes.find( + (i) => i.type === 'decl' && i.prop === 'inset-inline-end', + ) as Declaration | undefined; + + if (insetInlineStart && insetInlineEnd) { + insetInlineStart.cloneBefore({ + prop: 'inset-inline', + value: `${insetInlineEnd.value} ${insetInlineStart.value}`, + }); + insetInlineStart.remove(); + insetInlineEnd.remove(); + } + + if (!hasEmptyChildNodes(cloned)) { + rule.parent?.insertAfter(rule, cloned); + markProcessed(cloned); + } } - } - decl.remove() - }) - - const insetInlineStart = cloned.nodes.find(i => i.type === 'decl' && i.prop === 'inset-inline-start') as Declaration | undefined - const insetInlineEnd = cloned.nodes.find((i) => i.type === 'decl' && i.prop === 'inset-inline-end') as Declaration | undefined - - if (insetInlineStart && insetInlineEnd) { - insetInlineStart.cloneBefore( { - prop: 'inset-inline', - value: `${insetInlineEnd.value} ${insetInlineStart.value}` - }) - insetInlineStart.remove() - insetInlineEnd.remove() - } - - if (!hasEmptyChildNodes(cloned)) { - rule.parent?.insertAfter(rule, cloned) - markProcessed(cloned) - } - } - - }, - Declaration: { - 'padding-inline': processor(shorthandProcessor), - 'padding-block': processor(shorthandProcessor), - 'margin-inline': processor(shorthandProcessor), - 'margin-block': processor(shorthandProcessor), - 'inset-block-start': processor(insetBlockProcessorPositioned), - 'inset-block-end': processor(insetBlockProcessorPositioned), - 'inset-block': processor(shorthandProcessor), - 'inset-inline-start': processor(insetInlineProcessorPositioned), - 'inset-inline-end': processor(insetInlineProcessorPositioned), - 'inset-inline': processor(insetInlineProcessor), - clear: processor(floatProcessor), - float: processor(floatProcessor), - 'border-start-start-radius': processor(borderRadiusProcessorPositioned), - 'border-start-end-radius': processor(borderRadiusProcessorPositioned), - 'border-end-start-radius': processor(borderRadiusProcessorPositioned), - 'border-end-end-radius': processor(borderRadiusProcessorPositioned), - } - } -} - -module.exports.postcss = true + }, + Declaration: { + 'padding-inline': processor(shorthandProcessor), + 'padding-block': processor(shorthandProcessor), + 'margin-inline': processor(shorthandProcessor), + 'margin-block': processor(shorthandProcessor), + 'inset-block-start': processor(insetBlockProcessorPositioned), + 'inset-block-end': processor(insetBlockProcessorPositioned), + 'inset-block': processor(shorthandProcessor), + 'inset-inline-start': processor(insetInlineProcessorPositioned), + 'inset-inline-end': processor(insetInlineProcessorPositioned), + 'inset-inline': processor(insetInlineProcessor), + clear: processor(floatProcessor), + float: processor(floatProcessor), + 'border-start-start-radius': processor(borderRadiusProcessorPositioned), + 'border-start-end-radius': processor(borderRadiusProcessorPositioned), + 'border-end-start-radius': processor(borderRadiusProcessorPositioned), + 'border-end-end-radius': processor(borderRadiusProcessorPositioned), + }, + }; +}; + +module.exports.postcss = true; diff --git a/packages/postcss-logical-fallback/src/utils/is-css-variable.ts b/packages/postcss-logical-fallback/src/utils/is-css-variable.ts new file mode 100644 index 0000000..f1def02 --- /dev/null +++ b/packages/postcss-logical-fallback/src/utils/is-css-variable.ts @@ -0,0 +1 @@ +export const isCssVariable = (value: string): boolean => /var\(--[^)]+\)/.test(value); diff --git a/packages/postcss-logical-fallback/tests/no-changes.test.ts b/packages/postcss-logical-fallback/tests/no-changes.test.ts index 237746d..31d5ec4 100644 --- a/packages/postcss-logical-fallback/tests/no-changes.test.ts +++ b/packages/postcss-logical-fallback/tests/no-changes.test.ts @@ -35,4 +35,45 @@ test('should not copy comments', async () => { ); }); +test('should not fallback statements with variables', async () => { + await run( + ` + .class { + padding-inline: var(--some-variable); + } + `, + ` + .class { + padding-inline: var(--some-variable); + } + `, + ); + + await run( + ` + .class { + margin-block: var(--some-variable); + } + `, + ` + .class { + margin-block: var(--some-variable); + } + `, + ); + + await run( + ` + .class { + inset-inline: var(--some-variable); + } + `, + ` + .class { + inset-inline: var(--some-variable); + } + `, + ); +}); + test.run();