@vaadin/details 24.0.0-alpha6 → 24.0.0-alpha8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/details",
3
- "version": "24.0.0-alpha6",
3
+ "version": "24.0.0-alpha8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -37,12 +37,11 @@
37
37
  "dependencies": {
38
38
  "@open-wc/dedupe-mixin": "^1.3.0",
39
39
  "@polymer/polymer": "^3.0.0",
40
- "@vaadin/button": "24.0.0-alpha6",
41
- "@vaadin/component-base": "24.0.0-alpha6",
42
- "@vaadin/field-base": "24.0.0-alpha6",
43
- "@vaadin/vaadin-lumo-styles": "24.0.0-alpha6",
44
- "@vaadin/vaadin-material-styles": "24.0.0-alpha6",
45
- "@vaadin/vaadin-themable-mixin": "24.0.0-alpha6"
40
+ "@vaadin/button": "24.0.0-alpha8",
41
+ "@vaadin/component-base": "24.0.0-alpha8",
42
+ "@vaadin/vaadin-lumo-styles": "24.0.0-alpha8",
43
+ "@vaadin/vaadin-material-styles": "24.0.0-alpha8",
44
+ "@vaadin/vaadin-themable-mixin": "24.0.0-alpha8"
46
45
  },
47
46
  "devDependencies": {
48
47
  "@esm-bundle/chai": "^4.3.4",
@@ -53,5 +52,5 @@
53
52
  "web-types.json",
54
53
  "web-types.lit.json"
55
54
  ],
