@vaadin/details 24.0.0-alpha5 → 24.0.0-alpha7

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-alpha5",
3
+ "version": "24.0.0-alpha7",
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-alpha5",
40
- "@vaadin/field-base": "24.0.0-alpha5",
41
- "@vaadin/vaadin-lumo-styles": "24.0.0-alpha5",
42
- "@vaadin/vaadin-material-styles": "24.0.0-alpha5",
43
- "@vaadin/vaadin-themable-mixin": "24.0.0-alpha5"
40
+ "@vaadin/button": "24.0.0-alpha7",
41
+ "@vaadin/component-base": "24.0.0-alpha7",
42
+ "@vaadin/field-base": "24.0.0-alpha7",
43
+ "@vaadin/vaadin-lumo-styles": "24.0.0-alpha7",
44
+ "@vaadin/vaadin-material-styles": "24.0.0-alpha7",
45
+ "@vaadin/vaadin-themable-mixin": "24.0.0-alpha7"
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": "fc0b1721eda9e39cb289b239e440fc9e29573a31"
56
+ "gitHead": "aeb4535336813636736759e0a5de148b26bfc3b6"
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
+ * List of elements passed to the details default slot.
21
+ */
22
+ protected _contentElements: HTMLElement[];
23
+
24
+ /**
25
+ * An element used to toggle the content visibility.
26
+ */
27
+ protected _toggleElement: HTMLElement;
28
+ }
@@ -0,0 +1,84 @@
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
+ * List of elements passed to the details default slot.
29
+ *
30
+ * @protected
31
+ */
32
+ _contentElements: {
33
+ type: Array,
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)', '_openedOrContentChanged(opened, _contentElements)'];
51
+ }
52
+
53
+ /** @private */
54
+ _openedOrContentChanged(opened, elements) {
55
+ if (elements) {
56
+ elements.forEach((el) => {
57
+ el.setAttribute('aria-hidden', opened ? 'false' : 'true');
58
+ });
59
+ }
60
+ }
61
+
62
+ /** @private */
63
+ _openedOrToggleChanged(opened, toggleElement) {
64
+ if (toggleElement) {
65
+ toggleElement.setAttribute('aria-expanded', opened ? 'true' : 'false');
66
+ }
67
+ }
68
+
69
+ /** @private */
70
+ _toggleElementChanged(toggleElement) {
71
+ if (toggleElement) {
72
+ // Only handle click and not keydown, because `vaadin-details-summary` uses `ButtonMixin`
73
+ // that already covers this logic, and `vaadin-accordion-heading` uses native `<button>`.
74
+ toggleElement.addEventListener('click', () => {
75
+ this._toggle();
76
+ });
77
+ }
78
+ }
79
+
80
+ /** @private */
81
+ _toggle() {
82
+ this.opened = !this.opened;
83
+ }
84
+ };
@@ -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,49 @@
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';
11
+ import { SlotObserveController } from '@vaadin/component-base/src/slot-observe-controller.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';
13
+ import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.js';
14
+ import { DelegateStateMixin } from '@vaadin/field-base/src/delegate-state-mixin.js';
12
15
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
16
+ import { DetailsMixin } from './vaadin-details-mixin.js';
17
+
18
+ class SummaryController extends SlotController {
19
+ constructor(host) {
20
+ super(host, 'summary', 'vaadin-details-summary', {
21
+ useUniqueId: true,
22
+ initializer: (node, host) => {
23
+ host._toggleElement = node;
24
+ host._setFocusElement(node);
25
+ host.stateTarget = node;
26
+ },
27
+ });
28
+ }
29
+ }
30
+
31
+ class ContentController extends SlotObserveController {
32
+ /**
33
+ * Override method from `SlotController` to change
34
+ * the ID prefix for the default slot content.
35
+ *
36
+ * @param {HTMLElement} host
37
+ * @return {string}
38
+ * @protected
39
+ * @override
40
+ */
41
+ static generateId(host) {
42
+ return super.generateId(host, 'content');
43
+ }
44
+
45
+ constructor(host) {
46
+ super(host, '', null, { multiple: true });
47
+ }
48
+ }
13
49
 
14
50
  /**
15
51
  * `<vaadin-details>` is a Web Component which the creates an
@@ -17,8 +53,10 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
17
53
  *
18
54
  * ```
19
55
  * <vaadin-details>
20
- * <div slot="summary">Expandable Details</div>
21
- * Toggle using mouse, Enter and Space keys.
56
+ * <vaadin-details-summary slot="summary">Expandable Details</vaadin-details-summary>
57
+ * <div>
58
+ * Toggle using mouse, Enter and Space keys.
59
+ * </div>
22
60
  * </vaadin-details>
23
61
  * ```
24
62
  *
@@ -48,11 +86,14 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
48
86
  *
49
87
  * @extends HTMLElement
50
88
  * @mixes ControllerMixin
51
- * @mixes ShadowFocusMixin
89
+ * @mixes DelegateFocusMixin
90
+ * @mixes DelegateStateMixin
52
91
  * @mixes ElementMixin
53
92
  * @mixes ThemableMixin
54
93
  */
