@rufous/ui 0.2.54 → 0.2.56

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/main.js CHANGED
@@ -9118,7 +9118,7 @@ var TranslateModal = ({ editor, onClose, onTranslate, initialSource, initialTarg
9118
9118
  },
9119
9119
  /* @__PURE__ */ React110.createElement("span", { className: "translate-code" }, lang.code),
9120
9120
  /* @__PURE__ */ React110.createElement("span", { className: "translate-name" }, lang.name)
9121
- ))))), error && /* @__PURE__ */ React110.createElement("div", { className: "translate-error" }, error)), /* @__PURE__ */ React110.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React110.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React110.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "\xD7 Cancel")), /* @__PURE__ */ React110.createElement("button", { className: "modal-btn-apply", onClick: handleSave, disabled: translating }, translating ? "Translating..." : "\u2714 Save"))));
9121
+ ))))), error && /* @__PURE__ */ React110.createElement("div", { className: "translate-error" }, error)), /* @__PURE__ */ React110.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React110.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React110.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "Cancel")), /* @__PURE__ */ React110.createElement("button", { className: "modal-btn-apply", onClick: handleSave, disabled: translating }, translating ? "Translating..." : "Save"))));
9122
9122
  };
9123
9123
  var TranslateModal_default = TranslateModal;
9124
9124
 
@@ -9641,31 +9641,32 @@ var CustomTaskItem = TaskItem.extend({
9641
9641
  }
9642
9642
  }
9643
9643
  if (taskItemDepth === -1) {
9644
- const parentDepth = $from.depth > 0 ? $from.depth - 1 : 0;
9644
+ if ($from.depth < 1) return false;
9645
+ const parentDepth = $from.depth - 1;
9645
9646
  const indexInParent = $from.index(parentDepth);
9646
9647
  if (indexInParent > 0) {
9647
9648
  const prevNode = $from.node(parentDepth).child(indexInParent - 1);
9648
9649
  if (prevNode.type.name === "taskList") {
9649
- const lastTaskItem = prevNode.lastChild;
9650
- if (lastTaskItem) {
9650
+ try {
9651
9651
  const tr = state.tr;
9652
- const paraStart = $from.before($from.depth > 0 ? $from.depth : 1);
9653
- const paraEnd = $from.after($from.depth > 0 ? $from.depth : 1);
9652
+ const paraStart = $from.before($from.depth);
9653
+ const paraEnd = $from.after($from.depth);
9654
9654
  const paraContent = $from.parent.content;
9655
- const taskListStart = $from.before(parentDepth) !== void 0 ? paraStart - 1 : null;
9656
- if (taskListStart !== null) {
9657
- const $taskListEnd = tr.doc.resolve(taskListStart);
9658
- const lastItemParaEnd = $taskListEnd.end($taskListEnd.depth);
9659
- tr.delete(paraStart, paraEnd);
9660
- let insertAt = lastItemParaEnd;
9661
- paraContent.forEach((inline) => {
9662
- tr.insert(insertAt, inline);
9663
- insertAt += inline.nodeSize;
9664
- });
9665
- tr.setSelection(TextSelection.create(tr.doc, lastItemParaEnd));
9666
- this.editor.view.dispatch(tr);
9667
- return true;
9668
- }
9655
+ const taskListEndPos = paraStart - 1;
9656
+ if (taskListEndPos < 0) return false;
9657
+ const $taskListEnd = tr.doc.resolve(taskListEndPos);
9658
+ const lastItemParaEnd = $taskListEnd.end($taskListEnd.depth);
9659
+ tr.delete(paraStart, paraEnd);
9660
+ let insertAt = lastItemParaEnd;
9661
+ paraContent.forEach((inline) => {
9662
+ tr.insert(insertAt, inline);
9663
+ insertAt += inline.nodeSize;
9664
+ });
9665
+ tr.setSelection(TextSelection.create(tr.doc, lastItemParaEnd));
9666
+ this.editor.view.dispatch(tr);
9667
+ return true;
9668
+ } catch {
9669
+ return false;
9669
9670
  }
9670
9671
  }
9671
9672
  }
@@ -9736,7 +9737,8 @@ var CustomTaskItem = TaskItem.extend({
9736
9737
  "border: 2px solid " + colors.border,
9737
9738
  `background-image: url("${imageUrl}")`,
9738
9739
  "background-repeat: no-repeat",
9739
- "background-position: center"
9740
+ "background-position: center",
9741
+ "box-sizing: unset !important"
9740
9742
  ].join("; ");
9741
9743
  li.setAttribute("data-status", status);
9742
9744
  };
@@ -9967,12 +9969,24 @@ var Dropdown = ({ trigger, children, className = "", keepOpen = false }) => {
9967
9969
  const menu = menuRef.current;
9968
9970
  menu.style.left = "0";
9969
9971
  menu.style.right = "auto";
9970
- const rect = menu.getBoundingClientRect();
9971
- const vw = window.innerWidth;
9972
- if (rect.right > vw - 8) {
9973
- menu.style.left = "auto";
9974
- menu.style.right = "0";
9975
- }
9972
+ requestAnimationFrame(() => {
9973
+ if (!menu) return;
9974
+ const rect = menu.getBoundingClientRect();
9975
+ const vw = window.innerWidth;
9976
+ const parentLeft = ref.current?.getBoundingClientRect().left || 0;
9977
+ if (rect.right > vw - 8) {
9978
+ menu.style.left = "auto";
9979
+ menu.style.right = "0";
9980
+ const newRect = menu.getBoundingClientRect();
9981
+ if (newRect.left < 8) {
9982
+ menu.style.left = `${8 - parentLeft}px`;
9983
+ menu.style.right = "auto";
9984
+ }
9985
+ } else if (rect.left < 8) {
9986
+ menu.style.left = `${8 - parentLeft}px`;
9987
+ menu.style.right = "auto";
9988
+ }
9989
+ });
9976
9990
  }, [open]);
9977
9991
  return /* @__PURE__ */ React112.createElement("div", { className: `dropdown ${className}`, ref }, /* @__PURE__ */ React112.createElement(
9978
9992
  "button",
@@ -10237,10 +10251,11 @@ var ColorPickerPanel = ({ editor, onClose }) => {
10237
10251
  }
10238
10252
  ))), /* @__PURE__ */ React112.createElement("div", { className: "color-picker-footer" }, /* @__PURE__ */ React112.createElement("div", { className: "color-picker-preview", style: { background: activeColor || "#000" } }), /* @__PURE__ */ React112.createElement("button", { className: "color-picker-remove", onClick: removeColor, title: "Remove color" }, "\u2713")));
