@vaadin/details 24.0.0-alpha4 → 24.0.0-alpha6

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": "24.0.0-alpha4",
3
+ "version": "24.0.0-alpha6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,12 +35,14 @@
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": "24.0.0-alpha4",
40
- "@vaadin/field-base": "24.0.0-alpha4",
41
- "@vaadin/vaadin-lumo-styles": "24.0.0-alpha4",
42
- "@vaadin/vaadin-material-styles": "24.0.0-alpha4",
43
- "@vaadin/vaadin-themable-mixin": "24.0.0-alpha4"
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"
44
46
  },
45
47
  "devDependencies": {
46
48
  "@esm-bundle/chai": "^4.3.4",
@@ -51,5 +53,5 @@
51
53
  "web-types.json",
52
54
  "web-types.lit.json"
53
55
  ],
54
- "gitHead": "66be46e82c4d0a673859fbc9bdb1581dd89f360c"
56
+ "gitHead": "0004ac92b6e5f415b5fa949e0582d1d11e527b1f"
55
57
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 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
+ * A content area controlled by the toggle element.
21
+ */
22
+ protected _collapsible: HTMLElement;
23
+
24
+ /**
25
+ * An element used to toggle the content visibility.
26
+ */
27
+ protected _toggleElement: HTMLElement;
28
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2019 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * A mixin providing common details functionality.
9
+ *
10
+ * @polymerMixin
11
+ */
12
+ export const DetailsMixin = (superClass) =>
13
+ class DetailsMixinClass extends superClass {
14
+ static get properties() {
15
+ return {
16
+ /**
17
+ * If true, the collapsible content is visible.
18
+ * @type {boolean}
19
+ */
20
+ opened: {
21
+ type: Boolean,
22
+ value: false,
23
+ reflectToAttribute: true,
24
+ notify: true,
25
+ },
26
+
27
+ /**
28
+ * A content area controlled by the toggle element.
29
+ *
30
+ * @protected
31
+ */
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',
45
+ },
46
+ };
47
+ }
48
+
49
+ static get observers() {
50
+ return ['_openedOrToggleChanged(opened, _toggleElement)', '_openedOrCollapsibleChanged(opened, _collapsible)'];
51
+ }
52
+
53
+ /** @private */
54
+ _openedOrCollapsibleChanged(opened, collapsible) {
55
+ if (collapsible) {
56
+ collapsible.setAttribute('aria-hidden', opened ? 'false' : 'true');
57
+ }
58
+ }
59
+
60
+ /** @private */
61
+ _openedOrToggleChanged(opened, toggleElement) {
62
+ if (toggleElement) {
63
+ toggleElement.setAttribute('aria-expanded', opened ? 'true' : 'false');
64
+ }
65
+ }
66
+
67
+ /** @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();
74
+ });
75
+ }
76
+ }
77
+
78
+ /** @private */
79
+ _toggle() {
80
+ this.opened = !this.opened;
81
+ }
82
+ };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 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);
@@ -5,8 +5,10 @@
5
5
  */
