+ )
+ ).toThrow(
+ "createFormStore: the state selector argument must be a function"
+ );
+
+ console.error = originalError;
+ });
+
+ it("should throw if the initial form state is not an object", () => {
+ const originalError = console.error;
+ console.error = jest.fn();
+
+ const [formStore] = myFormStore;
+
+ expect(() =>
+ render(
+
+
+ state.counter} initialFormState={[]} />
+
+ )
+ ).toThrow(
+ "createFormStore: the initial form state argument must be an object"
+ );
+
+ console.error = originalError;
+ });
+});
diff --git a/docs/Collection.mdx b/docs/Collection.mdx
index 67058ab..f04d058 100644
--- a/docs/Collection.mdx
+++ b/docs/Collection.mdx
@@ -136,7 +136,7 @@ import { Form, Input, Collection } from "usetheform";
Array Collection of Input fields with indexes handled automatically for custom Inputs.
-```javascript
+```jsx
import React from "react";
import { withIndex, useField, Collection } from "usetheform";
@@ -232,7 +232,7 @@ Validation at Collection level starts only on form submission if the prop **`tou
Async Validation for Collections is triggered on Submit event. The form submission is prevented if the validation fails.
This means that the onSubmit function passed as prop to the **Form** component will not be invoked.
-```javascript
+```jsx
import { useAsyncValidation, useForm } from 'usetheform'
const Submit = () => {
diff --git a/docs/Form.mdx b/docs/Form.mdx
index b8cf9a0..4d52664 100644
--- a/docs/Form.mdx
+++ b/docs/Form.mdx
@@ -171,7 +171,7 @@ import { reduceTotalPrice,reduceTotalQuantity } from './components/Item/utils';
#### Detailed Explanation:
-```javascript
+```jsx
export const Item = ({ price, qty, desc }) => {
return (
@@ -262,7 +262,7 @@ import { Form, Collection, Input, useAsyncValidation } from 'usetheform';
#### Detailed Explanation:
-```javascript
+```jsx
import { useForm } from 'usetheform'
const Submit = () => {
diff --git a/docs/FormContext.mdx b/docs/FormContext.mdx
index 59e4b6d..8c9aad5 100644
--- a/docs/FormContext.mdx
+++ b/docs/FormContext.mdx
@@ -223,7 +223,7 @@ import { FormContext, Collection, Input, useAsyncValidation } from 'usetheform';
#### Detailed Explanation:
-```javascript
+```jsx
import { useForm } from 'usetheform'
const Submit = () => {
diff --git a/docs/Input.mdx b/docs/Input.mdx
index 7431e08..01c8751 100644
--- a/docs/Input.mdx
+++ b/docs/Input.mdx
@@ -55,7 +55,7 @@ Renders all the inputs of the types listed at: [W3schools Input Types](https://w
- When you need to access the underlying DOM node created by an Input (e.g. to call focus), you can use a ref to store a reference to the input dom node.
-```javascript
+```jsx
const ref = useRef(null)
```
@@ -148,7 +148,7 @@ import { Form, Input } from 'usetheform';
#### Detailed Explanation:
-```javascript
+```jsx
import { useForm } from 'usetheform'
export const asyncTestInput = value =>
diff --git a/docs/Select.mdx b/docs/Select.mdx
index a8c4d4e..1e65e36 100644
--- a/docs/Select.mdx
+++ b/docs/Select.mdx
@@ -51,7 +51,7 @@ It accepts, as props, any html attribute listed at: [Html Select Attributes](htt
- When you need to access the underlying DOM node created by Select (e.g. to call focus), you can use a ref to store a reference to the select dom node.
-```javascript
+```jsx
const ref = useRef(null)
```
@@ -145,7 +145,7 @@ const ref = useRef(null)
## Validation - Async
-```javascript
+```jsx
import { useAsyncValidation, useForm } from 'usetheform'
const Submit = () => {
diff --git a/docs/TextArea.mdx b/docs/TextArea.mdx
index 75ebcbc..a4d4314 100644
--- a/docs/TextArea.mdx
+++ b/docs/TextArea.mdx
@@ -46,7 +46,7 @@ Renders a *textarea* element ([W3schools Textarea](https://www.w3schools.com/tag
- When you need to access the underlying DOM node created by TextArea (e.g. to call focus), you can use a ref to store a reference to the textarea dom node.
-```javascript
+```jsx
const ref = useRef(null)
```
@@ -108,7 +108,7 @@ const ref = useRef(null)
## Validation - Async
-```javascript
+```jsx
import { useAsyncValidation, useForm } from 'usetheform'
const Submit = () => {
diff --git a/docs/createFormStore.mdx b/docs/createFormStore.mdx
new file mode 100644
index 0000000..7c3b6cb
--- /dev/null
+++ b/docs/createFormStore.mdx
@@ -0,0 +1,88 @@
+---
+name: createFormStore
+menu: API Reference
+---
+
+# createFormStore
+`createFormStore(initialFormState: Object)` creates a read-only form store that holds the state tree of your Form and the hook function to select a "Field" from the Form state.
+
+## Arguments
+
+**`initialFormState`**: object
+
+## Returns
+
+**`helpers`** : array
+
+An array that holds the form store and the hook function to select a "Field" from the Form state.
+
+## Basic usage
+
+### ๐ First: create a form store
+
+```javascript
+import { createFormStore } from 'usetheform';
+
+const [formStore, useFormSelector] = createFormStore({ counter: 0 });
+
+export const awesomeFormStore = formStore;
+export const useAwesomeFormSelector = useFormSelector;
+```
+
+### ๐ Next: create your awesome Form
+
+```jsx
+import { Form } from 'usetheform';
+import { awesomeFormStore } from './formStore';
+
+export default function AwesomeForm() {
+ return (
+ <>
+
+
+ >
+ );
+}
+```
+
+### ๐ Finally: bind your components, and that's it!
+
+Use the `useAwesomeFormSelector` hook anywhere, no providers needed. Select your state and the component will re-render on changes.
+
+```jsx
+import { useAwesomeFormSelector } from './formStore'
+
+export const Counter = () => {
+ const [counter, setCounterValue] = useAwesomeFormSelector((state) => state.counter);
+ return (
+
+ {counter}
+
+
+
+
+ );
+}
+```
+
+The `` component will re-render on changes.
+
+**IMPORTANT**: Multiple field-selections within the same selector function are not allowed.
+
+```javascript
+// BAD ๐ โ
+const [counter, setCounter] = useFormSelector(state => ({ counter1 : state.counter1, counter2 : state.counter2 }));
+```
+```javascript
+// OK ๐ โ
+const [counter1, setCounter1] = useFormSelector(state => state.counter1);
+const [counter2, setCounter2] = useFormSelector(state => state.counter2);
+```
\ No newline at end of file
diff --git a/docs/index.mdx b/docs/index.mdx
index 7991f3d..c6b1a4e 100644
--- a/docs/index.mdx
+++ b/docs/index.mdx
@@ -68,6 +68,65 @@ npm install --save usetheform
๐ [**Check out the Reset Button**](https://iusehooks.github.io/usetheform/docs-use-form#basic-usage)
+## ๐ Recipes
+
+### Need to read or manipulate Form's Fields anywhere outside Form context?
+
+#### ๐ First: create a form store
+
+```jsx
+import { createFormStore } from 'usetheform';
+
+const [formStore, useFormSelector] = createFormStore({ counter: 0 });
+
+export const awesomeFormStore = formStore;
+export const useAwesomeFormSelector = useFormSelector;
+```
+
+#### ๐ Next: create your awesome Form
+
+```jsx
+import { Form } from 'usetheform';
+import { awesomeFormStore } from './awesomeFormStore';
+
+export default function AwesomeForm() {
+ return (
+ <>
+
+
+ >
+ );
+}
+```
+
+#### ๐ Finally: bind your components, and that's it!
+
+Use the `useAwesomeFormSelector` hook anywhere, no providers needed. Select your state and the component will re-render on changes.
+
+```jsx
+import { useAwesomeFormSelector } from './awesomeFormStore'
+
+export const Counter = () => {
+ const [counter, setCounterValue] = useAwesomeFormSelector((state) => state.counter);
+ return (
+