@react-email/editor 0.0.0-experimental.22 → 0.0.0-experimental.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/columns-CUxUEHje.mjs +497 -0
  2. package/dist/columns-CUxUEHje.mjs.map +1 -0
  3. package/dist/columns-ZSaLdkg9.cjs +630 -0
  4. package/dist/core/index.cjs +8 -0
  5. package/dist/core/index.d.cts +2 -0
  6. package/dist/core/index.d.mts +2 -0
  7. package/dist/core/index.mjs +4 -0
  8. package/dist/core-C5_RDJBI.mjs +1982 -0
  9. package/dist/core-C5_RDJBI.mjs.map +1 -0
  10. package/dist/core-Rxnpk8B_.cjs +2239 -0
  11. package/dist/extensions/index.cjs +47 -0
  12. package/dist/extensions/index.d.cts +394 -0
  13. package/dist/extensions/index.d.cts.map +1 -0
  14. package/dist/extensions/index.d.mts +394 -0
  15. package/dist/extensions/index.d.mts.map +1 -0
  16. package/dist/extensions/index.mjs +4 -0
  17. package/dist/index-CfslA7KT.d.cts +130 -0
  18. package/dist/index-CfslA7KT.d.cts.map +1 -0
  19. package/dist/index-hbHRR7oB.d.mts +130 -0
  20. package/dist/index-hbHRR7oB.d.mts.map +1 -0
  21. package/dist/set-text-alignment-Bx3bPteH.cjs +24 -0
  22. package/dist/set-text-alignment-DZvgnbvz.mjs +19 -0
  23. package/dist/set-text-alignment-DZvgnbvz.mjs.map +1 -0
  24. package/dist/ui/index.cjs +1646 -0
  25. package/dist/ui/index.d.cts +668 -0
  26. package/dist/ui/index.d.cts.map +1 -0
  27. package/dist/ui/index.d.mts +668 -0
  28. package/dist/ui/index.d.mts.map +1 -0
  29. package/dist/ui/index.mjs +1584 -0
  30. package/dist/ui/index.mjs.map +1 -0
  31. package/dist/utils/index.cjs +3 -0
  32. package/dist/utils/index.d.cts +7 -0
  33. package/dist/utils/index.d.cts.map +1 -0
  34. package/dist/utils/index.d.mts +7 -0
  35. package/dist/utils/index.d.mts.map +1 -0
  36. package/dist/utils/index.mjs +3 -0
  37. package/package.json +39 -11
  38. package/dist/index.cjs +0 -4228
  39. package/dist/index.d.cts +0 -1175
  40. package/dist/index.d.cts.map +0 -1
  41. package/dist/index.d.mts +0 -1175
  42. package/dist/index.d.mts.map +0 -1
  43. package/dist/index.mjs +0 -4072
  44. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,2239 @@
