@sofereditor/react 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,16 +1,23 @@
1
1
  // src/Editor.tsx
2
2
  import {
3
- useCallback as useCallback5,
4
- useEffect as useEffect7,
5
- useLayoutEffect as useLayoutEffect4,
3
+ useCallback as useCallback7,
4
+ useEffect as useEffect9,
5
+ useLayoutEffect as useLayoutEffect5,
6
6
  useMemo as useMemo4,
7
- useRef as useRef10
7
+ useRef as useRef11,
8
+ useState as useState10
8
9
  } from "react";
9
10
  import {
10
11
  deleteBackward,
11
12
  deleteForward,
13
+ deleteSelection,
14
+ encodeSelection,
12
15
  insertParagraph,
13
- insertText
16
+ insertSlice,
17
+ insertText,
18
+ serializeSelection,
19
+ sliceToText,
20
+ SOFER_MIME
14
21
  } from "@sofereditor/core";
15
22
 
16
23
  // src/dom-bridge.ts
@@ -211,6 +218,7 @@ function locatePoint(root, pos) {
211
218
  let remaining = Math.max(0, pos.offset - containerStart);
212
219
  let result = null;
213
220
  let lastImg = null;
221
+ let lastText = null;
214
222
  function visit(n) {
215
223
  if (result) return;
216
224
  if (n.nodeType === Node.TEXT_NODE) {
@@ -221,6 +229,7 @@ function locatePoint(root, pos) {
221
229
  }
222
230
  remaining -= len;
223
231
  lastImg = null;
232
+ lastText = n;
224
233
  return;
225
234
  }
226
235
  if (n.nodeType !== Node.ELEMENT_NODE) return;
@@ -250,6 +259,10 @@ function locatePoint(root, pos) {
250
259
  const parent = lastImg.parentNode;
251
260
  if (parent) return { node: parent, offset: indexInParent(lastImg) + 1 };
252
261
  }
262
+ if (lastText) {
263
+ const t = lastText;
264
+ return { node: t, offset: (t.textContent ?? "").length };
265
+ }
253
266
  return { node: container, offset: 0 };
254
267
  }
255
268
  function selectionsEqual(a, b) {
@@ -270,6 +283,9 @@ function applyDomSelection(root, modelSel) {
270
283
  const anchorPt = locatePoint(root, modelSel.anchor);
271
284
  const focusPt = locatePoint(root, modelSel.focus);
272
285
  if (!anchorPt || !focusPt) return;
286
+ if (domSel.anchorNode === anchorPt.node && domSel.anchorOffset === anchorPt.offset && domSel.focusNode === focusPt.node && domSel.focusOffset === focusPt.offset) {
287
+ return;
288
+ }
273
289
  try {
274
290
  domSel.removeAllRanges();
275
291
  domSel.setBaseAndExtent(anchorPt.node, anchorPt.offset, focusPt.node, focusPt.offset);
@@ -277,22 +293,262 @@ function applyDomSelection(root, modelSel) {
277
293
  }
278
294
  }
279
295
 
296
+ // src/BehindImageSelectAffordance.tsx
297
+ import {
298
+ useCallback,
299
+ useEffect,
300
+ useLayoutEffect,
301
+ useState
302
+ } from "react";
303
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
304
+ var ACCENT = "#3b82f6";
305
+ function BehindImageSelectAffordance({
306
+ blockIndex,
307
+ offset,
308
+ cellIndex,
309
+ rootRef,
310
+ onSelect
311
+ }) {
312
+ const [rect, setRect] = useState(null);
313
+ const locateImage = useCallback(() => {
314
+ const root = rootRef.current;
315
+ if (!root) return null;
316
+ let container = null;
317
+ if (cellIndex != null) {
318
+ container = root.querySelector(
319
+ `[data-block-index="${blockIndex}"] [data-cell-index="${cellIndex}"]`
320
+ );
321
+ } else {
322
+ container = getFragmentForOffset(root, blockIndex, offset);
323
+ }
324
+ if (!container) return null;
325
+ const fragmentStart = container.dataset.fragmentStart ? Number.parseInt(container.dataset.fragmentStart, 10) || 0 : 0;
326
+ const localOffset = offset - fragmentStart;
327
+ return container.querySelector(
328
+ `img[data-embed="image"][data-embed-offset="${localOffset}"]`
329
+ );
330
+ }, [rootRef, blockIndex, offset, cellIndex]);
331
+ const measure = useCallback(() => {
332
+ const img = locateImage();
333
+ const root = rootRef.current;
334
+ if (!img || !root) {
335
+ setRect((prev) => prev === null ? prev : null);
336
+ return;
337
+ }
338
+ const r = img.getBoundingClientRect();
339
+ const rr = root.getBoundingClientRect();
340
+ const next = {
341
+ top: r.top - rr.top + root.scrollTop,
342
+ left: r.left - rr.left + root.scrollLeft,
343
+ width: r.width,
344
+ height: r.height
345
+ };
346
+ setRect(
347
+ (prev) => prev && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
348
+ );
349
+ }, [locateImage, rootRef]);
350
+ useLayoutEffect(() => {
351
+ measure();
352
+ let cancelled = false;
353
+ const remeasure = () => {
354
+ if (!cancelled) measure();
355
+ };
356
+ const id = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
357
+ return () => {
358
+ cancelled = true;
359
+ if (typeof cancelAnimationFrame === "function" && typeof id === "number" && id > 0) {
360
+ cancelAnimationFrame(id);
361
+ }
362
+ };
363
+ }, [measure]);
364
+ useEffect(() => {
365
+ const root = rootRef.current;
366
+ if (!root) return;
367
+ const onScroll = () => measure();
368
+ window.addEventListener("resize", onScroll);
369
+ root.addEventListener("scroll", onScroll);
370
+ return () => {
371
+ window.removeEventListener("resize", onScroll);
372
+ root.removeEventListener("scroll", onScroll);
373
+ };
374
+ }, [measure, rootRef]);
375
+ if (!rect) return null;
376
+ const outlineStyle = {
377
+ position: "absolute",
378
+ top: rect.top,
379
+ left: rect.left,
380
+ width: rect.width,
381
+ height: rect.height,
382
+ border: `1.5px dashed ${ACCENT}`,
383
+ borderRadius: 2,
384
+ boxSizing: "border-box",
385
+ pointerEvents: "none",
386
+ zIndex: 4
387
+ };
388
+ const badgeStyle = {
389
+ position: "absolute",
390
+ top: rect.top - 2,
391
+ left: rect.left - 2,
392
+ width: 24,
393
+ height: 24,
394
+ display: "flex",
395
+ alignItems: "center",
396
+ justifyContent: "center",
397
+ background: ACCENT,
398
+ color: "#fff",
399
+ borderRadius: 4,
400
+ cursor: "pointer",
401
+ pointerEvents: "auto",
402
+ boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
403
+ zIndex: 5
404
+ };
405
+ const onBadgeDown = (e) => {
406
+ if (e.button !== 0) return;
407
+ e.preventDefault();
408
+ e.stopPropagation();
409
+ onSelect();
410
+ };
411
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
412
+ /* @__PURE__ */ jsx("div", { style: outlineStyle, contentEditable: false, "aria-hidden": true }),
413
+ /* @__PURE__ */ jsx(
414
+ "div",
415
+ {
416
+ style: badgeStyle,
417
+ contentEditable: false,
418
+ onPointerDown: onBadgeDown,
419
+ role: "button",
420
+ "aria-label": "Selecionar imagem",
421
+ title: "Selecionar imagem",
422
+ children: /* @__PURE__ */ jsx(
423
+ "svg",
424
+ {
425
+ width: "14",
426
+ height: "14",
427
+ viewBox: "0 0 24 24",
428
+ fill: "none",
429
+ stroke: "currentColor",
430
+ strokeWidth: "2",
431
+ strokeLinecap: "round",
432
+ strokeLinejoin: "round",
433
+ "aria-hidden": true,
434
+ children: /* @__PURE__ */ jsx("path", { d: "M5 9l-3 3 3 3M9 5l3-3 3 3M15 19l-3 3-3-3M19 9l3 3-3 3M2 12h20M12 2v20" })
435
+ }
436
+ )
437
+ }
438
+ )
439
+ ] });
440
+ }
441
+
442
+ // src/LinkHoverTooltip.tsx
443
+ import { createPortal } from "react-dom";
444
+
445
+ // src/platform.ts
446
+ var IS_MAC = (() => {
447
+ if (typeof navigator === "undefined") return false;
448
+ const platform = navigator.userAgentData?.platform || navigator.platform || navigator.userAgent || "";
449
+ return /mac|iphone|ipad|ipod/i.test(platform);
450
+ })();
451
+ var MOD_SYMBOL = IS_MAC ? "\u2318" : "\u2303";
452
+ function hasOpenModifier(e) {
453
+ return IS_MAC ? e.metaKey : e.ctrlKey;
454
+ }
455
+
456
+ // src/LinkHoverTooltip.tsx
457
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
458
+ var MAX_WIDTH = 360;
459
+ var GAP = 6;
460
+ function LinkHoverTooltip({ href, rect }) {
461
+ const above = rect.top > 48;
462
+ const viewportW = typeof window !== "undefined" ? window.innerWidth : MAX_WIDTH + 16;
463
+ const left = Math.max(8, Math.min(rect.left, viewportW - MAX_WIDTH - 8));
464
+ const style = {
465
+ position: "fixed",
466
+ left,
467
+ top: above ? rect.top - GAP : rect.bottom + GAP,
468
+ transform: above ? "translateY(-100%)" : void 0,
469
+ maxWidth: MAX_WIDTH,
470
+ background: "#1f2937",
471
+ color: "#fff",
472
+ fontSize: 12,
473
+ lineHeight: 1.4,
474
+ padding: "6px 9px",
475
+ borderRadius: 6,
476
+ boxShadow: "0 4px 14px rgba(0,0,0,0.28)",
477
+ zIndex: 60,
478
+ pointerEvents: "none"
479
+ };
480
+ const urlStyle = {
481
+ display: "block",
482
+ maxWidth: MAX_WIDTH - 18,
483
+ overflow: "hidden",
484
+ textOverflow: "ellipsis",
485
+ whiteSpace: "nowrap",
486
+ fontWeight: 600
487
+ };
488
+ const hintStyle = {
489
+ display: "flex",
490
+ alignItems: "center",
491
+ gap: 4,
492
+ marginTop: 3,
493
+ fontSize: 11,
494
+ opacity: 0.85
495
+ };
496
+ const keycapStyle = {
497
+ display: "inline-flex",
498
+ alignItems: "center",
499
+ justifyContent: "center",
500
+ minWidth: 16,
501
+ height: 16,
502
+ padding: "0 4px",
503
+ fontSize: 11,
504
+ fontFamily: "system-ui, -apple-system, sans-serif",
505
+ background: "rgba(255,255,255,0.16)",
506
+ border: "1px solid rgba(255,255,255,0.4)",
507
+ borderRadius: 4,
508
+ boxShadow: "inset 0 -1px 0 rgba(0,0,0,0.25)"
509
+ };
510
+ if (typeof document === "undefined") return /* @__PURE__ */ jsx2(Fragment2, {});
511
+ return createPortal(
512
+ /* @__PURE__ */ jsxs2("div", { style, contentEditable: false, "aria-hidden": true, role: "tooltip", children: [
513
+ /* @__PURE__ */ jsx2("span", { style: urlStyle, children: href }),
514
+ /* @__PURE__ */ jsxs2("span", { style: hintStyle, children: [
515
+ /* @__PURE__ */ jsx2("kbd", { style: keycapStyle, children: MOD_SYMBOL }),
516
+ /* @__PURE__ */ jsx2("span", { style: { opacity: 0.8 }, children: "+ clique para abrir" })
517
+ ] })
518
+ ] }),
519
+ document.body
520
+ );
521
+ }
522
+
280
523
  // src/EditorContext.tsx
281
524
  import { createContext, useContext } from "react";
282
525
 
283
526
  // src/LinkDialog.tsx
284
527
  import {
285
- useEffect,
528
+ useEffect as useEffect2,
286
529
  useRef,
287
- useState
530
+ useState as useState2
288
531
  } from "react";
