Coder Social home page Coder Social logo

elliottcable / bs-emotion Goto Github PK

View Code? Open in Web Editor NEW

This project forked from ahrefs/bs-emotion

0.0 2.0 0.0 1.5 MB

BuckleScript bindings to Emotion

License: MIT License

OCaml 3.23% HTML 0.24% C++ 0.09% JavaScript 1.66% Shell 0.18% Reason 94.61%

bs-emotion's Introduction

bs-emotion

bs-emotion status bs-emotion-ppx status

BuckleScript bindings to Emotion.

BuckleScript v8+

bs-emotion and bs-emotion-ppx are compatible with BuckleScript v7 starting from version 2.0.0.

Previous versions

Use v1.0.1 if you need compatibility with BuckleScript v7.

If you need to use them with BuckleScript v5 or below, install the earlier versions:

  • @ahrefs/bs-emotion version ^0.1.2
  • @ahrefs/bs-emotion-ppx version ^0.0.7

Installation

Get the package:

# yarn
yarn add @ahrefs/bs-emotion
# or npm
npm install --save @ahrefs/bs-emotion

Then add it to bsconfig.json:

"bs-dependencies": [
  "@ahrefs/bs-emotion"
]

bs-emotion-ppx

If you want to auto-label generated classnames for easier debugging, you can install bs-emotion-ppx:

# yarn
yarn add --dev @ahrefs/bs-emotion-ppx
# or npm
npm install --save-dev @ahrefs/bs-emotion-ppx

Then add it to bsconfig.json:

"ppx-flags": ["@ahrefs/bs-emotion-ppx/ppx"],

Usage

Defining styles

There are 2 ways to define a CSS class:

open Emotion

(* If you use ppx *)
let button = [%css [ ... ]] (* -> "css-HASHED-button" *)

(* If you don't use ppx *)
let button = css [ ... ] (* -> "css-HASHED" *)

And here's real-world example:

It's in OCaml syntax, but you can use Reason too.

(* ComponentStyles.ml *)

open Emotion

let container = [%css [
  display `flex;
  flexFlow `column `nowrap;
  alignItems `center;
]]

let shape = [%css [
  display `flex;
  flexFlow `row `nowrap;
  alignItems `center;
  justifyContent `center;
  transitionProperty "border-radius";
  transitionDuration (`ms 100);
  transitionTimingFunction `easeInOut;
  width (`px 200);
  height (`px 200);
  borderRadius (`px 6);
  backgroundColor (`hex "29d");

  (* :hover selector, same as `select ":hover" [ ... ]` *)
  hover [
    borderRadius (`pct 50.);
    important (cursor `grab);
  ];
]]

(* Dynamic styling *)
(* NOTE: ppx supports functions with max 2 arguments *)
let text ~size = [%css [
  color (`hex "fff");
  fontSize (`px size);
  fontWeight 700;

  (* Transition takes property, duration, timing-function & delay *)
  transition "font-size" (`ms 100) `easeInOut `zero;

  (* You can define multiple transitions by packing them into list of tuples *)
  transitions [
    ("font-size", `ms 100, `easeInOut, `ms 0);
  ];

  (* Complex selector that uses .container class defined above *)
  (* Rendered as: `.container:hover .text {...}` *)
  select {j|.$container:hover &|j} [
    fontSize Calc.(((`px size) + (`pct 150.)) * (`n 1.5));
  ];

  (* @media quiery with nested selectors *)
  media "(max-width: 900px)" [
    color (`hex "ff69b4");

    select ":hover" [
      color (`hex "fff");
    ];
  ];
]]

(* Define keyframes *)
let bounce = keyframes [
  (0,   [ transform (`translateY `zero); ]);
  (50,  [ transform (`translateY (`px (-20))); ]);
  (100, [ transform (`translateY `zero); ]);
]

let animated = [%css [
  (* Use generated animation name *)
  animationName bounce;
  animationDuration (`ms 300);
  animationIterationCount (`i 7);
]]

(* Compose things *)
let smallText = [%css [
  fontSize (`em 0.8);
]]

let note = css ~extend: smallText [
  label "note";

  marginTop (`px 10);
]

Applying styles

/* Component.re */

module Css = ComponentStyles;

let component = ReasonReact.statelessComponent(__MODULE__);

let make = _ => {
  ...component,
  render: _ => <div className=Css.container> ... </div>,
};

Composing classnames

Cx

This package provides Cx.merge function which is a binding to Emotion's cx. It merges 2 Emotion's CSS classes into single unique class. See the Caveats section for details.

Cn

Also, there is re-classnames. You can use it to combine classnames together. It's not aware of Emotion and simply operates on strings.

Caveats

First, let's talk about the difference between Cn.make and Cx.merge:

Cn.make([Css.one, Css.two]) /* => "css-<HASH>-one css-<HASH>-two" */
Cx.merge([|Css.one, Css.two|]) /* => "css-<HASH>-one-two" */

If the former simply concatenates two classname strings into a single string (and as a result 2 CSS classes are applied) then the latter merges 2 Emotion classes into single unique class and applies it to a node (as a result 1 unique CSS class is applied).

Caveat #1
<div className={Cx.merge([|Css.foo, Css.bar|])}>
  <button className=Css.button />
</div>
let foo = css [ ... ]
let bar = css [ ... ]

let button = css [
  ...

  select {j|.$foo:hover &|j} [
    (*
      It won't work due to `.foo` class is being merged w/ `.bar`
      into single unique classname inside component
    *)
  ]
]

To make this css work you can use Cn.make, e.g:

<div className={Cn.make([Css.foo, Css.bar])} />
Caveat #2
let make = (~className, children) => {
  ...component,
  render: _ =>
    <div className={Cn.make([Css.foo, className])}>
      ...children
    </div>,
};

Oftentimes, UI abstractions accept className prop to extend or override default CSS of abstraction. Since position of classname on application site doesn't guarantee precedence of className prop (in CSS, precedence is determined by position of classname on definition site), it's not safe to use Cn.make here. In this case, use Cx.merge since Emotion determines precedence on application site and guarantees that last classname has precedence over the preceding classes.

<div className={Cx.merge([|Css.foo, className|])} />

Contributing

See CONTRIBUTING.md.

Thanks

bs-emotion's People

Contributors

alex35mil avatar anmonteiro avatar believer avatar dependabot[bot] avatar jchavarri avatar jsiebern avatar nikgraf avatar parkerziegler avatar rusty-key avatar ulrikstrid avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.