Skip to content

Commit 9234df3

Browse files
committed
Add utility helper for creating utility rules that are automatically escaped and respect prefix/important options
1 parent 960275c commit 9234df3

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

__tests__/processPlugins.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,55 @@ test("plugins can apply the user's chosen prefix", () => {
418418
}
419419
`)
420420
})
421+
422+
test("utilities are escaped and automatically respect prefix and important options when created via `utility`", () => {
423+
const [, utilities] = processPlugins({
424+
plugins: [
425+
function({ utility, addUtilities }) {
426+
addUtilities([
427+
utility('.rotate-1/4', {
428+
transform: 'rotate(90deg)',
429+
}),
430+
])
431+
},
432+
],
433+
options: {
434+
prefix: 'tw-',
435+
important: true,
436+
},
437+
})
438+
439+
expect(css(utilities)).toMatchCss(`
440+
@variants {
441+
.tw-rotate-1\\/4 {
442+
transform: rotate(90deg) !important
443+
}
444+
}
445+
`)
446+
})
447+
448+
test("leading '.' is optional when creating utilities via `utility`", () => {
449+
const [, utilities] = processPlugins({
450+
plugins: [
451+
function({ utility, addUtilities }) {
452+
addUtilities([
453+
utility('rotate-1/4', {
454+
transform: 'rotate(90deg)',
455+
}),
456+
])
457+
},
458+
],
459+
options: {
460+
prefix: 'tw-',
461+
important: true,
462+
},
463+
})
464+
465+
expect(css(utilities)).toMatchCss(`
466+
@variants {
467+
.tw-rotate-1\\/4 {
468+
transform: rotate(90deg) !important
469+
}
470+
}
471+
`)
472+
})

src/util/processPlugins.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ function defineRule(selector, properties) {
1515
return postcss.rule({ selector }).append(decls)
1616
}
1717

18+
function defineUtility(selector, properties, options) {
19+
if (selector.startsWith('.')) {
20+
return defineUtility(selector.slice(1), properties, options)
21+
}
22+
23+
const rule = defineRule(prefixSelector(options.prefix, `.${escapeClassName(selector)}`), properties)
24+
25+
if (options.important) {
26+
rule.walkDecls(decl => (decl.important = true))
27+
}
28+
29+
return rule
30+
}
31+
1832
function defineAtRule(atRule, rules) {
1933
const [name, ...params] = atRule.split(' ')
2034

@@ -34,6 +48,7 @@ export default function(config) {
3448
plugin({
3549
config: (path, defaultValue) => _.get(config, path, defaultValue),
3650
rule: defineRule,
51+
utility: (selector, properties) => defineUtility(selector, properties, config.options),
3752
atRule: defineAtRule,
3853
e: escapeClassName,
3954
addUtilities: (utilities, variants = []) => {

0 commit comments

Comments
 (0)