or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfile-editor.mdfile-management.mdindex.mdmodal-management.mdpanel-management.mdplugin-integration.md

file-editor.mddocs/

0

# File Editor Integration

1

2

Integrate with file editor plugins for image editing and metadata management.

3

4

## Capabilities

5

6

### Open File Editor

7

8

Open the file editor interface for a specific file with compatible editor plugins.

9

10

```typescript { .api }

11

/**

12

* Open file editor for specific file

13

* Checks for compatible editor plugins and activates editor overlay

14

* @param file - File to open in editor

15

*/

16

openFileEditor(file: UppyFile): void;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import Dashboard from "@uppy/dashboard";

23

24

const dashboard = uppy.getPlugin("Dashboard") as Dashboard;

25

26

// Open editor for file

27

const file = uppy.getFile("file-id");

28

dashboard.openFileEditor(file);

29

30

// Open editor from file list click

31

function handleEditClick(fileId: string) {

32

const file = uppy.getFile(fileId);

33

if (file && dashboard.canEditFile(file)) {

34

dashboard.openFileEditor(file);

35

}

36

}

37

38

// Auto-open editor for images

39

uppy.on("file-added", (file) => {

40

if (file.type?.startsWith("image/") && dashboard.canEditFile(file)) {

41

dashboard.openFileEditor(file);

42

}

43

});

44

```

45

46

**Behavior:**

47

- Sets `showFileEditor` to true in dashboard state

48

- Sets `fileCardFor` to the file ID

49

- Sets `activeOverlayType` to 'FileEditor'

50

- Calls `selectFile(file)` on all registered editor plugins

51

- Only works if compatible editor plugins are available

52

53

### Close File Editor

54

55

Close the file editor interface and return to appropriate dashboard state.

56

57

```typescript { .api }

58

/**

59

* Close file editor panel

60

* Returns to file card if metadata editing is enabled, otherwise to main view

61

*/

62

closeFileEditor(): void;

63

```

64

65

**Usage Examples:**

66

67

```typescript

68

// Close editor programmatically

69

dashboard.closeFileEditor();

70

71

// Close editor on escape key

72

document.addEventListener("keydown", (event) => {

73

if (event.key === "Escape" && dashboard.getPluginState().showFileEditor) {

74

dashboard.closeFileEditor();

75

}

76

});

77

78

// Close editor after timeout

79

function autoCloseEditor(timeoutMs: number = 300000) { // 5 minutes

80

setTimeout(() => {

81

if (dashboard.getPluginState().showFileEditor) {

82

dashboard.closeFileEditor();

83

}

84

}, timeoutMs);

85

}

86

```

87

88

**Behavior:**

89

- Sets `showFileEditor` to false

90

- If metadata editing is enabled: sets `activeOverlayType` to 'FileCard'

91

- If metadata editing is disabled: sets `fileCardFor` to null and `activeOverlayType` to 'AddFiles'

92

93

### Save File Editor

94

95

Save changes from the file editor and close the editor interface.

96

97

```typescript { .api }

98

/**

99

* Save file editor changes

100

* Calls save() on all registered editor plugins and closes editor

101

*/

102

saveFileEditor(): void;

103

```

104

105

**Usage Examples:**

106

107

```typescript

108

// Save editor changes

109

dashboard.saveFileEditor();

110

111

// Save with confirmation

112

function saveWithConfirmation() {

113

if (confirm("Save changes to file?")) {

114

dashboard.saveFileEditor();

115

} else {

116

dashboard.closeFileEditor();

117

}

118

}

119

120

// Auto-save editor changes

121

let autoSaveInterval: number;

122

123

uppy.on("dashboard:file-edit-start", () => {

124

autoSaveInterval = setInterval(() => {

125

if (dashboard.getPluginState().showFileEditor) {

126

dashboard.saveFileEditor();

127

}

128

}, 60000); // Auto-save every minute

129

});

130

131

uppy.on("dashboard:file-edit-complete", () => {

132

clearInterval(autoSaveInterval);

133

});

134

```

135

136

**Behavior:**

137

- Calls `save()` method on all registered editor plugins

138

- Calls `closeFileEditor()` to hide the editor interface

139

140

### Check File Editor Compatibility

141

142

Determine if a file can be edited with available editor plugins.

143

144

```typescript { .api }

145

/**

146

* Check if file can be edited with available editor plugins

147

* @param file - File to check for editor compatibility

148

* @returns True if file can be edited, false otherwise

149

*/

150

canEditFile(file: UppyFile): boolean;

151

```

152

153

**Usage Examples:**

154

155

