diff --git a/__tests__/reductiveContext_test.re b/__tests__/reductiveContext_test.re
deleted file mode 100644
index 6756bbb..0000000
--- a/__tests__/reductiveContext_test.re
+++ /dev/null
@@ -1,309 +0,0 @@
-[@bs.config {jsx: 3}];
-open Jest;
-open Expect;
-open ReasonHooksTestingLibrary;
-
-module TestStoreContext = {
- type testState = {
- counter: int,
- content: string,
- };
-
- type testAction =
- | Increment
- | Decrement
- | AppendA
- | AppendB
- | Reset;
-
- let testReducer = (state, action) =>
- switch (action) {
- | Increment => {...state, counter: state.counter + 1}
- | Decrement => {...state, counter: state.counter - 1}
- | AppendA => {...state, content: state.content ++ "A"}
- | AppendB => {...state, content: state.content ++ "B"}
- | Reset => {counter: 0, content: ""}
- };
-
- let appStore =
- Reductive.Store.create(
- ~reducer=testReducer,
- ~preloadedState={counter: 0, content: ""},
- (),
- );
-
- include ReductiveContext.Make({
- type action = testAction;
- type state = testState;
- });
-};
-
-module App = {
- [@react.component]
- let make = (~children) => {
-
- children
- ;
- };
-};
-
-type selectorMockTest = {. "selector": TestStoreContext.testState => int};
-type spyReturnMockValue = string;
-
-let getResult = container =>
- container->Testing.Result.result->Testing.Result.current;
-
-describe("reductiveContext", () => {
- open Testing;
- open ReactTestingLibrary;
-
- let options = Options.t(~wrapper=App.make, ());
- beforeEach(() =>
- Reductive.Store.dispatch(TestStoreContext.appStore, Reset)
- );
-
- describe("useSelector", () => {
- test("sets initial state correctly", () => {
- let selector = (state: TestStoreContext.testState) => state.counter;
-
- let container =
- renderHook(
- () => TestStoreContext.useSelector(selector),
- ~options,
- (),
- );
-
- expect(getResult(container)) |> toEqual(0);
- });
-
- test("selects the state and re-renders component on store updates", () => {
- let selector = (state: TestStoreContext.testState) => state.counter;
-
- let container =
- renderHook(
- () => TestStoreContext.useSelector(selector),
- ~options,
- (),
- );
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment);
- ();
- });
-
- expect(getResult(container)) |> toEqual(1);
- });
-
- test("always gives back the latest state", () => {
- let selector = (state: TestStoreContext.testState) => state.counter;
- let renderedStates: ref(array(int)) = ref([||]);
-
- module Comp = {
- [@react.component]
- let make = () => {
- let counter = TestStoreContext.useSelector(selector);
- renderedStates := Belt.Array.concat(renderedStates^, [|counter|]);
-
;
- };
- };
-
- let element = ;
- render(element) |> ignore;
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment);
- Reductive.Store.dispatch(TestStoreContext.appStore, Decrement);
- ();
- });
-
- expect(renderedStates^) |> toEqual([|0, 1, 0|]);
- });
-
- test("prevents re-render if selected state is referentially equal", () => {
- let renderedStates: ref(array(int)) = ref([||]);
- let selector = (state: TestStoreContext.testState) => state.counter;
-
- module Comp = {
- [@react.component]
- let make = () => {
- let counter = TestStoreContext.useSelector(selector);
- renderedStates := Belt.Array.concat(renderedStates^, [|counter|]);
-
;
- };
- };
-
- let element = ;
- render(element) |> ignore;
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, AppendA);
- Reductive.Store.dispatch(TestStoreContext.appStore, AppendB);
- ();
- });
-
- expect(renderedStates^) |> toEqual([|0|]);
- });
-
- test("correctly updates selected state if selector depends on props", () => {
- let renderedStates: ref(array(int)) = ref([||]);
-
- module Comp = {
- [@react.component]
- let make = (~prop) => {
- let selector =
- React.useCallback1(
- (s: TestStoreContext.testState) => s.counter + prop,
- [|prop|],
- );
-
- let counter = TestStoreContext.useSelector(selector);
-
- renderedStates := Belt.Array.concat(renderedStates^, [|counter|]);
-
;
- };
- };
-
- let updateProp = ref(() => ());
- module Parent = {
- [@react.component]
- let make = () => {
- let (prop, dispatch) = React.useReducer((s, _) => s + 1, 0);
- updateProp := dispatch;
- ;
- };
- };
- let element = ;
-
- render(element) |> ignore;
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment); // state.counter - 1, prop - 0, total - 1
- updateProp^(); // state.counter - 1, prop - 1, total - 2
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment); // state.counter - 2, prop - 1, total - 3
- updateProp^(); // state.counter - 2, prop - 2, total - 4
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment); // state.counter - 3, prop - 2, total - 5
- ();
- });
-
- // changing selector function that depends on props leads to double re-render and duplicated state values
- let distinctRenderState =
- (renderedStates^)
- ->Belt.Array.keepWithIndex((value, index) =>
- (renderedStates^)
- ->Belt.Array.getIndexBy(v => v === value)
- ->Belt.Option.getWithDefault(-1)
- === index
- );
- expect(distinctRenderState) |> toEqual([|0, 1, 2, 3, 4, 5|]);
- });
-
- test("removes subscription on unmount", () => {
- let setupSpy: selectorMockTest => spyReturnMockValue = [%bs.raw
- {|
- function (obj) {
- return jest.spyOn(obj, "selector");
- }
- |}
- ];
-
- let selector = (state: TestStoreContext.testState) => state.counter;
- let selectorSpyObject = ref({"selector": selector});
-
- let selectStateFromSpy = state => {
- let spySelector = (selectorSpyObject^)##selector;
- spySelector(state);
- };
-
- module Comp = {
- [@react.component]
- let make = () => {
- let _ = TestStoreContext.useSelector(selectStateFromSpy);
-
;
- };
- };
-
- let element = ;
- render(element) |> unmount() |> ignore;
-
- // start spying after unmount
- let spy = setupSpy(selectorSpyObject^);
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment);
- Reductive.Store.dispatch(TestStoreContext.appStore, Decrement);
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment);
- ();
- });
-
- let expectSelectorToHaveBeenCalled: spyReturnMockValue => unit = [%bs.raw
- {|
- function (spy) {
- console.log(spy)
- return expect(spy).toHaveBeenCalledTimes(0)
- }
- |}
- ];
-
- expectSelectorToHaveBeenCalled(spy);
- expect(true) |> toEqual(true);
- });
- });
-
- describe("useStore", () => {
- test("gets the store", () => {
- let container =
- renderHook(() => TestStoreContext.useStore(), ~options, ());
-
- expect(getResult(container)) |> toEqual(TestStoreContext.appStore);
- });
-
- test("re-renders component on store updates", () => {
- let container =
- renderHook(() => TestStoreContext.useStore(), ~options, ());
-
- act(() => {
- Reductive.Store.dispatch(TestStoreContext.appStore, Increment);
- ();
- });
-
- let state = container->getResult->Reductive.Store.getState;
- expect(state.counter) |> toEqual(1);
- });
- });
-
- describe("useDispatch", () =>
- test("has stable reference", () => {
- let dispatchRerenders: ref(int) = ref(0);
- let forceRender = ref(() => ());
-
- module Comp = {
- [@react.component]
- let make = () => {
- let (_, setState) = React.useState(() => 0);
- forceRender := (() => setState(prev => prev + 1));
-
- let dispatch = TestStoreContext.useDispatch();
- React.useEffect1(
- () => {
- dispatchRerenders := dispatchRerenders^ + 1;
- None;
- },
- [|dispatch|],
- );
-
;
- };
- };
-
- let element = ;
- render(element) |> ignore;
-
- act(() => {
- forceRender^();
- forceRender^();
- forceRender^();
- ();
- });
- expect(dispatchRerenders^) |> toEqual(1);
- })
- );
-});
diff --git a/__tests__/reductiveContext_test.res b/__tests__/reductiveContext_test.res
new file mode 100644
index 0000000..0a89644
--- /dev/null
+++ b/__tests__/reductiveContext_test.res
@@ -0,0 +1,300 @@
+open Jest
+open Expect
+
+// Bindings to react-hooks testing library
+module HooksTestingLibrary = {
+ module Testing = {
+ module Result = {
+ @deriving({abstract: light})
+ type current<'value> = {current: 'value}
+
+ @deriving({abstract: light})
+ type t<'value> = {result: current<'value>}
+ }
+
+ module Options = {
+ @deriving({abstract: light})
+ type t<'props> = {
+ @optional
+ initialProps: 'props,
+ @optional
+ wrapper: React.component<{
+ "children": React.element,
+ }>,
+ }
+ }
+
+ @module("@testing-library/react-hooks")
+ external renderHook: (
+ @uncurry ('props => 'hook),
+ ~options: Options.t<'props>=?,
+ unit,
+ ) => Result.t<'hook> = "renderHook"
+ }
+}
+
+open HooksTestingLibrary
+
+module TestStoreContext = {
+ type testState = {
+ counter: int,
+ content: string,
+ }
+
+ type testAction =
+ | Increment
+ | Decrement
+ | AppendA
+ | AppendB
+ | Reset
+
+ let testReducer = (state, action) =>
+ switch action {
+ | Increment => {...state, counter: state.counter + 1}
+ | Decrement => {...state, counter: state.counter - 1}
+ | AppendA => {...state, content: state.content ++ "A"}
+ | AppendB => {...state, content: state.content ++ "B"}
+ | Reset => {counter: 0, content: ""}
+ }
+
+ let appStore = Reductive.Store.create(
+ ~reducer=testReducer,
+ ~preloadedState={counter: 0, content: ""},
+ (),
+ )
+
+ include ReductiveContext.Make({
+ type action = testAction
+ type state = testState
+ })
+}
+
+module App = {
+ @react.component
+ let make = (~children) =>
+
+ children
+
+}
+
+type selectorMockTest = {"selector": TestStoreContext.testState => int}
+type spyReturnMockValue = string
+
+let getResult = container => container->Testing.Result.result->Testing.Result.current
+
+describe("reductiveContext", () => {
+ open Testing
+ open! ReactTestingLibrary
+
+ let options = Options.t(~wrapper=App.make, ())
+ beforeEach(() => Reductive.Store.dispatch(TestStoreContext.appStore, Reset))
+
+ describe("useSelector", () => {
+ test("sets initial state correctly", () => {
+ let selector = (state: TestStoreContext.testState) => state.counter
+
+ let container = renderHook(() => TestStoreContext.useSelector(selector), ~options, ())
+
+ expect(getResult(container)) |> toEqual(0)
+ })
+
+ test("selects the state and re-renders component on store updates", () => {
+ let selector = (state: TestStoreContext.testState) => state.counter
+
+ let container = renderHook(() => TestStoreContext.useSelector(selector), ~options, ())
+
+ act(() => {
+ Reductive.Store.dispatch(TestStoreContext.appStore, Increment)
+ ()
+ })
+
+ expect(getResult(container)) |> toEqual(1)
+ })
+
+ test("always gives back the latest state", () => {
+ let selector = (state: TestStoreContext.testState) => state.counter
+ let renderedStates: ref> = ref([])
+
+ module Comp = {
+ @react.component
+ let make = () => {
+ let counter = TestStoreContext.useSelector(selector)
+ renderedStates := Belt.Array.concat(renderedStates.contents, [counter])
+
+ }
+ }
+
+ let element =
+ render(element) |> ignore
+
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment))
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Decrement))
+
+ expect(renderedStates.contents) |> toEqual([0, 1, 0])
+ })
+
+ test("prevents re-render if selected state is referentially equal", () => {
+ let renderedStates: ref> = ref([])
+ let selector = (state: TestStoreContext.testState) => state.counter
+
+ module Comp = {
+ @react.component
+ let make = () => {
+ let counter = TestStoreContext.useSelector(selector)
+ renderedStates := Belt.Array.concat(renderedStates.contents, [counter])
+
+ }
+ }
+
+ let element =
+ render(element) |> ignore
+
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, AppendA))
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, AppendB))
+
+ expect(renderedStates.contents) |> toEqual([0])
+ })
+
+ test("correctly updates selected state if selector depends on props", () => {
+ let renderedStates: ref> = ref([])
+
+ module Comp = {
+ @react.component
+ let make = (~prop) => {
+ let selector = React.useCallback1(
+ (s: TestStoreContext.testState) => s.counter + prop,
+ [prop],
+ )
+
+ let counter = TestStoreContext.useSelector(selector)
+
+ renderedStates := Belt.Array.concat(renderedStates.contents, [counter])
+
+ }
+ }
+
+ let updateProp = ref(() => ())
+ module Parent = {
+ @react.component
+ let make = () => {
+ let (prop, dispatch) = React.useReducer((s, _) => s + 1, 0)
+ updateProp := dispatch
+
+ }
+ }
+ let element =
+
+ render(element) |> ignore
+
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment)) // state.counter - 1, prop - 0, total - 1
+ act(() => updateProp.contents()) // state.counter - 1, prop - 1, total - 2
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment)) // state.counter - 2, prop - 1, total - 3
+ act(() => updateProp.contents()) // state.counter - 2, prop - 2, total - 4
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment)) // state.counter - 3, prop - 2, total - 5
+
+ // changing selector function that depends on props leads to double re-render and duplicated state values
+ let distinctRenderState =
+ renderedStates.contents->Belt.Array.keepWithIndex((value, index) =>
+ renderedStates.contents
+ ->Belt.Array.getIndexBy(v => v === value)
+ ->Belt.Option.getWithDefault(-1) === index
+ )
+ expect(distinctRenderState) |> toEqual([0, 1, 2, 3, 4, 5])
+ })
+
+ test("removes subscription on unmount", () => {
+ let setupSpy: selectorMockTest => spyReturnMockValue = %raw(`
+ function (obj) {
+ return jest.spyOn(obj, "selector");
+ }
+ `)
+
+ let selector = (state: TestStoreContext.testState) => state.counter
+ let selectorSpyObject = ref({"selector": selector})
+
+ let selectStateFromSpy = state => {
+ let spySelector = selectorSpyObject.contents["selector"]
+ spySelector(state)
+ }
+
+ module Comp = {
+ @react.component
+ let make = () => {
+ let _ = TestStoreContext.useSelector(selectStateFromSpy)
+
+ }
+ }
+
+ let element =
+ render(element) |> unmount() |> ignore
+
+ // start spying after unmount
+ let spy = setupSpy(selectorSpyObject.contents)
+
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment))
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Decrement))
+ act(() => Reductive.Store.dispatch(TestStoreContext.appStore, Increment))
+
+ let expectSelectorToHaveBeenCalled: spyReturnMockValue => unit = %raw(`
+ function (spy) {
+ console.log(spy)
+ return expect(spy).toHaveBeenCalledTimes(0)
+ }
+ `)
+
+ expectSelectorToHaveBeenCalled(spy)
+ expect(true) |> toEqual(true)
+ })
+ })
+
+ describe("useStore", () => {
+ test("gets the store", () => {
+ let container = renderHook(() => TestStoreContext.useStore(), ~options, ())
+
+ expect(getResult(container)) |> toEqual(TestStoreContext.appStore)
+ })
+
+ test("re-renders component on store updates", () => {
+ let container = renderHook(() => TestStoreContext.useStore(), ~options, ())
+
+ act(() => {
+ Reductive.Store.dispatch(TestStoreContext.appStore, Increment)
+ ()
+ })
+
+ let state = container->getResult->Reductive.Store.getState
+ expect(state.counter) |> toEqual(1)
+ })
+ })
+
+ describe("useDispatch", () =>
+ test("has stable reference", () => {
+ let dispatchRerenders: ref = ref(0)
+ let forceRender = ref(() => ())
+
+ module Comp = {
+ @react.component
+ let make = () => {
+ let (_, setState) = React.useState(() => 0)
+ forceRender := (() => setState(prev => prev + 1))
+
+ let dispatch = TestStoreContext.useDispatch()
+ React.useEffect1(() => {
+ dispatchRerenders := dispatchRerenders.contents + 1
+ None
+ }, [dispatch])
+
+ }
+ }
+
+ let element =
+ render(element) |> ignore
+
+ act(() => forceRender.contents())
+ act(() => forceRender.contents())
+ act(() => forceRender.contents())
+
+ expect(dispatchRerenders.contents) |> toEqual(1)
+ })
+ )
+})
diff --git a/bsconfig.json b/bsconfig.json
index ead74a2..da911d4 100644
--- a/bsconfig.json
+++ b/bsconfig.json
@@ -1,20 +1,14 @@
{
"name": "reductive",
"refmt": 3,
- "bsc-flags": [
- "-bs-super-errors"
- ],
+ "bsc-flags": ["-bs-super-errors"],
"reason": {
"react-jsx": 3
},
- "bs-dependencies": [
- "reason-react"
- ],
+ "bs-dependencies": ["@rescript/react"],
"bs-dev-dependencies": [
- "immutable-re",
"@glennsl/bs-jest",
- "bs-react-testing-library",
- "reason-hooks-testing-library"
+ "@rescriptbr/react-testing-library"
],
"sources": [
"src",
diff --git a/examples/basic/basicEntry.re b/examples/basic/basicEntry.re
deleted file mode 100644
index 45149ef..0000000
--- a/examples/basic/basicEntry.re
+++ /dev/null
@@ -1,48 +0,0 @@
-let unsubscribe = Reductive.Store.subscribe(SimpleStore.store, () => Js.log("store has updated"));
-
-let dispatch = Reductive.Store.dispatch(SimpleStore.store);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Decrement);
-
-dispatch(Increment);
-
-Reductive.Store.subscribe(
- SimpleStore.store,
- () => Js.log(Reductive.Store.getState(SimpleStore.store))
-);
-
-/* when replacing reducers, the action and state types must match*/
-Reductive.Store.replaceReducer(SimpleStore.store, SimpleStore.doubleCounter);
-
-dispatch(Increment);
-
-unsubscribe();
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-dispatch(Increment);
-
-Reductive.Store.subscribe(
- ComplexStore.store,
- () => Js.log(Reductive.Store.getState(ComplexStore.store))
-);
-
-Reductive.Store.dispatch(ComplexStore.store, ComplexStore.StringAction(A));
-
-Reductive.Store.dispatch(ComplexStore.store, ComplexStore.StringAction(B));
-
-Reductive.Store.dispatch(ComplexStore.store, ComplexStore.CounterAction(Increment));
diff --git a/examples/basic/basicEntry.res b/examples/basic/basicEntry.res
new file mode 100644
index 0000000..30694b0
--- /dev/null
+++ b/examples/basic/basicEntry.res
@@ -0,0 +1,46 @@
+let unsubscribe = Reductive.Store.subscribe(SimpleStore.store, () => Js.log("store has updated"))
+
+let dispatch = Reductive.Store.dispatch(SimpleStore.store)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Decrement)
+
+dispatch(Increment)
+
+let _: unit => unit = Reductive.Store.subscribe(SimpleStore.store, () =>
+ Js.log(Reductive.Store.getState(SimpleStore.store))
+)
+
+/* when replacing reducers, the action and state types must match */
+Reductive.Store.replaceReducer(SimpleStore.store, SimpleStore.doubleCounter)
+
+dispatch(Increment)
+
+unsubscribe()
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+dispatch(Increment)
+
+let _: unit => unit = Reductive.Store.subscribe(ComplexStore.store, () =>
+ Js.log(Reductive.Store.getState(ComplexStore.store))
+)
+
+Reductive.Store.dispatch(ComplexStore.store, ComplexStore.StringAction(A))
+
+Reductive.Store.dispatch(ComplexStore.store, ComplexStore.StringAction(B))
+
+Reductive.Store.dispatch(ComplexStore.store, ComplexStore.CounterAction(Increment))
diff --git a/examples/basic/complexStore.re b/examples/basic/complexStore.res
similarity index 64%
rename from examples/basic/complexStore.re
rename to examples/basic/complexStore.res
index 024547f..fa43d47 100644
--- a/examples/basic/complexStore.re
+++ b/examples/basic/complexStore.res
@@ -1,34 +1,33 @@
-open SimpleStore;
+open SimpleStore
type stringAction =
| A
- | B;
+ | B
let stringReduce = (state, action) =>
switch action {
| A => state ++ "a"
| B => state ++ "b"
- };
+ }
type appActions =
| StringAction(stringAction)
- | CounterAction(action);
+ | CounterAction(action)
type appState = {
counter: int,
- notACounter: string
-};
+ notACounter: string,
+}
let appReducer = (state, action) =>
switch action {
| StringAction(action) => {...state, notACounter: stringReduce(state.notACounter, action)}
| CounterAction(action) => {...state, counter: counter(state.counter, action)}
- };
+ }
-let store =
- Reductive.Store.create(
- ~reducer=appReducer,
- ~preloadedState={counter: 0, notACounter: ""},
- ~enhancer=Middleware.logger,
- ()
- );
+let store = Reductive.Store.create(
+ ~reducer=appReducer,
+ ~preloadedState={counter: 0, notACounter: ""},
+ ~enhancer=Middleware.logger,
+ (),
+)
diff --git a/examples/basic/simpleStore.re b/examples/basic/simpleStore.res
similarity index 89%
rename from examples/basic/simpleStore.re
rename to examples/basic/simpleStore.res
index 63b4911..62ee3d2 100644
--- a/examples/basic/simpleStore.re
+++ b/examples/basic/simpleStore.res
@@ -1,17 +1,17 @@
type action =
| Increment
- | Decrement;
+ | Decrement
let counter = (state, action) =>
switch action {
| Increment => state + 1
| Decrement => state - 1
- };
+ }
let doubleCounter = (state, action) =>
switch action {
| Increment => state + 2
| Decrement => state - 2
- };
+ }
-let store = Reductive.Store.create(~reducer=counter, ~preloadedState=0, ());
+let store = Reductive.Store.create(~reducer=counter, ~preloadedState=0, ())
diff --git a/examples/immutable/appState.re b/examples/immutable/appState.res
similarity index 57%
rename from examples/immutable/appState.re
rename to examples/immutable/appState.res
index 2615484..1d0e3cd 100644
--- a/examples/immutable/appState.re
+++ b/examples/immutable/appState.res
@@ -1,4 +1,4 @@
type appState = {
counter: int,
- notACounter: string
-};
+ notACounter: string,
+}
diff --git a/examples/immutable/immutableEntry.re b/examples/immutable/immutableEntry.re
deleted file mode 100644
index 6ae06ed..0000000
--- a/examples/immutable/immutableEntry.re
+++ /dev/null
@@ -1,7 +0,0 @@
-[@bs.config {jsx: 3}];
-ReactDOMRe.renderToElementWithId(
-
-
- ,
- "index",
-);
diff --git a/examples/immutable/immutableEntry.res b/examples/immutable/immutableEntry.res
new file mode 100644
index 0000000..83ba12c
--- /dev/null
+++ b/examples/immutable/immutableEntry.res
@@ -0,0 +1,7 @@
+ReactDOM.querySelector("#index")->Belt.Option.forEach(
+ ReactDOM.render(
+
+
+ ,
+ ),
+)
diff --git a/examples/immutable/immutableRenderer.re b/examples/immutable/immutableRenderer.re
deleted file mode 100644
index b883db8..0000000
--- a/examples/immutable/immutableRenderer.re
+++ /dev/null
@@ -1,50 +0,0 @@
-[@bs.config {jsx: 3}];
-
-let stateSelector = state => state;
-[@react.component]
-let make = () => {
- let state = TimeTravelStore.useSelector(stateSelector);
- let dispatch = TimeTravelStore.useDispatch();
-
- let incrementIfOdd =
- (store: Reductive.Store.t(ReduxThunk.thunk(AppState.appState), AppState.appState)) =>
- switch (Reductive.Store.getState(store)) {
- | {counter} when counter mod 2 === 1 =>
- Reductive.Store.dispatch(store, TimeTravelStore.CounterAction(SimpleStore.Increment))
- | _ => ()
- };
- let incrementAsync = (store) =>
- ignore(
- Js.Global.setTimeout(
- () =>
- Reductive.Store.dispatch(store, TimeTravelStore.CounterAction(SimpleStore.Increment)),
- 1000
- )
- );
-
-
-
(ReasonReact.string("string: " ++ state.notACounter))
-
(ReasonReact.string("counter: " ++ string_of_int(state.counter)))
-
dispatch(TimeTravelStore.CounterAction(SimpleStore.Increment)))>
- (ReasonReact.string("Increment"))
-
-
dispatch(TimeTravelStore.CounterAction(SimpleStore.Decrement)))>
- (ReasonReact.string("Decrement"))
-
-
dispatch(TimeTravelStore.StringAction(TimeTravelStore.A)))>
- (ReasonReact.string("add a"))
-
-
dispatch(ReduxThunk.Thunk(incrementAsync)))>
- (ReasonReact.string("Increment Async"))
-
-
dispatch(ReduxThunk.Thunk(incrementIfOdd)))>
- (ReasonReact.string("Increment if Odd"))
-
-
dispatch(TimeTravelStore.TravelBackward))>
- (ReasonReact.string("Undo"))
-
-
dispatch(TimeTravelStore.TravelForward))>
- (ReasonReact.string("Redo"))
-
-
;
-};
diff --git a/examples/immutable/immutableRenderer.res b/examples/immutable/immutableRenderer.res
new file mode 100644
index 0000000..655f337
--- /dev/null
+++ b/examples/immutable/immutableRenderer.res
@@ -0,0 +1,46 @@
+let stateSelector = state => state
+@react.component
+let make = () => {
+ let state = TimeTravelStore.useSelector(stateSelector)
+ let dispatch = TimeTravelStore.useDispatch()
+
+ let incrementIfOdd = (
+ store: Reductive.Store.t, AppState.appState>,
+ ) =>
+ switch Reductive.Store.getState(store) {
+ | {counter} if mod(counter, 2) === 1 =>
+ Reductive.Store.dispatch(store, TimeTravelStore.CounterAction(SimpleStore.Increment))
+ | _ => ()
+ }
+ let incrementAsync = store =>
+ ignore(
+ Js.Global.setTimeout(
+ () => Reductive.Store.dispatch(store, TimeTravelStore.CounterAction(SimpleStore.Increment)),
+ 1000,
+ ),
+ )
+
+
+
{React.string("string: " ++ state.notACounter)}
+
{React.string("counter: " ++ string_of_int(state.counter))}
+
dispatch(TimeTravelStore.CounterAction(SimpleStore.Increment))}>
+ {React.string("Increment")}
+
+
dispatch(TimeTravelStore.CounterAction(SimpleStore.Decrement))}>
+ {React.string("Decrement")}
+
+
dispatch(TimeTravelStore.StringAction(TimeTravelStore.A))}>
+ {React.string("add a")}
+
+
dispatch(ReduxThunk.Thunk(incrementAsync))}>
+ {React.string("Increment Async")}
+
+
dispatch(ReduxThunk.Thunk(incrementIfOdd))}>
+ {React.string("Increment if Odd")}
+
+
dispatch(TimeTravelStore.TravelBackward)}>
+ {React.string("Undo")}
+
+
dispatch(TimeTravelStore.TravelForward)}> {React.string("Redo")}
+
+}
diff --git a/examples/immutable/timeTravelStore.re b/examples/immutable/timeTravelStore.re
deleted file mode 100644
index b4d403a..0000000
--- a/examples/immutable/timeTravelStore.re
+++ /dev/null
@@ -1,94 +0,0 @@
-open SimpleStore;
-
-type stringAction =
- | A
- | B;
-
-let stringReduce = (state, action) =>
- switch action {
- | A => state ++ "a"
- | B => state ++ "b"
- };
-
-type ReduxThunk.thunk(_) +=
- | StringAction (stringAction)
- | CounterAction (action);
-
-type ReduxThunk.thunk('a) +=
- | ReplaceState ('a);
-
-let appReducter = (state: AppState.appState, action) =>
- switch action {
- | StringAction(action) => {...state, notACounter: stringReduce(state.notACounter, action)}
- | CounterAction(action) => {...state, counter: counter(state.counter, action)}
- | ReplaceState(replacedState) => replacedState
- | _ => state
- };
-
-type ReduxThunk.thunk(_) +=
- | TravelBackward
- | TravelForward;
-
-let past = ref(Immutable.Stack.empty());
-
-let future = ref(Immutable.Stack.empty());
-
-let goBack = currentState =>
- switch (Immutable.Stack.first(past^)) {
- | Some(lastState) =>
- future := Immutable.Stack.addFirst(currentState, future^);
- if (Immutable.Stack.isNotEmpty(past^)) {
- past := Immutable.Stack.removeFirstOrRaise(past^);
- };
- lastState;
- | None => currentState
- };
-
-let goForward = currentState =>
- switch (Immutable.Stack.first(future^)) {
- | Some(nextState) =>
- past := Immutable.Stack.addFirst(currentState, past^);
- if (Immutable.Stack.isNotEmpty(future^)) {
- future := Immutable.Stack.removeFirstOrRaise(future^);
- };
- nextState;
- | None => currentState
- };
-
-let recordHistory = currentState => {
- past := Immutable.Stack.addFirst(currentState, past^);
- future := Immutable.Stack.empty();
-};
-
-let timeTravel = (store, next, action) => {
- let currentState = Reductive.Store.getState(store);
- switch (action) {
- | TravelBackward => next(ReplaceState(goBack(currentState)))
- | TravelForward => next(ReplaceState(goForward(currentState)))
- | _ =>
- next(action);
- let newState = Reductive.Store.getState(store);
- if (currentState !== newState) {
- recordHistory(currentState);
- };
- };
-};
-
-let thunkedLoggedTimeTravelLogger = (store, next) =>
- Middleware.thunk(store) @@
- Middleware.logger(store) @@
- timeTravel(store) @@
- next;
-
-let timeTravelStore =
- Reductive.Store.create(
- ~reducer=appReducter,
- ~preloadedState={counter: 0, notACounter: ""},
- ~enhancer=thunkedLoggedTimeTravelLogger,
- (),
- );
-
-include ReductiveContext.Make({
- type action = ReduxThunk.thunk(AppState.appState);
- type state = AppState.appState;
-});
diff --git a/examples/immutable/timeTravelStore.res b/examples/immutable/timeTravelStore.res
new file mode 100644
index 0000000..8acef4e
--- /dev/null
+++ b/examples/immutable/timeTravelStore.res
@@ -0,0 +1,95 @@
+open SimpleStore
+
+type stringAction =
+ | A
+ | B
+
+let stringReduce = (state, action) =>
+ switch action {
+ | A => state ++ "a"
+ | B => state ++ "b"
+ }
+
+type ReduxThunk.thunk<_> +=
+ | StringAction(stringAction)
+ | CounterAction(action)
+
+type ReduxThunk.thunk<'a> +=
+ | ReplaceState('a)
+
+let appReducter = (state: AppState.appState, action) =>
+ switch action {
+ | StringAction(action) => {...state, notACounter: stringReduce(state.notACounter, action)}
+ | CounterAction(action) => {...state, counter: counter(state.counter, action)}
+ | ReplaceState(replacedState) => replacedState
+ | _ => state
+ }
+
+type ReduxThunk.thunk<_> +=
+ | TravelBackward
+ | TravelForward
+
+let past = ref(list{})
+
+let future = ref(list{})
+
+let goBack = currentState =>
+ switch Belt.List.head(past.contents) {
+ | Some(lastState) =>
+ future := Belt.List.add(future.contents, currentState)
+ past :=
+ switch past.contents {
+ | list{} => list{}
+ | list{_, ...t} => t
+ }
+ lastState
+ | None => currentState
+ }
+
+let goForward = currentState =>
+ switch Belt.List.head(future.contents) {
+ | Some(nextState) =>
+ past := Belt.List.add(past.contents, currentState)
+ future :=
+ switch future.contents {
+ | list{} => list{}
+ | list{_, ...t} => t
+ }
+
+ nextState
+ | None => currentState
+ }
+
+let recordHistory = currentState => {
+ past := Belt.List.add(past.contents, currentState)
+ future := list{}
+}
+
+let timeTravel = (store, next, action) => {
+ let currentState = Reductive.Store.getState(store)
+ switch action {
+ | TravelBackward => next(ReplaceState(goBack(currentState)))
+ | TravelForward => next(ReplaceState(goForward(currentState)))
+ | _ =>
+ next(action)
+ let newState = Reductive.Store.getState(store)
+ if currentState !== newState {
+ recordHistory(currentState)
+ }
+ }
+}
+
+let thunkedLoggedTimeTravelLogger = (store, next) =>
+ \"@@"(Middleware.thunk(store), \"@@"(Middleware.logger(store), \"@@"(timeTravel(store), next)))
+
+let timeTravelStore = Reductive.Store.create(
+ ~reducer=appReducter,
+ ~preloadedState={counter: 0, notACounter: ""},
+ ~enhancer=thunkedLoggedTimeTravelLogger,
+ (),
+)
+
+include ReductiveContext.Make({
+ type action = ReduxThunk.thunk
+ type state = AppState.appState
+})
diff --git a/examples/middleware.re b/examples/middleware.res
similarity index 85%
rename from examples/middleware.re
rename to examples/middleware.res
index fef168b..ef8a460 100644
--- a/examples/middleware.re
+++ b/examples/middleware.res
@@ -6,18 +6,17 @@
* return value can be used by the middleware that called you (optional)
*/
-/***
+/* **
* logs the action before dispatching and the new state after.
*/
let logger = (store, next, action) => {
- Js.log(action);
- let returnValue = next(action);
- Js.log(Reductive.Store.getState(store));
+ Js.log(action)
+ let returnValue = next(action)
+ Js.log(Reductive.Store.getState(store))
returnValue
-};
+}
-
-/***
+/* **
* middleware that listens for a specific action and calls that function.
* Allows for async actions.
*/
@@ -25,4 +24,4 @@ let thunk = (store, next, action) =>
switch action {
| ReduxThunk.Thunk(func) => func(store)
| _ => next(action)
- };
+ }
diff --git a/examples/react/dataRenderer.re b/examples/react/dataRenderer.re
deleted file mode 100644
index 6a4b4b7..0000000
--- a/examples/react/dataRenderer.re
+++ /dev/null
@@ -1,42 +0,0 @@
-let stateSelector = state => state;
-
-[@react.component]
-let make = () => {
- let state = ThunkedStore.useSelector(stateSelector);
- let dispatch = ThunkedStore.useDispatch();
-
- let incrementIfOdd =
- (store: Reductive.Store.t(ReduxThunk.thunk(ThunkedStore.appState), ThunkedStore.appState)) =>
- switch (Reductive.Store.getState(store)) {
- | {counter} when counter mod 2 === 1 =>
- Reductive.Store.dispatch(store, ThunkedStore.CounterAction(SimpleStore.Increment))
- | _ => ()
- };
- let incrementAsync = (store) =>
- ignore(
- Js.Global.setTimeout(
- () => Reductive.Store.dispatch(store, ThunkedStore.CounterAction(SimpleStore.Increment)),
- 1000
- )
- );
-
-
-
(ReasonReact.string("string: " ++ state.notACounter))
-
(ReasonReact.string("counter: " ++ string_of_int(state.counter)))
-
dispatch(ThunkedStore.CounterAction(SimpleStore.Increment)))>
- (ReasonReact.string("Increment"))
-
-
dispatch(ThunkedStore.CounterAction(SimpleStore.Decrement)))>
- (ReasonReact.string("Decrement"))
-
-
dispatch(ThunkedStore.StringAction(ThunkedStore.A)))>
- (ReasonReact.string("add a"))
-
-
dispatch(ReduxThunk.Thunk(incrementAsync)))>
- (ReasonReact.string("Increment Async"))
-
-
dispatch(ReduxThunk.Thunk(incrementIfOdd)))>
- (ReasonReact.string("Increment if Odd"))
-
-
;
-};
diff --git a/examples/react/dataRenderer.res b/examples/react/dataRenderer.res
new file mode 100644
index 0000000..6ba09e0
--- /dev/null
+++ b/examples/react/dataRenderer.res
@@ -0,0 +1,43 @@
+let stateSelector = state => state
+
+@react.component
+let make = () => {
+ let state = ThunkedStore.useSelector(stateSelector)
+ let dispatch = ThunkedStore.useDispatch()
+
+ let incrementIfOdd = (
+ store: Reductive.Store.t, ThunkedStore.appState>,
+ ) =>
+ switch Reductive.Store.getState(store) {
+ | {counter} if mod(counter, 2) === 1 =>
+ Reductive.Store.dispatch(store, ThunkedStore.CounterAction(SimpleStore.Increment))
+ | _ => ()
+ }
+ let incrementAsync = store =>
+ ignore(
+ Js.Global.setTimeout(
+ () => Reductive.Store.dispatch(store, ThunkedStore.CounterAction(SimpleStore.Increment)),
+ 1000,
+ ),
+ )
+
+
+
{React.string("string: " ++ state.notACounter)}
+
{React.string("counter: " ++ string_of_int(state.counter))}
+
dispatch(ThunkedStore.CounterAction(SimpleStore.Increment))}>
+ {React.string("Increment")}
+
+
dispatch(ThunkedStore.CounterAction(SimpleStore.Decrement))}>
+ {React.string("Decrement")}
+
+
dispatch(ThunkedStore.StringAction(ThunkedStore.A))}>
+ {React.string("add a")}
+
+
dispatch(ReduxThunk.Thunk(incrementAsync))}>
+ {React.string("Increment Async")}
+
+
dispatch(ReduxThunk.Thunk(incrementIfOdd))}>
+ {React.string("Increment if Odd")}
+
+
+}
diff --git a/examples/react/reactEntry.re b/examples/react/reactEntry.re
deleted file mode 100644
index 2fa98db..0000000
--- a/examples/react/reactEntry.re
+++ /dev/null
@@ -1,7 +0,0 @@
-[@bs.config {jsx: 3}];
-ReactDOMRe.renderToElementWithId(
-
-
- ,
- "index",
-);
diff --git a/examples/react/reactEntry.res b/examples/react/reactEntry.res
new file mode 100644
index 0000000..86fa6dc
--- /dev/null
+++ b/examples/react/reactEntry.res
@@ -0,0 +1,5 @@
+ReactDOM.querySelector("#index")->Belt.Option.forEach(
+ ReactDOM.render(
+ ,
+ ),
+)
diff --git a/examples/react/reduxThunk.re b/examples/react/reduxThunk.re
deleted file mode 100644
index ddfb302..0000000
--- a/examples/react/reduxThunk.re
+++ /dev/null
@@ -1,4 +0,0 @@
-type thunk('state) = ..;
-
-type thunk('state) +=
- | Thunk ((Reductive.Store.t(thunk('state), 'state) => unit));
diff --git a/examples/react/reduxThunk.res b/examples/react/reduxThunk.res
new file mode 100644
index 0000000..ee094fc
--- /dev/null
+++ b/examples/react/reduxThunk.res
@@ -0,0 +1,4 @@
+type thunk<'state> = ..
+
+type thunk<'state> +=
+ | Thunk(Reductive.Store.t, 'state> => unit)
diff --git a/examples/react/thunkedStore.re b/examples/react/thunkedStore.re
deleted file mode 100644
index bd8efc1..0000000
--- a/examples/react/thunkedStore.re
+++ /dev/null
@@ -1,43 +0,0 @@
-[@bs.config {jsx: 3}];
-open SimpleStore;
-
-type stringAction =
- | A
- | B;
-
-let stringReduce = (state, action) =>
- switch action {
- | A => state ++ "a"
- | B => state ++ "b"
- };
-
-type ReduxThunk.thunk(_) +=
- | StringAction (stringAction)
- | CounterAction (action);
-
-type appState = {
- counter: int,
- notACounter: string
-};
-
-let appReducer = (state, action) =>
- switch action {
- | StringAction(action) => {...state, notACounter: stringReduce(state.notACounter, action)}
- | CounterAction(action) => {...state, counter: counter(state.counter, action)}
- | _ => state
- };
-
-let thunkedLogger = (store, next) => Middleware.thunk(store) @@ Middleware.logger(store) @@ next;
-
-let appStore =
- Reductive.Store.create(
- ~reducer=appReducer,
- ~preloadedState={counter: 0, notACounter: ""},
- ~enhancer=thunkedLogger,
- (),
- );
-
-include ReductiveContext.Make({
- type state = appState;
- type action = ReduxThunk.thunk(appState);
-});
diff --git a/examples/react/thunkedStore.res b/examples/react/thunkedStore.res
new file mode 100644
index 0000000..eea3f87
--- /dev/null
+++ b/examples/react/thunkedStore.res
@@ -0,0 +1,42 @@
+open SimpleStore
+
+type stringAction =
+ | A
+ | B
+
+let stringReduce = (state, action) =>
+ switch action {
+ | A => state ++ "a"
+ | B => state ++ "b"
+ }
+
+type ReduxThunk.thunk<_> +=
+ | StringAction(stringAction)
+ | CounterAction(action)
+
+type appState = {
+ counter: int,
+ notACounter: string,
+}
+
+let appReducer = (state, action) =>
+ switch action {
+ | StringAction(action) => {...state, notACounter: stringReduce(state.notACounter, action)}
+ | CounterAction(action) => {...state, counter: counter(state.counter, action)}
+ | _ => state
+ }
+
+let thunkedLogger = (store, next) =>
+ \"@@"(Middleware.thunk(store), \"@@"(Middleware.logger(store), next))
+
+let appStore = Reductive.Store.create(
+ ~reducer=appReducer,
+ ~preloadedState={counter: 0, notACounter: ""},
+ ~enhancer=thunkedLogger,
+ (),
+)
+
+include ReductiveContext.Make({
+ type state = appState
+ type action = ReduxThunk.thunk
+})
diff --git a/examples/render-v2/renderEntryV2.re b/examples/render-v2/renderEntryV2.res
similarity index 50%
rename from examples/render-v2/renderEntryV2.re
rename to examples/render-v2/renderEntryV2.res
index e9b322c..2c0424f 100644
--- a/examples/render-v2/renderEntryV2.re
+++ b/examples/render-v2/renderEntryV2.res
@@ -9,39 +9,39 @@
module Counter = {
type counterAction =
| Increment
- | Decrement;
+ | Decrement
let counterReduce = (state, action) =>
- switch (action) {
+ switch action {
| Increment => state + 1
| Decrement => state - 1
- };
-};
+ }
+}
module Content = {
type contentAction =
| AppendA
- | AppendB;
+ | AppendB
let contentReduce = (state, action) =>
- switch (action) {
+ switch action {
| AppendA => state ++ "A"
| AppendB => state ++ "B"
- };
-};
+ }
+}
module App = {
type appState = {
counter: int,
content: string,
- };
+ }
type appAction =
| CounterAction(Counter.counterAction)
- | StringAction(Content.contentAction);
+ | StringAction(Content.contentAction)
let appReducer = (state, action) =>
- switch (action) {
+ switch action {
| StringAction(action) => {
...state,
content: Content.contentReduce(state.content, action),
@@ -50,77 +50,64 @@ module App = {
...state,
counter: Counter.counterReduce(state.counter, action),
}
- };
-};
+ }
+}
module Store = {
include ReductiveContext.Make({
- type action = App.appAction;
- type state = App.appState;
- });
+ type action = App.appAction
+ type state = App.appState
+ })
- let logger = (store, next) => Middleware.logger(store) @@ next;
+ let logger = (store, next) => \"@@"(Middleware.logger(store), next)
- let store =
- Reductive.Store.create(
- ~reducer=App.appReducer,
- ~preloadedState={counter: 0, content: ""},
- ~enhancer=logger,
- (),
- );
+ let store = Reductive.Store.create(
+ ~reducer=App.appReducer,
+ ~preloadedState={counter: 0, content: ""},
+ ~enhancer=logger,
+ (),
+ )
module Selectors = {
- open App;
- let state = state => state;
- let contentState = state => state.content;
- let counterState = state => state.counter;
- };
-};
+ open App
+ let state = state => state
+ let contentState = state => state.content
+ let counterState = state => state.counter
+ }
+}
module ContentComponent = {
- [@react.component]
+ @react.component
let make = () => {
- let dispatch = Store.useDispatch();
- let state = Store.useSelector(Store.Selectors.contentState);
+ let dispatch = Store.useDispatch()
+ let state = Store.useSelector(Store.Selectors.contentState)
-
{ReasonReact.string("Content: " ++ state)}
-
dispatch(StringAction(AppendA))}>
- {ReasonReact.string("+A")}
-
-
dispatch(StringAction(AppendB))}>
- {ReasonReact.string("+B")}
-
-
;
- };
-};
+ {React.string("Content: " ++ state)}
+ dispatch(StringAction(AppendA))}> {React.string("+A")}
+ dispatch(StringAction(AppendB))}> {React.string("+B")}
+
+ }
+}
module CounterComponent = {
- [@react.component]
+ @react.component
let make = () => {
- let dispatch = Store.useDispatch();
- let state = Store.useSelector(Store.Selectors.counterState);
+ let dispatch = Store.useDispatch()
+ let state = Store.useSelector(Store.Selectors.counterState)
{React.string("Counter: " ++ string_of_int(state))}
-
dispatch(CounterAction(Increment))}>
- {React.string("++")}
-
-
dispatch(CounterAction(Decrement))}>
- {React.string("--")}
-
-
;
- };
-};
+ dispatch(CounterAction(Increment))}> {React.string("++")}
+ dispatch(CounterAction(Decrement))}> {React.string("--")}
+
+ }
+}
module RenderApp = {
- [@react.component]
- let make = () => {
+ @react.component
+ let make = () =>
-
-
-
-
-
;
- };
-};
+
+
+}
-ReactDOMRe.renderToElementWithId( , "index");
+ReactDOM.querySelector("#index")->Belt.Option.forEach(ReactDOM.render( ))
diff --git a/examples/render/renderEntry.re b/examples/render/renderEntry.re
deleted file mode 100644
index 56447e7..0000000
--- a/examples/render/renderEntry.re
+++ /dev/null
@@ -1,115 +0,0 @@
-[@bs.config {jsx: 3}];
-/*
- * Example using multiple components to represent different slices of state.
- * Updating the state exposed by one component should not cause the other
- * components to also update (visually). Use the React Devtools "highlight
- * updates" feature to see this in action. If that proves difficult, then
- * try the Chrome devtools Rendering options, enabling "Paint flashing".
- */
-type counterAction =
- | Increment
- | Decrement;
-
-let counterReduce = (state, action) =>
- switch (action) {
- | Increment => state + 1
- | Decrement => state - 1
- };
-
-type stringAction =
- | AppendA
- | AppendB;
-
-let stringReduce = (state, action) =>
- switch (action) {
- | AppendA => state ++ "A"
- | AppendB => state ++ "B"
- };
-
-type ReduxThunk.thunk(_) +=
- | StringAction(stringAction)
- | CounterAction(counterAction);
-
-type appState = {
- counter: int,
- content: string,
-};
-
-let appReducer = (state, action) =>
- switch (action) {
- | StringAction(action) => {
- ...state,
- content: stringReduce(state.content, action),
- }
- | CounterAction(action) => {
- ...state,
- counter: counterReduce(state.counter, action),
- }
- | _ => state
- };
-
-let thunkedLogger = (store, next) =>
- Middleware.thunk(store) @@ Middleware.logger(store) @@ next;
-
-let appStore =
- Reductive.Store.create(
- ~reducer=appReducer,
- ~preloadedState={counter: 0, content: ""},
- ~enhancer=thunkedLogger,
- (),
- );
-
-module AppStore = {
- include ReductiveContext.Make({
- type state = appState;
- type action = ReduxThunk.thunk(appState);
- });
-};
-
-let contentSelector = state => state.content;
-module StringComponent = {
- [@react.component]
- let make = () => {
- let dispatch = AppStore.useDispatch();
- let state = AppStore.useSelector(contentSelector);
-
-
-
{ReasonReact.string("Content: " ++ state)}
-
dispatch(StringAction(AppendA))}>
- {ReasonReact.string("+A")}
-
-
dispatch(StringAction(AppendB))}>
- {ReasonReact.string("+B")}
-
-
;
- };
-};
-
-let counterSelector = state => state.counter;
-
-module CounterComponent = {
- [@react.component]
- let make = () => {
- let dispatch = AppStore.useDispatch();
- let state = AppStore.useSelector(counterSelector);
-
-
-
{ReasonReact.string("Counter: " ++ string_of_int(state))}
-
dispatch(CounterAction(Increment))}>
- {ReasonReact.string("++")}
-
-
dispatch(CounterAction(Decrement))}>
- {ReasonReact.string("--")}
-
-
;
- };
-};
-
-module RenderApp = {
- [@react.component]
- let make = () => {
-
;
- };
-};
-
-ReactDOMRe.renderToElementWithId( , "index");
diff --git a/examples/render/renderEntry.res b/examples/render/renderEntry.res
new file mode 100644
index 0000000..91b76c4
--- /dev/null
+++ b/examples/render/renderEntry.res
@@ -0,0 +1,108 @@
+/*
+ * Example using multiple components to represent different slices of state.
+ * Updating the state exposed by one component should not cause the other
+ * components to also update (visually). Use the React Devtools "highlight
+ * updates" feature to see this in action. If that proves difficult, then
+ * try the Chrome devtools Rendering options, enabling "Paint flashing".
+ */
+type counterAction =
+ | Increment
+ | Decrement
+
+let counterReduce = (state, action) =>
+ switch action {
+ | Increment => state + 1
+ | Decrement => state - 1
+ }
+
+type stringAction =
+ | AppendA
+ | AppendB
+
+let stringReduce = (state, action) =>
+ switch action {
+ | AppendA => state ++ "A"
+ | AppendB => state ++ "B"
+ }
+
+type ReduxThunk.thunk<_> +=
+ | StringAction(stringAction)
+ | CounterAction(counterAction)
+
+type appState = {
+ counter: int,
+ content: string,
+}
+
+let appReducer = (state, action) =>
+ switch action {
+ | StringAction(action) => {
+ ...state,
+ content: stringReduce(state.content, action),
+ }
+ | CounterAction(action) => {
+ ...state,
+ counter: counterReduce(state.counter, action),
+ }
+ | _ => state
+ }
+
+let thunkedLogger = (store, next) =>
+ \"@@"(Middleware.thunk(store), \"@@"(Middleware.logger(store), next))
+
+let appStore = Reductive.Store.create(
+ ~reducer=appReducer,
+ ~preloadedState={counter: 0, content: ""},
+ ~enhancer=thunkedLogger,
+ (),
+)
+
+module AppStore = {
+ include ReductiveContext.Make({
+ type state = appState
+ type action = ReduxThunk.thunk
+ })
+}
+
+let contentSelector = state => state.content
+module StringComponent = {
+ @react.component
+ let make = () => {
+ let dispatch = AppStore.useDispatch()
+ let state = AppStore.useSelector(contentSelector)
+
+
+
{React.string("Content: " ++ state)}
+
dispatch(StringAction(AppendA))}> {React.string("+A")}
+
dispatch(StringAction(AppendB))}> {React.string("+B")}
+
+ }
+}
+
+let counterSelector = state => state.counter
+
+module CounterComponent = {
+ @react.component
+ let make = () => {
+ let dispatch = AppStore.useDispatch()
+ let state = AppStore.useSelector(counterSelector)
+
+
+
{React.string("Counter: " ++ string_of_int(state))}
+
dispatch(CounterAction(Increment))}> {React.string("++")}
+
dispatch(CounterAction(Decrement))}> {React.string("--")}
+
+ }
+}
+
+module RenderApp = {
+ @react.component
+ let make = () =>
+
+}
+
+ReactDOM.querySelector("#index")->Belt.Option.forEach(ReactDOM.render( ))
diff --git a/examples/todomvc/todomvcEntry.re b/examples/todomvc/todomvcEntry.re
deleted file mode 100644
index 9fa4b37..0000000
--- a/examples/todomvc/todomvcEntry.re
+++ /dev/null
@@ -1,338 +0,0 @@
-[@bs.config {jsx: 3}];
-/**
- * Example of a todo list, loosely based on the redux example, mixed with
- * some code from Jared Forsyth's ReasonReact tutorial, and Cheng Lou's
- * todomvc ReasonReact example.
- *
- * Borrowed CSS from https://github.com/tastejs/todomvc-app-css
- */
-type visibility =
- | ALL
- | ACTIVE
- | COMPLETED;
-
-type appAction =
- | AddItem(string)
- | Show(visibility)
- | UpdateItem(int, string)
- | ToggleItem(int)
- | ToggleAll(bool)
- | ClearItem(int)
- | ClearCompleted;
-
-type todo = {
- id: int,
- text: string,
- completed: bool,
-};
-
-type appState = {
- todos: list(todo),
- filter: visibility,
-};
-
-let lastId = ref(0);
-let newItem = text => {
- lastId := lastId^ + 1;
- {id: lastId^, text, completed: false};
-};
-
-let appReducer = (state, action) =>
- switch (action) {
- | AddItem(text) => {...state, todos: [newItem(text), ...state.todos]}
- | Show(vis) => {...state, filter: vis}
- | UpdateItem(id, text) => {
- ...state,
- todos:
- List.map(
- todo => todo.id == id ? {...todo, text} : todo,
- state.todos,
- ),
- }
- | ToggleItem(id) => {
- ...state,
- todos:
- List.map(
- todo =>
- todo.id == id ? {...todo, completed: !todo.completed} : todo,
- state.todos,
- ),
- }
- | ToggleAll(checked) => {
- ...state,
- todos: List.map(todo => {...todo, completed: checked}, state.todos),
- }
- | ClearItem(id) => {
- ...state,
- todos: List.filter(todo => todo.id != id, state.todos),
- }
- | ClearCompleted => {
- ...state,
- todos: List.filter(todo => !todo.completed, state.todos),
- }
- };
-
-let logger = (store, next) => Middleware.logger(store) @@ next;
-
-let appStore =
- Reductive.Store.create(
- ~reducer=appReducer,
- ~preloadedState={todos: [], filter: ALL},
- ~enhancer=logger,
- (),
- );
-
-module AppStore = {
- include ReductiveContext.Make({
- type action = appAction;
- type state = appState;
- });
-};
-
-let valueFromEvent = (evt): string => ReactEvent.Form.target(evt)##value;
-
-module TodoItem = {
- type state = {
- editText: string,
- editing: bool,
- };
- type action =
- | Edit
- | FinishEdit(string)
- | CancelEdit
- | Change(string);
-
- let getInitialState = todo => {editText: todo.text, editing: false};
-
- [@react.component]
- let make = (~todo, ~dispatch) => {
- let editFieldRef = React.useRef(Js.Nullable.null);
-
- let reducer = (state, action) => {
- switch (action) {
- | Edit => {editing: true, editText: todo.text}
- | FinishEdit(editText) => {editing: false, editText}
- | Change(text) => state.editing ? {...state, editText: text} : state
- | CancelEdit => {editing: false, editText: todo.text}
- };
- };
- let (state, todoItemDispatch) =
- React.useReducer(reducer, getInitialState(todo));
-
- React.useEffect1(
- () => {
- Js.log("Inside effect ");
- let optionRef = editFieldRef->React.Ref.current->Js.Nullable.toOption;
- switch (state.editing, optionRef) {
- | (true, Some(field)) =>
- let node = ReactDOMRe.domElementToObj(field);
- Js.log(node);
-
- ignore(node##focus());
- ignore(
- node##setSelectionRange(node##value##length, node##value##length),
- );
- | _ => ()
- };
-
- None;
- },
- [|state.editing|],
- );
-
- let submit = () => {
- switch (String.trim(state.editText)) {
- | "" => dispatch(ClearItem(todo.id))
- | nonEmptyValue =>
- todoItemDispatch(FinishEdit(nonEmptyValue));
- dispatch(UpdateItem(todo.id, nonEmptyValue));
- };
- };
-
- let handleKeyDown = key => {
- switch (key) {
- | 27 => todoItemDispatch(CancelEdit)
- | 13 => submit()
- | _ => ()
- };
- };
-
- let className =
- [todo.completed ? "completed" : "", state.editing ? "editing" : ""]
- |> String.concat(" ");
-
-
-
- dispatch(ToggleItem(todo.id))}
- />
- todoItemDispatch(Edit)}>
- {ReasonReact.string(todo.text)}
-
- dispatch(ClearItem(todo.id))}
- />
-
- submit()}
- onChange={event => {
- let value = valueFromEvent(event);
- todoItemDispatch(Change(value));
- }}
- onKeyDown={event => handleKeyDown(ReactEvent.Keyboard.which(event))}
- />
- ;
- };
-};
-
-module TodoList = {
- [@react.component]
- let make = (~todos, ~dispatch) => {
- let todoItems =
- List.map(
- todo => ,
- todos,
- );
- let todoCount = List.length(todos);
- let completedCount =
- List.length(List.filter(todo => todo.completed, todos));
- let activeTodoCount = todoCount - completedCount;
-
- ;
- };
-};
-
-module TodoInput = {
- [@react.component]
- let make = (~onSubmit) => {
- let (value, setValue) = React.useState(() => "");
- let handleChange = event => {
- let value = valueFromEvent(event);
- setValue(_ => value);
- };
- let handleKeyDown = event =>
- if (ReactEvent.Keyboard.key(event) == "Enter") {
- onSubmit(value);
- setValue(_ => "");
- };
-
- ;
- };
-};
-
-module AddTodo = {
- [@react.component]
- let make = (~dispatch) => {
- dispatch(AddItem(text))} />;
- };
-};
-
-module VisibleTodoList = {
- [@react.component]
- let make = (~state: appState, ~dispatch) => {
- let todos =
- switch (state.filter) {
- | ALL => state.todos
- | ACTIVE => List.filter(t => !t.completed, state.todos)
- | COMPLETED => List.filter(t => t.completed, state.todos)
- };
- ;
- };
-};
-
-module FilterLink = {
- [@react.component]
- let make = (~filter, ~label, ~state: appState, ~dispatch) => {
- let className = filter == state.filter ? "selected" : "";
-
- dispatch(Show(filter))}>
- {ReasonReact.string(label)}
-
- ;
- };
-};
-
-module Footer = {
- [@react.component]
- let make = (~state: appState, ~dispatch) => {
- let completedCount =
- List.length(List.filter(todo => todo.completed, state.todos));
- let activeTodoCount = List.length(state.todos) - completedCount;
- let activeTodoWord = activeTodoCount === 1 ? "item" : "items";
- let clearButton =
- completedCount > 0
- ? dispatch(ClearCompleted)}>
- {ReasonReact.string("Clear completed")}
-
- : ReasonReact.null;
-
-
-
- {ReasonReact.string(string_of_int(activeTodoCount))}
-
- {ReasonReact.string(" " ++ activeTodoWord ++ " left")}
-
-
- clearButton
- ;
- };
-};
-
-let stateSelector = state => state;
-
-module App = {
- [@react.component]
- let make = () => {
- let dispatch = AppStore.useDispatch();
- let state = AppStore.useSelector(stateSelector);
-
-
-
- {ReasonReact.string("todos")}
-
-
-
-
-
;
- };
-};
-
-ReactDOMRe.renderToElementWithId(
- ,
- "TodoApp",
-);
diff --git a/examples/todomvc/todomvcEntry.res b/examples/todomvc/todomvcEntry.res
new file mode 100644
index 0000000..85b33ca
--- /dev/null
+++ b/examples/todomvc/todomvcEntry.res
@@ -0,0 +1,290 @@
+@ocaml.doc("
+ * Example of a todo list, loosely based on the redux example, mixed with
+ * some code from Jared Forsyth's ReasonReact tutorial, and Cheng Lou's
+ * todomvc ReasonReact example.
+ *
+ * Borrowed CSS from https://github.com/tastejs/todomvc-app-css
+ ")
+type visibility =
+ | ALL
+ | ACTIVE
+ | COMPLETED
+
+type appAction =
+ | AddItem(string)
+ | Show(visibility)
+ | UpdateItem(int, string)
+ | ToggleItem(int)
+ | ToggleAll(bool)
+ | ClearItem(int)
+ | ClearCompleted
+
+type todo = {
+ id: int,
+ text: string,
+ completed: bool,
+}
+
+type appState = {
+ todos: list,
+ filter: visibility,
+}
+
+let lastId = ref(0)
+let newItem = text => {
+ lastId := lastId.contents + 1
+ {id: lastId.contents, text: text, completed: false}
+}
+
+let appReducer = (state, action) =>
+ switch action {
+ | AddItem(text) => {...state, todos: list{newItem(text), ...state.todos}}
+ | Show(vis) => {...state, filter: vis}
+ | UpdateItem(id, text) => {
+ ...state,
+ todos: List.map(todo => todo.id == id ? {...todo, text: text} : todo, state.todos),
+ }
+ | ToggleItem(id) => {
+ ...state,
+ todos: List.map(
+ todo => todo.id == id ? {...todo, completed: !todo.completed} : todo,
+ state.todos,
+ ),
+ }
+ | ToggleAll(checked) => {
+ ...state,
+ todos: List.map(todo => {...todo, completed: checked}, state.todos),
+ }
+ | ClearItem(id) => {
+ ...state,
+ todos: List.filter(todo => todo.id != id, state.todos),
+ }
+ | ClearCompleted => {
+ ...state,
+ todos: List.filter(todo => !todo.completed, state.todos),
+ }
+ }
+
+let logger = (store, next) => \"@@"(Middleware.logger(store), next)
+
+let appStore = Reductive.Store.create(
+ ~reducer=appReducer,
+ ~preloadedState={todos: list{}, filter: ALL},
+ ~enhancer=logger,
+ (),
+)
+
+module AppStore = {
+ include ReductiveContext.Make({
+ type action = appAction
+ type state = appState
+ })
+}
+
+let valueFromEvent = (evt): string => ReactEvent.Form.target(evt)["value"]
+
+module TodoItem = {
+ type state = {
+ editText: string,
+ editing: bool,
+ }
+ type action =
+ | Edit
+ | FinishEdit(string)
+ | CancelEdit
+ | Change(string)
+
+ let getInitialState = todo => {editText: todo.text, editing: false}
+
+ @react.component
+ let make = (~todo, ~dispatch) => {
+ let editFieldRef = React.useRef(Js.Nullable.null)
+
+ let reducer = (state, action) =>
+ switch action {
+ | Edit => {editing: true, editText: todo.text}
+ | FinishEdit(editText) => {editing: false, editText: editText}
+ | Change(text) => state.editing ? {...state, editText: text} : state
+ | CancelEdit => {editing: false, editText: todo.text}
+ }
+ let (state, todoItemDispatch) = React.useReducer(reducer, getInitialState(todo))
+
+ React.useEffect1(() => {
+ Js.log("Inside effect ")
+ let optionRef = editFieldRef.current->Js.Nullable.toOption
+ switch (state.editing, optionRef) {
+ | (true, Some(field)) =>
+ let node = ReactDOM.domElementToObj(field)
+ Js.log(node)
+
+ ignore(node["focus"]())
+ ignore(node["setSelectionRange"](node["value"]["length"], node["value"]["length"]))
+ | _ => ()
+ }
+
+ None
+ }, [state.editing])
+
+ let submit = () =>
+ switch String.trim(state.editText) {
+ | "" => dispatch(ClearItem(todo.id))
+ | nonEmptyValue =>
+ todoItemDispatch(FinishEdit(nonEmptyValue))
+ dispatch(UpdateItem(todo.id, nonEmptyValue))
+ }
+
+ let handleKeyDown = key =>
+ switch key {
+ | 27 => todoItemDispatch(CancelEdit)
+ | 13 => submit()
+ | _ => ()
+ }
+
+ let className =
+ list{todo.completed ? "completed" : "", state.editing ? "editing" : ""} |> String.concat(" ")
+
+
+
+ dispatch(ToggleItem(todo.id))}
+ />
+ todoItemDispatch(Edit)}> {React.string(todo.text)}
+ dispatch(ClearItem(todo.id))} />
+
+ submit()}
+ onChange={event => {
+ let value = valueFromEvent(event)
+ todoItemDispatch(Change(value))
+ }}
+ onKeyDown={event => handleKeyDown(ReactEvent.Keyboard.which(event))}
+ />
+
+ }
+}
+
+module TodoList = {
+ @react.component
+ let make = (~todos, ~dispatch) => {
+ let todoItems = List.map(todo => , todos)
+ let todoCount = List.length(todos)
+ let completedCount = List.length(List.filter(todo => todo.completed, todos))
+ let activeTodoCount = todoCount - completedCount
+
+
+ }
+}
+
+module TodoInput = {
+ @react.component
+ let make = (~onSubmit) => {
+ let (value, setValue) = React.useState(() => "")
+ let handleChange = event => {
+ let value = valueFromEvent(event)
+ setValue(_ => value)
+ }
+ let handleKeyDown = event =>
+ if ReactEvent.Keyboard.key(event) == "Enter" {
+ onSubmit(value)
+ setValue(_ => "")
+ }
+
+
+ }
+}
+
+module AddTodo = {
+ @react.component
+ let make = (~dispatch) => dispatch(AddItem(text))} />
+}
+
+module VisibleTodoList = {
+ @react.component
+ let make = (~state: appState, ~dispatch) => {
+ let todos = switch state.filter {
+ | ALL => state.todos
+ | ACTIVE => List.filter(t => !t.completed, state.todos)
+ | COMPLETED => List.filter(t => t.completed, state.todos)
+ }
+
+ }
+}
+
+module FilterLink = {
+ @react.component
+ let make = (~filter, ~label, ~state: appState, ~dispatch) => {
+ let className = filter == state.filter ? "selected" : ""
+ dispatch(Show(filter))}> {React.string(label)}
+ }
+}
+
+module Footer = {
+ @react.component
+ let make = (~state: appState, ~dispatch) => {
+ let completedCount = List.length(List.filter(todo => todo.completed, state.todos))
+ let activeTodoCount = List.length(state.todos) - completedCount
+ let activeTodoWord = activeTodoCount === 1 ? "item" : "items"
+ let clearButton =
+ completedCount > 0
+ ? dispatch(ClearCompleted)}>
+ {React.string("Clear completed")}
+
+ : React.null
+
+
+ {React.string(string_of_int(activeTodoCount))}
+ {React.string(" " ++ (activeTodoWord ++ " left"))}
+
+
+ clearButton
+
+ }
+}
+
+let stateSelector = state => state
+
+module App = {
+ @react.component
+ let make = () => {
+ let dispatch = AppStore.useDispatch()
+ let state = AppStore.useSelector(stateSelector)
+
+
+ }
+}
+
+ReactDOM.querySelector("#index")->Belt.Option.forEach(
+ ReactDOM.render( ),
+)
diff --git a/package.json b/package.json
index c2a8ac6..3d847b6 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,12 @@
{
"name": "reductive",
"version": "2.1.1",
- "description": "Redux in Reason",
+ "description": "Redux in ReScript",
"main": "index.js",
"scripts": {
- "build": "bsb -make-world",
- "start": "bsb -make-world -w",
- "clean": "bsb -clean-world",
+ "build": "rescript build",
+ "start": "rescript build -w",
+ "clean": "rescript clean",
"test": "npm run build && jest --silent",
"webpack": "webpack -w"
},
@@ -17,26 +17,23 @@
"homepage": "https://github.com/reasonml-community/reductive#readme",
"bugs": "https://github.com/reasonml-community/reductive/issues",
"keywords": [
- "reason",
- "reasonml",
- "ocaml",
+ "rescript",
"redux",
"state management"
],
"author": "rickyvetter",
"license": "MIT",
"peerDependencies": {
- "reason-react": "^0.7.0"
+ "@rescript/react": "^0.10"
},
"devDependencies": {
"@glennsl/bs-jest": "^0.4.8",
- "bs-platform": "^5.0.6",
- "bs-react-testing-library": "^0.5.0",
- "immutable-re": "https://github.com/facebookincubator/immutable-re.git",
+ "@rescript/react": "^0.10",
+ "@rescriptbr/react-testing-library": "^1.0.1",
+ "@testing-library/react-hooks": "^7.0.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
- "reason-hooks-testing-library": "^0.2.0",
- "reason-react": "^0.7.0",
+ "rescript": "^9.1.4",
"webpack": "^4.21.0",
"webpack-cli": "^3.1.2"
},
diff --git a/src/context.bs.js b/src/context.bs.js
deleted file mode 100644
index c8e6ef6..0000000
--- a/src/context.bs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE
-'use strict';
-
-var React = require("react");
-
-function Make(Config) {
- var context = React.createContext(Config[/* defaultValue */0]);
- var make = context.Provider;
- var Provider = /* module */[/* make */make];
- return /* module */[
- /* context */context,
- /* Provider */Provider
- ];
-}
-
-exports.Make = Make;
-/* react Not a pure module */
diff --git a/src/reductive.bs.js b/src/reductive.bs.js
deleted file mode 100644
index 9553bca..0000000
--- a/src/reductive.bs.js
+++ /dev/null
@@ -1,173 +0,0 @@
-// Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE
-'use strict';
-
-var List = require("bs-platform/lib/js/list.js");
-var Curry = require("bs-platform/lib/js/curry.js");
-var React = require("react");
-var Caml_option = require("bs-platform/lib/js/caml_option.js");
-var Context$Reductive = require("./context.bs.js");
-
-function create(reducer, preloadedState, enhancer, param) {
- if (enhancer !== undefined) {
- return /* record */[
- /* state */preloadedState,
- /* reducer */reducer,
- /* listeners : [] */0,
- /* customDispatcher */enhancer
- ];
- } else {
- return /* record */[
- /* state */preloadedState,
- /* reducer */reducer,
- /* listeners : [] */0,
- /* customDispatcher */undefined
- ];
- }
-}
-
-function unsubscribe(store, listener, param) {
- store[/* listeners */2] = List.filter((function (l) {
- return listener !== l;
- }))(store[/* listeners */2]);
- return /* () */0;
-}
-
-function subscribe(store, listener) {
- store[/* listeners */2] = /* :: */[
- listener,
- store[/* listeners */2]
- ];
- return (function (param) {
- return unsubscribe(store, listener, param);
- });
-}
-
-function nativeDispatch(store, action) {
- store[/* state */0] = Curry._2(store[/* reducer */1], store[/* state */0], action);
- return List.iter((function (listener) {
- return Curry._1(listener, /* () */0);
- }), store[/* listeners */2]);
-}
-
-function dispatch(store, action) {
- var match = store[/* customDispatcher */3];
- if (match !== undefined) {
- return Curry._3(match, store, (function (param) {
- return nativeDispatch(store, param);
- }), action);
- } else {
- return nativeDispatch(store, action);
- }
-}
-
-function getState(store) {
- return store[/* state */0];
-}
-
-function replaceReducer(store, reducer) {
- store[/* reducer */1] = reducer;
- return /* () */0;
-}
-
-var Store = /* module */[
- /* create */create,
- /* unsubscribe */unsubscribe,
- /* subscribe */subscribe,
- /* nativeDispatch */nativeDispatch,
- /* dispatch */dispatch,
- /* getState */getState,
- /* replaceReducer */replaceReducer
-];
-
-function compose(param) {
- return /* () */0;
-}
-
-function combineReducers(param) {
- return /* () */0;
-}
-
-function applyMiddleware(param) {
- return /* () */0;
-}
-
-function bindActionCreators(actions, dispatch) {
- return List.map((function (action, param) {
- return Curry._1(dispatch, action);
- }), actions);
-}
-
-function Make(funarg) {
- var defaultValue = funarg[/* store */0];
- var include = Context$Reductive.Make(/* module */[/* defaultValue */defaultValue]);
- var context = include[0];
- var Provider = include[1];
- var Reductive$Make$Provider = function (Props) {
- var children = Props.children;
- return React.createElement(Provider[/* make */0], {
- value: funarg[/* store */0],
- children: children
- });
- };
- var Provider$1 = /* module */[/* make */Reductive$Make$Provider];
- var useSelector = function (selector) {
- var storeFromContext = React.useContext(context);
- var match = React.useReducer((function (s, param) {
- return s + 1 | 0;
- }), 0);
- var forceRerender = match[1];
- var latestSelectedState = React.useRef(undefined);
- var latestSelector = React.useRef(selector);
- React.useLayoutEffect((function () {
- latestSelector.current = selector;
- var newSelectedState = Curry._1(selector, funarg[/* store */0][/* state */0]);
- latestSelectedState.current = Caml_option.some(newSelectedState);
- return undefined;
- }), /* array */[selector]);
- React.useLayoutEffect((function () {
- var checkForUpdates = function (param) {
- var newSelectedState = Curry._1(selector, funarg[/* store */0][/* state */0]);
- var match = latestSelectedState.current;
- var hasStateChanged = match !== undefined ? newSelectedState !== Caml_option.valFromOption(match) : true;
- if (hasStateChanged) {
- latestSelectedState.current = Caml_option.some(newSelectedState);
- return Curry._1(forceRerender, /* () */0);
- } else {
- return 0;
- }
- };
- return subscribe(storeFromContext, checkForUpdates);
- }), /* array */[storeFromContext]);
- var currentStoreState = funarg[/* store */0][/* state */0];
- if (latestSelector.current !== selector) {
- return Curry._1(selector, currentStoreState);
- } else {
- var match$1 = latestSelectedState.current;
- if (match$1 !== undefined) {
- return Caml_option.valFromOption(match$1);
- } else {
- return Curry._1(selector, currentStoreState);
- }
- }
- };
- var useDispatch = function (param) {
- var partial_arg = React.useContext(context);
- return (function (param) {
- return dispatch(partial_arg, param);
- });
- };
- return [
- [context],
- Provider$1,
- useSelector,
- useDispatch
- ];
-}
-
-exports.Store = Store;
-exports.Make = Make;
-exports.compose = compose;
-exports.combineReducers = combineReducers;
-exports.applyMiddleware = applyMiddleware;
-exports.bindActionCreators = bindActionCreators;
-/* react Not a pure module */
diff --git a/src/reductive.re b/src/reductive.re
deleted file mode 100644
index a6e33e8..0000000
--- a/src/reductive.re
+++ /dev/null
@@ -1,164 +0,0 @@
-module Store = {
- type t('action, 'state) = {
- mutable state: 'state,
- mutable reducer: ('state, 'action) => 'state,
- mutable listeners: list(unit => unit),
- customDispatcher:
- option((t('action, 'state), 'action => unit, 'action) => unit),
- };
- let create = (~reducer, ~preloadedState, ~enhancer=?, ()) =>
- switch (preloadedState, enhancer, reducer) {
- | (preloadedState, None, reducer) => {
- state: preloadedState,
- listeners: [],
- reducer,
- customDispatcher: None,
- }
- | (preloadedState, Some(enhancer), reducer) => {
- state: preloadedState,
- listeners: [],
- reducer,
- customDispatcher: Some(enhancer),
- }
- };
- let unsubscribe = (store, listener, ()) =>
- store.listeners = List.filter(l => listener !== l, store.listeners);
- let subscribe = (store, listener) => {
- store.listeners = [listener, ...store.listeners];
- unsubscribe(store, listener);
- };
- let nativeDispatch = (store, action) => {
- store.state = store.reducer(store.state, action);
- List.iter(listener => listener(), store.listeners);
- };
- let dispatch = (store, action) =>
- switch (store.customDispatcher) {
- | Some(customDispatcher) =>
- customDispatcher(store, nativeDispatch(store), action)
- | None => nativeDispatch(store, action)
- };
- let getState = store => store.state;
- let replaceReducer = (store, reducer) => store.reducer = reducer;
-};
-
-/* deprecated, use hooks API instead */
-module Lense = {
- type state('reductiveState) = {
- reductiveState: option('reductiveState),
- unsubscribe: option(unit => unit),
- };
- type action =
- | UpdateState
- | AddListener(action => unit);
- let createMake =
- (
- ~name="Lense",
- ~lense: 'state => 'lense,
- store: Store.t('action, 'state),
- ) => {
- let innerComponent = ReasonReact.reducerComponent(name);
- let make =
- (
- ~component:
- (
- ~state: 'lense,
- ~dispatch: 'action => unit,
- array(ReasonReact.reactElement)
- ) =>
- ReasonReact.component('a, 'b, 'c),
- _children: array(ReasonReact.reactElement),
- )
- : ReasonReact.component(
- state('lense),
- ReasonReact.noRetainedProps,
- action,
- ) => {
- ...innerComponent,
- initialState: () => {
- reductiveState: Some(lense(Store.getState(store))),
- unsubscribe: None,
- },
- reducer: (action, state) =>
- switch (action) {
- | AddListener(send) =>
- ReasonReact.Update({
- unsubscribe:
- Some(Store.subscribe(store, _ => send(UpdateState))),
- reductiveState: Some(lense(Store.getState(store))),
- })
- | UpdateState =>
- lense(Store.getState(store))
- |. Some
- |. Belt.Option.eq(state.reductiveState, (a,b) => a === b)
- ? ReasonReact.NoUpdate
- : ReasonReact.Update({
- ...state,
- reductiveState: Some(lense(Store.getState(store))),
- })
- },
- didMount: ({send}) => send(AddListener(send)),
- willUnmount: ({state}) =>
- switch (state.unsubscribe) {
- | Some(unsubscribe) => unsubscribe()
- | None => ()
- },
- render: ({state}) =>
- switch (state.reductiveState) {
- | None => ReasonReact.null
- | Some(state) =>
- ReasonReact.element(
- component(~state, ~dispatch=Store.dispatch(store), [||]),
- )
- },
- };
- make;
- };
-};
-
-/* deprecated, use provider from reductiveContext.re */
-module Provider = {
- type state('reductiveState) = Lense.state('reductiveState);
- type action = Lense.action;
- let createMake = (~name="Provider", store: Store.t('action, 'state)) =>
- Lense.createMake(~name, ~lense=s => s, store);
-};
-
-/*** These are all visible apis of Redux that aren't needed in Reason.
- * When used, build tools will provide explanation of alternatives.
- * (see .rei for those)
- */
-let compose = _ => ();
-
-let combineReducers = _ => ();
-
-let applyMiddleware = _ => ();
-
-let bindActionCreators = (actions, dispatch) =>
- List.map((action, ()) => dispatch(action), actions);
-
-type store('action, 'state) = Store.t('action, 'state);
-type reducer('action, 'state) = ('state, 'action) => 'state;
-
-type middleware('action, 'state) =
- (store('action, 'state), 'action => unit, 'action) => unit;
-
-type storeCreator('action, 'state) =
- (
- ~reducer: reducer('action, 'state),
- ~preloadedState: 'state,
- ~enhancer: middleware('action, 'state)=?,
- unit
- ) =>
- store('action, 'state);
-
-type storeEnhancer('action, 'state) =
- storeCreator('action, 'state) => storeCreator('action, 'state);
-
-type liftedStoreEnhancer('action, 'state, 'enhancedAction, 'enhancedState) =
- (
- ~reducer: reducer('action, 'state),
- ~preloadedState: 'enhancedState,
- ~enhancer: middleware('enhancedAction, 'enhancedState)=?,
- unit
- ) =>
- store('enhancedAction, 'enhancedState);
\ No newline at end of file
diff --git a/src/reductive.rei b/src/reductive.rei
deleted file mode 100644
index a331c35..0000000
--- a/src/reductive.rei
+++ /dev/null
@@ -1,163 +0,0 @@
-module Store: {
- type t('action, 'state);
- let create:
- (
- ~reducer: ('state, 'action) => 'state,
- ~preloadedState: 'state,
- ~enhancer: (t('action, 'state), 'action => unit, 'action) => unit=?,
- unit
- ) =>
- t('action, 'state);
- let unsubscribe: (t('action, 'state), unit => unit, unit) => unit;
- let subscribe: (t('action, 'state), unit => unit, unit) => unit;
- /* skips all middleware and applies an update directly to the store */
- let nativeDispatch: (t('action, 'state), 'action) => unit;
- let dispatch: (t('action, 'state), 'action) => unit;
- let getState: t('action, 'state) => 'state;
- let replaceReducer:
- (t('action, 'state), ('state, 'action) => 'state) => unit;
-};
-
-module Lense: {
- type state('reductiveState);
- type action =
- | UpdateState
- | AddListener(action => unit);
-
- [@deprecated "Legacy API, prefer the new hooks API with jsx 3"]
- let createMake:
- (
- ~name: string=?,
- ~lense: 'state => 'lense,
- Store.t('action, 'state),
- ~component: (
- ~state: 'lense,
- ~dispatch: 'action => unit,
- array(ReasonReact.reactElement)
- ) =>
- ReasonReact.component('a, 'b, 'c),
- array(ReasonReact.reactElement)
- ) =>
- ReasonReact.component(state('lense), ReasonReact.noRetainedProps, action);
-};
-
-module Provider: {
- type state('reductiveState) = Lense.state('reductiveState);
- type action = Lense.action;
-
- [@deprecated "Legacy API, prefer the new hooks API with jsx 3"]
- let createMake:
- (
- ~name: string=?,
- Store.t('action, 'state),
- ~component: (
- ~state: 'state,
- ~dispatch: 'action => unit,
- array(ReasonReact.reactElement)
- ) =>
- ReasonReact.component('a, 'b, 'c),
- array(ReasonReact.reactElement)
- ) =>
- ReasonReact.component(state('state), ReasonReact.noRetainedProps, action);
-};
-
-/*** These are all visible apis of Redux that aren't needed in Reason.
- * When used, build tools will provide explanation of alternatives.
- */
-[@ocaml.deprecated
- {|
-Use the |> as an infix operator to chain the
-result of one function into another:
-
-`compose(f, g, h)(x)`
-in JS goes to
-`x |> h |> g |> f`
-in Reason.
-|}
-]
-let compose: _ => unit;
-
-[@ocaml.deprecated
- {|
-combineReducers uses some introspection to determine
-the shape of your state. Instead, consider a declarative pattern like:
-
-type counterAction =
-| Increment
-| Decrement;
-type stringAction =
-| A
-| B;
-type action =
-| StringAction stringAction
-| CounterAction counterAction;
-type state = {string, counter};
-
-let combinedReducer state action => {
-| StringAction action => {...state, string: stringReducer state action}
-| CounterAction action => {...state, counter: counterReducer state action}
-};
-
-this pattern gives you full control over the shape of your state.
-|}
-]
-let combineReducers: _ => unit;
-
-[@ocaml.deprecated
- {|
-The enhancer attribute in Redux allows you
-to provide a custom dispatch method (to perform more
-actions before or after the dispatch function). You can simply pass in
-a function directly which handles the exact actions you're looking for.
-
-To chain middlewares you can do something like:
-
-let thunkedLoggedTimeTravelLogger store next =>
- Middleware.thunk store @@
- Middleware.logger store @@
- Middleware.timeTravel store @@
- next;
-|}
-]
-let applyMiddleware: _ => unit;
-
-[@ocaml.deprecated
- {|
-bindActionCreators is not as useful in Reason,
-since action creators are types, not functions.
-The code is implemented as:
-
-let bindActionCreators actions dispatch =>
-List.map (fun action () => dispatch action) actions;
-
-Instead - you are free to build the action data type at dispatch time.
-|}
-]
-let bindActionCreators: (list('a), 'a => 'b) => list(unit => 'b);
-
-type store('action, 'state) = Store.t('action, 'state);
-type reducer('action, 'state) = ('state, 'action) => 'state;
-
-type middleware('action, 'state) =
- (store('action, 'state), 'action => unit, 'action) => unit;
-
-type storeCreator('action, 'state) =
- (
- ~reducer: reducer('action, 'state),
- ~preloadedState: 'state,
- ~enhancer: middleware('action, 'state)=?,
- unit
- ) =>
- store('action, 'state);
-
-type storeEnhancer('action, 'state) =
- storeCreator('action, 'state) => storeCreator('action, 'state);
-
-type liftedStoreEnhancer('action, 'state, 'enhancedAction, 'enhancedState) =
- (
- ~reducer: reducer('action, 'state),
- ~preloadedState: 'enhancedState,
- ~enhancer: middleware('enhancedAction, 'enhancedState)=?,
- unit
- ) =>
- store('enhancedAction, 'enhancedState);
\ No newline at end of file
diff --git a/src/reductive.res b/src/reductive.res
new file mode 100644
index 0000000..7a24050
--- /dev/null
+++ b/src/reductive.res
@@ -0,0 +1,73 @@
+module Store = {
+ type rec t<'action, 'state> = {
+ mutable state: 'state,
+ mutable reducer: ('state, 'action) => 'state,
+ mutable listeners: list unit>,
+ customDispatcher: option<(t<'action, 'state>, 'action => unit, 'action) => unit>,
+ }
+ let create = (~reducer, ~preloadedState, ~enhancer=?, ()) =>
+ switch (preloadedState, enhancer, reducer) {
+ | (preloadedState, None, reducer) => {
+ state: preloadedState,
+ listeners: list{},
+ reducer: reducer,
+ customDispatcher: None,
+ }
+ | (preloadedState, Some(enhancer), reducer) => {
+ state: preloadedState,
+ listeners: list{},
+ reducer: reducer,
+ customDispatcher: Some(enhancer),
+ }
+ }
+ let unsubscribe = (store, listener, ()) =>
+ store.listeners = List.filter(l => listener !== l, store.listeners)
+ let subscribe = (store, listener) => {
+ store.listeners = list{listener, ...store.listeners}
+ unsubscribe(store, listener)
+ }
+ let nativeDispatch = (store, action) => {
+ store.state = store.reducer(store.state, action)
+ List.iter(listener => listener(), store.listeners)
+ }
+ let dispatch = (store, action) =>
+ switch store.customDispatcher {
+ | Some(customDispatcher) => customDispatcher(store, nativeDispatch(store), action)
+ | None => nativeDispatch(store, action)
+ }
+ let getState = store => store.state
+ let replaceReducer = (store, reducer) => store.reducer = reducer
+}
+
+/* ** These are all visible apis of Redux that aren't needed in Reason.
+ * When used, build tools will provide explanation of alternatives.
+ * (see .rei for those)
+ */
+let compose = _ => ()
+
+let combineReducers = _ => ()
+
+let applyMiddleware = _ => ()
+
+let bindActionCreators = (actions, dispatch) => List.map((action, ()) => dispatch(action), actions)
+
+type store<'action, 'state> = Store.t<'action, 'state>
+type reducer<'action, 'state> = ('state, 'action) => 'state
+
+type middleware<'action, 'state> = (store<'action, 'state>, 'action => unit, 'action) => unit
+
+type storeCreator<'action, 'state> = (
+ ~reducer: reducer<'action, 'state>,
+ ~preloadedState: 'state,
+ ~enhancer: middleware<'action, 'state>=?,
+ unit,
+) => store<'action, 'state>
+
+type storeEnhancer<'action, 'state> = storeCreator<'action, 'state> => storeCreator<'action, 'state>
+
+type liftedStoreEnhancer<'action, 'state, 'enhancedAction, 'enhancedState> = (
+ ~reducer: reducer<'action, 'state>,
+ ~preloadedState: 'enhancedState,
+ ~enhancer: middleware<'enhancedAction, 'enhancedState>=?,
+ unit,
+) => store<'enhancedAction, 'enhancedState>
diff --git a/src/reductive.resi b/src/reductive.resi
new file mode 100644
index 0000000..354ec5f
--- /dev/null
+++ b/src/reductive.resi
@@ -0,0 +1,103 @@
+module Store: {
+ type t<'action, 'state>
+ let create: (
+ ~reducer: ('state, 'action) => 'state,
+ ~preloadedState: 'state,
+ ~enhancer: (t<'action, 'state>, 'action => unit, 'action) => unit=?,
+ unit,
+ ) => t<'action, 'state>
+ let unsubscribe: (t<'action, 'state>, unit => unit, unit) => unit
+ let subscribe: (t<'action, 'state>, unit => unit, unit) => unit
+ /* skips all middleware and applies an update directly to the store */
+ let nativeDispatch: (t<'action, 'state>, 'action) => unit
+ let dispatch: (t<'action, 'state>, 'action) => unit
+ let getState: t<'action, 'state> => 'state
+ let replaceReducer: (t<'action, 'state>, ('state, 'action) => 'state) => unit
+}
+
+/* ** These are all visible apis of Redux that aren't needed in Reason.
+ * When used, build tools will provide explanation of alternatives.
+ */
+@ocaml.deprecated(`
+Use the |> as an infix operator to chain the
+result of one function into another:
+
+\`compose(f, g, h)(x)\`
+in JS goes to
+\`x |> h |> g |> f\`
+in Reason.
+`)
+let compose: _ => unit
+
+@ocaml.deprecated(`
+combineReducers uses some introspection to determine
+the shape of your state. Instead, consider a declarative pattern like:
+
+type counterAction =
+| Increment
+| Decrement;
+type stringAction =
+| A
+| B;
+type action =
+| StringAction stringAction
+| CounterAction counterAction;
+type state = {string, counter};
+
+let combinedReducer state action => {
+| StringAction action => {...state, string: stringReducer state action}
+| CounterAction action => {...state, counter: counterReducer state action}
+};
+
+this pattern gives you full control over the shape of your state.
+`)
+let combineReducers: _ => unit
+
+@ocaml.deprecated(`
+The enhancer attribute in Redux allows you
+to provide a custom dispatch method (to perform more
+actions before or after the dispatch function). You can simply pass in
+a function directly which handles the exact actions you're looking for.
+
+To chain middlewares you can do something like:
+
+let thunkedLoggedTimeTravelLogger store next =>
+ Middleware.thunk store @@
+ Middleware.logger store @@
+ Middleware.timeTravel store @@
+ next;
+`)
+let applyMiddleware: _ => unit
+
+@ocaml.deprecated(`
+bindActionCreators is not as useful in Reason,
+since action creators are types, not functions.
+The code is implemented as:
+
+let bindActionCreators actions dispatch =>
+List.map (fun action () => dispatch action) actions;
+
+Instead - you are free to build the action data type at dispatch time.
+`)
+let bindActionCreators: (list<'a>, 'a => 'b) => list 'b>
+
+type store<'action, 'state> = Store.t<'action, 'state>
+type reducer<'action, 'state> = ('state, 'action) => 'state
+
+type middleware<'action, 'state> = (store<'action, 'state>, 'action => unit, 'action) => unit
+
+type storeCreator<'action, 'state> = (
+ ~reducer: reducer<'action, 'state>,
+ ~preloadedState: 'state,
+ ~enhancer: middleware<'action, 'state>=?,
+ unit,
+) => store<'action, 'state>
+
+type storeEnhancer<'action, 'state> = storeCreator<'action, 'state> => storeCreator<'action, 'state>
+
+type liftedStoreEnhancer<'action, 'state, 'enhancedAction, 'enhancedState> = (
+ ~reducer: reducer<'action, 'state>,
+ ~preloadedState: 'enhancedState,
+ ~enhancer: middleware<'enhancedAction, 'enhancedState>=?,
+ unit,
+) => store<'enhancedAction, 'enhancedState>
diff --git a/src/reductiveContext.re b/src/reductiveContext.re
deleted file mode 100644
index ff4199e..0000000
--- a/src/reductiveContext.re
+++ /dev/null
@@ -1,63 +0,0 @@
-module type Config = {
- type state;
- type action;
-};
-
-module Make = (Config: Config) => {
- open Subscription;
- let storeContext = React.createContext(None);
-
- module ContextProvider = {
- let make = React.Context.provider(storeContext);
- let makeProps =
- (
- ~value: option(Reductive.Store.t(Config.action, Config.state)),
- ~children,
- (),
- ) => {
- "value": value,
- "children": children,
- };
- };
-
- module Provider = {
- [@react.component]
- let make = (~children, ~store) => {
- children ;
- };
- };
-
- let useStore = () => {
- let storeFromContext = React.useContext(storeContext);
- switch (storeFromContext) {
- | None =>
- failwith(
- "Could not find reductive context value; please ensure the component is wrapped in a ",
- )
- | Some(store) => store
- };
- };
-
- let useSelector = selector => {
- let store = useStore();
-
- let source =
- React.useMemo2(
- () =>
- {
- subscribe: Reductive.Store.subscribe(store),
- getCurrentValue: () => selector(Reductive.Store.getState(store)),
- },
- (selector, store),
- );
-
- let selectedState = useSubscription(source);
-
- selectedState;
- };
-
- let useDispatch = () => {
- let store = useStore();
- React.useCallback1(Reductive.Store.dispatch(store), [|store|]);
- };
-};
diff --git a/src/reductiveContext.rei b/src/reductiveContext.rei
deleted file mode 100644
index 7c11f5c..0000000
--- a/src/reductiveContext.rei
+++ /dev/null
@@ -1,34 +0,0 @@
-module type Config = {
- type state;
- type action;
-};
-module Make:
- (Config: Config) =>
- {
- module Provider: {
- [@bs.obj]
- external makeProps:
- (
- ~children: 'children,
- ~store: Reductive.Store.t(Config.action, Config.state),
- ~key: string=?,
- unit
- ) =>
- {
- .
- "children": 'children,
- "store": Reductive.Store.t(Config.action, Config.state),
- } =
- "";
- let make:
- {
- .
- "children": React.element,
- "store": Reductive.Store.t(Config.action, Config.state),
- } =>
- React.element;
- };
- let useSelector: (Config.state => 'selectedState) => 'selectedState;
- let useDispatch: (unit, Config.action) => unit;
- let useStore: unit => Reductive.Store.t(Config.action, Config.state);
- };
diff --git a/src/reductiveContext.res b/src/reductiveContext.res
new file mode 100644
index 0000000..1399703
--- /dev/null
+++ b/src/reductiveContext.res
@@ -0,0 +1,57 @@
+module type Config = {
+ type state
+ type action
+}
+
+module Make = (Config: Config) => {
+ open Subscription
+ let storeContext = React.createContext(None)
+
+ module ContextProvider = {
+ let make = React.Context.provider(storeContext)
+ let makeProps = (
+ ~value: option>,
+ ~children,
+ (),
+ ) =>
+ {
+ "value": value,
+ "children": children,
+ }
+ }
+
+ module Provider = {
+ @react.component
+ let make = (~children, ~store) =>
+ children
+ }
+
+ let useStore = () => {
+ let storeFromContext = React.useContext(storeContext)
+ switch storeFromContext {
+ | None =>
+ failwith(
+ "Could not find reductive context value; please ensure the component is wrapped in a ",
+ )
+ | Some(store) => store
+ }
+ }
+
+ let useSelector = selector => {
+ let store = useStore()
+
+ let source = React.useMemo2(() => {
+ subscribe: Reductive.Store.subscribe(store),
+ getCurrentValue: () => selector(Reductive.Store.getState(store)),
+ }, (selector, store))
+
+ let selectedState = useSubscription(source)
+
+ selectedState
+ }
+
+ let useDispatch = () => {
+ let store = useStore()
+ React.useCallback1(Reductive.Store.dispatch(store), [store])
+ }
+}
diff --git a/src/reductiveContext.resi b/src/reductiveContext.resi
new file mode 100644
index 0000000..e3193a8
--- /dev/null
+++ b/src/reductiveContext.resi
@@ -0,0 +1,23 @@
+module type Config = {
+ type state
+ type action
+}
+module Make: (Config: Config) =>
+{
+ module Provider: {
+ @obj
+ external makeProps: (
+ ~children: 'children,
+ ~store: Reductive.Store.t,
+ ~key: string=?,
+ unit,
+ ) => {"children": 'children, "store": Reductive.Store.t} = ""
+ let make: {
+ "children": React.element,
+ "store": Reductive.Store.t,
+ } => React.element
+ }
+ let useSelector: (Config.state => 'selectedState) => 'selectedState
+ let useDispatch: (unit, Config.action) => unit
+ let useStore: unit => Reductive.Store.t
+}
diff --git a/src/subscription.re b/src/subscription.re
deleted file mode 100644
index cffab86..0000000
--- a/src/subscription.re
+++ /dev/null
@@ -1,13 +0,0 @@
-[@bs.deriving {jsConverter: newType}]
-type source('a) = {
- subscribe: (unit => unit, unit) => unit,
- getCurrentValue: unit => 'a,
-};
-
-[@bs.module "use-subscription"]
-external useSubscriptionJs: abs_source('a) => 'a = "useSubscription";
-
-let useSubscription = source => {
- let sourceJs = React.useMemo1(() => sourceToJs(source), [|source|]);
- useSubscriptionJs(sourceJs);
-};
diff --git a/src/subscription.res b/src/subscription.res
new file mode 100644
index 0000000..1a7a932
--- /dev/null
+++ b/src/subscription.res
@@ -0,0 +1,13 @@
+@deriving({jsConverter: newType})
+type source<'a> = {
+ subscribe: (unit => unit, unit) => unit,
+ getCurrentValue: unit => 'a,
+}
+
+@module("use-subscription")
+external useSubscriptionJs: abs_source<'a> => 'a = "useSubscription"
+
+let useSubscription = source => {
+ let sourceJs = React.useMemo1(() => sourceToJs(source), [source])
+ useSubscriptionJs(sourceJs)
+}
diff --git a/yarn.lock b/yarn.lock
index eec0af9..6e6c2f4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9,6 +9,13 @@
dependencies:
"@babel/highlight" "^7.0.0"
+"@babel/code-frame@^7.10.4":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
+ integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
+ dependencies:
+ "@babel/highlight" "^7.14.5"
+
"@babel/core@^7.1.0":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30"
@@ -68,6 +75,11 @@
dependencies:
"@babel/types" "^7.4.4"
+"@babel/helper-validator-identifier@^7.14.5":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz#32be33a756f29e278a0d644fa08a2c9e0f88a34c"
+ integrity sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==
+
"@babel/helpers@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.5.tgz#63908d2a73942229d1e6685bc2a0e730dde3b75e"
@@ -86,6 +98,15 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
+"@babel/highlight@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
+ integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.14.5"
+ chalk "^2.0.0"
+ js-tokens "^4.0.0"
+
"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b"
@@ -98,12 +119,20 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3":
- version "7.5.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
- integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
+"@babel/runtime-corejs3@^7.10.2":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.14.8.tgz#68539e0129f13eb1ed9a9aa273d3542b93c88384"
+ integrity sha512-4dMD5QRBkumn45oweR0SxoNtt15oz3BUBAQ8cIx7HJqZTtE8zjpM0My8aHJHVnyf4XfRg6DNzaE1080WLBiC1w==
dependencies:
- regenerator-runtime "^0.13.2"
+ core-js-pure "^3.15.0"
+ regenerator-runtime "^0.13.4"
+
+"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446"
+ integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==
+ dependencies:
+ regenerator-runtime "^0.13.4"
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
version "7.4.4"
@@ -301,19 +330,67 @@
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
-"@sheerun/mutationobserver-shim@^0.3.2":
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b"
- integrity sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==
-
-"@testing-library/react-hooks@^1.1.0":
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-1.1.0.tgz#14b6b5c7c3d0e2cb3e55e9cbb248b44321641c64"
- integrity sha512-piE/ceQoNf134FFVXBABDbttBJ8eLPD4eg7zIciVJv92RyvoIsBHCvvG8Vd4IG5pyuWYrkLsZTO8ucZBwa4twA==
+"@jest/types@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
+ integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
dependencies:
- "@babel/runtime" "^7.4.2"
- "@types/react" "^16.8.22"
- "@types/react-test-renderer" "^16.8.2"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^15.0.0"
+ chalk "^4.0.0"
+
+"@rescript/react@^0.10":
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/@rescript/react/-/react-0.10.3.tgz#a2a8bed6b017940ec26c2154764b350f50348889"
+ integrity sha512-Lf9rzrR3bQPKJjOK3PBRa/B3xrJ7CqQ1HYr9VHPVxJidarIJJFZBhj0Dg1uZURX+Wg/xiP0PHFxXmdj2bK8Vxw==
+
+"@rescriptbr/react-testing-library@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@rescriptbr/react-testing-library/-/react-testing-library-1.0.1.tgz#23815a778dc4834fa73799f47851b52cb2fd7f92"
+ integrity sha512-9hajpAGvdQZSGqnrVwNI3KhIiP5ewkWf1ff1/nLupOkH+Vg3eEG3grviPM/IjEh8h227hV8UDuDphdLDYuoajw==
+ dependencies:
+ "@testing-library/react" "^11.1.0"
+ bs-dom-testing-library "^0.7.0"
+
+"@testing-library/dom@^7.26.3", "@testing-library/dom@^7.28.1":
+ version "7.31.2"
+ resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a"
+ integrity sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.12.5"
+ "@types/aria-query" "^4.2.0"
+ aria-query "^4.2.2"
+ chalk "^4.1.0"
+ dom-accessibility-api "^0.5.6"
+ lz-string "^1.4.4"
+ pretty-format "^26.6.2"
+
+"@testing-library/react-hooks@^7.0.1":
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-7.0.1.tgz#8429d8bf55bfe82e486bd582dd06457c2464900a"
+ integrity sha512-bpEQ2SHSBSzBmfJ437NmnP+oArQ7aVmmULiAp6Ag2rtyLBLPNFSMmgltUbFGmQOJdPWo4Ub31kpUC5T46zXNwQ==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@types/react" ">=16.9.0"
+ "@types/react-dom" ">=16.9.0"
+ "@types/react-test-renderer" ">=16.9.0"
+ react-error-boundary "^3.1.0"
+
+"@testing-library/react@^11.1.0":
+ version "11.2.7"
+ resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.7.tgz#b29e2e95c6765c815786c0bc1d5aed9cb2bf7818"
+ integrity sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@testing-library/dom" "^7.28.1"
+
+"@types/aria-query@^4.2.0":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
+ integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
"@types/babel__core@^7.1.0":
version "7.1.2"
@@ -368,25 +445,50 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff"
+ integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/node@*":
+ version "16.4.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.7.tgz#f7afa78769d4b477f5092d7c3468e2e8653d779c"
+ integrity sha512-aDDY54sst8sx47CWT6QQqIZp45yURq4dic0+HCYfYNcY5Ejlb/CLmFnRLfy3wQuYafOeh3lB/DAKaqRKBtcZmA==
+
"@types/prop-types@*":
- version "15.7.1"
- resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6"
- integrity sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==
+ version "15.7.4"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
+ integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
-"@types/react-test-renderer@^16.8.2":
- version "16.9.0"
- resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.0.tgz#d60f530ecf4c906721511603cca711b4fa830d41"
- integrity sha512-bN5EyjtuTY35xX7N5j0KP1vg5MpUXHpFTX6tGsqkNOthjNvet4VQOYRxFh+NT5cDSJrATmAFK9NLeYZ4mp/o0Q==
+"@types/react-dom@>=16.9.0":
+ version "17.0.9"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add"
+ integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react-test-renderer@>=16.9.0":
+ version "17.0.1"
+ resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b"
+ integrity sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw==
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@^16.8.22":
- version "16.9.2"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.2.tgz#6d1765431a1ad1877979013906731aae373de268"
- integrity sha512-jYP2LWwlh+FTqGd9v7ynUKZzjj98T8x7Yclz479QdRhHfuW9yQ+0jjnD31eXSXutmBpppj5PYNLYLRfnZJvcfg==
+"@types/react@*", "@types/react@>=16.9.0":
+ version "17.0.15"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.15.tgz#c7533dc38025677e312606502df7656a6ea626d0"
+ integrity sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==
dependencies:
"@types/prop-types" "*"
- csstype "^2.2.0"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
+"@types/scheduler@*":
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
+ integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/stack-utils@^1.0.1":
version "1.0.1"
@@ -405,6 +507,13 @@
dependencies:
"@types/yargs-parser" "*"
+"@types/yargs@^15.0.0":
+ version "15.0.14"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06"
+ integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==
+ dependencies:
+ "@types/yargs-parser" "*"
+
"@webassemblyjs/ast@1.7.8":
version "1.7.8"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.8.tgz#f31f480debeef957f01b623f27eabc695fa4fe8f"
@@ -643,6 +752,11 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+ansi-regex@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+ integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -650,6 +764,13 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@@ -671,6 +792,14 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.6"
+aria-query@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
+ integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
+ dependencies:
+ "@babel/runtime" "^7.10.2"
+ "@babel/runtime-corejs3" "^7.10.2"
+
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -951,30 +1080,12 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-bs-dom-testing-library@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/bs-dom-testing-library/-/bs-dom-testing-library-0.4.1.tgz#46fd1fea65465edd799f1e7dd1596a633ef44b05"
- integrity sha512-UxpDl6Ain7ZvjieWFeeJZjmcaZOVe8KAKo9Olnji1kF5ne2w9x+b8AzSC0z20OKhpP3/SiiAuRnGNiO81NqI6A==
- dependencies:
- dom-testing-library "^3.19.0"
-
-bs-platform@^2.2.1:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-2.2.3.tgz#d905ae10a5f3621e6a739041dfa0b58483a2174f"
- integrity sha1-2QWuEKXzYh5qc5BB36C1hIOiF08=
-
-bs-platform@^5.0.6:
- version "5.0.6"
- resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-5.0.6.tgz#88c13041fb020479800de3d82c680bf971091425"
- integrity sha512-6Boa2VEcWJp2WJr38L7bp3J929nYha7gDarjxb070jWzgfPJ/WbzjipmSfnu2eqqk1MfjEIpBipbPz6n1NISwA==
-
-bs-react-testing-library@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/bs-react-testing-library/-/bs-react-testing-library-0.5.0.tgz#3906666ffc6dfd22ff25ae01bfa8f5ba65c30db0"
- integrity sha512-EmISyRVFXCipeaaymKKv34kf8Cnn40hg3oRU2E36VLvou6XznkvMtAaWqYIGupp1+cnWkFNXhQAMZJNwSd9JiA==
+bs-dom-testing-library@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/bs-dom-testing-library/-/bs-dom-testing-library-0.7.0.tgz#6656561d471e99be8caa452d757c074c377f10df"
+ integrity sha512-bYbegL2TZ55DGWwdoeB3KugrJUIhIyZvMQablQ09hx9QD1Pzm2Sd6Rn17K2uHdoWj7kBVoSy5muTQOydzNmfWA==
dependencies:
- bs-dom-testing-library "^0.4.1"
- react-testing-library "^5.2.0"
+ "@testing-library/dom" "^7.26.3"
bser@^2.0.0:
version "2.1.0"
@@ -1086,6 +1197,14 @@ chalk@^2.4.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
+chalk@^4.0.0, chalk@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
+ integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
chokidar@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176"
@@ -1183,11 +1302,23 @@ color-convert@^1.9.0:
dependencies:
color-name "1.1.3"
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -1271,6 +1402,11 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+core-js-pure@^3.15.0:
+ version "3.15.2"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.15.2.tgz#c8e0874822705f3385d3197af9348f7c9ae2e3ce"
+ integrity sha512-D42L7RYh1J2grW8ttxoY1+17Y4wXZeKe7uyplAI3FkNQyI5OgBIAjUfFiTPfL1rs0qLpxaabITNbjKl1Sp82tA==
+
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -1347,10 +1483,10 @@ cssstyle@^1.0.0:
dependencies:
cssom "0.3.x"
-csstype@^2.2.0:
- version "2.6.6"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41"
- integrity sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==
+csstype@^3.0.2:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
+ integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
cyclist@~0.2.2:
version "0.2.2"
@@ -1502,15 +1638,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
-dom-testing-library@^3.13.1, dom-testing-library@^3.19.0:
- version "3.19.4"
- resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-3.19.4.tgz#f5b737f59ee9749a4568fa353f1f59be97c888c3"
- integrity sha512-GJOx8CLpnkvM3takILOsld/itUUc9+7Qh6caN1Spj6+9jIgNPY36fsvoH7sEgYokC0lBRdttO7G7fIFYCXlmcA==
- dependencies:
- "@babel/runtime" "^7.4.3"
- "@sheerun/mutationobserver-shim" "^0.3.2"
- pretty-format "^24.7.0"
- wait-for-expect "^1.1.1"
+dom-accessibility-api@^0.5.6:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9"
+ integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==
domain-browser@^1.1.1:
version "1.2.0"
@@ -2072,6 +2203,11 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
has-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
@@ -2202,12 +2338,6 @@ ignore-walk@^3.0.1:
dependencies:
minimatch "^3.0.4"
-"immutable-re@https://github.com/facebookincubator/immutable-re.git":
- version "0.0.15"
- resolved "https://github.com/facebookincubator/immutable-re.git#d55f65f7fc638ac17cfdd8064a0401d4cde5aad2"
- dependencies:
- bs-platform "^2.2.1"
-
import-local@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
@@ -3093,6 +3223,11 @@ lru-cache@^4.1.1:
pseudomap "^1.0.2"
yallist "^2.1.2"
+lz-string@^1.4.4:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
+ integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
+
make-dir@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
@@ -3828,7 +3963,7 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
-pretty-format@^24.7.0, pretty-format@^24.9.0:
+pretty-format@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9"
integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==
@@ -3838,6 +3973,16 @@ pretty-format@^24.7.0, pretty-format@^24.9.0:
ansi-styles "^3.2.0"
react-is "^16.8.4"
+pretty-format@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
+ integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==
+ dependencies:
+ "@jest/types" "^26.6.2"
+ ansi-regex "^5.0.0"
+ ansi-styles "^4.0.0"
+ react-is "^17.0.1"
+
process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
@@ -3985,7 +4130,7 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-dom@>=16.8.1, react-dom@^16.8.6:
+react-dom@^16.8.6:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962"
integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==
@@ -3995,30 +4140,24 @@ react-dom@>=16.8.1, react-dom@^16.8.6:
prop-types "^15.6.2"
scheduler "^0.15.0"
-react-is@^16.8.4, react-is@^16.9.0:
+react-error-boundary@^3.1.0:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.3.tgz#276bfa05de8ac17b863587c9e0647522c25e2a0b"
+ integrity sha512-A+F9HHy9fvt9t8SNDlonq01prnU8AmkjvGKV4kk8seB9kU3xMEO8J/PQlLVmoOIDODl5U2kufSBs4vrWIqhsAA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
+react-is@^16.8.4:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb"
integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==
-react-test-renderer@^16.8.6:
- version "16.9.0"
- resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.9.0.tgz#7ed657a374af47af88f66f33a3ef99c9610c8ae9"
- integrity sha512-R62stB73qZyhrJo7wmCW9jgl/07ai+YzvouvCXIJLBkRlRqLx4j9RqcLEAfNfU3OxTGucqR2Whmn3/Aad6L3hQ==
- dependencies:
- object-assign "^4.1.1"
- prop-types "^15.6.2"
- react-is "^16.9.0"
- scheduler "^0.15.0"
-
-react-testing-library@^5.2.0:
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/react-testing-library/-/react-testing-library-5.9.0.tgz#e1c8a586d2f2cbd5f0035474ca90258eef1fece6"
- integrity sha512-T303PJZvrLKeeiPpjmMD1wxVpzEg9yI0qteH/cUvpFqNHOzPe3yN+Pu+jo9JlxuTMvVGPAmCAcgZ3sEtEDpJUQ==
- dependencies:
- "@babel/runtime" "^7.3.1"
- dom-testing-library "^3.13.1"
+react-is@^17.0.1:
+ version "17.0.2"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
+ integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-react@>=16.8.1, react@^16.8.6:
+react@^16.8.6:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa"
integrity sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==
@@ -4074,26 +4213,10 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
-reason-hooks-testing-library@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/reason-hooks-testing-library/-/reason-hooks-testing-library-0.2.0.tgz#6d6c2cd5e8725ab74ebe8c6f25f484afd34b65f6"
- integrity sha512-lWWszdGYdyNmiPthq2OJKUu1HVufxZDOBaamedDk274KD/Bl1HDSo+X3QIeLAoyJHduboUPuhitdYpiINHLL+g==
- dependencies:
- "@testing-library/react-hooks" "^1.1.0"
- react-test-renderer "^16.8.6"
-
-reason-react@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/reason-react/-/reason-react-0.7.0.tgz#46a975c321e81cd51310d7b1a02418ca7667b0d6"
- integrity sha512-czR/f0lY5iyLCki9gwftOFF5Zs40l7ZSFmpGK/Z6hx2jBVeFDmIiXB8bAQW/cO6IvtuEt97OmsYueiuOYG9XjQ==
- dependencies:
- react ">=16.8.1"
- react-dom ">=16.8.1"
-
-regenerator-runtime@^0.13.2:
- version "0.13.3"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
- integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
+regenerator-runtime@^0.13.4:
+ version "0.13.9"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
+ integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
@@ -4175,6 +4298,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+rescript@^9.1.4:
+ version "9.1.4"
+ resolved "https://registry.yarnpkg.com/rescript/-/rescript-9.1.4.tgz#1eb126f98d6c16942c0bf0df67c050198e580515"
+ integrity sha512-aXANK4IqecJzdnDpJUsU6pxMViCR5ogAxzuqS0mOr8TloMnzAjJFu63fjD6LCkWrKAhlMkFFzQvVQYaAaVkFXw==
+
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@@ -4661,6 +4789,13 @@ supports-color@^6.1.0:
dependencies:
has-flag "^3.0.0"
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@@ -4976,11 +5111,6 @@ w3c-hr-time@^1.0.1:
dependencies:
browser-process-hrtime "^0.1.2"
-wait-for-expect@^1.1.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.3.0.tgz#65241ce355425f907f5d127bdb5e72c412ff830c"
- integrity sha512-8fJU7jiA96HfGPt+P/UilelSAZfhMBJ52YhKzlmZQvKEZU2EcD1GQ0yqGB6liLdHjYtYAoGVigYwdxr5rktvzA==
-
walker@^1.0.7, walker@~1.0.5:
version "1.0.7"
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"