or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auto-scrolling.mdcomponent-utilities.mddrag-drop-hooks.mdeditor-transforms.mdindex.mdplugin-configuration.mdutility-functions.md

component-utilities.mddocs/

0

# Component Utilities

1

2

Pre-built components and hooks for common drag-and-drop UI patterns. These utilities provide higher-level abstractions for implementing draggable elements and visual drop indicators in your Plate editor components.

3

4

## Capabilities

5

6

### useDraggable

7

8

Hook that provides a simplified interface for making elements draggable with pre-configured behavior and state management.

9

10

```typescript { .api }

11

/**

12

* Simplified hook for making elements draggable

13

* Provides pre-configured draggable state and refs

14

* @param props - Configuration options for draggable behavior

15

* @returns Draggable state with refs and status

16

*/

17

export function useDraggable(props: UseDndNodeOptions): DraggableState;

18

19

export type DraggableState = {

20

/** Whether the element is currently being dragged */

21

isDragging: boolean;

22

/** Reference to the draggable preview element */

23

previewRef: React.RefObject<HTMLDivElement | null>;

24

/** Reference function for the drag handle element */

25

handleRef: (

26

elementOrNode:

27

| Element

28

| React.ReactElement<any>

29

| React.RefObject<any>

30

| null

31

) => void;

32

};

33

```

34

35

**Usage Examples:**

36

37

```typescript

38

import { useDraggable } from "@udecode/plate-dnd";

39

import { useElement } from "@udecode/plate/react";

40

41

function DraggableBlockWithHandle({ children }) {

42

const element = useElement();

43

44

const { isDragging, previewRef, handleRef } = useDraggable({

45

element,

46

orientation: 'vertical'

47

});

48

49

return (

50

<div

51

ref={previewRef}

52

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

53

>

54

<div

55

ref={handleRef}

56

style={{

57

cursor: 'grab',

58

padding: '4px',

59

background: '#f0f0f0',

60

marginBottom: '4px'

61

}}

62

>

63

⋮⋮ Drag Handle

64

</div>

65

{children}

66

</div>

67

);

68

}

69

70

// With custom drop handler

71

function CustomDraggableBlock({ children }) {

72

const element = useElement();

73

74

const { isDragging, previewRef, handleRef } = useDraggable({

75

element,

76

onDropHandler: (editor, { id }) => {

77

console.log('Block dropped:', id);

78

return false; // Allow default behavior

79

}

80

});

81

82

return (

83

<div ref={previewRef}>

84

<button ref={handleRef} disabled={isDragging}>

85

{isDragging ? 'Dragging...' : 'Drag me'}

86

</button>

87

{children}

88

</div>

89

);

90

}

91

```

92

93

### useDropLine

94

95

Hook for managing visual drop line indicators that show where dragged items will be dropped.

96

97

```typescript { .api }

98

/**

99

* Hook for managing drop line visual indicators

100

* Shows visual feedback for drop zones during drag operations

101

* @param options - Configuration for drop line behavior

102

* @returns Object containing the current drop line direction

103

*/

104

export function useDropLine(options?: {

105

/** The id of the element to show the dropline for */

106

id?: string;

107

/** Orientation of the drop line */

108

orientation?: 'horizontal' | 'vertical';

109

}): {

110

dropLine?: DropLineDirection;

111

};

112

113

export type DropLineDirection = '' | 'bottom' | 'left' | 'right' | 'top';

114

```

115

116

**Usage Examples:**

117

118

