Skip to content

Commit

Permalink
allow css(), cx(), and style() to be used for rule definition
Browse files Browse the repository at this point in the history
  • Loading branch information
sastan committed Jan 29, 2022
1 parent 24b095a commit b728000
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 3 deletions.
56 changes: 56 additions & 0 deletions .changeset/silver-falcons-perform.md
@@ -0,0 +1,56 @@
---
'twind': patch
---

allow `css()`, `cx()`, and `style()` to be used for rule definition

```js
defineConfig({
rules: [
// Using css
[
'target-new-tab',
css`
target-name: new;
target-new: tab;
`,
],
// dynamic
[
'target-new-(tab|window)',
({ 1: $1 }) => css`
target-name: new;
target-new: ${$1};
`,
],

// Using cx
['highlight(-rounded)?', ({ 1: rounded }) => cx({ 'bg-yellow-200': true, rounded })],

// Using style
// `box?color=coral` -> `.box\\?color\\=coral{background-color:coral}`
// `box?rounded` -> `.box\\?rounded{border-radius:0.25rem}`
// `box?color=coral&rounded` -> `.box\\?color\\=coral\\&rounded{background-color:coral;border-radius:0.25rem}`
// `box?color=purple&rounded=md` -> `.box\\?color\\=purple\\&rounded\\=md{background-color:purple;border-radius:0.375rem}`
[
'box\\?(.+)',
style({
props: {
color: {
coral: css({
backgroundColor: 'coral',
}),
purple: css`
background-color: purple;
`,
},
rounded: {
'': 'rounded',
md: 'rounded-md',
},
},
}),
],
],
})
```
54 changes: 54 additions & 0 deletions documentation/40-reference/README.md
Expand Up @@ -223,6 +223,51 @@ defineConfig({

// dynamic apply
['btn-', ({ $$ }) => `@(bg-${$$}-400 text-${$$}-100 py-2 px-4 rounded-lg)`],

// Using cx
['highlight(-rounded)?', ({ 1: rounded }) => cx({ 'bg-yellow-200': true, rounded })],

// Using css
[
'target-new-tab',
css`
target-name: new;
target-new: tab;
`,
],
// dynamic
[
'target-new-(tab|window)',
({ 1: $1 }) => css`
target-name: new;
target-new: ${$1};
`,
],

// Using style
// `box?color=coral` -> `.box\\?color\\=coral{background-color:coral}`
// `box?rounded` -> `.box\\?rounded{border-radius:0.25rem}`
// `box?color=coral&rounded` -> `.box\\?color\\=coral\\&rounded{background-color:coral;border-radius:0.25rem}`
// `box?color=purple&rounded=md` -> `.box\\?color\\=purple\\&rounded\\=md{background-color:purple;border-radius:0.375rem}`
[
'box\\?(.+)',
style({
props: {
color: {
coral: css({
backgroundColor: 'coral',
}),
purple: css`
background-color: purple;
`,
},
rounded: {
'': 'rounded',
md: 'rounded-md',
},
},
}),
],
],
})
```
Expand Down Expand Up @@ -261,3 +306,12 @@ The following JS APIs may need polyfills:
- [Math.imul](https://caniuse.com/mdn-javascript_builtins_math_imul)
- Firefox<20, Chrome<28, Safari<7, Opera<16
- [polyfill](https://www.npmjs.com/package/math.imul)

When using `style()` within `config.rules`:

- [Object.fromEntries](https://caniuse.com/mdn-javascript_builtins_object_fromentries)
- Edge<79, Firefox<63, Chrome<73, Safari<12.2, Opera<60
- [polyfill](https://www.npmjs.com/package/object.fromentries) or [@ungap/from-entries](https://github.com/ungap/from-entries)
- [URLSearchParams](https://caniuse.com/urlsearchparams)
- Edge<17, Firefox<44, Chrome<49, Safari<10.3, Opera<36
- [polyfill](https://www.npmjs.com/package/url-search-params-polyfill) or [@ungap/url-search-params](https://github.com/ungap/url-search-params)
8 changes: 8 additions & 0 deletions packages/preset-tailwind/src/rules.test.json
Expand Up @@ -1891,6 +1891,14 @@
".btn-green:hover{--tw-bg-opacity:1;background-color:rgba(21,128,61,var(--tw-bg-opacity))}"
],
"btn-red": ".btn-red{--tw-bg-opacity:1;background-color:rgba(248,113,113,var(--tw-bg-opacity));--tw-text-opacity:1;color:rgba(254,226,226,var(--tw-text-opacity));padding-top:0.5rem;padding-bottom:0.5rem;padding-left:1rem;padding-right:1rem;border-radius:0.5rem}",
"target-new-tab": ".target-new-tab{target-name:new;target-new:tab}",
"target-new-window": ".target-new-window{target-name:new;target-new:window}",
"highlight": ".highlight{--tw-bg-opacity:1;background-color:rgba(254,240,138,var(--tw-bg-opacity))}",
"highlight-rounded": ".highlight-rounded{--tw-bg-opacity:1;background-color:rgba(254,240,138,var(--tw-bg-opacity));border-radius:0.25rem}",
"box?color=coral": ".box\\?color\\=coral{background-color:coral}",
"box?rounded": ".box\\?rounded{border-radius:0.25rem}",
"box?color=coral&rounded": ".box\\?color\\=coral\\&rounded{background-color:coral;border-radius:0.25rem}",
"box?color=purple&rounded=md": ".box\\?color\\=purple\\&rounded\\=md{background-color:purple;border-radius:0.375rem}",
"m-5 mr-3 mx-1": [
"m-5 mx-1 mr-3",
[
Expand Down
45 changes: 44 additions & 1 deletion packages/preset-tailwind/src/rules.test.ts
@@ -1,6 +1,6 @@
import { assert, test, afterEach } from 'vitest'

import { apply, twind, virtual } from 'twind'
import { apply, css, cx, style, twind, virtual } from 'twind'

import tailwind from '.'
import data from './rules.test.json'
Expand Down Expand Up @@ -63,6 +63,49 @@ const tw = twind(

// dynamic apply
['btn-', ({ $$ }) => `@(bg-${$$}-400 text-${$$}-100 py-2 px-4 rounded-lg)`],

// Using css
[
'target-new-tab',
css`
target-name: new;
target-new: tab;
`,
],
// dynamic
[
'target-new-(tab|window)',
({ 1: $1 }) => css`
target-name: new;
target-new: ${$1};
`,
],

// Using cx
['highlight(-rounded)?', ({ 1: rounded }) => cx({ 'bg-yellow-200': true, rounded })],

// Using style
// box?color=coral&rounded
// box?color=purple&rounded=md
[
'box\\?(.+)',
style({
props: {
color: {
coral: css({
backgroundColor: 'coral',
}),
purple: css`
background-color: purple;
`,
},
rounded: {
'': 'rounded',
md: 'rounded-md',
},
},
}),
],
],
},
virtual(),
Expand Down
36 changes: 34 additions & 2 deletions packages/twind/src/style.ts
Expand Up @@ -2,7 +2,7 @@
// Based on https://github.com/modulz/stitches
// License MIT

import type { Falsey } from './types'
import type { Falsey, MatchResult } from './types'
import { parse } from './internal/parse'
import { Layer } from './internal/precedence'

Expand Down Expand Up @@ -116,6 +116,26 @@ export interface Style<Variants> {
*/
(props?: StyleProps<Variants>): string

/**
* To be used as resolve within config.rules:
*
* ```js
* {
* rules: [
* // label?prop=value&other=propValue
* // if the style has base eg no prop is required
* ['label(\\?.+)?', style( /* ... *\/ )],
*
* // if the style requires at least one prop
* ['label\\?(.+)', style( /* ... *\/ )],
* ]
* }
* ```
*
* The first group is used to extract the props using {@link URLSearchParams}.
*/
(match: MatchResult): string

readonly defaults: StyleProps<Variants>

/**
Expand Down Expand Up @@ -195,9 +215,21 @@ function createStyle<Variants, BaseVariants>(

return Object.defineProperties(
function style(allProps) {
let isWithinRuleDeclaration

if (Array.isArray(allProps)) {
isWithinRuleDeclaration = true
allProps = Object.fromEntries(new URLSearchParams(allProps[1]).entries()) as VariantsProps<
Variants & BaseVariants
>
}

const props = { ...defaults, ...allProps }

let classNames = (parent ? parent(props) + ' ' : '') + className
// If this style is used within config.rules we do NOT include the marker classes
let classNames = isWithinRuleDeclaration
? ''
: (parent ? parent(props) + ' ' : '') + className

let token: StyleToken

Expand Down

0 comments on commit b728000

Please sign in to comment.