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
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ function SortableGridInner<I>({
flexBasis: mainGroupSize.value ? undefined : `${100 / groups}%`,
paddingHorizontal: columnGap.value / 2,
width: mainGroupSize.value
? mainGroupSize.value + columnGap.value
: undefined
}
: { height: rowHeight }
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import type { PropsWithChildren } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import type { ManualGesture } from 'react-native-gesture-handler';
import {
runOnJS,
type SharedValue,
useAnimatedReaction
} from 'react-native-reanimated';
import { runOnJS, useAnimatedReaction } from 'react-native-reanimated';

import { useStableCallback } from '../../../hooks';
import type { AnimatedStyleProp } from '../../../integrations/reanimated';
import { useMutableValue } from '../../../integrations/reanimated';
import {
CommonValuesContext,
Expand All @@ -17,23 +12,25 @@ import {
} from '../../../providers';
import type { CommonValuesContextType } from '../../../types';
import { getContextProvider } from '../../../utils';
import type { ItemCellProps } from './ItemCell';
import TeleportedItemCell from './TeleportedItemCell';

const CommonValuesContextProvider = getContextProvider(CommonValuesContext);

type ActiveItemPortalProps = PropsWithChildren<{
itemKey: string;
activationAnimationProgress: SharedValue<number>;
commonValuesContext: CommonValuesContextType;
cellStyle: AnimatedStyleProp;
isActive: SharedValue<boolean>;
gesture: ManualGesture;
onTeleport: (isTeleported: boolean) => void;
}>;
type ActiveItemPortalProps = PropsWithChildren<
Pick<
ItemCellProps,
'activationAnimationProgress' | 'baseStyle' | 'isActive' | 'itemKey'
> & {
commonValuesContext: CommonValuesContextType;
gesture: ManualGesture;
onTeleport: (isTeleported: boolean) => void;
}
>;

export default function ActiveItemPortal({
activationAnimationProgress,
cellStyle,
baseStyle,
children,
commonValuesContext,
gesture,
Expand All @@ -58,8 +55,7 @@ export default function ActiveItemPortal({
itemKey={itemKey}>
<TeleportedItemCell
activationAnimationProgress={activationAnimationProgress}
cellStyle={cellStyle}
innerCellStyle={commonValuesContext.controlledDimensionsStyle}
baseStyle={baseStyle}
isActive={isActive}
itemKey={itemKey}>
{children}
Expand All @@ -74,7 +70,7 @@ export default function ActiveItemPortal({
gesture,
isActive,
itemKey,
cellStyle
baseStyle
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
ItemContextProvider,
useCommonValuesContext,
useDragContext,
useItemLayout,
useItemPanGesture,
useItemStyles,
useMeasurementsContext,
usePortalContext
} from '../../../providers';
Expand All @@ -44,13 +44,16 @@ function DraggableView({
const { handleItemMeasurement, removeItemMeasurements } =
useMeasurementsContext();
const { handleDragEnd } = useDragContext();
const { activeItemKey, controlledDimensionsStyle, customHandle } =
commonValuesContext;
const { activeItemKey, customHandle } = commonValuesContext;

const [isHidden, setIsHidden] = useState(false);
const activationAnimationProgress = useMutableValue(0);
const isActive = useDerivedValue(() => activeItemKey.value === key);
const layoutStyle = useItemStyles(key, isActive, activationAnimationProgress);
const layoutStyleValue = useItemLayout(
key,
isActive,
activationAnimationProgress
);
const gesture = useItemPanGesture(key, activationAnimationProgress);

useEffect(() => {
Expand All @@ -75,13 +78,13 @@ function DraggableView({
const innerComponent = (
<ItemCell
activationAnimationProgress={activationAnimationProgress}
cellStyle={[style, layoutStyle]}
baseStyle={style}
entering={itemEntering ?? undefined}
exiting={itemExiting ?? undefined}
hidden={hidden}
innerCellStyle={controlledDimensionsStyle}
isActive={isActive}
itemKey={key}
layoutStyleValue={layoutStyleValue}
onLayout={onLayout}>
<LayoutAnimationConfig skipEntering={false} skipExiting={false}>
{children}
Expand Down Expand Up @@ -121,7 +124,7 @@ function DraggableView({
{renderItemCell(isHidden)}
<ActiveItemPortal
activationAnimationProgress={activationAnimationProgress}
cellStyle={style}
baseStyle={style}
commonValuesContext={commonValuesContext}
gesture={gesture}
isActive={isActive}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import type { PropsWithChildren } from 'react';
import { type LayoutChangeEvent, StyleSheet } from 'react-native';
import type { SharedValue } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';
import {
type LayoutChangeEvent,
Platform,
StyleSheet,
type ViewStyle
} from 'react-native';
import type { SharedValue, TransformArrayItem } from 'react-native-reanimated';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';

import { HIDDEN_X_OFFSET } from '../../../constants';
import type {
AnimatedStyleProp,
LayoutAnimation
} from '../../../integrations/reanimated';
import { useItemDecorationStyles } from '../../../providers';
import { useItemDecoration } from '../../../providers';
import AnimatedOnLayoutView from '../AnimatedOnLayoutView';

type TransformsArray = Array<TransformArrayItem>;

export type ItemCellProps = PropsWithChildren<{
itemKey: string;
isActive: SharedValue<boolean>;
activationAnimationProgress: SharedValue<number>;
innerCellStyle: AnimatedStyleProp;
cellStyle: AnimatedStyleProp;
baseStyle: AnimatedStyleProp;
layoutStyleValue: SharedValue<ViewStyle>;
hidden?: boolean;
entering?: LayoutAnimation;
exiting?: LayoutAnimation;
Expand All @@ -25,28 +32,37 @@ export type ItemCellProps = PropsWithChildren<{

export default function ItemCell({
activationAnimationProgress,
cellStyle,
baseStyle,
children,
entering,
exiting,
hidden,
innerCellStyle,
isActive,
itemKey,
layoutStyleValue,
onLayout
}: ItemCellProps) {
const decorationStyles = useItemDecorationStyles(
const decorationStyleValue = useItemDecoration(
itemKey,
isActive,
activationAnimationProgress
);

const animatedStyle = useAnimatedStyle(() => ({
...decorationStyleValue.value,
...layoutStyleValue.value,
transform: [
...((layoutStyleValue.value.transform ?? []) as TransformsArray),
...((decorationStyleValue.value.transform ?? []) as TransformsArray)
]
}));

return (
<Animated.View style={cellStyle}>
<Animated.View style={[baseStyle, styles.decoration, animatedStyle]}>
<AnimatedOnLayoutView
entering={entering}
exiting={exiting}
style={[decorationStyles, innerCellStyle, hidden && styles.hidden]}
style={hidden && styles.hidden}
onLayout={onLayout}>
{children}
</AnimatedOnLayoutView>
Expand All @@ -55,6 +71,18 @@ export default function ItemCell({
}

const styles = StyleSheet.create({
decoration: Platform.select<ViewStyle>({
android: {},
default: {},
native: {
shadowOffset: {
height: 0,
width: 0
},
shadowOpacity: 1,
shadowRadius: 5
}
}),
hidden: {
// We change the x position to hide items when teleported (we can't use
// non-layout props like opacity as they are sometimes not updated via
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
import { LayoutAnimationConfig } from 'react-native-reanimated';

import { useTeleportedItemStyles } from '../../../providers';
import { useTeleportedItemLayout } from '../../../providers';
import type { ItemCellProps } from './ItemCell';
import ItemCell from './ItemCell';

type TeleportedItemCellProps = Pick<
ItemCellProps,
| 'activationAnimationProgress'
| 'cellStyle'
| 'baseStyle'
| 'children'
| 'innerCellStyle'
| 'isActive'
| 'itemKey'
| 'onLayout'
>;

export default function TeleportedItemCell({
activationAnimationProgress,
cellStyle,
baseStyle,
children,
innerCellStyle,
isActive,
itemKey,
onLayout
}: TeleportedItemCellProps) {
const teleportedItemStyles = useTeleportedItemStyles(
const teleportedItemLayoutValue = useTeleportedItemLayout(
itemKey,
isActive,
activationAnimationProgress
Expand All @@ -33,10 +31,10 @@ export default function TeleportedItemCell({
return (
<ItemCell
activationAnimationProgress={activationAnimationProgress}
cellStyle={[cellStyle, teleportedItemStyles]}
innerCellStyle={innerCellStyle}
baseStyle={baseStyle}
isActive={isActive}
itemKey={itemKey}
layoutStyleValue={teleportedItemLayoutValue}
onLayout={onLayout}>
<LayoutAnimationConfig skipEntering>{children}</LayoutAnimationConfig>
</ItemCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ const { GridLayoutProvider, useGridLayoutContext } = createProvider(
const crossGap = isVertical ? rowGap : columnGap;

const mainGroupSize = useMutableValue<null | number>(null);
const shouldAnimateTimeoutId = useMutableValue<null | ReturnType<
typeof setTimeout
>>(null);

// MAIN GROUP SIZE UPDATER
useAnimatedReaction(
Expand Down Expand Up @@ -144,13 +147,25 @@ const { GridLayoutProvider, useGridLayoutContext } = createProvider(

// On the web, animate layout only if parent container is not resized
// (e.g. skip animation when the browser window is resized)
shouldAnimateLayout.value =
!IS_WEB ||
!previousProps?.itemHeights ||
!previousProps?.itemWidths ||
isVertical
? props.itemWidths === previousProps?.itemWidths
: props.itemHeights === previousProps?.itemHeights;
if (IS_WEB) {
const shouldAnimate =
!previousProps?.itemHeights ||
!previousProps?.itemWidths ||
(isVertical
? props.itemWidths === previousProps?.itemWidths
: props.itemHeights === previousProps?.itemHeights);

if (shouldAnimateTimeoutId.value !== null) {
clearTimeout(shouldAnimateTimeoutId.value);
}
if (!shouldAnimate) {
shouldAnimateLayout.value = false;
}
// Enable after timeout when the user stops resizing the browser window
shouldAnimateTimeoutId.value = setTimeout(() => {
shouldAnimateLayout.value = true;
}, 100);
}

// DEBUG ONLY
if (debugCrossGapRects) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,10 @@ function AutoScrollUpdater({
// position of the view is not changed (because of too small scroll distance).
position += targetScrollOffset.value - currentScrollOffset.value;
}

return {
bounds: contentAxisBounds.value,
position
};
return position;
},
({ bounds, position }) => {
if (!position || !bounds) {
position => {
if (position === null) {
debug?.hideDebugViews?.();
return;
}
Expand All @@ -183,7 +179,6 @@ function AutoScrollUpdater({
contentContainerMeasurements,
scrollContainerMeasurements,
activationOffset,
bounds,
maxOverscroll,
autoScrollExtrapolation
);
Expand Down
Loading
Loading