@cyberyozh/text-editor 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/editor.css +12 -2
  2. package/dist/editor.css.map +1 -1
  3. package/dist/editor.d.mts +1 -0
  4. package/dist/editor.d.ts +1 -0
  5. package/dist/editor.js +202 -139
  6. package/dist/editor.js.map +1 -1
  7. package/dist/editor.mjs +200 -137
  8. package/dist/editor.mjs.map +1 -1
  9. package/dist/render.js +76 -11
  10. package/dist/render.js.map +1 -1
  11. package/dist/render.mjs +76 -11
  12. package/dist/render.mjs.map +1 -1
  13. package/dist/styles/index.css +12 -2
  14. package/package.json +2 -4
  15. package/src/editor/controls/bubble-menu-content.tsx +4 -8
  16. package/src/editor/controls/callout-menu.tsx +2 -0
  17. package/src/editor/controls/drag-handle.tsx +6 -1
  18. package/src/editor/dialogs/add-link-dialog/add-link-dialog.css +12 -4
  19. package/src/editor/dialogs/add-link-dialog/add-link-dialog.tsx +65 -28
  20. package/src/editor/dialogs/image-dialog/image-dialog.tsx +1 -1
  21. package/src/editor/editor.tsx +19 -12
  22. package/src/editor/handlers/dialog-handlers.ts +87 -156
  23. package/src/editor/handlers/index.ts +1 -2
  24. package/src/extensions/base/compatibility.ts +52 -0
  25. package/src/extensions/base/figure.ts +7 -0
  26. package/src/extensions/base/link.ts +3 -3
  27. package/src/extensions/views/components/table.tsx +23 -4
  28. package/src/extensions/views/node-views/figure.tsx +1 -1
  29. package/src/render/static-renderer-config.tsx +1 -17
  30. package/src/styles/editor/base.css +1 -1
  31. package/src/styles/extensions/callout.css +1 -1
  32. package/src/translations/en.json +5 -1
  33. package/src/translations/ru.json +5 -1
  34. package/src/types/image-handler.ts +2 -0
  35. package/src/types/link.ts +9 -0
  36. package/src/editor/handlers/create-image-upload-handler.ts +0 -24
package/dist/editor.js CHANGED
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(editor_exports);
36
36
 
37
37
  // src/editor/editor.tsx
38
38
  var import_react36 = require("react");
39
- var import_state5 = require("@tiptap/pm/state");
39
+ var import_state6 = require("@tiptap/pm/state");
40
40
  var import_model = require("@tiptap/pm/model");
41
41
  var import_react37 = require("@tiptap/react");
42
42
  var import_menus = require("@tiptap/react/menus");
@@ -816,12 +816,8 @@ var BubbleMenuContent = ({ editor, onLinkClick }) => {
816
816
  editor.state.selection.$from.pos,
817
817
  editor.state.selection.$to.pos
818
818
  );
819
- let linkUrl;
820
- if (isLink) {
821
- const link = editor.getAttributes("link");
822
- linkUrl = link.href;
823
- }
824
- onLinkClick?.(selectedText, linkUrl);
819
+ const linkAttrs = editor.getAttributes("link");
820
+ onLinkClick?.({ title: selectedText, ...linkAttrs });
825
821
  openDialogCommand("link");
826
822
  };
827
823
  return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
@@ -1279,7 +1275,7 @@ var CalloutMenu = ({ isOpen, onClose, onColorSelect, editor, nodePos }) => {
1279
1275
  const b = parseInt(bgColor.slice(5, 7), 16);
1280
1276
  const brightness = (r * 299 + g * 587 + b * 114) / 1e3;
1281
1277
  const textColor = brightness > 128 ? "#000000" : "#FFFFFF";
1282
- editor.chain().setTextSelection({ from, to }).setColor(textColor).setNodeSelection(nodePos).updateAttributes("callout", { bgColor }).run();
1278
+ editor.chain().setTextSelection({ from, to }).setColor(textColor).setNodeSelection(nodePos).updateAttributes("callout", { bgColor }).updateAttributes("calloutTip", { bgColor }).updateAttributes("calloutAlert", { bgColor }).run();
1283
1279
  }