10239
10253
  };
10240
- var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload }) => {
10254
+ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons }) => {
10241
10255
  const [, setEditorState] = useState30(0);
10242
10256
  const [isFullscreen, setIsFullscreen] = useState30(false);
10243
10257
  const [todoEnabled, setTodoEnabled] = useState30(false);
10258
+ const show = (id) => !visibleButtons || visibleButtons.has(id);
10244
10259
  useEffect23(() => {
10245
10260
  if (!editor) return;
10246
10261
  const onTransaction = () => setEditorState((n) => n + 1);
@@ -10324,7 +10339,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10324
10339
  setTimeout(() => setTranslateStatus(""), 2e3);
10325
10340
  }, [editor, translateSource, translateTarget, onTranslate]);
10326
10341
  if (!editor) return null;
10327
- return /* @__PURE__ */ React112.createElement("div", { className: "toolbar" }, /* @__PURE__ */ React112.createElement("div", { className: `toolbar-row ${onClose ? "with-close" : ""}` }, /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(
10342
+ return /* @__PURE__ */ React112.createElement("div", { className: "toolbar" }, /* @__PURE__ */ React112.createElement("div", { className: `toolbar-row ${onClose ? "with-close" : ""}` }, (show("undo") || show("redo")) && /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, show("undo") && /* @__PURE__ */ React112.createElement(
10328
10343
  "button",
10329
10344
  {
10330
10345
  className: "toolbar-btn",
@@ -10333,7 +10348,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10333
10348
  title: "Undo (Ctrl+Z)"
10334
10349
  },
10335
10350
  /* @__PURE__ */ React112.createElement(IconUndo, null)
10336
- ), /* @__PURE__ */ React112.createElement(
10351
+ ), show("redo") && /* @__PURE__ */ React112.createElement(
10337
10352
  "button",
10338
10353
  {
10339
10354
  className: "toolbar-btn",
@@ -10342,7 +10357,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10342
10357
  title: "Redo (Ctrl+Y)"
10343
10358
  },
10344
10359
  /* @__PURE__ */ React112.createElement(IconRedo, null)
10345
- )), /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(AICommands_default, { editor, onAICommand })), /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(
10360
+ )), show("ai") && /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(AICommands_default, { editor, onAICommand })), /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, show("paragraph") && /* @__PURE__ */ React112.createElement(
10346
10361
  Dropdown,
10347
10362
  {
10348
10363
  trigger: {
@@ -10409,7 +10424,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10409
10424
  " Code Block"
10410
10425
  ),
10411
10426
  /* @__PURE__ */ React112.createElement("button", { className: "dropdown-item", onClick: () => editor.chain().focus().setHorizontalRule().run() }, "\u2014 Horizontal Rule")
10412
- ), /* @__PURE__ */ React112.createElement(
10427
+ ), show("fontsize") && /* @__PURE__ */ React112.createElement(
10413
10428
  Dropdown,
10414
10429
  {
10415
10430
  trigger: {
@@ -10436,7 +10451,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10436
10451
  sizeStr
10437
10452
  );
10438
10453
  })
10439
- ), /* @__PURE__ */ React112.createElement(
10454
+ ), show("font") && /* @__PURE__ */ React112.createElement(
10440
10455
  Dropdown,
10441
10456
  {
10442
10457
  trigger: {
@@ -10463,7 +10478,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10463
10478
  font
10464
10479
  );
10465
10480
  })
10466
- ), /* @__PURE__ */ React112.createElement(
10481
+ ), show("color") && /* @__PURE__ */ React112.createElement(
10467
10482
  Dropdown,
10468
10483
  {
10469
10484
  trigger: {
@@ -10473,7 +10488,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10473
10488
  keepOpen: true
10474
10489
  },
10475
10490
  (close) => /* @__PURE__ */ React112.createElement(ColorPickerPanel, { editor, onClose: close })
10476
- ), /* @__PURE__ */ React112.createElement(
10491
+ ), show("bold") && /* @__PURE__ */ React112.createElement(
10477
10492
  "button",
10478
10493
  {
10479
10494
  className: `toolbar-btn ${editor.isActive("bold") ? "is-active" : ""}`,
@@ -10481,7 +10496,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10481
10496
  title: "Bold (Ctrl+B)"
10482
10497
  },
10483
10498
  /* @__PURE__ */ React112.createElement(IconBold, null)
10484
- ), /* @__PURE__ */ React112.createElement(
10499
+ ), show("italic") && /* @__PURE__ */ React112.createElement(
10485
10500
  "button",
10486
10501
  {
10487
10502
  className: `toolbar-btn ${editor.isActive("italic") ? "is-active" : ""}`,
@@ -10489,7 +10504,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10489
10504
  title: "Italic (Ctrl+I)"
10490
10505
  },
10491
10506
  /* @__PURE__ */ React112.createElement(IconItalic, null)
10492
- ), /* @__PURE__ */ React112.createElement(
10507
+ ), show("strike") && /* @__PURE__ */ React112.createElement(
10493
10508
  Dropdown,
10494
10509
  {
10495
10510
  trigger: { label: /* @__PURE__ */ React112.createElement(IconStrike, null), title: "Text decoration", className: editor.isActive("strike") ? "is-active" : "" }
@@ -10514,7 +10529,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10514
10529
  c.run();
10515
10530
  }
10516
10531
  } }, "\u2715 Clear formatting")
