@redseed/redseed-ui-vue3 2.18.0 → 2.18.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import { onClickOutside } from '@vueuse/core'
|
|
2
|
+
import { ref, computed, onMounted, onUnmounted, watchEffect } from 'vue'
|
|
3
|
+
import { onClickOutside, useResizeObserver, useElementBounding } from '@vueuse/core'
|
|
4
4
|
import FormFieldSlot from './FormFieldSlot.vue'
|
|
5
5
|
import { ChevronDownIcon, CheckIcon } from '@heroicons/vue/24/outline'
|
|
6
6
|
|
|
@@ -19,14 +19,11 @@ const props = defineProps({
|
|
|
19
19
|
|
|
20
20
|
const emit = defineEmits(['change'])
|
|
21
21
|
|
|
22
|
-
const formFieldSelectElement = ref(null)
|
|
23
|
-
|
|
24
|
-
onClickOutside(formFieldSelectElement, () => close())
|
|
25
|
-
|
|
26
22
|
const isOpen = ref(false)
|
|
27
23
|
|
|
28
24
|
function toggleOptions() {
|
|
29
25
|
isOpen.value = !isOpen.value
|
|
26
|
+
if (isOpen.value) setTimeout(() => calculateDropdownPosition(), 1)
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
function close() {
|
|
@@ -43,7 +40,80 @@ function nativeChoose(event) {
|
|
|
43
40
|
emit('change', event.target.value)
|
|
44
41
|
}
|
|
45
42
|
|
|
43
|
+
const formFieldSelectElement = ref(null)
|
|
46
44
|
const selectElement = ref(null)
|
|
45
|
+
const dropdownElement = ref(null)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
onClickOutside(formFieldSelectElement, () => close())
|
|
50
|
+
|
|
51
|
+
// useResizeObserver(formFieldSelectElement, (entries) => {
|
|
52
|
+
// const entry = entries[0]
|
|
53
|
+
// const { width } = entry.contentRect
|
|
54
|
+
// dropdownWidth.value = width
|
|
55
|
+
// })
|
|
56
|
+
|
|
57
|
+
// watchEffect(() => calculateDropdownPosition())
|
|
58
|
+
|
|
59
|
+
const selectElementBounding = useElementBounding(selectElement)
|
|
60
|
+
|
|
61
|
+
function calculateDropdownPosition() {
|
|
62
|
+
if (!dropdownElement.value) return
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get the viewport height
|
|
66
|
+
*/
|
|
67
|
+
const viewportHeight = window.innerHeight
|
|
68
|
+
console.log('viewportHeight', viewportHeight)
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get the dropdown element height
|
|
72
|
+
*/
|
|
73
|
+
const dropdownElementHeight = dropdownElement.value.offsetHeight
|
|
74
|
+
console.log('dropdownElementHeight', dropdownElementHeight)
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get space above the select element
|
|
78
|
+
*/
|
|
79
|
+
const spaceAboveSelectElement = selectElementBounding.top.value
|
|
80
|
+
console.log('spaceAboveSelectElement', spaceAboveSelectElement)
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get space below the select element
|
|
84
|
+
*/
|
|
85
|
+
const spaceBelowSelectElement = viewportHeight - selectElementBounding.bottom.value
|
|
86
|
+
console.log('spaceBelowSelectElement', spaceBelowSelectElement)
|
|
87
|
+
|
|
88
|
+
dropdownElement.value.style.width = `${selectElementBounding.width.value}px`
|
|
89
|
+
|
|
90
|
+
if (spaceAboveSelectElement <= dropdownElementHeight
|
|
91
|
+
&& spaceBelowSelectElement <= dropdownElementHeight) {
|
|
92
|
+
dropdownElement.value.style.top = '0'
|
|
93
|
+
dropdownElement.value.style.bottom = 'auto'
|
|
94
|
+
return
|
|
95
|
+
} else if (spaceBelowSelectElement > dropdownElementHeight) {
|
|
96
|
+
console.log('space below >= dropdown height')
|
|
97
|
+
dropdownElement.value.style.top = `${selectElementBounding.bottom.value}px`
|
|
98
|
+
console.log('dropdownElement.value.style.top', dropdownElement.value.style.top)
|
|
99
|
+
dropdownElement.value.style.bottom = 'auto'
|
|
100
|
+
return
|
|
101
|
+
} else if (spaceAboveSelectElement > dropdownElementHeight) {
|
|
102
|
+
console.log('space above > dropdown height')
|
|
103
|
+
dropdownElement.value.style.top = 'auto'
|
|
104
|
+
dropdownElement.value.style.bottom = `${spaceBelowSelectElement + selectElementBounding.height.value + 8}px`
|
|
105
|
+
console.log('dropdownElement.value.style.bottom', dropdownElement.value.style.bottom)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onMounted(() => {
|
|
111
|
+
window.addEventListener('resize', () => calculateDropdownPosition())
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
onUnmounted(() => {
|
|
115
|
+
window.removeEventListener('resize', () => calculateDropdownPosition())
|
|
116
|
+
})
|
|
47
117
|
|
|
48
118
|
defineExpose({
|
|
49
119
|
focus() {
|
|
@@ -89,45 +159,49 @@ defineExpose({
|
|
|
89
159
|
</option>
|
|
90
160
|
</select>
|
|
91
161
|
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<div v-show="isOpen"
|
|
101
|
-
:class="[
|
|
102
|
-
'rsui-form-field-select__options',
|
|
103
|
-
{ 'rsui-form-field-select__options--open': isOpen }
|
|
104
|
-
]"
|
|
162
|
+
<Teleport to="body">
|
|
163
|
+
<transition
|
|
164
|
+
enter-active-class="enter-active-class"
|
|
165
|
+
enter-from-class="enter-from-class"
|
|
166
|
+
enter-to-class="enter-to-class"
|
|
167
|
+
leave-active-class="leave-active-class"
|
|
168
|
+
leave-from-class="leave-from-class"
|
|
169
|
+
leave-to-class="leave-to-class"
|
|
105
170
|
>
|
|
106
|
-
<div
|
|
107
|
-
|
|
171
|
+
<div ref="dropdownElement"
|
|
172
|
+
v-show="isOpen"
|
|
173
|
+
:class="[
|
|
174
|
+
'rsui-form-field-select__options',
|
|
175
|
+
{ 'rsui-form-field-select__options--open': isOpen }
|
|
176
|
+
]"
|
|
108
177
|
>
|
|
109
|
-
<div class="rsui-form-field-select__option-
|
|
110
|
-
|
|
111
|
-
Select an option
|
|
112
|
-
</slot>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
<div v-for="option in options"
|
|
116
|
-
:key="option.value"
|
|
117
|
-
class="rsui-form-field-select__option"
|
|
118
|
-
@click="choose(option)"
|
|
119
|
-
>
|
|
120
|
-
<div class="rsui-form-field-select__option-label"
|
|
121
|
-
:title="option.label"
|
|
178
|
+
<div class="rsui-form-field-select__option rsui-form-field-select__option--disabled"
|
|
179
|
+
value=""
|
|
122
180
|
>
|
|
123
|
-
|
|
181
|
+
<div class="rsui-form-field-select__option-label">
|
|
182
|
+
<slot name="default-option">
|
|
183
|
+
Select an option
|
|
184
|
+
</slot>
|
|
185
|
+
</div>
|
|
124
186
|
</div>
|
|
125
|
-
<div
|
|
126
|
-
|
|
187
|
+
<div v-for="option in options"
|
|
188
|
+
:key="option.value"
|
|
189
|
+
class="rsui-form-field-select__option"
|
|
190
|
+
@click="choose(option)"
|
|
191
|
+
>
|
|
192
|
+
<div class="rsui-form-field-select__option-label"
|
|
193
|
+
:title="option.label"
|
|
194
|
+
>
|
|
195
|
+
{{ option.label }}
|
|
196
|
+
</div>
|
|
197
|
+
<div class="rsui-form-field-select__option-icon">
|
|
198
|
+
<CheckIcon v-if="option.value === model"></CheckIcon>
|
|
199
|
+
</div>
|
|
127
200
|
</div>
|
|
128
201
|
</div>
|
|
129
|
-
</
|
|
130
|
-
</
|
|
202
|
+
</transition>
|
|
203
|
+
</Teleport>
|
|
204
|
+
|
|
131
205
|
<div :class="[
|
|
132
206
|
'rsui-form-field-select__icon',
|
|
133
207
|
{ 'rsui-form-field-select__icon--open': isOpen }
|
|
@@ -173,8 +247,9 @@ defineExpose({
|
|
|
173
247
|
}
|
|
174
248
|
|
|
175
249
|
&__options {
|
|
176
|
-
@apply hidden absolute
|
|
250
|
+
@apply hidden absolute top-0 w-full z-10;
|
|
177
251
|
@apply bg-white p-2 mt-2 rounded-md shadow-full-light;
|
|
252
|
+
@apply max-h-[80vh] sm:max-h-[60vh] overflow-y-auto;
|
|
178
253
|
&--open {
|
|
179
254
|
@apply block;
|
|
180
255
|
}
|