@vaadin/checkbox 24.4.0-alpha8 → 24.4.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,6 @@ An input field representing a binary choice.
5
5
  [Documentation + Live Demo ↗](https://vaadin.com/docs/latest/components/checkbox)
6
6
 
7
7
  [![npm version](https://badgen.net/npm/v/@vaadin/checkbox)](https://www.npmjs.com/package/@vaadin/checkbox)
8
- [![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)
9
8
 
10
9
  ```html
11
10
  <vaadin-checkbox label="Checked" checked></vaadin-checkbox>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/checkbox",
3
- "version": "24.4.0-alpha8",
3
+ "version": "24.4.0-beta1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -37,12 +37,12 @@
37
37
  "dependencies": {
38
38
  "@open-wc/dedupe-mixin": "^1.3.0",
39
39
  "@polymer/polymer": "^3.0.0",
40
- "@vaadin/a11y-base": "24.4.0-alpha8",
41
- "@vaadin/component-base": "24.4.0-alpha8",
42
- "@vaadin/field-base": "24.4.0-alpha8",
43
- "@vaadin/vaadin-lumo-styles": "24.4.0-alpha8",
44
- "@vaadin/vaadin-material-styles": "24.4.0-alpha8",
45
- "@vaadin/vaadin-themable-mixin": "24.4.0-alpha8",
40
+ "@vaadin/a11y-base": "24.4.0-beta1",
41
+ "@vaadin/component-base": "24.4.0-beta1",
42
+ "@vaadin/field-base": "24.4.0-beta1",
43
+ "@vaadin/vaadin-lumo-styles": "24.4.0-beta1",
44
+ "@vaadin/vaadin-material-styles": "24.4.0-beta1",
45
+ "@vaadin/vaadin-themable-mixin": "24.4.0-beta1",
46
46
  "lit": "^3.0.0"
47
47
  },
48
48
  "devDependencies": {
@@ -54,5 +54,5 @@
54
54
  "web-types.json",
55
55
  "web-types.lit.json"
56
56
  ],
57
- "gitHead": "a26ec541cd39218eb2af1fe5f627c9ddd9f2df69"
57
+ "gitHead": "504787f741d677467ae93ca7cd31d84489366a9c"
58
58
  }
@@ -12,8 +12,10 @@ import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js
12
12
  import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
13
13
  import type { DelegateStateMixinClass } from '@vaadin/component-base/src/delegate-state-mixin.js';
14
14
  import type { CheckedMixinClass } from '@vaadin/field-base/src/checked-mixin.js';
15
+ import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
15
16
  import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
16
17
  import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
18
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
17
19
 
18
20
  /**
19
21
  * A mixin providing common checkbox functionality.
@@ -27,10 +29,12 @@ export declare function CheckboxMixin<T extends Constructor<HTMLElement>>(
27
29
  Constructor<DelegateFocusMixinClass> &
28
30
  Constructor<DelegateStateMixinClass> &
29
31
  Constructor<DisabledMixinClass> &
32
+ Constructor<FieldMixinClass> &
30
33
  Constructor<FocusMixinClass> &
31
34
  Constructor<InputMixinClass> &
32
35
  Constructor<KeyboardMixinClass> &
33
36
  Constructor<LabelMixinClass> &
37
+ Constructor<ValidateMixinClass> &
34
38
  T;
35
39
 
36
40
  export declare class CheckboxMixinClass {
@@ -47,4 +51,12 @@ export declare class CheckboxMixinClass {
47
51
  * The name of the checkbox.
48
52
  */
49
53
  name: string;
54
+
55
+ /**
56
+ * When true, the user cannot modify the value of the checkbox.
57
+ * The difference between `disabled` and `readonly` is that the
58
+ * read-only checkbox remains focusable, is announced by screen
59
+ * readers and its value can be submitted as part of the form.
60
+ */
61
+ readonly: boolean;
50
62
  }
@@ -6,8 +6,8 @@
6
6
  import { ActiveMixin } from '@vaadin/a11y-base/src/active-mixin.js';
7
7
  import { DelegateFocusMixin } from '@vaadin/a11y-base/src/delegate-focus-mixin.js';
8
8
  import { CheckedMixin } from '@vaadin/field-base/src/checked-mixin.js';
9
+ import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
9
10
  import { InputController } from '@vaadin/field-base/src/input-controller.js';
10
- import { LabelMixin } from '@vaadin/field-base/src/label-mixin.js';
11
11
  import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-controller.js';
12
12
 
13
13
  /**
@@ -17,10 +17,10 @@ import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-c
17
17
  * @mixes ActiveMixin
18
18
  * @mixes CheckedMixin
19
19
  * @mixes DelegateFocusMixin
20
- * @mixes LabelMixin
20
+ * @mixes FieldMixin
21
21
  */
22
22
  export const CheckboxMixin = (superclass) =>
23
- class CheckboxMixinClass extends LabelMixin(CheckedMixin(DelegateFocusMixin(ActiveMixin(superclass)))) {
23
+ class CheckboxMixinClass extends FieldMixin(CheckedMixin(DelegateFocusMixin(ActiveMixin(superclass)))) {
24
24
  static get properties() {
25
25
  return {
26
26
  /**
@@ -49,6 +49,18 @@ export const CheckboxMixin = (superclass) =>
49
49
  value: '',
50
50
  },
51
51
 
52
+ /**
53
+ * When true, the user cannot modify the value of the checkbox.
54
+ * The difference between `disabled` and `readonly` is that the
55
+ * read-only checkbox remains focusable, is announced by screen
56
+ * readers and its value can be submitted as part of the form.
57
+ */
58
+ readonly: {
59
+ type: Boolean,
60
+ value: false,
61
+ reflectToAttribute: true,
62
+ },
63
+
52
64
  /**
53
65
  * Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
54
66
  *
@@ -63,6 +75,10 @@ export const CheckboxMixin = (superclass) =>
63
75
  };
64
76
  }
65
77
 
78
+ static get observers() {
79
+ return ['__readonlyChanged(readonly, inputElement)'];
80
+ }
81
+
66
82
  /** @override */
67
83
  static get delegateProps() {
68
84
  return [...super.delegateProps, 'indeterminate'];
@@ -70,7 +86,7 @@ export const CheckboxMixin = (superclass) =>
70
86
 
71
87
  /** @override */
72
88
  static get delegateAttrs() {
73
- return [...super.delegateAttrs, 'name'];
89
+ return [...super.delegateAttrs, 'name', 'invalid'];
74
90
  }
75
91
 
76
92
  constructor() {
@@ -78,6 +94,8 @@ export const CheckboxMixin = (superclass) =>
78
94
 
79
95
  this._setType('checkbox');
80
96
 
97
+ this._boundOnInputClick = this._onInputClick.bind(this);
98
+
81
99
  // Set the string "on" as the default value for the checkbox following the HTML specification:
82
100
  // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
83
101
  this.value = 'on';
@@ -96,11 +114,14 @@ export const CheckboxMixin = (superclass) =>
96
114
  }),
97
115
  );
98
116
  this.addController(new LabelledInputController(this.inputElement, this._labelController));
117
+
118
+ this._createMethodObserver('_checkedChanged(checked)');
99
119
  }
100
120
 
101
121
  /**
102
- * Override method inherited from `ActiveMixin` to prevent setting
103
- * `active` attribute when clicking a link placed inside the label.
122
+ * Override method inherited from `ActiveMixin` to prevent setting `active`
123
+ * attribute when readonly, or when clicking a link placed inside the label,
124
+ * or when clicking slotted helper or error message element.
104
125
  *
105
126
  * @param {Event} event
106
127
  * @return {boolean}
@@ -108,13 +129,64 @@ export const CheckboxMixin = (superclass) =>
108
129
  * @override
109
130
  */
110
131
  _shouldSetActive(event) {
111
- if (event.target.localName === 'a') {
132
+ if (
133
+ this.readonly ||
134
+ event.target.localName === 'a' ||
135
+ event.target === this._helperNode ||
136
+ event.target === this._errorNode
137
+ ) {
112
138
  return false;
113
139
  }
114
140
 
115
141
  return super._shouldSetActive(event);
116
142
  }
117
143
 
144
+ /**
145
+ * Override method inherited from `InputMixin`.
146
+ * @param {!HTMLElement} input
147
+ * @protected
148
+ * @override
149
+ */
150
+ _addInputListeners(input) {
151
+ super._addInputListeners(input);
152
+
153
+ input.addEventListener('click', this._boundOnInputClick);
154
+ }
155
+
156
+ /**
157
+ * Override method inherited from `InputMixin`.
158
+ * @param {!HTMLElement} input
159
+ * @protected
160
+ * @override
161
+ */
162
+ _removeInputListeners(input) {
163
+ super._removeInputListeners(input);
164
+
165
+ input.removeEventListener('click', this._boundOnInputClick);
166
+ }
167
+
168
+ /** @private */
169
+ _onInputClick(event) {
170
+ // Prevent native checkbox checked change
171
+ if (this.readonly) {
172
+ event.preventDefault();
173
+ }
174
+ }
175
+
176
+ /** @private */
177
+ __readonlyChanged(readonly, inputElement) {
178
+ if (!inputElement) {
179
+ return;
180
+ }
181
+
182
+ // Use aria-readonly since native checkbox doesn't support readonly
183
+ if (readonly) {
184
+ inputElement.setAttribute('aria-readonly', 'true');
185
+ } else {
186
+ inputElement.removeAttribute('aria-readonly');
187
+ }
188
+ }
189
+
118
190
  /**
119
191
  * Override method inherited from `CheckedMixin` to reset
120
192
  * `indeterminate` state checkbox is toggled by the user.
@@ -131,6 +203,58 @@ export const CheckboxMixin = (superclass) =>
131
203
  super._toggleChecked(checked);
132
204
  }
133
205
 
206
+ /**
207
+ * @override
208
+ * @return {boolean}
209
+ */
210
+ checkValidity() {
211
+ return !this.required || !!this.checked;
212
+ }
213
+
214
+ /**
215
+ * Override method inherited from `FocusMixin` to validate on blur.
216
+ * @param {boolean} focused
217
+ * @protected
218
+ */
219
+ _setFocused(focused) {
220
+ super._setFocused(focused);
221
+
222
+ // Do not validate when focusout is caused by document
223
+ // losing focus, which happens on browser tab switch.
224
+ if (!focused && document.hasFocus()) {
225
+ this.validate();
226
+ }
227
+ }
228
+
229
+ /** @private */
230
+ _checkedChanged(checked) {
231
+ if (checked || this.__oldChecked) {
232
+ this.validate();
233
+ }
234
+
235
+ this.__oldChecked = checked;
236
+ }
237
+
238
+ /**
239
+ * Override an observer from `FieldMixin`
240
+ * to validate when required is removed.
241
+ *
242
+ * @protected
243
+ * @override
244
+ */
245
+ _requiredChanged(required) {
246
+ super._requiredChanged(required);
247
+
248
+ if (required === false) {
249
+ this.validate();
250
+ }
251
+ }
252
+
253
+ /** @private */
254
+ _onRequiredIndicatorClick() {
255
+ this._labelNode.click();
256
+ }
257
+
134
258
  /**
135
259
  * Fired when the checkbox is checked or unchecked by the user.
136
260
  *
@@ -26,7 +26,7 @@ export const checkboxStyles = css`
26
26
 
27
27
  [part='checkbox'],
28
28
  ::slotted(input),
29
- ::slotted(label) {
29
+ [part='label'] {
30
30
  grid-row: 1;
31
31
  }
32
32
 
@@ -35,6 +35,16 @@ export const checkboxStyles = css`
35
35
  grid-column: 1;
36
36
  }
37
37
 
38
+ [part='helper-text'],
39
+ [part='error-message'] {
40
+ grid-column: 2;
41
+ }
42
+
43
+ :host(:not([has-helper])) [part='helper-text'],
44
+ :host(:not([has-error-message])) [part='error-message'] {
45
+ display: none;
46
+ }
47
+
38
48
  [part='checkbox'] {
39
49
  width: var(--vaadin-checkbox-size, 1em);
40
50
  height: var(--vaadin-checkbox-size, 1em);
@@ -3,13 +3,9 @@
3
3
  * Copyright (c) 2017 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { ActiveMixin } from '@vaadin/a11y-base/src/active-mixin.js';
7
- import { DelegateFocusMixin } from '@vaadin/a11y-base/src/delegate-focus-mixin.js';
8
- import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
9
6
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
- import { CheckedMixin } from '@vaadin/field-base/src/checked-mixin.js';
11
- import { LabelMixin } from '@vaadin/field-base/src/label-mixin.js';
12
7
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
+ import { CheckboxMixin } from './vaadin-checkbox-mixin.js';
13
9
 
14
10
  /**
15
11
  * Fired when the checkbox is checked or unchecked by the user.
@@ -28,10 +24,24 @@ export type CheckboxCheckedChangedEvent = CustomEvent<{ value: boolean }>;
28
24
  */
29
25
  export type CheckboxIndeterminateChangedEvent = CustomEvent<{ value: boolean }>;
30
26
 
27
+ /**
28
+ * Fired when the `invalid` property changes.
29
+ */
30
+ export type CheckboxInvalidChangedEvent = CustomEvent<{ value: boolean }>;
31
+
32
+ /**
33
+ * Fired whenever the checkbox is validated.
34
+ */
35
+ export type CheckboxValidatedEvent = CustomEvent<{ valid: boolean }>;
36
+
31
37
  export interface CheckboxCustomEventMap {
32
38
  'checked-changed': CheckboxCheckedChangedEvent;
33
39
 
34
40
  'indeterminate-changed': CheckboxIndeterminateChangedEvent;
41
+
42
+ 'invalid-changed': CheckboxInvalidChangedEvent;
43
+
44
+ validated: CheckboxValidatedEvent;
35
45
  }
36
46
 
37
47
  export interface CheckboxEventMap extends HTMLElementEventMap, CheckboxCustomEventMap {
@@ -49,21 +59,29 @@ export interface CheckboxEventMap extends HTMLElementEventMap, CheckboxCustomEve
49
59
  *
50
60
  * The following shadow DOM parts are available for styling:
51
61
  *
52
- * Part name | Description
53
- * ------------|-------------
54
- * `checkbox` | The element representing a stylable custom checkbox.
62
+ * Part name | Description
63
+ * ---------------------|-------------
64
+ * `checkbox` | The element representing a stylable custom checkbox
65
+ * `label` | The slotted label element wrapper
66
+ * `helper-text` | The slotted helper text element wrapper
67
+ * `error-message` | The slotted error message element wrapper
68
+ * `required-indicator` | The `required` state indicator element
55
69
  *
56
70
  * The following state attributes are available for styling:
57
71
  *
58
- * Attribute | Description
59
- * ----------------|-------------
60
- * `active` | Set when the checkbox is activated with mouse, touch or the keyboard.
61
- * `checked` | Set when the checkbox is checked.
62
- * `disabled` | Set when the checkbox is disabled.
63
- * `focus-ring` | Set when the checkbox is focused using the keyboard.
64
- * `focused` | Set when the checkbox is focused.
65
- * `indeterminate` | Set when the checkbox is in the indeterminate state.
66
- * `has-label` | Set when the checkbox has a label.
72
+ * Attribute | Description
73
+ * ---------------------|-------------
74
+ * `active` | Set when the checkbox is activated with mouse, touch or the keyboard.
75
+ * `checked` | Set when the checkbox is checked.
76
+ * `disabled` | Set when the checkbox is disabled.
77
+ * `readonly` | Set when the checkbox is readonly.
78
+ * `focus-ring` | Set when the checkbox is focused using the keyboard.
79
+ * `focused` | Set when the checkbox is focused.
80
+ * `indeterminate` | Set when the checkbox is in the indeterminate state.
81
+ * `invalid` | Set when the checkbox is invalid.
82
+ * `has-label` | Set when the checkbox has a label.
83
+ * `has-helper` | Set when the checkbox has helper text.
84
+ * `has-error-message` | Set when the checkbox has an error message.
67
85
  *
68
86
  * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
69
87
  *
@@ -71,23 +89,7 @@ export interface CheckboxEventMap extends HTMLElementEventMap, CheckboxCustomEve
71
89
  * @fires {CustomEvent} checked-changed - Fired when the `checked` property changes.
72
90
  * @fires {CustomEvent} indeterminate-changed - Fired when the `indeterminate` property changes.
73
91
  */
74
- declare class Checkbox extends LabelMixin(
75
- CheckedMixin(DelegateFocusMixin(ActiveMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement)))))),
76
- ) {
77
- /**
78
- * True if the checkbox is in the indeterminate state which means
79
- * it is not possible to say whether it is checked or unchecked.
80
- * The state is reset once the user switches the checkbox by hand.
81
- *
82
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes
83
- */
84
- indeterminate: boolean;
85
-
86
- /**
87
- * The name of the checkbox.
88
- */
89
- name: string;
90
-
92
+ declare class Checkbox extends CheckboxMixin(ElementMixin(ThemableMixin(HTMLElement))) {
91
93
  addEventListener<K extends keyof CheckboxEventMap>(
92
94
  type: K,
93
95
  listener: (this: Checkbox, ev: CheckboxEventMap[K]) => void,
@@ -24,21 +24,29 @@ registerStyles('vaadin-checkbox', checkboxStyles, { moduleId: 'vaadin-checkbox-s
24
24
  *
25
25
  * The following shadow DOM parts are available for styling:
26
26
  *
27
- * Part name | Description
28
- * ------------|-------------
29
- * `checkbox` | The element representing a stylable custom checkbox.
27
+ * Part name | Description
28
+ * ---------------------|-------------
29
+ * `checkbox` | The element representing a stylable custom checkbox
30
+ * `label` | The slotted label element wrapper
31
+ * `helper-text` | The slotted helper text element wrapper
32
+ * `error-message` | The slotted error message element wrapper
33
+ * `required-indicator` | The `required` state indicator element
30
34
  *
31
35
  * The following state attributes are available for styling:
32
36
  *
33
- * Attribute | Description
34
- * ----------------|-------------
35
- * `active` | Set when the checkbox is activated with mouse, touch or the keyboard.
36
- * `checked` | Set when the checkbox is checked.
37
- * `disabled` | Set when the checkbox is disabled.
38
- * `focus-ring` | Set when the checkbox is focused using the keyboard.
39
- * `focused` | Set when the checkbox is focused.
40
- * `indeterminate` | Set when the checkbox is in the indeterminate state.
41
- * `has-label` | Set when the checkbox has a label.
37
+ * Attribute | Description
38
+ * ---------------------|-------------
39
+ * `active` | Set when the checkbox is activated with mouse, touch or the keyboard.
40
+ * `checked` | Set when the checkbox is checked.
41
+ * `disabled` | Set when the checkbox is disabled.
42
+ * `readonly` | Set when the checkbox is readonly.
43
+ * `focus-ring` | Set when the checkbox is focused using the keyboard.
44
+ * `focused` | Set when the checkbox is focused.
45
+ * `indeterminate` | Set when the checkbox is in the indeterminate state.
46
+ * `invalid` | Set when the checkbox is invalid.
47
+ * `has-label` | Set when the checkbox has a label.
48
+ * `has-helper` | Set when the checkbox has helper text.
49
+ * `has-error-message` | Set when the checkbox has an error message.
42
50
  *
43
51
  * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
44
52
  *
@@ -62,7 +70,16 @@ export class Checkbox extends CheckboxMixin(ElementMixin(ThemableMixin(PolymerEl
62
70
  <div class="vaadin-checkbox-container">
63
71
  <div part="checkbox" aria-hidden="true"></div>
64
72
  <slot name="input"></slot>
65
- <slot name="label"></slot>
73
+ <div part="label">
74
+ <slot name="label"></slot>
75
+ <div part="required-indicator" on-click="_onRequiredIndicatorClick"></div>
76
+ </div>
77
+ <div part="helper-text">
78
+ <slot name="helper"></slot>
79
+ </div>
80
+ <div part="error-message">
81
+ <slot name="error-message"></slot>
82
+ </div>
66
83
  </div>
67
84
  <slot name="tooltip"></slot>
68
85
  `;
@@ -36,7 +36,16 @@ export class Checkbox extends CheckboxMixin(ElementMixin(ThemableMixin(PolylitMi
36
36
  <div class="vaadin-checkbox-container">
37
37
  <div part="checkbox" aria-hidden="true"></div>
38
38
  <slot name="input"></slot>
39
- <slot name="label"></slot>
39
+ <div part="label">
40
+ <slot name="label"></slot>
41
+ <div part="required-indicator" @click="${this._onRequiredIndicatorClick}"></div>
42
+ </div>
43
+ <div part="helper-text">
44
+ <slot name="helper"></slot>
45
+ </div>
46
+ <div part="error-message">
47
+ <slot name="error-message"></slot>
48
+ </div>
40
49
  </div>
41
50
  <slot name="tooltip"></slot>
42
51
  `;
@@ -26,6 +26,13 @@ registerStyles(
26
26
  --_focus-ring-color: var(--vaadin-focus-ring-color, var(--lumo-primary-color-50pct));
27
27
  --_focus-ring-width: var(--vaadin-focus-ring-width, 2px);
28
28
  --_selection-color: var(--vaadin-selection-color, var(--lumo-primary-color));
29
+ --_invalid-background: var(--vaadin-input-field-invalid-background, var(--lumo-error-color-10pct));
30
+ }
31
+
32
+ [part='label'] {
33
+ display: flex;
34
+ position: relative;
35
+ max-width: max-content;
29
36
  }
30
37
 
31
38
  :host([has-label]) ::slotted(label) {
@@ -35,6 +42,14 @@ registerStyles(
35
42
  );
36
43
  }
37
44
 
45
+ :host([dir='rtl'][has-label]) ::slotted(label) {
46
+ padding: var(--lumo-space-xs) var(--lumo-space-xs) var(--lumo-space-xs) var(--lumo-space-s);
47
+ }
48
+
49
+ :host([has-label][required]) ::slotted(label) {
50
+ padding-inline-end: var(--lumo-space-m);
51
+ }
52
+
38
53
  [part='checkbox'] {
39
54
  width: var(--_checkbox-size);
40
55
  height: var(--_checkbox-size);
@@ -77,6 +92,27 @@ registerStyles(
77
92
  opacity: 1;
78
93
  }
79
94
 
95
+ :host([readonly]:not([checked]):not([indeterminate])) {
96
+ color: var(--lumo-secondary-text-color);
97
+ }
98
+
99
+ :host([readonly]:not([checked]):not([indeterminate])) [part='checkbox'] {
100
+ background: transparent;
101
+ box-shadow: none;
102
+ }
103
+
104
+ :host([readonly]:not([checked]):not([indeterminate])) [part='checkbox']::after {
105
+ content: '';
106
+ box-sizing: border-box;
107
+ width: 100%;
108
+ height: 100%;
109
+ border-radius: inherit;
110
+ top: 0;
111
+ left: 0;
112
+ opacity: 1;
113
+ border: var(--vaadin-input-field-readonly-border, 1px dashed var(--lumo-contrast-50pct));
114
+ }
115
+
80
116
  /* Indeterminate checkmark */
81
117
  :host([indeterminate]) [part='checkbox']::after {
82
118
  content: var(--vaadin-checkbox-checkmark-char-indeterminate, '');
@@ -96,10 +132,13 @@ registerStyles(
96
132
  inset 0 0 0 var(--_input-border-width, 0) var(--_input-border-color);
97
133
  }
98
134
 
135
+ :host([focus-ring][readonly]:not([checked]):not([indeterminate])) [part='checkbox'] {
136
+ box-shadow: 0 0 0 1px var(--lumo-base-color), 0 0 0 calc(var(--_focus-ring-width) + 1px) var(--_focus-ring-color);
137
+ }
138
+
99
139
  /* Disabled */
100
140
  :host([disabled]) {
101
141
  pointer-events: none;
102
- color: var(--lumo-disabled-text-color);
103
142
  --vaadin-input-field-border-color: var(--lumo-contrast-20pct);
104
143
  }
105
144
 
@@ -115,13 +154,19 @@ registerStyles(
115
154
  color: var(--lumo-contrast-30pct);
116
155
  }
117
156
 
157
+ :host([disabled]) [part='label'],
158
+ :host([disabled]) [part='helper-text'] {
159
+ color: var(--lumo-disabled-text-color);
160
+ -webkit-text-fill-color: var(--lumo-disabled-text-color);
161
+ }
162
+
118
163
  :host([indeterminate][disabled]) [part='checkbox']::after {
119
164
  background-color: var(--lumo-contrast-30pct);
120
165
  }
121
166
 
122
- /* RTL specific styles */
123
- :host([dir='rtl'][has-label]) ::slotted(label) {
124
- padding: var(--lumo-space-xs) var(--lumo-space-xs) var(--lumo-space-xs) var(--lumo-space-s);
167
+ :host([readonly][checked]) [part='checkbox'],
168
+ :host([readonly][indeterminate]) [part='checkbox'] {
169
+ background-color: var(--vaadin-checkbox-readonly-checked-background, var(--lumo-contrast-70pct));
125
170
  }
126
171
 
127
172
  /* Used for activation "halo" */
@@ -139,13 +184,14 @@ registerStyles(
139
184
  }
140
185
 
141
186
  /* Hover */
142
- :host(:not([checked]):not([indeterminate]):not([disabled]):hover) [part='checkbox'] {
187
+ :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):not([invalid]):hover) [part='checkbox'] {
143
188
  background: var(--vaadin-checkbox-background-hover, var(--lumo-contrast-30pct));
144
189
  }
145
190
 
146
191
  /* Disable hover for touch devices */
147
192
  @media (pointer: coarse) {
148
- :host(:not([checked]):not([indeterminate]):not([disabled]):hover) [part='checkbox'] {
193
+ /* prettier-ignore */
194
+ :host(:not([checked]):not([indeterminate]):not([disabled]):not([readonly]):not([invalid]):hover) [part='checkbox'] {
149
195
  background: var(--vaadin-checkbox-background, var(--lumo-contrast-20pct));
150
196
  }
151
197
  }
@@ -165,6 +211,94 @@ registerStyles(
165
211
  transform: scale(0);
166
212
  opacity: 0.4;
167
213
  }
214
+
215
+ /* Required */
216
+ :host([required]) [part='required-indicator'] {
217
+ position: absolute;
218
+ top: var(--lumo-space-xs);
219
+ right: var(--lumo-space-xs);
220
+ }
221
+
222
+ :host([required][dir='rtl']) [part='required-indicator'] {
223
+ right: auto;
224
+ left: var(--lumo-space-xs);
225
+ }
226
+
227
+ :host([required]) [part='required-indicator']::after {
228
+ content: var(--lumo-required-field-indicator, '\\2022');
229
+ transition: opacity 0.2s;
230
+ color: var(--lumo-required-field-indicator-color, var(--lumo-primary-text-color));
231
+ width: 1em;
232
+ text-align: center;
233
+ }
234
+
235
+ /* Invalid */
236
+ :host([invalid]) {
237
+ --vaadin-input-field-border-color: var(--lumo-error-color);
238
+ }
239
+
240
+ :host([invalid]) [part='checkbox'] {
241
+ background: var(--_invalid-background);
242
+ background-image: linear-gradient(var(--_invalid-background) 0%, var(--_invalid-background) 100%);
243
+ }
244
+
245
+ :host([invalid]:hover) [part='checkbox'] {
246
+ background-image: linear-gradient(var(--_invalid-background) 0%, var(--_invalid-background) 100%),
247
+ linear-gradient(var(--_invalid-background) 0%, var(--_invalid-background) 100%);
248
+ }
249
+
250
+ :host([invalid][focus-ring]) {
251
+ --_focus-ring-color: var(--lumo-error-color-50pct);
252
+ }
253
+
254
+ :host([invalid]) [part='required-indicator']::after {
255
+ color: var(--lumo-required-field-indicator-color, var(--lumo-error-text-color));
256
+ }
257
+
258
+ /* Error message */
259
+ [part='error-message'] {
260
+ font-size: var(--vaadin-input-field-error-font-size, var(--lumo-font-size-xs));
261
+ line-height: var(--lumo-line-height-xs);
262
+ font-weight: var(--vaadin-input-field-error-font-weight, 400);
263
+ color: var(--vaadin-input-field-error-color, var(--lumo-error-text-color));
264
+ will-change: max-height;
265
+ transition: 0.4s max-height;
266
+ max-height: 5em;
267
+ padding-inline-start: var(--lumo-space-xs);
268
+ }
269
+
270
+ :host([has-error-message]) [part='error-message']::after,
271
+ :host([has-helper]) [part='helper-text']::after {
272
+ content: '';
273
+ display: block;
274
+ height: 0.4em;
275
+ }
276
+
277
+ :host(:not([invalid])) [part='error-message'] {
278
+ max-height: 0;
279
+ overflow: hidden;
280
+ }
281
+
282
+ /* Helper */
283
+ [part='helper-text'] {
284
+ display: block;
285
+ color: var(--vaadin-input-field-helper-color, var(--lumo-secondary-text-color));
286
+ font-size: var(--vaadin-input-field-helper-font-size, var(--lumo-font-size-xs));
287
+ line-height: var(--lumo-line-height-xs);
288
+ font-weight: var(--vaadin-input-field-helper-font-weight, 400);
289
+ margin-left: calc(var(--lumo-border-radius-m) / 4);
290
+ transition: color 0.2s;
291
+ padding-inline-start: var(--lumo-space-xs);
292
+ }
293
+
294
+ :host(:hover:not([readonly])) [part='helper-text'] {
295
+ color: var(--lumo-body-text-color);
296
+ }
297
+
298
+ :host([has-error-message]) ::slotted(label),
299
+ :host([has-helper]) ::slotted(label) {
300
+ padding-bottom: 0;
301
+ }
168
302
  `,
169
303
  { moduleId: 'lumo-checkbox' },
170
304
  );
@@ -15,6 +15,12 @@ registerStyles(
15
15
  --_checkbox-size: var(--vaadin-checkbox-size, 16px);
16
16
  }
17
17
 
18
+ [part='label'] {
19
+ display: flex;
20
+ position: relative;
21
+ max-width: max-content;
22
+ }
23
+
18
24
  :host([has-label]) ::slotted(label) {
19
25
  padding: 3px 12px 3px 6px;
20
26
  }
@@ -118,10 +124,62 @@ registerStyles(
118
124
  background-color: var(--material-disabled-color);
119
125
  }
120
126
 
127
+ :host([readonly][checked]) [part='checkbox'],
128
+ :host([readonly][indeterminate]) [part='checkbox'],
129
+ :host([readonly]) [part='checkbox']::before {
130
+ background-color: var(--material-secondary-text-color);
131
+ }
132
+
121
133
  /* RTL specific styles */
122
134
  :host([dir='rtl'][has-label]) ::slotted(label) {
123
135
  padding: 3px 6px 3px 12px;
124
136
  }
137
+
138
+ /* Required */
139
+ :host([required]) [part='required-indicator'] {
140
+ position: absolute;
141
+ top: 3px;
142
+ right: 2px;
143
+ }
144
+
145
+ :host([dir='rtl'][required]) [part='required-indicator'] {
146
+ right: auto;
147
+ left: 2px;
148
+ }
149
+
150
+ :host([required]:not([disabled])) [part='required-indicator'] {
151
+ color: var(--material-secondary-text-color);
152
+ }
153
+
154
+ :host([required]) [part='required-indicator']::after {
155
+ content: '*';
156
+ }
157
+
158
+ :host([invalid]) [part='required-indicator']::after {
159
+ color: var(--material-error-text-color);
160
+ }
161
+
162
+ [part='error-message'],
163
+ [part='helper-text'] {
164
+ font-size: 0.75em;
165
+ line-height: 1;
166
+ padding-left: 6px;
167
+ }
168
+
169
+ [part='error-message'] {
170
+ color: var(--material-error-text-color);
171
+ }
172
+
173
+ [part='helper-text'] {
174
+ color: var(--material-secondary-text-color);
175
+ }
176
+
177
+ :host([has-error-message]) [part='error-message']::before,
178
+ :host([has-helper]) [part='helper-text']::before {
179
+ content: '';
180
+ display: block;
181
+ height: 6px;
182
+ }
125
183
  `,
126
184
  { moduleId: 'material-checkbox' },
127
185
  );
package/web-types.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/checkbox",
4
- "version": "24.4.0-alpha8",
4
+ "version": "24.4.0-beta1",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
10
  "name": "vaadin-checkbox",
11
- "description": "`<vaadin-checkbox>` is an input field representing a binary choice.\n\n```html\n<vaadin-checkbox label=\"I accept the terms and conditions\"></vaadin-checkbox>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n------------|-------------\n`checkbox` | The element representing a stylable custom checkbox.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n----------------|-------------\n`active` | Set when the checkbox is activated with mouse, touch or the keyboard.\n`checked` | Set when the checkbox is checked.\n`disabled` | Set when the checkbox is disabled.\n`focus-ring` | Set when the checkbox is focused using the keyboard.\n`focused` | Set when the checkbox is focused.\n`indeterminate` | Set when the checkbox is in the indeterminate state.\n`has-label` | Set when the checkbox has a label.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
11
+ "description": "`<vaadin-checkbox>` is an input field representing a binary choice.\n\n```html\n<vaadin-checkbox label=\"I accept the terms and conditions\"></vaadin-checkbox>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|-------------\n`checkbox` | The element representing a stylable custom checkbox\n`label` | The slotted label element wrapper\n`helper-text` | The slotted helper text element wrapper\n`error-message` | The slotted error message element wrapper\n`required-indicator` | The `required` state indicator element\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|-------------\n`active` | Set when the checkbox is activated with mouse, touch or the keyboard.\n`checked` | Set when the checkbox is checked.\n`disabled` | Set when the checkbox is disabled.\n`readonly` | Set when the checkbox is readonly.\n`focus-ring` | Set when the checkbox is focused using the keyboard.\n`focused` | Set when the checkbox is focused.\n`indeterminate` | Set when the checkbox is in the indeterminate state.\n`invalid` | Set when the checkbox is invalid.\n`has-label` | Set when the checkbox has a label.\n`has-helper` | Set when the checkbox has helper text.\n`has-error-message` | Set when the checkbox has an error message.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "disabled",
@@ -63,6 +63,72 @@
63
63
  ]
64
64
  }
65
65
  },
66
+ {
67
+ "name": "invalid",
68
+ "description": "Set to true when the field is invalid.",
69
+ "value": {
70
+ "type": [
71
+ "boolean",
72
+ "null",
73
+ "undefined"
74
+ ]
75
+ }
76
+ },
77
+ {
78
+ "name": "required",
79
+ "description": "Specifies that the user must fill in a value.",
80
+ "value": {
81
+ "type": [
82
+ "boolean",
83
+ "null",
84
+ "undefined"
85
+ ]
86
+ }
87
+ },
88
+ {
89
+ "name": "error-message",
90
+ "description": "Error to show when the field is invalid.",
91
+ "value": {
92
+ "type": [
93
+ "string",
94
+ "null",
95
+ "undefined"
96
+ ]
97
+ }
98
+ },
99
+ {
100
+ "name": "helper-text",
101
+ "description": "String used for the helper text.",
102
+ "value": {
103
+ "type": [
104
+ "string",
105
+ "null",
106
+ "undefined"
107
+ ]
108
+ }
109
+ },
110
+ {
111
+ "name": "accessible-name",
112
+ "description": "String used to label the component to screen reader users.",
113
+ "value": {
114
+ "type": [
115
+ "string",
116
+ "null",
117
+ "undefined"
118
+ ]
119
+ }
120
+ },
121
+ {
122
+ "name": "accessible-name-ref",
123
+ "description": "Id of the element used as label of the component to screen reader users.",
124
+ "value": {
125
+ "type": [
126
+ "string",
127
+ "null",
128
+ "undefined"
129
+ ]
130
+ }
131
+ },
66
132
  {
67
133
  "name": "indeterminate",
68
134
  "description": "True if the checkbox is in the indeterminate state which means\nit is not possible to say whether it is checked or unchecked.\nThe state is reset once the user switches the checkbox by hand.\n\nhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes",
@@ -81,6 +147,17 @@
81
147
  ]
82
148
  }
83
149
  },
150
+ {
151
+ "name": "readonly",
152
+ "description": "When true, the user cannot modify the value of the checkbox.\nThe difference between `disabled` and `readonly` is that the\nread-only checkbox remains focusable, is announced by screen\nreaders and its value can be submitted as part of the form.",
153
+ "value": {
154
+ "type": [
155
+ "boolean",
156
+ "null",
157
+ "undefined"
158
+ ]
159
+ }
160
+ },
84
161
  {
85
162
  "name": "theme",
86
163
  "description": "The theme variants to apply to the component.",
@@ -148,6 +225,72 @@
148
225
  ]
149
226
  }
150
227
  },
