@vnmfify/core
Version:
```shell npm i @vnmfify/core -S ```
438 lines (382 loc) • 16.2 kB
JavaScript
import _clamp from "lodash/clamp";
var _excluded = ["className", "defaultValue", "value", "lazyRender", "loop", "touchable", "autoplay", "duration", "width", "height", "direction", "stopPropagation", "children", "onChange"];
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { useForceUpdate, useUncontrolled } from "@vnmfify/hooks";
import { View } from "@vnxjs/components";
import { nextTick } from "@vnxjs/vnmf";
import classNames from "classnames";
import * as React from "react";
import { Children, cloneElement, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useMounted, useWindowResize } from "../hooks";
import { prefixClassname } from "../styles";
import { getComputedStyle } from "../utils/dom/computed-style";
import { preventDefault } from "../utils/dom/event";
import { getRect, makeRect } from "../utils/dom/rect";
import { addUnitPx, unitToPx } from "../utils/format/unit";
import { doubleRaf } from "../utils/raf";
import { useRendered, useRenderedRef, useToRef } from "../utils/state";
import { useTouch } from "../utils/touch";
import SwiperIndicator from "./swiper-indicator";
import SwiperItem from "./swiper-item";
import SwiperContext from "./swiper.context";
function useSwiperChildren(children) {
var __children__ = {
items: [],
indicator: undefined,
count: 0
};
var index = 0;
Children.forEach(children, (child, i) => {
if (! /*#__PURE__*/isValidElement(child)) {
return;
}
var element = child;
var elementType = element.type;
if (elementType === SwiperIndicator) {
__children__.indicator = element;
} else if (elementType === SwiperItem) {
var {
key
} = element;
__children__.items.push( /*#__PURE__*/cloneElement(element, _objectSpread(_objectSpread({}, element.props), {}, {
key: key !== null && key !== void 0 ? key : i,
__dataIndex__: index++
})));
} else {
__children__.items.push(element);
}
});
__children__.count = __children__.items.length;
return __children__;
}
function getIndicatorValue(value, count) {
return (value + count) % count;
}
function Swiper(props) {
var {
className,
defaultValue,
value: valueProp,
lazyRender,
loop = true,
touchable = true,
autoplay = 0,
duration = 500,
width,
height,
direction = "horizontal",
stopPropagation = true,
children: childrenProp,
onChange: onChangeProp
} = props,
restProps = _objectWithoutProperties(props, _excluded);
var {
value = 0,
setValue
} = useUncontrolled({
value: valueProp,
defaultValue,
onChange: onChangeProp
});
var valueRef = useToRef(value);
var {
count,
indicator,
items
} = useSwiperChildren(childrenProp);
var itemInstances = useMemo(() => [], []);
var touch = useTouch();
var forceUpdate = useForceUpdate();
var vertical = direction === "vertical";
var rootRef = useRef();
var rectRef = useRef();
var [offset, setOffset] = useState(0);
var swipingRef = useRef(false);
var activeIndexRef = useRef(0);
var touchStartTimeRef = useRef(0);
var autoplayTimerRef = useRef();
var valueIndicatorRef = useRenderedRef(() => getIndicatorValue(value, count));
var activeIndicatorRef = useRenderedRef(() => getIndicatorValue(activeIndexRef.current, count));
var getDelta = useCallback(() => vertical ? touch.deltaY : touch.deltaX, []);
var getCorrectDirection = useCallback(() => touch.direction === direction, []);
var getCustomRect = useCallback(() => {
var _rectRef$current, _rectRef$current2;
return {
width: width !== null && width !== void 0 ? width : (_rectRef$current = rectRef.current) === null || _rectRef$current === void 0 ? void 0 : _rectRef$current.width,
height: height !== null && height !== void 0 ? height : (_rectRef$current2 = rectRef.current) === null || _rectRef$current2 === void 0 ? void 0 : _rectRef$current2.height
};
}, [height, width]);
var propRectRef = useRenderedRef(() => ({
width,
height
}));
var getSize = useCallback(() => {
var _ref;
var {
height,
width
} = getCustomRect();
return (_ref = vertical ? height : width) !== null && _ref !== void 0 ? _ref : 0;
}, [getCustomRect, vertical]);
var getTrackSize = useCallback(() => count * getSize(), [count, getSize]);
var getMinOffset = useCallback(() => {
if (rectRef.current) {
var _ref2, _rectRef$current3, _rectRef$current4;
var base = (_ref2 = vertical ? (_rectRef$current3 = rectRef.current) === null || _rectRef$current3 === void 0 ? void 0 : _rectRef$current3.height : (_rectRef$current4 = rectRef.current) === null || _rectRef$current4 === void 0 ? void 0 : _rectRef$current4.width) !== null && _ref2 !== void 0 ? _ref2 : 0;
return base - getSize() * count;
}
return 0;
}, [count, getSize, vertical]);
var getMaxCount = useCallback(() => Math.ceil(Math.abs(getMinOffset()) / getSize()), [getMinOffset, getSize]);
var getTargetActive = useCallback(pace => {
if (pace) {
if (loop) {
return _clamp(activeIndexRef.current + pace, -1, count);
}
return _clamp(activeIndexRef.current + pace, 0, getMaxCount());
}
return activeIndexRef.current;
}, [loop, getMaxCount, count]);
var getTargetOffset = useCallback(function (targetActive) {
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var size = getSize();
var minOffset = getMinOffset();
var currentPosition = targetActive * size;
if (!loop) {
currentPosition = Math.min(currentPosition, -minOffset);
}
var targetOffset = offset - currentPosition;
if (!loop) {
targetOffset = _clamp(targetOffset, getMinOffset(), 0);
}
return targetOffset;
}, [getMinOffset, getSize, loop]);
var moveTo = useCallback(_ref3 => {
var {
pace = 0,
offset = 0,
emitChange = false
} = _ref3;
if (count <= 1) {
return;
}
var minOffset = getMinOffset();
var targetActive = getTargetActive(pace);
var targetOffset = getTargetOffset(targetActive, offset);
if (loop) {
if (itemInstances[0] && targetOffset !== minOffset) {
var outRightBound = targetOffset < minOffset;
itemInstances[0].setOffset(outRightBound ? getTrackSize() : 0);
}
if (itemInstances[count - 1] && targetOffset !== 0) {
var outLeftBound = targetOffset > 0;
itemInstances[count - 1].setOffset(outLeftBound ? -getTrackSize() : 0);
}
}
var previousActiveIndex = activeIndexRef.current;
activeIndexRef.current = targetActive;
setOffset(targetOffset);
if (emitChange && previousActiveIndex !== targetActive) {
setValue(getIndicatorValue(targetActive, count));
}
}, [count, getMinOffset, getTargetActive, getTargetOffset, loop, itemInstances, getSize, getTrackSize, setValue]);
var correctPosition = useCallback(() => {
swipingRef.current = true;
if (activeIndexRef.current <= -1) {
moveTo({
pace: count
});
} else if (activeIndexRef.current >= count) {
moveTo({
pace: -count
});
}
}, [count, moveTo]);
var swipeTo = useCallback(index => {
correctPosition();
touch.reset();
doubleRaf(() => {
var targetIndex;
if (loop && index === count) {
targetIndex = activeIndexRef.current === 0 ? 0 : index;
} else {
targetIndex = index % count;
}
swipingRef.current = false;
moveTo({
pace: targetIndex - activeIndexRef.current,
emitChange: true
});
});
}, [correctPosition, count, loop, moveTo, touch]);
var next = useCallback(() => {
correctPosition();
doubleRaf(() => {
swipingRef.current = false;
moveTo({
pace: 1,
emitChange: true
});
});
}, [correctPosition, moveTo]);
var stopAutoplay = useCallback(() => {
if (autoplayTimerRef.current) {
clearTimeout(autoplayTimerRef.current);
}
}, []);
var startAutoplay = useCallback(() => {
stopAutoplay();
if (autoplay > 0 && count > 1) {
autoplayTimerRef.current = setTimeout(() => {
next();
startAutoplay();
}, +autoplay);
}
}, [autoplay, count, next, stopAutoplay]);
var onTouchStart = useCallback(event => {
if (!touchable) {
return;
}
touch.start(event);
touchStartTimeRef.current = Date.now();
stopAutoplay();
correctPosition();
}, [correctPosition, stopAutoplay, touch, touchable]);
var onTouchMove = useCallback(event => {
if (!touchable || !swipingRef.current) {
return;
}
touch.move(event);
var correctDirection = getCorrectDirection();
var shouldPrevent = correctDirection || touch.offsetY > touch.offsetX === vertical;
if (shouldPrevent) {
preventDefault(event, stopPropagation);
}
if (correctDirection) {
moveTo({
offset: getDelta()
});
}
}, [getCorrectDirection, getDelta, moveTo, stopPropagation, touch, touchable, vertical]);
var onTouchEnd = useCallback(() => {
if (!touchable || !swipingRef.current) {
return;
}
var duration = Date.now() - touchStartTimeRef.current;
var delta = getDelta();
var speed = delta / duration;
var size = getSize();
var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(delta) > size / 2;
swipingRef.current = false;
var correctDirection = getCorrectDirection();
if (shouldSwipe && correctDirection) {
var _offset = vertical ? touch.offsetY : touch.offsetX;
var pace;
if (loop) {
pace = _offset > 0 ? delta > 0 ? -1 : 1 : 0;
} else {
pace = -Math[delta > 0 ? "ceil" : "floor"](delta / size);
}
moveTo({
pace,
emitChange: true
});
} else if (delta) {
moveTo({
pace: 0
});
}
startAutoplay();
}, [touchable, getDelta, getSize, getCorrectDirection, startAutoplay, vertical, touch.offsetY, touch.offsetX, loop, moveTo]);
var getTrackRect = useCallback(() => new Promise(resolve => {
nextTick(() => resolve(Promise.all([getRect(rootRef), getComputedStyle(rootRef, ["width", "height"])]).then(_ref4 => {
var [rect, style] = _ref4;
return makeRect(style.width === "auto" ? rect.width : unitToPx(style.width), style.height === "auto" ? rect.height : unitToPx(style.height));
})));
}), []);
var initialize = useCallback( /*#__PURE__*/_asyncToGenerator(function* () {
var activeIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : valueRef.current;
if (!rootRef.current) {
return;
}
rectRef.current = yield getTrackRect();
if (count) {
activeIndex = Math.min(count - 1, activeIndex);
}
activeIndexRef.current = activeIndex;
swipingRef.current = true;
var targetOffset = getTargetOffset(activeIndex);
setOffset(targetOffset);
if (targetOffset === offset) {
forceUpdate();
}
itemInstances.forEach(item => item.setOffset(0));
}), [valueRef, getTrackRect, count, getTargetOffset, offset, itemInstances, forceUpdate]);
var resize = useCallback(() => nextTick(() => initialize(activeIndexRef.current)), [initialize]);
useMounted(initialize);
useWindowResize(resize);
useMounted(() => {
startAutoplay();
return stopAutoplay;
});
useEffect(() => {
var valueIndicator = valueIndicatorRef.current;
var activeIndicator = activeIndicatorRef.current;
if (valueIndicator !== activeIndicator) {
try {
stopAutoplay();
swipeTo(valueIndicator);
} finally {
startAutoplay();
}
}
}, [valueIndicatorRef.current]);
var trackStyle = useRendered(() => {
var style = {
transitionDuration: "".concat(swipingRef.current ? 0 : duration, "ms"),
transform: "translate".concat(vertical ? "Y" : "X", "(").concat(addUnitPx(offset), ")")
};
var size = getSize === null || getSize === void 0 ? void 0 : getSize();
if (size) {
var mainAxis = vertical ? "height" : "width";
style[mainAxis] = "".concat(addUnitPx(size));
var crossAxis = vertical ? "width" : "height";
var crossAxisValue = propRectRef.current[crossAxis];
style[crossAxis] = crossAxisValue ? addUnitPx(crossAxisValue) : "";
}
return style;
});
return /*#__PURE__*/React.createElement(View, _objectSpread({
ref: rootRef,
className: classNames(prefixClassname("swiper"), className)
}, restProps), /*#__PURE__*/React.createElement(SwiperContext.Provider, {
value: {
lazyRender,
loop,
direction,
indicator: activeIndicatorRef.current,
getSize,
count,
itemInstances
}
}, /*#__PURE__*/React.createElement(View, {
className: classNames(prefixClassname("swiper__track"), {
[prefixClassname("swiper__track--vertical")]: vertical
}),
catchMove: stopPropagation,
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
onTouchCancel: onTouchEnd,
style: trackStyle,
children: items
}), indicator));
}
export default Swiper;
//# sourceMappingURL=swiper.js.map