@fiscozen/composables 0.1.20-beta.2 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/FzFloating.vue +31 -4
- package/src/__tests__/__snapshots__/FzFloating.spec.ts.snap +24 -12
- package/src/composables/index.ts +1 -1
- package/src/composables/useClickOutside.ts +6 -6
- package/src/composables/useCurrency.ts +71 -84
- package/src/composables/useFloating.ts +125 -75
- package/src/composables/useKeyDown.ts +4 -1
- package/src/composables/useKeyUp.ts +6 -4
- package/src/types.ts +10 -1
- package/src/utils/index.ts +16 -7
package/package.json
CHANGED
package/src/FzFloating.vue
CHANGED
|
@@ -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,22 +41,39 @@ 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
|
-
() =>
|
|
58
|
+
() => setPositionWhenOpen()
|
|
37
59
|
)
|
|
38
60
|
watch(
|
|
39
61
|
() => props.isOpen,
|
|
40
62
|
(newVal) => {
|
|
41
63
|
if (!newVal || !content.value) {
|
|
64
|
+
window.removeEventListener('scroll', setPositionWhenOpen)
|
|
42
65
|
return
|
|
43
66
|
}
|
|
67
|
+
window.addEventListener('scroll', setPositionWhenOpen)
|
|
44
68
|
content.value.style.top = '0px'
|
|
45
69
|
content.value.style.left = '0px'
|
|
46
70
|
content.value.style.transform = 'none'
|
|
47
71
|
floating.setPosition()
|
|
48
72
|
}
|
|
49
73
|
)
|
|
74
|
+
onBeforeUnmount(() => {
|
|
75
|
+
window.removeEventListener('scroll', setPositionWhenOpen)
|
|
76
|
+
})
|
|
50
77
|
|
|
51
78
|
const contentClass = computed(() => {
|
|
52
79
|
if (props.overrideContentClass) {
|
|
@@ -68,7 +95,7 @@ const contentClass = computed(() => {
|
|
|
68
95
|
v-if="!teleport"
|
|
69
96
|
ref="content"
|
|
70
97
|
v-show="$slots.default && (!$slots.opener || ($slots.opener && isOpen))"
|
|
71
|
-
class="fz__floating__content bg-core-white fixed p-4
|
|
98
|
+
class="fz__floating__content bg-core-white fixed z-10 p-4"
|
|
72
99
|
:class="contentClass"
|
|
73
100
|
>
|
|
74
101
|
<slot :isOpen :floating></slot>
|
|
@@ -77,7 +104,7 @@ const contentClass = computed(() => {
|
|
|
77
104
|
<div
|
|
78
105
|
ref="content"
|
|
79
106
|
v-show="$slots.default && (!$slots.opener || ($slots.opener && isOpen))"
|
|
80
|
-
class="fz__floating__content bg-core-white
|
|
107
|
+
class="fz__floating__content bg-core-white fixed z-10 p-4"
|
|
81
108
|
:class="contentClass"
|
|
82
109
|
>
|
|
83
110
|
<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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
`;
|
package/src/composables/index.ts
CHANGED
|
@@ -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:
|
|
17
|
+
const listener = (event: Event) => {
|
|
18
18
|
if (
|
|
19
19
|
!component.value ||
|
|
20
20
|
event.target === component.value ||
|
|
@@ -28,12 +28,12 @@ function useClickOutside(
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (elementToListenClicksOn) {
|
|
31
|
-
watch(elementToListenClicksOn, (newVal:
|
|
31
|
+
watch(elementToListenClicksOn, (newVal: Element | undefined, oldVal: Element | undefined) => {
|
|
32
32
|
if (oldVal) {
|
|
33
33
|
oldVal.removeEventListener('click', listener)
|
|
34
34
|
}
|
|
35
35
|
newVal?.addEventListener('click', listener)
|
|
36
|
-
})
|
|
36
|
+
})
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
onMounted(() => {
|
|
@@ -45,7 +45,7 @@ function useClickOutside(
|
|
|
45
45
|
onBeforeUnmount(() => {
|
|
46
46
|
if (elementToListenClicksOn) {
|
|
47
47
|
elementToListenClicksOn.value!.removeEventListener('click', listener)
|
|
48
|
-
return
|
|
48
|
+
return
|
|
49
49
|
}
|
|
50
50
|
document.removeEventListener('click', listener)
|
|
51
51
|
})
|
|
@@ -1,103 +1,90 @@
|
|
|
1
|
-
import {Ref, watch, getCurrentInstance, computed, ref,
|
|
1
|
+
import { Ref, watch, getCurrentInstance, computed, ref, onMounted } from 'vue'
|
|
2
2
|
|
|
3
3
|
export const useCurrency = () => {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const inputRef: Ref<HTMLInputElement | null> = ref(null)
|
|
5
|
+
const vm = getCurrentInstance()
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const modelValue = computed<number | undefined>(
|
|
8
|
+
() => vm?.props.modelValue as unknown as number | undefined
|
|
9
|
+
)
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
maximumFractionDigits: 2,
|
|
14
|
-
useGrouping: false
|
|
15
|
-
})
|
|
11
|
+
const format = (input: number | null) => {
|
|
12
|
+
if (input === null) {
|
|
13
|
+
return '';
|
|
16
14
|
}
|
|
15
|
+
return input.toLocaleString('it-IT', {
|
|
16
|
+
minimumFractionDigits: 2,
|
|
17
|
+
maximumFractionDigits: 2
|
|
18
|
+
})
|
|
19
|
+
}
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const parse = (text: string) => {
|
|
22
|
+
// strip currency, handle edge cases...
|
|
23
|
+
return parseFloat(text)
|
|
24
|
+
}
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
if (vm) {
|
|
28
|
-
internalVal.value = val
|
|
29
|
-
vm.emit('update:amount', typeof computedModel.value === 'number' ? val : val.toString())
|
|
30
|
-
}
|
|
26
|
+
const setValue = (val: number | null) => {
|
|
27
|
+
if (Number.isNaN(val)) {
|
|
28
|
+
return
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
setTimeout(() => {
|
|
36
|
-
if (!inputRef.value) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
inputRef.value.value = val;
|
|
40
|
-
}, 0)
|
|
41
|
-
}
|
|
31
|
+
vm && vm.emit('update:modelValue', val)
|
|
32
|
+
}
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
let {value} = el;
|
|
48
|
-
value = value.replace(/[^0-9,.]/g, '')
|
|
49
|
-
setValue(value)
|
|
50
|
-
const number = parse(value)
|
|
51
|
-
emitAmount(Number.isNaN(number) ? 0 : number)
|
|
34
|
+
const onInput = (el: HTMLInputElement) => (e: Event) => {
|
|
35
|
+
if (!inputRef.value || !e.target) {
|
|
36
|
+
return
|
|
52
37
|
}
|
|
38
|
+
let { value } = el
|
|
39
|
+
value = value.replace(/[^0-9,.]/g, '')
|
|
40
|
+
inputRef.value.value = value
|
|
41
|
+
const numberValue = (vm?.props.nullOnEmpty && value === '') ? null : parse(value)
|
|
42
|
+
setValue(Number.isNaN(numberValue) ? 0 : numberValue)
|
|
43
|
+
}
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
let number = parse((e.target as HTMLInputElement).value)
|
|
59
|
-
if (Number.isNaN(number)) {
|
|
60
|
-
number = 0;
|
|
61
|
-
}
|
|
62
|
-
const text = format(number)
|
|
63
|
-
setValue(text)
|
|
64
|
-
emitAmount(parse(text))
|
|
45
|
+
const onBlur = (e: FocusEvent) => {
|
|
46
|
+
if (!inputRef.value || !e.target) {
|
|
47
|
+
return
|
|
65
48
|
}
|
|
49
|
+
let rawValue = (e.target as HTMLInputElement).value.replace(/,/g, '.');
|
|
50
|
+
let number: number | null;
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
if (rawValue === '' && vm?.props.nullOnEmpty) {
|
|
53
|
+
number = null
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
number = parse(rawValue)
|
|
57
|
+
if (Number.isNaN(number)) {
|
|
58
|
+
number = 0
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const text = format(number)
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
newVal.addEventListener('input', onInput(newVal))
|
|
77
|
-
newVal.addEventListener('blur', onBlur)
|
|
78
|
-
})
|
|
63
|
+
inputRef.value.value = text
|
|
64
|
+
setValue(number)
|
|
65
|
+
}
|
|
79
66
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
// we need to format here only if someone externally set the
|
|
86
|
-
// value of the amount model
|
|
87
|
-
if (internalVal.value !== newVal) {
|
|
88
|
-
const formatted = format(newVal)
|
|
89
|
-
inputRef.value.value = formatted
|
|
90
|
-
internalVal.value = newVal
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
})
|
|
67
|
+
watch(inputRef, (newVal, oldVal) => {
|
|
68
|
+
if (!newVal) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
94
71
|
|
|
72
|
+
if (oldVal) {
|
|
73
|
+
oldVal?.removeEventListener('input', onInput(newVal))
|
|
74
|
+
oldVal?.removeEventListener('blur', onBlur)
|
|
75
|
+
}
|
|
76
|
+
newVal.addEventListener('input', onInput(newVal))
|
|
77
|
+
newVal.addEventListener('blur', onBlur)
|
|
95
78
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
parse,
|
|
99
|
-
format,
|
|
100
|
-
emitAmount,
|
|
101
|
-
setValue
|
|
79
|
+
if (modelValue.value) {
|
|
80
|
+
newVal.value = format(modelValue.value)
|
|
102
81
|
}
|
|
103
|
-
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
inputRef,
|
|
86
|
+
parse,
|
|
87
|
+
format,
|
|
88
|
+
setValue
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { FzFloatingPosition, FzRect, FzUseFloatingArgs } from '../types'
|
|
2
|
-
import { ref, reactive, onUnmounted, Ref, nextTick
|
|
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 |
|
|
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
|
|
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,24 @@ export const useFloating = (
|
|
|
30
36
|
) => {}
|
|
31
37
|
|
|
32
38
|
const floatObserver = ref(new IntersectionObserver(handleIntersect, options))
|
|
39
|
+
const actualPosition = ref<FzFloatingPosition>()
|
|
33
40
|
|
|
34
41
|
const setPosition = () =>
|
|
35
42
|
nextTick(() => {
|
|
36
|
-
|
|
43
|
+
actualPosition.value = args.position ? args.position.value : 'auto'
|
|
44
|
+
safeElementDomRef.value = (
|
|
37
45
|
typeof args.element.domRef.value === 'string'
|
|
38
46
|
? document.querySelector(args.element.domRef.value)
|
|
39
47
|
: args.element.domRef.value
|
|
48
|
+
) as HTMLElement
|
|
40
49
|
if (!args.container) {
|
|
41
50
|
safeContainerDomRef.value = document.body
|
|
42
51
|
} else {
|
|
43
|
-
safeContainerDomRef.value =
|
|
52
|
+
safeContainerDomRef.value = (
|
|
44
53
|
typeof args.container.domRef.value === 'string'
|
|
45
54
|
? document.querySelector(args.container.domRef.value)
|
|
46
55
|
: args.container.domRef.value
|
|
56
|
+
) as HTMLElement
|
|
47
57
|
safeContainerDomRef.value ??= document.body
|
|
48
58
|
}
|
|
49
59
|
|
|
@@ -52,78 +62,104 @@ export const useFloating = (
|
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
if (args.opener) {
|
|
55
|
-
safeOpenerDomRef.value =
|
|
65
|
+
safeOpenerDomRef.value = (
|
|
56
66
|
typeof args.opener.domRef.value === 'string'
|
|
57
67
|
? document.querySelector(args.opener.domRef.value)
|
|
58
68
|
: args.opener.domRef.value
|
|
69
|
+
) as HTMLElement
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
rect.value = safeElementDomRef.value.getBoundingClientRect()
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
openerRect.value = safeOpenerDomRef.value?.getBoundingClientRect()
|
|
74
|
+
containerRect.value = safeContainerDomRef.value.getBoundingClientRect()
|
|
64
75
|
|
|
65
|
-
const elStyle = window.getComputedStyle(safeElementDomRef.value)
|
|
76
|
+
const elStyle = window.getComputedStyle(safeElementDomRef.value as HTMLElement)
|
|
66
77
|
|
|
67
78
|
// 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'
|
|
79
|
+
floatObserver.value.observe(safeElementDomRef.value as HTMLElement)
|
|
80
|
+
floatObserver.value.observe(safeContainerDomRef.value as HTMLElement)
|
|
72
81
|
|
|
73
82
|
let translateY = 0
|
|
74
83
|
let translateX = 0
|
|
75
84
|
|
|
76
|
-
if (args.opener && safeOpenerDomRef.value && openerRect) {
|
|
85
|
+
if (args.opener && safeOpenerDomRef.value && openerRect && openerRect.value) {
|
|
77
86
|
const leftWithoutXMargin =
|
|
78
|
-
openerRect.left - parseFloat(elStyle.marginLeft) - parseFloat(elStyle.marginRight)
|
|
79
|
-
const leftWithoutLeftMargin = openerRect.left - parseFloat(elStyle.marginLeft)
|
|
87
|
+
openerRect.value.left - parseFloat(elStyle.marginLeft) - parseFloat(elStyle.marginRight)
|
|
88
|
+
const leftWithoutLeftMargin = openerRect.value.left - parseFloat(elStyle.marginLeft)
|
|
80
89
|
const topWithoutYMargin =
|
|
81
|
-
openerRect.top - parseFloat(elStyle.marginTop) - parseFloat(elStyle.marginBottom)
|
|
82
|
-
const topWithoutTopMargin = openerRect.top - parseFloat(elStyle.marginTop)
|
|
90
|
+
openerRect.value.top - parseFloat(elStyle.marginTop) - parseFloat(elStyle.marginBottom)
|
|
91
|
+
const topWithoutTopMargin = openerRect.value.top - parseFloat(elStyle.marginTop)
|
|
83
92
|
|
|
84
|
-
switch (
|
|
93
|
+
switch (actualPosition.value) {
|
|
85
94
|
case 'auto':
|
|
86
|
-
|
|
87
|
-
safeContainerDomRef.value,
|
|
88
|
-
safeElementDomRef.value,
|
|
89
|
-
safeOpenerDomRef.value
|
|
95
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
96
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
97
|
+
safeElementDomRef.value as HTMLElement,
|
|
98
|
+
safeOpenerDomRef.value as HTMLElement
|
|
99
|
+
)
|
|
100
|
+
break
|
|
101
|
+
case 'auto-vertical':
|
|
102
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
103
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
104
|
+
safeElementDomRef.value as HTMLElement,
|
|
105
|
+
safeOpenerDomRef.value as HTMLElement,
|
|
106
|
+
undefined,
|
|
107
|
+
true
|
|
90
108
|
)
|
|
91
109
|
break
|
|
92
110
|
case 'auto-start':
|
|
93
|
-
|
|
94
|
-
safeContainerDomRef.value,
|
|
95
|
-
safeElementDomRef.value,
|
|
96
|
-
safeOpenerDomRef.value,
|
|
111
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
112
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
113
|
+
safeElementDomRef.value as HTMLElement,
|
|
114
|
+
safeOpenerDomRef.value as HTMLElement,
|
|
97
115
|
'start'
|
|
98
116
|
)
|
|
99
117
|
break
|
|
118
|
+
case 'auto-vertical-start':
|
|
119
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
120
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
121
|
+
safeElementDomRef.value as HTMLElement,
|
|
122
|
+
safeOpenerDomRef.value as HTMLElement,
|
|
123
|
+
'start',
|
|
124
|
+
true
|
|
125
|
+
)
|
|
126
|
+
break
|
|
100
127
|
case 'auto-end':
|
|
101
|
-
|
|
102
|
-
safeContainerDomRef.value,
|
|
103
|
-
safeElementDomRef.value,
|
|
104
|
-
safeOpenerDomRef.value,
|
|
128
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
129
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
130
|
+
safeElementDomRef.value as HTMLElement,
|
|
131
|
+
safeOpenerDomRef.value as HTMLElement,
|
|
105
132
|
'end'
|
|
106
133
|
)
|
|
107
134
|
break
|
|
135
|
+
case 'auto-vertical-end':
|
|
136
|
+
actualPosition.value = getHighestAvailableSpacePos(
|
|
137
|
+
args.useViewport ? null : (safeContainerDomRef.value as HTMLElement),
|
|
138
|
+
safeElementDomRef.value as HTMLElement,
|
|
139
|
+
safeOpenerDomRef.value as HTMLElement,
|
|
140
|
+
'end',
|
|
141
|
+
true
|
|
142
|
+
)
|
|
143
|
+
break
|
|
108
144
|
default:
|
|
109
145
|
break
|
|
110
146
|
}
|
|
111
|
-
switch (
|
|
147
|
+
switch (actualPosition.value) {
|
|
112
148
|
case 'bottom':
|
|
113
|
-
float.position.y = openerRect.bottom
|
|
114
|
-
float.position.x = leftWithoutLeftMargin + openerRect.width / 2
|
|
149
|
+
float.position.y = openerRect.value.bottom
|
|
150
|
+
float.position.x = leftWithoutLeftMargin + openerRect.value.width / 2
|
|
115
151
|
translateX = -50
|
|
116
152
|
translateY = 0
|
|
117
153
|
break
|
|
118
154
|
case 'bottom-start':
|
|
119
|
-
float.position.y = openerRect.bottom
|
|
155
|
+
float.position.y = openerRect.value.bottom
|
|
120
156
|
float.position.x = leftWithoutXMargin
|
|
121
157
|
translateX = 0
|
|
122
158
|
translateY = 0
|
|
123
159
|
break
|
|
124
160
|
case 'bottom-end':
|
|
125
|
-
float.position.y = openerRect.bottom
|
|
126
|
-
float.position.x = openerRect.right
|
|
161
|
+
float.position.y = openerRect.value.bottom
|
|
162
|
+
float.position.x = openerRect.value.right
|
|
127
163
|
translateX = -100
|
|
128
164
|
translateY = 0
|
|
129
165
|
break
|
|
@@ -134,13 +170,13 @@ export const useFloating = (
|
|
|
134
170
|
translateY = 0
|
|
135
171
|
break
|
|
136
172
|
case 'left':
|
|
137
|
-
float.position.y = topWithoutTopMargin + openerRect.height / 2
|
|
173
|
+
float.position.y = topWithoutTopMargin + openerRect.value.height / 2
|
|
138
174
|
float.position.x = leftWithoutXMargin
|
|
139
175
|
translateY = -50
|
|
140
176
|
translateX = -100
|
|
141
177
|
break
|
|
142
178
|
case 'left-end':
|
|
143
|
-
float.position.y = openerRect.bottom
|
|
179
|
+
float.position.y = openerRect.value.bottom
|
|
144
180
|
float.position.x = leftWithoutXMargin
|
|
145
181
|
translateY = -100
|
|
146
182
|
translateX = -100
|
|
@@ -153,31 +189,31 @@ export const useFloating = (
|
|
|
153
189
|
break
|
|
154
190
|
case 'top':
|
|
155
191
|
float.position.y = topWithoutYMargin
|
|
156
|
-
float.position.x = leftWithoutLeftMargin + openerRect.width / 2
|
|
192
|
+
float.position.x = leftWithoutLeftMargin + openerRect.value.width / 2
|
|
157
193
|
translateX = -50
|
|
158
194
|
translateY = -100
|
|
159
195
|
break
|
|
160
196
|
case 'top-end':
|
|
161
197
|
float.position.y = topWithoutYMargin
|
|
162
|
-
float.position.x = openerRect.right
|
|
198
|
+
float.position.x = openerRect.value.right
|
|
163
199
|
translateX = -100
|
|
164
200
|
translateY = -100
|
|
165
201
|
break
|
|
166
202
|
case 'right-start':
|
|
167
203
|
float.position.y = topWithoutYMargin
|
|
168
|
-
float.position.x = openerRect.right
|
|
204
|
+
float.position.x = openerRect.value.right
|
|
169
205
|
translateX = 0
|
|
170
206
|
translateY = 0
|
|
171
207
|
break
|
|
172
208
|
case 'right':
|
|
173
|
-
float.position.y = topWithoutTopMargin + openerRect.height / 2
|
|
174
|
-
float.position.x = openerRect.right
|
|
209
|
+
float.position.y = topWithoutTopMargin + openerRect.value.height / 2
|
|
210
|
+
float.position.x = openerRect.value.right
|
|
175
211
|
translateY = -50
|
|
176
212
|
translateX = 0
|
|
177
213
|
break
|
|
178
214
|
case 'right-end':
|
|
179
|
-
float.position.y = openerRect.bottom
|
|
180
|
-
float.position.x = openerRect.right
|
|
215
|
+
float.position.y = openerRect.value.bottom
|
|
216
|
+
float.position.x = openerRect.value.right
|
|
181
217
|
translateY = -100
|
|
182
218
|
translateX = 0
|
|
183
219
|
break
|
|
@@ -185,42 +221,45 @@ export const useFloating = (
|
|
|
185
221
|
break
|
|
186
222
|
}
|
|
187
223
|
} else {
|
|
188
|
-
switch (
|
|
224
|
+
switch (actualPosition.value) {
|
|
189
225
|
case 'bottom':
|
|
190
|
-
float.position.y = containerRect.bottom - rect.value.height
|
|
191
|
-
float.position.x = containerRect.left + containerRect.width / 2
|
|
226
|
+
float.position.y = containerRect.value.bottom - rect.value.height
|
|
227
|
+
float.position.x = containerRect.value.left + containerRect.value.width / 2
|
|
192
228
|
translateX = -50
|
|
193
229
|
break
|
|
194
230
|
case 'left-end':
|
|
195
231
|
case 'bottom-start':
|
|
196
|
-
float.position.y = containerRect.bottom - rect.value.height
|
|
197
|
-
float.position.x = containerRect.left
|
|
232
|
+
float.position.y = containerRect.value.bottom - rect.value.height
|
|
233
|
+
float.position.x = containerRect.value.left
|
|
198
234
|
break
|
|
199
235
|
case 'right-end':
|
|
200
236
|
case 'bottom-end':
|
|
201
|
-
float.position.y = containerRect.bottom - rect.value.height
|
|
202
|
-
float.position.x = containerRect.right - rect.value.width
|
|
237
|
+
float.position.y = containerRect.value.bottom - rect.value.height
|
|
238
|
+
float.position.x = containerRect.value.right - rect.value.width
|
|
203
239
|
break
|
|
204
240
|
case 'left':
|
|
205
|
-
float.position.y =
|
|
206
|
-
|
|
241
|
+
float.position.y =
|
|
242
|
+
containerRect.value.top + (containerRect.value.height - rect.value.height) / 2
|
|
243
|
+
float.position.x = containerRect.value.left
|
|
207
244
|
break
|
|
208
245
|
case 'top-start':
|
|
209
246
|
case 'left-start':
|
|
210
|
-
float.position.y = containerRect.top
|
|
211
|
-
float.position.x = containerRect.left
|
|
247
|
+
float.position.y = containerRect.value.top
|
|
248
|
+
float.position.x = containerRect.value.left
|
|
212
249
|
break
|
|
213
250
|
case 'top':
|
|
214
|
-
float.position.y = containerRect.top
|
|
215
|
-
float.position.x =
|
|
251
|
+
float.position.y = containerRect.value.top
|
|
252
|
+
float.position.x =
|
|
253
|
+
containerRect.value.left + (containerRect.value.width - rect.value.width) / 2
|
|
216
254
|
break
|
|
217
255
|
case 'top-end':
|
|
218
256
|
case 'right-start':
|
|
219
|
-
float.position.y = containerRect.top
|
|
220
|
-
float.position.x = containerRect.right - rect.value.width
|
|
257
|
+
float.position.y = containerRect.value.top
|
|
258
|
+
float.position.x = containerRect.value.right - rect.value.width
|
|
221
259
|
case 'right':
|
|
222
|
-
float.position.y =
|
|
223
|
-
|
|
260
|
+
float.position.y =
|
|
261
|
+
containerRect.value.top + (containerRect.value.height - rect.value.height) / 2
|
|
262
|
+
float.position.x = containerRect.value.right - rect.value.width
|
|
224
263
|
break
|
|
225
264
|
default:
|
|
226
265
|
break
|
|
@@ -232,32 +271,40 @@ export const useFloating = (
|
|
|
232
271
|
float.position.x = realPos.x
|
|
233
272
|
float.position.y = realPos.y
|
|
234
273
|
|
|
235
|
-
if (realPos.x < containerRect.left) {
|
|
236
|
-
float.position.x = containerRect.left
|
|
274
|
+
if (realPos.x < containerRect.value.left) {
|
|
275
|
+
float.position.x = containerRect.value.left
|
|
237
276
|
translateX = 0
|
|
238
277
|
}
|
|
239
278
|
|
|
240
|
-
if (realPos.x + rect.value.width > containerRect.right) {
|
|
241
|
-
|
|
279
|
+
if (realPos.x + rect.value.width > containerRect.value.right) {
|
|
280
|
+
const fixVal = containerRect.value.right - rect.value.width
|
|
281
|
+
if (fixVal > 0) {
|
|
282
|
+
float.position.x = fixVal
|
|
283
|
+
}
|
|
242
284
|
translateX = 0
|
|
243
285
|
}
|
|
244
286
|
|
|
245
|
-
if (realPos.y < containerRect.top) {
|
|
246
|
-
float.position.y = containerRect.top
|
|
287
|
+
if (realPos.y < containerRect.value.top) {
|
|
288
|
+
float.position.y = containerRect.value.top
|
|
247
289
|
translateY = 0
|
|
248
290
|
}
|
|
249
291
|
|
|
250
|
-
if (realPos.y + rect.value.height > containerRect.bottom) {
|
|
251
|
-
|
|
292
|
+
if (realPos.y + rect.value.height > containerRect.value.bottom) {
|
|
293
|
+
const fixVal = containerRect.value.bottom - rect.value.height
|
|
294
|
+
if (fixVal > 0) {
|
|
295
|
+
float.position.y = fixVal
|
|
296
|
+
}
|
|
252
297
|
translateY = 0
|
|
253
298
|
}
|
|
254
299
|
|
|
255
300
|
safeElementDomRef.value.style.top = `${float.position.y}px`
|
|
256
301
|
safeElementDomRef.value.style.left = `${float.position.x}px`
|
|
257
|
-
|
|
302
|
+
safeElementDomRef.value.style.position = 'fixed'
|
|
258
303
|
safeElementDomRef.value.style.display = 'flex'
|
|
259
304
|
|
|
260
305
|
rect.value = safeElementDomRef.value.getBoundingClientRect()
|
|
306
|
+
|
|
307
|
+
args.callback && args.callback(rect, openerRect, containerRect, position, actualPosition)
|
|
261
308
|
})
|
|
262
309
|
|
|
263
310
|
onUnmounted(() => {
|
|
@@ -267,7 +314,10 @@ export const useFloating = (
|
|
|
267
314
|
return {
|
|
268
315
|
float,
|
|
269
316
|
rect,
|
|
270
|
-
|
|
271
|
-
|
|
317
|
+
setPosition,
|
|
318
|
+
position,
|
|
319
|
+
actualPosition,
|
|
320
|
+
openerRect,
|
|
321
|
+
containerRect
|
|
272
322
|
}
|
|
273
323
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { onBeforeUnmount, onMounted, Ref } from 'vue'
|
|
2
2
|
|
|
3
|
-
function useKeyDown(
|
|
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(
|
|
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
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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) {
|