228
+ {
229
+ "name": "invalid",
230
+ "description": "Set to true when the field is invalid.",
231
+ "value": {
232
+ "type": [
233
+ "boolean",
234
+ "null",
235
+ "undefined"
236
+ ]
237
+ }
238
+ },
239
+ {
240
+ "name": "required",
241
+ "description": "Specifies that the user must fill in a value.",
242
+ "value": {
243
+ "type": [
244
+ "boolean",
245
+ "null",
246
+ "undefined"
247
+ ]
248
+ }
249
+ },
250
+ {
251
+ "name": "errorMessage",
252
+ "description": "Error to show when the field is invalid.",
253
+ "value": {
254
+ "type": [
255
+ "string",
256
+ "null",
257
+ "undefined"
258
+ ]
259
+ }
260
+ },
261
+ {
262
+ "name": "helperText",
263
+ "description": "String used for the helper text.",
264
+ "value": {
265
+ "type": [
266
+ "string",
267
+ "null",
268
+ "undefined"
269
+ ]
270
+ }
271
+ },
272
+ {
273
+ "name": "accessibleName",
274
+ "description": "String used to label the component to screen reader users.",
275
+ "value": {
276
+ "type": [
277
+ "string",
278
+ "null",
279
+ "undefined"
280
+ ]
281
+ }
282
+ },
283
+ {
284
+ "name": "accessibleNameRef",
285
+ "description": "Id of the element used as label of the component to screen reader users.",
286
+ "value": {
287
+ "type": [
288
+ "string",
289
+ "null",
290
+ "undefined"
291
+ ]
292
+ }
293
+ },
151
294
  {
152
295
  "name": "indeterminate",
153
296
  "description": "True if the checkbox is in the indeterminate state which means\nit is not possible to say whether it is checked or unchecked.\nThe state is reset once the user switches the checkbox by hand.\n\nhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes",
@@ -165,9 +308,24 @@
165
308
  "string"
166
309
  ]
