davesnx / styled-ppx

Type-safe styled components for ReScript, Melange and native with type-safe CSS
https://styled-ppx.vercel.app
BSD 2-Clause "Simplified" License
398 stars 31 forks source link

CSS Extraction at build-time #433

Open davesnx opened 4 months ago

davesnx commented 4 months ago

We can remove the runtime completely and go for static styles. Generate CSS files in the _build folder (for Melange/native) and in-source in ReScript.

Design

styled.div

module C = [%styled.div "height: 100%"]
(* pushes into the Stylesheet ".div12312 {height: 100%}" *)
(* module C = <div className=".div12312" /> *)

module C = [%styled.div (~what) => "width: $(what); height: 100%"]
(* pushes static properties ".div12312 {height: 100%}" *)
(* generates dynamic properties with CSS vars ".div12345 {width: (--var-what)}" *)
(* module C = <div className=".div12312" style={ReactDOM.Style.make("--var-what": what)} /> *)

cx

let cx = [%cx "height: 100%"]
(* pushes properties ".hash {height: 100%}" *)
(* let cx = ".hash" *)

Ideal plan

Some JavaScript implementations

davesnx commented 3 days ago

The problem remaining to solve is the static interpolation:

let small = `px 10 in
let classname = [%cx {| margin: $(small); |}];

How can we access small, and turn it into a CSS variable?

Possible solutions

let%cx classname = {
  let lola = small in
  {| font-size: $(lola) |}
};

let%css_var = `px 10 in
(* let small = CssJs.publishGlobalVar (__MODULE__ ++ "-small",`px 10); `px 10 in *)

let classname = [%cx {| margin: var(--small); |}]

(Problems of hashing name, and others)


let classname = [%cx {| margin: $(small); |}] @@ { small: small }