Skip to content

Commit

Permalink
feat: support @value at-rule in selectors (#941)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: if you have name of `@value` in selector it will be replaced, you need to rename your name of `@value` or rename your selector
  • Loading branch information
evilebottnawi authored May 28, 2019
1 parent fd8d2e6 commit 05a42e2
Show file tree
Hide file tree
Showing 9 changed files with 476 additions and 87 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,33 @@ To import from multiple modules use multiple `composes:` rules.
}
```

##### `Values`

You can use `@value` to specific values to be reused throughout a document.

We recommend use prefix `v-` for values, `s-` for selectors and `m-` for media at-rules.

```css
@value v-primary: #BF4040;
@value s-black: black-selector;
@value m-large: (min-width: 960px);

.header {
color: v-primary;
padding: 0 10px;
}

.s-black {
color: black;
}

@media m-large {
.header {
padding: 0 20px;
}
}
```

#### `Boolean`

Enable **CSS Modules** features.
Expand Down
44 changes: 8 additions & 36 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
"normalize-path": "^3.0.0",
"postcss": "^7.0.14",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^2.0.6",
"postcss-modules-local-by-default": "^3.0.1",
"postcss-modules-scope": "^2.1.0",
"postcss-modules-values": "^2.0.0",
"postcss-modules-values": "^3.0.0",
"postcss-value-parser": "^3.3.0",
"schema-utils": "^1.0.0"
},
Expand Down
55 changes: 29 additions & 26 deletions src/plugins/postcss-icss-parser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import { extractICSS } from 'icss-utils';
import { extractICSS, replaceValueSymbols } from 'icss-utils';
import loaderUtils from 'loader-utils';

const pluginName = 'postcss-icss-parser';
Expand All @@ -9,22 +9,23 @@ export default postcss.plugin(
pluginName,
() =>
function process(css, result) {
const imports = {};
const icss = extractICSS(css);
const exports = icss.icssExports;
const importReplacements = Object.create(null);
const { icssImports, icssExports } = extractICSS(css);

Object.keys(icss.icssImports).forEach((key) => {
let index = 0;

Object.keys(icssImports).forEach((key) => {
const url = loaderUtils.parseString(key);

Object.keys(icss.icssImports[key]).forEach((prop) => {
const index = Object.keys(imports).length;
Object.keys(icssImports[key]).forEach((prop) => {
index += 1;

imports[`$${prop}`] = index;
importReplacements[prop] = `___CSS_LOADER_IMPORT___${index}___`;

result.messages.push({
pluginName,
type: 'icss-import',
item: { url, export: icss.icssImports[key][prop], index },
item: { url, export: icssImports[key][prop], index },
});

const alreadyIncluded = result.messages.find(
Expand Down Expand Up @@ -56,41 +57,43 @@ export default postcss.plugin(
}

const token = node.value;
const importIndex = imports[`$${token}`];
const replacement = importReplacements[token];

if (typeof importIndex === 'number') {
if (replacement) {
// eslint-disable-next-line no-param-reassign
node.value = `___CSS_LOADER_IMPORT___${importIndex}___`;
node.value = replacement;
}
});

return tokens.toString();
}

// Replace tokens in declarations
css.walkDecls((decl) => {
// eslint-disable-next-line no-param-reassign
decl.value = replaceImportsInString(decl.value.toString());
});

// Replace tokens in at-rules
css.walkAtRules((atrule) => {
// Due reusing `ast` from `postcss-loader` some plugins may lack
// `params` property, we need to account for this possibility
if (atrule.params) {
// Replace tokens
css.walk((node) => {
// Due reusing `ast` from `postcss-loader` some plugins may remove `value`, `selector` or `params` properties
if (node.type === 'decl' && node.value) {
// eslint-disable-next-line no-param-reassign
node.value = replaceImportsInString(node.value.toString());
} else if (node.type === 'rule' && node.selector) {
// eslint-disable-next-line no-param-reassign
node.selector = replaceValueSymbols(
node.selector.toString(),
importReplacements
);
} else if (node.type === 'atrule' && node.params) {
// eslint-disable-next-line no-param-reassign
atrule.params = replaceImportsInString(atrule.params.toString());
node.params = replaceImportsInString(node.params.toString());
}
});

// Replace tokens in export
Object.keys(exports).forEach((exportName) => {
Object.keys(icssExports).forEach((exportName) => {
result.messages.push({
pluginName,
type: 'export',
item: {
key: exportName,
value: replaceImportsInString(exports[exportName]),
value: replaceImportsInString(icssExports[exportName]),
},
});
});
Expand Down
Loading

0 comments on commit 05a42e2

Please sign in to comment.