twin.macro icon indicating copy to clipboard operation
twin.macro copied to clipboard

Add initial support for linaria for static CSS interop

Open NateRadebaugh opened this issue 3 years ago β€’ 16 comments

Related discussion:

  • https://github.com/ben-rogerson/twin.macro/discussions/244

NateRadebaugh avatar Dec 09 '20 15:12 NateRadebaugh

thanks for the PR's, you got a good base ready this feature - 🀞 it can be done!

ben-rogerson avatar Dec 10 '20 09:12 ben-rogerson

I have given this a quick initial test with the styled import (and by including the fix from #256).

This is working:

import tw from 'twin.macro'
import { styled } from 'linaria/react'

const Button = styled.button`
  ${tw`bg-black`}
`

But importing from twin doesn't work:

import tw, { styled } from 'twin.macro'

const Button = styled.button`
  ${tw`bg-black`}
`

Results in Using the "styled" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.

Array styling

There's also a common syntax twin uses/advertises which is adding the items to an array. Either linaria needs some adjustments or twin (or a bit of both) to allow this:

import tw from "twin.macro";

const Button = tw.button`bg-black`;

// ↓ ↓ ↓ ↓ ↓ ↓

import { styled as _styled } from "linaria/react";

const Button = _styled.button({
  "--tw-bg-opacity": "1",
  "backgroundColor": "rgba(0, 0, 0, var(--tw-bg-opacity))"
});

and also this:

import tw, { styled } from "twin.macro";

const Button = styled.button([tw`bg-black`]);

// ↓ ↓ ↓ ↓ ↓ ↓

import { styled as _styled } from "linaria/react";

const Button = _styled.button([{
  "--tw-bg-opacity": "1",
  "backgroundColor": "rgba(0, 0, 0, var(--tw-bg-opacity))"
}]);

ben-rogerson avatar Dec 12 '20 01:12 ben-rogerson

Agreed, I haven't figured out the glue here but while I've got the example rendering linaria fully can't see any of the twin.macro ones working as expected. I don't understand the twin code well enough to determine the fix at the moment.

NateRadebaugh avatar Dec 12 '20 03:12 NateRadebaugh

I'm keen to explore this further, but I've got quite a bit on my plate at the moment so I'll have to circle back around and tackle it πŸ‘

ben-rogerson avatar Dec 16 '20 04:12 ben-rogerson

will it merged in near future?

vinverdy avatar Apr 16 '21 09:04 vinverdy

What is this PR missing? Can I help in any way?

zaguiini avatar Dec 29 '21 15:12 zaguiini

This PR was never completed and is still just a draft. Was hoping @ben-rogerson would pick it up or give some pointers.

NateRadebaugh avatar Dec 29 '21 16:12 NateRadebaugh

I'm planning to wait for version 4 to come out of beta before pursuing an integration. Unless the API is similar enough?

ben-rogerson avatar Dec 30 '21 01:12 ben-rogerson

I'm planning to wait for version 3 to come out of beta before pursuing an integration. Unless the API is similar enough?

I would be so excited to see twin.macro add support for a zero-runtime CSS library. With linaria V4 recently being released, I would love to help twin.macro implement support for linaria. @ben-rogerson, would you be open to PRs adding linaria support? Or is that something you would prefer to tackle on your own?

lukesmurray avatar Aug 05 '22 15:08 lukesmurray

Hey Luke - yeah definitely open to a PR - how about a new "Linaria + Emotion + TypeScript" example?

As there's so many changes in the next twin.macro@rc I wouldn't advise working with any code in this repository at the moment but see how you go adding an example in the twin.examples repo - if you run into any issues either contact me on Discord or post up the unfinished PR and ask questions there - thanks!

As there's no preset="linaria" added yet, you can specify custom imports like this:

// In your twin config
styled: { import: 'default', from: '@emotion/styled' },
css: { import: 'css', from: '@emotion/react' },
global: { import: 'Global', from: '@emotion/react' },

ben-rogerson avatar Aug 08 '22 04:08 ben-rogerson

Note to whoever implements this following @ben-rogerson's comment about custom imports: global styles in Linaria work a little bit differently: https://github.com/callstack/linaria/blob/v4.0.0/docs/BASICS.md#adding-global-styles.

EDIT: well, actually, it's kind of different: https://scottspence.com/posts/linaria-getting-started#global-style 🀷 the import for global is also css and you don't need to reference it at all as simply defining and exporting the css tagged-template makes Linaria append the style to the page.

zaguiini avatar Aug 08 '22 05:08 zaguiini

With global styles we should use the globalStyles (style object) import rather than GlobalStyles (for use in jsx) import.

Something like this:

import { globalStyles } from 'twin.macro'
import { css } from 'linaria'

export const globals = css(globalStyles)

ben-rogerson avatar Aug 08 '22 06:08 ben-rogerson

sounds good i'll put one together :)

lukesmurray avatar Aug 09 '22 02:08 lukesmurray

Started working on this but ran into an issue with vite and linaria. I submitted an issue to linaria https://github.com/callstack/linaria/issues/1044.

lukesmurray avatar Aug 09 '22 14:08 lukesmurray

Ok I gave this a first shot in a public repo (codesandbox demo). I can add that code to the examples repo but there were so many things that didn't work that the default example app used in all the other examples didn't seem like a reasonable place to start. Feel free to fork my code. I can add a license of your choosing to it if that is an issue. But I don't place any claims on it at all.

Note: The linaria -> vite integration only works with the beta version, not with the 4.0 release but the API between the last beta and the current release seems to be identical. This is due to this issue https://github.com/callstack/linaria/issues/1044

Things that work

  • global styles
  • css import
  • Styled import
  • interpolating arrays in css and styled imports
// array interpolation works πŸ‘ 
css`${[tw`bg-red-500`, tw`text-sm`]}`

Things that don't work

  • css prop
  • tw prop
  • using tw import to create styled objects

Potential issues

Linaria styled tags allow for conditional styling via prop interpolation functions. However, these functions only let you conditionally determine a css property value, not a css property name and property value. This limitation is due to the fact that linaria compiles prop interpolations into css variables and you can't represent a property name and value with a css variable.

// this works
const Title = styled.h1`
  color: ${props => (props.primary ? 'tomato' : 'black')};
`;

// this will never work
const Title = styled.h1`
  ${props => (props.primary ? tw`text-red-500` :  tw`text-black`)};
`;

Linaria css interpolation is not linked to components and doesn't have access to state or props. If you want to condtionally apply styles you need to separate each potential style into a separate css call and conditionally apply the class names using cx.

// this works
const Title = ({primary, children}) => {
  return <h1 className={cx(primary ? css`${tw`text-red-500`}` :  css`${tw`text-black`}`)}>{children}</h1>
}

// this will never work
const Title = ({primary, children}) => {
  return <h1 className={css`${primary ? tw`text-red-500` :  tw`text-black`}`}>{children}</h1>
}

So in summary I'm optimistic that we can get this working but we probably need to do some leg work to get the css prop working. Most likely we want the css prop to accept any of tw, css or an array of either. tw should probably be compiled into css when used at the top level and can be left alone when used inside of css. Arrays passed to the css prop should be merged with cx.

lukesmurray avatar Aug 09 '22 18:08 lukesmurray

if it's possible to implement support for the tw and css props without modifying tw.macro itself i could try to do that but i would need a little hint.

lukesmurray avatar Aug 10 '22 12:08 lukesmurray

There’s some great findings here Luke! You're right, further updates would need to be made in the twin.macro repo.

Let's put this on hold for a little while until I'm through the v3 updates - both me and the repo will be better primed to pick this up again and complete the new linaria preset.

ben-rogerson avatar Aug 12 '22 03:08 ben-rogerson