```typescript

156

// Check if file can be edited

157

const file = uppy.getFile("file-id");

158

if (dashboard.canEditFile(file)) {

159

// Show edit button

160

showEditButton(file.id);

161

} else {

162

// Hide edit button

163

hideEditButton(file.id);

164

}

165

166

// Filter editable files

167

const editableFiles = uppy.getFiles().filter(file =>

168

dashboard.canEditFile(file)

169

);

170

171

// Conditional UI rendering

172

function renderFileActions(file: UppyFile) {

173

const canEdit = dashboard.canEditFile(file);

174

return (

175

<div className="file-actions">

176

<button onClick={() => removeFile(file.id)}>Remove</button>

177

{canEdit && (

178

<button onClick={() => dashboard.openFileEditor(file)}>

179

Edit

180

</button>

181

)}

182

</div>

183

);

184

}

185

```

186

187

### Editor Plugin Integration

188

189

How editor plugins integrate with the dashboard file editor system.

190

191

```typescript { .api }

192

/**

193

* Editor plugin requirements for dashboard integration

194

*/

195

interface EditorPlugin {

196

/** Plugin must have unique ID */

197

id: string;

198

/** Plugin must be 'editor' type */

199

type: 'editor';

200

/** Check if plugin can edit specific file */

201

canEditFile(file: UppyFile): boolean;

202

/** Select file for editing */

203

selectFile(file: UppyFile): void;

204

/** Save editor changes */

205

save(): void;

206

/** Render editor interface */

207

render(): ComponentChild;

208

}

209

```

210

211

**Editor Plugin Examples:**

212

213

```typescript

214

// Image editor plugin

215

class ImageEditor extends BasePlugin {

216

type = 'editor';

217

id = 'ImageEditor';

218

219

canEditFile(file: UppyFile): boolean {

220

return file.type?.startsWith('image/') || false;

221

}

222

223

selectFile(file: UppyFile): void {

224

this.selectedFile = file;

225

this.loadImageIntoEditor(file.data);

226

}

227

228

save(): void {

229

if (this.selectedFile && this.hasChanges) {

230

const editedBlob = this.exportEditedImage();

231

this.uppy.setFileData(this.selectedFile.id, editedBlob);

232

}

233

}

234

235

render() {

236

return h('div', { className: 'image-editor' }, [

237

h('canvas', { ref: this.canvasRef }),

238

h('div', { className: 'editor-tools' }, this.renderTools())

239

]);

240

}

241

}

242

243

// Text metadata editor

244

class MetadataEditor extends BasePlugin {

245

type = 'editor';

246

id = 'MetadataEditor';

247

248

canEditFile(): boolean {

249

return true; // Can edit metadata for any file

250

}

251

252

selectFile(file: UppyFile): void {

253

this.selectedFile = file;

254

this.loadMetadata(file.meta);

255

}

256

257

save(): void {

258

if (this.selectedFile) {

259

const newMeta = this.getFormData();

260

this.uppy.setFileMeta(this.selectedFile.id, newMeta);

261

}

262

}

263

}

264

```

265

266

### Auto-Open Configuration

267

268

Configure automatic editor opening based on file types or conditions.

269

270

```typescript { .api }

271

/**

272

* Auto-open configuration options

273

*/

274

interface AutoOpenConfig {

275

/** Auto-open editor type on file selection */

276

autoOpen?: 'metaEditor' | 'imageEditor' | null;

277

}

278

```

279

280

**Auto-Open Examples:**

281

282

```typescript

283

// Auto-open metadata editor

284

uppy.use(Dashboard, {

285

autoOpen: 'metaEditor'

286

});

287

288

// Auto-open image editor for images

289

uppy.use(Dashboard, {

290

autoOpen: 'imageEditor'

291

});

292

293

// Custom auto-open logic

294

uppy.use(Dashboard, {

295

autoOpen: null // Disable automatic opening

296

});

297

298

uppy.on('files-added', (files) => {

299

files.forEach(file => {

300

if (file.type?.startsWith('image/') && needsImageEditing(file)) {

301

dashboard.openFileEditor(file);

302

} else if (needsMetadataEditing(file)) {

303

dashboard.toggleFileCard(true, file.id);

304

}

305

});

306

});

307

```

308

309

### Editor State Management

310

311

State properties related to file editor functionality.

312

313

```typescript { .api }

314

/**

315

* File editor state properties

316

*/

317

interface FileEditorState {

318

/** Whether file editor is currently shown */

319

showFileEditor: boolean;

320

/** File ID being edited, null if no file selected */

321

fileCardFor: string | null;

322

/** Active overlay type */

323

activeOverlayType: 'FileEditor' | 'FileCard' | null;

324

}

325

```

326

327

### Editor Events

328

329

Events emitted during file editor lifecycle.

330

331

```typescript { .api }

332

/**

333

* File editor events

334

*/

335

interface FileEditorEvents<M extends Meta, B extends Body> {

336

/** Emitted when file editing starts */

337

"dashboard:file-edit-start": (file?: UppyFile<M, B>) => void;

338

/** Emitted when file editing completes */

339

"dashboard:file-edit-complete": (file?: UppyFile<M, B>) => void;

340

}

341

```

