Skip to content

Commit

Permalink
feat: support template literals for css and keyframes (#91)
Browse files Browse the repository at this point in the history
* feat: support template literals for css and keyframes

* test: css with tw.apply

* fix: animation with support for template literals

* test: preflight with css

* refactor: move common code into utils

* doc: template literal documention

* chore: lint

* chore: cleanup todos

* fix: use InlineDirective to type lazy helper

* fix: use new theme helper
  • Loading branch information
sastan committed Jan 18, 2021
1 parent dd30065 commit 7be6243
Show file tree
Hide file tree
Showing 12 changed files with 844 additions and 228 deletions.
30 changes: 25 additions & 5 deletions docs/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ const btn = tw.apply`

</details>

<details><summary>Using within <code>CSS</code> – pending</summary>
<details><summary>Using within <code>CSS</code></summary>

`tw.apply` can be used with `css` (_pending variable arguments, array support_):
`tw.apply` can be used with `css`:

```js
const prose = css(
Expand All @@ -208,13 +208,15 @@ const prose = css(
)
```

Using template literal syntax (_pending, but I'm working on it_):
Using template literal syntax:

```js
const prose = css`
${tw.apply`text-gray-700 dark:text-gray-300`)
${tw.apply`text-gray-700 dark:text-gray-300`}
p { ${tw.apply('my-5')} }
p {
${tw.apply`my-5`}
}
h1 {
${tw.apply`text-black dark:text-white`}
Expand All @@ -237,6 +239,24 @@ const motion = animation('.6s ease-in-out infinite', {
'50%': tw.apply`scale-125 rotate-45`,
'100%': tw.apply`scale-100 rotate-0`,
})

const bounce = animation(
'1s ease infinite',
keyframes`
from, 20%, 53%, 80%, to {
${tw.apply`transform-gpu translate-x-0`}
}
40%, 43% {
${tw.apply`transform-gpu -translate-x-7`}
}
70% {
${tw.apply`transform-gpu -translate-x-3.5`}
},
90% {
${tw.apply`transform-gpu -translate-x-1`}
}
`,
)
```

</details>
Expand Down
162 changes: 125 additions & 37 deletions docs/css-in-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Sometimes you might find yourself wanting to write some arbitrary styles for an
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [CSS directive](#css-directive)
- [Template Literals](#template-literals)
- [Accessing the theme](#accessing-the-theme)
- [Animation Directive](#animation-directive)
- [Keyframes Helper](#keyframes-helper)
Expand Down Expand Up @@ -55,21 +56,95 @@ tw`
// => sm:hover:tw-xxxx
```

Values within the CSS object can be a function which are called with the `context` and should return the value to be used:
Values within the CSS object can be functions which are called with the `context` and should return the value to be used:

```js
import { theme } from 'twind'

const styles = css({
// .tw-xxx a
a: ({ theme }) => ({
a: {
color: theme('colors.blue.500'),
// .tw-xxx a:hover
'&:hover': {
color: theme('colors.blue.700'),
},
}),
},
})
```

`css` allows to define global styles using the `:global` selector:

```js
const styles = css({
':global': {
a: {
color: theme('colors.blue.500'),
},
},
})
```

Tagged template literal syntax works like in emotion, goober or styled-components:

```js
const style = css`
color: rebeccapurple;
background-color: ${theme('colors.gray.500')};
&:hover {
${tw.apply`text-purple-700`}
}
`
```

> Please note that the template literal syntax has a little performance impact as twind needs to parse the CSS. For optimal performance use the object notation.
Variadic arguments and arrays (nested as deep as you like) are supported as well:

```js
const style = css(
{
backgroundColor: 'hotpink',
'&:hover': {
color: 'darkgreen',
},
},
{
color: 'red',
},
)

const style = css([
{
backgroundColor: 'hotpink',
'&:hover': {
color: 'darkgreen',
},
},
{
color: 'red',
},
])
```

[tw.apply](./components) can be used within `css`:

```js
css(tw.apply`text-gray(700 dark:300)`, {
p: tw.apply`my-5`,
h1: tw.apply`text(black dark:white hover:purple-500)`,
})

// Or using template literals
css`
${tw.apply`text-gray(700 dark:300)`}
p {
${tw.apply('my-5')}
}
`
```

CSS directives can be used without applying it through `tw`:

```js
Expand Down Expand Up @@ -98,35 +173,30 @@ document.body.className = css.call(tw, {
'&::before': { content: '"🙁"' },
'&::after': { content: '"😊"' },
})

// Or providing tw on generation
const smiley = css({
'&::before': { content: '"🙁"' },
'&::after': { content: '"😊"' },
})
document.body.className = smiley({ tw })
```

### Template Literals

### Accessing the theme

Values of the CSS object maybe functions that are passed the context and should return the value to be used:

```js
css({
color: ({ theme }) => theme('colors.blue.500'),
color: theme('colors.blue.500'),
'&:hover': {
color: ({ theme }) => theme('colors.blue.700'),
color: theme('colors.blue.700'),
},
})

css({
a: ({ theme }) => ({
a: {
color: theme('colors.blue.500'),
// .tw-xxx a:hover
'&:hover': {
color: theme('colors.blue.700'),
},
}),
},
})
```

Expand Down Expand Up @@ -157,6 +227,25 @@ const bounce = animation('1s ease infinite', {
tw`hover:${bounce}`
```

Template literal syntax is supported as well:

```js
const bounce = animation('1s ease infinite')`
from, 20%, 53%, 80%, to {
${tw.apply`transform-gpu translate-x-0`}
}
40%, 43% {
${tw.apply`transform-gpu -translate-x-7`}
}
70% {
${tw.apply`transform-gpu -translate-x-3.5`}
},
90% {
${tw.apply`transform-gpu -translate-x-1`}
}
`
```

The first argument can be a [animation shorthand CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation) string, an object of CSS animation properties or a function which is passed the context to return the shorthand CSS:

```js
Expand All @@ -172,10 +261,12 @@ const slidein = animation(
},
)

import { theme } from 'twind'

const bounce = animation(
{
animationDuration: '1s',
animationTimingFunction: ({ theme }) => theme('transitionTimingFunction.in-out'),
animationTimingFunction: theme('transitionTimingFunction.in-out'),
animationIterationCount: 'infinite',
},
{
Expand Down Expand Up @@ -205,17 +296,6 @@ const animate = animation.bind(tw)
const bounce = animation.call(tw, {
/* same as above */
})

// Or providing tw on generation
const slidein = animation('1s slidein', {
from: {
transform: 'translateX(0%)',
},
to: {
transform: 'translateX(100%)',
},
})
slidein({ tw })
```

## Keyframes Helper
Expand All @@ -241,6 +321,25 @@ const bounce = keyframes({
})
```

Template literal syntax is supported as well:

```js
const bounce = keyframes`
from, 20%, 53%, 80%, to {
${tw.apply`transform-gpu translate-x-0`}
}
40%, 43% {
${tw.apply`transform-gpu -translate-x-7`}
}
70% {
${tw.apply`transform-gpu -translate-x-3.5`}
},
90% {
${tw.apply`transform-gpu -translate-x-1`}
}
`
```

The returned values can be used like this:

```js
Expand Down Expand Up @@ -273,17 +372,6 @@ const kf = keyframes.bind(tw)
const bounce = keyframes.call(tw, {
/* same as above */
})

// Or providing tw on generation
const slidein = keyframes({
from: {
transform: 'translateX(0%)',
},
to: {
transform: 'translateX(100%)',
},
})
slidein({ tw })
```

<hr/>
Expand Down
22 changes: 21 additions & 1 deletion docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,31 @@ To smooth over browser inconsistencies, Tailwind provide a [opinionated modern r
```js
setup({
preflight: {
body: tw.apply('bg-gray-900 text-white'),
body: tw.apply`bg-gray-900 text-white`,
},
})
```

- use [css](./css-in-js.md) to merge rules

```js
import { theme } from 'twind'
import { css } from 'twind/css'

setup({
preflight: (preflight) =>
css(
preflight,
{
body: {
backgroundColor: theme('colors.gray.900'),
},
},
{ body: tw.apply`text-gray-100` },
),
})
```

## Mode

One benefit of doing compilation at runtime is that it is possible to warn developers about errors such as:
Expand Down
12 changes: 6 additions & 6 deletions src/__tests__/apply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ test('with animation', ({ tw, sheet }) => {

assert.equal(sheet.target, [])

assert.is(motion({ tw }), 'tw-1aowhnt')
assert.is(tw(motion), 'tw-1u2v2kj')
assert.equal(sheet.target, [
'@keyframes tw-1qi9ouj{0%{--tw-vkgkf8:1;--tw-1lff04g:1;transform:scale(1);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1))}50%{--tw-vkgkf8:1.25;--tw-1lff04g:1.25;transform:rotate(45deg);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1));--tw-9ouawy:45deg}100%{--tw-vkgkf8:1;--tw-1lff04g:1;transform:rotate(0deg);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1));--tw-9ouawy:0deg}}',
'.tw-1aowhnt{animation:.6s ease-in-out infinite;animation-name:tw-1qi9ouj}',
'@keyframes tw-25lzqb{0%{--tw-vkgkf8:1;--tw-1lff04g:1;transform:scale(1);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1))}50%{--tw-vkgkf8:1.25;--tw-1lff04g:1.25;transform:rotate(45deg);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1));--tw-9ouawy:45deg}100%{--tw-vkgkf8:1;--tw-1lff04g:1;transform:rotate(0deg);transform:translateX(var(--tw-1e4pbj4,0)) translateY(var(--tw-142admc,0)) rotate(var(--tw-9ouawy,0)) skewX(var(--tw-wnlb2r,0)) skewY(var(--tw-o4ir2d,0)) scaleX(var(--tw-vkgkf8,1)) scaleY(var(--tw-1lff04g,1));--tw-9ouawy:0deg}}',
'.tw-1u2v2kj{animation:.6s ease-in-out infinite;animation-name:tw-25lzqb}',
])
})

Expand Down Expand Up @@ -304,12 +304,12 @@ test('use :global within css', ({ tw, sheet }) => {
a: tw.apply('text-blue(500 hover:700)'),
})

assert.is(tw(style), 'tw-dhqh4q')
assert.is(tw(style), 'tw-18yto84')

assert.equal(sheet.target, [
'body{--tw-17cwy6m:1;background-color:#111827;background-color:rgba(17,24,39,var(--tw-17cwy6m));--tw-dxr4o8:1;color:#fff;color:rgba(255,255,255,var(--tw-dxr4o8))}',
'.tw-dhqh4q a:hover{--tw-dxr4o8:1;color:#1d4ed8;color:rgba(29,78,216,var(--tw-dxr4o8))}',
'.tw-dhqh4q a{--tw-dxr4o8:1;color:#3b82f6;color:rgba(59,130,246,var(--tw-dxr4o8))}',
'.tw-18yto84 a:hover{--tw-dxr4o8:1;color:#1d4ed8;color:rgba(29,78,216,var(--tw-dxr4o8))}',
'.tw-18yto84 a{--tw-dxr4o8:1;color:#3b82f6;color:rgba(59,130,246,var(--tw-dxr4o8))}',
])
})

Expand Down

0 comments on commit 7be6243

Please sign in to comment.