| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- import { nextTick, unref } from "vue";
- export const useScroll = () => {
- const resolveElement = (value) => {
- const instance = unref(value);
- return instance?.$el ?? instance ?? null;
- };
- const resolveContainer = (targetElement, containerRef) => {
- const containerInstance = unref(containerRef);
- if (typeof containerInstance?.setScrollPosition === "function") {
- return {
- instance: containerInstance,
- element:
- containerInstance.getScrollTarget?.() ??
- containerInstance.$el?.querySelector?.(
- ".q-scrollarea__container",
- ) ??
- containerInstance.$el,
- isQuasar: true,
- };
- }
- const providedElement = resolveElement(containerRef);
- const detectedElement = targetElement?.closest?.(
- ".q-scrollarea__container, .scroll, .scroll-y",
- );
- const element =
- providedElement ??
- detectedElement ??
- document.scrollingElement ??
- document.documentElement;
- return {
- instance: element,
- element,
- isQuasar: false,
- };
- };
- //
- const calculatePosition = (targetElement, containerElement, offset) => {
- const targetRect = targetElement.getBoundingClientRect();
- const isDocumentContainer =
- containerElement === document.body ||
- containerElement === document.documentElement ||
- containerElement === document.scrollingElement;
- if (isDocumentContainer) {
- return Math.max(
- 0,
- targetRect.top + window.scrollY - offset,
- );
- }
- const containerRect = containerElement.getBoundingClientRect();
- return Math.max(
- 0,
- targetRect.top -
- containerRect.top +
- containerElement.scrollTop -
- offset,
- );
- };
- const scrollToComponent = (targetRef, containerRef, options = {}) => {
- const { offset = 150, duration = 150, behavior = "smooth" } = options;
- const targetElement = resolveElement(targetRef);
- if (!targetElement) {
- console.warn("useScroll: Target element not found");
- return false;
- }
- const container = resolveContainer(targetElement, containerRef);
- const containerElement = container.element;
- if (!containerElement) {
- console.warn("useScroll: Container element not found");
- return false;
- }
- const isDocumentContainer =
- containerElement === document.body ||
- containerElement === document.documentElement ||
- containerElement === document.scrollingElement;
- if (
- !isDocumentContainer &&
- !containerElement.contains(targetElement)
- ) {
- console.warn("useScroll: Target is not inside the container");
- return false;
- }
- try {
- const targetPosition = calculatePosition(
- targetElement,
- containerElement,
- offset,
- );
- if (container.isQuasar) {
- container.instance.setScrollPosition(
- "vertical",
- targetPosition,
- duration,
- );
- } else if (isDocumentContainer) {
- window.scrollTo({
- top: targetPosition,
- behavior,
- });
- } else {
- containerElement.scrollTo({
- top: targetPosition,
- behavior,
- });
- }
- return true;
- } catch (error) {
- console.error("useScroll: Error while scrolling", error);
- return false;
- }
- };
- const scrollToFirstError = async (
- formRef,
- containerRef,
- options = {},
- ) => {
- await nextTick();
- const forms = unref(formRef);
- const formInstances = Array.isArray(forms) ? forms : [forms];
- for (const formInstance of formInstances) {
- const formElement = resolveElement(formInstance);
- const errorElement =
- formElement?.matches?.(".q-field--error")
- ? formElement
- : formElement?.querySelector?.(".q-field--error");
- if (errorElement) {
- const scrollFn = options.scrollFn ?? scrollToComponent;
- return scrollFn(errorElement, containerRef, options);
- }
- }
- return false;
- };
- return {
- scrollToComponent,
- scrollToFirstError,
- };
- };
|