@vaadin/menu-bar 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.
@@ -1,287 +0,0 @@
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
- import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
7
-
8
- /**
9
- * @polymerMixin
10
- * @mixes ResizeMixin
11
- */
12
- export const ButtonsMixin = (superClass) =>
13
- class extends ResizeMixin(superClass) {
14
- static get properties() {
15
- return {
16
- /**
17
- * @type {boolean}
18
- * @protected
19
- */
20
- _hasOverflow: {
21
- type: Boolean,
22
- value: false,
23
- },
24
- };
25
- }
26
-
27
- static get observers() {
28
- return ['_menuItemsChanged(items, items.splices)'];
29
- }
30
-
31
- /**
32
- * Override getter from `ResizeMixin` to observe parent.
33
- *
34
- * @protected
35
- * @override
36
- */
37
- get _observeParent() {
38
- return true;
39
- }
40
-
41
- /** @protected */
42
- ready() {
43
- super.ready();
44
-
45
- this.setAttribute('role', 'menubar');
46
- }
47
-
48
- /** @protected */
49
- connectedCallback() {
50
- super.connectedCallback();
51
-
52
- this._initButtonAttrs(this._overflow);
53
- }
54
-
55
- /**
56
- * @return {!Array<!HTMLElement>}
57
- * @protected
58
- */
59
- get _buttons() {
60
- return Array.from(this.shadowRoot.querySelectorAll('[part$="button"]'));
61
- }
62
-
63
- /**
64
- * @return {!HTMLElement}
65
- * @protected
66
- */
67
- get _container() {
68
- return this.shadowRoot.querySelector('[part="container"]');
69
- }
70
-
71
- /**
72
- * @return {!HTMLElement}
73
- * @protected
74
- */
75
- get _overflow() {
76
- return this.shadowRoot.querySelector('[part="overflow-button"]');
77
- }
78
-
79
- /** @private */
80
- _menuItemsChanged(items) {
81
- if (items !== this._oldItems) {
82
- this._oldItems = items;
83
- this.__renderButtons(items);
84
- }
85
- }
86
-
87
- /** @private */
88
- __getOverflowCount(overflow) {
89
- // We can't use optional chaining due to webpack 4
90
- return (overflow.item && overflow.item.children && overflow.item.children.length) || 0;
91
- }
92
-
93
- /** @private */
94
- __restoreButtons(buttons) {
95
- for (let i = 0; i < buttons.length; i++) {
96
- const btn = buttons[i];
97
- btn.disabled = (btn.item && btn.item.disabled) || this.disabled;
98
- btn.style.visibility = '';
99
- btn.style.position = '';
100
-
101
- // Teleport item component back from "overflow" sub-menu
102
- const item = btn.item && btn.item.component;
103
- if (item instanceof HTMLElement && item.classList.contains('vaadin-menu-item')) {
104
- btn.appendChild(item);
105
- item.classList.remove('vaadin-menu-item');
106
- }
107
- }
108
- this.__updateOverflow([]);
109
- }
110
-
111
- /** @private */
112
- __updateOverflow(items) {
113
- this._overflow.item = { children: items };
114
- this._hasOverflow = items.length > 0;
115
- }
116
-
117
- /** @private */
118
- __setOverflowItems(buttons, overflow) {
119
- const container = this._container;
120
-
121
- if (container.offsetWidth < container.scrollWidth) {
122
- this._hasOverflow = true;
123
-
124
- const isRTL = this.getAttribute('dir') === 'rtl';
125
-
126
- let i;
127
- for (i = buttons.length; i > 0; i--) {
128
- const btn = buttons[i - 1];
129
- const btnStyle = getComputedStyle(btn);
130
-
131
- // If this button isn't overflowing, then the rest aren't either
132
- if (
133
- (!isRTL && btn.offsetLeft + btn.offsetWidth < container.offsetWidth - overflow.offsetWidth) ||
134
- (isRTL && btn.offsetLeft >= overflow.offsetWidth)
135
- ) {
136
- break;
137
- }
138
-
139
- btn.disabled = true;
140
- btn.style.visibility = 'hidden';
141
- btn.style.position = 'absolute';
142
- // Save width for buttons with component
143
- btn.style.width = btnStyle.width;
144
- }
145
- const items = buttons.filter((_, idx) => idx >= i).map((b) => b.item);
146
- this.__updateOverflow(items);
147
- }
148
- }
149
-
150
- /** @private */
151
- __detectOverflow() {
152
- const overflow = this._overflow;
153
- const buttons = this._buttons.filter((btn) => btn !== overflow);
154
- const oldOverflowCount = this.__getOverflowCount(overflow);
155
-
156
- // Reset all buttons in the menu bar and the overflow button
157
- this.__restoreButtons(buttons);
158
-
159
- // Hide any overflowing buttons and put them in the 'overflow' button
160
- this.__setOverflowItems(buttons, overflow);
161
-
162
- const newOverflowCount = this.__getOverflowCount(overflow);
163
- if (oldOverflowCount !== newOverflowCount && this._subMenu.opened) {
164
- this._subMenu.close();
165
- }
166
-
167
- const isSingleButton = newOverflowCount === buttons.length || (newOverflowCount === 0 && buttons.length === 1);
168
- this.toggleAttribute('has-single-button', isSingleButton);
169
- }
170
-
171
- /** @protected */
172
- _removeButtons() {
173
- const container = this._container;
174
-
175
- while (container.children.length > 1) {
176
- container.removeChild(container.firstElementChild);
177
- }
178
- }
179
-
180
- /** @protected */
181
- _initButton(item) {
182
- const button = document.createElement('vaadin-menu-bar-button');
183
- button.setAttribute('part', 'menu-bar-button');
184
-
185
- const itemCopy = { ...item };
186
- button.item = itemCopy;
187
-
188
- if (item.component) {
189
- const component = this.__getComponent(itemCopy);
190
- itemCopy.component = component;
191
- // Save item for overflow menu
192
- component.item = itemCopy;
193
- button.appendChild(component);
194
- } else if (item.text) {
195
- button.textContent = item.text;
196
- }
197
-
198
- return button;
199
- }
200
-
201
- /** @protected */
202
- _initButtonAttrs(button) {
203
- button.setAttribute('role', 'menuitem');
204
-
205
- if (button === this._overflow || (button.item && button.item.children)) {
206
- button.setAttribute('aria-haspopup', 'true');
207
- button.setAttribute('aria-expanded', 'false');
208
- }
209
- }
210
-
211
- /** @protected */
212
- _setButtonDisabled(button, disabled) {
213
- button.disabled = disabled;
214
- button.setAttribute('tabindex', disabled ? '-1' : '0');
215
- }
216
-
217
- /** @protected */
218
- _setButtonTheme(btn, hostTheme) {
219
- let theme = hostTheme;
220
-
221
- // Item theme takes precedence over host theme even if it's empty, as long as it's not undefined or null
222
- const itemTheme = btn.item && btn.item.theme;
223
- if (itemTheme != null) {
224
- theme = Array.isArray(itemTheme) ? itemTheme.join(' ') : itemTheme;
225
- }
226
-
227
- if (theme) {
228
- btn.setAttribute('theme', theme);
229
- } else {
230
- btn.removeAttribute('theme');
231
- }
232
- }
233
-
234
- /** @protected */
235
- _appendButton(button) {
236
- this._container.insertBefore(button, this._overflow);
237
- }
238
-
239
- /** @private */
240
- __getComponent(item) {
241
- const itemComponent = item.component;
242
- let component;
243
-
244
- const isElement = itemComponent instanceof HTMLElement;
245
- // Use existing item component, if any
246
- if (isElement && itemComponent.localName === 'vaadin-context-menu-item') {
247
- component = itemComponent;
248
- } else {
249
- component = document.createElement('vaadin-context-menu-item');
250
- component.appendChild(isElement ? itemComponent : document.createElement(itemComponent));
251
- }
252
- if (item.text) {
253
- const node = component.firstChild || component;
254
- node.textContent = item.text;
255
- }
256
- component.setAttribute('theme', 'menu-bar-item');
257
- return component;
258
- }
259
-
260
- /** @private */
261
- __renderButtons(items = []) {
262
- this._removeButtons();
263
-
264
- /* Empty array, do nothing */
265
- if (items.length === 0) {
266
- return;
267
- }
268
-
269
- items.forEach((item) => {
270
- const button = this._initButton(item);
271
- this._appendButton(button);
272
- this._setButtonDisabled(button, item.disabled);
273
- this._initButtonAttrs(button);
274
- this._setButtonTheme(button, this._theme);
275
- });
276
-
277
- this.__detectOverflow();
278
- }
279
-
280
- /**
281
- * @protected
282
- * @override
283
- */
284
- _onResize() {
285
- this.__detectOverflow();
286
- }
287
- };