Skip to content

Commit

Permalink
feat(MdInput): README.md improvements and autofill support.
Browse files Browse the repository at this point in the history
* Change the CSS to allow for autofill reactions; it works!
* Add a lot of examples and information to the README.md
* Add support for `warn` color to the labels.
hansl committed Apr 3, 2016
1 parent 5a6657a commit b711c2b
Showing 7 changed files with 239 additions and 42 deletions.
87 changes: 83 additions & 4 deletions src/components/input/README.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@

Inputs are the basic input component of Material 2. The spec can be found [here](https://www.google.com/design/spec/components/text-fields.html).

### Screenshots


## Notes
* The `<md-input>` component fully support two-way binding of `ngModel`, as if it was a normal `<input>`.



@@ -12,22 +15,27 @@ At the time of writing this README, the `[type]` attribute is copied to the actu

The valid `type` attribute values are any supported by your browser, with the exception of `file`, `checkbox` and `radio`. File inputs aren't supported for now, while check boxes and radio buttons have their own components.



## Prefix and Suffix

You can include HTML before, and after the input tag, as prefix or suffix. It will be underlined as per the Material specification, and clicking it will focus the input.

To add a prefix, use the `md-prefix` attribute on the element. Similarly, to add a suffix, use the `md-suffix` attribute. For example, in a template:

#### Example

```html
<md-input type="number" placeholder="amount">
<span md-prefix>$</span>
<md-input placeholder="amount" align="end">
<span md-prefix>$&nbsp;</span>
<span md-suffix>.00</span>
</md-input>
```

Will result in this:

!!!! INSERT SCREENSHOT HERE.
<img src="https://material.angularjs.org/material2_assets/input/prefix-suffix.png">



## Hint Labels
@@ -38,5 +46,76 @@ You specify a hint-label in one of two ways; either using the `hintLabel` attrib

Specifying a side twice will result in an exception during initialization.

#### Example

A simple character counter can be made like the following:

```html
<md-input placeholder="Character count (100 max)" maxLength="100" class="demo-full-width"
value="Hello world. How are you?"
#characterCountHintExample>
<md-hint align="end">{{characterCountHintExample.characterCount}} / 100</md-hint>
</md-input>
```

<img src="https://material.angularjs.org/material2_assets/input/character-count.png">



## Divider Color

The divider (line under the <md-input> content) color can be changed by using the `dividerColor` attribute. A value of `primary` is the default and will correspond to your theme primary color. Alternatively, you can specify `accent` or `warn`.

#### Example

^((please not that this example has been doctored to show the colors; they would normally show only on focus)^)

<img src="https://material.angularjs.org/material2_assets/input/divider-colors.png">



## Labelling

You can label the `<md-input>` as you would a regular `<input>`.



## Full Forms

You can make a full form using inputs, and it will support autofill natively.

#### Example

```html
<md-card class="demo-card demo-basic">
<md-toolbar color="primary">Basic</md-toolbar>
<md-card-content>
<form>
<md-input class="demo-full-width" placeholder="Company (disabled)" disabled value="Google">
</md-input>

<table style="width: 100%" cellspacing="0"><tr>
<td><md-input placeholder="First name" style="width: 100%"></md-input></td>
<td><md-input placeholder="Long Last Name That Will Be Truncated" style="width: 100%"></md-input></td>
</tr></table>
<p>
<md-input class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-input>
<md-input class="demo-full-width" placeholder="Address 2"></md-input>
</p>
<table style="width: 100%" cellspacing="0"><tr>
<td><md-input class="demo-full-width" placeholder="City"></md-input></td>
<td><md-input class="demo-full-width" placeholder="State"></md-input></td>
<td><md-input #postalCode class="demo-full-width" maxLength="5"
placeholder="Postal Code"
value="94043">
<md-hint align="end">{{postalCode.characterCount}} / 5</md-hint>
</md-input></td>
</tr></table>
</form>
</md-card-content>
</md-card>
```

Will result in this:

<img src="https://material.angularjs.org/material2_assets/input/full-form.png">
62 changes: 33 additions & 29 deletions src/components/input/input.html
Original file line number Diff line number Diff line change
@@ -2,35 +2,38 @@
<div class="md-input-table">
<div class="md-input-prefix"><ng-content select="[md-prefix]"></ng-content></div>

<label class="md-input-placeholder"
[attr.for]="id"
[class.md-empty]="empty"
[class.md-focused]="focused"
[class.md-float]="floatingPlaceholder"
[class.md-accent]="dividerColor == 'accent'"
*ngIf="hasPlaceholder()">
<ng-content select="md-placeholder"></ng-content>
{{placeholder}}
<span class="md-placeholder-required" *ngIf="required">*</span>
</label>
<div class="md-input-infix">
<input #input
aria-target
class="md-input-element"
[class.md-end]="align == 'end'"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledBy"
[attr.aria-disabled]="ariaDisabled"
[attr.aria-required]="ariaRequired"
[attr.aria-invalid]="ariaInvalid"
[id]="id"
[disabled]="disabled"
[required]="required"
[attr.maxlength]="maxLength"
[type]="type"
(focus)="onFocus()"
(blur)="onBlur()"
[(ngModel)]="value">

<input #input
aria-target
class="md-input-element"
[class.md-end]="align == 'end'"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledBy"
[attr.aria-disabled]="ariaDisabled"
[attr.aria-required]="ariaRequired"
[attr.aria-invalid]="ariaInvalid"
[id]="id"
[disabled]="disabled"
[required]="required"
[attr.maxlength]="maxLength"
[type]="type"
(focus)="onFocus()"
(blur)="onBlur()"
[(ngModel)]="value">
<label class="md-input-placeholder"
[attr.for]="id"
[class.md-empty]="empty"
[class.md-focused]="focused"
[class.md-float]="floatingPlaceholder"
[class.md-accent]="dividerColor == 'accent'"
[class.md-warn]="dividerColor == 'warn'"
*ngIf="hasPlaceholder()">
<ng-content select="md-placeholder"></ng-content>
{{placeholder}}
<span class="md-placeholder-required" *ngIf="required">*</span>
</label>
</div>

<div class="md-input-suffix"><ng-content select="[md-suffix]"></ng-content></div>
</div>
@@ -39,7 +42,8 @@
[class.md-disabled]="disabled">
<span class="md-input-ripple"
[class.md-focused]="focused"
[class.md-accent]="dividerColor == 'accent'"></span>
[class.md-accent]="dividerColor == 'accent'"
[class.md-warn]="dividerColor == 'warn'"></span>
</div>

<div *ngIf="hintLabel != ''" class="md-hint">{{hintLabel}}</div>
58 changes: 51 additions & 7 deletions src/components/input/input.scss
Original file line number Diff line number Diff line change
@@ -11,18 +11,37 @@ $md-input-required-placeholder-color: md-color($md-accent);
// Underline colors.
$md-input-underline-color: md-color($md-foreground, hint-text);
$md-input-underline-color-accent: md-color($md-accent);
$md-input-underline-color-warn: md-color($md-warn);
$md-input-underline-disabled-color: md-color($md-foreground, hint-text);
$md-input-underline-focused-color: md-color($md-primary);

// Gradient for showing the dashed line when the input is disabled.
$md-input-underline-disabled-background-image: linear-gradient(to right,
rgba(0,0,0,0.26) 0%, rgba(0,0,0,0.26) 33%, transparent 0%);


/**
* Applies a floating placeholder above the input itself.
*/
%md-input-placeholder-floating {
visibility: visible;
padding-bottom: 5px;
transform: translateY(-100%) scale(0.75);

.md-placeholder-required {
color: $md-input-required-placeholder-color;
}
}


:host {
display: inline-block;
position: relative;
font-family: $md-font-family;

// To avoid problems with text-align.
text-align: left;

// Global wrapper. We need to apply margin to the element for spacing, but
// cannot apply it to the host element directly.
.md-input-wrapper {
@@ -61,18 +80,32 @@ $md-input-underline-disabled-background-image: linear-gradient(to right,
}
}

.md-input-infix {
position: relative;
}

// The placeholder label. This is invisible unless it is. The logic to show it is
// basically `empty || (float && (!empty || focused))`. Float is dependent on the
// `floatingPlaceholder` input.
.md-input-placeholder {
// The placeholder is after the <input>, but needs to be aligned top-left of the
// infix <div>.
position: absolute;
left: 0;
top: 0;

visibility: hidden;
font-size: 100%;
pointer-events: none; // We shouldn't catch mouse events (let them through).
color: $md-input-placeholder-color;
z-index: 1;

// Put ellipsis text overflow.
width: 100%;
display: block;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;

transform: translateY(0);
transform-origin: bottom left;
@@ -87,13 +120,7 @@ $md-input-underline-disabled-background-image: linear-gradient(to right,

// Show the placeholder above the input when it's not empty, or focused.
&.md-float:not(.md-empty), &.md-float.md-focused {
visibility: visible;
padding-bottom: 5px;
transform: translateY(-100%) scale(0.75);

.md-placeholder-required {
color: $md-input-required-placeholder-color;
}
@extend %md-input-placeholder-floating;
}

// :focus is applied to the input, but we apply md-focused to the other elements
@@ -104,9 +131,21 @@ $md-input-underline-disabled-background-image: linear-gradient(to right,
&.md-accent {
color: $md-input-underline-color-accent;
}
&.md-warn {
color: $md-input-underline-color-warn;
}
}
}

// Pseudo-class for Chrome and Safari auto-fill to move the placeholder to
// the floating position. This is necessary because these browsers do not actually
// fire any events when a form auto-fill is occurring.
// Once the autofill is committed, a change event happen and the regular md-input
// classes take over to fulfill this behaviour.
input:-webkit-autofill + .md-input-placeholder {
@extend %md-input-placeholder-floating;
}

// The underline is what's shown under the input, its prefix and its suffix.
// The ripple is the blue animation coming on top of it.
.md-input-underline {
@@ -140,6 +179,9 @@ $md-input-underline-disabled-background-image: linear-gradient(to right,
&.md-accent {
background-color: $md-input-underline-color-accent;
}
&.md-warn {
background-color: $md-input-underline-color-warn;
}

&.md-focused {
opacity: 1;
@@ -164,6 +206,8 @@ $md-input-underline-disabled-background-image: linear-gradient(to right,

// RTL support.
:host-context([dir="rtl"]) {
text-align: right;

.md-input-placeholder {
transform-origin: bottom right;
}
2 changes: 1 addition & 1 deletion src/components/input/input.ts
Original file line number Diff line number Diff line change
@@ -131,7 +131,7 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange
*/
@Input() @OneOf(['start', 'end']) align: string = 'start';
@Input() @BooleanFieldValue() disabled: boolean = false;
@Input() @OneOf(['primary', 'accent']) dividerColor: string = 'primary';
@Input() @OneOf(['primary', 'accent', 'warn']) dividerColor: string = 'primary';
@Input() @BooleanFieldValue() floatingPlaceholder: boolean = true;
@Input() hintLabel: string = '';
@Input() id: string = `md-input-${nextUniqueId++}`;
60 changes: 60 additions & 0 deletions src/demo-app/input/input-demo.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,63 @@
<md-card class="demo-card demo-basic">
<md-toolbar color="primary">Basic</md-toolbar>
<md-card-content>
<form>
<md-input class="demo-full-width" placeholder="Company (disabled)" disabled value="Google">
</md-input>

<table style="width: 100%" cellspacing="0"><tr>
<td><md-input placeholder="First name" style="width: 100%"></md-input></td>
<td><md-input placeholder="Long Last Name That Will Be Truncated" style="width: 100%"></md-input></td>
</tr></table>
<p>
<md-input class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-input>
<md-input class="demo-full-width" placeholder="Address 2"></md-input>
</p>
<table style="width: 100%" cellspacing="0"><tr>
<td><md-input class="demo-full-width" placeholder="City" value="Mountain View"></md-input></td>
<td><md-input class="demo-full-width" placeholder="State" maxLength="2" value="CA"></md-input></td>
<td><md-input #postalCode class="demo-full-width" maxLength="5"
placeholder="Postal Code"
value="94043">
<md-hint align="end">{{postalCode.characterCount}} / 5</md-hint>
</md-input></td>
</tr></table>
</form>
</md-card-content>
</md-card>

<md-card class="demo-card demo-basic">
<md-toolbar color="primary">Prefix + Suffix</md-toolbar>
<md-card-content>
<md-input placeholder="amount" align="end">
<span md-prefix>$&nbsp;</span>
<span md-suffix>.00</span>
</md-input>
</md-card-content>
</md-card>

<md-card class="demo-card demo-basic">
<md-toolbar color="primary">Divider Colors</md-toolbar>
<md-card-content>
<md-input dividerColor="primary" placeholder="Default Color" value="example"></md-input>
<md-input dividerColor="accent" placeholder="Accent Color" value="example"></md-input>
<md-input dividerColor="warn" placeholder="Warn Color" value="example"></md-input>
</md-card-content>
</md-card>

<md-card class="demo-card demo-basic">
<md-toolbar color="primary">Hints</md-toolbar>
<md-card-content>
<p>
<md-input placeholder="Character count (100 max)" maxLength="100" class="demo-full-width"
value="Hello world. How are you?"
#characterCountHintExample>
<md-hint align="end">{{characterCountHintExample.characterCount}} / 100</md-hint>
</md-input>
</p>
</md-card-content>
</md-card>

<md-card class="demo-card">
<md-card-title>
Hello <md-input [(ngModel)]="name" type="string" placeholder="First name"></md-input>,
9 changes: 9 additions & 0 deletions src/demo-app/input/input-demo.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
@import 'default-theme';
@import 'variables';

.demo-basic {
padding: 0;
}
.demo-basic md-card-content {
padding: 16px;
}
.demo-full-width {
width: 100%;
}

.demo-icons {
font-size: 100%;
3 changes: 2 additions & 1 deletion src/demo-app/input/input-demo.ts
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ import {MD_INPUT_DIRECTIVES} from '../../components/input/input';
import {MdButton} from '../../components/button/button';
import {MdCard} from '../../components/card/card';
import {MdCheckbox} from '../../components/checkbox/checkbox';
import {MdToolbar} from '../../components/toolbar/toolbar';


let max = 5;
@@ -11,7 +12,7 @@ let max = 5;
selector: 'input-demo',
templateUrl: 'demo-app/input/input-demo.html',
styleUrls: ['demo-app/input/input-demo.css'],
directives: [MdCard, MdCheckbox, MdButton, MD_INPUT_DIRECTIVES]
directives: [MdCard, MdCheckbox, MdButton, MdToolbar, MD_INPUT_DIRECTIVES]
})
export class InputDemo {
dividerColor: boolean;

0 comments on commit b711c2b

Please sign in to comment.