import * as React from 'react'; import Picker, { ExportedPickerProps } from './Picker'; import { ParsableDate } from '../constants/prop-types'; import { MuiPickersAdapter } from '../_shared/hooks/useUtils'; import { parsePickerInputValue } from '../_helpers/date-utils'; import { withDefaultProps } from '../_shared/withDefaultProps'; import { KeyboardDateInput } from '../_shared/KeyboardDateInput'; import { SomeWrapper, ExtendWrapper } from '../wrappers/Wrapper'; import { ResponsiveWrapper } from '../wrappers/ResponsiveWrapper'; import { withDateAdapterProp } from '../_shared/withDateAdapterProp'; import { makeWrapperComponent } from '../wrappers/makeWrapperComponent'; import { PureDateInput, DateInputProps } from '../_shared/PureDateInput'; import { usePickerState, PickerStateValueManager } from '../_shared/hooks/usePickerState'; import { AnyPickerView, AllSharedPickerProps, ToolbarComponentProps } from './SharedPickerProps'; type AllAvailableForOverrideProps = ExportedPickerProps; export type AllPickerProps = T & AllSharedPickerProps & ExtendWrapper; export interface MakePickerOptions { name: string; /** * Hook that running validation for the `value` and input. */ useValidation: (value: ParsableDate, props: T) => string | null; /** * Intercept props to override or inject default props specifically for picker. */ useInterceptProps: (props: AllPickerProps) => AllPickerProps & { inputFormat: string }; DefaultToolbarComponent: React.ComponentType; } const valueManager: PickerStateValueManager = { emptyValue: null, parseInput: parsePickerInputValue, areValuesEqual: (utils: MuiPickersAdapter, a: unknown, b: unknown) => utils.isEqual(a, b), }; export type SharedPickerProps = ExtendWrapper & AllSharedPickerProps, TDate | null> & React.RefAttributes; type PickerComponent< TViewProps extends AllAvailableForOverrideProps, TWrapper extends SomeWrapper > = (props: TViewProps & SharedPickerProps) => JSX.Element; export function makePickerWithStateAndWrapper< T extends AllAvailableForOverrideProps, TWrapper extends SomeWrapper = typeof ResponsiveWrapper >( Wrapper: TWrapper, { name, useInterceptProps, useValidation, DefaultToolbarComponent }: MakePickerOptions ): PickerComponent { const WrapperComponent = makeWrapperComponent>(Wrapper, { KeyboardDateInputComponent: KeyboardDateInput, PureDateInputComponent: PureDateInput, }); function PickerWithState( __props: T & AllSharedPickerProps, TDate> & ExtendWrapper ) { const allProps = useInterceptProps(__props) as AllPickerProps; const validationError = useValidation(allProps.value, allProps) !== null; const { pickerProps, inputProps, wrapperProps } = usePickerState, TDate>( allProps, valueManager as PickerStateValueManager, TDate> ); // Note that we are passing down all the value without spread. // It saves us >1kb gzip and make any prop available automatically on any level down. const { value, onChange, ...other } = allProps; const AllDateInputProps = { ...inputProps, ...other, validationError }; return ( ); } const FinalPickerComponent = withDefaultProps({ name }, withDateAdapterProp(PickerWithState)); // @ts-ignore Simply ignore generic values in props, because it is impossible // to keep generics without additional cast when using forwardRef // @see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/35834 return React.forwardRef>( (props, ref) => ); }