8
8
* <overflow-menu></overflow-menu>
9
9
* ```
10
10
*/
11
+ const stylesheet = new CSSStyleSheet ( )
12
+ stylesheet . replaceSync ( `
13
+ :host {
14
+ display: flex;
15
+ gap: 0.5em;
16
+ }
17
+ div {
18
+ position: relative;
19
+ }
20
+ #overflow {
21
+ position: absolute;
22
+ }
23
+ ::slotted(overflow-menu-item::part(label)) {
24
+ display: none
25
+ }
26
+ ` )
27
+
28
+ const resizeObserver = new ResizeObserver ( records => {
29
+ for ( const record of records ) {
30
+ if ( record . target instanceof OverflowMenuElement ) {
31
+ record . target . assignElements ( )
32
+ }
33
+ }
34
+ } )
35
+
11
36
class OverflowMenuElement extends HTMLElement {
37
+ #renderRoot! : ShadowRoot
38
+
39
+ #mainSlot: HTMLSlotElement
40
+ #overflowSlot: HTMLSlotElement
41
+ #button: HTMLButtonElement
42
+ #overflow: HTMLElement
43
+
44
+ async connectedCallback ( ) : void {
45
+ this . #renderRoot = this . attachShadow ( { mode : 'open' , slotAssignment : 'manual' } )
46
+ this . #renderRoot. innerHTML = `
47
+ <slot></slot>
48
+ <div>
49
+ <button id="more">
50
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-more-vertical"><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle></svg>
51
+ </button>
52
+ <div id="overflow" hidden>
53
+ <slot name="overflow"></slot>
54
+ </div>
55
+ </div>
56
+ `
57
+ this . #button = this . #renderRoot. querySelector ( 'button' ) !
58
+ this . #overflow = this . #renderRoot. querySelector ( '#overflow' ) !
59
+ this . #mainSlot = this . #renderRoot. querySelector ( 'slot:not([name])' ) !
60
+ this . #overflowSlot = this . #renderRoot. querySelector ( 'slot[name=overflow]' ) !
61
+ this . #renderRoot. adoptedStyleSheets . push ( stylesheet )
62
+ this . #renderRoot. addEventListener ( 'click' , this )
63
+ resizeObserver . observe ( this )
64
+ await Promise . resolve ( )
65
+ this . assignElements ( )
66
+ }
67
+
68
+ assignElements ( ) {
69
+ const els = this . querySelectorAll ( 'overflow-menu-item' )
70
+ this . #mainSlot. assign ( ...els )
71
+ let totalWidth = this . getBoundingClientRect ( ) . width
72
+ const overflowEls = [ ]
73
+ for ( const el of els ) {
74
+ const width = el . getBoundingClientRect ( ) . width
75
+ if ( totalWidth - width < 0 ) {
76
+ overflowEls . push ( el )
77
+ }
78
+ totalWidth -= width
79
+ }
80
+ this . #overflowSlot. assign ( ...overflowEls )
81
+ }
82
+
83
+ handleEvent ( event : Event ) {
84
+ if ( event . type === 'click' && event . target . closest ( 'button' ) === this . #button) {
85
+ this . #overflow. hidden = ! this . #overflow. hidden
86
+ }
87
+ }
88
+ }
89
+
90
+ const itemStylesheet = new CSSStyleSheet ( )
91
+ itemStylesheet . replaceSync ( `
92
+ :host {
93
+ display: flex;
94
+ place-items: center;
95
+ min-width: 100px;
96
+ }
97
+ ` )
98
+ // eslint-disable-next-line
99
+ class OverflowMenuItemElement extends HTMLElement {
100
+ #renderRoot! : ShadowRoot
101
+
12
102
connectedCallback ( ) : void {
13
- this . textContent = ':wave:'
103
+ this . #renderRoot = this . attachShadow ( { mode : 'open' } )
104
+ this . #renderRoot. innerHTML = `<slot name="icon"></slot><slot part="label"></slot>`
105
+ this . #renderRoot. adoptedStyleSheets . push ( itemStylesheet )
14
106
}
15
107
}
16
108
@@ -26,3 +118,8 @@ if (!window.customElements.get('overflow-menu')) {
26
118
window . OverflowMenuElement = OverflowMenuElement
27
119
window . customElements . define ( 'overflow-menu' , OverflowMenuElement )
28
120
}
121
+
122
+ if ( ! window . customElements . get ( 'overflow-menu-item' ) ) {
123
+ window . OverflowMenuItemElement = OverflowMenuItemElement
124
+ window . customElements . define ( 'overflow-menu-item' , OverflowMenuItemElement )
125
+ }
0 commit comments