feat(switch): add types
This commit is contained in:
parent
7d4b6d32db
commit
06123918d0
5 changed files with 63 additions and 16 deletions
5
.changeset/popular-pianos-warn.md
Normal file
5
.changeset/popular-pianos-warn.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/switch': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add types for switch package.
|
||||||
|
|
@ -2,6 +2,7 @@ import { css, html, ScopedElementsMixin } from '@lion/core';
|
||||||
import { ChoiceInputMixin, LionField } from '@lion/form-core';
|
import { ChoiceInputMixin, LionField } from '@lion/form-core';
|
||||||
import { LionSwitchButton } from './LionSwitchButton.js';
|
import { LionSwitchButton } from './LionSwitchButton.js';
|
||||||
|
|
||||||
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/40110
|
||||||
export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField)) {
|
export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField)) {
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [
|
||||||
|
|
@ -25,10 +26,26 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input node here is the lion-switch-button, which is not compatible with LionField _inputNode --> HTMLInputElement
|
||||||
|
* Therefore we do a full override and typecast to an intersection type that includes LionSwitchButton
|
||||||
|
* @returns {HTMLInputElement & LionSwitchButton}
|
||||||
|
*/
|
||||||
|
get _inputNode() {
|
||||||
|
return /** @type {HTMLInputElement & LionSwitchButton} */ (Array.from(this.children).find(
|
||||||
|
el => el.slot === 'input',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
get slots() {
|
get slots() {
|
||||||
return {
|
return {
|
||||||
...super.slots,
|
...super.slots,
|
||||||
input: () => document.createElement(this.constructor.getScopedTagName('lion-switch-button')),
|
input: () =>
|
||||||
|
document.createElement(
|
||||||
|
/** @type {typeof LionSwitch} */ (this.constructor).getScopedTagName(
|
||||||
|
'lion-switch-button',
|
||||||
|
),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,6 +99,7 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {import('lit-element').PropertyValues } changedProperties */
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
this._syncButtonSwitch();
|
this._syncButtonSwitch();
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,9 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
||||||
this.setAttribute('aria-checked', `${this.checked}`);
|
this.setAttribute('aria-checked', `${this.checked}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {KeyboardEvent} e
|
||||||
|
*/
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
__handleKeydown(e) {
|
__handleKeydown(e) {
|
||||||
// prevent "space" scrolling on "macOS"
|
// prevent "space" scrolling on "macOS"
|
||||||
|
|
@ -121,12 +124,16 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {KeyboardEvent} e
|
||||||
|
*/
|
||||||
__handleKeyup(e) {
|
__handleKeyup(e) {
|
||||||
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) {
|
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) {
|
||||||
this.__toggleChecked();
|
this.__toggleChecked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {import('lit-element').PropertyValues } changedProperties */
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
if (changedProperties.has('disabled')) {
|
if (changedProperties.has('disabled')) {
|
||||||
this.setAttribute('aria-disabled', `${this.disabled}`); // create mixin if we need it in more places
|
this.setAttribute('aria-disabled', `${this.disabled}`); // create mixin if we need it in more places
|
||||||
|
|
@ -136,6 +143,8 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
||||||
/**
|
/**
|
||||||
* We synchronously update aria-checked to support voice over on safari.
|
* We synchronously update aria-checked to support voice over on safari.
|
||||||
*
|
*
|
||||||
|
* @param {PropertyKey} name
|
||||||
|
* @param {?} oldValue
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
requestUpdateInternal(name, oldValue) {
|
requestUpdateInternal(name, oldValue) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
import { expect, fixture, html } from '@open-wc/testing';
|
import { expect, fixture as _fixture, html } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import '../lion-switch-button.js';
|
import '../lion-switch-button.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/LionSwitchButton').LionSwitchButton} LionSwitchButton
|
||||||
|
* @typedef {import('lit-html').TemplateResult} TemplateResult
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fixture = /** @type {(arg: TemplateResult) => Promise<LionSwitchButton>} */ (_fixture);
|
||||||
|
|
||||||
describe('lion-switch-button', () => {
|
describe('lion-switch-button', () => {
|
||||||
|
/** @type {LionSwitchButton} */
|
||||||
let el;
|
let el;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
el = await fixture(html`<lion-switch-button></lion-switch-button>`);
|
el = await fixture(html`<lion-switch-button></lion-switch-button>`);
|
||||||
|
|
@ -62,15 +70,15 @@ describe('lion-switch-button', () => {
|
||||||
el.click();
|
el.click();
|
||||||
el.click();
|
el.click();
|
||||||
expect(handlerSpy.callCount).to.equal(2);
|
expect(handlerSpy.callCount).to.equal(2);
|
||||||
const checkCall = call => {
|
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||||
expect(call.args).to.have.a.lengthOf(1);
|
expect(call.args).to.have.lengthOf(1);
|
||||||
const e = call.args[0];
|
const e = call.args[0];
|
||||||
expect(e).to.be.an.instanceof(Event);
|
expect(e).to.be.an.instanceof(Event);
|
||||||
expect(e.bubbles).to.be.true;
|
expect(e.bubbles).to.be.true;
|
||||||
expect(e.composed).to.be.true;
|
expect(e.composed).to.be.true;
|
||||||
};
|
};
|
||||||
checkCall(handlerSpy.getCall(0), true);
|
checkCall(handlerSpy.getCall(0));
|
||||||
checkCall(handlerSpy.getCall(1), false);
|
checkCall(handlerSpy.getCall(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dispatch "checked-changed" event when checked changed', () => {
|
it('should dispatch "checked-changed" event when checked changed', () => {
|
||||||
|
|
@ -79,15 +87,15 @@ describe('lion-switch-button', () => {
|
||||||
el.checked = true;
|
el.checked = true;
|
||||||
el.checked = false;
|
el.checked = false;
|
||||||
expect(handlerSpy.callCount).to.equal(2);
|
expect(handlerSpy.callCount).to.equal(2);
|
||||||
const checkCall = call => {
|
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||||
expect(call.args).to.have.a.lengthOf(1);
|
expect(call.args).to.have.lengthOf(1);
|
||||||
const e = call.args[0];
|
const e = call.args[0];
|
||||||
expect(e).to.be.an.instanceof(Event);
|
expect(e).to.be.an.instanceof(Event);
|
||||||
expect(e.bubbles).to.be.true;
|
expect(e.bubbles).to.be.true;
|
||||||
expect(e.composed).to.be.true;
|
expect(e.composed).to.be.true;
|
||||||
};
|
};
|
||||||
checkCall(handlerSpy.getCall(0), true);
|
checkCall(handlerSpy.getCall(0));
|
||||||
checkCall(handlerSpy.getCall(1), false);
|
checkCall(handlerSpy.getCall(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not dispatch "checked-changed" event if disabled', () => {
|
it('should not dispatch "checked-changed" event if disabled', () => {
|
||||||
|
|
@ -117,7 +125,7 @@ describe('lion-switch-button', () => {
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.getAttribute('aria-checked')).to.equal('false');
|
expect(el.getAttribute('aria-checked')).to.equal('false');
|
||||||
|
|
||||||
el.setAttribute('checked', true);
|
el.setAttribute('checked', '');
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.getAttribute('aria-checked')).to.equal('true');
|
expect(el.getAttribute('aria-checked')).to.equal('true');
|
||||||
el.removeAttribute('checked');
|
el.removeAttribute('checked');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
import { expect, fixture, html } from '@open-wc/testing';
|
import { expect, fixture as _fixture, html } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import '../lion-switch.js';
|
import '../lion-switch.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/LionSwitch').LionSwitch} LionSwitch
|
||||||
|
* @typedef {import('lit-html').TemplateResult} TemplateResult
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fixture = /** @type {(arg: TemplateResult) => Promise<LionSwitch>} */ (_fixture);
|
||||||
|
|
||||||
describe('lion-switch', () => {
|
describe('lion-switch', () => {
|
||||||
it('should have default "input" element', async () => {
|
it('should have default "input" element', async () => {
|
||||||
const el = await fixture(html`<lion-switch></lion-switch>`);
|
const el = await fixture(html`<lion-switch></lion-switch>`);
|
||||||
|
|
@ -83,15 +90,15 @@ describe('lion-switch', () => {
|
||||||
el._labelNode.click();
|
el._labelNode.click();
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(handlerSpy.callCount).to.equal(2);
|
expect(handlerSpy.callCount).to.equal(2);
|
||||||
const checkCall = call => {
|
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||||
expect(call.args).to.have.a.lengthOf(1);
|
expect(call.args).to.have.lengthOf(1);
|
||||||
const e = call.args[0];
|
const e = call.args[0];
|
||||||
expect(e).to.be.an.instanceof(Event);
|
expect(e).to.be.an.instanceof(Event);
|
||||||
expect(e.bubbles).to.be.true;
|
expect(e.bubbles).to.be.true;
|
||||||
expect(e.composed).to.be.true;
|
expect(e.composed).to.be.true;
|
||||||
};
|
};
|
||||||
checkCall(handlerSpy.getCall(0), true);
|
checkCall(handlerSpy.getCall(0));
|
||||||
checkCall(handlerSpy.getCall(1), false);
|
checkCall(handlerSpy.getCall(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dispatch "checked-changed" event when checked changed', async () => {
|
it('should dispatch "checked-changed" event when checked changed', async () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue