mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Certain plugins behave differently and the rules about `default` meaning "no suffix" are not universal (see the cursor plugin). The simplest thing to do right now is keep things as they are, which means only certain plugins respect the default option and only certain other plugins respect the negative prefix convention.
1134 lines
23 KiB
JavaScript
1134 lines
23 KiB
JavaScript
import _ from 'lodash'
|
|
import _postcss from 'postcss'
|
|
import processPlugins from '../src/util/processPlugins'
|
|
|
|
function css(nodes) {
|
|
return _postcss.root({ nodes }).toString()
|
|
}
|
|
|
|
function makeConfig(overrides) {
|
|
return _.defaultsDeep(overrides, {
|
|
prefix: '',
|
|
important: false,
|
|
separator: ':',
|
|
})
|
|
}
|
|
|
|
test('plugins can create utilities with object syntax', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities({
|
|
'.object-fill': {
|
|
'object-fit': 'fill',
|
|
},
|
|
'.object-contain': {
|
|
'object-fit': 'contain',
|
|
},
|
|
'.object-cover': {
|
|
'object-fit': 'cover',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create utilities with arrays of objects', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities([
|
|
{
|
|
'.object-fill': {
|
|
'object-fit': 'fill',
|
|
},
|
|
},
|
|
{
|
|
'.object-contain': {
|
|
'object-fit': 'contain',
|
|
},
|
|
},
|
|
{
|
|
'.object-cover': {
|
|
'object-fit': 'cover',
|
|
},
|
|
},
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create utilities with raw PostCSS nodes', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities, postcss }) {
|
|
addUtilities([
|
|
postcss.rule({ selector: '.object-fill' }).append([
|
|
postcss.decl({
|
|
prop: 'object-fit',
|
|
value: 'fill',
|
|
}),
|
|
]),
|
|
postcss.rule({ selector: '.object-contain' }).append([
|
|
postcss.decl({
|
|
prop: 'object-fit',
|
|
value: 'contain',
|
|
}),
|
|
]),
|
|
postcss.rule({ selector: '.object-cover' }).append([
|
|
postcss.decl({
|
|
prop: 'object-fit',
|
|
value: 'cover',
|
|
}),
|
|
]),
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create utilities with mixed object styles and PostCSS nodes', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities, postcss }) {
|
|
addUtilities([
|
|
{
|
|
'.object-fill': {
|
|
objectFit: 'fill',
|
|
},
|
|
},
|
|
postcss.rule({ selector: '.object-contain' }).append([
|
|
postcss.decl({
|
|
prop: 'object-fit',
|
|
value: 'contain',
|
|
}),
|
|
]),
|
|
postcss.rule({ selector: '.object-cover' }).append([
|
|
postcss.decl({
|
|
prop: 'object-fit',
|
|
value: 'cover',
|
|
}),
|
|
]),
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create utilities with variants', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities(
|
|
{
|
|
'.object-fill': {
|
|
'object-fit': 'fill',
|
|
},
|
|
'.object-contain': {
|
|
'object-fit': 'contain',
|
|
},
|
|
'.object-cover': {
|
|
'object-fit': 'cover',
|
|
},
|
|
},
|
|
['responsive', 'hover', 'group-hover', 'focus']
|
|
)
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants responsive, hover, group-hover, focus {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create components with object syntax', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents({
|
|
'.btn-blue': {
|
|
backgroundColor: 'blue',
|
|
color: 'white',
|
|
padding: '.5rem 1rem',
|
|
borderRadius: '.25rem',
|
|
},
|
|
'.btn-blue:hover': {
|
|
backgroundColor: 'darkblue',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue;
|
|
color: white;
|
|
padding: .5rem 1rem;
|
|
border-radius: .25rem
|
|
}
|
|
.btn-blue:hover {
|
|
background-color: darkblue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can add base styles with object syntax', () => {
|
|
const { base } = processPlugins(
|
|
[
|
|
function({ addBase }) {
|
|
addBase({
|
|
img: {
|
|
maxWidth: '100%',
|
|
},
|
|
button: {
|
|
fontFamily: 'inherit',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(css(base)).toMatchCss(`
|
|
img {
|
|
max-width: 100%
|
|
}
|
|
button {
|
|
font-family: inherit
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can add base styles with raw PostCSS nodes', () => {
|
|
const { base } = processPlugins(
|
|
[
|
|
function({ addBase, postcss }) {
|
|
addBase([
|
|
postcss.rule({ selector: 'img' }).append([
|
|
postcss.decl({
|
|
prop: 'max-width',
|
|
value: '100%',
|
|
}),
|
|
]),
|
|
postcss.rule({ selector: 'button' }).append([
|
|
postcss.decl({
|
|
prop: 'font-family',
|
|
value: 'inherit',
|
|
}),
|
|
]),
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(css(base)).toMatchCss(`
|
|
img {
|
|
max-width: 100%
|
|
}
|
|
button {
|
|
font-family: inherit
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create components with raw PostCSS nodes', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents, postcss }) {
|
|
addComponents([
|
|
postcss.rule({ selector: '.btn-blue' }).append([
|
|
postcss.decl({
|
|
prop: 'background-color',
|
|
value: 'blue',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'color',
|
|
value: 'white',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'padding',
|
|
value: '.5rem 1rem',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'border-radius',
|
|
value: '.25rem',
|
|
}),
|
|
]),
|
|
postcss.rule({ selector: '.btn-blue:hover' }).append([
|
|
postcss.decl({
|
|
prop: 'background-color',
|
|
value: 'darkblue',
|
|
}),
|
|
]),
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue;
|
|
color: white;
|
|
padding: .5rem 1rem;
|
|
border-radius: .25rem
|
|
}
|
|
.btn-blue:hover {
|
|
background-color: darkblue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create components with mixed object styles and raw PostCSS nodes', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents, postcss }) {
|
|
addComponents([
|
|
postcss.rule({ selector: '.btn-blue' }).append([
|
|
postcss.decl({
|
|
prop: 'background-color',
|
|
value: 'blue',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'color',
|
|
value: 'white',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'padding',
|
|
value: '.5rem 1rem',
|
|
}),
|
|
postcss.decl({
|
|
prop: 'border-radius',
|
|
value: '.25rem',
|
|
}),
|
|
]),
|
|
{
|
|
'.btn-blue:hover': {
|
|
backgroundColor: 'darkblue',
|
|
},
|
|
},
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue;
|
|
color: white;
|
|
padding: .5rem 1rem;
|
|
border-radius: .25rem
|
|
}
|
|
.btn-blue:hover {
|
|
background-color: darkblue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create components with media queries with object syntax', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents({
|
|
'.container': {
|
|
width: '100%',
|
|
},
|
|
'@media (min-width: 100px)': {
|
|
'.container': {
|
|
maxWidth: '100px',
|
|
},
|
|
},
|
|
'@media (min-width: 200px)': {
|
|
'.container': {
|
|
maxWidth: '200px',
|
|
},
|
|
},
|
|
'@media (min-width: 300px)': {
|
|
'.container': {
|
|
maxWidth: '300px',
|
|
},
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.container {
|
|
width: 100%
|
|
}
|
|
@media (min-width: 100px) {
|
|
.container {
|
|
max-width: 100px
|
|
}
|
|
}
|
|
@media (min-width: 200px) {
|
|
.container {
|
|
max-width: 200px
|
|
}
|
|
}
|
|
@media (min-width: 300px) {
|
|
.container {
|
|
max-width: 300px
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('media queries can be defined multiple times using objects-in-array syntax', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents([
|
|
{
|
|
'.container': {
|
|
width: '100%',
|
|
},
|
|
'@media (min-width: 100px)': {
|
|
'.container': {
|
|
maxWidth: '100px',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'.btn': {
|
|
padding: '1rem .5rem',
|
|
display: 'block',
|
|
},
|
|
'@media (min-width: 100px)': {
|
|
'.btn': {
|
|
display: 'inline-block',
|
|
},
|
|
},
|
|
},
|
|
])
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.container {
|
|
width: 100%
|
|
}
|
|
@media (min-width: 100px) {
|
|
.container {
|
|
max-width: 100px
|
|
}
|
|
}
|
|
.btn {
|
|
padding: 1rem .5rem;
|
|
display: block
|
|
}
|
|
@media (min-width: 100px) {
|
|
.btn {
|
|
display: inline-block
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create nested rules', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents({
|
|
'.btn-blue': {
|
|
backgroundColor: 'blue',
|
|
color: 'white',
|
|
padding: '.5rem 1rem',
|
|
borderRadius: '.25rem',
|
|
'&:hover': {
|
|
backgroundColor: 'darkblue',
|
|
},
|
|
'@media (min-width: 500px)': {
|
|
'&:hover': {
|
|
backgroundColor: 'orange',
|
|
},
|
|
},
|
|
'> a': {
|
|
color: 'red',
|
|
},
|
|
'h1 &': {
|
|
color: 'purple',
|
|
},
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue;
|
|
color: white;
|
|
padding: .5rem 1rem;
|
|
border-radius: .25rem;
|
|
}
|
|
.btn-blue:hover {
|
|
background-color: darkblue;
|
|
}
|
|
@media (min-width: 500px) {
|
|
.btn-blue:hover {
|
|
background-color: orange;
|
|
}
|
|
}
|
|
.btn-blue > a {
|
|
color: red;
|
|
}
|
|
h1 .btn-blue {
|
|
color: purple;
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can create rules with escaped selectors', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ e, addUtilities }) {
|
|
addUtilities({
|
|
[`.${e('top-1/4')}`]: {
|
|
top: '25%',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.top-1\\/4 {
|
|
top: 25%
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can access the current config', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents, config }) {
|
|
const containerClasses = [
|
|
{
|
|
'.container': {
|
|
width: '100%',
|
|
},
|
|
},
|
|
]
|
|
|
|
_.forEach(config('screens'), breakpoint => {
|
|
containerClasses.push({
|
|
[`@media (min-width: ${breakpoint})`]: {
|
|
'.container': { maxWidth: breakpoint },
|
|
},
|
|
})
|
|
})
|
|
addComponents(containerClasses)
|
|
},
|
|
],
|
|
makeConfig({
|
|
screens: {
|
|
sm: '576px',
|
|
md: '768px',
|
|
lg: '992px',
|
|
xl: '1200px',
|
|
},
|
|
})
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.container {
|
|
width: 100%
|
|
}
|
|
@media (min-width: 576px) {
|
|
.container {
|
|
max-width: 576px
|
|
}
|
|
}
|
|
@media (min-width: 768px) {
|
|
.container {
|
|
max-width: 768px
|
|
}
|
|
}
|
|
@media (min-width: 992px) {
|
|
.container {
|
|
max-width: 992px
|
|
}
|
|
}
|
|
@media (min-width: 1200px) {
|
|
.container {
|
|
max-width: 1200px
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can access the variants config directly', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities, variants }) {
|
|
addUtilities(
|
|
{
|
|
'.object-fill': {
|
|
'object-fit': 'fill',
|
|
},
|
|
'.object-contain': {
|
|
'object-fit': 'contain',
|
|
},
|
|
'.object-cover': {
|
|
'object-fit': 'cover',
|
|
},
|
|
},
|
|
variants('objectFit')
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
variants: {
|
|
objectFit: ['responsive', 'focus', 'hover'],
|
|
},
|
|
})
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants responsive, focus, hover {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
.object-contain {
|
|
object-fit: contain
|
|
}
|
|
.object-cover {
|
|
object-fit: cover
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins apply all global variants when variants are configured globally', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities, variants }) {
|
|
addUtilities(
|
|
{
|
|
'.object-fill': {
|
|
'object-fit': 'fill',
|
|
},
|
|
},
|
|
variants('objectFit')
|
|
)
|
|
addUtilities(
|
|
{
|
|
'.rotate-90deg': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
},
|
|
variants('rotate')
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
variants: ['responsive', 'focus', 'hover'],
|
|
})
|
|
)
|
|
|
|
expect(components.length).toBe(0)
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants responsive, focus, hover {
|
|
.object-fill {
|
|
object-fit: fill
|
|
}
|
|
}
|
|
@variants responsive, focus, hover {
|
|
.rotate-90deg {
|
|
transform: rotate(90deg)
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins can provide fallbacks to keys missing from the config', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addComponents, config }) {
|
|
addComponents({
|
|
'.btn': {
|
|
borderRadius: config('borderRadius.default', '.25rem'),
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig({
|
|
borderRadius: {
|
|
'1': '1px',
|
|
'2': '2px',
|
|
'4': '4px',
|
|
'8': '8px',
|
|
},
|
|
})
|
|
)
|
|
|
|
expect(utilities.length).toBe(0)
|
|
expect(css(components)).toMatchCss(`
|
|
.btn {
|
|
border-radius: .25rem
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('variants are optional when adding utilities', () => {
|
|
const { utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities({
|
|
'.border-collapse': {
|
|
'border-collapse': 'collapse',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.border-collapse {
|
|
border-collapse: collapse
|
|
}
|
|
}`)
|
|
})
|
|
|
|
test('plugins can add multiple sets of utilities and components', () => {
|
|
const { components, utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities, addComponents }) {
|
|
addComponents({
|
|
'.card': {
|
|
padding: '1rem',
|
|
borderRadius: '.25rem',
|
|
},
|
|
})
|
|
|
|
addUtilities({
|
|
'.skew-12deg': {
|
|
transform: 'skewY(-12deg)',
|
|
},
|
|
})
|
|
|
|
addComponents({
|
|
'.btn': {
|
|
padding: '1rem .5rem',
|
|
display: 'inline-block',
|
|
},
|
|
})
|
|
|
|
addUtilities({
|
|
'.border-collapse': {
|
|
borderCollapse: 'collapse',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig()
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.skew-12deg {
|
|
transform: skewY(-12deg)
|
|
}
|
|
}
|
|
@variants {
|
|
.border-collapse {
|
|
border-collapse: collapse
|
|
}
|
|
}
|
|
`)
|
|
expect(css(components)).toMatchCss(`
|
|
.card {
|
|
padding: 1rem;
|
|
border-radius: .25rem
|
|
}
|
|
.btn {
|
|
padding: 1rem .5rem;
|
|
display: inline-block
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('plugins respect prefix and important options by default when adding utilities', () => {
|
|
const { utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities({
|
|
'.rotate-90': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
important: true,
|
|
})
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.tw-rotate-90 {
|
|
transform: rotate(90deg) !important
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test("component declarations respect the 'prefix' option by default", () => {
|
|
const { components } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents({
|
|
'.btn-blue': {
|
|
backgroundColor: 'blue',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
})
|
|
)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.tw-btn-blue {
|
|
background-color: blue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('all selectors in a rule are prefixed', () => {
|
|
const { utilities, components } = processPlugins(
|
|
[
|
|
function({ addUtilities, addComponents }) {
|
|
addUtilities({
|
|
'.rotate-90, .rotate-1\\/4': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
})
|
|
addComponents({
|
|
'.btn-blue, .btn-red': {
|
|
padding: '10px',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
})
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.tw-rotate-90, .tw-rotate-1\\/4 {
|
|
transform: rotate(90deg)
|
|
}
|
|
}
|
|
`)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.tw-btn-blue, .tw-btn-red {
|
|
padding: 10px
|
|
}
|
|
`)
|
|
})
|
|
|
|
test("component declarations can optionally ignore 'prefix' option", () => {
|
|
const { components } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents(
|
|
{
|
|
'.btn-blue': {
|
|
backgroundColor: 'blue',
|
|
},
|
|
},
|
|
{ respectPrefix: false }
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
})
|
|
)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test("component declarations are not affected by the 'important' option", () => {
|
|
const { components } = processPlugins(
|
|
[
|
|
function({ addComponents }) {
|
|
addComponents({
|
|
'.btn-blue': {
|
|
backgroundColor: 'blue',
|
|
},
|
|
})
|
|
},
|
|
],
|
|
makeConfig({
|
|
important: true,
|
|
})
|
|
)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.btn-blue {
|
|
background-color: blue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test("plugins can apply the user's chosen prefix to components manually", () => {
|
|
const { components } = processPlugins(
|
|
[
|
|
function({ addComponents, prefix }) {
|
|
addComponents(
|
|
{
|
|
[prefix('.btn-blue')]: {
|
|
backgroundColor: 'blue',
|
|
},
|
|
},
|
|
{ respectPrefix: false }
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
})
|
|
)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.tw-btn-blue {
|
|
background-color: blue
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('prefix can optionally be ignored for utilities', () => {
|
|
const { utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities(
|
|
{
|
|
'.rotate-90': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
},
|
|
{
|
|
respectPrefix: false,
|
|
}
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
important: true,
|
|
})
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.rotate-90 {
|
|
transform: rotate(90deg) !important
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('important can optionally be ignored for utilities', () => {
|
|
const { utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities(
|
|
{
|
|
'.rotate-90': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
},
|
|
{
|
|
respectImportant: false,
|
|
}
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
important: true,
|
|
})
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants {
|
|
.tw-rotate-90 {
|
|
transform: rotate(90deg)
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('variants can still be specified when ignoring prefix and important options', () => {
|
|
const { utilities } = processPlugins(
|
|
[
|
|
function({ addUtilities }) {
|
|
addUtilities(
|
|
{
|
|
'.rotate-90': {
|
|
transform: 'rotate(90deg)',
|
|
},
|
|
},
|
|
{
|
|
variants: ['responsive', 'hover', 'focus'],
|
|
respectImportant: false,
|
|
respectPrefix: false,
|
|
}
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
important: true,
|
|
})
|
|
)
|
|
|
|
expect(css(utilities)).toMatchCss(`
|
|
@variants responsive, hover, focus {
|
|
.rotate-90 {
|
|
transform: rotate(90deg)
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('prefix will prefix all classes in a selector', () => {
|
|
const { components } = processPlugins(
|
|
[
|
|
function({ addComponents, prefix }) {
|
|
addComponents(
|
|
{
|
|
[prefix('.btn-blue .w-1\\/4 > h1.text-xl + a .bar')]: {
|
|
backgroundColor: 'blue',
|
|
},
|
|
},
|
|
{ respectPrefix: false }
|
|
)
|
|
},
|
|
],
|
|
makeConfig({
|
|
prefix: 'tw-',
|
|
})
|
|
)
|
|
|
|
expect(css(components)).toMatchCss(`
|
|
.tw-btn-blue .tw-w-1\\/4 > h1.tw-text-xl + a .tw-bar {
|
|
background-color: blue
|
|
}
|
|
`)
|
|
})
|