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.

589 lines 24.2 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.Cursor = 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 isFiniteNumber_1 = require("../../internal/isFiniteNumber"); var noopIfDestroyed_1 = require("../../internal/noopIfDestroyed"); var textDirection_1 = require("../../internal/textDirection"); var utils_1 = require("../../utils"); var listeners_1 = require("../../utils/listeners"); var math_1 = require("../../utils/math"); var Raf_1 = require("../Raf"); var constants_1 = require("./constants"); var HoverElement_1 = require("./HoverElement"); var Path_1 = require("./Path"); var props_1 = require("./props"); var styles_1 = require("./styles"); __exportStar(require("./types"), exports); /** * A customizable custom cursor component with smooth animations and hover interactions. * Supports dynamic appearance changes and enhanced user interaction. * * [Documentation](https://vevetjs.com/docs/Cursor) * * @group Components */ var Cursor = /** @class */ (function (_super) { __extends(Cursor, _super); function Cursor(props, onCallbacks) { var _this = _super.call(this, props, onCallbacks) || this; /** Attached hover elements */ _this._elements = []; /** Active hovered element */ _this._activeElements = []; /** Defines if the cursor has been moved after initialization */ _this._isFirstMove = true; var isEnabled = _this.props.enabled; var _a = _this, initialWidth = _a.initialWidth, initialHeight = _a.initialHeight; // Set default variables _this._coords = { x: 0, y: 0, width: initialWidth, height: initialHeight, angle: 0, velocity: 0, }; _this._rawTarget = __assign({}, _this._coords); _this._types = []; _this._activeTypes = []; // Create cursor path _this._path = new Path_1.CursorPath(_this.hasPath); // No need to remove styles on destroy (0, styles_1.createCursorStyles)(_this.prefix); // Setup _this._setClassNames(); _this._createElements(); _this._setEvents(); // enable by default _this._toggle(isEnabled); return _this; } /** Get default static properties */ Cursor.prototype._getStatic = function () { return __assign(__assign({}, _super.prototype._getStatic.call(this)), props_1.STATIC_PROPS); }; /** Get default mutable properties */ Cursor.prototype._getMutable = function () { return __assign(__assign({}, _super.prototype._getMutable.call(this)), props_1.MUTABLE_PROPS); }; Object.defineProperty(Cursor.prototype, "prefix", { /** * Classname prefix for styling elements. */ get: function () { return "".concat((0, initVevet_1.initVevet)().prefix, "cursor"); }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "container", { /** The cursor container */ get: function () { return this.props.container; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "domContainer", { /** Returns the DOM parent for the cursor element. */ get: function () { if (this.container instanceof Window) { return env_1.body; } return this.container; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "outer", { /** * The outer element of the custom cursor. * This is the visual element that represents the cursor on screen. */ get: function () { return this._outer; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "inner", { /** * The inner element of the custom cursor. * This element is nested inside the outer element and can provide additional styling. */ get: function () { return this._inner; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "initialWidth", { /** Cursor initial width */ get: function () { return (0, utils_1.toPixels)(this.props.width); }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "initialHeight", { /** Cursor initial width */ get: function () { return (0, utils_1.toPixels)(this.props.height); }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "coords", { /** * The current coordinates (x, y, width, height). * These are updated during cursor movement. */ get: function () { return this._coords; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "hoveredElement", { /** * The currently hovered element. * Stores information about the element that the cursor is currently interacting with. */ get: function () { var activeElements = this._activeElements; return activeElements[activeElements.length - 1]; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "targetCoords", { /** Target coordinates of the cursor (without smooth interpolation). */ get: function () { var _a, _b, _c, _d; var _e = this, hoveredElement = _e.hoveredElement, initialWidth = _e.initialWidth, initialHeight = _e.initialHeight; var _f = this._rawTarget, x = _f.x, y = _f.y; var _g = this._rawTarget, angle = _g.angle, velocity = _g.velocity; var width = initialWidth; var height = initialHeight; var padding = 0; if (hoveredElement) { var dimensions = hoveredElement.getDimensions(); width = (_a = dimensions.width) !== null && _a !== void 0 ? _a : initialWidth; height = (_b = dimensions.height) !== null && _b !== void 0 ? _b : initialHeight; x = (_c = dimensions.x) !== null && _c !== void 0 ? _c : x; y = (_d = dimensions.y) !== null && _d !== void 0 ? _d : y; padding = dimensions.padding; } width += padding * 2; height += padding * 2; return { x: x, y: y, width: width, height: height, angle: angle, velocity: velocity }; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "path", { /** Returns an SVG path element which represents the cursor movement */ get: function () { return this._path.path; }, enumerable: false, configurable: true }); Object.defineProperty(Cursor.prototype, "hasPath", { /** Check if the cursor has a path */ get: function () { return this.props.behavior === 'path'; }, enumerable: false, configurable: true }); /** Handles property mutations */ Cursor.prototype._handleProps = function (props) { _super.prototype._handleProps.call(this, props); this._toggle(this.props.enabled); }; /** Sets class names */ Cursor.prototype._setClassNames = function () { var domContainer = this.domContainer; // Hide native cursor if (this.props.hideNative) { domContainer.style.cursor = 'none'; this._addTempClassName(domContainer, this._cn('-hide-default')); } // Set class names this._addTempClassName(domContainer, this._cn('-container')); // Set container position if (domContainer !== env_1.body) { domContainer.style.position = 'relative'; } // Reset styles this.onDestroy(function () { domContainer.style.cursor = ''; }); }; /** Creates the custom cursor and appends it to the DOM. */ Cursor.prototype._createElements = function () { var _a = this, container = _a.container, domContainer = _a.domContainer, props = _a.props; var isWindow = container instanceof Window; var cn = this._cn.bind(this); // Create outer element var outer = env_1.doc.createElement('div'); (0, cn_1.cnAdd)(outer, cn('')); (0, cn_1.cnAdd)(outer, cn(isWindow ? '-in-window' : '-in-element')); (0, cn_1.cnAdd)(outer, cn('-disabled')); // Append the outer element to the DOM container if (props.append) { domContainer.append(outer); } // set direction var direction = (0, textDirection_1.getTextDirection)(outer); (0, cn_1.cnAdd)(outer, cn("_".concat(direction))); // Create inner element var inner = env_1.doc.createElement('div'); outer.append(inner); (0, cn_1.cnAdd)(inner, cn('__inner')); (0, cn_1.cnAdd)(inner, cn('-disabled')); outer.append(inner); // assign this._outer = outer; this._inner = inner; // Destroy the cursor this.onDestroy(function () { inner.remove(); outer.remove(); }); }; /** Sets up the various event listeners for the cursor, such as mouse movements and clicks. */ Cursor.prototype._setEvents = function () { var _this = this; var domContainer = this.domContainer; this._raf = new Raf_1.Raf({ enabled: false }); this._raf.on('frame', function () { return _this.render(); }); var mouseenter = (0, listeners_1.addEventListener)(domContainer, 'mouseenter', this._handleMouseEnter.bind(this)); var mouseleave = (0, listeners_1.addEventListener)(domContainer, 'mouseleave', this._handleMouseLeave.bind(this)); var mousemove = (0, listeners_1.addEventListener)(domContainer, 'mousemove', this._handleMouseMove.bind(this)); var mousedown = (0, listeners_1.addEventListener)(domContainer, 'mousedown', this._handleMouseDown.bind(this)); var mouseup = (0, listeners_1.addEventListener)(domContainer, 'mouseup', this._handleMouseUp.bind(this)); var blur = (0, listeners_1.addEventListener)(window, 'blur', this._handleWindowBlur.bind(this)); this.onDestroy(function () { var _a; (_a = _this._raf) === null || _a === void 0 ? void 0 : _a.destroy(); mouseenter(); mouseleave(); mousemove(); mousedown(); mouseup(); blur(); }); }; /** Enables cursor animation. */ Cursor.prototype._toggle = function (enabled) { var _a; var className = this._cn('-disabled'); (0, cn_1.cnToggle)(this.outer, className, !enabled); (0, cn_1.cnToggle)(this.inner, className, !enabled); (_a = this._raf) === null || _a === void 0 ? void 0 : _a.updateProps({ enabled: enabled }); }; /** Handles mouse enter events. */ Cursor.prototype._handleMouseEnter = function (evt) { if (!this.props.enabled) { return; } var x = evt.clientX, y = evt.clientY; var target = this._rawTarget; this._coords.x = x; this._coords.y = y; target.x = x; target.y = y; this._path.addPoint(target, true); (0, cn_1.cnAdd)(this.outer, this._cn('-visible')); }; /** Handles mouse leave events. */ Cursor.prototype._handleMouseLeave = function () { (0, cn_1.cnRemove)(this.outer, this._cn('-visible')); }; /** Handles mouse move events. */ Cursor.prototype._handleMouseMove = function (evt) { var _a; if (!this.props.enabled) { return; } var x = evt.clientX, y = evt.clientY; var target = this._rawTarget; var prevX = target.x, prevY = target.y; // Calculate angle var deltaX = prevX - this._coords.x; var deltaY = prevY - this._coords.y; var prevAngle = target.angle; var rawAngle = (Math.atan2(deltaY, deltaX) * 180) / Math.PI; var targetAngle = prevAngle + ((((rawAngle - prevAngle) % 360) + 540) % 360) - 180; // Calculate velocity var velocity = Math.min(Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)) * 2, 150) / 150; // Update target coordinates target.x = x; target.y = y; target.angle = targetAngle; target.velocity = velocity; // Update interpolated coords if first move if (this._isFirstMove) { this._coords.x = target.x; this._coords.y = target.y; this._coords.angle = target.angle; this._coords.velocity = target.velocity; this._isFirstMove = false; } // Add path point this._path.addPoint(target); // Handle classnames (0, cn_1.cnAdd)(this.outer, this._cn('-visible')); // Enable animation (_a = this._raf) === null || _a === void 0 ? void 0 : _a.play(); }; /** Handles mouse down events. */ Cursor.prototype._handleMouseDown = function (evt) { var className = this._cn('-click'); if (evt.which === 1) { (0, cn_1.cnAdd)(this.outer, className); (0, cn_1.cnAdd)(this.inner, className); } }; /** Handles mouse up events. */ Cursor.prototype._handleMouseUp = function () { var className = this._cn('-click'); (0, cn_1.cnRemove)(this.outer, className); (0, cn_1.cnRemove)(this.inner, className); }; /** Handles window blur events. */ Cursor.prototype._handleWindowBlur = function () { this._handleMouseUp(); }; /** * Registers an element to interact with the cursor, enabling dynamic size and position changes based on hover effects. * @returns Returns a destructor */ Cursor.prototype.attachHover = function (settings) { var _this = this; var element = new HoverElement_1.CursorHoverElement(settings, function (data) { return _this._handleElementEnter(data); }, function (data) { return _this._handleElementLeave(data); }); this._elements.push(element); var destroy = function () { _this._elements = _this._elements.filter(function (i) { return i !== element; }); element.destroy(); }; this.onDestroy(function () { return destroy(); }); return function () { return destroy(); }; }; /** Handle element mouse enter event */ Cursor.prototype._handleElementEnter = function (data) { var _a; if (!this.props.enabled) { return; } this._activeElements.push(data); if (data.type) { this._toggleType(data.type, true); } this.callbacks.emit('hoverEnter', data); (_a = this._raf) === null || _a === void 0 ? void 0 : _a.play(); }; /** Handle element mouse leave event */ Cursor.prototype._handleElementLeave = function (data) { var _a; this._activeElements = this._activeElements.filter(function (i) { return i !== data; }); if (data.type) { this._toggleType(data.type, false); } this.callbacks.emit('hoverLeave', data); if (this.props.enabled) { (_a = this._raf) === null || _a === void 0 ? void 0 : _a.play(); } }; /** * Registers a cursor type. */ Cursor.prototype.attachCursor = function (_a) { var _b; var element = _a.element, type = _a.type; this._types.push({ element: element, type: type }); (_b = this._inner) === null || _b === void 0 ? void 0 : _b.append(element); }; /** Enable or disable a cursor type */ Cursor.prototype._toggleType = function (type, isEnabled) { var targetType = this._types.find(function (item) { return item.type === type; }); if (isEnabled) { this._activeTypes.push(type); } else { this._activeTypes = this._activeTypes.filter(function (item) { return type !== item; }); } var activeTypes = this._activeTypes; var activeType = activeTypes.length > 0 ? activeTypes[activeTypes.length - 1] : null; this._types.forEach(function (item) { (0, cn_1.cnToggle)(item.element, 'active', item.type === activeType); }); if (targetType) { this.callbacks.emit(isEnabled ? 'typeShow' : 'typeHide', targetType); } if (!activeType) { this.callbacks.emit('noType', undefined); } }; Object.defineProperty(Cursor.prototype, "isInterpolated", { /** * Checks if all coordinates are interpolated. * @returns {boolean} True if all coordinates are interpolated, false otherwise. */ get: function () { var _a = this, coords = _a.coords, targetCoords = _a.targetCoords, props = _a.props; var isWidthDone = coords.width === targetCoords.width; var isHeightDone = coords.height === targetCoords.height; var isAngleDone = coords.angle === targetCoords.angle; var isVelocityDone = coords.velocity === targetCoords.velocity; var isElementsDone = !this._elements.find(function (element) { return !element.isInterpolated; }); var isPathDone = this._path.isInterpolated; var isCoordsDone = coords.x === targetCoords.x && coords.y === targetCoords.y; return (isWidthDone && isHeightDone && isAngleDone && isVelocityDone && isElementsDone && (props.behavior === 'path' ? isPathDone : isCoordsDone)); }, enumerable: false, configurable: true }); /** Renders the cursor. */ Cursor.prototype.render = function () { var _a; this._calculate(); this._renderElements(); if (this.props.autoStop && this.isInterpolated) { (_a = this._raf) === null || _a === void 0 ? void 0 : _a.pause(); } // Launch render events this.callbacks.emit('render', undefined); }; /** Recalculates current coordinates. */ Cursor.prototype._calculate = function () { var _a = this, target = _a.targetCoords, coords = _a._coords; var lerpFactor = this._getLerpFactor(); this._path.lerp(lerpFactor); this._path.minimize(); try { if (this.hasPath) { var pathCoord = this._path.coord; coords.x = pathCoord.x; coords.y = pathCoord.y; } else { throw new Error('No path'); } } catch (_b) { coords.x = this._lerp(coords.x, target.x); coords.y = this._lerp(coords.y, target.y); } coords.width = this._lerp(coords.width, target.width); coords.height = this._lerp(coords.height, target.height); coords.angle = this._lerp(coords.angle, target.angle); this._rawTarget.velocity = this._lerp(this._rawTarget.velocity, 0); coords.velocity = this._lerp(coords.velocity, this._rawTarget.velocity); }; /** Gets the interpolation factor. */ Cursor.prototype._getLerpFactor = function (input) { if (input === void 0) { input = this.props.lerp; } if (!(0, isFiniteNumber_1.isFiniteNumber)(input)) { return 1; } var lerpFactor = (0, math_1.clamp)(input, 0, 1); return this._raf.lerpFactor(lerpFactor); }; /** Performs linear interpolation. */ Cursor.prototype._lerp = function (current, target) { var lerpFactor = this._getLerpFactor(); var value = (0, math_1.lerp)(current, target, lerpFactor, constants_1.LERP_APPROXIMATION); return value; }; /** Renders the cursor elements. */ Cursor.prototype._renderElements = function () { var _this = this; var _a = this, container = _a.container, domContainer = _a.domContainer, outer = _a.outer, props = _a.props, coords = _a.coords; var width = coords.width, height = coords.height; var x = coords.x, y = coords.y; if (!(container instanceof Window)) { var bounding = domContainer.getBoundingClientRect(); x -= bounding.left; y -= bounding.top; } // Update DOM coordinates var style = outer.style; style.setProperty('--cursor-w', "".concat(width, "px")); style.setProperty('--cursor-h', "".concat(height, "px")); style.transform = props.transformModifier(__assign(__assign({}, coords), { x: x, y: y })); // Render element this._elements.forEach(function (element) { return element.render(_this._getLerpFactor.bind(_this)); }); }; __decorate([ noopIfDestroyed_1.noopIfDestroyed ], Cursor.prototype, "attachHover", null); __decorate([ noopIfDestroyed_1.noopIfDestroyed ], Cursor.prototype, "attachCursor", null); __decorate([ noopIfDestroyed_1.noopIfDestroyed ], Cursor.prototype, "render", null); return Cursor; }(Module_1.Module)); exports.Cursor = Cursor; //# sourceMappingURL=index.js.map