Requesting code review for RAC date picker customization #4914
-
Gday folks, long story short ive kinda hijacked the RAC DatePicker and DatePickerRange components in such a way that ive removed the segments and am left with just the button, whos label is a formated date or date value (ie. 3 Aug 2023 instead of 03-08-2023). Storybook isn't complaining about the accessibility and by all appearances it works like a charm. however theres that part of me that needs a little vindication to make sure im not setting myself for disaster by using the spray can in a manner other than directed....id of pushed this up into a codesandbox, however i got no idea how to get tailwind to work in that damn thing so this will have to suffice. Cheers folks. import { type DateValue } from "@internationalized/date";
import { RangeValue } from "@react-types/shared";
import { Fragment, useMemo, useRef, useState } from "react";
import { useDateFormatter } from "react-aria";
import { Button, DateRangePicker, Dialog } from "react-aria-components";
import { RangeCalendar } from "../../date-time";
import { Icon } from "../../display";
import { Popover } from "../../overlays";
import { dateSelectStyles } from "../date-select/date-select.styles";
import { FieldIcon } from "../field-icon";
import { FieldLabel } from "../field-label";
import { FieldMessage } from "../field-message";
import { getMinDate, parseSQLDateString } from "../utils";
import { DEFAULT_RANGE } from "./date-range-select.const";
import type { DateRangeSelectProps } from "./date-range-select.types";
import { formatDateRange } from "./date-range-select.utils";
export function DateRangeSelect({
defaultOpen,
description,
errorMessage,
hideLabel = false,
icon,
isOpen: _isOpen,
label,
maxValue,
minValue,
...props
}: DateRangeSelectProps) {
const triggerRef = useRef<HTMLButtonElement>(null);
const [isOpen, onOpenChange] = useState(Boolean(defaultOpen || _isOpen));
const [value, setValue] = useState<RangeValue<DateValue>>(DEFAULT_RANGE);
const formatter = useDateFormatter({ dateStyle: "medium" });
const formattedDateRange = useMemo(() => {
return formatDateRange(formatter, value);
}, [value, formatter]);
const parsedMaxRange = useMemo(() => {
const parsedMaxDate = parseSQLDateString(maxValue);
const parsedMinDate = parseSQLDateString(minValue);
const baseMinDate = getMinDate(parsedMinDate);
return {
max: parsedMaxDate,
min: baseMinDate,
};
}, [maxValue, minValue]);
const isInvalid = Boolean(errorMessage);
const hasIcon = Boolean(icon);
const { button, buttonIcon, buttonIconWrapper, buttonValue, datePicker } =
dateSelectStyles({ hasIcon, isInvalid });
return (
<DateRangePicker
{...props}
className={datePicker()}
isOpen={isOpen}
maxValue={parsedMaxRange.max}
minValue={parsedMaxRange.min}
onChange={setValue}
onOpenChange={onOpenChange}
value={value}
>
<FieldLabel hidden={hideLabel}>{label}</FieldLabel>
<Button
className={button()}
data-open={isOpen || undefined}
ref={triggerRef}
>
{({ isFocusVisible, isHovered, isPressed }) => (
<Fragment>
{icon && (
<FieldIcon
icon={icon}
isActive={isFocusVisible || isHovered || isPressed || isOpen}
isInvalid={isInvalid}
/>
)}
<span className={buttonValue()}>
{formattedDateRange ?? "Select a date range"}
</span>
<div aria-hidden className={buttonIconWrapper()}>
<Icon.Interface.CalendarSearch className={buttonIcon()} />
</div>
</Fragment>
)}
</Button>
<FieldMessage description={description} errorMessage={errorMessage} />
<Popover
isOpen={isOpen}
onOpenChange={onOpenChange}
triggerRef={triggerRef}
>
<Dialog>
<RangeCalendar aria-label={label} />
</Dialog>
</Popover>
</DateRangePicker>
);
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
If you're not using the date segments I guess I wouldn't use the Pseudo code: let [value, setValue] = useState(...);
<DialogTrigger>
<Button>{formatDateValue(value)}</Button>
<Popover>
<Dialog>
<RangeCalendar value={value} onChange={setValue} />
</Dialog>
</Popover>
</DialogTrigger> |
Beta Was this translation helpful? Give feedback.
If you're not using the date segments I guess I wouldn't use the
DateRangePicker
component at all. You could just use a button that triggers a popover yourself, e.g. usingDialogTrigger
.Pseudo code: