### What? Ensures `path` is required and only present on the fields that expect it (all fields except row). Deprecates `useFieldComponents` and `FieldComponentsProvider` and instead extends the RenderField component to account for all field types. This also improves type safety within `RenderField`. ### Why? `path` being optional just adds DX overhead and annoyance. ### How? Added `FieldPaths` type which is added to iterable field types. Placed `path` back onto the ClientFieldBase type.
103 lines
2.9 KiB
TypeScript
103 lines
2.9 KiB
TypeScript
'use client'
|
|
import type { DateFieldClientComponent, DateFieldValidation } from 'payload'
|
|
|
|
import { getTranslation } from '@payloadcms/translations'
|
|
import React, { useCallback } from 'react'
|
|
|
|
import { DatePickerField } from '../../elements/DatePicker/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 { useTranslation } from '../../providers/Translation/index.js'
|
|
import { fieldBaseClass } from '../shared/index.js'
|
|
import './index.scss'
|
|
|
|
const baseClass = 'date-time-field'
|
|
|
|
const DateTimeFieldComponent: DateFieldClientComponent = (props) => {
|
|
const {
|
|
field: {
|
|
name,
|
|
admin: { className, date: datePickerProps, description, placeholder, style, width } = {},
|
|
label,
|
|
localized,
|
|
required,
|
|
},
|
|
path,
|
|
readOnly,
|
|
validate,
|
|
} = props
|
|
|
|
const { i18n } = useTranslation()
|
|
|
|
const memoizedValidate: DateFieldValidation = useCallback(
|
|
(value, options) => {
|
|
if (typeof validate === 'function') {
|
|
return validate(value, { ...options, required })
|
|
}
|
|
},
|
|
[validate, required],
|
|
)
|
|
|
|
const {
|
|
customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {},
|
|
setValue,
|
|
showError,
|
|
value,
|
|
} = useField<Date>({
|
|
path,
|
|
validate: memoizedValidate,
|
|
})
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
fieldBaseClass,
|
|
baseClass,
|
|
className,
|
|
showError && `${baseClass}--has-error`,
|
|
readOnly && 'read-only',
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
style={{
|
|
...style,
|
|
width,
|
|
}}
|
|
>
|
|
<RenderCustomComponent
|
|
CustomComponent={Label}
|
|
Fallback={<FieldLabel label={label} localized={localized} required={required} />}
|
|
/>
|
|
<div className={`${fieldBaseClass}__wrap`} id={`field-${path.replace(/\./g, '__')}`}>
|
|
<RenderCustomComponent
|
|
CustomComponent={Error}
|
|
Fallback={<FieldError path={path} showError={showError} />}
|
|
/>
|
|
{BeforeInput}
|
|
<DatePickerField
|
|
{...datePickerProps}
|
|
onChange={(incomingDate) => {
|
|
if (!readOnly) {
|
|
setValue(incomingDate?.toISOString() || null)
|
|
}
|
|
}}
|
|
placeholder={getTranslation(placeholder, i18n)}
|
|
readOnly={readOnly}
|
|
value={value}
|
|
/>
|
|
{AfterInput}
|
|
</div>
|
|
<RenderCustomComponent
|
|
CustomComponent={Description}
|
|
Fallback={<FieldDescription description={description} path={path} />}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const DateTimeField = withCondition(DateTimeFieldComponent)
|