import type { HTMLAttributes } from "react"; import { useFieldValue, useTranslate } from "ra-core"; import { genericMemo } from "@/lib/genericMemo"; import type { FieldProps } from "@/lib/field.type"; const DateFieldImpl = < // eslint-disable-next-line @typescript-eslint/no-explicit-any RecordType extends Record = Record, >( inProps: DateFieldProps, ) => { const { empty, locales, options, showTime = false, showDate = true, transform = defaultTransform, source, record, defaultValue, ...rest } = inProps; const translate = useTranslate(); if (!showTime && !showDate) { throw new Error( " cannot have showTime and showDate false at the same time", ); } const value = useFieldValue({ source, record, defaultValue }); if (value == null || value === "") { if (!empty) { return null; } return ( {typeof empty === "string" ? translate(empty, { _: empty }) : empty} ); } const date = transform(value); let dateString = ""; if (date) { if (showTime && showDate) { dateString = toLocaleStringSupportsLocales ? date.toLocaleString(locales, options) : date.toLocaleString(); } else if (showDate) { // If input is a date string (e.g. '2022-02-15') without time and time zone, // force timezone to UTC to fix issue with people in negative time zones // who may see a different date when calling toLocaleDateString(). const dateOptions = options ?? (typeof value === "string" && value.length <= 10 ? { timeZone: "UTC" } : undefined); dateString = toLocaleStringSupportsLocales ? date.toLocaleDateString(locales, dateOptions) : date.toLocaleDateString(); } else if (showTime) { dateString = toLocaleStringSupportsLocales ? date.toLocaleTimeString(locales, options) : date.toLocaleTimeString(); } } return {dateString}; }; DateFieldImpl.displayName = "DateFieldImpl"; /** * Displays a date value with locale-specific formatting. * * This field automatically formats dates according to the user's locale using Intl.DateTimeFormat. * It supports showing date only, time only, or both, with custom locales and formatting options. * To be used with RecordField or DataTable.Col components, or anywhere a RecordContext is available. * * @see {@link https://marmelab.com/shadcn-admin-kit/docs/datefield/ DateField documentation} * * @example * import { * List, * DataTable, * DateField, * } from '@/components/admin'; * * const PostList = () => ( * * * * * * * * * * * * ); */ export const DateField = genericMemo(DateFieldImpl); export interface DateFieldProps< // eslint-disable-next-line @typescript-eslint/no-explicit-any RecordType extends Record = Record, > extends FieldProps, HTMLAttributes { locales?: Intl.LocalesArgument; options?: Intl.DateTimeFormatOptions; showTime?: boolean; showDate?: boolean; transform?: (value: unknown) => Date; } const defaultTransform = (value: unknown) => value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : undefined; const toLocaleStringSupportsLocales = (() => { // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString try { new Date().toLocaleString("i"); } catch (error) { return error instanceof RangeError; } return false; })();