From 12e8d9f1cc7938d2db0d5bd2cd993cfec6f68afe Mon Sep 17 00:00:00 2001 From: web-padawan Date: Thu, 28 Mar 2024 11:54:36 +0200 Subject: [PATCH 01/16] feat: add required, error message and helper text to checkbox --- .../__snapshots__/checkbox-group.test.snap.js | 168 ++++++++++++++---- .../checkbox/src/vaadin-checkbox-mixin.d.ts | 4 + .../checkbox/src/vaadin-checkbox-mixin.js | 55 +++++- .../checkbox/src/vaadin-checkbox-styles.js | 12 +- packages/checkbox/src/vaadin-checkbox.d.ts | 31 ++-- packages/checkbox/src/vaadin-checkbox.js | 42 +++-- packages/checkbox/src/vaadin-lit-checkbox.js | 11 +- .../dom/__snapshots__/checkbox.test.snap.js | 161 +++++++++++++++-- packages/checkbox/test/dom/checkbox.test.js | 19 +- .../checkbox/test/typings/checkbox.types.ts | 4 + packages/checkbox/test/validation-lit.test.js | 2 + .../checkbox/test/validation-polymer.test.js | 2 + packages/checkbox/test/validation.common.js | 147 +++++++++++++++ .../test/visual/lumo/checkbox.test.js | 29 +++ .../checkbox/baseline/error-message.png | Bin 0 -> 2332 bytes .../checkbox/baseline/helper-text.png | Bin 0 -> 1913 bytes .../checkbox/baseline/invalid-focus-ring.png | Bin 0 -> 1628 bytes .../checkbox/baseline/required.png | Bin 0 -> 1296 bytes .../checkbox/baseline/rtl-required.png | Bin 0 -> 1258 bytes .../test/visual/material/checkbox.test.js | 22 +++ .../checkbox/baseline/error-message.png | Bin 0 -> 2092 bytes .../checkbox/baseline/helper-text.png | Bin 0 -> 1745 bytes .../checkbox/baseline/required.png | Bin 0 -> 1174 bytes .../checkbox/baseline/rtl-required.png | Bin 0 -> 1130 bytes .../theme/lumo/vaadin-checkbox-styles.js | 95 +++++++++- .../theme/material/vaadin-checkbox-styles.js | 49 +++++ 26 files changed, 773 insertions(+), 80 deletions(-) create mode 100644 packages/checkbox/test/validation-lit.test.js create mode 100644 packages/checkbox/test/validation-polymer.test.js create mode 100644 packages/checkbox/test/validation.common.js create mode 100644 packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/error-message.png create mode 100644 packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/helper-text.png create mode 100644 packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/invalid-focus-ring.png create mode 100644 packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/required.png create mode 100644 packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/rtl-required.png create mode 100644 packages/checkbox/test/visual/material/screenshots/checkbox/baseline/error-message.png create mode 100644 packages/checkbox/test/visual/material/screenshots/checkbox/baseline/helper-text.png create mode 100644 packages/checkbox/test/visual/material/screenshots/checkbox/baseline/required.png create mode 100644 packages/checkbox/test/visual/material/screenshots/checkbox/baseline/rtl-required.png diff --git a/packages/checkbox-group/test/dom/__snapshots__/checkbox-group.test.snap.js b/packages/checkbox-group/test/dom/__snapshots__/checkbox-group.test.snap.js index 9f18c60d6b..ca0574cd78 100644 --- a/packages/checkbox-group/test/dom/__snapshots__/checkbox-group.test.snap.js +++ b/packages/checkbox-group/test/dom/__snapshots__/checkbox-group.test.snap.js @@ -10,14 +10,21 @@ snapshots["vaadin-checkbox-group host default"] = value="1" > + + + + + + + + + + + + + + >( Constructor & Constructor & Constructor & + Constructor & Constructor & Constructor & Constructor & Constructor & + Constructor & T; export declare class CheckboxMixinClass { diff --git a/packages/checkbox/src/vaadin-checkbox-mixin.js b/packages/checkbox/src/vaadin-checkbox-mixin.js index 79aa5898db..17b92968d9 100644 --- a/packages/checkbox/src/vaadin-checkbox-mixin.js +++ b/packages/checkbox/src/vaadin-checkbox-mixin.js @@ -6,8 +6,8 @@ import { ActiveMixin } from '@vaadin/a11y-base/src/active-mixin.js'; import { DelegateFocusMixin } from '@vaadin/a11y-base/src/delegate-focus-mixin.js'; import { CheckedMixin } from '@vaadin/field-base/src/checked-mixin.js'; +import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js'; import { InputController } from '@vaadin/field-base/src/input-controller.js'; -import { LabelMixin } from '@vaadin/field-base/src/label-mixin.js'; import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-controller.js'; /** @@ -17,10 +17,10 @@ import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-c * @mixes ActiveMixin * @mixes CheckedMixin * @mixes DelegateFocusMixin - * @mixes LabelMixin + * @mixes FieldMixin */ export const CheckboxMixin = (superclass) => - class CheckboxMixinClass extends LabelMixin(CheckedMixin(DelegateFocusMixin(ActiveMixin(superclass)))) { + class CheckboxMixinClass extends FieldMixin(CheckedMixin(DelegateFocusMixin(ActiveMixin(superclass)))) { static get properties() { return { /** @@ -114,6 +114,8 @@ export const CheckboxMixin = (superclass) => }), ); this.addController(new LabelledInputController(this.inputElement, this._labelController)); + + this._createMethodObserver('_checkedChanged(checked)'); } /** @@ -195,6 +197,53 @@ export const CheckboxMixin = (superclass) => super._toggleChecked(checked); } + /** + * @override + * @return {boolean} + */ + checkValidity() { + return !this.required || !!this.checked; + } + + /** + * Override method inherited from `FocusMixin` to validate on blur. + * @param {boolean} focused + * @protected + */ + _setFocused(focused) { + super._setFocused(focused); + + // Do not validate when focusout is caused by document + // losing focus, which happens on browser tab switch. + if (!focused && document.hasFocus()) { + this.validate(); + } + } + + /** @private */ + _checkedChanged(checked) { + if (checked || this.__oldChecked) { + this.validate(); + } + + this.__oldChecked = checked; + } + + /** + * Override an observer from `FieldMixin` + * to validate when required is removed. + * + * @protected + * @override + */ + _requiredChanged(required) { + super._requiredChanged(required); + + if (required === false) { + this.validate(); + } + } + /** * Fired when the checkbox is checked or unchecked by the user. * diff --git a/packages/checkbox/src/vaadin-checkbox-styles.js b/packages/checkbox/src/vaadin-checkbox-styles.js index 55bb8a6763..ff660e6aa5 100644 --- a/packages/checkbox/src/vaadin-checkbox-styles.js +++ b/packages/checkbox/src/vaadin-checkbox-styles.js @@ -26,7 +26,7 @@ export const checkboxStyles = css` [part='checkbox'], ::slotted(input), - ::slotted(label) { + [part='label'] { grid-row: 1; } @@ -35,6 +35,16 @@ export const checkboxStyles = css` grid-column: 1; } + [part='helper-text'], + [part='error-message'] { + grid-column: 2; + } + + :host(:not([has-helper])) [part='helper-text'], + :host(:not([has-error-message])) [part='error-message'] { + display: none; + } + [part='checkbox'] { width: var(--vaadin-checkbox-size, 1em); height: var(--vaadin-checkbox-size, 1em); diff --git a/packages/checkbox/src/vaadin-checkbox.d.ts b/packages/checkbox/src/vaadin-checkbox.d.ts index 4d1e482f36..e609a8fef8 100644 --- a/packages/checkbox/src/vaadin-checkbox.d.ts +++ b/packages/checkbox/src/vaadin-checkbox.d.ts @@ -45,21 +45,28 @@ export interface CheckboxEventMap extends HTMLElementEventMap, CheckboxCustomEve * * The following shadow DOM parts are available for styling: * - * Part name | Description - * ------------|------------- - * `checkbox` | The element representing a stylable custom checkbox. + * Part name | Description + * ---------------------|------------- + * `checkbox` | The element representing a stylable custom checkbox + * `label` | The slotted label element wrapper + * `helper-text` | The slotted helper text element wrapper + * `error-message` | The slotted error message element wrapper + * `required-indicator` | The `required` state indicator element * * The following state attributes are available for styling: * - * Attribute | Description - * ----------------|------------- - * `active` | Set when the checkbox is activated with mouse, touch or the keyboard. - * `checked` | Set when the checkbox is checked. - * `disabled` | Set when the checkbox is disabled. - * `focus-ring` | Set when the checkbox is focused using the keyboard. - * `focused` | Set when the checkbox is focused. - * `indeterminate` | Set when the checkbox is in the indeterminate state. - * `has-label` | Set when the checkbox has a label. + * Attribute | Description + * ---------------------|------------- + * `active` | Set when the checkbox is activated with mouse, touch or the keyboard. + * `checked` | Set when the checkbox is checked. + * `disabled` | Set when the checkbox is disabled. + * `focus-ring` | Set when the checkbox is focused using the keyboard. + * `focused` | Set when the checkbox is focused. + * `indeterminate` | Set when the checkbox is in the indeterminate state. + * `invalid` | Set when the checkbox is invalid. + * `has-label` | Set when the checkbox has a label. + * `has-helper` | Set when the checkbox has helper text. + * `has-error-message` | Set when the checkbox has an error message. * * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation. * diff --git a/packages/checkbox/src/vaadin-checkbox.js b/packages/checkbox/src/vaadin-checkbox.js index 52800f408b..4158b7ecfc 100644 --- a/packages/checkbox/src/vaadin-checkbox.js +++ b/packages/checkbox/src/vaadin-checkbox.js @@ -24,21 +24,28 @@ registerStyles('vaadin-checkbox', checkboxStyles, { moduleId: 'vaadin-checkbox-s * * The following shadow DOM parts are available for styling: * - * Part name | Description - * ------------|------------- - * `checkbox` | The element representing a stylable custom checkbox. + * Part name | Description + * ---------------------|------------- + * `checkbox` | The element representing a stylable custom checkbox + * `label` | The slotted label element wrapper + * `helper-text` | The slotted helper text element wrapper + * `error-message` | The slotted error message element wrapper + * `required-indicator` | The `required` state indicator element * * The following state attributes are available for styling: * - * Attribute | Description - * ----------------|------------- - * `active` | Set when the checkbox is activated with mouse, touch or the keyboard. - * `checked` | Set when the checkbox is checked. - * `disabled` | Set when the checkbox is disabled. - * `focus-ring` | Set when the checkbox is focused using the keyboard. - * `focused` | Set when the checkbox is focused. - * `indeterminate` | Set when the checkbox is in the indeterminate state. - * `has-label` | Set when the checkbox has a label. + * Attribute | Description + * ---------------------|------------- + * `active` | Set when the checkbox is activated with mouse, touch or the keyboard. + * `checked` | Set when the checkbox is checked. + * `disabled` | Set when the checkbox is disabled. + * `focus-ring` | Set when the checkbox is focused using the keyboard. + * `focused` | Set when the checkbox is focused. + * `indeterminate` | Set when the checkbox is in the indeterminate state. + * `invalid` | Set when the checkbox is invalid. + * `has-label` | Set when the checkbox has a label. + * `has-helper` | Set when the checkbox has helper text. + * `has-error-message` | Set when the checkbox has an error message. * * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation. * @@ -62,7 +69,16 @@ export class Checkbox extends CheckboxMixin(ElementMixin(ThemableMixin(PolymerEl
- +
+ +
+
+
+ +
+
+ +
`; diff --git a/packages/checkbox/src/vaadin-lit-checkbox.js b/packages/checkbox/src/vaadin-lit-checkbox.js index 1c06ca3a38..ee7cf1bd12 100644 --- a/packages/checkbox/src/vaadin-lit-checkbox.js +++ b/packages/checkbox/src/vaadin-lit-checkbox.js @@ -36,7 +36,16 @@ export class Checkbox extends CheckboxMixin(ElementMixin(ThemableMixin(PolylitMi
- +
+ +
+
+
+ +
+
+ +
`; diff --git a/packages/checkbox/test/dom/__snapshots__/checkbox.test.snap.js b/packages/checkbox/test/dom/__snapshots__/checkbox.test.snap.js index a0d23e270b..bd8ebf0083 100644 --- a/packages/checkbox/test/dom/__snapshots__/checkbox.test.snap.js +++ b/packages/checkbox/test/dom/__snapshots__/checkbox.test.snap.js @@ -4,13 +4,19 @@ export const snapshots = {}; snapshots["vaadin-checkbox host default"] = ` + + + + + + + + +
+ Helper +
+
+`; +/* end snapshot vaadin-checkbox host helper */ + +snapshots["vaadin-checkbox host required"] = +` + + + + +`; +/* end snapshot vaadin-checkbox host required */ + +snapshots["vaadin-checkbox host error"] = +` + + + + +`; +/* end snapshot vaadin-checkbox host error */ + snapshots["vaadin-checkbox shadow default"] = `
- - +
+ + +
+
+
+
+ + +
+
+ + +
diff --git a/packages/checkbox/test/dom/checkbox.test.js b/packages/checkbox/test/dom/checkbox.test.js index d03601da34..407fa38fc9 100644 --- a/packages/checkbox/test/dom/checkbox.test.js +++ b/packages/checkbox/test/dom/checkbox.test.js @@ -1,5 +1,5 @@ import { expect } from '@esm-bundle/chai'; -import { fixtureSync } from '@vaadin/testing-helpers'; +import { aTimeout, fixtureSync } from '@vaadin/testing-helpers'; import '../../vaadin-checkbox.js'; import { resetUniqueId } from '@vaadin/component-base/src/unique-id-utils.js'; @@ -35,6 +35,23 @@ describe('vaadin-checkbox', () => { checkbox.readonly = true; await expect(checkbox).dom.to.equalSnapshot(); }); + + it('helper', async () => { + checkbox.helperText = 'Helper'; + await expect(checkbox).dom.to.equalSnapshot(); + }); + + it('required', async () => { + checkbox.required = true; + await expect(checkbox).dom.to.equalSnapshot(); + }); + + it('error', async () => { + checkbox.errorMessage = 'Error'; + checkbox.invalid = true; + await aTimeout(0); + await expect(checkbox).dom.to.equalSnapshot(); + }); }); describe('shadow', () => { diff --git a/packages/checkbox/test/typings/checkbox.types.ts b/packages/checkbox/test/typings/checkbox.types.ts index b513bb5cd9..e9ea54ed6b 100644 --- a/packages/checkbox/test/typings/checkbox.types.ts +++ b/packages/checkbox/test/typings/checkbox.types.ts @@ -7,7 +7,9 @@ import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js'; import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js'; import type { CheckedMixinClass } from '@vaadin/field-base/src/checked-mixin.js'; +import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js'; import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js'; +import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js'; import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; import type { CheckboxMixinClass } from '../../src/vaadin-checkbox-mixin.js'; import type { @@ -37,12 +39,14 @@ assertType(checkbox); assertType(checkbox); assertType(checkbox); assertType(checkbox); +assertType(checkbox); assertType(checkbox); assertType(checkbox); assertType(checkbox); assertType(checkbox); assertType(checkbox); assertType(checkbox); +assertType(checkbox); // Events checkbox.addEventListener('checked-changed', (event) => { diff --git a/packages/checkbox/test/validation-lit.test.js b/packages/checkbox/test/validation-lit.test.js new file mode 100644 index 0000000000..eb186ae2bf --- /dev/null +++ b/packages/checkbox/test/validation-lit.test.js @@ -0,0 +1,2 @@ +import '../src/vaadin-lit-checkbox.js'; +import './validation.common.js'; diff --git a/packages/checkbox/test/validation-polymer.test.js b/packages/checkbox/test/validation-polymer.test.js new file mode 100644 index 0000000000..887e5b2c43 --- /dev/null +++ b/packages/checkbox/test/validation-polymer.test.js @@ -0,0 +1,2 @@ +import '../src/vaadin-checkbox.js'; +import './validation.common.js'; diff --git a/packages/checkbox/test/validation.common.js b/packages/checkbox/test/validation.common.js new file mode 100644 index 0000000000..91b98d0bf7 --- /dev/null +++ b/packages/checkbox/test/validation.common.js @@ -0,0 +1,147 @@ +import { expect } from '@esm-bundle/chai'; +import { fixtureSync, nextFrame, nextRender, nextUpdate } from '@vaadin/testing-helpers'; +import { sendKeys } from '@web/test-runner-commands'; +import sinon from 'sinon'; + +describe('validation', () => { + let checkbox, validateSpy; + + describe('initial', () => { + beforeEach(() => { + checkbox = document.createElement('vaadin-checkbox'); + validateSpy = sinon.spy(checkbox, 'validate'); + }); + + afterEach(() => { + checkbox.remove(); + }); + + it('should not validate by default', async () => { + document.body.appendChild(checkbox); + await nextRender(); + expect(validateSpy.called).to.be.false; + }); + + it('should not validate when the checkbox is initially checked', async () => { + checkbox.checked = true; + document.body.appendChild(checkbox); + await nextRender(); + expect(validateSpy.called).to.be.false; + }); + + it('should not validate when the field is initially checked and invalid', async () => { + checkbox.checked = true; + checkbox.invalid = true; + document.body.appendChild(checkbox); + await nextRender(); + expect(validateSpy.called).to.be.false; + }); + }); + + describe('basic', () => { + beforeEach(async () => { + checkbox = fixtureSync(''); + await nextRender(); + validateSpy = sinon.spy(checkbox, 'validate'); + }); + + it('should pass validation by default', () => { + expect(checkbox.checkValidity()).to.be.true; + }); + + it('should validate when toggling checked property', async () => { + checkbox.checked = true; + await nextUpdate(checkbox); + expect(validateSpy.calledOnce).to.be.true; + + checkbox.checked = false; + await nextUpdate(checkbox); + expect(validateSpy.calledTwice).to.be.true; + }); + + it('should validate on focusout', async () => { + // Focus the checkbox. + await sendKeys({ press: 'Tab' }); + expect(validateSpy.called).to.be.false; + + // Blur the checkbox. + await sendKeys({ down: 'Shift' }); + await sendKeys({ press: 'Tab' }); + await sendKeys({ up: 'Shift' }); + + expect(validateSpy.calledOnce).to.be.true; + }); + + it('should fire a validated event on validation success', () => { + const validatedSpy = sinon.spy(); + checkbox.addEventListener('validated', validatedSpy); + checkbox.validate(); + + expect(validatedSpy.calledOnce).to.be.true; + const event = validatedSpy.firstCall.args[0]; + expect(event.detail.valid).to.be.true; + }); + + it('should fire a validated event on validation failure', () => { + const validatedSpy = sinon.spy(); + checkbox.addEventListener('validated', validatedSpy); + checkbox.required = true; + checkbox.validate(); + + expect(validatedSpy.calledOnce).to.be.true; + const event = validatedSpy.firstCall.args[0]; + expect(event.detail.valid).to.be.false; + }); + + describe('document losing focus', () => { + beforeEach(() => { + sinon.stub(document, 'hasFocus').returns(false); + }); + + afterEach(() => { + document.hasFocus.restore(); + }); + + it('should not validate on blur when document does not have focus', async () => { + // Focus the checkbox. + await sendKeys({ press: 'Tab' }); + + // Blur the checkbox. + await sendKeys({ down: 'Shift' }); + await sendKeys({ press: 'Tab' }); + await sendKeys({ up: 'Shift' }); + + expect(validateSpy.called).to.be.false; + }); + }); + }); + + describe('required', () => { + let checkboxes; + + beforeEach(async () => { + checkbox = fixtureSync(''); + await nextFrame(); + validateSpy = sinon.spy(checkbox, 'validate'); + }); + + it('should fail validation with checked set to false', () => { + expect(checkbox.checkValidity()).to.be.false; + }); + + it('should pass validation with checked set to true', () => { + checkbox.checked = true; + expect(checkbox.checkValidity()).to.be.true; + }); + + it('should be valid after toggling a checkbox', () => { + checkbox.click(); + expect(checkbox.invalid).to.be.false; + }); + + it('should pass validation with required set to false', () => { + checkbox.required = false; + expect(checkbox.invalid).to.be.false; + }); + }); +}); diff --git a/packages/checkbox/test/visual/lumo/checkbox.test.js b/packages/checkbox/test/visual/lumo/checkbox.test.js index f05d9adf24..16e5dbec89 100644 --- a/packages/checkbox/test/visual/lumo/checkbox.test.js +++ b/packages/checkbox/test/visual/lumo/checkbox.test.js @@ -44,6 +44,30 @@ describe('checkbox', () => { await visualDiff(div, 'checked-focus-ring'); }); + it('required', async () => { + element.required = true; + await visualDiff(div, 'required'); + }); + + it('invalid focus-ring', async () => { + element.required = true; + element.invalid = true; + await sendKeys({ press: 'Tab' }); + await visualDiff(div, 'invalid-focus-ring'); + }); + + it('error message', async () => { + element.errorMessage = 'This field is required'; + element.required = true; + element.validate(); + await visualDiff(div, 'error-message'); + }); + + it('helper text', async () => { + element.helperText = 'Helper text'; + await visualDiff(div, 'helper-text'); + }); + describe('disabled', () => { beforeEach(() => { element.disabled = true; @@ -106,6 +130,11 @@ describe('checkbox', () => { element.label = ''; await visualDiff(div, 'rtl-empty'); }); + + it('required', async () => { + element.required = true; + await visualDiff(div, 'rtl-required'); + }); }); describe('borders enabled', () => { diff --git a/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/error-message.png b/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/error-message.png new file mode 100644 index 0000000000000000000000000000000000000000..9e14f1eacc4d48d5f797afdf485cb3657ba59650 GIT binary patch literal 2332 zcma)8X*iUP8h#TpWE(;pIuD&iQda_mAiK@%(u1`?*QiZQ#7z;@kiL@LFCmvpZtS z5v;j5k7}m@S?h?71=_()fXZHpMF8L$wKOxn@gR3K7j?xsRHT!d=q%-vdfsiGP+by# zlG8iiMTlU719!x$*`It~g;tRZy64l<< zfEDpwgO(*t+2wAh6+@tF)&YTmZoc4-g3XA_ODvWyH5K*2aDKnCK@rSu3>d3_l%HP( zj1{C1;2z^*napT2OZ5|^r)WN~Y^#LKRlM$%H1@z`1<>5t|2A-t*5^Lme&Xjs2v=w4 zWf5q%ijtx+V$q?HEK@K`VxuUG@iVxgMwfMHeLkDEMy&W4OLB5J(}-!f-toBoaQ1$* zfM0qu2a5Mb+sjlm6tp^M*KD0^n)NZ1~tg$2RLq9Q=!Q$$ z=NVB6BpK+n+n1&XuRO)WWhBj-g)#N~T|MSbxIl=E*0FD*W1Ft4z)pH%w&3&&_SQDvd{@ue5vg%7&U31n`C-n}|l{ z-cR_7`!{()gP4|VT`knJR7nVL4<7&Y+OgH&R7g_!w*(;2u_n@wyEKubHVwrGofg~V zfAQoLkWH;Gy4&z*D-4ZQ=HB->LoMdr^+~HK#daTSrp2;p6&HTB;ctZ5WWI=6TclXo z>({7VHI?Uc&d1bd&PL)1uyep-l|9*o>A%@ zthg}8M)uRdpQI*3*#kaaC*^DjXW=Dh9Y{Cw6Xyt$@iy=7)SIp*lTF+?;<`~q4XzLI z{5cN{IewI1C9{rC2}mMC1#*4c{fS+7Ecv|P_jS0fbYj2hTkzVv>E;lSMF;m{*iEZS zb1|W|%v7w>)0R_y8;|^?ecOKwM9(RD4Jslhp)cq1WioEuQEhbcxQ|e&CsaA2lAJjQ zh}vUFv9&8ZIlDRqEUj!sjV0zRXO_X_9qfoEt`4AVY$v50S=h_BC zLCZ5<%%~FO7d^w|dU|Dhia`|_S?*_GgX;u~c;+KGZ-sgTxsEBx?v$1R4F51~spa*7 z3lSia?0Fd2_{vt{zPZq~?rO%`$LS@f?z3zQ(GITP^$fTgDNfp3LXtr}h2vVvBjsT< z7emKC{OJRtHI~E@6PaCG5Nr2R=pn1Agv@SU5Sj6ew|L{TA#V8~cb9HXLH=E5EG(%D zzZzvUW0lJrN_u*>7te!b%BhO}Usmx?FTuVsKfQy=3w(*o{c}D`vaFBoR@RRkpH8Kh zou%z@s|~^Bdd;+<^YW{DQtXgbE`md2n`?QXH?ud(Wk(ef9=PgQz~e31w>K1j)JI8I zCx5dyI1s5t6&N%XU&x-d#~o`92gLRiu1NqiM5w&-@$uGi#F@H+X|{$`)?}V!eB2<{ zP}(+tq{RjO%~wfm0_OzD34Y>+gop%#DqL2!A#Pt`FI-f0XIBh{pQ2;t+YYvj0@*#>67eg+mvk7=yGI{OS4o+-qvn}3x+eIq}x{B!*2*#L+ATu(P4RHF(l~SJw}RmK4mD| zvyeY!;yY=+$#%oXuM#4)M;ViNJRNjAQM10d%U(@g_<{sbl9J1tZHa`EK{nIyYgO_L*^$mw5El6-vuNmNtkV12c6q$$Rk)ct=}gd|7Bb1s z8GzqG`}HQAV>tFEc42GhQ-|6gSZBd377n<{k>0g}FBGYnzQDrVbM-MwZ|}!}i}Zb+ zI?EN~(*sWavd@Iryx^HQ3zPJ*DR8w_pOm@eH?5}wa(qTkw~X@%%+ECsj4IL zV@}Qa3vV{YKg`;jDkq7E4fa@m@Q^W|*{i=Vp#~rcnktAf4y$^r@)U?`nvJY9dMA=& zgAcPE`x`uId@yxGZD1J*)7S}?GG8)d1lBJf?}BUPs77t)!5YW`=PDoan1!96sL`Y| z-@$amt>VAu1bU%5y=`XY86J;|#)zM-##`4t=*w&!xCOYG9u569q2E5?U}S=@=54xv zUFPMAPk6v>=nnn;%_i_O89UCFK$0}|!9MI>&9y0y5LdcCvLLN`xC@xAr(-Xj)DD^B z82#bMdVy*bcwUgPjeCkZmFI_@*#nokluz(OA~P&b-wD%+8gX1&|J6?8x%=BmPPu1a zX7p=yb*nb1R8hZ6NB`b@NR{|RBxCV9iUcx&+x5ZI$@}H2Uup ou$Y79i~V0;|DRI+kKAy0qGh>i67rSRaujy}OLH5uN)t5xU!sLnKmY&$ literal 0 HcmV?d00001 diff --git a/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/helper-text.png b/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/helper-text.png new file mode 100644 index 0000000000000000000000000000000000000000..d43f79e3747d3af33ccb033fd8eb8202fc9d40fb GIT binary patch literal 1913 zcmaKtYd8}O8-T}KCL%FslAN|)Vo}q(w&g61X(>6y6e_wW1hUGI=nM!-8 zLo&G9M`N7I`B6}5%I-hIM@|arlaktX%W3n3Ge4g>b+~o2d*@btUDO%9F`1 zH-U&rp!}M7_dsaGho;86s8hZYc^NrMyx{f36h^;*FrI=Lbi@5K?Qc?4 zy3c#?Z1~p}dD0(>MB^Z*4QxsC&oxlboOPr<&(BDFWUe<_ZxJH9oW=O(sNxM%#stUU zJ<=}u3z8_^6d>M!M+A~#2KS4q$6lhYSi(oyDqaqnxP(POA4Y6!k$Wm&zAf{>XkeI3XT49F>{S4wS5ZI|(Ip>OJnK+e78WY0zAVu!M6| z6a6y;qSUIP$&EgHRlhEYb)uteS@H79w-mzH z)gbBOwS)`2ON$lsB8|AT<)Ya8xvj>``q;4j6}7UUwjutVz-&&W8sK}cq6rPXkU|<4 zsy0g2Mk9125VlrNb>^h{RqIA?WrN{VbMfQ2cl??DdkS%Vi@m;TzD(B532l<%p|p?n z!%1AGc_&HI+ywis{krjlFWt8l);CK{r6Ggwo@WAnDIqN#tg5Ws8C(%BW_nv^c$YKOoNr zEJwmgWeVm}0^aPy;BC9KYYiJ{v;B^tkyTmlDMt0hHjcml4uBPNE^JnOtw8Ih52*+_ zgar8T;1zxWHYw8$o^uq1!AyNs@4_Eme<~Z$_-g!iaGxV1sm{{+iTA{iYa-S2sRG&`n zNWud~o7%^<_V~Oo>SU>V(G710q~7515#Z`+AzcH(-j2NUHJuQ`za7QyKulsDmkeIF z`B*$BTKm%|&z-SFrA0A^PntOnR~zv>Fm-dHkIu?VR|Q@kBZB;hKp0nOW+d>di&*Ws z*y{OeqAqu+M~j(U$H~?j307PBo0S2YmxZd%LwhUB29Q|m94+e`(!s_^{uc~j$u#wg z&s#J1U}S6Is>P0`HklgQ9qNU-=Hf<;OW~xHMti26+LZaVglth~LmdL?8~4bPCw}*w z3fC$ecRXHk0X>KR?$y+B>iwgot#o?1H>YX;z?p+d`Bio>BoK_>LpxVRRZo}UT!&!2ex^(j{K$NFv$x@Ufhr2N8O8hCEcJ} zArSlYOPIQ6U31lsi literal 0 HcmV?d00001 diff --git a/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/invalid-focus-ring.png b/packages/checkbox/test/visual/lumo/screenshots/checkbox/baseline/invalid-focus-ring.png new file mode 100644 index 0000000000000000000000000000000000000000..1ec2ce2f7cdcae027b1d20e1016c0e7a7ac62e1a GIT binary patch literal 1628 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 A5dZ)H literal 0 HcmV?d00001 diff --git a/packages/checkbox/test/visual/material/checkbox.test.js b/packages/checkbox/test/visual/material/checkbox.test.js index 5b08468025..6145dbc006 100644 --- a/packages/checkbox/test/visual/material/checkbox.test.js +++ b/packages/checkbox/test/visual/material/checkbox.test.js @@ -43,6 +43,23 @@ describe('checkbox', () => { await visualDiff(div, 'checked-focus-ring'); }); + it('required', async () => { + element.required = true; + await visualDiff(div, 'required'); + }); + + it('error message', async () => { + element.errorMessage = 'This field is required'; + element.required = true; + element.validate(); + await visualDiff(div, 'error-message'); + }); + + it('helper text', async () => { + element.helperText = 'Helper text'; + await visualDiff(div, 'helper-text'); + }); + describe('readonly', () => { beforeEach(() => { element.readonly = true; @@ -106,5 +123,10 @@ describe('checkbox', () => { element.label = ''; await visualDiff(div, 'rtl-empty'); }); + + it('required', async () => { + element.required = true; + await visualDiff(div, 'rtl-required'); + }); }); }); diff --git a/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/error-message.png b/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/error-message.png new file mode 100644 index 0000000000000000000000000000000000000000..72db53cd7bc29029c5a60abc42b014797d542877 GIT binary patch literal 2092 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 O3V^=g;q=5IB=bK``eif# literal 0 HcmV?d00001 diff --git a/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/required.png b/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/required.png new file mode 100644 index 0000000000000000000000000000000000000000..4b35b456ade7e1de3eefed934a11c900b8007638 GIT binary patch literal 1174 zcmeAS@N?(olHy`uVBq!ia0vp^?Le%T^NJ;QEd&TW5#_Jumsrdd_411J3%U*N^

>qD7HTsSpNVvc3p-m22XL z7;-Y0X8y0dywTm|X~6GgKfB}AwrgI#f8(oM!QtPN>@VG(GFkpd_2G$Z*JW;}OnWap zl`%3}VAt};c@YY6UB;{*I+rq~`|Q2=LND>+p%fRB6Z*rvy*7I(O&UgllEDRknMq^ZRXiZWZ&ZE6=L;nST3sxw0)<*8lbY&y07seQFW@ zJSl$@`<)YY&({5%XD*)@z4O;22?xpE8_xwMPSerojMJG{;QPww=IrY_m(s30Zmrlg zt98}pt&t9rZ#VnNe>G7&aqFD>oB2|c3@`7^t4&pSSzBJ}DR=I=hqstY&)g|e(>J_$ z=G^eS@i}Y5LZQT)wa0zmiRW`ZT5pk8_vHRF|9407IlIp0YhPdVY=?&9wV*TK74ly` zJojlzi_je7)Ym1)B`|S2&S~AC!*?n41>|$7br}KW%^XAQM#b1rvp9?aiUd}l- zf90>s=N@S}OmYbInTIJqv!DWM4Z|ZdzTHCPo!U5^KNmW zDT2RGGrs!rx9I|}rqWsnL2AId9&r-|qtjcHO;bp`285 zlS%TH?d~4F%+!dN6Py&5pS`fo`c%;OlGM5hp4v*6(u6jo-N~9=ZZDp^%j^ESGIiZQ_Ih9wOFe$y_u+N3eCi)>f;|O WzbLrJ{|Z>pFnGH9xvX<^$I8QCX`7>zmZ?ia!M~b zaG7WErta*US7SG?+|Vt2CH$;trzgieWtYYSuWBc8+dO_Q`1$48)7%nXnym_3K3rZV zuCOP@h0n43gkpxEC5x_7`vTV|0$Vy{n#3kLUr;LIh(eWo`rKFFp<>4A)81`|6~n{B z`>XP@v%CNPtt~4n3#(e6(ieW<=+UE#k237ow=c~?X5GJ}uOTAyuQd3-TK`mSwS>so zr^{9ad5IRT>DpOnzV_Ol6JAU8x^_eq{;7QN{r9T-@9l3F^Jbry`JWDyJaae}s2IvDD%GDd>&$DRC#(DZ|5&s4 zS;g!5pY#53-`_QP{{IsTgKM6fZ%!?mdy%{7&X%MH=Y0)o*-j}Lx;6N&;4+XowRPQ< zBk~~+N;$)%{(rogaW-%s>yslbb+awa+BJJjCEY8k<~@n{DOUR=_G_#8JMlVwyQ0Ti zWVKZna}?<6`08BdkNlEW#3L!u=3b_r=9wgM*|7PE->j7<_uQN@F{3D8X2$a=Cns&} zO_}xZ-97(P|GPgLMedf#|63eWdS?CO^?zp9KfPslEcE%?^B@O>+MYjfj?#4XmHwv{o$(V-puPS4HBZ6wyB1&0zQ()vwr%NUFVT;G z^H!}2db+J7@^+HLnyzKPZ{F$dZY?#rdvjW4d4$CN+V^+bP0l+XkKyB8!T literal 0 HcmV?d00001 diff --git a/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js b/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js index de3a9ab275..890e37d9af 100644 --- a/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js +++ b/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js @@ -26,6 +26,13 @@ registerStyles( --_focus-ring-color: var(--vaadin-focus-ring-color, var(--lumo-primary-color-50pct)); --_focus-ring-width: var(--vaadin-focus-ring-width, 2px); --_selection-color: var(--vaadin-selection-color, var(--lumo-primary-color)); + --_helper-spacing: var(--vaadin-input-field-helper-spacing, 0.4em); + --_invalid-background: var(--vaadin-input-field-invalid-background, var(--lumo-error-color-10pct)); + } + + [part='label'] { + display: flex; + position: relative; } :host([has-label]) ::slotted(label) { @@ -169,13 +176,13 @@ registerStyles( } /* Hover */ - :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):hover) [part='checkbox'] { + :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):not([invalid]):hover) [part='checkbox'] { background: var(--vaadin-checkbox-background-hover, var(--lumo-contrast-30pct)); } /* Disable hover for touch devices */ @media (pointer: coarse) { - :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):hover) [part='checkbox'] { + :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):not([invalid]):hover) [part='checkbox'] { background: var(--vaadin-checkbox-background, var(--lumo-contrast-20pct)); } } @@ -195,6 +202,90 @@ registerStyles( transform: scale(0); opacity: 0.4; } + + /* Required */ + :host([required]) [part='required-indicator'] { + position: relative; + right: var(--lumo-space-xs); + align-self: center; + } + + :host([required][dir='rtl']) [part='required-indicator'] { + right: auto; + left: var(--lumo-space-xs); + } + + :host([required]) [part='required-indicator']::after { + content: var(--lumo-required-field-indicator, '\\2022'); + transition: opacity 0.2s; + color: var(--lumo-required-field-indicator-color, var(--lumo-primary-text-color)); + width: 1em; + text-align: center; + } + + /* Invalid */ + :host([invalid]) [part='checkbox'] { + background: var(--_invalid-background); + } + + :host([invalid][focus-ring]) { + --_focus-ring-color: var(--lumo-error-color-50pct); + } + + :host([invalid]) [part='required-indicator']::after { + color: var(--lumo-required-field-indicator-color, var(--lumo-error-text-color)); + } + + /* Error message */ + [part='error-message'] { + font-size: var(--vaadin-input-field-error-font-size, var(--lumo-font-size-xs)); + line-height: var(--lumo-line-height-xs); + font-weight: var(--vaadin-input-field-error-font-weight, 400); + color: var(--vaadin-input-field-error-color, var(--lumo-error-text-color)); + will-change: max-height; + transition: 0.4s max-height; + max-height: 5em; + padding-inline-start: var(--lumo-space-xs); + } + + :host([has-error-message]) [part='error-message']::before, + :host([has-error-message]) [part='error-message']::after { + content: ''; + display: block; + height: 0.4em; + } + + :host(:not([invalid])) [part='error-message'] { + max-height: 0; + overflow: hidden; + } + + /* Helper */ + :host([has-helper]) [part='helper-text']::before { + content: ''; + display: block; + height: var(--_helper-spacing); + } + + [part='helper-text'] { + display: block; + color: var(--vaadin-input-field-helper-color, var(--lumo-secondary-text-color)); + font-size: var(--vaadin-input-field-helper-font-size, var(--lumo-font-size-xs)); + line-height: var(--lumo-line-height-xs); + font-weight: var(--vaadin-input-field-helper-font-weight, 400); + margin-left: calc(var(--lumo-border-radius-m) / 4); + transition: color 0.2s; + padding-inline-start: var(--lumo-space-xs); + } + + :host(:hover:not([readonly])) [part='helper-text'] { + color: var(--lumo-body-text-color); + } + + :host([disabled]) [part='helper-text'] { + color: var(--lumo-disabled-text-color); + -webkit-text-fill-color: var(--lumo-disabled-text-color); + } `, { moduleId: 'lumo-checkbox' }, ); diff --git a/packages/checkbox/theme/material/vaadin-checkbox-styles.js b/packages/checkbox/theme/material/vaadin-checkbox-styles.js index 05b4e4eb18..baf7caa540 100644 --- a/packages/checkbox/theme/material/vaadin-checkbox-styles.js +++ b/packages/checkbox/theme/material/vaadin-checkbox-styles.js @@ -15,6 +15,11 @@ registerStyles( --_checkbox-size: var(--vaadin-checkbox-size, 16px); } + [part='label'] { + display: flex; + position: relative; + } + :host([has-label]) ::slotted(label) { padding: 3px 12px 3px 6px; } @@ -128,6 +133,50 @@ registerStyles( :host([dir='rtl'][has-label]) ::slotted(label) { padding: 3px 6px 3px 12px; } + + /* Required */ + :host([required]) [part='required-indicator'] { + position: relative; + right: 9px; + color: var(--material-error-text-color); + align-self: center; + } + + :host([dir='rtl'][required]) [part='required-indicator'] { + right: auto; + left: 9px; + } + + :host([required]) [part='required-indicator']::after { + content: '*'; + } + + [part='error-message'] { + font-size: 0.75em; + line-height: 1; + padding-left: 6px; + color: var(--material-error-text-color); + } + + :host([has-error-message]) [part='error-message']::before { + content: ''; + display: block; + height: 6px; + } + + /* Helper */ + [part='helper-text'] { + font-size: 0.75rem; + line-height: 1; + padding-left: 6px; + color: var(--material-secondary-text-color); + } + + :host([has-helper]) [part='helper-text']::before { + content: ''; + display: block; + height: 6px; + } `, { moduleId: 'material-checkbox' }, ); From e593ec8b901cef57ff0128e0e964000c1115c19d Mon Sep 17 00:00:00 2001 From: web-padawan Date: Thu, 28 Mar 2024 12:07:53 +0200 Subject: [PATCH 02/16] fix: do not set active attribute on helper or error click --- packages/checkbox/src/vaadin-checkbox-mixin.js | 10 ++++++++-- packages/checkbox/test/checkbox.common.js | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/checkbox/src/vaadin-checkbox-mixin.js b/packages/checkbox/src/vaadin-checkbox-mixin.js index 17b92968d9..f07e0259a8 100644 --- a/packages/checkbox/src/vaadin-checkbox-mixin.js +++ b/packages/checkbox/src/vaadin-checkbox-mixin.js @@ -120,7 +120,8 @@ export const CheckboxMixin = (superclass) => /** * Override method inherited from `ActiveMixin` to prevent setting `active` - * attribute when readonly or when clicking a link placed inside the label. + * attribute when readonly, or when clicking a link placed inside the label, + * or when clicking slotted helper or error message element. * * @param {Event} event * @return {boolean} @@ -128,7 +129,12 @@ export const CheckboxMixin = (superclass) => * @override */ _shouldSetActive(event) { - if (this.readonly || event.target.localName === 'a') { + if ( + this.readonly || + event.target.localName === 'a' || + event.target === this._helperNode || + event.target === this._errorNode + ) { return false; } diff --git a/packages/checkbox/test/checkbox.common.js b/packages/checkbox/test/checkbox.common.js index 62cab3a762..ba617a6cb0 100644 --- a/packages/checkbox/test/checkbox.common.js +++ b/packages/checkbox/test/checkbox.common.js @@ -1,5 +1,5 @@ import { expect } from '@esm-bundle/chai'; -import { fixtureSync, mousedown, mouseup, nextRender, nextUpdate } from '@vaadin/testing-helpers'; +import { fixtureSync, mousedown, mouseup, nextFrame, nextRender, nextUpdate } from '@vaadin/testing-helpers'; import { resetMouse, sendKeys, sendMouse } from '@web/test-runner-commands'; import sinon from 'sinon'; @@ -210,6 +210,21 @@ describe('checkbox', () => { await sendKeys({ up: 'Space' }); expect(checkbox.hasAttribute('active')).to.be.false; }); + + it('should not set active attribute on helper element click', async () => { + checkbox.helperText = 'Helper'; + await nextFrame(); + mousedown(checkbox.querySelector('[slot="helper"]')); + expect(checkbox.hasAttribute('active')).to.be.false; + }); + + it('should not set active attribute on error message element click', async () => { + checkbox.errorMessage = 'Error'; + checkbox.invalid = true; + await nextFrame(); + mousedown(checkbox.querySelector('[slot="error-message"]')); + expect(checkbox.hasAttribute('active')).to.be.false; + }); }); describe('change event', () => { From c83e5bbbcc624ec51c6ee2afba8c5425e87d98a8 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Thu, 28 Mar 2024 12:29:43 +0200 Subject: [PATCH 03/16] test: update Material focus-ring screenshots --- .../checkbox-group/baseline/label-focused.png | Bin 2026 -> 2155 bytes .../checkbox/baseline/checked-focus-ring.png | Bin 1750 -> 1961 bytes .../checkbox/baseline/focus-ring.png | Bin 1551 -> 1745 bytes .../baseline/readonly-checked-focus-ring.png | Bin 1752 -> 1950 bytes .../baseline/checkbox-focused.png | Bin 5670 -> 5828 bytes .../baseline/checkbox-group-focused.png | Bin 8373 -> 8739 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/checkbox-group/test/visual/material/screenshots/checkbox-group/baseline/label-focused.png b/packages/checkbox-group/test/visual/material/screenshots/checkbox-group/baseline/label-focused.png index 149ad86b463f9b73d1bc722d81bba230646507e8..3b4f1c0e6d1ec542be604edf7f580e47256d3869 100644 GIT binary patch literal 2155 zcmbUj_ct2~H=Z3eN>t2P6{S@g#4L$udG>CpBE%{&f?Bb~Y-_col#2I^mkJf5r&dwa zv!X$$^*l8yC?8exdHLb{2fpu|JI+1#+C!G+ZE)My7F z1%T8OLFzxmYiz)~@65mCKiS zZoQw=ZX|haKhKYpK2=gIUQ_pwimdDu^)C^g*iV0P;}04Y-FH)Kr+Y`xy16Z|o{;xI zb3}Gtr%~OHz`Kx=+iRita*{(4qZY zxr&K0&XDwgqK{E4^6>|-iHc}XHznw= zo^|ar{I&FuSns1oHWcZyBAin>Te?(R66{^8zs&K%yS>azrQ}94IJ|as3I-bxdN#P{ z6~LMJ&!IG_VR2>Yn`YNPpOYO`IFs;~Vt@gySw8Z~{t==VTW3jxC6w(xnWOyTM-7mMXg?lEMa_Kss&1%129A;%2CCKy`J-xcSv@IF$ko>*tkKT63 zbQraiO^9~lpp|fuQ{R7aT$UST!$8Xtpy^ofm+YxXU>zHxZ8KM+?9wN@0a zaMijgDk>VPBPGPqlXqU&hoGzXeUfE2md`gfkbwtXd<~sx^YhJ>lX#LK#Vt7=*g|S* zDv0$jD8|RFp}E8X_H`iAg#W}Bh4@+6NHz(i^+~+W5tvPik2OU`&1j7b`Fy5n{HI1y zm{+mToc;y6dJQ^~tML)70Sg=w&gnPyNHab7#EZK&s#0WsG@$z=`Vc`^vN$dnmO46l$0C^bk!otFrjHUVc$%Q*|GPmPv zPgA**T3WO$EiJ*ec3#o?<>$4AIK5YQ^j=MOR9+tjB$dKLHUk^GyFD0!h-$T*eo`y* z=jjBU&R#KILk_+%Jv|Kow1q59x43(FRIJe~ZEUKls=OH(D=RA=u2dmYJD1bAYXf^* zMaQ|l%j$sFRH_IZJO5#0LwW3#{$tO<*1|6^v3BlB@3`RQP%sNv<`{j*_Wp5WV`I|T zm^DW#!mNP9ynrPF+UA}-Vo(qTiqzo|3uRCWgW3OF)n#&Jb8{0J7pFfkILIID#!nR& zGi&~HvRWBlpyt9mi=8>1>Y3Bi6&HH5 zD|?>){yf;WIojcrI#V1Ca;t7VK8|s8a;obl4ezmEfb2kaZf-e@29HwrZ0s``Lu7F9 zjh8Q9hQG)nWy1W%YWo}%icCvjbew~OgMUy^+Tcph@&5YW)-1J2I&cfa@=hj`{R09t z+ClC<_XkEsF3n@%57ZbGrY0QTx3ULzPL)`*FCWL`vQk9JUoN|imjKXaW-^zTy++2z zOCPvS`rRD=XrI`(CXT zfL{wZ8W?;Hj2!*PJ0-LQXpZjKKC zhCuFGSXj&+(A0|gux*kdiyesTS5!CCDY;D>#Ny)OJktRPi<>u$-yW3>mf~K&uvlGg%ia98Qkm_KR zi3$5th!HkQ_x(})?W6Mq7Nj97-(ZM|l3|sqCept5>Zc3ZGmfUnE*nf{-*E9w4Q*{g z+|Ql53-N4{tPqc9bTk<77b~6@#ZB8TfQ*a`9KkxF+d~>#RJyqMP*Yo*R8^(Gd>1ul zD2d>wjymt|dkV~Fi9kay{=rM>hAXbaS(}8C6*86;Qm=b|b{yZ;)Y)5;et)n=X$JlF z1NyChc?g9<88|u7J2^d#guA-9)Wj@Uy7$Xx%lq8F!x%JG5GccO8XP!gRXep20=TJDXZ0z|6Mg7!@wjB!jmWbFy>I$!Nx>E zd4SyS3S_@49Bcv^eQ#XDX%0^_Wpq;~?0IeL&OP%#w=s#&#a%*veamJ4Fp8hLfQ7fX zMCeGF8to~phK%dp%;;kyPq~h`0)j?sX}c+3y_b0B(MBI_g*Y6Yov+jz_KI1J`#FR9 zch>`Ewhs+MHkD9(qc&qUN`(Z&*5TFg2`~|4i7QF2H>%GbT;Yx~v0p<`9ly^gteU!% zz<}qjJSShc(P2Ul@jvCMCd`LCmv9q&odS br}PZsK4D#NARJ`C`W^u0rq(D5(lg~>s+a^h literal 2026 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 delta 1722 zcmV;r21WU)57rHkFn+hAv>nU;qBJQYCqck=>EVC^IiQ1t zTXJZ(4AdxX=}kt_;Vyi5=OJ z$k%}sE!nbfrz9caCfv=6~) zOPn@1Z7)q->>h%}Ww^8|5V5(<4Pq3x?>cbstK?|krE@e~*~MkS(kiT8QBc%jTaJm6 zp~QC`ICv^~u`7}8c%gz&1S?6w>MJ5Pf*BD?{3t~~)q%hWKv6}cb;q1fDDn3myEJzv zyC_H`1(&bK0e`_XIahq?!qfk{w42je4K5}GuiR4Npm0i@JIvD*9-!Tn{Q8qSwe~JL zXNte~c)G%OX}yr_J&p}v8VnS_xhE%njX#g(uB5pa-*}ufr^I(1c=pTe2maYF64#k^ zFJ5j=iU0hG8~Ji>6r?NJ--+G-B!=f9u8k zc%qk$K>SWi;lgzB+39 z{1S-Y9`ey_SQ1IWhhMMr{y*2as*QH-{`rdn`Kpd-SIDJ~&!=(~q-FU3r71`YV_*&A zkRn&HG4)Z?=a)bYw-f!fwJZGXJ1U>Qd%#Y8lz*k$50u~g5{yEh@B!)jnAC~d(O(1t z@tteZTXS8SOf4slMNB`a+kvuLRneag;hudvd z&3|vQ#RH_YG4(3>hrI#eHh2A)LE0v@OxHNPm;uX6vrV09ev3i+*S3r3rtQ^HNFOH@ zGi=}W%3B5$gSx%Apq%r|NE=fxk`X0pq{vmg{Gg+0plLc_U`a`D^-&Xyst}=<_@}si zN9Dt>*ZJg6&jBJ8eiU@mrs7{Cw4T9hlz&SUse(8W7H&7VONpXkA^rTRTm_jsS#zCo zHbcE2sSFauumZ8t1q-8?p}gH7r#&QJHLxmO|CA#4z@%Kwvt28YPD8pNu@Gc71sE1m zPEd89VCD;TH0i&4*y8hd54e3trSQ!NDj{^m{IrbD$}AHOc}2UhkSm0XH?J%2>F zUd)rPLUB8cFV@ifAh1y%kUyo725R+V*OD&y0c&xaX)GE8@zsUVw@`Hr;MSWex896+ z#=m-x_x|cYu{6*HdoHyUez0nTgF{Wz&rAz2ETnCs7c(L5CDf@`A+4oIX=$LyAe%{R zU2ow14$by23EA?*gV;cPWeoAbGk<_@KRe>v&yFH@^>6*9fl#K{>kx4+?~F zlBrw)qnc;4H;QVMDc2x%H-}!$v(?)`t#mrzO690n#^89M$9QU`3`O1Kej0B@qC+ur zY^05H={P<39TjpZf9Xh`%}E=8^x5BWrTwTA`uH_3ug9--O^Uv0r7pngmHBb8t5@PzxhBaepSm(9uT3ecVD;+k`|&b!N_<5TY+RrH zpl@6kh}n1JrDk9>wY)A^yE?l-YwfDS@_MZNq&ZXJwQGWoS_=AQooWz;qxVB@;N%H>%2X*1Mk zS)8{2g^s-lj6gtQ!wW3c(Kq(SjKN4BWO6!^gQuQ181`u QkN^Mx07*qoM6N<$f(@5$!vFvP diff --git a/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/focus-ring.png b/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/focus-ring.png index 744278d6499329f1eb996223ab8043ce4f709b9e..7bab3d4815aa1ee54e3f09bd65c371305701eb9b 100644 GIT binary patch delta 1717 zcmV;m21@yl4ABjcFnczuA57Coo#|DF*M-|eGGQpE#@2Q}$UhPD>i-8@6>}Kj=^dj!iZptKS+NJOBuwPyl z+s&l*PqyU)IrM$ryzkq5-{;NqzIhXd5JKQ`Dq)A+0GHw6{eRa22qDmQ9eaCwXti1( zgrL=G0RUK*1;a34Sr%Te7aorX48#0$qg{Ff)6K9?2tlLKK(pDTLR-b-@xbf#Vq|2* z?Fd80miUAaXqtvbqtTPfM@B~A_xs&WFeEIA-)qtT#O(yb!BW82PvHTe(P%)^w7!+^ z(wQSYpAZ5?QGcN8`al}v@pupn2Hg>0Kpg4$gA^VBbX|v{CC#`?#3zJ6Rn=j%#e}M=a95uDOPlykin^WDmXnA{ zd}HO#DKr`l*Zcd3X>H$5p!N0ZSFEnC;>V94wkkY-{(n4f-MWR#moHn&uW1_2oH=8w z4i{^fJl{@q|KY<2+rk6D&dv^2S640P-`m@>U5AS`sOPs@En5$1c6N3E0NHHTR)v{N z##W~>+QqUgBuT>c>({AG6h$PHNfZhNJbLs9wOS24&*Q;^2jF?$R=bWuRaKiJIgu-)BV%+AhYetsUZEQ1h2V}WoujIFILD*VdIN>A%Hgw5r0UD=%s z_55Kh=vbvtC}3@E4e#E)!}$0(P3L(Y9LJ$lDj^gKA)n9p)Z+ml5D4Jq%a>i-oecGS zyU*nZ#rF0#-oAZ{nVA`r@CNaC92YKJaKzfgaeu?{;(z=04WB-JLNprfXb%Jec>MS= z0)c=jJ)h5mVHiwKPNG~c)AU-chGa4chGD=k3?xZ9)RxcZJJu;l63z2x%#+P#JC?1g zDrRSAsV$jIqE@T5rAv}@Xc@hRihq*k)A#S+2eAKO>e{tyc>n%AfPHZn7Z;Jw=RpX8 zEPu-o1Oer8nZ^v6Oa_Dyh@yz4r6p6xF({Qv5JeG$5L1BnQxRu~~W@ZKx z6BF3n+(fZhL?{&M+cg4?f%u_N2v@FL!RF>>Ps$SnfzB3;gXeim-+cb9fQMYGDp2C=?3RCP`9Tz%@QTj#sZ2!ZP0QnzH)5x!1zbqdM3x5k_VPV16 zIo+P8X&NDf5J3wMr6+1ht8xXv&{TrHG;^M3!X|i^bZ~2_YSA z+uPeDl}gbxK@iC2&!6e z+-Zy`x0~f%yXT!fd)Cn-(|>V=uJExe3zlUq&-X`1NAdIL&#u<8FJ8Q8Ij_+!m)>K# zs$Q@4x3_NJzHLiHgVE7Z+`M_ya(I^?Ex00000 LNkvXXu0mjfq*+v- delta 1521 zcmVl*O6vux@NmgtmfHPHE3ar)fS00xI2c8df&2&=19YH92`G@!0y>aDKR{LuEvU^264;_->UEIBNVepVwk0t( ze*g#Zj(1P|zk7T~9;rk`$a#=x+cqF)dlYZmfQS%95f>L1jDN>tM1=8p41lI-D5cOe zjbgD#p-@06b!($@?gn*}urDGEheJlAQ7m*)3WWm2Vv(Jlo!k+&Oe*n3gfI*l4u^Nr z`OeM`<#IW9f-R9q{JR$YGPx6MheQeAI)w)q4u^zcxVH9lmUHdM7ZJ|R&WNIDBgPa8 z1@`v#@(8dYu74f*n-m@(iXzU=&NkNHLuaMFFsaCnt&PUtC#<=G_`Kkak*&G8R^{`42vO_oOT+RwQ3=x^MvZ=dXo|Igq24j8(= zqCy3;X>!>w`mF<$QYdvmYr!*o9HpjZ3ddhvc7M=X;ZnX6*HMcN;5)0@?oTdVar+Mb zlKqZUR5)$&ow495(BLI7boqv zoG<0^|7c@Yrc*~6RM+hQG9?T{`S|f;;_c|@NREzB$#M!>4X=s|3c)q{Czt4vcA7U}n zP_0%I*PYpwbN4Kq)nYOE+gq<*y-FqGjQ#z6Uc7jbxPGZrO5I0JG8UF@i+>28K7HDz zJy&@0+xm@0sEmz3j;#n_OE~Z&I;aPLU`^eHvDhtb|vS7n~XQ}w5 zQfaHBu3RqXiQWcSIfp8j%M=QQP1*uXW*m9A-wfAIpf~-}q*98#y}ga~_s~i7e*R!E zSo?bZQmMr5?(SOq$XO)umufjiqtV)4{h$Ci@~ZY_S!w@ZGpeZc$= X%aRqf$*d?Z00000NkvXXu0mjf+*Jw2 diff --git a/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/readonly-checked-focus-ring.png b/packages/checkbox/test/visual/material/screenshots/checkbox/baseline/readonly-checked-focus-ring.png index aa8c7a340630b8fe5b8a982229f08fb33f478387..4370989cb413cf9870c24a9557355d789a0b81cc 100644 GIT binary patch delta 1923 zcmV-}2YmS04W18>Fn7gakqZ*omp0&_GD24<=NpA`zcqw@3N~C7j#^`>B zd^>1OTL0_!xj)EdW}SDk&->22GdsJKD2gIvh7!8p9gyiC%71nn5JeHk$HzE1IYGHx zM!8%@rBVR^&@>H&LIH(B0i{xjk&zKl6xDX8WjX`Z%CKLlR3Hcf5xp5yDiuaXMld=$ z3YwM&o_^Al_>$;?AfVk;fubld3U28TY&KXdmVaI=?Ez@D+NNyCG)7J2H?vQlNFIW4f{_*i~*NiX>gBv$)wEX*gJ`bnUiKV3_q*5t}qDZDEgTa7o zHVcm9;BYvQNF+MdZ2+gjx?C;S2N^QwH~VO|Q5c57^71mKrl#QWc#zBGnrT2Ob zp-@Z0=W;oG`0xR9b8|JqOIWQ|T)A>ZUKX}M&79v!{uF+9cekZ>zJLFY&!0cTWHOy= zXK`^648zovMQZD5MQr?hECeN)qFL$WUJ^q~MeLmlrZA*E9RA;x_ z!GCdFU3oH@JhzQb({|+FzI_|dpFgj;`JEEJRp#gC0h~UHzH{deK7RZN;8fg|l@&xH z5s0FQR4N6p*Nb#IO>zde+YM0^5e|pp_xo!cM`Ckx6X9?eqA0@cc9U|C$Aj6~S%{(t zuh)yEr6r`(X_6P*yLXQ)Us;xg!{GqW^M6=dTZ7l@#m$>HVK5kAGMQkr+3@q{Pt45B zbnQM7@!NTfIyE(g<>h5^GN+%y13)+&hQr|i!!VefoFwJ(cpSlC5C($*6h*;evEb9E zPuSbrLp&bG%*+hA*$#&T`}_MfQ_Zhmzu26nq0z-e%}TrOm@S)@`a0D#-=#@yT-EEWq64h|5H$D!BjyLOL&s)UcG>6W5j z68FiICvdr30Dy^!iH-?BK0c1?*RSK?;GpfcfK!30qgA4jWt!jb2LMb?PX03@H5v_A zmIVN0GMT!1gTVl!(TGeYQ{ynnWPcLLWD*?5bzOWC`R$ye+uhwoC=|lP#6(Ah2Y{^BjN+64zRtwjqUC2j(-pJi;Ige z8jX1T_;HN`2!eps)m1!t^r)dIvD@v)WHNaD`ZXy_r_ZB;F z#%wm@?c29!<^$Ev^X}a{uq+F!)e5WCil;MZ{EB?G#Vvs1Ofq=&1RU*W^8P1!0-2yx=<*DYuB!kO&pKML#Bss z-@d_OvA}M(gXei7SoJ~FwY4>p2L%EFuq;dRjW1um)QIf&`w<8PAb$t~VzC&4!61Uc zARaz^*zl;7e3z)1=to9I8vdcpW@}1B37t-d`}glRe0?*0l4*{bquZ5A1-V>qAWrfC zr+W{2ya!Z3_1d>5%(-)S_Ofp~Y0rfFz2ntpfV|C&0LDT*41 zV^dnKR*w2Eb7qLE)#|=RokpX9TCMJz{bAwU@qKJ;tS_0iTCK*|*jUf)4kLe^+%I0d z*wZz(LZQHg3m1B3Z`f(*{rp0q(DjE548sgWt}#qB{AG?}v3!U^q0p6&GibG1jE;_W zv|X8h)6{2K%H=Y7iLw))Wswp~dHc3MwERIPp66R~0{L4!gF{Q=S95Z5g5SS?qf{zE z6h%}j72*&SMS-SiP!t7~N(HrA-H}JfGM%Aq@n!yZk;mO3=0Ayuj@K?6^Z)<=002ov JPDHLkV1lfVvYh|` delta 1724 zcmV;t21EIt57-TmFnB8(8i$|a(~X%K#gb;H#+QS{hEMdRj@6&F#ZPA?&3LTqhq;q!TcXO%b- ze<*sp-DciYK?s4OC@6~Jb%GT!mH2Lo{-6PaP7sMiyeVPHOf}?Mtro3T%XQ(w${AX% z7T4F;uG{u_ntvxpzLb)yt1G(Q?ot{P3i=F2y}+e^YoMzLat;Mqabov^R@9 z7Q+MaudlBclGQs!O1aYLvk8oe-|zR=D%`f)ZEy51kbkkgeJ7*->({TGo}SWZG#ojM z#bWI5@AK-_t3Rzf+yjV4qmF!dOvl*Bcd}3a<;xex!UJ4hUUGVRI(7Y3tT;9WTl`+H z=Scj^%gdRaI_WgSUkd>+3kV_XPqx$mObP{aP}`(nA9s@mrK~{Mew>!CC${)EH#ZA& zq9_WlUw^-z`TU!kKdg(JHYwI6Qd*x+93VuR9AF7Q{M$_$l(KR3%BpJt~; zQ4|gj4|(_Q9XmTaGuilG>0juT48?jGO}#s=YGq_KKlqlykX7;%EzE<8R<2Xb%v!#_ z*y1lDs~!rUNF+EuKIY=$Vg@U}^XotV19@Xicz>JJPZX))cA(z`#^!uCxi9?r`T1;y ze*cXRKqi@dq=JfOXx#4?jZ$`y8)O+z0j#`Wm^X}1)8l22<_@E|$Gv&pEIej=kQdnY z3z!p*7tE(@xXaul|IM2>7>0qODE2YegrAX$9_N5hNLi6_H^>=ey@;6} zc7F~lXP|18)r%P_`T>*lH&1e8ign9|k-96$r8(KN&adVnXWO>&f|52kN7gB3a->B8 z6BVs&)rSnpBqWm=AWv0FM$Nm8z0Max%)GOgNF+EsJmllYj{qwb9w1Y!Qy$C_$&riK zC>6+20dX%aJZZ2;fn2_d9Mo5}GE%#5xqn6}o2F(+%9BLNS8cIUMwNUnP3fe8miz_1 zlBZf8#wQi+Q;||d=fpHfr66TUstD3?0r@IYE>QIW_Q;?0R;u&!bB>RXNhA^+9UXCW zbmXq^-+jjqK&4ij-xdrmtQ`B4HI-UzigZ1vqgNnzGEFQ_k{l#~joO6zYLXOS)_?9o zOUf7|thp1Gv1puIe7NfXySuyW?(Vuf;{Wj@|9%hT3KK)H6;cb+Uo3NSa+pkJ9xb!U zSCRE1nOu5`y@VRI3Z#-MYBB}nnAB%d$ze3G{*PpRFePM53r}KQ5g)7$aCUaa+1Z)v zq5jR!|0PcaJ$^rVYf#D_z$b%gf`6o{8RRQE@zE@*QKDpmx~Gw;=p2kXFbfY8E>)vk z%}>q;MmmpKNR!JH`6-39BFR85eb-4FrNUjg{eP6v)WOmbo%n(~fIa620(0NO&*#sd z=e9A4K;U}}DcLJnbE0mSjIRAhHhJ_oS?UxWO( zOiL^lo7t(VPTH-ROdt^OgnwTUV-tNS6q@?P{r!DMA`XegV!VC(cIx_0+T`Jkv0JzM z{XQ2L7i)1R4_JE-FJHd&ZslGOV%8fJbWQ>)dQsS|kb;#nVN5`UE2 z+grYU`$o6hMM_D(-!->8gb)Is&xa6#U@%BH9CqcWV-I(jTYQhdE?(T-VEzw>$tAU% S2sBLq0000jnVEZ^I6YkrN^)j$002O#rKt|Z%K`k^NlJ{r zy8re(#0#JgR6`X|HOjgT05F7UsjC!$>bs>zJ2UwY{`ro3RfHW2X