From eb19b8ff68b3dfd29957b8e7679fa207ce1a53e6 Mon Sep 17 00:00:00 2001 From: Jan Vincent Liwanag Date: Fri, 2 Aug 2019 13:03:44 +0800 Subject: [PATCH 1/2] Add support for React Context * See https://reactjs.org/docs/context.html --- src/React/Basic.js | 8 ++++++++ src/React/Basic.purs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/React/Basic.js b/src/React/Basic.js index 803c9c3..acf7f48 100644 --- a/src/React/Basic.js +++ b/src/React/Basic.js @@ -218,3 +218,11 @@ exports.toReactComponent = function(_unionDict) { }; }; }; + +exports.createContext = function(defaultValue) { + var context = React.createContext(defaultValue); + return { + consumer: context.Consumer, + provider: context.Provider + }; +}; diff --git a/src/React/Basic.purs b/src/React/Basic.purs index 4546723..411aa8b 100644 --- a/src/React/Basic.purs +++ b/src/React/Basic.purs @@ -21,6 +21,10 @@ module React.Basic , ReactComponentInstance , toReactComponent , Ref + , ReactContext + , createContext + , provider + , consumer ) where import Prelude @@ -369,6 +373,46 @@ foreign import toReactComponent -> { render :: Self props state -> JSX | spec } -> ReactComponent { | jsProps } +type ReactContext a = + { provider :: ReactComponent { value :: a, children :: Array JSX } + , consumer :: ReactComponent { children :: a -> Array JSX } + } + +-- | Create a `ReactContext` given a default value. Use `provider` and `consumer` +-- | to provide and consume context values. Alternatively, use the fields of +-- | `ReactContext` directly if a `ReactComponent` is required for interop. +-- | +-- | ```purs +-- | render self = +-- | R.div_ +-- | [ R.button +-- | { onClick: capture_ $ self.setState \s -> s { counter = s.counter + 1 } +-- | , children: [ R.text "Tick!" ] +-- | } +-- | , provider countContext self.state.counter +-- | [ consumer countContext \counter -> +-- | [ R.text $ "Ticks: " <> (show counter) +-- | ] +-- | ] +-- | ] +-- | ``` +-- | +-- | __*See also:* `provider`, `consumer`, React's documentation regarding Context__ +foreign import createContext :: forall a. a -> ReactContext a + +-- | Create a provider `JSX` given a context value and children. +-- | +-- | __*See also:* `createContext`, `consumer`__ +provider :: forall a. ReactContext a -> a -> Array JSX -> JSX +provider context value children = + element context.provider { value, children } + +-- | Create a consumer `JSX` from a context value to children. +-- | +-- | __*See also:* `createContext`, `producer`__ +consumer :: forall a. ReactContext a -> (a -> Array JSX) -> JSX +consumer context children = + element context.consumer { children } -- | -- | Internal utility or FFI functions From 24de5ef30591d32171ebbfe416ecc1952075a611 Mon Sep 17 00:00:00 2001 From: Jan Vincent Liwanag Date: Fri, 2 Aug 2019 15:17:52 +0800 Subject: [PATCH 2/2] Change ReactContext to be foreign data type --- src/React/Basic.js | 14 ++++++++++---- src/React/Basic.purs | 27 ++++++++++++++++++--------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/React/Basic.js b/src/React/Basic.js index acf7f48..641501e 100644 --- a/src/React/Basic.js +++ b/src/React/Basic.js @@ -220,9 +220,15 @@ exports.toReactComponent = function(_unionDict) { }; exports.createContext = function(defaultValue) { - var context = React.createContext(defaultValue); - return { - consumer: context.Consumer, - provider: context.Provider + return function () { + return React.createContext(defaultValue); }; }; + +exports.contextProvider = function(context) { + return context.Provider; +}; + +exports.contextConsumer = function(context) { + return context.Consumer; +}; diff --git a/src/React/Basic.purs b/src/React/Basic.purs index 411aa8b..91a9fa5 100644 --- a/src/React/Basic.purs +++ b/src/React/Basic.purs @@ -23,6 +23,8 @@ module React.Basic , Ref , ReactContext , createContext + , contextConsumer + , contextProvider , provider , consumer ) where @@ -373,14 +375,11 @@ foreign import toReactComponent -> { render :: Self props state -> JSX | spec } -> ReactComponent { | jsProps } -type ReactContext a = - { provider :: ReactComponent { value :: a, children :: Array JSX } - , consumer :: ReactComponent { children :: a -> Array JSX } - } +foreign import data ReactContext :: Type -> Type -- | Create a `ReactContext` given a default value. Use `provider` and `consumer` --- | to provide and consume context values. Alternatively, use the fields of --- | `ReactContext` directly if a `ReactComponent` is required for interop. +-- | to provide and consume context values. Alternatively, use `contextProvider` +-- | and `contextConsumer` directly if a `ReactComponent` is required for interop. -- | -- | ```purs -- | render self = @@ -398,21 +397,31 @@ type ReactContext a = -- | ``` -- | -- | __*See also:* `provider`, `consumer`, React's documentation regarding Context__ -foreign import createContext :: forall a. a -> ReactContext a +foreign import createContext :: forall a. a -> Effect (ReactContext a) + +foreign import contextProvider + :: forall a + . ReactContext a + -> ReactComponent { value :: a, children :: Array JSX } + +foreign import contextConsumer + :: forall a + . ReactContext a + -> ReactComponent { children :: a -> Array JSX } -- | Create a provider `JSX` given a context value and children. -- | -- | __*See also:* `createContext`, `consumer`__ provider :: forall a. ReactContext a -> a -> Array JSX -> JSX provider context value children = - element context.provider { value, children } + element (contextProvider context) { value, children } -- | Create a consumer `JSX` from a context value to children. -- | -- | __*See also:* `createContext`, `producer`__ consumer :: forall a. ReactContext a -> (a -> Array JSX) -> JSX consumer context children = - element context.consumer { children } + element (contextConsumer context) { children } -- | -- | Internal utility or FFI functions