Flexbox layouts for Threepenny-gui.
This library was written following the wonderful A Complete Guide to Flexbox and using the equally wonderful Clay library as a CSS domain specific language.
Ultimately we just want to set Flexbox properties on elements, both parent and
child elements. In CSS these properties would look like flex-grow: 1;
.
We collect Flexbox properties that apply to the parent element, things like
flex-direction
, in a ParentProps
data type. Flexbox properties that apply to
child elements, things like flex-grow
, are collected in a ChildProps
data
type.
If you want ChildProps
with flex-grow: 1;
you can just do:
flexGrow 1
You can define multiple properties using (<>)
:
order 1 <> flexGrow 1 <> flexShrink 2
Some properties like flexGrow
simply take an Int
but others take a value
from the Clay
library. Here's an example for ParentProps
:
display Clay.Display.inlineFlex <> flexWrap Clay.Flexbox.nowrap
If you just want ParentProps
or ChildProps
with default values:
parentProps :: ParentProps
childProps :: ChildProps
Once you have your properties defined you'll want to apply them to elements. For
this you can use setFlex
which can be used with Threepenny's reverse function
application operator #
:
UI.div # set UI.text "foo" # setFlex (flexGrow 1)
Note that setFlex
will set any properties you don't specify explictly to the
default values from parentProps
or childProps
. If that is undesirable (for
instance, in case you have already used setFlex
elsewhere to set several
properties and only want to change a few of them), you can instead use
modifyFlex
, which leaves unspecified properties unchanged:
myRow = UI.div # setFlex (
flexDirection Clay.Flexbox.row
<> flexWrap Clay.Flexbox.wrap
<> justifyContent Clay.Flexbox.spaceBetween
<> alignItems Clay.Common.baseline
)
-- Elsewhere:
myRow # modifyFlex (alignItems Clay.Common.center)
You can also convert ParentProps
or ChildProps
to a [(String, String)]
which
is
how Threepenny expects CSS.
This can be done using toStyle
:
UI.div # set UI.style (toStyle $ order 1)
We provide a utility function flex
(and a few variants thereof) which takes
both parent and child elements and their respective ParentProps
and
ChildProps
, applies the properties through setFlex
to the respective
elements and then returns the parent element with children attached.
Here is a full example, which produces the above image of three orange text
boxes in ratio 1:2:1. First done without flex_p
and then with flex_p
.
flex_p
is a variant of flex
which applies default Flexbox properties to the
parent element.
-- |Example without 'flex_p'.
example :: Window -> UI ()
example w = void $
getBody w # setFlex parentProps #+ [
foo # setFlex (flexGrow 1)
, foo # setFlex (flexGrow 2)
, foo # setFlex (flexGrow 1)
]
-- |Example with 'flex_p'.
example' :: Window -> UI ()
example' w = void $
flex_p (getBody w) [
(foo, flexGrow 1)
, (foo, flexGrow 2)
, (foo, flexGrow 1)
]
-- | Simple coloured 'div'.
foo = UI.div # set UI.text "foo"
# set UI.style [("background-color", "#F89406"),
("margin", "8px")]