@portabletext/plugin-typeahead-picker 2.1.0 → 3.0.0

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/README.md CHANGED
@@ -37,9 +37,9 @@ const emojiPicker = defineTypeaheadPicker<EmojiMatch>({
37
37
  // Return matches for the keyword. Can be sync or async (with mode: 'async').
38
38
  getMatches: ({keyword}) => searchEmojis(keyword),
39
39
 
40
- // Actions to execute when a match is selected (Enter/Tab or click).
40
+ // Action to execute when a match is selected (Enter/Tab or click).
41
41
  // Receives the event containing the selected match and pattern selection.
42
- actions: [
42
+ onSelect: [
43
43
  ({event}) => [
44
44
  raise({type: 'delete', at: event.patternSelection}), // Delete `:joy`
45
45
  raise({type: 'insert.text', text: event.match.emoji}), // Insert 😂
@@ -114,7 +114,7 @@ const emojiPicker = defineTypeaheadPicker<EmojiMatch>({
114
114
  keyword: /\S*/,
115
115
  delimiter: ':',
116
116
  getMatches: ({keyword}) => searchEmojis(keyword),
117
- actions: [
117
+ onSelect: [
118
118
  ({event}) => [
119
119
  raise({type: 'delete', at: event.patternSelection}),
120
120
  raise({type: 'insert.text', text: event.match.emoji}),
@@ -136,7 +136,7 @@ const mentionPicker = defineTypeaheadPicker<MentionMatch>({
136
136
  keyword: /\w*/,
137
137
  debounceMs: 200,
138
138
  getMatches: async ({keyword}) => api.searchUsers(keyword),
139
- actions: [
139
+ onSelect: [
140
140
  ({event}) => [
141
141
  raise({type: 'delete', at: event.patternSelection}),
142
142
  raise({
@@ -158,7 +158,7 @@ const commandPicker = defineTypeaheadPicker<CommandMatch>({
158
158
  trigger: /^\//, // ^ anchors to start of block
159
159
  keyword: /\w*/,
160
160
  getMatches: ({keyword}) => searchCommands(keyword),
161
- actions: [
161
+ onSelect: [
162
162
  ({event}) => {
163
163
  switch (event.match.command) {
164
164
  case 'h1':
@@ -204,7 +204,7 @@ const emojiPicker = defineTypeaheadPicker<EmojiMatch>({
204
204
  return true
205
205
  },
206
206
 
207
- actions: [
207
+ onSelect: [
208
208
  ({event}) => [
209
209
  raise({type: 'delete', at: event.patternSelection}),
210
210
  raise({type: 'insert.text', text: event.match.emoji}),
@@ -235,7 +235,8 @@ Creates a picker definition to pass to `useTypeaheadPicker`.
235
235
  | `mode` | `'sync' \| 'async'` | Whether `getMatches` returns synchronously or a Promise (default: `'sync'`) |
236
236
  | `debounceMs` | `number?` | Delay in ms before calling `getMatches`. Useful for both async (API calls) and sync (expensive local search) modes. (default: `0`) |
237
237
  | `getMatches` | `(ctx: {keyword: string}) => TMatch[]` | Function that returns matches for the keyword |
238
- | `actions` | `Array<TypeaheadSelectActionSet>` | Actions to execute when a match is selected |
238
+ | `onSelect` | `TypeaheadSelectActionSet[]` | Action sets to execute when a match is selected |
239
+ | `onDismiss` | `TypeaheadDismissActionSet[]?` | Optional action sets to execute when the picker is dismissed |
239
240
 
240
241
  **Trigger pattern rules:**
241
242
 
@@ -352,16 +353,59 @@ function EmojiPickerPlugin() {
352
353
 
353
354
  The error is cleared when the picker returns to idle (e.g., via Escape or cursor movement).
354
355
 
355
- ## Advanced Actions
356
+ ## onDismiss
356
357
 
357
- Action functions receive more than just the event. The full payload includes access to the editor snapshot, which is useful for generating keys, accessing the schema, or reading the current editor state.
358
+ The optional `onDismiss` callback runs when the picker is dismissed via Escape. This is useful for cleaning up the typed trigger and keyword text.
359
+
360
+ ```ts
361
+ const mentionPicker = defineTypeaheadPicker<MentionMatch>({
362
+ trigger: /@/,
363
+ keyword: /\w*/,
364
+ getMatches: ({keyword}) => searchUsers(keyword),
365
+ onSelect: [
366
+ ({event}) => [
367
+ raise({type: 'delete', at: event.patternSelection}),
368
+ raise({type: 'insert.text', text: `@${event.match.name}`}),
369
+ ],
370
+ ],
371
+ // Delete the typed text when user presses Escape
372
+ onDismiss: [
373
+ ({event}) => [raise({type: 'delete', at: event.patternSelection})],
374
+ ],
375
+ })
376
+ ```
377
+
378
+ Without `onDismiss`, pressing Escape leaves the typed text in place (e.g., `@john` remains in the editor). With `onDismiss` configured to delete the pattern, the text is removed.
379
+
380
+ **onDismiss payload:**
381
+
382
+ | Property | Description |
383
+ | ------------------------ | -------------------------------------------------------------- |
384
+ | `event.patternSelection` | Selection range covering the trigger + keyword (e.g., `@john`) |
385
+ | `snapshot` | Current editor snapshot |
386
+
387
+ Note: `onDismiss` is called when the user actively dismisses the picker:
388
+
389
+ - Pressing Escape
390
+ - Pressing Enter/Tab when there are no matches
391
+ - Programmatically via `picker.send({type: 'dismiss'})`
392
+
393
+ It is NOT called when:
394
+
395
+ - The user selects a match (Enter/Tab/click with a match selected)
396
+ - The picker is dismissed due to cursor movement
397
+ - The picker is dismissed due to invalid pattern (e.g., typing a space)
398
+
399
+ ## Advanced onSelect
400
+
401
+ The `onSelect` callback receives more than just the event. The full payload includes access to the editor snapshot, which is useful for generating keys, accessing the schema, or reading the current editor state.
358
402
 
359
403
  ```tsx
360
404
  const commandPicker = defineTypeaheadPicker<CommandMatch>({
361
405
  trigger: /^\//,
362
406
  keyword: /\w*/,
363
407
  getMatches: ({keyword}) => searchCommands(keyword),
364
- actions: [
408
+ onSelect: [
365
409
  ({event, snapshot}) => {
366
410
  // Access schema to check for block object fields
367
411
  const blockObjectSchema = snapshot.context.schema.blockObjects.find(
@@ -383,7 +427,7 @@ const commandPicker = defineTypeaheadPicker<CommandMatch>({
383
427
  })
384
428
  ```
385
429
 
386
- **Action payload:**
430
+ **onSelect payload:**
387
431
 
388
432
  | Property | Description |
389
433
  | ---------- | ----------------------------------------------------------------------------- |
@@ -515,14 +559,12 @@ The following keyboard shortcuts are handled automatically by the picker:
515
559
 
516
560
  ### Focus issues after selection
517
561
 
518
- - Ensure your actions include focus restoration if needed:
562
+ - Ensure your onSelect includes focus restoration if needed:
519
563
  ```tsx
520
- actions: [
564
+ onSelect: [
521
565
  ({event}) => [
522
566
  raise({type: 'delete', at: event.patternSelection}),
523
567
  raise({type: 'insert.text', text: event.match.emoji}),
524
- ],
525
- () => [
526
568
  effect(({send}) => {
527
569
  send({type: 'focus'})
528
570
  }),
package/dist/index.d.ts CHANGED
@@ -98,10 +98,15 @@ declare type BaseConfigWithDelimiter<TMatch extends AutoCompleteMatch> = {
98
98
  */
99
99
  guard?: TypeaheadTriggerGuard
100
100
  /**
101
- * Actions to execute when a match is selected.
102
- * Typically deletes the trigger text and inserts the selected content.
101
+ * Called when a match is selected.
102
+ * Returns behavior actions to execute (e.g., delete trigger text, insert content).
103
103
  */
104
- actions: Array<TypeaheadSelectActionSet<TMatch>>
104
+ onSelect: TypeaheadSelectActionSet<TMatch>[]
105
+ /**
106
+ * Called when the picker is dismissed.
107
+ * Returns behavior actions to execute (optional cleanup).
108
+ */
109
+ onDismiss?: TypeaheadDismissActionSet[]
105
110
  }
106
111
 
107
112
  declare type BaseConfigWithoutDelimiter<TMatch extends object> = {
@@ -127,10 +132,15 @@ declare type BaseConfigWithoutDelimiter<TMatch extends object> = {
127
132
  */
128
133
  guard?: TypeaheadTriggerGuard
129
134
  /**
130
- * Actions to execute when a match is selected.
131
- * Typically deletes the trigger text and inserts the selected content.
135
+ * Called when a match is selected.
136
+ * Returns behavior actions to execute (e.g., delete trigger text, insert content).
137
+ */
138
+ onSelect: TypeaheadSelectActionSet<TMatch>[]
139
+ /**
140
+ * Called when the picker is dismissed.
141
+ * Returns behavior actions to execute (optional cleanup).
132
142
  */
133
- actions: Array<TypeaheadSelectActionSet<TMatch>>
143
+ onDismiss?: TypeaheadDismissActionSet[]
134
144
  }
135
145
 
136
146
  /**
@@ -143,7 +153,12 @@ declare type BaseConfigWithoutDelimiter<TMatch extends object> = {
143
153
  * keyword: /[\S]+/,
144
154
  * delimiter: ':',
145
155
  * getMatches: ({keyword}) => searchEmojis(keyword),
146
- * actions: [insertEmojiAction],
156
+ * onSelect: [
157
+ * ({event}) => [
158
+ * raise({type: 'delete', at: event.patternSelection}),
159
+ * raise({type: 'insert.text', text: event.match.emoji}),
160
+ * ],
161
+ * ],
147
162
  * })
148
163
  * ```
149
164
  *
@@ -155,17 +170,12 @@ declare type BaseConfigWithoutDelimiter<TMatch extends object> = {
155
170
  * keyword: /[\w]+/,
156
171
  * debounceMs: 200,
157
172
  * getMatches: async ({keyword}) => api.searchUsers(keyword),
158
- * actions: [insertMentionAction],
159
- * })
160
- * ```
161
- *
162
- * @example Slash commands at start of block
163
- * ```ts
164
- * const slashCommandPicker = defineTypeaheadPicker({
165
- * trigger: /^\//,
166
- * keyword: /[\w]+/,
167
- * getMatches: ({keyword}) => filterCommands(keyword),
168
- * actions: [executeCommandAction],
173
+ * onSelect: [
174
+ * ({event}) => [
175
+ * raise({type: 'delete', at: event.patternSelection}),
176
+ * raise({type: 'insert.inline object', inlineObject: {_type: 'mention', userId: event.match.id}}),
177
+ * ],
178
+ * ],
169
179
  * })
170
180
  * ```
171
181
  *
@@ -175,15 +185,16 @@ declare type BaseConfigWithoutDelimiter<TMatch extends object> = {
175
185
  * trigger: /:/,
176
186
  * keyword: /[\S]+/,
177
187
  * getMatches: ({keyword}) => searchEmojis(keyword),
178
- * guard: ({snapshot}) => {
179
- * // Return false to prevent picker from activating
188
+ * guard: ({snapshot, event, dom}) => {
180
189
  * if (anotherPickerIsOpen()) return false
181
190
  * return true
182
191
  * },
183
- * actions: [({event}) => [
184
- * raise({type: 'delete', at: event.patternSelection}),
185
- * raise({type: 'insert.text', text: event.match.emoji}),
186
- * ]],
192
+ * onSelect: [
193
+ * ({event}) => [
194
+ * raise({type: 'delete', at: event.patternSelection}),
195
+ * raise({type: 'insert.text', text: event.match.emoji}),
196
+ * ],
197
+ * ],
187
198
  * })
188
199
  * ```
189
200
  *
@@ -275,6 +286,28 @@ declare type SyncConfigWithoutDelimiter<TMatch extends object> =
275
286
  getMatches: (context: {keyword: string}) => ReadonlyArray<TMatch>
276
287
  }
277
288
 
289
+ /**
290
+ * Action set that runs when the picker is dismissed.
291
+ * Returns an array of behavior actions to execute (optional cleanup).
292
+ *
293
+ * @public
294
+ */
295
+ export declare type TypeaheadDismissActionSet = BehaviorActionSet<
296
+ TypeaheadDismissEvent,
297
+ true
298
+ >
299
+
300
+ /**
301
+ * Event passed to `onDismiss` when the picker is dismissed.
302
+ *
303
+ * @public
304
+ */
305
+ export declare type TypeaheadDismissEvent = {
306
+ type: 'custom.typeahead dismiss'
307
+ /** Selection range covering the full pattern match (e.g., `@john`) for cleanup */
308
+ patternSelection: NonNullable<EditorSelection>
309
+ }
310
+
278
311
  /**
279
312
  * The picker instance returned by {@link useTypeaheadPicker}.
280
313
  *
@@ -360,7 +393,12 @@ export declare type TypeaheadPickerContext<TMatch> = {
360
393
  * keyword: /[\S]+/,
361
394
  * delimiter: ':',
362
395
  * getMatches: ({keyword}) => searchEmojis(keyword),
363
- * actions: [insertEmojiAction],
396
+ * onSelect: [
397
+ * ({event}) => [
398
+ * raise({type: 'delete', at: event.patternSelection}),
399
+ * raise({type: 'insert.text', text: event.match.emoji}),
400
+ * ],
401
+ * ],
364
402
  * })
365
403
  * ```
366
404
  *
@@ -423,12 +461,25 @@ declare type TypeaheadPickerDefinitionBase<TMatch extends object> = {
423
461
  */
424
462
  guard?: TypeaheadTriggerGuard
425
463
  /**
426
- * Actions to execute when a match is selected.
427
- * Typically deletes the trigger text and inserts the selected content.
464
+ * Called when a match is selected.
465
+ * Returns behavior actions to execute (e.g., delete trigger text, insert content).
428
466
  *
429
- * @see {@link TypeaheadSelectActionSet}
467
+ * @example
468
+ * ```ts
469
+ * onSelect: [
470
+ * ({event}) => [
471
+ * raise({type: 'delete', at: event.patternSelection}),
472
+ * raise({type: 'insert.text', text: event.match.emoji}),
473
+ * ],
474
+ * ]
475
+ * ```
476
+ */
477
+ onSelect: TypeaheadSelectActionSet<TMatch>[]
478
+ /**
479
+ * Called when the picker is dismissed (Escape, cursor movement, etc.).
480
+ * Returns behavior actions to execute (optional cleanup).
430
481
  */
431
- actions: Array<TypeaheadSelectActionSet<TMatch>>
482
+ onDismiss?: TypeaheadDismissActionSet[]
432
483
  }
433
484
 
434
485
  /**
@@ -504,19 +555,9 @@ export declare type TypeaheadPickerState =
504
555
  }
505
556
 
506
557
  /**
507
- * Action function that runs when a match is selected.
558
+ * Action set that runs when a match is selected.
508
559
  * Returns an array of behavior actions to execute (e.g., delete trigger text, insert content).
509
560
  *
510
- * @example
511
- * ```ts
512
- * const insertEmoji: TypeaheadSelectActionSet<EmojiMatch> = (
513
- * {event},
514
- * ) => [
515
- * raise({type: 'delete', at: event.patternSelection}),
516
- * raise({type: 'insert.text', text: event.match.emoji}),
517
- * ]
518
- * ```
519
- *
520
561
  * @public
521
562
  */
522
563
  export declare type TypeaheadSelectActionSet<TMatch> = BehaviorActionSet<
@@ -525,7 +566,7 @@ export declare type TypeaheadSelectActionSet<TMatch> = BehaviorActionSet<
525
566
  >
526
567
 
527
568
  /**
528
- * Event passed to typeahead select action sets.
569
+ * Event passed to `onSelect` when a match is selected.
529
570
  *
530
571
  * @public
531
572
  */
package/dist/index.js CHANGED
@@ -343,20 +343,50 @@ const triggerListenerCallback = () => ({
343
343
  };
344
344
  }, escapeListenerCallback = () => ({
345
345
  sendBack,
346
- input
347
- }) => input.editor.registerBehavior({
348
- behavior: defineBehavior({
349
- on: "keyboard.keydown",
350
- guard: ({
351
- event
352
- }) => escapeShortcut.guard(event.originEvent),
353
- actions: [() => [effect(() => {
354
- sendBack({
355
- type: "dismiss"
356
- });
357
- })]]
358
- })
359
- }), arrowListenerCallback = () => ({
346
+ input,
347
+ receive
348
+ }) => {
349
+ let context = input.context;
350
+ return receive((event) => {
351
+ context = event.context;
352
+ }), input.context.editor.registerBehavior({
353
+ behavior: defineBehavior({
354
+ on: "keyboard.keydown",
355
+ guard: ({
356
+ event
357
+ }) => escapeShortcut.guard(event.originEvent),
358
+ actions: [({
359
+ snapshot,
360
+ dom
361
+ }) => {
362
+ if (!context.focusSpan || !context.definition.onDismiss)
363
+ return [effect(() => sendBack({
364
+ type: "close"
365
+ }))];
366
+ const patternSelection = {
367
+ anchor: {
368
+ path: context.focusSpan.path,
369
+ offset: context.focusSpan.textBefore.length
370
+ },
371
+ focus: {
372
+ path: context.focusSpan.path,
373
+ offset: context.focusSpan.node.text.length - context.focusSpan.textAfter.length
374
+ }
375
+ };
376
+ return [...context.definition.onDismiss.flatMap((actionSet) => actionSet({
377
+ snapshot,
378
+ dom,
379
+ event: {
380
+ type: "custom.typeahead dismiss",
381
+ patternSelection
382
+ }
383
+ }, !0)), effect(() => sendBack({
384
+ type: "close"
385
+ }))];
386
+ }]
387
+ })
388
+ });
389
+ }, arrowListenerCallback = () => ({
360
390
  sendBack,
361
391
  input
362
392
  }) => {
@@ -396,7 +426,52 @@ const triggerListenerCallback = () => ({
396
426
  sendBack({
397
427
  type: "selection changed"
398
428
  });
399
- }).unsubscribe, submitListenerCallback = () => ({
429
+ }).unsubscribe, dismissListenerCallback = () => ({
430
+ sendBack,
431
+ input,
432
+ receive
433
+ }) => {
434
+ let context = input.context;
435
+ return receive((event) => {
436
+ context = event.context;
437
+ }), input.context.editor.registerBehavior({
438
+ behavior: defineBehavior({
439
+ on: "custom.typeahead dismiss",
440
+ guard: ({
441
+ event
442
+ }) => event.pickerId === context.definition._id,
443
+ actions: [({
444
+ snapshot,
445
+ dom
446
+ }) => {
447
+ if (!context.focusSpan || !context.definition.onDismiss)
448
+ return [effect(() => sendBack({
449
+ type: "close"
450
+ }))];
451
+ const patternSelection = {
452
+ anchor: {
453
+ path: context.focusSpan.path,
454
+ offset: context.focusSpan.textBefore.length
455
+ },
456
+ focus: {
457
+ path: context.focusSpan.path,
458
+ offset: context.focusSpan.node.text.length - context.focusSpan.textAfter.length
459
+ }
460
+ };
461
+ return [...context.definition.onDismiss.flatMap((actionSet) => actionSet({
462
+ snapshot,
463
+ dom,
464
+ event: {
465
+ type: "custom.typeahead dismiss",
466
+ patternSelection
467
+ }
468
+ }, !0)), effect(() => sendBack({
469
+ type: "close"
470
+ }))];
471
+ }]
472
+ })
473
+ });
474
+ }, submitListenerCallback = () => ({
400
475
  sendBack,
401
476
  input,
402
477
  receive
@@ -435,7 +510,7 @@ const triggerListenerCallback = () => ({
435
510
  event
436
511
  }) => [forward(event), effect(() => {
437
512
  sendBack({
438
- type: "dismiss"
513
+ type: "close"
439
514
  });
440
515
  })]]
441
516
  })
@@ -445,11 +520,35 @@ const triggerListenerCallback = () => ({
445
520
  guard: ({
446
521
  event
447
522
  }) => (enterShortcut.guard(event.originEvent) || tabShortcut.guard(event.originEvent)) && context.patternText.length > 1 && context.matches.length === 0,
448
- actions: [() => [effect(() => {
449
- sendBack({
450
- type: "dismiss"
451
- });
452
- })]]
523
+ actions: [({
524
+ snapshot,
525
+ dom
526
+ }) => {
527
+ if (!context.focusSpan || !context.definition.onDismiss)
528
+ return [effect(() => sendBack({
529
+ type: "close"
530
+ }))];
531
+ const patternSelection = {
532
+ anchor: {
533
+ path: context.focusSpan.path,
534
+ offset: context.focusSpan.textBefore.length
535
+ },
536
+ focus: {
537
+ path: context.focusSpan.path,
538
+ offset: context.focusSpan.node.text.length - context.focusSpan.textAfter.length
539
+ }
540
+ };
541
+ return [...context.definition.onDismiss.flatMap((actionSet) => actionSet({
542
+ snapshot,
543
+ dom,
544
+ event: {
545
+ type: "custom.typeahead dismiss",
546
+ patternSelection
547
+ }
548
+ }, !0)), effect(() => sendBack({
549
+ type: "close"
550
+ }))];
551
+ }]
453
552
  })
454
553
  })];
455
554
  return () => {
@@ -482,7 +581,7 @@ const triggerListenerCallback = () => ({
482
581
  event
483
582
  }) => [forward(event), effect(() => {
484
583
  sendBack({
485
- type: "dismiss"
584
+ type: "close"
486
585
  });
487
586
  })]]
488
587
  })
@@ -510,26 +609,21 @@ const triggerListenerCallback = () => ({
510
609
  path: event.focusSpan.path,
511
610
  offset: event.focusSpan.node.text.length - event.focusSpan.textAfter.length
512
611
  }
513
- }, allActions = [effect(() => {
612
+ }, selectActions = input.context.definition.onSelect.flatMap((actionSet) => actionSet({
613
+ snapshot,
614
+ dom,
615
+ event: {
616
+ type: "custom.typeahead select",
617
+ match: event.match,
618
+ keyword: event.keyword,
619
+ patternSelection
620
+ }
621
+ }, !0));
622
+ return [effect(() => {
514
623
  sendBack({
515
- type: "dismiss"
624
+ type: "close"
516
625
  });
517
- })];
518
- for (const actionSet of input.context.definition.actions) {
519
- const actions = actionSet({
520
- snapshot,
521
- dom,
522
- event: {
523
- type: "custom.typeahead select",
524
- match: event.match,
525
- keyword: event.keyword,
526
- patternSelection
527
- }
528
- }, !0);
529
- for (const action of actions)
530
- allActions.push(action);
531
- }
532
- return allActions;
626
+ }), ...selectActions];
533
627
  }]
534
628
  })
535
629
  });
@@ -553,6 +647,7 @@ function createTypeaheadPickerMachine() {
553
647
  "submit listener": fromCallback(submitListenerCallback()),
554
648
  "text insertion listener": fromCallback(textInsertionListenerCallback()),
555
649
  "select match listener": fromCallback(selectMatchListenerCallback()),
650
+ "dismiss listener": fromCallback(dismissListenerCallback()),
556
651
  "get matches": fromPromise(async ({
557
652
  input
558
653
  }) => {
@@ -594,83 +689,84 @@ function createTypeaheadPickerMachine() {
594
689
  selectedIndex: 0
595
690
  };
596
691
  }),
597
- "update focus span": assign({
598
- focusSpan: ({
599
- context
600
- }) => {
601
- if (!context.focusSpan)
602
- return context.focusSpan;
603
- const snapshot = context.editor.getSnapshot(), focusSpan = getFocusSpan(snapshot);
604
- if (!snapshot.context.selection || !focusSpan)
605
- return;
606
- const nextSpan = getNextSpan({
607
- ...snapshot,
608
- context: {
609
- ...snapshot.context,
610
- selection: {
611
- anchor: {
612
- path: context.focusSpan.path,
613
- offset: 0
614
- },
615
- focus: {
616
- path: context.focusSpan.path,
617
- offset: 0
618
- }
619
- }
620
- }
621
- });
622
- if (!isEqualPaths(focusSpan.path, context.focusSpan.path))
623
- return nextSpan && context.focusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && isSelectionCollapsed(snapshot) ? context.focusSpan : void 0;
624
- if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore) || !focusSpan.node.text.endsWith(context.focusSpan.textAfter))
625
- return;
626
- const keywordAnchor = {
627
- path: focusSpan.path,
628
- offset: context.focusSpan.textBefore.length
629
- }, keywordFocus = {
630
- path: focusSpan.path,
631
- offset: focusSpan.node.text.length - context.focusSpan.textAfter.length
632
- }, selectionIsBeforeKeyword = isPointAfterSelection(keywordAnchor)(snapshot), selectionIsAfterKeyword = isPointBeforeSelection(keywordFocus)(snapshot);
633
- if (!(selectionIsBeforeKeyword || selectionIsAfterKeyword))
634
- return {
635
- node: focusSpan.node,
636
- path: focusSpan.path,
637
- textBefore: context.focusSpan.textBefore,
638
- textAfter: context.focusSpan.textAfter
639
- };
640
- }
641
- }),
642
- "update pattern text": assign(({
692
+ "handle selection changed": assign(({
643
693
  context
644
694
  }) => {
645
695
  if (!context.focusSpan)
646
- return {};
647
- const patternText = extractPatternTextFromFocusSpan(context.focusSpan);
648
- return patternText === context.patternText ? {} : {
649
- patternText,
650
- selectedIndex: 0
651
- };
652
- }),
653
- "update keyword": assign(({
654
- context
655
- }) => {
656
- if (!context.focusSpan || !context.patternText)
657
- return {};
658
- const keyword = extractKeyword(context.patternText, context.triggerPattern, context.definition.delimiter, context.completePattern);
659
- return keyword === context.keyword ? {} : {
696
+ return {
697
+ focusSpan: void 0
698
+ };
699
+ const snapshot = context.editor.getSnapshot(), currentFocusSpan = getFocusSpan(snapshot);
700
+ if (!snapshot.context.selection || !currentFocusSpan)
701
+ return {
702
+ focusSpan: void 0
703
+ };
704
+ const nextSpan = getNextSpan({
705
+ ...snapshot,
706
+ context: {
707
+ ...snapshot.context,
708
+ selection: {
709
+ anchor: {
710
+ path: context.focusSpan.path,
711
+ offset: 0
712
+ },
713
+ focus: {
714
+ path: context.focusSpan.path,
715
+ offset: 0
716
+ }
717
+ }
718
+ }
719
+ });
720
+ if (!isEqualPaths(currentFocusSpan.path, context.focusSpan.path))
721
+ return nextSpan && context.focusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && isSelectionCollapsed(snapshot) ? {} : {
722
+ focusSpan: void 0
723
+ };
724
+ if (!currentFocusSpan.node.text.startsWith(context.focusSpan.textBefore))
725
+ return {
726
+ focusSpan: void 0
727
+ };
728
+ if (!currentFocusSpan.node.text.endsWith(context.focusSpan.textAfter))
729
+ return {
730
+ focusSpan: void 0
731
+ };
732
+ const keywordAnchor = {
733
+ path: currentFocusSpan.path,
734
+ offset: context.focusSpan.textBefore.length
735
+ }, keywordFocus = {
736
+ path: currentFocusSpan.path,
737
+ offset: currentFocusSpan.node.text.length - context.focusSpan.textAfter.length
738
+ }, selectionIsBeforeKeyword = isPointAfterSelection(keywordAnchor)(snapshot), selectionIsAfterKeyword = isPointBeforeSelection(keywordFocus)(snapshot);
739
+ if (selectionIsBeforeKeyword || selectionIsAfterKeyword)
740
+ return {
741
+ focusSpan: void 0
742
+ };
743
+ const focusSpan = {
744
+ node: currentFocusSpan.node,
745
+ path: currentFocusSpan.path,
746
+ textBefore: context.focusSpan.textBefore,
747
+ textAfter: context.focusSpan.textAfter
748
+ }, patternText = extractPatternTextFromFocusSpan(focusSpan), keyword = extractKeyword(patternText, context.triggerPattern, context.definition.delimiter, context.completePattern);
749
+ if (context.definition.mode === "async" || context.definition.debounceMs)
750
+ return {
751
+ focusSpan,
752
+ patternText,
753
+ keyword,
754
+ selectedIndex: patternText !== context.patternText ? 0 : context.selectedIndex,
755
+ isLoading: context.isLoading || context.requestedKeyword !== keyword
756
+ };
757
+ const matches = context.definition.getMatches({
660
758
  keyword
759
+ });
760
+ return {
761
+ focusSpan,
762
+ patternText,
763
+ keyword,
764
+ matches,
765
+ requestedKeyword: keyword,
766
+ selectedIndex: patternText !== context.patternText ? 0 : context.selectedIndex,
767
+ isLoading: !1
661
768
  };
662
769
  }),
663
- "update matches": assign(({
664
- context
665
- }) => !context.focusSpan || !context.patternText ? {} : context.definition.mode === "async" || context.definition.debounceMs ? {
666
- isLoading: context.isLoading || context.requestedKeyword !== context.keyword
667
- } : {
668
- matches: context.definition.getMatches({
669
- keyword: context.keyword
670
- }),
671
- requestedKeyword: context.keyword,
672
- isLoading: !1
673
- }),
674
770
  "handle async load complete": assign(({
675
771
  context,
676
772
  event
@@ -731,6 +827,18 @@ function createTypeaheadPickerMachine() {
731
827
  type: "context changed",
732
828
  context
733
829
  })),
830
+ "update escape listener context": sendTo("escape listener", ({
831
+ context
832
+ }) => ({
833
+ type: "context changed",
834
+ context
835
+ })),
836
+ "update request dismiss listener context": sendTo("dismiss listener", ({
837
+ context
838
+ }) => ({
839
+ type: "context changed",
840
+ context
841
+ })),
734
842
  "handle error": assign({
735
843
  isLoading: !1,
736
844
  error: ({
@@ -879,10 +987,11 @@ function createTypeaheadPickerMachine() {
879
987
  })
880
988
  }, {
881
989
  src: "escape listener",
990
+ id: "escape listener",
882
991
  input: ({
883
992
  context
884
993
  }) => ({
885
- editor: context.editor
994
+ context
886
995
  })
887
996
  }, {
888
997
  src: "selection listener",
@@ -907,13 +1016,21 @@ function createTypeaheadPickerMachine() {
907
1016
  }) => ({
908
1017
  context
909
1018
  })
1019
+ }, {
1020
+ src: "dismiss listener",
1021
+ id: "dismiss listener",
1022
+ input: ({
1023
+ context
1024
+ }) => ({
1025
+ context
1026
+ })
910
1027
  }],
911
1028
  on: {
912
- dismiss: {
1029
+ close: {
913
1030
  target: "idle"
914
1031
  },
915
1032
  "selection changed": {
916
- actions: ["update focus span", "update pattern text", "update keyword", "update matches", "update submit listener context", "update text insertion listener context"]
1033
+ actions: ["handle selection changed", "update submit listener context", "update text insertion listener context", "update escape listener context", "update request dismiss listener context"]
917
1034
  }
918
1035
  },
919
1036
  always: [{
@@ -1141,7 +1258,7 @@ function getFirstExactMatch(matches) {
1141
1258
  return matches.find((match) => match?.type === "exact");
1142
1259
  }
1143
1260
  function useTypeaheadPicker(definition) {
1144
- const $ = c(19), editor = useEditor();
1261
+ const $ = c(21), editor = useEditor();
1145
1262
  let t0;
1146
1263
  $[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t0 = createTypeaheadPickerMachine(), $[0] = t0) : t0 = $[0];
1147
1264
  let t1;
@@ -1168,14 +1285,17 @@ function useTypeaheadPicker(definition) {
1168
1285
  context: t4
1169
1286
  }, $[11] = t2, $[12] = t4, $[13] = t5) : t5 = $[13];
1170
1287
  let t6;
1171
- $[14] !== send ? (t6 = (event) => {
1172
- send(event);
1173
- }, $[14] = send, $[15] = t6) : t6 = $[15];
1288
+ $[14] !== definition || $[15] !== editor || $[16] !== send ? (t6 = (event) => {
1289
+ event.type === "dismiss" ? editor.send({
1290
+ type: "custom.typeahead dismiss",
1291
+ pickerId: definition._id
1292
+ }) : send(event);
1293
+ }, $[14] = definition, $[15] = editor, $[16] = send, $[17] = t6) : t6 = $[17];
1174
1294
  let t7;
1175
- return $[16] !== t5 || $[17] !== t6 ? (t7 = {
1295
+ return $[18] !== t5 || $[19] !== t6 ? (t7 = {
1176
1296
  snapshot: t5,
1177
1297
  send: t6
1178
- }, $[16] = t5, $[17] = t6, $[18] = t7) : t7 = $[18], t7;
1298
+ }, $[18] = t5, $[19] = t6, $[20] = t7) : t7 = $[20], t7;
1179
1299
  }
1180
1300
  export {
1181
1301
  defineTypeaheadPicker,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/define-typeahead-picker.ts","../src/extract-keyword.ts","../src/typeahead-picker-machine.tsx","../src/use-typeahead-picker.ts"],"sourcesContent":["import type {\n AutoCompleteMatch,\n TypeaheadPickerDefinition,\n TypeaheadSelectActionSet,\n TypeaheadTriggerGuard,\n} from './typeahead-picker.types'\n\ntype BaseConfigWithoutDelimiter<TMatch extends object> = {\n /**\n * Pattern that activates the picker. Must be a single character.\n * Can include `^` for start-of-block triggers.\n *\n * @example `/:/` - activates on colon\n * @example `/@/` - activates on at-sign\n * @example `/^\\//` - activates on slash at start of block\n */\n trigger: RegExp\n /**\n * Pattern matching the keyword portion after the trigger.\n * The entire match becomes the keyword passed to `getMatches`.\n * Common patterns: non-whitespace (`\\S*`) or word characters (`\\w*`).\n */\n keyword: RegExp\n delimiter?: undefined\n /**\n * Guard function that runs at trigger time to conditionally prevent activation.\n * Return `false` to block activation, or `true` to allow it.\n */\n guard?: TypeaheadTriggerGuard\n /**\n * Actions to execute when a match is selected.\n * Typically deletes the trigger text and inserts the selected content.\n */\n actions: Array<TypeaheadSelectActionSet<TMatch>>\n}\n\ntype BaseConfigWithDelimiter<TMatch extends AutoCompleteMatch> = {\n /**\n * Pattern that activates the picker. Must be a single character.\n * Can include `^` for start-of-block triggers.\n *\n * @example `/:/` - activates on colon\n * @example `/@/` - activates on at-sign\n * @example `/^\\//` - activates on slash at start of block\n */\n trigger: RegExp\n /**\n * Pattern matching the keyword portion after the trigger.\n * The entire match becomes the keyword passed to `getMatches`.\n * Common patterns: non-whitespace (`\\S*`) or word characters (`\\w*`).\n */\n keyword: RegExp\n /**\n * Character that triggers auto-completion.\n * Typing this after a keyword with an exact match auto-inserts it.\n *\n * @example `':'` - typing `:joy:` auto-inserts the joy emoji\n */\n delimiter: string\n /**\n * Guard function that runs at trigger time to conditionally prevent activation.\n * Return `false` to block activation, or `true` to allow it.\n */\n guard?: TypeaheadTriggerGuard\n /**\n * Actions to execute when a match is selected.\n * Typically deletes the trigger text and inserts the selected content.\n */\n actions: Array<TypeaheadSelectActionSet<TMatch>>\n}\n\ntype SyncConfigWithoutDelimiter<TMatch extends object> =\n BaseConfigWithoutDelimiter<TMatch> & {\n /**\n * Whether `getMatches` returns synchronously or asynchronously.\n * @defaultValue `'sync'`\n */\n mode?: 'sync'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Useful for expensive local searches.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => ReadonlyArray<TMatch>\n }\n\ntype SyncConfigWithDelimiter<TMatch extends AutoCompleteMatch> =\n BaseConfigWithDelimiter<TMatch> & {\n /**\n * Whether `getMatches` returns synchronously or asynchronously.\n * @defaultValue `'sync'`\n */\n mode?: 'sync'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Useful for expensive local searches.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => ReadonlyArray<TMatch>\n }\n\ntype AsyncConfigWithoutDelimiter<TMatch extends object> =\n BaseConfigWithoutDelimiter<TMatch> & {\n /**\n * Set to `'async'` when `getMatches` returns a Promise.\n */\n mode: 'async'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Recommended for API calls to reduce request frequency.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Async function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => Promise<ReadonlyArray<TMatch>>\n }\n\ntype AsyncConfigWithDelimiter<TMatch extends AutoCompleteMatch> =\n BaseConfigWithDelimiter<TMatch> & {\n /**\n * Set to `'async'` when `getMatches` returns a Promise.\n */\n mode: 'async'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Recommended for API calls to reduce request frequency.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Async function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => Promise<ReadonlyArray<TMatch>>\n }\n\n/**\n * Creates a typeahead picker definition to use with {@link useTypeaheadPicker}.\n *\n * @example Emoji picker with auto-complete\n * ```ts\n * const emojiPicker = defineTypeaheadPicker({\n * trigger: /:/,\n * keyword: /[\\S]+/,\n * delimiter: ':',\n * getMatches: ({keyword}) => searchEmojis(keyword),\n * actions: [insertEmojiAction],\n * })\n * ```\n *\n * @example Async mention picker\n * ```ts\n * const mentionPicker = defineTypeaheadPicker({\n * mode: 'async',\n * trigger: /@/,\n * keyword: /[\\w]+/,\n * debounceMs: 200,\n * getMatches: async ({keyword}) => api.searchUsers(keyword),\n * actions: [insertMentionAction],\n * })\n * ```\n *\n * @example Slash commands at start of block\n * ```ts\n * const slashCommandPicker = defineTypeaheadPicker({\n * trigger: /^\\//,\n * keyword: /[\\w]+/,\n * getMatches: ({keyword}) => filterCommands(keyword),\n * actions: [executeCommandAction],\n * })\n * ```\n *\n * @example Picker with guard (runs at trigger time)\n * ```ts\n * const emojiPicker = defineTypeaheadPicker({\n * trigger: /:/,\n * keyword: /[\\S]+/,\n * getMatches: ({keyword}) => searchEmojis(keyword),\n * guard: ({snapshot}) => {\n * // Return false to prevent picker from activating\n * if (anotherPickerIsOpen()) return false\n * return true\n * },\n * actions: [({event}) => [\n * raise({type: 'delete', at: event.patternSelection}),\n * raise({type: 'insert.text', text: event.match.emoji}),\n * ]],\n * })\n * ```\n *\n * @public\n */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config: SyncConfigWithoutDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends AutoCompleteMatch>(\n config: SyncConfigWithDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config: AsyncConfigWithoutDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends AutoCompleteMatch>(\n config: AsyncConfigWithDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config:\n | SyncConfigWithoutDelimiter<TMatch>\n | SyncConfigWithDelimiter<TMatch & AutoCompleteMatch>\n | AsyncConfigWithoutDelimiter<TMatch>\n | AsyncConfigWithDelimiter<TMatch & AutoCompleteMatch>,\n): TypeaheadPickerDefinition<TMatch> {\n return {\n ...config,\n _id: Symbol('typeahead-picker'),\n } as TypeaheadPickerDefinition<TMatch>\n}\n","/**\n * Extract keyword from pattern text using the trigger pattern.\n * Removes the trigger match from the start and delimiter from the end.\n *\n * @param patternText - The full pattern text (e.g., `:joy:` or `:joy`)\n * @param triggerPattern - Pattern matching the trigger (e.g., /:/)\n * @param delimiter - Optional delimiter character (e.g., `:`)\n * @param completePattern - Optional complete pattern to detect if this is a complete match\n */\nexport function extractKeyword(\n patternText: string,\n triggerPattern: RegExp,\n delimiter?: string,\n completePattern?: RegExp,\n): string {\n const triggerMatch = patternText.match(triggerPattern)\n\n if (!triggerMatch || triggerMatch.index !== 0) {\n return patternText\n }\n\n let keyword = patternText.slice(triggerMatch[0].length)\n\n if (delimiter && keyword.endsWith(delimiter)) {\n // Check if this is a complete match (pattern matches the complete pattern exactly)\n const isCompleteMatch =\n completePattern &&\n (() => {\n const completeMatch = patternText.match(completePattern)\n return (\n completeMatch &&\n completeMatch.index === 0 &&\n completeMatch[0] === patternText\n )\n })()\n\n // Strip delimiter if:\n // - This is a complete match (even if keyword becomes empty), OR\n // - Keyword would remain non-empty after stripping\n if (isCompleteMatch || keyword.length > delimiter.length) {\n keyword = keyword.slice(0, -delimiter.length)\n }\n }\n\n return keyword\n}\n","import type {\n ChildPath,\n Editor,\n EditorSelector,\n EditorSnapshot,\n PortableTextSpan,\n} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n type BehaviorAction,\n} from '@portabletext/editor/behaviors'\nimport {\n getFocusSpan,\n getMarkState,\n getNextSpan,\n getPreviousSpan,\n isPointAfterSelection,\n isPointBeforeSelection,\n isSelectionCollapsed,\n type MarkState,\n} from '@portabletext/editor/selectors'\nimport {isEqualPaths, isEqualSelectionPoints} from '@portabletext/editor/utils'\nimport {createKeyboardShortcut} from '@portabletext/keyboard-shortcuts'\nimport {\n defineInputRule,\n defineInputRuleBehavior,\n type InputRuleMatch,\n} from '@portabletext/plugin-input-rule'\nimport {\n assign,\n fromCallback,\n fromPromise,\n sendTo,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {extractKeyword} from './extract-keyword'\nimport type {\n AutoCompleteMatch,\n TypeaheadPickerDefinition,\n} from './typeahead-picker.types'\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/**\n * Build the trigger pattern from the definition.\n */\nfunction buildTriggerPattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp {\n return new RegExp(definition.trigger.source)\n}\n\n/**\n * Build the partial pattern (trigger + keyword) from the definition.\n */\nfunction buildPartialPattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp {\n return new RegExp(definition.trigger.source + definition.keyword.source)\n}\n\n/**\n * Build the complete pattern (trigger + keyword + delimiter) from the definition.\n */\nfunction buildCompletePattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp | undefined {\n if (!definition.delimiter) {\n return undefined\n }\n\n const escapedDelimiter = escapeRegExp(definition.delimiter)\n return new RegExp(\n definition.trigger.source + definition.keyword.source + escapedDelimiter,\n )\n}\n\nconst arrowUpShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowUp'}],\n})\nconst arrowDownShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowDown'}],\n})\nconst enterShortcut = createKeyboardShortcut({\n default: [{key: 'Enter'}],\n})\nconst tabShortcut = createKeyboardShortcut({\n default: [{key: 'Tab'}],\n})\nconst escapeShortcut = createKeyboardShortcut({\n default: [{key: 'Escape'}],\n})\n\nconst getTriggerState: EditorSelector<\n | {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n }\n markState: MarkState\n focusSpanTextBefore: string\n focusSpanTextAfter: string\n previousSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n nextSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n }\n | undefined\n> = (snapshot) => {\n const focusSpan = getFocusSpan(snapshot)\n const markState = getMarkState(snapshot)\n\n if (!focusSpan || !markState || !snapshot.context.selection) {\n return undefined\n }\n\n const focusSpanTextBefore = focusSpan.node.text.slice(\n 0,\n snapshot.context.selection.focus.offset,\n )\n const focusSpanTextAfter = focusSpan.node.text.slice(\n snapshot.context.selection.focus.offset,\n )\n const previousSpan = getPreviousSpan(snapshot)\n const nextSpan = getNextSpan(snapshot)\n\n return {\n focusSpan,\n markState,\n focusSpanTextBefore,\n focusSpanTextAfter,\n previousSpan,\n nextSpan,\n }\n}\n\ntype FocusSpanData = {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n}\n\nfunction createTriggerActions({\n snapshot,\n payload,\n keywordState,\n pickerId,\n}: {\n snapshot: EditorSnapshot\n payload: TriggerPayload\n keywordState: 'partial' | 'complete'\n pickerId: symbol\n}) {\n if (payload.markState.state === 'unchanged') {\n const textBeforeMatch = payload.focusSpanTextBefore.slice(\n 0,\n payload.lastMatch.targetOffsets.anchor.offset,\n )\n const focusSpan = {\n node: {\n _key: payload.focusSpan.node._key,\n _type: payload.focusSpan.node._type,\n text: `${textBeforeMatch}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: payload.focusSpan.path,\n textBefore: textBeforeMatch,\n textAfter: payload.focusSpanTextAfter,\n }\n\n if (keywordState === 'complete') {\n return [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n }\n\n return [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n }\n\n const newSpan = {\n _key: snapshot.context.keyGenerator(),\n _type: payload.focusSpan.node._type,\n text: payload.lastMatch.text,\n marks: payload.markState.marks,\n }\n\n let focusSpan: FocusSpanData = {\n node: {\n _key: newSpan._key,\n _type: newSpan._type,\n text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: [\n {_key: payload.focusSpan.path[0]._key},\n 'children',\n {_key: newSpan._key},\n ] satisfies ChildPath,\n textBefore: '',\n textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter,\n }\n\n if (\n payload.previousSpan &&\n payload.focusSpanTextBefore.length === 0 &&\n JSON.stringify(payload.previousSpan.node.marks ?? []) ===\n JSON.stringify(payload.markState.marks)\n ) {\n focusSpan = {\n node: {\n _key: payload.previousSpan.node._key,\n _type: newSpan._type,\n text: `${payload.previousSpan.node.text}${newSpan.text}`,\n marks: newSpan.marks,\n },\n path: payload.previousSpan.path,\n textBefore: payload.previousSpan.node.text,\n textAfter: '',\n }\n }\n\n return [\n raise({type: 'select', at: payload.lastMatch.targetOffsets}),\n raise({type: 'delete', at: payload.lastMatch.targetOffsets}),\n raise({type: 'insert.child', child: newSpan}),\n ...(keywordState === 'complete'\n ? [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n : [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]),\n ]\n}\n\ntype TriggerFoundEvent = {\n type: 'custom.typeahead trigger found'\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}\n\nfunction createTriggerFoundEvent(payload: {\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}): TriggerFoundEvent {\n return {\n type: 'custom.typeahead trigger found',\n ...payload,\n }\n}\n\ntype KeywordFoundEvent = {\n type: 'custom.typeahead keyword found'\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}\n\nfunction createKeywordFoundEvent(payload: {\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}): KeywordFoundEvent {\n return {\n type: 'custom.typeahead keyword found',\n ...payload,\n }\n}\n\ntype TypeaheadPickerMachineContext<TMatch extends object> = {\n editor: Editor\n definition: TypeaheadPickerDefinition<TMatch>\n triggerPattern: RegExp\n partialPattern: RegExp\n completePattern: RegExp | undefined\n matches: ReadonlyArray<TMatch>\n selectedIndex: number\n focusSpan: FocusSpanData | undefined\n patternText: string\n keyword: string\n requestedKeyword: string\n error: Error | undefined\n isLoading: boolean\n}\n\ntype TypeaheadPickerMachineEvent<TMatch extends object> =\n | TriggerFoundEvent\n | KeywordFoundEvent\n | {type: 'selection changed'}\n | {type: 'dismiss'}\n | {type: 'navigate down'}\n | {type: 'navigate up'}\n | {type: 'navigate to'; index: number}\n | {type: 'select'}\n | {type: 'matches loaded'; matches: ReadonlyArray<TMatch>}\n | {type: 'matches error'; error: Error}\n\ntype TriggerPayload = ReturnType<typeof getTriggerState> & {\n lastMatch: InputRuleMatch\n extractedKeyword: string\n}\n\n/**\n * Extract the pattern text (trigger + keyword) from focus span data.\n */\nfunction extractPatternTextFromFocusSpan(focusSpan: FocusSpanData): string {\n if (focusSpan.textBefore.length > 0 && focusSpan.textAfter.length > 0) {\n return focusSpan.node.text.slice(\n focusSpan.textBefore.length,\n -focusSpan.textAfter.length,\n )\n }\n\n if (focusSpan.textBefore.length > 0) {\n return focusSpan.node.text.slice(focusSpan.textBefore.length)\n }\n\n if (focusSpan.textAfter.length > 0) {\n return focusSpan.node.text.slice(0, -focusSpan.textAfter.length)\n }\n\n return focusSpan.node.text\n}\n\nfunction createInputRules<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n) {\n const rules: Array<ReturnType<typeof defineInputRule<TriggerPayload>>> = []\n\n const triggerPattern = buildTriggerPattern(definition)\n const partialPattern = buildPartialPattern(definition)\n const completePattern = buildCompletePattern(definition)\n\n if (completePattern) {\n const completeRule = defineInputRule<TriggerPayload>({\n on: completePattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n // Match starts before insertion. Check if the inserted text itself\n // matches the complete pattern (e.g., inserting `:dog:` after `foo:`).\n const insertedMatch = event.textInserted.match(completePattern)\n\n if (insertedMatch === null || insertedMatch.index !== 0) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch: {\n ...lastMatch,\n text: event.textInserted,\n targetOffsets: {\n ...lastMatch.targetOffsets,\n anchor: {\n ...lastMatch.targetOffsets.anchor,\n offset: event.textBefore.length,\n },\n },\n },\n extractedKeyword: extractKeyword(\n event.textInserted,\n triggerPattern,\n definition.delimiter,\n completePattern,\n ),\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: extractKeyword(\n lastMatch.text,\n triggerPattern,\n definition.delimiter,\n completePattern,\n ),\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'complete',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(completeRule)\n }\n\n const partialRule = defineInputRule<TriggerPayload>({\n on: partialPattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n // Match starts before insertion. Check if the inserted text itself\n // matches the partial pattern (e.g., inserting `:dog` after `foo:`).\n const insertedMatch = event.textInserted.match(partialPattern)\n\n if (insertedMatch === null || insertedMatch.index !== 0) {\n return false\n }\n\n // Don't match if this is actually a complete pattern\n if (completePattern) {\n const completeMatch = event.textInserted.match(completePattern)\n\n if (\n completeMatch !== null &&\n completeMatch.index === 0 &&\n completeMatch[0] === event.textInserted\n ) {\n return false\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch: {\n ...lastMatch,\n text: event.textInserted,\n targetOffsets: {\n ...lastMatch.targetOffsets,\n anchor: {\n ...lastMatch.targetOffsets.anchor,\n offset: event.textBefore.length,\n },\n },\n },\n extractedKeyword: extractKeyword(\n event.textInserted,\n triggerPattern,\n definition.delimiter,\n ),\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: extractKeyword(\n lastMatch.text,\n triggerPattern,\n definition.delimiter,\n ),\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'partial',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(partialRule)\n\n const triggerRule = defineInputRule<TriggerPayload>({\n on: triggerPattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (event.textInserted !== lastMatch.text) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: '',\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'partial',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(triggerRule)\n\n return rules\n}\n\nfunction createTriggerGuard<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n) {\n return ({\n event,\n snapshot,\n dom,\n }: {\n event: TriggerFoundEvent | KeywordFoundEvent\n snapshot: EditorSnapshot\n dom: Parameters<NonNullable<typeof definition.guard>>[0]['dom']\n }): true | false => {\n if (event.pickerId !== definition._id) {\n return false\n }\n\n if (!definition.guard) {\n return true\n }\n\n return definition.guard({\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead trigger found',\n },\n })\n }\n}\n\nconst triggerListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor; definition: TypeaheadPickerDefinition<TMatch>}\n> => {\n return ({sendBack, input}) => {\n const rules = createInputRules(input.definition)\n const triggerGuard = createTriggerGuard(input.definition)\n\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineInputRuleBehavior({rules}),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<KeywordFoundEvent, KeywordFoundEvent['type']>({\n on: 'custom.typeahead keyword found',\n guard: triggerGuard,\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<TriggerFoundEvent, TriggerFoundEvent['type']>({\n on: 'custom.typeahead trigger found',\n guard: triggerGuard,\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst escapeListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor}\n> => {\n return ({sendBack, input}) => {\n return input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => escapeShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n }\n}\n\nconst arrowListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor}\n> => {\n return ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowDownShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate down'})\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowUpShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate up'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst selectionListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor}\n> => {\n return ({sendBack, input}) => {\n const subscription = input.editor.on('selection', () => {\n sendBack({type: 'selection changed'})\n })\n\n return subscription.unsubscribe\n }\n}\n\nconst submitListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n const unregisterBehaviors = [\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => {\n if (\n !enterShortcut.guard(event.originEvent) &&\n !tabShortcut.guard(event.originEvent)\n ) {\n return false\n }\n\n const focusSpan = context.focusSpan\n const match = context.matches[context.selectedIndex]\n\n return match && focusSpan ? {focusSpan, match} : false\n },\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'select'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.patternText.length === 1,\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.patternText.length > 1 &&\n context.matches.length === 0,\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst textInsertionListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'insert.text',\n guard: ({snapshot}) => {\n if (!context.focusSpan) {\n return false\n }\n\n if (!snapshot.context.selection) {\n return false\n }\n\n const keywordAnchor = {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n\n return isEqualSelectionPoints(\n snapshot.context.selection.focus,\n keywordAnchor,\n )\n },\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n }\n}\n\ntype InsertMatchEvent<TMatch extends object> = {\n type: 'custom.typeahead insert match'\n match: TMatch\n focusSpan: FocusSpanData\n keyword: string\n pickerId: symbol\n}\n\nconst selectMatchListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input}) => {\n return input.context.editor.registerBehavior({\n behavior: defineBehavior<InsertMatchEvent<TMatch>>({\n on: 'custom.typeahead select match',\n guard: ({event}) => event.pickerId === input.context.definition._id,\n actions: [\n ({event, snapshot, dom}) => {\n const patternSelection = {\n anchor: {\n path: event.focusSpan.path,\n offset: event.focusSpan.textBefore.length,\n },\n focus: {\n path: event.focusSpan.path,\n offset:\n event.focusSpan.node.text.length -\n event.focusSpan.textAfter.length,\n },\n }\n\n const allActions: Array<BehaviorAction> = [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ]\n\n for (const actionSet of input.context.definition.actions) {\n const actions = actionSet(\n {\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead select',\n match: event.match,\n keyword: event.keyword,\n patternSelection,\n },\n },\n true,\n )\n\n for (const action of actions) {\n allActions.push(action)\n }\n }\n\n return allActions\n },\n ],\n }),\n })\n }\n}\n\nexport function createTypeaheadPickerMachine<TMatch extends object>() {\n return setup({\n types: {\n context: {} as TypeaheadPickerMachineContext<TMatch>,\n input: {} as {\n editor: Editor\n definition: TypeaheadPickerDefinition<TMatch>\n },\n events: {} as TypeaheadPickerMachineEvent<TMatch>,\n },\n delays: {\n DEBOUNCE: ({context}) => context.definition.debounceMs ?? 0,\n },\n actors: {\n 'trigger listener': fromCallback(triggerListenerCallback<TMatch>()),\n 'escape listener': fromCallback(escapeListenerCallback<TMatch>()),\n 'arrow listener': fromCallback(arrowListenerCallback<TMatch>()),\n 'selection listener': fromCallback(selectionListenerCallback<TMatch>()),\n 'submit listener': fromCallback(submitListenerCallback<TMatch>()),\n 'text insertion listener': fromCallback(\n textInsertionListenerCallback<TMatch>(),\n ),\n 'select match listener': fromCallback(\n selectMatchListenerCallback<TMatch>(),\n ),\n 'get matches': fromPromise(\n async ({\n input,\n }: {\n input: {\n keyword: string\n getMatches: TypeaheadPickerDefinition<TMatch>['getMatches']\n }\n }) => {\n const result = input.getMatches({keyword: input.keyword})\n const matches = await Promise.resolve(result)\n return {keyword: input.keyword, matches}\n },\n ),\n },\n actions: {\n 'handle trigger found': assign(({context, event}) => {\n if (\n event.type !== 'custom.typeahead trigger found' &&\n event.type !== 'custom.typeahead keyword found'\n ) {\n return {}\n }\n\n const focusSpan = event.focusSpan\n const patternText = extractPatternTextFromFocusSpan(focusSpan)\n const keyword = event.extractedKeyword\n\n if (\n context.definition.mode === 'async' ||\n context.definition.debounceMs\n ) {\n return {\n focusSpan,\n patternText,\n keyword,\n isLoading: true,\n selectedIndex: 0,\n }\n }\n\n const matches = context.definition.getMatches({\n keyword,\n }) as Array<TMatch>\n\n return {\n focusSpan,\n patternText,\n keyword,\n matches,\n requestedKeyword: keyword,\n isLoading: false,\n selectedIndex: 0,\n }\n }),\n 'update focus span': assign({\n focusSpan: ({context}) => {\n if (!context.focusSpan) {\n return context.focusSpan\n }\n\n const snapshot = context.editor.getSnapshot()\n const focusSpan = getFocusSpan(snapshot)\n\n if (!snapshot.context.selection || !focusSpan) {\n return undefined\n }\n\n const nextSpan = getNextSpan({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: {path: context.focusSpan.path, offset: 0},\n focus: {path: context.focusSpan.path, offset: 0},\n },\n },\n })\n\n if (!isEqualPaths(focusSpan.path, context.focusSpan.path)) {\n if (\n nextSpan &&\n context.focusSpan.textAfter.length === 0 &&\n snapshot.context.selection.focus.offset === 0 &&\n isSelectionCollapsed(snapshot)\n ) {\n // This is an edge case where the caret is moved from the end of\n // the focus span to the start of the next span.\n return context.focusSpan\n }\n\n return undefined\n }\n\n if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore)) {\n return undefined\n }\n\n if (!focusSpan.node.text.endsWith(context.focusSpan.textAfter)) {\n return undefined\n }\n\n const keywordAnchor = {\n path: focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n const keywordFocus = {\n path: focusSpan.path,\n offset:\n focusSpan.node.text.length - context.focusSpan.textAfter.length,\n }\n\n const selectionIsBeforeKeyword =\n isPointAfterSelection(keywordAnchor)(snapshot)\n const selectionIsAfterKeyword =\n isPointBeforeSelection(keywordFocus)(snapshot)\n\n if (selectionIsBeforeKeyword || selectionIsAfterKeyword) {\n return undefined\n }\n\n return {\n node: focusSpan.node,\n path: focusSpan.path,\n textBefore: context.focusSpan.textBefore,\n textAfter: context.focusSpan.textAfter,\n }\n },\n }),\n 'update pattern text': assign(({context}) => {\n if (!context.focusSpan) {\n return {}\n }\n\n const patternText = extractPatternTextFromFocusSpan(context.focusSpan)\n\n if (patternText === context.patternText) {\n return {}\n }\n\n return {patternText, selectedIndex: 0}\n }),\n 'update keyword': assign(({context}) => {\n if (!context.focusSpan || !context.patternText) {\n return {}\n }\n\n const keyword = extractKeyword(\n context.patternText,\n context.triggerPattern,\n context.definition.delimiter,\n context.completePattern,\n )\n\n if (keyword === context.keyword) {\n return {}\n }\n\n return {keyword}\n }),\n 'update matches': assign(({context}) => {\n if (!context.focusSpan || !context.patternText) {\n return {}\n }\n\n if (\n context.definition.mode === 'async' ||\n context.definition.debounceMs\n ) {\n return {\n isLoading:\n context.isLoading || context.requestedKeyword !== context.keyword,\n }\n }\n\n const matches = context.definition.getMatches({\n keyword: context.keyword,\n }) as Array<TMatch>\n\n return {\n matches,\n requestedKeyword: context.keyword,\n isLoading: false,\n }\n }),\n 'handle async load complete': assign(({context, event}) => {\n const output = (\n event as unknown as {\n output: {keyword: string; matches: ReadonlyArray<TMatch>}\n }\n ).output\n\n if (output.keyword !== context.keyword) {\n return {isLoading: context.keyword !== context.requestedKeyword}\n }\n\n return {\n matches: output.matches,\n isLoading: context.keyword !== context.requestedKeyword,\n }\n }),\n 'reset': assign({\n patternText: '',\n keyword: '',\n matches: [],\n selectedIndex: 0,\n isLoading: false,\n requestedKeyword: '',\n focusSpan: undefined,\n error: undefined,\n }),\n 'navigate': assign(({context, event}) => {\n if (context.matches.length === 0) {\n return {selectedIndex: 0}\n }\n\n if (event.type === 'navigate to') {\n return {selectedIndex: event.index}\n }\n\n if (event.type === 'navigate up') {\n return {\n selectedIndex:\n (context.selectedIndex - 1 + context.matches.length) %\n context.matches.length,\n }\n }\n\n return {\n selectedIndex: (context.selectedIndex + 1) % context.matches.length,\n }\n }),\n 'select match': ({context}, params: {exact?: boolean}) => {\n if (!context.focusSpan) {\n return\n }\n\n const match = params.exact\n ? getFirstExactMatch(context.matches)\n : context.matches[context.selectedIndex]\n\n if (!match) {\n return\n }\n\n context.editor.send({\n type: 'custom.typeahead select match',\n match,\n focusSpan: context.focusSpan,\n keyword: context.keyword,\n pickerId: context.definition._id,\n })\n },\n 'update submit listener context': sendTo(\n 'submit listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'update text insertion listener context': sendTo(\n 'text insertion listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'handle error': assign({\n isLoading: false,\n error: ({event}) => (event as {error: Error}).error,\n }),\n },\n guards: {\n 'no focus span': ({context}) => !context.focusSpan,\n 'invalid pattern': ({context}) => {\n if (!context.patternText) {\n return true\n }\n\n // Check if trigger pattern matches entire text (just the trigger, no keyword yet)\n const triggerMatch = context.patternText.match(context.triggerPattern)\n\n if (\n triggerMatch &&\n triggerMatch.index === 0 &&\n triggerMatch[0] === context.patternText\n ) {\n return false\n }\n\n // Check partial pattern matches entire text\n const partialMatch = context.patternText.match(context.partialPattern)\n\n if (\n partialMatch &&\n partialMatch.index === 0 &&\n partialMatch[0] === context.patternText\n ) {\n return false\n }\n\n // Check complete pattern matches entire text (if configured)\n if (context.completePattern) {\n const completeMatch = context.patternText.match(\n context.completePattern,\n )\n\n if (\n completeMatch &&\n completeMatch.index === 0 &&\n completeMatch[0] === context.patternText\n ) {\n return false\n }\n }\n\n return true\n },\n 'no debounce': ({context}) =>\n !context.definition.debounceMs || context.definition.debounceMs === 0,\n 'is complete keyword': ({context}) => {\n if (!context.completePattern || !context.focusSpan) {\n return false\n }\n\n const fullKeywordText = context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n context.focusSpan.textAfter.length > 0\n ? -context.focusSpan.textAfter.length\n : undefined,\n )\n const completeMatch = fullKeywordText.match(context.completePattern)\n\n if (\n !completeMatch ||\n completeMatch.index !== 0 ||\n completeMatch[0] !== fullKeywordText\n ) {\n return false\n }\n\n return hasAtLeastOneExactMatch(context.matches)\n },\n 'has matches': ({context}) => context.matches.length > 0,\n 'no matches': ({context}) => context.matches.length === 0,\n 'is loading': ({context}) => context.isLoading,\n },\n }).createMachine({\n id: 'typeahead picker',\n context: ({input}) => ({\n editor: input.editor,\n definition: input.definition,\n triggerPattern: buildTriggerPattern(input.definition),\n partialPattern: buildPartialPattern(input.definition),\n completePattern: buildCompletePattern(input.definition),\n matches: [],\n selectedIndex: 0,\n focusSpan: undefined,\n patternText: '',\n keyword: '',\n requestedKeyword: '',\n error: undefined,\n isLoading: false,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n entry: ['reset'],\n invoke: {\n src: 'trigger listener',\n input: ({context}) => ({\n editor: context.editor,\n definition: context.definition,\n }),\n },\n on: {\n 'custom.typeahead trigger found': {\n target: 'active',\n actions: ['handle trigger found'],\n },\n 'custom.typeahead keyword found': {\n target: 'checking complete',\n actions: ['handle trigger found'],\n },\n },\n },\n 'checking complete': {\n invoke: [\n {\n src: 'select match listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: [\n {\n guard: ({event}) =>\n hasAtLeastOneExactMatch(event.output.matches),\n target: 'idle',\n actions: [\n assign({matches: ({event}) => event.output.matches}),\n {type: 'select match', params: {exact: true}},\n ],\n },\n {\n target: 'active',\n actions: [assign({matches: ({event}) => event.output.matches})],\n },\n ],\n onError: {\n target: 'active.no matches',\n actions: ['handle error'],\n },\n },\n ],\n },\n 'active': {\n invoke: [\n {\n src: 'select match listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'escape listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'submit listener',\n id: 'submit listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'text insertion listener',\n id: 'text insertion listener',\n input: ({context}) => ({context}),\n },\n ],\n on: {\n 'dismiss': {\n target: 'idle',\n },\n 'selection changed': {\n actions: [\n 'update focus span',\n 'update pattern text',\n 'update keyword',\n 'update matches',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n },\n always: [\n {\n guard: 'no focus span',\n target: 'idle',\n },\n {\n guard: 'invalid pattern',\n target: 'idle',\n },\n {\n guard: 'is complete keyword',\n actions: [{type: 'select match', params: {exact: false}}],\n target: 'idle',\n },\n ],\n initial: 'evaluating',\n states: {\n 'evaluating': {\n always: [\n {\n guard: 'is loading',\n target: 'loading',\n },\n {\n guard: 'has matches',\n target: 'showing matches',\n },\n {\n target: 'no matches',\n },\n ],\n },\n 'loading': {\n entry: [assign({requestedKeyword: ({context}) => context.keyword})],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.evaluating',\n actions: [\n assign(({context, event}) => {\n if (event.output.keyword !== context.keyword) {\n return {\n isLoading:\n context.patternText !== context.requestedKeyword,\n }\n }\n\n return {\n matches: event.output.matches,\n isLoading:\n context.keyword !== context.requestedKeyword,\n }\n }),\n ],\n },\n onError: {\n target: '#typeahead picker.active.no matches',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n 'no matches': {\n entry: [assign({selectedIndex: 0})],\n always: [\n {\n guard: 'has matches',\n target: 'showing matches',\n },\n ],\n initial: 'idle',\n states: {\n idle: {\n always: [{guard: 'is loading', target: 'loading'}],\n },\n loading: {\n entry: [\n assign({\n requestedKeyword: ({context}) => context.keyword,\n }),\n ],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.no matches.idle',\n actions: ['handle async load complete'],\n },\n onError: {\n target: '#typeahead picker.active.no matches.idle',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n },\n },\n 'showing matches': {\n entry: [\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n invoke: {\n src: 'arrow listener',\n input: ({context}) => ({editor: context.editor}),\n },\n always: [\n {\n guard: 'no matches',\n target: 'no matches',\n },\n ],\n on: {\n 'navigate down': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'navigate up': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'navigate to': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'select': {\n target: '#typeahead picker.idle',\n actions: [{type: 'select match', params: {exact: false}}],\n },\n },\n initial: 'idle',\n states: {\n idle: {\n always: [{guard: 'is loading', target: 'loading'}],\n },\n loading: {\n entry: [\n assign({\n requestedKeyword: ({context}) => context.keyword,\n }),\n ],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.showing matches.idle',\n actions: ['handle async load complete'],\n },\n onError: {\n target: '#typeahead picker.active.showing matches.idle',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n })\n}\n\n/**\n * Check if matches contain at least one exact match.\n */\nfunction hasAtLeastOneExactMatch<TMatch extends object>(\n matches: ReadonlyArray<TMatch>,\n): boolean {\n return matches.some(\n (match) =>\n (match as unknown as AutoCompleteMatch | undefined)?.type === 'exact',\n )\n}\n\n/**\n * Get the first exact match from matches.\n */\nfunction getFirstExactMatch<TMatch extends object>(\n matches: ReadonlyArray<TMatch>,\n): TMatch | undefined {\n return matches.find(\n (match) =>\n (match as unknown as AutoCompleteMatch | undefined)?.type === 'exact',\n )\n}\n","import {useEditor} from '@portabletext/editor'\nimport {useActor} from '@xstate/react'\nimport {createTypeaheadPickerMachine} from './typeahead-picker-machine'\nimport type {\n TypeaheadPicker,\n TypeaheadPickerDefinition,\n TypeaheadPickerEvent,\n TypeaheadPickerState,\n} from './typeahead-picker.types'\n\n/**\n * React hook that activates a typeahead picker and returns its current state.\n *\n * Call inside a component rendered within an `EditorProvider`.\n * The picker automatically monitors the editor for trigger patterns.\n *\n * @example\n * ```tsx\n * function MentionPickerUI() {\n * const picker = useTypeaheadPicker(mentionPickerDefinition)\n *\n * if (picker.snapshot.matches('idle')) return null\n * if (picker.snapshot.matches({active: 'loading'})) return <Spinner />\n * if (picker.snapshot.matches({active: 'no matches'})) return <NoResults />\n *\n * const {matches, selectedIndex} = picker.snapshot.context\n *\n * return (\n * <ul>\n * {matches.map((match, index) => (\n * <li\n * key={match.key}\n * aria-selected={index === selectedIndex}\n * onMouseEnter={() => picker.send({type: 'navigate to', index})}\n * onClick={() => picker.send({type: 'select'})}\n * >\n * {match.name}\n * </li>\n * ))}\n * </ul>\n * )\n * }\n * ```\n *\n * @public\n */\nexport function useTypeaheadPicker<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): TypeaheadPicker<TMatch> {\n const editor = useEditor()\n const [actorSnapshot, send] = useActor(\n createTypeaheadPickerMachine<TMatch>(),\n {\n input: {\n editor,\n definition,\n },\n },\n )\n\n return {\n snapshot: {\n matches: (state: TypeaheadPickerState) => actorSnapshot.matches(state),\n context: {\n keyword: actorSnapshot.context.keyword,\n matches: actorSnapshot.context.matches as ReadonlyArray<TMatch>,\n selectedIndex: actorSnapshot.context.selectedIndex,\n error: actorSnapshot.context.error,\n },\n },\n send: (event: TypeaheadPickerEvent) => {\n send(event)\n },\n }\n}\n"],"names":["defineTypeaheadPicker","config","_id","extractKeyword","patternText","triggerPattern","delimiter","completePattern","triggerMatch","match","index","keyword","slice","length","endsWith","completeMatch","escapeRegExp","str","replace","buildTriggerPattern","definition","RegExp","trigger","source","buildPartialPattern","buildCompletePattern","escapedDelimiter","arrowUpShortcut","createKeyboardShortcut","default","key","arrowDownShortcut","enterShortcut","tabShortcut","escapeShortcut","getTriggerState","snapshot","focusSpan","getFocusSpan","markState","getMarkState","context","selection","focusSpanTextBefore","node","text","focus","offset","focusSpanTextAfter","previousSpan","getPreviousSpan","nextSpan","getNextSpan","createTriggerActions","payload","keywordState","pickerId","state","textBeforeMatch","lastMatch","targetOffsets","anchor","_key","_type","marks","path","textBefore","textAfter","raise","createKeywordFoundEvent","extractedKeyword","createTriggerFoundEvent","newSpan","keyGenerator","JSON","stringify","type","at","child","extractPatternTextFromFocusSpan","createInputRules","rules","partialPattern","completeRule","defineInputRule","on","guard","event","matches","undefined","insertedMatch","textInserted","triggerState","actions","push","partialRule","triggerRule","createTriggerGuard","dom","triggerListenerCallback","sendBack","input","triggerGuard","unregisterBehaviors","editor","registerBehavior","behavior","defineInputRuleBehavior","defineBehavior","effect","unregister","escapeListenerCallback","originEvent","arrowListenerCallback","selectionListenerCallback","unsubscribe","submitListenerCallback","receive","selectedIndex","forward","textInsertionListenerCallback","keywordAnchor","isEqualSelectionPoints","selectMatchListenerCallback","patternSelection","allActions","actionSet","action","createTypeaheadPickerMachine","setup","types","events","delays","DEBOUNCE","debounceMs","actors","fromCallback","fromPromise","result","getMatches","Promise","resolve","assign","mode","isLoading","requestedKeyword","getSnapshot","isEqualPaths","isSelectionCollapsed","startsWith","keywordFocus","selectionIsBeforeKeyword","isPointAfterSelection","selectionIsAfterKeyword","isPointBeforeSelection","output","error","select match","params","exact","getFirstExactMatch","send","sendTo","guards","no focus span","invalid pattern","partialMatch","no debounce","is complete keyword","fullKeywordText","hasAtLeastOneExactMatch","has matches","no matches","is loading","createMachine","id","initial","states","entry","invoke","src","target","onDone","onError","always","debouncing","after","fetching","idle","loading","some","find","useTypeaheadPicker","$","_c","useEditor","t0","Symbol","for","t1","actorSnapshot","useActor","t2","t3","t4","t5","t6","t7"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/define-typeahead-picker.ts","../src/extract-keyword.ts","../src/typeahead-picker-machine.tsx","../src/use-typeahead-picker.ts"],"sourcesContent":["import type {\n AutoCompleteMatch,\n TypeaheadDismissActionSet,\n TypeaheadPickerDefinition,\n TypeaheadSelectActionSet,\n TypeaheadTriggerGuard,\n} from './typeahead-picker.types'\n\ntype BaseConfigWithoutDelimiter<TMatch extends object> = {\n /**\n * Pattern that activates the picker. Must be a single character.\n * Can include `^` for start-of-block triggers.\n *\n * @example `/:/` - activates on colon\n * @example `/@/` - activates on at-sign\n * @example `/^\\//` - activates on slash at start of block\n */\n trigger: RegExp\n /**\n * Pattern matching the keyword portion after the trigger.\n * The entire match becomes the keyword passed to `getMatches`.\n * Common patterns: non-whitespace (`\\S*`) or word characters (`\\w*`).\n */\n keyword: RegExp\n delimiter?: undefined\n /**\n * Guard function that runs at trigger time to conditionally prevent activation.\n * Return `false` to block activation, or `true` to allow it.\n */\n guard?: TypeaheadTriggerGuard\n /**\n * Called when a match is selected.\n * Returns behavior actions to execute (e.g., delete trigger text, insert content).\n */\n onSelect: TypeaheadSelectActionSet<TMatch>[]\n /**\n * Called when the picker is dismissed.\n * Returns behavior actions to execute (optional cleanup).\n */\n onDismiss?: TypeaheadDismissActionSet[]\n}\n\ntype BaseConfigWithDelimiter<TMatch extends AutoCompleteMatch> = {\n /**\n * Pattern that activates the picker. Must be a single character.\n * Can include `^` for start-of-block triggers.\n *\n * @example `/:/` - activates on colon\n * @example `/@/` - activates on at-sign\n * @example `/^\\//` - activates on slash at start of block\n */\n trigger: RegExp\n /**\n * Pattern matching the keyword portion after the trigger.\n * The entire match becomes the keyword passed to `getMatches`.\n * Common patterns: non-whitespace (`\\S*`) or word characters (`\\w*`).\n */\n keyword: RegExp\n /**\n * Character that triggers auto-completion.\n * Typing this after a keyword with an exact match auto-inserts it.\n *\n * @example `':'` - typing `:joy:` auto-inserts the joy emoji\n */\n delimiter: string\n /**\n * Guard function that runs at trigger time to conditionally prevent activation.\n * Return `false` to block activation, or `true` to allow it.\n */\n guard?: TypeaheadTriggerGuard\n /**\n * Called when a match is selected.\n * Returns behavior actions to execute (e.g., delete trigger text, insert content).\n */\n onSelect: TypeaheadSelectActionSet<TMatch>[]\n /**\n * Called when the picker is dismissed.\n * Returns behavior actions to execute (optional cleanup).\n */\n onDismiss?: TypeaheadDismissActionSet[]\n}\n\ntype SyncConfigWithoutDelimiter<TMatch extends object> =\n BaseConfigWithoutDelimiter<TMatch> & {\n /**\n * Whether `getMatches` returns synchronously or asynchronously.\n * @defaultValue `'sync'`\n */\n mode?: 'sync'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Useful for expensive local searches.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => ReadonlyArray<TMatch>\n }\n\ntype SyncConfigWithDelimiter<TMatch extends AutoCompleteMatch> =\n BaseConfigWithDelimiter<TMatch> & {\n /**\n * Whether `getMatches` returns synchronously or asynchronously.\n * @defaultValue `'sync'`\n */\n mode?: 'sync'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Useful for expensive local searches.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => ReadonlyArray<TMatch>\n }\n\ntype AsyncConfigWithoutDelimiter<TMatch extends object> =\n BaseConfigWithoutDelimiter<TMatch> & {\n /**\n * Set to `'async'` when `getMatches` returns a Promise.\n */\n mode: 'async'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Recommended for API calls to reduce request frequency.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Async function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => Promise<ReadonlyArray<TMatch>>\n }\n\ntype AsyncConfigWithDelimiter<TMatch extends AutoCompleteMatch> =\n BaseConfigWithDelimiter<TMatch> & {\n /**\n * Set to `'async'` when `getMatches` returns a Promise.\n */\n mode: 'async'\n /**\n * Debounce delay in milliseconds before calling `getMatches`.\n * Recommended for API calls to reduce request frequency.\n * @defaultValue `0` (no debounce)\n */\n debounceMs?: number\n /**\n * Async function that returns matches for the current keyword.\n * Called whenever the keyword changes (after debounce if configured).\n */\n getMatches: (context: {keyword: string}) => Promise<ReadonlyArray<TMatch>>\n }\n\n/**\n * Creates a typeahead picker definition to use with {@link useTypeaheadPicker}.\n *\n * @example Emoji picker with auto-complete\n * ```ts\n * const emojiPicker = defineTypeaheadPicker({\n * trigger: /:/,\n * keyword: /[\\S]+/,\n * delimiter: ':',\n * getMatches: ({keyword}) => searchEmojis(keyword),\n * onSelect: [\n * ({event}) => [\n * raise({type: 'delete', at: event.patternSelection}),\n * raise({type: 'insert.text', text: event.match.emoji}),\n * ],\n * ],\n * })\n * ```\n *\n * @example Async mention picker\n * ```ts\n * const mentionPicker = defineTypeaheadPicker({\n * mode: 'async',\n * trigger: /@/,\n * keyword: /[\\w]+/,\n * debounceMs: 200,\n * getMatches: async ({keyword}) => api.searchUsers(keyword),\n * onSelect: [\n * ({event}) => [\n * raise({type: 'delete', at: event.patternSelection}),\n * raise({type: 'insert.inline object', inlineObject: {_type: 'mention', userId: event.match.id}}),\n * ],\n * ],\n * })\n * ```\n *\n * @example Picker with guard (runs at trigger time)\n * ```ts\n * const emojiPicker = defineTypeaheadPicker({\n * trigger: /:/,\n * keyword: /[\\S]+/,\n * getMatches: ({keyword}) => searchEmojis(keyword),\n * guard: ({snapshot, event, dom}) => {\n * if (anotherPickerIsOpen()) return false\n * return true\n * },\n * onSelect: [\n * ({event}) => [\n * raise({type: 'delete', at: event.patternSelection}),\n * raise({type: 'insert.text', text: event.match.emoji}),\n * ],\n * ],\n * })\n * ```\n *\n * @public\n */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config: SyncConfigWithoutDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends AutoCompleteMatch>(\n config: SyncConfigWithDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config: AsyncConfigWithoutDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends AutoCompleteMatch>(\n config: AsyncConfigWithDelimiter<TMatch>,\n): TypeaheadPickerDefinition<TMatch>\n/** @public */\nexport function defineTypeaheadPicker<TMatch extends object>(\n config:\n | SyncConfigWithoutDelimiter<TMatch>\n | SyncConfigWithDelimiter<TMatch & AutoCompleteMatch>\n | AsyncConfigWithoutDelimiter<TMatch>\n | AsyncConfigWithDelimiter<TMatch & AutoCompleteMatch>,\n): TypeaheadPickerDefinition<TMatch> {\n return {\n ...config,\n _id: Symbol('typeahead-picker'),\n } as TypeaheadPickerDefinition<TMatch>\n}\n","/**\n * Extract keyword from pattern text using the trigger pattern.\n * Removes the trigger match from the start and delimiter from the end.\n *\n * @param patternText - The full pattern text (e.g., `:joy:` or `:joy`)\n * @param triggerPattern - Pattern matching the trigger (e.g., /:/)\n * @param delimiter - Optional delimiter character (e.g., `:`)\n * @param completePattern - Optional complete pattern to detect if this is a complete match\n */\nexport function extractKeyword(\n patternText: string,\n triggerPattern: RegExp,\n delimiter?: string,\n completePattern?: RegExp,\n): string {\n const triggerMatch = patternText.match(triggerPattern)\n\n if (!triggerMatch || triggerMatch.index !== 0) {\n return patternText\n }\n\n let keyword = patternText.slice(triggerMatch[0].length)\n\n if (delimiter && keyword.endsWith(delimiter)) {\n // Check if this is a complete match (pattern matches the complete pattern exactly)\n const isCompleteMatch =\n completePattern &&\n (() => {\n const completeMatch = patternText.match(completePattern)\n return (\n completeMatch &&\n completeMatch.index === 0 &&\n completeMatch[0] === patternText\n )\n })()\n\n // Strip delimiter if:\n // - This is a complete match (even if keyword becomes empty), OR\n // - Keyword would remain non-empty after stripping\n if (isCompleteMatch || keyword.length > delimiter.length) {\n keyword = keyword.slice(0, -delimiter.length)\n }\n }\n\n return keyword\n}\n","import type {\n ChildPath,\n Editor,\n EditorSelector,\n EditorSnapshot,\n PortableTextSpan,\n} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n} from '@portabletext/editor/behaviors'\nimport {\n getFocusSpan,\n getMarkState,\n getNextSpan,\n getPreviousSpan,\n isPointAfterSelection,\n isPointBeforeSelection,\n isSelectionCollapsed,\n type MarkState,\n} from '@portabletext/editor/selectors'\nimport {isEqualPaths, isEqualSelectionPoints} from '@portabletext/editor/utils'\nimport {createKeyboardShortcut} from '@portabletext/keyboard-shortcuts'\nimport {\n defineInputRule,\n defineInputRuleBehavior,\n type InputRuleMatch,\n} from '@portabletext/plugin-input-rule'\nimport {\n assign,\n fromCallback,\n fromPromise,\n sendTo,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {extractKeyword} from './extract-keyword'\nimport type {\n AutoCompleteMatch,\n TypeaheadPickerDefinition,\n} from './typeahead-picker.types'\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/**\n * Build the trigger pattern from the definition.\n */\nfunction buildTriggerPattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp {\n return new RegExp(definition.trigger.source)\n}\n\n/**\n * Build the partial pattern (trigger + keyword) from the definition.\n */\nfunction buildPartialPattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp {\n return new RegExp(definition.trigger.source + definition.keyword.source)\n}\n\n/**\n * Build the complete pattern (trigger + keyword + delimiter) from the definition.\n */\nfunction buildCompletePattern<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): RegExp | undefined {\n if (!definition.delimiter) {\n return undefined\n }\n\n const escapedDelimiter = escapeRegExp(definition.delimiter)\n return new RegExp(\n definition.trigger.source + definition.keyword.source + escapedDelimiter,\n )\n}\n\nconst arrowUpShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowUp'}],\n})\nconst arrowDownShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowDown'}],\n})\nconst enterShortcut = createKeyboardShortcut({\n default: [{key: 'Enter'}],\n})\nconst tabShortcut = createKeyboardShortcut({\n default: [{key: 'Tab'}],\n})\nconst escapeShortcut = createKeyboardShortcut({\n default: [{key: 'Escape'}],\n})\n\nconst getTriggerState: EditorSelector<\n | {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n }\n markState: MarkState\n focusSpanTextBefore: string\n focusSpanTextAfter: string\n previousSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n nextSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n }\n | undefined\n> = (snapshot) => {\n const focusSpan = getFocusSpan(snapshot)\n const markState = getMarkState(snapshot)\n\n if (!focusSpan || !markState || !snapshot.context.selection) {\n return undefined\n }\n\n const focusSpanTextBefore = focusSpan.node.text.slice(\n 0,\n snapshot.context.selection.focus.offset,\n )\n const focusSpanTextAfter = focusSpan.node.text.slice(\n snapshot.context.selection.focus.offset,\n )\n const previousSpan = getPreviousSpan(snapshot)\n const nextSpan = getNextSpan(snapshot)\n\n return {\n focusSpan,\n markState,\n focusSpanTextBefore,\n focusSpanTextAfter,\n previousSpan,\n nextSpan,\n }\n}\n\ntype FocusSpanData = {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n}\n\nfunction createTriggerActions({\n snapshot,\n payload,\n keywordState,\n pickerId,\n}: {\n snapshot: EditorSnapshot\n payload: TriggerPayload\n keywordState: 'partial' | 'complete'\n pickerId: symbol\n}) {\n if (payload.markState.state === 'unchanged') {\n const textBeforeMatch = payload.focusSpanTextBefore.slice(\n 0,\n payload.lastMatch.targetOffsets.anchor.offset,\n )\n const focusSpan = {\n node: {\n _key: payload.focusSpan.node._key,\n _type: payload.focusSpan.node._type,\n text: `${textBeforeMatch}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: payload.focusSpan.path,\n textBefore: textBeforeMatch,\n textAfter: payload.focusSpanTextAfter,\n }\n\n if (keywordState === 'complete') {\n return [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n }\n\n return [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n }\n\n const newSpan = {\n _key: snapshot.context.keyGenerator(),\n _type: payload.focusSpan.node._type,\n text: payload.lastMatch.text,\n marks: payload.markState.marks,\n }\n\n let focusSpan: FocusSpanData = {\n node: {\n _key: newSpan._key,\n _type: newSpan._type,\n text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: [\n {_key: payload.focusSpan.path[0]._key},\n 'children',\n {_key: newSpan._key},\n ] satisfies ChildPath,\n textBefore: '',\n textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter,\n }\n\n if (\n payload.previousSpan &&\n payload.focusSpanTextBefore.length === 0 &&\n JSON.stringify(payload.previousSpan.node.marks ?? []) ===\n JSON.stringify(payload.markState.marks)\n ) {\n focusSpan = {\n node: {\n _key: payload.previousSpan.node._key,\n _type: newSpan._type,\n text: `${payload.previousSpan.node.text}${newSpan.text}`,\n marks: newSpan.marks,\n },\n path: payload.previousSpan.path,\n textBefore: payload.previousSpan.node.text,\n textAfter: '',\n }\n }\n\n return [\n raise({type: 'select', at: payload.lastMatch.targetOffsets}),\n raise({type: 'delete', at: payload.lastMatch.targetOffsets}),\n raise({type: 'insert.child', child: newSpan}),\n ...(keywordState === 'complete'\n ? [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]\n : [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n extractedKeyword: payload.extractedKeyword,\n pickerId,\n }),\n ),\n ]),\n ]\n}\n\ntype TriggerFoundEvent = {\n type: 'custom.typeahead trigger found'\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}\n\nfunction createTriggerFoundEvent(payload: {\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}): TriggerFoundEvent {\n return {\n type: 'custom.typeahead trigger found',\n ...payload,\n }\n}\n\ntype KeywordFoundEvent = {\n type: 'custom.typeahead keyword found'\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}\n\nfunction createKeywordFoundEvent(payload: {\n focusSpan: FocusSpanData\n extractedKeyword: string\n pickerId: symbol\n}): KeywordFoundEvent {\n return {\n type: 'custom.typeahead keyword found',\n ...payload,\n }\n}\n\ntype TypeaheadPickerMachineContext<TMatch extends object> = {\n editor: Editor\n definition: TypeaheadPickerDefinition<TMatch>\n triggerPattern: RegExp\n partialPattern: RegExp\n completePattern: RegExp | undefined\n matches: ReadonlyArray<TMatch>\n selectedIndex: number\n focusSpan: FocusSpanData | undefined\n patternText: string\n keyword: string\n requestedKeyword: string\n error: Error | undefined\n isLoading: boolean\n}\n\ntype TypeaheadPickerMachineEvent<TMatch extends object> =\n | TriggerFoundEvent\n | KeywordFoundEvent\n | {type: 'selection changed'}\n | {type: 'close'}\n | {type: 'navigate down'}\n | {type: 'navigate up'}\n | {type: 'navigate to'; index: number}\n | {type: 'select'}\n | {type: 'matches loaded'; matches: ReadonlyArray<TMatch>}\n | {type: 'matches error'; error: Error}\n\ntype TriggerPayload = ReturnType<typeof getTriggerState> & {\n lastMatch: InputRuleMatch\n extractedKeyword: string\n}\n\n/**\n * Extract the pattern text (trigger + keyword) from focus span data.\n */\nfunction extractPatternTextFromFocusSpan(focusSpan: FocusSpanData): string {\n if (focusSpan.textBefore.length > 0 && focusSpan.textAfter.length > 0) {\n return focusSpan.node.text.slice(\n focusSpan.textBefore.length,\n -focusSpan.textAfter.length,\n )\n }\n\n if (focusSpan.textBefore.length > 0) {\n return focusSpan.node.text.slice(focusSpan.textBefore.length)\n }\n\n if (focusSpan.textAfter.length > 0) {\n return focusSpan.node.text.slice(0, -focusSpan.textAfter.length)\n }\n\n return focusSpan.node.text\n}\n\nfunction createInputRules<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n) {\n const rules: Array<ReturnType<typeof defineInputRule<TriggerPayload>>> = []\n\n const triggerPattern = buildTriggerPattern(definition)\n const partialPattern = buildPartialPattern(definition)\n const completePattern = buildCompletePattern(definition)\n\n if (completePattern) {\n const completeRule = defineInputRule<TriggerPayload>({\n on: completePattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n // Match starts before insertion. Check if the inserted text itself\n // matches the complete pattern (e.g., inserting `:dog:` after `foo:`).\n const insertedMatch = event.textInserted.match(completePattern)\n\n if (insertedMatch === null || insertedMatch.index !== 0) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch: {\n ...lastMatch,\n text: event.textInserted,\n targetOffsets: {\n ...lastMatch.targetOffsets,\n anchor: {\n ...lastMatch.targetOffsets.anchor,\n offset: event.textBefore.length,\n },\n },\n },\n extractedKeyword: extractKeyword(\n event.textInserted,\n triggerPattern,\n definition.delimiter,\n completePattern,\n ),\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: extractKeyword(\n lastMatch.text,\n triggerPattern,\n definition.delimiter,\n completePattern,\n ),\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'complete',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(completeRule)\n }\n\n const partialRule = defineInputRule<TriggerPayload>({\n on: partialPattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n // Match starts before insertion. Check if the inserted text itself\n // matches the partial pattern (e.g., inserting `:dog` after `foo:`).\n const insertedMatch = event.textInserted.match(partialPattern)\n\n if (insertedMatch === null || insertedMatch.index !== 0) {\n return false\n }\n\n // Don't match if this is actually a complete pattern\n if (completePattern) {\n const completeMatch = event.textInserted.match(completePattern)\n\n if (\n completeMatch !== null &&\n completeMatch.index === 0 &&\n completeMatch[0] === event.textInserted\n ) {\n return false\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch: {\n ...lastMatch,\n text: event.textInserted,\n targetOffsets: {\n ...lastMatch.targetOffsets,\n anchor: {\n ...lastMatch.targetOffsets.anchor,\n offset: event.textBefore.length,\n },\n },\n },\n extractedKeyword: extractKeyword(\n event.textInserted,\n triggerPattern,\n definition.delimiter,\n ),\n }\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: extractKeyword(\n lastMatch.text,\n triggerPattern,\n definition.delimiter,\n ),\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'partial',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(partialRule)\n\n const triggerRule = defineInputRule<TriggerPayload>({\n on: triggerPattern,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (event.textInserted !== lastMatch.text) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n extractedKeyword: '',\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({\n snapshot,\n payload,\n keywordState: 'partial',\n pickerId: definition._id,\n }),\n ],\n })\n\n rules.push(triggerRule)\n\n return rules\n}\n\nfunction createTriggerGuard<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n) {\n return ({\n event,\n snapshot,\n dom,\n }: {\n event: TriggerFoundEvent | KeywordFoundEvent\n snapshot: EditorSnapshot\n dom: Parameters<NonNullable<typeof definition.guard>>[0]['dom']\n }): true | false => {\n if (event.pickerId !== definition._id) {\n return false\n }\n\n if (!definition.guard) {\n return true\n }\n\n return definition.guard({\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead trigger found',\n },\n })\n }\n}\n\nconst triggerListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor; definition: TypeaheadPickerDefinition<TMatch>}\n> => {\n return ({sendBack, input}) => {\n const rules = createInputRules(input.definition)\n const triggerGuard = createTriggerGuard(input.definition)\n\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineInputRuleBehavior({rules}),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<KeywordFoundEvent, KeywordFoundEvent['type']>({\n on: 'custom.typeahead keyword found',\n guard: triggerGuard,\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<TriggerFoundEvent, TriggerFoundEvent['type']>({\n on: 'custom.typeahead trigger found',\n guard: triggerGuard,\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst escapeListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => escapeShortcut.guard(event.originEvent),\n actions: [\n ({snapshot, dom}) => {\n if (!context.focusSpan || !context.definition.onDismiss) {\n return [effect(() => sendBack({type: 'close'}))]\n }\n\n const patternSelection = {\n anchor: {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n },\n focus: {\n path: context.focusSpan.path,\n offset:\n context.focusSpan.node.text.length -\n context.focusSpan.textAfter.length,\n },\n }\n\n const dismissActions = context.definition.onDismiss.flatMap(\n (actionSet) =>\n actionSet(\n {\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead dismiss',\n patternSelection,\n },\n },\n true,\n ),\n )\n\n return [...dismissActions, effect(() => sendBack({type: 'close'}))]\n },\n ],\n }),\n })\n }\n}\n\nconst arrowListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor}\n> => {\n return ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowDownShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate down'})\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowUpShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate up'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst selectionListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {editor: Editor}\n> => {\n return ({sendBack, input}) => {\n const subscription = input.editor.on('selection', () => {\n sendBack({type: 'selection changed'})\n })\n\n return subscription.unsubscribe\n }\n}\n\ntype DismissEvent = {\n type: 'custom.typeahead dismiss'\n pickerId: symbol\n}\n\nconst dismissListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior<DismissEvent, DismissEvent['type']>({\n on: 'custom.typeahead dismiss',\n guard: ({event}) => event.pickerId === context.definition._id,\n actions: [\n ({snapshot, dom}) => {\n if (!context.focusSpan || !context.definition.onDismiss) {\n return [effect(() => sendBack({type: 'close'}))]\n }\n\n const patternSelection = {\n anchor: {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n },\n focus: {\n path: context.focusSpan.path,\n offset:\n context.focusSpan.node.text.length -\n context.focusSpan.textAfter.length,\n },\n }\n\n const dismissActions = context.definition.onDismiss.flatMap(\n (actionSet) =>\n actionSet(\n {\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead dismiss',\n patternSelection,\n },\n },\n true,\n ),\n )\n\n return [...dismissActions, effect(() => sendBack({type: 'close'}))]\n },\n ],\n }),\n })\n }\n}\n\nconst submitListenerCallback = <TMatch extends object>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n const unregisterBehaviors = [\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => {\n if (\n !enterShortcut.guard(event.originEvent) &&\n !tabShortcut.guard(event.originEvent)\n ) {\n return false\n }\n\n const focusSpan = context.focusSpan\n const match = context.matches[context.selectedIndex]\n\n return match && focusSpan ? {focusSpan, match} : false\n },\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'select'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.patternText.length === 1,\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'close'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.patternText.length > 1 &&\n context.matches.length === 0,\n actions: [\n ({snapshot, dom}) => {\n if (!context.focusSpan || !context.definition.onDismiss) {\n return [effect(() => sendBack({type: 'close'}))]\n }\n\n const patternSelection = {\n anchor: {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n },\n focus: {\n path: context.focusSpan.path,\n offset:\n context.focusSpan.node.text.length -\n context.focusSpan.textAfter.length,\n },\n }\n\n const dismissActions = context.definition.onDismiss.flatMap(\n (actionSet) =>\n actionSet(\n {\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead dismiss',\n patternSelection,\n },\n },\n true,\n ),\n )\n\n return [\n ...dismissActions,\n effect(() => sendBack({type: 'close'})),\n ]\n },\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n }\n}\n\nconst textInsertionListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n {type: 'context changed'; context: TypeaheadPickerMachineContext<TMatch>},\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'insert.text',\n guard: ({snapshot}) => {\n if (!context.focusSpan) {\n return false\n }\n\n if (!snapshot.context.selection) {\n return false\n }\n\n const keywordAnchor = {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n\n return isEqualSelectionPoints(\n snapshot.context.selection.focus,\n keywordAnchor,\n )\n },\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'close'})\n }),\n ],\n ],\n }),\n })\n }\n}\n\ntype InsertMatchEvent<TMatch extends object> = {\n type: 'custom.typeahead insert match'\n match: TMatch\n focusSpan: FocusSpanData\n keyword: string\n pickerId: symbol\n}\n\nconst selectMatchListenerCallback = <\n TMatch extends object,\n>(): CallbackLogicFunction<\n AnyEventObject,\n TypeaheadPickerMachineEvent<TMatch>,\n {context: TypeaheadPickerMachineContext<TMatch>}\n> => {\n return ({sendBack, input}) => {\n return input.context.editor.registerBehavior({\n behavior: defineBehavior<InsertMatchEvent<TMatch>>({\n on: 'custom.typeahead select match',\n guard: ({event}) => event.pickerId === input.context.definition._id,\n actions: [\n ({event, snapshot, dom}) => {\n const patternSelection = {\n anchor: {\n path: event.focusSpan.path,\n offset: event.focusSpan.textBefore.length,\n },\n focus: {\n path: event.focusSpan.path,\n offset:\n event.focusSpan.node.text.length -\n event.focusSpan.textAfter.length,\n },\n }\n\n const selectActions = input.context.definition.onSelect.flatMap(\n (actionSet) =>\n actionSet(\n {\n snapshot,\n dom,\n event: {\n type: 'custom.typeahead select',\n match: event.match,\n keyword: event.keyword,\n patternSelection,\n },\n },\n true,\n ),\n )\n\n return [\n effect(() => {\n sendBack({type: 'close'})\n }),\n ...selectActions,\n ]\n },\n ],\n }),\n })\n }\n}\n\nexport function createTypeaheadPickerMachine<TMatch extends object>() {\n return setup({\n types: {\n context: {} as TypeaheadPickerMachineContext<TMatch>,\n input: {} as {\n editor: Editor\n definition: TypeaheadPickerDefinition<TMatch>\n },\n events: {} as TypeaheadPickerMachineEvent<TMatch>,\n },\n delays: {\n DEBOUNCE: ({context}) => context.definition.debounceMs ?? 0,\n },\n actors: {\n 'trigger listener': fromCallback(triggerListenerCallback<TMatch>()),\n 'escape listener': fromCallback(escapeListenerCallback<TMatch>()),\n 'arrow listener': fromCallback(arrowListenerCallback<TMatch>()),\n 'selection listener': fromCallback(selectionListenerCallback<TMatch>()),\n 'submit listener': fromCallback(submitListenerCallback<TMatch>()),\n 'text insertion listener': fromCallback(\n textInsertionListenerCallback<TMatch>(),\n ),\n 'select match listener': fromCallback(\n selectMatchListenerCallback<TMatch>(),\n ),\n 'dismiss listener': fromCallback(dismissListenerCallback<TMatch>()),\n 'get matches': fromPromise(\n async ({\n input,\n }: {\n input: {\n keyword: string\n getMatches: TypeaheadPickerDefinition<TMatch>['getMatches']\n }\n }) => {\n const result = input.getMatches({keyword: input.keyword})\n const matches = await Promise.resolve(result)\n return {keyword: input.keyword, matches}\n },\n ),\n },\n actions: {\n 'handle trigger found': assign(({context, event}) => {\n if (\n event.type !== 'custom.typeahead trigger found' &&\n event.type !== 'custom.typeahead keyword found'\n ) {\n return {}\n }\n\n const focusSpan = event.focusSpan\n const patternText = extractPatternTextFromFocusSpan(focusSpan)\n const keyword = event.extractedKeyword\n\n if (\n context.definition.mode === 'async' ||\n context.definition.debounceMs\n ) {\n return {\n focusSpan,\n patternText,\n keyword,\n isLoading: true,\n selectedIndex: 0,\n }\n }\n\n const matches = context.definition.getMatches({\n keyword,\n }) as Array<TMatch>\n\n return {\n focusSpan,\n patternText,\n keyword,\n matches,\n requestedKeyword: keyword,\n isLoading: false,\n selectedIndex: 0,\n }\n }),\n 'handle selection changed': assign(({context}) => {\n if (!context.focusSpan) {\n return {focusSpan: undefined}\n }\n\n const snapshot = context.editor.getSnapshot()\n const currentFocusSpan = getFocusSpan(snapshot)\n\n if (!snapshot.context.selection || !currentFocusSpan) {\n return {focusSpan: undefined}\n }\n\n const nextSpan = getNextSpan({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: {path: context.focusSpan.path, offset: 0},\n focus: {path: context.focusSpan.path, offset: 0},\n },\n },\n })\n\n if (!isEqualPaths(currentFocusSpan.path, context.focusSpan.path)) {\n if (\n nextSpan &&\n context.focusSpan.textAfter.length === 0 &&\n snapshot.context.selection.focus.offset === 0 &&\n isSelectionCollapsed(snapshot)\n ) {\n // Edge case: caret moved from end of focus span to start of next span\n return {}\n }\n return {focusSpan: undefined}\n }\n\n if (\n !currentFocusSpan.node.text.startsWith(context.focusSpan.textBefore)\n ) {\n return {focusSpan: undefined}\n }\n\n if (!currentFocusSpan.node.text.endsWith(context.focusSpan.textAfter)) {\n return {focusSpan: undefined}\n }\n\n const keywordAnchor = {\n path: currentFocusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n const keywordFocus = {\n path: currentFocusSpan.path,\n offset:\n currentFocusSpan.node.text.length -\n context.focusSpan.textAfter.length,\n }\n\n const selectionIsBeforeKeyword =\n isPointAfterSelection(keywordAnchor)(snapshot)\n const selectionIsAfterKeyword =\n isPointBeforeSelection(keywordFocus)(snapshot)\n\n if (selectionIsBeforeKeyword || selectionIsAfterKeyword) {\n return {focusSpan: undefined}\n }\n\n const focusSpan = {\n node: currentFocusSpan.node,\n path: currentFocusSpan.path,\n textBefore: context.focusSpan.textBefore,\n textAfter: context.focusSpan.textAfter,\n }\n\n const patternText = extractPatternTextFromFocusSpan(focusSpan)\n\n const keyword = extractKeyword(\n patternText,\n context.triggerPattern,\n context.definition.delimiter,\n context.completePattern,\n )\n\n if (\n context.definition.mode === 'async' ||\n context.definition.debounceMs\n ) {\n return {\n focusSpan,\n patternText,\n keyword,\n selectedIndex:\n patternText !== context.patternText ? 0 : context.selectedIndex,\n isLoading:\n context.isLoading || context.requestedKeyword !== keyword,\n }\n }\n\n const matches = context.definition.getMatches({\n keyword,\n }) as Array<TMatch>\n\n return {\n focusSpan,\n patternText,\n keyword,\n matches,\n requestedKeyword: keyword,\n selectedIndex:\n patternText !== context.patternText ? 0 : context.selectedIndex,\n isLoading: false,\n }\n }),\n 'handle async load complete': assign(({context, event}) => {\n const output = (\n event as unknown as {\n output: {keyword: string; matches: ReadonlyArray<TMatch>}\n }\n ).output\n\n if (output.keyword !== context.keyword) {\n return {isLoading: context.keyword !== context.requestedKeyword}\n }\n\n return {\n matches: output.matches,\n isLoading: context.keyword !== context.requestedKeyword,\n }\n }),\n 'reset': assign({\n patternText: '',\n keyword: '',\n matches: [],\n selectedIndex: 0,\n isLoading: false,\n requestedKeyword: '',\n focusSpan: undefined,\n error: undefined,\n }),\n 'navigate': assign(({context, event}) => {\n if (context.matches.length === 0) {\n return {selectedIndex: 0}\n }\n\n if (event.type === 'navigate to') {\n return {selectedIndex: event.index}\n }\n\n if (event.type === 'navigate up') {\n return {\n selectedIndex:\n (context.selectedIndex - 1 + context.matches.length) %\n context.matches.length,\n }\n }\n\n return {\n selectedIndex: (context.selectedIndex + 1) % context.matches.length,\n }\n }),\n 'select match': ({context}, params: {exact?: boolean}) => {\n if (!context.focusSpan) {\n return\n }\n\n const match = params.exact\n ? getFirstExactMatch(context.matches)\n : context.matches[context.selectedIndex]\n\n if (!match) {\n return\n }\n\n context.editor.send({\n type: 'custom.typeahead select match',\n match,\n focusSpan: context.focusSpan,\n keyword: context.keyword,\n pickerId: context.definition._id,\n })\n },\n 'update submit listener context': sendTo(\n 'submit listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'update text insertion listener context': sendTo(\n 'text insertion listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'update escape listener context': sendTo(\n 'escape listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'update request dismiss listener context': sendTo(\n 'dismiss listener',\n ({context}) => ({type: 'context changed', context}),\n ),\n 'handle error': assign({\n isLoading: false,\n error: ({event}) => (event as {error: Error}).error,\n }),\n },\n guards: {\n 'no focus span': ({context}) => !context.focusSpan,\n 'invalid pattern': ({context}) => {\n if (!context.patternText) {\n return true\n }\n\n // Check if trigger pattern matches entire text (just the trigger, no keyword yet)\n const triggerMatch = context.patternText.match(context.triggerPattern)\n\n if (\n triggerMatch &&\n triggerMatch.index === 0 &&\n triggerMatch[0] === context.patternText\n ) {\n return false\n }\n\n // Check partial pattern matches entire text\n const partialMatch = context.patternText.match(context.partialPattern)\n\n if (\n partialMatch &&\n partialMatch.index === 0 &&\n partialMatch[0] === context.patternText\n ) {\n return false\n }\n\n // Check complete pattern matches entire text (if configured)\n if (context.completePattern) {\n const completeMatch = context.patternText.match(\n context.completePattern,\n )\n\n if (\n completeMatch &&\n completeMatch.index === 0 &&\n completeMatch[0] === context.patternText\n ) {\n return false\n }\n }\n\n return true\n },\n 'no debounce': ({context}) =>\n !context.definition.debounceMs || context.definition.debounceMs === 0,\n 'is complete keyword': ({context}) => {\n if (!context.completePattern || !context.focusSpan) {\n return false\n }\n\n const fullKeywordText = context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n context.focusSpan.textAfter.length > 0\n ? -context.focusSpan.textAfter.length\n : undefined,\n )\n const completeMatch = fullKeywordText.match(context.completePattern)\n\n if (\n !completeMatch ||\n completeMatch.index !== 0 ||\n completeMatch[0] !== fullKeywordText\n ) {\n return false\n }\n\n return hasAtLeastOneExactMatch(context.matches)\n },\n 'has matches': ({context}) => context.matches.length > 0,\n 'no matches': ({context}) => context.matches.length === 0,\n 'is loading': ({context}) => context.isLoading,\n },\n }).createMachine({\n id: 'typeahead picker',\n context: ({input}) => ({\n editor: input.editor,\n definition: input.definition,\n triggerPattern: buildTriggerPattern(input.definition),\n partialPattern: buildPartialPattern(input.definition),\n completePattern: buildCompletePattern(input.definition),\n matches: [],\n selectedIndex: 0,\n focusSpan: undefined,\n patternText: '',\n keyword: '',\n requestedKeyword: '',\n error: undefined,\n isLoading: false,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n entry: ['reset'],\n invoke: {\n src: 'trigger listener',\n input: ({context}) => ({\n editor: context.editor,\n definition: context.definition,\n }),\n },\n on: {\n 'custom.typeahead trigger found': {\n target: 'active',\n actions: ['handle trigger found'],\n },\n 'custom.typeahead keyword found': {\n target: 'checking complete',\n actions: ['handle trigger found'],\n },\n },\n },\n 'checking complete': {\n invoke: [\n {\n src: 'select match listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: [\n {\n guard: ({event}) =>\n hasAtLeastOneExactMatch(event.output.matches),\n target: 'idle',\n actions: [\n assign({matches: ({event}) => event.output.matches}),\n {type: 'select match', params: {exact: true}},\n ],\n },\n {\n target: 'active',\n actions: [assign({matches: ({event}) => event.output.matches})],\n },\n ],\n onError: {\n target: 'active.no matches',\n actions: ['handle error'],\n },\n },\n ],\n },\n 'active': {\n invoke: [\n {\n src: 'select match listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'escape listener',\n id: 'escape listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'submit listener',\n id: 'submit listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'text insertion listener',\n id: 'text insertion listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'dismiss listener',\n id: 'dismiss listener',\n input: ({context}) => ({context}),\n },\n ],\n on: {\n 'close': {\n target: 'idle',\n },\n 'selection changed': {\n actions: [\n 'handle selection changed',\n 'update submit listener context',\n 'update text insertion listener context',\n 'update escape listener context',\n 'update request dismiss listener context',\n ],\n },\n },\n always: [\n {\n guard: 'no focus span',\n target: 'idle',\n },\n {\n guard: 'invalid pattern',\n target: 'idle',\n },\n {\n guard: 'is complete keyword',\n actions: [{type: 'select match', params: {exact: false}}],\n target: 'idle',\n },\n ],\n initial: 'evaluating',\n states: {\n 'evaluating': {\n always: [\n {\n guard: 'is loading',\n target: 'loading',\n },\n {\n guard: 'has matches',\n target: 'showing matches',\n },\n {\n target: 'no matches',\n },\n ],\n },\n 'loading': {\n entry: [assign({requestedKeyword: ({context}) => context.keyword})],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.evaluating',\n actions: [\n assign(({context, event}) => {\n if (event.output.keyword !== context.keyword) {\n return {\n isLoading:\n context.patternText !== context.requestedKeyword,\n }\n }\n\n return {\n matches: event.output.matches,\n isLoading:\n context.keyword !== context.requestedKeyword,\n }\n }),\n ],\n },\n onError: {\n target: '#typeahead picker.active.no matches',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n 'no matches': {\n entry: [assign({selectedIndex: 0})],\n always: [\n {\n guard: 'has matches',\n target: 'showing matches',\n },\n ],\n initial: 'idle',\n states: {\n idle: {\n always: [{guard: 'is loading', target: 'loading'}],\n },\n loading: {\n entry: [\n assign({\n requestedKeyword: ({context}) => context.keyword,\n }),\n ],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.no matches.idle',\n actions: ['handle async load complete'],\n },\n onError: {\n target: '#typeahead picker.active.no matches.idle',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n },\n },\n 'showing matches': {\n entry: [\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n invoke: {\n src: 'arrow listener',\n input: ({context}) => ({editor: context.editor}),\n },\n always: [\n {\n guard: 'no matches',\n target: 'no matches',\n },\n ],\n on: {\n 'navigate down': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'navigate up': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'navigate to': {\n actions: [\n 'navigate',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n 'select': {\n target: '#typeahead picker.idle',\n actions: [{type: 'select match', params: {exact: false}}],\n },\n },\n initial: 'idle',\n states: {\n idle: {\n always: [{guard: 'is loading', target: 'loading'}],\n },\n loading: {\n entry: [\n assign({\n requestedKeyword: ({context}) => context.keyword,\n }),\n ],\n initial: 'debouncing',\n states: {\n debouncing: {\n always: [{guard: 'no debounce', target: 'fetching'}],\n after: {\n DEBOUNCE: 'fetching',\n },\n },\n fetching: {\n invoke: {\n src: 'get matches',\n input: ({context}) => ({\n keyword: context.keyword,\n getMatches: context.definition.getMatches,\n }),\n onDone: {\n target: '#typeahead picker.active.showing matches.idle',\n actions: ['handle async load complete'],\n },\n onError: {\n target: '#typeahead picker.active.showing matches.idle',\n actions: ['handle error'],\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n })\n}\n\n/**\n * Check if matches contain at least one exact match.\n */\nfunction hasAtLeastOneExactMatch<TMatch extends object>(\n matches: ReadonlyArray<TMatch>,\n): boolean {\n return matches.some(\n (match) =>\n (match as unknown as AutoCompleteMatch | undefined)?.type === 'exact',\n )\n}\n\n/**\n * Get the first exact match from matches.\n */\nfunction getFirstExactMatch<TMatch extends object>(\n matches: ReadonlyArray<TMatch>,\n): TMatch | undefined {\n return matches.find(\n (match) =>\n (match as unknown as AutoCompleteMatch | undefined)?.type === 'exact',\n )\n}\n","import {useEditor} from '@portabletext/editor'\nimport {useActor} from '@xstate/react'\nimport {createTypeaheadPickerMachine} from './typeahead-picker-machine'\nimport type {\n TypeaheadPicker,\n TypeaheadPickerDefinition,\n TypeaheadPickerEvent,\n TypeaheadPickerState,\n} from './typeahead-picker.types'\n\n/**\n * React hook that activates a typeahead picker and returns its current state.\n *\n * Call inside a component rendered within an `EditorProvider`.\n * The picker automatically monitors the editor for trigger patterns.\n *\n * @example\n * ```tsx\n * function MentionPickerUI() {\n * const picker = useTypeaheadPicker(mentionPickerDefinition)\n *\n * if (picker.snapshot.matches('idle')) return null\n * if (picker.snapshot.matches({active: 'loading'})) return <Spinner />\n * if (picker.snapshot.matches({active: 'no matches'})) return <NoResults />\n *\n * const {matches, selectedIndex} = picker.snapshot.context\n *\n * return (\n * <ul>\n * {matches.map((match, index) => (\n * <li\n * key={match.key}\n * aria-selected={index === selectedIndex}\n * onMouseEnter={() => picker.send({type: 'navigate to', index})}\n * onClick={() => picker.send({type: 'select'})}\n * >\n * {match.name}\n * </li>\n * ))}\n * </ul>\n * )\n * }\n * ```\n *\n * @public\n */\nexport function useTypeaheadPicker<TMatch extends object>(\n definition: TypeaheadPickerDefinition<TMatch>,\n): TypeaheadPicker<TMatch> {\n const editor = useEditor()\n const [actorSnapshot, send] = useActor(\n createTypeaheadPickerMachine<TMatch>(),\n {\n input: {\n editor,\n definition,\n },\n },\n )\n\n return {\n snapshot: {\n matches: (state: TypeaheadPickerState) => actorSnapshot.matches(state),\n context: {\n keyword: actorSnapshot.context.keyword,\n matches: actorSnapshot.context.matches as ReadonlyArray<TMatch>,\n selectedIndex: actorSnapshot.context.selectedIndex,\n error: actorSnapshot.context.error,\n },\n },\n send: (event: TypeaheadPickerEvent) => {\n if (event.type === 'dismiss') {\n editor.send({\n type: 'custom.typeahead dismiss',\n pickerId: definition._id,\n })\n } else {\n send(event)\n }\n },\n }\n}\n"],"names":["defineTypeaheadPicker","config","_id","extractKeyword","patternText","triggerPattern","delimiter","completePattern","triggerMatch","match","index","keyword","slice","length","endsWith","completeMatch","escapeRegExp","str","replace","buildTriggerPattern","definition","RegExp","trigger","source","buildPartialPattern","buildCompletePattern","escapedDelimiter","arrowUpShortcut","createKeyboardShortcut","default","key","arrowDownShortcut","enterShortcut","tabShortcut","escapeShortcut","getTriggerState","snapshot","focusSpan","getFocusSpan","markState","getMarkState","context","selection","focusSpanTextBefore","node","text","focus","offset","focusSpanTextAfter","previousSpan","getPreviousSpan","nextSpan","getNextSpan","createTriggerActions","payload","keywordState","pickerId","state","textBeforeMatch","lastMatch","targetOffsets","anchor","_key","_type","marks","path","textBefore","textAfter","raise","createKeywordFoundEvent","extractedKeyword","createTriggerFoundEvent","newSpan","keyGenerator","JSON","stringify","type","at","child","extractPatternTextFromFocusSpan","createInputRules","rules","partialPattern","completeRule","defineInputRule","on","guard","event","matches","undefined","insertedMatch","textInserted","triggerState","actions","push","partialRule","triggerRule","createTriggerGuard","dom","triggerListenerCallback","sendBack","input","triggerGuard","unregisterBehaviors","editor","registerBehavior","behavior","defineInputRuleBehavior","defineBehavior","effect","unregister","escapeListenerCallback","receive","originEvent","onDismiss","patternSelection","flatMap","actionSet","arrowListenerCallback","selectionListenerCallback","unsubscribe","dismissListenerCallback","submitListenerCallback","selectedIndex","forward","textInsertionListenerCallback","keywordAnchor","isEqualSelectionPoints","selectMatchListenerCallback","selectActions","onSelect","createTypeaheadPickerMachine","setup","types","events","delays","DEBOUNCE","debounceMs","actors","fromCallback","fromPromise","result","getMatches","Promise","resolve","assign","mode","isLoading","requestedKeyword","getSnapshot","currentFocusSpan","isEqualPaths","isSelectionCollapsed","startsWith","keywordFocus","selectionIsBeforeKeyword","isPointAfterSelection","selectionIsAfterKeyword","isPointBeforeSelection","output","error","select match","params","exact","getFirstExactMatch","send","sendTo","guards","no focus span","invalid pattern","partialMatch","no debounce","is complete keyword","fullKeywordText","hasAtLeastOneExactMatch","has matches","no matches","is loading","createMachine","id","initial","states","entry","invoke","src","target","onDone","onError","always","debouncing","after","fetching","idle","loading","some","find","useTypeaheadPicker","$","_c","useEditor","t0","Symbol","for","t1","actorSnapshot","useActor","t2","t3","t4","t5","t6","t7"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/plugin-typeahead-picker",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "Generic typeahead picker infrastructure for the Portable Text Editor",
5
5
  "keywords": [
6
6
  "portabletext",
@@ -52,9 +52,9 @@
52
52
  "typescript": "5.9.3",
53
53
  "typescript-eslint": "^8.48.0",
54
54
  "vitest": "^4.0.16",
55
- "@portabletext/editor": "^4.3.6",
56
55
  "@portabletext/schema": "2.1.1",
57
- "racejar": "2.0.2"
56
+ "racejar": "2.0.2",
57
+ "@portabletext/editor": "^4.3.6"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@portabletext/editor": "^4.3.6",