@featherk/composables 0.17.1 → 0.18.1
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.
- package/README.md +62 -15
- package/dist/address.cjs +2 -0
- package/dist/address.cjs.map +1 -0
- package/dist/address.mjs +6 -0
- package/dist/address.mjs.map +1 -0
- package/dist/chunks/useActiveIdRegistry-BG8VR__Z.mjs +43 -0
- package/dist/chunks/useActiveIdRegistry-BG8VR__Z.mjs.map +1 -0
- package/dist/chunks/useActiveIdRegistry-C1b00tqW.cjs +2 -0
- package/dist/chunks/useActiveIdRegistry-C1b00tqW.cjs.map +1 -0
- package/dist/chunks/useCompositeId-DyrJ0Fqj.cjs +2 -0
- package/dist/chunks/useCompositeId-DyrJ0Fqj.cjs.map +1 -0
- package/dist/chunks/useCompositeId-xg87ehXQ.mjs +9 -0
- package/dist/chunks/useCompositeId-xg87ehXQ.mjs.map +1 -0
- package/dist/chunks/useFieldsetValidationKit-7W1XDbbr.cjs +2 -0
- package/dist/chunks/useFieldsetValidationKit-7W1XDbbr.cjs.map +1 -0
- package/dist/chunks/useFieldsetValidationKit-x0Rh48mE.mjs +64 -0
- package/dist/chunks/useFieldsetValidationKit-x0Rh48mE.mjs.map +1 -0
- package/dist/chunks/useGridRowAction-Di25yeqb.cjs +2 -0
- package/dist/chunks/useGridRowAction-Di25yeqb.cjs.map +1 -0
- package/dist/chunks/useGridRowAction-akjwkV_F.mjs +532 -0
- package/dist/chunks/useGridRowAction-akjwkV_F.mjs.map +1 -0
- package/dist/chunks/useIntersectionObserver-A4xQV_pl.mjs +23 -0
- package/dist/chunks/useIntersectionObserver-A4xQV_pl.mjs.map +1 -0
- package/dist/chunks/useIntersectionObserver-CfgNAo2N.cjs +2 -0
- package/dist/chunks/useIntersectionObserver-CfgNAo2N.cjs.map +1 -0
- package/dist/chunks/useMaskedDateInput-COOksUM_.mjs +276 -0
- package/dist/chunks/useMaskedDateInput-COOksUM_.mjs.map +1 -0
- package/dist/chunks/useMaskedDateInput-wRnYlR3L.cjs +2 -0
- package/dist/chunks/useMaskedDateInput-wRnYlR3L.cjs.map +1 -0
- package/dist/chunks/useMaskedDateRangeInput-DST5aQe0.cjs +2 -0
- package/dist/chunks/useMaskedDateRangeInput-DST5aQe0.cjs.map +1 -0
- package/dist/chunks/useMaskedDateRangeInput-owYSg36r.mjs +328 -0
- package/dist/chunks/useMaskedDateRangeInput-owYSg36r.mjs.map +1 -0
- package/dist/chunks/useMaskedTimeInput-DPd2lysd.cjs +2 -0
- package/dist/chunks/useMaskedTimeInput-DPd2lysd.cjs.map +1 -0
- package/dist/chunks/useMaskedTimeInput-DjtBdvsf.mjs +363 -0
- package/dist/chunks/useMaskedTimeInput-DjtBdvsf.mjs.map +1 -0
- package/dist/chunks/usePopupMenu-CZLtgrXk.mjs +296 -0
- package/dist/chunks/usePopupMenu-CZLtgrXk.mjs.map +1 -0
- package/dist/chunks/usePopupMenu-DeTWakUH.cjs +2 -0
- package/dist/chunks/usePopupMenu-DeTWakUH.cjs.map +1 -0
- package/dist/chunks/usePopupTrap-DQudM6YA.cjs +2 -0
- package/dist/chunks/usePopupTrap-DQudM6YA.cjs.map +1 -0
- package/dist/chunks/usePopupTrap-DeuXHLZR.mjs +105 -0
- package/dist/chunks/usePopupTrap-DeuXHLZR.mjs.map +1 -0
- package/dist/chunks/useUSAddress-BYZZfbHc.cjs +2 -0
- package/dist/chunks/useUSAddress-BYZZfbHc.cjs.map +1 -0
- package/dist/chunks/useUSAddress-CRcqdqrZ.mjs +291 -0
- package/dist/chunks/useUSAddress-CRcqdqrZ.mjs.map +1 -0
- package/dist/chunks/useWindow-C4XFBuJA.mjs +210 -0
- package/dist/chunks/useWindow-C4XFBuJA.mjs.map +1 -0
- package/dist/chunks/useWindow-Yia2I6zX.cjs +2 -0
- package/dist/chunks/useWindow-Yia2I6zX.cjs.map +1 -0
- package/dist/date/useMaskedDateInput.d.ts +4 -0
- package/dist/date.cjs +2 -0
- package/dist/date.cjs.map +1 -0
- package/dist/date.mjs +5 -0
- package/dist/date.mjs.map +1 -0
- package/dist/{docs-manifest.js → docs-manifest.mjs} +24 -24
- package/dist/form.cjs +2 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.mjs +6 -0
- package/dist/form.mjs.map +1 -0
- package/dist/geometry.cjs +2 -0
- package/dist/geometry.cjs.map +1 -0
- package/dist/geometry.mjs +60 -0
- package/dist/geometry.mjs.map +1 -0
- package/dist/grid.cjs +2 -0
- package/dist/grid.cjs.map +1 -0
- package/dist/grid.mjs +7 -0
- package/dist/grid.mjs.map +1 -0
- package/dist/id.cjs +2 -0
- package/dist/id.cjs.map +1 -0
- package/dist/id.mjs +5 -0
- package/dist/id.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +37 -0
- package/dist/index.mjs.map +1 -0
- package/dist/menu.cjs +2 -0
- package/dist/menu.cjs.map +1 -0
- package/dist/menu.mjs +5 -0
- package/dist/menu.mjs.map +1 -0
- package/dist/observer.cjs +2 -0
- package/dist/observer.cjs.map +1 -0
- package/dist/observer.mjs +5 -0
- package/dist/observer.mjs.map +1 -0
- package/dist/range/useMaskedDateRangeInput.d.ts +4 -0
- package/dist/range.cjs +2 -0
- package/dist/range.cjs.map +1 -0
- package/dist/range.mjs +5 -0
- package/dist/range.mjs.map +1 -0
- package/dist/registry.cjs +2 -0
- package/dist/registry.cjs.map +1 -0
- package/dist/registry.mjs +6 -0
- package/dist/registry.mjs.map +1 -0
- package/dist/time/useMaskedTimeInput.d.ts +4 -0
- package/dist/time.cjs +2 -0
- package/dist/time.cjs.map +1 -0
- package/dist/time.mjs +5 -0
- package/dist/time.mjs.map +1 -0
- package/dist/trap.cjs +2 -0
- package/dist/trap.cjs.map +1 -0
- package/dist/trap.mjs +7 -0
- package/dist/trap.mjs.map +1 -0
- package/dist/window.cjs +2 -0
- package/dist/window.cjs.map +1 -0
- package/dist/window.mjs +6 -0
- package/dist/window.mjs.map +1 -0
- package/docs/date/useMaskedDateInput.md +3 -0
- package/docs/range/useMaskedDateRangeInput.md +6 -7
- package/docs/time/useMaskedTimeInput.md +3 -0
- package/package.json +38 -36
- package/dist/featherk-composables.es.js +0 -2628
- package/dist/featherk-composables.es.js.map +0 -1
- package/dist/featherk-composables.umd.js +0 -2
- package/dist/featherk-composables.umd.js.map +0 -1
- /package/dist/{docs-manifest.d.ts → docs-manifest.d.mts} +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { ref as V, shallowRef as R, computed as S, watch as y, toValue as M, onUnmounted as G, nextTick as B } from "vue";
|
|
2
|
+
import { onClickOutside as J } from "@vueuse/core";
|
|
3
|
+
import { u as Q } from "./useIntersectionObserver-A4xQV_pl.mjs";
|
|
4
|
+
import { computeCollisionOffset as Z } from "../geometry.mjs";
|
|
5
|
+
const ee = ".k-table-row", b = (n) => {
|
|
6
|
+
if (n instanceof HTMLElement) return n;
|
|
7
|
+
const r = n?.$el;
|
|
8
|
+
return r instanceof HTMLElement ? r : null;
|
|
9
|
+
}, te = (n, r) => r === "row" ? n.matches("tr.k-table-row") : !n.matches("tr.k-table-row"), ne = (n, r) => {
|
|
10
|
+
console.warn(
|
|
11
|
+
`usePopupMenu: triggerMode "${r}" does not match resolved element <${n.tagName.toLowerCase()}${n.className ? `.${n.className.split(" ").join(".")}` : ""}>; ARIA management skipped.`
|
|
12
|
+
);
|
|
13
|
+
}, re = (n) => {
|
|
14
|
+
let r = n.parentElement, C = null;
|
|
15
|
+
for (; r; ) {
|
|
16
|
+
const { overflow: m, overflowX: l, overflowY: c } = window.getComputedStyle(r), f = /auto|scroll|overlay/.test(`${m} ${l}`), a = /auto|scroll|overlay/.test(`${m} ${c}`);
|
|
17
|
+
if ((f || a) && (C ??= r), f && r.scrollWidth > r.clientWidth || a && r.scrollHeight > r.clientHeight)
|
|
18
|
+
return r;
|
|
19
|
+
r = r.parentElement;
|
|
20
|
+
}
|
|
21
|
+
return C;
|
|
22
|
+
}, ge = (n) => {
|
|
23
|
+
const r = V(null), C = n.menuItemSelector ?? ".k-menu-item:not(.k-disabled)", m = n.triggerMode, l = n.anchor === !0 ? {} : n.anchor, c = l?.activationPoint ? l.activationPoint === !0 ? {} : l.activationPoint : null, f = R(null), a = R(null), H = l?.anchorAlign ?? {
|
|
24
|
+
horizontal: "left",
|
|
25
|
+
vertical: "bottom"
|
|
26
|
+
}, N = l?.popupAlign ?? {
|
|
27
|
+
horizontal: "left",
|
|
28
|
+
vertical: "top"
|
|
29
|
+
}, _ = l?.collision ?? {
|
|
30
|
+
horizontal: "flip",
|
|
31
|
+
vertical: "flip"
|
|
32
|
+
}, O = R(null), w = () => b(n.triggerRef.value), p = S(() => w()), D = S(
|
|
33
|
+
() => l && l.hideWhenAnchorClipped !== !1 ? p.value : null
|
|
34
|
+
), W = () => {
|
|
35
|
+
const e = l?.clipRoot ? M(l.clipRoot) : null;
|
|
36
|
+
if (e) {
|
|
37
|
+
const t = e.getBoundingClientRect();
|
|
38
|
+
return {
|
|
39
|
+
left: t.left,
|
|
40
|
+
top: t.top,
|
|
41
|
+
right: t.right,
|
|
42
|
+
bottom: t.bottom
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
left: 0,
|
|
47
|
+
top: 0,
|
|
48
|
+
right: window.innerWidth,
|
|
49
|
+
bottom: window.innerHeight
|
|
50
|
+
};
|
|
51
|
+
}, X = S(() => {
|
|
52
|
+
const e = f.value;
|
|
53
|
+
if (!n.isOpen.value || !e) return { left: 0, top: 0 };
|
|
54
|
+
const t = W(), o = Z({
|
|
55
|
+
anchor: e,
|
|
56
|
+
popup: O.value,
|
|
57
|
+
anchorAlign: H,
|
|
58
|
+
popupAlign: N,
|
|
59
|
+
bounds: t,
|
|
60
|
+
collision: _
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
left: o.left + window.scrollX,
|
|
64
|
+
top: o.top + window.scrollY
|
|
65
|
+
};
|
|
66
|
+
}), x = () => {
|
|
67
|
+
const e = n.resolveFocusTarget?.() ?? b(n.focusTargetRef?.value);
|
|
68
|
+
return e || (n.focusTargetContainerSelector ? w()?.closest(
|
|
69
|
+
n.focusTargetContainerSelector
|
|
70
|
+
) ?? null : null);
|
|
71
|
+
}, Y = (e, t) => {
|
|
72
|
+
if (!c) return !1;
|
|
73
|
+
const o = b(e);
|
|
74
|
+
if (!o)
|
|
75
|
+
return a.value = null, !1;
|
|
76
|
+
const s = o.getBoundingClientRect();
|
|
77
|
+
if (t.triggerType === "keyboard") {
|
|
78
|
+
const h = c.keyboardPosition, i = h?.y ?? "center", d = typeof i == "number" ? i : i === "top" ? 0 : i === "bottom" ? s.height : s.height / 2;
|
|
79
|
+
return a.value = {
|
|
80
|
+
trigger: o,
|
|
81
|
+
point: { x: h?.x ?? 8, y: d },
|
|
82
|
+
hasMatchedTrigger: !1
|
|
83
|
+
}, !0;
|
|
84
|
+
}
|
|
85
|
+
return t.coordinates ? (a.value = {
|
|
86
|
+
trigger: o,
|
|
87
|
+
point: {
|
|
88
|
+
x: t.coordinates.clientX - s.left + (c.pointerOffset?.x ?? 0),
|
|
89
|
+
y: t.coordinates.clientY - s.top + (c.pointerOffset?.y ?? 0)
|
|
90
|
+
},
|
|
91
|
+
hasMatchedTrigger: !1
|
|
92
|
+
}, !0) : (a.value = null, !1);
|
|
93
|
+
}, L = () => {
|
|
94
|
+
if (m !== "button") return null;
|
|
95
|
+
if (n.escapeFocusTarget) return n.escapeFocusTarget();
|
|
96
|
+
const e = n.escapeFocusContainerSelector ?? ee;
|
|
97
|
+
return (w() ?? document.activeElement)?.closest(e) ?? null;
|
|
98
|
+
}, U = () => {
|
|
99
|
+
const e = x() ?? L();
|
|
100
|
+
if (e)
|
|
101
|
+
return e.focus(), !0;
|
|
102
|
+
const t = w();
|
|
103
|
+
return t?.focus(), !!t;
|
|
104
|
+
}, K = () => {
|
|
105
|
+
b(n.menuRef.value)?.querySelector(C)?.focus({ preventScroll: !0 });
|
|
106
|
+
}, k = R(null), T = R(null);
|
|
107
|
+
let F = !1;
|
|
108
|
+
const z = () => {
|
|
109
|
+
const e = r.value;
|
|
110
|
+
if (e === "keyboard" || e === "escape") {
|
|
111
|
+
const t = k.value ?? T.value;
|
|
112
|
+
t?.focus(), e === "keyboard" && t && t === T.value && (F = !0);
|
|
113
|
+
} else r.value === "mouse-selection" && T.value?.focus();
|
|
114
|
+
r.value = null, k.value = null, T.value = null;
|
|
115
|
+
}, v = (e) => {
|
|
116
|
+
n.isOpen.value && (r.value = e, k.value = x() ?? (e === "escape" ? L() : null), T.value = w(), $(!1), n.requestHide(), B(z));
|
|
117
|
+
};
|
|
118
|
+
y(
|
|
119
|
+
[p, a],
|
|
120
|
+
([e], t, o) => {
|
|
121
|
+
if (!l || !e) {
|
|
122
|
+
f.value = null;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let s = null;
|
|
126
|
+
const h = () => {
|
|
127
|
+
s = null;
|
|
128
|
+
const u = a.value;
|
|
129
|
+
if (c) {
|
|
130
|
+
u && u.trigger === e ? u.hasMatchedTrigger = !0 : u?.hasMatchedTrigger && (u.trigger = e);
|
|
131
|
+
const A = e.getBoundingClientRect();
|
|
132
|
+
f.value = u?.trigger === e ? new DOMRect(
|
|
133
|
+
A.left + u.point.x,
|
|
134
|
+
A.top + u.point.y,
|
|
135
|
+
0,
|
|
136
|
+
0
|
|
137
|
+
) : null;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
f.value = l.getRect?.(e) ?? e.getBoundingClientRect();
|
|
141
|
+
}, i = () => {
|
|
142
|
+
s === null && (s = window.requestAnimationFrame(h));
|
|
143
|
+
}, d = typeof window.ResizeObserver == "function" ? new window.ResizeObserver(i) : null;
|
|
144
|
+
d?.observe(e), window.addEventListener("scroll", i, {
|
|
145
|
+
capture: !0,
|
|
146
|
+
passive: !0
|
|
147
|
+
}), window.addEventListener("resize", i, { passive: !0 }), i(), o(() => {
|
|
148
|
+
s !== null && window.cancelAnimationFrame(s), d?.disconnect(), window.removeEventListener("scroll", i, !0), window.removeEventListener("resize", i);
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
{ immediate: !0, flush: "post" }
|
|
152
|
+
);
|
|
153
|
+
const I = () => {
|
|
154
|
+
const e = b(
|
|
155
|
+
n.popupContentRef?.value ?? n.menuRef.value
|
|
156
|
+
);
|
|
157
|
+
return e?.closest(".k-popup") ?? e;
|
|
158
|
+
};
|
|
159
|
+
l && y(
|
|
160
|
+
n.isOpen,
|
|
161
|
+
(e, t, o) => {
|
|
162
|
+
if (!e) {
|
|
163
|
+
O.value = null;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
let s = null;
|
|
167
|
+
const h = () => {
|
|
168
|
+
s = null;
|
|
169
|
+
const A = I();
|
|
170
|
+
O.value = A?.getBoundingClientRect() ?? null;
|
|
171
|
+
}, i = () => {
|
|
172
|
+
s === null && (s = window.requestAnimationFrame(h));
|
|
173
|
+
}, d = I(), u = d && typeof window.ResizeObserver == "function" ? new window.ResizeObserver(i) : null;
|
|
174
|
+
u?.observe(d), i(), o(() => {
|
|
175
|
+
s !== null && window.cancelAnimationFrame(s), u?.disconnect();
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
{ immediate: !0, flush: "post" }
|
|
179
|
+
), Q({
|
|
180
|
+
target: D,
|
|
181
|
+
root: () => l?.clipRoot ? M(l.clipRoot) : p.value ? re(p.value) : null,
|
|
182
|
+
threshold: l?.intersectionThreshold ?? (c ? 0 : 0.5),
|
|
183
|
+
onChange: (e) => {
|
|
184
|
+
e.isIntersecting || v("anchor-hidden");
|
|
185
|
+
}
|
|
186
|
+
}), J(n.menuRef, () => v("outside-click"), {
|
|
187
|
+
ignore: [p]
|
|
188
|
+
});
|
|
189
|
+
let g = null, E = null;
|
|
190
|
+
const P = () => {
|
|
191
|
+
g?.isConnected && g.setAttribute("aria-expanded", "false"), g = null;
|
|
192
|
+
}, $ = (e) => {
|
|
193
|
+
if (n.manageMenuTriggerAria === !1) return;
|
|
194
|
+
const t = p.value;
|
|
195
|
+
if (!t) {
|
|
196
|
+
g?.isConnected && g.setAttribute("aria-expanded", e ? "true" : "false");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!te(t, m)) {
|
|
200
|
+
ne(t, m), P();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
g && g !== t && P(), t.setAttribute("aria-expanded", e ? "true" : "false"), g = t;
|
|
204
|
+
}, j = () => {
|
|
205
|
+
const e = b(n.menuRef.value), t = e?.matches('[role="menubar"]') ? e : e?.querySelector('[role="menubar"]'), o = M(n.menuLabel)?.trim();
|
|
206
|
+
E && E !== t && E.removeAttribute("aria-label"), t && (o ? t.setAttribute("aria-label", o) : t.removeAttribute("aria-label")), E = t ?? null;
|
|
207
|
+
};
|
|
208
|
+
y(
|
|
209
|
+
[n.isOpen, n.triggerRef],
|
|
210
|
+
([e]) => {
|
|
211
|
+
$(e), !e && c && (a.value = null, f.value = null);
|
|
212
|
+
},
|
|
213
|
+
{ immediate: !0, flush: "post" }
|
|
214
|
+
), y(
|
|
215
|
+
[n.isOpen, n.menuRef, () => M(n.menuLabel)],
|
|
216
|
+
j,
|
|
217
|
+
{ immediate: !0, flush: "post" }
|
|
218
|
+
), G(() => {
|
|
219
|
+
a.value = null, P(), E?.removeAttribute("aria-label");
|
|
220
|
+
}), y(
|
|
221
|
+
n.isOpen,
|
|
222
|
+
(e) => {
|
|
223
|
+
e && K();
|
|
224
|
+
},
|
|
225
|
+
{ flush: "post" }
|
|
226
|
+
);
|
|
227
|
+
const q = (...e) => {
|
|
228
|
+
const t = e[0];
|
|
229
|
+
if (F) {
|
|
230
|
+
F = !1;
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (n.isOpen.value) {
|
|
234
|
+
v("trigger-click");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
n.requestShow(t);
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
/**
|
|
241
|
+
* Sets the anchor activation state, controlling whether the popup menu
|
|
242
|
+
* should respond to trigger interactions.
|
|
243
|
+
*/
|
|
244
|
+
setAnchorActivation: Y,
|
|
245
|
+
/**
|
|
246
|
+
* Handles Kendo Menu selection: records keyboard or mouse modality,
|
|
247
|
+
* requests popup close, then runs the optional caller-owned action.
|
|
248
|
+
*/
|
|
249
|
+
handleMenuSelect: (e, t) => {
|
|
250
|
+
v(
|
|
251
|
+
e.event?.type?.startsWith("key") ? "keyboard" : "mouse-selection"
|
|
252
|
+
), t?.(e);
|
|
253
|
+
},
|
|
254
|
+
/**
|
|
255
|
+
* Toggles the action menu. When opening, focuses the first enabled Kendo
|
|
256
|
+
* Menu item after Vue renders the popup.
|
|
257
|
+
*/
|
|
258
|
+
handleTriggerClick: q,
|
|
259
|
+
/**
|
|
260
|
+
* Handles trigger keyboard input: Enter and Space toggle the menu; Escape
|
|
261
|
+
* closes an open menu or focuses the configured target when already closed.
|
|
262
|
+
*/
|
|
263
|
+
handleTriggerKeydown: (...e) => {
|
|
264
|
+
const t = e[0], o = e[1];
|
|
265
|
+
if (t.key === "Enter" || t.code === "Space") {
|
|
266
|
+
t.preventDefault(), q(o);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (t.key === "Escape") {
|
|
270
|
+
if (t.preventDefault(), t.stopPropagation(), n.isOpen.value) {
|
|
271
|
+
v("escape");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
U();
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
/** Closes the open menu through the keyboard path when Escape is pressed inside it. */
|
|
278
|
+
handleMenuEscape: (e) => {
|
|
279
|
+
e.preventDefault(), e.stopPropagation(), v("escape");
|
|
280
|
+
},
|
|
281
|
+
/**
|
|
282
|
+
* Restores focus after Kendo Popup closes: keyboard menu selection and
|
|
283
|
+
* Escape prefer the configured focus target (Escape then falls back to
|
|
284
|
+
* `escapeFocusTarget`), mouse selections return to the trigger, and
|
|
285
|
+
* outside clicks do not move focus.
|
|
286
|
+
*/
|
|
287
|
+
handlePopupClose: () => {
|
|
288
|
+
B(z);
|
|
289
|
+
},
|
|
290
|
+
offset: X
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
export {
|
|
294
|
+
ge as u
|
|
295
|
+
};
|
|
296
|
+
//# sourceMappingURL=usePopupMenu-CZLtgrXk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopupMenu-CZLtgrXk.mjs","sources":["../../src/menu/usePopupMenu.ts"],"sourcesContent":["import {\n computed,\n nextTick,\n onUnmounted,\n ref,\n shallowRef,\n toValue,\n watch,\n type ComponentPublicInstance,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from \"vue\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { useIntersectionObserver } from \"../observer\";\nimport {\n computeCollisionOffset,\n type GeometryAlign,\n type GeometryBounds,\n type GeometryCollision,\n} from \"../geometry\";\n\n/** A template ref that may point to an element or a Vue/Kendo component. */\nexport type PopupMenuElementRef = Ref<\n HTMLElement | ComponentPublicInstance | null\n>;\n\nexport type PopupMenuTriggerMode = \"button\" | \"row\";\n\n/** Default `escapeFocusContainerSelector` for `triggerMode: \"button\"`. */\nconst DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR = \".k-table-row\";\n\nexport type PopupMenuOffset = {\n left: number;\n top: number;\n};\n\n/** Mirrors Kendo Popup's `anchorAlign`/`popupAlign` point shape. */\nexport type PopupMenuAlign = GeometryAlign;\n\n/** Per-axis viewport collision behavior for offset-positioned popups. */\nexport type PopupMenuCollision = GeometryCollision;\n\nexport type PopupMenuAnchorActivation = {\n triggerType: \"click\" | \"keyboard\";\n coordinates?: {\n clientX: number;\n clientY: number;\n };\n};\n\nexport type PopupMenuActivationPointOptions = {\n /** Added to pointer coordinates after they are made trigger-relative. */\n pointerOffset?: { x?: number; y?: number };\n /** Trigger-relative keyboard position. Defaults to 8px from the left and vertically centered. */\n keyboardPosition?: {\n x?: number;\n y?: number | \"top\" | \"center\" | \"bottom\";\n };\n};\n\ntype PopupMenuAnchorBaseOptions = {\n /** Scrollable/clipping container used for out-of-view dismissal. */\n clipRoot?: MaybeRefOrGetter<Element | null>;\n /** Closes the menu after its trigger leaves the clipping container. */\n hideWhenAnchorClipped?: boolean;\n /** Intersection ratio required to keep the anchor considered visible. */\n intersectionThreshold?: number | number[];\n /** Per-axis collision behavior. Defaults to `flip` on both axes. */\n collision?: PopupMenuCollision;\n /**\n * Point on the anchor rect that `offset` is computed from. Mirrors Kendo\n * Popup's `anchorAlign` semantics. Defaults to `{ vertical: \"bottom\",\n * horizontal: \"left\" }`, matching Kendo's own default. Passing `anchorAlign`/\n * `popupAlign` directly to `<Popup>` has no effect when positioning via\n * `offset` (no `anchor` DOM ref) - Kendo's own alignment engine only runs\n * against a real anchor element - so these options exist to reproduce that\n * alignment ourselves in the computed `offset`.\n */\n anchorAlign?: PopupMenuAlign;\n /**\n * Point on the popup itself that is placed at the computed anchor point.\n * Mirrors Kendo Popup's `popupAlign` semantics. Defaults to `{ vertical:\n * \"top\", horizontal: \"left\" }`. Requires measuring the rendered popup\n * border box; until it has a size (e.g. the first open frame), non-\"left\"/\n * \"top\" alignments briefly fall back to \"left\"/\"top\".\n */\n popupAlign?: PopupMenuAlign;\n};\n\n/** Offset-positioning options for a Popup with a dynamically changing trigger. */\nexport type PopupMenuAnchorOptions = PopupMenuAnchorBaseOptions &\n (\n | {\n /** Tracks a pointer or keyboard activation point relative to the trigger. */\n activationPoint: true | PopupMenuActivationPointOptions;\n getRect?: never;\n }\n | {\n activationPoint?: never;\n /** Resolves a custom anchor rect from the current trigger element. */\n getRect?: (trigger: HTMLElement) => DOMRect | null;\n }\n );\n\n/** Why the popup was closed, including the focus policy for mouse paths. */\nexport type PopupMenuCloseReason =\n /** Keyboard-driven menu selection (Enter/Space on a menu item); restores the configured focus target. */\n | \"keyboard\"\n /** Escape key; restores the configured focus target, then `escapeFocusTarget`, then the trigger. */\n | \"escape\"\n /** Pointer menu selection; restores focus to the trigger. */\n | \"mouse-selection\"\n /** Pointer interaction outside the menu; leaves browser focus unchanged. */\n | \"outside-click\"\n /** Interaction with the open trigger; leaves browser focus unchanged. */\n | \"trigger-click\"\n /** Trigger left its clipping area; closes without scrolling it back into view. */\n | \"anchor-hidden\"\n /** No close has been requested yet. */\n | null;\nexport type PopupMenuCloseTrigger = Exclude<PopupMenuCloseReason, null>;\n\n/** Minimal event shape emitted by Kendo Menu `@select`. */\nexport type KendoMenuSelectEvent<\n TItem = { text?: string; id?: string; cssClass?: string; data?: unknown },\n> = {\n item?: TItem;\n event?: {\n type?: string;\n } | null;\n};\n\n/** Options for configuring {@link usePopupMenu}. */\nexport type UsePopupMenuOptions = {\n /** Read-only reactive flag reflecting whether the popup menu is currently open. */\n isOpen: Readonly<Ref<boolean>>;\n /** Ref to the popup menu element or component. Used for outside-click detection. */\n menuRef: PopupMenuElementRef;\n /**\n * Optional measurement source for custom popup markup. The source is\n * promoted to its nearest Kendo `.k-popup` so alignment and collision use\n * the complete border box. Defaults to `menuRef`; outside-click detection\n * always uses `menuRef` directly.\n */\n popupContentRef?: PopupMenuElementRef;\n /** Ref to the trigger button element or component. Ignored by outside-click detection. */\n triggerRef: PopupMenuElementRef;\n /** Called to open the popup menu. Kendo passes its event args as a rest tuple. */\n requestShow: (...args: unknown[]) => void;\n /** Called to close the popup menu. Kendo passes its event args as a rest tuple. */\n requestHide: (...args: unknown[]) => void;\n /**\n * Optional target to focus after a keyboard-driven close.\n * Supports ordinary elements and Vue/Kendo components exposing `$el`.\n */\n focusTargetRef?: PopupMenuElementRef;\n /**\n * Resolves the focus target when it is virtualized or dynamically rendered.\n * Takes precedence over `focusTargetRef`.\n */\n resolveFocusTarget?: () => HTMLElement | null;\n /**\n * Resolves the closest matching ancestor of the trigger as the configured\n * keyboard-close focus target. Used after `resolveFocusTarget` and\n * `focusTargetRef`.\n */\n focusTargetContainerSelector?: string;\n /**\n * Resolves a fallback focus target for Escape closes when no `focusTargetRef`/\n * `resolveFocusTarget` is configured, e.g. the trigger's containing grid row so\n * keyboard users land back in row navigation instead of on the trigger button.\n * Only consulted for `triggerMode: \"button\"`; row triggers already restore to\n * themselves. Takes effect only for Escape, not keyboard menu selection.\n * Takes precedence over `escapeFocusContainerSelector`.\n */\n escapeFocusTarget?: () => HTMLElement | null;\n /**\n * CSS selector for the closest ancestor of the trigger (or, if the menu was\n * never opened, of `document.activeElement`) to focus on Escape. Sugar over\n * `escapeFocusTarget` for the common \"collapse back into the row\" case.\n * Defaults to `\".k-table-row\"` for `triggerMode: \"button\"`; harmless to leave\n * at its default for non-grid button triggers since a missing ancestor simply\n * falls through to focusing the trigger. Ignored when `escapeFocusTarget` is set.\n */\n escapeFocusContainerSelector?: string;\n /**\n * CSS selector used to find the first focusable menu item after open.\n * Defaults to `\".k-menu-item:not(.k-disabled)\"` for Kendo Menu.\n */\n menuItemSelector?: string;\n /**\n * Keeps `aria-expanded` in sync with `isOpen` on the resolved `triggerRef`.\n * Defaults to `true`. The consumer is always responsible for the static\n * `aria-haspopup=\"menu\"` and baseline `aria-expanded=\"false\"` attributes.\n */\n manageMenuTriggerAria?: boolean;\n /** Applies an accessible name to the rendered `role=\"menubar\"` when provided. */\n menuLabel?: MaybeRefOrGetter<string | null | undefined>;\n /**\n * Declares whether `triggerRef` is a button or a `tr.k-table-row`. Required so\n * misrouted refs (e.g. a button-mode ref that resolves to a row) are never\n * silently managed.\n */\n triggerMode: PopupMenuTriggerMode;\n /** Enables offset positioning and lifecycle tracking for a dynamic trigger. */\n anchor?: PopupMenuAnchorOptions | true;\n};\n\n/** Functions returned by {@link usePopupMenu} for the action menu. */\nexport type UsePopupMenuReturn = {\n /** Captures an activation relative to a trigger for activation-point anchoring. */\n setAnchorActivation: (\n trigger: HTMLElement | ComponentPublicInstance | null,\n activation: PopupMenuAnchorActivation,\n ) => boolean;\n /** Opens the menu, or closes it when it is already open. */\n handleTriggerClick: (...args: unknown[]) => void;\n /**\n * Handles keyboard input on the trigger. Enter and Space open or close\n * the menu. Escape closes an open menu or moves focus to the configured target.\n */\n handleTriggerKeydown: (...args: unknown[]) => void;\n /** Closes the menu when Escape is pressed while using the menu. */\n handleMenuEscape: (event: KeyboardEvent) => void;\n /**\n * Closes the menu after an item is chosen, then runs the optional action\n * provided by the consuming component.\n */\n handleMenuSelect: (\n event: KendoMenuSelectEvent,\n onAction?: (event: KendoMenuSelectEvent) => void,\n ) => void;\n /**\n * Restores focus after the popup closes. Keyboard actions prefer the\n * configured focus target; mouse menu selections return focus to the trigger.\n */\n handlePopupClose: () => void;\n /** Bind to Kendo Popup's `offset` prop when `anchor` is enabled. */\n offset: ComputedRef<PopupMenuOffset>;\n};\n\nconst resolveElement = (\n target: HTMLElement | ComponentPublicInstance | null | undefined,\n) => {\n if (target instanceof HTMLElement) return target;\n\n const componentElement = target?.$el;\n return componentElement instanceof HTMLElement ? componentElement : null;\n};\n\nconst isManagedTrigger = (\n element: HTMLElement,\n triggerMode: PopupMenuTriggerMode,\n) =>\n triggerMode === \"row\"\n ? element.matches(\"tr.k-table-row\")\n : !element.matches(\"tr.k-table-row\");\n\nconst warnMismatchedTrigger = (\n element: HTMLElement,\n triggerMode: PopupMenuTriggerMode,\n) => {\n console.warn(\n `usePopupMenu: triggerMode \"${triggerMode}\" does not match resolved element <${element.tagName.toLowerCase()}${\n element.className ? `.${element.className.split(\" \").join(\".\")}` : \"\"\n }>; ARIA management skipped.`,\n );\n};\n\nconst findScrollableAncestor = (element: HTMLElement) => {\n let parent = element.parentElement;\n let styledFallback: HTMLElement | null = null;\n\n while (parent) {\n const { overflow, overflowX, overflowY } = window.getComputedStyle(parent);\n const scrollsX = /auto|scroll|overlay/.test(`${overflow} ${overflowX}`);\n const scrollsY = /auto|scroll|overlay/.test(`${overflow} ${overflowY}`);\n if (scrollsX || scrollsY) styledFallback ??= parent;\n\n if (\n (scrollsX && parent.scrollWidth > parent.clientWidth) ||\n (scrollsY && parent.scrollHeight > parent.clientHeight)\n ) {\n return parent;\n }\n parent = parent.parentElement;\n }\n\n return styledFallback;\n};\n\n/**\n * Composable for accessible Kendo Popup + Menu action-menu interactions.\n *\n * It manages toggling, menu-item focus, selection modality, and contextual\n * focus restoration. The consuming component keeps ownership of menu state\n * and business-specific actions.\n *\n * @param options - Parent-owned popup state, refs, and focus configuration.\n * @returns Template event handlers for the action trigger, Kendo Menu, and Popup.\n */\nexport const usePopupMenu = (\n options: UsePopupMenuOptions,\n): UsePopupMenuReturn => {\n const popupCloseReason = ref<PopupMenuCloseReason>(null);\n const menuItemSelector =\n options.menuItemSelector ?? \".k-menu-item:not(.k-disabled)\";\n const triggerMode = options.triggerMode;\n const anchorOptions: PopupMenuAnchorOptions | undefined =\n options.anchor === true ? {} : options.anchor;\n const activationPointOptions = anchorOptions?.activationPoint\n ? anchorOptions.activationPoint === true\n ? {}\n : anchorOptions.activationPoint\n : null;\n const anchorRect = shallowRef<DOMRect | null>(null);\n const anchorActivation = shallowRef<{\n trigger: HTMLElement;\n point: { x: number; y: number };\n hasMatchedTrigger: boolean;\n } | null>(null);\n const anchorAlign: PopupMenuAlign = anchorOptions?.anchorAlign ?? {\n horizontal: \"left\",\n vertical: \"bottom\",\n };\n const popupAlign: PopupMenuAlign = anchorOptions?.popupAlign ?? {\n horizontal: \"left\",\n vertical: \"top\",\n };\n const collision: PopupMenuCollision = anchorOptions?.collision ?? {\n horizontal: \"flip\",\n vertical: \"flip\",\n };\n // Always measured (via ResizeObserver below) whenever anchor tracking is on -\n // needed both for a non-\"left\"/\"top\" popupAlign and for flip/collision\n // detection, which must compare the popup's real size against `bounds`.\n const popupRect = shallowRef<DOMRect | null>(null);\n\n const resolveTriggerElement = () => resolveElement(options.triggerRef.value);\n const triggerEl = computed(() => resolveTriggerElement());\n const anchorObserverTarget = computed(() =>\n anchorOptions && anchorOptions.hideWhenAnchorClipped !== false\n ? triggerEl.value\n : null,\n );\n // Viewport by default; the configured clipRoot when provided, matching the\n // same container `hideWhenAnchorClipped`'s intersection check already uses.\n const getOffsetBounds = (): GeometryBounds => {\n const clip = anchorOptions?.clipRoot\n ? toValue(anchorOptions.clipRoot)\n : null;\n if (clip) {\n const rect = clip.getBoundingClientRect();\n return {\n left: rect.left,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n };\n }\n return {\n left: 0,\n top: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n };\n };\n const offset = computed<PopupMenuOffset>(() => {\n const rect = anchorRect.value;\n if (!options.isOpen.value || !rect) return { left: 0, top: 0 };\n\n const bounds = getOffsetBounds();\n const corner = computeCollisionOffset({\n anchor: rect,\n popup: popupRect.value,\n anchorAlign,\n popupAlign,\n bounds,\n collision,\n });\n\n return {\n left: corner.left + window.scrollX,\n top: corner.top + window.scrollY,\n };\n });\n\n const resolveConfiguredFocusTarget = () => {\n const explicitTarget =\n options.resolveFocusTarget?.() ??\n resolveElement(options.focusTargetRef?.value);\n if (explicitTarget) return explicitTarget;\n\n return options.focusTargetContainerSelector\n ? (resolveTriggerElement()?.closest<HTMLElement>(\n options.focusTargetContainerSelector,\n ) ?? null)\n : null;\n };\n\n const setAnchorActivation = (\n trigger: HTMLElement | ComponentPublicInstance | null,\n activation: PopupMenuAnchorActivation,\n ) => {\n if (!activationPointOptions) return false;\n\n const triggerElement = resolveElement(trigger);\n if (!triggerElement) {\n anchorActivation.value = null;\n return false;\n }\n\n const triggerRect = triggerElement.getBoundingClientRect();\n if (activation.triggerType === \"keyboard\") {\n const keyboardPosition = activationPointOptions.keyboardPosition;\n const verticalPosition = keyboardPosition?.y ?? \"center\";\n const y =\n typeof verticalPosition === \"number\"\n ? verticalPosition\n : verticalPosition === \"top\"\n ? 0\n : verticalPosition === \"bottom\"\n ? triggerRect.height\n : triggerRect.height / 2;\n anchorActivation.value = {\n trigger: triggerElement,\n point: { x: keyboardPosition?.x ?? 8, y },\n hasMatchedTrigger: false,\n };\n return true;\n }\n\n if (!activation.coordinates) {\n anchorActivation.value = null;\n return false;\n }\n\n anchorActivation.value = {\n trigger: triggerElement,\n point: {\n x:\n activation.coordinates.clientX -\n triggerRect.left +\n (activationPointOptions.pointerOffset?.x ?? 0),\n y:\n activation.coordinates.clientY -\n triggerRect.top +\n (activationPointOptions.pointerOffset?.y ?? 0),\n },\n hasMatchedTrigger: false,\n };\n return true;\n };\n\n /**\n * Escape-only fallback below the configured focus target: a custom resolver,\n * else the closest `escapeFocusContainerSelector` ancestor of the trigger, or\n * of `document.activeElement` when the menu was never opened (so the trigger\n * isn't yet known to a shared registry). Button mode only.\n */\n const resolveEscapeFallbackTarget = (): HTMLElement | null => {\n if (triggerMode !== \"button\") return null;\n if (options.escapeFocusTarget) return options.escapeFocusTarget();\n\n const selector =\n options.escapeFocusContainerSelector ??\n DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR;\n const anchor =\n resolveTriggerElement() ?? (document.activeElement as HTMLElement | null);\n return anchor?.closest<HTMLElement>(selector) ?? null;\n };\n\n const focusConfiguredTargetOrTrigger = () => {\n const target =\n resolveConfiguredFocusTarget() ?? resolveEscapeFallbackTarget();\n if (target) {\n target.focus();\n return true;\n }\n\n const trigger = resolveTriggerElement();\n trigger?.focus();\n return !!trigger;\n };\n\n const focusFirstEnabledMenuItem = () => {\n const menuElement = resolveElement(options.menuRef.value);\n const firstEnabledItem = menuElement?.querySelector(menuItemSelector);\n (firstEnabledItem as HTMLElement | null)?.focus({ preventScroll: true });\n };\n\n // Captured before requestHide(), since shared-instance triggerRefs (e.g. useActiveIdRegistry)\n // can resolve to null the instant the active id is cleared, before the Popup's async close fires.\n const pendingFocusTarget = shallowRef<HTMLElement | null>(null);\n const pendingTrigger = shallowRef<HTMLElement | null>(null);\n\n // Pressing Enter/Space on a focused <button> makes the browser synthesize a\n // click on keyup; since focus restoration below runs before that keyup fires,\n // the synthetic click would otherwise land on the trigger and reopen the menu.\n let suppressNextTriggerClick = false;\n\n /**\n * Restores focus for the reason recorded by `closePopup`, then clears the\n * pending state so a second call (e.g. a delayed Kendo Popup `@close`) is a no-op.\n */\n const restorePendingFocus = () => {\n const reason = popupCloseReason.value;\n if (reason === \"keyboard\" || reason === \"escape\") {\n const target = pendingFocusTarget.value ?? pendingTrigger.value;\n target?.focus();\n // Only \"keyboard\" (Enter/Space menu selection) risks the native click-on-keyup\n // reopen; Escape never synthesizes a click, so no suppression is needed there.\n if (reason === \"keyboard\" && target && target === pendingTrigger.value) {\n suppressNextTriggerClick = true;\n }\n } else if (popupCloseReason.value === \"mouse-selection\") {\n pendingTrigger.value?.focus();\n }\n\n popupCloseReason.value = null;\n pendingFocusTarget.value = null;\n pendingTrigger.value = null;\n };\n\n /** Closes the popup if open, preserving its input modality for restoration. */\n const closePopup = (reason: PopupMenuCloseTrigger) => {\n if (!options.isOpen.value) return;\n popupCloseReason.value = reason;\n pendingFocusTarget.value =\n resolveConfiguredFocusTarget() ??\n (reason === \"escape\" ? resolveEscapeFallbackTarget() : null);\n pendingTrigger.value = resolveTriggerElement();\n syncManagedTrigger(false);\n options.requestHide();\n // Restores focus itself rather than waiting on Kendo Popup's `@close`, which\n // fires from an exit-animation callback that isn't reliably observed for every close.\n nextTick(restorePendingFocus);\n };\n\n watch(\n [triggerEl, anchorActivation],\n ([trigger], _, onCleanup) => {\n if (!anchorOptions || !trigger) {\n anchorRect.value = null;\n return;\n }\n\n let animationFrame: number | null = null;\n const measure = () => {\n animationFrame = null;\n const activation = anchorActivation.value;\n if (activationPointOptions) {\n if (activation && activation.trigger === trigger) {\n activation.hasMatchedTrigger = true;\n } else if (activation?.hasMatchedTrigger) {\n activation.trigger = trigger;\n }\n const triggerRect = trigger.getBoundingClientRect();\n anchorRect.value =\n activation?.trigger === trigger\n ? new DOMRect(\n triggerRect.left + activation.point.x,\n triggerRect.top + activation.point.y,\n 0,\n 0,\n )\n : null;\n return;\n }\n anchorRect.value =\n anchorOptions.getRect?.(trigger) ?? trigger.getBoundingClientRect();\n };\n const scheduleMeasure = () => {\n if (animationFrame === null)\n animationFrame = window.requestAnimationFrame(measure);\n };\n const observer =\n typeof window.ResizeObserver === \"function\"\n ? new window.ResizeObserver(scheduleMeasure)\n : null;\n observer?.observe(trigger);\n window.addEventListener(\"scroll\", scheduleMeasure, {\n capture: true,\n passive: true,\n });\n window.addEventListener(\"resize\", scheduleMeasure, { passive: true });\n scheduleMeasure();\n\n onCleanup(() => {\n if (animationFrame !== null)\n window.cancelAnimationFrame(animationFrame);\n observer?.disconnect();\n window.removeEventListener(\"scroll\", scheduleMeasure, true);\n window.removeEventListener(\"resize\", scheduleMeasure);\n });\n },\n { immediate: true, flush: \"post\" },\n );\n\n // Needed whenever anchor tracking is on - both for a non-\"left\"/\"top\"\n // popupAlign and for flip/collision detection, which always needs the\n // popup's real size to compare against bounds. Runs post-flush since the\n // element only has a real size once open.\n const resolvePopupContentElement = () => {\n const content = resolveElement(\n options.popupContentRef?.value ?? options.menuRef.value,\n );\n return content?.closest<HTMLElement>(\".k-popup\") ?? content;\n };\n if (anchorOptions) {\n watch(\n options.isOpen,\n (open, _prev, onCleanup) => {\n if (!open) {\n popupRect.value = null;\n return;\n }\n\n let animationFrame: number | null = null;\n const measure = () => {\n animationFrame = null;\n const contentElement = resolvePopupContentElement();\n popupRect.value = contentElement?.getBoundingClientRect() ?? null;\n };\n const scheduleMeasure = () => {\n if (animationFrame === null)\n animationFrame = window.requestAnimationFrame(measure);\n };\n const contentElement = resolvePopupContentElement();\n const observer =\n contentElement && typeof window.ResizeObserver === \"function\"\n ? new window.ResizeObserver(scheduleMeasure)\n : null;\n observer?.observe(contentElement!);\n scheduleMeasure();\n\n onCleanup(() => {\n if (animationFrame !== null)\n window.cancelAnimationFrame(animationFrame);\n observer?.disconnect();\n });\n },\n { immediate: true, flush: \"post\" },\n );\n }\n\n useIntersectionObserver({\n target: anchorObserverTarget,\n root: () =>\n anchorOptions?.clipRoot\n ? toValue(anchorOptions.clipRoot)\n : triggerEl.value\n ? findScrollableAncestor(triggerEl.value)\n : null,\n threshold:\n anchorOptions?.intersectionThreshold ??\n (activationPointOptions ? 0 : 0.5),\n onChange: (entry) => {\n if (!entry.isIntersecting) closePopup(\"anchor-hidden\");\n },\n });\n\n onClickOutside(options.menuRef, () => closePopup(\"outside-click\"), {\n ignore: [triggerEl],\n });\n\n let previousTrigger: HTMLElement | null = null;\n let previousMenubar: HTMLElement | null = null;\n\n // Reverts the previous trigger to its closed baseline; aria-haspopup is the consumer's.\n const demoteManagedTrigger = () => {\n if (previousTrigger?.isConnected) {\n previousTrigger.setAttribute(\"aria-expanded\", \"false\");\n }\n previousTrigger = null;\n };\n\n const syncManagedTrigger = (open: boolean) => {\n if (options.manageMenuTriggerAria === false) return;\n\n const trigger = triggerEl.value;\n if (!trigger) {\n if (previousTrigger?.isConnected) {\n previousTrigger.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n }\n return;\n }\n\n if (!isManagedTrigger(trigger, triggerMode)) {\n warnMismatchedTrigger(trigger, triggerMode);\n demoteManagedTrigger();\n return;\n }\n\n if (previousTrigger && previousTrigger !== trigger) {\n demoteManagedTrigger();\n }\n\n trigger.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n previousTrigger = trigger;\n };\n\n const syncMenuLabel = () => {\n const menuElement = resolveElement(options.menuRef.value);\n const menubar = menuElement?.matches('[role=\"menubar\"]')\n ? menuElement\n : menuElement?.querySelector<HTMLElement>('[role=\"menubar\"]');\n const label = toValue(options.menuLabel)?.trim();\n\n if (previousMenubar && previousMenubar !== menubar) {\n previousMenubar.removeAttribute(\"aria-label\");\n }\n if (menubar) {\n if (label) menubar.setAttribute(\"aria-label\", label);\n else menubar.removeAttribute(\"aria-label\");\n }\n previousMenubar = menubar ?? null;\n };\n\n watch(\n [options.isOpen, options.triggerRef],\n ([open]) => {\n syncManagedTrigger(open);\n if (!open && activationPointOptions) {\n anchorActivation.value = null;\n anchorRect.value = null;\n }\n },\n { immediate: true, flush: \"post\" },\n );\n\n watch(\n [options.isOpen, options.menuRef, () => toValue(options.menuLabel)],\n syncMenuLabel,\n { immediate: true, flush: \"post\" },\n );\n\n // Resets managed ARIA attributes on unmount; aria-haspopup remains consumer-owned.\n onUnmounted(() => {\n anchorActivation.value = null;\n demoteManagedTrigger();\n previousMenubar?.removeAttribute(\"aria-label\");\n });\n\n // Focuses the first enabled item whenever the menu opens, however it was opened\n // (handleTriggerClick, or a consumer driving isOpen directly for row triggers).\n // flush: \"post\" already waits for the Popup/Menu DOM to render, so no extra nextTick is needed.\n watch(\n options.isOpen,\n (open) => {\n if (open) focusFirstEnabledMenuItem();\n },\n { flush: \"post\" },\n );\n\n /** Toggles the menu and focuses its first enabled item after opening. */\n const handleTriggerClick = (...args: unknown[]) => {\n const context = args[0];\n\n if (suppressNextTriggerClick) {\n suppressNextTriggerClick = false;\n return;\n }\n\n if (options.isOpen.value) {\n closePopup(\"trigger-click\");\n return;\n }\n\n options.requestShow(context);\n };\n\n /** Handles Enter, Space, and Escape on the trigger. */\n const handleTriggerKeydown = (...args: unknown[]) => {\n const event = args[0] as KeyboardEvent;\n const context = args[1];\n\n if (event.key === \"Enter\" || event.code === \"Space\") {\n event.preventDefault();\n handleTriggerClick(context);\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n\n if (options.isOpen.value) {\n closePopup(\"escape\");\n return;\n }\n\n focusConfiguredTargetOrTrigger();\n }\n };\n\n /** Escape handler bound inside the menu. */\n const handleMenuEscape = (event: KeyboardEvent) => {\n event.preventDefault();\n event.stopPropagation();\n closePopup(\"escape\");\n };\n\n /** Closes the menu then delegates its business action to the caller. */\n const handleMenuSelect = (\n event: KendoMenuSelectEvent,\n onAction?: (event: KendoMenuSelectEvent) => void,\n ) => {\n closePopup(\n event.event?.type?.startsWith(\"key\") ? \"keyboard\" : \"mouse-selection\",\n );\n onAction?.(event);\n };\n\n /**\n * Bind to the Kendo Popup `@close` event after the owner updates `isOpen`.\n * Keyboard menu selection and Escape both try the configured focus target\n * first, Escape then falls back to `escapeFocusTarget`, and both fall back\n * to the trigger. Mouse menu selection restores the trigger, while outside\n * clicks leave focus under browser control.\n */\n // Kept as a safety net for consumers that still wire Kendo Popup's `@close`;\n // restorePendingFocus() is idempotent once closePopup's own nextTick has already run.\n const handlePopupClose = () => {\n nextTick(restorePendingFocus);\n };\n\n return {\n /**\n * Sets the anchor activation state, controlling whether the popup menu\n * should respond to trigger interactions.\n */\n setAnchorActivation,\n /**\n * Handles Kendo Menu selection: records keyboard or mouse modality,\n * requests popup close, then runs the optional caller-owned action.\n */\n handleMenuSelect,\n /**\n * Toggles the action menu. When opening, focuses the first enabled Kendo\n * Menu item after Vue renders the popup.\n */\n handleTriggerClick,\n /**\n * Handles trigger keyboard input: Enter and Space toggle the menu; Escape\n * closes an open menu or focuses the configured target when already closed.\n */\n handleTriggerKeydown,\n /** Closes the open menu through the keyboard path when Escape is pressed inside it. */\n handleMenuEscape,\n /**\n * Restores focus after Kendo Popup closes: keyboard menu selection and\n * Escape prefer the configured focus target (Escape then falls back to\n * `escapeFocusTarget`), mouse selections return to the trigger, and\n * outside clicks do not move focus.\n */\n handlePopupClose,\n offset,\n };\n};\n"],"names":["DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR","resolveElement","target","componentElement","isManagedTrigger","element","triggerMode","warnMismatchedTrigger","findScrollableAncestor","parent","styledFallback","overflow","overflowX","overflowY","scrollsX","scrollsY","usePopupMenu","options","popupCloseReason","ref","menuItemSelector","anchorOptions","activationPointOptions","anchorRect","shallowRef","anchorActivation","anchorAlign","popupAlign","collision","popupRect","resolveTriggerElement","triggerEl","computed","anchorObserverTarget","getOffsetBounds","clip","toValue","rect","offset","bounds","corner","computeCollisionOffset","resolveConfiguredFocusTarget","explicitTarget","setAnchorActivation","trigger","activation","triggerElement","triggerRect","keyboardPosition","verticalPosition","y","resolveEscapeFallbackTarget","selector","focusConfiguredTargetOrTrigger","focusFirstEnabledMenuItem","pendingFocusTarget","pendingTrigger","suppressNextTriggerClick","restorePendingFocus","reason","closePopup","syncManagedTrigger","nextTick","watch","_","onCleanup","animationFrame","measure","scheduleMeasure","observer","resolvePopupContentElement","content","open","_prev","contentElement","useIntersectionObserver","entry","onClickOutside","previousTrigger","previousMenubar","demoteManagedTrigger","syncMenuLabel","menuElement","menubar","label","onUnmounted","handleTriggerClick","args","context","event","onAction"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const l=require("vue"),X=require("@vueuse/core"),Y=require("./useIntersectionObserver-CfgNAo2N.cjs"),U=require("../geometry.cjs"),K=".k-table-row",b=n=>{if(n instanceof HTMLElement)return n;const r=n?.$el;return r instanceof HTMLElement?r:null},j=(n,r)=>r==="row"?n.matches("tr.k-table-row"):!n.matches("tr.k-table-row"),G=(n,r)=>{console.warn(`usePopupMenu: triggerMode "${r}" does not match resolved element <${n.tagName.toLowerCase()}${n.className?`.${n.className.split(" ").join(".")}`:""}>; ARIA management skipped.`)},J=n=>{let r=n.parentElement,y=null;for(;r;){const{overflow:m,overflowX:o,overflowY:f}=window.getComputedStyle(r),d=/auto|scroll|overlay/.test(`${m} ${o}`),c=/auto|scroll|overlay/.test(`${m} ${f}`);if((d||c)&&(y??=r),d&&r.scrollWidth>r.clientWidth||c&&r.scrollHeight>r.clientHeight)return r;r=r.parentElement}return y},Q=n=>{const r=l.ref(null),y=n.menuItemSelector??".k-menu-item:not(.k-disabled)",m=n.triggerMode,o=n.anchor===!0?{}:n.anchor,f=o?.activationPoint?o.activationPoint===!0?{}:o.activationPoint:null,d=l.shallowRef(null),c=l.shallowRef(null),I=o?.anchorAlign??{horizontal:"left",vertical:"bottom"},z=o?.popupAlign??{horizontal:"left",vertical:"top"},$=o?.collision??{horizontal:"flip",vertical:"flip"},M=l.shallowRef(null),T=()=>b(n.triggerRef.value),v=l.computed(()=>T()),B=l.computed(()=>o&&o.hideWhenAnchorClipped!==!1?v.value:null),H=()=>{const e=o?.clipRoot?l.toValue(o.clipRoot):null;if(e){const t=e.getBoundingClientRect();return{left:t.left,top:t.top,right:t.right,bottom:t.bottom}}return{left:0,top:0,right:window.innerWidth,bottom:window.innerHeight}},N=l.computed(()=>{const e=d.value;if(!n.isOpen.value||!e)return{left:0,top:0};const t=H(),s=U.computeCollisionOffset({anchor:e,popup:M.value,anchorAlign:I,popupAlign:z,bounds:t,collision:$});return{left:s.left+window.scrollX,top:s.top+window.scrollY}}),F=()=>{const e=n.resolveFocusTarget?.()??b(n.focusTargetRef?.value);return e||(n.focusTargetContainerSelector?T()?.closest(n.focusTargetContainerSelector)??null:null)},_=(e,t)=>{if(!f)return!1;const s=b(e);if(!s)return c.value=null,!1;const u=s.getBoundingClientRect();if(t.triggerType==="keyboard"){const w=f.keyboardPosition,a=w?.y??"center",p=typeof a=="number"?a:a==="top"?0:a==="bottom"?u.height:u.height/2;return c.value={trigger:s,point:{x:w?.x??8,y:p},hasMatchedTrigger:!1},!0}return t.coordinates?(c.value={trigger:s,point:{x:t.coordinates.clientX-u.left+(f.pointerOffset?.x??0),y:t.coordinates.clientY-u.top+(f.pointerOffset?.y??0)},hasMatchedTrigger:!1},!0):(c.value=null,!1)},P=()=>{if(m!=="button")return null;if(n.escapeFocusTarget)return n.escapeFocusTarget();const e=n.escapeFocusContainerSelector??K;return(T()??document.activeElement)?.closest(e)??null},D=()=>{const e=F()??P();if(e)return e.focus(),!0;const t=T();return t?.focus(),!!t},W=()=>{b(n.menuRef.value)?.querySelector(y)?.focus({preventScroll:!0})},O=l.shallowRef(null),R=l.shallowRef(null);let A=!1;const S=()=>{const e=r.value;if(e==="keyboard"||e==="escape"){const t=O.value??R.value;t?.focus(),e==="keyboard"&&t&&t===R.value&&(A=!0)}else r.value==="mouse-selection"&&R.value?.focus();r.value=null,O.value=null,R.value=null},h=e=>{n.isOpen.value&&(r.value=e,O.value=F()??(e==="escape"?P():null),R.value=T(),L(!1),n.requestHide(),l.nextTick(S))};l.watch([v,c],([e],t,s)=>{if(!o||!e){d.value=null;return}let u=null;const w=()=>{u=null;const i=c.value;if(f){i&&i.trigger===e?i.hasMatchedTrigger=!0:i?.hasMatchedTrigger&&(i.trigger=e);const C=e.getBoundingClientRect();d.value=i?.trigger===e?new DOMRect(C.left+i.point.x,C.top+i.point.y,0,0):null;return}d.value=o.getRect?.(e)??e.getBoundingClientRect()},a=()=>{u===null&&(u=window.requestAnimationFrame(w))},p=typeof window.ResizeObserver=="function"?new window.ResizeObserver(a):null;p?.observe(e),window.addEventListener("scroll",a,{capture:!0,passive:!0}),window.addEventListener("resize",a,{passive:!0}),a(),s(()=>{u!==null&&window.cancelAnimationFrame(u),p?.disconnect(),window.removeEventListener("scroll",a,!0),window.removeEventListener("resize",a)})},{immediate:!0,flush:"post"});const x=()=>{const e=b(n.popupContentRef?.value??n.menuRef.value);return e?.closest(".k-popup")??e};o&&l.watch(n.isOpen,(e,t,s)=>{if(!e){M.value=null;return}let u=null;const w=()=>{u=null;const C=x();M.value=C?.getBoundingClientRect()??null},a=()=>{u===null&&(u=window.requestAnimationFrame(w))},p=x(),i=p&&typeof window.ResizeObserver=="function"?new window.ResizeObserver(a):null;i?.observe(p),a(),s(()=>{u!==null&&window.cancelAnimationFrame(u),i?.disconnect()})},{immediate:!0,flush:"post"}),Y.useIntersectionObserver({target:B,root:()=>o?.clipRoot?l.toValue(o.clipRoot):v.value?J(v.value):null,threshold:o?.intersectionThreshold??(f?0:.5),onChange:e=>{e.isIntersecting||h("anchor-hidden")}}),X.onClickOutside(n.menuRef,()=>h("outside-click"),{ignore:[v]});let g=null,E=null;const k=()=>{g?.isConnected&&g.setAttribute("aria-expanded","false"),g=null},L=e=>{if(n.manageMenuTriggerAria===!1)return;const t=v.value;if(!t){g?.isConnected&&g.setAttribute("aria-expanded",e?"true":"false");return}if(!j(t,m)){G(t,m),k();return}g&&g!==t&&k(),t.setAttribute("aria-expanded",e?"true":"false"),g=t},V=()=>{const e=b(n.menuRef.value),t=e?.matches('[role="menubar"]')?e:e?.querySelector('[role="menubar"]'),s=l.toValue(n.menuLabel)?.trim();E&&E!==t&&E.removeAttribute("aria-label"),t&&(s?t.setAttribute("aria-label",s):t.removeAttribute("aria-label")),E=t??null};l.watch([n.isOpen,n.triggerRef],([e])=>{L(e),!e&&f&&(c.value=null,d.value=null)},{immediate:!0,flush:"post"}),l.watch([n.isOpen,n.menuRef,()=>l.toValue(n.menuLabel)],V,{immediate:!0,flush:"post"}),l.onUnmounted(()=>{c.value=null,k(),E?.removeAttribute("aria-label")}),l.watch(n.isOpen,e=>{e&&W()},{flush:"post"});const q=(...e)=>{const t=e[0];if(A){A=!1;return}if(n.isOpen.value){h("trigger-click");return}n.requestShow(t)};return{setAnchorActivation:_,handleMenuSelect:(e,t)=>{h(e.event?.type?.startsWith("key")?"keyboard":"mouse-selection"),t?.(e)},handleTriggerClick:q,handleTriggerKeydown:(...e)=>{const t=e[0],s=e[1];if(t.key==="Enter"||t.code==="Space"){t.preventDefault(),q(s);return}if(t.key==="Escape"){if(t.preventDefault(),t.stopPropagation(),n.isOpen.value){h("escape");return}D()}},handleMenuEscape:e=>{e.preventDefault(),e.stopPropagation(),h("escape")},handlePopupClose:()=>{l.nextTick(S)},offset:N}};exports.usePopupMenu=Q;
|
|
2
|
+
//# sourceMappingURL=usePopupMenu-DeTWakUH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopupMenu-DeTWakUH.cjs","sources":["../../src/menu/usePopupMenu.ts"],"sourcesContent":["import {\n computed,\n nextTick,\n onUnmounted,\n ref,\n shallowRef,\n toValue,\n watch,\n type ComponentPublicInstance,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from \"vue\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { useIntersectionObserver } from \"../observer\";\nimport {\n computeCollisionOffset,\n type GeometryAlign,\n type GeometryBounds,\n type GeometryCollision,\n} from \"../geometry\";\n\n/** A template ref that may point to an element or a Vue/Kendo component. */\nexport type PopupMenuElementRef = Ref<\n HTMLElement | ComponentPublicInstance | null\n>;\n\nexport type PopupMenuTriggerMode = \"button\" | \"row\";\n\n/** Default `escapeFocusContainerSelector` for `triggerMode: \"button\"`. */\nconst DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR = \".k-table-row\";\n\nexport type PopupMenuOffset = {\n left: number;\n top: number;\n};\n\n/** Mirrors Kendo Popup's `anchorAlign`/`popupAlign` point shape. */\nexport type PopupMenuAlign = GeometryAlign;\n\n/** Per-axis viewport collision behavior for offset-positioned popups. */\nexport type PopupMenuCollision = GeometryCollision;\n\nexport type PopupMenuAnchorActivation = {\n triggerType: \"click\" | \"keyboard\";\n coordinates?: {\n clientX: number;\n clientY: number;\n };\n};\n\nexport type PopupMenuActivationPointOptions = {\n /** Added to pointer coordinates after they are made trigger-relative. */\n pointerOffset?: { x?: number; y?: number };\n /** Trigger-relative keyboard position. Defaults to 8px from the left and vertically centered. */\n keyboardPosition?: {\n x?: number;\n y?: number | \"top\" | \"center\" | \"bottom\";\n };\n};\n\ntype PopupMenuAnchorBaseOptions = {\n /** Scrollable/clipping container used for out-of-view dismissal. */\n clipRoot?: MaybeRefOrGetter<Element | null>;\n /** Closes the menu after its trigger leaves the clipping container. */\n hideWhenAnchorClipped?: boolean;\n /** Intersection ratio required to keep the anchor considered visible. */\n intersectionThreshold?: number | number[];\n /** Per-axis collision behavior. Defaults to `flip` on both axes. */\n collision?: PopupMenuCollision;\n /**\n * Point on the anchor rect that `offset` is computed from. Mirrors Kendo\n * Popup's `anchorAlign` semantics. Defaults to `{ vertical: \"bottom\",\n * horizontal: \"left\" }`, matching Kendo's own default. Passing `anchorAlign`/\n * `popupAlign` directly to `<Popup>` has no effect when positioning via\n * `offset` (no `anchor` DOM ref) - Kendo's own alignment engine only runs\n * against a real anchor element - so these options exist to reproduce that\n * alignment ourselves in the computed `offset`.\n */\n anchorAlign?: PopupMenuAlign;\n /**\n * Point on the popup itself that is placed at the computed anchor point.\n * Mirrors Kendo Popup's `popupAlign` semantics. Defaults to `{ vertical:\n * \"top\", horizontal: \"left\" }`. Requires measuring the rendered popup\n * border box; until it has a size (e.g. the first open frame), non-\"left\"/\n * \"top\" alignments briefly fall back to \"left\"/\"top\".\n */\n popupAlign?: PopupMenuAlign;\n};\n\n/** Offset-positioning options for a Popup with a dynamically changing trigger. */\nexport type PopupMenuAnchorOptions = PopupMenuAnchorBaseOptions &\n (\n | {\n /** Tracks a pointer or keyboard activation point relative to the trigger. */\n activationPoint: true | PopupMenuActivationPointOptions;\n getRect?: never;\n }\n | {\n activationPoint?: never;\n /** Resolves a custom anchor rect from the current trigger element. */\n getRect?: (trigger: HTMLElement) => DOMRect | null;\n }\n );\n\n/** Why the popup was closed, including the focus policy for mouse paths. */\nexport type PopupMenuCloseReason =\n /** Keyboard-driven menu selection (Enter/Space on a menu item); restores the configured focus target. */\n | \"keyboard\"\n /** Escape key; restores the configured focus target, then `escapeFocusTarget`, then the trigger. */\n | \"escape\"\n /** Pointer menu selection; restores focus to the trigger. */\n | \"mouse-selection\"\n /** Pointer interaction outside the menu; leaves browser focus unchanged. */\n | \"outside-click\"\n /** Interaction with the open trigger; leaves browser focus unchanged. */\n | \"trigger-click\"\n /** Trigger left its clipping area; closes without scrolling it back into view. */\n | \"anchor-hidden\"\n /** No close has been requested yet. */\n | null;\nexport type PopupMenuCloseTrigger = Exclude<PopupMenuCloseReason, null>;\n\n/** Minimal event shape emitted by Kendo Menu `@select`. */\nexport type KendoMenuSelectEvent<\n TItem = { text?: string; id?: string; cssClass?: string; data?: unknown },\n> = {\n item?: TItem;\n event?: {\n type?: string;\n } | null;\n};\n\n/** Options for configuring {@link usePopupMenu}. */\nexport type UsePopupMenuOptions = {\n /** Read-only reactive flag reflecting whether the popup menu is currently open. */\n isOpen: Readonly<Ref<boolean>>;\n /** Ref to the popup menu element or component. Used for outside-click detection. */\n menuRef: PopupMenuElementRef;\n /**\n * Optional measurement source for custom popup markup. The source is\n * promoted to its nearest Kendo `.k-popup` so alignment and collision use\n * the complete border box. Defaults to `menuRef`; outside-click detection\n * always uses `menuRef` directly.\n */\n popupContentRef?: PopupMenuElementRef;\n /** Ref to the trigger button element or component. Ignored by outside-click detection. */\n triggerRef: PopupMenuElementRef;\n /** Called to open the popup menu. Kendo passes its event args as a rest tuple. */\n requestShow: (...args: unknown[]) => void;\n /** Called to close the popup menu. Kendo passes its event args as a rest tuple. */\n requestHide: (...args: unknown[]) => void;\n /**\n * Optional target to focus after a keyboard-driven close.\n * Supports ordinary elements and Vue/Kendo components exposing `$el`.\n */\n focusTargetRef?: PopupMenuElementRef;\n /**\n * Resolves the focus target when it is virtualized or dynamically rendered.\n * Takes precedence over `focusTargetRef`.\n */\n resolveFocusTarget?: () => HTMLElement | null;\n /**\n * Resolves the closest matching ancestor of the trigger as the configured\n * keyboard-close focus target. Used after `resolveFocusTarget` and\n * `focusTargetRef`.\n */\n focusTargetContainerSelector?: string;\n /**\n * Resolves a fallback focus target for Escape closes when no `focusTargetRef`/\n * `resolveFocusTarget` is configured, e.g. the trigger's containing grid row so\n * keyboard users land back in row navigation instead of on the trigger button.\n * Only consulted for `triggerMode: \"button\"`; row triggers already restore to\n * themselves. Takes effect only for Escape, not keyboard menu selection.\n * Takes precedence over `escapeFocusContainerSelector`.\n */\n escapeFocusTarget?: () => HTMLElement | null;\n /**\n * CSS selector for the closest ancestor of the trigger (or, if the menu was\n * never opened, of `document.activeElement`) to focus on Escape. Sugar over\n * `escapeFocusTarget` for the common \"collapse back into the row\" case.\n * Defaults to `\".k-table-row\"` for `triggerMode: \"button\"`; harmless to leave\n * at its default for non-grid button triggers since a missing ancestor simply\n * falls through to focusing the trigger. Ignored when `escapeFocusTarget` is set.\n */\n escapeFocusContainerSelector?: string;\n /**\n * CSS selector used to find the first focusable menu item after open.\n * Defaults to `\".k-menu-item:not(.k-disabled)\"` for Kendo Menu.\n */\n menuItemSelector?: string;\n /**\n * Keeps `aria-expanded` in sync with `isOpen` on the resolved `triggerRef`.\n * Defaults to `true`. The consumer is always responsible for the static\n * `aria-haspopup=\"menu\"` and baseline `aria-expanded=\"false\"` attributes.\n */\n manageMenuTriggerAria?: boolean;\n /** Applies an accessible name to the rendered `role=\"menubar\"` when provided. */\n menuLabel?: MaybeRefOrGetter<string | null | undefined>;\n /**\n * Declares whether `triggerRef` is a button or a `tr.k-table-row`. Required so\n * misrouted refs (e.g. a button-mode ref that resolves to a row) are never\n * silently managed.\n */\n triggerMode: PopupMenuTriggerMode;\n /** Enables offset positioning and lifecycle tracking for a dynamic trigger. */\n anchor?: PopupMenuAnchorOptions | true;\n};\n\n/** Functions returned by {@link usePopupMenu} for the action menu. */\nexport type UsePopupMenuReturn = {\n /** Captures an activation relative to a trigger for activation-point anchoring. */\n setAnchorActivation: (\n trigger: HTMLElement | ComponentPublicInstance | null,\n activation: PopupMenuAnchorActivation,\n ) => boolean;\n /** Opens the menu, or closes it when it is already open. */\n handleTriggerClick: (...args: unknown[]) => void;\n /**\n * Handles keyboard input on the trigger. Enter and Space open or close\n * the menu. Escape closes an open menu or moves focus to the configured target.\n */\n handleTriggerKeydown: (...args: unknown[]) => void;\n /** Closes the menu when Escape is pressed while using the menu. */\n handleMenuEscape: (event: KeyboardEvent) => void;\n /**\n * Closes the menu after an item is chosen, then runs the optional action\n * provided by the consuming component.\n */\n handleMenuSelect: (\n event: KendoMenuSelectEvent,\n onAction?: (event: KendoMenuSelectEvent) => void,\n ) => void;\n /**\n * Restores focus after the popup closes. Keyboard actions prefer the\n * configured focus target; mouse menu selections return focus to the trigger.\n */\n handlePopupClose: () => void;\n /** Bind to Kendo Popup's `offset` prop when `anchor` is enabled. */\n offset: ComputedRef<PopupMenuOffset>;\n};\n\nconst resolveElement = (\n target: HTMLElement | ComponentPublicInstance | null | undefined,\n) => {\n if (target instanceof HTMLElement) return target;\n\n const componentElement = target?.$el;\n return componentElement instanceof HTMLElement ? componentElement : null;\n};\n\nconst isManagedTrigger = (\n element: HTMLElement,\n triggerMode: PopupMenuTriggerMode,\n) =>\n triggerMode === \"row\"\n ? element.matches(\"tr.k-table-row\")\n : !element.matches(\"tr.k-table-row\");\n\nconst warnMismatchedTrigger = (\n element: HTMLElement,\n triggerMode: PopupMenuTriggerMode,\n) => {\n console.warn(\n `usePopupMenu: triggerMode \"${triggerMode}\" does not match resolved element <${element.tagName.toLowerCase()}${\n element.className ? `.${element.className.split(\" \").join(\".\")}` : \"\"\n }>; ARIA management skipped.`,\n );\n};\n\nconst findScrollableAncestor = (element: HTMLElement) => {\n let parent = element.parentElement;\n let styledFallback: HTMLElement | null = null;\n\n while (parent) {\n const { overflow, overflowX, overflowY } = window.getComputedStyle(parent);\n const scrollsX = /auto|scroll|overlay/.test(`${overflow} ${overflowX}`);\n const scrollsY = /auto|scroll|overlay/.test(`${overflow} ${overflowY}`);\n if (scrollsX || scrollsY) styledFallback ??= parent;\n\n if (\n (scrollsX && parent.scrollWidth > parent.clientWidth) ||\n (scrollsY && parent.scrollHeight > parent.clientHeight)\n ) {\n return parent;\n }\n parent = parent.parentElement;\n }\n\n return styledFallback;\n};\n\n/**\n * Composable for accessible Kendo Popup + Menu action-menu interactions.\n *\n * It manages toggling, menu-item focus, selection modality, and contextual\n * focus restoration. The consuming component keeps ownership of menu state\n * and business-specific actions.\n *\n * @param options - Parent-owned popup state, refs, and focus configuration.\n * @returns Template event handlers for the action trigger, Kendo Menu, and Popup.\n */\nexport const usePopupMenu = (\n options: UsePopupMenuOptions,\n): UsePopupMenuReturn => {\n const popupCloseReason = ref<PopupMenuCloseReason>(null);\n const menuItemSelector =\n options.menuItemSelector ?? \".k-menu-item:not(.k-disabled)\";\n const triggerMode = options.triggerMode;\n const anchorOptions: PopupMenuAnchorOptions | undefined =\n options.anchor === true ? {} : options.anchor;\n const activationPointOptions = anchorOptions?.activationPoint\n ? anchorOptions.activationPoint === true\n ? {}\n : anchorOptions.activationPoint\n : null;\n const anchorRect = shallowRef<DOMRect | null>(null);\n const anchorActivation = shallowRef<{\n trigger: HTMLElement;\n point: { x: number; y: number };\n hasMatchedTrigger: boolean;\n } | null>(null);\n const anchorAlign: PopupMenuAlign = anchorOptions?.anchorAlign ?? {\n horizontal: \"left\",\n vertical: \"bottom\",\n };\n const popupAlign: PopupMenuAlign = anchorOptions?.popupAlign ?? {\n horizontal: \"left\",\n vertical: \"top\",\n };\n const collision: PopupMenuCollision = anchorOptions?.collision ?? {\n horizontal: \"flip\",\n vertical: \"flip\",\n };\n // Always measured (via ResizeObserver below) whenever anchor tracking is on -\n // needed both for a non-\"left\"/\"top\" popupAlign and for flip/collision\n // detection, which must compare the popup's real size against `bounds`.\n const popupRect = shallowRef<DOMRect | null>(null);\n\n const resolveTriggerElement = () => resolveElement(options.triggerRef.value);\n const triggerEl = computed(() => resolveTriggerElement());\n const anchorObserverTarget = computed(() =>\n anchorOptions && anchorOptions.hideWhenAnchorClipped !== false\n ? triggerEl.value\n : null,\n );\n // Viewport by default; the configured clipRoot when provided, matching the\n // same container `hideWhenAnchorClipped`'s intersection check already uses.\n const getOffsetBounds = (): GeometryBounds => {\n const clip = anchorOptions?.clipRoot\n ? toValue(anchorOptions.clipRoot)\n : null;\n if (clip) {\n const rect = clip.getBoundingClientRect();\n return {\n left: rect.left,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n };\n }\n return {\n left: 0,\n top: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n };\n };\n const offset = computed<PopupMenuOffset>(() => {\n const rect = anchorRect.value;\n if (!options.isOpen.value || !rect) return { left: 0, top: 0 };\n\n const bounds = getOffsetBounds();\n const corner = computeCollisionOffset({\n anchor: rect,\n popup: popupRect.value,\n anchorAlign,\n popupAlign,\n bounds,\n collision,\n });\n\n return {\n left: corner.left + window.scrollX,\n top: corner.top + window.scrollY,\n };\n });\n\n const resolveConfiguredFocusTarget = () => {\n const explicitTarget =\n options.resolveFocusTarget?.() ??\n resolveElement(options.focusTargetRef?.value);\n if (explicitTarget) return explicitTarget;\n\n return options.focusTargetContainerSelector\n ? (resolveTriggerElement()?.closest<HTMLElement>(\n options.focusTargetContainerSelector,\n ) ?? null)\n : null;\n };\n\n const setAnchorActivation = (\n trigger: HTMLElement | ComponentPublicInstance | null,\n activation: PopupMenuAnchorActivation,\n ) => {\n if (!activationPointOptions) return false;\n\n const triggerElement = resolveElement(trigger);\n if (!triggerElement) {\n anchorActivation.value = null;\n return false;\n }\n\n const triggerRect = triggerElement.getBoundingClientRect();\n if (activation.triggerType === \"keyboard\") {\n const keyboardPosition = activationPointOptions.keyboardPosition;\n const verticalPosition = keyboardPosition?.y ?? \"center\";\n const y =\n typeof verticalPosition === \"number\"\n ? verticalPosition\n : verticalPosition === \"top\"\n ? 0\n : verticalPosition === \"bottom\"\n ? triggerRect.height\n : triggerRect.height / 2;\n anchorActivation.value = {\n trigger: triggerElement,\n point: { x: keyboardPosition?.x ?? 8, y },\n hasMatchedTrigger: false,\n };\n return true;\n }\n\n if (!activation.coordinates) {\n anchorActivation.value = null;\n return false;\n }\n\n anchorActivation.value = {\n trigger: triggerElement,\n point: {\n x:\n activation.coordinates.clientX -\n triggerRect.left +\n (activationPointOptions.pointerOffset?.x ?? 0),\n y:\n activation.coordinates.clientY -\n triggerRect.top +\n (activationPointOptions.pointerOffset?.y ?? 0),\n },\n hasMatchedTrigger: false,\n };\n return true;\n };\n\n /**\n * Escape-only fallback below the configured focus target: a custom resolver,\n * else the closest `escapeFocusContainerSelector` ancestor of the trigger, or\n * of `document.activeElement` when the menu was never opened (so the trigger\n * isn't yet known to a shared registry). Button mode only.\n */\n const resolveEscapeFallbackTarget = (): HTMLElement | null => {\n if (triggerMode !== \"button\") return null;\n if (options.escapeFocusTarget) return options.escapeFocusTarget();\n\n const selector =\n options.escapeFocusContainerSelector ??\n DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR;\n const anchor =\n resolveTriggerElement() ?? (document.activeElement as HTMLElement | null);\n return anchor?.closest<HTMLElement>(selector) ?? null;\n };\n\n const focusConfiguredTargetOrTrigger = () => {\n const target =\n resolveConfiguredFocusTarget() ?? resolveEscapeFallbackTarget();\n if (target) {\n target.focus();\n return true;\n }\n\n const trigger = resolveTriggerElement();\n trigger?.focus();\n return !!trigger;\n };\n\n const focusFirstEnabledMenuItem = () => {\n const menuElement = resolveElement(options.menuRef.value);\n const firstEnabledItem = menuElement?.querySelector(menuItemSelector);\n (firstEnabledItem as HTMLElement | null)?.focus({ preventScroll: true });\n };\n\n // Captured before requestHide(), since shared-instance triggerRefs (e.g. useActiveIdRegistry)\n // can resolve to null the instant the active id is cleared, before the Popup's async close fires.\n const pendingFocusTarget = shallowRef<HTMLElement | null>(null);\n const pendingTrigger = shallowRef<HTMLElement | null>(null);\n\n // Pressing Enter/Space on a focused <button> makes the browser synthesize a\n // click on keyup; since focus restoration below runs before that keyup fires,\n // the synthetic click would otherwise land on the trigger and reopen the menu.\n let suppressNextTriggerClick = false;\n\n /**\n * Restores focus for the reason recorded by `closePopup`, then clears the\n * pending state so a second call (e.g. a delayed Kendo Popup `@close`) is a no-op.\n */\n const restorePendingFocus = () => {\n const reason = popupCloseReason.value;\n if (reason === \"keyboard\" || reason === \"escape\") {\n const target = pendingFocusTarget.value ?? pendingTrigger.value;\n target?.focus();\n // Only \"keyboard\" (Enter/Space menu selection) risks the native click-on-keyup\n // reopen; Escape never synthesizes a click, so no suppression is needed there.\n if (reason === \"keyboard\" && target && target === pendingTrigger.value) {\n suppressNextTriggerClick = true;\n }\n } else if (popupCloseReason.value === \"mouse-selection\") {\n pendingTrigger.value?.focus();\n }\n\n popupCloseReason.value = null;\n pendingFocusTarget.value = null;\n pendingTrigger.value = null;\n };\n\n /** Closes the popup if open, preserving its input modality for restoration. */\n const closePopup = (reason: PopupMenuCloseTrigger) => {\n if (!options.isOpen.value) return;\n popupCloseReason.value = reason;\n pendingFocusTarget.value =\n resolveConfiguredFocusTarget() ??\n (reason === \"escape\" ? resolveEscapeFallbackTarget() : null);\n pendingTrigger.value = resolveTriggerElement();\n syncManagedTrigger(false);\n options.requestHide();\n // Restores focus itself rather than waiting on Kendo Popup's `@close`, which\n // fires from an exit-animation callback that isn't reliably observed for every close.\n nextTick(restorePendingFocus);\n };\n\n watch(\n [triggerEl, anchorActivation],\n ([trigger], _, onCleanup) => {\n if (!anchorOptions || !trigger) {\n anchorRect.value = null;\n return;\n }\n\n let animationFrame: number | null = null;\n const measure = () => {\n animationFrame = null;\n const activation = anchorActivation.value;\n if (activationPointOptions) {\n if (activation && activation.trigger === trigger) {\n activation.hasMatchedTrigger = true;\n } else if (activation?.hasMatchedTrigger) {\n activation.trigger = trigger;\n }\n const triggerRect = trigger.getBoundingClientRect();\n anchorRect.value =\n activation?.trigger === trigger\n ? new DOMRect(\n triggerRect.left + activation.point.x,\n triggerRect.top + activation.point.y,\n 0,\n 0,\n )\n : null;\n return;\n }\n anchorRect.value =\n anchorOptions.getRect?.(trigger) ?? trigger.getBoundingClientRect();\n };\n const scheduleMeasure = () => {\n if (animationFrame === null)\n animationFrame = window.requestAnimationFrame(measure);\n };\n const observer =\n typeof window.ResizeObserver === \"function\"\n ? new window.ResizeObserver(scheduleMeasure)\n : null;\n observer?.observe(trigger);\n window.addEventListener(\"scroll\", scheduleMeasure, {\n capture: true,\n passive: true,\n });\n window.addEventListener(\"resize\", scheduleMeasure, { passive: true });\n scheduleMeasure();\n\n onCleanup(() => {\n if (animationFrame !== null)\n window.cancelAnimationFrame(animationFrame);\n observer?.disconnect();\n window.removeEventListener(\"scroll\", scheduleMeasure, true);\n window.removeEventListener(\"resize\", scheduleMeasure);\n });\n },\n { immediate: true, flush: \"post\" },\n );\n\n // Needed whenever anchor tracking is on - both for a non-\"left\"/\"top\"\n // popupAlign and for flip/collision detection, which always needs the\n // popup's real size to compare against bounds. Runs post-flush since the\n // element only has a real size once open.\n const resolvePopupContentElement = () => {\n const content = resolveElement(\n options.popupContentRef?.value ?? options.menuRef.value,\n );\n return content?.closest<HTMLElement>(\".k-popup\") ?? content;\n };\n if (anchorOptions) {\n watch(\n options.isOpen,\n (open, _prev, onCleanup) => {\n if (!open) {\n popupRect.value = null;\n return;\n }\n\n let animationFrame: number | null = null;\n const measure = () => {\n animationFrame = null;\n const contentElement = resolvePopupContentElement();\n popupRect.value = contentElement?.getBoundingClientRect() ?? null;\n };\n const scheduleMeasure = () => {\n if (animationFrame === null)\n animationFrame = window.requestAnimationFrame(measure);\n };\n const contentElement = resolvePopupContentElement();\n const observer =\n contentElement && typeof window.ResizeObserver === \"function\"\n ? new window.ResizeObserver(scheduleMeasure)\n : null;\n observer?.observe(contentElement!);\n scheduleMeasure();\n\n onCleanup(() => {\n if (animationFrame !== null)\n window.cancelAnimationFrame(animationFrame);\n observer?.disconnect();\n });\n },\n { immediate: true, flush: \"post\" },\n );\n }\n\n useIntersectionObserver({\n target: anchorObserverTarget,\n root: () =>\n anchorOptions?.clipRoot\n ? toValue(anchorOptions.clipRoot)\n : triggerEl.value\n ? findScrollableAncestor(triggerEl.value)\n : null,\n threshold:\n anchorOptions?.intersectionThreshold ??\n (activationPointOptions ? 0 : 0.5),\n onChange: (entry) => {\n if (!entry.isIntersecting) closePopup(\"anchor-hidden\");\n },\n });\n\n onClickOutside(options.menuRef, () => closePopup(\"outside-click\"), {\n ignore: [triggerEl],\n });\n\n let previousTrigger: HTMLElement | null = null;\n let previousMenubar: HTMLElement | null = null;\n\n // Reverts the previous trigger to its closed baseline; aria-haspopup is the consumer's.\n const demoteManagedTrigger = () => {\n if (previousTrigger?.isConnected) {\n previousTrigger.setAttribute(\"aria-expanded\", \"false\");\n }\n previousTrigger = null;\n };\n\n const syncManagedTrigger = (open: boolean) => {\n if (options.manageMenuTriggerAria === false) return;\n\n const trigger = triggerEl.value;\n if (!trigger) {\n if (previousTrigger?.isConnected) {\n previousTrigger.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n }\n return;\n }\n\n if (!isManagedTrigger(trigger, triggerMode)) {\n warnMismatchedTrigger(trigger, triggerMode);\n demoteManagedTrigger();\n return;\n }\n\n if (previousTrigger && previousTrigger !== trigger) {\n demoteManagedTrigger();\n }\n\n trigger.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n previousTrigger = trigger;\n };\n\n const syncMenuLabel = () => {\n const menuElement = resolveElement(options.menuRef.value);\n const menubar = menuElement?.matches('[role=\"menubar\"]')\n ? menuElement\n : menuElement?.querySelector<HTMLElement>('[role=\"menubar\"]');\n const label = toValue(options.menuLabel)?.trim();\n\n if (previousMenubar && previousMenubar !== menubar) {\n previousMenubar.removeAttribute(\"aria-label\");\n }\n if (menubar) {\n if (label) menubar.setAttribute(\"aria-label\", label);\n else menubar.removeAttribute(\"aria-label\");\n }\n previousMenubar = menubar ?? null;\n };\n\n watch(\n [options.isOpen, options.triggerRef],\n ([open]) => {\n syncManagedTrigger(open);\n if (!open && activationPointOptions) {\n anchorActivation.value = null;\n anchorRect.value = null;\n }\n },\n { immediate: true, flush: \"post\" },\n );\n\n watch(\n [options.isOpen, options.menuRef, () => toValue(options.menuLabel)],\n syncMenuLabel,\n { immediate: true, flush: \"post\" },\n );\n\n // Resets managed ARIA attributes on unmount; aria-haspopup remains consumer-owned.\n onUnmounted(() => {\n anchorActivation.value = null;\n demoteManagedTrigger();\n previousMenubar?.removeAttribute(\"aria-label\");\n });\n\n // Focuses the first enabled item whenever the menu opens, however it was opened\n // (handleTriggerClick, or a consumer driving isOpen directly for row triggers).\n // flush: \"post\" already waits for the Popup/Menu DOM to render, so no extra nextTick is needed.\n watch(\n options.isOpen,\n (open) => {\n if (open) focusFirstEnabledMenuItem();\n },\n { flush: \"post\" },\n );\n\n /** Toggles the menu and focuses its first enabled item after opening. */\n const handleTriggerClick = (...args: unknown[]) => {\n const context = args[0];\n\n if (suppressNextTriggerClick) {\n suppressNextTriggerClick = false;\n return;\n }\n\n if (options.isOpen.value) {\n closePopup(\"trigger-click\");\n return;\n }\n\n options.requestShow(context);\n };\n\n /** Handles Enter, Space, and Escape on the trigger. */\n const handleTriggerKeydown = (...args: unknown[]) => {\n const event = args[0] as KeyboardEvent;\n const context = args[1];\n\n if (event.key === \"Enter\" || event.code === \"Space\") {\n event.preventDefault();\n handleTriggerClick(context);\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n\n if (options.isOpen.value) {\n closePopup(\"escape\");\n return;\n }\n\n focusConfiguredTargetOrTrigger();\n }\n };\n\n /** Escape handler bound inside the menu. */\n const handleMenuEscape = (event: KeyboardEvent) => {\n event.preventDefault();\n event.stopPropagation();\n closePopup(\"escape\");\n };\n\n /** Closes the menu then delegates its business action to the caller. */\n const handleMenuSelect = (\n event: KendoMenuSelectEvent,\n onAction?: (event: KendoMenuSelectEvent) => void,\n ) => {\n closePopup(\n event.event?.type?.startsWith(\"key\") ? \"keyboard\" : \"mouse-selection\",\n );\n onAction?.(event);\n };\n\n /**\n * Bind to the Kendo Popup `@close` event after the owner updates `isOpen`.\n * Keyboard menu selection and Escape both try the configured focus target\n * first, Escape then falls back to `escapeFocusTarget`, and both fall back\n * to the trigger. Mouse menu selection restores the trigger, while outside\n * clicks leave focus under browser control.\n */\n // Kept as a safety net for consumers that still wire Kendo Popup's `@close`;\n // restorePendingFocus() is idempotent once closePopup's own nextTick has already run.\n const handlePopupClose = () => {\n nextTick(restorePendingFocus);\n };\n\n return {\n /**\n * Sets the anchor activation state, controlling whether the popup menu\n * should respond to trigger interactions.\n */\n setAnchorActivation,\n /**\n * Handles Kendo Menu selection: records keyboard or mouse modality,\n * requests popup close, then runs the optional caller-owned action.\n */\n handleMenuSelect,\n /**\n * Toggles the action menu. When opening, focuses the first enabled Kendo\n * Menu item after Vue renders the popup.\n */\n handleTriggerClick,\n /**\n * Handles trigger keyboard input: Enter and Space toggle the menu; Escape\n * closes an open menu or focuses the configured target when already closed.\n */\n handleTriggerKeydown,\n /** Closes the open menu through the keyboard path when Escape is pressed inside it. */\n handleMenuEscape,\n /**\n * Restores focus after Kendo Popup closes: keyboard menu selection and\n * Escape prefer the configured focus target (Escape then falls back to\n * `escapeFocusTarget`), mouse selections return to the trigger, and\n * outside clicks do not move focus.\n */\n handlePopupClose,\n offset,\n };\n};\n"],"names":["DEFAULT_ESCAPE_FOCUS_CONTAINER_SELECTOR","resolveElement","target","componentElement","isManagedTrigger","element","triggerMode","warnMismatchedTrigger","findScrollableAncestor","parent","styledFallback","overflow","overflowX","overflowY","scrollsX","scrollsY","usePopupMenu","options","popupCloseReason","ref","menuItemSelector","anchorOptions","activationPointOptions","anchorRect","shallowRef","anchorActivation","anchorAlign","popupAlign","collision","popupRect","resolveTriggerElement","triggerEl","computed","anchorObserverTarget","getOffsetBounds","clip","toValue","rect","offset","bounds","corner","computeCollisionOffset","resolveConfiguredFocusTarget","explicitTarget","setAnchorActivation","trigger","activation","triggerElement","triggerRect","keyboardPosition","verticalPosition","y","resolveEscapeFallbackTarget","selector","focusConfiguredTargetOrTrigger","focusFirstEnabledMenuItem","pendingFocusTarget","pendingTrigger","suppressNextTriggerClick","restorePendingFocus","reason","closePopup","syncManagedTrigger","nextTick","watch","_","onCleanup","animationFrame","measure","scheduleMeasure","observer","resolvePopupContentElement","content","open","_prev","contentElement","useIntersectionObserver","entry","onClickOutside","previousTrigger","previousMenubar","demoteManagedTrigger","syncMenuLabel","menuElement","menubar","label","onUnmounted","handleTriggerClick","args","context","event","onAction"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const o=require("vue"),O=require("@vueuse/integrations/useFocusTrap"),g=require("@vueuse/core"),m={outsideClick:!1,returnFocusToTrigger:!1,focusTrapOptions:{returnFocusOnDeactivate:!1}},y={outsideClick:!1};function F(e){const r=o.shallowRef(null),T=[".k-animation-container .k-popup",".k-popup",".k-timepicker-popup",".k-menu-popup"],a=Array.isArray(e.popupSelector)?e.popupSelector:[e.popupSelector??T].flat(),k=n=>n?typeof e.initialFocus=="string"?n.querySelector(e.initialFocus)??n:typeof e.initialFocus=="function"?e.initialFocus(n)??n:n.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')??n:null,{activate:f,deactivate:p}=O.useFocusTrap(r,{escapeDeactivates:!1,clickOutsideDeactivates:!1,allowOutsideClick:!0,fallbackFocus:()=>r.value,initialFocus:()=>k(r.value),...e.focusTrapOptions??{}});let c=null,s=o.ref(null);const P=()=>{if(e.resolvePopupEl)return e.resolvePopupEl();const n=(t,i)=>{const l=Array.from(t.querySelectorAll(i));if(!l.length)return null;const d=l.filter(v=>v.offsetParent!==null||v.getClientRects().length>0);return d[d.length-1]??l[l.length-1]??null},u=e.triggerEl?.value?.closest?.(".k-animation-container")??document.body;for(const t of a){const i=n(u,t);if(i)return i}for(const t of a){const i=n(document,t);if(i)return i}return null};return e.outsideClick!==!1&&g.onClickOutside(r,n=>{e.isOpen.value&&(s.value="outside",e.onRequestClose?.("outside",n))},e.outsideClick),o.watch(()=>e.isOpen.value,n=>{n?(s.value=null,o.nextTick(()=>{const u=P();u&&(u.tabIndex<0&&(u.tabIndex=-1),r.value=u,setTimeout(()=>{try{f()}catch(t){console.warn("usePopupTrap: focus trap failed to activate",t)}},0),c||(c=t=>{t.key==="Escape"&&(s.value="escape",e.isOpen.value&&e.onRequestClose?.("escape",t))},document.addEventListener("keydown",c,!0)))})):(p(),c&&(document.removeEventListener("keydown",c,!0),c=null),r.value=null,s.value==="outside"&&o.nextTick(()=>{const u=()=>{const t=e.triggerEl?.value,i=t?.querySelector("input"),l=document.activeElement;l&&(l===i||t&&t.contains(l))&&(i??t)?.blur?.()};requestAnimationFrame(()=>setTimeout(u,0))}),e.returnFocusToTrigger!==!1&&s.value==="escape"&&e.triggerEl?.value&&o.nextTick(()=>{const u=()=>{const t=e.triggerEl?.value;if(!t)return;(t.querySelector("input")??t)?.focus?.()};requestAnimationFrame(()=>setTimeout(u,0))}))}),{popupRef:r,activate:f,deactivate:p,lastCloseReason:o.readonly(s),setPopupEl:n=>r.value=n}}exports.DIALOG_TRAP_OPTIONS=y;exports.POPUP_MENU_TRAP_OPTIONS=m;exports.usePopupTrap=F;
|
|
2
|
+
//# sourceMappingURL=usePopupTrap-DQudM6YA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopupTrap-DQudM6YA.cjs","sources":["../../src/trap/usePopupTrap.ts"],"sourcesContent":["import { nextTick, readonly, ref, shallowRef, watch, type Ref } from \"vue\";\nimport { useFocusTrap } from \"@vueuse/integrations/useFocusTrap\";\nimport { onClickOutside, type OnClickOutsideOptions } from \"@vueuse/core\";\n\nexport type CloseReason = \"escape\" | \"outside\";\nexport type PopupTrapOutsideClickOptions = Pick<\n OnClickOutsideOptions,\n \"ignore\"\n>;\nexport type InitialFocus =\n | string\n | ((root: HTMLElement) => HTMLElement | null | undefined);\n\n/**\n * Dismissal and focus-restoration options for pairing with `usePopupMenu`.\n *\n * `usePopupMenu` owns outside dismissal and menu-close focus restoration.\n * These settings disable the trap's outside listener and both competing\n * restoration paths in `usePopupTrap` and the underlying\n * `focus-trap` implementation. Spread this preset last so those integration\n * settings take precedence.\n */\nexport const POPUP_MENU_TRAP_OPTIONS = {\n outsideClick: false,\n returnFocusToTrigger: false,\n focusTrapOptions: {\n returnFocusOnDeactivate: false,\n },\n} as const;\n\nexport const DIALOG_TRAP_OPTIONS = {\n outsideClick: false,\n} as const;\n\nexport function usePopupTrap(opts: {\n isOpen: Ref<boolean>;\n onRequestClose?: (reason: CloseReason, ev?: Event) => void;\n popupSelector?: string | string[];\n triggerEl?: Ref<HTMLElement | null>;\n resolvePopupEl?: () => HTMLElement | null;\n initialFocus?: InitialFocus;\n outsideClick?: false | PopupTrapOutsideClickOptions;\n focusTrapOptions?: Parameters<typeof useFocusTrap>[1];\n returnFocusToTrigger?: boolean;\n}) {\n const popupRef = shallowRef<HTMLElement | null>(null);\n\n const defaultSelectors = [\n \".k-animation-container .k-popup\",\n \".k-popup\",\n \".k-timepicker-popup\",\n \".k-menu-popup\",\n ];\n\n const selectors = Array.isArray(opts.popupSelector)\n ? opts.popupSelector\n : [opts.popupSelector ?? defaultSelectors].flat();\n\n const pickInitialFocus = (root: HTMLElement) => {\n if (!root) return null as unknown as HTMLElement;\n if (typeof opts.initialFocus === \"string\") {\n const found = root.querySelector(opts.initialFocus) as HTMLElement | null;\n return found ?? root;\n }\n if (typeof opts.initialFocus === \"function\") {\n return (opts.initialFocus(root) as HTMLElement | null) ?? root;\n }\n const candidate = root.querySelector(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n return candidate ?? root;\n };\n\n const { activate, deactivate } = useFocusTrap(popupRef, {\n escapeDeactivates: false,\n clickOutsideDeactivates: false,\n // Without this, focus-trap's own default (false) preventDefault()s and\n // swallows every outside pointerdown/click while active - not just ones\n // that would close it - blocking interaction with anything else on the\n // page (e.g. another trigger in the same row) until the trap deactivates.\n allowOutsideClick: true,\n fallbackFocus: () => popupRef.value as HTMLElement,\n initialFocus: () => pickInitialFocus(popupRef.value as HTMLElement),\n ...(opts.focusTrapOptions ?? {}),\n });\n\n let escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n let lastCloseReason = ref<CloseReason | null>(null);\n\n const findPopup = (): HTMLElement | null => {\n if (opts.resolvePopupEl) return opts.resolvePopupEl();\n\n const pickLastVisible = (root: ParentNode, sel: string) => {\n const list = Array.from(root.querySelectorAll(sel)) as HTMLElement[];\n if (!list.length) return null as HTMLElement | null;\n const visible = list.filter(\n (el) => el.offsetParent !== null || el.getClientRects().length > 0,\n );\n return visible[visible.length - 1] ?? list[list.length - 1] ?? null;\n };\n\n const scopeRoot =\n opts.triggerEl?.value?.closest?.(\".k-animation-container\") ??\n document.body;\n\n for (const sel of selectors) {\n const el = pickLastVisible(scopeRoot, sel);\n if (el) return el;\n }\n\n for (const sel of selectors) {\n const el = pickLastVisible(document, sel);\n if (el) return el;\n }\n\n return null;\n };\n\n if (opts.outsideClick !== false) {\n onClickOutside(\n popupRef,\n (event) => {\n if (!opts.isOpen.value) return;\n lastCloseReason.value = \"outside\";\n opts.onRequestClose?.(\"outside\", event);\n },\n opts.outsideClick,\n );\n }\n\n watch(\n () => opts.isOpen.value,\n (open) => {\n if (open) {\n // Reset on open so the previous reason remains visible while closed\n lastCloseReason.value = null;\n nextTick(() => {\n const popup = findPopup();\n if (!popup) return;\n // Guarantees a valid fallback/initial focus target even when no\n // descendant is currently tabbable (e.g. Kendo Menu items only gain\n // a live tabindex via its own roving-tabindex JS on interaction) -\n // without this, focus-trap's activate() throws and silently no-ops,\n // leaving Tab to escape the popup entirely.\n if (popup.tabIndex < 0) popup.tabIndex = -1;\n popupRef.value = popup;\n setTimeout(() => {\n try {\n activate();\n } catch (error) {\n console.warn(\n \"usePopupTrap: focus trap failed to activate\",\n error,\n );\n }\n }, 0);\n\n if (!escapeHandler) {\n escapeHandler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n lastCloseReason.value = \"escape\";\n if (opts.isOpen.value) {\n opts.onRequestClose?.(\"escape\", e);\n }\n }\n };\n // Capture on document to catch Escape even when focus\n // stays on the trigger (e.g., TimeInput masked field).\n document.addEventListener(\"keydown\", escapeHandler, true);\n }\n });\n } else {\n deactivate();\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n popupRef.value = null;\n\n // On outside close, ensure trigger/input is not focused\n if (lastCloseReason.value === \"outside\") {\n nextTick(() => {\n const doBlur = () => {\n const root = opts.triggerEl?.value as HTMLElement | null;\n const input = root?.querySelector(\"input\") as HTMLElement | null;\n const active = document.activeElement as HTMLElement | null;\n // Only blur if focus is still on the trigger/input to avoid interfering\n if (\n active &&\n (active === input || (root && root.contains(active)))\n ) {\n (input ?? root)?.blur?.();\n }\n };\n requestAnimationFrame(() => setTimeout(doBlur, 0));\n });\n }\n\n if (\n opts.returnFocusToTrigger !== false &&\n lastCloseReason.value === \"escape\"\n ) {\n if (opts.triggerEl?.value) {\n // Schedule after Vue updates and after event/click propagation\n nextTick(() => {\n const doFocus = () => {\n const root = opts.triggerEl?.value as HTMLElement | null;\n if (!root) return;\n const input = root.querySelector(\"input\") as HTMLElement | null;\n const target = (input ?? root) as HTMLElement | null;\n target?.focus?.();\n };\n requestAnimationFrame(() => setTimeout(doFocus, 0));\n });\n }\n }\n }\n },\n );\n\n return {\n popupRef,\n activate,\n deactivate,\n lastCloseReason: readonly(lastCloseReason),\n setPopupEl: (el: HTMLElement | null) => (popupRef.value = el),\n };\n}\n"],"names":["POPUP_MENU_TRAP_OPTIONS","DIALOG_TRAP_OPTIONS","usePopupTrap","opts","popupRef","shallowRef","defaultSelectors","selectors","pickInitialFocus","root","activate","deactivate","useFocusTrap","escapeHandler","lastCloseReason","ref","findPopup","pickLastVisible","sel","list","visible","el","scopeRoot","onClickOutside","event","watch","open","nextTick","popup","error","e","doBlur","input","active","doFocus","readonly"],"mappings":"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"}
|