56
- "gitHead": "0004ac92b6e5f415b5fa949e0582d1d11e527b1f"
55
+ "gitHead": "476752249bb12295c500980d98a3256ad3b22b73"
57
56
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js';
7
+
8
+ /**
9
+ * A controller to manage the default content slot.
10
+ */
11
+ export class ContentController extends SlotChildObserveController {}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js';
7
+
8
+ /**
9
+ * A controller to manage the default content slot.
10
+ */
11
+ export class ContentController extends SlotChildObserveController {
12
+ /**
13
+ * Override method from `SlotController` to change
14
+ * the ID prefix for the default slot content.
15
+ *
16
+ * @param {HTMLElement} host
17
+ * @return {string}
18
+ * @protected
19
+ * @override
20
+ */
21
+ static generateId(host) {
22
+ return super.generateId(host, 'content');
23
+ }
24
+
25
+ constructor(host) {
26
+ super(host, '', null, { multiple: true });
27
+ }
28
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js';
7
+
8
+ /**
9
+ * A controller to manage the summary element.
10
+ */
11
+ export class SummaryController extends SlotChildObserveController {
12
+ /**
13
+ * String used for the summary.
14
+ */
15
+ protected summary: string | null | undefined;
16
+
17
+ /**
18
+ * Set summary based on corresponding host property.
19
+ */
20
+ setSummary(label: string | null | undefined): void;
21
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js';
7
+
8
+ /**
9
+ * A controller to manage the summary element.
10
+ */
11
+ export class SummaryController extends SlotChildObserveController {
12
+ constructor(host, tagName) {
13
+ super(host, 'summary', tagName);
14
+ }
15
+
16
+ /**
17
+ * Set summary based on corresponding host property.
18
+ *
19
+ * @param {string} summary
20
+ */
21
+ setSummary(summary) {
22
+ this.summary = summary;
23
+
24
+ // Restore the default summary, if needed.
25
+ const summaryNode = this.getSlotChild();
26
+ if (!summaryNode) {
27
+ this.restoreDefaultNode();
28
+ }
29
+
30
+ // When default summary is used, update it.
31
+ if (this.node === this.defaultNode) {
32
+ this.updateDefaultNode(this.node);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Override method inherited from `SlotChildObserveController`
38
+ * to restore and observe the default summary element.
39
+ *
40
+ * @protected
41
+ * @override
42
+ */
43
+ restoreDefaultNode() {
44
+ const { summary } = this;
45
+
46
+ // Restore the default summary.
47
+ if (summary && summary.trim() !== '') {
48
+ this.attachDefaultNode();
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Override method inherited from `SlotChildObserveController`
54
+ * to update the default summary element text content.
55
+ *
56
+ * @param {Node | undefined} node
57
+ * @protected
58
+ * @override
59
+ */
60
+ updateDefaultNode(node) {
61
+ if (node) {
62
+ node.textContent = this.summary;
63
+ }
64
+
65
+ // Notify the host after update.
66
+ super.updateDefaultNode(node);
67
+ }
68
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2017 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import type { Constructor } from '@open-wc/dedupe-mixin';
@@ -17,12 +17,7 @@ export declare class DetailsMixinClass {
17
17
  opened: boolean;
18
18
 
19
19
  /**
20
- * A content area controlled by the toggle element.
20
+ * List of elements passed to the details default slot.
21
21
  */
22
- protected _collapsible: HTMLElement;
23
-
24
- /**
25
- * An element used to toggle the content visibility.
26
- */
27
- protected _toggleElement: HTMLElement;
22
+ protected _contentElements: HTMLElement[];
28
23
  }
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2019 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
+ import { ContentController } from './content-controller.js';
6
7
 
7
8
  /**
8
9
  * A mixin providing common details functionality.
@@ -25,58 +26,54 @@ export const DetailsMixin = (superClass) =>
25
26
  },
26
27
 
27
28
  /**
28
- * A content area controlled by the toggle element.
29
+ * List of elements passed to the details default slot.
29
30
  *
30
31
  * @protected
31
32
  */
32
- _collapsible: {
33
- type: Object,
34
- },
35
-
36
- /**
37
- * An element used to toggle the content visibility.
38
- *
39
- * @type {!HTMLElement | undefined}
40
- * @protected
41
- */
42
- _toggleElement: {
43
- type: Object,
44
- observer: '_toggleElementChanged',
33
+ _contentElements: {
34
+ type: Array,
45
35
  },
46
36
  };
47
37
  }
48
38
 
49
39
  static get observers() {
50
- return ['_openedOrToggleChanged(opened, _toggleElement)', '_openedOrCollapsibleChanged(opened, _collapsible)'];
40
+ return ['_openedOrContentChanged(opened, _contentElements)'];
51
41
  }
52
42
 
53
- /** @private */
54
- _openedOrCollapsibleChanged(opened, collapsible) {
55
- if (collapsible) {
56
- collapsible.setAttribute('aria-hidden', opened ? 'false' : 'true');
57
- }
43
+ constructor() {
44
+ super();
45
+
46
+ this._contentController = new ContentController(this);
47
+
48
+ this._contentController.addEventListener('slot-content-changed', (event) => {
49
+ const content = event.target.nodes || [];
50
+
51
+ // Exclude nodes that are no longer connected
52
+ this._contentElements = content.filter((node) => node.parentNode === this);
53
+ });
58
54
  }
59
55
 
60
- /** @private */
61
- _openedOrToggleChanged(opened, toggleElement) {
62
- if (toggleElement) {
63
- toggleElement.setAttribute('aria-expanded', opened ? 'true' : 'false');
64
- }
56
+ /** @protected */
57
+ ready() {
58
+ super.ready();
59
+
60
+ this.addController(this._contentController);
61
+
62
+ // Only handle click and not keydown, because `vaadin-details-summary` uses `ButtonMixin`
63
+ // that already covers this logic, and `vaadin-accordion-heading` uses native `<button>`.
64
+ this.addEventListener('click', (event) => {
65
+ if (event.target === this.focusElement) {
66
+ this.opened = !this.opened;
67
+ }
68
+ });
65
69
  }
66
70
 
67
71
  /** @private */
68
- _toggleElementChanged(toggleElement) {
69
- if (toggleElement) {
70
- // Only handle click and not keydown, because `vaadin-details-summary` uses `ButtonMixin`
71
- // that already covers this logic, and `vaadin-accordion-heading` uses native `<button>`.
72
- toggleElement.addEventListener('click', () => {
73
- this._toggle();
72
+ _openedOrContentChanged(opened, elements) {
73
+ if (elements) {
74
+ elements.forEach((el) => {
75
+ el.setAttribute('aria-hidden', opened ? 'false' : 'true');
74
76
  });
75
77
  }
76
78
  }
77
-
78
- /** @private */
79
- _toggle() {
80
- this.opened = !this.opened;
81
- }
82
79
  };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2017 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2019 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
7
+ import { DelegateFocusMixin } from '@vaadin/component-base/src/delegate-focus-mixin.js';
8
+ import { DelegateStateMixin } from '@vaadin/component-base/src/delegate-state-mixin.js';
7
9
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
8
- import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.js';
9
- import { DelegateStateMixin } from '@vaadin/field-base/src/delegate-state-mixin.js';
10
10
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
11
  import { DetailsMixin } from './vaadin-details-mixin.js';
12
12
 
@@ -61,6 +61,12 @@ export type DetailsEventMap = DetailsCustomEventMap & HTMLElementEventMap;
61
61
  declare class Details extends DetailsMixin(
62
62
  DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement))))),
63
63
  ) {
64
+ /**
65
+ * A text that is displayed in the summary, if no
66
+ * element is assigned to the `summary` slot.
67
+ */
68
+ summary: string | null | undefined;
69
+
64
70
  addEventListener<K extends keyof DetailsEventMap>(
65
71
  type: K,
66
72
  listener: (this: Details, ev: DetailsEventMap[K]) => void,
@@ -1,32 +1,19 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2019 - 2022 Vaadin Ltd.
3
+ * Copyright (c) 2019 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import './vaadin-details-summary.js';
7
7
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
8
8
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
9
+ import { DelegateFocusMixin } from '@vaadin/component-base/src/delegate-focus-mixin.js';
10
+ import { DelegateStateMixin } from '@vaadin/component-base/src/delegate-state-mixin.js';
9
11
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
- import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
11
12
  import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
12
- import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.js';
13
- import { DelegateStateMixin } from '@vaadin/field-base/src/delegate-state-mixin.js';
14
13
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
14
+ import { SummaryController } from './summary-controller.js';
15
15
  import { DetailsMixin } from './vaadin-details-mixin.js';
16
16
 
17
- class SummaryController extends SlotController {
18
- constructor(host) {
19
- super(host, 'summary', 'vaadin-details-summary', {
20
- useUniqueId: true,
21
- initializer: (node, host) => {
22
- host._toggleElement = node;
23
- host._setFocusElement(node);
24
- host.stateTarget = node;
25
- },
26
- });
27
- }
28
- }
29
-
30
17
  /**
31
18
  * `<vaadin-details>` is a Web Component which the creates an
32
19
  * expandable panel similar to `<details>` HTML element.
@@ -66,6 +53,7 @@ class SummaryController extends SlotController {
66
53
  *
67
54
  * @extends HTMLElement
68
55
  * @mixes ControllerMixin
56
+ * @mixes DetailsMixin
69
57
  * @mixes DelegateFocusMixin
70
58
  * @mixes DelegateStateMixin
71
59
  * @mixes ElementMixin
@@ -108,6 +96,23 @@ class Details extends DetailsMixin(
108
96
  return 'vaadin-details';
109
97
  }
110
98
 
99
+ static get properties() {
100
+ return {
101
+ /**
102
+ * A text that is displayed in the summary, if no
103
+ * element is assigned to the `summary` slot.
104
+ */
105
+ summary: {
106
+ type: String,
107
+ observer: '_summaryChanged',
108
+ },
109
+ };
110
+ }
111
+
112
+ static get observers() {
113
+ return ['__updateAriaControls(focusElement, _contentElements)', '__updateAriaExpanded(focusElement, opened)'];
114
+ }
115
+
111
116
  static get delegateAttrs() {
112
117
  return ['theme'];
113
118
  }
@@ -116,24 +121,31 @@ class Details extends DetailsMixin(
116
121
  return ['disabled', 'opened'];
117
122
  }
118
123
 
119
- /** @protected */
120
- ready() {
121
- super.ready();
124
+ constructor() {
125
+ super();
122
126
 
123
- // TODO: Generate unique IDs for a summary and a content panel when added to the slot,
124
- // and use them to set `aria-controls` and `aria-labelledby` attributes, respectively.
127
+ this._summaryController = new SummaryController(this, 'vaadin-details-summary');
128
+ this._summaryController.addEventListener('slot-content-changed', (event) => {
129
+ const { node } = event.target;
125
130
 
126
- this._collapsible = this.shadowRoot.querySelector('[part="content"]');
131
+ this._setFocusElement(node);
132
+ this.stateTarget = node;
127
133
 
128
- this.addController(new SummaryController(this));
134
+ this._tooltipController.setTarget(node);
135
+ });
129
136
 
130
137
  this._tooltipController = new TooltipController(this);
131
- this.addController(this._tooltipController);
132
-
133
- this._tooltipController.setTarget(this._toggleElement);
134
138
  this._tooltipController.setPosition('bottom-start');
135
139
  }
136
140
 
141
+ /** @protected */
142
+ ready() {
143
+ super.ready();
144
+
145
+ this.addController(this._summaryController);
146
+ this.addController(this._tooltipController);
147
+ }
148
+
137
149
  /**
138
150
  * Override method inherited from `DisabledMixin`
139
151
  * to not set `aria-disabled` on the host element.
@@ -144,6 +156,31 @@ class Details extends DetailsMixin(
144
156
  _setAriaDisabled() {
145
157
  // The `aria-disabled` is set on the details summary.
146
158
  }
159
+
160
+ /** @private */
161
+ _summaryChanged(summary) {
162
+ this._summaryController.setSummary(summary);
163
+ }
164
+
165
+ /** @private */
166
+ __updateAriaControls(summary, contentElements) {
167
+ if (summary && contentElements) {
168
+ const node = contentElements[0];
169
+
170
+ if (node && node.id) {
171
+ summary.setAttribute('aria-controls', node.id);
172
+ } else {
173
+ summary.removeAttribute('aria-controls');
174
+ }
175
+ }
176
+ }
177
+
178
+ /** @private */
179
+ __updateAriaExpanded(focusElement, opened) {
180
+ if (focusElement) {
181
+ focusElement.setAttribute('aria-expanded', opened ? 'true' : 'false');
182
+ }
183
+ }
147
184
  }
148
185
 
149
186
  customElements.define(Details.is, Details);
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/details",
4
- "version": "24.0.0-alpha6",
4
+ "version": "24.0.0-alpha8",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -76,6 +76,15 @@
76
76
  "name": "vaadin-details",
77
77
  "description": "`<vaadin-details>` is a Web Component which the creates an\nexpandable panel similar to `<details>` HTML element.\n\n```\n<vaadin-details>\n <vaadin-details-summary slot=\"summary\">Expandable Details</vaadin-details-summary>\n <div>\n Toggle using mouse, Enter and Space keys.\n </div>\n</vaadin-details>\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n-----------------|----------------\n`summary` | The element used to open and close collapsible content.\n`toggle` | The element used as indicator, can represent an icon.\n`summary-content`| The wrapper for the slotted summary content.\n`content` | The wrapper for the collapsible details content.\n\nThe following attributes are exposed for styling:\n\nAttribute | Description\n-------------| -----------\n`opened` | Set when the collapsible content is expanded and visible.\n`disabled` | Set when the element is disabled.\n`focus-ring` | Set when the element is focused using the keyboard.\n`focused` | Set when the element is focused.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
78
78
  "attributes": [
79
+ {
80
+ "name": "opened",
81
+ "description": "If true, the collapsible content is visible.",
82
+ "value": {
83
+ "type": [
84
+ "boolean"
85
+ ]
86
+ }
87
+ },
79
88
  {
80
89
  "name": "disabled",
81
90
  "description": "If true, the user cannot interact with this element.",
@@ -98,6 +107,17 @@
98
107
  ]
99
108
  }
100
109
  },
110
+ {
111
+ "name": "summary",
112
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
113
+ "value": {
114
+ "type": [
115
+ "string",
116
+ "null",
117
+ "undefined"
118
+ ]
119
+ }
120
+ },
101
121
  {
102
122
  "name": "theme",
103
123
  "description": "The theme variants to apply to the component.",
@@ -112,6 +132,15 @@
112
132
  ],
113
133
  "js": {
114
134
  "properties": [
135
+ {
136
+ "name": "opened",
137
+ "description": "If true, the collapsible content is visible.",
138
+ "value": {
139
+ "type": [
140
+ "boolean"
141
+ ]
142
+ }
143
+ },
115
144
  {
116
145
  "name": "disabled",
117
146
  "description": "If true, the user cannot interact with this element.",
@@ -133,9 +162,25 @@
133
162
  "undefined"
134
163
  ]
135
164
  }
165
+ },
166
+ {
167
+ "name": "summary",
168
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
169
+ "value": {
170
+ "type": [
171
+ "string",
172
+ "null",
173
+ "undefined"
174
+ ]
175
+ }
136
176
  }
137
177
  ],
138
- "events": []
178
+ "events": [
179
+ {
180
+ "name": "opened-changed",
181
+ "description": "Fired when the `opened` property changes."
182
+ }
183
+ ]
139
184
  }
140
185
  }
141
186
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/details",
4
- "version": "24.0.0-alpha6",
4
+ "version": "24.0.0-alpha8",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -40,6 +40,13 @@
40
40
  "description": "`<vaadin-details>` is a Web Component which the creates an\nexpandable panel similar to `<details>` HTML element.\n\n```\n<vaadin-details>\n <vaadin-details-summary slot=\"summary\">Expandable Details</vaadin-details-summary>\n <div>\n Toggle using mouse, Enter and Space keys.\n </div>\n</vaadin-details>\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n-----------------|----------------\n`summary` | The element used to open and close collapsible content.\n`toggle` | The element used as indicator, can represent an icon.\n`summary-content`| The wrapper for the slotted summary content.\n`content` | The wrapper for the collapsible details content.\n\nThe following attributes are exposed for styling:\n\nAttribute | Description\n-------------| -----------\n`opened` | Set when the collapsible content is expanded and visible.\n`disabled` | Set when the element is disabled.\n`focus-ring` | Set when the element is focused using the keyboard.\n`focused` | Set when the element is focused.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.",
41
41
  "extension": true,
42
42
  "attributes": [
43
+ {
44
+ "name": "?opened",
45
+ "description": "If true, the collapsible content is visible.",
46
+ "value": {
47
+ "kind": "expression"
48
+ }
49
+ },
43
50
  {
44
51
  "name": "?disabled",
45
52
  "description": "If true, the user cannot interact with this element.",
@@ -53,6 +60,20 @@
53
60
  "value": {
54
61
  "kind": "expression"
55
62
  }
63
+ },
64
+ {
65
+ "name": ".summary",
66
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
67
+ "value": {
68
+ "kind": "expression"
69
+ }
70
+ },
71
+ {
72
+ "name": "@opened-changed",
73
+ "description": "Fired when the `opened` property changes.",
74
+ "value": {
75
+ "kind": "expression"
76
+ }
56
77
  }
57
78
  ]
58
79
  }