diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx index 2cb1e356..e26621bb 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx +++ b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx @@ -1,13 +1,8 @@ import type { IFormDynBlock, IFormField, IFormRegisterFunc } from '../../types'; import type { ReactElement } from 'react'; -import { Alien, Cube, Leaf, TreasureChest } from '@phosphor-icons/react'; - -export const blockOptionsMock = [ - { id: 'default', label: 'Default', leftSection: }, - { id: 'other', label: 'Other', leftSection: }, - { id: 'stuff', label: 'Stuff', leftSection: }, -]; +import { Group } from '@mantine/core'; +import { Cube, Leaf } from '@phosphor-icons/react'; export const dynamicBlocksMock: IFormDynBlock[] = [ { @@ -15,16 +10,16 @@ export const dynamicBlocksMock: IFormDynBlock[] = [ blockHeader: ( <> - Example + Example A ), - blockType: 'default', + blockType: 'exampleA', opened: true, - value: 'initial', + value: '', }, button: { - blockType: 'default', - label: 'Example', + blockType: 'exampleA', + label: 'Example A', leftSection: , }, renderFunc: ( @@ -34,10 +29,63 @@ export const dynamicBlocksMock: IFormDynBlock[] = [ registerName: string, ): ReactElement => { return ( + + + + + ); + }, + }, + { + block: { + blockHeader: ( <> - works - + + Example B + ), + blockType: 'exampleB', + opened: true, + value: '', + }, + button: { + blockType: 'exampleB', + label: 'Example B', + leftSection: , + }, + renderFunc: ( + b: IFormField, + _i: number, + register: IFormRegisterFunc, + registerName: string, + ): ReactElement => { + return ( + ); }, }, diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx index c0a2d56b..0a6cb153 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx +++ b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx @@ -2,6 +2,7 @@ import type { IFormDynamicZoneProps } from './FormDynamicZone'; import type { Meta, StoryObj } from '@storybook/react'; import type { ReactElement } from 'react'; +import { action } from '@storybook/addon-actions'; import { FormProvider, useForm } from 'react-hook-form'; import { FormDynamicZone as Cmp } from './FormDynamicZone'; @@ -30,6 +31,10 @@ function render() { } export const FormDynamicZone: IStory = { - args: { dynamicBlocks: dynamicBlocksMock, dynamicZoneName: 'dynTest' }, + args: { + dynamicBlocks: dynamicBlocksMock, + dynamicZoneName: 'dynTest', + onFormSubmit: action('results'), + }, render: render(), }; diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx index 193e3a5a..f5f2f9d5 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx +++ b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx @@ -1,6 +1,7 @@ import type { ReactElement } from 'react'; import { renderWithProviders } from '@smile/haring-react-shared/test-utils'; +import { action } from '@storybook/addon-actions'; import { FormProvider, useForm } from 'react-hook-form'; import { FormDynamicZone } from './FormDynamicZone'; @@ -15,6 +16,7 @@ describe('FormDynamicZone', () => { ); diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx index 19ddef54..0b88028f 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx +++ b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx @@ -1,6 +1,7 @@ import type { IFormDynBlock, IFormDynSubmit, + IFormDynSubmitResults, IFormField, IFormFieldWithoutId, } from '../../types'; @@ -30,6 +31,7 @@ export interface IFormDynamicZoneProps { actionLabels?: IFormDynamicZoneActionLabels; dynamicBlocks: IFormDynBlock[]; dynamicZoneName: string; + onFormSubmit: (data: IFormDynSubmitResults) => void; } export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { @@ -37,9 +39,10 @@ export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { dynamicBlocks, dynamicZoneName, actionLabels = defaultActionLabels, + onFormSubmit, } = props; - const { control, register, handleSubmit } = + const { control, register, handleSubmit, getValues } = useFormContext>(); const { fields, append, remove, swap, update } = useFieldArray({ control, @@ -78,9 +81,9 @@ export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { } } - function onToggle(block: IFormField, index: number, opened: boolean): void { - const { id, ...blockWithoutId } = block; - update(index, { ...blockWithoutId, opened }); + function onToggle(_block: IFormField, index: number, opened: boolean): void { + const updatedBlock = getValues(dynamicZoneName)[index]; + update(index, { ...updatedBlock, opened }); } function isMoveDisabled( @@ -131,7 +134,11 @@ export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { } function onSubmit(data: IFormDynSubmit): void { - console.log(data); + onFormSubmit( + data[dynamicZoneName].map( + ({ blockActions, blockHeader, blockFooter, ...block }) => block, + ), + ); } return ( @@ -147,6 +154,11 @@ export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { onRenderBlockContent={renderBlock} onToggleBlock={onToggle} /> + {/* TODO: Move this out, should be in the story/text not part of this component since it's just a field */} + {/* TODO: then decide how to send errors/messages upwards, where they can go (everything should be doable with props) */} + {/* TODO: build mock example of error messages and where they can go (at the form level, somewhere inside this component, in blocks... */} + {/* TODO: then focus and nested focus, multiple errors, auto-opening a block if it wants to focus inside, auto-scroll the page */} + {/* TODO: then animations */} diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap b/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap index ec2bf540..9a52dfb1 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap +++ b/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap @@ -43,7 +43,7 @@ exports[`FormDynamicZone matches snapshot 1`] = ` data-size="md" data-variant="default" data-with-left-section="true" - label="Example" + label="Example A" style="--button-height: var(--button-height-md); --button-padding-x: var(--button-padding-x-md); --button-fz: var(--mantine-font-size-md); --button-radius: var(--mantine-radius-md); --button-bg: var(--mantine-color-default); --button-hover: var(--mantine-color-default-hover); --button-color: var(--mantine-color-default-color); --button-bd: calc(0.0625rem * var(--mantine-scale)) solid var(--mantine-color-default-border);" type="button" > @@ -69,7 +69,42 @@ exports[`FormDynamicZone matches snapshot 1`] = ` - Example + Example A + + + + diff --git a/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts b/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts index 1c801af8..5a0a69f7 100644 --- a/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts +++ b/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts @@ -29,3 +29,7 @@ export interface IFormDynBlock { } export type IFormDynSubmit = Record; +export type IFormDynSubmitResults = IOmitRespectIndexSignature< + IFormFieldWithoutId, + 'blockActions' | 'blockFooter' | 'blockHeader' +>[];