167
310
  }
311
+ },
312
+ {
313
+ "name": "readonly",
314
+ "description": "When true, the user cannot modify the value of the checkbox.\nThe difference between `disabled` and `readonly` is that the\nread-only checkbox remains focusable, is announced by screen\nreaders and its value can be submitted as part of the form.",
315
+ "value": {
316
+ "type": [
317
+ "boolean",
318
+ "null",
319
+ "undefined"
320
+ ]
321
+ }
168
322
  }
169
323
  ],
170
324
  "events": [
325
+ {
326
+ "name": "validated",
327
+ "description": "Fired whenever the field is validated."
328
+ },
171
329
  {
172
330
  "name": "change",
173
331
  "description": "Fired when the checkbox is checked or unchecked by the user."
@@ -180,6 +338,10 @@
180
338
  "name": "checked-changed",
181
339
  "description": "Fired when the `checked` property changes."
182
340
  },
341
+ {
342
+ "name": "invalid-changed",
343
+ "description": "Fired when the `invalid` property changes."
344
+ },
183
345
  {
184
346
  "name": "indeterminate-changed",
185
347
  "description": "Fired when the `indeterminate` property changes."
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/checkbox",
4
- "version": "24.4.0-alpha8",
4
+ "version": "24.4.0-beta1",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,7 +16,7 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-checkbox",
19
- "description": "`<vaadin-checkbox>` is an input field representing a binary choice.\n\n```html\n<vaadin-checkbox label=\"I accept the terms and conditions\"></vaadin-checkbox>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n------------|-------------\n`checkbox` | The element representing a stylable custom checkbox.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n----------------|-------------\n`active` | Set when the checkbox is activated with mouse, touch or the keyboard.\n`checked` | Set when the checkbox is checked.\n`disabled` | Set when the checkbox is disabled.\n`focus-ring` | Set when the checkbox is focused using the keyboard.\n`focused` | Set when the checkbox is focused.\n`indeterminate` | Set when the checkbox is in the indeterminate state.\n`has-label` | Set when the checkbox has a label.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
19
+ "description": "`<vaadin-checkbox>` is an input field representing a binary choice.\n\n```html\n<vaadin-checkbox label=\"I accept the terms and conditions\"></vaadin-checkbox>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|-------------\n`checkbox` | The element representing a stylable custom checkbox\n`label` | The slotted label element wrapper\n`helper-text` | The slotted helper text element wrapper\n`error-message` | The slotted error message element wrapper\n`required-indicator` | The `required` state indicator element\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|-------------\n`active` | Set when the checkbox is activated with mouse, touch or the keyboard.\n`checked` | Set when the checkbox is checked.\n`disabled` | Set when the checkbox is disabled.\n`readonly` | Set when the checkbox is readonly.\n`focus-ring` | Set when the checkbox is focused using the keyboard.\n`focused` | Set when the checkbox is focused.\n`indeterminate` | Set when the checkbox is in the indeterminate state.\n`invalid` | Set when the checkbox is invalid.\n`has-label` | Set when the checkbox has a label.\n`has-helper` | Set when the checkbox has helper text.\n`has-error-message` | Set when the checkbox has an error message.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -40,6 +40,20 @@
40
40
  "kind": "expression"
41
41
  }
42
42
  },
