UNPKG

@varlet/ui

Version:

A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.

535 lines (534 loc) • 18.5 kB
var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; import { computed, defineComponent, onActivated, ref, watch } from "vue"; import { call, clamp, doubleRaf, isNumber, preventDefault, toNumber } from "@varlet/shared"; import { onSmartUnmounted, onWindowResize, useEventListener, useTouch } from "@varlet/use"; import VarButton from "../button/index.mjs"; import Hover from "../hover/index.mjs"; import VarIcon from "../icon/index.mjs"; import { usePopup } from "../popup/provide.mjs"; import { createNamespace } from "../utils/components.mjs"; import { toSizeUnit } from "../utils/elements.mjs"; import { props } from "./props.mjs"; import { useSwipeItems, useSwipeResizeListeners } from "./provide.mjs"; const SWIPE_DELAY = 250; const SWIPE_OFFSET = 20; const { name, n, classes } = createNamespace("swipe"); import { renderSlot as _renderSlot, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode, normalizeProps as _normalizeProps, guardReactiveProps as _guardReactiveProps, resolveComponent as _resolveComponent, createVNode as _createVNode, withCtx as _withCtx, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, Transition as _Transition, mergeProps as _mergeProps, renderList as _renderList, Fragment as _Fragment, resolveDirective as _resolveDirective, withDirectives as _withDirectives } from "vue"; const _hoisted_1 = ["onClick"]; function __render__(_ctx, _cache) { const _component_var_icon = _resolveComponent("var-icon"); const _component_var_button = _resolveComponent("var-button"); const _directive_hover = _resolveDirective("hover"); return _withDirectives((_openBlock(), _createElementBlock( "div", { ref: "swipeEl", class: _normalizeClass(_ctx.n()) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.classes(_ctx.n("track"), [_ctx.vertical, _ctx.n("--vertical")])), style: _normalizeStyle({ width: !_ctx.vertical ? _ctx.toSizeUnit(_ctx.trackSize) : void 0, height: _ctx.vertical ? _ctx.toSizeUnit(_ctx.trackSize) : void 0, transform: `translate${_ctx.vertical ? "Y" : "X"}(${_ctx.toSizeUnit(_ctx.trackTranslate)})`, transitionDuration: _ctx.lockDuration ? "0ms" : `${_ctx.toNumber(_ctx.duration)}ms` }), onTouchstart: _cache[0] || (_cache[0] = (...args) => _ctx.handleTouchstart && _ctx.handleTouchstart(...args)), onTouchmove: _cache[1] || (_cache[1] = (...args) => _ctx.handleTouchmove && _ctx.handleTouchmove(...args)), onTouchend: _cache[2] || (_cache[2] = (...args) => _ctx.handleTouchend && _ctx.handleTouchend(...args)) }, [ _renderSlot(_ctx.$slots, "default") ], 38 /* CLASS, STYLE, NEED_HYDRATION */ ), _ctx.navigation ? _renderSlot(_ctx.$slots, "prev", _normalizeProps(_mergeProps({ key: 0 }, { index: _ctx.index, length: _ctx.length, prev: _ctx.prev, next: _ctx.next, to: _ctx.to, hovering: _ctx.hovering })), () => [ _createVNode(_Transition, { name: _ctx.getNavigationAnimation("prev") }, { default: _withCtx(() => [ _ctx.navigation === true || _ctx.hovering ? (_openBlock(), _createElementBlock( "div", { key: 0, class: _normalizeClass(_ctx.classes(_ctx.n("navigation"), _ctx.n("navigation-prev"), [_ctx.vertical, _ctx.n("--navigation-vertical-prev")])) }, [ _createVNode(_component_var_button, { "var-swipe-cover": "", disabled: !_ctx.loop && _ctx.index === 0, class: _normalizeClass(_ctx.n("navigation-prev-button")), onClick: _cache[3] || (_cache[3] = ($event) => _ctx.prev()) }, { default: _withCtx(() => [ _createVNode(_component_var_icon, { "var-swipe-cover": "", class: _normalizeClass(_ctx.n("navigation-prev-button-icon")), name: _ctx.vertical ? "chevron-up" : "chevron-left" }, null, 8, ["class", "name"]) ]), _: 1 /* STABLE */ }, 8, ["disabled", "class"]) ], 2 /* CLASS */ )) : _createCommentVNode("v-if", true) ]), _: 1 /* STABLE */ }, 8, ["name"]) ]) : _createCommentVNode("v-if", true), _ctx.navigation ? _renderSlot(_ctx.$slots, "next", _normalizeProps(_mergeProps({ key: 1 }, { index: _ctx.index, length: _ctx.length, hovering: _ctx.hovering, prev: _ctx.prev, next: _ctx.next, to: _ctx.to })), () => [ _createVNode(_Transition, { name: _ctx.getNavigationAnimation("next") }, { default: _withCtx(() => [ _ctx.navigation === true || _ctx.hovering ? (_openBlock(), _createElementBlock( "div", { key: 0, class: _normalizeClass(_ctx.classes(_ctx.n("navigation"), _ctx.n("navigation-next"), [_ctx.vertical, _ctx.n("--navigation-vertical-next")])) }, [ _createVNode(_component_var_button, { "var-swipe-cover": "", class: _normalizeClass(_ctx.n("navigation-next-button")), disabled: !_ctx.loop && _ctx.index === _ctx.length - 1, onClick: _cache[4] || (_cache[4] = ($event) => _ctx.next()) }, { default: _withCtx(() => [ _createVNode(_component_var_icon, { "var-swipe-cover": "", class: _normalizeClass(_ctx.n("navigation-next-button-icon")), name: _ctx.vertical ? "chevron-down" : "chevron-right" }, null, 8, ["class", "name"]) ]), _: 1 /* STABLE */ }, 8, ["class", "disabled"]) ], 2 /* CLASS */ )) : _createCommentVNode("v-if", true) ]), _: 1 /* STABLE */ }, 8, ["name"]) ]) : _createCommentVNode("v-if", true), _renderSlot(_ctx.$slots, "indicator", _normalizeProps(_guardReactiveProps({ index: _ctx.index, length: _ctx.length, hovering: _ctx.hovering, prev: _ctx.prev, next: _ctx.next, to: _ctx.to })), () => [ _ctx.indicator && _ctx.length ? (_openBlock(), _createElementBlock( "div", { key: 0, class: _normalizeClass(_ctx.classes(_ctx.n("indicators"), [_ctx.vertical, _ctx.n("--indicators-vertical")])) }, [ (_openBlock(true), _createElementBlock( _Fragment, null, _renderList(_ctx.length, (l, idx) => { return _openBlock(), _createElementBlock("div", { key: l, class: _normalizeClass( _ctx.classes(_ctx.n("indicator"), [_ctx.index === idx, _ctx.n("--indicator-active")], [_ctx.vertical, _ctx.n("--indicator-vertical")]) ), style: _normalizeStyle({ background: _ctx.indicatorColor }), onClick: ($event) => _ctx.to(idx) }, null, 14, _hoisted_1); }), 128 /* KEYED_FRAGMENT */ )) ], 2 /* CLASS */ )) : _createCommentVNode("v-if", true) ]) ], 2 /* CLASS */ )), [ [_directive_hover, _ctx.handleHovering] ]); } const __sfc__ = defineComponent({ name, directives: { Hover }, components: { VarButton, VarIcon }, props, setup(props2) { const swipeEl = ref(null); const size = ref(0); const vertical = computed(() => props2.vertical); const trackSize = ref(0); const trackTranslate = ref(0); const lockDuration = ref(false); const index = ref(0); const hovering = ref(false); const { swipeItems, bindSwipeItems, length } = useSwipeItems(); const { swipeResizeListeners, bindSwipeResizeListeners } = useSwipeResizeListeners(); const { popup, bindPopup } = usePopup(); const { deltaX, deltaY, moveX, moveY, offsetX, offsetY, touching, direction, startTime, startTouch, moveTouch, endTouch } = useTouch(); const isExpectDirection = computed(() => direction.value === (props2.vertical ? "vertical" : "horizontal")); let initializedIndex = false; let timer = -1; const swipeProvider = { size, currentIndex: index, vertical }; bindSwipeItems(swipeProvider); useEventListener(() => window, "keydown", handleKeydown); call(bindPopup, null); call(bindSwipeResizeListeners, null); watch( () => length.value, () => __async(this, null, function* () { yield doubleRaf(); initialIndex(); resize(); }) ); if (popup) { watch( () => popup.show.value, (show) => __async(this, null, function* () { if (show) { yield doubleRaf(); resize(); } else { stopAutoplay(); } }) ); } onActivated(resize); onSmartUnmounted(stopAutoplay); onWindowResize(resize); function findSwipeItem(idx) { return swipeItems.find(({ index: index2 }) => index2.value === idx); } function dispatchSwipeItems() { if (!props2.loop) { return; } if (trackTranslate.value >= 0) { findSwipeItem(length.value - 1).setTranslate(-trackSize.value); } if (trackTranslate.value <= -(trackSize.value - size.value)) { findSwipeItem(0).setTranslate(trackSize.value); } if (trackTranslate.value > -(trackSize.value - size.value) && trackTranslate.value < 0) { findSwipeItem(length.value - 1).setTranslate(0); findSwipeItem(0).setTranslate(0); } } function getSwipeIndex(targetSwipeIndex) { const swipeIndex = isNumber(targetSwipeIndex) ? targetSwipeIndex : Math.floor((trackTranslate.value - size.value / 2) / -size.value); const { loop } = props2; if (swipeIndex <= -1) { return loop ? -1 : 0; } if (swipeIndex >= length.value) { return loop ? length.value : length.value - 1; } return swipeIndex; } function swipeIndexToIndex(swipeIndex) { const { loop } = props2; if (swipeIndex === -1) { return loop ? length.value - 1 : 0; } if (swipeIndex === length.value) { return loop ? 0 : length.value - 1; } return swipeIndex; } function clampIndex(index2) { if (props2.loop) { if (index2 < 0) { return length.value + index2; } if (index2 >= length.value) { return index2 - length.value; } return index2; } return clamp(index2, 0, length.value - 1); } function fixPosition() { return __async(this, null, function* () { const overLeft = trackTranslate.value >= size.value; const overRight = trackTranslate.value <= -trackSize.value; const leftTranslate = 0; const rightTranslate = -(trackSize.value - size.value); lockDuration.value = true; if (overLeft || overRight) { lockDuration.value = true; trackTranslate.value = overRight ? leftTranslate : rightTranslate; findSwipeItem(0).setTranslate(0); findSwipeItem(length.value - 1).setTranslate(0); } yield doubleRaf(); lockDuration.value = false; }); } function initialIndex() { if (initializedIndex) { return; } index.value = clampIndex(toNumber(props2.initialIndex)); initializedIndex = true; } function startAutoplay() { const { autoplay } = props2; if (!autoplay || length.value <= 1) { return; } stopAutoplay(); timer = window.setTimeout(() => { next(); startAutoplay(); }, toNumber(autoplay)); } function stopAutoplay() { timer && clearTimeout(timer); } function handleTouchstart(event) { return __async(this, null, function* () { if (length.value <= 1 || !props2.touchable) { return; } startTouch(event); stopAutoplay(); yield fixPosition(); lockDuration.value = true; }); } function handleTouchmove(event) { const { touchable, vertical: vertical2 } = props2; if (!touching.value || !touchable) { return; } moveTouch(event); if (!isExpectDirection.value) { return; } preventDefault(event); trackTranslate.value += vertical2 ? moveY.value : moveX.value; dispatchSwipeItems(); } function handleTouchend() { if (!touching.value) { return; } endTouch(); if (!isExpectDirection.value) { return; } const { vertical: vertical2, onChange } = props2; const positive = vertical2 ? deltaY.value < 0 : deltaX.value < 0; const offset = vertical2 ? offsetY.value : offsetX.value; const quickSwiping = performance.now() - startTime.value <= SWIPE_DELAY && offset >= SWIPE_OFFSET; const swipeIndex = quickSwiping ? positive ? getSwipeIndex(index.value + 1) : getSwipeIndex(index.value - 1) : getSwipeIndex(); lockDuration.value = false; trackTranslate.value = swipeIndex * -size.value; const prevIndex = index.value; index.value = swipeIndexToIndex(swipeIndex); startAutoplay(); if (prevIndex !== index.value) { call(onChange, index.value); } } function handleHovering(value) { if (props2.navigation === "hover") { hovering.value = value; } } function getNavigationAnimation(type) { if (props2.navigation !== "hover") { return ""; } return n(`--navigation${props2.vertical ? "-vertical" : ""}-${type}-animation`); } function handleKeydown(event) { if (!swipeItems.length) { return; } const focusingSwipeItemIndex = swipeItems.findIndex(({ isFocusing }) => isFocusing.value); if (focusingSwipeItemIndex === -1) { return; } const { key } = event; preventDefault(event); if (key === "ArrowLeft") { prev(); } if (key === "ArrowRight") { next(); } } function resize() { if (!swipeEl.value) { return; } lockDuration.value = true; size.value = props2.vertical ? swipeEl.value.offsetHeight : swipeEl.value.offsetWidth; trackSize.value = size.value * length.value; trackTranslate.value = index.value * -size.value; swipeItems.forEach((swipeItem) => { swipeItem.setTranslate(0); }); startAutoplay(); setTimeout(() => { lockDuration.value = false; }); swipeResizeListeners.forEach(({ onResize }) => { onResize(); }); } function next(options) { return __async(this, null, function* () { if (length.value <= 1) { return; } initialIndex(); const { loop, onChange } = props2; const currentIndex = index.value; index.value = clampIndex(currentIndex + 1); if ((options == null ? void 0 : options.event) !== false) { call(onChange, index.value); } yield fixPosition(); if (currentIndex === length.value - 1 && loop) { findSwipeItem(0).setTranslate(trackSize.value); trackTranslate.value = length.value * -size.value; return; } if (currentIndex !== length.value - 1) { trackTranslate.value = index.value * -size.value; } }); } function prev(options) { return __async(this, null, function* () { if (length.value <= 1) { return; } initialIndex(); const { loop, onChange } = props2; const currentIndex = index.value; index.value = clampIndex(currentIndex - 1); if ((options == null ? void 0 : options.event) !== false) { call(onChange, index.value); } yield fixPosition(); if (currentIndex === 0 && loop) { findSwipeItem(length.value - 1).setTranslate(-trackSize.value); trackTranslate.value = size.value; return; } if (currentIndex !== 0) { trackTranslate.value = index.value * -size.value; } }); } function to(idx, options) { if (length.value <= 1 || idx === index.value) { return; } idx = idx < 0 ? 0 : idx; idx = idx >= length.value ? length.value : idx; const task = idx > index.value ? next : prev; const count = Math.abs(idx - index.value); Array.from({ length: count }).forEach((_, index2) => { task({ event: index2 === count - 1 ? options == null ? void 0 : options.event : false }); }); } return { length, index, swipeEl, trackSize, trackTranslate, lockDuration, hovering, n, toSizeUnit, classes, handleTouchstart, handleTouchmove, handleTouchend, next, prev, to, resize, toNumber, handleHovering, getNavigationAnimation }; } }); __sfc__.render = __render__; var stdin_default = __sfc__; export { stdin_default as default };