|
1 | | -import { defineComponent, h, ref, provide, watch, PropType, onUnmounted, nextTick } from 'vue' |
| 1 | +import { defineComponent, h, nextTick, onUnmounted, provide, PropType, ref, Ref, watch } from 'vue' |
2 | 2 | import type { Placement } from '@popperjs/core' |
3 | 3 |
|
4 | 4 | import { usePopper } from '../../composables' |
5 | 5 | import type { Triggers } from '../../types' |
6 | 6 | import { getNextActiveElement, isRTL } from '../../utils' |
7 | 7 |
|
8 | 8 | import type { Alignments } from './types' |
9 | | -import { getPlacement } from './utils' |
| 9 | +import { getPlacement, getReferenceElement } from './utils' |
10 | 10 | import { CFocusTrap } from '../focus-trap' |
11 | 11 |
|
12 | 12 | const CDropdown = defineComponent({ |
@@ -113,6 +113,21 @@ const CDropdown = defineComponent({ |
113 | 113 | type: Boolean, |
114 | 114 | default: true, |
115 | 115 | }, |
| 116 | + /** |
| 117 | + * Sets the reference element for positioning the Vue Dropdown Menu. |
| 118 | + * - `toggle` - The Vue Dropdown Toggle button (default). |
| 119 | + * - `parent` - The Vue Dropdown wrapper element. |
| 120 | + * - `HTMLElement` - A custom HTML element. |
| 121 | + * - `Ref` - A custom reference element. |
| 122 | + * |
| 123 | + * @since 5.7.0 |
| 124 | + */ |
| 125 | + reference: { |
| 126 | + type: [String, Object] as PropType< |
| 127 | + 'parent' | 'toggle' | HTMLElement | Ref<HTMLElement | null> |
| 128 | + >, |
| 129 | + default: 'toggle', |
| 130 | + }, |
116 | 131 | /** |
117 | 132 | * Generates dropdown menu using Teleport. |
118 | 133 | * |
@@ -157,8 +172,9 @@ const CDropdown = defineComponent({ |
157 | 172 | 'show', |
158 | 173 | ], |
159 | 174 | setup(props, { slots, emit }) { |
160 | | - const dropdownToggleRef = ref() |
161 | | - const dropdownMenuRef = ref() |
| 175 | + const dropdownRef = ref<HTMLElement | null>(null) |
| 176 | + const dropdownMenuRef = ref<HTMLElement | null>(null) |
| 177 | + const dropdownToggleRef = ref<HTMLElement | null>(null) |
162 | 178 | const pendingKeyDownEventRef = ref<KeyboardEvent | null>(null) |
163 | 179 | const popper = ref(typeof props.alignment === 'object' ? false : props.popper) |
164 | 180 | const visible = ref(props.visible) |
@@ -191,8 +207,13 @@ const CDropdown = defineComponent({ |
191 | 207 |
|
192 | 208 | watch(visible, () => { |
193 | 209 | if (visible.value && dropdownToggleRef.value && dropdownMenuRef.value) { |
194 | | - if (popper.value) { |
195 | | - initPopper(dropdownToggleRef.value, dropdownMenuRef.value, popperConfig) |
| 210 | + const referenceElement = getReferenceElement( |
| 211 | + props.reference, |
| 212 | + dropdownToggleRef, |
| 213 | + dropdownRef |
| 214 | + ) |
| 215 | + if (referenceElement && popper.value) { |
| 216 | + initPopper(referenceElement, dropdownMenuRef.value, popperConfig) |
196 | 217 | } |
197 | 218 |
|
198 | 219 | window.addEventListener('click', handleClick) |
@@ -334,6 +355,7 @@ const CDropdown = defineComponent({ |
334 | 355 | ? 'dropup dropup-center' |
335 | 356 | : props.direction, |
336 | 357 | ], |
| 358 | + ref: dropdownRef, |
337 | 359 | }, |
338 | 360 | slots.default && slots.default() |
339 | 361 | ) |
|
0 commit comments