fix(input): add input highlight for ios, fix the highlight size

The input highlight can now be enabled for ios. Fixed wp’s
valid/invalid highlighting. The highlight bar now goes on top of the
item-inner border so it will resize if there is an icon to the left.

BREAKING CHANGES:

Fixed typos in the input highlight variables:

- `$text-input-md-hightlight-color-valid` ->
`$text-input-md-highlight-color-valid`
- `$text-input-wp-hightlight-color-valid` ->
`$text-input-wp-highlight-color-valid`

Modified variables to turn on/off the highlight:

ios (defaults to false for all):

```
$text-input-ios-show-focus-highlight:      false !default;
$text-input-ios-show-valid-highlight:
$text-input-ios-show-focus-highlight !default;
$text-input-ios-show-invalid-highlight:
$text-input-ios-show-focus-highlight !default;
```

md (defaults to true for all):

```
$text-input-md-show-focus-highlight:        true !default;
$text-input-md-show-valid-highlight:
$text-input-md-show-focus-highlight !default;
$text-input-md-show-invalid-highlight:
$text-input-md-show-focus-highlight !default;
```

wp (defaults to true for all):

```
$text-input-wp-show-focus-highlight:        true !default;
$text-input-wp-show-valid-highlight:
$text-input-wp-show-focus-highlight !default;
$text-input-wp-show-invalid-highlight:
$text-input-wp-show-focus-highlight !default;
```

fixes #6449
references #5052
This commit is contained in:
Brandy Carney
2016-07-15 11:31:42 -04:00
parent 86fd8a480f
commit 11a24b98aa
6 changed files with 296 additions and 42 deletions

View File

@ -16,6 +16,14 @@ $text-input-ios-input-clear-icon-color: rgba(0, 0, 0, .5) !default;
$text-input-ios-input-clear-icon-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path fill='" + $text-input-ios-input-clear-icon-color + "' d='M403.1,108.9c-81.2-81.2-212.9-81.2-294.2,0s-81.2,212.9,0,294.2c81.2,81.2,212.9,81.2,294.2,0S484.3,190.1,403.1,108.9z M352,340.2L340.2,352l-84.4-84.2l-84,83.8L160,339.8l84-83.8l-84-83.8l11.8-11.8l84,83.8l84.4-84.2l11.8,11.8L267.6,256L352,340.2z'/></svg>" !default;
$text-input-ios-input-clear-icon-size: 18px !default;
$text-input-ios-show-focus-highlight: false !default;
$text-input-ios-show-valid-highlight: $text-input-ios-show-focus-highlight !default;
$text-input-ios-show-invalid-highlight: $text-input-ios-show-focus-highlight !default;
$text-input-ios-highlight-color: color($colors-ios, primary) !default;
$text-input-ios-highlight-color-valid: color($colors-ios, secondary) !default;
$text-input-ios-highlight-color-invalid: color($colors-ios, danger) !default;
// iOS Default Input
// --------------------------------------------------
@ -82,3 +90,61 @@ ion-input[clearInput] {
background-size: $text-input-ios-input-clear-icon-size;
}
// iOS Highlighted Input
// --------------------------------------------------
// Input highlight mixin for focus, valid, and invalid states
@mixin ios-input-highlight($highlight-color) {
border-bottom-color: $highlight-color;
}
// Show the focus highlight when the input has focus
@if ($text-input-ios-show-focus-highlight) {
// In order to get a 2px border we need to add an inset
// box-shadow 1px (this is to avoid the div resizing)
.item-input.input-has-focus .item-inner {
@include ios-input-highlight($text-input-ios-highlight-color);
}
// The last item in a list has a border on the item, not the
// inner item, so add it to the item itself
ion-list .item-input.input-has-focus:last-child {
@include ios-input-highlight($text-input-ios-highlight-color);
.item-inner {
box-shadow: none;
}
}
}
// Show the valid highlight when it has the .ng-valid class and a value
@if ($text-input-ios-show-valid-highlight) {
.item-input.ng-valid.input-has-value:not(.input-has-focus) .item-inner {
@include ios-input-highlight($text-input-ios-highlight-color-valid);
}
ion-list .item-input.ng-valid.input-has-value:not(.input-has-focus):last-child {
@include ios-input-highlight($text-input-ios-highlight-color-valid);
.item-inner {
box-shadow: none;
}
}
}
// Show the invalid highlight when it has the invalid class and has been touched
@if ($text-input-ios-show-invalid-highlight) {
.item-input.ng-invalid.ng-touched:not(.input-has-focus) .item-inner {
@include ios-input-highlight($text-input-ios-highlight-color-invalid);
}
ion-list .item-input.ng-invalid.ng-touched:not(.input-has-focus):last-child {
@include ios-input-highlight($text-input-ios-highlight-color-invalid);
.item-inner {
box-shadow: none;
}
}
}

