️ feat: create date picker component

This commit is contained in:
Wahyu Kurniawan 2024-02-22 16:42:05 +07:00
parent 779b660631
commit a8fdd4bb53
No known key found for this signature in database
GPG Key ID: 040A1549143A8E33
3 changed files with 110 additions and 0 deletions

View File

@ -0,0 +1,9 @@
import { VariantProps, tv } from 'tailwind-variants';
export const datePickerTheme = tv({
slots: {
input: [],
},
});
export type DatePickerTheme = VariantProps<typeof datePickerTheme>;

View File

@ -0,0 +1,100 @@
import React, { useCallback, useState } from 'react';
import { Input, InputProps } from 'components/shared/Input';
import * as Popover from '@radix-ui/react-popover';
import { datePickerTheme } from './DatePicker.theme';
import { Calendar, CalendarProps } from 'components/shared/Calendar';
import { CalendarIcon } from 'components/shared/CustomIcon';
import { Value } from 'react-calendar/dist/cjs/shared/types';
import { format } from 'date-fns';
export interface DatePickerProps
extends Omit<InputProps, 'onChange' | 'value'> {
/**
* The props for the calendar component.
*/
calendarProps?: CalendarProps;
/**
* Optional callback function that is called when the value of the input changes.
* @param {string} value - The new value of the input.
* @returns None
*/
onChange?: (value: Value) => void;
/**
* The value of the input.
*/
value?: Value;
/**
* Whether to allow the selection of a date range.
*/
selectRange?: boolean;
}
/**
* A date picker component that allows users to select a date from a calendar.
* @param {DatePickerProps} props - The props for the date picker component.
* @returns The rendered date picker component.
*/
export const DatePicker = ({
className,
calendarProps,
value,
onChange,
selectRange = false,
...props
}: DatePickerProps) => {
const { input } = datePickerTheme();
const [open, setOpen] = useState(false);
/**
* Renders the value of the date based on the current state of `props.value`.
* @returns {string | undefined} - The formatted date value or `undefined` if `props.value` is falsy.
*/
const renderValue = useCallback(() => {
if (!value) return undefined;
if (Array.isArray(value)) {
return value
.map((date) => format(date as Date, 'dd/MM/yyyy'))
.join(' - ');
}
return format(value, 'dd/MM/yyyy');
}, [value]);
/**
* Handles the selection of a date from the calendar.
*/
const handleSelect = useCallback(
(date: Value) => {
setOpen(false);
onChange?.(date);
},
[setOpen, onChange],
);
return (
<Popover.Root open={open}>
<Popover.Trigger>
<Input
{...props}
rightIcon={<CalendarIcon onClick={() => setOpen(true)} />}
readOnly
placeholder="Select a date..."
value={renderValue()}
className={input({ className })}
onClick={() => setOpen(true)}
/>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content onInteractOutside={() => setOpen(false)}>
<Calendar
{...calendarProps}
selectRange={selectRange}
value={value}
onCancel={() => setOpen(false)}
onSelect={handleSelect}
/>
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
};

View File

@ -0,0 +1 @@
export * from './DatePicker';