mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-19 14:00:50 +08:00
refactor(popover): ts
This commit is contained in:
parent
defbb58129
commit
88db9bf48f
@ -97,6 +97,10 @@
|
||||
</div>
|
||||
```
|
||||
|
||||
```script
|
||||
console.log('wow')
|
||||
```
|
||||
|
||||
```css
|
||||
.popover-grid {
|
||||
display: grid;
|
||||
|
@ -1 +0,0 @@
|
||||
export { default as NPopover } from './src/Popover'
|
1
src/popover/index.ts
Normal file
1
src/popover/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as NPopover, popoverProps } from './src/Popover'
|
@ -1,310 +0,0 @@
|
||||
import { h, ref, computed, watch, createTextVNode, defineComponent } from 'vue'
|
||||
import { VBinder, VTarget } from 'vueuc'
|
||||
import { useMergedState, useCompitable, useIsMounted, useMemo } from 'vooks'
|
||||
import { call, keep, warn } from '../../_utils'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import NPopoverBody from './PopoverBody'
|
||||
|
||||
const bodyPropKeys = Object.keys(NPopoverBody.props)
|
||||
|
||||
function appendEvents (vNode, events) {
|
||||
Object.entries(events).forEach(([key, handler]) => {
|
||||
if (!vNode.props) vNode.props = {}
|
||||
const originalHandler = vNode.props[key]
|
||||
if (!originalHandler) vNode.props[key] = handler
|
||||
else {
|
||||
vNode.props[key] = (...args) => {
|
||||
originalHandler(...args)
|
||||
handler()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getFirstSlotVNode (slots, slotName = 'default') {
|
||||
let slot = slots[slotName]
|
||||
if (!slot) {
|
||||
warn('getFirstSlotVNode', `slot[${slotName}] is empty`)
|
||||
}
|
||||
slot = slot()
|
||||
// vue will normalize the slot, so slot must be an array
|
||||
if (slot.length === 1) {
|
||||
return slot[0]
|
||||
} else {
|
||||
warn('getFirstSlotVNode', `slot[${slotName}] should have exactly one child`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const textVNodeType = createTextVNode('').type
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Popover',
|
||||
provide () {
|
||||
return {
|
||||
NPopover: this
|
||||
}
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
...useTheme.props,
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
defaultShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
trigger: {
|
||||
validator (value) {
|
||||
return ['hover', 'click'].includes(value)
|
||||
},
|
||||
default: undefined
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
raw: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'bottom'
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
displayDirective: {
|
||||
type: String,
|
||||
default: 'if'
|
||||
},
|
||||
arrowStyle: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
},
|
||||
filp: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// private
|
||||
padded: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// events
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:show': {
|
||||
type: Function,
|
||||
default: undefined
|
||||
},
|
||||
// deprecated
|
||||
onShow: {
|
||||
validator () {
|
||||
warn(
|
||||
'popover',
|
||||
'`on-show` is deprecated, please use `on-update:show` instead.'
|
||||
)
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
},
|
||||
onHide: {
|
||||
validator () {
|
||||
warn(
|
||||
'popover',
|
||||
'`on-hide` is deprecated, please use `on-update:show` instead.'
|
||||
)
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
},
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
// setup show
|
||||
const controlledShowRef = computed(() => props.show)
|
||||
const uncontrolledShowRef = ref(props.defaultShow)
|
||||
const mergedShowWithoutDisabledRef = useMergedState(
|
||||
controlledShowRef,
|
||||
uncontrolledShowRef
|
||||
)
|
||||
const mergedShowRef = computed(() => {
|
||||
return props.disabled ? false : mergedShowWithoutDisabledRef.value
|
||||
})
|
||||
// setup show-arrow
|
||||
const compatibleShowArrowRef = useCompitable(props, ['arrow', 'showArrow'])
|
||||
watch(mergedShowRef, (value) => {
|
||||
if (props.showWatcher) {
|
||||
props.showWatcher(value)
|
||||
}
|
||||
})
|
||||
return {
|
||||
isMounted: useIsMounted(),
|
||||
positionManually: useMemo(() => {
|
||||
return props.x !== undefined && props.y !== undefined
|
||||
}),
|
||||
// if to show popover body
|
||||
uncontrolledShow: uncontrolledShowRef,
|
||||
mergedShow: mergedShowRef,
|
||||
compatibleShowArrow: compatibleShowArrowRef
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showTimerId: null,
|
||||
hideTimerId: null,
|
||||
triggerVNode: null,
|
||||
bodyInstance: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doUpdateShow (value) {
|
||||
const { 'onUpdate:show': onUpdateShow, onShow, onHide } = this
|
||||
this.uncontrolledShow = value
|
||||
if (onUpdateShow) {
|
||||
call(onUpdateShow, value)
|
||||
}
|
||||
if (value && onShow) {
|
||||
call(onShow, true)
|
||||
}
|
||||
if (value && onHide) {
|
||||
call(onHide, false)
|
||||
}
|
||||
},
|
||||
syncPosition () {
|
||||
if (this.bodyInstance) {
|
||||
this.bodyInstance.syncPosition()
|
||||
}
|
||||
},
|
||||
getTriggerElement () {
|
||||
return this.triggerVNode.el
|
||||
},
|
||||
clearTimer () {
|
||||
const { showTimerId, hideTimerId } = this
|
||||
if (showTimerId) {
|
||||
window.clearTimeout(showTimerId)
|
||||
this.showTimerId = null
|
||||
}
|
||||
if (hideTimerId) {
|
||||
window.clearTimeout(hideTimerId)
|
||||
this.hideTimerId = null
|
||||
}
|
||||
},
|
||||
handleMouseEnter () {
|
||||
if (this.trigger === 'hover' && !this.disabled) {
|
||||
this.clearTimer()
|
||||
if (this.mergedShow) return
|
||||
this.showTimerId = window.setTimeout(() => {
|
||||
this.doUpdateShow(true)
|
||||
this.showTimerId = null
|
||||
}, this.delay)
|
||||
}
|
||||
},
|
||||
handleMouseLeave () {
|
||||
if (this.trigger === 'hover' && !this.disabled) {
|
||||
this.clearTimer()
|
||||
if (!this.mergedShow) return
|
||||
this.hideTimerId = window.setTimeout(() => {
|
||||
this.doUpdateShow(false)
|
||||
this.hideTimerId = null
|
||||
}, this.duration)
|
||||
}
|
||||
},
|
||||
// will be called in popover-content
|
||||
handleMouseMoveOutside (e) {
|
||||
this.handleMouseLeave(e)
|
||||
},
|
||||
// will be called in popover-content
|
||||
handleClickOutside () {
|
||||
if (!this.mergedShow) return
|
||||
if (this.trigger === 'click') {
|
||||
this.clearTimer()
|
||||
this.doUpdateShow(false)
|
||||
}
|
||||
},
|
||||
handleClick () {
|
||||
if (this.trigger === 'click' && !this.disabled) {
|
||||
this.clearTimer()
|
||||
const nextShow = !this.mergedShow
|
||||
this.doUpdateShow(nextShow)
|
||||
}
|
||||
},
|
||||
setShow (value) {
|
||||
this.uncontrolledShow = value
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { positionManually } = this
|
||||
const slots = { ...this.$slots }
|
||||
let triggerVNode
|
||||
if (!positionManually) {
|
||||
if (slots.activator) {
|
||||
triggerVNode = getFirstSlotVNode(slots, 'activator')
|
||||
} else {
|
||||
triggerVNode = getFirstSlotVNode(slots, 'trigger')
|
||||
}
|
||||
triggerVNode =
|
||||
triggerVNode.type === textVNodeType
|
||||
? h('span', [triggerVNode])
|
||||
: triggerVNode
|
||||
|
||||
appendEvents(triggerVNode, {
|
||||
onClick: this.handleClick,
|
||||
onMouseEnter: this.handleMouseEnter,
|
||||
onMouseLeave: this.handleMouseLeave
|
||||
})
|
||||
this.triggerVNode = triggerVNode
|
||||
}
|
||||
|
||||
return h(VBinder, null, {
|
||||
default: () => {
|
||||
return [
|
||||
positionManually
|
||||
? null
|
||||
: h(VTarget, null, {
|
||||
default: () => triggerVNode
|
||||
}),
|
||||
h(
|
||||
NPopoverBody,
|
||||
keep(this.$props, bodyPropKeys, {
|
||||
...this.$attrs,
|
||||
show: this.mergedShow
|
||||
}),
|
||||
slots
|
||||
)
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
371
src/popover/src/Popover.ts
Normal file
371
src/popover/src/Popover.ts
Normal file
@ -0,0 +1,371 @@
|
||||
import {
|
||||
h,
|
||||
ref,
|
||||
reactive,
|
||||
computed,
|
||||
createTextVNode,
|
||||
defineComponent,
|
||||
PropType,
|
||||
VNode,
|
||||
Slots,
|
||||
provide
|
||||
} from 'vue'
|
||||
import { VBinder, VTarget, FollowerPlacement } from 'vueuc'
|
||||
import { useMergedState, useCompitable, useIsMounted, useMemo } from 'vooks'
|
||||
import { call, keep, warn } from '../../_utils'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import NPopoverBody, { popoverBodyProps } from './PopoverBody'
|
||||
|
||||
const bodyPropKeys = Object.keys(
|
||||
popoverBodyProps
|
||||
) as (keyof typeof popoverBodyProps)[]
|
||||
|
||||
function appendEvents (
|
||||
vNode: VNode,
|
||||
events: {
|
||||
onClick: (e: MouseEvent) => void
|
||||
onMouseEnter: (e: MouseEvent) => void
|
||||
onMouseLeave: (e: MouseEvent) => void
|
||||
}
|
||||
): void {
|
||||
Object.entries(events).forEach(([key, handler]) => {
|
||||
if (!vNode.props) vNode.props = {}
|
||||
const originalHandler = vNode.props[key]
|
||||
if (!originalHandler) vNode.props[key] = handler
|
||||
else {
|
||||
vNode.props[key] = (...args: unknown[]) => {
|
||||
originalHandler(...args)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
;(handler as any)(...args)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getFirstSlotVNode (slots: Slots, slotName = 'default'): VNode | null {
|
||||
const slot = slots[slotName]
|
||||
if (!slot) {
|
||||
warn('getFirstSlotVNode', `slot[${slotName}] is empty`)
|
||||
return null
|
||||
}
|
||||
const slotContent = slot()
|
||||
// vue will normalize the slot, so slot must be an array
|
||||
if (slotContent.length === 1) {
|
||||
return slotContent[0]
|
||||
} else {
|
||||
warn('getFirstSlotVNode', `slot[${slotName}] should have exactly one child`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const textVNodeType = createTextVNode('').type
|
||||
|
||||
type BodyInstance = { syncPosition: () => void; [key: string]: unknown }
|
||||
|
||||
export interface PopoverInjection {
|
||||
handleMouseLeave: (e: MouseEvent) => void
|
||||
handleMouseEnter: (e: MouseEvent) => void
|
||||
handleMouseMoveOutside: (e: MouseEvent) => void
|
||||
handleClickOutside: (e: MouseEvent) => void
|
||||
getTriggerElement: () => HTMLElement
|
||||
setBodyInstance: (value: BodyInstance | null) => void
|
||||
isMounted: boolean
|
||||
}
|
||||
|
||||
export const popoverProps = {
|
||||
...useTheme.props,
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
defaultShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
trigger: {
|
||||
type: String as PropType<'hover' | 'click'>,
|
||||
default: undefined
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
raw: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placement: {
|
||||
type: String as PropType<FollowerPlacement>,
|
||||
default: 'bottom'
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
displayDirective: {
|
||||
type: String,
|
||||
default: 'if'
|
||||
},
|
||||
arrowStyle: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
},
|
||||
filp: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// private
|
||||
padded: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// events
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:show': {
|
||||
type: Function,
|
||||
default: undefined
|
||||
},
|
||||
// deprecated
|
||||
onShow: {
|
||||
type: Function,
|
||||
validator: (): boolean => {
|
||||
warn(
|
||||
'popover',
|
||||
'`on-show` is deprecated, please use `on-update:show` instead.'
|
||||
)
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
},
|
||||
onHide: {
|
||||
type: Function,
|
||||
validator: (): boolean => {
|
||||
warn(
|
||||
'popover',
|
||||
'`on-hide` is deprecated, please use `on-update:show` instead.'
|
||||
)
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
},
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
maxWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Popover',
|
||||
inheritAttrs: false,
|
||||
props: popoverProps,
|
||||
setup (props) {
|
||||
const isMountedRef = useIsMounted()
|
||||
// setup show
|
||||
const controlledShowRef = computed(() => props.show)
|
||||
const uncontrolledShowRef = ref(props.defaultShow)
|
||||
const mergedShowWithoutDisabledRef = useMergedState(
|
||||
controlledShowRef,
|
||||
uncontrolledShowRef
|
||||
)
|
||||
const mergedShowRef = computed(() => {
|
||||
return props.disabled ? false : mergedShowWithoutDisabledRef.value
|
||||
})
|
||||
// setup show-arrow
|
||||
const compatibleShowArrowRef = useCompitable(props, ['arrow', 'showArrow'])
|
||||
// trigger
|
||||
let triggerVNode = null as VNode | null
|
||||
// bodyInstance
|
||||
let bodyInstance = null as BodyInstance | null
|
||||
const showTimerIdRef = ref<number | null>(null)
|
||||
const hideTimerIdRef = ref<number | null>(null)
|
||||
// methods
|
||||
function doUpdateShow (value: boolean) {
|
||||
const { 'onUpdate:show': onUpdateShow, onShow, onHide } = props
|
||||
uncontrolledShowRef.value = value
|
||||
if (onUpdateShow) {
|
||||
call(onUpdateShow, value)
|
||||
}
|
||||
if (value && onShow) {
|
||||
call(onShow, true)
|
||||
}
|
||||
if (value && onHide) {
|
||||
call(onHide, false)
|
||||
}
|
||||
}
|
||||
function syncPosition () {
|
||||
if (bodyInstance) {
|
||||
bodyInstance.syncPosition()
|
||||
}
|
||||
}
|
||||
function clearTimer () {
|
||||
const { value: showTimerId } = showTimerIdRef
|
||||
const { value: hideTimerId } = hideTimerIdRef
|
||||
if (showTimerId) {
|
||||
window.clearTimeout(showTimerId)
|
||||
showTimerIdRef.value = null
|
||||
}
|
||||
if (hideTimerId) {
|
||||
window.clearTimeout(hideTimerId)
|
||||
hideTimerIdRef.value = null
|
||||
}
|
||||
}
|
||||
function handleMouseEnter () {
|
||||
if (props.trigger === 'hover' && !props.disabled) {
|
||||
clearTimer()
|
||||
if (mergedShowRef.value) return
|
||||
showTimerIdRef.value = window.setTimeout(() => {
|
||||
doUpdateShow(true)
|
||||
showTimerIdRef.value = null
|
||||
}, props.delay)
|
||||
}
|
||||
}
|
||||
function handleMouseLeave () {
|
||||
if (props.trigger === 'hover' && !props.disabled) {
|
||||
clearTimer()
|
||||
if (!mergedShowRef.value) return
|
||||
hideTimerIdRef.value = window.setTimeout(() => {
|
||||
doUpdateShow(false)
|
||||
hideTimerIdRef.value = null
|
||||
}, props.duration)
|
||||
}
|
||||
}
|
||||
// will be called in popover-content
|
||||
function handleMouseMoveOutside () {
|
||||
handleMouseLeave()
|
||||
}
|
||||
// will be called in popover-content
|
||||
function handleClickOutside () {
|
||||
if (!mergedShowRef.value) return
|
||||
if (props.trigger === 'click') {
|
||||
clearTimer()
|
||||
doUpdateShow(false)
|
||||
}
|
||||
}
|
||||
function handleClick () {
|
||||
if (props.trigger === 'click' && !props.disabled) {
|
||||
clearTimer()
|
||||
const nextShow = !mergedShowRef.value
|
||||
doUpdateShow(nextShow)
|
||||
}
|
||||
}
|
||||
function setShow (value: boolean) {
|
||||
uncontrolledShowRef.value = value
|
||||
}
|
||||
function getTriggerElement () {
|
||||
return triggerVNode?.el as HTMLElement
|
||||
}
|
||||
function setBodyInstance (value: BodyInstance | null): void {
|
||||
bodyInstance = value
|
||||
}
|
||||
provide<PopoverInjection>(
|
||||
'NPopover',
|
||||
reactive({
|
||||
getTriggerElement,
|
||||
handleMouseEnter,
|
||||
handleMouseLeave,
|
||||
handleClickOutside,
|
||||
handleMouseMoveOutside,
|
||||
setBodyInstance,
|
||||
isMounted: isMountedRef
|
||||
})
|
||||
)
|
||||
return {
|
||||
positionManually: useMemo(() => {
|
||||
return props.x !== undefined && props.y !== undefined
|
||||
}),
|
||||
// if to show popover body
|
||||
uncontrolledShow: uncontrolledShowRef,
|
||||
mergedShow: mergedShowRef,
|
||||
compatibleShowArrow: compatibleShowArrowRef,
|
||||
setShow,
|
||||
handleClick,
|
||||
handleMouseEnter,
|
||||
handleMouseLeave,
|
||||
setTriggerVNode (v: VNode | null) {
|
||||
triggerVNode = v
|
||||
},
|
||||
syncPosition
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { positionManually } = this
|
||||
const slots = { ...this.$slots }
|
||||
let triggerVNode: VNode | null
|
||||
if (!positionManually) {
|
||||
if (slots.activator) {
|
||||
triggerVNode = getFirstSlotVNode(slots, 'activator')
|
||||
} else {
|
||||
triggerVNode = getFirstSlotVNode(slots, 'trigger')
|
||||
}
|
||||
if (triggerVNode) {
|
||||
triggerVNode =
|
||||
triggerVNode.type === textVNodeType
|
||||
? h('span', [triggerVNode])
|
||||
: triggerVNode
|
||||
|
||||
appendEvents(triggerVNode, {
|
||||
onClick: this.handleClick,
|
||||
onMouseEnter: this.handleMouseEnter,
|
||||
onMouseLeave: this.handleMouseLeave
|
||||
})
|
||||
}
|
||||
this.setTriggerVNode(triggerVNode)
|
||||
}
|
||||
|
||||
return h(VBinder, null, {
|
||||
default: () => {
|
||||
return [
|
||||
positionManually
|
||||
? null
|
||||
: h(VTarget, null, {
|
||||
default: () => triggerVNode
|
||||
}),
|
||||
h(
|
||||
NPopoverBody,
|
||||
keep(this.$props, bodyPropKeys, {
|
||||
...this.$attrs,
|
||||
show: this.mergedShow
|
||||
}),
|
||||
slots
|
||||
)
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
@ -1,304 +0,0 @@
|
||||
import {
|
||||
h,
|
||||
vShow,
|
||||
withDirectives,
|
||||
Transition,
|
||||
ref,
|
||||
defineComponent,
|
||||
computed,
|
||||
mergeProps,
|
||||
inject
|
||||
} from 'vue'
|
||||
import { VFollower } from 'vueuc'
|
||||
import { clickoutside, mousemoveoutside } from 'vdirs'
|
||||
import { useTheme, useConfig } from '../../_mixins'
|
||||
import { formatLength, useAdjustedTo, getSlot } from '../../_utils'
|
||||
import { popoverLight } from '../styles'
|
||||
import style from './styles/index.cssr.js'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PopoverBody',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
...useTheme.props,
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
trigger: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
raw: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
arrowStyle: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
},
|
||||
displayDirective: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
filp: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
// private
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
padded: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
// deprecated
|
||||
width: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
maxWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const themeRef = useTheme('Popover', 'Popover', style, popoverLight, props)
|
||||
const NPopover = inject('NPopover')
|
||||
return {
|
||||
...useConfig(props),
|
||||
NPopover,
|
||||
adjustedTo: useAdjustedTo(props),
|
||||
followerEnabled: ref(props.show),
|
||||
followerRef: ref(null),
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
common: {
|
||||
cubicBezierEaseInOut,
|
||||
cubicBezierEaseIn,
|
||||
cubicBezierEaseOut
|
||||
},
|
||||
self: {
|
||||
space,
|
||||
spaceArrow,
|
||||
padding,
|
||||
fontSize,
|
||||
textColor,
|
||||
color,
|
||||
boxShadow,
|
||||
borderRadius,
|
||||
arrowHeight,
|
||||
arrowOffset,
|
||||
arrowOffsetVertical
|
||||
}
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--box-shadow': boxShadow,
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--bezier-ease-in': cubicBezierEaseIn,
|
||||
'--bezier-ease-out': cubicBezierEaseOut,
|
||||
'--font-size': fontSize,
|
||||
'--text-color': textColor,
|
||||
'--color': color,
|
||||
'--border-radius': borderRadius,
|
||||
'--arrow-height': arrowHeight,
|
||||
'--arrow-offset': arrowOffset,
|
||||
'--arrow-offset-vertical': arrowOffsetVertical,
|
||||
'--padding': padding,
|
||||
'--space': space,
|
||||
'--space-arrow': spaceArrow
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
useVShow () {
|
||||
return this.displayDirective === 'show'
|
||||
},
|
||||
directives () {
|
||||
const { trigger } = this
|
||||
const directives = []
|
||||
if (trigger === 'click') {
|
||||
directives.push([clickoutside, this.handleClickOutside])
|
||||
}
|
||||
if (trigger === 'hover') {
|
||||
directives.push([mousemoveoutside, this.handleMouseMoveOutside])
|
||||
}
|
||||
if (this.useVShow) directives.push([vShow, this.show])
|
||||
return directives
|
||||
},
|
||||
style () {
|
||||
return [
|
||||
{
|
||||
width: formatLength(this.width),
|
||||
maxWidth: formatLength(this.maxWidth),
|
||||
minWidth: formatLength(this.minWidth)
|
||||
},
|
||||
this.cssVars
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show (value) {
|
||||
if (value) this.followerEnabled = true
|
||||
else {
|
||||
if (!this.animated) {
|
||||
this.followerEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.NPopover.bodyInstance = this
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.NPopover.bodyInstance = null
|
||||
},
|
||||
methods: {
|
||||
syncPosition () {
|
||||
this.followerRef.syncPosition()
|
||||
},
|
||||
handleMouseEnter (e) {
|
||||
if (this.trigger === 'hover') {
|
||||
this.NPopover.handleMouseEnter(e)
|
||||
}
|
||||
},
|
||||
handleMouseLeave (e) {
|
||||
if (this.trigger === 'hover') {
|
||||
this.NPopover.handleMouseLeave(e)
|
||||
}
|
||||
},
|
||||
handleMouseMoveOutside (e) {
|
||||
if (
|
||||
this.trigger === 'hover' &&
|
||||
!this.getTriggerElement().contains(e.target)
|
||||
) {
|
||||
this.NPopover.handleMouseMoveOutside(e)
|
||||
}
|
||||
},
|
||||
handleClickOutside (e) {
|
||||
if (
|
||||
this.trigger === 'click' &&
|
||||
!this.getTriggerElement().contains(e.target)
|
||||
) {
|
||||
this.NPopover.handleClickOutside()
|
||||
}
|
||||
},
|
||||
getTriggerElement () {
|
||||
return this.NPopover.getTriggerElement()
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { animated } = this
|
||||
const contentNode =
|
||||
this.useVShow || this.show
|
||||
? withDirectives(
|
||||
h(
|
||||
'div',
|
||||
mergeProps(
|
||||
{
|
||||
class: [
|
||||
'n-popover',
|
||||
{
|
||||
'n-popover--no-arrow': !this.showArrow,
|
||||
'n-popover--shadow': this.shadow,
|
||||
'n-popover--padded': this.padded,
|
||||
'n-popover--raw': this.raw
|
||||
}
|
||||
],
|
||||
ref: 'body',
|
||||
style: this.style,
|
||||
onMouseEnter: this.handleMouseEnter,
|
||||
onMouseLeave: this.handleMouseLeave
|
||||
},
|
||||
this.$attrs
|
||||
),
|
||||
[
|
||||
getSlot(this),
|
||||
this.showArrow
|
||||
? h(
|
||||
'div',
|
||||
{
|
||||
class: 'n-popover-arrow-wrapper'
|
||||
},
|
||||
[
|
||||
h('div', {
|
||||
class: 'n-popover-arrow',
|
||||
style: this.arrowStyle
|
||||
})
|
||||
]
|
||||
)
|
||||
: null
|
||||
]
|
||||
),
|
||||
this.directives
|
||||
)
|
||||
: null
|
||||
return h(
|
||||
VFollower,
|
||||
{
|
||||
show: this.show,
|
||||
enabled: this.followerEnabled,
|
||||
to: this.adjustedTo,
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
placement: this.placement,
|
||||
containerClass: this.namespace,
|
||||
ref: 'followerRef'
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return animated
|
||||
? h(
|
||||
Transition,
|
||||
{
|
||||
name: 'popover-transition',
|
||||
appear: this.NPopover.isMounted,
|
||||
onAfterLeave: () => {
|
||||
this.followerEnabled = false
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => contentNode
|
||||
}
|
||||
)
|
||||
: contentNode
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
313
src/popover/src/PopoverBody.ts
Normal file
313
src/popover/src/PopoverBody.ts
Normal file
@ -0,0 +1,313 @@
|
||||
import {
|
||||
h,
|
||||
vShow,
|
||||
withDirectives,
|
||||
Transition,
|
||||
ref,
|
||||
defineComponent,
|
||||
computed,
|
||||
mergeProps,
|
||||
inject,
|
||||
onBeforeUnmount,
|
||||
DirectiveArguments,
|
||||
PropType,
|
||||
watch,
|
||||
toRef
|
||||
} from 'vue'
|
||||
import { VFollower, FollowerPlacement, FollowerRef } from 'vueuc'
|
||||
import { clickoutside, mousemoveoutside } from 'vdirs'
|
||||
import { useTheme, useConfig } from '../../_mixins'
|
||||
import { formatLength, useAdjustedTo, getSlot } from '../../_utils'
|
||||
import { popoverLight } from '../styles'
|
||||
import style from './styles/index.cssr'
|
||||
import { PopoverThemeVars } from '../styles/light'
|
||||
import { PopoverInjection } from './Popover'
|
||||
|
||||
export const popoverBodyProps = {
|
||||
...useTheme.props,
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
trigger: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
raw: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
arrowStyle: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
},
|
||||
displayDirective: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
filp: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
placement: {
|
||||
type: String as PropType<FollowerPlacement>,
|
||||
default: undefined
|
||||
},
|
||||
// private
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
padded: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
// deprecated
|
||||
width: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
maxWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PopoverBody',
|
||||
inheritAttrs: false,
|
||||
props: popoverBodyProps,
|
||||
setup (props) {
|
||||
const themeRef = useTheme<PopoverThemeVars>(
|
||||
'Popover',
|
||||
'Popover',
|
||||
style,
|
||||
popoverLight,
|
||||
props
|
||||
)
|
||||
const followerRef = ref<FollowerRef | null>(null)
|
||||
const NPopover = inject<PopoverInjection>('NPopover') as PopoverInjection
|
||||
const followerEnabledRef = ref(props.show)
|
||||
const directivesRef = computed<DirectiveArguments>(() => {
|
||||
const { trigger } = props
|
||||
const directives = []
|
||||
if (trigger === 'click') {
|
||||
directives.push([clickoutside, handleClickOutside])
|
||||
}
|
||||
if (trigger === 'hover') {
|
||||
directives.push([mousemoveoutside, handleMouseMoveOutside])
|
||||
}
|
||||
if (props.displayDirective === 'show') { directives.push([vShow, props.show]) }
|
||||
return directives as DirectiveArguments
|
||||
})
|
||||
const styleRef = computed(() => {
|
||||
return [
|
||||
{
|
||||
width: formatLength(props.width),
|
||||
maxWidth: formatLength(props.maxWidth),
|
||||
minWidth: formatLength(props.minWidth)
|
||||
},
|
||||
cssVarsRef.value
|
||||
]
|
||||
})
|
||||
const cssVarsRef = computed(() => {
|
||||
const {
|
||||
common: { cubicBezierEaseInOut, cubicBezierEaseIn, cubicBezierEaseOut },
|
||||
self: {
|
||||
space,
|
||||
spaceArrow,
|
||||
padding,
|
||||
fontSize,
|
||||
textColor,
|
||||
color,
|
||||
boxShadow,
|
||||
borderRadius,
|
||||
arrowHeight,
|
||||
arrowOffset,
|
||||
arrowOffsetVertical
|
||||
}
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--box-shadow': boxShadow,
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--bezier-ease-in': cubicBezierEaseIn,
|
||||
'--bezier-ease-out': cubicBezierEaseOut,
|
||||
'--font-size': fontSize,
|
||||
'--text-color': textColor,
|
||||
'--color': color,
|
||||
'--border-radius': borderRadius,
|
||||
'--arrow-height': arrowHeight,
|
||||
'--arrow-offset': arrowOffset,
|
||||
'--arrow-offset-vertical': arrowOffsetVertical,
|
||||
'--padding': padding,
|
||||
'--space': space,
|
||||
'--space-arrow': spaceArrow
|
||||
}
|
||||
})
|
||||
NPopover.setBodyInstance({
|
||||
syncPosition
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
NPopover.setBodyInstance(null)
|
||||
})
|
||||
watch(toRef(props, 'show'), (value) => {
|
||||
if (value) followerEnabledRef.value = true
|
||||
else {
|
||||
if (!props.animated) {
|
||||
followerEnabledRef.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
function syncPosition () {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
followerRef.value?.syncPosition()
|
||||
}
|
||||
function handleMouseEnter (e: MouseEvent) {
|
||||
if (props.trigger === 'hover') {
|
||||
NPopover.handleMouseEnter(e)
|
||||
}
|
||||
}
|
||||
function handleMouseLeave (e: MouseEvent) {
|
||||
if (props.trigger === 'hover') {
|
||||
NPopover.handleMouseLeave(e)
|
||||
}
|
||||
}
|
||||
function handleMouseMoveOutside (e: MouseEvent) {
|
||||
if (
|
||||
props.trigger === 'hover' &&
|
||||
!getTriggerElement().contains(e.target as Node)
|
||||
) {
|
||||
NPopover.handleMouseMoveOutside(e)
|
||||
}
|
||||
}
|
||||
function handleClickOutside (e: MouseEvent) {
|
||||
if (
|
||||
props.trigger === 'click' &&
|
||||
!getTriggerElement().contains(e.target as Node)
|
||||
) {
|
||||
NPopover.handleClickOutside(e)
|
||||
}
|
||||
}
|
||||
function getTriggerElement () {
|
||||
return NPopover.getTriggerElement()
|
||||
}
|
||||
return {
|
||||
...useConfig(props),
|
||||
NPopover,
|
||||
followerRef,
|
||||
adjustedTo: useAdjustedTo(props),
|
||||
followerEnabled: followerEnabledRef,
|
||||
style: styleRef,
|
||||
directives: directivesRef,
|
||||
handleMouseEnter,
|
||||
handleMouseLeave
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { animated } = this
|
||||
const contentNode =
|
||||
this.displayDirective === 'show' || this.show
|
||||
? withDirectives(
|
||||
h(
|
||||
'div',
|
||||
mergeProps(
|
||||
{
|
||||
class: [
|
||||
'n-popover',
|
||||
{
|
||||
'n-popover--no-arrow': !this.showArrow,
|
||||
'n-popover--shadow': this.shadow,
|
||||
'n-popover--padded': this.padded,
|
||||
'n-popover--raw': this.raw
|
||||
}
|
||||
],
|
||||
ref: 'body',
|
||||
style: this.style,
|
||||
onMouseEnter: this.handleMouseEnter,
|
||||
onMouseLeave: this.handleMouseLeave
|
||||
},
|
||||
this.$attrs
|
||||
),
|
||||
[
|
||||
getSlot(this),
|
||||
this.showArrow
|
||||
? h(
|
||||
'div',
|
||||
{
|
||||
class: 'n-popover-arrow-wrapper'
|
||||
},
|
||||
[
|
||||
h('div', {
|
||||
class: 'n-popover-arrow',
|
||||
style: this.arrowStyle
|
||||
})
|
||||
]
|
||||
)
|
||||
: null
|
||||
]
|
||||
),
|
||||
this.directives
|
||||
)
|
||||
: null
|
||||
return h(
|
||||
VFollower,
|
||||
{
|
||||
show: this.show,
|
||||
enabled: this.followerEnabled,
|
||||
to: this.adjustedTo,
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
placement: this.placement,
|
||||
containerClass: this.namespace,
|
||||
ref: 'followerRef'
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return animated
|
||||
? h(
|
||||
Transition,
|
||||
{
|
||||
name: 'popover-transition',
|
||||
appear: this.NPopover.isMounted,
|
||||
onAfterLeave: () => {
|
||||
this.followerEnabled = false
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => contentNode
|
||||
}
|
||||
)
|
||||
: contentNode
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
@ -1,3 +1,4 @@
|
||||
import { FollowerPlacement } from 'vueuc'
|
||||
import { c, cB, cM, cNotM } from '../../../_utils/cssr'
|
||||
|
||||
const oppositePlacement = {
|
||||
@ -22,7 +23,9 @@ const oppositePlacement = {
|
||||
// --space
|
||||
// --space-arrow
|
||||
export default c([
|
||||
cB('popover', `
|
||||
cB(
|
||||
'popover',
|
||||
`
|
||||
transition:
|
||||
background-color .3s var(--bezier),
|
||||
color .3s var(--bezier);
|
||||
@ -30,40 +33,62 @@ export default c([
|
||||
position: relative;
|
||||
font-size: var(--font-size);
|
||||
color: var(--text-color);
|
||||
`, [
|
||||
// body transition
|
||||
c('&.popover-transition-enter-from, &.popover-transition-leave-to', `
|
||||
`,
|
||||
[
|
||||
// body transition
|
||||
c(
|
||||
'&.popover-transition-enter-from, &.popover-transition-leave-to',
|
||||
`
|
||||
opacity: 0;
|
||||
transform: scale(.85);
|
||||
`),
|
||||
c('&.popover-transition-enter-to, &.popover-transition-leave-from', `
|
||||
`
|
||||
),
|
||||
c(
|
||||
'&.popover-transition-enter-to, &.popover-transition-leave-from',
|
||||
`
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
`),
|
||||
c('&.popover-transition-enter-active', `
|
||||
`
|
||||
),
|
||||
c(
|
||||
'&.popover-transition-enter-active',
|
||||
`
|
||||
transition:
|
||||
opacity .15s var(--bezier-ease-out),
|
||||
transform .15s var(--bezier-ease-out);
|
||||
`),
|
||||
c('&.popover-transition-leave-active', `
|
||||
`
|
||||
),
|
||||
c(
|
||||
'&.popover-transition-leave-active',
|
||||
`
|
||||
transition:
|
||||
opacity .15s var(--bezier-ease-in),
|
||||
transform .15s var(--bezier-ease-in);
|
||||
`),
|
||||
cNotM('raw', `
|
||||
`
|
||||
),
|
||||
cNotM(
|
||||
'raw',
|
||||
`
|
||||
background-color: var(--color);
|
||||
border-radius: var(--border-radius);
|
||||
`, [
|
||||
cM('padded', {
|
||||
padding: 'var(--padding)'
|
||||
})
|
||||
]),
|
||||
cB('popover-arrow-wrapper', `
|
||||
`,
|
||||
[
|
||||
cM('padded', {
|
||||
padding: 'var(--padding)'
|
||||
})
|
||||
]
|
||||
),
|
||||
cB(
|
||||
'popover-arrow-wrapper',
|
||||
`
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
`, [
|
||||
cB('popover-arrow', `
|
||||
`,
|
||||
[
|
||||
cB(
|
||||
'popover-arrow',
|
||||
`
|
||||
transition: background-color .3s var(--bezier);
|
||||
position: absolute;
|
||||
display: block;
|
||||
@ -73,83 +98,134 @@ export default c([
|
||||
transform: rotate(45deg);
|
||||
background-color: var(--color);
|
||||
pointer-events: all;
|
||||
`)
|
||||
]),
|
||||
cM('shadow', {
|
||||
boxShadow: 'var(--box-shadow)'
|
||||
})
|
||||
]),
|
||||
placementStyle('top-start', `
|
||||
`
|
||||
)
|
||||
]
|
||||
),
|
||||
cM('shadow', {
|
||||
boxShadow: 'var(--box-shadow)'
|
||||
})
|
||||
]
|
||||
),
|
||||
placementStyle(
|
||||
'top-start',
|
||||
`
|
||||
top: calc(-0.707 * var(--arrow-height));
|
||||
left: var(--arrow-offset);
|
||||
`),
|
||||
placementStyle('top', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'top',
|
||||
`
|
||||
top: calc(-0.707 * var(--arrow-height));
|
||||
transform: translateX(calc(-0.707 * var(--arrow-height))) rotate(45deg);
|
||||
left: 50%;
|
||||
`),
|
||||
placementStyle('top-end', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'top-end',
|
||||
`
|
||||
top: calc(-0.707 * var(--arrow-height));
|
||||
right: var(--arrow-offset);
|
||||
`),
|
||||
placementStyle('bottom-start', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'bottom-start',
|
||||
`
|
||||
bottom: calc(-0.707 * var(--arrow-height));
|
||||
left: var(--arrow-offset);
|
||||
`),
|
||||
placementStyle('bottom', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'bottom',
|
||||
`
|
||||
bottom: calc(-0.707 * var(--arrow-height));
|
||||
transform: translateX(calc(-0.707 * var(--arrow-height))) rotate(45deg);
|
||||
left: 50%;
|
||||
`),
|
||||
placementStyle('bottom-end', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'bottom-end',
|
||||
`
|
||||
bottom: calc(-0.707 * var(--arrow-height));
|
||||
right: var(--arrow-offset);
|
||||
`),
|
||||
placementStyle('left-start', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'left-start',
|
||||
`
|
||||
left: calc(-0.707 * var(--arrow-height));
|
||||
top: var(--arrow-offset-vertical);
|
||||
`),
|
||||
placementStyle('left', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'left',
|
||||
`
|
||||
left: calc(-0.707 * var(--arrow-height));
|
||||
transform: translateY(calc(-0.707 * var(--arrow-height))) rotate(45deg);
|
||||
top: 50%;
|
||||
`),
|
||||
placementStyle('left-end', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'left-end',
|
||||
`
|
||||
left: calc(-0.707 * var(--arrow-height));
|
||||
bottom: var(--arrow-offset-vertical);
|
||||
`),
|
||||
placementStyle('right-start', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'right-start',
|
||||
`
|
||||
right: calc(-0.707 * var(--arrow-height));
|
||||
top: var(--arrow-offset-vertical);
|
||||
`),
|
||||
placementStyle('right', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'right',
|
||||
`
|
||||
right: calc(-0.707 * var(--arrow-height));
|
||||
transform: translateY(calc(-0.707 * var(--arrow-height))) rotate(45deg);
|
||||
top: 50%;
|
||||
`),
|
||||
placementStyle('right-end', `
|
||||
`
|
||||
),
|
||||
placementStyle(
|
||||
'right-end',
|
||||
`
|
||||
right: calc(-0.707 * var(--arrow-height));
|
||||
bottom: var(--arrow-offset-vertical);
|
||||
`)
|
||||
`
|
||||
)
|
||||
])
|
||||
|
||||
function placementStyle (
|
||||
placement,
|
||||
arrowStyleLiteral
|
||||
placement: FollowerPlacement,
|
||||
arrowStyleLiteral: string
|
||||
) {
|
||||
const position = placement.split('-')[0]
|
||||
const position = placement.split('-')[0] as
|
||||
| 'top'
|
||||
| 'right'
|
||||
| 'bottom'
|
||||
| 'left'
|
||||
const sizeStyle = ['top', 'bottom'].includes(position)
|
||||
? 'height: var(--space-arrow);'
|
||||
: 'width: var(--space-arrow);'
|
||||
return c(`[v-placement="${placement}"]`, [
|
||||
cB('popover', `
|
||||
cB(
|
||||
'popover',
|
||||
`
|
||||
margin-${oppositePlacement[position]}: var(--space-arrow);
|
||||
`, [
|
||||
cM('no-arrow', `
|
||||
`,
|
||||
[
|
||||
cM(
|
||||
'no-arrow',
|
||||
`
|
||||
margin-${position}: var(--space);
|
||||
margin-${oppositePlacement[position]}: var(--space);
|
||||
`),
|
||||
cB('popover-arrow-wrapper', `
|
||||
`
|
||||
),
|
||||
cB(
|
||||
'popover-arrow-wrapper',
|
||||
`
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
@ -157,9 +233,10 @@ function placementStyle (
|
||||
${position}: 100%;
|
||||
${oppositePlacement[position]}: auto;
|
||||
${sizeStyle}
|
||||
`, [
|
||||
cB('popover-arrow', arrowStyleLiteral)
|
||||
])
|
||||
])
|
||||
`,
|
||||
[cB('popover-arrow', arrowStyleLiteral)]
|
||||
)
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
import commonVariables from './_common'
|
||||
import { commonDark } from '../../_styles/new-common'
|
||||
import type { ThemeCommonVars } from '../../_styles/new-common'
|
||||
import commonVariables from './_common'
|
||||
import { PopoverThemeVars } from './light'
|
||||
|
||||
export default {
|
||||
name: 'Popover',
|
||||
common: commonDark,
|
||||
self (vars) {
|
||||
self (vars: ThemeCommonVars): PopoverThemeVars {
|
||||
const {
|
||||
popoverColor,
|
||||
textColor2Overlay,
|
@ -1,2 +0,0 @@
|
||||
export { default as popoverDark } from './dark.js'
|
||||
export { default as popoverLight } from './light.js'
|
2
src/popover/styles/index.ts
Normal file
2
src/popover/styles/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as popoverDark } from './dark'
|
||||
export { default as popoverLight } from './light'
|
@ -1,10 +1,11 @@
|
||||
import commonVariables from './_common'
|
||||
import { commonLight } from '../../_styles/new-common'
|
||||
import type { ThemeCommonVars } from '../../_styles/new-common'
|
||||
import commonVariables from './_common'
|
||||
|
||||
export default {
|
||||
const popoverLight = {
|
||||
name: 'Popover',
|
||||
common: commonLight,
|
||||
self (vars) {
|
||||
self (vars: ThemeCommonVars) {
|
||||
const {
|
||||
boxShadow2,
|
||||
popoverColor,
|
||||
@ -22,3 +23,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default popoverLight
|
||||
|
||||
export type PopoverThemeVars = ReturnType<typeof popoverLight.self>
|
Loading…
x
Reference in New Issue
Block a user