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 { LionSwitchButton } from './LionSwitchButton.js';
|
||||
|
||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/40110
|
||||
export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField)) {
|
||||
static get styles() {
|
||||
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() {
|
||||
return {
|
||||
...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) {
|
||||
super.updated(changedProperties);
|
||||
this._syncButtonSwitch();
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
|||
this.setAttribute('aria-checked', `${this.checked}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
__handleKeydown(e) {
|
||||
// prevent "space" scrolling on "macOS"
|
||||
|
|
@ -121,12 +124,16 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
__handleKeyup(e) {
|
||||
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) {
|
||||
this.__toggleChecked();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {import('lit-element').PropertyValues } changedProperties */
|
||||
updated(changedProperties) {
|
||||
if (changedProperties.has('disabled')) {
|
||||
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.
|
||||
*
|
||||
* @param {PropertyKey} name
|
||||
* @param {?} oldValue
|
||||
* @override
|
||||
*/
|
||||
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 '../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', () => {
|
||||
/** @type {LionSwitchButton} */
|
||||
let el;
|
||||
beforeEach(async () => {
|
||||
el = await fixture(html`<lion-switch-button></lion-switch-button>`);
|
||||
|
|
@ -62,15 +70,15 @@ describe('lion-switch-button', () => {
|
|||
el.click();
|
||||
el.click();
|
||||
expect(handlerSpy.callCount).to.equal(2);
|
||||
const checkCall = call => {
|
||||
expect(call.args).to.have.a.lengthOf(1);
|
||||
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||
expect(call.args).to.have.lengthOf(1);
|
||||
const e = call.args[0];
|
||||
expect(e).to.be.an.instanceof(Event);
|
||||
expect(e.bubbles).to.be.true;
|
||||
expect(e.composed).to.be.true;
|
||||
};
|
||||
checkCall(handlerSpy.getCall(0), true);
|
||||
checkCall(handlerSpy.getCall(1), false);
|
||||
checkCall(handlerSpy.getCall(0));
|
||||
checkCall(handlerSpy.getCall(1));
|
||||
});
|
||||
|
||||
it('should dispatch "checked-changed" event when checked changed', () => {
|
||||
|
|
@ -79,15 +87,15 @@ describe('lion-switch-button', () => {
|
|||
el.checked = true;
|
||||
el.checked = false;
|
||||
expect(handlerSpy.callCount).to.equal(2);
|
||||
const checkCall = call => {
|
||||
expect(call.args).to.have.a.lengthOf(1);
|
||||
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||
expect(call.args).to.have.lengthOf(1);
|
||||
const e = call.args[0];
|
||||
expect(e).to.be.an.instanceof(Event);
|
||||
expect(e.bubbles).to.be.true;
|
||||
expect(e.composed).to.be.true;
|
||||
};
|
||||
checkCall(handlerSpy.getCall(0), true);
|
||||
checkCall(handlerSpy.getCall(1), false);
|
||||
checkCall(handlerSpy.getCall(0));
|
||||
checkCall(handlerSpy.getCall(1));
|
||||
});
|
||||
|
||||
it('should not dispatch "checked-changed" event if disabled', () => {
|
||||
|
|
@ -117,7 +125,7 @@ describe('lion-switch-button', () => {
|
|||
await el.updateComplete;
|
||||
expect(el.getAttribute('aria-checked')).to.equal('false');
|
||||
|
||||
el.setAttribute('checked', true);
|
||||
el.setAttribute('checked', '');
|
||||
await el.updateComplete;
|
||||
expect(el.getAttribute('aria-checked')).to.equal('true');
|
||||
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 '../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', () => {
|
||||
it('should have default "input" element', async () => {
|
||||
const el = await fixture(html`<lion-switch></lion-switch>`);
|
||||
|
|
@ -83,15 +90,15 @@ describe('lion-switch', () => {
|
|||
el._labelNode.click();
|
||||
await el.updateComplete;
|
||||
expect(handlerSpy.callCount).to.equal(2);
|
||||
const checkCall = call => {
|
||||
expect(call.args).to.have.a.lengthOf(1);
|
||||
const checkCall = /** @param {import('sinon').SinonSpyCall} call */ call => {
|
||||
expect(call.args).to.have.lengthOf(1);
|
||||
const e = call.args[0];
|
||||
expect(e).to.be.an.instanceof(Event);
|
||||
expect(e.bubbles).to.be.true;
|
||||
expect(e.composed).to.be.true;
|
||||
};
|
||||
checkCall(handlerSpy.getCall(0), true);
|
||||
checkCall(handlerSpy.getCall(1), false);
|
||||
checkCall(handlerSpy.getCall(0));
|
||||
checkCall(handlerSpy.getCall(1));
|
||||
});
|
||||
|
||||
it('should dispatch "checked-changed" event when checked changed', async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue