Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/BottomSheetScaleView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type PropsWithChildren } from 'react';
import { StyleSheet } from 'react-native';
import Animated from 'react-native-reanimated';
import { useScaleAnimatedStyle } from './useScaleAnimation';
import { useBackgroundScaleAnimatedStyle } from './useScaleAnimation';

/**
* Wraps your app content with iOS-style scale animation when a bottom sheet
Expand All @@ -19,7 +19,7 @@ import { useScaleAnimatedStyle } from './useScaleAnimation';
* ```
*/
export function BottomSheetScaleView({ children }: PropsWithChildren) {
const animatedStyle = useScaleAnimatedStyle();
const animatedStyle = useBackgroundScaleAnimatedStyle();

return (
<Animated.View style={[styles.container, animatedStyle]}>
Expand Down
14 changes: 9 additions & 5 deletions src/QueueItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { memo, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
import { useSafeAreaFrame } from 'react-native-safe-area-context';
Expand All @@ -15,23 +15,27 @@ import {
} from './bottomSheet.store';
import { BottomSheetBackdrop } from './BottomSheetBackdrop';
import { cleanupSheetRef } from './refsMap';
import { useScaleAnimatedStyle } from './useScaleAnimation';
import { useSheetScaleAnimatedStyle } from './useScaleAnimation';

interface QueueItemProps {
id: string;
stackIndex: number;
isActive: boolean;
}

export function QueueItem({ id, stackIndex, isActive }: QueueItemProps) {
export const QueueItem = memo(function QueueItem({
id,
stackIndex,
isActive,
}: QueueItemProps) {
const content = useSheetContent(id);
const usePortal = useSheetUsePortal(id);
const keepMounted = useSheetKeepMounted(id);
const portalSession = useSheetPortalSession(id);
const startClosing = useStartClosing();

const { width, height } = useSafeAreaFrame();
const scaleStyle = useScaleAnimatedStyle({ id });
const scaleStyle = useSheetScaleAnimatedStyle(id);

useEffect(() => {
return () => {
Expand Down Expand Up @@ -76,7 +80,7 @@ export function QueueItem({ id, stackIndex, isActive }: QueueItemProps) {
</Animated.View>
</>
);
}
});

const styles = StyleSheet.create({
container: {},
Expand Down
25 changes: 25 additions & 0 deletions src/store/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ export const useIsSheetOpen = (id: string) =>
return status === 'open' || status === 'opening';
}, shallow);

export const useHasScaleBackgroundAbove = (id: string) =>
useBottomSheetStore((state) => {
const { stackOrder, sheetsById } = state;
const sheetIndex = stackOrder.indexOf(id);

if (sheetIndex === -1) {
return false;
}

// Check if any sheet above this one has scaleBackground
for (let i = sheetIndex + 1; i < stackOrder.length; i++) {
const aboveId = stackOrder[i]!;
const aboveSheet = sheetsById[aboveId];
if (
aboveSheet &&
aboveSheet.scaleBackground &&
aboveSheet.status !== 'closing' &&
aboveSheet.status !== 'hidden'
) {
return true;
}
}
return false;
}, shallow);

// Action hooks

export const useOpen = () => useBottomSheetStore((state) => state.open);
Expand Down
30 changes: 18 additions & 12 deletions src/useScaleAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const DEFAULT_CONFIG = {
} satisfies Required<ScaleConfig>;

function useBackgroundScaleDepth(groupId: string): number {
return useBottomSheetStore((state) => {
const depth = useBottomSheetStore((state) => {
const { stackOrder, sheetsById } = state;

for (let i = 0; i < stackOrder.length; i++) {
Expand All @@ -55,6 +55,7 @@ function useBackgroundScaleDepth(groupId: string): number {
}
return 0;
});
return depth;
}

function useSheetScaleDepth(
Expand All @@ -63,7 +64,7 @@ function useSheetScaleDepth(
): number {
const prevDepthRef = useRef(0);

return useBottomSheetStore((state) => {
const result = useBottomSheetStore((state) => {
if (!sheetId) {
return 0;
}
Expand Down Expand Up @@ -93,10 +94,11 @@ function useSheetScaleDepth(
prevDepthRef.current = depth;
return depth;
});
return result;
}

export function useScaleAnimatedStyle({ id }: { id?: string } = {}) {
const { groupId, scaleConfig } = useBottomSheetManagerContext();
function useScaleAnimatedStyleInternal(scaleDepth: number) {
const { scaleConfig } = useBottomSheetManagerContext();

const {
scale = DEFAULT_CONFIG.scale,
Expand All @@ -105,14 +107,6 @@ export function useScaleAnimatedStyle({ id }: { id?: string } = {}) {
animation = DEFAULT_CONFIG.animation,
} = scaleConfig ?? {};

const isBackground = id === undefined;

const backgroundDepth = useBackgroundScaleDepth(groupId);
const sheetDepth = useSheetScaleDepth(groupId, id);

const scaleDepth = isBackground ? backgroundDepth : sheetDepth;

// Animate the depth change
const progress = useDerivedValue(() => {
if (animation.type === 'spring') {
return withSpring(scaleDepth, animation.config);
Expand Down Expand Up @@ -142,3 +136,15 @@ export function useScaleAnimatedStyle({ id }: { id?: string } = {}) {
};
});
}

export function useBackgroundScaleAnimatedStyle() {
const { groupId } = useBottomSheetManagerContext();
const scaleDepth = useBackgroundScaleDepth(groupId);
return useScaleAnimatedStyleInternal(scaleDepth);
}

export function useSheetScaleAnimatedStyle(sheetId: string) {
const { groupId } = useBottomSheetManagerContext();
const scaleDepth = useSheetScaleDepth(groupId, sheetId);
return useScaleAnimatedStyleInternal(scaleDepth);
}
28 changes: 26 additions & 2 deletions src/useSheetRenderData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { shallow } from 'zustand/shallow';
import {
useBottomSheetStore,
type BottomSheetState,
Expand All @@ -11,6 +10,31 @@ export interface SheetRenderItem {
isActive: boolean;
}

/**
* Deep comparison for SheetRenderItem arrays.
* Returns true if arrays have same items with same values.
*/
function sheetRenderDataEqual(
a: SheetRenderItem[],
b: SheetRenderItem[]
): boolean {
if (a.length !== b.length) return false;

for (let i = 0; i < a.length; i++) {
const itemA = a[i]!;
const itemB = b[i]!;
if (
itemA.id !== itemB.id ||
itemA.stackIndex !== itemB.stackIndex ||
itemA.isActive !== itemB.isActive
) {
return false;
}
}

return true;
}

/**
* Returns a flat list of sheets to render.
*
Expand All @@ -29,7 +53,7 @@ export function useSheetRenderData(): SheetRenderItem[] {
const active = getActiveSheets(state, groupId);

return [...hiddenPersistent, ...active];
}, shallow);
}, sheetRenderDataEqual);
}

function getHiddenPersistentSheets(
Expand Down
Loading