forked from cerc-io/snowballtools-base
[T-4845: feat] Date picker component (#97)
* ⚡️ feat: create calendar icon for date picker * ⚡️ feat: create date picker component * 📝 docs: add date picker to the example page * 🔧 chore: install `@radix-ui/react-popover`
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
"@material-tailwind/react": "^2.1.7",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-radio-group": "^1.1.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from './CustomIcon';
|
||||
|
||||
export const CalendarIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="18"
|
||||
height="19"
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5 0C5.55228 0 6 0.447715 6 1V2H12V1C12 0.447715 12.4477 0 13 0C13.5523 0 14 0.447715 14 1V2H16C17.1046 2 18 2.89543 18 4V17C18 18.1046 17.1046 19 16 19H2C0.89543 19 0 18.1046 0 17V4C0 2.89543 0.895431 2 2 2H4V1C4 0.447715 4.44772 0 5 0ZM2 9V17H16V9H2Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
||||
@@ -9,6 +9,7 @@ export * from './WarningIcon';
|
||||
export * from './SearchIcon';
|
||||
export * from './CrossIcon';
|
||||
export * from './GlobeIcon';
|
||||
export * from './CalendarIcon';
|
||||
export * from './CheckRoundFilledIcon';
|
||||
export * from './InfoRoundFilledIcon';
|
||||
export * from './LoadingIcon';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { VariantProps, tv } from 'tailwind-variants';
|
||||
|
||||
export const datePickerTheme = tv({
|
||||
slots: {
|
||||
input: [],
|
||||
},
|
||||
});
|
||||
|
||||
export type DatePickerTheme = VariantProps<typeof datePickerTheme>;
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './DatePicker';
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
renderInlineNotifications,
|
||||
} from './renders/inlineNotifications';
|
||||
import { renderInputs } from './renders/input';
|
||||
import { DatePicker } from 'components/shared/DatePicker';
|
||||
import { renderToast, renderToastsWithCta } from './renders/toast';
|
||||
import { renderTooltips } from './renders/tooltip';
|
||||
|
||||
@@ -61,7 +62,7 @@ const Page = () => {
|
||||
|
||||
<div className="w-full h border border-gray-200 px-20 my-10" />
|
||||
|
||||
{/* Button */}
|
||||
{/* Tooltip */}
|
||||
<div className="flex flex-col gap-10 items-center justify-between">
|
||||
<h1 className="text-2xl font-bold">Tooltip</h1>
|
||||
<div className="flex w-full flex-wrap max-w-[680px] justify-center gap-10">
|
||||
@@ -152,6 +153,16 @@ const Page = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl font-bold">Date Picker</h1>
|
||||
<div className="flex flex-col gap-10 items-center justify-center">
|
||||
<DatePicker value={singleDate} onChange={setSingleDate} />
|
||||
<DatePicker
|
||||
selectRange
|
||||
value={dateRange}
|
||||
onChange={setDateRange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full h border border-gray-200 px-20 my-10" />
|
||||
|
||||
Reference in New Issue
Block a user