element-plus
Version:
A Component Library for Vue 3
1 lines • 10.8 kB
Source Map (JSON)
{"version":3,"file":"helper.mjs","names":["offsetMiddleware","offset"],"sources":["../../../../../../packages/components/tour/src/helper.ts"],"sourcesContent":["import {\n computed,\n onBeforeUnmount,\n onMounted,\n ref,\n unref,\n watch,\n watchEffect,\n} from 'vue'\nimport {\n arrow,\n autoUpdate,\n computePosition,\n detectOverflow,\n flip,\n offset as offsetMiddleware,\n shift,\n} from '@floating-ui/dom'\nimport {\n isArray,\n isClient,\n isFunction,\n isString,\n keysOf,\n} from '@element-plus/utils'\n\nimport type {\n CSSProperties,\n Component,\n InjectionKey,\n Ref,\n SetupContext,\n} from 'vue'\nimport type { UseNamespaceReturn } from '@element-plus/hooks'\nimport type { PosInfo, TourGap, TourMask } from './types'\nimport type {\n ComputePositionReturn,\n Middleware,\n Placement,\n Strategy,\n VirtualElement,\n} from '@floating-ui/dom'\nimport type { TourStepProps } from './step'\n\nexport const useTarget = (\n target: Ref<\n string | HTMLElement | (() => HTMLElement | null) | null | undefined\n >,\n open: Ref<boolean>,\n gap: Ref<TourGap>,\n mergedMask: Ref<TourMask>,\n scrollIntoViewOptions: Ref<boolean | ScrollIntoViewOptions>\n) => {\n const posInfo: Ref<PosInfo | null> = ref(null)\n\n const getTargetEl = () => {\n let targetEl: HTMLElement | null | undefined\n if (isString(target.value)) {\n targetEl = document.querySelector<HTMLElement>(target.value)\n } else if (isFunction(target.value)) {\n targetEl = target.value()\n } else {\n targetEl = target.value\n }\n return targetEl\n }\n\n const updatePosInfo = () => {\n const targetEl = getTargetEl()\n if (!targetEl || !open.value) {\n posInfo.value = null\n return\n }\n if (!isInViewPort(targetEl)) {\n targetEl.scrollIntoView(scrollIntoViewOptions.value)\n }\n const { left, top, width, height } = targetEl.getBoundingClientRect()\n posInfo.value = {\n left,\n top,\n width,\n height,\n radius: 0,\n }\n }\n\n onMounted(() => {\n watch(\n [open, target],\n () => {\n updatePosInfo()\n },\n {\n immediate: true,\n }\n )\n window.addEventListener('resize', updatePosInfo)\n })\n\n onBeforeUnmount(() => {\n window.removeEventListener('resize', updatePosInfo)\n })\n\n const getGapOffset = (index: number) =>\n (isArray(gap.value.offset) ? gap.value.offset[index] : gap.value.offset) ??\n 6\n\n const mergedPosInfo = computed(() => {\n if (!posInfo.value) return posInfo.value\n\n const gapOffsetX = getGapOffset(0)\n const gapOffsetY = getGapOffset(1)\n const gapRadius = gap.value?.radius || 2\n\n return {\n left: posInfo.value.left - gapOffsetX,\n top: posInfo.value.top - gapOffsetY,\n width: posInfo.value.width + gapOffsetX * 2,\n height: posInfo.value.height + gapOffsetY * 2,\n radius: gapRadius,\n }\n })\n\n const triggerTarget = computed(() => {\n const targetEl = getTargetEl()\n if (!mergedMask.value || !targetEl || !window.DOMRect) {\n return targetEl || undefined\n }\n\n return {\n getBoundingClientRect() {\n return window.DOMRect.fromRect({\n width: mergedPosInfo.value?.width || 0,\n height: mergedPosInfo.value?.height || 0,\n x: mergedPosInfo.value?.left || 0,\n y: mergedPosInfo.value?.top || 0,\n })\n },\n }\n })\n\n return {\n mergedPosInfo,\n triggerTarget,\n }\n}\n\nexport interface TourContext {\n currentStep: Ref<TourStepProps | undefined>\n current: Ref<number>\n total: Ref<number>\n showClose: Ref<boolean>\n closeIcon: Ref<string | Component | undefined>\n mergedType: Ref<'default' | 'primary' | undefined>\n ns: UseNamespaceReturn\n slots: SetupContext['slots']\n updateModelValue(modelValue: boolean): void\n onClose(): void\n onFinish(): void\n onChange(): void\n}\n\nexport const tourKey: InjectionKey<TourContext> = Symbol('ElTour')\n\nfunction isInViewPort(element: HTMLElement) {\n const viewWidth = window.innerWidth || document.documentElement.clientWidth\n const viewHeight = window.innerHeight || document.documentElement.clientHeight\n const { top, right, bottom, left } = element.getBoundingClientRect()\n\n return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight\n}\n\nexport const useFloating = (\n referenceRef: Ref<HTMLElement | VirtualElement | null>,\n contentRef: Ref<HTMLElement | null>,\n arrowRef: Ref<HTMLElement | null>,\n placement: Ref<Placement | undefined>,\n strategy: Ref<Strategy>,\n offset: Ref<number>,\n zIndex: Ref<number>,\n showArrow: Ref<boolean>\n) => {\n const x = ref<number>()\n const y = ref<number>()\n const middlewareData = ref<ComputePositionReturn['middlewareData']>({})\n\n const states = {\n x,\n y,\n placement,\n strategy,\n middlewareData,\n } as const\n\n const middleware = computed(() => {\n const _middleware: Middleware[] = [\n offsetMiddleware(unref(offset)),\n flip(),\n shift(),\n overflowMiddleware(),\n ]\n\n if (unref(showArrow) && unref(arrowRef)) {\n _middleware.push(\n arrow({\n element: unref(arrowRef)!,\n })\n )\n }\n return _middleware\n })\n\n const update = async () => {\n if (!isClient) return\n\n const referenceEl = unref(referenceRef)\n const contentEl = unref(contentRef)\n if (!referenceEl || !contentEl) return\n\n const data = await computePosition(referenceEl, contentEl, {\n placement: unref(placement),\n strategy: unref(strategy),\n middleware: unref(middleware),\n })\n\n keysOf(states).forEach((key) => {\n states[key].value = data[key]\n })\n }\n\n const contentStyle = computed<CSSProperties>(() => {\n if (!unref(referenceRef)) {\n return {\n position: 'fixed',\n top: '50%',\n left: '50%',\n transform: 'translate3d(-50%, -50%, 0)',\n maxWidth: '100vw',\n zIndex: unref(zIndex),\n }\n }\n\n const { overflow } = unref(middlewareData)\n\n return {\n position: unref(strategy),\n zIndex: unref(zIndex),\n top: unref(y) != null ? `${unref(y)}px` : '',\n left: unref(x) != null ? `${unref(x)}px` : '',\n maxWidth: overflow?.maxWidth ? `${overflow?.maxWidth}px` : '',\n }\n })\n\n const arrowStyle = computed<CSSProperties>(() => {\n if (!unref(showArrow)) return {}\n\n const { arrow } = unref(middlewareData)\n return {\n left: arrow?.x != null ? `${arrow?.x}px` : '',\n top: arrow?.y != null ? `${arrow?.y}px` : '',\n }\n })\n\n let cleanup: any\n onMounted(() => {\n const referenceEl = unref(referenceRef)\n const contentEl = unref(contentRef)\n if (referenceEl && contentEl) {\n cleanup = autoUpdate(referenceEl, contentEl, update)\n }\n\n watchEffect(() => {\n update()\n })\n })\n\n onBeforeUnmount(() => {\n cleanup && cleanup()\n })\n\n return {\n update,\n contentStyle,\n arrowStyle,\n }\n}\n\nconst overflowMiddleware = (): Middleware => {\n return {\n name: 'overflow',\n async fn(state) {\n const overflow = await detectOverflow(state)\n let overWidth = 0\n if (overflow.left > 0) overWidth = overflow.left\n if (overflow.right > 0) overWidth = overflow.right\n const floatingWidth = state.rects.floating.width\n return {\n data: {\n maxWidth: floatingWidth - overWidth,\n },\n }\n },\n }\n}\n"],"mappings":"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"}