1284
1280
  }
1285
1281
  },
@@ -1313,7 +1309,7 @@ var DragHandle = ({ editor }) => {
1313
1309
  currentNodePosRef.current = pos;
1314
1310
  try {
1315
1311
  const node = editor.view.state.doc.nodeAt(pos);
1316
- const isCallout = node?.type.name === "callout";
1312
+ const isCallout = node?.type.name === "callout" || node?.type.name === "calloutAlert" || node?.type.name === "calloutTip";
1317
1313
  setIsCalloutNode(isCallout);
1318
1314
  if (prevPos !== null && prevPos !== pos) {
1319
1315
  setShowCalloutMenu(false);
@@ -1341,7 +1337,7 @@ var DragHandle = ({ editor }) => {
1341
1337
  if (node) {
1342
1338
  const from = pos + 1;
1343
1339
  const to = pos + node.nodeSize - 1;
1344
- editor.chain().setTextSelection({ from, to }).setColor(textColor).setNodeSelection(pos).updateAttributes("callout", { bgColor }).run();
1340
+ editor.chain().setTextSelection({ from, to }).setColor(textColor).setNodeSelection(pos).updateAttributes("callout", { bgColor }).updateAttributes("calloutTip", { bgColor }).updateAttributes("calloutAlert", { bgColor }).run();
1345
1341
  }
1346
1342
  setShowCalloutMenu(false);
1347
1343
  }
@@ -2010,7 +2006,8 @@ var ImageDialog = ({
2010
2006
  title: formState.title,
2011
2007
  caption: formState.caption,
2012
2008
  width: formState.width,
2013
- height: formState.height
2009
+ height: formState.height,
2010
+ storageKey: result.storageKey
2014
2011
  });
2015
2012
  handleClose();
2016
2013
  } finally {
@@ -2262,24 +2259,32 @@ var AddLinkDialog = ({
2262
2259
  open,
2263
2260
  onClose,
2264
2261
  onLinkAdd,
2265
- initialTitle = "",
2266
- initialUrl = ""
2262
+ linkDialogContext
2267
2263
  }) => {
2268
2264
  const translations2 = useTiptapTranslations();
2269
- const [title, setTitle] = (0, import_react15.useState)(initialTitle);
2270
- const [url, setUrl] = (0, import_react15.useState)(initialUrl);
2265
+ const initialLinkTarget = linkDialogContext?.target ? linkDialogContext.target === "_blank" : true;
2266
+ const initialLinkRel = linkDialogContext?.rel ? linkDialogContext.rel?.includes("noopener") : true;
2267
+ const [title, setTitle] = (0, import_react15.useState)(linkDialogContext?.title);
2268
+ const [url, setUrl] = (0, import_react15.useState)(linkDialogContext?.href);
2269
+ const [openInNewTab, setOpenInNewTab] = (0, import_react15.useState)(initialLinkTarget);
2270
+ const [addNoopener, setAddNoopener] = (0, import_react15.useState)(initialLinkRel);
2271
2271
  const [error, setError] = (0, import_react15.useState)("");
2272
2272
  const titleInputRef = (0, import_react15.useRef)(null);
2273
+ const clearDialogState = () => {
2274
+ setTitle(linkDialogContext?.title);
2275
+ setUrl(linkDialogContext?.href);
2276
+ setOpenInNewTab(initialLinkTarget);
2277
+ setAddNoopener(initialLinkRel);
2278
+ setError("");
2279
+ };
2273
2280
  (0, import_react15.useEffect)(() => {
2274
2281
  if (open) {
2275
- setTitle(initialTitle);
2276
- setUrl(initialUrl);
2277
- setError("");
2282
+ clearDialogState();
2278
2283
  setTimeout(() => {
2279
2284
  titleInputRef.current?.focus();
2280
2285
  }, 0);
2281
2286
  }
2282
- }, [open, initialTitle, initialUrl]);
2287
+ }, [open, linkDialogContext]);
2283
2288
  const validateUrl = (urlStr) => {
2284
2289
  if (!urlStr.trim()) {
2285
2290
  setError(translations2.link.emptyUrl);
@@ -2305,22 +2310,22 @@ var AddLinkDialog = ({
2305
2310
  };
2306
2311
  const handleSubmit = () => {
2307
2312
  setError("");
2308
- if (!title.trim()) {
2313
+ if (!title?.trim()) {
2309
2314
  setError(translations2.link.titleError);
2310
2315
  return;
2311
2316
  }
2312
- if (!validateUrl(url)) {
2317
+ if (!validateUrl(url ?? "")) {
2313
2318
  return;
2314
2319
  }
2315
- const hasProtocol = url.includes("://") || url.startsWith("mailto:") || url.startsWith("tel:");
2320
+ const hasProtocol = url?.includes("://") || url?.startsWith("mailto:") || url?.startsWith("tel:");
2316
2321
  const finalUrl = hasProtocol ? url : `https://${url}`;
2317
- onLinkAdd(title, finalUrl);
2322
+ const target = openInNewTab ? "_blank" : "_self";
2323
+ const rel = addNoopener ? "noopener noreferrer nofollow" : null;
2324
+ onLinkAdd({ title, href: finalUrl ?? "", target, rel });
2318
2325
  handleClose();
2319
2326
  };
2320
2327
  const handleClose = () => {
2321
- setTitle(initialTitle);
2322
- setUrl(initialUrl);
2323
- setError("");
2328
+ clearDialogState();
2324
2329
  onClose();
2325
2330
  };
2326
2331
  const handleKeyDown = (e) => {
@@ -2335,7 +2340,7 @@ var AddLinkDialog = ({
2335
2340
  open,
2336
2341
  handleClose,
2337
2342
  children: [
2338
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "link-dialog-title", children: initialUrl ? translations2.link.editLink : translations2.link.addLink }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "link-dialog-title", children: linkDialogContext?.href ? translations2.link.editLink : translations2.link.addLink }),
2339
2344
  /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("hr", { className: "link-dialog-divider" }),
2340
2345
  /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "link-dialog-content", children: [
2341
2346
  /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "link-dialog-form-group", children: [
@@ -2377,12 +2382,40 @@ var AddLinkDialog = ({
2377
2382
  type: "text",
2378
2383
  className: "link-dialog-input",
2379
2384
  placeholder: translations2.link.urlPlaceholder,
2380
- value: url,
2385
+ value: url ?? "",
2381
2386
  onChange: (e) => setUrl(e.target.value),
2382
2387
  onKeyDown: handleKeyDown
2383
2388
  }
2384
2389
  )
2385
2390
  ] }),
2391
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "link-dialog-form-group", children: [
2392
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "link-dialog-checkbox-label", children: [
2393
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
2394
+ "input",
2395
+ {
2396
+ type: "checkbox",
2397
+ checked: openInNewTab,
2398
+ onChange: (e) => setOpenInNewTab(e.target.checked)
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { children: translations2.link.openInNewTab })
2402
+ ] }),
2403
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "link-dialog-help-text", children: translations2.link.openInNewTabHelp })
2404
+ ] }),
2405
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "link-dialog-form-group", children: [
2406
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "link-dialog-checkbox-label", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
2408
+ "input",
2409
+ {
2410
+ type: "checkbox",
2411
+ checked: addNoopener,
2412
+ onChange: (e) => setAddNoopener(e.target.checked)
2413
+ }
2414
+ ),
2415
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { children: translations2.link.addNofollow })
2416
+ ] }),
2417
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "link-dialog-help-text", children: translations2.link.addNofollowHelp })
2418
+ ] }),
2386
2419
  error && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "link-dialog-error", children: error })
