"use strict";
'use client';
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZoomTransitionSourceContextProvider = ZoomTransitionSourceContextProvider;
exports.ZoomTransitionTargetContextProvider = ZoomTransitionTargetContextProvider;
const react_1 = require("react");
const ZoomTransitionEnabler_1 = require("./ZoomTransitionEnabler");
const zoom_transition_context_1 = require("./zoom-transition-context");
const navigationParams_1 = require("../../navigationParams");
const url_1 = require("../../utils/url");
const PreviewRouteContext_1 = require("../preview/PreviewRouteContext");
function ZoomTransitionSourceContextProvider({ children, linkProps, }) {
const { href, asChild } = linkProps;
const isExternalHref = typeof href === 'string' ? (0, url_1.shouldLinkExternally)(href) : (0, url_1.shouldLinkExternally)(href.pathname);
const numberOfSources = (0, react_1.useRef)(0);
const [hasZoomSource, setHasZoomSource] = (0, react_1.useState)(false);
const zoomTransitionId = (0, react_1.useId)();
const addSource = (0, react_1.useCallback)(() => {
if (!(0, ZoomTransitionEnabler_1.isZoomTransitionEnabled)()) {
throw new Error('[expo-router] Zoom transitions are not enabled.');
}
if (numberOfSources.current >= 1) {
throw new Error('[expo-router] Only one Link.ZoomTransitionSource can be used within a single Link component.');
}
if (!asChild) {
throw new Error('[expo-router] Link must be used with `asChild` prop to enable zoom transitions.');
}
if (isExternalHref) {
throw new Error('[expo-router] Zoom transitions can only be used with internal links.');
}
numberOfSources.current += 1;
setHasZoomSource(true);
}, [asChild, isExternalHref]);
const removeSource = (0, react_1.useCallback)(() => {
numberOfSources.current -= 1;
if (numberOfSources.current <= 0) {
setHasZoomSource(false);
}
}, []);
const value = (0, react_1.useMemo)(() => ({
identifier: zoomTransitionId,
hasZoomSource,
addSource,
removeSource,
}), [zoomTransitionId, hasZoomSource, addSource, removeSource]);
return {children};
}
function ZoomTransitionTargetContextProvider({ route, children, }) {
const [dismissalBoundsRect, setDismissalBoundsRect] = (0, react_1.useState)(null);
// TODO(@ubax): Move this logic to within NativeStackView
// https://linear.app/expo/issue/ENG-19580/remove-hasenabler-logic-from-zoomtransitiontargetcontext
// This is a temporary solution to detect if zoom transition was enabled for the screen
// In theory we could do all the checks here and only mount the enabler when all conditions are met
// However this would require using use(DescriptorsContext) here,
// which would cause unnecessary re-renders of the entire screen whenever descriptors change
const [numberOfEnablers, setNumberOfEnablers] = (0, react_1.useState)(0);
const addEnabler = (0, react_1.useCallback)(() => setNumberOfEnablers((prev) => prev + 1), []);
const removeEnabler = (0, react_1.useCallback)(() => setNumberOfEnablers((prev) => prev - 1), []);
const hasEnabler = numberOfEnablers > 0;
const isPreview = (0, PreviewRouteContext_1.useIsPreview)();
if ((0, ZoomTransitionEnabler_1.isZoomTransitionEnabled)() &&
!isPreview &&
route &&
typeof route === 'object' &&
'params' in route &&
typeof route.params === 'object' &&
'key' in route &&
typeof route.key === 'string') {
const params = route.params ?? {};
const internalParams = (0, navigationParams_1.getInternalExpoRouterParams)(params);
const zoomTransitionId = internalParams[navigationParams_1.INTERNAL_EXPO_ROUTER_ZOOM_TRANSITION_SOURCE_ID_PARAM_NAME];
const zoomTransitionScreenId = internalParams[navigationParams_1.INTERNAL_EXPO_ROUTER_ZOOM_TRANSITION_SCREEN_ID_PARAM_NAME];
const hasZoomTransition = !!zoomTransitionId && zoomTransitionScreenId === route.key;
if (hasZoomTransition && typeof zoomTransitionId === 'string') {
return (
{children}
);
}
}
return children;
}
//# sourceMappingURL=zoom-transition-context-providers.ios.js.map