@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
  {
2
2
  "name": "@redseed/redseed-ui-vue3",
3
- "version": "2.18.0",
3
+ "version": "2.18.1",
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,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
- <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
- ]"
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 class="rsui-form-field-select__option rsui-form-field-select__option--disabled"
107
- value=""
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-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"
178
+ <div class="rsui-form-field-select__option rsui-form-field-select__option--disabled"
179
+ value=""
122
180
  >
123
- {{ option.label }}
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 class="rsui-form-field-select__option-icon">
126
- <CheckIcon v-if="option.value === model"></CheckIcon>
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
- </div>
130
- </transition>
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 origin-top w-full z-10;
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
  }