Skip to content

Commit 1d06c6f

Browse files
authored
feat: Customizable dimensions animation type - layout and worklet (#355)
## Description This PR removes `animateHeight` and `animateWidth` props and replaces them with `dimensionsAnimationType` property. This prop is used for both - height and width animation. It is not just a boolean flag but accepts string these values: - `'none'` - no animation - default, - `'layout'` - uses reanimated layout animations for container dimensions animation - more efficient but doesn't influence other components (rendered below, near the sortable component), - `'worklet'` - worklet-based animations using `useAnimatedStyle` - less efficient but also affect layout of other views (if other components are rendered below, near the sortable component)
1 parent dd3143e commit 1d06c6f

10 files changed

Lines changed: 32 additions & 34 deletions

File tree

example/app/src/examples/SortableFlex/features/DataChangeExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ export default function DataChangeExample() {
141141

142142
<Sortable.Flex
143143
columnGap={spacing.sm}
144+
dimensionsAnimationType='worklet'
144145
rowGap={spacing.xs}
145146
scrollableRef={scrollableRef}
146-
animateHeight
147147
hapticsEnabled
148148
onDragEnd={({ order }) => setData(order(data))}>
149149
{data.map(item => (

example/app/src/examples/SortableGrid/features/DataChangeExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,10 @@ export default function DataChangeExample() {
149149
columnGap={spacing.sm}
150150
columns={COLUMNS}
151151
data={data}
152+
dimensionsAnimationType='worklet'
152153
renderItem={renderItem}
153154
rowGap={spacing.xs}
154155
scrollableRef={scrollableRef}
155-
animateHeight
156156
hapticsEnabled
157157
onDragEnd={({ data: newData }) => setData(newData)}
158158
/>

example/app/src/examples/SortableGrid/features/DragHandleExample.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default function DragHandleExample() {
6767
columnGap={10}
6868
columns={columns}
6969
data={DATA}
70+
dimensionsAnimationType='layout'
7071
dragActivationDelay={0}
7172
overDrag={overDrag}
7273
renderItem={renderItem}

example/app/src/examples/SortableGrid/features/OrderingStrategyExample.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ export default function OrderingStrategyExample() {
2525
columnGap={spacing.xs}
2626
columns={COLUMNS}
2727
data={DATA}
28+
dimensionsAnimationType='worklet'
2829
renderItem={renderItem}
2930
rowGap={spacing.xs}
3031
strategy='insert'
31-
animateHeight
3232
/>
3333
</Section>
3434

@@ -39,10 +39,10 @@ export default function OrderingStrategyExample() {
3939
columnGap={spacing.xs}
4040
columns={COLUMNS}
4141
data={DATA}
42+
dimensionsAnimationType='worklet'
4243
renderItem={renderItem}
4344
rowGap={spacing.xs}
4445
strategy='swap'
45-
animateHeight
4646
/>
4747
</Section>
4848
</Stagger>

example/app/src/examples/SortableGrid/miscellaneous/StaggerAnimationExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ export default function StaggerAnimationExample() {
6767
columnGap={10}
6868
columns={3}
6969
data={data}
70+
dimensionsAnimationType='worklet'
7071
overflow='visible'
7172
renderItem={renderItem}
7273
rowGap={10}
73-
animateHeight
7474
onDragEnd={handleDragEnd}
7575
/>
7676

packages/react-native-sortables/src/components/SortableFlex.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ function SortableFlex(props: SortableFlexProps) {
2828
},
2929
sharedProps: {
3030
DropIndicatorComponent,
31-
animateHeight,
32-
animateWidth,
31+
dimensionsAnimationType,
3332
dropIndicatorStyle,
3433
itemEntering,
3534
itemExiting,
@@ -77,9 +76,8 @@ function SortableFlex(props: SortableFlexProps) {
7776
useAdditionalValues={useFlexLayoutContext}
7877
/>
7978
<SortableFlexInner
80-
animateHeight={animateHeight}
81-
animateWidth={animateWidth}
8279
childrenArray={childrenArray}
80+
dimensionsAnimationType={dimensionsAnimationType}
8381
DropIndicatorComponent={DropIndicatorComponent}
8482
dropIndicatorStyle={dropIndicatorStyle}
8583
itemEntering={itemEntering}
@@ -107,8 +105,7 @@ type SortableFlexInnerProps = {
107105
Required<
108106
Pick<
109107
SortableFlexProps,
110-
| 'animateHeight'
111-
| 'animateWidth'
108+
| 'dimensionsAnimationType'
112109
| 'itemEntering'
113110
| 'itemExiting'
114111
| 'itemsLayout'

packages/react-native-sortables/src/components/SortableGrid.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ function SortableGrid<I>(props: SortableGridProps<I>) {
4545
},
4646
sharedProps: {
4747
DropIndicatorComponent,
48-
animateHeight,
49-
animateWidth,
48+
dimensionsAnimationType,
5049
dropIndicatorStyle,
5150
itemEntering,
5251
itemExiting,
@@ -109,10 +108,9 @@ function SortableGrid<I>(props: SortableGridProps<I>) {
109108
useAdditionalValues={useGridLayoutContext}
110109
/>
111110
<SortableGridInner
112-
animateHeight={animateHeight}
113-
animateWidth={animateWidth}
114111
columnGap={columnGapValue}
115112
data={data}
113+
dimensionsAnimationType={dimensionsAnimationType}
116114
DropIndicatorComponent={DropIndicatorComponent}
117115
dropIndicatorStyle={dropIndicatorStyle}
118116
groups={groups}
@@ -142,9 +140,8 @@ type SortableGridInnerProps<I> = {
142140
Required<
143141
Pick<
144142
SortableGridProps<I>,
145-
| 'animateHeight'
146-
| 'animateWidth'
147143
| 'data'
144+
| 'dimensionsAnimationType'
148145
| 'itemEntering'
149146
| 'itemExiting'
150147
| 'itemsLayout'

packages/react-native-sortables/src/components/shared/SortableContainer.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type ViewStyle
77
} from 'react-native';
88
import Animated, {
9+
LinearTransition,
910
useAnimatedStyle,
1011
withTiming
1112
} from 'react-native-reanimated';
@@ -16,30 +17,29 @@ import {
1617
useCommonValuesContext,
1718
useMeasurementsContext
1819
} from '../../providers';
19-
import {
20-
AbsoluteLayoutState,
21-
type DropIndicatorSettings,
22-
type Overflow
20+
import type {
21+
DimensionsAnimation,
22+
DropIndicatorSettings,
23+
Overflow
2324
} from '../../types';
25+
import { AbsoluteLayoutState } from '../../types';
2426
import AnimatedOnLayoutView from './AnimatedOnLayoutView';
2527
import DropIndicator from './DropIndicator';
2628

2729
const SCREEN_DIMENSIONS = Dimensions.get('screen');
2830

2931
type AnimatedHeightContainerProps = PropsWithChildren<
3032
{
31-
animateHeight: boolean;
32-
animateWidth: boolean;
33+
dimensionsAnimationType: DimensionsAnimation;
3334
overflow: Overflow;
3435
style?: StyleProp<ViewStyle>;
3536
} & DropIndicatorSettings
3637
>;
3738

3839
export default function SortableContainer({
3940
DropIndicatorComponent,
40-
animateHeight,
41-
animateWidth,
4241
children,
42+
dimensionsAnimationType,
4343
dropIndicatorStyle,
4444
overflow,
4545
showDropIndicator,
@@ -58,6 +58,9 @@ export default function SortableContainer({
5858
const { handleHelperContainerMeasurement, measurementsContainerRef } =
5959
useMeasurementsContext();
6060

61+
const animateWorklet = dimensionsAnimationType === 'worklet';
62+
const animateLayout = dimensionsAnimationType === 'layout';
63+
6164
const outerContainerStyle = useAnimatedStyle(() => {
6265
if (absoluteLayoutState.value !== AbsoluteLayoutState.COMPLETE) {
6366
return EMPTY_OBJECT;
@@ -73,18 +76,18 @@ export default function SortableContainer({
7376
return {
7477
height: maybeAnimate(
7578
ctrl.height ? containerHeight.value : null,
76-
animateHeight
79+
animateWorklet
7780
),
7881
overflow:
7982
activeItemKey.value !== null || !activeItemDropped.value
8083
? 'visible'
8184
: overflow,
8285
width: maybeAnimate(
8386
ctrl.width ? containerWidth.value : null,
84-
animateWidth
87+
animateWorklet
8588
)
8689
};
87-
}, [animateHeight, animateWidth]);
90+
}, [dimensionsAnimationType]);
8891

8992
const innerContainerStyle = useAnimatedStyle(() => {
9093
if (absoluteLayoutState.value !== AbsoluteLayoutState.COMPLETE) {
@@ -119,6 +122,7 @@ export default function SortableContainer({
119122

120123
return (
121124
<Animated.View
125+
layout={animateLayout ? LinearTransition : undefined}
122126
// @ts-expect-error - contain is a correct CSS prop on web
123127
style={[outerContainerStyle, IS_WEB && { contain: 'layout' }]}>
124128
{showDropIndicator && (

packages/react-native-sortables/src/constants/props.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@ export const DEFAULT_SHARED_PROPS = {
3030
activeItemOpacity: 1,
3131
activeItemScale: 1.1,
3232
activeItemShadowOpacity: 0.2,
33-
animateHeight: false,
34-
animateWidth: false,
3533
autoScrollActivationOffset: 75,
3634
autoScrollDirection: 'vertical',
3735
autoScrollEnabled: true,
3836
autoScrollSpeed: 1,
3937
customHandle: false,
4038
debug: false,
39+
dimensionsAnimationType: 'none',
4140
dragActivationDelay: 200,
4241
dragActivationFailOffset: 5,
4342
dropAnimationDuration: 300,

packages/react-native-sortables/src/types/props/shared.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,14 @@ export type SortableCallbacks = {
222222

223223
export type Overflow = 'hidden' | 'visible';
224224

225+
export type DimensionsAnimation = 'layout' | 'none' | 'worklet';
226+
225227
export type SharedProps = Simplify<
226228
Omit<SortableCallbacks, 'onDragEnd'> &
227229
Partial<
228230
{
229-
/** Whether to animate container height changes when items are moved */
230-
animateHeight: boolean;
231-
/** Whether to animate container width changes when items are moved */
232-
animateWidth: boolean;
231+
/** Whether and how to animate container dimensions changes */
232+
dimensionsAnimationType: DimensionsAnimation;
233233
/** Enable haptic feedback when sorting items */
234234
hapticsEnabled: boolean;
235235
/** Controls whether sorting functionality is enabled */

0 commit comments

Comments
 (0)