@volverjs/ui-vue 0.0.8-beta.7 → 0.0.8-beta.8

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.
@@ -1,7 +1,12 @@
1
1
  <script lang="ts">
2
2
  export default {
3
3
  name: 'VvCombobox',
4
- components: { VvDropdown, VvDropdownOption, VvDropdownOptgroup },
4
+ components: {
5
+ VvDropdown,
6
+ VvDropdownOption,
7
+ VvDropdownOptgroup,
8
+ VvButton,
9
+ },
5
10
  }
6
11
  </script>
7
12
 
@@ -14,6 +19,7 @@
14
19
  import VvDropdownOptgroup from '../VvDropdown/VvDropdownOptgroup.vue'
15
20
  import VvSelect from '../VvSelect/VvSelect.vue'
16
21
  import VvBadge from '../VvBadge/VvBadge.vue'
22
+ import VvButton from '../VvButton/VvButton.vue'
17
23
  import HintSlotFactory from '../common/HintSlot'
18
24
  import type { Option } from '../../types/generic'
19
25
  import { DropdownRole } from '../../constants'
@@ -133,6 +139,9 @@
133
139
  const hasSearchId = computed(() => `${hasId.value}-search`)
134
140
  const hasLabelId = computed(() => `${hasId.value}-label`)
135
141
 
142
+ // ref
143
+ const dropdownEl = ref()
144
+
136
145
  // icons
