Skip to content

Commit c41752e

Browse files
committed
feat: add ability to provide custom overflow button #2
Code now checks for an existing button in slot "overflow-button". If none is found, then it creates the default button. The default button is added to the light dom, not the shadow dom anymore.
1 parent 7819e93 commit c41752e

File tree

3 files changed

+71
-24
lines changed

3 files changed

+71
-24
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ import '@vaadin-component-factory/vcf-toolbar-layout';
4545
</vcf-toolbar-layout>
4646
```
4747

48+
### Custom Overflow Button
49+
50+
```html
51+
<vcf-toolbar-layout>
52+
<vaadin-button slot="overflow-button">View overflow items</vaadin-button>
53+
</vcf-toolbar-layout>
54+
```
55+
4856
### Reverse Collapse and Debounce Delay
4957

5058
```html

demo/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,38 @@ <h3>Basic Demo Sample</h3>
5555
</vcf-toolbar-layout>
5656
</div>
5757

58+
<h3>Custom Overflow Button</h3>
59+
<p>Pass in your own button with <code>slot="overflow-button"</code>.
60+
<div class="resizable-wrapper">
61+
<vcf-toolbar-layout>
62+
<vaadin-text-field placeholder="Search">
63+
<vaadin-icon slot="suffix" icon="vaadin:search"></vaadin-icon>
64+
</vaadin-text-field>
65+
<hr>
66+
<vaadin-button>
67+
Download
68+
<vaadin-icon icon="vaadin:download" slot="suffix"></vaadin-icon>
69+
</vaadin-button>
70+
<vaadin-button theme="icon error">
71+
<vaadin-icon icon="vaadin:close" slot="prefix"></vaadin-icon>
72+
Remove
73+
</vaadin-button>
74+
<vaadin-button theme="contrast">
75+
<vaadin-icon icon="vaadin:arrow-backward" slot="prefix"></vaadin-icon>
76+
Undo
77+
</vaadin-button>
78+
<vaadin-menu-bar theme="dropdown-indicators"></vaadin-menu-bar>
79+
<a href="#">Link</a>
80+
<vaadin-combo-box
81+
placeholder="Select user"
82+
></vaadin-combo-box>
83+
<!-- add our custom overflow button with slot="overflow-button" -->
84+
<vaadin-button slot="overflow-button" part="overflow-button" theme="primary">
85+
View overflow items <vaadin-icon icon="vaadin:angle-right" slot="suffix"></vaadin-icon>
86+
</vaadin-button>
87+
</vcf-toolbar-layout>
88+
</div>
89+
5890
<h3>Reverse Collapse</h3>
5991
<p>Add attribute: <code>reverse-collapse</code></p>
6092
<div class="resizable-wrapper">

src/component/vcf-toolbar-layout.ts

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import '@vaadin/button';
2626
import '@vaadin/popover';
2727
import '@vaadin/vertical-layout';
2828
import { Popover } from '@vaadin/popover';
29+
import { Button } from '@vaadin/button';
2930

