diff --git a/packages/hooks/use-popper/index.ts b/packages/hooks/use-popper/index.ts index 1bd806bcd5..64d106d76d 100644 --- a/packages/hooks/use-popper/index.ts +++ b/packages/hooks/use-popper/index.ts @@ -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, - default: () => DEFAULT_FALLBACK_PLACEMENTS, - }, - gpuAcceleration: { - type: Boolean, - default: true, - }, - offset: { - type: Number, - default: 12, - }, - placement: { - type: String as PropType, - default: 'bottom' as Placement, - }, - // Once this option were given, the entire popper is under the users' control, top priority - popperOptions: { - type: Object as PropType, - default: () => null, - }, - strategy: { - type: String as PropType, - 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(null) const popperRef = ref(null) - const popperOptions = usePopperOptions(arrowRef) const popperStyle = ref({ 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, diff --git a/packages/hooks/use-popper/use-popper-options.ts b/packages/hooks/use-popper/use-popper-options.ts index da9e04786b..db18f671fb 100644 --- a/packages/hooks/use-popper/use-popper-options.ts +++ b/packages/hooks/use-popper/use-popper-options.ts @@ -1,108 +1,50 @@ -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 - gpuAcceleration: boolean - offset: number - popperOptions: Options - placement: Placement - strategy: PositioningStrategy -} +export const DEFAULT_FALLBACK_PLACEMENTS = [] -export const usePopperOptions = (arrowRef: Ref) => { - const vm = getCurrentInstance() +export const defaultModifiers = [ + { + name: 'offset', + options: { + offset: [0, 12], + }, + }, + { + name: 'preventOverflow', + options: { + padding: { + top: 2, + bottom: 2, + left: 5, + right: 5, + }, + }, + }, + { + name: 'flip', + options: { + padding: 5, + fallbackPlacements: [], + }, + }, + { + name: 'computeStyles', + options: { + gpuAcceleration: true, + adaptive: true, + }, + }, +] - const props = vm.props as unknown as IUsePopperProps - - return computed(() => { +export const defaultPopperOptions = { + type: Object as PropType, + default: () => { 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), + fallbackPlacements: DEFAULT_FALLBACK_PLACEMENTS, + strategy: 'fixed', + modifiers: defaultModifiers, } - }) -} - -interface ModifierProps { - offset?: number - arrow?: HTMLElement - arrowOffset?: number - gpuAcceleration?: boolean - fallbackPlacements?: Array -} - -function buildModifiers(props: ModifierProps, externalModifiers: StrictModifiers[] = []) { - - const { - arrow, - arrowOffset, - offset, - gpuAcceleration, - fallbackPlacements, - } = props - - const modifiers: Array = [ - { - name: 'offset', - options: { - offset: [0, offset ?? 12], - }, - }, - { - name: 'preventOverflow', - options: { - padding: { - top: 2, - bottom: 2, - left: 5, - right: 5, - }, - }, - }, - { - name: 'flip', - options: { - padding: 5, - fallbackPlacements: fallbackPlacements ?? [], - }, - }, - { - name: 'computeStyles', - options: { - gpuAcceleration, - adaptive: gpuAcceleration, - }, - }, - // tippyModifier, - ] - - if (arrow) { - modifiers.push({ - name: 'arrow', - options: { - element: arrow, - padding: arrowOffset ?? 5, - }, - }) - } - - modifiers.push(...(externalModifiers)) - return modifiers + }, }