UNPKG

@proyecto26/animatable-component

Version:
513 lines (506 loc) • 19.8 kB
import { r as registerInstance, c as createEvent, h, g as getElement, H as Host } from './index-d6bfca92.js'; import { K as KEYFRAMES, a as EASING_FUNCTIONS, g as getKeyFramesByAnimation } from './index-9a8fe12c.js'; /** * Get element to animate */ const getElementToAnimate = (parent) => { return parent.shadowRoot !== null ? parent : (parent.firstElementChild || (parent.children.length && parent.children[0]) || parent); }; /** * Create a new animation. * @param element - The element to animate. * @param context - Animatable context. */ function createAnimation(element, context) { const newKeyFrames = context.keyFrames || (context.animation && KEYFRAMES[context.animation]) || (context.keyFramesData && JSON.parse(context.keyFramesData)) || []; const options = getAnimationOptions(context); const newAnimation = element.animate(newKeyFrames, options); newAnimation.pause(); if (context.currentTime !== undefined) newAnimation.currentTime = context.currentTime; if (context.startTime !== undefined) newAnimation.startTime = context.startTime; return newAnimation; } /** * Clear props of the animatable context. * @param context - Animatable context. * @param options - Keyframe options. */ function clearPropsWithOptions(context, options) { for (const key in options) { if (options.hasOwnProperty(key)) { if (key === 'id') { context.animateId = undefined; } else { context[key] = undefined; } } } } /** * Load the options of the animation. * @param context - The data of the animation. */ function getAnimationOptions(context) { const animationOptions = context.options || (context.optionsData && JSON.parse(context.optionsData)) || {}; if (context.delay !== undefined) animationOptions.delay = context.delay; if (context.duration !== undefined) animationOptions.duration = context.duration; if (context.direction !== undefined) animationOptions.direction = context.direction; if (context.composite !== undefined) animationOptions.composite = context.composite; const easingType = (context.easing || animationOptions.easing); animationOptions.easing = EASING_FUNCTIONS[easingType] || easingType; if (context.endDelay !== undefined) animationOptions.endDelay = context.endDelay; if (context.fill !== undefined) animationOptions.fill = context.fill; if (context.animateId !== undefined) animationOptions.id = context.animateId; if (context.iterations !== undefined) animationOptions.iterations = context.iterations; if (context.iterationStart !== undefined) animationOptions.iterationStart = context.iterationStart; if (context.iterationComposite !== undefined) animationOptions.iterationComposite = context.iterationComposite; return animationOptions; } /** * A manager to handle the animations of the Components. */ class AnimationManager { constructor(initState) { this.animation = null; /** * Emit `onStart` event and update class name with `fromClassName`. */ this.onStartAnimation = () => { this.state.onStart.emit(this.element); if (this.state.fromClassName !== undefined) { this.className = this.element.className; this.element.className = this.state.fromClassName; } }; /** * Emit `onCancel` event and restore class name. */ this.onCancelAnimation = () => { this.state.onCancel.emit(this.element); if (this.state.fromClassName !== undefined && this.className !== undefined) { this.element.className = this.className; } }; /** * Emit `onFinish` event and update class name with `toClassName`. */ this.onFinishAnimation = () => { const { element, state } = this; state.onFinish.emit(element); if (state.toClassName !== undefined) { element.className = state.toClassName; } }; this.state = initState; } get currentAnimation() { return this.animation || this.loadAnimation(); } set currentAnimation(value) { this.animation = value; } loadAnimation() { const { element, state } = this; const newAnimation = createAnimation(element, state); /** * Add listeners */ newAnimation.addEventListener('finish', this.onFinishAnimation); newAnimation.addEventListener('cancel', this.onCancelAnimation); return this.animation = newAnimation; } clearAnimation() { if (this.animation === null) return; this.animation.removeEventListener('finish', this.onFinishAnimation); this.animation.removeEventListener('cancel', this.onCancelAnimation); this.animation = null; } destroyAnimation() { if (this.animation === null) return; const currentAnimation = this.animation; this.clearAnimation(); currentAnimation.cancel(); } /** * Emit start event if playState is not running or playing a new animation. */ playAnimation() { if (this.currentAnimation.playState === 'running' && !this.isUpdatingState) return; /** * Cancel current animation before to create another one */ if (this.isUpdatingState) { this.destroyAnimation(); } this.currentAnimation.play(); this.onStartAnimation(); } setState(element, newState) { this.isUpdatingState = true; this.element = element; this.state = newState; } savedState() { /** * Check if `autoPlay` is enabled to play a new animation and emit the event. */ if (this.state.autoPlay) { this.playAnimation(); } this.isUpdatingState = false; } } const AnimatableComponent = class { constructor(hostRef) { registerInstance(this, hostRef); this.onStart = createEvent(this, "start", 3); this.onFinish = createEvent(this, "finish", 3); this.onCancel = createEvent(this, "cancel", 3); /** * Animation manager for Animatable */ this.manager = null; /** * Start the animation when the component is mounted. */ this.autoPlay = false; } get element() { return getElementToAnimate(this.el); } animationDidChangeHandler(animation) { this.keyFrames = getKeyFramesByAnimation(animation); } /** * Get keyFrames of the animation from string data. * @param text - The string with the keyFrames of the animation. */ keyFramesDidChangeHandler(text) { if (text !== undefined) this.keyFrames = JSON.parse(text); } /** * Get options of the animation from string data. * @param text - The string with the options of the animation. */ optionsDidChangeHandler(options) { clearPropsWithOptions(this, options); } /** * Get options of the animation from string data. * @param text - The string with the options of the animation. */ optionsDataDidChangeHandler(text) { if (text !== undefined) this.options = JSON.parse(text); } setCurrenTime(newValue) { this.manager.currentAnimation.currentTime = newValue; } /** * Returns the current time value of the animation in milliseconds, whether running or paused. */ async getCurrentTime() { return Promise.resolve(this.manager.currentAnimation.currentTime); } setStartTime(newValue) { this.manager.currentAnimation.startTime = newValue; } /** * Returns the scheduled time when an animation's playback should begin. */ async getStartTime() { return Promise.resolve(this.manager.currentAnimation.startTime); } /** * Indicates whether the animation is currently waiting * for an asynchronous operation such as initiating playback * or pausing a running animation. */ async getPending() { return Promise.resolve(this.manager.currentAnimation.pending); } setPlaybackRate(newValue) { this.manager.currentAnimation.playbackRate = newValue; } /** * Returns the playback rate of the animation. */ async getPlaybackRate() { return Promise.resolve(this.manager.currentAnimation.playbackRate); } /** * Returns an enumerated value describing the playback state of an animation. */ async getPlayState() { return Promise.resolve(this.manager.currentAnimation.playState); } /** * Clears all `KeyframeEffects` caused by this animation and aborts its playback. */ async cancel() { this.manager.currentAnimation.cancel(); } /** * Sets the current playback time to the end of the animation * corresponding to the current playback direction. */ async finish() { this.manager.currentAnimation.finish(); } /** * Suspends playback of the animation. */ async pause() { this.manager.currentAnimation.pause(); } /** * Starts or resumes playing of an animation. */ async play() { this.manager.playAnimation(); } /** * Reverses the playback direction, meaning the animation ends at its beginning. */ async reverse() { this.manager.currentAnimation.reverse(); } /** * Clear the current animation */ async clear() { this.manager.clearAnimation(); } /** * Destroy the current animation */ async destroy() { if (this.manager !== null) { this.manager.destroyAnimation(); } } /** * Initialize manager */ connectedCallback() { this.manager = new AnimationManager(this); this.manager.setState(this.element, this); } componentDidLoad() { this.manager.savedState(); } componentShouldUpdate() { this.manager.setState(this.element, this); } componentDidUpdate() { this.manager.savedState(); } disconnectedCallback() { this.destroy(); } render() { return h("slot", null); } get el() { return getElement(this); } static get watchers() { return { "animation": ["animationDidChangeHandler"], "keyFramesData": ["keyFramesDidChangeHandler"], "options": ["optionsDidChangeHandler"], "optionsData": ["optionsDataDidChangeHandler"], "currentTime": ["setCurrenTime"], "startTime": ["setStartTime"], "playbackRate": ["setPlaybackRate"] }; } }; const animatableCubeCss = ":host{--size:var(--animatable-cube-size, var(--animatable-cube-width, var(--animatable-cube-height, 100px)));--perspective:var(--animatable-cube-perspective, 1000px);--perspective-origin:var(--animatable-cube-perspective-origin, 50% 50%);--display:var(--animatable-cube-display, flex);--transition-property:var(--animatable-cube-transition-property, (width, height));--transition-duration:var(--animatable-cube-transition-duration, 0);--transition-delay:var(--animatable-cube-transition-delay, 0);--transition-timing-function:var(--animatable-cube-transition-timing-function, initial);--align-items:var(--animatable-cube-align-items, center);--justify-content:var(--animatable-cube-justify-content, center);--margin:var(--animatable-cube-margin, 0);--padding:var(--animatable-cube-padding, 0);--face-border:var(--animatable-cube-face-border, none);--face-background:var(--animatable-cube-face-background, white);--face-background-size:var(--animatable-cube-face-background-size, 100% 100%);--face-animation:var(\n --animatable-cube-face-animation,\n backgroundAnimation\n var(--animatable-cube-face-animation-duration, 0s)\n var(--animatable-cube-face-animation-timing-function, initial)\n var(--animatable-cube-face-animation-delay, 0s)\n var(--animatable-cube-face-animation-iteration-count, infinite)\n var(--animatable-cube-face-animation-direction, alternate)\n );--face-size:calc(var(--size)/2);--face-transform-origin:var(--animatable-cube-face-transform-origin, center center);perspective:var(--perspective);perspective-origin:var(--perspective-origin);padding:var(--padding);margin:var(--margin);display:var(--display);align-items:var(--align-items);justify-content:var(--justify-content);width:var(--size);height:var(--size);transition-property:var(--transition-property);transition-duration:var(--transition-duration);transition-delay:var(--transition-delay);transition-timing-function:var(--transition-timing-function)}:host>div{display:block;height:100%;width:100%;max-width:100%;position:relative;background:transparent;transform-style:preserve-3d;transform:var(--animatable-cube-transform, translateZ(-var(--face-size)));transform-origin:var(--animatable-cube-transform-origin, initial);transition:transform var(--transition-duration)}.face{background:var(--animatable-cube-face-background, var(--face-background));position:absolute;height:100%;width:100%;border:var(--face-border);transition:transform var(--transition-duration);transform-origin:var(--face-transform-origin)}.front{transform:rotateY(0deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-front-face-background, var(--face-background));background-size:var(--animatable-cube-front-face-background-size, var(--face-background-size));animation:var(--animatable-cube-front-face-animation, var(--face-animation))}.back{transform:rotateY(180deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-back-face-background, var(--face-background));background-size:var(--animatable-cube-back-face-background-size, var(--face-background-size));animation:var(--animatable-cube-back-face-animation, var(--face-animation))}.right{transform:rotateY(90deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-right-face-background, var(--face-background));background-size:var(--animatable-cube-right-face-background-size, var(--face-background-size));animation:var(--animatable-cube-right-face-animation, var(--face-animation))}.left{transform:rotateY(-90deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-left-face-background, var(--face-background));background-size:var(--animatable-cube-left-face-background-size, var(--face-background-size));animation:var(--animatable-cube-left-face-animation, var(--face-animation))}.top{transform:rotateX(90deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-top-face-background, var(--face-background));background-size:var(--animatable-cube-top-face-background-size, var(--face-background-size));animation:var(--animatable-cube-top-face-animation, var(--face-animation))}.bottom{transform:rotateX(-90deg)\n translateZ(var(--face-size));will-change:transform;background:var(--animatable-cube-bottom-face-background, var(--face-background));background-size:var(--animatable-cube-bottom-face-background-size, var(--face-background-size));animation:var(--animatable-cube-bottom-face-animation, var(--face-animation))}@keyframes backgroundAnimation{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}"; const Cube = class { constructor(hostRef) { registerInstance(this, hostRef); this.onStart = createEvent(this, "start", 3); this.onFinish = createEvent(this, "finish", 3); this.onCancel = createEvent(this, "cancel", 3); /** * Animation manager for Animatable */ this.manager = null; /** * Start the animation when the component is mounted. */ this.autoPlay = false; } get element() { return this.el.shadowRoot.querySelector(':host > div'); } animationDidChangeHandler(animation) { this.keyFrames = getKeyFramesByAnimation(animation); } /** * Get keyFrames of the animation from string data. * @param text - The string with the keyFrames of the animation. */ keyFramesDidChangeHandler(text) { if (text !== undefined) this.keyFrames = JSON.parse(text); } /** * Get options of the animation from string data. * @param text - The string with the options of the animation. */ optionsDidChangeHandler(options) { clearPropsWithOptions(this, options); } /** * Get options of the animation from string data. * @param text - The string with the options of the animation. */ optionsDataDidChangeHandler(text) { if (text !== undefined) this.options = JSON.parse(text); } setCurrenTime(newValue) { this.manager.currentAnimation.currentTime = newValue; } /** * Returns the current time value of the animation in milliseconds, whether running or paused. */ async getCurrentTime() { return Promise.resolve(this.manager.currentAnimation.currentTime); } setStartTime(newValue) { this.manager.currentAnimation.startTime = newValue; } /** * Returns the scheduled time when an animation's playback should begin. */ async getStartTime() { return Promise.resolve(this.manager.currentAnimation.startTime); } /** * Indicates whether the animation is currently waiting * for an asynchronous operation such as initiating playback * or pausing a running animation. */ async getPending() { return Promise.resolve(this.manager.currentAnimation.pending); } setPlaybackRate(newValue) { this.manager.currentAnimation.playbackRate = newValue; } /** * Returns the playback rate of the animation. */ async getPlaybackRate() { return Promise.resolve(this.manager.currentAnimation.playbackRate); } /** * Returns an enumerated value describing the playback state of an animation. */ async getPlayState() { return Promise.resolve(this.manager.currentAnimation.playState); } /** * Clears all `KeyframeEffects` caused by this animation and aborts its playback. */ async cancel() { this.manager.currentAnimation.cancel(); } /** * Sets the current playback time to the end of the animation * corresponding to the current playback direction. */ async finish() { this.manager.currentAnimation.finish(); } /** * Suspends playback of the animation. */ async pause() { this.manager.currentAnimation.pause(); } /** * Starts or resumes playing of an animation. */ async play() { this.manager.playAnimation(); } /** * Reverses the playback direction, meaning the animation ends at its beginning. */ async reverse() { this.manager.currentAnimation.reverse(); } /** * Clear the current animation */ async clear() { this.manager.clearAnimation(); } /** * Destroy the current animation */ async destroy() { if (this.manager !== null) { this.manager.destroyAnimation(); } } /** * Initialize manager */ connectedCallback() { this.manager = new AnimationManager(this); } componentDidLoad() { this.manager.setState(this.element, this); this.manager.savedState(); } componentShouldUpdate() { this.manager.setState(this.element, this); } componentDidUpdate() { this.manager.savedState(); } disconnectedCallback() { this.destroy(); } render() { return (h(Host, null, h("div", null, h("div", { class: "front face" }, h("slot", { name: 'front-face' })), h("div", { class: "back face" }, h("slot", { name: 'back-face' })), h("div", { class: "right face" }, h("slot", { name: 'right-face' })), h("div", { class: "left face" }, h("slot", { name: 'left-face' })), h("div", { class: "top face" }, h("slot", { name: 'top-face' })), h("div", { class: "bottom face" }, h("slot", { name: 'bottom-face' })), h("slot", null)))); } get el() { return getElement(this); } static get watchers() { return { "animation": ["animationDidChangeHandler"], "keyFramesData": ["keyFramesDidChangeHandler"], "options": ["optionsDidChangeHandler"], "optionsData": ["optionsDataDidChangeHandler"], "currentTime": ["setCurrenTime"], "startTime": ["setStartTime"], "playbackRate": ["setPlaybackRate"] }; } }; Cube.style = animatableCubeCss; export { AnimatableComponent as animatable_component, Cube as animatable_cube };