diff --git a/packages/react-native-sortables/src/components/SortableGrid.tsx b/packages/react-native-sortables/src/components/SortableGrid.tsx index b8a494cb..989ddc81 100644 --- a/packages/react-native-sortables/src/components/SortableGrid.tsx +++ b/packages/react-native-sortables/src/components/SortableGrid.tsx @@ -1,4 +1,4 @@ -import { useLayoutEffect, useMemo, useRef } from 'react'; +import { useMemo } from 'react'; import type { DimensionValue } from 'react-native'; import { StyleSheet } from 'react-native'; import type { SharedValue } from 'react-native-reanimated'; @@ -193,22 +193,11 @@ function SortableGridComponent({ strategy, ...rest }: SortableGridComponentProps) { - const { handleContainerMeasurement, resetMeasurements } = - useMeasurementsContext(); + const { handleContainerMeasurement } = useMeasurementsContext(); const { mainGroupSize } = useGridLayoutContext(); - const isFirstRenderRef = useRef(true); - useOrderUpdater(strategy, GRID_STRATEGIES); - useLayoutEffect(() => { - if (isFirstRenderRef.current) { - isFirstRenderRef.current = false; - return; - } - resetMeasurements(); - }, [groups, resetMeasurements]); - const animatedInnerStyle = useAnimatedStyle(() => isVertical ? { diff --git a/packages/react-native-sortables/src/components/shared/DraggableView/ActiveItemPortal.tsx b/packages/react-native-sortables/src/components/shared/DraggableView/ActiveItemPortal.tsx index 53e8677c..9d1ebc27 100644 --- a/packages/react-native-sortables/src/components/shared/DraggableView/ActiveItemPortal.tsx +++ b/packages/react-native-sortables/src/components/shared/DraggableView/ActiveItemPortal.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; import type { ManualGesture } from 'react-native-gesture-handler'; import { runOnJS, useAnimatedReaction } from 'react-native-reanimated'; @@ -42,7 +42,7 @@ export default function ActiveItemPortal({ const teleportEnabled = useMutableValue(false); const isFirstUpdateRef = useRef(true); - const renderTeleportedItemCell = useCallback( + const teleportedItemCell = useMemo( () => ( // We have to wrap the TeleportedItemCell in context providers as they won't // be accessible otherwise, when the item is rendered in the portal outlet @@ -77,7 +77,7 @@ export default function ActiveItemPortal({ const enableTeleport = useStableCallback(() => { isFirstUpdateRef.current = true; - teleport?.(teleportedItemId, renderTeleportedItemCell()); + teleport?.(teleportedItemId, teleportedItemCell); onTeleport(true); }); @@ -93,8 +93,7 @@ export default function ActiveItemPortal({ if (!checkTeleported()) return; const update = () => - checkTeleported() && - teleport?.(teleportedItemId, renderTeleportedItemCell()); + checkTeleported() && teleport?.(teleportedItemId, teleportedItemCell); if (isFirstUpdateRef.current) { isFirstUpdateRef.current = false; @@ -103,7 +102,7 @@ export default function ActiveItemPortal({ } else { update(); } - }, [isTeleported, renderTeleportedItemCell, teleport, teleportedItemId]); + }, [isTeleported, teleportedItemCell, teleport, teleportedItemId]); useAnimatedReaction( () => activationAnimationProgress.value, diff --git a/packages/react-native-sortables/src/components/shared/DraggableView/DraggableView.tsx b/packages/react-native-sortables/src/components/shared/DraggableView/DraggableView.tsx index b2c38523..cf8041c2 100644 --- a/packages/react-native-sortables/src/components/shared/DraggableView/DraggableView.tsx +++ b/packages/react-native-sortables/src/components/shared/DraggableView/DraggableView.tsx @@ -1,9 +1,8 @@ -import { Fragment, memo, useCallback, useEffect, useState } from 'react'; -import type { LayoutChangeEvent } from 'react-native'; +import { Fragment, memo, useCallback, useState } from 'react'; +import type { View } from 'react-native'; import { GestureDetector } from 'react-native-gesture-handler'; import { LayoutAnimationConfig, - runOnUI, useDerivedValue } from 'react-native-reanimated'; @@ -16,7 +15,6 @@ import { ItemContextProvider, ItemOutlet, useCommonValuesContext, - useDragContext, useItemLayout, useItemPanGesture, useMeasurementsContext, @@ -40,9 +38,7 @@ function DraggableView({ }: DraggableViewProps) { const portalContext = usePortalContext(); const commonValuesContext = useCommonValuesContext(); - const { handleItemMeasurement, removeItemMeasurements } = - useMeasurementsContext(); - const { handleDragEnd } = useDragContext(); + const { updateItemRef } = useMeasurementsContext(); const { activeItemKey, customHandle } = commonValuesContext; const [isHidden, setIsHidden] = useState(false); @@ -55,22 +51,9 @@ function DraggableView({ ); const gesture = useItemPanGesture(key, activationAnimationProgress); - useEffect(() => { - return () => { - removeItemMeasurements(key); - runOnUI(() => { - handleDragEnd(key, activationAnimationProgress); - })(); - }; - }, [activationAnimationProgress, handleDragEnd, key, removeItemMeasurements]); - - const onLayout = useCallback( - ({ - nativeEvent: { - layout: { height, width } - } - }: LayoutChangeEvent) => handleItemMeasurement(key, { height, width }), - [handleItemMeasurement, key] + const ref = useCallback( + (instance: null | View) => updateItemRef(key, instance), + [key, updateItemRef] ); const renderItemCell = (hidden = false) => { @@ -84,7 +67,7 @@ function DraggableView({ isActive={isActive} itemKey={key} layoutStyleValue={layoutStyleValue} - onLayout={onLayout}> + ref={ref}> diff --git a/packages/react-native-sortables/src/components/shared/DraggableView/ItemCell.tsx b/packages/react-native-sortables/src/components/shared/DraggableView/ItemCell.tsx index 5fbf6b1d..b8800056 100644 --- a/packages/react-native-sortables/src/components/shared/DraggableView/ItemCell.tsx +++ b/packages/react-native-sortables/src/components/shared/DraggableView/ItemCell.tsx @@ -1,10 +1,6 @@ import type { PropsWithChildren } from 'react'; -import { - type LayoutChangeEvent, - Platform, - StyleSheet, - type ViewStyle -} from 'react-native'; +import type { View, ViewStyle } from 'react-native'; +import { Platform, StyleSheet } from 'react-native'; import type { SharedValue, TransformArrayItem } from 'react-native-reanimated'; import Animated, { useAnimatedStyle } from 'react-native-reanimated'; @@ -14,7 +10,7 @@ import type { LayoutAnimation } from '../../../integrations/reanimated'; import { useCommonValuesContext, useItemDecoration } from '../../../providers'; -import AnimatedOnLayoutView from '../AnimatedOnLayoutView'; +import { componentWithRef } from '../../../utils/react'; type TransformsArray = Array; @@ -27,21 +23,22 @@ export type ItemCellProps = PropsWithChildren<{ hidden?: boolean; entering?: LayoutAnimation; exiting?: LayoutAnimation; - onLayout?: (event: LayoutChangeEvent) => void; }>; -export default function ItemCell({ - activationAnimationProgress, - baseStyle, - children, - entering, - exiting, - hidden, - isActive, - itemKey, - layoutStyleValue, - onLayout -}: ItemCellProps) { +const ItemCell = componentWithRef(function ItemCell( + { + activationAnimationProgress, + baseStyle, + children, + entering, + exiting, + hidden, + isActive, + itemKey, + layoutStyleValue + }, + ref +) { const { controlledItemDimensionsStyle } = useCommonValuesContext(); const decorationStyleValue = useItemDecoration( @@ -50,29 +47,29 @@ export default function ItemCell({ activationAnimationProgress ); - const animatedStyle = useAnimatedStyle(() => { - return { - ...decorationStyleValue.value, - ...layoutStyleValue.value, - transform: [ - ...((layoutStyleValue.value.transform ?? []) as TransformsArray), - ...((decorationStyleValue.value.transform ?? []) as TransformsArray) - ] - }; - }); + const animatedStyle = useAnimatedStyle(() => ({ + ...decorationStyleValue.value, + ...layoutStyleValue.value, + transform: [ + ...((layoutStyleValue.value.transform ?? []) as TransformsArray), + ...((decorationStyleValue.value.transform ?? []) as TransformsArray) + ] + })); return ( - + ); -} +}); + +export default ItemCell; const styles = StyleSheet.create({ decoration: Platform.select({ diff --git a/packages/react-native-sortables/src/components/shared/DraggableView/TeleportedItemCell.tsx b/packages/react-native-sortables/src/components/shared/DraggableView/TeleportedItemCell.tsx index baaa9e61..2ed75abd 100644 --- a/packages/react-native-sortables/src/components/shared/DraggableView/TeleportedItemCell.tsx +++ b/packages/react-native-sortables/src/components/shared/DraggableView/TeleportedItemCell.tsx @@ -11,7 +11,6 @@ type TeleportedItemCellProps = Pick< | 'children' | 'isActive' | 'itemKey' - | 'onLayout' >; export default function TeleportedItemCell({ @@ -19,8 +18,7 @@ export default function TeleportedItemCell({ baseStyle, children, isActive, - itemKey, - onLayout + itemKey }: TeleportedItemCellProps) { const teleportedItemLayoutValue = useTeleportedItemLayout( itemKey, @@ -34,8 +32,7 @@ export default function TeleportedItemCell({ baseStyle={baseStyle} isActive={isActive} itemKey={itemKey} - layoutStyleValue={teleportedItemLayoutValue} - onLayout={onLayout}> + layoutStyleValue={teleportedItemLayoutValue}> {children} ); diff --git a/packages/react-native-sortables/src/constants/props.ts b/packages/react-native-sortables/src/constants/props.ts index a4d9abe1..2dbba818 100644 --- a/packages/react-native-sortables/src/constants/props.ts +++ b/packages/react-native-sortables/src/constants/props.ts @@ -50,7 +50,6 @@ 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, diff --git a/packages/react-native-sortables/src/providers/shared/CommonValuesProvider.ts b/packages/react-native-sortables/src/providers/shared/CommonValuesProvider.ts index 6054f174..4157011b 100644 --- a/packages/react-native-sortables/src/providers/shared/CommonValuesProvider.ts +++ b/packages/react-native-sortables/src/providers/shared/CommonValuesProvider.ts @@ -93,10 +93,19 @@ const { CommonValuesContext, CommonValuesProvider, useCommonValuesContext } = const controlledItemHeight = useDerivedValue(() => typeof itemHeights.value === 'number' ? itemHeights.value : undefined ); - const controlledItemDimensionsStyle = useAnimatedStyle(() => ({ - height: controlledItemHeight.value, - width: controlledItemWidth.value - })); + const controlledItemDimensionsStyle = useAnimatedStyle(() => { + console.log( + 'controlledItemDimensionsStyle', + controlledItemWidth.value, + controlledItemHeight.value + ); + return { + height: controlledItemHeight.value, + maxHeight: controlledItemHeight.value, + maxWidth: controlledItemWidth.value, + width: controlledItemWidth.value + }; + }); // DRAG STATE const activeItemKey = useMutableValue(null); diff --git a/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemOutlet.tsx b/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemOutlet.tsx index a323070a..cb64a02e 100644 --- a/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemOutlet.tsx +++ b/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemOutlet.tsx @@ -1,13 +1,20 @@ -import { memo } from 'react'; +import { memo, useLayoutEffect } from 'react'; import { useItemNode } from './hooks'; type ItemOutletProps = { itemKey: string; + onUpdate?: () => void; }; -function ItemOutlet({ itemKey }: ItemOutletProps) { - return useItemNode(itemKey); +function ItemOutlet({ itemKey, onUpdate }: ItemOutletProps) { + const node = useItemNode(itemKey); + + useLayoutEffect(() => { + onUpdate?.(); + }, [node, onUpdate]); + + return node; } export default memo(ItemOutlet); diff --git a/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemsProvider.tsx b/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemsProvider.tsx index 2d4008ec..10e70689 100644 --- a/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemsProvider.tsx +++ b/packages/react-native-sortables/src/providers/shared/ItemsProvider/ItemsProvider.tsx @@ -29,6 +29,7 @@ const { ItemsProvider, useItemsContext } = createProvider('Items')< getKeys: store.getKeys, getNode: store.getNode, subscribeItem: store.subscribeItem, + subscribeItems: store.subscribeItems, subscribeKeys: store.subscribeKeys } }; diff --git a/packages/react-native-sortables/src/providers/shared/ItemsProvider/store.ts b/packages/react-native-sortables/src/providers/shared/ItemsProvider/store.ts index f405e549..8ee7feb9 100644 --- a/packages/react-native-sortables/src/providers/shared/ItemsProvider/store.ts +++ b/packages/react-native-sortables/src/providers/shared/ItemsProvider/store.ts @@ -8,6 +8,9 @@ export type Store = { getNode: (key: string) => ReactNode | undefined; subscribeItem: (key: string, listener: () => void) => () => void; + subscribeItems: ( + listener: (updatedItemKeys: Array) => void + ) => () => void; update: ( entries: Array<[key: string, item: I]>, @@ -28,6 +31,7 @@ export function createItemsStore( const keyListeners = new Set<() => void>(); const itemListeners = new Map void>>(); + const itemsListeners = new Set<(updatedItemKeys: Array) => void>(); // Track the renderer to detect changes let currentRenderer: RenderItem | undefined = initialRenderItem; @@ -50,6 +54,19 @@ export function createItemsStore( }; }; + const subscribeItems = ( + listener: (updatedItemKeys: Array) => void + ) => { + itemsListeners.add(listener); + + // Notify immediately with current items if any exist + if (keys.length > 0) { + queueMicrotask(() => listener([...keys])); + } + + return () => itemsListeners.delete(listener); + }; + // Core logic for init + updates function apply( entries: Array<[string, I]>, @@ -74,7 +91,7 @@ export function createItemsStore( keys = nextKeys; } - const touched = new Set(); + const updatedItemKeys = new Set(); entries.forEach(([k, item], index) => { const prev = meta.get(k); @@ -86,16 +103,24 @@ export function createItemsStore( const info = { index, item }; meta.set(k, info); nodes.set(k, renderItem ? renderItem(info) : (item as ReactNode)); - touched.add(k); + updatedItemKeys.add(k); }); if (!notify) return; if (keysChanged) keyListeners.forEach(fn => fn()); - touched.forEach(k => { + updatedItemKeys.forEach(k => { const subs = itemListeners.get(k); if (subs) subs.forEach(fn => fn()); }); + + // Notify items listeners if any items changed + if (updatedItemKeys.size > 0) { + const updatedItemKeysArray = Array.from(updatedItemKeys); + queueMicrotask(() => { + itemsListeners.forEach(fn => fn(updatedItemKeysArray)); + }); + } } // Initial snapshot (sync), no notifications @@ -104,5 +129,12 @@ export function createItemsStore( const update: Store['update'] = (entries, renderItem) => apply(entries, renderItem, true); - return { getKeys, getNode, subscribeItem, subscribeKeys, update }; + return { + getKeys, + getNode, + subscribeItem, + subscribeItems, + subscribeKeys, + update + }; } diff --git a/packages/react-native-sortables/src/providers/shared/MeasurementsProvider.ts b/packages/react-native-sortables/src/providers/shared/MeasurementsProvider.ts index 522502c0..62e6ba5d 100644 --- a/packages/react-native-sortables/src/providers/shared/MeasurementsProvider.ts +++ b/packages/react-native-sortables/src/providers/shared/MeasurementsProvider.ts @@ -1,39 +1,18 @@ -import { useCallback, useRef } from 'react'; -import type { SharedValue } from 'react-native-reanimated'; +import { useCallback, useEffect, useRef } from 'react'; +import type { View } from 'react-native'; import { runOnUI } from 'react-native-reanimated'; -import { useStableCallback } from '../../hooks'; -import { - setAnimatedTimeout, - useAnimatedDebounce, - useMutableValue -} from '../../integrations/reanimated'; -import type { - Dimension, - Dimensions, - ItemSizes, - MeasurementsContextType -} from '../../types'; -import { areValuesDifferent, resolveDimension } from '../../utils'; +import { setAnimatedTimeout } from '../../integrations/reanimated'; +import type { Dimensions, MeasurementsContextType } from '../../types'; +import { areValuesDifferent } from '../../utils'; import { createProvider } from '../utils'; import { useCommonValuesContext } from './CommonValuesProvider'; import { useItemsContext } from './ItemsProvider'; import { useMultiZoneContext } from './MultiZoneProvider'; -type StateContextType = { - measuredItemKeys: Set; - queuedMeasurements: Map; -}; - -type MeasurementsProviderProps = { - measureDebounceDelay: number; -}; - const { MeasurementsProvider, useMeasurementsContext } = createProvider( 'Measurements' -)(({ - measureDebounceDelay -}) => { +), MeasurementsContextType>(() => { const { activeItemDimensions, activeItemKey, @@ -47,136 +26,115 @@ const { MeasurementsProvider, useMeasurementsContext } = createProvider( } = useCommonValuesContext(); const { activeItemDimensions: multiZoneActiveItemDimensions } = useMultiZoneContext() ?? {}; - const { getKeys } = useItemsContext(); + const { subscribeItems } = useItemsContext(); - const context = useMutableValue(null); - const previousItemDimensionsRef = useRef>({}); - const debounce = useAnimatedDebounce(); + const prevItemDimensionsRef = useRef>({}); + const itemRefs = useRef>({}); - const handleItemMeasurement = useStableCallback( - (key: string, dimensions: Dimensions) => { - const prevDimensions = previousItemDimensionsRef.current[key]; + const updateDimensionsUI = useCallback( + ( + widthUpdates: null | Record, + heightUpdates: null | Record + ) => { + 'worklet'; + if (widthUpdates) { + itemWidths.value = { + ...(itemWidths.value as Record), + ...widthUpdates + }; + } + if (heightUpdates) { + itemHeights.value = { + ...(itemHeights.value as Record), + ...heightUpdates + }; + } - const { height: isHeightControlled, width: isWidthControlled } = - controlledItemDimensions; - if (isWidthControlled && isHeightControlled) { + const activeKey = activeItemKey.value; + if (activeKey === null) { return; } - const changedDimensions: Partial = {}; - - if ( - !isWidthControlled && - areValuesDifferent(prevDimensions?.width, dimensions.width, 1) - ) { - changedDimensions.width = dimensions.width; - } - if ( - !isHeightControlled && - areValuesDifferent(prevDimensions?.height, dimensions.height, 1) - ) { - changedDimensions.height = dimensions.height; - } + const newHeight = + heightUpdates?.[activeKey] ?? activeItemDimensions.value?.height; + const newWidth = + widthUpdates?.[activeKey] ?? activeItemDimensions.value?.width; - if (!Object.keys(changedDimensions).length) { + if (newHeight === undefined || newWidth === undefined) { return; } - previousItemDimensionsRef.current[key] = dimensions; - const itemsCount = getKeys().length; - - runOnUI(() => { - context.value ??= { - measuredItemKeys: new Set(), - queuedMeasurements: new Map() + activeItemDimensions.value = { + height: newHeight, + width: newWidth + }; + if (multiZoneActiveItemDimensions) { + multiZoneActiveItemDimensions.value = { + height: newHeight, + width: newWidth }; + } + }, + [ + itemHeights, + itemWidths, + activeItemDimensions, + multiZoneActiveItemDimensions, + activeItemKey + ] + ); - const ctx = context.value; - - const isNewItem = - !ctx.measuredItemKeys.has(key) && - (resolveDimension(itemWidths.value, key) === null || - resolveDimension(itemHeights.value, key) === null); - - if (isNewItem) { - ctx.measuredItemKeys.add(key); - } - - ctx.queuedMeasurements.set(key, dimensions); - - if (activeItemKey.value === key) { - activeItemDimensions.value = dimensions; - if (multiZoneActiveItemDimensions) { - multiZoneActiveItemDimensions.value = dimensions; - } - } - - // Update the array of item dimensions only after all items have been - // measured to reduce the number of times animated reactions are triggered - if (ctx.measuredItemKeys.size !== itemsCount) { - return; - } - - const updateDimensions = () => { - const updateDimension = ( - dimension: Dimension, - sizes: SharedValue - ) => { - const newSizes = { ...(sizes.value as Record) }; - for (const [k, dims] of ctx.queuedMeasurements.entries()) { - newSizes[k] = dims[dimension]; + useEffect( + () => + subscribeItems(itemKeys => { + const updatedWidths: Record = {}; + let hasWidthUpdates = false; + const updatedHeights: Record = {}; + let hasHeightUpdates = false; + + itemKeys.forEach(key => { + itemRefs.current[key]?.measure((_x, _y, width, height) => { + const prevDimensions = prevItemDimensionsRef.current[key]; + + if ( + !controlledItemDimensions.width && + (!prevDimensions || + areValuesDifferent(prevDimensions.width, width, 1)) + ) { + updatedWidths[key] = width; + hasWidthUpdates = true; + } + if ( + !controlledItemDimensions.height && + (!prevDimensions || + areValuesDifferent(prevDimensions.height, height, 1)) + ) { + updatedHeights[key] = height; + hasHeightUpdates = true; } - sizes.value = newSizes; - }; - - if (!isWidthControlled) { - updateDimension('width', itemWidths); - } - if (!isHeightControlled) { - updateDimension('height', itemHeights); - } - - ctx.queuedMeasurements.clear(); - debounce.cancel(); - }; - if (isNewItem || ctx.queuedMeasurements.size === itemsCount) { - // Update dimensions immediately to avoid unnecessary delays when: - // - measurements were triggered because of adding new items and all new items have been measured - // - all sortable container items' dimensions have changed (e.g. when someone creates collapsible - // items which change their height when the user starts dragging them) - updateDimensions(); - } else { - // In all other cases, debounce the update to reduce the number of - // updates when dimensions change many times within a short period of time - debounce.schedule(updateDimensions, measureDebounceDelay); - } - })(); - } - ); + prevItemDimensionsRef.current[key] = { height, width }; + }); + }); - const removeItemMeasurements = useCallback( - (key: string) => { - delete previousItemDimensionsRef.current[key]; - const { height: isHeightControlled, width: isWidthControlled } = - controlledItemDimensions; - if (isWidthControlled && isHeightControlled) { - return; - } + const widthUpdates = hasWidthUpdates ? updatedWidths : null; + const heightUpdates = hasHeightUpdates ? updatedHeights : null; - runOnUI(() => { - if (itemWidths.value && typeof itemWidths.value === 'object') { - delete itemWidths.value[key]; + if (widthUpdates || heightUpdates) { + runOnUI(updateDimensionsUI)(widthUpdates, heightUpdates); } - if (itemHeights.value && typeof itemHeights.value === 'object') { - delete itemHeights.value[key]; - } - context.value?.measuredItemKeys.delete(key); - })(); - }, - [controlledItemDimensions, itemHeights, itemWidths, context] + }), + [subscribeItems, itemRefs, updateDimensionsUI, controlledItemDimensions] ); + const updateItemRef = useCallback((key: string, instance: null | View) => { + if (instance) { + itemRefs.current[key] = instance; + } else { + delete itemRefs.current[key]; + } + }, []); + const handleContainerMeasurement = useCallback( (width: number, height: number) => { 'worklet'; @@ -222,26 +180,11 @@ const { MeasurementsProvider, useMeasurementsContext } = createProvider( ] ); - const resetMeasurements = useCallback(() => { - previousItemDimensionsRef.current = {}; - runOnUI(() => { - context.value = null; - if (typeof itemWidths.value === 'object') { - itemWidths.value = null; - } - if (typeof itemHeights.value === 'object') { - itemHeights.value = null; - } - })(); - }, [itemHeights, itemWidths, context]); - return { value: { applyControlledContainerDimensions, handleContainerMeasurement, - handleItemMeasurement, - removeItemMeasurements, - resetMeasurements + updateItemRef } }; }); diff --git a/packages/react-native-sortables/src/providers/shared/SharedProvider.tsx b/packages/react-native-sortables/src/providers/shared/SharedProvider.tsx index 5babd4c0..838cd764 100644 --- a/packages/react-native-sortables/src/providers/shared/SharedProvider.tsx +++ b/packages/react-native-sortables/src/providers/shared/SharedProvider.tsx @@ -38,7 +38,6 @@ export type SharedProviderProps = PropsWithChildren< | 'debug' | 'hapticsEnabled' | 'itemsLayoutTransitionMode' - | 'measureDebounceDelay' | 'sortEnabled' > > & @@ -63,7 +62,6 @@ export default function SharedProvider({ customHandle, debug, hapticsEnabled, - measureDebounceDelay, onActiveItemDropped, onDragEnd, onDragMove, @@ -95,7 +93,7 @@ export default function SharedProvider({ {...rest} />, // Provider used for measurements of items and the container - , + , // Provider used for auto-scrolling when dragging an item near the // edge of the container scrollableRef && ( diff --git a/packages/react-native-sortables/src/types/props/shared.ts b/packages/react-native-sortables/src/types/props/shared.ts index 1c4b1de7..33d103a0 100644 --- a/packages/react-native-sortables/src/types/props/shared.ts +++ b/packages/react-native-sortables/src/types/props/shared.ts @@ -302,11 +302,6 @@ export type SharedProps = Simplify< DropIndicatorSettings & ItemDragSettings & ItemLayoutAnimationSettings & { - /** Delay after the last item measurement and the measurements commit - * triggering the layout calculation - * @default 0 - */ - measureDebounceDelay: number; /** Whether and how to animate container dimensions changes * @default 'none' */ diff --git a/packages/react-native-sortables/src/types/providers/shared.ts b/packages/react-native-sortables/src/types/providers/shared.ts index 0ecf4cd1..5f20fd27 100644 --- a/packages/react-native-sortables/src/types/providers/shared.ts +++ b/packages/react-native-sortables/src/types/providers/shared.ts @@ -44,6 +44,9 @@ export type ItemsContextType = { subscribeKeys: (callback: () => void) => () => void; getNode: (key: string) => ReactNode | undefined; subscribeItem: (key: string, callback: () => void) => () => void; + subscribeItems: ( + callback: (updatedItemKeys: Array) => void + ) => () => void; }; // COMMON VALUES @@ -102,11 +105,9 @@ export type CommonValuesContextType = // MEASUREMENTS export type MeasurementsContextType = { - handleItemMeasurement: (key: string, dimensions: Dimensions) => void; - removeItemMeasurements: (key: string) => void; + updateItemRef: (key: string, instance: null | View) => void; handleContainerMeasurement: (width: number, height: number) => void; applyControlledContainerDimensions: (dimensions: Partial) => void; - resetMeasurements: () => void; }; // AUTO SCROLL diff --git a/packages/react-native-sortables/src/utils/equality.ts b/packages/react-native-sortables/src/utils/equality.ts index 94a2d9d7..42fe3760 100644 --- a/packages/react-native-sortables/src/utils/equality.ts +++ b/packages/react-native-sortables/src/utils/equality.ts @@ -14,22 +14,22 @@ export const areArraysDifferent = ( arr1.some((item, index) => !areEqual(item, arr2[index] as T)); export const areValuesDifferent = ( - dim1: number | undefined, - dim2: number | undefined, + value1: number | undefined, + value2: number | undefined, eps?: number ): boolean => { - if (dim1 === undefined) { - return dim2 !== undefined; + if (value1 === undefined) { + return value2 !== undefined; } - if (dim2 === undefined) { + if (value2 === undefined) { return true; } if (eps) { - return Math.abs(dim1 - dim2) > eps; + return Math.abs(value1 - value2) > eps; } - return dim1 !== dim2; + return value1 !== value2; }; export const areVectorsDifferent = (