module Graphics.UI.Threepenny.Ext.Flexbox ( -- * Parent Properties ParentProps (..), -- ** Parent Property Constructors parentProps, display, flexDirection, flexWrap, justifyContent, alignItems, aligContent, -- * Child Properties ChildProps (..), -- ** Child Property Constructors childProps, order, flexGrow, flexShrink, flexBasis, alignSelf, -- * Core Functions ToStyle (..), setFlex, -- * Useful Abstractions flex, flex_p, flex_c, flex_pc ) where import qualified Clay.Common as CC import Clay.Display (Display) import qualified Clay.Display as CD import Clay.Flexbox (AlignContentValue, AlignItemsValue, AlignSelfValue, FlexDirection, FlexWrap, JustifyContentValue) import qualified Clay.Flexbox as CF import Clay.Property (unKeys, unPlain, unValue) import Clay.Size (LengthUnit, Size) import Clay.Stylesheet (Rule (Property), runS) import Data.Text (unpack) import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core hiding (column, row) -- |Convert to Threepenny style. class ToStyle a where toStyle :: a -> [(String, String)] -- |Convert a Clay Property to Threepnny style. instance ToStyle Rule where toStyle (Property k v) = [(unpack $ unPlain $ unKeys k, unpack $ unPlain $ unValue v)] -- |Properties for a parent. data ParentProps = ParentProps { pDisplay :: Display , pFlexDirection :: FlexDirection , pFlexWrap :: FlexWrap , pJustifyContent :: JustifyContentValue , pAlignItems :: AlignItemsValue , pAlignContent :: AlignContentValue } -- |Convert parent properties to Threepenny style. instance ToStyle ParentProps where toStyle p = concatMap toStyle $ concatMap runS [ CD.display $ pDisplay p , CF.flexDirection $ pFlexDirection p , CF.flexWrap $ pFlexWrap p , CF.justifyContent $ pJustifyContent p , CF.alignItems $ pAlignItems p , CF.alignContent $ pAlignContent p ] -- |Default properties for a parent. parentProps :: ParentProps parentProps = ParentProps { pDisplay = CD.flex , pFlexDirection = CF.row , pFlexWrap = CF.nowrap , pJustifyContent = CF.flexStart , pAlignItems = CF.stretch , pAlignContent = CF.stretch } display x = parentProps { pDisplay = x } flexDirection x = parentProps { pFlexDirection = x } flexWrap x = parentProps { pFlexWrap = x } justifyContent x = parentProps { pJustifyContent = x } alignItems x = parentProps { pAlignItems = x } aligContent x = parentProps { pAlignContent = x } -- |Properties for a child. data ChildProps = ChildProps { cOrder :: Int , cFlexGrow :: Int , cFlexShrink :: Int , cFlexBasis :: Size LengthUnit , cAlignSelf :: AlignSelfValue } -- |Convert child properties to Threepenny style. instance ToStyle ChildProps where toStyle c = concatMap toStyle $ concatMap runS [ CF.order $ cOrder c , CF.flexGrow $ cFlexGrow c , CF.flexShrink $ cFlexShrink c , CF.flexBasis $ cFlexBasis c , CF.alignSelf $ cAlignSelf c ] -- |Default properties for a child. childProps :: ChildProps childProps = ChildProps { cOrder = 1 , cFlexGrow = 0 , cFlexShrink = 1 , cFlexBasis = CC.auto , cAlignSelf = CC.auto } order x = childProps { cOrder = x } flexGrow x = childProps { cFlexGrow = x } flexShrink x = childProps { cFlexShrink = x } flexBasis x = childProps { cFlexBasis = x } alignSelf x = childProps { cAlignSelf = x } -- |Set Flexbox properties on an element. setFlex :: ToStyle a => a -> UI Element -> UI Element setFlex props el = el # set UI.style (toStyle props) -- |Attach elements to a parent element, applying given Flexbox properties. flex :: UI Element -- ^ Parent -> ParentProps -- ^ Parent Flexbox properties -> [(UI Element, ChildProps)] -- ^ Children and respective Flexbox properties -> UI Element -- ^ Parent with attached children flex p pProps cs = do p' <- p # setFlex pProps cs' <- mapM (\(c, cProps) -> c # setFlex cProps) cs element p' #+ map element cs' -- |Like 'flex' but apply default properties to the parent. flex_p :: UI Element -- ^ Parent -> [(UI Element, ChildProps)] -- ^ Children and respective Flexbox properties -> UI Element -- ^ Parent with attached children flex_p p = flex p parentProps -- |Like 'flex' but apply default properties to the children. flex_c :: UI Element -- ^ Parent -> ParentProps -- ^ Parent Flexbox properties -> [UI Element] -- ^ Children -> UI Element -- ^ Parent with attached children flex_c p pProps cs = flex p pProps $ zip cs $ repeat childProps -- |Like 'flex' but apply default properties to the parent and children. flex_pc :: UI Element -- ^ Parent -> [UI Element] -- ^ Children -> UI Element -- ^ Parent with attached children flex_pc p = flex_c p parentProps