UNPKG

@studiometa/js-toolkit

Version:

A set of useful little bits of JavaScript to boost your project! 🚀

182 lines (181 loc) • 5.47 kB
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( axis === "x" ? window.scrollX : window.scrollY, 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