43
+ {
44
+ "name": "?invalid",
45
+ "description": "Set to true when the field is invalid.",
46
+ "value": {
47
+ "kind": "expression"
48
+ }
49
+ },
50
+ {
51
+ "name": "?required",
52
+ "description": "Specifies that the user must fill in a value.",
53
+ "value": {
54
+ "kind": "expression"
55
+ }
56
+ },
43
57
  {
44
58
  "name": "?indeterminate",
45
59
  "description": "True if the checkbox is in the indeterminate state which means\nit is not possible to say whether it is checked or unchecked.\nThe state is reset once the user switches the checkbox by hand.\n\nhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes",
@@ -47,6 +61,13 @@
47
61
  "kind": "expression"
48
62
  }
49
63
  },
64
+ {
65
+ "name": "?readonly",
66
+ "description": "When true, the user cannot modify the value of the checkbox.\nThe difference between `disabled` and `readonly` is that the\nread-only checkbox remains focusable, is announced by screen\nreaders and its value can be submitted as part of the form.",
67
+ "value": {
68
+ "kind": "expression"
69
+ }
70
+ },
50
71
  {
51
72
  "name": ".value",
52
73
  "description": "The value of the field.",
@@ -61,6 +82,34 @@
61
82
  "kind": "expression"
62
83
  }