6
6
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
7
7
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
8
- import { ShadowFocusMixin } from '@vaadin/field-base/src/shadow-focus-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';
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,12 +58,9 @@ 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)))) {
58
- /**
59
- * If true, the details content is visible.
60
- */
61
- opened: boolean;
62
-
61
+ declare class Details extends DetailsMixin(
62
+ DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement))))),
63
+ ) {
63
64
  addEventListener<K extends keyof DetailsEventMap>(
64
65
  type: K,
65
66
  listener: (this: Details, ev: DetailsEventMap[K]) => void,
@@ -3,13 +3,29 @@
3
3
  * Copyright (c) 2019 - 2022 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';
8
9
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
+ import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
9
11
  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
+ import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.js';
13
+ import { DelegateStateMixin } from '@vaadin/field-base/src/delegate-state-mixin.js';
12
14
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
15
+ import { DetailsMixin } from './vaadin-details-mixin.js';
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
+ }
13
29
 
14
30
  /**
15
31
  * `<vaadin-details>` is a Web Component which the creates an
@@ -17,8 +33,10 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
17
33
  *
18
34
  * ```
19
35
  * <vaadin-details>
20
- * <div slot="summary">Expandable Details</div>
21
- * Toggle using mouse, Enter and Space keys.
36
+ * <vaadin-details-summary slot="summary">Expandable Details</vaadin-details-summary>
37
+ * <div>
38
+ * Toggle using mouse, Enter and Space keys.
39
+ * </div>
22
40
  * </vaadin-details>
23
41
  * ```
24
42
  *
@@ -48,11 +66,14 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
48
66
  *
49
67
  * @extends HTMLElement
50
68
  * @mixes ControllerMixin
51
- * @mixes ShadowFocusMixin
69
+ * @mixes DelegateFocusMixin
70
+ * @mixes DelegateStateMixin
52
71
  * @mixes ElementMixin
53
72
  * @mixes ThemableMixin
54
73
  */
55
- class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement)))) {
74
+ class Details extends DetailsMixin(
75
+ DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement))))),
76
+ ) {
56
77
  static get template() {
57
78
  return html`
58
79
  <style>
@@ -66,36 +87,20 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
66
87
 
67
88
  [part='content'] {
68
89
  display: none;
69
- overflow: hidden;
70
- }
71
-
72
- [part='summary'][disabled] {
73
- pointer-events: none;
74
90
  }
75
91
 
76
92
  :host([opened]) [part='content'] {
77
93
  display: block;
78
- overflow: visible;
79
94
  }
80
95
  </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)]]">
96
+
97
+ <slot name="summary"></slot>
98
+
99
+ <div part="content">
97
100
  <slot></slot>
98
- </section>
101
+ </div>
102
+
103
+ <slot name="tooltip"></slot>
99
104
  `;
100
105
  }
101
106
 
@@ -103,83 +108,41 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
103
108
  return 'vaadin-details';
104
109
  }
105
110
 
106
- static get properties() {
107
- return {
108
- /**
109
- * If true, the details content is visible.
110
- * @type {boolean}
111
- */
112
- opened: {
113
- type: Boolean,
114
- value: false,
115
- reflectToAttribute: true,
116
- notify: true,
117
- observer: '_openedChanged',
118
- },
119
- };
111
+ static get delegateAttrs() {
112
+ return ['theme'];
120
113
  }
121
114
 
122
- /**
123
- * @return {!HTMLElement}
124
- * @protected
125
- */
126
- get _collapsible() {
127
- return this.shadowRoot.querySelector('[part="content"]');
128
- }
129
-
130
- /**
131
- * Focusable element used by `ShadowFocusMixin`.
132
- * @return {!HTMLElement}
133
- * @protected
134
- */
135
- get focusElement() {
136
- return this.shadowRoot.querySelector('[part="summary"]');
115
+ static get delegateProps() {
116
+ return ['disabled', 'opened'];
137
117
  }
138
118
 
139
119
  /** @protected */
140
120
  ready() {
141
121
  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
- }
148
- });
149
122
 
150
- this._tooltipController = new TooltipController(this);
151
- this.addController(this._tooltipController);
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.
152
125
 
153
- this._tooltipController.setTarget(this.focusElement);
154
- this._tooltipController.setPosition('bottom-start');
155
- }
126
+ this._collapsible = this.shadowRoot.querySelector('[part="content"]');
156
127
 
157
- /** @private */
158
- _getAriaExpanded(opened) {
159
- return opened ? 'true' : 'false';
160
- }
128
+ this.addController(new SummaryController(this));
161
129
 
162
- /** @private */
163
- _getAriaHidden(opened) {
164
- return opened ? 'false' : 'true';
165
- }
166
-
167
- /** @private */
168
- _openedChanged(opened) {
169
- this._collapsible.style.maxHeight = opened ? '' : '0px';
170
- }
130
+ this._tooltipController = new TooltipController(this);
131
+ this.addController(this._tooltipController);
171
132
 
172
- /** @private */
173
- _onToggleClick() {
174
- this.opened = !this.opened;
133
+ this._tooltipController.setTarget(this._toggleElement);
134
+ this._tooltipController.setPosition('bottom-start');
175
135
  }
