@portabletext/plugin-typeahead-picker 1.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/LICENSE +21 -0
- package/README.md +495 -0
- package/dist/index.d.ts +459 -0
- package/dist/index.js +1117 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { useEditor } from "@portabletext/editor";
|
|
3
|
+
import { useActor } from "@xstate/react";
|
|
4
|
+
import { defineBehavior, effect, forward, raise } from "@portabletext/editor/behaviors";
|
|
5
|
+
import { getFocusSpan, getNextSpan, isSelectionCollapsed, isPointAfterSelection, isPointBeforeSelection, getMarkState, getPreviousSpan } from "@portabletext/editor/selectors";
|
|
6
|
+
import { isEqualPaths, isEqualSelectionPoints } from "@portabletext/editor/utils";
|
|
7
|
+
import { createKeyboardShortcut } from "@portabletext/keyboard-shortcuts";
|
|
8
|
+
import { defineInputRuleBehavior, defineInputRule } from "@portabletext/plugin-input-rule";
|
|
9
|
+
import { setup, assign, sendTo, fromPromise, fromCallback } from "xstate";
|
|
10
|
+
function defineTypeaheadPicker(config) {
|
|
11
|
+
return {
|
|
12
|
+
...config,
|
|
13
|
+
_id: /* @__PURE__ */ Symbol("typeahead-picker")
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function extractKeywordFromPattern(matchedText, pattern, autoCompleteWith) {
|
|
17
|
+
if (autoCompleteWith && matchedText.endsWith(autoCompleteWith)) {
|
|
18
|
+
const strippedMatch = matchedText.slice(0, -autoCompleteWith.length).match(pattern), strippedKeyword = strippedMatch ? strippedMatch[1] ?? strippedMatch[0] : "";
|
|
19
|
+
if (strippedKeyword.length > 0)
|
|
20
|
+
return strippedKeyword;
|
|
21
|
+
}
|
|
22
|
+
const match = matchedText.match(pattern);
|
|
23
|
+
return match ? match[1] ?? match[0] : matchedText;
|
|
24
|
+
}
|
|
25
|
+
function escapeRegExp(str) {
|
|
26
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27
|
+
}
|
|
28
|
+
function normalizePattern(pattern) {
|
|
29
|
+
return new RegExp(pattern.source);
|
|
30
|
+
}
|
|
31
|
+
function buildCompletePattern(definition) {
|
|
32
|
+
if (!definition.autoCompleteWith)
|
|
33
|
+
return;
|
|
34
|
+
const autoCompleteWith = escapeRegExp(definition.autoCompleteWith);
|
|
35
|
+
return new RegExp(`${definition.pattern.source}${autoCompleteWith}`);
|
|
36
|
+
}
|
|
37
|
+
const arrowUpShortcut = createKeyboardShortcut({
|
|
38
|
+
default: [{
|
|
39
|
+
key: "ArrowUp"
|
|
40
|
+
}]
|
|
41
|
+
}), arrowDownShortcut = createKeyboardShortcut({
|
|
42
|
+
default: [{
|
|
43
|
+
key: "ArrowDown"
|
|
44
|
+
}]
|
|
45
|
+
}), enterShortcut = createKeyboardShortcut({
|
|
46
|
+
default: [{
|
|
47
|
+
key: "Enter"
|
|
48
|
+
}]
|
|
49
|
+
}), tabShortcut = createKeyboardShortcut({
|
|
50
|
+
default: [{
|
|
51
|
+
key: "Tab"
|
|
52
|
+
}]
|
|
53
|
+
}), escapeShortcut = createKeyboardShortcut({
|
|
54
|
+
default: [{
|
|
55
|
+
key: "Escape"
|
|
56
|
+
}]
|
|
57
|
+
}), getTriggerState = (snapshot) => {
|
|
58
|
+
const focusSpan = getFocusSpan(snapshot), markState = getMarkState(snapshot);
|
|
59
|
+
if (!focusSpan || !markState || !snapshot.context.selection)
|
|
60
|
+
return;
|
|
61
|
+
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);
|
|
62
|
+
return {
|
|
63
|
+
focusSpan,
|
|
64
|
+
markState,
|
|
65
|
+
focusSpanTextBefore,
|
|
66
|
+
focusSpanTextAfter,
|
|
67
|
+
previousSpan,
|
|
68
|
+
nextSpan
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
function createTriggerActions({
|
|
72
|
+
snapshot,
|
|
73
|
+
payload,
|
|
74
|
+
keywordState,
|
|
75
|
+
pickerId
|
|
76
|
+
}) {
|
|
77
|
+
if (payload.markState.state === "unchanged") {
|
|
78
|
+
const textBeforeMatch = payload.focusSpanTextBefore.slice(0, payload.lastMatch.targetOffsets.anchor.offset), focusSpan2 = {
|
|
79
|
+
node: {
|
|
80
|
+
_key: payload.focusSpan.node._key,
|
|
81
|
+
_type: payload.focusSpan.node._type,
|
|
82
|
+
text: `${textBeforeMatch}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,
|
|
83
|
+
marks: payload.markState.marks
|
|
84
|
+
},
|
|
85
|
+
path: payload.focusSpan.path,
|
|
86
|
+
textBefore: textBeforeMatch,
|
|
87
|
+
textAfter: payload.focusSpanTextAfter
|
|
88
|
+
};
|
|
89
|
+
return keywordState === "complete" ? [raise(createKeywordFoundEvent({
|
|
90
|
+
focusSpan: focusSpan2,
|
|
91
|
+
extractedKeyword: payload.extractedKeyword,
|
|
92
|
+
pickerId
|
|
93
|
+
}))] : [raise(createTriggerFoundEvent({
|
|
94
|
+
focusSpan: focusSpan2,
|
|
95
|
+
extractedKeyword: payload.extractedKeyword,
|
|
96
|
+
pickerId
|
|
97
|
+
}))];
|
|
98
|
+
}
|
|
99
|
+
const newSpan = {
|
|
100
|
+
_key: snapshot.context.keyGenerator(),
|
|
101
|
+
_type: payload.focusSpan.node._type,
|
|
102
|
+
text: payload.lastMatch.text,
|
|
103
|
+
marks: payload.markState.marks
|
|
104
|
+
};
|
|
105
|
+
let focusSpan = {
|
|
106
|
+
node: {
|
|
107
|
+
_key: newSpan._key,
|
|
108
|
+
_type: newSpan._type,
|
|
109
|
+
text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,
|
|
110
|
+
marks: payload.markState.marks
|
|
111
|
+
},
|
|
112
|
+
path: [{
|
|
113
|
+
_key: payload.focusSpan.path[0]._key
|
|
114
|
+
}, "children", {
|
|
115
|
+
_key: newSpan._key
|
|
116
|
+
}],
|
|
117
|
+
textBefore: "",
|
|
118
|
+
textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter
|
|
119
|
+
};
|
|
120
|
+
return payload.previousSpan && payload.focusSpanTextBefore.length === 0 && JSON.stringify(payload.previousSpan.node.marks ?? []) === JSON.stringify(payload.markState.marks) && (focusSpan = {
|
|
121
|
+
node: {
|
|
122
|
+
_key: payload.previousSpan.node._key,
|
|
123
|
+
_type: newSpan._type,
|
|
124
|
+
text: `${payload.previousSpan.node.text}${newSpan.text}`,
|
|
125
|
+
marks: newSpan.marks
|
|
126
|
+
},
|
|
127
|
+
path: payload.previousSpan.path,
|
|
128
|
+
textBefore: payload.previousSpan.node.text,
|
|
129
|
+
textAfter: ""
|
|
130
|
+
}), [raise({
|
|
131
|
+
type: "select",
|
|
132
|
+
at: payload.lastMatch.targetOffsets
|
|
133
|
+
}), raise({
|
|
134
|
+
type: "delete",
|
|
135
|
+
at: payload.lastMatch.targetOffsets
|
|
136
|
+
}), raise({
|
|
137
|
+
type: "insert.child",
|
|
138
|
+
child: newSpan
|
|
139
|
+
}), ...keywordState === "complete" ? [raise(createKeywordFoundEvent({
|
|
140
|
+
focusSpan,
|
|
141
|
+
extractedKeyword: payload.extractedKeyword,
|
|
142
|
+
pickerId
|
|
143
|
+
}))] : [raise(createTriggerFoundEvent({
|
|
144
|
+
focusSpan,
|
|
145
|
+
extractedKeyword: payload.extractedKeyword,
|
|
146
|
+
pickerId
|
|
147
|
+
}))]];
|
|
148
|
+
}
|
|
149
|
+
function createTriggerFoundEvent(payload) {
|
|
150
|
+
return {
|
|
151
|
+
type: "custom.typeahead trigger found",
|
|
152
|
+
...payload
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function createKeywordFoundEvent(payload) {
|
|
156
|
+
return {
|
|
157
|
+
type: "custom.typeahead keyword found",
|
|
158
|
+
...payload
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function extractFullMatchFromFocusSpan(focusSpan) {
|
|
162
|
+
return focusSpan.textBefore.length > 0 && focusSpan.textAfter.length > 0 ? focusSpan.node.text.slice(focusSpan.textBefore.length, -focusSpan.textAfter.length) : focusSpan.textBefore.length > 0 ? focusSpan.node.text.slice(focusSpan.textBefore.length) : focusSpan.textAfter.length > 0 ? focusSpan.node.text.slice(0, -focusSpan.textAfter.length) : focusSpan.node.text;
|
|
163
|
+
}
|
|
164
|
+
function validateFocusSpan(currentFocusSpan, editor, partialPattern, completePattern) {
|
|
165
|
+
const snapshot = editor.getSnapshot(), focusSpan = getFocusSpan(snapshot);
|
|
166
|
+
if (!snapshot.context.selection || !focusSpan)
|
|
167
|
+
return;
|
|
168
|
+
const nextSpan = getNextSpan({
|
|
169
|
+
...snapshot,
|
|
170
|
+
context: {
|
|
171
|
+
...snapshot.context,
|
|
172
|
+
selection: {
|
|
173
|
+
anchor: {
|
|
174
|
+
path: currentFocusSpan.path,
|
|
175
|
+
offset: 0
|
|
176
|
+
},
|
|
177
|
+
focus: {
|
|
178
|
+
path: currentFocusSpan.path,
|
|
179
|
+
offset: 0
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
if (!isEqualPaths(focusSpan.path, currentFocusSpan.path))
|
|
185
|
+
return nextSpan && currentFocusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && isSelectionCollapsed(snapshot) ? currentFocusSpan : void 0;
|
|
186
|
+
if (!focusSpan.node.text.startsWith(currentFocusSpan.textBefore) || !focusSpan.node.text.endsWith(currentFocusSpan.textAfter))
|
|
187
|
+
return;
|
|
188
|
+
const keywordAnchor = {
|
|
189
|
+
path: focusSpan.path,
|
|
190
|
+
offset: currentFocusSpan.textBefore.length
|
|
191
|
+
}, keywordFocus = {
|
|
192
|
+
path: focusSpan.path,
|
|
193
|
+
offset: focusSpan.node.text.length - currentFocusSpan.textAfter.length
|
|
194
|
+
}, selectionIsBeforeKeyword = isPointAfterSelection(keywordAnchor)(snapshot), selectionIsAfterKeyword = isPointBeforeSelection(keywordFocus)(snapshot);
|
|
195
|
+
if (selectionIsBeforeKeyword || selectionIsAfterKeyword)
|
|
196
|
+
return;
|
|
197
|
+
const keywordText = focusSpan.node.text.slice(currentFocusSpan.textBefore.length, currentFocusSpan.textAfter.length > 0 ? -currentFocusSpan.textAfter.length : void 0), patternMatch = keywordText.match(partialPattern);
|
|
198
|
+
if (!patternMatch || patternMatch.index !== 0)
|
|
199
|
+
return;
|
|
200
|
+
let matchEnd = currentFocusSpan.textBefore.length + patternMatch[0].length;
|
|
201
|
+
if (completePattern) {
|
|
202
|
+
const completeMatch = keywordText.match(completePattern);
|
|
203
|
+
completeMatch && completeMatch.index === 0 && completeMatch[0] === keywordText && (matchEnd = currentFocusSpan.textBefore.length + completeMatch[0].length);
|
|
204
|
+
}
|
|
205
|
+
if (!(snapshot.context.selection.focus.offset > matchEnd))
|
|
206
|
+
return {
|
|
207
|
+
node: focusSpan.node,
|
|
208
|
+
path: focusSpan.path,
|
|
209
|
+
textBefore: currentFocusSpan.textBefore,
|
|
210
|
+
textAfter: currentFocusSpan.textAfter
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function extractKeywordFromMatch(match, pattern, autoCompleteWith) {
|
|
214
|
+
const firstGroupMatch = match.groupMatches[0];
|
|
215
|
+
return firstGroupMatch && firstGroupMatch.text.length > 0 ? firstGroupMatch.text : extractKeywordFromPattern(match.text, pattern, autoCompleteWith);
|
|
216
|
+
}
|
|
217
|
+
function createInputRules(definition) {
|
|
218
|
+
const rules = [], partialPattern = definition.pattern, completePattern = buildCompletePattern(definition);
|
|
219
|
+
if (completePattern) {
|
|
220
|
+
const completeTriggerRule = defineInputRule({
|
|
221
|
+
on: completePattern,
|
|
222
|
+
guard: ({
|
|
223
|
+
snapshot,
|
|
224
|
+
event
|
|
225
|
+
}) => {
|
|
226
|
+
const lastMatch = event.matches.at(-1);
|
|
227
|
+
if (!lastMatch || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
|
|
228
|
+
return !1;
|
|
229
|
+
const triggerState = getTriggerState(snapshot);
|
|
230
|
+
return triggerState ? {
|
|
231
|
+
...triggerState,
|
|
232
|
+
lastMatch,
|
|
233
|
+
extractedKeyword: extractKeywordFromMatch(lastMatch, partialPattern, definition.autoCompleteWith)
|
|
234
|
+
} : !1;
|
|
235
|
+
},
|
|
236
|
+
actions: [({
|
|
237
|
+
snapshot
|
|
238
|
+
}, payload) => createTriggerActions({
|
|
239
|
+
snapshot,
|
|
240
|
+
payload,
|
|
241
|
+
keywordState: "complete",
|
|
242
|
+
pickerId: definition._id
|
|
243
|
+
})]
|
|
244
|
+
});
|
|
245
|
+
rules.push(completeTriggerRule);
|
|
246
|
+
}
|
|
247
|
+
const partialTriggerRule = defineInputRule({
|
|
248
|
+
on: partialPattern,
|
|
249
|
+
guard: ({
|
|
250
|
+
snapshot,
|
|
251
|
+
event
|
|
252
|
+
}) => {
|
|
253
|
+
const lastMatch = event.matches.at(-1);
|
|
254
|
+
if (!lastMatch || lastMatch.targetOffsets.anchor.offset < event.textBefore.length)
|
|
255
|
+
return !1;
|
|
256
|
+
const triggerState = getTriggerState(snapshot);
|
|
257
|
+
if (!triggerState)
|
|
258
|
+
return !1;
|
|
259
|
+
if (completePattern) {
|
|
260
|
+
const completeMatch = triggerState.focusSpan.node.text.slice(lastMatch.targetOffsets.anchor.offset).match(completePattern);
|
|
261
|
+
if (completeMatch && completeMatch.index === 0)
|
|
262
|
+
return !1;
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
...triggerState,
|
|
266
|
+
lastMatch,
|
|
267
|
+
extractedKeyword: extractKeywordFromMatch(lastMatch, partialPattern, definition.autoCompleteWith)
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
actions: [({
|
|
271
|
+
snapshot
|
|
272
|
+
}, payload) => createTriggerActions({
|
|
273
|
+
snapshot,
|
|
274
|
+
payload,
|
|
275
|
+
keywordState: "partial",
|
|
276
|
+
pickerId: definition._id
|
|
277
|
+
})]
|
|
278
|
+
});
|
|
279
|
+
return rules.push(partialTriggerRule), rules;
|
|
280
|
+
}
|
|
281
|
+
const triggerListenerCallback = () => ({
|
|
282
|
+
sendBack,
|
|
283
|
+
input
|
|
284
|
+
}) => {
|
|
285
|
+
const rules = createInputRules(input.definition), unregisterBehaviors = [input.editor.registerBehavior({
|
|
286
|
+
behavior: defineInputRuleBehavior({
|
|
287
|
+
rules
|
|
288
|
+
})
|
|
289
|
+
}), input.editor.registerBehavior({
|
|
290
|
+
behavior: defineBehavior({
|
|
291
|
+
on: "custom.typeahead keyword found",
|
|
292
|
+
guard: ({
|
|
293
|
+
event
|
|
294
|
+
}) => event.pickerId === input.definition._id,
|
|
295
|
+
actions: [({
|
|
296
|
+
event
|
|
297
|
+
}) => [effect(() => {
|
|
298
|
+
sendBack(event);
|
|
299
|
+
})]]
|
|
300
|
+
})
|
|
301
|
+
}), input.editor.registerBehavior({
|
|
302
|
+
behavior: defineBehavior({
|
|
303
|
+
on: "custom.typeahead trigger found",
|
|
304
|
+
guard: ({
|
|
305
|
+
event
|
|
306
|
+
}) => event.pickerId === input.definition._id,
|
|
307
|
+
actions: [({
|
|
308
|
+
event
|
|
309
|
+
}) => [effect(() => {
|
|
310
|
+
sendBack(event);
|
|
311
|
+
})]]
|
|
312
|
+
})
|
|
313
|
+
})];
|
|
314
|
+
return () => {
|
|
315
|
+
for (const unregister of unregisterBehaviors)
|
|
316
|
+
unregister();
|
|
317
|
+
};
|
|
318
|
+
}, escapeListenerCallback = () => ({
|
|
319
|
+
sendBack,
|
|
320
|
+
input
|
|
321
|
+
}) => input.editor.registerBehavior({
|
|
322
|
+
behavior: defineBehavior({
|
|
323
|
+
on: "keyboard.keydown",
|
|
324
|
+
guard: ({
|
|
325
|
+
event
|
|
326
|
+
}) => escapeShortcut.guard(event.originEvent),
|
|
327
|
+
actions: [() => [effect(() => {
|
|
328
|
+
sendBack({
|
|
329
|
+
type: "dismiss"
|
|
330
|
+
});
|
|
331
|
+
})]]
|
|
332
|
+
})
|
|
333
|
+
}), arrowListenerCallback = () => ({
|
|
334
|
+
sendBack,
|
|
335
|
+
input
|
|
336
|
+
}) => {
|
|
337
|
+
const unregisterBehaviors = [input.editor.registerBehavior({
|
|
338
|
+
behavior: defineBehavior({
|
|
339
|
+
on: "keyboard.keydown",
|
|
340
|
+
guard: ({
|
|
341
|
+
event
|
|
342
|
+
}) => arrowDownShortcut.guard(event.originEvent),
|
|
343
|
+
actions: [() => [effect(() => {
|
|
344
|
+
sendBack({
|
|
345
|
+
type: "navigate down"
|
|
346
|
+
});
|
|
347
|
+
})]]
|
|
348
|
+
})
|
|
349
|
+
}), input.editor.registerBehavior({
|
|
350
|
+
behavior: defineBehavior({
|
|
351
|
+
on: "keyboard.keydown",
|
|
352
|
+
guard: ({
|
|
353
|
+
event
|
|
354
|
+
}) => arrowUpShortcut.guard(event.originEvent),
|
|
355
|
+
actions: [() => [effect(() => {
|
|
356
|
+
sendBack({
|
|
357
|
+
type: "navigate up"
|
|
358
|
+
});
|
|
359
|
+
})]]
|
|
360
|
+
})
|
|
361
|
+
})];
|
|
362
|
+
return () => {
|
|
363
|
+
for (const unregister of unregisterBehaviors)
|
|
364
|
+
unregister();
|
|
365
|
+
};
|
|
366
|
+
}, selectionListenerCallback = () => ({
|
|
367
|
+
sendBack,
|
|
368
|
+
input
|
|
369
|
+
}) => input.editor.on("selection", () => {
|
|
370
|
+
sendBack({
|
|
371
|
+
type: "selection changed"
|
|
372
|
+
});
|
|
373
|
+
}).unsubscribe, submitListenerCallback = () => ({
|
|
374
|
+
sendBack,
|
|
375
|
+
input,
|
|
376
|
+
receive
|
|
377
|
+
}) => {
|
|
378
|
+
let context = input.context;
|
|
379
|
+
receive((event) => {
|
|
380
|
+
context = event.context;
|
|
381
|
+
});
|
|
382
|
+
const unregisterBehaviors = [input.context.editor.registerBehavior({
|
|
383
|
+
behavior: defineBehavior({
|
|
384
|
+
on: "keyboard.keydown",
|
|
385
|
+
guard: ({
|
|
386
|
+
event
|
|
387
|
+
}) => {
|
|
388
|
+
if (!enterShortcut.guard(event.originEvent) && !tabShortcut.guard(event.originEvent))
|
|
389
|
+
return !1;
|
|
390
|
+
const focusSpan = context.focusSpan, match = context.matches[context.selectedIndex];
|
|
391
|
+
return match && focusSpan ? {
|
|
392
|
+
focusSpan,
|
|
393
|
+
match
|
|
394
|
+
} : !1;
|
|
395
|
+
},
|
|
396
|
+
actions: [() => [effect(() => {
|
|
397
|
+
sendBack({
|
|
398
|
+
type: "select"
|
|
399
|
+
});
|
|
400
|
+
})]]
|
|
401
|
+
})
|
|
402
|
+
}), input.context.editor.registerBehavior({
|
|
403
|
+
behavior: defineBehavior({
|
|
404
|
+
on: "keyboard.keydown",
|
|
405
|
+
guard: ({
|
|
406
|
+
event
|
|
407
|
+
}) => (enterShortcut.guard(event.originEvent) || tabShortcut.guard(event.originEvent)) && context.fullMatch.length === 1,
|
|
408
|
+
actions: [({
|
|
409
|
+
event
|
|
410
|
+
}) => [forward(event), effect(() => {
|
|
411
|
+
sendBack({
|
|
412
|
+
type: "dismiss"
|
|
413
|
+
});
|
|
414
|
+
})]]
|
|
415
|
+
})
|
|
416
|
+
}), input.context.editor.registerBehavior({
|
|
417
|
+
behavior: defineBehavior({
|
|
418
|
+
on: "keyboard.keydown",
|
|
419
|
+
guard: ({
|
|
420
|
+
event
|
|
421
|
+
}) => (enterShortcut.guard(event.originEvent) || tabShortcut.guard(event.originEvent)) && context.fullMatch.length > 1 && context.matches.length === 0,
|
|
422
|
+
actions: [() => [effect(() => {
|
|
423
|
+
sendBack({
|
|
424
|
+
type: "dismiss"
|
|
425
|
+
});
|
|
426
|
+
})]]
|
|
427
|
+
})
|
|
428
|
+
})];
|
|
429
|
+
return () => {
|
|
430
|
+
for (const unregister of unregisterBehaviors)
|
|
431
|
+
unregister();
|
|
432
|
+
};
|
|
433
|
+
}, textInsertionListenerCallback = () => ({
|
|
434
|
+
sendBack,
|
|
435
|
+
input,
|
|
436
|
+
receive
|
|
437
|
+
}) => {
|
|
438
|
+
let context = input.context;
|
|
439
|
+
return receive((event) => {
|
|
440
|
+
context = event.context;
|
|
441
|
+
}), input.context.editor.registerBehavior({
|
|
442
|
+
behavior: defineBehavior({
|
|
443
|
+
on: "insert.text",
|
|
444
|
+
guard: ({
|
|
445
|
+
snapshot
|
|
446
|
+
}) => {
|
|
447
|
+
if (!context.focusSpan || !snapshot.context.selection)
|
|
448
|
+
return !1;
|
|
449
|
+
const keywordAnchor = {
|
|
450
|
+
path: context.focusSpan.path,
|
|
451
|
+
offset: context.focusSpan.textBefore.length
|
|
452
|
+
};
|
|
453
|
+
return isEqualSelectionPoints(snapshot.context.selection.focus, keywordAnchor);
|
|
454
|
+
},
|
|
455
|
+
actions: [({
|
|
456
|
+
event
|
|
457
|
+
}) => [forward(event), effect(() => {
|
|
458
|
+
sendBack({
|
|
459
|
+
type: "dismiss"
|
|
460
|
+
});
|
|
461
|
+
})]]
|
|
462
|
+
})
|
|
463
|
+
});
|
|
464
|
+
}, insertMatchListenerCallback = () => ({
|
|
465
|
+
sendBack,
|
|
466
|
+
input
|
|
467
|
+
}) => input.context.editor.registerBehavior({
|
|
468
|
+
behavior: defineBehavior({
|
|
469
|
+
on: "custom.typeahead insert match",
|
|
470
|
+
guard: ({
|
|
471
|
+
event
|
|
472
|
+
}) => event.pickerId === input.context.definition._id,
|
|
473
|
+
actions: [({
|
|
474
|
+
event,
|
|
475
|
+
snapshot,
|
|
476
|
+
dom
|
|
477
|
+
}) => {
|
|
478
|
+
const patternSelection = {
|
|
479
|
+
anchor: {
|
|
480
|
+
path: event.focusSpan.path,
|
|
481
|
+
offset: event.focusSpan.textBefore.length
|
|
482
|
+
},
|
|
483
|
+
focus: {
|
|
484
|
+
path: event.focusSpan.path,
|
|
485
|
+
offset: event.focusSpan.node.text.length - event.focusSpan.textAfter.length
|
|
486
|
+
}
|
|
487
|
+
}, allActions = [effect(() => {
|
|
488
|
+
sendBack({
|
|
489
|
+
type: "dismiss"
|
|
490
|
+
});
|
|
491
|
+
})];
|
|
492
|
+
for (const actionSet of input.context.definition.actions) {
|
|
493
|
+
const actions = actionSet({
|
|
494
|
+
snapshot,
|
|
495
|
+
dom,
|
|
496
|
+
event: {
|
|
497
|
+
type: "typeahead.select",
|
|
498
|
+
match: event.match,
|
|
499
|
+
keyword: event.keyword,
|
|
500
|
+
patternSelection
|
|
501
|
+
}
|
|
502
|
+
}, !0);
|
|
503
|
+
for (const action of actions)
|
|
504
|
+
allActions.push(action);
|
|
505
|
+
}
|
|
506
|
+
return allActions.push(effect(() => {
|
|
507
|
+
queueMicrotask(() => {
|
|
508
|
+
const currentSelection = input.context.editor.getSnapshot().context.selection;
|
|
509
|
+
currentSelection && input.context.editor.send({
|
|
510
|
+
type: "select",
|
|
511
|
+
at: currentSelection
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
})), allActions;
|
|
515
|
+
}]
|
|
516
|
+
})
|
|
517
|
+
});
|
|
518
|
+
function createTypeaheadPickerMachine() {
|
|
519
|
+
return setup({
|
|
520
|
+
types: {
|
|
521
|
+
context: {},
|
|
522
|
+
input: {},
|
|
523
|
+
events: {}
|
|
524
|
+
},
|
|
525
|
+
delays: {
|
|
526
|
+
DEBOUNCE: ({
|
|
527
|
+
context
|
|
528
|
+
}) => context.definition.debounceMs ?? 0
|
|
529
|
+
},
|
|
530
|
+
actors: {
|
|
531
|
+
"trigger listener": fromCallback(triggerListenerCallback()),
|
|
532
|
+
"escape listener": fromCallback(escapeListenerCallback()),
|
|
533
|
+
"arrow listener": fromCallback(arrowListenerCallback()),
|
|
534
|
+
"selection listener": fromCallback(selectionListenerCallback()),
|
|
535
|
+
"submit listener": fromCallback(submitListenerCallback()),
|
|
536
|
+
"text insertion listener": fromCallback(textInsertionListenerCallback()),
|
|
537
|
+
"insert match listener": fromCallback(insertMatchListenerCallback()),
|
|
538
|
+
"get matches": fromPromise(async ({
|
|
539
|
+
input
|
|
540
|
+
}) => {
|
|
541
|
+
const result = input.getMatches({
|
|
542
|
+
keyword: input.keyword
|
|
543
|
+
}), matches = await Promise.resolve(result);
|
|
544
|
+
return {
|
|
545
|
+
keyword: input.keyword,
|
|
546
|
+
matches
|
|
547
|
+
};
|
|
548
|
+
})
|
|
549
|
+
},
|
|
550
|
+
actions: {
|
|
551
|
+
"handle trigger found": assign(({
|
|
552
|
+
context,
|
|
553
|
+
event
|
|
554
|
+
}) => {
|
|
555
|
+
if (event.type !== "custom.typeahead trigger found" && event.type !== "custom.typeahead keyword found")
|
|
556
|
+
return {};
|
|
557
|
+
const focusSpan = event.focusSpan, fullMatch = extractFullMatchFromFocusSpan(focusSpan), keyword = event.extractedKeyword;
|
|
558
|
+
if (context.definition.mode === "async" || context.definition.debounceMs)
|
|
559
|
+
return {
|
|
560
|
+
focusSpan,
|
|
561
|
+
fullMatch,
|
|
562
|
+
keyword,
|
|
563
|
+
isLoading: !0,
|
|
564
|
+
selectedIndex: 0
|
|
565
|
+
};
|
|
566
|
+
const matches = context.definition.getMatches({
|
|
567
|
+
keyword
|
|
568
|
+
});
|
|
569
|
+
return {
|
|
570
|
+
focusSpan,
|
|
571
|
+
fullMatch,
|
|
572
|
+
keyword,
|
|
573
|
+
matches,
|
|
574
|
+
loadingFullMatch: fullMatch,
|
|
575
|
+
isLoading: !1,
|
|
576
|
+
selectedIndex: 0
|
|
577
|
+
};
|
|
578
|
+
}),
|
|
579
|
+
"handle selection changed": assign(({
|
|
580
|
+
context
|
|
581
|
+
}) => {
|
|
582
|
+
if (!context.focusSpan)
|
|
583
|
+
return {
|
|
584
|
+
focusSpan: void 0,
|
|
585
|
+
fullMatch: "",
|
|
586
|
+
keyword: "",
|
|
587
|
+
matches: [],
|
|
588
|
+
selectedIndex: 0,
|
|
589
|
+
isLoading: !1
|
|
590
|
+
};
|
|
591
|
+
const updatedFocusSpan = validateFocusSpan(context.focusSpan, context.editor, context.partialPattern, context.completePattern);
|
|
592
|
+
if (!updatedFocusSpan)
|
|
593
|
+
return {
|
|
594
|
+
focusSpan: void 0,
|
|
595
|
+
fullMatch: "",
|
|
596
|
+
keyword: "",
|
|
597
|
+
matches: [],
|
|
598
|
+
selectedIndex: 0,
|
|
599
|
+
isLoading: !1
|
|
600
|
+
};
|
|
601
|
+
const fullMatch = extractFullMatchFromFocusSpan(updatedFocusSpan);
|
|
602
|
+
if (fullMatch === context.fullMatch)
|
|
603
|
+
return {
|
|
604
|
+
focusSpan: updatedFocusSpan
|
|
605
|
+
};
|
|
606
|
+
const keyword = extractKeywordFromPattern(fullMatch, context.definition.pattern, context.definition.autoCompleteWith);
|
|
607
|
+
if (context.definition.mode === "async" || context.definition.debounceMs)
|
|
608
|
+
return {
|
|
609
|
+
focusSpan: updatedFocusSpan,
|
|
610
|
+
fullMatch,
|
|
611
|
+
keyword,
|
|
612
|
+
selectedIndex: 0,
|
|
613
|
+
isLoading: context.isLoading || context.loadingFullMatch !== fullMatch
|
|
614
|
+
};
|
|
615
|
+
const matches = context.definition.getMatches({
|
|
616
|
+
keyword
|
|
617
|
+
});
|
|
618
|
+
return {
|
|
619
|
+
focusSpan: updatedFocusSpan,
|
|
620
|
+
fullMatch,
|
|
621
|
+
keyword,
|
|
622
|
+
matches,
|
|
623
|
+
loadingFullMatch: fullMatch,
|
|
624
|
+
selectedIndex: 0,
|
|
625
|
+
isLoading: !1
|
|
626
|
+
};
|
|
627
|
+
}),
|
|
628
|
+
"handle async load complete": assign(({
|
|
629
|
+
context,
|
|
630
|
+
event
|
|
631
|
+
}) => {
|
|
632
|
+
const output = event.output;
|
|
633
|
+
return output.keyword !== context.keyword ? {
|
|
634
|
+
isLoading: context.fullMatch !== context.loadingFullMatch
|
|
635
|
+
} : {
|
|
636
|
+
matches: output.matches,
|
|
637
|
+
isLoading: context.fullMatch !== context.loadingFullMatch
|
|
638
|
+
};
|
|
639
|
+
}),
|
|
640
|
+
reset: assign({
|
|
641
|
+
fullMatch: "",
|
|
642
|
+
keyword: "",
|
|
643
|
+
matches: [],
|
|
644
|
+
selectedIndex: 0,
|
|
645
|
+
isLoading: !1,
|
|
646
|
+
loadingFullMatch: "",
|
|
647
|
+
focusSpan: void 0,
|
|
648
|
+
error: void 0
|
|
649
|
+
}),
|
|
650
|
+
navigate: assign(({
|
|
651
|
+
context,
|
|
652
|
+
event
|
|
653
|
+
}) => context.matches.length === 0 ? {
|
|
654
|
+
selectedIndex: 0
|
|
655
|
+
} : event.type === "navigate to" ? {
|
|
656
|
+
selectedIndex: event.index
|
|
657
|
+
} : event.type === "navigate up" ? {
|
|
658
|
+
selectedIndex: (context.selectedIndex - 1 + context.matches.length) % context.matches.length
|
|
659
|
+
} : {
|
|
660
|
+
selectedIndex: (context.selectedIndex + 1) % context.matches.length
|
|
661
|
+
}),
|
|
662
|
+
"insert match": ({
|
|
663
|
+
context
|
|
664
|
+
}, params) => {
|
|
665
|
+
if (!context.focusSpan)
|
|
666
|
+
return;
|
|
667
|
+
const match = params.exact ? getExactMatch(context.matches) : context.matches[context.selectedIndex];
|
|
668
|
+
match && context.editor.send({
|
|
669
|
+
type: "custom.typeahead insert match",
|
|
670
|
+
match,
|
|
671
|
+
focusSpan: context.focusSpan,
|
|
672
|
+
keyword: context.keyword,
|
|
673
|
+
pickerId: context.definition._id
|
|
674
|
+
});
|
|
675
|
+
},
|
|
676
|
+
"update submit listener context": sendTo("submit listener", ({
|
|
677
|
+
context
|
|
678
|
+
}) => ({
|
|
679
|
+
type: "context changed",
|
|
680
|
+
context
|
|
681
|
+
})),
|
|
682
|
+
"update text insertion listener context": sendTo("text insertion listener", ({
|
|
683
|
+
context
|
|
684
|
+
}) => ({
|
|
685
|
+
type: "context changed",
|
|
686
|
+
context
|
|
687
|
+
})),
|
|
688
|
+
"handle error": assign({
|
|
689
|
+
isLoading: !1,
|
|
690
|
+
error: ({
|
|
691
|
+
event
|
|
692
|
+
}) => event.error
|
|
693
|
+
})
|
|
694
|
+
},
|
|
695
|
+
guards: {
|
|
696
|
+
"no focus span": ({
|
|
697
|
+
context
|
|
698
|
+
}) => !context.focusSpan,
|
|
699
|
+
"no debounce": ({
|
|
700
|
+
context
|
|
701
|
+
}) => !context.definition.debounceMs || context.definition.debounceMs === 0,
|
|
702
|
+
"is complete keyword": ({
|
|
703
|
+
context
|
|
704
|
+
}) => {
|
|
705
|
+
if (!context.completePattern || !context.focusSpan)
|
|
706
|
+
return !1;
|
|
707
|
+
const fullKeywordText = context.focusSpan.node.text.slice(context.focusSpan.textBefore.length, context.focusSpan.textAfter.length > 0 ? -context.focusSpan.textAfter.length : void 0), completeMatch = fullKeywordText.match(context.completePattern);
|
|
708
|
+
return !completeMatch || completeMatch.index !== 0 || completeMatch[0] !== fullKeywordText ? !1 : hasExactlyOneExactMatch(context.matches);
|
|
709
|
+
},
|
|
710
|
+
"has matches": ({
|
|
711
|
+
context
|
|
712
|
+
}) => context.matches.length > 0,
|
|
713
|
+
"no matches": ({
|
|
714
|
+
context
|
|
715
|
+
}) => context.matches.length === 0,
|
|
716
|
+
"is loading": ({
|
|
717
|
+
context
|
|
718
|
+
}) => context.isLoading
|
|
719
|
+
}
|
|
720
|
+
}).createMachine({
|
|
721
|
+
id: "typeahead picker",
|
|
722
|
+
context: ({
|
|
723
|
+
input
|
|
724
|
+
}) => ({
|
|
725
|
+
editor: input.editor,
|
|
726
|
+
definition: input.definition,
|
|
727
|
+
partialPattern: normalizePattern(input.definition.pattern),
|
|
728
|
+
completePattern: buildCompletePattern(input.definition),
|
|
729
|
+
matches: [],
|
|
730
|
+
selectedIndex: 0,
|
|
731
|
+
focusSpan: void 0,
|
|
732
|
+
fullMatch: "",
|
|
733
|
+
keyword: "",
|
|
734
|
+
loadingFullMatch: "",
|
|
735
|
+
error: void 0,
|
|
736
|
+
isLoading: !1
|
|
737
|
+
}),
|
|
738
|
+
initial: "idle",
|
|
739
|
+
states: {
|
|
740
|
+
idle: {
|
|
741
|
+
entry: ["reset"],
|
|
742
|
+
invoke: {
|
|
743
|
+
src: "trigger listener",
|
|
744
|
+
input: ({
|
|
745
|
+
context
|
|
746
|
+
}) => ({
|
|
747
|
+
editor: context.editor,
|
|
748
|
+
definition: context.definition
|
|
749
|
+
})
|
|
750
|
+
},
|
|
751
|
+
on: {
|
|
752
|
+
"custom.typeahead trigger found": {
|
|
753
|
+
target: "active",
|
|
754
|
+
actions: ["handle trigger found"]
|
|
755
|
+
},
|
|
756
|
+
"custom.typeahead keyword found": {
|
|
757
|
+
target: "checking complete",
|
|
758
|
+
actions: ["handle trigger found"]
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
},
|
|
762
|
+
"checking complete": {
|
|
763
|
+
invoke: [{
|
|
764
|
+
src: "insert match listener",
|
|
765
|
+
input: ({
|
|
766
|
+
context
|
|
767
|
+
}) => ({
|
|
768
|
+
context
|
|
769
|
+
})
|
|
770
|
+
}, {
|
|
771
|
+
src: "get matches",
|
|
772
|
+
input: ({
|
|
773
|
+
context
|
|
774
|
+
}) => ({
|
|
775
|
+
keyword: context.keyword,
|
|
776
|
+
getMatches: context.definition.getMatches
|
|
777
|
+
}),
|
|
778
|
+
onDone: [{
|
|
779
|
+
guard: ({
|
|
780
|
+
event
|
|
781
|
+
}) => hasExactlyOneExactMatch(event.output.matches),
|
|
782
|
+
target: "idle",
|
|
783
|
+
actions: [assign({
|
|
784
|
+
matches: ({
|
|
785
|
+
event
|
|
786
|
+
}) => event.output.matches
|
|
787
|
+
}), {
|
|
788
|
+
type: "insert match",
|
|
789
|
+
params: {
|
|
790
|
+
exact: !0
|
|
791
|
+
}
|
|
792
|
+
}]
|
|
793
|
+
}, {
|
|
794
|
+
target: "active",
|
|
795
|
+
actions: [assign({
|
|
796
|
+
matches: ({
|
|
797
|
+
event
|
|
798
|
+
}) => event.output.matches
|
|
799
|
+
})]
|
|
800
|
+
}],
|
|
801
|
+
onError: {
|
|
802
|
+
target: "active.no matches",
|
|
803
|
+
actions: ["handle error"]
|
|
804
|
+
}
|
|
805
|
+
}]
|
|
806
|
+
},
|
|
807
|
+
active: {
|
|
808
|
+
invoke: [{
|
|
809
|
+
src: "insert match listener",
|
|
810
|
+
input: ({
|
|
811
|
+
context
|
|
812
|
+
}) => ({
|
|
813
|
+
context
|
|
814
|
+
})
|
|
815
|
+
}, {
|
|
816
|
+
src: "escape listener",
|
|
817
|
+
input: ({
|
|
818
|
+
context
|
|
819
|
+
}) => ({
|
|
820
|
+
editor: context.editor
|
|
821
|
+
})
|
|
822
|
+
}, {
|
|
823
|
+
src: "selection listener",
|
|
824
|
+
input: ({
|
|
825
|
+
context
|
|
826
|
+
}) => ({
|
|
827
|
+
editor: context.editor
|
|
828
|
+
})
|
|
829
|
+
}, {
|
|
830
|
+
src: "submit listener",
|
|
831
|
+
id: "submit listener",
|
|
832
|
+
input: ({
|
|
833
|
+
context
|
|
834
|
+
}) => ({
|
|
835
|
+
context
|
|
836
|
+
})
|
|
837
|
+
}, {
|
|
838
|
+
src: "text insertion listener",
|
|
839
|
+
id: "text insertion listener",
|
|
840
|
+
input: ({
|
|
841
|
+
context
|
|
842
|
+
}) => ({
|
|
843
|
+
context
|
|
844
|
+
})
|
|
845
|
+
}],
|
|
846
|
+
on: {
|
|
847
|
+
dismiss: {
|
|
848
|
+
target: "idle"
|
|
849
|
+
},
|
|
850
|
+
"selection changed": {
|
|
851
|
+
actions: ["handle selection changed", "update submit listener context", "update text insertion listener context"]
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
always: [{
|
|
855
|
+
guard: "no focus span",
|
|
856
|
+
target: "idle"
|
|
857
|
+
}, {
|
|
858
|
+
guard: "is complete keyword",
|
|
859
|
+
actions: [{
|
|
860
|
+
type: "insert match",
|
|
861
|
+
params: {
|
|
862
|
+
exact: !1
|
|
863
|
+
}
|
|
864
|
+
}],
|
|
865
|
+
target: "idle"
|
|
866
|
+
}],
|
|
867
|
+
initial: "evaluating",
|
|
868
|
+
states: {
|
|
869
|
+
evaluating: {
|
|
870
|
+
always: [{
|
|
871
|
+
guard: "is loading",
|
|
872
|
+
target: "loading"
|
|
873
|
+
}, {
|
|
874
|
+
guard: "has matches",
|
|
875
|
+
target: "showing matches"
|
|
876
|
+
}, {
|
|
877
|
+
target: "no matches"
|
|
878
|
+
}]
|
|
879
|
+
},
|
|
880
|
+
loading: {
|
|
881
|
+
entry: [assign({
|
|
882
|
+
loadingFullMatch: ({
|
|
883
|
+
context
|
|
884
|
+
}) => context.fullMatch
|
|
885
|
+
})],
|
|
886
|
+
initial: "debouncing",
|
|
887
|
+
states: {
|
|
888
|
+
debouncing: {
|
|
889
|
+
always: [{
|
|
890
|
+
guard: "no debounce",
|
|
891
|
+
target: "fetching"
|
|
892
|
+
}],
|
|
893
|
+
after: {
|
|
894
|
+
DEBOUNCE: "fetching"
|
|
895
|
+
}
|
|
896
|
+
},
|
|
897
|
+
fetching: {
|
|
898
|
+
invoke: {
|
|
899
|
+
src: "get matches",
|
|
900
|
+
input: ({
|
|
901
|
+
context
|
|
902
|
+
}) => ({
|
|
903
|
+
keyword: context.keyword,
|
|
904
|
+
getMatches: context.definition.getMatches
|
|
905
|
+
}),
|
|
906
|
+
onDone: {
|
|
907
|
+
target: "#typeahead picker.active.evaluating",
|
|
908
|
+
actions: [assign(({
|
|
909
|
+
context,
|
|
910
|
+
event
|
|
911
|
+
}) => event.output.keyword !== context.keyword ? {
|
|
912
|
+
isLoading: context.fullMatch !== context.loadingFullMatch
|
|
913
|
+
} : {
|
|
914
|
+
matches: event.output.matches,
|
|
915
|
+
isLoading: context.fullMatch !== context.loadingFullMatch
|
|
916
|
+
})]
|
|
917
|
+
},
|
|
918
|
+
onError: {
|
|
919
|
+
target: "#typeahead picker.active.no matches",
|
|
920
|
+
actions: ["handle error"]
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
"no matches": {
|
|
927
|
+
entry: [assign({
|
|
928
|
+
selectedIndex: 0
|
|
929
|
+
})],
|
|
930
|
+
always: [{
|
|
931
|
+
guard: "has matches",
|
|
932
|
+
target: "showing matches"
|
|
933
|
+
}],
|
|
934
|
+
initial: "idle",
|
|
935
|
+
states: {
|
|
936
|
+
idle: {
|
|
937
|
+
always: [{
|
|
938
|
+
guard: "is loading",
|
|
939
|
+
target: "loading"
|
|
940
|
+
}]
|
|
941
|
+
},
|
|
942
|
+
loading: {
|
|
943
|
+
entry: [assign({
|
|
944
|
+
loadingFullMatch: ({
|
|
945
|
+
context
|
|
946
|
+
}) => context.fullMatch
|
|
947
|
+
})],
|
|
948
|
+
initial: "debouncing",
|
|
949
|
+
states: {
|
|
950
|
+
debouncing: {
|
|
951
|
+
always: [{
|
|
952
|
+
guard: "no debounce",
|
|
953
|
+
target: "fetching"
|
|
954
|
+
}],
|
|
955
|
+
after: {
|
|
956
|
+
DEBOUNCE: "fetching"
|
|
957
|
+
}
|
|
958
|
+
},
|
|
959
|
+
fetching: {
|
|
960
|
+
invoke: {
|
|
961
|
+
src: "get matches",
|
|
962
|
+
input: ({
|
|
963
|
+
context
|
|
964
|
+
}) => ({
|
|
965
|
+
keyword: context.keyword,
|
|
966
|
+
getMatches: context.definition.getMatches
|
|
967
|
+
}),
|
|
968
|
+
onDone: {
|
|
969
|
+
target: "#typeahead picker.active.no matches.idle",
|
|
970
|
+
actions: ["handle async load complete"]
|
|
971
|
+
},
|
|
972
|
+
onError: {
|
|
973
|
+
target: "#typeahead picker.active.no matches.idle",
|
|
974
|
+
actions: ["handle error"]
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
"showing matches": {
|
|
983
|
+
entry: ["update submit listener context", "update text insertion listener context"],
|
|
984
|
+
invoke: {
|
|
985
|
+
src: "arrow listener",
|
|
986
|
+
input: ({
|
|
987
|
+
context
|
|
988
|
+
}) => ({
|
|
989
|
+
editor: context.editor
|
|
990
|
+
})
|
|
991
|
+
},
|
|
992
|
+
always: [{
|
|
993
|
+
guard: "no matches",
|
|
994
|
+
target: "no matches"
|
|
995
|
+
}],
|
|
996
|
+
on: {
|
|
997
|
+
"navigate down": {
|
|
998
|
+
actions: ["navigate", "update submit listener context", "update text insertion listener context"]
|
|
999
|
+
},
|
|
1000
|
+
"navigate up": {
|
|
1001
|
+
actions: ["navigate", "update submit listener context", "update text insertion listener context"]
|
|
1002
|
+
},
|
|
1003
|
+
"navigate to": {
|
|
1004
|
+
actions: ["navigate", "update submit listener context", "update text insertion listener context"]
|
|
1005
|
+
},
|
|
1006
|
+
select: {
|
|
1007
|
+
target: "#typeahead picker.idle",
|
|
1008
|
+
actions: [{
|
|
1009
|
+
type: "insert match",
|
|
1010
|
+
params: {
|
|
1011
|
+
exact: !1
|
|
1012
|
+
}
|
|
1013
|
+
}]
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
initial: "idle",
|
|
1017
|
+
states: {
|
|
1018
|
+
idle: {
|
|
1019
|
+
always: [{
|
|
1020
|
+
guard: "is loading",
|
|
1021
|
+
target: "loading"
|
|
1022
|
+
}]
|
|
1023
|
+
},
|
|
1024
|
+
loading: {
|
|
1025
|
+
entry: [assign({
|
|
1026
|
+
loadingFullMatch: ({
|
|
1027
|
+
context
|
|
1028
|
+
}) => context.fullMatch
|
|
1029
|
+
})],
|
|
1030
|
+
initial: "debouncing",
|
|
1031
|
+
states: {
|
|
1032
|
+
debouncing: {
|
|
1033
|
+
always: [{
|
|
1034
|
+
guard: "no debounce",
|
|
1035
|
+
target: "fetching"
|
|
1036
|
+
}],
|
|
1037
|
+
after: {
|
|
1038
|
+
DEBOUNCE: "fetching"
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
fetching: {
|
|
1042
|
+
invoke: {
|
|
1043
|
+
src: "get matches",
|
|
1044
|
+
input: ({
|
|
1045
|
+
context
|
|
1046
|
+
}) => ({
|
|
1047
|
+
keyword: context.keyword,
|
|
1048
|
+
getMatches: context.definition.getMatches
|
|
1049
|
+
}),
|
|
1050
|
+
onDone: {
|
|
1051
|
+
target: "#typeahead picker.active.showing matches.idle",
|
|
1052
|
+
actions: ["handle async load complete"]
|
|
1053
|
+
},
|
|
1054
|
+
onError: {
|
|
1055
|
+
target: "#typeahead picker.active.showing matches.idle",
|
|
1056
|
+
actions: ["handle error"]
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
function hasExactlyOneExactMatch(matches) {
|
|
1070
|
+
return matches.filter((match) => match?.type === "exact").length === 1;
|
|
1071
|
+
}
|
|
1072
|
+
function getExactMatch(matches) {
|
|
1073
|
+
const exactMatches = matches.filter((match) => match?.type === "exact");
|
|
1074
|
+
return exactMatches.length === 1 ? exactMatches[0] : void 0;
|
|
1075
|
+
}
|
|
1076
|
+
function useTypeaheadPicker(definition) {
|
|
1077
|
+
const $ = c(19), editor = useEditor();
|
|
1078
|
+
let t0;
|
|
1079
|
+
$[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t0 = createTypeaheadPickerMachine(), $[0] = t0) : t0 = $[0];
|
|
1080
|
+
let t1;
|
|
1081
|
+
$[1] !== definition || $[2] !== editor ? (t1 = {
|
|
1082
|
+
input: {
|
|
1083
|
+
editor,
|
|
1084
|
+
definition
|
|
1085
|
+
}
|
|
1086
|
+
}, $[1] = definition, $[2] = editor, $[3] = t1) : t1 = $[3];
|
|
1087
|
+
const [actorSnapshot, send] = useActor(t0, t1);
|
|
1088
|
+
let t2;
|
|
1089
|
+
$[4] !== actorSnapshot ? (t2 = (state) => actorSnapshot.matches(state), $[4] = actorSnapshot, $[5] = t2) : t2 = $[5];
|
|
1090
|
+
const t3 = actorSnapshot.context.matches;
|
|
1091
|
+
let t4;
|
|
1092
|
+
$[6] !== actorSnapshot.context.error || $[7] !== actorSnapshot.context.keyword || $[8] !== actorSnapshot.context.selectedIndex || $[9] !== t3 ? (t4 = {
|
|
1093
|
+
keyword: actorSnapshot.context.keyword,
|
|
1094
|
+
matches: t3,
|
|
1095
|
+
selectedIndex: actorSnapshot.context.selectedIndex,
|
|
1096
|
+
error: actorSnapshot.context.error
|
|
1097
|
+
}, $[6] = actorSnapshot.context.error, $[7] = actorSnapshot.context.keyword, $[8] = actorSnapshot.context.selectedIndex, $[9] = t3, $[10] = t4) : t4 = $[10];
|
|
1098
|
+
let t5;
|
|
1099
|
+
$[11] !== t2 || $[12] !== t4 ? (t5 = {
|
|
1100
|
+
matches: t2,
|
|
1101
|
+
context: t4
|
|
1102
|
+
}, $[11] = t2, $[12] = t4, $[13] = t5) : t5 = $[13];
|
|
1103
|
+
let t6;
|
|
1104
|
+
$[14] !== send ? (t6 = (event) => {
|
|
1105
|
+
send(event);
|
|
1106
|
+
}, $[14] = send, $[15] = t6) : t6 = $[15];
|
|
1107
|
+
let t7;
|
|
1108
|
+
return $[16] !== t5 || $[17] !== t6 ? (t7 = {
|
|
1109
|
+
snapshot: t5,
|
|
1110
|
+
send: t6
|
|
1111
|
+
}, $[16] = t5, $[17] = t6, $[18] = t7) : t7 = $[18], t7;
|
|
1112
|
+
}
|
|
1113
|
+
export {
|
|
1114
|
+
defineTypeaheadPicker,
|
|
1115
|
+
useTypeaheadPicker
|
|
1116
|
+
};
|
|
1117
|
+
//# sourceMappingURL=index.js.map
|