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
```