@vaadin/menu-bar 25.2.13 → 25.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/menu-bar",
|
|
3
|
-
"version": "25.2.
|
|
3
|
+
"version": "25.2.14",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -35,23 +35,23 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
38
|
-
"@vaadin/a11y-base": "~25.2.
|
|
39
|
-
"@vaadin/button": "~25.2.
|
|
40
|
-
"@vaadin/component-base": "~25.2.
|
|
41
|
-
"@vaadin/context-menu": "~25.2.
|
|
42
|
-
"@vaadin/item": "~25.2.
|
|
43
|
-
"@vaadin/list-box": "~25.2.
|
|
44
|
-
"@vaadin/overlay": "~25.2.
|
|
45
|
-
"@vaadin/vaadin-themable-mixin": "~25.2.
|
|
38
|
+
"@vaadin/a11y-base": "~25.2.14",
|
|
39
|
+
"@vaadin/button": "~25.2.14",
|
|
40
|
+
"@vaadin/component-base": "~25.2.14",
|
|
41
|
+
"@vaadin/context-menu": "~25.2.14",
|
|
42
|
+
"@vaadin/item": "~25.2.14",
|
|
43
|
+
"@vaadin/list-box": "~25.2.14",
|
|
44
|
+
"@vaadin/overlay": "~25.2.14",
|
|
45
|
+
"@vaadin/vaadin-themable-mixin": "~25.2.14",
|
|
46
46
|
"lit": "^3.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@vaadin/aura": "~25.2.
|
|
50
|
-
"@vaadin/chai-plugins": "~25.2.
|
|
51
|
-
"@vaadin/icon": "~25.2.
|
|
52
|
-
"@vaadin/test-runner-commands": "~25.2.
|
|
49
|
+
"@vaadin/aura": "~25.2.14",
|
|
50
|
+
"@vaadin/chai-plugins": "~25.2.14",
|
|
51
|
+
"@vaadin/icon": "~25.2.14",
|
|
52
|
+
"@vaadin/test-runner-commands": "~25.2.14",
|
|
53
53
|
"@vaadin/testing-helpers": "^2.0.0",
|
|
54
|
-
"@vaadin/vaadin-lumo-styles": "~25.2.
|
|
54
|
+
"@vaadin/vaadin-lumo-styles": "~25.2.14",
|
|
55
55
|
"sinon": "^22.0.0"
|
|
56
56
|
},
|
|
57
57
|
"customElements": "custom-elements.json",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"web-types.json",
|
|
60
60
|
"web-types.lit.json"
|
|
61
61
|
],
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "7f2566cacb4ca4f83c44fbcc79776b4a3aa0823e"
|
|
63
63
|
}
|
|
@@ -15,6 +15,12 @@ export const menuBarStyles = css`
|
|
|
15
15
|
display: none !important;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/* Keep the width measured with all buttons in flow while the host is frozen */
|
|
19
|
+
:host([overflow-frozen]) {
|
|
20
|
+
contain: inline-size !important;
|
|
21
|
+
contain-intrinsic-inline-size: var(--_vaadin-menu-bar-content-width);
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
[part='container'] {
|
|
19
25
|
display: flex;
|
|
20
26
|
flex-wrap: nowrap;
|
|
@@ -475,7 +475,6 @@ export const MenuBarMixin = (superClass) =>
|
|
|
475
475
|
buttons.forEach((button) => {
|
|
476
476
|
button.style.visibility = '';
|
|
477
477
|
button.style.position = '';
|
|
478
|
-
button.style.width = '';
|
|
479
478
|
|
|
480
479
|
// Teleport item component back from "overflow" sub-menu
|
|
481
480
|
const item = button.item && button.item.component;
|
|
@@ -486,6 +485,19 @@ export const MenuBarMixin = (superClass) =>
|
|
|
486
485
|
this.__updateOverflow([]);
|
|
487
486
|
}
|
|
488
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Restores all buttons, the overflow button and the state attributes, so that
|
|
490
|
+
* the measurement does not use the button margins of the previous state.
|
|
491
|
+
*
|
|
492
|
+
* @param {!Array<!HTMLElement>} buttons
|
|
493
|
+
* @private
|
|
494
|
+
*/
|
|
495
|
+
__restoreState(buttons) {
|
|
496
|
+
this.__restoreButtons(buttons);
|
|
497
|
+
this.toggleAttribute('has-single-button', buttons.length === 1);
|
|
498
|
+
this.__updateVisibleAttributes(buttons);
|
|
499
|
+
}
|
|
500
|
+
|
|
489
501
|
/** @private */
|
|
490
502
|
__restoreItem(button, item) {
|
|
491
503
|
button.appendChild(item);
|
|
@@ -515,14 +527,28 @@ export const MenuBarMixin = (superClass) =>
|
|
|
515
527
|
}
|
|
516
528
|
|
|
517
529
|
/**
|
|
518
|
-
*
|
|
519
|
-
*
|
|
530
|
+
* Whether the element ends past the container, with the tolerance for fractional widths.
|
|
531
|
+
*
|
|
532
|
+
* @param {!HTMLElement} el
|
|
533
|
+
* @return {boolean}
|
|
534
|
+
* @private
|
|
535
|
+
*/
|
|
536
|
+
__isPastContainerEnd(el) {
|
|
537
|
+
return this.__getInlineEnd(el) > this.__getInlineEnd(this._container) + OVERFLOW_TOLERANCE;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Layout of the buttons, the overflow button and the container, read in one batch
|
|
542
|
+
* before any button is hidden. Positions are mirrored in RTL so that a larger value
|
|
543
|
+
* is always further along the inline axis.
|
|
520
544
|
*
|
|
521
545
|
* @typedef {object} MenuBarOverflowLayout
|
|
522
546
|
* @property {number[]} starts Inline start of each button
|
|
523
547
|
* @property {number[]} ends Inline end of each button
|
|
524
548
|
* @property {number[]} margins Inline start margin of each button
|
|
525
549
|
* @property {number} overflowExtent Space the overflow button adds after the last button
|
|
550
|
+
* @property {number} containerWidth Width of the container
|
|
551
|
+
* @property {number} contentWidth Width of all buttons and the overflow button in flow
|
|
526
552
|
*/
|
|
527
553
|
|
|
528
554
|
/**
|
|
@@ -531,17 +557,22 @@ export const MenuBarMixin = (superClass) =>
|
|
|
531
557
|
* @return {!MenuBarOverflowLayout}
|
|
532
558
|
* @private
|
|
533
559
|
*/
|
|
534
|
-
|
|
560
|
+
__getOverflowLayout(buttons, overflow) {
|
|
535
561
|
const isRTL = this.__isRTL;
|
|
536
562
|
const rects = buttons.map((btn) => btn.getBoundingClientRect());
|
|
537
563
|
const ends = rects.map(({ left, right }) => (isRTL ? -left : right));
|
|
564
|
+
const overflowEnd = this.__getInlineEnd(overflow);
|
|
565
|
+
const containerRect = this._container.getBoundingClientRect();
|
|
566
|
+
const containerStart = isRTL ? -containerRect.right : containerRect.left;
|
|
538
567
|
|
|
539
568
|
return {
|
|
540
569
|
starts: rects.map(({ left, right }) => (isRTL ? -right : left)),
|
|
541
570
|
ends,
|
|
542
571
|
// `auto` resolves to 0 while the content overflows.
|
|
543
572
|
margins: buttons.map((btn) => parseFloat(getComputedStyle(btn).marginInlineStart) || 0),
|
|
544
|
-
overflowExtent:
|
|
573
|
+
overflowExtent: overflowEnd - ends.at(-1),
|
|
574
|
+
containerWidth: containerRect.width,
|
|
575
|
+
contentWidth: overflowEnd - containerStart,
|
|
545
576
|
};
|
|
546
577
|
}
|
|
547
578
|
|
|
@@ -552,11 +583,10 @@ export const MenuBarMixin = (superClass) =>
|
|
|
552
583
|
*
|
|
553
584
|
* @param {!Array<!HTMLElement>} buttons
|
|
554
585
|
* @param {!MenuBarOverflowLayout} layout
|
|
555
|
-
* @param {number} containerWidth
|
|
556
586
|
* @return {!Array<!HTMLElement>} buttons to collapse, in DOM order
|
|
557
587
|
* @private
|
|
558
588
|
*/
|
|
559
|
-
|
|
589
|
+
__getButtonsToCollapse(buttons, { starts, ends, margins, overflowExtent, containerWidth }) {
|
|
560
590
|
let lo = 0;
|
|
561
591
|
let hi = buttons.length - 1;
|
|
562
592
|
|
|
@@ -572,38 +602,64 @@ export const MenuBarMixin = (superClass) =>
|
|
|
572
602
|
return buttons.filter((_, i) => i < lo || i > hi);
|
|
573
603
|
}
|
|
574
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Keeps the intrinsic width of the host at the given value. A parent sized by content,
|
|
607
|
+
* such as a split layout pane, shrinks the host once the buttons are out of flow. The
|
|
608
|
+
* width the host had with all buttons in flow keeps the collapse that was decided for it.
|
|
609
|
+
* The `overflow-frozen` attribute marks the frozen state for the styles and for the next
|
|
610
|
+
* detection. It is internal and not documented.
|
|
611
|
+
*
|
|
612
|
+
* @param {number} width
|
|
613
|
+
* @private
|
|
614
|
+
*/
|
|
615
|
+
__freezeWidth(width) {
|
|
616
|
+
this.style.setProperty('--_vaadin-menu-bar-content-width', `${width}px`);
|
|
617
|
+
this.setAttribute('overflow-frozen', '');
|
|
618
|
+
}
|
|
619
|
+
|
|
575
620
|
/** @private */
|
|
621
|
+
__unfreezeWidth() {
|
|
622
|
+
this.style.removeProperty('--_vaadin-menu-bar-content-width');
|
|
623
|
+
this.removeAttribute('overflow-frozen');
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Shows the overflow button and collapses buttons into it when the last button
|
|
628
|
+
* does not fit in the container. Freezes the host width when the parent shrinks
|
|
629
|
+
* the host after the collapse. A frozen host stays frozen until all buttons and the
|
|
630
|
+
* overflow button fit, so that its flex basis does not change between detections
|
|
631
|
+
* when another element in the same row depends on it.
|
|
632
|
+
*
|
|
633
|
+
* @param {!Array<!HTMLElement>} buttons
|
|
634
|
+
* @param {!HTMLElement} overflow
|
|
635
|
+
* @private
|
|
636
|
+
*/
|
|
576
637
|
__setOverflowItems(buttons, overflow) {
|
|
577
|
-
const container = this._container;
|
|
578
|
-
// Read before any write, so a menu bar that fits forces no layout
|
|
579
|
-
const width = container.offsetWidth;
|
|
580
638
|
const lastButton = buttons.at(-1);
|
|
639
|
+
// A frozen host is as wide as all buttons plus the overflow button, so the quick
|
|
640
|
+
// check would report a fit one overflow button too early. Measure instead.
|
|
641
|
+
const wasFrozen = this.hasAttribute('overflow-frozen');
|
|
642
|
+
if (!lastButton || (!wasFrozen && !this.__isPastContainerEnd(lastButton))) {
|
|
643
|
+
this.__unfreezeWidth();
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
this._hasOverflow = true;
|
|
581
647
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const layout = this.__measureButtons(buttons, overflow);
|
|
593
|
-
const containerWidth = container.getBoundingClientRect().width;
|
|
594
|
-
const collapsed = this.__getCollapsedButtons(buttons, layout, containerWidth);
|
|
595
|
-
// Read button widths once outside of the loop to avoid repetitive layout
|
|
596
|
-
const widths = collapsed.map((btn) => getComputedStyle(btn).width);
|
|
597
|
-
|
|
598
|
-
// Write the DOM state
|
|
599
|
-
collapsed.forEach((btn, i) => {
|
|
600
|
-
btn.style.width = widths[i];
|
|
601
|
-
btn.style.visibility = 'hidden';
|
|
602
|
-
btn.style.position = 'absolute';
|
|
603
|
-
});
|
|
604
|
-
this.__updateOverflow(collapsed.map((btn) => btn.item));
|
|
648
|
+
// Read the layout once the overflow button is in flow
|
|
649
|
+
const layout = this.__getOverflowLayout(buttons, overflow);
|
|
650
|
+
const collapsed = this.__getButtonsToCollapse(buttons, layout);
|
|
651
|
+
|
|
652
|
+
// Write the DOM state
|
|
653
|
+
collapsed.forEach((btn) => {
|
|
654
|
+
btn.style.visibility = 'hidden';
|
|
655
|
+
btn.style.position = 'absolute';
|
|
656
|
+
});
|
|
657
|
+
this.__updateOverflow(collapsed.map((btn) => btn.item));
|
|
605
658
|
|
|
606
|
-
|
|
659
|
+
if (collapsed.length === 0) {
|
|
660
|
+
this.__unfreezeWidth();
|
|
661
|
+
} else if (wasFrozen || this.__isPastContainerEnd(overflow)) {
|
|
662
|
+
this.__freezeWidth(layout.contentWidth);
|
|
607
663
|
}
|
|
608
664
|
}
|
|
609
665
|
|
|
@@ -620,8 +676,7 @@ export const MenuBarMixin = (superClass) =>
|
|
|
620
676
|
const buttons = this._buttons.filter((btn) => btn !== overflow);
|
|
621
677
|
const oldOverflowCount = this.__getOverflowCount(overflow);
|
|
622
678
|
|
|
623
|
-
|
|
624
|
-
this.__restoreButtons(buttons);
|
|
679
|
+
this.__restoreState(buttons);
|
|
625
680
|
|
|
626
681
|
// Hide any overflowing buttons and put them in the 'overflow' button
|
|
627
682
|
this.__setOverflowItems(buttons, overflow);
|
|
@@ -646,8 +701,12 @@ export const MenuBarMixin = (superClass) =>
|
|
|
646
701
|
this._setTabindex(visibleButtons[visibleButtons.length - 1], true);
|
|
647
702
|
}
|
|
648
703
|
|
|
649
|
-
|
|
650
|
-
|
|
704
|
+
this.__updateVisibleAttributes(visibleButtons);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/** @private */
|
|
708
|
+
__updateVisibleAttributes(visibleButtons) {
|
|
709
|
+
visibleButtons.forEach((btn, index) => {
|
|
651
710
|
btn.toggleAttribute('first-visible', index === 0);
|
|
652
711
|
btn.toggleAttribute('last-visible', !this._hasOverflow && index === visibleButtons.length - 1);
|
|
653
712
|
});
|
package/web-types.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/menu-bar",
|
|
4
|
-
"version": "25.2.
|
|
4
|
+
"version": "25.2.14",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
8
8
|
"elements": [
|
|
9
9
|
{
|
|
10
10
|
"name": "vaadin-menu-bar",
|
|
11
|
-
"description": "`<vaadin-menu-bar>` is a Web Component providing a set of horizontally stacked buttons offering\nthe user quick access to a consistent set of commands. Each button can toggle a submenu with\nsupport for additional levels of nested menus.\n\nTo create the menu bar, first add the component to the page:\n\n```html\n<vaadin-menu-bar></vaadin-menu-bar>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/25.2.
|
|
11
|
+
"description": "`<vaadin-menu-bar>` is a Web Component providing a set of horizontally stacked buttons offering\nthe user quick access to a consistent set of commands. Each button can toggle a submenu with\nsupport for additional levels of nested menus.\n\nTo create the menu bar, first add the component to the page:\n\n```html\n<vaadin-menu-bar></vaadin-menu-bar>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-menu-bar#property-items) property to initialize the structure:\n\n```js\ndocument.querySelector('vaadin-menu-bar').items = [{text: 'File'}, {text: 'Edit'}];\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n------------------|----------------\n`container` | The container wrapping menu bar buttons.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n--------------------|----------------------------------\n`disabled` | Set when the menu bar is disabled\n`has-single-button` | Set when there is only one button visible\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:---------------------------|\n| `--vaadin-menu-bar-gap` |\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nIn addition to `<vaadin-menu-bar>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-menu-bar-button>` - has the same API as [`<vaadin-button>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-button).\n- `<vaadin-menu-bar-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-item).\n- `<vaadin-menu-bar-list-box>` - has the same API as [`<vaadin-list-box>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-list-box).\n- `<vaadin-menu-bar-submenu>` - has the same API as [`<vaadin-context-menu>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-context-menu).\n\nThe `<vaadin-menu-bar-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
12
12
|
"attributes": [
|
|
13
13
|
{
|
|
14
14
|
"name": "disabled",
|
package/web-types.lit.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/menu-bar",
|
|
4
|
-
"version": "25.2.
|
|
4
|
+
"version": "25.2.14",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"framework": "lit",
|
|
7
7
|
"framework-config": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"elements": [
|
|
17
17
|
{
|
|
18
18
|
"name": "vaadin-menu-bar",
|
|
19
|
-
"description": "`<vaadin-menu-bar>` is a Web Component providing a set of horizontally stacked buttons offering\nthe user quick access to a consistent set of commands. Each button can toggle a submenu with\nsupport for additional levels of nested menus.\n\nTo create the menu bar, first add the component to the page:\n\n```html\n<vaadin-menu-bar></vaadin-menu-bar>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/25.2.
|
|
19
|
+
"description": "`<vaadin-menu-bar>` is a Web Component providing a set of horizontally stacked buttons offering\nthe user quick access to a consistent set of commands. Each button can toggle a submenu with\nsupport for additional levels of nested menus.\n\nTo create the menu bar, first add the component to the page:\n\n```html\n<vaadin-menu-bar></vaadin-menu-bar>\n```\n\nAnd then use [`items`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-menu-bar#property-items) property to initialize the structure:\n\n```js\ndocument.querySelector('vaadin-menu-bar').items = [{text: 'File'}, {text: 'Edit'}];\n```\n\n### Styling\n\nThe following shadow DOM parts are exposed for styling:\n\nPart name | Description\n------------------|----------------\n`container` | The container wrapping menu bar buttons.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n--------------------|----------------------------------\n`disabled` | Set when the menu bar is disabled\n`has-single-button` | Set when there is only one button visible\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:---------------------------|\n| `--vaadin-menu-bar-gap` |\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nIn addition to `<vaadin-menu-bar>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-menu-bar-button>` - has the same API as [`<vaadin-button>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-button).\n- `<vaadin-menu-bar-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-item).\n- `<vaadin-menu-bar-list-box>` - has the same API as [`<vaadin-list-box>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-list-box).\n- `<vaadin-menu-bar-submenu>` - has the same API as [`<vaadin-context-menu>`](https://cdn.vaadin.com/vaadin-web-components/25.2.14/#/elements/vaadin-context-menu).\n\nThe `<vaadin-menu-bar-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
20
20
|
"extension": true,
|
|
21
21
|
"attributes": [
|
|
22
22
|
{
|