or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-provider.mddrag-layer.mddrag-sources.mddrop-targets.mdindex.mdutilities.md

utilities.mddocs/

0

# Utilities

1

2

React DnD provides utility components and functions for advanced drag and drop scenarios and integration with the underlying drag and drop system.

3

4

## Capabilities

5

6

### DragPreviewImage

7

8

Utility component for rendering drag preview images with proper lifecycle management.

9

10

```typescript { .api }

11

/**

12

* A utility component for rendering a drag preview image

13

* @param props - Preview image configuration

14

* @returns React element (renders null, used for side effects)

15

*/

16

function DragPreviewImage(props: DragPreviewImageProps): React.ReactElement;

17

18

interface DragPreviewImageProps {

19

/** Connector function from useDrag hook */

20

connect: ConnectDragPreview;

21

/** Image source URL */

22

src: string;

23

}

24

```

25

26

**Usage Example:**

27

28

```typescript

29

import React from "react";

30

import { useDrag, DragPreviewImage } from "react-dnd";

31

32

function DraggableWithImagePreview({ id, name, previewImageUrl }) {

33

const [{ isDragging }, drag, preview] = useDrag({

34

type: "item",

35

item: { id, name },

36

collect: (monitor) => ({

37

isDragging: monitor.isDragging(),

38

}),

39

});

40

41

return (

42

<div>

43

{/* The DragPreviewImage component handles image loading and connection */}

44

<DragPreviewImage connect={preview} src={previewImageUrl} />

45

46

<div

47

ref={drag}

48

style={{ opacity: isDragging ? 0.5 : 1 }}

49

>

50

{name}

51

</div>

52

</div>

53

);

54

}

55

```

56

57

**Advanced Usage with Dynamic Images:**

58

59

```typescript

60

import React, { useState, useEffect } from "react";

61

import { useDrag, DragPreviewImage } from "react-dnd";

62

63

function DynamicPreviewItem({ item }) {

64

const [previewUrl, setPreviewUrl] = useState(null);

65

66

const [{ isDragging }, drag, preview] = useDrag({

67

type: "item",

68

item,

69

collect: (monitor) => ({

70

isDragging: monitor.isDragging(),

71

}),

72

});

73

74

// Generate or fetch preview image

75

useEffect(() => {

76

generatePreviewImage(item).then(setPreviewUrl);

77

}, [item]);

78

79

return (

80

<div>

81

{previewUrl && <DragPreviewImage connect={preview} src={previewUrl} />}

82

83

<div ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>

84

<ItemContent item={item} />

85

</div>

86

</div>

87

);

88

}

89

90

async function generatePreviewImage(item) {

91

// Generate canvas-based preview or fetch from API

92

const canvas = document.createElement("canvas");

93

const ctx = canvas.getContext("2d");

94

95

canvas.width = 200;

96

canvas.height = 100;

97

98

ctx.fillStyle = "#f0f0f0";

99

ctx.fillRect(0, 0, canvas.width, canvas.height);

100

ctx.fillStyle = "#333";

101

ctx.font = "16px Arial";

102

ctx.fillText(item.name, 10, 50);

103

104

return canvas.toDataURL();

105

}

106

```

107

108

### useDragDropManager Hook

109

110

Low-level hook for accessing the DragDropManager instance directly for advanced operations.

111

112

```typescript { .api }

113

/**

114

* Hook to retrieve the DragDropManager from Context

115

* @returns DragDropManager instance

116

* @throws Error if used outside DndProvider

117

*/

118

function useDragDropManager(): DragDropManager;

119

```

120

121

**Usage Examples:**

122

123

