@react-email/editor 1.3.10 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.cjs +3 -3
- package/dist/{core-CLyAVVUW.cjs → core-Dte9KXcz.cjs} +2 -2
- package/dist/{email-node-DvyWFrOM.cjs → email-node-BhbXb22u.cjs} +1 -1
- package/dist/{event-bus-C_wS2tD6.cjs → event-bus-C0haBiDw.cjs} +1 -1
- package/dist/{extension-D_sNGTbX.cjs → extension-bVrEjbFA.cjs} +2 -2
- package/dist/{extension-C1ilEKq-.cjs → extension-mBZiGbpM.cjs} +2 -2
- package/dist/extensions/index.cjs +3 -3
- package/dist/extensions/index.d.cts.map +1 -1
- package/dist/extensions/index.d.mts.map +1 -1
- package/dist/extensions/index.mjs +2 -2
- package/dist/{extensions-oOPUnW7d.cjs → extensions-BQca53AB.cjs} +5 -5
- package/dist/{extensions-CU0ndoee.mjs → extensions-F1FqbQUp.mjs} +2 -2
- package/dist/{extensions-CU0ndoee.mjs.map → extensions-F1FqbQUp.mjs.map} +1 -1
- package/dist/{focus-scopes-B_0O7l7d.mjs → focus-scopes-DOsiXV7b.mjs} +88 -30
- package/dist/focus-scopes-DOsiXV7b.mjs.map +1 -0
- package/dist/{focus-scopes-l_Ki0562.cjs → focus-scopes-Ncj54H_M.cjs} +87 -29
- package/dist/{image-BpsmuXKq.cjs → image-D8OUIgwB.cjs} +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.mjs +2 -2
- package/dist/plugins/index.cjs +4 -4
- package/dist/{root-yYM1BF1C.mjs → root-DYLwAjbF.mjs} +2 -2
- package/dist/{root-yYM1BF1C.mjs.map → root-DYLwAjbF.mjs.map} +1 -1
- package/dist/{root-D8zhkKgc.cjs → root-snVuaxh6.cjs} +2 -2
- package/dist/ui/index.cjs +5 -5
- package/dist/ui/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/focus-scopes-B_0O7l7d.mjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { i as inlineCssToJs, t as EmailNode } from "./email-node-B-_g4X-S.mjs";
|
|
|
2
2
|
import { Column, Row } from "react-email";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { Extension, extensions, mergeAttributes } from "@tiptap/core";
|
|
5
|
-
import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
5
|
+
import { NodeSelection, Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
6
6
|
//#region src/utils/attribute-helpers.ts
|
|
7
7
|
/**
|
|
8
8
|
* Creates TipTap attribute definitions for a list of HTML attributes.
|
|
@@ -159,6 +159,76 @@ const NODE_TYPE_MAP = {
|
|
|
159
159
|
3: "threeColumns",
|
|
160
160
|
4: "fourColumns"
|
|
161
161
|
};
|
|
162
|
+
function isColumnEmpty(col) {
|
|
163
|
+
return col.childCount === 1 && col.firstChild?.type.name === "paragraph" && col.firstChild?.childCount === 0;
|
|
164
|
+
}
|
|
165
|
+
function deleteColumnParent(editor, state, from, to, parentChildCount) {
|
|
166
|
+
const tr = state.tr;
|
|
167
|
+
if (parentChildCount === 1) tr.replaceWith(from, to, state.schema.nodes.paragraph.create());
|
|
168
|
+
else tr.delete(from, to);
|
|
169
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(from)));
|
|
170
|
+
editor.view.dispatch(tr);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
function handleNodeSelectionBackspace(editor, selection, $from, state) {
|
|
174
|
+
if (!(selection instanceof NodeSelection)) return false;
|
|
175
|
+
if (!COLUMN_PARENT_SET.has(selection.node.type.name)) return false;
|
|
176
|
+
if (!Array.from({ length: selection.node.childCount }, (_, i) => selection.node.child(i)).every(isColumnEmpty)) return false;
|
|
177
|
+
const parent = $from.node($from.depth);
|
|
178
|
+
return deleteColumnParent(editor, state, selection.from, selection.to, parent.childCount);
|
|
179
|
+
}
|
|
180
|
+
function handleCursorBackspace(editor, $from, state) {
|
|
181
|
+
for (let depth = $from.depth; depth >= 1; depth--) {
|
|
182
|
+
if ($from.node(depth).type.name === "columnsColumn") return handleBackspaceInsideColumn(editor, $from, state, depth);
|
|
183
|
+
const indexInParent = $from.index(depth - 1);
|
|
184
|
+
if (indexInParent === 0) continue;
|
|
185
|
+
const prevNode = $from.node(depth - 1).child(indexInParent - 1);
|
|
186
|
+
if (COLUMN_PARENT_SET.has(prevNode.type.name)) {
|
|
187
|
+
const from = $from.before(depth) - prevNode.nodeSize;
|
|
188
|
+
const to = $from.before(depth);
|
|
189
|
+
editor.view.dispatch(state.tr.delete(from, to));
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function handleBackspaceInsideColumn(editor, $from, state, depth) {
|
|
197
|
+
const column = $from.node(depth);
|
|
198
|
+
const columnParent = $from.node(depth - 1);
|
|
199
|
+
if (!COLUMN_PARENT_SET.has(columnParent.type.name)) return false;
|
|
200
|
+
if (!isColumnEmpty(column)) return false;
|
|
201
|
+
const deletedIndex = $from.index(depth - 1);
|
|
202
|
+
const remainingColumns = Array.from({ length: columnParent.childCount }, (_, i) => columnParent.child(i)).filter((_, i) => i !== deletedIndex);
|
|
203
|
+
const columnParentFrom = $from.before(depth - 1);
|
|
204
|
+
const columnParentTo = $from.after(depth - 1);
|
|
205
|
+
const tr = state.tr;
|
|
206
|
+
const deletingFirstColumn = deletedIndex === 0;
|
|
207
|
+
const focusIndex = deletingFirstColumn ? 0 : deletedIndex - 1;
|
|
208
|
+
const direction = deletingFirstColumn ? "right" : "left";
|
|
209
|
+
if (remainingColumns.length === 1) {
|
|
210
|
+
const survivingContent = Array.from({ length: remainingColumns[0].childCount }, (_, i) => remainingColumns[0].child(i));
|
|
211
|
+
const replacement = survivingContent.length > 0 ? survivingContent : [state.schema.nodes.paragraph.create()];
|
|
212
|
+
tr.replaceWith(columnParentFrom, columnParentTo, replacement);
|
|
213
|
+
const totalReplacementSize = replacement.reduce((sum, n) => sum + n.nodeSize, 0);
|
|
214
|
+
const cursorPos = deletingFirstColumn ? columnParentFrom + 1 : columnParentFrom + totalReplacementSize;
|
|
215
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(cursorPos), direction === "right" ? 1 : -1));
|
|
216
|
+
} else {
|
|
217
|
+
const smallerLayoutType = state.schema.nodes[NODE_TYPE_MAP[remainingColumns.length]];
|
|
218
|
+
tr.replaceWith(columnParentFrom, columnParentTo, smallerLayoutType.create(columnParent.attrs, remainingColumns));
|
|
219
|
+
focusColumn(tr, columnParentFrom, remainingColumns, focusIndex, direction);
|
|
220
|
+
}
|
|
221
|
+
editor.view.dispatch(tr);
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
function focusColumn(tr, columnParentPos, columns, index, direction = "right") {
|
|
225
|
+
let pos = columnParentPos + 1;
|
|
226
|
+
for (let i = 0; i < index; i++) pos += columns[i].nodeSize;
|
|
227
|
+
pos += 1;
|
|
228
|
+
if (direction === "left") pos += columns[index].content.size;
|
|
229
|
+
const bias = direction === "right" ? 1 : -1;
|
|
230
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(pos), bias));
|
|
231
|
+
}
|
|
162
232
|
function createColumnsNode(config, includeCommands) {
|
|
163
233
|
return EmailNode.create({
|
|
164
234
|
name: config.name,
|
|
@@ -190,20 +260,20 @@ function createColumnsNode(config, includeCommands) {
|
|
|
190
260
|
];
|
|
191
261
|
},
|
|
192
262
|
...includeCommands && { addCommands() {
|
|
193
|
-
return { insertColumns: (count) => ({
|
|
263
|
+
return { insertColumns: (count) => ({ state, dispatch }) => {
|
|
194
264
|
if (getColumnsDepth(state.doc, state.selection.from) >= 3) return false;
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
265
|
+
const emptyColumn = () => state.schema.nodes.columnsColumn.create(null, state.schema.nodes.paragraph.create());
|
|
266
|
+
const columnBlock = state.schema.nodes[NODE_TYPE_MAP[count]].create(null, Array.from({ length: count }, emptyColumn));
|
|
267
|
+
const tr = state.tr.replaceSelectionWith(columnBlock);
|
|
268
|
+
const $head = tr.selection.$head;
|
|
269
|
+
for (let d = $head.depth; d >= 0; d--) {
|
|
270
|
+
if (!COLUMN_PARENT_SET.has($head.node(d).type.name)) continue;
|
|
271
|
+
const insertedColumns = Array.from({ length: $head.node(d).childCount }, (_, i) => $head.node(d).child(i));
|
|
272
|
+
focusColumn(tr, $head.before(d), insertedColumns, 0);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if (dispatch) dispatch(tr);
|
|
276
|
+
return true;
|
|
207
277
|
} };
|
|
208
278
|
} },
|
|
209
279
|
renderToReactEmail({ children, node, style }) {
|
|
@@ -251,21 +321,9 @@ const ColumnsColumn = EmailNode.create({
|
|
|
251
321
|
const { state } = editor;
|
|
252
322
|
const { selection } = state;
|
|
253
323
|
const { empty, $from } = selection;
|
|
254
|
-
if (!empty) return
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const indexInParent = $from.index(depth - 1);
|
|
258
|
-
if (indexInParent === 0) continue;
|
|
259
|
-
const prevNode = $from.node(depth - 1).child(indexInParent - 1);
|
|
260
|
-
if (COLUMN_PARENT_SET.has(prevNode.type.name)) {
|
|
261
|
-
const deleteFrom = $from.before(depth) - prevNode.nodeSize;
|
|
262
|
-
const deleteTo = $from.before(depth);
|
|
263
|
-
editor.view.dispatch(state.tr.delete(deleteFrom, deleteTo));
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
return false;
|
|
324
|
+
if (!empty) return handleNodeSelectionBackspace(editor, selection, $from, state);
|
|
325
|
+
if ($from.parentOffset !== 0) return false;
|
|
326
|
+
return handleCursorBackspace(editor, $from, state);
|
|
269
327
|
},
|
|
270
328
|
"Mod-a": ({ editor }) => {
|
|
271
329
|
const { state } = editor;
|
|
@@ -406,4 +464,4 @@ const FocusScopes = Extension.create({
|
|
|
406
464
|
//#endregion
|
|
407
465
|
export { TABLE_ATTRIBUTES as _, COLUMN_PARENT_TYPES as a, createStandardAttributes as b, MAX_COLUMNS_DEPTH as c, getColumnsDepth as d, hasPrismThemeLoaded as f, LAYOUT_ATTRIBUTES as g, COMMON_HTML_ATTRIBUTES as h, focusScopePluginKey as i, ThreeColumns as l, removePrismTheme as m, createFocusScopePlugin as n, ColumnsColumn as o, loadPrismTheme as p, createFocusScopesStorage as r, FourColumns as s, FocusScopes as t, TwoColumns as u, TABLE_CELL_ATTRIBUTES as v, TABLE_HEADER_ATTRIBUTES as y };
|
|
408
466
|
|
|
409
|
-
//# sourceMappingURL=focus-scopes-
|
|
467
|
+
//# sourceMappingURL=focus-scopes-DOsiXV7b.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-scopes-DOsiXV7b.mjs","names":["nativeTiptapExtensions"],"sources":["../src/utils/attribute-helpers.ts","../src/utils/prism-utils.ts","../src/extensions/columns.tsx","../src/extensions/focus-scopes.ts"],"sourcesContent":["/**\n * Creates TipTap attribute definitions for a list of HTML attributes.\n * Each attribute will have the same pattern:\n * - default: null\n * - parseHTML: extracts the attribute from the element\n * - renderHTML: conditionally renders the attribute if it has a value\n *\n * @param attributeNames - Array of HTML attribute names to create definitions for\n * @returns Object with TipTap attribute definitions\n *\n * @example\n * const attrs = createStandardAttributes(['class', 'id', 'title']);\n * // Returns:\n * // {\n * // class: {\n * // default: null,\n * // parseHTML: (element) => element.getAttribute('class'),\n * // renderHTML: (attributes) => attributes.class ? { class: attributes.class } : {}\n * // },\n * // ...\n * // }\n */\nexport function createStandardAttributes(attributeNames: readonly string[]) {\n return Object.fromEntries(\n attributeNames.map((attr) => [\n attr,\n {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute(attr),\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes[attr]) {\n return {};\n }\n\n return {\n [attr]: attributes[attr],\n };\n },\n },\n ]),\n );\n}\n\n/**\n * Common HTML attributes used across multiple extensions.\n * These preserve attributes during HTML import and editing for better\n * fidelity when importing existing email templates.\n */\nexport const COMMON_HTML_ATTRIBUTES = [\n 'id',\n 'class',\n 'title',\n 'lang',\n 'dir',\n 'data-id',\n] as const;\n\n/**\n * Layout-specific HTML attributes used for positioning and sizing.\n */\nexport const LAYOUT_ATTRIBUTES = ['align', 'width', 'height'] as const;\n\n/**\n * Table-specific HTML attributes used for table layout and styling.\n */\nexport const TABLE_ATTRIBUTES = [\n 'border',\n 'cellpadding',\n 'cellspacing',\n] as const;\n\n/**\n * Table cell-specific HTML attributes.\n */\nexport const TABLE_CELL_ATTRIBUTES = [\n 'valign',\n 'bgcolor',\n 'colspan',\n 'rowspan',\n] as const;\n\n/**\n * Table header cell-specific HTML attributes.\n * These are additional attributes that only apply to <th> elements.\n */\nexport const TABLE_HEADER_ATTRIBUTES = [\n ...TABLE_CELL_ATTRIBUTES,\n 'scope',\n] as const;\n","const publicURL = '/styles/prism';\n\nexport function loadPrismTheme(theme: string) {\n // Create new link element for the new theme\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = `${publicURL}/prism-${theme}.css`;\n link.setAttribute('data-prism-theme', ''); // Mark this link as the Prism theme\n\n // Append the new link element to the head\n document.head.appendChild(link);\n}\n\nexport function removePrismTheme() {\n const existingTheme = document.querySelectorAll(\n 'link[rel=\"stylesheet\"][data-prism-theme]',\n );\n if (existingTheme.length > 0) {\n existingTheme.forEach((cssLinkTag) => {\n cssLinkTag.remove();\n });\n }\n}\n\nexport function hasPrismThemeLoaded(theme: string) {\n const existingTheme = document.querySelector(\n `link[rel=\"stylesheet\"][data-prism-theme][href=\"${publicURL}/prism-${theme}.css\"]`,\n );\n return !!existingTheme;\n}\n","import { type CommandProps, type Editor, mergeAttributes } from '@tiptap/core';\nimport type { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model';\nimport {\n type EditorState,\n NodeSelection,\n TextSelection,\n type Transaction,\n} from '@tiptap/pm/state';\nimport { Column, Row } from 'react-email';\nimport { EmailNode } from '../core/serializer/email-node';\nimport {\n COMMON_HTML_ATTRIBUTES,\n createStandardAttributes,\n LAYOUT_ATTRIBUTES,\n} from '../utils/attribute-helpers';\nimport { inlineCssToJs } from '../utils/styles';\n\nconst COLUMN_PARENT_ATTRIBUTES = ['cellspacing'] as const;\n\nfunction getColumnGapCss(cellspacing: unknown): string | undefined {\n if (cellspacing === undefined || cellspacing === null || cellspacing === '') {\n return undefined;\n }\n\n const value = String(cellspacing).trim();\n if (value === '') {\n return undefined;\n }\n\n if (/^\\d+(\\.\\d+)?$/.test(value)) {\n return `${value}px`;\n }\n\n return value;\n}\n\nfunction getRowCellSpacing(cellspacing: unknown): string | undefined {\n if (cellspacing === undefined || cellspacing === null || cellspacing === '') {\n return undefined;\n }\n\n const value = String(cellspacing).trim();\n if (value === '' || value === '0') {\n return undefined;\n }\n\n return value;\n}\n\nfunction mergeColumnsEditorStyle(\n spacing: unknown,\n existingStyle: unknown,\n): string | undefined {\n const gap = getColumnGapCss(spacing);\n const currentStyle =\n typeof existingStyle === 'string' && existingStyle.trim() !== ''\n ? existingStyle.trim()\n : '';\n\n if (!gap) {\n return currentStyle || undefined;\n }\n\n const separator = currentStyle.endsWith(';') ? '' : ';';\n return currentStyle\n ? `${currentStyle}${separator}gap:${gap};`\n : `gap:${gap};`;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n columns: {\n insertColumns: (count: 2 | 3 | 4) => ReturnType;\n };\n }\n}\n\nexport const COLUMN_PARENT_TYPES = [\n 'twoColumns',\n 'threeColumns',\n 'fourColumns',\n] as const;\n\nconst COLUMN_PARENT_SET = new Set<string>(COLUMN_PARENT_TYPES);\n\nexport const MAX_COLUMNS_DEPTH = 3;\n\nexport function getColumnsDepth(doc: ProseMirrorNode, from: number): number {\n const $from = doc.resolve(from);\n let depth = 0;\n for (let d = $from.depth; d > 0; d--) {\n if (COLUMN_PARENT_SET.has($from.node(d).type.name)) {\n depth++;\n }\n }\n return depth;\n}\n\ninterface ColumnsVariantConfig {\n name: (typeof COLUMN_PARENT_TYPES)[number];\n columnCount: number;\n content: string;\n dataType: string;\n}\n\nconst VARIANTS: ColumnsVariantConfig[] = [\n {\n name: 'twoColumns',\n columnCount: 2,\n content: 'columnsColumn columnsColumn',\n dataType: 'two-columns',\n },\n {\n name: 'threeColumns',\n columnCount: 3,\n content: 'columnsColumn columnsColumn columnsColumn',\n dataType: 'three-columns',\n },\n {\n name: 'fourColumns',\n columnCount: 4,\n content: 'columnsColumn{4}',\n dataType: 'four-columns',\n },\n];\n\nconst NODE_TYPE_MAP: Record<number, (typeof COLUMN_PARENT_TYPES)[number]> = {\n 2: 'twoColumns',\n 3: 'threeColumns',\n 4: 'fourColumns',\n};\n\nfunction isColumnEmpty(col: ProseMirrorNode): boolean {\n return (\n col.childCount === 1 &&\n col.firstChild?.type.name === 'paragraph' &&\n col.firstChild?.childCount === 0\n );\n}\n\nfunction deleteColumnParent(\n editor: Editor,\n state: EditorState,\n from: number,\n to: number,\n parentChildCount: number,\n): boolean {\n const tr = state.tr;\n if (parentChildCount === 1) {\n tr.replaceWith(from, to, state.schema.nodes.paragraph.create());\n } else {\n tr.delete(from, to);\n }\n tr.setSelection(TextSelection.near(tr.doc.resolve(from)));\n editor.view.dispatch(tr);\n return true;\n}\n\nfunction handleNodeSelectionBackspace(\n editor: Editor,\n selection: EditorState['selection'],\n $from: ResolvedPos,\n state: EditorState,\n): boolean {\n if (!(selection instanceof NodeSelection)) return false;\n if (!COLUMN_PARENT_SET.has(selection.node.type.name)) return false;\n\n const allColumnsEmpty = Array.from(\n { length: selection.node.childCount },\n (_, i) => selection.node.child(i),\n ).every(isColumnEmpty);\n\n if (!allColumnsEmpty) return false;\n\n const parent = $from.node($from.depth);\n return deleteColumnParent(\n editor,\n state,\n selection.from,\n selection.to,\n parent.childCount,\n );\n}\n\nfunction handleCursorBackspace(\n editor: Editor,\n $from: ResolvedPos,\n state: EditorState,\n): boolean {\n for (let depth = $from.depth; depth >= 1; depth--) {\n const currentNode = $from.node(depth);\n\n if (currentNode.type.name === 'columnsColumn') {\n return handleBackspaceInsideColumn(editor, $from, state, depth);\n }\n\n const indexInParent = $from.index(depth - 1);\n\n if (indexInParent === 0) continue;\n\n const parent = $from.node(depth - 1);\n const prevNode = parent.child(indexInParent - 1);\n\n if (COLUMN_PARENT_SET.has(prevNode.type.name)) {\n const from = $from.before(depth) - prevNode.nodeSize;\n const to = $from.before(depth);\n editor.view.dispatch(state.tr.delete(from, to));\n return true;\n }\n\n break;\n }\n\n return false;\n}\n\nfunction handleBackspaceInsideColumn(\n editor: Editor,\n $from: ResolvedPos,\n state: EditorState,\n depth: number,\n): boolean {\n const column = $from.node(depth);\n const columnParent = $from.node(depth - 1);\n\n if (!COLUMN_PARENT_SET.has(columnParent.type.name)) return false;\n if (!isColumnEmpty(column)) return false;\n\n const deletedIndex = $from.index(depth - 1);\n const remainingColumns = Array.from(\n { length: columnParent.childCount },\n (_, i) => columnParent.child(i),\n ).filter((_, i) => i !== deletedIndex);\n\n const columnParentFrom = $from.before(depth - 1);\n const columnParentTo = $from.after(depth - 1);\n const tr = state.tr;\n const deletingFirstColumn = deletedIndex === 0;\n const focusIndex = deletingFirstColumn ? 0 : deletedIndex - 1;\n const direction = deletingFirstColumn ? 'right' : 'left';\n\n if (remainingColumns.length === 1) {\n // 2 → 1: replace the column layout with the surviving column's content\n const survivingContent = Array.from(\n { length: remainingColumns[0].childCount },\n (_, i) => remainingColumns[0].child(i),\n );\n const replacement =\n survivingContent.length > 0\n ? survivingContent\n : [state.schema.nodes.paragraph.create()];\n tr.replaceWith(columnParentFrom, columnParentTo, replacement);\n const totalReplacementSize = replacement.reduce(\n (sum, n) => sum + n.nodeSize,\n 0,\n );\n const cursorPos = deletingFirstColumn\n ? columnParentFrom + 1\n : columnParentFrom + totalReplacementSize;\n tr.setSelection(\n TextSelection.near(\n tr.doc.resolve(cursorPos),\n direction === 'right' ? 1 : -1,\n ),\n );\n } else {\n // 3 → 2 or 4 → 3: convert to the smaller column layout\n const smallerLayoutType =\n state.schema.nodes[NODE_TYPE_MAP[remainingColumns.length]];\n tr.replaceWith(\n columnParentFrom,\n columnParentTo,\n smallerLayoutType.create(columnParent.attrs, remainingColumns),\n );\n focusColumn(tr, columnParentFrom, remainingColumns, focusIndex, direction);\n }\n\n editor.view.dispatch(tr);\n return true;\n}\n\nfunction focusColumn(\n tr: Transaction,\n columnParentPos: number,\n columns: ProseMirrorNode[],\n index: number,\n direction: 'left' | 'right' = 'right',\n): void {\n let pos = columnParentPos + 1;\n for (let i = 0; i < index; i++) {\n pos += columns[i].nodeSize;\n }\n pos += 1;\n\n if (direction === 'left') {\n pos += columns[index].content.size;\n }\n\n const bias = direction === 'right' ? 1 : -1;\n tr.setSelection(TextSelection.near(tr.doc.resolve(pos), bias));\n}\n\nfunction createColumnsNode(\n config: ColumnsVariantConfig,\n includeCommands: boolean,\n) {\n return EmailNode.create({\n name: config.name,\n group: 'block',\n content: config.content,\n isolating: true,\n defining: true,\n\n addAttributes() {\n return createStandardAttributes([\n ...LAYOUT_ATTRIBUTES,\n ...COMMON_HTML_ATTRIBUTES,\n ...COLUMN_PARENT_ATTRIBUTES,\n ]);\n },\n\n parseHTML() {\n return [{ tag: `div[data-type=\"${config.dataType}\"]` }];\n },\n\n renderHTML({ HTMLAttributes }) {\n const { style, cellspacing, ...attributes } = HTMLAttributes as Record<\n string,\n unknown\n >;\n const mergedStyle = mergeColumnsEditorStyle(cellspacing, style);\n\n return [\n 'div',\n mergeAttributes(\n {\n 'data-type': config.dataType,\n class: 'node-columns',\n ...(mergedStyle ? { style: mergedStyle } : {}),\n },\n attributes,\n ),\n 0,\n ];\n },\n\n ...(includeCommands && {\n addCommands() {\n return {\n insertColumns:\n (count: 2 | 3 | 4) =>\n ({ state, dispatch }: CommandProps) => {\n const tooDeep =\n getColumnsDepth(state.doc, state.selection.from) >=\n MAX_COLUMNS_DEPTH;\n if (tooDeep) return false;\n\n const emptyColumn = () =>\n state.schema.nodes.columnsColumn.create(\n null,\n state.schema.nodes.paragraph.create(),\n );\n\n const columnBlock = state.schema.nodes[\n NODE_TYPE_MAP[count]\n ].create(null, Array.from({ length: count }, emptyColumn));\n\n const tr = state.tr.replaceSelectionWith(columnBlock);\n\n // Find the inserted column block and focus its first column\n const $head = tr.selection.$head;\n for (let d = $head.depth; d >= 0; d--) {\n if (!COLUMN_PARENT_SET.has($head.node(d).type.name)) continue;\n const insertedColumns = Array.from(\n { length: $head.node(d).childCount },\n (_, i) => $head.node(d).child(i),\n );\n focusColumn(tr, $head.before(d), insertedColumns, 0);\n break;\n }\n\n if (dispatch) dispatch(tr);\n return true;\n },\n };\n },\n }),\n\n renderToReactEmail({ children, node, style }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n const cellSpacing = getRowCellSpacing(node.attrs?.cellspacing);\n\n return (\n <Row\n className={node.attrs?.class || undefined}\n style={{ ...style, ...inlineStyles }}\n {...(cellSpacing ? { cellSpacing } : {})}\n >\n {children}\n </Row>\n );\n },\n });\n}\n\nexport const TwoColumns = createColumnsNode(VARIANTS[0], true);\nexport const ThreeColumns = createColumnsNode(VARIANTS[1], false);\nexport const FourColumns = createColumnsNode(VARIANTS[2], false);\n\nexport const ColumnsColumn = EmailNode.create({\n name: 'columnsColumn',\n group: 'columnsColumn',\n content: 'block+',\n isolating: true,\n\n addAttributes() {\n return {\n ...createStandardAttributes([\n ...LAYOUT_ATTRIBUTES,\n ...COMMON_HTML_ATTRIBUTES,\n ]),\n };\n },\n\n parseHTML() {\n return [{ tag: 'div[data-type=\"column\"]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'div',\n mergeAttributes(\n { 'data-type': 'column', class: 'node-column' },\n HTMLAttributes,\n ),\n 0,\n ];\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: ({ editor }) => {\n const { state } = editor;\n const { selection } = state;\n const { empty, $from } = selection;\n\n if (!empty) {\n return handleNodeSelectionBackspace(editor, selection, $from, state);\n }\n\n if ($from.parentOffset !== 0) return false;\n\n return handleCursorBackspace(editor, $from, state);\n },\n 'Mod-a': ({ editor }) => {\n const { state } = editor;\n const { $from } = state.selection;\n\n for (let d = $from.depth; d > 0; d--) {\n if ($from.node(d).type.name !== 'columnsColumn') {\n continue;\n }\n\n const columnStart = $from.start(d);\n const columnEnd = $from.end(d);\n const { from, to } = state.selection;\n\n if (from === columnStart && to === columnEnd) {\n return false;\n }\n\n editor.view.dispatch(\n state.tr.setSelection(\n TextSelection.create(state.doc, columnStart, columnEnd),\n ),\n );\n return true;\n }\n\n return false;\n },\n };\n },\n\n renderToReactEmail({ children, node, style }) {\n const inlineStyles = inlineCssToJs(node.attrs?.style);\n const width = node.attrs?.width;\n return (\n <Column\n className={node.attrs?.class || undefined}\n style={{\n ...style,\n ...inlineStyles,\n ...(width ? { width } : {}),\n }}\n >\n {children}\n </Column>\n );\n },\n});\n","import {\n type Editor,\n Extension,\n extensions as nativeTiptapExtensions,\n} from '@tiptap/core';\nimport { Plugin, PluginKey, TextSelection } from '@tiptap/pm/state';\n\nexport interface FocusScopesOptions {\n clearSelectionOnBlur: boolean;\n}\n\nexport interface FocusScopesStorage {\n registerScope: (el: HTMLElement | null) => void;\n unregisterScope: (el: HTMLElement | null) => void;\n}\n\ndeclare module '@tiptap/core' {\n interface Storage {\n focusScope: FocusScopesStorage;\n }\n}\n\nexport const focusScopePluginKey = new PluginKey('reactEmailFocusScopes');\n\nconst noop = () => {};\n\nexport function createFocusScopesStorage(): FocusScopesStorage {\n return {\n registerScope: noop,\n unregisterScope: noop,\n };\n}\n\nexport function createFocusScopePlugin({\n editor,\n storage,\n clearSelectionOnBlur,\n}: {\n editor: Editor;\n storage: FocusScopesStorage;\n clearSelectionOnBlur: boolean;\n}) {\n const scopeRefs = new Set<HTMLElement>();\n\n const isInsideScope = (node: Node | null) =>\n Boolean(node && [...scopeRefs].some((el) => el.contains(node)));\n\n const getClosestScope = (node: Node | null) => {\n if (!node) return null;\n\n let closest: HTMLElement | null = null;\n for (const scope of scopeRefs) {\n if (!scope.contains(node)) continue;\n if (!closest || closest.contains(scope)) {\n closest = scope;\n }\n }\n return closest;\n };\n\n const handleFocusIn = (event: FocusEvent) => {\n const target = event.target;\n if (!(target instanceof Node) || !editor.view.dom.contains(target)) {\n return;\n }\n\n const previous = editor.isFocused;\n editor.isFocused = true;\n\n if (previous !== editor.isFocused) {\n const transaction = editor.state.tr\n .setMeta('focus', { event })\n .setMeta('addToHistory', false);\n\n editor.view.dispatch(transaction);\n }\n };\n\n const handleFocusOut = (event: FocusEvent) => {\n const blur = () => {\n const previous = editor.isFocused;\n editor.isFocused = false;\n\n if (previous !== editor.isFocused) {\n const transaction = editor.state.tr\n .setMeta('blur', { event })\n .setMeta('addToHistory', false);\n\n if (clearSelectionOnBlur) {\n transaction.setSelection(TextSelection.create(transaction.doc, 0));\n }\n\n editor.view.dispatch(transaction);\n }\n };\n\n const nextFocus = event.relatedTarget as Node | null;\n if (!nextFocus) {\n const previousFocus = event.target as Node | null;\n const fallbackScope = getClosestScope(previousFocus);\n\n // queueMicrotask is needed so that we can determine reliably\n // whether or not previousFocus is inside of the DOM\n queueMicrotask(() => {\n if (isInsideScope(event.view?.document.activeElement ?? null)) {\n return;\n }\n\n if (!previousFocus?.isConnected && fallbackScope?.isConnected) {\n fallbackScope.focus({ preventScroll: true });\n return;\n }\n\n blur();\n });\n return;\n }\n\n if (isInsideScope(nextFocus)) {\n return;\n }\n\n blur();\n };\n\n const registerScope = (el: HTMLElement | null) => {\n if (!el || scopeRefs.has(el)) return;\n\n scopeRefs.add(el);\n el.addEventListener('focusin', handleFocusIn);\n el.addEventListener('focusout', handleFocusOut);\n };\n\n const unregisterScope = (el: HTMLElement | null) => {\n if (!el || !scopeRefs.has(el)) return;\n\n scopeRefs.delete(el);\n el.removeEventListener('focusin', handleFocusIn);\n el.removeEventListener('focusout', handleFocusOut);\n };\n\n storage.registerScope = registerScope;\n storage.unregisterScope = unregisterScope;\n\n return new Plugin({\n key: focusScopePluginKey,\n view(view) {\n storage.registerScope = registerScope;\n storage.unregisterScope = unregisterScope;\n registerScope(view.dom);\n\n return {\n destroy() {\n for (const scope of [...scopeRefs]) {\n unregisterScope(scope);\n }\n storage.registerScope = noop;\n storage.unregisterScope = noop;\n },\n };\n },\n });\n}\n\nexport const FocusScopes = Extension.create<\n FocusScopesOptions,\n FocusScopesStorage\n>({\n name: 'focusScope',\n\n addOptions() {\n return {\n clearSelectionOnBlur: true,\n };\n },\n\n addStorage() {\n return createFocusScopesStorage();\n },\n\n onCreate() {\n this.editor.unregisterPlugin(nativeTiptapExtensions.focusEventsPluginKey);\n },\n\n addProseMirrorPlugins() {\n return [\n createFocusScopePlugin({\n editor: this.editor,\n storage: this.storage,\n clearSelectionOnBlur: this.options.clearSelectionOnBlur,\n }),\n ];\n },\n});\n"],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
20
20
|
enumerable: true
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
//#endregion
|
|
23
|
-
const require_email_node = require("./email-node-
|
|
23
|
+
const require_email_node = require("./email-node-BhbXb22u.cjs");
|
|
24
24
|
let react_email = require("react-email");
|
|
25
25
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
26
26
|
let _tiptap_core = require("@tiptap/core");
|
|
@@ -181,6 +181,76 @@ const NODE_TYPE_MAP = {
|
|
|
181
181
|
3: "threeColumns",
|
|
182
182
|
4: "fourColumns"
|
|
183
183
|
};
|
|
184
|
+
function isColumnEmpty(col) {
|
|
185
|
+
return col.childCount === 1 && col.firstChild?.type.name === "paragraph" && col.firstChild?.childCount === 0;
|
|
186
|
+
}
|
|
187
|
+
function deleteColumnParent(editor, state, from, to, parentChildCount) {
|
|
188
|
+
const tr = state.tr;
|
|
189
|
+
if (parentChildCount === 1) tr.replaceWith(from, to, state.schema.nodes.paragraph.create());
|
|
190
|
+
else tr.delete(from, to);
|
|
191
|
+
tr.setSelection(_tiptap_pm_state.TextSelection.near(tr.doc.resolve(from)));
|
|
192
|
+
editor.view.dispatch(tr);
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
function handleNodeSelectionBackspace(editor, selection, $from, state) {
|
|
196
|
+
if (!(selection instanceof _tiptap_pm_state.NodeSelection)) return false;
|
|
197
|
+
if (!COLUMN_PARENT_SET.has(selection.node.type.name)) return false;
|
|
198
|
+
if (!Array.from({ length: selection.node.childCount }, (_, i) => selection.node.child(i)).every(isColumnEmpty)) return false;
|
|
199
|
+
const parent = $from.node($from.depth);
|
|
200
|
+
return deleteColumnParent(editor, state, selection.from, selection.to, parent.childCount);
|
|
201
|
+
}
|
|
202
|
+
function handleCursorBackspace(editor, $from, state) {
|
|
203
|
+
for (let depth = $from.depth; depth >= 1; depth--) {
|
|
204
|
+
if ($from.node(depth).type.name === "columnsColumn") return handleBackspaceInsideColumn(editor, $from, state, depth);
|
|
205
|
+
const indexInParent = $from.index(depth - 1);
|
|
206
|
+
if (indexInParent === 0) continue;
|
|
207
|
+
const prevNode = $from.node(depth - 1).child(indexInParent - 1);
|
|
208
|
+
if (COLUMN_PARENT_SET.has(prevNode.type.name)) {
|
|
209
|
+
const from = $from.before(depth) - prevNode.nodeSize;
|
|
210
|
+
const to = $from.before(depth);
|
|
211
|
+
editor.view.dispatch(state.tr.delete(from, to));
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
function handleBackspaceInsideColumn(editor, $from, state, depth) {
|
|
219
|
+
const column = $from.node(depth);
|
|
220
|
+
const columnParent = $from.node(depth - 1);
|
|
221
|
+
if (!COLUMN_PARENT_SET.has(columnParent.type.name)) return false;
|
|
222
|
+
if (!isColumnEmpty(column)) return false;
|
|
223
|
+
const deletedIndex = $from.index(depth - 1);
|
|
224
|
+
const remainingColumns = Array.from({ length: columnParent.childCount }, (_, i) => columnParent.child(i)).filter((_, i) => i !== deletedIndex);
|
|
225
|
+
const columnParentFrom = $from.before(depth - 1);
|
|
226
|
+
const columnParentTo = $from.after(depth - 1);
|
|
227
|
+
const tr = state.tr;
|
|
228
|
+
const deletingFirstColumn = deletedIndex === 0;
|
|
229
|
+
const focusIndex = deletingFirstColumn ? 0 : deletedIndex - 1;
|
|
230
|
+
const direction = deletingFirstColumn ? "right" : "left";
|
|
231
|
+
if (remainingColumns.length === 1) {
|
|
232
|
+
const survivingContent = Array.from({ length: remainingColumns[0].childCount }, (_, i) => remainingColumns[0].child(i));
|
|
233
|
+
const replacement = survivingContent.length > 0 ? survivingContent : [state.schema.nodes.paragraph.create()];
|
|
234
|
+
tr.replaceWith(columnParentFrom, columnParentTo, replacement);
|
|
235
|
+
const totalReplacementSize = replacement.reduce((sum, n) => sum + n.nodeSize, 0);
|
|
236
|
+
const cursorPos = deletingFirstColumn ? columnParentFrom + 1 : columnParentFrom + totalReplacementSize;
|
|
237
|
+
tr.setSelection(_tiptap_pm_state.TextSelection.near(tr.doc.resolve(cursorPos), direction === "right" ? 1 : -1));
|
|
238
|
+
} else {
|
|
239
|
+
const smallerLayoutType = state.schema.nodes[NODE_TYPE_MAP[remainingColumns.length]];
|
|
240
|
+
tr.replaceWith(columnParentFrom, columnParentTo, smallerLayoutType.create(columnParent.attrs, remainingColumns));
|
|
241
|
+
focusColumn(tr, columnParentFrom, remainingColumns, focusIndex, direction);
|
|
242
|
+
}
|
|
243
|
+
editor.view.dispatch(tr);
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
function focusColumn(tr, columnParentPos, columns, index, direction = "right") {
|
|
247
|
+
let pos = columnParentPos + 1;
|
|
248
|
+
for (let i = 0; i < index; i++) pos += columns[i].nodeSize;
|
|
249
|
+
pos += 1;
|
|
250
|
+
if (direction === "left") pos += columns[index].content.size;
|
|
251
|
+
const bias = direction === "right" ? 1 : -1;
|
|
252
|
+
tr.setSelection(_tiptap_pm_state.TextSelection.near(tr.doc.resolve(pos), bias));
|
|
253
|
+
}
|
|
184
254
|
function createColumnsNode(config, includeCommands) {
|
|
185
255
|
return require_email_node.EmailNode.create({
|
|
186
256
|
name: config.name,
|
|
@@ -212,20 +282,20 @@ function createColumnsNode(config, includeCommands) {
|
|
|
212
282
|
];
|
|
213
283
|
},
|
|
214
284
|
...includeCommands && { addCommands() {
|
|
215
|
-
return { insertColumns: (count) => ({
|
|
285
|
+
return { insertColumns: (count) => ({ state, dispatch }) => {
|
|
216
286
|
if (getColumnsDepth(state.doc, state.selection.from) >= 3) return false;
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
287
|
+
const emptyColumn = () => state.schema.nodes.columnsColumn.create(null, state.schema.nodes.paragraph.create());
|
|
288
|
+
const columnBlock = state.schema.nodes[NODE_TYPE_MAP[count]].create(null, Array.from({ length: count }, emptyColumn));
|
|
289
|
+
const tr = state.tr.replaceSelectionWith(columnBlock);
|
|
290
|
+
const $head = tr.selection.$head;
|
|
291
|
+
for (let d = $head.depth; d >= 0; d--) {
|
|
292
|
+
if (!COLUMN_PARENT_SET.has($head.node(d).type.name)) continue;
|
|
293
|
+
const insertedColumns = Array.from({ length: $head.node(d).childCount }, (_, i) => $head.node(d).child(i));
|
|
294
|
+
focusColumn(tr, $head.before(d), insertedColumns, 0);
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
if (dispatch) dispatch(tr);
|
|
298
|
+
return true;
|
|
229
299
|
} };
|
|
230
300
|
} },
|
|
231
301
|
renderToReactEmail({ children, node, style }) {
|
|
@@ -273,21 +343,9 @@ const ColumnsColumn = require_email_node.EmailNode.create({
|
|
|
273
343
|
const { state } = editor;
|
|
274
344
|
const { selection } = state;
|
|
275
345
|
const { empty, $from } = selection;
|
|
276
|
-
if (!empty) return
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const indexInParent = $from.index(depth - 1);
|
|
280
|
-
if (indexInParent === 0) continue;
|
|
281
|
-
const prevNode = $from.node(depth - 1).child(indexInParent - 1);
|
|
282
|
-
if (COLUMN_PARENT_SET.has(prevNode.type.name)) {
|
|
283
|
-
const deleteFrom = $from.before(depth) - prevNode.nodeSize;
|
|
284
|
-
const deleteTo = $from.before(depth);
|
|
285
|
-
editor.view.dispatch(state.tr.delete(deleteFrom, deleteTo));
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
return false;
|
|
346
|
+
if (!empty) return handleNodeSelectionBackspace(editor, selection, $from, state);
|
|
347
|
+
if ($from.parentOffset !== 0) return false;
|
|
348
|
+
return handleCursorBackspace(editor, $from, state);
|
|
291
349
|
},
|
|
292
350
|
"Mod-a": ({ editor }) => {
|
|
293
351
|
const { state } = editor;
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
require("./focus-scopes-
|
|
3
|
-
const require_core = require("./core-
|
|
4
|
-
const require_extensions = require("./extensions-
|
|
5
|
-
const require_extension = require("./extension-
|
|
6
|
-
const require_extension$1 = require("./extension-
|
|
7
|
-
const require_root = require("./root-
|
|
2
|
+
require("./focus-scopes-Ncj54H_M.cjs");
|
|
3
|
+
const require_core = require("./core-Dte9KXcz.cjs");
|
|
4
|
+
const require_extensions = require("./extensions-BQca53AB.cjs");
|
|
5
|
+
const require_extension = require("./extension-mBZiGbpM.cjs");
|
|
6
|
+
const require_extension$1 = require("./extension-bVrEjbFA.cjs");
|
|
7
|
+
const require_root = require("./root-snVuaxh6.cjs");
|
|
8
8
|
let _tiptap_react = require("@tiptap/react");
|
|
9
9
|
let react = require("react");
|
|
10
10
|
let _tiptap_html = require("@tiptap/html");
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as composeReactEmail } from "./core-CbSTyrV4.mjs";
|
|
2
|
-
import { t as StarterKit } from "./extensions-
|
|
2
|
+
import { t as StarterKit } from "./extensions-F1FqbQUp.mjs";
|
|
3
3
|
import { t as EmailTheming } from "./extension-B_qJnv3m.mjs";
|
|
4
4
|
import { t as createImageExtension } from "./extension-CDrL5i44.mjs";
|
|
5
|
-
import { t as SlashCommandRoot, x as BubbleMenu } from "./root-
|
|
5
|
+
import { t as SlashCommandRoot, x as BubbleMenu } from "./root-DYLwAjbF.mjs";
|
|
6
6
|
import { EditorProvider, useCurrentEditor } from "@tiptap/react";
|
|
7
7
|
import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef } from "react";
|
|
8
8
|
import { generateJSON } from "@tiptap/html";
|
package/dist/plugins/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
require("../focus-scopes-
|
|
3
|
-
const require_extension = require("../extension-
|
|
4
|
-
const require_extension$1 = require("../extension-
|
|
5
|
-
const require_image = require("../image-
|
|
2
|
+
require("../focus-scopes-Ncj54H_M.cjs");
|
|
3
|
+
const require_extension = require("../extension-mBZiGbpM.cjs");
|
|
4
|
+
const require_extension$1 = require("../extension-bVrEjbFA.cjs");
|
|
5
|
+
const require_image = require("../image-D8OUIgwB.cjs");
|
|
6
6
|
let react = require("react");
|
|
7
7
|
//#region src/plugins/image/slash-command.tsx
|
|
8
8
|
const imageSlashCommand = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as getColumnsDepth, i as focusScopePluginKey, n as createFocusScopePlugin, r as createFocusScopesStorage } from "./focus-scopes-
|
|
1
|
+
import { d as getColumnsDepth, i as focusScopePluginKey, n as createFocusScopePlugin, r as createFocusScopesStorage } from "./focus-scopes-DOsiXV7b.mjs";
|
|
2
2
|
import { t as editorEventBus } from "./event-bus-CqrIUE24.mjs";
|
|
3
3
|
import { t as setTextAlignment } from "./set-text-alignment-Bgdg7-5y.mjs";
|
|
4
4
|
import { useCurrentEditor, useEditorState } from "@tiptap/react";
|
|
@@ -2515,4 +2515,4 @@ function SlashCommandRoot({ items: itemsProp, filterItems: filterItemsProp, char
|
|
|
2515
2515
|
//#endregion
|
|
2516
2516
|
export { BubbleMenuButtonToolbar as $, BubbleMenuImageUnlink as A, ChevronDownIcon as At, BubbleMenuNodeSelector as B, BubbleMenuLinkDefault as C, Heading2Icon as Ct, BubbleMenuLinkForm as D, Columns3Icon as Dt, BubbleMenuLinkOpenLink as E, Columns4Icon as Et, RootWithDefault as F, AlignLeftIcon as Ft, BubbleMenuItalic as G, NodeSelectorRoot as H, BubbleMenuUppercase as I, AlignCenterIcon as It, EditorFocusScope as J, BubbleMenuItemGroup as K, BubbleMenuUnderline as L, BubbleMenuImageForm as M, CaseUpperIcon as Mt, BubbleMenuImageEditLink as N, BoldIcon as Nt, BubbleMenuLinkEditLink as O, Columns2Icon as Ot, BubbleMenuButtonDefault as P, AlignRightIcon as Pt, BubbleMenuButtonUnlink as Q, bubbleMenuTriggers as R, BubbleMenuSeparator as S, Heading3Icon as St, BubbleMenuLinkToolbar as T, ExternalLinkIcon as Tt, NodeSelectorTrigger as U, NodeSelectorContent as V, BubbleMenuLinkSelector as W, FocusScopeContext as X, EditorFocusScopeProvider as Y, useEditorFocusScope as Z, TWO_COLUMNS as _, MousePointerIcon as _t, BUTTON as a, BubbleMenuAlignCenter as at, isInsideNode as b, LinkIcon as bt, FOUR_COLUMNS as c, UnlinkIcon as ct, H3 as d, TextIcon as dt, BubbleMenuButtonForm as et, NUMBERED_LIST as f, StrikethroughIcon as ft, THREE_COLUMNS as g, PencilIcon as gt, TEXT as h, Rows2Icon as ht, BULLET_LIST as i, BubbleMenuAlignLeft as it, BubbleMenuImageToolbar as j, CheckIcon as jt, BubbleMenuImageDefault as k, CodeIcon as kt, H1 as l, UnderlineIcon as lt, SECTION as m, SplitSquareVerticalIcon as mt, filterAndRankItems as n, BubbleMenuBold as nt, CODE as o, BubbleMenuItem as ot, QUOTE as p, SquareCodeIcon as pt, BubbleMenuCode as q, scoreItem as r, BubbleMenuAlignRight as rt, DIVIDER as s, useBubbleMenuContext as st, SlashCommandRoot as t, BubbleMenuButtonEditLink as tt, H2 as u, TextQuoteIcon as ut, defaultSlashCommands as v, ListOrderedIcon as vt, BubbleMenuLinkUnlink as w, Heading1Icon as wt, BubbleMenu$1 as x, ItalicIcon as xt, isAtMaxColumnsDepth as y, ListIcon as yt, BubbleMenuStrike as z };
|
|
2517
2517
|
|
|
2518
|
-
//# sourceMappingURL=root-
|
|
2518
|
+
//# sourceMappingURL=root-DYLwAjbF.mjs.map
|