sb-floating-panel-vue 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,62 +1,103 @@
1
- import { Teleport as e, Transition as t, computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createVNode as o, defineComponent as s, inject as c, mergeModels as l, mergeProps as u, nextTick as d, normalizeStyle as f, onBeforeUnmount as p, onMounted as m, onScopeDispose as h, openBlock as g, provide as _, readonly as v, ref as y, renderSlot as b, resolveDynamicComponent as x, toRef as S, toValue as C, unref as w, useAttrs as T, useId as E, useModel as D, watch as O, watchEffect as k, withCtx as A } from "vue";
2
- import { autoUpdate as j, flip as M, hide as N, limitShift as P, offset as F, shift as ee, size as te, useFloating as I } from "@floating-ui/vue";
1
+ import { Teleport as e, Transition as t, computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createVNode as o, defineComponent as s, inject as c, mergeModels as l, mergeProps as u, nextTick as ee, normalizeStyle as d, onBeforeUnmount as f, onMounted as p, onScopeDispose as m, openBlock as h, provide as g, readonly as _, ref as v, renderSlot as te, resolveDynamicComponent as y, toRef as b, toValue as x, unref as S, useAttrs as C, useId as w, useModel as T, watch as E, watchEffect as D, withCtx as O } from "vue";
2
+ import { autoUpdate as k, flip as A, hide as j, limitShift as M, offset as N, shift as P, size as F, useFloating as ne } from "@floating-ui/vue";
3
+ //#region src/utils/dom.ts
4
+ var re = "data-sbf-focus-guard", I = [
5
+ "a[href]",
6
+ "button:not([disabled])",
7
+ "input:not([disabled]):not([type=\"hidden\"])",
8
+ "select:not([disabled])",
9
+ "textarea:not([disabled])",
10
+ "summary",
11
+ "audio[controls]",
12
+ "video[controls]",
13
+ "[tabindex]",
14
+ "[contenteditable=\"true\"]"
15
+ ].join(","), L = (e) => e.tabIndex >= 0 && !e.hasAttribute("data-sbf-focus-guard") && !e.closest("[inert]") && (e.checkVisibility?.() ?? !0);
16
+ function ie(e) {
17
+ let t = e && typeof e == "object" && "$el" in e ? e.$el : e;
18
+ return t instanceof HTMLElement ? t : null;
19
+ }
20
+ function R(e) {
21
+ let t = e instanceof Element ? e.closest(I) : null;
22
+ return !!t && !t.closest("[inert]");
23
+ }
24
+ function ae(e) {
25
+ try {
26
+ return e.matches(":focus-visible");
27
+ } catch {
28
+ return !0;
29
+ }
30
+ }
31
+ var oe = (e) => e.matches(I) && !e.closest("[inert]");
32
+ function z(e) {
33
+ return [...e.querySelectorAll(I)].filter(L);
34
+ }
35
+ function B(e, t) {
36
+ return z(e.ownerDocument).find((n) => !!(e.compareDocumentPosition(n) & Node.DOCUMENT_POSITION_FOLLOWING) && !e.contains(n) && !t(n));
37
+ }
38
+ //#endregion
3
39
  //#region src/utils/warn.ts
