feat(checkbox-group): add checkbox-indeterminate component
This commit is contained in:
parent
f98aab23f1
commit
8d2b251384
5 changed files with 530 additions and 37 deletions
5
.changeset/five-onions-hope.md
Normal file
5
.changeset/five-onions-hope.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/checkbox-group': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add checkbox-indeterminate component, which is a mixed state checkbox that depends on its child checkbox states.
|
||||||
|
|
@ -173,11 +173,75 @@ export const event = () => html`
|
||||||
```js preview-story
|
```js preview-story
|
||||||
export const indeterminate = () => html`
|
export const indeterminate = () => html`
|
||||||
<lion-checkbox-group name="scientists[]">
|
<lion-checkbox-group name="scientists[]">
|
||||||
<lion-checkbox-indeterminate indeterminate label="Favorite scientists">
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes"></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon"></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie"></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const indeterminateSiblings = () => html`
|
||||||
|
<lion-checkbox-group name="scientists[]" label="Favorite scientists">
|
||||||
|
<lion-checkbox-indeterminate label="Old Greek scientists">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Archimedes"
|
||||||
|
.choiceValue=${'Archimedes'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Plato" .choiceValue=${'Plato'}></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Pythagoras"
|
||||||
|
.choiceValue=${'Pythagoras'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
<lion-checkbox-indeterminate label="17th Century scientists">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Isaac Newton"
|
||||||
|
.choiceValue=${'Isaac Newton'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Galileo Galilei"
|
||||||
|
.choiceValue=${'Galileo Galilei'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const indeterminateChildren = () => html`
|
||||||
|
<lion-checkbox-group name="scientists[]" label="Favorite scientists">
|
||||||
|
<lion-checkbox-indeterminate label="Scientists">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Isaac Newton"
|
||||||
|
.choiceValue=${'Isaac Newton'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Galileo Galilei"
|
||||||
|
.choiceValue=${'Galileo Galilei'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox-indeterminate slot="checkbox" label="Old Greek scientists">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Archimedes"
|
||||||
|
.choiceValue=${'Archimedes'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Plato" .choiceValue=${'Plato'}></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Pythagoras"
|
||||||
|
.choiceValue=${'Pythagoras'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
</lion-checkbox-indeterminate>
|
</lion-checkbox-indeterminate>
|
||||||
<lion-checkbox label="Archimedes"></lion-checkbox>
|
|
||||||
<lion-checkbox label="Francis Bacon"></lion-checkbox>
|
|
||||||
<lion-checkbox label="Marie Curie"></lion-checkbox>
|
|
||||||
</lion-checkbox-group>
|
</lion-checkbox-group>
|
||||||
`;
|
`;
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,28 @@
|
||||||
|
import { html, css } from '@lion/core';
|
||||||
import { LionCheckbox } from './LionCheckbox.js';
|
import { LionCheckbox } from './LionCheckbox.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./LionCheckboxGroup').LionCheckboxGroup} LionCheckboxGroup
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-expect-error false positive for incompatible static get properties. Lit-element merges super properties already for you.
|
||||||
export class LionCheckboxIndeterminate extends LionCheckbox {
|
export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
|
static get styles() {
|
||||||
|
const superCtor = /** @type {typeof LionCheckbox} */ (super.prototype.constructor);
|
||||||
|
return [
|
||||||
|
superCtor.styles ? superCtor.styles : [],
|
||||||
|
css`
|
||||||
|
:host .choice-field__nested-checkboxes {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
::slotted([slot='checkbox']) {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
|
|
@ -14,52 +36,99 @@ export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
get _checkboxGroupNode() {
|
get _checkboxGroupNode() {
|
||||||
return /** @type {import('./LionCheckboxGroup').LionCheckboxGroup} */ (this.parentElement);
|
return /** @type LionCheckboxGroup */ (this._parentFormGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
get _subCheckboxes() {
|
get _subCheckboxes() {
|
||||||
return this._checkboxGroupNode.formElements.filter(checkbox => checkbox !== this);
|
let checkboxes = [];
|
||||||
|
if (
|
||||||
|
this._checkboxGroupNode &&
|
||||||
|
this._checkboxGroupNode.formElements &&
|
||||||
|
this._checkboxGroupNode.formElements.length > 0
|
||||||
|
) {
|
||||||
|
checkboxes = this._checkboxGroupNode.formElements.filter(
|
||||||
|
checkbox => checkbox !== this && this.contains(checkbox),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return /** @type LionCheckbox[] */ (checkboxes);
|
||||||
}
|
}
|
||||||
|
|
||||||
_parentModelValueChanged() {
|
_setOwnCheckedState() {
|
||||||
const checkedElements = this._subCheckboxes.filter(checkbox => checkbox.checked);
|
const subCheckboxes = this._subCheckboxes;
|
||||||
switch (this._subCheckboxes.length - checkedElements.length) {
|
if (!subCheckboxes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__settingOwnChecked = true;
|
||||||
|
const checkedElements = subCheckboxes.filter(checkbox => checkbox.checked);
|
||||||
|
switch (subCheckboxes.length - checkedElements.length) {
|
||||||
// all checked
|
// all checked
|
||||||
case 0:
|
case 0:
|
||||||
this.indeterminate = false;
|
this.indeterminate = false;
|
||||||
this.checked = true;
|
this.checked = true;
|
||||||
break;
|
break;
|
||||||
// none checked
|
// none checked
|
||||||
case this._subCheckboxes.length:
|
case subCheckboxes.length:
|
||||||
this.indeterminate = false;
|
this.indeterminate = false;
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.indeterminate = true;
|
this.indeterminate = true;
|
||||||
|
this.checked = false;
|
||||||
}
|
}
|
||||||
|
this.updateComplete.then(() => {
|
||||||
|
this.__settingOwnChecked = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_ownModelValueChanged(ev) {
|
/**
|
||||||
if (ev.target === this) {
|
* @param {Event} ev
|
||||||
|
*/
|
||||||
|
__onModelValueChanged(ev) {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _ev = /** @type {CustomEvent} */ (ev);
|
||||||
|
if (_ev.detail.formPath[0] === this && !this.__settingOwnChecked) {
|
||||||
this._subCheckboxes.forEach(checkbox => {
|
this._subCheckboxes.forEach(checkbox => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
checkbox.checked = this.checked;
|
checkbox.checked = this._inputNode.checked;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this._setOwnCheckedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_afterTemplate() {
|
||||||
|
return html`
|
||||||
|
<div class="choice-field__nested-checkboxes">
|
||||||
|
<slot name="checkbox"></slot>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onRequestToAddFormElement() {
|
||||||
|
this._setOwnCheckedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.indeterminate = false;
|
this.indeterminate = false;
|
||||||
|
this._onRequestToAddFormElement = this._onRequestToAddFormElement.bind(this);
|
||||||
|
this.__onModelValueChanged = this.__onModelValueChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._checkboxGroupNode.addEventListener(
|
this.addEventListener('model-value-changed', this.__onModelValueChanged);
|
||||||
'model-value-changed',
|
this.addEventListener('form-element-register', this._onRequestToAddFormElement);
|
||||||
this._parentModelValueChanged.bind(this),
|
}
|
||||||
);
|
|
||||||
this.addEventListener('model-value-changed', this._ownModelValueChanged);
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this.removeEventListener('model-value-changed', this.__onModelValueChanged);
|
||||||
|
this.removeEventListener('form-element-register', this._onRequestToAddFormElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {import('lit-element').PropertyValues } changedProperties */
|
/** @param {import('lit-element').PropertyValues } changedProperties */
|
||||||
|
|
@ -69,23 +138,4 @@ export class LionCheckboxIndeterminate extends LionCheckbox {
|
||||||
this._inputNode.indeterminate = this.indeterminate;
|
this._inputNode.indeterminate = this.indeterminate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* clicking on indeterminate status will set the status as checked
|
|
||||||
*/
|
|
||||||
__toggleChecked() {
|
|
||||||
if (this.disabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// always turn off indeterminate
|
|
||||||
// and set checked to true
|
|
||||||
if (this.indeterminate) {
|
|
||||||
this.indeterminate = false;
|
|
||||||
this.checked = true;
|
|
||||||
} else {
|
|
||||||
this.checked = !this.checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import '../lion-checkbox-indeterminate.js';
|
||||||
|
import { runChoiceInputMixinSuite } from '@lion/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js';
|
||||||
|
|
||||||
|
runChoiceInputMixinSuite({ tagString: 'lion-checkbox-indeterminate' });
|
||||||
370
packages/checkbox-group/test/lion-checkbox-indeterminate.test.js
Normal file
370
packages/checkbox-group/test/lion-checkbox-indeterminate.test.js
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
import { expect, fixture, html } from '@open-wc/testing';
|
||||||
|
import '../lion-checkbox-indeterminate.js';
|
||||||
|
import '../lion-checkbox-group.js';
|
||||||
|
import '../lion-checkbox.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/LionCheckboxIndeterminate').LionCheckboxIndeterminate} LionCheckboxIndeterminate
|
||||||
|
* @typedef {import('../src/LionCheckboxGroup').LionCheckboxGroup} LionCheckboxGroup
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('<lion-checkbox-indeterminate>', () => {
|
||||||
|
it('should have type = checkbox', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = await fixture(html`
|
||||||
|
<lion-checkbox-indeterminate
|
||||||
|
name="checkbox"
|
||||||
|
.choiceValue="${'male'}"
|
||||||
|
></lion-checkbox-indeterminate>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(el.getAttribute('type')).to.equal('checkbox');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be indeterminate by default if all children are unchecked', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = 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"></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be indeterminate if one child is 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" checked></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be checked if all children 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" checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie" checked></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`));
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'lion-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?.checked).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should become indeterminate if one child is 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"></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._subCheckboxes[0].checked = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should become checked if all children 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"></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._subCheckboxes[0].checked = true;
|
||||||
|
elIndeterminate._subCheckboxes[1].checked = true;
|
||||||
|
elIndeterminate._subCheckboxes[2].checked = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?.checked).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync all 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" checked></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync all children when parent is checked (from unchecked 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"></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',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync all children when parent is checked (from checked to unchecked)', 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" checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon" checked></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie" checked></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`));
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'lion-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._inputNode.click();
|
||||||
|
await elIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work as expected with siblings checkbox-indeterminate', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]" label="Favorite scientists">
|
||||||
|
<lion-checkbox-indeterminate label="Old Greek scientists" id="first-checkbox-indeterminate">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Archimedes"
|
||||||
|
.choiceValue=${'Archimedes'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Plato" .choiceValue=${'Plato'}></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Pythagoras"
|
||||||
|
.choiceValue=${'Pythagoras'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
<lion-checkbox-indeterminate
|
||||||
|
label="17th Century scientists"
|
||||||
|
id="second-checkbox-indeterminate"
|
||||||
|
>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Isaac Newton"
|
||||||
|
.choiceValue=${'Isaac Newton'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Galileo Galilei"
|
||||||
|
.choiceValue=${'Galileo Galilei'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`));
|
||||||
|
const elFirstIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'#first-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
const elSecondIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'#second-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act - check the first sibling
|
||||||
|
elFirstIndeterminate._inputNode.click();
|
||||||
|
await elFirstIndeterminate.updateComplete;
|
||||||
|
await elSecondIndeterminate.updateComplete;
|
||||||
|
|
||||||
|
// Assert - the second sibling should not be affected
|
||||||
|
expect(elFirstIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elFirstIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elFirstIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elFirstIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elSecondIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.false;
|
||||||
|
expect(elSecondIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work as expected with nested indeterminate checkboxes', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]" label="Favorite scientists">
|
||||||
|
<lion-checkbox-indeterminate label="Scientists" id="parent-checkbox-indeterminate">
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Isaac Newton"
|
||||||
|
.choiceValue=${'Isaac Newton'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Galileo Galilei"
|
||||||
|
.choiceValue=${'Galileo Galilei'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox-indeterminate
|
||||||
|
slot="checkbox"
|
||||||
|
label="Old Greek scientists"
|
||||||
|
id="nested-checkbox-indeterminate"
|
||||||
|
>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Archimedes"
|
||||||
|
.choiceValue=${'Archimedes'}
|
||||||
|
></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Plato" .choiceValue=${'Plato'}></lion-checkbox>
|
||||||
|
<lion-checkbox
|
||||||
|
slot="checkbox"
|
||||||
|
label="Pythagoras"
|
||||||
|
.choiceValue=${'Pythagoras'}
|
||||||
|
></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`));
|
||||||
|
const elNestedIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'#nested-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
const elParentIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'#parent-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act - check a nested checkbox
|
||||||
|
elNestedIndeterminate?._subCheckboxes[0]._inputNode.click();
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
|
||||||
|
// Act - check all nested checkbox
|
||||||
|
elNestedIndeterminate?._subCheckboxes[1]._inputNode.click();
|
||||||
|
elNestedIndeterminate?._subCheckboxes[2]._inputNode.click();
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elNestedIndeterminate?.hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elParentIndeterminate?.hasAttribute('checked')).to.be.false;
|
||||||
|
expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.true;
|
||||||
|
|
||||||
|
// Act - finally check all remaining checkbox
|
||||||
|
elParentIndeterminate?._subCheckboxes[0]._inputNode.click();
|
||||||
|
elParentIndeterminate?._subCheckboxes[1]._inputNode.click();
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elNestedIndeterminate?.hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elParentIndeterminate?.hasAttribute('checked')).to.be.true;
|
||||||
|
expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work as expected if extra html', async () => {
|
||||||
|
// Arrange
|
||||||
|
const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
|
||||||
|
<lion-checkbox-group name="scientists[]">
|
||||||
|
<div>
|
||||||
|
Let's have some fun
|
||||||
|
<div>Hello I'm a div</div>
|
||||||
|
<lion-checkbox-indeterminate label="Favorite scientists">
|
||||||
|
<div>useless div</div>
|
||||||
|
<lion-checkbox slot="checkbox" label="Archimedes"></lion-checkbox>
|
||||||
|
<lion-checkbox slot="checkbox" label="Francis Bacon"></lion-checkbox>
|
||||||
|
<div>absolutely useless</div>
|
||||||
|
<lion-checkbox slot="checkbox" label="Marie Curie"></lion-checkbox>
|
||||||
|
</lion-checkbox-indeterminate>
|
||||||
|
</div>
|
||||||
|
<div>Too much fun, stop it !</div>
|
||||||
|
</lion-checkbox-group>
|
||||||
|
`));
|
||||||
|
const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
|
||||||
|
'lion-checkbox-indeterminate',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
elIndeterminate._subCheckboxes[0].checked = true;
|
||||||
|
elIndeterminate._subCheckboxes[1].checked = true;
|
||||||
|
elIndeterminate._subCheckboxes[2].checked = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
|
||||||
|
expect(elIndeterminate?.checked).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue