forked from cerc-io/snowballtools-base
⚡️ feat: add onReset
prop
This commit is contained in:
parent
630af612a2
commit
e0c5895e9c
@ -19,6 +19,7 @@ import {
|
|||||||
|
|
||||||
import './Calendar.css';
|
import './Calendar.css';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
import { cn } from 'utils/classnames';
|
||||||
|
|
||||||
type ValuePiece = Date | null;
|
type ValuePiece = Date | null;
|
||||||
export type Value = ValuePiece | [ValuePiece, ValuePiece];
|
export type Value = ValuePiece | [ValuePiece, ValuePiece];
|
||||||
@ -63,6 +64,11 @@ export interface CalendarProps extends CustomReactCalendarProps, CalendarTheme {
|
|||||||
* @returns None
|
* @returns None
|
||||||
*/
|
*/
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
|
/**
|
||||||
|
* Optional callback function that is called when a reset action is triggered.
|
||||||
|
* @returns None
|
||||||
|
*/
|
||||||
|
onReset?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +86,7 @@ export const Calendar = ({
|
|||||||
actions,
|
actions,
|
||||||
onSelect,
|
onSelect,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
onReset,
|
||||||
onChange: onChangeProp,
|
onChange: onChangeProp,
|
||||||
...props
|
...props
|
||||||
}: CalendarProps): JSX.Element => {
|
}: CalendarProps): JSX.Element => {
|
||||||
@ -217,6 +224,11 @@ export const Calendar = ({
|
|||||||
[setValue, setActiveDate, changeNavigationLabel, selectRange],
|
[setValue, setActiveDate, changeNavigationLabel, selectRange],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleReset = useCallback(() => {
|
||||||
|
setValue(null);
|
||||||
|
onReset?.();
|
||||||
|
}, [setValue, onReset]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...wrapperProps}
|
{...wrapperProps}
|
||||||
@ -276,12 +288,20 @@ export const Calendar = ({
|
|||||||
{/* Footer or CTA */}
|
{/* Footer or CTA */}
|
||||||
<div
|
<div
|
||||||
{...footerProps}
|
{...footerProps}
|
||||||
className={footer({ className: footerProps?.className })}
|
className={cn(footer({ className: footerProps?.className }), {
|
||||||
|
'justify-between': value,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
{actions ? (
|
{actions ? (
|
||||||
actions
|
actions
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{value && (
|
||||||
|
<Button variant="danger" onClick={handleReset}>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<div className="space-x-3">
|
||||||
<Button variant="tertiary" onClick={onCancel}>
|
<Button variant="tertiary" onClick={onCancel}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
@ -291,6 +311,7 @@ export const Calendar = ({
|
|||||||
>
|
>
|
||||||
Select
|
Select
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import { VariantProps, tv } from 'tailwind-variants';
|
|||||||
|
|
||||||
export const datePickerTheme = tv({
|
export const datePickerTheme = tv({
|
||||||
slots: {
|
slots: {
|
||||||
input: [],
|
input: ['w-full'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { Input, InputProps } from 'components/shared/Input';
|
import { Input, InputProps } from 'components/shared/Input';
|
||||||
import * as Popover from '@radix-ui/react-popover';
|
import * as Popover from '@radix-ui/react-popover';
|
||||||
import { datePickerTheme } from './DatePicker.theme';
|
import { datePickerTheme } from './DatePicker.theme';
|
||||||
@ -27,6 +27,10 @@ export interface DatePickerProps
|
|||||||
* Whether to allow the selection of a date range.
|
* Whether to allow the selection of a date range.
|
||||||
*/
|
*/
|
||||||
selectRange?: boolean;
|
selectRange?: boolean;
|
||||||
|
/**
|
||||||
|
* Optional callback function that is called when the date picker is reset.
|
||||||
|
*/
|
||||||
|
onReset?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,6 +43,7 @@ export const DatePicker = ({
|
|||||||
calendarProps,
|
calendarProps,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
onReset,
|
||||||
selectRange = false,
|
selectRange = false,
|
||||||
...props
|
...props
|
||||||
}: DatePickerProps) => {
|
}: DatePickerProps) => {
|
||||||
@ -50,16 +55,16 @@ export const DatePicker = ({
|
|||||||
* Renders the value of the date based on the current state of `props.value`.
|
* 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.
|
* @returns {string | undefined} - The formatted date value or `undefined` if `props.value` is falsy.
|
||||||
*/
|
*/
|
||||||
const renderValue = useCallback(() => {
|
const renderValue = useMemo(() => {
|
||||||
if (!value) return undefined;
|
if (!value) return '';
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value
|
return value
|
||||||
.map((date) => format(date as Date, 'dd/MM/yyyy'))
|
.map((date) => format(date as Date, 'dd/MM/yyyy'))
|
||||||
.join(' - ');
|
.join(' - ');
|
||||||
}
|
}
|
||||||
return format(value, 'dd/MM/yyyy');
|
return format(value, 'dd/MM/yyyy');
|
||||||
}, [value]);
|
}, [value, onReset]);
|
||||||
|
console.log(renderValue);
|
||||||
/**
|
/**
|
||||||
* Handles the selection of a date from the calendar.
|
* Handles the selection of a date from the calendar.
|
||||||
*/
|
*/
|
||||||
@ -71,15 +76,20 @@ export const DatePicker = ({
|
|||||||
[setOpen, onChange],
|
[setOpen, onChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleReset = useCallback(() => {
|
||||||
|
setOpen(false);
|
||||||
|
onReset?.();
|
||||||
|
}, [setOpen, onReset]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover.Root open={open}>
|
<Popover.Root open={open}>
|
||||||
<Popover.Trigger>
|
<Popover.Trigger className="w-full">
|
||||||
<Input
|
<Input
|
||||||
{...props}
|
{...props}
|
||||||
rightIcon={<CalendarIcon onClick={() => setOpen(true)} />}
|
rightIcon={<CalendarIcon onClick={() => setOpen(true)} />}
|
||||||
readOnly
|
readOnly
|
||||||
placeholder="Select a date..."
|
placeholder="Select a date..."
|
||||||
value={renderValue()}
|
value={renderValue}
|
||||||
className={input({ className })}
|
className={input({ className })}
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
/>
|
/>
|
||||||
@ -93,6 +103,7 @@ export const DatePicker = ({
|
|||||||
{...calendarProps}
|
{...calendarProps}
|
||||||
selectRange={selectRange}
|
selectRange={selectRange}
|
||||||
value={value}
|
value={value}
|
||||||
|
onReset={handleReset}
|
||||||
onCancel={() => setOpen(false)}
|
onCancel={() => setOpen(false)}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
/>
|
/>
|
||||||
|
@ -2,7 +2,7 @@ import { VariantProps, tv } from 'tailwind-variants';
|
|||||||
|
|
||||||
export const selectTheme = tv({
|
export const selectTheme = tv({
|
||||||
slots: {
|
slots: {
|
||||||
container: ['flex', 'flex-col', 'relative', 'gap-2'],
|
container: ['flex', 'flex-col', 'relative', 'gap-2', 'w-full'],
|
||||||
label: ['text-sm', 'text-elements-high-em'],
|
label: ['text-sm', 'text-elements-high-em'],
|
||||||
description: ['text-xs', 'text-elements-low-em'],
|
description: ['text-xs', 'text-elements-low-em'],
|
||||||
inputWrapper: [
|
inputWrapper: [
|
||||||
|
@ -3,7 +3,6 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
ComponentPropsWithoutRef,
|
ComponentPropsWithoutRef,
|
||||||
useMemo,
|
useMemo,
|
||||||
useCallback,
|
|
||||||
MouseEvent,
|
MouseEvent,
|
||||||
useRef,
|
useRef,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -12,7 +11,7 @@ import { useMultipleSelection, useCombobox } from 'downshift';
|
|||||||
import { SelectTheme, selectTheme } from './Select.theme';
|
import { SelectTheme, selectTheme } from './Select.theme';
|
||||||
import {
|
import {
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
CrossIcon,
|
CrossCircleIcon,
|
||||||
WarningIcon,
|
WarningIcon,
|
||||||
} from 'components/shared/CustomIcon';
|
} from 'components/shared/CustomIcon';
|
||||||
import { cloneIcon } from 'utils/cloneIcon';
|
import { cloneIcon } from 'utils/cloneIcon';
|
||||||
@ -270,11 +269,8 @@ export const Select = ({
|
|||||||
itemToString: (item) => (item && !multiple ? item.label : ''),
|
itemToString: (item) => (item && !multiple ? item.label : ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSelected = useCallback(
|
const isSelected = (item: SelectOption) =>
|
||||||
(item: SelectOption) =>
|
multiple ? selectedItems.includes(item) : selectedItem === item;
|
||||||
multiple ? selectedItems.includes(item) : selectedItem === item,
|
|
||||||
[selectedItems, selectedItem, multiple],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClear = (e: MouseEvent<SVGSVGElement, globalThis.MouseEvent>) => {
|
const handleClear = (e: MouseEvent<SVGSVGElement, globalThis.MouseEvent>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -306,7 +302,7 @@ export const Select = ({
|
|||||||
return (
|
return (
|
||||||
<div className={theme.iconContainer({ class: 'pr-4 right-0' })}>
|
<div className={theme.iconContainer({ class: 'pr-4 right-0' })}>
|
||||||
{clearable && (selectedItems.length > 0 || selectedItem) && (
|
{clearable && (selectedItems.length > 0 || selectedItem) && (
|
||||||
<CrossIcon
|
<CrossCircleIcon
|
||||||
className={theme.icon({ class: 'h-4 w-4' })}
|
className={theme.icon({ class: 'h-4 w-4' })}
|
||||||
onClick={handleClear}
|
onClick={handleClear}
|
||||||
/>
|
/>
|
||||||
@ -318,7 +314,7 @@ export const Select = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}, [cloneIcon, theme, rightIcon]);
|
}, [cloneIcon, theme, rightIcon, selectedItem, selectedItems, clearable]);
|
||||||
|
|
||||||
const renderHelperText = useMemo(
|
const renderHelperText = useMemo(
|
||||||
() => (
|
() => (
|
||||||
|
@ -62,7 +62,9 @@ const SelectItem = forwardRef<HTMLLIElement, SelectItemProps>(
|
|||||||
<p className={theme.label()} data-disabled={disabled}>
|
<p className={theme.label()} data-disabled={disabled}>
|
||||||
{label}
|
{label}
|
||||||
</p>
|
</p>
|
||||||
{orientation === 'horizontal' && <span className={theme.dot()} />}
|
{orientation === 'horizontal' && description && (
|
||||||
|
<span className={theme.dot()} />
|
||||||
|
)}
|
||||||
{description && (
|
{description && (
|
||||||
<p className={theme.description()} data-disabled={disabled}>
|
<p className={theme.description()} data-disabled={disabled}>
|
||||||
{description}
|
{description}
|
||||||
|
Loading…
Reference in New Issue
Block a user