Skip to content

Commit 78b128a

Browse files
committed
revert(BPopover): revert bpopover script setup
Since Vue SFC cannot scrub external interfaces for complex types, and Popover object is too complex to recreate interanlly, a reversion to pre script setup is necessary to fix this issue. The post code is still included but is commented for future ease of use.
1 parent 5265ca7 commit 78b128a

File tree

1 file changed

+149
-1
lines changed

1 file changed

+149
-1
lines changed

packages/bootstrap-vue-3/src/components/BPopover.vue

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,160 @@
2020
</div>
2121
</template>
2222

23-
<script setup lang="ts">
23+
<script lang="ts">
24+
import {
25+
ComponentPublicInstance,
26+
computed,
27+
defineComponent,
28+
nextTick,
29+
onBeforeUnmount,
30+
onMounted,
31+
PropType,
32+
ref,
33+
watch,
34+
} from 'vue'
35+
import Popover from 'bootstrap/js/dist/popover'
36+
import {useEventListener} from '../composables'
37+
import type {BPopoverDelayObject} from '../types/components'
38+
import type {ColorVariant} from '../types'
39+
40+
export default defineComponent({
41+
props: {
42+
container: {
43+
type: [String, Object] as PropType<
44+
string | ComponentPublicInstance<HTMLElement> | HTMLElement
45+
>,
46+
default: 'body',
47+
},
48+
content: {type: String},
49+
id: {type: String},
50+
noninteractive: {type: Boolean, default: false},
51+
placement: {type: String as PropType<Popover.Options['placement']>, default: 'right'},
52+
target: {
53+
type: [String, Object] as PropType<
54+
string | ComponentPublicInstance<HTMLElement> | HTMLElement | undefined
55+
>,
56+
default: undefined,
57+
},
58+
title: {type: String},
59+
delay: {type: [Number, Object] as PropType<number | BPopoverDelayObject>, default: 0},
60+
triggers: {type: String as PropType<Popover.Options['trigger']>, default: 'click'},
61+
show: {type: Boolean, default: false},
62+
variant: {type: String as PropType<ColorVariant>, default: undefined},
63+
html: {type: Boolean, default: true},
64+
sanitize: {type: Boolean, default: false},
65+
offset: {type: String as PropType<Popover.Options['offset']>, default: '0'},
66+
},
67+
emits: ['show', 'shown', 'hide', 'hidden', 'inserted'],
68+
setup(props, {emit, slots}) {
69+
const element = ref<HTMLElement>()
70+
const target = ref<HTMLElement | undefined>()
71+
const instance = ref<Popover>()
72+
const titleRef = ref<HTMLElement>()
73+
const contentRef = ref<HTMLElement>()
74+
const classes = computed(() => ({
75+
[`b-popover-${props.variant}`]: props.variant,
76+
}))
77+
78+
const cleanElementProp = (
79+
target: string | ComponentPublicInstance<HTMLElement> | HTMLElement | undefined
80+
): HTMLElement | string | undefined => {
81+
if (typeof target === 'string') {
82+
return target
83+
} else if (target instanceof HTMLElement) return target
84+
else if (typeof target !== 'undefined')
85+
return (target as ComponentPublicInstance<HTMLElement>).$el as HTMLElement
86+
return undefined
87+
}
88+
89+
const getElement = (element: HTMLElement | string | undefined): HTMLElement | undefined => {
90+
if (!element) return undefined
91+
if (typeof element === 'string') {
92+
const idElement = document.getElementById(element)
93+
return idElement ? idElement : undefined
94+
}
95+
return element
96+
}
97+
98+
const generatePopoverInstance = (
99+
targetValue: string | ComponentPublicInstance<HTMLElement> | HTMLElement | undefined
100+
) => {
101+
target.value = getElement(cleanElementProp(targetValue))
102+
103+
if (!target.value) return
104+
105+
instance.value = new Popover(target.value, {
106+
container: cleanElementProp(props.container),
107+
trigger: props.triggers,
108+
placement: props.placement,
109+
title: props.title || slots.title ? titleRef.value : '',
110+
content: contentRef.value,
111+
html: props.html,
112+
delay: props.delay,
113+
sanitize: props.sanitize,
114+
offset: props.offset,
115+
})
116+
}
117+
118+
onMounted(() => {
119+
nextTick(() => {
120+
generatePopoverInstance(props.target)
121+
})
122+
123+
element.value?.parentNode?.removeChild(element.value)
124+
125+
if (props.show) {
126+
instance.value?.show()
127+
}
128+
})
129+
130+
onBeforeUnmount(() => {
131+
instance.value?.dispose()
132+
})
133+
134+
watch(
135+
() => props.target,
136+
(newValue) => {
137+
instance.value?.dispose()
138+
generatePopoverInstance(newValue)
139+
}
140+
)
141+
142+
watch(
143+
() => props.show,
144+
(show, oldVal) => {
145+
if (show !== oldVal) {
146+
if (show) {
147+
instance.value?.show()
148+
} else {
149+
instance.value?.hide()
150+
}
151+
}
152+
}
153+
)
154+
155+
useEventListener(target, 'show.bs.popover', () => emit('show'))
156+
useEventListener(target, 'shown.bs.popover', () => emit('shown'))
157+
useEventListener(target, 'hide.bs.popover', () => emit('hide'))
158+
useEventListener(target, 'hidden.bs.popover', () => emit('hidden'))
159+
useEventListener(target, 'inserted.bs.popover', () => emit('inserted'))
160+
161+
return {
162+
element,
163+
titleRef,
164+
contentRef,
165+
classes,
166+
}
167+
},
168+
})
169+
/*
24170
// import type {BPopoverEmits, BPopoverProps} from '../types/components'
25171
import type {BPopoverDelayObject} from '../types/components'
26172
import Popover from 'bootstrap/js/dist/popover'
27173
import {
28174
ComponentPublicInstance,
29175
computed,
176+
defineComponent,
30177
nextTick,
31178
onBeforeUnmount,
32179
onMounted,
@@ -171,4 +318,5 @@ useEventListener(target, 'shown.bs.popover', () => emit('shown'))
171318
useEventListener(target, 'hide.bs.popover', () => emit('hide'))
172319
useEventListener(target, 'hidden.bs.popover', () => emit('hidden'))
173320
useEventListener(target, 'inserted.bs.popover', () => emit('inserted'))
321+
*/
174322
</script>

0 commit comments

Comments
 (0)