176
136
 
177
- /** @private */
178
- _onToggleKeyDown(e) {
179
- if ([13, 32].indexOf(e.keyCode) > -1) {
180
- e.preventDefault();
181
- this.opened = !this.opened;
182
- }
137
+ /**
138
+ * Override method inherited from `DisabledMixin`
139
+ * to not set `aria-disabled` on the host element.
140
+ *
141
+ * @protected
142
+ * @override
143
+ */
144
+ _setAriaDisabled() {
145
+ // The `aria-disabled` is set on the details summary.
183
146
  }
184
147
  }
185
148
 
@@ -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,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/details",
4
- "version": "24.0.0-alpha4",
4
+ "version": "24.0.0-alpha6",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
- "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.",
10
+ "name": "vaadin-details-summary",
11
+ "description": "The details summary element.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "disabled",
@@ -22,8 +22,8 @@
22
22
  }
23
23
  },
24
24
  {
25
- "name": "autofocus",
26
- "description": "Specify that this control should have input focus when the page loads.",
25
+ "name": "opened",
26
+ "description": "When true, the element is opened.",
27
27
  "value": {
28
28
  "type": [
29
29
  "boolean",
@@ -33,11 +33,68 @@
33
33
  }
34
34
  },
35
35
  {
36
- "name": "opened",
37
- "description": "If true, the details content is visible.",
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
+ },
75
+ {
76
+ "name": "vaadin-details",
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
+ "attributes": [
79
+ {
80
+ "name": "disabled",
81
+ "description": "If true, the user cannot interact with this element.",
38
82
  "value": {
39
83
  "type": [
40
- "boolean"
84
+ "boolean",
85
+ "null",
86
+ "undefined"
87
+ ]
88
+ }
89
+ },
90
+ {
91
+ "name": "autofocus",
92
+ "description": "Specify that this control should have input focus when the page loads.",
93
+ "value": {
94
+ "type": [
95
+ "boolean",
96
+ "null",
97
+ "undefined"
41
98
  ]
42
99
  }
43
100
  },
@@ -76,23 +133,9 @@
76
133
  "undefined"
77
134
  ]
78
135
  }
79
- },
80
- {
81
- "name": "opened",
82
- "description": "If true, the details content is visible.",
83
- "value": {
84
- "type": [
85
- "boolean"
86
- ]
87
- }
88
136
  }
89
137
  ],
90
- "events": [
91
- {
92
- "name": "opened-changed",
93
- "description": "Fired when the `opened` property changes."
94
- }
95
- ]
138
+ "events": []
96
139
  }
97
140
  }
98
141
  ]
@@ -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-alpha4",
4
+ "version": "24.0.0-alpha6",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -15,8 +15,8 @@
15
15
  "html": {
16
16
  "elements": [
17
17
  {
18
- "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.",
18
+ "name": "vaadin-details-summary",
19
+ "description": "The details summary element.",
20
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -27,22 +27,29 @@
27
27
  }
28
28
  },
29
29
  {
30
- "name": "?autofocus",
31
- "description": "Specify that this control should have input focus when the page loads.",
30
+ "name": "?opened",
31
+ "description": "When true, the element is opened.",
32
32
  "value": {
33
33
  "kind": "expression"
34
34
  }
35
- },
35
+ }
36
+ ]
37
+ },
38
+ {
39
+ "name": "vaadin-details",
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
+ "extension": true,
42
+ "attributes": [
36
43
  {
37
- "name": "?opened",
38
- "description": "If true, the details content is visible.",
44
+ "name": "?disabled",
45
+ "description": "If true, the user cannot interact with this element.",
39
46
  "value": {
40
47
  "kind": "expression"
41
48
  }
42
49
  },
43
50
  {
44
- "name": "@opened-changed",
45
- "description": "Fired when the `opened` property changes.",
51
+ "name": "?autofocus",
52
+ "description": "Specify that this control should have input focus when the page loads.",
46
53
  "value": {
47
54
  "kind": "expression"
48
55
  }