UNPKG

@baseplate-dev/ui-components

Version:

Shared UI component library

100 lines 5.29 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { format, parseISO, set } from 'date-fns'; import { useId, useState } from 'react'; import { MdSchedule } from 'react-icons/md'; import { useControllerMerged } from '#src/hooks/use-controller-merged.js'; import { cn } from '#src/utils/index.js'; import { Button } from '../button/button.js'; import { Calendar } from '../calendar/calendar.js'; import { FormControl, FormDescription, FormItem, FormLabel, FormMessage, } from '../form-item/form-item.js'; import { Input } from '../input/input.js'; import { Popover, PopoverContent, PopoverTrigger } from '../popover/popover.js'; /** * Field with label and error states that wraps a Calendar and time input for date-time selection. */ function DateTimePickerField({ className, wrapperClassName, disabled, placeholder = 'Pick date and time', onChange, value, label, error, description, dateTimeFormat = 'PPP pp', showSeconds = false, calendarProps, ref, }) { const addWrapper = label ?? error ?? description; const id = useId(); const [open, setOpen] = useState(false); // Parse string value to Date for internal operations const dateTimeValue = value ? parseISO(value) : undefined; const handleDateSelect = (date) => { if (!date) { onChange?.(undefined); return; } let newDate; if (dateTimeValue) { // Preserve existing time when changing date newDate = set(date, { hours: dateTimeValue.getHours(), minutes: dateTimeValue.getMinutes(), seconds: showSeconds ? dateTimeValue.getSeconds() : 0, }); } else { // Set default time to current time or noon if no current time const now = new Date(); newDate = set(date, { hours: now.getHours(), minutes: now.getMinutes(), seconds: showSeconds ? now.getSeconds() : 0, }); } // Convert to ISO string onChange?.(newDate.toISOString()); }; const handleTimeChange = (timeString) => { if (!dateTimeValue) { // If no date selected, use today's date const today = new Date(); const [hours, minutes, seconds = 0] = timeString .split(':') .map((n) => (n ? Number(n) : 0)); const newDate = set(today, { hours, minutes, seconds: showSeconds ? seconds : 0, }); onChange?.(newDate.toISOString()); return; } const [hours, minutes, seconds = 0] = timeString .split(':') .map((n) => (n ? Number(n) : 0)); const newDate = set(dateTimeValue, { hours, minutes, seconds: showSeconds ? seconds : 0, }); onChange?.(newDate.toISOString()); }; const formatTimeValue = (date) => { if (!date) return ''; const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, '0'); if (showSeconds) { return `${hours}:${minutes}:${seconds}`; } return `${hours}:${minutes}`; }; const inputComponent = (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", "data-empty": !dateTimeValue, disabled: disabled, id: id, ref: ref, className: cn('w-[280px] justify-start text-left font-normal data-[empty=true]:text-muted-foreground', className), children: [_jsx(MdSchedule, {}), dateTimeValue ? (format(dateTimeValue, dateTimeFormat)) : (_jsx("span", { children: placeholder }))] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsxs("div", { className: "space-y-3 p-3", children: [_jsx(Calendar, { mode: "single", selected: dateTimeValue, onSelect: handleDateSelect, captionLayout: "dropdown", ...calendarProps }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium", children: "Time" }), _jsx(Input, { type: "time", step: showSeconds ? 1 : 60, value: formatTimeValue(dateTimeValue), onChange: (e) => { handleTimeChange(e.target.value); }, className: "w-full" })] })] }) })] })); if (addWrapper) { return (_jsxs(FormItem, { error: error, className: cn('flex gap-2', wrapperClassName), children: [_jsx(FormLabel, { children: label }), _jsx(FormControl, { children: inputComponent }), _jsx(FormDescription, { children: description }), _jsx(FormMessage, {})] })); } return inputComponent; } function DateTimePickerFieldController({ control, name, ref, ...rest }) { const { field: fieldProps, fieldState: { error }, } = useControllerMerged({ control, name, }, rest, ref); return (_jsx(DateTimePickerField, { error: error?.message, ...rest, ...fieldProps })); } export { DateTimePickerField, DateTimePickerFieldController }; //# sourceMappingURL=date-time-picker-field.js.map