@cyberyozh/text-editor 0.1.16 → 0.2.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/editor.js CHANGED
@@ -36,10 +36,10 @@ __export(editor_exports, {
36
36
  module.exports = __toCommonJS(editor_exports);
37
37
 
38
38
  // src/editor/editor.tsx
39
- var import_react36 = require("react");
39
+ var import_react37 = require("react");
40
40
  var import_state6 = require("@tiptap/pm/state");
41
- var import_model = require("@tiptap/pm/model");
42
- var import_react37 = require("@tiptap/react");
41
+ var import_model2 = require("@tiptap/pm/model");
42
+ var import_react38 = require("@tiptap/react");
43
43
  var import_menus = require("@tiptap/react/menus");
44
44
  var import_github_dark = require("highlight.js/styles/github-dark.css");
45
45
  var import_katex_min = require("katex/dist/katex.min.css");
@@ -1917,6 +1917,7 @@ var import_jsx_runtime67 = require("react/jsx-runtime");
1917
1917
  var ImageDialog = ({
1918
1918
  open,
1919
1919
  onClose,
1920
+ defaultFile,
1920
1921
  onImageAdd,
1921
1922
  onImageEdit,
1922
1923
  uploadHandler,
@@ -2000,6 +2001,11 @@ var ImageDialog = ({
2000
2001
  }));
2001
2002
  };
2002
2003
  };
2004
+ (0, import_react13.useEffect)(() => {
2005
+ if (defaultFile) {
2006
+ handleSelectFile(defaultFile);
2007
+ }
2008
+ }, []);
2003
2009
  const handleAreaClick = () => {
2004
2010
  inputRef.current?.click();
2005
2011
  };
@@ -6470,7 +6476,8 @@ var Figure2 = BaseFigure.extend({
6470
6476
  };
6471
6477
  const updateImageDimensions = (width, height) => {
6472
6478
  imageContainer.style.width = `${width}px`;
6473
- imageContainer.style.height = `${height}px`;
6479
+ imageContainer.style.aspectRatio = `${width} / ${height}`;
6480
+ imageContainer.style.height = "";
6474
6481
  };
6475
6482
  const figure = document.createElement("figure");
6476
6483
  figure.setAttribute("data-drag-handle", "");
@@ -6482,7 +6489,7 @@ var Figure2 = BaseFigure.extend({
6482
6489
  if (attrs.title) img.title = attrs.title;
6483
6490
  if (attrs.width && attrs.height) {
6484
6491
  imageContainer.style.width = `${attrs.width}px`;
6485
- imageContainer.style.height = `${attrs.height}px`;
6492
+ imageContainer.style.aspectRatio = `${attrs.width} / ${attrs.height}`;
6486
6493
  }
6487
6494
  img.onload = () => {
6488
6495
  naturalAspectRatio = img.naturalHeight / img.naturalWidth;
@@ -6490,15 +6497,11 @@ var Figure2 = BaseFigure.extend({
6490
6497
  maxHeight = Math.round(maxWidth * naturalAspectRatio);
6491
6498
  }
6492
6499
  if (attrs.width && attrs.height && maxWidth && attrs.width > maxWidth) {
6493
- const width = maxWidth;
6494
- const height = Math.round(attrs.height / attrs.width * maxWidth);
6495
- imageContainer.style.width = `${width}px`;
6496
- imageContainer.style.height = `${height}px`;
6497
6500
  const pos = getPos();
6498
6501
  if (typeof pos === "number") {
6499
6502
  editor.chain().updateAttributes("image", {
6500
- width: Math.round(width),
6501
- height: Math.round(height)
6503
+ width: maxWidth,
6504
+ height: Math.round(attrs.height / attrs.width * maxWidth)
6502
6505
  }).run();
6503
6506
  }
6504
6507
  }
@@ -6540,11 +6543,12 @@ var Figure2 = BaseFigure.extend({
6540
6543
  }
6541
6544
  },
6542
6545
  onUpdate: (updatedNode) => {
6543
- if (updatedNode.attrs.width) {
6544
- imageContainer.style.width = `${updatedNode.attrs.width}px`;
6545
- }
6546
- if (updatedNode.attrs.height) {
6547
- imageContainer.style.height = `${updatedNode.attrs.height}px`;
6546
+ const newWidth = updatedNode.attrs.width;
6547
+ const newHeight = updatedNode.attrs.height;
6548
+ if (newWidth) imageContainer.style.width = `${newWidth}px`;
6549
+ if (newWidth && newHeight) {
6550
+ imageContainer.style.aspectRatio = `${newWidth} / ${newHeight}`;
6551
+ imageContainer.style.height = "";
6548
6552
  }
6549
6553
  const existingCaption = figure.querySelector("figcaption");
6550
6554
  if (updatedNode.attrs.caption && !existingCaption) {
@@ -6582,6 +6586,7 @@ var Figure2 = BaseFigure.extend({
6582
6586
  }
6583
6587
  }
6584
6588
  });
6589
+ imageContainer.style.height = "";
6585
6590
  figure.appendChild(resizableView.dom);
6586
6591
  if (attrs.caption) {
6587
6592
  const figcaption = document.createElement("figcaption");
@@ -6775,10 +6780,110 @@ var createHandleKatexAdd = (editor, closeDialogCommand, savedPos) => {
6775
6780
  };
6776
6781
  };
6777
6782
 
6783
+ // src/editor/handlers/insertion-handlers.ts
6784
+ var import_react35 = require("react");
6785
+
6786
+ // src/utils/prosemirror-iterator.ts
6787
+ var import_model = require("@tiptap/pm/model");
6788
+ function prosemirrorIterator(slice, cb) {
6789
+ const stack = [];
6790
+ if (slice instanceof import_model.Slice) {
6791
+ collectFragmentChildren(slice.content, stack);
6792
+ } else if (slice instanceof import_model.Fragment) {
6793
+ collectFragmentChildren(slice, stack);
6794
+ } else {
6795
+ stack.push(slice);
6796
+ }
6797
+ while (stack.length > 0) {
6798
+ const node = stack.pop();
6799
+ const shouldStop = cb(node);
6800
+ if (shouldStop === true) break;
6801
+ if (node.content.size > 0) {
6802
+ collectFragmentChildren(node.content, stack);
6803
+ }
6804
+ }
6805
+ }
6806
+ function collectFragmentChildren(fragment, stack) {
6807
+ for (let i = fragment.childCount - 1; i >= 0; i--) {
6808
+ stack.push(fragment.child(i));
6809
+ }
6810
+ }
6811
+
6812
+ // src/editor/handlers/insertion-handlers.ts
6813
+ function useInsertionHandlers() {
6814
+ const [insertedImage, setInsertedImage] = (0, import_react35.useState)(null);
6815
+ const { activeDialog, openDialogCommand } = useDialogCommand();
6816
+ (0, import_react35.useEffect)(() => {
6817
+ if (insertedImage && !activeDialog) {
6818
+ setInsertedImage(null);
6819
+ }
6820
+ }, [insertedImage, activeDialog]);
6821
+ function genericInsertionHandler(file, event) {
6822
+ if (!file || !file.type.startsWith("image/")) return;
6823
+ event.preventDefault();
6824
+ event.stopPropagation();
6825
+ setInsertedImage(file);
6826
+ openDialogCommand("image");
6827
+ }
6828
+ function onPaste(_, event) {
6829
+ const file = event.clipboardData?.files?.[0];
6830
+ genericInsertionHandler(file, event);
6831
+ }
6832
+ function onDrop(_, event) {
6833
+ const file = event.dataTransfer?.files?.[0];
6834
+ genericInsertionHandler(file, event);
6835
+ }
6836
+ function onMarkupInsertion(view, event, slice, setDisabled, uploadMultipleByURL) {
6837
+ if (!uploadMultipleByURL) return;
6838
+ let hasMarkupInsertion = false;
6839
+ if ("clipboardData" in event && Array.from(event.clipboardData?.items ?? []).some(
6840
+ (item) => item.type === "text/html"
6841
+ )) {
6842
+ hasMarkupInsertion = true;
6843
+ }
6844
+ if ("dataTransfer" in event && Array.from(event.dataTransfer?.items ?? []).some(
6845
+ (item) => item.type === "text/html"
6846
+ )) {
6847
+ hasMarkupInsertion = true;
6848
+ }
6849
+ if (hasMarkupInsertion) {
6850
+ const imagesToNodes = [];
6851
+ setDisabled(true);
6852
+ prosemirrorIterator(slice, (node) => {
6853
+ if (node.type.name === "image" && !node.attrs.fileId) {
6854
+ try {
6855
+ const url = new URL(node.attrs.src).toString();
6856
+ imagesToNodes.push([url, node]);
6857
+ } catch {
6858
+ }
6859
+ }
6860
+ });
6861
+ uploadMultipleByURL(imagesToNodes.map(([url]) => url)).then((results) => {
6862
+ results.forEach((result, index) => {
6863
+ const node = imagesToNodes[index][1];
6864
+ node.attrs.src = null;
6865
+ node.attrs.fileId = result?.fileId;
6866
+ node.attrs.storageKey = result?.storageKey;
6867
+ });
6868
+ view.dispatch(view.state.tr.replaceSelection(slice));
6869
+ }).finally(() => {
6870
+ setDisabled(false);
6871
+ });
6872
+ return true;
6873
+ }
6874
+ }
6875
+ return {
6876
+ insertedImage,
6877
+ onPaste,
6878
+ onDrop,
6879
+ onMarkupInsertion
6880
+ };
6881
+ }
6882
+
6778
6883
  // src/editor/commands/suggestion.tsx
6779
6884
  var import_dom = require("@floating-ui/dom");
6780
6885
  var import_core19 = require("@tiptap/core");
6781
- var import_react35 = require("@tiptap/react");
6886
+ var import_react36 = require("@tiptap/react");
6782
6887
 
6783
6888
  // src/editor/commands/items.ts
6784
6889
  var getCommandItems = (translations2, hasImageHandlers) => [
@@ -7111,7 +7216,7 @@ var createSuggestions = (translations2, hasImageHandlers) => ({
7111
7216
  render: () => {
7112
7217
  return {
7113
7218
  onStart: async (props) => {
7114
- component = new import_react35.ReactRenderer(CommandsList, {
7219
+ component = new import_react36.ReactRenderer(CommandsList, {
7115
7220
  props,
7116
7221
  editor: props.editor
7117
7222
  });
@@ -7534,27 +7639,35 @@ function TiptapContent({
7534
7639
  lang,
7535
7640
  error
7536
7641
  }) {
7537
- const [linkDialogContext, setLinkDialogContext] = (0, import_react36.useState)(null);
7538
- const [katexDialogContext, setKatexDialogContext] = (0, import_react36.useState)(
7642
+ const [linkDialogContext, setLinkDialogContext] = (0, import_react37.useState)(null);
7643
+ const [katexDialogContext, setKatexDialogContext] = (0, import_react37.useState)(
7539
7644
  null
7540
7645
  );
7541
- const [editFigureContext, setEditFigureContext] = (0, import_react36.useState)(null);
7542
- const [savedDialogCursorPos, setSavedDialogCursorPos] = (0, import_react36.useState)(void 0);
7646
+ const [editFigureContext, setEditFigureContext] = (0, import_react37.useState)(null);
7647
+ const [savedDialogCursorPos, setSavedDialogCursorPos] = (0, import_react37.useState)(void 0);
7543
7648
  const { activeDialog, closeDialogCommand, openDialogCommand } = useDialogCommand();
7544
7649
  const translations2 = useTiptapTranslations();
7650
+ const [isDisabledInternal, setIsDisabledInternal] = (0, import_react37.useState)(isDisabled);
7651
+ const disabled = isDisabled || isDisabledInternal;
7545
7652
  let safeContent;
7546
7653
  try {
7547
7654
  safeContent = JSON.parse(content);
7548
7655
  } catch {
7549
7656
  safeContent = { type: "doc", content: [{ type: "paragraph" }] };
7550
7657
  }
7551
- const editor = (0, import_react37.useEditor)(
7658
+ const {
7659
+ insertedImage,
7660
+ onPaste,
7661
+ onDrop,
7662
+ onMarkupInsertion
7663
+ } = useInsertionHandlers();
7664
+ const editor = (0, import_react38.useEditor)(
7552
7665
  {
7553
- editable: isEditable && !isDisabled,
7666
+ editable: isEditable && !disabled,
7554
7667
  extensions: getEditorExtensions({
7555
7668
  translations: translations2,
7556
7669
  suggestion: createSuggestions(translations2, !!imageHandlers),
7557
- isEditable: isEditable && !isDisabled,
7670
+ isEditable: isEditable && !disabled,
7558
7671
  getImageById: imageHandlers?.getImage,
7559
7672
  onKatexClick: (latex, pos) => {
7560
7673
  setKatexDialogContext({ latex, pos });
@@ -7568,14 +7681,38 @@ function TiptapContent({
7568
7681
  content: safeContent,
7569
7682
  immediatelyRender: false,
7570
7683
  editorProps: {
7571
- handlePaste: (view, event) => {
7684
+ handleDOMEvents: {
7685
+ paste: onPaste,
7686
+ drop: onDrop
7687
+ },
7688
+ handleDrop: (view, event, slice) => {
7689
+ if (view.dragging) return false;
7690
+ const toReturn = onMarkupInsertion(
7691
+ view,
7692
+ event,
7693
+ slice,
7694
+ setIsDisabledInternal,
7695
+ imageHandlers?.uploadMultipleByURL
7696
+ );
7697
+ if (typeof toReturn === "boolean") return toReturn;
7698
+ return false;
7699
+ },
7700
+ handlePaste: (view, event, slice) => {
7701
+ const toReturn = onMarkupInsertion(
7702
+ view,
7703
+ event,
7704
+ slice,
7705
+ setIsDisabledInternal,
7706
+ imageHandlers?.uploadMultipleByURL
7707
+ );
7708
+ if (typeof toReturn === "boolean") return toReturn;
7572
7709
  try {
7573
7710
  const text = event.clipboardData?.getData("text/plain");
7574
7711
  if (!text) return false;
7575
7712
  const json = JSON.parse(text);
7576
7713
  if (json.type === "doc" && json.content) {
7577
7714
  const node = view.state.schema.nodeFromJSON(json);
7578
- const newSlice = new import_model.Slice(node.content, 0, 0);
7715
+ const newSlice = new import_model2.Slice(node.content, 0, 0);
7579
7716
  view.dispatch(view.state.tr.replaceSelection(newSlice));
7580
7717
  return true;
7581
7718
  }
@@ -7590,7 +7727,7 @@ function TiptapContent({
7590
7727
  },
7591
7728
  [lang]
7592
7729
  );
7593
- (0, import_react36.useEffect)(() => {
7730
+ (0, import_react37.useEffect)(() => {
7594
7731
  if (activeDialog && editor && !editor.isDestroyed) {
7595
7732
  const pos = editor.state.selection.from;
7596
7733
  setSavedDialogCursorPos(pos);
@@ -7617,7 +7754,7 @@ function TiptapContent({
7617
7754
  const katexHandler = createHandleKatexAdd(editor, handleCloseDialog, savedDialogCursorPos);
7618
7755
  katexHandler(latex, katexDialogContext?.pos);
7619
7756
  };
7620
- (0, import_react36.useEffect)(() => {
7757
+ (0, import_react37.useEffect)(() => {
7621
7758
  if (!editor || editor.isDestroyed) return;
7622
7759
  editor.commands.setContent(safeContent, {
7623
7760
  emitUpdate: false
@@ -7638,8 +7775,8 @@ function TiptapContent({
7638
7775
  if (!editor) return null;
7639
7776
  return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(import_jsx_runtime92.Fragment, { children: [
7640
7777
  /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(DragHandle, { editor }),
7641
- isEditable && !isDisabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(TableMenu, { editor }),
7642
- isEditable && !isDisabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
7778
+ isEditable && !disabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(TableMenu, { editor }),
7779
+ isEditable && !disabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
7643
7780
  import_menus.BubbleMenu,
7644
7781
  {
7645
7782
  shouldShow: shouldBubbleMenuShow,
@@ -7657,10 +7794,10 @@ function TiptapContent({
7657
7794
  /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
7658
7795
  "div",
7659
7796
  {
7660
- className: `tiptap-content-wrapper ${!!error ? "has-error" : ""} ${isDisabled ? "is-disabled" : ""}`,
7797
+ className: `tiptap-content-wrapper ${!!error ? "has-error" : ""} ${disabled ? "is-disabled" : ""}`,
7661
7798
  children: [
7662
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(import_react37.EditorContent, { editor }),
7663
- isEditable && !isDisabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(CharacterCount, { editor })
7799
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(import_react38.EditorContent, { editor }),
7800
+ isEditable && !disabled && /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(CharacterCount, { editor })
7664
7801
  ]
7665
7802
  }
7666
7803
  ),
@@ -7671,6 +7808,7 @@ function TiptapContent({
7671
7808
  {
7672
7809
  open: true,
7673
7810
  onClose: handleCloseDialog,
7811
+ defaultFile: insertedImage,
7674
7812
  onImageAdd: handleImageAdd,
7675
7813
  onImageEdit: handleImageEdit,
7676
7814
  uploadHandler: imageHandlers?.upload,