10517
- ), /* @__PURE__ */ React112.createElement(
10532
+ ), show("link") && /* @__PURE__ */ React112.createElement(
10518
10533
  "button",
10519
10534
  {
10520
10535
  className: `toolbar-btn ${editor.isActive("link") ? "is-active" : ""}`,
@@ -10522,7 +10537,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10522
10537
  title: "Insert Link"
10523
10538
  },
10524
10539
  /* @__PURE__ */ React112.createElement(IconLink, null)
10525
- ), /* @__PURE__ */ React112.createElement(
10540
+ ), show("lineheight") && /* @__PURE__ */ React112.createElement(
10526
10541
  Dropdown,
10527
10542
  {
10528
10543
  trigger: {
@@ -10549,7 +10564,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10549
10564
  lh
10550
10565
  );
10551
10566
  })
10552
- )), /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(
10567
+ )), (show("ul") || show("ol")) && /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, show("ul") && /* @__PURE__ */ React112.createElement(
10553
10568
  Dropdown,
10554
10569
  {
10555
10570
  trigger: {
@@ -10592,7 +10607,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10592
10607
  " ",
10593
10608
  item.label
10594
10609
  ))
10595
- ), /* @__PURE__ */ React112.createElement(
10610
+ ), show("ol") && /* @__PURE__ */ React112.createElement(
10596
10611
  Dropdown,
10597
10612
  {
10598
10613
  trigger: {
@@ -10637,7 +10652,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10637
10652
  " ",
10638
10653
  item.label
10639
10654
  ))
10640
- )), /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, /* @__PURE__ */ React112.createElement(
10655
+ )), (show("align") || show("indent") || show("outdent")) && /* @__PURE__ */ React112.createElement("div", { className: "toolbar-group" }, show("align") && /* @__PURE__ */ React112.createElement(
10641
10656
  Dropdown,
10642
10657
  {
10643
10658
  trigger: {
@@ -10662,7 +10677,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10662
10677
  " ",
10663
10678
  item.label
10664
10679
  ))
10665
- ), /* @__PURE__ */ React112.createElement(
10680
+ ), show("indent") && /* @__PURE__ */ React112.createElement(
10666
10681
  "button",
10667
10682
  {
10668
10683
  className: "toolbar-btn",
@@ -10683,7 +10698,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10683
10698
  title: "Increase Indent"
10684
10699
  },
10685
10700
  /* @__PURE__ */ React112.createElement(IconIndentIncrease, null)
10686
- ), /* @__PURE__ */ React112.createElement(
10701
+ ), show("outdent") && /* @__PURE__ */ React112.createElement(
10687
10702
  "button",
10688
10703
  {
10689
10704
  className: "toolbar-btn",
@@ -10704,7 +10719,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10704
10719
  title: "Decrease Indent"
10705
10720
  },
10706
10721
  /* @__PURE__ */ React112.createElement(IconIndentDecrease, null)
10707
- )), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconTable, null), title: "Insert Table" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(TableGridSelector, { editor, onClose: close })), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconImage, null), title: "Insert Image" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(ImagePanel, { editor, onClose: close, onImageUpload })), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconVideo, null), title: "Insert Video" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(InsertPanel, { editor, onClose: close, mode: "video" })), /* @__PURE__ */ React112.createElement(
10722
+ )), show("table") && /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconTable, null), title: "Insert Table" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(TableGridSelector, { editor, onClose: close })), show("image") && /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconImage, null), title: "Insert Image" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(ImagePanel, { editor, onClose: close, onImageUpload })), show("video") && /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: /* @__PURE__ */ React112.createElement(IconVideo, null), title: "Insert Video" }, keepOpen: true }, (close) => /* @__PURE__ */ React112.createElement(InsertPanel, { editor, onClose: close, mode: "video" })), show("cut") && /* @__PURE__ */ React112.createElement(
10708
10723
  "button",
10709
10724
  {
10710
10725
  className: "toolbar-btn",
@@ -10712,7 +10727,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10712
10727
  title: "Cut (Ctrl+X)"
10713
10728
  },
10714
10729
  /* @__PURE__ */ React112.createElement(IconCut, null)
10715
- ), /* @__PURE__ */ React112.createElement(
10730
+ ), show("copy") && /* @__PURE__ */ React112.createElement(
10716
10731
  "button",
10717
10732
  {
10718
10733
  className: "toolbar-btn",
@@ -10720,7 +10735,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10720
10735
  title: "Copy selected text"
10721
10736
  },
10722
10737
  copySuccess ? /* @__PURE__ */ React112.createElement(IconCheck, null) : /* @__PURE__ */ React112.createElement(IconCopy, null)
10723
- ), /* @__PURE__ */ React112.createElement(
10738
+ ), show("paste") && /* @__PURE__ */ React112.createElement(
10724
10739
  "button",
10725
10740
  {
10726
10741
  className: "toolbar-btn",
@@ -10728,7 +10743,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10728
10743
  title: "Paste (Ctrl+V)"
10729
10744
  },
10730
10745
  /* @__PURE__ */ React112.createElement(IconPaste, null)
10731
- ), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: "\u03A9", title: "Special characters", className: "special-characters-btn" } }, /* @__PURE__ */ React112.createElement("div", { className: "char-grid" }, SPECIAL_CHARS.map((char) => /* @__PURE__ */ React112.createElement(
10746
+ ), show("specialchars") && /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: "\u03A9", title: "Special characters", className: "special-characters-btn" } }, /* @__PURE__ */ React112.createElement("div", { className: "char-grid" }, SPECIAL_CHARS.map((char) => /* @__PURE__ */ React112.createElement(
10732
10747
  "button",
10733
10748
  {
10734
10749
  key: char,
@@ -10736,7 +10751,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10736
10751
  onClick: () => insertSpecialChar(char)
10737
10752
  },
10738
10753
  char
10739
- )))), /* @__PURE__ */ React112.createElement(
10754
+ )))), show("code") && /* @__PURE__ */ React112.createElement(
10740
10755
  Dropdown,
10741
10756
  {
10742
10757
  trigger: { label: /* @__PURE__ */ React112.createElement(IconCode, null), title: "Code", className: editor.isActive("code") || editor.isActive("codeBlock") ? "is-active" : "" }
@@ -10760,7 +10775,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10760
10775
  }
10761
10776
  } }, "</>", " Inline Code"),
