mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 21:48:42 +08:00
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:
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
0
src/components/input/test/highlight/e2e.ts
Normal file
0
src/components/input/test/highlight/e2e.ts
Normal file
54
src/components/input/test/highlight/index.ts
Normal file
54
src/components/input/test/highlight/index.ts
Normal 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);
|
105
src/components/input/test/highlight/main.html
Normal file
105
src/components/input/test/highlight/main.html
Normal 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>
|
Reference in New Issue
Block a user