fix(checkbox-group): indeterminate checkbox respects disabled states (#1698)
Co-authored-by: Danny Moerkerke <danny.moerkerke@ing.com>
This commit is contained in:
parent
6c0b0201e6
commit
05e17d69e5
4 changed files with 145 additions and 7 deletions
5
.changeset/mighty-bats-decide.md
Normal file
5
.changeset/mighty-bats-decide.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/checkbox-group': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Checkbox indeterminate now properly handles disabled states on child checkboxes.
|
||||||
|
|
@ -13,7 +13,6 @@ export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
:host .choice-field__nested-checkboxes {
|
:host .choice-field__nested-checkboxes {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
::slotted([slot='checkbox']) {
|
::slotted([slot='checkbox']) {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
@ -86,6 +85,7 @@ export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
|
|
||||||
this.__settingOwnChecked = true;
|
this.__settingOwnChecked = true;
|
||||||
const checkedElements = subCheckboxes.filter(checkbox => checkbox.checked);
|
const checkedElements = subCheckboxes.filter(checkbox => checkbox.checked);
|
||||||
|
|
||||||
switch (subCheckboxes.length - checkedElements.length) {
|
switch (subCheckboxes.length - checkedElements.length) {
|
||||||
// all checked
|
// all checked
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -147,13 +147,29 @@ export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.__settingOwnSubs = true;
|
this.__settingOwnSubs = true;
|
||||||
if (this.indeterminate && this.mixedState) {
|
|
||||||
|
const subCheckboxes = this._subCheckboxes;
|
||||||
|
const checkedElements = subCheckboxes.filter(checkbox => checkbox.checked);
|
||||||
|
const disabledElements = subCheckboxes.filter(checkbox => checkbox.disabled);
|
||||||
|
const allChecked =
|
||||||
|
subCheckboxes.length > 0 && subCheckboxes.length === checkedElements.length;
|
||||||
|
const allDisabled =
|
||||||
|
subCheckboxes.length > 0 && subCheckboxes.length === disabledElements.length;
|
||||||
|
const hasDisabledElements = disabledElements.length > 0;
|
||||||
|
|
||||||
|
if (allDisabled) {
|
||||||
|
this.checked = allChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indeterminate && (this.mixedState || hasDisabledElements)) {
|
||||||
this._subCheckboxes.forEach((checkbox, i) => {
|
this._subCheckboxes.forEach((checkbox, i) => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
checkbox.checked = this._indeterminateSubStates[i];
|
checkbox.checked = this._indeterminateSubStates[i];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._subCheckboxes.forEach(checkbox => {
|
this._subCheckboxes
|
||||||
|
.filter(checkbox => !checkbox.disabled)
|
||||||
|
.forEach(checkbox => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
checkbox.checked = this._inputNode.checked;
|
checkbox.checked = this._inputNode.checked;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,34 @@ describe('<lion-checkbox-indeterminate>', () => {
|
||||||
expect(elIndeterminate?.checked).to.be.true;
|
expect(elIndeterminate?.checked).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should become indeterminate if all children except disabled ones are checked', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]">
|
||||||
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes"></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" disabled></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie"></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (
|
||||||
|
el.querySelector('lion-checkbox-indeterminate')
|
||||||
|
);
|
||||||
|
const { _subCheckboxes } = getCheckboxIndeterminateMembers(elIndeterminate);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
_subCheckboxes[0].checked = true;
|
||||||
|
_subCheckboxes[2].checked = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
expect(elIndeterminate?.checked).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
it('should sync all children when parent is checked (from indeterminate to checked)', async () => {
|
it('should sync all children when parent is checked (from indeterminate to checked)', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const el = /** @type {LionCheckboxGroup} */ (
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
|
@ -182,6 +210,95 @@ describe('<lion-checkbox-indeterminate>', () => {
|
||||||
expect(_subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
expect(_subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not sync any disabled children when parent is checked (from indeterminate to checked)', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]">
|
||||||
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes"></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" disabled></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie"></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (
|
||||||
|
el.querySelector('lion-checkbox-indeterminate')
|
||||||
|
);
|
||||||
|
const { _subCheckboxes, _inputNode } = getCheckboxIndeterminateMembers(elIndeterminate);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
_inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
expect(_subCheckboxes[0].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(_subCheckboxes[1].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(_subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remain unchecked when parent is clicked and all children are disabled', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]">
|
||||||
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes" disabled></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" disabled></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie" disabled></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (
|
||||||
|
el.querySelector('lion-checkbox-indeterminate')
|
||||||
|
);
|
||||||
|
const { _subCheckboxes, _inputNode } = getCheckboxIndeterminateMembers(elIndeterminate);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
_inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate.hasAttribute('checked')).to.be.false;
|
||||||
|
expect(_subCheckboxes[0].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(_subCheckboxes[1].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(_subCheckboxes[2].hasAttribute('checked')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remain checked when parent is clicked and all children are disabled and checked', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]">
|
||||||
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes" disabled checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" disabled checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie" disabled checked></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (
|
||||||
|
el.querySelector('lion-checkbox-indeterminate')
|
||||||
|
);
|
||||||
|
const { _subCheckboxes, _inputNode } = getCheckboxIndeterminateMembers(elIndeterminate);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
_inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate.hasAttribute('checked')).to.be.true;
|
||||||
|
expect(_subCheckboxes[0].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(_subCheckboxes[1].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(_subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
it('should sync all children when parent is checked (from unchecked to checked)', async () => {
|
it('should sync all children when parent is checked (from unchecked to checked)', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const el = /** @type {LionCheckboxGroup} */ (
|
const el = /** @type {LionCheckboxGroup} */ (
|
||||||
|
|
|
||||||
|
|
@ -3430,7 +3430,7 @@ autosize@4.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.2.tgz#073cfd07c8bf45da4b9fd153437f5bafbba1e4c9"
|
resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.2.tgz#073cfd07c8bf45da4b9fd153437f5bafbba1e4c9"
|
||||||
integrity sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA==
|
integrity sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA==
|
||||||
|
|
||||||
awesome-phonenumber@3.0.1:
|
awesome-phonenumber@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/awesome-phonenumber/-/awesome-phonenumber-3.0.1.tgz#8d73aaa1c2b0a660b117567b0d9797623457e1d0"
|
resolved "https://registry.yarnpkg.com/awesome-phonenumber/-/awesome-phonenumber-3.0.1.tgz#8d73aaa1c2b0a660b117567b0d9797623457e1d0"
|
||||||
integrity sha512-H5rqjTJ1+HxmyuSKDoPgvHUgP+RBRhtWQ25ccy4BmSLQL5UVg3K+yo2QCX4IlkxiVNst3suGMArV9TH7B1KEPw==
|
integrity sha512-H5rqjTJ1+HxmyuSKDoPgvHUgP+RBRhtWQ25ccy4BmSLQL5UVg3K+yo2QCX4IlkxiVNst3suGMArV9TH7B1KEPw==
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue