@fiscozen/composables 0.1.13 → 0.1.16-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
1
- import { ref as f, reactive as M, onUnmounted as z, nextTick as P, onMounted as w, onBeforeUnmount as C, defineComponent as A, useSlots as N, computed as O, toRef as T, watch as $, openBlock as D, createElementBlock as W, createElementVNode as F, renderSlot as k, unref as S, withDirectives as q, normalizeClass as I, vShow as U } from "vue";
2
- const x = (o, t, i, n) => {
3
- let a = "right", e = "right-start";
4
- const c = o.getBoundingClientRect(), d = t.getBoundingClientRect(), r = i.getBoundingClientRect(), b = (r.left - c.left - d.width) / c.width, l = (c.right - r.right - d.width) / c.width, s = (r.top - c.top - d.height) / c.height, h = (c.bottom - r.bottom - d.height) / c.height;
5
- if (a = [
1
+ import { ref as f, reactive as q, onUnmounted as W, nextTick as I, onMounted as w, watch as B, onBeforeUnmount as C, defineComponent as U, useSlots as K, computed as O, toRef as Q, openBlock as x, createElementBlock as P, renderSlot as k, createElementVNode as S, unref as E, withDirectives as M, normalizeClass as A, vShow as N, createCommentVNode as D, createBlock as T, Teleport as X } from "vue";
2
+ const y = (n, o, i, s, a) => {
3
+ let t = a ? "bottom" : "right", p = a ? "bottom-start" : "right-start";
4
+ const l = n.getBoundingClientRect(), e = o.getBoundingClientRect(), c = i.getBoundingClientRect(), r = (c.left - l.left - e.width) / l.width, g = (l.right - c.right - e.width) / l.width, R = (c.top - l.top - e.height) / l.height, h = (l.bottom - c.bottom - e.height) / l.height;
5
+ let v = [
6
6
  {
7
7
  key: "right",
8
- space: l
8
+ space: g
9
9
  },
10
10
  {
11
11
  key: "top",
12
- space: s
12
+ space: R
13
13
  },
14
14
  {
15
15
  key: "bottom",
@@ -17,217 +17,266 @@ const x = (o, t, i, n) => {
17
17
  },
18
18
  {
19
19
  key: "left",
20
- space: b
20
+ space: r
21
21
  }
22
- ].sort((p, u) => u.space - p.space)[0].key, !n)
23
- switch (a) {
22
+ ].sort((u, m) => m.space - u.space);
23
+ if (a && (v = v.filter((u) => u.key === "top" || u.key === "bottom")), t = v[0].key, !s)
24
+ switch (t) {
24
25
  case "right":
25
26
  case "left":
26
- const p = (d.height - r.height) / 2;
27
- c.top > r.top - p && (n = "end"), c.bottom < r.top - p && (n = "start");
27
+ const u = (e.height - c.height) / 2;
28
+ l.top > c.top - u && (s = "end"), l.bottom < c.top - u && (s = "start");
28
29
  break;
29
30
  }
30
- return e = n ? `${a}-${n}` : a, e;
31
- }, K = (o, t, i, n) => ({
32
- x: t.x + o.width * i / 100,
33
- y: t.y + o.height * n / 100
34
- }), Q = (o) => {
35
- const t = f(null), i = f(null), n = f(null), a = f(null), e = M({
31
+ return p = s ? `${t}-${s}` : t, p;
32
+ }, Y = (n, o, i, s) => ({
33
+ x: o.x + n.width * i / 100,
34
+ y: o.y + n.height * s / 100
35
+ }), G = (n) => {
36
+ const o = f(null), i = f(null), s = f(null), a = f(), t = f(), p = f("auto"), l = f(), e = q({
36
37
  position: { x: 0, y: 0 }
37
38
  }), c = {
38
39
  root: null,
39
40
  rootMargin: "0px",
40
41
  threshold: 1,
41
- ...o.element.intersectionOptions
42
- }, d = (l, s) => {
43
- }, r = f(new IntersectionObserver(d, c)), b = () => P(() => {
44
- var E;
45
- if (t.value = typeof o.element.domRef.value == "string" ? document.querySelector(o.element.domRef.value) : o.element.domRef.value, o.container ? (i.value = typeof o.container.domRef.value == "string" ? document.querySelector(o.container.domRef.value) : o.container.domRef.value, i.value ?? (i.value = document.body)) : i.value = document.body, !t.value)
42
+ ...n.element.intersectionOptions
43
+ }, r = (h, v) => {
44
+ }, g = f(new IntersectionObserver(r, c));
45
+ p.value = n.position ? n.position.value : "auto";
46
+ const R = () => I(() => {
47
+ var L;
48
+ if (o.value = typeof n.element.domRef.value == "string" ? document.querySelector(n.element.domRef.value) : n.element.domRef.value, n.container ? (i.value = typeof n.container.domRef.value == "string" ? document.querySelector(n.container.domRef.value) : n.container.domRef.value, i.value ?? (i.value = document.body)) : i.value = document.body, !o.value)
46
49
  throw new Error("missing reference element for floating behavior");
47
- o.opener && (n.value = typeof o.opener.domRef.value == "string" ? document.querySelector(o.opener.domRef.value) : o.opener.domRef.value), a.value = t.value.getBoundingClientRect();
48
- const l = (E = n.value) == null ? void 0 : E.getBoundingClientRect(), s = i.value.getBoundingClientRect(), h = window.getComputedStyle(t.value);
49
- r.value.observe(t.value), r.value.observe(i.value);
50
- let v = o.position ? o.position.value : "auto", p = 0, u = 0;
51
- if (o.opener && n.value && l) {
52
- const g = l.left - parseFloat(h.marginLeft) - parseFloat(h.marginRight), L = l.left - parseFloat(h.marginLeft), y = l.top - parseFloat(h.marginTop) - parseFloat(h.marginBottom), B = l.top - parseFloat(h.marginTop);
53
- switch (v) {
50
+ n.opener && (s.value = typeof n.opener.domRef.value == "string" ? document.querySelector(n.opener.domRef.value) : n.opener.domRef.value), l.value = o.value.getBoundingClientRect(), a.value = (L = s.value) == null ? void 0 : L.getBoundingClientRect(), t.value = i.value.getBoundingClientRect();
51
+ const h = window.getComputedStyle(o.value);
52
+ g.value.observe(o.value), g.value.observe(i.value);
53
+ let v = 0, u = 0;
54
+ if (n.opener && s.value && a && a.value) {
55
+ const d = a.value.left - parseFloat(h.marginLeft) - parseFloat(h.marginRight), z = a.value.left - parseFloat(h.marginLeft), b = a.value.top - parseFloat(h.marginTop) - parseFloat(h.marginBottom), F = a.value.top - parseFloat(h.marginTop);
56
+ switch (p.value) {
54
57
  case "auto":
55
- v = x(
58
+ p.value = y(
56
59
  i.value,
57
- t.value,
58
- n.value
60
+ o.value,
61
+ s.value
62
+ );
63
+ break;
64
+ case "auto-vertical":
65
+ p.value = y(
66
+ i.value,
67
+ o.value,
68
+ s.value,
69
+ void 0,
70
+ !0
59
71
  );
60
72
  break;
61
73
  case "auto-start":
62
- v = x(
74
+ p.value = y(
63
75
  i.value,
64
- t.value,
65
- n.value,
76
+ o.value,
77
+ s.value,
66
78
  "start"
67
79
  );
68
80
  break;
81
+ case "auto-vertical-start":
82
+ p.value = y(
83
+ i.value,
84
+ o.value,
85
+ s.value,
86
+ "start",
87
+ !0
88
+ );
89
+ break;
69
90
  case "auto-end":
70
- v = x(
91
+ p.value = y(
71
92
  i.value,
72
- t.value,
73
- n.value,
93
+ o.value,
94
+ s.value,
74
95
  "end"
75
96
  );
76
97
  break;
98
+ case "auto-vertical-end":
99
+ p.value = y(
100
+ i.value,
101
+ o.value,
102
+ s.value,
103
+ "end",
104
+ !0
105
+ );
106
+ break;
77
107
  }
78
- switch (v) {
108
+ switch (p.value) {
79
109
  case "bottom":
80
- e.position.y = l.bottom, e.position.x = L + l.width / 2, u = -50, p = 0;
110
+ e.position.y = a.value.bottom, e.position.x = z + a.value.width / 2, u = -50, v = 0;
81
111
  break;
82
112
  case "bottom-start":
83
- e.position.y = l.bottom, e.position.x = g, u = 0, p = 0;
113
+ e.position.y = a.value.bottom, e.position.x = d, u = 0, v = 0;
84
114
  break;
85
115
  case "bottom-end":
86
- e.position.y = l.bottom, e.position.x = l.right, u = -100, p = 0;
116
+ e.position.y = a.value.bottom, e.position.x = a.value.right, u = -100, v = 0;
87
117
  break;
88
118
  case "left-start":
89
- e.position.y = y, e.position.x = g, u = -100, p = 0;
119
+ e.position.y = b, e.position.x = d, u = -100, v = 0;
90
120
  break;
91
121
  case "left":
92
- e.position.y = B + l.height / 2, e.position.x = g, p = -50, u = -100;
122
+ e.position.y = F + a.value.height / 2, e.position.x = d, v = -50, u = -100;
93
123
  break;
94
124
  case "left-end":
95
- e.position.y = l.bottom, e.position.x = g, p = -100, u = -100;
125
+ e.position.y = a.value.bottom, e.position.x = d, v = -100, u = -100;
96
126
  break;
97
127
  case "top-start":
98
- e.position.y = y, e.position.x = g, p = -100, u = 0;
128
+ e.position.y = b, e.position.x = d, v = -100, u = 0;
99
129
  break;
100
130
  case "top":
101
- e.position.y = y, e.position.x = L + l.width / 2, u = -50, p = -100;
131
+ e.position.y = b, e.position.x = z + a.value.width / 2, u = -50, v = -100;
102
132
  break;
103
133
  case "top-end":
104
- e.position.y = y, e.position.x = l.right, u = -100, p = -100;
134
+ e.position.y = b, e.position.x = a.value.right, u = -100, v = -100;
105
135
  break;
106
136
  case "right-start":
107
- e.position.y = y, e.position.x = l.right, u = 0, p = 0;
137
+ e.position.y = b, e.position.x = a.value.right, u = 0, v = 0;
108
138
  break;
109
139
  case "right":
110
- e.position.y = B + l.height / 2, e.position.x = l.right, p = -50, u = 0;
140
+ e.position.y = F + a.value.height / 2, e.position.x = a.value.right, v = -50, u = 0;
111
141
  break;
112
142
  case "right-end":
113
- e.position.y = l.bottom, e.position.x = l.right, p = -100, u = 0;
143
+ e.position.y = a.value.bottom, e.position.x = a.value.right, v = -100, u = 0;
114
144
  break;
115
145
  }
116
146
  } else
117
- switch (v) {
147
+ switch (p.value) {
118
148
  case "bottom":
119
- e.position.y = s.bottom - a.value.height, e.position.x = s.left + s.width / 2, u = -50;
149
+ e.position.y = t.value.bottom - l.value.height, e.position.x = t.value.left + t.value.width / 2, u = -50;
120
150
  break;
121
151
  case "left-end":
122
152
  case "bottom-start":
123
- e.position.y = s.bottom - a.value.height, e.position.x = s.left;
153
+ e.position.y = t.value.bottom - l.value.height, e.position.x = t.value.left;
124
154
  break;
125
155
  case "right-end":
126
156
  case "bottom-end":
127
- e.position.y = s.bottom - a.value.height, e.position.x = s.right - a.value.width;
157
+ e.position.y = t.value.bottom - l.value.height, e.position.x = t.value.right - l.value.width;
128
158
  break;
129
159
  case "left":
130
- e.position.y = s.top + (s.height - a.value.height) / 2, e.position.x = s.left;
160
+ e.position.y = t.value.top + (t.value.height - l.value.height) / 2, e.position.x = t.value.left;
131
161
  break;
132
162
  case "top-start":
133
163
  case "left-start":
134
- e.position.y = s.top, e.position.x = s.left;
164
+ e.position.y = t.value.top, e.position.x = t.value.left;
135
165
  break;
136
166
  case "top":
137
- e.position.y = s.top, e.position.x = s.left + (s.width - a.value.width) / 2;
167
+ e.position.y = t.value.top, e.position.x = t.value.left + (t.value.width - l.value.width) / 2;
138
168
  break;
139
169
  case "top-end":
140
170
  case "right-start":
141
- e.position.y = s.top, e.position.x = s.right - a.value.width;
171
+ e.position.y = t.value.top, e.position.x = t.value.right - l.value.width;
142
172
  case "right":
143
- e.position.y = s.top + (s.height - a.value.height) / 2, e.position.x = s.right - a.value.width;
173
+ e.position.y = t.value.top + (t.value.height - l.value.height) / 2, e.position.x = t.value.right - l.value.width;
144
174
  break;
145
175
  }
146
- const m = K(a.value, e.position, u, p);
147
- e.position.x = m.x, e.position.y = m.y, m.x < s.left && (e.position.x = s.left, u = 0), m.x + a.value.width > s.right && (e.position.x = s.right - a.value.width, u = 0), m.y < s.top && (e.position.y = s.top, p = 0), m.y + a.value.height > s.bottom && (e.position.y = s.bottom - a.value.height, p = 0), t.value.style.top = `${e.position.y}px`, t.value.style.left = `${e.position.x}px`, t.value.style.position = "fixed", t.value.style.display = "flex", a.value = t.value.getBoundingClientRect();
176
+ const m = Y(l.value, e.position, u, v);
177
+ if (e.position.x = m.x, e.position.y = m.y, m.x < t.value.left && (e.position.x = t.value.left, u = 0), m.x + l.value.width > t.value.right) {
178
+ const d = t.value.right - l.value.width;
179
+ d > 0 && (e.position.x = d), u = 0;
180
+ }
181
+ if (m.y < t.value.top && (e.position.y = t.value.top, v = 0), m.y + l.value.height > t.value.bottom) {
182
+ const d = t.value.bottom - l.value.height;
183
+ d > 0 && (e.position.y = d), v = 0;
184
+ }
185
+ o.value.style.top = `${e.position.y}px`, o.value.style.left = `${e.position.x}px`, o.value.style.display = "flex", l.value = o.value.getBoundingClientRect(), n.callback && n.callback(l, a, t, p);
148
186
  });
149
- return z(() => {
150
- r.value.disconnect();
187
+ return W(() => {
188
+ g.value.disconnect();
151
189
  }), {
152
190
  float: e,
153
- rect: a,
154
- floatObserver: r,
155
- setPosition: b
191
+ rect: l,
192
+ setPosition: R,
193
+ position: p,
194
+ openerRect: a,
195
+ containerRect: t
156
196
  };
157
197
  };
158
- function R(o) {
159
- const t = window.matchMedia(o), i = f(t.matches);
160
- function n(a) {
198
+ function $(n) {
199
+ const o = window.matchMedia(n), i = f(o.matches);
200
+ function s(a) {
161
201
  i.value = a.matches;
162
202
  }
163
203
  return w(() => {
164
- t.addEventListener("change", n);
165
- }), z(() => {
166
- t.removeEventListener("change", n);
204
+ o.addEventListener("change", s);
205
+ }), W(() => {
206
+ o.removeEventListener("change", s);
167
207
  }), i;
168
208
  }
169
- function Y(o) {
209
+ function J(n) {
170
210
  return {
171
- isGreater(t) {
172
- return R(`(min-width: ${o[t]})`);
211
+ isGreater(o) {
212
+ return $(`(min-width: ${n[o]})`);
173
213
  },
174
- isSmaller(t) {
175
- return R(`(max-width: ${o[t]})`);
214
+ isSmaller(o) {
215
+ return $(`(max-width: ${n[o]})`);
176
216
  },
177
- isInBetween(t, i) {
178
- return R(`(min-width: ${o[t]}) and (max-width: ${o[i]})`);
217
+ isInBetween(o, i) {
218
+ return $(`(min-width: ${n[o]}) and (max-width: ${n[i]})`);
179
219
  }
180
220
  };
181
221
  }
182
- function G(o, t) {
183
- if (!o)
222
+ function Z(n, o, i) {
223
+ if (!n)
184
224
  throw new Error("A target component has to be provided.");
185
- if (!t)
225
+ if (!o)
186
226
  throw new Error("A callback has to be provided.");
187
- const i = (n) => {
188
- !o.value || n.target === o.value || n.composedPath().includes(o.value) || typeof t == "function" && t();
227
+ const s = (a) => {
228
+ !n.value || a.target === n.value || a.composedPath().includes(n.value) || typeof o == "function" && o();
189
229
  };
190
- w(() => {
191
- window.addEventListener("click", i);
230
+ i && B(
231
+ i,
232
+ (a, t) => {
233
+ t && t.removeEventListener("click", s), a == null || a.addEventListener("click", s);
234
+ }
235
+ ), w(() => {
236
+ i || document.addEventListener("click", s);
192
237
  }), C(() => {
193
- window.removeEventListener("click", i);
238
+ if (i) {
239
+ i.value.removeEventListener("click", s);
240
+ return;
241
+ }
242
+ document.removeEventListener("click", s);
194
243
  });
195
244
  }
196
- function H(o, t) {
197
- if (!o)
245
+ function V(n, o) {
246
+ if (!n)
198
247
  throw new Error("A target component has to be provided.");
199
- if (!t || typeof t != "function")
248
+ if (!o || typeof o != "function")
200
249
  throw new Error("A callback has to be provided.");
201
- const i = (n) => {
202
- t(n);
250
+ const i = (s) => {
251
+ o(s);
203
252
  };
204
253
  w(() => {
205
- o.value.addEventListener("keydown", i);
254
+ n.value.addEventListener("keydown", i);
206
255
  }), C(() => {
207
- o.value.removeEventListener("keydown", i);
256
+ n.value.removeEventListener("keydown", i);
208
257
  });
209
258
  }
210
- function V(o, t) {
211
- if (!o || typeof o != "function")
259
+ function _(n, o) {
260
+ if (!n || typeof n != "function")
212
261
  throw new Error("A callback has to be provided.");
213
- const i = (n) => {
214
- o(n);
262
+ const i = (s) => {
263
+ n(s);
215
264
  };
216
265
  w(() => {
217
- if (!t) {
266
+ if (!o) {
218
267
  document.addEventListener("keyup", i);
219
268
  return;
220
269
  }
221
- t.value.addEventListener("keyup", i);
270
+ o.value.addEventListener("keyup", i);
222
271
  }), C(() => {
223
- if (!t) {
272
+ if (!o) {
224
273
  document.removeEventListener("keyup", i);
225
274
  return;
226
275
  }
227
- t.value.removeEventListener("keyup", i);
276
+ o.value.removeEventListener("keyup", i);
228
277
  });
229
278
  }
230
- const J = /* @__PURE__ */ A({
279
+ const j = /* @__PURE__ */ U({
231
280
  __name: "FzFloating",
232
281
  props: {
233
282
  isOpen: { type: Boolean, default: !1 },
@@ -235,65 +284,91 @@ const J = /* @__PURE__ */ A({
235
284
  container: {},
236
285
  contentClass: {},
237
286
  openerClass: {},
238
- overrideContentClass: { type: Boolean }
287
+ overrideContentClass: { type: Boolean },
288
+ teleport: { type: Boolean, default: !1 }
239
289
  },
240
- setup(o) {
241
- const t = o, i = f(null), n = f(null), a = N(), e = {
242
- position: O(() => t.position),
290
+ emits: ["fzfloating:setPosition"],
291
+ setup(n, { emit: o }) {
292
+ const i = n, s = o, a = f(null), t = f(null), p = K(), l = {
293
+ position: O(() => i.position),
243
294
  element: {
244
- domRef: n
295
+ // @ts-ignore
296
+ domRef: t
245
297
  },
246
298
  container: {
247
- domRef: T(t.container || document.body)
299
+ // @ts-ignore
300
+ domRef: Q(i.container || document.body)
301
+ },
302
+ callback(...r) {
303
+ s("fzfloating:setPosition", ...r);
248
304
  }
249
305
  };
250
- a.opener && (e.opener = {
251
- domRef: i
306
+ p.opener && (l.opener = {
307
+ domRef: a
252
308
  });
253
- const c = Q(e);
254
- $(
255
- () => t.position,
256
- () => t.isOpen && c.setPosition()
257
- ), $(
258
- () => t.isOpen,
309
+ const e = G(l);
310
+ B(
311
+ () => i.position,
312
+ () => i.isOpen && e.setPosition()
313
+ ), B(
314
+ () => i.isOpen,
259
315
  (r) => {
260
- !r || !n.value || (n.value.style.top = "0px", n.value.style.left = "0px", n.value.style.transform = "none", c.setPosition());
316
+ !r || !t.value || (t.value.style.top = "0px", t.value.style.left = "0px", t.value.style.transform = "none", e.setPosition());
261
317
  }
262
318
  );
263
- const d = O(() => t.overrideContentClass ? t.contentClass : ["bg-core-white fixed p-4 z-10", t.contentClass]);
264
- return (r, b) => (D(), W("div", null, [
265
- F("div", {
319
+ const c = O(() => i.overrideContentClass ? i.contentClass : ["bg-core-white fixed p-4 z-10", i.contentClass]);
320
+ return (r, g) => (x(), P("div", null, [
321
+ k(r.$slots, "opener-start"),
322
+ S("div", {
266
323
  ref_key: "opener",
267
- ref: i,
324
+ ref: a,
268
325
  class: "inline-flex"
269
326
  }, [
270
327
  k(r.$slots, "opener", {
271
328
  isOpen: r.isOpen,
272
- floating: S(c)
329
+ floating: E(e)
273
330
  })
274
331
  ], 512),
275
332
  k(r.$slots, "opener-end"),
276
- q(F("div", {
333
+ r.teleport ? D("", !0) : M((x(), P("div", {
334
+ key: 0,
277
335
  ref_key: "content",
278
- ref: n,
279
- class: I(d.value)
336
+ ref: t,
337
+ class: A(["fz__floating__content bg-core-white fixed p-4 z-10", c.value])
280
338
  }, [
281
339
  k(r.$slots, "default", {
282
340
  isOpen: r.isOpen,
283
- floating: S(c)
341
+ floating: E(e)
284
342
  })
285
- ], 2), [
286
- [U, r.$slots.default && (!r.$slots.opener || r.$slots.opener && r.isOpen)]
287
- ])
343
+ ], 2)), [
344
+ [N, r.$slots.default && (!r.$slots.opener || r.$slots.opener && r.isOpen)]
345
+ ]),
346
+ r.teleport ? (x(), T(X, {
347
+ key: 1,
348
+ to: "body"
349
+ }, [
350
+ M(S("div", {
351
+ ref_key: "content",
352
+ ref: t,
353
+ class: A(["fz__floating__content bg-core-white absolute p-4 z-10", c.value])
354
+ }, [
355
+ k(r.$slots, "default", {
356
+ isOpen: r.isOpen,
357
+ floating: E(e)
358
+ })
359
+ ], 2), [
360
+ [N, r.$slots.default && (!r.$slots.opener || r.$slots.opener && r.isOpen)]
361
+ ])
362
+ ])) : D("", !0)
288
363
  ]));
289
364
  }
290
365
  });
291
366
  export {
292
- J as FzFloating,
293
- Y as useBreakpoints,
294
- G as useClickOutside,
295
- Q as useFloating,
296
- H as useKeyDown,
297
- V as useKeyUp,
298
- R as useMediaQuery
367
+ j as FzFloating,
368
+ J as useBreakpoints,
369
+ Z as useClickOutside,
370
+ G as useFloating,
371
+ V as useKeyDown,
372
+ _ as useKeyUp,
373
+ $ as useMediaQuery
299
374
  };
@@ -1 +1 @@
1
- (function(f,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],o):(f=typeof globalThis<"u"?globalThis:f||self,o(f.FzComposables={},f.Vue))})(this,function(f,o){"use strict";const x=(n,t,i,s)=>{let r="right",e="right-start";const d=n.getBoundingClientRect(),h=t.getBoundingClientRect(),l=i.getBoundingClientRect(),k=(l.left-d.left-h.width)/d.width,p=(d.right-l.right-h.width)/d.width,a=(l.top-d.top-h.height)/d.height,m=(d.bottom-l.bottom-h.height)/d.height;if(r=[{key:"right",space:p},{key:"top",space:a},{key:"bottom",space:m},{key:"left",space:k}].sort((c,u)=>u.space-c.space)[0].key,!s)switch(r){case"right":case"left":const c=(h.height-l.height)/2;d.top>l.top-c&&(s="end"),d.bottom<l.top-c&&(s="start");break}return e=s?`${r}-${s}`:r,e},L=(n,t,i,s)=>({x:t.x+n.width*i/100,y:t.y+n.height*s/100}),R=n=>{const t=o.ref(null),i=o.ref(null),s=o.ref(null),r=o.ref(null),e=o.reactive({position:{x:0,y:0}}),d={root:null,rootMargin:"0px",threshold:1,...n.element.intersectionOptions},h=(p,a)=>{},l=o.ref(new IntersectionObserver(h,d)),k=()=>o.nextTick(()=>{var C;if(t.value=typeof n.element.domRef.value=="string"?document.querySelector(n.element.domRef.value):n.element.domRef.value,n.container?(i.value=typeof n.container.domRef.value=="string"?document.querySelector(n.container.domRef.value):n.container.domRef.value,i.value??(i.value=document.body)):i.value=document.body,!t.value)throw new Error("missing reference element for floating behavior");n.opener&&(s.value=typeof n.opener.domRef.value=="string"?document.querySelector(n.opener.domRef.value):n.opener.domRef.value),r.value=t.value.getBoundingClientRect();const p=(C=s.value)==null?void 0:C.getBoundingClientRect(),a=i.value.getBoundingClientRect(),m=window.getComputedStyle(t.value);l.value.observe(t.value),l.value.observe(i.value);let g=n.position?n.position.value:"auto",c=0,u=0;if(n.opener&&s.value&&p){const v=p.left-parseFloat(m.marginLeft)-parseFloat(m.marginRight),E=p.left-parseFloat(m.marginLeft),b=p.top-parseFloat(m.marginTop)-parseFloat(m.marginBottom),B=p.top-parseFloat(m.marginTop);switch(g){case"auto":g=x(i.value,t.value,s.value);break;case"auto-start":g=x(i.value,t.value,s.value,"start");break;case"auto-end":g=x(i.value,t.value,s.value,"end");break}switch(g){case"bottom":e.position.y=p.bottom,e.position.x=E+p.width/2,u=-50,c=0;break;case"bottom-start":e.position.y=p.bottom,e.position.x=v,u=0,c=0;break;case"bottom-end":e.position.y=p.bottom,e.position.x=p.right,u=-100,c=0;break;case"left-start":e.position.y=b,e.position.x=v,u=-100,c=0;break;case"left":e.position.y=B+p.height/2,e.position.x=v,c=-50,u=-100;break;case"left-end":e.position.y=p.bottom,e.position.x=v,c=-100,u=-100;break;case"top-start":e.position.y=b,e.position.x=v,c=-100,u=0;break;case"top":e.position.y=b,e.position.x=E+p.width/2,u=-50,c=-100;break;case"top-end":e.position.y=b,e.position.x=p.right,u=-100,c=-100;break;case"right-start":e.position.y=b,e.position.x=p.right,u=0,c=0;break;case"right":e.position.y=B+p.height/2,e.position.x=p.right,c=-50,u=0;break;case"right-end":e.position.y=p.bottom,e.position.x=p.right,c=-100,u=0;break}}else switch(g){case"bottom":e.position.y=a.bottom-r.value.height,e.position.x=a.left+a.width/2,u=-50;break;case"left-end":case"bottom-start":e.position.y=a.bottom-r.value.height,e.position.x=a.left;break;case"right-end":case"bottom-end":e.position.y=a.bottom-r.value.height,e.position.x=a.right-r.value.width;break;case"left":e.position.y=a.top+(a.height-r.value.height)/2,e.position.x=a.left;break;case"top-start":case"left-start":e.position.y=a.top,e.position.x=a.left;break;case"top":e.position.y=a.top,e.position.x=a.left+(a.width-r.value.width)/2;break;case"top-end":case"right-start":e.position.y=a.top,e.position.x=a.right-r.value.width;case"right":e.position.y=a.top+(a.height-r.value.height)/2,e.position.x=a.right-r.value.width;break}const y=L(r.value,e.position,u,c);e.position.x=y.x,e.position.y=y.y,y.x<a.left&&(e.position.x=a.left,u=0),y.x+r.value.width>a.right&&(e.position.x=a.right-r.value.width,u=0),y.y<a.top&&(e.position.y=a.top,c=0),y.y+r.value.height>a.bottom&&(e.position.y=a.bottom-r.value.height,c=0),t.value.style.top=`${e.position.y}px`,t.value.style.left=`${e.position.x}px`,t.value.style.position="fixed",t.value.style.display="flex",r.value=t.value.getBoundingClientRect()});return o.onUnmounted(()=>{l.value.disconnect()}),{float:e,rect:r,floatObserver:l,setPosition:k}};function w(n){const t=window.matchMedia(n),i=o.ref(t.matches);function s(r){i.value=r.matches}return o.onMounted(()=>{t.addEventListener("change",s)}),o.onUnmounted(()=>{t.removeEventListener("change",s)}),i}function O(n){return{isGreater(t){return w(`(min-width: ${n[t]})`)},isSmaller(t){return w(`(max-width: ${n[t]})`)},isInBetween(t,i){return w(`(min-width: ${n[t]}) and (max-width: ${n[i]})`)}}}function F(n,t){if(!n)throw new Error("A target component has to be provided.");if(!t)throw new Error("A callback has to be provided.");const i=s=>{!n.value||s.target===n.value||s.composedPath().includes(n.value)||typeof t=="function"&&t()};o.onMounted(()=>{window.addEventListener("click",i)}),o.onBeforeUnmount(()=>{window.removeEventListener("click",i)})}function S(n,t){if(!n)throw new Error("A target component has to be provided.");if(!t||typeof t!="function")throw new Error("A callback has to be provided.");const i=s=>{t(s)};o.onMounted(()=>{n.value.addEventListener("keydown",i)}),o.onBeforeUnmount(()=>{n.value.removeEventListener("keydown",i)})}function $(n,t){if(!n||typeof n!="function")throw new Error("A callback has to be provided.");const i=s=>{n(s)};o.onMounted(()=>{if(!t){document.addEventListener("keyup",i);return}t.value.addEventListener("keyup",i)}),o.onBeforeUnmount(()=>{if(!t){document.removeEventListener("keyup",i);return}t.value.removeEventListener("keyup",i)})}const M=o.defineComponent({__name:"FzFloating",props:{isOpen:{type:Boolean,default:!1},position:{default:"auto"},container:{},contentClass:{},openerClass:{},overrideContentClass:{type:Boolean}},setup(n){const t=n,i=o.ref(null),s=o.ref(null),r=o.useSlots(),e={position:o.computed(()=>t.position),element:{domRef:s},container:{domRef:o.toRef(t.container||document.body)}};r.opener&&(e.opener={domRef:i});const d=R(e);o.watch(()=>t.position,()=>t.isOpen&&d.setPosition()),o.watch(()=>t.isOpen,l=>{!l||!s.value||(s.value.style.top="0px",s.value.style.left="0px",s.value.style.transform="none",d.setPosition())});const h=o.computed(()=>t.overrideContentClass?t.contentClass:["bg-core-white fixed p-4 z-10",t.contentClass]);return(l,k)=>(o.openBlock(),o.createElementBlock("div",null,[o.createElementVNode("div",{ref_key:"opener",ref:i,class:"inline-flex"},[o.renderSlot(l.$slots,"opener",{isOpen:l.isOpen,floating:o.unref(d)})],512),o.renderSlot(l.$slots,"opener-end"),o.withDirectives(o.createElementVNode("div",{ref_key:"content",ref:s,class:o.normalizeClass(h.value)},[o.renderSlot(l.$slots,"default",{isOpen:l.isOpen,floating:o.unref(d)})],2),[[o.vShow,l.$slots.default&&(!l.$slots.opener||l.$slots.opener&&l.isOpen)]])]))}});f.FzFloating=M,f.useBreakpoints=O,f.useClickOutside=F,f.useFloating=R,f.useKeyDown=S,f.useKeyUp=$,f.useMediaQuery=w,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(d=typeof globalThis<"u"?globalThis:d||self,t(d.FzComposables={},d.Vue))})(this,function(d,t){"use strict";const y=(a,n,i,s,l)=>{let o=l?"bottom":"right",f=l?"bottom-start":"right-start";const r=a.getBoundingClientRect(),e=n.getBoundingClientRect(),v=i.getBoundingClientRect(),u=(v.left-r.left-e.width)/r.width,b=(r.right-v.right-e.width)/r.width,R=(v.top-r.top-e.height)/r.height,m=(r.bottom-v.bottom-e.height)/r.height;let p=[{key:"right",space:b},{key:"top",space:R},{key:"bottom",space:m},{key:"left",space:u}].sort((c,g)=>g.space-c.space);if(l&&(p=p.filter(c=>c.key==="top"||c.key==="bottom")),o=p[0].key,!s)switch(o){case"right":case"left":const c=(e.height-v.height)/2;r.top>v.top-c&&(s="end"),r.bottom<v.top-c&&(s="start");break}return f=s?`${o}-${s}`:o,f},$=(a,n,i,s)=>({x:n.x+a.width*i/100,y:n.y+a.height*s/100}),B=a=>{const n=t.ref(null),i=t.ref(null),s=t.ref(null),l=t.ref(),o=t.ref(),f=t.ref("auto"),r=t.ref(),e=t.reactive({position:{x:0,y:0}}),v={root:null,rootMargin:"0px",threshold:1,...a.element.intersectionOptions},u=(m,p)=>{},b=t.ref(new IntersectionObserver(u,v));f.value=a.position?a.position.value:"auto";const R=()=>t.nextTick(()=>{var E;if(n.value=typeof a.element.domRef.value=="string"?document.querySelector(a.element.domRef.value):a.element.domRef.value,a.container?(i.value=typeof a.container.domRef.value=="string"?document.querySelector(a.container.domRef.value):a.container.domRef.value,i.value??(i.value=document.body)):i.value=document.body,!n.value)throw new Error("missing reference element for floating behavior");a.opener&&(s.value=typeof a.opener.domRef.value=="string"?document.querySelector(a.opener.domRef.value):a.opener.domRef.value),r.value=n.value.getBoundingClientRect(),l.value=(E=s.value)==null?void 0:E.getBoundingClientRect(),o.value=i.value.getBoundingClientRect();const m=window.getComputedStyle(n.value);b.value.observe(n.value),b.value.observe(i.value);let p=0,c=0;if(a.opener&&s.value&&l&&l.value){const h=l.value.left-parseFloat(m.marginLeft)-parseFloat(m.marginRight),x=l.value.left-parseFloat(m.marginLeft),k=l.value.top-parseFloat(m.marginTop)-parseFloat(m.marginBottom),C=l.value.top-parseFloat(m.marginTop);switch(f.value){case"auto":f.value=y(i.value,n.value,s.value);break;case"auto-vertical":f.value=y(i.value,n.value,s.value,void 0,!0);break;case"auto-start":f.value=y(i.value,n.value,s.value,"start");break;case"auto-vertical-start":f.value=y(i.value,n.value,s.value,"start",!0);break;case"auto-end":f.value=y(i.value,n.value,s.value,"end");break;case"auto-vertical-end":f.value=y(i.value,n.value,s.value,"end",!0);break}switch(f.value){case"bottom":e.position.y=l.value.bottom,e.position.x=x+l.value.width/2,c=-50,p=0;break;case"bottom-start":e.position.y=l.value.bottom,e.position.x=h,c=0,p=0;break;case"bottom-end":e.position.y=l.value.bottom,e.position.x=l.value.right,c=-100,p=0;break;case"left-start":e.position.y=k,e.position.x=h,c=-100,p=0;break;case"left":e.position.y=C+l.value.height/2,e.position.x=h,p=-50,c=-100;break;case"left-end":e.position.y=l.value.bottom,e.position.x=h,p=-100,c=-100;break;case"top-start":e.position.y=k,e.position.x=h,p=-100,c=0;break;case"top":e.position.y=k,e.position.x=x+l.value.width/2,c=-50,p=-100;break;case"top-end":e.position.y=k,e.position.x=l.value.right,c=-100,p=-100;break;case"right-start":e.position.y=k,e.position.x=l.value.right,c=0,p=0;break;case"right":e.position.y=C+l.value.height/2,e.position.x=l.value.right,p=-50,c=0;break;case"right-end":e.position.y=l.value.bottom,e.position.x=l.value.right,p=-100,c=0;break}}else switch(f.value){case"bottom":e.position.y=o.value.bottom-r.value.height,e.position.x=o.value.left+o.value.width/2,c=-50;break;case"left-end":case"bottom-start":e.position.y=o.value.bottom-r.value.height,e.position.x=o.value.left;break;case"right-end":case"bottom-end":e.position.y=o.value.bottom-r.value.height,e.position.x=o.value.right-r.value.width;break;case"left":e.position.y=o.value.top+(o.value.height-r.value.height)/2,e.position.x=o.value.left;break;case"top-start":case"left-start":e.position.y=o.value.top,e.position.x=o.value.left;break;case"top":e.position.y=o.value.top,e.position.x=o.value.left+(o.value.width-r.value.width)/2;break;case"top-end":case"right-start":e.position.y=o.value.top,e.position.x=o.value.right-r.value.width;case"right":e.position.y=o.value.top+(o.value.height-r.value.height)/2,e.position.x=o.value.right-r.value.width;break}const g=$(r.value,e.position,c,p);if(e.position.x=g.x,e.position.y=g.y,g.x<o.value.left&&(e.position.x=o.value.left,c=0),g.x+r.value.width>o.value.right){const h=o.value.right-r.value.width;h>0&&(e.position.x=h),c=0}if(g.y<o.value.top&&(e.position.y=o.value.top,p=0),g.y+r.value.height>o.value.bottom){const h=o.value.bottom-r.value.height;h>0&&(e.position.y=h),p=0}n.value.style.top=`${e.position.y}px`,n.value.style.left=`${e.position.x}px`,n.value.style.display="flex",r.value=n.value.getBoundingClientRect(),a.callback&&a.callback(r,l,o,f)});return t.onUnmounted(()=>{b.value.disconnect()}),{float:e,rect:r,setPosition:R,position:f,openerRect:l,containerRect:o}};function w(a){const n=window.matchMedia(a),i=t.ref(n.matches);function s(l){i.value=l.matches}return t.onMounted(()=>{n.addEventListener("change",s)}),t.onUnmounted(()=>{n.removeEventListener("change",s)}),i}function S(a){return{isGreater(n){return w(`(min-width: ${a[n]})`)},isSmaller(n){return w(`(max-width: ${a[n]})`)},isInBetween(n,i){return w(`(min-width: ${a[n]}) and (max-width: ${a[i]})`)}}}function z(a,n,i){if(!a)throw new Error("A target component has to be provided.");if(!n)throw new Error("A callback has to be provided.");const s=l=>{!a.value||l.target===a.value||l.composedPath().includes(a.value)||typeof n=="function"&&n()};i&&t.watch(i,(l,o)=>{o&&o.removeEventListener("click",s),l==null||l.addEventListener("click",s)}),t.onMounted(()=>{i||document.addEventListener("click",s)}),t.onBeforeUnmount(()=>{if(i){i.value.removeEventListener("click",s);return}document.removeEventListener("click",s)})}function L(a,n){if(!a)throw new Error("A target component has to be provided.");if(!n||typeof n!="function")throw new Error("A callback has to be provided.");const i=s=>{n(s)};t.onMounted(()=>{a.value.addEventListener("keydown",i)}),t.onBeforeUnmount(()=>{a.value.removeEventListener("keydown",i)})}function F(a,n){if(!a||typeof a!="function")throw new Error("A callback has to be provided.");const i=s=>{a(s)};t.onMounted(()=>{if(!n){document.addEventListener("keyup",i);return}n.value.addEventListener("keyup",i)}),t.onBeforeUnmount(()=>{if(!n){document.removeEventListener("keyup",i);return}n.value.removeEventListener("keyup",i)})}const M=t.defineComponent({__name:"FzFloating",props:{isOpen:{type:Boolean,default:!1},position:{default:"auto"},container:{},contentClass:{},openerClass:{},overrideContentClass:{type:Boolean},teleport:{type:Boolean,default:!1}},emits:["fzfloating:setPosition"],setup(a,{emit:n}){const i=a,s=n,l=t.ref(null),o=t.ref(null),f=t.useSlots(),r={position:t.computed(()=>i.position),element:{domRef:o},container:{domRef:t.toRef(i.container||document.body)},callback(...u){s("fzfloating:setPosition",...u)}};f.opener&&(r.opener={domRef:l});const e=B(r);t.watch(()=>i.position,()=>i.isOpen&&e.setPosition()),t.watch(()=>i.isOpen,u=>{!u||!o.value||(o.value.style.top="0px",o.value.style.left="0px",o.value.style.transform="none",e.setPosition())});const v=t.computed(()=>i.overrideContentClass?i.contentClass:["bg-core-white fixed p-4 z-10",i.contentClass]);return(u,b)=>(t.openBlock(),t.createElementBlock("div",null,[t.renderSlot(u.$slots,"opener-start"),t.createElementVNode("div",{ref_key:"opener",ref:l,class:"inline-flex"},[t.renderSlot(u.$slots,"opener",{isOpen:u.isOpen,floating:t.unref(e)})],512),t.renderSlot(u.$slots,"opener-end"),u.teleport?t.createCommentVNode("",!0):t.withDirectives((t.openBlock(),t.createElementBlock("div",{key:0,ref_key:"content",ref:o,class:t.normalizeClass(["fz__floating__content bg-core-white fixed p-4 z-10",v.value])},[t.renderSlot(u.$slots,"default",{isOpen:u.isOpen,floating:t.unref(e)})],2)),[[t.vShow,u.$slots.default&&(!u.$slots.opener||u.$slots.opener&&u.isOpen)]]),u.teleport?(t.openBlock(),t.createBlock(t.Teleport,{key:1,to:"body"},[t.withDirectives(t.createElementVNode("div",{ref_key:"content",ref:o,class:t.normalizeClass(["fz__floating__content bg-core-white absolute p-4 z-10",v.value])},[t.renderSlot(u.$slots,"default",{isOpen:u.isOpen,floating:t.unref(e)})],2),[[t.vShow,u.$slots.default&&(!u.$slots.opener||u.$slots.opener&&u.isOpen)]])])):t.createCommentVNode("",!0)]))}});d.FzFloating=M,d.useBreakpoints=S,d.useClickOutside=z,d.useFloating=B,d.useKeyDown=L,d.useKeyUp=F,d.useMediaQuery=w,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiscozen/composables",
3
- "version": "0.1.13",
3
+ "version": "0.1.16-beta.1",
4
4
  "description": "Design System utility composables",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -9,6 +9,8 @@ const props = withDefaults(defineProps<FzFloatingProps>(), {
9
9
  teleport: false
10
10
  })
11
11
 
12
+ const emits = defineEmits(['fzfloating:setPosition'])
13
+
12
14
  const opener = ref(null)
13
15
  const content = ref<HTMLElement | null>(null)
14
16
 
@@ -17,10 +19,15 @@ const slots = useSlots()
17
19
  const useFloatingOpts: FzUseFloatingArgs = {
18
20
  position: computed(() => props.position),
19
21
  element: {
22
+ // @ts-ignore
20
23
  domRef: content
21
24
  },
22
25
  container: {
26
+ // @ts-ignore
23
27
  domRef: toRef(props.container || document.body)
28
+ },
29
+ callback(...args) {
30
+ emits('fzfloating:setPosition', ...args)
24
31
  }
25
32
  }
26
33
  if (slots.opener) {
@@ -59,6 +66,7 @@ const contentClass = computed(() => {
59
66
 
60
67
  <template>
61
68
  <div>
69
+ <slot name="opener-start"></slot>
62
70
  <div ref="opener" class="inline-flex">
63
71
  <slot name="opener" :isOpen :floating></slot>
64
72
  </div>
@@ -76,7 +84,7 @@ const contentClass = computed(() => {
76
84
  <div
77
85
  ref="content"
78
86
  v-show="$slots.default && (!$slots.opener || ($slots.opener && isOpen))"
79
- class="fz__floating__content bg-core-white fixed p-4 z-10"
87
+ class="fz__floating__content bg-core-white absolute p-4 z-10"
80
88
  :class="contentClass"
81
89
  >
82
90
  <slot :isOpen :floating></slot>
@@ -3,107 +3,119 @@
3
3
  exports[`FzFloating > should match snapshot 1`] = `
4
4
  "<div>
5
5
  <div class="inline-flex"><button>opener</button></div>
6
- <div class="bg-core-white absolute p-4 z-10">
6
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
7
7
  <div>content</div>
8
8
  </div>
9
+ <!--v-if-->
9
10
  </div>"
10
11
  `;
11
12
 
12
13
  exports[`FzFloating > should match snapshot 2`] = `
13
14
  "<div>
14
15
  <div class="inline-flex"><button>opener</button></div>
15
- <div class="bg-core-white absolute p-4 z-10">
16
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
16
17
  <div>content</div>
17
18
  </div>
19
+ <!--v-if-->
18
20
  </div>"
19
21
  `;
20
22
 
21
23
  exports[`FzFloating > should match snapshot 3`] = `
22
24
  "<div>
23
25
  <div class="inline-flex"><button>opener</button></div>
24
- <div class="bg-core-white absolute p-4 z-10">
26
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
25
27
  <div>content</div>
26
28
  </div>
29
+ <!--v-if-->
27
30
  </div>"
28
31
  `;
29
32
 
30
33
  exports[`FzFloating > should match snapshot 4`] = `
31
34
  "<div>
32
35
  <div class="inline-flex"><button>opener</button></div>
33
- <div class="bg-core-white absolute p-4 z-10">
36
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
34
37
  <div>content</div>
35
38
  </div>
39
+ <!--v-if-->
36
40
  </div>"
37
41
  `;
38
42
 
39
43
  exports[`FzFloating > should match snapshot 5`] = `
40
44
  "<div>
41
45
  <div class="inline-flex"><button>opener</button></div>
42
- <div class="bg-core-white absolute p-4 z-10">
46
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
43
47
  <div>content</div>
44
48
  </div>
49
+ <!--v-if-->
45
50
  </div>"
46
51
  `;
47
52
 
48
53
  exports[`FzFloating > should match snapshot 6`] = `
49
54
  "<div>
50
55
  <div class="inline-flex"><button>opener</button></div>
51
- <div class="bg-core-white absolute p-4 z-10">
56
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
52
57
  <div>content</div>
53
58
  </div>
59
+ <!--v-if-->
54
60
  </div>"
55
61
  `;
56
62
 
57
63
  exports[`FzFloating > should match snapshot 7`] = `
58
64
  "<div>
59
65
  <div class="inline-flex"><button>opener</button></div>
60
- <div class="bg-core-white absolute p-4 z-10">
66
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
61
67
  <div>content</div>
62
68
  </div>
69
+ <!--v-if-->
63
70
  </div>"
64
71
  `;
65
72
 
66
73
  exports[`FzFloating > should match snapshot 8`] = `
67
74
  "<div>
68
75
  <div class="inline-flex"><button>opener</button></div>
69
- <div class="bg-core-white absolute p-4 z-10">
76
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
70
77
  <div>content</div>
71
78
  </div>
79
+ <!--v-if-->
72
80
  </div>"
73
81
  `;
74
82
 
75
83
  exports[`FzFloating > should match snapshot 9`] = `
76
84
  "<div>
77
85
  <div class="inline-flex"><button>opener</button></div>
78
- <div class="bg-core-white absolute p-4 z-10">
86
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
79
87
  <div>content</div>
80
88
  </div>
89
+ <!--v-if-->
81
90
  </div>"
82
91
  `;
83
92
 
84
93
  exports[`FzFloating > should match snapshot 10`] = `
85
94
  "<div>
86
95
  <div class="inline-flex"><button>opener</button></div>
87
- <div class="bg-core-white absolute p-4 z-10">
96
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
88
97
  <div>content</div>
89
98
  </div>
99
+ <!--v-if-->
90
100
  </div>"
91
101
  `;
92
102
 
93
103
  exports[`FzFloating > should match snapshot 11`] = `
94
104
  "<div>
95
105
  <div class="inline-flex"><button>opener</button></div>
96
- <div class="bg-core-white absolute p-4 z-10">
106
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
97
107
  <div>content</div>
98
108
  </div>
109
+ <!--v-if-->
99
110
  </div>"
100
111
  `;
101
112
 
102
113
  exports[`FzFloating > should match snapshot 12`] = `
103
114
  "<div>
104
115
  <div class="inline-flex"><button>opener</button></div>
105
- <div class="bg-core-white absolute p-4 z-10">
116
+ <div class="fz__floating__content bg-core-white fixed z-10 p-4 bg-core-white fixed p-4 z-10">
106
117
  <div>content</div>
107
118
  </div>
119
+ <!--v-if-->
108
120
  </div>"
109
121
  `;
@@ -3,4 +3,4 @@ export * from './useMediaQuery'
3
3
  export * from './useBreakpoints'
4
4
  export * from './useClickOutside'
5
5
  export * from './useKeyDown'
6
- export * from './useKeyUp'
6
+ export * from './useKeyUp'
@@ -1,9 +1,9 @@
1
- import { onBeforeUnmount, onMounted, Ref } from 'vue'
1
+ import { onBeforeUnmount, onMounted, Ref, watch } from 'vue'
2
2
 
3
3
  function useClickOutside(
4
- component: Ref<HTMLElement | undefined>,
4
+ component: Ref<HTMLElement | undefined>,
5
5
  callback: () => void,
6
- elementToListenClicksOn?: Ref<HTMLElement | undefined>,
6
+ elementToListenClicksOn?: Ref<HTMLElement | undefined>
7
7
  ) {
8
8
  // fail early if any of the required params is missing
9
9
  if (!component) {
@@ -14,7 +14,7 @@ function useClickOutside(
14
14
  throw new Error('A callback has to be provided.')
15
15
  }
16
16
 
17
- const listener = (event: MouseEvent) => {
17
+ const listener = (event: Event) => {
18
18
  if (
19
19
  !component.value ||
20
20
  event.target === component.value ||
@@ -27,12 +27,30 @@ function useClickOutside(
27
27
  }
28
28
  }
29
29
 
30
+ if (elementToListenClicksOn) {
31
+ watch(
32
+ elementToListenClicksOn,
33
+ (newVal: Element | undefined, oldVal: Element | undefined) => {
34
+ if (oldVal) {
35
+ oldVal.removeEventListener('click', listener)
36
+ }
37
+ newVal?.addEventListener('click', listener)
38
+ }
39
+ )
40
+ }
41
+
30
42
  onMounted(() => {
31
- (elementToListenClicksOn ?? component).value!.addEventListener('click', listener)
43
+ if (!elementToListenClicksOn) {
44
+ document.addEventListener('click', listener)
45
+ }
32
46
  })
33
47
 
34
48
  onBeforeUnmount(() => {
35
- (elementToListenClicksOn ?? component).value!.removeEventListener('click', listener)
49
+ if (elementToListenClicksOn) {
50
+ elementToListenClicksOn.value!.removeEventListener('click', listener)
51
+ return
52
+ }
53
+ document.removeEventListener('click', listener)
36
54
  })
37
55
  }
38
56
 
@@ -1,19 +1,24 @@
1
1
  import { FzFloatingPosition, FzRect, FzUseFloatingArgs } from '../types'
2
- import { ref, reactive, onUnmounted, Ref, nextTick, computed } from 'vue'
2
+ import { ref, reactive, onUnmounted, Ref, nextTick } from 'vue'
3
3
  import { calcRealPos, getHighestAvailableSpacePos } from '../utils'
4
4
 
5
5
  export const useFloating = (
6
6
  args: FzUseFloatingArgs
7
7
  ): {
8
8
  float: FzRect
9
- rect: Ref<DOMRect | null>
10
- floatObserver: Ref<IntersectionObserver>
9
+ rect: Ref<DOMRect | undefined>
11
10
  setPosition: () => Promise<void>
11
+ position: Ref<FzFloatingPosition>
12
+ openerRect: Ref<DOMRect | undefined>
13
+ containerRect: Ref<DOMRect | undefined>
12
14
  } => {
13
15
  const safeElementDomRef = ref<HTMLElement | null>(null)
14
16
  const safeContainerDomRef = ref<HTMLElement | null>(null)
15
17
  const safeOpenerDomRef = ref<HTMLElement | null>(null)
16
- const rect = ref<DOMRect | null>(null)
18
+ const openerRect = ref<DOMRect | undefined>()
19
+ const containerRect = ref<DOMRect | undefined>()
20
+ const position = ref<FzFloatingPosition>('auto')
21
+ const rect = ref<DOMRect | undefined>()
17
22
  const float = reactive<FzRect>({
18
23
  position: { x: 0, y: 0 }
19
24
  })
@@ -30,20 +35,21 @@ export const useFloating = (
30
35
  ) => {}
31
36
 
32
37
  const floatObserver = ref(new IntersectionObserver(handleIntersect, options))
38
+ position.value = args.position ? args.position.value : 'auto'
33
39
 
34
40
  const setPosition = () =>
35
41
  nextTick(() => {
36
42
  safeElementDomRef.value =
37
- typeof args.element.domRef.value === 'string'
38
- ? document.querySelector(args.element.domRef.value)
39
- : args.element.domRef.value
43
+ (typeof args.element.domRef.value === 'string'
44
+ ? document.querySelector(args.element.domRef.value)
45
+ : args.element.domRef.value) as HTMLElement
40
46
  if (!args.container) {
41
47
  safeContainerDomRef.value = document.body
42
48
  } else {
43
49
  safeContainerDomRef.value =
44
- typeof args.container.domRef.value === 'string'
50
+ (typeof args.container.domRef.value === 'string'
45
51
  ? document.querySelector(args.container.domRef.value)
46
- : args.container.domRef.value
52
+ : args.container.domRef.value) as HTMLElement
47
53
  safeContainerDomRef.value ??= document.body
48
54
  }
49
55
 
@@ -53,77 +59,102 @@ export const useFloating = (
53
59
 
54
60
  if (args.opener) {
55
61
  safeOpenerDomRef.value =
56
- typeof args.opener.domRef.value === 'string'
62
+ (typeof args.opener.domRef.value === 'string'
57
63
  ? document.querySelector(args.opener.domRef.value)
58
- : args.opener.domRef.value
64
+ : args.opener.domRef.value) as HTMLElement
59
65
  }
60
66
 
61
67
  rect.value = safeElementDomRef.value.getBoundingClientRect()
62
- const openerRect = safeOpenerDomRef.value?.getBoundingClientRect()
63
- const containerRect = safeContainerDomRef.value.getBoundingClientRect()
68
+ openerRect.value = safeOpenerDomRef.value?.getBoundingClientRect()
69
+ containerRect.value = safeContainerDomRef.value.getBoundingClientRect()
64
70
 
65
- const elStyle = window.getComputedStyle(safeElementDomRef.value)
71
+ const elStyle = window.getComputedStyle(safeElementDomRef.value as HTMLElement)
66
72
 
67
73
  // multiple observer calls on same target do not cause multiple registrations
68
- floatObserver.value.observe(safeElementDomRef.value)
69
- floatObserver.value.observe(safeContainerDomRef.value)
70
-
71
- let position: FzFloatingPosition = args.position ? args.position.value : 'auto'
74
+ floatObserver.value.observe(safeElementDomRef.value as HTMLElement)
75
+ floatObserver.value.observe(safeContainerDomRef.value as HTMLElement)
72
76
 
73
77
  let translateY = 0
74
78
  let translateX = 0
75
79
 
76
- if (args.opener && safeOpenerDomRef.value && openerRect) {
80
+ if (args.opener && safeOpenerDomRef.value && openerRect && openerRect.value) {
77
81
  const leftWithoutXMargin =
78
- openerRect.left - parseFloat(elStyle.marginLeft) - parseFloat(elStyle.marginRight)
79
- const leftWithoutLeftMargin = openerRect.left - parseFloat(elStyle.marginLeft)
82
+ openerRect.value.left - parseFloat(elStyle.marginLeft) - parseFloat(elStyle.marginRight)
83
+ const leftWithoutLeftMargin = openerRect.value.left - parseFloat(elStyle.marginLeft)
80
84
  const topWithoutYMargin =
81
- openerRect.top - parseFloat(elStyle.marginTop) - parseFloat(elStyle.marginBottom)
82
- const topWithoutTopMargin = openerRect.top - parseFloat(elStyle.marginTop)
85
+ openerRect.value.top - parseFloat(elStyle.marginTop) - parseFloat(elStyle.marginBottom)
86
+ const topWithoutTopMargin = openerRect.value.top - parseFloat(elStyle.marginTop)
83
87
 
84
- switch (position) {
88
+ switch (position.value) {
85
89
  case 'auto':
86
- position = getHighestAvailableSpacePos(
87
- safeContainerDomRef.value,
88
- safeElementDomRef.value,
89
- safeOpenerDomRef.value
90
+ position.value = getHighestAvailableSpacePos(
91
+ safeContainerDomRef.value as HTMLElement,
92
+ safeElementDomRef.value as HTMLElement,
93
+ safeOpenerDomRef.value as HTMLElement
94
+ )
95
+ break
96
+ case 'auto-vertical':
97
+ position.value = getHighestAvailableSpacePos(
98
+ safeContainerDomRef.value as HTMLElement,
99
+ safeElementDomRef.value as HTMLElement,
100
+ safeOpenerDomRef.value as HTMLElement,
101
+ undefined,
102
+ true
90
103
  )
91
104
  break
92
105
  case 'auto-start':
93
- position = getHighestAvailableSpacePos(
94
- safeContainerDomRef.value,
95
- safeElementDomRef.value,
96
- safeOpenerDomRef.value,
106
+ position.value = getHighestAvailableSpacePos(
107
+ safeContainerDomRef.value as HTMLElement,
108
+ safeElementDomRef.value as HTMLElement,
109
+ safeOpenerDomRef.value as HTMLElement,
97
110
  'start'
98
111
  )
99
112
  break
113
+ case 'auto-vertical-start':
114
+ position.value = getHighestAvailableSpacePos(
115
+ safeContainerDomRef.value as HTMLElement,
116
+ safeElementDomRef.value as HTMLElement,
117
+ safeOpenerDomRef.value as HTMLElement,
118
+ 'start',
119
+ true
120
+ )
121
+ break
100
122
  case 'auto-end':
101
- position = getHighestAvailableSpacePos(
102
- safeContainerDomRef.value,
103
- safeElementDomRef.value,
104
- safeOpenerDomRef.value,
123
+ position.value = getHighestAvailableSpacePos(
124
+ safeContainerDomRef.value as HTMLElement,
125
+ safeElementDomRef.value as HTMLElement,
126
+ safeOpenerDomRef.value as HTMLElement,
105
127
  'end'
106
128
  )
107
129
  break
130
+ case 'auto-vertical-end':
131
+ position.value = getHighestAvailableSpacePos(
132
+ safeContainerDomRef.value as HTMLElement,
133
+ safeElementDomRef.value as HTMLElement,
134
+ safeOpenerDomRef.value as HTMLElement,
135
+ 'end',
136
+ true
137
+ )
138
+ break
108
139
  default:
109
140
  break
110
141
  }
111
- switch (position) {
142
+ switch (position.value) {
112
143
  case 'bottom':
113
- float.position.y = openerRect.bottom
114
- float.position.x = leftWithoutLeftMargin + openerRect.width / 2
144
+ float.position.y = openerRect.value.bottom
145
+ float.position.x = leftWithoutLeftMargin + openerRect.value.width / 2
115
146
  translateX = -50
116
147
  translateY = 0
117
148
  break
118
149
  case 'bottom-start':
119
- float.position.y = openerRect.bottom
150
+ float.position.y = openerRect.value.bottom
120
151
  float.position.x = leftWithoutXMargin
121
152
  translateX = 0
122
153
  translateY = 0
123
154
  break
124
155
  case 'bottom-end':
125
- float.position.y = openerRect.bottom
126
- float.position.x = openerRect.right
156
+ float.position.y = openerRect.value.bottom
157
+ float.position.x = openerRect.value.right
127
158
  translateX = -100
128
159
  translateY = 0
129
160
  break
@@ -134,13 +165,13 @@ export const useFloating = (
134
165
  translateY = 0
135
166
  break
136
167
  case 'left':
137
- float.position.y = topWithoutTopMargin + openerRect.height / 2
168
+ float.position.y = topWithoutTopMargin + openerRect.value.height / 2
138
169
  float.position.x = leftWithoutXMargin
139
170
  translateY = -50
140
171
  translateX = -100
141
172
  break
142
173
  case 'left-end':
143
- float.position.y = openerRect.bottom
174
+ float.position.y = openerRect.value.bottom
144
175
  float.position.x = leftWithoutXMargin
145
176
  translateY = -100
146
177
  translateX = -100
@@ -153,31 +184,31 @@ export const useFloating = (
153
184
  break
154
185
  case 'top':
155
186
  float.position.y = topWithoutYMargin
156
- float.position.x = leftWithoutLeftMargin + openerRect.width / 2
187
+ float.position.x = leftWithoutLeftMargin + openerRect.value.width / 2
157
188
  translateX = -50
158
189
  translateY = -100
159
190
  break
160
191
  case 'top-end':
161
192
  float.position.y = topWithoutYMargin
162
- float.position.x = openerRect.right
193
+ float.position.x = openerRect.value.right
163
194
  translateX = -100
164
195
  translateY = -100
165
196
  break
166
197
  case 'right-start':
167
198
  float.position.y = topWithoutYMargin
168
- float.position.x = openerRect.right
199
+ float.position.x = openerRect.value.right
169
200
  translateX = 0
170
201
  translateY = 0
171
202
  break
172
203
  case 'right':
173
- float.position.y = topWithoutTopMargin + openerRect.height / 2
174
- float.position.x = openerRect.right
204
+ float.position.y = topWithoutTopMargin + openerRect.value.height / 2
205
+ float.position.x = openerRect.value.right
175
206
  translateY = -50
176
207
  translateX = 0
177
208
  break
178
209
  case 'right-end':
179
- float.position.y = openerRect.bottom
180
- float.position.x = openerRect.right
210
+ float.position.y = openerRect.value.bottom
211
+ float.position.x = openerRect.value.right
181
212
  translateY = -100
182
213
  translateX = 0
183
214
  break
@@ -185,42 +216,45 @@ export const useFloating = (
185
216
  break
186
217
  }
187
218
  } else {
188
- switch (position) {
219
+ switch (position.value) {
189
220
  case 'bottom':
190
- float.position.y = containerRect.bottom - rect.value.height
191
- float.position.x = containerRect.left + containerRect.width / 2
221
+ float.position.y = containerRect.value.bottom - rect.value.height
222
+ float.position.x = containerRect.value.left + containerRect.value.width / 2
192
223
  translateX = -50
193
224
  break
194
225
  case 'left-end':
195
226
  case 'bottom-start':
196
- float.position.y = containerRect.bottom - rect.value.height
197
- float.position.x = containerRect.left
227
+ float.position.y = containerRect.value.bottom - rect.value.height
228
+ float.position.x = containerRect.value.left
198
229
  break
199
230
  case 'right-end':
200
231
  case 'bottom-end':
201
- float.position.y = containerRect.bottom - rect.value.height
202
- float.position.x = containerRect.right - rect.value.width
232
+ float.position.y = containerRect.value.bottom - rect.value.height
233
+ float.position.x = containerRect.value.right - rect.value.width
203
234
  break
204
235
  case 'left':
205
- float.position.y = containerRect.top + (containerRect.height - rect.value.height) / 2
206
- float.position.x = containerRect.left
236
+ float.position.y =
237
+ containerRect.value.top + (containerRect.value.height - rect.value.height) / 2
238
+ float.position.x = containerRect.value.left
207
239
  break
208
240
  case 'top-start':
209
241
  case 'left-start':
210
- float.position.y = containerRect.top
211
- float.position.x = containerRect.left
242
+ float.position.y = containerRect.value.top
243
+ float.position.x = containerRect.value.left
212
244
  break
213
245
  case 'top':
214
- float.position.y = containerRect.top
215
- float.position.x = containerRect.left + (containerRect.width - rect.value.width) / 2
246
+ float.position.y = containerRect.value.top
247
+ float.position.x =
248
+ containerRect.value.left + (containerRect.value.width - rect.value.width) / 2
216
249
  break
217
250
  case 'top-end':
218
251
  case 'right-start':
219
- float.position.y = containerRect.top
220
- float.position.x = containerRect.right - rect.value.width
252
+ float.position.y = containerRect.value.top
253
+ float.position.x = containerRect.value.right - rect.value.width
221
254
  case 'right':
222
- float.position.y = containerRect.top + (containerRect.height - rect.value.height) / 2
223
- float.position.x = containerRect.right - rect.value.width
255
+ float.position.y =
256
+ containerRect.value.top + (containerRect.value.height - rect.value.height) / 2
257
+ float.position.x = containerRect.value.right - rect.value.width
224
258
  break
225
259
  default:
226
260
  break
@@ -232,32 +266,40 @@ export const useFloating = (
232
266
  float.position.x = realPos.x
233
267
  float.position.y = realPos.y
234
268
 
235
- if (realPos.x < containerRect.left) {
236
- float.position.x = containerRect.left
269
+ if (realPos.x < containerRect.value.left) {
270
+ float.position.x = containerRect.value.left
237
271
  translateX = 0
238
272
  }
239
273
 
240
- if (realPos.x + rect.value.width > containerRect.right) {
241
- float.position.x = containerRect.right - rect.value.width
274
+ if (realPos.x + rect.value.width > containerRect.value.right) {
275
+ const fixVal = containerRect.value.right - rect.value.width
276
+ if (fixVal > 0) {
277
+ float.position.x = fixVal
278
+ }
242
279
  translateX = 0
243
280
  }
244
281
 
245
- if (realPos.y < containerRect.top) {
246
- float.position.y = containerRect.top
282
+ if (realPos.y < containerRect.value.top) {
283
+ float.position.y = containerRect.value.top
247
284
  translateY = 0
248
285
  }
249
286
 
250
- if (realPos.y + rect.value.height > containerRect.bottom) {
251
- float.position.y = containerRect.bottom - rect.value.height
287
+ if (realPos.y + rect.value.height > containerRect.value.bottom) {
288
+ const fixVal = containerRect.value.bottom - rect.value.height
289
+ if (fixVal > 0) {
290
+ float.position.y = fixVal
291
+ }
252
292
  translateY = 0
253
293
  }
254
294
 
255
295
  safeElementDomRef.value.style.top = `${float.position.y}px`
256
296
  safeElementDomRef.value.style.left = `${float.position.x}px`
257
- safeElementDomRef.value.style.position = 'fixed'
297
+ // safeElementDomRef.value.style.position = 'fixed'
258
298
  safeElementDomRef.value.style.display = 'flex'
259
299
 
260
300
  rect.value = safeElementDomRef.value.getBoundingClientRect()
301
+
302
+ args.callback && args.callback(rect, openerRect, containerRect, position)
261
303
  })
262
304
 
263
305
  onUnmounted(() => {
@@ -267,7 +309,9 @@ export const useFloating = (
267
309
  return {
268
310
  float,
269
311
  rect,
270
- floatObserver,
271
- setPosition
312
+ setPosition,
313
+ position,
314
+ openerRect,
315
+ containerRect
272
316
  }
273
317
  }
@@ -1,6 +1,9 @@
1
1
  import { onBeforeUnmount, onMounted, Ref } from 'vue'
2
2
 
3
- function useKeyDown(component: Ref<HTMLElement | undefined>, callback: (event: KeyboardEvent) => void) {
3
+ function useKeyDown(
4
+ component: Ref<HTMLElement | undefined>,
5
+ callback: (event: KeyboardEvent) => void
6
+ ) {
4
7
  // fail early if any of the required params is missing
5
8
  if (!component) {
6
9
  throw new Error('A target component has to be provided.')
@@ -1,7 +1,9 @@
1
1
  import { onBeforeUnmount, onMounted, Ref } from 'vue'
2
2
 
3
- function useKeyUp(callback: (event: KeyboardEvent) => void, component?: Ref<HTMLElement | undefined>) {
4
-
3
+ function useKeyUp(
4
+ callback: (event: KeyboardEvent) => void,
5
+ component?: Ref<HTMLElement | undefined>
6
+ ) {
5
7
  if (!callback || typeof callback !== 'function') {
6
8
  throw new Error('A callback has to be provided.')
7
9
  }
@@ -13,7 +15,7 @@ function useKeyUp(callback: (event: KeyboardEvent) => void, component?: Ref<HTML
13
15
  onMounted(() => {
14
16
  if (!component) {
15
17
  document.addEventListener('keyup', listener)
16
- return;
18
+ return
17
19
  }
18
20
  component.value!.addEventListener('keyup', listener)
19
21
  })
@@ -21,7 +23,7 @@ function useKeyUp(callback: (event: KeyboardEvent) => void, component?: Ref<HTML
21
23
  onBeforeUnmount(() => {
22
24
  if (!component) {
23
25
  document.removeEventListener('keyup', listener)
24
- return;
26
+ return
25
27
  }
26
28
  component.value!.removeEventListener('keyup', listener)
27
29
  })
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Ref } from 'vue'
2
2
 
3
- type PositionPrimary = 'bottom' | 'left' | 'top' | 'right' | 'auto'
3
+ type PositionPrimary = 'bottom' | 'left' | 'top' | 'right' | 'auto' | 'auto-vertical'
4
4
  type PositionSecondary = 'start' | 'end'
5
5
  export type FzFloatingPosition = PositionPrimary | `${PositionPrimary}-${PositionSecondary}`
6
6
 
@@ -40,4 +40,10 @@ export interface FzUseFloatingArgs {
40
40
  container?: FzFloatElement
41
41
  opener?: FzFloatElement
42
42
  position?: Ref<FzFloatingPosition>
43
+ callback?: (
44
+ rect: Ref<DOMRect | undefined>,
45
+ openerRect: Ref<DOMRect | undefined>,
46
+ containerRect: Ref<DOMRect | undefined>,
47
+ position: Ref<FzFloatingPosition>
48
+ ) => void
43
49
  }
@@ -10,11 +10,12 @@ export const getHighestAvailableSpacePos = (
10
10
  container: HTMLElement,
11
11
  el: HTMLElement,
12
12
  opener: HTMLElement,
13
- justify?: 'start' | 'end'
13
+ justify?: 'start' | 'end',
14
+ verticalOnly?: boolean
14
15
  ): FzFloatingPosition => {
15
- let mainPosition: MainPosition = 'right'
16
+ let mainPosition: MainPosition = verticalOnly ? 'bottom' : 'right'
16
17
 
17
- let positionRes: FzFloatingPosition = 'right-start'
18
+ let positionRes: FzFloatingPosition = verticalOnly ? 'bottom-start' : 'right-start'
18
19
 
19
20
  const containerRect = container.getBoundingClientRect()
20
21
  const elRect = el.getBoundingClientRect()
@@ -29,7 +30,7 @@ export const getHighestAvailableSpacePos = (
29
30
  const spaceBottomNormalized =
30
31
  (containerRect.bottom - openerRect.bottom - elRect.height) / containerRect.height
31
32
 
32
- const positionList = [
33
+ let positionList = [
33
34
  {
34
35
  key: 'right',
35
36
  space: spaceRightNormalized
@@ -48,6 +49,10 @@ export const getHighestAvailableSpacePos = (
48
49
  } as PositionListItem
49
50
  ].sort((a, b) => b.space - a.space)
50
51
 
52
+ if (verticalOnly) {
53
+ positionList = positionList.filter((pos) => pos.key === 'top' || pos.key === 'bottom')
54
+ }
55
+
51
56
  mainPosition = positionList[0].key
52
57
 
53
58
  if (!justify) {