Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components / paper-input / paper-input-container.html
blobbd585fa954c0de4ad7236e247012f1ff8f10ceca
1 <!--
2 @license
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9 -->
11 <link rel="import" href="../polymer/polymer.html">
12 <link rel="import" href="../paper-styles/paper-styles.html">
14 <!--
15 `<paper-input-container>` is a container for a `<label>`, an `<input is="iron-input">` or
16 `<iron-autogrow-textarea>` and optional add-on elements such as an error message or character
17 counter, used to implement Material Design text fields.
19 For example:
21 <paper-input-container>
22 <label>Your name</label>
23 <input is="iron-input">
24 </paper-input-container>
26 ### Listening for input changes
28 By default, it listens for changes on the `bind-value` attribute on its children nodes and perform
29 tasks such as auto-validating and label styling when the `bind-value` changes. You can configure
30 the attribute it listens to with the `attr-for-value` attribute.
32 ### Using a custom input element
34 You can use a custom input element in a `<paper-input-container>`, for example to implement a
35 compound input field like a social security number input. The custom input element should have the
36 `paper-input-input` class, have a `notify:true` value property and optionally implements
37 `Polymer.IronValidatableBehavior` if it is validatble.
39 <paper-input-container attr-for-value="ssn-value">
40 <label>Social security number</label>
41 <ssn-input class="paper-input-input"></ssn-input>
42 </paper-input-container>
44 ### Validation
46 If the `auto-validate` attribute is set, the input container will validate the input and update
47 the container styling when the input value changes.
49 ### Add-ons
51 Add-ons are child elements of a `<paper-input-container>` with the `add-on` attribute and
52 implements the `Polymer.PaperInputAddonBehavior` behavior. They are notified when the input value
53 or validity changes, and may implement functionality such as error messages or character counters.
54 They appear at the bottom of the input.
56 ### Styling
58 The following custom properties and mixins are available for styling:
60 Custom property | Description | Default
61 ----------------|-------------|----------
62 `--paper-input-container-color` | Label and underline color when the input is not focused | `--secondary-text-color`
63 `--paper-input-container-focus-color` | Label and underline color when the input is focused | `--default-primary-color`
64 `--paper-input-container-invalid-color` | Label and underline color when the input is focused | `--google-red-500`
65 `--paper-input-container-input-color` | Input foreground color | `--primary-text-color`
66 `--paper-input-container` | Mixin applied to the container | `{}`
67 `--paper-input-container-label` | Mixin applied to the label | `{}`
68 `--paper-input-container-label-focus` | Mixin applied to the label when the input is focused | `{}`
69 `--paper-input-container-input` | Mixin applied to the input | `{}`
70 `--paper-input-container-underline` | Mixin applied to the underline | `{}`
71 `--paper-input-container-underline-focus` | Mixin applied to the underline when the input is focued | `{}`
72 `--paper-input-container-underline-disabled` | Mixin applied to the underline when the input is disabled | `{}`
74 This element is `display:block` by default, but you can set the `inline` attribute to make it
75 `display:inline-block`.
76 -->
77 <dom-module id="paper-input-container">
79 <style>
81 :host {
82 display: block;
83 padding: 8px 0;
85 @apply(--paper-input-container);
88 :host[inline] {
89 display: inline-block;
92 :host([disabled]) {
93 pointer-events: none;
94 opacity: 0.33;
97 .floated-label-placeholder {
98 @apply(--paper-font-caption);
101 .underline {
102 position: relative;
105 .focused-line {
106 height: 2px;
108 -webkit-transform-origin: center center;
109 transform-origin: center center;
110 -webkit-transform: scale3d(0,1,1);
111 transform: scale3d(0,1,1);
113 background: var(--paper-input-container-focus-color, --default-primary-color);
115 @apply(--paper-input-container-underline-focus);
118 .underline.is-highlighted .focused-line {
119 -webkit-transform: none;
120 transform: none;
121 -webkit-transition: -webkit-transform 0.25s;
122 transition: transform 0.25s;
124 @apply(--paper-transition-easing);
127 .underline.is-invalid .focused-line {
128 background: var(--paper-input-container-invalid-color, --google-red-500);
130 -webkit-transform: none;
131 transform: none;
132 -webkit-transition: -webkit-transform 0.25s;
133 transition: transform 0.25s;
135 @apply(--paper-transition-easing);
138 .unfocused-line {
139 height: 1px;
140 background: var(--paper-input-container-color, --secondary-text-color);
142 @apply(--paper-input-container-underline);
145 :host([disabled]) .unfocused-line {
146 border-bottom: 1px dashed;
147 border-color: var(--paper-input-container-color, --secondary-text-color);
148 background: transparent;
150 @apply(--paper-input-container-underline-disabled);
153 .input-content {
154 position: relative;
157 .input-content ::content label,
158 .input-content ::content .paper-input-label {
159 position: absolute;
160 top: 0;
161 right: 0;
162 left: 0;
163 font: inherit;
164 color: var(--paper-input-container-color, --secondary-text-color);
166 @apply(--paper-font-subhead);
167 @apply(--paper-input-container-label);
170 .input-content.label-is-floating ::content label,
171 .input-content.label-is-floating ::content .paper-input-label {
172 -webkit-transform: translate3d(0, -75%, 0) scale(0.75);
173 transform: translate3d(0, -75%, 0) scale(0.75);
174 -webkit-transform-origin: left top;
175 transform-origin: left top;
176 -webkit-transition: -webkit-transform 0.25s;
177 transition: transform 0.25s;
179 @apply(--paper-transition-easing);
182 .input-content.label-is-highlighted ::content label,
183 .input-content.label-is-highlighted ::content .paper-input-label {
184 color: var(--paper-input-container-focus-color, --default-primary-color);
186 @apply(--paper-input-container-label-focus);
189 .input-content.is-invalid ::content label,
190 .input-content.is-invalid ::content .paper-input-label {
191 color: var(--paper-input-container-invalid-color, --google-red-500);
194 .input-content.label-is-hidden ::content label,
195 .input-content.label-is-hidden ::content .paper-input-label {
196 visibility: hidden;
199 .input-content ::content input,
200 .input-content ::content textarea,
201 .input-content ::content iron-autogrow-textarea,
202 .input-content ::content .paper-input-input {
203 position: relative; /* to make a stacking context */
204 outline: none;
205 box-shadow: none;
206 padding: 0;
207 width: 100%;
208 background: transparent;
209 border: none;
210 color: var(--paper-input-container-input-color, --primary-text-color);
212 @apply(--paper-font-subhead);
213 @apply(--paper-input-container-input);
216 /* Firefox sets a min-width on the input, which can cause layout issues */
217 .input-content ::content input {
218 min-width: 0;
221 .input-content ::content textarea {
222 resize: none;
225 .add-on-content.is-invalid ::content * {
226 color: var(--paper-input-container-invalid-color, --google-red-500);
229 .add-on-content.is-highlighted ::content * {
230 color: var(--paper-input-container-focus-color, --default-primary-color);
233 </style>
235 <template>
237 <template is="dom-if" if="[[!noLabelFloat]]">
238 <div class="floated-label-placeholder">&nbsp;</div>
239 </template>
241 <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]">
242 <content select=":not([add-on])"></content>
243 </div>
245 <div class$="[[_computeUnderlineClass(focused,invalid)]]">
246 <div class="unfocused-line fit"></div>
247 <div class="focused-line fit"></div>
248 </div>
250 <div class$="[[_computeAddOnContentClass(focused,invalid)]]">
251 <content id="addOnContent" select="[add-on]"></content>
252 </div>
254 </template>
256 </dom-module>
258 <script>
259 (function() {
261 Polymer({
263 is: 'paper-input-container',
265 properties: {
268 * Set to true to disable the floating label. The label disappears when the input value is
269 * not null.
271 noLabelFloat: {
272 type: Boolean,
273 value: false
277 * Set to true to always float the floating label.
279 alwaysFloatLabel: {
280 type: Boolean,
281 value: false
285 * The attribute to listen for value changes on.
287 attrForValue: {
288 type: String,
289 value: 'bind-value'
293 * Set to true to auto-validate the input value when it changes.
295 autoValidate: {
296 type: Boolean,
297 value: false
301 * True if the input is invalid. This property is set automatically when the input value
302 * changes if auto-validating, or when the `iron-input-valid` event is heard from a child.
304 invalid: {
305 observer: '_invalidChanged',
306 type: Boolean,
307 value: false
311 * True if the input has focus.
313 focused: {
314 readOnly: true,
315 type: Boolean,
316 value: false
319 _addons: {
320 type: Array
321 // do not set a default value here intentionally - it will be initialized lazily when a
322 // distributed child is attached, which may occur before configuration for this element
323 // in polyfill.
326 _inputHasContent: {
327 type: Boolean,
328 value: false
331 _inputSelector: {
332 type: String,
333 value: 'input,textarea,.paper-input-input'
336 _boundOnFocus: {
337 type: Function,
338 value: function() {
339 return this._onFocus.bind(this);
343 _boundOnBlur: {
344 type: Function,
345 value: function() {
346 return this._onBlur.bind(this);
350 _boundOnInput: {
351 type: Function,
352 value: function() {
353 return this._onInput.bind(this);
357 _boundValueChanged: {
358 type: Function,
359 value: function() {
360 return this._onValueChanged.bind(this);
366 listeners: {
367 'addon-attached': '_onAddonAttached',
368 'iron-input-validate': '_onIronInputValidate'
371 get _valueChangedEvent() {
372 return this.attrForValue + '-changed';
375 get _propertyForValue() {
376 return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
379 get _inputElement() {
380 return Polymer.dom(this).querySelector(this._inputSelector);
383 ready: function() {
384 if (!this._addons) {
385 this._addons = [];
387 this.addEventListener('focus', this._boundOnFocus, true);
388 this.addEventListener('blur', this._boundOnBlur, true);
389 if (this.attrForValue) {
390 this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
391 } else {
392 this.addEventListener('input', this._onInput);
396 attached: function() {
397 this._handleValue(this._inputElement);
400 _onAddonAttached: function(event) {
401 if (!this._addons) {
402 this._addons = [];
404 var target = event.target;
405 if (this._addons.indexOf(target) === -1) {
406 this._addons.push(target);
407 if (this.isAttached) {
408 this._handleValue(this._inputElement);
413 _onFocus: function() {
414 this._setFocused(true);
417 _onBlur: function() {
418 this._setFocused(false);
421 _onInput: function(event) {
422 this._handleValue(event.target);
425 _onValueChanged: function(event) {
426 this._handleValue(event.target);
429 _handleValue: function(inputElement) {
430 var value = inputElement[this._propertyForValue] || inputElement.value;
432 if (this.autoValidate) {
433 var valid;
434 if (inputElement.validate) {
435 valid = inputElement.validate(value);
436 } else {
437 valid = inputElement.checkValidity();
439 this.invalid = !valid;
442 // type="number" hack needed because this.value is empty until it's valid
443 if (value || (inputElement.type === 'number' && !inputElement.checkValidity())) {
444 this._inputHasContent = true;
445 } else {
446 this._inputHasContent = false;
449 this.updateAddons({
450 inputElement: inputElement,
451 value: value,
452 invalid: this.invalid
456 _onIronInputValidate: function(event) {
457 this.invalid = this._inputElement.invalid;
460 _invalidChanged: function() {
461 if (this._addons) {
462 this.updateAddons({invalid: this.invalid});
467 * Call this to update the state of add-ons.
468 * @param {Object} state Add-on state.
470 updateAddons: function(state) {
471 for (var addon, index = 0; addon = this._addons[index]; index++) {
472 addon.update(state);
476 _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
477 var cls = 'input-content';
478 if (!noLabelFloat) {
479 if (alwaysFloatLabel || _inputHasContent) {
480 cls += ' label-is-floating';
481 if (invalid) {
482 cls += ' is-invalid';
483 } else if (focused) {
484 cls += " label-is-highlighted";
487 } else {
488 if (_inputHasContent) {
489 cls += ' label-is-hidden';
492 return cls;
495 _computeUnderlineClass: function(focused, invalid) {
496 var cls = 'underline';
497 if (invalid) {
498 cls += ' is-invalid';
499 } else if (focused) {
500 cls += ' is-highlighted'
502 return cls;
505 _computeAddOnContentClass: function(focused, invalid) {
506 var cls = 'add-on-content';
507 if (invalid) {
508 cls += ' is-invalid';
509 } else if (focused) {
510 cls += ' is-highlighted'
512 return cls;
517 })();
518 </script>