137
146
  const { hasIcon, hasIconBefore, hasIconAfter } = useComponentIcon(
138
147
  icon,
@@ -366,11 +375,13 @@
366
375
  </label>
367
376
  <div ref="wrapperEl" class="vv-select__wrapper">
368
377
  <VvDropdown
378
+ ref="dropdownEl"
369
379
  v-model="expanded"
370
380
  v-bind="dropdownProps"
371
381
  :role="DropdownRole.listbox"
372
382
  @after-expand="onAfterExpand"
373
383
  @after-collapse="onAfterCollapse"
384
+ @click="$event.stopPropagation()"
374
385
  >
375
386
  <template
376
387
  v-if="searchable || $slots['dropdown::before']"
@@ -563,9 +574,16 @@
563
574
  </slot>
564
575
  </VvDropdownOption>
565
576
  </template>
566
- <template v-if="$slots['dropdown::after']" #after>
577
+ <template #after>
567
578
  <!-- @slot Slot after dropdown items -->
568
- <slot name="dropdown::after" />
579
+ <slot name="dropdown::after">
580
+ <!-- Close button if dropdown custom position is enabled and floating-ui disabled -->
581
+ <VvButton
582
+ v-if="dropdownEl?.dropdownCustomPosition === 'true'"
583
+ label="Close"
584
+ modifiers="secondary"
585
+ />
586
+ </slot>
569
587
  </template>
570
588
  </VvDropdown>
571
589
  </div>
@@ -132,6 +132,7 @@ export const VvComboboxProps = {
132
132
  */
133
133
  dropdownModifiers: {
134
134
  type: [String, Array] as PropType<string | string[]>,
135
+ default: 'mobile',
135
136
  },
136
137
  /**
137
138
  * Open dropdown on focus
@@ -43,7 +43,7 @@
43
43
 
44
44
  // template elements
45
45
  const localReferenceEl = ref<HTMLElement | null>(null)
46
- const floatingEl: Ref<HTMLElement | null> = ref(null)
46
+ const floatingEl: Ref = ref()
47
47
  const arrowEl = ref<HTMLElement | null>(null)
48
48
  const listEl = ref<HTMLUListElement | null>(null)
49
49
  const referenceEl = computed({
@@ -53,6 +53,25 @@
53
53
  },
54
54
  })
55
55
 
56
+ // ref to store the value of css-var "--dropdown-custom-position"
57
+ const dropdownCustomPosition = ref()
58
+
59
+ // set dropdownCustomPosition value from css-var "--dropdown-custom-position"
60
+ const onChangeDropdownCustomPosition = () => {
61
+ dropdownCustomPosition.value = window
62
+ .getComputedStyle(floatingEl.value)
63
+ .getPropertyValue('--dropdown-custom-position')
64
+ ?.trim()
65
+ }
66
+
67
+ // observe dropdown style for "--dropdown-custom-position" css var to disable floating-ui
68
+ onMounted(() => {
69
+ useMutationObserver(floatingEl.value, onChangeDropdownCustomPosition, {
70
+ attributeFilter: ['style'],
71
+ window,
72
+ })
73
+ })
74
+
56
75
  // floating ui
57
76
  const middleware = computed(() => {
58
77
  const toReturn = []
@@ -138,17 +157,22 @@
138
157
  middleware,
139
158
  },
140
159
  )
141
- const dropdownPlacement = computed(() => ({
142
- position: strategy.value,
143
- top: `${y.value ?? 0}px`,
144
- left: `${x.value ?? 0}px`,
145
- maxWidth: maxWidth.value,
146
- maxHeight: maxHeight.value,
147
- width:
148
- props.triggerWidth && referenceEl.value
149
- ? `${referenceEl.value.offsetWidth}px`
150
- : undefined,
151
- }))
160
+ const dropdownPlacement = computed(() => {
161
+ if (dropdownCustomPosition?.value === 'true') {
162
+ return {}
163
+ }
164
+ return {
165
+ position: strategy.value,
166
+ top: `${y.value ?? 0}px`,
167
+ left: `${x.value ?? 0}px`,
168
+ maxWidth: maxWidth.value,
169
+ maxHeight: maxHeight.value,
170
+ width:
171
+ props.triggerWidth && referenceEl.value
172
+ ? `${referenceEl.value.offsetWidth}px`
173
+ : undefined,
174
+ }
175
+ })
152
176
 
153
177
  // placement
154
178
  const side = computed(() => placement.value.split('-')[0])
@@ -162,6 +186,9 @@
162
186
  }[side.value] ?? 'bottom'),
163
187
  )
164
188
  const arrowPlacement = computed(() => {
189
+ if (dropdownCustomPosition?.value === 'true') {
190
+ return {}
191
+ }
165
192
  if (['bottom', 'top'].includes(staticSide.value)) {
166
193
  return {
167
194
  right: `${middlewareData.value.arrow?.x ?? 0}px`,
@@ -201,7 +228,7 @@
201
228
  const init = (el: HTMLElement) => {
202
229
  referenceEl.value = el
203
230
  }
204
- defineExpose({ toggle, show, hide, init })
231
+ defineExpose({ toggle, show, hide, init, dropdownCustomPosition })
205
232
  watch(expanded, (newValue) => {
206
233
  if (newValue && props.autofocusFirst) {
207
234
  nextTick(() => {
@@ -344,14 +371,10 @@
344
371
  }
345
372
  })
346
373
  onKeyStroke([' ', 'Enter'], (e) => {
347
- if (
348
- expanded.value &&
349
- focused.value &&
350
- e.target !== document.activeElement
351
- ) {
352
- e.preventDefault()
353
- const activeElement = document.activeElement as HTMLElement
354
- activeElement.click()
374
+ const htmlEl = e.target as HTMLElement
375
+
376
+ if (expanded.value && focused.value && htmlEl) {
377
+ htmlEl?.click()
355
378
  }
356
379
  })
357
380
  const onTransitionBeforeEnter = () => {
@@ -380,6 +403,7 @@
380
403
  ref="floatingEl"
381
404
  :style="dropdownPlacement"
382
405
  :class="bemCssClasses"
406
+ @click="hide()"
383
407
  >
384
408
  <div
385
409
  v-if="props.arrow"
@@ -1,11 +1,17 @@
1
1
  import type { PropType } from 'vue'
2
- import { DropdownProps, IdProps, ModifiersProps } from '../../props'
2
+ import { DropdownProps, IdProps } from '../../props'
3
3
  import { DropdownRole } from '../../constants'
4
4
 
5
5
  export const VvDropdownProps = {
6
6
  ...IdProps,
7
- ...ModifiersProps,
8
7
  ...DropdownProps,
8
+ /**
9
+ * Component BEM modifiers
10
+ */
11
+ modifiers: {
12
+ type: [String, Array] as PropType<string | string[]>,
13
+ default: 'mobile',
14
+ },
9
15
  /**
10
16
  * Show / hide dropdown programmatically
11
17
  */
@@ -19,7 +19,28 @@ export const defaultArgs = {
19
19
  ...propsToObject(VvComboboxProps),
20
20
  name: 'vv-combobox',
21
21
  maxValues: undefined,
22
- options: ['Option 1', 'Option 2', 'Option 3'],
22
+ options: [
23
+ 'Option 1',
24
+ 'Option 2',
25
+ 'Option 3',
26
+ 'Option 4',
27
+ 'Option 5',
28
+ 'Option 6',
29
+ 'Option 7',
30
+ 'Option 8',
31
+ 'Option 9',
32
+ 'Option 10',
33
+ 'Option 11',
34
+ 'Option 12',
35
+ 'Option 13',
36
+ 'Option 14',
37
+ 'Option 15',
38
+ 'Option 16',
39
+ 'Option 17',
40
+ 'Option 18',
41
+ 'Option 19',
42
+ 'Option 20',
43
+ ],
23
44
  placeholder: 'Select an option',
24
45
  label: 'Combobox label',
25
46
  }