```typescript

124

import React, { useEffect, useState } from "react";

125

import { useDragDropManager } from "react-dnd";

126

127

function AdvancedDragMonitor() {

128

const manager = useDragDropManager();

129

const [dragState, setDragState] = useState({});

130

131

useEffect(() => {

132

const monitor = manager.getMonitor();

133

134

// Subscribe to all drag and drop state changes

135

const unsubscribe = monitor.subscribeToStateChange(() => {

136

setDragState({

137

isDragging: monitor.isDragging(),

138

itemType: monitor.getItemType(),

139

item: monitor.getItem(),

140

dropResult: monitor.getDropResult(),

141

clientOffset: monitor.getClientOffset(),

142

});

143

});

144

145

return unsubscribe;

146

}, [manager]);

147

148

return (

149

<div className="drag-monitor">

150

<h3>Global Drag State</h3>

151

<pre>{JSON.stringify(dragState, null, 2)}</pre>

152

</div>

153

);

154

}

155

```

156

157

**Backend Management:**

158

159

```typescript

160

import React, { useEffect } from "react";

161

import { useDragDropManager } from "react-dnd";

162

163

function BackendController() {

164

const manager = useDragDropManager();

165

166

useEffect(() => {

167

const backend = manager.getBackend();

168

169

// Access backend-specific functionality

170

if (backend.setup) {

171

backend.setup();

172

}

173

174

// Custom backend configuration

175

if (backend.addEventListener) {

176

backend.addEventListener("dragstart", handleDragStart);

177

backend.addEventListener("dragend", handleDragEnd);

178

}

179

180

return () => {

181

if (backend.teardown) {

182

backend.teardown();

183

}

184

};

185

}, [manager]);

186

187

const handleDragStart = (event) => {

188

console.log("Backend drag start:", event);

189

};

190

191

const handleDragEnd = (event) => {

192

console.log("Backend drag end:", event);

193

};

194

195

return <div>Backend Controller Active</div>;

196

}

197

```

198

199

### Type Guards and Utilities

200

201

Utility functions for working with React DnD types and values.

202

203

```typescript { .api }

204

/** Utility type for values that can be provided as instance or factory */

205

type FactoryOrInstance<T> = T | (() => T);

206

207

/** Factory function type for creating drag objects */

208

type DragObjectFactory<T> = (monitor: DragSourceMonitor<T>) => T | null;

209

210

/** Coordinate pair for pointer/element positions */

211

interface XYCoord {

212

x: number;

213

y: number;

214

}

215

216

/** Valid element types that can be connected for drag/drop */

217

type ConnectableElement = React.RefObject<any> | React.ReactElement | Element | null;

218

```

219

220

**Utility Functions Example:**

221

222

```typescript

223

import React from "react";

224

import type { XYCoord, ConnectableElement } from "react-dnd";

225

226

// Helper function to calculate distance between coordinates

227

function calculateDistance(a: XYCoord, b: XYCoord): number {

228

return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

229

}

230

231

// Helper function to check if element is connectable

232

function isConnectable(element: any): element is ConnectableElement {

233

return element === null ||

234

React.isValidElement(element) ||

235

(element && typeof element === "object" && "current" in element) ||

236

element instanceof Element;

237

}

238

239

// Helper to create factory functions

240

function createItemFactory<T>(baseItem: T) {

241

return (monitor: DragSourceMonitor<T>): T => {

242

return {

243

...baseItem,

244

dragStartTime: Date.now(),

245

initialOffset: monitor.getInitialClientOffset(),

246

};

247

};

248

}

249

250

function UtilityExample() {

251

const itemFactory = createItemFactory({ id: "1", name: "Example" });

252

253

const [{ isDragging }, drag] = useDrag({

254

type: "item",

255

item: itemFactory, // Use factory function

256

collect: (monitor) => ({

257

isDragging: monitor.isDragging(),

258

}),

259

});

260

261

return <div ref={drag}>Draggable with factory</div>;

262

}

263

```

264

265

## Integration Helpers

266

267

### Custom Backend Integration

268

269

