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