@vaadin/checkbox-group 24.4.0-alpha2 → 24.4.0-alpha21

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-alpha2",
3
+ "version": "24.4.0-alpha21",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,14 +35,15 @@
35
35
  "polymer"
36
36
  ],
37
37
  "dependencies": {
38
+ "@open-wc/dedupe-mixin": "^1.3.0",
38
39
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/a11y-base": "24.4.0-alpha2",
40
- "@vaadin/checkbox": "24.4.0-alpha2",
41
- "@vaadin/component-base": "24.4.0-alpha2",
42
- "@vaadin/field-base": "24.4.0-alpha2",
43
- "@vaadin/vaadin-lumo-styles": "24.4.0-alpha2",
44
- "@vaadin/vaadin-material-styles": "24.4.0-alpha2",
45
- "@vaadin/vaadin-themable-mixin": "24.4.0-alpha2"
40
+ "@vaadin/a11y-base": "24.4.0-alpha21",
41
+ "@vaadin/checkbox": "24.4.0-alpha21",
42
+ "@vaadin/component-base": "24.4.0-alpha21",
43
+ "@vaadin/field-base": "24.4.0-alpha21",
44
+ "@vaadin/vaadin-lumo-styles": "24.4.0-alpha21",
45
+ "@vaadin/vaadin-material-styles": "24.4.0-alpha21",
46
+ "@vaadin/vaadin-themable-mixin": "24.4.0-alpha21"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@esm-bundle/chai": "^4.3.4",
@@ -53,5 +54,5 @@
53
54
  "web-types.json",
54
55
  "web-types.lit.json"
55
56
  ],
56
- "gitHead": "f303ead58d27e15d81a55db0559611fb77c0e421"
57
+ "gitHead": "2efeeebbeabddfde14c845ee4098f9e62e352ffe"
57
58
  }
