import { createVNode as _createVNode } from "vue";
import "./styles/slide-group.css";
import { computed, ref, watch, watchEffect } from "vue";
import { clamp, useRender } from "@veno-ui/utils";
import { createSymbol, defineComponent } from "../../utils";
import { FadeTransition } from "../transition";
import { Icon } from "../icon";
import { makeGroupProps, useGroup } from "../../composables/group";
import { makeTagProps } from "../../composables/tag";
import { useDisplay } from "../../composables";
import { useResizeObserver } from "../../composables/resize-observer";
import { bias, calculateCenteredOffset, calculateUpdatedOffset } from "./helpers";
const SlideGroupKey = createSymbol("slide-group");
const SlideGroup = defineComponent({
  name: "VeSlideGroup",
  props: {
    activeClass: {
      type: String,
      default: "v-slide-item--active"
    },
    centerActive: Boolean,
    direction: {
      type: String,
      default: "horizontal"
    },
    symbol: {
      type: null,
      default: SlideGroupKey
    },
    nextIcon: {
      type: String,
      default: "$next"
    },
    prevIcon: {
      type: String,
      default: "$prev"
    },
    showArrows: {
      type: [Boolean, String],
      validator: (v) => typeof v === "boolean" || ["always", "desktop", "mobile"].includes(v)
    },
    ...makeTagProps(),
    ...makeGroupProps()
  },
  emits: {
    "update:modelValue": (_modelValue) => true
  },
  setup(props, {
    slots
  }) {
    const isRtl = ref(false);
    const {
      mobile
    } = useDisplay();
    const group = useGroup(props, props.symbol);
    const isOverflowing = ref(false);
    const scrollOffset = ref(0);
    const containerSize = ref(0);
    const contentSize = ref(0);
    const isHorizontal = computed(() => props.direction === "horizontal");
    const {
      resizeRef: containerRef,
      contentRect: containerRect
    } = useResizeObserver();
    const {
      resizeRef: contentRef,
      contentRect
    } = useResizeObserver();
    watchEffect(() => {
      if (!containerRect.value || !contentRect.value)
        return;
      const sizeProperty = isHorizontal.value ? "width" : "height";
      containerSize.value = containerRect.value[sizeProperty];
      contentSize.value = contentRect.value[sizeProperty];
      isOverflowing.value = containerSize.value + 1 < contentSize.value;
    });
    watch(group.selected, (selected) => {
      if (!selected.length || !contentRef.value)
        return;
      const index = group.items.value.findIndex((item) => item.id === selected[selected.length - 1]);
      const selectedElement = contentRef.value.children[index];
      if (index === 0 || !isOverflowing.value) {
        scrollOffset.value = 0;
      } else if (props.centerActive) {
        scrollOffset.value = calculateCenteredOffset({
          selectedElement,
          containerSize: containerSize.value,
          contentSize: contentSize.value,
          isRtl: isRtl.value,
          isHorizontal: isHorizontal.value
        });
      } else if (isOverflowing.value) {
        scrollOffset.value = calculateUpdatedOffset({
          selectedElement,
          containerSize: containerSize.value,
          contentSize: contentSize.value,
          isRtl: isRtl.value,
          currentScrollOffset: scrollOffset.value,
          isHorizontal: isHorizontal.value
        });
      }
    });
    const disableTransition = ref(false);
    let startTouch = 0;
    let startOffset = 0;
    function onTouchstart(e) {
      const sizeProperty = isHorizontal.value ? "clientX" : "clientY";
      startOffset = scrollOffset.value;
      startTouch = e.touches[0][sizeProperty];
      disableTransition.value = true;
    }
    function onTouchmove(e) {
      if (!isOverflowing.value)
        return;
      const sizeProperty = isHorizontal.value ? "clientX" : "clientY";
      scrollOffset.value = startOffset + startTouch - e.touches[0][sizeProperty];
    }
    function onTouchend(_event) {
      const maxScrollOffset = contentSize.value - containerSize.value;
      if (isRtl.value) {
        if (scrollOffset.value > 0 || !isOverflowing.value) {
          scrollOffset.value = 0;
        } else if (scrollOffset.value <= -maxScrollOffset) {
          scrollOffset.value = -maxScrollOffset;
        }
      } else {
        if (scrollOffset.value < 0 || !isOverflowing.value) {
          scrollOffset.value = 0;
        } else if (scrollOffset.value >= maxScrollOffset) {
          scrollOffset.value = maxScrollOffset;
        }
      }
      disableTransition.value = false;
    }
    function onScroll() {
      containerRef.value && (containerRef.value.scrollLeft = 0);
    }
    const isFocused = ref(false);
    function onFocusin(e) {
      isFocused.value = true;
      if (!isOverflowing.value || !contentRef.value)
        return;
      for (const el of e.composedPath()) {
        for (const item of contentRef.value.children) {
          if (item === el) {
            scrollOffset.value = calculateUpdatedOffset({
              selectedElement: item,
              containerSize: containerSize.value,
              contentSize: contentSize.value,
              isRtl: isRtl.value,
              currentScrollOffset: scrollOffset.value,
              isHorizontal: isHorizontal.value
            });
            return;
          }
        }
      }
    }
    function onFocusout(_e) {
      isFocused.value = false;
    }
    function onFocus(e) {
      if (!isFocused.value && !(e.relatedTarget && contentRef.value?.contains(e.relatedTarget)))
        focus();
    }
    function onKeydown(e) {
      if (!contentRef.value)
        return;
      if (e.key === (isHorizontal.value ? "ArrowRight" : "ArrowDown")) {
        focus("next");
      } else if (e.key === (isHorizontal.value ? "ArrowLeft" : "ArrowUp")) {
        focus("prev");
      } else if (e.key === "Home") {
        focus("first");
      } else if (e.key === "End") {
        focus("last");
      }
    }
    function focus(location) {
      if (!contentRef.value)
        return;
      if (!location) {
        contentRef.value.querySelector("[tabindex]");
        const focusable = [...contentRef.value.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')].filter((el) => !el.hasAttribute("disabled"));
        focusable[0]?.focus();
      } else if (location === "next") {
        const el = contentRef.value.querySelector(":focus")?.nextElementSibling;
        if (el)
          el.focus();
        else
          focus("first");
      } else if (location === "prev") {
        const el = contentRef.value.querySelector(":focus")?.previousElementSibling;
        if (el)
          el.focus();
        else
          focus("last");
      } else if (location === "first") {
        contentRef.value.firstElementChild?.focus();
      } else if (location === "last") {
        contentRef.value.lastElementChild?.focus();
      }
    }
    function scrollTo(location) {
      const sign = isRtl.value ? -1 : 1;
      const newAbosluteOffset = sign * scrollOffset.value + (location === "prev" ? -1 : 1) * containerSize.value;
      scrollOffset.value = sign * clamp(newAbosluteOffset, 0, contentSize.value - containerSize.value);
    }
    const contentStyles = computed(() => {
      const scrollAmount = scrollOffset.value <= 0 ? bias(-scrollOffset.value) : scrollOffset.value > contentSize.value - containerSize.value ? -(contentSize.value - containerSize.value) + bias(contentSize.value - containerSize.value - scrollOffset.value) : -scrollOffset.value;
      return {
        transform: `translate${isHorizontal.value ? "X" : "Y"}(${scrollAmount}px)`,
        transition: disableTransition.value ? "none" : "",
        willChange: disableTransition.value ? "transform" : ""
      };
    });
    const slotProps = computed(() => ({
      next: group.next,
      prev: group.prev,
      select: group.select,
      isSelected: group.isSelected
    }));
    const hasAffixes = computed(() => {
      switch (props.showArrows) {
        case "always":
          return true;
        case "desktop":
          return mobile.value;
        case true:
          return isOverflowing.value || Math.abs(scrollOffset.value) > 0;
        case "mobile":
          return mobile.value || isOverflowing.value || Math.abs(scrollOffset.value) > 0;
        default:
          return !mobile.value && (isOverflowing.value || Math.abs(scrollOffset.value) > 0);
      }
    });
    const hasPrev = computed(() => {
      return hasAffixes.value && scrollOffset.value > 0;
    });
    const hasNext = computed(() => {
      if (!hasAffixes.value)
        return false;
      return contentSize.value > Math.abs(scrollOffset.value) + containerSize.value;
    });
    useRender(() => _createVNode(props.tag, {
      "class": ["ve-slide-group", {
        "ve-slide-group--vertical": !isHorizontal.value,
        "ve-slide-group--has-affixes": hasAffixes.value,
        "ve-slide-group--is-overflowing": isOverflowing.value
      }],
      "tabindex": isFocused.value || group.selected.value.length ? -1 : 0,
      "onFocus": onFocus
    }, {
      default: () => [hasAffixes.value && _createVNode("div", {
        "class": ["ve-slide-group__prev", {
          "ve-slide-group__prev--disabled": !hasPrev.value
        }],
        "onClick": () => scrollTo("prev")
      }, [slots.prev?.(slotProps.value) ?? _createVNode(FadeTransition, null, {
        default: () => [_createVNode(Icon, {
          "icon": props.prevIcon
        }, null)]
      })]), _createVNode("div", {
        "ref": containerRef,
        "class": "ve-slide-group__container",
        "onScroll": onScroll
      }, [_createVNode("div", {
        "ref": contentRef,
        "class": "ve-slide-group__content",
        "style": contentStyles.value,
        "onTouchstart": onTouchstart,
        "onTouchmove": onTouchmove,
        "onTouchend": onTouchend,
        "onFocusin": onFocusin,
        "onFocusout": onFocusout,
        "onKeydown": onKeydown
      }, [slots.default?.(slotProps.value)])]), hasAffixes.value && _createVNode("div", {
        "class": ["ve-slide-group__next", {
          "ve-slide-group__next--disabled": !hasNext.value
        }],
        "onClick": () => scrollTo("next")
      }, [slots.next?.(slotProps.value) ?? _createVNode(FadeTransition, null, {
        default: () => [_createVNode(Icon, {
          "icon": props.nextIcon
        }, null)]
      })])]
    }));
    return {
      selected: group.selected,
      scrollTo,
      scrollOffset,
      focus
    };
  }
});
export {
  SlideGroup,
  SlideGroupKey
};
//# sourceMappingURL=slide-group.mjs.map
