Introduce TextInput.onChangeSync
Summary: changelog: [internal] Add experimental `TextInput.onChangeSync` which delivers onChange event synchronously. Reviewed By: ShikaSD Differential Revision: D33188083 fbshipit-source-id: 1e1dcd0d71c7eec98d3d5f69967659e07ac4e6a6
This commit is contained in:
Родитель
f3d0a67a73
Коммит
8c6a98400e
|
@ -598,12 +598,33 @@ export type Props = $ReadOnly<{|
|
|||
*/
|
||||
onChange?: ?(e: ChangeEvent) => mixed,
|
||||
|
||||
/**
|
||||
* DANGER: this API is not stable and will change in the future.
|
||||
*
|
||||
* Callback will be called on the main thread and may result in dropped frames.
|
||||
* Callback that is called when the text input's text changes.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
unstable_onChangeSync?: ?(e: ChangeEvent) => mixed,
|
||||
|
||||
/**
|
||||
* Callback that is called when the text input's text changes.
|
||||
* Changed text is passed as an argument to the callback handler.
|
||||
*/
|
||||
onChangeText?: ?(text: string) => mixed,
|
||||
|
||||
/**
|
||||
* DANGER: this API is not stable and will change in the future.
|
||||
*
|
||||
* Callback will be called on the main thread and may result in dropped frames.
|
||||
* Callback that is called when the text input's text changes.
|
||||
* Changed text is passed as an argument to the callback handler.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
unstable_onChangeTextSync?: ?(text: string) => mixed,
|
||||
|
||||
/**
|
||||
* Callback that is called when the text input's content size changes.
|
||||
* This will be called with
|
||||
|
@ -643,7 +664,7 @@ export type Props = $ReadOnly<{|
|
|||
* the typed-in character otherwise including `' '` for space.
|
||||
* Fires before `onChange` callbacks.
|
||||
*
|
||||
* Only available in Fabric on iOS.
|
||||
* @platform ios
|
||||
*/
|
||||
unstable_onKeyPressSync?: ?(e: KeyPressEvent) => mixed,
|
||||
|
||||
|
@ -1101,6 +1122,26 @@ function InternalTextInput(props: Props): React.Node {
|
|||
setMostRecentEventCount(event.nativeEvent.eventCount);
|
||||
};
|
||||
|
||||
const _onChangeSync = (event: ChangeEvent) => {
|
||||
const currentText = event.nativeEvent.text;
|
||||
props.unstable_onChangeSync && props.unstable_onChangeSync(event);
|
||||
props.unstable_onChangeTextSync &&
|
||||
props.unstable_onChangeTextSync(currentText);
|
||||
|
||||
if (inputRef.current == null) {
|
||||
// calling `props.onChange` or `props.onChangeText`
|
||||
// may clean up the input itself. Exits here.
|
||||
return;
|
||||
}
|
||||
|
||||
setLastNativeText(currentText);
|
||||
// This must happen last, after we call setLastNativeText.
|
||||
// Different ordering can cause bugs when editing AndroidTextInputs
|
||||
// with multiple Fragments.
|
||||
// We must update this so that controlled input updates work.
|
||||
setMostRecentEventCount(event.nativeEvent.eventCount);
|
||||
};
|
||||
|
||||
const _onSelectionChange = (event: SelectionChangeEvent) => {
|
||||
props.onSelectionChange && props.onSelectionChange(event);
|
||||
|
||||
|
@ -1187,6 +1228,10 @@ function InternalTextInput(props: Props): React.Node {
|
|||
? [styles.multilineInput, props.style]
|
||||
: props.style;
|
||||
|
||||
const useOnChangeSync =
|
||||
(props.unstable_onChangeSync || props.unstable_onChangeTextSync) &&
|
||||
!(props.onChange || props.onChangeText);
|
||||
|
||||
textInput = (
|
||||
<RCTTextInputView
|
||||
ref={_setNativeRef}
|
||||
|
@ -1201,6 +1246,7 @@ function InternalTextInput(props: Props): React.Node {
|
|||
onBlur={_onBlur}
|
||||
onKeyPressSync={props.unstable_onKeyPressSync}
|
||||
onChange={_onChange}
|
||||
onChangeSync={useOnChangeSync === true ? _onChangeSync : null}
|
||||
onContentSizeChange={props.onContentSizeChange}
|
||||
onFocus={_onFocus}
|
||||
onScroll={_onScroll}
|
||||
|
|
|
@ -10,6 +10,7 @@ exports[`TextInput tests should render as expected: should deep render when mock
|
|||
mostRecentEventCount={0}
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onChangeSync={null}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
|
@ -38,6 +39,7 @@ exports[`TextInput tests should render as expected: should deep render when not
|
|||
mostRecentEventCount={0}
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onChangeSync={null}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
|
|
|
@ -35,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange;
|
||||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onSelectionChange;
|
||||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onChange;
|
||||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onChangeSync;
|
||||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onTextInput;
|
||||
@property (nonatomic, copy, nullable) RCTDirectEventBlock onScroll;
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ RCT_EXPORT_VIEW_PROPERTY(passwordRules, NSString)
|
|||
|
||||
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onKeyPressSync, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onChangeSync, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
|
||||
|
|
|
@ -381,7 +381,13 @@ using namespace facebook::react;
|
|||
[self _updateState];
|
||||
|
||||
if (_eventEmitter) {
|
||||
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onChange([self _textInputMetrics]);
|
||||
auto const &textInputEventEmitter = *std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter);
|
||||
auto const &props = *std::static_pointer_cast<TextInputProps const>(_props);
|
||||
if (props.onChangeSync) {
|
||||
textInputEventEmitter.onChangeSync([self _textInputMetrics]);
|
||||
} else {
|
||||
textInputEventEmitter.onChange([self _textInputMetrics]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,12 @@ void TextInputEventEmitter::onChange(
|
|||
dispatchTextInputEvent("change", textInputMetrics);
|
||||
}
|
||||
|
||||
void TextInputEventEmitter::onChangeSync(
|
||||
TextInputMetrics const &textInputMetrics) const {
|
||||
dispatchTextInputEvent(
|
||||
"changeSync", textInputMetrics, EventPriority::SynchronousBatched);
|
||||
}
|
||||
|
||||
void TextInputEventEmitter::onContentSizeChange(
|
||||
TextInputMetrics const &textInputMetrics) const {
|
||||
dispatchTextInputEvent("contentSizeChange", textInputMetrics);
|
||||
|
|
|
@ -40,6 +40,7 @@ class TextInputEventEmitter : public ViewEventEmitter {
|
|||
void onFocus(TextInputMetrics const &textInputMetrics) const;
|
||||
void onBlur(TextInputMetrics const &textInputMetrics) const;
|
||||
void onChange(TextInputMetrics const &textInputMetrics) const;
|
||||
void onChangeSync(TextInputMetrics const &textInputMetrics) const;
|
||||
void onContentSizeChange(TextInputMetrics const &textInputMetrics) const;
|
||||
void onSelectionChange(TextInputMetrics const &textInputMetrics) const;
|
||||
void onEndEditing(TextInputMetrics const &textInputMetrics) const;
|
||||
|
|
|
@ -99,6 +99,12 @@ TextInputProps::TextInputProps(
|
|||
rawProps,
|
||||
"onKeyPressSync",
|
||||
sourceProps.onKeyPressSync,
|
||||
{})),
|
||||
onChangeSync(convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"onChangeSync",
|
||||
sourceProps.onChangeSync,
|
||||
{})){};
|
||||
|
||||
TextAttributes TextInputProps::getEffectiveTextAttributes(
|
||||
|
|
|
@ -63,6 +63,7 @@ class TextInputProps final : public ViewProps, public BaseTextProps {
|
|||
std::string const inputAccessoryViewID{};
|
||||
|
||||
bool onKeyPressSync{false};
|
||||
bool onChangeSync{false};
|
||||
|
||||
/*
|
||||
* Accessors
|
||||
|
|
Загрузка…
Ссылка в новой задаче