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.

218 lines 7.1 kB
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; }; import { Module } from '../../base'; import { initVevet } from '../../global/initVevet'; import { noopIfDestroyed } from '../../internal/noopIfDestroyed'; import { onResize } from '../../utils/listeners/onResize'; import { MUTABLE_PROPS, GET_STATIC_PROPS } from './props'; import { saveInitialNodes } from './utils/saveInitialNodes'; import { splitBase } from './utils/splitBase'; import { wrapLines } from './utils/wrapLines'; export * from './types'; /** * `SplitText` splits text within a container into individual lines, words, and letters. * * Features: * - Supports resizing, HTML content, and special symbols like emojis. * - Handles multi-line breaks and non-breaking spaces. * - Saves initial nodes for easy restoration. * - Allows splitting into lines, words, or letters as needed. * * **Note**: Apply `fontKerning: none` to prevent layout shifts. * * [Documentation](https://vevetjs.com/docs/SplitText) * * @group Components */ export class SplitText extends Module { /** Get default static properties. */ _getStatic() { return Object.assign(Object.assign({}, super._getStatic()), GET_STATIC_PROPS(this.prefix)); } /** Get default mutable properties. */ _getMutable() { return Object.assign(Object.assign({}, super._getMutable()), MUTABLE_PROPS); } /** * Initializes the SplitText instance and saves the initial state. */ constructor(props, onCallbacks) { super(props, onCallbacks); /** * Tracks whether the text is already split into base elements: words and letters. */ this._hasSplitBase = false; /** * List of letters metadata. */ this._lettersMeta = []; /** * List of words metadata. */ this._wordsMeta = []; /** * List of lines metadata. */ this._linesMeta = []; const { container, ariaLabel } = this.props; const { style } = container; // Add styles style.fontKerning = 'none'; style.display = 'block'; // A11Y if (ariaLabel) { container.setAttribute('aria-label', typeof ariaLabel === 'string' ? ariaLabel : container.textContent || ''); } // Disable translate container.translate = false; // Add classes this._addTempClassName(container, this._cn('')); // Save initial nodes this._initials = saveInitialNodes(container); // Set events this._setEvents(); } /** * Classname prefix for styling elements. */ get prefix() { return `${initVevet().prefix}split-text`; } /** * Retrieves an array of letters metadata. */ get lettersMeta() { return this._lettersMeta; } /** * Retrieves an array of letter elements. */ get letters() { return this._lettersMeta.map((letter) => letter.element); } /** * Retrieves an array of words metadata. */ get wordsMeta() { return this._wordsMeta; } /** * Retrieves an array of word elements. */ get words() { return this._wordsMeta.map((word) => word.element); } /** * Retrieves an array of lines metadata. */ get linesMeta() { return this._linesMeta; } /** * Retrieves an array of line elements. */ get lines() { return this._linesMeta.map((line) => line.element); } /** * Sets up event listeners and handles initial splitting. */ _setEvents() { const { container, resizeDebounce } = this.props; if (!this.props.lines) { this.split(); return; } const resizeHandler = onResize({ callback: () => this.split(), element: container, viewportTarget: 'width', resizeDebounce, name: this.name, }); resizeHandler.resize(); this.onDestroy(() => resizeHandler.remove()); } /** * Splits the text into letters, words, and optionally lines based on configuration. */ split() { this.callbacks.emit('beforeSplit', undefined); this._splitBase(); if (this.props.lines) { this._splitLines(); } this.callbacks.emit('split', undefined); } /** * Splits text into base elements: letters and words. */ _splitBase() { if (this._hasSplitBase) { return; } const { container, letterTag, wordTag, wordClass, letterClass, ignore, prepareText, wordDelimiter, wordDelimiterOutput, } = this.props; this._hasSplitBase = true; const { wordsMeta, lettersMeta } = splitBase({ container, letterClassName: letterClass, wordClassName: wordClass, hasLetters: this.props.letters, letterTag, wordTag, ignore, prepareText, wordDelimiter, wordDelimiterOutput, }); this._wordsMeta = wordsMeta; this._lettersMeta = lettersMeta; } /** * Wraps words into line containers. */ _splitLines() { var _a; const { wordsMeta } = this; const { container, lineTag, lineClass, lineWrapperClass } = this.props; const isHidden = container.offsetParent === null; if (isHidden) { return; } (_a = this._lineSplitWrapper) === null || _a === void 0 ? void 0 : _a.destroy(); this._lineSplitWrapper = wrapLines({ container, hasLinesWrapper: this.props.linesWrapper, wordsMeta, lineClassName: lineClass, lineWrapperClassName: lineWrapperClass, tagName: lineTag, }); this._linesMeta = this._lineSplitWrapper.linesMeta; } /** * Destroys the component. * This method does not restore the initial nodes. For this purpose, use `restore()`. */ _destroy() { super._destroy(); if (!this._lineSplitWrapper) { this._initials.restore(); } else { const isSuccessfulDestroy = this._lineSplitWrapper.destroy(); this._lineSplitWrapper = undefined; if (isSuccessfulDestroy) { this._initials.restore(); } } } } __decorate([ noopIfDestroyed ], SplitText.prototype, "split", null); //# sourceMappingURL=index.js.map