10762
10777
  /* @__PURE__ */ React112.createElement("button", { className: "dropdown-item", onClick: () => editor.chain().focus().toggleCodeBlock().run() }, "{ }", " Code Block")
10763
- ), /* @__PURE__ */ React112.createElement(
10778
+ ), show("fullscreen") && /* @__PURE__ */ React112.createElement(
10764
10779
  "button",
10765
10780
  {
10766
10781
  className: `toolbar-btn ${isFullscreen ? "is-active" : ""}`,
@@ -10768,7 +10783,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10768
10783
  title: "Toggle Fullscreen"
10769
10784
  },
10770
10785
  /* @__PURE__ */ React112.createElement(IconFullscreen, null)
10771
- ), /* @__PURE__ */ React112.createElement(TextToSpeech_default, { editor, onTextToSpeech }), /* @__PURE__ */ React112.createElement(SpeechToText_default, { editor, onSpeechToText }), /* @__PURE__ */ React112.createElement("div", { className: "translate-split-btn" }, /* @__PURE__ */ React112.createElement(
10786
+ ), show("tts") && /* @__PURE__ */ React112.createElement(TextToSpeech_default, { editor, onTextToSpeech }), show("stt") && /* @__PURE__ */ React112.createElement(SpeechToText_default, { editor, onSpeechToText }), show("translate") && /* @__PURE__ */ React112.createElement("div", { className: "translate-split-btn" }, /* @__PURE__ */ React112.createElement(
10772
10787
  "button",
10773
10788
  {
10774
10789
  className: "toolbar-btn",
@@ -10776,7 +10791,7 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10776
10791
  title: "Translate selected text"
10777
10792
  },
10778
10793
  /* @__PURE__ */ React112.createElement(IconTranslate, null)
10779
- ), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: "", title: "Translate options", className: "translate-arrow-btn" } }, /* @__PURE__ */ React112.createElement("button", { className: "dropdown-item", onClick: () => setShowTranslateModal(true) }, "Options")), translateStatus && /* @__PURE__ */ React112.createElement("span", { className: `translate-toast-popup ${translateStatus === "Please select the text" || translateStatus === "Translation failed" ? "error" : ""}` }, translateStatus)), /* @__PURE__ */ React112.createElement("div", { className: "todo-split-btn" }, /* @__PURE__ */ React112.createElement(
10794
+ ), /* @__PURE__ */ React112.createElement(Dropdown, { trigger: { label: "", title: "Translate options", className: "translate-arrow-btn" } }, /* @__PURE__ */ React112.createElement("button", { className: "dropdown-item", onClick: () => setShowTranslateModal(true) }, "Options")), translateStatus && /* @__PURE__ */ React112.createElement("span", { className: `translate-toast-popup ${translateStatus === "Please select the text" || translateStatus === "Translation failed" ? "error" : ""}` }, translateStatus)), show("todo") && /* @__PURE__ */ React112.createElement("div", { className: "todo-split-btn" }, /* @__PURE__ */ React112.createElement(
10780
10795
  "button",
10781
10796
  {
10782
10797
  className: `toolbar-btn ${todoEnabled ? "is-active" : ""}`,
@@ -11019,7 +11034,7 @@ var ImagePropertiesModal = ({ editor, node, onClose }) => {
11019
11034
  checked: openInNewTab,
11020
11035
  onChange: (e) => setOpenInNewTab(e.target.checked)
11021
11036
  }
11022
- ), "Open link in new tab")) : /* @__PURE__ */ React113.createElement(React113.Fragment, null, /* @__PURE__ */ React113.createElement("label", { className: "modal-label" }, "CSS Class"), /* @__PURE__ */ React113.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. rounded shadow" }), /* @__PURE__ */ React113.createElement("label", { className: "modal-label" }, "Inline Style"), /* @__PURE__ */ React113.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. border: 1px solid #ccc" }))))), /* @__PURE__ */ React113.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React113.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "\xD7 Cancel"), /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "\u{1F5D1} Delete")), /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "\u2714 Apply"))));
11037
+ ), "Open link in new tab")) : /* @__PURE__ */ React113.createElement(React113.Fragment, null, /* @__PURE__ */ React113.createElement("label", { className: "modal-label" }, "CSS Class"), /* @__PURE__ */ React113.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. rounded shadow" }), /* @__PURE__ */ React113.createElement("label", { className: "modal-label" }, "Inline Style"), /* @__PURE__ */ React113.createElement("input", { type: "text", className: "modal-input", placeholder: "e.g. border: 1px solid #ccc" }))))), /* @__PURE__ */ React113.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React113.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "Cancel"), /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "Delete")), /* @__PURE__ */ React113.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "Apply"))));
11023
11038
  };
