@rufous/ui 0.2.66 → 0.2.67

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
@@ -8290,8 +8290,8 @@ var PhoneField = forwardRef10(function PhoneField2(props, ref) {
8290
8290
  PhoneField.displayName = "PhoneField";
8291
8291
 
8292
8292
  // lib/RufousTextEditor/RufousTextEditor.tsx
8293
- import React115, { useMemo as useMemo4, useCallback as useCallback13, useState as useState33, useRef as useRef29, useEffect as useEffect26 } from "react";
8294
- import { createPortal as createPortal7 } from "react-dom";
8293
+ import React116, { useMemo as useMemo4, useCallback as useCallback13, useState as useState34, useRef as useRef30, useEffect as useEffect27 } from "react";
8294
+ import { createPortal as createPortal8 } from "react-dom";
8295
8295
  import { useEditor, EditorContent, EditorContext, FloatingMenu, BubbleMenu } from "@tiptap/react";
8296
8296
  import StarterKit from "@tiptap/starter-kit";
8297
8297
  import Placeholder from "@tiptap/extension-placeholder";
@@ -8416,8 +8416,8 @@ import React112, { useState as useState30, useRef as useRef26, useEffect as useE
8416
8416
  import { createPortal as createPortal4 } from "react-dom";
8417
8417
 
8418
8418
  // lib/RufousTextEditor/TextToSpeech.tsx
8419
- import React107, { useState as useState26, useEffect as useEffect20, useRef as useRef23, useCallback as useCallback9 } from "react";
8420
- var TextToSpeech = ({ editor, onTextToSpeech }) => {
8419
+ import React107, { useState as useState26, useEffect as useEffect20, useRef as useRef23, useCallback as useCallback9, forwardRef as forwardRef12, useImperativeHandle as useImperativeHandle2 } from "react";
8420
+ var TextToSpeech = forwardRef12(({ editor, onTextToSpeech }, ref) => {
8421
8421
  const [speaking, setSpeaking] = useState26(false);
8422
8422
  const [paused, setPaused] = useState26(false);
8423
8423
  const [voices, setVoices] = useState26([]);
@@ -8520,6 +8520,7 @@ var TextToSpeech = ({ editor, onTextToSpeech }) => {
8520
8520
  setSpeaking(false);
8521
8521
  setPaused(false);
8522
8522
  }, []);
8523
+ useImperativeHandle2(ref, () => ({ stop: handleStop }), [handleStop]);
8523
8524
  return /* @__PURE__ */ React107.createElement("div", { className: "tts-wrapper", ref: panelRef }, /* @__PURE__ */ React107.createElement(
8524
8525
  "button",
8525
8526
  {
@@ -8557,12 +8558,12 @@ var TextToSpeech = ({ editor, onTextToSpeech }) => {
8557
8558
  handleSpeak();
8558
8559
  setShowPanel(false);
8559
8560
  } }, "\u25B6 Speak")), speaking && /* @__PURE__ */ React107.createElement("div", { className: "tts-controls" }, paused ? /* @__PURE__ */ React107.createElement("button", { className: "toolbar-btn", onClick: handleResume, title: "Resume" }, "\u25B6") : /* @__PURE__ */ React107.createElement("button", { className: "toolbar-btn", onClick: handlePause, title: "Pause" }, "\u275A\u275A"), /* @__PURE__ */ React107.createElement("button", { className: "toolbar-btn", onClick: handleStop, title: "Stop" }, "\u25A0")));
8560
- };
8561
+ });
8561
8562
  var TextToSpeech_default = TextToSpeech;
8562
8563
 
8563
8564
  // lib/RufousTextEditor/SpeechToText.tsx
8564
- import React108, { useState as useState27, useRef as useRef24, useCallback as useCallback10, useEffect as useEffect21 } from "react";
8565
- var SpeechToText = ({ editor, onSpeechToText }) => {
8565
+ import React108, { useState as useState27, useRef as useRef24, useCallback as useCallback10, useEffect as useEffect21, forwardRef as forwardRef13, useImperativeHandle as useImperativeHandle3 } from "react";
8566
+ var SpeechToText = forwardRef13(({ editor, onSpeechToText }, ref) => {
8566
8567
  const [listening, setListening] = useState27(false);
8567
8568
  const [showPanel, setShowPanel] = useState27(false);
8568
8569
  const [language, setLanguage] = useState27("en-US");
@@ -8673,6 +8674,7 @@ var SpeechToText = ({ editor, onSpeechToText }) => {
8673
8674
  setListening(false);
8674
8675
  setInterim("");
8675
8676
  }, []);
8677
+ useImperativeHandle3(ref, () => ({ stop: stopListening }), [stopListening]);
8676
8678
  if (!supported) {
8677
8679
  return /* @__PURE__ */ React108.createElement("button", { className: "toolbar-btn", disabled: true, title: "Speech recognition not supported in this browser" }, "\u{1F3A4}");
8678
8680
  }
@@ -8719,7 +8721,7 @@ var SpeechToText = ({ editor, onSpeechToText }) => {
8719
8721
  },
8720
8722
  LANGUAGES2.map((l) => /* @__PURE__ */ React108.createElement("option", { key: l.code, value: l.code }, l.label))
8721
8723
  ), /* @__PURE__ */ React108.createElement("div", { className: "stt-info" }, "Speak into your microphone and the text will be typed into the editor."), /* @__PURE__ */ React108.createElement("button", { className: "stt-start-btn", onClick: startListening }, "\u{1F3A4} Start Listening")), listening && interim && /* @__PURE__ */ React108.createElement("div", { className: "stt-interim" }, interim));
