@vaadin/details 23.3.3 → 24.0.0-alpha10

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
@@ -9,8 +9,8 @@ A web component that provides an expandable panel for showing and hiding content
9
9
 
10
10
  ```html
11
11
  <vaadin-details opened>
12
- <div slot="summary">Expandable Details</div>
13
- Toggle using mouse, Enter and Space keys.
12
+ <vaadin-details-summary slot="summary">Expandable Details</vaadin-details-summary>
13
+ <div>Toggle using mouse, Enter and Space keys.</div>
14
14
  </vaadin-details>
15
15
  ```
16
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/details",
3
- "version": "23.3.3",
3
+ "version": "24.0.0-alpha10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,12 +35,13 @@
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/component-base": "~23.3.3",
40
- "@vaadin/field-base": "~23.3.3",
41
- "@vaadin/vaadin-lumo-styles": "~23.3.3",
42
- "@vaadin/vaadin-material-styles": "~23.3.3",
43
- "@vaadin/vaadin-themable-mixin": "~23.3.3"
40
+ "@vaadin/button": "24.0.0-alpha10",
41
+ "@vaadin/component-base": "24.0.0-alpha10",
42
+ "@vaadin/vaadin-lumo-styles": "24.0.0-alpha10",
43
+ "@vaadin/vaadin-material-styles": "24.0.0-alpha10",
44
+ "@vaadin/vaadin-themable-mixin": "24.0.0-alpha10"
44
45
  },
45
46
  "devDependencies": {
46
47
  "@esm-bundle/chai": "^4.3.4",
@@ -51,5 +52,5 @@
51
52
  "web-types.json",
52
53
  "web-types.lit.json"
53
54
  ],
54
- "gitHead": "1529ed623e053d28a3c1c66af55ebe402743ddd0"
55
+ "gitHead": "2e04534d8b47bcd216f89b5f849bafef1a73b174"
55
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
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 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
+
8
+ /**
9
+ * A mixin providing common details functionality.
10
+ */
11
+ export declare function DetailsMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<DetailsMixinClass> & T;
12
+
13
+ export declare class DetailsMixinClass {
14
+ /**
15
+ * If true, the collapsible content is visible.
16
+ */
17
+ opened: boolean;
18
+
19
+ /**
20
+ * List of elements passed to the details default slot.
21
+ */
22
+ protected _contentElements: HTMLElement[];
23
+ }
@@ -0,0 +1,79 @@
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 { ContentController } from './content-controller.js';
7
+
8
+ /**
9
+ * A mixin providing common details functionality.
10
+ *
11
+ * @polymerMixin
12
+ */
13
+ export const DetailsMixin = (superClass) =>
14
+ class DetailsMixinClass extends superClass {
15
+ static get properties() {
16
+ return {
17
+ /**
18
+ * If true, the collapsible content is visible.
19
+ * @type {boolean}
20
+ */
21
+ opened: {
22
+ type: Boolean,
23
+ value: false,
24
+ reflectToAttribute: true,
25
+ notify: true,
26
+ },
27
+
28
+ /**
29
+ * List of elements passed to the details default slot.
30
+ *
31
+ * @protected
32
+ */
33
+ _contentElements: {
34
+ type: Array,
35
+ },
36
+ };
37
+ }
38
+
39
+ static get observers() {
40
+ return ['_openedOrContentChanged(opened, _contentElements)'];
41
+ }
42
+
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
+ });
54
+ }
55
+
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
+ });
69
+ }
70
+
71
+ /** @private */
72
+ _openedOrContentChanged(opened, elements) {
73
+ if (elements) {
74
+ elements.forEach((el) => {
75
+ el.setAttribute('aria-hidden', opened ? 'false' : 'true');
76
+ });
77
+ }
78
+ }
79
+ };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
7
+ import { ButtonMixin } from '@vaadin/button/src/vaadin-button-mixin.js';
8
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
9
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
+
11
+ /**
12
+ * The details summary element.
13
+ *
14
+ * @extends HTMLElement
15
+ * @mixes ButtonMixin
16
+ * @mixes DirMixin
17
+ * @mixes ThemableMixin
18
+ */
19
+ class DetailsSummary extends ButtonMixin(DirMixin(ThemableMixin(PolymerElement))) {
20
+ static get is() {
21
+ return 'vaadin-details-summary';
22
+ }
23
+
24
+ static get template() {
25
+ return html`
26
+ <style>
27
+ :host {
28
+ display: block;
29
+ outline: none;
30
+ white-space: nowrap;
31
+ -webkit-user-select: none;
32
+ -moz-user-select: none;
33
+ user-select: none;
34
+ }
35
+
36
+ :host([hidden]) {
37
+ display: none !important;
38
+ }
39
+
40
+ :host([disabled]) {
41
+ pointer-events: none;
42
+ }
43
+ </style>
44
+ <span part="toggle" aria-hidden="true"></span>
45
+ <div part="content"><slot></slot></div>
46
+ `;
47
+ }
48
+
49
+ static get properties() {
50
+ return {
51
+ /**
52
+ * When true, the element is opened.
53
+ */
54
+ opened: {
55
+ type: Boolean,
56
+ reflectToAttribute: true,
57
+ },
58
+ };
59
+ }
60
+ }
61
+
62
+ customElements.define(DetailsSummary.is, DetailsSummary);
@@ -1,12 +1,14 @@
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 { ShadowFocusMixin } from '@vaadin/field-base/src/shadow-focus-mixin.js';
9
10
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
+ import { DetailsMixin } from './vaadin-details-mixin.js';
10
12
 
