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`.
102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
'use client'
|
|
import type { TextareaFieldClientComponent, TextareaFieldValidation } from 'payload'
|
|
|
|
import { getTranslation } from '@payloadcms/translations'
|
|
import React, { useCallback, useMemo } from 'react'
|
|
|
|
import type { TextAreaInputProps } from './types.js'
|
|
|
|
import { useField } from '../../forms/useField/index.js'
|
|
import { withCondition } from '../../forms/withCondition/index.js'
|
|
import { useConfig } from '../../providers/Config/index.js'
|
|
import { useLocale } from '../../providers/Locale/index.js'
|
|
import { useTranslation } from '../../providers/Translation/index.js'
|
|
import { mergeFieldStyles } from '../mergeFieldStyles.js'
|
|
import './index.scss'
|
|
import { isFieldRTL } from '../shared/index.js'
|
|
import { TextareaInput } from './Input.js'
|
|
|
|
export { TextareaInput, TextAreaInputProps }
|
|
|
|
const TextareaFieldComponent: TextareaFieldClientComponent = (props) => {
|
|
const {
|
|
field,
|
|
field: {
|
|
admin: { className, description, placeholder, rows, rtl } = {},
|
|
label,
|
|
localized,
|
|
maxLength,
|
|
minLength,
|
|
required,
|
|
},
|
|
path,
|
|
readOnly,
|
|
validate,
|
|
} = props
|
|
|
|
const { i18n } = useTranslation()
|
|
|
|
const {
|
|
config: { localization },
|
|
} = useConfig()
|
|
|
|
const locale = useLocale()
|
|
|
|
const isRTL = isFieldRTL({
|
|
fieldLocalized: localized,
|
|
fieldRTL: rtl,
|
|
locale,
|
|
localizationConfig: localization || undefined,
|
|
})
|
|
|
|
const memoizedValidate: TextareaFieldValidation = useCallback(
|
|
(value, options) => {
|
|
if (typeof validate === 'function') {
|
|
return validate(value, { ...options, maxLength, minLength, required })
|
|
}
|
|
},
|
|
[validate, required, maxLength, minLength],
|
|
)
|
|
|
|
const {
|
|
customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {},
|
|
disabled,
|
|
setValue,
|
|
showError,
|
|
value,
|
|
} = useField<string>({
|
|
path,
|
|
validate: memoizedValidate,
|
|
})
|
|
|
|
const styles = useMemo(() => mergeFieldStyles(field), [field])
|
|
|
|
return (
|
|
<TextareaInput
|
|
AfterInput={AfterInput}
|
|
BeforeInput={BeforeInput}
|
|
className={className}
|
|
Description={Description}
|
|
description={description}
|
|
Error={Error}
|
|
Label={Label}
|
|
label={label}
|
|
localized={localized}
|
|
onChange={(e) => {
|
|
setValue(e.target.value)
|
|
}}
|
|
path={path}
|
|
placeholder={getTranslation(placeholder, i18n)}
|
|
readOnly={readOnly || disabled}
|
|
required={required}
|
|
rows={rows}
|
|
rtl={isRTL}
|
|
showError={showError}
|
|
style={styles}
|
|
value={value}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export const TextareaField = withCondition(TextareaFieldComponent)
|