UNPKG

react-aria-components

Version:

A library of styleable components built using React Aria

130 lines (122 loc) 6.4 kB
import {useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3} from "./utils.mjs"; import {flushSync as $I3GNx$flushSync} from "react-dom"; import $I3GNx$react, {createContext as $I3GNx$createContext, useRef as $I3GNx$useRef, forwardRef as $I3GNx$forwardRef, useState as $I3GNx$useState, useContext as $I3GNx$useContext} from "react"; import {useLayoutEffect as $I3GNx$useLayoutEffect} from "@react-aria/utils"; import {useObjectRef as $I3GNx$useObjectRef} from "react-aria"; /* * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ const $c8a5a149f625efcf$var$SharedElementContext = /*#__PURE__*/ (0, $I3GNx$createContext)(null); function $c8a5a149f625efcf$export$758399f318e6385a(props) { let ref = (0, $I3GNx$useRef)({}); return /*#__PURE__*/ (0, $I3GNx$react).createElement($c8a5a149f625efcf$var$SharedElementContext.Provider, { value: ref }, props.children); } const $c8a5a149f625efcf$export$c34620ff8881d89f = /*#__PURE__*/ (0, $I3GNx$forwardRef)(function SharedElement(props, ref) { let { name: name, isVisible: isVisible = true, children: children, className: className, style: style, ...divProps } = props; let [state, setState] = (0, $I3GNx$useState)(isVisible ? 'visible' : 'hidden'); let scopeRef = (0, $I3GNx$useContext)($c8a5a149f625efcf$var$SharedElementContext); if (!scopeRef) throw new Error('<SharedElement> must be rendered inside a <SharedElementTransition>'); if (isVisible && state === 'hidden') setState('visible'); ref = (0, $I3GNx$useObjectRef)(ref); (0, $I3GNx$useLayoutEffect)(()=>{ let element = ref.current; let scope = scopeRef.current; let prevSnapshot = scope[name]; let frame = null; if (element && isVisible && prevSnapshot) { // Element is transitioning from a previous instance. setState('visible'); let animations = element.getAnimations(); // Set properties to animate from. let values = prevSnapshot.style.map(([property, prevValue])=>{ let value = element.style[property]; if (property === 'translate') { let prevRect = prevSnapshot.rect; let currentItem = element.getBoundingClientRect(); let deltaX = prevRect.left - (currentItem === null || currentItem === void 0 ? void 0 : currentItem.left); let deltaY = prevRect.top - (currentItem === null || currentItem === void 0 ? void 0 : currentItem.top); element.style.translate = `${deltaX}px ${deltaY}px`; } else element.style[property] = prevValue; return [ property, value ]; }); // Cancel any new animations triggered by these properties. for (let a of element.getAnimations())if (!animations.includes(a)) a.cancel(); // Remove overrides after one frame to animate to the current values. frame = requestAnimationFrame(()=>{ frame = null; for (let [property, value] of values)element.style[property] = value; }); delete scope[name]; } else if (element && isVisible && !prevSnapshot) { // No previous instance exists, apply the entering state. queueMicrotask(()=>(0, $I3GNx$flushSync)(()=>setState('entering'))); frame = requestAnimationFrame(()=>{ frame = null; setState('visible'); }); } else if (element && !isVisible) // Wait until layout effects finish, and check if a snapshot still exists. // If so, no new SharedElement consumed it, so enter the exiting state. queueMicrotask(()=>{ if (scope[name]) { delete scope[name]; (0, $I3GNx$flushSync)(()=>setState('exiting')); Promise.all(element.getAnimations().map((a)=>a.finished)).then(()=>setState('hidden')).catch(()=>{}); } else // Snapshot was consumed by another instance, unmount. setState('hidden'); }); return ()=>{ if (frame != null) cancelAnimationFrame(frame); if (element && element.isConnected && !element.hasAttribute('data-exiting')) { // On unmount, store a snapshot of the rectangle and computed style for transitioning properties. let style = window.getComputedStyle(element); if (style.transitionProperty !== 'none') { let transitionProperty = style.transitionProperty.split(/\s*,\s*/); scope[name] = { rect: element.getBoundingClientRect(), style: transitionProperty.map((p)=>[ p, style[p] ]) }; } } }; }, [ ref, scopeRef, name, isVisible ]); let renderProps = (0, $64fa3d84918910a7$export$4d86445c2cf5e3)({ children: children, className: className, style: style, values: { isEntering: state === 'entering', isExiting: state === 'exiting' } }); if (state === 'hidden') return null; return /*#__PURE__*/ (0, $I3GNx$react).createElement("div", { ...divProps, ...renderProps, ref: ref, "data-entering": state === 'entering' || undefined, "data-exiting": state === 'exiting' || undefined }); }); export {$c8a5a149f625efcf$export$758399f318e6385a as SharedElementTransition, $c8a5a149f625efcf$export$c34620ff8881d89f as SharedElement}; //# sourceMappingURL=SharedElementTransition.module.js.map