feat(ios): textfield option to disable iOS autofill strong password handling (#8348)

* feat(ios): textfield option to disable autofill strong password handling

* chore: api change report
This commit is contained in:
Nathan Walker
2020-03-23 03:16:40 -07:00
committed by GitHub
parent 8ab0e72bc9
commit 42fc4acea3
4 changed files with 80 additions and 64 deletions

View File

@ -878,45 +878,45 @@ export interface GestureEventData extends EventData {
// @public // @public
export interface GestureEventDataWithState extends GestureEventData { export interface GestureEventDataWithState extends GestureEventData {
// (undocumented) // (undocumented)
state: number; state: number;
} }
// @public // @public
export class GesturesObserver { export class GesturesObserver {
constructor(target: View, callback: (args: GestureEventData) => void, context: any); constructor(target: View, callback: (args: GestureEventData) => void, context: any);
androidOnTouchEvent: (motionEvent: any /* android.view.MotionEvent */) => void; androidOnTouchEvent: (motionEvent: any /* android.view.MotionEvent */) => void;
callback: (args: GestureEventData) => void; callback: (args: GestureEventData) => void;
context: any; context: any;
disconnect(); disconnect();
observe(type: GestureTypes); observe(type: GestureTypes);
type: GestureTypes; type: GestureTypes;
} }
// @public // @public
export enum GestureStateTypes { export enum GestureStateTypes {
began, began,
cancelled, cancelled,
changed, changed,
ended ended
} }
// @public // @public
export enum GestureTypes { export enum GestureTypes {
doubleTap, doubleTap,
longPress, longPress,
pan, pan,
pinch, pinch,
rotation, rotation,
swipe, swipe,
tap, tap,
touch touch
} }
// @public // @public
@ -1011,49 +1011,49 @@ export const Http: {
// @public // @public
export interface HttpContent { export interface HttpContent {
raw: any; raw: any;
toArrayBuffer: () => ArrayBuffer; toArrayBuffer: () => ArrayBuffer;
toFile: (destinationFilePath?: string) => File; toFile: (destinationFilePath?: string) => File;
toImage: () => Promise<ImageSource>; toImage: () => Promise<ImageSource>;
toJSON: (encoding?: HttpResponseEncoding) => any; toJSON: (encoding?: HttpResponseEncoding) => any;
toString: (encoding?: HttpResponseEncoding) => string; toString: (encoding?: HttpResponseEncoding) => string;
} }
// @public // @public
export interface HttpRequestOptions { export interface HttpRequestOptions {
content?: string | FormData | ArrayBuffer; content?: string | FormData | ArrayBuffer;
dontFollowRedirects?: boolean; dontFollowRedirects?: boolean;
headers?: any; headers?: any;
method: string; method: string;
timeout?: number; timeout?: number;
url: string; url: string;
} }
// @public // @public
export interface HttpResponse { export interface HttpResponse {
content?: HttpContent; content?: HttpContent;
headers: Headers; headers: Headers;
statusCode: number; statusCode: number;
} }
// @public (undocumented) // @public (undocumented)
export enum HttpResponseEncoding { export enum HttpResponseEncoding {
// (undocumented) // (undocumented)
GBK, GBK,
// (undocumented) // (undocumented)
UTF8 UTF8
} }
// @public // @public
@ -1642,10 +1642,10 @@ export class Page extends ContentView {
// @public // @public
export interface PanGestureEventData extends GestureEventDataWithState { export interface PanGestureEventData extends GestureEventDataWithState {
// (undocumented) // (undocumented)
deltaX: number; deltaX: number;
// (undocumented) // (undocumented)
deltaY: number; deltaY: number;
} }
// @public // @public
@ -1694,14 +1694,14 @@ export module path {
// @public // @public
export interface PinchGestureEventData extends GestureEventDataWithState { export interface PinchGestureEventData extends GestureEventDataWithState {
// (undocumented) // (undocumented)
getFocusX(): number; getFocusX(): number;
// (undocumented) // (undocumented)
getFocusY(): number; getFocusY(): number;
// (undocumented) // (undocumented)
scale: number; scale: number;
} }
// @public // @public
@ -1765,8 +1765,8 @@ export class Repeater extends CustomLayoutView {
// @public // @public
export interface RotationGestureEventData extends GestureEventDataWithState { export interface RotationGestureEventData extends GestureEventDataWithState {
// (undocumented) // (undocumented)
rotation: number; rotation: number;
} }
// @public // @public
@ -2172,16 +2172,16 @@ export class Style extends Observable {
// @public // @public
export enum SwipeDirection { export enum SwipeDirection {
down, down,
left, left,
right, right,
up up
} }
// @public // @public
export interface SwipeGestureEventData extends GestureEventData { export interface SwipeGestureEventData extends GestureEventData {
// (undocumented) // (undocumented)
direction: SwipeDirection; direction: SwipeDirection;
} }
// @public // @public
@ -2424,10 +2424,9 @@ export class TabViewItem extends ViewBase {
// @public // @public
export interface TapGestureEventData extends GestureEventData { export interface TapGestureEventData extends GestureEventData {
getPointerCount(): number; getPointerCount(): number;
getX(): number; getX(): number;
getY(): number; getY(): number;
} }
// @public // @public
@ -2508,6 +2507,8 @@ export class TextField extends EditableTextBase {
public static returnPressEvent: string; public static returnPressEvent: string;
secure: boolean; secure: boolean;
secureWithoutAutofill: boolean;
} }
// @public // @public
@ -2552,10 +2553,10 @@ export interface TimerInfo {
// @public // @public
export interface TouchGestureEventData extends TapGestureEventData { export interface TouchGestureEventData extends TapGestureEventData {
action: "up" | "move" | "down" | "cancel"; action: "up" | "move" | "down" | "cancel";
// Warning: (ae-forgotten-export) The symbol "Pointer" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Pointer" needs to be exported by the entry point index.d.ts
getActivePointers(): Array<Pointer>; getActivePointers(): Array<Pointer>;
getAllPointers(): Array<Pointer>; getAllPointers(): Array<Pointer>;
} }
// @public (undocumented) // @public (undocumented)

View File

@ -8,6 +8,8 @@ export class TextFieldBase extends EditableTextBase implements TextFieldDefiniti
public static returnPressEvent = "returnPress"; public static returnPressEvent = "returnPress";
public secure: boolean; public secure: boolean;
public closeOnReturn: boolean; public closeOnReturn: boolean;
// iOS only (to avoid 12+ suggested strong password handling)
public secureWithoutAutofill: boolean;
} }
TextFieldBase.prototype.recycleNativeView = "auto"; TextFieldBase.prototype.recycleNativeView = "auto";

View File

@ -32,4 +32,9 @@ export class TextField extends EditableTextBase {
* Gets or sets if a text field should dismiss on return. * Gets or sets if a text field should dismiss on return.
*/ */
closeOnReturn: boolean; closeOnReturn: boolean;
/**
* iOS only (to avoid 12+ auto suggested strong password handling)
*/
secureWithoutAutofill: boolean;
} }

View File

@ -78,6 +78,14 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean { public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean {
const owner = this._owner.get(); const owner = this._owner.get();
if (owner) { if (owner) {
if (owner.secureWithoutAutofill && !textField.secureTextEntry) {
/**
* Helps avoid iOS 12+ autofill strong password suggestion prompt
* Discussed in several circles but for example:
* https://github.com/expo/expo/issues/2571#issuecomment-473347380
*/
textField.secureTextEntry = true;
}
const delta = replacementString.length - range.length; const delta = replacementString.length - range.length;
if (delta > 0) { if (delta > 0) {
if (textField.text.length + delta > owner.maxLength) { if (textField.text.length + delta > owner.maxLength) {