Skip to content

Instantly share code, notes, and snippets.

@hew
Last active April 29, 2019 19:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hew/3d2b8c00b62e58fd45fb73fefc71d203 to your computer and use it in GitHub Desktop.
Save hew/3d2b8c00b62e58fd45fb73fefc71d203 to your computer and use it in GitHub Desktop.
Reason React Native Styled System (Beta)

Reason React Native Styled System (Beta)

[@bs.module "react-native-responsive-fontsize"]
external rf: float => float = "default";
module type Config = {let scale: array(int);};
module TextMaker = (Config: Config) => {
open Belt.Option;
let systemize = shorthand =>
shorthand->mapWithDefault(0, m =>
switch (m) {
| 1
| 2
| 3
| 4
| 5 => Config.scale[m]
| _ => m
}
)
|> float_of_int;
let systemizeFont = v =>
v->mapWithDefault(16, m =>
switch (m) {
| 1
| 2
| 3
| 4
| 5 => Config.scale[m]
| _ => m
}
)
|> float_of_int;
let systemizeSize = v => v |> systemize |> Style.Size.pct;
let systemizeMargin = v => v |> systemize |> Style.Margin.pct;
[@react.component]
let make =
(
~py=?,
~px=?,
~p=?,
~mt=?,
~mb=?,
~ml=?,
~mr=?,
~size=?,
~style as styl: Style.t=?,
~color as clr=?,
~weight=?,
~align=?,
~children,
(),
) =>
<Text
style=Style.(
listOption([
mt->isSome
? Some(style(~marginTop=systemizeMargin(mt), ())) : None,
mb->isSome
? Some(style(~marginBottom=systemizeMargin(mb), ())) : None,
ml->isSome
? Some(style(~marginLeft=systemizeMargin(ml), ())) : None,
mr->isSome
? Some(style(~marginRight=systemizeMargin(mr), ())) : None,
p->isSome ? Some(style(~padding=systemizeSize(p), ())) : None,
py->isSome
? Some(style(~paddingTop=systemizeSize(py), ())) : None,
py->isSome
? Some(style(~paddingBottom=systemizeSize(py), ())) : None,
px->isSome
? Some(style(~paddingLeft=systemizeSize(px), ())) : None,
px->isSome
? Some(style(~paddingRight=systemizeSize(px), ())) : None,
size->isSome
? Some(style(~fontSize=systemizeFont(size), ())) : None,
clr->isSome
? Some(
style(
~color=clr->mapWithDefault("black", v => v) |> color,
(),
),
)
: None,
weight->isSome
? Some(
style(
~fontWeight=weight->mapWithDefault(`normal, w => w),
(),
),
)
: None,
align->isSome
? Some(
style(~textAlign=align->mapWithDefault(`center, w => w), ()),
)
: None,
Some(styl),
])
)>
children
</Text>;
};
module BoxMaker = (Config: Config) => {
open Belt.Option;
let systemize = shorthand =>
shorthand->mapWithDefault(0, m =>
switch (m) {
| 1
| 2
| 3
| 4
| 5 => Config.scale[m]
| _ => m
}
)
|> float_of_int;
let systemizeSize = v => v |> systemize |> rf |> Style.Size.pt;
let systemizeMargin = v => v |> systemize |> rf |> Style.Margin.pt;
[@react.component]
let make =
(
~py=?,
~px=?,
~p=?,
~mt=?,
~mb=?,
~ml=?,
~mr=?,
~bgColor=?,
~width=?,
~flex=?,
~content=?,
~direction=?,
~style as styl: Style.t=?,
~children=?,
(),
) =>
<View
style=Style.(
listOption([
mt->isSome
? Some(style(~marginTop=systemizeMargin(mt), ())) : None,
mb->isSome
? Some(style(~marginBottom=systemizeMargin(mb), ())) : None,
ml->isSome
? Some(style(~marginLeft=systemizeMargin(ml), ())) : None,
mr->isSome
? Some(style(~marginRight=systemizeMargin(mr), ())) : None,
p->isSome ? Some(style(~padding=systemizeSize(p), ())) : None,
py->isSome
? Some(style(~paddingTop=systemizeSize(py), ())) : None,
py->isSome
? Some(style(~paddingBottom=systemizeSize(py), ())) : None,
px->isSome
? Some(style(~paddingLeft=systemizeSize(px), ())) : None,
px->isSome
? Some(style(~paddingRight=systemizeSize(px), ())) : None,
width->isSome
? Some(
style(
~width=width->mapWithDefault(100., v => v) |> Size.pct,
(),
),
)
: None,
bgColor->isSome
? Some(
style(
~backgroundColor=
bgColor->mapWithDefault("black", v => v) |> color,
(),
),
)
: None,
content->isSome
? Some(
style(
~justifyContent=content->mapWithDefault(`flexStart, w => w),
(),
),
)
: None,
direction->isSome
? Some(
style(
~flexDirection=direction->mapWithDefault(`column, w => w),
(),
),
)
: None,
flex->isSome
? Some(style(~flex=flex->mapWithDefault(1., w => w), ())) : None,
Some(styl),
])
)>
{switch (children) {
| Some(child) => child
| None => React.null
}}
</View>;
};
module Box =
BoxMaker({
let scale = System.Scale.space;
});
module Txt =
TextMaker({
let scale = System.Scale.font;
});
@hew
Copy link
Author

hew commented Apr 24, 2019

@yawaramin

Avoid opening modules across such wide scopes, especially library modules like Belt.Option. IF you need a shorthand try aliasing it to a module, e.g. module BeltOpt = Belt.Option;

Slightly off topic, but I sometimes see a flag in other people's bsconfig that is something to the effect of "-belt-open" and I always assumed it made Belt essentially globally available. Have you ever heard of that flag?

@yawaramin
Copy link

@hew Yes, this flag is sometimes used to 'overlay' a new set of standard modules on top of the built-in ones that are available in OCaml. Typically it's desirable to open modules which will have as little effect on the global namespace as possible. So, open Belt is not too bad because it brings a small number of top-level modules into scope (as seen in https://bucklescript.github.io/bucklescript/api/Belt.html ). But open Belt.Option is a bit more frowned on because it will bring a large number of functions into scope. And at module scope it will pollute your namespace with lots of names. The more this is done, the harder it is to track where names are coming from and you have to keep referring to other parts of the code when you're reading some function, to figure it out.

@hew
Copy link
Author

hew commented Apr 24, 2019

I think I understand now. the global open only adds like 4 more things to the namespace, but Belt.Option has a bunch of functions, and opening it floods any given namespace with all of them. I'll default to something like let Opt = Belt.Option in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment