@arbidocs/blocks 0.4.84 → 0.4.86
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/MailBodyEditor-5PIQLYVY.js +217 -0
- package/dist/MailBodyEditor-5PIQLYVY.js.map +1 -0
- package/dist/MailBodyEditor-D7MGJMLH.cjs +223 -0
- package/dist/MailBodyEditor-D7MGJMLH.cjs.map +1 -0
- package/dist/agents/index.cjs +282 -281
- package/dist/agents/index.js +7 -6
- package/dist/agents/workflows/StepBarFrame.d.ts +3 -1
- package/dist/agents/workflows/WorkflowRunner.d.ts +10 -1
- package/dist/agents/workflows/run.d.ts +24 -3
- package/dist/agents/workflows/stepWindow.d.ts +4 -2
- package/dist/agents/workflows/types.d.ts +5 -0
- package/dist/agents/workflows/useWorkflowView.d.ts +16 -1
- package/dist/chat/index.cjs +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/chunk-3R6XBYL7.cjs +576 -0
- package/dist/chunk-3R6XBYL7.cjs.map +1 -0
- package/dist/{chunk-CKB64Z4R.js → chunk-4XJZ6AAY.js} +6 -245
- package/dist/chunk-4XJZ6AAY.js.map +1 -0
- package/dist/{chunk-B3WCKBJ7.cjs → chunk-5YXG342J.cjs} +6 -18
- package/dist/chunk-5YXG342J.cjs.map +1 -0
- package/dist/{chunk-SB5ZKOYN.js → chunk-7C35WXYB.js} +4 -63
- package/dist/chunk-7C35WXYB.js.map +1 -0
- package/dist/chunk-7RJTEWYM.js +362 -0
- package/dist/chunk-7RJTEWYM.js.map +1 -0
- package/dist/chunk-AFSOUS5X.cjs +253 -0
- package/dist/chunk-AFSOUS5X.cjs.map +1 -0
- package/dist/{chunk-F4RUCUXF.cjs → chunk-C2HRZSAT.cjs} +2 -63
- package/dist/chunk-C2HRZSAT.cjs.map +1 -0
- package/dist/{chunk-XA5S4776.cjs → chunk-IHYVK6F7.cjs} +52 -51
- package/dist/chunk-IHYVK6F7.cjs.map +1 -0
- package/dist/{chunk-CONIA2ZA.js → chunk-KHY4PYU7.js} +246 -146
- package/dist/chunk-KHY4PYU7.js.map +1 -0
- package/dist/chunk-LGX6UFYG.js +557 -0
- package/dist/chunk-LGX6UFYG.js.map +1 -0
- package/dist/chunk-O4YPVYPO.cjs +373 -0
- package/dist/chunk-O4YPVYPO.cjs.map +1 -0
- package/dist/chunk-R26OHONI.js +250 -0
- package/dist/chunk-R26OHONI.js.map +1 -0
- package/dist/{chunk-RYYYHPFU.cjs → chunk-RZUMQM7W.cjs} +246 -146
- package/dist/chunk-RZUMQM7W.cjs.map +1 -0
- package/dist/{chunk-RX35SMPR.js → chunk-S2NFD4QV.js} +8 -7
- package/dist/chunk-S2NFD4QV.js.map +1 -0
- package/dist/{chunk-YJQVLVBJ.cjs → chunk-S5HZBXZA.cjs} +2 -243
- package/dist/chunk-S5HZBXZA.cjs.map +1 -0
- package/dist/{chunk-GJV2G4FC.js → chunk-W7NZRZ54.js} +6 -18
- package/dist/chunk-W7NZRZ54.js.map +1 -0
- package/dist/{chunk-ZQYE7J3J.cjs → chunk-WRSBM6QN.cjs} +332 -94
- package/dist/chunk-WRSBM6QN.cjs.map +1 -0
- package/dist/{chunk-RSKSXEPW.js → chunk-X23U6QEJ.js} +324 -88
- package/dist/chunk-X23U6QEJ.js.map +1 -0
- package/dist/collaboration/index.cjs +100 -49
- package/dist/collaboration/index.js +4 -1
- package/dist/collaboration/mail/MailBodyEditor.d.ts +7 -0
- package/dist/collaboration/mail/MailDeliveryList.d.ts +8 -0
- package/dist/collaboration/mail/MailDocumentPicker.d.ts +15 -0
- package/dist/collaboration/mail/MailGrid.d.ts +17 -0
- package/dist/collaboration/mail/MailMessageView.d.ts +27 -0
- package/dist/collaboration/mail/PlainMailBodyEditor.d.ts +12 -0
- package/dist/collaboration/mail/index.d.ts +6 -0
- package/dist/collaboration/mail/mailCompose.d.ts +24 -0
- package/dist/connect/index.cjs +1673 -96
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.ts +2 -1
- package/dist/connect/index.js +1634 -63
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedSettings.d.ts +1 -4
- package/dist/connection/ConnectedTagTable.d.ts +32 -0
- package/dist/connection/mail/ConnectedMailAccounts.d.ts +21 -0
- package/dist/connection/mail/ConnectedMailComposer.d.ts +40 -0
- package/dist/connection/mail/ConnectedMailSetup.d.ts +16 -0
- package/dist/connection/mail/ConnectedMailbox.d.ts +65 -0
- package/dist/connection/mail/MailComposerForm.d.ts +25 -0
- package/dist/connection/mail/attachments.d.ts +13 -0
- package/dist/connection/mail/index.d.ts +6 -0
- package/dist/connection/mail/mailbox.d.ts +6 -0
- package/dist/connection/mail/types.d.ts +92 -0
- package/dist/connection/useConnectedWorkNotifications.d.ts +6 -0
- package/dist/connection/useWorkflowThread.d.ts +7 -2
- package/dist/facts/index.cjs +3 -3
- package/dist/facts/index.js +3 -3
- package/dist/files/index.cjs +48 -368
- package/dist/files/index.cjs.map +1 -1
- package/dist/files/index.js +11 -361
- package/dist/files/index.js.map +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +496 -437
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -20
- package/dist/index.js.map +1 -1
- package/dist/settings/PasswordChangeDialog.d.ts +9 -12
- package/dist/settings/index.cjs +44 -43
- package/dist/settings/index.cjs.map +1 -1
- package/dist/settings/index.js +3 -2
- package/dist/settings/index.js.map +1 -1
- package/dist/shell/index.cjs +2 -2
- package/dist/shell/index.js +2 -2
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.js +1 -1
- package/dist/tags/TagColumnsEditor.d.ts +34 -0
- package/dist/tags/TagDetail.d.ts +13 -11
- package/dist/tags/TagTable.d.ts +99 -0
- package/dist/tags/TagsNav.d.ts +2 -2
- package/dist/tags/index.d.ts +7 -5
- package/dist/tags/{tagMatrixDocx.d.ts → tagTableDocx.d.ts} +12 -12
- package/dist/tags/tagTableModel.d.ts +47 -0
- package/dist/workflow-canvas/index.cjs +50 -49
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +7 -6
- package/dist/workflow-canvas/index.js.map +1 -1
- package/package.json +29 -4
- package/dist/chunk-B3WCKBJ7.cjs.map +0 -1
- package/dist/chunk-CKB64Z4R.js.map +0 -1
- package/dist/chunk-CONIA2ZA.js.map +0 -1
- package/dist/chunk-F4RUCUXF.cjs.map +0 -1
- package/dist/chunk-GJV2G4FC.js.map +0 -1
- package/dist/chunk-RSKSXEPW.js.map +0 -1
- package/dist/chunk-RX35SMPR.js.map +0 -1
- package/dist/chunk-RYYYHPFU.cjs.map +0 -1
- package/dist/chunk-SB5ZKOYN.js.map +0 -1
- package/dist/chunk-XA5S4776.cjs.map +0 -1
- package/dist/chunk-YJQVLVBJ.cjs.map +0 -1
- package/dist/chunk-ZQYE7J3J.cjs.map +0 -1
- package/dist/connection/ConnectedTagMatrix.d.ts +0 -23
- package/dist/tags/TagMatrix.d.ts +0 -87
- package/dist/tags/tagMatrixModel.d.ts +0 -43
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import './chunk-VUNV25KB.js';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
|
5
|
+
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
|
6
|
+
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
|
7
|
+
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
|
8
|
+
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
9
|
+
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
|
|
10
|
+
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
|
|
11
|
+
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
|
|
12
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
13
|
+
import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
|
|
14
|
+
import { ListNode, ListItemNode, $isListNode, REMOVE_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND } from '@lexical/list';
|
|
15
|
+
import { LinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
|
|
16
|
+
import { $getRoot, $createParagraphNode, $createTextNode, $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND, UNDO_COMMAND, REDO_COMMAND } from 'lexical';
|
|
17
|
+
import { Bold, Italic, Underline, List, ListOrdered, Link, Undo2, Redo2 } from 'lucide-react';
|
|
18
|
+
import { Tooltip, TooltipTrigger, Button, TooltipContent } from '@arbidocs/react/ui';
|
|
19
|
+
import DOMPurify from 'dompurify';
|
|
20
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
21
|
+
|
|
22
|
+
function Toolbar({ disabled }) {
|
|
23
|
+
const [editor] = useLexicalComposerContext();
|
|
24
|
+
const [addingLink, setAddingLink] = useState(false);
|
|
25
|
+
const [url, setUrl] = useState("");
|
|
26
|
+
const [formats, setFormats] = useState({});
|
|
27
|
+
useEffect(
|
|
28
|
+
() => editor.registerUpdateListener(
|
|
29
|
+
({ editorState }) => editorState.read(() => {
|
|
30
|
+
const selection = $getSelection();
|
|
31
|
+
if (!$isRangeSelection(selection)) return;
|
|
32
|
+
let parent = selection.anchor.getNode().getParent();
|
|
33
|
+
while (parent && !$isListNode(parent)) parent = parent.getParent();
|
|
34
|
+
const list = $isListNode(parent) ? parent.getListType() : null;
|
|
35
|
+
setFormats({
|
|
36
|
+
Bold: selection.hasFormat("bold"),
|
|
37
|
+
Italic: selection.hasFormat("italic"),
|
|
38
|
+
Underline: selection.hasFormat("underline"),
|
|
39
|
+
"Bulleted list": list === "bullet",
|
|
40
|
+
"Numbered list": list === "number"
|
|
41
|
+
});
|
|
42
|
+
})
|
|
43
|
+
),
|
|
44
|
+
[editor]
|
|
45
|
+
);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
editor.setEditable(!disabled);
|
|
48
|
+
}, [editor, disabled]);
|
|
49
|
+
const buttons = [
|
|
50
|
+
{ label: "Bold", icon: Bold, run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold") },
|
|
51
|
+
{
|
|
52
|
+
label: "Italic",
|
|
53
|
+
icon: Italic,
|
|
54
|
+
run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic")
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: "Underline",
|
|
58
|
+
icon: Underline,
|
|
59
|
+
run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, "underline")
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
label: "Bulleted list",
|
|
63
|
+
icon: List,
|
|
64
|
+
run: () => editor.dispatchCommand(
|
|
65
|
+
formats["Bulleted list"] ? REMOVE_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND,
|
|
66
|
+
void 0
|
|
67
|
+
)
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: "Numbered list",
|
|
71
|
+
icon: ListOrdered,
|
|
72
|
+
run: () => editor.dispatchCommand(
|
|
73
|
+
formats["Numbered list"] ? REMOVE_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,
|
|
74
|
+
void 0
|
|
75
|
+
)
|
|
76
|
+
},
|
|
77
|
+
{ label: "Insert link", icon: Link, run: () => setAddingLink(!addingLink) },
|
|
78
|
+
{ label: "Undo", icon: Undo2, run: () => editor.dispatchCommand(UNDO_COMMAND, void 0) },
|
|
79
|
+
{ label: "Redo", icon: Redo2, run: () => editor.dispatchCommand(REDO_COMMAND, void 0) }
|
|
80
|
+
];
|
|
81
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
82
|
+
/* @__PURE__ */ jsx(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
role: "toolbar",
|
|
86
|
+
"aria-label": "Message formatting",
|
|
87
|
+
className: "flex flex-wrap gap-0.5 border-b border-border/60 py-1",
|
|
88
|
+
children: buttons.map(({ label, icon: Icon, run }) => /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
90
|
+
Button,
|
|
91
|
+
{
|
|
92
|
+
type: "button",
|
|
93
|
+
variant: "ghost",
|
|
94
|
+
size: "sm",
|
|
95
|
+
"aria-label": label,
|
|
96
|
+
"aria-pressed": formats[label],
|
|
97
|
+
disabled,
|
|
98
|
+
className: "size-7 p-1 text-primary aria-pressed:bg-primary/10",
|
|
99
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
100
|
+
onClick: run,
|
|
101
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-3.5" })
|
|
102
|
+
}
|
|
103
|
+
) }),
|
|
104
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: label })
|
|
105
|
+
] }, label))
|
|
106
|
+
}
|
|
107
|
+
),
|
|
108
|
+
addingLink && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-2", children: [
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
"input",
|
|
111
|
+
{
|
|
112
|
+
"aria-label": "Link URL",
|
|
113
|
+
type: "url",
|
|
114
|
+
placeholder: "https://example.com",
|
|
115
|
+
value: url,
|
|
116
|
+
onChange: (event) => setUrl(event.target.value),
|
|
117
|
+
className: "min-w-0 flex-1 rounded border bg-background px-2 py-1 text-sm"
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
Button,
|
|
122
|
+
{
|
|
123
|
+
type: "button",
|
|
124
|
+
size: "sm",
|
|
125
|
+
disabled: disabled || !/^https?:\/\/\S+$/i.test(url),
|
|
126
|
+
onClick: () => {
|
|
127
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);
|
|
128
|
+
editor.update(() => {
|
|
129
|
+
const selection = $getSelection();
|
|
130
|
+
if ($isRangeSelection(selection))
|
|
131
|
+
selection.anchor.set(
|
|
132
|
+
selection.focus.key,
|
|
133
|
+
selection.focus.offset,
|
|
134
|
+
selection.focus.type
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
editor.focus();
|
|
138
|
+
setAddingLink(false);
|
|
139
|
+
setUrl("");
|
|
140
|
+
},
|
|
141
|
+
children: "Insert"
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
/* @__PURE__ */ jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: () => setAddingLink(false), children: "Cancel" })
|
|
145
|
+
] })
|
|
146
|
+
] });
|
|
147
|
+
}
|
|
148
|
+
function MailBodyEditor({
|
|
149
|
+
text,
|
|
150
|
+
html,
|
|
151
|
+
disabled,
|
|
152
|
+
onChange
|
|
153
|
+
}) {
|
|
154
|
+
const [config] = useState(() => ({
|
|
155
|
+
namespace: "mail-body",
|
|
156
|
+
nodes: [ListNode, ListItemNode, LinkNode],
|
|
157
|
+
theme: {
|
|
158
|
+
text: { bold: "font-bold", italic: "italic", underline: "underline" },
|
|
159
|
+
list: { ul: "list-disc pl-6", ol: "list-decimal pl-6" },
|
|
160
|
+
link: "text-primary underline",
|
|
161
|
+
paragraph: "mb-2"
|
|
162
|
+
},
|
|
163
|
+
onError: (error) => {
|
|
164
|
+
throw error;
|
|
165
|
+
},
|
|
166
|
+
editorState: (editor) => {
|
|
167
|
+
const root = $getRoot();
|
|
168
|
+
if (html) {
|
|
169
|
+
const dom = new DOMParser().parseFromString(DOMPurify.sanitize(html), "text/html");
|
|
170
|
+
const nodes = $generateNodesFromDOM(editor, dom);
|
|
171
|
+
root.select();
|
|
172
|
+
root.append(...nodes);
|
|
173
|
+
} else {
|
|
174
|
+
for (const line of text.split("\n"))
|
|
175
|
+
root.append($createParagraphNode().append($createTextNode(line)));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
return /* @__PURE__ */ jsx(LexicalComposer, { initialConfig: config, children: /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
|
|
180
|
+
/* @__PURE__ */ jsx(Toolbar, { disabled }),
|
|
181
|
+
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
|
|
182
|
+
RichTextPlugin,
|
|
183
|
+
{
|
|
184
|
+
contentEditable: /* @__PURE__ */ jsx(
|
|
185
|
+
ContentEditable,
|
|
186
|
+
{
|
|
187
|
+
"aria-label": "Message",
|
|
188
|
+
className: "min-h-64 w-full py-3 text-sm leading-relaxed outline-none"
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
placeholder: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute left-0 top-3 text-sm text-muted-foreground", children: "Write your message\u2026" }),
|
|
192
|
+
ErrorBoundary: LexicalErrorBoundary
|
|
193
|
+
}
|
|
194
|
+
) }),
|
|
195
|
+
/* @__PURE__ */ jsx(HistoryPlugin, {}),
|
|
196
|
+
" ",
|
|
197
|
+
/* @__PURE__ */ jsx(ListPlugin, {}),
|
|
198
|
+
" ",
|
|
199
|
+
/* @__PURE__ */ jsx(LinkPlugin, { validateUrl: (url) => /^https?:\/\//i.test(url) }),
|
|
200
|
+
/* @__PURE__ */ jsx(
|
|
201
|
+
OnChangePlugin,
|
|
202
|
+
{
|
|
203
|
+
ignoreSelectionChange: true,
|
|
204
|
+
onChange: (state, editor) => state.read(
|
|
205
|
+
() => onChange(
|
|
206
|
+
$getRoot().getTextContent(),
|
|
207
|
+
DOMPurify.sanitize($generateHtmlFromNodes(editor))
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] }) });
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export { MailBodyEditor as default };
|
|
216
|
+
//# sourceMappingURL=MailBodyEditor-5PIQLYVY.js.map
|
|
217
|
+
//# sourceMappingURL=MailBodyEditor-5PIQLYVY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/collaboration/mail/MailBodyEditor.tsx"],"names":[],"mappings":"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","file":"MailBodyEditor-5PIQLYVY.js","sourcesContent":["import { useEffect, useState } from 'react'\nimport { LexicalComposer } from '@lexical/react/LexicalComposer'\nimport { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable'\nimport { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'\nimport { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'\nimport { ListPlugin } from '@lexical/react/LexicalListPlugin'\nimport { LinkPlugin } from '@lexical/react/LexicalLinkPlugin'\nimport { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'\nimport {\n ListNode,\n ListItemNode,\n INSERT_UNORDERED_LIST_COMMAND,\n INSERT_ORDERED_LIST_COMMAND,\n REMOVE_LIST_COMMAND,\n $isListNode,\n} from '@lexical/list'\nimport { LinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'\nimport {\n $getRoot,\n $getSelection,\n $isRangeSelection,\n $createParagraphNode,\n $createTextNode,\n FORMAT_TEXT_COMMAND,\n UNDO_COMMAND,\n REDO_COMMAND,\n} from 'lexical'\nimport { Bold, Italic, Underline, List, ListOrdered, Link, Undo2, Redo2 } from 'lucide-react'\nimport { Button, Tooltip, TooltipTrigger, TooltipContent } from '@arbidocs/react/ui'\nimport DOMPurify from 'dompurify'\n\nfunction Toolbar({ disabled }: { disabled: boolean }) {\n const [editor] = useLexicalComposerContext()\n const [addingLink, setAddingLink] = useState(false)\n const [url, setUrl] = useState('')\n const [formats, setFormats] = useState<Record<string, boolean>>({})\n useEffect(\n () =>\n editor.registerUpdateListener(({ editorState }) =>\n editorState.read(() => {\n const selection = $getSelection()\n if (!$isRangeSelection(selection)) return\n let parent = selection.anchor.getNode().getParent()\n while (parent && !$isListNode(parent)) parent = parent.getParent()\n const list = $isListNode(parent) ? parent.getListType() : null\n setFormats({\n Bold: selection.hasFormat('bold'),\n Italic: selection.hasFormat('italic'),\n Underline: selection.hasFormat('underline'),\n 'Bulleted list': list === 'bullet',\n 'Numbered list': list === 'number',\n })\n })\n ),\n [editor]\n )\n useEffect(() => {\n editor.setEditable(!disabled)\n }, [editor, disabled])\n const buttons = [\n { label: 'Bold', icon: Bold, run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold') },\n {\n label: 'Italic',\n icon: Italic,\n run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic'),\n },\n {\n label: 'Underline',\n icon: Underline,\n run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline'),\n },\n {\n label: 'Bulleted list',\n icon: List,\n run: () =>\n editor.dispatchCommand(\n formats['Bulleted list'] ? REMOVE_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND,\n undefined\n ),\n },\n {\n label: 'Numbered list',\n icon: ListOrdered,\n run: () =>\n editor.dispatchCommand(\n formats['Numbered list'] ? REMOVE_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,\n undefined\n ),\n },\n { label: 'Insert link', icon: Link, run: () => setAddingLink(!addingLink) },\n { label: 'Undo', icon: Undo2, run: () => editor.dispatchCommand(UNDO_COMMAND, undefined) },\n { label: 'Redo', icon: Redo2, run: () => editor.dispatchCommand(REDO_COMMAND, undefined) },\n ]\n return (\n <>\n <div\n role=\"toolbar\"\n aria-label=\"Message formatting\"\n className=\"flex flex-wrap gap-0.5 border-b border-border/60 py-1\"\n >\n {buttons.map(({ label, icon: Icon, run }) => (\n <Tooltip key={label}>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={label}\n aria-pressed={formats[label]}\n disabled={disabled}\n className=\"size-7 p-1 text-primary aria-pressed:bg-primary/10\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={run}\n >\n <Icon className=\"size-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n ))}\n </div>\n {addingLink && (\n <div className=\"flex items-center gap-2 py-2\">\n <input\n aria-label=\"Link URL\"\n type=\"url\"\n placeholder=\"https://example.com\"\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n className=\"min-w-0 flex-1 rounded border bg-background px-2 py-1 text-sm\"\n />\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={disabled || !/^https?:\\/\\/\\S+$/i.test(url)}\n onClick={() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, url)\n editor.update(() => {\n const selection = $getSelection()\n if ($isRangeSelection(selection))\n selection.anchor.set(\n selection.focus.key,\n selection.focus.offset,\n selection.focus.type\n )\n })\n editor.focus()\n setAddingLink(false)\n setUrl('')\n }}\n >\n Insert\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setAddingLink(false)}>\n Cancel\n </Button>\n </div>\n )}\n </>\n )\n}\n\n/** Small mail editor using the same Lexical engine as the document editor. */\nexport default function MailBodyEditor({\n text,\n html,\n disabled,\n onChange,\n}: {\n text: string\n html?: string\n disabled: boolean\n onChange: (text: string, html: string) => void\n}) {\n const [config] = useState(() => ({\n namespace: 'mail-body',\n nodes: [ListNode, ListItemNode, LinkNode],\n theme: {\n text: { bold: 'font-bold', italic: 'italic', underline: 'underline' },\n list: { ul: 'list-disc pl-6', ol: 'list-decimal pl-6' },\n link: 'text-primary underline',\n paragraph: 'mb-2',\n },\n onError: (error: Error) => {\n throw error\n },\n editorState: (editor: Parameters<typeof $generateNodesFromDOM>[0]) => {\n const root = $getRoot()\n if (html) {\n const dom = new DOMParser().parseFromString(DOMPurify.sanitize(html), 'text/html')\n const nodes = $generateNodesFromDOM(editor, dom)\n root.select()\n root.append(...nodes)\n } else {\n for (const line of text.split('\\n'))\n root.append($createParagraphNode().append($createTextNode(line)))\n }\n },\n }))\n return (\n <LexicalComposer initialConfig={config}>\n <div className=\"mt-2\">\n <Toolbar disabled={disabled} />\n <div className=\"relative\">\n <RichTextPlugin\n contentEditable={\n <ContentEditable\n aria-label=\"Message\"\n className=\"min-h-64 w-full py-3 text-sm leading-relaxed outline-none\"\n />\n }\n placeholder={\n <span className=\"pointer-events-none absolute left-0 top-3 text-sm text-muted-foreground\">\n Write your message…\n </span>\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n </div>\n <HistoryPlugin /> <ListPlugin />{' '}\n <LinkPlugin validateUrl={(url) => /^https?:\\/\\//i.test(url)} />\n <OnChangePlugin\n ignoreSelectionChange\n onChange={(state, editor) =>\n state.read(() =>\n onChange(\n $getRoot().getTextContent(),\n DOMPurify.sanitize($generateHtmlFromNodes(editor))\n )\n )\n }\n />\n </div>\n </LexicalComposer>\n )\n}\n"]}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
require('./chunk-DES3K4SD.cjs');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var LexicalComposer = require('@lexical/react/LexicalComposer');
|
|
7
|
+
var LexicalRichTextPlugin = require('@lexical/react/LexicalRichTextPlugin');
|
|
8
|
+
var LexicalContentEditable = require('@lexical/react/LexicalContentEditable');
|
|
9
|
+
var LexicalHistoryPlugin = require('@lexical/react/LexicalHistoryPlugin');
|
|
10
|
+
var LexicalOnChangePlugin = require('@lexical/react/LexicalOnChangePlugin');
|
|
11
|
+
var LexicalListPlugin = require('@lexical/react/LexicalListPlugin');
|
|
12
|
+
var LexicalLinkPlugin = require('@lexical/react/LexicalLinkPlugin');
|
|
13
|
+
var LexicalErrorBoundary = require('@lexical/react/LexicalErrorBoundary');
|
|
14
|
+
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
15
|
+
var html = require('@lexical/html');
|
|
16
|
+
var list = require('@lexical/list');
|
|
17
|
+
var link = require('@lexical/link');
|
|
18
|
+
var lexical = require('lexical');
|
|
19
|
+
var lucideReact = require('lucide-react');
|
|
20
|
+
var ui = require('@arbidocs/react/ui');
|
|
21
|
+
var DOMPurify = require('dompurify');
|
|
22
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
23
|
+
|
|
24
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
|
+
|
|
26
|
+
var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
27
|
+
|
|
28
|
+
function Toolbar({ disabled }) {
|
|
29
|
+
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
30
|
+
const [addingLink, setAddingLink] = react.useState(false);
|
|
31
|
+
const [url, setUrl] = react.useState("");
|
|
32
|
+
const [formats, setFormats] = react.useState({});
|
|
33
|
+
react.useEffect(
|
|
34
|
+
() => editor.registerUpdateListener(
|
|
35
|
+
({ editorState }) => editorState.read(() => {
|
|
36
|
+
const selection = lexical.$getSelection();
|
|
37
|
+
if (!lexical.$isRangeSelection(selection)) return;
|
|
38
|
+
let parent = selection.anchor.getNode().getParent();
|
|
39
|
+
while (parent && !list.$isListNode(parent)) parent = parent.getParent();
|
|
40
|
+
const list$1 = list.$isListNode(parent) ? parent.getListType() : null;
|
|
41
|
+
setFormats({
|
|
42
|
+
Bold: selection.hasFormat("bold"),
|
|
43
|
+
Italic: selection.hasFormat("italic"),
|
|
44
|
+
Underline: selection.hasFormat("underline"),
|
|
45
|
+
"Bulleted list": list$1 === "bullet",
|
|
46
|
+
"Numbered list": list$1 === "number"
|
|
47
|
+
});
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
[editor]
|
|
51
|
+
);
|
|
52
|
+
react.useEffect(() => {
|
|
53
|
+
editor.setEditable(!disabled);
|
|
54
|
+
}, [editor, disabled]);
|
|
55
|
+
const buttons = [
|
|
56
|
+
{ label: "Bold", icon: lucideReact.Bold, run: () => editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, "bold") },
|
|
57
|
+
{
|
|
58
|
+
label: "Italic",
|
|
59
|
+
icon: lucideReact.Italic,
|
|
60
|
+
run: () => editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, "italic")
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: "Underline",
|
|
64
|
+
icon: lucideReact.Underline,
|
|
65
|
+
run: () => editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, "underline")
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
label: "Bulleted list",
|
|
69
|
+
icon: lucideReact.List,
|
|
70
|
+
run: () => editor.dispatchCommand(
|
|
71
|
+
formats["Bulleted list"] ? list.REMOVE_LIST_COMMAND : list.INSERT_UNORDERED_LIST_COMMAND,
|
|
72
|
+
void 0
|
|
73
|
+
)
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
label: "Numbered list",
|
|
77
|
+
icon: lucideReact.ListOrdered,
|
|
78
|
+
run: () => editor.dispatchCommand(
|
|
79
|
+
formats["Numbered list"] ? list.REMOVE_LIST_COMMAND : list.INSERT_ORDERED_LIST_COMMAND,
|
|
80
|
+
void 0
|
|
81
|
+
)
|
|
82
|
+
},
|
|
83
|
+
{ label: "Insert link", icon: lucideReact.Link, run: () => setAddingLink(!addingLink) },
|
|
84
|
+
{ label: "Undo", icon: lucideReact.Undo2, run: () => editor.dispatchCommand(lexical.UNDO_COMMAND, void 0) },
|
|
85
|
+
{ label: "Redo", icon: lucideReact.Redo2, run: () => editor.dispatchCommand(lexical.REDO_COMMAND, void 0) }
|
|
86
|
+
];
|
|
87
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
89
|
+
"div",
|
|
90
|
+
{
|
|
91
|
+
role: "toolbar",
|
|
92
|
+
"aria-label": "Message formatting",
|
|
93
|
+
className: "flex flex-wrap gap-0.5 border-b border-border/60 py-1",
|
|
94
|
+
children: buttons.map(({ label, icon: Icon, run }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
+
ui.Button,
|
|
97
|
+
{
|
|
98
|
+
type: "button",
|
|
99
|
+
variant: "ghost",
|
|
100
|
+
size: "sm",
|
|
101
|
+
"aria-label": label,
|
|
102
|
+
"aria-pressed": formats[label],
|
|
103
|
+
disabled,
|
|
104
|
+
className: "size-7 p-1 text-primary aria-pressed:bg-primary/10",
|
|
105
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
106
|
+
onClick: run,
|
|
107
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5" })
|
|
108
|
+
}
|
|
109
|
+
) }),
|
|
110
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { children: label })
|
|
111
|
+
] }, label))
|
|
112
|
+
}
|
|
113
|
+
),
|
|
114
|
+
addingLink && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-2", children: [
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
116
|
+
"input",
|
|
117
|
+
{
|
|
118
|
+
"aria-label": "Link URL",
|
|
119
|
+
type: "url",
|
|
120
|
+
placeholder: "https://example.com",
|
|
121
|
+
value: url,
|
|
122
|
+
onChange: (event) => setUrl(event.target.value),
|
|
123
|
+
className: "min-w-0 flex-1 rounded border bg-background px-2 py-1 text-sm"
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
127
|
+
ui.Button,
|
|
128
|
+
{
|
|
129
|
+
type: "button",
|
|
130
|
+
size: "sm",
|
|
131
|
+
disabled: disabled || !/^https?:\/\/\S+$/i.test(url),
|
|
132
|
+
onClick: () => {
|
|
133
|
+
editor.dispatchCommand(link.TOGGLE_LINK_COMMAND, url);
|
|
134
|
+
editor.update(() => {
|
|
135
|
+
const selection = lexical.$getSelection();
|
|
136
|
+
if (lexical.$isRangeSelection(selection))
|
|
137
|
+
selection.anchor.set(
|
|
138
|
+
selection.focus.key,
|
|
139
|
+
selection.focus.offset,
|
|
140
|
+
selection.focus.type
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
editor.focus();
|
|
144
|
+
setAddingLink(false);
|
|
145
|
+
setUrl("");
|
|
146
|
+
},
|
|
147
|
+
children: "Insert"
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", size: "sm", variant: "ghost", onClick: () => setAddingLink(false), children: "Cancel" })
|
|
151
|
+
] })
|
|
152
|
+
] });
|
|
153
|
+
}
|
|
154
|
+
function MailBodyEditor({
|
|
155
|
+
text,
|
|
156
|
+
html: html$1,
|
|
157
|
+
disabled,
|
|
158
|
+
onChange
|
|
159
|
+
}) {
|
|
160
|
+
const [config] = react.useState(() => ({
|
|
161
|
+
namespace: "mail-body",
|
|
162
|
+
nodes: [list.ListNode, list.ListItemNode, link.LinkNode],
|
|
163
|
+
theme: {
|
|
164
|
+
text: { bold: "font-bold", italic: "italic", underline: "underline" },
|
|
165
|
+
list: { ul: "list-disc pl-6", ol: "list-decimal pl-6" },
|
|
166
|
+
link: "text-primary underline",
|
|
167
|
+
paragraph: "mb-2"
|
|
168
|
+
},
|
|
169
|
+
onError: (error) => {
|
|
170
|
+
throw error;
|
|
171
|
+
},
|
|
172
|
+
editorState: (editor) => {
|
|
173
|
+
const root = lexical.$getRoot();
|
|
174
|
+
if (html$1) {
|
|
175
|
+
const dom = new DOMParser().parseFromString(DOMPurify__default.default.sanitize(html$1), "text/html");
|
|
176
|
+
const nodes = html.$generateNodesFromDOM(editor, dom);
|
|
177
|
+
root.select();
|
|
178
|
+
root.append(...nodes);
|
|
179
|
+
} else {
|
|
180
|
+
for (const line of text.split("\n"))
|
|
181
|
+
root.append(lexical.$createParagraphNode().append(lexical.$createTextNode(line)));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}));
|
|
185
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LexicalComposer.LexicalComposer, { initialConfig: config, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2", children: [
|
|
186
|
+
/* @__PURE__ */ jsxRuntime.jsx(Toolbar, { disabled }),
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
188
|
+
LexicalRichTextPlugin.RichTextPlugin,
|
|
189
|
+
{
|
|
190
|
+
contentEditable: /* @__PURE__ */ jsxRuntime.jsx(
|
|
191
|
+
LexicalContentEditable.ContentEditable,
|
|
192
|
+
{
|
|
193
|
+
"aria-label": "Message",
|
|
194
|
+
className: "min-h-64 w-full py-3 text-sm leading-relaxed outline-none"
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
placeholder: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-0 top-3 text-sm text-muted-foreground", children: "Write your message\u2026" }),
|
|
198
|
+
ErrorBoundary: LexicalErrorBoundary.LexicalErrorBoundary
|
|
199
|
+
}
|
|
200
|
+
) }),
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsx(LexicalHistoryPlugin.HistoryPlugin, {}),
|
|
202
|
+
" ",
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx(LexicalListPlugin.ListPlugin, {}),
|
|
204
|
+
" ",
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx(LexicalLinkPlugin.LinkPlugin, { validateUrl: (url) => /^https?:\/\//i.test(url) }),
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
LexicalOnChangePlugin.OnChangePlugin,
|
|
208
|
+
{
|
|
209
|
+
ignoreSelectionChange: true,
|
|
210
|
+
onChange: (state, editor) => state.read(
|
|
211
|
+
() => onChange(
|
|
212
|
+
lexical.$getRoot().getTextContent(),
|
|
213
|
+
DOMPurify__default.default.sanitize(html.$generateHtmlFromNodes(editor))
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
] }) });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
module.exports = MailBodyEditor;
|
|
222
|
+
//# sourceMappingURL=MailBodyEditor-D7MGJMLH.cjs.map
|
|
223
|
+
//# sourceMappingURL=MailBodyEditor-D7MGJMLH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/collaboration/mail/MailBodyEditor.tsx"],"names":["useLexicalComposerContext","useState","useEffect","$getSelection","$isRangeSelection","$isListNode","list","Bold","FORMAT_TEXT_COMMAND","Italic","Underline","List","REMOVE_LIST_COMMAND","INSERT_UNORDERED_LIST_COMMAND","ListOrdered","INSERT_ORDERED_LIST_COMMAND","Link","Undo2","UNDO_COMMAND","Redo2","REDO_COMMAND","jsxs","Fragment","jsx","Tooltip","TooltipTrigger","Button","TooltipContent","TOGGLE_LINK_COMMAND","html","ListNode","ListItemNode","LinkNode","$getRoot","DOMPurify","$generateNodesFromDOM","$createParagraphNode","$createTextNode","LexicalComposer","RichTextPlugin","ContentEditable","LexicalErrorBoundary","HistoryPlugin","ListPlugin","LinkPlugin","OnChangePlugin","$generateHtmlFromNodes"],"mappings":"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","file":"MailBodyEditor-D7MGJMLH.cjs","sourcesContent":["import { useEffect, useState } from 'react'\nimport { LexicalComposer } from '@lexical/react/LexicalComposer'\nimport { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable'\nimport { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'\nimport { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'\nimport { ListPlugin } from '@lexical/react/LexicalListPlugin'\nimport { LinkPlugin } from '@lexical/react/LexicalLinkPlugin'\nimport { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'\nimport {\n ListNode,\n ListItemNode,\n INSERT_UNORDERED_LIST_COMMAND,\n INSERT_ORDERED_LIST_COMMAND,\n REMOVE_LIST_COMMAND,\n $isListNode,\n} from '@lexical/list'\nimport { LinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'\nimport {\n $getRoot,\n $getSelection,\n $isRangeSelection,\n $createParagraphNode,\n $createTextNode,\n FORMAT_TEXT_COMMAND,\n UNDO_COMMAND,\n REDO_COMMAND,\n} from 'lexical'\nimport { Bold, Italic, Underline, List, ListOrdered, Link, Undo2, Redo2 } from 'lucide-react'\nimport { Button, Tooltip, TooltipTrigger, TooltipContent } from '@arbidocs/react/ui'\nimport DOMPurify from 'dompurify'\n\nfunction Toolbar({ disabled }: { disabled: boolean }) {\n const [editor] = useLexicalComposerContext()\n const [addingLink, setAddingLink] = useState(false)\n const [url, setUrl] = useState('')\n const [formats, setFormats] = useState<Record<string, boolean>>({})\n useEffect(\n () =>\n editor.registerUpdateListener(({ editorState }) =>\n editorState.read(() => {\n const selection = $getSelection()\n if (!$isRangeSelection(selection)) return\n let parent = selection.anchor.getNode().getParent()\n while (parent && !$isListNode(parent)) parent = parent.getParent()\n const list = $isListNode(parent) ? parent.getListType() : null\n setFormats({\n Bold: selection.hasFormat('bold'),\n Italic: selection.hasFormat('italic'),\n Underline: selection.hasFormat('underline'),\n 'Bulleted list': list === 'bullet',\n 'Numbered list': list === 'number',\n })\n })\n ),\n [editor]\n )\n useEffect(() => {\n editor.setEditable(!disabled)\n }, [editor, disabled])\n const buttons = [\n { label: 'Bold', icon: Bold, run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold') },\n {\n label: 'Italic',\n icon: Italic,\n run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic'),\n },\n {\n label: 'Underline',\n icon: Underline,\n run: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline'),\n },\n {\n label: 'Bulleted list',\n icon: List,\n run: () =>\n editor.dispatchCommand(\n formats['Bulleted list'] ? REMOVE_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND,\n undefined\n ),\n },\n {\n label: 'Numbered list',\n icon: ListOrdered,\n run: () =>\n editor.dispatchCommand(\n formats['Numbered list'] ? REMOVE_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,\n undefined\n ),\n },\n { label: 'Insert link', icon: Link, run: () => setAddingLink(!addingLink) },\n { label: 'Undo', icon: Undo2, run: () => editor.dispatchCommand(UNDO_COMMAND, undefined) },\n { label: 'Redo', icon: Redo2, run: () => editor.dispatchCommand(REDO_COMMAND, undefined) },\n ]\n return (\n <>\n <div\n role=\"toolbar\"\n aria-label=\"Message formatting\"\n className=\"flex flex-wrap gap-0.5 border-b border-border/60 py-1\"\n >\n {buttons.map(({ label, icon: Icon, run }) => (\n <Tooltip key={label}>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={label}\n aria-pressed={formats[label]}\n disabled={disabled}\n className=\"size-7 p-1 text-primary aria-pressed:bg-primary/10\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={run}\n >\n <Icon className=\"size-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n ))}\n </div>\n {addingLink && (\n <div className=\"flex items-center gap-2 py-2\">\n <input\n aria-label=\"Link URL\"\n type=\"url\"\n placeholder=\"https://example.com\"\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n className=\"min-w-0 flex-1 rounded border bg-background px-2 py-1 text-sm\"\n />\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={disabled || !/^https?:\\/\\/\\S+$/i.test(url)}\n onClick={() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, url)\n editor.update(() => {\n const selection = $getSelection()\n if ($isRangeSelection(selection))\n selection.anchor.set(\n selection.focus.key,\n selection.focus.offset,\n selection.focus.type\n )\n })\n editor.focus()\n setAddingLink(false)\n setUrl('')\n }}\n >\n Insert\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setAddingLink(false)}>\n Cancel\n </Button>\n </div>\n )}\n </>\n )\n}\n\n/** Small mail editor using the same Lexical engine as the document editor. */\nexport default function MailBodyEditor({\n text,\n html,\n disabled,\n onChange,\n}: {\n text: string\n html?: string\n disabled: boolean\n onChange: (text: string, html: string) => void\n}) {\n const [config] = useState(() => ({\n namespace: 'mail-body',\n nodes: [ListNode, ListItemNode, LinkNode],\n theme: {\n text: { bold: 'font-bold', italic: 'italic', underline: 'underline' },\n list: { ul: 'list-disc pl-6', ol: 'list-decimal pl-6' },\n link: 'text-primary underline',\n paragraph: 'mb-2',\n },\n onError: (error: Error) => {\n throw error\n },\n editorState: (editor: Parameters<typeof $generateNodesFromDOM>[0]) => {\n const root = $getRoot()\n if (html) {\n const dom = new DOMParser().parseFromString(DOMPurify.sanitize(html), 'text/html')\n const nodes = $generateNodesFromDOM(editor, dom)\n root.select()\n root.append(...nodes)\n } else {\n for (const line of text.split('\\n'))\n root.append($createParagraphNode().append($createTextNode(line)))\n }\n },\n }))\n return (\n <LexicalComposer initialConfig={config}>\n <div className=\"mt-2\">\n <Toolbar disabled={disabled} />\n <div className=\"relative\">\n <RichTextPlugin\n contentEditable={\n <ContentEditable\n aria-label=\"Message\"\n className=\"min-h-64 w-full py-3 text-sm leading-relaxed outline-none\"\n />\n }\n placeholder={\n <span className=\"pointer-events-none absolute left-0 top-3 text-sm text-muted-foreground\">\n Write your message…\n </span>\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n </div>\n <HistoryPlugin /> <ListPlugin />{' '}\n <LinkPlugin validateUrl={(url) => /^https?:\\/\\//i.test(url)} />\n <OnChangePlugin\n ignoreSelectionChange\n onChange={(state, editor) =>\n state.read(() =>\n onChange(\n $getRoot().getTextContent(),\n DOMPurify.sanitize($generateHtmlFromNodes(editor))\n )\n )\n }\n />\n </div>\n </LexicalComposer>\n )\n}\n"]}
|