Skip to content

jerbaroo/threepenny-gui-flexbox

Repository files navigation

Threepenny-gui Flexbox

CircleCI Hackage Stackage Nightly Stackage LTS

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.

Usage

Properties

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

Setting Properties

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)

'flex'

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")]