289
- import { jsx, jsxs } from "react/jsx-runtime";
532
+
533
+ // src/dialogCenterStyle.ts
534
+ var DIALOG_CENTER_STYLE = {
535
+ position: "fixed",
536
+ top: "50%",
537
+ left: "50%",
538
+ transform: "translate(-50%, -50%)",
539
+ margin: 0,
540
+ maxHeight: "90vh",
541
+ overflow: "auto"
542
+ };
543
+
544
+ // src/LinkDialog.tsx
545
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
290
546
  function LinkDialog() {
291
547
  const { linkRequest, resolveLinkRequest } = useEditorContext();
292
548
  const dialogRef = useRef(null);
293
549
  const inputRef = useRef(null);
294
- const [href, setHref] = useState("");
295
- useEffect(() => {
550
+ const [href, setHref] = useState2("");
551
+ useEffect2(() => {
296
552
  const dialog = dialogRef.current;
297
553
  if (!dialog) return;
298
554
  if (linkRequest) {
@@ -320,20 +576,21 @@ function LinkDialog() {
320
576
  const onCancel = () => {
321
577
  resolveLinkRequest(null);
322
578
  };
323
- return /* @__PURE__ */ jsx(
579
+ return /* @__PURE__ */ jsx3(
324
580
  "dialog",
325
581
  {
326
582
  ref: dialogRef,
327
583
  className: "ed-link-dialog",
584
+ style: DIALOG_CENTER_STYLE,
328
585
  onClose: onCancel,
329
586
  onCancel: (e) => {
330
587
  e.preventDefault();
331
588
  onCancel();
332
589
  },
333
- children: /* @__PURE__ */ jsxs("form", { onSubmit, className: "ed-link-dialog-form", children: [
334
- /* @__PURE__ */ jsxs("div", { className: "ed-link-dialog-row", children: [
335
- /* @__PURE__ */ jsx("label", { htmlFor: "ed-link-href", children: "URL" }),
336
- /* @__PURE__ */ jsx(
590
+ children: /* @__PURE__ */ jsxs3("form", { onSubmit, className: "ed-link-dialog-form", children: [
591
+ /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-row", children: [
592
+ /* @__PURE__ */ jsx3("label", { htmlFor: "ed-link-href", children: "URL" }),
593
+ /* @__PURE__ */ jsx3(
337
594
  "input",
338
595
  {
339
596
  id: "ed-link-href",
@@ -347,11 +604,11 @@ function LinkDialog() {
347
604
  }
348
605
  )
349
606
  ] }),
350
- /* @__PURE__ */ jsxs("div", { className: "ed-link-dialog-actions", children: [
351
- linkRequest.initialHref ? /* @__PURE__ */ jsx("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover link" }) : /* @__PURE__ */ jsx("span", {}),
352
- /* @__PURE__ */ jsxs("div", { className: "ed-link-dialog-confirm", children: [
353
- /* @__PURE__ */ jsx("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
354
- /* @__PURE__ */ jsx("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
607
+ /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-actions", children: [
608
+ linkRequest.initialHref ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover link" }) : /* @__PURE__ */ jsx3("span", {}),
609
+ /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-confirm", children: [
610
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
611
+ /* @__PURE__ */ jsx3("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
355
612
  ] })
356
613
  ] })
357
614
  ] })
@@ -360,7 +617,7 @@ function LinkDialog() {
360
617
  }
361
618
 
362
619
  // src/PageConfigDialog.tsx
363
- import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
620
+ import { useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
364
621
  import {
365
622
  MARGIN_PRESETS,
366
623
  PAGE_PRESETS,
@@ -368,19 +625,19 @@ import {
368
625
  mmToPx,
369
626
  pxToMm
370
627
  } from "@sofereditor/core";
371
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
628
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
372
629
  function PageConfigDialog() {
373
630
  const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();
374
631
  const dialogRef = useRef2(null);
375
- const [sizePreset, setSizePreset] = useState2("a4");
376
- const [widthMm, setWidthMm] = useState2(210);
377
- const [heightMm, setHeightMm] = useState2(297);
378
- const [marginPreset, setMarginPreset] = useState2("normal");
379
- const [marginTopMm, setMarginTopMm] = useState2(25.4);
380
- const [marginBottomMm, setMarginBottomMm] = useState2(25.4);
381
- const [marginLeftMm, setMarginLeftMm] = useState2(25.4);
382
- const [marginRightMm, setMarginRightMm] = useState2(25.4);
383
- useEffect2(() => {
632
+ const [sizePreset, setSizePreset] = useState3("a4");
633
+ const [widthMm, setWidthMm] = useState3(210);
634
+ const [heightMm, setHeightMm] = useState3(297);
635
+ const [marginPreset, setMarginPreset] = useState3("normal");
636
+ const [marginTopMm, setMarginTopMm] = useState3(25.4);
637
+ const [marginBottomMm, setMarginBottomMm] = useState3(25.4);
638
+ const [marginLeftMm, setMarginLeftMm] = useState3(25.4);
639
+ const [marginRightMm, setMarginRightMm] = useState3(25.4);
640
+ useEffect3(() => {
384
641
  const dialog = dialogRef.current;
385
642
  if (!dialog) return;
386
643
  if (pageConfigRequest) {
@@ -399,13 +656,13 @@ function PageConfigDialog() {
399
656
  dialog.close();
400
657
  }
401
658
  }, [pageConfigRequest]);
402
- useEffect2(() => {
659
+ useEffect3(() => {
403
660
  if (sizePreset === "custom") return;
404
661
  const p = PAGE_PRESETS[sizePreset];
405
662
  setWidthMm(roundMm(pxToMm(p.width)));
406
663
  setHeightMm(roundMm(pxToMm(p.height)));
407
664
  }, [sizePreset]);
408
- useEffect2(() => {
665
+ useEffect3(() => {
409
666
  if (marginPreset === "custom") return;
410
667
  const px = MARGIN_PRESETS[marginPreset];
411
668
  const mm = roundMm(pxToMm(px));
@@ -437,23 +694,24 @@ function PageConfigDialog() {
437
694
  resolvePageConfigRequest(true);
438
695
  };
439
696
  const onCancel = () => resolvePageConfigRequest(false);
440
- return /* @__PURE__ */ jsx2(
697
+ return /* @__PURE__ */ jsx4(
441
698
  "dialog",
442
699
  {
443
700
  ref: dialogRef,
444
701
  className: "ed-page-config-dialog",
702
+ style: DIALOG_CENTER_STYLE,
445
703
  onClose: onCancel,
446
704
  onCancel: (e) => {
447
705
  e.preventDefault();
448
706
  onCancel();
449
707
  },
450
- children: /* @__PURE__ */ jsxs2("form", { onSubmit: onApply, className: "ed-page-config-form", children: [
451
- /* @__PURE__ */ jsx2("h2", { children: "Configurar p\xE1gina" }),
452
- /* @__PURE__ */ jsxs2("fieldset", { children: [
453
- /* @__PURE__ */ jsx2("legend", { children: "Tamanho" }),
454
- /* @__PURE__ */ jsxs2("div", { className: "ed-page-config-row", children: [
455
- /* @__PURE__ */ jsxs2("label", { children: [
456
- /* @__PURE__ */ jsx2(
708
+ children: /* @__PURE__ */ jsxs4("form", { onSubmit: onApply, className: "ed-page-config-form", children: [
709
+ /* @__PURE__ */ jsx4("h2", { children: "Configurar p\xE1gina" }),
710
+ /* @__PURE__ */ jsxs4("fieldset", { children: [
711
+ /* @__PURE__ */ jsx4("legend", { children: "Tamanho" }),
712
+ /* @__PURE__ */ jsxs4("div", { className: "ed-page-config-row", children: [
713
+ /* @__PURE__ */ jsxs4("label", { children: [
714
+ /* @__PURE__ */ jsx4(
457
715
  "input",
458
716
  {
459
717
  type: "radio",
@@ -465,8 +723,8 @@ function PageConfigDialog() {
465
723
  " ",
466
724
  "A4 (210 \xD7 297 mm)"
467
725
  ] }),
468
- /* @__PURE__ */ jsxs2("label", { children: [
469
- /* @__PURE__ */ jsx2(
726
+ /* @__PURE__ */ jsxs4("label", { children: [
727
+ /* @__PURE__ */ jsx4(
470
728
  "input",
471
729
  {
472
730
  type: "radio",
@@ -478,8 +736,8 @@ function PageConfigDialog() {
478
736
  " ",
479
737
  "Carta (216 \xD7 279 mm)"
480
738
  ] }),
481
- /* @__PURE__ */ jsxs2("label", { children: [
482
- /* @__PURE__ */ jsx2(
739
+ /* @__PURE__ */ jsxs4("label", { children: [
740
+ /* @__PURE__ */ jsx4(
483
741
  "input",
484
742
  {
485
743
  type: "radio",
@@ -491,8 +749,8 @@ function PageConfigDialog() {
491
749
  " ",
492
750
  "Of\xEDcio (216 \xD7 330 mm)"
493
751
  ] }),
494
- /* @__PURE__ */ jsxs2("label", { children: [
495
- /* @__PURE__ */ jsx2(
752
+ /* @__PURE__ */ jsxs4("label", { children: [
753
+ /* @__PURE__ */ jsx4(
496
754
  "input",
497
755
  {
498
756
  type: "radio",
@@ -505,11 +763,11 @@ function PageConfigDialog() {
505
763
  "Personalizado"
506
764
  ] })
507
765
  ] }),
508
- /* @__PURE__ */ jsxs2("div", { className: "ed-page-config-row", children: [
509
- /* @__PURE__ */ jsxs2("label", { children: [
766
+ /* @__PURE__ */ jsxs4("div", { className: "ed-page-config-row", children: [
767
+ /* @__PURE__ */ jsxs4("label", { children: [
510
768
  "Largura (mm)",
511
769
  " ",
512
- /* @__PURE__ */ jsx2(
770
+ /* @__PURE__ */ jsx4(
513
771
  "input",
514
772
  {
515
773
  type: "number",
@@ -522,10 +780,10 @@ function PageConfigDialog() {
522
780
  }
523
781
  )
524
782
  ] }),
525
- /* @__PURE__ */ jsxs2("label", { children: [
783
+ /* @__PURE__ */ jsxs4("label", { children: [
526
784
  "Altura (mm)",
527
785
  " ",
528
- /* @__PURE__ */ jsx2(
786
+ /* @__PURE__ */ jsx4(
529
787
  "input",
530
788
  {
531
789
  type: "number",
@@ -538,7 +796,7 @@ function PageConfigDialog() {
538
796
  }
539
797
  )
540
798
  ] }),
541
- /* @__PURE__ */ jsxs2("span", { className: "ed-page-config-preview", children: [
799
+ /* @__PURE__ */ jsxs4("span", { className: "ed-page-config-preview", children: [
542
800
  previewPx.width,
543
801
  " \xD7 ",
544
802
  previewPx.height,
@@ -546,11 +804,11 @@ function PageConfigDialog() {
546
804
  ] })
547
805
  ] })
548
806
  ] }),
549
- /* @__PURE__ */ jsxs2("fieldset", { children: [
550
- /* @__PURE__ */ jsx2("legend", { children: "Margens" }),
551
- /* @__PURE__ */ jsxs2("div", { className: "ed-page-config-row", children: [
552
- /* @__PURE__ */ jsxs2("label", { children: [
553
- /* @__PURE__ */ jsx2(
807
+ /* @__PURE__ */ jsxs4("fieldset", { children: [
808
+ /* @__PURE__ */ jsx4("legend", { children: "Margens" }),
809
+ /* @__PURE__ */ jsxs4("div", { className: "ed-page-config-row", children: [
810
+ /* @__PURE__ */ jsxs4("label", { children: [
811
+ /* @__PURE__ */ jsx4(
554
812
  "input",
555
813
  {
556
814
  type: "radio",
@@ -562,8 +820,8 @@ function PageConfigDialog() {
562
820
  " ",
563
821
  "Normal (25,4 mm)"
564
822
  ] }),
565
- /* @__PURE__ */ jsxs2("label", { children: [
566
- /* @__PURE__ */ jsx2(
823
+ /* @__PURE__ */ jsxs4("label", { children: [
824
+ /* @__PURE__ */ jsx4(
567
825
  "input",
568
826
  {
569
827
  type: "radio",
@@ -575,8 +833,8 @@ function PageConfigDialog() {
575
833
  " ",
576
834
  "Estreita (12,7 mm)"
577
835
  ] }),
578
- /* @__PURE__ */ jsxs2("label", { children: [
579
- /* @__PURE__ */ jsx2(
836
+ /* @__PURE__ */ jsxs4("label", { children: [
837
+ /* @__PURE__ */ jsx4(
580
838
  "input",
581
839
  {
582
840
  type: "radio",
@@ -588,8 +846,8 @@ function PageConfigDialog() {
588
846
  " ",
589
847
  "Larga (50,8 mm)"
590
848
  ] }),
591
- /* @__PURE__ */ jsxs2("label", { children: [
592
- /* @__PURE__ */ jsx2(
849
+ /* @__PURE__ */ jsxs4("label", { children: [
850
+ /* @__PURE__ */ jsx4(
593
851
  "input",
594
852
  {
595
853
  type: "radio",
@@ -602,11 +860,11 @@ function PageConfigDialog() {
602
860
  "Personalizada"
603
861
  ] })
604
862
  ] }),
605
- /* @__PURE__ */ jsxs2("div", { className: "ed-page-config-row", children: [
606
- /* @__PURE__ */ jsxs2("label", { children: [
863
+ /* @__PURE__ */ jsxs4("div", { className: "ed-page-config-row", children: [
864
+ /* @__PURE__ */ jsxs4("label", { children: [
607
865
  "Topo",
608
866
  " ",
609
- /* @__PURE__ */ jsx2(
867
+ /* @__PURE__ */ jsx4(
610
868
  "input",
611
869
  {
612
870
  type: "number",
@@ -621,10 +879,10 @@ function PageConfigDialog() {
621
879
  }
622
880
  )
623
881
  ] }),
624
- /* @__PURE__ */ jsxs2("label", { children: [
882
+ /* @__PURE__ */ jsxs4("label", { children: [
625
883
  "Inferior",
626
884
  " ",
627
- /* @__PURE__ */ jsx2(
885
+ /* @__PURE__ */ jsx4(
628
886
  "input",
629
887
  {
630
888
  type: "number",
@@ -639,10 +897,10 @@ function PageConfigDialog() {
639
897
  }
640
898
  )
641
899
  ] }),
642
- /* @__PURE__ */ jsxs2("label", { children: [
900
+ /* @__PURE__ */ jsxs4("label", { children: [
643
901
  "Esquerda",
644
902
  " ",
645
- /* @__PURE__ */ jsx2(
903
+ /* @__PURE__ */ jsx4(
646
904
  "input",
647
905
  {
648
906
  type: "number",
@@ -657,10 +915,10 @@ function PageConfigDialog() {
657
915
  }
658
916
  )
659
917
  ] }),
660
- /* @__PURE__ */ jsxs2("label", { children: [
918
+ /* @__PURE__ */ jsxs4("label", { children: [
661
919
  "Direita",
662
920
  " ",
663
- /* @__PURE__ */ jsx2(
921
+ /* @__PURE__ */ jsx4(
664
922
  "input",
665
923
  {
666
924
  type: "number",
@@ -677,9 +935,9 @@ function PageConfigDialog() {
677
935
  ] })
678
936
  ] })
679
937
  ] }),
680
- /* @__PURE__ */ jsxs2("div", { className: "ed-page-config-actions", children: [
681
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
682
- /* @__PURE__ */ jsx2("button", { type: "submit", className: "ed-page-config-apply", children: "Aplicar" })
938
+ /* @__PURE__ */ jsxs4("div", { className: "ed-page-config-actions", children: [
939
+ /* @__PURE__ */ jsx4("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
940
+ /* @__PURE__ */ jsx4("button", { type: "submit", className: "ed-page-config-apply", children: "Aplicar" })
683
941
  ] })
684
942
  ] })
685
943
  }
@@ -714,15 +972,15 @@ function detectMarginPreset(s) {
714
972
  }
715
973
 
716
974
  // src/ImageCaptionDialog.tsx
717
- import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
718
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
975
+ import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
976
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
719
977
  function ImageCaptionDialog() {
720
978
  const { imageCaptionRequest, resolveImageCaptionRequest } = useEditorContext();
721
979
  const dialogRef = useRef3(null);
722
980
  const inputRef = useRef3(null);
723
- const [caption, setCaption] = useState3("");
724
- const [align, setAlign] = useState3("center");
725
- useEffect3(() => {
981
+ const [caption, setCaption] = useState4("");
982
+ const [align, setAlign] = useState4("center");
983
+ useEffect4(() => {
726
984
  const dialog = dialogRef.current;
727
985
  if (!dialog) return;
728
986
  if (imageCaptionRequest) {
@@ -747,20 +1005,21 @@ function ImageCaptionDialog() {
747
1005
  };
748
1006
  const onRemove = () => resolveImageCaptionRequest({ caption: "", align });
749
1007
  const onCancel = () => resolveImageCaptionRequest(null);
750
- return /* @__PURE__ */ jsx3(
1008
+ return /* @__PURE__ */ jsx5(
751
1009
  "dialog",
752
1010
  {
753
1011
  ref: dialogRef,
754
1012
  className: "ed-caption-dialog ed-link-dialog",
1013
+ style: DIALOG_CENTER_STYLE,
755
1014
  onClose: onCancel,
756
1015
  onCancel: (e) => {
757
1016
  e.preventDefault();
758
1017
  onCancel();
759
1018
  },
760
- children: /* @__PURE__ */ jsxs3("form", { onSubmit, className: "ed-link-dialog-form", children: [
761
- /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-row", children: [
762
- /* @__PURE__ */ jsx3("label", { htmlFor: "ed-caption-input", children: "Legenda" }),
763
- /* @__PURE__ */ jsx3(
1019
+ children: /* @__PURE__ */ jsxs5("form", { onSubmit, className: "ed-link-dialog-form", children: [
1020
+ /* @__PURE__ */ jsxs5("div", { className: "ed-link-dialog-row", children: [
1021
+ /* @__PURE__ */ jsx5("label", { htmlFor: "ed-caption-input", children: "Legenda" }),
1022
+ /* @__PURE__ */ jsx5(
764
1023
  "input",
765
1024
  {
766
1025
  id: "ed-caption-input",
@@ -773,10 +1032,10 @@ function ImageCaptionDialog() {
773
1032
  }
774
1033
  )
775
1034
  ] }),
776
- /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-row", children: [
777
- /* @__PURE__ */ jsx3("span", { children: "Alinhamento" }),
778
- /* @__PURE__ */ jsx3("div", { className: "ed-caption-align-group", role: "radiogroup", "aria-label": "Alinhamento da legenda", children: ["left", "center", "right"].map((value) => /* @__PURE__ */ jsxs3("label", { className: "ed-caption-align-option", children: [
779
- /* @__PURE__ */ jsx3(
1035
+ /* @__PURE__ */ jsxs5("div", { className: "ed-link-dialog-row", children: [
1036
+ /* @__PURE__ */ jsx5("span", { children: "Alinhamento" }),
1037
+ /* @__PURE__ */ jsx5("div", { className: "ed-caption-align-group", role: "radiogroup", "aria-label": "Alinhamento da legenda", children: ["left", "center", "right"].map((value) => /* @__PURE__ */ jsxs5("label", { className: "ed-caption-align-option", children: [
1038
+ /* @__PURE__ */ jsx5(
780
1039
  "input",
781
1040
  {
782
1041
  type: "radio",
@@ -789,11 +1048,11 @@ function ImageCaptionDialog() {
789
1048
  value === "left" ? "Esquerda" : value === "center" ? "Centro" : "Direita"
790
1049
  ] }, value)) })
791
1050
  ] }),
792
- /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-actions", children: [
793
- imageCaptionRequest.initialCaption ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover legenda" }) : /* @__PURE__ */ jsx3("span", {}),
794
- /* @__PURE__ */ jsxs3("div", { className: "ed-link-dialog-confirm", children: [
795
- /* @__PURE__ */ jsx3("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
796
- /* @__PURE__ */ jsx3("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
1051
+ /* @__PURE__ */ jsxs5("div", { className: "ed-link-dialog-actions", children: [
1052
+ imageCaptionRequest.initialCaption ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover legenda" }) : /* @__PURE__ */ jsx5("span", {}),
1053
+ /* @__PURE__ */ jsxs5("div", { className: "ed-link-dialog-confirm", children: [
1054
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
1055
+ /* @__PURE__ */ jsx5("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
797
1056
  ] })
798
1057
  ] })
799
1058
  ] })
@@ -802,14 +1061,14 @@ function ImageCaptionDialog() {
802
1061
  }
803
1062
 
804
1063
  // src/EditorContext.tsx
805
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1064
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
806
1065
  var EditorContext = createContext(null);
807
1066
  function EditorProvider({ editor, children }) {
808
- return /* @__PURE__ */ jsxs4(EditorContext.Provider, { value: editor, children: [
1067
+ return /* @__PURE__ */ jsxs6(EditorContext.Provider, { value: editor, children: [
809
1068
  children,
810
- /* @__PURE__ */ jsx4(LinkDialog, {}),
811
- /* @__PURE__ */ jsx4(PageConfigDialog, {}),
812
- /* @__PURE__ */ jsx4(ImageCaptionDialog, {})
1069
+ /* @__PURE__ */ jsx6(LinkDialog, {}),
1070
+ /* @__PURE__ */ jsx6(PageConfigDialog, {}),
1071
+ /* @__PURE__ */ jsx6(ImageCaptionDialog, {})
813
1072
  ] });
814
1073
  }
815
1074
  function useEditorContext() {
@@ -822,13 +1081,13 @@ function useEditorContext() {
822
1081
 
823
1082
  // src/ImageResizeOverlay.tsx
824
1083
  import {
825
- useCallback,
826
- useEffect as useEffect4,
827
- useLayoutEffect,
1084
+ useCallback as useCallback2,
1085
+ useEffect as useEffect5,
1086
+ useLayoutEffect as useLayoutEffect2,
828
1087
  useRef as useRef4,
829
- useState as useState4
1088
+ useState as useState5
830
1089
  } from "react";
831
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1090
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
832
1091
  function ImageResizeOverlay({
833
1092
  rootRef,
834
1093
  blockIndex,
@@ -836,11 +1095,13 @@ function ImageResizeOverlay({
836
1095
  cellIndex,
837
1096
  embed,
838
1097
  onCommit,
839
- onCommitMove
1098
+ onCommitMove,
1099
+ onReanchor
840
1100
  }) {
841
- const [rect, setRect] = useState4(null);
1101
+ const [rect, setRect] = useState5(null);
1102
+ const [isMoving, setIsMoving] = useState5(false);
842
1103
  const imgRef = useRef4(null);
843
- const locateImage = useCallback(() => {
1104
+ const locateImage = useCallback2(() => {
844
1105
  const root = rootRef.current;
845
1106
  if (!root) return null;
846
1107
  let container = null;
@@ -858,7 +1119,7 @@ function ImageResizeOverlay({
858
1119
  `img[data-embed="image"][data-embed-offset="${localOffset}"]`
859
1120
  );
860
1121
  }, [rootRef, blockIndex, offset, cellIndex]);
861
- const measure = useCallback(() => {
1122
+ const measure = useCallback2(() => {
862
1123
  const img = locateImage();
863
1124
  if (!img) {
864
1125
  setRect((prev) => prev === null ? prev : null);
@@ -879,22 +1140,28 @@ function ImageResizeOverlay({
879
1140
  (prev) => prev && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
880
1141
  );
881
1142
  }, [locateImage, rootRef]);
882
- useLayoutEffect(() => {
1143
+ useLayoutEffect2(() => {
883
1144
  measure();
884
1145
  let cancelled = false;
1146
+ let frame = 0;
1147
+ let rafId = 0;
885
1148
  const remeasure = () => {
886
1149
  if (cancelled) return;
887
1150
  measure();
1151
+ if (!locateImage() && frame++ < 30) {
1152
+ rafId = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
1153
+ }
888
1154
  };
889
- const id = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
1155
+ rafId = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
890
1156
  return () => {
891
1157
  cancelled = true;
892
- if (typeof cancelAnimationFrame === "function" && typeof id === "number" && id > 0) {
893
- cancelAnimationFrame(id);
1158
+ if (typeof cancelAnimationFrame === "function" && typeof rafId === "number" && rafId > 0) {
1159
+ cancelAnimationFrame(rafId);
894
1160
  }
895
1161
  };
896
1162
  }, [
897
1163
  measure,
1164
+ locateImage,
898
1165
  embed.width,
899
1166
  embed.height,
900
1167
  embed.align,
@@ -903,7 +1170,7 @@ function ImageResizeOverlay({
903
1170
  embed.offsetX,
904
1171
  embed.offsetY
905
1172
  ]);
906
- useEffect4(() => {
1173
+ useEffect5(() => {
907
1174
  const root = rootRef.current;
908
1175
  if (!root) return;
909
1176
  const onScroll = () => measure();
@@ -914,7 +1181,7 @@ function ImageResizeOverlay({
914
1181
  root.removeEventListener("scroll", onScroll);
915
1182
  };
916
1183
  }, [measure, rootRef]);
917
- useEffect4(() => {
1184
+ useEffect5(() => {
918
1185
  if (typeof ResizeObserver === "undefined") return;
919
1186
  const img = locateImage();
920
1187
  const root = rootRef.current;
@@ -927,14 +1194,36 @@ function ImageResizeOverlay({
927
1194
  if (!rect) return null;
928
1195
  const layout = embed.layout ?? "inline";
929
1196
  const movable = layout !== "inline" && onCommitMove !== void 0;
930
- return /* @__PURE__ */ jsxs5(
1197
+ return /* @__PURE__ */ jsxs7(
931
1198
  "div",
932
1199
  {
933
1200
  className: "ed-image-overlay",
934
1201
  style: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },
935
1202
  contentEditable: false,
936
1203
  children: [
937
- movable && /* @__PURE__ */ jsx5(
1204
+ isMoving && // Non-clipped drag preview (Tier 2): the overlay lives in .ed-root and
1205
+ // follows the cursor, so the image stays visible while it crosses the
1206
+ // page boundary (the real, clipped figure is hidden during the drag).
1207
+ // Inline styles only — the package does not ship CSS.
1208
+ /* @__PURE__ */ jsx7(
1209
+ "img",
1210
+ {
1211
+ src: embed.src,
1212
+ alt: "",
1213
+ "aria-hidden": true,
1214
+ draggable: false,
1215
+ style: {
1216
+ position: "absolute",
1217
+ inset: 0,
1218
+ width: "100%",
1219
+ height: "100%",
1220
+ objectFit: "fill",
1221
+ opacity: 0.8,
1222
+ pointerEvents: "none"
1223
+ }
1224
+ }
1225
+ ),
1226
+ movable && /* @__PURE__ */ jsx7(
938
1227
  MoveHandle,
939
1228
  {
940
1229
  layout,
@@ -942,10 +1231,17 @@ function ImageResizeOverlay({
942
1231
  startOffsetY: embed.offsetY ?? 0,
943
1232
  imgRef,
944
1233
  onCommit: onCommitMove,
945
- onLiveChange: measure
1234
+ onLiveChange: measure,
1235
+ rootRef,
1236
+ blockIndex,
1237
+ offset,
1238
+ cellIndex,
1239
+ onReanchor,
1240
+ onMoveStart: () => setIsMoving(true),
1241
+ onMoveEnd: () => setIsMoving(false)
946
1242
  }
947
1243
  ),
948
- /* @__PURE__ */ jsx5(
1244
+ /* @__PURE__ */ jsx7(
949
1245
  Handle,
950
1246
  {
951
1247
  corner: "nw",
@@ -956,7 +1252,7 @@ function ImageResizeOverlay({
956
1252
  onLiveChange: measure
957
1253
  }
958
1254
  ),
959
- /* @__PURE__ */ jsx5(
1255
+ /* @__PURE__ */ jsx7(
960
1256
  Handle,
961
1257
  {
962
1258
  corner: "ne",
@@ -967,7 +1263,7 @@ function ImageResizeOverlay({
967
1263
  onLiveChange: measure
968
1264
  }
969
1265
  ),
970
- /* @__PURE__ */ jsx5(
1266
+ /* @__PURE__ */ jsx7(
971
1267
  Handle,
972
1268
  {
973
1269
  corner: "sw",
@@ -978,7 +1274,7 @@ function ImageResizeOverlay({
978
1274
  onLiveChange: measure
979
1275
  }
980
1276
  ),
981
- /* @__PURE__ */ jsx5(
1277
+ /* @__PURE__ */ jsx7(
982
1278
  Handle,
983
1279
  {
984
1280
  corner: "se",
@@ -999,7 +1295,14 @@ function MoveHandle({
999
1295
  startOffsetY,
1000
1296
  imgRef,
1001
1297
  onCommit,
1002
- onLiveChange
1298
+ onLiveChange,
1299
+ rootRef,
1300
+ blockIndex,
1301
+ offset,
1302
+ cellIndex,
1303
+ onReanchor,
1304
+ onMoveStart,
1305
+ onMoveEnd
1003
1306
  }) {
1004
1307
  const dragRef = useRef4(null);
1005
1308
  const onPointerDown = (e) => {
@@ -1014,35 +1317,65 @@ function MoveHandle({
1014
1317
  liveOX: startOffsetX,
1015
1318
  liveOY: startOffsetY
1016
1319
  };
1320
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1321
+ styled.style.opacity = "0";
1322
+ onMoveStart?.();
1017
1323
  };
1018
1324
  const onPointerMove = (e) => {
1019
1325
  const d = dragRef.current;
1020
1326
  if (!d || !imgRef.current) return;
1021
1327
  const dx = e.clientX - d.startX;
1022
1328
  const dy = e.clientY - d.startY;
1023
- const img = imgRef.current;
1329
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1024
1330
  let nox = startOffsetX;
1025
1331
  let noy = startOffsetY;
1026
1332
  if (layout === "wrap-left") {
1027
1333
  nox = Math.max(8, startOffsetX + dx);
1028
1334
  noy = Math.max(0, startOffsetY + dy);
1029
- img.style.marginRight = `${nox}px`;
1030
- img.style.marginTop = `${noy}px`;
1335
+ styled.style.marginRight = `${nox}px`;
1336
+ styled.style.marginTop = `${noy}px`;
1031
1337
  } else if (layout === "wrap-right") {
1032
1338
  nox = Math.max(8, startOffsetX - dx);
1033
1339
  noy = Math.max(0, startOffsetY + dy);
1034
- img.style.marginLeft = `${nox}px`;
1035
- img.style.marginTop = `${noy}px`;
1340
+ styled.style.marginLeft = `${nox}px`;
1341
+ styled.style.marginTop = `${noy}px`;
1036
1342
  } else if (layout === "behind" || layout === "front") {
1037
1343
  nox = startOffsetX + dx;
1038
1344
  noy = startOffsetY + dy;
1039
- img.style.left = `${nox}px`;
1040
- img.style.top = `${noy}px`;
1345
+ styled.style.left = `${nox}px`;
1346
+ styled.style.top = `${noy}px`;
1041
1347
  }
1042
1348
  d.liveOX = nox;
1043
1349
  d.liveOY = noy;
1044
1350
  onLiveChange();
1045
1351
  };
1352
+ const clampOffsetToFragment = (frag, oy) => {
1353
+ const img = imgRef.current;
1354
+ if (!img) return oy;
1355
+ const page = frag.closest(".ed-page");
1356
+ const content = page?.querySelector(".ed-page-content");
1357
+ if (!content) return oy;
1358
+ const fragRect = frag.getBoundingClientRect();
1359
+ const contentRect = content.getBoundingClientRect();
1360
+ const imgH = img.getBoundingClientRect().height;
1361
+ const minLocalTop = contentRect.top - fragRect.top;
1362
+ const maxLocalTop = contentRect.bottom - fragRect.top - imgH;
1363
+ return Math.round(Math.max(minLocalTop, Math.min(oy, maxLocalTop)));
1364
+ };
1365
+ const clampedCommit = (ox, oy) => {
1366
+ const img = imgRef.current;
1367
+ const root = rootRef.current;
1368
+ if (!img || !root || layout !== "behind" && layout !== "front") {
1369
+ onCommit(ox, oy);
1370
+ return;
1371
+ }
1372
+ const frag = getFragmentForOffset(root, blockIndex, offset);
1373
+ if (!frag) {
1374
+ onCommit(ox, oy);
1375
+ return;
1376
+ }
1377
+ onCommit(ox, clampOffsetToFragment(frag, oy));
1378
+ };
1046
1379
  const finish = (e) => {
1047
1380
  const d = dragRef.current;
1048
1381
  if (!d) return;
@@ -1051,9 +1384,77 @@ function MoveHandle({
1051
1384
  e.target.releasePointerCapture(e.pointerId);
1052
1385
  } catch {
1053
1386
  }
1054
- onCommit(Math.round(d.liveOX), Math.round(d.liveOY));
1387
+ if (imgRef.current) {
1388
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1389
+ styled.style.opacity = "";
1390
+ }
1391
+ onMoveEnd?.();
1392
+ const img = imgRef.current;
1393
+ const root = rootRef.current;
1394
+ const liveOX = Math.round(d.liveOX);
1395
+ const liveOY = Math.round(d.liveOY);
1396
+ if (!img || !root || onReanchor === void 0 || cellIndex != null) {
1397
+ clampedCommit(liveOX, liveOY);
1398
+ return;
1399
+ }
1400
+ const imgRect = img.getBoundingClientRect();
1401
+ const centerY = imgRect.top + imgRect.height / 2;
1402
+ const pages = Array.from(root.querySelectorAll(".ed-page"));
1403
+ let destPage = null;
1404
+ let bestPageDist = Infinity;
1405
+ for (const pg of pages) {
1406
+ const r = pg.getBoundingClientRect();
1407
+ if (centerY >= r.top && centerY <= r.bottom) {
1408
+ destPage = pg;
1409
+ break;
1410
+ }
1411
+ const dist = centerY < r.top ? r.top - centerY : centerY - r.bottom;
1412
+ if (dist < bestPageDist) {
1413
+ bestPageDist = dist;
1414
+ destPage = pg;
1415
+ }
1416
+ }
1417
+ const currentFrag = getFragmentForOffset(root, blockIndex, offset);
1418
+ const currentPage = currentFrag?.closest(".ed-page") ?? null;
1419
+ if (destPage == null || destPage === currentPage) {
1420
+ clampedCommit(liveOX, liveOY);
1421
+ return;
1422
+ }
1423
+ const blocksOnPage = Array.from(
1424
+ destPage.querySelectorAll("[data-block-index]")
1425
+ );
1426
+ let destFrag = null;
1427
+ let bestBlockDist = Infinity;
1428
+ for (const b of blocksOnPage) {
1429
+ const dist = Math.abs(b.getBoundingClientRect().top - imgRect.top);
1430
+ if (dist < bestBlockDist) {
1431
+ bestBlockDist = dist;
1432
+ destFrag = b;
1433
+ }
1434
+ }
1435
+ if (!destFrag) {
1436
+ clampedCommit(liveOX, liveOY);
1437
+ return;
1438
+ }
1439
+ const destBlockIndex = findBlockIndex(destFrag, root);
1440
+ if (destBlockIndex == null) {
1441
+ clampedCommit(liveOX, liveOY);
1442
+ return;
1443
+ }
1444
+ const destOffset = destFrag.dataset.fragmentStart ? Number.parseInt(destFrag.dataset.fragmentStart, 10) || 0 : 0;
1445
+ const fragRect = destFrag.getBoundingClientRect();
1446
+ const newOffsetX = Math.round(imgRect.left - fragRect.left);
1447
+ const newOffsetY = clampOffsetToFragment(
1448
+ destFrag,
1449
+ Math.round(imgRect.top - fragRect.top)
1450
+ );
1451
+ onReanchor(
1452
+ { blockIndex: destBlockIndex, offset: destOffset, cellIndex: void 0 },
1453
+ newOffsetX,
1454
+ newOffsetY
1455
+ );
1055
1456
  };
1056
- return /* @__PURE__ */ jsx5(
1457
+ return /* @__PURE__ */ jsx7(
1057
1458
  "div",
1058
1459
  {
1059
1460
  className: "ed-image-move",
@@ -1116,7 +1517,7 @@ function Handle({
1116
1517
  }
1117
1518
  onCommit(Math.round(d.liveW), Math.round(d.liveH));
1118
1519
  };
1119
- return /* @__PURE__ */ jsx5(
1520
+ return /* @__PURE__ */ jsx7(
1120
1521
  "div",
1121
1522
  {
1122
1523
  className: `ed-image-handle ${corner}`,
@@ -1128,17 +1529,194 @@ function Handle({
1128
1529
  );
1129
1530
  }
1130
1531
 
1532
+ // src/RemoteCursorsOverlay.tsx
1533
+ import {
1534
+ useCallback as useCallback3,
1535
+ useEffect as useEffect6,
1536
+ useRef as useRef5,
1537
+ useState as useState6
1538
+ } from "react";
1539
+ import {
1540
+ decodeSelection
1541
+ } from "@sofereditor/core";
1542
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1543
+ var DEFAULT_COLOR = "#3b82f6";
1544
+ function RemoteCursorsOverlay({
1545
+ rootRef,
1546
+ doc,
1547
+ awareness,
1548
+ revision
1549
+ }) {
1550
+ const [views, setViews] = useState6([]);
1551
+ const rafRef = useRef5(null);
1552
+ const measure = useCallback3(() => {
1553
+ const root = rootRef.current;
1554
+ if (!root) {
1555
+ setViews((prev) => prev.length === 0 ? prev : []);
1556
+ return;
1557
+ }
1558
+ const rr = root.getBoundingClientRect();
1559
+ const out = [];
1560
+ awareness.getStates().forEach((state, clientId) => {
1561
+ if (clientId === awareness.clientID) return;
1562
+ const s = state;
1563
+ if (!s.cursor) return;
1564
+ const sel = decodeSelection(doc, s.cursor);
1565
+ if (!sel) return;
1566
+ const color = s.user?.color || DEFAULT_COLOR;
1567
+ const name = s.user?.name || "An\xF4nimo";
1568
+ const focus = locatePoint(root, sel.focus);
1569
+ let caret = null;
1570
+ if (focus) {
1571
+ try {
1572
+ const range = document.createRange();
1573
+ range.setStart(focus.node, focus.offset);
1574
+ range.collapse(true);
1575
+ let rect = range.getBoundingClientRect();
1576
+ if (rect.height === 0 && focus.node.nodeType === Node.ELEMENT_NODE) {
1577
+ rect = focus.node.getBoundingClientRect();
1578
+ }
1579
+ caret = {
1580
+ top: rect.top - rr.top + root.scrollTop,
1581
+ left: rect.left - rr.left + root.scrollLeft,
1582
+ height: rect.height || 18
1583
+ };
1584
+ } catch {
1585
+ }
1586
+ }
1587
+ const collapsed = sel.anchor.blockIndex === sel.focus.blockIndex && (sel.anchor.cellIndex ?? -1) === (sel.focus.cellIndex ?? -1) && sel.anchor.offset === sel.focus.offset;
1588
+ const selection = [];
1589
+ if (!collapsed && focus) {
1590
+ const anchor = locatePoint(root, sel.anchor);
1591
+ if (anchor) {
1592
+ try {
1593
+ const r = document.createRange();
1594
+ r.setStart(anchor.node, anchor.offset);
1595
+ r.setEnd(focus.node, focus.offset);
1596
+ if (r.collapsed) {
1597
+ r.setStart(focus.node, focus.offset);
1598
+ r.setEnd(anchor.node, anchor.offset);
1599
+ }
1600
+ for (const cr of Array.from(r.getClientRects())) {
1601
+ if (cr.width === 0 || cr.height === 0) continue;
1602
+ selection.push({
1603
+ top: cr.top - rr.top + root.scrollTop,
1604
+ left: cr.left - rr.left + root.scrollLeft,
1605
+ width: cr.width,
1606
+ height: cr.height
1607
+ });
1608
+ }
1609
+ } catch {
1610
+ }
1611
+ }
1612
+ }
1613
+ out.push({ clientId, name, color, caret, selection });
1614
+ });
1615
+ setViews(out);
1616
+ }, [rootRef, doc, awareness]);
1617
+ const scheduleMeasure = useCallback3(() => {
1618
+ if (rafRef.current != null) return;
1619
+ const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(() => cb(0), 16);
1620
+ rafRef.current = raf(() => {
1621
+ rafRef.current = null;
1622
+ measure();
1623
+ });
1624
+ }, [measure]);
1625
+ useEffect6(() => {
1626
+ const onChange = () => scheduleMeasure();
1627
+ awareness.on("change", onChange);
1628
+ scheduleMeasure();
1629
+ return () => awareness.off("change", onChange);
1630
+ }, [awareness, scheduleMeasure]);
1631
+ useEffect6(() => {
1632
+ scheduleMeasure();
1633
+ }, [revision, scheduleMeasure]);
1634
+ useEffect6(() => {
1635
+ const root = rootRef.current;
1636
+ if (!root) return;
1637
+ const onScroll = () => scheduleMeasure();
1638
+ root.addEventListener("scroll", onScroll, { passive: true });
1639
+ let ro = null;
1640
+ if (typeof ResizeObserver !== "undefined") {
1641
+ ro = new ResizeObserver(() => scheduleMeasure());
1642
+ ro.observe(root);
1643
+ }
1644
+ return () => {
1645
+ root.removeEventListener("scroll", onScroll);
1646
+ ro?.disconnect();
1647
+ };
1648
+ }, [rootRef, scheduleMeasure]);
1649
+ if (views.length === 0) return null;
1650
+ const layer = {
1651
+ position: "absolute",
1652
+ inset: 0,
1653
+ pointerEvents: "none",
1654
+ zIndex: 6
1655
+ };
1656
+ return /* @__PURE__ */ jsx8("div", { className: "ed-remote-cursors", "aria-hidden": true, style: layer, children: views.map((v) => /* @__PURE__ */ jsxs8("div", { children: [
1657
+ v.selection.map((r, i) => /* @__PURE__ */ jsx8(
1658
+ "div",
1659
+ {
1660
+ style: {
1661
+ position: "absolute",
1662
+ top: r.top,
1663
+ left: r.left,
1664
+ width: r.width,
1665
+ height: r.height,
1666
+ background: v.color,
1667
+ opacity: 0.22,
1668
+ borderRadius: 2
1669
+ }
1670
+ },
1671
+ i
1672
+ )),
1673
+ v.caret && /* @__PURE__ */ jsx8(
1674
+ "div",
1675
+ {
1676
+ style: {
1677
+ position: "absolute",
1678
+ top: v.caret.top,
1679
+ left: v.caret.left,
1680
+ height: v.caret.height,
1681
+ width: 2,
1682
+ background: v.color
1683
+ },
1684
+ children: /* @__PURE__ */ jsx8(
1685
+ "span",
1686
+ {
1687
+ style: {
1688
+ position: "absolute",
1689
+ top: -15,
1690
+ left: -1,
1691
+ fontSize: 10,
1692
+ lineHeight: "14px",
1693
+ padding: "0 4px",
1694
+ borderRadius: 3,
1695
+ color: "#fff",
1696
+ background: v.color,
1697
+ whiteSpace: "nowrap",
1698
+ fontFamily: "system-ui, sans-serif",
1699
+ userSelect: "none"
1700
+ },
1701
+ children: v.name
1702
+ }
1703
+ )
1704
+ }
1705
+ )
1706
+ ] }, v.clientId)) });
1707
+ }
1708
+
1131
1709
  // src/NodeView.tsx
1132
- import { useMemo as useMemo2, useRef as useRef6 } from "react";
1710
+ import { useMemo as useMemo2, useRef as useRef7 } from "react";
1133
1711
  import { tableRectSelection } from "@sofereditor/core";
1134
1712
 
1135
1713
  // src/renderInline.tsx
1136
- import { Fragment, memo } from "react";
1714
+ import { Fragment as Fragment3, memo } from "react";
1137
1715
  import { isImageEmbed } from "@sofereditor/core";
1138
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1716
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1139
1717
  function renderInline(delta, keyPrefix) {
1140
1718
  if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
1141
- return /* @__PURE__ */ jsx6("br", { "data-empty": "true" });
1719
+ return /* @__PURE__ */ jsx9("br", { "data-empty": "true" });
1142
1720
  }
1143
1721
  let offset = 0;
1144
1722
  const wrapAnchors = [];
@@ -1148,7 +1726,7 @@ function renderInline(delta, keyPrefix) {
1148
1726
  const text = op.insert;
1149
1727
  if (text.length === 0) continue;
1150
1728
  const key = `${keyPrefix}-${offset}`;
1151
- body.push(/* @__PURE__ */ jsx6(Fragment, { children: wrap(text, op.attributes) }, key));
1729
+ body.push(/* @__PURE__ */ jsx9(Fragment3, { children: wrap(text, op.attributes) }, key));
1152
1730
  offset += text.length;
1153
1731
  } else if (isImageEmbed(op.insert)) {
1154
1732
  const key = `${keyPrefix}-${offset}`;
@@ -1156,10 +1734,10 @@ function renderInline(delta, keyPrefix) {
1156
1734
  const commentMarkId = op.attributes?.comment?.markId;
1157
1735
  if (layout === "wrap-left" || layout === "wrap-right") {
1158
1736
  wrapAnchors.push(
1159
- /* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1737
+ /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1160
1738
  );
1161
1739
  body.push(
1162
- /* @__PURE__ */ jsx6(
1740
+ /* @__PURE__ */ jsx9(
1163
1741
  "span",
1164
1742
  {
1165
1743
  "data-embed-phantom": "true",
@@ -1171,10 +1749,10 @@ function renderInline(delta, keyPrefix) {
1171
1749
  )
1172
1750
  );
1173
1751
  } else {
1174
- const imgNode = /* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset }, key);
1752
+ const imgNode = /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset }, key);
1175
1753
  if (commentMarkId) {
1176
1754
  body.push(
1177
- /* @__PURE__ */ jsx6("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1755
+ /* @__PURE__ */ jsx9("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1178
1756
  );
1179
1757
  } else {
1180
1758
  body.push(imgNode);
@@ -1185,7 +1763,7 @@ function renderInline(delta, keyPrefix) {
1185
1763
  offset += 1;
1186
1764
  }
1187
1765
  }
1188
- if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ jsx6("br", { "data-empty": "true" });
1766
+ if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ jsx9("br", { "data-empty": "true" });
1189
1767
  return [...wrapAnchors, ...body];
1190
1768
  }
1191
1769
  var PHANTOM_STYLE = {
@@ -1195,6 +1773,11 @@ var PHANTOM_STYLE = {
1195
1773
  overflow: "hidden",
1196
1774
  verticalAlign: "baseline"
1197
1775
  };
1776
+ var LINK_STYLE = {
1777
+ color: "#2563eb",
1778
+ textDecoration: "underline",
1779
+ cursor: "text"
1780
+ };
1198
1781
  function imageEmbedPropsEqual(a, b) {
1199
1782
  if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;
1200
1783
  const x = a.embed;
@@ -1260,8 +1843,12 @@ function ImageEmbedViewImpl({
1260
1843
  };
1261
1844
  break;
1262
1845
  }
1263
- const imgStyle = hasCaption ? { width: embed.width, height: embed.height, display: "block" } : outerStyle;
1264
- const img = /* @__PURE__ */ jsx6(
1846
+ const imgStyle = {
1847
+ width: embed.width,
1848
+ height: embed.height,
1849
+ display: "block"
1850
+ };
1851
+ const img = /* @__PURE__ */ jsx9(
1265
1852
  "img",
1266
1853
  {
1267
1854
  src: embed.src,
@@ -1280,19 +1867,18 @@ function ImageEmbedViewImpl({
1280
1867
  alt: ""
1281
1868
  }
1282
1869
  );
1283
- if (!hasCaption) return img;
1284
1870
  const captionAlign = embed.captionAlign ?? "center";
1285
- return /* @__PURE__ */ jsxs6(
1871
+ return /* @__PURE__ */ jsxs9(
1286
1872
  "figure",
1287
1873
  {
1288
1874
  className: "ed-figure",
1289
1875
  contentEditable: false,
1290
- "data-embed-figure": "true",
1876
+ "data-embed-figure": hasCaption ? "true" : void 0,
1291
1877
  "data-embed-layout": layout,
1292
1878
  style: outerStyle,
1293
1879
  children: [
1294
1880
  img,
1295
- /* @__PURE__ */ jsx6(
1881
+ hasCaption && /* @__PURE__ */ jsx9(
1296
1882
  "figcaption",
1297
1883
  {
1298
1884
  className: "ed-figcaption",
@@ -1308,34 +1894,38 @@ function ImageEmbedViewImpl({
1308
1894
  function wrap(text, attrs) {
1309
1895
  let node = text;
1310
1896
  if (!attrs) return node;
1311
- if (attrs.bold) node = /* @__PURE__ */ jsx6("strong", { children: node });
1312
- if (attrs.italic) node = /* @__PURE__ */ jsx6("em", { children: node });
1313
- if (attrs.underline) node = /* @__PURE__ */ jsx6("u", { children: node });
1314
- if (attrs.strike) node = /* @__PURE__ */ jsx6("s", { children: node });
1897
+ if (attrs.bold) node = /* @__PURE__ */ jsx9("strong", { children: node });
1898
+ if (attrs.italic) node = /* @__PURE__ */ jsx9("em", { children: node });
1899
+ if (attrs.underline) node = /* @__PURE__ */ jsx9("u", { children: node });
1900
+ if (attrs.strike) node = /* @__PURE__ */ jsx9("s", { children: node });
1315
1901
  const styleParts = {};
1316
1902
  if (attrs.color) styleParts.color = attrs.color;
1317
1903
  if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;
1318
1904
  if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;
1319
1905
  if (Object.keys(styleParts).length > 0) {
1320
- node = /* @__PURE__ */ jsx6("span", { style: styleParts, children: node });
1906
+ node = /* @__PURE__ */ jsx9("span", { style: styleParts, children: node });
1321
1907
  }
1322
1908
  if (attrs.link?.href) {
1323
- node = /* @__PURE__ */ jsx6(
1909
+ node = /* @__PURE__ */ jsx9(
1324
1910
  "a",
1325
1911
  {
1326
1912
  href: attrs.link.href,
1327
1913
  title: attrs.link.title,
1328
1914
  rel: "noopener noreferrer",
1329
1915
  target: "_blank",
1916
+ style: LINK_STYLE,
1330
1917
  onClick: (e) => {
1331
- if (!(e.metaKey || e.ctrlKey)) e.preventDefault();
1918
+ e.preventDefault();
1919
+ if (hasOpenModifier(e) && attrs.link?.href) {
1920
+ window.open(attrs.link.href, "_blank", "noopener,noreferrer");
1921
+ }
1332
1922
  },
1333
1923
  children: node
1334
1924
  }
1335
1925
  );
1336
1926
  }
1337
1927
  if (attrs.comment?.markId) {
1338
- node = /* @__PURE__ */ jsx6("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
1928
+ node = /* @__PURE__ */ jsx9("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
1339
1929
  }
1340
1930
  return node;
1341
1931
  }
@@ -1380,19 +1970,19 @@ function sliceDelta(delta, start, end) {
1380
1970
 
1381
1971
  // src/TableResizeOverlay.tsx
1382
1972
  import {
1383
- useCallback as useCallback2,
1384
- useEffect as useEffect5,
1385
- useLayoutEffect as useLayoutEffect2,
1386
- useRef as useRef5,
1387
- useState as useState5
1973
+ useCallback as useCallback4,
1974
+ useEffect as useEffect7,
1975
+ useLayoutEffect as useLayoutEffect3,
1976
+ useRef as useRef6,
1977
+ useState as useState7
1388
1978
  } from "react";
1389
- import { Fragment as Fragment2, jsx as jsx7 } from "react/jsx-runtime";
1979
+ import { Fragment as Fragment4, jsx as jsx10 } from "react/jsx-runtime";
1390
1980
  function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1391
1981
  const editor = useEditorContext();
1392
- const [positions, setPositions] = useState5(null);
1393
- const [layout, setLayout] = useState5(null);
1394
- const draggingRef = useRef5(null);
1395
- const measure = useCallback2(() => {
1982
+ const [positions, setPositions] = useState7(null);
1983
+ const [layout, setLayout] = useState7(null);
1984
+ const draggingRef = useRef6(null);
1985
+ const measure = useCallback4(() => {
1396
1986
  const table = tableRef.current;
1397
1987
  if (!table) return;
1398
1988
  const tableRect = table.getBoundingClientRect();
@@ -1422,17 +2012,17 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1422
2012
  }
1423
2013
  setLayout({ rights, height: tableRect.height });
1424
2014
  }, [cols, tableRef]);
1425
- useLayoutEffect2(() => {
2015
+ useLayoutEffect3(() => {
1426
2016
  measure();
1427
2017
  }, [measure]);
1428
- useEffect5(() => {
2018
+ useEffect7(() => {
1429
2019
  const table = tableRef.current;
1430
2020
  if (!table) return;
1431
2021
  const ro = new ResizeObserver(() => measure());
1432
2022
  ro.observe(table);
1433
2023
  return () => ro.disconnect();
1434
2024
  }, [measure, tableRef]);
1435
- const onPointerDown = useCallback2(
2025
+ const onPointerDown = useCallback4(
1436
2026
  (col) => (e) => {
1437
2027
  e.preventDefault();
1438
2028
  e.stopPropagation();
@@ -1446,7 +2036,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1446
2036
  },
1447
2037
  [layout, tableRef]
1448
2038
  );
1449
- const onPointerMove = useCallback2(
2039
+ const onPointerMove = useCallback4(
1450
2040
  (e) => {
1451
2041
  const d = draggingRef.current;
1452
2042
  if (!d) return;
@@ -1456,7 +2046,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1456
2046
  },
1457
2047
  [blockIndex, editor]
1458
2048
  );
1459
- const onPointerUp = useCallback2((e) => {
2049
+ const onPointerUp = useCallback4((e) => {
1460
2050
  draggingRef.current = null;
1461
2051
  setPositions(null);
1462
2052
  try {
@@ -1475,7 +2065,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1475
2065
  zIndex: 5
1476
2066
  });
1477
2067
  void positions;
1478
- return /* @__PURE__ */ jsx7(Fragment2, { children: layout.rights.map((x, c) => /* @__PURE__ */ jsx7(
2068
+ return /* @__PURE__ */ jsx10(Fragment4, { children: layout.rights.map((x, c) => /* @__PURE__ */ jsx10(
1479
2069
  "div",
1480
2070
  {
1481
2071
  contentEditable: false,
@@ -1492,10 +2082,10 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1492
2082
  }
1493
2083
 
1494
2084
  // src/NodeView.tsx
1495
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2085
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1496
2086
  function NodeView({ block, index, children, fragment, tableFragment }) {
1497
2087
  if (block.type === "table") {
1498
- return /* @__PURE__ */ jsx8(TableView, { block, index, tableFragment });
2088
+ return /* @__PURE__ */ jsx11(TableView, { block, index, tableFragment });
1499
2089
  }
1500
2090
  const inline = fragment ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index) : renderInline(block.delta, index);
1501
2091
  const common = commonBlockProps(block.attrs, index, block.type, fragment);
@@ -1503,7 +2093,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1503
2093
  case "heading": {
1504
2094
  const level = clampLevel(block.attrs.level);
1505
2095
  const Tag = `h${level}`;
1506
- return /* @__PURE__ */ jsx8(
2096
+ return /* @__PURE__ */ jsx11(
1507
2097
  Tag,
1508
2098
  {
1509
2099
  ...common,
@@ -1513,7 +2103,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1513
2103
  );
1514
2104
  }
1515
2105
  case "blockquote":
1516
- return /* @__PURE__ */ jsx8(
2106
+ return /* @__PURE__ */ jsx11(
1517
2107
  "blockquote",
1518
2108
  {
1519
2109
  ...common,
@@ -1522,18 +2112,18 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1522
2112
  }
1523
2113
  );
1524
2114
  case "codeBlock":
1525
- return /* @__PURE__ */ jsx8(
2115
+ return /* @__PURE__ */ jsx11(
1526
2116
  "pre",
1527
2117
  {
1528
2118
  ...common,
1529
2119
  "data-language": block.attrs.language ?? void 0,
1530
2120
  className: `ed-block ed-codeblock${alignClass(block.attrs.align)}`,
1531
- children: /* @__PURE__ */ jsx8("code", { children: inline })
2121
+ children: /* @__PURE__ */ jsx11("code", { children: inline })
1532
2122
  }
1533
2123
  );
1534
2124
  case "listItem": {
1535
2125
  const level = clampListLevel(block.attrs.listLevel);
1536
- return /* @__PURE__ */ jsxs7(
2126
+ return /* @__PURE__ */ jsxs10(
1537
2127
  "li",
1538
2128
  {
1539
2129
  ...common,
@@ -1549,7 +2139,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1549
2139
  }
1550
2140
  case "paragraph":
1551
2141
  default:
1552
- return /* @__PURE__ */ jsx8(
2142
+ return /* @__PURE__ */ jsx11(
1553
2143
  "div",
1554
2144
  {
1555
2145
  ...common,
@@ -1594,7 +2184,7 @@ function TableView({ block, index, tableFragment }) {
1594
2184
  const cols = clampPositive(block.attrs.cols);
1595
2185
  const cells = block.cells ?? [];
1596
2186
  const widths = readColWidths(block.attrs.colWidths, cols);
1597
- const tableRef = useRef6(null);
2187
+ const tableRef = useRef7(null);
1598
2188
  const rowStart = tableFragment?.rowStart ?? 0;
1599
2189
  const rowEnd = tableFragment?.rowEnd ?? rows;
1600
2190
  const isFirstFragment = !tableFragment || tableFragment.index === 0;
@@ -1604,8 +2194,8 @@ function TableView({ block, index, tableFragment }) {
1604
2194
  if (editor.selection.focus.blockIndex !== index) return null;
1605
2195
  return tableRectSelection(editor.doc, editor.selection);
1606
2196
  }, [editor.doc, editor.selection, index]);
1607
- return /* @__PURE__ */ jsxs7("div", { className: "ed-table-wrap", children: [
1608
- /* @__PURE__ */ jsxs7(
2197
+ return /* @__PURE__ */ jsxs10("div", { className: "ed-table-wrap", children: [
2198
+ /* @__PURE__ */ jsxs10(
1609
2199
  "table",
1610
2200
  {
1611
2201
  ref: tableRef,
@@ -1613,10 +2203,10 @@ function TableView({ block, index, tableFragment }) {
1613
2203
  "data-block-type": "table",
1614
2204
  className: "ed-block ed-table",
1615
2205
  children: [
1616
- widths && /* @__PURE__ */ jsx8("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ jsx8("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
1617
- /* @__PURE__ */ jsx8("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
2206
+ widths && /* @__PURE__ */ jsx11("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ jsx11("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
2207
+ /* @__PURE__ */ jsx11("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
1618
2208
  const r = rowStart + i;
1619
- return /* @__PURE__ */ jsx8("tr", { "data-cell-row": r, children: Array.from({ length: cols }, (_2, c) => {
2209
+ return /* @__PURE__ */ jsx11("tr", { "data-cell-row": r, children: Array.from({ length: cols }, (_2, c) => {
1620
2210
  const flat = r * cols + c;
1621
2211
  const cell = cells[flat];
1622
2212
  if (cell?.attrs.covered === true) return null;
@@ -1624,7 +2214,7 @@ function TableView({ block, index, tableFragment }) {
1624
2214
  const colspan = spanAttr(cell?.attrs.colspan);
1625
2215
  const delta = cell?.delta ?? [];
1626
2216
  const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
1627
- return /* @__PURE__ */ jsx8(
2217
+ return /* @__PURE__ */ jsx11(
1628
2218
  "td",
1629
2219
  {
1630
2220
  "data-cell-index": flat,
@@ -1634,6 +2224,7 @@ function TableView({ block, index, tableFragment }) {
1634
2224
  "data-cell-colspan": colspan,
1635
2225
  rowSpan: rowspan > 1 ? rowspan : void 0,
1636
2226
  colSpan: colspan > 1 ? colspan : void 0,
2227
+ style: cell?.attrs.align ? { textAlign: cell.attrs.align } : void 0,
1637
2228
  className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
1638
2229
  children: renderInline(delta, `t${index}-c${flat}`)
1639
2230
  },
@@ -1644,7 +2235,7 @@ function TableView({ block, index, tableFragment }) {
1644
2235
  ]
1645
2236
  }
1646
2237
  ),
1647
- isFirstFragment && /* @__PURE__ */ jsx8(TableResizeOverlay, { tableRef, blockIndex: index, cols })
2238
+ isFirstFragment && /* @__PURE__ */ jsx11(TableResizeOverlay, { tableRef, blockIndex: index, cols })
1648
2239
  ] });
1649
2240
  }
1650
2241
  function readColWidths(raw, cols) {
@@ -1666,7 +2257,7 @@ function clampPositive(n) {
1666
2257
  }
1667
2258
 
1668
2259
  // src/usePagination.ts
1669
- import { useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState6 } from "react";
2260
+ import { useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState8 } from "react";
1670
2261
  var A4_PAGE = {
1671
2262
  width: 794,
1672
2263
  height: 1123,
@@ -1692,10 +2283,10 @@ function defaultPageLayout(topLevelCount) {
1692
2283
  };
1693
2284
  }
1694
2285
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1695
- const [phase, setPhase] = useState6("measure");
1696
- const [layout, setLayout] = useState6(() => defaultPageLayout(topLevelCount));
1697
- const lastDepsRef = useRef7(null);
1698
- useLayoutEffect3(() => {
2286
+ const [phase, setPhase] = useState8("measure");
2287
+ const [layout, setLayout] = useState8(() => defaultPageLayout(topLevelCount));
2288
+ const lastDepsRef = useRef8(null);
2289
+ useLayoutEffect4(() => {
1699
2290
  const currentDeps = [...deps, topLevelCount, geometry];
1700
2291
  if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
1701
2292
  return;
@@ -1707,7 +2298,7 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1707
2298
  });
1708
2299
  setPhase("measure");
1709
2300
  });
1710
- useLayoutEffect3(() => {
2301
+ useLayoutEffect4(() => {
1711
2302
  if (phase !== "measure") return;
1712
2303
  const root = rootRef.current;
1713
2304
  if (!root) return;
@@ -2179,17 +2770,17 @@ function layoutsDeepEqual(a, b) {
2179
2770
  }
2180
2771
 
2181
2772
  // src/useEditor.ts
2182
- import { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef9, useState as useState7 } from "react";
2773
+ import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo3, useRef as useRef10, useState as useState9 } from "react";
2183
2774
 
2184
2775
  // src/usePageSettings.ts
2185
- import { useCallback as useCallback3, useRef as useRef8, useSyncExternalStore } from "react";
2776
+ import { useCallback as useCallback5, useRef as useRef9, useSyncExternalStore } from "react";
2186
2777
  function usePageSettings(doc) {
2187
- const cacheRef = useRef8(null);
2188
- const subscribe = useCallback3(
2778
+ const cacheRef = useRef9(null);
2779
+ const subscribe = useCallback5(
2189
2780
  (notify) => doc.observePageSettings(notify),
2190
2781
  [doc]
2191
2782
  );
2192
- const getSnapshot = useCallback3(() => {
2783
+ const getSnapshot = useCallback5(() => {
2193
2784
  const next = doc.getPageSettings();
2194
2785
  const prev = cacheRef.current;
2195
2786
  if (prev && shallowEqual(prev, next)) return prev;
@@ -2215,6 +2806,7 @@ import {
2215
2806
  mergeDown as cmdMergeDown,
2216
2807
  mergeRight as cmdMergeRight,
2217
2808
  mergeSelection as cmdMergeSelection,
2809
+ moveEmbedAnchor as cmdMoveEmbedAnchor,
2218
2810
  setColumnWidth as cmdSetColumnWidth,
2219
2811
  setImageAttrs as cmdSetImageAttrs,
2220
2812
  splitCell as cmdSplitCell,
@@ -2231,6 +2823,7 @@ import {
2231
2823
  orderedRange,
2232
2824
  removeMark as cmdRemoveMark,
2233
2825
  setBlockAttr as cmdSetBlockAttr,
2826
+ setCellAttr as cmdSetCellAttr,
2234
2827
  setBlockType as cmdSetBlockType,
2235
2828
  setMark as cmdSetMark,
2236
2829
  splitListItem as cmdSplitListItem,
@@ -2242,19 +2835,19 @@ var MAX_INSERT_WIDTH = 600;
2242
2835
  function useEditor(opts = {}) {
2243
2836
  const doc = useMemo3(() => opts.document ?? new EditorDocument(), [opts.document]);
2244
2837
  const history = useMemo3(() => new EditorHistory(doc), [doc]);
2245
- const [snapshot, setSnapshot] = useState7(() => doc.toJSON());
2246
- const [selection, setSelectionState] = useState7(
2838
+ const [snapshot, setSnapshot] = useState9(() => doc.toJSON());
2839
+ const [selection, setSelectionState] = useState9(
2247
2840
  () => collapsedSelection({ blockIndex: 0, offset: 0 })
2248
2841
  );
2249
- const selectionRef = useRef9(selection);
2842
+ const selectionRef = useRef10(selection);
2250
2843
  selectionRef.current = selection;
2251
- const pendingMarksRef = useRef9({});
2252
- const [pendingMarks, setPendingMarksState] = useState7({});
2253
- const setPendingMarks = useCallback4((next) => {
2844
+ const pendingMarksRef = useRef10({});
2845
+ const [pendingMarks, setPendingMarksState] = useState9({});
2846
+ const setPendingMarks = useCallback6((next) => {
2254
2847
  pendingMarksRef.current = next;
2255
2848
  setPendingMarksState(next);
2256
2849
  }, []);
2257
- useEffect6(() => {
2850
+ useEffect8(() => {
2258
2851
  let scheduled = false;
2259
2852
  let cancelled = false;
2260
2853
  let frame = 0;
@@ -2281,8 +2874,8 @@ function useEditor(opts = {}) {
2281
2874
  doc.ydoc.off("afterTransaction", schedule);
2282
2875
  };
2283
2876
  }, [doc]);
2284
- const getSelection = useCallback4(() => selectionRef.current, []);
2285
- const setSelection = useCallback4(
2877
+ const getSelection = useCallback6(() => selectionRef.current, []);
2878
+ const setSelection = useCallback6(
2286
2879
  (sel) => {
2287
2880
  const prev = selectionRef.current;
2288
2881
  selectionRef.current = sel;
@@ -2297,16 +2890,16 @@ function useEditor(opts = {}) {
2297
2890
  },
2298
2891
  []
2299
2892
  );
2300
- const ctxRef = useRef9({ doc, getSelection, setSelection });
2893
+ const ctxRef = useRef10({ doc, getSelection, setSelection });
2301
2894
  ctxRef.current = { doc, getSelection, setSelection };
2302
- const consumePendingMarks = useCallback4(() => {
2895
+ const consumePendingMarks = useCallback6(() => {
2303
2896
  const current = pendingMarksRef.current;
2304
2897
  if (Object.keys(current).length === 0) return void 0;
2305
2898
  pendingMarksRef.current = {};
2306
2899
  setPendingMarksState({});
2307
2900
  return current;
2308
2901
  }, []);
2309
- const isMarkActive = useCallback4(
2902
+ const isMarkActive = useCallback6(
2310
2903
  (name, value) => {
2311
2904
  const sel = selectionRef.current;
2312
2905
  const { start, end } = orderedRange(sel);
@@ -2337,7 +2930,7 @@ function useEditor(opts = {}) {
2337
2930
  },
2338
2931
  [doc]
2339
2932
  );
2340
- const getActiveMarks = useCallback4(() => {
2933
+ const getActiveMarks = useCallback6(() => {
2341
2934
  const sel = selectionRef.current;
2342
2935
  const { start, end } = orderedRange(sel);
2343
2936
  if (start.blockIndex !== end.blockIndex) {
@@ -2351,7 +2944,7 @@ function useEditor(opts = {}) {
2351
2944
  }
2352
2945
  return getMarksInRange(yText, start.offset, end.offset);
2353
2946
  }, [doc]);
2354
- const toggleMark = useCallback4(
2947
+ const toggleMark = useCallback6(
2355
2948
  (name, value) => {
2356
2949
  const sel = selectionRef.current;
2357
2950
  const { start, end } = orderedRange(sel);
@@ -2371,7 +2964,7 @@ function useEditor(opts = {}) {
2371
2964
  },
2372
2965
  [isMarkActive, setPendingMarks]
2373
2966
  );
2374
- const setMark = useCallback4(
2967
+ const setMark = useCallback6(
2375
2968
  (name, value) => {
2376
2969
  const sel = selectionRef.current;
2377
2970
  const { start, end } = orderedRange(sel);
@@ -2384,7 +2977,7 @@ function useEditor(opts = {}) {
2384
2977
  },
2385
2978
  [setPendingMarks]
2386
2979
  );
2387
- const removeMark = useCallback4(
2980
+ const removeMark = useCallback6(
2388
2981
  (name) => {
2389
2982
  const sel = selectionRef.current;
2390
2983
  const { start, end } = orderedRange(sel);
@@ -2397,7 +2990,7 @@ function useEditor(opts = {}) {
2397
2990
  },
2398
2991
  [setPendingMarks]
2399
2992
  );
2400
- const getBlockType = useCallback4(() => {
2993
+ const getBlockType = useCallback6(() => {
2401
2994
  const sel = selectionRef.current;
2402
2995
  const { start, end } = orderedRange(sel);
2403
2996
  const first = doc.getBlockType(start.blockIndex);
@@ -2407,7 +3000,7 @@ function useEditor(opts = {}) {
2407
3000
  }
2408
3001
  return first;
2409
3002
  }, [doc]);
2410
- const getBlockAttr = useCallback4(
3003
+ const getBlockAttr = useCallback6(
2411
3004
  (key) => {
2412
3005
  const sel = selectionRef.current;
2413
3006
  const { start, end } = orderedRange(sel);
@@ -2420,16 +3013,29 @@ function useEditor(opts = {}) {
2420
3013
  },
2421
3014
  [doc]
2422
3015
  );
2423
- const setBlockType = useCallback4((type, attrs) => {
3016
+ const setBlockType = useCallback6((type, attrs) => {
2424
3017
  cmdSetBlockType(ctxRef.current, type, attrs);
2425
3018
  }, []);
2426
- const setBlockAttr = useCallback4(
3019
+ const setBlockAttr = useCallback6(
2427
3020
  (key, value) => {
2428
3021
  cmdSetBlockAttr(ctxRef.current, key, value);
2429
3022
  },
2430
3023
  []
2431
3024
  );
2432
- const isListActive = useCallback4(
3025
+ const setAlign = useCallback6((value) => {
3026
+ const sel = selectionRef.current;
3027
+ const inCell = sel.focus.cellIndex != null;
3028
+ if (inCell) cmdSetCellAttr(ctxRef.current, "align", value);
3029
+ else cmdSetBlockAttr(ctxRef.current, "align", value);
3030
+ }, []);
3031
+ const getAlign = useCallback6(() => {
3032
+ const sel = selectionRef.current;
3033
+ if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {
3034
+ return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).align;
3035
+ }
3036
+ return getBlockAttr("align");
3037
+ }, [doc, getBlockAttr]);
3038
+ const isListActive = useCallback6(
2433
3039
  (kind) => {
2434
3040
  const sel = selectionRef.current;
2435
3041
  const { start, end } = orderedRange(sel);
@@ -2441,110 +3047,116 @@ function useEditor(opts = {}) {
2441
3047
  },
2442
3048
  [doc]
2443
3049
  );
2444
- const toggleList = useCallback4((kind) => {
3050
+ const toggleList = useCallback6((kind) => {
2445
3051
  cmdToggleList(ctxRef.current, kind);
2446
3052
  }, []);
2447
- const indentList = useCallback4(() => {
3053
+ const indentList = useCallback6(() => {
2448
3054
  cmdIndentList(ctxRef.current);
2449
3055
  }, []);
2450
- const dedentList = useCallback4(() => {
3056
+ const dedentList = useCallback6(() => {
2451
3057
  cmdDedentList(ctxRef.current);
2452
3058
  }, []);
2453
- const splitListItem = useCallback4(() => {
3059
+ const splitListItem = useCallback6(() => {
2454
3060
  return cmdSplitListItem(ctxRef.current);
2455
3061
  }, []);
2456
- const isInTable = useCallback4(() => {
3062
+ const isInTable = useCallback6(() => {
2457
3063
  return selectionRef.current.focus.cellIndex != null;
2458
3064
  }, []);
2459
- const getTableLocation = useCallback4(() => {
3065
+ const getTableLocation = useCallback6(() => {
2460
3066
  return tableLocationOf(doc, selectionRef.current.focus);
2461
3067
  }, [doc]);
2462
- const insertTable = useCallback4((rows, cols) => {
3068
+ const insertTable = useCallback6((rows, cols) => {
2463
3069
  cmdInsertTable(ctxRef.current, rows, cols);
2464
3070
  }, []);
2465
- const deleteTable = useCallback4((blockIndex) => {
3071
+ const deleteTable = useCallback6((blockIndex) => {
2466
3072
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
2467
3073
  cmdDeleteTable(ctxRef.current, idx);
2468
3074
  }, []);
2469
- const insertRowAbove = useCallback4(() => {
3075
+ const insertRowAbove = useCallback6(() => {
2470
3076
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2471
3077
  if (!loc) return;
2472
3078
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "before");
2473
3079
  }, [doc]);
2474
- const insertRowBelow = useCallback4(() => {
3080
+ const insertRowBelow = useCallback6(() => {
2475
3081
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2476
3082
  if (!loc) return;
2477
3083
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "after");
2478
3084
  }, [doc]);
2479
- const deleteCurrentRow = useCallback4(() => {
3085
+ const deleteCurrentRow = useCallback6(() => {
2480
3086
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2481
3087
  if (!loc) return;
2482
3088
  cmdDeleteRow(ctxRef.current, loc.blockIndex, loc.row);
2483
3089
  }, [doc]);
2484
- const insertColumnLeft = useCallback4(() => {
3090
+ const insertColumnLeft = useCallback6(() => {
2485
3091
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2486
3092
  if (!loc) return;
2487
3093
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "before");
2488
3094
  }, [doc]);
2489
- const insertColumnRight = useCallback4(() => {
3095
+ const insertColumnRight = useCallback6(() => {
2490
3096
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2491
3097
  if (!loc) return;
2492
3098
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "after");
2493
3099
  }, [doc]);
2494
- const deleteCurrentColumn = useCallback4(() => {
3100
+ const deleteCurrentColumn = useCallback6(() => {
2495
3101
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2496
3102
  if (!loc) return;
2497
3103
  cmdDeleteColumn(ctxRef.current, loc.blockIndex, loc.col);
2498
3104
  }, [doc]);
2499
- const moveToNextCell = useCallback4(() => {
3105
+ const moveToNextCell = useCallback6(() => {
2500
3106
  cmdMoveNextCell(ctxRef.current);
2501
3107
  }, []);
2502
- const moveToPrevCell = useCallback4(() => {
3108
+ const moveToPrevCell = useCallback6(() => {
2503
3109
  cmdMovePrevCell(ctxRef.current);
2504
3110
  }, []);
2505
- const mergeRight = useCallback4(() => {
3111
+ const mergeRight = useCallback6(() => {
2506
3112
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2507
3113
  if (!loc) return false;
2508
3114
  return cmdMergeRight(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2509
3115
  }, [doc]);
2510
- const mergeDown = useCallback4(() => {
3116
+ const mergeDown = useCallback6(() => {
2511
3117
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2512
3118
  if (!loc) return false;
2513
3119
  return cmdMergeDown(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2514
3120
  }, [doc]);
2515
- const splitCell = useCallback4(() => {
3121
+ const splitCell = useCallback6(() => {
2516
3122
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2517
3123
  if (!loc) return false;
2518
3124
  return cmdSplitCell(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2519
3125
  }, [doc]);
2520
- const setColumnWidth = useCallback4(
3126
+ const setColumnWidth = useCallback6(
2521
3127
  (blockIndex, col, widthPx) => {
2522
3128
  cmdSetColumnWidth(ctxRef.current, blockIndex, col, widthPx);
2523
3129
  },
2524
3130
  []
2525
3131
  );
2526
- const getTableRect = useCallback4(
3132
+ const getTableRect = useCallback6(
2527
3133
  () => tableRectSelection2(doc, selectionRef.current),
2528
3134
  [doc]
2529
3135
  );
2530
- const hasTableRectSelection = useCallback4(() => {
3136
+ const hasTableRectSelection = useCallback6(() => {
2531
3137
  return tableRectSelection2(doc, selectionRef.current) !== null;
2532
3138
  }, [doc]);
2533
- const mergeSelection = useCallback4(() => {
3139
+ const mergeSelection = useCallback6(() => {
2534
3140
  return cmdMergeSelection(ctxRef.current);
2535
3141
  }, []);
2536
- const insertImage = useCallback4((embed) => {
3142
+ const insertImage = useCallback6((embed) => {
2537
3143
  cmdInsertImage(ctxRef.current, embed);
2538
3144
  }, []);
2539
- const setImageAttrs = useCallback4(
3145
+ const setImageAttrs = useCallback6(
2540
3146
  (blockIndex, offset, partial, cellIndex, newOffset) => {
2541
3147
  cmdSetImageAttrs(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
2542
3148
  },
2543
3149
  []
2544
3150
  );
2545
- const uploadImageRef = useRef9(opts.uploadImage);
3151
+ const moveEmbedAnchor = useCallback6(
3152
+ (from, to, newOffsetX, newOffsetY) => {
3153
+ cmdMoveEmbedAnchor(ctxRef.current, from, to, newOffsetX, newOffsetY);
3154
+ },
3155
+ []
3156
+ );
3157
+ const uploadImageRef = useRef10(opts.uploadImage);
2546
3158
  uploadImageRef.current = opts.uploadImage;
2547
- const insertImageFromFile = useCallback4(async (file) => {
3159
+ const insertImageFromFile = useCallback6(async (file) => {
2548
3160
  if (!file.type.startsWith("image/")) return;
2549
3161
  const dataUrl = await readAsDataURL(file);
2550
3162
  const dims = await readImageDimensions(dataUrl);
@@ -2558,7 +3170,7 @@ function useEditor(opts = {}) {
2558
3170
  const src = upload ? await upload(file) : dataUrl;
2559
3171
  cmdInsertImage(ctxRef.current, { type: "image", src, width: w, height: h });
2560
3172
  }, []);
2561
- const getSelectedEmbed = useCallback4(() => {
3173
+ const getSelectedEmbed = useCallback6(() => {
2562
3174
  const sel = selectionRef.current;
2563
3175
  if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;
2564
3176
  if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;
@@ -2587,39 +3199,48 @@ function useEditor(opts = {}) {
2587
3199
  }
2588
3200
  return null;
2589
3201
  }, [doc]);
2590
- const [linkRequest, setLinkRequest] = useState7(null);
2591
- const requestLink = useCallback4((initialHref = "") => {
3202
+ const [linkRequest, setLinkRequest] = useState9(null);
3203
+ const linkRequestRef = useRef10(null);
3204
+ const requestLink = useCallback6((initialHref = "") => {
2592
3205
  return new Promise((resolve) => {
2593
- setLinkRequest({ initialHref, resolve });
2594
- });
2595
- }, []);
2596
- const resolveLinkRequest = useCallback4((href) => {
2597
- setLinkRequest((prev) => {
2598
- if (prev) prev.resolve(href);
2599
- return null;
3206
+ const req = { initialHref, resolve, selection: selectionRef.current };
3207
+ linkRequestRef.current = req;
3208
+ setLinkRequest(req);
2600
3209
  });
2601
3210
  }, []);
3211
+ const resolveLinkRequest = useCallback6(
3212
+ (href) => {
3213
+ const req = linkRequestRef.current;
3214
+ linkRequestRef.current = null;
3215
+ setLinkRequest(null);
3216
+ if (req) {
3217
+ setSelection(req.selection);
3218
+ req.resolve(href);
3219
+ }
3220
+ },
3221
+ [setSelection]
3222
+ );
2602
3223
  const pageSettings = usePageSettings(doc);
2603
- const setPageSettings = useCallback4(
3224
+ const setPageSettings = useCallback6(
2604
3225
  (partial) => {
2605
3226
  doc.setPageSettings(partial);
2606
3227
  },
2607
3228
  [doc]
2608
3229
  );
2609
- const [pageConfigRequest, setPageConfigRequest] = useState7(null);
2610
- const requestPageConfig = useCallback4(() => {
3230
+ const [pageConfigRequest, setPageConfigRequest] = useState9(null);
3231
+ const requestPageConfig = useCallback6(() => {
2611
3232
  return new Promise((resolve) => {
2612
3233
  setPageConfigRequest({ initial: doc.getPageSettings(), resolve });
2613
3234
  });
2614
3235
  }, [doc]);
2615
- const resolvePageConfigRequest = useCallback4((applied) => {
3236
+ const resolvePageConfigRequest = useCallback6((applied) => {
2616
3237
  setPageConfigRequest((prev) => {
2617
3238
  if (prev) prev.resolve(applied);
2618
3239
  return null;
2619
3240
  });
2620
3241
  }, []);
2621
- const [imageCaptionRequest, setImageCaptionRequest] = useState7(null);
2622
- const requestImageCaption = useCallback4(
3242
+ const [imageCaptionRequest, setImageCaptionRequest] = useState9(null);
3243
+ const requestImageCaption = useCallback6(
2623
3244
  (initialCaption = "", initialAlign = "center") => {
2624
3245
  return new Promise((resolve) => {
2625
3246
  setImageCaptionRequest({ initialCaption, initialAlign, resolve });
@@ -2627,7 +3248,7 @@ function useEditor(opts = {}) {
2627
3248
  },
2628
3249
  []
2629
3250
  );
2630
- const resolveImageCaptionRequest = useCallback4((result) => {
3251
+ const resolveImageCaptionRequest = useCallback6((result) => {
2631
3252
  setImageCaptionRequest((prev) => {
2632
3253
  if (prev) prev.resolve(result);
2633
3254
  return null;
@@ -2651,6 +3272,8 @@ function useEditor(opts = {}) {
2651
3272
  getBlockAttr,
2652
3273
  setBlockType,
2653
3274
  setBlockAttr,
3275
+ setAlign,
3276
+ getAlign,
2654
3277
  isListActive,
2655
3278
  toggleList,
2656
3279
  indentList,
@@ -2680,6 +3303,7 @@ function useEditor(opts = {}) {
2680
3303
  mergeSelection,
2681
3304
  insertImage,
2682
3305
  setImageAttrs,
3306
+ moveEmbedAnchor,
2683
3307
  insertImageFromFile,
2684
3308
  getSelectedEmbed,
2685
3309
  pageSettings,
@@ -2721,54 +3345,99 @@ function sameValue(a, b) {
2721
3345
  }
2722
3346
 
2723
3347
  // src/Editor.tsx
2724
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3348
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2725
3349
  var defaultFooter = ({ pageNumber, pageCount }) => `${pageNumber} / ${pageCount}`;
2726
3350
  function Editor({
2727
3351
  editor: providedEditor,
2728
3352
  className,
2729
3353
  pageGeometry,
2730
3354
  renderPageHeader,
2731
- renderPageFooter = defaultFooter
3355
+ renderPageFooter = defaultFooter,
3356
+ awareness
2732
3357
  }) {
2733
3358
  const internal = useEditor();
2734
3359
  const editor = providedEditor ?? internal;
2735
3360
  const { doc, history, snapshot, getSelection, setSelection } = editor;
2736
- const rootRef = useRef10(null);
2737
- const isComposingRef = useRef10(false);
2738
- const suppressSelectionSyncRef = useRef10(false);
2739
- const ctxRef = useRef10({ doc, getSelection, setSelection });
3361
+ const rootRef = useRef11(null);
3362
+ const isComposingRef = useRef11(false);
3363
+ const [hoveredBehind, setHoveredBehind] = useState10(null);
3364
+ const hoveredBehindRef = useRef11(null);
3365
+ const [hoveredLink, setHoveredLink] = useState10(null);
3366
+ const hoveredLinkElRef = useRef11(null);
3367
+ const suppressSelectionSyncRef = useRef11(false);
3368
+ useEffect9(() => {
3369
+ if (!awareness) return;
3370
+ const root = rootRef.current;
3371
+ if (!root) return;
3372
+ let raf = null;
3373
+ const publish = () => {
3374
+ raf = null;
3375
+ const sel = readDomSelection(root);
3376
+ awareness.setLocalStateField(
3377
+ "cursor",
3378
+ sel ? encodeSelection(doc, sel) ?? null : null
3379
+ );
3380
+ };
3381
+ const onSelChange = () => {
3382
+ const s = document.getSelection();
3383
+ if (!s || s.rangeCount === 0) return;
3384
+ if (s.anchorNode && !root.contains(s.anchorNode)) return;
3385
+ if (raf != null) return;
3386
+ raf = requestAnimationFrame(publish);
3387
+ };
3388
+ const onBlur = () => awareness.setLocalStateField("cursor", null);
3389
+ document.addEventListener("selectionchange", onSelChange);
3390
+ root.addEventListener("blur", onBlur, true);
3391
+ return () => {
3392
+ document.removeEventListener("selectionchange", onSelChange);
3393
+ root.removeEventListener("blur", onBlur, true);
3394
+ if (raf != null) cancelAnimationFrame(raf);
3395
+ awareness.setLocalStateField("cursor", null);
3396
+ };
3397
+ }, [awareness, doc]);
3398
+ const ctxRef = useRef11({ doc, getSelection, setSelection });
2740
3399
  ctxRef.current = { doc, getSelection, setSelection };
2741
- const historyRef = useRef10(history);
3400
+ const historyRef = useRef11(history);
2742
3401
  historyRef.current = history;
2743
- const editorRef = useRef10(editor);
3402
+ const editorRef = useRef11(editor);
2744
3403
  editorRef.current = editor;
2745
- useLayoutEffect4(() => {
3404
+ useLayoutEffect5(() => {
2746
3405
  const root = rootRef.current;
2747
3406
  if (!root) return;
2748
3407
  if (isComposingRef.current) return;
2749
3408
  if (document.activeElement !== root) return;
2750
3409
  const current = readDomSelection(root);
2751
3410
  if (current && selectionsEqual(current, editor.selection)) return;
3411
+ if (isTableRectSelection(editor.selection)) {
3412
+ applyDomSelection(root, editor.selection);
3413
+ suppressSelectionSyncRef.current = false;
3414
+ return;
3415
+ }
2752
3416
  suppressSelectionSyncRef.current = true;
2753
3417
  applyDomSelection(root, editor.selection);
2754
- queueMicrotask(() => {
2755
- suppressSelectionSyncRef.current = false;
2756
- });
2757
3418
  });
2758
- useEffect7(() => {
3419
+ useEffect9(() => {
2759
3420
  const root = rootRef.current;
2760
3421
  if (!root) return;
2761
3422
  const handler = () => {
2762
- if (suppressSelectionSyncRef.current) return;
2763
3423
  if (isComposingRef.current) return;
2764
- if (document.activeElement !== root) return;
3424
+ if (document.activeElement !== root) {
3425
+ suppressSelectionSyncRef.current = false;
3426
+ return;
3427
+ }
2765
3428
  const modelSel = readDomSelection(root);
3429
+ if (suppressSelectionSyncRef.current) {
3430
+ if (modelSel && selectionsEqual(modelSel, editorRef.current.getSelection())) {
3431
+ suppressSelectionSyncRef.current = false;
3432
+ }
3433
+ return;
3434
+ }
2766
3435
  if (modelSel) setSelection(modelSel);
2767
3436
  };
2768
3437
  document.addEventListener("selectionchange", handler);
2769
3438
  return () => document.removeEventListener("selectionchange", handler);
2770
3439
  }, [setSelection]);
2771
- useEffect7(() => {
3440
+ useEffect9(() => {
2772
3441
  const root = rootRef.current;
2773
3442
  if (!root) return;
2774
3443
  let drag = null;
@@ -2839,7 +3508,7 @@ function Editor({
2839
3508
  document.removeEventListener("pointerup", onPointerUp);
2840
3509
  };
2841
3510
  }, []);
2842
- useEffect7(() => {
3511
+ useEffect9(() => {
2843
3512
  const root = rootRef.current;
2844
3513
  if (!root) return;
2845
3514
  const onDragOver = (e) => {
@@ -2877,7 +3546,7 @@ function Editor({
2877
3546
  root.removeEventListener("drop", onDrop);
2878
3547
  };
2879
3548
  }, []);
2880
- useEffect7(() => {
3549
+ useEffect9(() => {
2881
3550
  const root = rootRef.current;
2882
3551
  if (!root) return;
2883
3552
  const onPointerDown = (e) => {
@@ -2905,7 +3574,95 @@ function Editor({
2905
3574
  root.addEventListener("pointerdown", onPointerDown);
2906
3575
  return () => root.removeEventListener("pointerdown", onPointerDown);
2907
3576
  }, []);
2908
- useEffect7(() => {
3577
+ useEffect9(() => {
3578
+ const root = rootRef.current;
3579
+ if (!root) return;
3580
+ const same = (a, b) => a === b || !!a && !!b && a.blockIndex === b.blockIndex && a.offset === b.offset && (a.cellIndex ?? -1) === (b.cellIndex ?? -1);
3581
+ const set = (next) => {
3582
+ if (same(next, hoveredBehindRef.current)) return;
3583
+ hoveredBehindRef.current = next;
3584
+ setHoveredBehind(next);
3585
+ };
3586
+ let raf = 0;
3587
+ const onMove = (e) => {
3588
+ if (raf) return;
3589
+ const x = e.clientX;
3590
+ const y = e.clientY;
3591
+ raf = requestAnimationFrame(() => {
3592
+ raf = 0;
3593
+ const imgs = root.querySelectorAll(
3594
+ 'img[data-embed="image"][data-embed-layout="behind"]'
3595
+ );
3596
+ let hit = null;
3597
+ for (const img of imgs) {
3598
+ const r = img.getBoundingClientRect();
3599
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {
3600
+ hit = img;
3601
+ break;
3602
+ }
3603
+ }
3604
+ if (!hit) {
3605
+ set(null);
3606
+ return;
3607
+ }
3608
+ const blockEl = hit.closest("[data-block-index]");
3609
+ const offsetAttr = hit.dataset.embedOffset;
3610
+ if (!blockEl || offsetAttr == null) {
3611
+ set(null);
3612
+ return;
3613
+ }
3614
+ const blockIndex = Number.parseInt(blockEl.dataset.blockIndex, 10);
3615
+ const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? "0", 10) || 0;
3616
+ const cellEl = hit.closest("[data-cell-index]");
3617
+ const cellIndex = cellEl ? Number.parseInt(cellEl.dataset.cellIndex, 10) : void 0;
3618
+ set({ blockIndex, offset: fragmentStart + Number.parseInt(offsetAttr, 10), cellIndex });
3619
+ });
3620
+ };
3621
+ const onLeave = () => set(null);
3622
+ root.addEventListener("pointermove", onMove);
3623
+ root.addEventListener("pointerleave", onLeave);
3624
+ return () => {
3625
+ root.removeEventListener("pointermove", onMove);
3626
+ root.removeEventListener("pointerleave", onLeave);
3627
+ if (raf) cancelAnimationFrame(raf);
3628
+ };
3629
+ }, []);
3630
+ useEffect9(() => {
3631
+ const root = rootRef.current;
3632
+ if (!root) return;
3633
+ const clear = () => {
3634
+ if (hoveredLinkElRef.current) {
3635
+ hoveredLinkElRef.current = null;
3636
+ setHoveredLink(null);
3637
+ }
3638
+ };
3639
+ const onOver = (e) => {
3640
+ const target = e.target;
3641
+ const a = target?.closest?.("a[href]");
3642
+ if (a && root.contains(a)) {
3643
+ if (hoveredLinkElRef.current === a) return;
3644
+ hoveredLinkElRef.current = a;
3645
+ const r = a.getBoundingClientRect();
3646
+ setHoveredLink({
3647
+ href: a.getAttribute("href") ?? "",
3648
+ rect: { top: r.top, left: r.left, bottom: r.bottom, width: r.width }
3649
+ });
3650
+ } else {
3651
+ clear();
3652
+ }
3653
+ };
3654
+ root.addEventListener("mouseover", onOver);
3655
+ root.addEventListener("mouseleave", clear);
3656
+ root.addEventListener("scroll", clear, true);
3657
+ window.addEventListener("scroll", clear, true);
3658
+ return () => {
3659
+ root.removeEventListener("mouseover", onOver);
3660
+ root.removeEventListener("mouseleave", clear);
3661
+ root.removeEventListener("scroll", clear, true);
3662
+ window.removeEventListener("scroll", clear, true);
3663
+ };
3664
+ }, []);
3665
+ useEffect9(() => {
2909
3666
  const root = rootRef.current;
2910
3667
  if (!root) return;
2911
3668
  const handler = (e) => {
@@ -2981,22 +3738,6 @@ function Editor({
2981
3738
  }
2982
3739
  case "insertFromPaste": {
2983
3740
  e.preventDefault();
2984
- const images = Array.from(e.dataTransfer?.files ?? []).filter(
2985
- (f) => f.type.startsWith("image/")
2986
- );
2987
- if (images.length > 0) {
2988
- void (async () => {
2989
- for (const f of images) await editorRef.current.insertImageFromFile(f);
2990
- })();
2991
- return;
2992
- }
2993
- const text = e.dataTransfer?.getData("text/plain") ?? "";
2994
- if (text.length === 0) return;
2995
- const lines = text.split(/\r\n|\r|\n/);
2996
- lines.forEach((line, i) => {
2997
- if (i > 0) insertParagraph(ctx);
2998
- if (line.length > 0) insertText(ctx, line);
2999
- });
3000
3741
  return;
3001
3742
  }
3002
3743
  case "deleteContentBackward":
@@ -3034,7 +3775,67 @@ function Editor({
3034
3775
  root.addEventListener("beforeinput", handler);
3035
3776
  return () => root.removeEventListener("beforeinput", handler);
3036
3777
  }, []);
3037
- const onKeyDown = useCallback5((e) => {
3778
+ useEffect9(() => {
3779
+ const root = rootRef.current;
3780
+ if (!root) return;
3781
+ const writeSlice = (e) => {
3782
+ const ctx = ctxRef.current;
3783
+ const slice = serializeSelection(ctx.doc, ctx.getSelection());
3784
+ if (!slice || !e.clipboardData) return false;
3785
+ e.clipboardData.setData(SOFER_MIME, JSON.stringify(slice));
3786
+ e.clipboardData.setData("text/plain", sliceToText(slice));
3787
+ return true;
3788
+ };
3789
+ const onCopy = (e) => {
3790
+ if (writeSlice(e)) e.preventDefault();
3791
+ };
3792
+ const onCut = (e) => {
3793
+ e.preventDefault();
3794
+ if (writeSlice(e)) deleteSelection(ctxRef.current);
3795
+ };
3796
+ const onPaste = (e) => {
3797
+ const ctx = ctxRef.current;
3798
+ const cd = e.clipboardData;
3799
+ if (!cd) return;
3800
+ const raw = cd.getData(SOFER_MIME);
3801
+ if (raw) {
3802
+ try {
3803
+ const slice = JSON.parse(raw);
3804
+ if (slice && Array.isArray(slice.blocks)) {
3805
+ e.preventDefault();
3806
+ insertSlice(ctx, slice);
3807
+ return;
3808
+ }
3809
+ } catch {
3810
+ }
3811
+ }
3812
+ const images = Array.from(cd.files ?? []).filter((f) => f.type.startsWith("image/"));
3813
+ if (images.length > 0) {
3814
+ e.preventDefault();
3815
+ void (async () => {
3816
+ for (const f of images) await editorRef.current.insertImageFromFile(f);
3817
+ })();
3818
+ return;
3819
+ }
3820
+ const text = cd.getData("text/plain");
3821
+ if (text.length === 0) return;
3822
+ e.preventDefault();
3823
+ const lines = text.split(/\r\n|\r|\n/);
3824
+ lines.forEach((line, i) => {
3825
+ if (i > 0) insertParagraph(ctx);
3826
+ if (line.length > 0) insertText(ctx, line);
3827
+ });
3828
+ };
3829
+ root.addEventListener("copy", onCopy);
3830
+ root.addEventListener("cut", onCut);
3831
+ root.addEventListener("paste", onPaste);
3832
+ return () => {
3833
+ root.removeEventListener("copy", onCopy);
3834
+ root.removeEventListener("cut", onCut);
3835
+ root.removeEventListener("paste", onPaste);
3836
+ };
3837
+ }, []);
3838
+ const onKeyDown = useCallback7((e) => {
3038
3839
  const ed = editorRef.current;
3039
3840
  const mod = e.metaKey || e.ctrlKey;
3040
3841
  if (e.key === "Tab") {
@@ -3108,10 +3909,10 @@ function Editor({
3108
3909
  });
3109
3910
  }
3110
3911
  }, []);
3111
- const onCompositionStart = useCallback5(() => {
3912
+ const onCompositionStart = useCallback7(() => {
3112
3913
  isComposingRef.current = true;
3113
3914
  }, []);
3114
- const onCompositionEnd = useCallback5((e) => {
3915
+ const onCompositionEnd = useCallback7((e) => {
3115
3916
  isComposingRef.current = false;
3116
3917
  if (e.data && e.data.length > 0) {
3117
3918
  insertText(ctxRef.current, e.data);
@@ -3159,7 +3960,7 @@ function Editor({
3159
3960
  geom.marginRight
3160
3961
  ]
3161
3962
  );
3162
- const body = /* @__PURE__ */ jsxs8(
3963
+ const body = /* @__PURE__ */ jsxs11(
3163
3964
  "div",
3164
3965
  {
3165
3966
  ref: rootRef,
@@ -3185,7 +3986,7 @@ function Editor({
3185
3986
  const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
3186
3987
  "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
3187
3988
  } : void 0;
3188
- return /* @__PURE__ */ jsxs8(
3989
+ return /* @__PURE__ */ jsxs11(
3189
3990
  "div",
3190
3991
  {
3191
3992
  className: "ed-page",
@@ -3193,15 +3994,15 @@ function Editor({
3193
3994
  "data-page-total": ctx.pageCount,
3194
3995
  style: pageInlineStyle,
3195
3996
  children: [
3196
- renderPageHeader && /* @__PURE__ */ jsx9("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3197
- /* @__PURE__ */ jsx9("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3198
- renderPageFooter && /* @__PURE__ */ jsx9("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
3997
+ renderPageHeader && /* @__PURE__ */ jsx12("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3998
+ /* @__PURE__ */ jsx12("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3999
+ renderPageFooter && /* @__PURE__ */ jsx12("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
3199
4000
  ]
3200
4001
  },
3201
4002
  `page-${pi}`
3202
4003
  );
3203
4004
  }) : topLevels.map((t) => renderTopLevel(t)),
3204
- selectedEmbed && /* @__PURE__ */ jsx9(
4005
+ selectedEmbed && /* @__PURE__ */ jsx12(
3205
4006
  ImageResizeOverlay,
3206
4007
  {
3207
4008
  rootRef,
@@ -3220,13 +4021,54 @@ function Editor({
3220
4021
  selectedEmbed.offset,
3221
4022
  { offsetX: ox, offsetY: oy },
3222
4023
  selectedEmbed.cellIndex
4024
+ ),
4025
+ onReanchor: (to, ox, oy) => editor.moveEmbedAnchor(
4026
+ {
4027
+ blockIndex: selectedEmbed.blockIndex,
4028
+ offset: selectedEmbed.offset,
4029
+ cellIndex: selectedEmbed.cellIndex
4030
+ },
4031
+ to,
4032
+ ox,
4033
+ oy
3223
4034
  )
3224
4035
  }
4036
+ ),
4037
+ hoveredBehind && !(selectedEmbed && selectedEmbed.blockIndex === hoveredBehind.blockIndex && selectedEmbed.offset === hoveredBehind.offset && (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)) && /* @__PURE__ */ jsx12(
4038
+ BehindImageSelectAffordance,
4039
+ {
4040
+ rootRef,
4041
+ blockIndex: hoveredBehind.blockIndex,
4042
+ offset: hoveredBehind.offset,
4043
+ cellIndex: hoveredBehind.cellIndex,
4044
+ onSelect: () => setSelection({
4045
+ anchor: {
4046
+ blockIndex: hoveredBehind.blockIndex,
4047
+ cellIndex: hoveredBehind.cellIndex,
4048
+ offset: hoveredBehind.offset
4049
+ },
4050
+ focus: {
4051
+ blockIndex: hoveredBehind.blockIndex,
4052
+ cellIndex: hoveredBehind.cellIndex,
4053
+ offset: hoveredBehind.offset + 1
4054
+ }
4055
+ })
4056
+ }
4057
+ ),
4058
+ hoveredLink && hoveredLink.href && /* @__PURE__ */ jsx12(LinkHoverTooltip, { href: hoveredLink.href, rect: hoveredLink.rect }),
4059
+ awareness && /* @__PURE__ */ jsx12(
4060
+ RemoteCursorsOverlay,
4061
+ {
4062
+ rootRef,
4063
+ doc,
4064
+ awareness,
4065
+ revision: snapshot
4066
+ }
3225
4067
  )
3226
4068
  ]
3227
4069
  }
3228
4070
  );
3229
- return /* @__PURE__ */ jsx9(EditorProvider, { editor, children: body });
4071
+ return /* @__PURE__ */ jsx12(EditorProvider, { editor, children: body });
3230
4072
  }
3231
4073
  function groupTopLevels(snapshot) {
3232
4074
  const out = [];
@@ -3276,7 +4118,7 @@ function renderSlot(slot, topLevels) {
3276
4118
  start: slot.fragment.start,
3277
4119
  end: slot.fragment.end
3278
4120
  };
3279
- return /* @__PURE__ */ jsx9(
4121
+ return /* @__PURE__ */ jsx12(
3280
4122
  NodeView,
3281
4123
  {
3282
4124
  block: top.block,
@@ -3287,7 +4129,7 @@ function renderSlot(slot, topLevels) {
3287
4129
  );
3288
4130
  }
3289
4131
  if (slot.tableFragment && top.kind === "block" && top.block.type === "table") {
3290
- return /* @__PURE__ */ jsx9(
4132
+ return /* @__PURE__ */ jsx12(
3291
4133
  NodeView,
3292
4134
  {
3293
4135
  block: top.block,
@@ -3307,7 +4149,7 @@ function renderTopLevel(top) {
3307
4149
  const tree = buildListTree(top.items);
3308
4150
  return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
3309
4151
  }
3310
- return /* @__PURE__ */ jsx9(NodeView, { block: top.block, index: top.blockIndex }, top.key);
4152
+ return /* @__PURE__ */ jsx12(NodeView, { block: top.block, index: top.blockIndex }, top.key);
3311
4153
  }
3312
4154
  function renderListFragment(top, frag) {
3313
4155
  const ranges = topLevelItemRanges(top.items);
@@ -3349,9 +4191,9 @@ function buildListTree(items) {
3349
4191
  function renderListTree(tree, top, start, key) {
3350
4192
  const className = `ed-list ed-list-${top.listKind}`;
3351
4193
  const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
3352
- const items = tree.map((node) => /* @__PURE__ */ jsx9(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, top.listKind, `nested-${node.entry.index}`) : null }, node.entry.index));
4194
+ const items = tree.map((node) => /* @__PURE__ */ jsx12(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, top.listKind, `nested-${node.entry.index}`) : null }, node.entry.index));
3353
4195
  if (top.listKind === "ordered") {
3354
- return /* @__PURE__ */ jsx9(
4196
+ return /* @__PURE__ */ jsx12(
3355
4197
  "ol",
3356
4198
  {
3357
4199
  className,
@@ -3363,11 +4205,11 @@ function renderListTree(tree, top, start, key) {
3363
4205
  key
3364
4206
  );
3365
4207
  }
3366
- return /* @__PURE__ */ jsx9("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
4208
+ return /* @__PURE__ */ jsx12("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
3367
4209
  }
3368
4210
  function renderNestedListTree(tree, kind, key) {
3369
4211
  const Tag = kind === "ordered" ? "ol" : "ul";
3370
- return /* @__PURE__ */ jsx9(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx9(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, kind, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
4212
+ return /* @__PURE__ */ jsx12(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx12(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, kind, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
3371
4213
  }
3372
4214
  function clampListLevel2(l) {
3373
4215
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
@@ -3396,12 +4238,12 @@ function caretRangeFromPoint(x, y) {
3396
4238
 
3397
4239
  // src/Toolbar.tsx
3398
4240
  import {
3399
- useCallback as useCallback6,
3400
- useEffect as useEffect8,
3401
- useRef as useRef11,
3402
- useState as useState8
4241
+ useCallback as useCallback8,
4242
+ useEffect as useEffect10,
4243
+ useRef as useRef12,
4244
+ useState as useState11
3403
4245
  } from "react";
3404
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4246
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
3405
4247
  var FONT_FAMILIES = ["Arial"];
3406
4248
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
3407
4249
  var BLOCK_OPTIONS = [
@@ -3441,6 +4283,8 @@ function Toolbar({ className }) {
3441
4283
  getBlockAttr,
3442
4284
  setBlockType,
3443
4285
  setBlockAttr,
4286
+ setAlign,
4287
+ getAlign,
3444
4288
  isListActive,
3445
4289
  toggleList,
3446
4290
  indentList,
@@ -3449,7 +4293,7 @@ function Toolbar({ className }) {
3449
4293
  const active = getActiveMarks();
3450
4294
  const blockType = getBlockType();
3451
4295
  const blockLevel = getBlockAttr("level");
3452
- const blockAlign = getBlockAttr("align");
4296
+ const blockAlign = getAlign();
3453
4297
  const blockDir = getBlockAttr("dir");
3454
4298
  const stop = (e) => {
3455
4299
  const t = e.target;
@@ -3492,16 +4336,16 @@ function Toolbar({ className }) {
3492
4336
  );
3493
4337
  return;
3494
4338
  }
3495
- setBlockAttr("align", value);
4339
+ setAlign(value);
3496
4340
  };
3497
- const onInsertImageClick = useCallback6(
4341
+ const onInsertImageClick = useCallback8(
3498
4342
  (e) => {
3499
4343
  e.preventDefault();
3500
4344
  imageInputRef.current?.click();
3501
4345
  },
3502
4346
  []
3503
4347
  );
3504
- const onImageInputChange = useCallback6(
4348
+ const onImageInputChange = useCallback8(
3505
4349
  (e) => {
3506
4350
  const file = e.target.files?.[0];
3507
4351
  if (file) void editor.insertImageFromFile(file);
@@ -3509,14 +4353,14 @@ function Toolbar({ className }) {
3509
4353
  },
3510
4354
  [editor]
3511
4355
  );
3512
- const imageInputRef = useRef11(null);
4356
+ const imageInputRef = useRef12(null);
3513
4357
  const onToggleDir = (e) => {
3514
4358
  e.preventDefault();
3515
4359
  const next = blockDir === "rtl" ? "ltr" : "rtl";
3516
4360
  setBlockAttr("dir", next);
3517
4361
  };
3518
4362
  const linkActive = isMarkActive("link");
3519
- const onLinkClick = useCallback6(
4363
+ const onLinkClick = useCallback8(
3520
4364
  (e) => {
3521
4365
  e.preventDefault();
3522
4366
  const currentHref = active.link && typeof active.link === "object" && "href" in active.link ? active.link.href : "";
@@ -3546,7 +4390,7 @@ function Toolbar({ className }) {
3546
4390
  sel.cellIndex
3547
4391
  );
3548
4392
  };
3549
- return /* @__PURE__ */ jsxs9(
4393
+ return /* @__PURE__ */ jsxs12(
3550
4394
  "div",
3551
4395
  {
3552
4396
  className: className ?? "ed-toolbar",
@@ -3554,7 +4398,7 @@ function Toolbar({ className }) {
3554
4398
  "aria-label": "Editor toolbar",
3555
4399
  onMouseDown: stop,
3556
4400
  children: [
3557
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsxs9(
4401
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsxs12(
3558
4402
  "select",
3559
4403
  {
3560
4404
  className: "ed-toolbar-select",
@@ -3563,23 +4407,23 @@ function Toolbar({ className }) {
3563
4407
  onMouseDown: stop,
3564
4408
  "aria-label": "Tipo de bloco",
3565
4409
  children: [
3566
- blockValue === "" && /* @__PURE__ */ jsx10("option", { value: "", children: "\u2014 (misto)" }),
3567
- BLOCK_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.value, children: o.label }, o.value))
4410
+ blockValue === "" && /* @__PURE__ */ jsx13("option", { value: "", children: "\u2014 (misto)" }),
4411
+ BLOCK_OPTIONS.map((o) => /* @__PURE__ */ jsx13("option", { value: o.value, children: o.label }, o.value))
3568
4412
  ]
3569
4413
  }
3570
4414
  ) }),
3571
- /* @__PURE__ */ jsxs9(Group, { children: [
3572
- /* @__PURE__ */ jsx10(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ jsx10("strong", { children: "B" }) }),
3573
- /* @__PURE__ */ jsx10(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ jsx10("em", { children: "I" }) }),
3574
- /* @__PURE__ */ jsx10(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ jsx10("u", { children: "U" }) }),
3575
- /* @__PURE__ */ jsx10(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ jsx10("s", { children: "S" }) })
4415
+ /* @__PURE__ */ jsxs12(Group, { children: [
4416
+ /* @__PURE__ */ jsx13(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ jsx13("strong", { children: "B" }) }),
4417
+ /* @__PURE__ */ jsx13(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ jsx13("em", { children: "I" }) }),
4418
+ /* @__PURE__ */ jsx13(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ jsx13("u", { children: "U" }) }),
4419
+ /* @__PURE__ */ jsx13(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ jsx13("s", { children: "S" }) })
3576
4420
  ] }),
3577
- /* @__PURE__ */ jsxs9(Group, { children: [
3578
- /* @__PURE__ */ jsxs9("label", { className: "ed-toolbar-label", children: [
3579
- /* @__PURE__ */ jsx10("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
3580
- /* @__PURE__ */ jsx10("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
4421
+ /* @__PURE__ */ jsxs12(Group, { children: [
4422
+ /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", children: [
4423
+ /* @__PURE__ */ jsx13("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
4424
+ /* @__PURE__ */ jsx13("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
3581
4425
  ] }),
3582
- /* @__PURE__ */ jsx10(
4426
+ /* @__PURE__ */ jsx13(
3583
4427
  "button",
3584
4428
  {
3585
4429
  type: "button",
@@ -3594,8 +4438,8 @@ function Toolbar({ className }) {
3594
4438
  }
3595
4439
  )
3596
4440
  ] }),
3597
- /* @__PURE__ */ jsxs9(Group, { children: [
3598
- /* @__PURE__ */ jsxs9(
4441
+ /* @__PURE__ */ jsxs12(Group, { children: [
4442
+ /* @__PURE__ */ jsxs12(
3599
4443
  "select",
3600
4444
  {
3601
4445
  className: "ed-toolbar-select",
@@ -3604,12 +4448,12 @@ function Toolbar({ className }) {
3604
4448
  onMouseDown: stop,
3605
4449
  "aria-label": "Fam\xEDlia da fonte",
3606
4450
  children: [
3607
- /* @__PURE__ */ jsx10("option", { value: "", children: "Fonte\u2026" }),
3608
- FONT_FAMILIES.map((f) => /* @__PURE__ */ jsx10("option", { value: f, children: f }, f))
4451
+ /* @__PURE__ */ jsx13("option", { value: "", children: "Fonte\u2026" }),
4452
+ FONT_FAMILIES.map((f) => /* @__PURE__ */ jsx13("option", { value: f, children: f }, f))
3609
4453
  ]
3610
4454
  }
3611
4455
  ),
3612
- /* @__PURE__ */ jsxs9(
4456
+ /* @__PURE__ */ jsxs12(
3613
4457
  "select",
3614
4458
  {
3615
4459
  className: "ed-toolbar-select",
@@ -3618,13 +4462,13 @@ function Toolbar({ className }) {
3618
4462
  onMouseDown: stop,
3619
4463
  "aria-label": "Tamanho da fonte",
3620
4464
  children: [
3621
- /* @__PURE__ */ jsx10("option", { value: "", children: "Tamanho\u2026" }),
3622
- FONT_SIZES.map((s) => /* @__PURE__ */ jsx10("option", { value: s, children: s }, s))
4465
+ /* @__PURE__ */ jsx13("option", { value: "", children: "Tamanho\u2026" }),
4466
+ FONT_SIZES.map((s) => /* @__PURE__ */ jsx13("option", { value: s, children: s }, s))
3623
4467
  ]
3624
4468
  }
3625
4469
  )
3626
4470
  ] }),
3627
- /* @__PURE__ */ jsx10(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx10(
4471
+ /* @__PURE__ */ jsx13(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx13(
3628
4472
  "button",
3629
4473
  {
3630
4474
  type: "button",
@@ -3637,7 +4481,7 @@ function Toolbar({ className }) {
3637
4481
  },
3638
4482
  a.value
3639
4483
  )) }),
3640
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4484
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3641
4485
  "button",
3642
4486
  {
3643
4487
  type: "button",
@@ -3649,8 +4493,8 @@ function Toolbar({ className }) {
3649
4493
  children: blockDir === "rtl" ? "RTL" : "LTR"
3650
4494
  }
3651
4495
  ) }),
3652
- /* @__PURE__ */ jsxs9(Group, { children: [
3653
- /* @__PURE__ */ jsx10(
4496
+ /* @__PURE__ */ jsxs12(Group, { children: [
4497
+ /* @__PURE__ */ jsx13(
3654
4498
  "button",
3655
4499
  {
3656
4500
  type: "button",
@@ -3665,7 +4509,7 @@ function Toolbar({ className }) {
3665
4509
  children: "\u2022"
3666
4510
  }
3667
4511
  ),
3668
- /* @__PURE__ */ jsx10(
4512
+ /* @__PURE__ */ jsx13(
3669
4513
  "button",
3670
4514
  {
3671
4515
  type: "button",
@@ -3680,7 +4524,7 @@ function Toolbar({ className }) {
3680
4524
  children: "1."
3681
4525
  }
3682
4526
  ),
3683
- /* @__PURE__ */ jsx10(
4527
+ /* @__PURE__ */ jsx13(
3684
4528
  "button",
3685
4529
  {
3686
4530
  type: "button",
@@ -3694,7 +4538,7 @@ function Toolbar({ className }) {
3694
4538
  children: "\u21E4"
3695
4539
  }
3696
4540
  ),
3697
- /* @__PURE__ */ jsx10(
4541
+ /* @__PURE__ */ jsx13(
3698
4542
  "button",
3699
4543
  {
3700
4544
  type: "button",
@@ -3709,7 +4553,7 @@ function Toolbar({ className }) {
3709
4553
  }
3710
4554
  )
3711
4555
  ] }),
3712
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4556
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3713
4557
  "button",
3714
4558
  {
3715
4559
  type: "button",
@@ -3721,9 +4565,9 @@ function Toolbar({ className }) {
3721
4565
  children: "\u{1F517}"
3722
4566
  }
3723
4567
  ) }),
3724
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(TableMenu, {}) }),
3725
- /* @__PURE__ */ jsxs9(Group, { children: [
3726
- /* @__PURE__ */ jsx10(
4568
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(TableMenu, {}) }),
4569
+ /* @__PURE__ */ jsxs12(Group, { children: [
4570
+ /* @__PURE__ */ jsx13(
3727
4571
  "button",
3728
4572
  {
3729
4573
  type: "button",
@@ -3734,7 +4578,7 @@ function Toolbar({ className }) {
3734
4578
  children: "\u{1F5BC}"
3735
4579
  }
3736
4580
  ),
3737
- /* @__PURE__ */ jsx10(
4581
+ /* @__PURE__ */ jsx13(
3738
4582
  "input",
3739
4583
  {
3740
4584
  ref: imageInputRef,
@@ -3745,8 +4589,8 @@ function Toolbar({ className }) {
3745
4589
  }
3746
4590
  )
3747
4591
  ] }),
3748
- selectedEmbed && /* @__PURE__ */ jsxs9(Group, { children: [
3749
- IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx10(
4592
+ selectedEmbed && /* @__PURE__ */ jsxs12(Group, { children: [
4593
+ IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx13(
3750
4594
  "button",
3751
4595
  {
3752
4596
  type: "button",
@@ -3759,7 +4603,7 @@ function Toolbar({ className }) {
3759
4603
  },
3760
4604
  opt.value
3761
4605
  )),
3762
- /* @__PURE__ */ jsx10(
4606
+ /* @__PURE__ */ jsx13(
3763
4607
  "button",
3764
4608
  {
3765
4609
  type: "button",
@@ -3789,7 +4633,7 @@ function Toolbar({ className }) {
3789
4633
  }
3790
4634
  )
3791
4635
  ] }),
3792
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4636
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3793
4637
  "button",
3794
4638
  {
3795
4639
  type: "button",
@@ -3810,9 +4654,9 @@ function Toolbar({ className }) {
3810
4654
  function TableMenu() {
3811
4655
  const editor = useEditorContext();
3812
4656
  const inTable = editor.isInTable();
3813
- const [open, setOpen] = useState8(false);
3814
- const rootRef = useRef11(null);
3815
- useEffect8(() => {
4657
+ const [open, setOpen] = useState11(false);
4658
+ const rootRef = useRef12(null);
4659
+ useEffect10(() => {
3816
4660
  if (!open) return;
3817
4661
  const onDown = (e) => {
3818
4662
  if (!rootRef.current) return;
@@ -3822,8 +4666,8 @@ function TableMenu() {
3822
4666
  document.addEventListener("mousedown", onDown);
3823
4667
  return () => document.removeEventListener("mousedown", onDown);
3824
4668
  }, [open]);
3825
- return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
3826
- /* @__PURE__ */ jsx10(
4669
+ return /* @__PURE__ */ jsxs12("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
4670
+ /* @__PURE__ */ jsx13(
3827
4671
  "button",
3828
4672
  {
3829
4673
  type: "button",
@@ -3838,7 +4682,7 @@ function TableMenu() {
3838
4682
  children: "\u25A6"
3839
4683
  }
3840
4684
  ),
3841
- open && /* @__PURE__ */ jsxs9(
4685
+ open && /* @__PURE__ */ jsxs12(
3842
4686
  "div",
3843
4687
  {
3844
4688
  className: "ed-table-popover",
@@ -3850,7 +4694,7 @@ function TableMenu() {
3850
4694
  }
3851
4695
  },
3852
4696
  children: [
3853
- /* @__PURE__ */ jsx10(
4697
+ /* @__PURE__ */ jsx13(
3854
4698
  TableSizePicker,
3855
4699
  {
3856
4700
  onPick: (rows, cols) => {
@@ -3859,34 +4703,34 @@ function TableMenu() {
3859
4703
  }
3860
4704
  }
3861
4705
  ),
3862
- inTable && /* @__PURE__ */ jsxs9("div", { className: "ed-table-actions", children: [
3863
- /* @__PURE__ */ jsx10("hr", {}),
3864
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4706
+ inTable && /* @__PURE__ */ jsxs12("div", { className: "ed-table-actions", children: [
4707
+ /* @__PURE__ */ jsx13("hr", {}),
4708
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3865
4709
  setOpen(false);
3866
4710
  editor.insertRowAbove();
3867
4711
  }, children: "Inserir linha acima" }),
3868
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4712
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3869
4713
  setOpen(false);
3870
4714
  editor.insertRowBelow();
3871
4715
  }, children: "Inserir linha abaixo" }),
3872
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4716
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3873
4717
  setOpen(false);
3874
4718
  editor.insertColumnLeft();
3875
4719
  }, children: "Inserir coluna \xE0 esquerda" }),
3876
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4720
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3877
4721
  setOpen(false);
3878
4722
  editor.insertColumnRight();
3879
4723
  }, children: "Inserir coluna \xE0 direita" }),
3880
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4724
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3881
4725
  setOpen(false);
3882
4726
  editor.deleteCurrentRow();
3883
4727
  }, children: "Excluir linha" }),
3884
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4728
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3885
4729
  setOpen(false);
3886
4730
  editor.deleteCurrentColumn();
3887
4731
  }, children: "Excluir coluna" }),
3888
- /* @__PURE__ */ jsx10("hr", {}),
3889
- editor.hasTableRectSelection() && /* @__PURE__ */ jsx10(
4732
+ /* @__PURE__ */ jsx13("hr", {}),
4733
+ editor.hasTableRectSelection() && /* @__PURE__ */ jsx13(
3890
4734
  "button",
3891
4735
  {
3892
4736
  type: "button",
@@ -3897,19 +4741,19 @@ function TableMenu() {
3897
4741
  children: "Mesclar c\xE9lulas selecionadas"
3898
4742
  }
3899
4743
  ),
3900
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4744
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3901
4745
  setOpen(false);
3902
4746
  editor.mergeRight();
3903
4747
  }, children: "Mesclar com c\xE9lula \xE0 direita" }),
3904
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4748
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3905
4749
  setOpen(false);
3906
4750
  editor.mergeDown();
3907
4751
  }, children: "Mesclar com c\xE9lula abaixo" }),
3908
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4752
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3909
4753
  setOpen(false);
3910
4754
  editor.splitCell();
3911
4755
  }, children: "Dividir c\xE9lulas mescladas" }),
3912
- /* @__PURE__ */ jsx10(
4756
+ /* @__PURE__ */ jsx13(
3913
4757
  "button",
3914
4758
  {
3915
4759
  type: "button",
@@ -3930,11 +4774,11 @@ function TableMenu() {
3930
4774
  var PICKER_MAX_ROWS = 8;
3931
4775
  var PICKER_MAX_COLS = 10;
3932
4776
  function TableSizePicker({ onPick }) {
3933
- const [hover, setHover] = useState8(null);
4777
+ const [hover, setHover] = useState11(null);
3934
4778
  const label = hover ? `${hover.r + 1} \xD7 ${hover.c + 1}` : "Inserir tabela";
3935
- return /* @__PURE__ */ jsxs9("div", { className: "ed-table-picker", children: [
3936
- /* @__PURE__ */ jsx10("div", { className: "ed-table-picker-label", children: label }),
3937
- /* @__PURE__ */ jsx10(
4779
+ return /* @__PURE__ */ jsxs12("div", { className: "ed-table-picker", children: [
4780
+ /* @__PURE__ */ jsx13("div", { className: "ed-table-picker-label", children: label }),
4781
+ /* @__PURE__ */ jsx13(
3938
4782
  "div",
3939
4783
  {
3940
4784
  className: "ed-table-picker-grid",
@@ -3947,7 +4791,7 @@ function TableSizePicker({ onPick }) {
3947
4791
  { length: PICKER_MAX_ROWS },
3948
4792
  (_, r) => Array.from({ length: PICKER_MAX_COLS }, (_2, c) => {
3949
4793
  const filled = hover != null && r <= hover.r && c <= hover.c;
3950
- return /* @__PURE__ */ jsx10(
4794
+ return /* @__PURE__ */ jsx13(
3951
4795
  "button",
3952
4796
  {
3953
4797
  type: "button",
@@ -3977,10 +4821,10 @@ function blockSelectValue(type, level) {
3977
4821
  return type;
3978
4822
  }
3979
4823
  function Group({ children }) {
3980
- return /* @__PURE__ */ jsx10("div", { className: "ed-toolbar-group", children });
4824
+ return /* @__PURE__ */ jsx13("div", { className: "ed-toolbar-group", children });
3981
4825
  }
3982
4826
  function MarkButton({ title, pressed, onClick, children }) {
3983
- return /* @__PURE__ */ jsx10(
4827
+ return /* @__PURE__ */ jsx13(
3984
4828
  "button",
3985
4829
  {
3986
4830
  type: "button",
@@ -4001,6 +4845,7 @@ export {
4001
4845
  LinkDialog,
4002
4846
  NodeView,
4003
4847
  PageConfigDialog,
4848
+ RemoteCursorsOverlay,
4004
4849
  Toolbar,
4005
4850
  applyDomSelection,
4006
4851
  contentHeight,
@@ -4012,6 +4857,7 @@ export {
4012
4857
  getCellElement,
4013
4858
  getFragmentForOffset,
4014
4859
  isTableRectSelection,
4860
+ locatePoint,
4015
4861
  readDomSelection,
4016
4862
  renderInline,
4017
4863
  selectionsEqual,