3031
@customElement('vcf-toolbar-layout')
3132
export class VcfToolbarLayout extends ResizeMixin(
@@ -56,27 +57,28 @@ export class VcfToolbarLayout extends ResizeMixin(
5657
gap: var(--vcf-toolbar-layout-gap););
5758
}
5859
59-
/* Overflow button is hidden unless needed */
60-
[slot='overflow-button'] {
60+
::slotted([slot="overflow-button"]) {
6161
display: none;
6262
}
63-
[slot='overflow-button'].visible {
63+
64+
::slotted([slot="overflow-button"].visible) {
6465
display: initial;
6566
}
6667
67-
:host([reverse-collapse]) [slot='overflow-button'] {
68+
:host([reverse-collapse]) ::slotted([slot='overflow-button']) {
6869
order: -1;
6970
}
7071
`;
7172
}
7273

7374
// overflow container is attached to the popover overlay (different shadow root) so we need to inject styles globally
74-
protected readonly _overflowContainerStyles: string = `
75+
protected readonly _globalStyles: string = `
7576
/* Hide label on icon buttons */
7677
vcf-toolbar-layout vaadin-button[theme~="icon"]::part(label) {
7778
display: none;
7879
}
79-
80+
81+
/* Overflow container styles */
8082
.overflow-container {
8183
--overflow-container-padding: var(--lumo-space-s);
8284
--overflow-container-item-gap: var(--lumo-space-xs);
@@ -271,20 +273,20 @@ export class VcfToolbarLayout extends ResizeMixin(
271273
return;
272274
}
273275

274-
// get the overflow button
275-
this._overflowButton = this.shadowRoot.querySelector('[slot="overflow-button"]') as HTMLElement;
276+
// get the overflow button (or create it)
277+
this._overflowButton = this.querySelector('[slot="overflow-button"]') as HTMLElement;
278+
if (!this._overflowButton) {
279+
this._overflowButton = this._createDefaultOverflowButton();
280+
this.appendChild(this._overflowButton);
281+
}
276282

277283
// setup overflow container
278284
this._overflowContainer = document.createElement('vaadin-vertical-layout');
279285
this._overflowContainer.classList.add('overflow-container');
280286

281287
// setup the popover
282288
let popover: Popover = this.shadowRoot.querySelector('vaadin-popover') as Popover;
283-
popover.setAttribute('for', 'overflow-button');
284-
popover.setAttribute("overlay-role", "menu");
285-
popover.setAttribute('accessible-name-ref', "overflowed menu items");
286-
popover.setAttribute('position', 'bottom-start');
287-
popover.setAttribute('modal', 'true');
289+
popover.target = this._overflowButton;
288290
popover.renderer = (root: Element) => {
289291
// Ensure content is only added once
290292
if (!root.firstChild) {
@@ -297,24 +299,29 @@ export class VcfToolbarLayout extends ResizeMixin(
297299
setTimeout(() => this._updateOverflowingItems(), 0);
298300
}
299301

302+
protected _createDefaultOverflowButton() {
303+
let button = document.createElement('vaadin-button') as Button;
304+
button.setAttribute('slot', 'overflow-button');
305+
button.setAttribute('part', 'overflow-button');
306+
button.setAttribute('theme', 'icon');
307+
button.setAttribute('aria-label', 'open menu');
308+
button.innerHTML = '<vaadin-icon icon="vaadin:ellipsis-dots-v" slot="suffix"></vaadin-icon>';
309+
return button;
310+
}
311+
300312
render() {
301313
return html`
302314
<slot></slot>
303315
<slot name="menu"></slot>
304316
<slot name="overflow-button"></slot>
305317
306-
<!-- todo: move this to be dynamically created so dev can provide their own button if desired -->
307-
<vaadin-button
308-
id="overflow-button"
309-
part="overflow-button"
310-
slot="overflow-button"
311-
theme="icon"
312-
>
313-
<vaadin-icon icon="vaadin:ellipsis-dots-v"></vaadin-icon>
314-
</vaadin-button>
315318
<vaadin-popover
316319
part="popover"
317320
theme="no-padding ${this.theme}"
321+
modal="true"
322+
position="bottom-start"
323+
overlay-role="menu"
324+
accessible-name-ref="overflowed menu items"
318325
></vaadin-popover>
319326
`;
320327
}
@@ -410,7 +417,7 @@ export class VcfToolbarLayout extends ResizeMixin(
410417
}
411418

412419
protected _getVisibleItems(): Element[] {
413-
return Array.from(this.querySelectorAll(':scope > *'));
420+
return Array.from(this.querySelectorAll(':scope > *:not([slot="overflow-button"])'));
414421
}
415422

416423
protected _getOverflowedItems(): Element[] {
@@ -466,7 +473,7 @@ export class VcfToolbarLayout extends ResizeMixin(
466473

467474
const style = document.createElement('style');
468475
style.id = styleId;
469-
style.textContent = this._overflowContainerStyles;
476+
style.textContent = this._globalStyles;
470477
document.head.appendChild(style);
471478
}
472479

0 commit comments

Comments
 (0)