diff --git a/src/vaadin-password-field.html b/src/vaadin-password-field.html
index 0e987f14..a14e5653 100644
--- a/src/vaadin-password-field.html
+++ b/src/vaadin-password-field.html
@@ -141,6 +141,10 @@
}
_onChange(e) {
+ const slotted = this.querySelector(`${this._slottedTagName}[slot="${this._slottedTagName}"]`);
+ if (slotted) {
+ e.stopPropagation();
+ }
if (this._passwordVisibilityChanging) {
this._cachedChangeEvent = e;
} else {
diff --git a/src/vaadin-text-area.html b/src/vaadin-text-area.html
index 185db3be..5ba8b8f8 100644
--- a/src/vaadin-text-area.html
+++ b/src/vaadin-text-area.html
@@ -56,26 +56,9 @@
-
+
+
+
@@ -173,6 +156,10 @@
}
}
+ get _slottedTagName() {
+ return 'textarea';
+ }
+
_textAreaValueChanged(value) {
this._updateHeight();
}
diff --git a/src/vaadin-text-field-mixin.html b/src/vaadin-text-field-mixin.html
index e596dba0..81169a22 100644
--- a/src/vaadin-text-field-mixin.html
+++ b/src/vaadin-text-field-mixin.html
@@ -47,7 +47,9 @@
}
/* Reset the native input styles */
- [part="value"] {
+ [part="value"],
+ [part="input-field"] ::slotted(input),
+ [part="input-field"] ::slotted(textarea) {
-webkit-appearance: none;
-moz-appearance: none;
outline: none;
@@ -69,8 +71,10 @@
flex: none;
}
- /* Slotted by vaadin-dropdown-menu-text-field */
[part="value"],
+ [part="input-field"] ::slotted(input),
+ [part="input-field"] ::slotted(textarea),
+ /* Slotted by vaadin-select-text-field */
[part="input-field"] ::slotted([part="value"]) {
flex: auto;
white-space: nowrap;
@@ -79,7 +83,12 @@
height: 100%;
}
- [part="value"]::-ms-clear {
+ [part="input-field"] ::slotted(textarea) {
+ resize: none;
+ }
+
+ [part="value"]::-ms-clear,
+ [part="input-field"] ::slotted(input)::-ms-clear {
display: none;
}
@@ -100,6 +109,18 @@
*/
window.Vaadin = window.Vaadin || {};
+ const HOST_PROPS = {
+ default: ['list', 'autofocus', 'pattern', 'autocapitalize', 'autocorrect', 'maxlength',
+ 'minlength', 'name', 'placeholder', 'autocomplete', 'title'],
+ accessible: ['disabled', 'readonly', 'required', 'invalid']
+ };
+
+ const PROP_TYPE = {
+ DEFAULT: 'default',
+ ACCESSIBLE: 'accessible'
+ };
+
+
/**
* @polymerMixin
* @memberof Vaadin
@@ -259,11 +280,26 @@
}
static get observers() {
- return ['_stateChanged(disabled, readonly, clearButtonVisible, hasValue)'];
+ return ['_stateChanged(disabled, readonly, clearButtonVisible, hasValue)',
+ '_hostPropsChanged(' + HOST_PROPS.default.join(', ') + ')',
+ '_hostAccessiblePropsChanged(' + HOST_PROPS.accessible.join(', ') + ')',
+ '_getActiveErrorId(invalid, errorMessage, _errorId)',
+ '_getActiveLabelId(label, _labelId)'];
}
get focusElement() {
- return this.root && this.root.querySelector('[part=value]');
+ if (!this.shadowRoot) {
+ return;
+ }
+ const slotted = this.querySelector(`${this._slottedTagName}[slot="${this._slottedTagName}"]`);
+ if (slotted) {
+ return slotted;
+ }
+ return this.shadowRoot.querySelector('[part="value"]');
+ }
+
+ get _slottedTagName() {
+ return 'input';
}
_onInput(e) {
@@ -271,8 +307,11 @@
const input = this.focusElement;
if (input.value.length > 0 && !this.checkValidity()) {
input.value = this.value || '';
+ return;
}
}
+ this.__userInput = true;
+ this.value = e.target.value;
}
// NOTE(yuriy): Workaround needed for IE11 and Edge for proper displaying
@@ -311,14 +350,25 @@
if (newVal === '' && oldVal === undefined) {
return;
}
- if (this.invalid) {
- this.validate();
- }
+
if (newVal !== '' && newVal != null) {
this.hasValue = true;
} else {
this.hasValue = false;
}
+
+ if (this.__userInput) {
+ this.__userInput = false;
+ return;
+ } else if (newVal !== undefined) {
+ this.focusElement.value = newVal;
+ } else {
+ this.value = '';
+ }
+
+ if (this.invalid) {
+ this.validate();
+ }
}
_labelChanged(label) {
@@ -329,6 +379,74 @@
}
}
+ _onSlotChange() {
+ const slotted = this.querySelector(`${this._slottedTagName}[slot="${this._slottedTagName}"]`);
+
+ if (this.value) {
+ this.focusElement.value = this.value;
+ this.validate();
+ }
+
+ if (slotted && !this._slottedInput) {
+ this._validateSlottedValue(slotted);
+ this._addInputListeners(slotted);
+ this._addIEListeners(slotted);
+ this._slottedInput = slotted;
+ } else if (!this._slottedInput) {
+ this._removeInputListeners(this._slottedInput);
+ this._removeIEListeners(this._slottedInput);
+ this._slottedInput = undefined;
+ }
+
+ Object.keys(PROP_TYPE).map(key => PROP_TYPE[key]).forEach(type =>
+ this._propagateHostAttributes(HOST_PROPS[type].map(attr => this[attr]), type));
+ }
+
+ _hostPropsChanged(...attributesValues) {
+ this._propagateHostAttributes(attributesValues, PROP_TYPE.DEFAULT);
+ }
+
+ _hostAccessiblePropsChanged(...attributesValues) {
+ this._propagateHostAttributes(attributesValues, PROP_TYPE.ACCESSIBLE);
+ }
+
+ _validateSlottedValue(slotted) {
+ if (slotted.value !== this.value) {
+ console.warn('Please define value on the vaadin-text-field component!');
+ slotted.value = '';
+ }
+ }
+
+ _propagateHostAttributes(attributesValues, type) {
+ const input = this.focusElement;
+ const attributeNames = HOST_PROPS[type];
+
+ if (type === 'accessible') {
+ attributeNames.forEach((attr, index) => {
+ this._setOrToggleAttribute(attr, attributesValues[index], input);
+ this._setOrToggleAttribute(`aria-${attr}`, attributesValues[index], input);
+ });
+ } else {
+ attributeNames.forEach((attr, index) => {
+ this._setOrToggleAttribute(attr, attributesValues[index], input);
+ });
+ }
+ }
+
+ _setOrToggleAttribute(name, value, node) {
+ if (!name || !node) {
+ return;
+ }
+
+ if (node.hasAttribute(name) === !value) {
+ if (value) {
+ node.setAttribute(name, (typeof value === 'boolean') ? '' : value);
+ } else {
+ node.removeAttribute(name);
+ }
+ }
+ }
+
/**
* Returns true if the current input value satisfies all constraints (if any)
* @returns {boolean}
@@ -341,9 +459,37 @@
}
}
+ _addInputListeners(node) {
+ node.addEventListener('input', this._boundOnInput);
+ node.addEventListener('change', this._boundOnChange);
+ node.addEventListener('blur', this._boundOnBlur);
+ }
+
+ _removeInputListeners(node) {
+ node.removeEventListener('input', this._boundOnInput);
+ node.removeEventListener('change', this._boundOnChange);
+ node.removeEventListener('blur', this._boundOnBlur);
+ }
ready() {
super.ready();
+
+ this._boundOnInput = this._onInput.bind(this);
+ this._boundOnChange = this._onChange.bind(this);
+ this._boundOnBlur = this.validate.bind(this);
+
+ const defaultInput = this.shadowRoot.querySelector('[part="value"]');
+ this._slottedInput = this.querySelector(`${this._slottedTagName}[slot="${this._slottedTagName}"]`);
+ this._addInputListeners(defaultInput);
+ this._addIEListeners(defaultInput);
+ if (this._slottedInput) {
+ this._addIEListeners(this._slottedInput);
+ this._addInputListeners(this._slottedInput);
+ }
+
+ this.shadowRoot.querySelector('[name="input"], [name="textarea"]')
+ .addEventListener('slotchange', this._onSlotChange.bind(this));
+
if (!(window.ShadyCSS && window.ShadyCSS.nativeCss)) {
this.updateStyles();
}
@@ -355,11 +501,6 @@
var uniqueId = Vaadin.TextFieldMixin._uniqueId = 1 + Vaadin.TextFieldMixin._uniqueId || 0;
this._errorId = `${this.constructor.is}-error-${uniqueId}`;
this._labelId = `${this.constructor.is}-label-${uniqueId}`;
-
- /* istanbul ignore if */
- if (navigator.userAgent.match(/Trident/)) {
- this._addIEListeners();
- }
}
/**
@@ -381,7 +522,7 @@
this.focusElement.focus();
this.clear();
this._valueClearing = false;
- this.focusElement.dispatchEvent(new Event('change', {bubbles: true}));
+ this.focusElement.dispatchEvent(new Event('change', {bubbles: !this._slottedInput}));
}
_onKeyDown(e) {
@@ -390,31 +531,46 @@
}
}
- _addIEListeners() {
- // IE11 dispatches `input` event in following cases:
- // - focus or blur, when placeholder attribute is set
- // - placeholder attribute value changed
- // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/101220/
- const prevent = e => {
- e.stopImmediatePropagation();
- this.focusElement.removeEventListener('input', prevent);
- };
- const shouldPreventInput = () => this.placeholder && this.focusElement.addEventListener('input', prevent);
- this.focusElement.addEventListener('focusin', shouldPreventInput);
- this.focusElement.addEventListener('focusout', shouldPreventInput);
- this._createPropertyObserver('placeholder', shouldPreventInput);
+ _addIEListeners(node) {
+ /* istanbul ignore if */
+ if (navigator.userAgent.match(/Trident/)) {
+ // IE11 dispatches `input` event in following cases:
+ // - focus or blur, when placeholder attribute is set
+ // - placeholder attribute value changed
+ // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/101220/
+ this._prevent = e => {
+ e.stopImmediatePropagation();
+ this.focusElement.removeEventListener('input', this._prevent);
+ };
+ this._shouldPreventInput = () => this.placeholder && node.addEventListener('input', this._prevent);
+ node.addEventListener('focusin', this._shouldPreventInput);
+ node.addEventListener('focusout', this._shouldPreventInput);
+ this._createPropertyObserver('placeholder', this._shouldPreventInput);
+ }
+ }
+
+ _removeIEListeners(node) {
+ /* istanbul ignore if */
+ if (navigator.userAgent.match(/Trident/)) {
+ node.removeEventListener('focusin', this._shouldPreventInput);
+ node.removeEventListener('focusout', this._shouldPreventInput);
+ }
}
_getActiveErrorId(invalid, errorMessage, errorId) {
- return errorMessage && invalid ? errorId : undefined;
+ this._setOrToggleAttribute('aria-describedby',
+ (errorMessage && invalid ? errorId : undefined),
+ this.focusElement);
}
_getActiveLabelId(label, labelId) {
- return label ? labelId : undefined;
+ this._setOrToggleAttribute('aria-labelledby',
+ (label ? labelId : undefined),
+ this.focusElement);
}
_getErrorMessageAriaHidden(invalid, errorMessage, errorId) {
- return (!this._getActiveErrorId(invalid, errorMessage, errorId)).toString();
+ return (!(errorMessage && invalid ? errorId : undefined)).toString();
}
/**
diff --git a/src/vaadin-text-field.html b/src/vaadin-text-field.html
index 7c685283..d3fbee5b 100644
--- a/src/vaadin-text-field.html
+++ b/src/vaadin-text-field.html
@@ -22,30 +22,9 @@
-
+
+
+
diff --git a/test/accessibility.html b/test/accessibility.html
index cad15f07..9f42a984 100644
--- a/test/accessibility.html
+++ b/test/accessibility.html
@@ -19,18 +19,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -38,191 +62,244 @@
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/password-field.html b/test/password-field.html
index 265b9005..09edd8a7 100644
--- a/test/password-field.html
+++ b/test/password-field.html
@@ -19,127 +19,141 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/test-suites.js b/test/test-suites.js
index 76a27d8a..7cad4ce1 100644
--- a/test/test-suites.js
+++ b/test/test-suites.js
@@ -3,5 +3,6 @@ window.VaadinTextFieldSuites = [
'text-area.html',
'password-field.html',
'validation.html',
- 'accessibility.html'
+ 'accessibility.html',
+ 'custom-input.html'
];
diff --git a/test/text-area.html b/test/text-area.html
index b6b471e4..a1a94b3a 100644
--- a/test/text-area.html
+++ b/test/text-area.html
@@ -18,338 +18,352 @@
+
+
+
+
+
+
+
+
diff --git a/test/text-field.html b/test/text-field.html
index e2cedf60..c3c0d4e6 100644
--- a/test/text-field.html
+++ b/test/text-field.html
@@ -19,273 +19,287 @@
+
+
+
+
+
+
+
+
diff --git a/test/validation.html b/test/validation.html
index d4730b20..b38adbcf 100644
--- a/test/validation.html
+++ b/test/validation.html
@@ -10,6 +10,7 @@
+
@@ -24,6 +25,19 @@
+
+
+
+
+
+
+
+
@@ -34,170 +48,193 @@
-
diff --git a/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/chrome.png b/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/chrome.png
new file mode 100644
index 00000000..ff858482
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/firefox.png b/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/firefox.png
new file mode 100644
index 00000000..3e351e5e
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/password-field-custom-input-lumo/password-field-custom-input/firefox.png differ
diff --git a/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/chrome.png b/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/chrome.png
new file mode 100644
index 00000000..685c6736
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/firefox.png b/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/firefox.png
new file mode 100644
index 00000000..2d128f26
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/password-field-custom-input-material/password-field-custom-input/firefox.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/chrome.png b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/chrome.png
new file mode 100644
index 00000000..a459edba
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/firefox.png b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/firefox.png
new file mode 100644
index 00000000..c03df701
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-lumo/text-area-custom-textarea/firefox.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/chrome.png b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/chrome.png
new file mode 100644
index 00000000..a5a8d525
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/firefox.png b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/firefox.png
new file mode 100644
index 00000000..c22b5ecc
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-area-custom-textarea-material/text-area-custom-textarea/firefox.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/chrome.png b/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/chrome.png
new file mode 100644
index 00000000..806207ab
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/firefox.png b/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/firefox.png
new file mode 100644
index 00000000..13c37edf
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-field-custom-input-lumo/text-field-custom-input/firefox.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/chrome.png b/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/chrome.png
new file mode 100644
index 00000000..9d37156b
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/chrome.png differ
diff --git a/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/firefox.png b/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/firefox.png
new file mode 100644
index 00000000..f05e319b
Binary files /dev/null and b/test/visual/screens/vaadin-text-field/text-field-custom-input-material/text-field-custom-input/firefox.png differ
diff --git a/test/visual/vaadin-password-field/password-field-custom-input.html b/test/visual/vaadin-password-field/password-field-custom-input.html
new file mode 100644
index 00000000..28f50119
--- /dev/null
+++ b/test/visual/vaadin-password-field/password-field-custom-input.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/visual/vaadin-text-area/styling.html b/test/visual/vaadin-text-area/styling.html
index 668f2224..bbe1022b 100644
--- a/test/visual/vaadin-text-area/styling.html
+++ b/test/visual/vaadin-text-area/styling.html
@@ -26,7 +26,11 @@
font-weight: bold;
}
- [part~="value"] {
+ /* NOTE(yuriy): Targeting slotted elements as workaround for
+ gemini firfox 47 to overcome stronger selector */
+ [part="value"],
+ [part="input-field"] ::slotted(input),
+ [part="input-field"] ::slotted(textarea) {
background-color: red;
border: none;
--_lumo-text-field-overflow-mask-image: none;
diff --git a/test/visual/vaadin-text-area/text-area-custom-textarea.html b/test/visual/vaadin-text-area/text-area-custom-textarea.html
new file mode 100644
index 00000000..539c3d1b
--- /dev/null
+++ b/test/visual/vaadin-text-area/text-area-custom-textarea.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/visual/vaadin-text-field/styling.html b/test/visual/vaadin-text-field/styling.html
index fe1787b2..bd1c6e9b 100644
--- a/test/visual/vaadin-text-field/styling.html
+++ b/test/visual/vaadin-text-field/styling.html
@@ -26,7 +26,11 @@
font-weight: bold;
}
- [part~="value"] {
+ /* NOTE(yuriy): Targeting slotted elements as workaround for
+ gemini firfox 47 to overcome stronger selector */
+ [part="value"],
+ [part="input-field"] ::slotted(input),
+ [part="input-field"] ::slotted(textarea) {
background-color: red;
border: none;
--_lumo-text-field-overflow-mask-image: none;
diff --git a/test/visual/vaadin-text-field/text-field-custom-input.html b/test/visual/vaadin-text-field/text-field-custom-input.html
new file mode 100644
index 00000000..1ae28129
--- /dev/null
+++ b/test/visual/vaadin-text-field/text-field-custom-input.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme/lumo/vaadin-placeholder-styles.html b/theme/lumo/vaadin-placeholder-styles.html
new file mode 100644
index 00000000..64f99ede
--- /dev/null
+++ b/theme/lumo/vaadin-placeholder-styles.html
@@ -0,0 +1,61 @@
+
+
+
+
+
diff --git a/theme/lumo/vaadin-text-area-styles.html b/theme/lumo/vaadin-text-area-styles.html
index 9f49d8e1..38344c11 100644
--- a/theme/lumo/vaadin-text-area-styles.html
+++ b/theme/lumo/vaadin-text-area-styles.html
@@ -5,7 +5,8 @@
+
+
+
diff --git a/theme/material/vaadin-text-field-styles.html b/theme/material/vaadin-text-field-styles.html
index 11842aa1..1446f163 100644
--- a/theme/material/vaadin-text-field-styles.html
+++ b/theme/material/vaadin-text-field-styles.html
@@ -76,13 +76,17 @@
:host([disabled]) [part="label"],
:host([disabled]) [part="value"],
+ :host([disabled]) [part="input-field"] ::slotted(input),
+ :host([disabled]) [part="input-field"] ::slotted(textarea),
:host([disabled]) [part="input-field"] ::slotted([part="value"]) {
color: var(--material-disabled-text-color);
-webkit-text-fill-color: var(--material-disabled-text-color);
}
[part="value"],
- /* For vaadin-dropdown-menu-text-field */
+ :host([disabled]) [part="input-field"] ::slotted(input),
+ :host([disabled]) [part="input-field"] ::slotted(textarea),
+ /* Slotted by vaadin-select-text-field */
[part="input-field"] ::slotted([part="value"]) {
outline: none;
margin: 0;
@@ -209,7 +213,7 @@
/* Slotted content */
- [part="input-field"] ::slotted(*:not([part="value"])) {
+ [part="input-field"] ::slotted(*:not([part="value"]):not(input):not(textarea)) {
color: var(--material-secondary-text-color);
}