@react-email/editor 0.0.0-experimental.16 → 0.0.0-experimental.18
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.cjs +477 -194
- package/dist/index.d.cts +270 -190
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +268 -188
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +473 -198
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as ReactEmailComponents from "@react-email/components";
|
|
2
|
-
import { Body as Body$1, Button as Button$1, CodeBlock, Column, Head, Html, Preview, Row, Section as Section$1, pretty, render, toPlainText } from "@react-email/components";
|
|
2
|
+
import { Body as Body$1, Button as Button$1, CodeBlock, Column, Head, Heading as Heading$1, Hr, Html, Link as Link$1, Preview, Row, Section as Section$1, pretty, render, toPlainText } from "@react-email/components";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { Extension, Mark, Node as Node$1, findChildren, markInputRule, markPasteRule, mergeAttributes } from "@tiptap/core";
|
|
4
|
+
import { Extension, InputRule, Mark, Node as Node$1, findChildren, markInputRule, markPasteRule, mergeAttributes } from "@tiptap/core";
|
|
5
5
|
import { UndoRedo } from "@tiptap/extensions";
|
|
6
|
-
import { ReactRenderer, useCurrentEditor, useEditor as useEditor$1, useEditorState } from "@tiptap/react";
|
|
6
|
+
import { NodeViewContent, NodeViewWrapper, ReactNodeViewRenderer, ReactRenderer, useCurrentEditor, useEditor as useEditor$1, useEditorState } from "@tiptap/react";
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
9
|
-
import
|
|
9
|
+
import TipTapStarterKit from "@tiptap/starter-kit";
|
|
10
10
|
import BlockquoteBase from "@tiptap/extension-blockquote";
|
|
11
11
|
import BulletListBase from "@tiptap/extension-bullet-list";
|
|
12
12
|
import CodeBase from "@tiptap/extension-code";
|
|
@@ -15,8 +15,11 @@ import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
|
15
15
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
16
16
|
import { fromHtml } from "hast-util-from-html";
|
|
17
17
|
import Prism from "prismjs";
|
|
18
|
+
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
18
19
|
import HardBreakBase from "@tiptap/extension-hard-break";
|
|
20
|
+
import { Heading as Heading$2 } from "@tiptap/extension-heading";
|
|
19
21
|
import ItalicBase from "@tiptap/extension-italic";
|
|
22
|
+
import TiptapLink from "@tiptap/extension-link";
|
|
20
23
|
import ListItemBase from "@tiptap/extension-list-item";
|
|
21
24
|
import OrderedListBase from "@tiptap/extension-ordered-list";
|
|
22
25
|
import ParagraphBase from "@tiptap/extension-paragraph";
|
|
@@ -1132,10 +1135,153 @@ const Div = EmailNode.create({
|
|
|
1132
1135
|
}
|
|
1133
1136
|
});
|
|
1134
1137
|
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/extensions/divider.tsx
|
|
1140
|
+
const Divider = EmailNode.from(HorizontalRule.extend({
|
|
1141
|
+
addAttributes() {
|
|
1142
|
+
return { class: { default: "divider" } };
|
|
1143
|
+
},
|
|
1144
|
+
addInputRules() {
|
|
1145
|
+
return [new InputRule({
|
|
1146
|
+
find: /^(?:---|—-|___\s|\*\*\*\s)$/,
|
|
1147
|
+
handler: ({ state, range }) => {
|
|
1148
|
+
const attributes = {};
|
|
1149
|
+
const { tr } = state;
|
|
1150
|
+
const start = range.from;
|
|
1151
|
+
const end = range.to;
|
|
1152
|
+
tr.insert(start - 1, this.type.create(attributes)).delete(tr.mapping.map(start), tr.mapping.map(end));
|
|
1153
|
+
}
|
|
1154
|
+
})];
|
|
1155
|
+
},
|
|
1156
|
+
addNodeView() {
|
|
1157
|
+
return ReactNodeViewRenderer((props) => {
|
|
1158
|
+
const node = props.node;
|
|
1159
|
+
const { class: className, ...rest } = node.attrs;
|
|
1160
|
+
return /* @__PURE__ */ jsx(NodeViewWrapper, { children: /* @__PURE__ */ jsx(Hr, {
|
|
1161
|
+
...rest,
|
|
1162
|
+
className: "node-hr",
|
|
1163
|
+
style: inlineCssToJs(node.attrs.style)
|
|
1164
|
+
}) });
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
}), ({ node, style }) => {
|
|
1168
|
+
return /* @__PURE__ */ jsx(Hr, {
|
|
1169
|
+
className: node.attrs?.class || void 0,
|
|
1170
|
+
style: {
|
|
1171
|
+
...style,
|
|
1172
|
+
...inlineCssToJs(node.attrs?.style)
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
//#endregion
|
|
1178
|
+
//#region src/extensions/global-content.ts
|
|
1179
|
+
const GLOBAL_CONTENT_NODE_TYPE = "globalContent";
|
|
1180
|
+
let cachedGlobalPosition = null;
|
|
1181
|
+
function findGlobalContentPositions(doc) {
|
|
1182
|
+
const positions = [];
|
|
1183
|
+
doc.descendants((node, position) => {
|
|
1184
|
+
if (node.type.name === GLOBAL_CONTENT_NODE_TYPE) positions.push(position);
|
|
1185
|
+
});
|
|
1186
|
+
return positions;
|
|
1187
|
+
}
|
|
1188
|
+
function getCachedGlobalContentPosition(doc) {
|
|
1189
|
+
if (cachedGlobalPosition != null) try {
|
|
1190
|
+
if (doc.nodeAt(cachedGlobalPosition)?.type.name === GLOBAL_CONTENT_NODE_TYPE) return cachedGlobalPosition;
|
|
1191
|
+
} catch {
|
|
1192
|
+
cachedGlobalPosition = null;
|
|
1193
|
+
}
|
|
1194
|
+
cachedGlobalPosition = findGlobalContentPositions(doc)[0] ?? null;
|
|
1195
|
+
return cachedGlobalPosition;
|
|
1196
|
+
}
|
|
1197
|
+
function getGlobalContent(key, editor) {
|
|
1198
|
+
const position = getCachedGlobalContentPosition(editor.state.doc);
|
|
1199
|
+
if (cachedGlobalPosition == null) return null;
|
|
1200
|
+
return editor.state.doc.nodeAt(position)?.attrs.data[key] ?? null;
|
|
1201
|
+
}
|
|
1202
|
+
const GlobalContent = Node$1.create({
|
|
1203
|
+
name: GLOBAL_CONTENT_NODE_TYPE,
|
|
1204
|
+
addOptions() {
|
|
1205
|
+
return {
|
|
1206
|
+
key: GLOBAL_CONTENT_NODE_TYPE,
|
|
1207
|
+
data: {}
|
|
1208
|
+
};
|
|
1209
|
+
},
|
|
1210
|
+
group: "block",
|
|
1211
|
+
selectable: false,
|
|
1212
|
+
draggable: false,
|
|
1213
|
+
atom: true,
|
|
1214
|
+
addAttributes() {
|
|
1215
|
+
return { data: { default: this.options.data } };
|
|
1216
|
+
},
|
|
1217
|
+
parseHTML() {
|
|
1218
|
+
return [{ tag: `div[data-type="${this.name}"]` }];
|
|
1219
|
+
},
|
|
1220
|
+
renderHTML({ HTMLAttributes }) {
|
|
1221
|
+
return ["div", mergeAttributes(HTMLAttributes, {
|
|
1222
|
+
"data-type": this.name,
|
|
1223
|
+
style: "width: 100%; height: 1px; visibility: hidden;"
|
|
1224
|
+
})];
|
|
1225
|
+
},
|
|
1226
|
+
addCommands() {
|
|
1227
|
+
return { setGlobalContent: (key, value) => ({ tr, dispatch }) => {
|
|
1228
|
+
const ensureGlobalPosition = () => {
|
|
1229
|
+
const positions = findGlobalContentPositions(tr.doc);
|
|
1230
|
+
for (let i = positions.length - 1; i > 0; i--) tr.delete(positions[i], positions[i] + 1);
|
|
1231
|
+
const pos = positions[0] ?? -1;
|
|
1232
|
+
if (pos >= 0) cachedGlobalPosition = pos;
|
|
1233
|
+
else {
|
|
1234
|
+
cachedGlobalPosition = 0;
|
|
1235
|
+
tr.insert(0, this.type.create());
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
if (dispatch) {
|
|
1239
|
+
ensureGlobalPosition();
|
|
1240
|
+
if (cachedGlobalPosition == null) return false;
|
|
1241
|
+
tr.setNodeAttribute(cachedGlobalPosition, "data", {
|
|
1242
|
+
...tr.doc.nodeAt(cachedGlobalPosition)?.attrs.data,
|
|
1243
|
+
[key]: value
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
return true;
|
|
1247
|
+
} };
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1135
1251
|
//#endregion
|
|
1136
1252
|
//#region src/extensions/hard-break.tsx
|
|
1137
1253
|
const HardBreak = EmailNode.from(HardBreakBase, () => /* @__PURE__ */ jsx("br", {}));
|
|
1138
1254
|
|
|
1255
|
+
//#endregion
|
|
1256
|
+
//#region src/extensions/heading.tsx
|
|
1257
|
+
const Heading = EmailNode.from(Heading$2.extend({ addNodeView() {
|
|
1258
|
+
return ReactNodeViewRenderer(({ node }) => {
|
|
1259
|
+
const level = node.attrs.level ?? 1;
|
|
1260
|
+
const { class: className, ...rest } = node.attrs;
|
|
1261
|
+
const attrs = {
|
|
1262
|
+
...rest,
|
|
1263
|
+
className: `node-h${level} ${className}`,
|
|
1264
|
+
style: inlineCssToJs(node.attrs.style)
|
|
1265
|
+
};
|
|
1266
|
+
return /* @__PURE__ */ jsx(NodeViewWrapper, { children: /* @__PURE__ */ jsx(Heading$1, {
|
|
1267
|
+
as: `h${level}`,
|
|
1268
|
+
...attrs,
|
|
1269
|
+
children: /* @__PURE__ */ jsx(NodeViewContent, {})
|
|
1270
|
+
}) });
|
|
1271
|
+
});
|
|
1272
|
+
} }), ({ children, node, style }) => {
|
|
1273
|
+
return /* @__PURE__ */ jsx(Heading$1, {
|
|
1274
|
+
as: `h${node.attrs?.level ?? 1}`,
|
|
1275
|
+
className: node.attrs?.class || void 0,
|
|
1276
|
+
style: {
|
|
1277
|
+
...style,
|
|
1278
|
+
...inlineCssToJs(node.attrs?.style),
|
|
1279
|
+
...getTextAlignment(node.attrs?.align ?? node.attrs?.alignment)
|
|
1280
|
+
},
|
|
1281
|
+
children
|
|
1282
|
+
});
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1139
1285
|
//#endregion
|
|
1140
1286
|
//#region src/extensions/italic.tsx
|
|
1141
1287
|
const Italic = EmailMark.from(ItalicBase, ({ children, style }) => /* @__PURE__ */ jsx("em", {
|
|
@@ -1143,6 +1289,160 @@ const Italic = EmailMark.from(ItalicBase, ({ children, style }) => /* @__PURE__
|
|
|
1143
1289
|
children
|
|
1144
1290
|
}));
|
|
1145
1291
|
|
|
1292
|
+
//#endregion
|
|
1293
|
+
//#region src/extensions/preserved-style.tsx
|
|
1294
|
+
const PreservedStyle = EmailMark.create({
|
|
1295
|
+
name: "preservedStyle",
|
|
1296
|
+
addAttributes() {
|
|
1297
|
+
return { style: {
|
|
1298
|
+
default: null,
|
|
1299
|
+
parseHTML: (element) => element.getAttribute("style"),
|
|
1300
|
+
renderHTML: (attributes) => {
|
|
1301
|
+
if (!attributes.style) return {};
|
|
1302
|
+
return { style: attributes.style };
|
|
1303
|
+
}
|
|
1304
|
+
} };
|
|
1305
|
+
},
|
|
1306
|
+
parseHTML() {
|
|
1307
|
+
return [{
|
|
1308
|
+
tag: "span[style]",
|
|
1309
|
+
getAttrs: (element) => {
|
|
1310
|
+
if (typeof element === "string") return false;
|
|
1311
|
+
const style = element.getAttribute("style");
|
|
1312
|
+
if (style && hasPreservableStyles(style)) return { style };
|
|
1313
|
+
return false;
|
|
1314
|
+
}
|
|
1315
|
+
}];
|
|
1316
|
+
},
|
|
1317
|
+
renderHTML({ HTMLAttributes }) {
|
|
1318
|
+
return [
|
|
1319
|
+
"span",
|
|
1320
|
+
mergeAttributes(HTMLAttributes),
|
|
1321
|
+
0
|
|
1322
|
+
];
|
|
1323
|
+
},
|
|
1324
|
+
renderToReactEmail({ children, mark }) {
|
|
1325
|
+
return /* @__PURE__ */ jsx("span", {
|
|
1326
|
+
style: mark.attrs?.style ? inlineCssToJs(mark.attrs.style) : void 0,
|
|
1327
|
+
children
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
});
|
|
1331
|
+
const LINK_INDICATOR_STYLES = [
|
|
1332
|
+
"color",
|
|
1333
|
+
"text-decoration",
|
|
1334
|
+
"text-decoration-line",
|
|
1335
|
+
"text-decoration-color",
|
|
1336
|
+
"text-decoration-style"
|
|
1337
|
+
];
|
|
1338
|
+
function parseStyleString(styleString) {
|
|
1339
|
+
const temp = document.createElement("div");
|
|
1340
|
+
temp.style.cssText = styleString;
|
|
1341
|
+
return temp.style;
|
|
1342
|
+
}
|
|
1343
|
+
function hasBackground(style) {
|
|
1344
|
+
const bgColor = style.backgroundColor;
|
|
1345
|
+
const bg = style.background;
|
|
1346
|
+
if (bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") return true;
|
|
1347
|
+
if (bg && bg !== "transparent" && bg !== "none" && bg !== "rgba(0, 0, 0, 0)") return true;
|
|
1348
|
+
return false;
|
|
1349
|
+
}
|
|
1350
|
+
function hasPreservableStyles(styleString) {
|
|
1351
|
+
return processStylesForUnlink(styleString) !== null;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Processes styles when unlinking:
|
|
1355
|
+
* - Has background (button-like): preserve all styles
|
|
1356
|
+
* - No background: strip link-indicator styles (color, text-decoration), keep the rest
|
|
1357
|
+
*/
|
|
1358
|
+
function processStylesForUnlink(styleString) {
|
|
1359
|
+
if (!styleString) return null;
|
|
1360
|
+
const style = parseStyleString(styleString);
|
|
1361
|
+
if (hasBackground(style)) return styleString;
|
|
1362
|
+
const filtered = [];
|
|
1363
|
+
for (let i = 0; i < style.length; i++) {
|
|
1364
|
+
const prop = style[i];
|
|
1365
|
+
if (LINK_INDICATOR_STYLES.includes(prop)) continue;
|
|
1366
|
+
const value = style.getPropertyValue(prop);
|
|
1367
|
+
if (value) filtered.push(`${prop}: ${value}`);
|
|
1368
|
+
}
|
|
1369
|
+
return filtered.length > 0 ? filtered.join("; ") : null;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
//#endregion
|
|
1373
|
+
//#region src/extensions/link.tsx
|
|
1374
|
+
const Link = EmailMark.from(TiptapLink, ({ children, mark, style }) => {
|
|
1375
|
+
const linkMarkStyle = mark.attrs?.style ? inlineCssToJs(mark.attrs.style) : {};
|
|
1376
|
+
return /* @__PURE__ */ jsx(Link$1, {
|
|
1377
|
+
href: mark.attrs?.href ?? void 0,
|
|
1378
|
+
rel: mark.attrs?.rel ?? void 0,
|
|
1379
|
+
style: {
|
|
1380
|
+
...style,
|
|
1381
|
+
...linkMarkStyle
|
|
1382
|
+
},
|
|
1383
|
+
target: mark.attrs?.target ?? void 0,
|
|
1384
|
+
...mark.attrs?.["ses:no-track"] ? { "ses:no-track": mark.attrs["ses:no-track"] } : {},
|
|
1385
|
+
children
|
|
1386
|
+
});
|
|
1387
|
+
}).extend({
|
|
1388
|
+
parseHTML() {
|
|
1389
|
+
return [{
|
|
1390
|
+
tag: "a[target]:not([data-id=\"react-email-button\"])",
|
|
1391
|
+
getAttrs: (node) => {
|
|
1392
|
+
if (typeof node === "string") return false;
|
|
1393
|
+
const element = node;
|
|
1394
|
+
const attrs = {};
|
|
1395
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
1396
|
+
attrs[attr.name] = attr.value;
|
|
1397
|
+
});
|
|
1398
|
+
return attrs;
|
|
1399
|
+
}
|
|
1400
|
+
}, {
|
|
1401
|
+
tag: "a[href]:not([data-id=\"react-email-button\"])",
|
|
1402
|
+
getAttrs: (node) => {
|
|
1403
|
+
if (typeof node === "string") return false;
|
|
1404
|
+
const element = node;
|
|
1405
|
+
const attrs = {};
|
|
1406
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
1407
|
+
attrs[attr.name] = attr.value;
|
|
1408
|
+
});
|
|
1409
|
+
return attrs;
|
|
1410
|
+
}
|
|
1411
|
+
}];
|
|
1412
|
+
},
|
|
1413
|
+
addAttributes() {
|
|
1414
|
+
return {
|
|
1415
|
+
...this.parent?.(),
|
|
1416
|
+
"ses:no-track": {
|
|
1417
|
+
default: null,
|
|
1418
|
+
parseHTML: (element) => element.getAttribute("ses:no-track")
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
},
|
|
1422
|
+
addCommands() {
|
|
1423
|
+
return {
|
|
1424
|
+
...this.parent?.(),
|
|
1425
|
+
unsetLink: () => ({ state, chain }) => {
|
|
1426
|
+
const { from } = state.selection;
|
|
1427
|
+
const linkStyle = state.doc.resolve(from).marks().find((m) => m.type.name === "link")?.attrs?.style ?? null;
|
|
1428
|
+
const preservedStyle = processStylesForUnlink(linkStyle);
|
|
1429
|
+
const shouldRemoveUnderline = preservedStyle !== linkStyle;
|
|
1430
|
+
if (preservedStyle) {
|
|
1431
|
+
const cmd = chain().extendMarkRange("link").unsetMark("link").setMark("preservedStyle", { style: preservedStyle });
|
|
1432
|
+
return shouldRemoveUnderline ? cmd.unsetMark("underline").run() : cmd.run();
|
|
1433
|
+
}
|
|
1434
|
+
return chain().extendMarkRange("link").unsetMark("link").unsetMark("underline").run();
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
},
|
|
1438
|
+
addKeyboardShortcuts() {
|
|
1439
|
+
return { "Mod-k": () => {
|
|
1440
|
+
editorEventBus.dispatch("bubble-menu:add-link", void 0);
|
|
1441
|
+
return this.editor.chain().focus().toggleLink({ href: "" }).run();
|
|
1442
|
+
} };
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
1445
|
+
|
|
1146
1446
|
//#endregion
|
|
1147
1447
|
//#region src/extensions/list-item.tsx
|
|
1148
1448
|
const ListItem = EmailNode.from(ListItemBase, ({ children, node, style }) => /* @__PURE__ */ jsx("li", {
|
|
@@ -1267,86 +1567,6 @@ const Placeholder = TipTapPlaceholder.configure({
|
|
|
1267
1567
|
includeChildren: true
|
|
1268
1568
|
});
|
|
1269
1569
|
|
|
1270
|
-
//#endregion
|
|
1271
|
-
//#region src/extensions/preserved-style.tsx
|
|
1272
|
-
const PreservedStyle = EmailMark.create({
|
|
1273
|
-
name: "preservedStyle",
|
|
1274
|
-
addAttributes() {
|
|
1275
|
-
return { style: {
|
|
1276
|
-
default: null,
|
|
1277
|
-
parseHTML: (element) => element.getAttribute("style"),
|
|
1278
|
-
renderHTML: (attributes) => {
|
|
1279
|
-
if (!attributes.style) return {};
|
|
1280
|
-
return { style: attributes.style };
|
|
1281
|
-
}
|
|
1282
|
-
} };
|
|
1283
|
-
},
|
|
1284
|
-
parseHTML() {
|
|
1285
|
-
return [{
|
|
1286
|
-
tag: "span[style]",
|
|
1287
|
-
getAttrs: (element) => {
|
|
1288
|
-
if (typeof element === "string") return false;
|
|
1289
|
-
const style = element.getAttribute("style");
|
|
1290
|
-
if (style && hasPreservableStyles(style)) return { style };
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
}];
|
|
1294
|
-
},
|
|
1295
|
-
renderHTML({ HTMLAttributes }) {
|
|
1296
|
-
return [
|
|
1297
|
-
"span",
|
|
1298
|
-
mergeAttributes(HTMLAttributes),
|
|
1299
|
-
0
|
|
1300
|
-
];
|
|
1301
|
-
},
|
|
1302
|
-
renderToReactEmail({ children, mark }) {
|
|
1303
|
-
return /* @__PURE__ */ jsx("span", {
|
|
1304
|
-
style: mark.attrs?.style ? inlineCssToJs(mark.attrs.style) : void 0,
|
|
1305
|
-
children
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1308
|
-
});
|
|
1309
|
-
const LINK_INDICATOR_STYLES = [
|
|
1310
|
-
"color",
|
|
1311
|
-
"text-decoration",
|
|
1312
|
-
"text-decoration-line",
|
|
1313
|
-
"text-decoration-color",
|
|
1314
|
-
"text-decoration-style"
|
|
1315
|
-
];
|
|
1316
|
-
function parseStyleString(styleString) {
|
|
1317
|
-
const temp = document.createElement("div");
|
|
1318
|
-
temp.style.cssText = styleString;
|
|
1319
|
-
return temp.style;
|
|
1320
|
-
}
|
|
1321
|
-
function hasBackground(style) {
|
|
1322
|
-
const bgColor = style.backgroundColor;
|
|
1323
|
-
const bg = style.background;
|
|
1324
|
-
if (bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") return true;
|
|
1325
|
-
if (bg && bg !== "transparent" && bg !== "none" && bg !== "rgba(0, 0, 0, 0)") return true;
|
|
1326
|
-
return false;
|
|
1327
|
-
}
|
|
1328
|
-
function hasPreservableStyles(styleString) {
|
|
1329
|
-
return processStylesForUnlink(styleString) !== null;
|
|
1330
|
-
}
|
|
1331
|
-
/**
|
|
1332
|
-
* Processes styles when unlinking:
|
|
1333
|
-
* - Has background (button-like): preserve all styles
|
|
1334
|
-
* - No background: strip link-indicator styles (color, text-decoration), keep the rest
|
|
1335
|
-
*/
|
|
1336
|
-
function processStylesForUnlink(styleString) {
|
|
1337
|
-
if (!styleString) return null;
|
|
1338
|
-
const style = parseStyleString(styleString);
|
|
1339
|
-
if (hasBackground(style)) return styleString;
|
|
1340
|
-
const filtered = [];
|
|
1341
|
-
for (let i = 0; i < style.length; i++) {
|
|
1342
|
-
const prop = style[i];
|
|
1343
|
-
if (LINK_INDICATOR_STYLES.includes(prop)) continue;
|
|
1344
|
-
const value = style.getPropertyValue(prop);
|
|
1345
|
-
if (value) filtered.push(`${prop}: ${value}`);
|
|
1346
|
-
}
|
|
1347
|
-
return filtered.length > 0 ? filtered.join("; ") : null;
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
1570
|
//#endregion
|
|
1351
1571
|
//#region src/extensions/preview-text.ts
|
|
1352
1572
|
const PreviewText = Node$1.create({
|
|
@@ -1938,44 +2158,13 @@ const ColumnsColumn = EmailNode.create({
|
|
|
1938
2158
|
|
|
1939
2159
|
//#endregion
|
|
1940
2160
|
//#region src/extensions/index.ts
|
|
1941
|
-
const
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
bold: false,
|
|
1949
|
-
italic: false,
|
|
1950
|
-
strike: false,
|
|
1951
|
-
code: false,
|
|
1952
|
-
paragraph: false,
|
|
1953
|
-
bulletList: false,
|
|
1954
|
-
orderedList: false,
|
|
1955
|
-
listItem: false,
|
|
1956
|
-
blockquote: false,
|
|
1957
|
-
hardBreak: false,
|
|
1958
|
-
gapcursor: false,
|
|
1959
|
-
codeBlock: false,
|
|
1960
|
-
horizontalRule: false,
|
|
1961
|
-
dropcursor: {
|
|
1962
|
-
color: "#61a8f8",
|
|
1963
|
-
class: "rounded-full animate-[fade-in_300ms_ease-in-out] !z-40",
|
|
1964
|
-
width: 4
|
|
1965
|
-
}
|
|
1966
|
-
}),
|
|
1967
|
-
CodeBlockPrism.configure({
|
|
1968
|
-
defaultLanguage: "javascript",
|
|
1969
|
-
HTMLAttributes: { class: "prism node-codeBlock" }
|
|
1970
|
-
}),
|
|
1971
|
-
Code.configure({ HTMLAttributes: {
|
|
1972
|
-
class: "node-inlineCode",
|
|
1973
|
-
spellcheck: "false"
|
|
1974
|
-
} }),
|
|
1975
|
-
Paragraph.configure({ HTMLAttributes: { class: "node-paragraph" } }),
|
|
1976
|
-
BulletList.configure({ HTMLAttributes: { class: "node-bulletList" } }),
|
|
1977
|
-
OrderedList.configure({ HTMLAttributes: { class: "node-orderedList" } }),
|
|
1978
|
-
Blockquote.configure({ HTMLAttributes: { class: "node-blockquote" } }),
|
|
2161
|
+
const starterKitExtensions = {
|
|
2162
|
+
CodeBlockPrism,
|
|
2163
|
+
Code,
|
|
2164
|
+
Paragraph,
|
|
2165
|
+
BulletList,
|
|
2166
|
+
OrderedList,
|
|
2167
|
+
Blockquote,
|
|
1979
2168
|
ListItem,
|
|
1980
2169
|
HardBreak,
|
|
1981
2170
|
Italic,
|
|
@@ -1983,6 +2172,9 @@ const coreExtensions = [
|
|
|
1983
2172
|
PreviewText,
|
|
1984
2173
|
Bold,
|
|
1985
2174
|
Strike,
|
|
2175
|
+
Heading,
|
|
2176
|
+
Divider,
|
|
2177
|
+
Link,
|
|
1986
2178
|
Sup,
|
|
1987
2179
|
Uppercase,
|
|
1988
2180
|
PreservedStyle,
|
|
@@ -1994,80 +2186,162 @@ const coreExtensions = [
|
|
|
1994
2186
|
Div,
|
|
1995
2187
|
Button,
|
|
1996
2188
|
Section,
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2189
|
+
GlobalContent,
|
|
2190
|
+
AlignmentAttribute,
|
|
2191
|
+
StyleAttribute,
|
|
2192
|
+
ClassAttribute,
|
|
2193
|
+
MaxNesting
|
|
2194
|
+
};
|
|
2195
|
+
const StarterKit = Extension.create({
|
|
2196
|
+
name: "reactEmailStarterKit",
|
|
2197
|
+
addOptions() {
|
|
2198
|
+
return {
|
|
2199
|
+
TiptapStarterKit: {},
|
|
2200
|
+
CodeBlockPrism: {
|
|
2201
|
+
defaultLanguage: "javascript",
|
|
2202
|
+
HTMLAttributes: { class: "prism node-codeBlock" }
|
|
2203
|
+
},
|
|
2204
|
+
Code: { HTMLAttributes: {
|
|
2205
|
+
class: "node-inlineCode",
|
|
2206
|
+
spellcheck: "false"
|
|
2207
|
+
} },
|
|
2208
|
+
Paragraph: { HTMLAttributes: { class: "node-paragraph" } },
|
|
2209
|
+
BulletList: { HTMLAttributes: { class: "node-bulletList" } },
|
|
2210
|
+
OrderedList: { HTMLAttributes: { class: "node-orderedList" } },
|
|
2211
|
+
Blockquote: { HTMLAttributes: { class: "node-blockquote" } },
|
|
2212
|
+
ListItem: {},
|
|
2213
|
+
HardBreak: {},
|
|
2214
|
+
Italic: {},
|
|
2215
|
+
Placeholder: {},
|
|
2216
|
+
PreviewText: {},
|
|
2217
|
+
Bold: {},
|
|
2218
|
+
Strike: {},
|
|
2219
|
+
Heading: {},
|
|
2220
|
+
Divider: {},
|
|
2221
|
+
Link: {},
|
|
2222
|
+
Sup: {},
|
|
2223
|
+
Uppercase: {},
|
|
2224
|
+
PreservedStyle: {},
|
|
2225
|
+
Table: {},
|
|
2226
|
+
TableRow: {},
|
|
2227
|
+
TableCell: {},
|
|
2228
|
+
TableHeader: {},
|
|
2229
|
+
Body: {},
|
|
2230
|
+
Div: {},
|
|
2231
|
+
Button: {},
|
|
2232
|
+
Section: {},
|
|
2233
|
+
GlobalContent: {},
|
|
2234
|
+
AlignmentAttribute: { types: [
|
|
2235
|
+
"heading",
|
|
2236
|
+
"paragraph",
|
|
2237
|
+
"image",
|
|
2238
|
+
"blockquote",
|
|
2239
|
+
"codeBlock",
|
|
2240
|
+
"bulletList",
|
|
2241
|
+
"orderedList",
|
|
2242
|
+
"listItem",
|
|
2243
|
+
"button",
|
|
2244
|
+
"youtube",
|
|
2245
|
+
"twitter",
|
|
2246
|
+
"table",
|
|
2247
|
+
"tableRow",
|
|
2248
|
+
"tableCell",
|
|
2249
|
+
"tableHeader",
|
|
2250
|
+
"columnsColumn"
|
|
2251
|
+
] },
|
|
2252
|
+
StyleAttribute: { types: [
|
|
2253
|
+
"heading",
|
|
2254
|
+
"paragraph",
|
|
2255
|
+
"image",
|
|
2256
|
+
"blockquote",
|
|
2257
|
+
"codeBlock",
|
|
2258
|
+
"bulletList",
|
|
2259
|
+
"orderedList",
|
|
2260
|
+
"listItem",
|
|
2261
|
+
"button",
|
|
2262
|
+
"youtube",
|
|
2263
|
+
"twitter",
|
|
2264
|
+
"horizontalRule",
|
|
2265
|
+
"footer",
|
|
2266
|
+
"section",
|
|
2267
|
+
"div",
|
|
2268
|
+
"body",
|
|
2269
|
+
"table",
|
|
2270
|
+
"tableRow",
|
|
2271
|
+
"tableCell",
|
|
2272
|
+
"tableHeader",
|
|
2273
|
+
"columnsColumn",
|
|
2274
|
+
"link"
|
|
2275
|
+
] },
|
|
2276
|
+
ClassAttribute: { types: [
|
|
2277
|
+
"heading",
|
|
2278
|
+
"paragraph",
|
|
2279
|
+
"image",
|
|
2280
|
+
"blockquote",
|
|
2281
|
+
"bulletList",
|
|
2282
|
+
"orderedList",
|
|
2283
|
+
"listItem",
|
|
2284
|
+
"button",
|
|
2285
|
+
"youtube",
|
|
2286
|
+
"twitter",
|
|
2287
|
+
"horizontalRule",
|
|
2288
|
+
"footer",
|
|
2289
|
+
"section",
|
|
2290
|
+
"div",
|
|
2291
|
+
"body",
|
|
2292
|
+
"table",
|
|
2293
|
+
"tableRow",
|
|
2294
|
+
"tableCell",
|
|
2295
|
+
"tableHeader",
|
|
2296
|
+
"columnsColumn",
|
|
2297
|
+
"link"
|
|
2298
|
+
] },
|
|
2299
|
+
MaxNesting: {
|
|
2300
|
+
maxDepth: 50,
|
|
2301
|
+
nodeTypes: [
|
|
2302
|
+
"section",
|
|
2303
|
+
"bulletList",
|
|
2304
|
+
"orderedList"
|
|
2305
|
+
]
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2308
|
+
},
|
|
2309
|
+
addExtensions() {
|
|
2310
|
+
const extensions = [];
|
|
2311
|
+
if (this.options.TiptapStarterKit !== false) extensions.push(TipTapStarterKit.configure({
|
|
2312
|
+
undoRedo: false,
|
|
2313
|
+
heading: false,
|
|
2314
|
+
link: false,
|
|
2315
|
+
underline: false,
|
|
2316
|
+
trailingNode: false,
|
|
2317
|
+
bold: false,
|
|
2318
|
+
italic: false,
|
|
2319
|
+
strike: false,
|
|
2320
|
+
code: false,
|
|
2321
|
+
paragraph: false,
|
|
2322
|
+
bulletList: false,
|
|
2323
|
+
orderedList: false,
|
|
2324
|
+
listItem: false,
|
|
2325
|
+
blockquote: false,
|
|
2326
|
+
hardBreak: false,
|
|
2327
|
+
gapcursor: false,
|
|
2328
|
+
codeBlock: false,
|
|
2329
|
+
horizontalRule: false,
|
|
2330
|
+
dropcursor: {
|
|
2331
|
+
color: "#61a8f8",
|
|
2332
|
+
class: "rounded-full animate-[fade-in_300ms_ease-in-out] !z-40",
|
|
2333
|
+
width: 4
|
|
2334
|
+
},
|
|
2335
|
+
...this.options.TiptapStarterKit
|
|
2336
|
+
}));
|
|
2337
|
+
for (const [name, extension] of Object.entries(starterKitExtensions)) {
|
|
2338
|
+
const key = name;
|
|
2339
|
+
const extensionOptions = this.options[key];
|
|
2340
|
+
if (extensionOptions !== false) extensions.push(extension.configure(extensionOptions));
|
|
2341
|
+
}
|
|
2342
|
+
return extensions;
|
|
2343
|
+
}
|
|
2344
|
+
});
|
|
2071
2345
|
|
|
2072
2346
|
//#endregion
|
|
2073
2347
|
//#region src/core/create-drop-handler.ts
|
|
@@ -2226,13 +2500,14 @@ function useEditor({ content, extensions = [], onUpdate, onPaste, onUploadImage,
|
|
|
2226
2500
|
const [contentError, setContentError] = React.useState(null);
|
|
2227
2501
|
const isCollaborative = hasCollaborationExtension(extensions);
|
|
2228
2502
|
const effectiveExtensions = React.useMemo(() => [
|
|
2229
|
-
|
|
2503
|
+
StarterKit,
|
|
2230
2504
|
...isCollaborative ? [] : [UndoRedo],
|
|
2231
2505
|
...extensions
|
|
2232
2506
|
], [extensions, isCollaborative]);
|
|
2233
2507
|
const editor = useEditor$1({
|
|
2234
2508
|
content: isCollaborative ? void 0 : content,
|
|
2235
2509
|
extensions: effectiveExtensions,
|
|
2510
|
+
editable,
|
|
2236
2511
|
immediatelyRender: false,
|
|
2237
2512
|
enableContentCheck: true,
|
|
2238
2513
|
onContentError({ editor: editor$1, error, disableCollaboration }) {
|
|
@@ -3846,5 +4121,5 @@ function createSlashCommand(options) {
|
|
|
3846
4121
|
const SlashCommand = createSlashCommand();
|
|
3847
4122
|
|
|
3848
4123
|
//#endregion
|
|
3849
|
-
export { AlignmentAttribute, BULLET_LIST, BUTTON, Blockquote, Body, Bold, BubbleMenu, BubbleMenuAlignCenter, BubbleMenuAlignLeft, BubbleMenuAlignRight, BubbleMenuBold, BubbleMenuCode, BubbleMenuDefault, BubbleMenuItalic, BubbleMenuItem, BubbleMenuItemGroup, BubbleMenuLinkSelector, BubbleMenuNodeSelector, BubbleMenuRoot, BubbleMenuSeparator, BubbleMenuStrike, BubbleMenuUnderline, BubbleMenuUppercase, BulletList, Button, ButtonBubbleMenu, ButtonBubbleMenuDefault, ButtonBubbleMenuEditLink, ButtonBubbleMenuRoot, ButtonBubbleMenuToolbar, CODE, COLUMN_PARENT_TYPES, ClassAttribute, Code, CodeBlockPrism, ColumnsColumn, CommandList, DIVIDER, Div, EmailNode, FOUR_COLUMNS, FourColumns, H1, H2, H3, HardBreak, ImageBubbleMenu, ImageBubbleMenuDefault, ImageBubbleMenuEditLink, ImageBubbleMenuRoot, ImageBubbleMenuToolbar, Italic, LinkBubbleMenu, LinkBubbleMenuDefault, LinkBubbleMenuEditLink, LinkBubbleMenuForm, LinkBubbleMenuOpenLink, LinkBubbleMenuRoot, LinkBubbleMenuToolbar, LinkBubbleMenuUnlink, ListItem, MAX_COLUMNS_DEPTH, MaxNesting, NUMBERED_LIST, NodeSelectorContent, NodeSelectorRoot, NodeSelectorTrigger, OrderedList, Paragraph, Placeholder, PreservedStyle, PreviewText, QUOTE, SECTION, Section, SlashCommand, Strike, StyleAttribute, Sup, TEXT, THREE_COLUMNS, TWO_COLUMNS, Table, TableCell, TableHeader, TableRow, ThreeColumns, TwoColumns, Uppercase, composeReactEmail,
|
|
4124
|
+
export { AlignmentAttribute, BULLET_LIST, BUTTON, Blockquote, Body, Bold, BubbleMenu, BubbleMenuAlignCenter, BubbleMenuAlignLeft, BubbleMenuAlignRight, BubbleMenuBold, BubbleMenuCode, BubbleMenuDefault, BubbleMenuItalic, BubbleMenuItem, BubbleMenuItemGroup, BubbleMenuLinkSelector, BubbleMenuNodeSelector, BubbleMenuRoot, BubbleMenuSeparator, BubbleMenuStrike, BubbleMenuUnderline, BubbleMenuUppercase, BulletList, Button, ButtonBubbleMenu, ButtonBubbleMenuDefault, ButtonBubbleMenuEditLink, ButtonBubbleMenuRoot, ButtonBubbleMenuToolbar, CODE, COLUMN_PARENT_TYPES, ClassAttribute, Code, CodeBlockPrism, ColumnsColumn, CommandList, DIVIDER, Div, Divider, EmailNode, FOUR_COLUMNS, FourColumns, GlobalContent, H1, H2, H3, HardBreak, Heading, ImageBubbleMenu, ImageBubbleMenuDefault, ImageBubbleMenuEditLink, ImageBubbleMenuRoot, ImageBubbleMenuToolbar, Italic, Link, LinkBubbleMenu, LinkBubbleMenuDefault, LinkBubbleMenuEditLink, LinkBubbleMenuForm, LinkBubbleMenuOpenLink, LinkBubbleMenuRoot, LinkBubbleMenuToolbar, LinkBubbleMenuUnlink, ListItem, MAX_COLUMNS_DEPTH, MaxNesting, NUMBERED_LIST, NodeSelectorContent, NodeSelectorRoot, NodeSelectorTrigger, OrderedList, Paragraph, Placeholder, PreservedStyle, PreviewText, QUOTE, SECTION, Section, SlashCommand, StarterKit, Strike, StyleAttribute, Sup, TEXT, THREE_COLUMNS, TWO_COLUMNS, Table, TableCell, TableHeader, TableRow, ThreeColumns, TwoColumns, Uppercase, composeReactEmail, createSlashCommand, defaultSlashCommands, editorEventBus, filterAndRankItems, getColumnsDepth, getGlobalContent, isAtMaxColumnsDepth, isInsideNode, processStylesForUnlink, scoreItem, setTextAlignment, useButtonBubbleMenuContext, useEditor, useImageBubbleMenuContext, useLinkBubbleMenuContext };
|
|
3850
4125
|
//# sourceMappingURL=index.mjs.map
|