@rufous/ui 0.2.66 → 0.2.68

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
@@ -3388,6 +3388,7 @@ import React72, {
3388
3388
  useEffect as useEffect6,
3389
3389
  useCallback as useCallback2
3390
3390
  } from "react";
3391
+ import ReactDOM from "react-dom";
3391
3392
  var ChevronDownIcon = () => /* @__PURE__ */ React72.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React72.createElement("polyline", { points: "6 9 12 15 18 9" }));
3392
3393
  var CloseSmIcon = ({ size = 16 }) => /* @__PURE__ */ React72.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ React72.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ React72.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }));
3393
3394
  var CheckIcon = () => /* @__PURE__ */ React72.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React72.createElement("polyline", { points: "20 6 9 17 4 12" }));
@@ -3441,11 +3442,21 @@ function AutocompleteInner(props, _ref) {
3441
3442
  const [open, setOpen] = useState7(false);
3442
3443
  const [inputStr, setInputStr] = useState7("");
3443
3444
  const [focusedIdx, setFocusedIdx] = useState7(-1);
3445
+ const [popupStyle, setPopupStyle] = useState7({});
3444
3446
  const containerRef = useRef6(null);
3445
3447
  const inputRef = useRef6(null);
3446
3448
  const listRef = useRef6(null);
3447
3449
  const inputId = useRef6(`rf-ac-${Math.random().toString(36).slice(2, 9)}`).current;
3448
3450
  const sxClass = useSx(sx);
3451
+ const calcPopupStyle = useCallback2(() => {
3452
+ if (!containerRef.current) return;
3453
+ const rect = containerRef.current.getBoundingClientRect();
3454
+ setPopupStyle({
3455
+ top: rect.bottom + 4,
3456
+ left: rect.left,
3457
+ width: rect.width
3458
+ });
3459
+ }, []);
3449
3460
  const activeInput = controlledInput !== void 0 ? controlledInput : inputStr;
3450
3461
  const selectedValues = multiple ? Array.isArray(value) ? value : [] : value != null ? [value] : [];
3451
3462
  const isEqual = useCallback2(
@@ -3479,12 +3490,13 @@ function AutocompleteInner(props, _ref) {
3479
3490
  filtered.forEach((opt, i) => flatEntries.push({ kind: "option", option: opt, flatIdx: i }));
3480
3491
  }
3481
3492
  const selectableOptions = flatEntries.filter((e) => e.kind === "option");
3482
- const openPopup = () => {
3493
+ const openPopup = useCallback2(() => {
3483
3494
  if (disabled) return;
3495
+ calcPopupStyle();
3484
3496
  setOpen(true);
3485
3497
  setFocusedIdx(-1);
3486
3498
  onOpen?.();
3487
- };
3499
+ }, [disabled, calcPopupStyle, onOpen]);
3488
3500
  const closePopup = useCallback2(() => {
3489
3501
  setOpen(false);
3490
3502
  setFocusedIdx(-1);
@@ -3496,14 +3508,20 @@ function AutocompleteInner(props, _ref) {
3496
3508
  }, [freeSolo, multiple, value, onInputChange, onClose]);
3497
3509
  useEffect6(() => {
3498
3510
  if (!open) return;
3499
- const handler = (e) => {
3511
+ const handleOutside = (e) => {
3500
3512
  if (containerRef.current && !containerRef.current.contains(e.target)) {
3501
3513
  closePopup();
3502
3514
  }
3503
3515
  };
3504
- document.addEventListener("mousedown", handler);
3505
- return () => document.removeEventListener("mousedown", handler);
3506
- }, [open, closePopup]);
3516
+ document.addEventListener("mousedown", handleOutside);
3517
+ window.addEventListener("scroll", calcPopupStyle, true);
3518
+ window.addEventListener("resize", calcPopupStyle);
3519
+ return () => {
3520
+ document.removeEventListener("mousedown", handleOutside);
3521
+ window.removeEventListener("scroll", calcPopupStyle, true);
3522
+ window.removeEventListener("resize", calcPopupStyle);
3523
+ };
3524
+ }, [open, closePopup, calcPopupStyle]);
3507
3525
  useEffect6(() => {
3508
3526
  if (controlledInput !== void 0) return;
3509
3527
  if (!multiple) {
@@ -3688,34 +3706,37 @@ function AutocompleteInner(props, _ref) {
3688
3706
  },
3689
3707
  /* @__PURE__ */ React72.createElement(ChevronDownIcon, null)
3690
3708
  ))
3691
- ), helperText && /* @__PURE__ */ React72.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__popup", role: "presentation" }, loading ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ React72.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ React72.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3692
- // Grouped render
3693
- (() => {
3694
- const rendered = [];
3695
- let groupItems = [];
3696
- let currentGroup = "";
3697
- flatEntries.forEach((entry, ei) => {
3698
- if (entry.kind === "group") {
3699
- if (groupItems.length > 0) {
3709
+ ), helperText && /* @__PURE__ */ React72.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && ReactDOM.createPortal(
3710
+ /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__popup", role: "presentation", style: popupStyle }, loading ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ React72.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ React72.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3711
+ // Grouped render
3712
+ (() => {
3713
+ const rendered = [];
3714
+ let groupItems = [];
3715
+ let currentGroup = "";
3716
+ flatEntries.forEach((entry, ei) => {
3717
+ if (entry.kind === "group") {
3718
+ if (groupItems.length > 0) {
3719
+ rendered.push(
3720
+ /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3721
+ );
3722
+ groupItems = [];
3723
+ }
3724
+ currentGroup = entry.label;
3725
+ } else {
3726
+ const { option, flatIdx } = entry;
3727
+ groupItems.push(renderOptionItem(option, flatIdx));
3728
+ }
3729
+ if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3700
3730
  rendered.push(
3701
3731
  /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3702
3732
  );
3703
- groupItems = [];
3704
3733
  }
3705
- currentGroup = entry.label;
3706
- } else {
3707
- const { option, flatIdx } = entry;
3708
- groupItems.push(renderOptionItem(option, flatIdx));
3709
- }
3710
- if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3711
- rendered.push(
3712
- /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3713
- );
3714
- }
3715
- });
3716
- return rendered;
3717
- })()
3718
- ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))));
3734
+ });
3735
+ return rendered;
3736
+ })()
3737
+ ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))),
3738
+ document.body
3739
+ ));
3719
3740
  function renderOptionItem(option, flatIdx) {
3720
3741
  const selected = isSelected(option);
3721
3742
  const focused = focusedIdx === flatIdx;
@@ -4428,6 +4449,7 @@ import React75, {
4428
4449
  useEffect as useEffect8,
4429
4450
  useCallback as useCallback3
4430
4451
  } from "react";
4452
+ import ReactDOM2 from "react-dom";
4431
4453
  var ChevronDownIcon2 = () => /* @__PURE__ */ React75.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React75.createElement("polyline", { points: "6 9 12 15 18 9" }));