8722
- };
8724
+ });
8723
8725
  var SpeechToText_default = SpeechToText;
8724
8726
 
8725
8727
  // lib/RufousTextEditor/AICommands.tsx
@@ -10290,10 +10292,11 @@ var ColorPickerPanel = ({ editor, onClose }) => {
10290
10292
  }
10291
10293
  ))), /* @__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")));
10292
10294
  };
10293
- var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons }) => {
10295
+ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons, isFullscreen, onToggleFullscreen }) => {
10294
10296
  const [, setEditorState] = useState30(0);
10295
- const [isFullscreen, setIsFullscreen] = useState30(false);
10296
10297
  const [todoEnabled, setTodoEnabled] = useState30(false);
10298
+ const ttsRef = useRef26(null);
10299
+ const sttRef = useRef26(null);
10297
10300
  const show = (id) => !visibleButtons || visibleButtons.has(id);
10298
10301
  useEffect23(() => {
10299
10302
  if (!editor) return;
@@ -10301,16 +10304,6 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10301
10304
  editor.on("transaction", onTransaction);
10302
10305
  return () => editor.off("transaction", onTransaction);
10303
10306
  }, [editor]);
10304
- const toggleFullscreen = useCallback12(() => {
10305
- const wrapper = document.querySelector(".editor-wrapper");
10306
- if (!wrapper) return;
10307
- if (!isFullscreen) {
10308
- wrapper.classList.add("fullscreen");
10309
- } else {
10310
- wrapper.classList.remove("fullscreen");
10311
- }
10312
- setIsFullscreen(!isFullscreen);
10313
- }, [isFullscreen]);
10314
10307
  const insertSpecialChar = useCallback12((char) => {
10315
10308
  if (!editor) return;
10316
10309
  editor.chain().focus().insertContent(char).run();
@@ -10814,11 +10807,11 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10814
10807
  "button",
10815
10808
  {
10816
10809
  className: `toolbar-btn ${isFullscreen ? "is-active" : ""}`,
10817
- onClick: toggleFullscreen,
10810
+ onClick: onToggleFullscreen,
10818
10811
  title: "Toggle Fullscreen"
10819
10812
  },
10820
10813
  /* @__PURE__ */ React112.createElement(IconFullscreen, null)
