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`.
105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
'use client'
|
|
import type { CodeFieldClientComponent } from 'payload'
|
|
|
|
import React, { useCallback, useMemo } from 'react'
|
|
|
|
import { CodeEditor } from '../../elements/CodeEditor/index.js'
|
|
import { RenderCustomComponent } from '../../elements/RenderCustomComponent/index.js'
|
|
import { FieldDescription } from '../../fields/FieldDescription/index.js'
|
|
import { FieldError } from '../../fields/FieldError/index.js'
|
|
import { FieldLabel } from '../../fields/FieldLabel/index.js'
|
|
import { useField } from '../../forms/useField/index.js'
|
|
import { withCondition } from '../../forms/withCondition/index.js'
|
|
import { mergeFieldStyles } from '../mergeFieldStyles.js'
|
|
import './index.scss'
|
|
import { fieldBaseClass } from '../shared/index.js'
|
|
|
|
const prismToMonacoLanguageMap = {
|
|
js: 'javascript',
|
|
ts: 'typescript',
|
|
}
|
|
|
|
const baseClass = 'code-field'
|
|
|
|
const CodeFieldComponent: CodeFieldClientComponent = (props) => {
|
|
const {
|
|
field,
|
|
field: {
|
|
admin: { className, description, editorOptions = {}, language = 'javascript' } = {},
|
|
label,
|
|
localized,
|
|
required,
|
|
},
|
|
onMount,
|
|
path,
|
|
readOnly,
|
|
validate,
|
|
} = props
|
|
|
|
const memoizedValidate = useCallback(
|
|
(value, options) => {
|
|
if (typeof validate === 'function') {
|
|
return validate(value, { ...options, required })
|
|
}
|
|
},
|
|
[validate, required],
|
|
)
|
|
|
|
const {
|
|
customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {},
|
|
disabled,
|
|
setValue,
|
|
showError,
|
|
value,
|
|
} = useField({
|
|
path,
|
|
validate: memoizedValidate,
|
|
})
|
|
|
|
const styles = useMemo(() => mergeFieldStyles(field), [field])
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
fieldBaseClass,
|
|
baseClass,
|
|
className,
|
|
showError && 'error',
|
|
(readOnly || disabled) && 'read-only',
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
style={styles}
|
|
>
|
|
<RenderCustomComponent
|
|
CustomComponent={Label}
|
|
Fallback={
|
|
<FieldLabel label={label} localized={localized} path={path} required={required} />
|
|
}
|
|
/>
|
|
<div className={`${fieldBaseClass}__wrap`}>
|
|
<RenderCustomComponent
|
|
CustomComponent={Error}
|
|
Fallback={<FieldError path={path} showError={showError} />}
|
|
/>
|
|
{BeforeInput}
|
|
<CodeEditor
|
|
defaultLanguage={prismToMonacoLanguageMap[language] || language}
|
|
onChange={readOnly || disabled ? () => null : (val) => setValue(val)}
|
|
onMount={onMount}
|
|
options={editorOptions}
|
|
readOnly={readOnly || disabled}
|
|
value={(value as string) || ''}
|
|
/>
|
|
{AfterInput}
|
|
</div>
|
|
<RenderCustomComponent
|
|
CustomComponent={Description}
|
|
Fallback={<FieldDescription description={description} path={path} />}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const CodeField = withCondition(CodeFieldComponent)
|