lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
166 lines • 8.02 kB
JavaScript
;
// ThreeDScrollTrigger.tsx
"use client";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrap = void 0;
exports.ThreeDScrollTriggerContainer = ThreeDScrollTriggerContainer;
exports.ThreeDScrollTriggerRow = ThreeDScrollTriggerRow;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importStar(require("react"));
const framer_motion_1 = require("framer-motion");
const utils_1 = require("@/components/lib/utils");
/* -------------------------
Utility: wrap (unchanged)
------------------------- */
const wrap = (min, max, v) => {
const rangeSize = max - min;
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};
exports.wrap = wrap;
/* -----------------------------------
Context to share velocity between rows
----------------------------------- */
const ThreeDScrollTriggerContext = react_1.default.createContext(null);
/* --------------------------
Container that provides velocity
-------------------------- */
function ThreeDScrollTriggerContainer({ children, className, ...props }) {
const { scrollY } = (0, framer_motion_1.useScroll)();
const scrollVelocity = (0, framer_motion_1.useVelocity)(scrollY);
const smoothVelocity = (0, framer_motion_1.useSpring)(scrollVelocity, {
damping: 50,
stiffness: 400,
});
// map to a bounded factor [-5...5] with smoother behaviour
const velocityFactor = (0, framer_motion_1.useTransform)(smoothVelocity, (v) => {
const sign = v < 0 ? -1 : 1;
const magnitude = Math.min(5, (Math.abs(v) / 1000) * 5);
return sign * magnitude;
});
return ((0, jsx_runtime_1.jsx)(ThreeDScrollTriggerContext.Provider, { value: velocityFactor, children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("relative w-full", className), ...props, children: children }) }));
}
/* --------------------------
Row entry that chooses shared or local velocity
-------------------------- */
function ThreeDScrollTriggerRow(props) {
const sharedVelocityFactor = (0, react_1.useContext)(ThreeDScrollTriggerContext);
if (sharedVelocityFactor) {
return ((0, jsx_runtime_1.jsx)(ThreeDScrollTriggerRowImpl, { ...props, velocityFactor: sharedVelocityFactor }));
}
return (0, jsx_runtime_1.jsx)(ThreeDScrollTriggerRowLocal, { ...props });
}
function ThreeDScrollTriggerRowImpl({ children, baseVelocity = 5, direction = 1, className, velocityFactor, ...props }) {
const containerRef = (0, react_1.useRef)(null);
const [numCopies, setNumCopies] = (0, react_1.useState)(3);
const x = (0, framer_motion_1.useMotionValue)(0);
const prevTimeRef = (0, react_1.useRef)(null);
const unitWidthRef = (0, react_1.useRef)(0);
const baseXRef = (0, react_1.useRef)(0);
// Memoized children
const childrenArray = (0, react_1.useMemo)(() => react_1.default.Children.toArray(children), [children]);
const BlockContent = (0, react_1.useMemo)(() => {
return ((0, jsx_runtime_1.jsx)("div", { className: "inline-flex shrink-0", style: { contain: "paint" }, children: childrenArray }));
}, [childrenArray]);
// Measure block width
(0, react_1.useEffect)(() => {
const container = containerRef.current;
if (!container)
return;
const block = container.querySelector(".threed-scroll-trigger-block");
if (block) {
unitWidthRef.current = block.scrollWidth;
// keep just enough to cover the viewport + 1
const containerWidth = container.offsetWidth;
const needed = Math.max(3, Math.ceil(containerWidth / unitWidthRef.current) + 2);
setNumCopies(needed);
}
}, [childrenArray]);
// Optimize: Check if container is in view
const isInView = (0, framer_motion_1.useInView)(containerRef, { margin: "20%" });
// Animation loop
(0, framer_motion_1.useAnimationFrame)((time) => {
if (!isInView)
return;
if (prevTimeRef.current == null)
prevTimeRef.current = time;
const dt = Math.max(0, (time - prevTimeRef.current) / 1000);
prevTimeRef.current = time;
const unitWidth = unitWidthRef.current;
if (unitWidth <= 0)
return;
const velocity = velocityFactor.get();
const speedMultiplier = Math.min(5, Math.abs(velocity));
const scrollDirection = velocity >= 0 ? 1 : -1;
const currentDirection = direction * scrollDirection;
const pixelsPerSecond = (unitWidth * baseVelocity) / 100;
const moveBy = currentDirection * pixelsPerSecond * (1 + speedMultiplier) * dt;
const newX = baseXRef.current + moveBy;
// ✅ FIXED: Proper wrapping in both directions
// When moving right (positive newX), wrap back
if (newX >= unitWidth) {
baseXRef.current = newX % unitWidth;
}
// When moving left (negative newX), wrap forward
else if (newX <= 0) {
baseXRef.current = unitWidth + (newX % unitWidth);
}
else {
baseXRef.current = newX;
}
x.set(baseXRef.current);
});
const xTransform = (0, framer_motion_1.useTransform)(x, (v) => `translate3d(${-v}px,0,0)`);
return ((0, jsx_runtime_1.jsx)("div", { ref: containerRef, className: (0, utils_1.cn)("w-full overflow-hidden whitespace-nowrap", className), ...props, children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "inline-flex will-change-transform transform-gpu", style: { transform: xTransform }, children: Array.from({ length: numCopies }).map((_, i) => ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("inline-flex shrink-0", i === 0 ? "threed-scroll-trigger-block" : ""), children: BlockContent }, i))) }) }));
}
/* --------------------------
Local row (if no shared velocity)
-------------------------- */
function ThreeDScrollTriggerRowLocal(props) {
const { scrollY } = (0, framer_motion_1.useScroll)();
const localVelocity = (0, framer_motion_1.useVelocity)(scrollY);
const localSmoothVelocity = (0, framer_motion_1.useSpring)(localVelocity, {
damping: 50,
stiffness: 400,
});
const localVelocityFactor = (0, framer_motion_1.useTransform)(localSmoothVelocity, (v) => {
const sign = v < 0 ? -1 : 1;
const magnitude = Math.min(5, (Math.abs(v) / 1000) * 5);
return sign * magnitude;
});
return ((0, jsx_runtime_1.jsx)(ThreeDScrollTriggerRowImpl, { ...props, velocityFactor: localVelocityFactor }));
}
exports.default = ThreeDScrollTriggerRow;
//# sourceMappingURL=3d-scroll-trigger.js.map