motion-v
Version:
<p align="center"> <img width="100" height="100" alt="Motion logo" src="https://user-images.githubusercontent.com/7850794/164965523-3eced4c4-6020-467e-acde-f11b7900ad62.png" /> </p> <h1 align="center">Motion for Vue</h1>
61 lines (60 loc) • 1.87 kB
JavaScript
import { Feature } from "../../feature.mjs";
import { inView } from "../../../external/.pnpm/framer-motion@12.5.0/external/framer-motion/dist/es/render/dom/viewport/index.mjs";
import { frame } from "../../../external/.pnpm/motion-dom@12.5.0/external/motion-dom/dist/es/frameloop/frame.mjs";
import "../../../external/.pnpm/motion-utils@12.5.0/external/motion-utils/dist/es/errors.mjs";
function handleHoverEvent(state, entry, lifecycle) {
const props = state.options;
if (props.whileInView) {
state.setActive("whileInView", lifecycle === "Enter");
}
const eventName = `onViewport${lifecycle}`;
const callback = props[eventName];
if (callback) {
frame.postRender(() => callback(entry));
}
}
class InViewGesture extends Feature {
isActive() {
return Boolean(this.state.options.whileInView);
}
constructor(state) {
super(state);
}
startObserver() {
const element = this.state.element;
if (!element || !this.isActive())
return;
this.unmount();
const { once, ...viewOptions } = this.state.options.inViewOptions || {};
this.unmount = inView(
element,
(_, entry) => {
handleHoverEvent(this.state, entry, "Enter");
if (!once) {
return (endEvent) => {
handleHoverEvent(this.state, entry, "Leave");
};
}
},
viewOptions
);
}
mount() {
this.startObserver();
}
update() {
const { props, prevProps } = this.state.visualElement;
const hasOptionsChanged = ["amount", "margin", "root"].some(
hasViewportOptionChanged(props, prevProps)
);
if (hasOptionsChanged) {
this.startObserver();
}
}
}
function hasViewportOptionChanged({ inViewOptions = {} }, { inViewOptions: prevViewport = {} } = {}) {
return (name) => inViewOptions[name] !== prevViewport[name];
}
export {
InViewGesture
};