342

343

**Event Usage Examples:**

344

345

```typescript

346

// Track editor usage

347

uppy.on('dashboard:file-edit-start', (file) => {

348

console.log(`Started editing: ${file?.name}`);

349

trackEvent('file_edit_start', {

350

fileType: file?.type,

351

fileSize: file?.size

352

});

353

});

354

355

uppy.on('dashboard:file-edit-complete', (file) => {

356

console.log(`Finished editing: ${file?.name}`);

357

trackEvent('file_edit_complete', {

358

fileType: file?.type,

359

duration: Date.now() - editStartTime

360

});

361

});

362

363

// Editor session management

364

let editSession: EditSession | null = null;

365

366

uppy.on('dashboard:file-edit-start', (file) => {

367

editSession = new EditSession(file);

368

editSession.start();

369

});

370

371

uppy.on('dashboard:file-edit-complete', (file) => {

372

if (editSession) {

373

editSession.complete();

374

editSession = null;

375

}

376

});

377

```

378

379

### Multiple Editor Support

380

381

Handle multiple editor plugins and editor selection.

382

383

```typescript { .api }

384

/**

385

* Multiple editor management

386

*/

387

interface MultipleEditorSupport {

388

/** Get all registered editor plugins */

389

getEditors(targets: Target[]): TargetWithRender[];

390

/** Check if any editor can handle file */

391

canEditFile(file: UppyFile): boolean;

392

/** Open file in all compatible editors */

393

openFileEditor(file: UppyFile): void;

394

}

395

```

396

397

**Multiple Editor Examples:**

398

399

```typescript

400

// Register multiple editors

401

uppy.use(ImageEditor, { /* options */ });

402

uppy.use(MetadataEditor, { /* options */ });

403

uppy.use(CropEditor, { /* options */ });

404

405

// Selective editor activation

406

function openSpecificEditor(file: UppyFile, editorType: string) {

407

const editors = dashboard.getPluginState().targets

408

.filter(target => target.type === 'editor' && target.id === editorType);

409

410

if (editors.length > 0) {

411

const plugin = uppy.getPlugin(editorType);

412

if (plugin && plugin.canEditFile(file)) {

413

dashboard.openFileEditor(file);

414

}

415

}

416

}

417

418

// Editor selection UI

419

function renderEditorOptions(file: UppyFile) {

420

const availableEditors = dashboard.getPluginState().targets

421

.filter(target => target.type === 'editor')

422

.filter(target => uppy.getPlugin(target.id).canEditFile(file));

423

424

return availableEditors.map(editor => (

425

<button

426

key={editor.id}

427

onClick={() => openSpecificEditor(file, editor.id)}

428

>

429

Edit with {editor.name}

430

</button>

431

));

432

}

433

```

434

435

### Editor Integration Best Practices

436

437

Recommended patterns for editor plugin development and integration.

438

439

```typescript { .api }

440

/**

441

* Editor plugin best practices

442

*/

443

interface EditorBestPractices {

444

/** Implement proper file type checking */

445

canEditFile(file: UppyFile): boolean;

446

/** Handle file loading and error states */

447

selectFile(file: UppyFile): Promise<void>;

448

/** Provide clear save/cancel actions */

449

save(): Promise<void>;

450

/** Clean up resources on unmount */

451

unmount(): void;

452

/** Provide keyboard shortcuts */

453

handleKeyboard(event: KeyboardEvent): void;

454

/** Support undo/redo operations */

455

undo(): void;

456

redo(): void;

457

}

458

```

459

460

**Best Practice Examples:**

461

462

```typescript

463

class AdvancedImageEditor extends BasePlugin {

464

type = 'editor';

465

466

async selectFile(file: UppyFile) {

467

try {

468

this.setStatus('loading');

469

await this.loadImageData(file.data);

470

this.setStatus('ready');

471

} catch (error) {

472

this.setStatus('error');

473

this.uppy.info('Failed to load image in editor', 'error');

474

}

475

}

476

477

async save() {

478

try {

479

this.setStatus('saving');

480

const editedData = await this.exportImage();

481

this.uppy.setFileData(this.selectedFile.id, editedData);

482

this.setStatus('saved');

483

} catch (error) {

484

this.setStatus('error');

485

this.uppy.info('Failed to save edited image', 'error');

486

}

487

}

488

489

handleKeyboard(event: KeyboardEvent) {

490

if (event.ctrlKey || event.metaKey) {

491

switch (event.key) {

492

case 'z':

493

event.preventDefault();

494

if (event.shiftKey) {

495

this.redo();

496

} else {

497

this.undo();

498

}

499

break;

500

case 's':

501

event.preventDefault();

502

this.save();

503

break;

504

}

505

}

506

}

507

}

508

```