4432
4454
  var CheckIcon2 = () => /* @__PURE__ */ React75.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React75.createElement("polyline", { points: "20 6 9 17 4 12" }));
4433
4455
  function normaliseOptions(options) {
@@ -4454,10 +4476,20 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4454
4476
  } = props;
4455
4477
  const [open, setOpen] = useState9(false);
4456
4478
  const [focusedIdx, setFocusedIdx] = useState9(-1);
4479
+ const [popupStyle, setPopupStyle] = useState9({});
4457
4480
  const containerRef = useRef9(null);
4458
4481
  const listRef = useRef9(null);
4459
4482
  const inputId = useRef9(`rf-sel-${Math.random().toString(36).slice(2, 9)}`).current;
4460
4483
  const sxClass = useSx(sx);
4484
+ const calcPopupStyle = useCallback3(() => {
4485
+ if (!containerRef.current) return;
4486
+ const rect = containerRef.current.getBoundingClientRect();
4487
+ setPopupStyle({
4488
+ top: rect.bottom + 4,
4489
+ left: rect.left,
4490
+ width: rect.width
4491
+ });
4492
+ }, []);
4461
4493
  const options = normaliseOptions(rawOptions);
4462
4494
  const selectedValues = multiple ? Array.isArray(value) ? value : value != null ? [value] : [] : value != null ? [value] : [];
4463
4495
  const isSelected = useCallback3(
@@ -4469,9 +4501,10 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4469
4501
  const isFloating = Boolean(open || hasValue);
4470
4502
  const openPopup = useCallback3(() => {
4471
4503
  if (disabled) return;
4504
+ calcPopupStyle();
4472
4505
  setOpen(true);
4473
4506
  setFocusedIdx(-1);
4474
- }, [disabled]);
4507
+ }, [disabled, calcPopupStyle]);
4475
4508
  const closePopup = useCallback3(() => {
4476
4509
  setOpen(false);
4477
4510
  setFocusedIdx(-1);
@@ -4482,14 +4515,20 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4482
4515
  }, [open, openPopup, closePopup]);
4483
4516
  useEffect8(() => {
4484
4517
  if (!open) return;
4485
- const handler = (e) => {
4518
+ const handleOutside = (e) => {
4486
4519
  if (containerRef.current && !containerRef.current.contains(e.target)) {
4487
4520
  closePopup();
4488
4521
  }
4489
4522
  };
4490
- document.addEventListener("mousedown", handler);
4491
- return () => document.removeEventListener("mousedown", handler);
4492
- }, [open, closePopup]);
4523
+ document.addEventListener("mousedown", handleOutside);
4524
+ window.addEventListener("scroll", calcPopupStyle, true);
4525
+ window.addEventListener("resize", calcPopupStyle);
4526
+ return () => {
4527
+ document.removeEventListener("mousedown", handleOutside);
4528
+ window.removeEventListener("scroll", calcPopupStyle, true);
4529
+ window.removeEventListener("resize", calcPopupStyle);
4530
+ };
4531
+ }, [open, closePopup, calcPopupStyle]);
4493
4532
  const selectOption = useCallback3((opt) => {
4494
4533
  if (opt.disabled) return;
4495
4534
  if (multiple) {
@@ -4608,32 +4647,35 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4608
4647
  /* @__PURE__ */ React75.createElement("div", { className: "rf-select__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(ChevronDownIcon2, null))
4609
4648
  ),
4610
4649
  helperText && /* @__PURE__ */ React75.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText),
4611
- open && !disabled && /* @__PURE__ */ React75.createElement("div", { className: "rf-select__popup", role: "presentation" }, /* @__PURE__ */ React75.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4612
- const selected = isSelected(opt.value);
4613
- const focused = focusedIdx === idx;
4614
- return /* @__PURE__ */ React75.createElement(
4615
- "li",
4616
- {
4617
- key: opt.value,
4618
- "data-idx": idx,
4619
- role: "option",
4620
- "aria-selected": selected,
4621
- "aria-disabled": opt.disabled,
4622
- className: [
4623
- "rf-select__option",
4624
- selected ? "rf-select__option--selected" : "",
4625
- focused ? "rf-select__option--focused" : "",
4626
- opt.disabled ? "rf-select__option--disabled" : ""
4627
- ].filter(Boolean).join(" "),
4628
- onMouseEnter: () => setFocusedIdx(idx),
4629
- onMouseLeave: () => setFocusedIdx(-1),
4630
- onMouseDown: (e) => e.preventDefault(),
4631
- onClick: () => selectOption(opt)
4632
- },
4633
- /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-label" }, opt.label),
4634
- /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(CheckIcon2, null))
4635
- );
4636
- })))
4650
+ open && !disabled && ReactDOM2.createPortal(
4651
+ /* @__PURE__ */ React75.createElement("div", { className: "rf-select__popup", role: "presentation", style: popupStyle }, /* @__PURE__ */ React75.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4652
+ const selected = isSelected(opt.value);
4653
+ const focused = focusedIdx === idx;
4654
+ return /* @__PURE__ */ React75.createElement(
4655
+ "li",
4656
+ {
4657
+ key: opt.value,
4658
+ "data-idx": idx,
4659
+ role: "option",
4660
+ "aria-selected": selected,
4661
+ "aria-disabled": opt.disabled,
4662
+ className: [
4663
+ "rf-select__option",
4664
+ selected ? "rf-select__option--selected" : "",
4665
+ focused ? "rf-select__option--focused" : "",
4666
+ opt.disabled ? "rf-select__option--disabled" : ""
4667
+ ].filter(Boolean).join(" "),
4668
+ onMouseEnter: () => setFocusedIdx(idx),
4669
+ onMouseLeave: () => setFocusedIdx(-1),
4670
+ onMouseDown: (e) => e.preventDefault(),
4671
+ onClick: () => selectOption(opt)
4672
+ },
4673
+ /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-label" }, opt.label),
4674
+ /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(CheckIcon2, null))
4675
+ );
4676
+ }))),
4677
+ document.body
4678
+ )
4637
4679
  );