55
- class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement)))) {
94
+ class Details extends DetailsMixin(
95
+ DelegateStateMixin(DelegateFocusMixin(ElementMixin(ThemableMixin(ControllerMixin(PolymerElement))))),
96
+ ) {
56
97
  static get template() {
57
98
  return html`
58
99
  <style>
@@ -66,36 +107,20 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
66
107
 
67
108
  [part='content'] {
68
109
  display: none;
69
- overflow: hidden;
70
- }
71
-
72
- [part='summary'][disabled] {
73
- pointer-events: none;
74
110
  }
75
111
 
76
112
  :host([opened]) [part='content'] {
77
113
  display: block;
78
- overflow: visible;
79
114
  }
80
115
  </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)]]">
116
+
117
+ <slot name="summary"></slot>
118
+
119
+ <div part="content">
97
120
  <slot></slot>
98
- </section>
121
+ </div>
122
+
123
+ <slot name="tooltip"></slot>
99
124
  `;
100
125
  }
101
126
 
@@ -103,83 +128,64 @@ class Details extends ShadowFocusMixin(ElementMixin(ThemableMixin(ControllerMixi
103
128
  return 'vaadin-details';
104
129
  }
105
130
 
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
- };
131
+ static get delegateAttrs() {
132
+ return ['theme'];
120
133
  }
121
134
 
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"]');
135
+ static get delegateProps() {
136
+ return ['disabled', 'opened'];
137
137
  }
138
138
 
139
139
  /** @protected */
140
140
  ready() {
141
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
- }
148
- });
149
142
 
150
- this._tooltipController = new TooltipController(this);
151
- this.addController(this._tooltipController);
152
-
153
- this._tooltipController.setTarget(this.focusElement);
154
- this._tooltipController.setPosition('bottom-start');
143
+ this._initSummary();
144
+ this._initContent();
145
+ this._initTooltip();
155
146
  }
156
147
 
157
- /** @private */
158
- _getAriaExpanded(opened) {
159
- return opened ? 'true' : 'false';
148
+ /**
149
+ * Override method inherited from `DisabledMixin`
150
+ * to not set `aria-disabled` on the host element.
151
+ *
152
+ * @protected
153
+ * @override
154
+ */
155
+ _setAriaDisabled() {
156
+ // The `aria-disabled` is set on the details summary.
160
157
  }
161
158
 
162
159
  /** @private */
163
- _getAriaHidden(opened) {
164
- return opened ? 'false' : 'true';
160
+ _initSummary() {
161
+ this._summaryController = new SummaryController(this);
162
+ this.addController(this._summaryController);
165
163
  }
166
164
 
167
165
  /** @private */
168
- _openedChanged(opened) {
169
- this._collapsible.style.maxHeight = opened ? '' : '0px';
166
+ _initContent() {
167
+ this._contentController = new ContentController(this);
168
+ this._contentController.addEventListener('slot-content-changed', (event) => {
169
+ // Store nodes to toggle `aria-hidden` attribute
170
+ const { nodes } = event.target;
171
+ this._contentElements = nodes;
172
+
173
+ if (nodes[0] && nodes[0].id) {
174
+ this._toggleElement.setAttribute('aria-controls', nodes[0].id);
175
+ } else {
176
+ this._toggleElement.removeAttribute('aria-controls');
177
+ }
178
+ });
179
+ this.addController(this._contentController);
170
180
  }
171
181
 
172
182
  /** @private */
173
- _onToggleClick() {
174
- this.opened = !this.opened;
175
- }
183
+ _initTooltip() {
184
+ this._tooltipController = new TooltipController(this);
185
+ this.addController(this._tooltipController);
176
186
 
177
- /** @private */
178
- _onToggleKeyDown(e) {
179
- if ([13, 32].indexOf(e.keyCode) > -1) {
180
- e.preventDefault();
181
- this.opened = !this.opened;
182
- }
187
+ this._tooltipController.setTarget(this._toggleElement);
188
+ this._tooltipController.setPosition('bottom-start');
183
189
  }
184
190
  }
185
191
 
@@ -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-alpha5",
4
+ "version": "24.0.0-alpha7",
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
  },
@@ -78,21 +135,45 @@
78
135
  }
79
136
  },
80
137
  {
81
- "name": "opened",
82
- "description": "If true, the details content is visible.",
138
+ "name": "rootPath",
139
+ "description": "",
83
140
  "value": {
84
141
  "type": [
85
- "boolean"
142
+ "string"
86
143
  ]
87
144
  }
88
- }
89
- ],
90
- "events": [
145
+ },
146
+ {
147
+ "name": "importPath",
148
+ "description": "",
149
+ "value": {
150
+ "type": [
151
+ "string"
152
+ ]
153
+ }
154
+ },
155
+ {
156
+ "name": "root",
157
+ "description": "",
158
+ "value": {
159
+ "type": [
160
+ "StampedTemplate",
161
+ "HTMLElement",
162
+ "ShadowRoot"
163
+ ]
164
+ }
165
+ },
91
166
  {
92
- "name": "opened-changed",
93
- "description": "Fired when the `opened` property changes."
167
+ "name": "$",
168
+ "description": "",
169
+ "value": {
170
+ "type": [
171
+ "Object.<string, Element>"
172
+ ]
173
+ }
94
174
  }
95
- ]
175
+ ],
176
+ "events": []
96
177
  }
97
178
  }
98
179
  ]
@@ -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-alpha5",
4
+ "version": "24.0.0-alpha7",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -14,9 +14,30 @@
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": [
22
43
  {
@@ -34,15 +55,29 @@
34
55
  }
35
56
  },
36
57
  {
37
- "name": "?opened",
38
- "description": "If true, the details content is visible.",
58
+ "name": ".rootPath",
59
+ "description": "",
60
+ "value": {
61
+ "kind": "expression"
62
+ }
63
+ },
64
+ {
65
+ "name": ".importPath",
66
+ "description": "",
67
+ "value": {
68
+ "kind": "expression"
69
+ }
70
+ },
71
+ {
72
+ "name": ".root",
73
+ "description": "",
39
74
  "value": {
40
75
  "kind": "expression"
41
76
  }
42
77
  },
43
78
  {
44
- "name": "@opened-changed",
45
- "description": "Fired when the `opened` property changes.",
79
+ "name": ".$",
80
+ "description": "",
46
81
  "value": {
47
82
  "kind": "expression"
48
83
  }