fix(inputs): inputs work inside <form>

This commit is contained in:
Manu Mtz.-Almeida
2018-07-23 23:57:29 +02:00
parent 073f45c94b
commit 8324bd1f7f
10 changed files with 65 additions and 30 deletions

View File

@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core';
import { CheckboxInput, CheckedInputChangeEvent, Color, Mode, StyleEvent } from '../../interface';
import { deferEvent } from '../../utils/helpers';
import { deferEvent, renderHiddenInput } from '../../utils/helpers';
import { createColorClasses, hostContext } from '../../utils/theme';
@ -129,6 +129,8 @@ export class Checkbox implements CheckboxInput {
}
render() {
renderHiddenInput(this.el, this.name, this.value, this.disabled);
return [
<div class="checkbox-icon">
<div class="checkbox-inner"></div>

View File

@ -21,6 +21,7 @@
height: 100%;
/* stylelint-disable */
/* TODO: find a better solution in padding.css, that does not require !important, */
margin: 0 !important;
padding: 0 !important;

View File

@ -18,6 +18,11 @@
align-items: center;
width: 100%;
/* stylelint-disable */
/* TODO: find a better solution in padding.css, that does not require !important, */
padding: 0 !important;
/* stylelint-enable */
}
@ -55,15 +60,16 @@
font-family: inherit;
font-weight: var(--placeholder-weight);
}
&:-webkit-autofill {
background-color: transparent;
}
}
.native-input[disabled] {
opacity: .4;
}
.native-input:-webkit-autofill {
background-color: transparent;
}
// Input Cover: Unfocused
@ -99,16 +105,13 @@
border: 0;
outline: none;
background-color: transparent;
background-repeat: no-repeat;
visibility: hidden;
appearance: none;
&:active,
&:focus {
outline: none;
}
}
:host(.has-focus.has-value) .input-clear-icon {

View File

@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core';
import { Color, InputChangeEvent, Mode, StyleEvent } from '../../interface';
import { debounceEvent, deferEvent } from '../../utils/helpers';
import { debounceEvent, deferEvent, renderHiddenInput } from '../../utils/helpers';
import { hostContext } from '../../utils/theme';
import { InputComponent } from './input-base';
@ -16,6 +16,7 @@ import { InputComponent } from './input-base';
export class Input implements InputComponent {
private nativeInput?: HTMLInputElement;
private inputId = `ion-input-${inputIds++}`;
didBlurAfterEdit = false;
mode!: Mode;
@ -148,7 +149,7 @@ export class Input implements InputComponent {
/**
* The name of the control, which is submitted with the form data.
*/
@Prop() name?: string;
@Prop() name: string = this.inputId;
/**
* A regular expression that the value is checked against. The pattern must match the entire value, not just some subset. Use the title attribute to describe the pattern to help the user. This attribute applies when the value of the type attribute is `"text"`, `"search"`, `"tel"`, `"url"`, `"email"`, or `"password"`, otherwise it is ignored.
@ -276,14 +277,10 @@ export class Input implements InputComponent {
}
}
private inputKeydown() {
this.checkClearOnEdit();
}
/**
* Check if we need to clear the text input if clearOnEdit is enabled
*/
private checkClearOnEdit() {
private onKeydown() {
if (!this.clearOnEdit) {
return;
}
@ -317,7 +314,7 @@ export class Input implements InputComponent {
}
render() {
// TODO aria-labelledby={this.item.labelId}
renderHiddenInput(this.el, this.name, this.value, this.disabled);
return [
<input
@ -350,8 +347,9 @@ export class Input implements InputComponent {
onInput={this.onInput.bind(this)}
onBlur={this.onBlur.bind(this)}
onFocus={this.onFocus.bind(this)}
onKeyDown={this.inputKeydown.bind(this)}
onKeyDown={this.onKeydown.bind(this)}
/>,
<slot></slot>,
this.clearInput && <button
type="button"
class="input-clear-icon"
@ -360,3 +358,5 @@ export class Input implements InputComponent {
];
}
}
let inputIds = 0;

View File

@ -7,11 +7,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
<link rel="stylesheet" type="text/css" href="/css/ionic.min.css">
<style>
ion-label {
color: red;
}
</style>
</head>
<body>
<ion-label>Default</ion-label>
<ion-label>Wrap label this label just goes on and on and on</ion-label>
<ion-label color="primary">Wrap label this label just goes on and on and on</ion-label>
<ion-label position="fixed">Fixed</ion-label>
<ion-label position="floating">Floating</ion-label>
<ion-label position="stacked">Stacked</ion-label>

View File

@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Listen, Prop, State, Watch } from '@stencil/core';
import { ActionSheetButton, ActionSheetOptions, AlertInput, AlertOptions, CssClassMap, Mode, PopoverOptions, SelectInputChangeEvent, SelectInterface, SelectPopoverOption, StyleEvent} from '../../interface';
import { deferEvent } from '../../utils/helpers';
import { deferEvent, renderHiddenInput } from '../../utils/helpers';
import { createThemedClasses, hostContext } from '../../utils/theme';
@ -15,7 +15,7 @@ import { createThemedClasses, hostContext } from '../../utils/theme';
export class Select {
private childOpts: HTMLIonSelectOptionElement[] = [];
private selectId = `ion-sel-${selectIds++}`;
private inputId = `ion-sel-${selectIds++}`;
private labelId?: string;
private overlay?: HTMLIonActionSheetElement | HTMLIonAlertElement | HTMLIonPopoverElement;
@ -54,7 +54,7 @@ export class Select {
/**
* The name of the control, which is submitted with the form data.
*/
@Prop({ mutable: true }) name?: string;
@Prop() name: string = this.inputId;
/**
* The text to display instead of the selected option's value.
@ -225,7 +225,6 @@ export class Select {
if (!this.value) {
this.value = this.multiple ? [] : undefined;
}
this.name = this.name || this.selectId;
}
componentDidLoad() {
@ -460,6 +459,8 @@ export class Select {
}
render() {
renderHiddenInput(this.el, this.name, parseValue(this.value), this.disabled);
let addPlaceholderClass = false;
let selectText = this.selectedText || this.text;
@ -496,8 +497,7 @@ export class Select {
class="select-cover">
<slot></slot>
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
</button>,
<input type="hidden" name={this.name} value={parseValue(this.value)}/>
</button>
];
}
}

View File

@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core';
import { Color, InputChangeEvent, Mode, StyleEvent } from '../../interface';
import { debounceEvent, deferEvent } from '../../utils/helpers';
import { debounceEvent, deferEvent, renderHiddenInput } from '../../utils/helpers';
import { TextareaComponent } from '../input/input-base';
@ -15,6 +15,7 @@ import { TextareaComponent } from '../input/input-base';
export class Textarea implements TextareaComponent {
private inputEl?: HTMLTextAreaElement;
private inputId = `ion-input-${textareaIds++}`;
mode!: Mode;
color?: Color;
@ -103,7 +104,7 @@ export class Textarea implements TextareaComponent {
/**
* The name of the control, which is submitted with the form data.
*/
@Prop() name?: string;
@Prop() name: string = this.inputId;
/**
* Instructional text that shows before the input has a value.
@ -229,6 +230,8 @@ export class Textarea implements TextareaComponent {
}
render() {
renderHiddenInput(this.el, this.name, this.value, this.disabled);
return (
<textarea
class="native-textarea"
@ -257,3 +260,5 @@ export class Textarea implements TextareaComponent {
);
}
}
let textareaIds = 0;

View File

@ -1,7 +1,7 @@
import { Component, Element, Event, EventEmitter, Prop, State, Watch } from '@stencil/core';
import { CheckboxInput, CheckedInputChangeEvent, Color, GestureDetail, Mode, StyleEvent } from '../../interface';
import { hapticSelection } from '../../utils/haptic';
import { deferEvent } from '../../utils/helpers';
import { deferEvent, renderHiddenInput } from '../../utils/helpers';
import { createColorClasses, hostContext } from '../../utils/theme';
@ -169,6 +169,8 @@ export class Toggle implements CheckboxInput {
}
render() {
renderHiddenInput(this.el, this.name, this.value, this.disabled);
return [
<ion-gesture
onStart={this.onDragStart.bind(this)}
@ -197,7 +199,8 @@ export class Toggle implements CheckboxInput {
name={this.name}
value={this.value}
disabled={this.disabled}
ref={r => this.nativeInput = (r as any)}/>
ref={r => this.nativeInput = (r as any)}/>,
<slot></slot>
];
}
}

View File

@ -8,6 +8,21 @@ export function reorderArray(array: any[], indexes: {from: number, to: number}):
return array;
}
export function renderHiddenInput(container: HTMLElement, name: string, value: string, disabled: boolean) {
if (container.shadowRoot) {
let input = container.querySelector('input.aux-input') as HTMLInputElement;
if (!input) {
input = container.ownerDocument.createElement('input');
input.type = 'hidden';
input.classList.add('aux-input');
container.appendChild(input);
}
input.disabled = disabled;
input.name = name;
input.value = value;
}
}
export function clamp(min: number, n: number, max: number) {
return Math.max(min, Math.min(n, max));
}

View File

@ -24,7 +24,7 @@ export function startInputShims(
const scrollAssistMap = new WeakMap<HTMLElement, Function>();
function registerInput(componentEl: HTMLElement) {
const inputEl = componentEl.querySelector('input');
const inputEl = (componentEl.shadowRoot || componentEl).querySelector('input');
const contentEl = componentEl.closest('ion-content');
const scrollEl = contentEl && contentEl.getScrollElement();