OLD | NEW |
(Empty) | |
| 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.g
ithub.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/CONTRI
BUTORS.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/PATEN
TS.txt |
| 9 --> |
| 10 |
| 11 <link rel="import" href="../polymer/polymer.html"> |
| 12 <link rel="import" href="../paper-styles/paper-styles.html"> |
| 13 |
| 14 <style is="x-style"> |
| 15 |
| 16 * { |
| 17 |
| 18 --paper-input-container-font: var(--paper-font-subhead); |
| 19 --paper-input-container-floating-label-font: var(--paper-font-caption); |
| 20 --paper-input-container-add-on-font: var(--paper-font-caption); |
| 21 |
| 22 --paper-input-container-focus-color: var(--default-primary-color); |
| 23 --paper-input-container-color: var(--secondary-text-color); |
| 24 --paper-input-container-invalid-color: var(--google-red-500); |
| 25 --paper-input-container-input-color: var(--primary-text-color); |
| 26 |
| 27 } |
| 28 |
| 29 </style> |
| 30 |
| 31 <!-- |
| 32 `<paper-input-container>` wraps an `<input>` and `<label>` element, decorating |
| 33 them following the [Material Design spec](http://www.google.com/design/spec/comp
onents/text-fields.html#text-fields-single-line-text-field) |
| 34 |
| 35 For example: |
| 36 |
| 37 <paper-input-container> |
| 38 <label>email address</label> |
| 39 <input type="email"> |
| 40 </paper-input-container> |
| 41 |
| 42 --> |
| 43 <dom-module id="paper-input-container"> |
| 44 |
| 45 <style> |
| 46 |
| 47 :host { |
| 48 display: block; |
| 49 padding: 8px 0; |
| 50 |
| 51 --mixin(--paper-input-container); |
| 52 } |
| 53 |
| 54 .floated-label-placeholder { |
| 55 mixin(--paper-input-container-label-font); |
| 56 } |
| 57 |
| 58 .focused-line { |
| 59 height: 2px; |
| 60 |
| 61 -webkit-transform-origin: center center; |
| 62 transform-origin: center center; |
| 63 -webkit-transform: scale3d(0,1,1); |
| 64 transform: scale3d(0,1,1); |
| 65 |
| 66 background: var(--paper-input-container-focus-color); |
| 67 } |
| 68 |
| 69 .is-highlighted .focused-line { |
| 70 -webkit-transform: none; |
| 71 transform: none; |
| 72 -webkit-transition: -webkit-transform 0.25s; |
| 73 transition: transform 0.25s; |
| 74 |
| 75 mixin(--paper-transition-easing); |
| 76 } |
| 77 |
| 78 .is-invalid .focused-line { |
| 79 background: var(--paper-input-container-invalid-color); |
| 80 |
| 81 -webkit-transform: none; |
| 82 transform: none; |
| 83 -webkit-transition: -webkit-transform 0.25s; |
| 84 transition: transform 0.25s; |
| 85 |
| 86 mixin(--paper-transition-easing); |
| 87 } |
| 88 |
| 89 .unfocused-line { |
| 90 height: 1px; |
| 91 background: var(--paper-input-container-color); |
| 92 } |
| 93 |
| 94 .input-content ::content label, |
| 95 .input-content ::content .paper-input-label { |
| 96 position: absolute; |
| 97 top: 0; |
| 98 right: 0; |
| 99 left: 0; |
| 100 font: inherit; |
| 101 color: var(--paper-input-container-color); |
| 102 |
| 103 mixin(--paper-input-container-font); |
| 104 |
| 105 mixin(--paper-input-container-label); |
| 106 } |
| 107 |
| 108 .input-content.label-is-floating ::content label, |
| 109 .input-content.label-is-floating ::content .paper-input-label { |
| 110 -webkit-transform: translate3d(0, -75%, 0) scale(0.75); |
| 111 transform: translate3d(0, -75%, 0) scale(0.75); |
| 112 -webkit-transform-origin: left top; |
| 113 transform-origin: left top; |
| 114 -webkit-transition: -webkit-transform 0.25s; |
| 115 transition: transform 0.25s; |
| 116 |
| 117 mixin(--paper-transition-easing); |
| 118 } |
| 119 |
| 120 .input-content.label-is-highlighted ::content label, |
| 121 .input-content.label-is-highlighted ::content .paper-input-label { |
| 122 color: var(--paper-input-container-focus-color); |
| 123 } |
| 124 |
| 125 .input-content.is-invalid ::content label, |
| 126 .input-content.is-invalid ::content .paper-input-label { |
| 127 color: var(--paper-input-container-invalid-color); |
| 128 } |
| 129 |
| 130 .input-content.label-is-hidden ::content label, |
| 131 .input-content.label-is-hidden ::content .paper-input-label { |
| 132 visibility: hidden; |
| 133 } |
| 134 |
| 135 .input-content ::content input, |
| 136 .input-content ::content textarea, |
| 137 .input-content ::content .paper-input-input { |
| 138 position: relative; /* to make a stacking context */ |
| 139 outline: none; |
| 140 color: var(--paper-input-container-input-color); |
| 141 |
| 142 mixin(--paper-input-container-floating-label-font); |
| 143 } |
| 144 |
| 145 .input-content ::content input, |
| 146 .input-content ::content textarea { |
| 147 padding: 0; |
| 148 width: 100%; |
| 149 background: transparent; |
| 150 border: none; |
| 151 |
| 152 mixin(--paper-input-container-font); |
| 153 |
| 154 mixin(--paper-input-container-input); |
| 155 } |
| 156 |
| 157 .input-content ::content textarea { |
| 158 resize: none; |
| 159 } |
| 160 |
| 161 .add-on-content.is-invalid ::content * { |
| 162 color: var(--paper-input-container-invalid-color); |
| 163 } |
| 164 |
| 165 .add-on-content.is-highlighted ::content * { |
| 166 color: var(--paper-input-container-focus-color); |
| 167 } |
| 168 |
| 169 </style> |
| 170 |
| 171 <template> |
| 172 |
| 173 <template is="x-if" if="[[!noLabelFloat]]"> |
| 174 <div class="floated-label-placeholder"> </div> |
| 175 </template> |
| 176 |
| 177 <div class$="[[_computeInputContentClass(noLabelFloat,focused,_inputHasConte
nt,_inputIsInvalid)]]"> |
| 178 <content select=":not([add-on])"></content> |
| 179 </div> |
| 180 |
| 181 <div class$="[[_computeUnderlineClass(focused,_inputIsInvalid)]]"> |
| 182 <div class="unfocused-line fit"></div> |
| 183 <div class="focused-line fit"></div> |
| 184 </div> |
| 185 |
| 186 <div class$="[[_computeAddOnContentClass(focused,_inputIsInvalid)]]"> |
| 187 <content id="addOnContent" select="[add-on]"></content> |
| 188 </div> |
| 189 |
| 190 </template> |
| 191 |
| 192 </dom-module> |
| 193 |
| 194 <script> |
| 195 (function() { |
| 196 |
| 197 Polymer({ |
| 198 |
| 199 is: 'paper-input-container', |
| 200 |
| 201 enableCustomStyleProperties: true, |
| 202 |
| 203 properties: { |
| 204 |
| 205 /** |
| 206 * Set to true to disable the floating label. |
| 207 */ |
| 208 noLabelFloat: { |
| 209 type: Boolean, |
| 210 value: false |
| 211 }, |
| 212 |
| 213 /** |
| 214 * The attribute to listen for value changes on. |
| 215 */ |
| 216 attrForValue: { |
| 217 type: String, |
| 218 value: 'bind-value' |
| 219 }, |
| 220 |
| 221 /** |
| 222 * Set to true to auto-validate the input value. |
| 223 */ |
| 224 autoValidate: { |
| 225 type: Boolean, |
| 226 value: false |
| 227 }, |
| 228 |
| 229 /** |
| 230 * True if the input has focus. |
| 231 */ |
| 232 focused: { |
| 233 readOnly: true, |
| 234 type: Boolean, |
| 235 value: false |
| 236 }, |
| 237 |
| 238 _addons: { |
| 239 type: Array, |
| 240 value: function() { |
| 241 return []; |
| 242 } |
| 243 }, |
| 244 |
| 245 _inputHasContent: { |
| 246 type: Boolean, |
| 247 value: false |
| 248 }, |
| 249 |
| 250 _inputIsInvalid: { |
| 251 type: Boolean, |
| 252 value: false |
| 253 }, |
| 254 |
| 255 _inputSelector: { |
| 256 type: String, |
| 257 value: 'input,textarea,.paper-input-input' |
| 258 }, |
| 259 |
| 260 _boundOnFocus: { |
| 261 type: Function, |
| 262 value: function() { |
| 263 return this._onFocus.bind(this); |
| 264 } |
| 265 }, |
| 266 |
| 267 _boundOnBlur: { |
| 268 type: Function, |
| 269 value: function() { |
| 270 return this._onBlur.bind(this); |
| 271 } |
| 272 }, |
| 273 |
| 274 _boundValueChanged: { |
| 275 type: Function, |
| 276 value: function() { |
| 277 return this._onValueChanged.bind(this); |
| 278 } |
| 279 } |
| 280 |
| 281 }, |
| 282 |
| 283 listeners: { |
| 284 'addon-attached': '_onAddonAttached', |
| 285 'input': '_onInput' |
| 286 }, |
| 287 |
| 288 get _valueChangedEvent() { |
| 289 return this.attrForValue + '-changed'; |
| 290 }, |
| 291 |
| 292 get _propertyForValue() { |
| 293 return Polymer.CaseMap.dashToCamelCase(this.attrForValue); |
| 294 }, |
| 295 |
| 296 get _inputElement() { |
| 297 return Polymer.dom(this).querySelector(this._inputSelector); |
| 298 }, |
| 299 |
| 300 ready: function() { |
| 301 this.addEventListener('focus', this._boundOnFocus, true); |
| 302 this.addEventListener('blur', this._boundOnBlur, true); |
| 303 this.addEventListener(this._valueChangedEvent, this._boundValueChanged, tr
ue); |
| 304 }, |
| 305 |
| 306 attached: function() { |
| 307 this._handleInput(this._inputElement); |
| 308 }, |
| 309 |
| 310 _onAddonAttached: function(event) { |
| 311 this._addons.push(event.target); |
| 312 this._handleInput(this._inputElement); |
| 313 }, |
| 314 |
| 315 _onFocus: function() { |
| 316 this._setFocused(true); |
| 317 }, |
| 318 |
| 319 _onBlur: function() { |
| 320 this._setFocused(false); |
| 321 }, |
| 322 |
| 323 _onInput: function(event) { |
| 324 this._handleInput(event.target); |
| 325 }, |
| 326 |
| 327 _onValueChanged: function(event) { |
| 328 this._handleInput(event.target); |
| 329 }, |
| 330 |
| 331 _handleInput: function(inputElement) { |
| 332 var value = inputElement[this._propertyForValue] || inputElement.value; |
| 333 var valid = inputElement.checkValidity(); |
| 334 |
| 335 // type="number" hack needed because this.value is empty until it's valid |
| 336 if (value || inputElement.type === 'number' && !valid) { |
| 337 this._inputHasContent = true; |
| 338 } else { |
| 339 this._inputHasContent = false; |
| 340 } |
| 341 |
| 342 if (this.autoValidate) { |
| 343 this._inputIsInvalid = !valid; |
| 344 } |
| 345 |
| 346 // notify add-ons |
| 347 for (var addon, i = 0; addon = this._addons[i]; i++) { |
| 348 // need to set all of these, or call method... thanks input type="number
"! |
| 349 addon.inputElement = inputElement; |
| 350 addon.value = value; |
| 351 addon.invalid = !valid; |
| 352 } |
| 353 }, |
| 354 |
| 355 _computeInputContentClass: function(noLabelFloat, focused, _inputHasContent,
_inputIsInvalid) { |
| 356 var cls = 'input-content relative'; |
| 357 if (!noLabelFloat) { |
| 358 if (_inputHasContent) { |
| 359 cls += ' label-is-floating'; |
| 360 if (_inputIsInvalid) { |
| 361 cls += ' is-invalid'; |
| 362 } else if (focused) { |
| 363 cls += " label-is-highlighted"; |
| 364 } |
| 365 } |
| 366 } else { |
| 367 if (_inputHasContent) { |
| 368 cls += ' label-is-hidden'; |
| 369 } |
| 370 } |
| 371 return cls; |
| 372 }, |
| 373 |
| 374 _computeUnderlineClass: function(focused, _inputIsInvalid) { |
| 375 var cls = 'relative'; |
| 376 if (_inputIsInvalid) { |
| 377 cls += ' is-invalid'; |
| 378 } else if (focused) { |
| 379 cls += ' is-highlighted' |
| 380 } |
| 381 return cls; |
| 382 }, |
| 383 |
| 384 _computeAddOnContentClass: function(focused, _inputIsInvalid) { |
| 385 var cls = 'add-on-content'; |
| 386 if (_inputIsInvalid) { |
| 387 cls += ' is-invalid'; |
| 388 } else if (focused) { |
| 389 cls += ' is-highlighted' |
| 390 } |
| 391 return cls; |
| 392 } |
| 393 |
| 394 }); |
| 395 |
| 396 })(); |
| 397 </script> |
OLD | NEW |