10821
- ), 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(
10814
+ ), show("tts") && /* @__PURE__ */ React112.createElement(TextToSpeech_default, { ref: ttsRef, editor, onTextToSpeech }), show("stt") && /* @__PURE__ */ React112.createElement(SpeechToText_default, { ref: sttRef, editor, onSpeechToText }), show("translate") && /* @__PURE__ */ React112.createElement("div", { className: "translate-split-btn" }, /* @__PURE__ */ React112.createElement(
10822
10815
  "button",
10823
10816
  {
10824
10817
  className: "toolbar-btn",
@@ -10912,7 +10905,17 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10912
10905
  "button",
10913
10906
  {
10914
10907
  className: "toolbar-btn btn-cross",
10915
- onClick: onClose,
10908
+ onClick: () => {
10909
+ try {
10910
+ ttsRef.current?.stop();
10911
+ } catch {
10912
+ }
10913
+ try {
10914
+ sttRef.current?.stop();
10915
+ } catch {
10916
+ }
10917
+ onClose();
10918
+ },
10916
10919
  title: "Close"
10917
10920
  },
10918
10921
  /* @__PURE__ */ React112.createElement(closeIcon_default, { color: "#a81c08" })
@@ -11454,6 +11457,175 @@ var VideoToolbar = ({ editor }) => {
11454
11457
  };
11455
11458
  var VideoToolbar_default = VideoToolbar;
11456
11459
 
11460
+ // lib/RufousTextEditor/TableToolbar.tsx
11461
+ import React115, { useState as useState33, useEffect as useEffect26, useRef as useRef29 } from "react";
11462
+ import { createPortal as createPortal7 } from "react-dom";
11463
+ var IconAddRowBefore = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ React115.createElement("path", { d: "M9 6h2v1.5h1.5v2H11V11H9V9.5H7.5v-2H9z" }));
11464
+ var IconAddRowAfter = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ React115.createElement("path", { d: "M9 14h2v1.5h1.5v2H11V19H9v-1.5H7.5v-2H9z" }));
11465
+ var IconAddColBefore = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-9 16H5V5h6v14zm8 0h-6V5h6v14z" }), /* @__PURE__ */ React115.createElement("path", { d: "M6 10h1.5v2H6v1.5H4v-2h1.5V10H4V8h2z", transform: "translate(2,1)" }));
11466
+ var IconAddColAfter = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-9 16H5V5h6v14zm8 0h-6V5h6v14z" }), /* @__PURE__ */ React115.createElement("path", { d: "M15 9h2v1.5h1.5v2H17V14h-2v-1.5h-1.5v-2H15z" }));
11467
+ var IconDeleteRow = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ React115.createElement("path", { d: "M8 14.5h8v2H8z" }));
11468
+ var IconDeleteCol = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-9 16H5V5h6v14zm8 0h-6V5h6v14z" }), /* @__PURE__ */ React115.createElement("path", { d: "M14 9.5v6h2v-6z" }));
11469
+ var IconDeleteTable = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 16H5V5h14v14z" }), /* @__PURE__ */ React115.createElement("path", { d: "M9.17 10l-1.41 1.41L10.59 14l-2.83 2.83 1.41 1.41L12 15.41l2.83 2.83 1.41-1.41L13.41 14l2.83-2.83-1.41-1.41L12 12.59z" }));
11470
+ var IconMergeCells = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M3 3h18v18H3V3zm2 2v5h6V5H5zm8 0v5h6V5h-6zM5 13v6h14v-6H5z" }), /* @__PURE__ */ React115.createElement("path", { d: "M8 15h8v2H8z" }));
11471
+ var IconSplitCell = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M3 3h18v18H3V3zm2 2v5h6V5H5zm8 0v5h6V5h-6zM5 13v6h6v-6H5zm8 0v6h6v-6h-6z" }));
11472
+ var IconToggleHeader = () => /* @__PURE__ */ React115.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React115.createElement("path", { d: "M3 3h18v18H3V3zm2 2v4h14V5H5zm0 6v8h14v-8H5z" }), /* @__PURE__ */ React115.createElement("rect", { x: "5", y: "5", width: "14", height: "4", opacity: "0.4" }));
11473
+ var TableToolbar = ({ editor }) => {
11474
+ const [pos, setPos] = useState33(null);
11475
+ const toolbarRef = useRef29(null);
11476
+ useEffect26(() => {
11477
+ if (!editor) return;
11478
+ const update = () => {
11479
+ if (!editor.isActive("table")) {
11480
+ setPos(null);
11481
+ return;
11482
+ }
11483
+ try {
11484
+ const { $from } = editor.state.selection;
11485
+ let depth = $from.depth;
11486
+ while (depth > 0) {
11487
+ const node = $from.node(depth);
11488
+ if (node.type.name === "table") {
11489
+ const domNode = editor.view.nodeDOM($from.before(depth));
11490
+ if (domNode) {
11491
+ const tableEl = domNode.tagName === "TABLE" ? domNode : domNode.querySelector?.("table") || domNode;
11492
+ const rect = tableEl.getBoundingClientRect();
11493
+ setPos({
11494
+ top: rect.top + window.scrollY - 40,
11495
+ left: rect.left + window.scrollX
11496
+ });
11497
+ }
11498
+ return;
11499
+ }
11500
+ depth--;
11501
+ }
11502
+ setPos(null);
11503
+ } catch {
11504
+ setPos(null);
11505
+ }
11506
+ };
11507
+ editor.on("selectionUpdate", update);
11508
+ editor.on("update", update);
11509
+ update();
11510
+ return () => {
11511
+ editor.off("selectionUpdate", update);
11512
+ editor.off("update", update);
11513
+ };
11514
+ }, [editor]);
11515
+ if (!editor || !pos || !editor.isActive("table")) return null;
11516
+ const canMerge = editor.can().mergeCells();
11517
+ const canSplit = editor.can().splitCell();
11518
+ const prevent = (e) => e.preventDefault();
11519
+ return createPortal7(
11520
+ /* @__PURE__ */ React115.createElement(
11521
+ "div",
11522
+ {
11523
+ ref: toolbarRef,
11524
+ className: "rf-table-toolbar",
11525
+ style: { top: pos.top, left: pos.left },
11526
+ onMouseDown: prevent
11527
+ },
11528
+ /* @__PURE__ */ React115.createElement(
11529
+ "button",
11530
+ {
11531
+ className: "rf-table-toolbar-btn",
11532
+ onClick: () => editor.chain().focus().addRowBefore().run(),
11533
+ title: "Insert row above"
11534
+ },
11535
+ /* @__PURE__ */ React115.createElement(IconAddRowBefore, null)
11536
+ ),
11537
+ /* @__PURE__ */ React115.createElement(
11538
+ "button",
11539
+ {
11540
+ className: "rf-table-toolbar-btn",
11541
+ onClick: () => editor.chain().focus().addRowAfter().run(),
11542
+ title: "Insert row below"
11543
+ },
11544
+ /* @__PURE__ */ React115.createElement(IconAddRowAfter, null)
11545
+ ),
11546
+ /* @__PURE__ */ React115.createElement(
11547
+ "button",
11548
+ {
11549
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11550
+ onClick: () => editor.chain().focus().deleteRow().run(),
11551
+ title: "Delete row"
11552
+ },
11553
+ /* @__PURE__ */ React115.createElement(IconDeleteRow, null)
11554
+ ),
11555
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11556
+ /* @__PURE__ */ React115.createElement(
11557
+ "button",
11558
+ {
11559
+ className: "rf-table-toolbar-btn",
11560
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
11561
+ title: "Insert column left"
11562
+ },
11563
+ /* @__PURE__ */ React115.createElement(IconAddColBefore, null)
11564
+ ),
11565
+ /* @__PURE__ */ React115.createElement(
11566
+ "button",
11567
+ {
11568
+ className: "rf-table-toolbar-btn",
11569
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
11570
+ title: "Insert column right"
11571
+ },
11572
+ /* @__PURE__ */ React115.createElement(IconAddColAfter, null)
11573
+ ),
11574
+ /* @__PURE__ */ React115.createElement(
11575
+ "button",
11576
+ {
11577
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11578
+ onClick: () => editor.chain().focus().deleteColumn().run(),
11579
+ title: "Delete column"
11580
+ },
11581
+ /* @__PURE__ */ React115.createElement(IconDeleteCol, null)
11582
+ ),
11583
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11584
+ /* @__PURE__ */ React115.createElement(
11585
+ "button",
11586
+ {
11587
+ className: "rf-table-toolbar-btn",
11588
+ onClick: () => editor.chain().focus().mergeCells().run(),
11589
+ disabled: !canMerge,
11590
+ title: "Merge cells"
11591
+ },
11592
+ /* @__PURE__ */ React115.createElement(IconMergeCells, null)
11593
+ ),
11594
+ /* @__PURE__ */ React115.createElement(
11595
+ "button",
11596
+ {
11597
+ className: "rf-table-toolbar-btn",
11598
+ onClick: () => editor.chain().focus().splitCell().run(),
11599
+ disabled: !canSplit,
11600
+ title: "Split cell"
11601
+ },
11602
+ /* @__PURE__ */ React115.createElement(IconSplitCell, null)
11603
+ ),
11604
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11605
+ /* @__PURE__ */ React115.createElement(
11606
+ "button",
11607
+ {
11608
+ className: `rf-table-toolbar-btn ${editor.isActive("tableHeader") ? "active" : ""}`,
11609
+ onClick: () => editor.chain().focus().toggleHeaderRow().run(),
11610
+ title: "Toggle header row"
11611
+ },
11612
+ /* @__PURE__ */ React115.createElement(IconToggleHeader, null)
11613
+ ),
11614
+ /* @__PURE__ */ React115.createElement(
11615
+ "button",
11616
+ {
11617
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11618
+ onClick: () => editor.chain().focus().deleteTable().run(),
11619
+ title: "Delete table"
11620
+ },
11621
+ /* @__PURE__ */ React115.createElement(IconDeleteTable, null)
11622
+ )
11623
+ ),
11624
+ document.body
11625
+ );
11626
+ };
11627
+ var TableToolbar_default = TableToolbar;
11628
+
11457
11629
  // lib/RufousTextEditor/legacyTodoTransform.ts
