@sofereditor/react 0.1.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,17 +1726,18 @@ 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}`;
1155
1733
  const layout = op.insert.layout ?? "inline";
1734
+ const commentMarkId = op.attributes?.comment?.markId;
1156
1735
  if (layout === "wrap-left" || layout === "wrap-right") {
1157
1736
  wrapAnchors.push(
1158
- /* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1737
+ /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1159
1738
  );
1160
1739
  body.push(
1161
- /* @__PURE__ */ jsx6(
1740
+ /* @__PURE__ */ jsx9(
1162
1741
  "span",
1163
1742
  {
1164
1743
  "data-embed-phantom": "true",
@@ -1170,14 +1749,21 @@ function renderInline(delta, keyPrefix) {
1170
1749
  )
1171
1750
  );
1172
1751
  } else {
1173
- body.push(/* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset }, key));
1752
+ const imgNode = /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset }, key);
1753
+ if (commentMarkId) {
1754
+ body.push(
1755
+ /* @__PURE__ */ jsx9("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1756
+ );
1757
+ } else {
1758
+ body.push(imgNode);
1759
+ }
1174
1760
  }
1175
1761
  offset += 1;
1176
1762
  } else if (op.insert != null) {
1177
1763
  offset += 1;
1178
1764
  }
1179
1765
  }
1180
- 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" });
1181
1767
  return [...wrapAnchors, ...body];
1182
1768
  }
1183
1769
  var PHANTOM_STYLE = {
@@ -1187,6 +1773,11 @@ var PHANTOM_STYLE = {
1187
1773
  overflow: "hidden",
1188
1774
  verticalAlign: "baseline"
1189
1775
  };
1776
+ var LINK_STYLE = {
1777
+ color: "#2563eb",
1778
+ textDecoration: "underline",
1779
+ cursor: "text"
1780
+ };
1190
1781
  function imageEmbedPropsEqual(a, b) {
1191
1782
  if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;
1192
1783
  const x = a.embed;
@@ -1252,8 +1843,12 @@ function ImageEmbedViewImpl({
1252
1843
  };
1253
1844
  break;
1254
1845
  }
1255
- const imgStyle = hasCaption ? { width: embed.width, height: embed.height, display: "block" } : outerStyle;
1256
- const img = /* @__PURE__ */ jsx6(
1846
+ const imgStyle = {
1847
+ width: embed.width,
1848
+ height: embed.height,
1849
+ display: "block"
1850
+ };
1851
+ const img = /* @__PURE__ */ jsx9(
1257
1852
  "img",
1258
1853
  {
1259
1854
  src: embed.src,
@@ -1261,6 +1856,8 @@ function ImageEmbedViewImpl({
1261
1856
  height: embed.height,
1262
1857
  contentEditable: false,
1263
1858
  draggable: false,
1859
+ decoding: "sync",
1860
+ loading: "eager",
1264
1861
  "data-embed": "image",
1265
1862
  "data-embed-offset": offset,
1266
1863
  "data-embed-align": align ?? "",
@@ -1270,19 +1867,18 @@ function ImageEmbedViewImpl({
1270
1867
  alt: ""
1271
1868
  }
1272
1869
  );
1273
- if (!hasCaption) return img;
1274
1870
  const captionAlign = embed.captionAlign ?? "center";
1275
- return /* @__PURE__ */ jsxs6(
1871
+ return /* @__PURE__ */ jsxs9(
1276
1872
  "figure",
1277
1873
  {
1278
1874
  className: "ed-figure",
1279
1875
  contentEditable: false,
1280
- "data-embed-figure": "true",
1876
+ "data-embed-figure": hasCaption ? "true" : void 0,
1281
1877
  "data-embed-layout": layout,
1282
1878
  style: outerStyle,
1283
1879
  children: [
1284
1880
  img,
1285
- /* @__PURE__ */ jsx6(
1881
+ hasCaption && /* @__PURE__ */ jsx9(
1286
1882
  "figcaption",
1287
1883
  {
1288
1884
  className: "ed-figcaption",
@@ -1298,34 +1894,38 @@ function ImageEmbedViewImpl({
1298
1894
  function wrap(text, attrs) {
1299
1895
  let node = text;
1300
1896
  if (!attrs) return node;
1301
- if (attrs.bold) node = /* @__PURE__ */ jsx6("strong", { children: node });
1302
- if (attrs.italic) node = /* @__PURE__ */ jsx6("em", { children: node });
1303
- if (attrs.underline) node = /* @__PURE__ */ jsx6("u", { children: node });
1304
- 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 });
1305
1901
  const styleParts = {};
1306
1902
  if (attrs.color) styleParts.color = attrs.color;
1307
1903
  if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;
1308
1904
  if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;
1309
1905
  if (Object.keys(styleParts).length > 0) {
1310
- node = /* @__PURE__ */ jsx6("span", { style: styleParts, children: node });
1906
+ node = /* @__PURE__ */ jsx9("span", { style: styleParts, children: node });
1311
1907
  }
1312
1908
  if (attrs.link?.href) {
1313
- node = /* @__PURE__ */ jsx6(
1909
+ node = /* @__PURE__ */ jsx9(
1314
1910
  "a",
1315
1911
  {
1316
1912
  href: attrs.link.href,
1317
1913
  title: attrs.link.title,
1318
1914
  rel: "noopener noreferrer",
1319
1915
  target: "_blank",
1916
+ style: LINK_STYLE,
1320
1917
  onClick: (e) => {
1321
- 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
+ }
1322
1922
  },
1323
1923
  children: node
1324
1924
  }
1325
1925
  );
1326
1926
  }
1327
1927
  if (attrs.comment?.markId) {
1328
- 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 });
1329
1929
  }
1330
1930
  return node;
1331
1931
  }
@@ -1370,19 +1970,19 @@ function sliceDelta(delta, start, end) {
1370
1970
 
1371
1971
  // src/TableResizeOverlay.tsx
1372
1972
  import {
1373
- useCallback as useCallback2,
1374
- useEffect as useEffect5,
1375
- useLayoutEffect as useLayoutEffect2,
1376
- useRef as useRef5,
1377
- useState as useState5
1973
+ useCallback as useCallback4,
1974
+ useEffect as useEffect7,
1975
+ useLayoutEffect as useLayoutEffect3,
1976
+ useRef as useRef6,
1977
+ useState as useState7
1378
1978
  } from "react";
1379
- import { Fragment as Fragment2, jsx as jsx7 } from "react/jsx-runtime";
1979
+ import { Fragment as Fragment4, jsx as jsx10 } from "react/jsx-runtime";
1380
1980
  function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1381
1981
  const editor = useEditorContext();
1382
- const [positions, setPositions] = useState5(null);
1383
- const [layout, setLayout] = useState5(null);
1384
- const draggingRef = useRef5(null);
1385
- const measure = useCallback2(() => {
1982
+ const [positions, setPositions] = useState7(null);
1983
+ const [layout, setLayout] = useState7(null);
1984
+ const draggingRef = useRef6(null);
1985
+ const measure = useCallback4(() => {
1386
1986
  const table = tableRef.current;
1387
1987
  if (!table) return;
1388
1988
  const tableRect = table.getBoundingClientRect();
@@ -1412,17 +2012,17 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1412
2012
  }
1413
2013
  setLayout({ rights, height: tableRect.height });
1414
2014
  }, [cols, tableRef]);
1415
- useLayoutEffect2(() => {
2015
+ useLayoutEffect3(() => {
1416
2016
  measure();
1417
2017
  }, [measure]);
1418
- useEffect5(() => {
2018
+ useEffect7(() => {
1419
2019
  const table = tableRef.current;
1420
2020
  if (!table) return;
1421
2021
  const ro = new ResizeObserver(() => measure());
1422
2022
  ro.observe(table);
1423
2023
  return () => ro.disconnect();
1424
2024
  }, [measure, tableRef]);
1425
- const onPointerDown = useCallback2(
2025
+ const onPointerDown = useCallback4(
1426
2026
  (col) => (e) => {
1427
2027
  e.preventDefault();
1428
2028
  e.stopPropagation();
@@ -1436,7 +2036,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1436
2036
  },
1437
2037
  [layout, tableRef]
1438
2038
  );
1439
- const onPointerMove = useCallback2(
2039
+ const onPointerMove = useCallback4(
1440
2040
  (e) => {
1441
2041
  const d = draggingRef.current;
1442
2042
  if (!d) return;
@@ -1446,7 +2046,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1446
2046
  },
1447
2047
  [blockIndex, editor]
1448
2048
  );
1449
- const onPointerUp = useCallback2((e) => {
2049
+ const onPointerUp = useCallback4((e) => {
1450
2050
  draggingRef.current = null;
1451
2051
  setPositions(null);
1452
2052
  try {
@@ -1465,7 +2065,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1465
2065
  zIndex: 5
1466
2066
  });
1467
2067
  void positions;
1468
- 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(
1469
2069
  "div",
1470
2070
  {
1471
2071
  contentEditable: false,
@@ -1482,10 +2082,10 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1482
2082
  }
1483
2083
 
1484
2084
  // src/NodeView.tsx
1485
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2085
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1486
2086
  function NodeView({ block, index, children, fragment, tableFragment }) {
1487
2087
  if (block.type === "table") {
1488
- return /* @__PURE__ */ jsx8(TableView, { block, index, tableFragment });
2088
+ return /* @__PURE__ */ jsx11(TableView, { block, index, tableFragment });
1489
2089
  }
1490
2090
  const inline = fragment ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index) : renderInline(block.delta, index);
1491
2091
  const common = commonBlockProps(block.attrs, index, block.type, fragment);
@@ -1493,7 +2093,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1493
2093
  case "heading": {
1494
2094
  const level = clampLevel(block.attrs.level);
1495
2095
  const Tag = `h${level}`;
1496
- return /* @__PURE__ */ jsx8(
2096
+ return /* @__PURE__ */ jsx11(
1497
2097
  Tag,
1498
2098
  {
1499
2099
  ...common,
@@ -1503,7 +2103,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1503
2103
  );
1504
2104
  }
1505
2105
  case "blockquote":
1506
- return /* @__PURE__ */ jsx8(
2106
+ return /* @__PURE__ */ jsx11(
1507
2107
  "blockquote",
1508
2108
  {
1509
2109
  ...common,
@@ -1512,18 +2112,18 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1512
2112
  }
1513
2113
  );
1514
2114
  case "codeBlock":
1515
- return /* @__PURE__ */ jsx8(
2115
+ return /* @__PURE__ */ jsx11(
1516
2116
  "pre",
1517
2117
  {
1518
2118
  ...common,
1519
2119
  "data-language": block.attrs.language ?? void 0,
1520
2120
  className: `ed-block ed-codeblock${alignClass(block.attrs.align)}`,
1521
- children: /* @__PURE__ */ jsx8("code", { children: inline })
2121
+ children: /* @__PURE__ */ jsx11("code", { children: inline })
1522
2122
  }
1523
2123
  );
1524
2124
  case "listItem": {
1525
2125
  const level = clampListLevel(block.attrs.listLevel);
1526
- return /* @__PURE__ */ jsxs7(
2126
+ return /* @__PURE__ */ jsxs10(
1527
2127
  "li",
1528
2128
  {
1529
2129
  ...common,
@@ -1539,7 +2139,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1539
2139
  }
1540
2140
  case "paragraph":
1541
2141
  default:
1542
- return /* @__PURE__ */ jsx8(
2142
+ return /* @__PURE__ */ jsx11(
1543
2143
  "div",
1544
2144
  {
1545
2145
  ...common,
@@ -1584,7 +2184,7 @@ function TableView({ block, index, tableFragment }) {
1584
2184
  const cols = clampPositive(block.attrs.cols);
1585
2185
  const cells = block.cells ?? [];
1586
2186
  const widths = readColWidths(block.attrs.colWidths, cols);
1587
- const tableRef = useRef6(null);
2187
+ const tableRef = useRef7(null);
1588
2188
  const rowStart = tableFragment?.rowStart ?? 0;
1589
2189
  const rowEnd = tableFragment?.rowEnd ?? rows;
1590
2190
  const isFirstFragment = !tableFragment || tableFragment.index === 0;
@@ -1594,8 +2194,8 @@ function TableView({ block, index, tableFragment }) {
1594
2194
  if (editor.selection.focus.blockIndex !== index) return null;
1595
2195
  return tableRectSelection(editor.doc, editor.selection);
1596
2196
  }, [editor.doc, editor.selection, index]);
1597
- return /* @__PURE__ */ jsxs7("div", { className: "ed-table-wrap", children: [
1598
- /* @__PURE__ */ jsxs7(
2197
+ return /* @__PURE__ */ jsxs10("div", { className: "ed-table-wrap", children: [
2198
+ /* @__PURE__ */ jsxs10(
1599
2199
  "table",
1600
2200
  {
1601
2201
  ref: tableRef,
@@ -1603,10 +2203,10 @@ function TableView({ block, index, tableFragment }) {
1603
2203
  "data-block-type": "table",
1604
2204
  className: "ed-block ed-table",
1605
2205
  children: [
1606
- widths && /* @__PURE__ */ jsx8("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ jsx8("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
1607
- /* @__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) => {
1608
2208
  const r = rowStart + i;
1609
- 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) => {
1610
2210
  const flat = r * cols + c;
1611
2211
  const cell = cells[flat];
1612
2212
  if (cell?.attrs.covered === true) return null;
@@ -1614,7 +2214,7 @@ function TableView({ block, index, tableFragment }) {
1614
2214
  const colspan = spanAttr(cell?.attrs.colspan);
1615
2215
  const delta = cell?.delta ?? [];
1616
2216
  const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
1617
- return /* @__PURE__ */ jsx8(
2217
+ return /* @__PURE__ */ jsx11(
1618
2218
  "td",
1619
2219
  {
1620
2220
  "data-cell-index": flat,
@@ -1624,6 +2224,7 @@ function TableView({ block, index, tableFragment }) {
1624
2224
  "data-cell-colspan": colspan,
1625
2225
  rowSpan: rowspan > 1 ? rowspan : void 0,
1626
2226
  colSpan: colspan > 1 ? colspan : void 0,
2227
+ style: cell?.attrs.align ? { textAlign: cell.attrs.align } : void 0,
1627
2228
  className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
1628
2229
  children: renderInline(delta, `t${index}-c${flat}`)
1629
2230
  },
@@ -1634,7 +2235,7 @@ function TableView({ block, index, tableFragment }) {
1634
2235
  ]
1635
2236
  }
1636
2237
  ),
1637
- isFirstFragment && /* @__PURE__ */ jsx8(TableResizeOverlay, { tableRef, blockIndex: index, cols })
2238
+ isFirstFragment && /* @__PURE__ */ jsx11(TableResizeOverlay, { tableRef, blockIndex: index, cols })
1638
2239
  ] });
1639
2240
  }
1640
2241
  function readColWidths(raw, cols) {
@@ -1656,7 +2257,7 @@ function clampPositive(n) {
1656
2257
  }
1657
2258
 
1658
2259
  // src/usePagination.ts
1659
- 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";
1660
2261
  var A4_PAGE = {
1661
2262
  width: 794,
1662
2263
  height: 1123,
@@ -1665,8 +2266,9 @@ var A4_PAGE = {
1665
2266
  marginLeft: 96,
1666
2267
  marginRight: 96
1667
2268
  };
1668
- function contentHeight(g) {
1669
- return g.height - g.marginTop - g.marginBottom;
2269
+ function contentHeight(g, pageIndex = 0) {
2270
+ const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;
2271
+ return g.height - g.marginTop - g.marginBottom - extra;
1670
2272
  }
1671
2273
  function contentWidth(g) {
1672
2274
  return g.width - g.marginLeft - g.marginRight;
@@ -1681,17 +2283,22 @@ function defaultPageLayout(topLevelCount) {
1681
2283
  };
1682
2284
  }
1683
2285
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1684
- const [phase, setPhase] = useState6("measure");
1685
- const [layout, setLayout] = useState6(() => defaultPageLayout(topLevelCount));
1686
- const lastDepsRef = useRef7([]);
1687
- const currentDeps = [...deps, topLevelCount, geometry];
1688
- if (!shallowArrayEqual(lastDepsRef.current, currentDeps)) {
2286
+ const [phase, setPhase] = useState8("measure");
2287
+ const [layout, setLayout] = useState8(() => defaultPageLayout(topLevelCount));
2288
+ const lastDepsRef = useRef8(null);
2289
+ useLayoutEffect4(() => {
2290
+ const currentDeps = [...deps, topLevelCount, geometry];
2291
+ if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
2292
+ return;
2293
+ }
1689
2294
  lastDepsRef.current = currentDeps;
1690
- if (phase !== "measure") setPhase("measure");
1691
- const next = defaultPageLayout(topLevelCount);
1692
- if (!layoutsDeepEqual(layout, next)) setLayout(next);
1693
- }
1694
- useLayoutEffect3(() => {
2295
+ setLayout((prev) => {
2296
+ const next = defaultPageLayout(topLevelCount);
2297
+ return layoutsDeepEqual(prev, next) ? prev : next;
2298
+ });
2299
+ setPhase("measure");
2300
+ });
2301
+ useLayoutEffect4(() => {
1695
2302
  if (phase !== "measure") return;
1696
2303
  const root = rootRef.current;
1697
2304
  if (!root) return;
@@ -1700,19 +2307,20 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1700
2307
  if (!layoutsDeepEqual(layout, next)) setLayout(next);
1701
2308
  setPhase("stable");
1702
2309
  }, [phase, layout, geometry, topLevelCount, rootRef]);
1703
- return layout;
2310
+ return { layout, phase };
1704
2311
  }
1705
2312
  function isUnfragmented(layout) {
1706
2313
  return layout.pages.length === 1 && layout.pages[0].slots.every(
1707
- (s) => s.fragment === void 0 && s.tableFragment === void 0
2314
+ (s) => s.fragment === void 0 && s.tableFragment === void 0 && s.listFragment === void 0
1708
2315
  );
1709
2316
  }
1710
2317
  function computeLayout(root, geometry, topLevelCount) {
1711
2318
  const tops = collectTopLevelElements(root);
1712
2319
  if (tops.length === 0) return defaultPageLayout(topLevelCount);
1713
- const limit = contentHeight(geometry);
2320
+ const limitFor = (pageIndex) => contentHeight(geometry, pageIndex);
1714
2321
  const pages = [{ slots: [] }];
1715
2322
  let currentPage = pages[0];
2323
+ let limit = limitFor(0);
1716
2324
  let used = 0;
1717
2325
  const cap = Math.min(tops.length, topLevelCount);
1718
2326
  for (let i = 0; i < cap; i++) {
@@ -1724,14 +2332,23 @@ function computeLayout(root, geometry, topLevelCount) {
1724
2332
  continue;
1725
2333
  }
1726
2334
  if (isFragmentable(el)) {
1727
- const result = placeFragmentedBlock(el, i, pages, used, limit);
2335
+ const result = placeFragmentedBlock(el, i, pages, used, limitFor);
1728
2336
  currentPage = pages[pages.length - 1];
2337
+ limit = limitFor(pages.length - 1);
1729
2338
  used = result.lastUsed;
1730
2339
  continue;
1731
2340
  }
1732
2341
  if (isTableTopLevel(el)) {
1733
- const result = placeFragmentedTable(el, i, pages, used, limit);
2342
+ const result = placeFragmentedTable(el, i, pages, used, limitFor);
1734
2343
  currentPage = pages[pages.length - 1];
2344
+ limit = limitFor(pages.length - 1);
2345
+ used = result.lastUsed;
2346
+ continue;
2347
+ }
2348
+ if (isListTopLevel(el)) {
2349
+ const result = placeFragmentedList(el, i, pages, used, limitFor);
2350
+ currentPage = pages[pages.length - 1];
2351
+ limit = limitFor(pages.length - 1);
1735
2352
  used = result.lastUsed;
1736
2353
  continue;
1737
2354
  }
@@ -1739,10 +2356,12 @@ function computeLayout(root, geometry, topLevelCount) {
1739
2356
  currentPage.slots.push({ topLevelIndex: i });
1740
2357
  pages.push({ slots: [] });
1741
2358
  currentPage = pages[pages.length - 1];
2359
+ limit = limitFor(pages.length - 1);
1742
2360
  used = 0;
1743
2361
  } else {
1744
2362
  pages.push({ slots: [] });
1745
2363
  currentPage = pages[pages.length - 1];
2364
+ limit = limitFor(pages.length - 1);
1746
2365
  currentPage.slots.push({ topLevelIndex: i });
1747
2366
  used = h;
1748
2367
  }
@@ -1750,7 +2369,8 @@ function computeLayout(root, geometry, topLevelCount) {
1750
2369
  if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();
1751
2370
  return { pages };
1752
2371
  }
1753
- function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
2372
+ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limitFor) {
2373
+ let limit = limitFor(pages.length - 1);
1754
2374
  const totalChars = getBlockTextLength(el);
1755
2375
  if (totalChars === 0) {
1756
2376
  const h = elTotalHeight(el);
@@ -1758,6 +2378,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1758
2378
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1759
2379
  pages.push({ slots: [] });
1760
2380
  currentPage2 = pages[pages.length - 1];
2381
+ limit = limitFor(pages.length - 1);
1761
2382
  startUsed = 0;
1762
2383
  }
1763
2384
  currentPage2.slots.push({ topLevelIndex });
@@ -1770,6 +2391,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1770
2391
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1771
2392
  pages.push({ slots: [] });
1772
2393
  currentPage2 = pages[pages.length - 1];
2394
+ limit = limitFor(pages.length - 1);
1773
2395
  startUsed = 0;
1774
2396
  }
1775
2397
  currentPage2.slots.push({ topLevelIndex });
@@ -1784,6 +2406,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1784
2406
  if (available <= 0) {
1785
2407
  pages.push({ slots: [] });
1786
2408
  currentPage = pages[pages.length - 1];
2409
+ limit = limitFor(pages.length - 1);
1787
2410
  used = 0;
1788
2411
  continue;
1789
2412
  }
@@ -1800,6 +2423,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1800
2423
  } else {
1801
2424
  pages.push({ slots: [] });
1802
2425
  currentPage = pages[pages.length - 1];
2426
+ limit = limitFor(pages.length - 1);
1803
2427
  used = 0;
1804
2428
  continue;
1805
2429
  }
@@ -1817,6 +2441,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1817
2441
  if (lineIdx < lines.length) {
1818
2442
  pages.push({ slots: [] });
1819
2443
  currentPage = pages[pages.length - 1];
2444
+ limit = limitFor(pages.length - 1);
1820
2445
  used = 0;
1821
2446
  }
1822
2447
  }
@@ -1905,7 +2530,8 @@ function isFragmentable(el) {
1905
2530
  function isTableTopLevel(el) {
1906
2531
  return el.querySelector(':scope > table[data-block-type="table"]') !== null;
1907
2532
  }
1908
- function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
2533
+ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limitFor) {
2534
+ let limit = limitFor(pages.length - 1);
1909
2535
  const table = el.querySelector(':scope > table[data-block-type="table"]');
1910
2536
  const tbody = table?.querySelector(":scope > tbody");
1911
2537
  const trs = tbody ? Array.from(tbody.children) : [];
@@ -1915,6 +2541,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1915
2541
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1916
2542
  pages.push({ slots: [] });
1917
2543
  currentPage2 = pages[pages.length - 1];
2544
+ limit = limitFor(pages.length - 1);
1918
2545
  startUsed = 0;
1919
2546
  }
1920
2547
  currentPage2.slots.push({ topLevelIndex });
@@ -1946,6 +2573,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1946
2573
  if (available <= 0) {
1947
2574
  pages.push({ slots: [] });
1948
2575
  currentPage = pages[pages.length - 1];
2576
+ limit = limitFor(pages.length - 1);
1949
2577
  used = 0;
1950
2578
  continue;
1951
2579
  }
@@ -1964,6 +2592,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1964
2592
  } else {
1965
2593
  pages.push({ slots: [] });
1966
2594
  currentPage = pages[pages.length - 1];
2595
+ limit = limitFor(pages.length - 1);
1967
2596
  used = 0;
1968
2597
  continue;
1969
2598
  }
@@ -1981,6 +2610,77 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1981
2610
  if (rowIdx < trs.length) {
1982
2611
  pages.push({ slots: [] });
1983
2612
  currentPage = pages[pages.length - 1];
2613
+ limit = limitFor(pages.length - 1);
2614
+ used = 0;
2615
+ }
2616
+ }
2617
+ return { lastUsed: used };
2618
+ }
2619
+ function isListTopLevel(el) {
2620
+ if (el.tagName !== "OL" && el.tagName !== "UL") return false;
2621
+ return el.classList.contains("ed-list");
2622
+ }
2623
+ function placeFragmentedList(el, topLevelIndex, pages, startUsed, limitFor) {
2624
+ let limit = limitFor(pages.length - 1);
2625
+ const items = [];
2626
+ for (const c of Array.from(el.children)) {
2627
+ if (c instanceof HTMLLIElement && c.classList.contains("ed-listitem")) {
2628
+ items.push(c);
2629
+ }
2630
+ }
2631
+ if (items.length === 0) {
2632
+ const h = elTotalHeight(el);
2633
+ let currentPage2 = pages[pages.length - 1];
2634
+ if (startUsed + h > limit && currentPage2.slots.length > 0) {
2635
+ pages.push({ slots: [] });
2636
+ currentPage2 = pages[pages.length - 1];
2637
+ limit = limitFor(pages.length - 1);
2638
+ startUsed = 0;
2639
+ }
2640
+ currentPage2.slots.push({ topLevelIndex });
2641
+ return { lastUsed: startUsed + h };
2642
+ }
2643
+ const heights = items.map((li) => elTotalHeight(li));
2644
+ const sumHeights = heights.reduce((a, b) => a + b, 0);
2645
+ const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);
2646
+ let i = 0;
2647
+ let currentPage = pages[pages.length - 1];
2648
+ let used = startUsed;
2649
+ let fragIndex = 0;
2650
+ while (i < items.length) {
2651
+ const available = Math.max(0, limit - used);
2652
+ const isFirstFragment = fragIndex === 0;
2653
+ let bestK = -1;
2654
+ let runningH = isFirstFragment ? wrapperOverhead : 0;
2655
+ for (let k = i; k < items.length; k++) {
2656
+ runningH += heights[k];
2657
+ if (runningH <= available) bestK = k;
2658
+ else break;
2659
+ }
2660
+ if (bestK < 0) {
2661
+ if (currentPage.slots.length === 0) {
2662
+ bestK = i;
2663
+ } else {
2664
+ pages.push({ slots: [] });
2665
+ currentPage = pages[pages.length - 1];
2666
+ limit = limitFor(pages.length - 1);
2667
+ used = 0;
2668
+ continue;
2669
+ }
2670
+ }
2671
+ currentPage.slots.push({
2672
+ topLevelIndex,
2673
+ listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 }
2674
+ });
2675
+ let consumed = isFirstFragment ? wrapperOverhead : 0;
2676
+ for (let k = i; k <= bestK; k++) consumed += heights[k];
2677
+ used += consumed;
2678
+ i = bestK + 1;
2679
+ fragIndex++;
2680
+ if (i < items.length) {
2681
+ pages.push({ slots: [] });
2682
+ currentPage = pages[pages.length - 1];
2683
+ limit = limitFor(pages.length - 1);
1984
2684
  used = 0;
1985
2685
  }
1986
2686
  }
@@ -2056,23 +2756,31 @@ function layoutsDeepEqual(a, b) {
2056
2756
  return false;
2057
2757
  }
2058
2758
  }
2759
+ const lA = sA[j].listFragment;
2760
+ const lB = sB[j].listFragment;
2761
+ if (lA || lB) {
2762
+ if (!lA || !lB) return false;
2763
+ if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {
2764
+ return false;
2765
+ }
2766
+ }
2059
2767
  }
2060
2768
  }
2061
2769
  return true;
2062
2770
  }
2063
2771
 
2064
2772
  // src/useEditor.ts
2065
- 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";
2066
2774
 
2067
2775
  // src/usePageSettings.ts
2068
- import { useCallback as useCallback3, useRef as useRef8, useSyncExternalStore } from "react";
2776
+ import { useCallback as useCallback5, useRef as useRef9, useSyncExternalStore } from "react";
2069
2777
  function usePageSettings(doc) {
2070
- const cacheRef = useRef8(null);
2071
- const subscribe = useCallback3(
2778
+ const cacheRef = useRef9(null);
2779
+ const subscribe = useCallback5(
2072
2780
  (notify) => doc.observePageSettings(notify),
2073
2781
  [doc]
2074
2782
  );
2075
- const getSnapshot = useCallback3(() => {
2783
+ const getSnapshot = useCallback5(() => {
2076
2784
  const next = doc.getPageSettings();
2077
2785
  const prev = cacheRef.current;
2078
2786
  if (prev && shallowEqual(prev, next)) return prev;
@@ -2082,7 +2790,7 @@ function usePageSettings(doc) {
2082
2790
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
2083
2791
  }
2084
2792
  function shallowEqual(a, b) {
2085
- return a.width === b.width && a.height === b.height && a.marginTop === b.marginTop && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft && a.marginRight === b.marginRight && a.preset === b.preset;
2793
+ return a.width === b.width && a.height === b.height && a.marginTop === b.marginTop && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft && a.marginRight === b.marginRight && a.preset === b.preset && a.systemHeaderTitle === b.systemHeaderTitle && a.systemHeaderAuthor === b.systemHeaderAuthor;
2086
2794
  }
2087
2795
 
2088
2796
  // src/useEditor.ts
@@ -2098,6 +2806,7 @@ import {
2098
2806
  mergeDown as cmdMergeDown,
2099
2807
  mergeRight as cmdMergeRight,
2100
2808
  mergeSelection as cmdMergeSelection,
2809
+ moveEmbedAnchor as cmdMoveEmbedAnchor,
2101
2810
  setColumnWidth as cmdSetColumnWidth,
2102
2811
  setImageAttrs as cmdSetImageAttrs,
2103
2812
  splitCell as cmdSplitCell,
@@ -2114,6 +2823,7 @@ import {
2114
2823
  orderedRange,
2115
2824
  removeMark as cmdRemoveMark,
2116
2825
  setBlockAttr as cmdSetBlockAttr,
2826
+ setCellAttr as cmdSetCellAttr,
2117
2827
  setBlockType as cmdSetBlockType,
2118
2828
  setMark as cmdSetMark,
2119
2829
  splitListItem as cmdSplitListItem,
@@ -2125,19 +2835,19 @@ var MAX_INSERT_WIDTH = 600;
2125
2835
  function useEditor(opts = {}) {
2126
2836
  const doc = useMemo3(() => opts.document ?? new EditorDocument(), [opts.document]);
2127
2837
  const history = useMemo3(() => new EditorHistory(doc), [doc]);
2128
- const [snapshot, setSnapshot] = useState7(() => doc.toJSON());
2129
- const [selection, setSelectionState] = useState7(
2838
+ const [snapshot, setSnapshot] = useState9(() => doc.toJSON());
2839
+ const [selection, setSelectionState] = useState9(
2130
2840
  () => collapsedSelection({ blockIndex: 0, offset: 0 })
2131
2841
  );
2132
- const selectionRef = useRef9(selection);
2842
+ const selectionRef = useRef10(selection);
2133
2843
  selectionRef.current = selection;
2134
- const pendingMarksRef = useRef9({});
2135
- const [pendingMarks, setPendingMarksState] = useState7({});
2136
- const setPendingMarks = useCallback4((next) => {
2844
+ const pendingMarksRef = useRef10({});
2845
+ const [pendingMarks, setPendingMarksState] = useState9({});
2846
+ const setPendingMarks = useCallback6((next) => {
2137
2847
  pendingMarksRef.current = next;
2138
2848
  setPendingMarksState(next);
2139
2849
  }, []);
2140
- useEffect6(() => {
2850
+ useEffect8(() => {
2141
2851
  let scheduled = false;
2142
2852
  let cancelled = false;
2143
2853
  let frame = 0;
@@ -2164,8 +2874,8 @@ function useEditor(opts = {}) {
2164
2874
  doc.ydoc.off("afterTransaction", schedule);
2165
2875
  };
2166
2876
  }, [doc]);
2167
- const getSelection = useCallback4(() => selectionRef.current, []);
2168
- const setSelection = useCallback4(
2877
+ const getSelection = useCallback6(() => selectionRef.current, []);
2878
+ const setSelection = useCallback6(
2169
2879
  (sel) => {
2170
2880
  const prev = selectionRef.current;
2171
2881
  selectionRef.current = sel;
@@ -2180,16 +2890,16 @@ function useEditor(opts = {}) {
2180
2890
  },
2181
2891
  []
2182
2892
  );
2183
- const ctxRef = useRef9({ doc, getSelection, setSelection });
2893
+ const ctxRef = useRef10({ doc, getSelection, setSelection });
2184
2894
  ctxRef.current = { doc, getSelection, setSelection };
2185
- const consumePendingMarks = useCallback4(() => {
2895
+ const consumePendingMarks = useCallback6(() => {
2186
2896
  const current = pendingMarksRef.current;
2187
2897
  if (Object.keys(current).length === 0) return void 0;
2188
2898
  pendingMarksRef.current = {};
2189
2899
  setPendingMarksState({});
2190
2900
  return current;
2191
2901
  }, []);
2192
- const isMarkActive = useCallback4(
2902
+ const isMarkActive = useCallback6(
2193
2903
  (name, value) => {
2194
2904
  const sel = selectionRef.current;
2195
2905
  const { start, end } = orderedRange(sel);
@@ -2220,7 +2930,7 @@ function useEditor(opts = {}) {
2220
2930
  },
2221
2931
  [doc]
2222
2932
  );
2223
- const getActiveMarks = useCallback4(() => {
2933
+ const getActiveMarks = useCallback6(() => {
2224
2934
  const sel = selectionRef.current;
2225
2935
  const { start, end } = orderedRange(sel);
2226
2936
  if (start.blockIndex !== end.blockIndex) {
@@ -2234,7 +2944,7 @@ function useEditor(opts = {}) {
2234
2944
  }
2235
2945
  return getMarksInRange(yText, start.offset, end.offset);
2236
2946
  }, [doc]);
2237
- const toggleMark = useCallback4(
2947
+ const toggleMark = useCallback6(
2238
2948
  (name, value) => {
2239
2949
  const sel = selectionRef.current;
2240
2950
  const { start, end } = orderedRange(sel);
@@ -2254,7 +2964,7 @@ function useEditor(opts = {}) {
2254
2964
  },
2255
2965
  [isMarkActive, setPendingMarks]
2256
2966
  );
2257
- const setMark = useCallback4(
2967
+ const setMark = useCallback6(
2258
2968
  (name, value) => {
2259
2969
  const sel = selectionRef.current;
2260
2970
  const { start, end } = orderedRange(sel);
@@ -2267,7 +2977,7 @@ function useEditor(opts = {}) {
2267
2977
  },
2268
2978
  [setPendingMarks]
2269
2979
  );
2270
- const removeMark = useCallback4(
2980
+ const removeMark = useCallback6(
2271
2981
  (name) => {
2272
2982
  const sel = selectionRef.current;
2273
2983
  const { start, end } = orderedRange(sel);
@@ -2280,7 +2990,7 @@ function useEditor(opts = {}) {
2280
2990
  },
2281
2991
  [setPendingMarks]
2282
2992
  );
2283
- const getBlockType = useCallback4(() => {
2993
+ const getBlockType = useCallback6(() => {
2284
2994
  const sel = selectionRef.current;
2285
2995
  const { start, end } = orderedRange(sel);
2286
2996
  const first = doc.getBlockType(start.blockIndex);
@@ -2290,7 +3000,7 @@ function useEditor(opts = {}) {
2290
3000
  }
2291
3001
  return first;
2292
3002
  }, [doc]);
2293
- const getBlockAttr = useCallback4(
3003
+ const getBlockAttr = useCallback6(
2294
3004
  (key) => {
2295
3005
  const sel = selectionRef.current;
2296
3006
  const { start, end } = orderedRange(sel);
@@ -2303,16 +3013,29 @@ function useEditor(opts = {}) {
2303
3013
  },
2304
3014
  [doc]
2305
3015
  );
2306
- const setBlockType = useCallback4((type, attrs) => {
3016
+ const setBlockType = useCallback6((type, attrs) => {
2307
3017
  cmdSetBlockType(ctxRef.current, type, attrs);
2308
3018
  }, []);
2309
- const setBlockAttr = useCallback4(
3019
+ const setBlockAttr = useCallback6(
2310
3020
  (key, value) => {
2311
3021
  cmdSetBlockAttr(ctxRef.current, key, value);
2312
3022
  },
2313
3023
  []
2314
3024
  );
2315
- 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(
2316
3039
  (kind) => {
2317
3040
  const sel = selectionRef.current;
2318
3041
  const { start, end } = orderedRange(sel);
@@ -2324,110 +3047,116 @@ function useEditor(opts = {}) {
2324
3047
  },
2325
3048
  [doc]
2326
3049
  );
2327
- const toggleList = useCallback4((kind) => {
3050
+ const toggleList = useCallback6((kind) => {
2328
3051
  cmdToggleList(ctxRef.current, kind);
2329
3052
  }, []);
2330
- const indentList = useCallback4(() => {
3053
+ const indentList = useCallback6(() => {
2331
3054
  cmdIndentList(ctxRef.current);
2332
3055
  }, []);
2333
- const dedentList = useCallback4(() => {
3056
+ const dedentList = useCallback6(() => {
2334
3057
  cmdDedentList(ctxRef.current);
2335
3058
  }, []);
2336
- const splitListItem = useCallback4(() => {
3059
+ const splitListItem = useCallback6(() => {
2337
3060
  return cmdSplitListItem(ctxRef.current);
2338
3061
  }, []);
2339
- const isInTable = useCallback4(() => {
3062
+ const isInTable = useCallback6(() => {
2340
3063
  return selectionRef.current.focus.cellIndex != null;
2341
3064
  }, []);
2342
- const getTableLocation = useCallback4(() => {
3065
+ const getTableLocation = useCallback6(() => {
2343
3066
  return tableLocationOf(doc, selectionRef.current.focus);
2344
3067
  }, [doc]);
2345
- const insertTable = useCallback4((rows, cols) => {
3068
+ const insertTable = useCallback6((rows, cols) => {
2346
3069
  cmdInsertTable(ctxRef.current, rows, cols);
2347
3070
  }, []);
2348
- const deleteTable = useCallback4((blockIndex) => {
3071
+ const deleteTable = useCallback6((blockIndex) => {
2349
3072
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
2350
3073
  cmdDeleteTable(ctxRef.current, idx);
2351
3074
  }, []);
2352
- const insertRowAbove = useCallback4(() => {
3075
+ const insertRowAbove = useCallback6(() => {
2353
3076
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2354
3077
  if (!loc) return;
2355
3078
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "before");
2356
3079
  }, [doc]);
2357
- const insertRowBelow = useCallback4(() => {
3080
+ const insertRowBelow = useCallback6(() => {
2358
3081
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2359
3082
  if (!loc) return;
2360
3083
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "after");
2361
3084
  }, [doc]);
2362
- const deleteCurrentRow = useCallback4(() => {
3085
+ const deleteCurrentRow = useCallback6(() => {
2363
3086
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2364
3087
  if (!loc) return;
2365
3088
  cmdDeleteRow(ctxRef.current, loc.blockIndex, loc.row);
2366
3089
  }, [doc]);
2367
- const insertColumnLeft = useCallback4(() => {
3090
+ const insertColumnLeft = useCallback6(() => {
2368
3091
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2369
3092
  if (!loc) return;
2370
3093
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "before");
2371
3094
  }, [doc]);
2372
- const insertColumnRight = useCallback4(() => {
3095
+ const insertColumnRight = useCallback6(() => {
2373
3096
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2374
3097
  if (!loc) return;
2375
3098
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "after");
2376
3099
  }, [doc]);
2377
- const deleteCurrentColumn = useCallback4(() => {
3100
+ const deleteCurrentColumn = useCallback6(() => {
2378
3101
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2379
3102
  if (!loc) return;
2380
3103
  cmdDeleteColumn(ctxRef.current, loc.blockIndex, loc.col);
2381
3104
  }, [doc]);
2382
- const moveToNextCell = useCallback4(() => {
3105
+ const moveToNextCell = useCallback6(() => {
2383
3106
  cmdMoveNextCell(ctxRef.current);
2384
3107
  }, []);
2385
- const moveToPrevCell = useCallback4(() => {
3108
+ const moveToPrevCell = useCallback6(() => {
2386
3109
  cmdMovePrevCell(ctxRef.current);
2387
3110
  }, []);
2388
- const mergeRight = useCallback4(() => {
3111
+ const mergeRight = useCallback6(() => {
2389
3112
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2390
3113
  if (!loc) return false;
2391
3114
  return cmdMergeRight(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2392
3115
  }, [doc]);
2393
- const mergeDown = useCallback4(() => {
3116
+ const mergeDown = useCallback6(() => {
2394
3117
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2395
3118
  if (!loc) return false;
2396
3119
  return cmdMergeDown(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2397
3120
  }, [doc]);
2398
- const splitCell = useCallback4(() => {
3121
+ const splitCell = useCallback6(() => {
2399
3122
  const loc = tableLocationOf(doc, selectionRef.current.focus);
2400
3123
  if (!loc) return false;
2401
3124
  return cmdSplitCell(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2402
3125
  }, [doc]);
2403
- const setColumnWidth = useCallback4(
3126
+ const setColumnWidth = useCallback6(
2404
3127
  (blockIndex, col, widthPx) => {
2405
3128
  cmdSetColumnWidth(ctxRef.current, blockIndex, col, widthPx);
2406
3129
  },
2407
3130
  []
2408
3131
  );
2409
- const getTableRect = useCallback4(
3132
+ const getTableRect = useCallback6(
2410
3133
  () => tableRectSelection2(doc, selectionRef.current),
2411
3134
  [doc]
2412
3135
  );
2413
- const hasTableRectSelection = useCallback4(() => {
3136
+ const hasTableRectSelection = useCallback6(() => {
2414
3137
  return tableRectSelection2(doc, selectionRef.current) !== null;
2415
3138
  }, [doc]);
2416
- const mergeSelection = useCallback4(() => {
3139
+ const mergeSelection = useCallback6(() => {
2417
3140
  return cmdMergeSelection(ctxRef.current);
2418
3141
  }, []);
2419
- const insertImage = useCallback4((embed) => {
3142
+ const insertImage = useCallback6((embed) => {
2420
3143
  cmdInsertImage(ctxRef.current, embed);
2421
3144
  }, []);
2422
- const setImageAttrs = useCallback4(
3145
+ const setImageAttrs = useCallback6(
2423
3146
  (blockIndex, offset, partial, cellIndex, newOffset) => {
2424
3147
  cmdSetImageAttrs(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
2425
3148
  },
2426
3149
  []
2427
3150
  );
2428
- 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);
2429
3158
  uploadImageRef.current = opts.uploadImage;
2430
- const insertImageFromFile = useCallback4(async (file) => {
3159
+ const insertImageFromFile = useCallback6(async (file) => {
2431
3160
  if (!file.type.startsWith("image/")) return;
2432
3161
  const dataUrl = await readAsDataURL(file);
2433
3162
  const dims = await readImageDimensions(dataUrl);
@@ -2441,7 +3170,7 @@ function useEditor(opts = {}) {
2441
3170
  const src = upload ? await upload(file) : dataUrl;
2442
3171
  cmdInsertImage(ctxRef.current, { type: "image", src, width: w, height: h });
2443
3172
  }, []);
2444
- const getSelectedEmbed = useCallback4(() => {
3173
+ const getSelectedEmbed = useCallback6(() => {
2445
3174
  const sel = selectionRef.current;
2446
3175
  if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;
2447
3176
  if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;
@@ -2470,39 +3199,48 @@ function useEditor(opts = {}) {
2470
3199
  }
2471
3200
  return null;
2472
3201
  }, [doc]);
2473
- const [linkRequest, setLinkRequest] = useState7(null);
2474
- const requestLink = useCallback4((initialHref = "") => {
3202
+ const [linkRequest, setLinkRequest] = useState9(null);
3203
+ const linkRequestRef = useRef10(null);
3204
+ const requestLink = useCallback6((initialHref = "") => {
2475
3205
  return new Promise((resolve) => {
2476
- setLinkRequest({ initialHref, resolve });
2477
- });
2478
- }, []);
2479
- const resolveLinkRequest = useCallback4((href) => {
2480
- setLinkRequest((prev) => {
2481
- if (prev) prev.resolve(href);
2482
- return null;
3206
+ const req = { initialHref, resolve, selection: selectionRef.current };
3207
+ linkRequestRef.current = req;
3208
+ setLinkRequest(req);
2483
3209
  });
2484
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
+ );
2485
3223
  const pageSettings = usePageSettings(doc);
2486
- const setPageSettings = useCallback4(
3224
+ const setPageSettings = useCallback6(
2487
3225
  (partial) => {
2488
3226
  doc.setPageSettings(partial);
2489
3227
  },
2490
3228
  [doc]
2491
3229
  );
2492
- const [pageConfigRequest, setPageConfigRequest] = useState7(null);
2493
- const requestPageConfig = useCallback4(() => {
3230
+ const [pageConfigRequest, setPageConfigRequest] = useState9(null);
3231
+ const requestPageConfig = useCallback6(() => {
2494
3232
  return new Promise((resolve) => {
2495
3233
  setPageConfigRequest({ initial: doc.getPageSettings(), resolve });
2496
3234
  });
2497
3235
  }, [doc]);
2498
- const resolvePageConfigRequest = useCallback4((applied) => {
3236
+ const resolvePageConfigRequest = useCallback6((applied) => {
2499
3237
  setPageConfigRequest((prev) => {
2500
3238
  if (prev) prev.resolve(applied);
2501
3239
  return null;
2502
3240
  });
2503
3241
  }, []);
2504
- const [imageCaptionRequest, setImageCaptionRequest] = useState7(null);
2505
- const requestImageCaption = useCallback4(
3242
+ const [imageCaptionRequest, setImageCaptionRequest] = useState9(null);
3243
+ const requestImageCaption = useCallback6(
2506
3244
  (initialCaption = "", initialAlign = "center") => {
2507
3245
  return new Promise((resolve) => {
2508
3246
  setImageCaptionRequest({ initialCaption, initialAlign, resolve });
@@ -2510,7 +3248,7 @@ function useEditor(opts = {}) {
2510
3248
  },
2511
3249
  []
2512
3250
  );
2513
- const resolveImageCaptionRequest = useCallback4((result) => {
3251
+ const resolveImageCaptionRequest = useCallback6((result) => {
2514
3252
  setImageCaptionRequest((prev) => {
2515
3253
  if (prev) prev.resolve(result);
2516
3254
  return null;
@@ -2534,6 +3272,8 @@ function useEditor(opts = {}) {
2534
3272
  getBlockAttr,
2535
3273
  setBlockType,
2536
3274
  setBlockAttr,
3275
+ setAlign,
3276
+ getAlign,
2537
3277
  isListActive,
2538
3278
  toggleList,
2539
3279
  indentList,
@@ -2563,6 +3303,7 @@ function useEditor(opts = {}) {
2563
3303
  mergeSelection,
2564
3304
  insertImage,
2565
3305
  setImageAttrs,
3306
+ moveEmbedAnchor,
2566
3307
  insertImageFromFile,
2567
3308
  getSelectedEmbed,
2568
3309
  pageSettings,
@@ -2604,54 +3345,99 @@ function sameValue(a, b) {
2604
3345
  }
2605
3346
 
2606
3347
  // src/Editor.tsx
2607
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3348
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2608
3349
  var defaultFooter = ({ pageNumber, pageCount }) => `${pageNumber} / ${pageCount}`;
2609
3350
  function Editor({
2610
3351
  editor: providedEditor,
2611
3352
  className,
2612
3353
  pageGeometry,
2613
3354
  renderPageHeader,
2614
- renderPageFooter = defaultFooter
3355
+ renderPageFooter = defaultFooter,
3356
+ awareness
2615
3357
  }) {
2616
3358
  const internal = useEditor();
2617
3359
  const editor = providedEditor ?? internal;
2618
3360
  const { doc, history, snapshot, getSelection, setSelection } = editor;
2619
- const rootRef = useRef10(null);
2620
- const isComposingRef = useRef10(false);
2621
- const suppressSelectionSyncRef = useRef10(false);
2622
- 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 });
2623
3399
  ctxRef.current = { doc, getSelection, setSelection };
2624
- const historyRef = useRef10(history);
3400
+ const historyRef = useRef11(history);
2625
3401
  historyRef.current = history;
2626
- const editorRef = useRef10(editor);
3402
+ const editorRef = useRef11(editor);
2627
3403
  editorRef.current = editor;
2628
- useLayoutEffect4(() => {
3404
+ useLayoutEffect5(() => {
2629
3405
  const root = rootRef.current;
2630
3406
  if (!root) return;
2631
3407
  if (isComposingRef.current) return;
2632
3408
  if (document.activeElement !== root) return;
2633
3409
  const current = readDomSelection(root);
2634
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
+ }
2635
3416
  suppressSelectionSyncRef.current = true;
2636
3417
  applyDomSelection(root, editor.selection);
2637
- queueMicrotask(() => {
2638
- suppressSelectionSyncRef.current = false;
2639
- });
2640
3418
  });
2641
- useEffect7(() => {
3419
+ useEffect9(() => {
2642
3420
  const root = rootRef.current;
2643
3421
  if (!root) return;
2644
3422
  const handler = () => {
2645
- if (suppressSelectionSyncRef.current) return;
2646
3423
  if (isComposingRef.current) return;
2647
- if (document.activeElement !== root) return;
3424
+ if (document.activeElement !== root) {
3425
+ suppressSelectionSyncRef.current = false;
3426
+ return;
3427
+ }
2648
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
+ }
2649
3435
  if (modelSel) setSelection(modelSel);
2650
3436
  };
2651
3437
  document.addEventListener("selectionchange", handler);
2652
3438
  return () => document.removeEventListener("selectionchange", handler);
2653
3439
  }, [setSelection]);
2654
- useEffect7(() => {
3440
+ useEffect9(() => {
2655
3441
  const root = rootRef.current;
2656
3442
  if (!root) return;
2657
3443
  let drag = null;
@@ -2722,7 +3508,7 @@ function Editor({
2722
3508
  document.removeEventListener("pointerup", onPointerUp);
2723
3509
  };
2724
3510
  }, []);
2725
- useEffect7(() => {
3511
+ useEffect9(() => {
2726
3512
  const root = rootRef.current;
2727
3513
  if (!root) return;
2728
3514
  const onDragOver = (e) => {
@@ -2760,7 +3546,7 @@ function Editor({
2760
3546
  root.removeEventListener("drop", onDrop);
2761
3547
  };
2762
3548
  }, []);
2763
- useEffect7(() => {
3549
+ useEffect9(() => {
2764
3550
  const root = rootRef.current;
2765
3551
  if (!root) return;
2766
3552
  const onPointerDown = (e) => {
@@ -2788,7 +3574,95 @@ function Editor({
2788
3574
  root.addEventListener("pointerdown", onPointerDown);
2789
3575
  return () => root.removeEventListener("pointerdown", onPointerDown);
2790
3576
  }, []);
2791
- 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(() => {
2792
3666
  const root = rootRef.current;
2793
3667
  if (!root) return;
2794
3668
  const handler = (e) => {
@@ -2806,8 +3680,33 @@ function Editor({
2806
3680
  }
2807
3681
  return;
2808
3682
  }
2809
- case "insertParagraph":
2810
3683
  case "insertLineBreak": {
3684
+ e.preventDefault();
3685
+ if (ed.getBlockType() === "listItem") {
3686
+ insertText(ctx, "\n", ed.consumePendingMarks());
3687
+ return;
3688
+ }
3689
+ const selEmbed = ed.getSelectedEmbed();
3690
+ if (selEmbed) {
3691
+ const off = selEmbed.offset + 1;
3692
+ ctx.setSelection({
3693
+ anchor: {
3694
+ blockIndex: selEmbed.blockIndex,
3695
+ cellIndex: selEmbed.cellIndex,
3696
+ offset: off
3697
+ },
3698
+ focus: {
3699
+ blockIndex: selEmbed.blockIndex,
3700
+ cellIndex: selEmbed.cellIndex,
3701
+ offset: off
3702
+ }
3703
+ });
3704
+ }
3705
+ if (ed.splitListItem()) return;
3706
+ insertParagraph(ctx);
3707
+ return;
3708
+ }
3709
+ case "insertParagraph": {
2811
3710
  e.preventDefault();
2812
3711
  const selectedEmbed2 = ed.getSelectedEmbed();
2813
3712
  if (selectedEmbed2) {
@@ -2839,22 +3738,6 @@ function Editor({
2839
3738
  }
2840
3739
  case "insertFromPaste": {
2841
3740
  e.preventDefault();
2842
- const images = Array.from(e.dataTransfer?.files ?? []).filter(
2843
- (f) => f.type.startsWith("image/")
2844
- );
2845
- if (images.length > 0) {
2846
- void (async () => {
2847
- for (const f of images) await editorRef.current.insertImageFromFile(f);
2848
- })();
2849
- return;
2850
- }
2851
- const text = e.dataTransfer?.getData("text/plain") ?? "";
2852
- if (text.length === 0) return;
2853
- const lines = text.split(/\r\n|\r|\n/);
2854
- lines.forEach((line, i) => {
2855
- if (i > 0) insertParagraph(ctx);
2856
- if (line.length > 0) insertText(ctx, line);
2857
- });
2858
3741
  return;
2859
3742
  }
2860
3743
  case "deleteContentBackward":
@@ -2892,7 +3775,67 @@ function Editor({
2892
3775
  root.addEventListener("beforeinput", handler);
2893
3776
  return () => root.removeEventListener("beforeinput", handler);
2894
3777
  }, []);
2895
- 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) => {
2896
3839
  const ed = editorRef.current;
2897
3840
  const mod = e.metaKey || e.ctrlKey;
2898
3841
  if (e.key === "Tab") {
@@ -2906,6 +3849,20 @@ function Editor({
2906
3849
  else ed.indentList();
2907
3850
  return;
2908
3851
  }
3852
+ if (!mod && (e.key === "Home" || e.key === "End")) {
3853
+ const root = rootRef.current;
3854
+ const sel = window.getSelection();
3855
+ const sm = sel?.modify;
3856
+ if (root && sel && sel.rangeCount > 0 && typeof sm === "function") {
3857
+ e.preventDefault();
3858
+ const alter = e.shiftKey ? "extend" : "move";
3859
+ const direction = e.key === "Home" ? "left" : "right";
3860
+ sm.call(sel, alter, direction, "lineboundary");
3861
+ const modelSel = readDomSelection(root);
3862
+ if (modelSel) ctxRef.current.setSelection(modelSel);
3863
+ }
3864
+ return;
3865
+ }
2909
3866
  if (!mod) return;
2910
3867
  const key = e.key.toLowerCase();
2911
3868
  if (!e.shiftKey && !e.altKey && key === "z") {
@@ -2952,37 +3909,58 @@ function Editor({
2952
3909
  });
2953
3910
  }
2954
3911
  }, []);
2955
- const onCompositionStart = useCallback5(() => {
3912
+ const onCompositionStart = useCallback7(() => {
2956
3913
  isComposingRef.current = true;
2957
3914
  }, []);
2958
- const onCompositionEnd = useCallback5((e) => {
3915
+ const onCompositionEnd = useCallback7((e) => {
2959
3916
  isComposingRef.current = false;
2960
3917
  if (e.data && e.data.length > 0) {
2961
3918
  insertText(ctxRef.current, e.data);
2962
3919
  }
2963
3920
  }, []);
2964
3921
  const topLevels = useMemo4(() => groupTopLevels(snapshot.blocks), [snapshot]);
3922
+ const topLevelsStructuralKey = useMemo4(
3923
+ () => topLevels.map(
3924
+ (t) => t.kind === "list" ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}` : `B:${t.block.type}:${t.block.attrs.level ?? ""}`
3925
+ ).join("|"),
3926
+ [topLevels]
3927
+ );
2965
3928
  const docSettings = usePageSettings(editor.doc);
