adobe/react-spectrum

Allow providing generic FocusableProps type in DateRangePicker

Open

#5 766 ouverte le 29 janv. 2024

Voir sur GitHub
 (2 commentaires) (0 réactions) (0 assignés)TypeScript (1 500 forks)auto 404
help wantedtypescript

Métriques du dépôt

Stars
 (15 634 stars)
Métriques de merge PR
 (Métriques PR en attente)

Description

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

Guide contributeur