Skip to content

Commit

Permalink
fix(textarea): reposition textarea when keybard appears (#18098)
Browse files Browse the repository at this point in the history
fixes #17847
  • Loading branch information
brandyscarney committed Apr 24, 2019
1 parent 95945c0 commit 3cdab10
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 13 deletions.
21 changes: 18 additions & 3 deletions core/src/components/textarea/textarea.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@
// --------------------------------------------------

:host-context(ion-item) {
position: static;

align-self: baseline;
}

Expand All @@ -79,7 +77,8 @@
display: block;

width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;

border: 0;

Expand All @@ -106,3 +105,19 @@
.native-textarea[disabled] {
opacity: .4;
}

// Input Cover: Unfocused
// --------------------------------------------------
// The input cover is the div that actually receives the
// tap/click event when scroll assist is configured to true.
// This make it so the native input element is not clickable.
// This will only show when the scroll assist is configured
// otherwise the .input-cover will not be rendered at all
// The input cover is not clickable when the input is disabled
.cloned-input {
@include position(0, null, null, 0);

position: absolute;

pointer-events: none;
}
18 changes: 18 additions & 0 deletions core/src/components/textarea/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,30 @@ export class Textarea implements ComponentInterface {
*/
@Event() ionFocus!: EventEmitter<void>;

/**
* Emitted when the input has been created.
* @internal
*/
@Event() ionInputDidLoad!: EventEmitter<void>;

/**
* Emitted when the input has been removed.
* @internal
*/
@Event() ionInputDidUnload!: EventEmitter<void>;

componentWillLoad() {
this.emitStyle();
}

componentDidLoad() {
this.debounceChanged();

this.ionInputDidLoad.emit();
}

componentDidUnload() {
this.ionInputDidUnload.emit();
}

/**
Expand Down
8 changes: 4 additions & 4 deletions core/src/utils/input-shims/hacks/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const cloneMap = new WeakMap<HTMLElement, HTMLElement>();

export function relocateInput(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
inputEl: HTMLInputElement | HTMLTextAreaElement,
shouldRelocate: boolean,
inputRelativeY = 0
) {
Expand All @@ -17,11 +17,11 @@ export function relocateInput(
}
}

export function isFocused(input: HTMLInputElement): boolean {
export function isFocused(input: HTMLInputElement | HTMLTextAreaElement): boolean {
return input === (input as any).getRootNode().activeElement;
}

function addClone(componentEl: HTMLElement, inputEl: HTMLInputElement, inputRelativeY: number) {
function addClone(componentEl: HTMLElement, inputEl: HTMLInputElement | HTMLTextAreaElement, inputRelativeY: number) {
// 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
Expand All @@ -34,7 +34,7 @@ function addClone(componentEl: HTMLElement, inputEl: HTMLInputElement, inputRela
const parentEl = inputEl.parentNode!;

// DOM WRITES
const clonedEl = inputEl.cloneNode(false) as HTMLInputElement;
const clonedEl = inputEl.cloneNode(false) as HTMLElement;
clonedEl.classList.add('cloned-input');
clonedEl.tabIndex = -1;
parentEl.appendChild(clonedEl);
Expand Down
2 changes: 1 addition & 1 deletion core/src/utils/input-shims/hacks/hide-caret.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isFocused, relocateInput } from './common';

export function enableHideCaretOnScroll(componentEl: HTMLElement, inputEl: HTMLInputElement | undefined, scrollEl: HTMLIonContentElement | undefined) {
export function enableHideCaretOnScroll(componentEl: HTMLElement, inputEl: HTMLInputElement | HTMLTextAreaElement | undefined, scrollEl: HTMLIonContentElement | undefined) {
if (!scrollEl || !inputEl) {
return () => { return; };
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/utils/input-shims/hacks/scroll-assist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getScrollData } from './scroll-data';

export function enableScrollAssist(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
inputEl: HTMLInputElement | HTMLTextAreaElement,
contentEl: HTMLIonContentElement,
keyboardHeight: number
) {
Expand Down Expand Up @@ -45,7 +45,7 @@ export function enableScrollAssist(

function jsSetFocus(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
inputEl: HTMLInputElement | HTMLTextAreaElement,
contentEl: HTMLIonContentElement,
keyboardHeight: number
) {
Expand Down
6 changes: 3 additions & 3 deletions core/src/utils/input-shims/input-shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function startInputShims(
const scrollAssistMap = new WeakMap<HTMLElement, () => void>();

function registerInput(componentEl: HTMLElement) {
const inputEl = (componentEl.shadowRoot || componentEl).querySelector('input');
const inputEl = (componentEl.shadowRoot || componentEl).querySelector('input') || (componentEl.shadowRoot || componentEl).querySelector('textarea');
const scrollEl = componentEl.closest('ion-content');

if (!inputEl) {
Expand Down Expand Up @@ -70,9 +70,9 @@ export function startInputShims(
}

// Input might be already loaded in the DOM before ion-device-hacks did.
// At this point we need to look for all the ion-inputs not registered yet
// At this point we need to look for all of the inputs not registered yet
// and register them.
const inputs = Array.from(doc.querySelectorAll('ion-input'));
const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea')) as HTMLElement[];
for (const input of inputs) {
registerInput(input);
}
Expand Down

0 comments on commit 3cdab10

Please sign in to comment.