2966
3929
  const propIsSet = pageGeometry !== void 0;
2967
3930
  const geom = propIsSet ? pageGeometry ?? A4_PAGE : docSettings;
2968
3931
  const paginated = pageGeometry !== null;
2969
3932
  const selectedEmbed = editor.getSelectedEmbed();
2970
- const layout = usePageLayout(
3933
+ const { layout, phase: paginationPhase } = usePageLayout(
2971
3934
  rootRef,
2972
3935
  geom,
2973
3936
  topLevels.length,
2974
- [topLevels, pageGeometry]
3937
+ // Usar a chave estrutural (string) em vez do array `topLevels` direto:
3938
+ // o array reference muda a cada keystroke, mas a chave só muda quando
3939
+ // a SHAPE dos top-levels muda. `usePageLayout` compara deps via
3940
+ // `shallowArrayEqual` — string equality cobre isso.
3941
+ [topLevelsStructuralKey, pageGeometry]
2975
3942
  );
2976
3943
  const effectiveLayout = paginated ? layout : defaultPageLayout(topLevels.length);
2977
- const pageStyle = paginated ? {
2978
- "--ed-page-width": `${geom.width}px`,
2979
- "--ed-page-height": `${geom.height}px`,
2980
- "--ed-page-margin-top": `${geom.marginTop}px`,
2981
- "--ed-page-margin-bottom": `${geom.marginBottom}px`,
2982
- "--ed-page-margin-left": `${geom.marginLeft}px`,
2983
- "--ed-page-margin-right": `${geom.marginRight}px`
2984
- } : void 0;
2985
- const body = /* @__PURE__ */ jsxs8(
3944
+ const pageStyle = useMemo4(
3945
+ () => paginated ? {
3946
+ "--ed-page-width": `${geom.width}px`,
3947
+ "--ed-page-height": `${geom.height}px`,
3948
+ "--ed-page-margin-top": `${geom.marginTop}px`,
3949
+ "--ed-page-margin-bottom": `${geom.marginBottom}px`,
3950
+ "--ed-page-margin-left": `${geom.marginLeft}px`,
3951
+ "--ed-page-margin-right": `${geom.marginRight}px`
3952
+ } : void 0,
3953
+ [
3954
+ paginated,
3955
+ geom.width,
3956
+ geom.height,
3957
+ geom.marginTop,
3958
+ geom.marginBottom,
3959
+ geom.marginLeft,
3960
+ geom.marginRight
3961
+ ]
3962
+ );
3963
+ const body = /* @__PURE__ */ jsxs11(
2986
3964
  "div",
2987
3965
  {
2988
3966
  ref: rootRef,
@@ -2994,6 +3972,7 @@ function Editor({
2994
3972
  role: "textbox",
2995
3973
  "aria-multiline": "true",
2996
3974
  className: (className ?? "ed-root") + (paginated ? " ed-root--paged" : " ed-root--flat"),
3975
+ "data-pagination-phase": paginated ? paginationPhase : void 0,
2997
3976
  style: pageStyle,
2998
3977
  onKeyDown,
2999
3978
  onCompositionStart,
@@ -3004,22 +3983,26 @@ function Editor({
3004
3983
  pageNumber: pi + 1,
3005
3984
  pageCount: effectiveLayout.pages.length
3006
3985
  };
3007
- return /* @__PURE__ */ jsxs8(
3986
+ const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
3987
+ "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
3988
+ } : void 0;
3989
+ return /* @__PURE__ */ jsxs11(
3008
3990
  "div",
3009
3991
  {
3010
3992
  className: "ed-page",
3011
3993
  "data-page-number": ctx.pageNumber,
3012
3994
  "data-page-total": ctx.pageCount,
3995
+ style: pageInlineStyle,
3013
3996
  children: [
3014
- renderPageHeader && /* @__PURE__ */ jsx9("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3015
- /* @__PURE__ */ jsx9("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3016
- 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) })
3017
4000
  ]
3018
4001
  },
3019
4002
  `page-${pi}`
3020
4003
  );
3021
4004
  }) : topLevels.map((t) => renderTopLevel(t)),
3022
- selectedEmbed && /* @__PURE__ */ jsx9(
4005
+ selectedEmbed && /* @__PURE__ */ jsx12(
3023
4006
  ImageResizeOverlay,
3024
4007
  {
3025
4008
  rootRef,
@@ -3038,13 +4021,54 @@ function Editor({
3038
4021
  selectedEmbed.offset,
3039
4022
  { offsetX: ox, offsetY: oy },
3040
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
3041
4034
  )
3042
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
+ }
3043
4067
  )
3044
4068
  ]
3045
4069
  }
3046
4070
  );
3047
- return /* @__PURE__ */ jsx9(EditorProvider, { editor, children: body });
4071
+ return /* @__PURE__ */ jsx12(EditorProvider, { editor, children: body });
3048
4072
  }
3049
4073
  function groupTopLevels(snapshot) {
3050
4074
  const out = [];
@@ -3055,11 +4079,29 @@ function groupTopLevels(snapshot) {
3055
4079
  const groupStart = i;
3056
4080
  const items = [];
3057
4081
  const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
3058
- while (i < snapshot.length && snapshot[i].type === "listItem" && (snapshot[i].attrs.listKind ?? "bullet") === kind) {
3059
- items.push({ block: snapshot[i], index: i });
4082
+ const groupStyle = block.attrs.listStyle;
4083
+ while (i < snapshot.length) {
4084
+ const b = snapshot[i];
4085
+ if (b.type !== "listItem") break;
4086
+ if ((b.attrs.listKind ?? "bullet") !== kind) break;
4087
+ if (i > groupStart) {
4088
+ if (typeof b.attrs.listStart === "number") break;
4089
+ const itemStyle = b.attrs.listStyle;
4090
+ if (itemStyle !== void 0 && itemStyle !== groupStyle) break;
4091
+ }
4092
+ items.push({ block: b, index: i });
3060
4093
  i++;
3061
4094
  }
3062
- out.push({ kind: "list", items, listKind: kind, key: groupStart });
4095
+ const firstAttrs = items[0].block.attrs;
4096
+ const ordinalStart = typeof firstAttrs.listStart === "number" && firstAttrs.listStart > 0 ? firstAttrs.listStart : 1;
4097
+ out.push({
4098
+ kind: "list",
4099
+ items,
4100
+ listKind: kind,
4101
+ ordinalStart,
4102
+ listStyle: groupStyle,
4103
+ key: groupStart
4104
+ });
3063
4105
  continue;
3064
4106
  }
3065
4107
  out.push({ kind: "block", block, blockIndex: i, key: i });
@@ -3076,7 +4118,7 @@ function renderSlot(slot, topLevels) {
3076
4118
  start: slot.fragment.start,
3077
4119
  end: slot.fragment.end
3078
4120
  };
3079
- return /* @__PURE__ */ jsx9(
4121
+ return /* @__PURE__ */ jsx12(
3080
4122
  NodeView,
3081
4123
  {
3082
4124
  block: top.block,
@@ -3087,7 +4129,7 @@ function renderSlot(slot, topLevels) {
3087
4129
  );
3088
4130
  }
3089
4131
  if (slot.tableFragment && top.kind === "block" && top.block.type === "table") {
3090
- return /* @__PURE__ */ jsx9(
4132
+ return /* @__PURE__ */ jsx12(
3091
4133
  NodeView,
3092
4134
  {
3093
4135
  block: top.block,
@@ -3097,14 +4139,42 @@ function renderSlot(slot, topLevels) {
3097
4139
  `${top.key}-tf${slot.tableFragment.index}`
3098
4140
  );
3099
4141
  }
4142
+ if (slot.listFragment && top.kind === "list") {
4143
+ return renderListFragment(top, slot.listFragment);
4144
+ }
3100
4145
  return renderTopLevel(top);
3101
4146
  }
3102
4147
  function renderTopLevel(top) {
3103
4148
  if (top.kind === "list") {
3104
4149
  const tree = buildListTree(top.items);
3105
- return renderListTree(tree, top.listKind, `list-${top.key}`);
4150
+ return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
3106
4151
  }
3107
- 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);
4153
+ }
4154
+ function renderListFragment(top, frag) {
4155
+ const ranges = topLevelItemRanges(top.items);
4156
+ const startRange = ranges[frag.itemStart];
4157
+ const endRange = ranges[frag.itemEnd - 1];
4158
+ if (!startRange || !endRange) return renderTopLevel(top);
4159
+ const sliced = top.items.slice(startRange[0], endRange[1]);
4160
+ const ordinalStart = top.ordinalStart + frag.itemStart;
4161
+ const key = `list-${top.key}-f${frag.index}`;
4162
+ const slicedTop = { ...top, items: sliced };
4163
+ const tree = buildListTree(sliced);
4164
+ return renderListTree(tree, slicedTop, ordinalStart, key);
4165
+ }
4166
+ function topLevelItemRanges(items) {
4167
+ const out = [];
4168
+ let currentStart = -1;
4169
+ items.forEach((it, idx) => {
4170
+ const level = clampListLevel2(it.block.attrs.listLevel);
4171
+ if (level === 0) {
4172
+ if (currentStart >= 0) out.push([currentStart, idx]);
4173
+ currentStart = idx;
4174
+ }
4175
+ });
4176
+ if (currentStart >= 0) out.push([currentStart, items.length]);
4177
+ return out;
3108
4178
  }
3109
4179
  function buildListTree(items) {
3110
4180
  const roots = [];
@@ -3118,9 +4188,28 @@ function buildListTree(items) {
3118
4188
  }
3119
4189
  return roots;
3120
4190
  }
3121
- function renderListTree(tree, kind, key) {
4191
+ function renderListTree(tree, top, start, key) {
4192
+ const className = `ed-list ed-list-${top.listKind}`;
4193
+ const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
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));
4195
+ if (top.listKind === "ordered") {
4196
+ return /* @__PURE__ */ jsx12(
4197
+ "ol",
4198
+ {
4199
+ className,
4200
+ "data-list-kind": "ordered",
4201
+ start: start > 1 ? start : void 0,
4202
+ style,
4203
+ children: items
4204
+ },
4205
+ key
4206
+ );
4207
+ }
4208
+ return /* @__PURE__ */ jsx12("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
4209
+ }
4210
+ function renderNestedListTree(tree, kind, key) {
3122
4211
  const Tag = kind === "ordered" ? "ol" : "ul";
3123
- 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 ? renderListTree(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);
3124
4213
  }
3125
4214
  function clampListLevel2(l) {
3126
4215
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
@@ -3149,12 +4238,12 @@ function caretRangeFromPoint(x, y) {
3149
4238
 
3150
4239
  // src/Toolbar.tsx
3151
4240
  import {
3152
- useCallback as useCallback6,
3153
- useEffect as useEffect8,
3154
- useRef as useRef11,
3155
- useState as useState8
4241
+ useCallback as useCallback8,
4242
+ useEffect as useEffect10,
4243
+ useRef as useRef12,
4244
+ useState as useState11
3156
4245
  } from "react";
3157
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4246
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
3158
4247
  var FONT_FAMILIES = ["Arial"];
3159
4248
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
3160
4249
  var BLOCK_OPTIONS = [
@@ -3194,6 +4283,8 @@ function Toolbar({ className }) {
3194
4283
  getBlockAttr,
3195
4284
  setBlockType,
3196
4285
  setBlockAttr,
4286
+ setAlign,
4287
+ getAlign,
3197
4288
  isListActive,
3198
4289
  toggleList,
3199
4290
  indentList,
@@ -3202,7 +4293,7 @@ function Toolbar({ className }) {
3202
4293
  const active = getActiveMarks();
3203
4294
  const blockType = getBlockType();
3204
4295
  const blockLevel = getBlockAttr("level");
3205
- const blockAlign = getBlockAttr("align");
4296
+ const blockAlign = getAlign();
3206
4297
  const blockDir = getBlockAttr("dir");
3207
4298
  const stop = (e) => {
3208
4299
  const t = e.target;
@@ -3245,16 +4336,16 @@ function Toolbar({ className }) {
3245
4336
  );
3246
4337
  return;
3247
4338
  }
3248
- setBlockAttr("align", value);
4339
+ setAlign(value);
3249
4340
  };
3250
- const onInsertImageClick = useCallback6(
4341
+ const onInsertImageClick = useCallback8(
3251
4342
  (e) => {
3252
4343
  e.preventDefault();
3253
4344
  imageInputRef.current?.click();
3254
4345
  },
3255
4346
  []
3256
4347
  );
3257
- const onImageInputChange = useCallback6(
4348
+ const onImageInputChange = useCallback8(
3258
4349
  (e) => {
3259
4350
  const file = e.target.files?.[0];
3260
4351
  if (file) void editor.insertImageFromFile(file);
@@ -3262,14 +4353,14 @@ function Toolbar({ className }) {
3262
4353
  },
3263
4354
  [editor]
3264
4355
  );
3265
- const imageInputRef = useRef11(null);
4356
+ const imageInputRef = useRef12(null);
3266
4357
  const onToggleDir = (e) => {
3267
4358
  e.preventDefault();
3268
4359
  const next = blockDir === "rtl" ? "ltr" : "rtl";
3269
4360
  setBlockAttr("dir", next);
3270
4361
  };
3271
4362
  const linkActive = isMarkActive("link");
3272
- const onLinkClick = useCallback6(
4363
+ const onLinkClick = useCallback8(
3273
4364
  (e) => {
3274
4365
  e.preventDefault();
3275
4366
  const currentHref = active.link && typeof active.link === "object" && "href" in active.link ? active.link.href : "";
@@ -3299,7 +4390,7 @@ function Toolbar({ className }) {
3299
4390
  sel.cellIndex
3300
4391
  );
3301
4392
  };
3302
- return /* @__PURE__ */ jsxs9(
4393
+ return /* @__PURE__ */ jsxs12(
3303
4394
  "div",
3304
4395
  {
3305
4396
  className: className ?? "ed-toolbar",
@@ -3307,7 +4398,7 @@ function Toolbar({ className }) {
3307
4398
  "aria-label": "Editor toolbar",
3308
4399
  onMouseDown: stop,
3309
4400
  children: [
3310
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsxs9(
4401
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsxs12(
3311
4402
  "select",
3312
4403
  {
3313
4404
  className: "ed-toolbar-select",
@@ -3316,23 +4407,23 @@ function Toolbar({ className }) {
3316
4407
  onMouseDown: stop,
3317
4408
  "aria-label": "Tipo de bloco",
3318
4409
  children: [
3319
- blockValue === "" && /* @__PURE__ */ jsx10("option", { value: "", children: "\u2014 (misto)" }),
3320
- 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))
3321
4412
  ]
3322
4413
  }
3323
4414
  ) }),
3324
- /* @__PURE__ */ jsxs9(Group, { children: [
3325
- /* @__PURE__ */ jsx10(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ jsx10("strong", { children: "B" }) }),
3326
- /* @__PURE__ */ jsx10(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ jsx10("em", { children: "I" }) }),
3327
- /* @__PURE__ */ jsx10(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ jsx10("u", { children: "U" }) }),
3328
- /* @__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" }) })
3329
4420
  ] }),
3330
- /* @__PURE__ */ jsxs9(Group, { children: [
3331
- /* @__PURE__ */ jsxs9("label", { className: "ed-toolbar-label", children: [
3332
- /* @__PURE__ */ jsx10("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
3333
- /* @__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" })
3334
4425
  ] }),
3335
- /* @__PURE__ */ jsx10(
4426
+ /* @__PURE__ */ jsx13(
3336
4427
  "button",
3337
4428
  {
3338
4429
  type: "button",
@@ -3347,8 +4438,8 @@ function Toolbar({ className }) {
3347
4438
  }
3348
4439
  )
3349
4440
  ] }),
3350
- /* @__PURE__ */ jsxs9(Group, { children: [
3351
- /* @__PURE__ */ jsxs9(
4441
+ /* @__PURE__ */ jsxs12(Group, { children: [
4442
+ /* @__PURE__ */ jsxs12(
3352
4443
  "select",
3353
4444
  {
3354
4445
  className: "ed-toolbar-select",
@@ -3357,12 +4448,12 @@ function Toolbar({ className }) {
3357
4448
  onMouseDown: stop,
3358
4449
  "aria-label": "Fam\xEDlia da fonte",
3359
4450
  children: [
3360
- /* @__PURE__ */ jsx10("option", { value: "", children: "Fonte\u2026" }),
3361
- 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))
3362
4453
  ]
3363
4454
  }
3364
4455
  ),
3365
- /* @__PURE__ */ jsxs9(
4456
+ /* @__PURE__ */ jsxs12(
3366
4457
  "select",
3367
4458
  {
3368
4459
  className: "ed-toolbar-select",
@@ -3371,13 +4462,13 @@ function Toolbar({ className }) {
3371
4462
  onMouseDown: stop,
3372
4463
  "aria-label": "Tamanho da fonte",
3373
4464
  children: [
3374
- /* @__PURE__ */ jsx10("option", { value: "", children: "Tamanho\u2026" }),
3375
- 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))
3376
4467
  ]
3377
4468
  }
3378
4469
  )
3379
4470
  ] }),
3380
- /* @__PURE__ */ jsx10(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx10(
4471
+ /* @__PURE__ */ jsx13(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx13(
3381
4472
  "button",
3382
4473
  {
3383
4474
  type: "button",
@@ -3390,7 +4481,7 @@ function Toolbar({ className }) {
3390
4481
  },
3391
4482
  a.value
3392
4483
  )) }),
3393
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4484
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3394
4485
  "button",
3395
4486
  {
3396
4487
  type: "button",
@@ -3402,8 +4493,8 @@ function Toolbar({ className }) {
3402
4493
  children: blockDir === "rtl" ? "RTL" : "LTR"
3403
4494
  }
3404
4495
  ) }),
3405
- /* @__PURE__ */ jsxs9(Group, { children: [
3406
- /* @__PURE__ */ jsx10(
4496
+ /* @__PURE__ */ jsxs12(Group, { children: [
4497
+ /* @__PURE__ */ jsx13(
3407
4498
  "button",
3408
4499
  {
3409
4500
  type: "button",
@@ -3418,7 +4509,7 @@ function Toolbar({ className }) {
3418
4509
  children: "\u2022"
3419
4510
  }
3420
4511
  ),
3421
- /* @__PURE__ */ jsx10(
4512
+ /* @__PURE__ */ jsx13(
3422
4513
  "button",
3423
4514
  {
3424
4515
  type: "button",
@@ -3433,7 +4524,7 @@ function Toolbar({ className }) {
3433
4524
  children: "1."
3434
4525
  }
3435
4526
  ),
3436
- /* @__PURE__ */ jsx10(
4527
+ /* @__PURE__ */ jsx13(
3437
4528
  "button",
3438
4529
  {
3439
4530
  type: "button",
@@ -3447,7 +4538,7 @@ function Toolbar({ className }) {
3447
4538
  children: "\u21E4"
3448
4539
  }
3449
4540
  ),
3450
- /* @__PURE__ */ jsx10(
4541
+ /* @__PURE__ */ jsx13(
3451
4542
  "button",
3452
4543
  {
3453
4544
  type: "button",
@@ -3462,7 +4553,7 @@ function Toolbar({ className }) {
3462
4553
  }
3463
4554
  )
3464
4555
  ] }),
3465
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4556
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3466
4557
  "button",
3467
4558
  {
3468
4559
  type: "button",
@@ -3474,9 +4565,9 @@ function Toolbar({ className }) {
3474
4565
  children: "\u{1F517}"
3475
4566
  }
3476
4567
  ) }),
3477
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(TableMenu, {}) }),
3478
- /* @__PURE__ */ jsxs9(Group, { children: [
3479
- /* @__PURE__ */ jsx10(
4568
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(TableMenu, {}) }),
4569
+ /* @__PURE__ */ jsxs12(Group, { children: [
4570
+ /* @__PURE__ */ jsx13(
3480
4571
  "button",
3481
4572
  {
3482
4573
  type: "button",
@@ -3487,7 +4578,7 @@ function Toolbar({ className }) {
3487
4578
  children: "\u{1F5BC}"
3488
4579
  }
3489
4580
  ),
3490
- /* @__PURE__ */ jsx10(
4581
+ /* @__PURE__ */ jsx13(
3491
4582
  "input",
3492
4583
  {
3493
4584
  ref: imageInputRef,
@@ -3498,8 +4589,8 @@ function Toolbar({ className }) {
3498
4589
  }
3499
4590
  )
3500
4591
  ] }),
3501
- selectedEmbed && /* @__PURE__ */ jsxs9(Group, { children: [
3502
- IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx10(
4592
+ selectedEmbed && /* @__PURE__ */ jsxs12(Group, { children: [
4593
+ IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx13(
3503
4594
  "button",
3504
4595
  {
3505
4596
  type: "button",
@@ -3512,7 +4603,7 @@ function Toolbar({ className }) {
3512
4603
  },
3513
4604
  opt.value
3514
4605
  )),
3515
- /* @__PURE__ */ jsx10(
4606
+ /* @__PURE__ */ jsx13(
3516
4607
  "button",
3517
4608
  {
3518
4609
  type: "button",
@@ -3542,7 +4633,7 @@ function Toolbar({ className }) {
3542
4633
  }
3543
4634
  )
3544
4635
  ] }),
3545
- /* @__PURE__ */ jsx10(Group, { children: /* @__PURE__ */ jsx10(
4636
+ /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
3546
4637
  "button",
3547
4638
  {
3548
4639
  type: "button",
@@ -3563,9 +4654,9 @@ function Toolbar({ className }) {
3563
4654
  function TableMenu() {
3564
4655
  const editor = useEditorContext();
3565
4656
  const inTable = editor.isInTable();
3566
- const [open, setOpen] = useState8(false);
3567
- const rootRef = useRef11(null);
3568
- useEffect8(() => {
4657
+ const [open, setOpen] = useState11(false);
4658
+ const rootRef = useRef12(null);
4659
+ useEffect10(() => {
3569
4660
  if (!open) return;
3570
4661
  const onDown = (e) => {
3571
4662
  if (!rootRef.current) return;
@@ -3575,8 +4666,8 @@ function TableMenu() {
3575
4666
  document.addEventListener("mousedown", onDown);
3576
4667
  return () => document.removeEventListener("mousedown", onDown);
3577
4668
  }, [open]);
3578
- return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
3579
- /* @__PURE__ */ jsx10(
4669
+ return /* @__PURE__ */ jsxs12("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
4670
+ /* @__PURE__ */ jsx13(
3580
4671
  "button",
3581
4672
  {
3582
4673
  type: "button",
@@ -3591,7 +4682,7 @@ function TableMenu() {
3591
4682
  children: "\u25A6"
3592
4683
  }
3593
4684
  ),
3594
- open && /* @__PURE__ */ jsxs9(
4685
+ open && /* @__PURE__ */ jsxs12(
3595
4686
  "div",
3596
4687
  {
3597
4688
  className: "ed-table-popover",
@@ -3603,7 +4694,7 @@ function TableMenu() {
3603
4694
  }
3604
4695
  },
3605
4696
  children: [
3606
- /* @__PURE__ */ jsx10(
4697
+ /* @__PURE__ */ jsx13(
3607
4698
  TableSizePicker,
3608
4699
  {
3609
4700
  onPick: (rows, cols) => {
@@ -3612,34 +4703,34 @@ function TableMenu() {
3612
4703
  }
3613
4704
  }
3614
4705
  ),
3615
- inTable && /* @__PURE__ */ jsxs9("div", { className: "ed-table-actions", children: [
3616
- /* @__PURE__ */ jsx10("hr", {}),
3617
- /* @__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: () => {
3618
4709
  setOpen(false);
3619
4710
  editor.insertRowAbove();
3620
4711
  }, children: "Inserir linha acima" }),
3621
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4712
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3622
4713
  setOpen(false);
3623
4714
  editor.insertRowBelow();
3624
4715
  }, children: "Inserir linha abaixo" }),
3625
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4716
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3626
4717
  setOpen(false);
3627
4718
  editor.insertColumnLeft();
3628
4719
  }, children: "Inserir coluna \xE0 esquerda" }),
3629
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4720
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3630
4721
  setOpen(false);
3631
4722
  editor.insertColumnRight();
3632
4723
  }, children: "Inserir coluna \xE0 direita" }),
3633
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4724
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3634
4725
  setOpen(false);
3635
4726
  editor.deleteCurrentRow();
3636
4727
  }, children: "Excluir linha" }),
3637
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4728
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3638
4729
  setOpen(false);
3639
4730
  editor.deleteCurrentColumn();
3640
4731
  }, children: "Excluir coluna" }),
3641
- /* @__PURE__ */ jsx10("hr", {}),
3642
- editor.hasTableRectSelection() && /* @__PURE__ */ jsx10(
4732
+ /* @__PURE__ */ jsx13("hr", {}),
4733
+ editor.hasTableRectSelection() && /* @__PURE__ */ jsx13(
3643
4734
  "button",
3644
4735
  {
3645
4736
  type: "button",
@@ -3650,19 +4741,19 @@ function TableMenu() {
3650
4741
  children: "Mesclar c\xE9lulas selecionadas"
3651
4742
  }
3652
4743
  ),
3653
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4744
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3654
4745
  setOpen(false);
3655
4746
  editor.mergeRight();
3656
4747
  }, children: "Mesclar com c\xE9lula \xE0 direita" }),
3657
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4748
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3658
4749
  setOpen(false);
3659
4750
  editor.mergeDown();
3660
4751
  }, children: "Mesclar com c\xE9lula abaixo" }),
3661
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => {
4752
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
3662
4753
  setOpen(false);
3663
4754
  editor.splitCell();
3664
4755
  }, children: "Dividir c\xE9lulas mescladas" }),
3665
- /* @__PURE__ */ jsx10(
4756
+ /* @__PURE__ */ jsx13(
3666
4757
  "button",
3667
4758
  {
3668
4759
  type: "button",
@@ -3683,11 +4774,11 @@ function TableMenu() {
3683
4774
  var PICKER_MAX_ROWS = 8;
3684
4775
  var PICKER_MAX_COLS = 10;
3685
4776
  function TableSizePicker({ onPick }) {
3686
- const [hover, setHover] = useState8(null);
4777
+ const [hover, setHover] = useState11(null);
3687
4778
  const label = hover ? `${hover.r + 1} \xD7 ${hover.c + 1}` : "Inserir tabela";
3688
- return /* @__PURE__ */ jsxs9("div", { className: "ed-table-picker", children: [
3689
- /* @__PURE__ */ jsx10("div", { className: "ed-table-picker-label", children: label }),
3690
- /* @__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(
3691
4782
  "div",
3692
4783
  {
3693
4784
  className: "ed-table-picker-grid",
@@ -3700,7 +4791,7 @@ function TableSizePicker({ onPick }) {
3700
4791
  { length: PICKER_MAX_ROWS },
3701
4792
  (_, r) => Array.from({ length: PICKER_MAX_COLS }, (_2, c) => {
3702
4793
  const filled = hover != null && r <= hover.r && c <= hover.c;
3703
- return /* @__PURE__ */ jsx10(
4794
+ return /* @__PURE__ */ jsx13(
3704
4795
  "button",
3705
4796
  {
3706
4797
  type: "button",
@@ -3730,10 +4821,10 @@ function blockSelectValue(type, level) {
3730
4821
  return type;
3731
4822
  }
3732
4823
  function Group({ children }) {
3733
- return /* @__PURE__ */ jsx10("div", { className: "ed-toolbar-group", children });
4824
+ return /* @__PURE__ */ jsx13("div", { className: "ed-toolbar-group", children });
3734
4825
  }
3735
4826
  function MarkButton({ title, pressed, onClick, children }) {
3736
- return /* @__PURE__ */ jsx10(
4827
+ return /* @__PURE__ */ jsx13(
3737
4828
  "button",
3738
4829
  {
3739
4830
  type: "button",
@@ -3754,6 +4845,7 @@ export {
3754
4845
  LinkDialog,
3755
4846
  NodeView,
3756
4847
  PageConfigDialog,
4848
+ RemoteCursorsOverlay,
3757
4849
  Toolbar,
3758
4850
  applyDomSelection,
3759
4851
  contentHeight,
@@ -3765,6 +4857,7 @@ export {
3765
4857
  getCellElement,
3766
4858
  getFragmentForOffset,
3767
4859
  isTableRectSelection,
4860
+ locatePoint,
3768
4861
  readDomSelection,
3769
4862
  renderInline,
3770
4863
  selectionsEqual,