Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useState } from 'react';
import type { ViewStyle } from 'react-native';
import { StyleSheet, Text } from 'react-native';
import Animated, {
LinearTransition,
Expand All @@ -7,58 +8,108 @@
import type { SortableGridRenderItem } from 'react-native-sortables';
import Sortable from 'react-native-sortables';

import { Group, Screen } from '@/components';
import { Group, Screen, Section } from '@/components';
import { IS_WEB } from '@/constants';
import { colors, radius, sizes, spacing, style, text } from '@/theme';

const DATA = Array.from({ length: 20 }, (_, index) => `Item ${index + 1}`);
const DATA = Array.from({ length: 15 }, (_, index) => `Item ${index + 1}`);

export default function CollapsibleItemsExample() {
return (
<Screen includeNavBarHeight>
<Section
description='With vertical auto-scroll'
padding='none'
title='Vertical'
fill>
<Example />
</Section>
<Section
description='With horizontal auto-scroll '
padding='none'
title='Horizontal'>
<Example horizontal />
</Section>
</Screen>
);
}

type ExampleProps = {
horizontal?: boolean;
};

function Example({ horizontal }: ExampleProps) {
const [collapsed, setCollapsed] = useState(false);
const scrollableRef = useAnimatedRef<Animated.ScrollView>();

const dimension = horizontal ? 'width' : 'height';

const renderItem = useCallback<SortableGridRenderItem<string>>(
({ item }) => (
<Animated.View
layout={LinearTransition.delay(40)}
style={[styles.card, { height: collapsed ? sizes.lg : sizes.xxxl }]}>
<Animated.Text layout={LinearTransition.delay(40)} style={styles.text}>
layout={LinearTransition}
style={[
styles.card,
{ [dimension]: collapsed ? sizes.lg : sizes.xxxl }
]}>
<Animated.Text layout={LinearTransition} style={styles.text}>
{item}
</Animated.Text>
</Animated.View>
),
[collapsed]
[collapsed, dimension]
);

const props = horizontal
? ({
autoScrollDirection: 'horizontal',
columnGap: 10,
overDrag: 'horizontal',
rowHeight: sizes.xl,
rows: 1
} as const)
: ({
overDrag: 'vertical',
rowGap: 10
} as const);

const groupStyle: ViewStyle = horizontal
? { height: sizes.xl, width: sizes.xxl }
: { height: sizes.xl };

return (
<Screen>
<Animated.ScrollView
contentContainerStyle={[styles.container, IS_WEB && style.webContent]}
ref={scrollableRef}>
<Group style={styles.group} withMargin={false} bordered center>
<Text style={styles.title}>Above Collapsible Items</Text>
</Group>
<Animated.ScrollView
contentContainerStyle={[styles.container, IS_WEB && style.webContent]}
horizontal={horizontal}
ref={scrollableRef}>
<Group style={groupStyle} withMargin={false} bordered center>
<Text style={styles.title}>Before Collapsible Items</Text>
</Group>

<Sortable.Grid
activeItemScale={1.05}
autoScrollMaxOverscroll={[50, 120]}
columnGap={10}
data={DATA}
overDrag='vertical'
overflow='visible'
renderItem={renderItem}
rowGap={10}
// scrollableRef={scrollableRef} // TODO - add correct auto scroll support for collapsible items
// autoAdjustOffsetDuringDrag
onActiveItemDropped={() => setCollapsed(false)}
onDragStart={() => setCollapsed(true)}
/>
<Sortable.Grid
{...props}
activeItemScale={1.05}
autoScrollMaxVelocity={750}
data={DATA}
dimensionsAnimationType='worklet'
overflow='visible'
renderItem={renderItem}
scrollableRef={scrollableRef}
autoAdjustOffsetDuringDrag
onActiveItemDropped={() => {
console.log('onActiveItemDropped');

Check warning on line 100 in example/app/src/examples/SortableGrid/miscellaneous/CollapsibleItemsExample.tsx

View workflow job for this annotation

GitHub Actions / check

Unexpected console statement. Only these console methods are allowed: warn, error
setCollapsed(false);
}}
onDragStart={() => {
console.log('onDragStart');

Check warning on line 104 in example/app/src/examples/SortableGrid/miscellaneous/CollapsibleItemsExample.tsx

View workflow job for this annotation

GitHub Actions / check

Unexpected console statement. Only these console methods are allowed: warn, error
setCollapsed(true);
}}
/>

<Group style={styles.group} withMargin={false} bordered center>
<Text style={styles.title}>Below Collapsible Items</Text>
</Group>
</Animated.ScrollView>
</Screen>
<Group style={groupStyle} withMargin={false} bordered center>
<Text style={styles.title}>After Collapsible Items</Text>
</Group>
</Animated.ScrollView>
);
}

Expand All @@ -72,19 +123,13 @@
},
container: {
gap: spacing.md,
padding: spacing.md,
paddingBottom: 120
},
group: {
height: sizes.xxl
padding: spacing.md
},
text: {
...text.label2,
color: colors.white
},
title: {
...text.subHeading2,
marginLeft: spacing.md,
marginTop: spacing.sm
...text.subHeading2
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ function SortableGridComponent<I>({
const { handleContainerMeasurement, resetMeasurements } =
useMeasurementsContext();
const { mainGroupSize } = useGridLayoutContext();

const isFirstRenderRef = useRef(true);

useOrderUpdater(strategy, GRID_STRATEGIES);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export default function ActiveItemPortal({
if (!checkTeleported()) return;

const update = () =>
checkTeleported() &&
teleport?.(teleportedItemId, renderTeleportedItemCell());

if (isFirstUpdateRef.current) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ export default function ItemCell({
activationAnimationProgress
);

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

return (
<Animated.View style={[baseStyle, styles.decoration, animatedStyle]}>
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-sortables/src/constants/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export const DEFAULT_SHARED_PROPS = {

export const DEFAULT_SORTABLE_GRID_PROPS = {
autoAdjustOffsetDuringDrag: false,
autoAdjustOffsetResetTimeout: 1000,
autoAdjustOffsetScrollPadding: 25,
columnGap: 0,
columns: 1,
keyExtractor: defaultKeyExtractor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function setAnimatedTimeout<F extends AnyFunction>(
return;
}
startTimestamp ??= newTimestamp;
if (newTimestamp >= startTimestamp + delay) {
if (newTimestamp > startTimestamp + delay) {
removeFromPendingTimeouts(currentId);
callback();
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './animatedTimeout';
export * from './interpolation';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'worklet';

import { Extrapolation, interpolate } from 'react-native-reanimated';

import type { Vector } from '../../../types/layout';

export const interpolateVector = (
progress: number,
from: Vector,
to: Vector,
extrapolation?: Extrapolation
) => {
const inputRange = [0, 1];
const extrapolate = extrapolation ?? Extrapolation.CLAMP;
return {
x: interpolate(progress, inputRange, [from.x, to.x], extrapolate),
y: interpolate(progress, inputRange, [from.y, to.y], extrapolate)
};
};

This file was deleted.

Loading
Loading