@@ -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,307 @@
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
+ observer: '__valueChanged',
38
+ },
39
+
40
+ /**
41
+ * When true, the user cannot modify the value of the checkbox group.
42
+ * The difference between `disabled` and `readonly` is that in the
43
+ * read-only checkbox group, all the checkboxes are also read-only,
44
+ * and therefore remain focusable and announced by screen readers.
45
+ */
46
+ readonly: {
47
+ type: Boolean,
48
+ value: false,
49
+ reflectToAttribute: true,
50
+ observer: '__readonlyChanged',
51
+ },
52
+ };
53
+ }
54
+
55
+ constructor() {
56
+ super();
57
+
58
+ this.__registerCheckbox = this.__registerCheckbox.bind(this);
59
+ this.__unregisterCheckbox = this.__unregisterCheckbox.bind(this);
60
+ this.__onCheckboxCheckedChanged = this.__onCheckboxCheckedChanged.bind(this);
61
+
62
+ this._tooltipController = new TooltipController(this);
63
+ this._tooltipController.addEventListener('tooltip-changed', (event) => {
64
+ const tooltip = event.detail.node;
65
+ if (tooltip && tooltip.isConnected) {
66
+ // Tooltip element has been added to the DOM
67
+ const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
68
+ this._tooltipController.setAriaTarget(inputs);
69
+ } else {
70
+ // Tooltip element is no longer connected
71
+ this._tooltipController.setAriaTarget([]);
72
+ }
73
+ });
74
+ }
75
+
76
+ /**
77
+ * A collection of the checkboxes.
78
+ *
79
+ * @return {!Array<!Checkbox>}
80
+ * @private
81
+ */
82
+ get __checkboxes() {
83
+ return this.__filterCheckboxes([...this.children]);
84
+ }
85
+
86
+ /** @protected */
87
+ ready() {
88
+ super.ready();
89
+
90
+ this.ariaTarget = this;
91
+
92
+ // See https://github.com/vaadin/vaadin-web-components/issues/94
93
+ this.setAttribute('role', 'group');
94
+
95
+ const slot = this.shadowRoot.querySelector('slot:not([name])');
96
+ this._observer = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
97
+ const addedCheckboxes = this.__filterCheckboxes(addedNodes);
98
+ const removedCheckboxes = this.__filterCheckboxes(removedNodes);
99
+
100
+ addedCheckboxes.forEach(this.__registerCheckbox);
101
+ removedCheckboxes.forEach(this.__unregisterCheckbox);
102
+
103
+ const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
104
+ this._tooltipController.setAriaTarget(inputs);
105
+
106
+ this.__warnOfCheckboxesWithoutValue(addedCheckboxes);
107
+ });
108
+
109
+ this.addController(this._tooltipController);
110
+ }
111
+
112
+ /**
113
+ * Override method inherited from `ValidateMixin`
114
+ * to validate the value array.
115
+ *
116
+ * @override
117
+ * @return {boolean}
118
+ */
119
+ checkValidity() {
120
+ return !this.required || this.value.length > 0;
121
+ }
122
+
123
+ /**
124
+ * @param {!Array<!Node>} nodes
125
+ * @return {!Array<!Checkbox>}
126
+ * @private
127
+ */
128
+ __filterCheckboxes(nodes) {
129
+ return nodes.filter((node) => node.nodeType === Node.ELEMENT_NODE && node.localName === 'vaadin-checkbox');
130
+ }
131
+
132
+ /**
133
+ * @param {!Array<!Checkbox>} checkboxes
134
+ * @private
135
+ */
136
+ __warnOfCheckboxesWithoutValue(checkboxes) {
137
+ const hasCheckboxesWithoutValue = checkboxes.some((checkbox) => {
138
+ const { value } = checkbox;
139
+
140
+ return !checkbox.hasAttribute('value') && (!value || value === 'on');
141
+ });
142
+
143
+ if (hasCheckboxesWithoutValue) {
144
+ console.warn('Please provide the value attribute to all the checkboxes inside the checkbox group.');
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Registers the checkbox after adding it to the group.
150
+ *
151
+ * @param {!Checkbox} checkbox
152
+ * @private
153
+ */
154
+ __registerCheckbox(checkbox) {
155
+ checkbox.addEventListener('checked-changed', this.__onCheckboxCheckedChanged);
156
+
157
+ if (this.disabled) {
158
+ checkbox.disabled = true;
159
+ }
160
+
161
+ if (this.readonly) {
162
+ checkbox.readonly = true;
163
+ }
164
+
165
+ if (checkbox.checked) {
166
+ this.__addCheckboxToValue(checkbox.value);
167
+ } else if (this.value.includes(checkbox.value)) {
168
+ checkbox.checked = true;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Unregisters the checkbox before removing it from the group.
174
+ *
175
+ * @param {!Checkbox} checkbox
176
+ * @private
177
+ */
178
+ __unregisterCheckbox(checkbox) {
179
+ checkbox.removeEventListener('checked-changed', this.__onCheckboxCheckedChanged);
180
+
181
+ if (checkbox.checked) {
182
+ this.__removeCheckboxFromValue(checkbox.value);
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Override method inherited from `DisabledMixin`
188
+ * to propagate the `disabled` property to the checkboxes.
189
+ *
190
+ * @param {boolean} newValue
191
+ * @param {boolean} oldValue
192
+ * @override
193
+ * @protected
194
+ */
195
+ _disabledChanged(newValue, oldValue) {
196
+ super._disabledChanged(newValue, oldValue);
197
+
198
+ // Prevent updating the `disabled` property for the checkboxes at initialization.
199
+ // Otherwise, the checkboxes may end up enabled regardless the `disabled` attribute
200
+ // intentionally added by the user on some of them.
201
+ if (!newValue && oldValue === undefined) {
202
+ return;
203
+ }
204
+
205
+ if (oldValue !== newValue) {
206
+ this.__checkboxes.forEach((checkbox) => {
207
+ checkbox.disabled = newValue;
208
+ });
209
+ }
210
+ }
211
+
212
+ /**
213
+ * @param {string} value
214
+ * @private
215
+ */
216
+ __addCheckboxToValue(value) {
217
+ if (!this.value.includes(value)) {
218
+ this.value = [...this.value, value];
219
+ }
220
+ }
221
+
222
+ /**
223
+ * @param {string} value
224
+ * @private
225
+ */
226
+ __removeCheckboxFromValue(value) {
227
+ if (this.value.includes(value)) {
228
+ this.value = this.value.filter((v) => v !== value);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * @param {!CustomEvent} event
234
+ * @private
235
+ */
236
+ __onCheckboxCheckedChanged(event) {
237
+ const checkbox = event.target;
238
+
239
+ if (checkbox.checked) {
240
+ this.__addCheckboxToValue(checkbox.value);
241
+ } else {
242
+ this.__removeCheckboxFromValue(checkbox.value);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * @param {string | null | undefined} value
248
+ * @param {string | null | undefined} oldValue
249
+ * @private
250
+ */
251
+ __valueChanged(value, oldValue) {
252
+ // Setting initial value to empty array, skip validation
253
+ if (value.length === 0 && oldValue === undefined) {
254
+ return;
255
+ }
256
+
257
+ this.toggleAttribute('has-value', value.length > 0);
258
+
259
+ this.__checkboxes.forEach((checkbox) => {
260
+ checkbox.checked = value.includes(checkbox.value);
261
+ });
262
+
263
+ if (oldValue !== undefined) {
264
+ this.validate();
265
+ }
266
+ }
267
+
268
+ /** @private */
269
+ __readonlyChanged(readonly, oldReadonly) {
270
+ if (readonly || oldReadonly) {
271
+ this.__checkboxes.forEach((checkbox) => {
272
+ checkbox.readonly = readonly;
273
+ });
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Override method inherited from `FocusMixin`
279
+ * to prevent removing the `focused` attribute
280
+ * when focus moves between checkboxes inside the group.
281
+ *
282
+ * @param {!FocusEvent} event
283
+ * @return {boolean}
284
+ * @protected
285
+ */
286
+ _shouldRemoveFocus(event) {
287
+ return !this.contains(event.relatedTarget);
288
+ }
289
+
290
+ /**
291
+ * Override method inherited from `FocusMixin`
292
+ * to run validation when the group loses focus.
293
+ *
294
+ * @param {boolean} focused
295
+ * @override
296
+ * @protected
297
+ */
298
+ _setFocused(focused) {
299
+ super._setFocused(focused);
300
+
301
+ // Do not validate when focusout is caused by document
302
+ // losing focus, which happens on browser tab switch.
303
+ if (!focused && document.hasFocus()) {
304
+ this.validate();
305
+ }
306
+ }
307
+ };
@@ -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
+ `;
@@ -3,11 +3,9 @@
3
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,
@@ -3,16 +3,15 @@
3
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,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';
@@ -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 CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/checkbox-group",
4
- "version": "24.4.0-alpha2",
4
+ "version": "24.4.0-alpha21",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
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`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.",
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
12
  "attributes": [
13
13
  {
14
14
  "name": "disabled",
@@ -98,6 +98,17 @@
98
98
  ]
99
99
  }
100
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
+ },
101
112
  {
102
113
  "name": "theme",
103
114
  "description": "The theme variants to apply to the component.",
@@ -208,6 +219,17 @@
208
219
  "Array.<string>"
209
220
  ]
210
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
+ }
211
233
  }
212
234
  ],
213
235
  "events": [
@@ -215,13 +237,13 @@
215
237
  "name": "validated",
216
238
  "description": "Fired whenever the field is validated."
217
239
  },
218
- {
219
- "name": "value-changed",
220
- "description": "Fired when the `value` property changes."
221
- },
222
240
  {
223
241
  "name": "invalid-changed",
224
242
  "description": "Fired when the `invalid` property changes."
243
+ },
244
+ {
245
+ "name": "value-changed",
246
+ "description": "Fired when the `value` property changes."
225
247
  }
226
248
  ]
227
249
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/checkbox-group",
4
- "version": "24.4.0-alpha2",
4
+ "version": "24.4.0-alpha21",
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-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`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.",
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
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -40,6 +40,13 @@
40
40
  "kind": "expression"
41
41
  }
42
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
+ },
43
50
  {
44
51
  "name": ".label",
45
52
  "description": "The label text for the input node.\nWhen no light dom defined via [slot=label], this value will be used.",
@@ -90,15 +97,15 @@
90
97
  }
91
98
  },
92
99
  {
93
- "name": "@value-changed",
94
- "description": "Fired when the `value` property changes.",
100
+ "name": "@invalid-changed",
101
+ "description": "Fired when the `invalid` property changes.",
95
102
  "value": {
96
103
  "kind": "expression"
97
104
  }
98
105
  },
99
106
  {
100
- "name": "@invalid-changed",
101
- "description": "Fired when the `invalid` property changes.",
107
+ "name": "@value-changed",
108
+ "description": "Fired when the `value` property changes.",
102
109
  "value": {
103
110
  "kind": "expression"
104
111
  }