api-console-assets
Version:
This repo only exists to publish api console components to npm
536 lines (475 loc) • 16.7 kB
HTML
<!--
@license
Copyright 2017 Mulesoft.
All rights reserved.
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../anypoint-styles/typography.html">
<link rel="import" href="../anypoint-styles/colors.html">
<!--
The `<paper-input-container>` is a container for a `label` and input text styled to match the
Anypoint platform styling.
### Styling
`<paper-input-field>` provides the following custom properties and mixins for styling:
Custom property | Description | Default
----------------|-------------|----------
`--paper-input-container` | Mixin applied to the input container | `{}`
`--paper-input-container-disabled` | Mixin applied to the disabled container | `{}`
`--paper-input-container-border` | Mixin applied to the border element on the left and right hand side of the input | ``
`--paper-input-container-border-focused` | Mixin applied to the border element on the left and right hand side of the input | ``
`--paper-input-container-border-color` | Color of the right and left border of the input | `--anypoint-color-aluminum4`
`--paper-input-container-border-focused-color` | Color of the right and left border of the input when the input is focused | `--anypoint-color-steel2`
`--paper-input-container-invalid-color,` | Error color | `--anypoint-color-danger`
`--paper-input-container-label-color` | Color of the label | `--anypoint-color-aluminum5`
`--paper-input-container-label` | Mixin applied to the label | `{}`
`--paper-input-container-label-floating` | Mixin applied to the floating label | `{}`
`--paper-input-container-label-focus` | Mixin applied to the label when focused | `{}`
`--paper-input-container-focus-color` | Color applied to the label and input when focused | `--anypoint-color-aluminum5`
`--paper-input-field-prefix` | Mixin applied to any prefix element added to the container | `{}`
`--paper-input-field-suffix` | Mixin applied to any suffix element added to the container | `{}`
`--paper-input-container-input` | Mixin applied to the input control | ``
`--paper-input-container-input-color` | Color of the input control | `--anypoint-color-steel5`
`--paper-input-container-input-focus-color` | Color of the input control when focused | `--anypoint-color-steel5`
`--paper-input-container-input-background-colol` | Background color of the input element | `#fff`
`--paper-input-container-input-focus-background-color` | Background color of the input element when focused | `#fff`
@demo demo/index.html
-->
<dom-module id="paper-input-container">
<template>
<style>
:host {
display: block;
padding: 8px 0;
@apply --paper-input-container;
}
:host([inline]) {
display: inline-block;
}
:host([disabled]) {
pointer-events: none;
opacity: 0.33;
@apply --paper-input-container-disabled;
}
:host([hidden]) {
display: none ;
}
.borderline {
@apply --layout-horizontal;
@apply --layout-self-stretch;
}
.unfocused-border {
@apply --layout-flex;
@apply --layout-self-stretch;
width: 2px;
background-color: var(--paper-input-container-border-color, --anypoint-color-aluminum4);
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transition: all .2s ease-out;
transition: all .2s ease-out;
@apply --paper-input-container-border;
}
.borderline.is-highlighted .unfocused-border {
background-color: var(--paper-input-container-border-focused-color, --anypoint-color-steel2);
@apply --paper-input-container-border-focused;
}
.borderline.is-highlighted .unfocused-border.left {
transform: translate(-2px);
}
.borderline.is-highlighted .unfocused-border.right {
transform: translate(2px);
}
.borderline.is-invalid .unfocused-border {
background-color: var(--paper-input-container-invalid-color, --anypoint-color-danger);
}
.label-and-input-container {
@apply --layout-flex-auto;
@apply --layout-relative;
width: 100%;
max-width: 100%;
}
.input-content {
@apply --layout-horizontal;
@apply --layout-center;
position: relative;
}
.input-content ::content label,
.input-content ::content .paper-input-label {
position: absolute;
top: 19px;
right: 0;
left: 15px;
font: inherit;
color: var(--paper-input-container-label-color, --anypoint-color-aluminum5);
-webkit-transition: -webkit-transform 0.25s, width 0.25s;
transition: transform 0.25s, width 0.25s;
-webkit-transform-origin: left top;
transform-origin: left top;
@apply --anypoint-font-common-nowrap;
@apply --anypoint-font-body;
@apply --paper-input-container-label;
font-size: 14px;
font-style: normal;
font-weight: 400;
z-index: 1;
}
.input-content.label-is-floating ::content label,
.input-content.label-is-floating ::content .paper-input-label {
/* Instead font size it uses scale transformation to animate the label */
-webkit-transform: translateY(-40%) scale(0.75);
transform: translateY(-70%) scale(0.75);
/* translateX(5px) */
/* Since we scale to 75/100 of the size, we actually have 100/75 of the
original space now available */
width: 133%;
@apply --paper-input-container-label-floating;
}
:host-context([dir="rtl"]) .input-content.label-is-floating ::content label,
:host-context([dir="rtl"]) .input-content.label-is-floating ::content .paper-input-label {
width: 100%;
-webkit-transform-origin: right top;
transform-origin: right top;
}
.input-content.label-is-highlighted ::content label,
.input-content.label-is-highlighted ::content .paper-input-label {
color: var(--paper-input-container-focus-color, --anypoint-color-aluminum5);
@apply --paper-input-container-label-focus;
}
.input-content.is-invalid ::content label,
.input-content.is-invalid ::content .paper-input-label {
color: var(--paper-input-container-invalid-color, --anypoint-color-danger);
}
.input-content.label-is-hidden ::content label,
.input-content.label-is-hidden ::content .paper-input-label {
visibility: hidden;
}
.input-content ::content input,
.input-content ::content textarea,
.input-content ::content .paper-input-input {
position: relative;
outline: none;
box-shadow: none;
padding: 0 14px;
width: 100%;
max-width: 100%;
background: transparent;
border: none;
color: var(--paper-input-container-input-color, --anypoint-color-steel5);
background-color: var(--paper-input-container-input-background-color, #fff);
-webkit-appearance: none;
text-align: inherit;
vertical-align: bottom;
height: 45px;
padding-top: 10px;
box-sizing: border-box;
@apply --anypoint-font-body;
@apply --paper-input-container-input;
}
.input-content ::content textarea {
padding-top: 16px;
}
.input-content.label-is-highlighted ::content input,
.input-content.label-is-highlighted ::content textarea,
.input-content.label-is-highlighted ::content .paper-input-input {
color: var(--paper-input-container-input-focus-color, --anypoint-color-steel5);
background-color: var(--paper-input-container-input-focus-background-color, #fff);
}
.input-content ::content input::-webkit-outer-spin-button,
.input-content ::content input::-webkit-inner-spin-button {
@apply --paper-input-container-input-webkit-spinner;
}
::content [prefix] {
margin-left: 5px;
@apply --paper-input-field-prefix;
@apply --layout-flex-none;
}
::content [suffix] {
@apply --paper-input-field-suffix;
@apply --layout-flex-none;
}
/* Firefox sets a min-width on the input, which can cause layout issues */
.input-content ::content input {
min-width: 0;
}
.input-content ::content textarea {
resize: none;
}
.add-on-content {
position: relative;
}
.add-on-content.is-invalid ::content * {
color: var(--paper-input-container-invalid-color, --anypoint-color-danger);
}
.add-on-content.is-highlighted ::content * {
color: var(--paper-input-container-focus-color, --anypoint-color-aluminum5);
}
</style>
<div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]">
<div class$="[[_computeBorderClass(focused,invalid)]]">
<div class="unfocused-border left"> </div>
</div>
<content select="[prefix]" id="prefix"></content>
<div class="label-and-input-container" id="labelAndInputContainer">
<content select=":not([add-on]):not([prefix]):not([suffix])"></content>
</div>
<content select="[suffix]"></content>
<div class$="[[_computeBorderClass(focused,invalid)]]">
<div class="unfocused-border right"></div>
</div>
</div>
<div class$="[[_computeAddOnContentClass(focused,invalid)]]">
<content id="addOnContent" select="[add-on]"></content>
</div>
</template>
<script>
Polymer({
is: 'paper-input-container',
properties: {
/**
* Set to true to disable the floating label. The label disappears when the input value is
* not null.
*/
noLabelFloat: {
type: Boolean,
value: false
},
/**
* Set to true to always float the floating label.
*/
alwaysFloatLabel: {
type: Boolean,
value: false
},
/**
* The attribute to listen for value changes on.
*/
attrForValue: {
type: String,
value: 'bind-value'
},
/**
* Set to true to auto-validate the input value when it changes.
*/
autoValidate: {
type: Boolean,
value: false
},
/**
* True if the input is invalid. This property is set automatically when the input value
* changes if auto-validating, or when the `iron-input-validate` event is heard from a
* child.
*/
invalid: {
observer: '_invalidChanged',
type: Boolean,
value: false
},
/**
* True if the input has focus.
*/
focused: {
readOnly: true,
type: Boolean,
value: false,
notify: true
},
_addons: {
type: Array
// do not set a default value here intentionally - it will be initialized lazily when a
// distributed child is attached, which may occur before configuration for this element
// in polyfill.
},
_inputHasContent: {
type: Boolean,
value: false
},
_inputSelector: {
type: String,
value: 'input,textarea,.paper-input-input,.iron-input'
},
_boundOnFocus: {
type: Function,
value: function() {
return this._onFocus.bind(this);
}
},
_boundOnBlur: {
type: Function,
value: function() {
return this._onBlur.bind(this);
}
},
_boundOnInput: {
type: Function,
value: function() {
return this._onInput.bind(this);
}
},
_boundValueChanged: {
type: Function,
value: function() {
return this._onValueChanged.bind(this);
}
}
},
listeners: {
'addon-attached': '_onAddonAttached',
'iron-input-validate': '_onIronInputValidate'
},
get _valueChangedEvent() {
return this.attrForValue + '-changed';
},
get _propertyForValue() {
return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
},
get _inputElement() {
return Polymer.dom(this).querySelector(this._inputSelector);
},
get _inputElementValue() {
return this._inputElement[this._propertyForValue] || this._inputElement.value;
},
ready: function() {
if (!this._addons) {
this._addons = [];
}
this.addEventListener('focus', this._boundOnFocus, true);
this.addEventListener('blur', this._boundOnBlur, true);
},
attached: function() {
if (this.attrForValue) {
this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
} else {
this.addEventListener('input', this._onInput);
}
// Only validate when attached if the input already has a value.
if (this._inputElementValue !== '') {
this._handleValueAndAutoValidate(this._inputElement);
} else {
this._handleValue(this._inputElement);
}
},
_onAddonAttached: function(event) {
if (!this._addons) {
this._addons = [];
}
var target = event.target;
if (this._addons.indexOf(target) === -1) {
this._addons.push(target);
if (this.isAttached) {
this._handleValue(this._inputElement);
}
}
},
_onFocus: function() {
this._setFocused(true);
},
_onBlur: function() {
this._setFocused(false);
this._handleValueAndAutoValidate(this._inputElement);
},
_onInput: function(event) {
this._handleValueAndAutoValidate(event.target);
},
_onValueChanged: function(event) {
this._handleValueAndAutoValidate(event.target);
},
_handleValue: function(inputElement) {
var value = this._inputElementValue;
// type="number" hack needed because this.value is empty until it's valid
if (value || value === 0 || (inputElement.type === 'number' &&
!inputElement.checkValidity())) {
this._inputHasContent = true;
} else {
this._inputHasContent = false;
}
this.updateAddons({
inputElement: inputElement,
value: value,
invalid: this.invalid
});
},
_handleValueAndAutoValidate: function(inputElement) {
if (this.autoValidate) {
var valid;
if (inputElement.validate) {
valid = inputElement.validate(this._inputElementValue);
} else {
valid = inputElement.checkValidity();
}
this.invalid = !valid;
}
// Call this last to notify the add-ons.
this._handleValue(inputElement);
},
_onIronInputValidate: function() {
this.invalid = this._inputElement.invalid;
},
_invalidChanged: function() {
if (this._addons) {
this.updateAddons({
invalid: this.invalid
});
}
},
/**
* Call this to update the state of add-ons.
* @param {Object} state Add-on state.
*/
updateAddons: function(state) {
var addon;
for (var index = 0, len = this._addons.length; index < len; index++) {
addon = this._addons[index];
addon.update(state);
}
},
_computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid,
_inputHasContent) {
var cls = 'input-content';
if (!noLabelFloat) {
var label = this.querySelector('label');
if (alwaysFloatLabel || _inputHasContent || focused) {
cls += ' label-is-floating';
// If the label is floating, ignore any offsets that may have been
// applied from a prefix element.
// this.$.labelAndInputContainer.style.position = 'static';
this.$.labelAndInputContainer.style.position = 'relative';
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += ' label-is-highlighted';
}
} else {
// When the label is not floating, it should overlap the input element.
if (label) {
this.$.labelAndInputContainer.style.position = 'relative';
}
}
} else {
if (_inputHasContent) {
cls += ' label-is-hidden';
}
}
return cls;
},
_computeBorderClass: function(focused, invalid) {
var cls = 'borderline';
if (invalid) {
cls += ' is-invalid';
}
if (focused) {
cls += ' is-highlighted';
}
return cls;
},
_computeAddOnContentClass: function(focused, invalid) {
var cls = 'add-on-content';
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += ' is-highlighted';
}
return cls;
}
});
</script>
</dom-module>