@tiptap/suggestion 3.26.1 → 3.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Middleware, AutoUpdateOptions } from '@floating-ui/dom';
1
2
  import { Range, Editor } from '@tiptap/core';
2
3
  import { PluginKey, Transaction, EditorState, Plugin } from '@tiptap/pm/state';
3
4
  import { EditorView } from '@tiptap/pm/view';
@@ -18,6 +19,56 @@ type SuggestionMatch = {
18
19
  } | null;
19
20
  declare function findSuggestionMatch(config: Trigger): SuggestionMatch;
20
21
 
22
+ type SuggestionPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
23
+ type SuggestionFloatingUiOptions = {
24
+ strategy?: 'absolute' | 'fixed';
25
+ middleware?: Middleware[];
26
+ };
27
+ type SuggestionFloatingUiConfig = {
28
+ placement: SuggestionPlacement;
29
+ strategy: 'absolute' | 'fixed';
30
+ middleware: Middleware[];
31
+ };
32
+ /**
33
+ * The computed position handed to a custom `onPosition` callback when using
34
+ * managed positioning via {@link SuggestionProps.mount}.
35
+ */
36
+ type SuggestionPositionData = {
37
+ x: number;
38
+ y: number;
39
+ placement: SuggestionPlacement;
40
+ strategy: 'absolute' | 'fixed';
41
+ };
42
+ /**
43
+ * Options for managed mounting + positioning via {@link SuggestionProps.mount}.
44
+ */
45
+ type SuggestionMountOptions = {
46
+ /**
47
+ * Override how the computed position is applied to the element.
48
+ * When provided, the plugin stops writing `style.left`/`style.top` itself and
49
+ * hands you the computed coordinates so you can apply them however you want
50
+ * (custom transforms, animation, writing to a framework ref, etc.).
51
+ */
52
+ onPosition?: (data: SuggestionPositionData) => void;
53
+ /**
54
+ * Options forwarded to Floating UI's `autoUpdate`. Use this to opt into
55
+ * `animationFrame` polling for anchors that move inside transformed or
56
+ * animated containers, or to disable specific observers.
57
+ * @see https://floating-ui.com/docs/autoUpdate
58
+ */
59
+ autoUpdate?: AutoUpdateOptions;
60
+ };
61
+ /**
62
+ * Mounts a floating element and takes over its positioning. The plugin appends
63
+ * the element into the configured `container` (default `document.body`), keeps
64
+ * it anchored to the suggestion's cursor rect, and automatically repositions it
65
+ * on scroll, resize, and layout shifts via Floating UI's `autoUpdate` — no
66
+ * manual listeners required.
67
+ *
68
+ * Returns an `unmount` function that tears down the listeners and removes the
69
+ * element (when the plugin mounted it). Call it from `onExit`.
70
+ */
71
+ type SuggestionMount = (element: HTMLElement, options?: SuggestionMountOptions) => () => void;
21
72
  interface SuggestionOptions<I = any, TSelected = any> {
22
73
  /**
23
74
  * The plugin key for the suggestion plugin.
@@ -128,6 +179,67 @@ interface SuggestionOptions<I = any, TSelected = any> {
128
179
  range: Range;
129
180
  props: TSelected;
130
181
  }) => void;
182
+ /**
183
+ * Minimum query length before `items()` is called.
184
+ * When the query is shorter, empty items are passed to the renderer.
185
+ * @default 0 (no filter, same as before)
186
+ * @example 2
187
+ */
188
+ minQueryLength?: number;
189
+ /**
190
+ * Debounce in milliseconds. When set, `items()` will only be called
191
+ * after the user stops typing for this duration.
192
+ * @default 0 (no debounce, same as before)
193
+ * @example 300
194
+ */
195
+ debounce?: number;
196
+ /**
197
+ * Items shown immediately when the suggestion popup opens,
198
+ * before the async `items()` call resolves.
199
+ * Useful for showing recent or popular items while loading.
200
+ * @default undefined (no pre-populated items)
201
+ */
202
+ initialItems?: I[];
203
+ /**
204
+ * Placement of the popup relative to the cursor.
205
+ * Consumers can read this from `SuggestionProps` to configure their positioning library.
206
+ * @default 'bottom-start'
207
+ */
208
+ placement?: SuggestionPlacement;
209
+ /**
210
+ * Offset of the popup in pixels.
211
+ * Consumers can read this from `SuggestionProps` to configure their positioning library.
212
+ * @default { mainAxis: 4, crossAxis: 0 }
213
+ */
214
+ offset?: {
215
+ mainAxis?: number;
216
+ crossAxis?: number;
217
+ };
218
+ /**
219
+ * CSS selector or element that defines the containment context for the popup.
220
+ * Consumers can read this from `SuggestionProps` when rendering inside modals or dialogs.
221
+ * @default undefined (no containment)
222
+ */
223
+ container?: string | HTMLElement;
224
+ /**
225
+ * Whether the popup should automatically flip when there isn't enough space.
226
+ * Consumers can read this from `SuggestionProps` to configure their positioning library.
227
+ * @default true
228
+ */
229
+ flip?: boolean;
230
+ /**
231
+ * Additional Floating UI options and middleware passed through to the renderer.
232
+ * The plugin keeps ownership of the anchor and placement, but consumers can
233
+ * append custom middleware here.
234
+ */
235
+ floatingUi?: SuggestionFloatingUiOptions;
236
+ /**
237
+ * Dismiss the suggestion when the user interacts outside both the popup and
238
+ * the editor. Only applies when using managed mounting via
239
+ * {@link SuggestionProps.mount} (the plugin needs to know the popup element).
240
+ * @default true
241
+ */
242
+ dismissOnOutsideClick?: boolean;
131
243
  /**
132
244
  * A function that returns the suggestion items in form of an array.
133
245
  * @param props The props object.
@@ -139,6 +251,7 @@ interface SuggestionOptions<I = any, TSelected = any> {
139
251
  items?: (props: {
140
252
  query: string;
141
253
  editor: Editor;
254
+ signal: AbortSignal;
142
255
  }) => I[] | Promise<I[]>;
143
256
  /**
144
257
  * The render function for the suggestion.
@@ -165,6 +278,9 @@ interface SuggestionOptions<I = any, TSelected = any> {
165
278
  }) => boolean;
166
279
  findSuggestionMatch?: typeof findSuggestionMatch;
167
280
  }
281
+ /**
282
+ * The props passed to the suggestion's render functions (onStart, onUpdate, onExit).
283
+ */
168
284
  interface SuggestionProps<I = any, TSelected = any> {
169
285
  /**
170
286
  * The editor instance.
@@ -203,18 +319,93 @@ interface SuggestionProps<I = any, TSelected = any> {
203
319
  * @example () => new DOMRect(0, 0, 0, 0)
204
320
  */
205
321
  clientRect?: (() => DOMRect | null) | null;
322
+ /**
323
+ * Placement of the popup relative to the cursor.
324
+ * @default 'bottom-start'
325
+ */
326
+ placement: SuggestionPlacement;
327
+ /**
328
+ * Offset of the popup in pixels.
329
+ * @default { mainAxis: 4, crossAxis: 0 }
330
+ */
331
+ offset: {
332
+ mainAxis: number;
333
+ crossAxis: number;
334
+ };
335
+ /**
336
+ * CSS selector or element that defines the containment context for the popup.
337
+ * @default undefined
338
+ */
339
+ container?: string | HTMLElement;
340
+ /**
341
+ * Whether the popup should automatically flip when there isn't enough space.
342
+ * @default true
343
+ */
344
+ flip: boolean;
345
+ /**
346
+ * Resolved Floating UI config for direct use with `computePosition()`.
347
+ * This is the escape hatch: reach for it only when you mount the element
348
+ * yourself and want to run the positioning loop manually instead of using
349
+ * {@link SuggestionProps.mount}.
350
+ */
351
+ floatingUi: SuggestionFloatingUiConfig;
352
+ /**
353
+ * Mounts your floating element and takes over positioning — the recommended,
354
+ * default way to render a suggestion popup.
355
+ *
356
+ * Pass the element you rendered (e.g. from `ReactRenderer`/`VueRenderer`). The
357
+ * plugin appends it into the configured `container` (default `document.body`),
358
+ * keeps it anchored to the cursor, and repositions it on scroll, resize, and
359
+ * layout shifts — no manual listeners required. Returns an `unmount` function
360
+ * that tears everything down; call it in `onExit`.
361
+ *
362
+ * Escape hatch: mount the element yourself and skip this, then run your own
363
+ * positioning loop with {@link SuggestionProps.floatingUi} +
364
+ * {@link SuggestionProps.clientRect}.
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * onStart: props => {
369
+ * component = new ReactRenderer(DropdownList, { props, editor: props.editor })
370
+ * unmount = props.mount(component.element)
371
+ * },
372
+ * onExit: () => unmount?.(),
373
+ * ```
374
+ */
375
+ mount: SuggestionMount;
376
+ /**
377
+ * Whether the items are currently being loaded.
378
+ * `true` before the async `items()` call resolves.
379
+ * Useful for showing a loading spinner or skeleton.
380
+ * @default false
381
+ */
382
+ loading: boolean;
206
383
  }
384
+ /**
385
+ * The props passed to the suggestion's onKeyDown render function
386
+ */
207
387
  interface SuggestionKeyDownProps {
208
388
  view: EditorView;
209
389
  event: KeyboardEvent;
210
390
  range: Range;
211
391
  }
392
+ /** @internal Internal state shape for the suggestion plugin. */
393
+ interface SuggestionPluginState {
394
+ active: boolean;
395
+ range: Range;
396
+ query: null | string;
397
+ text: null | string;
398
+ composing: boolean;
399
+ decorationId?: string | null;
400
+ dismissedRange: Range | null;
401
+ }
402
+
212
403
  declare const SuggestionPluginKey: PluginKey<any>;
213
404
  /**
214
405
  * This utility allows you to create suggestions.
215
406
  * @see https://tiptap.dev/api/utilities/suggestion
216
407
  */
217
- declare function Suggestion<I = any, TSelected = any>({ pluginKey, editor, char, allowSpaces, allowToIncludeChar, allowedPrefixes, startOfLine, decorationTag, decorationClass, decorationContent, decorationEmptyClass, command, items, render, allow, findSuggestionMatch, shouldShow, shouldResetDismissed, }: SuggestionOptions<I, TSelected>): Plugin<any>;
408
+ declare function Suggestion<I = any, TSelected = any>({ pluginKey, editor, char, allowSpaces, allowToIncludeChar, allowedPrefixes, startOfLine, decorationTag, decorationClass, decorationContent, decorationEmptyClass, command, items, minQueryLength, debounce, initialItems, placement, offset: offsetOption, container, flip, floatingUi, dismissOnOutsideClick, render, allow, findSuggestionMatch, shouldShow, shouldResetDismissed, }: SuggestionOptions<I, TSelected>): Plugin<SuggestionPluginState>;
218
409
  /**
219
410
  * Programmatically exit a suggestion plugin by dispatching a metadata-only
220
411
  * transaction. This is the safe, recommended API to remove suggestion
@@ -222,4 +413,4 @@ declare function Suggestion<I = any, TSelected = any>({ pluginKey, editor, char,
222
413
  */
223
414
  declare function exitSuggestion(view: EditorView, pluginKeyRef?: PluginKey): void;
224
415
 
225
- export { Suggestion, type SuggestionKeyDownProps, type SuggestionMatch, type SuggestionOptions, SuggestionPluginKey, type SuggestionProps, type Trigger, Suggestion as default, exitSuggestion, findSuggestionMatch };
416
+ export { Suggestion, type SuggestionFloatingUiConfig, type SuggestionFloatingUiOptions, type SuggestionKeyDownProps, type SuggestionMatch, type SuggestionMount, type SuggestionMountOptions, type SuggestionOptions, type SuggestionPlacement, SuggestionPluginKey, type SuggestionPositionData, type SuggestionProps, type Trigger, Suggestion as default, exitSuggestion, findSuggestionMatch };