dnd-block-tree 0.1.2 → 0.2.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/README.md CHANGED
@@ -4,11 +4,13 @@ A headless React library for building hierarchical drag-and-drop interfaces. Bri
4
4
 
5
5
  ## Features
6
6
 
7
- - **Weighted Collision Detection** - Custom algorithm that scores drop zones by edge distance with bottom bias for natural drag behavior
8
- - **Smart Drop Zones** - Only one before-zone rendered, none around active block. Prevents visual clutter and accidental drops
7
+ - **Stable Drop Zones** - Zones render based on original block positions, not preview state, ensuring consistent drop targets during drag
8
+ - **Ghost Preview** - Semi-transparent preview shows where blocks will land without affecting zone positions
9
+ - **Depth-Aware Collision** - Smart algorithm prefers nested zones when cursor is at indented levels, with hysteresis to prevent flickering
9
10
  - **8px Activation Distance** - Prevents accidental drags. Pointer must move 8px before drag starts, allowing normal clicks
10
11
  - **Snapshot-Based Computation** - State captured at drag start. All preview computations use snapshot, ensuring consistent behavior
11
12
  - **Debounced Preview** - 150ms debounced virtual state for smooth drag previews without jitter
13
+ - **Customizable Drag Rules** - `canDrag` and `canDrop` filters for fine-grained control over drag behavior
12
14
 
13
15
  ## Installation
14
16
 
@@ -64,6 +66,9 @@ function App() {
64
66
  | `dragOverlay` | `(block: T) => ReactNode` | - | Custom drag overlay renderer |
65
67
  | `activationDistance` | `number` | `8` | Pixels to move before drag starts |
66
68
  | `previewDebounce` | `number` | `150` | Debounce delay for preview updates |
69
+ | `showDropPreview` | `boolean` | `true` | Show live preview of block at drop position |
70
+ | `canDrag` | `(block: T) => boolean` | - | Filter which blocks can be dragged |
71
+ | `canDrop` | `(block, zone, target) => boolean` | - | Filter valid drop targets |
67
72
  | `className` | `string` | - | Root container class |
68
73
  | `dropZoneClassName` | `string` | - | Drop zone class |
69
74
  | `dropZoneActiveClassName` | `string` | - | Active drop zone class |
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import * as _dnd_kit_core from '@dnd-kit/core';
4
- import { UniqueIdentifier, CollisionDetection } from '@dnd-kit/core';
4
+ import { UniqueIdentifier, CollisionDetection, PointerActivationConstraint } from '@dnd-kit/core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  /**
@@ -40,11 +40,6 @@ interface ContainerRendererProps<T extends BaseBlock = BaseBlock> extends BlockR
40
40
  }
41
41
  /**
42
42
  * Get the appropriate props type for a renderer based on whether it's a container type
43
- *
44
- * @example
45
- * type SectionProps = RendererPropsFor<MyBlock, 'section', typeof CONTAINER_TYPES>
46
- * // If CONTAINER_TYPES includes 'section', this is ContainerRendererProps
47
- * // Otherwise, it's BlockRendererProps
48
43
  */
49
44
  type RendererPropsFor<T extends BaseBlock, K extends T['type'], C extends readonly string[]> = K extends C[number] ? ContainerRendererProps<T & {
50
45
  type: K;
@@ -53,14 +48,6 @@ type RendererPropsFor<T extends BaseBlock, K extends T['type'], C extends readon
53
48
  }>;
54
49
  /**
55
50
  * Map of block types to their renderers with automatic container detection
56
- *
57
- * @example
58
- * const CONTAINER_TYPES = ['section'] as const
59
- *
60
- * const renderers: BlockRenderers<MyBlock, typeof CONTAINER_TYPES> = {
61
- * section: (props) => <Section {...props} />, // props includes isExpanded, onToggleExpand
62
- * task: (props) => <Task {...props} />, // props is BlockRendererProps
63
- * }
64
51
  */