```typescript

270

import React from "react";

271

import { DndProvider, useDragDropManager } from "react-dnd";

272

273

// Custom backend example

274

class CustomBackend {

275

constructor(manager, context, options) {

276

this.manager = manager;

277

this.context = context;

278

this.options = options;

279

}

280

281

setup() {

282

// Initialize custom drag and drop handling

283

this.context.addEventListener("mousedown", this.handleMouseDown);

284

this.context.addEventListener("mouseup", this.handleMouseUp);

285

}

286

287

teardown() {

288

// Clean up event listeners

289

this.context.removeEventListener("mousedown", this.handleMouseDown);

290

this.context.removeEventListener("mouseup", this.handleMouseUp);

291

}

292

293

handleMouseDown = (event) => {

294

// Custom drag initiation logic

295

};

296

297

handleMouseUp = (event) => {

298

// Custom drop handling logic

299

};

300

}

301

302

function createCustomBackend(manager, context, options) {

303

return new CustomBackend(manager, context, options);

304

}

305

306

function AppWithCustomBackend() {

307

return (

308

<DndProvider backend={createCustomBackend}>

309

<MyDragDropComponents />

310

</DndProvider>

311

);

312

}

313

```

314

315

### Testing Utilities

316

317

```typescript

318

import React from "react";

319

import { render, fireEvent } from "@testing-library/react";

320

import { DndProvider } from "react-dnd";

321

import { TestBackend } from "react-dnd-test-backend";

322

323

function createDndWrapper() {

324

return function DndWrapper({ children }) {

325

return (

326

<DndProvider backend={TestBackend}>

327

{children}

328

</DndProvider>

329

);

330

};

331

}

332

333

// Example test utility

334

function simulateDragDrop(dragElement, dropElement) {

335

fireEvent.dragStart(dragElement);

336

fireEvent.dragEnter(dropElement);

337

fireEvent.dragOver(dropElement);

338

fireEvent.drop(dropElement);

339

fireEvent.dragEnd(dragElement);

340

}

341

342

// Test example

343

test("drag and drop functionality", () => {

344

const { getByTestId } = render(

345

<MyDragDropComponent />,

346

{ wrapper: createDndWrapper() }

347

);

348

349

const dragElement = getByTestId("draggable");

350

const dropElement = getByTestId("droppable");

351

352

simulateDragDrop(dragElement, dropElement);

353

354

// Assert expected behavior

355

});

356

```

357

358

### Performance Optimization Helpers

359

360

```typescript

361

import React, { useMemo, useCallback } from "react";

362

import { useDrag, useDrop } from "react-dnd";

363

364

// Memoized drag spec to prevent unnecessary re-renders

365

function OptimizedDraggable({ item, onDragEnd }) {

366

const dragSpec = useMemo(() => ({

367

type: "item",

368

item,

369

end: onDragEnd,

370

collect: (monitor) => ({

371

isDragging: monitor.isDragging(),

372

}),

373

}), [item, onDragEnd]);

374

375

const [{ isDragging }, drag] = useDrag(dragSpec);

376

377

return (

378

<div ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>

379

{item.name}

380

</div>

381

);

382

}

383

384

// Optimized drop target with memoized handlers

385

function OptimizedDropTarget({ onDrop, acceptTypes }) {

386

const handleDrop = useCallback((item, monitor) => {

387

onDrop(item, monitor.getDropResult());

388

}, [onDrop]);

389

390

const dropSpec = useMemo(() => ({

391

accept: acceptTypes,

392

drop: handleDrop,

393

collect: (monitor) => ({

394

isOver: monitor.isOver(),

395

canDrop: monitor.canDrop(),

396

}),

397

}), [acceptTypes, handleDrop]);

398

399

const [{ isOver, canDrop }, drop] = useDrop(dropSpec);

400

401

return (

402

<div

403

ref={drop}

404

style={{

405

backgroundColor: isOver && canDrop ? "lightgreen" : "transparent",

406

}}

407

>

408

Drop Zone

409

</div>

410

);

411

}

412

```