@lion/switch
Advanced tools
Comparing version 0.11.2 to 0.12.0
# Change Log | ||
## 0.12.0 | ||
### Minor Changes | ||
- 06123918: Add types for switch package. | ||
### Patch Changes | ||
- 85720654: - prevent toggle of checked state when disabled | ||
- dispatch checked-changed on label click | ||
- Updated dependencies [4b7bea96] | ||
- Updated dependencies [01a798e5] | ||
- Updated dependencies [a31b7217] | ||
- Updated dependencies [85720654] | ||
- Updated dependencies [32202a88] | ||
- Updated dependencies [b9327627] | ||
- Updated dependencies [02145a06] | ||
- @lion/form-core@0.6.2 | ||
- @lion/core@0.13.0 | ||
## 0.11.2 | ||
@@ -4,0 +24,0 @@ |
{ | ||
"name": "@lion/switch", | ||
"version": "0.11.2", | ||
"version": "0.12.0", | ||
"description": "A Switch is used for switching a property or feature on and off", | ||
@@ -36,4 +36,4 @@ "license": "MIT", | ||
"dependencies": { | ||
"@lion/core": "0.12.0", | ||
"@lion/form-core": "0.6.1" | ||
"@lion/core": "0.13.0", | ||
"@lion/form-core": "0.6.2" | ||
}, | ||
@@ -40,0 +40,0 @@ "keywords": [ |
@@ -5,2 +5,3 @@ import { css, html, ScopedElementsMixin } from '@lion/core'; | ||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/40110 | ||
export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField)) { | ||
@@ -29,6 +30,22 @@ static get styles() { | ||
/** | ||
* 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', | ||
), | ||
), | ||
}; | ||
@@ -56,8 +73,14 @@ } | ||
constructor() { | ||
super(); | ||
this.role = 'switch'; | ||
this.checked = false; | ||
this.__handleButtonSwitchCheckedChanged = this.__handleButtonSwitchCheckedChanged.bind(this); | ||
} | ||
connectedCallback() { | ||
super.connectedCallback(); | ||
this._inputNode.addEventListener( | ||
'checked-changed', | ||
this.__handleButtonSwitchCheckedChanged.bind(this), | ||
); | ||
if (this._inputNode) { | ||
this._inputNode.addEventListener('checked-changed', this.__handleButtonSwitchCheckedChanged); | ||
} | ||
if (this._labelNode) { | ||
@@ -71,2 +94,8 @@ this._labelNode.addEventListener('click', this.__toggleChecked); | ||
disconnectedCallback() { | ||
if (this._inputNode) { | ||
this._inputNode.removeEventListener( | ||
'checked-changed', | ||
this.__handleButtonSwitchCheckedChanged, | ||
); | ||
} | ||
if (this._labelNode) { | ||
@@ -77,2 +106,3 @@ this._labelNode.removeEventListener('click', this.__toggleChecked); | ||
/** @param {import('lit-element').PropertyValues } changedProperties */ | ||
updated(changedProperties) { | ||
@@ -87,3 +117,5 @@ super.updated(changedProperties); | ||
// eslint-disable-next-line class-methods-use-this | ||
_isEmpty() {} | ||
_isEmpty() { | ||
return false; | ||
} | ||
@@ -95,5 +127,4 @@ __handleButtonSwitchCheckedChanged() { | ||
_syncButtonSwitch() { | ||
this._inputNode.checked = this.checked; | ||
this._inputNode.disabled = this.disabled; | ||
} | ||
} |
@@ -77,5 +77,5 @@ import { html, css, LitElement, DisabledWithTabIndexMixin } from '@lion/core'; | ||
this.checked = false; | ||
this.addEventListener('click', this.__handleToggleStateChange); | ||
this.addEventListener('keydown', this.__handleKeydown); | ||
this.addEventListener('keyup', this.__handleKeyup); | ||
this.__toggleChecked = this.__toggleChecked.bind(this); | ||
this.__handleKeydown = this.__handleKeydown.bind(this); | ||
this.__handleKeyup = this.__handleKeyup.bind(this); | ||
} | ||
@@ -86,5 +86,15 @@ | ||
this.setAttribute('aria-checked', `${this.checked}`); | ||
this.addEventListener('click', this.__toggleChecked); | ||
this.addEventListener('keydown', this.__handleKeydown); | ||
this.addEventListener('keyup', this.__handleKeyup); | ||
} | ||
__handleToggleStateChange() { | ||
disconnectedCallback() { | ||
super.disconnectedCallback(); | ||
this.removeEventListener('click', this.__toggleChecked); | ||
this.removeEventListener('keydown', this.__handleKeydown); | ||
this.removeEventListener('keyup', this.__handleKeyup); | ||
} | ||
__toggleChecked() { | ||
if (this.disabled) { | ||
@@ -96,2 +106,5 @@ return; | ||
this.checked = !this.checked; | ||
} | ||
__checkedStateChange() { | ||
this.dispatchEvent( | ||
@@ -103,4 +116,8 @@ new Event('checked-changed', { | ||
); | ||
this.setAttribute('aria-checked', `${this.checked}`); | ||
} | ||
/** | ||
* @param {KeyboardEvent} e | ||
*/ | ||
// eslint-disable-next-line class-methods-use-this | ||
@@ -114,8 +131,12 @@ __handleKeydown(e) { | ||
/** | ||
* @param {KeyboardEvent} e | ||
*/ | ||
__handleKeyup(e) { | ||
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) { | ||
this.__handleToggleStateChange(); | ||
this.__toggleChecked(); | ||
} | ||
} | ||
/** @param {import('lit-element').PropertyValues } changedProperties */ | ||
updated(changedProperties) { | ||
@@ -130,2 +151,4 @@ if (changedProperties.has('disabled')) { | ||
* | ||
* @param {PropertyKey} name | ||
* @param {?} oldValue | ||
* @override | ||
@@ -135,6 +158,6 @@ */ | ||
super.requestUpdateInternal(name, oldValue); | ||
if (this.isConnected && name === 'checked') { | ||
this.setAttribute('aria-checked', `${this.checked}`); | ||
if (this.isConnected && name === 'checked' && this.checked !== oldValue) { | ||
this.__checkedStateChange(); | ||
} | ||
} | ||
} |
@@ -1,6 +0,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-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; | ||
@@ -65,4 +73,4 @@ beforeEach(async () => { | ||
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]; | ||
@@ -73,6 +81,23 @@ expect(e).to.be.an.instanceof(Event); | ||
}; | ||
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', () => { | ||
const handlerSpy = sinon.spy(); | ||
el.addEventListener('checked-changed', handlerSpy); | ||
el.checked = true; | ||
el.checked = false; | ||
expect(handlerSpy.callCount).to.equal(2); | ||
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)); | ||
checkCall(handlerSpy.getCall(1)); | ||
}); | ||
it('should not dispatch "checked-changed" event if disabled', () => { | ||
@@ -105,3 +130,3 @@ const handlerSpy = sinon.spy(); | ||
el.setAttribute('checked', true); | ||
el.setAttribute('checked', ''); | ||
await el.updateComplete; | ||
@@ -108,0 +133,0 @@ expect(el.getAttribute('aria-checked')).to.equal('true'); |
@@ -1,4 +0,12 @@ | ||
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', () => { | ||
@@ -18,2 +26,8 @@ it('should have default "input" element', async () => { | ||
it('clicking the label should not toggle the checked state when disabled', async () => { | ||
const el = await fixture(html`<lion-switch disabled label="Enable Setting"></lion-switch>`); | ||
el._labelNode.click(); | ||
expect(el.checked).to.be.false; | ||
}); | ||
it('should sync its "disabled" state to child button', async () => { | ||
@@ -72,2 +86,30 @@ const el = await fixture(html`<lion-switch disabled></lion-switch>`); | ||
it('should dispatch "checked-changed" event when toggled via button or label', async () => { | ||
const handlerSpy = sinon.spy(); | ||
const el = await fixture(html`<lion-switch .choiceValue=${'foo'}></lion-switch>`); | ||
el.addEventListener('checked-changed', handlerSpy); | ||
el._inputNode.click(); | ||
el._labelNode.click(); | ||
await el.updateComplete; | ||
expect(handlerSpy.callCount).to.equal(2); | ||
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)); | ||
checkCall(handlerSpy.getCall(1)); | ||
}); | ||
it('should dispatch "checked-changed" event when checked changed', async () => { | ||
const handlerSpy = sinon.spy(); | ||
const el = await fixture(html`<lion-switch .choiceValue=${'foo'}></lion-switch>`); | ||
el.addEventListener('checked-changed', handlerSpy); | ||
el.checked = true; | ||
await el.updateComplete; | ||
expect(handlerSpy.callCount).to.equal(1); | ||
}); | ||
it('is submitted by default', async () => { | ||
@@ -74,0 +116,0 @@ const el = await fixture(html`<lion-switch></lion-switch>`); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
39060
17
536
+ Added@lion/core@0.13.0(transitive)
+ Added@lion/form-core@0.6.2(transitive)
+ Added@lion/localize@0.14.5(transitive)
- Removed@lion/core@0.12.0(transitive)
- Removed@lion/form-core@0.6.1(transitive)
- Removed@lion/localize@0.14.4(transitive)
Updated@lion/core@0.13.0
Updated@lion/form-core@0.6.2