Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 1x 1x 1x 1x 37x 34x 33x 33x 36x 36x 100x 33x 33x 36x 33x 2x 30x 1x 25x 25x 25x 65x 64x 34x 34x 30x 30x 30x 30x 25x 24x 24x 24x 25x 1x 24x 24x 24x 1x 23x 1x | /**
* postcss-scope-tokens
*
* Transforms all SLDS design token declaration blocks into a layered cascade
* architecture using CSS `@layer`.
*
* Two presets are exported for convenience:
*
* LEGACY (default):
* @layer deprecated, defaults, shared, theme, component;
* --slds-g-* / --slds-r-* → defaults, --lwc-* → deprecated,
* --slds-s-* → shared, --slds-c-* → component
*
* THEME_LAYER_PRESET:
* @layer deprecated, theme, customization;
* --slds-g-* / --slds-r-* / --slds-s-* → theme, --lwc-* → deprecated
*
* For every matched token block the plugin:
* 1. Strips all selector aliases (`.slds-theme_*`, `.slds-theme--*`); only `:where(html)` is kept.
* 2. Wraps the rule in the appropriate `@layer` at-rule.
*
* The `@layer` order declaration is injected as the very first node in the output,
* immediately after any existing header comment, so the cascade order is established
* before any token definitions.
*/
/** Legacy layer order and token mapping (used by dist/css/ outputs). */
const LEGACY_LAYER_ORDER = 'deprecated, defaults, shared, theme, component';
const LEGACY_TOKEN_LAYER = new Map([
['--slds-r-', 'defaults'],
['--slds-g-', 'defaults'],
['--slds-s-', 'shared'],
['--slds-c-', 'component'],
['--lwc-', 'deprecated'],
]);
/** Theme-layer preset (used by all theme-layer outputs: build/ and dist/). */
export const THEME_LAYER_PRESET = {
layerOrder: 'deprecated, theme, customization',
tokenLayer: new Map([
['--slds-r-', 'theme'],
['--slds-g-', 'theme'],
['--slds-s-', 'theme'],
['--lwc-', 'deprecated'],
]),
};
/**
* Determine which layer all declarations in a rule belong to.
* Returns the layer name if every declaration maps to the same layer, otherwise null.
*
* @param {import('postcss').Rule} rule
* @param {Map<string, string>} tokenLayerMap
* @returns {string | null}
*/
const resolveLayer = (rule, tokenLayerMap) => {
const declarations = rule.nodes?.filter((n) => n.type === 'decl') ?? [];
if (declarations.length === 0) return null;
let layer = null;
for (const decl of declarations) {
let match = null;
for (const [prefix, name] of tokenLayerMap) {
if (decl.prop.startsWith(prefix)) {
match = name;
break;
}
}
if (match === null) return null;
if (layer === null) layer = match;
else Iif (layer !== match) return null;
}
return layer;
};
/**
* @param {{ injectLayerOrder?: boolean, layerOrder?: string, tokenLayer?: Map<string, string> }} [opts]
* @param {boolean} [opts.injectLayerOrder=true] When false, skip the `@layer` order declaration.
* @param {string} [opts.layerOrder] Custom layer order string (defaults to legacy).
* @param {Map<string, string>} [opts.tokenLayer] Custom token-prefix-to-layer mapping (defaults to legacy).
*/
const plugin = ({
injectLayerOrder = true,
layerOrder = LEGACY_LAYER_ORDER,
tokenLayer = LEGACY_TOKEN_LAYER,
} = {}) => ({
postcssPlugin: 'postcss-scope-tokens',
// Track whether the @layer order declaration has been injected yet.
prepare() {
let layerOrderInjected = !injectLayerOrder;
return {
Rule(rule, { AtRule }) {
if (!rule.selector.includes(':root') && !rule.selector.includes(':where(html)')) return;
// Skip rules already inside an @layer — they've already been processed.
if (rule.parent?.type === 'atrule' && rule.parent.name === 'layer') return;
const layer = resolveLayer(rule, tokenLayer);
if (layer === null) return;
// Rewrite selector to bare :where(html), dropping all theme class aliases.
rule.selector = ':where(html)';
// Wrap in @layer <name> { … }
const atLayer = new AtRule({ name: 'layer', params: layer });
atLayer.append(rule.clone());
rule.replaceWith(atLayer);
},
OnceExit(root, { AtRule, Declaration }) {
if (layerOrderInjected) return;
layerOrderInjected = true;
// Find the insertion point: after any leading comment, before first real rule/at-rule.
let insertAfter = null;
for (const node of root.nodes) {
if (node.type === 'comment') {
insertAfter = node;
} else {
break;
}
}
const layerDecl = new AtRule({ name: 'layer', params: layerOrder });
if (insertAfter) {
insertAfter.after(layerDecl);
} else {
root.prepend(layerDecl);
}
},
};
},
});
plugin.postcss = true;
export default plugin;
|