diff --git a/.changeset/olive-months-admire.md b/.changeset/olive-months-admire.md new file mode 100644 index 00000000..82bf5f90 --- /dev/null +++ b/.changeset/olive-months-admire.md @@ -0,0 +1,6 @@ +--- +'storybook-pages': minor +'@smile/haring-react': minor +--- + +Renamed components into Zone, DynamicZone, and the example page into FormDynamicZone, added example page with animations using AutoAnimate diff --git a/package-lock.json b/package-lock.json index de8c08c9..2981c0f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3453,6 +3453,11 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" }, + "node_modules/@formkit/auto-animate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.2.tgz", + "integrity": "sha512-SwPWfeRa5veb1hOIBMdzI+73te5puUBHmqqaF1Bu7FjvxlYSz/kJcZKSa9Cg60zL0uRNeJL2SbRxV6Jp6Q1nFQ==" + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -36084,6 +36089,7 @@ "version": "0.15.0", "license": "LGPL-3.0", "dependencies": { + "@formkit/auto-animate": "^0.8.2", "@hookform/error-message": "^2.0.1", "@mantine/carousel": "^7.11.0", "@mantine/charts": "^7.11.0", diff --git a/packages/haring-react/src/Components/DynamicZone/DynamicZone.mock.tsx b/packages/haring-react/src/Components/DynamicZone/DynamicZone.mock.tsx new file mode 100644 index 00000000..2690b082 --- /dev/null +++ b/packages/haring-react/src/Components/DynamicZone/DynamicZone.mock.tsx @@ -0,0 +1,133 @@ +import type { + IBaseBlock, + IBaseBlockFull, + IDynamicZoneBlock, +} from '../../types'; +import type { ReactElement } from 'react'; + +import { Group } from '@mantine/core'; +import { Cube, Leaf } from '@phosphor-icons/react'; + +export interface IExampleBlock extends IBaseBlock { + value?: string; +} + +export const dynamicZoneBlocksMock: IBaseBlockFull[] = [ + { + blockHeader: ( + <> + + Example A + + ), + blockType: 'exampleA', + id: '0', + opened: true, + value: 'existing value', + }, + { + blockHeader: ( + <> + + Example A + + ), + blockType: 'exampleA', + id: '1', + opened: false, + }, + { + blockHeader: ( + <> + + Example B + + ), + blockType: 'exampleB', + id: '2', + opened: true, + value: 'selectB', + }, +]; + +export const dynamicZoneAvailableBlocksMock: IDynamicZoneBlock[] = + [ + { + block: { + blockType: 'exampleA', + opened: true, + value: '', + }, + blockButtonOptions: { + blockType: 'exampleA', + label: 'Example A', + leftSection: , + }, + blockCardOptions: { + blockHeader: ( + <> + + Example A + + ), + }, + renderFunc: (b: IExampleBlock, i: number): ReactElement => { + return ( + + + + + ); + }, + }, + { + block: { + blockType: 'exampleB', + opened: true, + value: '', + }, + blockButtonOptions: { + blockType: 'exampleB', + label: 'Example B', + leftSection: , + maxInstances: 1, + tooltipLabel: (b) => (b.disabled ? 'Cannot add more than 1' : ''), + variant: 'outline', + }, + blockCardOptions: { + blockHeader: ( + <> + + Example B + + ), + }, + renderFunc: (b: IExampleBlock, i: number): ReactElement => { + return ( + + ); + }, + }, + ]; diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx b/packages/haring-react/src/Components/DynamicZone/DynamicZone.stories.tsx similarity index 69% rename from packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx rename to packages/haring-react/src/Components/DynamicZone/DynamicZone.stories.tsx index a42a5e5e..c6b00748 100644 --- a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx +++ b/packages/haring-react/src/Components/DynamicZone/DynamicZone.stories.tsx @@ -1,24 +1,27 @@ -import type { IExampleBlock } from './FormDynamicZone.mock'; +import type { IExampleBlock } from './DynamicZone.mock'; import type { Meta, StoryObj } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { FormDynamicZone as Cmp } from './FormDynamicZone'; -import { availableBlocksMock, blocksMock } from './FormDynamicZone.mock'; +import { DynamicZone as Cmp } from './DynamicZone'; +import { + dynamicZoneAvailableBlocksMock, + dynamicZoneBlocksMock, +} from './DynamicZone.mock'; const meta = { component: Cmp, tags: ['autodocs'], - title: '3-custom/Form/FormDynamicZone', + title: '3-custom/Components/DynamicZone', } satisfies Meta>; export default meta; type IStory = StoryObj; -export const FormDynamicZone: IStory = { +export const DynamicZone: IStory = { args: { - availableBlocks: availableBlocksMock, - blocksArray: blocksMock, + availableBlocks: dynamicZoneAvailableBlocksMock, + blocksArray: dynamicZoneBlocksMock, onAppendUpdate: action('append'), onRemoveUpdate: action('remove'), onSwapUpdate: action('swap'), @@ -28,8 +31,8 @@ export const FormDynamicZone: IStory = { export const CustomInternalProps: IStory = { args: { - availableBlocks: availableBlocksMock, - blocksArray: blocksMock, + availableBlocks: dynamicZoneAvailableBlocksMock, + blocksArray: dynamicZoneBlocksMock, internalDynamicZoneProps: { internalBlockComponentProps: { headerActionListProps: { diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx b/packages/haring-react/src/Components/DynamicZone/DynamicZone.test.tsx similarity index 54% rename from packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx rename to packages/haring-react/src/Components/DynamicZone/DynamicZone.test.tsx index 475893a3..4ee76028 100644 --- a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx +++ b/packages/haring-react/src/Components/DynamicZone/DynamicZone.test.tsx @@ -1,17 +1,20 @@ -import type { IExampleBlock } from './FormDynamicZone.mock'; +import type { IExampleBlock } from './DynamicZone.mock'; import { renderWithProviders } from '@smile/haring-react-shared/test-utils'; import { action } from '@storybook/addon-actions'; -import { FormDynamicZone } from './FormDynamicZone'; -import { availableBlocksMock, blocksMock } from './FormDynamicZone.mock'; +import { DynamicZone } from './DynamicZone'; +import { + dynamicZoneAvailableBlocksMock, + dynamicZoneBlocksMock, +} from './DynamicZone.mock'; -describe('FormDynamicZone', () => { +describe('DynamicZone', () => { it('matches snapshot', () => { const { container } = renderWithProviders( - - availableBlocks={availableBlocksMock} - blocksArray={blocksMock} + + availableBlocks={dynamicZoneAvailableBlocksMock} + blocksArray={dynamicZoneBlocksMock} onAppendUpdate={action('append')} onRemoveUpdate={action('remove')} onSwapUpdate={action('swap')} diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx b/packages/haring-react/src/Components/DynamicZone/DynamicZone.tsx similarity index 76% rename from packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx rename to packages/haring-react/src/Components/DynamicZone/DynamicZone.tsx index e40d6aee..7299bf59 100644 --- a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx +++ b/packages/haring-react/src/Components/DynamicZone/DynamicZone.tsx @@ -2,14 +2,14 @@ import type { IBaseBlock, IBaseBlockButtonOptions, IBaseBlockFull, - IFormDynamicZoneBlock, + IDynamicZoneBlock, } from '../../types'; -import type { IDynamicZoneInternalComponentProps } from '../DynamicZone/DynamicZone'; -import type { IBaseBlockType } from '@smile/haring-react'; +import type { IZoneInternalComponentProps } from '../Zone/Zone'; import type { - IDynamicZoneBlockInternalComponentProps, - IDynamicZoneBlockReference, -} from '@smile/haring-react/src/Form/DynamicZone/DynamicZoneBlock/DynamicZoneBlock'; + IZoneBlockInternalComponentProps, + IZoneBlockReference, +} from '../Zone/ZoneBlock/ZoneBlock'; +import type { IBaseBlockType } from '@smile/haring-react'; import type { IAction } from '@smile/haring-react-shared'; import type { ReactElement } from 'react'; @@ -17,27 +17,27 @@ import { ArrowDown, ArrowUp, Trash } from '@phosphor-icons/react'; import { isNotNullNorEmpty } from '@smile/haring-react-shared'; import { useMemo } from 'react'; -import { DynamicZone } from '../DynamicZone/DynamicZone'; +import { Zone } from '../Zone/Zone'; -interface IFormDynamicZoneActionLabels { +interface IDynamicZoneActionLabels { deleteLabel: string; moveDownLabel: string; moveUpLabel: string; } -const defaultActionLabels: IFormDynamicZoneActionLabels = { +const defaultActionLabels: IDynamicZoneActionLabels = { deleteLabel: 'Delete', moveDownLabel: 'Move Down', moveUpLabel: 'Move Up', }; -export interface IFormDynamicZoneProps { - actionLabels?: IFormDynamicZoneActionLabels; - availableBlocks: IFormDynamicZoneBlock[]; +export interface IDynamicZoneProps { + actionLabels?: IDynamicZoneActionLabels; + availableBlocks: IDynamicZoneBlock[]; blocksArray: Block[]; internalDynamicZoneProps?: { - internalBlockComponentProps?: IDynamicZoneBlockInternalComponentProps; - internalComponentProps?: IDynamicZoneInternalComponentProps; + internalBlockComponentProps?: IZoneBlockInternalComponentProps; + internalComponentProps?: IZoneInternalComponentProps; }; onAppendUpdate: (newBlock: Block) => void; onRemoveUpdate: (index: number) => void; @@ -45,8 +45,8 @@ export interface IFormDynamicZoneProps { onToggleUpdate: (index: number, opened: boolean) => void; } -export function FormDynamicZone( - props: IFormDynamicZoneProps, +export function DynamicZone( + props: IDynamicZoneProps, ): ReactElement { const { actionLabels = defaultActionLabels, @@ -82,20 +82,17 @@ export function FormDynamicZone( ); if (correspondingType === undefined) { throw Error( - `Could not render a block of blockType '${block.blockType} in given IFormDynamicZoneBlock[]'`, + `Could not render a block of blockType '${block.blockType} in given IDynamicZoneBlock[]'`, ); } return correspondingType.renderFunc(block, index); } - function onRemove(ref: IDynamicZoneBlockReference): void { + function onRemove(ref: IZoneBlockReference): void { onRemoveUpdate(ref.index); } - function onSwap( - ref: IDynamicZoneBlockReference, - direction: 'down' | 'up', - ): void { + function onSwap(ref: IZoneBlockReference, direction: 'down' | 'up'): void { const secondIndex = ref.index + (direction === 'up' ? -1 : 1); if (secondIndex >= 0 && secondIndex < ref.arrayLength) { onSwapUpdate(ref.index, secondIndex); @@ -111,7 +108,7 @@ export function FormDynamicZone( } function isMoveDisabled( - ref: IDynamicZoneBlockReference, + ref: IZoneBlockReference, direction: 'down' | 'up', ): boolean { return direction === 'up' @@ -119,7 +116,7 @@ export function FormDynamicZone( : ref.index === ref.arrayLength - 1; } - const formDynamicZoneDefaultActions: IAction[] = [ + const dynamicZoneDefaultActions: IAction[] = [ { componentProps: (ref) => ({ disabled: isMoveDisabled(ref, 'up') }), icon: , @@ -148,7 +145,7 @@ export function FormDynamicZone( ); if (correspondingType === undefined) { throw Error( - `Could not append a block of blockType '${type} in given IFormDynamicZoneBlock[]'`, + `Could not append a block of blockType '${type} in given IDynamicZoneBlock[]'`, ); } const newBlock = { @@ -162,13 +159,13 @@ export function FormDynamicZone( .filter(isNotNullNorEmpty) .map((b) => ({ ...b, - blockActions: formDynamicZoneDefaultActions, + blockActions: dynamicZoneDefaultActions, ...availableBlocks.find((o) => o.block.blockType === b.blockType) ?.blockCardOptions, })); return ( -
@@ -72,10 +73,12 @@ exports[`DynamicZone matches snapshot 1`] = ` xmlns="http://www.w3.org/2000/svg" > - First + + Example A +
@@ -223,10 +242,12 @@ exports[`DynamicZone matches snapshot 1`] = ` xmlns="http://www.w3.org/2000/svg" > - Second + + Example A +
- +
+ + +
- footer -
+ style="padding: 0rem;" + />
@@ -376,10 +410,12 @@ exports[`DynamicZone matches snapshot 1`] = ` xmlns="http://www.w3.org/2000/svg" > - Third + + Example B +
- footer -
+ style="padding: 0rem;" + />
- Default + Example A - diff --git a/packages/haring-react/src/Form/DynamicZone/DynamicZone.mock.tsx b/packages/haring-react/src/Components/Zone/Zone.mock.tsx similarity index 59% rename from packages/haring-react/src/Form/DynamicZone/DynamicZone.mock.tsx rename to packages/haring-react/src/Components/Zone/Zone.mock.tsx index 54d01eb3..b525f9ee 100644 --- a/packages/haring-react/src/Form/DynamicZone/DynamicZone.mock.tsx +++ b/packages/haring-react/src/Components/Zone/Zone.mock.tsx @@ -1,4 +1,4 @@ -import type { IDynamicZoneBlockReference } from './DynamicZoneBlock/DynamicZoneBlock'; +import type { IZoneBlockReference } from './ZoneBlock/ZoneBlock'; import type { IBaseBlockButtonOptions, IBaseBlockFull } from '../../types'; import type { IAction } from '@smile/haring-react-shared'; @@ -12,7 +12,7 @@ import { } from '@phosphor-icons/react'; import { action } from '@storybook/addon-actions'; -const dynamicZoneBlockActionsMock: IAction[] = [ +const zoneBlockActionsMock: IAction[] = [ { icon: , id: 'move-up', @@ -33,9 +33,8 @@ const dynamicZoneBlockActionsMock: IAction[] = [ }, ]; -export const dynamicZoneBlocks: IBaseBlockFull[] = [ +export const zoneBlocksMock: IBaseBlockFull[] = [ { - blockActions: dynamicZoneBlockActionsMock, blockHeader: ( <> @@ -48,7 +47,6 @@ export const dynamicZoneBlocks: IBaseBlockFull[] = [ value: 'initial', }, { - blockActions: dynamicZoneBlockActionsMock, blockFooter: 'footer', blockHeader: ( <> @@ -62,7 +60,6 @@ export const dynamicZoneBlocks: IBaseBlockFull[] = [ value: 'initial', }, { - blockActions: dynamicZoneBlockActionsMock, blockFooter: 'footer', blockHeader: ( <> @@ -77,7 +74,51 @@ export const dynamicZoneBlocks: IBaseBlockFull[] = [ }, ]; -export const dynamicZoneButtons: IBaseBlockButtonOptions[] = [ +export const withActionsMock: IBaseBlockFull[] = [ + { + blockActions: zoneBlockActionsMock, + blockHeader: ( + <> + + First + + ), + blockType: 'default', + id: '1', + opened: false, + value: 'initial', + }, + { + blockActions: zoneBlockActionsMock, + blockFooter: 'footer', + blockHeader: ( + <> + + Second + + ), + blockType: 'default', + id: '2', + opened: true, + value: 'initial', + }, + { + blockActions: zoneBlockActionsMock, + blockFooter: 'footer', + blockHeader: ( + <> + + Third + + ), + blockType: 'default', + id: '3', + opened: false, + value: 'initial', + }, +]; + +export const zoneButtonsMock: IBaseBlockButtonOptions[] = [ { blockType: 'default', label: 'Default', leftSection: }, { blockType: 'other', label: 'Other', leftSection: }, { blockType: 'stuff', label: 'Stuff', leftSection: }, diff --git a/packages/haring-react/src/Form/DynamicZone/DynamicZone.module.css b/packages/haring-react/src/Components/Zone/Zone.module.css similarity index 100% rename from packages/haring-react/src/Form/DynamicZone/DynamicZone.module.css rename to packages/haring-react/src/Components/Zone/Zone.module.css diff --git a/packages/haring-react/src/Form/DynamicZone/DynamicZone.stories.tsx b/packages/haring-react/src/Components/Zone/Zone.stories.tsx similarity index 62% rename from packages/haring-react/src/Form/DynamicZone/DynamicZone.stories.tsx rename to packages/haring-react/src/Components/Zone/Zone.stories.tsx index abebb507..94021922 100644 --- a/packages/haring-react/src/Form/DynamicZone/DynamicZone.stories.tsx +++ b/packages/haring-react/src/Components/Zone/Zone.stories.tsx @@ -2,22 +2,33 @@ import type { Meta, StoryObj } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { DynamicZone as Cmp } from './DynamicZone'; -import { dynamicZoneBlocks, dynamicZoneButtons } from './DynamicZone.mock'; +import { Zone as Cmp } from './Zone'; +import { withActionsMock, zoneBlocksMock, zoneButtonsMock } from './Zone.mock'; const meta = { component: Cmp, tags: ['autodocs'], - title: '3-custom/Form/DynamicZone', + title: '3-custom/Components/Zone', } satisfies Meta; export default meta; type IStory = StoryObj; -export const DynamicZone: IStory = { +export const Zone: IStory = { args: { - blockOptions: dynamicZoneButtons, - blocks: dynamicZoneBlocks, + blockOptions: zoneButtonsMock, + blocks: zoneBlocksMock, + buttonsText: 'Ajouter un block', + onAppendBlock: action('onAppendBlock, id'), + onRenderBlockContent: (_b, index) => , + onToggleBlock: action('onToggleBlock'), + }, +}; + +export const ZoneWithActions: IStory = { + args: { + blockOptions: zoneButtonsMock, + blocks: withActionsMock, buttonsText: 'Ajouter un block', onAppendBlock: action('onAppendBlock, id'), onRenderBlockContent: (_b, index) => , @@ -27,8 +38,8 @@ export const DynamicZone: IStory = { export const CustomInternalProps: IStory = { args: { - blockOptions: dynamicZoneButtons, - blocks: dynamicZoneBlocks, + blockOptions: zoneButtonsMock, + blocks: withActionsMock, internalBlockComponentProps: { headerActionListProps: { actionIconDefaultProps: { diff --git a/packages/haring-react/src/Form/DynamicZone/DynamicZone.test.tsx b/packages/haring-react/src/Components/Zone/Zone.test.tsx similarity index 73% rename from packages/haring-react/src/Form/DynamicZone/DynamicZone.test.tsx rename to packages/haring-react/src/Components/Zone/Zone.test.tsx index 56e26ef7..7fe485c6 100644 --- a/packages/haring-react/src/Form/DynamicZone/DynamicZone.test.tsx +++ b/packages/haring-react/src/Components/Zone/Zone.test.tsx @@ -5,19 +5,19 @@ import { renderWithProviders } from '@smile/haring-react-shared/test-utils'; import { action } from '@storybook/addon-actions'; import { expect } from '@storybook/jest'; -import { DynamicZone } from './DynamicZone'; -import { dynamicZoneBlocks, dynamicZoneButtons } from './DynamicZone.mock'; +import { Zone } from './Zone'; +import { zoneBlocksMock, zoneButtonsMock } from './Zone.mock'; -describe('DynamicZone', () => { +describe('Zone', () => { it('matches snapshot', () => { const onRender = ( _b: IBaseBlockCardOptions, index: number, ): ReactElement => ; const { container } = renderWithProviders( - ; blockCardProps?: CardProps; blocksStackProps?: StackProps; bottomContainerProps?: ContainerProps; @@ -26,12 +27,12 @@ export interface IDynamicZoneInternalComponentProps { buttonsTextProps?: TextProps; } -export interface IDynamicZoneProps extends ContainerProps { +export interface IZoneProps extends ContainerProps { blockOptions: IBaseBlockButtonOptions[]; blocks: IBaseBlockFull[]; buttonsText?: string; - internalBlockComponentProps?: IDynamicZoneBlockInternalComponentProps; - internalComponentProps?: IDynamicZoneInternalComponentProps; + internalBlockComponentProps?: IZoneBlockInternalComponentProps; + internalComponentProps?: IZoneInternalComponentProps; onAppendBlock: (blockType: IBaseBlockType) => void; onRenderBlockContent: (block: IBaseBlockFull, index: number) => ReactElement; onToggleBlock: ( @@ -41,7 +42,7 @@ export interface IDynamicZoneProps extends ContainerProps { ) => void; } -export function DynamicZone(props: IDynamicZoneProps): ReactElement { +export function Zone(props: IZoneProps): ReactElement { const { blockOptions, blocks, @@ -60,9 +61,13 @@ export function DynamicZone(props: IDynamicZoneProps): ReactElement { return ( - + {blocks.map((block, index) => ( - {onRenderBlockContent(block, index)} - + ))} , + IActionListProps, 'actions' | 'isCompactStyle' | 'selectedElements' >; headerCardSectionProps?: CardSectionProps; headerGroupProps?: GroupProps; - toggleComponentProps?: IDynamicZoneBlockToggleProps; + toggleComponentProps?: IZoneBlockToggleProps; } -export interface IDynamicZoneBlockToggleProps { +export interface IZoneBlockToggleProps { actionIconProps?: ActionIconProps; downIcon?: ReactNode; upIcon?: ReactNode; } -export interface IDynamicZoneBlockReference extends Record { +export interface IZoneBlockReference extends Record { arrayLength: number; id: string; index: number; } -export interface IDynamicZoneBlockProps extends CardProps { - actions?: IAction[]; +export interface IZoneBlockProps extends CardProps { + actions?: IAction[]; children: ReactNode; footerChildren?: ReactNode; headerChildren?: ReactNode; - internalComponentProps?: IDynamicZoneBlockInternalComponentProps; + internalComponentProps?: IZoneBlockInternalComponentProps; onToggle: (opened: boolean) => void; opened: boolean; - reference: IDynamicZoneBlockReference; + reference: IZoneBlockReference; } -export function DynamicZoneBlock(props: IDynamicZoneBlockProps): ReactElement { +export function ZoneBlock(props: IZoneBlockProps): ReactElement { const { actions, children, @@ -72,7 +72,7 @@ export function DynamicZoneBlock(props: IDynamicZoneBlockProps): ReactElement { reference, ...cardProps } = props; - const toggleProps: IDynamicZoneBlockToggleProps = { + const toggleProps: IZoneBlockToggleProps = { downIcon: , upIcon: , ...internalComponentProps?.toggleComponentProps, @@ -103,7 +103,7 @@ export function DynamicZoneBlock(props: IDynamicZoneBlockProps): ReactElement { {headerChildren} {actions && actions.length > 0 ? ( - + actions={actions} isCompactStyle selectedElements={reference} diff --git a/packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap b/packages/haring-react/src/Components/Zone/__snapshots__/Zone.test.tsx.snap similarity index 62% rename from packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap rename to packages/haring-react/src/Components/Zone/__snapshots__/Zone.test.tsx.snap index 9a8ea739..cc77fbf4 100644 --- a/packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap +++ b/packages/haring-react/src/Components/Zone/__snapshots__/Zone.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FormDynamicZone matches snapshot 1`] = ` +exports[`Zone matches snapshot 1`] = `