diff --git a/.travis.yml b/.travis.yml
index 4d946f15..2cd349e6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,7 @@ jobs:
include:
- stage: Check compilation
node_js: node
- script: npm build
+ script: npm run build
- stage: Produce Coverage
node_js: node
diff --git a/docs/README.md b/docs/README.md
index 97d0d6cb..eac36338 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,8 @@
---
id: redux-leaves
-title: Core API
+title: reduxLeaves
hide_title: true
-sidebar_label: reduxLeaves API
+sidebar_label: reduxLeaves
---
# `reduxLeaves(initialState, [reducersDict = {}])`
@@ -13,7 +13,7 @@ Returns a reducer function and an object.
## Parameters
- [`initialState`](#initialstate) *(object)*: the state shape and initial values for your Redux store
-- [`reducersDict`](#reducersdict) *(object, optional)*: a collection of [leaf reducers](leafReducers.md) keyed by their [creator keys](creatorKeys.md)
+- [`reducersDict`](#reducersdict) *(object, optional)*: a collection of [leaf reducers](api/leafReducers.md) keyed by their [creator keys](api/creatorKeys.md)
### `initialState`
*(object)*
@@ -38,8 +38,8 @@ const initialState = {
*(object)*
This is an object where every `key`-`value` pair is such that:
-- `value` *(function | object)* is a [leaf reducer](leafReducers.md);
-- `key` is a [creator key](creatorKeys.md) for that leaf reducer.
+- `value` *(function | object)* is a [leaf reducer](api/leafReducers.md);
+- `key` is a [creator key](api/creatorKeys.md) for that leaf reducer.
#### Example
@@ -56,90 +56,14 @@ const reducersDict = {
## Returns
`array`, with two elements:
- 0th: `reducer` *(function)*: a reducer function to pass to redux's `createStore`
-- 1st: `actions` *(object)*: an object with same shape as `initialState`
+- 1st: [`actions`](api/actions.md) *(object)*: an object with same shape as `initialState`
### `reducer`
The root reducer for your Redux store.
-It listens to actions created through [`actions`](#actions) at a given leaf for a given [creator key](creatorKeys.md), and updates that leaf's state using the [leaf reducer](leafReducers.md) keyed by the creator key.
+It listens to actions created through [`actions`](api/actions.md) at a given leaf for a given [creator key](api/creatorKeys.md), and updates that leaf's state using the [leaf reducer](api/leafReducers.md) keyed by the creator key.
### `actions`
-An object with nested action creator functions, following the same shape as the `initialState` passed to `reduxLeaves`.
-
-#### Example
-
-First, grab `reducer` and `actions` by destructuring the return value of `reduxLeaves`:
-
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- counter: 1,
- foo: ['bar']
- nested: {
- deep: {}
- state: {
- manageable: 'maybe...?'
- }
- }
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-
-`actions` is an object with the same shape as `initialState`, with corresponding branches and leaves.
-
-Every action branch and leaf is an object, regardless of the initial data type:
-
-```js
-console.log(typeof actions.counter) // 'object'
-console.log(typeof actions.nested.deep) // 'object'
-console.log(typeof actions.nested.state.manageable) // 'object'
-```
-
-Every action branch and leaf also has an additional property, `create`, that is an object:
-
-```js
-console.log(typeof actions.counter.create) // 'object'
-console.log(typeof actions.nested.deep.create) // 'object'
-console.log(typeof actions.nested.state.manageable.create) // 'object'
-```
-
-This `create` property is the API through which you can access action creators.
-
-For example, suppose I want to dispatch an action that will increment my `counter` state by 2.
-
-```js
-// We can destructure to access the 'increment' method from the create API
-const { increment } = actions.counter.create
-
-// Increment is an action creator function which takes one argument
-const action = increment(2)
-
-// Dispatch the action to the store
-store.dispatch(action)
-
-// The store's state changes as expected!
-console.log(store.getState())
-/*
-* {
-* counter: 3, <--------------- incremented by 2!
-* foo: ['bar'],
-* nested: {
-* deep: {},
-* manageable: 'maybe...?'
-* }
-* }
-*/
-```
-This API allows for concise but descriptive dispatching of actions.
-```js
-// Push 'FOO' to the 'foo' (array) slice of state
-// by creating and dispatching an action
-
-store.dispatch(actions.foo.create.push('FOO'))
-```
\ No newline at end of file
+See documentation on the [`actions`](api/actions.md) object.
\ No newline at end of file
diff --git a/docs/api/actions.md b/docs/api/actions.md
new file mode 100644
index 00000000..13c31e26
--- /dev/null
+++ b/docs/api/actions.md
@@ -0,0 +1,67 @@
+---
+id: actions
+title: actions
+hide_title: true
+sidebar_label: actions
+---
+
+# `actions`
+
+## Arbitrary property paths
+
+The `actions` object returned by `reduxLeaves` can take an arbitrary path of properties after it, which typically correspond to a 'leaf' at the corresponding path from your state.
+
+```js
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ counter: 0,
+ arbitrary: {
+ nested: {
+ path: ['hi!']
+ }
+ }
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+
+// state.counter
+console.log(typeof actions.counter) // 'object'
+
+// state.arbitrary.nested
+console.log(typeof actions.arbitrary.nested) // 'object'
+
+// state.arbitrary.nested.path
+console.log(typeof actions.arbitrary.nested.path) // 'object'
+
+// but also works for paths not in your initial state
+console.log(typeof actions.not.in.my.initial.state) // 'object'
+```
+
+## Accessing `create`
+
+For a given arbitrary property path, you have two options: navigating to a deeper property / leaf, or accessing the [`create`](create.md) property.
+
+```js
+// Access create at the state root
+console.log(typeof actions.create) // 'function'
+
+// Go deeper
+console.log(typeof actions.arbitrary) // 'object'
+
+// Access create at state.arbitrary
+console.log(typeof actions.arbitrary.create) // 'function'
+
+// Go deeper
+console.log(typeof actions.arbitrary.nested.path)
+
+// Access create at state.arbitary.nested.path
+console.log(typeof actions.arbitrary.nested.path.create) // 'function'
+```
+
+Once you've accessed `create`, you can't go arbitrarily deeper beyond that.
+```js
+console.log(typeof actions.create.arbitrary) // 'undefined'
+```
+
+This is because the `create` key accesses the Redux-Leaves [action creator (`create`) API](create.md) at the corresponding leaf of state.
\ No newline at end of file
diff --git a/docs/api/actions.spec.js b/docs/api/actions.spec.js
new file mode 100644
index 00000000..dbc12241
--- /dev/null
+++ b/docs/api/actions.spec.js
@@ -0,0 +1,33 @@
+import reduxLeaves from '../../src';
+
+describe('actions can take an arbitrary path of properties after it', () => {
+ const initialState = {
+ counter: 0,
+ arbitrary: {
+ nested: {
+ path: ['hi!']
+ }
+ }
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+
+ test('Any arbitrary path returns an object', () => {
+ expect(typeof actions.counter).toBe('object')
+ expect(typeof actions.arbitrary.nested).toBe('object')
+ expect(typeof actions.arbitrary.nested.path).toBe('object')
+ expect(typeof actions.not.in.my.initial.state).toBe('object')
+ })
+
+ test('Any arbitrary path has the create function property', () => {
+ expect(typeof actions.create).toBe('function')
+ expect(typeof actions.counter.create).toBe('function')
+ expect(typeof actions.arbitrary.nested.create).toBe('function')
+ expect(typeof actions.arbitrary.nested.path.create).toBe('function')
+ expect(typeof actions.not.in.my.initial.state.create).toBe('function')
+ })
+
+ test("You can't access arbitrary paths from create", () => {
+ expect(typeof actions.create.arbitrary).toBe('undefined')
+ })
+})
\ No newline at end of file
diff --git a/docs/api/create.md b/docs/api/create.md
new file mode 100644
index 00000000..30c83959
--- /dev/null
+++ b/docs/api/create.md
@@ -0,0 +1,100 @@
+---
+id: create
+title: create
+hide_title: true
+sidebar_label: create
+---
+
+# `create`
+
+When you access the `create` property from any arbitrary path from the [`actions`](actions.md) object, you access the Redux-Leaves action creators API.
+
+Consider the `actions` object returned below.
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ counter: 0,
+ arbitrary: {
+ nested: {
+ path: ['hi!']
+ }
+ }
+}
+
+const reducersDict = {
+ convertToFoobar: () => 'foobar'
+}
+
+const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+```
+
+* `actions.counter.create` corresponds to creating actions at `state.counter`;
+* `actions.arbitrary.nested.path.create` corresponds to creating actions at `state.arbitrary.nested.path`;
+* `actions.create` corresponds to creating actions at the `state`'s root.
+
+## `create[creatorKey]`
+### Action creators
+You can access action creators (functions) from the `create` API at any leaf by using their [`creatorKey`](creatorKeys.md) as a property, both for the default ones and any custom ones you've defined.
+
+```js
+// Example defaults: update, set, push
+console.log(typeof actions.counter.create.update) // 'function'
+console.log(typeof actions.arbitrary.nested.create.set) // 'function'
+console.log(typeof actions.arbitrary.nested.path.create.push) // 'function'
+
+// Custom creatorKey of 'convertToFoobar'
+console.log(typeof actions.create.convertToFoobar) // 'function'
+console.log(typeof actions.arbitrary.nested.path.create.convertToFoobar) // 'function'
+```
+
+### Actions
+Executing these functions then create the actions that you should dispatch to your Redux store.
+
+```js
+const store = createStore(reducer) // using reducer from reduxLeaves
+console.log(store.getState().counter) // 0
+
+const updateCounter = actions.counter.create.update
+
+store.dispatch(updateCounter(5))
+console.log(store.getState().counter) // 5
+
+store.dispatch(updateCounter(3))
+console.log(store.getState().counter) // 3
+```
+
+### Optional `actionType` argument
+Rather than directly accessing action creators from `create`, you can optionally provide an `actionType` string as an argument to `create` before accessing the action creator functions:
+
+```js
+// Defaults, e.g. update creatorKey
+console.log(typeof actions.counter.create.update) // 'function'
+console.log(typeof actions.counter.create('UPDATE_COUNTER').update) // 'function'
+
+// Custom creatorKey of 'convertToFoobar'
+console.log(typeof actions.create.convertToFoobar) // 'function'
+console.log(typeof actions.create('CONVERT_TO_FOOBAR').convertToFoobar) // 'function'
+```
+
+Providing an `actionType` string in this way does not change the way that the reducer will respond to actions; it merely overrides the created action's `type` property to be the string passed in (which might be desirable for a debugging perspective for Redux DevTools, for example):
+
+```js
+const createDefaultIncrement = actions.counter.create.increment
+const createNamedIncrement = actions.counter.create('NAMED_INCREMENT').increment
+
+console.log(store.getState().counter) // 3
+
+const defaultIncrement = createDefaultIncrement()
+console.log(defaultIncrement.type) // 'counter/INCREMENT'
+dispatch(defaultIncrement)
+console.log(store.getState().counter) // 4
+
+const namedIncrement = createNamedIncrement()
+console.log(namedIncrement.type) // 'NAMED_INCREMENT'
+dispatch(namedIncrement)
+console.log(store.getState().counter) // 5
+```
+
+(It is safe to override name in this way because the Redux-Leaves `reducer` does not switch over the action's `type`.)
\ No newline at end of file
diff --git a/docs/api/create.spec.js b/docs/api/create.spec.js
new file mode 100644
index 00000000..98486709
--- /dev/null
+++ b/docs/api/create.spec.js
@@ -0,0 +1,59 @@
+import { createStore } from 'redux'
+import reduxLeaves from '../../src';
+
+describe('create has action creators keyed by default and custom creatorKeys', () => {
+ const initialState = {
+ counter: 0,
+ arbitrary: {
+ nested: {
+ path: ['hi!']
+ }
+ }
+ }
+
+ const reducersDict = {
+ convertToFoobar: () => 'foobar'
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+
+ test('All creates have default creatorKeys like update, set and push', () => {
+ expect(typeof actions.counter.create.update).toBe('function')
+ expect(typeof actions.arbitrary.nested.create.set).toBe('function')
+ expect(typeof actions.arbitrary.nested.path.create.push).toBe('function')
+ })
+
+ test('All creates also have supplied custom creatorKeys', () => {
+ expect(typeof actions.create.convertToFoobar).toBe('function')
+ expect(typeof actions.arbitrary.nested.path.create.convertToFoobar).toBe('function')
+ })
+
+ const store = createStore(reducer)
+
+ test("Executing an action creator returns an action to dispatch to the Redux store", () => {
+ const updateCounter = actions.counter.create.update
+
+ store.dispatch(updateCounter(5))
+ expect(store.getState().counter).toBe(5)
+
+ store.dispatch(updateCounter(3))
+ expect(store.getState().counter).toBe(3)
+ })
+
+ describe('create can take a string argument as actionType', () => {
+ test('If given this argument, it still has properties corresponding to default and custom provided creators', () => {
+ expect(typeof actions.counter.create('UPDATE_COUNTER').update).toBe('function')
+ expect(typeof actions.create('CONVERT_TO_FOOBAR').convertToFoobar).toBe('function')
+ })
+
+ test('The created actions have the supplied actionType as type', () => {
+ const createNamedIncrement = actions.counter.create('NAMED_INCREMENT').increment
+ const namedIncrement = createNamedIncrement()
+
+ expect(namedIncrement.type).toBe('NAMED_INCREMENT')
+ const currVal = store.getState().counter
+ store.dispatch(namedIncrement)
+ expect(store.getState().counter).toBe(currVal + 1)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/creatorKeys.md b/docs/api/creatorKeys.md
similarity index 86%
rename from docs/creatorKeys.md
rename to docs/api/creatorKeys.md
index c8114e18..7b119f08 100644
--- a/docs/creatorKeys.md
+++ b/docs/api/creatorKeys.md
@@ -9,9 +9,9 @@ sidebar_label: Creator keys
A creator key (`creatorKey`) serves two roles:
-1. In a [`reducersDict`](README.md#reducersdict), it uniquely identifies a given [leaf reducer](leafReducers.md); and
+1. In a [`reducersDict`](../README.md#reducersdict), it uniquely identifies a given [leaf reducer](leafReducers.md); and
2. In the `actions` API, it:
- - is an action creator available at a given [leaf](leaf/README.md) through [`.create[creatorKey]`](create/defaults.md), that
+ - is an action creator available at a given leaf through [`.create[creatorKey]`](create.md), that
- triggers the corresponding leaf reducer logic (when said action creator is called and its resultant action is dispatched).
## Example
diff --git a/docs/leafReducers.md b/docs/api/leafReducers.md
similarity index 91%
rename from docs/leafReducers.md
rename to docs/api/leafReducers.md
index ba442ae0..07cfce00 100644
--- a/docs/leafReducers.md
+++ b/docs/api/leafReducers.md
@@ -7,11 +7,11 @@ sidebar_label: Leaf reducers
# Leaf reducers
-A leaf reducer is a function or configuration object that updates the state of an arbitrary [leaf](leaf/README.md) in your state tree.
+A leaf reducer is a function or configuration object that updates the state of an arbitrary leaf in your state tree.
They are:
-- passed into [`reduxLeaves`](README.md) with a unique `creatorKey` as part of [`reducersDict`](README.md#reducersdict); and
-- triggered at an arbitrary leaf only by dispatching an action created by the leaf's [`create[creatorKey]`](create/README.md) method.
+- passed into [`reduxLeaves`](../README.md) with a unique [`creatorKey`](creatorKey.md) as part of [`reducersDict`](README.md#reducersdict); and
+- triggered at an arbitrary leaf only by dispatching an action created by the leaf's [`create[creatorKey]`](create.md#createcreatorkey) method.
## Syntax
diff --git a/docs/leafReducers.spec.js b/docs/api/leafReducers.spec.js
similarity index 89%
rename from docs/leafReducers.spec.js
rename to docs/api/leafReducers.spec.js
index 9901e8a6..fc92c435 100644
--- a/docs/leafReducers.spec.js
+++ b/docs/api/leafReducers.spec.js
@@ -1,5 +1,5 @@
import { createStore } from "redux";
-import reduxLeaves from '../src';
+import reduxLeaves from '../../src';
describe("Function shorthand", () => {
@@ -269,37 +269,4 @@ describe("Object longhand", () => {
})
})
})
-
- // describe("mutate", () => {
- // describe("GIVEN the leaf reducer setPropTrue", () => {
- // const setPropTrue = {
- // reducer: (leafState, { payload }) => {
- // leafState[payload] = true
- // },
- // mutate: true
- // }
-
- // describe("WHEN we initialise reduxLeaves with empty state and setPropTrue in the dictionary", () => {
- // const [reducer, actions] = reduxLeaves({}, { setPropTrue })
- // let store
- // beforeEach(() => {
- // store = createStore(reducer)
- // })
-
- // test("THEN the store's state is {}", () => {
- // expect(store.getState()).toEqual({})
- // })
-
- // describe("AND we dispatch actions.create.setPropTrue('foobar')", () => {
- // beforeEach(() => {
- // store.dispatch(actions.create.setPropTrue('foobar'))
- // })
-
- // test("THEN the store's state is { foobar: true }", () => {
- // expect(store.getState()).toEqual({ foobar: true })
- // })
- // })
- // })
- // })
- // })
})
\ No newline at end of file
diff --git a/docs/create/README.md b/docs/create/README.md
deleted file mode 100644
index 1e94aa3b..00000000
--- a/docs/create/README.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-id: creators
-title: Action Creators
-hide_title: true
-sidebar_label: Actions
----
-
-# `actions`
-
-## Action creators
-
-With Redux-Leaves, all [leaf reducers](../leafReducers.md) that you define in your [`reducersDict`](../README.md#reducersdict) are automatically given a corresponding action creator, keyed by the same [`creatorKey`](../creatorKeys.md).
-
-`create[creatorKey]` is then an action creator function available at every single [leaf](../leaf/README.md) on our `actions` object.
-
-Dispatch an action created by `create[creatorKey]` will trigger the matching leaf reducer.
-
-## `create[creatorKey]`
-
-### Parameters
-- `...args` *(...any)*: passed to the leaf reducer's [`argsToPayload`](../leafReducers.md#argstopayload) function
-
-### Returns
-`action` *(object)*: a Leaf-Standard-Action
-
-### Example
-
-#### 1. Grab actions from `reduxLeaves`
-
-```js
-import reduxLeaves from 'redux-leaves'
-import { createStore } from 'redux'
-
-const initialState = {
- foo: 1
-}
-
-const reducersDict = {
- addOne: leafState => leafState + 1,
- double: leafState => 2 * n,
- exponentiate: (leafState, { payload }) => leafState ** payload
-}
-
-const [reducer, actions] = reduxLeaves(initialState, reducersDict)
-```
-
-#### 2. Create actions using creator keys
-```js
-const { create } = actions.foo // action creators for the foo leaf of state
-
-const actionToAddOneToFoo = create.addOne()
-const actionToDoubleFoo = create.double()
-const actionToCubeFoo = create.exponentiate(3)
-```
-Redux-Leaves' action creators can take optional arguments. By default, the first argument (if it exists) becomes the action's payload, but [this behaviour can be configured](../leafReducers.md#argstopayload).
-
-#### 3. Dispatch actions to the store
-```js
-const store = createStore(initialState)
-
-store.dispatch(actionToAddOneToFoo)
-store.dispatch(actionToDoubleFoo)
-store.dispatch(actionToCubeFoo)
-
-// ((1+1)*2)^3 = 64
-console.log(store.getState()) // { foo: 64 }; success!
-```
-
-## `create(actionType)`
-
-### Parameters
-- `actionType` *(string)*
-
-## Example
-```js
-import reduxLeaves from 'redux-leaves'
-import { createStore } from 'redux'
-
-const initialState = {
- counter: 1
-}
-
-const [reducer, actions] = reduxLeaves(initialState, reducersDict)
-const store = createStore(initialState)
-
-const createIncrementCounter = actions.foo.create('INCREMENT_FOO').increment
-console.log(typeof createIncrementCounter) // 'function'
-
-const actionToIncrementCounter = createIncrementCounter()
-console.log(actionToIncrementCounter.type) // 'INCREMENT_FOO'
-
-store.dispatch(actionToIncrementCounter)
-console.log(store.getState()) // { counter: 2 }
-```
-
-## Defaults
-
-Redux-Leaves also ships with some [default action creators](defaults.md) available.
\ No newline at end of file
diff --git a/docs/create/apply.spec.js b/docs/create/apply.spec.js
deleted file mode 100644
index aaa013e5..00000000
--- a/docs/create/apply.spec.js
+++ /dev/null
@@ -1,173 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../src';
-
-describe("leaf.create.apply(callback): returns an action that, when dispatched, updates the leaf's state to the return value of callback(state, entireState)", () => {
-
- describe("Documentation example 1", () => {
- describe("GIVEN setup of initialState and store as documented", () => {
- const initialState = {
- bool: false,
- num: 2,
- str: 'foo',
- arr: [1, 2, 3],
- obj: {}
- }
-
- const [reducer, actions] = reduxLeaves(initialState)
- let store
-
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- describe("WHEN we execute store.dispatch(actions.str.create.apply(state => state.toUpperCase()))", () => {
- beforeEach(() => {
- store.dispatch(actions.str.create.apply(state => state.toUpperCase()))
- })
-
- test("THEN the store's state.str is 'FOO'", () => {
- expect(store.getState().str).toBe('FOO')
- })
-
- describe("AND we execute store.dispatch(actions.create.apply(state => ({ num: state.num, arr: state.arr })))", () => {
- beforeEach(() => {
- store.dispatch(actions.create.apply(state => ({ num: state.num, arr: state.arr })))
- })
-
- test("THEN the store's state is { num: 2, arr: [1, 2, 3] }", () => {
- expect(store.getState()).toEqual({
- num: 2,
- arr: [1, 2, 3]
- })
- })
-
- describe("AND we execute store.dispatch(actions.arr.create.apply((leafState, entireState) => (leafState.map(element => element * entireState.num))))))", () => {
- beforeEach(() => {
- store.dispatch(actions.arr.create.apply((leafState, entireState) => (
- leafState.map(element => element * entireState.num)
- )))
- })
-
- test("THEN the store's state is { num: 2, arr: [2, 4, 6] }", () => {
- expect(store.getState()).toEqual({
- num: 2,
- arr: [2, 4, 6]
- })
- })
- })
- })
- })
- })
-
-
- })
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.counter.create.apply is a function", () => {
- expect(typeof actions.counter.create.apply).toBe("function")
- })
-
- test("AND actions.foo.create.apply is a function", () => {
- expect(typeof actions.foo.create.apply).toBe("function")
- })
-
- test("AND actions.nested.deep.create.apply is a function", () => {
- expect(typeof actions.nested.deep.create.apply).toBe("function")
- })
-
- test("AND actions.nested.state.manageable.create.apply is a function", () => {
- expect(typeof actions.nested.state.manageable.create.apply).toBe("function")
- })
-
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.counter.create.apply(n => n * 7)", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.apply(n => n * 7))
- })
-
- test("THEN actions.counter updates to 7", () => {
- const state = store.getState()
- expect(state.counter).toBe(7)
- expect(state).toEqual({ ...initialState, counter: 7 })
- })
- })
-
- describe("AND we dispatch actions.foo.create.apply(arr => ['foo', ...arr])", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.apply(arr => ['foo', ...arr]))
- })
-
- test("THEN actions.foo updates to ['foo', 'bar']", () => {
- const state = store.getState()
- expect(state.foo).toEqual(['foo', 'bar'])
- expect(state).toEqual({ ...initialState, foo: ['foo', 'bar'] })
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.apply(obj => ({ ...obj, arbitrarily: true }))", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.apply(obj => ({ ...obj, arbitrarily: true })))
- })
-
- test("THEN actions.nested.deep updates to { arbitrarily: true }", () => {
- const state = store.getState()
- expect(state.nested.deep).toEqual({ arbitrarily: true })
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { arbitrarily: true }
- }
- })
- })
- })
-
- describe("AND we dispatch actions.nested.state.manageable.create.apply(str => str.concat(' DEFINITELY!'))", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.state.manageable.create.apply(str => str.concat(' DEFINITELY!')))
- })
-
- test("THEN actions.nested.state.manageable updates to 'maybe...? DEFINITELY!'", () => {
- const state = store.getState()
- expect(state.nested.state.manageable).toEqual('maybe...? DEFINITELY!')
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- state: {
- ...initialState.nested.state,
- manageable: 'maybe...? DEFINITELY!'
- }
- }
- })
- })
- })
-
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asArray/README.md b/docs/create/asArray/README.md
deleted file mode 100644
index df01496e..00000000
--- a/docs/create/asArray/README.md
+++ /dev/null
@@ -1,178 +0,0 @@
----
-id: array-creators
-title: Array Action Creators
-hide_title: true
-sidebar_label: Array
----
-
-# `create.asArray`
-
-Every single leaf on our `actions` object has access to `create.asArray` methods.
-
-If the leaf was initialised with array state, then these methods are also accessible directly through the [`create` API](../defaults.md).
-
-If the current `leafState` is *not* an array, then it is first coerced into an array, before the state is updated according to the action dispatched.
-
-## Action creators
-- [`.concat(array)`](#concatarray)
-- [`.drop([n = 1])`](#createdropn--1)
-- [`.filter(callback)`](#filter(callback))
-- [`.push(element, [index = -1], [replace = false])`](#createpushelement-index---1-replace--false)
-
-[Back to all `create` action creators](../defaults.md)
-
-## `concat(array)`
-**`create.asArray.concat`**
-
-**alias: `create.concat`** *(when `initialLeafState` is an array)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state by concatening it with `array`.
-
-### Parameters
-- `array` *(array)*: the array to concatenate
-
-### Returns
-`action` *(object)*: an object to dispatch to the `store`
-
-##### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: [1, 2, 3]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asArray.concat(['a', 'b', 'c']))
-console.log(store.getState().foo) // [1, 2, 3, 'a', 'b', 'c']
-```
-Back to:
-* [`create.asArray` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
-
-## `drop([n = 1])`
-**`create.asArray.drop`**
-
-**alias: `create.drop`** *(when `initialLeafState` is an array)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, drops the first `n` elements from the leaf's state.
-
-### Parameters
-- `n` *(number, optional)*: the number of elements to drop
-
-### Returns
-`action` *(object)*: an object to dispatch to the `store`
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: ['a', 'b', 'c']
- bar: ['a', 'b', 'c']
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-#### No argument provided
-```js
-store.dispatch(actions.foo.create.asArray.drop())
-console.log(store.getState().foo) // ['b', 'c']
-```
-#### Providing an argument
-```js
-store.dispatch(actions.bar.create.asArray.drop(2))
-console.log(store.getState().bar) // ['c']
-```
-Back to:
-* [`create.asArray` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
-
-## `filter(callback)`
-**via: `create.asArray.filter`**
-
-**alias: `create.filter`** *(when `initialLeafState` is an array)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state by selecting elements that return true when passed to `callback`.
-
-(Effectively, this uses the vanilla javascript [`Array.prototype.filter(callback)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) API.)
-
-### Parameters
-- `callback` *(function)*: the callback function to test each element with
-
-### Returns
-`action` *(object)*: an object to dispatch to the `store`
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: [1, 2, 3, 4, 5]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asArray.filter(e => !(e % 2)))
-console.log(store.getState().foo) // [2, 4]
-```
-Back to:
-* [`create.asArray` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
-
-## `push(element, [index = -1], [replace = false])`
-**`create.asArray.push`**
-
-**alias: `create.push`** *(when `initialLeafState` is an array)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, non-mutatively pushes `element` to the leaf's state at index `index`. If `replace === true`, then `element` replaces the existing element with that index.
-
-### Parameters
-- `element` *(any)*: the element to insert to the leaf's state
-- `index` *(integer, optional)*: the index of the array where `element` should be inserted
-- `replace` *(boolean, optional)*: whether or not `element` should replace the current `index`th element
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: [1, 2, 3]
- bar: [1, 2, 3]
- foobar: [1, 2, 3]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-#### Providing element
-```js
-store.dispatch(actions.foo.create.asArray.push(4))
-console.log(store.getState().foo) // [1, 2, 3, 4]
-```
-#### Providing element and index
-```js
-store.dispatch(actions.bar.create.asArray.push(4, 0))
-console.log(store.getState().bar) // [4, 1, 2, 3]
-```
-#### Providing element, index and replace
-```js
-store.dispatch(actions.foobar.create.asArray.push(4, 0, true))
-console.log(store.getState().foobar) // [4, 2, 3]
-```
-Back to:
-* [`create.asArray` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
\ No newline at end of file
diff --git a/docs/create/asArray/concat.spec.js b/docs/create/asArray/concat.spec.js
deleted file mode 100644
index 9a24e6d9..00000000
--- a/docs/create/asArray/concat.spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.concat(array): returns an action that, when dispatched, updates the leaf's state by non-mutatively concatenating it with array", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- empty: [],
- integers: [1, 2, 3]
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.empty.create.concat is a function", () => {
- expect(typeof actions.empty.create.concat).toBe("function")
- })
-
- test("AND actions.integers.create.concat is a function", () => {
- expect(typeof actions.integers.create.concat).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.empty.create.concat([1, 2, 3])", () => {
- beforeEach(() => {
- store.dispatch(actions.empty.create.concat([1, 2, 3]))
- })
-
- test("THEN actions.empty state updates non-mutatively to [1, 2, 3]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- empty: [1, 2, 3]
- })
- expect(initialState.empty).toEqual([])
- })
- })
-
- describe("AND we dispatch actions.integers.create.concat([4, 5, 6])", () => {
- beforeEach(() => {
- store.dispatch(actions.integers.create.concat([4, 5, 6]))
- })
-
- test("THEN actions.integers state updates non-mutatively to [1, 2, 3,4, 5, 6]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- integers: [1, 2, 3, 4, 5, 6]
- })
- expect(initialState.integers).toEqual([1, 2, 3])
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asArray/drop.spec.js b/docs/create/asArray/drop.spec.js
deleted file mode 100644
index 1c07ba9d..00000000
--- a/docs/create/asArray/drop.spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.drop(n = 1): returns an action that, when dispatched, updates the leaf's state by non-mutatively dropping the first n values", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- empty: [],
- integers: [1, 2, 3]
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.empty.create.drop is a function", () => {
- expect(typeof actions.empty.create.drop).toBe("function")
- })
-
- test("AND actions.integers.create.drop is a function", () => {
- expect(typeof actions.integers.create.drop).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.integers.create.drop()", () => {
- beforeEach(() => {
- store.dispatch(actions.integers.create.drop())
- })
-
- test("THEN actions.integers state updates non-mutatively to [2, 3]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- integers: [2, 3]
- })
- expect(initialState.integers).toEqual([1, 2, 3])
- })
- })
-
- describe("AND we dispatch actions.integers.create.drop(2)", () => {
- beforeEach(() => {
- store.dispatch(actions.integers.create.drop(2))
- })
-
- test("THEN actions.integers state updates non-mutatively to [3]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- integers: [3]
- })
- expect(initialState.integers).toEqual([1, 2, 3])
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asArray/filter.spec.js b/docs/create/asArray/filter.spec.js
deleted file mode 100644
index 564213eb..00000000
--- a/docs/create/asArray/filter.spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.filter(callback): returns an action that, when dispatched, updates the leaf's state by filtering it with the callback", () => {
-
- describe("Documentation example 1", () => {
-
- describe("GIVEN initialState, reducer, actions and created store", () => {
- const initialState = {
- foo: [1, 2, 3, 4, 5]
- }
- const [reducer, actions] = reduxLeaves(initialState)
-
- let store
-
- beforeEach(() => store = createStore(reducer))
-
- test("THEN the store initialises with initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- test("AND actions.foo.create.filter is a function", () => {
- expect(typeof actions.foo.create.filter).toBe("function")
- })
-
- describe("WHEN we dispatch foo.create.filter(e => !(e % 2))", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.filter(e => !(e % 2)))
- })
-
- test("THEN state.foo updates to [2, 4]", () => {
- expect(store.getState()).toEqual({ foo: [2, 4] })
- })
- })
-
- })
-
- })
-})
\ No newline at end of file
diff --git a/docs/create/asArray/push.spec.js b/docs/create/asArray/push.spec.js
deleted file mode 100644
index 2f150da3..00000000
--- a/docs/create/asArray/push.spec.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.push(element, [index = -1], [replace = false]): returns an action that, when dispatched, updates the leaf's state by non-mutatively pushing element into leaf's state at index. If replace === true, then element replaces the existing element with that index.", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- foo: [1, 2, 3],
- bar: [1, 2, 3],
- foobar: [1, 2, 3]
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.foo.create.push is a function", () => {
- expect(typeof actions.foo.create.push).toBe("function")
- })
-
- test("AND actions.bar.create.push is a function", () => {
- expect(typeof actions.bar.create.push).toBe("function")
- })
-
- test("AND actions.foobar.create.push is a function", () => {
- expect(typeof actions.foobar.create.push).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.foo.create.push(4)", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.push(4))
- })
-
- test("THEN actions.foo state updates non-mutatively to [1, 2, 3, 4]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- foo: [1, 2, 3, 4]
- })
- expect(initialState.foo).toEqual([1, 2, 3])
- })
- })
-
- describe("AND we dispatch actions.foo.create.push([4, 5])", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.push([4, 5]))
- })
-
- test("THEN actions.foo state updates non-mutatively to [1, 2, 3, [4, 5]]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- foo: [1, 2, 3, [4, 5]]
- })
- expect(initialState.foo).toEqual([1, 2, 3])
- })
- })
-
- describe("AND we dispatch actions.bar.create.push(4, 0)", () => {
- beforeEach(() => {
- store.dispatch(actions.bar.create.push(4, 0))
- })
-
- test("THEN actions.bar state updates non-mutatively to [4, 1, 2, 3]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- bar: [4, 1, 2, 3]
- })
- expect(initialState.bar).toEqual([1, 2, 3])
- })
- })
-
- describe("AND we dispatch actions.foobar.create.push(4, 0, true)", () => {
- beforeEach(() => {
- store.dispatch(actions.foobar.create.push(4, 0, true))
- })
-
- test("THEN actions.foobar state updates non-mutatively to [4, 2, 3]", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- foobar: [4, 2, 3]
- })
- expect(initialState.foobar).toEqual([1, 2, 3])
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asBoolean/README.md b/docs/create/asBoolean/README.md
deleted file mode 100644
index 07813663..00000000
--- a/docs/create/asBoolean/README.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-id: boolean-creators
-title: Boolean Action Creators
-hide_title: true
-sidebar_label: Boolean
----
-
-# `create.asBoolean`
-
-Every single leaf on our `actions` object has access to `create.asBoolean` methods.
-
-If the leaf was initialised with boolean state, then these methods are also accessible directly through the [`create` API](../defaults.md).
-
-If the current `leafState` is *not* a boolean, then it is first coerced into a boolean as `!!leafState`, before the state is updated according to the action dispatched.
-
-## Action creators
-- [`.off()`](#off)
-- [`.on()`](#on)
-- [`.toggle()`](#toggle)
-
-[Back to all `create` action creators](../defaults.md)
-
-## `off()`
-**`create.asBoolean.off`**
-
-**alias: `create.off`** *(when `initialLeafState` is a boolean)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `false`.
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: true
- bar: false
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asBoolean.off())
-console.log(store.getState().foo) // false
-```
-```js
-store.dispatch(actions.bar.create.asBoolean.off())
-console.log(store.getState().bar) // false
-```
-Back to:
-* [`create.asBoolean` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
-
-## `on()`
-**`create.asBoolean.on`**
-
-**alias: `create.on`** *(when `initialLeafState` is a boolean)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `true`.
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: true
- bar: false
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asBoolean.on())
-console.log(store.getState().foo) // true
-```
-```js
-store.dispatch(actions.bar.create.asBoolean.on())
-console.log(store.getState().bar) // true
-```
-
-## `toggle()`
-**`create.asBoolean.toggle`**
-
-**alias: `create.toggle`** *(when `initialLeafState` is a boolean)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `!leafState`.
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: true
- bar: false
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asBoolean.toggle())
-console.log(store.getState().foo) // false
-```
-```js
-store.dispatch(actions.bar.create.asBoolean.toggle())
-console.log(store.getState().bar) // true
-```
-Back to:
-* [`create.asBoolean` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
\ No newline at end of file
diff --git a/docs/create/asBoolean/off.spec.js b/docs/create/asBoolean/off.spec.js
deleted file mode 100644
index 2db03c7e..00000000
--- a/docs/create/asBoolean/off.spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.off(): returns an action that, when dispatched, updates the leaf's state to false", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- true: true,
- false: false
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.true.create.off is a function", () => {
- expect(typeof actions.true.create.off).toBe("function")
- })
-
- test("AND actions.false.create.off is a function", () => {
- expect(typeof actions.false.create.off).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.true.create.off()", () => {
- beforeEach(() => {
- store.dispatch(actions.true.create.off())
- })
-
- test("THEN actions.true state updates non-mutatively to false", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- true: false
- })
- expect(initialState.true).toBe(true)
- })
- })
-
- describe("AND we dispatch actions.false.create.off()", () => {
- beforeEach(() => {
- store.dispatch(actions.false.create.off())
- })
-
- test("THEN actions.false state remains false", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- false: false
- })
- expect(initialState.false).toBe(false)
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asBoolean/on.spec.js b/docs/create/asBoolean/on.spec.js
deleted file mode 100644
index 074e325d..00000000
--- a/docs/create/asBoolean/on.spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.on(): returns an action that, when dispatched, updates the leaf's state to true", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- true: true,
- false: false
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.true.create.on is a function", () => {
- expect(typeof actions.true.create.on).toBe("function")
- })
-
- test("AND actions.false.create.on is a function", () => {
- expect(typeof actions.false.create.on).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.true.create.on()", () => {
- beforeEach(() => {
- store.dispatch(actions.true.create.on())
- })
-
- test("THEN actions.true state remains true", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- true: true
- })
- expect(initialState.true).toBe(true)
- })
- })
-
- describe("AND we dispatch actions.false.create.on()", () => {
- beforeEach(() => {
- store.dispatch(actions.false.create.on())
- })
-
- test("THEN actions.false state updates non-mutatively to true", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- false: true
- })
- expect(initialState.false).toBe(false)
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asBoolean/toggle.spec.js b/docs/create/asBoolean/toggle.spec.js
deleted file mode 100644
index 51cd73a6..00000000
--- a/docs/create/asBoolean/toggle.spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.toggle(): returns an action that, when dispatched, updates the leaf's state to !state", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- true: true,
- false: false
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.true.create.toggle is a function", () => {
- expect(typeof actions.true.create.toggle).toBe("function")
- })
-
- test("AND actions.false.create.toggle is a function", () => {
- expect(typeof actions.false.create.toggle).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.true.create.toggle()", () => {
- beforeEach(() => {
- store.dispatch(actions.true.create.toggle())
- })
-
- test("THEN actions.true state updates non-mutatively to false", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- true: false
- })
- expect(initialState.true).toBe(true)
- })
- })
-
- describe("AND we dispatch actions.false.create.toggle()", () => {
- beforeEach(() => {
- store.dispatch(actions.false.create.toggle())
- })
-
- test("THEN actions.false state updates non-mutatively to true", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- false: true
- })
- expect(initialState.false).toBe(false)
- })
- })
- })
- })
- })
-})
diff --git a/docs/create/asNumber/README.md b/docs/create/asNumber/README.md
deleted file mode 100644
index ed1600c8..00000000
--- a/docs/create/asNumber/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-id: number-creators
-title: Number Action Creators
-hide_title: true
-sidebar_label: Number
----
-
-# `create.asNumber`
-
-Every single leaf on our `actions` object has access to `create.asNumber` methods.
-
-If the leaf was initialised with number state, then these methods are also accessible directly through the [`create` API](../defaults.md).
-
-If the current `leafState` is *not* a number, then it is first coerced into an array, before the state is updated according to the action dispatched.
-
-## Action creators
-- [`.increment([n = 1])`](#incrementn--1)
-
-[Back to all `create` action creators](../defaults.md)
-
-## `increment([n = 1])`
-**`create.asNumber.increment`**
-
-**alias: `create.increment`** *(when `initialLeafState` is a number)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, increments leaf's state by `n`.
-
-### Parameters
-- `n` *(number)*: the number to increment the leaf's state by
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: 5
- bar: 5
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-#### No argument provided
-```js
-store.dispatch(actions.foo.create.asNumber.increment())
-console.log(store.getState().foo) // 6
-```
-#### Providing an argument
-```js
-store.dispatch(actions.bar.create.asNumber.increment(-6))
-console.log(store.getState().bar) // -1
-```
-Back to:
-* [`create.asNumber` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
\ No newline at end of file
diff --git a/docs/create/asNumber/increment.spec.js b/docs/create/asNumber/increment.spec.js
deleted file mode 100644
index 846e06bf..00000000
--- a/docs/create/asNumber/increment.spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.increment(n = 1): returns an action that, when dispatched, updates the leaf's state by non-mutatively incrementing it by n", () => {
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.counter.create.increment is a function", () => {
- expect(typeof actions.counter.create.increment).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.counter.create.increment()", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.increment())
- })
-
- test("THEN actions.counter state non-mutatively updates to 2", () => {
- const state = store.getState()
- expect(state).toEqual({ ...initialState, counter: 2 })
- expect(initialState.counter).toBe(1)
- })
- })
-
- describe("AND we dispatch actions.counter.create.increment(4)", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.increment(4))
- })
-
- test("THEN actions.counter state non-mutatively updates to 5", () => {
- const state = store.getState()
- expect(state).toEqual({ ...initialState, counter: 5 })
- expect(initialState.counter).toBe(1)
- })
- })
-
- describe("AND we dispatch actions.counter.create.increment(-1.5)", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.increment(-1.5))
- })
-
- test("THEN actions.counter state non-mutatively updates to -0.5", () => {
- const state = store.getState()
- expect(state).toEqual({ ...initialState, counter: -0.5 })
- expect(initialState.counter).toBe(1)
- })
- })
- })
- })
- })
-})
diff --git a/docs/create/asObject/README.md b/docs/create/asObject/README.md
deleted file mode 100644
index 3c2910c1..00000000
--- a/docs/create/asObject/README.md
+++ /dev/null
@@ -1,105 +0,0 @@
----
-id: object-creators
-title: Object Action Creators
-hide_title: true
-sidebar_label: Object
----
-
-# `create.asObject`
-
-Every single leaf on our `actions` object has access to `create.asObject` methods.
-
-If the leaf was initialised with [plain object](#plain-object) state, then these methods are also accessible directly through the [`create` API](../defaults.md).
-
-If the current `leafState` is *not* a plain object, then it is first coerced into a plain object, before the state is updated according to the action dispatched.
-
-#### Plain object
-A plain object is created using `{}`, `new Object()` or `Object.create(null)`
-
-## Action creators
-- [`.assign(...sources)`](#assignsources)
-- [`.set(path, value)`](#setpath-value)
-
-[Back to all `create` action creators](../defaults.md)
-
-## `assign(...sources)`
-**`create.asObject.assign`**
-
-**alias: `create.assign`** *(when `initialLeafState` is a [plain object](#plain-object))*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the copies all properties from `sources` into the leaf's state.
-
-(This is essentially a convenience wrapper on top of the vanilla JavaScript [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign).)
-
-### Parameters
-- `sources` *(...objects)*: the path of the property to set
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: { props: true }
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asObject.assign({ string: 'foo' }))
-console.log(store.getState().foo) // { props: true, string: 'foo' }
-```
-```js
-store.dispatch(actions.ar.create.asObject.assign({ props: false }))
-console.log(store.getState().foo) // { props: false, string: 'foo' }
-```
-Back to:
-* [`create.asObject` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
-
-
-## `set(key, value)`
-**`create.asObject.set`**
-
-**alias: `create.set`** *(when `initialLeafState` is a [plain object](#plain-object))*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state at the property `key` with `value`.
-
-```js
-// TODO update this
-```
-
-### Parameters
-- `key` *(string)*: the path of the property to set
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: {}
- bar: { props: true }
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asObject.set('accessed', true))
-console.log(store.getState().foo) // { accessed: true }
-```
-```js
-store.dispatch(actions.bar.create.asObject.set('props', false))
-console.log(store.getState().bar.props) // false
-```
-Back to:
-* [`create.asObject` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
\ No newline at end of file
diff --git a/docs/create/asObject/assign.spec.js b/docs/create/asObject/assign.spec.js
deleted file mode 100644
index 59a05dbc..00000000
--- a/docs/create/asObject/assign.spec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.assign(...sources): returns an action that, when dispatched, updates the leaf's state by non-mutatively copying over properties from the sources", () => {
-
- describe("Documentation example 1", () => {
-
- describe("GIVEN initial state, reducer, actions and store as in example", () => {
- const initialState = {
- foo: { props: true }
- }
-
- const [reducer, actions] = reduxLeaves(initialState)
- let store
-
- beforeEach(() => store = createStore(reducer))
-
- test("THEN store initialises with initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("WHEN we dispatch actions.foo.create.assign({ string: 'foo' })", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.assign({ string: 'foo' }))
- })
-
- test("THEN store state.foo updates to { props: true, string: 'foo' }", () => {
- expect(store.getState()).toEqual({
- foo: { props: true, string: 'foo' }
- })
- })
-
- })
- })
-
-
- })
-})
\ No newline at end of file
diff --git a/docs/create/asObject/path.spec.js b/docs/create/asObject/path.spec.js
deleted file mode 100644
index 714e294f..00000000
--- a/docs/create/asObject/path.spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.path(path, value): returns an action that, when dispatched, updates the leaf's state by non-mutatively pathting value at state object's path", () => {
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.nested.deep.create.path is a function", () => {
- expect(typeof actions.nested.deep.create.path).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.nested.deep.create.path(['arbitrarily'], true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.path(['arbitrarily'], true))
- })
-
- test("THEN actions.counter state non-mutatively updates to { arbitrarily: true }", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { arbitrarily: true }
- }
- })
- expect(initialState.nested.deep).toEqual({})
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.path(['arbitrarily', 'so'], true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.path(['arbitrarily', 'so'], true))
- })
-
- test("THEN actions.counter state non-mutatively updates to { arbitrarily: {so : true } }", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { arbitrarily: { so: true } }
- }
- })
- expect(initialState.nested.deep).toEqual({})
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asObject/set.spec.js b/docs/create/asObject/set.spec.js
deleted file mode 100644
index 6c4f3690..00000000
--- a/docs/create/asObject/set.spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.set(path, value): returns an action that, when dispatched, updates the leaf's state by non-mutatively setting value at state object's path", () => {
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.nested.deep.create.set is a function", () => {
- expect(typeof actions.nested.deep.create.set).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.nested.deep.create.set('arbitrarily', true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.set('arbitrarily', true))
- })
-
- test("THEN actions.counter state non-mutatively updates to { arbitrarily: true }", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { arbitrarily: true }
- }
- })
- expect(initialState.nested.deep).toEqual({})
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.set('arbitrarily.so', true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.set('arbitrarily.so', true))
- })
-
- test("THEN actions.counter state non-mutatively updates to { 'arbitrarily.so': true }", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { 'arbitrarily.so': true }
- }
- })
- expect(initialState.nested.deep).toEqual({})
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/asString/README.md b/docs/create/asString/README.md
deleted file mode 100644
index 60751379..00000000
--- a/docs/create/asString/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-id: string-creators
-title: String Action Creators
-hide_title: true
-sidebar_label: String
----
-
-# `create.asString`
-
-Every single leaf on our `actions` object has access to `create.asString` methods.
-
-If the leaf was initialised with string state, then these methods are also accessible directly through the [`create` API](../defaults.md).
-
-If the current `leafState` is *not* a string, then it is first coerced into a string, before the state is updated according to the action dispatched.
-
-## Action creators
-- [`.concat(...strings)`](#concatstrings)
-- [`.replace(pattern, replacement)`](#replacepattern-replacement)
-
-[Back to all `create` action creators](../defaults.md)
-
-## `replace(pattern, replacement)`
-**`create.asString.replace`**
-
-**alias: `create.replace`** *(when `initialLeafState` is a string)*
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state by replacing some, or all, matches of `pattern` with `replacement`.
-
-### Parameters
-- `pattern` *(RegExp | string)*: the pattern to replace
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- foo: 'foo'
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-```js
-store.dispatch(actions.foo.create.asString.replace('f', 'B'))
-console.log(store.getState().foo) // 'Boo'
-```
-Back to:
-* [`create.asString` action creators](#action-creators)
-* [all `create` action creators](../README.md#action-creators)
\ No newline at end of file
diff --git a/docs/create/asString/replace.spec.js b/docs/create/asString/replace.spec.js
deleted file mode 100644
index 0ff29050..00000000
--- a/docs/create/asString/replace.spec.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../../src';
-
-describe("leaf.create.replace(): returns an action that, when dispatched, updates the leaf's state to !state", () => {
-
- describe("GIVEN initialState is an object", () => {
- const initialState = {
- foo: "foo"
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.foo.create.replace is a function", () => {
- expect(typeof actions.foo.create.replace).toBe("function")
- })
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.foo.create.replace('f', 'b')", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.replace('f', 'b'))
- })
-
- test("THEN actions.foo state updates non-mutatively to 'boo'", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- foo: 'boo'
- })
- expect(initialState.foo).toBe('foo')
- })
- })
- })
- })
- })
-})
diff --git a/docs/create/clear.spec.js b/docs/create/clear.spec.js
deleted file mode 100644
index c791d0ab..00000000
--- a/docs/create/clear.spec.js
+++ /dev/null
@@ -1,210 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../src';
-
-describe("leaf.create.clear(toNull = false): returns an action that, when dispatched, clear's the leaf's state", () => {
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.counter.create.clear is a function", () => {
- expect(typeof actions.counter.create.clear).toBe("function")
- })
-
- test("AND actions.foo.create.clear is a function", () => {
- expect(typeof actions.foo.create.clear).toBe("function")
- })
-
- test("AND actions.nested.deep.create.clear is a function", () => {
- expect(typeof actions.nested.deep.create.clear).toBe("function")
- })
-
- test("AND actions.nested.state.manageable.create.clear is a function", () => {
- expect(typeof actions.nested.state.manageable.create.clear).toBe("function")
- })
-
-
- describe("AND store = createStore(reducer, otherState)", () => {
- let store
- const otherState = {
- counter: 5,
- foo: ["FOOBAR"],
- nested: {
- deep: {
- props: true
- },
- state: {
- manageable: "let's find out"
- }
- }
- }
- beforeEach(() => {
- store = createStore(reducer, otherState)
- })
-
- test("THEN store is initialised with state = otherState", () => {
- expect(store.getState()).toEqual(otherState)
- })
-
- describe("AND we dispatch actions.counter.create.clear()", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.clear())
- })
-
- test("THEN actions.counter updates to 0", () => {
- const state = store.getState()
- expect(state.counter).toBe(0)
- expect(state).toEqual({ ...otherState, counter: 0 })
- })
- })
-
- describe("AND we dispatch actions.counter.create.clear(true)", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.clear(true))
- })
-
- test("THEN actions.counter updates to null", () => {
- const state = store.getState()
- expect(state.counter).toBeNull()
- expect(state).toEqual({ ...otherState, counter: null })
- })
- })
-
- describe("AND we dispatch actions.foo.create.clear()", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.clear())
- })
-
- test("THEN actions.foo updates to []", () => {
- const state = store.getState()
- expect(state.foo).toEqual([])
- expect(state).toEqual({ ...otherState, foo: [] })
- })
- })
-
- describe("AND we dispatch actions.foo.create.clear(true)", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.clear(true))
- })
-
- test("THEN actions.foo updates to null", () => {
- const state = store.getState()
- expect(state.foo).toBeNull()
- expect(state).toEqual({ ...otherState, foo: null })
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.clear()", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.clear())
- })
-
- test("THEN actions.nested.deep updates to {}", () => {
- const state = store.getState()
- expect(state.nested.deep).toEqual({})
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- deep: {}
- }
- })
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.clear(true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.clear(true))
- })
-
- test("THEN actions.nested.deep updates to null", () => {
- const state = store.getState()
- expect(state.nested.deep).toBeNull()
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- deep: null
- }
- })
- })
- })
-
- describe("AND we dispatch actions.nested.state.manageable.create.clear()", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.state.manageable.create.clear())
- })
-
- test("THEN actions.nested.state.manageable updates to ''", () => {
- const state = store.getState()
- expect(state.nested.state.manageable).toBe('')
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- state: {
- ...otherState.nested.state,
- manageable: ''
- }
- }
- })
- })
- })
-
- describe("AND we dispatch actions.nested.state.manageable.create.clear(true)", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.state.manageable.create.clear(true))
- })
-
- test("THEN actions.nested.state.manageable updates to null", () => {
- const state = store.getState()
- expect(state.nested.state.manageable).toBeNull()
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- state: {
- ...otherState.nested.state,
- manageable: null
- }
- }
- })
- })
- })
-
- describe("AND we dispatch actions.create.clear(true)", () => {
- beforeEach(() => {
- store.dispatch(actions.create.clear(true))
- })
-
- test("THEN state updates to null", () => {
- const state = store.getState()
- expect(state).toBeNull()
- })
- })
-
- describe("AND we dispatch actions.create.clear()", () => {
- beforeEach(() => {
- store.dispatch(actions.create.clear())
- })
-
- test("THEN state updates to {}", () => {
- const state = store.getState()
- expect(state).toEqual({})
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/defaults.md b/docs/create/defaults.md
deleted file mode 100644
index 837c1c7b..00000000
--- a/docs/create/defaults.md
+++ /dev/null
@@ -1,249 +0,0 @@
----
-id: defaults
-title: Default Action Creators
-hide_title: true
-sidebar_label: Universal
----
-
-# `create`
-
-Every single [leaf](../leaf/README.md) on our [`actions`](README.md) object has a `create` property, through which we can access action creator functions corresponding to the [`reducersDict`](../README.md#reducersdict) passed to to [`reduxLeaves`](../README.md).
-
-In addition, `create` also contains a number of default action creators, which are listed below.
-
-The default action creators can be overwritten by supplying your own [leaf reducer](../leafReducers.md) definition (with the same [`creatorKey`](../creatorKeys.md)) in your `reducersDict`.
-
-## Action creators
-### Universal
-- [`.apply(callback)`](#applycallback)
-- [`.clear([toNull = false])`](#cleartonull--false)
-- [`.reset()`](#reset)
-- [`.update(value)`](#updatevalue)
-
-### Type-specific
-These are [spread into the `create` object](typeSpecific.md) depending on the `initialLeafState`, or accessible through their respective APIs:
-
-- [`create.asArray`](asArray/README.md#createasarray)
-- [`create.asBoolean`](asBoolean/README.md#createasboolean)
-- [`create.asNumber`](asNumber/README.md#createasnumber)
-- [`create.asObject`](asObject/README.md#createasobject)
-- [`create.asString`](asString/README.md#createasstring)
-
-
-## `apply(callback)`
-**`create.apply`**
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to the return value of `callback(leafState, entireState)`.
-
-*Note: creating an action using `apply(callback)` violates Redux's recommendation that [actions should always be serializable](https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants), since the resultant action will have the function `callback` as its `payload`.*
-
-### Parameters
-- `callback` *(function)*: invoked by the leaf's reducer with two arguments, `leafState` and `entireState`
-
-### Returns
-`action` *(object)*: an object to dispatch to the `store`
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- bool: false,
- num: 2,
- str: 'foo',
- arr: [1, 2, 3]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-
-Calling `create.apply` on a leaf:
-
-```js
-store.dispatch(actions.str.create.apply(state => state.toUpperCase()))
-console.log(store.getState().str) // 'FOO'
-```
-
-Calling `create.apply` on a branch:
-
-```js
-store.dispatch(actions.create.apply(state => ({ num: state.num, arr: state.arr }))
-console.log(store.getState()) // { num: 2, arr: [1, 2, 3] }
-```
-
-Calling `create.apply` with two arguments:
-
-```js
-store.dispatch(actions.arr.create.apply(
- (leafState, entireState) => leafState.map(element => element * entireState.num)
-))
-console.log(store.getState()) // { num: 2, arr: [2, 4, 6] }
-```
-
-[Back to all `create` action creators](#action-creators)
-
-## `clear([toNull = false])`
-**`create.clear`**
-
-Returns an object that, *when dispatched to a store created with the original state tree*, clears the leaf's state.
-
-If `toNull === true`, then it updates it to `null`, otherwise it follows the type of the leaf's initial state:
-- *number*: `0`
-- *string*: `''`
-- *boolean*: `false`
-- *array*: `[]`
-- *object*: `{}`
-
-### Parameters
-- `toNull` *(boolean, optional)*: defaults to `false`
-
-### Returns
-`action` *(object)*: an object to dispatch to the `store`
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- bool: true,
- num: 2,
- str: 'foo',
- arr: [1, 2, 3]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-#### bool
-```js
-store.dispatch(actions.bool.create.clear())
-console.log(store.getState().bool) // false
-
-store.dispatch(actions.bool.create.clear(true))
-console.log(store.getState().bool) // null
-```
-#### num
-```js
-store.dispatch(actions.num.create.clear())
-console.log(store.getState().num) // 0
-
-store.dispatch(actions.num.create.clear(true))
-console.log(store.getState().num) // null
-```
-#### str
-```js
-store.dispatch(actions.str.create.clear(true))
-console.log(store.getState().str) // null
-
-store.dispatch(actions.str.create.clear())
-console.log(store.getState().str) // ''
-```
-#### arr
-```js
-store.dispatch(actions.arr.create.clear(true))
-console.log(store.getState().arr) // null
-
-store.dispatch(actions.arr.create.clear())
-console.log(store.getState().arr) // []
-```
-#### obj
-```js
-store.dispatch(actions.create.clear(true))
-console.log(store.getState()) // null
-
-store.dispatch(actions.create.clear())
-console.log(store.getState()) // {}
-```
-
-[Back to all `create` action creators](#action-creators)
-
-## `reset()`
-**`create.reset`**
-
-Returns an object that, *when dispatched to a store created with the original state tree*, resets the leaf's state to its initial state stored in the actions.
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- num: 2,
- arr: [1, 2, 3]
-
-const otherState = {
- num: 11,
- arr: ['a', 'b', 'c']
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer, otherState) // preloads otherState
-
-/* store.getState()
-* {
-* num: 11,
-* arr: ['a', 'b', 'c']
-* }
-*/
-
-```
-Calling `create.reset` on a leaf:
-```js
-store.dispatch(actions.num.create.reset())
-console.log(store.getState().num) // 2
-```
-Calling `create.reset` on a branch:
-```js
-store.dispatch(actions.create.reset())
-console.log(store.getState()) // { num: 2, arr: [1, 2, 3] }
-```
-
-[Back to all `create` action creators](#action-creators)
-
-## `update(value)`
-**`create.update`**
-
-Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `value`.
-
-### Parameters
-- `value` *(any)*: the new value for the leaf's state
-
-### Returns
-`action` *(object)*: an object to dispatch to the store
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- bool: false,
- num: 2,
- str: 'foo',
- arr: [1, 2, 3]
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-
-Calling `create.update` on a leaf:
-
-```js
-store.dispatch(actions.str.create.update("I can put anything here"))
-console.log(store.getState().str) // 'I can put anything here'
-```
-
-Calling `create.update` on a branch:
-```js
-store.dispatch(actions.create.update({ any: { properties: true }}))
-console.log(store.getState()) // { any: { properties: true } }
-```
-
-[Back to all `create` action creators](#action-creators)
\ No newline at end of file
diff --git a/docs/create/reset.spec.js b/docs/create/reset.spec.js
deleted file mode 100644
index 9b079b2a..00000000
--- a/docs/create/reset.spec.js
+++ /dev/null
@@ -1,176 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../src';
-
-describe("leaf.create.reset(): returns an action that, when dispatched, updates the leaf's state to the reducer's initialised state", () => {
-
- describe("Documentation example 1", () => {
- describe("GIVEN setup of initialState, otherState and store as documented", () => {
- const initialState = {
- num: 2,
- arr: [1, 2, 3],
- }
-
- const otherState = {
- num: 11,
- arr: ['a', 'b', 'c']
- }
-
- const [reducer, actions] = reduxLeaves(initialState)
- let store
-
- beforeEach(() => {
- store = createStore(reducer, otherState)
- })
-
- test("THEN store is initialised with otherState", () => {
- expect(store.getState()).toEqual(otherState)
- })
-
- describe("WHEN we execute store.dispatch(actions.num.create.reset()))", () => {
- beforeEach(() => {
- store.dispatch(actions.num.create.reset())
- })
-
- test("THEN the store's state.num is 2", () => {
- expect(store.getState().num).toBe(2)
- })
-
- describe("AND we execute store.dispatch(actions.create.reset())", () => {
- beforeEach(() => {
- store.dispatch(actions.create.reset())
- })
-
- test("THEN the store's state is { num: 2, arr: [1, 2, 3] }", () => {
- expect(store.getState()).toEqual({
- num: 2,
- arr: [1, 2, 3]
- })
- })
- })
- })
- })
-
-
- })
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.counter.create.reset is a function", () => {
- expect(typeof actions.counter.create.reset).toBe("function")
- })
-
- test("AND actions.foo.create.reset is a function", () => {
- expect(typeof actions.foo.create.reset).toBe("function")
- })
-
- test("AND actions.nested.deep.create.reset is a function", () => {
- expect(typeof actions.nested.deep.create.reset).toBe("function")
- })
-
- test("AND actions.nested.state.manageable.create.reset is a function", () => {
- expect(typeof actions.nested.state.manageable.create.reset).toBe("function")
- })
-
-
- describe("AND store = createStore(reducer, otherState)", () => {
- let store
- const otherState = {
- counter: 5,
- foo: ["FOOBAR"],
- nested: {
- deep: {
- props: true
- },
- state: {
- manageable: "let's find out"
- }
- }
- }
- beforeEach(() => {
- store = createStore(reducer, otherState)
- })
-
- test("THEN store is initialised with state = otherState", () => {
- expect(store.getState()).toEqual(otherState)
- })
-
- describe("AND we dispatch actions.counter.create.reset()", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.reset())
- })
-
- test("THEN actions.counter resets to 1", () => {
- const state = store.getState()
- expect(state.counter).toBe(1)
- expect(state).toEqual({ ...otherState, counter: 1 })
- })
- })
-
- describe("AND we dispatch actions.foo.create.reset()", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.reset())
- })
-
- test("THEN actions.foo resets to ['bar']", () => {
- const state = store.getState()
- expect(state.foo).toEqual(['bar'])
- expect(state).toEqual({ ...otherState, foo: ['bar'] })
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.reset()", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.reset())
- })
-
- test("THEN actions.nested.deep resets to {}", () => {
- const state = store.getState()
- expect(state.nested.deep).toEqual({})
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- deep: {}
- }
- })
- })
- })
-
- describe("AND we dispatch actions.nested.state.manageable.create.reset()", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.state.manageable.create.reset())
- })
-
- test("THEN actions.nested.state.manageable resets to 'maybe...?'", () => {
- const state = store.getState()
- expect(state.nested.state.manageable).toEqual('maybe...?')
- expect(state).toEqual({
- ...otherState,
- nested: {
- ...otherState.nested,
- state: {
- ...otherState.nested.state,
- manageable: 'maybe...?'
- }
- }
- })
- })
- })
-
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/create/typeSpecific.md b/docs/create/typeSpecific.md
deleted file mode 100644
index 9c8c6cb4..00000000
--- a/docs/create/typeSpecific.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-id: type-specific
-title: Type-Specific Action Creators
-hide_title: true
-sidebar_label: Type-specific
----
-
-# Type-specific `create` methods
-
-- [`create.asArray`](asArray/README.md#createasarray)
-- [`create.asBoolean`](asBoolean/README.md#createasboolean)
-- [`create.asNumber`](asNumber/README.md#createasnumber)
-- [`create.asObject`](asObject/README.md#createasobject)
-- [`create.asString`](asString/README.md#createasstring)
-
-
-All type-agnostic methods can be accessed through every leaf's `create` property.
-
-Additionally, every leaf has access to type-specific methods (e.g. [`create.asArray` methods](asArray/README.md#createasarray)), even if the leaf state is not an array.
-
-For convenience, *if applicable at initialisation through [`reduxLeaves`](../README.md)*, type-specific methods are also aliased so that they are directly available through `create` directly.
-
-
-#### Example
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'reduxLeaves'
-
-const initialState = {
- bool: false, // initialised as boolean
- num: 2, // initialised as number
- str: 'foo', // initialised as string
- arr: [1, 2, 3], // initialised as array
- obj: {} // initialised as object
-}
-
-const [reducer, actions] = reduxLeaves(initialState)
-const store = createStore(reducer)
-```
-All leaves have access to [`create.asArray.push`](asArray/README.md#createpushelement-index---1-replace--false):
-```js
-console.log(typeof actions.bool.create.asArray.push) // function
-console.log(typeof actions.num.create.asArray.push) // function
-console.log(typeof actions.str.create.asArray.push) // function
-console.log(typeof actions.str.arr.create.asArray.push) // function
-console.log(typeof actions.str.obj.create.asArray.push) // function
-```
-But **only** `actions.arr.create` has *direct* access to `create.push`, since it is the only leaf that was initialised as an array:
-```js
-console.log(typeof actions.bool.create.push) // undefined
-console.log(typeof actions.num.create.push) // undefined
-console.log(typeof actions.str.create.push) // undefined
-console.log(typeof actions.str.arr.create.push) // function: initialised as array
-console.log(typeof actions.str.obj.create.push) // undefined
-```
\ No newline at end of file
diff --git a/docs/create/update.spec.js b/docs/create/update.spec.js
deleted file mode 100644
index f4b88440..00000000
--- a/docs/create/update.spec.js
+++ /dev/null
@@ -1,174 +0,0 @@
-import { createStore } from "redux";
-import reduxLeaves from '../../src';
-
-describe("leaf.create.update(value): returns an action that, when dispatched, updates the leaf's state to value", () => {
-
- describe("Documentation example 1", () => {
- describe("GIVEN setup of initialState and store as documented", () => {
- const initialState = {
- bool: false,
- num: 2,
- str: 'foo',
- arr: [1, 2, 3]
- }
-
- const [reducer, actions] = reduxLeaves(initialState)
- let store
-
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- describe("WHEN we execute store.dispatch(actions.str.create.update('I can put anything here'))", () => {
- beforeEach(() => {
- store.dispatch(actions.str.create.update('I can put anything here'))
- })
-
- test("THEN the store's state.str is 'I can put anything here'", () => {
- expect(store.getState().str).toBe('I can put anything here')
- })
-
- describe("AND we execute store.dispatch(actions.create.update({ any: { properties: true } }))", () => {
- beforeEach(() => {
- store.dispatch(actions.create.update({ any: { properties: true } }))
- })
-
- test("THEN the store's state is { any: { properties: { true }} }", () => {
- expect(store.getState()).toEqual({
- any: { properties: true }
- })
- })
- })
- })
-
- describe("WHEN we create an action with actions.str.create('DID_AN_UPDATE').update('I can put anything here')", () => {
- const action = actions.str.create('DID_AN_UPDATE').update('I can put anything here')
-
- test("THEN the action's type is 'DID_AN_UPDATE'", () => {
- expect(action.type).toBe('DID_AN_UPDATE')
- })
-
- describe('WHEN we dispatch that action to the store', () => {
- beforeEach(() => {
- store.dispatch(actions.str.create('DID_AN_UPDATE').update('I can put anything here'))
- })
-
- test("THEN the store's state.str is 'I can put anything here'", () => {
- expect(store.getState().str).toBe('I can put anything here')
- })
- })
- })
- })
-
-
- })
-
- describe("GIVEN non-trivially nested API (as in the documentation)", () => {
- const initialState = {
- counter: 1,
- foo: ["bar"],
- nested: {
- deep: {},
- state: {
- manageable: "maybe...?"
- }
- }
- }
-
- describe("WHEN [reducer, actions] = reduxLeaves(initialState)", () => {
- const [reducer, actions] = reduxLeaves(initialState)
-
- test("THEN actions.counter.create.update is a function", () => {
- expect(typeof actions.counter.create.update).toBe("function")
- })
-
- test("AND actions.foo.create.update is a function", () => {
- expect(typeof actions.foo.create.update).toBe("function")
- })
-
- test("AND actions.nested.deep.create.update is a function", () => {
- expect(typeof actions.nested.deep.create.update).toBe("function")
- })
-
- test("AND actions.nested.state.manageable.create.update is a function", () => {
- expect(typeof actions.nested.state.manageable.create.update).toBe("function")
- })
-
-
- describe("AND store = createStore(reducer)", () => {
- let store
- beforeEach(() => {
- store = createStore(reducer)
- })
-
- test("THEN store is initialised with state = initialState", () => {
- expect(store.getState()).toEqual(initialState)
- })
-
- describe("AND we dispatch actions.counter.create.update(9)", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.update(9))
- })
-
- test("THEN actions.counter state updates non-mutatively to 9", () => {
- const state = store.getState()
- expect(state).toEqual({ ...initialState, counter: 9 })
- expect(initialState.counter).toBe(1)
- })
- })
-
- describe("AND we dispatch actions.foo.create.update(['f', 'o', 'o'])", () => {
- beforeEach(() => {
- store.dispatch(actions.foo.create.update(['f', 'o', 'o']))
- })
-
- test("THEN actions.foo state updates non-mutatively to ['f', 'o', 'o']", () => {
- const state = store.getState()
- expect(state).toEqual({ ...initialState, foo: ['f', 'o', 'o'] })
- expect(initialState.foo).toEqual(['bar'])
- })
- })
-
- describe("AND we dispatch actions.nested.deep.create.update({ here: true })", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.deep.create.update({ here: true }))
- })
-
- test("THEN actions.nested.deep updates to { here: true }", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- deep: { here: true }
- }
- })
- expect(initialState.nested.deep).toEqual({})
- })
- })
-
- describe("AND we dispatch actions.nested.state.manageabl.createe.update('thanks to redux-leaves!')", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.state.manageable.create.update('thanks to redux-leaves!'))
- })
-
- test("THEN actions.nested.state.manageable updates to 'thanks to redux-leaves!'", () => {
- const state = store.getState()
- expect(state).toEqual({
- ...initialState,
- nested: {
- ...initialState.nested,
- state: {
- ...initialState.nested.state,
- manageable: 'thanks to redux-leaves!'
- }
- }
- })
- expect(initialState.nested.state.manageable).toBe("maybe...?")
- })
- })
-
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/defaults/README.md b/docs/defaults/README.md
new file mode 100644
index 00000000..fd4f7a1e
--- /dev/null
+++ b/docs/defaults/README.md
@@ -0,0 +1,41 @@
+---
+id:
+title: Default action creators by type
+hide_title: true
+sidebar_label: By type
+---
+
+# Default action creators by type
+
+All of the below action creators are availble through the [`create`](../api/create.md) API at any arbitrary leaf of [`actions`](../api/actions.md).
+
+Some are more useful depending on the type of leaf state you are operating with:
+
+## any
+- [`.apply(callback)`](apply.md)
+- [`.clear([toNull = false])`](clear.md)
+- [`.reset()`](reset.md)
+- [`.update(value)`](update.md)
+
+## array
+- [`.concat(array)`](concat.md)
+- [`.drop([n = 1])`](drop.md)
+- [`.filter(callback)`](filter.md)
+- [`.push(element, [index = -1], [replace = false])`](push.md)
+
+## boolean
+- [`.off()`](off.md)
+- [`.on()`](on.md)
+- [`.toggle()`](toggle.md)
+
+# number
+- [`.increment([n = 1])`](increment.md)
+
+## object
+- [`.assign(...sources)`](assign.md)
+- [`.path(path, value)`](path.md)
+- [`.set(key, value)`](set.md)
+
+## string
+- [`.concat(string)`](concat.md)
+
diff --git a/docs/defaults/apply.md b/docs/defaults/apply.md
new file mode 100644
index 00000000..4c6933c3
--- /dev/null
+++ b/docs/defaults/apply.md
@@ -0,0 +1,71 @@
+---
+id: apply
+title: apply
+hide_title: true
+sidebar_label: apply
+---
+
+# `apply(callback)`
+**`create.apply`**
+**`create(actionType).apply`**
+*Appropriate leaf state: any*
+
+Returns an action object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to the return value of `callback(leafState, treeState)`.
+
+*Note: creating an action using `apply(callback)` does not follow Redux's non-enforced recommendation that [actions should always be serializable](https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants), since the resultant action will have the function `callback` as its `payload`.*
+
+## Parameters
+- `callback` *(function)*: invoked by the leaf's reducer with two arguments, `leafState` and `entireState`
+
+## Returns
+`action` *(object)*: an object to dispatch to the `store`
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ bool: false,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3]
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling `create.apply` on a leaf:
+
+```js
+const applyToString = actions.str.create.apply
+store.dispatch(applyToString(state => state.toUpperCase()))
+console.log(store.getState().str) // 'FOO'
+```
+
+### Calling `create(actionType).apply` on a leaf:
+
+```js
+const applyToBoolean = actions.bool.create('APPLY_TO_BOOLEAN').apply
+store.dispatch(applyToBoolean(state => !state))
+console.log(store.getState().bool) // true
+```
+
+### Calling `create.apply` on a branch:
+
+```js
+const applyToState = actions.create.apply
+store.dispatch(applyToState(state => ({ num: state.num, arr: state.arr }))
+console.log(store.getState()) // { num: 2, arr: [1, 2, 3] }
+```
+
+### Calling `create.apply` with two arguments:
+
+```js
+const applyToArray = actions.arr.create.apply
+store.dispatch(applyToArray(
+ (leafState, treeState) => leafState.map(element => element * treeState.num)
+))
+console.log(store.getState()) // { num: 2, arr: [2, 4, 6] }
+```
\ No newline at end of file
diff --git a/docs/defaults/apply.spec.js b/docs/defaults/apply.spec.js
new file mode 100644
index 00000000..e285d94f
--- /dev/null
+++ b/docs/defaults/apply.spec.js
@@ -0,0 +1,41 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.apply(callback): returns an action that, when dispatched, updates the leaf's state to the return value of callback(state, entireState)", () => {
+ const initialState = {
+ bool: false,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3],
+ obj: {}
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Calling create.apply on a leaf", () => {
+ const applyToString = actions.str.create.apply
+ store.dispatch(applyToString(state => state.toUpperCase()))
+ expect(store.getState().str).toBe('FOO')
+ })
+
+ test("Calling create(actionType).apply on a leaf", () => {
+ const applyToBoolean = actions.bool.create('APPLY_TO_BOOLEAN').apply
+ store.dispatch(applyToBoolean(state => !state))
+ expect(store.getState().bool).toBe(true)
+ })
+
+ test("Calling create.apply on a branch", () => {
+ const applyToState = actions.create.apply
+ store.dispatch(applyToState(state => ({ num: state.num, arr: state.arr })))
+ expect(store.getState()).toEqual({ num: 2, arr: [1, 2, 3] })
+ })
+
+ test("Calling create.apply with two arguments", () => {
+ const applyToArray = actions.arr.create.apply
+ store.dispatch(applyToArray(
+ (leafState, treeState) => leafState.map(element => element * treeState.num)
+ ))
+ expect(store.getState()).toEqual({ num: 2, arr: [2, 4, 6] })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/assign.md b/docs/defaults/assign.md
new file mode 100644
index 00000000..726be3f3
--- /dev/null
+++ b/docs/defaults/assign.md
@@ -0,0 +1,47 @@
+---
+id: assign
+title: assign
+hide_title: true
+sidebar_label: assign
+---
+
+# `assign(...sources)`
+**`create.assign`**
+**`create(actionType).assign`**
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the copies all properties from `sources` into the leaf's state.
+
+(This is essentially a convenience wrapper on top of the vanilla JavaScript [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign).)
+
+## Parameters
+- `sources` *(...objects)*: the path of the property to set
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: { props: true },
+ bar: { props: false }
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Assigning new properties
+```js
+const assignToFoo = actions.foo.create.assign
+store.dispatch(assignToFoo({ count: 2 }))
+console.log(store.getState().foo) // { props: true, count: 2 }
+```
+### Overwriting properties
+```js
+const assignToBar = actions.bar.create.assign
+store.dispatch(assignToBar({ props: true }))
+console.log(store.getState().bar) // { props: true }
+```
\ No newline at end of file
diff --git a/docs/defaults/assign.spec.js b/docs/defaults/assign.spec.js
new file mode 100644
index 00000000..1ba8aab2
--- /dev/null
+++ b/docs/defaults/assign.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.assign(...sources): returns an action that, when dispatched, updates the leaf's state by non-mutatively copying over properties from the sources", () => {
+ const initialState = {
+ foo: { props: true },
+ bar: { props: false }
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Assigning new properties", () => {
+ const assignToFoo = actions.foo.create.assign
+ store.dispatch(assignToFoo({ count: 2 }))
+ expect(store.getState().foo).toEqual({ props: true, count: 2 })
+ })
+
+ test("Overwriting properties", () => {
+ const assignToBar = actions.bar.create.assign
+ store.dispatch(assignToBar({ props: true }))
+ expect(store.getState().bar).toEqual({ props: true })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/clear.md b/docs/defaults/clear.md
new file mode 100644
index 00000000..f93cd319
--- /dev/null
+++ b/docs/defaults/clear.md
@@ -0,0 +1,92 @@
+---
+id: clear
+title: clear
+hide_title: true
+sidebar_label: clear
+---
+
+# `clear(toNull = false)`
+**create.clear**
+**create(actionType).clear**
+*Appropriate leaf state: any*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, clears the leaf's state.
+
+If `toNull === true`, then it updates it to `null`, otherwise it follows the type of the leaf's state:
+- *number* clears to `0`
+- *string* clears to `''`
+- *boolean* clears to `false`
+- *array* clears to `[]`
+- *object* clears to `{}`
+
+## Parameters
+- `toNull` *(boolean, optional)*: defaults to `false`
+
+## Returns
+`action` *(object)*: an object to dispatch to the `store`
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ bool: true,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3]
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+### Boolean state
+```js
+const clearBool = actions.bool.create.clear
+
+store.dispatch(clearBool())
+console.log(store.getState().bool) // false
+
+store.dispatch(clearBool(true))
+console.log(store.getState().bool) // null
+```
+### Number state
+```js
+const clearNum = actions.num.create.clear
+
+store.dispatch(clearNum())
+console.log(store.getState().num) // 0
+
+store.dispatch(clearNum(true))
+console.log(store.getState().num) // null
+```
+### String state
+```js
+const clearStr = actions.str.create.clear
+
+store.dispatch(clearStr())
+console.log(store.getState().str) // ''
+
+store.dispatch(clearStr(true))
+console.log(store.getState().str) // null
+```
+### Array state
+```js
+const clearArr = actions.arr.create.clear
+
+store.dispatch(clearArr())
+console.log(store.getState().arr) // []
+
+store.dispatch(clearArr(true))
+console.log(store.getState().arr) // null
+```
+### Object state
+```js
+const clearState = actions.create.clear
+
+store.dispatch(clearState())
+console.log(store.getState()) // {}
+
+store.dispatch(clearState(true))
+console.log(store.getState()) // null
+```
\ No newline at end of file
diff --git a/docs/defaults/clear.spec.js b/docs/defaults/clear.spec.js
new file mode 100644
index 00000000..5fc2bf87
--- /dev/null
+++ b/docs/defaults/clear.spec.js
@@ -0,0 +1,84 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.clear(toNull = false): returns an action that, when dispatched, clear's the leaf's state", () => {
+ const initialState = {
+ bool: true,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3]
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ describe('Boolean state', () => {
+ const clearBool = actions.bool.create.clear
+
+ it('Clears to false', () => {
+ store.dispatch(clearBool())
+ expect(store.getState().bool).toBe(false)
+ })
+
+ it('Clears to null if passed true', () => {
+ store.dispatch(clearBool(true))
+ expect(store.getState().bool).toBe(null)
+ })
+ })
+
+ describe('Number state', () => {
+ const clearNum = actions.num.create.clear
+
+ it('Clears to 0', () => {
+ store.dispatch(clearNum())
+ expect(store.getState().num).toBe(0)
+ })
+
+ it('Clears to null if passed true', () => {
+ store.dispatch(clearNum(true))
+ expect(store.getState().num).toBe(null)
+ })
+ })
+
+ describe('String state', () => {
+ const clearStr = actions.str.create.clear
+
+ it("Clears to ''", () => {
+ store.dispatch(clearStr())
+ expect(store.getState().str).toBe('')
+ })
+
+ it('Clears to null if passed true', () => {
+ store.dispatch(clearStr(true))
+ expect(store.getState().str).toBe(null)
+ })
+ })
+
+ describe('Array state', () => {
+ const clearArr = actions.arr.create.clear
+
+ it("Clears to []", () => {
+ store.dispatch(clearArr())
+ expect(store.getState().arr).toEqual([])
+ })
+
+ it('Clears to null if passed true', () => {
+ store.dispatch(clearArr(true))
+ expect(store.getState().arr).toBe(null)
+ })
+ })
+
+ describe('Object state', () => {
+ const clearState = actions.create.clear
+
+ it("Clears to []", () => {
+ store.dispatch(clearState())
+ expect(store.getState()).toEqual({})
+ })
+
+ it('Clears to null if passed true', () => {
+ store.dispatch(clearState(true))
+ expect(store.getState()).toBe(null)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/concat.md b/docs/defaults/concat.md
new file mode 100644
index 00000000..ca656ecc
--- /dev/null
+++ b/docs/defaults/concat.md
@@ -0,0 +1,47 @@
+---
+id: concat
+title: concat
+hide_title: true
+sidebar_label: concat
+---
+
+# `concat(arrayOrString)`
+**`create.concat`**
+**`create(actionType).concat`**
+*Appropriate leaf state: array | string*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state by concatening it with `arrayOrString`.
+
+## Parameters
+- `arrayOrString` *(array | string)*: the array to concatenate
+
+## Returns
+`action` *(object)*: an object to dispatch to the `store`
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ arr: [1, 2, 3],
+ str: 'foo'
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Concatenating an array
+```js
+const concatToArr = actions.arr.create.concat
+store.dispatch(concatToArr(['a', 'b', 'c']))
+console.log(store.getState().arr) // [1, 2, 3, 'a', 'b', 'c']
+```
+
+### Concatenating a string
+```js
+const concatToStr = actions.str.create.concat
+store.dispatch(concatToStr('bar'))
+console.log(store.getState().str) // 'foobar'
+```
diff --git a/docs/defaults/concat.spec.js b/docs/defaults/concat.spec.js
new file mode 100644
index 00000000..4e46c6f3
--- /dev/null
+++ b/docs/defaults/concat.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.concat(array): returns an action that, when dispatched, updates the leaf's state by non-mutatively concatenating it with array", () => {
+ const initialState = {
+ arr: [1, 2, 3],
+ str: 'foo'
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Concatenating an array', () => {
+ const concatToArr = actions.arr.create.concat
+ store.dispatch(concatToArr(['a', 'b', 'c']))
+ expect(store.getState().arr).toEqual([1, 2, 3, 'a', 'b', 'c'])
+ })
+
+ test('Concatenating a string', () => {
+ const concatToStr = actions.str.create.concat
+ store.dispatch(concatToStr('bar'))
+ expect(store.getState().str).toBe('foobar')
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/drop.md b/docs/defaults/drop.md
new file mode 100644
index 00000000..080a8d86
--- /dev/null
+++ b/docs/defaults/drop.md
@@ -0,0 +1,46 @@
+---
+id: drop
+title: drop
+hide_title: true
+sidebar_label: drop
+---
+
+# `drop([n = 1])`
+**`create.drop`**
+**`create(actionType).drop**
+*Appropriate leaf state: array*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, drops the first `n` elements from the leaf's state.
+
+## Parameters
+- `n` *(number, optional)*: the number of elements to drop
+
+## Returns
+`action` *(object)*: an object to dispatch to the `store`
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: ['a', 'b', 'c'],
+ bar: ['a', 'b', 'c']
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+### No argument provided
+```js
+const dropFromFoo = actions.foo.create.drop
+store.dispatch(dropFromFoo())
+console.log(store.getState().foo) // ['b', 'c']
+```
+
+### Providing an argument
+```js
+const dropFromBar = actions.bar.create.drop
+store.dispatch(dropFromBar(2))
+console.log(store.getState().bar) // ['c']
+```
\ No newline at end of file
diff --git a/docs/defaults/drop.spec.js b/docs/defaults/drop.spec.js
new file mode 100644
index 00000000..ca3776bb
--- /dev/null
+++ b/docs/defaults/drop.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.drop(n = 1): returns an action that, when dispatched, updates the leaf's state by non-mutatively dropping the first n values", () => {
+ const initialState = {
+ foo: ['a', 'b', 'c'],
+ bar: ['a', 'b', 'c']
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("No argument provided", () => {
+ const dropFromFoo = actions.foo.create.drop
+ store.dispatch(dropFromFoo())
+ expect(store.getState().foo).toEqual(['b', 'c'])
+ })
+
+ test("Providing an argument", () => {
+ const dropFromBar = actions.bar.create.drop
+ store.dispatch(dropFromBar(2))
+ expect(store.getState().bar).toEqual(['c'])
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/filter.md b/docs/defaults/filter.md
new file mode 100644
index 00000000..d991d60b
--- /dev/null
+++ b/docs/defaults/filter.md
@@ -0,0 +1,49 @@
+---
+id: filter
+title: filter
+hide_title: true
+sidebar_label: filter
+---
+
+# `filter(callback)`
+**`create.filter`**
+**`create(actionType).filter`**
+*Appropriate leaf state: array*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state by selecting elements that return true when passed to `callback`.
+
+(Effectively, this uses the vanilla javascript [`Array.prototype.filter(callback)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) API.)
+
+## Parameters
+- `callback` *(function)*: the callback function to test each element with
+
+## Returns
+`action` *(object)*: an object to dispatch to the `store`
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: [1, 2, 3, 4, 5],
+ bar: ['cat', 'dog', 'bat']
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling create.filter
+```js
+const filterFoo = actions.foo.create.filter
+store.dispatch(filterFoo(e => !(e % 2)))
+console.log(store.getState().foo) // [2, 4]
+```
+
+### Calling create(actionType).filter
+```js
+const filterBar = actions.bar.create('FILTER_BAR').filter
+store.dispatch(filterBar(e => e.includes('at')))
+console.log(store.getState().bar) // ['cat', 'bat']
+```
\ No newline at end of file
diff --git a/docs/defaults/filter.spec.js b/docs/defaults/filter.spec.js
new file mode 100644
index 00000000..1c782088
--- /dev/null
+++ b/docs/defaults/filter.spec.js
@@ -0,0 +1,26 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.filter(callback): returns an action that, when dispatched, updates the leaf's state by filtering it with the callback", () => {
+ const initialState = {
+ foo: [1, 2, 3, 4, 5],
+ bar: ['cat', 'dog', 'bat']
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Calling create.filter', () => {
+ const filterFoo = actions.foo.create.filter
+ store.dispatch(filterFoo(e => !(e % 2)))
+ expect(store.getState().foo).toEqual([2, 4])
+ })
+
+ test('Calling create(actionType).filter', () => {
+ const filterBar = actions.bar.create('FILTER_BAR').filter
+ store.dispatch(filterBar(e => e.includes('at')))
+ expect(store.getState().bar).toEqual(['cat', 'bat'])
+ })
+
+
+})
\ No newline at end of file
diff --git a/docs/defaults/increment.md b/docs/defaults/increment.md
new file mode 100644
index 00000000..c72169c3
--- /dev/null
+++ b/docs/defaults/increment.md
@@ -0,0 +1,45 @@
+---
+id: increment
+title: increment
+hide_title: true
+sidebar_label: increment
+---
+
+# `increment([n = 1])`
+**`create.increment`**
+**`create(actionType).increment`**
+*Appropriate leaf state: number*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, increments leaf's state by `n`.
+
+## Parameters
+- `n` *(number, optional)*: the number to increment the leaf's state by, defaulting to 1
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: 5,
+ bar: 5
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+### No argument provided
+```js
+const incrementFoo = actions.foo.create.increment
+store.dispatch(incrementFoo())
+console.log(store.getState().foo) // 6
+```
+### Providing an argument
+```js
+const incrementBar = actions.bar.create.increment
+store.dispatch(incrementBar(37))
+console.log(store.getState().bar) // 42
+```
\ No newline at end of file
diff --git a/docs/defaults/increment.spec.js b/docs/defaults/increment.spec.js
new file mode 100644
index 00000000..111cea88
--- /dev/null
+++ b/docs/defaults/increment.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.increment(n = 1): returns an action that, when dispatched, updates the leaf's state by non-mutatively incrementing it by n", () => {
+ const initialState = {
+ foo: 5,
+ bar: 5
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("No argument provided", () => {
+ const incrementFoo = actions.foo.create.increment
+ store.dispatch(incrementFoo())
+ expect(store.getState().foo).toBe(6)
+ })
+
+ test("Providing an argument", () => {
+ const incrementBar = actions.bar.create.increment
+ store.dispatch(incrementBar(37))
+ expect(store.getState().bar).toBe(42)
+ })
+})
diff --git a/docs/defaults/off.md b/docs/defaults/off.md
new file mode 100644
index 00000000..8783c6fe
--- /dev/null
+++ b/docs/defaults/off.md
@@ -0,0 +1,44 @@
+---
+id: off
+title: off
+hide_title: true
+sidebar_label: off
+---
+
+# `off()`
+**`create.off`**
+**`create(actionType).off`**
+*Appropriate leaf state: boolean*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `false`.
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: true,
+ bar: true
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling `create.off`
+```js
+const turnOffFoo = actions.foo.create.off
+store.dispatch(turnOffFoo())
+console.log(store.getState().foo) // false
+```
+
+### Calling `create(actionType).off`
+```js
+const turnOffBar = actions.bar.create('TURN_OFF_BAR').off
+store.dispatch(turnOffBar())
+console.log(store.getState().bar) // false
+```
\ No newline at end of file
diff --git a/docs/defaults/off.spec.js b/docs/defaults/off.spec.js
new file mode 100644
index 00000000..7e6e99e1
--- /dev/null
+++ b/docs/defaults/off.spec.js
@@ -0,0 +1,27 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.off(): returns an action that, when dispatched, updates the leaf's state to false", () => {
+
+ describe("GIVEN initialState is an object", () => {
+ const initialState = {
+ foo: true,
+ bar: true
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Calling create.off', () => {
+ const turnOffFoo = actions.foo.create.off
+ store.dispatch(turnOffFoo())
+ expect(store.getState().foo).toBe(false)
+ })
+
+ test('Calling create(actionType).off', () => {
+ const turnOffBar = actions.bar.create("TURN_OFF_BAR").off
+ store.dispatch(turnOffBar())
+ expect(store.getState().bar).toBe(false)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/on.md b/docs/defaults/on.md
new file mode 100644
index 00000000..6eeece28
--- /dev/null
+++ b/docs/defaults/on.md
@@ -0,0 +1,44 @@
+---
+id: on
+title: on
+hide_title: true
+sidebar_label: on
+---
+
+# `on()`
+**`create.on`**
+**`create(actionType).on`**
+*Appropriate leaf state: boolean*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `true`.
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: false,
+ bar: false
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling `create.on`
+```js
+const turnOffFoo = actions.foo.create.on
+store.dispatch(turnOffFoo())
+console.log(store.getState().foo) // true
+```
+
+### Calling `create(actionType).on`
+```js
+const turnOffBar = actions.bar.create('TURN_ON_BAR').on
+store.dispatch(turnOffBar())
+console.log(store.getState().bar) // ture
+```
\ No newline at end of file
diff --git a/docs/defaults/on.spec.js b/docs/defaults/on.spec.js
new file mode 100644
index 00000000..1bfffee3
--- /dev/null
+++ b/docs/defaults/on.spec.js
@@ -0,0 +1,27 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.createon(): returns an action that, when dispatched, updates the leaf's state to false", () => {
+
+ describe("GIVEN initialState is an object", () => {
+ const initialState = {
+ foo: false,
+ bar: false
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Calling create.on', () => {
+ const turnOnFoo = actions.foo.create.on
+ store.dispatch(turnOnFoo())
+ expect(store.getState().foo).toBe(true)
+ })
+
+ test('Calling create(actionType).on', () => {
+ const turnOnBar = actions.bar.create("TURN_ON_BAR").on
+ store.dispatch(turnOnBar())
+ expect(store.getState().bar).toBe(true)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/path.md b/docs/defaults/path.md
new file mode 100644
index 00000000..df98dc62
--- /dev/null
+++ b/docs/defaults/path.md
@@ -0,0 +1,48 @@
+---
+id: path
+title: path
+hide_title: true
+sidebar_label: path
+---
+
+# `path(path, value)`
+**`create.path`**
+**`create(actionType).path`**
+*Appropriate leaf type: object*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, sets a property at `path` as `value`.
+
+## Parameters
+- `path` *(string[])*: the property path to set at
+- `value` *(any)*: the value to set
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: {}
+ bar: { arbitrary: { keys: 3 } }
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Setting a new property
+```js
+const setAtPathInFoo = actions.foo.create.path
+store.dispatch(setAtPathInFoo(['nested', 'deep'], true))
+console.log(store.getState().foo) // { nested: { deep: true } }
+
+```
+### Overwriting a property
+```js
+const setAtPathInBar = actions.bar.create("SET_AT_PATH_IN_BAR").path
+store.dispatch(setAtPathInBar(['arbitrary', 'keys'], 5))
+console.log(store.getState().bar) // { arbitrary: { keys: 5 } }
+```
\ No newline at end of file
diff --git a/docs/defaults/path.spec.js b/docs/defaults/path.spec.js
new file mode 100644
index 00000000..a5a27626
--- /dev/null
+++ b/docs/defaults/path.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.path(path, value): returns an action that, when dispatched, updates the leaf's state by setting a proprety at path as value", () => {
+ const initialState = {
+ foo: {},
+ bar: {}
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Setting a new property", () => {
+ const setAtPathInFoo = actions.foo.create.path
+ store.dispatch(setAtPathInFoo(['nested', 'deep'], true))
+ expect(store.getState().foo).toEqual({ nested: { deep: true } })
+ })
+
+ test("Overwriting a property", () => {
+ const setAtPathInBar = actions.bar.create.path
+ store.dispatch(setAtPathInBar(['arbitrary', 'keys'], 5))
+ expect(store.getState().bar).toEqual({ arbitrary: { keys: 5 }})
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/push.md b/docs/defaults/push.md
new file mode 100644
index 00000000..da8400cb
--- /dev/null
+++ b/docs/defaults/push.md
@@ -0,0 +1,54 @@
+---
+id: push
+title: push
+hide_title: true
+sidebar_label: push
+---
+
+# `push(element, [index = -1], [replace = false])`
+**`create.push`**
+**`create(actionType).push`**
+*Appropriate leaf type: array*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, non-mutatively pushes `element` to the leaf's state at index `index`. If `replace` is `true`, then `element` replaces the existing element with that index.
+
+## Parameters
+- `element` *(any)*: the element to insert to the leaf's state
+- `index` *(integer, optional)*: the index of the array where `element` should be inserted
+- `replace` *(boolean, optional)*: whether or not `element` should replace the current `index`th element
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: [1, 2, 3],
+ bar: [1, 2, 3],
+ foobar: [1, 2, 3]
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+### Providing element
+```js
+const pushToFoo = actions.foo.create.push
+store.dispatch(pushToFoo(4))
+console.log(store.getState().foo) // [1, 2, 3, 4]
+```
+### Providing element and index
+```js
+const pushToBar = actions.bar.create.push
+store.dispatch(pushToBar(4, 0)) // push 4 to have index 0
+console.log(store.getState().bar) // [4, 1, 2, 3]
+```
+### Providing element, index and replace
+```js
+const pushToFoobar = actions.foobar.create.push
+store.dispatch(pushToFoobar(4, 0, true)) // replace 0th element with 4
+console.log(store.getState().foobar) // [4, 2, 3]
+```
\ No newline at end of file
diff --git a/docs/defaults/push.spec.js b/docs/defaults/push.spec.js
new file mode 100644
index 00000000..1396ea4f
--- /dev/null
+++ b/docs/defaults/push.spec.js
@@ -0,0 +1,31 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.push(element, [index = -1], [replace = false]): returns an action that, when dispatched, updates the leaf's state by non-mutatively pushing element into leaf's state at index. If replace === true, then element replaces the existing element with that index.", () => {
+ const initialState = {
+ foo: [1, 2, 3],
+ bar: [1, 2, 3],
+ foobar: [1, 2, 3]
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Providing element", () => {
+ const pushToFoo = actions.foo.create.push
+ store.dispatch(pushToFoo(4))
+ expect(store.getState().foo).toEqual([1, 2, 3, 4])
+ })
+
+ test("Providing element and index", () => {
+ const pushToBar = actions.bar.create.push
+ store.dispatch(pushToBar(4, 0))
+ expect(store.getState().bar).toEqual([4, 1, 2, 3])
+ })
+
+ test("Providing element, index and replace", () => {
+ const pushToFoobar = actions.foobar.create.push
+ store.dispatch(pushToFoobar(4, 0, true))
+ expect(store.getState().foobar).toEqual([4, 2, 3])
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/reset.md b/docs/defaults/reset.md
new file mode 100644
index 00000000..66c5e75d
--- /dev/null
+++ b/docs/defaults/reset.md
@@ -0,0 +1,66 @@
+---
+id: reset
+title: reset
+hide_title: true
+sidebar_label: reset
+---
+
+# `reset()`
+**`create.reset`**
+**`create(actionType).reset`**
+*Appropriate leaf state: any*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, resets the leaf's state to its initial state stored in the actions.
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ num: 2,
+ arr: [1, 2, 3],
+ bool: true
+}
+
+const otherState = {
+ num: 11,
+ arr: ['a', 'b', 'c'],
+ bool: false
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer, otherState) // preloads otherState
+
+/* store.getState()
+* {
+* num: 11,
+* arr: ['a', 'b', 'c']
+* }
+*/
+
+```
+
+### Calling `create.reset` on a leaf:
+```js
+const resetNum = actions.num.create.reset
+store.dispatch(resetNum())
+console.log(store.getState().num) // 2
+```
+
+### Calling `create(actionType).reset` on a leaf:
+```js
+const resetBool = actions.bool.create.reset
+store.dispatch(resetBool())
+console.log(store.getState().bool) // true
+```
+
+### Calling `create.reset` on a branch:
+```js
+const resetState = actions.create.reset
+store.dispatch(resetState())
+console.log(store.getState()) // { num: 2, arr: [1, 2, 3], bool: true }
+```
diff --git a/docs/defaults/reset.spec.js b/docs/defaults/reset.spec.js
new file mode 100644
index 00000000..19dbcd5d
--- /dev/null
+++ b/docs/defaults/reset.spec.js
@@ -0,0 +1,46 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.reset(): returns an action that, when dispatched, updates the leaf's state to the reducer's initialised state", () => {
+ const initialState = {
+ num: 2,
+ arr: [1, 2, 3],
+ bool: true
+ }
+
+ const otherState = {
+ num: 11,
+ arr: ['a', 'b', 'c'],
+ bool: false
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer, otherState)
+
+ test("State is the preloaded state", () => {
+ expect(store.getState()).toEqual(otherState)
+ })
+
+ test("Calling create.reset on a leaf", () => {
+ const resetNum = actions.num.create.reset
+ store.dispatch(resetNum())
+ expect(store.getState().num).toBe(2)
+ })
+
+ test("Calling create(actionType).reset on a leaf", () => {
+ const resetBool = actions.bool.create.reset
+ store.dispatch(resetBool())
+ expect(store.getState().bool).toBe(true)
+ })
+
+
+ test("Calling create.reset on a branch", () => {
+ const resetState = actions.create.reset
+ store.dispatch(resetState())
+ expect(store.getState()).toEqual({
+ num: 2,
+ arr: [1, 2, 3],
+ bool: true
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/set.md b/docs/defaults/set.md
new file mode 100644
index 00000000..f44d15eb
--- /dev/null
+++ b/docs/defaults/set.md
@@ -0,0 +1,48 @@
+---
+id: set
+title: set
+hide_title: true
+sidebar_label: set
+---
+
+# `set(key, value)`
+**`create.set`**
+**`create(actionType).set`**
+*Appropriate leaf type: object*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state at the property `key` with `value`.
+
+## Parameters
+- `key` *(string)*: the path of the property to set
+- `value` *(any)*: the value to set
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: {},
+ bar: { props: true }
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Setting a new property
+```js
+const setInFoo = actions.foo.create.set
+store.dispatch(setInFoo('accessed', true))
+console.log(store.getState().foo) // { accessed: true }
+```
+
+### Overwriting a property
+```js
+const setInBar = actions.bar.create.set
+store.dispatch(setInBar('props', false))
+console.log(store.getState().bar) // { props: false }
+```
\ No newline at end of file
diff --git a/docs/defaults/set.spec.js b/docs/defaults/set.spec.js
new file mode 100644
index 00000000..2118937b
--- /dev/null
+++ b/docs/defaults/set.spec.js
@@ -0,0 +1,24 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.set(path, value): returns an action that, when dispatched, updates the leaf's state by non-mutatively setting value at state object's path", () => {
+ const initialState = {
+ foo: {},
+ bar: { props: true }
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Setting a new property", () => {
+ const setInFoo = actions.foo.create.set
+ store.dispatch(setInFoo('accessed', true))
+ expect(store.getState().foo).toEqual({ accessed: true })
+ })
+
+ test("Overwriting a property", () => {
+ const setInBar = actions.bar.create.set
+ store.dispatch(setInBar('props', false))
+ expect(store.getState().bar).toEqual({ props: false })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/toggle.md b/docs/defaults/toggle.md
new file mode 100644
index 00000000..18199bc2
--- /dev/null
+++ b/docs/defaults/toggle.md
@@ -0,0 +1,44 @@
+---
+id: toggle
+title: toggle
+hide_title: true
+sidebar_label: toggle
+---
+
+# `toggle()`
+**`create.toggle`**
+**`create(actionType).toggle`**
+*Appropriate leaf state: boolean*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `!leafState`.
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ foo: true,
+ bar: false
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling `create.toggle`
+```js
+const toggleFoo = actions.foo.create.toggle
+store.dispatch(toggleFoo())
+console.log(store.getState().foo) // false
+```
+
+### Calling `create(actionType).toggle`
+```js
+const toggleBar = actions.bar.create('TOGGLE_BAR').toggle
+store.dispatch(toggleBar())
+console.log(store.getState().bar) // true
+```
\ No newline at end of file
diff --git a/docs/defaults/toggle.spec.js b/docs/defaults/toggle.spec.js
new file mode 100644
index 00000000..768c8f05
--- /dev/null
+++ b/docs/defaults/toggle.spec.js
@@ -0,0 +1,27 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.toggle(): returns an action that, when dispatched, updates the leaf's state to false", () => {
+
+ describe("GIVEN initialState is an object", () => {
+ const initialState = {
+ foo: true,
+ bar: false
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Calling create.toggle', () => {
+ const turnOnFoo = actions.foo.create.toggle
+ store.dispatch(turnOnFoo())
+ expect(store.getState().foo).toBe(false)
+ })
+
+ test('Calling create(actionType).toggle', () => {
+ const turnOnBar = actions.bar.create("TURN_ON_BAR").toggle
+ store.dispatch(turnOnBar())
+ expect(store.getState().bar).toBe(true)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/defaults/update.md b/docs/defaults/update.md
new file mode 100644
index 00000000..bb9e5e9a
--- /dev/null
+++ b/docs/defaults/update.md
@@ -0,0 +1,58 @@
+---
+id: update
+title: update
+hide_title: true
+sidebar_label: update
+---
+
+# `update(value)`
+**`create.update`**
+**`create(actionType).update`**
+*Appropriate leaf state: any*
+
+Returns an object that, *when dispatched to a store created with the original state tree*, updates the leaf's state to `value`.
+
+## Parameters
+- `value` *(any)*: the new value for the leaf's state
+
+## Returns
+`action` *(object)*: an object to dispatch to the store
+
+## Example
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'reduxLeaves'
+
+const initialState = {
+ bool: false,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3]
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Calling `create.update` on a leaf:
+
+```js
+const updateStr = actions.str.create.update
+store.dispatch(updateStr("I can put anything here"))
+console.log(store.getState().str) // 'I can put anything here'
+```
+
+### Calling `create(actionType).update` on a leaf:
+
+```js
+const updateNum = actions.num.create('UPDATE_NUM').update
+store.dispatch(updateNum(9001))
+console.log(store.getState().num) // 9001
+```
+
+### Calling `create.update` on a branch:
+```js
+const updateState = actions.create.update
+store.dispatch(updateState({ any: { properties: true }}))
+console.log(store.getState()) // { any: { properties: true } }
+```
\ No newline at end of file
diff --git a/docs/defaults/update.spec.js b/docs/defaults/update.spec.js
new file mode 100644
index 00000000..a8d3857c
--- /dev/null
+++ b/docs/defaults/update.spec.js
@@ -0,0 +1,33 @@
+import { createStore } from "redux";
+import reduxLeaves from '../../src';
+
+describe("leaf.create.update(value): returns an action that, when dispatched, updates the leaf's state to value", () => {
+
+ const initialState = {
+ bool: false,
+ num: 2,
+ str: 'foo',
+ arr: [1, 2, 3]
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test('Calling create.update on a leaf', () => {
+ const updateStr = actions.str.create.update
+ store.dispatch(updateStr("I can put anything here"))
+ expect(store.getState().str).toBe('I can put anything here')
+ })
+
+ test('Calling create(actionType).update on a leaf', () => {
+ const updateNum = actions.num.create('UPDATE_NUM').update
+ store.dispatch(updateNum(9001))
+ expect(store.getState().num).toBe(9001)
+ })
+
+ test('Calling create.update on a branch', () => {
+ const updateState = actions.create.update
+ store.dispatch(updateState({ any: { properties: true } }))
+ expect(store.getState()).toEqual({ any: { properties: true } })
+ })
+})
\ No newline at end of file
diff --git a/docs/examples/advancedExample.md b/docs/examples/advancedExample.md
new file mode 100644
index 00000000..0ff78899
--- /dev/null
+++ b/docs/examples/advancedExample.md
@@ -0,0 +1,119 @@
+---
+id: advanced-example
+title: Advanced example
+hide_title: true
+sidebar_label: Advanced example
+---
+
+# Advanced example: custom types and controlling payloads
+
+## Custom action types
+
+### Default action types
+When you create an action through Redux-Leaves - whether using a default creator or some custom reducer logic you've supplied - it gives the action an informative `type` property:
+
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ list: ['a', 'b'],
+ nested: {
+ counter: 0,
+ state: {
+ deep: 'somewhat'
+ }
+ }
+}
+
+const reducersDict = {
+ duplicate: leafState => leafState.concat(leafState)
+}
+
+const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+
+const actionToPushToList = actions.list.create.push('c')
+console.log(actionToPushToList.type) // 'list/PUSH'
+
+const actionToDuplicateList = actions.list.create.duplicate()
+console.log(actionToDuplicateList.type) // 'list/DUPLICATE'
+
+const actionToUpdateDeepState = actions.nested.state.deep.create.update('could go deeper')
+console.log(actionToUpdateDeepState.payload)
+// 'nested/state/deep/UPDATE'
+```
+
+### Overriding the default action type
+You may find benefits, e.g. with Redux DevTools, to overriding the default action type.
+
+You can do this by providing a string argument to `create`:
+
+```js
+const appendLetter = actions.list.create('APPEND_LETTER').push
+console.log(appendLetter('c').type) // 'APPEND_LETTER'
+
+const duplicateList = actions.list.create('DUPLICATE_LIST').duplicate
+console.log(duplicateList().type) // 'DUPLICATE LIST'
+```
+
+Overriding the default action type won't change how the Redux-Leaves `reducer` responds to the action:
+```js
+const store = createStore(reducer)
+console.log(store.getState().list) // ['a', 'b']
+
+store.dispatch(appendLetter('c'))
+console.log(store.getState().list) // ['a', 'b', 'c']
+
+store.dispatch(duplicateList())
+console.log(store.getState().list)
+// ['a', 'b', 'c', 'a', 'b', 'c']
+```
+
+### Usage pattern
+An expected pattern that this facilitates is the defining of action creators in one file, e.g. `actions.js`:
+```js
+// import the actions object created by Redux-Leaves
+import { actions } from './some/location'
+
+export const incrementCounter = actions.counter.create('INCREMENT_COUNTER').increment
+export const updateDeepState = actions.nested.state.deep.create('UPDATE_DEEP_STATE').update
+```
+and then import these action creators into whichever file needs access to them.
+
+## Controlling payloads
+Suppose I want to create a custom creator, `addMultiple`, such that I can pass multiple numbers as arguments and have them all added to a given leaf's state.
+
+The default behaviour of a custom action creator is that only the first argument is passed as an action's payload, but we can configure that:
+
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ counter: 0
+}
+
+const reducersDict = {
+ // object configuration longhand
+ addMultiple: {
+ // Capture all arguments and pass them to the reducer:
+ argsToPayload: (...args) => args,
+ reducer: (leafState, { payload }) => payload.reduce((acc, val) => acc + val, leafState)
+ },
+
+ // function shorthand
+ // uses default payload behaviour
+ addFirstThing: (leafState, { payload }) => leafState + payload
+}
+
+const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+const store = createStore(reducer)
+
+console.log(store.getState().counter) // 0
+
+store.dispatch(actions.counter.create.addMultiple(4, 2, 10))
+console.log(store.getState().counter) // 16
+
+store.dispatch(actions.counter.create.addFirstThing(1, 100))
+console.log(store.getState().counter) // 17
+```
\ No newline at end of file
diff --git a/docs/examples/advancedExample.spec.js b/docs/examples/advancedExample.spec.js
new file mode 100644
index 00000000..e845ad5d
--- /dev/null
+++ b/docs/examples/advancedExample.spec.js
@@ -0,0 +1,84 @@
+import { createStore } from 'redux';
+import reduxLeaves from '../../src';
+
+
+describe('Advanced example', () => {
+ describe('Custom types', () => {
+ const initialState = {
+ list: ['a', 'b'],
+ nested: {
+ counter: 0,
+ state: {
+ deep: 'somewhat'
+ }
+ }
+ }
+
+ const reducersDict = {
+ duplicate: leafState => leafState.concat(leafState)
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+
+ it('Creates informative action types by default', () => {
+ const actionToPushToList = actions.list.create.push('c')
+ expect(actionToPushToList.type).toBe('list/PUSH')
+
+ const actionToDuplicateList = actions.list.create.duplicate()
+ expect(actionToDuplicateList.type).toBe('list/DUPLICATE')
+
+ const actionToUpdateDeepState = actions.nested.state.deep.create.update('could go deeper')
+ expect(actionToUpdateDeepState.type).toBe('nested/state/deep/UPDATE')
+ })
+
+ test('You can override the default action type', () => {
+ const appendLetter = actions.list.create('APPEND_LETTER').push
+ expect(appendLetter('c').type).toBe('APPEND_LETTER')
+
+ const duplicateList = actions.list.create('DUPLICATE_LIST').duplicate
+ expect(duplicateList().type).toBe('DUPLICATE_LIST')
+ })
+
+ test("Overriding action type doesn't change how the reducer responds", () => {
+ const store = createStore(reducer)
+ expect(store.getState().list).toEqual(['a', 'b'])
+
+ store.dispatch(actions.list.create('APPEND_LETTER').push('c'))
+ expect(store.getState().list).toEqual(['a', 'b', 'c'])
+
+ store.dispatch(actions.list.create('DUPLICATE_LIST').duplicate())
+ expect(store.getState().list).toEqual(['a', 'b', 'c', 'a', 'b', 'c'])
+ })
+ })
+
+ describe('Controlling payloads', () => {
+ const initialState = {
+ counter: 0
+ }
+
+ const reducersDict = {
+ addMultiple: {
+ argsToPayload: (...args) => args,
+ reducer: (leafState, { payload }) => payload.reduce((acc, val) => acc + val, leafState)
+ },
+ addFirstThing: (leafState, { payload }) => leafState + payload
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+ const store = createStore(reducer)
+
+ test('We can configure to use custom argsToPayload', () => {
+ expect(store.getState().counter).toBe(0)
+
+ store.dispatch(actions.counter.create.addMultiple(4, 2, 10))
+ expect(store.getState().counter).toBe(16)
+ })
+
+ test("If we don't configure, it uses only the first argument as payload", () => {
+ expect(store.getState().counter).toBe(16)
+
+ store.dispatch(actions.counter.create.addFirstThing(1, 100))
+ expect(store.getState().counter).toBe(17)
+ })
+ })
+})
\ No newline at end of file
diff --git a/docs/examples/basicExample.md b/docs/examples/basicExample.md
new file mode 100644
index 00000000..f2f713b3
--- /dev/null
+++ b/docs/examples/basicExample.md
@@ -0,0 +1,122 @@
+---
+id: basic-example
+title: Basic example
+hide_title: true
+sidebar_label: Basic example
+---
+
+# Basic example: 30 second demo
+
+**Situation**: I want to be able to increment two different counters in Redux state, `counterOne` and `counterTwo`.
+**Complication**: I want to do this as quickly, painlessly and intuitively as possible.
+**Question**: Do I really have to define reducers, action types and creators to do this?
+
+Answer: no! Just provide Redux-Leaves with your state shape, i.e. the two counters, and it'll do the rest for you!
+
+## Demonstration
+
+### Set up the store's state
+```js
+// Imports for Redux and Redux-Leaves
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+// Your job: provide some initial state
+const initialState = {
+ counterOne: 0,
+ counterTwo: 0
+}
+
+// Redux-Leaves's job: to write your reducer and actions for you
+const [reducer, actions] = reduxLeaves(initialState)
+
+// Create your Redux store using the given reducer
+const store = createStore(reducer)
+```
+
+### Update the store's state
+```js
+console.log(store.getState()) // { counterOne: 0, counterTwo: 0 }
+
+// Let's create an action to increment counterOne by 3
+const actionToIncrementCounterOneByThree = actions.counterOne.create.increment(3)
+
+// Dispatch our created action to the store
+store.dispatch(actionToIncrementCounterOneByThree)
+
+// The store's state will be updated!
+console.log(store.getState()) // { counterOne: 3, counterTwo: 0 }
+
+// Now let's increment counterTwo by 10
+store.dispatch(actions.counterTwo.create.increment(10))
+console.log(store.getState()) // { counterOne: 3, counterTwo: 10 }
+```
+
+## Default action creators
+`increment` is one of many default action creators that Redux-Leaves writes for you.
+
+If you want to add some custom action creators, look at the [intermediate example](intermediateExample.md).
+
+Here are some other common defaults that you might like to use:
+
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ arr: [3, 'things', 'here'],
+ bool: false,
+ obj: {
+ nested: true
+ }
+ title: 'Redux-Leaves',
+}
+
+const [reducer, actions] = reduxLeaves(initialState)
+const store = createStore(reducer)
+```
+
+### Arrays
+```js
+// push: push an element to an array
+store.dispatch(actions.arr.create.push('new element'))
+console.log(store.getState().arr) // [3, 'things', 'here', 'new element']
+
+// drop: drop n elements from an array
+store.dispatch(actions.arr.create.drop(2))
+console.log(store.getState().arr) // [3, 'things']
+```
+
+### Booleans
+```js
+// toggle: toggles a boolean
+store.dispatch(actions.bool.create.toggle())
+console.log(store.getState().bool) // true
+
+// off: make a boolean false (or 'on' for true)
+store.dispatch(actions.bool.create.off())
+console.log(store.getState().bool) // false
+```
+
+### Plain objects
+```js
+// assign: spreads properties
+store.dispatch(actions.obj.create.assign({ deep: false }))
+console.log(store.getState().obj) // { nested: true, deep: false }
+
+// path: sets a value at a given path in the object
+store.dispatch(actions.obj.create.path(['arbitrary', 'property'], 3))
+console.log(store.getState().obj.arbitrary) // { property: 3 }
+```
+
+### Type agnostic
+```js
+// apply: updates state by applying a callback
+store.dispatch(actions.title.create.apply(str => str.toUpperCase())
+console.log(store.getState().title) // 'REDUX-LEAVES'
+
+// update: changes state to the value provided
+store.dispatch(actions.title.create.update('Redux-Leaves is GREAT'))
+console.log(store.getState().title) // 'Redux-Leaves is GREAT'
+```
+
diff --git a/docs/examples/basicExample.spec.js b/docs/examples/basicExample.spec.js
new file mode 100644
index 00000000..9a0a1951
--- /dev/null
+++ b/docs/examples/basicExample.spec.js
@@ -0,0 +1,28 @@
+import { createStore } from 'redux';
+import reduxLeaves from '../../src';
+
+
+describe('Basic example', () => {
+ const initialState = {
+ counterOne: 0,
+ counterTwo: 0
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState)
+ const store = createStore(reducer)
+
+ test("Store initialises with the provided initialState", () => {
+ expect(store.getState()).toEqual({ counterOne: 0, counterTwo: 0 })
+ })
+
+ test("We can increment counterOne by 3", () => {
+ const actionToIncrementCounterOneByThree = actions.counterOne.create.increment(3)
+ store.dispatch(actionToIncrementCounterOneByThree)
+ expect(store.getState()).toEqual({ counterOne: 3, counterTwo: 0 })
+ })
+
+ test("We can increment counterTwo by 10", () => {
+ store.dispatch(actions.counterTwo.create.increment(10))
+ expect(store.getState()).toEqual({ counterOne: 3, counterTwo: 10 })
+ })
+})
\ No newline at end of file
diff --git a/docs/examples/intermediateExample.md b/docs/examples/intermediateExample.md
new file mode 100644
index 00000000..dc0c7290
--- /dev/null
+++ b/docs/examples/intermediateExample.md
@@ -0,0 +1,67 @@
+---
+id: intermediate-example
+title: Intermediate example
+hide_title: true
+sidebar_label: Intermediate example
+---
+
+# Intermediate example: custom logic
+
+**Situation**: I want to define a general type of reducer logic that can be reused on any arbitrary slice of state.
+**Complication**: I want to do this as quickly, painlessly and intuitively as possible.
+**Question**: Do I really have to create sub-reducers with the same underlying logic?
+
+Answer: no! Just provide Redux-Leaves once with your custom reducer logic, and you can automatically use it at any leaf of your state tree.
+
+## Demonstration
+
+### Set up with your custom reducer logic
+```js
+import { createStore } from 'redux'
+import reduxLeaves from 'redux-leaves'
+
+const initialState = {
+ counter: 2,
+ list: ['first', 'second'],
+ nested: { arbitrarily: { deep: 0 } }
+}
+
+// Key your reducer logic by a descriptive verb
+const reducersDict = {
+ double: leafState => leafState * 2,
+ appendToEach: (leafState, action) => leafState.map(str => str.concat(action.payload)),
+ countTreeKeys: (leafState, action, treeState) => Object.keys(treeState).length
+}
+
+// Provide the dictionary of your reducer logic to reduxLeaves
+const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+const store = createStore(reducer)
+```
+
+### Dispatch actions at any leaf with the corresponding keys
+```js
+store.dispatch(actions.counter.create.double())
+console.log(store.getState().counter) // 4
+
+store.dispatch(actions.list.create.appendToEach(' item')) // ' item' will be the action payload
+console.log(store.getState().list) // ['first item', 'second item']
+
+store.dispatch(actions.nested.arbitrarily.deep.create.countTreeKeys())
+console.log(store.getState().nested.arbitrarily.deep) // 3
+
+// And to demonstrate reusing logic at an arbitrary leaf:
+store.dispatch(actions.nested.arbitrarily.deep.create.double())
+console.log(store.getState().nested.arbitrarily.deep) // 6
+```
+
+## Default handling of arguments
+When you supply `reduxLeaves` with custom reducer logic, it provides the corresponding action creators, e.g. `actions.list.create.appendToEach` used above.
+
+The *default behaviour* of these action creators is that, if they receive any arguments, *only the first argument* is passed to the created action as a payload:
+
+```js
+const actionToAppend = actions.list.create.appendToEach('foo', 'bar')
+console.log(actionToAppend.payload) // 'foo'
+```
+
+If you would like to customise this behaviour, look at the [advanced example](advancedExample.md).
\ No newline at end of file
diff --git a/docs/examples/intermediateExample.spec.js b/docs/examples/intermediateExample.spec.js
new file mode 100644
index 00000000..7226b518
--- /dev/null
+++ b/docs/examples/intermediateExample.spec.js
@@ -0,0 +1,49 @@
+import { createStore } from 'redux';
+import reduxLeaves from '../../src';
+
+
+describe('Intermediate example', () => {
+ const initialState = {
+ counter: 2,
+ list: ['first', 'second'],
+ nested: { arbitrarily: { deep: 0 } }
+ }
+
+ const reducersDict = {
+ double: leafState => leafState * 2,
+ appendToEach: (leafState, action) => leafState.map(str => str.concat(action.payload)),
+ countTreeKeys: (leafState, action, treeState) => Object.keys(treeState).length
+ }
+
+ const [reducer, actions] = reduxLeaves(initialState, reducersDict)
+ const store = createStore(reducer)
+
+ test("We can double the counter's state", () => {
+ expect(store.getState().counter).toBe(2)
+ store.dispatch(actions.counter.create.double())
+ expect(store.getState().counter).toBe(4)
+ })
+
+ test("We can append to the list", () => {
+ expect(store.getState().list).toEqual(['first', 'second'])
+ store.dispatch(actions.list.create.appendToEach(' item'))
+ expect(store.getState().list).toEqual(['first item', 'second item'])
+ })
+
+ test("We can count the number of keys in the state tree", () => {
+ expect(store.getState().nested.arbitrarily.deep).toBe(0)
+ store.dispatch(actions.nested.arbitrarily.deep.create.countTreeKeys())
+ expect(store.getState().nested.arbitrarily.deep).toBe(3)
+ })
+
+ test("We can double arbitrarily deep state", () => {
+ expect(store.getState().nested.arbitrarily.deep).toBe(3)
+ store.dispatch(actions.nested.arbitrarily.deep.create.double())
+ expect(store.getState().nested.arbitrarily.deep).toBe(6)
+ })
+
+ test("By default, when providing arguments, the first becomes the payload", () => {
+ const actionToAppend = actions.list.create.appendToEach('foo', 'bar')
+ expect(actionToAppend.payload).toBe('foo')
+ })
+})
\ No newline at end of file
diff --git a/docs/intro/README.md b/docs/intro/README.md
index 05859474..84c9ecee 100644
--- a/docs/intro/README.md
+++ b/docs/intro/README.md
@@ -10,7 +10,7 @@ The guiding philosophy of Redux-Leaves is *"write once, reduce anywhere"*.
This page explains more about the motivation of Redux-Leaves and how its design philosophy is put into practice.
-> **Just want to see some code? Check out the [30 second demo](demo.md) or [Code Sandbox](https://codesandbox.io/s/reduxleaves-iwc4f).**
+> **Just want to see some code? Check out the basic [30 second demo](examples/basicExample.md).**
## Motivation
diff --git a/docs/intro/demo.md b/docs/intro/demo.md
deleted file mode 100644
index a83a5f4d..00000000
--- a/docs/intro/demo.md
+++ /dev/null
@@ -1,76 +0,0 @@
----
-id: demo
-title: 30 Second Demo
-hide_title: true
-sidebar_label: 30 second demo
----
-
-# Redux-Leaves
-
-**[Write once](#write-once). [Reduce anywhere](#reduce-anywhere).**
-
-## Write once.
-
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'redux-leaves'
-
-// 1. Define initialState
-const initialState = {
- counter: 1,
- list: ['first'],
- nested: { arbitrarily: { deep: 0 } }
-}
-
-// 2. (Optional) Define custom reducers dictionary
-const reducersDict = {
- double: leafState => leafState * 2,
- appendToEach: (leafState, action) => leafState.map(str => str.concat(action.payload)),
- countKeys: (leafState, action, wholeState) => Object.keys(wholeState).length
-}
-
-// 3. Grab reducer and actions from reduxLeaves, then create the Redux store
-const [reducer, actions] = reduxLeaves(initialState, reducersDict)
-const store = createStore(reducer)
-```
-
-## Reduce anywhere.
-
-```js
-// *** KEY ***
-// Default: an action creator that ships with Redux-Leaves by default
-// Custom: an action creator generated by the custom reducersDict
-
-// Default: increment state.counter
-store.dispatch(actions.counter.create.increment())
-console.log(store.getState().counter) // 2
-
-// Custom: double state.counter
-store.dispatch(actions.counter.create.double())
-console.log(store.getState().counter) // 4
-
-// Default: push 'second' to state.list
-store.dispatch(actions.list.create.push('second'))
-console.log(store.getState().list) // ['first', 'second']
-
-// Custom: append ' item' to each element in state.list
-store.dispatch(actions.list.create.appendToEach(' item'))
-console.log(store.getState().list) // ['first item', 'second item']
-
-// Default: assign true to key 'newKey' at the top-level of state
-store.dispatch(actions.create.assign({ newKey: true }))
-console.log(store.getState().newKey) // true
-
-// Custom: update state.nested.arbitrarily.deep with state's number of top-level keys
-store.dispatch(actions.nested.arbitrarily.deep.create.countKeys())
-console.log(store.getState().nested.arbitrarily.deep) // 4
-
-console.log(store.getState())
-/*
- {
- counter: 4,
- list: ['first item', ' second item'],
- nested: { arbitrarily: { deep: 4 } }
- }
-*/
-```
diff --git a/docs/intro/demo.spec.js b/docs/intro/demo.spec.js
deleted file mode 100644
index afe5ecce..00000000
--- a/docs/intro/demo.spec.js
+++ /dev/null
@@ -1,147 +0,0 @@
-import reduxLeaves from "../../src";
-import { createStore } from "redux";
-
-describe("Redux-Leaves. Write once. Reduce anywhere.", () => {
- describe("GIVEN initialState, reducers, reducersDict, actions and initialised redux store", () => {
- const initialState = {
- counter: 1,
- list: ['first'],
- nested: { arbitrarily: { deep: 0 } }
- }
-
- const reducersDict = {
- double: leafState => leafState * 2,
- splice: {
- argsToPayload: (first, second) => [first, second],
- mutate: true,
- reducer: (leafState, { payload }) => { leafState.splice(...payload) }
- },
- appendToEach: (leafState, action) => leafState.map(str => str.concat(action.payload)),
- countKeys: (leafState, action, wholeState) => Object.keys(wholeState).length
- }
-
- const [reducer, actions] = reduxLeaves(initialState, reducersDict)
-
- let store
-
- beforeEach(() => store = createStore(reducer))
-
- test("THEN actions has defined action creators for double, appendToEach and countKeys", () => {
- [actions.counter, actions.list, actions.nested, actions.nested.arbitrarily, actions.nested.arbitrarily.deep].forEach(
- leaf => {
- expect(typeof leaf.create.double).toBe("function")
- expect(typeof leaf.create.appendToEach).toBe("function")
- expect(typeof leaf.create.countKeys).toBe("function")
- }
- )
- })
-
- describe("WHEN we dispatch actions.counter.create.increment() to the store", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.increment())
- })
-
- test("THEN the store's state.counter increments non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 2,
- list: ['first'],
- nested: { arbitrarily: { deep: 0 } }
- })
- expect(initialState.counter).toBe(1)
- })
-
- describe("AND we dispatch actions.counter.create.double() to the store", () => {
- beforeEach(() => {
- store.dispatch(actions.counter.create.double())
- })
-
- test("THEN the store's state.counter doubles non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['first'],
- nested: { arbitrarily: { deep: 0 } }
- })
- expect(initialState.counter).toBe(1)
- })
-
- describe("AND we dispatch actions.list.create.push('second') to the store", () => {
- beforeEach(() => {
- store.dispatch(actions.list.create.push('second'))
- })
-
- test("THEN the store's state.list updates non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['first', 'second'],
- nested: { arbitrarily: { deep: 0 } }
- })
- expect(initialState.list).toEqual(['first'])
- })
-
- describe("AND we dispatch actions.list.create.appendToEach(' item') to the store", () => {
- beforeEach(() => {
- store.dispatch(actions.list.create.appendToEach(' item'))
- })
-
- test("THEN the store's state.list updates non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['first item', 'second item'],
- nested: { arbitrarily: { deep: 0 } }
- })
- expect(initialState.list).toEqual(['first'])
- })
-
- describe("AND we dispatch actions.create.assign({ newKey: true })", () => {
- beforeEach(() => {
- store.dispatch(actions.create.assign({ newKey: true }))
- })
-
- test("THEN the store's state.newKey updates non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['first item', 'second item'],
- nested: { arbitrarily: { deep: 0 } },
- newKey: true
- })
- expect(initialState.newKey).not.toBeDefined()
- })
-
- describe("AND we dispatch actions.nested.arbitrarily.deep.create.countKeys()", () => {
- beforeEach(() => {
- store.dispatch(actions.nested.arbitrarily.deep.create.countKeys())
- })
-
- test("THEN the store's state.nested.arbitrarily.deep updates non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['first item', 'second item'],
- nested: { arbitrarily: { deep: 4 } },
- newKey: true
- })
- expect(initialState.nested.arbitrarily.deep).toBe(0)
- })
-
- describe("AND we dispatch actions.list.create.splice(0, 1)", () => {
- beforeEach(() => {
- store.dispatch(actions.list.create.splice(0, 1))
- })
-
- test("THEN the store's state.list updates non-mutatively", () => {
- expect(store.getState()).toEqual({
- counter: 4,
- list: ['second item'],
- nested: { arbitrarily: { deep: 4 } },
- newKey: true
- })
- expect(initialState.list).toEqual(['first'])
- })
- })
- })
- })
- })
- })
- })
- })
- })
-})
\ No newline at end of file
diff --git a/docs/leaf/README.md b/docs/leaf/README.md
deleted file mode 100644
index e5044e89..00000000
--- a/docs/leaf/README.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-id: about
-title: Leaves in Redux-Leaves
-hide_title: true
-sidebar_label: About 'leaves'
----
-
-# 'Leaves' in Redux-Leaves
-
-*Leaves* are a simple but important concept in Redux-Leaves.
-
-## In short
-- [**Every node** of the initial state shape is a leaf](#every-node-of-the-initial-state-shape-is-a-leaf); and
-- [**Nothing else** is a leaf](#nothing-else-is-a-leaf).
-
-In particular: *not every node of the Redux state is a leaf*, since the Redux state can have nodes that weren't present in the [initial state shape passed to `reduxLeaves`](../README.md#initialstate).
-
-Additionally:
-- [The `actions` object also contains every leaf](#the-actions-object-also-contains-every-leaf); and
-- [Every leaf of `actions` has a `create` property](#every-leaf-of-actions-has-a-create-property).
-
-This is explored further through a worked example of a simple todo app.
-
-## Leaves and state
-
-### Every node of the initial state shape is a leaf
-
-First, let's set up, assuming that we have defined [`reducersDict`](../README.md#reducersdict) elsewhere.
-
-```js
-import { createStore } from 'redux'
-import reduxLeaves from 'redux-leaves'
-import reducersDict from './path/to/reducersDict'
-
-const initialState = {
- todos: {
- byId: {},
- allIds: []
- },
- visibilityFilter: "SHOW_ALL"
-}
-
-const [reducer, actions] = reduxLeaves(initialState, reducersDict)
-```
-[From before:](#in-short)
-> - **Every node** of the initial state shape is a leaf;
-> - **Nothing else** is a leaf.
-
-Thus, each of the following is a leaf:
-- `todos`;
-- `todos.byId`;
-- `todos.allIds`; and
-- `visibilityFilter`.
-
-Additionally, we can consider the whole state tree to be a leaf (as the ancestral node).
-
-Here are some non-leaves:
-- `{ byId: {}, allIds: [] }`: this is the initial state of a leaf, but not a leaf itself;
-- `SHOW_ALL`: this is the initial state of a leaf, but not a leaf itself;
-- `todos.current`: there is no `todos.current` provided in the initial state shape; and
-- `todos.byId.007`: there is no `todos.byId.007` provided in the initial state shape.
-
-### Nothing else is a leaf
-(In particular: **not every node of the Redux state is a leaf**.)
-
-Having established what are and what are not leaves, let's now create our Redux store, and [hydrate it with some preloaded state](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer):
-
-```js
-const preloadedState = {
- todos: {
- byId: {
- f23f: {
- title: "Read a book",
- completed: true
- }
- },
- allIds: ['f23f'],
- current: 'f23f'
- },
- visibilityFilter: "SHOW_INCOMPLETE"
-}
-
-const store = createStore(initialState, preloadedState)
-```
-The following are all still leaves:
-- `todos`;
-- `todos.byId`;
-- `todos.allIds`; and
-- `visibilityFilter`.
-
-However, neither `todos.byId.f23f` nor `todos.current` have become leaves.
-
-(Even though they are nodes in the Redux state tree, since they were not nodes on the initial state shape, they are not leaves.)
-
-## Leaves and action creators
-
-### The `actions` object also contains every leaf
-
-Every leaf is defined as an object on `actions`.
-```js
-console.log(typeof actions.todos) // object
-console.log(typeof actions.todos.allIds) // object
-console.log(typeof actions.visibilityFilter) // object
-
-// Non-leaves are not defined:
-console.log(typeof actions.todos.current) // undefined - todos.current is not a leaf
-```
-
-### Every leaf of `actions` has a [`create`](../create/defaults.md) property
-
-Each of these action leaves has a [`create`](../create/defaults.md) property that is an object:
-
-```js
-console.log(typeof actions.todos.create) // object
-console.log(typeof actions.todos.allIds.create) // object
-console.log(typeof actions.visibilityFilter.create) // object
-
-// Won't work for non-leaves under actions
-console.log(typeof actions.todos.byId.f23f.create) // Uncaught TypeError - todos.byId.f23f is not a leaf
-console.log(typeof actions.todos.current.create) // Uncaught TypeError - todos.current is not a leaf
-```
-
-Every actions leaf can therefore create actions appropriate to that leaf through the [`create` API](../create/defaults.md).
\ No newline at end of file
diff --git a/docs/leaf/standardActions.md b/docs/leaf/standardActions.md
deleted file mode 100644
index febbfe6c..00000000
--- a/docs/leaf/standardActions.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-id: standard-actions
-title: Leaf-Standard-Actions
-hide_title: true
-sidebar_label: Leaf-Standard-Actions
----
-
-# Leaf-Standard-Actions (LSA)
-
-Redux-Leaves builds upon the '[Flux Standard Action](https://github.com/redux-utilities/flux-standard-action)' (FSA) framework.
-
-## Background
-The common Redux standard for reducers is that they [use an action's `type` property](https://redux.js.org/faq/reducers#do-i-have-to-use-the-switch-statement-to-handle-actions) to decide which logic to trigger.
-
-It is advised that [`type` should be a string, or at least serializable](https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants).
-
-`type` is also used prominently in [Redux DevTools](http://extension.remotedev.io/) on that assumption.
-
-Although Redux doesn't require that actions be FSA, it is [given as a recommendation](https://redux.js.org/glossary#action).
-
-### Recap of FSA
-[Definition of a FSA](https://github.com/redux-utilities/flux-standard-action/blob/master/README.md#actions):
-> An action MUST
->
-> * be a plain JavaScript object.
-> * have a `type` property.
->
-> An action MAY
->
-> * have an `error` property.
-> * have a `payload` property.
-> * have a `meta` property.
->
-> An action MUST NOT include properties other than `type`, `payload`, `error`, and `meta`.
-
-
-## Motivation
-
-There *could conceivably* be a conflict between:
-- `type` being maximally useful for Redux DevTools debugging ('the *descriptive* imperative'); and
-- `type` being maximally useful as a director of reducer logic ('the *procedural* imperative').
-
-However, there is no intrinsic reason why reducers *have* to look at `type` to decide what to do.
-
-As such, Redux-Leaves takes the design decision to separate out the *descriptive* and the *procedural* imperative, by:
-
-- reserving the `type` property for the descriptive imperative; and
-- introducing a `leaf` property for the procedural imperative.
-
-## The descriptive imperative: `type`
-
-The roadmap for Redux-Leaves includes adding a [configuration key](../leafReducers.md#configuration-keys) so that developers can customise the `type` used by a given [action creator](../create/README.md).
-
-The default (and, for now, only) behaviour is such that:
-
-```js
-const action = actions.foo.bar.create.myCustomActionCreator()
-console.log(action.type) // foo/bar/MY_CUSTOM_ACTION_CREATOR
-```
-
-## The procedural imperative: `leaf`
-
-In order to free `type` up to focus entirely on the *descriptive* imperative, Redux-Leaves introduces the **`leaf`** property to take care of the *procedural* imperative.
-
-```js
-const action = actions.foo.bar.create.myCustomActionCreator()
-console.log(action.leaf)
-/*
-{
- path: ['foo', 'bar'],
- creatorKey: 'myCustomActionCreator',
- CREATOR_KEY: 'MY_CUSTOM_ACTION_CREATOR'
- custom: true
-}
-/*
-```
-### Properties
-- `path`
-- `creatorKey`
-- `CREATOR_KEY`
-- `custom`
-
diff --git a/package.json b/package.json
index 41cf27a7..f364c103 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "redux-leaves",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "Write once. Reduce anywhere",
"main": "dist/index.js",
"license": "MIT",
diff --git a/src/actions/create/defaults/makeCreateDefaults.ts b/src/actions/create/defaults/makeCreateDefaults.ts
index e14ec9ed..e230e7d6 100644
--- a/src/actions/create/defaults/makeCreateDefaults.ts
+++ b/src/actions/create/defaults/makeCreateDefaults.ts
@@ -21,7 +21,7 @@ const makeCreateDefaults = (path: string[]) => (actionType?: string | LeafAction
on: () => producerOfLeafStandardActions(atomicActions.ON)(),
path: (path: string[], value: any) => producerOfLeafStandardActions(atomicActions.SET)({ path, value }),
push: (element: any, index: number = -1, replace: boolean = false) => producerOfLeafStandardActions(atomicActions.PUSH)({ element, index, replace }),
- replace: (pattern: string | RegExp, replacement: string) => producerOfLeafStandardActions(atomicActions.REPLACE)({ pattern, replacement }),
+ // replace: (pattern: string | RegExp, replacement: string) => producerOfLeafStandardActions(atomicActions.REPLACE)({ pattern, replacement }),
reset: () => producerOfLeafStandardActions(atomicActions.RESET)(),
set: (key: string, value: any) => producerOfLeafStandardActions(atomicActions.SET)({ path: [key], value }),
toggle: () => producerOfLeafStandardActions(atomicActions.TOGGLE)(),
diff --git a/src/leafReducer/custom/leafReducerCustom.ts b/src/leafReducer/custom/leafReducerCustom.ts
index 17dbb652..1ef6b5e1 100644
--- a/src/leafReducer/custom/leafReducerCustom.ts
+++ b/src/leafReducer/custom/leafReducerCustom.ts
@@ -12,13 +12,7 @@ const leafReducerCustom: LeafReducerTyped = (leafState, action, wholeState, redu
}
const applyReducer = (config: LeafReducerConfig, leafState: any, action: LeafStandardAction, wholeState: any) => {
- if (config.mutate) {
- return produce(leafState, (draftLeafState: any) => {
- config.reducer(draftLeafState, action, wholeState)
- })
- } else {
- return config.reducer(leafState, action, wholeState)
- }
+ return config.reducer(leafState, action, wholeState)
}
export default leafReducerCustom
\ No newline at end of file
diff --git a/src/leafReducer/leafReducer.ts b/src/leafReducer/leafReducer.ts
index 84ab9409..79c87c00 100644
--- a/src/leafReducer/leafReducer.ts
+++ b/src/leafReducer/leafReducer.ts
@@ -39,7 +39,7 @@ export const leafReducer = (
case atomicActions.OFF: return false
case atomicActions.ON: return true
case atomicActions.PUSH: return push(draftLeafState, payload)
- case atomicActions.REPLACE: return replace(draftLeafState, payload)
+ // case atomicActions.REPLACE: return replace(draftLeafState, payload)
case atomicActions.RESET: return reset(initialWhole, path)
case atomicActions.SET: return set(draftLeafState, payload)
case atomicActions.TOGGLE: return !draftLeafState
@@ -90,10 +90,10 @@ const push = (
: insertAtIndex(leafState, index, element)
)
-const replace = (
- leafState: string,
- { pattern, replacement }: { pattern: string | RegExp, replacement: string }
-) => leafState.replace(pattern, replacement)
+// const replace = (
+// leafState: string,
+// { pattern, replacement }: { pattern: string | RegExp, replacement: string }
+// ) => leafState.replace(pattern, replacement)
const reset = (initialWholeState: any, path: string[]) => (
path.length >= 1 ? R.path(path, initialWholeState) : initialWholeState
diff --git a/website/pages/en/index.js b/website/pages/en/index.js
index 0775a9a0..1a1c85b6 100644
--- a/website/pages/en/index.js
+++ b/website/pages/en/index.js
@@ -65,7 +65,7 @@ class HomeSplash extends React.Component {
-
+
@@ -169,7 +169,7 @@ class Index extends React.Component {
},
{
title: 'Quick setup.',
- content: `With multiple action creators built in by default, it takes just 30 seconds to get up and running.`,
+ content: `With multiple action creators built in by default, it takes just 30 seconds to get up and running.`,
image: `${baseUrl}img/fast.png`,
imageAlign: 'top',
},
diff --git a/website/sidebars.json b/website/sidebars.json
index c0a6794c..ba3d1518 100644
--- a/website/sidebars.json
+++ b/website/sidebars.json
@@ -2,31 +2,72 @@
"docs": {
"Introduction": [
"intro/overview",
- "intro/demo",
"intro/features"
],
- "Leaves & Reducers":[
- "redux-leaves",
- "leaf/about",
- "leaf-reducers",
- "creator-keys"
+ "Examples":[
+ "examples/basic-example",
+ "examples/intermediate-example",
+ "examples/advanced-example"
],
- "Actions": [
- "create/creators",
- "leaf/standard-actions"
+ "API Reference": [
+ "redux-leaves",
+ "api/leaf-reducers",
+ "api/creator-keys",
+ "api/actions",
+ "api/create"
],
"Default creators": [
- "create/defaults",
- "create/type-specific",
+ "defaults/by-type",
+ {
+ "type": "subcategory",
+ "label": "any",
+ "ids": [
+ "create/apply",
+ "create/clear",
+ "create/reset",
+ "create/update"
+ ]
+ },
+ {
+ "type": "subcategory",
+ "label": "array",
+ "ids": [
+ "create/concat",
+ "create/drop",
+ "create/filter",
+ "create/push"
+ ]
+ },
+ {
+ "type": "subcategory",
+ "label": "boolean",
+ "ids": [
+ "create/off",
+ "create/on",
+ "create/toggle"
+ ]
+ },
+ {
+ "type": "subcategory",
+ "label": "number",
+ "ids": [
+ "create/increment"
+ ]
+ },
+ {
+ "type": "subcategory",
+ "label": "object",
+ "ids": [
+ "create/assign",
+ "create/path",
+ "create/set"
+ ]
+ },
{
"type": "subcategory",
- "label": "create.as",
+ "label": "string",
"ids": [
- "create/asArray/array-creators",
- "create/asBoolean/boolean-creators",
- "create/asNumber/number-creators",
- "create/asObject/object-creators",
- "create/asString/string-creators"
+ "create/concat"
]
}
]