@vaadin/checkbox-group 24.4.0-dev.b3e1d14600 → 24.5.0-alpha1

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 @@ A web component that allows the user to choose several items from a group of bin
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-group)](https://www.npmjs.com/package/@vaadin/checkbox-group)
8
- [![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)
9
8
 
10
9
  ```html
11
10
  <vaadin-checkbox-group label="Export data">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/checkbox-group",
3
- "version": "24.4.0-dev.b3e1d14600",
3
+ "version": "24.5.0-alpha1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -25,7 +25,9 @@
25
25
  "vaadin-*.d.ts",
26
26
  "vaadin-*.js",
27
27
  "web-types.json",
28
- "web-types.lit.json"
28
+ "web-types.lit.json",
29
+ "!vaadin-lit-*.d.ts",
30
+ "!vaadin-lit-*.js"
29
31
  ],
30
32
  "keywords": [
31
33
  "Vaadin",
@@ -35,14 +37,15 @@
35
37
  "polymer"
36
38
  ],
37
39
  "dependencies": {
40
+ "@open-wc/dedupe-mixin": "^1.3.0",
38
41
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/a11y-base": "24.4.0-dev.b3e1d14600",
40
- "@vaadin/checkbox": "24.4.0-dev.b3e1d14600",
41
- "@vaadin/component-base": "24.4.0-dev.b3e1d14600",
42
- "@vaadin/field-base": "24.4.0-dev.b3e1d14600",
43
- "@vaadin/vaadin-lumo-styles": "24.4.0-dev.b3e1d14600",
44
- "@vaadin/vaadin-material-styles": "24.4.0-dev.b3e1d14600",
45
- "@vaadin/vaadin-themable-mixin": "24.4.0-dev.b3e1d14600"
42
+ "@vaadin/a11y-base": "24.5.0-alpha1",
43
+ "@vaadin/checkbox": "24.5.0-alpha1",
44
+ "@vaadin/component-base": "24.5.0-alpha1",
45
+ "@vaadin/field-base": "24.5.0-alpha1",
46
+ "@vaadin/vaadin-lumo-styles": "24.5.0-alpha1",
47
+ "@vaadin/vaadin-material-styles": "24.5.0-alpha1",
48
+ "@vaadin/vaadin-themable-mixin": "24.5.0-alpha1"
46
49
  },
47
50
  "devDependencies": {
48
51
  "@esm-bundle/chai": "^4.3.4",
@@ -53,5 +56,5 @@
53
56
  "web-types.json",
54
57
  "web-types.lit.json"
55
58
  ],
56
- "gitHead": "502d4f5b03f770a83d270d98078cde230254dd0e"
59
+ "gitHead": "57806caac5468532a3b4e3dbdda730cd0fca193a"
57
60
  }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
8
+ import type { FocusMixinClass } from '@vaadin/a11y-base/src/focus-mixin.js';
9
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
10
+ import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
11
+ import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
12
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
13
+
14
+ /**
15
+ * A mixin providing common checkbox-group functionality.
16
+ */
17
+ export declare function CheckboxGroupMixin<T extends Constructor<HTMLElement>>(
18
+ base: T,
19
+ ): Constructor<CheckboxGroupMixinClass> &
20
+ Constructor<ControllerMixinClass> &
21
+ Constructor<DisabledMixinClass> &
22
+ Constructor<FieldMixinClass> &
23
+ Constructor<FocusMixinClass> &
24
+ Constructor<LabelMixinClass> &
25
+ Constructor<ValidateMixinClass> &
26
+ T;
27
+
28
+ export declare class CheckboxGroupMixinClass {
29
+ /**
30
+ * An array containing values of the currently checked checkboxes.
31
+ *
32
+ * The array is immutable so toggling checkboxes always results in
33
+ * creating a new array.
34
+ */
35
+ value: string[];
36
+
37
+ /**
38
+ * When true, the user cannot modify the value of the checkbox group.
39
+ * The difference between `disabled` and `readonly` is that in the
40
+ * read-only checkbox group, all the checkboxes are also read-only,
41
+ * and therefore remain focusable and announced by screen readers.
42
+ */
43
+ readonly: boolean;
44
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
7
+ import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
8
+ import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
9
+ import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
10
+ import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
11
+
12
+ /**
13
+ * A mixin providing common checkbox-group functionality.
14
+ *
15
+ * @polymerMixin
16
+ * @mixes DisabledMixin
17
+ * @mixes FieldMixin
18
+ * @mixes FocusMixin
19
+ * @mixes KeyboardMixin
20
+ */
21
+ export const CheckboxGroupMixin = (superclass) =>
22
+ class CheckboxGroupMixinClass extends FieldMixin(FocusMixin(DisabledMixin(superclass))) {
23
+ static get properties() {
24
+ return {
25
+ /**
26
+ * An array containing values of the currently checked checkboxes.
27
+ *
28
+ * The array is immutable so toggling checkboxes always results in
29
+ * creating a new array.
30
+ *
31
+ * @type {!Array<!string>}
32
+ */
33
+ value: {
34
+ type: Array,
35
+ value: () => [],
36
+ notify: true,
37
+ sync: true,
38
+ observer: '__valueChanged',
39
+ },
40
+
41
+ /**
42
+ * When true, the user cannot modify the value of the checkbox group.
43
+ * The difference between `disabled` and `readonly` is that in the
44
+ * read-only checkbox group, all the checkboxes are also read-only,
45
+ * and therefore remain focusable and announced by screen readers.
46
+ */
47
+ readonly: {
48
+ type: Boolean,
49
+ value: false,
50
+ reflectToAttribute: true,
51
+ observer: '__readonlyChanged',
52
+ },
53
+ };
54
+ }
55
+
56
+ constructor() {
57
+ super();
58
+
59
+ this.__registerCheckbox = this.__registerCheckbox.bind(this);
60
+ this.__unregisterCheckbox = this.__unregisterCheckbox.bind(this);
61
+ this.__onCheckboxCheckedChanged = this.__onCheckboxCheckedChanged.bind(this);
62
+
63
+ this._tooltipController = new TooltipController(this);
64
+ this._tooltipController.addEventListener('tooltip-changed', (event) => {
65
+ const tooltip = event.detail.node;
66
+ if (tooltip && tooltip.isConnected) {
67
+ // Tooltip element has been added to the DOM
68
+ const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
69
+ this._tooltipController.setAriaTarget(inputs);
70
+ } else {
71
+ // Tooltip element is no longer connected
72
+ this._tooltipController.setAriaTarget([]);
73
+ }
74
+ });
75
+ }
76
+
77
+ /**
78
+ * A collection of the checkboxes.
79
+ *
80
+ * @return {!Array<!Checkbox>}
81
+ * @private
82
+ */
83
+ get __checkboxes() {
84
+ return this.__filterCheckboxes([...this.children]);
85
+ }
86
+
87
+ /** @protected */
88
+ ready() {
89
+ super.ready();
90
+
91
+ this.ariaTarget = this;
92
+
93
+ // See https://github.com/vaadin/vaadin-web-components/issues/94
94
+ this.setAttribute('role', 'group');
95
+
96
+ const slot = this.shadowRoot.querySelector('slot:not([name])');
97
+ this._observer = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
98
+ const addedCheckboxes = this.__filterCheckboxes(addedNodes);
99
+ const removedCheckboxes = this.__filterCheckboxes(removedNodes);
100
+
101
+ addedCheckboxes.forEach(this.__registerCheckbox);
102
+ removedCheckboxes.forEach(this.__unregisterCheckbox);
103
+
104
+ const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
105
+ this._tooltipController.setAriaTarget(inputs);
106
+
107
+ this.__warnOfCheckboxesWithoutValue(addedCheckboxes);
108
+ });
109
+
110
+ this.addController(this._tooltipController);
111
+ }
112
+
113
+ /**
114
+ * Override method inherited from `ValidateMixin`
115
+ * to validate the value array.
116
+ *
117
+ * @override
118
+ * @return {boolean}
119
+ */
120
+ checkValidity() {
121
+ return !this.required || this.value.length > 0;
122
+ }
123
+
124
+ /**
125
+ * @param {!Array<!Node>} nodes
126
+ * @return {!Array<!Checkbox>}
127
+ * @private
128
+ */
129
+ __filterCheckboxes(nodes) {
130
+ return nodes.filter((node) => node.nodeType === Node.ELEMENT_NODE && node.localName === 'vaadin-checkbox');
131
+ }
132
+
133
+ /**
134
+ * @param {!Array<!Checkbox>} checkboxes
135
+ * @private
136
+ */
137
+ __warnOfCheckboxesWithoutValue(checkboxes) {
138
+ const hasCheckboxesWithoutValue = checkboxes.some((checkbox) => {
139
+ const { value } = checkbox;
140
+
141
+ return !checkbox.hasAttribute('value') && (!value || value === 'on');
142
+ });
143
+
144
+ if (hasCheckboxesWithoutValue) {
145
+ console.warn('Please provide the value attribute to all the checkboxes inside the checkbox group.');
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Registers the checkbox after adding it to the group.
151
+ *
152
+ * @param {!Checkbox} checkbox
153
+ * @private
154
+ */
155
+ __registerCheckbox(checkbox) {
156
+ checkbox.addEventListener('checked-changed', this.__onCheckboxCheckedChanged);
157
+
158
+ if (this.disabled) {
159
+ checkbox.disabled = true;
160
+ }
161
+
162
+ if (this.readonly) {
163
+ checkbox.readonly = true;
164
+ }
165
+
166
+ if (checkbox.checked) {
167
+ this.__addCheckboxToValue(checkbox.value);
168
+ } else if (this.value.includes(checkbox.value)) {
169
+ checkbox.checked = true;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Unregisters the checkbox before removing it from the group.
175
+ *
176
+ * @param {!Checkbox} checkbox
177
+ * @private
178
+ */
179
+ __unregisterCheckbox(checkbox) {
180
+ checkbox.removeEventListener('checked-changed', this.__onCheckboxCheckedChanged);
181
+
182
+ if (checkbox.checked) {
183
+ this.__removeCheckboxFromValue(checkbox.value);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Override method inherited from `DisabledMixin`
189
+ * to propagate the `disabled` property to the checkboxes.
190
+ *
191
+ * @param {boolean} newValue
192
+ * @param {boolean} oldValue
193
+ * @override
194
+ * @protected
195
+ */
196
+ _disabledChanged(newValue, oldValue) {
197
+ super._disabledChanged(newValue, oldValue);
198
+
199
+ // Prevent updating the `disabled` property for the checkboxes at initialization.
200
+ // Otherwise, the checkboxes may end up enabled regardless the `disabled` attribute
201
+ // intentionally added by the user on some of them.
202
+ if (!newValue && oldValue === undefined) {
203
+ return;
204
+ }
205
+
206
+ if (oldValue !== newValue) {
207
+ this.__checkboxes.forEach((checkbox) => {
208
+ checkbox.disabled = newValue;
209
+ });
210
+ }
211
+ }
212
+
213
+ /**
214
+ * @param {string} value
215
+ * @private
216
+ */
217
+ __addCheckboxToValue(value) {
218
+ if (!this.value.includes(value)) {
219
+ this.value = [...this.value, value];
220
+ }
221
+ }
222
+
223
+ /**
224
+ * @param {string} value
225
+ * @private
226
+ */
227
+ __removeCheckboxFromValue(value) {
228
+ if (this.value.includes(value)) {
229
+ this.value = this.value.filter((v) => v !== value);
230
+ }
231
+ }
232
+
233
+ /**
234
+ * @param {!CustomEvent} event
235
+ * @private
236
+ */
237
+ __onCheckboxCheckedChanged(event) {
238
+ const checkbox = event.target;
239
+
240
+ if (checkbox.checked) {
241
+ this.__addCheckboxToValue(checkbox.value);
242
+ } else {
243
+ this.__removeCheckboxFromValue(checkbox.value);
244
+ }
245
+ }
246
+
247
+ /**
248
+ * @param {string | null | undefined} value
249
+ * @param {string | null | undefined} oldValue
250
+ * @private
251
+ */
252
+ __valueChanged(value, oldValue) {
253
+ // Setting initial value to empty array, skip validation
254
+ if (value.length === 0 && oldValue === undefined) {
255
+ return;
256
+ }
257
+
258
+ this.toggleAttribute('has-value', value.length > 0);
259
+
260
+ this.__checkboxes.forEach((checkbox) => {
261
+ checkbox.checked = value.includes(checkbox.value);
262
+ });
263
+
264
+ if (oldValue !== undefined) {
265
+ this.validate();
266
+ }
267
+ }
268
+
269
+ /** @private */
270
+ __readonlyChanged(readonly, oldReadonly) {
271
+ if (readonly || oldReadonly) {
272
+ this.__checkboxes.forEach((checkbox) => {
273
+ checkbox.readonly = readonly;
274
+ });
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Override method inherited from `FocusMixin`
280
+ * to prevent removing the `focused` attribute
281
+ * when focus moves between checkboxes inside the group.
282
+ *
283
+ * @param {!FocusEvent} event
284
+ * @return {boolean}
285
+ * @protected
286
+ */
287
+ _shouldRemoveFocus(event) {
288
+ return !this.contains(event.relatedTarget);
289
+ }
290
+
291
+ /**
292
+ * Override method inherited from `FocusMixin`
293
+ * to run validation when the group loses focus.
294
+ *
295
+ * @param {boolean} focused
296
+ * @override
297
+ * @protected
298
+ */
299
+ _setFocused(focused) {
300
+ super._setFocused(focused);
301
+
302
+ // Do not validate when focusout is caused by document
303
+ // losing focus, which happens on browser tab switch.
304
+ if (!focused && document.hasFocus()) {
305
+ this.validate();
306
+ }
307
+ }
308
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const checkboxGroupStyles: CSSResult;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
7
+
8
+ export const checkboxGroupStyles = css`
9
+ :host {
10
+ display: inline-flex;
11
+ }
12
+
13
+ :host::before {
14
+ content: '\\2003';
15
+ width: 0;
16
+ display: inline-block;
17
+ }
18
+
19
+ :host([hidden]) {
20
+ display: none !important;
21
+ }
22
+
23
+ .vaadin-group-field-container {
24
+ display: flex;
25
+ flex-direction: column;
26
+ width: 100%;
27
+ }
28
+
29
+ [part='group-field'] {
30
+ display: flex;
31
+ flex-wrap: wrap;
32
+ }
33
+
34
+ :host(:not([has-label])) [part='label'] {
35
+ display: none;
36
+ }
37
+ `;
@@ -1,13 +1,11 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2018 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2018 - 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 { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
7
- import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
8
6
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
9
- import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
10
7
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
+ import { CheckboxGroupMixin } from './vaadin-checkbox-group-mixin.js';
11
9
 
12
10
  /**
13
11
  * Fired when the `invalid` property changes.
@@ -63,6 +61,7 @@ export interface CheckboxGroupEventMap extends HTMLElementEventMap, CheckboxGrou
63
61
  * Attribute | Description | Part name
64
62
  * --------------------|-------------------------------------------|------------
65
63
  * `disabled` | Set when the element is disabled | :host
64
+ * `readonly` | Set when the element is readonly | :host
66
65
  * `invalid` | Set when the element is invalid | :host
67
66
  * `focused` | Set when the element is focused | :host
68
67
  * `has-label` | Set when the element has a label | :host
@@ -76,15 +75,7 @@ export interface CheckboxGroupEventMap extends HTMLElementEventMap, CheckboxGrou
76
75
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
77
76
  * @fires {CustomEvent} validated - Fired whenever the field is validated.
78
77
  */
79
- declare class CheckboxGroup extends FieldMixin(FocusMixin(DisabledMixin(ElementMixin(ThemableMixin(HTMLElement))))) {
80
- /**
81
- * An array containing values of the currently checked checkboxes.
82
- *
83
- * The array is immutable so toggling checkboxes always results in
84
- * creating a new array.
85
- */
86
- value: string[];
87
-
78
+ declare class CheckboxGroup extends CheckboxGroupMixin(ElementMixin(ThemableMixin(HTMLElement))) {
88
79
  addEventListener<K extends keyof CheckboxGroupEventMap>(
89
80
  type: K,
90
81
  listener: (this: CheckboxGroup, ev: CheckboxGroupEventMap[K]) => void,
@@ -1,18 +1,17 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2018 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2018 - 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 '@vaadin/checkbox/src/vaadin-checkbox.js';
6
7
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
7
- import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
8
- import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
9
- import { Checkbox } from '@vaadin/checkbox/src/vaadin-checkbox.js';
10
8
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
11
9
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
12
- import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
13
- import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
14
- import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
15
- import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
+ import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
+ import { CheckboxGroupMixin } from './vaadin-checkbox-group-mixin.js';
12
+ import { checkboxGroupStyles } from './vaadin-checkbox-group-styles.js';
13
+
14
+ registerStyles('vaadin-checkbox-group', checkboxGroupStyles, { moduleId: 'vaadin-checkbox-group-styles' });
16
15
 
17
16
  /**
18
17
  * `<vaadin-checkbox-group>` is a web component that allows the user to choose several items from a group of binary choices.
@@ -43,6 +42,7 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
43
42
  * Attribute | Description | Part name
44
43
  * --------------------|-------------------------------------------|------------
45
44
  * `disabled` | Set when the element is disabled | :host
45
+ * `readonly` | Set when the element is readonly | :host
46
46
  * `invalid` | Set when the element is invalid | :host
47
47
  * `focused` | Set when the element is focused | :host
48
48
  * `has-label` | Set when the element has a label | :host
@@ -59,49 +59,16 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
59
59
  * @customElement
60
60
  * @extends HTMLElement
61
61
  * @mixes ThemableMixin
62
- * @mixes DisabledMixin
63
62
  * @mixes ElementMixin
64
- * @mixes FocusMixin
65
- * @mixes FieldMixin
63
+ * @mixes CheckboxGroupMixin
66
64
  */
67
- class CheckboxGroup extends FieldMixin(FocusMixin(DisabledMixin(ElementMixin(ThemableMixin(PolymerElement))))) {
65
+ class CheckboxGroup extends CheckboxGroupMixin(ElementMixin(ThemableMixin(PolymerElement))) {
68
66
  static get is() {
69
67
  return 'vaadin-checkbox-group';
70
68
  }
71
69
 
72
70
  static get template() {
73
71
  return html`
74
- <style>
75
- :host {
76
- display: inline-flex;
77
- }
78
-
79
- :host::before {
80
- content: '\\2003';
81
- width: 0;
82
- display: inline-block;
83
- }
84
-
85
- :host([hidden]) {
86
- display: none !important;
87
- }
88
-
89
- .vaadin-group-field-container {
90
- display: flex;
91
- flex-direction: column;
92
- width: 100%;
93
- }
94
-
95
- [part='group-field'] {
96
- display: flex;
97
- flex-wrap: wrap;
98
- }
99
-
100
- :host(:not([has-label])) [part='label'] {
101
- display: none;
102
- }
103
- </style>
104
-
105
72
  <div class="vaadin-group-field-container">
106
73
  <div part="label">
107
74
  <slot name="label"></slot>
@@ -124,265 +91,6 @@ class CheckboxGroup extends FieldMixin(FocusMixin(DisabledMixin(ElementMixin(The
124
91
  <slot name="tooltip"></slot>
125
92
  `;
126
93
  }
127
-
128
- static get properties() {
129
- return {
130
- /**
131
- * An array containing values of the currently checked checkboxes.
132
- *
133
- * The array is immutable so toggling checkboxes always results in
134
- * creating a new array.
135
- *
136
- * @type {!Array<!string>}
137
- */
138
- value: {
139
- type: Array,
140
- value: () => [],
141
- notify: true,
142
- observer: '__valueChanged',
143
- },
144
- };
145
- }
146
-
147
- constructor() {
148
- super();
149
-
150
- this.__registerCheckbox = this.__registerCheckbox.bind(this);
151
- this.__unregisterCheckbox = this.__unregisterCheckbox.bind(this);
152
- this.__onCheckboxCheckedChanged = this.__onCheckboxCheckedChanged.bind(this);
153
-
154
- this._tooltipController = new TooltipController(this);
155
- this._tooltipController.addEventListener('tooltip-changed', (event) => {
156
- const tooltip = event.detail.node;
157
- if (tooltip && tooltip.isConnected) {
158
- // Tooltip element has been added to the DOM
159
- const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
160
- this._tooltipController.setAriaTarget(inputs);
161
- } else {
162
- // Tooltip element is no longer connected
163
- this._tooltipController.setAriaTarget([]);
164
- }
165
- });
166
- }
167
-
168
- /**
169
- * A collection of the checkboxes.
170
- *
171
- * @return {!Array<!Checkbox>}
172
- * @private
173
- */
174
- get __checkboxes() {
175
- return this.__filterCheckboxes([...this.children]);
176
- }
177
-
178
- /** @protected */
179
- ready() {
180
- super.ready();
181
-
182
- this.ariaTarget = this;
183
-
184
- // See https://github.com/vaadin/vaadin-web-components/issues/94
185
- this.setAttribute('role', 'group');
186
-
187
- const slot = this.shadowRoot.querySelector('slot:not([name])');
188
- this._observer = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
189
- const addedCheckboxes = this.__filterCheckboxes(addedNodes);
190
- const removedCheckboxes = this.__filterCheckboxes(removedNodes);
191
-
192
- addedCheckboxes.forEach(this.__registerCheckbox);
193
- removedCheckboxes.forEach(this.__unregisterCheckbox);
194
-
195
- const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
196
- this._tooltipController.setAriaTarget(inputs);
197
-
198
- this.__warnOfCheckboxesWithoutValue(addedCheckboxes);
199
- });
200
-
201
- this.addController(this._tooltipController);
202
- }
203
-
204
- /**
205
- * Override method inherited from `ValidateMixin`
206
- * to validate the value array.
207
- *
208
- * @override
209
- * @return {boolean}
210
- */
211
- checkValidity() {
212
- return !this.required || this.value.length > 0;
213
- }
214
-
215
- /**
216
- * @param {!Array<!Node>} nodes
217
- * @return {!Array<!Checkbox>}
218
- * @private
219
- */
220
- __filterCheckboxes(nodes) {
221
- return nodes.filter((child) => child instanceof Checkbox);
222
- }
223
-
224
- /**
225
- * @param {!Array<!Checkbox>} checkboxes
226
- * @private
227
- */
228
- __warnOfCheckboxesWithoutValue(checkboxes) {
229
- const hasCheckboxesWithoutValue = checkboxes.some((checkbox) => {
230
- const { value } = checkbox;
231
-
232
- return !checkbox.hasAttribute('value') && (!value || value === 'on');
233
- });
234
-
235
- if (hasCheckboxesWithoutValue) {
236
- console.warn('Please provide the value attribute to all the checkboxes inside the checkbox group.');
237
- }
238
- }
239
-
240
- /**
241
- * Registers the checkbox after adding it to the group.
242
- *
243
- * @param {!Checkbox} checkbox
244
- * @private
245
- */
246
- __registerCheckbox(checkbox) {
247
- checkbox.addEventListener('checked-changed', this.__onCheckboxCheckedChanged);
248
-
249
- if (this.disabled) {
250
- checkbox.disabled = true;
251
- }
252
-
253
- if (checkbox.checked) {
254
- this.__addCheckboxToValue(checkbox.value);
255
- } else if (this.value.includes(checkbox.value)) {
256
- checkbox.checked = true;
257
- }
258
- }
259
-
260
- /**
261
- * Unregisters the checkbox before removing it from the group.
262
- *
263
- * @param {!Checkbox} checkbox
264
- * @private
265
- */
266
- __unregisterCheckbox(checkbox) {
267
- checkbox.removeEventListener('checked-changed', this.__onCheckboxCheckedChanged);
268
-
269
- if (checkbox.checked) {
270
- this.__removeCheckboxFromValue(checkbox.value);
271
- }
272
- }
273
-
274
- /**
275
- * Override method inherited from `DisabledMixin`
276
- * to propagate the `disabled` property to the checkboxes.
277
- *
278
- * @param {boolean} newValue
279
- * @param {boolean} oldValue
280
- * @override
281
- * @protected
282
- */
283
- _disabledChanged(newValue, oldValue) {
284
- super._disabledChanged(newValue, oldValue);
285
-
286
- // Prevent updating the `disabled` property for the checkboxes at initialization.
287
- // Otherwise, the checkboxes may end up enabled regardless the `disabled` attribute
288
- // intentionally added by the user on some of them.
289
- if (!newValue && oldValue === undefined) {
290
- return;
291
- }
292
-
293
- if (oldValue !== newValue) {
294
- this.__checkboxes.forEach((checkbox) => {
295
- checkbox.disabled = newValue;
296
- });
297
- }
298
- }
299
-
300
- /**
301
- * @param {string} value
302
- * @private
303
- */
304
- __addCheckboxToValue(value) {
305
- if (!this.value.includes(value)) {
306
- this.value = [...this.value, value];
307
- }
308
- }
309
-
310
- /**
311
- * @param {string} value
312
- * @private
313
- */
314
- __removeCheckboxFromValue(value) {
315
- if (this.value.includes(value)) {
316
- this.value = this.value.filter((v) => v !== value);
317
- }
318
- }
319
-
320
- /**
321
- * @param {!CustomEvent} event
322
- * @private
323
- */
324
- __onCheckboxCheckedChanged(event) {
325
- const checkbox = event.target;
326
-
327
- if (checkbox.checked) {
328
- this.__addCheckboxToValue(checkbox.value);
329
- } else {
330
- this.__removeCheckboxFromValue(checkbox.value);
331
- }
332
- }
333
-
334
- /**
335
- * @param {string | null | undefined} value
336
- * @param {string | null | undefined} oldValue
337
- * @private
338
- */
339
- __valueChanged(value, oldValue) {
340
- // Setting initial value to empty array, skip validation
341
- if (value.length === 0 && oldValue === undefined) {
342
- return;
343
- }
344
-
345
- this.toggleAttribute('has-value', value.length > 0);
346
-
347
- this.__checkboxes.forEach((checkbox) => {
348
- checkbox.checked = value.includes(checkbox.value);
349
- });
350
-
351
- if (oldValue !== undefined) {
352
- this.validate();
353
- }
354
- }
355
-
356
- /**
357
- * Override method inherited from `FocusMixin`
358
- * to prevent removing the `focused` attribute
359
- * when focus moves between checkboxes inside the group.
360
- *
361
- * @param {!FocusEvent} event
362
- * @return {boolean}
363
- * @protected
364
- */
365
- _shouldRemoveFocus(event) {
366
- return !this.contains(event.relatedTarget);
367
- }
368
-
369
- /**
370
- * Override method inherited from `FocusMixin`
371
- * to run validation when the group loses focus.
372
- *
373
- * @param {boolean} focused
374
- * @override
375
- * @protected
376
- */
377
- _setFocused(focused) {
378
- super._setFocused(focused);
379
-
380
- // Do not validate when focusout is caused by document
381
- // losing focus, which happens on browser tab switch.
382
- if (!focused && document.hasFocus()) {
383
- this.validate();
384
- }
385
- }
386
94
  }
387
95
 
388
96
  defineCustomElement(CheckboxGroup);
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ export * from './vaadin-checkbox-group.js';
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import '@vaadin/checkbox/src/vaadin-lit-checkbox.js';
7
+ import { html, LitElement } from 'lit';
8
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
9
+ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
11
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
+ import { CheckboxGroupMixin } from './vaadin-checkbox-group-mixin.js';
13
+ import { checkboxGroupStyles } from './vaadin-checkbox-group-styles.js';
14
+
15
+ /**
16
+ * LitElement based version of `<vaadin-checkbox-group>` web component.
17
+ *
18
+ * ## Disclaimer
19
+ *
20
+ * This component is an experiment and not yet a part of Vaadin platform.
21
+ * There is no ETA regarding specific Vaadin version where it'll land.
22
+ * Feel free to try this code in your apps as per Apache 2.0 license.
23
+ */
24
+ class CheckboxGroup extends CheckboxGroupMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
25
+ static get is() {
26
+ return 'vaadin-checkbox-group';
27
+ }
28
+
29
+ static get styles() {
30
+ return checkboxGroupStyles;
31
+ }
32
+
33
+ /** @protected */
34
+ render() {
35
+ return html`
36
+ <div class="vaadin-group-field-container">
37
+ <div part="label">
38
+ <slot name="label"></slot>
39
+ <span part="required-indicator" aria-hidden="true"></span>
40
+ </div>
41
+
42
+ <div part="group-field">
43
+ <slot></slot>
44
+ </div>
45
+
46
+ <div part="helper-text">
47
+ <slot name="helper"></slot>
48
+ </div>
49
+
50
+ <div part="error-message">
51
+ <slot name="error-message"></slot>
52
+ </div>
53
+ </div>
54
+
55
+ <slot name="tooltip"></slot>
56
+ `;
57
+ }
58
+ }
59
+
60
+ defineCustomElement(CheckboxGroup);
61
+
62
+ export { CheckboxGroup };
@@ -0,0 +1,5 @@
1
+ import '@vaadin/vaadin-lumo-styles/color.js';
2
+ import '@vaadin/vaadin-lumo-styles/sizing.js';
3
+ import '@vaadin/vaadin-lumo-styles/spacing.js';
4
+ import '@vaadin/vaadin-lumo-styles/style.js';
5
+ import '@vaadin/vaadin-lumo-styles/typography.js';
@@ -39,14 +39,14 @@ const checkboxGroup = css`
39
39
  color: var(--lumo-primary-text-color);
40
40
  }
41
41
 
42
- :host(:hover:not([disabled]):not([focused])) [part='label'],
43
- :host(:hover:not([disabled]):not([focused])) [part='helper-text'] {
42
+ :host(:hover:not([readonly]):not([disabled]):not([focused])) [part='label'],
43
+ :host(:hover:not([readonly]):not([disabled]):not([focused])) [part='helper-text'] {
44
44
  color: var(--lumo-body-text-color);
45
45
  }
46
46
 
47
47
  /* Touch device adjustment */
48
48
  @media (pointer: coarse) {
49
- :host(:hover:not([disabled]):not([focused])) [part='label'] {
49
+ :host(:hover:not([readonly]):not([disabled]):not([focused])) [part='label'] {
50
50
  color: var(--lumo-secondary-text-color);
51
51
  }
52
52
  }
@@ -0,0 +1,3 @@
1
+ import '@vaadin/checkbox/theme/lumo/vaadin-checkbox.js';
2
+ import './vaadin-checkbox-group-styles.js';
3
+ import '../../src/vaadin-checkbox-group.js';
@@ -0,0 +1 @@
1
+ import '@vaadin/vaadin-material-styles/color.js';
@@ -0,0 +1,3 @@
1
+ import '@vaadin/checkbox/theme/material/vaadin-checkbox.js';
2
+ import './vaadin-checkbox-group-styles.js';
3
+ import '../../src/vaadin-checkbox-group.js';
package/web-types.json ADDED
@@ -0,0 +1,254 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/web-types",
3
+ "name": "@vaadin/checkbox-group",
4
+ "version": "24.5.0-alpha1",
5
+ "description-markup": "markdown",
6
+ "contributions": {
7
+ "html": {
8
+ "elements": [
9
+ {
10
+ "name": "vaadin-checkbox-group",
11
+ "description": "`<vaadin-checkbox-group>` is a web component that allows the user to choose several items from a group of binary choices.\n\n```html\n<vaadin-checkbox-group label=\"Export data\">\n <vaadin-checkbox value=\"0\" label=\"Order ID\"></vaadin-checkbox>\n <vaadin-checkbox value=\"1\" label=\"Product name\"></vaadin-checkbox>\n <vaadin-checkbox value=\"2\" label=\"Customer\"></vaadin-checkbox>\n <vaadin-checkbox value=\"3\" label=\"Status\"></vaadin-checkbox>\n</vaadin-checkbox-group>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The slotted label element wrapper\n`group-field` | The checkbox elements 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 | Part name\n--------------------|-------------------------------------------|------------\n`disabled` | Set when the element is disabled | :host\n`readonly` | Set when the element is readonly | :host\n`invalid` | Set when the element is invalid | :host\n`focused` | Set when the element is focused | :host\n`has-label` | Set when the element has a label | :host\n`has-value` | Set when the element has a value | :host\n`has-helper` | Set when the element has helper text | :host\n`has-error-message` | Set when the element has an error message | :host\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
+ "attributes": [
13
+ {
14
+ "name": "disabled",
15
+ "description": "If true, the user cannot interact with this element.",
16
+ "value": {
17
+ "type": [
18
+ "boolean",
19
+ "null",
20
+ "undefined"
21
+ ]
22
+ }
23
+ },
24
+ {
25
+ "name": "label",
26
+ "description": "The label text for the input node.\nWhen no light dom defined via [slot=label], this value will be used.",
27
+ "value": {
28
+ "type": [
29
+ "string",
30
+ "null",
31
+ "undefined"
32
+ ]
33
+ }
34
+ },
35
+ {
36
+ "name": "invalid",
37
+ "description": "Set to true when the field is invalid.",
38
+ "value": {
39
+ "type": [
40
+ "boolean",
41
+ "null",
42
+ "undefined"
43
+ ]
44
+ }
45
+ },
46
+ {
47
+ "name": "required",
48
+ "description": "Specifies that the user must fill in a value.",
49
+ "value": {
50
+ "type": [
51
+ "boolean",
52
+ "null",
53
+ "undefined"
54
+ ]
55
+ }
56
+ },
57
+ {
58
+ "name": "error-message",
59
+ "description": "Error to show when the field is invalid.",
60
+ "value": {
61
+ "type": [
62
+ "string",
63
+ "null",
64
+ "undefined"
65
+ ]
66
+ }
67
+ },
68
+ {
69
+ "name": "helper-text",
70
+ "description": "String used for the helper text.",
71
+ "value": {
72
+ "type": [
73
+ "string",
74
+ "null",
75
+ "undefined"
76
+ ]
77
+ }
78
+ },
79
+ {
80
+ "name": "accessible-name",
81
+ "description": "String used to label the component to screen reader users.",
82
+ "value": {
83
+ "type": [
84
+ "string",
85
+ "null",
86
+ "undefined"
87
+ ]
88
+ }
89
+ },
90
+ {
91
+ "name": "accessible-name-ref",
92
+ "description": "Id of the element used as label of the component to screen reader users.",
93
+ "value": {
94
+ "type": [
95
+ "string",
96
+ "null",
97
+ "undefined"
98
+ ]
99
+ }
100
+ },
101
+ {
102
+ "name": "readonly",
103
+ "description": "When true, the user cannot modify the value of the checkbox group.\nThe difference between `disabled` and `readonly` is that in the\nread-only checkbox group, all the checkboxes are also read-only,\nand therefore remain focusable and announced by screen readers.",
104
+ "value": {
105
+ "type": [
106
+ "boolean",
107
+ "null",
108
+ "undefined"
109
+ ]
110
+ }
111
+ },
112
+ {
113
+ "name": "theme",
114
+ "description": "The theme variants to apply to the component.",
115
+ "value": {
116
+ "type": [
117
+ "string",
118
+ "null",
119
+ "undefined"
120
+ ]
121
+ }
122
+ }
123
+ ],
124
+ "js": {
125
+ "properties": [
126
+ {
127
+ "name": "disabled",
128
+ "description": "If true, the user cannot interact with this element.",
129
+ "value": {
130
+ "type": [
131
+ "boolean",
132
+ "null",
133
+ "undefined"
134
+ ]
135
+ }
136
+ },
137
+ {
138
+ "name": "label",
139
+ "description": "The label text for the input node.\nWhen no light dom defined via [slot=label], this value will be used.",
140
+ "value": {
141
+ "type": [
142
+ "string",
143
+ "null",
144
+ "undefined"
145
+ ]
146
+ }
147
+ },
148
+ {
149
+ "name": "invalid",
150
+ "description": "Set to true when the field is invalid.",
151
+ "value": {
152
+ "type": [
153
+ "boolean",
154
+ "null",
155
+ "undefined"
156
+ ]
157
+ }
158
+ },
159
+ {
160
+ "name": "required",
161
+ "description": "Specifies that the user must fill in a value.",
162
+ "value": {
163
+ "type": [
164
+ "boolean",
165
+ "null",
166
+ "undefined"
167
+ ]
168
+ }
169
+ },
170
+ {
171
+ "name": "errorMessage",
172
+ "description": "Error to show when the field is invalid.",
173
+ "value": {
174
+ "type": [
175
+ "string",
176
+ "null",
177
+ "undefined"
178
+ ]
179
+ }
180
+ },
181
+ {
182
+ "name": "helperText",
183
+ "description": "String used for the helper text.",
184
+ "value": {
185
+ "type": [
186
+ "string",
187
+ "null",
188
+ "undefined"
189
+ ]
190
+ }
191
+ },
192
+ {
193
+ "name": "accessibleName",
194
+ "description": "String used to label the component to screen reader users.",
195
+ "value": {
196
+ "type": [
197
+ "string",
198
+ "null",
199
+ "undefined"
200
+ ]
201
+ }
202
+ },
203
+ {
204
+ "name": "accessibleNameRef",
205
+ "description": "Id of the element used as label of the component to screen reader users.",
206
+ "value": {
207
+ "type": [
208
+ "string",
209
+ "null",
210
+ "undefined"
211
+ ]
212
+ }
213
+ },
214
+ {
215
+ "name": "value",
216
+ "description": "An array containing values of the currently checked checkboxes.\n\nThe array is immutable so toggling checkboxes always results in\ncreating a new array.",
217
+ "value": {
218
+ "type": [
219
+ "Array.<string>"
220
+ ]
221
+ }
222
+ },
223
+ {
224
+ "name": "readonly",
225
+ "description": "When true, the user cannot modify the value of the checkbox group.\nThe difference between `disabled` and `readonly` is that in the\nread-only checkbox group, all the checkboxes are also read-only,\nand therefore remain focusable and announced by screen readers.",
226
+ "value": {
227
+ "type": [
228
+ "boolean",
229
+ "null",
230
+ "undefined"
231
+ ]
232
+ }
233
+ }
234
+ ],
235
+ "events": [
236
+ {
237
+ "name": "validated",
238
+ "description": "Fired whenever the field is validated."
239
+ },
240
+ {
241
+ "name": "invalid-changed",
242
+ "description": "Fired when the `invalid` property changes."
243
+ },
244
+ {
245
+ "name": "value-changed",
246
+ "description": "Fired when the `value` property changes."
247
+ }
248
+ ]
249
+ }
250
+ }
251
+ ]
252
+ }
253
+ }
254
+ }
@@ -0,0 +1,118 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/web-types",
3
+ "name": "@vaadin/checkbox-group",
4
+ "version": "24.5.0-alpha1",
5
+ "description-markup": "markdown",
6
+ "framework": "lit",
7
+ "framework-config": {
8
+ "enable-when": {
9
+ "node-packages": [
10
+ "lit"
11
+ ]
12
+ }
13
+ },
14
+ "contributions": {
15
+ "html": {
16
+ "elements": [
17
+ {
18
+ "name": "vaadin-checkbox-group",
19
+ "description": "`<vaadin-checkbox-group>` is a web component that allows the user to choose several items from a group of binary choices.\n\n```html\n<vaadin-checkbox-group label=\"Export data\">\n <vaadin-checkbox value=\"0\" label=\"Order ID\"></vaadin-checkbox>\n <vaadin-checkbox value=\"1\" label=\"Product name\"></vaadin-checkbox>\n <vaadin-checkbox value=\"2\" label=\"Customer\"></vaadin-checkbox>\n <vaadin-checkbox value=\"3\" label=\"Status\"></vaadin-checkbox>\n</vaadin-checkbox-group>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The slotted label element wrapper\n`group-field` | The checkbox elements 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 | Part name\n--------------------|-------------------------------------------|------------\n`disabled` | Set when the element is disabled | :host\n`readonly` | Set when the element is readonly | :host\n`invalid` | Set when the element is invalid | :host\n`focused` | Set when the element is focused | :host\n`has-label` | Set when the element has a label | :host\n`has-value` | Set when the element has a value | :host\n`has-helper` | Set when the element has helper text | :host\n`has-error-message` | Set when the element has an error message | :host\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
+ "extension": true,
21
+ "attributes": [
22
+ {
23
+ "name": "?disabled",
24
+ "description": "If true, the user cannot interact with this element.",
25
+ "value": {
26
+ "kind": "expression"
27
+ }
28
+ },
29
+ {
30
+ "name": "?invalid",
31
+ "description": "Set to true when the field is invalid.",
32
+ "value": {
33
+ "kind": "expression"
34
+ }
35
+ },
36
+ {
37
+ "name": "?required",
38
+ "description": "Specifies that the user must fill in a value.",
39
+ "value": {
40
+ "kind": "expression"
41
+ }
42
+ },
43
+ {
44
+ "name": "?readonly",
45
+ "description": "When true, the user cannot modify the value of the checkbox group.\nThe difference between `disabled` and `readonly` is that in the\nread-only checkbox group, all the checkboxes are also read-only,\nand therefore remain focusable and announced by screen readers.",
46
+ "value": {
47
+ "kind": "expression"
48
+ }
49
+ },
50
+ {
51
+ "name": ".label",
52
+ "description": "The label text for the input node.\nWhen no light dom defined via [slot=label], this value will be used.",
53
+ "value": {
54
+ "kind": "expression"
55
+ }
56
+ },
57
+ {
58
+ "name": ".errorMessage",
59
+ "description": "Error to show when the field is invalid.",
60
+ "value": {
61
+ "kind": "expression"
62
+ }
63
+ },
64
+ {
65
+ "name": ".helperText",
66
+ "description": "String used for the helper text.",
67
+ "value": {
68
+ "kind": "expression"
69
+ }
70
+ },
71
+ {
72
+ "name": ".accessibleName",
73
+ "description": "String used to label the component to screen reader users.",
74
+ "value": {
75
+ "kind": "expression"
76
+ }
77
+ },
78
+ {
79
+ "name": ".accessibleNameRef",
80
+ "description": "Id of the element used as label of the component to screen reader users.",
81
+ "value": {
82
+ "kind": "expression"
83
+ }
84
+ },
85
+ {
86
+ "name": ".value",
87
+ "description": "An array containing values of the currently checked checkboxes.\n\nThe array is immutable so toggling checkboxes always results in\ncreating a new array.",
88
+ "value": {
89
+ "kind": "expression"
90
+ }
91
+ },
92
+ {
93
+ "name": "@validated",
94
+ "description": "Fired whenever the field is validated.",
95
+ "value": {
96
+ "kind": "expression"
97
+ }
98
+ },
99
+ {
100
+ "name": "@invalid-changed",
101
+ "description": "Fired when the `invalid` property changes.",
102
+ "value": {
103
+ "kind": "expression"
104
+ }
105
+ },
106
+ {
107
+ "name": "@value-changed",
108
+ "description": "Fired when the `value` property changes.",
109
+ "value": {
110
+ "kind": "expression"
111
+ }
112
+ }
113
+ ]
114
+ }
115
+ ]
116
+ }
117
+ }
118
+ }