2387
2420
  ] }),
2388
2421
  /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "link-dialog-actions", children: [
@@ -2401,7 +2434,7 @@ var AddLinkDialog = ({
2401
2434
  className: "link-dialog-button-submit",
2402
2435
  onClick: handleSubmit,
2403
2436
  type: "button",
2404
- children: initialUrl ? translations2.link.editLink : translations2.link.addLink
2437
+ children: linkDialogContext?.href ? translations2.link.editLink : translations2.link.addLink
2405
2438
  }
2406
2439
  )
2407
2440
  ] })
@@ -3248,6 +3281,13 @@ var BaseFigure = import_extension_image.default.extend({
3248
3281
  caption: {
3249
3282
  default: null,
3250
3283
  parseHTML: (element) => element.querySelector("figcaption")?.textContent || null
3284
+ },
3285
+ storageKey: {
3286
+ default: null,
3287
+ parseHTML: (element) => element.getAttribute("data-storage-key"),
3288
+ renderHTML: (attributes) => ({
3289
+ "data-storage-key": attributes.storageKey
3290
+ })
3251
3291
  }
3252
3292
  };
3253
3293
  },
@@ -3338,6 +3378,32 @@ var BaseLegacyBookAlert = import_core8.Node.create({
3338
3378
  return {
3339
3379
  type: {
3340
3380
  default: "error"
3381
+ },
3382
+ bgColor: {
3383
+ default: null,
3384
+ parseHTML: (element) => {
3385
+ if (typeof element === "string") return null;
3386
+ return element.getAttribute("data-bg-color");
3387
+ },
3388
+ renderHTML: (attributes) => {
3389
+ if (!attributes.bgColor) return {};
3390
+ return {
3391
+ "data-bg-color": attributes.bgColor
3392
+ };
3393
+ }
3394
+ },
3395
+ emoji: {
3396
+ default: null,
3397
+ parseHTML: (element) => {
3398
+ if (typeof element === "string") return null;
3399
+ return element.getAttribute("data-emoji");
3400
+ },
3401
+ renderHTML: (attributes) => {
3402
+ if (!attributes.emoji) return {};
3403
+ return {
3404
+ "data-emoji": attributes.emoji
3405
+ };
3406
+ }
3341
3407
  }
3342
3408
  };
3343
3409
  },
@@ -3367,6 +3433,32 @@ var BaseLegacyBookTip = import_core8.Node.create({
3367
3433
  return {
3368
3434
  type: {
3369
3435
  default: "info"
3436
+ },
3437
+ bgColor: {
3438
+ default: null,
3439
+ parseHTML: (element) => {
3440
+ if (typeof element === "string") return null;
3441
+ return element.getAttribute("data-bg-color");
3442
+ },
3443
+ renderHTML: (attributes) => {
3444
+ if (!attributes.bgColor) return {};
3445
+ return {
3446
+ "data-bg-color": attributes.bgColor
3447
+ };
3448
+ }
3449
+ },
3450
+ emoji: {
3451
+ default: null,
3452
+ parseHTML: (element) => {
3453
+ if (typeof element === "string") return null;
3454
+ return element.getAttribute("data-emoji");
3455
+ },
3456
+ renderHTML: (attributes) => {
3457
+ if (!attributes.emoji) return {};
3458
+ return {
3459
+ "data-emoji": attributes.emoji
3460
+ };
3461
+ }
3370
3462
  }
3371
3463
  };
3372
3464
  },
@@ -4498,7 +4590,7 @@ var CustomQuoteSignView = (props) => {
4498
4590
  var import_react25 = require("@tiptap/react");
4499
4591
  var import_jsx_runtime89 = require("react/jsx-runtime");
4500
4592
  var FigureView = ({ node, getPos, editor }) => {
4501
- const { fileId, src, alt, title, caption, width, height } = node.attrs;
4593
+ const { fileId, src, alt, title, caption, width, height, storageKey } = node.attrs;
4502
4594
  const imageExtension = editor.extensionManager.extensions.find((ext) => ext.name === "image");
4503
4595
  const getImageById = imageExtension?.options.getImageById;
4504
4596
  const onFigureClick = imageExtension?.options.onFigureClick;
@@ -5165,31 +5257,24 @@ function getEditorExtensions(options) {
5165
5257
  }
5166
5258
 
5167
5259
  // src/editor/handlers/dialog-handlers.ts
5260
+ var import_state5 = require("@tiptap/pm/state");
5168
5261
  var createHandleImageAdd = (editor, closeDialogCommand, savedPos) => {
5169
5262
  return (attrs) => {
5170
5263
  if (!editor) return;
5171
5264
  const { state } = editor;
5172
- const { $from } = state.selection;
5173
- const text = $from.parent.textContent;
5174
- if (text.lastIndexOf("/") !== -1) {
5175
- editor.chain().focus().command(({ tr }) => {
5176
- const node = editor.schema.nodes.image.create({ ...attrs });
5177
- tr.replaceWith($from.before(), $from.after(), node);
5178
- return true;
5179
- }).scrollIntoView().run();
5180
- } else {
5181
- const insertPos = savedPos ?? state.selection.from;
5182
- editor.chain().focus().command(({ tr, state: state2 }) => {
5183
- const $pos = state2.doc.resolve(insertPos);
5184
- const figureNode = state2.schema.nodes.figure.create({ ...attrs });
5185
- if ($pos.parent.type.name === "paragraph" && $pos.parent.textContent === "") {
5186
- tr.replaceWith($pos.before(), $pos.after(), figureNode);
5187
- } else {
5188
- tr.insert(insertPos, figureNode);
5189
- }
5190
- return true;
5191
- }).scrollIntoView().run();
5192
- }
5265
+ const insertPos = savedPos ?? state.selection.from;
5266
+ editor.chain().focus().command(({ tr, state: state2 }) => {
5267
+ const $pos = state2.doc.resolve(insertPos);
5268
+ const imageNode = state2.schema.nodes.image.create({ ...attrs });
5269
+ if ($pos.parent.type.name === "paragraph" && $pos.parent.textContent === "") {
5270
+ tr.replaceWith($pos.before(), $pos.after(), imageNode);
5271
+ tr.setSelection(import_state5.TextSelection.near(tr.doc.resolve($pos.before())));
5272
+ } else {
5273
+ tr.insert(insertPos, imageNode);
5274
+ tr.setSelection(import_state5.TextSelection.near(tr.doc.resolve(insertPos)));
5275
+ }
5276
+ return true;
5277
+ }).run();
5193
5278
  closeDialogCommand();
5194
5279
  };
5195
5280
  };
@@ -5204,69 +5289,47 @@ var createHandleVideoAdd = (editor, closeDialogCommand, savedPos) => {
5204
5289
  return (url) => {
5205
5290
  if (!editor) return;
5206
5291
  const { state } = editor;
5207
- const { $from } = state.selection;
5208
- const text = $from.parent.textContent;
5209
- if (text.lastIndexOf("/") !== -1) {
5210
- editor.chain().focus().command(({ tr }) => {
5211
- tr.replaceWith(
5212
- $from.before(),
5213
- $from.after(),
5214
- editor.schema.nodes.video.create({ src: url })
5215
- );
5216
- return true;
5217
- }).scrollIntoView().run();
5218
- } else {
5219
- const insertPos = savedPos ?? state.selection.from;
5220
- editor.chain().focus().command(({ tr, state: state2 }) => {
5221
- const $pos = state2.doc.resolve(insertPos);
5222
- const videoNode = state2.schema.nodes.video.create({ src: url });
5223
- if ($pos.parent.type.name === "paragraph" && $pos.parent.textContent === "") {
5224
- tr.replaceWith($pos.before(), $pos.after(), videoNode);
5225
- } else {
5226
- tr.insert(insertPos, videoNode);
5227
- }
5228
- return true;
5229
- }).scrollIntoView().run();
5230
- }
5231
- closeDialogCommand();
5232
- };
5233
- };
5234
- var createHandleLinkAdd = (editor, closeDialogCommand, savedPos) => {
5235
- return (title, url) => {
5236
- if (!editor) return;
5237
- const hasSelection = !editor.state.selection.empty;
5238
- if (hasSelection) {
5239
- editor.chain().focus().command(({ tr, state }) => {
5240
- const { from, to } = state.selection;
5241
- tr.insertText(title, from, to);
5242
- tr.addMark(from, from + title.length, editor.schema.marks.link.create({ href: url }));
5243
- return true;
5244
- }).run();
5245
- } else {
5246
- const { state } = editor;
5247
- const { $from } = state.selection;
5248
- const text = $from.parent.textContent;
5249
- const nodeStart = $from.start();
5250
- const beforeCursor = text.substring(0, $from.pos - nodeStart);
5251
- const slashIndex = beforeCursor.lastIndexOf("/");
5252
- if (slashIndex !== -1) {
5253
- editor.chain().focus().command(({ tr }) => {
5254
- tr.delete(nodeStart + slashIndex, $from.pos);
5255
- return true;
5256
- }).extendMarkRange("link").setLink({ href: url }).insertContent(title).scrollIntoView().run();
5292
+ const insertPos = savedPos ?? state.selection.from;
5293
+ editor.chain().focus().command(({ tr, state: state2 }) => {
5294
+ const $pos = state2.doc.resolve(insertPos);
5295
+ const videoNode = state2.schema.nodes.video.create({ src: url });
5296
+ if ($pos.parent.type.name === "paragraph" && $pos.parent.textContent === "") {
5297
+ tr.replaceWith($pos.before(), $pos.after(), videoNode);
5298
+ tr.setSelection(import_state5.TextSelection.near(tr.doc.resolve($pos.before())));
5257
5299
  } else {
5258
- const insertPos = savedPos ?? state.selection.from;
5259
- editor.chain().focus().command(({ tr }) => {
5260
- const linkMark = editor.schema.marks.link.create({ href: url });
5261
- const textNode = editor.schema.text(title, [linkMark]);
5262
- tr.insert(insertPos, textNode);
5263
- return true;
5264
- }).scrollIntoView().run();
5300
+ tr.insert(insertPos, videoNode);
5301
+ tr.setSelection(import_state5.TextSelection.near(tr.doc.resolve(insertPos)));
5265
5302
  }
5266
- }
5303
+ return true;
5304
+ }).run();
5267
5305
  closeDialogCommand();
5268
5306
  };
5269
5307
  };
5308
+ var createHandleLinkAdd = (editor, closeDialogCommand, linkParams, savedPos) => {
5309
+ if (!editor) return;
5310
+ const hasSelection = !editor.state.selection.empty;
5311
+ const titleLength = linkParams.title?.length ?? 0;
5312
+ if (hasSelection) {
5313
+ editor.chain().focus().command(({ tr, state }) => {
5314
+ const { from, to } = state.selection;
5315
+ tr.insertText(linkParams.title ?? "", from, to);
5316
+ tr.addMark(from, from + titleLength, editor.schema.marks.link.create({ ...linkParams }));
5317
+ return true;
5318
+ }).run();
5319
+ } else {
5320
+ const { state } = editor;
5321
+ const insertPos = savedPos ?? state.selection.from;
5322
+ const titleLength2 = linkParams.title?.length ?? 0;
5323
+ editor.chain().focus().command(({ tr }) => {
5324
+ const linkMark = editor.schema.marks.link.create({ ...linkParams });
5325
+ const textNode = editor.schema.text(linkParams.title ?? "", [linkMark]);
5326
+ tr.insert(insertPos, textNode);
5327
+ tr.setSelection(import_state5.TextSelection.create(tr.doc, insertPos, insertPos + titleLength2));
5328
+ return true;
5329
+ }).run();
5330
+ }
5331
+ closeDialogCommand();
5332
+ };
5270
5333
  var createHandleKatexAdd = (editor, closeDialogCommand, savedPos) => {
5271
5334
  return (latex, pos) => {
5272
5335
  if (!editor) return;
@@ -5274,27 +5337,13 @@ var createHandleKatexAdd = (editor, closeDialogCommand, savedPos) => {
5274
5337
  editor.chain().setNodeSelection(pos).updateInlineMath({ latex }).focus().run();
5275
5338
  } else {
5276
5339
  const { state } = editor;
5277
- const { $from } = state.selection;
5278
- const text = $from.parent.textContent;
5279
- const nodeStart = $from.start();
5280
- const beforeCursor = text.substring(0, $from.pos - nodeStart);
5281
- const slashIndex = beforeCursor.lastIndexOf("/");
5282
- if (slashIndex !== -1) {
5283
- const deleteFrom = nodeStart + slashIndex;
5284
- const deleteTo = $from.pos;
5285
- editor.chain().focus().command(({ tr, state: state2 }) => {
5286
- const inlineMathNode = state2.schema.nodes.inlineMath.create({ latex });
5287
- tr.replaceRangeWith(deleteFrom, deleteTo, inlineMathNode);
5288
- return true;
5289
- }).scrollIntoView().run();
5290
- } else {
5291
- const insertPos = savedPos ?? state.selection.from;
5292
- editor.chain().focus().command(({ tr, state: state2 }) => {
5293
- const inlineMathNode = state2.schema.nodes.inlineMath.create({ latex });
5294
- tr.insert(insertPos, inlineMathNode);
5295
- return true;
5296
- }).scrollIntoView().run();
5297
- }
5340
+ const insertPos = savedPos ?? state.selection.from;
5341
+ editor.chain().focus().command(({ tr, state: state2 }) => {
5342
+ const inlineMathNode = state2.schema.nodes.inlineMath.create({ latex });
5343
+ tr.insert(insertPos, inlineMathNode);
5344
+ tr.setSelection(import_state5.TextSelection.near(tr.doc.resolve(insertPos)));
5345
+ return true;
5346
+ }).run();
5298
5347
  }
5299
5348
  closeDialogCommand();
5300
5349
  };
@@ -5746,7 +5795,11 @@ var ru_default = {
5746
5795
  invalidUrl: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 URL",
5747
5796
  emptyUrl: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 URL \u0441\u0441\u044B\u043B\u043A\u0438",
5748
5797
  addLinkTitle: "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443",
5749
- removeLinkTitle: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443"
5798
+ removeLinkTitle: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443",
5799
+ openInNewTab: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 \u043D\u043E\u0432\u043E\u0439 \u0432\u043A\u043B\u0430\u0434\u043A\u0435",
5800
+ openInNewTabHelp: "\u0421\u0441\u044B\u043B\u043A\u0430 \u043E\u0442\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u0432 \u043D\u043E\u0432\u043E\u043C \u043E\u043A\u043D\u0435 \u0438\u043B\u0438 \u0432\u043A\u043B\u0430\u0434\u043A\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430",
5801
+ addNofollow: '\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C rel="nofollow"',
5802
+ addNofollowHelp: "\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043F\u043E\u0438\u0441\u043A\u043E\u0432\u044B\u043C \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u043C \u043D\u0435 \u0443\u0447\u0438\u0442\u044B\u0432\u0430\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u043F\u0440\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0435 \u0440\u0435\u0439\u0442\u0438\u043D\u0433\u0430 \u0438 \u0438\u043D\u0434\u0435\u043A\u0441\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u043E\u043D\u0438 \u0440\u0430\u0437\u043C\u0435\u0449\u0435\u043D\u044B. \u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A\u043E \u0432\u0441\u0435\u043C \u0441\u0441\u044B\u043B\u043A\u0430\u043C \u043D\u0430 \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0438\u0435 \u0441\u0430\u0439\u0442\u044B."
5750
5803
  },
5751
5804
  lists: {
5752
5805
  bulletList: "\u041D\u0435\u043D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A",
@@ -5906,7 +5959,11 @@ var en_default = {
5906
5959
  invalidUrl: "Invalid URL",
5907
5960
  emptyUrl: "Enter link URL",
5908
5961
  addLinkTitle: "Add link",
5909
- removeLinkTitle: "Remove link"
5962
+ removeLinkTitle: "Remove link",
5963
+ openInNewTab: "Open in new tab",
5964
+ openInNewTabHelp: "Link will open in a new browser window or tab",
5965
+ addNofollow: 'Add rel="nofollow"',
5966
+ addNofollowHelp: "Tells search engines not to count this link when calculating page rankings and indexing. Recommended for all external links."
5910
5967
  },
5911
5968
  lists: {
5912
5969
  bulletList: "Bullet list",
@@ -6102,6 +6159,7 @@ function TiptapContent({
6102
6159
  return false;
6103
6160
  }
6104
6161
  },
6162
+ onCreate: ({ editor: editor2 }) => handleChange?.(editor2.getJSON()),
6105
6163
  onBlur: ({ editor: editor2 }) => handleChange?.(editor2.getJSON())
6106
6164
  },
6107
6165
  [lang]
@@ -6119,10 +6177,16 @@ function TiptapContent({
6119
6177
  setSavedDialogCursorPos(void 0);
6120
6178
  closeDialogCommand();
6121
6179
  };
6122
- const handleImageAdd = createHandleImageAdd(editor, handleCloseDialog, savedDialogCursorPos);
6180
+ const handleImageAdd = (attrs) => {
6181
+ createHandleImageAdd(editor, handleCloseDialog, savedDialogCursorPos)(attrs);
6182
+ };
6123
6183
  const handleImageEdit = createHandleImageEdit(editor, handleCloseDialog, editFigureContext?.pos);
6124
- const handleVideoAdd = createHandleVideoAdd(editor, handleCloseDialog, savedDialogCursorPos);
6125
- const handleLinkAdd = createHandleLinkAdd(editor, handleCloseDialog, savedDialogCursorPos);
6184
+ const handleVideoAdd = (url) => {
6185
+ createHandleVideoAdd(editor, handleCloseDialog, savedDialogCursorPos)(url);
6186
+ };
6187
+ const handleLinkAdd = (params) => {
6188
+ createHandleLinkAdd(editor, handleCloseDialog, params, savedDialogCursorPos);
6189
+ };
6126
6190
  const handleKatexAdd = (latex) => {
6127
6191
  const katexHandler = createHandleKatexAdd(editor, handleCloseDialog, savedDialogCursorPos);
6128
6192
  katexHandler(latex, katexDialogContext?.pos);
@@ -6134,7 +6198,7 @@ function TiptapContent({
6134
6198
  });
6135
6199
  }, [content, editor]);
6136
6200
  const shouldBubbleMenuShow = ({ state }) => {
6137
- if (state.selection instanceof import_state5.NodeSelection) {
6201
+ if (state.selection instanceof import_state6.NodeSelection) {
6138
6202
  return false;
6139
6203
  }
6140
6204
  if (state.selection.empty) {
@@ -6159,7 +6223,7 @@ function TiptapContent({
6159
6223
  BubbleMenuContent,
6160
6224
  {
6161
6225
  editor,
6162
- onLinkClick: (selectedText, url) => setLinkDialogContext({ selectedText, url })
6226
+ onLinkClick: (params) => setLinkDialogContext(params)
6163
6227
  }
6164
6228
  )
6165
6229
  }
@@ -6195,8 +6259,7 @@ function TiptapContent({
6195
6259
  open: true,
6196
6260
  onClose: handleCloseDialog,
6197
6261
  onLinkAdd: handleLinkAdd,
6198
- initialTitle: linkDialogContext?.selectedText || "",
6199
- initialUrl: linkDialogContext?.url || ""
6262
+ linkDialogContext
6200
6263
  }
6201
6264
  ),
6202
6265
  activeDialog === "video" && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(