adobe/react-spectrum

Allow providing generic FocusableProps type in DateRangePicker

Open

#5.766 aberto em 29 de jan. de 2024

Ver no GitHub
 (2 comments) (0 reactions) (0 assignees)TypeScript (1.500 forks)auto 404
help wantedtypescript

Métricas do repositório

Stars
 (15.634 stars)
Métricas de merge de PR
 (Métricas PR pendentes)

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

Guia do colaborador