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