or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-hooks.mdcomponent-extensions.mdcontent-rendering.mdcore-integration.mdeditor-hooks.mdindex.mdtable-extensions.mdui-components.mdutilities.md

advanced-hooks.mddocs/

0

# Advanced Hooks

1

2

Extended hooks for sophisticated editor interactions including positioning, suggestions, keyboard handling, and event management.

3

4

## Capabilities

5

6

### Positioning Hooks

7

8

Hooks for managing floating UI elements and positioning.

9

10

```typescript { .api }

11

/**

12

* Hook for managing a single positioned element with floating UI

13

* @param options - Positioning configuration options

14

* @returns Positioning state and control functions

15

*/

16

function usePositioner(options?: PositionerOptions): UsePositionerReturn;

17

18

interface UsePositionerReturn {

19

/** Whether the positioner is currently active */

20

active: boolean;

21

/** Current position coordinates */

22

position: { x: number; y: number };

23

/** Show the positioned element */

24

show: () => void;

25

/** Hide the positioned element */

26

hide: () => void;

27

/** Toggle visibility */

28

toggle: () => void;

29

/** Update position */

30

update: () => void;

31

}

32

33

interface PositionerOptions {

34

/** Placement preference */

35

placement?: Placement;

36

/** Offset from reference element */

37

offset?: number;

38

/** Whether to flip when space is limited */

39

flip?: boolean;

40

}

41

42

/**

43

* Hook for managing multiple positioned elements

44

* @returns Multi-positioner management interface

45

*/

46

function useMultiPositioner(): MultiPositionerReturn;

47

48

interface MultiPositionerReturn {

49

/** Create a new positioner */

50

create: (id: string, options?: PositionerOptions) => UsePositionerReturn;

51

/** Remove a positioner */

52

remove: (id: string) => void;

53

/** Get a specific positioner */

54

get: (id: string) => UsePositionerReturn | undefined;

55

/** Hide all positioners */

56

hideAll: () => void;

57

}

58

```

59

60

**Usage Example:**

61

62

```typescript

63

import React, { useState } from 'react';

64

import { usePositioner } from '@remirror/react';

65

66

function FloatingMenu() {

67

const [visible, setVisible] = useState(false);

68

const positioner = usePositioner({

69

placement: 'top',

70

offset: 10,

71

});

72

73

return (

74

<div>

75

<button

76

onClick={() => {

77

setVisible(!visible);

78

positioner.toggle();

79

}}

80

>

81

Toggle Menu

82

</button>

83

{positioner.active && (

84

<div style={{

85

position: 'absolute',

86

left: positioner.position.x,

87

top: positioner.position.y,

88

}}>

89

Floating menu content

90

</div>

91

)}

92

</div>

93

);

94

}

95

```

96

97

### Suggestion Hooks

98

99

Hooks for implementing suggestion systems like mentions, emoji, and custom suggestions.

100

101

```typescript { .api }

102

/**

103

* General-purpose suggestion hook for autocomplete functionality

104

* @param options - Suggestion configuration

105

* @returns Suggestion state and control functions

106

*/

107

function useSuggest<T = any>(options: SuggestOptions<T>): SuggestReturn<T>;

108

109

interface SuggestOptions<T> {

110

/** Trigger character(s) */

111

char: string | string[];

112

/** Function to fetch suggestions */

113

items: (query: string) => T[] | Promise<T[]>;

114

/** Function to render each suggestion */

115

render: (item: T) => React.ReactNode;

116

/** Function to handle selection */

117

onSelect: (item: T) => void;

118

}

119

120

interface SuggestReturn<T> {

121

/** Current suggestions */

122

items: T[];

123

/** Currently highlighted index */

124

index: number;

125

/** Whether suggestions are active */

126

active: boolean;

127

/** Current query string */

128

query: string;

129

/** Select highlighted item */

130

selectHighlighted: () => void;

131

/** Navigate suggestions */

132

next: () => void;

133

previous: () => void;

134

}

135

136

/**

137

* Hook for mention functionality

138

* @param options - Mention configuration

139

* @returns Mention state and handlers

140

*/

141

function useMention(options?: MentionOptions): MentionState;

142

143

interface MentionOptions {

144

/** Mention trigger character */

145

char?: string;

146

/** Function to fetch mention suggestions */

147

items?: (query: string) => MentionItem[] | Promise<MentionItem[]>;

148

/** Custom mention matcher */

149

matcher?: RegExp;

150

}

151

152

interface MentionState {

153

/** Current mention query */

154

query: string;

155

/** Available mention items */

156

items: MentionItem[];

157

/** Currently active mention */

158

active: boolean;

159

/** Highlighted item index */

160

index: number;

161

/** Insert a mention */

162

insertMention: (item: MentionItem) => void;

163

}

164

165

interface MentionItem {

166

/** Unique identifier */

167

id: string;

168

/** Display label */

169

label: string;

170

/** Optional avatar URL */

171

avatar?: string;

172

/** Additional data */

173

data?: any;

174

}

175

176

/**

177

* Hook for atomic mention handling (indivisible mentions)

178

* @param options - Atomic mention options

179

* @returns Atomic mention interface

180

*/

181

function useMentionAtom(options?: MentionAtomOptions): MentionAtomState;

182

183

interface MentionAtomOptions {

184

/** Mention character trigger */

185

char?: string;

186

/** Mention data provider */

187

items?: (query: string) => MentionItem[] | Promise<MentionItem[]>;

188

}

189

190

interface MentionAtomState {

191

/** Create new mention */

192

createMention: (item: MentionItem) => void;

193

/** Update existing mention */

194

updateMention: (id: string, data: Partial<MentionItem>) => void;

195

/** Remove mention */

196

removeMention: (id: string) => void;

197

/** Get all mentions in document */

198

getMentions: () => MentionItem[];

199

}

200

201

/**

202

* Hook for emoji suggestion functionality

203

* @param options - Emoji configuration

204

* @returns Emoji suggestion state

205

*/

206

function useEmoji(options?: EmojiOptions): EmojiState;

207

208

interface EmojiOptions {

209

/** Emoji trigger character */

210

char?: string;

211

/** Custom emoji dataset */

212

emojiData?: EmojiData[];

213

}

214

215

interface EmojiState {

216

/** Current emoji query */

217

query: string;

218

/** Matching emoji results */

219

results: EmojiData[];

220

/** Insert selected emoji */

221

insertEmoji: (emoji: EmojiData) => void;

222

/** Whether emoji picker is active */

223

active: boolean;

224

}

225

226

interface EmojiData {

227

/** Emoji unicode character */

228

emoji: string;

229

/** Emoji name/description */

230

name: string;

231

/** Category */

232

category: string;

233

/** Keywords for searching */

234

keywords: string[];

235

}

236

```

