@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
  {
2
2
  "name": "@redseed/redseed-ui-vue3",
3
- "version": "2.18.0",
3
+ "version": "2.18.2",
4
4
  "description": "RedSeed UI Vue 3 components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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
- <transition
93
- enter-active-class="enter-active-class"
94
- enter-from-class="enter-from-class"
95
- enter-to-class="enter-to-class"
96
- leave-active-class="leave-active-class"
97
- leave-from-class="leave-from-class"
98
- leave-to-class="leave-to-class"
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 class="rsui-form-field-select__option rsui-form-field-select__option--disabled"
107
- value=""
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-label">
110
- <slot name="default-option">
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
- {{ option.label }}
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 class="rsui-form-field-select__option-icon">
126
- <CheckIcon v-if="option.value === model"></CheckIcon>
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
- </div>
130
- </transition>
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 origin-top w-full z-10;
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
  }