diff --git a/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/TasksFormBuilder.tsx b/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/TasksFormBuilder.tsx index 52a039ec68e7..25df2cffe80c 100644 --- a/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/TasksFormBuilder.tsx +++ b/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/TasksFormBuilder.tsx @@ -1,20 +1,19 @@ -import {type CurrentUser, type SanityDocument} from '@sanity/types' +import {type SanityDocument, type SanityDocumentLike} from '@sanity/types' import {Box, rem} from '@sanity/ui' // eslint-disable-next-line camelcase import {getTheme_v2} from '@sanity/ui/theme' import {motion, type Variants} from 'framer-motion' -import {useEffect, useMemo} from 'react' +import {useEffect, useMemo, useState} from 'react' import {styled} from 'styled-components' import {LoadingBlock} from '../../../../components' -import {FormBuilder} from '../../../../form' +import {createPatchChannel, FormBuilder, useCreateForm} from '../../../../form' import {useCurrentUser} from '../../../../store' import {useWorkspace} from '../../../../studio' import {MentionUserProvider, useMentionUser, useTasks, useTasksNavigation} from '../../../context' import {type TaskDocument, type TaskTarget} from '../../../types' import {TasksAddonWorkspaceProvider} from '../addonWorkspace' import {getTargetValue} from '../utils' -import {useTasksFormBuilder} from './useTasksFormBuilder' const VARIANTS: Variants = { hidden: {opacity: 0}, @@ -35,25 +34,42 @@ const FormBuilderRoot = styled(motion.div)((props) => { ` }) +/** + * A partial task document with the `_id` and `_type` fields. + */ +type TaskDocumentInitialValue = Partial & SanityDocumentLike + const TasksFormBuilderInner = ({ documentId, initialValue, }: { documentId: string - currentUser: CurrentUser - initialValue?: Partial + initialValue?: TaskDocumentInitialValue }) => { - const formBuilderProps = useTasksFormBuilder({ - documentType: 'tasks.task', - documentId, - initialValue, - }) + const [patchChannel] = useState(() => createPatchChannel()) + + const { + formState, + onChange, + onPathOpen, + onFocus, + onBlur, + onSetActiveFieldGroup, + onSetCollapsedFieldSet, + onSetCollapsedPath, + collapsedFieldSets, + ready, + collapsedPaths, + schemaType, + value, + } = useCreateForm({documentId, documentType: 'tasks.task', initialValue}) + + const isLoading = formState === null || !ready + // Updates the selected document in the mention user context - to verify the user permissions. const {setSelectedDocument} = useMentionUser() - const target = formBuilderProps.loading - ? undefined - : (formBuilderProps.value?.target as TaskTarget) + const target = isLoading ? undefined : (value?.target as TaskTarget) const targetId = target?.document?._ref const targetType = target?.documentType @@ -67,11 +83,33 @@ const TasksFormBuilderInner = ({ return ( - {formBuilderProps.loading ? ( + {isLoading ? ( ) : ( - + )} @@ -89,7 +127,7 @@ export function TasksFormBuilder() { state: {selectedTask, viewMode, duplicateTaskValues}, } = useTasksNavigation() - const initialValue: Partial | undefined = useMemo(() => { + const initialValue: TaskDocumentInitialValue | undefined = useMemo(() => { if (!currentUser) return undefined if (!selectedTask) return undefined if (viewMode === 'duplicate') { @@ -130,11 +168,7 @@ export function TasksFormBuilder() { // This provider needs to be mounted before the TasksAddonWorkspaceProvider. - + ) diff --git a/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/useTasksFormBuilder.ts b/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/useTasksFormBuilder.ts deleted file mode 100644 index 37001003c455..000000000000 --- a/packages/sanity/src/core/tasks/components/form/tasksFormBuilder/useTasksFormBuilder.ts +++ /dev/null @@ -1,148 +0,0 @@ -import {type ObjectSchemaType, type Path} from '@sanity/types' -import {useCallback, useEffect, useRef, useState} from 'react' - -import { - createPatchChannel, - type FormBuilderProps, - type FormDocumentValue, - type PatchEvent, - setAtPath, - type StateTree, - toMutationPatches, - useFormState, -} from '../../../../form' -import { - useConnectionState, - useDocumentOperation, - useEditState, - useSchema, - useValidationStatus, -} from '../../../../hooks' -import {type DocumentPresence} from '../../../../store' -import {useUnique} from '../../../../util' -import {type TaskDocument} from '../../../types' - -type TasksFormBuilder = - | (FormBuilderProps & { - loading?: undefined - }) - | { - loading: true - } - -interface TasksFormBuilderOptions { - documentType: string - documentId: string - initialValue?: Partial -} - -export function useTasksFormBuilder(options: TasksFormBuilderOptions): TasksFormBuilder { - const {documentType = 'tasks.task', documentId, initialValue = {}} = options - const schema = useSchema() - - const tasksSchemaType = schema.get(documentType) as ObjectSchemaType | undefined - if (!tasksSchemaType) { - throw new Error(`Schema type for '${documentType}' not found`) - } - - const {validation: validationRaw} = useValidationStatus(documentId, documentType) - const validation = useUnique(validationRaw) - const [focusPath, setFocusPath] = useState([]) - const [openPath, setOpenPath] = useState([]) - const [collapsedPaths, onSetCollapsedPath] = useState>() - const [collapsedFieldSets, onSetCollapsedFieldSets] = useState>() - const [fieldGroupState, onSetFieldGroupState] = useState>() - const [presence] = useState([]) - - const handleFocus = useCallback( - (nextFocusPath: Path) => { - setFocusPath(nextFocusPath) - // presenceStore.setLocation([..... - }, - [setFocusPath], - ) - const handleBlur = useCallback(() => { - setFocusPath([]) - }, []) - - const handleOnSetCollapsedPath = useCallback((path: Path, collapsed: boolean) => { - onSetCollapsedPath((prevState) => setAtPath(prevState, path, collapsed)) - }, []) - - const handleOnSetCollapsedFieldSet = useCallback((path: Path, collapsed: boolean) => { - onSetCollapsedFieldSets((prevState) => setAtPath(prevState, path, collapsed)) - }, []) - - const handleSetActiveFieldGroup = useCallback( - (path: Path, groupName: string) => - onSetFieldGroupState((prevState) => setAtPath(prevState, path, groupName)), - [], - ) - - const {patch} = useDocumentOperation(documentId, documentType) - const patchRef = useRef<(event: PatchEvent) => void>(() => { - throw new Error( - 'Attempted to patch the Sanity document during initial render. Input components should only call `onChange()` in an effect or a callback.', - ) - }) - useEffect(() => { - patchRef.current = (event: PatchEvent) => { - patch.execute(toMutationPatches(event.patches), initialValue) - } - }, [initialValue, patch]) - - const handleChange = useCallback((event: PatchEvent) => patchRef.current(event), []) - - const connectionState = useConnectionState(documentId, documentType) - const editState = useEditState(documentId, documentType) - - const documentValue = editState?.draft || editState?.published || initialValue - - const formState = useFormState({ - schemaType: tasksSchemaType, - documentValue, - comparisonValue: documentValue, - readOnly: false, - changesOpen: false, - presence, - focusPath, - openPath, - collapsedPaths, - collapsedFieldSets, - fieldGroupState, - validation, - }) - - const ready = editState.ready && connectionState === 'connected' - - const [patchChannel] = useState(() => createPatchChannel()) - if (formState === null || !ready) { - return {loading: true} - } - - return { - id: 'root', - onChange: handleChange, - // eslint-disable-next-line camelcase - __internal_patchChannel: patchChannel, - // eslint-disable-next-line camelcase - __internal_fieldActions: undefined, - onPathFocus: handleFocus, - onPathOpen: setOpenPath, - onPathBlur: handleBlur, - onFieldGroupSelect: handleSetActiveFieldGroup, - onSetFieldSetCollapsed: handleOnSetCollapsedFieldSet, - onSetPathCollapsed: handleOnSetCollapsedPath, - collapsedPaths, - collapsedFieldSets, - focusPath: formState.focusPath, - changed: formState.changed, - focused: formState.focused, - groups: formState.groups, - validation: formState.validation, - members: formState.members, - presence: formState.presence, - schemaType: tasksSchemaType, - value: formState.value as FormDocumentValue, - } -}