63
84
  },
85
+ {
86
+ "name": ".errorMessage",
87
+ "description": "Error to show when the field is invalid.",
88
+ "value": {
89
+ "kind": "expression"
90
+ }
91
+ },
92
+ {
93
+ "name": ".helperText",
94
+ "description": "String used for the helper text.",
95
+ "value": {
96
+ "kind": "expression"
97
+ }
98
+ },
99
+ {
100
+ "name": ".accessibleName",
101
+ "description": "String used to label the component to screen reader users.",
102
+ "value": {
103
+ "kind": "expression"
104
+ }
105
+ },
106
+ {
107
+ "name": ".accessibleNameRef",
108
+ "description": "Id of the element used as label of the component to screen reader users.",
109
+ "value": {
110
+ "kind": "expression"
111
+ }
112
+ },
64
113
  {
65
114
  "name": ".name",
66
115
  "description": "The name of the checkbox.",
@@ -68,6 +117,13 @@
68
117
  "kind": "expression"
69
118
  }
70
119
  },
120
+ {
121
+ "name": "@validated",
122
+ "description": "Fired whenever the field is validated.",
123
+ "value": {
124
+ "kind": "expression"
125
+ }
126
+ },
71
127
  {
72
128
  "name": "@change",
73
129
  "description": "Fired when the checkbox is checked or unchecked by the user.",
@@ -89,6 +145,13 @@
89
145
  "kind": "expression"
90
146
  }
91
147
  },
148
+ {
149
+ "name": "@invalid-changed",
150
+ "description": "Fired when the `invalid` property changes.",
151
+ "value": {
152
+ "kind": "expression"
153
+ }
154
+ },
92
155
  {
93
156
  "name": "@indeterminate-changed",
94
157
  "description": "Fired when the `indeterminate` property changes.",