@rcarls/rc-adaptive-menu 0.5.0

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.
@@ -0,0 +1,589 @@
1
+ import { css as w, LitElement as y, html as x } from "lit";
2
+ import { property as p, query as b } from "lit/decorators.js";
3
+ import { AnchorController as O, keyNavigation as d, isFocusable as g } from "@rcarls/rc-common";
4
+ const A = w`
5
+ :host {
6
+ display: block;
7
+ inline-size: fit-content;
8
+ /*
9
+ * Raised past 100% by exactly the overlap amount so the cap only ever
10
+ * bounds the host's own visible content, not the content plus the
11
+ * intentional negative-margin overhang below. Inside a shrink-to-fit
12
+ * flex/grid ancestor (a toolbar's trailing group, for example) the
13
+ * ancestor's own auto size already accounts for the negative margin,
14
+ * so a plain 100% cap would re-clamp the host down to that
15
+ * already-shrunk size and silently cancel the overlap out from under
16
+ * it — confirmed live: with a plain 100% cap the host visibly shrank
17
+ * instead of overlapping.
18
+ */
19
+ max-inline-size: calc(
20
+ 100% + var(--rc-adaptive-menu-touch-target-overlap-inline-start, 0px) +
21
+ var(--rc-adaptive-menu-touch-target-overlap-inline-end, 0px)
22
+ );
23
+ min-inline-size: 0;
24
+ /*
25
+ * Zero by default. The overflow trigger's own touch-target inflation
26
+ * (see #overflow-trigger-target below) is what typically leaves dead
27
+ * space at a real edge, such as a toolbar's trailing-most control — but
28
+ * the margin has to live on the host, not on that internal wrapper:
29
+ * #root just lays out flush with the host's own edges, so a margin
30
+ * placed there has no visible effect on where the host itself renders
31
+ * in an outer flex/grid container. The host's own box is
32
+ * fit-content-sized and is what an outer container's own trailing
33
+ * alignment actually positions, so this is the point that needs to
34
+ * move. A theme or consumer sets one of these on a host that sits at a
35
+ * real edge (no neighbor on that side) to let it overlap into whatever
36
+ * sits just outside, such as a container's own edge padding, instead of
37
+ * also reserving layout space there — the same pattern as rc-button's
38
+ * and rc-menu-button's own touch-target overlap tokens.
39
+ */
40
+ margin-inline-start: calc(-1 * var(--rc-adaptive-menu-touch-target-overlap-inline-start, 0px));
41
+ margin-inline-end: calc(-1 * var(--rc-adaptive-menu-touch-target-overlap-inline-end, 0px));
42
+ }
43
+
44
+ #root {
45
+ display: flex;
46
+ flex-direction: row;
47
+ align-items: center;
48
+ gap: var(--rc-adaptive-menu-gap, var(--rc-control-gap, 0.25em));
49
+ min-inline-size: 0;
50
+ max-inline-size: 100%;
51
+ }
52
+
53
+ :host([orientation='vertical']) {
54
+ inline-size: 100%;
55
+ }
56
+
57
+ :host([orientation='vertical']) #root {
58
+ flex-direction: column;
59
+ align-items: stretch;
60
+ min-block-size: 0;
61
+ inline-size: 100%;
62
+ block-size: 100%;
63
+ }
64
+
65
+ #actions,
66
+ #overflow {
67
+ display: contents;
68
+ }
69
+
70
+ #overflow-trigger-target {
71
+ position: relative;
72
+ flex: none;
73
+ display: grid;
74
+ place-items: center;
75
+ box-sizing: border-box;
76
+ min-inline-size: var(
77
+ --rc-adaptive-menu-touch-target-inline-size,
78
+ var(--rc-adaptive-menu-touch-target-block-size, 3rem)
79
+ );
80
+ min-block-size: var(--rc-adaptive-menu-touch-target-block-size, 3rem);
81
+ }
82
+
83
+ #overflow-trigger {
84
+ position: relative;
85
+ display: inline-grid;
86
+ place-items: center;
87
+ box-sizing: border-box;
88
+ min-inline-size: var(--rc-adaptive-menu-trigger-inline-size, 2.5em);
89
+ min-block-size: var(--rc-adaptive-menu-trigger-block-size, 2.5em);
90
+ padding: var(--rc-adaptive-menu-trigger-padding, 0.5em);
91
+ border: var(--rc-adaptive-menu-trigger-border, 1px solid ButtonBorder);
92
+ border-radius: var(--rc-adaptive-menu-trigger-radius, var(--rc-control-radius, 0));
93
+ background: var(--rc-adaptive-menu-trigger-background, ButtonFace);
94
+ color: var(--rc-adaptive-menu-trigger-color, ButtonText);
95
+ font: inherit;
96
+ line-height: 1;
97
+ cursor: pointer;
98
+ }
99
+
100
+ #overflow-trigger::before {
101
+ content: '';
102
+ position: absolute;
103
+ inset-block: calc((var(--rc-adaptive-menu-touch-target-block-size, 3rem) - 100%) / -2);
104
+ inset-inline: calc(
105
+ (
106
+ var(
107
+ --rc-adaptive-menu-touch-target-inline-size,
108
+ var(--rc-adaptive-menu-touch-target-block-size, 3rem)
109
+ ) -
110
+ 100%
111
+ ) /
112
+ -2
113
+ );
114
+ }
115
+
116
+ :host(:not([data-overflow])) #overflow-trigger-target {
117
+ position: fixed;
118
+ visibility: hidden;
119
+ pointer-events: none;
120
+ }
121
+
122
+ #overflow-trigger:focus-visible {
123
+ outline: var(--rc-focus-ring, auto);
124
+ outline-offset: var(--rc-focus-ring-offset, 0);
125
+ }
126
+
127
+ #overflow-icon {
128
+ inline-size: var(--rc-adaptive-menu-icon-size, 1.5em);
129
+ block-size: var(--rc-adaptive-menu-icon-size, 1.5em);
130
+ fill: currentColor;
131
+ }
132
+
133
+ #popup {
134
+ position: fixed;
135
+ display: none;
136
+ flex-direction: column;
137
+ box-sizing: border-box;
138
+ min-inline-size: var(--rc-adaptive-menu-popup-min-inline-size, 10em);
139
+ max-inline-size: var(--rc-adaptive-menu-popup-max-inline-size, calc(100dvi - 0.5rem));
140
+ max-block-size: var(--rc-adaptive-menu-popup-max-block-size, calc(100dvb - 0.5rem));
141
+ margin: 0;
142
+ padding-block: var(--rc-adaptive-menu-popup-padding-block, 0.25em);
143
+ border: var(--rc-adaptive-menu-popup-border, var(--rc-border, 1px solid ButtonBorder));
144
+ border-radius: var(--rc-adaptive-menu-popup-radius, var(--rc-control-radius, 0));
145
+ background: var(--rc-adaptive-menu-popup-background, var(--rc-surface, Canvas));
146
+ box-shadow: var(
147
+ --rc-adaptive-menu-popup-shadow,
148
+ var(--rc-shadow, 0 2px 8px color-mix(in srgb, CanvasText 15%, transparent))
149
+ );
150
+ color: var(--rc-adaptive-menu-popup-color, var(--rc-field-text, CanvasText));
151
+ overflow: auto;
152
+ overscroll-behavior: contain;
153
+ scrollbar-gutter: stable;
154
+ }
155
+
156
+ #popup:is(:popover-open, [data-fallback-open]) {
157
+ display: flex;
158
+ }
159
+ `;
160
+ var k = Object.defineProperty, T = Object.getOwnPropertyDescriptor, c = (h, e, t, r) => {
161
+ for (var i = r > 1 ? void 0 : r ? T(e, t) : e, n = h.length - 1, u; n >= 0; n--)
162
+ (u = h[n]) && (i = (r ? u(e, t, i) : u(i)) || i);
163
+ return r && i && k(e, t, i), i;
164
+ };
165
+ const z = "rc-button, rc-chip, rc-menu-button", S = `
166
+ @layer rc-base {
167
+ rc-adaptive-menu > [data-rc-action-promoted],
168
+ rc-adaptive-menu > [data-rc-action-overflowed] {
169
+ box-sizing: border-box;
170
+ min-inline-size: 0;
171
+ }
172
+
173
+ rc-adaptive-menu > [data-rc-action-overflowed] {
174
+ display: flex;
175
+ inline-size: 100%;
176
+ }
177
+
178
+ rc-adaptive-menu > [data-rc-action-overflowed] > :is(button, a[href]),
179
+ rc-adaptive-menu > :is(button, a[href])[data-rc-action-overflowed] {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: var(--rc-adaptive-menu-item-gap, var(--rc-item-gap, 0.5em));
183
+ box-sizing: border-box;
184
+ inline-size: 100%;
185
+ min-block-size: var(--rc-adaptive-menu-item-min-block-size, 2.5em);
186
+ padding: var(--rc-adaptive-menu-item-padding-block, var(--rc-item-padding-block, 0.3em))
187
+ var(--rc-adaptive-menu-item-padding-inline, var(--rc-item-padding-inline, 0.75em));
188
+ border: none;
189
+ border-radius: 0;
190
+ background: transparent;
191
+ color: inherit;
192
+ font: inherit;
193
+ text-align: start;
194
+ text-decoration: none;
195
+ }
196
+
197
+ rc-adaptive-menu [data-rc-menu-leading],
198
+ rc-adaptive-menu [data-rc-menu-trailing] {
199
+ flex: none;
200
+ display: inline-flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ }
204
+
205
+ rc-adaptive-menu [data-rc-menu-label] {
206
+ flex: 1 1 auto;
207
+ min-inline-size: 0;
208
+ }
209
+
210
+ rc-adaptive-menu [data-rc-menu-trailing],
211
+ rc-adaptive-menu [data-rc-menu-shortcut],
212
+ rc-adaptive-menu [data-menu-shortcut] {
213
+ margin-inline-start: auto;
214
+ }
215
+ }
216
+ `;
217
+ var s;
218
+ const l = (s = class extends y {
219
+ constructor() {
220
+ super(...arguments), this.label = "Actions", this.maxShown = 3, this._defaultOpen = !1, this._openInitialized = !1, this.orientation = "horizontal", this.overflowLabel = "More actions", this._authored = /* @__PURE__ */ new Map(), this._applyingSlots = !1, this._restoreFocusWhenClosed = !1, this._focusWhenOpened = null, this._anchor = new O(this, {
221
+ anchor: () => this._$trigger,
222
+ floating: () => this._$popup,
223
+ placement: "bottom-end",
224
+ offset: 4,
225
+ shadowHost: () => this
226
+ }), this._onSlotChange = () => {
227
+ this._applyingSlots || queueMicrotask(() => {
228
+ this.isConnected && !this._applyingSlots && this._syncActions();
229
+ });
230
+ }, this._onMutation = (e) => {
231
+ if (!this._applyingSlots) {
232
+ if (e.some((t) => t.type === "childList" || t.attributeName === "slot")) {
233
+ this._syncActions();
234
+ return;
235
+ }
236
+ if (e.some((t) => t.attributeName === "data-priority")) {
237
+ this._applySlots();
238
+ return;
239
+ }
240
+ this._syncToolbarTabStops();
241
+ }
242
+ }, this._onFocusIn = (e) => {
243
+ const t = e.composedPath()[0];
244
+ t instanceof HTMLElement && this._promotedFocusTargets().includes(t) && this._syncToolbarTabStops(t);
245
+ }, this._onToolbarNavigate = (e) => {
246
+ this._focusByNavigationAction(e, this._promotedFocusTargets());
247
+ }, this._onTriggerNavigate = (e) => {
248
+ switch (e) {
249
+ case "open-to-first":
250
+ this._requestUserOpen(!0, !1, "first");
251
+ break;
252
+ case "open-to-last":
253
+ this._requestUserOpen(!0, !1, "last");
254
+ break;
255
+ case "escape":
256
+ this._requestUserOpen(!1, !0);
257
+ break;
258
+ }
259
+ }, this._onOverflowNavigate = (e) => {
260
+ if (e === "escape") {
261
+ this._requestUserOpen(!1, !0);
262
+ return;
263
+ }
264
+ this._focusByNavigationAction(e, this._overflowFocusTargets());
265
+ }, this._onTriggerClick = () => {
266
+ this._requestUserOpen(!this.open, !1, "none");
267
+ }, this._onDocumentPointerDown = (e) => {
268
+ this.open && !e.composedPath().includes(this) && this._requestUserOpen(!1, !1);
269
+ }, this._onDocumentKeydown = (e) => {
270
+ this.open && e.key === "Escape" && !e.composedPath().includes(this) && this._requestUserOpen(!1, !1);
271
+ }, this._onPopupClick = (e) => {
272
+ const t = e.composedPath(), r = Array.from(this._authored.entries()).find(
273
+ ([n, u]) => n.hasAttribute("data-rc-action-overflowed") && (t.includes(n) || t.includes(u.focusTarget))
274
+ );
275
+ if (!r || this._isDisabled(r[1].focusTarget))
276
+ return;
277
+ const i = r[1].focusTarget;
278
+ t.includes(i) && i.getAttribute("aria-haspopup") === "menu" || this._requestUserOpen(!1, !0);
279
+ };
280
+ }
281
+ get open() {
282
+ return this._open ?? this._uncontrolledOpen ?? this._defaultOpen;
283
+ }
284
+ set open(e) {
285
+ const t = this.open;
286
+ this._open = e, this._openInitialized = !0, this.requestUpdate("open", t);
287
+ }
288
+ get defaultOpen() {
289
+ return this._defaultOpen;
290
+ }
291
+ set defaultOpen(e) {
292
+ const t = this._defaultOpen;
293
+ this._defaultOpen = e, !this._openInitialized && this._open === void 0 && this._uncontrolledOpen === void 0 && this.requestUpdate("open", t), this.requestUpdate("defaultOpen", t);
294
+ }
295
+ connectedCallback() {
296
+ super.connectedCallback(), s._ensureBaseStyles(this.getRootNode()), this.addEventListener("focusin", this._onFocusIn), this.ownerDocument.addEventListener("pointerdown", this._onDocumentPointerDown), this.ownerDocument.addEventListener("keydown", this._onDocumentKeydown), typeof MutationObserver == "function" && (this._mutationObserver = new MutationObserver(this._onMutation), this._mutationObserver.observe(this, {
297
+ attributeFilter: ["aria-disabled", "data-priority", "disabled", "slot"],
298
+ childList: !0,
299
+ subtree: !0
300
+ })), this.hasUpdated && queueMicrotask(() => {
301
+ this.isConnected && (this._syncActions(), this._syncOpenState());
302
+ });
303
+ }
304
+ disconnectedCallback() {
305
+ this.removeEventListener("focusin", this._onFocusIn), this.ownerDocument.removeEventListener("pointerdown", this._onDocumentPointerDown), this.ownerDocument.removeEventListener("keydown", this._onDocumentKeydown), this._mutationObserver?.disconnect(), this._mutationObserver = void 0;
306
+ for (const [e, t] of this._authored)
307
+ this._restoreAction(e, t);
308
+ this._authored.clear(), super.disconnectedCallback();
309
+ }
310
+ firstUpdated() {
311
+ this._syncActions(), this._syncOpenState();
312
+ }
313
+ updated(e) {
314
+ e.has("orientation") && this._anchor.setOptions({
315
+ placement: this.orientation === "vertical" ? "right-start" : "bottom-end"
316
+ }), (e.has("maxShown") || e.has("orientation")) && this._applySlots(), e.has("open") && this._syncOpenState();
317
+ }
318
+ /** Original authored action elements in DOM order. */
319
+ get $actions() {
320
+ return this._entriesInDomOrder().map(([e]) => e);
321
+ }
322
+ /** Actions currently shown in the toolbar, in authored DOM order. */
323
+ get $promotedActions() {
324
+ return this.$actions.filter((e) => e.hasAttribute("data-rc-action-promoted"));
325
+ }
326
+ /** Actions currently assigned to the overflow menu, in authored DOM order. */
327
+ get $overflowedActions() {
328
+ return this.$actions.filter((e) => e.hasAttribute("data-rc-action-overflowed"));
329
+ }
330
+ /** Opens the overflow popup silently and optionally focuses an edge action. */
331
+ openMenu(e = "first") {
332
+ this.hasAttribute("data-overflow") && this._setProgrammaticOpen(!0, !1, e);
333
+ }
334
+ /** Closes the overflow popup silently. */
335
+ closeMenu(e = !1) {
336
+ this._setProgrammaticOpen(!1, e);
337
+ }
338
+ /** Toggles the overflow popup silently. */
339
+ toggleMenu(e = "first") {
340
+ !this.open && !this.hasAttribute("data-overflow") || this._setProgrammaticOpen(!this.open, this.open, e);
341
+ }
342
+ render() {
343
+ return x`
344
+ <div
345
+ id="root"
346
+ part="root"
347
+ role="toolbar"
348
+ aria-label=${this.label}
349
+ aria-orientation=${this.orientation}
350
+ ${d(this._onToolbarNavigate, {
351
+ navigationAxis: this.orientation
352
+ })}
353
+ >
354
+ <slot id="actions" @slotchange=${this._onSlotChange}></slot>
355
+ <span id="overflow-trigger-target">
356
+ <button
357
+ id="overflow-trigger"
358
+ part="overflow-trigger"
359
+ type="button"
360
+ aria-haspopup="menu"
361
+ aria-expanded="false"
362
+ aria-controls="popup"
363
+ aria-label=${this.overflowLabel}
364
+ title=${this.overflowLabel}
365
+ ${d(this._onTriggerNavigate, {
366
+ navigationAxis: this.orientation,
367
+ handleNavAxis: !1,
368
+ handleOpenAxis: !0,
369
+ handleEscape: this.open
370
+ })}
371
+ @click=${this._onTriggerClick}
372
+ >
373
+ <slot name="overflow-icon">
374
+ <svg id="overflow-icon" viewBox="0 0 24 24" aria-hidden="true">
375
+ <circle cx="12" cy="5" r="2"></circle>
376
+ <circle cx="12" cy="12" r="2"></circle>
377
+ <circle cx="12" cy="19" r="2"></circle>
378
+ </svg>
379
+ </slot>
380
+ </button>
381
+ </span>
382
+ </div>
383
+ <div
384
+ id="popup"
385
+ part="popup"
386
+ popover="manual"
387
+ role="menu"
388
+ aria-label=${this.overflowLabel}
389
+ ${d(this._onOverflowNavigate, {
390
+ navigationAxis: "vertical",
391
+ handleEscape: !0
392
+ })}
393
+ @click=${this._onPopupClick}
394
+ >
395
+ <slot id="overflow" name="overflow" @slotchange=${this._onSlotChange}></slot>
396
+ </div>
397
+ `;
398
+ }
399
+ static _ensureBaseStyles(e) {
400
+ if (s._styledRoots.has(e))
401
+ return;
402
+ s._styledRoots.add(e);
403
+ const t = (e instanceof Document ? e : e.ownerDocument).createElement("style");
404
+ t.setAttribute("data-rc-light-dom-base", "rc-adaptive-menu"), t.textContent = S, e instanceof Document ? e.head.append(t) : e.append(t);
405
+ }
406
+ _syncActions() {
407
+ const e = /* @__PURE__ */ new Set();
408
+ for (const t of Array.from(this.children)) {
409
+ if (!(t instanceof HTMLElement) || t.slot === "overflow-icon")
410
+ continue;
411
+ const r = this._authored.get(t), i = r?.slot ?? t.slot;
412
+ if (i && i !== "overflow")
413
+ continue;
414
+ const n = r?.focusTarget ?? this._focusTarget(t);
415
+ n && (e.add(t), r || this._authored.set(t, {
416
+ slot: i,
417
+ focusTarget: n,
418
+ orientation: t.getAttribute("orientation"),
419
+ role: n.getAttribute("role"),
420
+ tabindex: n.getAttribute("tabindex"),
421
+ forcedOverflow: i === "overflow"
422
+ }));
423
+ }
424
+ for (const [t, r] of this._authored)
425
+ e.has(t) || (this._restoreAction(t, r), this._authored.delete(t));
426
+ this._applySlots();
427
+ }
428
+ _entriesInDomOrder() {
429
+ return Array.from(this.children).flatMap((e) => {
430
+ if (!(e instanceof HTMLElement))
431
+ return [];
432
+ const t = this._authored.get(e);
433
+ return t ? [[e, t]] : [];
434
+ });
435
+ }
436
+ /**
437
+ * Assigns each authored action to the default (promoted) or overflow slot.
438
+ * A purely declarative computation from `max-shown`, `data-priority`, and
439
+ * authored `slot` — no size measurement of any kind.
440
+ */
441
+ _applySlots() {
442
+ const e = this._entriesInDomOrder(), t = (o) => {
443
+ const a = Number(o.dataset.priority ?? 0);
444
+ return Number.isFinite(a) ? a : 0;
445
+ }, r = ([o, a]) => a.forcedOverflow || t(o) < 0, i = e.filter((o) => !r(o)), n = i.map(([o], a) => ({
446
+ action: o,
447
+ index: a,
448
+ priority: t(o)
449
+ })).sort((o, a) => a.priority - o.priority || o.index - a.index), u = Number.isFinite(this.maxShown) ? Math.max(0, Math.trunc(this.maxShown)) : i.length, _ = Math.min(i.length, u), f = new Set(n.slice(0, _).map(({ action: o }) => o)), v = e.map(([o]) => o).filter((o) => !f.has(o)), m = e.find(
450
+ ([, o]) => o.focusTarget === this.ownerDocument.activeElement
451
+ )?.[0];
452
+ this.toggleAttribute("data-overflow", v.length > 0), m && v.includes(m) && this._$trigger.focus(), this._applyingSlots = !0;
453
+ for (const [o, a] of e)
454
+ f.has(o) ? (o.slot = "", o.setAttribute("data-rc-action-promoted", ""), o.removeAttribute("data-rc-action-overflowed"), this._restoreOrientation(o, a), this._restoreRole(a)) : (o.slot = "overflow", o.removeAttribute("data-rc-action-promoted"), o.setAttribute("data-rc-action-overflowed", ""), o.matches("rc-menu-button") && o.setAttribute("orientation", "vertical"), a.focusTarget.setAttribute("role", "menuitem"), a.focusTarget.setAttribute("tabindex", "-1"));
455
+ this._syncToolbarTabStops(), queueMicrotask(() => {
456
+ this._applyingSlots = !1;
457
+ }), this._syncOpenState();
458
+ }
459
+ _focusTarget(e) {
460
+ return e.matches(z) ? e.querySelector(
461
+ ':scope > button, :scope > a[href], :scope > [slot="trigger"]'
462
+ ) : e.matches("button, a[href]") ? e : null;
463
+ }
464
+ _promotedFocusTargets() {
465
+ const e = Array.from(this._authored.entries()).filter(([t]) => t.hasAttribute("data-rc-action-promoted")).map(([, t]) => t.focusTarget).filter((t) => g(t));
466
+ return this.hasAttribute("data-overflow") && e.push(this._$trigger), e;
467
+ }
468
+ _overflowFocusTargets() {
469
+ return Array.from(this._authored.entries()).filter(([e]) => e.hasAttribute("data-rc-action-overflowed")).map(([, e]) => e.focusTarget).filter((e) => g(e));
470
+ }
471
+ _syncToolbarTabStops(e) {
472
+ const t = this._promotedFocusTargets(), r = e && t.includes(e) ? e : t[0];
473
+ for (const i of t)
474
+ i.setAttribute("tabindex", i === r ? "0" : "-1");
475
+ }
476
+ _focusByNavigationAction(e, t) {
477
+ const r = this.ownerDocument.activeElement, i = r instanceof HTMLElement ? t.indexOf(r) : -1;
478
+ let n;
479
+ switch (e) {
480
+ case "next":
481
+ n = t[(i + 1) % t.length];
482
+ break;
483
+ case "prev":
484
+ n = t[(i - 1 + t.length) % t.length];
485
+ break;
486
+ case "start":
487
+ n = t[0];
488
+ break;
489
+ case "end":
490
+ n = t.at(-1);
491
+ break;
492
+ }
493
+ n?.focus();
494
+ }
495
+ _setProgrammaticOpen(e, t, r = "none") {
496
+ const i = this.open;
497
+ if (i === e) {
498
+ e && this._focusOverflowEdge(r);
499
+ return;
500
+ }
501
+ this._openInitialized ? this._open = e : this._uncontrolledOpen = e, this._restoreFocusWhenClosed = !e && t, this._focusWhenOpened = e ? r : null, this.requestUpdate("open", i), this._syncOpenState();
502
+ }
503
+ _requestUserOpen(e, t, r = "none") {
504
+ if (this.open !== e) {
505
+ if (this._restoreFocusWhenClosed = !e && t, this._focusWhenOpened = e ? r : null, this._open === void 0) {
506
+ const i = this.open;
507
+ this._uncontrolledOpen = e, this.requestUpdate("open", i), this._syncOpenState();
508
+ }
509
+ this.dispatchEvent(
510
+ new CustomEvent("rc-adaptive-menu-toggle", {
511
+ bubbles: !0,
512
+ composed: !0,
513
+ detail: { open: e }
514
+ })
515
+ );
516
+ }
517
+ }
518
+ _syncOpenState() {
519
+ const e = this._$popup;
520
+ if (e?.isConnected) {
521
+ if (this.open && this.hasAttribute("data-overflow")) {
522
+ let t = !1;
523
+ if (typeof e.showPopover == "function")
524
+ try {
525
+ e.showPopover(), t = !0;
526
+ } catch {
527
+ }
528
+ if (e.toggleAttribute("data-fallback-open", !t), this._$trigger.setAttribute("aria-expanded", "true"), this._anchor.update(), this._focusWhenOpened !== null) {
529
+ const r = this._focusWhenOpened;
530
+ this._focusWhenOpened = null, requestAnimationFrame(() => this._focusOverflowEdge(r));
531
+ }
532
+ return;
533
+ }
534
+ if (typeof e.hidePopover == "function")
535
+ try {
536
+ e.hidePopover();
537
+ } catch {
538
+ }
539
+ e.removeAttribute("data-fallback-open"), this._$trigger.setAttribute("aria-expanded", "false"), this._restoreFocusWhenClosed && (this._restoreFocusWhenClosed = !1, this._$trigger.focus());
540
+ }
541
+ }
542
+ _focusOverflowEdge(e) {
543
+ if (!this.open || e === "none")
544
+ return;
545
+ const t = this._overflowFocusTargets();
546
+ (e === "last" ? t.at(-1) : t[0])?.focus();
547
+ }
548
+ _restoreAction(e, t) {
549
+ e.slot = t.slot, e.removeAttribute("data-rc-action-promoted"), e.removeAttribute("data-rc-action-overflowed"), this._restoreOrientation(e, t), this._restoreRole(t), t.tabindex === null ? t.focusTarget.removeAttribute("tabindex") : t.focusTarget.setAttribute("tabindex", t.tabindex);
550
+ }
551
+ _restoreOrientation(e, t) {
552
+ e.matches("rc-menu-button") && (t.orientation === null ? e.removeAttribute("orientation") : e.setAttribute("orientation", t.orientation));
553
+ }
554
+ _restoreRole(e) {
555
+ e.role === null ? e.focusTarget.removeAttribute("role") : e.focusTarget.setAttribute("role", e.role);
556
+ }
557
+ _isDisabled(e) {
558
+ return e instanceof HTMLButtonElement && e.disabled || e.getAttribute("aria-disabled") === "true";
559
+ }
560
+ }, s.styles = A, s._styledRoots = /* @__PURE__ */ new WeakSet(), s);
561
+ c([
562
+ p({ type: String })
563
+ ], l.prototype, "label", 2);
564
+ c([
565
+ p({ type: Number, attribute: "max-shown" })
566
+ ], l.prototype, "maxShown", 2);
567
+ c([
568
+ p({ type: Boolean, reflect: !0 })
569
+ ], l.prototype, "open", 1);
570
+ c([
571
+ p({ type: Boolean, attribute: "default-open" })
572
+ ], l.prototype, "defaultOpen", 1);
573
+ c([
574
+ p({ type: String, reflect: !0 })
575
+ ], l.prototype, "orientation", 2);
576
+ c([
577
+ p({ type: String, attribute: "overflow-label" })
578
+ ], l.prototype, "overflowLabel", 2);
579
+ c([
580
+ b("#overflow-trigger")
581
+ ], l.prototype, "_$trigger", 2);
582
+ c([
583
+ b("#popup")
584
+ ], l.prototype, "_$popup", 2);
585
+ let E = l;
586
+ export {
587
+ E as R
588
+ };
589
+ //# sourceMappingURL=rc-adaptive-menu-BwvfkD_X.js.map