diff --git a/src/component/sugarform/index.ts b/src/component/sugarform/index.ts index afd117e..53ed2c6 100644 --- a/src/component/sugarform/index.ts +++ b/src/component/sugarform/index.ts @@ -1,14 +1,25 @@ -import { useRef } from 'react'; +import type { Dispatch, SetStateAction } from 'react'; +import { useRef, useState } from 'react'; import { SugarFormError } from '../../util/error'; import type { Sugar, SugarValue } from '../sugar'; import { createEmptySugar } from '../sugar/create'; export const useSugarForm = ({ defaultValue }:{ defaultValue: T }): { sugar: Sugar, - render: () => SugarValue + render: () => SugarValue, + useIsDirtyState: () => boolean, } => { const sugar = useRef>(); sugar.current ??= createEmptySugar('', defaultValue); + + const isDirtyStateRef = useRef>>(undefined); + + if (!sugar.current.mounted) { + sugar.current.upstream.listen('updateDirty', ({ isDirty }) => { + isDirtyStateRef.current?.(isDirty); + }); + } + return { sugar: sugar.current, render: (): SugarValue => { @@ -16,5 +27,12 @@ export const useSugarForm = ({ defaultValue }:{ defaultValue: T }): { if (sugarValue === undefined || !sugarValue.mounted) throw new SugarFormError('SF0021', 'Path: '); return sugarValue.get(); }, + useIsDirtyState: (): boolean => { + const [ isDirtyState, setIsDirtyState ] = useState(false); + if (isDirtyStateRef.current === undefined) { + isDirtyStateRef.current = setIsDirtyState; + } + return isDirtyState; + }, }; }; diff --git a/tests/useSugarForm.test.ts b/tests/useSugarForm.test.ts index d707553..147ded4 100644 --- a/tests/useSugarForm.test.ts +++ b/tests/useSugarForm.test.ts @@ -1,5 +1,5 @@ import { describe, it } from '@jest/globals'; -import { renderHook } from '@testing-library/react'; +import { act, renderHook } from '@testing-library/react'; import type { Sugar, SugarValue } from '../src/component/sugar'; import { useSugarForm } from '../src/component/sugarform'; @@ -7,7 +7,7 @@ describe('useSugarForm', () => { it('should work', () => { const { result: { current: { sugar, render } } } = - renderHook(() => useSugarForm<{ a: 'foo' }>({ defaultValue: { a: 'foo' } })); + renderHook(() => useSugarForm<{ a: string }>({ defaultValue: { a: 'foo' } })); const { result: { current: { fields: { a } } } } = renderHook(() => sugar.useObject({})); @@ -25,4 +25,30 @@ describe('useSugarForm', () => { }); }); + it('should work with isDirtyState', () => { + + const { result: { current: { sugar, useIsDirtyState } } } = + renderHook(() => useSugarForm<{ a: string }>({ defaultValue: { a: 'foo' } })); + + const { result: { current: { fields: { a } } } } = + renderHook(() => sugar.useObject({})); + + const { result: { current: { onBlur } } } = renderHook(() => a.useFromRef({ + get: () => ({ success: true, value: 'foo' }), + set: () => null, + })); + + const { result: isDirtyResult } = renderHook(() => useIsDirtyState()); + + expect(isDirtyResult.current).toBe(false); + + act(() => { + if (a.mounted) a.get = (): SugarValue => ({ success: true, value: 'bar' }); + onBlur(); + }); + + expect(isDirtyResult.current).toBe(true); + + }); + });