From a69ec36f84c15abb3837a6b8465bfa6e680d9961 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Tue, 27 Feb 2018 17:57:28 +0100 Subject: [PATCH] fix(input): scroll-assist --- .../core/src/components/content/content.tsx | 28 +++-- .../core/src/components/content/readme.md | 6 + .../components/input-shims/hacks/common.ts | 96 ++++++++++++++++ .../input-shims/hacks/hide-caret.ts | 107 +----------------- .../input-shims/hacks/input-blurring.ts | 7 +- .../input-shims/hacks/scroll-assist.ts | 90 +++++++++++++++ .../input-shims/hacks/scroll-data.ts | 81 +++++++------ .../input-shims/hacks/scroll-padding.ts | 45 ++++++++ .../src/components/input-shims/hacks/wip.ts | 15 --- .../components/input-shims/input-shims.tsx | 46 ++++++-- .../components/input/test/basic/index.html | 5 + .../popover/animations/ios.enter.ts | 1 - packages/core/src/components/scroll/readme.md | 3 + .../core/src/components/scroll/scroll.tsx | 5 + .../src/components/tap-click/tap-click.tsx | 9 +- packages/core/src/global/platform-configs.ts | 9 +- packages/core/src/utils/helpers.ts | 24 +--- 17 files changed, 374 insertions(+), 203 deletions(-) create mode 100644 packages/core/src/components/input-shims/hacks/common.ts create mode 100644 packages/core/src/components/input-shims/hacks/scroll-assist.ts create mode 100644 packages/core/src/components/input-shims/hacks/scroll-padding.ts diff --git a/packages/core/src/components/content/content.tsx b/packages/core/src/components/content/content.tsx index 7f29cb326a..cb88e9233b 100644 --- a/packages/core/src/components/content/content.tsx +++ b/packages/core/src/components/content/content.tsx @@ -49,14 +49,6 @@ export class Content { this.scrollEl = null; } - hostData() { - return { - class: { - 'statusbar-padding': this.config.getBoolean('statusbarPadding') - } - }; - } - /** * Scroll to the top of the content component. * @@ -79,7 +71,17 @@ export class Content { return this.scrollEl.scrollToBottom(duration); } - resize() { + @Method() + scrollByPoint(x: number, y: number, duration: number, done?: Function): Promise { + return this.scrollEl.scrollByPoint(x, y, duration, done); + } + + @Method() + scrollToPoint(x: number, y: number, duration: number, done?: Function): Promise { + return this.scrollEl.scrollToPoint(x, y, duration, done); + } + + private resize() { if (!this.scrollEl) { return; } @@ -114,6 +116,14 @@ export class Content { } } + hostData() { + return { + class: { + 'statusbar-padding': this.config.getBoolean('statusbarPadding') + } + }; + } + render() { this.resize(); diff --git a/packages/core/src/components/content/readme.md b/packages/core/src/components/content/readme.md index 3c4622cd0d..b0a2e96a6c 100644 --- a/packages/core/src/components/content/readme.md +++ b/packages/core/src/components/content/readme.md @@ -56,6 +56,9 @@ to transparent. ## Methods +#### scrollByPoint() + + #### scrollToBottom() Scroll to the bottom of the content component. @@ -64,6 +67,9 @@ Duration of the scroll animation in milliseconds. Defaults to `300`. Returns a promise which is resolved when the scroll has completed. +#### scrollToPoint() + + #### scrollToTop() Scroll to the top of the content component. diff --git a/packages/core/src/components/input-shims/hacks/common.ts b/packages/core/src/components/input-shims/hacks/common.ts new file mode 100644 index 0000000000..d7f2b7a9a8 --- /dev/null +++ b/packages/core/src/components/input-shims/hacks/common.ts @@ -0,0 +1,96 @@ +const RELOCATED_KEY= '$ionRelocated'; + +export function relocateInput( + componentEl: HTMLElement, + inputEl: HTMLInputElement, + shouldRelocate: boolean, + inputRelativeY: number = 0 +) { + if ((componentEl as any)[RELOCATED_KEY] === shouldRelocate) { + return; + } + console.debug(`native-input, hideCaret, shouldHideCaret: ${shouldRelocate}, input value: ${inputEl.value}`); + if (shouldRelocate) { + // this allows for the actual input to receive the focus from + // the user's touch event, but before it receives focus, it + // moves the actual input to a location that will not screw + // up the app's layout, and does not allow the native browser + // to attempt to scroll the input into place (messing up headers/footers) + // the cloned input fills the area of where native input should be + // while the native input fakes out the browser by relocating itself + // before it receives the actual focus event + // We hide the focused input (with the visible caret) invisiable by making it scale(0), + cloneInputComponent(componentEl, inputEl); + const tx = document.dir === 'rtl' ? 9999 : -9999; + inputEl.style.transform= `translate3d(${tx}px,${inputRelativeY}px,0)`; + // TODO + // inputEle.style.opacity = '0'; + } else { + removeClone(componentEl, inputEl); + } + (componentEl as any)[RELOCATED_KEY] = shouldRelocate; +} + + +export function isFocused(input: HTMLInputElement): boolean { + return input === document.activeElement; +} + +function removeClone(componentEl: HTMLElement, inputEl: HTMLElement) { + if (componentEl && componentEl.parentElement) { + const clonedInputEles = componentEl.parentElement.querySelectorAll('.cloned-input'); + for (let i = 0; i < clonedInputEles.length; i++) { + clonedInputEles[i].parentNode.removeChild(clonedInputEles[i]); + } + componentEl.style.pointerEvents = ''; + } + (inputEl.style)['transform'] = ''; + inputEl.style.opacity = ''; +} + +function cloneInputComponent(componentEl: HTMLElement, inputEl: HTMLInputElement) { + // Make sure we kill all the clones before creating new ones + // It is a defensive, removeClone() should do nothing + // removeClone(plt, srcComponentEle, srcNativeInputEle); + // given a native or