Merge f59b03c43336d3a1c485da9113d47e159b57e04a into 555b0add40685ad2d799e4bccfc4c69812abe207

This commit is contained in:
copybara-service[bot] 2026-01-06 20:41:45 +00:00 committed by GitHub
commit 78fec59126
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 86 additions and 10 deletions

View File

@ -23,6 +23,11 @@ import {
getValidityAnchor,
mixinConstraintValidation,
} from '../../labs/behaviors/constraint-validation.js';
import {
hasState,
mixinCustomStateSet,
toggleState,
} from '../../labs/behaviors/custom-state-set.js';
import {mixinElementInternals} from '../../labs/behaviors/element-internals.js';
import {
getFormState,
@ -34,7 +39,7 @@ import {CheckboxValidator} from '../../labs/behaviors/validators/checkbox-valida
// Separate variable needed for closure.
const checkboxBaseClass = mixinDelegatesAria(
mixinConstraintValidation(
mixinFormAssociated(mixinElementInternals(LitElement)),
mixinFormAssociated(mixinCustomStateSet(mixinElementInternals(LitElement))),
),
);
@ -59,14 +64,26 @@ export class Checkbox extends checkboxBaseClass {
/**
* Whether or not the checkbox is selected.
*/
@property({type: Boolean}) checked = false;
@property({type: Boolean})
get checked(): boolean {
return this[hasState]('checked');
}
set checked(checked: boolean) {
this[toggleState]('checked', checked);
}
/**
* Whether or not the checkbox is indeterminate.
*
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#indeterminate_state_checkboxes
*/
@property({type: Boolean}) indeterminate = false;
@property({type: Boolean})
get indeterminate(): boolean {
return this[hasState]('indeterminate');
}
set indeterminate(indeterminate: boolean) {
this[toggleState]('indeterminate', indeterminate);
}
/**
* When true, require the checkbox to be selected when participating in

View File

@ -152,6 +152,31 @@ describe('checkbox', () => {
expect(input.checked).toEqual(true);
expect(harness.element.checked).toEqual(true);
});
it('matches :state(checked) when true', async () => {
// Arrange
const {harness} = await setupTest();
// Act
harness.element.checked = true;
await env.waitForStability();
// Assert
expect(harness.element.matches(':state(checked)'))
.withContext("element.matches(':state(checked)')")
.toBeTrue();
});
it('does not match :state(checked) when false', async () => {
// Arrange
// Act
const {harness} = await setupTest();
// Assert
expect(harness.element.matches(':state(checked)'))
.withContext("element.matches(':state(checked)')")
.toBeFalse();
});
});
describe('indeterminate', () => {
@ -169,6 +194,31 @@ describe('checkbox', () => {
expect(input.indeterminate).toEqual(false);
expect(input.getAttribute('aria-checked')).not.toEqual('mixed');
});
it('matches :state(indeterminate) when true', async () => {
// Arrange
const {harness} = await setupTest();
// Act
harness.element.indeterminate = true;
await env.waitForStability();
// Assert
expect(harness.element.matches(':state(indeterminate)'))
.withContext("element.matches(':state(indeterminate)')")
.toBeTrue();
});
it('does not match :state(indeterminate) when false', async () => {
// Arrange
// Act
const {harness} = await setupTest();
// Assert
expect(harness.element.matches(':state(indeterminate)'))
.withContext("element.matches(':state(indeterminate)')")
.toBeFalse();
});
});
describe('disabled', () => {
@ -186,13 +236,15 @@ describe('checkbox', () => {
describe('form submission', () => {
async function setupFormTest(propsInit: Partial<Checkbox> = {}) {
return await setupTest(html` <form>
<md-test-checkbox
.checked=${propsInit.checked === true}
.disabled=${propsInit.disabled === true}
.name=${propsInit.name ?? ''}
.value=${propsInit.value ?? ''}></md-test-checkbox>
</form>`);
return await setupTest(
html`<form>
<md-test-checkbox
.checked=${propsInit.checked === true}
.disabled=${propsInit.disabled === true}
.name=${propsInit.name ?? ''}
.value=${propsInit.value ?? ''}></md-test-checkbox>
</form>`,
);
}
it('does not submit if not checked', async () => {

View File

@ -208,3 +208,10 @@ Token | Default value
<!-- mdformat on(autogenerated might break rendering in catalog) -->
<!-- auto-generated API docs end -->
#### States
| State | Description |
| --- | --- |
| `:state(checked)` | Matches when the checkbox is checked. |
| `:state(indeterminate)` | Matches when the checkbox is indeterminate. |