adobe/react-spectrum

Allow providing generic FocusableProps type in DateRangePicker

Open

#5,766 创建于 2024年1月29日

在 GitHub 查看
 (2 评论) (0 反应) (0 负责人)TypeScript (1,500 fork)auto 404
help wantedtypescript

仓库指标

Star
 (15,634 star)
PR 合并指标
 (PR 指标待抓取)

描述

Provide a general summary of the feature here

Currently DateRangePicker has props of type DateRangePickerProps which extends AriaDateRangePickerProps -> AriaDatePickerBaseProps -> DatePickerBase -> DateFieldBase which finally extends FocusableProps

DateFieldBase is not allowing FocusableProps to set custom Target element type (it's always Element)

interface DateFieldBase<T extends DateValue> extends InputBase, Validation<MappedDateValue<T>>, FocusableProps, LabelableProps, HelpTextProps, OverlayTriggerProps {
// ommited for brewity
}

This prevents using use of DateRangePicker with libraries like react-final-form, which has onBlur, onFocus event target set as HTMLElement.

Result in type error during compilation:

Type 'FocusEvent<Element, Element>' is not assignable to type 'FocusEvent<HTMLElement, Element>'.

🤔 Expected Behavior?

DateRangePicker, down to DateFieldBase should allow override default Target for FocusableProps.

https://github.com/adobe/react-spectrum/blob/87dbb748cbfd9bd6f53183221b8e2ef96defbfc3/packages/react-aria-components/src/DatePicker.tsx#L156C10-L156C25

😯 Current Behavior

DateFieldBase doesn't allow to specify target element element type (it's always typeof Element)

💁 Possible Solution

interface DateFieldBase<T extends DateValue, Target extends Element> extends InputBase, Validation<MappedDateValue<T>>, FocusableProps<Target>, LabelableProps, HelpTextProps, OverlayTriggerProps {
// ommited for brewity
}

🔦 Context

Creating form wrapper for DateRangePicker using react-final-form is not possible because react-final-form expects onBlur, onFocus event's target to extend HTMLElement:

💻 Examples

import type { DateRange } from 'react-aria';
import { Field } from 'react-final-form';
import { useTranslation } from 'next-i18next';
import { useCountry } from '@colonnade/api';
import { DateRangePicker } from '@colonnade/react-components';
import { GregorianCalendar, parseDate, toCalendar } from '@internationalized/date';
import { OverlayTriggerProps } from '@react-types/overlays';
import { FocusableProps, HelpTextProps, InputBase, LabelableProps, Validation } from '@react-types/shared';

interface TripValues {
	departureDate: string;
	returnDate: string;
}

export const InternationalSingleTrip = () => {
	const { t } = useTranslation('travel');
	const country = useCountry();

	const parseDateRange = (value: DateRange | null): TripValues | null => {
		if (!value) return null;
		return { departureDate: value.start.toString(), returnDate: value.end.toString() };
	};

	const formatDateRange = (value: TripValues | null): DateRange | null => {
		if (!value) return null;

		const start = toCalendar(parseDate(value.departureDate), new GregorianCalendar());
		const end = toCalendar(parseDate(value.returnDate), new GregorianCalendar());

		return { start, end };
	};

	return (
		<div>
			<Field<TripValues | null, HTMLElement, DateRange | null>
				name="tripDate"
				startName="departureDate"
				endName="returnDate"
				locale={country}
				parse={parseDateRange}
				format={formatDateRange}
				label={t('pages.tripDetails.basicTripInformation.tripDateRange.label')}
			>
				{({ input, ...otherProps }) => <DateRangePicker {...otherProps} {...input} />}
			</Field>
		</div>
	);
};

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

贡献者指南