UNPKG

vevet

Version:

Vevet is a JavaScript library for creative development that simplifies crafting rich interactions like split text animations, carousels, marquees, preloading, and more.

332 lines 13.8 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; 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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InView = void 0; var Module_1 = require("../../base/Module"); var initVevet_1 = require("../../global/initVevet"); var cn_1 = require("../../internal/cn"); var env_1 = require("../../internal/env"); var noopIfDestroyed_1 = require("../../internal/noopIfDestroyed"); var textDirection_1 = require("../../internal/textDirection"); var math_1 = require("../../utils/math"); var props_1 = require("./props"); __exportStar(require("./types"), exports); /** * InView is a visibility detection utility that leverages the `IntersectionObserver` API to monitor when elements enter or leave the viewport. * It provides customizable options for triggering events, delaying visibility changes, and dynamically adding CSS classes to elements based on their visibility state. * * [Documentation](https://vevetjs.com/docs/InView) * * @group Components */ var InView = /** @class */ (function (_super) { __extends(InView, _super); /** * Initializes the `InView` module. */ function InView(props, onCallbacks) { var _this = _super.call(this, props, onCallbacks) || this; /** Tracks whether this is the first time the elements are being observed. */ _this._isInitialStart = true; /** Stores the elements being observed. */ _this._elements = []; /** Detects if the container is RTL */ _this._isRtl = false; // get direction _this._isRtl = (0, textDirection_1.getTextDirection)(env_1.body) === 'rtl'; _this._setup(); return _this; } /** * Returns default static properties. */ InView.prototype._getStatic = function () { return __assign(__assign({}, _super.prototype._getStatic.call(this)), props_1.STATIC_PROPS); }; /** * Returns default mutable properties. */ InView.prototype._getMutable = function () { return __assign(__assign({}, _super.prototype._getMutable.call(this)), props_1.MUTABLE_PROPS); }; Object.defineProperty(InView.prototype, "isInitialStart", { /** * Indicates whether the observation has started for the first time. */ get: function () { return this._isInitialStart; }, enumerable: false, configurable: true }); Object.defineProperty(InView.prototype, "elements", { /** * Returns all elements currently being observed. */ get: function () { return this._elements; }, enumerable: false, configurable: true }); /** * Handles property mutations and updates observation events accordingly. */ InView.prototype._handleProps = function (props) { _super.prototype._handleProps.call(this, props); this._setup(); }; /** * Configures or reconfigures the view observation events. */ InView.prototype._setup = function () { this._removeViewEvents(); if (this.props.enabled) { this._setViewEvents(); } }; /** * Removes all observation events and disconnects observers. */ InView.prototype._removeViewEvents = function () { var _a, _b; (_a = this._in) === null || _a === void 0 ? void 0 : _a.disconnect(); this._in = undefined; (_b = this._out) === null || _b === void 0 ? void 0 : _b.disconnect(); this._out = undefined; }; /** * Sets up `IntersectionObserver` instances to detect visibility changes. */ InView.prototype._setViewEvents = function () { var _this = this; var _a = this, isInitialStart = _a.isInitialStart, props = _a.props; var rootMargin = isInitialStart ? '0% 0% 0% 0%' : props.rootMargin; this._in = new IntersectionObserver(function (data) { return _this._handleIn(data, isInitialStart); }, { root: null, threshold: 0, rootMargin: rootMargin }); this.elements.forEach(function (element) { var _a; return (_a = _this._in) === null || _a === void 0 ? void 0 : _a.observe(element); }); if (!props.hasOut) { return; } this._out = new IntersectionObserver(function (data) { return _this._handleOut(data); }, { root: null, threshold: 0, rootMargin: '0px 0px 0px 0px', }); this.elements.forEach(function (element) { var _a; return (_a = _this._out) === null || _a === void 0 ? void 0 : _a.observe(element); }); }; /** * Handles elements entering the viewport. */ InView.prototype._handleIn = function (data, isInitialStart) { var _this = this; data.forEach(function (entry) { var element = entry.target; if (!entry.isIntersecting || element.$vevetInViewBool) { return; } element.$vevetInViewBool = true; if (element.$vevetInViewTimeout) { clearTimeout(element.$vevetInViewTimeout); element.$vevetInViewTimeout = undefined; } element.$vevetInViewTimeout = setTimeout(function () { return _this._handleInOut(entry, true, isInitialStart); }, _this._getDelay(element)); if (!_this.props.hasOut) { _this.removeElement(element); } }); if (this._isInitialStart) { this._isInitialStart = false; this._setup(); } }; /** * Handles elements leaving the viewport. */ InView.prototype._handleOut = function (data) { var _this = this; data.forEach(function (entry) { var element = entry.target; if (entry.isIntersecting || !element.$vevetInViewBool) { return; } element.$vevetInViewBool = false; if (element.$vevetInViewTimeout) { clearTimeout(element.$vevetInViewTimeout); element.$vevetInViewTimeout = undefined; } element.$vevetInViewTimeout = setTimeout(function () { return _this._handleInOut(entry, false); }, 0); }); }; /** * Toggles visibility classes and emits events for visibility changes. */ InView.prototype._handleInOut = function (entry, isInView, isInitialStart) { if (isInitialStart === void 0) { isInitialStart = false; } var element = entry.target; var direction = this._getDirection(entry, isInView, isInitialStart); this._toggleClassname(element, isInView, direction); this.callbacks.emit(isInView ? 'in' : 'out', { element: element, direction: direction }); }; /** Toggles visibility classes */ InView.prototype._toggleClassname = function (element, isInView, direction) { var _a; var classNames = element.getAttribute('data-in-view-class'); if (!classNames) { return; } var split = classNames.split('|'); var direct = split[0].trim(); var reverse = ((_a = split[1]) === null || _a === void 0 ? void 0 : _a.trim()) || direct; if (!direct) { return; } if (isInView) { var isReverse = direction === 'fromRight' || direction === 'fromTop'; var className = isReverse ? reverse.trim() : direct.trim(); (0, cn_1.cnToggle)(element, className, isInView); return; } (0, cn_1.cnToggle)(element, direct, isInView); (0, cn_1.cnToggle)(element, reverse, isInView); }; /** Gets element direction */ InView.prototype._getDirection = function (entry, isInView, isInitialStart) { var app = (0, initVevet_1.initVevet)(); var bounding = entry.boundingClientRect; if (this.props.scrollDirection === 'horizontal') { var direction_1 = 'fromRight'; if ((isInView && !isInitialStart) || !isInView) { if (bounding.left > app.width / 2) { direction_1 = 'fromRight'; } else if (bounding.right < app.width / 2) { direction_1 = 'fromLeft'; } } return direction_1; } var direction = 'fromBottom'; if ((isInView && !isInitialStart) || !isInView) { if (bounding.top > app.height / 2) { direction = 'fromBottom'; } else if (bounding.bottom < app.height / 2) { direction = 'fromTop'; } } return direction; }; /** * Calculates the delay before triggering an element's visibility event. */ InView.prototype._getDelay = function (element) { var _a = this.props, scrollDirection = _a.scrollDirection, maxInitialDelay = _a.maxInitialDelay; var app = (0, initVevet_1.initVevet)(); if (!this.isInitialStart || maxInitialDelay <= 0) { return 0; } var bounding = element.getBoundingClientRect(); var rootBounding = { top: 0, left: 0, width: app.width, height: app.height, }; var progress = (0, math_1.clamp)(scrollDirection === 'horizontal' ? (bounding.left - rootBounding.left) / rootBounding.width : (bounding.top - rootBounding.top) / rootBounding.height); if (this._isRtl && scrollDirection === 'horizontal') { progress = 1 - progress; } return progress * maxInitialDelay; }; /** * Registers an element for visibility observation. * * If the element has a `data-in-view-class` attribute, the specified class will be applied upon entering the viewport. * * @returns A function to stop observing the element. */ InView.prototype.addElement = function (element) { var _this = this; var _a, _b; var finalElement = element; finalElement.$vevetInViewBool = undefined; this._elements.push(finalElement); (_a = this._in) === null || _a === void 0 ? void 0 : _a.observe(finalElement); (_b = this._out) === null || _b === void 0 ? void 0 : _b.observe(finalElement); return function () { return _this.removeElement(finalElement); }; }; /** * Removes an element from observation, preventing further visibility tracking. */ InView.prototype.removeElement = function (element) { var _a, _b; var finalElement = element; (_a = this._in) === null || _a === void 0 ? void 0 : _a.unobserve(finalElement); (_b = this._out) === null || _b === void 0 ? void 0 : _b.unobserve(finalElement); this._elements = this._elements.filter(function (el) { return el !== element; }); finalElement.$vevetInViewBool = undefined; }; /** * Cleans up the module and disconnects all observers and listeners. */ InView.prototype._destroy = function () { _super.prototype._destroy.call(this); this._removeViewEvents(); }; __decorate([ noopIfDestroyed_1.noopIfDestroyed ], InView.prototype, "addElement", null); __decorate([ noopIfDestroyed_1.noopIfDestroyed ], InView.prototype, "removeElement", null); return InView; }(Module_1.Module)); exports.InView = InView; //# sourceMappingURL=index.js.map