react-mail-inbox 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2255 @@
1
+ import { createContext, useContext, useState, useEffect, useRef, useCallback, useMemo } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
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 { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
9
+ import { createPortal } from 'react-dom';
10
+ import { MdClose, MdEdit, MdTextFields, MdCheck, MdImage, MdLink, MdAttachFile, MdTextFormat, MdArrowDropDown, MdFormatQuote, MdStrikethroughS, MdFormatClear, MdOutlineFormatIndentIncrease, MdFormatIndentDecrease, MdFormatListNumbered, MdFormatListBulleted, MdFormatAlignCenter, MdFormatAlignRight, MdFormatAlignLeft, MdFormatUnderlined, MdFormatItalic, MdFormatBold, MdRedo, MdUndo } from 'react-icons/md';
11
+ import Popup from 'reactjs-popup';
12
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
13
+ import { $getRoot, $getSelection, $isRangeSelection, SELECTION_CHANGE_COMMAND, REDO_COMMAND, UNDO_COMMAND, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND } from 'lexical';
14
+ import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND } from '@lexical/list';
15
+ import { LinkNode, AutoLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
16
+ import { $getNearestNodeOfType, mergeRegister } from '@lexical/utils';
17
+ import { $isAtNodeEnd, $patchStyleText } from '@lexical/selection';
18
+ import { useDropzone } from 'react-dropzone';
19
+ import heic2any from 'heic2any';
20
+ import { ListPlugin } from '@lexical/react/LexicalListPlugin';
21
+ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
22
+ import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
23
+
24
+ var ThemeContext = createContext(void 0);
25
+ var useTheme = () => {
26
+ const context = useContext(ThemeContext);
27
+ if (!context) {
28
+ throw new Error("useTheme must be used within a ThemeProvider");
29
+ }
30
+ return context;
31
+ };
32
+ var ThemeProvider = ({
33
+ children,
34
+ initialTheme = "dark",
35
+ onThemeChange
36
+ }) => {
37
+ const [theme, setTheme] = useState(initialTheme);
38
+ useEffect(() => {
39
+ document.documentElement.setAttribute("data-theme", theme);
40
+ if (onThemeChange) {
41
+ onThemeChange(theme);
42
+ }
43
+ }, [theme, onThemeChange]);
44
+ const toggleTheme = () => {
45
+ setTheme((prev) => prev === "light" ? "dark" : "light");
46
+ };
47
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme, toggleTheme }, children });
48
+ };
49
+ var EmailContext = createContext(void 0);
50
+ var useEmailContext = () => {
51
+ const context = useContext(EmailContext);
52
+ if (!context) {
53
+ throw new Error("useEmailContext must be used within an EmailProvider");
54
+ }
55
+ return context;
56
+ };
57
+ var EmailProvider = ({ children }) => {
58
+ const [emails, setEmails] = useState({
59
+ to: [],
60
+ cc: [],
61
+ bcc: []
62
+ });
63
+ const [isReply, setIsReply] = useState(false);
64
+ const [subject, setSubject] = useState("");
65
+ const [showCC, setShowCC] = useState(false);
66
+ const [showBCC, setShowBCC] = useState(false);
67
+ const [attachments, setAttachments] = useState([]);
68
+ useEffect(() => {
69
+ console.log("EmailProvider emails updated:", emails);
70
+ }, [emails]);
71
+ return /* @__PURE__ */ jsx(
72
+ EmailContext.Provider,
73
+ {
74
+ value: {
75
+ emails,
76
+ setEmails,
77
+ subject,
78
+ setSubject,
79
+ showCC,
80
+ setShowCC,
81
+ showBCC,
82
+ setShowBCC,
83
+ attachments,
84
+ setAttachments,
85
+ isReply,
86
+ setIsReply
87
+ },
88
+ children
89
+ }
90
+ );
91
+ };
92
+
93
+ // src/utils/toolbar.ts
94
+ var eventTypes = {
95
+ undo: "undo",
96
+ redo: "redo",
97
+ bold: "bold",
98
+ italic: "italic",
99
+ underline: "underline",
100
+ color: {
101
+ base: "colors"},
102
+ code: "code",
103
+ link: "link",
104
+ listNumber: "listNumber",
105
+ listBullet: "listBullet",
106
+ align: {
107
+ base: "align"},
108
+ indent: "indent",
109
+ indentDecrease: "indentDecrease",
110
+ strike: "strike",
111
+ attachFile: "attachFile",
112
+ fontSize: "fontSize",
113
+ fontFamily: "fontFamily"
114
+ };
115
+ var toolbarComponentType = {
116
+ styling: "styling",
117
+ divider: "divider",
118
+ component: "component"
119
+ };
120
+ var pluginList = [
121
+ {
122
+ type: toolbarComponentType["styling"],
123
+ icon: "Styling",
124
+ id: "4bc66ea9-2e35-4a7b-a674-be7e4ee163c5",
125
+ options: [
126
+ {
127
+ name: eventTypes["undo"],
128
+ type: toolbarComponentType["component"],
129
+ icon: "Undo",
130
+ id: "29cf5eb3-37cd-482f-9a15-c358faf19cc2"
131
+ },
132
+ {
133
+ name: eventTypes["redo"],
134
+ type: toolbarComponentType["component"],
135
+ icon: "Redo",
136
+ id: "8744f7ab-5818-46ce-9417-2fec87123afe"
137
+ },
138
+ {
139
+ type: toolbarComponentType["divider"],
140
+ id: "ed0104fd-3507-43f6-80c1-813fbdf04479"
141
+ },
142
+ {
143
+ name: eventTypes["fontFamily"],
144
+ type: toolbarComponentType["component"],
145
+ id: "1c12d7e2-aa6a-42b4-b25c-b55fe3bcf524"
146
+ },
147
+ {
148
+ type: toolbarComponentType["divider"],
149
+ id: "d0f67d01-0731-411a-b448-e1dca47014f4"
150
+ },
151
+ {
152
+ name: eventTypes["fontSize"],
153
+ type: toolbarComponentType["component"],
154
+ id: "82e31b62-5441-4052-887c-faa02d0b7075"
155
+ },
156
+ {
157
+ type: toolbarComponentType["divider"],
158
+ id: "2e3558e4-3ad4-422b-8502-ea3c58fb8c2e"
159
+ },
160
+ {
161
+ name: eventTypes["bold"],
162
+ type: toolbarComponentType["component"],
163
+ icon: "Bold",
164
+ id: "ac2b5b54-7323-44a4-bc6d-8bae6e48efe2"
165
+ },
166
+ {
167
+ name: eventTypes["italic"],
168
+ type: toolbarComponentType["component"],
169
+ icon: "Italic",
170
+ id: "6a927c2a-2230-4dc7-af71-47fbe9fb784d"
171
+ },
172
+ {
173
+ name: eventTypes["underline"],
174
+ type: toolbarComponentType["component"],
175
+ icon: "Underline",
176
+ id: "f07b3a6f-ffaa-4153-beae-79a36acb6a08"
177
+ },
178
+ {
179
+ name: eventTypes["color"].base,
180
+ type: toolbarComponentType["component"],
181
+ icon: "Color",
182
+ id: "e14ec25f-3dd3-4ed5-b33a-a033684d248b"
183
+ },
184
+ {
185
+ type: toolbarComponentType["divider"],
186
+ id: "93e60297-206f-4f31-bc29-11daff2052bd"
187
+ },
188
+ {
189
+ name: eventTypes.align.base,
190
+ type: toolbarComponentType["component"],
191
+ id: "30da93ea-efa6-4642-bfa5-28fd4dc9c5b3"
192
+ },
193
+ {
194
+ type: toolbarComponentType["divider"],
195
+ id: "9bad0563-6118-4855-9286-402bf98e00ad"
196
+ },
197
+ {
198
+ name: eventTypes["listNumber"],
199
+ type: toolbarComponentType["component"],
200
+ icon: "OrderedList",
201
+ id: "d37865e1-ff54-4118-a5cc-fa147d222471"
202
+ },
203
+ {
204
+ name: eventTypes["listBullet"],
205
+ type: toolbarComponentType["component"],
206
+ icon: "UnOrderedList",
207
+ id: "ed77e7c9-b89c-41c5-a749-e68ea0b30497"
208
+ },
209
+ {
210
+ type: toolbarComponentType["divider"],
211
+ id: "e5ecd77b-44cc-42fe-badb-48cadf3ddfb1"
212
+ },
213
+ {
214
+ name: eventTypes["indentDecrease"],
215
+ type: toolbarComponentType["component"],
216
+ icon: "IndentLess",
217
+ id: "2dc6a5e4-b1b5-47d1-ac2f-5d0becb02d33"
218
+ },
219
+ {
220
+ name: eventTypes["indent"],
221
+ type: toolbarComponentType["component"],
222
+ icon: "IndentMore",
223
+ id: "6903a3d1-a83f-4bc6-9bd9-f673feffe84f"
224
+ }
225
+ ]
226
+ },
227
+ {
228
+ type: "component",
229
+ name: eventTypes["attachFile"],
230
+ icon: "Attach",
231
+ id: "f43a284e-113e-4095-b001-9d00a1dddc4c"
232
+ },
233
+ {
234
+ type: "component",
235
+ name: eventTypes["link"],
236
+ icon: "Link",
237
+ id: "580db61e-7939-4efe-914c-304b271998ec"
238
+ }
239
+ // {
240
+ // type: "component",
241
+ // name: eventTypes["insertPhoto"],
242
+ // icon: "Image",
243
+ // id: "d032ba91-3e78-4ed5-8561-033cd1c49cae",
244
+ // },
245
+ ];
246
+ var icons = {
247
+ Undo: MdUndo,
248
+ Redo: MdRedo,
249
+ Bold: MdFormatBold,
250
+ Italic: MdFormatItalic,
251
+ Underline: MdFormatUnderlined,
252
+ Color: MdTextFormat,
253
+ LeftAlign: MdFormatAlignLeft,
254
+ RightAlign: MdFormatAlignRight,
255
+ CenterAlign: MdFormatAlignCenter,
256
+ UnOrderedList: MdFormatListBulleted,
257
+ OrderedList: MdFormatListNumbered,
258
+ IndentLess: MdFormatIndentDecrease,
259
+ IndentMore: MdOutlineFormatIndentIncrease,
260
+ RemoveFormat: MdFormatClear,
261
+ StrikeThrough: MdStrikethroughS,
262
+ CodeQuote: MdFormatQuote,
263
+ DownArrow: MdArrowDropDown,
264
+ Styling: MdTextFormat,
265
+ Attach: MdAttachFile,
266
+ Link: MdLink,
267
+ Image: MdImage,
268
+ Check: MdCheck,
269
+ TextFields: MdTextFields,
270
+ Edit: MdEdit,
271
+ Close: MdClose
272
+ };
273
+ var helper_default = icons;
274
+ var Icon = ({ name, size = 24, color, className }) => {
275
+ const IconComponent = helper_default[name];
276
+ if (!IconComponent) {
277
+ console.warn(`Icon "${name}" not found.`);
278
+ return null;
279
+ }
280
+ return /* @__PURE__ */ jsx(IconComponent, { size, color, className });
281
+ };
282
+ var Icon_default = Icon;
283
+ var MyPopup = ({
284
+ trigger,
285
+ children,
286
+ popUpDirection = "top center"
287
+ }) => {
288
+ const popupRef = useRef(null);
289
+ const handleClose = () => {
290
+ if (popupRef.current && typeof popupRef.current.close === "function") {
291
+ popupRef.current.close();
292
+ }
293
+ };
294
+ const renderContent = (close) => {
295
+ const combinedClose = () => {
296
+ close?.();
297
+ handleClose();
298
+ };
299
+ return children({ close: combinedClose });
300
+ };
301
+ return /* @__PURE__ */ jsx(
302
+ Popup,
303
+ {
304
+ ref: popupRef,
305
+ trigger,
306
+ closeOnDocumentClick: true,
307
+ repositionOnResize: true,
308
+ position: popUpDirection,
309
+ className: "filter-popup",
310
+ children: renderContent
311
+ }
312
+ );
313
+ };
314
+ var MyPopup_default = MyPopup;
315
+
316
+ // src/utils/core.ts
317
+ var fontOptions = [
318
+ {
319
+ label: "Sans Serif",
320
+ value: "sans-serif",
321
+ style: { fontFamily: "sans-serif" }
322
+ },
323
+ { label: "Serif", value: "serif", style: { fontFamily: "serif" } },
324
+ {
325
+ label: "Fixed Width",
326
+ value: "monospace",
327
+ style: { fontFamily: "monospace" }
328
+ },
329
+ {
330
+ label: "Wide",
331
+ value: "wide",
332
+ style: { fontWeight: "bold", letterSpacing: "0.05em" }
333
+ },
334
+ { label: "Narrow", value: "narrow", style: { fontStretch: "condensed" } },
335
+ {
336
+ label: "Comic Sans MS",
337
+ value: "Comic Sans MS",
338
+ style: { fontFamily: "Comic Sans MS, cursive" }
339
+ },
340
+ {
341
+ label: "Garamond",
342
+ value: "Garamond",
343
+ style: { fontFamily: "Garamond, serif" }
344
+ },
345
+ {
346
+ label: "Georgia",
347
+ value: "Georgia",
348
+ style: { fontFamily: "Georgia, serif" }
349
+ },
350
+ {
351
+ label: "Tahoma",
352
+ value: "Tahoma",
353
+ style: { fontFamily: "Tahoma, sans-serif" }
354
+ },
355
+ {
356
+ label: "Trebuchet MS",
357
+ value: "Trebuchet MS",
358
+ style: { fontFamily: "Trebuchet MS, sans-serif" }
359
+ },
360
+ {
361
+ label: "Verdana",
362
+ value: "Verdana",
363
+ style: { fontFamily: "Verdana, sans-serif" }
364
+ }
365
+ ];
366
+ var OPTIONS = [
367
+ { key: "small", label: "Small", sizePx: 12 },
368
+ { key: "normal", label: "Normal", sizePx: 18 },
369
+ { key: "large", label: "Large", sizePx: 28 },
370
+ { key: "huge", label: "Huge", sizePx: 56 }
371
+ ];
372
+ var GREYS = [
373
+ "#000000",
374
+ "#3a3a3a",
375
+ "#5a5a5a",
376
+ "#8a8a8a",
377
+ "#bfbfbf",
378
+ "#dedede",
379
+ "#f3f3f3",
380
+ "#ffffff"
381
+ ];
382
+ var ACCENTS = [
383
+ "#e53935",
384
+ "#fb8c00",
385
+ "#ffee58",
386
+ "#66ff66",
387
+ "#4dd0e1",
388
+ "#1e88e5",
389
+ "#9c27b0",
390
+ "#ff3bd6"
391
+ ];
392
+ var PALETTE = [
393
+ [
394
+ "#f7d7d7",
395
+ "#f3d0c8",
396
+ "#f0c5c5",
397
+ "#efc9d8",
398
+ "#f7e6e9",
399
+ "#f3edf7",
400
+ "#f0eaf6",
401
+ "#f8f0f6"
402
+ ],
403
+ [
404
+ "#f0b9b9",
405
+ "#f0d4c2",
406
+ "#e6f0d2",
407
+ "#e4f7e8",
408
+ "#d8eef8",
409
+ "#dbe1ff",
410
+ "#e9d9f6",
411
+ "#f5d9f7"
412
+ ],
413
+ [
414
+ "#e69a9a",
415
+ "#e6caa3",
416
+ "#d7e6b0",
417
+ "#c8f0e6",
418
+ "#bfe3ff",
419
+ "#cbd8ff",
420
+ "#d6c3f3",
421
+ "#f0c2f3"
422
+ ],
423
+ [
424
+ "#d16464",
425
+ "#d09a6a",
426
+ "#a8cf7b",
427
+ "#7fd6c0",
428
+ "#73b7ff",
429
+ "#7a9cff",
430
+ "#b483f1",
431
+ "#f08cf2"
432
+ ],
433
+ [
434
+ "#b23a3a",
435
+ "#b26a3a",
436
+ "#7aa04a",
437
+ "#3fb092",
438
+ "#296f94",
439
+ "#2a4177",
440
+ "#452a68",
441
+ "#6e1f4d"
442
+ ],
443
+ [
444
+ "#7a1d1d",
445
+ "#7a4a1e",
446
+ "#556a2a",
447
+ "#195b47",
448
+ "#123f5a",
449
+ "#182840",
450
+ "#2a1836",
451
+ "#3a1026"
452
+ ]
453
+ ];
454
+ var core_default = fontOptions;
455
+ function FontSelect({ value = "serif", onChange }) {
456
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
457
+ MyPopup_default,
458
+ {
459
+ trigger: /* @__PURE__ */ jsxs("button", { className: "font-option heading", children: [
460
+ core_default?.find((o) => o.value === value)?.label,
461
+ /* @__PURE__ */ jsx(Icon_default, { name: "DownArrow" })
462
+ ] }),
463
+ children: ({ close }) => /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "font-options", children: core_default.map((font) => /* @__PURE__ */ jsx(
464
+ "button",
465
+ {
466
+ className: "btn",
467
+ onClick: () => {
468
+ onChange(font.value);
469
+ close();
470
+ },
471
+ style: { ...font.style },
472
+ children: /* @__PURE__ */ jsxs("div", { className: "font-option", children: [
473
+ value === font.value && /* @__PURE__ */ jsx(Icon_default, { name: "Check" }),
474
+ font.label
475
+ ] })
476
+ },
477
+ font.value
478
+ )) }) })
479
+ }
480
+ ) });
481
+ }
482
+ function FontSizePicker({
483
+ value = "normal",
484
+ onChange = () => {
485
+ }
486
+ }) {
487
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
488
+ MyPopup_default,
489
+ {
490
+ trigger: /* @__PURE__ */ jsxs("button", { className: "font-option heading", children: [
491
+ /* @__PURE__ */ jsx(Icon_default, { name: "TextFields" }),
492
+ /* @__PURE__ */ jsx(Icon_default, { name: "DownArrow" })
493
+ ] }),
494
+ children: ({ close }) => /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "font-options", children: OPTIONS.map((font) => /* @__PURE__ */ jsx(
495
+ "button",
496
+ {
497
+ className: "btn",
498
+ onClick: () => {
499
+ onChange(font.key);
500
+ close();
501
+ },
502
+ style: { fontSize: `${font.sizePx}px` },
503
+ children: /* @__PURE__ */ jsxs("div", { className: "font-option", children: [
504
+ value === font.key && /* @__PURE__ */ jsx(Icon_default, { name: "Check" }),
505
+ font.label
506
+ ] })
507
+ },
508
+ font.key
509
+ )) }) })
510
+ }
511
+ ) });
512
+ }
513
+ function Swatch({ color, selected, onClick, label }) {
514
+ return /* @__PURE__ */ jsx(
515
+ "button",
516
+ {
517
+ className: "swatch",
518
+ title: label || color,
519
+ "aria-pressed": selected,
520
+ onClick: () => onClick(color),
521
+ style: { background: color },
522
+ children: selected && /* @__PURE__ */ jsx("svg", { className: "check", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx(
523
+ "path",
524
+ {
525
+ d: "M20 6L9 17l-5-5",
526
+ stroke: "white",
527
+ strokeWidth: "2",
528
+ strokeLinecap: "round",
529
+ strokeLinejoin: "round",
530
+ fill: "none"
531
+ }
532
+ ) })
533
+ }
534
+ );
535
+ }
536
+ function ColorPicker({
537
+ value = { background: "#ffffff", text: "#000000" },
538
+ onChange = () => {
539
+ }
540
+ }) {
541
+ function update(which, color) {
542
+ onChange({ ...value, [which]: color });
543
+ }
544
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
545
+ MyPopup_default,
546
+ {
547
+ trigger: /* @__PURE__ */ jsxs("button", { className: "font-option heading", children: [
548
+ /* @__PURE__ */ jsx(Icon_default, { name: "Styling" }),
549
+ /* @__PURE__ */ jsx(Icon_default, { name: "DownArrow" })
550
+ ] }),
551
+ children: ({ close }) => /* @__PURE__ */ jsx(
552
+ "div",
553
+ {
554
+ className: "color-popover",
555
+ role: "dialog",
556
+ "aria-label": "Choose colors",
557
+ children: /* @__PURE__ */ jsxs("div", { className: "color-columns", children: [
558
+ /* @__PURE__ */ jsxs("section", { className: "color-column", "aria-labelledby": "bg-label", children: [
559
+ /* @__PURE__ */ jsx("h4", { id: "bg-label", children: "Background color" }),
560
+ /* @__PURE__ */ jsx("div", { className: "row", children: GREYS.map((c) => /* @__PURE__ */ jsx(
561
+ Swatch,
562
+ {
563
+ color: c,
564
+ selected: value.background === c,
565
+ onClick: (col) => {
566
+ update("background", col);
567
+ close();
568
+ },
569
+ label: c
570
+ },
571
+ c + "bg"
572
+ )) }),
573
+ /* @__PURE__ */ jsx("div", { className: "row accent-row", children: ACCENTS.map((c) => /* @__PURE__ */ jsx(
574
+ Swatch,
575
+ {
576
+ color: c,
577
+ selected: value.background === c,
578
+ onClick: (col) => {
579
+ update("background", col);
580
+ close();
581
+ },
582
+ label: c
583
+ },
584
+ c + "bgacc"
585
+ )) }),
586
+ /* @__PURE__ */ jsx("div", { className: "palette", children: PALETTE.map((r, i) => /* @__PURE__ */ jsx("div", { className: "palette-row", children: r.map((c) => /* @__PURE__ */ jsx(
587
+ Swatch,
588
+ {
589
+ color: c,
590
+ selected: value.background === c,
591
+ onClick: (col) => {
592
+ update("background", col);
593
+ close();
594
+ },
595
+ label: c
596
+ },
597
+ c + "bgp" + i
598
+ )) }, "row" + i)) })
599
+ ] }),
600
+ /* @__PURE__ */ jsxs("section", { className: "color-column", "aria-labelledby": "text-label", children: [
601
+ /* @__PURE__ */ jsx("h4", { id: "text-label", children: "Text color" }),
602
+ /* @__PURE__ */ jsx("div", { className: "row", children: GREYS.map((c) => /* @__PURE__ */ jsx(
603
+ Swatch,
604
+ {
605
+ color: c,
606
+ selected: value.text === c,
607
+ onClick: (col) => {
608
+ update("text", col);
609
+ close();
610
+ },
611
+ label: c
612
+ },
613
+ c + "tx"
614
+ )) }),
615
+ /* @__PURE__ */ jsx("div", { className: "row accent-row", children: ACCENTS.map((c) => /* @__PURE__ */ jsx(
616
+ Swatch,
617
+ {
618
+ color: c,
619
+ selected: value.text === c,
620
+ onClick: (col) => {
621
+ update("text", col);
622
+ close();
623
+ },
624
+ label: c
625
+ },
626
+ c + "txacc"
627
+ )) }),
628
+ /* @__PURE__ */ jsx("div", { className: "palette", children: PALETTE.map((r, i) => /* @__PURE__ */ jsx("div", { className: "palette-row", children: r.map((c) => /* @__PURE__ */ jsx(
629
+ Swatch,
630
+ {
631
+ color: c,
632
+ selected: value.text === c,
633
+ onClick: (col) => {
634
+ update("text", col);
635
+ close();
636
+ },
637
+ label: c
638
+ },
639
+ c + "txp" + i
640
+ )) }, "txrow" + i)) })
641
+ ] })
642
+ ] })
643
+ }
644
+ )
645
+ }
646
+ ) });
647
+ }
648
+ var OPTIONS2 = [
649
+ { key: "left", iconName: "LeftAlign", label: "Left align" },
650
+ { key: "center", iconName: "CenterAlign", label: "Center align" },
651
+ { key: "right", iconName: "RightAlign", label: "Right align" }
652
+ ];
653
+ function AlignmentSelect({
654
+ value = "left",
655
+ onChange = () => {
656
+ }
657
+ }) {
658
+ function onSelect(key) {
659
+ onChange(key);
660
+ }
661
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
662
+ MyPopup_default,
663
+ {
664
+ trigger: /* @__PURE__ */ jsxs("button", { className: "font-option heading", children: [
665
+ /* @__PURE__ */ jsx(Icon_default, { name: OPTIONS2?.find((o) => o.key === value)?.iconName || "LeftAlign" }),
666
+ /* @__PURE__ */ jsx(Icon_default, { name: "DownArrow" })
667
+ ] }),
668
+ children: ({ close }) => /* @__PURE__ */ jsx("div", { className: "wrapper-alignment", children: OPTIONS2.map((opt) => {
669
+ const active = opt.key === value;
670
+ return /* @__PURE__ */ jsxs(
671
+ "button",
672
+ {
673
+ role: "menuitemradio",
674
+ "aria-checked": active,
675
+ tabIndex: 0,
676
+ className: `alignment-option ${active ? "active" : ""}`,
677
+ onClick: () => {
678
+ onSelect(opt.key);
679
+ close();
680
+ },
681
+ children: [
682
+ /* @__PURE__ */ jsx("div", { className: "option-icon", children: /* @__PURE__ */ jsx(Icon_default, { name: opt.iconName, size: 20 }) }),
683
+ /* @__PURE__ */ jsx(
684
+ "div",
685
+ {
686
+ className: `option-check ${active ? "" : "hidden"}`,
687
+ "aria-hidden": true,
688
+ children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx(
689
+ "path",
690
+ {
691
+ d: "M20 6L9 17l-5-5",
692
+ fill: "none",
693
+ stroke: "currentColor",
694
+ strokeWidth: "2",
695
+ strokeLinecap: "round",
696
+ strokeLinejoin: "round"
697
+ }
698
+ ) })
699
+ }
700
+ )
701
+ ]
702
+ },
703
+ opt.key
704
+ );
705
+ }) })
706
+ }
707
+ ) });
708
+ }
709
+ var LowPriority = 1;
710
+ function rgbToHex(rgb) {
711
+ if (!rgb) return rgb;
712
+ if (rgb.startsWith("#")) return rgb;
713
+ if (rgb.startsWith("rgba")) {
714
+ const match2 = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*([\d.]+)?\)/);
715
+ if (match2) {
716
+ const [, r, g, b, a] = match2;
717
+ if (a === "0") return "transparent";
718
+ return "#" + [r, g, b].map((x) => {
719
+ const hex = parseInt(x).toString(16);
720
+ return hex.length === 1 ? "0" + hex : hex;
721
+ }).join("");
722
+ }
723
+ }
724
+ const match = rgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
725
+ if (match) {
726
+ const [, r, g, b] = match;
727
+ return "#" + [r, g, b].map((x) => {
728
+ const hex = parseInt(x).toString(16);
729
+ return hex.length === 1 ? "0" + hex : hex;
730
+ }).join("");
731
+ }
732
+ return rgb;
733
+ }
734
+ function useOnClickListener() {
735
+ const [editor] = useLexicalComposerContext();
736
+ const [blockType, setBlockType] = useState("paragraph");
737
+ const [selectedEventTypes, setSelectedEventTypes] = useState({
738
+ [eventTypes.fontFamily]: "sans-serif",
739
+ [eventTypes.fontSize]: 16,
740
+ [eventTypes.align.base]: "left"
741
+ });
742
+ const [isLink, setIsLink] = useState(false);
743
+ const updateToolbar = useCallback(() => {
744
+ const selection = $getSelection();
745
+ const newState = {
746
+ // Set default values
747
+ [eventTypes.fontFamily]: "sans-serif",
748
+ [eventTypes.fontSize]: 16,
749
+ [eventTypes.align.base]: "left"
750
+ };
751
+ if ($isRangeSelection(selection)) {
752
+ const anchorNode = selection.anchor.getNode();
753
+ const element = anchorNode.getKey() === "root" ? anchorNode : anchorNode.getTopLevelElementOrThrow();
754
+ const elementKey = element.getKey();
755
+ const elementDOM = editor.getElementByKey(elementKey);
756
+ if (elementDOM !== null) {
757
+ if ($isListNode(element)) {
758
+ const parentList = $getNearestNodeOfType(anchorNode, ListNode);
759
+ const type = parentList ? parentList.getTag() : element.getTag();
760
+ setBlockType(type);
761
+ } else {
762
+ const type = element.getType();
763
+ setBlockType(type);
764
+ }
765
+ }
766
+ newState[eventTypes.bold] = selection.hasFormat("bold");
767
+ newState[eventTypes.italic] = selection.hasFormat("italic");
768
+ newState[eventTypes.underline] = selection.hasFormat("underline");
769
+ newState[eventTypes.strike] = selection.hasFormat("strikethrough");
770
+ newState[eventTypes.code] = selection.hasFormat("code");
771
+ const node = getSelectedNode2(selection);
772
+ const parent = node.getParent();
773
+ if ($isLinkNode(parent) || $isLinkNode(node)) {
774
+ newState[eventTypes.link] = true;
775
+ setIsLink(true);
776
+ } else {
777
+ newState[eventTypes.link] = false;
778
+ setIsLink(false);
779
+ }
780
+ const textNodeDOM = editor.getElementByKey(node.getKey());
781
+ const parentElement = editor.getElementByKey(parent.getKey());
782
+ const styleElement = textNodeDOM || parentElement || elementDOM;
783
+ if (styleElement) {
784
+ const computedStyle = window.getComputedStyle(styleElement);
785
+ const fontFamily = computedStyle.getPropertyValue("font-family");
786
+ if (fontFamily) {
787
+ let firstFont = fontFamily.split(",")[0].trim().replace(/['"]/g, "");
788
+ if (firstFont === "-apple-system" || firstFont === "BlinkMacSystemFont" || firstFont === "system-ui") {
789
+ firstFont = "sans-serif";
790
+ }
791
+ newState[eventTypes.fontFamily] = firstFont;
792
+ }
793
+ const fontSize = computedStyle.getPropertyValue("font-size");
794
+ if (fontSize) {
795
+ const fontSizeNum = parseInt(fontSize, 10);
796
+ newState[eventTypes.fontSize] = fontSizeNum || 16;
797
+ }
798
+ let color = null;
799
+ let backgroundColor = null;
800
+ if (styleElement instanceof HTMLElement && styleElement.style) {
801
+ color = styleElement.style.color || null;
802
+ backgroundColor = styleElement.style.backgroundColor || null;
803
+ }
804
+ if (!color) {
805
+ color = computedStyle.getPropertyValue("color");
806
+ }
807
+ if (!backgroundColor) {
808
+ backgroundColor = computedStyle.getPropertyValue("background-color");
809
+ }
810
+ console.log("\u{1F3A8} Color detection:", {
811
+ inlineColor: styleElement instanceof HTMLElement ? styleElement.style.color : "N/A",
812
+ inlineBg: styleElement instanceof HTMLElement ? styleElement.style.backgroundColor : "N/A",
813
+ computedColor: color,
814
+ computedBg: backgroundColor,
815
+ element: styleElement
816
+ });
817
+ const hexColor = color ? rgbToHex(color) : null;
818
+ const hexBgColor = backgroundColor && backgroundColor !== "rgba(0, 0, 0, 0)" && backgroundColor !== "transparent" ? rgbToHex(backgroundColor) : null;
819
+ if (hexColor || hexBgColor) {
820
+ newState[eventTypes.color.base] = {
821
+ text: hexColor || "#000000",
822
+ background: hexBgColor || "#ffffff"
823
+ };
824
+ }
825
+ let textAlign = computedStyle.getPropertyValue("text-align") || "left";
826
+ if (textAlign === "start") {
827
+ textAlign = "left";
828
+ }
829
+ newState[eventTypes.align.base] = textAlign;
830
+ }
831
+ setSelectedEventTypes(newState);
832
+ }
833
+ }, [editor]);
834
+ useEffect(() => {
835
+ return mergeRegister(
836
+ editor.registerUpdateListener(({ editorState }) => {
837
+ editorState.read(() => {
838
+ updateToolbar();
839
+ });
840
+ }),
841
+ editor.registerCommand(
842
+ SELECTION_CHANGE_COMMAND,
843
+ () => {
844
+ updateToolbar();
845
+ return false;
846
+ },
847
+ LowPriority
848
+ )
849
+ );
850
+ }, [editor, updateToolbar]);
851
+ function onChange(type, event) {
852
+ switch (type) {
853
+ case eventTypes.bold:
854
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
855
+ break;
856
+ case eventTypes.italic:
857
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
858
+ break;
859
+ case eventTypes.underline:
860
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "underline");
861
+ break;
862
+ case eventTypes.align.base:
863
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, event);
864
+ break;
865
+ case eventTypes.undo:
866
+ editor.dispatchCommand(UNDO_COMMAND, void 0);
867
+ break;
868
+ case eventTypes.redo:
869
+ editor.dispatchCommand(REDO_COMMAND, void 0);
870
+ break;
871
+ case eventTypes.listNumber:
872
+ formatNumberedList();
873
+ break;
874
+ case eventTypes.listBullet:
875
+ formatBulletList();
876
+ break;
877
+ case eventTypes.indent:
878
+ addIndent();
879
+ break;
880
+ case eventTypes.indentDecrease:
881
+ removeIndent();
882
+ break;
883
+ case eventTypes.color.base:
884
+ applyFontColor(event);
885
+ break;
886
+ case eventTypes.fontFamily:
887
+ applyFontFamily(event);
888
+ break;
889
+ case eventTypes.fontSize:
890
+ applyFontSize(event);
891
+ break;
892
+ case eventTypes.link:
893
+ insertLink();
894
+ break;
895
+ }
896
+ }
897
+ const addIndent = () => {
898
+ editor.dispatchCommand(INDENT_CONTENT_COMMAND, void 0);
899
+ };
900
+ const applyFontFamily = (fontFamily) => {
901
+ editor.update(() => {
902
+ const selection = $getSelection();
903
+ if ($isRangeSelection(selection)) {
904
+ $patchStyleText(selection, { "font-family": fontFamily });
905
+ }
906
+ });
907
+ };
908
+ const applyFontSize = (fontSize) => {
909
+ const selectedFontSize = OPTIONS.find((i) => i.key === fontSize)?.sizePx ?? 16;
910
+ editor.update(() => {
911
+ const selection = $getSelection();
912
+ if ($isRangeSelection(selection)) {
913
+ $patchStyleText(selection, { "font-size": `${selectedFontSize}px` });
914
+ }
915
+ });
916
+ };
917
+ const applyFontColor = (colorObj) => {
918
+ editor.update(() => {
919
+ const selection = $getSelection();
920
+ if ($isRangeSelection(selection)) {
921
+ $patchStyleText(selection, {
922
+ "background-color": colorObj.background,
923
+ color: colorObj.text
924
+ });
925
+ }
926
+ });
927
+ };
928
+ const insertLink = useCallback(() => {
929
+ if (!isLink) {
930
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, "https://");
931
+ } else {
932
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
933
+ }
934
+ }, [editor, isLink]);
935
+ const removeIndent = () => {
936
+ editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, void 0);
937
+ };
938
+ const formatBulletList = () => {
939
+ if (blockType !== "ul") {
940
+ editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, void 0);
941
+ } else {
942
+ editor.dispatchCommand(REMOVE_LIST_COMMAND, void 0);
943
+ }
944
+ };
945
+ const formatNumberedList = () => {
946
+ if (blockType !== "ol") {
947
+ editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, void 0);
948
+ } else {
949
+ editor.dispatchCommand(REMOVE_LIST_COMMAND, void 0);
950
+ }
951
+ };
952
+ function getSelectedNode2(selection) {
953
+ const anchor = selection.anchor;
954
+ const focus = selection.focus;
955
+ const anchorNode = selection.anchor.getNode();
956
+ const focusNode = selection.focus.getNode();
957
+ if (anchorNode === focusNode) {
958
+ return anchorNode;
959
+ }
960
+ const isBackward = selection.isBackward();
961
+ if (isBackward) {
962
+ return $isAtNodeEnd(focus) ? anchorNode : focusNode;
963
+ } else {
964
+ return $isAtNodeEnd(anchor) ? focusNode : anchorNode;
965
+ }
966
+ }
967
+ return { onChange, isLink, editor, selectedEventTypes, blockType };
968
+ }
969
+ var useOnClickListener_default = useOnClickListener;
970
+ function FloatingLinkEditor({ editor }) {
971
+ const editorRef = useRef(null);
972
+ const inputRef = useRef(null);
973
+ const mouseDownRef = useRef(false);
974
+ const [linkUrl, setLinkUrl] = useState("");
975
+ const [isEditMode, setEditMode] = useState(false);
976
+ const [lastSelection, setLastSelection] = useState(null);
977
+ const updateLinkEditor = useCallback(() => {
978
+ const nativeSelection = window.getSelection();
979
+ const selection = $getSelection();
980
+ if ($isRangeSelection(selection)) {
981
+ const node = getSelectedNode(selection);
982
+ const parent = node.getParent();
983
+ if ($isLinkNode(parent)) {
984
+ setLinkUrl(parent.getURL());
985
+ } else if ($isLinkNode(node)) {
986
+ setLinkUrl(node.getURL());
987
+ } else {
988
+ setLinkUrl("");
989
+ }
990
+ }
991
+ const editorElem = editorRef.current;
992
+ const activeElement = document.activeElement;
993
+ if (!editorElem) return;
994
+ const rootElement = editor.getRootElement();
995
+ if (selection && nativeSelection && !nativeSelection.isCollapsed && rootElement && rootElement.contains(nativeSelection.anchorNode)) {
996
+ const domRange = nativeSelection.getRangeAt(0);
997
+ let rect;
998
+ if (nativeSelection.anchorNode === rootElement) {
999
+ let inner = rootElement;
1000
+ while (inner.firstElementChild != null) inner = inner.firstElementChild;
1001
+ rect = inner.getBoundingClientRect();
1002
+ } else {
1003
+ rect = domRange.getBoundingClientRect();
1004
+ }
1005
+ if (!mouseDownRef.current) {
1006
+ positionEditorElement(editorElem, rect);
1007
+ }
1008
+ setLastSelection(selection);
1009
+ } else if (!activeElement || activeElement.className !== "link-input") {
1010
+ positionEditorElement(editorElem, null);
1011
+ setLastSelection(null);
1012
+ setEditMode(false);
1013
+ setLinkUrl("");
1014
+ }
1015
+ return true;
1016
+ }, [editor]);
1017
+ useEffect(() => {
1018
+ return mergeRegister(
1019
+ editor.registerUpdateListener(({ editorState }) => {
1020
+ editorState.read(() => {
1021
+ updateLinkEditor();
1022
+ });
1023
+ }),
1024
+ editor.registerCommand(
1025
+ SELECTION_CHANGE_COMMAND,
1026
+ () => {
1027
+ updateLinkEditor();
1028
+ return true;
1029
+ },
1030
+ 1
1031
+ )
1032
+ );
1033
+ }, [editor, updateLinkEditor]);
1034
+ useEffect(() => {
1035
+ editor.getEditorState().read(() => {
1036
+ updateLinkEditor();
1037
+ });
1038
+ }, [editor, updateLinkEditor]);
1039
+ useEffect(() => {
1040
+ if (isEditMode && inputRef.current) {
1041
+ inputRef.current.focus();
1042
+ }
1043
+ }, [isEditMode]);
1044
+ return /* @__PURE__ */ jsxs("div", { className: "floating-link-editor", ref: editorRef, children: [
1045
+ isEditMode ? /* @__PURE__ */ jsx(
1046
+ "input",
1047
+ {
1048
+ ref: inputRef,
1049
+ className: "link-input",
1050
+ value: linkUrl,
1051
+ onChange: (e) => setLinkUrl(e.target.value),
1052
+ onKeyDown: (e) => {
1053
+ if (e.key === "Enter") {
1054
+ e.preventDefault();
1055
+ if (lastSelection && linkUrl !== "") {
1056
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, linkUrl);
1057
+ }
1058
+ setEditMode(false);
1059
+ } else if (e.key === "Escape") {
1060
+ e.preventDefault();
1061
+ setEditMode(false);
1062
+ }
1063
+ },
1064
+ placeholder: "Enter link..."
1065
+ }
1066
+ ) : /* @__PURE__ */ jsx("div", { className: "link-display", children: /* @__PURE__ */ jsx("a", { href: linkUrl, target: "_blank", rel: "noopener noreferrer", children: linkUrl || "No link selected" }) }),
1067
+ /* @__PURE__ */ jsx(
1068
+ "button",
1069
+ {
1070
+ className: "link-button",
1071
+ onMouseDown: (e) => e.preventDefault(),
1072
+ onClick: () => {
1073
+ console.log("floating link editor", isEditMode);
1074
+ if (isEditMode) editor.dispatchCommand(TOGGLE_LINK_COMMAND, linkUrl);
1075
+ setEditMode((prev) => !prev);
1076
+ },
1077
+ children: /* @__PURE__ */ jsx(Icon_default, { name: isEditMode ? "Check" : "Edit" })
1078
+ }
1079
+ )
1080
+ ] });
1081
+ }
1082
+ function getSelectedNode(selection) {
1083
+ const anchorNode = selection.anchor.getNode();
1084
+ const focusNode = selection.focus.getNode();
1085
+ if (anchorNode === focusNode) return anchorNode;
1086
+ const isBackward = selection.isBackward();
1087
+ return isBackward ? $isAtNodeEnd(selection.focus) ? anchorNode : focusNode : $isAtNodeEnd(selection.anchor) ? focusNode : anchorNode;
1088
+ }
1089
+ function positionEditorElement(editor, rect) {
1090
+ if (!rect) {
1091
+ editor.style.opacity = "0";
1092
+ editor.style.top = "-1000px";
1093
+ editor.style.left = "-1000px";
1094
+ return;
1095
+ }
1096
+ const editorWidth = editor.offsetWidth;
1097
+ const editorHeight = editor.offsetHeight;
1098
+ const viewportWidth = window.innerWidth;
1099
+ const viewportHeight = window.innerHeight;
1100
+ let top = rect.top + rect.height + window.pageYOffset + 10;
1101
+ let left = rect.left + window.pageXOffset - editorWidth / 2 + rect.width / 2;
1102
+ if (left < 8) left = 8;
1103
+ if (left + editorWidth > viewportWidth - 8)
1104
+ left = viewportWidth - editorWidth - 8;
1105
+ if (top + editorHeight > viewportHeight - 8) {
1106
+ top = rect.top + window.pageYOffset - editorHeight - 10;
1107
+ }
1108
+ if (top < 8) top = 8;
1109
+ editor.style.opacity = "1";
1110
+ editor.style.top = `${top}px`;
1111
+ editor.style.left = `${left}px`;
1112
+ }
1113
+ var FloatingLinkEditor_default = FloatingLinkEditor;
1114
+ var FILE_UPLOAD_ERROR = {
1115
+ FILE_INVALID_TYPE: "file-invalid-type",
1116
+ FILE_TOO_LARGE: "file-too-large",
1117
+ TOO_MANY_FILES: "too-many-files",
1118
+ HEIC_CONVERSION_ERROR: "heic-conversion-error"
1119
+ };
1120
+ var MAX_NUMBER_OF_FILES_ALLOWED = 10;
1121
+ var MAX_SIZE_OF_FILE_ALLOWED_MB = 10;
1122
+ var getId = () => Math.random().toString(36).substring(2, 10) + Date.now().toString(36);
1123
+ var getMBs = (bytes) => {
1124
+ if (bytes < 1024) return { value: bytes.toString(), type: "bytes" };
1125
+ const kb = bytes / 1024;
1126
+ if (kb < 1024) return { value: kb.toFixed(1), type: "KB" };
1127
+ const mb = kb / 1024;
1128
+ if (mb < 1024) return { value: mb.toFixed(1), type: "MB" };
1129
+ const gb = mb / 1024;
1130
+ return { value: gb.toFixed(1), type: "GB" };
1131
+ };
1132
+ var useFileUpload = ({
1133
+ accept = {
1134
+ "image/*": [".png", ".gif", ".jpeg", ".jpg"],
1135
+ "application/pdf": [".pdf"]
1136
+ },
1137
+ maxSize = MAX_SIZE_OF_FILE_ALLOWED_MB * 1024 * 1024,
1138
+ maxFiles = MAX_NUMBER_OF_FILES_ALLOWED,
1139
+ multiple = true,
1140
+ isDisabled = false,
1141
+ replaceAfterUpload = false,
1142
+ files = [],
1143
+ handleFileChange = () => {
1144
+ }
1145
+ }) => {
1146
+ const [isFileDialogOpen, setIsFileDialogOpen] = useState(false);
1147
+ const [fileUploaded, setFileUploaded] = useState(files ?? []);
1148
+ const [rejectedFiles, setRejectedFile] = useState(
1149
+ []
1150
+ );
1151
+ const getErrorText = (errorCode) => {
1152
+ switch (errorCode) {
1153
+ case FILE_UPLOAD_ERROR.FILE_INVALID_TYPE:
1154
+ return "Invalid file type. Please upload a supported format.";
1155
+ case FILE_UPLOAD_ERROR.FILE_TOO_LARGE: {
1156
+ const { value, type } = getMBs(maxSize);
1157
+ return `File too large. Maximum allowed size is ${value} ${type}.`;
1158
+ }
1159
+ case FILE_UPLOAD_ERROR.TOO_MANY_FILES:
1160
+ return `Too many files selected. Maximum allowed: ${maxFiles}.`;
1161
+ case FILE_UPLOAD_ERROR.HEIC_CONVERSION_ERROR:
1162
+ return "Failed to convert HEIC image. Please upload a JPEG or PNG instead.";
1163
+ default:
1164
+ return "An unknown file error occurred.";
1165
+ }
1166
+ };
1167
+ useEffect(() => {
1168
+ handleFileChange(fileUploaded);
1169
+ }, [fileUploaded]);
1170
+ const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
1171
+ accept,
1172
+ maxSize,
1173
+ multiple,
1174
+ maxFiles,
1175
+ disabled: isDisabled,
1176
+ noClick: true,
1177
+ onFileDialogCancel: () => setIsFileDialogOpen(false),
1178
+ onFileDialogOpen: () => {
1179
+ if (!isDisabled) setIsFileDialogOpen(true);
1180
+ },
1181
+ onDrop: async (_acceptedFiles, fileRejections) => {
1182
+ const acceptedFiles = await Promise.all(
1183
+ _acceptedFiles.map(async (file) => {
1184
+ if (!file) return null;
1185
+ if (file.type === "image/heic") {
1186
+ try {
1187
+ const blob = await heic2any({ blob: file, toType: "image/jpeg" });
1188
+ const blobArray = Array.isArray(blob) ? blob[0] : blob;
1189
+ const convertedFile = new File(
1190
+ [blobArray],
1191
+ `${file.name.replace(/\.heic$/i, "")}.jpeg`,
1192
+ { type: "image/jpeg" }
1193
+ );
1194
+ return Object.assign(convertedFile, {
1195
+ uuid: getId(),
1196
+ preview: URL.createObjectURL(convertedFile)
1197
+ });
1198
+ } catch (err) {
1199
+ console.error("HEIC conversion error:", err);
1200
+ const msg = getErrorText(FILE_UPLOAD_ERROR.HEIC_CONVERSION_ERROR);
1201
+ setRejectedFile((prev) => [
1202
+ ...prev,
1203
+ {
1204
+ file,
1205
+ preview: URL.createObjectURL(file),
1206
+ readableErrors: [msg],
1207
+ errors: [
1208
+ {
1209
+ code: FILE_UPLOAD_ERROR.HEIC_CONVERSION_ERROR,
1210
+ message: msg
1211
+ }
1212
+ ]
1213
+ }
1214
+ ]);
1215
+ return null;
1216
+ }
1217
+ }
1218
+ return Object.assign(file, {
1219
+ uuid: getId(),
1220
+ preview: URL.createObjectURL(file)
1221
+ });
1222
+ })
1223
+ );
1224
+ const validFiles = acceptedFiles.filter(Boolean);
1225
+ if (!isDisabled) {
1226
+ let newFiles = replaceAfterUpload ? [] : [...fileUploaded];
1227
+ newFiles = [...newFiles, ...validFiles];
1228
+ const mappedRejections = fileRejections.map(
1229
+ (item) => {
1230
+ const readableErrors = item.errors.map(
1231
+ (err) => getErrorText(err.code)
1232
+ );
1233
+ return {
1234
+ file: item.file,
1235
+ errors: item.errors.map((err) => ({ code: err.code, message: err.message })),
1236
+ preview: URL.createObjectURL(item.file),
1237
+ readableErrors
1238
+ };
1239
+ }
1240
+ );
1241
+ setRejectedFile((prev) => [...prev, ...mappedRejections]);
1242
+ setFileUploaded(newFiles);
1243
+ return newFiles;
1244
+ }
1245
+ return fileUploaded;
1246
+ },
1247
+ validator: (item) => {
1248
+ const { name: fileName, type } = item;
1249
+ if (fileName) {
1250
+ const ext = fileName.split(".").pop()?.toLowerCase();
1251
+ if (accept && accept?.[type] && accept?.[type].length && !accept?.[type].includes(`.${ext}`)) {
1252
+ return {
1253
+ code: FILE_UPLOAD_ERROR.FILE_INVALID_TYPE,
1254
+ message: getErrorText(FILE_UPLOAD_ERROR.FILE_INVALID_TYPE)
1255
+ };
1256
+ }
1257
+ }
1258
+ return null;
1259
+ }
1260
+ });
1261
+ const removeFile = useCallback(
1262
+ (uuid) => {
1263
+ setFileUploaded((prev) => prev.filter((file) => file.uuid !== uuid));
1264
+ },
1265
+ [setFileUploaded]
1266
+ );
1267
+ const clearRejectedFiles = useCallback(() => {
1268
+ setRejectedFile([]);
1269
+ }, []);
1270
+ useEffect(() => {
1271
+ return () => {
1272
+ fileUploaded.forEach((f) => f.preview && URL.revokeObjectURL(f.preview));
1273
+ rejectedFiles.forEach((r) => r.preview && URL.revokeObjectURL(r.preview));
1274
+ };
1275
+ }, []);
1276
+ return {
1277
+ getRootProps,
1278
+ getInputProps,
1279
+ isDragActive,
1280
+ isFileDialogOpen,
1281
+ rejectedFiles,
1282
+ openFileDialog: open,
1283
+ removeFile,
1284
+ clearRejectedFiles
1285
+ };
1286
+ };
1287
+ var FileUploader = ({ handleFileChange }) => {
1288
+ const {
1289
+ getRootProps,
1290
+ getInputProps,
1291
+ openFileDialog
1292
+ } = useFileUpload({
1293
+ multiple: true,
1294
+ maxFiles: 5,
1295
+ maxSize: 5 * 1024 * 1024,
1296
+ // 5 MB
1297
+ handleFileChange: (files) => {
1298
+ handleFileChange(files);
1299
+ }
1300
+ });
1301
+ return /* @__PURE__ */ jsx("div", { className: "uploader-container", children: /* @__PURE__ */ jsxs("div", { ...getRootProps(), children: [
1302
+ /* @__PURE__ */ jsx("input", { ...getInputProps() }),
1303
+ /* @__PURE__ */ jsx("button", { onClick: openFileDialog, children: /* @__PURE__ */ jsx(Icon_default, { className: "upload-icon", name: "Attach" }) })
1304
+ ] }) });
1305
+ };
1306
+ var FileUploader_default = FileUploader;
1307
+ function FilePreview({ file, index, onRemove, onView }) {
1308
+ if (!file) return null;
1309
+ const name = file?.name ?? "unknown";
1310
+ const sizeBytes = file instanceof File ? file.size : "size" in file && file.size !== void 0 ? file.size : "bytes" in file && file.bytes !== void 0 ? file.bytes : null;
1311
+ const urlFromProp = ("url" in file ? file?.url : null) ?? null;
1312
+ const url = useMemo(() => {
1313
+ if (urlFromProp) return urlFromProp;
1314
+ if (typeof window !== "undefined" && file instanceof File) {
1315
+ try {
1316
+ return URL.createObjectURL(file);
1317
+ } catch (e) {
1318
+ return null;
1319
+ }
1320
+ }
1321
+ return null;
1322
+ }, [file, urlFromProp]);
1323
+ const formatSizeShort = (bytes) => {
1324
+ if (!bytes && bytes !== 0) return "";
1325
+ const kb = Math.round(bytes / 1024);
1326
+ if (kb < 1024) return `${kb}K`;
1327
+ const mb = Math.round(bytes / 1024 / 1024 * 10) / 10;
1328
+ return `${mb}M`;
1329
+ };
1330
+ const handleView = (e) => {
1331
+ e.preventDefault();
1332
+ if (onView) return onView(url ?? null);
1333
+ if (url) window.open(url, "_blank", "noopener");
1334
+ };
1335
+ const handleRemove = (index2) => {
1336
+ if (onRemove) onRemove(index2);
1337
+ };
1338
+ return /* @__PURE__ */ jsxs("div", { className: "fps-row", role: "group", "aria-label": `Attachment ${name}`, children: [
1339
+ /* @__PURE__ */ jsxs("div", { className: "fps-left", children: [
1340
+ /* @__PURE__ */ jsx(
1341
+ "a",
1342
+ {
1343
+ href: url ?? "#",
1344
+ className: "fps-filename",
1345
+ onClick: handleView,
1346
+ title: name,
1347
+ target: "_blank",
1348
+ rel: "noopener noreferrer",
1349
+ children: name
1350
+ }
1351
+ ),
1352
+ sizeBytes != null && /* @__PURE__ */ jsxs("span", { className: "fps-size", children: [
1353
+ "\xA0(",
1354
+ formatSizeShort(sizeBytes),
1355
+ ")"
1356
+ ] })
1357
+ ] }),
1358
+ /* @__PURE__ */ jsx(
1359
+ "button",
1360
+ {
1361
+ type: "button",
1362
+ className: "fps-close",
1363
+ "aria-label": `Remove ${name}`,
1364
+ onClick: () => handleRemove(index),
1365
+ children: "\xD7"
1366
+ }
1367
+ )
1368
+ ] });
1369
+ }
1370
+ var getToolbarComponent = (plugin, { onChange, state, setState, selectedEventTypes, blockType, setAttachments }) => {
1371
+ switch (plugin.name) {
1372
+ case eventTypes.undo:
1373
+ case eventTypes.redo:
1374
+ case eventTypes.bold:
1375
+ case eventTypes.italic:
1376
+ case eventTypes.underline:
1377
+ case eventTypes.indentDecrease:
1378
+ case eventTypes.indent:
1379
+ case eventTypes.link:
1380
+ return /* @__PURE__ */ jsx(
1381
+ "button",
1382
+ {
1383
+ className: `tool-bar-button ${selectedEventTypes?.[plugin.name] ? "active-btn-toolbar" : ""}`,
1384
+ onClick: () => {
1385
+ onChange(plugin.name, true);
1386
+ },
1387
+ children: /* @__PURE__ */ jsx(Icon_default, { className: "tool-bar-button-icon", name: plugin.icon })
1388
+ },
1389
+ `${plugin.name}-${plugin.icon}`
1390
+ );
1391
+ case eventTypes.listNumber:
1392
+ return /* @__PURE__ */ jsx(
1393
+ "button",
1394
+ {
1395
+ className: blockType === "ol" ? "active-btn-toolbar" : "",
1396
+ onClick: () => {
1397
+ onChange(plugin.name, true);
1398
+ },
1399
+ children: /* @__PURE__ */ jsx(Icon_default, { className: "tool-bar-button-icon", name: plugin.icon })
1400
+ },
1401
+ `${plugin.name}-${plugin.icon}`
1402
+ );
1403
+ case eventTypes.listBullet:
1404
+ return /* @__PURE__ */ jsx(
1405
+ "button",
1406
+ {
1407
+ className: blockType === "ul" ? "active-btn-toolbar" : "",
1408
+ onClick: () => {
1409
+ onChange(plugin.name, true);
1410
+ },
1411
+ children: /* @__PURE__ */ jsx(Icon_default, { className: "tool-bar-button-icon", name: plugin.icon })
1412
+ },
1413
+ `${plugin.name}-${plugin.icon}`
1414
+ );
1415
+ case eventTypes.attachFile:
1416
+ return /* @__PURE__ */ jsx(
1417
+ FileUploader_default,
1418
+ {
1419
+ value: state?.[plugin.name],
1420
+ handleFileChange: (e) => {
1421
+ console.log("\u{1F680} ~ getToolbarComponent ~ e:", e);
1422
+ setState((prev) => {
1423
+ return { ...prev, [plugin.name]: e };
1424
+ });
1425
+ setAttachments(e);
1426
+ }
1427
+ }
1428
+ );
1429
+ case eventTypes.fontFamily:
1430
+ return /* @__PURE__ */ jsx(
1431
+ FontSelect,
1432
+ {
1433
+ value: selectedEventTypes?.[plugin.name] || state?.[plugin.name],
1434
+ onChange: (e) => {
1435
+ onChange(plugin.name, e);
1436
+ }
1437
+ }
1438
+ );
1439
+ case eventTypes.fontSize:
1440
+ return /* @__PURE__ */ jsx(
1441
+ FontSizePicker,
1442
+ {
1443
+ value: selectedEventTypes?.[plugin.name] || state?.[plugin.name],
1444
+ onChange: (e) => {
1445
+ onChange(plugin.name, e);
1446
+ }
1447
+ }
1448
+ );
1449
+ case eventTypes.color.base:
1450
+ return /* @__PURE__ */ jsx(
1451
+ ColorPicker,
1452
+ {
1453
+ value: selectedEventTypes?.[plugin.name] || state?.[plugin.name],
1454
+ onChange: (e) => {
1455
+ onChange(plugin.name, e);
1456
+ }
1457
+ }
1458
+ );
1459
+ case eventTypes.align.base:
1460
+ return /* @__PURE__ */ jsx(
1461
+ AlignmentSelect,
1462
+ {
1463
+ value: selectedEventTypes?.[plugin.name] || state?.[plugin.name],
1464
+ onChange: (e) => {
1465
+ onChange(plugin.name, e);
1466
+ }
1467
+ }
1468
+ );
1469
+ }
1470
+ if (plugin.type === toolbarComponentType.divider)
1471
+ return /* @__PURE__ */ jsx("span", { className: "divider" });
1472
+ else return "-";
1473
+ };
1474
+ var getComponent = (plugin, {
1475
+ setToggle,
1476
+ toggle,
1477
+ onChange,
1478
+ state,
1479
+ setState,
1480
+ selectedEventTypes,
1481
+ blockType,
1482
+ setAttachments
1483
+ }) => {
1484
+ switch (plugin.type) {
1485
+ case toolbarComponentType.divider:
1486
+ return /* @__PURE__ */ jsx(
1487
+ "div",
1488
+ {
1489
+ className: "divider"
1490
+ },
1491
+ `divider-${plugin.type}-${plugin.icon}`
1492
+ );
1493
+ case toolbarComponentType.component:
1494
+ return getToolbarComponent(plugin, {
1495
+ onChange,
1496
+ state,
1497
+ setState,
1498
+ selectedEventTypes,
1499
+ blockType,
1500
+ setAttachments
1501
+ });
1502
+ case toolbarComponentType.styling:
1503
+ return /* @__PURE__ */ jsxs(
1504
+ "div",
1505
+ {
1506
+ className: "styling-toolbar",
1507
+ children: [
1508
+ toggle ? /* @__PURE__ */ jsx("div", { className: "styling-options", children: plugin.options?.length && Array.isArray(plugin.options) ? plugin.options?.map(
1509
+ (option) => getToolbarComponent(option, {
1510
+ onChange,
1511
+ state,
1512
+ setState,
1513
+ selectedEventTypes,
1514
+ blockType,
1515
+ setAttachments
1516
+ })
1517
+ ) : null }) : null,
1518
+ /* @__PURE__ */ jsx("button", { onClick: () => setToggle((prev) => !prev), children: /* @__PURE__ */ jsx(Icon_default, { className: "tool-bar-button-icon", name: plugin.icon }) })
1519
+ ]
1520
+ },
1521
+ `divider-${plugin.type}-${plugin.icon}`
1522
+ );
1523
+ }
1524
+ return "-";
1525
+ };
1526
+ function ToolBar({ rightChildren, leftChildren }) {
1527
+ const [toggle, setToggle] = useState(true);
1528
+ const [state, setState] = useState({});
1529
+ const { setAttachments } = useEmailContext();
1530
+ const { onChange, isLink, editor, selectedEventTypes, blockType } = useOnClickListener_default();
1531
+ console.log("\u{1F680} ~ ToolBar ~ selectedEventTypes:", selectedEventTypes);
1532
+ return /* @__PURE__ */ jsxs("div", { className: "toolbar-container", children: [
1533
+ state[eventTypes.attachFile]?.length ? /* @__PURE__ */ jsx("div", { className: "file-upload-container", children: state[eventTypes.attachFile]?.map((item, index) => /* @__PURE__ */ jsx(
1534
+ FilePreview,
1535
+ {
1536
+ file: item,
1537
+ index,
1538
+ onRemove: (index2) => {
1539
+ setState((prev) => {
1540
+ const updatedFiles = prev[eventTypes.attachFile].filter(
1541
+ (_file, i) => i !== index2
1542
+ );
1543
+ setAttachments(updatedFiles);
1544
+ return {
1545
+ ...prev,
1546
+ [eventTypes.attachFile]: updatedFiles
1547
+ };
1548
+ });
1549
+ }
1550
+ },
1551
+ index
1552
+ )) }) : null,
1553
+ /* @__PURE__ */ jsxs("div", { className: "toolbar-wrapper", children: [
1554
+ leftChildren,
1555
+ pluginList?.map(
1556
+ (plugin) => getComponent(plugin, {
1557
+ setToggle,
1558
+ state,
1559
+ setState,
1560
+ toggle,
1561
+ onChange,
1562
+ selectedEventTypes,
1563
+ blockType,
1564
+ setAttachments
1565
+ })
1566
+ ),
1567
+ rightChildren,
1568
+ isLink ? createPortal(/* @__PURE__ */ jsx(FloatingLinkEditor_default, { editor }), document.body) : null
1569
+ ] })
1570
+ ] });
1571
+ }
1572
+ var Toolbar_default = ToolBar;
1573
+
1574
+ // src/Themes/lexicalEditortheme.ts
1575
+ var lexicalEditorTheme = {
1576
+ ltr: "ltr",
1577
+ rtl: "rtl",
1578
+ placeholder: "editor-placeholder",
1579
+ paragraph: "editor-paragraph",
1580
+ quote: "editor-quote",
1581
+ heading: {
1582
+ h1: "editor-heading-h1",
1583
+ h2: "editor-heading-h2",
1584
+ h3: "editor-heading-h3",
1585
+ h4: "editor-heading-h4",
1586
+ h5: "editor-heading-h5"
1587
+ },
1588
+ list: {
1589
+ nested: {
1590
+ listitem: "editor-nested-listitem"
1591
+ },
1592
+ ol: "editor-list-ol",
1593
+ ul: "editor-list-ul",
1594
+ listitem: "editor-listitem"
1595
+ },
1596
+ image: "editor-image",
1597
+ link: "editor-link",
1598
+ text: {
1599
+ bold: "editor-text-bold",
1600
+ italic: "editor-text-italic",
1601
+ overflowed: "editor-text-overflowed",
1602
+ hashtag: "editor-text-hashtag",
1603
+ underline: "editor-text-underline",
1604
+ strikethrough: "editor-text-strikethrough",
1605
+ underlineStrikethrough: "editor-text-underlineStrikethrough",
1606
+ code: "editor-text-code"
1607
+ },
1608
+ code: "editor-code",
1609
+ codeHighlight: {
1610
+ atrule: "editor-tokenAttr",
1611
+ attr: "editor-tokenAttr",
1612
+ boolean: "editor-tokenProperty",
1613
+ builtin: "editor-tokenSelector",
1614
+ cdata: "editor-tokenComment",
1615
+ char: "editor-tokenSelector",
1616
+ class: "editor-tokenFunction",
1617
+ "class-name": "editor-tokenFunction",
1618
+ comment: "editor-tokenComment",
1619
+ constant: "editor-tokenProperty",
1620
+ deleted: "editor-tokenProperty",
1621
+ doctype: "editor-tokenComment",
1622
+ entity: "editor-tokenOperator",
1623
+ function: "editor-tokenFunction",
1624
+ important: "editor-tokenVariable",
1625
+ inserted: "editor-tokenSelector",
1626
+ keyword: "editor-tokenAttr",
1627
+ namespace: "editor-tokenVariable",
1628
+ number: "editor-tokenProperty",
1629
+ operator: "editor-tokenOperator",
1630
+ prolog: "editor-tokenComment",
1631
+ property: "editor-tokenProperty",
1632
+ punctuation: "editor-tokenPunctuation",
1633
+ regex: "editor-tokenVariable",
1634
+ selector: "editor-tokenSelector",
1635
+ string: "editor-tokenSelector",
1636
+ symbol: "editor-tokenProperty",
1637
+ tag: "editor-tokenProperty",
1638
+ url: "editor-tokenOperator",
1639
+ variable: "editor-tokenVariable"
1640
+ }
1641
+ };
1642
+ var lexicalEditortheme_default = lexicalEditorTheme;
1643
+ function SetInitialHTML({ initialHTML }) {
1644
+ const [editor] = useLexicalComposerContext();
1645
+ useEffect(() => {
1646
+ editor.update(() => {
1647
+ const parser = new DOMParser();
1648
+ const dom = parser.parseFromString(initialHTML, "text/html");
1649
+ const nodes = $generateNodesFromDOM(editor, dom);
1650
+ const root = $getRoot();
1651
+ root.clear();
1652
+ root.append(...nodes);
1653
+ });
1654
+ }, [editor, initialHTML]);
1655
+ return null;
1656
+ }
1657
+ var SetInitialHTML_default = SetInitialHTML;
1658
+ function OnChangePlugin({
1659
+ onChange
1660
+ }) {
1661
+ const [editor] = useLexicalComposerContext();
1662
+ useEffect(() => {
1663
+ return editor.registerUpdateListener(({ editorState }) => {
1664
+ editorState.read(() => {
1665
+ const html = $generateHtmlFromNodes(editor, null);
1666
+ onChange(html);
1667
+ });
1668
+ });
1669
+ }, [editor, onChange]);
1670
+ return null;
1671
+ }
1672
+ function onError(error) {
1673
+ console.error(error);
1674
+ }
1675
+ function EditorWrapper({
1676
+ placeholder = "Enter some text here",
1677
+ initialHTML = "",
1678
+ rightChildren,
1679
+ leftChildren,
1680
+ minHeight = "",
1681
+ onChange,
1682
+ editorChildren,
1683
+ isEditorVisible = true
1684
+ }) {
1685
+ const initialConfig = {
1686
+ namespace: "MyEditor",
1687
+ theme: lexicalEditortheme_default,
1688
+ nodes: [LinkNode, ListNode, ListItemNode, AutoLinkNode],
1689
+ onError
1690
+ };
1691
+ return /* @__PURE__ */ jsx("div", { className: "my-editor-wrapper", children: /* @__PURE__ */ jsxs(LexicalComposer, { initialConfig, children: [
1692
+ isEditorVisible ? /* @__PURE__ */ jsx(
1693
+ RichTextPlugin,
1694
+ {
1695
+ contentEditable: /* @__PURE__ */ jsx(
1696
+ ContentEditable,
1697
+ {
1698
+ style: { minHeight },
1699
+ className: "my-editor-content",
1700
+ "aria-placeholder": placeholder,
1701
+ placeholder: /* @__PURE__ */ jsx("div", { className: "my-editor-placeholder", children: placeholder })
1702
+ }
1703
+ ),
1704
+ ErrorBoundary: LexicalErrorBoundary
1705
+ }
1706
+ ) : editorChildren,
1707
+ /* @__PURE__ */ jsx(Toolbar_default, { rightChildren, leftChildren }),
1708
+ /* @__PURE__ */ jsx(HistoryPlugin, {}),
1709
+ /* @__PURE__ */ jsx(SetInitialHTML_default, { initialHTML }),
1710
+ /* @__PURE__ */ jsx(AutoFocusPlugin, {}),
1711
+ /* @__PURE__ */ jsx(ListPlugin, {}),
1712
+ /* @__PURE__ */ jsx(LinkPlugin, {}),
1713
+ onChange && /* @__PURE__ */ jsx(OnChangePlugin, { onChange })
1714
+ ] }) });
1715
+ }
1716
+ var EditorWrapper_default = EditorWrapper;
1717
+
1718
+ // src/utils/common.ts
1719
+ function isValidEmail(email) {
1720
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
1721
+ }
1722
+ function InputWithDropDown({ emails = [], setEmails, fetchOptions }) {
1723
+ const popupRef = useRef(null);
1724
+ const inputRef = useRef(null);
1725
+ const [currentEmail, setCurrentEmail] = useState("");
1726
+ const [popupOpen, setPopupOpen] = useState(false);
1727
+ const [selectedIndex, setSelectedIndex] = useState(-1);
1728
+ const [options, setOptions] = useState([]);
1729
+ const [loading, setLoading] = useState(false);
1730
+ const emailRefs = useRef([]);
1731
+ const optionRefs = useRef([]);
1732
+ useEffect(() => {
1733
+ emailRefs.current = emailRefs.current.slice(0, emails.length);
1734
+ }, [emails.length]);
1735
+ useEffect(() => {
1736
+ optionRefs.current = optionRefs.current.slice(0, options.length);
1737
+ }, [options.length]);
1738
+ useEffect(() => {
1739
+ if (isValidEmail(currentEmail)) {
1740
+ const loadOptions = async () => {
1741
+ setLoading(true);
1742
+ try {
1743
+ const data = await fetchOptions(currentEmail);
1744
+ setOptions(data);
1745
+ } catch (err) {
1746
+ console.error("Error fetching email options:", err);
1747
+ setOptions([]);
1748
+ } finally {
1749
+ setLoading(false);
1750
+ }
1751
+ };
1752
+ loadOptions();
1753
+ } else {
1754
+ setOptions([]);
1755
+ setLoading(false);
1756
+ }
1757
+ }, [currentEmail, fetchOptions]);
1758
+ useEffect(() => {
1759
+ if (!popupOpen) {
1760
+ setSelectedIndex(-1);
1761
+ }
1762
+ }, [popupOpen]);
1763
+ useEffect(() => {
1764
+ if (selectedIndex >= 0 && selectedIndex < optionRefs.current.length) {
1765
+ optionRefs.current[selectedIndex]?.scrollIntoView({
1766
+ block: "nearest",
1767
+ behavior: "smooth"
1768
+ });
1769
+ }
1770
+ }, [selectedIndex]);
1771
+ const focusInput = () => {
1772
+ inputRef.current?.focus();
1773
+ };
1774
+ const addEmail = (option) => {
1775
+ popupRef.current?.close();
1776
+ setCurrentEmail("");
1777
+ setEmails((prev) => [...prev, option]);
1778
+ setSelectedIndex(-1);
1779
+ requestAnimationFrame(() => inputRef.current?.focus());
1780
+ };
1781
+ const handleInputKeyDown = (e) => {
1782
+ if (popupOpen && isValidEmail(currentEmail) && options.length > 0) {
1783
+ if (e.key === "ArrowDown") {
1784
+ e.preventDefault();
1785
+ setSelectedIndex(
1786
+ (prev) => prev < options.length - 1 ? prev + 1 : prev
1787
+ );
1788
+ return;
1789
+ }
1790
+ if (e.key === "ArrowUp") {
1791
+ e.preventDefault();
1792
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : -1);
1793
+ return;
1794
+ }
1795
+ if (e.key === "Enter" && selectedIndex >= 0) {
1796
+ e.preventDefault();
1797
+ addEmail(options[selectedIndex]);
1798
+ return;
1799
+ }
1800
+ if (e.key === "Escape") {
1801
+ e.preventDefault();
1802
+ popupRef.current?.close();
1803
+ setSelectedIndex(-1);
1804
+ return;
1805
+ }
1806
+ }
1807
+ if (e.key === "Backspace" && currentEmail === "") {
1808
+ const lastIdx = emails.length - 1;
1809
+ const lastChip = emailRefs.current[lastIdx];
1810
+ if (lastChip) {
1811
+ lastChip.focus();
1812
+ e.preventDefault();
1813
+ }
1814
+ }
1815
+ };
1816
+ const removeEmailAt = (index) => {
1817
+ setEmails((prev) => {
1818
+ const next = [...prev];
1819
+ next.splice(index, 1);
1820
+ return next;
1821
+ });
1822
+ requestAnimationFrame(() => {
1823
+ const prevIdx = Math.min(Math.max(0, index - 1), emails.length - 2);
1824
+ const prevChip = emailRefs.current[prevIdx];
1825
+ if (prevChip) prevChip.focus();
1826
+ else focusInput();
1827
+ });
1828
+ };
1829
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1830
+ Popup,
1831
+ {
1832
+ ref: popupRef,
1833
+ trigger: /* @__PURE__ */ jsxs("div", { className: "container-receipts", children: [
1834
+ emails?.length ? /* @__PURE__ */ jsx("div", { className: "emails-container", children: emails.map((email, idx) => /* @__PURE__ */ jsxs(
1835
+ "div",
1836
+ {
1837
+ className: "emails",
1838
+ tabIndex: 0,
1839
+ ref: (el) => {
1840
+ emailRefs.current[idx] = el;
1841
+ },
1842
+ onKeyDown: (e) => {
1843
+ if (e.key === "Backspace") {
1844
+ e.preventDefault();
1845
+ removeEmailAt(idx);
1846
+ }
1847
+ if (e.key === "Enter") {
1848
+ e.preventDefault();
1849
+ removeEmailAt(idx);
1850
+ focusInput();
1851
+ }
1852
+ },
1853
+ role: "button",
1854
+ "aria-label": `Email ${email.email}`,
1855
+ children: [
1856
+ /* @__PURE__ */ jsx("span", { style: { marginRight: 8 }, children: email.email }),
1857
+ /* @__PURE__ */ jsx(
1858
+ "button",
1859
+ {
1860
+ className: "emails-close",
1861
+ onClick: (ev) => {
1862
+ ev.stopPropagation();
1863
+ removeEmailAt(idx);
1864
+ },
1865
+ "aria-label": `Remove ${email.email}`,
1866
+ children: /* @__PURE__ */ jsx(Icon_default, { name: "Close" })
1867
+ }
1868
+ )
1869
+ ]
1870
+ },
1871
+ email.email ?? idx
1872
+ )) }) : null,
1873
+ /* @__PURE__ */ jsx(
1874
+ "input",
1875
+ {
1876
+ ref: inputRef,
1877
+ type: "text",
1878
+ className: "input-header",
1879
+ value: currentEmail,
1880
+ autoFocus: true,
1881
+ onKeyDown: handleInputKeyDown,
1882
+ onChange: (e) => {
1883
+ const val = e.target.value;
1884
+ if (isValidEmail(val)) {
1885
+ popupRef.current?.open();
1886
+ }
1887
+ setCurrentEmail(val);
1888
+ }
1889
+ }
1890
+ )
1891
+ ] }),
1892
+ closeOnDocumentClick: true,
1893
+ repositionOnResize: true,
1894
+ position: "bottom left",
1895
+ className: "filter-popup",
1896
+ onOpen: () => {
1897
+ setPopupOpen(true);
1898
+ requestAnimationFrame(() => inputRef.current?.focus());
1899
+ },
1900
+ onClose: () => {
1901
+ setPopupOpen(false);
1902
+ },
1903
+ children: isValidEmail(currentEmail) ? /* @__PURE__ */ jsx("div", { className: "options-dropdown", children: loading ? (
1904
+ // Skeleton loader
1905
+ /* @__PURE__ */ jsx(Fragment, { children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs("div", { className: "option-dropdown skeleton-loader", children: [
1906
+ /* @__PURE__ */ jsx("div", { className: "skeleton-line skeleton-name" }),
1907
+ /* @__PURE__ */ jsx("div", { className: "skeleton-line skeleton-email" })
1908
+ ] }, i)) })
1909
+ ) : options.length > 0 ? options.map((opt, idx) => {
1910
+ return /* @__PURE__ */ jsxs(
1911
+ "button",
1912
+ {
1913
+ ref: (el) => {
1914
+ optionRefs.current[idx] = el;
1915
+ },
1916
+ className: `option-dropdown ${selectedIndex === idx ? "selected" : ""}`,
1917
+ onBlur: (e) => {
1918
+ e.stopPropagation();
1919
+ },
1920
+ onFocus: (e) => {
1921
+ e.stopPropagation();
1922
+ },
1923
+ onMouseEnter: () => setSelectedIndex(idx),
1924
+ onMouseLeave: () => setSelectedIndex(-1),
1925
+ onClick: (e) => {
1926
+ e.stopPropagation();
1927
+ addEmail(opt);
1928
+ },
1929
+ "aria-selected": selectedIndex === idx,
1930
+ children: [
1931
+ /* @__PURE__ */ jsx("h4", { children: opt.name }),
1932
+ opt.email
1933
+ ]
1934
+ },
1935
+ idx
1936
+ );
1937
+ }) : null }) : null
1938
+ }
1939
+ ) });
1940
+ }
1941
+ var InputWIthDropDown_default = InputWithDropDown;
1942
+ function InputForEmail({
1943
+ name,
1944
+ needCCAndBCC,
1945
+ setShowCC,
1946
+ setShowBCC,
1947
+ showBCC,
1948
+ showCC,
1949
+ emails,
1950
+ handleChange,
1951
+ fetchOptions
1952
+ }) {
1953
+ return /* @__PURE__ */ jsxs("div", { className: "container-receipts", children: [
1954
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: name }),
1955
+ /* @__PURE__ */ jsx(
1956
+ InputWIthDropDown_default,
1957
+ {
1958
+ emails,
1959
+ setEmails: handleChange,
1960
+ fetchOptions
1961
+ }
1962
+ ),
1963
+ needCCAndBCC && !showCC ? /* @__PURE__ */ jsx("button", { className: "btn", onClick: () => setShowCC?.((prev) => !prev), children: "CC" }) : null,
1964
+ needCCAndBCC && !showBCC ? /* @__PURE__ */ jsx("button", { className: "btn", onClick: () => setShowBCC?.((prev) => !prev), children: "BCC" }) : null
1965
+ ] });
1966
+ }
1967
+ var InputForEmail_default = InputForEmail;
1968
+ function ReceiptsHeading({ fetchEmailOptions }) {
1969
+ const [open, setOpen] = useState(false);
1970
+ const wrapperRef = useRef(null);
1971
+ const { emails, setEmails, showCC, setShowCC, showBCC, setShowBCC } = useEmailContext();
1972
+ useEffect(() => {
1973
+ if (open) {
1974
+ setShowCC(emails.cc.length > 0);
1975
+ setShowBCC(emails.bcc.length > 0);
1976
+ }
1977
+ }, [open, emails.cc.length, emails.bcc.length]);
1978
+ useEffect(() => {
1979
+ const wrapper = wrapperRef.current;
1980
+ if (!wrapper) return;
1981
+ const handleFocusIn = () => {
1982
+ setOpen(true);
1983
+ };
1984
+ const handleFocusOut = (e) => {
1985
+ console.log("\u{1F680} ~ handleFocusOut ~ e:", e);
1986
+ const next = e.relatedTarget;
1987
+ if (next && next.classList && next.classList.contains("option-dropdown") || next && wrapper.contains(next))
1988
+ return;
1989
+ console.log("why this ", next?.classList);
1990
+ setOpen(false);
1991
+ };
1992
+ wrapper.addEventListener("focusin", handleFocusIn);
1993
+ wrapper.addEventListener("focusout", handleFocusOut);
1994
+ return () => {
1995
+ wrapper.removeEventListener("focusin", handleFocusIn);
1996
+ wrapper.removeEventListener("focusout", handleFocusOut);
1997
+ };
1998
+ }, []);
1999
+ const getDisplayText = () => {
2000
+ if (emails.to.length === 0 && emails.cc.length === 0 && emails.bcc.length === 0) {
2001
+ return "Recipients";
2002
+ }
2003
+ const parts = [];
2004
+ if (emails.to.length > 0) {
2005
+ parts.push(emails.to.map((e) => e.email).join(", "));
2006
+ }
2007
+ if (emails.cc.length > 0) {
2008
+ parts.push(emails.cc.map((e) => e.email).join(", "));
2009
+ }
2010
+ if (emails.bcc.length > 0) {
2011
+ parts.push("bcc: " + emails.bcc.map((e) => e.email).join(", "));
2012
+ }
2013
+ return parts.join(", ");
2014
+ };
2015
+ return /* @__PURE__ */ jsx("div", { ref: wrapperRef, tabIndex: -1, className: "relative", children: !open ? /* @__PURE__ */ jsx(
2016
+ "input",
2017
+ {
2018
+ type: "text",
2019
+ placeholder: "Recipients",
2020
+ className: "input-header",
2021
+ value: getDisplayText(),
2022
+ readOnly: true
2023
+ }
2024
+ ) : /* @__PURE__ */ jsxs("div", { children: [
2025
+ /* @__PURE__ */ jsx(
2026
+ InputForEmail_default,
2027
+ {
2028
+ name: "To",
2029
+ needCCAndBCC: true,
2030
+ setShowCC,
2031
+ setShowBCC,
2032
+ showBCC,
2033
+ showCC,
2034
+ emails: emails.to,
2035
+ handleChange: (value) => {
2036
+ setEmails((prev) => ({
2037
+ ...prev,
2038
+ to: typeof value === "function" ? value(prev.to) : value
2039
+ }));
2040
+ },
2041
+ fetchOptions: fetchEmailOptions
2042
+ }
2043
+ ),
2044
+ showCC ? /* @__PURE__ */ jsx(
2045
+ InputForEmail_default,
2046
+ {
2047
+ name: "CC",
2048
+ needCCAndBCC: false,
2049
+ setShowCC,
2050
+ setShowBCC,
2051
+ showBCC,
2052
+ showCC,
2053
+ emails: emails.cc,
2054
+ handleChange: (value) => {
2055
+ setEmails((prev) => ({
2056
+ ...prev,
2057
+ cc: typeof value === "function" ? value(prev.cc) : value
2058
+ }));
2059
+ },
2060
+ fetchOptions: fetchEmailOptions
2061
+ }
2062
+ ) : null,
2063
+ showBCC ? /* @__PURE__ */ jsx(
2064
+ InputForEmail_default,
2065
+ {
2066
+ name: "BCC",
2067
+ needCCAndBCC: false,
2068
+ setShowCC,
2069
+ setShowBCC,
2070
+ showBCC,
2071
+ showCC,
2072
+ emails: emails.bcc,
2073
+ handleChange: (value) => {
2074
+ setEmails((prev) => ({
2075
+ ...prev,
2076
+ bcc: typeof value === "function" ? value(prev.bcc) : value
2077
+ }));
2078
+ },
2079
+ fetchOptions: fetchEmailOptions
2080
+ }
2081
+ ) : null
2082
+ ] }) });
2083
+ }
2084
+ var ReceiptsHeading_default = ReceiptsHeading;
2085
+ function GmailHeading({
2086
+ fetchEmailOptions
2087
+ }) {
2088
+ const { subject, setSubject, isReply } = useEmailContext();
2089
+ return /* @__PURE__ */ jsxs("div", { className: "gmail-header", children: [
2090
+ /* @__PURE__ */ jsx(ReceiptsHeading_default, { fetchEmailOptions }),
2091
+ /* @__PURE__ */ jsx(
2092
+ "input",
2093
+ {
2094
+ type: "text",
2095
+ placeholder: "Subject",
2096
+ className: "input-header",
2097
+ value: isReply && !subject.startsWith("Re: ") ? `Re: ${subject}` : subject,
2098
+ onChange: (e) => setSubject(e.target.value)
2099
+ }
2100
+ )
2101
+ ] });
2102
+ }
2103
+ var GmailHeading_default = GmailHeading;
2104
+ function GmailWrapperContent({
2105
+ initialData,
2106
+ isReply,
2107
+ fetchEmailOptions,
2108
+ handleChange,
2109
+ leftChildren,
2110
+ rightChildren,
2111
+ editorChildren,
2112
+ isEditorVisible = true
2113
+ }) {
2114
+ const {
2115
+ emails,
2116
+ subject,
2117
+ attachments,
2118
+ setEmails,
2119
+ setSubject,
2120
+ setAttachments,
2121
+ setIsReply
2122
+ } = useEmailContext();
2123
+ const [bodyHTML, setBodyHTML] = useState(initialData?.body || "");
2124
+ const [emailData, setEmailData] = useState({
2125
+ to: initialData?.to || [],
2126
+ cc: initialData?.cc || [],
2127
+ bcc: initialData?.bcc || [],
2128
+ subject: initialData?.subject || "",
2129
+ body: initialData?.body || "",
2130
+ attachments: initialData?.attachments || [],
2131
+ isReply: isReply || false
2132
+ });
2133
+ useEffect(() => {
2134
+ if (initialData) {
2135
+ if (initialData.to || initialData.cc || initialData.bcc) {
2136
+ setEmails({
2137
+ to: initialData.to || [],
2138
+ cc: initialData.cc || [],
2139
+ bcc: initialData.bcc || []
2140
+ });
2141
+ }
2142
+ if (initialData.subject) {
2143
+ setSubject(initialData.subject);
2144
+ }
2145
+ if (initialData.attachments) {
2146
+ setAttachments(initialData.attachments);
2147
+ }
2148
+ if (initialData.body) {
2149
+ setBodyHTML(initialData.body);
2150
+ }
2151
+ }
2152
+ if (isReply !== void 0) {
2153
+ setIsReply(isReply);
2154
+ }
2155
+ }, []);
2156
+ const handleEditorChange = (html) => {
2157
+ setBodyHTML(html);
2158
+ };
2159
+ useEffect(() => {
2160
+ setEmailData((prev) => ({
2161
+ ...prev,
2162
+ to: emails.to,
2163
+ cc: emails.cc,
2164
+ bcc: emails.bcc
2165
+ }));
2166
+ }, [emails]);
2167
+ useEffect(() => {
2168
+ setEmailData((prev) => ({
2169
+ ...prev,
2170
+ subject
2171
+ }));
2172
+ }, [subject]);
2173
+ useEffect(() => {
2174
+ setEmailData((prev) => ({
2175
+ ...prev,
2176
+ body: bodyHTML
2177
+ }));
2178
+ }, [bodyHTML]);
2179
+ useEffect(() => {
2180
+ setEmailData((prev) => ({
2181
+ ...prev,
2182
+ attachments
2183
+ }));
2184
+ }, [attachments]);
2185
+ useEffect(() => {
2186
+ setEmailData((prev) => ({
2187
+ ...prev,
2188
+ isReply
2189
+ }));
2190
+ }, [isReply]);
2191
+ useEffect(() => {
2192
+ handleChange(emailData);
2193
+ }, [emailData, handleChange]);
2194
+ return /* @__PURE__ */ jsxs("div", { className: "gmail-wrapper", children: [
2195
+ leftChildren,
2196
+ /* @__PURE__ */ jsx(GmailHeading_default, { fetchEmailOptions }),
2197
+ /* @__PURE__ */ jsx(
2198
+ EditorWrapper_default,
2199
+ {
2200
+ initialHTML: initialData?.body,
2201
+ onChange: handleEditorChange,
2202
+ editorChildren,
2203
+ isEditorVisible
2204
+ }
2205
+ ),
2206
+ rightChildren
2207
+ ] });
2208
+ }
2209
+ var GmailWrapperContent_default = GmailWrapperContent;
2210
+ function GmailWrapper({
2211
+ fetchEmailOptions,
2212
+ handleChange,
2213
+ initialData,
2214
+ leftChildren,
2215
+ rightChildren,
2216
+ isReply
2217
+ }) {
2218
+ return /* @__PURE__ */ jsx(EmailProvider, { children: /* @__PURE__ */ jsx(
2219
+ GmailWrapperContent_default,
2220
+ {
2221
+ fetchEmailOptions,
2222
+ handleChange,
2223
+ initialData,
2224
+ isReply,
2225
+ leftChildren,
2226
+ rightChildren
2227
+ }
2228
+ ) });
2229
+ }
2230
+ var GmailWrapper_default = GmailWrapper;
2231
+ function GmailInbox({
2232
+ fetchEmailOptions,
2233
+ handleChange,
2234
+ initialData,
2235
+ initialTheme = "dark",
2236
+ onThemeChange,
2237
+ leftChildren,
2238
+ rightChildren
2239
+ }) {
2240
+ return /* @__PURE__ */ jsx(ThemeProvider, { initialTheme, onThemeChange, children: /* @__PURE__ */ jsx(
2241
+ GmailWrapper_default,
2242
+ {
2243
+ fetchEmailOptions,
2244
+ handleChange,
2245
+ initialData,
2246
+ leftChildren,
2247
+ rightChildren
2248
+ }
2249
+ ) });
2250
+ }
2251
+ var GmailInbox_default = GmailInbox;
2252
+
2253
+ export { GmailInbox_default as GmailInbox, useTheme };
2254
+ //# sourceMappingURL=index.mjs.map
2255
+ //# sourceMappingURL=index.mjs.map