@arbidocs/blocks 0.4.84 → 0.4.85

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.
Files changed (114) hide show
  1. package/dist/MailBodyEditor-5PIQLYVY.js +217 -0
  2. package/dist/MailBodyEditor-5PIQLYVY.js.map +1 -0
  3. package/dist/MailBodyEditor-D7MGJMLH.cjs +223 -0
  4. package/dist/MailBodyEditor-D7MGJMLH.cjs.map +1 -0
  5. package/dist/agents/index.cjs +281 -280
  6. package/dist/agents/index.js +6 -5
  7. package/dist/agents/workflows/StepBarFrame.d.ts +3 -1
  8. package/dist/agents/workflows/WorkflowRunner.d.ts +10 -1
  9. package/dist/agents/workflows/run.d.ts +24 -3
  10. package/dist/agents/workflows/stepWindow.d.ts +4 -2
  11. package/dist/agents/workflows/types.d.ts +5 -0
  12. package/dist/agents/workflows/useWorkflowView.d.ts +16 -1
  13. package/dist/chat/index.cjs +1 -1
  14. package/dist/chat/index.js +1 -1
  15. package/dist/chunk-3R6XBYL7.cjs +576 -0
  16. package/dist/chunk-3R6XBYL7.cjs.map +1 -0
  17. package/dist/{chunk-CKB64Z4R.js → chunk-4XJZ6AAY.js} +6 -245
  18. package/dist/chunk-4XJZ6AAY.js.map +1 -0
  19. package/dist/{chunk-SB5ZKOYN.js → chunk-7C35WXYB.js} +4 -63
  20. package/dist/chunk-7C35WXYB.js.map +1 -0
  21. package/dist/chunk-7RJTEWYM.js +362 -0
  22. package/dist/chunk-7RJTEWYM.js.map +1 -0
  23. package/dist/chunk-AFSOUS5X.cjs +253 -0
  24. package/dist/chunk-AFSOUS5X.cjs.map +1 -0
  25. package/dist/{chunk-F4RUCUXF.cjs → chunk-C2HRZSAT.cjs} +2 -63
  26. package/dist/chunk-C2HRZSAT.cjs.map +1 -0
  27. package/dist/{chunk-RX35SMPR.js → chunk-FHOZMT5P.js} +7 -6
  28. package/dist/chunk-FHOZMT5P.js.map +1 -0
  29. package/dist/{chunk-CONIA2ZA.js → chunk-KHY4PYU7.js} +246 -146
  30. package/dist/chunk-KHY4PYU7.js.map +1 -0
  31. package/dist/chunk-LGX6UFYG.js +557 -0
  32. package/dist/chunk-LGX6UFYG.js.map +1 -0
  33. package/dist/chunk-O4YPVYPO.cjs +373 -0
  34. package/dist/chunk-O4YPVYPO.cjs.map +1 -0
  35. package/dist/chunk-R26OHONI.js +250 -0
  36. package/dist/chunk-R26OHONI.js.map +1 -0
  37. package/dist/{chunk-RYYYHPFU.cjs → chunk-RZUMQM7W.cjs} +246 -146
  38. package/dist/chunk-RZUMQM7W.cjs.map +1 -0
  39. package/dist/{chunk-YJQVLVBJ.cjs → chunk-S5HZBXZA.cjs} +2 -243
  40. package/dist/chunk-S5HZBXZA.cjs.map +1 -0
  41. package/dist/{chunk-ZQYE7J3J.cjs → chunk-WRSBM6QN.cjs} +332 -94
  42. package/dist/chunk-WRSBM6QN.cjs.map +1 -0
  43. package/dist/{chunk-RSKSXEPW.js → chunk-X23U6QEJ.js} +324 -88
  44. package/dist/chunk-X23U6QEJ.js.map +1 -0
  45. package/dist/{chunk-XA5S4776.cjs → chunk-Z7YUCYI6.cjs} +51 -50
  46. package/dist/chunk-Z7YUCYI6.cjs.map +1 -0
  47. package/dist/collaboration/index.cjs +100 -49
  48. package/dist/collaboration/index.js +4 -1
  49. package/dist/collaboration/mail/MailBodyEditor.d.ts +7 -0
  50. package/dist/collaboration/mail/MailDeliveryList.d.ts +8 -0
  51. package/dist/collaboration/mail/MailDocumentPicker.d.ts +15 -0
  52. package/dist/collaboration/mail/MailGrid.d.ts +17 -0
  53. package/dist/collaboration/mail/MailMessageView.d.ts +27 -0
  54. package/dist/collaboration/mail/PlainMailBodyEditor.d.ts +12 -0
  55. package/dist/collaboration/mail/index.d.ts +6 -0
  56. package/dist/collaboration/mail/mailCompose.d.ts +24 -0
  57. package/dist/connect/index.cjs +1647 -65
  58. package/dist/connect/index.cjs.map +1 -1
  59. package/dist/connect/index.d.ts +2 -1
  60. package/dist/connect/index.js +1631 -55
  61. package/dist/connect/index.js.map +1 -1
  62. package/dist/connection/ConnectedTagTable.d.ts +32 -0
  63. package/dist/connection/mail/ConnectedMailAccounts.d.ts +21 -0
  64. package/dist/connection/mail/ConnectedMailComposer.d.ts +40 -0
  65. package/dist/connection/mail/ConnectedMailSetup.d.ts +16 -0
  66. package/dist/connection/mail/ConnectedMailbox.d.ts +65 -0
  67. package/dist/connection/mail/MailComposerForm.d.ts +25 -0
  68. package/dist/connection/mail/attachments.d.ts +13 -0
  69. package/dist/connection/mail/index.d.ts +6 -0
  70. package/dist/connection/mail/mailbox.d.ts +6 -0
  71. package/dist/connection/mail/types.d.ts +92 -0
  72. package/dist/connection/useConnectedWorkNotifications.d.ts +6 -0
  73. package/dist/connection/useWorkflowThread.d.ts +7 -2
  74. package/dist/facts/index.cjs +2 -2
  75. package/dist/facts/index.js +2 -2
  76. package/dist/files/index.cjs +47 -367
  77. package/dist/files/index.cjs.map +1 -1
  78. package/dist/files/index.js +10 -360
  79. package/dist/files/index.js.map +1 -1
  80. package/dist/index.cjs +450 -391
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.js +21 -18
  83. package/dist/index.js.map +1 -1
  84. package/dist/settings/index.cjs +10 -9
  85. package/dist/settings/index.cjs.map +1 -1
  86. package/dist/settings/index.js +2 -1
  87. package/dist/settings/index.js.map +1 -1
  88. package/dist/shell/index.cjs +1 -1
  89. package/dist/shell/index.js +1 -1
  90. package/dist/tags/TagColumnsEditor.d.ts +34 -0
  91. package/dist/tags/TagDetail.d.ts +13 -11
  92. package/dist/tags/TagTable.d.ts +99 -0
  93. package/dist/tags/TagsNav.d.ts +2 -2
  94. package/dist/tags/index.d.ts +7 -5
  95. package/dist/tags/{tagMatrixDocx.d.ts → tagTableDocx.d.ts} +12 -12
  96. package/dist/tags/tagTableModel.d.ts +47 -0
  97. package/dist/workflow-canvas/index.cjs +49 -48
  98. package/dist/workflow-canvas/index.cjs.map +1 -1
  99. package/dist/workflow-canvas/index.js +6 -5
  100. package/dist/workflow-canvas/index.js.map +1 -1
  101. package/package.json +29 -4
  102. package/dist/chunk-CKB64Z4R.js.map +0 -1
  103. package/dist/chunk-CONIA2ZA.js.map +0 -1
  104. package/dist/chunk-F4RUCUXF.cjs.map +0 -1
  105. package/dist/chunk-RSKSXEPW.js.map +0 -1
  106. package/dist/chunk-RX35SMPR.js.map +0 -1
  107. package/dist/chunk-RYYYHPFU.cjs.map +0 -1
  108. package/dist/chunk-SB5ZKOYN.js.map +0 -1
  109. package/dist/chunk-XA5S4776.cjs.map +0 -1
  110. package/dist/chunk-YJQVLVBJ.cjs.map +0 -1
  111. package/dist/chunk-ZQYE7J3J.cjs.map +0 -1
  112. package/dist/connection/ConnectedTagMatrix.d.ts +0 -23
  113. package/dist/tags/TagMatrix.d.ts +0 -87
  114. 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"]}