237

238

**Usage Example:**

239

240

```typescript

241

import React from 'react';

242

import { useMention } from '@remirror/react';

243

244

function MentionSupport() {

245

const mention = useMention({

246

char: '@',

247

items: async (query) => {

248

// Fetch users matching query

249

const users = await fetchUsers(query);

250

return users.map(user => ({

251

id: user.id,

252

label: user.name,

253

avatar: user.avatar,

254

}));

255

},

256

});

257

258

return mention.active ? (

259

<div className="mention-popup">

260

{mention.items.map((item, index) => (

261

<div

262

key={item.id}

263

className={index === mention.index ? 'highlighted' : ''}

264

onClick={() => mention.insertMention(item)}

265

>

266

{item.avatar && <img src={item.avatar} alt="" />}

267

{item.label}

268

</div>

269

))}

270

</div>

271

) : null;

272

}

273

```

274

275

### Keyboard Handling Hooks

276

277

Hooks for managing keyboard shortcuts and navigation.

278

279

```typescript { .api }

280

/**

281

* Hook for binding a single keymap

282

* @param keymap - Key binding configuration

283

*/

284

function useKeymap(keymap: ProsemirrorKeyBindings): void;

285

286

/**

287

* Hook for binding multiple keymaps

288

* @param keymaps - Array of key binding configurations

289

*/

290

function useKeymaps(keymaps: ProsemirrorKeyBindings[]): void;

291

292

interface ProsemirrorKeyBindings {

293

[key: string]: (state: EditorState, dispatch?: any) => boolean;

294

}

295

296

/**

297

* Hook for keyboard navigation in menus and lists

298

* @param options - Navigation configuration

299

* @returns Navigation state and handlers

300

*/

301

function useMenuNavigation(options: MenuNavigationOptions): MenuNavigationReturn;

302

303

interface MenuNavigationOptions {

304

/** Total number of items */

305

items: number;

306

/** Initial selected index */

307

initialIndex?: number;

308

/** Whether to loop at ends */

309

loop?: boolean;

310

/** Custom key mappings */

311

keys?: {

312

up?: string;

313

down?: string;

314

select?: string;

315

escape?: string;

316

};

317

}

318

319

interface MenuNavigationReturn {

320

/** Currently selected index */

321

index: number;

322

/** Move to next item */

323

next: () => void;

324

/** Move to previous item */

325

previous: () => void;

326

/** Select current item */

327

select: () => void;

328

/** Reset to initial state */

329

reset: () => void;

330

/** Set specific index */

331

setIndex: (index: number) => void;

332

}

333

```

334

335

**Usage Example:**

336

337

```typescript

338

import React, { useEffect } from 'react';

339

import { useKeymap, useMenuNavigation } from '@remirror/react';

340

341

function CustomDropdown({ items, onSelect }) {

342

const navigation = useMenuNavigation({

343

items: items.length,

344

loop: true,

345

});

346

347

useKeymap({

348

'ArrowUp': () => {

349

navigation.previous();

350

return true;

351

},

352

'ArrowDown': () => {

353

navigation.next();

354

return true;

355

},

356

'Enter': () => {

357

onSelect(items[navigation.index]);

358

return true;

359

},

360

});

361

362

return (

363

<div className="dropdown">

364

{items.map((item, index) => (

365

<div

366

key={index}

367

className={index === navigation.index ? 'selected' : ''}

368

onClick={() => onSelect(item)}

369

>

370

{item.label}

371

</div>

372

))}

373

</div>

374

);

375

}

376

```

