@portabletext/plugin-emoji-picker 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,22 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
3
  var compilerRuntime = require("react/compiler-runtime"), editor = require("@portabletext/editor"), react = require("@xstate/react"), behaviors = require("@portabletext/editor/behaviors"), selectors = require("@portabletext/editor/selectors"), utils = require("@portabletext/editor/utils"), keyboardShortcuts = require("@portabletext/keyboard-shortcuts"), pluginInputRule = require("@portabletext/plugin-input-rule"), xstate = require("xstate");
4
- function _interopNamespaceCompat(e) {
5
- if (e && typeof e == "object" && "default" in e) return e;
6
- var n = /* @__PURE__ */ Object.create(null);
7
- return e && Object.keys(e).forEach(function(k) {
8
- if (k !== "default") {
9
- var d = Object.getOwnPropertyDescriptor(e, k);
10
- Object.defineProperty(n, k, d.get ? d : {
11
- enumerable: !0,
12
- get: function() {
13
- return e[k];
14
- }
15
- });
16
- }
17
- }), n.default = e, Object.freeze(n);
18
- }
19
- var selectors__namespace = /* @__PURE__ */ _interopNamespaceCompat(selectors), utils__namespace = /* @__PURE__ */ _interopNamespaceCompat(utils);
20
4
  function createMatchEmojis(config) {
21
5
  return ({
22
6
  keyword
@@ -72,22 +56,111 @@ const arrowUpShortcut = keyboardShortcuts.createKeyboardShortcut({
72
56
  default: [{
73
57
  key: "Escape"
74
58
  }]
75
- }), triggerRule = pluginInputRule.defineInputRule({
59
+ }), getTriggerState = (snapshot) => {
60
+ const focusSpan = selectors.getFocusSpan(snapshot), markState = selectors.getMarkState(snapshot);
61
+ if (!focusSpan || !markState || !snapshot.context.selection)
62
+ return;
63
+ const focusSpanTextBefore = focusSpan.node.text.slice(0, snapshot.context.selection.focus.offset), focusSpanTextAfter = focusSpan.node.text.slice(snapshot.context.selection.focus.offset), previousSpan = selectors.getPreviousSpan(snapshot), nextSpan = selectors.getNextSpan(snapshot);
64
+ return {
65
+ focusSpan,
66
+ markState,
67
+ focusSpanTextBefore,
68
+ focusSpanTextAfter,
69
+ previousSpan,
70
+ nextSpan
71
+ };
72
+ };
73
+ function createTriggerActions({
74
+ snapshot,
75
+ payload,
76
+ keywordState
77
+ }) {
78
+ if (payload.markState.state === "unchanged") {
79
+ const focusSpan2 = {
80
+ node: {
81
+ _key: payload.focusSpan.node._key,
82
+ _type: payload.focusSpan.node._type,
83
+ text: `${payload.focusSpanTextBefore}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,
84
+ marks: payload.markState.marks
85
+ },
86
+ path: payload.focusSpan.path,
87
+ textBefore: payload.focusSpanTextBefore,
88
+ textAfter: payload.focusSpanTextAfter
89
+ };
90
+ return keywordState === "complete" ? [behaviors.raise(createKeywordFoundEvent({
91
+ focusSpan: focusSpan2
92
+ }))] : [behaviors.raise(createTriggerFoundEvent({
93
+ focusSpan: focusSpan2
94
+ }))];
95
+ }
96
+ const newSpan = {
97
+ _key: snapshot.context.keyGenerator(),
98
+ _type: payload.focusSpan.node._type,
99
+ text: payload.lastMatch.text,
100
+ marks: payload.markState.marks
101
+ };
102
+ let focusSpan = {
103
+ node: {
104
+ _key: newSpan._key,
105
+ _type: newSpan._type,
106
+ text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,
107
+ marks: payload.markState.marks
108
+ },
109
+ path: [{
110
+ _key: payload.focusSpan.path[0]._key
111
+ }, "children", {
112
+ _key: newSpan._key
113
+ }],
114
+ textBefore: "",
115
+ textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter
116
+ };
117
+ return payload.previousSpan && payload.focusSpanTextBefore.length === 0 && JSON.stringify(payload.previousSpan.node.marks ?? []) === JSON.stringify(payload.markState.marks) && (focusSpan = {
118
+ node: {
119
+ _key: payload.previousSpan.node._key,
120
+ _type: newSpan._type,
121
+ text: `${payload.previousSpan.node.text}${newSpan.text}`,
122
+ marks: newSpan.marks
123
+ },
124
+ path: payload.previousSpan.path,
125
+ textBefore: payload.previousSpan.node.text,
126
+ textAfter: ""
127
+ }), [behaviors.raise({
128
+ type: "select",
129
+ at: payload.lastMatch.targetOffsets
130
+ }), behaviors.raise({
131
+ type: "delete",
132
+ at: payload.lastMatch.targetOffsets
133
+ }), behaviors.raise({
134
+ type: "insert.child",
135
+ child: newSpan
136
+ }), ...keywordState === "complete" ? [behaviors.raise(createKeywordFoundEvent({
137
+ focusSpan
138
+ }))] : [behaviors.raise(createTriggerFoundEvent({
139
+ focusSpan
140
+ }))]];
141
+ }
142
+ const triggerRule = pluginInputRule.defineInputRule({
76
143
  on: /:/,
77
144
  guard: ({
145
+ snapshot,
78
146
  event
79
147
  }) => {
80
148
  const lastMatch = event.matches.at(-1);
81
- return lastMatch === void 0 ? !1 : {
82
- keyword: lastMatch.text,
83
- keywordAnchor: {
84
- point: lastMatch.selection.anchor,
85
- blockOffset: lastMatch.targetOffsets.anchor
86
- },
87
- keywordFocus: lastMatch.targetOffsets.focus
88
- };
149
+ if (lastMatch === void 0)
150
+ return !1;
151
+ const triggerState = getTriggerState(snapshot);
152
+ return triggerState ? {
153
+ lastMatch,
154
+ ...triggerState
155
+ } : !1;
89
156
  },
90
- actions: [(_, payload) => [behaviors.raise(createTriggerFoundEvent(payload))]]
157
+ actions: [({
158
+ snapshot
159
+ }, payload) => createTriggerActions({
160
+ snapshot,
161
+ payload,
162
+ keywordState: "partial"
163
+ })]
91
164
  });
92
165
  function createTriggerFoundEvent(payload) {
93
166
  return {
@@ -98,48 +171,47 @@ function createTriggerFoundEvent(payload) {
98
171
  const partialKeywordRule = pluginInputRule.defineInputRule({
99
172
  on: /:[\S]+/,
100
173
  guard: ({
174
+ snapshot,
101
175
  event
102
176
  }) => {
103
177
  const lastMatch = event.matches.at(-1);
104
- if (lastMatch === void 0)
178
+ if (lastMatch === void 0 || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
105
179
  return !1;
106
- const keyword = lastMatch.text, keywordAnchor = {
107
- point: lastMatch.selection.anchor,
108
- blockOffset: lastMatch.targetOffsets.anchor
109
- }, keywordFocus = lastMatch.targetOffsets.focus;
110
- return {
111
- keyword,
112
- keywordAnchor,
113
- keywordFocus
114
- };
180
+ const triggerState = getTriggerState(snapshot);
181
+ return triggerState ? {
182
+ ...triggerState,
183
+ lastMatch
184
+ } : !1;
115
185
  },
116
- actions: [(_, payload) => [behaviors.raise(createPartialKeywordFoundEvent(payload))]]
117
- });
118
- function createPartialKeywordFoundEvent(payload) {
119
- return {
120
- type: "custom.partial keyword found",
121
- ...payload
122
- };
123
- }
124
- const keywordRule = pluginInputRule.defineInputRule({
186
+ actions: [({
187
+ snapshot
188
+ }, payload) => createTriggerActions({
189
+ snapshot,
190
+ payload,
191
+ keywordState: "partial"
192
+ })]
193
+ }), keywordRule = pluginInputRule.defineInputRule({
125
194
  on: /:[\S]+:/,
126
195
  guard: ({
196
+ snapshot,
127
197
  event
128
198
  }) => {
129
199
  const lastMatch = event.matches.at(-1);
130
- if (lastMatch === void 0)
200
+ if (lastMatch === void 0 || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
131
201
  return !1;
132
- const keyword = lastMatch.text, keywordAnchor = {
133
- point: lastMatch.selection.anchor,
134
- blockOffset: lastMatch.targetOffsets.anchor
135
- }, keywordFocus = lastMatch.targetOffsets.focus;
136
- return {
137
- keyword,
138
- keywordAnchor,
139
- keywordFocus
140
- };
202
+ const triggerState = getTriggerState(snapshot);
203
+ return triggerState ? {
204
+ ...triggerState,
205
+ lastMatch
206
+ } : !1;
141
207
  },
142
- actions: [(_, payload) => [behaviors.raise(createKeywordFoundEvent(payload))]]
208
+ actions: [({
209
+ snapshot
210
+ }, payload) => createTriggerActions({
211
+ snapshot,
212
+ payload,
213
+ keywordState: "complete"
214
+ })]
143
215
  });
144
216
  function createKeywordFoundEvent(payload) {
145
217
  return {
@@ -164,15 +236,6 @@ const triggerListenerCallback = ({
164
236
  sendBack(event);
165
237
  })]]
166
238
  })
167
- }), input.editor.registerBehavior({
168
- behavior: behaviors.defineBehavior({
169
- on: "custom.partial keyword found",
170
- actions: [({
171
- event
172
- }) => [behaviors.effect(() => {
173
- sendBack(event);
174
- })]]
175
- })
176
239
  }), input.editor.registerBehavior({
177
240
  behavior: behaviors.defineBehavior({
178
241
  on: "custom.trigger found",
@@ -248,10 +311,16 @@ const triggerListenerCallback = ({
248
311
  type: "dismiss"
249
312
  });
250
313
  }), behaviors.raise({
251
- type: "delete.text",
314
+ type: "delete",
252
315
  at: {
253
- anchor: event.anchor,
254
- focus: event.focus
316
+ anchor: {
317
+ path: event.focusSpan.path,
318
+ offset: event.focusSpan.textBefore.length
319
+ },
320
+ focus: {
321
+ path: event.focusSpan.path,
322
+ offset: event.focusSpan.node.text.length - event.focusSpan.textAfter.length
323
+ }
255
324
  }
256
325
  }), behaviors.raise({
257
326
  type: "insert.text",
@@ -275,22 +344,19 @@ const triggerListenerCallback = ({
275
344
  }) => {
276
345
  if (!enterShortcut.guard(event.originEvent) && !tabShortcut.guard(event.originEvent))
277
346
  return !1;
278
- const anchor = context.keywordAnchor?.blockOffset, focus = context.keywordFocus, match = context.matches[context.selectedIndex];
279
- return match && anchor && focus ? {
280
- anchor,
281
- focus,
347
+ const focusSpan = context.focusSpan, match = context.matches[context.selectedIndex];
348
+ return match && focusSpan ? {
349
+ focusSpan,
282
350
  emoji: match.emoji
283
351
  } : !1;
284
352
  },
285
353
  actions: [(_, {
286
- anchor,
287
- focus,
354
+ focusSpan,
288
355
  emoji
289
356
  }) => [behaviors.raise({
290
357
  type: "custom.insert emoji",
291
358
  emoji,
292
- anchor,
293
- focus
359
+ focusSpan
294
360
  })]]
295
361
  })
296
362
  }), input.context.editor.registerBehavior({
@@ -305,19 +371,6 @@ const triggerListenerCallback = ({
305
371
  });
306
372
  })]]
307
373
  })
308
- }), input.context.editor.registerBehavior({
309
- behavior: pluginInputRule.defineInputRuleBehavior({
310
- rules: [keywordRule]
311
- })
312
- }), input.context.editor.registerBehavior({
313
- behavior: behaviors.defineBehavior({
314
- on: "custom.keyword found",
315
- actions: [({
316
- event
317
- }) => [behaviors.effect(() => {
318
- sendBack(event);
319
- })]]
320
- })
321
374
  })];
322
375
  return () => {
323
376
  for (const unregister of unregisterBehaviors)
@@ -327,79 +380,40 @@ const triggerListenerCallback = ({
327
380
  sendBack,
328
381
  input
329
382
  }) => input.editor.on("selection", () => {
330
- const snapshot = input.editor.getSnapshot();
331
383
  sendBack({
332
- type: "selection changed",
333
- snapshot
384
+ type: "selection changed"
334
385
  });
335
- }).unsubscribe, textChangeListener = ({
386
+ }).unsubscribe, textInsertionListenerCallback = ({
336
387
  sendBack,
337
- input
388
+ input,
389
+ receive
338
390
  }) => {
339
- const unregisterBehaviors = [input.editor.registerBehavior({
391
+ let context = input.context;
392
+ return receive((event) => {
393
+ context = event.context;
394
+ }), input.context.editor.registerBehavior({
340
395
  behavior: behaviors.defineBehavior({
341
396
  on: "insert.text",
342
397
  guard: ({
343
398
  snapshot
344
- }) => snapshot.context.selection ? {
345
- focus: snapshot.context.selection.focus
346
- } : !1,
347
- actions: [({
348
- event
349
- }, {
350
- focus
351
- }) => [behaviors.effect(() => {
352
- sendBack({
353
- ...event,
354
- focus
355
- });
356
- }), behaviors.forward(event)]]
357
- })
358
- }), input.editor.registerBehavior({
359
- behavior: behaviors.defineBehavior({
360
- on: "delete.backward",
361
- guard: ({
362
- snapshot,
363
- event
364
- }) => event.unit === "character" && snapshot.context.selection ? {
365
- focus: snapshot.context.selection.focus
366
- } : !1,
367
- actions: [({
368
- event
369
- }, {
370
- focus
371
- }) => [behaviors.effect(() => {
372
- sendBack({
373
- type: "delete.backward",
374
- focus
375
- });
376
- }), behaviors.forward(event)]]
377
- })
378
- }), input.editor.registerBehavior({
379
- behavior: behaviors.defineBehavior({
380
- on: "delete.forward",
381
- guard: ({
382
- snapshot,
383
- event
384
- }) => event.unit === "character" && snapshot.context.selection ? {
385
- focus: snapshot.context.selection.focus
386
- } : !1,
399
+ }) => {
400
+ if (!context.focusSpan || !snapshot.context.selection)
401
+ return !1;
402
+ const keywordAnchor = {
403
+ path: context.focusSpan.path,
404
+ offset: context.focusSpan.textBefore.length
405
+ };
406
+ return utils.isEqualSelectionPoints(snapshot.context.selection.focus, keywordAnchor);
407
+ },
387
408
  actions: [({
388
409
  event
389
- }, {
390
- focus
391
- }) => [behaviors.effect(() => {
410
+ }) => [behaviors.forward(event), behaviors.effect(() => {
392
411
  sendBack({
393
- type: "delete.forward",
394
- focus
412
+ type: "dismiss"
395
413
  });
396
- }), behaviors.forward(event)]]
414
+ })]]
397
415
  })
398
- })];
399
- return () => {
400
- for (const unregister of unregisterBehaviors)
401
- unregister();
402
- };
416
+ });
403
417
  }, emojiPickerMachine = xstate.setup({
404
418
  types: {
405
419
  context: {},
@@ -413,60 +427,65 @@ const triggerListenerCallback = ({
413
427
  "trigger listener": xstate.fromCallback(triggerListenerCallback),
414
428
  "escape listener": xstate.fromCallback(escapeListenerCallback),
415
429
  "selection listener": xstate.fromCallback(selectionListenerCallback),
416
- "text change listener": xstate.fromCallback(textChangeListener)
430
+ "text insertion listener": xstate.fromCallback(textInsertionListenerCallback)
417
431
  },
418
432
  actions: {
419
- "init keyword": xstate.assign({
420
- keyword: ({
421
- context,
422
- event
423
- }) => event.type !== "custom.trigger found" && event.type !== "custom.partial keyword found" && event.type !== "custom.keyword found" ? context.keyword : event.keyword
424
- }),
425
- "set keyword anchor": xstate.assign({
426
- keywordAnchor: ({
427
- context,
428
- event
429
- }) => event.type !== "custom.trigger found" && event.type !== "custom.partial keyword found" && event.type !== "custom.keyword found" ? context.keywordAnchor : event.keywordAnchor
430
- }),
431
- "set keyword focus": xstate.assign({
432
- keywordFocus: ({
433
- context,
434
- event
435
- }) => event.type !== "custom.trigger found" && event.type !== "custom.partial keyword found" && event.type !== "custom.keyword found" ? context.keywordFocus : event.keywordFocus
436
- }),
437
- "update keyword focus": xstate.assign({
438
- keywordFocus: ({
433
+ "set focus span": xstate.assign({
434
+ focusSpan: ({
439
435
  context,
440
436
  event
441
- }) => (xstate.assertEvent(event, ["insert.text", "delete.backward", "delete.forward"]), context.keywordFocus ? {
442
- path: context.keywordFocus.path,
443
- offset: event.type === "insert.text" ? context.keywordFocus.offset + event.text.length : event.type === "delete.backward" || event.type === "delete.forward" ? context.keywordFocus.offset - 1 : event.focus.offset
444
- } : context.keywordFocus)
437
+ }) => event.type !== "custom.trigger found" && event.type !== "custom.keyword found" ? context.focusSpan : event.focusSpan
445
438
  }),
446
- "update keyword": xstate.assign({
447
- keyword: ({
448
- context,
449
- event
439
+ "update focus span": xstate.assign({
440
+ focusSpan: ({
441
+ context
450
442
  }) => {
451
- if (xstate.assertEvent(event, "selection changed"), !context.keywordAnchor || !context.keywordFocus)
452
- return "";
453
- const keywordFocusPoint = utils__namespace.blockOffsetToSpanSelectionPoint({
454
- context: event.snapshot.context,
455
- blockOffset: context.keywordFocus,
456
- direction: "forward"
457
- });
458
- return keywordFocusPoint ? selectors__namespace.getSelectionText({
459
- ...event.snapshot,
443
+ if (!context.focusSpan)
444
+ return;
445
+ const snapshot = context.editor.getSnapshot(), focusSpan = selectors.getFocusSpan(snapshot);
446
+ if (!snapshot.context.selection || !focusSpan)
447
+ return;
448
+ const nextSpan = selectors.getNextSpan({
449
+ ...snapshot,
460
450
  context: {
461
- ...event.snapshot.context,
451
+ ...snapshot.context,
462
452
  selection: {
463
- anchor: context.keywordAnchor.point,
464
- focus: keywordFocusPoint
453
+ anchor: {
454
+ path: context.focusSpan.path,
455
+ offset: 0
456
+ },
457
+ focus: {
458
+ path: context.focusSpan.path,
459
+ offset: 0
460
+ }
465
461
  }
466
462
  }
467
- }) : "";
463
+ });
464
+ if (JSON.stringify(focusSpan.path) !== JSON.stringify(context.focusSpan.path))
465
+ return nextSpan && context.focusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && utils.isSelectionCollapsed(snapshot.context.selection) ? context.focusSpan : void 0;
466
+ if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore) || !focusSpan.node.text.endsWith(context.focusSpan.textAfter))
467
+ return;
468
+ const keywordAnchor = {
469
+ path: focusSpan.path,
470
+ offset: context.focusSpan.textBefore.length
471
+ }, keywordFocus = {
472
+ path: focusSpan.path,
473
+ offset: focusSpan.node.text.length - context.focusSpan.textAfter.length
474
+ }, selectionIsBeforeKeyword = selectors.isPointAfterSelection(keywordAnchor)(snapshot), selectionIsAfterKeyword = selectors.isPointBeforeSelection(keywordFocus)(snapshot);
475
+ if (!(selectionIsBeforeKeyword || selectionIsAfterKeyword))
476
+ return {
477
+ node: focusSpan.node,
478
+ path: focusSpan.path,
479
+ textBefore: context.focusSpan.textBefore,
480
+ textAfter: context.focusSpan.textAfter
481
+ };
468
482
  }
469
483
  }),
484
+ "update keyword": xstate.assign({
485
+ keyword: ({
486
+ context
487
+ }) => context.focusSpan ? context.focusSpan.textBefore.length > 0 && context.focusSpan.textAfter.length > 0 ? context.focusSpan.node.text.slice(context.focusSpan.textBefore.length, -context.focusSpan.textAfter.length) : context.focusSpan.textBefore.length > 0 ? context.focusSpan.node.text.slice(context.focusSpan.textBefore.length) : context.focusSpan.textAfter.length > 0 ? context.focusSpan.node.text.slice(0, -context.focusSpan.textAfter.length) : context.focusSpan.node.text : ""
488
+ }),
470
489
  "update matches": xstate.assign({
471
490
  matches: ({
472
491
  context
@@ -495,99 +514,65 @@ const triggerListenerCallback = ({
495
514
  event
496
515
  }) => (xstate.assertEvent(event, "navigate to"), event.index)
497
516
  }),
498
- "update emoji insert listener context": xstate.sendTo("emoji insert listener", ({
517
+ "update submit listener context": xstate.sendTo("submit listener", ({
499
518
  context
500
519
  }) => ({
501
520
  type: "context changed",
502
521
  context
503
522
  })),
504
- "update submit listener context": xstate.sendTo("submit listener", ({
523
+ "update text insertion listener context": xstate.sendTo("text insertion listener", ({
505
524
  context
506
525
  }) => ({
507
526
  type: "context changed",
508
527
  context
509
528
  })),
510
529
  "insert selected match": ({
511
- context,
512
- event
530
+ context
513
531
  }) => {
514
532
  const match = context.matches[context.selectedIndex];
515
- !match || !context.keywordAnchor || !context.keywordFocus || event.type === "custom.keyword found" && match.type !== "exact" || context.editor.send({
533
+ !match || !context.focusSpan || context.editor.send({
516
534
  type: "custom.insert emoji",
517
535
  emoji: match.emoji,
518
- anchor: context.keywordAnchor.blockOffset,
519
- focus: context.keywordFocus
536
+ focusSpan: context.focusSpan
520
537
  });
521
538
  },
522
539
  reset: xstate.assign({
523
- keywordAnchor: void 0,
524
- keywordFocus: void 0,
540
+ focusSpan: void 0,
525
541
  keyword: "",
526
542
  matches: [],
527
543
  selectedIndex: 0
528
544
  })
529
545
  },
530
546
  guards: {
547
+ "no focus span": ({
548
+ context
549
+ }) => !context.focusSpan,
531
550
  "has matches": ({
532
551
  context
533
552
  }) => context.matches.length > 0,
534
553
  "no matches": xstate.not("has matches"),
535
- "keyword is wel-formed": ({
554
+ "keyword is malformed": ({
555
+ context
556
+ }) => !context.incompleteKeywordRegex.test(context.keyword),
557
+ "keyword is direct match": ({
536
558
  context
537
- }) => context.incompleteKeywordRegex.test(context.keyword),
538
- "keyword is malformed": xstate.not("keyword is wel-formed"),
539
- "selection is before keyword": ({
540
- context,
541
- event
542
- }) => (xstate.assertEvent(event, "selection changed"), context.keywordAnchor ? selectors__namespace.isPointAfterSelection(context.keywordAnchor.point)(event.snapshot) : !0),
543
- "selection is after keyword": ({
544
- context,
545
- event
546
- }) => {
547
- if (xstate.assertEvent(event, "selection changed"), context.keywordFocus === void 0)
548
- return !0;
549
- const keywordFocusPoint = utils__namespace.blockOffsetToSpanSelectionPoint({
550
- context: event.snapshot.context,
551
- blockOffset: context.keywordFocus,
552
- direction: "forward"
553
- });
554
- return keywordFocusPoint ? selectors__namespace.isPointBeforeSelection(keywordFocusPoint)(event.snapshot) : !0;
555
- },
556
- "selection is expanded": ({
557
- event
558
- }) => (xstate.assertEvent(event, "selection changed"), selectors__namespace.isSelectionExpanded(event.snapshot)),
559
- "selection moved unexpectedly": xstate.or(["selection is before keyword", "selection is after keyword", "selection is expanded"]),
560
- "unexpected text insertion": ({
561
- context,
562
- event
563
559
  }) => {
564
- if (event.type !== "insert.text" || !context.keywordAnchor)
560
+ if (!/^:[\S]+:$/.test(context.keyword))
565
561
  return !1;
566
- const snapshot = context.editor.getSnapshot();
567
- return selectors__namespace.isPointBeforeSelection(event.focus)({
568
- ...snapshot,
569
- context: {
570
- ...snapshot.context,
571
- selection: {
572
- anchor: context.keywordAnchor.point,
573
- focus: context.keywordAnchor.point
574
- }
575
- }
576
- }) || utils__namespace.isEqualSelectionPoints(event.focus, context.keywordAnchor.point);
562
+ const match = context.matches.at(context.selectedIndex);
563
+ return !(!match || match.type !== "exact");
577
564
  }
578
565
  }
579
566
  }).createMachine({
580
- /** @xstate-layout N4IgpgJg5mDOIC5RgLYHsBWBLABABywGMBrMAJwDosIAbMAYkLRrQDsctXZyAXSAbQAMAXUSg8aWFh5Y2YkAA9EARmUB2AJwUAzADYNADgCs65YO1q1ygDQgAnojUG1O5c+W7tAJmdfdRgF8A21RMXAIScgpuAEMyQgALTih6Tm4yHgo+BR4hUSQQCSkZOQKlBABaZW0DHSMAFksNQUF6oyNzL1sHBC9vCnrGtS8GtQaNNt0gkPRsfCJSSlj4pNYUiDA6PgoAMzQyAHc4iDz5IulZVnlyr3MKE30LA31DZoNuxD6vAaHdP29vOo1NNwLNwgsostEsl6BstmAKAAjGIkI5kE4iM6SC6lUDlerabT3arDfS3eoaPQfXr9QaWEaNcaTEGhOYRRbRMBxaFrWFYWAofmwU4Fc4lK5lFTqWqDAwUjReeoGbwaNTU1TPCh-QxNNS6XQGHwssHzSJLLkrGHcOiEcU4RIxNYCTGi7Hi66IfxE1oeZX1EbeZXUhUUZSKjxOOV6bTmY1hU0cqGrFLWsC2y72hKOmAnZT5cRuy4ehDVXQUVXDIyWGpmAzveyfLRKwQaVRVwR1ixeONsiHm7nJ+gigvFIuSkvKVuhgwaEwKmMKwbqkaCAaverqVuvKbBUHx9mQi08qAUVhoHAoGI8RJwHCwBJoA4w4eFQu4xSfaoDA3KOmCVSTn06r-i4-hGH0ZiEoI4H1D24JmpyA7JNED5PmsF5XjesD0KwMQAG5YFAV5gDgECPqwL5imOeKIIM9ShsoRh1i2erPB41L6C40GqISUb6n8cEJoeSFrChj7JBh14JHAOH4YRxE4AArnglFvhKNEIGoq4+E0yraPULa6PUHGqhQ3HVDUBL8dogkHv2lqife4noZeUkybhBFEXwOA8Ggqmju+5RGPqFBqP6ujDD4v4tjYDYIMqLjVKo5gdM4TGBLurLwYmR7JmJaFQJJWGpFwvB3psaZ8BARUJP5OLqR+CD1Loq5ymYfyeP4spGOqv70fpv7NBSBKtBlMz7n2iEOSeTkFTVMl1e645eB49wGP+K0UpBbjaMBzQUF4IzBYq7TNa2QS7meGzwAUWVCWQWIBQ15RVJq2ijJoLRtB03jUhUVYUHKtz-gqeoxkYGi2ZN1B0I99XFqobTlh4-5-Ot4H1j0ZirbcENhR4RmKrBmUmnZU3HnDS0aVUjHlh2cqtkqfTBdSSr0RMGieBS7htASUMIUmyFnvNsB3qhySU9RjUVBFdN1ltTPvbowZOGZEWHe9xgTHo-M5SJM3iy5mHSTdI7w+OlnlgY6heJzbgUv4ytxaqtSCBFg1eJFM4XQEQA */
581
567
  id: "emoji picker",
582
568
  context: ({
583
569
  input
584
570
  }) => ({
585
571
  editor: input.editor,
586
572
  keyword: "",
587
- keywordAnchor: void 0,
588
- keywordFocus: void 0,
573
+ focusSpan: void 0,
589
574
  matchEmojis: input.matchEmojis,
590
- incompleteKeywordRegex: /:[\S]*$/,
575
+ incompleteKeywordRegex: /^:[\S]*$/,
591
576
  matches: [],
592
577
  selectedIndex: 0
593
578
  }),
@@ -615,14 +600,10 @@ const triggerListenerCallback = ({
615
600
  on: {
616
601
  "custom.trigger found": {
617
602
  target: "searching",
618
- actions: ["set keyword anchor", "set keyword focus", "init keyword"]
619
- },
620
- "custom.partial keyword found": {
621
- target: "searching",
622
- actions: ["set keyword anchor", "set keyword focus", "init keyword"]
603
+ actions: ["set focus span", "update keyword"]
623
604
  },
624
605
  "custom.keyword found": {
625
- actions: ["set keyword anchor", "set keyword focus", "init keyword", "update matches", "insert selected match"],
606
+ actions: ["set focus span", "update keyword", "update matches", "insert selected match"],
626
607
  target: "idle",
627
608
  reenter: !0
628
609
  }
@@ -652,42 +633,32 @@ const triggerListenerCallback = ({
652
633
  editor: context.editor
653
634
  })
654
635
  }, {
655
- src: "text change listener",
636
+ src: "text insertion listener",
637
+ id: "text insertion listener",
656
638
  input: ({
657
639
  context
658
640
  }) => ({
659
- editor: context.editor
641
+ context
660
642
  })
661
643
  }],
662
644
  on: {
663
- "custom.keyword found": {
664
- actions: ["set keyword anchor", "set keyword focus", "init keyword", "update matches", "insert selected match"]
665
- },
666
- "insert.text": [{
667
- guard: "unexpected text insertion",
668
- target: "idle"
669
- }, {
670
- actions: ["update keyword focus"]
671
- }],
672
- "delete.forward": {
673
- actions: ["update keyword focus"]
674
- },
675
- "delete.backward": {
676
- actions: ["update keyword focus"]
677
- },
678
645
  dismiss: {
679
646
  target: "idle"
680
647
  },
681
648
  "selection changed": [{
682
- guard: "selection moved unexpectedly",
683
- target: "idle"
684
- }, {
685
- actions: ["update keyword", "update matches", "reset selected index", "update submit listener context"]
649
+ actions: ["update focus span", "update keyword", "update matches", "reset selected index", "update submit listener context", "update text insertion listener context"]
686
650
  }]
687
651
  },
688
652
  always: [{
653
+ guard: "no focus span",
654
+ target: "idle"
655
+ }, {
689
656
  guard: "keyword is malformed",
690
657
  target: "idle"
658
+ }, {
659
+ guard: "keyword is direct match",
660
+ actions: ["insert selected match"],
661
+ target: "idle"
691
662
  }],
692
663
  initial: "no matches showing",
693
664
  states: {