```typescript

119

import { useDropLine } from "@udecode/plate-dnd";

120

import { useElement } from "@udecode/plate/react";

121

122

function BlockWithDropLine({ children }) {

123

const element = useElement();

124

const { dropLine } = useDropLine({

125

id: element.id as string,

126

orientation: 'vertical'

127

});

128

129

return (

130

<div style={{ position: 'relative' }}>

131

{/* Drop line indicator */}

132

{dropLine && (

133

<div

134

style={{

135

position: 'absolute',

136

height: '2px',

137

backgroundColor: '#007acc',

138

left: 0,

139

right: 0,

140

[dropLine]: dropLine === 'top' ? '-1px' :

141

dropLine === 'bottom' ? 'calc(100% - 1px)' : '50%'

142

}}

143

/>

144

)}

145

{children}

146

</div>

147

);

148

}

149

150

// Horizontal drop lines

151

function HorizontalBlock({ children }) {

152

const element = useElement();

153

const { dropLine } = useDropLine({

154

orientation: 'horizontal'

155

});

156

157

return (

158

<div style={{

159

position: 'relative',

160

display: 'inline-block',

161

margin: '0 4px'

162

}}>

163

{dropLine && (

164

<div

165

style={{

166

position: 'absolute',

167

width: '2px',

168

backgroundColor: '#007acc',

169

top: 0,

170

bottom: 0,

171

[dropLine]: dropLine === 'left' ? '-1px' :

172

dropLine === 'right' ? 'calc(100% - 1px)' : '50%'

173

}}

174

/>

175

)}

176

{children}

177

</div>

178

);

179

}

180

181

// Custom drop line styling

182

function CustomDropLine({ children }) {

183

const { dropLine } = useDropLine();

184

185

const getDropLineStyle = () => {

186

if (!dropLine) return {};

187

188

const baseStyle = {

189

position: 'absolute' as const,

190

backgroundColor: '#ff6b6b',

191

zIndex: 1000,

192

borderRadius: '2px'

193

};

194

195

switch (dropLine) {

196

case 'top':

197

return { ...baseStyle, top: '-2px', left: 0, right: 0, height: '4px' };

198

case 'bottom':

199

return { ...baseStyle, bottom: '-2px', left: 0, right: 0, height: '4px' };

200

case 'left':

201

return { ...baseStyle, left: '-2px', top: 0, bottom: 0, width: '4px' };

202

case 'right':

203

return { ...baseStyle, right: '-2px', top: 0, bottom: 0, width: '4px' };

204

default:

205

return {};

206

}

207

};

208

209

return (

210

<div style={{ position: 'relative' }}>

211

{dropLine && <div style={getDropLineStyle()} />}

212

{children}

213

</div>

214

);

215

}

216

```

217

218

### Integration Example

219

220

Combining both utilities for a complete drag-and-drop block component:

221

222

```typescript

223

import { useDraggable, useDropLine } from "@udecode/plate-dnd";

224

import { useElement } from "@udecode/plate/react";

225

226

function CompleteDragDropBlock({ children }) {

227

const element = useElement();

228

229

// Draggable functionality

230

const { isDragging, previewRef, handleRef } = useDraggable({

231

element,

232

orientation: 'vertical'

233

});

234

235

// Drop line indicators

236

const { dropLine } = useDropLine({

237

id: element.id as string,

238

orientation: 'vertical'

239

});

240

241

return (

242

<div

243

ref={previewRef}

244

style={{

245

position: 'relative',

246

opacity: isDragging ? 0.5 : 1,

247

padding: '8px',

248

border: '1px solid #ddd',

249

borderRadius: '4px',

250

margin: '4px 0'

251

}}

252

>

253

{/* Drop line indicator */}

254

{dropLine === 'top' && (

255

<div style={{

256

position: 'absolute',

257

top: '-2px',

258

left: 0,

259

right: 0,

260

height: '4px',

261

backgroundColor: '#007acc',

262

borderRadius: '2px'

263

}} />

264

)}

265

266

{dropLine === 'bottom' && (

267

<div style={{

268

position: 'absolute',

269

bottom: '-2px',

270

left: 0,

271

right: 0,

272

height: '4px',

273

backgroundColor: '#007acc',

274

borderRadius: '2px'

275

}} />

276

)}

277

278

{/* Drag handle */}

279

<div

280

ref={handleRef}

281

style={{

282

position: 'absolute',

283

left: '-30px',

284

top: '50%',

285

transform: 'translateY(-50%)',

286

cursor: isDragging ? 'grabbing' : 'grab',

287

padding: '4px',

288

backgroundColor: '#f9f9f9',

289

border: '1px solid #ddd',

290

borderRadius: '4px',

291

fontSize: '12px'

292

}}

293

>

294

⋮⋮

295

</div>

296

297

{children}

298

</div>

299

);

300

}

301

```

302

303

## Types

304

305

```typescript { .api }

306

export interface UseDndNodeOptions {

307

element: TElement;

308

nodeRef?: any;

309

canDropNode?: CanDropCallback;

310

type?: string;

311

drag?: Partial<UseDragNodeOptions>;

312

drop?: Partial<UseDropNodeOptions>;

313

orientation?: 'horizontal' | 'vertical';

314

preview?: {

315

disable?: boolean;

316

ref?: any;

317

};

318

onDropHandler?: (

319

editor: PlateEditor,

320

props: {

321

id: string;

322

dragItem: DragItemNode;

323

monitor: DropTargetMonitor<DragItemNode, unknown>;

324

nodeRef: any;

325

}

326

) => boolean | void;

327

}

328

```