andywer / ideabox

Place to collect techy ideas and get feedback.
1 stars 1 forks source link

ReactCSSDOM #15

Open andywer opened 6 years ago

andywer commented 6 years ago

Extend react-dom to provide a generic, fully featured, declarative styling API that is as easy to use as inline styles, but comes with the power of CSS classes:

import React from 'react'

const MyButton = ({ children, primary }) => {
  return (
    <button css={{
      padding: '0 40px',
      background: primary ? '#ff7259' : '#00A1CB',
      border: 'none',
      border-radius: 3,
      color: 'rgba(255, 255, 255, 0.8)',
      ':hover': {
        color: 'rgba(255, 255, 255, 1)'
      }
    }}>{children}</button>
  )
}
export default MyButton

To render your app:

import * as ReactCSSDOM from 'react-css-dom'    // instead of react-dom
import MyButton from './Button'

ReactCSSDOM.render(
  <MyButton>Click me</MyButton>,
  document.getElementById('demo')
)

Server-side rendering should also be really simple. Something like that:

import * as ReactCSSDOM from 'react-css-dom'    // instead of react-dom
import MyButton from './Button'

const stylesheet = ReactCSSDOM.createStylesheet()
const rendered = ReactCSSDOM.renderToString(<MyButton>Click me</MyButton>, stylesheet)

const html = `
<!doctype html>
<html>
  <head>
    ${stylesheet.toStyleTag()}
  </head>
  <body>
    ${rendered}
  </body>
</html>
`

Benefits

andywer commented 6 years ago

Difference between ReactDOM & ReactCSSDOM

Compatibility

Implementation details

stereobooster commented 6 years ago

Question: how to generate @ rules like keyframes or font-face?

For inspiration:

andywer commented 6 years ago

@stereobooster This is a good question indeed and I am not completely sure yet.

I have been thinking about using native „pseudo elements“, though:

const spin = React.createRef()

const Spinner = () => (
  <div css={{ animationName: spin, animationDuration: 2s }} />
)

ReactCSSDOM.render(
  <>
    <keyframes
      ref={spin}
      steps={{
        '0%': {
          transform: 'rotate(0deg)'
        },
        '100%': {
          transform: 'rotate(360deg)'
        }
      }}
    />
    <Spinner />
  </>
)

The example uses React 16.3‘s new createRef() API. Not sure if this would be the best way to go, though. Just spitballing here 😉

giuseppeg commented 6 years ago

nice! styled-jsx manages styles in a similar way https://github.com/zeit/styled-jsx/blob/master/src/stylesheet-registry.js

andywer commented 6 years ago

@stereobooster I think this works better for at-rules:

const Spinner = () => (
  <keyframes
    steps={{
      '0%': {
        transform: 'rotate(0deg)'
      },
      '100%': {
        transform: 'rotate(360deg)'
      }
    }}
  >{spin => (
    <div css={{ animationName: spin, animationDuration: 2s }} />
  )}</keyframes>
)

It uses the children prop as render prop, very much like React 16.3's new context API does. Also this code snippet resembles a real-world use case better than the previous one.