11458
11630
  var IMAGE_TO_STATUS = {
11459
11631
  "todo-blank.svg": "todo",
@@ -11622,12 +11794,12 @@ var RufousTextEditor = ({
11622
11794
  return visible;
11623
11795
  }, [buttons, variant, hideButtons]);
11624
11796
  const mentionSuggestion = useMemo4(() => createMentionSuggestion(mentions), [mentions]);
11625
- const onChangeRef = useRef29(onChange);
11626
- const onBlurRef = useRef29(onBlur);
11627
- useEffect26(() => {
11797
+ const onChangeRef = useRef30(onChange);
11798
+ const onBlurRef = useRef30(onBlur);
11799
+ useEffect27(() => {
11628
11800
  onChangeRef.current = onChange;
11629
11801
  }, [onChange]);
11630
- useEffect26(() => {
11802
+ useEffect27(() => {
11631
11803
  onBlurRef.current = onBlur;
11632
11804
  }, [onBlur]);
11633
11805
  const isEditable = editable && !disabled;
@@ -11658,7 +11830,9 @@ var RufousTextEditor = ({
11658
11830
  multicolor: true
11659
11831
  }),
11660
11832
  Table.configure({
11661
- resizable: true
11833
+ resizable: true,
11834
+ cellMinWidth: 80,
11835
+ lastColumnResizable: true
11662
11836
  }),
11663
11837
  TableRow,
11664
11838
  TableCell,
@@ -11726,8 +11900,8 @@ var RufousTextEditor = ({
11726
11900
  onChangeRef.current?.(e.getHTML(), e.getJSON());
11727
11901
  }
11728
11902
  });
11729
- const wrapperRef = useRef29(null);
11730
- useEffect26(() => {
11903
+ const wrapperRef = useRef30(null);
11904
+ useEffect27(() => {
11731
11905
  if (!editor) return;
11732
11906
  let blurTimer = null;
11733
11907
  const handler = ({ event }) => {
@@ -11745,14 +11919,14 @@ var RufousTextEditor = ({
11745
11919
  if (blurTimer) clearTimeout(blurTimer);
11746
11920
  };
11747
11921
  }, [editor]);
11748
- const setLinkRef = useRef29(null);
11749
- const [linkModalOpen, setLinkModalOpen] = useState33(false);
11750
- const [linkUrl, setLinkUrl] = useState33("");
11751
- const [linkText, setLinkText] = useState33("");
11752
- const [linkClassName, setLinkClassName] = useState33("");
11753
- const [linkNewTab, setLinkNewTab] = useState33(true);
11754
- const [linkNoFollow, setLinkNoFollow] = useState33(true);
11755
- const [linkSelection, setLinkSelection] = useState33(null);
11922
+ const setLinkRef = useRef30(null);
11923
+ const [linkModalOpen, setLinkModalOpen] = useState34(false);
11924
+ const [linkUrl, setLinkUrl] = useState34("");
11925
+ const [linkText, setLinkText] = useState34("");
11926
+ const [linkClassName, setLinkClassName] = useState34("");
11927
+ const [linkNewTab, setLinkNewTab] = useState34(true);
11928
+ const [linkNoFollow, setLinkNoFollow] = useState34(true);
11929
+ const [linkSelection, setLinkSelection] = useState34(null);
11756
11930
  const setLink = useCallback13(() => {
11757
11931
  if (!editor) return;
11758
11932
  const attrs = editor.getAttributes("link");
@@ -11790,10 +11964,10 @@ var RufousTextEditor = ({
11790
11964
  setLinkSelection({ from, to });
11791
11965
  setLinkModalOpen(true);
11792
11966
  }, [editor]);
11793
- useEffect26(() => {
11967
+ useEffect27(() => {
11794
11968
  setLinkRef.current = setLink;
11795
11969
  }, [setLink]);
11796
- useEffect26(() => {
11970
+ useEffect27(() => {
11797
11971
  if (!editor?.view) return;
11798
11972
  const handleKeyDown = (event) => {
11799
11973
  if ((event.ctrlKey || event.metaKey) && event.key === "k") {
@@ -11878,7 +12052,7 @@ var RufousTextEditor = ({
11878
12052
  setLinkSelection(null);
11879
12053
  editor?.chain().focus().run();
11880
12054
  }, [editor]);
11881
- const [saveStatus, setSaveStatus] = useState33("");
12055
+ const [saveStatus, setSaveStatus] = useState34("");
11882
12056
  const handleSave = useCallback13(() => {
11883
12057
  if (!editor || !onSaveProp) return;
11884
12058
  onSaveProp(editor.getHTML(), editor.getJSON());
@@ -11890,18 +12064,20 @@ var RufousTextEditor = ({
11890
12064
  onExportProp(editor.getHTML(), editor.getJSON());
11891
12065
  }, [editor, onExportProp]);
11892
12066
  const providerValue = useMemo4(() => ({ editor }), [editor]);
11893
- return /* @__PURE__ */ React115.createElement(
12067
+ const [isFullscreen, setIsFullscreen] = useState34(false);
12068
+ const toggleFullscreen = useCallback13(() => setIsFullscreen((prev) => !prev), []);
12069
+ const wrapperJsx = /* @__PURE__ */ React116.createElement(
11894
12070
  "div",
11895
12071
  {
11896
12072
  ref: wrapperRef,
11897
- className: `rf-rte-wrapper editor-wrapper ${resizable ? "rf-rte-resizable" : ""} ${disabled ? "rf-rte-disabled" : ""} ${error ? "rf-rte-error" : ""} ${sxClass} ${className || ""}`,
11898
- style: {
12073
+ className: `rf-rte-wrapper editor-wrapper ${isFullscreen ? "fullscreen" : ""} ${resizable ? "rf-rte-resizable" : ""} ${disabled ? "rf-rte-disabled" : ""} ${error ? "rf-rte-error" : ""} ${sxClass} ${className || ""}`,
12074
+ style: isFullscreen ? void 0 : {
11899
12075
  ...style,
11900
12076
  ...width ? { width: typeof width === "number" ? `${width}px` : width } : {},
11901
12077
  ...height ? { height: typeof height === "number" ? `${height}px` : height } : {}
11902
12078
  }
11903
12079
  },
11904
- /* @__PURE__ */ React115.createElement(EditorContext.Provider, { value: providerValue }, /* @__PURE__ */ React115.createElement(
12080
+ /* @__PURE__ */ React116.createElement(EditorContext.Provider, { value: providerValue }, /* @__PURE__ */ React116.createElement(
11905
12081
  Toolbar_default,
11906
12082
  {
11907
12083
  editor,
@@ -11912,9 +12088,11 @@ var RufousTextEditor = ({
11912
12088
  onTextToSpeech,
11913
12089
  onImageUpload,
11914
12090
  onClose,
11915
- visibleButtons: toolbarButtons
12091
+ visibleButtons: toolbarButtons,
12092
+ isFullscreen,
12093
+ onToggleFullscreen: toggleFullscreen
11916
12094
  }
11917
- ), /* @__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(
12095
+ ), /* @__PURE__ */ React116.createElement(EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ React116.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ React116.createElement(VideoToolbar_default, { editor }), /* @__PURE__ */ React116.createElement(TableToolbar_default, { editor }), editor && /* @__PURE__ */ React116.createElement(
11918
12096
  BubbleMenu,
11919
12097
  {
11920
12098
  editor,
@@ -11932,31 +12110,31 @@ var RufousTextEditor = ({
11932
12110
  }
11933
12111
  }
11934
12112
  },
11935
- /* @__PURE__ */ React115.createElement(
12113
+ /* @__PURE__ */ React116.createElement(
11936
12114
  "button",
11937
12115
  {
11938
12116
  onClick: () => editor?.chain().focus().toggleBold().run(),
11939
12117
  className: editor?.isActive("bold") ? "is-active" : ""
11940
12118
  },
11941
- /* @__PURE__ */ React115.createElement("strong", null, "B")
12119
+ /* @__PURE__ */ React116.createElement("strong", null, "B")
11942
12120
  ),
11943
- /* @__PURE__ */ React115.createElement(
12121
+ /* @__PURE__ */ React116.createElement(
11944
12122
  "button",
11945
12123
  {
11946
12124
  onClick: () => editor?.chain().focus().toggleItalic().run(),
11947
12125
  className: editor?.isActive("italic") ? "is-active" : ""
11948
12126
  },
11949
- /* @__PURE__ */ React115.createElement("em", null, "I")
12127
+ /* @__PURE__ */ React116.createElement("em", null, "I")
11950
12128
  ),
11951
- /* @__PURE__ */ React115.createElement(
12129
+ /* @__PURE__ */ React116.createElement(
11952
12130
  "button",
11953
12131
  {
11954
12132
  onClick: () => editor?.chain().focus().toggleStrike().run(),
11955
12133
  className: editor?.isActive("strike") ? "is-active" : ""
11956
12134
  },
11957
- /* @__PURE__ */ React115.createElement("s", null, "S")
12135
+ /* @__PURE__ */ React116.createElement("s", null, "S")
11958
12136
  ),
11959
- /* @__PURE__ */ React115.createElement(
12137
+ /* @__PURE__ */ React116.createElement(
11960
12138
  "button",
11961
12139
  {
11962
12140
  onClick: () => editor?.chain().focus().toggleCode().run(),
@@ -11964,7 +12142,7 @@ var RufousTextEditor = ({
11964
12142
  },
11965
12143
  "</>"
11966
12144
  ),
11967
- /* @__PURE__ */ React115.createElement(
12145
+ /* @__PURE__ */ React116.createElement(
11968
12146
  "button",
11969
12147
  {
11970
12148
  onClick: setLink,
@@ -11972,7 +12150,7 @@ var RufousTextEditor = ({
11972
12150
  },
11973
12151
  "\u{1F517}"
11974
12152
  )
11975
- ), editor && /* @__PURE__ */ React115.createElement(
12153
+ ), editor && /* @__PURE__ */ React116.createElement(
11976
12154
  FloatingMenu,
11977
12155
  {
11978
12156
  editor,
@@ -11987,7 +12165,7 @@ var RufousTextEditor = ({
11987
12165
  }
11988
12166
  }
11989
12167
  },
11990
- /* @__PURE__ */ React115.createElement(
12168
+ /* @__PURE__ */ React116.createElement(
11991
12169
  "button",
11992
12170
  {
11993
12171
  onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
@@ -11995,7 +12173,7 @@ var RufousTextEditor = ({
11995
12173
  },
11996
12174
  "H1"
11997
12175
  ),
11998
- /* @__PURE__ */ React115.createElement(
12176
+ /* @__PURE__ */ React116.createElement(
11999
12177
  "button",
12000
12178
  {
12001
12179
  onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
@@ -12003,7 +12181,7 @@ var RufousTextEditor = ({
12003
12181
  },
12004
12182
  "H2"
12005
12183
  ),
12006
- /* @__PURE__ */ React115.createElement(
12184
+ /* @__PURE__ */ React116.createElement(
12007
12185
  "button",
12008
12186
  {
12009
12187
  onClick: () => editor?.chain().focus().toggleBulletList().run(),
@@ -12011,7 +12189,7 @@ var RufousTextEditor = ({
12011
12189
  },
12012
12190
  "\u2022 List"
12013
12191
  ),
12014
- /* @__PURE__ */ React115.createElement(
12192
+ /* @__PURE__ */ React116.createElement(
12015
12193
  "button",
12016
12194
  {
12017
12195
  onClick: () => editor?.chain().focus().toggleOrderedList().run(),
@@ -12019,7 +12197,7 @@ var RufousTextEditor = ({
12019
12197
  },
12020
12198
  "1. List"
12021
12199
  ),
12022
- /* @__PURE__ */ React115.createElement(
12200
+ /* @__PURE__ */ React116.createElement(
12023
12201
  "button",
12024
12202
  {
12025
12203
  onClick: () => editor?.chain().focus().toggleBlockquote().run(),
@@ -12027,8 +12205,8 @@ var RufousTextEditor = ({
12027
12205
  },
12028
12206
  "\u201C Quote"
12029
12207
  )
12030
- ), /* @__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 && createPortal7(
12031
- /* @__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(
12208
+ ), /* @__PURE__ */ React116.createElement("div", { className: "status-bar" }, /* @__PURE__ */ React116.createElement("div", { className: "status-bar-left" }, onSaveProp && /* @__PURE__ */ React116.createElement("button", { onClick: handleSave, className: "status-btn save-btn" }, "Save"), onExportProp && /* @__PURE__ */ React116.createElement("button", { onClick: handleExport, className: "status-btn export-btn" }, "Export")), /* @__PURE__ */ React116.createElement("div", { className: "status-bar-right" }, saveStatus && /* @__PURE__ */ React116.createElement("span", { className: "save-status" }, saveStatus), editor && /* @__PURE__ */ React116.createElement(React116.Fragment, null, /* @__PURE__ */ React116.createElement("span", { className: "word-count" }, "CHARS: ", editor.storage.characterCount?.characters?.() ?? editor.getText().length), /* @__PURE__ */ React116.createElement("span", { className: "word-count" }, "WORDS: ", editor.storage.characterCount?.words?.() ?? editor.getText().split(/\s+/).filter(Boolean).length)))), linkModalOpen && createPortal8(
12209
+ /* @__PURE__ */ React116.createElement("div", { className: "link-modal-overlay", onClick: handleLinkCancel }, /* @__PURE__ */ React116.createElement("div", { className: "link-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React116.createElement("div", { className: "link-modal-body" }, /* @__PURE__ */ React116.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React116.createElement("label", { className: "link-modal-label" }, "URL"), /* @__PURE__ */ React116.createElement(
12032
12210
  "input",
12033
12211
  {
12034
12212
  type: "url",
@@ -12041,7 +12219,7 @@ var RufousTextEditor = ({
12041
12219
  placeholder: "https://example.com",
12042
12220
  autoFocus: true
12043
12221
  }
12044
- )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-label" }, "Text"), /* @__PURE__ */ React115.createElement(
12222
+ )), /* @__PURE__ */ React116.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React116.createElement("label", { className: "link-modal-label" }, "Text"), /* @__PURE__ */ React116.createElement(
12045
12223
  "input",
12046
12224
  {
12047
12225
  type: "text",
@@ -12053,30 +12231,31 @@ var RufousTextEditor = ({
12053
12231
  },
12054
12232
  placeholder: "Link text"
12055
12233
  }
12056
- )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-checkboxes" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React115.createElement(
12234
+ )), /* @__PURE__ */ React116.createElement("div", { className: "link-modal-checkboxes" }, /* @__PURE__ */ React116.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React116.createElement(
12057
12235
  "input",
12058
12236
  {
12059
12237
  type: "checkbox",
12060
12238
  checked: linkNewTab,
12061
12239
  onChange: (e) => setLinkNewTab(e.target.checked)
12062
12240
  }
12063
- ), "Open in new tab"), /* @__PURE__ */ React115.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React115.createElement(
12241
+ ), "Open in new tab"), /* @__PURE__ */ React116.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React116.createElement(
12064
12242
  "input",
12065
12243
  {
12066
12244
  type: "checkbox",
12067
12245
  checked: linkNoFollow,
12068
12246
  onChange: (e) => setLinkNoFollow(e.target.checked)
12069
12247
  }
12070
- ), "No follow"))), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-footer" }, /* @__PURE__ */ React115.createElement("button", { className: "link-modal-btn-unlink", onClick: handleLinkRemove }, "Unlink"), /* @__PURE__ */ React115.createElement("button", { className: "link-modal-btn-apply", onClick: handleLinkSubmit }, "Update")))),
12248
+ ), "No follow"))), /* @__PURE__ */ React116.createElement("div", { className: "link-modal-footer" }, /* @__PURE__ */ React116.createElement("button", { className: "link-modal-btn-unlink", onClick: handleLinkRemove }, "Unlink"), /* @__PURE__ */ React116.createElement("button", { className: "link-modal-btn-apply", onClick: handleLinkSubmit }, "Update")))),
12071
12249
  document.body
12072
12250
  )),
12073
- helperText && /* @__PURE__ */ React115.createElement("div", { className: `rf-rte-helper-text ${error ? "rf-rte-helper-error" : ""}` }, helperText)
12251
+ helperText && /* @__PURE__ */ React116.createElement("div", { className: `rf-rte-helper-text ${error ? "rf-rte-helper-error" : ""}` }, helperText)
12074
12252
  );
12253
+ return isFullscreen ? createPortal8(wrapperJsx, document.body) : wrapperJsx;
12075
12254
  };
12076
12255
  var RufousTextContent = ({ content, className, style, sx }) => {
12077
12256
  const sxClass = useSx(sx);
12078
12257
  const transformedContent = useMemo4(() => transformLegacyTodos(content || ""), [content]);
12079
- return /* @__PURE__ */ React115.createElement(
12258
+ return /* @__PURE__ */ React116.createElement(
12080
12259
  "div",
12081
12260
  {
12082
12261
  className: `rf-rte-content ${sxClass} ${className || ""}`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.2.66",
4
+ "version": "0.2.67",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",