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.

145 lines 5.82 kB
import { clamp } from '../../../../../utils'; import { PARALLAX_GROUPS, PARALLAX_TYPES } from './constants'; import { getAttr, getFloatAttr, isParallaxAttr } from './utils'; export class SnapSlideParallax { constructor(_slide, _element, _getImpulse) { this._slide = _slide; this._element = _element; this._getImpulse = _getImpulse; this._items = []; this._debounceInit = null; this._initDebounce(); this._observer = new MutationObserver((mutations) => { mutations.forEach(({ attributeName }) => { if (attributeName && isParallaxAttr(attributeName)) { this._initDebounce(); } }); }); this._observer.observe(this._element, { attributes: true }); } /** Initialize parallax with debounce */ _initDebounce() { if (this._debounceInit) { clearTimeout(this._debounceInit); } this._debounceInit = setTimeout(() => this._init(), 16); } /** Initialize parallax */ _init() { this._fetchItems(); this.render(); } /** Fetch parallax items */ _fetchItems() { const element = this._element; const defaultScope = this._getScope(this._element, `scope`, [-1, 1]); const types = PARALLAX_TYPES.filter(({ attr }) => element.hasAttribute(attr)); this._items = types.map(({ attr, prop, unit: defaultUnit, isAbs: isAbsProp, modifier }) => { var _a; const group = PARALLAX_GROUPS.find(({ types }) => types.find((type) => type.attr === attr)); const scopeAttr = `${attr}-scope`; const scope = element.hasAttribute(scopeAttr) ? this._getScope(element, scopeAttr, [-1, 1]) : defaultScope; const attrValue = getAttr(element, attr); const unit = attrValue.replace(/[-\d.]+/g, '') || defaultUnit; const target = getFloatAttr(element, attr, 0); const offset = getFloatAttr(element, `${attr}-offset`, 0); const min = getFloatAttr(element, `${attr}-min`, -Infinity); const max = getFloatAttr(element, `${attr}-max`, Infinity); const impulseAttr = `${attr}-impulse`; const impulse = element.hasAttribute(impulseAttr) ? getFloatAttr(element, impulseAttr, 1) : 0; // legacy influence const influenceAttr = `${attr}-influence`; const influence = element.hasAttribute(influenceAttr) ? getFloatAttr(element, influenceAttr, 1) : 0; const directionalAttr = `${attr}-directional`; const isDirectional = element.hasAttribute(directionalAttr); const absAttr = `${attr}-abs`; const isAbs = isAbsProp || element.hasAttribute(absAttr); return { attr, prop, unit, group: (_a = group === null || group === void 0 ? void 0 : group.prop) !== null && _a !== void 0 ? _a : '', modifier, scope, progress: 0, target, value: 0, offset, min, max, impulse: impulse || influence, isDirectional, isAbs, }; }); } /** Get parallax scope */ _getScope(element, suffix, defaultValue) { const attrValue = getAttr(element, suffix); const stringValue = attrValue.toLowerCase(); if (stringValue === 'none') { return [-Infinity, Infinity]; } if (stringValue === 'const') { return [1, 1]; } const cleanValue = attrValue.replace(/[\s\\[\]]+/g, ''); const minMax = cleanValue.split(','); const minRaw = parseFloat(minMax[0]); const maxRaw = parseFloat(minMax[1]); const min = Number.isNaN(minRaw) ? defaultValue[0] : minRaw; const max = Number.isNaN(maxRaw) ? defaultValue[1] : maxRaw; return [min, max]; } /** Render parallax */ render() { const { _element: element, _items: items, _slide: slide } = this; const impulse = this._getImpulse(); const globalProgress = slide.progress; // Calculate parallax values items.forEach((item) => { let progress = clamp(globalProgress, ...item.scope); if (Math.abs(item.impulse) > 0) { progress *= Math.abs(impulse) * item.impulse; } if (item.isDirectional) { progress = Math.abs(progress) * Math.sign(impulse); } if (item.isAbs) { progress = Math.abs(progress); } item.progress = progress; item.value = item.offset + progress * item.target; if (item.modifier) { item.value = item.modifier(item.value); } item.value = clamp(item.value, item.min, item.max); }); PARALLAX_GROUPS.forEach(({ prop: groupProp }) => { const groupItems = items.filter((item) => item.group === groupProp); const styles = groupItems.map(({ value, prop, unit }) => { if (groupProp === 'opacity') { return `${value}`; } return `${prop}(${value}${unit})`; }); const styleString = styles.join(' '); element.style[groupProp] = styleString; }); } /** Destroy parallax */ destroy() { this._observer.disconnect(); if (this._debounceInit) { clearTimeout(this._debounceInit); } } } //# sourceMappingURL=index.js.map