Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/giraud/bs-css
Statically typed DSL for writing css in reason.
https://github.com/giraud/bs-css
Last synced: 16 days ago
JSON representation
Statically typed DSL for writing css in reason.
- Host: GitHub
- URL: https://github.com/giraud/bs-css
- Owner: giraud
- License: isc
- Created: 2017-10-25T16:16:17.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2023-10-17T12:53:14.000Z (about 1 year ago)
- Last Synced: 2024-04-14T09:31:54.589Z (7 months ago)
- Language: ReScript
- Homepage:
- Size: 4.94 MB
- Stars: 589
- Watchers: 6
- Forks: 103
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - bs-css
README
# bs-css
Statically typed DSL for writing css in reason and rescript.
The bs-css library contains type css core definitions, it has different implementations:
- bs-css-emotion is a typed interface to [Emotion](https://github.com/emotion-js/emotion)
- bs-css-fela is a typed interface to [Fela](https://github.com/robinweser/fela) (react)
- bs-css-dom is a typed interface to `ReactDOMRe.Style.t` (reason-react)If you know another implementation that can be added, send a link in an issue or create a PR.
## Installation
```sh
npm install --save bs-css bs-css-emotion
or
yarn add bs-css bs-css-emotion
```In your `bsconfig.json`, include `"bs-css"` and `"bs-css-emotion"` in the `bs-dependencies`.
You can replace `bs-css-emotion` with `bs-css-dom` in the above instructions if you prefer
to use React styles, or `bs-css-fela` for a different runtime.## Usage for bs-css-emotion
```rescript
module Theme = {
let basePadding = CssJs.px(5)
let textColor = CssJs.black
}module Styles = {
/*
Open the Css module, so we can access the style properties below without prefixing them with Css.
You can use either Css or CssJs: Css module is using lists, CssJs is using arrays.
If you're targeting js and/or using Rescript, prefer CssJs
*/
open CssJslet card = style(. [
display(flexBox),
flexDirection(column),
alignItems(stretch),
backgroundColor(white),
boxShadow(Shadow.box(~y=px(3), ~blur=px(5), rgba(0, 0, 0, #num(0.3)))),
// You can add non-standard and other unsafe style declarations using the `unsafe` function, with strings as the two arguments
unsafe("-webkit-overflow-scrolling", "touch"),
// You can place all your theme styles in Theme.re and access as normal module
padding(Theme.basePadding),
])let title = style(. [
fontSize(rem(1.5)),
lineHeight(#abs(1.25)),
color(Theme.textColor),
marginBottom(Theme.basePadding),
])let actionButton = disabled =>
style(. [
background(disabled ? darkgray : white),
color(black),
border(px(1), solid, black),
borderRadius(px(3)),
])
}@react.component
let make = () =>
{React.string("Hello")}
```**Global css**
You can define global css rules with `global`
```rescript
open CssJsglobal(. "body", [margin(px(0))])
global(. "h1, h2, h3", [color(rgb(33, 33, 33))])
```**Keyframes**
Define animation keyframes;
```rescript
open CssJslet bounce = keyframes(. [
(0, [transform(scale(0.1, 0.1)), opacity(0.0)]),
(60, [transform(scale(1.2, 1.2)), opacity(1.0)]),
(100, [transform(scale(1.0, 1.0)), opacity(1.0)]),
])let styles = style(. [
animationName(bounce),
animationDuration(2000),
width(px(50)),
height(px(50)),
backgroundColor(rgb(255, 0, 0)),
])// ...
{React.string("bounce!")}
```**Css attributes**
For some CSS parameters (like setting padding on an input field), one needs to use CSS attributes like so:
```css
input[type="text"] {
padding:20px;
}
```The `selector` function can be used:
```rescript
open CssJs
let styles = style(. [selector("input[type='text']", [padding(px(20))])])
```### Merging styles
You should avoid trying to merge styles in the same list of rules or by concatinating lists. A list of rules is converted into a JS object before being passed to Emotion where every property becomes a key in the object. This means you lose any earlier rule if you have another rule with the same property later in the list. This is especially noticable [when writing sub-selectors and media queries](https://github.com/SentiaAnalytics/bs-css/issues/86)
Trying to merge styles by just using concatenation can result in unexpected results.
This example:
```rescript
open CssJslet base = [
padding(px(0)),
fontSize(px(1))
]
let overrides = [
padding(px(20)),
fontSize(px(24)),
color(blue)
]
let media1 = [
media("(max-width: 768px)", [
padding(px(10))
])
]
let media2 = [
media("(max-width: 768px)", [
fontSize(px(16)),
color(red)
])
]
let mergedStyles = style(. Belt.Array.concatMany([base, overrides, media1, media2]))
```generates the following:
```css
.css-1nuk4bg {
padding: 20px;
font-size: 24px;
color: #0000ff;
}
@media (max-width: 768px) {
.css-1nuk4bg {
font-size: 16px;
color: #ff0000;
}
}
```As you can see both properties from `base` are overwritten (as opposed to overridden in css) and the media query in `media1` is also lost because the media query from `media2` overwrites it.
#### The `merge` method
`merge` safely merges styles by name. Uses [Emotion’s `cx` method](https://emotion.sh/docs/cx).
```reason
open CssJslet mergedStyles = merge(. [
style(. [padding(px(0)), fontSize(px(1))]),
style(. [padding(px(20)), fontSize(px(24)), color(blue)]),
style(. [media("(max-width: 768px)", [padding(px(10))])]),
style(. [media("(max-width: 768px)", [fontSize(px(16)), color(red)])]),
])
```Generates the following:
```css
.css-q0lkhz {
padding: 0px;
font-size: 1px;
padding: 20px;
font-size: 24px;
color: #0000ff;
}
@media (max-width: 768px) {
.css-q0lkhz {
padding: 10px;
}
}
@media (max-width: 768px) {
.css-q0lkhz {
font-size: 16px;
color: #ff0000;
}
}
```Nothing is lost and everything ends up in the final stylesheet where normal overrides apply.
## Usage for bs-css-fela
First you need to use a provider in your Jsx:
```rescript
let renderer = createRenderer()switch ReactDOM.querySelector("#app") {
| None => ()
| Some(dom) =>
ReactDOM.render( ... , dom)
}
```Then, you need to use the useFela hook in your Jsx:
```rescript
module Styles = {
/*
Open the Css module, so we can access the style properties below without prefixing them with Css.
You can use either Css or CssJs: Css module is using lists, CssJs is using arrays.
If you're targeting js and/or using Rescript, prefer CssJs
*/
open CssJslet card = style(. [
display(flexBox),
flexDirection(column),
alignItems(stretch),
backgroundColor(white),
boxShadow(Shadow.box(~y=px(3), ~blur=px(5), rgba(0, 0, 0, #num(0.3)))),
// You can add non-standard and other unsafe style declarations using the `unsafe` function, with strings as the two arguments
unsafe("-webkit-overflow-scrolling", "touch"),
// You can place all your theme styles in Theme.re and access as normal Reason module
padding(Theme.basePadding),
])let title = style(. [
fontSize(rem(1.5)),
lineHeight(#abs(1.25)),
color(Theme.textColor),
marginBottom(Theme.basePadding),
])let actionButton = disabled =>
style(. [
background(disabled ? darkgray : white),
color(black),
border(px(1), solid, black),
borderRadius(px(3)),
])
}@react.component
let make = () => {
let {css, _} = CssReact.useFela()
{React.string("Hello")}
}
```**Global css**
You can define global css rules with `global`
```rescript
open CssJs
let renderer = createRenderer()renderGlobal(. renderer, "body", [margin(px(0))])
renderGlobal(. renderer, "h1, h2, h3", [color(rgb(33, 33, 33))])
```## Usage for bs-css-dom
Use style instead of classname, for example:
```rescript
module Styles = {
// Open the Css module, so we can access the style properties below without prefixing them with Css
open CssJslet card = style(. [
display(flexBox),
flexDirection(column),
alignItems(stretch),
backgroundColor(white),
boxShadow(Shadow.box(~y=px(3), ~blur=px(5), rgba(0, 0, 0, #num(0.3)))),
// You can add non-standard and other unsafe style declarations using the `unsafe` function, with strings as the two arguments
unsafe("-webkit-overflow-scrolling", "touch"),
// You can place all your theme styles in Theme.re and access as normal Reason module
padding(Theme.basePadding),
])let title = style(. [fontSize(rem(1.5)), color(Theme.textColor), marginBottom(Theme.basePadding)])
let actionButton = disabled =>
style(. [
background(disabled ? darkgray : white),
color(black),
border(px(1), solid, black),
borderRadius(px(3)),
])
}@react.component
let make = () =>
{React.string("Hello")}
```## Where is the documentation?
You can check out [Css_Js_Core.rei](bs-css/src/Css_Js_Core.rei) and [Css_Legacy_Core.rei](bs-css/src/Css_Legacy_Core.rei).
## Thanks
Thanks to [emotion](https://github.com/emotion-js/emotion) which is doing all the heavy lifting.
Thanks to [bs-glamor](https://github.com/poeschko/bs-glamor) which this repo was forked from.
Thanks to [elm-css](https://github.com/rtfeldman/elm-css) for dsl design inspiration.