Skip to content

Commit 32377a5

Browse files
Merge pull request #70 from 92green/feature/branchable
Add .branchable, fix submit non-branchable
2 parents 0bafb6a + a1bbff0 commit 32377a5

File tree

6 files changed

+71
-9
lines changed

6 files changed

+71
-9
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ function MyComponent(props) {
273273
274274
[Demo](http://dendriform.xyz#branch)
275275
276+
A form containing a non-branchable value such as a string, number, undefined or null will throw an error if `.branch()` is called on it. You can check if a form is branchable using `.branchable`:
277+
278+
```js
279+
new Dendriform(123).branchable; // returns false
280+
new Dendriform({name: 'Bill'}).branchable; // returns true
281+
```
282+
283+
The `.branchAll()` methods can be used to branch all children at once, returning an array of branched forms.
284+
276285
### Rendering
277286
278287
The `.render()` function allows you to branch off and render a deep value in a React component.
@@ -1263,11 +1272,12 @@ const form = new Dendriform(value, {plugins});
12631272
// form can be submitted by calling:
12641273
form.plugins.submit.submit();
12651274

1266-
// get whether the form has changed value
1267-
form.plugins.submit.changed;
1275+
// get whether the form has changed value i.e. is dirty
1276+
form.plugins.submit.dirty.value;
1277+
form.plugins.submit.dirty.useValue();
12681278

12691279
// get whether the form has changed value at a path
1270-
form.branch('foo').plugins.submit.changed;
1280+
form.branch('foo').plugins.submit.dirty;
12711281
```
12721282
12731283
PluginSubmit has the following properties and methods.

packages/dendriform/README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ function MyComponent(props) {
273273
274274
[Demo](http://dendriform.xyz#branch)
275275
276+
A form containing a non-branchable value such as a string, number, undefined or null will throw an error if `.branch()` is called on it. You can check if a form is branchable using `.branchable`:
277+
278+
```js
279+
new Dendriform(123).branchable; // returns false
280+
new Dendriform({name: 'Bill'}).branchable; // returns true
281+
```
282+
283+
The `.branchAll()` methods can be used to branch all children at once, returning an array of branched forms.
284+
276285
### Rendering
277286
278287
The `.render()` function allows you to branch off and render a deep value in a React component.
@@ -1263,11 +1272,12 @@ const form = new Dendriform(value, {plugins});
12631272
// form can be submitted by calling:
12641273
form.plugins.submit.submit();
12651274

1266-
// get whether the form has changed value
1267-
form.plugins.submit.changed;
1275+
// get whether the form has changed value i.e. is dirty
1276+
form.plugins.submit.dirty.value;
1277+
form.plugins.submit.dirty.useValue();
12681278

12691279
// get whether the form has changed value at a path
1270-
form.branch('foo').plugins.submit.changed;
1280+
form.branch('foo').plugins.submit.dirty;
12711281
```
12721282
12731283
PluginSubmit has the following properties and methods.

packages/dendriform/src/Dendriform.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import React from 'react';
2121
import {useState, useEffect, useRef} from 'react';
2222
import {shallowEqualArrays} from 'shallow-equal';
23-
import {getIn, entries, applyPatches, zoomOutPatches, SET} from 'dendriform-immer-patch-optimiser';
23+
import {getIn, getType, entries, applyPatches, zoomOutPatches, SET, BASIC} from 'dendriform-immer-patch-optimiser';
2424
import type {Path} from 'dendriform-immer-patch-optimiser';
2525
import produce, {isDraft, original} from 'immer';
2626
import {producePatches, Patch} from './producePatches';
@@ -697,6 +697,9 @@ const Branch = React.memo(
697697
(prevProps, nextProps) => shallowEqualArrays(prevProps.deps, nextProps.deps)
698698
);
699699

700+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
701+
const branchable = (thing: any) => getType(thing) !== BASIC;
702+
700703
// eslint-disable-next-line @typescript-eslint/no-explicit-any
701704
const entriesOrDie = (thing: any, error: ErrorKey) => {
702705
try {
@@ -813,6 +816,10 @@ export class Dendriform<V,P extends Plugins = undefined> {
813816
return this.core.applyIdToPlugins(this.id, this.path) as P;
814817
}
815818

819+
get branchable(): boolean {
820+
return branchable(this.value);
821+
}
822+
816823
set = (toProduce: ToProduce<V>, options: SetOptions = {}): void => {
817824
this.core.setWithDebounce(this.id, toProduce, options);
818825
};

packages/dendriform/src/plugins/PluginSubmit.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ export class PluginSubmit<V,E=undefined> extends Plugin {
8787

8888
submit(): void {
8989
const state = this.getState();
90-
// call this to create nodes so arrays can diff in onSubmit
91-
state.previous.branchAll();
90+
if(state.previous.branchable) {
91+
// call this to create nodes so arrays can diff in onSubmit
92+
state.previous.branchAll();
93+
}
9294
state.previous.set(state.form.value);
9395
}
9496

packages/dendriform/test/Dendriform.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,21 @@ describe(`Dendriform`, () => {
562562
});
563563
});
564564

565+
describe(`branchable`, () => {
566+
test(`should determine if branchable`, () => {
567+
expect(new Dendriform(123).branchable).toBe(false);
568+
expect(new Dendriform('abc').branchable).toBe(false);
569+
expect(new Dendriform(true).branchable).toBe(false);
570+
expect(new Dendriform(undefined).branchable).toBe(false);
571+
expect(new Dendriform(null).branchable).toBe(false);
572+
expect(new Dendriform({foo: true}).branchable).toBe(true);
573+
expect(new Dendriform([1,2,3]).branchable).toBe(true);
574+
expect(new Dendriform(new Map()).branchable).toBe(true);
575+
expect(new Dendriform(new Set()).branchable).toBe(true);
576+
expect(new Dendriform(new Date()).branchable).toBe(true);
577+
});
578+
});
579+
565580
describe(`.branch()`, () => {
566581

567582
test(`should get child value`, () => {

packages/dendriform/test/plugins/PluginSubmit.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ describe(`plugin submit`, () => {
4343
foo: 456
4444
});
4545
});
46+
47+
test(`should submit basic value if changed`, () => {
48+
49+
const value: number = 2;
50+
51+
const onSubmit = jest.fn();
52+
53+
const plugins = {
54+
submit: new PluginSubmit({onSubmit})
55+
};
56+
57+
const form = new Dendriform(value, {plugins});
58+
form.set(3);
59+
form.plugins.submit.submit();
60+
61+
expect(onSubmit).toHaveBeenCalledTimes(1);
62+
expect(onSubmit.mock.calls[0][0]).toEqual(3);
63+
});
4664

4765
test(`should change value and show previous and dirty at paths`, () => {
4866

0 commit comments

Comments
 (0)