UNPKG

stream-chat-react-native-core

Version:

The official React Native and Expo components for Stream Chat, a service for building chat applications

355 lines 14.7 kB
Object.defineProperty(exports, "__esModule", { value: true }); exports.MessageOverlayHostLayer = exports.DefaultMessageOverlayBackground = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _reactNativeSafeAreaContext = require("react-native-safe-area-context"); var _reactNativeTeleport = require("react-native-teleport"); var _ClosingPortalHostsLayer = require("./ClosingPortalHostsLayer"); var _useA11yLabel = require("../../a11y/hooks/useA11yLabel"); var _useAccessibilityAnnouncer = require("../../components/Accessibility/useAccessibilityAnnouncer"); var _hooks = require("../../hooks"); var _stateStore = require("../../state-store"); var _ComponentsContext = require("../componentsContext/ComponentsContext"); var _ThemeContext = require("../themeContext/ThemeContext"); var _jsxRuntime = require("react/jsx-runtime"); var _jsxFileName = "/home/runner/work/stream-chat-react-native/stream-chat-react-native/package/src/contexts/overlayContext/MessageOverlayHostLayer.tsx"; function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } var DURATION = 300; var DefaultMessageOverlayBackground = () => { var _useTheme = (0, _ThemeContext.useTheme)(), semantics = _useTheme.theme.semantics; return (0, _jsxRuntime.jsx)(_reactNative.View, { pointerEvents: "none", style: _reactNative.StyleSheet.absoluteFill, children: (0, _jsxRuntime.jsx)(_reactNative.View, { pointerEvents: "none", style: [_reactNative.StyleSheet.absoluteFill, { backgroundColor: semantics.badgeBgOverlay }] }) }); }; exports.DefaultMessageOverlayBackground = DefaultMessageOverlayBackground; var MessageOverlayHostLayer = () => { var _useComponentsContext = (0, _ComponentsContext.useComponentsContext)(), MessageActions = _useComponentsContext.MessageActions, MessageOverlayBackground = _useComponentsContext.MessageOverlayBackground; var _useOverlayController = (0, _stateStore.useOverlayController)(), id = _useOverlayController.id, closing = _useOverlayController.closing; var insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)(); var _useWindowDimensions = (0, _reactNative.useWindowDimensions)(), screenH = _useWindowDimensions.height; var messageH = (0, _reactNativeReanimated.useSharedValue)(undefined); var topH = (0, _reactNativeReanimated.useSharedValue)(undefined); var bottomH = (0, _reactNativeReanimated.useSharedValue)(undefined); var closeCorrectionY = (0, _reactNativeReanimated.useSharedValue)(0); var topInset = insets.top; var bottomInset = insets.bottom === 0 && _reactNative.Platform.OS === 'android' ? 60 : insets.bottom; var isActive = !!id; var announce = (0, _useAccessibilityAnnouncer.useAccessibilityAnnouncer)(); var overlayOpenHint = (0, _useA11yLabel.useA11yLabel)('a11y/Swipe right to go through different actions'); var announcedOpenRef = (0, _react.useRef)(false); (0, _react.useEffect)(() => { if (isActive) { if (overlayOpenHint && !announcedOpenRef.current) { announce(overlayOpenHint, 'polite'); announcedOpenRef.current = true; } } else { announcedOpenRef.current = false; } }, [isActive, overlayOpenHint, announce]); var orientation = (0, _hooks.useScreenOrientation)(); var prevOrientationRef = (0, _react.useRef)(orientation); (0, _react.useEffect)(() => { if (prevOrientationRef.current === orientation) { return; } prevOrientationRef.current = orientation; (0, _stateStore.finalizeCloseOverlay)(); }, [orientation]); var padding = 8; var minY = topInset + padding; var maxY = screenH - bottomInset - padding; var scrollY = (0, _reactNativeReanimated.useSharedValue)(0); var scrollStartY = (0, _reactNativeReanimated.useSharedValue)(0); var scrollGeom = (0, _reactNativeReanimated.useDerivedValue)(() => { if (!messageH.value || !topH.value || !bottomH.value) { return { needsScroll: false }; } var available = maxY - minY; var contentH = topH.value.h + messageH.value.h + bottomH.value.h; return { needsScroll: contentH > available }; }); var maxScroll = (0, _reactNativeReanimated.useDerivedValue)(() => { if (!scrollGeom.value.needsScroll || !messageH.value || !topH.value || !bottomH.value) { return 0; } var available = maxY - minY; var contentH = topH.value.h + messageH.value.h + bottomH.value.h; return Math.max(0, contentH - available); }); (0, _react.useEffect)(() => { if (closing) { (0, _reactNativeReanimated.cancelAnimation)(scrollY); } else if (!isActive) { scrollY.value = 0; } }, [closing, isActive, scrollY]); var backdrop = (0, _reactNativeReanimated.useSharedValue)(0); var closeCoverOpacity = (0, _reactNativeReanimated.useSharedValue)(0); (0, _react.useEffect)(() => (0, _stateStore.registerOverlaySharedValueController)({ incrementCloseCorrectionY: deltaY => { closeCorrectionY.value += deltaY; }, resetCloseCorrectionY: () => { closeCorrectionY.value = 0; }, reset: () => { messageH.value = undefined; topH.value = undefined; bottomH.value = undefined; closeCorrectionY.value = 0; }, setBottomH: rect => { bottomH.value = rect; }, setMessageH: rect => { messageH.value = rect; }, setTopH: rect => { topH.value = rect; } }), [bottomH, closeCorrectionY, messageH, topH]); (0, _react.useEffect)(() => { var target = isActive && !closing ? 1 : 0; backdrop.value = (0, _reactNativeReanimated.withSpring)(target, { duration: DURATION + target * 100 }, finished => { if (finished && closing) { (0, _reactNativeReanimated.runOnJS)(_stateStore.finalizeCloseOverlay)(); } }); closeCoverOpacity.value = (0, _reactNativeReanimated.withSpring)(closing ? 1 : 0, { duration: DURATION }); }, [isActive, closing, backdrop, closeCoverOpacity]); var backdropStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({ opacity: backdrop.value })); var OverlayBackground = MessageOverlayBackground; var messageShiftY = (0, _reactNativeReanimated.useDerivedValue)(() => { if (!messageH.value || !topH.value || !bottomH.value) return 0; var anchorY = messageH.value.y; var msgH = messageH.value.h; var minTop = minY + topH.value.h; if (scrollGeom.value.needsScroll) { return minTop - anchorY; } var maxTopWithBottom = maxY - (msgH + bottomH.value.h); var canFitBottomWithoutOverlap = minTop <= maxTopWithBottom; var solvedTop = canFitBottomWithoutOverlap ? (0, _reactNativeReanimated.clamp)(anchorY, minTop, Math.max(minTop, maxTopWithBottom)) : minTop; return solvedTop - anchorY; }); var bottomShiftY = (0, _reactNativeReanimated.useDerivedValue)(() => { if (!messageH.value || !topH.value || !bottomH.value) return 0; var anchorMessageTop = messageH.value.y; var msgH = messageH.value.h; var minMessageTop = minY + topH.value.h; if (scrollGeom.value.needsScroll) { return maxY - bottomH.value.h - bottomH.value.y; } var maxMessageTopWithBottom = maxY - (msgH + bottomH.value.h); var canFitBottomWithoutOverlap = minMessageTop <= maxMessageTopWithBottom; var solvedMessageTop = canFitBottomWithoutOverlap ? (0, _reactNativeReanimated.clamp)(anchorMessageTop, minMessageTop, Math.max(minMessageTop, maxMessageTopWithBottom)) : minMessageTop; var solvedBottomTop = Math.min(solvedMessageTop + msgH, maxY - bottomH.value.h); return solvedBottomTop - bottomH.value.y; }); var topItemStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => { if (!topH.value) return { opacity: 0, height: 0, width: 0 }; var translateY = isActive ? closing ? closeCorrectionY.value : messageShiftY.value : 0; var horizontalPosition = _reactNative.I18nManager.isRTL ? { right: topH.value.x } : { left: topH.value.x }; return { height: topH.value.h, opacity: 1, position: 'absolute', top: topH.value.y, transform: [{ scale: backdrop.value }, { translateY: (0, _reactNativeReanimated.withSpring)(translateY, { duration: DURATION }) }], width: topH.value.w, ...horizontalPosition }; }); var bottomItemStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => { if (!bottomH.value) return { opacity: 0, height: 0, width: 0 }; var translateY = isActive ? closing ? closeCorrectionY.value : bottomShiftY.value : 0; var horizontalPosition = _reactNative.I18nManager.isRTL ? { right: bottomH.value.x } : { left: bottomH.value.x }; return { height: bottomH.value.h, opacity: 1, position: 'absolute', top: bottomH.value.y, transform: [{ scale: backdrop.value }, { translateY: (0, _reactNativeReanimated.withSpring)(translateY, { duration: DURATION }) }], width: bottomH.value.w, ...horizontalPosition }; }); var hostStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => { if (!messageH.value) return { height: 0 }; var scroll = scrollGeom.value.needsScroll ? scrollY.value : 0; var translateY = isActive ? closing ? closeCorrectionY.value + scroll : messageShiftY.value : 0; return { height: messageH.value.h, left: messageH.value.x, position: 'absolute', top: messageH.value.y, transform: [{ translateY: (0, _reactNativeReanimated.withSpring)(translateY, { duration: DURATION }) }, { translateY: scroll === 0 ? 0 : -scroll }], width: messageH.value.w }; }); var pan = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().onBegin(() => { scrollStartY.value = scrollY.value; }).onUpdate(e => { scrollY.value = (0, _reactNativeReanimated.clamp)(scrollStartY.value - e.translationY, 0, maxScroll.value); }).onEnd(e => { scrollY.value = (0, _reactNativeReanimated.withDecay)({ clamp: [0, maxScroll.value], velocity: -e.velocityY }); }), [maxScroll, scrollStartY, scrollY]); var tap = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Tap().onTouchesDown((e, state) => { var t = e.allTouches[0]; if (!t || !topH || !bottomH) return; var x = t.x; var y = t.y; var messageYShift = messageShiftY.value; var bottomYShift = bottomShiftY.value; var top = topH.value; if (top) { var topY = top.y + messageYShift; if (x >= top.x && x <= top.x + top.w && y >= topY && y <= topY + top.h) { state.fail(); return; } } var bot = bottomH.value; if (bot) { var botY = bot.y + bottomYShift; if (x >= bot.x && x <= bot.x + bot.w && y >= botY && y <= botY + bot.h) { state.fail(); return; } } }).onEnd(() => { (0, _reactNativeReanimated.runOnJS)(_stateStore.closeOverlay)(); }).requireExternalGestureToFail(pan), [bottomH, bottomShiftY, messageShiftY, pan, topH]); return (0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, { gesture: tap, children: (0, _jsxRuntime.jsxs)(_reactNative.View, { accessibilityViewIsModal: isActive, pointerEvents: "box-none", style: _reactNative.StyleSheet.absoluteFill, children: [isActive ? (0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { pointerEvents: "none", style: [_reactNative.StyleSheet.absoluteFill, backdropStyle], children: (0, _jsxRuntime.jsx)(OverlayBackground, {}) }) : null, (0, _jsxRuntime.jsxs)(_reactNative.View, { pointerEvents: "box-none", style: _reactNative.StyleSheet.absoluteFill, children: [isActive ? (0, _jsxRuntime.jsx)(_reactNative.Pressable, { onPress: _stateStore.closeOverlay, style: _reactNative.StyleSheet.absoluteFill, testID: "message-overlay-backdrop" }) : null, MessageActions ? (0, _jsxRuntime.jsx)(MessageActions, { bottomItemStyle: bottomItemStyle, hostStyle: hostStyle, portalHostStyle: styles.absoluteFill, topItemStyle: topItemStyle }) : (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, { gesture: pan, children: (0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: hostStyle, testID: "message-overlay-message", children: (0, _jsxRuntime.jsx)(_reactNativeTeleport.PortalHost, { name: "message-overlay", style: styles.absoluteFill }) }) }), (0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: topItemStyle, testID: "message-overlay-top", children: (0, _jsxRuntime.jsx)(_reactNativeTeleport.PortalHost, { name: "top-item", style: styles.absoluteFill }) }), (0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: bottomItemStyle, testID: "message-overlay-bottom", children: (0, _jsxRuntime.jsx)(_reactNativeTeleport.PortalHost, { name: "bottom-item", style: styles.absoluteFill }) })] })] }), (0, _jsxRuntime.jsx)(_ClosingPortalHostsLayer.ClosingPortalHostsLayer, { closeCoverOpacity: closeCoverOpacity })] }) }); }; exports.MessageOverlayHostLayer = MessageOverlayHostLayer; var styles = _reactNative.StyleSheet.create({ absoluteFill: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 } }); //# sourceMappingURL=MessageOverlayHostLayer.js.map