adobe/react-spectrum

Allow providing generic FocusableProps type in DateRangePicker

Open

#5766 aperta il 29 gen 2024

Vedi su GitHub
 (2 commenti) (0 reazioni) (0 assegnatari)TypeScript (1500 fork)auto 404
help wantedtypescript

Metriche repository

Star
 (15.634 star)
Metriche merge PR
 (Metriche PR in attesa)

Descrizione

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

Guida contributor