@react-spring/parallax
Version:
```bash yarn add @react-spring/parallax ```
258 lines (255 loc) • 8.79 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) {
__defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
}
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let react = require("react");
react = __toESM(react);
let _react_spring_shared = require("@react-spring/shared");
let _react_spring_web = require("@react-spring/web");
//#region src/index.tsx
const ParentContext = react.createContext(null);
function getScrollType(horizontal) {
return horizontal ? "scrollLeft" : "scrollTop";
}
function mapChildrenRecursive(children, callback) {
const isReactFragment = (node) => {
if (node.type) return node.type === react.Fragment;
return node === react.Fragment;
};
return react.Children.map(children, (child) => isReactFragment(child) ? mapChildrenRecursive(child.props.children, callback) : callback(child));
}
const START_TRANSLATE_3D = "translate3d(0px,0px,0px)";
const START_TRANSLATE = "translate(0px,0px)";
const ParallaxLayer = react.memo(react.forwardRef(({ horizontal, factor = 1, offset = 0, speed = 0, sticky, ...rest }, ref) => {
const parent = (0, react.useContext)(ParentContext);
const ctrl = (0, _react_spring_shared.useMemoOne)(() => {
let translate;
if (sticky) translate = (sticky.start || 0) * parent.space;
else {
const targetScroll = Math.floor(offset) * parent.space;
const distance = parent.space * offset + targetScroll * speed;
translate = -(parent.current * speed) + distance;
}
return new _react_spring_web.Controller({
space: sticky ? parent.space : parent.space * factor,
translate
});
}, []);
const layer = (0, _react_spring_shared.useMemoOne)(() => ({
horizontal: horizontal === void 0 || sticky ? parent.horizontal : horizontal,
sticky: void 0,
isSticky: false,
setPosition(height, scrollTop, immediate = false) {
if (sticky) setSticky(height, scrollTop);
else {
const targetScroll = Math.floor(offset) * height;
const distance = height * offset + targetScroll * speed;
ctrl.start({
translate: -(scrollTop * speed) + distance,
config: parent.config,
immediate
});
}
},
setHeight(height, immediate = false) {
ctrl.start({
space: sticky ? height : height * factor,
config: parent.config,
immediate
});
}
}), []);
(0, _react_spring_shared.useOnce)(() => {
if (sticky) {
const start = sticky.start || 0;
layer.sticky = {
start,
end: sticky.end || start + 1
};
}
});
react.useImperativeHandle(ref, () => layer);
const layerRef = (0, react.useRef)(void 0);
const setSticky = (height, scrollTop) => {
const start = layer.sticky.start * height;
const end = layer.sticky.end * height;
const isSticky = scrollTop >= start && scrollTop <= end;
if (isSticky === layer.isSticky) return;
layer.isSticky = isSticky;
const ref = layerRef.current;
ref.style.position = isSticky ? "sticky" : "absolute";
ctrl.set({ translate: isSticky ? 0 : scrollTop < start ? start : end });
};
(0, _react_spring_shared.useOnce)(() => {
if (parent) {
parent.layers.add(layer);
parent.update();
return () => {
parent.layers.delete(layer);
parent.update();
};
}
});
const translate3d = ctrl.springs.translate.to(layer.horizontal ? (x) => `translate3d(${x}px,0,0)` : (y) => `translate3d(0,${y}px,0)`);
return /* @__PURE__ */ react.createElement(_react_spring_web.a.div, {
...rest,
ref: layerRef,
style: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundSize: "auto",
backgroundRepeat: "no-repeat",
willChange: "transform",
[layer.horizontal ? "height" : "width"]: "100%",
[layer.horizontal ? "width" : "height"]: ctrl.springs.space,
WebkitTransform: translate3d,
msTransform: translate3d,
transform: translate3d,
...rest.style
}
});
}));
const Parallax = react.memo(react.forwardRef((props, ref) => {
const [ready, setReady] = (0, react.useState)(false);
const { pages, innerStyle: _innerStyle, config = _react_spring_web.config.slow, enabled = true, horizontal = false, children, ...rest } = props;
const containerRef = (0, react.useRef)(void 0);
const contentRef = (0, react.useRef)(void 0);
const state = (0, _react_spring_shared.useMemoOne)(() => ({
config,
horizontal,
busy: false,
space: 0,
current: 0,
offset: 0,
controller: new _react_spring_web.Controller({ scroll: 0 }),
layers: /* @__PURE__ */ new Set(),
container: containerRef,
content: contentRef,
update: () => update(),
scrollTo: (offset) => scrollTo(offset),
stop: () => state.controller.stop()
}), []);
(0, react.useEffect)(() => {
state.config = config;
}, [config]);
react.useImperativeHandle(ref, () => state);
const update = () => {
const container = containerRef.current;
if (!container) return;
state.space = container[horizontal ? "clientWidth" : "clientHeight"];
const scrollType = getScrollType(horizontal);
if (enabled) state.current = container[scrollType];
else container[scrollType] = state.current = state.offset * state.space;
const content = contentRef.current;
if (content) {
const sizeProp = horizontal ? "width" : "height";
content.style[sizeProp] = `${state.space * pages}px`;
}
state.layers.forEach((layer) => {
layer.setHeight(state.space, true);
layer.setPosition(state.space, state.current, true);
});
};
const scrollTo = (offset) => {
const container = containerRef.current;
const scrollType = getScrollType(horizontal);
state.offset = offset;
state.controller.set({ scroll: state.current });
state.controller.stop().start({
scroll: offset * state.space,
config,
onChange({ value: { scroll } }) {
container[scrollType] = scroll;
}
});
};
const onScroll = (event) => {
if (!state.busy) {
state.busy = true;
state.current = event.target[getScrollType(horizontal)];
_react_spring_shared.raf.onStart(() => {
state.layers.forEach((layer) => layer.setPosition(state.space, state.current));
state.busy = false;
});
}
};
(0, react.useEffect)(() => state.update());
(0, _react_spring_shared.useOnce)(() => {
setReady(true);
const onResize = () => {
const update = () => state.update();
_react_spring_shared.raf.onFrame(update);
setTimeout(update, 150);
};
window.addEventListener("resize", onResize, false);
return () => window.removeEventListener("resize", onResize, false);
});
const overflow = enabled ? {
overflowY: horizontal ? "hidden" : "scroll",
overflowX: horizontal ? "scroll" : "hidden"
} : {
overflowY: "hidden",
overflowX: "hidden"
};
return /* @__PURE__ */ react.createElement(_react_spring_web.a.div, {
...rest,
ref: containerRef,
onScroll,
onWheel: enabled ? state.stop : void 0,
onTouchStart: enabled ? state.stop : void 0,
style: {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
...overflow,
WebkitOverflowScrolling: "touch",
WebkitTransform: START_TRANSLATE,
msTransform: START_TRANSLATE,
transform: START_TRANSLATE_3D,
...rest.style
}
}, ready && /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_react_spring_web.a.div, {
ref: contentRef,
style: {
overflow: "hidden",
position: "absolute",
[horizontal ? "height" : "width"]: "100%",
[horizontal ? "width" : "height"]: state.space * pages,
WebkitTransform: START_TRANSLATE,
msTransform: START_TRANSLATE,
transform: START_TRANSLATE_3D,
...props.innerStyle
}
}, /* @__PURE__ */ react.createElement(ParentContext.Provider, { value: state }, mapChildrenRecursive(children, (child) => !child.props.sticky && child))), /* @__PURE__ */ react.createElement(ParentContext.Provider, { value: state }, mapChildrenRecursive(children, (child) => child.props.sticky && child))));
}));
//#endregion
exports.Parallax = Parallax;
exports.ParallaxLayer = ParallaxLayer;