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