88 * <overflow-menu></overflow-menu>
99 * ```
1010 */
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+
1136class 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+
12102 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 )
14106 }
15107}
16108
@@ -26,3 +118,8 @@ if (!window.customElements.get('overflow-menu')) {
26118 window . OverflowMenuElement = OverflowMenuElement
27119 window . customElements . define ( 'overflow-menu' , OverflowMenuElement )
28120}
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