mirror of
https://github.com/element-plus/element-plus.git
synced 2024-12-21 02:50:11 +08:00
feat(hooks): redesign popper apis (#2529)
* feat(hooks): redesign popper apis - Redesign use-popper APIs to make it more adaptable. * - Reorganize the popper APIs
This commit is contained in:
parent
a99b20a8c1
commit
c28d7b3738
@ -30,7 +30,7 @@ import useTeleport from '../use-teleport'
|
||||
import useTimeout from '../use-timeout'
|
||||
import { useModelToggle } from '../use-model-toggle'
|
||||
import { useTransitionFallthrough } from '../use-transition-fallthrough'
|
||||
import { usePopperOptions } from './use-popper-options'
|
||||
import { defaultPopperOptions, defaultModifiers } from './use-popper-options'
|
||||
import { useTargetEvents, DEFAULT_TRIGGER } from './use-target-events'
|
||||
|
||||
import type {
|
||||
@ -41,9 +41,7 @@ import type {
|
||||
} from 'vue'
|
||||
import type {
|
||||
Instance as PopperInstance,
|
||||
Options,
|
||||
Placement,
|
||||
PositioningStrategy,
|
||||
StrictModifiers,
|
||||
} from '@popperjs/core'
|
||||
import type { RefElement } from '@element-plus/utils/types'
|
||||
import type { Trigger } from './use-target-events'
|
||||
@ -56,47 +54,23 @@ type ElementType = ComponentPublicInstance | HTMLElement
|
||||
export const DARK_EFFECT = 'dark'
|
||||
export const LIGHT_EFFECT = 'light'
|
||||
|
||||
const DEFAULT_FALLBACK_PLACEMENTS = []
|
||||
|
||||
|
||||
export const popperConfigs = {
|
||||
export const usePopperControlProps = {
|
||||
appendToBody: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
arrowOffset: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
fallbackPlacements: {
|
||||
type: Array as PropType<Placement[]>,
|
||||
default: () => DEFAULT_FALLBACK_PLACEMENTS,
|
||||
},
|
||||
gpuAcceleration: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
offset: {
|
||||
type: Number,
|
||||
default: 12,
|
||||
},
|
||||
placement: {
|
||||
type: String as PropType<Placement>,
|
||||
default: 'bottom' as Placement,
|
||||
},
|
||||
// Once this option were given, the entire popper is under the users' control, top priority
|
||||
popperOptions: {
|
||||
type: Object as PropType<Options>,
|
||||
default: () => null,
|
||||
},
|
||||
strategy: {
|
||||
type: String as PropType<PositioningStrategy>,
|
||||
default: 'fixed' as PositioningStrategy,
|
||||
popperOptions: defaultPopperOptions,
|
||||
popperClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
}
|
||||
|
||||
export const usePopperProps = {
|
||||
...popperConfigs,
|
||||
...usePopperControlProps,
|
||||
// the arrow size is an equailateral triangle with 10px side length, the 3rd side length ~ 14.1px
|
||||
// adding a offset to the ceil of 4.1 should be 5 this resolves the problem of arrow overflowing out of popper.
|
||||
autoClose: {
|
||||
@ -107,10 +81,7 @@ export const usePopperProps = {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
class: String,
|
||||
style: Object,
|
||||
hideAfter: {
|
||||
type: Number,
|
||||
@ -136,10 +107,6 @@ export const usePopperProps = {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
popperClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
pure: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@ -176,7 +143,6 @@ export const usePopper = () => {
|
||||
const triggerRef = ref<ElementType>(null)
|
||||
const popperRef = ref<RefElement>(null)
|
||||
|
||||
const popperOptions = usePopperOptions(arrowRef)
|
||||
const popperStyle = ref<CSSProperties>({ zIndex: PopupManager.nextZIndex() })
|
||||
const visible = ref(false)
|
||||
const isManual = computed(() => props.manualMode || props.trigger === 'manual')
|
||||
@ -274,10 +240,33 @@ export const usePopper = () => {
|
||||
const $el = isHTMLElement(unwrappedTrigger)
|
||||
? unwrappedTrigger
|
||||
: (unwrappedTrigger as ComponentPublicInstance).$el
|
||||
popperInstance = createPopper($el, popperRef.value, popperOptions.value)
|
||||
|
||||
popperInstance = createPopper($el, popperRef.value, buildPopperOptions())
|
||||
popperInstance.update()
|
||||
}
|
||||
|
||||
function buildPopperOptions() {
|
||||
const modifiers = [
|
||||
...defaultModifiers,
|
||||
...props.popperOptions.modifiers,
|
||||
]
|
||||
|
||||
if (props.showArrow) {
|
||||
modifiers.push({
|
||||
name: 'arrow',
|
||||
options: {
|
||||
padding: props.arrowOffset || 5,
|
||||
element: arrowRef.value,
|
||||
},
|
||||
} as StrictModifiers)
|
||||
}
|
||||
|
||||
return {
|
||||
...props.popperOptions,
|
||||
modifiers,
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
onAfterEnter,
|
||||
onAfterLeave,
|
||||
|
@ -1,68 +1,14 @@
|
||||
import { computed, getCurrentInstance } from 'vue'
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
import type {
|
||||
Options,
|
||||
Placement,
|
||||
StrictModifiers,
|
||||
PositioningStrategy,
|
||||
} from '@popperjs/core'
|
||||
import type { PropType } from 'vue'
|
||||
import type { Options } from '@popperjs/core'
|
||||
|
||||
interface IUsePopperProps {
|
||||
arrowOffset: number
|
||||
fallbackPlacements: Array<Placement>
|
||||
gpuAcceleration: boolean
|
||||
offset: number
|
||||
popperOptions: Options
|
||||
placement: Placement
|
||||
strategy: PositioningStrategy
|
||||
}
|
||||
export const DEFAULT_FALLBACK_PLACEMENTS = []
|
||||
|
||||
export const usePopperOptions = (arrowRef: Ref<HTMLElement>) => {
|
||||
const vm = getCurrentInstance()
|
||||
|
||||
const props = vm.props as unknown as IUsePopperProps
|
||||
|
||||
return computed(() => {
|
||||
return {
|
||||
placement: props.placement,
|
||||
strategy: props.strategy,
|
||||
...props.popperOptions,
|
||||
// Avoiding overriding modifiers.
|
||||
modifiers: buildModifiers({
|
||||
arrow: arrowRef.value,
|
||||
arrowOffset: props.arrowOffset,
|
||||
offset: props.offset,
|
||||
gpuAcceleration: props.gpuAcceleration,
|
||||
fallbackPlacements: props.fallbackPlacements,
|
||||
}, props.popperOptions?.modifiers),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
interface ModifierProps {
|
||||
offset?: number
|
||||
arrow?: HTMLElement
|
||||
arrowOffset?: number
|
||||
gpuAcceleration?: boolean
|
||||
fallbackPlacements?: Array<Placement>
|
||||
}
|
||||
|
||||
function buildModifiers(props: ModifierProps, externalModifiers: StrictModifiers[] = []) {
|
||||
|
||||
const {
|
||||
arrow,
|
||||
arrowOffset,
|
||||
offset,
|
||||
gpuAcceleration,
|
||||
fallbackPlacements,
|
||||
} = props
|
||||
|
||||
const modifiers: Array<StrictModifiers> = [
|
||||
export const defaultModifiers = [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, offset ?? 12],
|
||||
offset: [0, 12],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -80,29 +26,25 @@ function buildModifiers(props: ModifierProps, externalModifiers: StrictModifiers
|
||||
name: 'flip',
|
||||
options: {
|
||||
padding: 5,
|
||||
fallbackPlacements: fallbackPlacements ?? [],
|
||||
fallbackPlacements: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'computeStyles',
|
||||
options: {
|
||||
gpuAcceleration,
|
||||
adaptive: gpuAcceleration,
|
||||
gpuAcceleration: true,
|
||||
adaptive: true,
|
||||
},
|
||||
},
|
||||
// tippyModifier,
|
||||
]
|
||||
|
||||
if (arrow) {
|
||||
modifiers.push({
|
||||
name: 'arrow',
|
||||
options: {
|
||||
element: arrow,
|
||||
padding: arrowOffset ?? 5,
|
||||
export const defaultPopperOptions = {
|
||||
type: Object as PropType<Options>,
|
||||
default: () => {
|
||||
return {
|
||||
fallbackPlacements: DEFAULT_FALLBACK_PLACEMENTS,
|
||||
strategy: 'fixed',
|
||||
modifiers: defaultModifiers,
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
modifiers.push(...(externalModifiers))
|
||||
return modifiers
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user