65
52
  type BlockRenderers<T extends BaseBlock = BaseBlock, C extends readonly string[] = readonly string[]> = {
66
53
  [K in T['type']]: (props: RendererPropsFor<T, K, C>) => ReactNode;
@@ -71,6 +58,167 @@ type BlockRenderers<T extends BaseBlock = BaseBlock, C extends readonly string[]
71
58
  type InternalRenderers<T extends BaseBlock = BaseBlock> = {
72
59
  [K in T['type']]: (props: BlockRendererProps<T> | ContainerRendererProps<T>) => ReactNode;
73
60
  };
61
+ /**
62
+ * Position info for a block
63
+ */
64
+ interface BlockPosition {
65
+ parentId: string | null;
66
+ index: number;
67
+ }
68
+ /**
69
+ * Event fired when drag starts
70
+ */
71
+ interface DragStartEvent<T extends BaseBlock = BaseBlock> {
72
+ block: T;
73
+ blockId: string;
74
+ }
75
+ /**
76
+ * Event fired during drag movement
77
+ */
78
+ interface DragMoveEvent<T extends BaseBlock = BaseBlock> {
79
+ block: T;
80
+ blockId: string;
81
+ /** Current hover zone ID, if any */
82
+ overZone: string | null;
83
+ /** Pointer coordinates */
84
+ coordinates: {
85
+ x: number;
86
+ y: number;
87
+ };
88
+ }
89
+ /**
90
+ * Event fired when drag ends
91
+ */
92
+ interface DragEndEvent<T extends BaseBlock = BaseBlock> {
93
+ block: T;
94
+ blockId: string;
95
+ /** Target zone where block was dropped */
96
+ targetZone: string | null;
97
+ /** Whether the drag was cancelled */
98
+ cancelled: boolean;
99
+ }
100
+ /**
101
+ * Event fired when a block is moved
102
+ */
103
+ interface BlockMoveEvent<T extends BaseBlock = BaseBlock> {
104
+ block: T;
105
+ from: BlockPosition;
106
+ to: BlockPosition;
107
+ /** All blocks after the move */
108
+ blocks: T[];
109
+ }
110
+ /**
111
+ * Event fired when expand state changes
112
+ */
113
+ interface ExpandChangeEvent<T extends BaseBlock = BaseBlock> {
114
+ block: T;
115
+ blockId: string;
116
+ expanded: boolean;
117
+ }
118
+ /**
119
+ * Event fired when hover zone changes
120
+ */
121
+ interface HoverChangeEvent<T extends BaseBlock = BaseBlock> {
122
+ zoneId: string | null;
123
+ zoneType: DropZoneType | null;
124
+ /** Block being hovered over (if any) */
125
+ targetBlock: T | null;
126
+ }
127
+ /**
128
+ * All available callback handlers for BlockTree
129
+ */
130
+ interface BlockTreeCallbacks<T extends BaseBlock = BaseBlock> {
131
+ /** Called when drag starts. Return false to prevent drag. */
132
+ onDragStart?: (event: DragStartEvent<T>) => boolean | void;
133
+ /** Called during drag movement (debounced) */
134
+ onDragMove?: (event: DragMoveEvent<T>) => void;
135
+ /** Called when drag ends (success or cancel) */
136
+ onDragEnd?: (event: DragEndEvent<T>) => void;
137
+ /** Called when drag is cancelled */
138
+ onDragCancel?: (event: DragEndEvent<T>) => void;
139
+ /** Called after a block is moved to a new position */
140
+ onBlockMove?: (event: BlockMoveEvent<T>) => void;
141
+ /** Called when expand/collapse state changes */
142
+ onExpandChange?: (event: ExpandChangeEvent<T>) => void;
143
+ /** Called when hover zone changes during drag */
144
+ onHoverChange?: (event: HoverChangeEvent<T>) => void;
145
+ }
146
+ /**
147
+ * Filter function to determine if a block can be dragged
148
+ */
149
+ type CanDragFn<T extends BaseBlock = BaseBlock> = (block: T) => boolean;
150
+ /**
151
+ * Filter function to determine if a block can be dropped at a location
152
+ */
153
+ type CanDropFn<T extends BaseBlock = BaseBlock> = (draggedBlock: T, targetZone: string, targetBlock: T | null) => boolean;
154
+ /**
155
+ * Custom ID generator function
156
+ */
157
+ type IdGeneratorFn = () => string;
158
+ /**
159
+ * Sensor configuration
160
+ */
161
+ interface SensorConfig {
162
+ activationDistance?: number;
163
+ activationDelay?: number;
164
+ tolerance?: number;
165
+ }
166
+ /**
167
+ * Drop zone configuration
168
+ */
169
+ interface DropZoneConfig {
170
+ /** Height of drop zones in pixels */
171
+ height?: number;
172
+ /** Gap between drop zones */
173
+ gap?: number;
174
+ /** Show drop zones inside empty containers */
175
+ showInEmptyContainers?: boolean;
176
+ }
177
+ /**
178
+ * Animation configuration
179
+ */
180
+ interface AnimationConfig {
181
+ /** Duration for expand/collapse animations in ms */
182
+ expandDuration?: number;
183
+ /** Duration for drag overlay animation in ms */
184
+ dragOverlayDuration?: number;
185
+ /** Easing function (CSS timing function) */
186
+ easing?: string;
187
+ }
188
+ /**
189
+ * Auto-expand configuration for containers during drag
190
+ */
191
+ interface AutoExpandConfig {
192
+ /** Enable auto-expand on hover */
193
+ enabled?: boolean;
194
+ /** Delay before expanding in ms */
195
+ delay?: number;
196
+ /** Auto-collapse when leaving */
197
+ collapseOnLeave?: boolean;
198
+ }
199
+ /**
200
+ * Full customization options for BlockTree
201
+ */
202
+ interface BlockTreeCustomization<T extends BaseBlock = BaseBlock> {
203
+ /** Filter which blocks can be dragged */
204
+ canDrag?: CanDragFn<T>;
205
+ /** Filter valid drop targets */
206
+ canDrop?: CanDropFn<T>;
207
+ /** Custom collision detection algorithm */
208
+ collisionDetection?: CollisionDetection;
209
+ /** Sensor configuration */
210
+ sensors?: SensorConfig;
211
+ /** Drop zone configuration */
212
+ dropZones?: DropZoneConfig;
213
+ /** Animation configuration */
214
+ animation?: AnimationConfig;
215
+ /** Auto-expand containers during drag */
216
+ autoExpand?: AutoExpandConfig;
217
+ /** Custom ID generator */
218
+ idGenerator?: IdGeneratorFn;
219
+ /** Initially expanded block IDs */
220
+ initialExpanded?: string[] | 'all' | 'none';
221
+ }
74
222
  /**
75
223
  * Block action types for the reducer
76
224
  */
@@ -184,16 +332,33 @@ interface TreeStateProviderProps<T extends BaseBlock = BaseBlock> {
184
332
  * - Returns single winner (lowest score)
185
333
  */
186
334
  declare const weightedVerticalCollision: CollisionDetection;
335
+ /**
336
+ * Create a collision detection with hysteresis to prevent flickering
337
+ * between adjacent drop zones.
338
+ *
339
+ * @param threshold - Minimum score improvement required to switch zones (default: 15px)
340
+ */
341
+ declare function createStickyCollision(threshold?: number): CollisionDetection & {
342
+ reset: () => void;
343
+ };
187
344
  /**
188
345
  * Simple closest center collision (fallback)
189
346
  */
190
347
  declare const closestCenterCollision: CollisionDetection;
191
348
 
192
- interface SensorConfig {
193
- activationDistance?: number;
349
+ /**
350
+ * Return type for getSensorConfig
351
+ */
352
+ interface SensorConfigResult {
353
+ pointer: {
354
+ activationConstraint: PointerActivationConstraint;
355
+ };
356
+ touch: {
357
+ activationConstraint: PointerActivationConstraint;
358
+ };
194
359
  }
195
360
  /**
196
- * Create configured sensors with activation distance constraint.
361
+ * Create configured sensors with activation constraints.
197
362
  * The activation distance prevents accidental drags while still allowing clicks.
198
363
  *
199
364
  * @param config - Sensor configuration
@@ -203,20 +368,9 @@ declare function useConfiguredSensors(config?: SensorConfig): _dnd_kit_core.Sens
203
368
  /**
204
369
  * Get sensor configuration for manual setup
205
370
  */
206
- declare function getSensorConfig(activationDistance?: number): {
207
- pointer: {
208
- activationConstraint: {
209
- distance: number;
210
- };
211
- };
212
- touch: {
213
- activationConstraint: {
214
- distance: number;
215
- };
216
- };
217
- };
371
+ declare function getSensorConfig(config?: SensorConfig): SensorConfigResult;
218
372
 
219
- interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]> {
373
+ interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]> extends BlockTreeCallbacks<T>, BlockTreeCustomization<T> {
220
374
  /** Current blocks array */
221
375
  blocks: T[];
222
376
  /** Block renderers for each type */
@@ -239,12 +393,14 @@ interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = r
239
393
  dropZoneActiveClassName?: string;
240
394
  /** Indent className for nested items */
241
395
  indentClassName?: string;
396
+ /** Show live preview of drop position during drag (default: true) */
397
+ showDropPreview?: boolean;
242
398
  }
243
399
  /**
244
400
  * Main BlockTree component
245
401
  * Provides drag-and-drop functionality for hierarchical block structures
246
402
  */
247
- declare function BlockTree<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]>({ blocks, renderers, containerTypes, onChange, dragOverlay, activationDistance, previewDebounce, className, dropZoneClassName, dropZoneActiveClassName, indentClassName, }: BlockTreeProps<T, C>): react_jsx_runtime.JSX.Element;
403
+ declare function BlockTree<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]>({ blocks, renderers, containerTypes, onChange, dragOverlay, activationDistance, previewDebounce, className, dropZoneClassName, dropZoneActiveClassName, indentClassName, showDropPreview, onDragStart, onDragMove, onDragEnd, onDragCancel, onBlockMove, onExpandChange, onHoverChange, canDrag, canDrop, collisionDetection, sensors: sensorConfig, initialExpanded, }: BlockTreeProps<T, C>): react_jsx_runtime.JSX.Element;
248
404
 
