mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-10 00:27:41 +08:00
fix(textarea): reposition textarea when keybard appears (#18098)
fixes #17847
This commit is contained in:
@ -57,8 +57,6 @@
|
|||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
:host-context(ion-item) {
|
:host-context(ion-item) {
|
||||||
position: static;
|
|
||||||
|
|
||||||
align-self: baseline;
|
align-self: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +77,8 @@
|
|||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|
||||||
@ -106,3 +105,19 @@
|
|||||||
.native-textarea[disabled] {
|
.native-textarea[disabled] {
|
||||||
opacity: .4;
|
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;
|
||||||
|
}
|
||||||
@ -164,12 +164,30 @@ export class Textarea implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Event() ionFocus!: EventEmitter<void>;
|
@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() {
|
componentWillLoad() {
|
||||||
this.emitStyle();
|
this.emitStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
this.debounceChanged();
|
this.debounceChanged();
|
||||||
|
|
||||||
|
this.ionInputDidLoad.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUnload() {
|
||||||
|
this.ionInputDidUnload.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const cloneMap = new WeakMap<HTMLElement, HTMLElement>();
|
|||||||
|
|
||||||
export function relocateInput(
|
export function relocateInput(
|
||||||
componentEl: HTMLElement,
|
componentEl: HTMLElement,
|
||||||
inputEl: HTMLInputElement,
|
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||||
shouldRelocate: boolean,
|
shouldRelocate: boolean,
|
||||||
inputRelativeY = 0
|
inputRelativeY = 0
|
||||||
) {
|
) {
|
||||||
@ -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;
|
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
|
// this allows for the actual input to receive the focus from
|
||||||
// the user's touch event, but before it receives focus, it
|
// the user's touch event, but before it receives focus, it
|
||||||
// moves the actual input to a location that will not screw
|
// moves the actual input to a location that will not screw
|
||||||
@ -34,7 +34,7 @@ function addClone(componentEl: HTMLElement, inputEl: HTMLInputElement, inputRela
|
|||||||
const parentEl = inputEl.parentNode!;
|
const parentEl = inputEl.parentNode!;
|
||||||
|
|
||||||
// DOM WRITES
|
// DOM WRITES
|
||||||
const clonedEl = inputEl.cloneNode(false) as HTMLInputElement;
|
const clonedEl = inputEl.cloneNode(false) as HTMLElement;
|
||||||
clonedEl.classList.add('cloned-input');
|
clonedEl.classList.add('cloned-input');
|
||||||
clonedEl.tabIndex = -1;
|
clonedEl.tabIndex = -1;
|
||||||
parentEl.appendChild(clonedEl);
|
parentEl.appendChild(clonedEl);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { isFocused, relocateInput } from './common';
|
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) {
|
if (!scrollEl || !inputEl) {
|
||||||
return () => { return; };
|
return () => { return; };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { getScrollData } from './scroll-data';
|
|||||||
|
|
||||||
export function enableScrollAssist(
|
export function enableScrollAssist(
|
||||||
componentEl: HTMLElement,
|
componentEl: HTMLElement,
|
||||||
inputEl: HTMLInputElement,
|
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||||
contentEl: HTMLIonContentElement,
|
contentEl: HTMLIonContentElement,
|
||||||
keyboardHeight: number
|
keyboardHeight: number
|
||||||
) {
|
) {
|
||||||
@ -45,7 +45,7 @@ export function enableScrollAssist(
|
|||||||
|
|
||||||
function jsSetFocus(
|
function jsSetFocus(
|
||||||
componentEl: HTMLElement,
|
componentEl: HTMLElement,
|
||||||
inputEl: HTMLInputElement,
|
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||||
contentEl: HTMLIonContentElement,
|
contentEl: HTMLIonContentElement,
|
||||||
keyboardHeight: number
|
keyboardHeight: number
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export function startInputShims(
|
|||||||
const scrollAssistMap = new WeakMap<HTMLElement, () => void>();
|
const scrollAssistMap = new WeakMap<HTMLElement, () => void>();
|
||||||
|
|
||||||
function registerInput(componentEl: HTMLElement) {
|
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');
|
const scrollEl = componentEl.closest('ion-content');
|
||||||
|
|
||||||
if (!inputEl) {
|
if (!inputEl) {
|
||||||
@ -70,9 +70,9 @@ export function startInputShims(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Input might be already loaded in the DOM before ion-device-hacks did.
|
// 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.
|
// 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) {
|
for (const input of inputs) {
|
||||||
registerInput(input);
|
registerInput(input);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user