diff --git a/docs/docs/blocks/blocks-in-forms.mdx b/docs/docs/blocks/blocks-in-forms.mdx new file mode 100644 index 0000000000..09ecfe9d09 --- /dev/null +++ b/docs/docs/blocks/blocks-in-forms.mdx @@ -0,0 +1,124 @@ +--- +title: Blocks in forms +sidebar_position: 6 +--- + +# Using blocks in forms + +This guide describes how to use a block in a Final Form. +We use a product form with a `DamImageBlock` as an example. +The product has the following schema in GraphQL: + +```graphql +type Product { + id: ID! + title: String! + // highlight-next-line + image: DamImageBlockData! +} +``` + +The following steps are necessary to add the `image` field to the form: + +1. Create a Final Form component for the block +2. Create the block state when initializing the form +3. Create the block output when submitting the form + +:::info + +The block transitions between the various states when being used in a form. +The states and transitions can be viewed [here](/docs/blocks/lifecycle#the-block-in-the-admin). + +::: + +## Create a Final Form component for the block + +The block's `AdminComponent` API (`state`, `updateState`) must be converted to the `Field` API (`input.value`, `input.onChange`). +Use the [createFinalFormBlock](https://github.com/vivid-planet/comet/blob/main/packages/admin/blocks-admin/src/form/createFinalFormBlock.tsx) helper for this: + +```tsx +import { createFinalFormBlock } from "@comet/blocks-admin"; + +const FinalFormDamImageBlock = createFinalFormBlock(DamImageBlock); +``` + +Use the newly created component in the corresponding `Field` via the `component` prop: + +```tsx +import isEqual from "lodash.isequal"; + +; +``` + +:::note + +A deep equality check using `isEqual` is necessary because the block state is an object. + +::: + +## Create the block state when initializing the form + +The block state needs to be created when initializing the form. +If a product exists (i.e., in edit mode), transform the block input to the block state. +When creating a new product, use the block's default values: + +```tsx +import { BlockState } from "@comet/blocks-admin"; +import isEqual from "lodash.isequal"; + +type FormValues = Omit & { + // highlight-next-line + image: BlockState; +}; + +const { data } = useQuery(productFormQuery, id ? { variables: { id } } : { skip: true }); + +const initialValues = useMemo>( + () => + data?.product + ? { + ...filterByFragment(productFormFragment, data.product), + // highlight-next-line + image: DamImageBlock.input2State(data.product.image), + } + : { + inStock: false, + // highlight-next-line + image: DamImageBlock.defaultValues(), + }, + [data], +); + +; +``` + +:::note + +A deep equality check using `initialValuesEqual` is necessary when using blocks in a form. + +::: + +## Create the block output when submitting the form + +Transform the block state to the block output before submitting the form: + +```tsx +const handleSubmit = async (values: FormValues) => { + const input = { + ...values, + // highlight-next-line + image: DamImageBlock.state2Output(values.image), + }; + + /* Create or update the product... */ +}; +``` diff --git a/docs/docs/blocks/composition.mdx b/docs/docs/blocks/composition.mdx index 18fbf95665..07a0db9a10 100644 --- a/docs/docs/blocks/composition.mdx +++ b/docs/docs/blocks/composition.mdx @@ -1,6 +1,6 @@ --- title: Composition -sidebar_position: 4 +sidebar_position: 5 --- # Composing blocks diff --git a/docs/docs/blocks/lifecycle.mdx b/docs/docs/blocks/lifecycle.mdx index a0a994c4d6..c168acca1f 100644 --- a/docs/docs/blocks/lifecycle.mdx +++ b/docs/docs/blocks/lifecycle.mdx @@ -1,6 +1,6 @@ --- title: Lifecycle -sidebar_position: 5 +sidebar_position: 7 --- # Deep dive: A block's lifecycle