377

378

### Editor Event Hooks

379

380

Hooks for handling various editor events and interactions.

381

382

```typescript { .api }

383

/**

384

* Hook for handling general editor events

385

* @param event - Event name to listen for

386

* @param handler - Event handler function

387

* @param options - Event options

388

*/

389

function useEditorEvent<T = any>(

390

event: string,

391

handler: (params: T) => void,

392

options?: EventOptions

393

): void;

394

395

interface EventOptions {

396

/** Event priority */

397

priority?: number;

398

/** Whether to capture the event */

399

capture?: boolean;

400

/** Event filter function */

401

filter?: (params: any) => boolean;

402

}

403

404

/**

405

* Hook for managing editor focus state

406

* @param options - Focus configuration

407

* @returns Focus state and control functions

408

*/

409

function useEditorFocus(options?: FocusOptions): EditorFocusReturn;

410

411

interface FocusOptions {

412

/** Auto focus on mount */

413

autoFocus?: boolean;

414

/** Focus delay in milliseconds */

415

delay?: number;

416

/** Callback when focus changes */

417

onFocusChange?: (focused: boolean) => void;

418

}

419

420

interface EditorFocusReturn {

421

/** Whether editor is currently focused */

422

focused: boolean;

423

/** Focus the editor */

424

focus: () => void;

425

/** Blur the editor */

426

blur: () => void;

427

/** Toggle focus state */

428

toggle: () => void;

429

}

430

431

/**

432

* Hook for handling hover interactions

433

* @param options - Hover configuration

434

* @returns Hover state and handlers

435

*/

436

function useHover(options?: HoverOptions): HoverReturn;

437

438

interface HoverOptions {

439

/** Hover delay in milliseconds */

440

delay?: number;

441

/** Element selector to monitor */

442

selector?: string;

443

/** Callback when hover state changes */

444

onHoverChange?: (hovering: boolean) => void;

445

}

446

447

interface HoverReturn {

448

/** Whether currently hovering */

449

hovering: boolean;

450

/** Hover event handlers */

451

handlers: {

452

onMouseEnter: () => void;

453

onMouseLeave: () => void;

454

};

455

}

456

457

/**

458

* Hook for managing editor history (undo/redo)

459

* @returns History state and control functions

460

*/

461

function useHistory(): HistoryReturn;

462

463

interface HistoryReturn {

464

/** Whether undo is available */

465

canUndo: boolean;

466

/** Whether redo is available */

467

canRedo: boolean;

468

/** Perform undo */

469

undo: () => void;

470

/** Perform redo */

471

redo: () => void;

472

/** Clear history */

473

clearHistory: () => void;

474

}

475

```

476

477

**Usage Example:**

478

479

```typescript

480

import React from 'react';

481

import { useEditorFocus, useHistory, useHover } from '@remirror/react';

482

483

function EditorControls() {

484

const { focused, focus, blur } = useEditorFocus();

485

const { canUndo, canRedo, undo, redo } = useHistory();

486

const { hovering, handlers } = useHover({

487

delay: 200,

488

});

489

490

return (

491

<div className="editor-controls" {...handlers}>

492

<div>

493

Editor focused: {focused ? 'Yes' : 'No'}

494

<button onClick={focused ? blur : focus}>

495

{focused ? 'Blur' : 'Focus'}

496

</button>

497

</div>

498

499

<div>

500

<button onClick={undo} disabled={!canUndo}>

501

Undo

502

</button>

503

<button onClick={redo} disabled={!canRedo}>

504

Redo

505

</button>

506

</div>

507

508

{hovering && <div>Hovering over controls</div>}

509

</div>

510

);

511

}

512

```

513

514

## Utility Hooks

515

516

Additional utility hooks for common operations.

517

518

```typescript { .api }

519

/**

520

* Calculate index from arrow key navigation

521

* @param current - Current index

522

* @param total - Total items

523

* @param direction - Navigation direction

524

* @param loop - Whether to loop at boundaries

525

* @returns New index after navigation

526

*/

527

function indexFromArrowPress(

528

current: number,

529

total: number,

530

direction: 'up' | 'down',

531

loop?: boolean

532

): number;

533

```

534

535

## Types

536

537

### Common Hook Types

538

539

```typescript { .api }

540

type Placement =

541

| 'top'

542

| 'top-start'

543

| 'top-end'

544

| 'bottom'

545

| 'bottom-start'

546

| 'bottom-end'

547

| 'left'

548

| 'left-start'

549

| 'left-end'

550

| 'right'

551

| 'right-start'

552

| 'right-end';

553

554

interface Position {

555

x: number;

556

y: number;

557

}

558

559

interface Bounds {

560

top: number;

561

left: number;

562

bottom: number;

563

right: number;

564

width: number;

565

height: number;

566

}

567

```