Files
payloadcms/packages/ui/src/elements/DocumentFields/index.tsx
Jacob Fletcher 0b1a1b585b fix(ui): processing and initializing form does not disable standalone fields (#11714)
The form component's `initializing` and `processing` states do not
disable fields that are rendered outside of `DocumentFields`. Fields
currently rely on the `readOnly` prop provided by `DocumentFields` and
do not subscribe to these states for themselves. This means that fields
that are rendered outright, such as within the bulk edit drawer, they do
not receive a `readOnly` prop and are therefore never disabled.

The fix is add a `disabled` property to the `useField` hook. This
subscribes to the `initializing` and `processing` states in the same way
as `DocumentFields`, however, now each field can determine its own
disabled state instead of relying solely on the `readOnly` prop. Adding
this new prop has no overhead as `processing` and `initializing` is
already being subscribed to within `useField`.
2025-03-17 10:27:21 -04:00

107 lines
3.0 KiB
TypeScript

'use client'
import type { ClientField, SanitizedDocumentPermissions } from 'payload'
import { fieldIsSidebar } from 'payload/shared'
import React, { useMemo } from 'react'
import { useFormInitializing, useFormProcessing } from '../../forms/Form/context.js'
import { RenderFields } from '../../forms/RenderFields/index.js'
import { Gutter } from '../Gutter/index.js'
import './index.scss'
const baseClass = 'document-fields'
type Args = {
readonly AfterFields?: React.ReactNode
readonly BeforeFields?: React.ReactNode
readonly Description?: React.ReactNode
readonly docPermissions: SanitizedDocumentPermissions
readonly fields: ClientField[]
readonly forceSidebarWrap?: boolean
readonly readOnly?: boolean
readonly schemaPathSegments: string[]
}
export const DocumentFields: React.FC<Args> = ({
AfterFields,
BeforeFields,
Description,
docPermissions,
fields,
forceSidebarWrap,
readOnly,
schemaPathSegments,
}) => {
const { hasSidebarFields, mainFields, sidebarFields } = useMemo(() => {
return fields.reduce(
(acc, field) => {
if (fieldIsSidebar(field)) {
acc.sidebarFields.push(field)
acc.mainFields.push(null)
acc.hasSidebarFields = true
} else {
acc.mainFields.push(field)
acc.sidebarFields.push(null)
}
return acc
},
{
hasSidebarFields: false,
mainFields: [] as ClientField[],
sidebarFields: [] as ClientField[],
},
)
}, [fields])
return (
<div
className={[
baseClass,
hasSidebarFields ? `${baseClass}--has-sidebar` : `${baseClass}--no-sidebar`,
forceSidebarWrap && `${baseClass}--force-sidebar-wrap`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__main`}>
<Gutter className={`${baseClass}__edit`}>
{Description ? (
<header className={`${baseClass}__header`}>
<div className={`${baseClass}__sub-header`}>{Description}</div>
</header>
) : null}
{BeforeFields}
<RenderFields
className={`${baseClass}__fields`}
fields={mainFields}
forceRender
parentIndexPath=""
parentPath=""
parentSchemaPath={schemaPathSegments.join('.')}
permissions={docPermissions?.fields}
readOnly={readOnly}
/>
{AfterFields}
</Gutter>
</div>
{hasSidebarFields ? (
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
fields={sidebarFields}
forceRender
parentIndexPath=""
parentPath=""
parentSchemaPath={schemaPathSegments.join('.')}
permissions={docPermissions?.fields}
readOnly={readOnly}
/>
</div>
</div>
</div>
) : null}
</div>
)
}