fix(ios): TextField keyboard handling with emoji, autofill, and shortcuts (#10154)

closes https://github.com/NativeScript/NativeScript/issues/10108
This commit is contained in:
Nathan Walker
2023-01-03 17:36:56 -08:00
committed by GitHub
parent d138ac000d
commit 00944bb1b5
9 changed files with 50 additions and 4 deletions

View File

@@ -105,7 +105,7 @@ export type { InstrumentationMode, TimerInfo } from './profiling';
export { encoding } from './text';
export * from './trace';
export * from './ui';
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, queueMacrotask, queueGC, throttle, debounce, dataSerialize, dataDeserialize, copyToClipboard, getFileExtension } from './utils';
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, queueMacrotask, queueGC, throttle, debounce, dataSerialize, dataDeserialize, copyToClipboard, getFileExtension, isEmoji } from './utils';
import { SDK_VERSION } from './utils/constants';
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
export declare const Utils: {
@@ -163,5 +163,6 @@ export declare const Utils: {
dismissSoftInput: typeof dismissSoftInput;
dismissKeyboard: typeof dismissKeyboard;
copyToClipboard: typeof copyToClipboard;
isEmoji: typeof isEmoji;
};
export { XmlParser, ParserEventType, ParserEvent } from './xml';

View File

@@ -137,7 +137,7 @@ export * from './trace';
export * from './ui';
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, dataDeserialize, dataSerialize, copyToClipboard, getFileExtension } from './utils';
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput, dismissKeyboard, dataDeserialize, dataSerialize, copyToClipboard, getFileExtension, isEmoji } from './utils';
import { SDK_VERSION } from './utils/constants';
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
@@ -199,6 +199,7 @@ export const Utils = {
dismissSoftInput,
dismissKeyboard,
copyToClipboard,
isEmoji,
};
export { XmlParser, ParserEventType, ParserEvent } from './xml';

View File

@@ -47,6 +47,7 @@
"@nativescript/hook": "~2.0.0",
"acorn": "^8.7.0",
"css-tree": "^1.1.2",
"emoji-regex": "^10.2.1",
"reduce-css-calc": "^2.1.7",
"tslib": "^2.0.0"
},

View File

@@ -4,7 +4,7 @@ import { hintProperty, placeholderColorProperty, _updateCharactersInRangeReplace
import { CoreTypes } from '../../core-types';
import { Color } from '../../color';
import { colorProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../styling/style-properties';
import { layout } from '../../utils';
import { layout, isEmoji } from '../../utils';
import { profile } from '../../profiling';
export * from './text-field-common';
@@ -200,7 +200,10 @@ export class TextField extends TextFieldBase {
}
if (this.updateTextTrigger === 'textChanged') {
const shouldReplaceString = (textField.secureTextEntry && this.firstEdit) || delta > 1;
// 1. secureTextEntry with firstEdit should not replace
// 2. emoji's should not replace value
// 3. convenient keyboard shortcuts should not replace value (eg, '.com')
const shouldReplaceString = (textField.secureTextEntry && this.firstEdit) || (delta > 1 && !isEmoji(replacementString) && delta !== replacementString.length);
if (shouldReplaceString) {
textProperty.nativeValueChange(this, replacementString);
} else {

View File

@@ -1,6 +1,7 @@
import * as types from './types';
import { dispatchToMainThread, dispatchToUIThread, isMainThread } from './mainthread-helper';
import { sanitizeModuleName } from '../ui/builder/module-name-sanitizer';
import emojiRegex from 'emoji-regex';
import { GC } from './index';
@@ -203,3 +204,9 @@ export function queueGC(delay = 900, useThrottle?: boolean) {
debouncedGC.get(delay)();
}
}
export function isEmoji(value: string): boolean {
// TODO: In a future runtime update, we can switch to using Unicode Property Escapes:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
return emojiRegex().test(value);
}