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 @@ -80,6 +80,7 @@ export default function DragHandleExample() {
style={flex.fill}>
<Sortable.Grid
activeItemScale={1}
autoScrollMaxOverscroll={[50, 120]}
columnGap={10}
columns={columns}
data={DATA}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
KeyboardAvoidingView,
StyleSheet,
Text,
TextInput,
View
} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import type { SortableGridRenderItem } from 'react-native-sortables';
import Sortable from 'react-native-sortables';

Expand Down
8 changes: 4 additions & 4 deletions example/expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"name": "example-expo",
"version": "1.0.0",
"dependencies": {
"expo": "54.0.0-preview.11",
"expo-status-bar": "~3.0.5",
"expo": "54.0.0-preview.16",
"expo-status-bar": "~3.0.7",
"react": "19.1.0",
"react-native": "0.81.1",
"react-native-gesture-handler": "~2.28.0",
"react-native-reanimated": "~4.0.2",
"react-native-worklets": "0.4.2"
"react-native-reanimated": "~4.1.0",
"react-native-worklets": "~0.5.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native-sortables/bob.config.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module.exports = {
source: 'src',
output: 'dist',
exclude: '{**/{__tests__,__fixtures__,__mocks__}/**,**/*.test.{js,jsx,ts,tsx}}',
exclude:
'{**/{__tests__,__fixtures__,__mocks__}/**,**/*.test.{js,jsx,ts,tsx}}',
targets: [
['module', { configFile: true }],
['typescript', { project: 'tsconfig.build.json' }]
Expand Down
22 changes: 6 additions & 16 deletions packages/react-native-sortables/src/components/SortableFlex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { StyleSheet } from 'react-native';
import { runOnUI, useAnimatedStyle } from 'react-native-reanimated';

import { DEFAULT_SORTABLE_FLEX_PROPS } from '../constants';
import type { RequiredBy } from '../helperTypes';
import type { PropsWithDefaults } from '../hooks';
import { useDragEndHandler, usePropsWithDefaults } from '../hooks';
import { useStableCallbackValues } from '../integrations/reanimated';
import type { FlexStyleProps } from '../providers';
import {
FLEX_STRATEGIES,
FlexProvider,
Expand All @@ -17,11 +17,7 @@ import {
useOrderUpdater,
useStrategyKey
} from '../providers';
import type {
DragEndCallback,
SortableFlexProps,
SortableFlexStyle
} from '../types';
import type { DragEndCallback, SortableFlexProps } from '../types';
import { orderItems, processChildren } from '../utils';
import { SortableContainer } from './shared';

Expand Down Expand Up @@ -71,11 +67,6 @@ const CONTROLLED_ITEM_DIMENSIONS = {
width: false
};

type StyleProps = RequiredBy<
SortableFlexStyle,
keyof SortableFlexStyle & keyof typeof DEFAULT_SORTABLE_FLEX_PROPS
>;

type SortableFlexInnerProps = PropsWithDefaults<
SortableFlexProps,
typeof DEFAULT_SORTABLE_FLEX_PROPS
Expand Down Expand Up @@ -129,13 +120,12 @@ const SortableFlexInner = memo(function SortableFlexInner({
[flexWrap, isColumn, height, width]
);

const styleProps: StyleProps = {
const styleProps: FlexStyleProps = {
alignContent,
alignItems,
columnGap,
columnGap: columnGap ?? gap,
flexDirection,
flexWrap,
gap,
height,
justifyContent,
maxHeight,
Expand All @@ -149,7 +139,7 @@ const SortableFlexInner = memo(function SortableFlexInner({
paddingRight,
paddingTop,
paddingVertical,
rowGap,
rowGap: rowGap ?? gap,
width
} as const;

Expand Down Expand Up @@ -189,7 +179,7 @@ type SortableFlexComponentProps = Pick<
| 'showDropIndicator'
| 'strategy'
> & {
styleProps: StyleProps;
styleProps: FlexStyleProps;
};

function SortableFlexComponent({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,7 @@ function SortableGridComponent<I>({
}
: {
flexBasis: mainGroupSize.value ? undefined : `${100 / groups}%`,
paddingHorizontal: columnGap.value / 2,
width: mainGroupSize.value
? mainGroupSize.value + columnGap.value
: undefined
paddingHorizontal: columnGap.value / 2
}
: { height: rowHeight }
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function ActiveItemPortal({
const teleportedItemId = `${commonValuesContext.containerId}-${itemKey}`;

const enableTeleport = useStableCallback(() => {
// isFirstUpdateRef.current = true;
isFirstUpdateRef.current = true;
teleport?.(teleportedItemId, renderTeleportedItemCell());
onTeleport(true);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {
AnimatedStyleProp,
LayoutAnimation
} from '../../../integrations/reanimated';
import { useItemDecoration } from '../../../providers';
import { useCommonValuesContext, useItemDecoration } from '../../../providers';
import AnimatedOnLayoutView from '../AnimatedOnLayoutView';

type TransformsArray = Array<TransformArrayItem>;
Expand Down Expand Up @@ -42,6 +42,8 @@ export default function ItemCell({
layoutStyleValue,
onLayout
}: ItemCellProps) {
const { controlledItemDimensionsStyle } = useCommonValuesContext();

const decorationStyleValue = useItemDecoration(
itemKey,
isActive,
Expand All @@ -64,7 +66,7 @@ export default function ItemCell({
<AnimatedOnLayoutView
entering={entering}
exiting={exiting}
style={hidden && styles.hidden}
style={[controlledItemDimensionsStyle, hidden && styles.hidden]}
onLayout={onLayout}>
{children}
</AnimatedOnLayoutView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ export default function SortableContainer({
return (
<Animated.View
layout={animateLayout ? LinearTransition : undefined}
// @ts-expect-error - contain is a correct CSS prop on web
style={[outerContainerStyle, IS_WEB && { contain: 'layout' }]}>
style={[
outerContainerStyle,
!controlledContainerDimensions.width && { minWidth: '100%' },
// @ts-expect-error - contain is a correct CSS prop on web
IS_WEB && { contain: 'layout' }
]}>
{/* Drop indicator */}
{showDropIndicator && (
<DropIndicator
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native-sortables/src/constants/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ export const DEFAULT_SHARED_PROPS = {
itemEntering: IS_WEB ? null : SortableItemEntering,
itemExiting: IS_WEB ? null : SortableItemExiting,
itemsLayoutTransitionMode: 'all',
measureDebounceDelay: 0,
onActiveItemDropped: undefined,
onDragMove: undefined,
onDragStart: undefined,
onOrderChange: undefined,
overDrag: 'both',
overflow: 'hidden',
overflow: 'visible',
reorderTriggerOrigin: 'center',
scrollableRef: undefined,
showDropIndicator: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type PropsWithChildren, useCallback } from 'react';
import { type PropsWithChildren, useCallback, useMemo } from 'react';
import { useAnimatedReaction, useDerivedValue } from 'react-native-reanimated';

import { type DEFAULT_SORTABLE_FLEX_PROPS, IS_WEB } from '../../../constants';
Expand All @@ -10,7 +10,6 @@ import type {
DimensionLimits,
FlexLayout,
FlexLayoutContextType,
Paddings,
SortableFlexStyle
} from '../../../types';
import { haveEqualPropValues } from '../../../utils';
Expand All @@ -23,22 +22,24 @@ import {
import { createProvider } from '../../utils';
import { calculateLayout, updateLayoutDebugRects } from './utils';

export type FlexLayoutProviderProps = PropsWithChildren<
RequiredBy<
SortableFlexStyle,
keyof SortableFlexStyle & keyof typeof DEFAULT_SORTABLE_FLEX_PROPS
export type FlexStyleProps = PropsWithChildren<
Omit<
RequiredBy<
SortableFlexStyle,
keyof SortableFlexStyle & keyof typeof DEFAULT_SORTABLE_FLEX_PROPS
>,
'gap'
>
>;

const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(
'FlexLayout'
)<FlexLayoutProviderProps, FlexLayoutContextType>(({
)<FlexStyleProps, FlexLayoutContextType>(({
alignContent,
alignItems,
columnGap: columnGap_,
columnGap = 0,
flexDirection,
flexWrap,
gap,
height,
justifyContent,
maxHeight,
Expand All @@ -52,7 +53,7 @@ const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(
paddingRight,
paddingTop,
paddingVertical,
rowGap: rowGap_,
rowGap = 0,
width
}) => {
const {
Expand All @@ -71,15 +72,31 @@ const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(

const keyToGroup = useMutableValue<Record<string, number>>({});

const columnGap = useDerivedValue(() => columnGap_ ?? gap);
const rowGap = useDerivedValue(() => rowGap_ ?? gap);
const gaps = useMemo(
() => ({
column: columnGap,
row: rowGap
}),
[columnGap, rowGap]
);

const paddings = useDerivedValue<Paddings>(() => ({
bottom: paddingBottom ?? paddingVertical ?? padding,
left: paddingLeft ?? paddingHorizontal ?? padding,
right: paddingRight ?? paddingHorizontal ?? padding,
top: paddingTop ?? paddingVertical ?? padding
}));
const paddings = useMemo(
() => ({
bottom: paddingBottom ?? paddingVertical ?? padding,
left: paddingLeft ?? paddingHorizontal ?? padding,
right: paddingRight ?? paddingHorizontal ?? padding,
top: paddingTop ?? paddingVertical ?? padding
}),
[
paddingBottom,
paddingVertical,
padding,
paddingLeft,
paddingHorizontal,
paddingRight,
paddingTop
]
);

const dimensionsLimits = useDerivedValue<DimensionLimits | null>(() => {
const h = height === 'fill' ? undefined : height;
Expand Down Expand Up @@ -135,15 +152,12 @@ const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(
},
flexDirection,
flexWrap,
gaps: {
column: columnGap.value,
row: rowGap.value
},
gaps,
indexToKey: indexToKey.value,
itemHeights: itemHeights.value,
itemWidths: itemWidths.value,
limits: dimensionsLimits.value,
paddings: paddings.value
paddings
}),
(props, previousProps) => {
const layout = calculateLayout(props);
Expand Down Expand Up @@ -198,15 +212,12 @@ const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(
},
flexDirection,
flexWrap,
gaps: {
column: columnGap.value,
row: rowGap.value
},
gaps,
indexToKey: idxToKey,
itemHeights: itemHeights.value,
itemWidths: itemWidths.value,
limits: dimensionsLimits.value,
paddings: paddings.value
paddings
});
},
[
Expand All @@ -215,12 +226,11 @@ const { FlexLayoutProvider, useFlexLayoutContext } = createProvider(
justifyContent,
flexDirection,
flexWrap,
columnGap,
rowGap,
itemHeights,
itemWidths,
dimensionsLimits,
paddings
paddings,
gaps
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const useInsertStrategy: SortStrategyFactory = () => {
let crossCoordinate: Coordinate;
let mainDimension: Dimension;
let crossDimension: Dimension;
let mainGap: SharedValue<number>;
let mainGap: number;
let mainItemSizes: SharedValue<ItemSizes>;

if (isRow) {
Expand Down Expand Up @@ -99,7 +99,7 @@ const useInsertStrategy: SortStrategyFactory = () => {
indexToKey: indexToKey.value,
itemGroups: appliedLayout.value.itemGroups,
keyToIndex: keyToIndex.value,
mainGap: mainGap.value,
mainGap,
mainItemSizes: isRow ? itemWidths.value : itemHeights.value
}
: null,
Expand Down Expand Up @@ -136,7 +136,7 @@ const useInsertStrategy: SortStrategyFactory = () => {
activeItemKey: activeKey,
fixedKeys: fixedItemKeys?.value,
groupSizeLimit: currentLayout.groupSizeLimit,
mainGap: mainGap.value,
mainGap,
mainItemSizes: isRow ? itemWidths.value : itemHeights.value
};

Expand Down Expand Up @@ -334,7 +334,7 @@ const useInsertStrategy: SortStrategyFactory = () => {
swapItemAfterBound =
averageOffset + (isCurrentBeforeNext ? 1 : -1) * additionalSwapOffset;

totalGroupSize += itemMainSize + mainGap.value;
totalGroupSize += itemMainSize + mainGap;
if (totalGroupSize + activeItemMainSize > currentLayout.groupSizeLimit) {
break;
}
Expand All @@ -350,10 +350,10 @@ const useInsertStrategy: SortStrategyFactory = () => {
const groupBeforeSize = getTotalGroupSize(
groupBefore,
mainItemSizes.value,
mainGap.value
mainGap
);
canBeFirst =
groupBeforeSize + activeItemMainSize + mainGap.value >
groupBeforeSize + activeItemMainSize + mainGap >
currentLayout.groupSizeLimit;
}

Expand Down
Loading
Loading