@react-email/editor 0.0.0-experimental.0 → 0.0.0-experimental.2

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 CHANGED
@@ -37,6 +37,8 @@ let hast_util_from_html = require("hast-util-from-html");
37
37
  hast_util_from_html = __toESM(hast_util_from_html);
38
38
  let prismjs = require("prismjs");
39
39
  prismjs = __toESM(prismjs);
40
+ let __tiptap_extension_placeholder = require("@tiptap/extension-placeholder");
41
+ __tiptap_extension_placeholder = __toESM(__tiptap_extension_placeholder);
40
42
 
41
43
  //#region src/core/email-node.ts
42
44
  var EmailNode = class EmailNode extends __tiptap_core.Node {
@@ -68,6 +70,61 @@ var EmailNode = class EmailNode extends __tiptap_core.Node {
68
70
  }
69
71
  };
70
72
 
73
+ //#endregion
74
+ //#region src/extensions/alignment-attribute.tsx
75
+ const AlignmentAttribute = __tiptap_core.Extension.create({
76
+ name: "alignmentAttribute",
77
+ addOptions() {
78
+ return {
79
+ types: [],
80
+ alignments: [
81
+ "left",
82
+ "center",
83
+ "right",
84
+ "justify"
85
+ ]
86
+ };
87
+ },
88
+ addGlobalAttributes() {
89
+ return [{
90
+ types: this.options.types,
91
+ attributes: { alignment: {
92
+ parseHTML: (element) => {
93
+ const explicitAlign = element.getAttribute("align") || element.getAttribute("alignment") || element.style.textAlign;
94
+ if (explicitAlign && this.options.alignments.includes(explicitAlign)) return explicitAlign;
95
+ return null;
96
+ },
97
+ renderHTML: (attributes) => {
98
+ if (attributes.alignment === "left") return {};
99
+ return { alignment: attributes.alignment };
100
+ }
101
+ } }
102
+ }];
103
+ },
104
+ addCommands() {
105
+ return { setAlignment: (alignment) => ({ commands }) => {
106
+ if (!this.options.alignments.includes(alignment)) return false;
107
+ return this.options.types.every((type) => commands.updateAttributes(type, { alignment }));
108
+ } };
109
+ },
110
+ addKeyboardShortcuts() {
111
+ return {
112
+ Enter: () => {
113
+ const { from } = this.editor.state.selection;
114
+ const currentAlignment = this.editor.state.doc.nodeAt(from)?.attrs?.alignment;
115
+ if (currentAlignment) requestAnimationFrame(() => {
116
+ this.editor.commands.setAlignment(currentAlignment);
117
+ });
118
+ return false;
119
+ },
120
+ "Mod-Shift-l": () => this.editor.commands.setAlignment("left"),
121
+ "Mod-Shift-e": () => this.editor.commands.setAlignment("center"),
122
+ "Mod-Shift-r": () => this.editor.commands.setAlignment("right"),
123
+ "Mod-Shift-j": () => this.editor.commands.setAlignment("justify")
124
+ };
125
+ }
126
+ });
127
+
71
128
  //#endregion
72
129
  //#region src/utils/attribute-helpers.ts
73
130
  /**
@@ -124,6 +181,14 @@ const LAYOUT_ATTRIBUTES = [
124
181
  "height"
125
182
  ];
126
183
  /**
184
+ * Table-specific HTML attributes used for table layout and styling.
185
+ */
186
+ const TABLE_ATTRIBUTES = [
187
+ "border",
188
+ "cellpadding",
189
+ "cellspacing"
190
+ ];
191
+ /**
127
192
  * Table cell-specific HTML attributes.
128
193
  */
129
194
  const TABLE_CELL_ATTRIBUTES = [
@@ -140,6 +205,7 @@ const TABLE_HEADER_ATTRIBUTES = [...TABLE_CELL_ATTRIBUTES, "scope"];
140
205
 
141
206
  //#endregion
142
207
  //#region src/utils/styles.ts
208
+ const WHITE_SPACE_REGEX = /\s+/;
143
209
  const inlineCssToJs = (inlineStyle, options = {}) => {
144
210
  const styleObject = {};
145
211
  if (!inlineStyle || inlineStyle === "" || typeof inlineStyle === "object") return styleObject;
@@ -154,6 +220,157 @@ const inlineCssToJs = (inlineStyle, options = {}) => {
154
220
  });
155
221
  return styleObject;
156
222
  };
