diff --git a/packages/dendriform/src/Dendriform.tsx b/packages/dendriform/src/Dendriform.tsx index e3c906d..a40c195 100644 --- a/packages/dendriform/src/Dendriform.tsx +++ b/packages/dendriform/src/Dendriform.tsx @@ -106,7 +106,7 @@ export type DeriveCallbackDetails = InternalMetaDetails & { }; export type DeriveCallback = (newValue: V, details: DeriveCallbackDetails) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export type DeriveCallbackRef = [DeriveCallback]; +export type DeriveCallbackRef = [string, DeriveCallback]; export type CancelCallback = (message: string) => void; @@ -265,12 +265,20 @@ export class Core { return path; }; + getValue = (id: string): unknown => { const path = this.getPath(id); if(!path) return undefined; return getIn(this.state.value, path); }; + getRevertValue = (id: string): unknown => { + const {stateRevert} = this; + const path = this.getPath(id); + if(!path || !stateRevert) return undefined; + return getIn(stateRevert.value, path); + }; + getKey = (id: string): unknown => { const path = this.getPath(id); return path ? path.slice(-1)[0] : undefined; @@ -490,24 +498,27 @@ export class Core { if(this.internalState.deriving) return; this.internalState.deriving = true; - const [deriveCallback] = deriveCallbackRef; + const [id, deriveCallback] = deriveCallbackRef; const patches = this.internalState.changeBuffer ?? new HistoryItem(); + const nextValue = this.getValue(id); + const prevValue = this.getRevertValue(id); + const details = { ...internalMeta, patches, prev: { - value: this.stateRevert?.value, + value: prevValue, nodes: this.stateRevert?.nodes }, next: { - value: this.state.value, + value: nextValue, nodes: this.state.nodes }, - id: '0' + id }; - deriveCallback(this.state.value, details); + deriveCallback(nextValue, details); this.internalState.deriving = false; }; @@ -836,7 +847,7 @@ export class Dendriform { }; onDerive(callback: DeriveCallback): (() => void) { - const deriveCallback: DeriveCallbackRef = [callback]; + const deriveCallback: DeriveCallbackRef = [this.id, callback]; this.core.deriveCallbackRefs.add(deriveCallback); // call immediately, and dont add to history diff --git a/packages/dendriform/test/Dendriform.test.tsx b/packages/dendriform/test/Dendriform.test.tsx index 321287f..619e63f 100644 --- a/packages/dendriform/test/Dendriform.test.tsx +++ b/packages/dendriform/test/Dendriform.test.tsx @@ -1676,6 +1676,35 @@ describe(`Dendriform`, () => { }); + test(`should allow derivers on branched forms`, () => { + + const form = new Dendriform({ + name: 'boo', + letters: 0 + }); + + const deriver = jest.fn(); + + form.branch('name').onDerive(deriver); + form.set(draft => { + draft.name = 'baa'; + }); + + expect(deriver).toHaveBeenCalledTimes(2); + expect(deriver.mock.calls[1][0]).toBe('baa'); + expect(deriver.mock.calls[1][1].id).toBe('1'); + expect(deriver.mock.calls[1][1].prev.value).toBe('boo'); + expect(deriver.mock.calls[1][1].next.value).toBe('baa'); + + // should always derive, for now, even if source field does not change + + form.set(draft => { + draft.letters = 2; + }); + + expect(deriver).toHaveBeenCalledTimes(3); + }); + test(`should handle multiple derivers on same form, calling them sequentially`, () => { const form = new Dendriform({