249
405
  interface TreeRendererProps<T extends BaseBlock> {
250
406
  blocks: T[];
@@ -261,11 +417,19 @@ interface TreeRendererProps<T extends BaseBlock> {
261
417
  dropZoneActiveClassName?: string;
262
418
  indentClassName?: string;
263
419
  rootClassName?: string;
420
+ canDrag?: CanDragFn<T>;
421
+ /** Preview position info - where to show the ghost */
422
+ previewPosition?: {
423
+ parentId: string | null;
424
+ index: number;
425
+ } | null;
426
+ /** The dragged block for rendering preview ghost */
427
+ draggedBlock?: T | null;
264
428
  }
265
429
  /**
266
430
  * Recursive tree renderer with smart drop zones
267
431
  */
268
- declare function TreeRenderer<T extends BaseBlock>({ blocks, blocksByParent, parentId, activeId, expandedMap, renderers, containerTypes, onHover, onToggleExpand, depth, dropZoneClassName, dropZoneActiveClassName, indentClassName, rootClassName, }: TreeRendererProps<T>): react_jsx_runtime.JSX.Element;
432
+ declare function TreeRenderer<T extends BaseBlock>({ blocks, blocksByParent, parentId, activeId, expandedMap, renderers, containerTypes, onHover, onToggleExpand, depth, dropZoneClassName, dropZoneActiveClassName, indentClassName, rootClassName, canDrag, previewPosition, draggedBlock, }: TreeRendererProps<T>): react_jsx_runtime.JSX.Element;
269
433
 
270
434
  interface DropZoneProps {
271
435
  id: string;
@@ -349,7 +513,7 @@ declare function getDescendantIds<T extends BaseBlock>(state: BlockIndex<T>, par
349
513
  declare function deleteBlockAndDescendants<T extends BaseBlock>(state: BlockIndex<T>, id: string): BlockIndex<T>;
350
514
 
351
515
  /**
352
- * Extract UUID from a zone ID by removing the prefix (before-, after-, into-)
516
+ * Extract UUID from a zone ID by removing the prefix (before-, after-, into-, end-)
353
517
  */
354
518
  declare function extractUUID(id: string, pattern?: string): string;
355
519
  /**
@@ -363,4 +527,4 @@ declare function debounce<Args extends unknown[]>(fn: (...args: Args) => void, d
363
527
  */
364
528
  declare function generateId(): string;
365
529
 
366
- export { type BaseBlock, type BlockAction, type BlockIndex, type BlockRendererProps, type BlockRenderers, type BlockStateContextValue, type BlockStateProviderProps, BlockTree, type BlockTreeConfig, type BlockTreeProps, type ContainerRendererProps, DragOverlay, type DragOverlayProps$1 as DragOverlayProps, DropZone, type DropZoneProps, type DropZoneType, type RendererPropsFor, TreeRenderer, type TreeRendererProps, type TreeStateContextValue, type TreeStateProviderProps, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, computeNormalizedIndex, createBlockState, createTreeState, debounce, deleteBlockAndDescendants, extractBlockId, extractUUID, generateId, getDescendantIds, getDropZoneType, getSensorConfig, reparentBlockIndex, useConfiguredSensors, weightedVerticalCollision };
530
+ export { type AnimationConfig, type AutoExpandConfig, type BaseBlock, type BlockAction, type BlockIndex, type BlockMoveEvent, type BlockPosition, type BlockRendererProps, type BlockRenderers, type BlockStateContextValue, type BlockStateProviderProps, BlockTree, type BlockTreeCallbacks, type BlockTreeConfig, type BlockTreeCustomization, type BlockTreeProps, type CanDragFn, type CanDropFn, type ContainerRendererProps, type DragEndEvent, type DragMoveEvent, DragOverlay, type DragOverlayProps$1 as DragOverlayProps, type DragStartEvent, DropZone, type DropZoneConfig, type DropZoneProps, type DropZoneType, type ExpandChangeEvent, type HoverChangeEvent, type IdGeneratorFn, type InternalRenderers, type RendererPropsFor, type SensorConfig, TreeRenderer, type TreeRendererProps, type TreeStateContextValue, type TreeStateProviderProps, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, computeNormalizedIndex, createBlockState, createStickyCollision, createTreeState, debounce, deleteBlockAndDescendants, extractBlockId, extractUUID, generateId, getDescendantIds, getDropZoneType, getSensorConfig, reparentBlockIndex, useConfiguredSensors, weightedVerticalCollision };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import * as _dnd_kit_core from '@dnd-kit/core';
4
- import { UniqueIdentifier, CollisionDetection } from '@dnd-kit/core';
4
+ import { UniqueIdentifier, CollisionDetection, PointerActivationConstraint } from '@dnd-kit/core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  /**
@@ -40,11 +40,6 @@ interface ContainerRendererProps<T extends BaseBlock = BaseBlock> extends BlockR
40
40
  }
41
41
  /**
42
42
  * Get the appropriate props type for a renderer based on whether it's a container type
43
- *
44
- * @example
45
- * type SectionProps = RendererPropsFor<MyBlock, 'section', typeof CONTAINER_TYPES>
46
- * // If CONTAINER_TYPES includes 'section', this is ContainerRendererProps
47
- * // Otherwise, it's BlockRendererProps
48
43
  */
49
44
  type RendererPropsFor<T extends BaseBlock, K extends T['type'], C extends readonly string[]> = K extends C[number] ? ContainerRendererProps<T & {
50
45
  type: K;
@@ -53,14 +48,6 @@ type RendererPropsFor<T extends BaseBlock, K extends T['type'], C extends readon
53
48
  }>;
54
49
  /**
55
50
  * Map of block types to their renderers with automatic container detection
56
- *
57
- * @example
58
- * const CONTAINER_TYPES = ['section'] as const
59
- *
60
- * const renderers: BlockRenderers<MyBlock, typeof CONTAINER_TYPES> = {
61
- * section: (props) => <Section {...props} />, // props includes isExpanded, onToggleExpand
62
- * task: (props) => <Task {...props} />, // props is BlockRendererProps
63
- * }
64
51
  */
65
52
  type BlockRenderers<T extends BaseBlock = BaseBlock, C extends readonly string[] = readonly string[]> = {
66
53
  [K in T['type']]: (props: RendererPropsFor<T, K, C>) => ReactNode;
@@ -71,6 +58,167 @@ type BlockRenderers<T extends BaseBlock = BaseBlock, C extends readonly string[]
71
58
  type InternalRenderers<T extends BaseBlock = BaseBlock> = {
72
59
  [K in T['type']]: (props: BlockRendererProps<T> | ContainerRendererProps<T>) => ReactNode;
73
60
  };
61
+ /**
62
+ * Position info for a block
63
+ */
64
+ interface BlockPosition {
65
+ parentId: string | null;
66
+ index: number;
67
+ }
68
+ /**
69
+ * Event fired when drag starts
70
+ */
71
+ interface DragStartEvent<T extends BaseBlock = BaseBlock> {
72
+ block: T;
73
+ blockId: string;
74
+ }
75
+ /**
76
+ * Event fired during drag movement
77
+ */
78
+ interface DragMoveEvent<T extends BaseBlock = BaseBlock> {
79
+ block: T;
80
+ blockId: string;
81
+ /** Current hover zone ID, if any */
82
+ overZone: string | null;
83
+ /** Pointer coordinates */
84
+ coordinates: {
85
+ x: number;
86
+ y: number;
87
+ };
88
+ }
89
+ /**
90
+ * Event fired when drag ends
91
+ */
92
+ interface DragEndEvent<T extends BaseBlock = BaseBlock> {
93
+ block: T;
94
+ blockId: string;
95
+ /** Target zone where block was dropped */
96
+ targetZone: string | null;
97
+ /** Whether the drag was cancelled */
98
+ cancelled: boolean;
99
+ }
100
+ /**
101
+ * Event fired when a block is moved
102
+ */
103
+ interface BlockMoveEvent<T extends BaseBlock = BaseBlock> {
104
+ block: T;
105
+ from: BlockPosition;
106
+ to: BlockPosition;
107
+ /** All blocks after the move */
108
+ blocks: T[];
109
+ }
110
+ /**
111
+ * Event fired when expand state changes
112
+ */
113
+ interface ExpandChangeEvent<T extends BaseBlock = BaseBlock> {
114
+ block: T;
115
+ blockId: string;
116
+ expanded: boolean;
117
+ }
118
+ /**
119
+ * Event fired when hover zone changes
120
+ */
121
+ interface HoverChangeEvent<T extends BaseBlock = BaseBlock> {
122
+ zoneId: string | null;
123
+ zoneType: DropZoneType | null;
124
+ /** Block being hovered over (if any) */
125
+ targetBlock: T | null;
126
+ }
127
+ /**
128
+ * All available callback handlers for BlockTree
129
+ */
130
+ interface BlockTreeCallbacks<T extends BaseBlock = BaseBlock> {
131
+ /** Called when drag starts. Return false to prevent drag. */
132
+ onDragStart?: (event: DragStartEvent<T>) => boolean | void;
133
+ /** Called during drag movement (debounced) */
134
+ onDragMove?: (event: DragMoveEvent<T>) => void;
135
+ /** Called when drag ends (success or cancel) */
136
+ onDragEnd?: (event: DragEndEvent<T>) => void;
137
+ /** Called when drag is cancelled */
138
+ onDragCancel?: (event: DragEndEvent<T>) => void;
139
+ /** Called after a block is moved to a new position */
140
+ onBlockMove?: (event: BlockMoveEvent<T>) => void;
141
+ /** Called when expand/collapse state changes */
142
+ onExpandChange?: (event: ExpandChangeEvent<T>) => void;
143
+ /** Called when hover zone changes during drag */
144
+ onHoverChange?: (event: HoverChangeEvent<T>) => void;
145
+ }
146
+ /**
147
+ * Filter function to determine if a block can be dragged
148
+ */
149
+ type CanDragFn<T extends BaseBlock = BaseBlock> = (block: T) => boolean;
150
+ /**
151
+ * Filter function to determine if a block can be dropped at a location
152
+ */
153
+ type CanDropFn<T extends BaseBlock = BaseBlock> = (draggedBlock: T, targetZone: string, targetBlock: T | null) => boolean;
154
+ /**
155
+ * Custom ID generator function
156
+ */
157
+ type IdGeneratorFn = () => string;
158
+ /**
159
+ * Sensor configuration
160
+ */
161
+ interface SensorConfig {
162
+ activationDistance?: number;
163
+ activationDelay?: number;
164
+ tolerance?: number;
165
+ }
166
+ /**
167
+ * Drop zone configuration
168
+ */
169
+ interface DropZoneConfig {
170
+ /** Height of drop zones in pixels */
171
+ height?: number;
172
+ /** Gap between drop zones */
173
+ gap?: number;
174
+ /** Show drop zones inside empty containers */
175
+ showInEmptyContainers?: boolean;
176
+ }
177
+ /**
178
+ * Animation configuration
179
+ */
180
+ interface AnimationConfig {
181
+ /** Duration for expand/collapse animations in ms */
182
+ expandDuration?: number;
183
+ /** Duration for drag overlay animation in ms */
184
+ dragOverlayDuration?: number;
185
+ /** Easing function (CSS timing function) */
186
+ easing?: string;
187
+ }
188
+ /**
189
+ * Auto-expand configuration for containers during drag
190
+ */
191
+ interface AutoExpandConfig {
192
+ /** Enable auto-expand on hover */
193
+ enabled?: boolean;
194
+ /** Delay before expanding in ms */
195
+ delay?: number;
196
+ /** Auto-collapse when leaving */
197
+ collapseOnLeave?: boolean;
198
+ }
199
+ /**
200
+ * Full customization options for BlockTree
201
+ */
202
+ interface BlockTreeCustomization<T extends BaseBlock = BaseBlock> {
203
+ /** Filter which blocks can be dragged */
204
+ canDrag?: CanDragFn<T>;
205
+ /** Filter valid drop targets */
206
+ canDrop?: CanDropFn<T>;
207
+ /** Custom collision detection algorithm */
208
+ collisionDetection?: CollisionDetection;
209
+ /** Sensor configuration */
210
+ sensors?: SensorConfig;
211
+ /** Drop zone configuration */
212
+ dropZones?: DropZoneConfig;
213
+ /** Animation configuration */
214
+ animation?: AnimationConfig;
215
+ /** Auto-expand containers during drag */
216
+ autoExpand?: AutoExpandConfig;
217
+ /** Custom ID generator */
218
+ idGenerator?: IdGeneratorFn;
219
+ /** Initially expanded block IDs */
220
+ initialExpanded?: string[] | 'all' | 'none';
221
+ }
74
222
  /**
75
223
  * Block action types for the reducer
76
224
  */
@@ -184,16 +332,33 @@ interface TreeStateProviderProps<T extends BaseBlock = BaseBlock> {
184
332
  * - Returns single winner (lowest score)
185
333
  */
186
334
  declare const weightedVerticalCollision: CollisionDetection;
335
+ /**
336
+ * Create a collision detection with hysteresis to prevent flickering
337
+ * between adjacent drop zones.
338
+ *
339
+ * @param threshold - Minimum score improvement required to switch zones (default: 15px)
340
+ */
341
+ declare function createStickyCollision(threshold?: number): CollisionDetection & {
342
+ reset: () => void;
343
+ };
187
344
  /**
188
345
  * Simple closest center collision (fallback)
189
346
  */
190
347
  declare const closestCenterCollision: CollisionDetection;
191
348
 
192
- interface SensorConfig {
193
- activationDistance?: number;
349
+ /**
350
+ * Return type for getSensorConfig
351
+ */
352
+ interface SensorConfigResult {
353
+ pointer: {
354
+ activationConstraint: PointerActivationConstraint;
355
+ };
356
+ touch: {
357
+ activationConstraint: PointerActivationConstraint;
358
+ };
194
359
  }
195
360
  /**
196
- * Create configured sensors with activation distance constraint.
361
+ * Create configured sensors with activation constraints.
197
362
  * The activation distance prevents accidental drags while still allowing clicks.
198
363
  *
199
364
  * @param config - Sensor configuration
@@ -203,20 +368,9 @@ declare function useConfiguredSensors(config?: SensorConfig): _dnd_kit_core.Sens
203
368
  /**
204
369
  * Get sensor configuration for manual setup
205
370
  */
206
- declare function getSensorConfig(activationDistance?: number): {
207
- pointer: {
208
- activationConstraint: {
209
- distance: number;
210
- };
211
- };
212
- touch: {
213
- activationConstraint: {
214
- distance: number;
215
- };
216
- };
217
- };
371
+ declare function getSensorConfig(config?: SensorConfig): SensorConfigResult;
218
372
 
219
- interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]> {
373
+ interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]> extends BlockTreeCallbacks<T>, BlockTreeCustomization<T> {
220
374
  /** Current blocks array */
221
375
  blocks: T[];
222
376
  /** Block renderers for each type */
@@ -239,12 +393,14 @@ interface BlockTreeProps<T extends BaseBlock, C extends readonly T['type'][] = r
239
393
  dropZoneActiveClassName?: string;
240
394
  /** Indent className for nested items */
241
395
  indentClassName?: string;
396
+ /** Show live preview of drop position during drag (default: true) */
397
+ showDropPreview?: boolean;
242
398
  }
243
399
  /**
244
400
  * Main BlockTree component
245
401
  * Provides drag-and-drop functionality for hierarchical block structures
246
402
  */
247
- declare function BlockTree<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]>({ blocks, renderers, containerTypes, onChange, dragOverlay, activationDistance, previewDebounce, className, dropZoneClassName, dropZoneActiveClassName, indentClassName, }: BlockTreeProps<T, C>): react_jsx_runtime.JSX.Element;
403
+ declare function BlockTree<T extends BaseBlock, C extends readonly T['type'][] = readonly T['type'][]>({ blocks, renderers, containerTypes, onChange, dragOverlay, activationDistance, previewDebounce, className, dropZoneClassName, dropZoneActiveClassName, indentClassName, showDropPreview, onDragStart, onDragMove, onDragEnd, onDragCancel, onBlockMove, onExpandChange, onHoverChange, canDrag, canDrop, collisionDetection, sensors: sensorConfig, initialExpanded, }: BlockTreeProps<T, C>): react_jsx_runtime.JSX.Element;
248
404
 
249
405
  interface TreeRendererProps<T extends BaseBlock> {
250
406
  blocks: T[];
@@ -261,11 +417,19 @@ interface TreeRendererProps<T extends BaseBlock> {
261
417
  dropZoneActiveClassName?: string;
262
418
  indentClassName?: string;
263
419
  rootClassName?: string;
420
+ canDrag?: CanDragFn<T>;
421
+ /** Preview position info - where to show the ghost */
422
+ previewPosition?: {
423
+ parentId: string | null;
424
+ index: number;
425
+ } | null;
426
+ /** The dragged block for rendering preview ghost */
427
+ draggedBlock?: T | null;
264
428
  }
265
429
  /**
266
430
  * Recursive tree renderer with smart drop zones
267
431
  */
268
- declare function TreeRenderer<T extends BaseBlock>({ blocks, blocksByParent, parentId, activeId, expandedMap, renderers, containerTypes, onHover, onToggleExpand, depth, dropZoneClassName, dropZoneActiveClassName, indentClassName, rootClassName, }: TreeRendererProps<T>): react_jsx_runtime.JSX.Element;
432
+ declare function TreeRenderer<T extends BaseBlock>({ blocks, blocksByParent, parentId, activeId, expandedMap, renderers, containerTypes, onHover, onToggleExpand, depth, dropZoneClassName, dropZoneActiveClassName, indentClassName, rootClassName, canDrag, previewPosition, draggedBlock, }: TreeRendererProps<T>): react_jsx_runtime.JSX.Element;
269
433
 
270
434
  interface DropZoneProps {
271
435
  id: string;
@@ -349,7 +513,7 @@ declare function getDescendantIds<T extends BaseBlock>(state: BlockIndex<T>, par
349
513
  declare function deleteBlockAndDescendants<T extends BaseBlock>(state: BlockIndex<T>, id: string): BlockIndex<T>;
350
514
 
351
515
  /**
352
- * Extract UUID from a zone ID by removing the prefix (before-, after-, into-)
516
+ * Extract UUID from a zone ID by removing the prefix (before-, after-, into-, end-)
353
517
  */
354
518
  declare function extractUUID(id: string, pattern?: string): string;
355
519
  /**
@@ -363,4 +527,4 @@ declare function debounce<Args extends unknown[]>(fn: (...args: Args) => void, d
363
527
  */
364
528
  declare function generateId(): string;
365
529
 
366
- export { type BaseBlock, type BlockAction, type BlockIndex, type BlockRendererProps, type BlockRenderers, type BlockStateContextValue, type BlockStateProviderProps, BlockTree, type BlockTreeConfig, type BlockTreeProps, type ContainerRendererProps, DragOverlay, type DragOverlayProps$1 as DragOverlayProps, DropZone, type DropZoneProps, type DropZoneType, type RendererPropsFor, TreeRenderer, type TreeRendererProps, type TreeStateContextValue, type TreeStateProviderProps, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, computeNormalizedIndex, createBlockState, createTreeState, debounce, deleteBlockAndDescendants, extractBlockId, extractUUID, generateId, getDescendantIds, getDropZoneType, getSensorConfig, reparentBlockIndex, useConfiguredSensors, weightedVerticalCollision };
530
+ export { type AnimationConfig, type AutoExpandConfig, type BaseBlock, type BlockAction, type BlockIndex, type BlockMoveEvent, type BlockPosition, type BlockRendererProps, type BlockRenderers, type BlockStateContextValue, type BlockStateProviderProps, BlockTree, type BlockTreeCallbacks, type BlockTreeConfig, type BlockTreeCustomization, type BlockTreeProps, type CanDragFn, type CanDropFn, type ContainerRendererProps, type DragEndEvent, type DragMoveEvent, DragOverlay, type DragOverlayProps$1 as DragOverlayProps, type DragStartEvent, DropZone, type DropZoneConfig, type DropZoneProps, type DropZoneType, type ExpandChangeEvent, type HoverChangeEvent, type IdGeneratorFn, type InternalRenderers, type RendererPropsFor, type SensorConfig, TreeRenderer, type TreeRendererProps, type TreeStateContextValue, type TreeStateProviderProps, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, computeNormalizedIndex, createBlockState, createStickyCollision, createTreeState, debounce, deleteBlockAndDescendants, extractBlockId, extractUUID, generateId, getDescendantIds, getDropZoneType, getSensorConfig, reparentBlockIndex, useConfiguredSensors, weightedVerticalCollision };