on develop help sign in
Merge remote-tracking branch 'origin/develop' into aa-base-4.12
de9ac2dAli Abrar
CONTRIBUTING.md+5
@@ -5,6 +5,7 @@ Contributions and issue reports are encouraged and appreciated!
5- [Opening Issues](#opening-issues)
5- [Opening Issues](#opening-issues)
6- [Submitting Changes](#submitting-changes)
6- [Submitting Changes](#submitting-changes)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
8 - [Code Quality](#code-quality)
9 - [Code Quality](#code-quality)
9 - [Documentation](#documentation)
10 - [Documentation](#documentation)
10
11
@@ -30,6 +31,10 @@ One way to think about it is that your commit message should be able to complete
30#### Body
31#### Body
31For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
32For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
32
33
34+### Guidelines for Pull Requests
35+
36+Wherever possible, pull requests should add a single feature or fix a single bug. Pull requests should not bundle several unrelated changes.
37+
33### Code Quality
38### Code Quality
34
39
35#### Warnings
40#### Warnings
default.nix+51−5
@@ -1,7 +1,53 @@
1−haskellPackages: nixpkgs: {
1+haskellPackages: let
2− reflex-dom = haskellPackages.callPackage ./reflex-dom {};
2+ pkgs = haskellPackages.callPackage ({ pkgs }: pkgs) {};
3+ inherit (pkgs) stdenv;
4+ haskellLib = pkgs.haskell.lib;
5+in {
6+ reflex-dom-core = let
7+ inherit (haskellPackages) ghc;
8+ noGcTest = stdenv.hostPlatform.system != "x86_64-linux"
9+ || stdenv.hostPlatform != stdenv.buildPlatform
10+ || (ghc.isGhcjs or false);
11+ in haskellLib.overrideCabal
3− reflex-dom-core = haskellPackages.callPackage ./reflex-dom-core {
12+ (haskellPackages.callCabal2nix "reflex-dom-core" ./reflex-dom-core { })
13+ (drv: {
14+ #TODO: Get hlint working for cross-compilation
15+ doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
16+
17+ # The headless browser run as part of the tests will exit without this
18+ preBuild = ''
19+ export HOME="$PWD"
20+ '';
21+
22+ # Show some output while running tests, so we might notice what's wrong
23+ testTarget = "--show-details=streaming";
24+
25+ testHaskellDepends = with haskellPackages; (drv.testHaskellDepends or []) ++ stdenv.lib.optionals (!noGcTest) [
26+ temporary
27+ jsaddle-warp
28+ process
29+ chrome-test-utils
30+ ];
31+
32+ testSystemDepends = with pkgs; (drv.testSystemDepends or []) ++ [
33+ selenium-server-standalone which
34+ ] ++ stdenv.lib.optionals (!noGcTest) [
4− inherit (nixpkgs) iproute chromium;
35+ chromium
36+ pkgs.iproute
37+ ];
38+ } // stdenv.lib.optionalAttrs (!noGcTest) {
39+ # The headless browser run as part of gc tests would hang/crash without this
40+ preCheck = ''
41+ export FONTCONFIG_PATH=${pkgs.fontconfig.out}/etc/fonts
42+ '';
43+ });
44+ reflex-dom = haskellLib.overrideCabal
45+ (haskellPackages.callCabal2nix "reflex-dom" ./reflex-dom { })
46+ (drv: {
47+ # Hack until https://github.com/NixOS/cabal2nix/pull/432 lands
48+ libraryHaskellDepends = (drv.libraryHaskellDepends or []) ++ stdenv.lib.optionals (with stdenv.hostPlatform; isAndroid && is32bit) [
49+ haskellPackages.android-activity
50+ ];
5− };
51+ });
6 chrome-test-utils = haskellPackages.callCabal2nix "chrome-test-utils" ./chrome-test-utils {};
52 chrome-test-utils = haskellPackages.callCabal2nix "chrome-test-utils" ./chrome-test-utils {};
7}
53}
dep/reflex-platform/default.nixnew file+7
@@ -0,0 +1,7 @@
1+# DO NOT HAND-EDIT THIS FILE
2+import ((import <nixpkgs> {}).fetchFromGitHub (
3+ let json = builtins.fromJSON (builtins.readFile ./github.json);
4+ in { inherit (json) owner repo rev sha256;
5+ private = json.private or false;
6+ }
7+))
dep/reflex-platform/github.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "owner": "reflex-frp",
3+ "repo": "reflex-platform",
4+ "branch": "develop",
5+ "rev": "338fc907e37d70e6469c529456f33221fb05ca1f",
6+ "sha256": "08gfhpp0pkvvi1wnlpcn6wmpzdjvy5z7dy1h66gp2w8b5cx8hx5h"
7+}
hydra.jsondeleted−29
@@ -1,29 +0,0 @@
1−{
2− "enabled": 1,
3− "hidden": true,
4− "description": "Jobsets",
5− "nixexprinput": "src",
6− "nixexprpath": "jobsets.nix",
7− "checkinterval": 300,
8− "schedulingshares": 100,
9− "enableemail": false,
10− "emailoverride": "",
11− "keepnr": 10,
12− "inputs": {
13− "src": {
14− "type": "git",
15− "value": "https://github.com/reflex-frp/reflex-dom.git develop",
16− "emailresponsible": false
17− },
18− "nixpkgs": {
19− "type": "git",
20− "value": "https://github.com/NixOS/nixpkgs-channels nixos-unstable",
21− "emailresponsible": false
22− },
23− "prs": {
24− "type": "githubpulls",
25− "value": "reflex-frp reflex-dom",
26− "emailresponsible": false
27− }
28− }
29−}
jobsets.nixdeleted−70
@@ -1,70 +0,0 @@
1−{ prs }:
2−
3−let
4− pkgs = (import ./reflex-platform.nix {}).nixpkgs;
5− mkFetchGithub = value: {
6− inherit value;
7− type = "git";
8− emailresponsible = false;
9− };
10−in
11−with pkgs.lib;
12−let
13− defaults = jobs: {
14− inherit (jobs) description;
15− enabled = 1;
16− hidden = false;
17− keepnr = 10;
18− schedulingshares = 100;
19− checkinterval = 120;
20− enableemail = false;
21− emailoverride = "";
22− nixexprinput = "reflex-dom";
23− nixexprpath = "release.nix";
24− inputs = jobs.inputs // {
25− nixpkgs = {
26− type = "git";
27− value = "https://github.com/NixOS/nixpkgs-channels nixos-unstable";
28− emailresponsible = false;
29− };
30− config = {
31− type = "nix";
32− value = "{ android_sdk.accept_license = true; }";
33− emailresponsible = false;
34− };
35− };
36− };
37− branchJobset = branch: defaults {
38− description = "reflex-dom-${branch}";
39− inputs = {
40− reflex-dom = {
41− value = "https://github.com/reflex-frp/reflex-dom ${branch}";
42− type = "git";
43− emailresponsible = false;
44− };
45− };
46− };
47− makePr = num: info: {
48− name = "reflex-dom-pr-${num}";
49− value = defaults {
50− description = "#${num}: ${info.title}";
51− inputs = {
52− reflex-dom = {
53− #NOTE: This should really use "pull/${num}/merge"; however, GitHub's
54− #status checks only operate on PR heads. This creates a race
55− #condition, which can currently only be solved by requiring PRs to be
56− #up to date before they're merged. See
57− #https://github.com/isaacs/github/issues/1002
58− value = "https://github.com/reflex-frp/reflex-dom pull/${num}/head";
59− type = "git";
60− emailresponsible = false;
61− };
62− };
63− };
64− };
65− processedPrs = mapAttrs' makePr (builtins.fromJSON (builtins.readFile prs));
66− jobsetsAttrs = processedPrs //
67− genAttrs ["develop"] branchJobset;
68−in {
69− jobsets = pkgs.writeText "spec.json" (builtins.toJSON jobsetsAttrs);
70−}
reflex-dom-core/ChangeLog.md+8−2
@@ -1,15 +1,21 @@
1# Revision history for reflex-dom-core
1# Revision history for reflex-dom-core
2
2
3+## Unreleased
4+
3## 0.5.2
5## 0.5.2
4
6
5* Update to use new dependent-sum/map packages and drop dependency on `*Tag` classes (e.g., `ShowTag`).
7* Update to use new dependent-sum/map packages and drop dependency on `*Tag` classes (e.g., `ShowTag`).
6* Update version bounds of base, containers, and stm
8* Update version bounds of base, containers, and stm
7−* Update to use split these/semialign packages
9+* Update to use the newly split `these`/`semialign` packages. To use the pre-split `these` package, set the `split-these` flag to false.
10+* Reintroduce "data-ssr": elements without this attribute are skipped during
11+ hydration.
12+* Fix an issue in the hydration tests that prevented the test from finding the chromium executable
13+* Relax constraints on `dyn` and `widgetHold` to match the ones in `networkView` and `networkHold` respectively
8
14
9## 0.5.1
15## 0.5.1
10
16
11* Added support for marking elements with a "data-skip-hydration" attribute, which will cause hydration to ignore and skip over them.
17* Added support for marking elements with a "data-skip-hydration" attribute, which will cause hydration to ignore and skip over them.
12−* Removed "data-ssr" attributes from statically rendered output.:q
18+* Removed "data-ssr" attributes from statically rendered output.
13
19
14## 0.5
20## 0.5
15
21
reflex-dom-core/default.nixdeleted−64
@@ -1,64 +0,0 @@
1−{ mkDerivation, aeson, base, bifunctors, bimap, blaze-builder
2−, bytestring, chrome-test-utils, constraints, constraints-extras, containers
3−, contravariant, data-default, dependent-map, dependent-sum
4−, dependent-sum-template, directory, exception-transformers
5−, exceptions, filepath, ghcjs-dom, hlint, hspec, hspec-webdriver, http-types, HUnit
6−, jsaddle, jsaddle-warp, keycode, lens, lifted-base
7−, monad-control, mtl, network, network-uri, primitive, process
8−, random, ref-tf, reflex, semigroups, silently, stdenv, stm
9−, template-haskell, temporary, text, these, transformers, unix, wai
10−, wai-websockets, warp, webdriver, websockets, zenc
11−, ghc, iproute, chromium, hashable, selenium-server-standalone, which, fontconfig
12−, semialign ? null
13−, splitThese ? (semialign != null)
14−}:
15−let addGcTestDepends = drv: if (stdenv.system != "x86_64-linux" || stdenv.hostPlatform != stdenv.buildPlatform || (ghc.isGhcjs or false)) then drv else drv // {
16− # The headless browser run as part of gc tests would hang/crash without this
17− preCheck = ''
18− export FONTCONFIG_PATH=${fontconfig.out}/etc/fonts
19− '';
20− testHaskellDepends = (drv.testHaskellDepends or []) ++ [
21− temporary
22− jsaddle-warp
23− process
24− chrome-test-utils
25− ];
26− testSystemDepends = (drv.testSystemDepends or []) ++ [ chromium iproute ];
27− };
28−in mkDerivation (addGcTestDepends {
29− pname = "reflex-dom-core";
30− version = "0.5.2";
31− src = ./.;
32− libraryHaskellDepends = [
33− aeson base bifunctors bimap blaze-builder bytestring constraints
34− containers contravariant data-default dependent-map dependent-sum
35− dependent-sum-template directory exception-transformers ghcjs-dom
36− jsaddle keycode lens monad-control mtl network-uri primitive random
37− ref-tf reflex semigroups stm template-haskell text these
38− transformers unix zenc
39− ] ++ (if ghc.isGhcjs or false then [ hashable ] else [])
40− ++ (if splitThese then [ semialign ] else []);
41−
42− #TODO: Get hlint working for cross-compilation
43− doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
44−
45− # The headless browser run as part of the tests will exit without this
46− preBuild = ''
47− export HOME="$PWD"
48− '';
49−
50− # Show some output while running tests, so we might notice what's wrong
51− testTarget = "--show-details=streaming";
52−
53− testSystemDepends = [ selenium-server-standalone which ];
54− testHaskellDepends = [
55− aeson base bytestring constraints constraints-extras containers
56− dependent-map dependent-sum dependent-sum-template directory
57− exceptions filepath ghcjs-dom hlint hspec hspec-webdriver http-types HUnit jsaddle
58− jsaddle-warp lens lifted-base network process random reflex
59− silently temporary text unix wai wai-websockets warp webdriver
60− websockets
61− ];
62− description = "Functional Reactive Web Apps with Reflex";
63− license = stdenv.lib.licenses.bsd3;
64−})
reflex-dom-core/reflex-dom-core.cabal+5−3
@@ -53,8 +53,8 @@ library
53 bimap >= 0.3 && < 0.4,
53 bimap >= 0.3 && < 0.4,
54 blaze-builder,
54 blaze-builder,
55 bytestring == 0.10.*,
55 bytestring == 0.10.*,
56− containers == 0.6.*,
56+ containers >= 0.6 && < 0.7,
57− constraints >= 0.9 && < 0.11,
57+ constraints >= 0.9 && < 0.12,
58 contravariant >= 1.4 && < 1.6,
58 contravariant >= 1.4 && < 1.6,
59 data-default >= 0.5 && < 0.8,
59 data-default >= 0.5 && < 0.8,
60 dependent-map >= 0.3 && < 0.4,
60 dependent-map >= 0.3 && < 0.4,
@@ -74,7 +74,7 @@ library
74 ref-tf == 0.4.*,
74 ref-tf == 0.4.*,
75 reflex >= 0.6.2,
75 reflex >= 0.6.2,
76 semigroups >= 0.16 && < 0.19,
76 semigroups >= 0.16 && < 0.19,
77− stm == 2.5.*,
77+ stm >= 2.4 && < 2.6,
78 text == 1.2.*,
78 text == 1.2.*,
79 transformers >= 0.3 && < 0.6,
79 transformers >= 0.3 && < 0.6,
80 network-uri >= 2.6.1 && < 2.7,
80 network-uri >= 2.6.1 && < 2.7,
@@ -106,6 +106,7 @@ library
106 Reflex.Dom.Builder.Class.Events
106 Reflex.Dom.Builder.Class.Events
107 Reflex.Dom.Builder.Immediate
107 Reflex.Dom.Builder.Immediate
108 Reflex.Dom.Builder.InputDisabled
108 Reflex.Dom.Builder.InputDisabled
109+ Reflex.Dom.Builder.Hydratable
109 Reflex.Dom.Builder.Static
110 Reflex.Dom.Builder.Static
110 Reflex.Dom.Class
111 Reflex.Dom.Class
111 Reflex.Dom.Core
112 Reflex.Dom.Core
@@ -200,6 +201,7 @@ test-suite hydration
200 , warp
201 , warp
201 , webdriver
202 , webdriver
202 , websockets
203 , websockets
204+ , which
203 hs-source-dirs: test
205 hs-source-dirs: test
204 ghc-options: -rtsopts -with-rtsopts=-T -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
206 ghc-options: -rtsopts -with-rtsopts=-T -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
205 ghc-prof-options: -fprof-auto -optP-DPROFILING
207 ghc-prof-options: -fprof-auto -optP-DPROFILING
reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hsnew file+116
@@ -0,0 +1,116 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE UndecidableInstances #-}
9+module Reflex.Dom.Builder.Hydratable where
10+
11+import Control.Monad.Fix
12+import Control.Monad.Primitive
13+import Control.Monad.Ref
14+import Control.Monad.Trans
15+import Control.Monad.Trans.Control
16+import Data.Coerce
17+import qualified Data.Map as Map
18+import Foreign.JavaScript.TH
19+#ifndef ghcjs_HOST_OS
20+import GHCJS.DOM.Types (MonadJSM (..))
21+#endif
22+import Reflex
23+import Reflex.Dom.Builder.Class
24+import Reflex.Dom.Builder.Immediate (HasDocument (..))
25+import Reflex.Host.Class
26+
27+-- | A DomBuilder transformer that adds "data-ssr" to all elements such that the
28+-- hydration builder knows which bits of DOM were added by us, and which were
29+-- added by external scripts.
30+newtype HydratableT m a = HydratableT { runHydratableT :: m a } deriving (Functor, Applicative, Monad, MonadAtomicRef, MonadFix, MonadIO)
31+
32+#ifndef ghcjs_HOST_OS
33+instance MonadJSM m => MonadJSM (HydratableT m) where
34+ liftJSM' = HydratableT . liftJSM'
35+#endif
36+
37+deriving instance MonadSample t m => MonadSample t (HydratableT m)
38+deriving instance MonadHold t m => MonadHold t (HydratableT m)
39+
40+instance MonadTrans HydratableT where
41+ lift = HydratableT
42+
43+instance MonadTransControl HydratableT where
44+ type StT HydratableT a = a
45+ liftWith f = HydratableT $ f runHydratableT
46+ restoreT = HydratableT
47+
48+instance MonadRef m => MonadRef (HydratableT m) where
49+ type Ref (HydratableT m) = Ref m
50+ newRef = lift . newRef
51+ readRef = lift . readRef
52+ writeRef ref = lift . writeRef ref
53+
54+instance PerformEvent t m => PerformEvent t (HydratableT m) where
55+ type Performable (HydratableT m) = Performable m
56+ performEvent_ = lift . performEvent_
57+ performEvent = lift . performEvent
58+
59+instance PrimMonad m => PrimMonad (HydratableT m) where
60+ type PrimState (HydratableT m) = PrimState m
61+ primitive = lift . primitive
62+
63+makeHydratable :: Reflex t => ElementConfig er t m -> ElementConfig er t m
64+makeHydratable cfg = cfg
65+ { _elementConfig_initialAttributes = Map.insert "data-ssr" "" $ _elementConfig_initialAttributes cfg
66+ , _elementConfig_modifyAttributes = fmap (Map.delete "data-ssr") <$> _elementConfig_modifyAttributes cfg
67+ }
68+
69+instance PostBuild t m => PostBuild t (HydratableT m) where
70+ getPostBuild = lift getPostBuild
71+
72+deriving instance TriggerEvent t m => TriggerEvent t (HydratableT m)
73+
74+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydratableT m) where
75+ newEventWithTrigger = lift . newEventWithTrigger
76+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
77+
78+instance Adjustable t m => Adjustable t (HydratableT m) where
79+ runWithReplace a0 a' = HydratableT $ runWithReplace (coerce a0) (coerceEvent a')
80+ traverseDMapWithKeyWithAdjust f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
81+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
82+ traverseIntMapWithKeyWithAdjust f m0 m' = HydratableT $ traverseIntMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce m0) (coerceEvent m')
83+
84+instance NotReady t m => NotReady t (HydratableT m) where
85+ notReadyUntil = lift . notReadyUntil
86+ notReady = lift notReady
87+
88+instance DomBuilder t m => DomBuilder t (HydratableT m) where
89+ type DomBuilderSpace (HydratableT m) = DomBuilderSpace m
90+ element t cfg = lift . element t (makeHydratable cfg) . runHydratableT
91+ inputElement cfg = lift $ inputElement $ cfg
92+ { _inputElementConfig_elementConfig = makeHydratable $ _inputElementConfig_elementConfig cfg
93+ }
94+ textAreaElement cfg = lift $ textAreaElement $ cfg
95+ { _textAreaElementConfig_elementConfig = makeHydratable $ _textAreaElementConfig_elementConfig cfg
96+ }
97+ selectElement cfg child = do
98+ let cfg' = cfg
99+ { _selectElementConfig_elementConfig = makeHydratable $ _selectElementConfig_elementConfig cfg
100+ }
101+ lift $ selectElement cfg' $ runHydratableT child
102+
103+instance HasDocument m => HasDocument (HydratableT m)
104+
105+instance HasJSContext m => HasJSContext (HydratableT m) where
106+ type JSContextPhantom (HydratableT m) = JSContextPhantom m
107+ askJSContext = lift askJSContext
108+
109+instance HasJS js m => HasJS js (HydratableT m) where
110+ type JSX (HydratableT m) = JSX m
111+ liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (HydratableT m) where
114+ withRenderHook f = HydratableT . withRenderHook f . runHydratableT
115+ requestDomAction = HydratableT . requestDomAction
116+ requestDomAction_ = HydratableT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+12−5
@@ -765,10 +765,17 @@ hydrateElement elementTag cfg child = do
765 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
765 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
766 wrapResult <- liftIO newEmptyMVar
766 wrapResult <- liftIO newEmptyMVar
767 let skipAttr = "data-hydration-skip" :: DOM.JSString
767 let skipAttr = "data-hydration-skip" :: DOM.JSString
768+ ssrAttr = "data-ssr" :: DOM.JSString
768− hasSkipAttribute :: DOM.Element -> HydrationRunnerT t m Bool
769+ shouldSkip :: DOM.Element -> HydrationRunnerT t m Bool
769− hasSkipAttribute e = case cfg ^. namespace of
770+ shouldSkip e = case cfg ^. namespace of
771+ Nothing -> do
770− Nothing -> hasAttribute e skipAttr
772+ skip <- hasAttribute e skipAttr
773+ ssr <- hasAttribute e ssrAttr
774+ pure $ skip || not ssr
775+ Just ns -> do
771− Just ns -> hasAttributeNS e (Just ns) skipAttr
776+ skip <- hasAttributeNS e (Just ns) skipAttr
777+ ssr <- hasAttributeNS e (Just ns) ssrAttr
778+ pure $ skip || not ssr
772 childDom <- liftIO $ readIORef childDelayedRef
779 childDom <- liftIO $ readIORef childDelayedRef
773 let rawCfg = extractRawElementConfig cfg
780 let rawCfg = extractRawElementConfig cfg
774 doc <- askDocument
781 doc <- askDocument
@@ -783,7 +790,7 @@ hydrateElement elementTag cfg child = do
783 pure e
790 pure e
784 Just node -> DOM.castTo DOM.Element node >>= \case
791 Just node -> DOM.castTo DOM.Element node >>= \case
785 Nothing -> go (Just node) -- this node is not an element, skip
792 Nothing -> go (Just node) -- this node is not an element, skip
786− Just e -> hasSkipAttribute e >>= \case
793+ Just e -> shouldSkip e >>= \case
787 True -> go (Just node) -- this element is explicitly marked for being skipped by hydration
794 True -> go (Just node) -- this element is explicitly marked for being skipped by hydration
788 False -> do
795 False -> do
789 t <- Element.getTagName e
796 t <- Element.getTagName e
reflex-dom-core/src/Reflex/Dom/Builder/InputDisabled.hs+6
@@ -80,6 +80,7 @@ instance Adjustable t m => Adjustable t (InputDisabledT m) where
80 runWithReplace a0 a' = InputDisabledT $ runWithReplace (coerce a0) (coerceEvent a')
80 runWithReplace a0 a' = InputDisabledT $ runWithReplace (coerce a0) (coerceEvent a')
81 traverseDMapWithKeyWithAdjust f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
81 traverseDMapWithKeyWithAdjust f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
82 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
82 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
83+ traverseIntMapWithKeyWithAdjust f m0 m' = InputDisabledT $ traverseIntMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce m0) (coerceEvent m')
83
84
84instance NotReady t m => NotReady t (InputDisabledT m) where
85instance NotReady t m => NotReady t (InputDisabledT m) where
85 notReadyUntil = lift . notReadyUntil
86 notReadyUntil = lift . notReadyUntil
@@ -108,3 +109,8 @@ instance HasJSContext m => HasJSContext (InputDisabledT m) where
108instance HasJS js m => HasJS js (InputDisabledT m) where
109instance HasJS js m => HasJS js (InputDisabledT m) where
109 type JSX (InputDisabledT m) = JSX m
110 type JSX (InputDisabledT m) = JSX m
110 liftJS = lift . liftJS
111 liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (InputDisabledT m) where
114+ withRenderHook f = InputDisabledT . withRenderHook f . runInputDisabledT
115+ requestDomAction = InputDisabledT . requestDomAction
116+ requestDomAction_ = InputDisabledT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Builder/Static.hs+1−1
@@ -288,7 +288,7 @@ instance SupportsStaticDomBuilder t m => DomBuilder t (StaticDomBuilderT t m) wh
288 StaticDomBuilderT $ do
288 StaticDomBuilderT $ do
289 let shouldEscape = elementTag `Set.notMember` noEscapeElements
289 let shouldEscape = elementTag `Set.notMember` noEscapeElements
290 (result, innerHtml) <- lift $ lift $ runStaticDomBuilderT child $ StaticDomBuilderEnv shouldEscape Nothing
290 (result, innerHtml) <- lift $ lift $ runStaticDomBuilderT child $ StaticDomBuilderEnv shouldEscape Nothing
291− attrs0 <- foldDyn applyMap (Map.insert "data-ssr" "" $ cfg ^. initialAttributes) (cfg ^. modifyAttributes)
291+ attrs0 <- foldDyn applyMap (cfg ^. initialAttributes) (cfg ^. modifyAttributes)
292 selectValue <- asks _staticDomBuilderEnv_selectValue
292 selectValue <- asks _staticDomBuilderEnv_selectValue
293 let addSelectedAttr attrs sel = case Map.lookup "value" attrs of
293 let addSelectedAttr attrs sel = case Map.lookup "value" attrs of
294 Just v | v == sel -> attrs <> Map.singleton "selected" ""
294 Just v | v == sel -> attrs <> Map.singleton "selected" ""
reflex-dom-core/src/Reflex/Dom/Core.hs+1
@@ -6,6 +6,7 @@ module Reflex.Dom.Core (module X) where
6
6
7import Reflex as X hiding (askEvents)
7import Reflex as X hiding (askEvents)
8import Reflex.Dom.Builder.Class as X
8import Reflex.Dom.Builder.Class as X
9+import Reflex.Dom.Builder.Hydratable as X
9import Reflex.Dom.Builder.Immediate as X
10import Reflex.Dom.Builder.Immediate as X
10import Reflex.Dom.Builder.InputDisabled as X
11import Reflex.Dom.Builder.InputDisabled as X
11import Reflex.Dom.Builder.Static as X
12import Reflex.Dom.Builder.Static as X
reflex-dom-core/src/Reflex/Dom/Prerender.hs+7−2
@@ -33,6 +33,7 @@ import Foreign.JavaScript.TH
33import GHCJS.DOM.Types (MonadJSM)
33import GHCJS.DOM.Types (MonadJSM)
34import Reflex hiding (askEvents)
34import Reflex hiding (askEvents)
35import Reflex.Dom.Builder.Class
35import Reflex.Dom.Builder.Class
36+import Reflex.Dom.Builder.Hydratable
36import Reflex.Dom.Builder.Immediate
37import Reflex.Dom.Builder.Immediate
37import Reflex.Dom.Builder.InputDisabled
38import Reflex.Dom.Builder.InputDisabled
38import Reflex.Dom.Builder.Static
39import Reflex.Dom.Builder.Static
@@ -283,8 +284,12 @@ instance (Prerender js t m, Monad m, Reflex t, MonadFix m, Group q, Additive q,
283 pure a
284 pure a
284
285
285instance (Prerender js t m, Monad m) => Prerender js t (InputDisabledT m) where
286instance (Prerender js t m, Monad m) => Prerender js t (InputDisabledT m) where
286− type Client (InputDisabledT m) = Client m
287+ type Client (InputDisabledT m) = InputDisabledT (Client m)
287− prerender (InputDisabledT server) client = InputDisabledT $ prerender server client
288+ prerender (InputDisabledT server) (InputDisabledT client) = InputDisabledT $ prerender server client
289+
290+instance (Prerender js t m, Monad m) => Prerender js t (HydratableT m) where
291+ type Client (HydratableT m) = HydratableT (Client m)
292+ prerender (HydratableT server) (HydratableT client) = HydratableT $ prerender server client
288
293
289instance (Prerender js t m, Monad m, ReflexHost t) => Prerender js t (PostBuildT t m) where
294instance (Prerender js t m, Monad m, ReflexHost t) => Prerender js t (PostBuildT t m) where
290 type Client (PostBuildT t m) = PostBuildT t (Client m)
295 type Client (PostBuildT t m) = PostBuildT t (Client m)
reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+5−4
@@ -60,6 +60,7 @@ module Reflex.Dom.Widget.Basic
60 , partitionMapBySetLT
60 , partitionMapBySetLT
61 ) where
61 ) where
62
62
63+import Reflex.Adjustable.Class
63import Reflex.Class
64import Reflex.Class
64import Reflex.Collection
65import Reflex.Collection
65import Reflex.Dom.Builder.Class
66import Reflex.Dom.Builder.Class
@@ -146,21 +147,21 @@ button t = do
146-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
147-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
147-- The returned Event of widget results occurs when the Dynamic does.
148-- The returned Event of widget results occurs when the Dynamic does.
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').
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 'switchHold').
149−dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
150+dyn :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
150dyn = networkView
151dyn = networkView
151
152
152-- | Like 'dyn' but discards result.
153-- | Like 'dyn' but discards result.
153−dyn_ :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m ()
154+dyn_ :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m ()
154dyn_ = void . dyn
155dyn_ = void . dyn
155
156
156-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
157-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
157-- The returned Dynamic of widget results occurs when the Event does.
158-- The returned Dynamic of widget results occurs when the Event does.
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').
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 (via 'switchDyn').
159−widgetHold :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
160+widgetHold :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
160widgetHold = networkHold
161widgetHold = networkHold
161
162
162-- | Like 'widgetHold' but discards result.
163-- | Like 'widgetHold' but discards result.
163−widgetHold_ :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m ()
164+widgetHold_ :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m ()
164widgetHold_ z = void . widgetHold z
165widgetHold_ z = void . widgetHold z
165
166
166-- | Create a DOM element
167-- | Create a DOM element
reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+4
@@ -33,6 +33,10 @@ import 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@
36+--
37+-- This function can cause strange scrollbars to appear in some circumstances.
38+-- These can be hidden with pseudo selectors, for example, in webkit browsers:
39+-- .wrapper *::-webkit-scrollbar { width: 0px; background: transparent; }
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)
40resizeDetector :: (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 ""
41resizeDetector = resizeDetectorWithStyle ""
38
42
reflex-dom-core/test/hlint.hs+1
@@ -20,6 +20,7 @@ main = do
20 , "--ignore=Unnecessary hiding" -- Interferes with cross-version compatibility
20 , "--ignore=Unnecessary hiding" -- Interferes with cross-version compatibility
21 , "--ignore=Use <$>"
21 , "--ignore=Use <$>"
22 , "--ignore=Reduce duplication" --TODO: Re-enable this test
22 , "--ignore=Reduce duplication" --TODO: Re-enable this test
23+ , "--ignore=Use list comprehension"
23 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 ]
25 ]
25 if null ideas then exitSuccess else exitFailure
26 if null ideas then exitSuccess else exitFailure
reflex-dom-core/test/hydration.hs+11−5
@@ -54,6 +54,7 @@ import System.IO (stderr)
54import System.IO.Silently
54import System.IO.Silently
55import System.IO.Temp
55import System.IO.Temp
56import System.Process
56import System.Process
57+import System.Which (staticWhich)
57import qualified Test.HUnit as HUnit (assertEqual, assertFailure)
58import qualified Test.HUnit as HUnit (assertEqual, assertFailure)
58import qualified Test.Hspec as H
59import qualified Test.Hspec as H
59import qualified Test.Hspec.Core.Spec as H
60import qualified Test.Hspec.Core.Spec as H
@@ -77,6 +78,9 @@ import qualified Test.WebDriver.Capabilities as WD
77import Test.Util.ChromeFlags
78import Test.Util.ChromeFlags
78import Test.Util.UnshareNetwork
79import Test.Util.UnshareNetwork
79
80
81+chromium :: FilePath
82+chromium = $(staticWhich "chromium")
83+
80seleniumPort, jsaddlePort :: PortNumber
84seleniumPort, jsaddlePort :: PortNumber
81seleniumPort = 8000
85seleniumPort = 8000
82jsaddlePort = 8001
86jsaddlePort = 8001
@@ -128,7 +132,7 @@ main = do
128 isHeadless <- (== Nothing) <$> lookupEnv "NO_HEADLESS"
132 isHeadless <- (== Nothing) <$> lookupEnv "NO_HEADLESS"
129 withSandboxedChromeFlags isHeadless $ \chromeFlags -> do
133 withSandboxedChromeFlags isHeadless $ \chromeFlags -> do
130 withSeleniumServer $ \selenium -> do
134 withSeleniumServer $ \selenium -> do
131− browserPath <- liftIO $ T.strip . T.pack <$> readProcess "which" [ "chromium" ] ""
135+ let browserPath = T.strip $ T.pack chromium
132 when (T.null browserPath) $ fail "No browser found"
136 when (T.null browserPath) $ fail "No browser found"
133 withDebugging <- isNothing <$> lookupEnv "NO_DEBUG"
137 withDebugging <- isNothing <$> lookupEnv "NO_DEBUG"
134 let wdConfig = WD.defaultConfig { WD.wdPort = fromIntegral $ _selenium_portNumber selenium }
138 let wdConfig = WD.defaultConfig { WD.wdPort = fromIntegral $ _selenium_portNumber selenium }
@@ -1205,7 +1209,9 @@ tests withDebugging wdConfig caps _selenium = do
1205 let preSwitchover = do
1209 let preSwitchover = do
1206 checkBodyText "before\ninner\nafter"
1210 checkBodyText "before\ninner\nafter"
1207 -- Two <p> tags should be present
1211 -- Two <p> tags should be present
1208− [p1, p2] <- WD.findElems (WD.ByTag "p")
1212+ (p1, p2) <- WD.findElems (WD.ByTag "p") >>= \case
1213+ [p1, p2] -> pure (p1, p2)
1214+ _ -> error "Unexpected number of `p` tags (expected 2)"
1209 ol <- findElemWithRetry (WD.ByTag "ol")
1215 ol <- findElemWithRetry (WD.ByTag "ol")
1210 shouldContainText "before" p1
1216 shouldContainText "before" p1
1211 shouldContainText "inner" ol
1217 shouldContainText "inner" ol
@@ -1349,9 +1355,9 @@ testWidgetDebug' withDebugging beforeJS afterSwitchover bodyWidget = do
1349 el "body" $ do
1355 el "body" $ do
1350 bodyWidget
1356 bodyWidget
1351 el "script" $ text $ TE.decodeUtf8 $ LBS.toStrict $ jsaddleJs False
1357 el "script" $ text $ TE.decodeUtf8 $ LBS.toStrict $ jsaddleJs False
1352− putStrLnDebug "rendering preSwitchover"
1358+ putStrLnDebug "rendering static"
1353− ((), html) <- liftIO $ renderStatic staticApp
1359+ ((), html) <- liftIO $ renderStatic $ runHydratableT staticApp
1354− putStrLnDebug "rendered preSwitchover"
1360+ putStrLnDebug "rendered static"
1355 waitBeforeJS <- liftIO newEmptyMVar -- Empty until JS should be run
1361 waitBeforeJS <- liftIO newEmptyMVar -- Empty until JS should be run
1356 waitUntilSwitchover <- liftIO newEmptyMVar -- Empty until switchover
1362 waitUntilSwitchover <- liftIO newEmptyMVar -- Empty until switchover
1357 let entryPoint = do
1363 let entryPoint = do
reflex-dom/default.nixdeleted−38
@@ -1,38 +0,0 @@
1−{ mkDerivation, base, bytestring, jsaddle-webkit2gtk, jsaddle-wkwebview, jsaddle-warp, reflex
2−, reflex-dom-core, stdenv, text, ghc, hostPlatform, jsaddle-clib, android-activity ? null
3−, ghcBackend ? if hostPlatform.isDarwin then "wkwebview" else "webkit2gtk"
4−}:
5−assert (builtins.elem ghcBackend [ "warp" "webkit2gtk" "wkwebview" ]);
6−let isAndroid = hostPlatform.libc == "bionic";
7− ghcBackendPackage = {
8− webkit2gtk = jsaddle-webkit2gtk;
9− warp = jsaddle-warp;
10− wkwebview = jsaddle-wkwebview;
11− }.${ghcBackend};
12−in mkDerivation {
13− pname = "reflex-dom";
14− version = "0.5.2";
15− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16− libraryHaskellDepends = [
17− base bytestring reflex reflex-dom-core text
18− ] ++ (if ghc.isGhcjs or false then [
19− ] else if hostPlatform.isiOS then [
20− jsaddle-wkwebview
21− ] else if isAndroid then [
22− jsaddle-clib
23− android-activity
24− ] else if hostPlatform.isMacOS then [
25− jsaddle-wkwebview
26− ghcBackendPackage
27− ] else [
28− ghcBackendPackage
29− ]);
30− configureFlags = if isAndroid then [
31− "-fandroid"
32− ] else if ghcBackend == "warp" then [
33− "-fuse-warp"
34− ] else [
35− ];
36− description = "Functional Reactive Web Apps with Reflex";
37− license = stdenv.lib.licenses.bsd3;
38−}
reflex-dom/reflex-dom.cabal+3−8
@@ -1,5 +1,5 @@
1Name: reflex-dom
1Name: reflex-dom
2−Version: 0.5.2
2+Version: 0.5.2.0
3Synopsis: Functional Reactive Web Apps with Reflex
3Synopsis: Functional Reactive Web Apps with Reflex
4Description:
4Description:
5 Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine.
5 Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine.
@@ -41,14 +41,9 @@ flag build-examples
41 default: False
41 default: False
42 manual: True
42 manual: True
43
43
44−flag android
45− description: Build an Android app
46− default: False
47− manual: True
48−
49library
44library
50 hs-source-dirs: src
45 hs-source-dirs: src
51− if flag(android)
46+ if os(android)
52 hs-source-dirs: src-android
47 hs-source-dirs: src-android
53 other-modules: Reflex.Dom.Android.MainWidget
48 other-modules: Reflex.Dom.Android.MainWidget
54 build-depends:
49 build-depends:
@@ -83,7 +78,7 @@ library
83 build-depends:
78 build-depends:
84 jsaddle-webkit2gtk
79 jsaddle-webkit2gtk
85 else
80 else
86− if !flag(android)
81+ if !os(android)
87 build-depends:
82 build-depends:
88 jsaddle-webkit2gtk
83 jsaddle-webkit2gtk
89
84
reflex-platform.nixdeleted−8
@@ -1,8 +0,0 @@
1−let
2− reflex-platform-src = (import <nixpkgs> {}).fetchFromGitHub {
3− owner = "reflex-frp";
4− repo = "reflex-platform";
5− rev = "384cd850f3adf1d404bced2424b5f6efb0f415f2";
6− sha256 = "1ws77prqx8khmp8j6br1ij4k2v4dlgv170r9fmg0p1jivfbn8y9d";
7− };
8−in import reflex-platform-src
release.nix+32−9
@@ -1,12 +1,35 @@
1−{ rp ? import ./reflex-platform.nix {}
1+{ reflex-platform-fun ? import ./dep/reflex-platform
2}:
2}:
3+
3let
4let
5+ native-reflex-platform = reflex-platform-fun {};
4− inherit (rp.nixpkgs) lib;
6+ inherit (native-reflex-platform.nixpkgs) lib;
5 systems = ["x86_64-linux" "x86_64-darwin"];
7 systems = ["x86_64-linux" "x86_64-darwin"];
6− compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
8+
7−in lib.genAttrs systems (system:
9+ perPlatform = lib.genAttrs systems (system: let
8− lib.genAttrs compilers (ghc: let
9− reflex-platform = import ./reflex-platform.nix { inherit system; };
10+ reflex-platform = reflex-platform-fun { inherit system; };
11+ compilers = [
12+ "ghc"
13+ "ghcjs"
14+ ] ++ lib.optionals (reflex-platform.androidSupport) [
15+ "ghcAndroidAarch64"
16+ "ghcAndroidAarch32"
17+ ] ++ lib.optionals (reflex-platform.iosSupport) [
18+ "ghcIosAarch64"
19+ ];
20+ hsPkgs = lib.genAttrs compilers (ghc: let
10− hsPkgs = reflex-platform.${ghc};
21+ ghc' = reflex-platform.${ghc}.override {
22+ overrides = self: super: import ./. self;
23+ };
24+ in {
11− in { inherit (import ./. hsPkgs reflex-platform.nixpkgs) reflex-dom reflex-dom-core; })
25+ inherit (ghc') reflex-dom reflex-dom-core;
26+ });
27+ in hsPkgs // {
28+ cache = reflex-platform.pinBuildInputs "reflex-dom-${system}"
29+ (lib.concatLists (map builtins.attrValues (builtins.attrValues hsPkgs)));
12−)
30+ });
31+
32+ metaCache = native-reflex-platform.pinBuildInputs "reflex-dom-everywhere"
33+ (map (a: a.cache) (builtins.attrValues perPlatform));
34+
35+in perPlatform // { inherit metaCache; }