react-slip-and-slide
Version:
##### A react and react-native carousel
1,855 lines (1,819 loc) • 50.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// packages/utils/src/components/AnimatedBox/web/AnimatedBox.tsx
import React2 from "react";
// packages/utils/src/spring/index.ts
import {
animated,
SpringValue,
to,
useSpringValue
} from "@react-spring/web";
// packages/utils/src/components/Box/web/Box.tsx
import React from "react";
var BoxBase = ({
children,
styles,
willMeasure,
onPress,
onPressStart,
web,
native: _,
style
}, ref) => {
const divRef = React.useRef(null);
React.useImperativeHandle(ref, () => ({
measure: () => {
return new Promise((res) => {
if (willMeasure && divRef.current) {
const { width, height } = divRef.current.getBoundingClientRect();
res({
width: divRef.current.offsetWidth || width,
height: divRef.current.offsetHeight || height
});
} else {
res({ width: 0, height: 0 });
}
});
},
addEventListener: (type, listener, options) => {
divRef.current?.addEventListener(type, listener, options);
},
removeEventListener: (type, listener, options) => {
divRef.current?.removeEventListener(type, listener, options);
},
dispatchEvent: (e) => !!divRef.current?.dispatchEvent(e)
}));
return /* @__PURE__ */ React.createElement(
"div",
{
ref: divRef,
onClick: onPress,
...web,
style: {
...styles,
...web?.style,
...style
},
onMouseDown: onPressStart,
onTouchStart: onPressStart
},
children
);
};
var Box = React.forwardRef(BoxBase);
// packages/utils/src/components/AnimatedBox/helpers.ts
var parseTranslate = (x, y) => {
if (x !== void 0 && y !== void 0) {
return `translate(${x}px, ${y}px)`;
} else if (x !== void 0) {
return `translateX(${x}px)`;
} else if (y !== void 0) {
return `translateY(${y}px)`;
}
return "";
};
var parseTransforms = (transform2) => {
return transform2?.reduce((acc, transform3) => {
const [trs] = Object.entries(transform3);
const [key, val] = trs;
acc[key] = val;
return acc;
}, {});
};
var selectTransforms = (transforms) => {
return {
rotateX: transforms?.rotateX,
rotateY: transforms?.rotateY,
rotateZ: transforms?.rotateZ,
rotate: transforms?.rotate,
scale: transforms?.scale,
scaleX: transforms?.scaleX,
scaleY: transforms?.scaleY,
transform: to(
[transforms?.translateX, transforms?.translateY],
parseTranslate
)
};
};
var springTransformsStyles = (transform2) => {
const transformsObject = parseTransforms(transform2);
return selectTransforms(transformsObject);
};
// packages/utils/src/components/AnimatedBox/web/AnimatedBox.tsx
var AnimatedProxy = animated(Box);
var AnimatedBox = React2.forwardRef(
({ children, style, ...rest }, ref) => {
const transforms = React2.useMemo(
() => springTransformsStyles(style?.transform),
[style?.transform]
);
return /* @__PURE__ */ React2.createElement(
AnimatedProxy,
{
ref,
style: {
...style,
...transforms
},
...rest
},
children
);
}
);
// packages/utils/src/components/GestureContainer/web/GestureContainer.tsx
import { useGesture } from "@use-gesture/react";
import { Lethargy } from "lethargy-ts";
import { throttle as throttle2 } from "lodash";
import React11 from "react";
// packages/utils/src/context/utils.ts
var utils_exports = {};
__export(utils_exports, {
initializeContextData: () => initializeContextData,
processContextData: () => processContextData
});
import { clamp as clamp2, sumBy, uniqueId } from "lodash";
// packages/utils/src/utilities/helpers.ts
import { clamp } from "lodash";
import React3 from "react";
var typedMemo = React3.memo;
function getCurrentDynamicIndex(_input, ranges, validDirection, direction, clampOffset, rangeOffsetPosition) {
let finalIndex = 0;
const input = Math.abs(clamp(_input, clampOffset.MAX, clampOffset.MIN));
const index = ranges.findIndex((item2) => {
return item2.range.start <= input && input <= item2.range.end;
});
if (index === -1) {
return finalIndex;
}
const item = ranges[index];
const itemOffset = item.range[rangeOffsetPosition];
const offset = input;
if (offset > itemOffset && validDirection === "left") {
finalIndex = item.index + 1;
} else if (offset < itemOffset && validDirection === "right") {
finalIndex = item.index - 1;
} else {
finalIndex = item.index;
}
if (!direction) {
finalIndex = item.index;
}
return clampIndex(finalIndex, ranges);
}
var getNextDynamicOffset = ({
offsetX,
ranges,
lastValidDirection,
direction,
clampOffset,
rangeOffsetPosition
}) => {
const currIndex = getCurrentDynamicIndex(
offsetX,
ranges,
lastValidDirection,
direction,
clampOffset,
rangeOffsetPosition
);
const offset = ranges[currIndex]?.range[rangeOffsetPosition] || 0;
return -offset;
};
var clampIndex = (index, data) => clamp(index, 0, data.length - 1);
var getDynamicRangeSum = (itemDimensionMap) => {
let previousSum = 0;
const range = [];
itemDimensionMap.forEach(({ width = 0 }, index) => {
range.push({
index,
width,
range: {
start: previousSum,
center: previousSum + width / 2,
end: previousSum + width
}
});
previousSum += width;
});
return range;
};
var isInRange = (index, { dataLength, viewSize, offsetX, visibleItems }) => {
const upperAmount = Math.round(visibleItems / 2);
const lowerAmount = visibleItems - upperAmount;
const fixedIndex = Math.round(-offsetX / viewSize);
const currentIndex = fixedIndex < 0 ? fixedIndex % dataLength + dataLength : fixedIndex;
const lowerRange = [
(currentIndex + dataLength - lowerAmount) % dataLength,
(currentIndex + dataLength - 1) % dataLength
];
const upperRange = [
currentIndex % dataLength,
(currentIndex + upperAmount) % dataLength
];
if (lowerRange[0] < dataLength && lowerRange[0] > lowerRange[1] || upperRange[0] > upperRange[1]) {
lowerRange[1] = dataLength - 1;
upperRange[0] = 0;
}
const isInLowerRange = index >= lowerRange[0] && index <= lowerRange[1];
const isInUpperRange = index >= upperRange[0] && index <= upperRange[1];
if (isInLowerRange || isInUpperRange) {
return true;
}
return false;
};
var useIsFirstRender = () => {
const isFirst = React3.useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
};
var processClampOffsets = ({
wrapperWidth,
sideMargins,
centered,
containerWidth,
itemDimensionMode,
ranges
}) => {
let MIN = 0;
let MAX = 0;
if (itemDimensionMode === "static") {
MAX = -wrapperWidth + containerWidth;
if (centered) {
const _MAX_CENTERED = MAX - sideMargins * 2;
MAX = _MAX_CENTERED;
}
} else {
const position = centered ? "center" : "start";
const firstDynamicOffset = -(ranges[0]?.range[position] || 0);
const sideMargins2 = !centered ? (containerWidth - (ranges[ranges.length - 1]?.width || 0)) / 2 : 0;
const initialCorrection = itemDimensionMode === "dynamic" && centered ? firstDynamicOffset : 0;
MIN = initialCorrection;
MAX = -ranges[ranges.length - 1]?.range[position] + sideMargins2 * 2 || 0;
}
if (wrapperWidth < containerWidth && !centered) {
MAX = MIN;
}
return {
MIN,
MAX
};
};
var elementDimensionStyles = ({
width,
height
}) => {
return {
width: width === 0 ? void 0 : width,
minWidth: width === 0 ? void 0 : width,
height: height === 0 ? void 0 : height,
minHeight: height === 0 ? void 0 : height
};
};
// packages/utils/src/context/utils.ts
var getLargestDynamicItem = (itemDimensionMap) => {
const widest = Math.max(...itemDimensionMap.map((d) => d.width || 0));
const highest = Math.max(...itemDimensionMap.map((d) => d.height || 0));
return {
width: isFinite(widest) ? widest : 0,
height: isFinite(highest) ? highest : 0
};
};
var getDynamicWrapperWidth = (itemDimensionMap) => {
return sumBy(itemDimensionMap, ({ width }) => width);
};
function processContextData(data) {
const {
dataLength,
itemDimensions: { width: itemWidth = 0, height: _itemHeight = 0 },
wrapperWidth: _wrapperWidth,
container,
centered,
fullWidthItem,
itemDimensionMode,
itemDimensionMap,
needsMeasurements
} = data;
const largestItem = getLargestDynamicItem(itemDimensionMap);
const dynamicWrapperWidth = getDynamicWrapperWidth(itemDimensionMap);
const itemDimensions = {
width: fullWidthItem ? container.width : itemWidth || largestItem.width,
height: needsMeasurements ? largestItem.height : _itemHeight
};
const containerDimensions = {
width: container.width,
height: container.height || itemDimensions.height
};
const wrapperWidth = itemDimensionMode === "static" ? dataLength * itemDimensions.width : dynamicWrapperWidth;
const sideMargins = (containerDimensions.width - itemDimensions.width) / 2;
const { MIN, MAX } = processClampOffsets({
wrapperWidth,
sideMargins,
containerWidth: containerDimensions.width,
centered,
itemDimensionMode,
ranges: data.ranges
});
return {
...data,
wrapperWidth,
clampOffset: {
MIN,
MAX
},
itemDimensionMode,
itemDimensions,
container: containerDimensions
};
}
function initializeContextData(props) {
const {
_testId = "",
data,
itemHeight = 0,
itemWidth = 0,
fullWidthItem,
infinite: _infinite,
visibleItems = 0,
containerWidth,
containerHeight,
interpolators,
centered,
momentumMultiplier = 2,
animateStartup = true,
initialIndex,
loadingTime
} = props;
const itemDimensionMode = itemWidth || fullWidthItem ? "static" : "dynamic";
const infinite = itemDimensionMode === "static" && !!_infinite;
const loadingType = visibleItems === 0 ? "eager" : "lazy";
const engineMode = infinite || loadingType === "lazy" ? "multi" : "single";
const shouldAnimatedStartup = !!animateStartup || !!initialIndex || !!loadingTime || itemDimensionMode === "dynamic";
const needsMeasurements = itemDimensionMode === "dynamic" || itemDimensionMode === "static" && engineMode === "multi" && !itemHeight && !containerHeight;
const initialContextData = {
_testId,
initId: uniqueId("init-"),
needsMeasurements,
infinite,
itemDimensionMode,
loadingType,
isReady: false,
shouldAnimatedStartup,
engineMode,
data: props.data,
itemDimensions: {
width: props.itemWidth || (fullWidthItem ? containerWidth : 0) || 0,
height: props.itemHeight || 0
},
container: {
width: containerWidth || 0,
height: containerHeight || itemHeight || 0
},
centered: !!centered,
visibleItems: props.visibleItems || 0,
dataLength: data.length,
wrapperWidth: 0,
clampOffset: {
MIN: 0,
MAX: 0
},
fullWidthItem: !!fullWidthItem,
itemDimensionMap: [],
ranges: [],
interpolators,
rangeOffsetPosition: centered ? "center" : "start",
momentumMultiplier: clamp2(momentumMultiplier, 0, 10),
currentIndex: typeof initialIndex === "number" ? initialIndex : initialIndex?.index || 0,
OffsetX: null
};
return initialContextData;
}
// packages/utils/src/context/hooks.ts
var hooks_exports = {};
__export(hooks_exports, {
useDataContext: () => useDataContext
});
import React10 from "react";
// packages/utils/src/context/provider.tsx
var provider_exports = {};
__export(provider_exports, {
DataProvider: () => DataProvider,
dataContext: () => dataContext
});
import { nothing, produce } from "immer";
import { uniqueId as uniqueId2 } from "lodash";
import React9 from "react";
// packages/utils/src/utilities/displacement.tsx
var displacement = ({
OffsetX,
index = 0,
itemWidth = 200,
infinite,
dataLength
}) => {
if (infinite) {
const halfData = Math.round((dataLength - 1) / 2) + 1;
const halfItem = itemWidth / 2;
const wrapperWidth = dataLength * itemWidth;
const startPosition = index > halfData ? (index - dataLength) * itemWidth : index * itemWidth;
const max = halfData * itemWidth;
const min = -((dataLength - halfData - 1) * itemWidth);
const input = [
-wrapperWidth,
min - halfItem - startPosition,
min - halfItem - startPosition,
0,
max + halfItem - startPosition,
max + halfItem - startPosition,
wrapperWidth
];
const output = [
startPosition,
max + halfItem,
min - halfItem,
startPosition,
max + halfItem,
min - halfItem,
startPosition
];
return to(OffsetX, input, output, "clamp");
}
return to(OffsetX, (x) => x + itemWidth * index);
};
// packages/utils/src/utilities/mergeRefs.ts
function mergeRefs(refs) {
return (value) => {
refs.forEach((ref) => {
if (typeof ref === "function") {
ref(value);
} else if (ref !== null) {
ref.current = value;
}
});
};
}
// packages/utils/src/utilities/rubberband.ts
import { clamp as clamp3 } from "lodash";
var scale = ({ size, multiplier }) => {
return (offset) => {
if (size === 0 || Math.abs(size) === Infinity) {
return Math.pow(offset, multiplier * 5);
}
return offset * size * multiplier / (size + multiplier * offset);
};
};
var createRubberband = ([min, max], multiplier = 0.15) => {
const size = max - min;
const rub = scale({ size, multiplier });
return (offset) => {
if (multiplier === 0) {
return clamp3(offset, min, max);
}
switch (true) {
case offset < min:
return -rub(min - offset) + min;
case offset > max:
return +rub(offset - max) + max;
default:
return offset;
}
};
};
// packages/utils/src/utilities/useDynamicDimension.tsx
import { defer, times } from "lodash";
import React4 from "react";
var useDynamicDimension = () => {
const {
state: { dataLength, initId, needsMeasurements },
actions: { setItemDimensionMap, setRanges }
} = Context.useDataContext();
const itemRefs = React4.useMemo(() => {
if (needsMeasurements) {
return times(dataLength, () => React4.createRef());
}
return [];
}, [dataLength]);
const measure = React4.useCallback(() => {
return new Promise((res) => {
defer(() => {
const promises = itemRefs.map((ref) => ref.current?.measure());
Promise.all(promises).then((measurements) => {
res(
measurements?.map((itemMeasurements) => ({
width: itemMeasurements?.width || 0,
height: itemMeasurements?.height || 0
}))
);
});
});
});
}, [itemRefs]);
React4.useEffect(() => {
if (needsMeasurements) {
measure().then((itemDimensionMap) => {
setItemDimensionMap(itemDimensionMap);
setRanges(getDynamicRangeSum(itemDimensionMap));
});
}
}, [
dataLength,
initId,
measure,
needsMeasurements,
setItemDimensionMap,
setRanges
]);
return {
itemRefs
};
};
// packages/utils/src/utilities/useInterpolation.tsx
import React5 from "react";
var useInterpolation = ({
index
}) => {
const {
state: {
dataLength,
itemDimensions: { width: itemWidth },
infinite,
itemDimensionMode,
ranges,
interpolators,
rangeOffsetPosition,
engineMode,
wrapperWidth,
OffsetX: ContextOffsetX
}
} = Context.useDataContext();
const dynamicOffset = ranges[index]?.range[rangeOffsetPosition] || 0;
const interpolatorsKeys = Object.entries(interpolators || {});
const getTranslateX = React5.useCallback(() => {
const OffsetX = engineMode === "single" ? ContextOffsetX : ContextOffsetX.to((offsetX) => offsetX % wrapperWidth);
const x = displacement({
OffsetX,
dataLength,
index,
itemWidth,
infinite
});
if (itemDimensionMode === "static") {
return x.to((val) => val / itemWidth).to([-1, 0, 1], [-itemWidth, 0, itemWidth]);
}
return to(OffsetX, (x2) => x2 + dynamicOffset);
}, [
ContextOffsetX,
dataLength,
dynamicOffset,
engineMode,
index,
infinite,
itemDimensionMode,
itemWidth,
wrapperWidth
]);
const { scale: scale2, opacity, translateX } = React5.useMemo(() => {
if (itemWidth && (interpolatorsKeys.length || engineMode === "multi")) {
const translateX2 = getTranslateX();
const { scale: scale3 = 1, opacity: opacity2 = 1 } = interpolatorsKeys.reduce(
(acc, [key, val]) => {
acc[key] = translateX2.to((val2) => val2 / itemWidth).to([-1, 0, 1], [val, 1, val], "clamp");
return acc;
},
{}
);
return {
translateX: translateX2,
scale: scale3,
opacity: opacity2
};
}
return {
translateX: 0,
scale: 1,
opacity: 1
};
}, [engineMode, getTranslateX, itemWidth, interpolatorsKeys]);
return {
translateX,
scale: scale2,
opacity
};
};
// packages/utils/src/utilities/useItemsRange.tsx
import React6 from "react";
// packages/utils/src/utilities/useScreenDimensions.tsx
import React7 from "react";
import {
asyncScheduler,
distinctUntilChanged,
fromEvent,
throttleTime
} from "rxjs";
// packages/utils/src/platform/index.ts
var Platform = {
is: (platform) => {
if (!platform) {
return "web";
}
const platforms = {
web: true,
native: false,
ios: false,
android: false
};
return platforms[platform];
}
};
// packages/utils/src/ScreenDimensions/index.ts
var ScreenDimensions = () => {
return {
width: window.innerWidth,
height: window.innerHeight
};
};
// packages/utils/src/utilities/useScreenDimensions.tsx
var useScreenDimensions = () => {
const throttle3 = 100;
const [screenDimensions, setScreenDimensions] = React7.useState(ScreenDimensions());
const set = () => {
setScreenDimensions(ScreenDimensions());
};
React7.useEffect(() => {
if (Platform.is("web")) {
const sub$ = fromEvent(window, "resize").pipe(
throttleTime(throttle3, asyncScheduler, {
leading: true,
trailing: true
}),
distinctUntilChanged()
).subscribe(set);
return () => sub$.unsubscribe();
}
}, []);
return screenDimensions;
};
// packages/utils/src/utilities/useEngine.tsx
import { clamp as clamp4, defer as defer2, throttle } from "lodash";
import React8 from "react";
// packages/utils/src/utilities/config.ts
var baseSpringConfig = {
tension: 220,
friction: 32,
mass: 1
};
var snappySpringConfig = {
...baseSpringConfig,
tension: 320
};
var springConfigByActionType = {
drag: baseSpringConfig,
wheel: baseSpringConfig,
release: baseSpringConfig,
correction: baseSpringConfig,
wheelSnap: snappySpringConfig,
navigate: snappySpringConfig,
ref: snappySpringConfig
};
// packages/utils/src/utilities/useEngine.tsx
var useEngine = ({
snap,
containerWidth: containerWidthProp,
pressToSlide,
rubberbandElasticity,
instanceRef,
initialIndex,
loadingTime,
animateStartup,
onChange,
onEdges,
onReady,
onItemPress
}) => {
const {
state: {
data,
dataLength,
itemDimensions: { width: itemWidth },
loadingType,
centered,
infinite,
itemDimensionMode,
container,
wrapperWidth,
clampOffset,
ranges,
rangeOffsetPosition,
momentumMultiplier,
OffsetX,
isReady,
shouldAnimatedStartup,
initId,
currentIndex
},
actions: { setContainerDimensions, reInit, setCurrentIndex }
} = Context.useDataContext();
const isFirstRender = useIsFirstRender();
const index = React8.useRef(currentIndex);
const [_, reRender] = React8.useState(0);
const lastOffset = React8.useRef(0);
const containerRef = React8.useRef(null);
const isDragging = React8.useRef(false);
const direction = React8.useRef(false);
const lastValidDirection = React8.useRef(null);
const isIntentionalDrag = React8.useRef(false);
const rubberband = React8.useMemo(
() => createRubberband(
[clampOffset.MAX, clampOffset.MIN],
rubberbandElasticity
),
[clampOffset.MAX, clampOffset.MIN, rubberbandElasticity]
);
const actionType = React8.useRef("release");
const Opacity = useSpringValue(shouldAnimatedStartup ? 0 : 1, {
config: {
tension: 220,
friction: 32,
mass: 1
}
});
const { width: screenWidth } = useScreenDimensions();
React8.useLayoutEffect(() => {
defer2(() => {
containerRef.current?.measure().then(({ width, height }) => {
setContainerDimensions({
height: container.height || height,
width: containerWidthProp || width
});
});
});
}, [container, screenWidth, initId]);
const setActionType = (type) => {
actionType.current = type;
};
const checkActionType = React8.useCallback((actionTypes) => {
return actionTypes.includes(actionType.current);
}, []);
const clampReleaseOffset = React8.useCallback(
(offset) => {
if (infinite && itemDimensionMode === "static") {
return offset;
}
return clamp4(offset, clampOffset.MAX, clampOffset.MIN);
},
[clampOffset.MAX, clampOffset.MIN, infinite, itemDimensionMode]
);
const processIndex = React8.useCallback(
({ offset }) => {
if (itemWidth) {
const modIndex = offset / itemWidth % dataLength;
return offset <= 0 ? Math.abs(modIndex) : Math.abs(modIndex > 0 ? dataLength - modIndex : 0);
}
return currentIndex || 0;
},
[currentIndex, dataLength, itemWidth]
);
const getCurrentIndex = React8.useCallback(
({ offset }) => {
if (infinite) {
return -Math.round(offset / itemWidth);
}
return Math.round(processIndex({ offset }));
},
[infinite, itemWidth, processIndex]
);
const getRelativeIndex = React8.useCallback(
({ offset }) => {
return Math.floor(processIndex({ offset }));
},
[processIndex]
);
const getCurrentOffset = React8.useCallback(
({ index: index2 }) => {
const finalOffset = -index2 * itemWidth;
return finalOffset;
},
[itemWidth]
);
const checkEdges = React8.useCallback(
({ offset }) => {
let start = false;
let end = false;
if (offset >= clampOffset.MIN) {
start = true;
} else if (offset <= clampOffset.MAX) {
end = true;
} else {
start = false;
end = false;
}
if (clampOffset.MIN === clampOffset.MAX) {
start = true;
end = true;
}
return { start, end };
},
[clampOffset]
);
const onCallbacks = React8.useCallback(() => {
if (currentIndex !== void 0) {
onChange?.(currentIndex);
}
if (!infinite && !isFirstRender) {
onEdges?.(checkEdges({ offset: lastOffset.current }));
}
}, [checkEdges, currentIndex, infinite, isFirstRender, onChange, onEdges]);
const onEdge = React8.useMemo(
() => throttle((edges) => {
onEdges?.(edges);
}, 120),
[onEdges]
);
const clampIdx = React8.useCallback(
(idx) => {
return clampIndex(idx, data);
},
[data]
);
const handleOnSpringStart = React8.useCallback(() => {
if (checkActionType(["navigate"])) {
onEdge?.(checkEdges({ offset: lastOffset.current }));
}
}, [checkActionType, checkEdges, onEdge]);
React8.useEffect(() => {
if (checkActionType(["release", "navigate", "correction", "wheelSnap"])) {
onCallbacks();
}
}, [currentIndex]);
const handleOnSpringRelease = React8.useCallback(
(clampedReleaseOffset) => {
if (checkActionType(["release", "navigate", "ref", "wheelSnap"])) {
lastOffset.current = clampedReleaseOffset;
if (itemDimensionMode === "static") {
index.current = clampIdx(
getRelativeIndex({ offset: lastOffset.current })
);
} else {
index.current = getCurrentDynamicIndex(
lastOffset.current,
ranges,
lastValidDirection.current,
direction.current,
clampOffset,
rangeOffsetPosition
);
}
setCurrentIndex(index.current);
if (loadingType === "lazy") {
reRender(index.current);
}
}
},
[
checkActionType,
clampIdx,
clampOffset,
getRelativeIndex,
itemDimensionMode,
loadingType,
rangeOffsetPosition,
ranges,
setCurrentIndex
]
);
const spring = React8.useCallback(
({ offset, immediate, onRest }) => {
const clampedReleaseOffset = clampReleaseOffset(offset);
OffsetX.start({
to: checkActionType(["drag", "correction"]) ? offset : clampedReleaseOffset,
immediate: immediate || checkActionType(["drag", "wheel"]),
onStart: () => {
handleOnSpringStart();
},
onRest: (x) => {
onRest?.(x);
},
config: springConfigByActionType[actionType.current]
});
handleOnSpringRelease(clampedReleaseOffset);
},
[
clampReleaseOffset,
OffsetX,
checkActionType,
handleOnSpringRelease,
handleOnSpringStart
]
);
const springIt = React8.useCallback(
({ offset, immediate, actionType: type, onRest }) => {
setActionType(type);
spring({ offset, immediate, onRest });
},
[spring]
);
const getCurrentIndexByOffset = React8.useCallback(
(offset) => {
let finalIndex = 0;
const neutralIndex = offset / wrapperWidth * dataLength;
const left = Math.ceil(neutralIndex);
const right = Math.floor(neutralIndex);
if (!snap) {
return right;
}
switch (direction.current) {
case "left":
finalIndex = left;
break;
case "right":
finalIndex = right;
break;
default:
if (lastValidDirection.current === "left") {
finalIndex = left;
} else if (lastValidDirection.current === "right") {
finalIndex = right;
}
break;
}
return finalIndex;
},
[dataLength, snap, wrapperWidth]
);
const nextIndexByDirection = (index2, direction2) => {
if (direction2 === "next") {
return index2 + 1;
} else if (direction2 === "prev") {
return index2 - 1;
}
return index2;
};
const navigateByDirection = React8.useCallback(
(direction2, immediate, actionType2 = "navigate") => {
let targetOffset = lastOffset.current;
if (itemDimensionMode === "static") {
const currentIndex2 = getCurrentIndex({ offset: OffsetX.get() });
const nextIndex = nextIndexByDirection(currentIndex2, direction2);
targetOffset = -nextIndex * itemWidth;
} else {
if (currentIndex !== void 0) {
const nextIndex = clampIdx(
nextIndexByDirection(currentIndex, direction2)
);
targetOffset = -ranges[nextIndex].range[rangeOffsetPosition];
}
}
springIt({
offset: targetOffset,
actionType: actionType2,
immediate
});
},
[
OffsetX,
clampIdx,
currentIndex,
getCurrentIndex,
itemDimensionMode,
itemWidth,
rangeOffsetPosition,
ranges,
springIt
]
);
const drag = React8.useCallback(
(x, actionType2) => {
const offset = infinite ? x : rubberband(x);
if (Platform.is("web")) {
onEdge?.(checkEdges({ offset }));
}
springIt({
offset,
actionType: actionType2
});
},
[checkEdges, infinite, onEdge, rubberband, springIt]
);
const withSnap = React8.useCallback(
({ offset }) => {
if (itemDimensionMode === "static") {
const page = getCurrentIndexByOffset(-offset);
const finalOffset = -page * itemWidth;
return finalOffset;
} else {
const nextDynamicOffset = getNextDynamicOffset({
offsetX: offset,
ranges,
lastValidDirection: lastValidDirection.current,
direction: direction.current,
clampOffset,
rangeOffsetPosition
});
return nextDynamicOffset;
}
},
[
clampOffset,
getCurrentIndexByOffset,
itemDimensionMode,
itemWidth,
rangeOffsetPosition,
ranges
]
);
const withMomentum = React8.useCallback(
({ offset, v }) => {
const multiplier = -(1 + momentumMultiplier);
const baseVelocity = -Math.abs(v);
const velocity = direction.current === "left" ? -(baseVelocity * multiplier) : direction.current === "right" ? baseVelocity * multiplier : 0;
const momentumOffset = offset + velocity;
return momentumOffset;
},
[momentumMultiplier]
);
const release = React8.useCallback(
({ offset, velocity: v }) => {
let offsetX = 0;
isDragging.current = false;
if (snap) {
if (isIntentionalDrag.current) {
offsetX = withSnap({ offset });
} else {
springIt({
offset: lastOffset.current,
actionType: "correction"
});
return;
}
} else {
offsetX = withMomentum({ offset, v });
}
springIt({
offset: offsetX,
actionType: "release"
});
},
[snap, springIt, withMomentum, withSnap]
);
const navigateByIndex = React8.useCallback(
(idx, immediate, actionType2 = "navigate", alignCentered = false) => {
const nextIndex = clampIdx(idx);
let targetOffset = lastOffset.current;
let currentItemWidth = itemWidth;
if (itemDimensionMode === "static") {
targetOffset = getCurrentOffset({ index: nextIndex });
} else {
if (ranges.length) {
currentItemWidth = ranges[nextIndex].width;
targetOffset = -ranges[nextIndex].range[rangeOffsetPosition];
}
}
if (alignCentered && !centered) {
targetOffset = targetOffset + container.width / 2 - currentItemWidth / 2;
}
springIt({
offset: targetOffset,
actionType: actionType2,
immediate
});
},
[
centered,
clampIdx,
container.width,
getCurrentOffset,
itemDimensionMode,
itemWidth,
rangeOffsetPosition,
ranges,
springIt
]
);
const navigate = React8.useCallback(
({
index: index2,
direction: direction2,
immediate,
actionType: actionType2 = "navigate",
alignCentered
}) => {
if (!isReady) {
return;
}
if (index2 !== void 0) {
navigateByIndex(index2, immediate, actionType2, alignCentered);
} else if (direction2) {
navigateByDirection(direction2, immediate, actionType2);
}
},
[isReady, navigateByIndex, navigateByDirection]
);
const initialNavigation = React8.useCallback(() => {
if (initialIndex !== 0) {
const alignCentered = typeof initialIndex === "object" ? initialIndex.centered : void 0;
navigate({ index: currentIndex, immediate: true, alignCentered });
}
}, [currentIndex, initialIndex, navigate]);
const move = React8.useCallback(
(offset) => {
if (!isReady) {
return;
}
springIt({
offset: OffsetX.get() + offset,
actionType: "navigate"
});
},
[OffsetX, isReady, springIt]
);
const goTo = React8.useCallback(
({
index: index2,
animated: animated2 = true,
centered: centered2
}) => {
if (!isReady) {
return;
}
navigateByIndex(index2, !animated2, "ref", centered2);
},
[isReady, navigateByIndex]
);
const getOffset = React8.useCallback(
({ current, target }) => {
if (Math.abs(target - current) >= dataLength / 2) {
const off = current > dataLength / 2 ? dataLength : -dataLength;
return off + (target - current);
}
return target - current;
},
[dataLength]
);
const handlePressToSlide = React8.useCallback(
(_index) => {
if (!pressToSlide || isDragging.current) {
return;
}
if (!OffsetX.isAnimating) {
const res = getOffset({ target: _index, current: currentIndex });
move(-(itemWidth * res));
}
},
[
OffsetX.isAnimating,
currentIndex,
getOffset,
itemWidth,
move,
pressToSlide
]
);
const handleOnItemPress = React8.useCallback(
(idx) => {
if (currentIndex !== void 0) {
handlePressToSlide(idx);
onItemPress?.({ currentIndex, pressedItemIndex: idx });
}
},
[currentIndex, handlePressToSlide, onItemPress]
);
React8.useEffect(() => {
if (isReady) {
initialNavigation();
defer2(() => {
onReady?.(true);
});
if (shouldAnimatedStartup) {
Opacity.start({
to: 1,
delay: loadingTime,
immediate: !animateStartup
});
}
}
}, [isReady]);
React8.useEffect(() => {
const { end } = checkEdges({ offset: OffsetX.get() });
if (end && isReady) {
springIt({
offset: clampOffset.MAX,
actionType: "release"
});
}
}, [clampOffset.MAX]);
React8.useEffect(() => {
if (!isFirstRender) {
onEdges?.(checkEdges({ offset: OffsetX.get() }));
}
}, [screenWidth, clampOffset.MAX]);
React8.useEffect(() => {
onEdges?.(checkEdges({ offset: OffsetX.get() }));
}, []);
React8.useImperativeHandle(
instanceRef,
() => ({
reinitialize: reInit,
next: () => navigate({ direction: "next" }),
previous: () => navigate({ direction: "prev" }),
goTo,
move
})
);
return {
handlers: {
onDrag: drag,
onRelease: release,
onItemPress: handleOnItemPress,
navigate
},
state: {
container,
centered
},
signals: {
direction,
isDragging,
isIntentionalDrag,
lastOffset,
lastValidDirection,
actionType
},
containerRef,
Opacity
};
};
// packages/utils/src/utilities/cssToNativeStyle.ts
import transform from "css-to-react-native";
import { toString } from "lodash";
// packages/utils/src/context/provider.tsx
var useProducer = (initialData) => {
return React9.useReducer(
produce((draft, action) => {
switch (action.type) {
case "INIT" /* INIT */: {
return action.payload;
}
case "RE_INIT" /* RE_INIT */: {
if (draft.itemDimensionMode === "dynamic") {
draft.isReady = false;
}
draft.initId = action.payload.initId;
break;
}
case "SET_CONTAINER_DIMENSIONS" /* SET_CONTAINER_DIMENSIONS */: {
const { width, height } = action.payload;
if (height) {
draft.container.height = height;
}
if (width) {
draft.container.width = width;
if (draft.itemDimensionMode === "static") {
draft.isReady = true;
}
}
break;
}
case "SET_WRAPPER_WIDTH" /* SET_WRAPPER_WIDTH */: {
const {
dataLength,
itemDimensions: { width: itemWidth = 0 },
itemDimensionMode
} = draft;
const payloadWrapperWidth = action.payload;
const nextWrapperWidth = itemDimensionMode === "static" ? dataLength * itemWidth : payloadWrapperWidth;
draft.wrapperWidth = nextWrapperWidth;
break;
}
case "SET_ITEM_DIMENSION_MAP" /* SET_ITEM_DIMENSION_MAP */: {
draft.itemDimensionMap = action.payload;
if (action.payload.length && draft.ranges.length) {
draft.isReady = true;
}
break;
}
case "SET_RANGES" /* SET_RANGES */: {
draft.ranges = action.payload;
if (action.payload.length && draft.itemDimensionMap.length) {
draft.isReady = true;
}
break;
}
case "SET_IS_READY" /* SET_IS_READY */: {
if (draft.isReady !== action.payload) {
draft.isReady = action.payload;
}
break;
}
case "SET_CURRENT_INDEX" /* SET_CURRENT_INDEX */: {
if (draft.currentIndex !== action.payload) {
draft.currentIndex = action.payload;
}
break;
}
default: {
return nothing;
}
}
}),
initialData
);
};
var dataContext = React9.createContext(
{}
);
function DataProvider({ props, children }) {
const isFirstRender = useIsFirstRender();
const [state, dispatch] = useProducer(initializeContextData(props));
const OffsetX = useSpringValue(0, {
config: baseSpringConfig
});
const actions = React9.useMemo(
() => ({
init: (payload) => dispatch({ type: "INIT" /* INIT */, payload }),
reInit: () => dispatch({
type: "RE_INIT" /* RE_INIT */,
payload: { initId: uniqueId2("init-") }
}),
setContainerDimensions: (payload) => dispatch({ type: "SET_CONTAINER_DIMENSIONS" /* SET_CONTAINER_DIMENSIONS */, payload }),
setWrapperWidth: (payload) => dispatch({ type: "SET_WRAPPER_WIDTH" /* SET_WRAPPER_WIDTH */, payload }),
setItemDimensionMap: (payload) => dispatch({ type: "SET_ITEM_DIMENSION_MAP" /* SET_ITEM_DIMENSION_MAP */, payload }),
setRanges: (payload) => dispatch({ type: "SET_RANGES" /* SET_RANGES */, payload }),
setIsReady: (payload) => dispatch({ type: "SET_IS_READY" /* SET_IS_READY */, payload }),
setCurrentIndex: (payload) => dispatch({ type: "SET_CURRENT_INDEX" /* SET_CURRENT_INDEX */, payload })
}),
[dispatch]
);
React9.useEffect(() => {
if (!isFirstRender) {
actions.init({
...initializeContextData(props),
currentIndex: state.currentIndex
});
}
}, [
props.data,
props.itemHeight,
props.itemWidth,
props.fullWidthItem,
props.infinite,
props.visibleItems,
props.containerWidth,
props.containerHeight,
props.interpolators?.opacity,
props.interpolators?.scale,
props.centered,
props.momentumMultiplier,
props.intentionalDragThreshold,
// eslint-disable-next-line react-hooks/exhaustive-deps
...props.listener || []
]);
const contextHandlers = React9.useMemo(
() => ({
state: {
...processContextData(state),
OffsetX
},
actions,
dispatch
}),
[OffsetX, actions, dispatch, state]
);
return /* @__PURE__ */ React9.createElement(dataContext.Provider, { value: contextHandlers }, children);
}
// packages/utils/src/context/hooks.ts
function useDataContext() {
const { state, actions, dispatch } = React10.useContext(
dataContext
);
return { state, actions, dispatch };
}
// packages/utils/src/context/index.ts
var Context = {
...utils_exports,
...hooks_exports,
...provider_exports
};
// packages/utils/src/components/GestureContainer/web/GestureContainer.tsx
var GestureContainerComponent = ({
style,
styles,
direction,
lastValidDirection,
lastOffset,
isIntentionalDrag,
isDragging,
useWheel,
snap,
intentionalDragThreshold,
onDrag,
onRelease,
navigate,
children
}, ref) => {
const {
state: { OffsetX }
} = Context.useDataContext();
const internalRef = React11.useRef(null);
const refs = mergeRefs([ref, internalRef]);
const lethargy = React11.useMemo(
() => new Lethargy({
sensitivity: 2,
inertiaDecay: 20,
delay: 100,
highVelocity: 100
}),
[]
);
const handleGesture = React11.useCallback(
({ active, mx, dirX, vx, actionType }) => {
if (mx === 0) {
onRelease({ offset: lastOffset.current, velocity: vx * 100 });
return;
}
const dir = dirX < 0 ? "left" : dirX > 0 ? "right" : false;
direction.current = dir;
if (dir) {
lastValidDirection.current = dir;
}
const offset = lastOffset.current + mx;
isIntentionalDrag.current = Math.abs(mx) >= intentionalDragThreshold;
isDragging.current = Math.abs(mx) !== 0;
if (active) {
onDrag(offset, actionType);
} else {
onRelease({ offset, velocity: vx * 100 });
}
},
[
direction,
intentionalDragThreshold,
isDragging,
isIntentionalDrag,
lastOffset,
lastValidDirection,
onDrag,
onRelease
]
);
const handleOnPressStart = () => {
if (!snap && OffsetX.isAnimating && OffsetX.get() !== lastOffset.current) {
lastOffset.current = OffsetX.get();
OffsetX.stop();
}
};
const handleOnWheel = React11.useCallback(
throttle2(
(dir) => {
const direction2 = dir < 0 ? "prev" : dir > 0 ? "next" : false;
if (direction2) {
navigate({ direction: direction2, actionType: "wheelSnap" });
}
},
200,
{ leading: true, trailing: false }
),
[navigate]
);
useGesture(
{
onTouchStart: handleOnPressStart,
onMouseDown: handleOnPressStart,
onDrag: ({
active,
movement: [mx],
direction: [dirX],
velocity: [vx]
}) => {
handleGesture({
active,
mx,
dirX,
vx,
actionType: "drag"
});
},
onWheel: ({
event,
active,
movement: [mx, my],
direction: [dirX, dirY]
}) => {
const move = -mx || -my;
const dir = dirX || dirY;
if (snap) {
if (lethargy.check(event)) {
handleOnWheel(dir);
}
} else {
handleGesture({
active,
mx: move,
dirX: dir,
vx: 0,
actionType: "wheel"
});
}
}
},
{
target: internalRef,
wheel: {
enabled: !!useWheel,
preventDefault: true,
eventOptions: { passive: false }
},
drag: { filterTaps: true, axis: "x" }
}
);
return /* @__PURE__ */ React11.createElement(
AnimatedBox,
{
ref: refs,
willMeasure: true,
style,
styles: {
display: "flex",
position: "relative",
flexDirection: "row",
...styles,
touchAction: "pan-y"
}
},
children
);
};
var GestureContainer = React11.forwardRef(GestureContainerComponent);
// packages/utils/src/components/LazyLoad/LazyLoad.tsx
import React12 from "react";
var LazyLoad = ({ render, children }) => {
if (render) {
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, children);
}
return /* @__PURE__ */ React12.createElement(React12.Fragment, null);
};
// packages/react-slip-and-slide/src/ReactSlipAndSlide.tsx
import React16 from "react";
// packages/react-slip-and-slide/src/Engine.tsx
import React15 from "react";
// packages/react-slip-and-slide/src/Item.tsx
import React13 from "react";
function ItemBaseComponent({ index, item, renderItem, onPress }, ref) {
const {
state: {
itemDimensions,
engineMode,
loadingType,
itemDimensionMode,
isReady
}
} = Context.useDataContext();
const isLazy = loadingType === "lazy";
const Opacity = useSpringValue(isLazy ? 0 : 1, {
config: {
tension: 220,
friction: 32,
mass: 1
}
});
React13.useEffect(() => {
if (isLazy) {
Opacity.start({
to: 1
});
}
}, [isLazy]);
const itemStyles = React13.useRef({
display: "flex",
justifyContent: "center",
alignItems: "center"
});
if (engineMode === "multi") {
itemStyles.current = {
...itemStyles.current,
position: isReady ? "absolute" : "static",
flexShrink: 0,
...elementDimensionStyles(itemDimensions)
};
}
if (itemDimensionMode === "static") {
itemStyles.current = {
...itemStyles.current,
...elementDimensionStyles(itemDimensions)
};
}
const { translateX, scale: scale2, opacity } = useInterpolation({ index });
const memoRenderItem = React13.useMemo(() => {
return renderItem({ item, index });
}, [index, item, renderItem]);
return /* @__PURE__ */ React13.createElement(
AnimatedBox,
{
willMeasure: true,
ref,
onPress,
web: {
onDragStart: (e) => e.preventDefault()
},
style: {
transform: [
{
translateX: engineMode === "multi" ? translateX : 0
},
{
scale: scale2
}
],
opacity
},
styles: itemStyles.current
},
/* @__PURE__ */ React13.createElement(LazyLayout, { isLazy, itemDimensions }, memoRenderItem)
);
}
var LazyLayout = ({
isLazy,
itemDimensions,
children
}) => {
const Opacity = useSpringValue(isLazy ? 0 : 1, {
config: {
tension: 220,
friction: 32,
mass: 1
}
});
React13.useEffect(() => {
if (isLazy) {
Opacity.start({
to: 1
});
}
}, [isLazy]);
if (isLazy) {
return /* @__PURE__ */ React13.createElement(
AnimatedBox,
{
styles: {
display: "flex",
alignItems: "center",
...elementDimensionStyles(itemDimensions),
width: "100%"
},
style: {
opacity: Opacity
}
},
children
);
}
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, children);
};
var ItemBase = React13.forwardRef(ItemBaseComponent);
// packages/react-slip-and-slide/src/LayoutManager.tsx
import React14 from "react";
var LayoutManager = ({
children
}) => {
const {
state: { itemDimensions, itemDimensionMode, engineMode, centered, OffsetX }
} = Context.useDataContext();
if (engineMode === "single") {
const dynamicCenteredCorrectionStyles = {
transform: itemDimensionMode === "dynamic" && centered ? `translateX(${itemDimensions.width / 2}px)` : void 0
};
return /* @__PURE__ */ React14.createElement(Box, { styles: dynamicCenteredCorrectionStyles }, /* @__PURE__ */ React14.createElement(
AnimatedBox,
{
style: {
transform: [{ translateX: OffsetX }]
},
styles: {
display: "flex",
flexDirection: "row",
alignItems: "center",
...elementDimensionStyles(itemDimensions)
}
},
children
));
}
return /* @__PURE__ */ React14.createElement(React14.Fragment, null, children);
};
// packages/react-slip-and-slide/src/Engine.tsx
var Engine = ({
onItemPress,
renderItem
}) => {
const {
state: {
data,
dataLength,
itemDimensions,
loadingType,
visibleItems,
OffsetX
}
} = Context.useDataContext();
const { itemRefs } = useDynamicDimension();
const shouldRender = React15.useCallback(
(i) => {
if (loadingType === "eager") {
return true;
}
return isInRange(i, {
dataLength,
viewSize: itemDimensions.width,
visibleItems: visibleItems || Math.round(dataLength / 2),
offsetX: OffsetX.get()
});
},
[OffsetX, dataLength, itemDimensions.width, loadingType, visibleItems]
);
return /* @__PURE__ */ React15.createElement(LayoutManager, null, data.map((item, index) => /* @__PURE__ */ React15.createElement(LazyLoad, { key: index, render: shouldRender(index) }, /* @__PURE__ */ React15.createElement(
ItemBase,
{
ref: itemRefs[index],
index,
item,
renderItem,
onPress: () => onItemPress(index)
}
))));
};
// packages/react-slip-and-slide/src/ReactSlipAndSlide.tsx
function ReactSlipAndSlideComponent({
snap,
containerWidth,
pressToSlide,
animateStartup = true,
rubberbandElasticity = 0.1,
overflowHidden = true,
intentionalDragThreshold = 20,
useWheel,
initialIndex,
loadingTime,
onChange,
onEdges,
onReady,
onItemPress,
renderItem
}, ref) {
const { handlers, state, signals, containerRef, Opacity } = useEngine({
snap,
containerWidth,
pressToSlide,
animateStartup,
rubberbandElasticity,
instanceRef: ref,
initialIndex,
loadingTime,
onChange,
onEdges,
onReady,
onItemPress
});
const gestureContainerStyles = {
justifyContent: state.centered ? "center" : "flex-start",
...elementDimensionStyles(state.container),
width: containerWidth || "100%",
minWidth: containerWidth || "100%",
overflow: overflowHidden ? "hidden" : void 0
};
return /* @__PURE__ */ React16.createElement(
GestureContainer,
{
ref: containerRef,
direction: signals.direction,
isDragging: signals.isDragging,
isIntentionalDrag: signals.isIntentionalDrag,
lastOffset: signals.lastOffset,
lastValidDirection: signals.lastValidDirection,
useWheel,
style: { opacity: Opacity },
styles: gestureContainerStyles,
snap,
intentionalDragThreshold,
onDrag: handlers.onDrag,
onRelease: handlers.onRelease,
navigate: handlers.navigate
},
/* @__PURE__ */ React16.createElement(Engine, { onItemPress: handlers.onItemPress, renderItem })
);
}
var ForwardReactSlipAndSlideRef = React16.forwardRef(
ReactSlipAndSlideComponent
);
function ReactSlipAndSlideWithContext(props, ref) {
return /* @__PURE__ */ React16.createElement(
Context.DataProvider,
{
props
},
props.childrenPosition === "above" && props.child