Skip to content

Commit

Permalink
Internal tab (#32)
Browse files Browse the repository at this point in the history
* Fire internal-tabbing on Tab, focus first input, add tests

* Add event documentation

* Rename to internal-tab

* Fire an event in tests
  • Loading branch information
yuriy-fix committed Jun 3, 2019
1 parent 066c3cc commit cf43bfa
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 2 deletions.
1 change: 1 addition & 0 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 23 additions & 0 deletions src/vaadin-custom-field-mixin.html
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
*/
};
</script>
3 changes: 2 additions & 1 deletion test/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"gemini": false,
"sinon": false,
"dispatchChange": false,
"dispatchSlotChange": false
"dispatchSlotChange": false,
"MockInteractions": false
}
}
6 changes: 6 additions & 0 deletions test/custom-field-basic-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++) {
Expand Down
80 changes: 80 additions & 0 deletions test/custom-field-keyboard-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!doctype html>

<head>
<meta charset="UTF-8">
<title>vaadin-custom-field tests</title>
<script src="../../web-component-tester/browser.js"></script>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../iron-test-helpers/mock-interactions.js"></script>
<link rel="import" href="../../test-fixture/test-fixture.html">
<link rel="import" href="../vaadin-custom-field.html">
<link rel="import" href="helpers.html">
</head>

<body>
<test-fixture id="default">
<template>
<vaadin-custom-field>
<input type="text">
<input type="text">
<input type="number">
<input type="number">
</vaadin-custom-field>
</template>
</test-fixture>

<script>
describe('keyboard navigation', function() {
var customField;

function tab(target) {
MockInteractions.keyDownOn(target, 9, [], 'Tab');
}

function shiftTab(target) {
MockInteractions.keyDownOn(target, 9, 'shift', 'Tab');
}

beforeEach(function() {
customField = fixture('default');
});

it('should fire `internal-tab` event on Tab', () => {
const internalTabSpy = sinon.spy();
customField.addEventListener('internal-tab', internalTabSpy);
for (let i = 0; i < 3; i ++) {
tab(customField.inputs[i]);
}

expect(internalTabSpy.callCount).to.equal(3);
});

it('should not fire `internal-tab` event on Tab from the last input', () => {
const internalTabSpy = sinon.spy();
customField.addEventListener('internal-tab', internalTabSpy);
tab(customField.inputs[3]);

expect(internalTabSpy).not.to.be.called;
});

it('should fire `internal-tab` event on Shift Tab', () => {
const internalTabSpy = sinon.spy();
customField.addEventListener('internal-tab', internalTabSpy);
for (let i = 3; i > 0; i --) {
shiftTab(customField.inputs[i]);
}

expect(internalTabSpy.callCount).to.equal(3);
});

it('should not fire `internal-tab` event on Shift Tab from the first input', () => {
const internalTabSpy = sinon.spy();
customField.addEventListener('internal-tab', internalTabSpy);
shiftTab(customField.inputs[0]);

expect(internalTabSpy).not.to.be.called;
});

});
</script>
</body>
3 changes: 2 additions & 1 deletion test/test-suites.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
];

0 comments on commit cf43bfa

Please sign in to comment.