composeai 0.1.4 → 0.1.7
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 +25 -1
- package/dist/index.cjs +817 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -18
- package/dist/index.d.ts +141 -18
- package/dist/index.js +819 -78
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/composer.css +262 -9
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createContext, forwardRef, useMemo, useState, useRef, useCallback, useEffect, useContext,
|
|
1
|
+
import { createContext, forwardRef, useMemo, useState, useRef, useCallback, useEffect, useContext, useId, isValidElement, cloneElement, useLayoutEffect } from 'react';
|
|
2
2
|
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
|
3
3
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
-
import { ParagraphNode, $getRoot, $createParagraphNode, ElementNode, $createTextNode, TextNode, addClassNamesToElement, $isElementNode, $isTextNode, $isParagraphNode,
|
|
4
|
+
import { ParagraphNode, $getRoot, $createParagraphNode, ElementNode, $createTextNode, TextNode, addClassNamesToElement, $isElementNode, $isTextNode, $isParagraphNode, $getSelection, $isRangeSelection, KEY_ENTER_COMMAND, COMMAND_PRIORITY_HIGH, PASTE_COMMAND, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_LOW, KEY_TAB_COMMAND, KEY_ESCAPE_COMMAND, $applyNodeReplacement, $isLineBreakNode } from 'lexical';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
|
7
7
|
import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin';
|
|
@@ -393,6 +393,13 @@ var IconAttach = makeIcon(
|
|
|
393
393
|
/* @__PURE__ */ jsx("path", { d: "m16 6-8.414 8.586a2 2 0 0 0 0 2.828 2 2 0 0 0 2.828 0l8.414-8.586a4 4 0 0 0 0-5.656 4 4 0 0 0-5.656 0l-8.415 8.585a6 6 0 1 0 8.486 8.486" })
|
|
394
394
|
] })
|
|
395
395
|
);
|
|
396
|
+
var IconPlus = makeIcon(
|
|
397
|
+
"IconPlus",
|
|
398
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
+
/* @__PURE__ */ jsx("path", { d: "M12 5v14" }),
|
|
400
|
+
/* @__PURE__ */ jsx("path", { d: "M5 12h14" })
|
|
401
|
+
] })
|
|
402
|
+
);
|
|
396
403
|
var IconImage = makeIcon(
|
|
397
404
|
"IconImage",
|
|
398
405
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -481,6 +488,7 @@ var DEFAULT_ICONS = {
|
|
|
481
488
|
send: IconSend,
|
|
482
489
|
stop: IconStop,
|
|
483
490
|
attach: IconAttach,
|
|
491
|
+
plus: IconPlus,
|
|
484
492
|
image: IconImage,
|
|
485
493
|
voice: IconVoice,
|
|
486
494
|
voiceRecording: IconVoiceRecording,
|
|
@@ -506,6 +514,8 @@ var DEFAULT_FEATURES = {
|
|
|
506
514
|
voice: true,
|
|
507
515
|
mermaid: true,
|
|
508
516
|
web: true,
|
|
517
|
+
// No consumer-defined actions by default.
|
|
518
|
+
custom: [],
|
|
509
519
|
// Off by default — ghost autocomplete is an opt-in input affordance that
|
|
510
520
|
// only makes sense when the consumer has a curated list of completions.
|
|
511
521
|
ghostedAutoComplete: false
|
|
@@ -537,6 +547,7 @@ function normalizeFeatures(features) {
|
|
|
537
547
|
voice: features.voice ?? DEFAULT_FEATURES.voice,
|
|
538
548
|
mermaid: features.mermaid ?? DEFAULT_FEATURES.mermaid,
|
|
539
549
|
web: features.web ?? DEFAULT_FEATURES.web,
|
|
550
|
+
custom: features.custom ?? DEFAULT_FEATURES.custom,
|
|
540
551
|
ghostedAutoComplete: features.ghostedAutoComplete ?? DEFAULT_FEATURES.ghostedAutoComplete
|
|
541
552
|
};
|
|
542
553
|
}
|
|
@@ -552,6 +563,7 @@ function ComposerProvider({
|
|
|
552
563
|
closeMenusOnOutsideClick = true,
|
|
553
564
|
attachmentOptions,
|
|
554
565
|
mode = "markdown",
|
|
566
|
+
variant = "compact",
|
|
555
567
|
multiline = true,
|
|
556
568
|
submitOnEnter = true,
|
|
557
569
|
smartNewline = true,
|
|
@@ -730,6 +742,7 @@ function ComposerProvider({
|
|
|
730
742
|
attachmentOptions: normalizedAttachmentOptions,
|
|
731
743
|
markdownMode,
|
|
732
744
|
mode,
|
|
745
|
+
variant,
|
|
733
746
|
multiline,
|
|
734
747
|
submitOnEnter,
|
|
735
748
|
smartNewline,
|
|
@@ -762,6 +775,7 @@ function ComposerProvider({
|
|
|
762
775
|
normalizedAttachmentOptions,
|
|
763
776
|
markdownMode,
|
|
764
777
|
mode,
|
|
778
|
+
variant,
|
|
765
779
|
multiline,
|
|
766
780
|
submitOnEnter,
|
|
767
781
|
smartNewline,
|
|
@@ -787,7 +801,9 @@ function useComposerContext() {
|
|
|
787
801
|
function EditorShell({
|
|
788
802
|
placeholder,
|
|
789
803
|
mode,
|
|
804
|
+
variant,
|
|
790
805
|
multiline,
|
|
806
|
+
expanded,
|
|
791
807
|
header,
|
|
792
808
|
toolbar,
|
|
793
809
|
sendButton,
|
|
@@ -795,11 +811,14 @@ function EditorShell({
|
|
|
795
811
|
}) {
|
|
796
812
|
const { classNames, sx, dir } = useComposerContext();
|
|
797
813
|
const isMarkdown = mode === "markdown";
|
|
798
|
-
const
|
|
814
|
+
const isCompact = variant === "compact";
|
|
815
|
+
const compactInline = isCompact && !expanded;
|
|
816
|
+
const fillEditor = compactInline || !isCompact && !multiline;
|
|
817
|
+
const editorClass = isCompact ? "composer-editor composer-editor--compact" : multiline ? "composer-editor composer-editor--multiline" : "composer-editor composer-editor--inline";
|
|
799
818
|
const editor = slotProps("editor", editorClass, classNames, sx);
|
|
800
819
|
const editorResolved = resolveSx(sx?.editor);
|
|
801
820
|
const placeholderBase = mirrorEditorPadding(editorResolved);
|
|
802
|
-
const placeholderClass = multiline ? "composer-placeholder composer-placeholder--multiline" : "composer-placeholder composer-placeholder--inline";
|
|
821
|
+
const placeholderClass = isCompact ? "composer-placeholder composer-placeholder--compact" : multiline ? "composer-placeholder composer-placeholder--multiline" : "composer-placeholder composer-placeholder--inline";
|
|
803
822
|
const placeholderProps = slotProps(
|
|
804
823
|
"placeholder",
|
|
805
824
|
placeholderClass,
|
|
@@ -814,8 +833,9 @@ function EditorShell({
|
|
|
814
833
|
{
|
|
815
834
|
className: cn(
|
|
816
835
|
"composer-editor-block",
|
|
817
|
-
// Inline: the editor block is the flex child that fills the
|
|
818
|
-
|
|
836
|
+
// Inline + compact: the editor block is the flex child that fills the
|
|
837
|
+
// row between the leading actions and the trailing send cluster.
|
|
838
|
+
fillEditor && "composer-editor-block--inline"
|
|
819
839
|
),
|
|
820
840
|
children: isMarkdown ? /* @__PURE__ */ jsx(
|
|
821
841
|
RichTextPlugin,
|
|
@@ -834,6 +854,32 @@ function EditorShell({
|
|
|
834
854
|
)
|
|
835
855
|
}
|
|
836
856
|
);
|
|
857
|
+
if (isCompact) {
|
|
858
|
+
const actions = toolbar && /* @__PURE__ */ jsx("div", { className: "composer-compact-actions", children: toolbar });
|
|
859
|
+
const sendCluster = sendButton && /* @__PURE__ */ jsx("div", { className: "composer-compact-send", children: sendButton });
|
|
860
|
+
if (expanded) {
|
|
861
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
862
|
+
header,
|
|
863
|
+
editorBlock,
|
|
864
|
+
(actions || sendCluster) && /* @__PURE__ */ jsxs("div", { className: "composer-compact-footer", children: [
|
|
865
|
+
actions ?? /* @__PURE__ */ jsx("span", {}),
|
|
866
|
+
sendCluster
|
|
867
|
+
] }),
|
|
868
|
+
/* @__PURE__ */ jsx(HistoryPlugin, {}),
|
|
869
|
+
footer
|
|
870
|
+
] });
|
|
871
|
+
}
|
|
872
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
873
|
+
header,
|
|
874
|
+
/* @__PURE__ */ jsxs("div", { className: "composer-compact-row", children: [
|
|
875
|
+
actions,
|
|
876
|
+
editorBlock,
|
|
877
|
+
sendCluster
|
|
878
|
+
] }),
|
|
879
|
+
/* @__PURE__ */ jsx(HistoryPlugin, {}),
|
|
880
|
+
footer
|
|
881
|
+
] });
|
|
882
|
+
}
|
|
837
883
|
if (!multiline) {
|
|
838
884
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
839
885
|
header,
|
|
@@ -1224,6 +1270,63 @@ function $createLinkTextNode(text = "", url = "") {
|
|
|
1224
1270
|
function $isLinkTextNode(node) {
|
|
1225
1271
|
return node instanceof LinkTextNode;
|
|
1226
1272
|
}
|
|
1273
|
+
var BASE_CLASS = "composer-code-tok";
|
|
1274
|
+
var CodeTokenNode = class _CodeTokenNode extends TextNode {
|
|
1275
|
+
__codeKind;
|
|
1276
|
+
static getType() {
|
|
1277
|
+
return "composeai-code-token";
|
|
1278
|
+
}
|
|
1279
|
+
static clone(node) {
|
|
1280
|
+
return new _CodeTokenNode(node.__text, node.__codeKind, node.__key);
|
|
1281
|
+
}
|
|
1282
|
+
constructor(text = "", codeKind = "text", key) {
|
|
1283
|
+
super(text, key);
|
|
1284
|
+
this.__codeKind = codeKind;
|
|
1285
|
+
}
|
|
1286
|
+
getCodeKind() {
|
|
1287
|
+
return this.getLatest().__codeKind;
|
|
1288
|
+
}
|
|
1289
|
+
setCodeKind(kind) {
|
|
1290
|
+
const self = this.getWritable();
|
|
1291
|
+
self.__codeKind = kind;
|
|
1292
|
+
return self;
|
|
1293
|
+
}
|
|
1294
|
+
createDOM(config) {
|
|
1295
|
+
const dom = super.createDOM(config);
|
|
1296
|
+
addClassNamesToElement(dom, BASE_CLASS, `${BASE_CLASS}--${this.__codeKind}`);
|
|
1297
|
+
return dom;
|
|
1298
|
+
}
|
|
1299
|
+
updateDOM(prevNode, dom, config) {
|
|
1300
|
+
const updated = super.updateDOM(prevNode, dom, config);
|
|
1301
|
+
if (prevNode.__codeKind !== this.__codeKind) {
|
|
1302
|
+
dom.classList.remove(`${BASE_CLASS}--${prevNode.__codeKind}`);
|
|
1303
|
+
dom.classList.add(`${BASE_CLASS}--${this.__codeKind}`);
|
|
1304
|
+
}
|
|
1305
|
+
return updated;
|
|
1306
|
+
}
|
|
1307
|
+
static importJSON(serializedNode) {
|
|
1308
|
+
return $createCodeTokenNode("", serializedNode.codeKind).updateFromJSON(
|
|
1309
|
+
serializedNode
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
updateFromJSON(serializedNode) {
|
|
1313
|
+
return super.updateFromJSON(serializedNode);
|
|
1314
|
+
}
|
|
1315
|
+
exportJSON() {
|
|
1316
|
+
return {
|
|
1317
|
+
...super.exportJSON(),
|
|
1318
|
+
type: _CodeTokenNode.getType(),
|
|
1319
|
+
version: 1,
|
|
1320
|
+
codeKind: this.__codeKind
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
function $createCodeTokenNode(text = "", codeKind = "text") {
|
|
1325
|
+
return $applyNodeReplacement(new CodeTokenNode(text, codeKind));
|
|
1326
|
+
}
|
|
1327
|
+
function $isCodeTokenNode(node) {
|
|
1328
|
+
return node instanceof CodeTokenNode;
|
|
1329
|
+
}
|
|
1227
1330
|
var HEADING_RE = /^(#{1,6}) /;
|
|
1228
1331
|
var QUOTE_RE = /^> /;
|
|
1229
1332
|
var BULLET_RE = /^[-*+] /;
|
|
@@ -1297,12 +1400,20 @@ function $computeBlockMap() {
|
|
|
1297
1400
|
const map = /* @__PURE__ */ new Map();
|
|
1298
1401
|
const root = $getRoot();
|
|
1299
1402
|
let insideCode = false;
|
|
1403
|
+
let codeLang;
|
|
1300
1404
|
for (const child of root.getChildren()) {
|
|
1301
1405
|
if (!$isParagraphNode(child)) continue;
|
|
1302
|
-
|
|
1406
|
+
let info = $resolveBlockFor(child, insideCode);
|
|
1407
|
+
if (info.kind === "code-fence-open") {
|
|
1408
|
+
insideCode = true;
|
|
1409
|
+
codeLang = info.lang;
|
|
1410
|
+
} else if (info.kind === "code-fence-close") {
|
|
1411
|
+
insideCode = false;
|
|
1412
|
+
codeLang = void 0;
|
|
1413
|
+
} else if (info.kind === "code-line" && codeLang) {
|
|
1414
|
+
info = { ...info, lang: codeLang };
|
|
1415
|
+
}
|
|
1303
1416
|
map.set(child.getKey(), info);
|
|
1304
|
-
if (info.kind === "code-fence-open") insideCode = true;
|
|
1305
|
-
else if (info.kind === "code-fence-close") insideCode = false;
|
|
1306
1417
|
}
|
|
1307
1418
|
return map;
|
|
1308
1419
|
}
|
|
@@ -1397,7 +1508,8 @@ function wrapByFormat(text, format) {
|
|
|
1397
1508
|
if (format & FORMAT_BIT.strike) out = `~~${out}~~`;
|
|
1398
1509
|
return out;
|
|
1399
1510
|
}
|
|
1400
|
-
function toMarkdown(editor) {
|
|
1511
|
+
function toMarkdown(editor, opts) {
|
|
1512
|
+
const linkedMention = opts?.linkedMention === true;
|
|
1401
1513
|
return editor.getEditorState().read(() => {
|
|
1402
1514
|
const root = $getRoot();
|
|
1403
1515
|
let usingLive = true;
|
|
@@ -1422,7 +1534,13 @@ function toMarkdown(editor) {
|
|
|
1422
1534
|
let out = "";
|
|
1423
1535
|
for (const child of paragraph.getChildren()) {
|
|
1424
1536
|
if ($isMentionNode(child)) {
|
|
1425
|
-
|
|
1537
|
+
const prefix = child.getMentionPrefix();
|
|
1538
|
+
const label = child.getMentionLabel();
|
|
1539
|
+
if (linkedMention) {
|
|
1540
|
+
out += `[${prefix}${label}](mention:${child.getMentionId()})`;
|
|
1541
|
+
} else {
|
|
1542
|
+
out += `${prefix}${label}`;
|
|
1543
|
+
}
|
|
1426
1544
|
continue;
|
|
1427
1545
|
}
|
|
1428
1546
|
if ($isLineBreakNode(child)) {
|
|
@@ -1501,11 +1619,6 @@ function $isInsideCodeFence() {
|
|
|
1501
1619
|
const block = $detectBlockFor(top);
|
|
1502
1620
|
return block.kind === "code-line" || block.kind === "code-fence-open";
|
|
1503
1621
|
}
|
|
1504
|
-
function $hasMultiLineContent() {
|
|
1505
|
-
const root = $getRoot();
|
|
1506
|
-
if (root.getChildrenSize() > 1) return true;
|
|
1507
|
-
return root.getTextContent().includes("\n");
|
|
1508
|
-
}
|
|
1509
1622
|
function $offsetWithinParagraph(paragraph, point) {
|
|
1510
1623
|
if (point.type === "element") {
|
|
1511
1624
|
const children = paragraph.getChildren();
|
|
@@ -1598,10 +1711,8 @@ function KeyboardPlugin({ onSubmit }) {
|
|
|
1598
1711
|
return true;
|
|
1599
1712
|
}
|
|
1600
1713
|
let inCodeFence = false;
|
|
1601
|
-
let hasMultiLine = false;
|
|
1602
1714
|
editor.getEditorState().read(() => {
|
|
1603
1715
|
inCodeFence = $isInsideCodeFence();
|
|
1604
|
-
hasMultiLine = $hasMultiLineContent();
|
|
1605
1716
|
});
|
|
1606
1717
|
if (inCodeFence) {
|
|
1607
1718
|
if (!multiline) {
|
|
@@ -1623,7 +1734,6 @@ function KeyboardPlugin({ onSubmit }) {
|
|
|
1623
1734
|
return true;
|
|
1624
1735
|
}
|
|
1625
1736
|
}
|
|
1626
|
-
if (smartNewline && hasMultiLine) return false;
|
|
1627
1737
|
if (!submitOnEnter) return false;
|
|
1628
1738
|
return trySubmit(event);
|
|
1629
1739
|
},
|
|
@@ -1753,6 +1863,134 @@ function PasteDropPlugin() {
|
|
|
1753
1863
|
return null;
|
|
1754
1864
|
}
|
|
1755
1865
|
|
|
1866
|
+
// src/plugins/mermaid-highlight.ts
|
|
1867
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
1868
|
+
"flowchart",
|
|
1869
|
+
"graph",
|
|
1870
|
+
"sequenceDiagram",
|
|
1871
|
+
"classDiagram",
|
|
1872
|
+
"stateDiagram",
|
|
1873
|
+
"stateDiagram-v2",
|
|
1874
|
+
"erDiagram",
|
|
1875
|
+
"journey",
|
|
1876
|
+
"gantt",
|
|
1877
|
+
"pie",
|
|
1878
|
+
"gitGraph",
|
|
1879
|
+
"mindmap",
|
|
1880
|
+
"timeline",
|
|
1881
|
+
"quadrantChart",
|
|
1882
|
+
"requirementDiagram",
|
|
1883
|
+
"C4Context",
|
|
1884
|
+
"subgraph",
|
|
1885
|
+
"end",
|
|
1886
|
+
"direction",
|
|
1887
|
+
"participant",
|
|
1888
|
+
"actor",
|
|
1889
|
+
"note",
|
|
1890
|
+
"loop",
|
|
1891
|
+
"alt",
|
|
1892
|
+
"opt",
|
|
1893
|
+
"par",
|
|
1894
|
+
"and",
|
|
1895
|
+
"else",
|
|
1896
|
+
"rect",
|
|
1897
|
+
"activate",
|
|
1898
|
+
"deactivate",
|
|
1899
|
+
"class",
|
|
1900
|
+
"state",
|
|
1901
|
+
"click",
|
|
1902
|
+
"call",
|
|
1903
|
+
"href",
|
|
1904
|
+
"style",
|
|
1905
|
+
"linkStyle",
|
|
1906
|
+
"classDef",
|
|
1907
|
+
"section",
|
|
1908
|
+
"title",
|
|
1909
|
+
"accTitle",
|
|
1910
|
+
"accDescr",
|
|
1911
|
+
"over",
|
|
1912
|
+
"as",
|
|
1913
|
+
// flowchart directions
|
|
1914
|
+
"TB",
|
|
1915
|
+
"TD",
|
|
1916
|
+
"BT",
|
|
1917
|
+
"RL",
|
|
1918
|
+
"LR"
|
|
1919
|
+
]);
|
|
1920
|
+
var ARROW_CHARS = /* @__PURE__ */ new Set(["-", "=", ".", "<", ">"]);
|
|
1921
|
+
var WS_RE = /\s/;
|
|
1922
|
+
var WORD_RE = /[A-Za-z0-9_]/;
|
|
1923
|
+
var DIGIT_RE = /[0-9]/;
|
|
1924
|
+
function tokenizeMermaidLine(line) {
|
|
1925
|
+
const out = [];
|
|
1926
|
+
const push = (text, kind) => {
|
|
1927
|
+
if (text) out.push({ text, kind });
|
|
1928
|
+
};
|
|
1929
|
+
let i = 0;
|
|
1930
|
+
const n = line.length;
|
|
1931
|
+
while (i < n) {
|
|
1932
|
+
const c = line[i];
|
|
1933
|
+
if (WS_RE.test(c)) {
|
|
1934
|
+
let j = i + 1;
|
|
1935
|
+
while (j < n && WS_RE.test(line[j])) j++;
|
|
1936
|
+
push(line.slice(i, j), "text");
|
|
1937
|
+
i = j;
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
if (c === "%" && line[i + 1] === "%") {
|
|
1941
|
+
push(line.slice(i), "comment");
|
|
1942
|
+
i = n;
|
|
1943
|
+
continue;
|
|
1944
|
+
}
|
|
1945
|
+
if (c === '"') {
|
|
1946
|
+
let j = i + 1;
|
|
1947
|
+
while (j < n && line[j] !== '"') j++;
|
|
1948
|
+
j = Math.min(j + 1, n);
|
|
1949
|
+
push(line.slice(i, j), "string");
|
|
1950
|
+
i = j;
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
if ("[](){}|".includes(c)) {
|
|
1954
|
+
push(c, "punct");
|
|
1955
|
+
i++;
|
|
1956
|
+
continue;
|
|
1957
|
+
}
|
|
1958
|
+
if (ARROW_CHARS.has(c)) {
|
|
1959
|
+
let j = i + 1;
|
|
1960
|
+
while (j < n && ARROW_CHARS.has(line[j])) j++;
|
|
1961
|
+
if (j < n && (line[j] === "x" || line[j] === "o") && j - i >= 2) j++;
|
|
1962
|
+
const run = line.slice(i, j);
|
|
1963
|
+
const isArrow = run.length >= 2 || run.includes(">") || run.includes("<");
|
|
1964
|
+
push(run, isArrow ? "arrow" : "punct");
|
|
1965
|
+
i = j;
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
if (":;,&+*".includes(c)) {
|
|
1969
|
+
push(c, "punct");
|
|
1970
|
+
i++;
|
|
1971
|
+
continue;
|
|
1972
|
+
}
|
|
1973
|
+
if (DIGIT_RE.test(c)) {
|
|
1974
|
+
let j = i + 1;
|
|
1975
|
+
while (j < n && /[0-9.]/.test(line[j])) j++;
|
|
1976
|
+
push(line.slice(i, j), "number");
|
|
1977
|
+
i = j;
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
if (WORD_RE.test(c)) {
|
|
1981
|
+
let j = i + 1;
|
|
1982
|
+
while (j < n && WORD_RE.test(line[j])) j++;
|
|
1983
|
+
const word = line.slice(i, j);
|
|
1984
|
+
push(word, KEYWORDS.has(word) ? "keyword" : "ident");
|
|
1985
|
+
i = j;
|
|
1986
|
+
continue;
|
|
1987
|
+
}
|
|
1988
|
+
push(c, "text");
|
|
1989
|
+
i++;
|
|
1990
|
+
}
|
|
1991
|
+
return out;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1756
1994
|
// src/plugins/markdown-tokenizer.ts
|
|
1757
1995
|
var PAIRED_PATTERNS = [
|
|
1758
1996
|
{ open: "**", close: "**", format: "bold" },
|
|
@@ -1864,6 +2102,13 @@ function readCurrentChildren(paragraph) {
|
|
|
1864
2102
|
});
|
|
1865
2103
|
} else if ($isMarkdownTokenNode(child)) {
|
|
1866
2104
|
out.push({ kind: "token", text: child.getTextContent(), format: 0 });
|
|
2105
|
+
} else if ($isCodeTokenNode(child)) {
|
|
2106
|
+
out.push({
|
|
2107
|
+
kind: "code",
|
|
2108
|
+
text: child.getTextContent(),
|
|
2109
|
+
format: 0,
|
|
2110
|
+
codeKind: child.getCodeKind()
|
|
2111
|
+
});
|
|
1867
2112
|
} else if ($isTextNode(child)) {
|
|
1868
2113
|
out.push({
|
|
1869
2114
|
kind: "text",
|
|
@@ -1886,6 +2131,7 @@ function nodesEqual(a, b) {
|
|
|
1886
2131
|
if (aKind !== bKind) return false;
|
|
1887
2132
|
if (ai.text !== bi.text) return false;
|
|
1888
2133
|
if (ai.format !== bi.format) return false;
|
|
2134
|
+
if (ai.codeKind !== bi.codeKind) return false;
|
|
1889
2135
|
}
|
|
1890
2136
|
return true;
|
|
1891
2137
|
}
|
|
@@ -2053,7 +2299,18 @@ function $applyStyling(paragraph, block, mode) {
|
|
|
2053
2299
|
trailingDropForOffsetMap = body.length;
|
|
2054
2300
|
body = "";
|
|
2055
2301
|
} else if (body.length > 0) {
|
|
2056
|
-
|
|
2302
|
+
if (block.kind === "code-line" && block.lang === "mermaid") {
|
|
2303
|
+
for (const tok of tokenizeMermaidLine(body)) {
|
|
2304
|
+
desired.push({
|
|
2305
|
+
kind: "code",
|
|
2306
|
+
text: tok.text,
|
|
2307
|
+
format: 0,
|
|
2308
|
+
codeKind: tok.kind
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
} else {
|
|
2312
|
+
desired.push({ kind: "text", text: body, format: 0 });
|
|
2313
|
+
}
|
|
2057
2314
|
}
|
|
2058
2315
|
} else if (block.kind === "hr") {
|
|
2059
2316
|
if (body.length > 0) {
|
|
@@ -2141,6 +2398,8 @@ function $applyStyling(paragraph, block, mode) {
|
|
|
2141
2398
|
for (const node of desired) {
|
|
2142
2399
|
if (node.kind === "token") {
|
|
2143
2400
|
paragraph.append($createMarkdownTokenNode(node.text));
|
|
2401
|
+
} else if (node.kind === "code") {
|
|
2402
|
+
paragraph.append($createCodeTokenNode(node.text, node.codeKind));
|
|
2144
2403
|
} else if (node.kind === "link") {
|
|
2145
2404
|
const t = $createLinkTextNode(node.text, node.url ?? "");
|
|
2146
2405
|
if (node.format !== 0) t.setFormat(node.format);
|
|
@@ -2402,10 +2661,13 @@ async function loadMermaid() {
|
|
|
2402
2661
|
function svgToDataUri(svg) {
|
|
2403
2662
|
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
|
2404
2663
|
}
|
|
2405
|
-
|
|
2664
|
+
var MermaidContext = createContext(null);
|
|
2665
|
+
function useMermaidContext() {
|
|
2666
|
+
return useContext(MermaidContext);
|
|
2667
|
+
}
|
|
2668
|
+
function MermaidProvider({ children }) {
|
|
2406
2669
|
const [editor] = useLexicalComposerContext();
|
|
2407
|
-
const { features,
|
|
2408
|
-
const { sparkle: SparkleIcon } = icons;
|
|
2670
|
+
const { features, renderDiagram } = useComposerContext();
|
|
2409
2671
|
const [diagrams, setDiagrams] = useState([]);
|
|
2410
2672
|
const keepSource = typeof features.mermaid === "object" ? features.mermaid.keepSource !== false : true;
|
|
2411
2673
|
useEffect(() => {
|
|
@@ -2413,10 +2675,10 @@ function MermaidPlugin() {
|
|
|
2413
2675
|
editor.getEditorState().read(() => {
|
|
2414
2676
|
const found = [];
|
|
2415
2677
|
const root = $getRoot();
|
|
2416
|
-
const
|
|
2678
|
+
const children2 = root.getChildren();
|
|
2417
2679
|
let i = 0;
|
|
2418
|
-
while (i <
|
|
2419
|
-
const opener =
|
|
2680
|
+
while (i < children2.length) {
|
|
2681
|
+
const opener = children2[i];
|
|
2420
2682
|
if (!$isParagraphNode(opener) || !FENCE_OPEN_MERMAID.test(opener.getTextContent())) {
|
|
2421
2683
|
i++;
|
|
2422
2684
|
continue;
|
|
@@ -2424,8 +2686,8 @@ function MermaidPlugin() {
|
|
|
2424
2686
|
const paragraphKeys = [opener.getKey()];
|
|
2425
2687
|
const codeLines = [];
|
|
2426
2688
|
let j = i + 1;
|
|
2427
|
-
while (j <
|
|
2428
|
-
const next =
|
|
2689
|
+
while (j < children2.length) {
|
|
2690
|
+
const next = children2[j];
|
|
2429
2691
|
if (!$isParagraphNode(next)) break;
|
|
2430
2692
|
const text = next.getTextContent();
|
|
2431
2693
|
paragraphKeys.push(next.getKey());
|
|
@@ -2489,26 +2751,190 @@ function MermaidPlugin() {
|
|
|
2489
2751
|
hiddenKeysRef.current.clear();
|
|
2490
2752
|
};
|
|
2491
2753
|
}, [editor]);
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
"composer-mermaid",
|
|
2496
|
-
classNames,
|
|
2497
|
-
sx
|
|
2754
|
+
const value = useMemo(
|
|
2755
|
+
() => ({ diagrams, renderDiagram }),
|
|
2756
|
+
[diagrams, renderDiagram]
|
|
2498
2757
|
);
|
|
2758
|
+
return /* @__PURE__ */ jsxs(MermaidContext.Provider, { value, children: [
|
|
2759
|
+
children,
|
|
2760
|
+
/* @__PURE__ */ jsx(MermaidBackground, {})
|
|
2761
|
+
] });
|
|
2762
|
+
}
|
|
2763
|
+
function MermaidBackground() {
|
|
2764
|
+
const ctx = useMermaidContext();
|
|
2765
|
+
if (!ctx || ctx.renderDiagram) return null;
|
|
2766
|
+
return /* @__PURE__ */ jsx(Fragment, { children: ctx.diagrams.map((d) => /* @__PURE__ */ jsx(DiagramBackdrop, { diagram: d }, d.id)) });
|
|
2767
|
+
}
|
|
2768
|
+
function DiagramBackdrop({ diagram }) {
|
|
2769
|
+
const [editor] = useLexicalComposerContext();
|
|
2770
|
+
const { svg } = useDiagramSvg(diagram);
|
|
2771
|
+
const [rect, setRect] = useState(null);
|
|
2772
|
+
const dataUri = useMemo(() => svg ? svgToDataUri(svg) : null, [svg]);
|
|
2773
|
+
useEffect(() => {
|
|
2774
|
+
if (!svg) {
|
|
2775
|
+
setRect(null);
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
const root = editor.getRootElement();
|
|
2779
|
+
const block2 = root?.parentElement;
|
|
2780
|
+
if (!root || !block2) return;
|
|
2781
|
+
let raf = 0;
|
|
2782
|
+
const measure = () => {
|
|
2783
|
+
raf = 0;
|
|
2784
|
+
const blockRect = block2.getBoundingClientRect();
|
|
2785
|
+
let top = Infinity;
|
|
2786
|
+
let left = Infinity;
|
|
2787
|
+
let right = -Infinity;
|
|
2788
|
+
let bottom = -Infinity;
|
|
2789
|
+
let any = false;
|
|
2790
|
+
for (const key of diagram.paragraphKeys) {
|
|
2791
|
+
const el = editor.getElementByKey(key);
|
|
2792
|
+
if (!el) continue;
|
|
2793
|
+
any = true;
|
|
2794
|
+
const r = el.getBoundingClientRect();
|
|
2795
|
+
top = Math.min(top, r.top);
|
|
2796
|
+
left = Math.min(left, r.left);
|
|
2797
|
+
right = Math.max(right, r.right);
|
|
2798
|
+
bottom = Math.max(bottom, r.bottom);
|
|
2799
|
+
}
|
|
2800
|
+
if (!any) {
|
|
2801
|
+
setRect(null);
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
const relTop = top - blockRect.top;
|
|
2805
|
+
const visTop = Math.max(0, relTop);
|
|
2806
|
+
const visBottom = Math.min(blockRect.height, relTop + (bottom - top));
|
|
2807
|
+
if (visBottom <= visTop) {
|
|
2808
|
+
setRect(null);
|
|
2809
|
+
return;
|
|
2810
|
+
}
|
|
2811
|
+
setRect({
|
|
2812
|
+
top: visTop,
|
|
2813
|
+
left: left - blockRect.left,
|
|
2814
|
+
width: right - left,
|
|
2815
|
+
height: visBottom - visTop
|
|
2816
|
+
});
|
|
2817
|
+
};
|
|
2818
|
+
const schedule = () => {
|
|
2819
|
+
if (!raf) raf = requestAnimationFrame(measure);
|
|
2820
|
+
};
|
|
2821
|
+
schedule();
|
|
2822
|
+
const unregister = editor.registerUpdateListener(schedule);
|
|
2823
|
+
root.addEventListener("scroll", schedule, { passive: true });
|
|
2824
|
+
const ro = new ResizeObserver(schedule);
|
|
2825
|
+
ro.observe(root);
|
|
2826
|
+
return () => {
|
|
2827
|
+
if (raf) cancelAnimationFrame(raf);
|
|
2828
|
+
unregister();
|
|
2829
|
+
root.removeEventListener("scroll", schedule);
|
|
2830
|
+
ro.disconnect();
|
|
2831
|
+
};
|
|
2832
|
+
}, [editor, svg, diagram.paragraphKeys]);
|
|
2833
|
+
const block = editor.getRootElement()?.parentElement;
|
|
2834
|
+
if (!dataUri || !rect || !block) return null;
|
|
2835
|
+
return createPortal(
|
|
2836
|
+
/* @__PURE__ */ jsx(
|
|
2837
|
+
"div",
|
|
2838
|
+
{
|
|
2839
|
+
"aria-hidden": true,
|
|
2840
|
+
className: "composer-mermaid-backdrop",
|
|
2841
|
+
style: {
|
|
2842
|
+
top: rect.top,
|
|
2843
|
+
left: rect.left,
|
|
2844
|
+
width: rect.width,
|
|
2845
|
+
height: rect.height,
|
|
2846
|
+
backgroundImage: `url("${dataUri}")`
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
),
|
|
2850
|
+
block
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
function MermaidPreview() {
|
|
2854
|
+
const ctx = useMermaidContext();
|
|
2855
|
+
const { icons, classNames, sx } = useComposerContext();
|
|
2856
|
+
const { sparkle: SparkleIcon } = icons;
|
|
2857
|
+
if (!ctx || ctx.diagrams.length === 0) return null;
|
|
2858
|
+
const preview = slotProps("mermaidPreview", "composer-mermaid", classNames, sx);
|
|
2499
2859
|
return /* @__PURE__ */ jsxs("div", { ...preview, children: [
|
|
2500
2860
|
/* @__PURE__ */ jsxs("div", { className: "composer-mermaid-head", children: [
|
|
2501
2861
|
/* @__PURE__ */ jsx(SparkleIcon, {}),
|
|
2502
2862
|
"Diagram preview"
|
|
2503
2863
|
] }),
|
|
2504
|
-
/* @__PURE__ */ jsx("div", { className: "composer-mermaid-row", children: diagrams.map((d) => /* @__PURE__ */ jsx(
|
|
2505
|
-
|
|
2864
|
+
/* @__PURE__ */ jsx("div", { className: "composer-mermaid-row", children: ctx.diagrams.map((d) => /* @__PURE__ */ jsx(DiagramTile, { diagram: d, renderDiagram: ctx.renderDiagram }, d.id)) })
|
|
2865
|
+
] });
|
|
2866
|
+
}
|
|
2867
|
+
function MermaidQuickAction() {
|
|
2868
|
+
const ctx = useMermaidContext();
|
|
2869
|
+
const { icons, closeMenusOnOutsideClick } = useComposerContext();
|
|
2870
|
+
const { sparkle: SparkleIcon } = icons;
|
|
2871
|
+
const [open, setOpen] = useState(false);
|
|
2872
|
+
const triggerRef = useRef(null);
|
|
2873
|
+
const popoverRef = useRef(null);
|
|
2874
|
+
const menuId = useId();
|
|
2875
|
+
useEffect(() => {
|
|
2876
|
+
if (!open) return;
|
|
2877
|
+
const onPointerDown = (event) => {
|
|
2878
|
+
if (!closeMenusOnOutsideClick) return;
|
|
2879
|
+
const target = event.target;
|
|
2880
|
+
if (!target) return;
|
|
2881
|
+
if (popoverRef.current?.contains(target)) return;
|
|
2882
|
+
if (triggerRef.current?.contains(target)) return;
|
|
2883
|
+
setOpen(false);
|
|
2884
|
+
};
|
|
2885
|
+
const onKeyDown = (event) => {
|
|
2886
|
+
if (event.key === "Escape") {
|
|
2887
|
+
event.preventDefault();
|
|
2888
|
+
setOpen(false);
|
|
2889
|
+
triggerRef.current?.focus();
|
|
2890
|
+
}
|
|
2891
|
+
};
|
|
2892
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
2893
|
+
document.addEventListener("keydown", onKeyDown);
|
|
2894
|
+
return () => {
|
|
2895
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
2896
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
2897
|
+
};
|
|
2898
|
+
}, [open, closeMenusOnOutsideClick]);
|
|
2899
|
+
if (!ctx || ctx.diagrams.length === 0) return null;
|
|
2900
|
+
const count = ctx.diagrams.length;
|
|
2901
|
+
return /* @__PURE__ */ jsxs("div", { className: "composer-quick-actions", children: [
|
|
2902
|
+
/* @__PURE__ */ jsxs(
|
|
2903
|
+
"button",
|
|
2506
2904
|
{
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2905
|
+
ref: triggerRef,
|
|
2906
|
+
type: "button",
|
|
2907
|
+
"aria-label": `Diagram preview (${count})`,
|
|
2908
|
+
"aria-haspopup": "dialog",
|
|
2909
|
+
"aria-expanded": open,
|
|
2910
|
+
"aria-controls": open ? menuId : void 0,
|
|
2911
|
+
"data-active": open ? "" : void 0,
|
|
2912
|
+
onClick: () => setOpen((o) => !o),
|
|
2913
|
+
className: "composer-mermaid-trigger",
|
|
2914
|
+
children: [
|
|
2915
|
+
/* @__PURE__ */ jsx(DiagramThumb, { diagram: ctx.diagrams[0], renderDiagram: ctx.renderDiagram }),
|
|
2916
|
+
count > 1 && /* @__PURE__ */ jsx("span", { className: "composer-mermaid-count", children: count })
|
|
2917
|
+
]
|
|
2918
|
+
}
|
|
2919
|
+
),
|
|
2920
|
+
open && /* @__PURE__ */ jsxs(
|
|
2921
|
+
"div",
|
|
2922
|
+
{
|
|
2923
|
+
ref: popoverRef,
|
|
2924
|
+
id: menuId,
|
|
2925
|
+
role: "dialog",
|
|
2926
|
+
"aria-label": "Diagram preview",
|
|
2927
|
+
"data-composer-popover": "open",
|
|
2928
|
+
className: "composer-popover-in composer-mermaid-pop",
|
|
2929
|
+
children: [
|
|
2930
|
+
/* @__PURE__ */ jsxs("div", { className: "composer-mermaid-head", children: [
|
|
2931
|
+
/* @__PURE__ */ jsx(SparkleIcon, {}),
|
|
2932
|
+
"Diagram preview"
|
|
2933
|
+
] }),
|
|
2934
|
+
/* @__PURE__ */ jsx("div", { className: "composer-mermaid-row", children: ctx.diagrams.map((d) => /* @__PURE__ */ jsx(DiagramTile, { diagram: d, renderDiagram: ctx.renderDiagram }, d.id)) })
|
|
2935
|
+
]
|
|
2936
|
+
}
|
|
2937
|
+
)
|
|
2512
2938
|
] });
|
|
2513
2939
|
}
|
|
2514
2940
|
function DiagramTile({ diagram, renderDiagram }) {
|
|
@@ -2530,12 +2956,9 @@ function ConsumerTile({
|
|
|
2530
2956
|
}
|
|
2531
2957
|
return /* @__PURE__ */ jsx("div", { className: "composer-mermaid-tile", children: content });
|
|
2532
2958
|
}
|
|
2533
|
-
function
|
|
2534
|
-
const { icons } = useComposerContext();
|
|
2535
|
-
const { zoom: ZoomIcon } = icons;
|
|
2959
|
+
function useDiagramSvg(diagram) {
|
|
2536
2960
|
const [svg, setSvg] = useState(null);
|
|
2537
2961
|
const [error, setError] = useState(null);
|
|
2538
|
-
const [zoom, setZoom] = useState(false);
|
|
2539
2962
|
const [mermaidMissing, setMermaidMissing] = useState(false);
|
|
2540
2963
|
const renderId = useMemo(
|
|
2541
2964
|
() => `mermaid-${diagram.id}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -2568,6 +2991,13 @@ function MermaidTile({ diagram }) {
|
|
|
2568
2991
|
cancelled = true;
|
|
2569
2992
|
};
|
|
2570
2993
|
}, [diagram.code, renderId]);
|
|
2994
|
+
return { svg, error, mermaidMissing };
|
|
2995
|
+
}
|
|
2996
|
+
function MermaidTile({ diagram }) {
|
|
2997
|
+
const { icons } = useComposerContext();
|
|
2998
|
+
const { zoom: ZoomIcon } = icons;
|
|
2999
|
+
const [zoom, setZoom] = useState(false);
|
|
3000
|
+
const { svg, error, mermaidMissing } = useDiagramSvg(diagram);
|
|
2571
3001
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2572
3002
|
/* @__PURE__ */ jsx(
|
|
2573
3003
|
"button",
|
|
@@ -2603,6 +3033,35 @@ function MermaidTile({ diagram }) {
|
|
|
2603
3033
|
)
|
|
2604
3034
|
] });
|
|
2605
3035
|
}
|
|
3036
|
+
function DiagramThumb({ diagram, renderDiagram }) {
|
|
3037
|
+
if (renderDiagram) {
|
|
3038
|
+
return /* @__PURE__ */ jsx(ConsumerThumb, { diagram, renderDiagram });
|
|
3039
|
+
}
|
|
3040
|
+
return /* @__PURE__ */ jsx(MermaidThumb, { diagram });
|
|
3041
|
+
}
|
|
3042
|
+
function ConsumerThumb({
|
|
3043
|
+
diagram,
|
|
3044
|
+
renderDiagram
|
|
3045
|
+
}) {
|
|
3046
|
+
let content = null;
|
|
3047
|
+
try {
|
|
3048
|
+
content = renderDiagram({ code: diagram.code, language: "mermaid" });
|
|
3049
|
+
} catch {
|
|
3050
|
+
content = null;
|
|
3051
|
+
}
|
|
3052
|
+
return /* @__PURE__ */ jsx("span", { className: "composer-mermaid-thumb", children: content });
|
|
3053
|
+
}
|
|
3054
|
+
function MermaidThumb({ diagram }) {
|
|
3055
|
+
const { svg } = useDiagramSvg(diagram);
|
|
3056
|
+
if (!svg) return /* @__PURE__ */ jsx("span", { className: "composer-mermaid-thumb" });
|
|
3057
|
+
return /* @__PURE__ */ jsx(
|
|
3058
|
+
"span",
|
|
3059
|
+
{
|
|
3060
|
+
className: "composer-mermaid-thumb",
|
|
3061
|
+
dangerouslySetInnerHTML: { __html: svg }
|
|
3062
|
+
}
|
|
3063
|
+
);
|
|
3064
|
+
}
|
|
2606
3065
|
function SlashMenu({
|
|
2607
3066
|
options,
|
|
2608
3067
|
selectedIndex,
|
|
@@ -3865,8 +4324,284 @@ function AttachmentTypePicker({
|
|
|
3865
4324
|
)
|
|
3866
4325
|
] });
|
|
3867
4326
|
}
|
|
4327
|
+
function useCustomActionContext(submit) {
|
|
4328
|
+
const [editor] = useLexicalComposerContext();
|
|
4329
|
+
return useMemo(
|
|
4330
|
+
() => ({
|
|
4331
|
+
insertText: (text) => {
|
|
4332
|
+
editor.update(() => {
|
|
4333
|
+
const sel = $getSelection();
|
|
4334
|
+
if ($isRangeSelection(sel)) sel.insertText(text);
|
|
4335
|
+
});
|
|
4336
|
+
focusEditor(editor);
|
|
4337
|
+
},
|
|
4338
|
+
insertMarkdown: (md) => {
|
|
4339
|
+
editor.update(() => {
|
|
4340
|
+
$insertTextWithParagraphBreaks(md);
|
|
4341
|
+
});
|
|
4342
|
+
focusEditor(editor);
|
|
4343
|
+
},
|
|
4344
|
+
submit
|
|
4345
|
+
}),
|
|
4346
|
+
[editor, submit]
|
|
4347
|
+
);
|
|
4348
|
+
}
|
|
4349
|
+
function CustomActionButtons({ submit }) {
|
|
4350
|
+
const { features, classNames, sx } = useComposerContext();
|
|
4351
|
+
const ctx = useCustomActionContext(submit);
|
|
4352
|
+
const actions = features.custom;
|
|
4353
|
+
const toolbarBtn = slotProps(
|
|
4354
|
+
"toolbarButton",
|
|
4355
|
+
"composer-toolbar-btn",
|
|
4356
|
+
classNames,
|
|
4357
|
+
sx
|
|
4358
|
+
);
|
|
4359
|
+
if (actions.length === 0) return null;
|
|
4360
|
+
return /* @__PURE__ */ jsx(Fragment, { children: actions.map((action, i) => /* @__PURE__ */ jsx(Tooltip, { content: action.title, side: "top", children: /* @__PURE__ */ jsx(
|
|
4361
|
+
"button",
|
|
4362
|
+
{
|
|
4363
|
+
type: "button",
|
|
4364
|
+
"aria-label": action.title,
|
|
4365
|
+
"aria-pressed": action.active,
|
|
4366
|
+
"data-active": action.active ? "" : void 0,
|
|
4367
|
+
disabled: action.disabled,
|
|
4368
|
+
onClick: () => action.onClick(ctx),
|
|
4369
|
+
...toolbarBtn,
|
|
4370
|
+
children: action.icon
|
|
4371
|
+
}
|
|
4372
|
+
) }, action.id ?? i)) });
|
|
4373
|
+
}
|
|
4374
|
+
function QuickActionsMenu({ extras, submit }) {
|
|
4375
|
+
const {
|
|
4376
|
+
features,
|
|
4377
|
+
attachmentsConfig,
|
|
4378
|
+
addFiles,
|
|
4379
|
+
webEnabled,
|
|
4380
|
+
toggleWeb,
|
|
4381
|
+
icons,
|
|
4382
|
+
classNames,
|
|
4383
|
+
sx,
|
|
4384
|
+
closeMenusOnOutsideClick
|
|
4385
|
+
} = useComposerContext();
|
|
4386
|
+
const {
|
|
4387
|
+
plus: PlusIcon,
|
|
4388
|
+
attach: AttachIcon,
|
|
4389
|
+
image: ImageIcon,
|
|
4390
|
+
web: WebIcon
|
|
4391
|
+
} = icons;
|
|
4392
|
+
const [open, setOpen] = useState(false);
|
|
4393
|
+
const triggerRef = useRef(null);
|
|
4394
|
+
const popoverRef = useRef(null);
|
|
4395
|
+
const fileInputRef = useRef(null);
|
|
4396
|
+
const imageInputRef = useRef(null);
|
|
4397
|
+
const menuId = useId();
|
|
4398
|
+
const attachmentsEnabled = !!features.attachments;
|
|
4399
|
+
const showFileBtn = attachmentsEnabled && attachmentsConfig.file !== false;
|
|
4400
|
+
const showImageBtn = attachmentsEnabled && attachmentsConfig.image !== false;
|
|
4401
|
+
const types = showFileBtn && Array.isArray(attachmentsConfig.types) ? attachmentsConfig.types : [];
|
|
4402
|
+
const hasTypePicker = types.length > 0;
|
|
4403
|
+
const customActions = features.custom;
|
|
4404
|
+
const actionCtx = useCustomActionContext(submit ?? (() => {
|
|
4405
|
+
}));
|
|
4406
|
+
const hasAnyAction = showFileBtn || showImageBtn || features.web || customActions.length > 0 || !!extras;
|
|
4407
|
+
const close = useCallback(() => setOpen(false), []);
|
|
4408
|
+
const openFilePicker = useCallback((accept) => {
|
|
4409
|
+
const input = fileInputRef.current;
|
|
4410
|
+
if (!input) return;
|
|
4411
|
+
input.accept = accept ?? attachmentsConfig.accept ?? "";
|
|
4412
|
+
input.click();
|
|
4413
|
+
}, [attachmentsConfig.accept]);
|
|
4414
|
+
useEffect(() => {
|
|
4415
|
+
if (!open) return;
|
|
4416
|
+
const onPointerDown = (event) => {
|
|
4417
|
+
if (!closeMenusOnOutsideClick) return;
|
|
4418
|
+
const target = event.target;
|
|
4419
|
+
if (!target) return;
|
|
4420
|
+
if (popoverRef.current?.contains(target)) return;
|
|
4421
|
+
if (triggerRef.current?.contains(target)) return;
|
|
4422
|
+
close();
|
|
4423
|
+
};
|
|
4424
|
+
const onKeyDown = (event) => {
|
|
4425
|
+
if (event.key === "Escape") {
|
|
4426
|
+
event.preventDefault();
|
|
4427
|
+
close();
|
|
4428
|
+
triggerRef.current?.focus();
|
|
4429
|
+
}
|
|
4430
|
+
};
|
|
4431
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
4432
|
+
document.addEventListener("keydown", onKeyDown);
|
|
4433
|
+
return () => {
|
|
4434
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
4435
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
4436
|
+
};
|
|
4437
|
+
}, [open, closeMenusOnOutsideClick, close]);
|
|
4438
|
+
if (!hasAnyAction) return null;
|
|
4439
|
+
const triggerBtn = slotProps(
|
|
4440
|
+
"toolbarButton",
|
|
4441
|
+
"composer-toolbar-btn",
|
|
4442
|
+
classNames,
|
|
4443
|
+
sx
|
|
4444
|
+
);
|
|
4445
|
+
return /* @__PURE__ */ jsxs("div", { className: "composer-quick-actions", children: [
|
|
4446
|
+
showFileBtn && /* @__PURE__ */ jsx(
|
|
4447
|
+
"input",
|
|
4448
|
+
{
|
|
4449
|
+
ref: fileInputRef,
|
|
4450
|
+
type: "file",
|
|
4451
|
+
multiple: true,
|
|
4452
|
+
accept: attachmentsConfig.accept,
|
|
4453
|
+
hidden: true,
|
|
4454
|
+
onChange: (e) => {
|
|
4455
|
+
const files = e.target.files;
|
|
4456
|
+
if (files) addFiles(Array.from(files));
|
|
4457
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
),
|
|
4461
|
+
showImageBtn && /* @__PURE__ */ jsx(
|
|
4462
|
+
"input",
|
|
4463
|
+
{
|
|
4464
|
+
ref: imageInputRef,
|
|
4465
|
+
type: "file",
|
|
4466
|
+
multiple: true,
|
|
4467
|
+
accept: "image/*",
|
|
4468
|
+
hidden: true,
|
|
4469
|
+
onChange: (e) => {
|
|
4470
|
+
const files = e.target.files;
|
|
4471
|
+
if (files) addFiles(Array.from(files));
|
|
4472
|
+
if (imageInputRef.current) imageInputRef.current.value = "";
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
),
|
|
4476
|
+
/* @__PURE__ */ jsx(
|
|
4477
|
+
"button",
|
|
4478
|
+
{
|
|
4479
|
+
ref: triggerRef,
|
|
4480
|
+
type: "button",
|
|
4481
|
+
"aria-label": "Quick actions",
|
|
4482
|
+
"aria-haspopup": "menu",
|
|
4483
|
+
"aria-expanded": open,
|
|
4484
|
+
"aria-controls": open ? menuId : void 0,
|
|
4485
|
+
"data-active": open ? "" : void 0,
|
|
4486
|
+
onClick: () => setOpen((o) => !o),
|
|
4487
|
+
...triggerBtn,
|
|
4488
|
+
children: /* @__PURE__ */ jsx(PlusIcon, {})
|
|
4489
|
+
}
|
|
4490
|
+
),
|
|
4491
|
+
open && /* @__PURE__ */ jsxs(
|
|
4492
|
+
"div",
|
|
4493
|
+
{
|
|
4494
|
+
ref: popoverRef,
|
|
4495
|
+
id: menuId,
|
|
4496
|
+
role: "menu",
|
|
4497
|
+
"aria-label": "Quick actions",
|
|
4498
|
+
"data-composer-popover": "open",
|
|
4499
|
+
className: "composer-popover-in composer-attach-menu composer-quick-menu",
|
|
4500
|
+
children: [
|
|
4501
|
+
showFileBtn && !hasTypePicker && /* @__PURE__ */ jsx(
|
|
4502
|
+
ActionItem,
|
|
4503
|
+
{
|
|
4504
|
+
icon: /* @__PURE__ */ jsx(AttachIcon, {}),
|
|
4505
|
+
label: "Attach file",
|
|
4506
|
+
onClick: () => {
|
|
4507
|
+
close();
|
|
4508
|
+
openFilePicker();
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
),
|
|
4512
|
+
hasTypePicker && types.map((type) => /* @__PURE__ */ jsx(
|
|
4513
|
+
ActionItem,
|
|
4514
|
+
{
|
|
4515
|
+
icon: type.icon ?? /* @__PURE__ */ jsx(AttachIcon, {}),
|
|
4516
|
+
label: type.label,
|
|
4517
|
+
description: type.description,
|
|
4518
|
+
onClick: () => {
|
|
4519
|
+
close();
|
|
4520
|
+
openFilePicker(type.accept);
|
|
4521
|
+
}
|
|
4522
|
+
},
|
|
4523
|
+
type.id
|
|
4524
|
+
)),
|
|
4525
|
+
showImageBtn && /* @__PURE__ */ jsx(
|
|
4526
|
+
ActionItem,
|
|
4527
|
+
{
|
|
4528
|
+
icon: /* @__PURE__ */ jsx(ImageIcon, {}),
|
|
4529
|
+
label: "Add image",
|
|
4530
|
+
onClick: () => {
|
|
4531
|
+
close();
|
|
4532
|
+
imageInputRef.current?.click();
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
),
|
|
4536
|
+
features.web && /* @__PURE__ */ jsx(
|
|
4537
|
+
ActionItem,
|
|
4538
|
+
{
|
|
4539
|
+
icon: /* @__PURE__ */ jsx(WebIcon, {}),
|
|
4540
|
+
label: "Search the web",
|
|
4541
|
+
active: webEnabled,
|
|
4542
|
+
onClick: () => {
|
|
4543
|
+
toggleWeb();
|
|
4544
|
+
close();
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
),
|
|
4548
|
+
customActions.map((action, i) => /* @__PURE__ */ jsx(
|
|
4549
|
+
ActionItem,
|
|
4550
|
+
{
|
|
4551
|
+
icon: action.icon,
|
|
4552
|
+
label: action.title,
|
|
4553
|
+
active: action.active,
|
|
4554
|
+
disabled: action.disabled,
|
|
4555
|
+
onClick: () => {
|
|
4556
|
+
action.onClick(actionCtx);
|
|
4557
|
+
close();
|
|
4558
|
+
}
|
|
4559
|
+
},
|
|
4560
|
+
action.id ?? i
|
|
4561
|
+
)),
|
|
4562
|
+
extras && /* @__PURE__ */ jsx("div", { className: "composer-quick-extras", children: extras })
|
|
4563
|
+
]
|
|
4564
|
+
}
|
|
4565
|
+
)
|
|
4566
|
+
] });
|
|
4567
|
+
}
|
|
4568
|
+
function ActionItem({
|
|
4569
|
+
icon,
|
|
4570
|
+
label,
|
|
4571
|
+
description,
|
|
4572
|
+
active,
|
|
4573
|
+
disabled,
|
|
4574
|
+
onClick
|
|
4575
|
+
}) {
|
|
4576
|
+
return /* @__PURE__ */ jsxs(
|
|
4577
|
+
"button",
|
|
4578
|
+
{
|
|
4579
|
+
role: "menuitem",
|
|
4580
|
+
type: "button",
|
|
4581
|
+
"aria-pressed": active,
|
|
4582
|
+
"data-active": active ? "" : void 0,
|
|
4583
|
+
disabled,
|
|
4584
|
+
onClick,
|
|
4585
|
+
className: cn("composer-attach-item"),
|
|
4586
|
+
children: [
|
|
4587
|
+
/* @__PURE__ */ jsx("span", { className: "composer-attach-item-icon", children: icon }),
|
|
4588
|
+
/* @__PURE__ */ jsx("span", { className: "composer-attach-item-label", children: label }),
|
|
4589
|
+
description ? /* @__PURE__ */ jsx("span", { className: "composer-attach-item-desc", children: description }) : null
|
|
4590
|
+
]
|
|
4591
|
+
}
|
|
4592
|
+
);
|
|
4593
|
+
}
|
|
3868
4594
|
var TOOLBAR_BTN_BASE = "composer-toolbar-btn";
|
|
3869
|
-
function Toolbar({ extras }) {
|
|
4595
|
+
function Toolbar({ extras, variant = "full", submit }) {
|
|
4596
|
+
if (variant === "compact") {
|
|
4597
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4598
|
+
/* @__PURE__ */ jsx(QuickActionsMenu, { extras, submit }),
|
|
4599
|
+
/* @__PURE__ */ jsx(MermaidQuickAction, {})
|
|
4600
|
+
] });
|
|
4601
|
+
}
|
|
4602
|
+
return /* @__PURE__ */ jsx(FullToolbar, { extras, submit });
|
|
4603
|
+
}
|
|
4604
|
+
function FullToolbar({ extras, submit }) {
|
|
3870
4605
|
const {
|
|
3871
4606
|
features,
|
|
3872
4607
|
attachmentsConfig,
|
|
@@ -3965,6 +4700,8 @@ function Toolbar({ extras }) {
|
|
|
3965
4700
|
]
|
|
3966
4701
|
}
|
|
3967
4702
|
),
|
|
4703
|
+
/* @__PURE__ */ jsx(CustomActionButtons, { submit: submit ?? (() => {
|
|
4704
|
+
}) }),
|
|
3968
4705
|
extras
|
|
3969
4706
|
] });
|
|
3970
4707
|
}
|
|
@@ -4058,7 +4795,6 @@ function HintBar({ hint }) {
|
|
|
4058
4795
|
const {
|
|
4059
4796
|
multiline,
|
|
4060
4797
|
submitOnEnter,
|
|
4061
|
-
smartNewline,
|
|
4062
4798
|
focusShortcut,
|
|
4063
4799
|
classNames,
|
|
4064
4800
|
sx
|
|
@@ -4072,16 +4808,6 @@ function HintBar({ hint }) {
|
|
|
4072
4808
|
" to send."
|
|
4073
4809
|
] });
|
|
4074
4810
|
}
|
|
4075
|
-
if (smartNewline && submitOnEnter) {
|
|
4076
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4077
|
-
"Press ",
|
|
4078
|
-
/* @__PURE__ */ jsx(Key, { children: "Enter" }),
|
|
4079
|
-
" to send a single line,",
|
|
4080
|
-
" ",
|
|
4081
|
-
/* @__PURE__ */ jsx(Key, { children: "\u2318/Ctrl + Enter" }),
|
|
4082
|
-
" to send once you've started a new line."
|
|
4083
|
-
] });
|
|
4084
|
-
}
|
|
4085
4811
|
if (!submitOnEnter) {
|
|
4086
4812
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4087
4813
|
"Press ",
|
|
@@ -4098,7 +4824,7 @@ function HintBar({ hint }) {
|
|
|
4098
4824
|
/* @__PURE__ */ jsx(Key, { children: "Shift + Enter" }),
|
|
4099
4825
|
" for newline."
|
|
4100
4826
|
] });
|
|
4101
|
-
}, [multiline, submitOnEnter
|
|
4827
|
+
}, [multiline, submitOnEnter]);
|
|
4102
4828
|
const focusHint = useMemo(() => {
|
|
4103
4829
|
if (!focusShortcut) return null;
|
|
4104
4830
|
const label = formatShortcut(focusShortcut);
|
|
@@ -4296,6 +5022,7 @@ var Composer = forwardRef(function Composer2(props, ref) {
|
|
|
4296
5022
|
toolbarExtras,
|
|
4297
5023
|
closeMenusOnOutsideClick = true,
|
|
4298
5024
|
mode = "markdown",
|
|
5025
|
+
variant = "compact",
|
|
4299
5026
|
multiline = true,
|
|
4300
5027
|
submitOnEnter = true,
|
|
4301
5028
|
smartNewline = true,
|
|
@@ -4324,6 +5051,7 @@ var Composer = forwardRef(function Composer2(props, ref) {
|
|
|
4324
5051
|
closeMenusOnOutsideClick,
|
|
4325
5052
|
attachmentOptions,
|
|
4326
5053
|
mode,
|
|
5054
|
+
variant,
|
|
4327
5055
|
multiline,
|
|
4328
5056
|
submitOnEnter,
|
|
4329
5057
|
smartNewline,
|
|
@@ -4358,6 +5086,7 @@ var Composer = forwardRef(function Composer2(props, ref) {
|
|
|
4358
5086
|
isStreaming: !!isStreaming,
|
|
4359
5087
|
toolbarExtras,
|
|
4360
5088
|
mode,
|
|
5089
|
+
variant,
|
|
4361
5090
|
multiline
|
|
4362
5091
|
}
|
|
4363
5092
|
),
|
|
@@ -4378,6 +5107,7 @@ var RICH_NODES = [
|
|
|
4378
5107
|
MarkdownTokenNode,
|
|
4379
5108
|
BlockParagraphNode,
|
|
4380
5109
|
LinkTextNode,
|
|
5110
|
+
CodeTokenNode,
|
|
4381
5111
|
BLOCK_PARAGRAPH_REPLACEMENT
|
|
4382
5112
|
];
|
|
4383
5113
|
var PLAIN_NODES = [MentionNode];
|
|
@@ -4393,6 +5123,7 @@ function ComposerCard({
|
|
|
4393
5123
|
isStreaming,
|
|
4394
5124
|
toolbarExtras,
|
|
4395
5125
|
mode,
|
|
5126
|
+
variant,
|
|
4396
5127
|
multiline
|
|
4397
5128
|
}) {
|
|
4398
5129
|
const { webEnabled, isDraggingFiles, classNames, sx } = useComposerContext();
|
|
@@ -4413,7 +5144,8 @@ function ComposerCard({
|
|
|
4413
5144
|
"div",
|
|
4414
5145
|
{
|
|
4415
5146
|
"data-composer-root": "",
|
|
4416
|
-
"data-composer-
|
|
5147
|
+
"data-composer-variant": variant,
|
|
5148
|
+
"data-composer-inline": variant === "full" && !multiline ? "" : void 0,
|
|
4417
5149
|
"data-composer-web": webEnabled ? "" : void 0,
|
|
4418
5150
|
"data-composer-dragging": isDraggingFiles ? "" : void 0,
|
|
4419
5151
|
...card,
|
|
@@ -4443,6 +5175,7 @@ function ComposerCard({
|
|
|
4443
5175
|
{
|
|
4444
5176
|
placeholder,
|
|
4445
5177
|
mode,
|
|
5178
|
+
variant,
|
|
4446
5179
|
multiline,
|
|
4447
5180
|
handleRef,
|
|
4448
5181
|
onSend,
|
|
@@ -4462,6 +5195,7 @@ function ComposerCard({
|
|
|
4462
5195
|
function ComposerInner({
|
|
4463
5196
|
placeholder,
|
|
4464
5197
|
mode,
|
|
5198
|
+
variant,
|
|
4465
5199
|
multiline,
|
|
4466
5200
|
handleRef,
|
|
4467
5201
|
onSend,
|
|
@@ -4489,6 +5223,9 @@ function ComposerInner({
|
|
|
4489
5223
|
const [hasText, setHasText] = useState(
|
|
4490
5224
|
!!initialValue && initialValue.trim().length > 0
|
|
4491
5225
|
);
|
|
5226
|
+
const [isMultiLine, setIsMultiLine] = useState(
|
|
5227
|
+
!!initialValue && initialValue.includes("\n")
|
|
5228
|
+
);
|
|
4492
5229
|
const onSendRef = useRef(onSend);
|
|
4493
5230
|
onSendRef.current = onSend;
|
|
4494
5231
|
const refocusOnSubmitRef = useRef(refocusOnSubmit);
|
|
@@ -4497,9 +5234,10 @@ function ComposerInner({
|
|
|
4497
5234
|
if (isStreaming) return;
|
|
4498
5235
|
if (uploadsBlocking) return;
|
|
4499
5236
|
let payload = null;
|
|
5237
|
+
const linkedMention = typeof features.mentions === "object" && !!features.mentions.linkedMention;
|
|
4500
5238
|
editor.getEditorState().read(() => {
|
|
4501
5239
|
const { text, mentions } = collectPlainAndMentions(editor);
|
|
4502
|
-
const markdown = toMarkdown(editor);
|
|
5240
|
+
const markdown = toMarkdown(editor, { linkedMention });
|
|
4503
5241
|
const trimmed = text.trim();
|
|
4504
5242
|
if (!trimmed) {
|
|
4505
5243
|
if (attachments.length === 0) return;
|
|
@@ -4566,8 +5304,10 @@ function ComposerInner({
|
|
|
4566
5304
|
useEffect(() => {
|
|
4567
5305
|
return editor.registerUpdateListener(() => {
|
|
4568
5306
|
editor.getEditorState().read(() => {
|
|
4569
|
-
const
|
|
4570
|
-
|
|
5307
|
+
const root = $getRoot();
|
|
5308
|
+
const text = root.getTextContent();
|
|
5309
|
+
setHasText(text.trim().length > 0);
|
|
5310
|
+
setIsMultiLine(root.getChildrenSize() > 1 || text.includes("\n"));
|
|
4571
5311
|
});
|
|
4572
5312
|
});
|
|
4573
5313
|
}, [editor]);
|
|
@@ -4583,8 +5323,10 @@ function ComposerInner({
|
|
|
4583
5323
|
}
|
|
4584
5324
|
});
|
|
4585
5325
|
}, [editor, registerRunPrompt, submit]);
|
|
4586
|
-
const
|
|
4587
|
-
const
|
|
5326
|
+
const isCompact = variant === "compact";
|
|
5327
|
+
const mermaidActive = multiline && mode === "markdown" && !!features.mermaid;
|
|
5328
|
+
const toolbarSlot = /* @__PURE__ */ jsx(Toolbar, { extras: toolbarExtras, variant, submit });
|
|
5329
|
+
const sendButton = /* @__PURE__ */ jsx(
|
|
4588
5330
|
SendButton,
|
|
4589
5331
|
{
|
|
4590
5332
|
canSend: (
|
|
@@ -4597,38 +5339,37 @@ function ComposerInner({
|
|
|
4597
5339
|
onStop
|
|
4598
5340
|
}
|
|
4599
5341
|
);
|
|
4600
|
-
|
|
5342
|
+
const sendButtonSlot = isCompact && features.voice ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5343
|
+
/* @__PURE__ */ jsx(VoiceButton, {}),
|
|
5344
|
+
sendButton
|
|
5345
|
+
] }) : sendButton;
|
|
5346
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4601
5347
|
/* @__PURE__ */ jsx(
|
|
4602
5348
|
EditorShell,
|
|
4603
5349
|
{
|
|
4604
5350
|
placeholder,
|
|
4605
5351
|
mode,
|
|
5352
|
+
variant,
|
|
4606
5353
|
multiline,
|
|
5354
|
+
expanded: isCompact && isMultiLine,
|
|
4607
5355
|
header: /* @__PURE__ */ jsx(AttachmentTray, {}),
|
|
4608
5356
|
toolbar: toolbarSlot,
|
|
4609
5357
|
sendButton: sendButtonSlot,
|
|
4610
|
-
footer:
|
|
5358
|
+
footer: mermaidActive && !isCompact ? /* @__PURE__ */ jsx(MermaidPreview, {}) : null
|
|
4611
5359
|
}
|
|
4612
5360
|
),
|
|
4613
5361
|
/* @__PURE__ */ jsx(KeyboardPlugin, { onSubmit: submit }),
|
|
4614
5362
|
/* @__PURE__ */ jsx(AutoFocusPlugin, { enabled: !!autoFocus }),
|
|
4615
5363
|
/* @__PURE__ */ jsx(PasteDropPlugin, {}),
|
|
4616
5364
|
markdownEnabled && /* @__PURE__ */ jsx(MarkdownPlugin, {}),
|
|
4617
|
-
features.slashCommands &&
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
onSubmit: submit
|
|
4622
|
-
}
|
|
4623
|
-
),
|
|
5365
|
+
features.slashCommands && // One typeahead per config — a single config or an array of them, so
|
|
5366
|
+
// consumers can register several trigger symbols (each with its own
|
|
5367
|
+
// action menu) at once. Keyed by trigger; give each a distinct symbol.
|
|
5368
|
+
(Array.isArray(features.slashCommands) ? features.slashCommands : [features.slashCommands]).map((cfg, i) => /* @__PURE__ */ jsx(SlashCommandPlugin, { config: cfg, onSubmit: submit }, cfg.trigger ?? `slash-${i}`)),
|
|
4624
5369
|
features.mentions && /* @__PURE__ */ jsx(MentionPlugin, { config: features.mentions }),
|
|
4625
5370
|
features.ghostedAutoComplete && /* @__PURE__ */ jsx(GhostedAutoCompletePlugin, { config: features.ghostedAutoComplete })
|
|
4626
5371
|
] });
|
|
4627
|
-
}
|
|
4628
|
-
function MermaidSlot() {
|
|
4629
|
-
const { features, mode } = useComposerContext();
|
|
4630
|
-
if (mode !== "markdown" || !features.mermaid) return null;
|
|
4631
|
-
return /* @__PURE__ */ jsx(MermaidPlugin, {});
|
|
5372
|
+
return mermaidActive ? /* @__PURE__ */ jsx(MermaidProvider, { children: content }) : content;
|
|
4632
5373
|
}
|
|
4633
5374
|
function SuggestionRow({ items, onSelect, className }) {
|
|
4634
5375
|
const { icons } = useComposerContext();
|