diff --git a/bower.json b/bower.json index 10298b0..6127d51 100644 --- a/bower.json +++ b/bower.json @@ -33,6 +33,7 @@ }, "devDependencies": { "iron-component-page": "^3.0.0", + "iron-test-helpers": "^2.0.0", "iron-form": "^2.0.0", "vaadin-text-field": "vaadin/vaadin-text-field#^2.3.0", "vaadin-time-picker": "vaadin/vaadin-time-picker#^1.1.1", diff --git a/src/vaadin-custom-field-mixin.html b/src/vaadin-custom-field-mixin.html index fd33b92..81511d4 100644 --- a/src/vaadin-custom-field-mixin.html +++ b/src/vaadin-custom-field-mixin.html @@ -80,11 +80,27 @@ this.__setInputsFromChildNodes(); + this.addEventListener('keydown', e => { + if (e.keyCode === 9) { + if (this.inputs.indexOf(e.target) < this.inputs.length - 1 && !e.shiftKey || + this.inputs.indexOf(e.target) > 0 && e.shiftKey) { + this.dispatchEvent(new CustomEvent('internal-tab')); + } + } + }); + var uniqueId = Vaadin.CustomFieldMixin._uniqueId = 1 + Vaadin.CustomFieldMixin._uniqueId || 1; this.__errorId = `${this.constructor.is}-error-${uniqueId}`; this.__labelId = `${this.constructor.is}-label-${uniqueId}`; } + /* + * @private + */ + focus() { + this.inputs && this.inputs[0].focus(); + } + __observeChildrenInputsChange() { const mutationObserverConfig = { 'childList': true, @@ -138,5 +154,12 @@ this.validate(); } } + + /** + * Fired on Tab keydown triggered from the internal inputs, + * meaning focus will not leave the inputs. + * + * @event internal-tab + */ }; diff --git a/test/.eslintrc.json b/test/.eslintrc.json index 59989e4..2b2df00 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -9,6 +9,7 @@ "gemini": false, "sinon": false, "dispatchChange": false, - "dispatchSlotChange": false + "dispatchSlotChange": false, + "MockInteractions": false } } diff --git a/test/custom-field-basic-test.html b/test/custom-field-basic-test.html index 9c581aa..fb824b8 100644 --- a/test/custom-field-basic-test.html +++ b/test/custom-field-basic-test.html @@ -32,6 +32,12 @@ expect(customField.localName).to.be.equal('vaadin-custom-field'); }); + it('should focus the first input on `focus()`', function() { + const spy = sinon.spy(customField.inputs[0], 'focus'); + customField.focus(); + expect(spy).to.be.calledOnce; + }); + it('should properly define internal inputs', function() { expect(customField.inputs.length).to.equal(2); for (var i = 0; i < 2; i ++) { diff --git a/test/custom-field-keyboard-test.html b/test/custom-field-keyboard-test.html new file mode 100644 index 0000000..a2c2272 --- /dev/null +++ b/test/custom-field-keyboard-test.html @@ -0,0 +1,80 @@ + + + + + vaadin-custom-field tests + + + + + + + + + + + + + + + diff --git a/test/test-suites.js b/test/test-suites.js index acabe43..17c9fa4 100644 --- a/test/test-suites.js +++ b/test/test-suites.js @@ -2,5 +2,6 @@ window.CustomFieldElementSuites = [ 'custom-field-basic-test.html', 'custom-field-slot-test.html', 'custom-field-validation-test.html', - 'custom-field-functions-test.html' + 'custom-field-functions-test.html', + 'custom-field-keyboard-test.html' ];