|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | import {AriaTextFieldProps} from '@react-types/textfield';
|
| 14 | +import {chain, filterDOMProps, getOwnerWindow, mergeProps, useFormReset} from '@react-aria/utils'; |
14 | 15 | import {DOMAttributes, ValidationResult} from '@react-types/shared';
|
15 |
| -import {filterDOMProps, getOwnerWindow, mergeProps, useFormReset} from '@react-aria/utils'; |
16 | 16 | import React, {
|
17 | 17 | ChangeEvent,
|
18 | 18 | HTMLAttributes,
|
19 | 19 | type JSX,
|
20 | 20 | LabelHTMLAttributes,
|
21 | 21 | RefObject,
|
| 22 | + useCallback, |
22 | 23 | useEffect,
|
| 24 | + useRef, |
23 | 25 | useState
|
24 | 26 | } from 'react';
|
25 | 27 | import {useControlledState} from '@react-stately/utils';
|
@@ -122,9 +124,20 @@ export function useTextField<T extends TextFieldIntrinsicElements = DefaultEleme
|
122 | 124 | isRequired = false,
|
123 | 125 | isReadOnly = false,
|
124 | 126 | type = 'text',
|
125 |
| - validationBehavior = 'aria' |
| 127 | + validationBehavior = 'aria', |
| 128 | + onChange: onChangeProp |
126 | 129 | } = props;
|
127 |
| - let [value, setValue] = useControlledState<string>(props.value, props.defaultValue || '', props.onChange); |
| 130 | + |
| 131 | + let isComposing = useRef(false); |
| 132 | + let onChange = useCallback((val) => { |
| 133 | + if (isComposing.current) { |
| 134 | + return; |
| 135 | + } |
| 136 | + |
| 137 | + onChangeProp?.(val); |
| 138 | + }, [onChangeProp]); |
| 139 | + |
| 140 | + let [value, setValue] = useControlledState<string>(props.value, props.defaultValue || '', onChange); |
128 | 141 | let {focusableProps} = useFocusable<TextFieldHTMLElementType[T]>(props, ref);
|
129 | 142 | let validationState = useFormValidationState({
|
130 | 143 | ...props,
|
@@ -165,6 +178,17 @@ export function useTextField<T extends TextFieldIntrinsicElements = DefaultEleme
|
165 | 178 | }
|
166 | 179 | }, [ref]);
|
167 | 180 |
|
| 181 | + let onCompositionStart = useCallback(() => { |
| 182 | + isComposing.current = true; |
| 183 | + }, []); |
| 184 | + |
| 185 | + let onCompositionEnd = useCallback((e) => { |
| 186 | + isComposing.current = false; |
| 187 | + if (e.data !== '') { |
| 188 | + onChangeProp?.(value); |
| 189 | + } |
| 190 | + }, [onChangeProp, value]); |
| 191 | + |
168 | 192 | return {
|
169 | 193 | labelProps,
|
170 | 194 | inputProps: mergeProps(
|
@@ -201,8 +225,8 @@ export function useTextField<T extends TextFieldIntrinsicElements = DefaultEleme
|
201 | 225 | onPaste: props.onPaste,
|
202 | 226 |
|
203 | 227 | // Composition events
|
204 |
| - onCompositionEnd: props.onCompositionEnd, |
205 |
| - onCompositionStart: props.onCompositionStart, |
| 228 | + onCompositionEnd: chain(onCompositionEnd, props.onCompositionEnd), |
| 229 | + onCompositionStart: chain(onCompositionStart, props.onCompositionStart), |
206 | 230 | onCompositionUpdate: props.onCompositionUpdate,
|
207 | 231 |
|
208 | 232 | // Selection events
|
|
0 commit comments