Files
payloadcms/packages/ui/src/fields/Textarea/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

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)