diff --git a/plugins/postcss-logical/src/index.js b/plugins/postcss-logical/src/index.js index 84c33c890..4d54192ba 100644 --- a/plugins/postcss-logical/src/index.js +++ b/plugins/postcss-logical/src/index.js @@ -10,6 +10,7 @@ import transformTextAlign from './lib/transform-text-align'; import transformTransition from './lib/transform-transition'; import { splitBySpace } from './lib/split'; import { hasKeyframesAtRuleAncestor } from './lib/has-keyframes-atrule-ancestor'; +import { resetCounter } from './lib/util/counter'; // plugin function postcssLogicalProperties(opts) { @@ -52,6 +53,9 @@ function postcssLogicalProperties(opts) { return { postcssPlugin: 'postcss-logical-properties', + Once: () => { + resetCounter(); + }, Declaration: { // Flow-Relative Values 'clear': makeTransform(transformFloat), diff --git a/plugins/postcss-logical/src/lib/clone-rule-for-variables.js b/plugins/postcss-logical/src/lib/clone-rule-for-variables.js new file mode 100644 index 000000000..cb80fe13e --- /dev/null +++ b/plugins/postcss-logical/src/lib/clone-rule-for-variables.js @@ -0,0 +1,11 @@ +import postcss from 'postcss'; + +export function cloneRuleAsDir(decl, dir) { + const rule = Object(decl.parent).type === 'rule' ? decl.parent.cloneBefore({ + raws: {}, + }).removeAll() : postcss.rule({ selector: '&' }); + + rule.assign({'selector': `:dir(${dir})`}); + + return rule; +} diff --git a/plugins/postcss-logical/src/lib/transform-float.js b/plugins/postcss-logical/src/lib/transform-float.js index ae81a8ecd..ef7fa8c35 100644 --- a/plugins/postcss-logical/src/lib/transform-float.js +++ b/plugins/postcss-logical/src/lib/transform-float.js @@ -1,4 +1,5 @@ -import cloneRule from './clone-rule'; +import { cloneRuleAsDir } from './clone-rule-for-variables'; +import { varId } from './util/counter'; export default (decl, values, dir, preserve) => { if (/^inline-start$/i.test(decl.value)) { @@ -11,12 +12,30 @@ export default (decl, values, dir, preserve) => { clean(decl, preserve); return; } else { - cloneRule(decl, 'ltr').append(lDecl(decl)); - cloneRule(decl, 'rtl').append(rDecl(decl)); + const id = varId(decl); + const dirLtr = cloneRuleAsDir(decl, 'ltr'); + const dirRtl = cloneRuleAsDir(decl, 'rtl'); + + const ltrClone = decl.clone(); + ltrClone.prop = `--logical-${id}`; + ltrClone.value = 'left'; + + dirLtr.append(ltrClone); + + const rtlClone = decl.clone(); + rtlClone.prop = `--logical-${id}`; + rtlClone.value = 'right'; + + dirRtl.append(rtlClone); + + decl.cloneBefore({ value: 'left' }); + decl.cloneBefore({ value: `var(--logical-${id})` }); clean(decl, preserve); return; } - } if (/^inline-end$/i.test(decl.value)) { + } + + if (/^inline-end$/i.test(decl.value)) { if (dir === 'ltr') { rDecl(decl); clean(decl, preserve); @@ -26,8 +45,24 @@ export default (decl, values, dir, preserve) => { clean(decl, preserve); return; } else { - cloneRule(decl, 'ltr').append(rDecl(decl)); - cloneRule(decl, 'rtl').append(lDecl(decl)); + const id = varId(decl); + const dirLtr = cloneRuleAsDir(decl, 'ltr'); + const dirRtl = cloneRuleAsDir(decl, 'rtl'); + + const ltrClone = decl.clone(); + ltrClone.prop = `--logical-${id}`; + ltrClone.value = 'right'; + + dirLtr.append(ltrClone); + + const rtlClone = decl.clone(); + rtlClone.prop = `--logical-${id}`; + rtlClone.value = 'left'; + + dirRtl.append(rtlClone); + + decl.cloneBefore({ value: 'right' }); + decl.cloneBefore({ value: `var(--logical-${id})` }); clean(decl, preserve); return; } diff --git a/plugins/postcss-logical/src/lib/util/counter.js b/plugins/postcss-logical/src/lib/util/counter.js new file mode 100644 index 000000000..f8172ea78 --- /dev/null +++ b/plugins/postcss-logical/src/lib/util/counter.js @@ -0,0 +1,23 @@ +import crypto from 'crypto'; + +let counter = 0; + +export function resetCounter() { + counter = 0; +} + +export function getCounter() { + counter++; + return counter; +} + +export function varId(node) { + let parent = node.parent; + + while (parent && parent.type !== 'root') { + parent = parent.parent; + } + + const hash = crypto.createHash('md5').update(parent.toString()).digest('hex'); + return `${hash.slice(0, 6)}-${getCounter()}`; +} diff --git a/plugins/postcss-logical/test/clear.expect.css b/plugins/postcss-logical/test/clear.expect.css index 43741d2c8..2b1505683 100644 --- a/plugins/postcss-logical/test/clear.expect.css +++ b/plugins/postcss-logical/test/clear.expect.css @@ -1,17 +1,21 @@ -test-clear:dir(ltr) { - clear: left; +:dir(ltr) { + --logical-55da70-1: left; } -test-clear:dir(rtl) { - clear: right; +:dir(rtl) { + --logical-55da70-1: right; } -test-clear:dir(ltr) { - clear: right; +:dir(ltr) { + --logical-63f1d9-2: right; } -test-clear:dir(rtl) { - clear: left; +:dir(rtl) { + --logical-63f1d9-2: left; } test-clear { clear: both; clear: left; + clear: left; + clear: var(--logical-55da70-1); + clear: right; + clear: var(--logical-63f1d9-2); clear: right; } diff --git a/plugins/postcss-logical/test/float.css b/plugins/postcss-logical/test/float.css index c6bc1a5ae..8cd1c5975 100644 --- a/plugins/postcss-logical/test/float.css +++ b/plugins/postcss-logical/test/float.css @@ -1,6 +1,21 @@ -test-float { +test-float-1 { float: left; +} + +test-float-2 { float: inline-start; +} + +test-float-3 { float: inline-end; +} + +@media screen and (min-width: 640px) { + test-float-3 { + float: center; + } +} + +test-float-4 { float: right; } diff --git a/plugins/postcss-logical/test/float.expect.css b/plugins/postcss-logical/test/float.expect.css index 37c4e1350..11076fb24 100644 --- a/plugins/postcss-logical/test/float.expect.css +++ b/plugins/postcss-logical/test/float.expect.css @@ -1,16 +1,39 @@ -test-float:dir(ltr) { +test-float-1 { float: left; } -test-float:dir(rtl) { - float: right; + +:dir(ltr) { + --logical-d9646c-1: left; } -test-float:dir(ltr) { - float: right; + +:dir(rtl) { + --logical-d9646c-1: right; } -test-float:dir(rtl) { + +test-float-2 { float: left; + float: var(--logical-d9646c-1); } -test-float { - float: left; + +:dir(ltr) { + --logical-b352c2-2: right; +} + +:dir(rtl) { + --logical-b352c2-2: left; +} + +test-float-3 { + float: right; + float: var(--logical-b352c2-2); +} + +@media screen and (min-width: 640px) { + test-float-3 { + float: center; + } +} + +test-float-4 { float: right; } diff --git a/plugins/postcss-logical/test/float.ltr.expect.css b/plugins/postcss-logical/test/float.ltr.expect.css index 590760eca..616aa545d 100644 --- a/plugins/postcss-logical/test/float.ltr.expect.css +++ b/plugins/postcss-logical/test/float.ltr.expect.css @@ -1,6 +1,21 @@ -test-float { +test-float-1 { float: left; +} + +test-float-2 { float: left; +} + +test-float-3 { float: right; +} + +@media screen and (min-width: 640px) { + test-float-3 { + float: center; + } +} + +test-float-4 { float: right; }