se-design 1.0.83-dev.5 → 1.0.83
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/dist/index19.js +158 -176
- package/dist/index19.js.map +1 -1
- package/dist/index72.js +46 -46
- package/dist/index72.js.map +1 -1
- package/package.json +1 -1
package/dist/index19.js
CHANGED
|
@@ -1,265 +1,250 @@
|
|
|
1
|
-
import B, { forwardRef as
|
|
1
|
+
import B, { forwardRef as we, useState as F, useRef as te, useEffect as M, useImperativeHandle as ge } from "react";
|
|
2
2
|
import he from "react-dom";
|
|
3
3
|
import { getA11yNameAttributes as be } from "./index81.js";
|
|
4
|
-
import { useDismissOnFocusOut as
|
|
5
|
-
import { getFirstFocusableElement as
|
|
4
|
+
import { useDismissOnFocusOut as ye } from "./index80.js";
|
|
5
|
+
import { getFirstFocusableElement as D, getLastFocusableElement as Ee, getFocusableElements as N, FOCUSABLE_WITH_ROLES_SELECTOR as ke } from "./index71.js";
|
|
6
6
|
import "./index72.js";
|
|
7
7
|
import { useRegisterPortalWithFocusTrap as Pe } from "./index208.js";
|
|
8
|
-
function
|
|
9
|
-
return
|
|
10
|
-
for (var
|
|
11
|
-
var m = arguments[
|
|
8
|
+
function T() {
|
|
9
|
+
return T = Object.assign ? Object.assign.bind() : function(b) {
|
|
10
|
+
for (var y = 1; y < arguments.length; y++) {
|
|
11
|
+
var m = arguments[y];
|
|
12
12
|
for (var h in m) ({}).hasOwnProperty.call(m, h) && (b[h] = m[h]);
|
|
13
13
|
}
|
|
14
14
|
return b;
|
|
15
|
-
},
|
|
15
|
+
}, T.apply(null, arguments);
|
|
16
16
|
}
|
|
17
|
-
const
|
|
17
|
+
const He = /* @__PURE__ */ we(({
|
|
18
18
|
className: b = "",
|
|
19
|
-
automationId:
|
|
19
|
+
automationId: y = "",
|
|
20
20
|
position: m = "bottom-center",
|
|
21
21
|
popoverContentAutomationId: h = "",
|
|
22
|
-
contentWidth:
|
|
22
|
+
contentWidth: R = "max",
|
|
23
23
|
renderPopoverContents: K,
|
|
24
|
-
renderPopoverSrcElement:
|
|
24
|
+
renderPopoverSrcElement: oe,
|
|
25
25
|
onPopoverToggle: z,
|
|
26
|
-
isPopoverOpen:
|
|
27
|
-
disabled:
|
|
26
|
+
isPopoverOpen: C,
|
|
27
|
+
disabled: E = !1,
|
|
28
28
|
isWithPortal: f = !1,
|
|
29
|
-
ariaLabel:
|
|
30
|
-
ariaLabelledBy:
|
|
31
|
-
sourceRole:
|
|
32
|
-
popupType:
|
|
33
|
-
popoverContentStyleProperty:
|
|
29
|
+
ariaLabel: ne,
|
|
30
|
+
ariaLabelledBy: re,
|
|
31
|
+
sourceRole: q = "button",
|
|
32
|
+
popupType: _ = "true",
|
|
33
|
+
popoverContentStyleProperty: $ = {
|
|
34
34
|
zIndex: 1e3,
|
|
35
35
|
borderColor: "var(--color-gray-200)",
|
|
36
36
|
color: "var(--color-gray-900)",
|
|
37
37
|
backgroundColor: "var(--color-white)"
|
|
38
38
|
},
|
|
39
|
-
disableClickToggle:
|
|
40
|
-
noBorder:
|
|
39
|
+
disableClickToggle: g = !1,
|
|
40
|
+
noBorder: se = !1,
|
|
41
41
|
disableAutoClose: v = !1,
|
|
42
|
-
focusFirstOnOpen:
|
|
43
|
-
...
|
|
42
|
+
focusFirstOnOpen: ie = !1,
|
|
43
|
+
...ce
|
|
44
44
|
}, ae) => {
|
|
45
|
-
const [
|
|
46
|
-
Pe(
|
|
45
|
+
const [i, p] = F(!1), [k, U] = F(m), [le, V] = F(!1), l = te(null), c = te(null);
|
|
46
|
+
Pe(c, f && i);
|
|
47
47
|
const ue = be({
|
|
48
|
-
ariaLabel:
|
|
49
|
-
ariaLabelledBy:
|
|
48
|
+
ariaLabel: ne,
|
|
49
|
+
ariaLabelledBy: re,
|
|
50
50
|
ariaDescribedBy: void 0
|
|
51
51
|
// Popover doesn't support describedBy yet
|
|
52
52
|
}), {
|
|
53
53
|
onBlurCapture: fe
|
|
54
|
-
} =
|
|
55
|
-
disabled: !
|
|
54
|
+
} = ye({
|
|
55
|
+
disabled: !i || v || f,
|
|
56
56
|
onFocusOut: () => p(!1),
|
|
57
57
|
closeOnEscape: !1
|
|
58
58
|
}), [L, A] = F({
|
|
59
59
|
top: 0,
|
|
60
60
|
left: 0,
|
|
61
61
|
srcWidth: 0
|
|
62
|
-
}), [pe,
|
|
63
|
-
|
|
62
|
+
}), [pe, W] = F(!1), P = () => {
|
|
63
|
+
g ? (D({
|
|
64
64
|
container: l.current,
|
|
65
65
|
includeRoles: !0
|
|
66
66
|
}) ?? l.current)?.focus() : l.current?.focus();
|
|
67
|
-
},
|
|
67
|
+
}, X = (e) => {
|
|
68
68
|
p(!1), e?.returnFocus !== !1 && requestAnimationFrame(() => {
|
|
69
69
|
e?.returnFocusTo ? (e.returnFocusTo instanceof HTMLElement ? e.returnFocusTo : e.returnFocusTo.current)?.focus() : P();
|
|
70
70
|
});
|
|
71
|
-
},
|
|
71
|
+
}, O = (e = "bottom-center") => {
|
|
72
72
|
if (!l.current) return {
|
|
73
73
|
top: 0,
|
|
74
74
|
left: 0,
|
|
75
75
|
srcWidth: 0
|
|
76
76
|
};
|
|
77
77
|
let o = e;
|
|
78
|
-
const t = l.current.getBoundingClientRect(),
|
|
79
|
-
let
|
|
78
|
+
const t = l.current.getBoundingClientRect(), r = window.innerWidth - document.documentElement.clientWidth, u = window.innerWidth - Math.max(r, 16), a = window.innerHeight;
|
|
79
|
+
let n = 0, s = 0;
|
|
80
80
|
switch (o) {
|
|
81
81
|
case "bottom-left":
|
|
82
|
-
|
|
82
|
+
n = t.bottom, s = t.left;
|
|
83
83
|
break;
|
|
84
84
|
case "bottom-right":
|
|
85
|
-
|
|
85
|
+
n = t.bottom, s = t.right - t.width * 0.5;
|
|
86
86
|
break;
|
|
87
87
|
case "bottom-center":
|
|
88
|
-
|
|
88
|
+
n = t.bottom, s = t.left + t.width / 2;
|
|
89
89
|
break;
|
|
90
90
|
case "top-left":
|
|
91
|
-
|
|
91
|
+
n = t.top - t.height * 1.9, s = t.left;
|
|
92
92
|
break;
|
|
93
93
|
case "top-right":
|
|
94
|
-
|
|
94
|
+
n = t.top - t.height * 1.9, s = t.right - t.width * 0.5;
|
|
95
95
|
break;
|
|
96
96
|
case "top-center":
|
|
97
|
-
|
|
97
|
+
n = t.top - t.height * 1.9, s = t.left + t.width / 2;
|
|
98
98
|
break;
|
|
99
99
|
default:
|
|
100
|
-
|
|
100
|
+
n = t.bottom, s = t.left;
|
|
101
101
|
break;
|
|
102
102
|
}
|
|
103
|
-
const d =
|
|
104
|
-
if ((o === "bottom-center" || o === "top-center") && (s = s - x / 2), s + x > u && (s = Math.max(0, u - x)), s < 0 && (s = 0),
|
|
105
|
-
const
|
|
106
|
-
|
|
103
|
+
const d = c.current?.getBoundingClientRect(), x = (R === "full" ? Math.max(t.width, d?.width || 0) : d?.width) || 0, w = d?.height || 0;
|
|
104
|
+
if ((o === "bottom-center" || o === "top-center") && (s = s - x / 2), s + x > u && (s = Math.max(0, u - x)), s < 0 && (s = 0), n + w > a) {
|
|
105
|
+
const ee = t.top, ve = a - t.bottom;
|
|
106
|
+
ee >= w || ee > ve ? (n = t.top - w, n < 48 && (n = 48)) : n = Math.max(48, a - w);
|
|
107
107
|
}
|
|
108
|
-
return
|
|
109
|
-
top: Math.round(
|
|
108
|
+
return n < 48 && (n = t.bottom, n + w > a && (n = Math.max(48, a - w))), {
|
|
109
|
+
top: Math.round(n),
|
|
110
110
|
left: Math.round(s),
|
|
111
111
|
srcWidth: t.width
|
|
112
112
|
};
|
|
113
113
|
};
|
|
114
114
|
M(() => {
|
|
115
|
-
if (z && z(
|
|
116
|
-
return v || document.body.addEventListener("click",
|
|
117
|
-
v || document.body.removeEventListener("click",
|
|
115
|
+
if (z && z(i), i && !f)
|
|
116
|
+
return v || document.body.addEventListener("click", j, !0), de(), () => {
|
|
117
|
+
v || document.body.removeEventListener("click", j, !0);
|
|
118
118
|
};
|
|
119
|
-
if (
|
|
120
|
-
v ? window.addEventListener("scroll",
|
|
121
|
-
const e = (
|
|
122
|
-
|
|
119
|
+
if (i && f) {
|
|
120
|
+
v ? window.addEventListener("scroll", G) : (document.body.addEventListener("click", I, !0), window.addEventListener("scroll", I)), window.addEventListener("resize", Y);
|
|
121
|
+
const e = (r) => {
|
|
122
|
+
r.key === "Escape" && c.current?.contains(document.activeElement) && (r.preventDefault(), r.stopPropagation(), p(!1), requestAnimationFrame(() => P()));
|
|
123
123
|
};
|
|
124
|
-
window.addEventListener("keydown", e, !0),
|
|
124
|
+
window.addEventListener("keydown", e, !0), H();
|
|
125
125
|
let o, t;
|
|
126
126
|
return o = requestAnimationFrame(() => {
|
|
127
127
|
t = requestAnimationFrame(() => {
|
|
128
|
-
const
|
|
129
|
-
|
|
128
|
+
const r = O(k);
|
|
129
|
+
r && A(r), W(!0);
|
|
130
130
|
});
|
|
131
131
|
}), () => {
|
|
132
|
-
v ? window.removeEventListener("scroll",
|
|
132
|
+
v ? window.removeEventListener("scroll", G) : (document.body.removeEventListener("click", I, !0), window.removeEventListener("scroll", I)), window.removeEventListener("resize", Y), window.removeEventListener("keydown", e, !0), cancelAnimationFrame(o), cancelAnimationFrame(t), W(!1);
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
-
}, [
|
|
136
|
-
const
|
|
135
|
+
}, [i, f, v]);
|
|
136
|
+
const H = () => {
|
|
137
137
|
if (!l.current) {
|
|
138
|
-
|
|
138
|
+
V(!1);
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
|
-
const e = l.current.getBoundingClientRect(), o = window.innerHeight, t = window.innerWidth,
|
|
142
|
-
|
|
141
|
+
const e = l.current.getBoundingClientRect(), o = window.innerHeight, t = window.innerWidth, r = e.top < o && e.bottom > 0 && e.left < t && e.right > 0;
|
|
142
|
+
V(r);
|
|
143
143
|
};
|
|
144
144
|
M(() => {
|
|
145
|
-
p(
|
|
146
|
-
}, [
|
|
147
|
-
|
|
148
|
-
const e =
|
|
149
|
-
container:
|
|
145
|
+
p(C ?? !1);
|
|
146
|
+
}, [C]), M(() => {
|
|
147
|
+
i && setTimeout(() => {
|
|
148
|
+
const e = D({
|
|
149
|
+
container: c.current,
|
|
150
150
|
includeRoles: !0
|
|
151
151
|
});
|
|
152
|
-
|
|
153
|
-
hasFocusable: !!e,
|
|
154
|
-
focusFirstOnOpen: O,
|
|
155
|
-
isSrcFocused: document.activeElement === l.current,
|
|
156
|
-
activeEl: document.activeElement?.className?.slice(0, 50),
|
|
157
|
-
willFocus: !!(e && (O || document.activeElement === l.current)),
|
|
158
|
-
isWithPortal: f,
|
|
159
|
-
hasPortalContent: !!i.current
|
|
160
|
-
}), e && (O || document.activeElement === l.current) && e.focus();
|
|
152
|
+
e && (ie || document.activeElement === l.current) && e.focus();
|
|
161
153
|
}, f ? 60 : 0);
|
|
162
|
-
}, [
|
|
154
|
+
}, [i]);
|
|
163
155
|
const de = () => {
|
|
164
|
-
if (!
|
|
165
|
-
const e =
|
|
166
|
-
e?.bottom > o ?
|
|
167
|
-
},
|
|
156
|
+
if (!c.current) return;
|
|
157
|
+
const e = c.current.getBoundingClientRect(), o = window.innerHeight;
|
|
158
|
+
e?.bottom > o ? U(m.includes("left") ? "top-left" : m.includes("right") ? "top-right" : "top-center") : e?.top < 0 && U(m.includes("left") ? "bottom-left" : m.includes("right") ? "bottom-right" : "bottom-center");
|
|
159
|
+
}, j = (e) => {
|
|
168
160
|
const o = l.current;
|
|
169
161
|
if (!o) return;
|
|
170
|
-
const t = e.target,
|
|
171
|
-
v || (!
|
|
162
|
+
const t = e.target, r = o.contains(t), u = c.current?.contains(t), n = t.closest?.(".se-design-popover-wrapper"), s = n && n !== o, d = c.current?.contains(n);
|
|
163
|
+
v || (!r && !u || s && !d) && p(!1);
|
|
172
164
|
}, I = (e) => {
|
|
173
|
-
const o = l.current, t =
|
|
165
|
+
const o = l.current, t = c.current;
|
|
174
166
|
if (!o) return;
|
|
175
|
-
if (
|
|
176
|
-
const
|
|
177
|
-
|
|
167
|
+
if (H(), e.type === "scroll" && i) {
|
|
168
|
+
const w = O(k);
|
|
169
|
+
w && A(w);
|
|
178
170
|
}
|
|
179
|
-
const
|
|
171
|
+
const r = e.target, u = o.contains(r), a = t?.contains(r), s = r.closest?.(".se-design-popover-wrapper"), d = s && s !== o, x = c.current?.contains(s);
|
|
180
172
|
v || (!u && !a || d && !x) && p(!1);
|
|
181
|
-
},
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
const e =
|
|
173
|
+
}, Y = () => {
|
|
174
|
+
if (i && f && l.current) {
|
|
175
|
+
H();
|
|
176
|
+
const e = O(k);
|
|
185
177
|
e && A(e);
|
|
186
178
|
}
|
|
187
|
-
},
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
const e =
|
|
179
|
+
}, G = () => {
|
|
180
|
+
if (i && f && l.current) {
|
|
181
|
+
H();
|
|
182
|
+
const e = O(k);
|
|
191
183
|
e && A(e);
|
|
192
184
|
}
|
|
193
|
-
},
|
|
194
|
-
const o =
|
|
185
|
+
}, S = (e = !1) => {
|
|
186
|
+
const o = i;
|
|
195
187
|
p((t) => !t), !o && e && setTimeout(() => {
|
|
196
188
|
if (e === "last") {
|
|
197
|
-
const t =
|
|
198
|
-
container:
|
|
189
|
+
const t = Ee({
|
|
190
|
+
container: c.current,
|
|
199
191
|
includeRoles: !0
|
|
200
192
|
});
|
|
201
193
|
t && t.focus();
|
|
202
194
|
} else {
|
|
203
|
-
const t =
|
|
204
|
-
container:
|
|
195
|
+
const t = D({
|
|
196
|
+
container: c.current,
|
|
205
197
|
includeRoles: !0
|
|
206
198
|
});
|
|
207
199
|
t && t.focus();
|
|
208
200
|
}
|
|
209
201
|
}, 50);
|
|
210
|
-
},
|
|
202
|
+
}, J = (e, o) => {
|
|
211
203
|
if (!o) return;
|
|
212
204
|
const t = document.activeElement;
|
|
213
205
|
if (t?.tagName === "INPUT" || t?.tagName === "TEXTAREA" || t?.tagName === "SELECT")
|
|
214
206
|
return;
|
|
215
|
-
const
|
|
216
|
-
const s = window.getComputedStyle(
|
|
217
|
-
return !
|
|
207
|
+
const r = Array.from(o.querySelectorAll(ke)).filter((n) => {
|
|
208
|
+
const s = window.getComputedStyle(n);
|
|
209
|
+
return !n.hasAttribute("disabled") && n.getAttribute("aria-disabled") !== "true" && s.display !== "none" && s.visibility !== "hidden" && (n.tabIndex >= 0 || n.hasAttribute("role"));
|
|
218
210
|
});
|
|
219
|
-
if (
|
|
220
|
-
const u =
|
|
211
|
+
if (r.length === 0) return;
|
|
212
|
+
const u = r.findIndex((n) => n === document.activeElement);
|
|
221
213
|
let a = -1;
|
|
222
|
-
e.key === "ArrowDown" ? (e.preventDefault(), e.stopPropagation(), a = u <
|
|
223
|
-
|
|
224
|
-
currentIndex: u,
|
|
225
|
-
nextIndex: a,
|
|
226
|
-
activeEl: document.activeElement?.tagName,
|
|
227
|
-
activeRole: document.activeElement?.getAttribute("role"),
|
|
228
|
-
firstEl: n[0]?.tagName + "." + n[0]?.className?.slice(0, 30)
|
|
229
|
-
}), a >= 0 && n[a] ? n[a].focus() : u === -1 && n.length > 0 && n[0].focus();
|
|
230
|
-
}, Z = (e) => {
|
|
214
|
+
e.key === "ArrowDown" ? (e.preventDefault(), e.stopPropagation(), a = u < r.length - 1 ? u + 1 : 0) : e.key === "ArrowUp" ? (e.preventDefault(), e.stopPropagation(), a = u > 0 ? u - 1 : r.length - 1) : e.key === "Home" ? (e.preventDefault(), e.stopPropagation(), a = 0) : e.key === "End" && (e.preventDefault(), e.stopPropagation(), a = r.length - 1), a >= 0 && r[a] ? r[a].focus() : u === -1 && r.length > 0 && r[0].focus();
|
|
215
|
+
}, Q = (e) => {
|
|
231
216
|
if (e.key === "Escape")
|
|
232
217
|
e.preventDefault(), e.stopPropagation(), p(!1), requestAnimationFrame(() => P());
|
|
233
218
|
else if (e.key === "Tab") {
|
|
234
|
-
if (
|
|
235
|
-
const o =
|
|
236
|
-
container:
|
|
219
|
+
if (_ === "dialog") {
|
|
220
|
+
const o = N({
|
|
221
|
+
container: c.current,
|
|
237
222
|
filterHidden: !0
|
|
238
|
-
}), t = o.indexOf(e.target),
|
|
223
|
+
}), t = o.indexOf(e.target), r = t === o.length - 1, u = t === 0 || t === -1;
|
|
239
224
|
if (e.shiftKey && u)
|
|
240
225
|
e.preventDefault(), p(!1), P();
|
|
241
|
-
else if (!e.shiftKey &&
|
|
226
|
+
else if (!e.shiftKey && r && (p(!1), f)) {
|
|
242
227
|
e.preventDefault();
|
|
243
|
-
const a = l.current,
|
|
228
|
+
const a = l.current, n = N({
|
|
244
229
|
container: document.body,
|
|
245
230
|
filterHidden: !0
|
|
246
|
-
}), s = a ?
|
|
231
|
+
}), s = a ? n.indexOf(a) : -1, d = n[s + 1];
|
|
247
232
|
d ? d.focus() : a?.focus();
|
|
248
233
|
}
|
|
249
234
|
} else if (p(!1), e.shiftKey)
|
|
250
235
|
e.preventDefault(), P();
|
|
251
236
|
else if (f) {
|
|
252
237
|
e.preventDefault();
|
|
253
|
-
const o = l.current, t =
|
|
238
|
+
const o = l.current, t = N({
|
|
254
239
|
container: document.body,
|
|
255
240
|
filterHidden: !0
|
|
256
|
-
}),
|
|
241
|
+
}), r = o ? t.indexOf(o) : -1, u = t[r + 1];
|
|
257
242
|
u ? u.focus() : o?.focus();
|
|
258
243
|
}
|
|
259
|
-
} else e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Home" || e.key === "End" ?
|
|
244
|
+
} else e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Home" || e.key === "End" ? J(e, c.current) : (e.key === "Enter" || e.key === " ") && e.stopPropagation();
|
|
260
245
|
};
|
|
261
|
-
|
|
262
|
-
togglePopover:
|
|
246
|
+
ge(ae, () => ({
|
|
247
|
+
togglePopover: S,
|
|
263
248
|
focusTrigger: () => l.current?.focus(),
|
|
264
249
|
element: l.current
|
|
265
250
|
}), []);
|
|
@@ -290,36 +275,33 @@ const Se = /* @__PURE__ */ ge(({
|
|
|
290
275
|
transform: "translateX(-50%)",
|
|
291
276
|
bottom: "100%"
|
|
292
277
|
}
|
|
293
|
-
},
|
|
294
|
-
return /* @__PURE__ */ B.createElement("div",
|
|
295
|
-
className: "se-design-popover-wrapper cursor-pointer relative focus-outline rounded-md" + (b.length > 0 ? ` ${b}` : "") + (
|
|
278
|
+
}, Z = se ? "" : "shadow-md border rounded-md";
|
|
279
|
+
return /* @__PURE__ */ B.createElement("div", T({
|
|
280
|
+
className: "se-design-popover-wrapper cursor-pointer relative focus-outline rounded-md" + (b.length > 0 ? ` ${b}` : "") + (i ? " open" : "") + (E ? " opacity-50 cursor-not-allowed pointer-events-none" : ""),
|
|
296
281
|
ref: l,
|
|
297
282
|
onClick: (e) => {
|
|
298
|
-
|
|
283
|
+
E || g || (e.stopPropagation(), S());
|
|
299
284
|
},
|
|
300
285
|
onKeyDown: (e) => {
|
|
301
|
-
if (!(
|
|
286
|
+
if (!(E || g))
|
|
302
287
|
if (e.key === "Enter" || e.key === " ") {
|
|
303
288
|
e.preventDefault(), e.stopPropagation();
|
|
304
|
-
const o =
|
|
305
|
-
|
|
306
|
-
const t =
|
|
307
|
-
container:
|
|
289
|
+
const o = i;
|
|
290
|
+
S(), o || setTimeout(() => {
|
|
291
|
+
const t = D({
|
|
292
|
+
container: c.current,
|
|
308
293
|
includeRoles: !0
|
|
309
294
|
});
|
|
310
295
|
t && t.focus();
|
|
311
296
|
}, f ? 60 : 0);
|
|
312
|
-
} else if (e.key === "Escape" &&
|
|
297
|
+
} else if (e.key === "Escape" && i)
|
|
313
298
|
e.preventDefault(), e.stopPropagation(), p(!1);
|
|
314
|
-
else if ((e.key === "ArrowDown" || e.key === "ArrowUp") &&
|
|
315
|
-
const o =
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
} else e.key === "ArrowDown" && !c && (e.preventDefault(), e.stopPropagation(), p(!0), setTimeout(() => {
|
|
321
|
-
const o = R({
|
|
322
|
-
container: i.current,
|
|
299
|
+
else if ((e.key === "ArrowDown" || e.key === "ArrowUp") && i) {
|
|
300
|
+
const o = c.current;
|
|
301
|
+
o && J(e, o);
|
|
302
|
+
} else e.key === "ArrowDown" && !i && (e.preventDefault(), e.stopPropagation(), p(!0), setTimeout(() => {
|
|
303
|
+
const o = D({
|
|
304
|
+
container: c.current,
|
|
323
305
|
includeRoles: !0
|
|
324
306
|
});
|
|
325
307
|
o && o.focus();
|
|
@@ -327,34 +309,34 @@ const Se = /* @__PURE__ */ ge(({
|
|
|
327
309
|
},
|
|
328
310
|
onBlurCapture: fe,
|
|
329
311
|
onBlur: (e) => {
|
|
330
|
-
if (!
|
|
331
|
-
const o = e.relatedTarget, t = !!(o && l.current?.contains(o)),
|
|
332
|
-
!t && !
|
|
312
|
+
if (!i || v || !f) return;
|
|
313
|
+
const o = e.relatedTarget, t = !!(o && l.current?.contains(o)), r = !!(o && c.current?.contains(o));
|
|
314
|
+
!t && !r && p(!1);
|
|
333
315
|
},
|
|
334
|
-
role:
|
|
335
|
-
"aria-expanded":
|
|
336
|
-
"aria-haspopup":
|
|
337
|
-
tabIndex:
|
|
338
|
-
"aria-disabled":
|
|
316
|
+
role: g ? "none" : q,
|
|
317
|
+
"aria-expanded": g ? void 0 : i ? "true" : "false",
|
|
318
|
+
"aria-haspopup": g ? void 0 : q === "combobox" ? "listbox" : _,
|
|
319
|
+
tabIndex: E || g ? -1 : 0,
|
|
320
|
+
"aria-disabled": g ? void 0 : E ? "true" : void 0
|
|
339
321
|
}, ue, {
|
|
340
|
-
"data-automation-id":
|
|
341
|
-
},
|
|
342
|
-
displayPopover:
|
|
343
|
-
togglePopover:
|
|
344
|
-
}),
|
|
345
|
-
className: `popover-content absolute ${
|
|
322
|
+
"data-automation-id": y
|
|
323
|
+
}, ce), oe({
|
|
324
|
+
displayPopover: i,
|
|
325
|
+
togglePopover: S
|
|
326
|
+
}), i && !f && /* @__PURE__ */ B.createElement("div", {
|
|
327
|
+
className: `popover-content absolute ${Z} z-[1000] ${R == "full" ? "w-full" : "w-max"}`,
|
|
346
328
|
style: {
|
|
347
|
-
|
|
329
|
+
...$,
|
|
348
330
|
...me[k]
|
|
349
331
|
},
|
|
350
332
|
onClick: (e) => e.stopPropagation(),
|
|
351
|
-
onKeyDown:
|
|
352
|
-
ref:
|
|
333
|
+
onKeyDown: Q,
|
|
334
|
+
ref: c,
|
|
353
335
|
"data-automation-id": h
|
|
354
336
|
}, K({
|
|
355
|
-
closePopoverCb:
|
|
356
|
-
})), f &&
|
|
357
|
-
className: `popover-content-with-portal z-[2002] ${
|
|
337
|
+
closePopoverCb: X
|
|
338
|
+
})), f && i && le && /* @__PURE__ */ he.createPortal(/* @__PURE__ */ B.createElement("div", {
|
|
339
|
+
className: `popover-content-with-portal z-[2002] ${Z} ${R == "full" ? "" : "w-max"}`,
|
|
358
340
|
style: {
|
|
359
341
|
position: "fixed",
|
|
360
342
|
top: L.top,
|
|
@@ -362,21 +344,21 @@ const Se = /* @__PURE__ */ ge(({
|
|
|
362
344
|
visibility: pe ? "visible" : "hidden",
|
|
363
345
|
maxHeight: "calc(100vh - 96px)",
|
|
364
346
|
overflowY: "hidden",
|
|
365
|
-
...
|
|
347
|
+
...R === "full" && L.srcWidth ? {
|
|
366
348
|
width: `${L.srcWidth}px`
|
|
367
349
|
} : {},
|
|
368
|
-
|
|
350
|
+
...$,
|
|
369
351
|
zIndex: 2002
|
|
370
352
|
},
|
|
371
353
|
onClick: (e) => e.stopPropagation(),
|
|
372
|
-
onKeyDown:
|
|
373
|
-
ref:
|
|
354
|
+
onKeyDown: Q,
|
|
355
|
+
ref: c,
|
|
374
356
|
"data-automation-id": h
|
|
375
357
|
}, K({
|
|
376
|
-
closePopoverCb:
|
|
358
|
+
closePopoverCb: X
|
|
377
359
|
})), document.body));
|
|
378
360
|
});
|
|
379
361
|
export {
|
|
380
|
-
|
|
362
|
+
He as Popover
|
|
381
363
|
};
|
|
382
364
|
//# sourceMappingURL=index19.js.map
|
package/dist/index19.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index19.js","sources":["../src/components/Popover/index.tsx"],"sourcesContent":["import React, { useState, useRef, ReactNode, useEffect, forwardRef, ForwardedRef, useImperativeHandle } from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n getA11yNameAttributes,\n useDismissOnFocusOut,\n FOCUSABLE_WITH_ROLES_SELECTOR,\n getFocusableElements,\n getFirstFocusableElement,\n getLastFocusableElement\n} from '../../utils/a11y';\nimport { useRegisterPortalWithFocusTrap } from '../../utils/a11y/FocusTrapPortalContext';\n\nexport interface PopoverHandle {\n togglePopover: (focusFirst?: boolean | 'last') => void;\n /** Focus the popover source/trigger element. */\n focusTrigger: () => void;\n /** The wrapper element that acts as the popover trigger. Stable DOM node with tabIndex=0. */\n element: HTMLElement | null;\n}\n\nexport interface PopoverProps {\n className?: string;\n automationId?: string;\n popoverContentAutomationId?: string;\n renderPopoverContents: (props: { closePopoverCb: (options?: { returnFocus?: boolean; returnFocusTo?: HTMLElement | React.RefObject<HTMLElement> }) => void }) => ReactNode;\n renderPopoverSrcElement: (props: { displayPopover: boolean; togglePopover: (focusFirst?: boolean | 'last') => void }) => ReactNode;\n position?: 'bottom-center' | 'bottom-left' | 'bottom-right' | 'top-center' | 'top-left' | 'top-right';\n onPopoverToggle?: (displayPopover: boolean) => void;\n contentWidth?: 'full' | 'max';\n isPopoverOpen?: boolean;\n disabled?: boolean;\n isWithPortal?: boolean;\n noBorder?: boolean;\n ariaLabel?: string;\n ariaLabelledBy?: string;\n sourceRole?: 'button' | 'combobox';\n popupType?: 'menu' | 'listbox' | 'dialog' | 'true';\n popoverContentStyleProperty?: React.CSSProperties;\n disableClickToggle?: boolean;\n disableAutoClose?: boolean;\n /** Focus the first focusable element when the popover opens via isPopoverOpen (external state). */\n focusFirstOnOpen?: boolean;\n}\n\nexport const Popover = forwardRef<PopoverHandle, PopoverProps>(\n (\n {\n className = '',\n automationId = '',\n position = 'bottom-center',\n popoverContentAutomationId = '',\n contentWidth = 'max',\n renderPopoverContents,\n renderPopoverSrcElement,\n onPopoverToggle,\n isPopoverOpen,\n disabled = false,\n isWithPortal = false,\n ariaLabel,\n ariaLabelledBy,\n sourceRole = 'button',\n popupType = 'true',\n popoverContentStyleProperty = {\n zIndex: 1000,\n borderColor: 'var(--color-gray-200)',\n color: 'var(--color-gray-900)',\n backgroundColor: 'var(--color-white)'\n },\n disableClickToggle = false,\n noBorder = false,\n disableAutoClose = false,\n focusFirstOnOpen = false,\n ...props\n },\n ref: ForwardedRef<PopoverHandle>\n ) => {\n const [displayPopover, setDisplayPopover] = useState(false);\n const [popoverPosition, setPopoverPosition] = useState(position);\n const [isSrcElementVisible, setIsSrcElementVisible] = useState(false);\n const srcElementRef = useRef<HTMLDivElement>(null);\n const popoverContentRef = useRef<HTMLDivElement>(null);\n\n // Register portal content with the nearest ancestor focus trap (e.g., Modal)\n // so the focus trap's safety net allows focus to move into portal content.\n useRegisterPortalWithFocusTrap(popoverContentRef, isWithPortal && displayPopover);\n\n // Compute accessible name/description props with correct precedence\n const accessibleNameProps = getA11yNameAttributes({\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy: undefined // Popover doesn't support describedBy yet\n });\n\n // Use shared focus-out dismissal for non-portal popovers.\n // Portal content lives outside the wrapper, so portal uses a dedicated onBlur fallback below.\n const { onBlurCapture: onDismissBlurCapture } = useDismissOnFocusOut<HTMLDivElement>({\n disabled: !displayPopover || disableAutoClose || isWithPortal,\n onFocusOut: () => setDisplayPopover(false),\n closeOnEscape: false\n });\n\n const [portalPosition, setPortalPosition] = useState({ top: 0, left: 0, srcWidth: 0 });\n const [isPortalMeasured, setIsPortalMeasured] = useState(false);\n\n // Focus the actual trigger element on popover close.\n // When disableClickToggle=true the wrapper is role=\"none\"/tabIndex=-1 — focus the\n // first focusable child (the inner Button/Icon) instead.\n const focusTriggerElement = () => {\n if (disableClickToggle) {\n const inner = getFirstFocusableElement({ container: srcElementRef.current, includeRoles: true });\n (inner ?? srcElementRef.current)?.focus();\n } else {\n srcElementRef.current?.focus();\n }\n };\n\n const closePopover = (options?: { returnFocus?: boolean; returnFocusTo?: HTMLElement | React.RefObject<HTMLElement> }) => {\n setDisplayPopover(false);\n if (options?.returnFocus !== false) {\n requestAnimationFrame(() => {\n if (options?.returnFocusTo) {\n const target = options.returnFocusTo instanceof HTMLElement\n ? options.returnFocusTo\n : options.returnFocusTo.current;\n target?.focus();\n } else {\n focusTriggerElement();\n }\n });\n }\n };\n\n const calculatePositionOfPopover = (position: string = 'bottom-center') => {\n if (!srcElementRef.current) return { top: 0, left: 0, srcWidth: 0 };\n\n let localPosition = position;\n\n const srcRect = srcElementRef.current.getBoundingClientRect();\n // Subtract scrollbar width so portal content doesn't render behind a scrollbar.\n // document.documentElement.clientWidth excludes any visible scrollbar;\n // fall back to a 16px buffer (max scrollbar width across OS/browsers) when\n // body overflow is hidden and the scrollbar belongs to a nested container.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const viewportWidth = window.innerWidth - Math.max(scrollbarWidth, 16);\n const viewportHeight = window.innerHeight;\n\n // Calculate position for portal\n let top = 0;\n let left = 0;\n\n switch (localPosition) {\n case 'bottom-left':\n top = srcRect.bottom;\n left = srcRect.left;\n break;\n case 'bottom-right':\n top = srcRect.bottom;\n left = srcRect.right - srcRect.width * 0.5;\n break;\n case 'bottom-center':\n top = srcRect.bottom;\n // Center the popover relative to the source element\n left = srcRect.left + srcRect.width / 2;\n break;\n case 'top-left':\n top = srcRect.top - srcRect.height * 1.9;\n left = srcRect.left;\n break;\n case 'top-right':\n top = srcRect.top - srcRect.height * 1.9;\n left = srcRect.right - srcRect.width * 0.5;\n break;\n case 'top-center':\n top = srcRect.top - srcRect.height * 1.9;\n // Center the popover relative to the source element\n left = srcRect.left + srcRect.width / 2;\n break;\n default:\n top = srcRect.bottom;\n left = srcRect.left;\n break;\n }\n\n // Get popover dimensions if available\n const popoverRect = popoverContentRef.current?.getBoundingClientRect();\n // When contentWidth='full', the panel will be sized to srcRect.width after measurement.\n // Use srcRect.width directly so centering and viewport clamping use the correct final width.\n const popoverWidth = (contentWidth === 'full' ? Math.max(srcRect.width, popoverRect?.width || 0) : popoverRect?.width) || 0;\n const popoverHeight = popoverRect?.height || 0;\n\n // Adjust center positions to account for popover width\n if (localPosition === 'bottom-center' || localPosition === 'top-center') {\n // Center the popover by subtracting half its width from the source center\n left = left - popoverWidth / 2;\n }\n\n // Adjust position to keep popover within viewport bounds\n // Horizontal adjustments\n if (left + popoverWidth > viewportWidth) {\n // Popover extends beyond right edge, shift it left\n left = Math.max(0, viewportWidth - popoverWidth);\n }\n if (left < 0) {\n // Popover extends beyond left edge, shift it right\n left = 0;\n }\n\n // Vertical adjustments\n if (top + popoverHeight > viewportHeight) {\n // Popover extends beyond bottom edge\n // Try to position it above the source element\n const spaceAbove = srcRect.top;\n const spaceBelow = viewportHeight - srcRect.bottom;\n\n if (spaceAbove >= popoverHeight || spaceAbove > spaceBelow) {\n // Position above if there's enough space or more space above\n top = srcRect.top - popoverHeight;\n // Ensure it doesn't go above the topbar (48px fixed header)\n if (top < 48) {\n top = 48;\n }\n } else {\n // Keep at bottom but adjust to fit within viewport\n top = Math.max(48, viewportHeight - popoverHeight);\n }\n }\n if (top < 48) {\n // Popover extends beyond top edge, position it below the source element\n top = srcRect.bottom;\n // Ensure it doesn't go below viewport\n if (top + popoverHeight > viewportHeight) {\n top = Math.max(48, viewportHeight - popoverHeight);\n }\n }\n\n return { top: Math.round(top), left: Math.round(left), srcWidth: srcRect.width };\n };\n\n useEffect(() => {\n if (onPopoverToggle) {\n onPopoverToggle(displayPopover);\n }\n\n if (displayPopover && !isWithPortal) {\n // Add click listener for auto-close behavior only if not disabled\n if (!disableAutoClose) {\n document.body.addEventListener('click', clickListener, true);\n }\n checkPopoverPosition();\n return () => {\n if (!disableAutoClose) {\n document.body.removeEventListener('click', clickListener, true);\n }\n };\n } else if (displayPopover && isWithPortal) {\n // Add click/scroll listeners for auto-close behavior only if not disabled\n if (!disableAutoClose) {\n document.body.addEventListener('click', clickAndScrollListenerWithPortal, true);\n window.addEventListener('scroll', clickAndScrollListenerWithPortal);\n } else {\n // When disableAutoClose is true, still listen to scroll for repositioning\n window.addEventListener('scroll', scrollListenerForRepositioning);\n }\n // Always add resize listener for repositioning\n window.addEventListener('resize', resizeListenerWithPortal);\n\n // Escape on window capture phase — must fire before document-capture listeners\n // (e.g. useDismissOnEscape in Modal) so Escape closes the portal Dropdown without\n // also dismissing the modal behind it.\n const escapeHandler = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n if (!popoverContentRef.current?.contains(document.activeElement)) return;\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n requestAnimationFrame(() => focusTriggerElement());\n };\n window.addEventListener('keydown', escapeHandler, true);\n\n // Trigger source visibility check immediately\n checkSourceVisibility();\n\n // Use double-rAF to measure portal after browser has completed layout,\n // guaranteeing real dimensions are available for flip/clamp calculations.\n // Portal is hidden via visibility:hidden until this completes (no flash).\n let rafId1: number;\n let rafId2: number;\n rafId1 = requestAnimationFrame(() => {\n rafId2 = requestAnimationFrame(() => {\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n setIsPortalMeasured(true);\n });\n });\n\n return () => {\n if (!disableAutoClose) {\n document.body.removeEventListener('click', clickAndScrollListenerWithPortal, true);\n window.removeEventListener('scroll', clickAndScrollListenerWithPortal);\n } else {\n window.removeEventListener('scroll', scrollListenerForRepositioning);\n }\n window.removeEventListener('resize', resizeListenerWithPortal);\n window.removeEventListener('keydown', escapeHandler, true);\n cancelAnimationFrame(rafId1);\n cancelAnimationFrame(rafId2);\n setIsPortalMeasured(false);\n };\n }\n }, [displayPopover, isWithPortal, disableAutoClose]);\n\n const checkSourceVisibility = () => {\n if (!srcElementRef.current) {\n setIsSrcElementVisible(false);\n return;\n }\n\n const rec = srcElementRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n\n const isVisible = rec.top < viewportHeight && rec.bottom > 0 && rec.left < viewportWidth && rec.right > 0;\n\n setIsSrcElementVisible(isVisible);\n };\n\n useEffect(() => {\n setDisplayPopover(isPopoverOpen ?? false);\n }, [isPopoverOpen]);\n\n useEffect(() => {\n // Focus first focusable element when popover opens.\n // For portal, delay longer so isSrcElementVisible can be set and portal can mount first.\n if (displayPopover) {\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n console.log('[Popover open] focus check:', {\n hasFocusable: !!firstFocusable,\n focusFirstOnOpen,\n isSrcFocused: document.activeElement === srcElementRef.current,\n activeEl: (document.activeElement as HTMLElement)?.className?.slice(0, 50),\n willFocus: !!(firstFocusable && (focusFirstOnOpen || document.activeElement === srcElementRef.current)),\n isWithPortal,\n hasPortalContent: !!popoverContentRef.current,\n });\n if (firstFocusable && (focusFirstOnOpen || document.activeElement === srcElementRef.current)) {\n firstFocusable.focus();\n }\n }, isWithPortal ? 60 : 0);\n }\n }, [displayPopover]);\n\n //Function to check popover position\n const checkPopoverPosition = () => {\n if (!popoverContentRef.current) return;\n\n const popoverRect = popoverContentRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n\n if (popoverRect?.bottom > viewportHeight) {\n setPopoverPosition(\n position.includes('left') ? 'top-left' : position.includes('right') ? 'top-right' : 'top-center'\n );\n } else if (popoverRect?.top < 0) {\n // If popover extends beyond top of viewport, switch to bottom position\n setPopoverPosition(\n position.includes('left') ? 'bottom-left' : position.includes('right') ? 'bottom-right' : 'bottom-center'\n );\n }\n };\n\n const clickListener = (event: MouseEvent) => {\n const currentDropRef = srcElementRef.current;\n if (!currentDropRef) return;\n\n const target = event.target as Node;\n const isSourcePopover = currentDropRef.contains(target);\n const isPopoverContent = popoverContentRef.current?.contains(target);\n\n // Check if click is on another popover's source element\n const clickedElement = target as HTMLElement;\n const closestPopoverWrapper = clickedElement.closest?.('.se-design-popover-wrapper');\n const isAnotherPopoverSource = closestPopoverWrapper && closestPopoverWrapper !== currentDropRef;\n\n // check if the clicked popover is a nesteded child of the current popover content\n const isNestedPopover = popoverContentRef.current?.contains(closestPopoverWrapper as Node);\n\n // if clicked source is parent or the popover-content, do not toggle dropdown.\n // Also close if clicking on another popover's source element\n if (disableAutoClose) return;\n if ((!isSourcePopover && !isPopoverContent) || (isAnotherPopoverSource && !isNestedPopover)) {\n setDisplayPopover(false);\n }\n };\n\n const clickAndScrollListenerWithPortal = (event: Event) => {\n const currentDropRef = srcElementRef.current;\n const currentPopoverRef = popoverContentRef.current;\n if (!currentDropRef) return;\n checkSourceVisibility();\n\n // Recalculate position on scroll\n if (event.type === 'scroll' && displayPopover) {\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n\n const target = event.target as Node;\n const isSourcePopover = currentDropRef.contains(target);\n const isPopoverContent = currentPopoverRef?.contains(target);\n\n // Check if click is on another popover's source element\n const clickedElement = target as HTMLElement;\n const closestPopoverWrapper = clickedElement.closest?.('.se-design-popover-wrapper');\n const isAnotherPopoverSource = closestPopoverWrapper && closestPopoverWrapper !== currentDropRef;\n\n // check if the clicked popover is a nesteded child of the current popover content\n const isNestedPopover = popoverContentRef.current?.contains(closestPopoverWrapper as Node);\n\n if (disableAutoClose) return;\n // if clicked source is parent or the popover-content, do not toggle dropdown.\n // Also close if clicking on another popover's source element\n if ((!isSourcePopover && !isPopoverContent) || (isAnotherPopoverSource && !isNestedPopover)) {\n setDisplayPopover(false);\n }\n };\n\n const resizeListenerWithPortal = () => {\n if (displayPopover && isWithPortal && srcElementRef.current) {\n checkSourceVisibility();\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n };\n\n const scrollListenerForRepositioning = () => {\n if (displayPopover && isWithPortal && srcElementRef.current) {\n checkSourceVisibility();\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n };\n\n const togglePopover = (focusFirst: boolean | 'last' = false) => {\n const wasOpen = displayPopover;\n setDisplayPopover((prev) => !prev);\n if (!wasOpen && focusFirst) {\n setTimeout(() => {\n if (focusFirst === 'last') {\n const lastFocusable = getLastFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (lastFocusable) lastFocusable.focus();\n } else {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }\n }, 50);\n }\n };\n\n const handleArrowKeyNavigation = (e: React.KeyboardEvent, container: HTMLDivElement | null) => {\n if (!container) return;\n\n // Native form controls own their arrow key behavior — don't intercept.\n // (e.g. a SearchBox inside a Popover should keep focus while typing/navigating)\n const activeEl = document.activeElement;\n if (activeEl?.tagName === 'INPUT' || activeEl?.tagName === 'TEXTAREA' || activeEl?.tagName === 'SELECT') {\n return;\n }\n\n const focusableElements = Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_WITH_ROLES_SELECTOR)).filter((el) => {\n // Filter out disabled and hidden elements.\n // Note: check aria-disabled VALUE not just presence — React always writes aria-disabled=\"false\"\n // on elements like MenuItem even when not disabled, so hasAttribute would wrongly exclude them.\n const style = window.getComputedStyle(el);\n return (\n !el.hasAttribute('disabled') &&\n el.getAttribute('aria-disabled') !== 'true' &&\n style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n (el.tabIndex >= 0 || el.hasAttribute('role'))\n );\n });\n\n if (focusableElements.length === 0) return;\n\n const currentIndex = focusableElements.findIndex((el) => el === document.activeElement);\n let nextIndex = -1;\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = currentIndex < focusableElements.length - 1 ? currentIndex + 1 : 0;\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : focusableElements.length - 1;\n } else if (e.key === 'Home') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = 0;\n } else if (e.key === 'End') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = focusableElements.length - 1;\n }\n\n console.log('[Popover] arrowNav:', {\n focusableCount: focusableElements.length,\n currentIndex,\n nextIndex,\n activeEl: document.activeElement?.tagName,\n activeRole: document.activeElement?.getAttribute('role'),\n firstEl: focusableElements[0]?.tagName + '.' + focusableElements[0]?.className?.slice(0, 30),\n });\n if (nextIndex >= 0 && focusableElements[nextIndex]) {\n focusableElements[nextIndex].focus();\n } else if (currentIndex === -1 && focusableElements.length > 0) {\n // If no element is currently focused, focus the first one\n focusableElements[0].focus();\n }\n };\n\n const handlePopoverContentKeyDown = (e: React.KeyboardEvent) => {\n // Allow Escape key to close popover when focus is on content\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n // Defer focus restoration to after React re-renders and portal unmounts.\n // Synchronous focus() during the event can be displaced by the portal\n // teardown in some browsers, especially when isWithPortal=true.\n requestAnimationFrame(() => focusTriggerElement());\n } else if (e.key === 'Tab') {\n if (popupType === 'dialog') {\n // Dialog popovers: let Tab flow naturally within the content.\n // Only close when focus would actually leave the popover.\n const focusables = getFocusableElements({ container: popoverContentRef.current, filterHidden: true });\n const currentIndex = focusables.indexOf(e.target as HTMLElement);\n const isOnLast = currentIndex === focusables.length - 1;\n const isOnFirst = currentIndex === 0 || currentIndex === -1;\n\n if (e.shiftKey && isOnFirst) {\n // Shift+Tab past first element — close and return focus to trigger\n e.preventDefault();\n setDisplayPopover(false);\n focusTriggerElement();\n } else if (!e.shiftKey && isOnLast) {\n // Tab past last element — close popover\n setDisplayPopover(false);\n if (isWithPortal) {\n e.preventDefault();\n const srcEl = srcElementRef.current;\n const allFocusables = getFocusableElements({ container: document.body, filterHidden: true });\n const idx = srcEl ? allFocusables.indexOf(srcEl) : -1;\n const next = allFocusables[idx + 1];\n if (next) next.focus();\n else srcEl?.focus();\n }\n }\n // Otherwise: let browser handle Tab naturally within the popover content\n } else {\n // Non-dialog: close popover when Tab exits the menu\n setDisplayPopover(false);\n if (e.shiftKey) {\n // Shift+Tab: prevent default (would go to wrapper) and focus trigger instead\n e.preventDefault();\n focusTriggerElement();\n } else if (isWithPortal) {\n // Portal forward Tab: portal content is at document.body so natural Tab order\n // skips back to the top of the page. Manually advance to the next focusable\n // element after the trigger in the main document instead.\n e.preventDefault();\n const srcEl = srcElementRef.current;\n const focusables = getFocusableElements({ container: document.body, filterHidden: true });\n const idx = srcEl ? focusables.indexOf(srcEl) : -1;\n const next = focusables[idx + 1];\n if (next) next.focus();\n else srcEl?.focus();\n }\n // Non-portal forward Tab: do NOT preventDefault — browser moves focus to next element naturally\n }\n } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End') {\n // Handle arrow key navigation for focusable elements inside popover\n handleArrowKeyNavigation(e, popoverContentRef.current);\n } else if (e.key === 'Enter' || e.key === ' ') {\n // Prevent Enter/Space from bubbling to wrapper (mirrors click stopPropagation)\n e.stopPropagation();\n }\n };\n\n useImperativeHandle(ref, () => ({ togglePopover, focusTrigger: () => srcElementRef.current?.focus(), element: srcElementRef.current }), []);\n\n const popoverContentStyle = {\n 'bottom-left': { left: '0', top: '100%' },\n 'bottom-right': { right: '0', top: '100%' },\n 'bottom-center': { left: '50%', transform: 'translateX(-50%)', top: '100%' },\n 'top-left': { left: '0', bottom: '100%' },\n 'top-right': { right: '0', bottom: '100%' },\n 'top-center': { left: '50%', transform: 'translateX(-50%)', bottom: '100%' }\n };\n const popoverContentClasses = noBorder ? '' : 'shadow-md border rounded-md';\n\n return (\n <div\n className={\n 'se-design-popover-wrapper cursor-pointer relative focus-outline rounded-md' +\n (className.length > 0 ? ` ${className}` : '') +\n (displayPopover ? ' open' : '') +\n (disabled ? ' opacity-50 cursor-not-allowed pointer-events-none' : '')\n }\n ref={srcElementRef}\n onClick={(e) => {\n if (disabled || disableClickToggle) return;\n e.stopPropagation();\n togglePopover();\n }}\n onKeyDown={(e) => {\n if (disabled || disableClickToggle) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n const wasOpen = displayPopover;\n togglePopover();\n // Focus first focusable element when opening.\n // Portal content isn't mounted until isSrcElementVisible resolves (via setTimeout 0),\n // so use a longer delay for portal to ensure popoverContentRef.current is set.\n if (!wasOpen) {\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }, isWithPortal ? 60 : 0);\n }\n } else if (e.key === 'Escape' && displayPopover) {\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && displayPopover) {\n // Handle arrow keys when popover is open\n const currentRef = popoverContentRef.current;\n console.log('[Popover] arrow on wrapper:', { key: e.key, hasRef: !!currentRef });\n if (currentRef) {\n handleArrowKeyNavigation(e, currentRef);\n }\n } else if (e.key === 'ArrowDown' && !displayPopover) {\n // Open popover and focus first item when ArrowDown is pressed\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(true);\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }, 0);\n }\n }}\n onBlurCapture={onDismissBlurCapture}\n onBlur={(e) => {\n // Portal content is rendered outside wrapper, so keep explicit check for that case.\n if (!displayPopover || disableAutoClose || !isWithPortal) return;\n\n const nextFocused = e.relatedTarget as Node | null;\n const isFocusInSource = !!(nextFocused && srcElementRef.current?.contains(nextFocused));\n const isFocusInPopover = !!(nextFocused && popoverContentRef.current?.contains(nextFocused));\n\n // Close only when focus leaves both source and portal content.\n if (!isFocusInSource && !isFocusInPopover) {\n setDisplayPopover(false);\n }\n }}\n role={disableClickToggle ? 'none' : sourceRole}\n aria-expanded={disableClickToggle ? undefined : displayPopover ? 'true' : 'false'}\n aria-haspopup={disableClickToggle ? undefined : sourceRole === 'combobox' ? 'listbox' : popupType}\n tabIndex={disabled || disableClickToggle ? -1 : 0}\n aria-disabled={disableClickToggle ? undefined : disabled ? 'true' : undefined}\n {...accessibleNameProps}\n data-automation-id={automationId}\n {...props}\n >\n {renderPopoverSrcElement({ displayPopover, togglePopover })}\n\n {displayPopover && !isWithPortal && (\n <div\n className={`popover-content absolute ${popoverContentClasses} z-[1000] ${\n contentWidth == 'full' ? 'w-full' : 'w-max'\n }`}\n style={{\n ...popoverContentStyleProperty,\n ...popoverContentStyle[popoverPosition]\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handlePopoverContentKeyDown}\n ref={popoverContentRef}\n data-automation-id={popoverContentAutomationId}\n >\n {renderPopoverContents({ closePopoverCb: closePopover })}\n </div>\n )}\n {isWithPortal &&\n displayPopover &&\n isSrcElementVisible &&\n ReactDOM.createPortal(\n <div\n className={`popover-content-with-portal z-[2002] ${popoverContentClasses} ${\n contentWidth == 'full' ? '' : 'w-max'\n }`}\n style={{\n position: 'fixed',\n top: portalPosition.top,\n left: portalPosition.left,\n visibility: isPortalMeasured ? 'visible' : 'hidden',\n maxHeight: 'calc(100vh - 96px)',\n overflowY: 'hidden',\n ...(contentWidth === 'full' && portalPosition.srcWidth\n ? { width: `${portalPosition.srcWidth}px` }\n : {}),\n ...popoverContentStyleProperty,\n zIndex: 2002\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handlePopoverContentKeyDown}\n ref={popoverContentRef}\n data-automation-id={popoverContentAutomationId}\n >\n {renderPopoverContents({ closePopoverCb: closePopover })}\n </div>,\n document.body\n )}\n </div>\n );\n }\n);\n"],"names":["Popover","className","automationId","position","popoverContentAutomationId","contentWidth","renderPopoverContents","renderPopoverSrcElement","onPopoverToggle","isPopoverOpen","disabled","isWithPortal","ariaLabel","ariaLabelledBy","sourceRole","popupType","popoverContentStyleProperty","zIndex","borderColor","color","backgroundColor","disableClickToggle","noBorder","disableAutoClose","focusFirstOnOpen","props","ref","displayPopover","setDisplayPopover","useState","popoverPosition","setPopoverPosition","isSrcElementVisible","setIsSrcElementVisible","srcElementRef","useRef","popoverContentRef","useRegisterPortalWithFocusTrap","accessibleNameProps","getA11yNameAttributes","ariaDescribedBy","undefined","onBlurCapture","onDismissBlurCapture","useDismissOnFocusOut","onFocusOut","closeOnEscape","portalPosition","setPortalPosition","top","left","srcWidth","isPortalMeasured","setIsPortalMeasured","focusTriggerElement","getFirstFocusableElement","container","current","includeRoles","focus","closePopover","options","returnFocus","requestAnimationFrame","returnFocusTo","HTMLElement","calculatePositionOfPopover","localPosition","srcRect","getBoundingClientRect","scrollbarWidth","window","innerWidth","document","documentElement","clientWidth","viewportWidth","Math","max","viewportHeight","innerHeight","bottom","right","width","height","popoverRect","popoverWidth","popoverHeight","spaceAbove","spaceBelow","round","useEffect","body","addEventListener","clickListener","checkPopoverPosition","removeEventListener","scrollListenerForRepositioning","clickAndScrollListenerWithPortal","resizeListenerWithPortal","escapeHandler","e","key","contains","activeElement","preventDefault","stopPropagation","checkSourceVisibility","rafId1","rafId2","cancelAnimationFrame","rec","isVisible","setTimeout","firstFocusable","console","log","hasFocusable","isSrcFocused","activeEl","slice","willFocus","hasPortalContent","includes","event","currentDropRef","target","isSourcePopover","isPopoverContent","closestPopoverWrapper","closest","isAnotherPopoverSource","isNestedPopover","currentPopoverRef","type","togglePopover","focusFirst","wasOpen","prev","lastFocusable","getLastFocusableElement","handleArrowKeyNavigation","tagName","focusableElements","Array","from","querySelectorAll","FOCUSABLE_WITH_ROLES_SELECTOR","filter","el","style","getComputedStyle","hasAttribute","getAttribute","display","visibility","tabIndex","length","currentIndex","findIndex","nextIndex","focusableCount","activeRole","firstEl","handlePopoverContentKeyDown","focusables","getFocusableElements","filterHidden","indexOf","isOnLast","isOnFirst","shiftKey","srcEl","allFocusables","idx","next","useImperativeHandle","focusTrigger","element","popoverContentStyle","transform","popoverContentClasses","React","createElement","_extends","onClick","onKeyDown","currentRef","hasRef","onBlur","nextFocused","relatedTarget","isFocusInSource","isFocusInPopover","role","closePopoverCb","ReactDOM","createPortal","maxHeight","overflowY"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index19.js","sources":["../src/components/Popover/index.tsx"],"sourcesContent":["import React, { useState, useRef, ReactNode, useEffect, forwardRef, ForwardedRef, useImperativeHandle } from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n getA11yNameAttributes,\n useDismissOnFocusOut,\n FOCUSABLE_WITH_ROLES_SELECTOR,\n getFocusableElements,\n getFirstFocusableElement,\n getLastFocusableElement\n} from '../../utils/a11y';\nimport { useRegisterPortalWithFocusTrap } from '../../utils/a11y/FocusTrapPortalContext';\n\nexport interface PopoverHandle {\n togglePopover: (focusFirst?: boolean | 'last') => void;\n /** Focus the popover source/trigger element. */\n focusTrigger: () => void;\n /** The wrapper element that acts as the popover trigger. Stable DOM node with tabIndex=0. */\n element: HTMLElement | null;\n}\n\nexport interface PopoverProps {\n className?: string;\n automationId?: string;\n popoverContentAutomationId?: string;\n renderPopoverContents: (props: { closePopoverCb: (options?: { returnFocus?: boolean; returnFocusTo?: HTMLElement | React.RefObject<HTMLElement> }) => void }) => ReactNode;\n renderPopoverSrcElement: (props: { displayPopover: boolean; togglePopover: (focusFirst?: boolean | 'last') => void }) => ReactNode;\n position?: 'bottom-center' | 'bottom-left' | 'bottom-right' | 'top-center' | 'top-left' | 'top-right';\n onPopoverToggle?: (displayPopover: boolean) => void;\n contentWidth?: 'full' | 'max';\n isPopoverOpen?: boolean;\n disabled?: boolean;\n isWithPortal?: boolean;\n noBorder?: boolean;\n ariaLabel?: string;\n ariaLabelledBy?: string;\n sourceRole?: 'button' | 'combobox';\n popupType?: 'menu' | 'listbox' | 'dialog' | 'true';\n popoverContentStyleProperty?: React.CSSProperties;\n disableClickToggle?: boolean;\n disableAutoClose?: boolean;\n /** Focus the first focusable element when the popover opens via isPopoverOpen (external state). */\n focusFirstOnOpen?: boolean;\n}\n\nexport const Popover = forwardRef<PopoverHandle, PopoverProps>(\n (\n {\n className = '',\n automationId = '',\n position = 'bottom-center',\n popoverContentAutomationId = '',\n contentWidth = 'max',\n renderPopoverContents,\n renderPopoverSrcElement,\n onPopoverToggle,\n isPopoverOpen,\n disabled = false,\n isWithPortal = false,\n ariaLabel,\n ariaLabelledBy,\n sourceRole = 'button',\n popupType = 'true',\n popoverContentStyleProperty = {\n zIndex: 1000,\n borderColor: 'var(--color-gray-200)',\n color: 'var(--color-gray-900)',\n backgroundColor: 'var(--color-white)'\n },\n disableClickToggle = false,\n noBorder = false,\n disableAutoClose = false,\n focusFirstOnOpen = false,\n ...props\n },\n ref: ForwardedRef<PopoverHandle>\n ) => {\n const [displayPopover, setDisplayPopover] = useState(false);\n const [popoverPosition, setPopoverPosition] = useState(position);\n const [isSrcElementVisible, setIsSrcElementVisible] = useState(false);\n const srcElementRef = useRef<HTMLDivElement>(null);\n const popoverContentRef = useRef<HTMLDivElement>(null);\n\n // Register portal content with the nearest ancestor focus trap (e.g., Modal)\n // so the focus trap's safety net allows focus to move into portal content.\n useRegisterPortalWithFocusTrap(popoverContentRef, isWithPortal && displayPopover);\n\n // Compute accessible name/description props with correct precedence\n const accessibleNameProps = getA11yNameAttributes({\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy: undefined // Popover doesn't support describedBy yet\n });\n\n // Use shared focus-out dismissal for non-portal popovers.\n // Portal content lives outside the wrapper, so portal uses a dedicated onBlur fallback below.\n const { onBlurCapture: onDismissBlurCapture } = useDismissOnFocusOut<HTMLDivElement>({\n disabled: !displayPopover || disableAutoClose || isWithPortal,\n onFocusOut: () => setDisplayPopover(false),\n closeOnEscape: false\n });\n\n const [portalPosition, setPortalPosition] = useState({ top: 0, left: 0, srcWidth: 0 });\n const [isPortalMeasured, setIsPortalMeasured] = useState(false);\n\n // Focus the actual trigger element on popover close.\n // When disableClickToggle=true the wrapper is role=\"none\"/tabIndex=-1 — focus the\n // first focusable child (the inner Button/Icon) instead.\n const focusTriggerElement = () => {\n if (disableClickToggle) {\n const inner = getFirstFocusableElement({ container: srcElementRef.current, includeRoles: true });\n (inner ?? srcElementRef.current)?.focus();\n } else {\n srcElementRef.current?.focus();\n }\n };\n\n const closePopover = (options?: { returnFocus?: boolean; returnFocusTo?: HTMLElement | React.RefObject<HTMLElement> }) => {\n setDisplayPopover(false);\n if (options?.returnFocus !== false) {\n requestAnimationFrame(() => {\n if (options?.returnFocusTo) {\n const target = options.returnFocusTo instanceof HTMLElement\n ? options.returnFocusTo\n : options.returnFocusTo.current;\n target?.focus();\n } else {\n focusTriggerElement();\n }\n });\n }\n };\n\n const calculatePositionOfPopover = (position: string = 'bottom-center') => {\n if (!srcElementRef.current) return { top: 0, left: 0, srcWidth: 0 };\n\n let localPosition = position;\n\n const srcRect = srcElementRef.current.getBoundingClientRect();\n // Subtract scrollbar width so portal content doesn't render behind a scrollbar.\n // document.documentElement.clientWidth excludes any visible scrollbar;\n // fall back to a 16px buffer (max scrollbar width across OS/browsers) when\n // body overflow is hidden and the scrollbar belongs to a nested container.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const viewportWidth = window.innerWidth - Math.max(scrollbarWidth, 16);\n const viewportHeight = window.innerHeight;\n\n // Calculate position for portal\n let top = 0;\n let left = 0;\n\n switch (localPosition) {\n case 'bottom-left':\n top = srcRect.bottom;\n left = srcRect.left;\n break;\n case 'bottom-right':\n top = srcRect.bottom;\n left = srcRect.right - srcRect.width * 0.5;\n break;\n case 'bottom-center':\n top = srcRect.bottom;\n // Center the popover relative to the source element\n left = srcRect.left + srcRect.width / 2;\n break;\n case 'top-left':\n top = srcRect.top - srcRect.height * 1.9;\n left = srcRect.left;\n break;\n case 'top-right':\n top = srcRect.top - srcRect.height * 1.9;\n left = srcRect.right - srcRect.width * 0.5;\n break;\n case 'top-center':\n top = srcRect.top - srcRect.height * 1.9;\n // Center the popover relative to the source element\n left = srcRect.left + srcRect.width / 2;\n break;\n default:\n top = srcRect.bottom;\n left = srcRect.left;\n break;\n }\n\n // Get popover dimensions if available\n const popoverRect = popoverContentRef.current?.getBoundingClientRect();\n // When contentWidth='full', the panel will be sized to srcRect.width after measurement.\n // Use srcRect.width directly so centering and viewport clamping use the correct final width.\n const popoverWidth = (contentWidth === 'full' ? Math.max(srcRect.width, popoverRect?.width || 0) : popoverRect?.width) || 0;\n const popoverHeight = popoverRect?.height || 0;\n\n // Adjust center positions to account for popover width\n if (localPosition === 'bottom-center' || localPosition === 'top-center') {\n // Center the popover by subtracting half its width from the source center\n left = left - popoverWidth / 2;\n }\n\n // Adjust position to keep popover within viewport bounds\n // Horizontal adjustments\n if (left + popoverWidth > viewportWidth) {\n // Popover extends beyond right edge, shift it left\n left = Math.max(0, viewportWidth - popoverWidth);\n }\n if (left < 0) {\n // Popover extends beyond left edge, shift it right\n left = 0;\n }\n\n // Vertical adjustments\n if (top + popoverHeight > viewportHeight) {\n // Popover extends beyond bottom edge\n // Try to position it above the source element\n const spaceAbove = srcRect.top;\n const spaceBelow = viewportHeight - srcRect.bottom;\n\n if (spaceAbove >= popoverHeight || spaceAbove > spaceBelow) {\n // Position above if there's enough space or more space above\n top = srcRect.top - popoverHeight;\n // Ensure it doesn't go above the topbar (48px fixed header)\n if (top < 48) {\n top = 48;\n }\n } else {\n // Keep at bottom but adjust to fit within viewport\n top = Math.max(48, viewportHeight - popoverHeight);\n }\n }\n if (top < 48) {\n // Popover extends beyond top edge, position it below the source element\n top = srcRect.bottom;\n // Ensure it doesn't go below viewport\n if (top + popoverHeight > viewportHeight) {\n top = Math.max(48, viewportHeight - popoverHeight);\n }\n }\n\n return { top: Math.round(top), left: Math.round(left), srcWidth: srcRect.width };\n };\n\n useEffect(() => {\n if (onPopoverToggle) {\n onPopoverToggle(displayPopover);\n }\n\n if (displayPopover && !isWithPortal) {\n // Add click listener for auto-close behavior only if not disabled\n if (!disableAutoClose) {\n document.body.addEventListener('click', clickListener, true);\n }\n checkPopoverPosition();\n return () => {\n if (!disableAutoClose) {\n document.body.removeEventListener('click', clickListener, true);\n }\n };\n } else if (displayPopover && isWithPortal) {\n // Add click/scroll listeners for auto-close behavior only if not disabled\n if (!disableAutoClose) {\n document.body.addEventListener('click', clickAndScrollListenerWithPortal, true);\n window.addEventListener('scroll', clickAndScrollListenerWithPortal);\n } else {\n // When disableAutoClose is true, still listen to scroll for repositioning\n window.addEventListener('scroll', scrollListenerForRepositioning);\n }\n // Always add resize listener for repositioning\n window.addEventListener('resize', resizeListenerWithPortal);\n\n // Escape on window capture phase — must fire before document-capture listeners\n // (e.g. useDismissOnEscape in Modal) so Escape closes the portal Dropdown without\n // also dismissing the modal behind it.\n const escapeHandler = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n if (!popoverContentRef.current?.contains(document.activeElement)) return;\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n requestAnimationFrame(() => focusTriggerElement());\n };\n window.addEventListener('keydown', escapeHandler, true);\n\n // Trigger source visibility check immediately\n checkSourceVisibility();\n\n // Use double-rAF to measure portal after browser has completed layout,\n // guaranteeing real dimensions are available for flip/clamp calculations.\n // Portal is hidden via visibility:hidden until this completes (no flash).\n let rafId1: number;\n let rafId2: number;\n rafId1 = requestAnimationFrame(() => {\n rafId2 = requestAnimationFrame(() => {\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n setIsPortalMeasured(true);\n });\n });\n\n return () => {\n if (!disableAutoClose) {\n document.body.removeEventListener('click', clickAndScrollListenerWithPortal, true);\n window.removeEventListener('scroll', clickAndScrollListenerWithPortal);\n } else {\n window.removeEventListener('scroll', scrollListenerForRepositioning);\n }\n window.removeEventListener('resize', resizeListenerWithPortal);\n window.removeEventListener('keydown', escapeHandler, true);\n cancelAnimationFrame(rafId1);\n cancelAnimationFrame(rafId2);\n setIsPortalMeasured(false);\n };\n }\n }, [displayPopover, isWithPortal, disableAutoClose]);\n\n const checkSourceVisibility = () => {\n if (!srcElementRef.current) {\n setIsSrcElementVisible(false);\n return;\n }\n\n const rec = srcElementRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n\n const isVisible = rec.top < viewportHeight && rec.bottom > 0 && rec.left < viewportWidth && rec.right > 0;\n\n setIsSrcElementVisible(isVisible);\n };\n\n useEffect(() => {\n setDisplayPopover(isPopoverOpen ?? false);\n }, [isPopoverOpen]);\n\n useEffect(() => {\n // Focus first focusable element when popover opens.\n // For portal, delay longer so isSrcElementVisible can be set and portal can mount first.\n if (displayPopover) {\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable && (focusFirstOnOpen || document.activeElement === srcElementRef.current)) {\n firstFocusable.focus();\n }\n }, isWithPortal ? 60 : 0);\n }\n }, [displayPopover]);\n\n //Function to check popover position\n const checkPopoverPosition = () => {\n if (!popoverContentRef.current) return;\n\n const popoverRect = popoverContentRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n\n if (popoverRect?.bottom > viewportHeight) {\n setPopoverPosition(\n position.includes('left') ? 'top-left' : position.includes('right') ? 'top-right' : 'top-center'\n );\n } else if (popoverRect?.top < 0) {\n // If popover extends beyond top of viewport, switch to bottom position\n setPopoverPosition(\n position.includes('left') ? 'bottom-left' : position.includes('right') ? 'bottom-right' : 'bottom-center'\n );\n }\n };\n\n const clickListener = (event: MouseEvent) => {\n const currentDropRef = srcElementRef.current;\n if (!currentDropRef) return;\n\n const target = event.target as Node;\n const isSourcePopover = currentDropRef.contains(target);\n const isPopoverContent = popoverContentRef.current?.contains(target);\n\n // Check if click is on another popover's source element\n const clickedElement = target as HTMLElement;\n const closestPopoverWrapper = clickedElement.closest?.('.se-design-popover-wrapper');\n const isAnotherPopoverSource = closestPopoverWrapper && closestPopoverWrapper !== currentDropRef;\n\n // check if the clicked popover is a nesteded child of the current popover content\n const isNestedPopover = popoverContentRef.current?.contains(closestPopoverWrapper as Node);\n\n // if clicked source is parent or the popover-content, do not toggle dropdown.\n // Also close if clicking on another popover's source element\n if (disableAutoClose) return;\n if ((!isSourcePopover && !isPopoverContent) || (isAnotherPopoverSource && !isNestedPopover)) {\n setDisplayPopover(false);\n }\n };\n\n const clickAndScrollListenerWithPortal = (event: Event) => {\n const currentDropRef = srcElementRef.current;\n const currentPopoverRef = popoverContentRef.current;\n if (!currentDropRef) return;\n checkSourceVisibility();\n\n // Recalculate position on scroll\n if (event.type === 'scroll' && displayPopover) {\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n\n const target = event.target as Node;\n const isSourcePopover = currentDropRef.contains(target);\n const isPopoverContent = currentPopoverRef?.contains(target);\n\n // Check if click is on another popover's source element\n const clickedElement = target as HTMLElement;\n const closestPopoverWrapper = clickedElement.closest?.('.se-design-popover-wrapper');\n const isAnotherPopoverSource = closestPopoverWrapper && closestPopoverWrapper !== currentDropRef;\n\n // check if the clicked popover is a nesteded child of the current popover content\n const isNestedPopover = popoverContentRef.current?.contains(closestPopoverWrapper as Node);\n\n if (disableAutoClose) return;\n // if clicked source is parent or the popover-content, do not toggle dropdown.\n // Also close if clicking on another popover's source element\n if ((!isSourcePopover && !isPopoverContent) || (isAnotherPopoverSource && !isNestedPopover)) {\n setDisplayPopover(false);\n }\n };\n\n const resizeListenerWithPortal = () => {\n if (displayPopover && isWithPortal && srcElementRef.current) {\n checkSourceVisibility();\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n };\n\n const scrollListenerForRepositioning = () => {\n if (displayPopover && isWithPortal && srcElementRef.current) {\n checkSourceVisibility();\n const position = calculatePositionOfPopover(popoverPosition);\n if (position) {\n setPortalPosition(position);\n }\n }\n };\n\n const togglePopover = (focusFirst: boolean | 'last' = false) => {\n const wasOpen = displayPopover;\n setDisplayPopover((prev) => !prev);\n if (!wasOpen && focusFirst) {\n setTimeout(() => {\n if (focusFirst === 'last') {\n const lastFocusable = getLastFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (lastFocusable) lastFocusable.focus();\n } else {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }\n }, 50);\n }\n };\n\n const handleArrowKeyNavigation = (e: React.KeyboardEvent, container: HTMLDivElement | null) => {\n if (!container) return;\n\n // Native form controls own their arrow key behavior — don't intercept.\n // (e.g. a SearchBox inside a Popover should keep focus while typing/navigating)\n const activeEl = document.activeElement;\n if (activeEl?.tagName === 'INPUT' || activeEl?.tagName === 'TEXTAREA' || activeEl?.tagName === 'SELECT') {\n return;\n }\n\n const focusableElements = Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_WITH_ROLES_SELECTOR)).filter((el) => {\n // Filter out disabled and hidden elements.\n // Note: check aria-disabled VALUE not just presence — React always writes aria-disabled=\"false\"\n // on elements like MenuItem even when not disabled, so hasAttribute would wrongly exclude them.\n const style = window.getComputedStyle(el);\n return (\n !el.hasAttribute('disabled') &&\n el.getAttribute('aria-disabled') !== 'true' &&\n style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n (el.tabIndex >= 0 || el.hasAttribute('role'))\n );\n });\n\n if (focusableElements.length === 0) return;\n\n const currentIndex = focusableElements.findIndex((el) => el === document.activeElement);\n let nextIndex = -1;\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = currentIndex < focusableElements.length - 1 ? currentIndex + 1 : 0;\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : focusableElements.length - 1;\n } else if (e.key === 'Home') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = 0;\n } else if (e.key === 'End') {\n e.preventDefault();\n e.stopPropagation();\n nextIndex = focusableElements.length - 1;\n }\n\n if (nextIndex >= 0 && focusableElements[nextIndex]) {\n focusableElements[nextIndex].focus();\n } else if (currentIndex === -1 && focusableElements.length > 0) {\n // If no element is currently focused, focus the first one\n focusableElements[0].focus();\n }\n };\n\n const handlePopoverContentKeyDown = (e: React.KeyboardEvent) => {\n // Allow Escape key to close popover when focus is on content\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n // Defer focus restoration to after React re-renders and portal unmounts.\n // Synchronous focus() during the event can be displaced by the portal\n // teardown in some browsers, especially when isWithPortal=true.\n requestAnimationFrame(() => focusTriggerElement());\n } else if (e.key === 'Tab') {\n if (popupType === 'dialog') {\n // Dialog popovers: let Tab flow naturally within the content.\n // Only close when focus would actually leave the popover.\n const focusables = getFocusableElements({ container: popoverContentRef.current, filterHidden: true });\n const currentIndex = focusables.indexOf(e.target as HTMLElement);\n const isOnLast = currentIndex === focusables.length - 1;\n const isOnFirst = currentIndex === 0 || currentIndex === -1;\n\n if (e.shiftKey && isOnFirst) {\n // Shift+Tab past first element — close and return focus to trigger\n e.preventDefault();\n setDisplayPopover(false);\n focusTriggerElement();\n } else if (!e.shiftKey && isOnLast) {\n // Tab past last element — close popover\n setDisplayPopover(false);\n if (isWithPortal) {\n e.preventDefault();\n const srcEl = srcElementRef.current;\n const allFocusables = getFocusableElements({ container: document.body, filterHidden: true });\n const idx = srcEl ? allFocusables.indexOf(srcEl) : -1;\n const next = allFocusables[idx + 1];\n if (next) next.focus();\n else srcEl?.focus();\n }\n }\n // Otherwise: let browser handle Tab naturally within the popover content\n } else {\n // Non-dialog: close popover when Tab exits the menu\n setDisplayPopover(false);\n if (e.shiftKey) {\n // Shift+Tab: prevent default (would go to wrapper) and focus trigger instead\n e.preventDefault();\n focusTriggerElement();\n } else if (isWithPortal) {\n // Portal forward Tab: portal content is at document.body so natural Tab order\n // skips back to the top of the page. Manually advance to the next focusable\n // element after the trigger in the main document instead.\n e.preventDefault();\n const srcEl = srcElementRef.current;\n const focusables = getFocusableElements({ container: document.body, filterHidden: true });\n const idx = srcEl ? focusables.indexOf(srcEl) : -1;\n const next = focusables[idx + 1];\n if (next) next.focus();\n else srcEl?.focus();\n }\n // Non-portal forward Tab: do NOT preventDefault — browser moves focus to next element naturally\n }\n } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End') {\n // Handle arrow key navigation for focusable elements inside popover\n handleArrowKeyNavigation(e, popoverContentRef.current);\n } else if (e.key === 'Enter' || e.key === ' ') {\n // Prevent Enter/Space from bubbling to wrapper (mirrors click stopPropagation)\n e.stopPropagation();\n }\n };\n\n useImperativeHandle(ref, () => ({ togglePopover, focusTrigger: () => srcElementRef.current?.focus(), element: srcElementRef.current }), []);\n\n const popoverContentStyle = {\n 'bottom-left': { left: '0', top: '100%' },\n 'bottom-right': { right: '0', top: '100%' },\n 'bottom-center': { left: '50%', transform: 'translateX(-50%)', top: '100%' },\n 'top-left': { left: '0', bottom: '100%' },\n 'top-right': { right: '0', bottom: '100%' },\n 'top-center': { left: '50%', transform: 'translateX(-50%)', bottom: '100%' }\n };\n const popoverContentClasses = noBorder ? '' : 'shadow-md border rounded-md';\n\n return (\n <div\n className={\n 'se-design-popover-wrapper cursor-pointer relative focus-outline rounded-md' +\n (className.length > 0 ? ` ${className}` : '') +\n (displayPopover ? ' open' : '') +\n (disabled ? ' opacity-50 cursor-not-allowed pointer-events-none' : '')\n }\n ref={srcElementRef}\n onClick={(e) => {\n if (disabled || disableClickToggle) return;\n e.stopPropagation();\n togglePopover();\n }}\n onKeyDown={(e) => {\n if (disabled || disableClickToggle) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n const wasOpen = displayPopover;\n togglePopover();\n // Focus first focusable element when opening.\n // Portal content isn't mounted until isSrcElementVisible resolves (via setTimeout 0),\n // so use a longer delay for portal to ensure popoverContentRef.current is set.\n if (!wasOpen) {\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }, isWithPortal ? 60 : 0);\n }\n } else if (e.key === 'Escape' && displayPopover) {\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(false);\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && displayPopover) {\n // Handle arrow keys when popover is open\n const currentRef = popoverContentRef.current;\n if (currentRef) {\n handleArrowKeyNavigation(e, currentRef);\n }\n } else if (e.key === 'ArrowDown' && !displayPopover) {\n // Open popover and focus first item when ArrowDown is pressed\n e.preventDefault();\n e.stopPropagation();\n setDisplayPopover(true);\n setTimeout(() => {\n const firstFocusable = getFirstFocusableElement({ container: popoverContentRef.current, includeRoles: true });\n if (firstFocusable) firstFocusable.focus();\n }, 0);\n }\n }}\n onBlurCapture={onDismissBlurCapture}\n onBlur={(e) => {\n // Portal content is rendered outside wrapper, so keep explicit check for that case.\n if (!displayPopover || disableAutoClose || !isWithPortal) return;\n\n const nextFocused = e.relatedTarget as Node | null;\n const isFocusInSource = !!(nextFocused && srcElementRef.current?.contains(nextFocused));\n const isFocusInPopover = !!(nextFocused && popoverContentRef.current?.contains(nextFocused));\n\n // Close only when focus leaves both source and portal content.\n if (!isFocusInSource && !isFocusInPopover) {\n setDisplayPopover(false);\n }\n }}\n role={disableClickToggle ? 'none' : sourceRole}\n aria-expanded={disableClickToggle ? undefined : displayPopover ? 'true' : 'false'}\n aria-haspopup={disableClickToggle ? undefined : sourceRole === 'combobox' ? 'listbox' : popupType}\n tabIndex={disabled || disableClickToggle ? -1 : 0}\n aria-disabled={disableClickToggle ? undefined : disabled ? 'true' : undefined}\n {...accessibleNameProps}\n data-automation-id={automationId}\n {...props}\n >\n {renderPopoverSrcElement({ displayPopover, togglePopover })}\n\n {displayPopover && !isWithPortal && (\n <div\n className={`popover-content absolute ${popoverContentClasses} z-[1000] ${\n contentWidth == 'full' ? 'w-full' : 'w-max'\n }`}\n style={{\n ...popoverContentStyleProperty,\n ...popoverContentStyle[popoverPosition]\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handlePopoverContentKeyDown}\n ref={popoverContentRef}\n data-automation-id={popoverContentAutomationId}\n >\n {renderPopoverContents({ closePopoverCb: closePopover })}\n </div>\n )}\n {isWithPortal &&\n displayPopover &&\n isSrcElementVisible &&\n ReactDOM.createPortal(\n <div\n className={`popover-content-with-portal z-[2002] ${popoverContentClasses} ${\n contentWidth == 'full' ? '' : 'w-max'\n }`}\n style={{\n position: 'fixed',\n top: portalPosition.top,\n left: portalPosition.left,\n visibility: isPortalMeasured ? 'visible' : 'hidden',\n maxHeight: 'calc(100vh - 96px)',\n overflowY: 'hidden',\n ...(contentWidth === 'full' && portalPosition.srcWidth\n ? { width: `${portalPosition.srcWidth}px` }\n : {}),\n ...popoverContentStyleProperty,\n zIndex: 2002\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handlePopoverContentKeyDown}\n ref={popoverContentRef}\n data-automation-id={popoverContentAutomationId}\n >\n {renderPopoverContents({ closePopoverCb: closePopover })}\n </div>,\n document.body\n )}\n </div>\n );\n }\n);\n"],"names":["Popover","className","automationId","position","popoverContentAutomationId","contentWidth","renderPopoverContents","renderPopoverSrcElement","onPopoverToggle","isPopoverOpen","disabled","isWithPortal","ariaLabel","ariaLabelledBy","sourceRole","popupType","popoverContentStyleProperty","zIndex","borderColor","color","backgroundColor","disableClickToggle","noBorder","disableAutoClose","focusFirstOnOpen","props","ref","displayPopover","setDisplayPopover","useState","popoverPosition","setPopoverPosition","isSrcElementVisible","setIsSrcElementVisible","srcElementRef","useRef","popoverContentRef","useRegisterPortalWithFocusTrap","accessibleNameProps","getA11yNameAttributes","ariaDescribedBy","undefined","onBlurCapture","onDismissBlurCapture","useDismissOnFocusOut","onFocusOut","closeOnEscape","portalPosition","setPortalPosition","top","left","srcWidth","isPortalMeasured","setIsPortalMeasured","focusTriggerElement","getFirstFocusableElement","container","current","includeRoles","focus","closePopover","options","returnFocus","requestAnimationFrame","returnFocusTo","HTMLElement","calculatePositionOfPopover","localPosition","srcRect","getBoundingClientRect","scrollbarWidth","window","innerWidth","document","documentElement","clientWidth","viewportWidth","Math","max","viewportHeight","innerHeight","bottom","right","width","height","popoverRect","popoverWidth","popoverHeight","spaceAbove","spaceBelow","round","useEffect","body","addEventListener","clickListener","checkPopoverPosition","removeEventListener","scrollListenerForRepositioning","clickAndScrollListenerWithPortal","resizeListenerWithPortal","escapeHandler","e","key","contains","activeElement","preventDefault","stopPropagation","checkSourceVisibility","rafId1","rafId2","cancelAnimationFrame","rec","isVisible","setTimeout","firstFocusable","includes","event","currentDropRef","target","isSourcePopover","isPopoverContent","closestPopoverWrapper","closest","isAnotherPopoverSource","isNestedPopover","currentPopoverRef","type","togglePopover","focusFirst","wasOpen","prev","lastFocusable","getLastFocusableElement","handleArrowKeyNavigation","activeEl","tagName","focusableElements","Array","from","querySelectorAll","FOCUSABLE_WITH_ROLES_SELECTOR","filter","el","style","getComputedStyle","hasAttribute","getAttribute","display","visibility","tabIndex","length","currentIndex","findIndex","nextIndex","handlePopoverContentKeyDown","focusables","getFocusableElements","filterHidden","indexOf","isOnLast","isOnFirst","shiftKey","srcEl","allFocusables","idx","next","useImperativeHandle","focusTrigger","element","popoverContentStyle","transform","popoverContentClasses","React","createElement","_extends","onClick","onKeyDown","currentRef","onBlur","nextFocused","relatedTarget","isFocusInSource","isFocusInPopover","role","closePopoverCb","ReactDOM","createPortal","maxHeight","overflowY"],"mappings":"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"}
|
package/dist/index72.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useRef as p, useLayoutEffect as
|
|
2
|
-
import { getFirstFocusableElement as
|
|
1
|
+
import { useRef as p, useLayoutEffect as a } from "react";
|
|
2
|
+
import { getFirstFocusableElement as A, getFocusableElements as L } from "./index71.js";
|
|
3
3
|
let f = null;
|
|
4
|
-
function
|
|
4
|
+
function F(e) {
|
|
5
5
|
const n = e.composedPath();
|
|
6
6
|
for (const s of n)
|
|
7
7
|
if (s instanceof HTMLElement && s.tabIndex >= 0) {
|
|
@@ -12,24 +12,24 @@ function L(e) {
|
|
|
12
12
|
function k(e) {
|
|
13
13
|
(e.key === "Enter" || e.key === " ") && (f = document.activeElement);
|
|
14
14
|
}
|
|
15
|
-
typeof document < "u" && (document.addEventListener("pointerdown",
|
|
16
|
-
function
|
|
15
|
+
typeof document < "u" && (document.addEventListener("pointerdown", F, !0), document.addEventListener("keydown", k, !0));
|
|
16
|
+
function T() {
|
|
17
17
|
const e = f;
|
|
18
18
|
return f = null, e;
|
|
19
19
|
}
|
|
20
|
-
let
|
|
21
|
-
function
|
|
22
|
-
l !== null && cancelAnimationFrame(l),
|
|
23
|
-
|
|
20
|
+
let m = null, l = null;
|
|
21
|
+
function _(e) {
|
|
22
|
+
l !== null && cancelAnimationFrame(l), m = e, l = requestAnimationFrame(() => {
|
|
23
|
+
m = null, l = null;
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
function I() {
|
|
27
27
|
l !== null && (cancelAnimationFrame(l), l = null);
|
|
28
|
-
const e =
|
|
29
|
-
return
|
|
28
|
+
const e = m;
|
|
29
|
+
return m = null, e;
|
|
30
30
|
}
|
|
31
31
|
function w(e, n) {
|
|
32
|
-
return n === "none" ? null : n === "first" ?
|
|
32
|
+
return n === "none" ? null : n === "first" ? A({
|
|
33
33
|
container: e
|
|
34
34
|
}) || e : n === "container" ? e : typeof n == "string" ? e.querySelector(n) : n instanceof HTMLElement ? n : null;
|
|
35
35
|
}
|
|
@@ -38,74 +38,74 @@ function C({
|
|
|
38
38
|
containerRef: n,
|
|
39
39
|
restoreFocus: s = !0,
|
|
40
40
|
initialFocus: d = "first",
|
|
41
|
-
returnFocusRef:
|
|
41
|
+
returnFocusRef: g,
|
|
42
42
|
portalContainerRefs: h
|
|
43
43
|
}) {
|
|
44
|
-
const
|
|
45
|
-
return
|
|
44
|
+
const u = p(null), E = p(null);
|
|
45
|
+
return a(() => {
|
|
46
46
|
if (!e) {
|
|
47
|
-
if (s &&
|
|
48
|
-
const t =
|
|
49
|
-
|
|
47
|
+
if (s && u.current) {
|
|
48
|
+
const t = u.current;
|
|
49
|
+
u.current = null, requestAnimationFrame(() => {
|
|
50
50
|
t.isConnected && t.focus();
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
57
|
-
const c =
|
|
55
|
+
const r = n.current;
|
|
56
|
+
if (!r) return;
|
|
57
|
+
const c = g?.current ?? I() ?? f ?? document.activeElement;
|
|
58
58
|
if (f = null, c?.tagName === "IFRAME") {
|
|
59
|
-
|
|
59
|
+
u.current = null;
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
|
-
return
|
|
63
|
-
w(
|
|
62
|
+
return u.current = c, r.contains(document.activeElement) || requestAnimationFrame(() => {
|
|
63
|
+
w(r, d)?.focus();
|
|
64
64
|
}), () => {
|
|
65
|
-
if (s &&
|
|
66
|
-
const t =
|
|
67
|
-
|
|
65
|
+
if (s && u.current) {
|
|
66
|
+
const t = u.current;
|
|
67
|
+
u.current = null, requestAnimationFrame(() => {
|
|
68
68
|
t.isConnected && t.focus();
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
|
-
}, [e, n, s, d]),
|
|
72
|
+
}, [e, n, s, d]), a(() => {
|
|
73
73
|
if (!e) return;
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
74
|
+
const r = n.current;
|
|
75
|
+
if (!r) return;
|
|
76
76
|
const c = (t) => {
|
|
77
77
|
if (t.key === "Tab") {
|
|
78
|
-
const
|
|
79
|
-
container:
|
|
78
|
+
const o = L({
|
|
79
|
+
container: r
|
|
80
80
|
});
|
|
81
|
-
if (
|
|
82
|
-
t.preventDefault(),
|
|
81
|
+
if (o.length === 0) {
|
|
82
|
+
t.preventDefault(), r.focus();
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
const i =
|
|
86
|
-
t.shiftKey &&
|
|
85
|
+
const i = o[0], v = o[o.length - 1], y = document.activeElement;
|
|
86
|
+
t.shiftKey && y === i ? (t.preventDefault(), v.focus()) : !t.shiftKey && y === v && (t.preventDefault(), i.focus());
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
89
|
return document.addEventListener("keydown", c, !0), () => document.removeEventListener("keydown", c, !0);
|
|
90
|
-
}, [e, n]),
|
|
90
|
+
}, [e, n]), a(() => {
|
|
91
91
|
if (!e) return;
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
92
|
+
const r = n.current;
|
|
93
|
+
if (!r) return;
|
|
94
94
|
const c = (t) => {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
container:
|
|
98
|
-
}) ||
|
|
95
|
+
const o = t.target;
|
|
96
|
+
o?.tagName !== "IFRAME" && (r.contains(o) ? E.current = o : h?.current?.some((i) => i.current?.contains(o)) || (E.current || A({
|
|
97
|
+
container: r
|
|
98
|
+
}) || r).focus());
|
|
99
99
|
};
|
|
100
100
|
return document.addEventListener("focusin", c, !0), () => document.removeEventListener("focusin", c, !0);
|
|
101
101
|
}, [e, n]), {
|
|
102
|
-
triggerRef:
|
|
102
|
+
triggerRef: u
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
export {
|
|
106
106
|
I as consumeFocusAnchor,
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
T as consumeLastInteractedElement,
|
|
108
|
+
_ as setFocusAnchor,
|
|
109
109
|
C as useFocusTrap
|
|
110
110
|
};
|
|
111
111
|
//# sourceMappingURL=index72.js.map
|
package/dist/index72.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index72.js","sources":["../src/utils/a11y/useFocusTrap.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport type { MutableRefObject, RefObject } from 'react';\nimport { getFocusableElements, getFirstFocusableElement } from './focusableElements';\n\nexport interface UseFocusTrapOptions<T extends HTMLElement = HTMLElement> {\n /**\n * Whether the focus trap is active.\n */\n enabled: boolean;\n /**\n * Container element ref to trap focus within.\n */\n containerRef: React.RefObject<T | null>;\n /**\n * Whether to restore focus to the element that had focus before trap activated.\n * Default: true\n */\n restoreFocus?: boolean;\n /**\n * Initial focus target when trap activates.\n * - 'first': Focus first focusable element (default)\n * - 'container': Focus the container itself\n * - 'none': Skip initial focus — browser handles it (e.g. autofocus attribute)\n * - CSS selector: Focus element matching selector\n * - HTMLElement: Focus this specific element\n */\n initialFocus?: 'first' | 'container' | 'none' | string | HTMLElement;\n /**\n * Explicit element to restore focus to when the trap deactivates.\n * Overrides the automatic trigger capture (_lastInteractedElement / document.activeElement).\n * Use when the opener is known at call-site (e.g. a ref on the toggle button).\n */\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n /**\n * Additional container refs that are logically part of this focus trap\n * (e.g., portal-rendered content from Popover/Dropdown). Focus moving to\n * these containers will NOT trigger the safety net redirect.\n */\n portalContainerRefs?: MutableRefObject<RefObject<HTMLElement | null>[]>;\n}\n\nexport interface UseFocusTrapReturn {\n /**\n * Ref to the element that had focus before trap activated.\n * Useful for manual focus restoration if needed.\n */\n triggerRef: React.MutableRefObject<HTMLElement | null>;\n}\n\n// Module-level trigger tracking: React's commit phase is bottom-up, so by the\n// time useFocusTrap's useLayoutEffect runs, document.activeElement may already\n// be the autoFocus element inside the modal rather than the opener button.\n// We capture the last interacted element via pointerdown/keydown listeners\n// (which fire before any React state update commits) to work around this.\nlet _lastInteractedElement: HTMLElement | null = null;\n\nfunction _onPointerDown(e: PointerEvent): void {\n // Walk composedPath to find the nearest focusable element being pressed.\n const path = e.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.tabIndex >= 0) {\n _lastInteractedElement = node;\n return;\n }\n }\n}\n\nfunction _onKeyDown(e: KeyboardEvent): void {\n // Enter/Space on a focused button will synthesise a click — capture before that.\n if (e.key === 'Enter' || e.key === ' ') {\n _lastInteractedElement = document.activeElement as HTMLElement;\n }\n}\n\nif (typeof document !== 'undefined') {\n document.addEventListener('pointerdown', _onPointerDown, true);\n document.addEventListener('keydown', _onKeyDown, true);\n}\n\n/**\n * Returns (and clears) the last element interacted with before a React commit.\n * Used by SidebarOverlay complementary mode to seed its trigger ref without\n * relying on document.activeElement timing.\n */\nexport function consumeLastInteractedElement(): HTMLElement | null {\n const el = _lastInteractedElement;\n _lastInteractedElement = null;\n return el;\n}\n\n// Focus anchor — explicit stable return-focus target, higher priority than\n// _lastInteractedElement. Auto-clears via setTimeout(0) to prevent a stale\n// anchor leaking to an unrelated open.\nlet _focusAnchor: HTMLElement | null = null;\nlet _focusAnchorClearFrame: ReturnType<typeof requestAnimationFrame> | null = null;\n\n/**\n * Sets an explicit focus-return anchor element.\n * Call this before dispatching an action that will open a modal or sidebar,\n * when the natural last-interacted element is not the right return target\n * (e.g. a popover menu item that will be unmounted when the popover closes).\n */\nexport function setFocusAnchor(el: HTMLElement | null): void {\n if (_focusAnchorClearFrame !== null) cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchor = el;\n // Auto-clear if not consumed — prevents stale anchor leaking to unrelated opens.\n // rAF fires after React has committed and painted, giving useFocusTrap time to\n // consume the anchor before it is discarded.\n _focusAnchorClearFrame = requestAnimationFrame(() => {\n _focusAnchor = null;\n _focusAnchorClearFrame = null;\n });\n}\n\n/**\n * Returns (and clears) the focus anchor if one was set, otherwise null.\n * Used internally by useFocusTrap and SidebarOverlay.\n */\nexport function consumeFocusAnchor(): HTMLElement | null {\n if (_focusAnchorClearFrame !== null) {\n cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchorClearFrame = null;\n }\n const el = _focusAnchor;\n _focusAnchor = null;\n return el;\n}\n\n/**\n * Resolve the initial focus target based on the initialFocus option.\n */\nfunction resolveInitialFocusTarget(\n container: HTMLElement,\n initialFocus: 'first' | 'container' | 'none' | string | HTMLElement\n): HTMLElement | null {\n if (initialFocus === 'none') return null;\n if (initialFocus === 'first') {\n return getFirstFocusableElement({ container }) || container;\n }\n if (initialFocus === 'container') {\n return container;\n }\n if (typeof initialFocus === 'string') {\n return container.querySelector<HTMLElement>(initialFocus);\n }\n if (initialFocus instanceof HTMLElement) {\n return initialFocus;\n }\n return null;\n}\n\n/**\n * Hook to trap focus within a container (for modals, dialogs, drawers).\n *\n * Implements WCAG 2.1 focus trap pattern:\n * - Moves focus into container on activation\n * - Wraps Tab/Shift+Tab navigation within container\n * - Restores focus to trigger element on deactivation\n * - Safety net: catches focus escaping via other means\n * - Handles autoFocus content: captures trigger before autoFocus fires\n * - Handles {isOpen && <Modal>} pattern: restores focus on unmount\n *\n * Note: For Escape key handling, use `useDismissOnEscape` hook separately.\n * This keeps focus trap (accessibility) separate from Escape handling (UX).\n *\n * @example\n * ```tsx\n * const MyModal = ({ isOpen, onClose }) => {\n * const containerRef = useRef<HTMLDivElement>(null);\n *\n * // Escape handling (UX)\n * useDismissOnEscape({\n * containerRef,\n * onDismiss: onClose,\n * enabled: isOpen\n * });\n *\n * // Focus trap (accessibility)\n * const { triggerRef } = useFocusTrap({\n * enabled: isOpen,\n * containerRef,\n * restoreFocus: true\n * });\n *\n * return (\n * <div ref={containerRef}>\n * <button>First</button>\n * <button>Second</button>\n * </div>\n * );\n * };\n * ```\n */\nexport function useFocusTrap<T extends HTMLElement = HTMLElement>({\n enabled,\n containerRef,\n restoreFocus = true,\n initialFocus = 'first',\n returnFocusRef,\n portalContainerRefs,\n}: UseFocusTrapOptions<T>): UseFocusTrapReturn {\n const triggerRef = useRef<HTMLElement | null>(null);\n const lastFocusedInContainer = useRef<HTMLElement | null>(null);\n\n // Focus management: save trigger, move focus into container on activate, restore on deactivate\n useLayoutEffect(() => {\n if (!enabled) {\n // Restore focus to trigger when trap deactivates\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n return;\n }\n\n const container = containerRef.current;\n if (!container) return;\n\n // Resolve trigger: explicit returnFocusRef wins, then focusAnchor (explicitly set\n // by caller for two-step flows like popover menu → modal), then the pre-commit\n // interaction record, then document.activeElement as final fallback.\n const previousActiveElement = returnFocusRef?.current ?? consumeFocusAnchor() ?? _lastInteractedElement ?? (document.activeElement as HTMLElement);\n _lastInteractedElement = null;\n\n // iframes manage their own internal focus. document.activeElement only ever\n // resolves to the <iframe> element from the parent doc — calling .focus()\n // on any parent-doc element forcibly blurs the iframe content (kills caret\n // in textareas, cancels native <select> dropdowns). Skip capture so the\n // auto-focus on open and focus-restore on close short-circuit on null trigger.\n if (previousActiveElement?.tagName === 'IFRAME') {\n triggerRef.current = null;\n return;\n }\n\n triggerRef.current = previousActiveElement;\n\n // Only move initial focus if autoFocus hasn't already placed it inside the container.\n if (!container.contains(document.activeElement)) {\n requestAnimationFrame(() => {\n resolveInitialFocusTarget(container, initialFocus)?.focus();\n });\n }\n\n // Restore focus on unmount while enabled (covers {isOpen && <Modal>} pattern\n // where the component unmounts before enabled can transition true → false)\n return () => {\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n };\n }, [enabled, containerRef, restoreFocus, initialFocus]);\n\n // Focus trap: Tab wrapping (only when enabled)\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Tab wrapping\n if (e.key === 'Tab') {\n const focusables = getFocusableElements({ container });\n\n if (focusables.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const activeElement = document.activeElement;\n\n if (e.shiftKey && activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [enabled, containerRef]);\n\n // Focus trap safety net: catch focus escaping\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as Node;\n\n // iframe focus is opaque from the parent doc — leave it alone, otherwise\n // a click into the iframe gets yanked back into the trap.\n if ((target as Element | null)?.tagName === 'IFRAME') return;\n\n if (container.contains(target)) {\n lastFocusedInContainer.current = target as HTMLElement;\n } else if (portalContainerRefs?.current?.some(ref => ref.current?.contains(target))) {\n // Focus is in a registered portal — allow it, but don't update\n // lastFocusedInContainer so safety net restores to the last main-container\n // element (e.g., the dropdown trigger) when the portal unmounts\n console.log('[FocusTrap] allowed portal focus:', (target as HTMLElement)?.tagName, (target as HTMLElement)?.className?.slice(0, 40));\n } else {\n // Focus escaped — redirect back\n console.log('[FocusTrap] REDIRECT:', (target as HTMLElement)?.tagName, (target as HTMLElement)?.className?.slice(0, 40), '→ back to container');\n const fallback = lastFocusedInContainer.current\n || getFirstFocusableElement({ container })\n || container;\n fallback.focus();\n }\n };\n\n document.addEventListener('focusin', handleFocusIn, true);\n return () => document.removeEventListener('focusin', handleFocusIn, true);\n }, [enabled, containerRef]);\n\n return { triggerRef };\n}\n"],"names":["_lastInteractedElement","_onPointerDown","e","path","composedPath","node","HTMLElement","tabIndex","_onKeyDown","key","document","activeElement","addEventListener","consumeLastInteractedElement","el","_focusAnchor","_focusAnchorClearFrame","setFocusAnchor","cancelAnimationFrame","requestAnimationFrame","consumeFocusAnchor","resolveInitialFocusTarget","container","initialFocus","getFirstFocusableElement","querySelector","useFocusTrap","enabled","containerRef","restoreFocus","returnFocusRef","portalContainerRefs","triggerRef","useRef","lastFocusedInContainer","useLayoutEffect","current","isConnected","focus","previousActiveElement","tagName","contains","handleKeyDown","focusables","getFocusableElements","length","preventDefault","first","last","shiftKey","removeEventListener","handleFocusIn","target","some","ref","console","log","className","slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index72.js","sources":["../src/utils/a11y/useFocusTrap.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport type { MutableRefObject, RefObject } from 'react';\nimport { getFocusableElements, getFirstFocusableElement } from './focusableElements';\n\nexport interface UseFocusTrapOptions<T extends HTMLElement = HTMLElement> {\n /**\n * Whether the focus trap is active.\n */\n enabled: boolean;\n /**\n * Container element ref to trap focus within.\n */\n containerRef: React.RefObject<T | null>;\n /**\n * Whether to restore focus to the element that had focus before trap activated.\n * Default: true\n */\n restoreFocus?: boolean;\n /**\n * Initial focus target when trap activates.\n * - 'first': Focus first focusable element (default)\n * - 'container': Focus the container itself\n * - 'none': Skip initial focus — browser handles it (e.g. autofocus attribute)\n * - CSS selector: Focus element matching selector\n * - HTMLElement: Focus this specific element\n */\n initialFocus?: 'first' | 'container' | 'none' | string | HTMLElement;\n /**\n * Explicit element to restore focus to when the trap deactivates.\n * Overrides the automatic trigger capture (_lastInteractedElement / document.activeElement).\n * Use when the opener is known at call-site (e.g. a ref on the toggle button).\n */\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n /**\n * Additional container refs that are logically part of this focus trap\n * (e.g., portal-rendered content from Popover/Dropdown). Focus moving to\n * these containers will NOT trigger the safety net redirect.\n */\n portalContainerRefs?: MutableRefObject<RefObject<HTMLElement | null>[]>;\n}\n\nexport interface UseFocusTrapReturn {\n /**\n * Ref to the element that had focus before trap activated.\n * Useful for manual focus restoration if needed.\n */\n triggerRef: React.MutableRefObject<HTMLElement | null>;\n}\n\n// Module-level trigger tracking: React's commit phase is bottom-up, so by the\n// time useFocusTrap's useLayoutEffect runs, document.activeElement may already\n// be the autoFocus element inside the modal rather than the opener button.\n// We capture the last interacted element via pointerdown/keydown listeners\n// (which fire before any React state update commits) to work around this.\nlet _lastInteractedElement: HTMLElement | null = null;\n\nfunction _onPointerDown(e: PointerEvent): void {\n // Walk composedPath to find the nearest focusable element being pressed.\n const path = e.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.tabIndex >= 0) {\n _lastInteractedElement = node;\n return;\n }\n }\n}\n\nfunction _onKeyDown(e: KeyboardEvent): void {\n // Enter/Space on a focused button will synthesise a click — capture before that.\n if (e.key === 'Enter' || e.key === ' ') {\n _lastInteractedElement = document.activeElement as HTMLElement;\n }\n}\n\nif (typeof document !== 'undefined') {\n document.addEventListener('pointerdown', _onPointerDown, true);\n document.addEventListener('keydown', _onKeyDown, true);\n}\n\n/**\n * Returns (and clears) the last element interacted with before a React commit.\n * Used by SidebarOverlay complementary mode to seed its trigger ref without\n * relying on document.activeElement timing.\n */\nexport function consumeLastInteractedElement(): HTMLElement | null {\n const el = _lastInteractedElement;\n _lastInteractedElement = null;\n return el;\n}\n\n// Focus anchor — explicit stable return-focus target, higher priority than\n// _lastInteractedElement. Auto-clears via setTimeout(0) to prevent a stale\n// anchor leaking to an unrelated open.\nlet _focusAnchor: HTMLElement | null = null;\nlet _focusAnchorClearFrame: ReturnType<typeof requestAnimationFrame> | null = null;\n\n/**\n * Sets an explicit focus-return anchor element.\n * Call this before dispatching an action that will open a modal or sidebar,\n * when the natural last-interacted element is not the right return target\n * (e.g. a popover menu item that will be unmounted when the popover closes).\n */\nexport function setFocusAnchor(el: HTMLElement | null): void {\n if (_focusAnchorClearFrame !== null) cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchor = el;\n // Auto-clear if not consumed — prevents stale anchor leaking to unrelated opens.\n // rAF fires after React has committed and painted, giving useFocusTrap time to\n // consume the anchor before it is discarded.\n _focusAnchorClearFrame = requestAnimationFrame(() => {\n _focusAnchor = null;\n _focusAnchorClearFrame = null;\n });\n}\n\n/**\n * Returns (and clears) the focus anchor if one was set, otherwise null.\n * Used internally by useFocusTrap and SidebarOverlay.\n */\nexport function consumeFocusAnchor(): HTMLElement | null {\n if (_focusAnchorClearFrame !== null) {\n cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchorClearFrame = null;\n }\n const el = _focusAnchor;\n _focusAnchor = null;\n return el;\n}\n\n/**\n * Resolve the initial focus target based on the initialFocus option.\n */\nfunction resolveInitialFocusTarget(\n container: HTMLElement,\n initialFocus: 'first' | 'container' | 'none' | string | HTMLElement\n): HTMLElement | null {\n if (initialFocus === 'none') return null;\n if (initialFocus === 'first') {\n return getFirstFocusableElement({ container }) || container;\n }\n if (initialFocus === 'container') {\n return container;\n }\n if (typeof initialFocus === 'string') {\n return container.querySelector<HTMLElement>(initialFocus);\n }\n if (initialFocus instanceof HTMLElement) {\n return initialFocus;\n }\n return null;\n}\n\n/**\n * Hook to trap focus within a container (for modals, dialogs, drawers).\n *\n * Implements WCAG 2.1 focus trap pattern:\n * - Moves focus into container on activation\n * - Wraps Tab/Shift+Tab navigation within container\n * - Restores focus to trigger element on deactivation\n * - Safety net: catches focus escaping via other means\n * - Handles autoFocus content: captures trigger before autoFocus fires\n * - Handles {isOpen && <Modal>} pattern: restores focus on unmount\n *\n * Note: For Escape key handling, use `useDismissOnEscape` hook separately.\n * This keeps focus trap (accessibility) separate from Escape handling (UX).\n *\n * @example\n * ```tsx\n * const MyModal = ({ isOpen, onClose }) => {\n * const containerRef = useRef<HTMLDivElement>(null);\n *\n * // Escape handling (UX)\n * useDismissOnEscape({\n * containerRef,\n * onDismiss: onClose,\n * enabled: isOpen\n * });\n *\n * // Focus trap (accessibility)\n * const { triggerRef } = useFocusTrap({\n * enabled: isOpen,\n * containerRef,\n * restoreFocus: true\n * });\n *\n * return (\n * <div ref={containerRef}>\n * <button>First</button>\n * <button>Second</button>\n * </div>\n * );\n * };\n * ```\n */\nexport function useFocusTrap<T extends HTMLElement = HTMLElement>({\n enabled,\n containerRef,\n restoreFocus = true,\n initialFocus = 'first',\n returnFocusRef,\n portalContainerRefs,\n}: UseFocusTrapOptions<T>): UseFocusTrapReturn {\n const triggerRef = useRef<HTMLElement | null>(null);\n const lastFocusedInContainer = useRef<HTMLElement | null>(null);\n\n // Focus management: save trigger, move focus into container on activate, restore on deactivate\n useLayoutEffect(() => {\n if (!enabled) {\n // Restore focus to trigger when trap deactivates\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n return;\n }\n\n const container = containerRef.current;\n if (!container) return;\n\n // Resolve trigger: explicit returnFocusRef wins, then focusAnchor (explicitly set\n // by caller for two-step flows like popover menu → modal), then the pre-commit\n // interaction record, then document.activeElement as final fallback.\n const previousActiveElement = returnFocusRef?.current ?? consumeFocusAnchor() ?? _lastInteractedElement ?? (document.activeElement as HTMLElement);\n _lastInteractedElement = null;\n\n // iframes manage their own internal focus. document.activeElement only ever\n // resolves to the <iframe> element from the parent doc — calling .focus()\n // on any parent-doc element forcibly blurs the iframe content (kills caret\n // in textareas, cancels native <select> dropdowns). Skip capture so the\n // auto-focus on open and focus-restore on close short-circuit on null trigger.\n if (previousActiveElement?.tagName === 'IFRAME') {\n triggerRef.current = null;\n return;\n }\n\n triggerRef.current = previousActiveElement;\n\n // Only move initial focus if autoFocus hasn't already placed it inside the container.\n if (!container.contains(document.activeElement)) {\n requestAnimationFrame(() => {\n resolveInitialFocusTarget(container, initialFocus)?.focus();\n });\n }\n\n // Restore focus on unmount while enabled (covers {isOpen && <Modal>} pattern\n // where the component unmounts before enabled can transition true → false)\n return () => {\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n };\n }, [enabled, containerRef, restoreFocus, initialFocus]);\n\n // Focus trap: Tab wrapping (only when enabled)\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Tab wrapping\n if (e.key === 'Tab') {\n const focusables = getFocusableElements({ container });\n\n if (focusables.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const activeElement = document.activeElement;\n\n if (e.shiftKey && activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [enabled, containerRef]);\n\n // Focus trap safety net: catch focus escaping\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as Node;\n\n // iframe focus is opaque from the parent doc — leave it alone, otherwise\n // a click into the iframe gets yanked back into the trap.\n if ((target as Element | null)?.tagName === 'IFRAME') return;\n\n if (container.contains(target)) {\n lastFocusedInContainer.current = target as HTMLElement;\n } else if (portalContainerRefs?.current?.some(ref => ref.current?.contains(target))) {\n // Focus is in a registered portal — allow it, but don't update\n // lastFocusedInContainer so safety net restores to the last main-container\n // element (e.g., the dropdown trigger) when the portal unmounts\n } else {\n // Focus escaped — redirect back\n const fallback = lastFocusedInContainer.current\n || getFirstFocusableElement({ container })\n || container;\n fallback.focus();\n }\n };\n\n document.addEventListener('focusin', handleFocusIn, true);\n return () => document.removeEventListener('focusin', handleFocusIn, true);\n }, [enabled, containerRef]);\n\n return { triggerRef };\n}\n"],"names":["_lastInteractedElement","_onPointerDown","e","path","composedPath","node","HTMLElement","tabIndex","_onKeyDown","key","document","activeElement","addEventListener","consumeLastInteractedElement","el","_focusAnchor","_focusAnchorClearFrame","setFocusAnchor","cancelAnimationFrame","requestAnimationFrame","consumeFocusAnchor","resolveInitialFocusTarget","container","initialFocus","getFirstFocusableElement","querySelector","useFocusTrap","enabled","containerRef","restoreFocus","returnFocusRef","portalContainerRefs","triggerRef","useRef","lastFocusedInContainer","useLayoutEffect","current","isConnected","focus","previousActiveElement","tagName","contains","handleKeyDown","focusables","getFocusableElements","length","preventDefault","first","last","shiftKey","removeEventListener","handleFocusIn","target","some","ref"],"mappings":"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"}
|