on develop help sign in
Merge remote-tracking branch 'origin/develop' into ts-hydration
dbae6d3Tom Smalley
Quickref.md+1−1
@@ -28,7 +28,7 @@ Widgets may return any type (this is 'a' in many of the functions below). Often
28-- This version returns the 'El' as well.
28-- This version returns the 'El' as well.
29[W] el' :: Text -> m a -> m (El, a)
29[W] el' :: Text -> m a -> m (El, a)
30
30
31−-- These two additionally apply attributes to the element, such as ("class" =: "blah")
31+-- These two additionally apply attributes to the element, such as ("class" =: "blah"). (=:) is 'Map.singleton'
32[W] elAttr :: Text -> Map Text Text -> m a -> m a
32[W] elAttr :: Text -> Map Text Text -> m a -> m a
33[W] elAttr' :: Text -> Map Text Text -> m a -> m (El, a)
33[W] elAttr' :: Text -> Map Text Text -> m a -> m (El, a)
34
34
README.md+8−3
@@ -1,12 +1,12 @@
1−## Reflex-DOM
1+## [Reflex-DOM](https://reflex-frp.org)
2### A Framework for Functional Reactive Web Apps in Haskell
2### A Framework for Functional Reactive Web Apps in Haskell
3
3
4Reflex-DOM is a framework for building web applications in Haskell, based on the [Functional Reactive Programming](https://wiki.haskell.org/Functional_Reactive_Programming) library [Reflex](https://github.com/reflex-frp/reflex).
4Reflex-DOM is a framework for building web applications in Haskell, based on the [Functional Reactive Programming](https://wiki.haskell.org/Functional_Reactive_Programming) library [Reflex](https://github.com/reflex-frp/reflex).
5
5
6−Comprehensive documentation is still a work in progress, but a [demo](https://github.com/reflex-frp/reflex-platform) is available and an introductory talk is available at [Part 1](https://www.youtube.com/watch?v=mYvkcskJbc4) / [Part 2](https://www.youtube.com/watch?v=3qfc9XFVo2c) ([Slides](https://obsidian.systems/reflex-nyhug/)).
7−
8A summary of Reflex-DOM functions is available in the [quick reference](Quickref.md).
6A summary of Reflex-DOM functions is available in the [quick reference](Quickref.md).
9
7
8+**Visit https://reflex-frp.org/ for more information, tutorials, documentation and [examples](https://examples.reflex-frp.org/).**
9+
10### Additional resources
10### Additional resources
11[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
11[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
12
12
@@ -15,3 +15,8 @@ A summary of Reflex-DOM functions is available in the [quick reference](Quickref
15[hackage](https://hackage.haskell.org/package/reflex)
15[hackage](https://hackage.haskell.org/package/reflex)
16
16
17[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
17[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
18+
19+### Hacking
20+
21+Use the `./scripts/hack-on dep/reflex-dom` script in [Reflex Platform](https://github.com/reflex-frp/reflex-platform) to checkout the source code of `reflex-dom` locally in `./dep/reflex-dom` directory.
22+Then do modifications to the source in place, and use the `./try-reflex` or `./scripts/work-on` scripts to create the shell to test your changes.
reflex-dom-core/reflex-dom-core.cabal−1
@@ -98,7 +98,6 @@ library
98 Reflex.Dom.Core
98 Reflex.Dom.Core
99 Reflex.Dom.Location
99 Reflex.Dom.Location
100 Reflex.Dom.Main
100 Reflex.Dom.Main
101− Reflex.Dom.Modals.Base
102 Reflex.Dom.Modals.Class
101 Reflex.Dom.Modals.Class
103 Reflex.Dom.Old
102 Reflex.Dom.Old
104 Reflex.Dom.Prerender
103 Reflex.Dom.Prerender
reflex-dom-core/src/Foreign/JavaScript/Orphans.hs+1
@@ -1,3 +1,4 @@
1+{-# OPTIONS_HADDOCK hide #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE CPP #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# OPTIONS_GHC -fno-warn-orphans #-}
4{-# OPTIONS_GHC -fno-warn-orphans #-}
reflex-dom-core/src/Reflex/Dom/Core.hs−1
@@ -12,7 +12,6 @@ import Reflex.Dom.Builder.Static as X
12import Reflex.Dom.Class as X
12import Reflex.Dom.Class as X
13import Reflex.Dom.Location as X
13import Reflex.Dom.Location as X
14import Reflex.Dom.Main as X
14import Reflex.Dom.Main as X
15−import Reflex.Dom.Modals.Base as X
16import Reflex.Dom.Modals.Class as X
15import Reflex.Dom.Modals.Class as X
17import Reflex.Dom.Old as X
16import Reflex.Dom.Old as X
18import Reflex.Dom.Prerender as X
17import Reflex.Dom.Prerender as X
reflex-dom-core/src/Reflex/Dom/Modals/Base.hsdeleted−199
@@ -1,199 +0,0 @@
1−{-
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5−{-# LANGUAGE OverloadedStrings #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE RankNTypes #-}
8−{-# LANGUAGE RecursiveDo #-}
9−{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE UndecidableInstances #-}
12−-}
13−module Reflex.Dom.Modals.Base
14−where
15−{-
16− ( ModalsT (..)
17− , ModalLayerConfig (..)
18− , withModalLayer
19− )where
20−
21−import Control.Lens hiding (element)
22−import Control.Monad.Fix
23−import Control.Monad.Primitive
24−import Control.Monad.Ref
25−import Control.Monad.Trans
26−import Data.Coerce
27−import Data.Default
28−import Data.Dependent.Map (DMap, DSum (..), GCompare)
29−import qualified Data.Dependent.Map as DMap
30−import Data.Functor.Compose
31−import Data.Proxy
32−import Data.Semigroup
33−import Data.Text (Text)
34−import qualified Data.Text as T
35−import Foreign.JavaScript.TH
36−import Language.Javascript.JSaddle (MonadJSM)
37−
38−import Data.Functor.Misc
39−import Reflex
40−import Reflex.Dom.Builder.Class
41−import Reflex.Dom.Builder.Immediate
42−import Reflex.Dom.Class
43−import Reflex.Dom.Modals.Class
44−import Reflex.Host.Class
45−
46−instance (Reflex t, PrimMonad m) => ModalOpener t (ModalsT t m) where
47− requestingModal = ModalsT . requesting . fmap Compose
48−
49−newtype ModalsT t m a = ModalsT { unModalsT :: RequesterT t (Compose (ModalsT t m) (Event t)) Maybe m a }
50− deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
51−
52−instance Wrapped (ModalsT t m a) where
53− type Unwrapped (ModalsT t m a) = RequesterT t (Compose (ModalsT t m) (Event t)) Maybe m a
54− _Wrapped' = iso coerce coerce
55−
56−instance ModalsT t m a ~ x => Rewrapped (ModalsT t m a) x
57−
58−instance MonadTrans (ModalsT t) where
59− lift = ModalsT . lift
60−
61−instance (Reflex t, PostBuild t m) => PostBuild t (ModalsT t m) where
62− getPostBuild = view _Unwrapped getPostBuild
63−
64−instance MonadSample t m => MonadSample t (ModalsT t m) where
65− {-# INLINABLE sample #-}
66− sample = lift . sample
67−
68−instance MonadHold t m => MonadHold t (ModalsT t m) where
69− {-# INLINABLE hold #-}
70− hold v0 = lift . hold v0
71− {-# INLINABLE holdDyn #-}
72− holdDyn v0 = lift . holdDyn v0
73− {-# INLINABLE holdIncremental #-}
74− holdIncremental v0 = lift . holdIncremental v0
75−
76−instance PerformEvent t m => PerformEvent t (ModalsT t m) where
77− type Performable (ModalsT t m) = Performable m
78− {-# INLINABLE performEvent_ #-}
79− performEvent_ = lift . performEvent_
80− {-# INLINABLE performEvent #-}
81− performEvent = lift . performEvent
82−
83−instance (ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexCreateTrigger t (ModalsT t m) where
84− {-# INLINABLE newEventWithTrigger #-}
85− newEventWithTrigger = ModalsT . lift . newEventWithTrigger
86− {-# INLINABLE newFanEventWithTrigger #-}
87− newFanEventWithTrigger f = ModalsT $ lift $ newFanEventWithTrigger f
88−
89−instance TriggerEvent t m => TriggerEvent t (ModalsT t m) where
90− {-# INLINABLE newTriggerEvent #-}
91− newTriggerEvent = lift newTriggerEvent
92− {-# INLINABLE newTriggerEventWithOnComplete #-}
93− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
94− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
95−
96−instance MonadRef m => MonadRef (ModalsT t m) where
97− type Ref (ModalsT t m) = Ref m
98− {-# INLINABLE newRef #-}
99− newRef = lift . newRef
100− {-# INLINABLE readRef #-}
101− readRef = lift . readRef
102− {-# INLINABLE writeRef #-}
103− writeRef r = lift . writeRef r
104−
105−instance MonadAtomicRef m => MonadAtomicRef (ModalsT t m) where
106− {-# INLINABLE atomicModifyRef #-}
107− atomicModifyRef r = lift . atomicModifyRef r
108−
109−instance (Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (ModalsT t m) where
110− runWithReplace a0 a' = ModalsT $ runWithReplace (unModalsT a0) (fmapCheap unModalsT a')
111− traverseDMapWithKeyWithAdjust f dm0 dm' = ModalsT $ traverseDMapWithKeyWithAdjust (coerce f) dm0 dm'
112− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = ModalsT $ traverseDMapWithKeyWithAdjustWithMove (coerce f) dm0 dm'
113−
114−instance (DomBuilder t m, PerformEvent t m, MonadFix m, MonadHold t m) => DomBuilder t (ModalsT t m) where
115− type DomBuilderSpace (ModalsT t m) = DomBuilderSpace m
116− element = coerce (element :: Text -> ElementConfig er t (DomBuilderSpace m) -> Unwrapped (ModalsT t m a) -> Unwrapped (ModalsT t m (Element er (DomBuilderSpace m) t, a)))
117− inputElement = coerce (inputElement :: InputElementConfig er t (DomBuilderSpace m) -> Unwrapped (ModalsT t m (InputElement er (DomBuilderSpace m) t)))
118− textAreaElement = coerce (textAreaElement :: TextAreaElementConfig er t (DomBuilderSpace m) -> Unwrapped (ModalsT t m (TextAreaElement er (DomBuilderSpace m) t)))
119− selectElement = coerce (selectElement :: SelectElementConfig er t (DomBuilderSpace m) -> Unwrapped (ModalsT t m a) -> Unwrapped (ModalsT t m (SelectElement er (DomBuilderSpace m) t, a)))
120− wrapRawElement e = (view _Unwrapped :: forall a. Unwrapped (ModalsT t m a) -> ModalsT t m a) . wrapRawElement e
121−
122−instance HasDocument m => HasDocument (ModalsT t m)
123−instance HasJSContext m => HasJSContext (ModalsT t m) where
124− type JSContextPhantom (ModalsT t m) = JSContextPhantom m
125− askJSContext = ModalsT askJSContext
126−#ifndef ghcjs_HOST_OS
127−instance MonadJSM m => MonadJSM (ModalsT t m)
128−#endif
129−
130−data ModalLayerConfig t m = ModalLayerConfig
131− { _modalLayerConfig_backdropElementConfig :: ElementConfig EventResult t (DomBuilderSpace m)
132− , _modalLayerConfig_bodyElementConfig :: ElementConfig EventResult t (DomBuilderSpace m)
133− }
134−
135−instance (DomBuilder t m) => Default (ModalLayerConfig t m) where
136− def = ModalLayerConfig
137− { _modalLayerConfig_backdropElementConfig = (def :: ElementConfig EventResult t (DomBuilderSpace m))
138− & elementConfig_eventSpec %~ addEventSpecFlags (Proxy :: Proxy (DomBuilderSpace m)) Click (const stopPropagation)
139− & initialAttributes .~ ("style" =: T.intercalate ";"
140− [ "position:absolute"
141− , "left:0", "right:0", "top:0", "bottom:0"
142− , "background-color:rgba(0,0,0,0.1)"
143− , "display:flex", "justify-content:center", "align-items:center"
144− ])
145− , _modalLayerConfig_bodyElementConfig = (def :: ElementConfig EventResult t (DomBuilderSpace m))
146− & elementConfig_eventSpec %~ addEventSpecFlags (Proxy :: Proxy (DomBuilderSpace m)) Click (const stopPropagation)
147− & initialAttributes .~ ("style" =: "background-color:white;opacity:1;padding:1em")
148− }
149−
150−instance (MonadQuery t q m, Monad m) => MonadQuery t q (ModalsT t m) where
151− tellQueryIncremental = lift . tellQueryIncremental
152− askQueryResult = lift askQueryResult
153− queryIncremental = lift . queryIncremental
154−
155−withModalLayer :: forall t m a. (Reflex t, MonadFix m, DomBuilder t m, MonadHold t m)
156− => ModalLayerConfig t m
157− -> ModalsT t m a
158− -> m a
159−withModalLayer cfg (ModalsT a) = do
160− rec (result, requests) <- do
161− runRequesterT a modalDone
162− modalDone <- modalInner requests cfg
163− return result
164−
165−modalInner :: forall t m k. (GCompare k, MonadHold t m, MonadFix m, DomBuilder t m)
166− => Event t (DMap k (Compose (ModalsT t m) (Event t)))
167− -> ModalLayerConfig t m
168− -> m (Event t (DMap k Maybe))
169−modalInner rqs' cfg = do
170− rec let rqs = fmap toInsertionsDMap rqs'
171− dones = fmap toDeletionsDMap modalDone
172− (m0, mpatch) <- traverseDMapWithKeyWithAdjust (\_ v -> Compose <$> modalBody cfg v) DMap.empty (rqs <> dones)
173− modal <- fmap (merge . mapKeyValuePairsMonotonic wrapArgs) . incrementalToDynamic <$> holdIncremental m0 mpatch
174− let modalDone = fmap (mapKeyValuePairsMonotonic unwrapArgs) $ switch $ current modal
175− return modalDone
176− where
177− wrapArgs (k :=> v) = WrapArg k :=> getCompose v
178− unwrapArgs :: DSum (WrapArg Maybe k) Identity -> DSum k Maybe
179− unwrapArgs (WrapArg k :=> Identity v) = k :=> v
180− toInsertionsDMap :: DMap k v -> PatchDMap k v
181− toInsertionsDMap = coerce . DMap.map (ComposeMaybe . Just)
182− toDeletionsDMap :: forall k' v v'. DMap k' v -> PatchDMap k' v'
183− toDeletionsDMap = coerce . DMap.map (\(_ :: v a) -> ComposeMaybe (Nothing :: Maybe (v' a)))
184−
185−modalBody :: forall t m a. (MonadHold t m, MonadFix m, DomBuilder t m)
186− => ModalLayerConfig t m
187− -> Compose (ModalsT t m) (Event t) a
188− -> m (Event t (Maybe a))
189−modalBody cfg v = do
190− (overlay, complete) <- element "div" (_modalLayerConfig_backdropElementConfig cfg) $ do
191− fmap snd $ element "div" (_modalLayerConfig_bodyElementConfig cfg) $ do
192− rec (rsps, rqs') <- runRequesterT (unModalsT (getCompose v)) innerDone
193− innerDone <- modalInner rqs' cfg
194− return rsps
195− return $ leftmost
196− [ Just <$> complete
197− , Nothing <$ domEvent Click overlay
198− ]
199−-}
reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+25−16
@@ -10,11 +10,9 @@
10{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeFamilies #-}
12module Reflex.Dom.Widget.Basic
12module Reflex.Dom.Widget.Basic
13− ( partitionMapBySetLT
13+ (
14− , ChildResult (..)
15−
16 -- * Displaying Values
14 -- * Displaying Values
17− , text
15+ text
18 , dynText
16 , dynText
19 , comment
17 , comment
20 , dynComment
18 , dynComment
@@ -59,6 +57,7 @@ module Reflex.Dom.Widget.Basic
59 , module Data.Map.Misc
57 , module Data.Map.Misc
60 , module Reflex.Collection
58 , module Reflex.Collection
61 , module Reflex.Workflow
59 , module Reflex.Workflow
60+ , partitionMapBySetLT
62 ) where
61 ) where
63
62
64import Reflex.Class
63import Reflex.Class
@@ -95,6 +94,7 @@ import Prelude hiding (mapM, mapM_, sequence, sequence_)
95-- No empty pieces will be included in the output.
94-- No empty pieces will be included in the output.
96
95
97--TODO: This can probably be done more efficiently by dividing and conquering, re-using the structure of the Set instead of going through the Set linearally
96--TODO: This can probably be done more efficiently by dividing and conquering, re-using the structure of the Set instead of going through the Set linearally
97+{-# DEPRECATED partitionMapBySetLT "This will be removed in future releases." #-}
98partitionMapBySetLT :: forall k v. Ord k => Set k -> Map k v -> Map (Either k ()) (Map k v)
98partitionMapBySetLT :: forall k v. Ord k => Set k -> Map k v -> Map (Either k ()) (Map k v)
99partitionMapBySetLT s m0 = Map.fromDistinctAscList $ go (Set.toAscList s) m0
99partitionMapBySetLT s m0 = Map.fromDistinctAscList $ go (Set.toAscList s) m0
100 where go :: [k] -> Map k v -> [(Either k (), Map k v)]
100 where go :: [k] -> Map k v -> [(Either k (), Map k v)]
@@ -107,8 +107,7 @@ partitionMapBySetLT s m0 = Map.fromDistinctAscList $ go (Set.toAscList s) m0
107 then go t geq
107 then go t geq
108 else (Left h, lt) : go t geq
108 else (Left h, lt) : go t geq
109
109
110−newtype ChildResult t k a = ChildResult { unChildResult :: (a, Event t (Map k (Maybe (ChildResult t k a)))) }
110+{-# INLINABLE text #-}
111−
112text :: DomBuilder t m => Text -> m ()
111text :: DomBuilder t m => Text -> m ()
113text t = void $ textNode $ def & textNodeConfig_initialContents .~ t
112text t = void $ textNode $ def & textNodeConfig_initialContents .~ t
114
113
@@ -146,7 +145,7 @@ button t = do
146--TODO: Should this be renamed to 'widgetView' for consistency with 'widgetHold'?
145--TODO: Should this be renamed to 'widgetView' for consistency with 'widgetHold'?
147-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
146-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
148-- The returned Event of widget results occurs when the Dynamic does.
147-- The returned Event of widget results occurs when the Dynamic does.
149−-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events that would typically be flattened (via 'switchPromptly').
148+-- Note: Often, the type @a@ is an 'Event', in which case the return value is an Event-of-Events that would typically be flattened (via 'switchHold').
150dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
149dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
151dyn = networkView
150dyn = networkView
152
151
@@ -156,7 +155,7 @@ dyn_ = void . dyn
156
155
157-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
156-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
158-- The returned Dynamic of widget results occurs when the Event does.
157-- The returned Dynamic of widget results occurs when the Event does.
159−-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
158+-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened (via 'switchDyn').
160widgetHold :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
159widgetHold :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
161widgetHold = networkHold
160widgetHold = networkHold
162
161
@@ -165,43 +164,51 @@ widgetHold_ :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m ()
165widgetHold_ z = void . widgetHold z
164widgetHold_ z = void . widgetHold z
166
165
167-- | Create a DOM element
166-- | Create a DOM element
167+--
168−-- > el "div" (text "Hello World")
168+-- >>> el "div" (text "Hello World")
169-- <div>Hello World</div>
169-- <div>Hello World</div>
170{-# INLINABLE el #-}
170{-# INLINABLE el #-}
171el :: forall t m a. DomBuilder t m => Text -> m a -> m a
171el :: forall t m a. DomBuilder t m => Text -> m a -> m a
172el elementTag child = snd <$> el' elementTag child
172el elementTag child = snd <$> el' elementTag child
173
173
174-- | Create a DOM element with attributes
174-- | Create a DOM element with attributes
175+--
175−-- > elAttr "a" ("href" =: "http://google.com") (text "Google!")
176+-- >>> elAttr "a" ("href" =: "https://reflex-frp.org") (text "Reflex-FRP!")
176−-- <a href="http://google.com">Google!</a>
177+-- <a href="https://reflex-frp.org">Reflex-FRP!</a>
177{-# INLINABLE elAttr #-}
178{-# INLINABLE elAttr #-}
178elAttr :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m a
179elAttr :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m a
179elAttr elementTag attrs child = snd <$> elAttr' elementTag attrs child
180elAttr elementTag attrs child = snd <$> elAttr' elementTag attrs child
180
181
181-- | Create a DOM element with classes
182-- | Create a DOM element with classes
183+--
182−-- > elClass "div" "row" (return ())
184+-- >>> elClass "div" "row" (return ())
183-- <div class="row"></div>
185-- <div class="row"></div>
184{-# INLINABLE elClass #-}
186{-# INLINABLE elClass #-}
185elClass :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m a
187elClass :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m a
186elClass elementTag c child = snd <$> elClass' elementTag c child
188elClass elementTag c child = snd <$> elClass' elementTag c child
187
189
188-- | Create a DOM element with Dynamic Attributes
190-- | Create a DOM element with Dynamic Attributes
191+--
189−-- > elClass "div" (constDyn ("class" =: "row")) (return ())
192+-- >>> elClass "div" (constDyn ("class" =: "row")) (return ())
190-- <div class="row"></div>
193-- <div class="row"></div>
191{-# INLINABLE elDynAttr #-}
194{-# INLINABLE elDynAttr #-}
192elDynAttr :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m a
195elDynAttr :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m a
193elDynAttr elementTag attrs child = snd <$> elDynAttr' elementTag attrs child
196elDynAttr elementTag attrs child = snd <$> elDynAttr' elementTag attrs child
194
197
195-- | Create a DOM element with a Dynamic Class
198-- | Create a DOM element with a Dynamic Class
199+--
196−-- > elDynClass "div" (constDyn "row") (return ())
200+-- >>> elDynClass "div" (constDyn "row") (return ())
197-- <div class="row"></div>
201-- <div class="row"></div>
198{-# INLINABLE elDynClass #-}
202{-# INLINABLE elDynClass #-}
199elDynClass :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t Text -> m a -> m a
203elDynClass :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t Text -> m a -> m a
200elDynClass elementTag c child = snd <$> elDynClass' elementTag c child
204elDynClass elementTag c child = snd <$> elDynClass' elementTag c child
201
205
202-- | Create a DOM element and return the element
206-- | Create a DOM element and return the element
207+--
208+-- @
203−-- > do (e, _) <- el' "div" (text "Click")
209+-- do (e, _) <- el' "div" (text "Click")
204−-- > return $ domEvent Click e
210+-- return $ domEvent Click e
211+-- @
205{-# INLINABLE el' #-}
212{-# INLINABLE el' #-}
206el' :: forall t m a. DomBuilder t m => Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
213el' :: forall t m a. DomBuilder t m => Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
207el' elementTag = element elementTag def
214el' elementTag = element elementTag def
@@ -287,6 +294,8 @@ newtype Link t
287 = Link { _link_clicked :: Event t ()
294 = Link { _link_clicked :: Event t ()
288 }
295 }
289
296
297+-- | >>> linkClass "Click here" "link-class"
298+-- > <a class="link-class">Click here</a>
290linkClass :: DomBuilder t m => Text -> Text -> m (Link t)
299linkClass :: DomBuilder t m => Text -> Text -> m (Link t)
291linkClass s c = do
300linkClass s c = do
292 (l,_) <- elAttr' "a" ("class" =: c) $ text s
301 (l,_) <- elAttr' "a" ("class" =: c) $ text s
reflex-dom-core/src/Reflex/Dom/Widget/Input.hs+3−9
@@ -346,16 +346,10 @@ fileInput config = do
346 & modifyAttributes .~ fmap mapKeysToAttributeName modifyAttrs
346 & modifyAttributes .~ fmap mapKeysToAttributeName modifyAttrs
347 & elementConfig_eventSpec . ghcjsEventSpec_filters .~ filters
347 & elementConfig_eventSpec . ghcjsEventSpec_filters .~ filters
348 cfg = (def :: InputElementConfig EventResult t (DomBuilderSpace m)) & inputElementConfig_elementConfig .~ elCfg
348 cfg = (def :: InputElementConfig EventResult t (DomBuilderSpace m)) & inputElementConfig_elementConfig .~ elCfg
349− eRaw <- inputElement cfg
349+ input <- inputElement cfg
350− let e = _inputElement_raw eRaw
351− eChange <- wrapDomEvent e (`on` Events.change) $ do
352− files <- Input.getFilesUnchecked e
353− len <- FileList.getLength files
354− mapM (fmap (fromMaybe (error "fileInput: fileList.item returned null")) . FileList.item files) [0 .. len-1]
355− dValue <- holdDyn [] eChange
356 return $ FileInput
350 return $ FileInput
357− { _fileInput_value = dValue
351+ { _fileInput_value = _inputElement_files input
358− , _fileInput_element = e
352+ , _fileInput_element = _inputElement_raw input
359 }
353 }
360
354
361data Dropdown t k
355data Dropdown t k
reflex-dom-core/src/Reflex/Dom/Widget/Lazy.hs+1−1
@@ -142,7 +142,7 @@ virtualListBuffered buffer heightPx rowPx maxIndex i0 setI keyToIndex items0 ite
142 (win, m) <- virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBuilder
142 (win, m) <- virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBuilder
143 pb <- getPostBuild
143 pb <- getPostBuild
144 let extendWin o l = (max 0 (o - l * (buffer-1) `div` 2), l * buffer)
144 let extendWin o l = (max 0 (o - l * (buffer-1) `div` 2), l * buffer)
145− rec let winHitEdge = fmapMaybe id $ attachWith (\(oldOffset, oldLimit) (winOffset, winLimit) ->
145+ rec let winHitEdge = attachWithMaybe (\(oldOffset, oldLimit) (winOffset, winLimit) ->
146 if winOffset > oldOffset && winOffset + winLimit < oldOffset + oldLimit
146 if winOffset > oldOffset && winOffset + winLimit < oldOffset + oldLimit
147 then Nothing
147 then Nothing
148 else Just (extendWin winOffset winLimit)) (current winBuffered) (updated win)
148 else Just (extendWin winOffset winLimit)) (current winBuffered) (updated win)
reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+1−1
@@ -32,7 +32,7 @@ import GHCJS.DOM.HTMLElement (getOffsetWidth, getOffsetHeight)
32import qualified GHCJS.DOM.Types as DOM
32import qualified GHCJS.DOM.Types as DOM
33
33
34-- | A widget that wraps the given widget in a div and fires an event when resized.
34-- | A widget that wraps the given widget in a div and fires an event when resized.
35−-- Adapted from github.com/marcj/css-element-queries
35+-- Adapted from @github.com\/marcj\/css-element-queries@
36resizeDetector :: (MonadJSM m, DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadJSM (Performable m), MonadFix m) => m a -> m (Event t (), a)
36resizeDetector :: (MonadJSM m, DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadJSM (Performable m), MonadFix m) => m a -> m (Event t (), a)
37resizeDetector = resizeDetectorWithStyle ""
37resizeDetector = resizeDetectorWithStyle ""
38
38
reflex-dom/reflex-dom.cabal+8−10
@@ -10,12 +10,7 @@ Stability: Experimental
10Category: FRP, Web, GUI, HTML, Javascript, Reactive, Reactivity, User Interfaces, User-interface
10Category: FRP, Web, GUI, HTML, Javascript, Reactive, Reactivity, User Interfaces, User-interface
11Build-type: Simple
11Build-type: Simple
12cabal-version: >=1.24
12cabal-version: >=1.24
13−-- Deal with https://github.com/haskell/cabal/issues/2544 / https://github.com/haskell/cabal/issues/367
14−extra-source-files: src/Reflex/Dom/Xhr/Foreign.hs
15− src/Reflex/Dom/WebSocket/Foreign.hs
16− src/Reflex/Dom/Xhr/ResponseType.hs
17− src/Reflex/Dom/Xhr/Exception.hs
18− java/org/reflexfrp/reflexdom/MainWidget.java
13+extra-source-files: java/org/reflexfrp/reflexdom/MainWidget.java
19
14
20flag use-warp
15flag use-warp
21 description: Use jsaddle-warp server
16 description: Use jsaddle-warp server
@@ -58,6 +53,7 @@ library
58 jsaddle
53 jsaddle
59 c-sources: cbits/MainWidget.c
54 c-sources: cbits/MainWidget.c
60 include-dirs: cbits/include
55 include-dirs: cbits/include
56+ install-includes: MainWidget.h
61 cpp-options: -DANDROID
57 cpp-options: -DANDROID
62 build-tools: hsc2hs
58 build-tools: hsc2hs
63 build-depends:
59 build-depends:
@@ -114,6 +110,7 @@ library
114 ghc-options: -fexpose-all-unfoldings
110 ghc-options: -fexpose-all-unfoldings
115 if flag(use-reflex-optimizer)
111 if flag(use-reflex-optimizer)
116 ghc-options: -fplugin=Reflex.Optimizer
112 ghc-options: -fplugin=Reflex.Optimizer
113+ default-language: Haskell2010
117
114
118executable sortableList
115executable sortableList
119 build-depends: base
116 build-depends: base
@@ -130,13 +127,13 @@ executable sortableList
130 hs-source-dirs: examples
127 hs-source-dirs: examples
131 main-is: sortableList.hs
128 main-is: sortableList.hs
132 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans -fspecialise-aggressively
129 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans -fspecialise-aggressively
133− ghc-prof-options: -fprof-auto
134 if !flag(build-examples)
130 if !flag(build-examples)
135 buildable: False
131 buildable: False
136 if flag(expose-all-unfoldings)
132 if flag(expose-all-unfoldings)
137 ghc-options: -fexpose-all-unfoldings
133 ghc-options: -fexpose-all-unfoldings
138 if flag(use-reflex-optimizer)
134 if flag(use-reflex-optimizer)
139 ghc-options: -fplugin=Reflex.Optimizer
135 ghc-options: -fplugin=Reflex.Optimizer
136+ default-language: Haskell2010
140
137
141executable benchmark
138executable benchmark
142 build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum
139 build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum
@@ -145,6 +142,7 @@ executable benchmark
145 ghc-options: -O2 -fspecialise-aggressively
142 ghc-options: -O2 -fspecialise-aggressively
146 if !impl(ghcjs)
143 if !impl(ghcjs)
147 buildable: False
144 buildable: False
145+ default-language: Haskell2010
148
146
149executable krausest
147executable krausest
150 build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum, vector
148 build-depends: base, reflex, reflex-dom, text, prim-uniq, dependent-map, containers, transformers, mtl, ghcjs-dom, ghc-prim, random, dependent-sum, vector
@@ -152,11 +150,11 @@ executable krausest
152 main-is: krausest.hs
150 main-is: krausest.hs
153 ghc-options: -O2 -fspecialise-aggressively
151 ghc-options: -O2 -fspecialise-aggressively
154 if impl(ghcjs)
152 if impl(ghcjs)
155− ghc-options: -dedupe
153+ ghcjs-options: -dedupe
156 cpp-options: -DGHCJS_BROWSER -DGHCJS_GC_INTERVAL=60000
154 cpp-options: -DGHCJS_BROWSER -DGHCJS_GC_INTERVAL=60000
157 else
155 else
158− --buildable: False
156+ buildable: False
159− type: exitcode-stdio-1.0
157+ default-language: Haskell2010
160
158
161source-repository head
159source-repository head
162 type: git
160 type: git