@studiometa/js-toolkit
Version:
A set of useful little bits of JavaScript to boost your project! 🚀
179 lines (178 loc) • 5.49 kB
JavaScript
import { useScroll } from "../../services/index.js";
import { withMountWhenInView } from "../withMountWhenInView.js";
import {
damp,
clamp,
clamp01,
getOffsetSizes,
isFunction,
domScheduler as scheduler
} from "../../utils/index.js";
import { normalizeOffset, getEdges } from "./utils.js";
function updateProgress(props, axis, progressKey, currentKey) {
props[progressKey][axis] = props.start[axis] === props.end[axis] ? 0 : clamp01(
(props[currentKey][axis] - props.start[axis]) / (props.end[axis] - props.start[axis])
);
}
function updateProps(props, dampFactor, dampPrecision, axis = "x") {
props.current[axis] = clamp(useScroll().props()[axis], props.start[axis], props.end[axis]);
props.dampedCurrent[axis] = damp(
props.current[axis],
props.dampedCurrent[axis],
dampFactor,
dampPrecision
);
updateProgress(props, axis, "progress", "current");
updateProgress(props, axis, "dampedProgress", "dampedCurrent");
}
function withScrolledInView(BaseClass, options = {}) {
class WithScrolledInView extends withMountWhenInView(
BaseClass,
options
) {
/**
* Config.
*/
static config = {
...BaseClass.config,
emits: ["scrolledInView"],
options: {
dampFactor: {
type: Number,
default: 0.1
},
dampPrecision: {
type: Number,
default: 1e-3
},
offset: {
type: String,
default: "start end / end start"
}
}
};
__props = {
start: {
x: 0,
y: 0
},
end: {
x: 0,
y: 0
},
current: {
x: 0,
y: 0
},
dampedCurrent: {
x: 0,
y: 0
},
progress: {
x: 0,
y: 0
},
dampedProgress: {
x: 0,
y: 0
}
};
shouldEvaluateProps = true;
get props() {
if (this.shouldEvaluateProps) {
this.shouldEvaluateProps = false;
const targetSizes = options.useOffsetSizes ? getOffsetSizes(this.$el) : this.$el.getBoundingClientRect();
targetSizes.y += window.scrollY;
targetSizes.x += window.scrollX;
const containerSizes = {
x: 0,
y: 0,
height: window.innerHeight,
width: window.innerWidth
};
const offset = normalizeOffset(this.$options.offset);
const [yStart, yEnd] = getEdges("y", targetSizes, containerSizes, offset);
const yCurrent = clamp(window.scrollY, yStart, yEnd);
const yProgress = yStart === yEnd ? 0 : clamp01((yCurrent - yStart) / (yEnd - yStart));
const [xStart, xEnd] = getEdges("x", targetSizes, containerSizes, offset);
const xCurrent = clamp(window.scrollX, xStart, xEnd);
const xProgress = xStart === xEnd ? 0 : clamp01((xCurrent - xStart) / (xEnd - xStart));
this.__props.start.x = xStart;
this.__props.start.y = yStart;
this.__props.end.x = xEnd;
this.__props.end.y = yEnd;
this.__props.current.x = xCurrent;
this.__props.current.y = yCurrent;
this.__props.dampedCurrent.x = xCurrent;
this.__props.dampedCurrent.y = yCurrent;
this.__props.progress.x = xProgress;
this.__props.progress.y = yProgress;
this.__props.dampedProgress.x = xProgress;
this.__props.dampedProgress.y = yProgress;
}
return this.__props;
}
/**
* Bind listeners.
*/
constructor(element) {
super(element);
const render = () => {
scheduler.read(() => {
const renderFn = this.__callMethod("scrolledInView", this.props);
if (isFunction(renderFn)) {
scheduler.write(() => {
renderFn(this.__props);
});
}
});
};
const delegate = {
handleEvent(event) {
delegate[event.type](event.detail[0]);
},
resized: () => {
this.shouldEvaluateProps = true;
render();
},
scrolled: (props) => {
if (props.changed.y || props.changed.x) {
this.$services.enable("ticked");
}
},
mounted: () => render(),
ticked: () => {
const { dampFactor, dampPrecision } = this.$options;
updateProps(this.__props, dampFactor, dampPrecision, "x");
updateProps(this.__props, dampFactor, dampPrecision, "y");
if (this.__props.dampedCurrent.x === this.__props.current.x && this.__props.dampedCurrent.y === this.__props.current.y) {
this.$services.disable("ticked");
}
render();
}
};
this.$on("before-mounted", () => {
this.$on("mounted", delegate);
this.$on("resized", delegate);
this.$on("scrolled", delegate);
this.$on("ticked", delegate);
});
this.$on("destroyed", () => {
this.$off("mounted", delegate);
this.$off("resized", delegate);
this.$off("scrolled", delegate);
this.$off("ticked", delegate);
this.__props.dampedCurrent.x = this.__props.current.x;
this.__props.dampedCurrent.y = this.__props.current.y;
this.__props.dampedProgress.x = this.__props.progress.x;
this.__props.dampedProgress.y = this.__props.progress.y;
render();
});
}
}
return WithScrolledInView;
}
export {
withScrolledInView
};
//# sourceMappingURL=withScrolledInView.js.map