223
+ /**
224
+ * Expands CSS shorthand properties (margin, padding) into their longhand equivalents.
225
+ * This prevents shorthand properties from overriding specific longhand properties in email clients.
226
+ *
227
+ * @param styles - Style object that may contain shorthand properties
228
+ * @returns New style object with shorthand properties expanded to longhand
229
+ *
230
+ * @example
231
+ * expandShorthandProperties({ margin: '0', paddingTop: '10px' })
232
+ * // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }
233
+ */
234
+ function expandShorthandProperties(styles) {
235
+ if (!styles || typeof styles !== "object") return {};
236
+ const expanded = {};
237
+ for (const key in styles) {
238
+ const value = styles[key];
239
+ if (value === void 0 || value === null || value === "") continue;
240
+ switch (key) {
241
+ case "margin": {
242
+ const values = parseShorthandValue(value);
243
+ expanded.marginTop = values.top;
244
+ expanded.marginRight = values.right;
245
+ expanded.marginBottom = values.bottom;
246
+ expanded.marginLeft = values.left;
247
+ break;
248
+ }
249
+ case "padding": {
250
+ const values = parseShorthandValue(value);
251
+ expanded.paddingTop = values.top;
252
+ expanded.paddingRight = values.right;
253
+ expanded.paddingBottom = values.bottom;
254
+ expanded.paddingLeft = values.left;
255
+ break;
256
+ }
257
+ case "border": {
258
+ const values = convertBorderValue(value);
259
+ expanded.borderStyle = values.style;
260
+ expanded.borderWidth = values.width;
261
+ expanded.borderColor = values.color;
262
+ break;
263
+ }
264
+ case "borderTopLeftRadius":
265
+ case "borderTopRightRadius":
266
+ case "borderBottomLeftRadius":
267
+ case "borderBottomRightRadius":
268
+ expanded[key] = value;
269
+ if (styles.borderTopLeftRadius && styles.borderTopRightRadius && styles.borderBottomLeftRadius && styles.borderBottomRightRadius) {
270
+ const values = [
271
+ styles.borderTopLeftRadius,
272
+ styles.borderTopRightRadius,
273
+ styles.borderBottomLeftRadius,
274
+ styles.borderBottomRightRadius
275
+ ];
276
+ if (new Set(values).size === 1) expanded.borderRadius = values[0];
277
+ }
278
+ break;
279
+ default: expanded[key] = value;
280
+ }
281
+ }
282
+ return expanded;
283
+ }
284
+ /**
285
+ * Parses CSS shorthand value (1-4 values) into individual side values.
286
+ * Follows CSS specification for shorthand property value parsing.
287
+ *
288
+ * @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')
289
+ * @returns Object with top, right, bottom, left values
290
+ */
291
+ function parseShorthandValue(value) {
292
+ const stringValue = String(value).trim();
293
+ const parts = stringValue.split(WHITE_SPACE_REGEX);
294
+ const len = parts.length;
295
+ if (len === 1) return {
296
+ top: parts[0],
297
+ right: parts[0],
298
+ bottom: parts[0],
299
+ left: parts[0]
300
+ };
301
+ if (len === 2) return {
302
+ top: parts[0],
303
+ right: parts[1],
304
+ bottom: parts[0],
305
+ left: parts[1]
306
+ };
307
+ if (len === 3) return {
308
+ top: parts[0],
309
+ right: parts[1],
310
+ bottom: parts[2],
311
+ left: parts[1]
312
+ };
313
+ if (len === 4) return {
314
+ top: parts[0],
315
+ right: parts[1],
316
+ bottom: parts[2],
317
+ left: parts[3]
318
+ };
319
+ return {
320
+ top: stringValue,
321
+ right: stringValue,
322
+ bottom: stringValue,
323
+ left: stringValue
324
+ };
325
+ }
326
+ function convertBorderValue(value) {
327
+ const stringValue = String(value).trim();
328
+ const parts = stringValue.split(WHITE_SPACE_REGEX);
329
+ switch (parts.length) {
330
+ case 1: return {
331
+ style: "solid",
332
+ width: parts[0],
333
+ color: "black"
334
+ };
335
+ case 2: return {
336
+ style: parts[1],
337
+ width: parts[0],
338
+ color: "black"
339
+ };
340
+ case 3: return {
341
+ style: parts[1],
342
+ width: parts[0],
343
+ color: parts[2]
344
+ };
345
+ case 4: return {
346
+ style: parts[1],
347
+ width: parts[0],
348
+ color: parts[2]
349
+ };
350
+ default: return {
351
+ style: "solid",
352
+ width: stringValue,
353
+ color: "black"
354
+ };
355
+ }
356
+ }
357
+ /**
358
+ * Resolves conflicts between reset styles and inline styles by expanding
359
+ * shorthand properties (margin, padding) to longhand before merging.
360
+ * This prevents shorthand properties from overriding specific longhand properties.
361
+ *
362
+ * @param resetStyles - Base reset styles that may contain shorthand properties
363
+ * @param inlineStyles - Inline styles that should override reset styles
364
+ * @returns Merged styles with inline styles taking precedence
365
+ */
366
+ function resolveConflictingStyles(resetStyles, inlineStyles) {
367
+ const expandedResetStyles = expandShorthandProperties(resetStyles);
368
+ const expandedInlineStyles = expandShorthandProperties(inlineStyles);
369
+ return {
370
+ ...expandedResetStyles,
371
+ ...expandedInlineStyles
372
+ };
373
+ }
157
374
 
