@react-email/editor 0.0.0-experimental.15 → 0.0.0-experimental.16
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 +738 -215
- package/dist/index.d.cts +204 -87
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +164 -47
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +724 -221
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -5
package/dist/index.cjs
CHANGED
|
@@ -25,11 +25,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
28
|
-
let _tiptap_core = require("@tiptap/core");
|
|
29
|
-
let _tiptap_starter_kit = require("@tiptap/starter-kit");
|
|
30
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
31
28
|
let _react_email_components = require("@react-email/components");
|
|
32
29
|
_react_email_components = __toESM(_react_email_components);
|
|
30
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
let _tiptap_core = require("@tiptap/core");
|
|
32
|
+
let _tiptap_extensions = require("@tiptap/extensions");
|
|
33
|
+
let _tiptap_react = require("@tiptap/react");
|
|
34
|
+
let react = require("react");
|
|
35
|
+
react = __toESM(react);
|
|
36
|
+
let _tiptap_starter_kit = require("@tiptap/starter-kit");
|
|
37
|
+
let _tiptap_extension_blockquote = require("@tiptap/extension-blockquote");
|
|
38
|
+
_tiptap_extension_blockquote = __toESM(_tiptap_extension_blockquote);
|
|
39
|
+
let _tiptap_extension_bullet_list = require("@tiptap/extension-bullet-list");
|
|
40
|
+
_tiptap_extension_bullet_list = __toESM(_tiptap_extension_bullet_list);
|
|
41
|
+
let _tiptap_extension_code = require("@tiptap/extension-code");
|
|
42
|
+
_tiptap_extension_code = __toESM(_tiptap_extension_code);
|
|
33
43
|
let _tiptap_extension_code_block = require("@tiptap/extension-code-block");
|
|
34
44
|
_tiptap_extension_code_block = __toESM(_tiptap_extension_code_block);
|
|
35
45
|
let _tiptap_pm_state = require("@tiptap/pm/state");
|
|
@@ -37,12 +47,22 @@ let _tiptap_pm_view = require("@tiptap/pm/view");
|
|
|
37
47
|
let hast_util_from_html = require("hast-util-from-html");
|
|
38
48
|
let prismjs = require("prismjs");
|
|
39
49
|
prismjs = __toESM(prismjs);
|
|
50
|
+
let _tiptap_extension_hard_break = require("@tiptap/extension-hard-break");
|
|
51
|
+
_tiptap_extension_hard_break = __toESM(_tiptap_extension_hard_break);
|
|
52
|
+
let _tiptap_extension_italic = require("@tiptap/extension-italic");
|
|
53
|
+
_tiptap_extension_italic = __toESM(_tiptap_extension_italic);
|
|
54
|
+
let _tiptap_extension_list_item = require("@tiptap/extension-list-item");
|
|
55
|
+
_tiptap_extension_list_item = __toESM(_tiptap_extension_list_item);
|
|
56
|
+
let _tiptap_extension_ordered_list = require("@tiptap/extension-ordered-list");
|
|
57
|
+
_tiptap_extension_ordered_list = __toESM(_tiptap_extension_ordered_list);
|
|
58
|
+
let _tiptap_extension_paragraph = require("@tiptap/extension-paragraph");
|
|
59
|
+
_tiptap_extension_paragraph = __toESM(_tiptap_extension_paragraph);
|
|
40
60
|
let _tiptap_extension_placeholder = require("@tiptap/extension-placeholder");
|
|
41
61
|
_tiptap_extension_placeholder = __toESM(_tiptap_extension_placeholder);
|
|
42
|
-
let
|
|
62
|
+
let _tiptap_extension_strike = require("@tiptap/extension-strike");
|
|
63
|
+
_tiptap_extension_strike = __toESM(_tiptap_extension_strike);
|
|
64
|
+
let _tiptap_html = require("@tiptap/html");
|
|
43
65
|
let lucide_react = require("lucide-react");
|
|
44
|
-
let react = require("react");
|
|
45
|
-
react = __toESM(react);
|
|
46
66
|
let _radix_ui_react_popover = require("@radix-ui/react-popover");
|
|
47
67
|
_radix_ui_react_popover = __toESM(_radix_ui_react_popover);
|
|
48
68
|
let _tiptap_react_menus = require("@tiptap/react/menus");
|
|
@@ -51,37 +71,6 @@ _tiptap_suggestion = __toESM(_tiptap_suggestion);
|
|
|
51
71
|
let tippy_js = require("tippy.js");
|
|
52
72
|
tippy_js = __toESM(tippy_js);
|
|
53
73
|
|
|
54
|
-
//#region src/core/email-node.ts
|
|
55
|
-
var EmailNode = class EmailNode extends _tiptap_core.Node {
|
|
56
|
-
constructor(config) {
|
|
57
|
-
super(config);
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Create a new Node instance
|
|
61
|
-
* @param config - Node configuration object or a function that returns a configuration object
|
|
62
|
-
*/
|
|
63
|
-
static create(config) {
|
|
64
|
-
return new EmailNode(typeof config === "function" ? config() : config);
|
|
65
|
-
}
|
|
66
|
-
static from(node, renderToReactEmail) {
|
|
67
|
-
const customNode = EmailNode.create({});
|
|
68
|
-
Object.assign(customNode, { ...node });
|
|
69
|
-
customNode.config = {
|
|
70
|
-
...node.config,
|
|
71
|
-
renderToReactEmail
|
|
72
|
-
};
|
|
73
|
-
return customNode;
|
|
74
|
-
}
|
|
75
|
-
configure(options) {
|
|
76
|
-
return super.configure(options);
|
|
77
|
-
}
|
|
78
|
-
extend(extendedConfig) {
|
|
79
|
-
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
80
|
-
return super.extend(resolvedConfig);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
//#endregion
|
|
85
74
|
//#region src/core/event-bus.ts
|
|
86
75
|
const EVENT_PREFIX = "@react-email/editor:";
|
|
87
76
|
var EditorEventBus = class {
|
|
@@ -123,139 +112,6 @@ var EditorEventBus = class {
|
|
|
123
112
|
};
|
|
124
113
|
const editorEventBus = new EditorEventBus();
|
|
125
114
|
|
|
126
|
-
//#endregion
|
|
127
|
-
//#region src/extensions/alignment-attribute.tsx
|
|
128
|
-
const AlignmentAttribute = _tiptap_core.Extension.create({
|
|
129
|
-
name: "alignmentAttribute",
|
|
130
|
-
addOptions() {
|
|
131
|
-
return {
|
|
132
|
-
types: [],
|
|
133
|
-
alignments: [
|
|
134
|
-
"left",
|
|
135
|
-
"center",
|
|
136
|
-
"right",
|
|
137
|
-
"justify"
|
|
138
|
-
]
|
|
139
|
-
};
|
|
140
|
-
},
|
|
141
|
-
addGlobalAttributes() {
|
|
142
|
-
return [{
|
|
143
|
-
types: this.options.types,
|
|
144
|
-
attributes: { alignment: {
|
|
145
|
-
parseHTML: (element) => {
|
|
146
|
-
const explicitAlign = element.getAttribute("align") || element.getAttribute("alignment") || element.style.textAlign;
|
|
147
|
-
if (explicitAlign && this.options.alignments.includes(explicitAlign)) return explicitAlign;
|
|
148
|
-
return null;
|
|
149
|
-
},
|
|
150
|
-
renderHTML: (attributes) => {
|
|
151
|
-
if (attributes.alignment === "left") return {};
|
|
152
|
-
return { alignment: attributes.alignment };
|
|
153
|
-
}
|
|
154
|
-
} }
|
|
155
|
-
}];
|
|
156
|
-
},
|
|
157
|
-
addCommands() {
|
|
158
|
-
return { setAlignment: (alignment) => ({ commands }) => {
|
|
159
|
-
if (!this.options.alignments.includes(alignment)) return false;
|
|
160
|
-
return this.options.types.every((type) => commands.updateAttributes(type, { alignment }));
|
|
161
|
-
} };
|
|
162
|
-
},
|
|
163
|
-
addKeyboardShortcuts() {
|
|
164
|
-
return {
|
|
165
|
-
Enter: () => {
|
|
166
|
-
const { from } = this.editor.state.selection;
|
|
167
|
-
const currentAlignment = this.editor.state.doc.nodeAt(from)?.attrs?.alignment;
|
|
168
|
-
if (currentAlignment) requestAnimationFrame(() => {
|
|
169
|
-
this.editor.commands.setAlignment(currentAlignment);
|
|
170
|
-
});
|
|
171
|
-
return false;
|
|
172
|
-
},
|
|
173
|
-
"Mod-Shift-l": () => this.editor.commands.setAlignment("left"),
|
|
174
|
-
"Mod-Shift-e": () => this.editor.commands.setAlignment("center"),
|
|
175
|
-
"Mod-Shift-r": () => this.editor.commands.setAlignment("right"),
|
|
176
|
-
"Mod-Shift-j": () => this.editor.commands.setAlignment("justify")
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
//#endregion
|
|
182
|
-
//#region src/utils/attribute-helpers.ts
|
|
183
|
-
/**
|
|
184
|
-
* Creates TipTap attribute definitions for a list of HTML attributes.
|
|
185
|
-
* Each attribute will have the same pattern:
|
|
186
|
-
* - default: null
|
|
187
|
-
* - parseHTML: extracts the attribute from the element
|
|
188
|
-
* - renderHTML: conditionally renders the attribute if it has a value
|
|
189
|
-
*
|
|
190
|
-
* @param attributeNames - Array of HTML attribute names to create definitions for
|
|
191
|
-
* @returns Object with TipTap attribute definitions
|
|
192
|
-
*
|
|
193
|
-
* @example
|
|
194
|
-
* const attrs = createStandardAttributes(['class', 'id', 'title']);
|
|
195
|
-
* // Returns:
|
|
196
|
-
* // {
|
|
197
|
-
* // class: {
|
|
198
|
-
* // default: null,
|
|
199
|
-
* // parseHTML: (element) => element.getAttribute('class'),
|
|
200
|
-
* // renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}
|
|
201
|
-
* // },
|
|
202
|
-
* // ...
|
|
203
|
-
* // }
|
|
204
|
-
*/
|
|
205
|
-
function createStandardAttributes(attributeNames) {
|
|
206
|
-
return Object.fromEntries(attributeNames.map((attr) => [attr, {
|
|
207
|
-
default: null,
|
|
208
|
-
parseHTML: (element) => element.getAttribute(attr),
|
|
209
|
-
renderHTML: (attributes) => {
|
|
210
|
-
if (!attributes[attr]) return {};
|
|
211
|
-
return { [attr]: attributes[attr] };
|
|
212
|
-
}
|
|
213
|
-
}]));
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Common HTML attributes used across multiple extensions.
|
|
217
|
-
* These preserve attributes during HTML import and editing for better
|
|
218
|
-
* fidelity when importing existing email templates.
|
|
219
|
-
*/
|
|
220
|
-
const COMMON_HTML_ATTRIBUTES = [
|
|
221
|
-
"id",
|
|
222
|
-
"class",
|
|
223
|
-
"title",
|
|
224
|
-
"lang",
|
|
225
|
-
"dir",
|
|
226
|
-
"data-id"
|
|
227
|
-
];
|
|
228
|
-
/**
|
|
229
|
-
* Layout-specific HTML attributes used for positioning and sizing.
|
|
230
|
-
*/
|
|
231
|
-
const LAYOUT_ATTRIBUTES = [
|
|
232
|
-
"align",
|
|
233
|
-
"width",
|
|
234
|
-
"height"
|
|
235
|
-
];
|
|
236
|
-
/**
|
|
237
|
-
* Table-specific HTML attributes used for table layout and styling.
|
|
238
|
-
*/
|
|
239
|
-
const TABLE_ATTRIBUTES = [
|
|
240
|
-
"border",
|
|
241
|
-
"cellpadding",
|
|
242
|
-
"cellspacing"
|
|
243
|
-
];
|
|
244
|
-
/**
|
|
245
|
-
* Table cell-specific HTML attributes.
|
|
246
|
-
*/
|
|
247
|
-
const TABLE_CELL_ATTRIBUTES = [
|
|
248
|
-
"valign",
|
|
249
|
-
"bgcolor",
|
|
250
|
-
"colspan",
|
|
251
|
-
"rowspan"
|
|
252
|
-
];
|
|
253
|
-
/**
|
|
254
|
-
* Table header cell-specific HTML attributes.
|
|
255
|
-
* These are additional attributes that only apply to <th> elements.
|
|
256
|
-
*/
|
|
257
|
-
const TABLE_HEADER_ATTRIBUTES = [...TABLE_CELL_ATTRIBUTES, "scope"];
|
|
258
|
-
|
|
259
115
|
//#endregion
|
|
260
116
|
//#region src/utils/styles.ts
|
|
261
117
|
const WHITE_SPACE_REGEX = /\s+/;
|
|
@@ -425,6 +281,342 @@ function resolveConflictingStyles(resetStyles, inlineStyles) {
|
|
|
425
281
|
};
|
|
426
282
|
}
|
|
427
283
|
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/core/serializer/default-base-template.tsx
|
|
286
|
+
function DefaultBaseTemplate({ children, previewText }) {
|
|
287
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_email_components.Html, { children: [
|
|
288
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_email_components.Head, { children: [
|
|
289
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
|
|
290
|
+
content: "width=device-width",
|
|
291
|
+
name: "viewport"
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
|
|
294
|
+
content: "IE=edge",
|
|
295
|
+
httpEquiv: "X-UA-Compatible"
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", { name: "x-apple-disable-message-reformatting" }),
|
|
298
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
|
|
299
|
+
content: "telephone=no,address=no,email=no,date=no,url=no",
|
|
300
|
+
name: "format-detection"
|
|
301
|
+
})
|
|
302
|
+
] }),
|
|
303
|
+
previewText && previewText !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Preview, { children: previewText }),
|
|
304
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Body, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
|
|
305
|
+
width: "100%",
|
|
306
|
+
align: "center",
|
|
307
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_email_components.Section, {
|
|
308
|
+
style: { width: "100%" },
|
|
309
|
+
children
|
|
310
|
+
})
|
|
311
|
+
}) })
|
|
312
|
+
] });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/core/serializer/email-mark.ts
|
|
317
|
+
var EmailMark = class EmailMark extends _tiptap_core.Mark {
|
|
318
|
+
constructor(config) {
|
|
319
|
+
super(config);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Create a new Mark instance
|
|
323
|
+
* @param config - Mark configuration object or a function that returns a configuration object
|
|
324
|
+
*/
|
|
325
|
+
static create(config) {
|
|
326
|
+
return new EmailMark(typeof config === "function" ? config() : config);
|
|
327
|
+
}
|
|
328
|
+
static from(mark, renderToReactEmail) {
|
|
329
|
+
const customMark = EmailMark.create({});
|
|
330
|
+
Object.assign(customMark, { ...mark });
|
|
331
|
+
customMark.config = {
|
|
332
|
+
...mark.config,
|
|
333
|
+
renderToReactEmail
|
|
334
|
+
};
|
|
335
|
+
return customMark;
|
|
336
|
+
}
|
|
337
|
+
configure(options) {
|
|
338
|
+
return super.configure(options);
|
|
339
|
+
}
|
|
340
|
+
extend(extendedConfig) {
|
|
341
|
+
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
342
|
+
return super.extend(resolvedConfig);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/core/serializer/email-node.ts
|
|
348
|
+
var EmailNode = class EmailNode extends _tiptap_core.Node {
|
|
349
|
+
constructor(config) {
|
|
350
|
+
super(config);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Create a new Node instance
|
|
354
|
+
* @param config - Node configuration object or a function that returns a configuration object
|
|
355
|
+
*/
|
|
356
|
+
static create(config) {
|
|
357
|
+
return new EmailNode(typeof config === "function" ? config() : config);
|
|
358
|
+
}
|
|
359
|
+
static from(node, renderToReactEmail) {
|
|
360
|
+
const customNode = EmailNode.create({});
|
|
361
|
+
Object.assign(customNode, { ...node });
|
|
362
|
+
customNode.config = {
|
|
363
|
+
...node.config,
|
|
364
|
+
renderToReactEmail
|
|
365
|
+
};
|
|
366
|
+
return customNode;
|
|
367
|
+
}
|
|
368
|
+
configure(options) {
|
|
369
|
+
return super.configure(options);
|
|
370
|
+
}
|
|
371
|
+
extend(extendedConfig) {
|
|
372
|
+
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
373
|
+
return super.extend(resolvedConfig);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/core/serializer/compose-react-email.tsx
|
|
379
|
+
const MARK_ORDER = {
|
|
380
|
+
preservedStyle: 0,
|
|
381
|
+
italic: 1,
|
|
382
|
+
strike: 2,
|
|
383
|
+
underline: 3,
|
|
384
|
+
link: 4,
|
|
385
|
+
bold: 5,
|
|
386
|
+
code: 6
|
|
387
|
+
};
|
|
388
|
+
const NODES_WITH_INCREMENTED_CHILD_DEPTH = new Set(["bulletList", "orderedList"]);
|
|
389
|
+
function getOrderedMarks(marks) {
|
|
390
|
+
if (!marks) return [];
|
|
391
|
+
return [...marks].sort((a, b) => (MARK_ORDER[a.type] ?? Number.MAX_SAFE_INTEGER) - (MARK_ORDER[b.type] ?? Number.MAX_SAFE_INTEGER));
|
|
392
|
+
}
|
|
393
|
+
const composeReactEmail = async ({ editor, preview }) => {
|
|
394
|
+
const data = editor.getJSON();
|
|
395
|
+
const extensions = editor.extensionManager.extensions;
|
|
396
|
+
const serializerPlugin = extensions.map((ext) => ext.options?.serializerPlugin).filter((p) => Boolean(p)).at(-1);
|
|
397
|
+
const emailNodeComponentRegistry = Object.fromEntries(extensions.filter((ext) => ext instanceof EmailNode).map((extension) => [extension.name, extension.config.renderToReactEmail]));
|
|
398
|
+
const emailMarkComponentRegistry = Object.fromEntries(extensions.filter((ext) => ext instanceof EmailMark).map((extension) => [extension.name, extension.config.renderToReactEmail]));
|
|
399
|
+
function renderMark(mark, node, children, depth) {
|
|
400
|
+
const markStyle = serializerPlugin?.getNodeStyles({
|
|
401
|
+
type: mark.type,
|
|
402
|
+
attrs: mark.attrs ?? {}
|
|
403
|
+
}, depth, editor) ?? {};
|
|
404
|
+
const markRenderer = emailMarkComponentRegistry[mark.type];
|
|
405
|
+
if (markRenderer) return markRenderer({
|
|
406
|
+
mark,
|
|
407
|
+
node,
|
|
408
|
+
style: markStyle,
|
|
409
|
+
children
|
|
410
|
+
});
|
|
411
|
+
return children;
|
|
412
|
+
}
|
|
413
|
+
function parseContent(content, depth = 0) {
|
|
414
|
+
if (!content) return;
|
|
415
|
+
return content.map((node, index) => {
|
|
416
|
+
const style = serializerPlugin?.getNodeStyles(node, depth, editor) ?? {};
|
|
417
|
+
const inlineStyles = inlineCssToJs(node.attrs?.style);
|
|
418
|
+
if (node.type && emailNodeComponentRegistry[node.type]) {
|
|
419
|
+
const Component = emailNodeComponentRegistry[node.type];
|
|
420
|
+
const childDepth = NODES_WITH_INCREMENTED_CHILD_DEPTH.has(node.type) ? depth + 1 : depth;
|
|
421
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
422
|
+
node: node.type === "table" && inlineStyles.width && !node.attrs?.width ? {
|
|
423
|
+
...node,
|
|
424
|
+
attrs: {
|
|
425
|
+
...node.attrs,
|
|
426
|
+
width: inlineStyles.width
|
|
427
|
+
}
|
|
428
|
+
} : node,
|
|
429
|
+
style,
|
|
430
|
+
children: parseContent(node.content, childDepth)
|
|
431
|
+
}, index);
|
|
432
|
+
}
|
|
433
|
+
switch (node.type) {
|
|
434
|
+
case "text": {
|
|
435
|
+
let wrappedText = node.text;
|
|
436
|
+
getOrderedMarks(node.marks).forEach((mark) => {
|
|
437
|
+
wrappedText = renderMark(mark, node, wrappedText, depth);
|
|
438
|
+
});
|
|
439
|
+
const textAttributes = node.marks?.find((mark) => mark.type === "textStyle")?.attrs;
|
|
440
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
441
|
+
style: {
|
|
442
|
+
...textAttributes,
|
|
443
|
+
...style
|
|
444
|
+
},
|
|
445
|
+
children: wrappedText
|
|
446
|
+
}, index);
|
|
447
|
+
}
|
|
448
|
+
default: return null;
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
const unformattedHtml = await (0, _react_email_components.render)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(serializerPlugin?.BaseTemplate ?? DefaultBaseTemplate, {
|
|
453
|
+
previewText: preview,
|
|
454
|
+
editor,
|
|
455
|
+
children: parseContent(data.content)
|
|
456
|
+
}));
|
|
457
|
+
const [prettyHtml, text] = await Promise.all([(0, _react_email_components.pretty)(unformattedHtml), (0, _react_email_components.toPlainText)(unformattedHtml)]);
|
|
458
|
+
return {
|
|
459
|
+
html: prettyHtml,
|
|
460
|
+
text
|
|
461
|
+
};
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/extensions/alignment-attribute.tsx
|
|
466
|
+
const AlignmentAttribute = _tiptap_core.Extension.create({
|
|
467
|
+
name: "alignmentAttribute",
|
|
468
|
+
addOptions() {
|
|
469
|
+
return {
|
|
470
|
+
types: [],
|
|
471
|
+
alignments: [
|
|
472
|
+
"left",
|
|
473
|
+
"center",
|
|
474
|
+
"right",
|
|
475
|
+
"justify"
|
|
476
|
+
]
|
|
477
|
+
};
|
|
478
|
+
},
|
|
479
|
+
addGlobalAttributes() {
|
|
480
|
+
return [{
|
|
481
|
+
types: this.options.types,
|
|
482
|
+
attributes: { alignment: {
|
|
483
|
+
parseHTML: (element) => {
|
|
484
|
+
const explicitAlign = element.getAttribute("align") || element.getAttribute("alignment") || element.style.textAlign;
|
|
485
|
+
if (explicitAlign && this.options.alignments.includes(explicitAlign)) return explicitAlign;
|
|
486
|
+
return null;
|
|
487
|
+
},
|
|
488
|
+
renderHTML: (attributes) => {
|
|
489
|
+
if (attributes.alignment === "left") return {};
|
|
490
|
+
return { alignment: attributes.alignment };
|
|
491
|
+
}
|
|
492
|
+
} }
|
|
493
|
+
}];
|
|
494
|
+
},
|
|
495
|
+
addCommands() {
|
|
496
|
+
return { setAlignment: (alignment) => ({ commands }) => {
|
|
497
|
+
if (!this.options.alignments.includes(alignment)) return false;
|
|
498
|
+
return this.options.types.every((type) => commands.updateAttributes(type, { alignment }));
|
|
499
|
+
} };
|
|
500
|
+
},
|
|
501
|
+
addKeyboardShortcuts() {
|
|
502
|
+
return {
|
|
503
|
+
Enter: () => {
|
|
504
|
+
const { from } = this.editor.state.selection;
|
|
505
|
+
const currentAlignment = this.editor.state.doc.nodeAt(from)?.attrs?.alignment;
|
|
506
|
+
if (currentAlignment) requestAnimationFrame(() => {
|
|
507
|
+
this.editor.commands.setAlignment(currentAlignment);
|
|
508
|
+
});
|
|
509
|
+
return false;
|
|
510
|
+
},
|
|
511
|
+
"Mod-Shift-l": () => this.editor.commands.setAlignment("left"),
|
|
512
|
+
"Mod-Shift-e": () => this.editor.commands.setAlignment("center"),
|
|
513
|
+
"Mod-Shift-r": () => this.editor.commands.setAlignment("right"),
|
|
514
|
+
"Mod-Shift-j": () => this.editor.commands.setAlignment("justify")
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region src/utils/get-text-alignment.ts
|
|
521
|
+
function getTextAlignment(alignment) {
|
|
522
|
+
switch (alignment) {
|
|
523
|
+
case "left": return { textAlign: "left" };
|
|
524
|
+
case "center": return { textAlign: "center" };
|
|
525
|
+
case "right": return { textAlign: "right" };
|
|
526
|
+
default: return {};
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/extensions/blockquote.tsx
|
|
532
|
+
const Blockquote = EmailNode.from(_tiptap_extension_blockquote.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("blockquote", {
|
|
533
|
+
className: node.attrs?.class || void 0,
|
|
534
|
+
style: {
|
|
535
|
+
...style,
|
|
536
|
+
...inlineCssToJs(node.attrs?.style),
|
|
537
|
+
...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
|
|
538
|
+
},
|
|
539
|
+
children
|
|
540
|
+
}));
|
|
541
|
+
|
|
542
|
+
//#endregion
|
|
543
|
+
//#region src/utils/attribute-helpers.ts
|
|
544
|
+
/**
|
|
545
|
+
* Creates TipTap attribute definitions for a list of HTML attributes.
|
|
546
|
+
* Each attribute will have the same pattern:
|
|
547
|
+
* - default: null
|
|
548
|
+
* - parseHTML: extracts the attribute from the element
|
|
549
|
+
* - renderHTML: conditionally renders the attribute if it has a value
|
|
550
|
+
*
|
|
551
|
+
* @param attributeNames - Array of HTML attribute names to create definitions for
|
|
552
|
+
* @returns Object with TipTap attribute definitions
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* const attrs = createStandardAttributes(['class', 'id', 'title']);
|
|
556
|
+
* // Returns:
|
|
557
|
+
* // {
|
|
558
|
+
* // class: {
|
|
559
|
+
* // default: null,
|
|
560
|
+
* // parseHTML: (element) => element.getAttribute('class'),
|
|
561
|
+
* // renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}
|
|
562
|
+
* // },
|
|
563
|
+
* // ...
|
|
564
|
+
* // }
|
|
565
|
+
*/
|
|
566
|
+
function createStandardAttributes(attributeNames) {
|
|
567
|
+
return Object.fromEntries(attributeNames.map((attr) => [attr, {
|
|
568
|
+
default: null,
|
|
569
|
+
parseHTML: (element) => element.getAttribute(attr),
|
|
570
|
+
renderHTML: (attributes) => {
|
|
571
|
+
if (!attributes[attr]) return {};
|
|
572
|
+
return { [attr]: attributes[attr] };
|
|
573
|
+
}
|
|
574
|
+
}]));
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Common HTML attributes used across multiple extensions.
|
|
578
|
+
* These preserve attributes during HTML import and editing for better
|
|
579
|
+
* fidelity when importing existing email templates.
|
|
580
|
+
*/
|
|
581
|
+
const COMMON_HTML_ATTRIBUTES = [
|
|
582
|
+
"id",
|
|
583
|
+
"class",
|
|
584
|
+
"title",
|
|
585
|
+
"lang",
|
|
586
|
+
"dir",
|
|
587
|
+
"data-id"
|
|
588
|
+
];
|
|
589
|
+
/**
|
|
590
|
+
* Layout-specific HTML attributes used for positioning and sizing.
|
|
591
|
+
*/
|
|
592
|
+
const LAYOUT_ATTRIBUTES = [
|
|
593
|
+
"align",
|
|
594
|
+
"width",
|
|
595
|
+
"height"
|
|
596
|
+
];
|
|
597
|
+
/**
|
|
598
|
+
* Table-specific HTML attributes used for table layout and styling.
|
|
599
|
+
*/
|
|
600
|
+
const TABLE_ATTRIBUTES = [
|
|
601
|
+
"border",
|
|
602
|
+
"cellpadding",
|
|
603
|
+
"cellspacing"
|
|
604
|
+
];
|
|
605
|
+
/**
|
|
606
|
+
* Table cell-specific HTML attributes.
|
|
607
|
+
*/
|
|
608
|
+
const TABLE_CELL_ATTRIBUTES = [
|
|
609
|
+
"valign",
|
|
610
|
+
"bgcolor",
|
|
611
|
+
"colspan",
|
|
612
|
+
"rowspan"
|
|
613
|
+
];
|
|
614
|
+
/**
|
|
615
|
+
* Table header cell-specific HTML attributes.
|
|
616
|
+
* These are additional attributes that only apply to <th> elements.
|
|
617
|
+
*/
|
|
618
|
+
const TABLE_HEADER_ATTRIBUTES = [...TABLE_CELL_ATTRIBUTES, "scope"];
|
|
619
|
+
|
|
428
620
|
//#endregion
|
|
429
621
|
//#region src/extensions/body.tsx
|
|
430
622
|
const Body = EmailNode.create({
|
|
@@ -471,7 +663,7 @@ const Body = EmailNode.create({
|
|
|
471
663
|
});
|
|
472
664
|
|
|
473
665
|
//#endregion
|
|
474
|
-
//#region src/extensions/bold.
|
|
666
|
+
//#region src/extensions/bold.tsx
|
|
475
667
|
/**
|
|
476
668
|
* Matches bold text via `**` as input.
|
|
477
669
|
*/
|
|
@@ -492,7 +684,7 @@ const underscorePasteRegex = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g;
|
|
|
492
684
|
* This extension allows you to mark text as bold.
|
|
493
685
|
* @see https://tiptap.dev/api/marks/bold
|
|
494
686
|
*/
|
|
495
|
-
const Bold =
|
|
687
|
+
const Bold = EmailMark.create({
|
|
496
688
|
name: "bold",
|
|
497
689
|
addOptions() {
|
|
498
690
|
return { HTMLAttributes: {} };
|
|
@@ -517,6 +709,12 @@ const Bold = _tiptap_core.Mark.create({
|
|
|
517
709
|
0
|
|
518
710
|
];
|
|
519
711
|
},
|
|
712
|
+
renderToReactEmail({ children, style }) {
|
|
713
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
714
|
+
style,
|
|
715
|
+
children
|
|
716
|
+
});
|
|
717
|
+
},
|
|
520
718
|
addCommands() {
|
|
521
719
|
return {
|
|
522
720
|
setBold: () => ({ commands }) => {
|
|
@@ -556,6 +754,17 @@ const Bold = _tiptap_core.Mark.create({
|
|
|
556
754
|
}
|
|
557
755
|
});
|
|
558
756
|
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/extensions/bullet-list.tsx
|
|
759
|
+
const BulletList = EmailNode.from(_tiptap_extension_bullet_list.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
760
|
+
className: node.attrs?.class || void 0,
|
|
761
|
+
style: {
|
|
762
|
+
...style,
|
|
763
|
+
...inlineCssToJs(node.attrs?.style)
|
|
764
|
+
},
|
|
765
|
+
children
|
|
766
|
+
}));
|
|
767
|
+
|
|
559
768
|
//#endregion
|
|
560
769
|
//#region src/extensions/button.tsx
|
|
561
770
|
const Button = EmailNode.create({
|
|
@@ -677,6 +886,16 @@ const ClassAttribute = _tiptap_core.Extension.create({
|
|
|
677
886
|
}
|
|
678
887
|
});
|
|
679
888
|
|
|
889
|
+
//#endregion
|
|
890
|
+
//#region src/extensions/code.tsx
|
|
891
|
+
const Code = EmailMark.from(_tiptap_extension_code.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
892
|
+
style: {
|
|
893
|
+
...style,
|
|
894
|
+
...inlineCssToJs(node.attrs?.style)
|
|
895
|
+
},
|
|
896
|
+
children
|
|
897
|
+
}));
|
|
898
|
+
|
|
680
899
|
//#endregion
|
|
681
900
|
//#region src/utils/prism-utils.ts
|
|
682
901
|
const publicURL = "/styles/prism";
|
|
@@ -955,6 +1174,29 @@ const Div = EmailNode.create({
|
|
|
955
1174
|
}
|
|
956
1175
|
});
|
|
957
1176
|
|
|
1177
|
+
//#endregion
|
|
1178
|
+
//#region src/extensions/hard-break.tsx
|
|
1179
|
+
const HardBreak = EmailNode.from(_tiptap_extension_hard_break.default, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}));
|
|
1180
|
+
|
|
1181
|
+
//#endregion
|
|
1182
|
+
//#region src/extensions/italic.tsx
|
|
1183
|
+
const Italic = EmailMark.from(_tiptap_extension_italic.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("em", {
|
|
1184
|
+
style,
|
|
1185
|
+
children
|
|
1186
|
+
}));
|
|
1187
|
+
|
|
1188
|
+
//#endregion
|
|
1189
|
+
//#region src/extensions/list-item.tsx
|
|
1190
|
+
const ListItem = EmailNode.from(_tiptap_extension_list_item.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
1191
|
+
className: node.attrs?.class || void 0,
|
|
1192
|
+
style: {
|
|
1193
|
+
...style,
|
|
1194
|
+
...inlineCssToJs(node.attrs?.style),
|
|
1195
|
+
...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
|
|
1196
|
+
},
|
|
1197
|
+
children
|
|
1198
|
+
}));
|
|
1199
|
+
|
|
958
1200
|
//#endregion
|
|
959
1201
|
//#region src/extensions/max-nesting.ts
|
|
960
1202
|
const MaxNesting = _tiptap_core.Extension.create({
|
|
@@ -1030,6 +1272,33 @@ const MaxNesting = _tiptap_core.Extension.create({
|
|
|
1030
1272
|
}
|
|
1031
1273
|
});
|
|
1032
1274
|
|
|
1275
|
+
//#endregion
|
|
1276
|
+
//#region src/extensions/ordered-list.tsx
|
|
1277
|
+
const OrderedList = EmailNode.from(_tiptap_extension_ordered_list.default, ({ children, node, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
|
|
1278
|
+
className: node.attrs?.class || void 0,
|
|
1279
|
+
start: node.attrs?.start,
|
|
1280
|
+
style: {
|
|
1281
|
+
...style,
|
|
1282
|
+
...inlineCssToJs(node.attrs?.style)
|
|
1283
|
+
},
|
|
1284
|
+
children
|
|
1285
|
+
}));
|
|
1286
|
+
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region src/extensions/paragraph.tsx
|
|
1289
|
+
const Paragraph = EmailNode.from(_tiptap_extension_paragraph.default, ({ children, node, style }) => {
|
|
1290
|
+
const isEmpty = !node.content || node.content.length === 0;
|
|
1291
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1292
|
+
className: node.attrs?.class || void 0,
|
|
1293
|
+
style: {
|
|
1294
|
+
...style,
|
|
1295
|
+
...inlineCssToJs(node.attrs?.style),
|
|
1296
|
+
...getTextAlignment(node.attrs?.align || node.attrs?.alignment)
|
|
1297
|
+
},
|
|
1298
|
+
children: isEmpty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}) : children
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1033
1302
|
//#endregion
|
|
1034
1303
|
//#region src/extensions/placeholder.ts
|
|
1035
1304
|
const Placeholder = _tiptap_extension_placeholder.default.configure({
|
|
@@ -1041,8 +1310,8 @@ const Placeholder = _tiptap_extension_placeholder.default.configure({
|
|
|
1041
1310
|
});
|
|
1042
1311
|
|
|
1043
1312
|
//#endregion
|
|
1044
|
-
//#region src/extensions/preserved-style.
|
|
1045
|
-
const PreservedStyle =
|
|
1313
|
+
//#region src/extensions/preserved-style.tsx
|
|
1314
|
+
const PreservedStyle = EmailMark.create({
|
|
1046
1315
|
name: "preservedStyle",
|
|
1047
1316
|
addAttributes() {
|
|
1048
1317
|
return { style: {
|
|
@@ -1071,6 +1340,12 @@ const PreservedStyle = _tiptap_core.Mark.create({
|
|
|
1071
1340
|
(0, _tiptap_core.mergeAttributes)(HTMLAttributes),
|
|
1072
1341
|
0
|
|
1073
1342
|
];
|
|
1343
|
+
},
|
|
1344
|
+
renderToReactEmail({ children, mark }) {
|
|
1345
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1346
|
+
style: mark.attrs?.style ? inlineCssToJs(mark.attrs.style) : void 0,
|
|
1347
|
+
children
|
|
1348
|
+
});
|
|
1074
1349
|
}
|
|
1075
1350
|
});
|
|
1076
1351
|
const LINK_INDICATOR_STYLES = [
|
|
@@ -1155,17 +1430,6 @@ const PreviewText = _tiptap_core.Node.create({
|
|
|
1155
1430
|
}
|
|
1156
1431
|
});
|
|
1157
1432
|
|
|
1158
|
-
//#endregion
|
|
1159
|
-
//#region src/utils/get-text-alignment.ts
|
|
1160
|
-
function getTextAlignment(alignment) {
|
|
1161
|
-
switch (alignment) {
|
|
1162
|
-
case "left": return { textAlign: "left" };
|
|
1163
|
-
case "center": return { textAlign: "center" };
|
|
1164
|
-
case "right": return { textAlign: "right" };
|
|
1165
|
-
default: return {};
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
1433
|
//#endregion
|
|
1170
1434
|
//#region src/extensions/section.tsx
|
|
1171
1435
|
const Section = EmailNode.create({
|
|
@@ -1214,6 +1478,13 @@ const Section = EmailNode.create({
|
|
|
1214
1478
|
}
|
|
1215
1479
|
});
|
|
1216
1480
|
|
|
1481
|
+
//#endregion
|
|
1482
|
+
//#region src/extensions/strike.tsx
|
|
1483
|
+
const Strike = EmailMark.from(_tiptap_extension_strike.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("s", {
|
|
1484
|
+
style,
|
|
1485
|
+
children
|
|
1486
|
+
}));
|
|
1487
|
+
|
|
1217
1488
|
//#endregion
|
|
1218
1489
|
//#region src/extensions/style-attribute.tsx
|
|
1219
1490
|
const StyleAttribute = _tiptap_core.Extension.create({
|
|
@@ -1263,12 +1534,12 @@ const StyleAttribute = _tiptap_core.Extension.create({
|
|
|
1263
1534
|
});
|
|
1264
1535
|
|
|
1265
1536
|
//#endregion
|
|
1266
|
-
//#region src/extensions/sup.
|
|
1537
|
+
//#region src/extensions/sup.tsx
|
|
1267
1538
|
/**
|
|
1268
1539
|
* This extension allows you to mark text as superscript.
|
|
1269
1540
|
* @see https://tiptap.dev/api/marks/superscript
|
|
1270
1541
|
*/
|
|
1271
|
-
const Sup =
|
|
1542
|
+
const Sup = EmailMark.create({
|
|
1272
1543
|
name: "sup",
|
|
1273
1544
|
addOptions() {
|
|
1274
1545
|
return { HTMLAttributes: {} };
|
|
@@ -1283,6 +1554,12 @@ const Sup = _tiptap_core.Mark.create({
|
|
|
1283
1554
|
0
|
|
1284
1555
|
];
|
|
1285
1556
|
},
|
|
1557
|
+
renderToReactEmail({ children, style }) {
|
|
1558
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
|
|
1559
|
+
style,
|
|
1560
|
+
children
|
|
1561
|
+
});
|
|
1562
|
+
},
|
|
1286
1563
|
addCommands() {
|
|
1287
1564
|
return {
|
|
1288
1565
|
setSup: () => ({ commands }) => {
|
|
@@ -1485,8 +1762,8 @@ const TableHeader = _tiptap_core.Node.create({
|
|
|
1485
1762
|
});
|
|
1486
1763
|
|
|
1487
1764
|
//#endregion
|
|
1488
|
-
//#region src/extensions/uppercase.
|
|
1489
|
-
const Uppercase =
|
|
1765
|
+
//#region src/extensions/uppercase.tsx
|
|
1766
|
+
const Uppercase = EmailMark.create({
|
|
1490
1767
|
name: "uppercase",
|
|
1491
1768
|
addOptions() {
|
|
1492
1769
|
return { HTMLAttributes: {} };
|
|
@@ -1507,6 +1784,15 @@ const Uppercase = _tiptap_core.Mark.create({
|
|
|
1507
1784
|
0
|
|
1508
1785
|
];
|
|
1509
1786
|
},
|
|
1787
|
+
renderToReactEmail({ children, style }) {
|
|
1788
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1789
|
+
style: {
|
|
1790
|
+
...style,
|
|
1791
|
+
textTransform: "uppercase"
|
|
1792
|
+
},
|
|
1793
|
+
children
|
|
1794
|
+
});
|
|
1795
|
+
},
|
|
1510
1796
|
addCommands() {
|
|
1511
1797
|
return {
|
|
1512
1798
|
setUppercase: () => ({ commands }) => {
|
|
@@ -1702,17 +1988,17 @@ const coreExtensions = [
|
|
|
1702
1988
|
underline: false,
|
|
1703
1989
|
trailingNode: false,
|
|
1704
1990
|
bold: false,
|
|
1991
|
+
italic: false,
|
|
1992
|
+
strike: false,
|
|
1993
|
+
code: false,
|
|
1994
|
+
paragraph: false,
|
|
1995
|
+
bulletList: false,
|
|
1996
|
+
orderedList: false,
|
|
1997
|
+
listItem: false,
|
|
1998
|
+
blockquote: false,
|
|
1999
|
+
hardBreak: false,
|
|
1705
2000
|
gapcursor: false,
|
|
1706
|
-
listItem: {},
|
|
1707
|
-
bulletList: { HTMLAttributes: { class: "node-bulletList" } },
|
|
1708
|
-
paragraph: { HTMLAttributes: { class: "node-paragraph" } },
|
|
1709
|
-
orderedList: { HTMLAttributes: { class: "node-orderedList" } },
|
|
1710
|
-
blockquote: { HTMLAttributes: { class: "node-blockquote" } },
|
|
1711
2001
|
codeBlock: false,
|
|
1712
|
-
code: { HTMLAttributes: {
|
|
1713
|
-
class: "node-inlineCode",
|
|
1714
|
-
spellcheck: "false"
|
|
1715
|
-
} },
|
|
1716
2002
|
horizontalRule: false,
|
|
1717
2003
|
dropcursor: {
|
|
1718
2004
|
color: "#61a8f8",
|
|
@@ -1724,9 +2010,21 @@ const coreExtensions = [
|
|
|
1724
2010
|
defaultLanguage: "javascript",
|
|
1725
2011
|
HTMLAttributes: { class: "prism node-codeBlock" }
|
|
1726
2012
|
}),
|
|
2013
|
+
Code.configure({ HTMLAttributes: {
|
|
2014
|
+
class: "node-inlineCode",
|
|
2015
|
+
spellcheck: "false"
|
|
2016
|
+
} }),
|
|
2017
|
+
Paragraph.configure({ HTMLAttributes: { class: "node-paragraph" } }),
|
|
2018
|
+
BulletList.configure({ HTMLAttributes: { class: "node-bulletList" } }),
|
|
2019
|
+
OrderedList.configure({ HTMLAttributes: { class: "node-orderedList" } }),
|
|
2020
|
+
Blockquote.configure({ HTMLAttributes: { class: "node-blockquote" } }),
|
|
2021
|
+
ListItem,
|
|
2022
|
+
HardBreak,
|
|
2023
|
+
Italic,
|
|
1727
2024
|
Placeholder,
|
|
1728
2025
|
PreviewText,
|
|
1729
2026
|
Bold,
|
|
2027
|
+
Strike,
|
|
1730
2028
|
Sup,
|
|
1731
2029
|
Uppercase,
|
|
1732
2030
|
PreservedStyle,
|
|
@@ -1813,6 +2111,221 @@ const coreExtensions = [
|
|
|
1813
2111
|
})
|
|
1814
2112
|
];
|
|
1815
2113
|
|
|
2114
|
+
//#endregion
|
|
2115
|
+
//#region src/core/create-drop-handler.ts
|
|
2116
|
+
function createDropHandler({ onPaste, onUploadImage }) {
|
|
2117
|
+
return (view, event, _slice, moved) => {
|
|
2118
|
+
if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {
|
|
2119
|
+
event.preventDefault();
|
|
2120
|
+
const file = event.dataTransfer.files[0];
|
|
2121
|
+
if (onPaste?.(file, view)) return true;
|
|
2122
|
+
if (file.type.includes("image/") && onUploadImage) {
|
|
2123
|
+
onUploadImage(file, view, (view.posAtCoords({
|
|
2124
|
+
left: event.clientX,
|
|
2125
|
+
top: event.clientY
|
|
2126
|
+
})?.pos || 0) - 1);
|
|
2127
|
+
return true;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
return false;
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
//#endregion
|
|
2135
|
+
//#region src/utils/paste-sanitizer.ts
|
|
2136
|
+
/**
|
|
2137
|
+
* Sanitizes pasted HTML.
|
|
2138
|
+
* - From editor (has node-* classes): pass through as-is
|
|
2139
|
+
* - From external: strip all styles/classes, keep only semantic HTML
|
|
2140
|
+
*/
|
|
2141
|
+
/**
|
|
2142
|
+
* Detects content from the Resend editor by checking for node-* class names.
|
|
2143
|
+
*/
|
|
2144
|
+
const EDITOR_CLASS_PATTERN = /class="[^"]*node-/;
|
|
2145
|
+
/**
|
|
2146
|
+
* Attributes to preserve on specific elements for EXTERNAL content.
|
|
2147
|
+
* Only functional attributes - NO style or class.
|
|
2148
|
+
*/
|
|
2149
|
+
const PRESERVED_ATTRIBUTES = {
|
|
2150
|
+
a: [
|
|
2151
|
+
"href",
|
|
2152
|
+
"target",
|
|
2153
|
+
"rel"
|
|
2154
|
+
],
|
|
2155
|
+
img: [
|
|
2156
|
+
"src",
|
|
2157
|
+
"alt",
|
|
2158
|
+
"width",
|
|
2159
|
+
"height"
|
|
2160
|
+
],
|
|
2161
|
+
td: ["colspan", "rowspan"],
|
|
2162
|
+
th: [
|
|
2163
|
+
"colspan",
|
|
2164
|
+
"rowspan",
|
|
2165
|
+
"scope"
|
|
2166
|
+
],
|
|
2167
|
+
table: [
|
|
2168
|
+
"border",
|
|
2169
|
+
"cellpadding",
|
|
2170
|
+
"cellspacing"
|
|
2171
|
+
],
|
|
2172
|
+
"*": ["id"]
|
|
2173
|
+
};
|
|
2174
|
+
function isFromEditor(html) {
|
|
2175
|
+
return EDITOR_CLASS_PATTERN.test(html);
|
|
2176
|
+
}
|
|
2177
|
+
function sanitizePastedHtml(html) {
|
|
2178
|
+
if (isFromEditor(html)) return html;
|
|
2179
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
2180
|
+
sanitizeNode(doc.body);
|
|
2181
|
+
return doc.body.innerHTML;
|
|
2182
|
+
}
|
|
2183
|
+
function sanitizeNode(node) {
|
|
2184
|
+
if (node.nodeType === Node.ELEMENT_NODE) sanitizeElement(node);
|
|
2185
|
+
for (const child of Array.from(node.childNodes)) sanitizeNode(child);
|
|
2186
|
+
}
|
|
2187
|
+
function sanitizeElement(el) {
|
|
2188
|
+
const allowedForTag = PRESERVED_ATTRIBUTES[el.tagName.toLowerCase()] || [];
|
|
2189
|
+
const allowedGlobal = PRESERVED_ATTRIBUTES["*"] || [];
|
|
2190
|
+
const allowed = new Set([...allowedForTag, ...allowedGlobal]);
|
|
2191
|
+
const attributesToRemove = [];
|
|
2192
|
+
for (const attr of Array.from(el.attributes)) {
|
|
2193
|
+
if (attr.name.startsWith("data-")) {
|
|
2194
|
+
attributesToRemove.push(attr.name);
|
|
2195
|
+
continue;
|
|
2196
|
+
}
|
|
2197
|
+
if (!allowed.has(attr.name)) attributesToRemove.push(attr.name);
|
|
2198
|
+
}
|
|
2199
|
+
for (const attr of attributesToRemove) el.removeAttribute(attr);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
//#endregion
|
|
2203
|
+
//#region src/core/create-paste-handler.ts
|
|
2204
|
+
function createPasteHandler({ onPaste, onUploadImage, extensions }) {
|
|
2205
|
+
return (view, event, slice) => {
|
|
2206
|
+
const text = event.clipboardData?.getData("text/plain");
|
|
2207
|
+
if (text && onPaste?.(text, view)) {
|
|
2208
|
+
event.preventDefault();
|
|
2209
|
+
return true;
|
|
2210
|
+
}
|
|
2211
|
+
if (event.clipboardData?.files?.[0]) {
|
|
2212
|
+
const file = event.clipboardData.files[0];
|
|
2213
|
+
if (onPaste?.(file, view)) {
|
|
2214
|
+
event.preventDefault();
|
|
2215
|
+
return true;
|
|
2216
|
+
}
|
|
2217
|
+
if (file.type.includes("image/") && onUploadImage) {
|
|
2218
|
+
const pos = view.state.selection.from;
|
|
2219
|
+
onUploadImage(file, view, pos);
|
|
2220
|
+
return true;
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
/**
|
|
2224
|
+
* If the coming content has a single child, we can assume
|
|
2225
|
+
* it's a plain text and doesn't need to be parsed and
|
|
2226
|
+
* be introduced in a new line
|
|
2227
|
+
*/
|
|
2228
|
+
if (slice.content.childCount === 1) return false;
|
|
2229
|
+
if (event.clipboardData?.getData?.("text/html")) {
|
|
2230
|
+
event.preventDefault();
|
|
2231
|
+
const jsonContent = (0, _tiptap_html.generateJSON)(sanitizePastedHtml(event.clipboardData.getData("text/html")), extensions);
|
|
2232
|
+
const node = view.state.schema.nodeFromJSON(jsonContent);
|
|
2233
|
+
const transaction = view.state.tr.replaceSelectionWith(node, false);
|
|
2234
|
+
view.dispatch(transaction);
|
|
2235
|
+
return true;
|
|
2236
|
+
}
|
|
2237
|
+
return false;
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
//#endregion
|
|
2242
|
+
//#region src/core/is-document-visually-empty.ts
|
|
2243
|
+
function isDocumentVisuallyEmpty(doc) {
|
|
2244
|
+
let nonGlobalNodeCount = 0;
|
|
2245
|
+
let firstNonGlobalNode = null;
|
|
2246
|
+
for (let index = 0; index < doc.childCount; index += 1) {
|
|
2247
|
+
const node = doc.child(index);
|
|
2248
|
+
if (node.type.name === "globalContent") continue;
|
|
2249
|
+
nonGlobalNodeCount += 1;
|
|
2250
|
+
if (firstNonGlobalNode === null) firstNonGlobalNode = {
|
|
2251
|
+
type: node.type,
|
|
2252
|
+
textContent: node.textContent,
|
|
2253
|
+
childCount: node.content.childCount
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
if (nonGlobalNodeCount === 0) return true;
|
|
2257
|
+
if (nonGlobalNodeCount !== 1) return false;
|
|
2258
|
+
return firstNonGlobalNode?.type.name === "paragraph" && firstNonGlobalNode.textContent.trim().length === 0 && firstNonGlobalNode.childCount === 0;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
//#endregion
|
|
2262
|
+
//#region src/core/use-editor.ts
|
|
2263
|
+
const COLLABORATION_EXTENSION_NAMES = new Set(["liveblocksExtension", "collaboration"]);
|
|
2264
|
+
function hasCollaborationExtension(exts) {
|
|
2265
|
+
return exts.some((ext) => COLLABORATION_EXTENSION_NAMES.has(ext.name));
|
|
2266
|
+
}
|
|
2267
|
+
function useEditor({ content, extensions = [], onUpdate, onPaste, onUploadImage, onReady, editable = true, ...rest }) {
|
|
2268
|
+
const [contentError, setContentError] = react.useState(null);
|
|
2269
|
+
const isCollaborative = hasCollaborationExtension(extensions);
|
|
2270
|
+
const effectiveExtensions = react.useMemo(() => [
|
|
2271
|
+
...coreExtensions,
|
|
2272
|
+
...isCollaborative ? [] : [_tiptap_extensions.UndoRedo],
|
|
2273
|
+
...extensions
|
|
2274
|
+
], [extensions, isCollaborative]);
|
|
2275
|
+
const editor = (0, _tiptap_react.useEditor)({
|
|
2276
|
+
content: isCollaborative ? void 0 : content,
|
|
2277
|
+
extensions: effectiveExtensions,
|
|
2278
|
+
immediatelyRender: false,
|
|
2279
|
+
enableContentCheck: true,
|
|
2280
|
+
onContentError({ editor: editor$1, error, disableCollaboration }) {
|
|
2281
|
+
disableCollaboration();
|
|
2282
|
+
setContentError(error);
|
|
2283
|
+
console.error(error);
|
|
2284
|
+
editor$1.setEditable(false);
|
|
2285
|
+
},
|
|
2286
|
+
onCreate({ editor: editor$1 }) {
|
|
2287
|
+
onReady?.(editor$1);
|
|
2288
|
+
},
|
|
2289
|
+
onUpdate({ editor: editor$1, transaction }) {
|
|
2290
|
+
onUpdate?.(editor$1, transaction);
|
|
2291
|
+
},
|
|
2292
|
+
editorProps: {
|
|
2293
|
+
handleDOMEvents: { click: (view, event) => {
|
|
2294
|
+
if (!view.editable) {
|
|
2295
|
+
if (event.target.closest("a")) {
|
|
2296
|
+
event.preventDefault();
|
|
2297
|
+
return true;
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
return false;
|
|
2301
|
+
} },
|
|
2302
|
+
handlePaste: createPasteHandler({
|
|
2303
|
+
onPaste,
|
|
2304
|
+
onUploadImage,
|
|
2305
|
+
extensions: effectiveExtensions
|
|
2306
|
+
}),
|
|
2307
|
+
handleDrop: createDropHandler({
|
|
2308
|
+
onPaste,
|
|
2309
|
+
onUploadImage
|
|
2310
|
+
})
|
|
2311
|
+
},
|
|
2312
|
+
...rest
|
|
2313
|
+
});
|
|
2314
|
+
return {
|
|
2315
|
+
editor,
|
|
2316
|
+
isEditorEmpty: (0, _tiptap_react.useEditorState)({
|
|
2317
|
+
editor,
|
|
2318
|
+
selector: (context) => {
|
|
2319
|
+
if (!context.editor) return true;
|
|
2320
|
+
return isDocumentVisuallyEmpty(context.editor.state.doc);
|
|
2321
|
+
}
|
|
2322
|
+
}) ?? true,
|
|
2323
|
+
extensions: effectiveExtensions,
|
|
2324
|
+
contentError,
|
|
2325
|
+
isCollaborative
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
|
|
1816
2329
|
//#endregion
|
|
1817
2330
|
//#region src/utils/set-text-alignment.ts
|
|
1818
2331
|
function setTextAlignment(editor, alignment) {
|
|
@@ -2967,13 +3480,12 @@ function groupByCategory(items) {
|
|
|
2967
3480
|
return ordered;
|
|
2968
3481
|
}
|
|
2969
3482
|
function CommandItem({ item, selected, onSelect }) {
|
|
2970
|
-
const Icon = item.icon;
|
|
2971
3483
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2972
3484
|
"data-re-slash-command-item": "",
|
|
2973
3485
|
"data-selected": selected || void 0,
|
|
2974
3486
|
onClick: onSelect,
|
|
2975
3487
|
type: "button",
|
|
2976
|
-
children: [
|
|
3488
|
+
children: [item.icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.title })]
|
|
2977
3489
|
});
|
|
2978
3490
|
}
|
|
2979
3491
|
function CommandList({ items, command, query, ref }) {
|
|
@@ -3048,11 +3560,11 @@ function CommandList({ items, command, query, ref }) {
|
|
|
3048
3560
|
}
|
|
3049
3561
|
|
|
3050
3562
|
//#endregion
|
|
3051
|
-
//#region src/ui/slash-command/commands.
|
|
3563
|
+
//#region src/ui/slash-command/commands.tsx
|
|
3052
3564
|
const TEXT = {
|
|
3053
3565
|
title: "Text",
|
|
3054
3566
|
description: "Plain text block",
|
|
3055
|
-
icon: lucide_react.Text,
|
|
3567
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Text, { size: 20 }),
|
|
3056
3568
|
category: "Text",
|
|
3057
3569
|
searchTerms: ["p", "paragraph"],
|
|
3058
3570
|
command: ({ editor, range }) => {
|
|
@@ -3062,7 +3574,7 @@ const TEXT = {
|
|
|
3062
3574
|
const H1 = {
|
|
3063
3575
|
title: "Title",
|
|
3064
3576
|
description: "Large heading",
|
|
3065
|
-
icon: lucide_react.Heading1,
|
|
3577
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading1, { size: 20 }),
|
|
3066
3578
|
category: "Text",
|
|
3067
3579
|
searchTerms: [
|
|
3068
3580
|
"title",
|
|
@@ -3077,7 +3589,7 @@ const H1 = {
|
|
|
3077
3589
|
const H2 = {
|
|
3078
3590
|
title: "Subtitle",
|
|
3079
3591
|
description: "Medium heading",
|
|
3080
|
-
icon: lucide_react.Heading2,
|
|
3592
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading2, { size: 20 }),
|
|
3081
3593
|
category: "Text",
|
|
3082
3594
|
searchTerms: [
|
|
3083
3595
|
"subtitle",
|
|
@@ -3091,7 +3603,7 @@ const H2 = {
|
|
|
3091
3603
|
const H3 = {
|
|
3092
3604
|
title: "Heading",
|
|
3093
3605
|
description: "Small heading",
|
|
3094
|
-
icon: lucide_react.Heading3,
|
|
3606
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heading3, { size: 20 }),
|
|
3095
3607
|
category: "Text",
|
|
3096
3608
|
searchTerms: [
|
|
3097
3609
|
"subtitle",
|
|
@@ -3105,7 +3617,7 @@ const H3 = {
|
|
|
3105
3617
|
const BULLET_LIST = {
|
|
3106
3618
|
title: "Bullet list",
|
|
3107
3619
|
description: "Unordered list",
|
|
3108
|
-
icon: lucide_react.List,
|
|
3620
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { size: 20 }),
|
|
3109
3621
|
category: "Text",
|
|
3110
3622
|
searchTerms: ["unordered", "point"],
|
|
3111
3623
|
command: ({ editor, range }) => {
|
|
@@ -3115,7 +3627,7 @@ const BULLET_LIST = {
|
|
|
3115
3627
|
const NUMBERED_LIST = {
|
|
3116
3628
|
title: "Numbered list",
|
|
3117
3629
|
description: "Ordered list",
|
|
3118
|
-
icon: lucide_react.ListOrdered,
|
|
3630
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ListOrdered, { size: 20 }),
|
|
3119
3631
|
category: "Text",
|
|
3120
3632
|
searchTerms: ["ordered"],
|
|
3121
3633
|
command: ({ editor, range }) => {
|
|
@@ -3125,7 +3637,7 @@ const NUMBERED_LIST = {
|
|
|
3125
3637
|
const QUOTE = {
|
|
3126
3638
|
title: "Quote",
|
|
3127
3639
|
description: "Block quote",
|
|
3128
|
-
icon: lucide_react.TextQuote,
|
|
3640
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.TextQuote, { size: 20 }),
|
|
3129
3641
|
category: "Text",
|
|
3130
3642
|
searchTerms: ["blockquote"],
|
|
3131
3643
|
command: ({ editor, range }) => {
|
|
@@ -3135,7 +3647,7 @@ const QUOTE = {
|
|
|
3135
3647
|
const CODE = {
|
|
3136
3648
|
title: "Code block",
|
|
3137
3649
|
description: "Code snippet",
|
|
3138
|
-
icon: lucide_react.SquareCode,
|
|
3650
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.SquareCode, { size: 20 }),
|
|
3139
3651
|
category: "Text",
|
|
3140
3652
|
searchTerms: ["codeblock"],
|
|
3141
3653
|
command: ({ editor, range }) => {
|
|
@@ -3145,7 +3657,7 @@ const CODE = {
|
|
|
3145
3657
|
const BUTTON = {
|
|
3146
3658
|
title: "Button",
|
|
3147
3659
|
description: "Clickable button",
|
|
3148
|
-
icon: lucide_react.MousePointer,
|
|
3660
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.MousePointer, { size: 20 }),
|
|
3149
3661
|
category: "Layout",
|
|
3150
3662
|
searchTerms: ["button"],
|
|
3151
3663
|
command: ({ editor, range }) => {
|
|
@@ -3155,7 +3667,7 @@ const BUTTON = {
|
|
|
3155
3667
|
const DIVIDER = {
|
|
3156
3668
|
title: "Divider",
|
|
3157
3669
|
description: "Horizontal separator",
|
|
3158
|
-
icon: lucide_react.SplitSquareVertical,
|
|
3670
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.SplitSquareVertical, { size: 20 }),
|
|
3159
3671
|
category: "Layout",
|
|
3160
3672
|
searchTerms: [
|
|
3161
3673
|
"hr",
|
|
@@ -3169,7 +3681,7 @@ const DIVIDER = {
|
|
|
3169
3681
|
const SECTION = {
|
|
3170
3682
|
title: "Section",
|
|
3171
3683
|
description: "Content section",
|
|
3172
|
-
icon: lucide_react.Rows2,
|
|
3684
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Rows2, { size: 20 }),
|
|
3173
3685
|
category: "Layout",
|
|
3174
3686
|
searchTerms: [
|
|
3175
3687
|
"section",
|
|
@@ -3183,7 +3695,7 @@ const SECTION = {
|
|
|
3183
3695
|
const TWO_COLUMNS = {
|
|
3184
3696
|
title: "2 columns",
|
|
3185
3697
|
description: "Two column layout",
|
|
3186
|
-
icon: lucide_react.Columns2,
|
|
3698
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns2, { size: 20 }),
|
|
3187
3699
|
category: "Layout",
|
|
3188
3700
|
searchTerms: [
|
|
3189
3701
|
"columns",
|
|
@@ -3204,7 +3716,7 @@ const TWO_COLUMNS = {
|
|
|
3204
3716
|
const THREE_COLUMNS = {
|
|
3205
3717
|
title: "3 columns",
|
|
3206
3718
|
description: "Three column layout",
|
|
3207
|
-
icon: lucide_react.Columns3,
|
|
3719
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns3, { size: 20 }),
|
|
3208
3720
|
category: "Layout",
|
|
3209
3721
|
searchTerms: [
|
|
3210
3722
|
"columns",
|
|
@@ -3224,7 +3736,7 @@ const THREE_COLUMNS = {
|
|
|
3224
3736
|
const FOUR_COLUMNS = {
|
|
3225
3737
|
title: "4 columns",
|
|
3226
3738
|
description: "Four column layout",
|
|
3227
|
-
icon: lucide_react.Columns4,
|
|
3739
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Columns4, { size: 20 }),
|
|
3228
3740
|
category: "Layout",
|
|
3229
3741
|
searchTerms: [
|
|
3230
3742
|
"columns",
|
|
@@ -3379,6 +3891,7 @@ const SlashCommand = createSlashCommand();
|
|
|
3379
3891
|
exports.AlignmentAttribute = AlignmentAttribute;
|
|
3380
3892
|
exports.BULLET_LIST = BULLET_LIST;
|
|
3381
3893
|
exports.BUTTON = BUTTON;
|
|
3894
|
+
exports.Blockquote = Blockquote;
|
|
3382
3895
|
exports.Body = Body;
|
|
3383
3896
|
exports.Bold = Bold;
|
|
3384
3897
|
exports.BubbleMenu = BubbleMenu;
|
|
@@ -3398,6 +3911,7 @@ exports.BubbleMenuSeparator = BubbleMenuSeparator;
|
|
|
3398
3911
|
exports.BubbleMenuStrike = BubbleMenuStrike;
|
|
3399
3912
|
exports.BubbleMenuUnderline = BubbleMenuUnderline;
|
|
3400
3913
|
exports.BubbleMenuUppercase = BubbleMenuUppercase;
|
|
3914
|
+
exports.BulletList = BulletList;
|
|
3401
3915
|
exports.Button = Button;
|
|
3402
3916
|
exports.ButtonBubbleMenu = ButtonBubbleMenu;
|
|
3403
3917
|
exports.ButtonBubbleMenuDefault = ButtonBubbleMenuDefault;
|
|
@@ -3407,6 +3921,7 @@ exports.ButtonBubbleMenuToolbar = ButtonBubbleMenuToolbar;
|
|
|
3407
3921
|
exports.CODE = CODE;
|
|
3408
3922
|
exports.COLUMN_PARENT_TYPES = COLUMN_PARENT_TYPES;
|
|
3409
3923
|
exports.ClassAttribute = ClassAttribute;
|
|
3924
|
+
exports.Code = Code;
|
|
3410
3925
|
exports.CodeBlockPrism = CodeBlockPrism;
|
|
3411
3926
|
exports.ColumnsColumn = ColumnsColumn;
|
|
3412
3927
|
exports.CommandList = CommandList;
|
|
@@ -3418,11 +3933,13 @@ exports.FourColumns = FourColumns;
|
|
|
3418
3933
|
exports.H1 = H1;
|
|
3419
3934
|
exports.H2 = H2;
|
|
3420
3935
|
exports.H3 = H3;
|
|
3936
|
+
exports.HardBreak = HardBreak;
|
|
3421
3937
|
exports.ImageBubbleMenu = ImageBubbleMenu;
|
|
3422
3938
|
exports.ImageBubbleMenuDefault = ImageBubbleMenuDefault;
|
|
3423
3939
|
exports.ImageBubbleMenuEditLink = ImageBubbleMenuEditLink;
|
|
3424
3940
|
exports.ImageBubbleMenuRoot = ImageBubbleMenuRoot;
|
|
3425
3941
|
exports.ImageBubbleMenuToolbar = ImageBubbleMenuToolbar;
|
|
3942
|
+
exports.Italic = Italic;
|
|
3426
3943
|
exports.LinkBubbleMenu = LinkBubbleMenu;
|
|
3427
3944
|
exports.LinkBubbleMenuDefault = LinkBubbleMenuDefault;
|
|
3428
3945
|
exports.LinkBubbleMenuEditLink = LinkBubbleMenuEditLink;
|
|
@@ -3431,12 +3948,15 @@ exports.LinkBubbleMenuOpenLink = LinkBubbleMenuOpenLink;
|
|
|
3431
3948
|
exports.LinkBubbleMenuRoot = LinkBubbleMenuRoot;
|
|
3432
3949
|
exports.LinkBubbleMenuToolbar = LinkBubbleMenuToolbar;
|
|
3433
3950
|
exports.LinkBubbleMenuUnlink = LinkBubbleMenuUnlink;
|
|
3951
|
+
exports.ListItem = ListItem;
|
|
3434
3952
|
exports.MAX_COLUMNS_DEPTH = MAX_COLUMNS_DEPTH;
|
|
3435
3953
|
exports.MaxNesting = MaxNesting;
|
|
3436
3954
|
exports.NUMBERED_LIST = NUMBERED_LIST;
|
|
3437
3955
|
exports.NodeSelectorContent = NodeSelectorContent;
|
|
3438
3956
|
exports.NodeSelectorRoot = NodeSelectorRoot;
|
|
3439
3957
|
exports.NodeSelectorTrigger = NodeSelectorTrigger;
|
|
3958
|
+
exports.OrderedList = OrderedList;
|
|
3959
|
+
exports.Paragraph = Paragraph;
|
|
3440
3960
|
exports.Placeholder = Placeholder;
|
|
3441
3961
|
exports.PreservedStyle = PreservedStyle;
|
|
3442
3962
|
exports.PreviewText = PreviewText;
|
|
@@ -3444,6 +3964,7 @@ exports.QUOTE = QUOTE;
|
|
|
3444
3964
|
exports.SECTION = SECTION;
|
|
3445
3965
|
exports.Section = Section;
|
|
3446
3966
|
exports.SlashCommand = SlashCommand;
|
|
3967
|
+
exports.Strike = Strike;
|
|
3447
3968
|
exports.StyleAttribute = StyleAttribute;
|
|
3448
3969
|
exports.Sup = Sup;
|
|
3449
3970
|
exports.TEXT = TEXT;
|
|
@@ -3456,6 +3977,7 @@ exports.TableRow = TableRow;
|
|
|
3456
3977
|
exports.ThreeColumns = ThreeColumns;
|
|
3457
3978
|
exports.TwoColumns = TwoColumns;
|
|
3458
3979
|
exports.Uppercase = Uppercase;
|
|
3980
|
+
exports.composeReactEmail = composeReactEmail;
|
|
3459
3981
|
exports.coreExtensions = coreExtensions;
|
|
3460
3982
|
exports.createSlashCommand = createSlashCommand;
|
|
3461
3983
|
exports.defaultSlashCommands = defaultSlashCommands;
|
|
@@ -3468,5 +3990,6 @@ exports.processStylesForUnlink = processStylesForUnlink;
|
|
|
3468
3990
|
exports.scoreItem = scoreItem;
|
|
3469
3991
|
exports.setTextAlignment = setTextAlignment;
|
|
3470
3992
|
exports.useButtonBubbleMenuContext = useButtonBubbleMenuContext;
|
|
3993
|
+
exports.useEditor = useEditor;
|
|
3471
3994
|
exports.useImageBubbleMenuContext = useImageBubbleMenuContext;
|
|
3472
3995
|
exports.useLinkBubbleMenuContext = useLinkBubbleMenuContext;
|