11
13
  /**
12
14
  * Fired when the `opened` property changes.
@@ -25,8 +27,10 @@ export type DetailsEventMap = DetailsCustomEventMap & HTMLElementEventMap;
25
27
  *
26
28
  * ```
27
29
  * <vaadin-details>
28
- * <div slot="summary">Expandable Details</div>
29
- * Toggle using mouse, Enter and Space keys.
30
+ * <vaadin-details-summary slot="summary">Expandable Details</vaadin-details-summary>
31
+ * <div>
32
+ * Toggle using mouse, Enter and Space keys.
33
+ * </div>
30
34
  * </vaadin-details>
31
35
  * ```
32
36
  *
@@ -54,11 +58,14 @@ export type DetailsEventMap = DetailsCustomEventMap & HTMLElementEventMap;
54
58
  *
55
59
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
56
60
  */
57
- declare class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement)))) {
61
+ declare class Details extends DetailsMixin(
62
+ DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement))))),
63
+ ) {
58
64
  /**
59
- * If true, the details content is visible.
65
+ * A text that is displayed in the summary, if no
66
+ * element is assigned to the `summary` slot.
60
67
  */
61
- opened: boolean;
68
+ summary: string | null | undefined;
62
69
 
63
70
  addEventListener<K extends keyof DetailsEventMap>(
64
71
  type: K,
@@ -1,15 +1,18 @@
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 './vaadin-details-summary.js';
6
7
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
7
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';
8
11
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
9
12
  import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
10
- import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
11
- import { ShadowFocusMixin } from '@vaadin/field-base/src/shadow-focus-mixin.js';
12
13
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
14
+ import { SummaryController } from './summary-controller.js';
15
+ import { DetailsMixin } from './vaadin-details-mixin.js';
13
16
 
14
17
  /**
15
18
  * `<vaadin-details>` is a Web Component which the creates an
@@ -17,8 +20,10 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
17
20
  *
18
21
  * ```
19
22
  * <vaadin-details>
20
- * <div slot="summary">Expandable Details</div>
21
- * Toggle using mouse, Enter and Space keys.
23
+ * <vaadin-details-summary slot="summary">Expandable Details</vaadin-details-summary>
24
+ * <div>
25
+ * Toggle using mouse, Enter and Space keys.
26
+ * </div>
22
27
  * </vaadin-details>
23
28
  * ```
24
29
  *
@@ -48,11 +53,15 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
48
53
  *
49
54
  * @extends HTMLElement
50
55
  * @mixes ControllerMixin
51
- * @mixes ShadowFocusMixin
56
+ * @mixes DetailsMixin
57
+ * @mixes DelegateFocusMixin
58
+ * @mixes DelegateStateMixin
52
59
  * @mixes ElementMixin
53
60
  * @mixes ThemableMixin
54
61
  */
55
- class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement)))) {
62
+ class Details extends DetailsMixin(
63
+ DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement))))),
64
+ ) {
56
65
  static get template() {
57
66
  return html`
58
67
  <style>
@@ -66,36 +75,20 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
66
75
 
67
76
  [part='content'] {
68
77
  display: none;
69
- overflow: hidden;
70
- }
71
-
72
- [part='summary'][disabled] {
73
- pointer-events: none;
74
78
  }
75
79
 
76
80
  :host([opened]) [part='content'] {
77
81
  display: block;
78
- overflow: visible;
79
82
  }
80
83
  </style>
81
- <div role="heading">
82
- <div
83
- role="button"
84
- part="summary"
85
- on-click="_onToggleClick"
86
- on-keydown="_onToggleKeyDown"
87
- disabled$="[[disabled]]"
88
- aria-expanded$="[[_getAriaExpanded(opened)]]"
89
- aria-controls$="[[_contentId]]"
90
- >
91
- <span part="toggle" aria-hidden="true"></span>
92
- <span part="summary-content"><slot name="summary"></slot></span>
93
- </div>
94
- <slot name="tooltip"></slot>
95
- </div>
96
- <section id$="[[_contentId]]" part="content" aria-hidden$="[[_getAriaHidden(opened)]]">
84
+
85
+ <slot name="summary"></slot>
86
+
87
+ <div part="content">
97
88
  <slot></slot>
98
- </section>
89
+ </div>
90
+
91
+ <slot name="tooltip"></slot>
99
92
  `;
100
93
  }
101
94
 
@@ -106,79 +99,86 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
106
99
  static get properties() {
107
100
  return {
108
101
  /**
109
- * If true, the details content is visible.
110
- * @type {boolean}
102
+ * A text that is displayed in the summary, if no
103
+ * element is assigned to the `summary` slot.
111
104
  */
112
- opened: {
113
- type: Boolean,
114
- value: false,
115
- reflectToAttribute: true,
116
- notify: true,
117
- observer: '_openedChanged',
105
+ summary: {
106
+ type: String,
107
+ observer: '_summaryChanged',
118
108
  },
119
109
  };
120
110
  }
121
111
 
122
- /**
123
- * @return {!HTMLElement}
124
- * @protected
125
- */
126
- get _collapsible() {
127
- return this.shadowRoot.querySelector('[part="content"]');
112
+ static get observers() {
113
+ return ['__updateAriaControls(focusElement, _contentElements)', '__updateAriaExpanded(focusElement, opened)'];
128
114
  }
129
115
 
130
- /**
131
- * Focusable element used by `ShadowFocusMixin`.
132
- * @return {!HTMLElement}
133
- * @protected
134
- */
135
- get focusElement() {
136
- return this.shadowRoot.querySelector('[part="summary"]');
116
+ static get delegateAttrs() {
117
+ return ['theme'];
137
118
  }
138
119
 
139
- /** @protected */
140
- ready() {
141
- super.ready();
142
- this._contentId = `${this.constructor.is}-content-${generateUniqueId()}`;
143
- // Prevent Shift + Tab on content from host blur
144
- this._collapsible.addEventListener('keydown', (e) => {
145
- if (e.shiftKey && e.keyCode === 9) {
146
- e.stopPropagation();
147
- }
120
+ static get delegateProps() {
121
+ return ['disabled', 'opened'];
122
+ }
123
+
124
+ constructor() {
125
+ super();
126
+
127
+ this._summaryController = new SummaryController(this, 'vaadin-details-summary');
128
+ this._summaryController.addEventListener('slot-content-changed', (event) => {
129
+ const { node } = event.target;
130
+
131
+ this._setFocusElement(node);
132
+ this.stateTarget = node;
133
+
134
+ this._tooltipController.setTarget(node);
148
135
  });
149
136
 
150
137
  this._tooltipController = new TooltipController(this);
151
- this.addController(this._tooltipController);
152
-
153
- this._tooltipController.setTarget(this.focusElement);
154
138
  this._tooltipController.setPosition('bottom-start');
155
139
  }
156
140
 
157
- /** @private */
158
- _getAriaExpanded(opened) {
159
- return opened ? 'true' : 'false';
141
+ /** @protected */
142
+ ready() {
143
+ super.ready();
144
+
145
+ this.addController(this._summaryController);
146
+ this.addController(this._tooltipController);
160
147
  }
161
148
 
162
- /** @private */
163
- _getAriaHidden(opened) {
164
- return opened ? 'false' : 'true';
149
+ /**
150
+ * Override method inherited from `DisabledMixin`
151
+ * to not set `aria-disabled` on the host element.
152
+ *
153
+ * @protected
154
+ * @override
155
+ */
156
+ _setAriaDisabled() {
157
+ // The `aria-disabled` is set on the details summary.
165
158
  }
166
159
 
167
160
  /** @private */
168
- _openedChanged(opened) {
169
- this._collapsible.style.maxHeight = opened ? '' : '0px';
161
+ _summaryChanged(summary) {
162
+ this._summaryController.setSummary(summary);
170
163
  }
171
164
 
172
165
  /** @private */
173
- _onToggleClick() {
174
- this.opened = !this.opened;
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
+ }
175
176
  }
176
177
 
177
178
  /** @private */
178
- _onToggleKeyDown(e) {
179
- if ([13, 32].indexOf(e.keyCode) > -1) {
180
- e.preventDefault();
181
- this.opened = !this.opened;
179
+ __updateAriaExpanded(focusElement, opened) {
180
+ if (focusElement) {
181
+ focusElement.setAttribute('aria-expanded', opened ? 'true' : 'false');
182
182
  }
183
183
  }
184
184
  }
@@ -1,6 +1,4 @@
1
1
  import '@vaadin/vaadin-lumo-styles/color.js';
2
- import '@vaadin/vaadin-lumo-styles/font-icons.js';
3
- import '@vaadin/vaadin-lumo-styles/sizing.js';
4
2
  import '@vaadin/vaadin-lumo-styles/spacing.js';
5
3
  import '@vaadin/vaadin-lumo-styles/style.js';
6
4
  import '@vaadin/vaadin-lumo-styles/typography.js';
@@ -12,64 +10,10 @@ const details = css`
12
10
  outline: none;
13
11
  }
14
12
 
15
- [part='summary'] {
16
- display: flex;
17
- align-items: center;
18
- width: 100%;
19
- outline: none;
20
- padding: var(--lumo-space-s) 0;
21
- box-sizing: border-box;
22
- font-family: var(--lumo-font-family);
23
- font-size: var(--lumo-font-size-m);
24
- font-weight: 500;
25
- line-height: var(--lumo-line-height-xs);
26
- color: var(--lumo-secondary-text-color);
27
- background-color: inherit;
28
- border-radius: var(--lumo-border-radius-m);
29
- cursor: var(--lumo-clickable-cursor);
30
- -webkit-tap-highlight-color: transparent;
31
- -webkit-font-smoothing: antialiased;
32
- -moz-osx-font-smoothing: grayscale;
33
- }
34
-
35
- :host([focus-ring]) [part='summary'] {
13
+ :host([focus-ring]) ::slotted([slot='summary']) {
36
14
  box-shadow: 0 0 0 2px var(--lumo-primary-color-50pct);
37
15
  }
38
16
 
39
- [part='toggle'] {
40
- display: block;
41
- width: 1em;
42
- height: 1em;
43
- margin-left: calc(var(--lumo-space-xs) * -1);
44
- margin-right: var(--lumo-space-xs);
45
- font-size: var(--lumo-icon-size-s);
46
- line-height: 1;
47
- color: var(--lumo-contrast-60pct);
48
- font-family: 'lumo-icons';
49
- cursor: var(--lumo-clickable-cursor);
50
- }
51
-
52
- :host([disabled]) [part='summary'],
53
- :host([disabled]) [part='toggle'] {
54
- color: var(--lumo-disabled-text-color);
55
- cursor: default;
56
- }
57
-
58
- @media (hover: hover) {
59
- :host(:not([disabled])) [part='summary']:hover,
60
- :host(:not([disabled])) [part='summary']:hover [part='toggle'] {
61
- color: var(--lumo-contrast-80pct);
62
- }
63
- }
64
-
65
- [part='toggle']::before {
66
- content: var(--lumo-icons-angle-right);
67
- }
68
-
69
- :host([opened]) [part='toggle'] {
70
- transform: rotate(90deg);
71
- }
72
-
73
17
  [part='content'] {
74
18
  padding: var(--lumo-space-xs) 0 var(--lumo-space-s);
75
19
  font-size: var(--lumo-font-size-m);
@@ -81,66 +25,14 @@ const details = css`
81
25
  border-radius: var(--lumo-border-radius-m);
82
26
  }
83
27
 
84
- :host([theme~='filled']) [part='summary'] {
85
- padding: var(--lumo-space-s) calc(var(--lumo-space-s) + var(--lumo-space-xs) / 2);
86
- }
87
-
88
28
  :host([theme~='filled']) [part='content'] {
89
29
  padding-left: var(--lumo-space-m);
90
30
  padding-right: var(--lumo-space-m);
91
31
  }
92
32
 
93
- :host([theme~='small']) [part='summary'] {
94
- padding-top: var(--lumo-space-xs);
95
- padding-bottom: var(--lumo-space-xs);
96
- }
97
-
98
- :host([theme~='small']) [part='toggle'] {
99
- margin-right: calc(var(--lumo-space-xs) / 2);
100
- }
101
-
102
- :host([theme~='small']) [part\$='content'] {
33
+ :host([theme~='small']) [part$='content'] {
103
34
  font-size: var(--lumo-font-size-s);
104
35
  }
105
-
106
- :host([theme~='reverse']) [part='summary'] {
107
- justify-content: space-between;
108
- }
109
-
110
- :host([theme~='reverse']) [part='toggle'] {
111
- order: 1;
112
- margin-right: 0;
113
- }
114
-
115
- :host([theme~='reverse'][theme~='filled']) [part='summary'] {
116
- padding-left: var(--lumo-space-m);
117
- }
118
-
119
- /* RTL specific styles */
120
- :host([dir='rtl']) [part='toggle'] {
121
- margin-left: var(--lumo-space-xs);
122
- margin-right: calc(var(--lumo-space-xs) * -1);
123
- }
124
-
125
- :host([dir='rtl']) [part='toggle']::before {
126
- content: var(--lumo-icons-angle-left);
127
- }
128
-
129
- :host([opened][dir='rtl']) [part='toggle'] {
130
- transform: rotate(-90deg);
131
- }
132
-
133
- :host([theme~='small'][dir='rtl']) [part='toggle'] {
134
- margin-left: calc(var(--lumo-space-xs) / 2);
135
- }
136
-
137
- :host([theme~='reverse'][dir='rtl']) [part='toggle'] {
138
- margin-left: 0;
139
- }
140
-
141
- :host([theme~='reverse'][theme~='filled'][dir='rtl']) [part='summary'] {
142
- padding-right: var(--lumo-space-m);
143
- }
144
36
  `;
145
37
 
146
38
  registerStyles('vaadin-details', details, { moduleId: 'lumo-details' });
@@ -0,0 +1,123 @@
1
+ import '@vaadin/vaadin-lumo-styles/color.js';
2
+ import '@vaadin/vaadin-lumo-styles/font-icons.js';
3
+ import '@vaadin/vaadin-lumo-styles/sizing.js';
4
+ import '@vaadin/vaadin-lumo-styles/spacing.js';
5
+ import '@vaadin/vaadin-lumo-styles/style.js';
6
+ import '@vaadin/vaadin-lumo-styles/typography.js';
7
+ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
+
9
+ const detailsSummary = css`
10
+ :host {
11
+ display: flex;
12
+ align-items: center;
13
+ width: 100%;
14
+ outline: none;
15
+ padding: var(--lumo-space-s) 0;
16
+ box-sizing: border-box;
17
+ font-family: var(--lumo-font-family);
18
+ font-size: var(--lumo-font-size-m);
19
+ font-weight: 500;
20
+ line-height: var(--lumo-line-height-xs);
21
+ color: var(--lumo-secondary-text-color);
22
+ background-color: inherit;
23
+ border-radius: var(--lumo-border-radius-m);
24
+ cursor: var(--lumo-clickable-cursor);
25
+ -webkit-tap-highlight-color: transparent;
26
+ -webkit-font-smoothing: antialiased;
27
+ -moz-osx-font-smoothing: grayscale;
28
+ }
29
+
30
+ :host([disabled]),
31
+ :host([disabled]) [part='toggle'] {
32
+ color: var(--lumo-disabled-text-color);
33
+ cursor: default;
34
+ }
35
+
36
+ @media (hover: hover) {
37
+ :host(:hover:not([disabled])),
38
+ :host(:hover:not([disabled])) [part='toggle'] {
39
+ color: var(--lumo-contrast-80pct);
40
+ }
41
+ }
42
+
43
+ [part='toggle'] {
44
+ display: block;
45
+ width: 1em;
46
+ height: 1em;
47
+ margin-left: calc(var(--lumo-space-xs) * -1);
48
+ margin-right: var(--lumo-space-xs);
49
+ font-size: var(--lumo-icon-size-s);
50
+ line-height: 1;
51
+ color: var(--lumo-contrast-60pct);
52
+ font-family: 'lumo-icons';
53
+ cursor: var(--lumo-clickable-cursor);
54
+ }
55
+
56
+ [part='toggle']::before {
57
+ content: var(--lumo-icons-angle-right);
58
+ }
59
+
60
+ :host([opened]) [part='toggle'] {
61
+ transform: rotate(90deg);
62
+ }
63
+
64
+ /* RTL styles */
65
+ :host([dir='rtl']) [part='toggle'] {
66
+ margin-left: var(--lumo-space-xs);
67
+ margin-right: calc(var(--lumo-space-xs) * -1);
68
+ }
69
+
70
+ :host([dir='rtl']) [part='toggle']::before {
71
+ content: var(--lumo-icons-angle-left);
72
+ }
73
+
74
+ :host([opened][dir='rtl']) [part='toggle'] {
75
+ transform: rotate(-90deg);
76
+ }
77
+
78
+ /* Small */
79
+ :host([theme~='small']) {
80
+ padding-top: var(--lumo-space-xs);
81
+ padding-bottom: var(--lumo-space-xs);
82
+ }
83
+
84
+ :host([theme~='small']) [part='toggle'] {
85
+ margin-right: calc(var(--lumo-space-xs) / 2);
86
+ }
87
+
88
+ :host([theme~='small'][dir='rtl']) [part='toggle'] {
89
+ margin-left: calc(var(--lumo-space-xs) / 2);
90
+ }
91
+
92
+ /* Filled */
93
+ :host([theme~='filled']) {
94
+ padding: var(--lumo-space-s) calc(var(--lumo-space-s) + var(--lumo-space-xs) / 2);
95
+ }
96
+
97
+ /* Reverse */
98
+ :host([theme~='reverse']) {
99
+ justify-content: space-between;
100
+ }
101
+
102
+ :host([theme~='reverse']) [part='toggle'] {
103
+ order: 1;
104
+ margin-right: 0;
105
+ }
106
+
107
+ :host([theme~='reverse'][dir='rtl']) [part='toggle'] {
108
+ margin-left: 0;
109
+ }
110
+
111
+ /* Filled reverse */
112
+ :host([theme~='reverse'][theme~='filled']) {
113
+ padding-left: var(--lumo-space-m);
114
+ }
115
+
116
+ :host([theme~='reverse'][theme~='filled'][dir='rtl']) {
117
+ padding-right: var(--lumo-space-m);
118
+ }
119
+ `;
120
+
121
+ registerStyles('vaadin-details-summary', detailsSummary, { moduleId: 'lumo-details-summary' });
122
+
123
+ export { detailsSummary };
@@ -1,2 +1,3 @@
1
+ import './vaadin-details-summary-styles.js';
1
2
  import './vaadin-details-styles.js';
2
3
  import '../../src/vaadin-details.js';
@@ -1,5 +1,4 @@
1
1
  import '@vaadin/vaadin-material-styles/color.js';
2
- import '@vaadin/vaadin-material-styles/font-icons.js';
3
2
  import '@vaadin/vaadin-material-styles/shadow.js';
4
3
  import '@vaadin/vaadin-material-styles/typography.js';
5
4
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
@@ -11,106 +10,13 @@ const details = css`
11
10
  outline: none;
12
11
  }
13
12
 
14
- [part='summary'] {
15
- display: flex;
16
- align-items: center;
17
- justify-content: space-between;
18
- width: 100%;
19
- position: relative;
20
- outline: none;
21
- min-height: 48px;
22
- padding: 0 24px;
23
- box-sizing: border-box;
24
- font-weight: 500;
25
- font-size: var(--material-small-font-size);
26
- background-color: var(--material-background-color);
27
- color: var(--material-body-text-color);
28
- cursor: default;
29
- -webkit-tap-highlight-color: transparent;
30
- -webkit-font-smoothing: antialiased;
31
- -moz-osx-font-smoothing: grayscale;
32
- }
33
-
34
- :host([disabled]) [part='summary'] {
35
- color: var(--material-disabled-text-color);
36
- background: var(--material-disabled-color);
37
- }
38
-
39
- :host([focus-ring]) [part='summary'] {
40
- background: var(--material-secondary-background-color);
41
- }
42
-
43
- [part='summary-content'] {
44
- margin: 12px 0;
45
- }
46
-
47
- [part='toggle'] {
48
- position: relative;
49
- order: 1;
50
- margin-right: -8px;
51
- width: 24px;
52
- height: 24px;
53
- padding: 4px;
54
- color: var(--material-secondary-text-color);
55
- line-height: 24px;
56
- text-align: center;
57
- transform: rotate(90deg);
58
- transition: transform 0.1s cubic-bezier(0.4, 0, 0.2, 0.1);
59
- }
60
-
61
- [part='toggle']::before {
62
- font-family: 'material-icons';
63
- font-size: 24px;
64
- width: 24px;
65
- display: inline-block;
66
- content: var(--material-icons-chevron-right);
67
- }
68
-
69
- [part='toggle']::after {
70
- display: inline-block;
71
- content: '';
72
- position: absolute;
73
- top: 0;
74
- left: 0;
75
- width: 100%;
76
- height: 100%;
77
- border-radius: 50%;
78
- background-color: var(--material-disabled-text-color);
79
- transform: scale(0);
80
- opacity: 0;
81
- transition: transform 0s 0.8s, opacity 0.8s;
82
- will-change: transform, opacity;
83
- }
84
-
85
- :host([disabled]) [part='toggle'] {
86
- color: var(--material-disabled-color);
87
- }
88
-
89
- :host(:not([disabled])) [part='summary']:active [part='toggle']::after {
90
- transition-duration: 0.08s, 0.01s;
91
- transition-delay: 0s, 0s;
92
- transform: scale(1.25);
93
- opacity: 0.15;
94
- }
95
-
96
- :host([opened]) [part='toggle'] {
97
- transform: rotate(270deg);
13
+ :host([focus-ring]) ::slotted([slot='summary']) {
14
+ background-color: var(--material-secondary-background-color);
98
15
  }
99
16
 
100
17
  [part='content'] {
101
18
  padding: 8px 24px 24px;
102
19
  }
103
-
104
- /* RTL specific styles */
105
- :host([dir='rtl']) [part='toggle'] {
106
- margin-left: -8px;
107
- margin-right: 0;
108
- }
109
-
110
- :host([dir='rtl']) [part='toggle']::after {
111
- left: auto;
112
- right: 0;
113
- }
114
20
  `;
115
21
 
116
22
  registerStyles('vaadin-details', details, { moduleId: 'material-details' });
@@ -0,0 +1,104 @@
1
+ import '@vaadin/vaadin-material-styles/color.js';
2
+ import '@vaadin/vaadin-material-styles/font-icons.js';
3
+ import '@vaadin/vaadin-material-styles/typography.js';
4
+ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
5
+
6
+ const detailsSummary = css`
7
+ :host {
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: space-between;
11
+ width: 100%;
12
+ position: relative;
13
+ outline: none;
14
+ min-height: 48px;
15
+ padding: 0 24px;
16
+ box-sizing: border-box;
17
+ font-weight: 500;
18
+ font-size: var(--material-small-font-size);
19
+ background-color: var(--material-background-color);
20
+ color: var(--material-body-text-color);
21
+ cursor: default;
22
+ -webkit-tap-highlight-color: transparent;
23
+ -webkit-font-smoothing: antialiased;
24
+ -moz-osx-font-smoothing: grayscale;
25
+ }
26
+
27
+ :host([disabled]) {
28
+ color: var(--material-disabled-text-color);
29
+ background-color: var(--material-disabled-color);
30
+ }
31
+
32
+ [part='content'] {
33
+ margin: 0;
34
+ position: relative;
35
+ }
36
+
37
+ [part='toggle'] {
38
+ position: relative;
39
+ order: 1;
40
+ margin-inline-start: auto;
41
+ right: -8px;
42
+ width: 24px;
43
+ height: 24px;
44
+ padding: 4px;
45
+ color: var(--material-secondary-text-color);
46
+ line-height: 24px;
47
+ text-align: center;
48
+ transform: rotate(90deg);
49
+ transition: transform 0.1s cubic-bezier(0.4, 0, 0.2, 0.1);
50
+ }
51
+
52
+ [part='toggle']::before {
53
+ font-family: 'material-icons';
54
+ font-size: 24px;
55
+ width: 24px;
56
+ display: inline-block;
57
+ content: var(--material-icons-chevron-right);
58
+ }
59
+
60
+ [part='toggle']::after {
61
+ display: inline-block;
62
+ content: '';
63
+ position: absolute;
64
+ top: 0;
65
+ left: 0;
66
+ width: 100%;
67
+ height: 100%;
68
+ border-radius: 50%;
69
+ background-color: var(--material-disabled-text-color);
70
+ transform: scale(0);
71
+ opacity: 0;
72
+ transition: transform 0s 0.8s, opacity 0.8s;
73
+ will-change: transform, opacity;
74
+ }
75
+
76
+ :host([disabled]) [part='toggle'] {
77
+ color: var(--material-disabled-color);
78
+ }
79
+
80
+ :host([active]:not([disabled])) [part='toggle']::after {
81
+ transition-duration: 0.08s, 0.01s;
82
+ transition-delay: 0s, 0s;
83
+ transform: scale(1.25);
84
+ opacity: 0.15;
85
+ }
86
+
87
+ :host([opened]) [part='toggle'] {
88
+ transform: rotate(270deg);
89
+ }
90
+
91
+ /* RTL specific styles */
92
+ :host([dir='rtl']) [part='toggle'] {
93
+ right: 8px;
94
+ }
95
+
96
+ :host([dir='rtl']) [part='toggle']::after {
97
+ left: auto;
98
+ right: 0;
99
+ }
100
+ `;
101
+
102
+ registerStyles('vaadin-details-summary', detailsSummary, { moduleId: 'material-details-summary' });
103
+
104
+ export { detailsSummary };
@@ -1,2 +1,3 @@
1
+ import './vaadin-details-summary-styles.js';
1
2
  import './vaadin-details-styles.js';
2
3
  import '../../src/vaadin-details.js';
package/web-types.json CHANGED
@@ -1,15 +1,90 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/details",
4
- "version": "23.3.3",
4
+ "version": "24.0.0-alpha10",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
+ {
10
+ "name": "vaadin-details-summary",
11
+ "description": "The details summary element.",
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": "opened",
26
+ "description": "When true, the element is opened.",
27
+ "value": {
28
+ "type": [
29
+ "boolean",
30
+ "null",
31
+ "undefined"
32
+ ]
33
+ }
34
+ },
35
+ {
36
+ "name": "theme",
37
+ "description": "The theme variants to apply to the component.",
38
+ "value": {
39
+ "type": [
40
+ "string",
41
+ "null",
42
+ "undefined"
43
+ ]
44
+ }
45
+ }
46
+ ],
47
+ "js": {
48
+ "properties": [
49
+ {
50
+ "name": "disabled",
51
+ "description": "If true, the user cannot interact with this element.",
52
+ "value": {
53
+ "type": [
54
+ "boolean",
55
+ "null",
56
+ "undefined"
57
+ ]
58
+ }
59
+ },
60
+ {
61
+ "name": "opened",
62
+ "description": "When true, the element is opened.",
63
+ "value": {
64
+ "type": [
65
+ "boolean",
66
+ "null",
67
+ "undefined"
68
+ ]
69
+ }
70
+ }
71
+ ],
72
+ "events": []
73
+ }
74
+ },
9
75
  {
10
76
  "name": "vaadin-details",
11
- "description": "`<vaadin-details>` is a Web Component which the creates an\nexpandable panel similar to `<details>` HTML element.\n\n```\n<vaadin-details>\n <div slot=\"summary\">Expandable Details</div>\n Toggle using mouse, Enter and Space keys.\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.",
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.",
12
78
  "attributes": [
79
+ {
80
+ "name": "opened",
81
+ "description": "If true, the collapsible content is visible.",
82
+ "value": {
83
+ "type": [
84
+ "boolean"
85
+ ]
86
+ }
87
+ },
13
88
  {
14
89
  "name": "disabled",
15
90
  "description": "If true, the user cannot interact with this element.",
@@ -33,11 +108,13 @@
33
108
  }
34
109
  },
35
110
  {
36
- "name": "opened",
37
- "description": "If true, the details content is visible.",
111
+ "name": "summary",
112
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
38
113
  "value": {
39
114
  "type": [
40
- "boolean"
115
+ "string",
116
+ "null",
117
+ "undefined"
41
118
  ]
42
119
  }
43
120
  },
@@ -55,6 +132,15 @@
55
132
  ],
56
133
  "js": {
57
134
  "properties": [
135
+ {
136
+ "name": "opened",
137
+ "description": "If true, the collapsible content is visible.",
138
+ "value": {
139
+ "type": [
140
+ "boolean"
141
+ ]
142
+ }
143
+ },
58
144
  {
59
145
  "name": "disabled",
60
146
  "description": "If true, the user cannot interact with this element.",
@@ -78,11 +164,13 @@
78
164
  }
79
165
  },
80
166
  {
81
- "name": "opened",
82
- "description": "If true, the details content is visible.",
167
+ "name": "summary",
168
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
83
169
  "value": {
84
170
  "type": [
85
- "boolean"
171
+ "string",
172
+ "null",
173
+ "undefined"
86
174
  ]
87
175
  }
88
176
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/details",
4
- "version": "23.3.3",
4
+ "version": "24.0.0-alpha10",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -14,11 +14,39 @@
14
14
  "contributions": {
15
15
  "html": {
16
16
  "elements": [
17
+ {
18
+ "name": "vaadin-details-summary",
19
+ "description": "The details summary element.",
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": "?opened",
31
+ "description": "When true, the element is opened.",
32
+ "value": {
33
+ "kind": "expression"
34
+ }
35
+ }
36
+ ]
37
+ },
17
38
  {
18
39
  "name": "vaadin-details",
19
- "description": "`<vaadin-details>` is a Web Component which the creates an\nexpandable panel similar to `<details>` HTML element.\n\n```\n<vaadin-details>\n <div slot=\"summary\">Expandable Details</div>\n Toggle using mouse, Enter and Space keys.\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.",
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.",
20
41
  "extension": true,
21
42
  "attributes": [
43
+ {
44
+ "name": "?opened",
45
+ "description": "If true, the collapsible content is visible.",
46
+ "value": {
47
+ "kind": "expression"
48
+ }
49
+ },
22
50
  {
23
51
  "name": "?disabled",
24
52
  "description": "If true, the user cannot interact with this element.",
@@ -34,8 +62,8 @@
34
62
  }
35
63
  },
36
64
  {
37
- "name": "?opened",
38
- "description": "If true, the details content is visible.",
65
+ "name": ".summary",
66
+ "description": "A text that is displayed in the summary, if no\nelement is assigned to the `summary` slot.",
39
67
  "value": {
40
68
  "kind": "expression"
41
69
  }