View File

@ -5,9 +5,6 @@
// --------------------------------------------------
$text-input-md-background-color: $list-md-background-color !default;
$text-input-md-highlight-color: color($colors-md, primary) !default;
$text-input-md-hightlight-color-valid: color($colors-md, secondary) !default;
$text-input-md-hightlight-color-invalid: color($colors-md, danger) !default;
$text-input-md-margin-top: $item-md-padding-top !default;
$text-input-md-margin-right: ($item-md-padding-right / 2) !default;
@ -19,8 +16,13 @@ $text-input-md-input-clear-icon-color: #5b5b5b !default;
$text-input-md-input-clear-icon-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><polygon fill='" + $text-input-md-input-clear-icon-color + "' points='405,136.798 375.202,107 256,226.202 136.798,107 107,136.798 226.202,256 107,375.202 136.798,405 256,285.798 375.202,405 405,375.202 285.798,256'/></svg>" !default;
$text-input-md-input-clear-icon-size: 22px !default;
$text-input-md-show-success-highlight: true !default;
$text-input-md-show-error-highlight: true !default;
$text-input-md-show-focus-highlight: true !default;
$text-input-md-show-valid-highlight: $text-input-md-show-focus-highlight !default;
$text-input-md-show-invalid-highlight: $text-input-md-show-focus-highlight !default;
$text-input-md-highlight-color: color($colors-md, primary) !default;
$text-input-md-highlight-color-valid: color($colors-md, secondary) !default;
$text-input-md-highlight-color-invalid: color($colors-md, danger) !default;
// Material Design Default Input
@ -46,42 +48,57 @@ $text-input-md-show-error-highlight: true !default;
// Material Design Highlighted Input
// --------------------------------------------------
.item-input::after {
position: absolute;
right: 0;
bottom: 0;
left: $item-md-padding-left;
border-bottom-width: 2px;
border-bottom-style: solid;
border-bottom-color: transparent;
content: "";
// Input highlight mixin for focus, valid, and invalid states
@mixin md-input-highlight($highlight-color) {
border-bottom-color: $highlight-color;
box-shadow: inset 0 -1px 0 0 $highlight-color;
}
.item-input.input-has-focus::after {
border-bottom-color: $text-input-md-highlight-color;
}
// Show the focus highlight when the input has focus
@if ($text-input-md-show-focus-highlight) {
// In order to get a 2px border we need to add an inset
// box-shadow 1px (this is to avoid the div resizing)
.item-input.input-has-focus .item-inner {
@include md-input-highlight($text-input-md-highlight-color);
}
@if($text-input-md-show-success-highlight) {
.item-input.ng-valid.input-has-value {
&::after {
border-bottom-color: $text-input-md-hightlight-color-valid;
}
// The last item in a list has a border on the item, not the
// inner item, so add it to the item itself
ion-list .item-input.input-has-focus:last-child {
@include md-input-highlight($text-input-md-highlight-color);
&.input-has-focus::after {
border-bottom-color: $text-input-md-highlight-color;
.item-inner {
box-shadow: none;
}
}
}
@if($text-input-md-show-error-highlight) {
.item-input.ng-invalid.ng-touched {
&::after {
border-bottom-color: $text-input-md-hightlight-color-invalid;
}
// Show the valid highlight when it has the .ng-valid class and a value
@if ($text-input-md-show-valid-highlight) {
.item-input.ng-valid.input-has-value:not(.input-has-focus) .item-inner {
@include md-input-highlight($text-input-md-highlight-color-valid);
}
&.input-has-focus::after {
border-bottom-color: $text-input-md-highlight-color;
ion-list .item-input.ng-valid.input-has-value:not(.input-has-focus):last-child {
@include md-input-highlight($text-input-md-highlight-color-valid);
.item-inner {
box-shadow: none;
}
}
}
// Show the invalid highlight when it has the invalid class and has been touched
@if ($text-input-md-show-invalid-highlight) {
.item-input.ng-invalid.ng-touched:not(.input-has-focus) .item-inner {
@include md-input-highlight($text-input-md-highlight-color-invalid);
}
ion-list .item-input.ng-invalid.ng-touched:not(.input-has-focus):last-child {
@include md-input-highlight($text-input-md-highlight-color-invalid);
.item-inner {
box-shadow: none;
}
}
}

View File

@ -16,15 +16,18 @@ $text-input-wp-padding-vertical: 0 !default;
$text-input-wp-padding-horizontal: 8px !default;
$text-input-wp-line-height: 3rem !default;
$text-input-wp-highlight-color: color($colors-wp, primary) !default;
$text-input-wp-hightlight-color-valid: color($colors-wp, secondary) !default;
$text-input-wp-hightlight-color-invalid: color($colors-wp, danger) !default;
$text-input-wp-input-clear-icon-width: 30px !default;
$text-input-wp-input-clear-icon-color: $input-wp-border-color !default;
$text-input-wp-input-clear-icon-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><polygon fill='" + $text-input-wp-input-clear-icon-color + "' points='405,136.798 375.202,107 256,226.202 136.798,107 107,136.798 226.202,256 107,375.202 136.798,405 256,285.798 375.202,405 405,375.202 285.798,256'/></svg>" !default;
$text-input-wp-input-clear-icon-size: 22px !default;
$text-input-wp-show-focus-highlight: true !default;
$text-input-wp-show-valid-highlight: $text-input-wp-show-focus-highlight !default;
$text-input-wp-show-invalid-highlight: $text-input-wp-show-focus-highlight !default;
$text-input-wp-highlight-color: color($colors-wp, primary) !default;
$text-input-wp-highlight-color-valid: color($colors-wp, secondary) !default;
$text-input-wp-highlight-color-invalid: color($colors-wp, danger) !default;
// Windows Default Input
@ -53,16 +56,25 @@ $text-input-wp-input-clear-icon-size: 22px !default;
// Windows Highlighted Input
// --------------------------------------------------
.input-has-focus .text-input {
border-color: $text-input-wp-highlight-color;
// Show the focus highlight when the input has focus
@if ($text-input-wp-show-focus-highlight) {
.item-input.input-has-focus .text-input {
border-color: $text-input-wp-highlight-color;
}
}
ion-input.ng-valid.input-has-value .text-input {
border-color: $text-input-wp-hightlight-color-valid;
// Show the valid highlight when it has the .ng-valid class and a value
@if ($text-input-wp-show-valid-highlight) {
.item-input.ng-valid.input-has-value:not(.input-has-focus) .text-input {
border-color: $text-input-wp-highlight-color-valid;
}
}
ion-input.ng-invalid.ng-touched .text-input {
border-color: $text-input-wp-hightlight-color-invalid;
// Show the invalid highlight when it has the invalid class and has been touched
@if ($text-input-wp-show-invalid-highlight) {
.item-input.ng-invalid.ng-touched:not(.input-has-focus) .text-input {
border-color: $text-input-wp-highlight-color-invalid;
}
}

View File

@ -0,0 +1,54 @@
import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/common';
import { ionicBootstrap } from '../../../../../src';
@Component({
templateUrl: 'main.html'
})
class E2EPage {
loginForm: any;
login = {
email: 'help@ionic.io',
username: 'admin',
};
submitted: boolean = false;
constructor(fb: FormBuilder) {
this.loginForm = fb.group({
email: ["", Validators.compose([
Validators.required,
this.emailValidator
])],
username: [""],
password: ["", Validators.required],
comments: ["", Validators.required],
inset: ["", Validators.required]
});
}
emailValidator(control: any) {
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
if (!EMAIL_REGEXP.test(control.value)) {
return {invalidEmail: true};
}
}
submit(ev: UIEvent, value: any) {
console.log("Submitted", value);
this.submitted = true;
}
}
@Component({
template: '<ion-nav [root]="root"></ion-nav>'
})
class E2EApp {
root = E2EPage;
}
ionicBootstrap(E2EApp);

View File

@ -0,0 +1,105 @@
<ion-header>
<ion-toolbar>
<ion-title>Form Inputs</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="outer-content">
<form [formGroup]="loginForm" #mf="ngForm" novalidate>
<ion-list>
<ion-item>
<ion-label stacked>Stacked</ion-label>
<ion-input clearInput [(ngModel)]="login.email" formControlName="email" type="email" required></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Floating</ion-label>
<ion-input clearInput [(ngModel)]="login.username" formControlName="username"></ion-input>
</ion-item>
<ion-item>
<ion-label fixed>Fixed</ion-label>
<ion-input clearInput [(ngModel)]="login.password" formControlName="password" type="password" required></ion-input>
</ion-item>
<ion-item>
<ion-label>Inline</ion-label>
<ion-textarea clearInput [(ngModel)]="login.comments" formControlName="comments" required>Comment value</ion-textarea>
</ion-item>
<ion-item inset>
<ion-label>Inset</ion-label>
<ion-input clearInput [(ngModel)]="login.inset" formControlName="inset" required></ion-input>
</ion-item>
</ion-list>
<ion-list>
<ion-item>
<ion-icon item-left name="logo-buffer"></ion-icon>
<ion-label stacked>Stacked</ion-label>
<ion-input clearInput [(ngModel)]="login.email" formControlName="email" type="email" required></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="apps"></ion-icon>
<ion-label floating>Floating</ion-label>
<ion-input clearInput [(ngModel)]="login.username" formControlName="username"></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="browsers"></ion-icon>
<ion-label fixed>Fixed</ion-label>
<ion-input clearInput [(ngModel)]="login.password" formControlName="password" type="password" required></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="card"></ion-icon>
<ion-label>Inline</ion-label>
<ion-textarea clearInput [(ngModel)]="login.comments" formControlName="comments" required>Comment value</ion-textarea>
</ion-item>
<ion-item inset>
<ion-icon item-left name="checkmark-circle"></ion-icon>
<ion-label>Inset</ion-label>
<ion-input clearInput [(ngModel)]="login.inset" formControlName="inset" required></ion-input>
</ion-item>
</ion-list>
<ion-card>
<ion-list>
<ion-item>
<ion-icon item-left name="logo-buffer"></ion-icon>
<ion-label stacked>Stacked</ion-label>
<ion-input clearInput [(ngModel)]="login.email" formControlName="email" type="email" required></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="apps"></ion-icon>
<ion-label floating>Floating</ion-label>
<ion-input clearInput [(ngModel)]="login.username" formControlName="username"></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="browsers"></ion-icon>
<ion-label fixed>Fixed</ion-label>
<ion-input clearInput [(ngModel)]="login.password" formControlName="password" type="password" required></ion-input>
</ion-item>
<ion-item>
<ion-icon item-left name="card"></ion-icon>
<ion-label>Inline</ion-label>
<ion-textarea clearInput [(ngModel)]="login.comments" formControlName="comments" required>Comment value</ion-textarea>
</ion-item>
<ion-item inset>
<ion-icon item-left name="checkmark-circle"></ion-icon>
<ion-label>Inset</ion-label>
<ion-input clearInput [(ngModel)]="login.inset" formControlName="inset" required></ion-input>
</ion-item>
</ion-list>
</ion-card>
</form>
</ion-content>