react-native-layout-dnd 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +262 -0
- package/lib/module/adapters/coordinates.js +135 -0
- package/lib/module/adapters/coordinates.js.map +1 -0
- package/lib/module/adapters/scroll.js +81 -0
- package/lib/module/adapters/scroll.js.map +1 -0
- package/lib/module/adapters/virtualizedList.js +69 -0
- package/lib/module/adapters/virtualizedList.js.map +1 -0
- package/lib/module/components/DndProvider.js +1144 -0
- package/lib/module/components/DndProvider.js.map +1 -0
- package/lib/module/components/DragHandle.js +65 -0
- package/lib/module/components/DragHandle.js.map +1 -0
- package/lib/module/components/GridController.js +151 -0
- package/lib/module/components/GridController.js.map +1 -0
- package/lib/module/components/GridDragHandle.js +15 -0
- package/lib/module/components/GridDragHandle.js.map +1 -0
- package/lib/module/components/GridZoneView.js +59 -0
- package/lib/module/components/GridZoneView.js.map +1 -0
- package/lib/module/components/SortableGrid.js +305 -0
- package/lib/module/components/SortableGrid.js.map +1 -0
- package/lib/module/components/SortableList.js +714 -0
- package/lib/module/components/SortableList.js.map +1 -0
- package/lib/module/components/dndTypes.js +4 -0
- package/lib/module/components/dndTypes.js.map +1 -0
- package/lib/module/components/gridTypes.js +4 -0
- package/lib/module/components/gridTypes.js.map +1 -0
- package/lib/module/components/handleViewProps.js +13 -0
- package/lib/module/components/handleViewProps.js.map +1 -0
- package/lib/module/contracts.js +4 -0
- package/lib/module/contracts.js.map +1 -0
- package/lib/module/controller/approval.js +98 -0
- package/lib/module/controller/approval.js.map +1 -0
- package/lib/module/controller/coordinatorBase.js +93 -0
- package/lib/module/controller/coordinatorBase.js.map +1 -0
- package/lib/module/controller/dndSession.js +621 -0
- package/lib/module/controller/dndSession.js.map +1 -0
- package/lib/module/controller/dndState.js +103 -0
- package/lib/module/controller/dndState.js.map +1 -0
- package/lib/module/controller/gridAdapter.js +191 -0
- package/lib/module/controller/gridAdapter.js.map +1 -0
- package/lib/module/controller/gridState.js +101 -0
- package/lib/module/controller/gridState.js.map +1 -0
- package/lib/module/controller/locations.js +48 -0
- package/lib/module/controller/locations.js.map +1 -0
- package/lib/module/controller/previewPath.js +73 -0
- package/lib/module/controller/previewPath.js.map +1 -0
- package/lib/module/controller/sessionCore.js +222 -0
- package/lib/module/controller/sessionCore.js.map +1 -0
- package/lib/module/controller/useDndState.js +9 -0
- package/lib/module/controller/useDndState.js.map +1 -0
- package/lib/module/controller/useGridState.js +9 -0
- package/lib/module/controller/useGridState.js.map +1 -0
- package/lib/module/controller/useStoreState.js +15 -0
- package/lib/module/controller/useStoreState.js.map +1 -0
- package/lib/module/defaults.js +7 -0
- package/lib/module/defaults.js.map +1 -0
- package/lib/module/diagnostics.js +16 -0
- package/lib/module/diagnostics.js.map +1 -0
- package/lib/module/engine/gridPlacements.js +54 -0
- package/lib/module/engine/gridPlacements.js.map +1 -0
- package/lib/module/engine/index.js +19 -0
- package/lib/module/engine/index.js.map +1 -0
- package/lib/module/engine/layout.js +36 -0
- package/lib/module/engine/layout.js.map +1 -0
- package/lib/module/engine/layoutMove.js +326 -0
- package/lib/module/engine/layoutMove.js.map +1 -0
- package/lib/module/engine/layoutState.js +344 -0
- package/lib/module/engine/layoutState.js.map +1 -0
- package/lib/module/engine/list.js +172 -0
- package/lib/module/engine/list.js.map +1 -0
- package/lib/module/engine/listIndex.js +125 -0
- package/lib/module/engine/listIndex.js.map +1 -0
- package/lib/module/engine/move.js +216 -0
- package/lib/module/engine/move.js.map +1 -0
- package/lib/module/engine/movementPolicy.js +77 -0
- package/lib/module/engine/movementPolicy.js.map +1 -0
- package/lib/module/engine/orderedTarget.js +71 -0
- package/lib/module/engine/orderedTarget.js.map +1 -0
- package/lib/module/engine/pack.js +30 -0
- package/lib/module/engine/pack.js.map +1 -0
- package/lib/module/engine/rectangles.js +12 -0
- package/lib/module/engine/rectangles.js.map +1 -0
- package/lib/module/engine/sameLayout.js +29 -0
- package/lib/module/engine/sameLayout.js.map +1 -0
- package/lib/module/engine/search.js +159 -0
- package/lib/module/engine/search.js.map +1 -0
- package/lib/module/engine/spatial.js +27 -0
- package/lib/module/engine/spatial.js.map +1 -0
- package/lib/module/engine/spatialAppRotation.js +39 -0
- package/lib/module/engine/spatialAppRotation.js.map +1 -0
- package/lib/module/engine/spatialExchange.js +164 -0
- package/lib/module/engine/spatialExchange.js.map +1 -0
- package/lib/module/engine/spatialInsertion.js +135 -0
- package/lib/module/engine/spatialInsertion.js.map +1 -0
- package/lib/module/engine/spatialPolicy.js +41 -0
- package/lib/module/engine/spatialPolicy.js.map +1 -0
- package/lib/module/engine/spatialRotation.js +48 -0
- package/lib/module/engine/spatialRotation.js.map +1 -0
- package/lib/module/engine/validation.js +205 -0
- package/lib/module/engine/validation.js.map +1 -0
- package/lib/module/gesture/DndGestureGroup.js +268 -0
- package/lib/module/gesture/DndGestureGroup.js.map +1 -0
- package/lib/module/gesture/DndGestureHost.js +32 -0
- package/lib/module/gesture/DndGestureHost.js.map +1 -0
- package/lib/module/gesture/gestureConfig.js +81 -0
- package/lib/module/gesture/gestureConfig.js.map +1 -0
- package/lib/module/gesture/gestureGrouping.js +122 -0
- package/lib/module/gesture/gestureGrouping.js.map +1 -0
- package/lib/module/gesture/gestureHost.js +106 -0
- package/lib/module/gesture/gestureHost.js.map +1 -0
- package/lib/module/index.js +23 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/pointer/dndTarget.js +101 -0
- package/lib/module/pointer/dndTarget.js.map +1 -0
- package/lib/module/pointer/geometry.js +363 -0
- package/lib/module/pointer/geometry.js.map +1 -0
- package/lib/module/pointer/layoutTarget.js +307 -0
- package/lib/module/pointer/layoutTarget.js.map +1 -0
- package/lib/module/pointer/listCellMotion.js +99 -0
- package/lib/module/pointer/listCellMotion.js.map +1 -0
- package/lib/module/pointer/listTarget.js +42 -0
- package/lib/module/pointer/listTarget.js.map +1 -0
- package/lib/module/pointer/motion.js +37 -0
- package/lib/module/pointer/motion.js.map +1 -0
- package/lib/module/runtime/dndPresentation.js +81 -0
- package/lib/module/runtime/dndPresentation.js.map +1 -0
- package/lib/module/runtime/dndRenderStore.js +129 -0
- package/lib/module/runtime/dndRenderStore.js.map +1 -0
- package/lib/module/runtime/dndRuntime.js +135 -0
- package/lib/module/runtime/dndRuntime.js.map +1 -0
- package/lib/module/runtime/dndSettlement.js +77 -0
- package/lib/module/runtime/dndSettlement.js.map +1 -0
- package/lib/module/runtime/gridRuntime.js +37 -0
- package/lib/module/runtime/gridRuntime.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/adapters/coordinates.d.ts +9 -0
- package/lib/typescript/src/adapters/coordinates.d.ts.map +1 -0
- package/lib/typescript/src/adapters/scroll.d.ts +49 -0
- package/lib/typescript/src/adapters/scroll.d.ts.map +1 -0
- package/lib/typescript/src/adapters/virtualizedList.d.ts +22 -0
- package/lib/typescript/src/adapters/virtualizedList.d.ts.map +1 -0
- package/lib/typescript/src/components/DndProvider.d.ts +4 -0
- package/lib/typescript/src/components/DndProvider.d.ts.map +1 -0
- package/lib/typescript/src/components/DragHandle.d.ts +4 -0
- package/lib/typescript/src/components/DragHandle.d.ts.map +1 -0
- package/lib/typescript/src/components/GridController.d.ts +21 -0
- package/lib/typescript/src/components/GridController.d.ts.map +1 -0
- package/lib/typescript/src/components/GridDragHandle.d.ts +8 -0
- package/lib/typescript/src/components/GridDragHandle.d.ts.map +1 -0
- package/lib/typescript/src/components/GridZoneView.d.ts +8 -0
- package/lib/typescript/src/components/GridZoneView.d.ts.map +1 -0
- package/lib/typescript/src/components/SortableGrid.d.ts +4 -0
- package/lib/typescript/src/components/SortableGrid.d.ts.map +1 -0
- package/lib/typescript/src/components/SortableList.d.ts +4 -0
- package/lib/typescript/src/components/SortableList.d.ts.map +1 -0
- package/lib/typescript/src/components/dndTypes.d.ts +94 -0
- package/lib/typescript/src/components/dndTypes.d.ts.map +1 -0
- package/lib/typescript/src/components/gridTypes.d.ts +84 -0
- package/lib/typescript/src/components/gridTypes.d.ts.map +1 -0
- package/lib/typescript/src/components/handleViewProps.d.ts +6 -0
- package/lib/typescript/src/components/handleViewProps.d.ts.map +1 -0
- package/lib/typescript/src/contracts.d.ts +145 -0
- package/lib/typescript/src/contracts.d.ts.map +1 -0
- package/lib/typescript/src/controller/approval.d.ts +66 -0
- package/lib/typescript/src/controller/approval.d.ts.map +1 -0
- package/lib/typescript/src/controller/coordinatorBase.d.ts +37 -0
- package/lib/typescript/src/controller/coordinatorBase.d.ts.map +1 -0
- package/lib/typescript/src/controller/dndSession.d.ts +152 -0
- package/lib/typescript/src/controller/dndSession.d.ts.map +1 -0
- package/lib/typescript/src/controller/dndState.d.ts +27 -0
- package/lib/typescript/src/controller/dndState.d.ts.map +1 -0
- package/lib/typescript/src/controller/gridAdapter.d.ts +44 -0
- package/lib/typescript/src/controller/gridAdapter.d.ts.map +1 -0
- package/lib/typescript/src/controller/gridState.d.ts +18 -0
- package/lib/typescript/src/controller/gridState.d.ts.map +1 -0
- package/lib/typescript/src/controller/locations.d.ts +9 -0
- package/lib/typescript/src/controller/locations.d.ts.map +1 -0
- package/lib/typescript/src/controller/previewPath.d.ts +49 -0
- package/lib/typescript/src/controller/previewPath.d.ts.map +1 -0
- package/lib/typescript/src/controller/sessionCore.d.ts +106 -0
- package/lib/typescript/src/controller/sessionCore.d.ts.map +1 -0
- package/lib/typescript/src/controller/useDndState.d.ts +8 -0
- package/lib/typescript/src/controller/useDndState.d.ts.map +1 -0
- package/lib/typescript/src/controller/useGridState.d.ts +8 -0
- package/lib/typescript/src/controller/useGridState.d.ts.map +1 -0
- package/lib/typescript/src/controller/useStoreState.d.ts +16 -0
- package/lib/typescript/src/controller/useStoreState.d.ts.map +1 -0
- package/lib/typescript/src/defaults.d.ts +5 -0
- package/lib/typescript/src/defaults.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics.d.ts +9 -0
- package/lib/typescript/src/diagnostics.d.ts.map +1 -0
- package/lib/typescript/src/engine/gridPlacements.d.ts +22 -0
- package/lib/typescript/src/engine/gridPlacements.d.ts.map +1 -0
- package/lib/typescript/src/engine/index.d.ts +28 -0
- package/lib/typescript/src/engine/index.d.ts.map +1 -0
- package/lib/typescript/src/engine/layout.d.ts +4 -0
- package/lib/typescript/src/engine/layout.d.ts.map +1 -0
- package/lib/typescript/src/engine/layoutMove.d.ts +46 -0
- package/lib/typescript/src/engine/layoutMove.d.ts.map +1 -0
- package/lib/typescript/src/engine/layoutState.d.ts +22 -0
- package/lib/typescript/src/engine/layoutState.d.ts.map +1 -0
- package/lib/typescript/src/engine/list.d.ts +68 -0
- package/lib/typescript/src/engine/list.d.ts.map +1 -0
- package/lib/typescript/src/engine/listIndex.d.ts +32 -0
- package/lib/typescript/src/engine/listIndex.d.ts.map +1 -0
- package/lib/typescript/src/engine/move.d.ts +10 -0
- package/lib/typescript/src/engine/move.d.ts.map +1 -0
- package/lib/typescript/src/engine/movementPolicy.d.ts +34 -0
- package/lib/typescript/src/engine/movementPolicy.d.ts.map +1 -0
- package/lib/typescript/src/engine/orderedTarget.d.ts +32 -0
- package/lib/typescript/src/engine/orderedTarget.d.ts.map +1 -0
- package/lib/typescript/src/engine/pack.d.ts +3 -0
- package/lib/typescript/src/engine/pack.d.ts.map +1 -0
- package/lib/typescript/src/engine/rectangles.d.ts +9 -0
- package/lib/typescript/src/engine/rectangles.d.ts.map +1 -0
- package/lib/typescript/src/engine/sameLayout.d.ts +4 -0
- package/lib/typescript/src/engine/sameLayout.d.ts.map +1 -0
- package/lib/typescript/src/engine/search.d.ts +28 -0
- package/lib/typescript/src/engine/search.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatial.d.ts +16 -0
- package/lib/typescript/src/engine/spatial.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatialAppRotation.d.ts +4 -0
- package/lib/typescript/src/engine/spatialAppRotation.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatialExchange.d.ts +5 -0
- package/lib/typescript/src/engine/spatialExchange.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatialInsertion.d.ts +5 -0
- package/lib/typescript/src/engine/spatialInsertion.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatialPolicy.d.ts +9 -0
- package/lib/typescript/src/engine/spatialPolicy.d.ts.map +1 -0
- package/lib/typescript/src/engine/spatialRotation.d.ts +8 -0
- package/lib/typescript/src/engine/spatialRotation.d.ts.map +1 -0
- package/lib/typescript/src/engine/validation.d.ts +9 -0
- package/lib/typescript/src/engine/validation.d.ts.map +1 -0
- package/lib/typescript/src/gesture/DndGestureGroup.d.ts +33 -0
- package/lib/typescript/src/gesture/DndGestureGroup.d.ts.map +1 -0
- package/lib/typescript/src/gesture/DndGestureHost.d.ts +12 -0
- package/lib/typescript/src/gesture/DndGestureHost.d.ts.map +1 -0
- package/lib/typescript/src/gesture/gestureConfig.d.ts +15 -0
- package/lib/typescript/src/gesture/gestureConfig.d.ts.map +1 -0
- package/lib/typescript/src/gesture/gestureGrouping.d.ts +66 -0
- package/lib/typescript/src/gesture/gestureGrouping.d.ts.map +1 -0
- package/lib/typescript/src/gesture/gestureHost.d.ts +23 -0
- package/lib/typescript/src/gesture/gestureHost.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +38 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/pointer/dndTarget.d.ts +14 -0
- package/lib/typescript/src/pointer/dndTarget.d.ts.map +1 -0
- package/lib/typescript/src/pointer/geometry.d.ts +28 -0
- package/lib/typescript/src/pointer/geometry.d.ts.map +1 -0
- package/lib/typescript/src/pointer/layoutTarget.d.ts +43 -0
- package/lib/typescript/src/pointer/layoutTarget.d.ts.map +1 -0
- package/lib/typescript/src/pointer/listCellMotion.d.ts +43 -0
- package/lib/typescript/src/pointer/listCellMotion.d.ts.map +1 -0
- package/lib/typescript/src/pointer/listTarget.d.ts +7 -0
- package/lib/typescript/src/pointer/listTarget.d.ts.map +1 -0
- package/lib/typescript/src/pointer/motion.d.ts +20 -0
- package/lib/typescript/src/pointer/motion.d.ts.map +1 -0
- package/lib/typescript/src/runtime/dndPresentation.d.ts +37 -0
- package/lib/typescript/src/runtime/dndPresentation.d.ts.map +1 -0
- package/lib/typescript/src/runtime/dndRenderStore.d.ts +46 -0
- package/lib/typescript/src/runtime/dndRenderStore.d.ts.map +1 -0
- package/lib/typescript/src/runtime/dndRuntime.d.ts +138 -0
- package/lib/typescript/src/runtime/dndRuntime.d.ts.map +1 -0
- package/lib/typescript/src/runtime/dndSettlement.d.ts +18 -0
- package/lib/typescript/src/runtime/dndSettlement.d.ts.map +1 -0
- package/lib/typescript/src/runtime/gridRuntime.d.ts +54 -0
- package/lib/typescript/src/runtime/gridRuntime.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +180 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +136 -0
- package/src/adapters/coordinates.ts +181 -0
- package/src/adapters/scroll.ts +147 -0
- package/src/adapters/virtualizedList.ts +112 -0
- package/src/components/DndProvider.tsx +1836 -0
- package/src/components/DragHandle.tsx +89 -0
- package/src/components/GridController.tsx +213 -0
- package/src/components/GridDragHandle.tsx +11 -0
- package/src/components/GridZoneView.tsx +57 -0
- package/src/components/SortableGrid.tsx +449 -0
- package/src/components/SortableList.tsx +1028 -0
- package/src/components/dndTypes.ts +102 -0
- package/src/components/gridTypes.ts +90 -0
- package/src/components/handleViewProps.ts +35 -0
- package/src/contracts.ts +149 -0
- package/src/controller/approval.ts +179 -0
- package/src/controller/coordinatorBase.ts +118 -0
- package/src/controller/dndSession.ts +1058 -0
- package/src/controller/dndState.ts +198 -0
- package/src/controller/gridAdapter.ts +268 -0
- package/src/controller/gridState.ts +187 -0
- package/src/controller/locations.ts +67 -0
- package/src/controller/previewPath.ts +90 -0
- package/src/controller/sessionCore.ts +390 -0
- package/src/controller/useDndState.ts +26 -0
- package/src/controller/useGridState.ts +22 -0
- package/src/controller/useStoreState.ts +27 -0
- package/src/defaults.ts +4 -0
- package/src/diagnostics.ts +23 -0
- package/src/engine/gridPlacements.ts +85 -0
- package/src/engine/index.ts +99 -0
- package/src/engine/layout.ts +29 -0
- package/src/engine/layoutMove.ts +401 -0
- package/src/engine/layoutState.ts +490 -0
- package/src/engine/list.ts +307 -0
- package/src/engine/listIndex.ts +174 -0
- package/src/engine/move.ts +274 -0
- package/src/engine/movementPolicy.ts +151 -0
- package/src/engine/orderedTarget.ts +131 -0
- package/src/engine/pack.ts +24 -0
- package/src/engine/rectangles.ts +18 -0
- package/src/engine/sameLayout.ts +50 -0
- package/src/engine/search.ts +174 -0
- package/src/engine/spatial.ts +36 -0
- package/src/engine/spatialAppRotation.ts +53 -0
- package/src/engine/spatialExchange.ts +212 -0
- package/src/engine/spatialInsertion.ts +157 -0
- package/src/engine/spatialPolicy.ts +48 -0
- package/src/engine/spatialRotation.ts +56 -0
- package/src/engine/validation.ts +358 -0
- package/src/gesture/DndGestureGroup.tsx +357 -0
- package/src/gesture/DndGestureHost.tsx +50 -0
- package/src/gesture/gestureConfig.ts +123 -0
- package/src/gesture/gestureGrouping.ts +210 -0
- package/src/gesture/gestureHost.tsx +163 -0
- package/src/index.ts +162 -0
- package/src/pointer/dndTarget.ts +213 -0
- package/src/pointer/geometry.ts +584 -0
- package/src/pointer/layoutTarget.ts +515 -0
- package/src/pointer/listCellMotion.ts +174 -0
- package/src/pointer/listTarget.ts +56 -0
- package/src/pointer/motion.ts +66 -0
- package/src/runtime/dndPresentation.ts +113 -0
- package/src/runtime/dndRenderStore.ts +246 -0
- package/src/runtime/dndRuntime.ts +311 -0
- package/src/runtime/dndSettlement.ts +117 -0
- package/src/runtime/gridRuntime.ts +73 -0
- package/src/types.ts +189 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useContext, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { type HostInstance, View } from 'react-native';
|
|
3
|
+
import { useAnimatedRef } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
import { validateGestureRelations } from '../gesture/gestureConfig';
|
|
6
|
+
import {
|
|
7
|
+
DndItemContext,
|
|
8
|
+
useDndHandleActive,
|
|
9
|
+
useDndRuntime,
|
|
10
|
+
} from '../runtime/dndRuntime';
|
|
11
|
+
import type { DragHandleProps } from './dndTypes';
|
|
12
|
+
import { pickHandleViewProps as viewProps } from './handleViewProps';
|
|
13
|
+
|
|
14
|
+
/** Registers a hit area. Native gesture ownership stays with the Provider. */
|
|
15
|
+
export function DragHandle(props: DragHandleProps) {
|
|
16
|
+
const runtime = useDndRuntime();
|
|
17
|
+
const scope = useContext(DndItemContext);
|
|
18
|
+
const ref = useAnimatedRef<HostInstance>();
|
|
19
|
+
const identity = useRef({}).current;
|
|
20
|
+
const relations = validateGestureRelations(props.gestureRelations);
|
|
21
|
+
const valid =
|
|
22
|
+
!!scope &&
|
|
23
|
+
(props.itemId === undefined || props.itemId === scope.itemId) &&
|
|
24
|
+
relations.valid;
|
|
25
|
+
const { cancel, reportIssues, registerHandle, unregisterHandle } = runtime;
|
|
26
|
+
const itemId = scope?.itemId;
|
|
27
|
+
const disabledWhileActive = useDndHandleActive(
|
|
28
|
+
runtime,
|
|
29
|
+
itemId,
|
|
30
|
+
props.disabled === true,
|
|
31
|
+
);
|
|
32
|
+
useLayoutEffect(() => {
|
|
33
|
+
if (scope?.preview) return;
|
|
34
|
+
const owner = `handle:${scope?.zoneId}:${itemId}`;
|
|
35
|
+
reportIssues(
|
|
36
|
+
owner,
|
|
37
|
+
valid
|
|
38
|
+
? []
|
|
39
|
+
: [
|
|
40
|
+
{
|
|
41
|
+
code: 'invalid-configuration',
|
|
42
|
+
itemId,
|
|
43
|
+
message:
|
|
44
|
+
'DragHandle must be inside its matching list item with valid gesture relations.',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
);
|
|
48
|
+
if (disabledWhileActive) cancel('disabled');
|
|
49
|
+
return () => reportIssues(owner, []);
|
|
50
|
+
}, [
|
|
51
|
+
cancel,
|
|
52
|
+
itemId,
|
|
53
|
+
props.disabled,
|
|
54
|
+
reportIssues,
|
|
55
|
+
disabledWhileActive,
|
|
56
|
+
scope?.preview,
|
|
57
|
+
scope?.zoneId,
|
|
58
|
+
valid,
|
|
59
|
+
]);
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
if (!valid || !scope || scope.preview || !relations.valid) {
|
|
62
|
+
unregisterHandle(identity);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
registerHandle(
|
|
66
|
+
{
|
|
67
|
+
itemId: scope.itemId,
|
|
68
|
+
zoneId: scope.zoneId,
|
|
69
|
+
ref,
|
|
70
|
+
sourceRef: scope.ref,
|
|
71
|
+
disabled: props.disabled === true,
|
|
72
|
+
gestureRelations: relations.relations,
|
|
73
|
+
},
|
|
74
|
+
identity,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
useLayoutEffect(
|
|
78
|
+
() => () => unregisterHandle(identity),
|
|
79
|
+
[identity, unregisterHandle],
|
|
80
|
+
);
|
|
81
|
+
// The preview copy keeps the same labels but never attaches a gesture.
|
|
82
|
+
if (!valid || !scope || scope.preview)
|
|
83
|
+
return <View {...viewProps(props)}>{props.children}</View>;
|
|
84
|
+
return (
|
|
85
|
+
<View {...viewProps(props)} ref={ref} collapsable={false}>
|
|
86
|
+
{props.children}
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
type ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
|
|
11
|
+
import type { DndDragEndEvent } from '../controller/dndSession';
|
|
12
|
+
import type { DndProposal, DndValue } from '../controller/dndState';
|
|
13
|
+
import {
|
|
14
|
+
convertGridValue,
|
|
15
|
+
gridChangeOf,
|
|
16
|
+
gridEndEvent,
|
|
17
|
+
gridIssues,
|
|
18
|
+
gridItemIndex,
|
|
19
|
+
type PreviousConversion,
|
|
20
|
+
} from '../controller/gridAdapter';
|
|
21
|
+
import type { LayoutValidationIssue } from '../contracts';
|
|
22
|
+
import { layoutToGridValue } from '../engine/layoutState';
|
|
23
|
+
import type { GridItem } from '../types';
|
|
24
|
+
|
|
25
|
+
import { DndProvider } from './DndProvider';
|
|
26
|
+
import type { DndPreviewArgs } from './dndTypes';
|
|
27
|
+
import type { GridControllerProps, ItemRenderArgs } from './gridTypes';
|
|
28
|
+
|
|
29
|
+
/** What `GridZoneView` needs from its controller to render the grid API's items. */
|
|
30
|
+
export type GridAdapterScope<T> = {
|
|
31
|
+
renderItem(args: ItemRenderArgs<T>): ReactNode;
|
|
32
|
+
/** The caller's own item object, so render callbacks see stable identities. */
|
|
33
|
+
itemOf(itemId: string): GridItem<T> | undefined;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const GridAdapterContext =
|
|
37
|
+
createContext<GridAdapterScope<unknown> | null>(null);
|
|
38
|
+
|
|
39
|
+
const EMPTY_STATE: DndValue<never> = { revision: 0, items: [], zones: [] };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The grid API on the shared provider. `GridValue` is converted to the
|
|
43
|
+
* provider's layout state once per committed value; candidates, changes and
|
|
44
|
+
* end events are converted back with their ordered zones, item data and
|
|
45
|
+
* revision intact. Zones render through `GridZoneView`, handles through
|
|
46
|
+
* `GridDragHandle`; both are thin wrappers over the provider's components.
|
|
47
|
+
* `onDragEnd` is delivered once the preview has settled, as the grid API
|
|
48
|
+
* always did (the provider's `onDragSettled` timing).
|
|
49
|
+
*/
|
|
50
|
+
export function GridController<T>({
|
|
51
|
+
value,
|
|
52
|
+
onChange,
|
|
53
|
+
renderItem,
|
|
54
|
+
renderDragPreview,
|
|
55
|
+
waitForDragPreviewReady = false,
|
|
56
|
+
dragPreviewStyle,
|
|
57
|
+
canDrop,
|
|
58
|
+
onDragStart,
|
|
59
|
+
onDragEnd,
|
|
60
|
+
onValidationError,
|
|
61
|
+
onDiagnostic,
|
|
62
|
+
searchBudget,
|
|
63
|
+
activation,
|
|
64
|
+
movementPolicy,
|
|
65
|
+
motion,
|
|
66
|
+
responseTimeoutMs,
|
|
67
|
+
disabled = false,
|
|
68
|
+
ref,
|
|
69
|
+
children,
|
|
70
|
+
...viewProps
|
|
71
|
+
}: GridControllerProps<T>) {
|
|
72
|
+
// Values without a revision get a synthetic one that advances with each
|
|
73
|
+
// layout change; a response without a base revision answers the pending
|
|
74
|
+
// proposal.
|
|
75
|
+
const previous = useRef<PreviousConversion<T> | null>(null);
|
|
76
|
+
const pendingProposal = useRef<DndProposal<T> | null>(null);
|
|
77
|
+
const [lastValidState, setLastValidState] = useState<DndValue<T> | null>(
|
|
78
|
+
null,
|
|
79
|
+
);
|
|
80
|
+
const converted = useMemo(
|
|
81
|
+
() =>
|
|
82
|
+
convertGridValue(
|
|
83
|
+
value,
|
|
84
|
+
previous.current,
|
|
85
|
+
pendingProposal.current?.baseRevision,
|
|
86
|
+
),
|
|
87
|
+
[value],
|
|
88
|
+
);
|
|
89
|
+
previous.current = {
|
|
90
|
+
value,
|
|
91
|
+
revision: converted.revision,
|
|
92
|
+
state: converted.state ?? previous.current?.state ?? null,
|
|
93
|
+
};
|
|
94
|
+
const state =
|
|
95
|
+
converted.state ?? lastValidState ?? (EMPTY_STATE as DndValue<T>);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (converted.state) setLastValidState(converted.state);
|
|
98
|
+
}, [converted.state]);
|
|
99
|
+
const includeBaseRevision = value.revision !== undefined;
|
|
100
|
+
|
|
101
|
+
const items = useMemo(() => gridItemIndex(value), [value]);
|
|
102
|
+
const itemOf = useCallback((itemId: string) => items.get(itemId), [items]);
|
|
103
|
+
const scope = useMemo<GridAdapterScope<T>>(
|
|
104
|
+
() => ({ renderItem, itemOf }),
|
|
105
|
+
[renderItem, itemOf],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Input validation keeps the grid API's issue codes; provider issues (zone
|
|
109
|
+
// geometry, handles) are translated. Repeating the same issues does not
|
|
110
|
+
// notify again, and an invalid value silences the zone issues it causes.
|
|
111
|
+
const valueValid = converted.state !== null;
|
|
112
|
+
const lastValueIssues = useRef<string | null>(null);
|
|
113
|
+
const lastProviderIssues = useRef<string | null>(null);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const key = converted.issues.length
|
|
116
|
+
? JSON.stringify(converted.issues)
|
|
117
|
+
: null;
|
|
118
|
+
if (key === lastValueIssues.current) return;
|
|
119
|
+
lastValueIssues.current = key;
|
|
120
|
+
if (key) onValidationError?.(converted.issues);
|
|
121
|
+
}, [converted.issues, onValidationError]);
|
|
122
|
+
const handleProviderIssues = useCallback(
|
|
123
|
+
(issues: LayoutValidationIssue[]) => {
|
|
124
|
+
if (!valueValid) return;
|
|
125
|
+
const key = issues.length ? JSON.stringify(issues) : null;
|
|
126
|
+
if (key === lastProviderIssues.current) return;
|
|
127
|
+
lastProviderIssues.current = key;
|
|
128
|
+
if (key) onValidationError?.(gridIssues(issues));
|
|
129
|
+
},
|
|
130
|
+
[onValidationError, valueValid],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const handleChange = useCallback(
|
|
134
|
+
(next: DndValue<T>, proposal: DndProposal<T>) => {
|
|
135
|
+
pendingProposal.current = proposal;
|
|
136
|
+
onChange(
|
|
137
|
+
layoutToGridValue(next),
|
|
138
|
+
gridChangeOf(proposal, includeBaseRevision),
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
[onChange, includeBaseRevision],
|
|
142
|
+
);
|
|
143
|
+
const handleDrop = useMemo(
|
|
144
|
+
() =>
|
|
145
|
+
canDrop
|
|
146
|
+
? (proposal: DndProposal<T>) => {
|
|
147
|
+
const item = itemOf(proposal.itemId);
|
|
148
|
+
if (!item) return { allowed: false, reason: 'unknown-item' };
|
|
149
|
+
return canDrop({
|
|
150
|
+
item,
|
|
151
|
+
change: gridChangeOf(proposal, includeBaseRevision),
|
|
152
|
+
proposedValue: layoutToGridValue(proposal.value),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
: undefined,
|
|
156
|
+
[canDrop, itemOf, includeBaseRevision],
|
|
157
|
+
);
|
|
158
|
+
const handleEnd = useCallback(
|
|
159
|
+
(event: DndDragEndEvent<T>) => {
|
|
160
|
+
pendingProposal.current = null;
|
|
161
|
+
onDragEnd?.(gridEndEvent(event, includeBaseRevision));
|
|
162
|
+
},
|
|
163
|
+
[onDragEnd, includeBaseRevision],
|
|
164
|
+
);
|
|
165
|
+
const handlePreview = useMemo(
|
|
166
|
+
() =>
|
|
167
|
+
renderDragPreview
|
|
168
|
+
? (args: DndPreviewArgs<T>) => {
|
|
169
|
+
const item = itemOf(args.item.id);
|
|
170
|
+
if (!item) return null;
|
|
171
|
+
return renderDragPreview({
|
|
172
|
+
item,
|
|
173
|
+
width: args.width,
|
|
174
|
+
height: args.height,
|
|
175
|
+
isDragging: true,
|
|
176
|
+
sessionId: args.sessionId,
|
|
177
|
+
onReady: args.onReady,
|
|
178
|
+
sourceZoneId: args.zoneId,
|
|
179
|
+
targetZoneId: args.targetZoneId,
|
|
180
|
+
validity: args.validity,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
: undefined,
|
|
184
|
+
[renderDragPreview, itemOf],
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<DndProvider<T>
|
|
189
|
+
{...viewProps}
|
|
190
|
+
ref={ref}
|
|
191
|
+
value={state}
|
|
192
|
+
onChange={handleChange}
|
|
193
|
+
canDrop={handleDrop}
|
|
194
|
+
onDragStart={onDragStart}
|
|
195
|
+
onDragSettled={handleEnd}
|
|
196
|
+
onValidationError={handleProviderIssues}
|
|
197
|
+
onDiagnostic={onDiagnostic}
|
|
198
|
+
searchBudget={searchBudget}
|
|
199
|
+
activation={activation}
|
|
200
|
+
movementPolicy={movementPolicy}
|
|
201
|
+
motion={motion}
|
|
202
|
+
responseTimeoutMs={responseTimeoutMs}
|
|
203
|
+
disabled={disabled || converted.state === null}
|
|
204
|
+
renderDragPreview={handlePreview}
|
|
205
|
+
waitForDragPreviewReady={waitForDragPreviewReady}
|
|
206
|
+
dragPreviewStyle={dragPreviewStyle}
|
|
207
|
+
>
|
|
208
|
+
<GridAdapterContext value={scope as GridAdapterScope<unknown>}>
|
|
209
|
+
{children}
|
|
210
|
+
</GridAdapterContext>
|
|
211
|
+
</DndProvider>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DragHandle } from './DragHandle';
|
|
2
|
+
import type { GridDragHandleProps } from './gridTypes';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A grid item's hit area. The provider owns one native recognizer per gesture
|
|
6
|
+
* relation signature, so mounting, re-rendering or unmounting a handle never
|
|
7
|
+
* creates, re-serializes or drops a native handler.
|
|
8
|
+
*/
|
|
9
|
+
export function GridDragHandle(props: GridDragHandleProps) {
|
|
10
|
+
return <DragHandle {...props} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useCallback, useContext } from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { GridItem } from '../types';
|
|
5
|
+
|
|
6
|
+
import type { GridItemRenderArgs } from './dndTypes';
|
|
7
|
+
import { GridAdapterContext } from './GridController';
|
|
8
|
+
import type { GridZoneViewProps } from './gridTypes';
|
|
9
|
+
import { SortableGrid } from './SortableGrid';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* One zone of a `GridController`: the provider's grid adapter rendering the
|
|
13
|
+
* controller's `renderItem` with the grid API's arguments. Ordered zones
|
|
14
|
+
* (`strategy: 'ordered'`) keep their slot layout and capacity.
|
|
15
|
+
*/
|
|
16
|
+
export function GridZoneView({
|
|
17
|
+
zoneId,
|
|
18
|
+
geometry,
|
|
19
|
+
children,
|
|
20
|
+
...props
|
|
21
|
+
}: GridZoneViewProps) {
|
|
22
|
+
const scope = useContext(GridAdapterContext);
|
|
23
|
+
if (!scope) throw new Error('GridZoneView must be inside GridController.');
|
|
24
|
+
const { renderItem, itemOf } = scope;
|
|
25
|
+
const renderCell = useCallback(
|
|
26
|
+
(args: GridItemRenderArgs<unknown>) => {
|
|
27
|
+
const item: GridItem<unknown> = itemOf(args.item.id) ?? {
|
|
28
|
+
id: args.item.id,
|
|
29
|
+
data: args.item.data,
|
|
30
|
+
span: args.span,
|
|
31
|
+
...(args.placement === undefined ? {} : { placement: args.placement }),
|
|
32
|
+
};
|
|
33
|
+
return renderItem({
|
|
34
|
+
item,
|
|
35
|
+
zoneId: args.zoneId,
|
|
36
|
+
width: args.width,
|
|
37
|
+
height: args.height,
|
|
38
|
+
isDragging: args.isDragging,
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
[renderItem, itemOf],
|
|
42
|
+
);
|
|
43
|
+
return (
|
|
44
|
+
<SortableGrid
|
|
45
|
+
{...props}
|
|
46
|
+
zoneId={zoneId}
|
|
47
|
+
geometry={geometry}
|
|
48
|
+
renderItem={renderCell}
|
|
49
|
+
// The grid API moves neighbors instead of drawing a destination marker.
|
|
50
|
+
dropIndicatorStyle={styles.noIndicator}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</SortableGrid>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const styles = StyleSheet.create({ noIndicator: { display: 'none' } });
|