Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions plugins/postcss-custom-selectors/.tape.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ postcssTape(plugin)({
preserve: true
}
},
'complex': {
message: 'supports complex usage'
},
'safety': {
message: 'supports safe tag ordering (.foo:--h1 becomes h1.foo instead of .fooh1)'
},
Expand Down
3 changes: 3 additions & 0 deletions plugins/postcss-custom-selectors/.tape.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ postcssTape(plugin)({
preserve: true
}
},
'complex': {
message: 'supports complex usage'
},
'safety': {
message: 'supports safe tag ordering (.foo:--h1 becomes h1.foo instead of .fooh1)'
},
Expand Down
4 changes: 4 additions & 0 deletions plugins/postcss-custom-selectors/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes to PostCSS Custom Selectors

### Unreleased

- Fixed: allow any valid ident in custom media (`@custom-selector :--🧑🏾‍🎤 .singer`)

### 6.0.2 (June 3, 2022)

- Fixed: prevent duplicate rules when custom selectors are not defined
Expand Down
42 changes: 23 additions & 19 deletions plugins/postcss-custom-selectors/src/custom-selectors-from-root.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import getASTFromSelectors from './selectors-ast-from-selectors-string';
import parser from 'postcss-selector-parser';

// return custom selectors from the css root, conditionally removing them
export default (root, opts) => {
Expand All @@ -7,28 +7,32 @@ export default (root, opts) => {

// for each custom selector atrule that is a child of the css root
root.nodes.slice().forEach(node => {
if (isCustomSelector(node)) {
// extract the name and selectors from the params of the custom selector
const [, name, selectors] = node.params.match(customSelectorParamsRegExp);
if (node.type !== 'atrule' || node.name !== 'custom-selector') {
return;
}

if (!node.params || !node.params.includes(':--')) {
return;
}

// write the parsed selectors to the custom selector
customSelectors[name] = getASTFromSelectors(selectors);
const source = node.params.trim();

// conditionally remove the custom selector atrule
if (!Object(opts).preserve) {
node.remove();
}
const selectorAST = parser().astSync(source);
const nameNode = selectorAST?.nodes?.[0]?.nodes?.[0];
if (!nameNode || nameNode.type !== 'pseudo' || !nameNode.value.startsWith(':--')) {
return;
}
});

return customSelectors;
};
const name = nameNode.toString();

// match the custom selector name
const customSelectorNameRegExp = /^custom-selector$/i;
// re-parsing is important to obtain the correct AST shape
customSelectors[name] = parser().astSync(source.slice(name.length).trim());

// match the custom selector params
const customSelectorParamsRegExp = /^(:--[A-z][\w-]*)\s+([\W\w]+)\s*$/;
// conditionally remove the custom selector atrule
if (!Object(opts).preserve) {
node.remove();
}
});

// whether the atrule is a custom selector
const isCustomSelector = node => node.type === 'atrule' && customSelectorNameRegExp.test(node.name) && customSelectorParamsRegExp.test(node.params);
return customSelectors;
};
4 changes: 2 additions & 2 deletions plugins/postcss-custom-selectors/src/import-from.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import postcss from 'postcss';
import getSelectorsAstFromSelectorsString from './selectors-ast-from-selectors-string';
import parser from 'postcss-selector-parser';
import getCustomSelectors from './custom-selectors-from-root';

/* Import Custom Selectors from CSS AST
Expand Down Expand Up @@ -31,7 +31,7 @@ function importCustomSelectorsFromObject(object) {
);

for (const key in customSelectors) {
customSelectors[key] = getSelectorsAstFromSelectorsString(customSelectors[key]);
customSelectors[key] = parser().astSync(customSelectors[key]);
}

return customSelectors;
Expand Down
2 changes: 1 addition & 1 deletion plugins/postcss-custom-selectors/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const creator = (opts) => {
await exportCustomSelectorsToDestinations(helpers[customSelectorHelperKey], exportTo);
},
Rule: (rule, helpers) => {
if (!rule.selector.match(/:--[A-z][\w-]*/)) {
if (!rule.selector.includes(':--')) {
return;
}

Expand Down

This file was deleted.

17 changes: 17 additions & 0 deletions plugins/postcss-custom-selectors/test/complex.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@custom-selector :--3xl .xl3;

:--3xl {
order: 1;
}

@custom-selector :--🧑🏾‍🎤 .singer;

:--🧑🏾‍🎤 {
order: 2;
}

@custom-selector :------- .dash;

:------- {
order: 3;
}
11 changes: 11 additions & 0 deletions plugins/postcss-custom-selectors/test/complex.expect.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.xl3 {
order: 1;
}

.singer {
order: 2;
}

.dash {
order: 3;
}