( props: AriaDateFieldOptions<T>, state: DateFieldState, ref: RefObject<Element | null> )
| 88 | * Each part of a date value is displayed in an individually editable segment. |
| 89 | */ |
| 90 | export function useDateField<T extends DateValue>( |
| 91 | props: AriaDateFieldOptions<T>, |
| 92 | state: DateFieldState, |
| 93 | ref: RefObject<Element | null> |
| 94 | ): DateFieldAria { |
| 95 | let {isInvalid, validationErrors, validationDetails} = state.displayValidation; |
| 96 | let {labelProps, fieldProps, descriptionProps, errorMessageProps} = useField({ |
| 97 | ...props, |
| 98 | labelElementType: 'span', |
| 99 | isInvalid, |
| 100 | errorMessage: props.errorMessage || validationErrors |
| 101 | }); |
| 102 | |
| 103 | let valueOnFocus = useRef<DateValue | null>(null); |
| 104 | let {focusWithinProps} = useFocusWithin({ |
| 105 | ...props, |
| 106 | onFocusWithin(e) { |
| 107 | valueOnFocus.current = state.value; |
| 108 | props.onFocus?.(e); |
| 109 | }, |
| 110 | onBlurWithin: e => { |
| 111 | state.confirmPlaceholder(); |
| 112 | if (state.value !== valueOnFocus.current) { |
| 113 | state.commitValidation(); |
| 114 | } |
| 115 | props.onBlur?.(e); |
| 116 | }, |
| 117 | onFocusWithinChange: props.onFocusChange |
| 118 | }); |
| 119 | |
| 120 | let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/datepicker'); |
| 121 | let message = |
| 122 | state.maxGranularity === 'hour' ? 'selectedTimeDescription' : 'selectedDateDescription'; |
| 123 | let field = state.maxGranularity === 'hour' ? 'time' : 'date'; |
| 124 | let description = state.value |
| 125 | ? stringFormatter.format(message, {[field]: state.formatValue({month: 'long'})}) |
| 126 | : ''; |
| 127 | let descProps = useDescription(description); |
| 128 | |
| 129 | // If within a date picker or date range picker, the date field will have role="presentation" and an aria-describedby |
| 130 | // will be passed in that references the value (e.g. entire range). Otherwise, add the field's value description. |
| 131 | let describedBy = |
| 132 | props[roleSymbol] === 'presentation' |
| 133 | ? fieldProps['aria-describedby'] |
| 134 | : [descProps['aria-describedby'], fieldProps['aria-describedby']].filter(Boolean).join(' ') || |
| 135 | undefined; |
| 136 | let propsFocusManager = props[focusManagerSymbol]; |
| 137 | let focusManager = useMemo( |
| 138 | () => propsFocusManager || createFocusManager(ref), |
| 139 | [propsFocusManager, ref] |
| 140 | ); |
| 141 | let groupProps = useDatePickerGroup(state, ref, props[roleSymbol] === 'presentation'); |
| 142 | |
| 143 | // Pass labels and other information to segments. |
| 144 | hookData.set(state, { |
| 145 | ariaLabel: props['aria-label'], |
| 146 | ariaLabelledBy: |
| 147 | [labelProps.id, props['aria-labelledby']].filter(Boolean).join(' ') || undefined, |
no test coverage detected