@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 +241 -270
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +245 -258
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/src/emoji-picker-machine.tsx +444 -377
- package/src/emoji-picker.feature +81 -24
- package/src/emoji-picker.test.tsx +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { c } from "react/compiler-runtime";
|
|
2
2
|
import { useEditor } from "@portabletext/editor";
|
|
3
3
|
import { useActorRef, useSelector } from "@xstate/react";
|
|
4
|
-
import { raise, defineBehavior,
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import { raise, defineBehavior, forward, effect } from "@portabletext/editor/behaviors";
|
|
5
|
+
import { getFocusSpan, getNextSpan, isPointAfterSelection, isPointBeforeSelection, getMarkState, getPreviousSpan } from "@portabletext/editor/selectors";
|
|
6
|
+
import { isSelectionCollapsed, isEqualSelectionPoints } from "@portabletext/editor/utils";
|
|
7
7
|
import { createKeyboardShortcut } from "@portabletext/keyboard-shortcuts";
|
|
8
8
|
import { defineInputRule, defineInputRuleBehavior } from "@portabletext/plugin-input-rule";
|
|
9
|
-
import { setup,
|
|
9
|
+
import { setup, not, assign, sendTo, fromCallback, assertEvent } from "xstate";
|
|
10
10
|
function createMatchEmojis(config) {
|
|
11
11
|
return ({
|
|
12
12
|
keyword
|
|
@@ -62,22 +62,111 @@ const arrowUpShortcut = createKeyboardShortcut({
|
|
|
62
62
|
default: [{
|
|
63
63
|
key: "Escape"
|
|
64
64
|
}]
|
|
65
|
-
}),
|
|
65
|
+
}), getTriggerState = (snapshot) => {
|
|
66
|
+
const focusSpan = getFocusSpan(snapshot), markState = getMarkState(snapshot);
|
|
67
|
+
if (!focusSpan || !markState || !snapshot.context.selection)
|
|
68
|
+
return;
|
|
69
|
+
const focusSpanTextBefore = focusSpan.node.text.slice(0, snapshot.context.selection.focus.offset), focusSpanTextAfter = focusSpan.node.text.slice(snapshot.context.selection.focus.offset), previousSpan = getPreviousSpan(snapshot), nextSpan = getNextSpan(snapshot);
|
|
70
|
+
return {
|
|
71
|
+
focusSpan,
|
|
72
|
+
markState,
|
|
73
|
+
focusSpanTextBefore,
|
|
74
|
+
focusSpanTextAfter,
|
|
75
|
+
previousSpan,
|
|
76
|
+
nextSpan
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
function createTriggerActions({
|
|
80
|
+
snapshot,
|
|
81
|
+
payload,
|
|
82
|
+
keywordState
|
|
83
|
+
}) {
|
|
84
|
+
if (payload.markState.state === "unchanged") {
|
|
85
|
+
const focusSpan2 = {
|
|
86
|
+
node: {
|
|
87
|
+
_key: payload.focusSpan.node._key,
|
|
88
|
+
_type: payload.focusSpan.node._type,
|
|
89
|
+
text: `${payload.focusSpanTextBefore}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,
|
|
90
|
+
marks: payload.markState.marks
|
|
91
|
+
},
|
|
92
|
+
path: payload.focusSpan.path,
|
|
93
|
+
textBefore: payload.focusSpanTextBefore,
|
|
94
|
+
textAfter: payload.focusSpanTextAfter
|
|
95
|
+
};
|
|
96
|
+
return keywordState === "complete" ? [raise(createKeywordFoundEvent({
|
|
97
|
+
focusSpan: focusSpan2
|
|
98
|
+
}))] : [raise(createTriggerFoundEvent({
|
|
99
|
+
focusSpan: focusSpan2
|
|
100
|
+
}))];
|
|
101
|
+
}
|
|
102
|
+
const newSpan = {
|
|
103
|
+
_key: snapshot.context.keyGenerator(),
|
|
104
|
+
_type: payload.focusSpan.node._type,
|
|
105
|
+
text: payload.lastMatch.text,
|
|
106
|
+
marks: payload.markState.marks
|
|
107
|
+
};
|
|
108
|
+
let focusSpan = {
|
|
109
|
+
node: {
|
|
110
|
+
_key: newSpan._key,
|
|
111
|
+
_type: newSpan._type,
|
|
112
|
+
text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,
|
|
113
|
+
marks: payload.markState.marks
|
|
114
|
+
},
|
|
115
|
+
path: [{
|
|
116
|
+
_key: payload.focusSpan.path[0]._key
|
|
117
|
+
}, "children", {
|
|
118
|
+
_key: newSpan._key
|
|
119
|
+
}],
|
|
120
|
+
textBefore: "",
|
|
121
|
+
textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter
|
|
122
|
+
};
|
|
123
|
+
return payload.previousSpan && payload.focusSpanTextBefore.length === 0 && JSON.stringify(payload.previousSpan.node.marks ?? []) === JSON.stringify(payload.markState.marks) && (focusSpan = {
|
|
124
|
+
node: {
|
|
125
|
+
_key: payload.previousSpan.node._key,
|
|
126
|
+
_type: newSpan._type,
|
|
127
|
+
text: `${payload.previousSpan.node.text}${newSpan.text}`,
|
|
128
|
+
marks: newSpan.marks
|
|
129
|
+
},
|
|
130
|
+
path: payload.previousSpan.path,
|
|
131
|
+
textBefore: payload.previousSpan.node.text,
|
|
132
|
+
textAfter: ""
|
|
133
|
+
}), [raise({
|
|
134
|
+
type: "select",
|
|
135
|
+
at: payload.lastMatch.targetOffsets
|
|
136
|
+
}), raise({
|
|
137
|
+
type: "delete",
|
|
138
|
+
at: payload.lastMatch.targetOffsets
|
|
139
|
+
}), raise({
|
|
140
|
+
type: "insert.child",
|
|
141
|
+
child: newSpan
|
|
142
|
+
}), ...keywordState === "complete" ? [raise(createKeywordFoundEvent({
|
|
143
|
+
focusSpan
|
|
144
|
+
}))] : [raise(createTriggerFoundEvent({
|
|
145
|
+
focusSpan
|
|
146
|
+
}))]];
|
|
147
|
+
}
|
|
148
|
+
const triggerRule = defineInputRule({
|
|
66
149
|
on: /:/,
|
|
67
150
|
guard: ({
|
|
151
|
+
snapshot,
|
|
68
152
|
event
|
|
69
153
|
}) => {
|
|
70
154
|
const lastMatch = event.matches.at(-1);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
};
|
|
155
|
+
if (lastMatch === void 0)
|
|
156
|
+
return !1;
|
|
157
|
+
const triggerState = getTriggerState(snapshot);
|
|
158
|
+
return triggerState ? {
|
|
159
|
+
lastMatch,
|
|
160
|
+
...triggerState
|
|
161
|
+
} : !1;
|
|
79
162
|
},
|
|
80
|
-
actions: [(
|
|
163
|
+
actions: [({
|
|
164
|
+
snapshot
|
|
165
|
+
}, payload) => createTriggerActions({
|
|
166
|
+
snapshot,
|
|
167
|
+
payload,
|
|
168
|
+
keywordState: "partial"
|
|
169
|
+
})]
|
|
81
170
|
});
|
|
82
171
|
function createTriggerFoundEvent(payload) {
|
|
83
172
|
return {
|
|
@@ -88,48 +177,47 @@ function createTriggerFoundEvent(payload) {
|
|
|
88
177
|
const partialKeywordRule = defineInputRule({
|
|
89
178
|
on: /:[\S]+/,
|
|
90
179
|
guard: ({
|
|
180
|
+
snapshot,
|
|
91
181
|
event
|
|
92
182
|
}) => {
|
|
93
183
|
const lastMatch = event.matches.at(-1);
|
|
94
|
-
if (lastMatch === void 0)
|
|
184
|
+
if (lastMatch === void 0 || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
|
|
95
185
|
return !1;
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
keyword,
|
|
102
|
-
keywordAnchor,
|
|
103
|
-
keywordFocus
|
|
104
|
-
};
|
|
186
|
+
const triggerState = getTriggerState(snapshot);
|
|
187
|
+
return triggerState ? {
|
|
188
|
+
...triggerState,
|
|
189
|
+
lastMatch
|
|
190
|
+
} : !1;
|
|
105
191
|
},
|
|
106
|
-
actions: [(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const keywordRule = defineInputRule({
|
|
192
|
+
actions: [({
|
|
193
|
+
snapshot
|
|
194
|
+
}, payload) => createTriggerActions({
|
|
195
|
+
snapshot,
|
|
196
|
+
payload,
|
|
197
|
+
keywordState: "partial"
|
|
198
|
+
})]
|
|
199
|
+
}), keywordRule = defineInputRule({
|
|
115
200
|
on: /:[\S]+:/,
|
|
116
201
|
guard: ({
|
|
202
|
+
snapshot,
|
|
117
203
|
event
|
|
118
204
|
}) => {
|
|
119
205
|
const lastMatch = event.matches.at(-1);
|
|
120
|
-
if (lastMatch === void 0)
|
|
206
|
+
if (lastMatch === void 0 || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
|
|
121
207
|
return !1;
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
keyword,
|
|
128
|
-
keywordAnchor,
|
|
129
|
-
keywordFocus
|
|
130
|
-
};
|
|
208
|
+
const triggerState = getTriggerState(snapshot);
|
|
209
|
+
return triggerState ? {
|
|
210
|
+
...triggerState,
|
|
211
|
+
lastMatch
|
|
212
|
+
} : !1;
|
|
131
213
|
},
|
|
132
|
-
actions: [(
|
|
214
|
+
actions: [({
|
|
215
|
+
snapshot
|
|
216
|
+
}, payload) => createTriggerActions({
|
|
217
|
+
snapshot,
|
|
218
|
+
payload,
|
|
219
|
+
keywordState: "complete"
|
|
220
|
+
})]
|
|
133
221
|
});
|
|
134
222
|
function createKeywordFoundEvent(payload) {
|
|
135
223
|
return {
|
|
@@ -154,15 +242,6 @@ const triggerListenerCallback = ({
|
|
|
154
242
|
sendBack(event);
|
|
155
243
|
})]]
|
|
156
244
|
})
|
|
157
|
-
}), input.editor.registerBehavior({
|
|
158
|
-
behavior: defineBehavior({
|
|
159
|
-
on: "custom.partial keyword found",
|
|
160
|
-
actions: [({
|
|
161
|
-
event
|
|
162
|
-
}) => [effect(() => {
|
|
163
|
-
sendBack(event);
|
|
164
|
-
})]]
|
|
165
|
-
})
|
|
166
245
|
}), input.editor.registerBehavior({
|
|
167
246
|
behavior: defineBehavior({
|
|
168
247
|
on: "custom.trigger found",
|
|
@@ -238,10 +317,16 @@ const triggerListenerCallback = ({
|
|
|
238
317
|
type: "dismiss"
|
|
239
318
|
});
|
|
240
319
|
}), raise({
|
|
241
|
-
type: "delete
|
|
320
|
+
type: "delete",
|
|
242
321
|
at: {
|
|
243
|
-
anchor:
|
|
244
|
-
|
|
322
|
+
anchor: {
|
|
323
|
+
path: event.focusSpan.path,
|
|
324
|
+
offset: event.focusSpan.textBefore.length
|
|
325
|
+
},
|
|
326
|
+
focus: {
|
|
327
|
+
path: event.focusSpan.path,
|
|
328
|
+
offset: event.focusSpan.node.text.length - event.focusSpan.textAfter.length
|
|
329
|
+
}
|
|
245
330
|
}
|
|
246
331
|
}), raise({
|
|
247
332
|
type: "insert.text",
|
|
@@ -265,22 +350,19 @@ const triggerListenerCallback = ({
|
|
|
265
350
|
}) => {
|
|
266
351
|
if (!enterShortcut.guard(event.originEvent) && !tabShortcut.guard(event.originEvent))
|
|
267
352
|
return !1;
|
|
268
|
-
const
|
|
269
|
-
return match &&
|
|
270
|
-
|
|
271
|
-
focus,
|
|
353
|
+
const focusSpan = context.focusSpan, match = context.matches[context.selectedIndex];
|
|
354
|
+
return match && focusSpan ? {
|
|
355
|
+
focusSpan,
|
|
272
356
|
emoji: match.emoji
|
|
273
357
|
} : !1;
|
|
274
358
|
},
|
|
275
359
|
actions: [(_, {
|
|
276
|
-
|
|
277
|
-
focus,
|
|
360
|
+
focusSpan,
|
|
278
361
|
emoji
|
|
279
362
|
}) => [raise({
|
|
280
363
|
type: "custom.insert emoji",
|
|
281
364
|
emoji,
|
|
282
|
-
|
|
283
|
-
focus
|
|
365
|
+
focusSpan
|
|
284
366
|
})]]
|
|
285
367
|
})
|
|
286
368
|
}), input.context.editor.registerBehavior({
|
|
@@ -295,19 +377,6 @@ const triggerListenerCallback = ({
|
|
|
295
377
|
});
|
|
296
378
|
})]]
|
|
297
379
|
})
|
|
298
|
-
}), input.context.editor.registerBehavior({
|
|
299
|
-
behavior: defineInputRuleBehavior({
|
|
300
|
-
rules: [keywordRule]
|
|
301
|
-
})
|
|
302
|
-
}), input.context.editor.registerBehavior({
|
|
303
|
-
behavior: defineBehavior({
|
|
304
|
-
on: "custom.keyword found",
|
|
305
|
-
actions: [({
|
|
306
|
-
event
|
|
307
|
-
}) => [effect(() => {
|
|
308
|
-
sendBack(event);
|
|
309
|
-
})]]
|
|
310
|
-
})
|
|
311
380
|
})];
|
|
312
381
|
return () => {
|
|
313
382
|
for (const unregister of unregisterBehaviors)
|
|
@@ -317,79 +386,40 @@ const triggerListenerCallback = ({
|
|
|
317
386
|
sendBack,
|
|
318
387
|
input
|
|
319
388
|
}) => input.editor.on("selection", () => {
|
|
320
|
-
const snapshot = input.editor.getSnapshot();
|
|
321
389
|
sendBack({
|
|
322
|
-
type: "selection changed"
|
|
323
|
-
snapshot
|
|
390
|
+
type: "selection changed"
|
|
324
391
|
});
|
|
325
|
-
}).unsubscribe,
|
|
392
|
+
}).unsubscribe, textInsertionListenerCallback = ({
|
|
326
393
|
sendBack,
|
|
327
|
-
input
|
|
394
|
+
input,
|
|
395
|
+
receive
|
|
328
396
|
}) => {
|
|
329
|
-
|
|
397
|
+
let context = input.context;
|
|
398
|
+
return receive((event) => {
|
|
399
|
+
context = event.context;
|
|
400
|
+
}), input.context.editor.registerBehavior({
|
|
330
401
|
behavior: defineBehavior({
|
|
331
402
|
on: "insert.text",
|
|
332
403
|
guard: ({
|
|
333
404
|
snapshot
|
|
334
|
-
}) =>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
...event,
|
|
344
|
-
focus
|
|
345
|
-
});
|
|
346
|
-
}), forward(event)]]
|
|
347
|
-
})
|
|
348
|
-
}), input.editor.registerBehavior({
|
|
349
|
-
behavior: defineBehavior({
|
|
350
|
-
on: "delete.backward",
|
|
351
|
-
guard: ({
|
|
352
|
-
snapshot,
|
|
353
|
-
event
|
|
354
|
-
}) => event.unit === "character" && snapshot.context.selection ? {
|
|
355
|
-
focus: snapshot.context.selection.focus
|
|
356
|
-
} : !1,
|
|
357
|
-
actions: [({
|
|
358
|
-
event
|
|
359
|
-
}, {
|
|
360
|
-
focus
|
|
361
|
-
}) => [effect(() => {
|
|
362
|
-
sendBack({
|
|
363
|
-
type: "delete.backward",
|
|
364
|
-
focus
|
|
365
|
-
});
|
|
366
|
-
}), forward(event)]]
|
|
367
|
-
})
|
|
368
|
-
}), input.editor.registerBehavior({
|
|
369
|
-
behavior: defineBehavior({
|
|
370
|
-
on: "delete.forward",
|
|
371
|
-
guard: ({
|
|
372
|
-
snapshot,
|
|
373
|
-
event
|
|
374
|
-
}) => event.unit === "character" && snapshot.context.selection ? {
|
|
375
|
-
focus: snapshot.context.selection.focus
|
|
376
|
-
} : !1,
|
|
405
|
+
}) => {
|
|
406
|
+
if (!context.focusSpan || !snapshot.context.selection)
|
|
407
|
+
return !1;
|
|
408
|
+
const keywordAnchor = {
|
|
409
|
+
path: context.focusSpan.path,
|
|
410
|
+
offset: context.focusSpan.textBefore.length
|
|
411
|
+
};
|
|
412
|
+
return isEqualSelectionPoints(snapshot.context.selection.focus, keywordAnchor);
|
|
413
|
+
},
|
|
377
414
|
actions: [({
|
|
378
415
|
event
|
|
379
|
-
}, {
|
|
380
|
-
focus
|
|
381
|
-
}) => [effect(() => {
|
|
416
|
+
}) => [forward(event), effect(() => {
|
|
382
417
|
sendBack({
|
|
383
|
-
type: "
|
|
384
|
-
focus
|
|
418
|
+
type: "dismiss"
|
|
385
419
|
});
|
|
386
|
-
})
|
|
420
|
+
})]]
|
|
387
421
|
})
|
|
388
|
-
})
|
|
389
|
-
return () => {
|
|
390
|
-
for (const unregister of unregisterBehaviors)
|
|
391
|
-
unregister();
|
|
392
|
-
};
|
|
422
|
+
});
|
|
393
423
|
}, emojiPickerMachine = setup({
|
|
394
424
|
types: {
|
|
395
425
|
context: {},
|
|
@@ -403,60 +433,65 @@ const triggerListenerCallback = ({
|
|
|
403
433
|
"trigger listener": fromCallback(triggerListenerCallback),
|
|
404
434
|
"escape listener": fromCallback(escapeListenerCallback),
|
|
405
435
|
"selection listener": fromCallback(selectionListenerCallback),
|
|
406
|
-
"text
|
|
436
|
+
"text insertion listener": fromCallback(textInsertionListenerCallback)
|
|
407
437
|
},
|
|
408
438
|
actions: {
|
|
409
|
-
"
|
|
410
|
-
|
|
411
|
-
context,
|
|
412
|
-
event
|
|
413
|
-
}) => event.type !== "custom.trigger found" && event.type !== "custom.partial keyword found" && event.type !== "custom.keyword found" ? context.keyword : event.keyword
|
|
414
|
-
}),
|
|
415
|
-
"set keyword anchor": assign({
|
|
416
|
-
keywordAnchor: ({
|
|
417
|
-
context,
|
|
418
|
-
event
|
|
419
|
-
}) => event.type !== "custom.trigger found" && event.type !== "custom.partial keyword found" && event.type !== "custom.keyword found" ? context.keywordAnchor : event.keywordAnchor
|
|
420
|
-
}),
|
|
421
|
-
"set keyword focus": assign({
|
|
422
|
-
keywordFocus: ({
|
|
439
|
+
"set focus span": assign({
|
|
440
|
+
focusSpan: ({
|
|
423
441
|
context,
|
|
424
442
|
event
|
|
425
|
-
}) => event.type !== "custom.trigger found" && event.type !== "custom.
|
|
443
|
+
}) => event.type !== "custom.trigger found" && event.type !== "custom.keyword found" ? context.focusSpan : event.focusSpan
|
|
426
444
|
}),
|
|
427
|
-
"update
|
|
428
|
-
|
|
429
|
-
context
|
|
430
|
-
event
|
|
431
|
-
}) => (assertEvent(event, ["insert.text", "delete.backward", "delete.forward"]), context.keywordFocus ? {
|
|
432
|
-
path: context.keywordFocus.path,
|
|
433
|
-
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
|
|
434
|
-
} : context.keywordFocus)
|
|
435
|
-
}),
|
|
436
|
-
"update keyword": assign({
|
|
437
|
-
keyword: ({
|
|
438
|
-
context,
|
|
439
|
-
event
|
|
445
|
+
"update focus span": assign({
|
|
446
|
+
focusSpan: ({
|
|
447
|
+
context
|
|
440
448
|
}) => {
|
|
441
|
-
if (
|
|
442
|
-
return
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return keywordFocusPoint ? selectors.getSelectionText({
|
|
449
|
-
...event.snapshot,
|
|
449
|
+
if (!context.focusSpan)
|
|
450
|
+
return;
|
|
451
|
+
const snapshot = context.editor.getSnapshot(), focusSpan = getFocusSpan(snapshot);
|
|
452
|
+
if (!snapshot.context.selection || !focusSpan)
|
|
453
|
+
return;
|
|
454
|
+
const nextSpan = getNextSpan({
|
|
455
|
+
...snapshot,
|
|
450
456
|
context: {
|
|
451
|
-
...
|
|
457
|
+
...snapshot.context,
|
|
452
458
|
selection: {
|
|
453
|
-
anchor:
|
|
454
|
-
|
|
459
|
+
anchor: {
|
|
460
|
+
path: context.focusSpan.path,
|
|
461
|
+
offset: 0
|
|
462
|
+
},
|
|
463
|
+
focus: {
|
|
464
|
+
path: context.focusSpan.path,
|
|
465
|
+
offset: 0
|
|
466
|
+
}
|
|
455
467
|
}
|
|
456
468
|
}
|
|
457
|
-
})
|
|
469
|
+
});
|
|
470
|
+
if (JSON.stringify(focusSpan.path) !== JSON.stringify(context.focusSpan.path))
|
|
471
|
+
return nextSpan && context.focusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && isSelectionCollapsed(snapshot.context.selection) ? context.focusSpan : void 0;
|
|
472
|
+
if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore) || !focusSpan.node.text.endsWith(context.focusSpan.textAfter))
|
|
473
|
+
return;
|
|
474
|
+
const keywordAnchor = {
|
|
475
|
+
path: focusSpan.path,
|
|
476
|
+
offset: context.focusSpan.textBefore.length
|
|
477
|
+
}, keywordFocus = {
|
|
478
|
+
path: focusSpan.path,
|
|
479
|
+
offset: focusSpan.node.text.length - context.focusSpan.textAfter.length
|
|
480
|
+
}, selectionIsBeforeKeyword = isPointAfterSelection(keywordAnchor)(snapshot), selectionIsAfterKeyword = isPointBeforeSelection(keywordFocus)(snapshot);
|
|
481
|
+
if (!(selectionIsBeforeKeyword || selectionIsAfterKeyword))
|
|
482
|
+
return {
|
|
483
|
+
node: focusSpan.node,
|
|
484
|
+
path: focusSpan.path,
|
|
485
|
+
textBefore: context.focusSpan.textBefore,
|
|
486
|
+
textAfter: context.focusSpan.textAfter
|
|
487
|
+
};
|
|
458
488
|
}
|
|
459
489
|
}),
|
|
490
|
+
"update keyword": assign({
|
|
491
|
+
keyword: ({
|
|
492
|
+
context
|
|
493
|
+
}) => 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 : ""
|
|
494
|
+
}),
|
|
460
495
|
"update matches": assign({
|
|
461
496
|
matches: ({
|
|
462
497
|
context
|
|
@@ -485,99 +520,65 @@ const triggerListenerCallback = ({
|
|
|
485
520
|
event
|
|
486
521
|
}) => (assertEvent(event, "navigate to"), event.index)
|
|
487
522
|
}),
|
|
488
|
-
"update
|
|
523
|
+
"update submit listener context": sendTo("submit listener", ({
|
|
489
524
|
context
|
|
490
525
|
}) => ({
|
|
491
526
|
type: "context changed",
|
|
492
527
|
context
|
|
493
528
|
})),
|
|
494
|
-
"update
|
|
529
|
+
"update text insertion listener context": sendTo("text insertion listener", ({
|
|
495
530
|
context
|
|
496
531
|
}) => ({
|
|
497
532
|
type: "context changed",
|
|
498
533
|
context
|
|
499
534
|
})),
|
|
500
535
|
"insert selected match": ({
|
|
501
|
-
context
|
|
502
|
-
event
|
|
536
|
+
context
|
|
503
537
|
}) => {
|
|
504
538
|
const match = context.matches[context.selectedIndex];
|
|
505
|
-
!match || !context.
|
|
539
|
+
!match || !context.focusSpan || context.editor.send({
|
|
506
540
|
type: "custom.insert emoji",
|
|
507
541
|
emoji: match.emoji,
|
|
508
|
-
|
|
509
|
-
focus: context.keywordFocus
|
|
542
|
+
focusSpan: context.focusSpan
|
|
510
543
|
});
|
|
511
544
|
},
|
|
512
545
|
reset: assign({
|
|
513
|
-
|
|
514
|
-
keywordFocus: void 0,
|
|
546
|
+
focusSpan: void 0,
|
|
515
547
|
keyword: "",
|
|
516
548
|
matches: [],
|
|
517
549
|
selectedIndex: 0
|
|
518
550
|
})
|
|
519
551
|
},
|
|
520
552
|
guards: {
|
|
553
|
+
"no focus span": ({
|
|
554
|
+
context
|
|
555
|
+
}) => !context.focusSpan,
|
|
521
556
|
"has matches": ({
|
|
522
557
|
context
|
|
523
558
|
}) => context.matches.length > 0,
|
|
524
559
|
"no matches": not("has matches"),
|
|
525
|
-
"keyword is
|
|
560
|
+
"keyword is malformed": ({
|
|
561
|
+
context
|
|
562
|
+
}) => !context.incompleteKeywordRegex.test(context.keyword),
|
|
563
|
+
"keyword is direct match": ({
|
|
526
564
|
context
|
|
527
|
-
}) => context.incompleteKeywordRegex.test(context.keyword),
|
|
528
|
-
"keyword is malformed": not("keyword is wel-formed"),
|
|
529
|
-
"selection is before keyword": ({
|
|
530
|
-
context,
|
|
531
|
-
event
|
|
532
|
-
}) => (assertEvent(event, "selection changed"), context.keywordAnchor ? selectors.isPointAfterSelection(context.keywordAnchor.point)(event.snapshot) : !0),
|
|
533
|
-
"selection is after keyword": ({
|
|
534
|
-
context,
|
|
535
|
-
event
|
|
536
|
-
}) => {
|
|
537
|
-
if (assertEvent(event, "selection changed"), context.keywordFocus === void 0)
|
|
538
|
-
return !0;
|
|
539
|
-
const keywordFocusPoint = utils.blockOffsetToSpanSelectionPoint({
|
|
540
|
-
context: event.snapshot.context,
|
|
541
|
-
blockOffset: context.keywordFocus,
|
|
542
|
-
direction: "forward"
|
|
543
|
-
});
|
|
544
|
-
return keywordFocusPoint ? selectors.isPointBeforeSelection(keywordFocusPoint)(event.snapshot) : !0;
|
|
545
|
-
},
|
|
546
|
-
"selection is expanded": ({
|
|
547
|
-
event
|
|
548
|
-
}) => (assertEvent(event, "selection changed"), selectors.isSelectionExpanded(event.snapshot)),
|
|
549
|
-
"selection moved unexpectedly": or(["selection is before keyword", "selection is after keyword", "selection is expanded"]),
|
|
550
|
-
"unexpected text insertion": ({
|
|
551
|
-
context,
|
|
552
|
-
event
|
|
553
565
|
}) => {
|
|
554
|
-
if (
|
|
566
|
+
if (!/^:[\S]+:$/.test(context.keyword))
|
|
555
567
|
return !1;
|
|
556
|
-
const
|
|
557
|
-
return
|
|
558
|
-
...snapshot,
|
|
559
|
-
context: {
|
|
560
|
-
...snapshot.context,
|
|
561
|
-
selection: {
|
|
562
|
-
anchor: context.keywordAnchor.point,
|
|
563
|
-
focus: context.keywordAnchor.point
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}) || utils.isEqualSelectionPoints(event.focus, context.keywordAnchor.point);
|
|
568
|
+
const match = context.matches.at(context.selectedIndex);
|
|
569
|
+
return !(!match || match.type !== "exact");
|
|
567
570
|
}
|
|
568
571
|
}
|
|
569
572
|
}).createMachine({
|
|
570
|
-
/** @xstate-layout N4IgpgJg5mDOIC5RgLYHsBWBLABABywGMBrMAJwDosIAbMAYkLRrQDsctXZyAXSAbQAMAXUSg8aWFh5Y2YkAA9EARmUB2AJwUAzADYNADgCs65YO1q1ygDQgAnojUG1O5c+W7tAJmdfdRgF8A21RMXAIScgpuAEMyQgALTih6Tm4yHgo+BR4hUSQQCSkZOQKlBABaZW0DHSMAFksNQUF6oyNzL1sHBC9vCnrGtS8GtQaNNt0gkPRsfCJSSlj4pNYUiDA6PgoAMzQyAHc4iDz5IulZVnlyr3MKE30LA31DZoNuxD6vAaHdP29vOo1NNwLNwgsostEsl6BstmAKAAjGIkI5kE4iM6SC6lUDlerabT3arDfS3eoaPQfXr9QaWEaNcaTEGhOYRRbRMBxaFrWFYWAofmwU4Fc4lK5lFTqWqDAwUjReeoGbwaNTU1TPCh-QxNNS6XQGHwssHzSJLLkrGHcOiEcU4RIxNYCTGi7Hi66IfxE1oeZX1EbeZXUhUUZSKjxOOV6bTmY1hU0cqGrFLWsC2y72hKOmAnZT5cRuy4ehDVXQUVXDIyWGpmAzveyfLRKwQaVRVwR1ixeONsiHm7nJ+gigvFIuSkvKVuhgwaEwKmMKwbqkaCAaverqVuvKbBUHx9mQi08qAUVhoHAoGI8RJwHCwBJoA4w4eFQu4xSfaoDA3KOmCVSTn06r-i4-hGH0ZiEoI4H1D24JmpyA7JNED5PmsF5XjesD0KwMQAG5YFAV5gDgECPqwL5imOeKIIM9ShsoRh1i2erPB41L6C40GqISUb6n8cEJoeSFrChj7JBh14JHAOH4YRxE4AArnglFvhKNEIGoq4+E0yraPULa6PUHGqhQ3HVDUBL8dogkHv2lqife4noZeUkybhBFEXwOA8Ggqmju+5RGPqFBqP6ujDD4v4tjYDYIMqLjVKo5gdM4TGBLurLwYmR7JmJaFQJJWGpFwvB3psaZ8BARUJP5OLqR+CD1Loq5ymYfyeP4spGOqv70fpv7NBSBKtBlMz7n2iEOSeTkFTVMl1e645eB49wGP+K0UpBbjaMBzQUF4IzBYq7TNa2QS7meGzwAUWVCWQWIBQ15RVJq2ijJoLRtB03jUhUVYUHKtz-gqeoxkYGi2ZN1B0I99XFqobTlh4-5-Ot4H1j0ZirbcENhR4RmKrBmUmnZU3HnDS0aVUjHlh2cqtkqfTBdSSr0RMGieBS7htASUMIUmyFnvNsB3qhySU9RjUVBFdN1ltTPvbowZOGZEWHe9xgTHo-M5SJM3iy5mHSTdI7w+OlnlgY6heJzbgUv4ytxaqtSCBFg1eJFM4XQEQA */
|
|
571
573
|
id: "emoji picker",
|
|
572
574
|
context: ({
|
|
573
575
|
input
|
|
574
576
|
}) => ({
|
|
575
577
|
editor: input.editor,
|
|
576
578
|
keyword: "",
|
|
577
|
-
|
|
578
|
-
keywordFocus: void 0,
|
|
579
|
+
focusSpan: void 0,
|
|
579
580
|
matchEmojis: input.matchEmojis,
|
|
580
|
-
incompleteKeywordRegex:
|
|
581
|
+
incompleteKeywordRegex: /^:[\S]*$/,
|
|
581
582
|
matches: [],
|
|
582
583
|
selectedIndex: 0
|
|
583
584
|
}),
|
|
@@ -605,14 +606,10 @@ const triggerListenerCallback = ({
|
|
|
605
606
|
on: {
|
|
606
607
|
"custom.trigger found": {
|
|
607
608
|
target: "searching",
|
|
608
|
-
actions: ["set
|
|
609
|
-
},
|
|
610
|
-
"custom.partial keyword found": {
|
|
611
|
-
target: "searching",
|
|
612
|
-
actions: ["set keyword anchor", "set keyword focus", "init keyword"]
|
|
609
|
+
actions: ["set focus span", "update keyword"]
|
|
613
610
|
},
|
|
614
611
|
"custom.keyword found": {
|
|
615
|
-
actions: ["set
|
|
612
|
+
actions: ["set focus span", "update keyword", "update matches", "insert selected match"],
|
|
616
613
|
target: "idle",
|
|
617
614
|
reenter: !0
|
|
618
615
|
}
|
|
@@ -642,42 +639,32 @@ const triggerListenerCallback = ({
|
|
|
642
639
|
editor: context.editor
|
|
643
640
|
})
|
|
644
641
|
}, {
|
|
645
|
-
src: "text
|
|
642
|
+
src: "text insertion listener",
|
|
643
|
+
id: "text insertion listener",
|
|
646
644
|
input: ({
|
|
647
645
|
context
|
|
648
646
|
}) => ({
|
|
649
|
-
|
|
647
|
+
context
|
|
650
648
|
})
|
|
651
649
|
}],
|
|
652
650
|
on: {
|
|
653
|
-
"custom.keyword found": {
|
|
654
|
-
actions: ["set keyword anchor", "set keyword focus", "init keyword", "update matches", "insert selected match"]
|
|
655
|
-
},
|
|
656
|
-
"insert.text": [{
|
|
657
|
-
guard: "unexpected text insertion",
|
|
658
|
-
target: "idle"
|
|
659
|
-
}, {
|
|
660
|
-
actions: ["update keyword focus"]
|
|
661
|
-
}],
|
|
662
|
-
"delete.forward": {
|
|
663
|
-
actions: ["update keyword focus"]
|
|
664
|
-
},
|
|
665
|
-
"delete.backward": {
|
|
666
|
-
actions: ["update keyword focus"]
|
|
667
|
-
},
|
|
668
651
|
dismiss: {
|
|
669
652
|
target: "idle"
|
|
670
653
|
},
|
|
671
654
|
"selection changed": [{
|
|
672
|
-
|
|
673
|
-
target: "idle"
|
|
674
|
-
}, {
|
|
675
|
-
actions: ["update keyword", "update matches", "reset selected index", "update submit listener context"]
|
|
655
|
+
actions: ["update focus span", "update keyword", "update matches", "reset selected index", "update submit listener context", "update text insertion listener context"]
|
|
676
656
|
}]
|
|
677
657
|
},
|
|
678
658
|
always: [{
|
|
659
|
+
guard: "no focus span",
|
|
660
|
+
target: "idle"
|
|
661
|
+
}, {
|
|
679
662
|
guard: "keyword is malformed",
|
|
680
663
|
target: "idle"
|
|
664
|
+
}, {
|
|
665
|
+
guard: "keyword is direct match",
|
|
666
|
+
actions: ["insert selected match"],
|
|
667
|
+
target: "idle"
|
|
681
668
|
}],
|
|
682
669
|
initial: "no matches showing",
|
|
683
670
|
states: {
|