{"version":3,"file":"hooks.mjs","sources":["../../../components/scroll/hooks.ts"],"sourcesContent":["import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'\r\n\r\nimport { useManualRef } from '@vexip-ui/hooks'\r\nimport { multipleFixed, toNumber } from '@vexip-ui/utils'\r\n\r\nimport type { Ref } from 'vue'\r\nimport type { ScrollMode } from './symbol'\r\n\r\nexport function useScrollWrapper({\r\n  mode,\r\n  disabled,\r\n  width,\r\n  height,\r\n  scrollX,\r\n  scrollY,\r\n  onResize,\r\n  onBeforeRefresh,\r\n  onAfterRefresh,\r\n}: {\r\n  mode: Ref<Exclude<ScrollMode, 'horizontal-exact'>>,\r\n  disabled: Ref<boolean>,\r\n  width: Ref<number | string>,\r\n  height: Ref<number | string>,\r\n  scrollX: Ref<number>,\r\n  scrollY: Ref<number>,\r\n  onResize?: (entry: ResizeObserverEntry) => void,\r\n  onBeforeRefresh?: () => void,\r\n  onAfterRefresh?: () => void,\r\n}) {\r\n  const { manualRef, triggerUpdate } = useManualRef()\r\n\r\n  const wrapperEl = ref<HTMLElement>()\r\n  const contentEl = ref<HTMLElement>()\r\n\r\n  // 容器长宽\r\n  const wrapper = reactive({\r\n    el: wrapperEl,\r\n    width: toNumber(width.value),\r\n    height: toNumber(height.value),\r\n  })\r\n\r\n  // 内容长宽\r\n  const content = reactive({\r\n    el: contentEl,\r\n    width: 0,\r\n    height: 0,\r\n  })\r\n\r\n  const x = manualRef(-scrollX.value)\r\n  const y = manualRef(-scrollY.value)\r\n\r\n  const isReady = ref(false)\r\n\r\n  const percentX = manualRef(0)\r\n  const percentY = manualRef(0)\r\n\r\n  const xScrollLimit = computed(() => {\r\n    return wrapper.width ? wrapper.width - content.width : 0\r\n  })\r\n  const yScrollLimit = computed(() => {\r\n    return wrapper.height ? wrapper.height - content.height : 0\r\n  })\r\n  const enableXScroll = computed(() => {\r\n    return (\r\n      !disabled.value &&\r\n      mode.value !== 'vertical' &&\r\n      !!wrapper.width &&\r\n      content.width - wrapper.width > 1\r\n    )\r\n  })\r\n  const enableYScroll = computed(() => {\r\n    return (\r\n      !disabled.value &&\r\n      mode.value !== 'horizontal' &&\r\n      !!wrapper.height &&\r\n      content.height - wrapper.height > 1\r\n    )\r\n  })\r\n  const xBarLength = computed(() => {\r\n    if (wrapper.width) {\r\n      return Math.max(Math.min((wrapper.width / (content.width || 1)) * 100, 99), 5)\r\n    }\r\n\r\n    return 35\r\n  })\r\n  const yBarLength = computed(() => {\r\n    if (wrapper.height) {\r\n      return Math.max(Math.min((wrapper.height / (content.height || 1)) * 100, 99), 5)\r\n    }\r\n\r\n    return 35\r\n  })\r\n\r\n  watch(wrapperEl, () => {\r\n    refreshWrapper()\r\n  })\r\n  watch(contentEl, () => {\r\n    computeContentSize()\r\n  })\r\n  watch(scrollX, value => {\r\n    x.value = -value\r\n    verifyScroll()\r\n  })\r\n  watch(scrollY, value => {\r\n    y.value = -value\r\n    verifyScroll()\r\n  })\r\n  watch(width, () => {\r\n    refreshWrapper().then(verifyScroll)\r\n  })\r\n  watch(height, () => {\r\n    refreshWrapper().then(verifyScroll)\r\n  })\r\n\r\n  function computeWrapperSize(sizeType: 'width' | 'height') {\r\n    return nextTick(() => {\r\n      if (!wrapper.el) return\r\n\r\n      const size = sizeType === 'width' ? width.value : height.value\r\n      const titleCaseSizeType = sizeType.slice(0, 1).toUpperCase() + sizeType.slice(1)\r\n\r\n      // 获取 wrapper 的 px 大小\r\n      if (typeof size === 'string') {\r\n        if (!size.endsWith('px') && (!size || Number.isNaN(Number(size)))) {\r\n          wrapper[sizeType] =\r\n            wrapper.el[`offset${titleCaseSizeType}` as 'offsetWidth' | 'offsetHeight']\r\n        } else {\r\n          wrapper[sizeType] = parseInt(size)\r\n        }\r\n      } else {\r\n        wrapper[sizeType] = size\r\n      }\r\n    })\r\n  }\r\n\r\n  async function refreshWrapper() {\r\n    const promises: Promise<void>[] = []\r\n\r\n    if (mode.value !== 'vertical') {\r\n      promises.push(computeWrapperSize('width'))\r\n    }\r\n\r\n    if (mode.value !== 'horizontal') {\r\n      promises.push(computeWrapperSize('height'))\r\n    }\r\n\r\n    await Promise.all(promises)\r\n  }\r\n\r\n  let timer: ReturnType<typeof setTimeout>\r\n\r\n  function computeContentSize() {\r\n    clearTimeout(timer)\r\n\r\n    return new Promise<void>(resolve => {\r\n      isReady.value = false\r\n\r\n      timer = setTimeout(() => {\r\n        if (!content.el) {\r\n          resolve()\r\n          return\r\n        }\r\n\r\n        if (mode.value !== 'vertical') {\r\n          content.width = content.el.offsetWidth\r\n\r\n          if (wrapper.width >= content.width) {\r\n            x.value = 0\r\n          } else {\r\n            if (x.value === 0) {\r\n              x.value = -scrollX.value\r\n            }\r\n          }\r\n        }\r\n\r\n        if (mode.value !== 'horizontal') {\r\n          content.height = content.el.offsetHeight\r\n\r\n          if (wrapper.height >= content.height) {\r\n            y.value = 0\r\n          } else {\r\n            if (y.value === 0) {\r\n              y.value = -scrollY.value\r\n            }\r\n          }\r\n        }\r\n\r\n        setTimeout(() => {\r\n          isReady.value = true\r\n          verifyScroll()\r\n          resolve()\r\n        }, 1)\r\n      }, 0)\r\n    })\r\n  }\r\n\r\n  /**\r\n   * Will post process the percent scroll values.\r\n   */\r\n  function verifyScroll() {\r\n    if (!isReady.value) {\r\n      return\r\n    }\r\n\r\n    if (mode.value !== 'vertical') {\r\n      x.value = Math.min(0, Math.max(x.value, xScrollLimit.value))\r\n\r\n      if (mode.value !== 'both') {\r\n        y.value = 0\r\n      }\r\n    }\r\n\r\n    if (mode.value !== 'horizontal') {\r\n      y.value = Math.min(0, Math.max(y.value, yScrollLimit.value))\r\n\r\n      if (mode.value !== 'both') {\r\n        x.value = 0\r\n      }\r\n    }\r\n\r\n    computePercent()\r\n    triggerUpdate()\r\n  }\r\n\r\n  function computePercent() {\r\n    percentX.value = multipleFixed(x.value / (xScrollLimit.value || -1), 100, 2)\r\n    percentY.value = multipleFixed(y.value / (yScrollLimit.value || -1), 100, 2)\r\n\r\n    percentX.value = Math.max(0, Math.min(percentX.value, 100))\r\n    percentY.value = Math.max(0, Math.min(percentY.value, 100))\r\n  }\r\n\r\n  function handleResize(entity: ResizeObserverEntry) {\r\n    refresh()\r\n    onResize?.(entity)\r\n  }\r\n\r\n  let isMounted = false\r\n\r\n  onMounted(() => {\r\n    refresh()\r\n    isMounted = true\r\n  })\r\n\r\n  async function refresh() {\r\n    if (typeof onBeforeRefresh === 'function') {\r\n      onBeforeRefresh()\r\n    }\r\n\r\n    refreshWrapper()\r\n    await computeContentSize().then(() => {\r\n      setTimeout(\r\n        () => {\r\n          verifyScroll()\r\n\r\n          if (typeof onAfterRefresh === 'function') {\r\n            onAfterRefresh()\r\n          }\r\n        },\r\n        isMounted ? 20 : 100,\r\n      )\r\n    })\r\n  }\r\n\r\n  return {\r\n    wrapperEl,\r\n    contentEl,\r\n\r\n    wrapper,\r\n    content,\r\n    isReady,\r\n    x,\r\n    y,\r\n    percentX,\r\n    percentY,\r\n    xScrollLimit,\r\n    yScrollLimit,\r\n    enableXScroll,\r\n    enableYScroll,\r\n    xBarLength,\r\n    yBarLength,\r\n\r\n    handleResize,\r\n    verifyScroll,\r\n    computePercent,\r\n    refresh,\r\n    triggerUpdate,\r\n  }\r\n}\r\n"],"names":["useScrollWrapper","mode","disabled","width","height","scrollX","scrollY","onResize","onBeforeRefresh","onAfterRefresh","manualRef","triggerUpdate","useManualRef","wrapperEl","ref","contentEl","wrapper","reactive","toNumber","content","x","y","isReady","percentX","percentY","xScrollLimit","computed","yScrollLimit","enableXScroll","enableYScroll","xBarLength","yBarLength","watch","refreshWrapper","computeContentSize","value","verifyScroll","computeWrapperSize","sizeType","nextTick","size","titleCaseSizeType","promises","timer","resolve","computePercent","multipleFixed","handleResize","entity","refresh","isMounted","onMounted"],"mappings":"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"}