4638
4680
  });
4639
4681
  Select.displayName = "Select";
@@ -5807,7 +5849,7 @@ import React87, {
5807
5849
  useRef as useRef14,
5808
5850
  useState as useState13
5809
5851
  } from "react";
5810
- import ReactDOM from "react-dom";
5852
+ import ReactDOM3 from "react-dom";
5811
5853
  var GAP = 8;
5812
5854
  function computePosition(anchor, tooltip, placement) {
5813
5855
  const { top: aTop, left: aLeft, width: aW, height: aH } = anchor;
@@ -6026,7 +6068,7 @@ var Tooltip = ({
6026
6068
  ...childProps
6027
6069
  },
6028
6070
  React87.cloneElement(children)
6029
- ), ReactDOM.createPortal(tooltipElement, document.body));
6071
+ ), ReactDOM3.createPortal(tooltipElement, document.body));
6030
6072
  };
6031
6073
  Tooltip.displayName = "Tooltip";
6032
6074
 
@@ -6932,7 +6974,7 @@ import React97, {
6932
6974
  useRef as useRef16,
6933
6975
  useState as useState17
6934
6976
  } from "react";
6935
- import ReactDOM2 from "react-dom";
6977
+ import ReactDOM4 from "react-dom";
6936
6978
  var MenuDivider = () => /* @__PURE__ */ React97.createElement("hr", { className: "rf-menu-divider", "aria-hidden": "true" });
6937
6979
  MenuDivider.displayName = "MenuDivider";
6938
6980
  var MenuItem = ({
@@ -7085,7 +7127,7 @@ var Menu = ({
7085
7127
  },
7086
7128
  children
7087
7129
  ));
7088
- return ReactDOM2.createPortal(portal, document.body);
7130
+ return ReactDOM4.createPortal(portal, document.body);
7089
7131
  };
7090
7132
  Menu.displayName = "Menu";
7091
7133
 
@@ -7094,7 +7136,7 @@ import React98, {
7094
7136
  useEffect as useEffect13,
7095
7137
  useState as useState18
7096
7138
  } from "react";
