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;
})();