1
+ const require_columns = require('./columns-ZSaLdkg9.cjs');
2
+ let _react_email_components = require("@react-email/components");
3
+ _react_email_components = require_columns.__toESM(_react_email_components);
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ let _tiptap_core = require("@tiptap/core");
6
+ let _tiptap_extensions = require("@tiptap/extensions");
7
+ let _tiptap_react = require("@tiptap/react");
8
+ let react = require("react");
9
+ react = require_columns.__toESM(react);
10
+ let _tiptap_starter_kit = require("@tiptap/starter-kit");
11
+ _tiptap_starter_kit = require_columns.__toESM(_tiptap_starter_kit);
12
+ let _tiptap_extension_blockquote = require("@tiptap/extension-blockquote");
13
+ _tiptap_extension_blockquote = require_columns.__toESM(_tiptap_extension_blockquote);
14
+ let _tiptap_extension_bold = require("@tiptap/extension-bold");
15
+ _tiptap_extension_bold = require_columns.__toESM(_tiptap_extension_bold);
16
+ let _tiptap_extension_bullet_list = require("@tiptap/extension-bullet-list");
17
+ _tiptap_extension_bullet_list = require_columns.__toESM(_tiptap_extension_bullet_list);
18
+ let _tiptap_extension_code = require("@tiptap/extension-code");
19
+ _tiptap_extension_code = require_columns.__toESM(_tiptap_extension_code);
20
+ let _tiptap_extension_code_block = require("@tiptap/extension-code-block");
21
+ _tiptap_extension_code_block = require_columns.__toESM(_tiptap_extension_code_block);
22
+ let _tiptap_pm_state = require("@tiptap/pm/state");
23
+ let _tiptap_pm_view = require("@tiptap/pm/view");
24
+ let hast_util_from_html = require("hast-util-from-html");
25
+ let prismjs = require("prismjs");
26
+ prismjs = require_columns.__toESM(prismjs);
27
+ let _tiptap_extension_horizontal_rule = require("@tiptap/extension-horizontal-rule");
28
+ _tiptap_extension_horizontal_rule = require_columns.__toESM(_tiptap_extension_horizontal_rule);
29
+ let _tiptap_extension_hard_break = require("@tiptap/extension-hard-break");
30
+ _tiptap_extension_hard_break = require_columns.__toESM(_tiptap_extension_hard_break);
31
+ let _tiptap_extension_heading = require("@tiptap/extension-heading");
32
+ let _tiptap_extension_italic = require("@tiptap/extension-italic");
33
+ _tiptap_extension_italic = require_columns.__toESM(_tiptap_extension_italic);
34
+ let _tiptap_extension_link = require("@tiptap/extension-link");
35
+ _tiptap_extension_link = require_columns.__toESM(_tiptap_extension_link);
36
+ let _tiptap_extension_list_item = require("@tiptap/extension-list-item");
37
+ _tiptap_extension_list_item = require_columns.__toESM(_tiptap_extension_list_item);
38
+ let _tiptap_extension_ordered_list = require("@tiptap/extension-ordered-list");
39
+ _tiptap_extension_ordered_list = require_columns.__toESM(_tiptap_extension_ordered_list);
40
+ let _tiptap_extension_paragraph = require("@tiptap/extension-paragraph");
41
+ _tiptap_extension_paragraph = require_columns.__toESM(_tiptap_extension_paragraph);
42
+ let _tiptap_extension_placeholder = require("@tiptap/extension-placeholder");
43
+ _tiptap_extension_placeholder = require_columns.__toESM(_tiptap_extension_placeholder);
44
+ let _tiptap_extension_strike = require("@tiptap/extension-strike");
45
+ _tiptap_extension_strike = require_columns.__toESM(_tiptap_extension_strike);
46
+ let _tiptap_extension_superscript = require("@tiptap/extension-superscript");
47
+ _tiptap_extension_superscript = require_columns.__toESM(_tiptap_extension_superscript);
48
+ let _tiptap_extension_text = require("@tiptap/extension-text");
49
+ let _tiptap_extension_underline = require("@tiptap/extension-underline");
50
+ _tiptap_extension_underline = require_columns.__toESM(_tiptap_extension_underline);
51
+ let _tiptap_html = require("@tiptap/html");
52
+
53
+ //#region src/core/is-document-visually-empty.ts
54
+ function isDocumentVisuallyEmpty(doc) {
55
+ let nonGlobalNodeCount = 0;
56
+ let firstNonGlobalNode = null;
57
+ for (let index = 0; index < doc.childCount; index += 1) {
58
+ const node = doc.child(index);
59
+ if (node.type.name === "globalContent") continue;
60
+ nonGlobalNodeCount += 1;
61
+ if (firstNonGlobalNode === null) firstNonGlobalNode = {
62
+ type: node.type,
63
+ textContent: node.textContent,
64
+ childCount: node.content.childCount
65
+ };
66
+ }
67
+ if (nonGlobalNodeCount === 0) return true;
68
+ if (nonGlobalNodeCount !== 1) return false;
69
+ return firstNonGlobalNode?.type.name === "paragraph" && firstNonGlobalNode.textContent.trim().length === 0 && firstNonGlobalNode.childCount === 0;
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/core/serializer/default-base-template.tsx
74
+ function DefaultBaseTemplate({ children, previewText }) {
75
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_email_components.Html, { children: [
76
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_email_components.Head, { children: [
77
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
78
+ content: "width=device-width",
79
+ name: "viewport"
80
+ }),
81
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
82
+ content: "IE=edge",
83
+ httpEquiv: "X-UA-Compatible"
84
+ }),
85
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", { name: "x-apple-disable-message-reformatting" }),
86
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
87
+ content: "telephone=no,address=no,email=no,date=no,url=no",
88
+ name: "format-detection"
89
+ })
90
+ ] }),
91
+ previewText && previewText !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Preview, { children: previewText }),
92
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Body, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
93
+ width: "100%",
94
+ align: "center",
95
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
96
+ style: { width: "100%" },
97
+ children
98
+ })
99
+ }) })
100
+ ] });
101
+ }
102
+
103
+ //#endregion
104
+ //#region src/core/serializer/email-mark.ts
105
+ var EmailMark = class EmailMark extends _tiptap_core.Mark {
106
+ constructor(config) {
107
+ super(config);
108
+ }
109
+ /**
110
+ * Create a new Mark instance
111
+ * @param config - Mark configuration object or a function that returns a configuration object
112
+ */
113
+ static create(config) {
114
+ return new EmailMark(typeof config === "function" ? config() : config);
115
+ }
116
+ static from(mark, renderToReactEmail) {
117
+ const customMark = EmailMark.create({});
118
+ Object.assign(customMark, { ...mark });
119
+ customMark.config = {
120
+ ...mark.config,
121
+ renderToReactEmail
122
+ };
123
+ return customMark;
124
+ }
125
+ configure(options) {
126
+ return super.configure(options);
127
+ }
128
+ extend(extendedConfig) {
129
+ const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
130
+ return super.extend(resolvedConfig);
131
+ }
132
+ };
133
+
134
+ //#endregion
135
+ //#region src/core/serializer/compose-react-email.tsx
136
+ const NODES_WITH_INCREMENTED_CHILD_DEPTH = new Set(["bulletList", "orderedList"]);
137
+ const composeReactEmail = async ({ editor, preview }) => {
138
+ const data = editor.getJSON();
139
+ const extensions = editor.extensionManager.extensions;
140
+ const serializerPlugin = extensions.map((ext) => ext.options?.serializerPlugin).filter((p) => Boolean(p)).at(-1);
141
+ const emailNodeComponentRegistry = Object.fromEntries(extensions.filter((ext) => ext instanceof require_columns.EmailNode).map((extension) => [extension.name, extension.config.renderToReactEmail]));
142
+ const emailMarkComponentRegistry = Object.fromEntries(extensions.filter((ext) => ext instanceof EmailMark).map((extension) => [extension.name, extension.config.renderToReactEmail]));
143
+ function renderMark(mark, node, children, depth) {
144
+ const markStyle = serializerPlugin?.getNodeStyles({
145
+ type: mark.type,
146
+ attrs: mark.attrs ?? {}
147
+ }, depth, editor) ?? {};
148
+ const markRenderer = emailMarkComponentRegistry[mark.type];
149
+ if (markRenderer) return markRenderer({
150
+ mark,
151
+ node,
152
+ style: markStyle,
153
+ children
154
+ });
155
+ return children;
156
+ }
157
+ function parseContent(content, depth = 0) {
158
+ if (!content) return;
159
+ return content.map((node, index) => {
160
+ const style = serializerPlugin?.getNodeStyles(node, depth, editor) ?? {};
161
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
162
+ if (node.type && emailNodeComponentRegistry[node.type]) {
163
+ const Component = emailNodeComponentRegistry[node.type];
164
+ const childDepth = NODES_WITH_INCREMENTED_CHILD_DEPTH.has(node.type) ? depth + 1 : depth;
165
+ let children = node.text ? node.text : parseContent(node.content, childDepth);
166
+ if (node.marks) for (const mark of node.marks) children = renderMark(mark, node, children, depth);
167
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
168
+ node: node.type === "table" && inlineStyles.width && !node.attrs?.width ? {
169
+ ...node,
170
+ attrs: {
171
+ ...node.attrs,
172
+ width: inlineStyles.width
173
+ }
174
+ } : node,
175
+ style,
176
+ children
177
+ }, index);
178
+ }
179
+ return null;
180
+ });
181
+ }
182
+ const unformattedHtml = await (0, _react_email_components.render)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(serializerPlugin?.BaseTemplate ?? DefaultBaseTemplate, {
183
+ previewText: preview,
184
+ editor,
185
+ children: parseContent(data.content)
186
+ }));
187
+ const [prettyHtml, text] = await Promise.all([(0, _react_email_components.pretty)(unformattedHtml), (0, _react_email_components.toPlainText)(unformattedHtml)]);
188
+ return {
189
+ html: prettyHtml,
190
+ text
191
+ };
192
+ };
193
+
194
+ //#endregion
195
+ //#region src/extensions/alignment-attribute.tsx
196
+ const AlignmentAttribute = _tiptap_core.Extension.create({
197
+ name: "alignmentAttribute",
198
+ addOptions() {
199
+ return {
200
+ types: [],
201
+ alignments: [
202
+ "left",
203
+ "center",
204
+ "right",
205
+ "justify"
206
+ ]
207
+ };
208
+ },
209
+ addGlobalAttributes() {
210
+ return [{
211
+ types: this.options.types,
212
+ attributes: { alignment: {
213
+ parseHTML: (element) => {
214
+ const explicitAlign = element.getAttribute("align") || element.getAttribute("alignment") || element.style.textAlign;
215
+ if (explicitAlign && this.options.alignments.includes(explicitAlign)) return explicitAlign;
216
+ return null;
217
+ },
218
+ renderHTML: (attributes) => {
219
+ if (attributes.alignment === "left") return {};
220
+ return { alignment: attributes.alignment };
221
+ }
222
+ } }
223
+ }];
224
+ },
225
+ addCommands() {
226
+ return { setAlignment: (alignment) => ({ commands }) => {
227
+ if (!this.options.alignments.includes(alignment)) return false;
228
+ return this.options.types.every((type) => commands.updateAttributes(type, { alignment }));
229
+ } };
230
+ },
231
+ addKeyboardShortcuts() {
232
+ return {
233
+ Enter: () => {
234
+ const { from } = this.editor.state.selection;
235
+ const currentAlignment = this.editor.state.doc.nodeAt(from)?.attrs?.alignment;
236
+ if (currentAlignment) requestAnimationFrame(() => {
237
+ this.editor.commands.setAlignment(currentAlignment);
238
+ });
239
+ return false;
240
+ },
241
+ "Mod-Shift-l": () => this.editor.commands.setAlignment("left"),
242
+ "Mod-Shift-e": () => this.editor.commands.setAlignment("center"),
243
+ "Mod-Shift-r": () => this.editor.commands.setAlignment("right"),
244
+ "Mod-Shift-j": () => this.editor.commands.setAlignment("justify")
245
+ };
246
+ }
247
+ });
248
+
249
+ //#endregion
250
+ //#region src/utils/get-text-alignment.ts
251
+ function getTextAlignment(alignment) {
252
+ switch (alignment) {
253
+ case "left": return { textAlign: "left" };
254
+ case "center": return { textAlign: "center" };
255
+ case "right": return { textAlign: "right" };
256
+ default: return {};
257
+ }
258
+ }
259
+
260
+ //#endregion
261
+ //#region src/extensions/blockquote.tsx
262
+ const Blockquote = require_columns.EmailNode.from(_tiptap_extension_blockquote.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("blockquote", {
263
+ className: node.attrs?.class || void 0,
264
+ style: {
265
+ ...style,
266
+ ...require_columns.inlineCssToJs(node.attrs?.style),
267
+ ...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
268
+ },
269
+ children
270
+ }));
271
+
272
+ //#endregion
273
+ //#region src/extensions/body.tsx
274
+ const Body = require_columns.EmailNode.create({
275
+ name: "body",
276
+ group: "block",
277
+ content: "block+",
278
+ defining: true,
279
+ isolating: true,
280
+ addAttributes() {
281
+ return { ...require_columns.createStandardAttributes([...require_columns.COMMON_HTML_ATTRIBUTES, ...require_columns.LAYOUT_ATTRIBUTES]) };
282
+ },
283
+ parseHTML() {
284
+ return [{
285
+ tag: "body",
286
+ getAttrs: (node) => {
287
+ if (typeof node === "string") return false;
288
+ const element = node;
289
+ const attrs = {};
290
+ Array.from(element.attributes).forEach((attr) => {
291
+ attrs[attr.name] = attr.value;
292
+ });
293
+ return attrs;
294
+ }
295
+ }];
296
+ },
297
+ renderHTML({ HTMLAttributes }) {
298
+ return [
299
+ "div",
300
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
301
+ 0
302
+ ];
303
+ },
304
+ renderToReactEmail({ children, node, style }) {
305
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
306
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
307
+ className: node.attrs?.class || void 0,
308
+ style: {
309
+ ...style,
310
+ ...inlineStyles
311
+ },
312
+ children
313
+ });
314
+ }
315
+ });
316
+
317
+ //#endregion
318
+ //#region src/extensions/bold.tsx
319
+ const BoldWithoutFontWeightInference = _tiptap_extension_bold.default.extend({ parseHTML() {
320
+ return [
321
+ { tag: "strong" },
322
+ {
323
+ tag: "b",
324
+ getAttrs: (node) => node.style.fontWeight !== "normal" && null
325
+ },
326
+ {
327
+ style: "font-weight=400",
328
+ clearMark: (mark) => mark.type.name === this.name
329
+ }
330
+ ];
331
+ } });
332
+ const Bold = EmailMark.from(BoldWithoutFontWeightInference, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
333
+ style,
334
+ children
335
+ }));
336
+
337
+ //#endregion
338
+ //#region src/extensions/bullet-list.tsx
339
+ const BulletList = require_columns.EmailNode.from(_tiptap_extension_bullet_list.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
340
+ className: node.attrs?.class || void 0,
341
+ style: {
342
+ ...style,
343
+ ...require_columns.inlineCssToJs(node.attrs?.style)
344
+ },
345
+ children
346
+ }));
347
+
348
+ //#endregion
349
+ //#region src/extensions/button.tsx
350
+ const Button = require_columns.EmailNode.create({
351
+ name: "button",
352
+ group: "block",
353
+ content: "inline*",
354
+ defining: true,
355
+ draggable: true,
356
+ marks: "bold",
357
+ addAttributes() {
358
+ return {
359
+ class: { default: "button" },
360
+ href: { default: "#" },
361
+ alignment: { default: "left" }
362
+ };
363
+ },
364
+ parseHTML() {
365
+ return [{
366
+ tag: "a[data-id=\"react-email-button\"]",
367
+ getAttrs: (node) => {
368
+ if (typeof node === "string") return false;
369
+ const element = node;
370
+ const attrs = {};
371
+ Array.from(element.attributes).forEach((attr) => {
372
+ attrs[attr.name] = attr.value;
373
+ });
374
+ return attrs;
375
+ }
376
+ }];
377
+ },
378
+ renderHTML({ HTMLAttributes }) {
379
+ return [
380
+ "div",
381
+ (0, _tiptap_core.mergeAttributes)({ class: `align-${HTMLAttributes?.alignment}` }),
382
+ [
383
+ "a",
384
+ (0, _tiptap_core.mergeAttributes)({
385
+ class: `node-button ${HTMLAttributes?.class}`,
386
+ style: HTMLAttributes?.style,
387
+ "data-id": "react-email-button",
388
+ "data-href": HTMLAttributes?.href
389
+ }),
390
+ 0
391
+ ]
392
+ ];
393
+ },
394
+ addCommands() {
395
+ return {
396
+ updateButton: (attributes) => ({ commands }) => {
397
+ return commands.updateAttributes("button", attributes);
398
+ },
399
+ setButton: () => ({ commands }) => {
400
+ return commands.insertContent({
401
+ type: "button",
402
+ content: [{
403
+ type: "text",
404
+ text: "Button"
405
+ }]
406
+ });
407
+ }
408
+ };
409
+ },
410
+ renderToReactEmail({ children, node, style }) {
411
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
412
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Row, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Column, {
413
+ align: node.attrs?.align || node.attrs?.alignment,
414
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Button, {
415
+ className: node.attrs?.class || void 0,
416
+ href: node.attrs?.href,
417
+ style: {
418
+ ...style,
419
+ ...inlineStyles
420
+ },
421
+ children
422
+ })
423
+ }) });
424
+ }
425
+ });
426
+
427
+ //#endregion
428
+ //#region src/extensions/class-attribute.tsx
429
+ const ClassAttribute = _tiptap_core.Extension.create({
430
+ name: "classAttribute",
431
+ addOptions() {
432
+ return {
433
+ types: [],
434
+ class: []
435
+ };
436
+ },
437
+ addGlobalAttributes() {
438
+ return [{
439
+ types: this.options.types,
440
+ attributes: { class: {
441
+ default: "",
442
+ parseHTML: (element) => element.className || "",
443
+ renderHTML: (attributes) => {
444
+ return attributes.class ? { class: attributes.class } : {};
445
+ }
446
+ } }
447
+ }];
448
+ },
449
+ addCommands() {
450
+ return {
451
+ unsetClass: () => ({ commands }) => {
452
+ return this.options.types.every((type) => commands.resetAttributes(type, "class"));
453
+ },
454
+ setClass: (classList) => ({ commands }) => {
455
+ return this.options.types.every((type) => commands.updateAttributes(type, { class: classList }));
456
+ }
457
+ };
458
+ },
459
+ addKeyboardShortcuts() {
460
+ return { Enter: ({ editor }) => {
461
+ requestAnimationFrame(() => {
462
+ editor.commands.resetAttributes("paragraph", "class");
463
+ });
464
+ return false;
465
+ } };
466
+ }
467
+ });
468
+
469
+ //#endregion
470
+ //#region src/extensions/code.tsx
471
+ const Code = EmailMark.from(_tiptap_extension_code.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
472
+ style: {
473
+ ...style,
474
+ ...require_columns.inlineCssToJs(node.attrs?.style)
475
+ },
476
+ children
477
+ }));
478
+
479
+ //#endregion
480
+ //#region src/utils/prism-utils.ts
481
+ const publicURL = "/styles/prism";
482
+ function loadPrismTheme(theme) {
483
+ const link = document.createElement("link");
484
+ link.rel = "stylesheet";
485
+ link.href = `${publicURL}/prism-${theme}.css`;
486
+ link.setAttribute("data-prism-theme", "");
487
+ document.head.appendChild(link);
488
+ }
489
+ function removePrismTheme() {
490
+ const existingTheme = document.querySelectorAll("link[rel=\"stylesheet\"][data-prism-theme]");
491
+ if (existingTheme.length > 0) existingTheme.forEach((cssLinkTag) => {
492
+ cssLinkTag.remove();
493
+ });
494
+ }
495
+ function hasPrismThemeLoaded(theme) {
496
+ return !!document.querySelector(`link[rel="stylesheet"][data-prism-theme][href="${publicURL}/prism-${theme}.css"]`);
497
+ }
498
+
499
+ //#endregion
500
+ //#region src/extensions/prism-plugin.ts
501
+ const PRISM_LANGUAGE_LOADED_META = "prismLanguageLoaded";
502
+ function parseNodes(nodes, className = []) {
503
+ return nodes.flatMap((node) => {
504
+ const classes = [...className, ...node.properties ? node.properties.className : []];
505
+ if (node.children) return parseNodes(node.children, classes);
506
+ return {
507
+ text: node.value ?? "",
508
+ classes
509
+ };
510
+ });
511
+ }
512
+ function getHighlightNodes(html) {
513
+ return (0, hast_util_from_html.fromHtml)(html, { fragment: true }).children;
514
+ }
515
+ function registeredLang(aliasOrLanguage) {
516
+ const allSupportLang = Object.keys(prismjs.default.languages).filter((id) => typeof prismjs.default.languages[id] === "object");
517
+ return Boolean(allSupportLang.find((x) => x === aliasOrLanguage));
518
+ }
519
+ function getDecorations({ doc, name, defaultLanguage, defaultTheme, loadingLanguages, onLanguageLoaded }) {
520
+ const decorations = [];
521
+ (0, _tiptap_core.findChildren)(doc, (node) => node.type.name === name).forEach((block) => {
522
+ let from = block.pos + 1;
523
+ const language = block.node.attrs.language || defaultLanguage;
524
+ const theme = block.node.attrs.theme || defaultTheme;
525
+ let html = "";
526
+ try {
527
+ if (!registeredLang(language) && !loadingLanguages.has(language)) {
528
+ loadingLanguages.add(language);
529
+ import(`prismjs/components/prism-${language}`).then(() => {
530
+ loadingLanguages.delete(language);
531
+ onLanguageLoaded(language);
532
+ }).catch(() => {
533
+ loadingLanguages.delete(language);
534
+ });
535
+ }
536
+ if (!hasPrismThemeLoaded(theme)) loadPrismTheme(theme);
537
+ html = prismjs.default.highlight(block.node.textContent, prismjs.default.languages[language], language);
538
+ } catch {
539
+ html = prismjs.default.highlight(block.node.textContent, prismjs.default.languages.javascript, "js");
540
+ }
541
+ parseNodes(getHighlightNodes(html)).forEach((node) => {
542
+ const to = from + node.text.length;
543
+ if (node.classes.length) {
544
+ const decoration = _tiptap_pm_view.Decoration.inline(from, to, { class: node.classes.join(" ") });
545
+ decorations.push(decoration);
546
+ }
547
+ from = to;
548
+ });
549
+ });
550
+ return _tiptap_pm_view.DecorationSet.create(doc, decorations);
551
+ }
552
+ function PrismPlugin({ name, defaultLanguage, defaultTheme }) {
553
+ if (!defaultLanguage) throw Error("You must specify the defaultLanguage parameter");
554
+ const loadingLanguages = /* @__PURE__ */ new Set();
555
+ let pluginView = null;
556
+ const onLanguageLoaded = (language) => {
557
+ if (pluginView) pluginView.dispatch(pluginView.state.tr.setMeta(PRISM_LANGUAGE_LOADED_META, language));
558
+ };
559
+ const prismjsPlugin = new _tiptap_pm_state.Plugin({
560
+ key: new _tiptap_pm_state.PluginKey("prism"),
561
+ view(view) {
562
+ pluginView = view;
563
+ return { destroy() {
564
+ pluginView = null;
565
+ } };
566
+ },
567
+ state: {
568
+ init: (_, { doc }) => {
569
+ return getDecorations({
570
+ doc,
571
+ name,
572
+ defaultLanguage,
573
+ defaultTheme,
574
+ loadingLanguages,
575
+ onLanguageLoaded
576
+ });
577
+ },
578
+ apply: (transaction, decorationSet, oldState, newState) => {
579
+ const oldNodeName = oldState.selection.$head.parent.type.name;
580
+ const newNodeName = newState.selection.$head.parent.type.name;
581
+ const oldNodes = (0, _tiptap_core.findChildren)(oldState.doc, (node) => node.type.name === name);
582
+ const newNodes = (0, _tiptap_core.findChildren)(newState.doc, (node) => node.type.name === name);
583
+ if (transaction.getMeta(PRISM_LANGUAGE_LOADED_META) || transaction.docChanged && ([oldNodeName, newNodeName].includes(name) || newNodes.length !== oldNodes.length || transaction.steps.some((step) => {
584
+ const rangeStep = step;
585
+ return rangeStep.from !== void 0 && rangeStep.to !== void 0 && oldNodes.some((node) => {
586
+ return node.pos >= rangeStep.from && node.pos + node.node.nodeSize <= rangeStep.to;
587
+ });
588
+ }))) return getDecorations({
589
+ doc: transaction.doc,
590
+ name,
591
+ defaultLanguage,
592
+ defaultTheme,
593
+ loadingLanguages,
594
+ onLanguageLoaded
595
+ });
596
+ return decorationSet.map(transaction.mapping, transaction.doc);
597
+ }
598
+ },
599
+ props: { decorations(state) {
600
+ return prismjsPlugin.getState(state);
601
+ } },
602
+ destroy() {
603
+ pluginView = null;
604
+ removePrismTheme();
605
+ }
606
+ });
607
+ return prismjsPlugin;
608
+ }
609
+
610
+ //#endregion
611
+ //#region src/extensions/code-block.tsx
612
+ const CodeBlockPrism = require_columns.EmailNode.from(_tiptap_extension_code_block.default.extend({
613
+ addOptions() {
614
+ return {
615
+ languageClassPrefix: "language-",
616
+ exitOnTripleEnter: false,
617
+ exitOnArrowDown: false,
618
+ enableTabIndentation: true,
619
+ tabSize: 2,
620
+ defaultLanguage: "javascript",
621
+ defaultTheme: "default",
622
+ HTMLAttributes: {}
623
+ };
624
+ },
625
+ addAttributes() {
626
+ return {
627
+ ...this.parent?.(),
628
+ language: {
629
+ default: this.options.defaultLanguage,
630
+ parseHTML: (element) => {
631
+ if (!element) return null;
632
+ const { languageClassPrefix } = this.options;
633
+ if (!languageClassPrefix) return null;
634
+ const language = [...element.firstElementChild?.classList || []].filter((className) => className.startsWith(languageClassPrefix || "")).map((className) => className.replace(languageClassPrefix, ""))[0];
635
+ if (!language) return null;
636
+ return language;
637
+ },
638
+ rendered: false
639
+ },
640
+ theme: {
641
+ default: this.options.defaultTheme,
642
+ rendered: false
643
+ }
644
+ };
645
+ },
646
+ renderHTML({ node, HTMLAttributes }) {
647
+ return [
648
+ "pre",
649
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, { class: node.attrs.language ? `${this.options.languageClassPrefix}${node.attrs.language}` : null }, { "data-theme": node.attrs.theme }),
650
+ [
651
+ "code",
652
+ { class: node.attrs.language ? `${this.options.languageClassPrefix}${node.attrs.language} node-codeTag` : "node-codeTag" },
653
+ 0
654
+ ]
655
+ ];
656
+ },
657
+ addKeyboardShortcuts() {
658
+ return {
659
+ ...this.parent?.(),
660
+ "Mod-a": ({ editor }) => {
661
+ const { state } = editor;
662
+ const { selection } = state;
663
+ const { $from } = selection;
664
+ for (let depth = $from.depth; depth >= 1; depth--) if ($from.node(depth).type.name === this.name) {
665
+ const blockStart = $from.start(depth);
666
+ const blockEnd = $from.end(depth);
667
+ if (selection.from === blockStart && selection.to === blockEnd) return false;
668
+ const tr = state.tr.setSelection(_tiptap_pm_state.TextSelection.create(state.doc, blockStart, blockEnd));
669
+ editor.view.dispatch(tr);
670
+ return true;
671
+ }
672
+ return false;
673
+ }
674
+ };
675
+ },
676
+ addProseMirrorPlugins() {
677
+ return [...this.parent?.() || [], PrismPlugin({
678
+ name: this.name,
679
+ defaultLanguage: this.options.defaultLanguage,
680
+ defaultTheme: this.options.defaultTheme
681
+ })];
682
+ }
683
+ }), ({ node, style }) => {
684
+ const language = node.attrs?.language ? `${node.attrs.language}` : "javascript";
685
+ const userTheme = _react_email_components[node.attrs?.theme];
686
+ const theme = userTheme ? {
687
+ ...userTheme,
688
+ base: {
689
+ ...userTheme.base,
690
+ borderRadius: "0.125rem",
691
+ padding: "0.75rem 1rem"
692
+ }
693
+ } : { base: {
694
+ color: "#1e293b",
695
+ background: "#f1f5f9",
696
+ lineHeight: "1.5",
697
+ fontFamily: "\"Fira Code\", \"Fira Mono\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace",
698
+ padding: "0.75rem 1rem",
699
+ borderRadius: "0.125rem"
700
+ } };
701
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.CodeBlock, {
702
+ code: node.content?.[0]?.text ?? "",
703
+ language,
704
+ theme,
705
+ style: {
706
+ width: "auto",
707
+ ...style
708
+ }
709
+ });
710
+ });
711
+
712
+ //#endregion
713
+ //#region src/extensions/div.tsx
714
+ const Div = require_columns.EmailNode.create({
715
+ name: "div",
716
+ group: "block",
717
+ content: "block+",
718
+ defining: true,
719
+ isolating: true,
720
+ parseHTML() {
721
+ return [{
722
+ tag: "div:not([data-type])",
723
+ getAttrs: (node) => {
724
+ if (typeof node === "string") return false;
725
+ const element = node;
726
+ const attrs = {};
727
+ Array.from(element.attributes).forEach((attr) => {
728
+ attrs[attr.name] = attr.value;
729
+ });
730
+ return attrs;
731
+ }
732
+ }];
733
+ },
734
+ renderHTML({ HTMLAttributes }) {
735
+ return [
736
+ "div",
737
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
738
+ 0
739
+ ];
740
+ },
741
+ addAttributes() {
742
+ return { ...require_columns.createStandardAttributes([...require_columns.COMMON_HTML_ATTRIBUTES, ...require_columns.LAYOUT_ATTRIBUTES]) };
743
+ },
744
+ renderToReactEmail({ children, node, style }) {
745
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
746
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
747
+ className: node.attrs?.class || void 0,
748
+ style: {
749
+ ...style,
750
+ ...inlineStyles
751
+ },
752
+ children
753
+ });
754
+ }
755
+ });
756
+
757
+ //#endregion
758
+ //#region src/extensions/divider.tsx
759
+ const Divider = require_columns.EmailNode.from(_tiptap_extension_horizontal_rule.default.extend({
760
+ addAttributes() {
761
+ return { class: { default: "divider" } };
762
+ },
763
+ addInputRules() {
764
+ return [new _tiptap_core.InputRule({
765
+ find: /^(?:---|—-|___\s|\*\*\*\s)$/,
766
+ handler: ({ state, range }) => {
767
+ const attributes = {};
768
+ const { tr } = state;
769
+ const start = range.from;
770
+ const end = range.to;
771
+ tr.insert(start - 1, this.type.create(attributes)).delete(tr.mapping.map(start), tr.mapping.map(end));
772
+ }
773
+ })];
774
+ },
775
+ addNodeView() {
776
+ return (0, _tiptap_react.ReactNodeViewRenderer)((props) => {
777
+ const node = props.node;
778
+ const { class: className, ...rest } = node.attrs;
779
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react.NodeViewWrapper, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Hr, {
780
+ ...rest,
781
+ className: "node-hr",
782
+ style: require_columns.inlineCssToJs(node.attrs.style)
783
+ }) });
784
+ });
785
+ }
786
+ }), ({ node, style }) => {
787
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Hr, {
788
+ className: node.attrs?.class || void 0,
789
+ style: {
790
+ ...style,
791
+ ...require_columns.inlineCssToJs(node.attrs?.style)
792
+ }
793
+ });
794
+ });
795
+
796
+ //#endregion
797
+ //#region src/extensions/global-content.ts
798
+ const GLOBAL_CONTENT_NODE_TYPE = "globalContent";
799
+ let cachedGlobalPosition = null;
800
+ function findGlobalContentPositions(doc) {
801
+ const positions = [];
802
+ doc.descendants((node, position) => {
803
+ if (node.type.name === GLOBAL_CONTENT_NODE_TYPE) positions.push(position);
804
+ });
805
+ return positions;
806
+ }
807
+ function getCachedGlobalContentPosition(doc) {
808
+ if (cachedGlobalPosition != null) try {
809
+ if (doc.nodeAt(cachedGlobalPosition)?.type.name === GLOBAL_CONTENT_NODE_TYPE) return cachedGlobalPosition;
810
+ } catch {
811
+ cachedGlobalPosition = null;
812
+ }
813
+ cachedGlobalPosition = findGlobalContentPositions(doc)[0] ?? null;
814
+ return cachedGlobalPosition;
815
+ }
816
+ function getGlobalContent(key, editor) {
817
+ const position = getCachedGlobalContentPosition(editor.state.doc);
818
+ if (cachedGlobalPosition == null) return null;
819
+ return editor.state.doc.nodeAt(position)?.attrs.data[key] ?? null;
820
+ }
821
+ const GlobalContent = _tiptap_core.Node.create({
822
+ name: GLOBAL_CONTENT_NODE_TYPE,
823
+ addOptions() {
824
+ return {
825
+ key: GLOBAL_CONTENT_NODE_TYPE,
826
+ data: {}
827
+ };
828
+ },
829
+ group: "block",
830
+ selectable: false,
831
+ draggable: false,
832
+ atom: true,
833
+ addAttributes() {
834
+ return { data: { default: this.options.data } };
835
+ },
836
+ parseHTML() {
837
+ return [{ tag: `div[data-type="${this.name}"]` }];
838
+ },
839
+ renderHTML({ HTMLAttributes }) {
840
+ return ["div", (0, _tiptap_core.mergeAttributes)(HTMLAttributes, {
841
+ "data-type": this.name,
842
+ style: "width: 100%; height: 1px; visibility: hidden;"
843
+ })];
844
+ },
845
+ addCommands() {
846
+ return { setGlobalContent: (key, value) => ({ tr, dispatch }) => {
847
+ const ensureGlobalPosition = () => {
848
+ const positions = findGlobalContentPositions(tr.doc);
849
+ for (let i = positions.length - 1; i > 0; i--) tr.delete(positions[i], positions[i] + 1);
850
+ const pos = positions[0] ?? -1;
851
+ if (pos >= 0) cachedGlobalPosition = pos;
852
+ else {
853
+ cachedGlobalPosition = 0;
854
+ tr.insert(0, this.type.create());
855
+ }
856
+ };
857
+ if (dispatch) {
858
+ ensureGlobalPosition();
859
+ if (cachedGlobalPosition == null) return false;
860
+ tr.setNodeAttribute(cachedGlobalPosition, "data", {
861
+ ...tr.doc.nodeAt(cachedGlobalPosition)?.attrs.data,
862
+ [key]: value
863
+ });
864
+ }
865
+ return true;
866
+ } };
867
+ }
868
+ });
869
+
870
+ //#endregion
871
+ //#region src/extensions/hard-break.tsx
872
+ const HardBreak = require_columns.EmailNode.from(_tiptap_extension_hard_break.default, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}));
873
+
874
+ //#endregion
875
+ //#region src/extensions/heading.tsx
876
+ const Heading = require_columns.EmailNode.from(_tiptap_extension_heading.Heading.extend({ addNodeView() {
877
+ return (0, _tiptap_react.ReactNodeViewRenderer)(({ node }) => {
878
+ const level = node.attrs.level ?? 1;
879
+ const { class: className, ...rest } = node.attrs;
880
+ const attrs = {
881
+ ...rest,
882
+ className: `node-h${level} ${className}`,
883
+ style: require_columns.inlineCssToJs(node.attrs.style)
884
+ };
885
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react.NodeViewWrapper, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Heading, {
886
+ as: `h${level}`,
887
+ ...attrs,
888
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react.NodeViewContent, {})
889
+ }) });
890
+ });
891
+ } }), ({ children, node, style }) => {
892
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Heading, {
893
+ as: `h${node.attrs?.level ?? 1}`,
894
+ className: node.attrs?.class || void 0,
895
+ style: {
896
+ ...style,
897
+ ...require_columns.inlineCssToJs(node.attrs?.style),
898
+ ...getTextAlignment(node.attrs?.align ?? node.attrs?.alignment)
899
+ },
900
+ children
901
+ });
902
+ });
903
+
904
+ //#endregion
905
+ //#region src/extensions/italic.tsx
906
+ const Italic = EmailMark.from(_tiptap_extension_italic.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("em", {
907
+ style,
908
+ children
909
+ }));
910
+
911
+ //#endregion
912
+ //#region src/extensions/preserved-style.tsx
913
+ const PreservedStyle = EmailMark.create({
914
+ name: "preservedStyle",
915
+ addAttributes() {
916
+ return { style: {
917
+ default: null,
918
+ parseHTML: (element) => element.getAttribute("style"),
919
+ renderHTML: (attributes) => {
920
+ if (!attributes.style) return {};
921
+ return { style: attributes.style };
922
+ }
923
+ } };
924
+ },
925
+ parseHTML() {
926
+ return [{
927
+ tag: "span[style]",
928
+ getAttrs: (element) => {
929
+ if (typeof element === "string") return false;
930
+ const style = element.getAttribute("style");
931
+ if (style && hasPreservableStyles(style)) return { style };
932
+ return false;
933
+ }
934
+ }];
935
+ },
936
+ renderHTML({ HTMLAttributes }) {
937
+ return [
938
+ "span",
939
+ (0, _tiptap_core.mergeAttributes)(HTMLAttributes),
940
+ 0
941
+ ];
942
+ },
943
+ renderToReactEmail({ children, mark }) {
944
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
945
+ style: mark.attrs?.style ? require_columns.inlineCssToJs(mark.attrs.style) : void 0,
946
+ children
947
+ });
948
+ }
949
+ });
950
+ const LINK_INDICATOR_STYLES = [
951
+ "color",
952
+ "text-decoration",
953
+ "text-decoration-line",
954
+ "text-decoration-color",
955
+ "text-decoration-style"
956
+ ];
957
+ function parseStyleString(styleString) {
958
+ const temp = document.createElement("div");
959
+ temp.style.cssText = styleString;
960
+ return temp.style;
961
+ }
962
+ function hasBackground(style) {
963
+ const bgColor = style.backgroundColor;
964
+ const bg = style.background;
965
+ if (bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") return true;
966
+ if (bg && bg !== "transparent" && bg !== "none" && bg !== "rgba(0, 0, 0, 0)") return true;
967
+ return false;
968
+ }
969
+ function hasPreservableStyles(styleString) {
970
+ return processStylesForUnlink(styleString) !== null;
971
+ }
972
+ /**
973
+ * Processes styles when unlinking:
974
+ * - Has background (button-like): preserve all styles
975
+ * - No background: strip link-indicator styles (color, text-decoration), keep the rest
976
+ */
977
+ function processStylesForUnlink(styleString) {
978
+ if (!styleString) return null;
979
+ const style = parseStyleString(styleString);
980
+ if (hasBackground(style)) return styleString;
981
+ const filtered = [];
982
+ for (let i = 0; i < style.length; i++) {
983
+ const prop = style[i];
984
+ if (LINK_INDICATOR_STYLES.includes(prop)) continue;
985
+ const value = style.getPropertyValue(prop);
986
+ if (value) filtered.push(`${prop}: ${value}`);
987
+ }
988
+ return filtered.length > 0 ? filtered.join("; ") : null;
989
+ }
990
+
991
+ //#endregion
992
+ //#region src/extensions/link.tsx
993
+ const Link = EmailMark.from(_tiptap_extension_link.default, ({ children, mark, style }) => {
994
+ const linkMarkStyle = mark.attrs?.style ? require_columns.inlineCssToJs(mark.attrs.style) : {};
995
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Link, {
996
+ href: mark.attrs?.href ?? void 0,
997
+ rel: mark.attrs?.rel ?? void 0,
998
+ style: {
999
+ ...style,
1000
+ ...linkMarkStyle
1001
+ },
1002
+ target: mark.attrs?.target ?? void 0,
1003
+ ...mark.attrs?.["ses:no-track"] ? { "ses:no-track": mark.attrs["ses:no-track"] } : {},
1004
+ children
1005
+ });
1006
+ }).extend({
1007
+ parseHTML() {
1008
+ return [{
1009
+ tag: "a[target]:not([data-id=\"react-email-button\"])",
1010
+ getAttrs: (node) => {
1011
+ if (typeof node === "string") return false;
1012
+ const element = node;
1013
+ const attrs = {};
1014
+ Array.from(element.attributes).forEach((attr) => {
1015
+ attrs[attr.name] = attr.value;
1016
+ });
1017
+ return attrs;
1018
+ }
1019
+ }, {
1020
+ tag: "a[href]:not([data-id=\"react-email-button\"])",
1021
+ getAttrs: (node) => {
1022
+ if (typeof node === "string") return false;
1023
+ const element = node;
1024
+ const attrs = {};
1025
+ Array.from(element.attributes).forEach((attr) => {
1026
+ attrs[attr.name] = attr.value;
1027
+ });
1028
+ return attrs;
1029
+ }
1030
+ }];
1031
+ },
1032
+ addAttributes() {
1033
+ return {
1034
+ ...this.parent?.(),
1035
+ "ses:no-track": {
1036
+ default: null,
1037
+ parseHTML: (element) => element.getAttribute("ses:no-track")
1038
+ }
1039
+ };
1040
+ },
1041
+ addCommands() {
1042
+ return {
1043
+ ...this.parent?.(),
1044
+ unsetLink: () => ({ state, chain }) => {
1045
+ const { from } = state.selection;
1046
+ const linkStyle = state.doc.resolve(from).marks().find((m) => m.type.name === "link")?.attrs?.style ?? null;
1047
+ const preservedStyle = processStylesForUnlink(linkStyle);
1048
+ const shouldRemoveUnderline = preservedStyle !== linkStyle;
1049
+ if (preservedStyle) {
1050
+ const cmd = chain().extendMarkRange("link").unsetMark("link").setMark("preservedStyle", { style: preservedStyle });
1051
+ return shouldRemoveUnderline ? cmd.unsetMark("underline").run() : cmd.run();
1052
+ }
1053
+ return chain().extendMarkRange("link").unsetMark("link").unsetMark("underline").run();
1054
+ }
1055
+ };
1056
+ },
1057
+ addKeyboardShortcuts() {
1058
+ return { "Mod-k": () => {
1059
+ require_columns.editorEventBus.dispatch("bubble-menu:add-link", void 0);
1060
+ return this.editor.chain().focus().toggleLink({ href: "" }).run();
1061
+ } };
1062
+ }
1063
+ });
1064
+
1065
+ //#endregion
1066
+ //#region src/extensions/list-item.tsx
1067
+ const ListItem = require_columns.EmailNode.from(_tiptap_extension_list_item.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
1068
+ className: node.attrs?.class || void 0,
1069
+ style: {
1070
+ ...style,
1071
+ ...require_columns.inlineCssToJs(node.attrs?.style),
1072
+ ...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
1073
+ },
1074
+ children
1075
+ }));
1076
+
1077
+ //#endregion
1078
+ //#region src/extensions/max-nesting.ts
1079
+ const MaxNesting = _tiptap_core.Extension.create({
1080
+ name: "maxNesting",
1081
+ addOptions() {
1082
+ return {
1083
+ maxDepth: 3,
1084
+ nodeTypes: void 0
1085
+ };
1086
+ },
1087
+ addProseMirrorPlugins() {
1088
+ const { maxDepth, nodeTypes } = this.options;
1089
+ if (typeof maxDepth !== "number" || maxDepth < 1) throw new Error("maxDepth must be a positive number");
1090
+ return [new _tiptap_pm_state.Plugin({
1091
+ key: new _tiptap_pm_state.PluginKey("maxNesting"),
1092
+ appendTransaction(transactions, _oldState, newState) {
1093
+ if (!transactions.some((tr$1) => tr$1.docChanged)) return null;
1094
+ const rangesToLift = [];
1095
+ newState.doc.descendants((node, pos) => {
1096
+ let depth = 0;
1097
+ let currentPos = pos;
1098
+ let currentNode = node;
1099
+ while (currentNode && depth <= maxDepth) {
1100
+ if (!nodeTypes || nodeTypes.includes(currentNode.type.name)) depth++;
1101
+ const $pos = newState.doc.resolve(currentPos);
1102
+ if ($pos.depth === 0) break;
1103
+ currentPos = $pos.before($pos.depth);
1104
+ currentNode = newState.doc.nodeAt(currentPos);
1105
+ }
1106
+ if (depth > maxDepth) {
1107
+ const $pos = newState.doc.resolve(pos);
1108
+ if ($pos.depth > 0) {
1109
+ const range = $pos.blockRange();
1110
+ if (range && "canReplace" in newState.schema.nodes.doc && typeof newState.schema.nodes.doc.canReplace === "function" && newState.schema.nodes.doc.canReplace(range.start - 1, range.end + 1, newState.doc.slice(range.start, range.end).content)) rangesToLift.push({
1111
+ range,
1112
+ target: range.start - 1
1113
+ });
1114
+ }
1115
+ }
1116
+ });
1117
+ if (rangesToLift.length === 0) return null;
1118
+ const tr = newState.tr;
1119
+ for (let i = rangesToLift.length - 1; i >= 0; i--) {
1120
+ const { range, target } = rangesToLift[i];
1121
+ tr.lift(range, target);
1122
+ }
1123
+ return tr;
1124
+ },
1125
+ filterTransaction(tr) {
1126
+ if (!tr.docChanged) return true;
1127
+ let wouldCreateDeepNesting = false;
1128
+ const newDoc = tr.doc;
1129
+ newDoc.descendants((node, pos) => {
1130
+ if (wouldCreateDeepNesting) return false;
1131
+ let depth = 0;
1132
+ let currentPos = pos;
1133
+ let currentNode = node;
1134
+ while (currentNode && depth <= maxDepth) {
1135
+ if (!nodeTypes || nodeTypes.includes(currentNode.type.name)) depth++;
1136
+ const $pos = newDoc.resolve(currentPos);
1137
+ if ($pos.depth === 0) break;
1138
+ currentPos = $pos.before($pos.depth);
1139
+ currentNode = newDoc.nodeAt(currentPos);
1140
+ }
1141
+ if (depth > maxDepth) {
1142
+ wouldCreateDeepNesting = true;
1143
+ return false;
1144
+ }
1145
+ });
1146
+ return !wouldCreateDeepNesting;
1147
+ }
1148
+ })];
1149
+ }
1150
+ });
1151
+
1152
+ //#endregion
1153
+ //#region src/extensions/ordered-list.tsx
1154
+ const OrderedList = require_columns.EmailNode.from(_tiptap_extension_ordered_list.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
1155
+ className: node.attrs?.class || void 0,
1156
+ start: node.attrs?.start,
1157
+ style: {
1158
+ ...style,
1159
+ ...require_columns.inlineCssToJs(node.attrs?.style)
1160
+ },
1161
+ children
1162
+ }));
1163
+
1164
+ //#endregion
1165
+ //#region src/extensions/paragraph.tsx
1166
+ const Paragraph = require_columns.EmailNode.from(_tiptap_extension_paragraph.default, ({ children, node, style }) => {
1167
+ const isEmpty = !node.content || node.content.length === 0;
1168
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1169
+ className: node.attrs?.class || void 0,
1170
+ style: {
1171
+ ...style,
1172
+ ...require_columns.inlineCssToJs(node.attrs?.style),
1173
+ ...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
1174
+ },
1175
+ children: isEmpty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}) : children
1176
+ });
1177
+ });
1178
+
1179
+ //#endregion
1180
+ //#region src/extensions/placeholder.ts
1181
+ const Placeholder = _tiptap_extension_placeholder.default.configure({
1182
+ placeholder: ({ node }) => {
1183
+ if (node.type.name === "heading") return `Heading ${node.attrs.level}`;
1184
+ return "Press '/' for commands";
1185
+ },
1186
+ includeChildren: true
1187
+ });
1188
+
1189
+ //#endregion
1190
+ //#region src/extensions/preview-text.ts
1191
+ const PreviewText = _tiptap_core.Node.create({
1192
+ name: "previewText",
1193
+ group: "block",
1194
+ selectable: false,
1195
+ draggable: false,
1196
+ atom: true,
1197
+ addOptions() {
1198
+ return { HTMLAttributes: {} };
1199
+ },
1200
+ addStorage() {
1201
+ return { previewText: null };
1202
+ },
1203
+ renderHTML() {
1204
+ return ["div", { style: "display: none" }];
1205
+ },
1206
+ parseHTML() {
1207
+ return [{
1208
+ tag: "div[data-skip-in-text=\"true\"]",
1209
+ getAttrs: (node) => {
1210
+ if (typeof node === "string") return false;
1211
+ const element = node;
1212
+ let directText = "";
1213
+ for (const child of element.childNodes) if (child.nodeType === 3) directText += child.textContent || "";
1214
+ const cleanText = directText.trim();
1215
+ if (cleanText) this.storage.previewText = cleanText;
1216
+ return false;
1217
+ }
1218
+ }, {
1219
+ tag: "span.preheader",
1220
+ getAttrs: (node) => {
1221
+ if (typeof node === "string") return false;
1222
+ const preheaderText = node.textContent?.trim();
1223
+ if (preheaderText) this.storage.previewText = preheaderText;
1224
+ return false;
1225
+ }
1226
+ }];
1227
+ }
1228
+ });
1229
+
1230
+ //#endregion
1231
+ //#region src/extensions/section.tsx
1232
+ const Section$1 = require_columns.EmailNode.create({
1233
+ name: "section",
1234
+ group: "block",
1235
+ content: "block+",
1236
+ isolating: true,
1237
+ defining: true,
1238
+ parseHTML() {
1239
+ return [{ tag: "section[data-type=\"section\"]" }];
1240
+ },
1241
+ renderHTML({ HTMLAttributes }) {
1242
+ return [
1243
+ "section",
1244
+ (0, _tiptap_core.mergeAttributes)({
1245
+ "data-type": "section",
1246
+ class: "node-section"
1247
+ }, HTMLAttributes),
1248
+ 0
1249
+ ];
1250
+ },
1251
+ addCommands() {
1252
+ return { insertSection: () => ({ commands }) => {
1253
+ return commands.insertContent({
1254
+ type: this.name,
1255
+ content: [{
1256
+ type: "paragraph",
1257
+ content: []
1258
+ }]
1259
+ });
1260
+ } };
1261
+ },
1262
+ renderToReactEmail({ children, node, style }) {
1263
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
1264
+ const textAlign = node.attrs?.align || node.attrs?.alignment;
1265
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
1266
+ className: node.attrs?.class || void 0,
1267
+ align: textAlign,
1268
+ style: {
1269
+ ...style,
1270
+ ...inlineStyles,
1271
+ ...getTextAlignment(textAlign)
1272
+ },
1273
+ children
1274
+ });
1275
+ }
1276
+ });
1277
+
1278
+ //#endregion
1279
+ //#region src/extensions/strike.tsx
1280
+ const Strike = EmailMark.from(_tiptap_extension_strike.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("s", {
1281
+ style,
1282
+ children
1283
+ }));
1284
+
1285
+ //#endregion
1286
+ //#region src/extensions/style-attribute.tsx
1287
+ const StyleAttribute = _tiptap_core.Extension.create({
1288
+ name: "styleAttribute",
1289
+ priority: 101,
1290
+ addOptions() {
1291
+ return {
1292
+ types: [],
1293
+ style: []
1294
+ };
1295
+ },
1296
+ addGlobalAttributes() {
1297
+ return [{
1298
+ types: this.options.types,
1299
+ attributes: { style: {
1300
+ default: "",
1301
+ parseHTML: (element) => element.getAttribute("style") || "",
1302
+ renderHTML: (attributes) => {
1303
+ return { style: attributes.style ?? "" };
1304
+ }
1305
+ } }
1306
+ }];
1307
+ },
1308
+ addCommands() {
1309
+ return {
1310
+ unsetStyle: () => ({ commands }) => {
1311
+ return this.options.types.every((type) => commands.resetAttributes(type, "style"));
1312
+ },
1313
+ setStyle: (style) => ({ commands }) => {
1314
+ return this.options.types.every((type) => commands.updateAttributes(type, { style }));
1315
+ }
1316
+ };
1317
+ },
1318
+ addKeyboardShortcuts() {
1319
+ return { Enter: ({ editor }) => {
1320
+ const { state } = editor.view;
1321
+ const { selection } = state;
1322
+ const { $from } = selection;
1323
+ const textBefore = $from.nodeBefore?.text || "";
1324
+ if (textBefore.includes("{{") || textBefore.includes("{{{")) return false;
1325
+ requestAnimationFrame(() => {
1326
+ editor.commands.resetAttributes("paragraph", "style");
1327
+ });
1328
+ return false;
1329
+ } };
1330
+ }
1331
+ });
1332
+
1333
+ //#endregion
1334
+ //#region src/extensions/sup.tsx
1335
+ const SupBase = _tiptap_extension_superscript.default.extend({
1336
+ name: "sup",
1337
+ addCommands() {
1338
+ return {
1339
+ ...this.parent?.(),
1340
+ setSup: () => ({ commands }) => {
1341
+ return commands.setMark(this.name);
1342
+ },
1343
+ toggleSup: () => ({ commands }) => {
1344
+ return commands.toggleMark(this.name);
1345
+ },
1346
+ unsetSup: () => ({ commands }) => {
1347
+ return commands.unsetMark(this.name);
1348
+ }
1349
+ };
1350
+ }
1351
+ });
1352
+ const Sup = EmailMark.from(SupBase, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
1353
+ style,
1354
+ children
1355
+ }));
1356
+
1357
+ //#endregion
1358
+ //#region src/extensions/table.tsx
1359
+ const Table = require_columns.EmailNode.create({
1360
+ name: "table",
1361
+ group: "block",
1362
+ content: "tableRow+",
1363
+ isolating: true,
1364
+ tableRole: "table",
1365
+ addAttributes() {
1366
+ return { ...require_columns.createStandardAttributes([
1367
+ ...require_columns.TABLE_ATTRIBUTES,
1368
+ ...require_columns.LAYOUT_ATTRIBUTES,
1369
+ ...require_columns.COMMON_HTML_ATTRIBUTES
1370
+ ]) };
1371
+ },
1372
+ parseHTML() {
1373
+ return [{
1374
+ tag: "table",
1375
+ getAttrs: (node) => {
1376
+ if (typeof node === "string") return false;
1377
+ const element = node;
1378
+ const attrs = {};
1379
+ Array.from(element.attributes).forEach((attr) => {
1380
+ attrs[attr.name] = attr.value;
1381
+ });
1382
+ return attrs;
1383
+ }
1384
+ }];
1385
+ },
1386
+ renderHTML({ HTMLAttributes }) {
1387
+ return [
1388
+ "table",
1389
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
1390
+ [
1391
+ "tbody",
1392
+ {},
1393
+ 0
1394
+ ]
1395
+ ];
1396
+ },
1397
+ renderToReactEmail({ children, node, style }) {
1398
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
1399
+ const alignment = node.attrs?.align || node.attrs?.alignment;
1400
+ const width = node.attrs?.width;
1401
+ const centeringStyles = alignment === "center" ? {
1402
+ marginLeft: "auto",
1403
+ marginRight: "auto"
1404
+ } : {};
1405
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
1406
+ className: node.attrs?.class || void 0,
1407
+ align: alignment,
1408
+ style: require_columns.resolveConflictingStyles(style, {
1409
+ ...inlineStyles,
1410
+ ...centeringStyles
1411
+ }),
1412
+ ...width !== void 0 ? { width } : {},
1413
+ children
1414
+ });
1415
+ }
1416
+ });
1417
+ const TableRow = require_columns.EmailNode.create({
1418
+ name: "tableRow",
1419
+ group: "tableRow",
1420
+ content: "(tableCell | tableHeader)+",
1421
+ addAttributes() {
1422
+ return { ...require_columns.createStandardAttributes([
1423
+ ...require_columns.TABLE_CELL_ATTRIBUTES,
1424
+ ...require_columns.LAYOUT_ATTRIBUTES,
1425
+ ...require_columns.COMMON_HTML_ATTRIBUTES
1426
+ ]) };
1427
+ },
1428
+ parseHTML() {
1429
+ return [{
1430
+ tag: "tr",
1431
+ getAttrs: (node) => {
1432
+ if (typeof node === "string") return false;
1433
+ const element = node;
1434
+ const attrs = {};
1435
+ Array.from(element.attributes).forEach((attr) => {
1436
+ attrs[attr.name] = attr.value;
1437
+ });
1438
+ return attrs;
1439
+ }
1440
+ }];
1441
+ },
1442
+ renderHTML({ HTMLAttributes }) {
1443
+ return [
1444
+ "tr",
1445
+ HTMLAttributes,
1446
+ 0
1447
+ ];
1448
+ },
1449
+ renderToReactEmail({ children, node, style }) {
1450
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
1451
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
1452
+ className: node.attrs?.class || void 0,
1453
+ style: {
1454
+ ...style,
1455
+ ...inlineStyles
1456
+ },
1457
+ children
1458
+ });
1459
+ }
1460
+ });
1461
+ const TableCell = require_columns.EmailNode.create({
1462
+ name: "tableCell",
1463
+ group: "tableCell",
1464
+ content: "block+",
1465
+ isolating: true,
1466
+ addAttributes() {
1467
+ return { ...require_columns.createStandardAttributes([
1468
+ ...require_columns.TABLE_CELL_ATTRIBUTES,
1469
+ ...require_columns.LAYOUT_ATTRIBUTES,
1470
+ ...require_columns.COMMON_HTML_ATTRIBUTES
1471
+ ]) };
1472
+ },
1473
+ parseHTML() {
1474
+ return [{
1475
+ tag: "td",
1476
+ getAttrs: (node) => {
1477
+ if (typeof node === "string") return false;
1478
+ const element = node;
1479
+ const attrs = {};
1480
+ Array.from(element.attributes).forEach((attr) => {
1481
+ attrs[attr.name] = attr.value;
1482
+ });
1483
+ return attrs;
1484
+ }
1485
+ }];
1486
+ },
1487
+ renderHTML({ HTMLAttributes }) {
1488
+ return [
1489
+ "td",
1490
+ HTMLAttributes,
1491
+ 0
1492
+ ];
1493
+ },
1494
+ renderToReactEmail({ children, node, style }) {
1495
+ const inlineStyles = require_columns.inlineCssToJs(node.attrs?.style);
1496
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Column, {
1497
+ className: node.attrs?.class || void 0,
1498
+ align: node.attrs?.align || node.attrs?.alignment,
1499
+ style: {
1500
+ ...style,
1501
+ ...inlineStyles
1502
+ },
1503
+ children
1504
+ });
1505
+ }
1506
+ });
1507
+ const TableHeader = _tiptap_core.Node.create({
1508
+ name: "tableHeader",
1509
+ group: "tableCell",
1510
+ content: "block+",
1511
+ isolating: true,
1512
+ addAttributes() {
1513
+ return { ...require_columns.createStandardAttributes([
1514
+ ...require_columns.TABLE_HEADER_ATTRIBUTES,
1515
+ ...require_columns.TABLE_CELL_ATTRIBUTES,
1516
+ ...require_columns.LAYOUT_ATTRIBUTES,
1517
+ ...require_columns.COMMON_HTML_ATTRIBUTES
1518
+ ]) };
1519
+ },
1520
+ parseHTML() {
1521
+ return [{
1522
+ tag: "th",
1523
+ getAttrs: (node) => {
1524
+ if (typeof node === "string") return false;
1525
+ const element = node;
1526
+ const attrs = {};
1527
+ Array.from(element.attributes).forEach((attr) => {
1528
+ attrs[attr.name] = attr.value;
1529
+ });
1530
+ return attrs;
1531
+ }
1532
+ }];
1533
+ },
1534
+ renderHTML({ HTMLAttributes }) {
1535
+ return [
1536
+ "th",
1537
+ HTMLAttributes,
1538
+ 0
1539
+ ];
1540
+ }
1541
+ });
1542
+
1543
+ //#endregion
1544
+ //#region src/extensions/text.tsx
1545
+ const Text = require_columns.EmailNode.from(_tiptap_extension_text.Text, ({ children }) => {
1546
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
1547
+ });
1548
+
1549
+ //#endregion
1550
+ //#region src/extensions/underline.tsx
1551
+ const Underline = EmailMark.from(_tiptap_extension_underline.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("u", {
1552
+ style,
1553
+ children
1554
+ }));
1555
+
1556
+ //#endregion
1557
+ //#region src/extensions/uppercase.tsx
1558
+ const Uppercase = EmailMark.create({
1559
+ name: "uppercase",
1560
+ addOptions() {
1561
+ return { HTMLAttributes: {} };
1562
+ },
1563
+ parseHTML() {
1564
+ return [{
1565
+ tag: "span",
1566
+ getAttrs: (node) => {
1567
+ if (node.style.textTransform === "uppercase") return {};
1568
+ return false;
1569
+ }
1570
+ }];
1571
+ },
1572
+ renderHTML({ HTMLAttributes }) {
1573
+ return [
1574
+ "span",
1575
+ (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, { style: "text-transform: uppercase" }),
1576
+ 0
1577
+ ];
1578
+ },
1579
+ renderToReactEmail({ children, style }) {
1580
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1581
+ style: {
1582
+ ...style,
1583
+ textTransform: "uppercase"
1584
+ },
1585
+ children
1586
+ });
1587
+ },
1588
+ addCommands() {
1589
+ return {
1590
+ setUppercase: () => ({ commands }) => {
1591
+ return commands.setMark(this.name);
1592
+ },
1593
+ toggleUppercase: () => ({ commands }) => {
1594
+ return commands.toggleMark(this.name);
1595
+ },
1596
+ unsetUppercase: () => ({ commands }) => {
1597
+ return commands.unsetMark(this.name);
1598
+ }
1599
+ };
1600
+ }
1601
+ });
1602
+
1603
+ //#endregion
1604
+ //#region src/extensions/index.ts
1605
+ const starterKitExtensions = {
1606
+ CodeBlockPrism,
1607
+ Code,
1608
+ TwoColumns: require_columns.TwoColumns,
1609
+ ThreeColumns: require_columns.ThreeColumns,
1610
+ FourColumns: require_columns.FourColumns,
1611
+ ColumnsColumn: require_columns.ColumnsColumn,
1612
+ Paragraph,
1613
+ BulletList,
1614
+ OrderedList,
1615
+ Blockquote,
1616
+ ListItem,
1617
+ HardBreak,
1618
+ Italic,
1619
+ Placeholder,
1620
+ PreviewText,
1621
+ Bold,
1622
+ Strike,
1623
+ Heading,
1624
+ Divider,
1625
+ Link,
1626
+ Sup,
1627
+ Underline,
1628
+ Uppercase,
1629
+ PreservedStyle,
1630
+ Table,
1631
+ TableRow,
1632
+ TableCell,
1633
+ TableHeader,
1634
+ Body,
1635
+ Div,
1636
+ Button,
1637
+ Section: Section$1,
1638
+ GlobalContent,
1639
+ Text,
1640
+ AlignmentAttribute,
1641
+ StyleAttribute,
1642
+ ClassAttribute,
1643
+ MaxNesting
1644
+ };
1645
+ const StarterKit = _tiptap_core.Extension.create({
1646
+ name: "reactEmailStarterKit",
1647
+ addOptions() {
1648
+ return {
1649
+ TiptapStarterKit: {},
1650
+ CodeBlockPrism: {
1651
+ defaultLanguage: "javascript",
1652
+ HTMLAttributes: { class: "prism node-codeBlock" }
1653
+ },
1654
+ Code: { HTMLAttributes: {
1655
+ class: "node-inlineCode",
1656
+ spellcheck: "false"
1657
+ } },
1658
+ TwoColumns: {},
1659
+ ThreeColumns: {},
1660
+ FourColumns: {},
1661
+ ColumnsColumn: {},
1662
+ Paragraph: { HTMLAttributes: { class: "node-paragraph" } },
1663
+ BulletList: { HTMLAttributes: { class: "node-bulletList" } },
1664
+ OrderedList: { HTMLAttributes: { class: "node-orderedList" } },
1665
+ Blockquote: { HTMLAttributes: { class: "node-blockquote" } },
1666
+ ListItem: {},
1667
+ HardBreak: {},
1668
+ Italic: {},
1669
+ Placeholder: {},
1670
+ PreviewText: {},
1671
+ Bold: {},
1672
+ Strike: {},
1673
+ Heading: {},
1674
+ Divider: {},
1675
+ Link: {},
1676
+ Sup: {},
1677
+ Underline: {},
1678
+ Uppercase: {},
1679
+ PreservedStyle: {},
1680
+ Table: {},
1681
+ TableRow: {},
1682
+ TableCell: {},
1683
+ TableHeader: {},
1684
+ Body: {},
1685
+ Div: {},
1686
+ Button: {},
1687
+ Section: {},
1688
+ GlobalContent: {},
1689
+ AlignmentAttribute: { types: [
1690
+ "heading",
1691
+ "paragraph",
1692
+ "image",
1693
+ "blockquote",
1694
+ "codeBlock",
1695
+ "bulletList",
1696
+ "orderedList",
1697
+ "listItem",
1698
+ "button",
1699
+ "youtube",
1700
+ "twitter",
1701
+ "table",
1702
+ "tableRow",
1703
+ "tableCell",
1704
+ "tableHeader",
1705
+ "columnsColumn"
1706
+ ] },
1707
+ StyleAttribute: { types: [
1708
+ "heading",
1709
+ "paragraph",
1710
+ "image",
1711
+ "blockquote",
1712
+ "codeBlock",
1713
+ "bulletList",
1714
+ "orderedList",
1715
+ "listItem",
1716
+ "button",
1717
+ "youtube",
1718
+ "twitter",
1719
+ "horizontalRule",
1720
+ "footer",
1721
+ "section",
1722
+ "div",
1723
+ "body",
1724
+ "table",
1725
+ "tableRow",
1726
+ "tableCell",
1727
+ "tableHeader",
1728
+ "columnsColumn",
1729
+ "link"
1730
+ ] },
1731
+ Text: {},
1732
+ ClassAttribute: { types: [
1733
+ "heading",
1734
+ "paragraph",
1735
+ "image",
1736
+ "blockquote",
1737
+ "bulletList",
1738
+ "orderedList",
1739
+ "listItem",
1740
+ "button",
1741
+ "youtube",
1742
+ "twitter",
1743
+ "horizontalRule",
1744
+ "footer",
1745
+ "section",
1746
+ "div",
1747
+ "body",
1748
+ "table",
1749
+ "tableRow",
1750
+ "tableCell",
1751
+ "tableHeader",
1752
+ "columnsColumn",
1753
+ "link"
1754
+ ] },
1755
+ MaxNesting: {
1756
+ maxDepth: 50,
1757
+ nodeTypes: [
1758
+ "section",
1759
+ "bulletList",
1760
+ "orderedList"
1761
+ ]
1762
+ }
1763
+ };
1764
+ },
1765
+ addExtensions() {
1766
+ const extensions = [];
1767
+ if (this.options.TiptapStarterKit !== false) extensions.push(_tiptap_starter_kit.default.configure({
1768
+ undoRedo: false,
1769
+ heading: false,
1770
+ link: false,
1771
+ underline: false,
1772
+ trailingNode: false,
1773
+ bold: false,
1774
+ italic: false,
1775
+ strike: false,
1776
+ code: false,
1777
+ paragraph: false,
1778
+ bulletList: false,
1779
+ orderedList: false,
1780
+ listItem: false,
1781
+ blockquote: false,
1782
+ hardBreak: false,
1783
+ gapcursor: false,
1784
+ codeBlock: false,
1785
+ text: false,
1786
+ horizontalRule: false,
1787
+ dropcursor: {
1788
+ color: "#61a8f8",
1789
+ class: "rounded-full animate-[fade-in_300ms_ease-in-out] !z-40",
1790
+ width: 4
1791
+ },
1792
+ ...this.options.TiptapStarterKit
1793
+ }));
1794
+ for (const [name, extension] of Object.entries(starterKitExtensions)) {
1795
+ const key = name;
1796
+ const extensionOptions = this.options[key];
1797
+ if (extensionOptions !== false) extensions.push(extension.configure(extensionOptions));
1798
+ }
1799
+ return extensions;
1800
+ }
1801
+ });
1802
+
1803
+ //#endregion
1804
+ //#region src/core/create-drop-handler.ts
1805
+ function createDropHandler({ onPaste, onUploadImage }) {
1806
+ return (view, event, _slice, moved) => {
1807
+ if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {
1808
+ event.preventDefault();
1809
+ const file = event.dataTransfer.files[0];
1810
+ if (onPaste?.(file, view)) return true;
1811
+ if (file.type.includes("image/") && onUploadImage) {
1812
+ onUploadImage(file, view, (view.posAtCoords({
1813
+ left: event.clientX,
1814
+ top: event.clientY
1815
+ })?.pos || 0) - 1);
1816
+ return true;
1817
+ }
1818
+ }
1819
+ return false;
1820
+ };
1821
+ }
1822
+
1823
+ //#endregion
1824
+ //#region src/utils/paste-sanitizer.ts
1825
+ /**
1826
+ * Sanitizes pasted HTML.
1827
+ * - From editor (has node-* classes): pass through as-is
1828
+ * - From external: strip all styles/classes, keep only semantic HTML
1829
+ */
1830
+ /**
1831
+ * Detects content from the Resend editor by checking for node-* class names.
1832
+ */
1833
+ const EDITOR_CLASS_PATTERN = /class="[^"]*node-/;
1834
+ /**
1835
+ * Attributes to preserve on specific elements for EXTERNAL content.
1836
+ * Only functional attributes - NO style or class.
1837
+ */
1838
+ const PRESERVED_ATTRIBUTES = {
1839
+ a: [
1840
+ "href",
1841
+ "target",
1842
+ "rel"
1843
+ ],
1844
+ img: [
1845
+ "src",
1846
+ "alt",
1847
+ "width",
1848
+ "height"
1849
+ ],
1850
+ td: ["colspan", "rowspan"],
1851
+ th: [
1852
+ "colspan",
1853
+ "rowspan",
1854
+ "scope"
1855
+ ],
1856
+ table: [
1857
+ "border",
1858
+ "cellpadding",
1859
+ "cellspacing"
1860
+ ],
1861
+ "*": ["id"]
1862
+ };
1863
+ function isFromEditor(html) {
1864
+ return EDITOR_CLASS_PATTERN.test(html);
1865
+ }
1866
+ function sanitizePastedHtml(html) {
1867
+ if (isFromEditor(html)) return html;
1868
+ const doc = new DOMParser().parseFromString(html, "text/html");
1869
+ sanitizeNode(doc.body);
1870
+ return doc.body.innerHTML;
1871
+ }
1872
+ function sanitizeNode(node) {
1873
+ if (node.nodeType === Node.ELEMENT_NODE) sanitizeElement(node);
1874
+ for (const child of Array.from(node.childNodes)) sanitizeNode(child);
1875
+ }
1876
+ function sanitizeElement(el) {
1877
+ const allowedForTag = PRESERVED_ATTRIBUTES[el.tagName.toLowerCase()] || [];
1878
+ const allowedGlobal = PRESERVED_ATTRIBUTES["*"] || [];
1879
+ const allowed = new Set([...allowedForTag, ...allowedGlobal]);
1880
+ const attributesToRemove = [];
1881
+ for (const attr of Array.from(el.attributes)) {
1882
+ if (attr.name.startsWith("data-")) {
1883
+ attributesToRemove.push(attr.name);
1884
+ continue;
1885
+ }
1886
+ if (!allowed.has(attr.name)) attributesToRemove.push(attr.name);
1887
+ }
1888
+ for (const attr of attributesToRemove) el.removeAttribute(attr);
1889
+ }
1890
+
1891
+ //#endregion
1892
+ //#region src/core/create-paste-handler.ts
1893
+ function createPasteHandler({ onPaste, onUploadImage, extensions }) {
1894
+ return (view, event, slice) => {
1895
+ const text = event.clipboardData?.getData("text/plain");
1896
+ if (text && onPaste?.(text, view)) {
1897
+ event.preventDefault();
1898
+ return true;
1899
+ }
1900
+ if (event.clipboardData?.files?.[0]) {
1901
+ const file = event.clipboardData.files[0];
1902
+ if (onPaste?.(file, view)) {
1903
+ event.preventDefault();
1904
+ return true;
1905
+ }
1906
+ if (file.type.includes("image/") && onUploadImage) {
1907
+ const pos = view.state.selection.from;
1908
+ onUploadImage(file, view, pos);
1909
+ return true;
1910
+ }
1911
+ }
1912
+ /**
1913
+ * If the coming content has a single child, we can assume
1914
+ * it's a plain text and doesn't need to be parsed and
1915
+ * be introduced in a new line
1916
+ */
1917
+ if (slice.content.childCount === 1) return false;
1918
+ if (event.clipboardData?.getData?.("text/html")) {
1919
+ event.preventDefault();
1920
+ const jsonContent = (0, _tiptap_html.generateJSON)(sanitizePastedHtml(event.clipboardData.getData("text/html")), extensions);
1921
+ const node = view.state.schema.nodeFromJSON(jsonContent);
1922
+ const transaction = view.state.tr.replaceSelectionWith(node, false);
1923
+ view.dispatch(transaction);
1924
+ return true;
1925
+ }
1926
+ return false;
1927
+ };
1928
+ }
1929
+
1930
+ //#endregion
1931
+ //#region src/core/use-editor.ts
1932
+ const COLLABORATION_EXTENSION_NAMES = new Set(["liveblocksExtension", "collaboration"]);
1933
+ function hasCollaborationExtension(exts) {
1934
+ return exts.some((ext) => COLLABORATION_EXTENSION_NAMES.has(ext.name));
1935
+ }
1936
+ function useEditor({ content, extensions = [], onUpdate, onPaste, onUploadImage, onReady, editable = true, ...rest }) {
1937
+ const [contentError, setContentError] = react.useState(null);
1938
+ const isCollaborative = hasCollaborationExtension(extensions);
1939
+ const effectiveExtensions = react.useMemo(() => [
1940
+ StarterKit,
1941
+ ...isCollaborative ? [] : [_tiptap_extensions.UndoRedo],
1942
+ ...extensions
1943
+ ], [extensions, isCollaborative]);
1944
+ const editor = (0, _tiptap_react.useEditor)({
1945
+ content: isCollaborative ? void 0 : content,
1946
+ extensions: effectiveExtensions,
1947
+ editable,
1948
+ immediatelyRender: false,
1949
+ enableContentCheck: true,
1950
+ onContentError({ editor: editor$1, error, disableCollaboration }) {
1951
+ disableCollaboration();
1952
+ setContentError(error);
1953
+ console.error(error);
1954
+ editor$1.setEditable(false);
1955
+ },
1956
+ onCreate({ editor: editor$1 }) {
1957
+ onReady?.(editor$1);
1958
+ },
1959
+ onUpdate({ editor: editor$1, transaction }) {
1960
+ onUpdate?.(editor$1, transaction);
1961
+ },
1962
+ editorProps: {
1963
+ handleDOMEvents: { click: (view, event) => {
1964
+ if (!view.editable) {
1965
+ if (event.target.closest("a")) {
1966
+ event.preventDefault();
1967
+ return true;
1968
+ }
1969
+ }
1970
+ return false;
1971
+ } },
1972
+ handlePaste: createPasteHandler({
1973
+ onPaste,
1974
+ onUploadImage,
1975
+ extensions: effectiveExtensions
1976
+ }),
1977
+ handleDrop: createDropHandler({
1978
+ onPaste,
1979
+ onUploadImage
1980
+ })
1981
+ },
1982
+ ...rest
1983
+ });
1984
+ return {
1985
+ editor,
1986
+ isEditorEmpty: (0, _tiptap_react.useEditorState)({
1987
+ editor,
1988
+ selector: (context) => {
1989
+ if (!context.editor) return true;
1990
+ return isDocumentVisuallyEmpty(context.editor.state.doc);
1991
+ }
1992
+ }) ?? true,
1993
+ extensions: effectiveExtensions,
1994
+ contentError,
1995
+ isCollaborative
1996
+ };
1997
+ }
1998
+
1999
+ //#endregion
2000
+ Object.defineProperty(exports, 'AlignmentAttribute', {
2001
+ enumerable: true,
2002
+ get: function () {
2003
+ return AlignmentAttribute;
2004
+ }
2005
+ });
2006
+ Object.defineProperty(exports, 'Blockquote', {
2007
+ enumerable: true,
2008
+ get: function () {
2009
+ return Blockquote;
2010
+ }
2011
+ });
2012
+ Object.defineProperty(exports, 'Body', {
2013
+ enumerable: true,
2014
+ get: function () {
2015
+ return Body;
2016
+ }
2017
+ });
2018
+ Object.defineProperty(exports, 'Bold', {
2019
+ enumerable: true,
2020
+ get: function () {
2021
+ return Bold;
2022
+ }
2023
+ });
2024
+ Object.defineProperty(exports, 'BulletList', {
2025
+ enumerable: true,
2026
+ get: function () {
2027
+ return BulletList;
2028
+ }
2029
+ });
2030
+ Object.defineProperty(exports, 'Button', {
2031
+ enumerable: true,
2032
+ get: function () {
2033
+ return Button;
2034
+ }
2035
+ });
2036
+ Object.defineProperty(exports, 'ClassAttribute', {
2037
+ enumerable: true,
2038
+ get: function () {
2039
+ return ClassAttribute;
2040
+ }
2041
+ });
2042
+ Object.defineProperty(exports, 'Code', {
2043
+ enumerable: true,
2044
+ get: function () {
2045
+ return Code;
2046
+ }
2047
+ });
2048
+ Object.defineProperty(exports, 'CodeBlockPrism', {
2049
+ enumerable: true,
2050
+ get: function () {
2051
+ return CodeBlockPrism;
2052
+ }
2053
+ });
2054
+ Object.defineProperty(exports, 'Div', {
2055
+ enumerable: true,
2056
+ get: function () {
2057
+ return Div;
2058
+ }
2059
+ });
2060
+ Object.defineProperty(exports, 'Divider', {
2061
+ enumerable: true,
2062
+ get: function () {
2063
+ return Divider;
2064
+ }
2065
+ });
2066
+ Object.defineProperty(exports, 'GlobalContent', {
2067
+ enumerable: true,
2068
+ get: function () {
2069
+ return GlobalContent;
2070
+ }
2071
+ });
2072
+ Object.defineProperty(exports, 'HardBreak', {
2073
+ enumerable: true,
2074
+ get: function () {
2075
+ return HardBreak;
2076
+ }
2077
+ });
2078
+ Object.defineProperty(exports, 'Heading', {
2079
+ enumerable: true,
2080
+ get: function () {
2081
+ return Heading;
2082
+ }
2083
+ });
2084
+ Object.defineProperty(exports, 'Italic', {
2085
+ enumerable: true,
2086
+ get: function () {
2087
+ return Italic;
2088
+ }
2089
+ });
2090
+ Object.defineProperty(exports, 'Link', {
2091
+ enumerable: true,
2092
+ get: function () {
2093
+ return Link;
2094
+ }
2095
+ });
2096
+ Object.defineProperty(exports, 'ListItem', {
2097
+ enumerable: true,
2098
+ get: function () {
2099
+ return ListItem;
2100
+ }
2101
+ });
2102
+ Object.defineProperty(exports, 'MaxNesting', {
2103
+ enumerable: true,
2104
+ get: function () {
2105
+ return MaxNesting;
2106
+ }
2107
+ });
2108
+ Object.defineProperty(exports, 'OrderedList', {
2109
+ enumerable: true,
2110
+ get: function () {
2111
+ return OrderedList;
2112
+ }
2113
+ });
2114
+ Object.defineProperty(exports, 'Paragraph', {
2115
+ enumerable: true,
2116
+ get: function () {
2117
+ return Paragraph;
2118
+ }
2119
+ });
2120
+ Object.defineProperty(exports, 'Placeholder', {
2121
+ enumerable: true,
2122
+ get: function () {
2123
+ return Placeholder;
2124
+ }
2125
+ });
2126
+ Object.defineProperty(exports, 'PreservedStyle', {
2127
+ enumerable: true,
2128
+ get: function () {
2129
+ return PreservedStyle;
2130
+ }
2131
+ });
2132
+ Object.defineProperty(exports, 'PreviewText', {
2133
+ enumerable: true,
2134
+ get: function () {
2135
+ return PreviewText;
2136
+ }
2137
+ });
2138
+ Object.defineProperty(exports, 'Section', {
2139
+ enumerable: true,
2140
+ get: function () {
2141
+ return Section$1;
2142
+ }
2143
+ });
2144
+ Object.defineProperty(exports, 'StarterKit', {
2145
+ enumerable: true,
2146
+ get: function () {
2147
+ return StarterKit;
2148
+ }
2149
+ });
2150
+ Object.defineProperty(exports, 'Strike', {
2151
+ enumerable: true,
2152
+ get: function () {
2153
+ return Strike;
2154
+ }
2155
+ });
2156
+ Object.defineProperty(exports, 'StyleAttribute', {
2157
+ enumerable: true,
2158
+ get: function () {
2159
+ return StyleAttribute;
2160
+ }
2161
+ });
2162
+ Object.defineProperty(exports, 'Sup', {
2163
+ enumerable: true,
2164
+ get: function () {
2165
+ return Sup;
2166
+ }
2167
+ });
2168
+ Object.defineProperty(exports, 'Table', {
2169
+ enumerable: true,
2170
+ get: function () {
2171
+ return Table;
2172
+ }
2173
+ });
2174
+ Object.defineProperty(exports, 'TableCell', {
2175
+ enumerable: true,
2176
+ get: function () {
2177
+ return TableCell;
2178
+ }
2179
+ });
2180
+ Object.defineProperty(exports, 'TableHeader', {
2181
+ enumerable: true,
2182
+ get: function () {
2183
+ return TableHeader;
2184
+ }
2185
+ });
2186
+ Object.defineProperty(exports, 'TableRow', {
2187
+ enumerable: true,
2188
+ get: function () {
2189
+ return TableRow;
2190
+ }
2191
+ });
2192
+ Object.defineProperty(exports, 'Text', {
2193
+ enumerable: true,
2194
+ get: function () {
2195
+ return Text;
2196
+ }
2197
+ });
2198
+ Object.defineProperty(exports, 'Underline', {
2199
+ enumerable: true,
2200
+ get: function () {
2201
+ return Underline;
2202
+ }
2203
+ });
2204
+ Object.defineProperty(exports, 'Uppercase', {
2205
+ enumerable: true,
2206
+ get: function () {
2207
+ return Uppercase;
2208
+ }
2209
+ });
2210
+ Object.defineProperty(exports, 'composeReactEmail', {
2211
+ enumerable: true,
2212
+ get: function () {
2213
+ return composeReactEmail;
2214
+ }
2215
+ });
2216
+ Object.defineProperty(exports, 'getGlobalContent', {
2217
+ enumerable: true,
2218
+ get: function () {
2219
+ return getGlobalContent;
2220
+ }
2221
+ });
2222
+ Object.defineProperty(exports, 'isDocumentVisuallyEmpty', {
2223
+ enumerable: true,
2224
+ get: function () {
2225
+ return isDocumentVisuallyEmpty;
2226
+ }
2227
+ });
2228
+ Object.defineProperty(exports, 'processStylesForUnlink', {
2229
+ enumerable: true,
2230
+ get: function () {
2231
+ return processStylesForUnlink;
2232
+ }
2233
+ });
2234
+ Object.defineProperty(exports, 'useEditor', {
2235
+ enumerable: true,
2236
+ get: function () {
2237
+ return useEditor;
2238
+ }
2239
+ });