@cyberyozh/text-editor 0.1.10 → 0.1.12

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/editor/editor.tsx
2
- import { useState as useState13, useEffect as useEffect10 } from "react";
2
+ import { useState as useState12, useEffect as useEffect9 } from "react";
3
3
  import { NodeSelection } from "@tiptap/pm/state";
4
4
  import { Slice } from "@tiptap/pm/model";
5
5
  import { useEditor, EditorContent } from "@tiptap/react";
@@ -1907,15 +1907,34 @@ var ImageDialog = ({
1907
1907
  const img = new Image();
1908
1908
  img.src = imageUrl;
1909
1909
  img.onload = () => {
1910
- const { width, height } = img;
1910
+ const naturalWidth = img.width;
1911
+ const naturalHeight = img.height;
1912
+ const naturalAspectRatio = naturalHeight / naturalWidth;
1913
+ let maxWidth;
1914
+ try {
1915
+ const editorElement = document.querySelector(".tiptap-content-wrapper");
1916
+ if (editorElement && editorElement.clientWidth > 0) {
1917
+ maxWidth = editorElement.clientWidth - 32;
1918
+ }
1919
+ } catch {
1920
+ }
1921
+ let finalWidth;
1922
+ let finalHeight;
1923
+ if (maxWidth && naturalWidth > maxWidth) {
1924
+ finalWidth = maxWidth;
1925
+ finalHeight = Math.round(maxWidth * naturalAspectRatio);
1926
+ } else {
1927
+ finalWidth = naturalWidth;
1928
+ finalHeight = naturalHeight;
1929
+ }
1911
1930
  setFormState((prev) => ({
1912
1931
  ...prev,
1913
1932
  file,
1914
1933
  fileUrl: imageUrl,
1915
1934
  title: file.name,
1916
1935
  alt: file.name,
1917
- width,
1918
- height
1936
+ width: finalWidth,
1937
+ height: finalHeight
1919
1938
  }));
1920
1939
  };
1921
1940
  };
@@ -3222,8 +3241,9 @@ var BaseFigure = Image2.extend({
3222
3241
  isolating: true,
3223
3242
  selectable: false,
3224
3243
  addOptions() {
3244
+ const parentOptions = this.parent?.() || {};
3225
3245
  return {
3226
- HTMLAttributes: {},
3246
+ ...parentOptions,
3227
3247
  getImageById: void 0,
3228
3248
  onFigureClick: void 0
3229
3249
  };
@@ -3757,7 +3777,7 @@ var BaseLegacyFigure = Image3.extend({
3757
3777
 
3758
3778
  // src/extensions/views/node-views/callout.tsx
3759
3779
  import { NodeViewContent, NodeViewWrapper } from "@tiptap/react";
3760
- import { useState as useState11 } from "react";
3780
+ import { useState as useState10 } from "react";
3761
3781
 
3762
3782
  // src/icons/color/TiptapCalloutError.tsx
3763
3783
  import { jsx as jsx71, jsxs as jsxs22 } from "react/jsx-runtime";
@@ -4346,27 +4366,23 @@ var PromptContent = ({ children, isEmpty, placeholder }) => /* @__PURE__ */ jsx8
4346
4366
  }
4347
4367
  ) });
4348
4368
 
4349
- // src/extensions/views/components/table.tsx
4350
- import { useEffect as useEffect8, useRef as useRef10, useState as useState10 } from "react";
4351
- import { jsx as jsx82, jsxs as jsxs33 } from "react/jsx-runtime";
4352
-
4353
4369
  // src/extensions/views/components/video.tsx
4354
- import { jsx as jsx83, jsxs as jsxs34 } from "react/jsx-runtime";
4370
+ import { jsx as jsx82, jsxs as jsxs33 } from "react/jsx-runtime";
4355
4371
  var Video = ({ src, children }) => {
4356
4372
  const videoInfo = detectVideoHosting(src);
4357
4373
  if (!videoInfo?.embedUrl) {
4358
- return /* @__PURE__ */ jsxs34("div", { className: "video-node", children: [
4359
- /* @__PURE__ */ jsx83("div", { className: "video-error", children: /* @__PURE__ */ jsx83("span", { children: "Unsupported or invalid video URL" }) }),
4374
+ return /* @__PURE__ */ jsxs33("div", { className: "video-node", children: [
4375
+ /* @__PURE__ */ jsx82("div", { className: "video-error", children: /* @__PURE__ */ jsx82("span", { children: "Unsupported or invalid video URL" }) }),
4360
4376
  children
4361
4377
  ] });
4362
4378
  }
4363
- return /* @__PURE__ */ jsxs34(
4379
+ return /* @__PURE__ */ jsxs33(
4364
4380
  "div",
4365
4381
  {
4366
4382
  className: "video-node",
4367
4383
  "data-video": "",
4368
4384
  children: [
4369
- /* @__PURE__ */ jsx83("div", { className: "video-player-wrapper", children: /* @__PURE__ */ jsx83(
4385
+ /* @__PURE__ */ jsx82("div", { className: "video-player-wrapper", children: /* @__PURE__ */ jsx82(
4370
4386
  "iframe",
4371
4387
  {
4372
4388
  className: "video-iframe",
@@ -4383,13 +4399,13 @@ var Video = ({ src, children }) => {
4383
4399
  };
4384
4400
 
4385
4401
  // src/editor/controls/emoji-picker.tsx
4386
- import { useEffect as useEffect9, useRef as useRef11 } from "react";
4402
+ import { useEffect as useEffect8, useRef as useRef10 } from "react";
4387
4403
  import EmojiPicker from "emoji-picker-react";
4388
- import { jsx as jsx84 } from "react/jsx-runtime";
4404
+ import { jsx as jsx83 } from "react/jsx-runtime";
4389
4405
  var EmojiPickerComponent = ({ isOpen, onClose, onEmojiSelect }) => {
4390
- const pickerRef = useRef11(null);
4406
+ const pickerRef = useRef10(null);
4391
4407
  const translations2 = useTiptapTranslations();
4392
- useEffect9(() => {
4408
+ useEffect8(() => {
4393
4409
  const handleClickOutside = (event) => {
4394
4410
  if (pickerRef.current && !pickerRef.current.contains(event.target)) {
4395
4411
  onClose();
@@ -4403,12 +4419,12 @@ var EmojiPickerComponent = ({ isOpen, onClose, onEmojiSelect }) => {
4403
4419
  };
4404
4420
  }, [isOpen, onClose]);
4405
4421
  if (!isOpen) return null;
4406
- return /* @__PURE__ */ jsx84(
4422
+ return /* @__PURE__ */ jsx83(
4407
4423
  "div",
4408
4424
  {
4409
4425
  ref: pickerRef,
4410
4426
  className: "tiptap__emoji-picker-wrapper",
4411
- children: /* @__PURE__ */ jsx84(
4427
+ children: /* @__PURE__ */ jsx83(
4412
4428
  EmojiPicker,
4413
4429
  {
4414
4430
  skinTonesDisabled: true,
@@ -4433,12 +4449,12 @@ var EmojiPickerComponent = ({ isOpen, onClose, onEmojiSelect }) => {
4433
4449
  };
4434
4450
 
4435
4451
  // src/extensions/views/node-views/callout.tsx
4436
- import { jsx as jsx85, jsxs as jsxs35 } from "react/jsx-runtime";
4452
+ import { jsx as jsx84, jsxs as jsxs34 } from "react/jsx-runtime";
4437
4453
  var CalloutView = (props) => {
4438
4454
  const type = props.node.attrs.type || "info";
4439
4455
  const bgColor = props.node.attrs.bgColor;
4440
4456
  const emoji = props.node.attrs.emoji;
4441
- const [showEmojiPicker, setShowEmojiPicker] = useState11(false);
4457
+ const [showEmojiPicker, setShowEmojiPicker] = useState10(false);
4442
4458
  const handleIconClick = (e) => {
4443
4459
  e.preventDefault();
4444
4460
  e.stopPropagation();
@@ -4448,23 +4464,23 @@ var CalloutView = (props) => {
4448
4464
  props.updateAttributes({ emoji: newEmoji });
4449
4465
  setShowEmojiPicker(false);
4450
4466
  };
4451
- return /* @__PURE__ */ jsx85(NodeViewWrapper, { children: /* @__PURE__ */ jsx85(
4467
+ return /* @__PURE__ */ jsx84(NodeViewWrapper, { children: /* @__PURE__ */ jsx84(
4452
4468
  Callout,
4453
4469
  {
4454
4470
  type,
4455
4471
  bgColor,
4456
4472
  emoji,
4457
- iconWrapper: (icon) => /* @__PURE__ */ jsxs35("div", { className: "callout-icon-wrapper", children: [
4458
- /* @__PURE__ */ jsx85(
4473
+ iconWrapper: (icon) => /* @__PURE__ */ jsxs34("div", { className: "callout-icon-wrapper", children: [
4474
+ /* @__PURE__ */ jsx84(
4459
4475
  "button",
4460
4476
  {
4461
4477
  className: "callout-icon-button",
4462
4478
  onClick: handleIconClick,
4463
4479
  type: "button",
4464
- children: /* @__PURE__ */ jsx85("div", { className: "callout-icon", children: icon })
4480
+ children: /* @__PURE__ */ jsx84("div", { className: "callout-icon", children: icon })
4465
4481
  }
4466
4482
  ),
4467
- /* @__PURE__ */ jsx85(
4483
+ /* @__PURE__ */ jsx84(
4468
4484
  EmojiPickerComponent,
4469
4485
  {
4470
4486
  isOpen: showEmojiPicker,
@@ -4473,101 +4489,101 @@ var CalloutView = (props) => {
4473
4489
  }
4474
4490
  )
4475
4491
  ] }),
4476
- children: /* @__PURE__ */ jsx85(NodeViewContent, { as: "div" })
4492
+ children: /* @__PURE__ */ jsx84(NodeViewContent, { as: "div" })
4477
4493
  }
4478
4494
  ) });
4479
4495
  };
4480
4496
 
4481
4497
  // src/extensions/views/node-views/code-block.tsx
4482
- import { useState as useState12 } from "react";
4498
+ import { useState as useState11 } from "react";
4483
4499
  import { NodeViewContent as NodeViewContent2, NodeViewWrapper as NodeViewWrapper2 } from "@tiptap/react";
4484
- import { jsx as jsx86 } from "react/jsx-runtime";
4500
+ import { jsx as jsx85 } from "react/jsx-runtime";
4485
4501
  var CodeBlockView = (props) => {
4486
- const [selectedLanguage, setSelectedLanguage] = useState12(props.node.attrs.language ?? "");
4502
+ const [selectedLanguage, setSelectedLanguage] = useState11(props.node.attrs.language ?? "");
4487
4503
  const translations2 = useTiptapTranslations();
4488
4504
  const handleLanguageChange = (language) => {
4489
4505
  props.updateAttributes({ language });
4490
4506
  setSelectedLanguage(language);
4491
4507
  };
4492
- return /* @__PURE__ */ jsx86(NodeViewWrapper2, { children: /* @__PURE__ */ jsx86(
4508
+ return /* @__PURE__ */ jsx85(NodeViewWrapper2, { children: /* @__PURE__ */ jsx85(
4493
4509
  CodeBlock,
4494
4510
  {
4495
4511
  language: selectedLanguage,
4496
4512
  isEditable: props.editor.isEditable,
4497
4513
  onLanguageChange: handleLanguageChange,
4498
4514
  translations: translations2,
4499
- children: /* @__PURE__ */ jsx86(NodeViewContent2, {})
4515
+ children: /* @__PURE__ */ jsx85(NodeViewContent2, {})
4500
4516
  }
4501
4517
  ) });
4502
4518
  };
4503
4519
 
4504
4520
  // src/extensions/views/node-views/copyable-text.tsx
4505
4521
  import { MarkViewContent } from "@tiptap/react";
4506
- import { jsx as jsx87 } from "react/jsx-runtime";
4522
+ import { jsx as jsx86 } from "react/jsx-runtime";
4507
4523
  var CopyableTextView = () => {
4508
- return /* @__PURE__ */ jsx87(CopyableText2, { children: /* @__PURE__ */ jsx87(MarkViewContent, {}) });
4524
+ return /* @__PURE__ */ jsx86(CopyableText2, { children: /* @__PURE__ */ jsx86(MarkViewContent, {}) });
4509
4525
  };
4510
4526
 
4511
4527
  // src/extensions/views/node-views/custom-quote.tsx
4512
4528
  import { NodeViewContent as NodeViewContent3, NodeViewWrapper as NodeViewWrapper3 } from "@tiptap/react";
4513
- import { jsx as jsx88 } from "react/jsx-runtime";
4529
+ import { jsx as jsx87 } from "react/jsx-runtime";
4514
4530
  var CustomQuoteView = () => {
4515
- return /* @__PURE__ */ jsx88(NodeViewWrapper3, { children: /* @__PURE__ */ jsx88(CustomQuote, { children: /* @__PURE__ */ jsx88(NodeViewContent3, {}) }) });
4531
+ return /* @__PURE__ */ jsx87(NodeViewWrapper3, { children: /* @__PURE__ */ jsx87(CustomQuote, { children: /* @__PURE__ */ jsx87(NodeViewContent3, {}) }) });
4516
4532
  };
4517
4533
  var CustomQuoteTextView = (props) => {
4518
4534
  const isEmpty = !props.node.content.size;
4519
4535
  const translations2 = useTiptapTranslations();
4520
- return /* @__PURE__ */ jsx88(NodeViewWrapper3, { children: /* @__PURE__ */ jsx88(
4536
+ return /* @__PURE__ */ jsx87(NodeViewWrapper3, { children: /* @__PURE__ */ jsx87(
4521
4537
  CustomQuoteText,
4522
4538
  {
4523
4539
  isEmpty,
4524
4540
  placeholder: translations2.customQuote.textPlaceholder,
4525
- children: /* @__PURE__ */ jsx88(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4541
+ children: /* @__PURE__ */ jsx87(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4526
4542
  }
4527
4543
  ) });
4528
4544
  };
4529
4545
  var CustomQuoteAuthorView = (props) => {
4530
4546
  const isEmpty = !props.node.content.size;
4531
4547
  const translations2 = useTiptapTranslations();
4532
- return /* @__PURE__ */ jsx88(NodeViewWrapper3, { children: /* @__PURE__ */ jsx88(
4548
+ return /* @__PURE__ */ jsx87(NodeViewWrapper3, { children: /* @__PURE__ */ jsx87(
4533
4549
  CustomQuoteAuthor,
4534
4550
  {
4535
4551
  isEmpty,
4536
4552
  placeholder: translations2.customQuote.authorPlaceholder,
4537
- children: /* @__PURE__ */ jsx88(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4553
+ children: /* @__PURE__ */ jsx87(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4538
4554
  }
4539
4555
  ) });
4540
4556
  };
4541
4557
  var CustomQuoteSignView = (props) => {
4542
4558
  const isEmpty = !props.node.content.size;
4543
4559
  const translations2 = useTiptapTranslations();
4544
- return /* @__PURE__ */ jsx88(NodeViewWrapper3, { children: /* @__PURE__ */ jsx88(
4560
+ return /* @__PURE__ */ jsx87(NodeViewWrapper3, { children: /* @__PURE__ */ jsx87(
4545
4561
  CustomQuoteSign,
4546
4562
  {
4547
4563
  isEmpty,
4548
4564
  placeholder: translations2.customQuote.signPlaceholder,
4549
- children: /* @__PURE__ */ jsx88(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4565
+ children: /* @__PURE__ */ jsx87(NodeViewContent3, { className: isEmpty ? "is-empty" : "" })
4550
4566
  }
4551
4567
  ) });
4552
4568
  };
4553
4569
 
4554
4570
  // src/extensions/views/node-views/figure.tsx
4555
4571
  import { NodeViewWrapper as NodeViewWrapper4 } from "@tiptap/react";
4556
- import { jsx as jsx89 } from "react/jsx-runtime";
4572
+ import { jsx as jsx88 } from "react/jsx-runtime";
4557
4573
  var FigureView = ({ node, getPos, editor }) => {
4558
- const { fileId, src, alt, title, caption, width, height, storageKey } = node.attrs;
4574
+ const { fileId, src, alt, title, caption, width, height } = node.attrs;
4559
4575
  const imageExtension = editor.extensionManager.extensions.find((ext) => ext.name === "image");
4560
4576
  const getImageById = imageExtension?.options.getImageById;
4561
4577
  const onFigureClick = imageExtension?.options.onFigureClick;
4562
4578
  const handleEditClick = () => {
4563
4579
  onFigureClick?.(node.attrs, getPos());
4564
4580
  };
4565
- return /* @__PURE__ */ jsx89(
4581
+ return /* @__PURE__ */ jsx88(
4566
4582
  NodeViewWrapper4,
4567
4583
  {
4568
4584
  className: "figure-node-view",
4569
4585
  "data-drag-handle": true,
4570
- children: /* @__PURE__ */ jsx89(
4586
+ children: /* @__PURE__ */ jsx88(
4571
4587
  Figure,
4572
4588
  {
4573
4589
  fileId,
@@ -4588,38 +4604,38 @@ var FigureView = ({ node, getPos, editor }) => {
4588
4604
 
4589
4605
  // src/extensions/views/node-views/prompt.tsx
4590
4606
  import { NodeViewContent as NodeViewContent4, NodeViewWrapper as NodeViewWrapper5 } from "@tiptap/react";
4591
- import { jsx as jsx90 } from "react/jsx-runtime";
4607
+ import { jsx as jsx89 } from "react/jsx-runtime";
4592
4608
  var PromptHeaderView = (props) => {
4593
4609
  const isEmpty = !props.node.content.size;
4594
4610
  const translations2 = useTiptapTranslations();
4595
- return /* @__PURE__ */ jsx90(NodeViewWrapper5, { children: /* @__PURE__ */ jsx90(
4611
+ return /* @__PURE__ */ jsx89(NodeViewWrapper5, { children: /* @__PURE__ */ jsx89(
4596
4612
  PromptHeader,
4597
4613
  {
4598
4614
  isEmpty,
4599
4615
  placeholder: translations2.prompt.headerPlaceholder,
4600
- children: /* @__PURE__ */ jsx90(NodeViewContent4, { className: isEmpty ? "is-empty" : "" })
4616
+ children: /* @__PURE__ */ jsx89(NodeViewContent4, { className: isEmpty ? "is-empty" : "" })
4601
4617
  }
4602
4618
  ) });
4603
4619
  };
4604
4620
  var PromptContentView = (props) => {
4605
4621
  const isEmpty = !props.node.content.size;
4606
4622
  const translations2 = useTiptapTranslations();
4607
- return /* @__PURE__ */ jsx90(NodeViewWrapper5, { children: /* @__PURE__ */ jsx90(
4623
+ return /* @__PURE__ */ jsx89(NodeViewWrapper5, { children: /* @__PURE__ */ jsx89(
4608
4624
  PromptContent,
4609
4625
  {
4610
4626
  isEmpty,
4611
4627
  placeholder: translations2.prompt.contentPlaceholder,
4612
- children: /* @__PURE__ */ jsx90(NodeViewContent4, { className: isEmpty ? "is-empty" : "" })
4628
+ children: /* @__PURE__ */ jsx89(NodeViewContent4, { className: isEmpty ? "is-empty" : "" })
4613
4629
  }
4614
4630
  ) });
4615
4631
  };
4616
4632
 
4617
4633
  // src/extensions/views/node-views/video.tsx
4618
4634
  import { NodeViewContent as NodeViewContent5, NodeViewWrapper as NodeViewWrapper6 } from "@tiptap/react";
4619
- import { jsx as jsx91 } from "react/jsx-runtime";
4635
+ import { jsx as jsx90 } from "react/jsx-runtime";
4620
4636
  var VideoView = (props) => {
4621
4637
  const { src } = props.node.attrs;
4622
- return /* @__PURE__ */ jsx91(NodeViewWrapper6, { children: /* @__PURE__ */ jsx91(Video, { src, children: /* @__PURE__ */ jsx91(
4638
+ return /* @__PURE__ */ jsx90(NodeViewWrapper6, { children: /* @__PURE__ */ jsx90(Video, { src, children: /* @__PURE__ */ jsx90(
4623
4639
  NodeViewContent5,
4624
4640
  {
4625
4641
  as: "div",
@@ -5138,9 +5154,159 @@ var LegacyPromptSEContent = BaseLegacyPromptSEContent.extend({
5138
5154
 
5139
5155
  // src/extensions/editor/figure.ts
5140
5156
  import { ReactNodeViewRenderer as ReactNodeViewRenderer6 } from "@tiptap/react";
5157
+ import { ResizableNodeView } from "@tiptap/core";
5141
5158
  var Figure2 = BaseFigure.extend({
5142
5159
  addNodeView() {
5143
- return ReactNodeViewRenderer6(FigureView);
5160
+ const resizeOptions = this.options.resize;
5161
+ if (!resizeOptions) {
5162
+ return ReactNodeViewRenderer6(FigureView);
5163
+ }
5164
+ return (props) => {
5165
+ const { node, getPos, editor } = props;
5166
+ const attrs = node.attrs;
5167
+ const imageExtension = editor.extensionManager.extensions.find(
5168
+ (ext) => ext.name === "image"
5169
+ );
5170
+ const getImageById = imageExtension?.options.getImageById;
5171
+ let imgSrc = attrs.src;
5172
+ if (attrs.fileId && getImageById) {
5173
+ const resolvedSrc = getImageById(attrs.fileId);
5174
+ if (resolvedSrc) imgSrc = resolvedSrc;
5175
+ }
5176
+ let maxWidth;
5177
+ try {
5178
+ if (editor.view?.dom) {
5179
+ const contentWrapper = editor.view.dom.closest(".tiptap-content-wrapper");
5180
+ if (contentWrapper && contentWrapper.clientWidth > 0) {
5181
+ maxWidth = contentWrapper.clientWidth - 32;
5182
+ }
5183
+ }
5184
+ } catch {
5185
+ }
5186
+ let naturalAspectRatio;
5187
+ let maxHeight;
5188
+ const constrainDimensions = (w, h) => {
5189
+ let constrainedW = w;
5190
+ let constrainedH = h;
5191
+ if (maxWidth && maxHeight && naturalAspectRatio && w >= maxWidth) {
5192
+ constrainedW = maxWidth;
5193
+ constrainedH = maxHeight;
5194
+ }
5195
+ return { width: constrainedW, height: constrainedH };
5196
+ };
5197
+ const updateImageDimensions = (width, height) => {
5198
+ imageContainer.style.width = `${width}px`;
5199
+ imageContainer.style.height = `${height}px`;
5200
+ };
5201
+ const figure = document.createElement("figure");
5202
+ figure.setAttribute("data-drag-handle", "");
5203
+ const imageContainer = document.createElement("div");
5204
+ imageContainer.className = "figure-image-container";
5205
+ const img = document.createElement("img");
5206
+ img.src = imgSrc || "";
5207
+ if (attrs.alt) img.alt = attrs.alt;
5208
+ if (attrs.title) img.title = attrs.title;
5209
+ if (attrs.width && attrs.height) {
5210
+ imageContainer.style.width = `${attrs.width}px`;
5211
+ imageContainer.style.height = `${attrs.height}px`;
5212
+ }
5213
+ img.onload = () => {
5214
+ naturalAspectRatio = img.naturalHeight / img.naturalWidth;
5215
+ if (maxWidth && naturalAspectRatio) {
5216
+ maxHeight = Math.round(maxWidth * naturalAspectRatio);
5217
+ }
5218
+ };
5219
+ imageContainer.appendChild(img);
5220
+ if (editor.isEditable) {
5221
+ const editButton = document.createElement("button");
5222
+ editButton.type = "button";
5223
+ editButton.className = "figure-edit-button";
5224
+ editButton.contentEditable = "false";
5225
+ editButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none"><path d="M2.52441 14.3751V17.5001H5.64941L14.8661 8.28346L11.7411 5.15846L2.52441 14.3751ZM17.2827 5.8668C17.6077 5.5418 17.6077 5.0168 17.2827 4.6918L15.3327 2.7418C15.0077 2.4168 14.4827 2.4168 14.1577 2.7418L12.6327 4.2668L15.7577 7.3918L17.2827 5.8668Z" fill="currentColor"/></svg>';
5226
+ editButton.addEventListener("click", () => {
5227
+ const onFigureClick = imageExtension?.options.onFigureClick;
5228
+ const pos = getPos();
5229
+ if (onFigureClick && typeof pos === "number") {
5230
+ onFigureClick(attrs, pos);
5231
+ }
5232
+ });
5233
+ imageContainer.appendChild(editButton);
5234
+ }
5235
+ const resizableView = new ResizableNodeView({
5236
+ element: imageContainer,
5237
+ node,
5238
+ getPos,
5239
+ onResize: (w, h) => {
5240
+ const { width, height } = constrainDimensions(w, h);
5241
+ updateImageDimensions(width, height);
5242
+ },
5243
+ onCommit: (w, h) => {
5244
+ const { width, height } = constrainDimensions(w, h);
5245
+ const pos = getPos();
5246
+ if (typeof pos === "number") {
5247
+ updateImageDimensions(Math.round(width), Math.round(height));
5248
+ editor.chain().focus().setNodeSelection(pos).updateAttributes("image", {
5249
+ width: Math.round(width),
5250
+ height: Math.round(height)
5251
+ }).run();
5252
+ }
5253
+ },
5254
+ onUpdate: (updatedNode) => {
5255
+ if (updatedNode.attrs.width) {
5256
+ imageContainer.style.width = `${updatedNode.attrs.width}px`;
5257
+ }
5258
+ if (updatedNode.attrs.height) {
5259
+ imageContainer.style.height = `${updatedNode.attrs.height}px`;
5260
+ }
5261
+ const existingCaption = figure.querySelector("figcaption");
5262
+ if (updatedNode.attrs.caption && !existingCaption) {
5263
+ const figcaption = document.createElement("figcaption");
5264
+ figcaption.textContent = updatedNode.attrs.caption;
5265
+ figure.appendChild(figcaption);
5266
+ } else if (existingCaption) {
5267
+ if (updatedNode.attrs.caption) {
5268
+ existingCaption.textContent = updatedNode.attrs.caption;
5269
+ } else {
5270
+ existingCaption.remove();
5271
+ }
5272
+ }
5273
+ if (updatedNode.type !== node.type) return false;
5274
+ return true;
5275
+ },
5276
+ options: {
5277
+ directions: resizeOptions.directions || [
5278
+ "bottom-right",
5279
+ "bottom-left",
5280
+ "top-right",
5281
+ "top-left"
5282
+ ],
5283
+ min: {
5284
+ width: resizeOptions.minWidth || 100,
5285
+ height: resizeOptions.minHeight || 100
5286
+ },
5287
+ max: maxWidth && maxHeight ? { width: maxWidth, height: maxHeight } : void 0,
5288
+ preserveAspectRatio: true,
5289
+ className: {
5290
+ container: "tiptap-resize-container",
5291
+ wrapper: "tiptap-resize-wrapper",
5292
+ handle: "tiptap-resize-handle",
5293
+ resizing: "is-resizing"
5294
+ }
5295
+ }
5296
+ });
5297
+ figure.appendChild(resizableView.dom);
5298
+ if (attrs.caption) {
5299
+ const figcaption = document.createElement("figcaption");
5300
+ figcaption.textContent = attrs.caption;
5301
+ figure.appendChild(figcaption);
5302
+ }
5303
+ return {
5304
+ dom: figure,
5305
+ contentDOM: resizableView.contentDOM,
5306
+ update: resizableView.update.bind(resizableView),
5307
+ destroy: resizableView.destroy?.bind(resizableView)
5308
+ };
5309
+ };
5144
5310
  }
5145
5311
  });
5146
5312
  var LegacyFigure = BaseLegacyFigure.extend({
@@ -5174,8 +5340,14 @@ function getEditorExtensions(options) {
5174
5340
  PromptHeader2,
5175
5341
  PromptContent2,
5176
5342
  Video2,
5177
- // Configure with optional getImageById for URL resolution and onFigureClick callback
5178
- Figure2.configure({ getImageById, onFigureClick }),
5343
+ Figure2.configure({
5344
+ getImageById,
5345
+ onFigureClick,
5346
+ resize: {
5347
+ enabled: true,
5348
+ directions: ["top-left", "top-right", "bottom-left", "bottom-right"]
5349
+ }
5350
+ }),
5179
5351
  Mathematics.configure({
5180
5352
  katexOptions: {
5181
5353
  throwOnError: false
@@ -5618,7 +5790,7 @@ var filterCommandItems = (items, query) => {
5618
5790
  };
5619
5791
 
5620
5792
  // src/editor/commands/suggestion.tsx
5621
- import { jsx as jsx92 } from "react/jsx-runtime";
5793
+ import { jsx as jsx91 } from "react/jsx-runtime";
5622
5794
  var component = null;
5623
5795
  var closeMenu = () => {
5624
5796
  if (component) {
@@ -5632,7 +5804,7 @@ var mapCommandMenuItemToCommandItem = (item) => {
5632
5804
  const IconComponent = item.icon;
5633
5805
  return {
5634
5806
  title: item.title,
5635
- icon: /* @__PURE__ */ jsx92(IconComponent, {}),
5807
+ icon: /* @__PURE__ */ jsx91(IconComponent, {}),
5636
5808
  command: ({ editor, range }) => {
5637
5809
  editor.chain().focus().deleteRange(range).run();
5638
5810
  item.onClick(editor);
@@ -6063,7 +6235,7 @@ function getTranslations(lang) {
6063
6235
  }
6064
6236
 
6065
6237
  // src/editor/editor.tsx
6066
- import { Fragment as Fragment3, jsx as jsx93, jsxs as jsxs36 } from "react/jsx-runtime";
6238
+ import { Fragment as Fragment3, jsx as jsx92, jsxs as jsxs35 } from "react/jsx-runtime";
6067
6239
  function TiptapContent({
6068
6240
  content,
6069
6241
  handleChange,
@@ -6073,12 +6245,12 @@ function TiptapContent({
6073
6245
  lang,
6074
6246
  error
6075
6247
  }) {
6076
- const [linkDialogContext, setLinkDialogContext] = useState13(null);
6077
- const [katexDialogContext, setKatexDialogContext] = useState13(
6248
+ const [linkDialogContext, setLinkDialogContext] = useState12(null);
6249
+ const [katexDialogContext, setKatexDialogContext] = useState12(
6078
6250
  null
6079
6251
  );
6080
- const [editFigureContext, setEditFigureContext] = useState13(null);
6081
- const [savedDialogCursorPos, setSavedDialogCursorPos] = useState13(void 0);
6252
+ const [editFigureContext, setEditFigureContext] = useState12(null);
6253
+ const [savedDialogCursorPos, setSavedDialogCursorPos] = useState12(void 0);
6082
6254
  const { activeDialog, closeDialogCommand, openDialogCommand } = useDialogCommand();
6083
6255
  const translations2 = useTiptapTranslations();
6084
6256
  let safeContent;
@@ -6129,7 +6301,7 @@ function TiptapContent({
6129
6301
  },
6130
6302
  [lang]
6131
6303
  );
6132
- useEffect10(() => {
6304
+ useEffect9(() => {
6133
6305
  if (activeDialog && editor && !editor.isDestroyed) {
6134
6306
  const pos = editor.state.selection.from;
6135
6307
  setSavedDialogCursorPos(pos);
@@ -6156,7 +6328,7 @@ function TiptapContent({
6156
6328
  const katexHandler = createHandleKatexAdd(editor, handleCloseDialog, savedDialogCursorPos);
6157
6329
  katexHandler(latex, katexDialogContext?.pos);
6158
6330
  };
6159
- useEffect10(() => {
6331
+ useEffect9(() => {
6160
6332
  if (!editor || editor.isDestroyed) return;
6161
6333
  editor.commands.setContent(safeContent, {
6162
6334
  emitUpdate: false
@@ -6175,16 +6347,16 @@ function TiptapContent({
6175
6347
  return true;
6176
6348
  };
6177
6349
  if (!editor) return null;
6178
- return /* @__PURE__ */ jsxs36(Fragment3, { children: [
6179
- /* @__PURE__ */ jsx93(DragHandle, { editor }),
6180
- isEditable && !isDisabled && /* @__PURE__ */ jsx93(TableMenu, { editor }),
6181
- isEditable && !isDisabled && /* @__PURE__ */ jsx93(
6350
+ return /* @__PURE__ */ jsxs35(Fragment3, { children: [
6351
+ /* @__PURE__ */ jsx92(DragHandle, { editor }),
6352
+ isEditable && !isDisabled && /* @__PURE__ */ jsx92(TableMenu, { editor }),
6353
+ isEditable && !isDisabled && /* @__PURE__ */ jsx92(
6182
6354
  BubbleMenu,
6183
6355
  {
6184
6356
  shouldShow: shouldBubbleMenuShow,
6185
6357
  editor,
6186
6358
  options: { placement: "bottom", offset: 8, flip: true },
6187
- children: /* @__PURE__ */ jsx93(
6359
+ children: /* @__PURE__ */ jsx92(
6188
6360
  BubbleMenuContent,
6189
6361
  {
6190
6362
  editor,
@@ -6193,19 +6365,19 @@ function TiptapContent({
6193
6365
  )
6194
6366
  }
6195
6367
  ),
6196
- /* @__PURE__ */ jsxs36(
6368
+ /* @__PURE__ */ jsxs35(
6197
6369
  "div",
6198
6370
  {
6199
6371
  className: `tiptap-content-wrapper ${!!error ? "has-error" : ""} ${isDisabled ? "is-disabled" : ""}`,
6200
6372
  children: [
6201
- /* @__PURE__ */ jsx93(EditorContent, { editor }),
6202
- isEditable && !isDisabled && /* @__PURE__ */ jsx93(CharacterCount, { editor })
6373
+ /* @__PURE__ */ jsx92(EditorContent, { editor }),
6374
+ isEditable && !isDisabled && /* @__PURE__ */ jsx92(CharacterCount, { editor })
6203
6375
  ]
6204
6376
  }
6205
6377
  ),
6206
- !!error && /* @__PURE__ */ jsx93("p", { className: "tiptap-error-message", children: error }),
6207
- isEditable && /* @__PURE__ */ jsxs36(Fragment3, { children: [
6208
- activeDialog === "image" && /* @__PURE__ */ jsx93(
6378
+ !!error && /* @__PURE__ */ jsx92("p", { className: "tiptap-error-message", children: error }),
6379
+ isEditable && /* @__PURE__ */ jsxs35(Fragment3, { children: [
6380
+ activeDialog === "image" && /* @__PURE__ */ jsx92(
6209
6381
  ImageDialog,
6210
6382
  {
6211
6383
  open: true,
@@ -6218,7 +6390,7 @@ function TiptapContent({
6218
6390
  mode: editFigureContext ? "edit" : "add"
6219
6391
  }
6220
6392
  ),
6221
- activeDialog === "link" && /* @__PURE__ */ jsx93(
6393
+ activeDialog === "link" && /* @__PURE__ */ jsx92(
6222
6394
  AddLinkDialog,
6223
6395
  {
6224
6396
  open: true,
@@ -6227,7 +6399,7 @@ function TiptapContent({
6227
6399
  linkDialogContext
6228
6400
  }
6229
6401
  ),
6230
- activeDialog === "video" && /* @__PURE__ */ jsx93(
6402
+ activeDialog === "video" && /* @__PURE__ */ jsx92(
6231
6403
  AddVideoDialog,
6232
6404
  {
6233
6405
  open: true,
@@ -6235,7 +6407,7 @@ function TiptapContent({
6235
6407
  onVideoAdd: handleVideoAdd
6236
6408
  }
6237
6409
  ),
6238
- activeDialog === "katex" && /* @__PURE__ */ jsx93(
6410
+ activeDialog === "katex" && /* @__PURE__ */ jsx92(
6239
6411
  AddKatexDialog,
6240
6412
  {
6241
6413
  open: true,
@@ -6250,7 +6422,7 @@ function TiptapContent({
6250
6422
  var Tiptap = (props) => {
6251
6423
  const { lang = "ru" } = props;
6252
6424
  const translations2 = getTranslations(lang);
6253
- return /* @__PURE__ */ jsx93(TiptapTranslationsProvider, { translations: translations2, children: /* @__PURE__ */ jsx93(DialogCommandProvider, { children: /* @__PURE__ */ jsx93(TiptapContent, { ...props }) }) });
6425
+ return /* @__PURE__ */ jsx92(TiptapTranslationsProvider, { translations: translations2, children: /* @__PURE__ */ jsx92(DialogCommandProvider, { children: /* @__PURE__ */ jsx92(TiptapContent, { ...props }) }) });
6254
6426
  };
6255
6427
  export {
6256
6428
  Tiptap