Files
payloadcms/packages/ui/src/fields/DateTime/index.tsx
Jarrod Flesch bcbca0e44a chore: improves field types (#9172)
### 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.
2024-11-13 13:53:47 -05:00

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)