@relevaince/mentions 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -83
- package/dist/index.d.mts +41 -8
- package/dist/index.d.ts +41 -8
- package/dist/index.js +536 -85
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +542 -91
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -3
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
39
39
|
|
|
40
40
|
// src/components/MentionsInput.tsx
|
|
41
41
|
var import_react5 = require("react");
|
|
42
|
+
var import_react_dom = require("react-dom");
|
|
42
43
|
var import_react6 = require("@tiptap/react");
|
|
43
44
|
|
|
44
45
|
// src/hooks/useMentionsEditor.ts
|
|
@@ -64,6 +65,12 @@ var MentionNode = import_core.Node.create({
|
|
|
64
65
|
atom: true,
|
|
65
66
|
selectable: true,
|
|
66
67
|
draggable: false,
|
|
68
|
+
addOptions() {
|
|
69
|
+
return {
|
|
70
|
+
onClickRef: void 0,
|
|
71
|
+
onHoverRef: void 0
|
|
72
|
+
};
|
|
73
|
+
},
|
|
67
74
|
addAttributes() {
|
|
68
75
|
return {
|
|
69
76
|
id: {
|
|
@@ -96,11 +103,17 @@ var MentionNode = import_core.Node.create({
|
|
|
96
103
|
const label = node.attrs.label;
|
|
97
104
|
const prefix = DEFAULT_PREFIXES[entityType] ?? "@";
|
|
98
105
|
const display = `${prefix}${label}`;
|
|
106
|
+
const hasClick = !!this.options.onClickRef?.current;
|
|
107
|
+
const extraAttrs = {};
|
|
108
|
+
if (hasClick) {
|
|
109
|
+
extraAttrs["data-mention-clickable"] = "";
|
|
110
|
+
}
|
|
99
111
|
return [
|
|
100
112
|
"span",
|
|
101
113
|
(0, import_core.mergeAttributes)(HTMLAttributes, {
|
|
102
114
|
"data-mention": "",
|
|
103
|
-
class: "mention-chip"
|
|
115
|
+
class: "mention-chip",
|
|
116
|
+
...extraAttrs
|
|
104
117
|
}),
|
|
105
118
|
display
|
|
106
119
|
];
|
|
@@ -111,6 +124,58 @@ var MentionNode = import_core.Node.create({
|
|
|
111
124
|
const prefix = DEFAULT_PREFIXES[entityType] ?? "@";
|
|
112
125
|
return `${prefix}${label}`;
|
|
113
126
|
},
|
|
127
|
+
addNodeView() {
|
|
128
|
+
const options = this.options;
|
|
129
|
+
return ({ node, HTMLAttributes }) => {
|
|
130
|
+
const entityType = node.attrs.entityType;
|
|
131
|
+
const label = node.attrs.label;
|
|
132
|
+
const id = node.attrs.id;
|
|
133
|
+
const prefix = DEFAULT_PREFIXES[entityType] ?? "@";
|
|
134
|
+
const dom = document.createElement("span");
|
|
135
|
+
Object.entries(
|
|
136
|
+
(0, import_core.mergeAttributes)(HTMLAttributes, {
|
|
137
|
+
"data-mention": "",
|
|
138
|
+
"data-type": entityType,
|
|
139
|
+
"data-id": id,
|
|
140
|
+
class: "mention-chip"
|
|
141
|
+
})
|
|
142
|
+
).forEach(([key, val]) => {
|
|
143
|
+
if (val != null && val !== false) dom.setAttribute(key, String(val));
|
|
144
|
+
});
|
|
145
|
+
dom.textContent = `${prefix}${label}`;
|
|
146
|
+
if (options.onClickRef?.current) {
|
|
147
|
+
dom.setAttribute("data-mention-clickable", "");
|
|
148
|
+
dom.style.cursor = "pointer";
|
|
149
|
+
}
|
|
150
|
+
dom.addEventListener("click", (event) => {
|
|
151
|
+
const handler = options.onClickRef?.current;
|
|
152
|
+
if (handler) {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
event.stopPropagation();
|
|
155
|
+
handler({ id, type: entityType, label }, event);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
let tooltip = null;
|
|
159
|
+
dom.addEventListener("mouseenter", () => {
|
|
160
|
+
const hoverFn = options.onHoverRef?.current;
|
|
161
|
+
if (!hoverFn) return;
|
|
162
|
+
const content = hoverFn({ id, type: entityType, label });
|
|
163
|
+
if (!content) return;
|
|
164
|
+
tooltip = document.createElement("div");
|
|
165
|
+
tooltip.setAttribute("data-mention-tooltip", "");
|
|
166
|
+
tooltip.textContent = typeof content === "string" ? content : "";
|
|
167
|
+
dom.style.position = "relative";
|
|
168
|
+
dom.appendChild(tooltip);
|
|
169
|
+
});
|
|
170
|
+
dom.addEventListener("mouseleave", () => {
|
|
171
|
+
if (tooltip && tooltip.parentNode) {
|
|
172
|
+
tooltip.parentNode.removeChild(tooltip);
|
|
173
|
+
tooltip = null;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return { dom };
|
|
177
|
+
};
|
|
178
|
+
},
|
|
114
179
|
addKeyboardShortcuts() {
|
|
115
180
|
return {
|
|
116
181
|
Backspace: () => this.editor.commands.command(({ tr, state }) => {
|
|
@@ -143,7 +208,13 @@ function detectTrigger(text, cursorPos, docStartPos, triggers) {
|
|
|
143
208
|
if (before.substring(i, i + trigger.length) === trigger) {
|
|
144
209
|
if (i === 0 || /\s/.test(before[i - 1])) {
|
|
145
210
|
const query = before.slice(i + trigger.length);
|
|
146
|
-
return {
|
|
211
|
+
return {
|
|
212
|
+
trigger,
|
|
213
|
+
query,
|
|
214
|
+
from: docStartPos + i,
|
|
215
|
+
to: cursorPos,
|
|
216
|
+
textBefore: before.slice(0, i)
|
|
217
|
+
};
|
|
147
218
|
}
|
|
148
219
|
}
|
|
149
220
|
}
|
|
@@ -151,7 +222,7 @@ function detectTrigger(text, cursorPos, docStartPos, triggers) {
|
|
|
151
222
|
return null;
|
|
152
223
|
}
|
|
153
224
|
var suggestionPluginKey = new import_state.PluginKey("mentionSuggestion");
|
|
154
|
-
function createSuggestionExtension(triggers, callbacksRef) {
|
|
225
|
+
function createSuggestionExtension(triggers, callbacksRef, allowTriggerRef) {
|
|
155
226
|
return import_core2.Extension.create({
|
|
156
227
|
name: "mentionSuggestion",
|
|
157
228
|
priority: 200,
|
|
@@ -229,6 +300,20 @@ function createSuggestionExtension(triggers, callbacksRef) {
|
|
|
229
300
|
const cursorPos = $pos.pos;
|
|
230
301
|
const match = detectTrigger(blockText, cursorPos, blockStart, triggers);
|
|
231
302
|
if (match) {
|
|
303
|
+
if (allowTriggerRef?.current) {
|
|
304
|
+
const allowed = allowTriggerRef.current(match.trigger, {
|
|
305
|
+
textBefore: match.textBefore
|
|
306
|
+
});
|
|
307
|
+
if (!allowed) {
|
|
308
|
+
if (active) {
|
|
309
|
+
active = false;
|
|
310
|
+
lastQuery = null;
|
|
311
|
+
lastTrigger = null;
|
|
312
|
+
callbacksRef.current.onExit();
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
232
317
|
const range = { from: match.from, to: match.to };
|
|
233
318
|
const props = {
|
|
234
319
|
query: match.query,
|
|
@@ -398,27 +483,48 @@ function buildOutput(editor) {
|
|
|
398
483
|
plainText: extractPlainText(json)
|
|
399
484
|
};
|
|
400
485
|
}
|
|
401
|
-
function
|
|
486
|
+
function collectMentionTokens(doc) {
|
|
487
|
+
const tokens = [];
|
|
488
|
+
function walk(node) {
|
|
489
|
+
if (node.type === "mention" && node.attrs) {
|
|
490
|
+
tokens.push({
|
|
491
|
+
id: node.attrs.id,
|
|
492
|
+
type: node.attrs.entityType ?? node.attrs.type,
|
|
493
|
+
label: node.attrs.label
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
if (node.content) {
|
|
497
|
+
for (const child of node.content) walk(child);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
walk(doc);
|
|
501
|
+
return tokens;
|
|
502
|
+
}
|
|
503
|
+
function createSubmitExtension(onSubmitRef, clearOnSubmitRef, submitKeyRef) {
|
|
402
504
|
return import_core3.Extension.create({
|
|
403
505
|
name: "submitShortcut",
|
|
404
506
|
priority: 150,
|
|
405
507
|
addKeyboardShortcuts() {
|
|
406
508
|
return {
|
|
407
509
|
"Mod-Enter": () => {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (
|
|
411
|
-
this.editor
|
|
510
|
+
const key = submitKeyRef.current;
|
|
511
|
+
if (key === "mod+enter" || key === "enter") {
|
|
512
|
+
if (onSubmitRef.current) {
|
|
513
|
+
onSubmitRef.current(buildOutput(this.editor));
|
|
514
|
+
if (clearOnSubmitRef.current) {
|
|
515
|
+
this.editor.commands.clearContent(true);
|
|
516
|
+
}
|
|
412
517
|
}
|
|
518
|
+
return true;
|
|
413
519
|
}
|
|
414
|
-
return
|
|
520
|
+
return false;
|
|
415
521
|
}
|
|
416
522
|
};
|
|
417
523
|
}
|
|
418
524
|
});
|
|
419
525
|
}
|
|
420
526
|
var enterSubmitPluginKey = new import_state2.PluginKey("enterSubmit");
|
|
421
|
-
function createEnterExtension(onSubmitRef, clearOnSubmitRef) {
|
|
527
|
+
function createEnterExtension(onSubmitRef, clearOnSubmitRef, submitKeyRef) {
|
|
422
528
|
return import_core3.Extension.create({
|
|
423
529
|
name: "enterSubmit",
|
|
424
530
|
priority: 150,
|
|
@@ -430,6 +536,11 @@ function createEnterExtension(onSubmitRef, clearOnSubmitRef) {
|
|
|
430
536
|
props: {
|
|
431
537
|
handleKeyDown(_view, event) {
|
|
432
538
|
if (event.key !== "Enter") return false;
|
|
539
|
+
const key = submitKeyRef.current;
|
|
540
|
+
if (key === "none") return false;
|
|
541
|
+
if (key === "mod+enter") {
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
433
544
|
if (event.shiftKey) {
|
|
434
545
|
editor.commands.splitBlock();
|
|
435
546
|
return true;
|
|
@@ -449,6 +560,33 @@ function createEnterExtension(onSubmitRef, clearOnSubmitRef) {
|
|
|
449
560
|
}
|
|
450
561
|
});
|
|
451
562
|
}
|
|
563
|
+
var mentionRemovePluginKey = new import_state2.PluginKey("mentionRemove");
|
|
564
|
+
function createMentionRemoveExtension(onMentionRemoveRef) {
|
|
565
|
+
return import_core3.Extension.create({
|
|
566
|
+
name: "mentionRemoveDetector",
|
|
567
|
+
priority: 100,
|
|
568
|
+
addProseMirrorPlugins() {
|
|
569
|
+
return [
|
|
570
|
+
new import_state2.Plugin({
|
|
571
|
+
key: mentionRemovePluginKey,
|
|
572
|
+
appendTransaction(transactions, oldState, newState) {
|
|
573
|
+
if (!onMentionRemoveRef.current) return null;
|
|
574
|
+
const oldMentions = collectMentionTokens(oldState.doc.toJSON());
|
|
575
|
+
const newMentions = collectMentionTokens(newState.doc.toJSON());
|
|
576
|
+
if (oldMentions.length <= newMentions.length) return null;
|
|
577
|
+
const newIds = new Set(newMentions.map((m) => m.id));
|
|
578
|
+
for (const m of oldMentions) {
|
|
579
|
+
if (!newIds.has(m.id)) {
|
|
580
|
+
onMentionRemoveRef.current(m);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
})
|
|
586
|
+
];
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
}
|
|
452
590
|
function useMentionsEditor({
|
|
453
591
|
providers,
|
|
454
592
|
value,
|
|
@@ -458,7 +596,15 @@ function useMentionsEditor({
|
|
|
458
596
|
placeholder,
|
|
459
597
|
autoFocus = false,
|
|
460
598
|
editable = true,
|
|
461
|
-
callbacksRef
|
|
599
|
+
callbacksRef,
|
|
600
|
+
onFocus,
|
|
601
|
+
onBlur,
|
|
602
|
+
submitKey = "enter",
|
|
603
|
+
onMentionRemove,
|
|
604
|
+
onMentionClick,
|
|
605
|
+
onMentionHover,
|
|
606
|
+
allowTrigger,
|
|
607
|
+
validateMention
|
|
462
608
|
}) {
|
|
463
609
|
const onChangeRef = (0, import_react.useRef)(onChange);
|
|
464
610
|
onChangeRef.current = onChange;
|
|
@@ -466,6 +612,23 @@ function useMentionsEditor({
|
|
|
466
612
|
onSubmitRef.current = onSubmit;
|
|
467
613
|
const clearOnSubmitRef = (0, import_react.useRef)(clearOnSubmit);
|
|
468
614
|
clearOnSubmitRef.current = clearOnSubmit;
|
|
615
|
+
const onFocusRef = (0, import_react.useRef)(onFocus);
|
|
616
|
+
onFocusRef.current = onFocus;
|
|
617
|
+
const onBlurRef = (0, import_react.useRef)(onBlur);
|
|
618
|
+
onBlurRef.current = onBlur;
|
|
619
|
+
const submitKeyRef = (0, import_react.useRef)(submitKey);
|
|
620
|
+
submitKeyRef.current = submitKey;
|
|
621
|
+
const onMentionRemoveRef = (0, import_react.useRef)(onMentionRemove);
|
|
622
|
+
onMentionRemoveRef.current = onMentionRemove;
|
|
623
|
+
const onMentionClickRef = (0, import_react.useRef)(onMentionClick);
|
|
624
|
+
onMentionClickRef.current = onMentionClick;
|
|
625
|
+
const onMentionHoverRef = (0, import_react.useRef)(onMentionHover);
|
|
626
|
+
onMentionHoverRef.current = onMentionHover;
|
|
627
|
+
const allowTriggerRef = (0, import_react.useRef)(allowTrigger);
|
|
628
|
+
allowTriggerRef.current = allowTrigger;
|
|
629
|
+
const validateMentionRef = (0, import_react.useRef)(validateMention);
|
|
630
|
+
validateMentionRef.current = validateMention;
|
|
631
|
+
const internalMarkdownRef = (0, import_react.useRef)(null);
|
|
469
632
|
const initialContent = (0, import_react.useMemo)(() => {
|
|
470
633
|
if (!value) return void 0;
|
|
471
634
|
return parseFromMarkdown(value);
|
|
@@ -477,16 +640,27 @@ function useMentionsEditor({
|
|
|
477
640
|
[triggersKey]
|
|
478
641
|
);
|
|
479
642
|
const suggestionExtension = (0, import_react.useMemo)(
|
|
480
|
-
() => createSuggestionExtension(triggers, callbacksRef),
|
|
643
|
+
() => createSuggestionExtension(triggers, callbacksRef, allowTriggerRef),
|
|
481
644
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
482
645
|
[triggersKey]
|
|
483
646
|
);
|
|
484
647
|
const submitExt = (0, import_react.useMemo)(
|
|
485
|
-
() => createSubmitExtension(onSubmitRef, clearOnSubmitRef),
|
|
648
|
+
() => createSubmitExtension(onSubmitRef, clearOnSubmitRef, submitKeyRef),
|
|
486
649
|
[]
|
|
487
650
|
);
|
|
488
651
|
const enterExt = (0, import_react.useMemo)(
|
|
489
|
-
() => createEnterExtension(onSubmitRef, clearOnSubmitRef),
|
|
652
|
+
() => createEnterExtension(onSubmitRef, clearOnSubmitRef, submitKeyRef),
|
|
653
|
+
[]
|
|
654
|
+
);
|
|
655
|
+
const mentionRemoveExt = (0, import_react.useMemo)(
|
|
656
|
+
() => createMentionRemoveExtension(onMentionRemoveRef),
|
|
657
|
+
[]
|
|
658
|
+
);
|
|
659
|
+
const mentionNodeExt = (0, import_react.useMemo)(
|
|
660
|
+
() => MentionNode.configure({
|
|
661
|
+
onClickRef: onMentionClickRef,
|
|
662
|
+
onHoverRef: onMentionHoverRef
|
|
663
|
+
}),
|
|
490
664
|
[]
|
|
491
665
|
);
|
|
492
666
|
const editor = (0, import_react2.useEditor)({
|
|
@@ -505,10 +679,11 @@ function useMentionsEditor({
|
|
|
505
679
|
placeholder: ({ editor: editor2 }) => editor2.isEmpty ? placeholder ?? "Type a message..." : "",
|
|
506
680
|
showOnlyCurrent: true
|
|
507
681
|
}),
|
|
508
|
-
|
|
682
|
+
mentionNodeExt,
|
|
509
683
|
suggestionExtension,
|
|
510
684
|
submitExt,
|
|
511
|
-
enterExt
|
|
685
|
+
enterExt,
|
|
686
|
+
mentionRemoveExt
|
|
512
687
|
],
|
|
513
688
|
content: initialContent,
|
|
514
689
|
autofocus: autoFocus ? "end" : false,
|
|
@@ -519,7 +694,15 @@ function useMentionsEditor({
|
|
|
519
694
|
}
|
|
520
695
|
},
|
|
521
696
|
onUpdate: ({ editor: editor2 }) => {
|
|
522
|
-
|
|
697
|
+
const output = buildOutput(editor2);
|
|
698
|
+
internalMarkdownRef.current = output.markdown;
|
|
699
|
+
onChangeRef.current?.(output);
|
|
700
|
+
},
|
|
701
|
+
onFocus: () => {
|
|
702
|
+
onFocusRef.current?.();
|
|
703
|
+
},
|
|
704
|
+
onBlur: () => {
|
|
705
|
+
onBlurRef.current?.();
|
|
523
706
|
}
|
|
524
707
|
});
|
|
525
708
|
(0, import_react.useEffect)(() => {
|
|
@@ -527,6 +710,36 @@ function useMentionsEditor({
|
|
|
527
710
|
editor.setEditable(editable);
|
|
528
711
|
}
|
|
529
712
|
}, [editor, editable]);
|
|
713
|
+
(0, import_react.useEffect)(() => {
|
|
714
|
+
if (!editor || value === void 0) return;
|
|
715
|
+
if (value === internalMarkdownRef.current) return;
|
|
716
|
+
const doc = parseFromMarkdown(value);
|
|
717
|
+
editor.commands.setContent(doc);
|
|
718
|
+
internalMarkdownRef.current = value;
|
|
719
|
+
}, [editor, value]);
|
|
720
|
+
(0, import_react.useEffect)(() => {
|
|
721
|
+
if (!editor || !validateMention) return;
|
|
722
|
+
const runValidation = async () => {
|
|
723
|
+
const doc = editor.getJSON();
|
|
724
|
+
const tokens = collectMentionTokens(doc);
|
|
725
|
+
const invalidIds = /* @__PURE__ */ new Set();
|
|
726
|
+
await Promise.all(
|
|
727
|
+
tokens.map(async (token) => {
|
|
728
|
+
const valid = await validateMention(token);
|
|
729
|
+
if (!valid) invalidIds.add(token.id);
|
|
730
|
+
})
|
|
731
|
+
);
|
|
732
|
+
editor.view.dom.querySelectorAll("[data-mention]").forEach((el) => {
|
|
733
|
+
const id = el.getAttribute("data-id");
|
|
734
|
+
if (id && invalidIds.has(id)) {
|
|
735
|
+
el.setAttribute("data-mention-invalid", "");
|
|
736
|
+
} else {
|
|
737
|
+
el.removeAttribute("data-mention-invalid");
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
};
|
|
741
|
+
runValidation();
|
|
742
|
+
}, [editor, validateMention]);
|
|
530
743
|
const clear = (0, import_react.useCallback)(() => {
|
|
531
744
|
editor?.commands.clearContent(true);
|
|
532
745
|
}, [editor]);
|
|
@@ -535,6 +748,7 @@ function useMentionsEditor({
|
|
|
535
748
|
if (!editor) return;
|
|
536
749
|
const doc = parseFromMarkdown(markdown);
|
|
537
750
|
editor.commands.setContent(doc);
|
|
751
|
+
internalMarkdownRef.current = markdown;
|
|
538
752
|
},
|
|
539
753
|
[editor]
|
|
540
754
|
);
|
|
@@ -550,6 +764,27 @@ function useMentionsEditor({
|
|
|
550
764
|
|
|
551
765
|
// src/hooks/useSuggestion.ts
|
|
552
766
|
var import_react3 = require("react");
|
|
767
|
+
|
|
768
|
+
// src/utils/debounce.ts
|
|
769
|
+
function debounce(fn, ms) {
|
|
770
|
+
let timer = null;
|
|
771
|
+
const debounced = ((...args) => {
|
|
772
|
+
if (timer != null) clearTimeout(timer);
|
|
773
|
+
timer = setTimeout(() => {
|
|
774
|
+
timer = null;
|
|
775
|
+
fn(...args);
|
|
776
|
+
}, ms);
|
|
777
|
+
});
|
|
778
|
+
debounced.cancel = () => {
|
|
779
|
+
if (timer != null) {
|
|
780
|
+
clearTimeout(timer);
|
|
781
|
+
timer = null;
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
return debounced;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// src/hooks/useSuggestion.ts
|
|
553
788
|
var IDLE_STATE = {
|
|
554
789
|
state: "idle",
|
|
555
790
|
items: [],
|
|
@@ -560,16 +795,24 @@ var IDLE_STATE = {
|
|
|
560
795
|
trigger: null,
|
|
561
796
|
query: ""
|
|
562
797
|
};
|
|
563
|
-
function useSuggestion(providers) {
|
|
798
|
+
function useSuggestion(providers, options = {}) {
|
|
564
799
|
const [uiState, setUIState] = (0, import_react3.useState)(IDLE_STATE);
|
|
565
800
|
const stateRef = (0, import_react3.useRef)(uiState);
|
|
566
801
|
stateRef.current = uiState;
|
|
567
802
|
const providersRef = (0, import_react3.useRef)(providers);
|
|
568
803
|
providersRef.current = providers;
|
|
804
|
+
const onMentionAddRef = (0, import_react3.useRef)(options.onMentionAdd);
|
|
805
|
+
onMentionAddRef.current = options.onMentionAdd;
|
|
569
806
|
const commandRef = (0, import_react3.useRef)(
|
|
570
807
|
null
|
|
571
808
|
);
|
|
572
809
|
const providerRef = (0, import_react3.useRef)(null);
|
|
810
|
+
const debouncedFetchRef = (0, import_react3.useRef)(null);
|
|
811
|
+
(0, import_react3.useEffect)(() => {
|
|
812
|
+
return () => {
|
|
813
|
+
debouncedFetchRef.current?.cancel();
|
|
814
|
+
};
|
|
815
|
+
}, []);
|
|
573
816
|
const fetchItems = (0, import_react3.useCallback)(
|
|
574
817
|
async (provider, query, parent, useSearchAll) => {
|
|
575
818
|
setUIState((prev) => ({ ...prev, loading: true, state: "loading" }));
|
|
@@ -600,6 +843,23 @@ function useSuggestion(providers) {
|
|
|
600
843
|
},
|
|
601
844
|
[]
|
|
602
845
|
);
|
|
846
|
+
const scheduleFetch = (0, import_react3.useCallback)(
|
|
847
|
+
(provider, query, parent, useSearchAll) => {
|
|
848
|
+
debouncedFetchRef.current?.cancel();
|
|
849
|
+
const ms = provider.debounceMs;
|
|
850
|
+
if (ms && ms > 0) {
|
|
851
|
+
setUIState((prev) => ({ ...prev, loading: true }));
|
|
852
|
+
const debouncedFn = debounce(() => {
|
|
853
|
+
fetchItems(provider, query, parent, useSearchAll);
|
|
854
|
+
}, ms);
|
|
855
|
+
debouncedFetchRef.current = debouncedFn;
|
|
856
|
+
debouncedFn();
|
|
857
|
+
} else {
|
|
858
|
+
fetchItems(provider, query, parent, useSearchAll);
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
[fetchItems]
|
|
862
|
+
);
|
|
603
863
|
const onStart = (0, import_react3.useCallback)(
|
|
604
864
|
(props) => {
|
|
605
865
|
const provider = providersRef.current.find(
|
|
@@ -618,13 +878,31 @@ function useSuggestion(providers) {
|
|
|
618
878
|
trigger: props.trigger,
|
|
619
879
|
query: props.query
|
|
620
880
|
});
|
|
881
|
+
if (!props.query.trim() && provider.getRecentItems) {
|
|
882
|
+
provider.getRecentItems().then((recentItems) => {
|
|
883
|
+
const tagged = recentItems.map((item) => ({
|
|
884
|
+
...item,
|
|
885
|
+
group: item.group ?? "Recent"
|
|
886
|
+
}));
|
|
887
|
+
setUIState((prev) => ({
|
|
888
|
+
...prev,
|
|
889
|
+
items: tagged,
|
|
890
|
+
loading: false,
|
|
891
|
+
state: "showing",
|
|
892
|
+
activeIndex: 0
|
|
893
|
+
}));
|
|
894
|
+
}).catch(() => {
|
|
895
|
+
scheduleFetch(provider, props.query);
|
|
896
|
+
});
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
621
899
|
if (props.query.trim() && provider.searchAll) {
|
|
622
|
-
|
|
900
|
+
scheduleFetch(provider, props.query, void 0, true);
|
|
623
901
|
} else {
|
|
624
|
-
|
|
902
|
+
scheduleFetch(provider, props.query);
|
|
625
903
|
}
|
|
626
904
|
},
|
|
627
|
-
[
|
|
905
|
+
[scheduleFetch]
|
|
628
906
|
);
|
|
629
907
|
const onUpdate = (0, import_react3.useCallback)(
|
|
630
908
|
(props) => {
|
|
@@ -648,14 +926,31 @@ function useSuggestion(providers) {
|
|
|
648
926
|
}));
|
|
649
927
|
}
|
|
650
928
|
if (props.query.trim() && provider.searchAll) {
|
|
651
|
-
|
|
929
|
+
scheduleFetch(provider, props.query, void 0, true);
|
|
930
|
+
} else if (!props.query.trim() && provider.getRecentItems) {
|
|
931
|
+
provider.getRecentItems().then((recentItems) => {
|
|
932
|
+
const tagged = recentItems.map((item) => ({
|
|
933
|
+
...item,
|
|
934
|
+
group: item.group ?? "Recent"
|
|
935
|
+
}));
|
|
936
|
+
setUIState((prev) => ({
|
|
937
|
+
...prev,
|
|
938
|
+
items: tagged,
|
|
939
|
+
loading: false,
|
|
940
|
+
state: "showing",
|
|
941
|
+
activeIndex: 0
|
|
942
|
+
}));
|
|
943
|
+
}).catch(() => {
|
|
944
|
+
scheduleFetch(provider, props.query);
|
|
945
|
+
});
|
|
652
946
|
} else {
|
|
653
|
-
|
|
947
|
+
scheduleFetch(provider, props.query);
|
|
654
948
|
}
|
|
655
949
|
},
|
|
656
|
-
[
|
|
950
|
+
[scheduleFetch]
|
|
657
951
|
);
|
|
658
952
|
const onExit = (0, import_react3.useCallback)(() => {
|
|
953
|
+
debouncedFetchRef.current?.cancel();
|
|
659
954
|
providerRef.current = null;
|
|
660
955
|
commandRef.current = null;
|
|
661
956
|
setUIState(IDLE_STATE);
|
|
@@ -690,8 +985,8 @@ function useSuggestion(providers) {
|
|
|
690
985
|
fetchItems(provider, "", selected);
|
|
691
986
|
return;
|
|
692
987
|
}
|
|
988
|
+
const rootLabel = current.breadcrumbs.length > 0 ? current.breadcrumbs[0].label : selected.rootLabel ?? null;
|
|
693
989
|
if (commandRef.current) {
|
|
694
|
-
const rootLabel = current.breadcrumbs.length > 0 ? current.breadcrumbs[0].label : selected.rootLabel ?? null;
|
|
695
990
|
commandRef.current({
|
|
696
991
|
id: selected.id,
|
|
697
992
|
label: selected.label,
|
|
@@ -699,6 +994,11 @@ function useSuggestion(providers) {
|
|
|
699
994
|
rootLabel
|
|
700
995
|
});
|
|
701
996
|
}
|
|
997
|
+
onMentionAddRef.current?.({
|
|
998
|
+
id: selected.id,
|
|
999
|
+
type: selected.type,
|
|
1000
|
+
label: selected.label
|
|
1001
|
+
});
|
|
702
1002
|
},
|
|
703
1003
|
[fetchItems]
|
|
704
1004
|
);
|
|
@@ -723,6 +1023,7 @@ function useSuggestion(providers) {
|
|
|
723
1023
|
});
|
|
724
1024
|
}, [fetchItems]);
|
|
725
1025
|
const close = (0, import_react3.useCallback)(() => {
|
|
1026
|
+
debouncedFetchRef.current?.cancel();
|
|
726
1027
|
setUIState(IDLE_STATE);
|
|
727
1028
|
}, []);
|
|
728
1029
|
const searchNested = (0, import_react3.useCallback)(
|
|
@@ -732,10 +1033,10 @@ function useSuggestion(providers) {
|
|
|
732
1033
|
const current = stateRef.current;
|
|
733
1034
|
const parent = current.breadcrumbs[current.breadcrumbs.length - 1];
|
|
734
1035
|
if (parent) {
|
|
735
|
-
|
|
1036
|
+
scheduleFetch(provider, query, parent);
|
|
736
1037
|
}
|
|
737
1038
|
},
|
|
738
|
-
[
|
|
1039
|
+
[scheduleFetch]
|
|
739
1040
|
);
|
|
740
1041
|
const onKeyDown = (0, import_react3.useCallback)(
|
|
741
1042
|
({ event }) => {
|
|
@@ -758,6 +1059,14 @@ function useSuggestion(providers) {
|
|
|
758
1059
|
}
|
|
759
1060
|
return true;
|
|
760
1061
|
}
|
|
1062
|
+
case "Tab": {
|
|
1063
|
+
event.preventDefault();
|
|
1064
|
+
const selectedItem = current.items[current.activeIndex];
|
|
1065
|
+
if (selectedItem) {
|
|
1066
|
+
select(selectedItem);
|
|
1067
|
+
}
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
761
1070
|
case "ArrowRight": {
|
|
762
1071
|
const activeItem = current.items[current.activeIndex];
|
|
763
1072
|
if (activeItem?.hasChildren) {
|
|
@@ -832,13 +1141,13 @@ function optionAttrs(id, selected, index) {
|
|
|
832
1141
|
|
|
833
1142
|
// src/components/SuggestionList.tsx
|
|
834
1143
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
835
|
-
var LISTBOX_ID = "mentions-suggestion-listbox";
|
|
836
1144
|
function SuggestionList({
|
|
837
1145
|
items,
|
|
838
1146
|
activeIndex,
|
|
839
1147
|
breadcrumbs,
|
|
840
1148
|
loading,
|
|
841
1149
|
trigger,
|
|
1150
|
+
query,
|
|
842
1151
|
clientRect,
|
|
843
1152
|
onSelect,
|
|
844
1153
|
onHover,
|
|
@@ -847,7 +1156,12 @@ function SuggestionList({
|
|
|
847
1156
|
onNavigateUp,
|
|
848
1157
|
onNavigateDown,
|
|
849
1158
|
onClose,
|
|
850
|
-
|
|
1159
|
+
onFocusEditor,
|
|
1160
|
+
renderItem,
|
|
1161
|
+
renderEmpty,
|
|
1162
|
+
renderLoading,
|
|
1163
|
+
renderGroupHeader,
|
|
1164
|
+
listboxId
|
|
851
1165
|
}) {
|
|
852
1166
|
const listRef = (0, import_react4.useRef)(null);
|
|
853
1167
|
const searchInputRef = (0, import_react4.useRef)(null);
|
|
@@ -861,18 +1175,24 @@ function SuggestionList({
|
|
|
861
1175
|
prevBreadcrumbKey.current = breadcrumbKey;
|
|
862
1176
|
}
|
|
863
1177
|
}, [breadcrumbKey]);
|
|
1178
|
+
const prevBreadcrumbsLen = (0, import_react4.useRef)(breadcrumbs.length);
|
|
864
1179
|
(0, import_react4.useEffect)(() => {
|
|
865
|
-
if (
|
|
1180
|
+
if (prevBreadcrumbsLen.current > 0 && breadcrumbs.length === 0) {
|
|
1181
|
+
onFocusEditor?.();
|
|
1182
|
+
} else if (breadcrumbs.length > 0 && searchInputRef.current) {
|
|
866
1183
|
requestAnimationFrame(() => searchInputRef.current?.focus());
|
|
867
1184
|
}
|
|
868
|
-
|
|
1185
|
+
prevBreadcrumbsLen.current = breadcrumbs.length;
|
|
1186
|
+
}, [breadcrumbKey, breadcrumbs.length, onFocusEditor]);
|
|
869
1187
|
(0, import_react4.useEffect)(() => {
|
|
870
1188
|
if (!listRef.current) return;
|
|
871
1189
|
const active = listRef.current.querySelector('[aria-selected="true"]');
|
|
872
1190
|
active?.scrollIntoView({ block: "nearest" });
|
|
873
1191
|
}, [activeIndex]);
|
|
874
|
-
const style = usePopoverPosition(clientRect);
|
|
875
|
-
|
|
1192
|
+
const { style, position } = usePopoverPosition(clientRect);
|
|
1193
|
+
const activeQuery = breadcrumbs.length > 0 ? nestedQuery : query;
|
|
1194
|
+
const showEmpty = !loading && items.length === 0 && activeQuery.trim().length > 0;
|
|
1195
|
+
if (items.length === 0 && !loading && !showEmpty) return null;
|
|
876
1196
|
const handleSearchKeyDown = (e) => {
|
|
877
1197
|
switch (e.key) {
|
|
878
1198
|
case "ArrowDown":
|
|
@@ -892,8 +1212,23 @@ function SuggestionList({
|
|
|
892
1212
|
}
|
|
893
1213
|
case "Escape":
|
|
894
1214
|
e.preventDefault();
|
|
1215
|
+
onFocusEditor?.();
|
|
895
1216
|
onClose?.();
|
|
896
1217
|
break;
|
|
1218
|
+
case "ArrowLeft":
|
|
1219
|
+
if (nestedQuery === "" || e.currentTarget.selectionStart === 0) {
|
|
1220
|
+
e.preventDefault();
|
|
1221
|
+
onGoBack();
|
|
1222
|
+
}
|
|
1223
|
+
break;
|
|
1224
|
+
case "ArrowRight": {
|
|
1225
|
+
const item = items[activeIndex];
|
|
1226
|
+
if (item?.hasChildren) {
|
|
1227
|
+
e.preventDefault();
|
|
1228
|
+
onSelect(item);
|
|
1229
|
+
}
|
|
1230
|
+
break;
|
|
1231
|
+
}
|
|
897
1232
|
case "Backspace":
|
|
898
1233
|
if (nestedQuery === "") {
|
|
899
1234
|
e.preventDefault();
|
|
@@ -902,11 +1237,13 @@ function SuggestionList({
|
|
|
902
1237
|
break;
|
|
903
1238
|
}
|
|
904
1239
|
};
|
|
1240
|
+
const hasGroups = items.some((item) => item.group);
|
|
905
1241
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
906
1242
|
"div",
|
|
907
1243
|
{
|
|
908
1244
|
"data-suggestions": "",
|
|
909
1245
|
"data-trigger": trigger,
|
|
1246
|
+
"data-suggestions-position": position,
|
|
910
1247
|
style,
|
|
911
1248
|
ref: listRef,
|
|
912
1249
|
children: [
|
|
@@ -944,28 +1281,76 @@ function SuggestionList({
|
|
|
944
1281
|
spellCheck: false
|
|
945
1282
|
}
|
|
946
1283
|
) }),
|
|
947
|
-
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-suggestion-loading": "", children: "Loading..." }),
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
item.id
|
|
963
|
-
);
|
|
964
|
-
}) })
|
|
1284
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-suggestion-loading": "", children: renderLoading ? renderLoading() : "Loading..." }),
|
|
1285
|
+
showEmpty && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-suggestion-empty": "", children: renderEmpty ? renderEmpty(activeQuery) : "No results" }),
|
|
1286
|
+
!loading && items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...listboxAttrs(listboxId, `${trigger ?? ""} suggestions`), children: hasGroups ? renderGroupedItems(items, activeIndex, depth, onSelect, onHover, renderItem, renderGroupHeader) : items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1287
|
+
SuggestionItem,
|
|
1288
|
+
{
|
|
1289
|
+
item,
|
|
1290
|
+
index,
|
|
1291
|
+
isActive: index === activeIndex,
|
|
1292
|
+
depth,
|
|
1293
|
+
onSelect,
|
|
1294
|
+
onHover,
|
|
1295
|
+
renderItem
|
|
1296
|
+
},
|
|
1297
|
+
item.id
|
|
1298
|
+
)) })
|
|
965
1299
|
]
|
|
966
1300
|
}
|
|
967
1301
|
);
|
|
968
1302
|
}
|
|
1303
|
+
function renderGroupedItems(items, activeIndex, depth, onSelect, onHover, renderItem, renderGroupHeader) {
|
|
1304
|
+
const elements = [];
|
|
1305
|
+
let lastGroup;
|
|
1306
|
+
items.forEach((item, index) => {
|
|
1307
|
+
if (item.group && item.group !== lastGroup) {
|
|
1308
|
+
lastGroup = item.group;
|
|
1309
|
+
elements.push(
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-suggestion-group-header": "", children: renderGroupHeader ? renderGroupHeader(item.group) : item.group }, `group-${item.group}`)
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
elements.push(
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1315
|
+
SuggestionItem,
|
|
1316
|
+
{
|
|
1317
|
+
item,
|
|
1318
|
+
index,
|
|
1319
|
+
isActive: index === activeIndex,
|
|
1320
|
+
depth,
|
|
1321
|
+
onSelect,
|
|
1322
|
+
onHover,
|
|
1323
|
+
renderItem
|
|
1324
|
+
},
|
|
1325
|
+
item.id
|
|
1326
|
+
)
|
|
1327
|
+
);
|
|
1328
|
+
});
|
|
1329
|
+
return elements;
|
|
1330
|
+
}
|
|
1331
|
+
function SuggestionItem({
|
|
1332
|
+
item,
|
|
1333
|
+
index,
|
|
1334
|
+
isActive,
|
|
1335
|
+
depth,
|
|
1336
|
+
onSelect,
|
|
1337
|
+
onHover,
|
|
1338
|
+
renderItem
|
|
1339
|
+
}) {
|
|
1340
|
+
const itemId = `mention-option-${item.id}`;
|
|
1341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1342
|
+
"div",
|
|
1343
|
+
{
|
|
1344
|
+
...optionAttrs(itemId, isActive, index),
|
|
1345
|
+
"data-suggestion-item": "",
|
|
1346
|
+
"data-suggestion-item-active": isActive ? "" : void 0,
|
|
1347
|
+
"data-has-children": item.hasChildren ? "" : void 0,
|
|
1348
|
+
onMouseEnter: () => onHover(index),
|
|
1349
|
+
onClick: () => onSelect(item),
|
|
1350
|
+
children: renderItem ? renderItem(item, depth) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultSuggestionItem, { item })
|
|
1351
|
+
}
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
969
1354
|
function DefaultSuggestionItem({ item }) {
|
|
970
1355
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
971
1356
|
item.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "data-suggestion-item-icon": "", children: item.icon }),
|
|
@@ -974,25 +1359,48 @@ function DefaultSuggestionItem({ item }) {
|
|
|
974
1359
|
item.hasChildren && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "data-suggestion-item-chevron": "", "aria-hidden": "true", children: "\u203A" })
|
|
975
1360
|
] });
|
|
976
1361
|
}
|
|
1362
|
+
var POPOVER_HEIGHT_ESTIMATE = 280;
|
|
1363
|
+
var POPOVER_WIDTH_ESTIMATE = 360;
|
|
977
1364
|
function usePopoverPosition(clientRect) {
|
|
978
1365
|
if (!clientRect) {
|
|
979
|
-
return { display: "none" };
|
|
1366
|
+
return { style: { display: "none" }, position: "below" };
|
|
980
1367
|
}
|
|
981
1368
|
const rect = clientRect();
|
|
982
1369
|
if (!rect) {
|
|
983
|
-
return { display: "none" };
|
|
1370
|
+
return { style: { display: "none" }, position: "below" };
|
|
1371
|
+
}
|
|
1372
|
+
const viewportH = typeof window !== "undefined" ? window.innerHeight : 800;
|
|
1373
|
+
const viewportW = typeof window !== "undefined" ? window.innerWidth : 1200;
|
|
1374
|
+
const spaceBelow = viewportH - rect.bottom;
|
|
1375
|
+
const shouldFlip = spaceBelow < POPOVER_HEIGHT_ESTIMATE && rect.top > spaceBelow;
|
|
1376
|
+
let left = rect.left;
|
|
1377
|
+
if (left + POPOVER_WIDTH_ESTIMATE > viewportW) {
|
|
1378
|
+
left = Math.max(0, viewportW - POPOVER_WIDTH_ESTIMATE);
|
|
1379
|
+
}
|
|
1380
|
+
if (shouldFlip) {
|
|
1381
|
+
return {
|
|
1382
|
+
style: {
|
|
1383
|
+
position: "fixed",
|
|
1384
|
+
left: `${left}px`,
|
|
1385
|
+
bottom: `${viewportH - rect.top + 4}px`,
|
|
1386
|
+
zIndex: 50
|
|
1387
|
+
},
|
|
1388
|
+
position: "above"
|
|
1389
|
+
};
|
|
984
1390
|
}
|
|
985
1391
|
return {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1392
|
+
style: {
|
|
1393
|
+
position: "fixed",
|
|
1394
|
+
left: `${left}px`,
|
|
1395
|
+
top: `${rect.bottom + 4}px`,
|
|
1396
|
+
zIndex: 50
|
|
1397
|
+
},
|
|
1398
|
+
position: "below"
|
|
990
1399
|
};
|
|
991
1400
|
}
|
|
992
1401
|
|
|
993
1402
|
// src/components/MentionsInput.tsx
|
|
994
1403
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
995
|
-
var LISTBOX_ID2 = "mentions-suggestion-listbox";
|
|
996
1404
|
var MentionsInput = (0, import_react5.forwardRef)(
|
|
997
1405
|
function MentionsInput2({
|
|
998
1406
|
value,
|
|
@@ -1006,10 +1414,29 @@ var MentionsInput = (0, import_react5.forwardRef)(
|
|
|
1006
1414
|
clearOnSubmit = true,
|
|
1007
1415
|
maxLength,
|
|
1008
1416
|
renderItem,
|
|
1009
|
-
renderChip
|
|
1417
|
+
renderChip,
|
|
1418
|
+
renderEmpty,
|
|
1419
|
+
renderLoading,
|
|
1420
|
+
renderGroupHeader,
|
|
1421
|
+
onFocus,
|
|
1422
|
+
onBlur,
|
|
1423
|
+
onMentionAdd,
|
|
1424
|
+
onMentionRemove,
|
|
1425
|
+
onMentionClick,
|
|
1426
|
+
onMentionHover,
|
|
1427
|
+
minHeight,
|
|
1428
|
+
maxHeight,
|
|
1429
|
+
submitKey = "enter",
|
|
1430
|
+
allowTrigger,
|
|
1431
|
+
validateMention,
|
|
1432
|
+
portalContainer
|
|
1010
1433
|
}, ref) {
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1434
|
+
const instanceId = (0, import_react5.useId)();
|
|
1435
|
+
const listboxId = `mentions-listbox-${instanceId}`;
|
|
1436
|
+
const { uiState, actions, callbacksRef } = useSuggestion(providers, {
|
|
1437
|
+
onMentionAdd
|
|
1438
|
+
});
|
|
1439
|
+
const { editor, getOutput, clear, setContent, focus } = useMentionsEditor({
|
|
1013
1440
|
providers,
|
|
1014
1441
|
value,
|
|
1015
1442
|
onChange,
|
|
@@ -1018,46 +1445,70 @@ var MentionsInput = (0, import_react5.forwardRef)(
|
|
|
1018
1445
|
placeholder,
|
|
1019
1446
|
autoFocus,
|
|
1020
1447
|
editable: !disabled,
|
|
1021
|
-
callbacksRef
|
|
1448
|
+
callbacksRef,
|
|
1449
|
+
onFocus,
|
|
1450
|
+
onBlur,
|
|
1451
|
+
submitKey,
|
|
1452
|
+
onMentionRemove,
|
|
1453
|
+
onMentionClick,
|
|
1454
|
+
onMentionHover,
|
|
1455
|
+
allowTrigger,
|
|
1456
|
+
validateMention
|
|
1022
1457
|
});
|
|
1023
1458
|
(0, import_react5.useImperativeHandle)(
|
|
1024
1459
|
ref,
|
|
1025
|
-
() => ({ clear, setContent, focus }),
|
|
1026
|
-
[clear, setContent, focus]
|
|
1460
|
+
() => ({ clear, setContent, focus, getOutput }),
|
|
1461
|
+
[clear, setContent, focus, getOutput]
|
|
1027
1462
|
);
|
|
1028
1463
|
const isExpanded = uiState.state !== "idle";
|
|
1029
1464
|
const handleHover = (0, import_react5.useCallback)((index) => {
|
|
1030
1465
|
void index;
|
|
1031
1466
|
}, []);
|
|
1467
|
+
const handleFocusEditor = (0, import_react5.useCallback)(() => {
|
|
1468
|
+
editor?.commands.focus();
|
|
1469
|
+
}, [editor]);
|
|
1470
|
+
const editorStyle = {};
|
|
1471
|
+
if (minHeight != null) editorStyle.minHeight = `${minHeight}px`;
|
|
1472
|
+
if (maxHeight != null) {
|
|
1473
|
+
editorStyle.maxHeight = `${maxHeight}px`;
|
|
1474
|
+
editorStyle.overflowY = "auto";
|
|
1475
|
+
}
|
|
1476
|
+
const suggestionList = isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1477
|
+
SuggestionList,
|
|
1478
|
+
{
|
|
1479
|
+
items: uiState.items,
|
|
1480
|
+
activeIndex: uiState.activeIndex,
|
|
1481
|
+
breadcrumbs: uiState.breadcrumbs,
|
|
1482
|
+
loading: uiState.loading,
|
|
1483
|
+
trigger: uiState.trigger,
|
|
1484
|
+
query: uiState.query,
|
|
1485
|
+
clientRect: uiState.clientRect,
|
|
1486
|
+
onSelect: (item) => actions.select(item),
|
|
1487
|
+
onHover: handleHover,
|
|
1488
|
+
onGoBack: actions.goBack,
|
|
1489
|
+
onSearchNested: actions.searchNested,
|
|
1490
|
+
onNavigateUp: actions.navigateUp,
|
|
1491
|
+
onNavigateDown: actions.navigateDown,
|
|
1492
|
+
onClose: actions.close,
|
|
1493
|
+
onFocusEditor: handleFocusEditor,
|
|
1494
|
+
renderItem,
|
|
1495
|
+
renderEmpty,
|
|
1496
|
+
renderLoading,
|
|
1497
|
+
renderGroupHeader,
|
|
1498
|
+
listboxId
|
|
1499
|
+
}
|
|
1500
|
+
) : null;
|
|
1032
1501
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1033
1502
|
"div",
|
|
1034
1503
|
{
|
|
1035
1504
|
className,
|
|
1036
1505
|
"data-mentions-input": "",
|
|
1037
1506
|
"data-disabled": disabled ? "" : void 0,
|
|
1038
|
-
...comboboxAttrs(isExpanded,
|
|
1507
|
+
...comboboxAttrs(isExpanded, listboxId),
|
|
1039
1508
|
"aria-activedescendant": isExpanded && uiState.items[uiState.activeIndex] ? `mention-option-${uiState.items[uiState.activeIndex].id}` : void 0,
|
|
1040
1509
|
children: [
|
|
1041
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react6.EditorContent, { editor }),
|
|
1042
|
-
|
|
1043
|
-
SuggestionList,
|
|
1044
|
-
{
|
|
1045
|
-
items: uiState.items,
|
|
1046
|
-
activeIndex: uiState.activeIndex,
|
|
1047
|
-
breadcrumbs: uiState.breadcrumbs,
|
|
1048
|
-
loading: uiState.loading,
|
|
1049
|
-
trigger: uiState.trigger,
|
|
1050
|
-
clientRect: uiState.clientRect,
|
|
1051
|
-
onSelect: (item) => actions.select(item),
|
|
1052
|
-
onHover: handleHover,
|
|
1053
|
-
onGoBack: actions.goBack,
|
|
1054
|
-
onSearchNested: actions.searchNested,
|
|
1055
|
-
onNavigateUp: actions.navigateUp,
|
|
1056
|
-
onNavigateDown: actions.navigateDown,
|
|
1057
|
-
onClose: actions.close,
|
|
1058
|
-
renderItem
|
|
1059
|
-
}
|
|
1060
|
-
)
|
|
1510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: editorStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react6.EditorContent, { editor }) }),
|
|
1511
|
+
portalContainer ? suggestionList && (0, import_react_dom.createPortal)(suggestionList, portalContainer) : suggestionList
|
|
1061
1512
|
]
|
|
1062
1513
|
}
|
|
1063
1514
|
);
|