Skip to content

Commit

Permalink
feat: progress on FormDynamicZone
Browse files Browse the repository at this point in the history
  • Loading branch information
Quentin LE CAIGNEC committed Sep 9, 2024
1 parent d1cf818 commit 180b47f
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
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: <Alien /> },
{ id: 'other', label: 'Other', leftSection: <Leaf /> },
{ id: 'stuff', label: 'Stuff', leftSection: <TreasureChest /> },
];
import { Group } from '@mantine/core';
import { Cube, Leaf } from '@phosphor-icons/react';

export const dynamicBlocksMock: IFormDynBlock[] = [
{
block: {
blockHeader: (
<>
<Cube key="1" />
<span key="2">Example</span>
<span key="2">Example A</span>
</>
),
blockType: 'default',
blockType: 'exampleA',
opened: true,
value: 'initial',
value: '',
},
button: {
blockType: 'default',
label: 'Example',
blockType: 'exampleA',
label: 'Example A',
leftSection: <Cube />,
},
renderFunc: (
Expand All @@ -34,10 +29,63 @@ export const dynamicBlocksMock: IFormDynBlock[] = [
registerName: string,
): ReactElement => {
return (
<Group>
<input
key={b.id + 1}
{...register(`${registerName}.input1`, {
minLength: 3,
required: true,
})}
placeholder="nested field 1"
required
/>
<input
key={b.id + 2}
{...register(`${registerName}.input2`, {
required: true,
})}
placeholder="nested field 2"
required
/>
</Group>
);
},
},
{
block: {
blockHeader: (
<>
<span>works</span>
<input key={b.id} {...register(registerName)} />
<Leaf key="1" />
<span key="2">Example B</span>
</>
),
blockType: 'exampleB',
opened: true,
value: '',
},
button: {
blockType: 'exampleB',
label: 'Example B',
leftSection: <Leaf />,
},
renderFunc: (
b: IFormField,
_i: number,
register: IFormRegisterFunc,
registerName: string,
): ReactElement => {
return (
<select
key={b.id}
{...register(registerName, { required: true })}
required
>
<option disabled value="">
-- Please choose an option --
</option>
<option value="selectA">Value A</option>
<option value="selectB">Value B</option>
</select>
);
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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(),
};
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -15,6 +16,7 @@ describe('FormDynamicZone', () => {
<FormDynamicZone
dynamicBlocks={dynamicBlocksMock}
dynamicZoneName="dynamicZoneTest"
onFormSubmit={action('results')}
/>
</FormProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
IFormDynBlock,
IFormDynSubmit,
IFormDynSubmitResults,
IFormField,
IFormFieldWithoutId,
} from '../../types';
Expand Down Expand Up @@ -30,16 +31,18 @@ export interface IFormDynamicZoneProps {
actionLabels?: IFormDynamicZoneActionLabels;
dynamicBlocks: IFormDynBlock[];
dynamicZoneName: string;
onFormSubmit: (data: IFormDynSubmitResults) => void;
}

export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement {
const {
dynamicBlocks,
dynamicZoneName,
actionLabels = defaultActionLabels,
onFormSubmit,
} = props;

const { control, register, handleSubmit } =
const { control, register, handleSubmit, getValues } =
useFormContext<Record<typeof dynamicZoneName, IFormFieldWithoutId[]>>();
const { fields, append, remove, swap, update } = useFieldArray({
control,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 (
Expand All @@ -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 */}

Check warning on line 157 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: Move this out, should be in the...'

Check warning on line 157 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: Move this out, should be in the...'
{/* TODO: then decide how to send errors/messages upwards, where they can go (everything should be doable with props) */}

Check warning on line 158 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then decide how to send...'

Check warning on line 158 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then decide how to send...'
{/* TODO: build mock example of error messages and where they can go (at the form level, somewhere inside this component, in blocks... */}

Check warning on line 159 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: build mock example of error...'

Check warning on line 159 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: build mock example of error...'
{/* TODO: then focus and nested focus, multiple errors, auto-opening a block if it wants to focus inside, auto-scroll the page */}

Check warning on line 160 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then focus and nested focus,...'

Check warning on line 160 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then focus and nested focus,...'
{/* TODO: then animations */}

Check warning on line 161 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then animations'

Check warning on line 161 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected 'todo' comment: 'TODO: then animations'
<input style={{ margin: 'auto' }} type="submit" />
</Stack>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
>
Expand All @@ -69,7 +69,42 @@ exports[`FormDynamicZone matches snapshot 1`] = `
<span
class="m_811560b9 mantine-Button-label"
>
Example
Example A
</span>
</span>
</button>
<button
class="haring-focus haring-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root"
data-size="md"
data-variant="default"
data-with-left-section="true"
label="Example B"
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"
>
<span
class="m_80f1301b mantine-Button-inner"
>
<span
class="m_a74036a mantine-Button-section"
data-position="left"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 256 256"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M223.45,40.07a8,8,0,0,0-7.52-7.52C139.8,28.08,78.82,51,52.82,94a87.09,87.09,0,0,0-12.76,49c.57,15.92,5.21,32,13.79,47.85l-19.51,19.5a8,8,0,0,0,11.32,11.32l19.5-19.51C81,210.73,97.09,215.37,113,215.94q1.67.06,3.33.06A86.93,86.93,0,0,0,162,203.18C205,177.18,227.93,116.21,223.45,40.07ZM153.75,189.5c-22.75,13.78-49.68,14-76.71.77l88.63-88.62a8,8,0,0,0-11.32-11.32L65.73,179c-13.19-27-13-54,.77-76.71,22.09-36.47,74.6-56.44,141.31-54.06C210.2,114.89,190.22,167.41,153.75,189.5Z"
/>
</svg>
</span>
<span
class="m_811560b9 mantine-Button-label"
>
Example B
</span>
</span>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ export interface IFormDynBlock {
}

export type IFormDynSubmit = Record<string, IFormFieldWithoutId[]>;
export type IFormDynSubmitResults = IOmitRespectIndexSignature<
IFormFieldWithoutId,
'blockActions' | 'blockFooter' | 'blockHeader'
>[];

0 comments on commit 180b47f

Please sign in to comment.