4
- var L = (() => {
40
+ var se = (() => {
5
41
  try {
6
42
  return process.env.NODE_ENV !== "production";
7
43
  } catch {
8
44
  return !1;
9
45
  }
10
46
  })();
11
- function R(e) {
12
- L && console.warn(`[sb-floating-panel-vue] ${e}`);
47
+ function V(e) {
48
+ se && console.warn(`[sb-floating-panel-vue] ${e}`);
13
49
  }
14
50
  //#endregion
15
51
  //#region src/composables/useSbFloatingContext.ts
16
- var z = Symbol("SbFloatingContext");
17
- function B(e, t, n) {
18
- return ++e.parts[t] > 1 && R(`<SbContainer> has more than one <${n}>: they share one open state and position, so only the last one works. Use one SbContainer for each panel.`), () => e.parts[t]--;
52
+ var H = (e) => e.parent?.navigation.value === "menu";
53
+ function U(e, t) {
54
+ let n = document.activeElement, r = e.reference.value;
55
+ return !n || !r || r.contains(n) || !e.contains(n) ? !1 : ((t ? r : B(r, (t) => e.contains(t)))?.focus({ preventScroll: !0 }), !0);
19
56
  }
20
- function ne(e) {
21
- let t = c(z, null);
57
+ var W = Symbol("SbFloatingContext");
58
+ function ce(e, t, n) {
59
+ return ++e.parts[t] > 1 && V(`<SbContainer> has more than one <${n}>: they share one open state and position, so only the last one works. Use one SbContainer for each panel.`), () => e.parts[t]--;
60
+ }
61
+ function le(e) {
62
+ let t = c(W, null);
22
63
  if (!t) throw Error(`[sb-floating-panel-vue] <${e}> must be used inside <SbContainer>.`);
23
64
  return t;
24
65
  }
25
66
  //#endregion
26
67
  //#region src/composables/useSbFloatingPanel.ts
27
- var V = (e) => `${Math.max(0, e)}px`, re = (e, t) => {
68
+ var G = (e) => `${Math.max(0, e)}px`, K = (e, t) => {
28
69
  let [n, r] = e.split("-"), i = t && (n === "top" || n === "bottom"), a = r === "start" ? i ? "100%" : "0%" : r === "end" ? i ? "0%" : "100%" : "50%";
29
70
  return n === "top" ? `${a} 100%` : n === "bottom" ? `${a} 0%` : n === "left" ? `100% ${a}` : `0% ${a}`;
30
71
  };
31
- function ie(e) {
32
- let t = y(null), r = y(null), i = n(() => {
33
- let t = C(e.padding), n = C(e.matchWidth), r = C(e.placement).includes("-"), i = M({
72
+ function q(e) {
73
+ let t = v(null), r = v(null), i = n(() => {
74
+ let t = x(e.padding), n = x(e.matchWidth), r = x(e.placement).includes("-"), i = A({
34
75
  padding: t,
35
76
  crossAxis: "alignment",
36
77
  fallbackAxisSideDirection: "end"
37
- }), a = ee({
78
+ }), a = P({
38
79
  padding: t,
39
- limiter: P()
80
+ limiter: M()
40
81
  }), o = [
41
- F(C(e.offset)),
82
+ N(x(e.offset)),
42
83
  ...r ? [i, a] : [a, i],
43
- te({
84
+ F({
44
85
  padding: t,
45
86
  apply({ rects: e, elements: t, availableWidth: r, availableHeight: i, placement: a }) {
46
- let { style: o } = t.floating, s = V(e.reference.width);
87
+ let { style: o } = t.floating, s = G(e.reference.width);
47
88
  o.setProperty("--sbf-reference-width", s);
48
89
  let c = getComputedStyle(t.floating).direction === "rtl";
49
- o.setProperty("--sbf-transform-origin", re(a, c)), o.setProperty("--sbf-available-width", V(r)), o.setProperty("--sbf-available-height", V(i)), o.width = n === !0 ? s : "", o.minWidth = n === "min" ? s : "";
90
+ o.setProperty("--sbf-transform-origin", K(a, c)), o.setProperty("--sbf-available-width", G(r)), o.setProperty("--sbf-available-height", G(i)), o.width = n === !0 ? s : "", o.minWidth = n === "min" ? s : "";
50
91
  }
51
92
  })
52
93
  ];
53
- return C(e.hideWhenDetached) && o.push(N({ padding: t })), o;
54
- }), { floatingStyles: a, middlewareData: o, placement: s, isPositioned: c, update: l } = I(t, r, {
55
- open: () => C(e.isOpen),
56
- placement: () => C(e.placement),
57
- strategy: () => C(e.strategy),
94
+ return x(e.hideWhenDetached) && o.push(j({ padding: t })), o;
95
+ }), { floatingStyles: a, middlewareData: o, placement: s, isPositioned: c, update: l } = ne(t, r, {
96
+ open: () => x(e.isOpen),
97
+ placement: () => x(e.placement),
98
+ strategy: () => x(e.strategy),
58
99
  middleware: i,
59
- whileElementsMounted: j
100
+ whileElementsMounted: k
60
101
  }), u = n(() => !!o.value.hide?.referenceHidden);
61
102
  return {
62
103
  reference: t,
@@ -74,37 +115,11 @@ function ie(e) {
74
115
  };
75
116
  }
76
117
  //#endregion
77
- //#region src/utils/dom.ts
78
- var ae = "data-sbf-focus-guard", H = [
79
- "a[href]",
80
- "button:not([disabled])",
81
- "input:not([disabled]):not([type=\"hidden\"])",
82
- "select:not([disabled])",
83
- "textarea:not([disabled])",
84
- "summary",
85
- "audio[controls]",
86
- "video[controls]",
87
- "[tabindex]",
88
- "[contenteditable=\"true\"]"
89
- ].join(","), oe = (e) => e.tabIndex >= 0 && !e.hasAttribute("data-sbf-focus-guard") && !e.closest("[inert]") && (e.checkVisibility?.() ?? !0);
90
- function se(e) {
91
- let t = e && typeof e == "object" && "$el" in e ? e.$el : e;
92
- return t instanceof HTMLElement ? t : null;
93
- }
94
- function U(e) {
95
- let t = e instanceof Element ? e.closest(H) : null;
96
- return !!t && !t.closest("[inert]");
97
- }
98
- var ce = (e) => e.matches(H) && !e.closest("[inert]");
99
- function W(e) {
100
- return [...e.querySelectorAll(H)].filter(oe);
101
- }
102
- function G(e, t) {
103
- return W(e.ownerDocument).find((n) => !!(e.compareDocumentPosition(n) & Node.DOCUMENT_POSITION_FOLLOWING) && !e.contains(n) && !t(n));
104
- }
105
- //#endregion
106
118
  //#region src/components/SbContainer.vue?vue&type=script&setup=true&lang.ts
107
- var K = [], le = /* @__PURE__ */ s({
119
+ var J = [], Y = {
120
+ open: 300,
121
+ close: 150
122
+ }, X = /* @__PURE__ */ s({
108
123
  inheritAttrs: !1,
109
124
  __name: "SbContainer",
110
125
  props: /*@__PURE__*/ l({
@@ -129,10 +144,7 @@ var K = [], le = /* @__PURE__ */ s({
129
144
  default: !1
130
145
  },
131
146
  trigger: { default: "click" },
132
- delay: { default: () => ({
133
- open: 300,
134
- close: 150
135
- }) },
147
+ delay: { default: () => ({ ...Y }) },
136
148
  closeOnEscape: {
137
149
  type: Boolean,
138
150
  default: !0
@@ -154,20 +166,17 @@ var K = [], le = /* @__PURE__ */ s({
154
166
  }),
155
167
  emits: /*@__PURE__*/ l(["open", "close"], ["update:open"]),
156
168
  setup(e, { expose: t, emit: r }) {
157
- let i = e, a = D(e, "open"), o = r, s = i.defaultOpen, l = n(() => !i.disabled && (a.value ?? s)), u;
158
- h(() => clearTimeout(u));
159
- let d = (e) => {
160
- clearTimeout(u), !(e && i.disabled) && e !== l.value && (a.value = e);
161
- }, f = () => d(!0), m = () => d(!1), g = () => d(!l.value), v = (e) => {
162
- if (e.pointerType === "touch" || (T?.hover(e), i.trigger !== "hover")) return;
169
+ let i = e, a = T(e, "open"), o = r, s = i.defaultOpen, l = n(() => !i.disabled && (a.value ?? s)), u;
170
+ m(() => clearTimeout(u));
171
+ let d, p = ((e, t) => {
172
+ clearTimeout(u), !(e && i.disabled) && e !== l.value && (d = t, a.value = e, ee(() => d = void 0));
173
+ }), h = () => p(!0, "api"), _ = () => p(!1, "api"), y = () => p(!l.value, "api"), x = (e) => {
174
+ if (e.pointerType === "touch" || (O?.hover(e), i.trigger !== "hover")) return;
163
175
  let t = e.type === "pointerenter" || k.contains(e.relatedTarget);
164
176
  if (clearTimeout(u), t === l.value) return;
165
- let { delay: n } = i, r = typeof n == "number" ? {
166
- open: n,
167
- close: n
168
- } : n, a = (t ? r.open : r.close) ?? (t ? 300 : 150);
169
- u = setTimeout(() => d(t), a);
170
- }, x = ie({
177
+ let { delay: n } = i, r = t ? "open" : "close", a = typeof n == "number" ? n : n[r] ?? Y[r];
178
+ u = setTimeout(() => p(t, "hover"), a);
179
+ }, C = q({
171
180
  isOpen: l,
172
181
  placement: () => i.placement,
173
182
  strategy: () => i.strategy,
@@ -175,38 +184,41 @@ var K = [], le = /* @__PURE__ */ s({
175
184
  padding: () => i.padding,
176
185
  matchWidth: () => i.matchWidth,
177
186
  hideWhenDetached: () => i.hideWhenDetached
178
- }), C = /* @__PURE__ */ new Set(), T = c(z, null), k = {
179
- ...x,
187
+ }), D = /* @__PURE__ */ new Set(), O = c(W, null), k = {
188
+ ...C,
180
189
  isOpen: l,
181
- disabled: S(i, "disabled"),
182
- trigger: S(i, "trigger"),
183
- floatingId: `${E()}-floating`,
184
- referenceId: y(),
185
- floatingRole: y("dialog"),
186
- navigation: y(null),
187
- focusRequest: y(null),
188
- parent: T,
190
+ disabled: b(i, "disabled"),
191
+ trigger: b(i, "trigger"),
192
+ floatingId: `${w()}-floating`,
193
+ referenceId: v(),
194
+ floatingRole: v("dialog"),
195
+ navigation: v(null),
196
+ focusRequest: v(null),
197
+ parent: O,
189
198
  skipFocusReturn: !1,
190
199
  parts: {
191
200
  reference: 0,
192
201
  floating: 0
193
202
  },
194
203
  isUnmounting: !1,
195
- open: f,
196
- close: m,
197
- toggle: g,
198
- hover: v,
199
- contains: (e) => e instanceof Node ? x.reference.value?.contains(e) || x.floating.value?.contains(e) ? !0 : [...C].some((t) => t.contains(e)) : !1,
200
- registerChild: (e) => (C.add(e), () => C.delete(e))
204
+ open: h,
205
+ close: _,
206
+ toggle: y,
207
+ setOpen: p,
208
+ hover: x,
209
+ contains: (e) => e instanceof Node ? C.reference.value?.contains(e) || C.floating.value?.contains(e) ? !0 : [...D].some((t) => t.contains(e)) : !1,
210
+ registerChild: (e) => (D.add(e), () => D.delete(e))
201
211
  };
202
- T && h(T.registerChild(k)), _(z, k), p(() => k.isUnmounting = !0);
212
+ O && m(O.registerChild(k)), g(W, k), f(() => {
213
+ k.isUnmounting = !0, U(k, !1);
214
+ });
203
215
  let A = (e) => {
204
216
  let t = e.composedPath()[0] ?? e.target;
205
- return K.findLast((e) => e.contains(t)) ?? K[K.length - 1];
217
+ return J.findLast((e) => e.contains(t)) ?? J[J.length - 1];
206
218
  }, j = (e) => {
207
- e.key === "Escape" && A(e) === k && (!i.closeOnEscape || e.defaultPrevented || e.isComposing || (e.preventDefault(), m()));
219
+ e.key === "Escape" && A(e) === k && (!i.closeOnEscape || e.defaultPrevented || e.isComposing || (e.preventDefault(), p(!1, "escape")));
208
220
  }, M = (e) => {
209
- k.contains(e) || (k.skipFocusReturn = U(e), m());
221
+ k.contains(e) || (k.skipFocusReturn = R(e), p(!1, "outside"));
210
222
  }, N, P = (e) => {
211
223
  if (N?.(), !i.closeOnClickOutside) return;
212
224
  let t = e.composedPath()[0] ?? e.target;
@@ -222,57 +234,60 @@ var K = [], le = /* @__PURE__ */ s({
222
234
  document.removeEventListener("click", n, !0), N = void 0;
223
235
  };
224
236
  }, F = (e) => {
225
- i.closeOnFocusOut && (k.contains(e.composedPath()[0] ?? e.target) || m());
237
+ i.closeOnFocusOut && (k.contains(e.composedPath()[0] ?? e.target) || p(!1, "focus-out"));
226
238
  };
227
- return O(l, (e, t, n) => {
228
- e && typeof document < "u" && (K.push(k), document.addEventListener("keydown", j), document.addEventListener("pointerdown", P, !0), document.addEventListener("focusin", F), n(() => {
229
- document.removeEventListener("keydown", j), document.removeEventListener("pointerdown", P, !0), document.removeEventListener("focusin", F), N?.(), K.splice(K.indexOf(k), 1);
239
+ return E(l, (e, t, n) => {
240
+ e && typeof document < "u" && (J.push(k), document.addEventListener("keydown", j), document.addEventListener("pointerdown", P, !0), document.addEventListener("focusin", F), n(() => {
241
+ document.removeEventListener("keydown", j), document.removeEventListener("pointerdown", P, !0), document.removeEventListener("focusin", F), N?.(), J.splice(J.indexOf(k), 1);
230
242
  }));
231
- }, { immediate: !0 }), O(l, (e) => o(e ? "open" : "close")), O(x.referenceHidden, (e) => {
232
- e && i.hideWhenDetached === "close" && m();
233
- }), O(() => i.disabled, (e) => {
243
+ }, { immediate: !0 }), E(l, (e) => {
244
+ let t = d ?? (!e && i.disabled ? "disabled" : "api");
245
+ d = void 0, o(e ? "open" : "close", t);
246
+ }), E(C.referenceHidden, (e) => {
247
+ e && i.hideWhenDetached === "close" && p(!1, "detached");
248
+ }), E(() => i.disabled, (e) => {
234
249
  e && (a.value ?? s) && (a.value = !1);
235
250
  }), t({
236
251
  get isOpen() {
237
252
  return l.value;
238
253
  },
239
- open: f,
240
- close: m,
241
- toggle: g,
242
- update: x.update
243
- }), (e, t) => b(e.$slots, "default", {
254
+ open: h,
255
+ close: _,
256
+ toggle: y,
257
+ update: C.update
258
+ }), (e, t) => te(e.$slots, "default", {
244
259
  isOpen: l.value,
245
- open: f,
246
- close: m,
247
- toggle: g,
248
- placement: w(x).placement.value,
249
- side: w(x).side.value,
250
- align: w(x).align.value,
260
+ open: h,
261
+ close: _,
262
+ toggle: y,
263
+ placement: S(C).placement.value,
264
+ side: S(C).side.value,
265
+ align: S(C).align.value,
251
266
  floatingId: k.floatingId,
252
267
  referenceId: k.referenceId.value
253
268
  });
254
269
  }
255
- }), q = {
270
+ }), ue = {
256
271
  dialog: "dialog",
257
272
  alertdialog: "dialog",
258
273
  menu: "menu",
259
274
  listbox: "listbox",
260
275
  tree: "tree",
261
276
  grid: "grid"
262
- }, J = {
277
+ }, Z = {
263
278
  menu: "[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"]",
264
279
  listbox: "[role=\"option\"]"
265
- }, ue = (e) => !!e && Object.hasOwn(J, e);
266
- function de(e, t) {
267
- return [...e.querySelectorAll(J[t])].filter((n) => n.closest(`[role="${t}"]`) === e && !n.matches(":disabled") && (n.checkVisibility?.() ?? !0));
280
+ }, de = (e) => !!e && Object.hasOwn(Z, e);
281
+ function fe(e, t) {
282
+ return [...e.querySelectorAll(Z[t])].filter((n) => n.closest(`[role="${t}"]`) === e && !n.matches(":disabled") && (n.checkVisibility?.() ?? !0));
268
283
  }
269
- var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [contenteditable]:not([contenteditable=\"false\"])"), fe = (e) => getComputedStyle(e).direction === "rtl" ? {
284
+ var Q = (e) => e instanceof Element && !!e.closest("input, textarea, select, [contenteditable]:not([contenteditable=\"false\"])"), pe = (e) => getComputedStyle(e).direction === "rtl" ? {
270
285
  open: "ArrowLeft",
271
286
  close: "ArrowRight"
272
287
  } : {
273
288
  open: "ArrowRight",
274
289
  close: "ArrowLeft"
275
- }, X = /* @__PURE__ */ s({
290
+ }, me = /* @__PURE__ */ s({
276
291
  __name: "SbReference",
277
292
  props: {
278
293
  as: { default: "button" },
@@ -280,68 +295,70 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
280
295
  ariaHaspopup: { default: void 0 }
281
296
  },
282
297
  setup(e) {
283
- let t = e, i = T(), a = ne("SbReference"), { isOpen: o, disabled: s, floatingId: c, floatingRole: l } = a, u = B(a, "reference", "SbReference"), d = [
298
+ let t = e, i = C(), a = le("SbReference"), { isOpen: o, disabled: s, floatingId: c, floatingRole: l } = a, u = ce(a, "reference", "SbReference"), ee = [
284
299
  "button",
285
300
  "input",
286
301
  "textarea",
287
302
  "select"
288
- ], f = () => typeof t.as != "string" || d.includes(t.as) || t.as === "a" && i.href != null, h = `${E()}-reference`, _ = n(() => t.id ?? h);
289
- k(() => {
290
- a.referenceId.value = _.value;
291
- }), m(() => {
292
- let e = a.reference.value;
293
- e ? Y(e) && a.navigation.value && R(`<SbReference> is a text field with a role="${a.navigation.value}" panel: the arrow keys move focus into the panel, so typing stops there. The combobox pattern (focus kept in the field with aria-activedescendant) is not supported.`) : R("<SbReference> rendered no element, so the panel cannot be positioned: a component in `as` must render a single root element.");
303
+ ], d = () => typeof t.as != "string" || ee.includes(t.as) || t.as === "a" && i.href != null, m = `${w()}-reference`, g = n(() => t.id ?? m);
304
+ D(() => {
305
+ a.referenceId.value = g.value;
294
306
  }), p(() => {
295
- a.referenceId.value === _.value && (a.referenceId.value = void 0), u(), !a.parts.reference && !a.isUnmounting && a.close();
307
+ let e = a.reference.value;
308
+ e ? Q(e) && a.navigation.value && V(`<SbReference> is a text field with a role="${a.navigation.value}" panel: the arrow keys move focus into the panel, so typing stops there. The combobox pattern (focus kept in the field with aria-activedescendant) is not supported.`) : V("<SbReference> rendered no element, so the panel cannot be positioned: a component in `as` must render a single root element.");
309
+ }), f(() => {
310
+ a.referenceId.value === g.value && (a.referenceId.value = void 0), u(), !a.parts.reference && !a.isUnmounting && (a.skipFocusReturn = U(a, !1), a.setOpen(!1, "api"));
296
311
  });
297
- let v = n(() => t.ariaHaspopup ?? (l.value && Object.hasOwn(q, l.value) ? q[l.value] : void 0)), y = (e) => {
298
- a.reference.value = se(e);
299
- }, S = () => {
300
- a.trigger.value === "click" && (Y(a.reference.value) ? a.open() : a.toggle());
301
- }, C = n(() => l.value === "tooltip"), D = () => a.trigger.value === "hover" || a.trigger.value === "focus", O = () => a.parent?.navigation.value === "menu", j = (e) => {
302
- D() && !O() && !a.contains(e.relatedTarget) && a.open();
303
- }, M = (e) => {
304
- D() && !a.contains(e.relatedTarget) && a.close();
305
- }, N = (e) => {
306
- let t = a.floating.value, n = t && W(t)[0];
312
+ let _ = n(() => t.ariaHaspopup ?? (l.value && Object.hasOwn(ue, l.value) ? ue[l.value] : void 0)), v = (e) => {
313
+ a.reference.value = ie(e);
314
+ }, b = () => {
315
+ a.trigger.value === "click" && (Q(a.reference.value) ? a.setOpen(!0, "trigger") : a.setOpen(!o.value, "trigger"));
316
+ }, x = n(() => l.value === "tooltip"), T = () => a.trigger.value === "hover" || a.trigger.value === "focus", E = (e) => {
317
+ if (!T() || H(a) || a.contains(e.relatedTarget)) return;
318
+ let t = e.target;
319
+ (a.trigger.value === "focus" || ae(t)) && a.setOpen(!0, "focus");
320
+ }, k = (e) => {
321
+ T() && !a.contains(e.relatedTarget) && a.setOpen(!1, "focus-out");
322
+ }, A = (e) => {
323
+ let t = a.floating.value, n = t && z(t)[0];
307
324
  n && (e.preventDefault(), n.focus());
308
- }, P = (e) => {
325
+ }, j = (e) => {
309
326
  if (a.navigation.value && !s.value && a.trigger.value !== "manual") {
310
- if (O()) {
327
+ if (H(a)) {
311
328
  let t = e.currentTarget;
312
- return e.key === fe(t).open ? "first" : void 0;
329
+ return e.key === pe(t).open ? "first" : void 0;
313
330
  }
314
331
  return e.key === "ArrowDown" ? "first" : e.key === "ArrowUp" ? "last" : void 0;
315
332
  }
316
- }, F = (e) => {
317
- if (e.key === "Tab" && !e.shiftKey && o.value && !O()) {
318
- N(e);
333
+ }, M = (e) => {
334
+ if (e.key === "Tab" && !e.shiftKey && o.value && !H(a)) {
335
+ A(e);
319
336
  return;
320
337
  }
321
- let t = P(e);
322
- t ? (e.preventDefault(), a.focusRequest.value = t, a.open()) : f() || e.key !== "Enter" && e.key !== " " || (e.preventDefault(), S());
338
+ let t = j(e);
339
+ t ? (e.preventDefault(), a.focusRequest.value = t, a.setOpen(!0, "trigger")) : d() || e.key !== "Enter" && e.key !== " " || (e.preventDefault(), b());
323
340
  };
324
- return (e, n) => (g(), r(x(t.as), {
325
- id: _.value,
326
- ref: y,
341
+ return (e, n) => (h(), r(y(t.as), {
342
+ id: g.value,
343
+ ref: v,
327
344
  type: t.as === "button" ? "button" : void 0,
328
- role: f() ? void 0 : "button",
329
- tabindex: f() ? void 0 : w(s) ? -1 : 0,
330
- disabled: t.as === "button" && w(s) ? !0 : void 0,
331
- "aria-disabled": t.as !== "button" && w(s) ? "true" : void 0,
332
- "aria-haspopup": v.value,
333
- "aria-expanded": C.value ? void 0 : w(o) ? "true" : "false",
334
- "aria-controls": w(o) && !C.value ? w(c) : void 0,
335
- "aria-describedby": w(o) && C.value ? w(c) : void 0,
336
- "data-sbf-state": w(o) ? "open" : "closed",
337
- onClick: S,
338
- onKeydown: F,
339
- onFocusin: j,
340
- onFocusout: M,
341
- onPointerenter: w(a).hover,
342
- onPointerleave: w(a).hover
345
+ role: d() ? void 0 : "button",
346
+ tabindex: d() ? void 0 : S(s) ? -1 : 0,
347
+ disabled: t.as === "button" && S(s) ? !0 : void 0,
348
+ "aria-disabled": t.as !== "button" && S(s) ? "true" : void 0,
349
+ "aria-haspopup": _.value,
350
+ "aria-expanded": x.value ? void 0 : S(o) ? "true" : "false",
351
+ "aria-controls": S(o) && !x.value ? S(c) : void 0,
352
+ "aria-describedby": S(o) && x.value ? S(c) : void 0,
353
+ "data-sbf-state": S(o) ? "open" : "closed",
354
+ onClick: b,
355
+ onKeydown: M,
356
+ onFocusin: E,
357
+ onFocusout: k,
358
+ onPointerenter: S(a).hover,
359
+ onPointerleave: S(a).hover
343
360
  }, {
344
- default: A(() => [b(e.$slots, "default")]),
361
+ default: O(() => [te(e.$slots, "default")]),
345
362
  _: 3
346
363
  }, 40, [
347
364
  "id",
@@ -359,7 +376,7 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
359
376
  "onPointerleave"
360
377
  ]));
361
378
  }
362
- }), pe = ":disabled, [aria-disabled=\"true\"], [aria-haspopup]:not([aria-haspopup=\"false\"])", me = /* @__PURE__ */ s({
379
+ }), he = ":disabled, [aria-disabled=\"true\"], [aria-haspopup]:not([aria-haspopup=\"false\"])", ge = /* @__PURE__ */ s({
363
380
  inheritAttrs: !1,
364
381
  __name: "SbFloating",
365
382
  props: {
@@ -386,26 +403,28 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
386
403
  },
387
404
  emits: ["after-enter", "after-leave"],
388
405
  setup(s, { emit: c }) {
389
- let l = s, _ = c, v = T(), S = ne("SbFloating");
390
- p(B(S, "floating", "SbFloating"));
391
- let { isOpen: C, floatingId: E, referenceId: D, side: j, align: M } = S;
392
- k(() => {
393
- S.floatingRole.value = l.role, S.navigation.value = l.keyboardNavigation && ue(l.role) ? l.role : null;
394
- }), m(() => {
395
- l.role === "tooltip" && S.trigger.value === "click" && R("<SbFloating role=\"tooltip\"> opens on click: a tooltip shows on hover and focus. Set trigger=\"hover\" or \"focus\" on SbContainer, or use another role for a panel opened by click.");
406
+ let l = s, g = c, _ = C(), b = le("SbFloating");
407
+ f(ce(b, "floating", "SbFloating")), f(() => {
408
+ b.isUnmounting || U(b, !0);
409
+ });
410
+ let { isOpen: x, floatingId: w, referenceId: T, side: k, align: A } = b;
411
+ D(() => {
412
+ b.floatingRole.value = l.role, b.navigation.value = l.keyboardNavigation && de(l.role) ? l.role : null;
413
+ }), p(() => {
414
+ l.role === "tooltip" && b.trigger.value === "click" && V("<SbFloating role=\"tooltip\"> opens on click: a tooltip shows on hover and focus. Set trigger=\"hover\" or \"focus\" on SbContainer, or use another role for a panel opened by click.");
396
415
  });
397
- let N = y(C.value), P = y(null), F = (e) => {
398
- S.floating.value = e instanceof HTMLElement ? e : null;
399
- }, ee = (e) => {
400
- P.value = se(e);
401
- }, te = n(() => ({
402
- ...S.floatingStyles.value,
416
+ let j = v(x.value), M = v(null), N = (e) => {
417
+ b.floating.value = e instanceof HTMLElement ? e : null;
418
+ }, P = (e) => {
419
+ M.value = ie(e);
420
+ }, F = n(() => ({
421
+ ...b.floatingStyles.value,
403
422
  ...l.zIndex === void 0 ? {} : { zIndex: l.zIndex }
404
- })), I = () => ({
405
- "aria-labelledby": l.role && Object.hasOwn(q, l.role) && v["aria-label"] == null ? D.value : void 0,
406
- ...v
407
- }), L = n(() => l.autoFocus ?? (l.role !== "tooltip" && S.trigger.value !== "hover" && S.trigger.value !== "focus" && !Y(S.reference.value))), z = n(() => C.value && l.teleport !== !1 && l.role !== "tooltip"), V = {
408
- [ae]: "",
423
+ })), ne = () => ({
424
+ "aria-labelledby": l.role && Object.hasOwn(ue, l.role) && _["aria-label"] == null ? T.value : void 0,
425
+ ..._
426
+ }), I = n(() => l.autoFocus ?? (l.role !== "tooltip" && b.trigger.value !== "hover" && b.trigger.value !== "focus" && !Q(b.reference.value))), L = n(() => x.value && l.teleport !== !1 && l.role !== "tooltip"), R = {
427
+ [re]: "",
409
428
  tabindex: 0,
410
429
  style: {
411
430
  position: "fixed",
@@ -413,90 +432,98 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
413
432
  outline: "none",
414
433
  pointerEvents: "none"
415
434
  }
416
- }, re = n(() => {
435
+ }, ae = n(() => {
417
436
  let { transition: e } = l;
418
437
  return e ? typeof e == "string" ? { name: e } : e : { css: !1 };
419
- }), ie = (e) => e.setAttribute("data-sbf-state", "closed"), H = () => _("after-enter"), oe = () => {
420
- C.value || (N.value = !1), _("after-leave");
421
- }, U = (e) => e instanceof Node && !!P.value?.contains(e), K = (e) => {
422
- let t = P.value;
438
+ }), se = (e) => e.setAttribute("data-sbf-state", "closed"), W = () => g("after-enter"), G = () => {
439
+ x.value || (j.value = !1), g("after-leave");
440
+ }, K = (e) => e instanceof Node && !!M.value?.contains(e), q = (e) => {
441
+ let t = M.value;
423
442
  if (!t) return;
424
- let n = W(t);
443
+ let n = z(t);
425
444
  ((e === "first" ? n[0] : n[n.length - 1]) ?? t).focus({ preventScroll: !0 });
426
- }, le = (e) => {
427
- U(e.relatedTarget) ? S.reference.value?.focus() : K("first");
428
445
  }, J = (e) => {
429
- if (!U(e.relatedTarget)) {
430
- K("last");
446
+ K(e.relatedTarget) ? b.reference.value?.focus() : q("first");
447
+ }, Y = (e) => {
448
+ if (!K(e.relatedTarget)) {
449
+ q("last");
431
450
  return;
432
451
  }
433
- let t = S.reference.value;
434
- ((t && G(t, (e) => S.contains(e))) ?? t)?.focus();
435
- }, X = () => {
436
- let e = S.navigation.value;
437
- return P.value && e ? de(P.value, e) : [];
452
+ let t = b.reference.value;
453
+ ((t && B(t, (e) => b.contains(e))) ?? t)?.focus();
454
+ }, X = (e) => {
455
+ if (e.key !== "Tab" || !e.shiftKey || e.defaultPrevented) return;
456
+ let t = b.reference.value;
457
+ t && M.value && z(M.value).length && (e.composedPath()[0] ?? e.target) === B(t, (e) => b.contains(e)) && (e.preventDefault(), q("last"));
458
+ };
459
+ E(L, (e, t, n) => {
460
+ e && typeof document < "u" && (document.addEventListener("keydown", X), n(() => document.removeEventListener("keydown", X)));
461
+ }, { immediate: !0 });
462
+ let Z = () => {
463
+ let e = b.navigation.value;
464
+ return M.value && e ? fe(M.value, e) : [];
438
465
  }, me = {
439
466
  menu: "[role=\"menuitem\"]",
440
467
  listbox: "[role=\"option\"]"
441
- }, he = {
468
+ }, ge = {
442
469
  menu: "role=\"menuitem\", \"menuitemcheckbox\" or \"menuitemradio\"",
443
470
  listbox: "role=\"option\""
444
- }, ge = !1, _e = (e) => {
445
- let t = S.navigation.value;
446
- if (ge || !t) return;
447
- let n = e.length ? e.every(ce) ? null : "has items that cannot take focus, so the arrow keys cannot move to them: make each one a button, or give it tabindex=\"-1\"." : `has no items the arrow keys can move to: items need ${he[t]} and must not be disabled.`;
448
- n && (ge = !0, R(`<SbFloating role="${t}"> ${n}`));
449
- }, ve = (e) => {
450
- let t = P.value;
471
+ }, _e = !1, ve = (e) => {
472
+ let t = b.navigation.value;
473
+ if (_e || !t) return;
474
+ let n = e.length ? e.every(oe) ? null : "has items that cannot take focus, so the arrow keys cannot move to them: make each one a button, or give it tabindex=\"-1\"." : `has no items the arrow keys can move to: items need ${ge[t]} and must not be disabled.`;
475
+ n && (_e = !0, V(`<SbFloating role="${t}"> ${n}`));
476
+ }, ye = (e) => {
477
+ let t = M.value;
451
478
  if (!t) return;
452
- let n = X();
453
- e && _e(n), (n.find((e) => e.getAttribute("aria-selected") === "true") ?? (e === "last" ? n[n.length - 1] : e ? n[0] : void 0) ?? t.querySelector("[autofocus]") ?? n[0] ?? W(t)[0] ?? t).focus({ preventScroll: !0 });
454
- }, Z = () => {
455
- let e = S.focusRequest.value;
456
- return S.focusRequest.value = null, e;
457
- }, Q = "", $;
458
- h(() => clearTimeout($));
459
- let ye = (e, t, n) => {
460
- Q += n.toLowerCase(), clearTimeout($), $ = setTimeout(() => Q = "", 500);
461
- let r = [...Q].every((e) => e === Q[0]) ? Q[0] : Q, i = Math.max(t, 0), a = [...e.slice(i), ...e.slice(0, i)];
462
- return r.length === 1 && t >= 0 && a.push(a.shift()), a.find((e) => e.textContent?.trim().toLowerCase().startsWith(r));
479
+ let n = Z();
480
+ e && ve(n), (n.find((e) => e.getAttribute("aria-selected") === "true") ?? (e === "last" ? n[n.length - 1] : e ? n[0] : void 0) ?? t.querySelector("[autofocus]") ?? n[0] ?? z(t)[0] ?? t).focus({ preventScroll: !0 });
463
481
  }, be = () => {
464
- let e = [S];
465
- for (; e[e.length - 1].parent?.navigation.value === "menu";) e.push(e[e.length - 1].parent);
482
+ let e = b.focusRequest.value;
483
+ return b.focusRequest.value = null, e;
484
+ }, $ = "", xe;
485
+ m(() => clearTimeout(xe));
486
+ let Se = (e, t, n) => {
487
+ $ += n.toLowerCase(), clearTimeout(xe), xe = setTimeout(() => $ = "", 500);
488
+ let r = [...$].every((e) => e === $[0]) ? $[0] : $, i = Math.max(t, 0), a = [...e.slice(i), ...e.slice(0, i)];
489
+ return r.length === 1 && t >= 0 && a.push(a.shift()), a.find((e) => e.textContent?.trim().toLowerCase().startsWith(r));
490
+ }, Ce = () => {
491
+ let e = [b];
492
+ for (; H(e[e.length - 1]);) e.push(e[e.length - 1].parent);
466
493
  return e;
467
- }, xe = (e, t) => {
468
- for (let t of e) t.skipFocusReturn = !0, t.close();
494
+ }, we = (e, t, n) => {
495
+ for (let t of e) t.skipFocusReturn = !0, t.setOpen(!1, n);
469
496
  t?.focus({ preventScroll: !0 });
470
- }, Se = (e) => {
471
- let t = be(), n = t[t.length - 1], r = n.reference.value, i = e ? r : (r && G(r, (e) => n.contains(e))) ?? r;
472
- xe(t, i);
473
- }, Ce = (e) => {
474
- let { role: t } = l, n = P.value;
475
- if (!l.closeOnSelect || e.defaultPrevented || !n || !ue(t)) return;
497
+ }, Te = (e) => {
498
+ let t = Ce(), n = t[t.length - 1], r = n.reference.value, i = e ? r : (r && B(r, (e) => n.contains(e))) ?? r;
499
+ we(t, i, "focus-out");
500
+ }, Ee = (e) => {
501
+ let { role: t } = l, n = M.value;
502
+ if (!l.closeOnSelect || e.defaultPrevented || !n || !de(t)) return;
476
503
  let r = e.target.closest(me[t]);
477
- if (!r || r.closest(`[role="${t}"]`) !== n || r.matches(pe) || t === "listbox" && n.getAttribute("aria-multiselectable") === "true") return;
478
- let i = t === "menu" ? be() : [S];
479
- xe(i, i[i.length - 1].reference.value);
480
- }, we = (e) => {
481
- let t = S.navigation.value;
482
- if (!t || e.defaultPrevented || e.isComposing || Y(e.target)) return;
483
- let n = X(), r = n.findIndex((t) => t.contains(e.target)), i = n.length - 1, a = t === "menu", o;
504
+ if (!r || r.closest(`[role="${t}"]`) !== n || r.matches(he) || t === "listbox" && n.getAttribute("aria-multiselectable") === "true") return;
505
+ let i = t === "menu" ? Ce() : [b];
506
+ we(i, i[i.length - 1].reference.value, "select");
507
+ }, De = (e) => {
508
+ let t = b.navigation.value;
509
+ if (!t || e.defaultPrevented || e.isComposing || Q(e.target)) return;
510
+ let n = Z(), r = n.findIndex((t) => t.contains(e.target)), i = n.length - 1, a = t === "menu", o;
484
511
  if ([
485
512
  "ArrowDown",
486
513
  "ArrowUp",
487
514
  "Home",
488
515
  "End"
489
- ].includes(e.key) && _e(n), e.key === "ArrowDown") o = n[r < i ? r + 1 : a ? 0 : i];
516
+ ].includes(e.key) && ve(n), e.key === "ArrowDown") o = n[r < i ? r + 1 : a ? 0 : i];
490
517
  else if (e.key === "ArrowUp") o = n[r > 0 ? r - 1 : a || r < 0 ? i : 0];
491
518
  else if (e.key === "Home") o = n[0];
492
519
  else if (e.key === "End") o = n[i];
493
520
  else if (e.key === "Tab" && t === "menu") {
494
- e.preventDefault(), Se(e.shiftKey);
521
+ e.preventDefault(), Te(e.shiftKey);
495
522
  return;
496
- } else if (t === "menu" && S.parent?.navigation.value === "menu" && P.value && e.key === fe(P.value).close) {
497
- e.preventDefault(), S.close();
523
+ } else if (t === "menu" && H(b) && M.value && e.key === pe(M.value).close) {
524
+ e.preventDefault(), b.setOpen(!1, "escape");
498
525
  return;
499
- } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && (e.key !== " " || Q)) e.preventDefault(), o = ye(n, r, e.key);
526
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && (e.key !== " " || $)) e.preventDefault(), o = Se(n, r, e.key);
500
527
  else if ((e.key === "Enter" || e.key === " ") && e.target === n[r]) {
501
528
  let t = n[r];
502
529
  if (t.matches("button, a[href], input, summary")) return;
@@ -505,49 +532,49 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
505
532
  }
506
533
  o && (e.preventDefault(), o.focus());
507
534
  };
508
- return O(C, (e) => {
509
- let t = S.skipFocusReturn;
510
- if (S.skipFocusReturn = !1, e) {
511
- N.value = !0;
535
+ return E(x, (e) => {
536
+ let t = b.skipFocusReturn;
537
+ if (b.skipFocusReturn = !1, e) {
538
+ j.value = !0;
512
539
  return;
513
540
  }
514
541
  let n = document.activeElement;
515
- !t && n && S.floating.value?.contains(n) && S.reference.value?.focus({ preventScroll: !0 });
516
- }), O(() => C.value && S.isPositioned.value, async (e) => {
542
+ !t && n && b.floating.value?.contains(n) && b.reference.value?.focus({ preventScroll: !0 });
543
+ }), E(() => x.value && b.isPositioned.value, async (e) => {
517
544
  if (!e) return;
518
- let t = Z();
519
- (t || L.value) && (await d(), ve(t));
520
- }), O(S.focusRequest, (e) => {
521
- e && C.value && S.isPositioned.value && ve(Z());
522
- }), (n, s) => (g(), r(e, {
545
+ let t = be();
546
+ (t || I.value) && (await ee(), ye(t));
547
+ }), E(b.focusRequest, (e) => {
548
+ e && x.value && b.isPositioned.value && ye(be());
549
+ }), (n, s) => (h(), r(e, {
523
550
  to: l.teleport || "body",
524
551
  disabled: l.teleport === !1
525
- }, [N.value ? (g(), a("div", {
552
+ }, [j.value ? (h(), a("div", {
526
553
  key: 0,
527
- ref: F,
528
- style: f(te.value),
529
- onPointerenter: s[0] ||= (...e) => w(S).hover && w(S).hover(...e),
530
- onPointerleave: s[1] ||= (...e) => w(S).hover && w(S).hover(...e)
554
+ ref: N,
555
+ style: d(F.value),
556
+ onPointerenter: s[0] ||= (...e) => S(b).hover && S(b).hover(...e),
557
+ onPointerleave: s[1] ||= (...e) => S(b).hover && S(b).hover(...e)
531
558
  }, [
532
- z.value ? (g(), a("span", u({ key: 0 }, V, { onFocus: le }), null, 16)) : i("", !0),
533
- o(t, u(re.value, {
559
+ L.value ? (h(), a("span", u({ key: 0 }, R, { onFocus: J }), null, 16)) : i("", !0),
560
+ o(t, u(ae.value, {
534
561
  appear: "",
535
- onBeforeLeave: ie,
536
- onAfterEnter: H,
537
- onAfterLeave: oe
562
+ onBeforeLeave: se,
563
+ onAfterEnter: W,
564
+ onAfterLeave: G
538
565
  }), {
539
- default: A(() => [w(C) ? (g(), r(x(l.as), u({ key: 0 }, I(), {
540
- id: w(E),
541
- ref: ee,
566
+ default: O(() => [S(x) ? (h(), r(y(l.as), u({ key: 0 }, ne(), {
567
+ id: S(w),
568
+ ref: P,
542
569
  role: l.role ?? void 0,
543
- tabindex: L.value ? -1 : void 0,
570
+ tabindex: I.value ? -1 : void 0,
544
571
  "data-sbf-state": "open",
545
- "data-sbf-side": w(j),
546
- "data-sbf-align": w(M),
547
- onKeydown: we,
548
- onClick: Ce
572
+ "data-sbf-side": S(k),
573
+ "data-sbf-align": S(A),
574
+ onKeydown: De,
575
+ onClick: Ee
549
576
  }), {
550
- default: A(() => [b(n.$slots, "default")]),
577
+ default: O(() => [te(n.$slots, "default")]),
551
578
  _: 3
552
579
  }, 16, [
553
580
  "id",
@@ -558,22 +585,22 @@ var Y = (e) => e instanceof Element && !!e.closest("input, textarea, select, [co
558
585
  ])) : i("", !0)]),
559
586
  _: 3
560
587
  }, 16),
561
- z.value ? (g(), a("span", u({ key: 1 }, V, { onFocus: J }), null, 16)) : i("", !0)
588
+ L.value ? (h(), a("span", u({ key: 1 }, R, { onFocus: Y }), null, 16)) : i("", !0)
562
589
  ], 36)) : i("", !0)], 8, ["to", "disabled"]));
563
590
  }
564
591
  });
565
592
  //#endregion
566
593
  //#region src/composables/useSbFloating.ts
567
- function he() {
568
- let e = c(z, null);
594
+ function _e() {
595
+ let e = c(W, null);
569
596
  if (!e) throw Error("[sb-floating-panel-vue] useSbFloating() must be called in a component inside <SbContainer>.");
570
597
  let { isOpen: t, open: n, close: r, toggle: i } = e;
571
598
  return {
572
- isOpen: v(t),
599
+ isOpen: _(t),
573
600
  open: n,
574
601
  close: r,
575
602
  toggle: i
576
603
  };
577
604
  }
578
605
  //#endregion
579
- export { le as SbContainer, me as SbFloating, X as SbReference, he as useSbFloating };
606
+ export { X as SbContainer, ge as SbFloating, me as SbReference, _e as useSbFloating };