7097
- import ReactDOM3 from "react-dom";
7139
+ import ReactDOM5 from "react-dom";
7098
7140
  var Drawer = ({
7099
7141
  open,
7100
7142
  onClose,
@@ -7194,7 +7236,7 @@ var Drawer = ({
7194
7236
  },
7195
7237
  children
7196
7238
  ));
7197
- return ReactDOM3.createPortal(
7239
+ return ReactDOM5.createPortal(
7198
7240
  /* @__PURE__ */ React98.createElement("div", { className: rootClasses, style }, drawerContent),
7199
7241
  document.body
7200
7242
  );
@@ -7208,7 +7250,7 @@ import React99, {
7208
7250
  useRef as useRef17,
7209
7251
  useState as useState19
7210
7252
  } from "react";
7211
- import ReactDOM4 from "react-dom";
7253
+ import ReactDOM6 from "react-dom";
7212
7254
  var SEVERITY_ICONS = {
7213
7255
  success: "\u2713",
7214
7256
  error: "\u2715",
@@ -7313,7 +7355,7 @@ var Snackbar = ({
7313
7355
  "\u2715"
7314
7356
  )
7315
7357
  ));
7316
- return ReactDOM4.createPortal(snackbarEl, document.body);
7358
+ return ReactDOM6.createPortal(snackbarEl, document.body);
7317
7359
  };
7318
7360
  Snackbar.displayName = "Snackbar";
7319
7361
 
@@ -7372,7 +7414,7 @@ import React101, {
7372
7414
  useRef as useRef18,
7373
7415
  useState as useState20
7374
7416
  } from "react";
7375
- import ReactDOM5 from "react-dom";
7417
+ import ReactDOM7 from "react-dom";
7376
7418
  function computePopperPosition(anchorRect, popperRect, placement, offset2 = [0, 8]) {
7377
7419
  const [skid, dist] = offset2;
7378
7420
  let top = 0;
@@ -7515,7 +7557,7 @@ var Popper = ({
7515
7557
  if (disablePortal) {
7516
7558
  return /* @__PURE__ */ React101.createElement(React101.Fragment, null, popper);
7517
7559
  }
7518
- return ReactDOM5.createPortal(popper, document.body);
7560
+ return ReactDOM7.createPortal(popper, document.body);
7519
7561
  };
7520
7562
  Popper.displayName = "Popper";
7521
7563
 
@@ -7526,7 +7568,7 @@ import React102, {
7526
7568
  useRef as useRef19,
7527
7569
  useState as useState21
7528
7570
  } from "react";
7529
- import ReactDOM6 from "react-dom";
7571
+ import ReactDOM8 from "react-dom";
7530
7572
  function getPoint(rect, v, h) {
7531
7573
  const x = h === "left" ? rect.left : h === "center" ? rect.left + rect.width / 2 : rect.right;
7532
7574
  const y = v === "top" ? rect.top : v === "center" ? rect.top + rect.height / 2 : rect.bottom;
@@ -7629,7 +7671,7 @@ var Popover = ({
7629
7671
  if (disablePortal) {
7630
7672
  return /* @__PURE__ */ React102.createElement("div", { className: `${rootClasses} rf-popover-inline`, style }, content);
7631
7673
  }
7632
- return ReactDOM6.createPortal(
7674
+ return ReactDOM8.createPortal(
7633
7675
  /* @__PURE__ */ React102.createElement("div", { className: rootClasses, style }, content),
7634
7676
  document.body
7635
7677
  );
@@ -8290,8 +8332,8 @@ var PhoneField = forwardRef10(function PhoneField2(props, ref) {
8290
8332
  PhoneField.displayName = "PhoneField";
8291
8333
 
8292
8334
  // 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";
8335
+ import React116, { useMemo as useMemo4, useCallback as useCallback13, useState as useState34, useRef as useRef30, useEffect as useEffect27 } from "react";
8336
+ import { createPortal as createPortal8 } from "react-dom";
8295
8337
  import { useEditor, EditorContent, EditorContext, FloatingMenu, BubbleMenu } from "@tiptap/react";
8296
8338
  import StarterKit from "@tiptap/starter-kit";
8297
8339
  import Placeholder from "@tiptap/extension-placeholder";
@@ -8416,8 +8458,8 @@ import React112, { useState as useState30, useRef as useRef26, useEffect as useE
8416
8458
  import { createPortal as createPortal4 } from "react-dom";
8417
8459
 
8418
8460
  // 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 }) => {
8461
+ import React107, { useState as useState26, useEffect as useEffect20, useRef as useRef23, useCallback as useCallback9, forwardRef as forwardRef12, useImperativeHandle as useImperativeHandle2 } from "react";
8462
+ var TextToSpeech = forwardRef12(({ editor, onTextToSpeech }, ref) => {
8421
8463
  const [speaking, setSpeaking] = useState26(false);
8422
8464
  const [paused, setPaused] = useState26(false);
8423
8465
  const [voices, setVoices] = useState26([]);
@@ -8520,6 +8562,7 @@ var TextToSpeech = ({ editor, onTextToSpeech }) => {
8520
8562
  setSpeaking(false);
8521
8563
  setPaused(false);
8522
8564
  }, []);
8565
+ useImperativeHandle2(ref, () => ({ stop: handleStop }), [handleStop]);
8523
8566
  return /* @__PURE__ */ React107.createElement("div", { className: "tts-wrapper", ref: panelRef }, /* @__PURE__ */ React107.createElement(
8524
8567
  "button",
8525
8568
  {
@@ -8557,12 +8600,12 @@ var TextToSpeech = ({ editor, onTextToSpeech }) => {
8557
8600
  handleSpeak();
8558
8601
  setShowPanel(false);
8559
8602
  } }, "\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
- };
8603
+ });
8561
8604
  var TextToSpeech_default = TextToSpeech;
8562
8605
 
8563
8606
  // 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 }) => {
8607
+ import React108, { useState as useState27, useRef as useRef24, useCallback as useCallback10, useEffect as useEffect21, forwardRef as forwardRef13, useImperativeHandle as useImperativeHandle3 } from "react";
8608
+ var SpeechToText = forwardRef13(({ editor, onSpeechToText }, ref) => {
8566
8609
  const [listening, setListening] = useState27(false);
8567
8610
  const [showPanel, setShowPanel] = useState27(false);
8568
8611
  const [language, setLanguage] = useState27("en-US");
@@ -8673,6 +8716,7 @@ var SpeechToText = ({ editor, onSpeechToText }) => {
8673
8716
  setListening(false);
8674
8717
  setInterim("");
8675
8718
  }, []);
8719
+ useImperativeHandle3(ref, () => ({ stop: stopListening }), [stopListening]);
8676
8720
  if (!supported) {
8677
8721
  return /* @__PURE__ */ React108.createElement("button", { className: "toolbar-btn", disabled: true, title: "Speech recognition not supported in this browser" }, "\u{1F3A4}");
8678
8722
  }
@@ -8719,7 +8763,7 @@ var SpeechToText = ({ editor, onSpeechToText }) => {
8719
8763
  },
8720
8764
  LANGUAGES2.map((l) => /* @__PURE__ */ React108.createElement("option", { key: l.code, value: l.code }, l.label))
8721
8765
  ), /* @__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
- };
8766
+ });
8723
8767
  var SpeechToText_default = SpeechToText;
8724
8768
 
8725
8769
  // lib/RufousTextEditor/AICommands.tsx
@@ -10290,10 +10334,11 @@ var ColorPickerPanel = ({ editor, onClose }) => {
10290
10334
  }
10291
10335
  ))), /* @__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
10336
  };
10293
- var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons }) => {
10337
+ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTextToSpeech, onClose, onImageUpload, visibleButtons, isFullscreen, onToggleFullscreen }) => {
10294
10338
  const [, setEditorState] = useState30(0);
10295
- const [isFullscreen, setIsFullscreen] = useState30(false);
10296
10339
  const [todoEnabled, setTodoEnabled] = useState30(false);
10340
+ const ttsRef = useRef26(null);
10341
+ const sttRef = useRef26(null);
10297
10342
  const show = (id) => !visibleButtons || visibleButtons.has(id);
10298
10343
  useEffect23(() => {
10299
10344
  if (!editor) return;
@@ -10301,16 +10346,6 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10301
10346
  editor.on("transaction", onTransaction);
10302
10347
  return () => editor.off("transaction", onTransaction);
10303
10348
  }, [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
10349
  const insertSpecialChar = useCallback12((char) => {
10315
10350
  if (!editor) return;
10316
10351
  editor.chain().focus().insertContent(char).run();
@@ -10814,11 +10849,11 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10814
10849
  "button",
10815
10850
  {
10816
10851
  className: `toolbar-btn ${isFullscreen ? "is-active" : ""}`,
10817
- onClick: toggleFullscreen,
10852
+ onClick: onToggleFullscreen,
10818
10853
  title: "Toggle Fullscreen"
10819
10854
  },
10820
10855
  /* @__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(
10856
+ ), 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
10857
  "button",
10823
10858
  {
10824
10859
  className: "toolbar-btn",
@@ -10912,7 +10947,17 @@ var Toolbar = ({ editor, setLink, onAICommand, onTranslate, onSpeechToText, onTe
10912
10947
  "button",
10913
10948
  {
10914
10949
  className: "toolbar-btn btn-cross",
10915
- onClick: onClose,
10950
+ onClick: () => {
10951
+ try {
10952
+ ttsRef.current?.stop();
10953
+ } catch {
10954
+ }
10955
+ try {
10956
+ sttRef.current?.stop();
10957
+ } catch {
10958
+ }
10959
+ onClose();
10960
+ },
10916
10961
  title: "Close"
10917
10962
  },
10918
10963
  /* @__PURE__ */ React112.createElement(closeIcon_default, { color: "#a81c08" })
@@ -11454,6 +11499,175 @@ var VideoToolbar = ({ editor }) => {
11454
11499
  };
11455
11500
  var VideoToolbar_default = VideoToolbar;
11456
11501
 
11502
+ // lib/RufousTextEditor/TableToolbar.tsx
11503
+ import React115, { useState as useState33, useEffect as useEffect26, useRef as useRef29 } from "react";
11504
+ import { createPortal as createPortal7 } from "react-dom";
11505
+ 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" }));
11506
+ 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" }));
11507
+ 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)" }));
11508
+ 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" }));
11509
+ 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" }));
11510
+ 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" }));
11511
+ 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" }));
11512
+ 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" }));
11513
+ 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" }));
11514
+ 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" }));
11515
+ var TableToolbar = ({ editor }) => {
11516
+ const [pos, setPos] = useState33(null);
11517
+ const toolbarRef = useRef29(null);
11518
+ useEffect26(() => {
11519
+ if (!editor) return;
11520
+ const update = () => {
11521
+ if (!editor.isActive("table")) {
11522
+ setPos(null);
11523
+ return;
11524
+ }
11525
+ try {
11526
+ const { $from } = editor.state.selection;
11527
+ let depth = $from.depth;
11528
+ while (depth > 0) {
11529
+ const node = $from.node(depth);
11530
+ if (node.type.name === "table") {
11531
+ const domNode = editor.view.nodeDOM($from.before(depth));
11532
+ if (domNode) {
11533
+ const tableEl = domNode.tagName === "TABLE" ? domNode : domNode.querySelector?.("table") || domNode;
11534
+ const rect = tableEl.getBoundingClientRect();
11535
+ setPos({
11536
+ top: rect.top + window.scrollY - 40,
11537
+ left: rect.left + window.scrollX
11538
+ });
11539
+ }
11540
+ return;
11541
+ }
11542
+ depth--;
11543
+ }
11544
+ setPos(null);
11545
+ } catch {
11546
+ setPos(null);
11547
+ }
11548
+ };
11549
+ editor.on("selectionUpdate", update);
11550
+ editor.on("update", update);
11551
+ update();
11552
+ return () => {
11553
+ editor.off("selectionUpdate", update);
11554
+ editor.off("update", update);
11555
+ };
11556
+ }, [editor]);
11557
+ if (!editor || !pos || !editor.isActive("table")) return null;
11558
+ const canMerge = editor.can().mergeCells();
11559
+ const canSplit = editor.can().splitCell();
11560
+ const prevent = (e) => e.preventDefault();
11561
+ return createPortal7(
11562
+ /* @__PURE__ */ React115.createElement(
11563
+ "div",
11564
+ {
11565
+ ref: toolbarRef,
11566
+ className: "rf-table-toolbar",
11567
+ style: { top: pos.top, left: pos.left },
11568
+ onMouseDown: prevent
11569
+ },
11570
+ /* @__PURE__ */ React115.createElement(
11571
+ "button",
11572
+ {
11573
+ className: "rf-table-toolbar-btn",
11574
+ onClick: () => editor.chain().focus().addRowBefore().run(),
11575
+ title: "Insert row above"
11576
+ },
11577
+ /* @__PURE__ */ React115.createElement(IconAddRowBefore, null)
11578
+ ),
11579
+ /* @__PURE__ */ React115.createElement(
11580
+ "button",
11581
+ {
11582
+ className: "rf-table-toolbar-btn",
11583
+ onClick: () => editor.chain().focus().addRowAfter().run(),
11584
+ title: "Insert row below"
11585
+ },
11586
+ /* @__PURE__ */ React115.createElement(IconAddRowAfter, null)
11587
+ ),
11588
+ /* @__PURE__ */ React115.createElement(
11589
+ "button",
11590
+ {
11591
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11592
+ onClick: () => editor.chain().focus().deleteRow().run(),
11593
+ title: "Delete row"
11594
+ },
11595
+ /* @__PURE__ */ React115.createElement(IconDeleteRow, null)
11596
+ ),
11597
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11598
+ /* @__PURE__ */ React115.createElement(
11599
+ "button",
11600
+ {
11601
+ className: "rf-table-toolbar-btn",
11602
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
11603
+ title: "Insert column left"
11604
+ },
11605
+ /* @__PURE__ */ React115.createElement(IconAddColBefore, null)
11606
+ ),
11607
+ /* @__PURE__ */ React115.createElement(
11608
+ "button",
11609
+ {
11610
+ className: "rf-table-toolbar-btn",
11611
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
11612
+ title: "Insert column right"
11613
+ },
11614
+ /* @__PURE__ */ React115.createElement(IconAddColAfter, null)
11615
+ ),
11616
+ /* @__PURE__ */ React115.createElement(
11617
+ "button",
11618
+ {
11619
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11620
+ onClick: () => editor.chain().focus().deleteColumn().run(),
11621
+ title: "Delete column"
11622
+ },
11623
+ /* @__PURE__ */ React115.createElement(IconDeleteCol, null)
11624
+ ),
11625
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11626
+ /* @__PURE__ */ React115.createElement(
11627
+ "button",
11628
+ {
11629
+ className: "rf-table-toolbar-btn",
11630
+ onClick: () => editor.chain().focus().mergeCells().run(),
11631
+ disabled: !canMerge,
11632
+ title: "Merge cells"
11633
+ },
11634
+ /* @__PURE__ */ React115.createElement(IconMergeCells, null)
11635
+ ),
11636
+ /* @__PURE__ */ React115.createElement(
11637
+ "button",
11638
+ {
11639
+ className: "rf-table-toolbar-btn",
11640
+ onClick: () => editor.chain().focus().splitCell().run(),
11641
+ disabled: !canSplit,
11642
+ title: "Split cell"
11643
+ },
11644
+ /* @__PURE__ */ React115.createElement(IconSplitCell, null)
11645
+ ),
11646
+ /* @__PURE__ */ React115.createElement("span", { className: "rf-table-toolbar-sep" }),
11647
+ /* @__PURE__ */ React115.createElement(
11648
+ "button",
11649
+ {
11650
+ className: `rf-table-toolbar-btn ${editor.isActive("tableHeader") ? "active" : ""}`,
11651
+ onClick: () => editor.chain().focus().toggleHeaderRow().run(),
11652
+ title: "Toggle header row"
11653
+ },
11654
+ /* @__PURE__ */ React115.createElement(IconToggleHeader, null)
11655
+ ),
11656
+ /* @__PURE__ */ React115.createElement(
11657
+ "button",
11658
+ {
11659
+ className: "rf-table-toolbar-btn rf-table-toolbar-btn-danger",
11660
+ onClick: () => editor.chain().focus().deleteTable().run(),
11661
+ title: "Delete table"
11662
+ },
11663
+ /* @__PURE__ */ React115.createElement(IconDeleteTable, null)
11664
+ )
11665
+ ),
11666
+ document.body
11667
+ );
11668
+ };
11669
+ var TableToolbar_default = TableToolbar;
11670
+
11457
11671
  // lib/RufousTextEditor/legacyTodoTransform.ts
11458
11672
  var IMAGE_TO_STATUS = {
11459
11673
  "todo-blank.svg": "todo",
@@ -11622,12 +11836,12 @@ var RufousTextEditor = ({
11622
11836
  return visible;
11623
11837
  }, [buttons, variant, hideButtons]);
11624
11838
  const mentionSuggestion = useMemo4(() => createMentionSuggestion(mentions), [mentions]);
11625
- const onChangeRef = useRef29(onChange);
11626
- const onBlurRef = useRef29(onBlur);
11627
- useEffect26(() => {
11839
+ const onChangeRef = useRef30(onChange);
11840
+ const onBlurRef = useRef30(onBlur);
11841
+ useEffect27(() => {
11628
11842
  onChangeRef.current = onChange;
11629
11843
  }, [onChange]);
11630
- useEffect26(() => {
11844
+ useEffect27(() => {
11631
11845
  onBlurRef.current = onBlur;
11632
11846
  }, [onBlur]);
11633
11847
  const isEditable = editable && !disabled;
@@ -11658,7 +11872,9 @@ var RufousTextEditor = ({
11658
11872
  multicolor: true
11659
11873
  }),
11660
11874
  Table.configure({
11661
- resizable: true
11875
+ resizable: true,
11876
+ cellMinWidth: 80,
11877
+ lastColumnResizable: true
11662
11878
  }),
11663
11879
  TableRow,
11664
11880
  TableCell,
@@ -11726,8 +11942,8 @@ var RufousTextEditor = ({
11726
11942
  onChangeRef.current?.(e.getHTML(), e.getJSON());
11727
11943
  }
11728
11944
  });
11729
- const wrapperRef = useRef29(null);
11730
- useEffect26(() => {
11945
+ const wrapperRef = useRef30(null);
11946
+ useEffect27(() => {
11731
11947
  if (!editor) return;
11732
11948
  let blurTimer = null;
11733
11949
  const handler = ({ event }) => {
@@ -11745,14 +11961,14 @@ var RufousTextEditor = ({
11745
11961
  if (blurTimer) clearTimeout(blurTimer);
11746
11962
  };
11747
11963
  }, [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);
11964
+ const setLinkRef = useRef30(null);
11965
+ const [linkModalOpen, setLinkModalOpen] = useState34(false);
11966
+ const [linkUrl, setLinkUrl] = useState34("");
11967
+ const [linkText, setLinkText] = useState34("");
11968
+ const [linkClassName, setLinkClassName] = useState34("");
11969
+ const [linkNewTab, setLinkNewTab] = useState34(true);
11970
+ const [linkNoFollow, setLinkNoFollow] = useState34(true);
11971
+ const [linkSelection, setLinkSelection] = useState34(null);
11756
11972
  const setLink = useCallback13(() => {
11757
11973
  if (!editor) return;
11758
11974
  const attrs = editor.getAttributes("link");
@@ -11790,10 +12006,10 @@ var RufousTextEditor = ({
11790
12006
  setLinkSelection({ from, to });
11791
12007
  setLinkModalOpen(true);
11792
12008
  }, [editor]);
11793
- useEffect26(() => {
12009
+ useEffect27(() => {
11794
12010
  setLinkRef.current = setLink;
11795
12011
  }, [setLink]);
11796
- useEffect26(() => {
12012
+ useEffect27(() => {
11797
12013
  if (!editor?.view) return;
11798
12014
  const handleKeyDown = (event) => {
11799
12015
  if ((event.ctrlKey || event.metaKey) && event.key === "k") {
@@ -11878,7 +12094,7 @@ var RufousTextEditor = ({
11878
12094
  setLinkSelection(null);
11879
12095
  editor?.chain().focus().run();
11880
12096
  }, [editor]);
11881
- const [saveStatus, setSaveStatus] = useState33("");
12097
+ const [saveStatus, setSaveStatus] = useState34("");
11882
12098
  const handleSave = useCallback13(() => {
11883
12099
  if (!editor || !onSaveProp) return;
11884
12100
  onSaveProp(editor.getHTML(), editor.getJSON());
@@ -11890,18 +12106,20 @@ var RufousTextEditor = ({
11890
12106
  onExportProp(editor.getHTML(), editor.getJSON());
11891
12107
  }, [editor, onExportProp]);
11892
12108
  const providerValue = useMemo4(() => ({ editor }), [editor]);
11893
- return /* @__PURE__ */ React115.createElement(
12109
+ const [isFullscreen, setIsFullscreen] = useState34(false);
12110
+ const toggleFullscreen = useCallback13(() => setIsFullscreen((prev) => !prev), []);
12111
+ const wrapperJsx = /* @__PURE__ */ React116.createElement(
11894
12112
  "div",
11895
12113
  {
11896
12114
  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: {
12115
+ className: `rf-rte-wrapper editor-wrapper ${isFullscreen ? "fullscreen" : ""} ${resizable ? "rf-rte-resizable" : ""} ${disabled ? "rf-rte-disabled" : ""} ${error ? "rf-rte-error" : ""} ${sxClass} ${className || ""}`,
12116
+ style: isFullscreen ? void 0 : {
11899
12117
  ...style,
11900
12118
  ...width ? { width: typeof width === "number" ? `${width}px` : width } : {},
11901
12119
  ...height ? { height: typeof height === "number" ? `${height}px` : height } : {}
11902
12120
  }
11903
12121
  },
11904
- /* @__PURE__ */ React115.createElement(EditorContext.Provider, { value: providerValue }, /* @__PURE__ */ React115.createElement(
12122
+ /* @__PURE__ */ React116.createElement(EditorContext.Provider, { value: providerValue }, /* @__PURE__ */ React116.createElement(
11905
12123
  Toolbar_default,
11906
12124
  {
11907
12125
  editor,
@@ -11912,9 +12130,11 @@ var RufousTextEditor = ({
11912
12130
  onTextToSpeech,
11913
12131
  onImageUpload,
11914
12132
  onClose,
11915
- visibleButtons: toolbarButtons
12133
+ visibleButtons: toolbarButtons,
12134
+ isFullscreen,
12135
+ onToggleFullscreen: toggleFullscreen
11916
12136
  }
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(
12137
+ ), /* @__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
12138
  BubbleMenu,
11919
12139
  {
11920
12140
  editor,
@@ -11932,31 +12152,31 @@ var RufousTextEditor = ({
11932
12152
  }
11933
12153
  }
11934
12154
  },
11935
- /* @__PURE__ */ React115.createElement(
12155
+ /* @__PURE__ */ React116.createElement(
11936
12156
  "button",
11937
12157
  {
11938
12158
  onClick: () => editor?.chain().focus().toggleBold().run(),
11939
12159
  className: editor?.isActive("bold") ? "is-active" : ""
11940
12160
  },
11941
- /* @__PURE__ */ React115.createElement("strong", null, "B")
12161
+ /* @__PURE__ */ React116.createElement("strong", null, "B")
11942
12162
  ),
11943
- /* @__PURE__ */ React115.createElement(
12163
+ /* @__PURE__ */ React116.createElement(
11944
12164
  "button",
11945
12165
  {
11946
12166
  onClick: () => editor?.chain().focus().toggleItalic().run(),
11947
12167
  className: editor?.isActive("italic") ? "is-active" : ""
11948
12168
  },
11949
- /* @__PURE__ */ React115.createElement("em", null, "I")
12169
+ /* @__PURE__ */ React116.createElement("em", null, "I")
11950
12170
  ),
11951
- /* @__PURE__ */ React115.createElement(
12171
+ /* @__PURE__ */ React116.createElement(
11952
12172
  "button",
11953
12173
  {
11954
12174
  onClick: () => editor?.chain().focus().toggleStrike().run(),
11955
12175
  className: editor?.isActive("strike") ? "is-active" : ""
11956
12176
  },
11957
- /* @__PURE__ */ React115.createElement("s", null, "S")
12177
+ /* @__PURE__ */ React116.createElement("s", null, "S")
11958
12178
  ),
11959
- /* @__PURE__ */ React115.createElement(
12179
+ /* @__PURE__ */ React116.createElement(
11960
12180
  "button",
11961
12181
  {
11962
12182
  onClick: () => editor?.chain().focus().toggleCode().run(),
@@ -11964,7 +12184,7 @@ var RufousTextEditor = ({
11964
12184
  },
11965
12185
  "</>"
11966
12186
  ),
11967
- /* @__PURE__ */ React115.createElement(
12187
+ /* @__PURE__ */ React116.createElement(
11968
12188
  "button",
11969
12189
  {
11970
12190
  onClick: setLink,
@@ -11972,7 +12192,7 @@ var RufousTextEditor = ({
11972
12192
  },
11973
12193
  "\u{1F517}"
11974
12194
  )
11975
- ), editor && /* @__PURE__ */ React115.createElement(
12195
+ ), editor && /* @__PURE__ */ React116.createElement(
11976
12196
  FloatingMenu,
11977
12197
  {
11978
12198
  editor,
@@ -11987,7 +12207,7 @@ var RufousTextEditor = ({
11987
12207
  }
11988
12208
  }
11989
12209
  },
11990
- /* @__PURE__ */ React115.createElement(
12210
+ /* @__PURE__ */ React116.createElement(
11991
12211
  "button",
11992
12212
  {
11993
12213
  onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
@@ -11995,7 +12215,7 @@ var RufousTextEditor = ({
11995
12215
  },
11996
12216
  "H1"
11997
12217
  ),
11998
- /* @__PURE__ */ React115.createElement(
12218
+ /* @__PURE__ */ React116.createElement(
11999
12219
  "button",
12000
12220
  {
12001
12221
  onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
@@ -12003,7 +12223,7 @@ var RufousTextEditor = ({
12003
12223
  },
12004
12224
  "H2"
12005
12225
  ),
12006
- /* @__PURE__ */ React115.createElement(
12226
+ /* @__PURE__ */ React116.createElement(
12007
12227
  "button",
12008
12228
  {
12009
12229
  onClick: () => editor?.chain().focus().toggleBulletList().run(),
@@ -12011,7 +12231,7 @@ var RufousTextEditor = ({
12011
12231
  },
12012
12232
  "\u2022 List"
12013
12233
  ),
12014
- /* @__PURE__ */ React115.createElement(
12234
+ /* @__PURE__ */ React116.createElement(
12015
12235
  "button",
12016
12236
  {
12017
12237
  onClick: () => editor?.chain().focus().toggleOrderedList().run(),
@@ -12019,7 +12239,7 @@ var RufousTextEditor = ({
12019
12239
  },
12020
12240
  "1. List"
12021
12241
  ),
12022
- /* @__PURE__ */ React115.createElement(
12242
+ /* @__PURE__ */ React116.createElement(
12023
12243
  "button",
12024
12244
  {
12025
12245
  onClick: () => editor?.chain().focus().toggleBlockquote().run(),
@@ -12027,8 +12247,8 @@ var RufousTextEditor = ({
12027
12247
  },
12028
12248
  "\u201C Quote"
12029
12249
  )
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(
12250
+ ), /* @__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(
12251
+ /* @__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
12252
  "input",
12033
12253
  {
12034
12254
  type: "url",
@@ -12041,7 +12261,7 @@ var RufousTextEditor = ({
12041
12261
  placeholder: "https://example.com",
12042
12262
  autoFocus: true
12043
12263
  }
12044
- )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-label" }, "Text"), /* @__PURE__ */ React115.createElement(
12264
+ )), /* @__PURE__ */ React116.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ React116.createElement("label", { className: "link-modal-label" }, "Text"), /* @__PURE__ */ React116.createElement(
12045
12265
  "input",
12046
12266
  {
12047
12267
  type: "text",
@@ -12053,30 +12273,31 @@ var RufousTextEditor = ({
12053
12273
  },
12054
12274
  placeholder: "Link text"
12055
12275
  }
12056
- )), /* @__PURE__ */ React115.createElement("div", { className: "link-modal-checkboxes" }, /* @__PURE__ */ React115.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React115.createElement(
12276
+ )), /* @__PURE__ */ React116.createElement("div", { className: "link-modal-checkboxes" }, /* @__PURE__ */ React116.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React116.createElement(
12057
12277
  "input",
12058
12278
  {
12059
12279
  type: "checkbox",
12060
12280
  checked: linkNewTab,
12061
12281
  onChange: (e) => setLinkNewTab(e.target.checked)
12062
12282
  }
12063
- ), "Open in new tab"), /* @__PURE__ */ React115.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React115.createElement(
12283
+ ), "Open in new tab"), /* @__PURE__ */ React116.createElement("label", { className: "link-modal-checkbox" }, /* @__PURE__ */ React116.createElement(
12064
12284
  "input",
12065
12285
  {
12066
12286
  type: "checkbox",
12067
12287
  checked: linkNoFollow,
12068
12288
  onChange: (e) => setLinkNoFollow(e.target.checked)
12069
12289
  }
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")))),
12290
+ ), "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
12291
  document.body
12072
12292
  )),
12073
- helperText && /* @__PURE__ */ React115.createElement("div", { className: `rf-rte-helper-text ${error ? "rf-rte-helper-error" : ""}` }, helperText)
12293
+ helperText && /* @__PURE__ */ React116.createElement("div", { className: `rf-rte-helper-text ${error ? "rf-rte-helper-error" : ""}` }, helperText)
12074
12294
  );
12295
+ return isFullscreen ? createPortal8(wrapperJsx, document.body) : wrapperJsx;
12075
12296
  };
12076
12297
  var RufousTextContent = ({ content, className, style, sx }) => {
12077
12298
  const sxClass = useSx(sx);
12078
12299
  const transformedContent = useMemo4(() => transformLegacyTodos(content || ""), [content]);
12079
- return /* @__PURE__ */ React115.createElement(
12300
+ return /* @__PURE__ */ React116.createElement(
12080
12301
  "div",
12081
12302
  {
12082
12303
  className: `rf-rte-content ${sxClass} ${className || ""}`,