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