11024
11039
  var ImageToolbar = ({ editor }) => {
11025
11040
  const [showModal, setShowModal] = useState31(false);
@@ -11272,7 +11287,7 @@ var VideoPropertiesModal = ({ editor, node, nodeType, onClose }) => {
11272
11287
  value: height,
11273
11288
  onChange: (e) => handleHeightChange(e.target.value)
11274
11289
  }
11275
- )))), /* @__PURE__ */ React114.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React114.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "\xD7 Cancel"), /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "\u{1F5D1} Delete")), /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "\u2714 Apply"))));
11290
+ )))), /* @__PURE__ */ React114.createElement("div", { className: "modal-footer" }, /* @__PURE__ */ React114.createElement("div", { className: "modal-footer-left" }, /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-cancel", onClick: onClose }, "Cancel"), /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-delete", onClick: handleDelete }, "Delete")), /* @__PURE__ */ React114.createElement("button", { className: "modal-btn-apply", onClick: handleApply }, "Apply"))));
11276
11291
  };
11277
11292
  var VideoToolbar = ({ editor }) => {
11278
11293
  const [showModal, setShowModal] = useState32(false);
@@ -11405,6 +11420,62 @@ var VideoToolbar = ({ editor }) => {
11405
11420
  var VideoToolbar_default = VideoToolbar;
11406
11421
 
11407
11422
  // lib/RufousTextEditor/RufousTextEditor.tsx
11423
+ var VARIANT_BUTTONS = {
11424
+ default: [
11425
+ "undo",
11426
+ "redo",
11427
+ "|",
11428
+ "ai",
11429
+ "|",
11430
+ "paragraph",
11431
+ "fontsize",
11432
+ "font",
11433
+ "color",
11434
+ "bold",
11435
+ "italic",
11436
+ "strike",
11437
+ "link",
11438
+ "lineheight",
11439
+ "|",
11440
+ "ul",
11441
+ "ol",
11442
+ "|",
11443
+ "align",
11444
+ "indent",
11445
+ "outdent",
11446
+ "|",
11447
+ "table",
11448
+ "image",
11449
+ "video",
11450
+ "|",
11451
+ "cut",
11452
+ "copy",
11453
+ "paste",
11454
+ "specialchars",
11455
+ "code",
11456
+ "fullscreen",
11457
+ "|",
11458
+ "tts",
11459
+ "stt",
11460
+ "translate",
11461
+ "|",
11462
+ "todo"
11463
+ ],
11464
+ basic: [
11465
+ "undo",
11466
+ "redo",
11467
+ "|",
11468
+ "paragraph",
11469
+ "fontsize",
11470
+ "font",
11471
+ "bold",
11472
+ "italic",
11473
+ "link",
11474
+ "|",
11475
+ "ul",
11476
+ "ol"
11477
+ ]
11478
+ };
11408
11479
  var RufousTextEditor = ({
11409
11480
  content: initialContent,
11410
11481
  placeholder: customPlaceholder,
@@ -11420,6 +11491,10 @@ var RufousTextEditor = ({
11420
11491
  onImageUpload,
11421
11492
  onClose,
11422
11493
  mentions,
11494
+ variant = "default",
11495
+ buttons,
11496
+ hideButtons,
11497
+ width,
11423
11498
  height,
11424
11499
  resizable = false,
11425
11500
  className,
@@ -11427,6 +11502,14 @@ var RufousTextEditor = ({
11427
11502
  sx
11428
11503
  }) => {
11429
11504
  const sxClass = useSx(sx);
11505
+ const toolbarButtons = useMemo4(() => {
11506
+ const list = buttons || VARIANT_BUTTONS[variant] || VARIANT_BUTTONS.default;
11507
+ const visible = new Set(list.filter((b) => b !== "|"));
11508
+ if (hideButtons) {
11509
+ hideButtons.forEach((b) => visible.delete(b));
11510
+ }
11511
+ return visible;
11512
+ }, [buttons, variant, hideButtons]);
11430
11513
  const mentionSuggestion = useMemo4(() => createMentionSuggestion(mentions), [mentions]);
11431
11514
  const onChangeRef = useRef29(onChange);
11432
11515
  const onBlurRef = useRef29(onBlur);
@@ -11592,6 +11675,25 @@ var RufousTextEditor = ({
11592
11675
  if ((event.ctrlKey || event.metaKey) && event.key === "k") {
11593
11676
  event.preventDefault();
11594
11677
  setLinkRef.current?.();
11678
+ return;
11679
+ }
11680
+ if (event.key === " " && editor.isActive("link")) {
11681
+ const { $from } = editor.state.selection;
11682
+ const linkMark = editor.state.schema.marks.link;
11683
+ const parent = $from.parent;
11684
+ let atLinkEnd = false;
11685
+ parent.forEach((child, offset2) => {
11686
+ if (child.isText && child.marks.some((m) => m.type === linkMark)) {
11687
+ const childEnd = offset2 + child.nodeSize;
11688
+ if ($from.parentOffset === childEnd) {
11689
+ atLinkEnd = true;
11690
+ }
11691
+ }
11692
+ });
11693
+ if (atLinkEnd) {
11694
+ event.preventDefault();
11695
+ editor.chain().focus().unsetMark("link").insertContent(" ").run();
11696
+ }
11595
11697
  }
11596
11698
  };
11597
11699
  editor.view.dom.addEventListener("keydown", handleKeyDown);
@@ -11652,7 +11754,6 @@ var RufousTextEditor = ({
11652
11754
  setLinkSelection(null);
11653
11755
  editor?.chain().focus().run();
11654
11756
  }, [editor]);
11655
- const [saveFormat, setSaveFormat] = useState33("html");
11656
11757
  const [saveStatus, setSaveStatus] = useState33("");
11657
11758
  const handleSave = useCallback13(() => {
11658
11759
  if (!editor || !onSaveProp) return;
@@ -11664,12 +11765,6 @@ var RufousTextEditor = ({
11664
11765
  if (!editor || !onExportProp) return;
11665
11766
  onExportProp(editor.getHTML(), editor.getJSON());
11666
11767
  }, [editor, onExportProp]);
11667
- const handleClear = useCallback13(() => {
11668
- if (!editor) return;
11669
- if (window.confirm("Clear all content? This cannot be undone.")) {
11670
- editor.commands.clearContent();
11671
- }
11672
- }, [editor]);
11673
11768
  const providerValue = useMemo4(() => ({ editor }), [editor]);
11674
11769
  return /* @__PURE__ */ React115.createElement(
11675
11770
  "div",
@@ -11677,6 +11772,7 @@ var RufousTextEditor = ({
11677
11772
  className: `rf-rte-wrapper editor-wrapper ${resizable ? "rf-rte-resizable" : ""} ${sxClass} ${className || ""}`,
11678
11773
  style: {
11679
11774
  ...style,
11775
+ ...width ? { width: typeof width === "number" ? `${width}px` : width } : {},
11680
11776
  ...height ? { height: typeof height === "number" ? `${height}px` : height } : {}
11681
11777
  }
11682
11778
  },
@@ -11690,7 +11786,8 @@ var RufousTextEditor = ({
11690
11786
  onSpeechToText,
11691
11787
  onTextToSpeech,
11692
11788
  onImageUpload,
11693
- onClose
11789
+ onClose,
11790
+ visibleButtons: toolbarButtons
11694
11791
  }
11695
11792
  ), /* @__PURE__ */ React115.createElement(EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ React115.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ React115.createElement(VideoToolbar_default, { editor }), editor && /* @__PURE__ */ React115.createElement(
11696
11793
  BubbleMenu,
@@ -11805,16 +11902,7 @@ var RufousTextEditor = ({
11805
11902
  },
11806
11903
  "\u201C Quote"
11807
11904
  )
11808
- ), /* @__PURE__ */ React115.createElement("div", { className: "status-bar" }, /* @__PURE__ */ React115.createElement("div", { className: "status-bar-left" }, /* @__PURE__ */ React115.createElement(
11809
- "select",
11810
- {
11811
- value: saveFormat,
11812
- onChange: (e) => setSaveFormat(e.target.value),
11813
- className: "format-select"
11814
- },
11815
- /* @__PURE__ */ React115.createElement("option", { value: "html" }, "HTML"),
11816
- /* @__PURE__ */ React115.createElement("option", { value: "json" }, "JSON")
11817
- ), onSaveProp && /* @__PURE__ */ React115.createElement("button", { onClick: handleSave, className: "status-btn save-btn" }, "Save"), onExportProp && /* @__PURE__ */ React115.createElement("button", { onClick: handleExport, className: "status-btn export-btn" }, "Export"), /* @__PURE__ */ React115.createElement("button", { onClick: handleClear, className: "status-btn clear-btn" }, "Clear")), /* @__PURE__ */ React115.createElement("div", { className: "status-bar-right" }, saveStatus && /* @__PURE__ */ React115.createElement("span", { className: "save-status" }, saveStatus), editor && /* @__PURE__ */ React115.createElement(React115.Fragment, null, /* @__PURE__ */ React115.createElement("span", { className: "word-count" }, "CHARS: ", editor.storage.characterCount?.characters?.() ?? editor.getText().length), /* @__PURE__ */ React115.createElement("span", { className: "word-count" }, "WORDS: ", editor.storage.characterCount?.words?.() ?? editor.getText().split(/\s+/).filter(Boolean).length)))), linkModalOpen && /* @__PURE__ */ React115.createElement("div", { className: "link-modal-overlay", onClick: handleLinkCancel }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal-body" }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-label" }, "URL"), /* @__PURE__ */ React115.createElement(
11905
+ ), /* @__PURE__ */ React115.createElement("div", { className: "status-bar" }, /* @__PURE__ */ React115.createElement("div", { className: "status-bar-left" }, onSaveProp && /* @__PURE__ */ React115.createElement("button", { onClick: handleSave, className: "status-btn save-btn" }, "Save"), onExportProp && /* @__PURE__ */ React115.createElement("button", { onClick: handleExport, className: "status-btn export-btn" }, "Export")), /* @__PURE__ */ React115.createElement("div", { className: "status-bar-right" }, saveStatus && /* @__PURE__ */ React115.createElement("span", { className: "save-status" }, saveStatus), editor && /* @__PURE__ */ React115.createElement(React115.Fragment, null, /* @__PURE__ */ React115.createElement("span", { className: "word-count" }, "CHARS: ", editor.storage.characterCount?.characters?.() ?? editor.getText().length), /* @__PURE__ */ React115.createElement("span", { className: "word-count" }, "WORDS: ", editor.storage.characterCount?.words?.() ?? editor.getText().split(/\s+/).filter(Boolean).length)))), linkModalOpen && /* @__PURE__ */ React115.createElement("div", { className: "link-modal-overlay", onClick: handleLinkCancel }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal-body" }, /* @__PURE__ */ React115.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-label" }, "URL"), /* @__PURE__ */ React115.createElement(
11818
11906
  "input",
11819
11907
  {
11820
11908
  type: "url",
@@ -11839,18 +11927,6 @@ var RufousTextEditor = ({
11839
11927
  },
11840
11928
  placeholder: "Link text"
11841
11929
  }
11842
- )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-label" }, "Class name"), /* @__PURE__ */ React115.createElement(
11843
- "input",
11844
- {
11845
- type: "text",
11846
- className: "link-modal-input",
11847
- value: linkClassName,
11848
- onChange: (e) => setLinkClassName(e.target.value),
11849
- onKeyDown: (e) => {
11850
- if (e.key === "Enter") handleLinkSubmit();
11851
- },
11852
- placeholder: ""
11853
- }
11854
11930
  )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-checkboxes" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React115.createElement(
11855
11931
  "input",
11856
11932
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.2.54",
4
+ "version": "0.2.56",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",