158
375
  //#endregion
159
376
  //#region src/extensions/body.tsx
@@ -200,6 +417,92 @@ const Body = EmailNode.create({
200
417
  }
201
418
  });
202
419
 
420
+ //#endregion
421
+ //#region src/extensions/bold.ts
422
+ /**
423
+ * Matches bold text via `**` as input.
424
+ */
425
+ const starInputRegex = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))$/;
426
+ /**
427
+ * Matches bold text via `**` while pasting.
428
+ */
429
+ const starPasteRegex = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))/g;
430
+ /**
431
+ * Matches bold text via `__` as input.
432
+ */
433
+ const underscoreInputRegex = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))$/;
434
+ /**
435
+ * Matches bold text via `__` while pasting.
436
+ */
437
+ const underscorePasteRegex = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g;
438
+ /**
439
+ * This extension allows you to mark text as bold.
440
+ * @see https://tiptap.dev/api/marks/bold
441
+ */
442
+ const Bold = __tiptap_core.Mark.create({
443
+ name: "bold",
444
+ addOptions() {
445
+ return { HTMLAttributes: {} };
446
+ },
447
+ parseHTML() {
448
+ return [
449
+ { tag: "strong" },
450
+ {
451
+ tag: "b",
452
+ getAttrs: (node) => node.style.fontWeight !== "normal" && null
453
+ },
454
+ {
455
+ style: "font-weight=400",
456
+ clearMark: (mark) => mark.type.name === this.name
457
+ }
458
+ ];
459
+ },
460
+ renderHTML({ HTMLAttributes }) {
461
+ return [
462
+ "strong",
463
+ (0, __tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
464
+ 0
465
+ ];
466
+ },
467
+ addCommands() {
468
+ return {
469
+ setBold: () => ({ commands }) => {
470
+ return commands.setMark(this.name);
471
+ },
472
+ toggleBold: () => ({ commands }) => {
473
+ return commands.toggleMark(this.name);
474
+ },
475
+ unsetBold: () => ({ commands }) => {
476
+ return commands.unsetMark(this.name);
477
+ }
478
+ };
479
+ },
480
+ addKeyboardShortcuts() {
481
+ return {
482
+ "Mod-b": () => this.editor.commands.toggleBold(),
483
+ "Mod-B": () => this.editor.commands.toggleBold()
484
+ };
485
+ },
486
+ addInputRules() {
487
+ return [(0, __tiptap_core.markInputRule)({
488
+ find: starInputRegex,
489
+ type: this.type
490
+ }), (0, __tiptap_core.markInputRule)({
491
+ find: underscoreInputRegex,
492
+ type: this.type
493
+ })];
494
+ },
495
+ addPasteRules() {
496
+ return [(0, __tiptap_core.markPasteRule)({
497
+ find: starPasteRegex,
498
+ type: this.type
499
+ }), (0, __tiptap_core.markPasteRule)({
500
+ find: underscorePasteRegex,
501
+ type: this.type
502
+ })];
503
+ }
504
+ });
505
+
203
506
  //#endregion
204
507
  //#region src/extensions/button.tsx
205
508
  const Button = EmailNode.create({
@@ -280,6 +583,48 @@ const Button = EmailNode.create({
280
583
  }
281
584
  });
282
585
 
586
+ //#endregion
587
+ //#region src/extensions/class-attribute.tsx
588
+ const ClassAttribute = __tiptap_core.Extension.create({
589
+ name: "classAttribute",
590
+ addOptions() {
591
+ return {
592
+ types: [],
593
+ class: []
594
+ };
595
+ },
596
+ addGlobalAttributes() {
597
+ return [{
598
+ types: this.options.types,
599
+ attributes: { class: {
600
+ default: "",
601
+ parseHTML: (element) => element.className || "",
602
+ renderHTML: (attributes) => {
603
+ return attributes.class ? { class: attributes.class } : {};
604
+ }
605
+ } }
606
+ }];
607
+ },
608
+ addCommands() {
609
+ return {
610
+ unsetClass: () => ({ commands }) => {
611
+ return this.options.types.every((type) => commands.resetAttributes(type, "class"));
612
+ },
613
+ setClass: (classList) => ({ commands }) => {
614
+ return this.options.types.every((type) => commands.updateAttributes(type, { class: classList }));
615
+ }
616
+ };
617
+ },
618
+ addKeyboardShortcuts() {
619
+ return { Enter: ({ editor }) => {
620
+ requestAnimationFrame(() => {
621
+ editor.commands.resetAttributes("paragraph", "class");
622
+ });
623
+ return false;
624
+ } };
625
+ }
626
+ });
627
+
283
628
  //#endregion
284
629
  //#region src/utils/prism-utils.ts
285
630
  const publicURL = "/styles/prism";
@@ -539,6 +884,169 @@ const Div = EmailNode.create({
539
884
  }
540
885
  });
541
886
 
887
+ //#endregion
888
+ //#region src/extensions/max-nesting.ts
889
+ const MaxNesting = __tiptap_core.Extension.create({
890
+ name: "maxNesting",
891
+ addOptions() {
892
+ return {
893
+ maxDepth: 3,
894
+ nodeTypes: void 0
895
+ };
896
+ },
897
+ addProseMirrorPlugins() {
898
+ const { maxDepth, nodeTypes } = this.options;
899
+ if (typeof maxDepth !== "number" || maxDepth < 1) throw new Error("maxDepth must be a positive number");
900
+ return [new __tiptap_pm_state.Plugin({
901
+ key: new __tiptap_pm_state.PluginKey("maxNesting"),
902
+ appendTransaction(transactions, _oldState, newState) {
903
+ if (!transactions.some((tr$1) => tr$1.docChanged)) return null;
904
+ const rangesToLift = [];
905
+ newState.doc.descendants((node, pos) => {
906
+ let depth = 0;
907
+ let currentPos = pos;
908
+ let currentNode = node;
909
+ while (currentNode && depth <= maxDepth) {
910
+ if (!nodeTypes || nodeTypes.includes(currentNode.type.name)) depth++;
911
+ const $pos = newState.doc.resolve(currentPos);
912
+ if ($pos.depth === 0) break;
913
+ currentPos = $pos.before($pos.depth);
914
+ currentNode = newState.doc.nodeAt(currentPos);
915
+ }
916
+ if (depth > maxDepth) {
917
+ const $pos = newState.doc.resolve(pos);
918
+ if ($pos.depth > 0) {
919
+ const range = $pos.blockRange();
920
+ 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({
921
+ range,
922
+ target: range.start - 1
923
+ });
924
+ }
925
+ }
926
+ });
927
+ if (rangesToLift.length === 0) return null;
928
+ const tr = newState.tr;
929
+ for (let i = rangesToLift.length - 1; i >= 0; i--) {
930
+ const { range, target } = rangesToLift[i];
931
+ tr.lift(range, target);
932
+ }
933
+ return tr;
934
+ },
935
+ filterTransaction(tr) {
936
+ if (!tr.docChanged) return true;
937
+ let wouldCreateDeepNesting = false;
938
+ const newDoc = tr.doc;
939
+ newDoc.descendants((node, pos) => {
940
+ if (wouldCreateDeepNesting) return false;
941
+ let depth = 0;
942
+ let currentPos = pos;
943
+ let currentNode = node;
944
+ while (currentNode && depth <= maxDepth) {
945
+ if (!nodeTypes || nodeTypes.includes(currentNode.type.name)) depth++;
946
+ const $pos = newDoc.resolve(currentPos);
947
+ if ($pos.depth === 0) break;
948
+ currentPos = $pos.before($pos.depth);
949
+ currentNode = newDoc.nodeAt(currentPos);
950
+ }
951
+ if (depth > maxDepth) {
952
+ wouldCreateDeepNesting = true;
953
+ return false;
954
+ }
955
+ });
956
+ return !wouldCreateDeepNesting;
957
+ }
958
+ })];
959
+ }
960
+ });
961
+
962
+ //#endregion
963
+ //#region src/extensions/placeholder.ts
964
+ const createPlaceholderExtension = (options) => {
965
+ return __tiptap_extension_placeholder.default.configure({
966
+ placeholder: ({ node }) => {
967
+ if (node.type.name === "heading") return `Heading ${node.attrs.level}`;
968
+ return "Press '/' for commands";
969
+ },
970
+ includeChildren: true,
971
+ ...options
972
+ });
973
+ };
974
+ const placeholder = createPlaceholderExtension();
975
+
976
+ //#endregion
977
+ //#region src/extensions/preserved-style.ts
978
+ const PreservedStyle = __tiptap_core.Mark.create({
979
+ name: "preservedStyle",
980
+ addAttributes() {
981
+ return { style: {
982
+ default: null,
983
+ parseHTML: (element) => element.getAttribute("style"),
984
+ renderHTML: (attributes) => {
985
+ if (!attributes.style) return {};
986
+ return { style: attributes.style };
987
+ }
988
+ } };
989
+ },
990
+ parseHTML() {
991
+ return [{
992
+ tag: "span[style]",
993
+ getAttrs: (element) => {
994
+ if (typeof element === "string") return false;
995
+ const style = element.getAttribute("style");
996
+ if (style && hasPreservableStyles(style)) return { style };
997
+ return false;
998
+ }
999
+ }];
1000
+ },
1001
+ renderHTML({ HTMLAttributes }) {
1002
+ return [
1003
+ "span",
1004
+ (0, __tiptap_core.mergeAttributes)(HTMLAttributes),
1005
+ 0
1006
+ ];
1007
+ }
1008
+ });
1009
+ const LINK_INDICATOR_STYLES = [
1010
+ "color",
1011
+ "text-decoration",
1012
+ "text-decoration-line",
1013
+ "text-decoration-color",
1014
+ "text-decoration-style"
1015
+ ];
1016
+ function parseStyleString(styleString) {
1017
+ const temp = document.createElement("div");
1018
+ temp.style.cssText = styleString;
1019
+ return temp.style;
1020
+ }
1021
+ function hasBackground(style) {
1022
+ const bgColor = style.backgroundColor;
1023
+ const bg = style.background;
1024
+ if (bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") return true;
1025
+ if (bg && bg !== "transparent" && bg !== "none" && bg !== "rgba(0, 0, 0, 0)") return true;
1026
+ return false;
1027
+ }
1028
+ function hasPreservableStyles(styleString) {
1029
+ return processStylesForUnlink(styleString) !== null;
1030
+ }
1031
+ /**
1032
+ * Processes styles when unlinking:
1033
+ * - Has background (button-like): preserve all styles
1034
+ * - No background: strip link-indicator styles (color, text-decoration), keep the rest
1035
+ */
1036
+ function processStylesForUnlink(styleString) {
1037
+ if (!styleString) return null;
1038
+ const style = parseStyleString(styleString);
1039
+ if (hasBackground(style)) return styleString;
1040
+ const filtered = [];
1041
+ for (let i = 0; i < style.length; i++) {
1042
+ const prop = style[i];
1043
+ if (LINK_INDICATOR_STYLES.includes(prop)) continue;
1044
+ const value = style.getPropertyValue(prop);
1045
+ if (value) filtered.push(`${prop}: ${value}`);
1046
+ }
1047
+ return filtered.length > 0 ? filtered.join("; ") : null;
1048
+ }
1049
+
542
1050
  //#endregion
543
1051
  //#region src/utils/get-text-alignment.ts
544
1052
  function getTextAlignment(alignment) {
@@ -599,9 +1107,293 @@ const Section = EmailNode.create({
599
1107
  });
600
1108
 
601
1109
  //#endregion
1110
+ //#region src/extensions/style-attribute.tsx
1111
+ const StyleAttribute = __tiptap_core.Extension.create({
1112
+ name: "styleAttribute",
1113
+ priority: 101,
1114
+ addOptions() {
1115
+ return {
1116
+ types: [],
1117
+ style: []
1118
+ };
1119
+ },
1120
+ addGlobalAttributes() {
1121
+ return [{
1122
+ types: this.options.types,
1123
+ attributes: { style: {
1124
+ default: "",
1125
+ parseHTML: (element) => element.getAttribute("style") || "",
1126
+ renderHTML: (attributes) => {
1127
+ return { style: attributes.style ?? "" };
1128
+ }
1129
+ } }
1130
+ }];
1131
+ },
1132
+ addCommands() {
1133
+ return {
1134
+ unsetStyle: () => ({ commands }) => {
1135
+ return this.options.types.every((type) => commands.resetAttributes(type, "style"));
1136
+ },
1137
+ setStyle: (style) => ({ commands }) => {
1138
+ return this.options.types.every((type) => commands.updateAttributes(type, { style }));
1139
+ }
1140
+ };
1141
+ },
1142
+ addKeyboardShortcuts() {
1143
+ return { Enter: ({ editor }) => {
1144
+ const { state } = editor.view;
1145
+ const { selection } = state;
1146
+ const { $from } = selection;
1147
+ const textBefore = $from.nodeBefore?.text || "";
1148
+ if (textBefore.includes("{{") || textBefore.includes("{{{")) return false;
1149
+ requestAnimationFrame(() => {
1150
+ editor.commands.resetAttributes("paragraph", "style");
1151
+ });
1152
+ return false;
1153
+ } };
1154
+ }
1155
+ });
1156
+
1157
+ //#endregion
1158
+ //#region src/extensions/sup.ts
1159
+ /**
1160
+ * This extension allows you to mark text as superscript.
1161
+ * @see https://tiptap.dev/api/marks/superscript
1162
+ */
1163
+ const Sup = __tiptap_core.Mark.create({
1164
+ name: "sup",
1165
+ addOptions() {
1166
+ return { HTMLAttributes: {} };
1167
+ },
1168
+ parseHTML() {
1169
+ return [{ tag: "sup" }];
1170
+ },
1171
+ renderHTML({ HTMLAttributes }) {
1172
+ return [
1173
+ "sup",
1174
+ (0, __tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
1175
+ 0
1176
+ ];
1177
+ },
1178
+ addCommands() {
1179
+ return {
1180
+ setSup: () => ({ commands }) => {
1181
+ return commands.setMark(this.name);
1182
+ },
1183
+ toggleSup: () => ({ commands }) => {
1184
+ return commands.toggleMark(this.name);
1185
+ },
1186
+ unsetSup: () => ({ commands }) => {
1187
+ return commands.unsetMark(this.name);
1188
+ }
1189
+ };
1190
+ }
1191
+ });
1192
+
1193
+ //#endregion
1194
+ //#region src/extensions/table.tsx
1195
+ const Table = EmailNode.create({
1196
+ name: "table",
1197
+ group: "block",
1198
+ content: "tableRow+",
1199
+ isolating: true,
1200
+ tableRole: "table",
1201
+ addAttributes() {
1202
+ return { ...createStandardAttributes([
1203
+ ...TABLE_ATTRIBUTES,
1204
+ ...LAYOUT_ATTRIBUTES,
1205
+ ...COMMON_HTML_ATTRIBUTES
1206
+ ]) };
1207
+ },
1208
+ parseHTML() {
1209
+ return [{
1210
+ tag: "table",
1211
+ getAttrs: (node) => {
1212
+ if (typeof node === "string") return false;
1213
+ const element = node;
1214
+ const attrs = {};
1215
+ Array.from(element.attributes).forEach((attr) => {
1216
+ attrs[attr.name] = attr.value;
1217
+ });
1218
+ return attrs;
1219
+ }
1220
+ }];
1221
+ },
1222
+ renderHTML({ HTMLAttributes }) {
1223
+ return [
1224
+ "table",
1225
+ (0, __tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
1226
+ [
1227
+ "tbody",
1228
+ {},
1229
+ 0
1230
+ ]
1231
+ ];
1232
+ },
1233
+ renderToReactEmail({ children, node, styles }) {
1234
+ const inlineStyles = inlineCssToJs(node.attrs?.style);
1235
+ const alignment = node.attrs?.align || node.attrs?.alignment;
1236
+ const width = node.attrs?.width;
1237
+ const centeringStyles = alignment === "center" ? {
1238
+ marginLeft: "auto",
1239
+ marginRight: "auto"
1240
+ } : {};
1241
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__react_email_components.Section, {
1242
+ className: node.attrs?.class || void 0,
1243
+ align: alignment,
1244
+ style: resolveConflictingStyles(styles.reset, {
1245
+ ...inlineStyles,
1246
+ ...centeringStyles
1247
+ }),
1248
+ ...width !== void 0 ? { width } : {},
1249
+ children
1250
+ });
1251
+ }
1252
+ });
1253
+ const TableRow = EmailNode.create({
1254
+ name: "tableRow",
1255
+ group: "tableRow",
1256
+ content: "(tableCell | tableHeader)+",
1257
+ addAttributes() {
1258
+ return { ...createStandardAttributes([
1259
+ ...TABLE_CELL_ATTRIBUTES,
1260
+ ...LAYOUT_ATTRIBUTES,
1261
+ ...COMMON_HTML_ATTRIBUTES
1262
+ ]) };
1263
+ },
1264
+ parseHTML() {
1265
+ return [{
1266
+ tag: "tr",
1267
+ getAttrs: (node) => {
1268
+ if (typeof node === "string") return false;
1269
+ const element = node;
1270
+ const attrs = {};
1271
+ Array.from(element.attributes).forEach((attr) => {
1272
+ attrs[attr.name] = attr.value;
1273
+ });
1274
+ return attrs;
1275
+ }
1276
+ }];
1277
+ },
1278
+ renderHTML({ HTMLAttributes }) {
1279
+ return [
1280
+ "tr",
1281
+ HTMLAttributes,
1282
+ 0
1283
+ ];
1284
+ },
1285
+ renderToReactEmail({ children, node, styles }) {
1286
+ const inlineStyles = inlineCssToJs(node.attrs?.style);
1287
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
1288
+ className: node.attrs?.class || void 0,
1289
+ style: {
1290
+ ...styles.reset,
1291
+ ...inlineStyles
1292
+ },
1293
+ children
1294
+ });
1295
+ }
1296
+ });
1297
+ const TableCell = EmailNode.create({
1298
+ name: "tableCell",
1299
+ group: "tableCell",
1300
+ content: "block+",
1301
+ isolating: true,
1302
+ addAttributes() {
1303
+ return { ...createStandardAttributes([
1304
+ ...TABLE_CELL_ATTRIBUTES,
1305
+ ...LAYOUT_ATTRIBUTES,
1306
+ ...COMMON_HTML_ATTRIBUTES
1307
+ ]) };
1308
+ },
1309
+ parseHTML() {
1310
+ return [{
1311
+ tag: "td",
1312
+ getAttrs: (node) => {
1313
+ if (typeof node === "string") return false;
1314
+ const element = node;
1315
+ const attrs = {};
1316
+ Array.from(element.attributes).forEach((attr) => {
1317
+ attrs[attr.name] = attr.value;
1318
+ });
1319
+ return attrs;
1320
+ }
1321
+ }];
1322
+ },
1323
+ renderHTML({ HTMLAttributes }) {
1324
+ return [
1325
+ "td",
1326
+ HTMLAttributes,
1327
+ 0
1328
+ ];
1329
+ },
1330
+ renderToReactEmail({ children, node, styles }) {
1331
+ const inlineStyles = inlineCssToJs(node.attrs?.style);
1332
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__react_email_components.Column, {
1333
+ className: node.attrs?.class || void 0,
1334
+ align: node.attrs?.align || node.attrs?.alignment,
1335
+ style: {
1336
+ ...styles.reset,
1337
+ ...inlineStyles
1338
+ },
1339
+ children
1340
+ });
1341
+ }
1342
+ });
1343
+ const TableHeader = __tiptap_core.Node.create({
1344
+ name: "tableHeader",
1345
+ group: "tableCell",
1346
+ content: "block+",
1347
+ isolating: true,
1348
+ addAttributes() {
1349
+ return { ...createStandardAttributes([
1350
+ ...TABLE_HEADER_ATTRIBUTES,
1351
+ ...TABLE_CELL_ATTRIBUTES,
1352
+ ...LAYOUT_ATTRIBUTES,
1353
+ ...COMMON_HTML_ATTRIBUTES
1354
+ ]) };
1355
+ },
1356
+ parseHTML() {
1357
+ return [{
1358
+ tag: "th",
1359
+ getAttrs: (node) => {
1360
+ if (typeof node === "string") return false;
1361
+ const element = node;
1362
+ const attrs = {};
1363
+ Array.from(element.attributes).forEach((attr) => {
1364
+ attrs[attr.name] = attr.value;
1365
+ });
1366
+ return attrs;
1367
+ }
1368
+ }];
1369
+ },
1370
+ renderHTML({ HTMLAttributes }) {
1371
+ return [
1372
+ "th",
1373
+ HTMLAttributes,
1374
+ 0
1375
+ ];
1376
+ }
1377
+ });
1378
+
1379
+ //#endregion
1380
+ exports.AlignmentAttribute = AlignmentAttribute;
602
1381
  exports.Body = Body;
1382
+ exports.Bold = Bold;
603
1383
  exports.Button = Button;
1384
+ exports.ClassAttribute = ClassAttribute;
604
1385
  exports.CodeBlockPrism = CodeBlockPrism;
605
1386
  exports.Div = Div;
606
1387
  exports.EmailNode = EmailNode;
607
- exports.Section = Section;
1388
+ exports.MaxNesting = MaxNesting;
1389
+ exports.PreservedStyle = PreservedStyle;
1390
+ exports.Section = Section;
1391
+ exports.StyleAttribute = StyleAttribute;
1392
+ exports.Sup = Sup;
1393
+ exports.Table = Table;
1394
+ exports.TableCell = TableCell;
1395
+ exports.TableHeader = TableHeader;
1396
+ exports.TableRow = TableRow;
1397
+ exports.createPlaceholderExtension = createPlaceholderExtension;
1398
+ exports.placeholder = placeholder;
1399
+ exports.processStylesForUnlink = processStylesForUnlink;