Skip to content

Commit 77e9878

Browse files
committed
initial implementation
1 parent 60451ec commit 77e9878

File tree

3 files changed

+143
-4
lines changed

3 files changed

+143
-4
lines changed

examples/index.html

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,51 @@
33
<head>
44
<meta charset="utf-8" />
55
<title>overflow-menu demo</title>
6+
<style>
7+
:root {
8+
font-family: sans-serif
9+
}
10+
</style>
611
</head>
712
<body>
8-
<overflow-menu></overflow-menu>
13+
<overflow-menu>
14+
<overflow-menu-item>
15+
<svg slot="icon" 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"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path></svg>
16+
<span>Bold</span>
17+
</overflow-menu-item>
18+
<overflow-menu-item>
19+
<svg slot="icon" 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"><line x1="19" y1="4" x2="10" y2="4"></line><line x1="14" y1="20" x2="5" y2="20"></line><line x1="15" y1="4" x2="9" y2="20"></line></svg>
20+
<span>Italic</span>
21+
</overflow-menu-item>
22+
<overflow-menu-item>
23+
<svg slot="icon" 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"><path d="M6 4v6a6 6 0 0 0 12 0V4"></path><line x1="4" y1="20" x2="20" y2="20"></line></svg>
24+
<span>Underline</span>
25+
</overflow-menu-item>
26+
<overflow-menu-item>
27+
<svg slot="icon" 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"><line x1="21" y1="6" x2="3" y2="6"></line><line x1="15" y1="12" x2="3" y2="12"></line><line x1="17" y1="18" x2="3" y2="18"></line></svg>
28+
<span>Align Left</span>
29+
</overflow-menu-item>
30+
<overflow-menu-item>
31+
<svg slot="icon" 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"><line x1="21" y1="6" x2="3" y2="6"></line><line x1="17" y1="12" x2="7" y2="12"></line><line x1="19" y1="18" x2="5" y2="18"></line></svg>
32+
<span>Align Center</span>
33+
</overflow-menu-item>
34+
<overflow-menu-item>
35+
<svg slot="icon" 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"><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="12" x2="9" y2="12"></line><line x1="21" y1="18" x2="7" y2="18"></line></svg>
36+
<span>Align Right</span>
37+
</overflow-menu-item>
38+
<overflow-menu-item>
39+
<svg slot="icon" 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"><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
40+
<span>Justify</span>
41+
</overflow-menu-item>
42+
<overflow-menu-item>
43+
<svg slot="icon" 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"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
44+
<span>Download</span>
45+
</overflow-menu-item>
46+
<overflow-menu-item>
47+
<svg slot="icon" 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"><path d="M5 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-1"></path><polygon points="12 15 17 21 7 21 12 15"></polygon></svg>
48+
<span>Airplay</span>
49+
</overflow-menu-item>
50+
</overflow-menu>
951

1052
<script type="module">
1153
// import 'https://unpkg.com/@github/custom-element-boilerplate@latest/dist/custom-element.js'

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/overflow-menu-element.ts

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,101 @@
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+
1136
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+
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

Comments
 (0)