reflex-dom-contrib-0.1: src/Reflex/Contrib/Interfaces.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
module Reflex.Contrib.Interfaces
( ReflexMap(..)
, ReflexList(..)
, rlist2rmap
, toReflexMap
, rmDeleteFunc
, selectViewListWithKey
) where
------------------------------------------------------------------------------
import Data.Map (Map)
import qualified Data.Map as M
import Data.Set (Set)
import qualified Data.Set as S
import Reflex
import Reflex.Dom
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- | A reflex interface to lists. It has a pure list of initial items, an
-- event for inserting multiple items, and an event for deleting multiple
-- items.
data ReflexList t v = ReflexList
{ rlInitialItems :: [v]
, rlInsertItems :: Event t [v]
, rlDeleteItems :: Event t [v]
}
------------------------------------------------------------------------------
-- | Converts a ReflexList to a ReflexMap with integer keys.
rlist2rmap
:: (Reflex t, Eq v)
=> ReflexList t v
-> Dynamic t (Map Int v)
-> ReflexMap t Int v
rlist2rmap ReflexList{..} curMap = ReflexMap
{ rmInitialItems = M.fromList $ zip [0..] rlInitialItems
, rmInsertItems = attachDynWith f curMap rlInsertItems
, rmDeleteItems = attachDynWith g curMap rlDeleteItems
}
where
f m is = zip [nextKey m..] is
g m is = M.keysSet $ M.filter (`elem` is) m
nextKey m = succ $ fst (M.findMax m)
------------------------------------------------------------------------------
-- | A reflex interface to maps that allows inserting and deleting multiple
-- items at a time.
data ReflexMap t k v = ReflexMap
{ rmInitialItems :: Map k v
, rmInsertItems :: Event t [(k,v)]
-- ^ We use a list of key-value pairs here because order is important
, rmDeleteItems :: Event t (Set k)
}
------------------------------------------------------------------------------
-- | Converts a ReflexList to a Dynamic list.
toReflexMap
:: (MonadWidget t m, Eq a)
=> ReflexList t a
-> (ReflexMap t Int a -> m (Dynamic t (Map Int a)))
-> m (Dynamic t [a])
toReflexMap rlist f = do
rec let rmap = rlist2rmap rlist m
m <- f rmap
mapDyn M.elems m
------------------------------------------------------------------------------
-- | Takes a set of keys and returns a function that deletes these keys from
-- a map.
rmDeleteFunc :: Ord k => Set k -> Map k v -> Map k v
rmDeleteFunc s m = foldr M.delete m (S.toList s)
------------------------------------------------------------------------------
-- | A generalized version of the one in reflex-dom.
selectViewListWithKey
:: forall t m k v a. (MonadWidget t m, Ord k)
=> Dynamic t k
-> Dynamic t (Map k v)
-> (k -> Dynamic t v -> Dynamic t Bool -> m a)
-> m (Dynamic t (Map k a))
selectViewListWithKey selection vals mkChild = do
let selectionDemux = demux selection
listWithKey vals $ \k v -> do
selected <- getDemuxed selectionDemux k
mkChild k v selected