@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.cjs CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  LinkDialog: () => LinkDialog,
28
28
  NodeView: () => NodeView,
29
29
  PageConfigDialog: () => PageConfigDialog,
30
+ RemoteCursorsOverlay: () => RemoteCursorsOverlay,
30
31
  Toolbar: () => Toolbar,
31
32
  applyDomSelection: () => applyDomSelection,
32
33
  contentHeight: () => contentHeight,
@@ -38,6 +39,7 @@ __export(index_exports, {
38
39
  getCellElement: () => getCellElement,
39
40
  getFragmentForOffset: () => getFragmentForOffset,
40
41
  isTableRectSelection: () => isTableRectSelection,
42
+ locatePoint: () => locatePoint,
41
43
  readDomSelection: () => readDomSelection,
42
44
  renderInline: () => renderInline,
43
45
  selectionsEqual: () => selectionsEqual,
@@ -51,8 +53,8 @@ __export(index_exports, {
51
53
  module.exports = __toCommonJS(index_exports);
52
54
 
53
55
  // src/Editor.tsx
54
- var import_react12 = require("react");
55
- var import_core5 = require("@sofereditor/core");
56
+ var import_react14 = require("react");
57
+ var import_core6 = require("@sofereditor/core");
56
58
 
57
59
  // src/dom-bridge.ts
58
60
  function findContainingBlockElement(node, root) {
@@ -252,6 +254,7 @@ function locatePoint(root, pos) {
252
254
  let remaining = Math.max(0, pos.offset - containerStart);
253
255
  let result = null;
254
256
  let lastImg = null;
257
+ let lastText = null;
255
258
  function visit(n) {
256
259
  if (result) return;
257
260
  if (n.nodeType === Node.TEXT_NODE) {
@@ -262,6 +265,7 @@ function locatePoint(root, pos) {
262
265
  }
263
266
  remaining -= len;
264
267
  lastImg = null;
268
+ lastText = n;
265
269
  return;
266
270
  }
267
271
  if (n.nodeType !== Node.ELEMENT_NODE) return;
@@ -291,6 +295,10 @@ function locatePoint(root, pos) {
291
295
  const parent = lastImg.parentNode;
292
296
  if (parent) return { node: parent, offset: indexInParent(lastImg) + 1 };
293
297
  }
298
+ if (lastText) {
299
+ const t = lastText;
300
+ return { node: t, offset: (t.textContent ?? "").length };
301
+ }
294
302
  return { node: container, offset: 0 };
295
303
  }
296
304
  function selectionsEqual(a, b) {
@@ -311,6 +319,9 @@ function applyDomSelection(root, modelSel) {
311
319
  const anchorPt = locatePoint(root, modelSel.anchor);
312
320
  const focusPt = locatePoint(root, modelSel.focus);
313
321
  if (!anchorPt || !focusPt) return;
322
+ if (domSel.anchorNode === anchorPt.node && domSel.anchorOffset === anchorPt.offset && domSel.focusNode === focusPt.node && domSel.focusOffset === focusPt.offset) {
323
+ return;
324
+ }
314
325
  try {
315
326
  domSel.removeAllRanges();
316
327
  domSel.setBaseAndExtent(anchorPt.node, anchorPt.offset, focusPt.node, focusPt.offset);
@@ -318,18 +329,253 @@ function applyDomSelection(root, modelSel) {
318
329
  }
319
330
  }
320
331
 
332
+ // src/BehindImageSelectAffordance.tsx
333
+ var import_react = require("react");
334
+ var import_jsx_runtime = require("react/jsx-runtime");
335
+ var ACCENT = "#3b82f6";
336
+ function BehindImageSelectAffordance({
337
+ blockIndex,
338
+ offset,
339
+ cellIndex,
340
+ rootRef,
341
+ onSelect
342
+ }) {
343
+ const [rect, setRect] = (0, import_react.useState)(null);
344
+ const locateImage = (0, import_react.useCallback)(() => {
345
+ const root = rootRef.current;
346
+ if (!root) return null;
347
+ let container = null;
348
+ if (cellIndex != null) {
349
+ container = root.querySelector(
350
+ `[data-block-index="${blockIndex}"] [data-cell-index="${cellIndex}"]`
351
+ );
352
+ } else {
353
+ container = getFragmentForOffset(root, blockIndex, offset);
354
+ }
355
+ if (!container) return null;
356
+ const fragmentStart = container.dataset.fragmentStart ? Number.parseInt(container.dataset.fragmentStart, 10) || 0 : 0;
357
+ const localOffset = offset - fragmentStart;
358
+ return container.querySelector(
359
+ `img[data-embed="image"][data-embed-offset="${localOffset}"]`
360
+ );
361
+ }, [rootRef, blockIndex, offset, cellIndex]);
362
+ const measure = (0, import_react.useCallback)(() => {
363
+ const img = locateImage();
364
+ const root = rootRef.current;
365
+ if (!img || !root) {
366
+ setRect((prev) => prev === null ? prev : null);
367
+ return;
368
+ }
369
+ const r = img.getBoundingClientRect();
370
+ const rr = root.getBoundingClientRect();
371
+ const next = {
372
+ top: r.top - rr.top + root.scrollTop,
373
+ left: r.left - rr.left + root.scrollLeft,
374
+ width: r.width,
375
+ height: r.height
376
+ };
377
+ setRect(
378
+ (prev) => prev && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
379
+ );
380
+ }, [locateImage, rootRef]);
381
+ (0, import_react.useLayoutEffect)(() => {
382
+ measure();
383
+ let cancelled = false;
384
+ const remeasure = () => {
385
+ if (!cancelled) measure();
386
+ };
387
+ const id = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
388
+ return () => {
389
+ cancelled = true;
390
+ if (typeof cancelAnimationFrame === "function" && typeof id === "number" && id > 0) {
391
+ cancelAnimationFrame(id);
392
+ }
393
+ };
394
+ }, [measure]);
395
+ (0, import_react.useEffect)(() => {
396
+ const root = rootRef.current;
397
+ if (!root) return;
398
+ const onScroll = () => measure();
399
+ window.addEventListener("resize", onScroll);
400
+ root.addEventListener("scroll", onScroll);
401
+ return () => {
402
+ window.removeEventListener("resize", onScroll);
403
+ root.removeEventListener("scroll", onScroll);
404
+ };
405
+ }, [measure, rootRef]);
406
+ if (!rect) return null;
407
+ const outlineStyle = {
408
+ position: "absolute",
409
+ top: rect.top,
410
+ left: rect.left,
411
+ width: rect.width,
412
+ height: rect.height,
413
+ border: `1.5px dashed ${ACCENT}`,
414
+ borderRadius: 2,
415
+ boxSizing: "border-box",
416
+ pointerEvents: "none",
417
+ zIndex: 4
418
+ };
419
+ const badgeStyle = {
420
+ position: "absolute",
421
+ top: rect.top - 2,
422
+ left: rect.left - 2,
423
+ width: 24,
424
+ height: 24,
425
+ display: "flex",
426
+ alignItems: "center",
427
+ justifyContent: "center",
428
+ background: ACCENT,
429
+ color: "#fff",
430
+ borderRadius: 4,
431
+ cursor: "pointer",
432
+ pointerEvents: "auto",
433
+ boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
434
+ zIndex: 5
435
+ };
436
+ const onBadgeDown = (e) => {
437
+ if (e.button !== 0) return;
438
+ e.preventDefault();
439
+ e.stopPropagation();
440
+ onSelect();
441
+ };
442
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
443
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: outlineStyle, contentEditable: false, "aria-hidden": true }),
444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
445
+ "div",
446
+ {
447
+ style: badgeStyle,
448
+ contentEditable: false,
449
+ onPointerDown: onBadgeDown,
450
+ role: "button",
451
+ "aria-label": "Selecionar imagem",
452
+ title: "Selecionar imagem",
453
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
454
+ "svg",
455
+ {
456
+ width: "14",
457
+ height: "14",
458
+ viewBox: "0 0 24 24",
459
+ fill: "none",
460
+ stroke: "currentColor",
461
+ strokeWidth: "2",
462
+ strokeLinecap: "round",
463
+ strokeLinejoin: "round",
464
+ "aria-hidden": true,
465
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 9l-3 3 3 3M9 5l3-3 3 3M15 19l-3 3-3-3M19 9l3 3-3 3M2 12h20M12 2v20" })
466
+ }
467
+ )
468
+ }
469
+ )
470
+ ] });
471
+ }
472
+
473
+ // src/LinkHoverTooltip.tsx
474
+ var import_react_dom = require("react-dom");
475
+
476
+ // src/platform.ts
477
+ var IS_MAC = (() => {
478
+ if (typeof navigator === "undefined") return false;
479
+ const platform = navigator.userAgentData?.platform || navigator.platform || navigator.userAgent || "";
480
+ return /mac|iphone|ipad|ipod/i.test(platform);
481
+ })();
482
+ var MOD_SYMBOL = IS_MAC ? "\u2318" : "\u2303";
483
+ function hasOpenModifier(e) {
484
+ return IS_MAC ? e.metaKey : e.ctrlKey;
485
+ }
486
+
487
+ // src/LinkHoverTooltip.tsx
488
+ var import_jsx_runtime2 = require("react/jsx-runtime");
489
+ var MAX_WIDTH = 360;
490
+ var GAP = 6;
491
+ function LinkHoverTooltip({ href, rect }) {
492
+ const above = rect.top > 48;
493
+ const viewportW = typeof window !== "undefined" ? window.innerWidth : MAX_WIDTH + 16;
494
+ const left = Math.max(8, Math.min(rect.left, viewportW - MAX_WIDTH - 8));
495
+ const style = {
496
+ position: "fixed",
497
+ left,
498
+ top: above ? rect.top - GAP : rect.bottom + GAP,
499
+ transform: above ? "translateY(-100%)" : void 0,
500
+ maxWidth: MAX_WIDTH,
501
+ background: "#1f2937",
502
+ color: "#fff",
503
+ fontSize: 12,
504
+ lineHeight: 1.4,
505
+ padding: "6px 9px",
506
+ borderRadius: 6,
507
+ boxShadow: "0 4px 14px rgba(0,0,0,0.28)",
508
+ zIndex: 60,
509
+ pointerEvents: "none"
510
+ };
511
+ const urlStyle = {
512
+ display: "block",
513
+ maxWidth: MAX_WIDTH - 18,
514
+ overflow: "hidden",
515
+ textOverflow: "ellipsis",
516
+ whiteSpace: "nowrap",
517
+ fontWeight: 600
518
+ };
519
+ const hintStyle = {
520
+ display: "flex",
521
+ alignItems: "center",
522
+ gap: 4,
523
+ marginTop: 3,
524
+ fontSize: 11,
525
+ opacity: 0.85
526
+ };
527
+ const keycapStyle = {
528
+ display: "inline-flex",
529
+ alignItems: "center",
530
+ justifyContent: "center",
531
+ minWidth: 16,
532
+ height: 16,
533
+ padding: "0 4px",
534
+ fontSize: 11,
535
+ fontFamily: "system-ui, -apple-system, sans-serif",
536
+ background: "rgba(255,255,255,0.16)",
537
+ border: "1px solid rgba(255,255,255,0.4)",
538
+ borderRadius: 4,
539
+ boxShadow: "inset 0 -1px 0 rgba(0,0,0,0.25)"
540
+ };
541
+ if (typeof document === "undefined") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
542
+ return (0, import_react_dom.createPortal)(
543
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style, contentEditable: false, "aria-hidden": true, role: "tooltip", children: [
544
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: urlStyle, children: href }),
545
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: hintStyle, children: [
546
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("kbd", { style: keycapStyle, children: MOD_SYMBOL }),
547
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { opacity: 0.8 }, children: "+ clique para abrir" })
548
+ ] })
549
+ ] }),
550
+ document.body
551
+ );
552
+ }
553
+
321
554
  // src/EditorContext.tsx
322
- var import_react4 = require("react");
555
+ var import_react5 = require("react");
323
556
 
324
557
  // src/LinkDialog.tsx
325
- var import_react = require("react");
326
- var import_jsx_runtime = require("react/jsx-runtime");
558
+ var import_react2 = require("react");
559
+
560
+ // src/dialogCenterStyle.ts
561
+ var DIALOG_CENTER_STYLE = {
562
+ position: "fixed",
563
+ top: "50%",
564
+ left: "50%",
565
+ transform: "translate(-50%, -50%)",
566
+ margin: 0,
567
+ maxHeight: "90vh",
568
+ overflow: "auto"
569
+ };
570
+
571
+ // src/LinkDialog.tsx
572
+ var import_jsx_runtime3 = require("react/jsx-runtime");
327
573
  function LinkDialog() {
328
574
  const { linkRequest, resolveLinkRequest } = useEditorContext();
329
- const dialogRef = (0, import_react.useRef)(null);
330
- const inputRef = (0, import_react.useRef)(null);
331
- const [href, setHref] = (0, import_react.useState)("");
332
- (0, import_react.useEffect)(() => {
575
+ const dialogRef = (0, import_react2.useRef)(null);
576
+ const inputRef = (0, import_react2.useRef)(null);
577
+ const [href, setHref] = (0, import_react2.useState)("");
578
+ (0, import_react2.useEffect)(() => {
333
579
  const dialog = dialogRef.current;
334
580
  if (!dialog) return;
335
581
  if (linkRequest) {
@@ -357,20 +603,21 @@ function LinkDialog() {
357
603
  const onCancel = () => {
358
604
  resolveLinkRequest(null);
359
605
  };
360
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
606
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
361
607
  "dialog",
362
608
  {
363
609
  ref: dialogRef,
364
610
  className: "ed-link-dialog",
611
+ style: DIALOG_CENTER_STYLE,
365
612
  onClose: onCancel,
366
613
  onCancel: (e) => {
367
614
  e.preventDefault();
368
615
  onCancel();
369
616
  },
370
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit, className: "ed-link-dialog-form", children: [
371
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ed-link-dialog-row", children: [
372
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "ed-link-href", children: "URL" }),
373
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
617
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit, className: "ed-link-dialog-form", children: [
618
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-row", children: [
619
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: "ed-link-href", children: "URL" }),
620
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
374
621
  "input",
375
622
  {
376
623
  id: "ed-link-href",
@@ -384,11 +631,11 @@ function LinkDialog() {
384
631
  }
385
632
  )
386
633
  ] }),
387
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ed-link-dialog-actions", children: [
388
- linkRequest.initialHref ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover link" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {}),
389
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ed-link-dialog-confirm", children: [
390
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
391
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
634
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-actions", children: [
635
+ linkRequest.initialHref ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover link" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", {}),
636
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-confirm", children: [
637
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
638
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
392
639
  ] })
393
640
  ] })
394
641
  ] })
@@ -397,21 +644,21 @@ function LinkDialog() {
397
644
  }
398
645
 
399
646
  // src/PageConfigDialog.tsx
400
- var import_react2 = require("react");
647
+ var import_react3 = require("react");
401
648
  var import_core = require("@sofereditor/core");
402
- var import_jsx_runtime2 = require("react/jsx-runtime");
649
+ var import_jsx_runtime4 = require("react/jsx-runtime");
403
650
  function PageConfigDialog() {
404
651
  const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();
405
- const dialogRef = (0, import_react2.useRef)(null);
406
- const [sizePreset, setSizePreset] = (0, import_react2.useState)("a4");
407
- const [widthMm, setWidthMm] = (0, import_react2.useState)(210);
408
- const [heightMm, setHeightMm] = (0, import_react2.useState)(297);
409
- const [marginPreset, setMarginPreset] = (0, import_react2.useState)("normal");
410
- const [marginTopMm, setMarginTopMm] = (0, import_react2.useState)(25.4);
411
- const [marginBottomMm, setMarginBottomMm] = (0, import_react2.useState)(25.4);
412
- const [marginLeftMm, setMarginLeftMm] = (0, import_react2.useState)(25.4);
413
- const [marginRightMm, setMarginRightMm] = (0, import_react2.useState)(25.4);
414
- (0, import_react2.useEffect)(() => {
652
+ const dialogRef = (0, import_react3.useRef)(null);
653
+ const [sizePreset, setSizePreset] = (0, import_react3.useState)("a4");
654
+ const [widthMm, setWidthMm] = (0, import_react3.useState)(210);
655
+ const [heightMm, setHeightMm] = (0, import_react3.useState)(297);
656
+ const [marginPreset, setMarginPreset] = (0, import_react3.useState)("normal");
657
+ const [marginTopMm, setMarginTopMm] = (0, import_react3.useState)(25.4);
658
+ const [marginBottomMm, setMarginBottomMm] = (0, import_react3.useState)(25.4);
659
+ const [marginLeftMm, setMarginLeftMm] = (0, import_react3.useState)(25.4);
660
+ const [marginRightMm, setMarginRightMm] = (0, import_react3.useState)(25.4);
661
+ (0, import_react3.useEffect)(() => {
415
662
  const dialog = dialogRef.current;
416
663
  if (!dialog) return;
417
664
  if (pageConfigRequest) {
@@ -430,13 +677,13 @@ function PageConfigDialog() {
430
677
  dialog.close();
431
678
  }
432
679
  }, [pageConfigRequest]);
433
- (0, import_react2.useEffect)(() => {
680
+ (0, import_react3.useEffect)(() => {
434
681
  if (sizePreset === "custom") return;
435
682
  const p = import_core.PAGE_PRESETS[sizePreset];
436
683
  setWidthMm(roundMm((0, import_core.pxToMm)(p.width)));
437
684
  setHeightMm(roundMm((0, import_core.pxToMm)(p.height)));
438
685
  }, [sizePreset]);
439
- (0, import_react2.useEffect)(() => {
686
+ (0, import_react3.useEffect)(() => {
440
687
  if (marginPreset === "custom") return;
441
688
  const px = import_core.MARGIN_PRESETS[marginPreset];
442
689
  const mm = roundMm((0, import_core.pxToMm)(px));
@@ -446,7 +693,7 @@ function PageConfigDialog() {
446
693
  setMarginRightMm(mm);
447
694
  }, [marginPreset]);
448
695
  const customWidth = sizePreset === "custom";
449
- const previewPx = (0, import_react2.useMemo)(
696
+ const previewPx = (0, import_react3.useMemo)(
450
697
  () => ({
451
698
  width: Math.round((0, import_core.mmToPx)(widthMm)),
452
699
  height: Math.round((0, import_core.mmToPx)(heightMm))
@@ -468,23 +715,24 @@ function PageConfigDialog() {
468
715
  resolvePageConfigRequest(true);
469
716
  };
470
717
  const onCancel = () => resolvePageConfigRequest(false);
471
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
718
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
472
719
  "dialog",
473
720
  {
474
721
  ref: dialogRef,
475
722
  className: "ed-page-config-dialog",
723
+ style: DIALOG_CENTER_STYLE,
476
724
  onClose: onCancel,
477
725
  onCancel: (e) => {
478
726
  e.preventDefault();
479
727
  onCancel();
480
728
  },
481
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: onApply, className: "ed-page-config-form", children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: "Configurar p\xE1gina" }),
483
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("fieldset", { children: [
484
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("legend", { children: "Tamanho" }),
485
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ed-page-config-row", children: [
486
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
487
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
729
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: onApply, className: "ed-page-config-form", children: [
730
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { children: "Configurar p\xE1gina" }),
731
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("fieldset", { children: [
732
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("legend", { children: "Tamanho" }),
733
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ed-page-config-row", children: [
734
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
735
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
488
736
  "input",
489
737
  {
490
738
  type: "radio",
@@ -496,8 +744,8 @@ function PageConfigDialog() {
496
744
  " ",
497
745
  "A4 (210 \xD7 297 mm)"
498
746
  ] }),
499
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
500
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
747
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
748
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
501
749
  "input",
502
750
  {
503
751
  type: "radio",
@@ -509,8 +757,8 @@ function PageConfigDialog() {
509
757
  " ",
510
758
  "Carta (216 \xD7 279 mm)"
511
759
  ] }),
512
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
513
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
760
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
761
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
514
762
  "input",
515
763
  {
516
764
  type: "radio",
@@ -522,8 +770,8 @@ function PageConfigDialog() {
522
770
  " ",
523
771
  "Of\xEDcio (216 \xD7 330 mm)"
524
772
  ] }),
525
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
526
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
773
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
527
775
  "input",
528
776
  {
529
777
  type: "radio",
@@ -536,11 +784,11 @@ function PageConfigDialog() {
536
784
  "Personalizado"
537
785
  ] })
538
786
  ] }),
539
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ed-page-config-row", children: [
540
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
787
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ed-page-config-row", children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
541
789
  "Largura (mm)",
542
790
  " ",
543
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
791
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
544
792
  "input",
545
793
  {
546
794
  type: "number",
@@ -553,10 +801,10 @@ function PageConfigDialog() {
553
801
  }
554
802
  )
555
803
  ] }),
556
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
804
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
557
805
  "Altura (mm)",
558
806
  " ",
559
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
807
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
560
808
  "input",
561
809
  {
562
810
  type: "number",
@@ -569,7 +817,7 @@ function PageConfigDialog() {
569
817
  }
570
818
  )
571
819
  ] }),
572
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ed-page-config-preview", children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ed-page-config-preview", children: [
573
821
  previewPx.width,
574
822
  " \xD7 ",
575
823
  previewPx.height,
@@ -577,11 +825,11 @@ function PageConfigDialog() {
577
825
  ] })
578
826
  ] })
579
827
  ] }),
580
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("fieldset", { children: [
581
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("legend", { children: "Margens" }),
582
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ed-page-config-row", children: [
583
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
584
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
828
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("fieldset", { children: [
829
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("legend", { children: "Margens" }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ed-page-config-row", children: [
831
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
585
833
  "input",
586
834
  {
587
835
  type: "radio",
@@ -593,8 +841,8 @@ function PageConfigDialog() {
593
841
  " ",
594
842
  "Normal (25,4 mm)"
595
843
  ] }),
596
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
597
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
844
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
845
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
598
846
  "input",
599
847
  {
600
848
  type: "radio",
@@ -606,8 +854,8 @@ function PageConfigDialog() {
606
854
  " ",
607
855
  "Estreita (12,7 mm)"
608
856
  ] }),
609
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
610
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
857
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
611
859
  "input",
612
860
  {
613
861
  type: "radio",
@@ -619,8 +867,8 @@ function PageConfigDialog() {
619
867
  " ",
620
868
  "Larga (50,8 mm)"
621
869
  ] }),
622
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
623
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
870
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
871
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
624
872
  "input",
625
873
  {
626
874
  type: "radio",
@@ -633,11 +881,11 @@ function PageConfigDialog() {
633
881
  "Personalizada"
634
882
  ] })
635
883
  ] }),
636
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ed-page-config-row", children: [
637
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ed-page-config-row", children: [
885
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
638
886
  "Topo",
639
887
  " ",
640
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
888
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
641
889
  "input",
642
890
  {
643
891
  type: "number",
@@ -652,10 +900,10 @@ function PageConfigDialog() {
652
900
  }
653
901
  )
654
902
  ] }),
655
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
903
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
656
904
  "Inferior",
657
905
  " ",
658
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
906
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
659
907
  "input",
660
908
  {
661
909
  type: "number",
@@ -670,10 +918,10 @@ function PageConfigDialog() {
670
918
  }
671
919
  )
672
920
  ] }),
673
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
674
922
  "Esquerda",
675
923
  " ",
676
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
924
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
677
925
  "input",
678
926
  {
679
927
  type: "number",
@@ -688,10 +936,10 @@ function PageConfigDialog() {
688
936
  }
689
937
  )
690
938
  ] }),
691
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
692
940
  "Direita",
693
941
  " ",
694
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
942
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
695
943
  "input",
696
944
  {
697
945
  type: "number",
@@ -708,9 +956,9 @@ function PageConfigDialog() {
708
956
  ] })
709
957
  ] })
710
958
  ] }),
711
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ed-page-config-actions", children: [
712
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
713
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", className: "ed-page-config-apply", children: "Aplicar" })
959
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ed-page-config-actions", children: [
960
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "submit", className: "ed-page-config-apply", children: "Aplicar" })
714
962
  ] })
715
963
  ] })
716
964
  }
@@ -745,15 +993,15 @@ function detectMarginPreset(s) {
745
993
  }
746
994
 
747
995
  // src/ImageCaptionDialog.tsx
748
- var import_react3 = require("react");
749
- var import_jsx_runtime3 = require("react/jsx-runtime");
996
+ var import_react4 = require("react");
997
+ var import_jsx_runtime5 = require("react/jsx-runtime");
750
998
  function ImageCaptionDialog() {
751
999
  const { imageCaptionRequest, resolveImageCaptionRequest } = useEditorContext();
752
- const dialogRef = (0, import_react3.useRef)(null);
753
- const inputRef = (0, import_react3.useRef)(null);
754
- const [caption, setCaption] = (0, import_react3.useState)("");
755
- const [align, setAlign] = (0, import_react3.useState)("center");
756
- (0, import_react3.useEffect)(() => {
1000
+ const dialogRef = (0, import_react4.useRef)(null);
1001
+ const inputRef = (0, import_react4.useRef)(null);
1002
+ const [caption, setCaption] = (0, import_react4.useState)("");
1003
+ const [align, setAlign] = (0, import_react4.useState)("center");
1004
+ (0, import_react4.useEffect)(() => {
757
1005
  const dialog = dialogRef.current;
758
1006
  if (!dialog) return;
759
1007
  if (imageCaptionRequest) {
@@ -778,20 +1026,21 @@ function ImageCaptionDialog() {
778
1026
  };
779
1027
  const onRemove = () => resolveImageCaptionRequest({ caption: "", align });
780
1028
  const onCancel = () => resolveImageCaptionRequest(null);
781
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1029
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
782
1030
  "dialog",
783
1031
  {
784
1032
  ref: dialogRef,
785
1033
  className: "ed-caption-dialog ed-link-dialog",
1034
+ style: DIALOG_CENTER_STYLE,
786
1035
  onClose: onCancel,
787
1036
  onCancel: (e) => {
788
1037
  e.preventDefault();
789
1038
  onCancel();
790
1039
  },
791
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit, className: "ed-link-dialog-form", children: [
792
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-row", children: [
793
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: "ed-caption-input", children: "Legenda" }),
794
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1040
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit, className: "ed-link-dialog-form", children: [
1041
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ed-link-dialog-row", children: [
1042
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: "ed-caption-input", children: "Legenda" }),
1043
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
795
1044
  "input",
796
1045
  {
797
1046
  id: "ed-caption-input",
@@ -804,10 +1053,10 @@ function ImageCaptionDialog() {
804
1053
  }
805
1054
  )
806
1055
  ] }),
807
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-row", children: [
808
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Alinhamento" }),
809
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ed-caption-align-group", role: "radiogroup", "aria-label": "Alinhamento da legenda", children: ["left", "center", "right"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "ed-caption-align-option", children: [
810
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1056
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ed-link-dialog-row", children: [
1057
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Alinhamento" }),
1058
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ed-caption-align-group", role: "radiogroup", "aria-label": "Alinhamento da legenda", children: ["left", "center", "right"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "ed-caption-align-option", children: [
1059
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
811
1060
  "input",
812
1061
  {
813
1062
  type: "radio",
@@ -820,11 +1069,11 @@ function ImageCaptionDialog() {
820
1069
  value === "left" ? "Esquerda" : value === "center" ? "Centro" : "Direita"
821
1070
  ] }, value)) })
822
1071
  ] }),
823
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-actions", children: [
824
- imageCaptionRequest.initialCaption ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover legenda" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", {}),
825
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ed-link-dialog-confirm", children: [
826
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
827
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
1072
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ed-link-dialog-actions", children: [
1073
+ imageCaptionRequest.initialCaption ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: onRemove, className: "ed-link-dialog-remove", children: "Remover legenda" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
1074
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ed-link-dialog-confirm", children: [
1075
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
1076
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "submit", className: "ed-link-dialog-apply", children: "Aplicar" })
828
1077
  ] })
829
1078
  ] })
830
1079
  ] })
@@ -833,18 +1082,18 @@ function ImageCaptionDialog() {
833
1082
  }
834
1083
 
835
1084
  // src/EditorContext.tsx
836
- var import_jsx_runtime4 = require("react/jsx-runtime");
837
- var EditorContext = (0, import_react4.createContext)(null);
1085
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1086
+ var EditorContext = (0, import_react5.createContext)(null);
838
1087
  function EditorProvider({ editor, children }) {
839
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(EditorContext.Provider, { value: editor, children: [
1088
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(EditorContext.Provider, { value: editor, children: [
840
1089
  children,
841
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LinkDialog, {}),
842
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PageConfigDialog, {}),
843
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ImageCaptionDialog, {})
1090
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LinkDialog, {}),
1091
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PageConfigDialog, {}),
1092
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageCaptionDialog, {})
844
1093
  ] });
845
1094
  }
846
1095
  function useEditorContext() {
847
- const ctx = (0, import_react4.useContext)(EditorContext);
1096
+ const ctx = (0, import_react5.useContext)(EditorContext);
848
1097
  if (!ctx) {
849
1098
  throw new Error("useEditorContext must be used inside an <EditorProvider>");
850
1099
  }
@@ -852,8 +1101,8 @@ function useEditorContext() {
852
1101
  }
853
1102
 
854
1103
  // src/ImageResizeOverlay.tsx
855
- var import_react5 = require("react");
856
- var import_jsx_runtime5 = require("react/jsx-runtime");
1104
+ var import_react6 = require("react");
1105
+ var import_jsx_runtime7 = require("react/jsx-runtime");
857
1106
  function ImageResizeOverlay({
858
1107
  rootRef,
859
1108
  blockIndex,
@@ -861,11 +1110,13 @@ function ImageResizeOverlay({
861
1110
  cellIndex,
862
1111
  embed,
863
1112
  onCommit,
864
- onCommitMove
1113
+ onCommitMove,
1114
+ onReanchor
865
1115
  }) {
866
- const [rect, setRect] = (0, import_react5.useState)(null);
867
- const imgRef = (0, import_react5.useRef)(null);
868
- const locateImage = (0, import_react5.useCallback)(() => {
1116
+ const [rect, setRect] = (0, import_react6.useState)(null);
1117
+ const [isMoving, setIsMoving] = (0, import_react6.useState)(false);
1118
+ const imgRef = (0, import_react6.useRef)(null);
1119
+ const locateImage = (0, import_react6.useCallback)(() => {
869
1120
  const root = rootRef.current;
870
1121
  if (!root) return null;
871
1122
  let container = null;
@@ -883,7 +1134,7 @@ function ImageResizeOverlay({
883
1134
  `img[data-embed="image"][data-embed-offset="${localOffset}"]`
884
1135
  );
885
1136
  }, [rootRef, blockIndex, offset, cellIndex]);
886
- const measure = (0, import_react5.useCallback)(() => {
1137
+ const measure = (0, import_react6.useCallback)(() => {
887
1138
  const img = locateImage();
888
1139
  if (!img) {
889
1140
  setRect((prev) => prev === null ? prev : null);
@@ -904,22 +1155,28 @@ function ImageResizeOverlay({
904
1155
  (prev) => prev && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
905
1156
  );
906
1157
  }, [locateImage, rootRef]);
907
- (0, import_react5.useLayoutEffect)(() => {
1158
+ (0, import_react6.useLayoutEffect)(() => {
908
1159
  measure();
909
1160
  let cancelled = false;
1161
+ let frame = 0;
1162
+ let rafId = 0;
910
1163
  const remeasure = () => {
911
1164
  if (cancelled) return;
912
1165
  measure();
1166
+ if (!locateImage() && frame++ < 30) {
1167
+ rafId = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
1168
+ }
913
1169
  };
914
- const id = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
1170
+ rafId = typeof requestAnimationFrame === "function" ? requestAnimationFrame(remeasure) : (queueMicrotask(remeasure), 0);
915
1171
  return () => {
916
1172
  cancelled = true;
917
- if (typeof cancelAnimationFrame === "function" && typeof id === "number" && id > 0) {
918
- cancelAnimationFrame(id);
1173
+ if (typeof cancelAnimationFrame === "function" && typeof rafId === "number" && rafId > 0) {
1174
+ cancelAnimationFrame(rafId);
919
1175
  }
920
1176
  };
921
1177
  }, [
922
1178
  measure,
1179
+ locateImage,
923
1180
  embed.width,
924
1181
  embed.height,
925
1182
  embed.align,
@@ -928,7 +1185,7 @@ function ImageResizeOverlay({
928
1185
  embed.offsetX,
929
1186
  embed.offsetY
930
1187
  ]);
931
- (0, import_react5.useEffect)(() => {
1188
+ (0, import_react6.useEffect)(() => {
932
1189
  const root = rootRef.current;
933
1190
  if (!root) return;
934
1191
  const onScroll = () => measure();
@@ -939,7 +1196,7 @@ function ImageResizeOverlay({
939
1196
  root.removeEventListener("scroll", onScroll);
940
1197
  };
941
1198
  }, [measure, rootRef]);
942
- (0, import_react5.useEffect)(() => {
1199
+ (0, import_react6.useEffect)(() => {
943
1200
  if (typeof ResizeObserver === "undefined") return;
944
1201
  const img = locateImage();
945
1202
  const root = rootRef.current;
@@ -952,14 +1209,36 @@ function ImageResizeOverlay({
952
1209
  if (!rect) return null;
953
1210
  const layout = embed.layout ?? "inline";
954
1211
  const movable = layout !== "inline" && onCommitMove !== void 0;
955
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1212
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
956
1213
  "div",
957
1214
  {
958
1215
  className: "ed-image-overlay",
959
1216
  style: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },
960
1217
  contentEditable: false,
961
1218
  children: [
962
- movable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1219
+ isMoving && // Non-clipped drag preview (Tier 2): the overlay lives in .ed-root and
1220
+ // follows the cursor, so the image stays visible while it crosses the
1221
+ // page boundary (the real, clipped figure is hidden during the drag).
1222
+ // Inline styles only — the package does not ship CSS.
1223
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1224
+ "img",
1225
+ {
1226
+ src: embed.src,
1227
+ alt: "",
1228
+ "aria-hidden": true,
1229
+ draggable: false,
1230
+ style: {
1231
+ position: "absolute",
1232
+ inset: 0,
1233
+ width: "100%",
1234
+ height: "100%",
1235
+ objectFit: "fill",
1236
+ opacity: 0.8,
1237
+ pointerEvents: "none"
1238
+ }
1239
+ }
1240
+ ),
1241
+ movable && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
963
1242
  MoveHandle,
964
1243
  {
965
1244
  layout,
@@ -967,10 +1246,17 @@ function ImageResizeOverlay({
967
1246
  startOffsetY: embed.offsetY ?? 0,
968
1247
  imgRef,
969
1248
  onCommit: onCommitMove,
970
- onLiveChange: measure
1249
+ onLiveChange: measure,
1250
+ rootRef,
1251
+ blockIndex,
1252
+ offset,
1253
+ cellIndex,
1254
+ onReanchor,
1255
+ onMoveStart: () => setIsMoving(true),
1256
+ onMoveEnd: () => setIsMoving(false)
971
1257
  }
972
1258
  ),
973
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1259
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
974
1260
  Handle,
975
1261
  {
976
1262
  corner: "nw",
@@ -981,7 +1267,7 @@ function ImageResizeOverlay({
981
1267
  onLiveChange: measure
982
1268
  }
983
1269
  ),
984
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1270
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
985
1271
  Handle,
986
1272
  {
987
1273
  corner: "ne",
@@ -992,7 +1278,7 @@ function ImageResizeOverlay({
992
1278
  onLiveChange: measure
993
1279
  }
994
1280
  ),
995
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1281
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
996
1282
  Handle,
997
1283
  {
998
1284
  corner: "sw",
@@ -1003,7 +1289,7 @@ function ImageResizeOverlay({
1003
1289
  onLiveChange: measure
1004
1290
  }
1005
1291
  ),
1006
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1292
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1007
1293
  Handle,
1008
1294
  {
1009
1295
  corner: "se",
@@ -1024,9 +1310,16 @@ function MoveHandle({
1024
1310
  startOffsetY,
1025
1311
  imgRef,
1026
1312
  onCommit,
1027
- onLiveChange
1313
+ onLiveChange,
1314
+ rootRef,
1315
+ blockIndex,
1316
+ offset,
1317
+ cellIndex,
1318
+ onReanchor,
1319
+ onMoveStart,
1320
+ onMoveEnd
1028
1321
  }) {
1029
- const dragRef = (0, import_react5.useRef)(null);
1322
+ const dragRef = (0, import_react6.useRef)(null);
1030
1323
  const onPointerDown = (e) => {
1031
1324
  if (e.button !== 0) return;
1032
1325
  if (!imgRef.current) return;
@@ -1039,35 +1332,65 @@ function MoveHandle({
1039
1332
  liveOX: startOffsetX,
1040
1333
  liveOY: startOffsetY
1041
1334
  };
1335
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1336
+ styled.style.opacity = "0";
1337
+ onMoveStart?.();
1042
1338
  };
1043
1339
  const onPointerMove = (e) => {
1044
1340
  const d = dragRef.current;
1045
1341
  if (!d || !imgRef.current) return;
1046
1342
  const dx = e.clientX - d.startX;
1047
1343
  const dy = e.clientY - d.startY;
1048
- const img = imgRef.current;
1344
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1049
1345
  let nox = startOffsetX;
1050
1346
  let noy = startOffsetY;
1051
1347
  if (layout === "wrap-left") {
1052
1348
  nox = Math.max(8, startOffsetX + dx);
1053
1349
  noy = Math.max(0, startOffsetY + dy);
1054
- img.style.marginRight = `${nox}px`;
1055
- img.style.marginTop = `${noy}px`;
1350
+ styled.style.marginRight = `${nox}px`;
1351
+ styled.style.marginTop = `${noy}px`;
1056
1352
  } else if (layout === "wrap-right") {
1057
1353
  nox = Math.max(8, startOffsetX - dx);
1058
1354
  noy = Math.max(0, startOffsetY + dy);
1059
- img.style.marginLeft = `${nox}px`;
1060
- img.style.marginTop = `${noy}px`;
1355
+ styled.style.marginLeft = `${nox}px`;
1356
+ styled.style.marginTop = `${noy}px`;
1061
1357
  } else if (layout === "behind" || layout === "front") {
1062
1358
  nox = startOffsetX + dx;
1063
1359
  noy = startOffsetY + dy;
1064
- img.style.left = `${nox}px`;
1065
- img.style.top = `${noy}px`;
1360
+ styled.style.left = `${nox}px`;
1361
+ styled.style.top = `${noy}px`;
1066
1362
  }
1067
1363
  d.liveOX = nox;
1068
1364
  d.liveOY = noy;
1069
1365
  onLiveChange();
1070
1366
  };
1367
+ const clampOffsetToFragment = (frag, oy) => {
1368
+ const img = imgRef.current;
1369
+ if (!img) return oy;
1370
+ const page = frag.closest(".ed-page");
1371
+ const content = page?.querySelector(".ed-page-content");
1372
+ if (!content) return oy;
1373
+ const fragRect = frag.getBoundingClientRect();
1374
+ const contentRect = content.getBoundingClientRect();
1375
+ const imgH = img.getBoundingClientRect().height;
1376
+ const minLocalTop = contentRect.top - fragRect.top;
1377
+ const maxLocalTop = contentRect.bottom - fragRect.top - imgH;
1378
+ return Math.round(Math.max(minLocalTop, Math.min(oy, maxLocalTop)));
1379
+ };
1380
+ const clampedCommit = (ox, oy) => {
1381
+ const img = imgRef.current;
1382
+ const root = rootRef.current;
1383
+ if (!img || !root || layout !== "behind" && layout !== "front") {
1384
+ onCommit(ox, oy);
1385
+ return;
1386
+ }
1387
+ const frag = getFragmentForOffset(root, blockIndex, offset);
1388
+ if (!frag) {
1389
+ onCommit(ox, oy);
1390
+ return;
1391
+ }
1392
+ onCommit(ox, clampOffsetToFragment(frag, oy));
1393
+ };
1071
1394
  const finish = (e) => {
1072
1395
  const d = dragRef.current;
1073
1396
  if (!d) return;
@@ -1076,9 +1399,77 @@ function MoveHandle({
1076
1399
  e.target.releasePointerCapture(e.pointerId);
1077
1400
  } catch {
1078
1401
  }
1079
- onCommit(Math.round(d.liveOX), Math.round(d.liveOY));
1402
+ if (imgRef.current) {
1403
+ const styled = imgRef.current.closest(".ed-figure") ?? imgRef.current;
1404
+ styled.style.opacity = "";
1405
+ }
1406
+ onMoveEnd?.();
1407
+ const img = imgRef.current;
1408
+ const root = rootRef.current;
1409
+ const liveOX = Math.round(d.liveOX);
1410
+ const liveOY = Math.round(d.liveOY);
1411
+ if (!img || !root || onReanchor === void 0 || cellIndex != null) {
1412
+ clampedCommit(liveOX, liveOY);
1413
+ return;
1414
+ }
1415
+ const imgRect = img.getBoundingClientRect();
1416
+ const centerY = imgRect.top + imgRect.height / 2;
1417
+ const pages = Array.from(root.querySelectorAll(".ed-page"));
1418
+ let destPage = null;
1419
+ let bestPageDist = Infinity;
1420
+ for (const pg of pages) {
1421
+ const r = pg.getBoundingClientRect();
1422
+ if (centerY >= r.top && centerY <= r.bottom) {
1423
+ destPage = pg;
1424
+ break;
1425
+ }
1426
+ const dist = centerY < r.top ? r.top - centerY : centerY - r.bottom;
1427
+ if (dist < bestPageDist) {
1428
+ bestPageDist = dist;
1429
+ destPage = pg;
1430
+ }
1431
+ }
1432
+ const currentFrag = getFragmentForOffset(root, blockIndex, offset);
1433
+ const currentPage = currentFrag?.closest(".ed-page") ?? null;
1434
+ if (destPage == null || destPage === currentPage) {
1435
+ clampedCommit(liveOX, liveOY);
1436
+ return;
1437
+ }
1438
+ const blocksOnPage = Array.from(
1439
+ destPage.querySelectorAll("[data-block-index]")
1440
+ );
1441
+ let destFrag = null;
1442
+ let bestBlockDist = Infinity;
1443
+ for (const b of blocksOnPage) {
1444
+ const dist = Math.abs(b.getBoundingClientRect().top - imgRect.top);
1445
+ if (dist < bestBlockDist) {
1446
+ bestBlockDist = dist;
1447
+ destFrag = b;
1448
+ }
1449
+ }
1450
+ if (!destFrag) {
1451
+ clampedCommit(liveOX, liveOY);
1452
+ return;
1453
+ }
1454
+ const destBlockIndex = findBlockIndex(destFrag, root);
1455
+ if (destBlockIndex == null) {
1456
+ clampedCommit(liveOX, liveOY);
1457
+ return;
1458
+ }
1459
+ const destOffset = destFrag.dataset.fragmentStart ? Number.parseInt(destFrag.dataset.fragmentStart, 10) || 0 : 0;
1460
+ const fragRect = destFrag.getBoundingClientRect();
1461
+ const newOffsetX = Math.round(imgRect.left - fragRect.left);
1462
+ const newOffsetY = clampOffsetToFragment(
1463
+ destFrag,
1464
+ Math.round(imgRect.top - fragRect.top)
1465
+ );
1466
+ onReanchor(
1467
+ { blockIndex: destBlockIndex, offset: destOffset, cellIndex: void 0 },
1468
+ newOffsetX,
1469
+ newOffsetY
1470
+ );
1080
1471
  };
1081
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1082
1473
  "div",
1083
1474
  {
1084
1475
  className: "ed-image-move",
@@ -1098,7 +1489,7 @@ function Handle({
1098
1489
  onCommit,
1099
1490
  onLiveChange
1100
1491
  }) {
1101
- const dragRef = (0, import_react5.useRef)(null);
1492
+ const dragRef = (0, import_react6.useRef)(null);
1102
1493
  const onPointerDown = (e) => {
1103
1494
  if (e.button !== 0) return;
1104
1495
  if (!imgRef.current) return;
@@ -1141,7 +1532,7 @@ function Handle({
1141
1532
  }
1142
1533
  onCommit(Math.round(d.liveW), Math.round(d.liveH));
1143
1534
  };
1144
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1535
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1145
1536
  "div",
1146
1537
  {
1147
1538
  className: `ed-image-handle ${corner}`,
@@ -1153,17 +1544,187 @@ function Handle({
1153
1544
  );
1154
1545
  }
1155
1546
 
1547
+ // src/RemoteCursorsOverlay.tsx
1548
+ var import_react7 = require("react");
1549
+ var import_core2 = require("@sofereditor/core");
1550
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1551
+ var DEFAULT_COLOR = "#3b82f6";
1552
+ function RemoteCursorsOverlay({
1553
+ rootRef,
1554
+ doc,
1555
+ awareness,
1556
+ revision
1557
+ }) {
1558
+ const [views, setViews] = (0, import_react7.useState)([]);
1559
+ const rafRef = (0, import_react7.useRef)(null);
1560
+ const measure = (0, import_react7.useCallback)(() => {
1561
+ const root = rootRef.current;
1562
+ if (!root) {
1563
+ setViews((prev) => prev.length === 0 ? prev : []);
1564
+ return;
1565
+ }
1566
+ const rr = root.getBoundingClientRect();
1567
+ const out = [];
1568
+ awareness.getStates().forEach((state, clientId) => {
1569
+ if (clientId === awareness.clientID) return;
1570
+ const s = state;
1571
+ if (!s.cursor) return;
1572
+ const sel = (0, import_core2.decodeSelection)(doc, s.cursor);
1573
+ if (!sel) return;
1574
+ const color = s.user?.color || DEFAULT_COLOR;
1575
+ const name = s.user?.name || "An\xF4nimo";
1576
+ const focus = locatePoint(root, sel.focus);
1577
+ let caret = null;
1578
+ if (focus) {
1579
+ try {
1580
+ const range = document.createRange();
1581
+ range.setStart(focus.node, focus.offset);
1582
+ range.collapse(true);
1583
+ let rect = range.getBoundingClientRect();
1584
+ if (rect.height === 0 && focus.node.nodeType === Node.ELEMENT_NODE) {
1585
+ rect = focus.node.getBoundingClientRect();
1586
+ }
1587
+ caret = {
1588
+ top: rect.top - rr.top + root.scrollTop,
1589
+ left: rect.left - rr.left + root.scrollLeft,
1590
+ height: rect.height || 18
1591
+ };
1592
+ } catch {
1593
+ }
1594
+ }
1595
+ const collapsed = sel.anchor.blockIndex === sel.focus.blockIndex && (sel.anchor.cellIndex ?? -1) === (sel.focus.cellIndex ?? -1) && sel.anchor.offset === sel.focus.offset;
1596
+ const selection = [];
1597
+ if (!collapsed && focus) {
1598
+ const anchor = locatePoint(root, sel.anchor);
1599
+ if (anchor) {
1600
+ try {
1601
+ const r = document.createRange();
1602
+ r.setStart(anchor.node, anchor.offset);
1603
+ r.setEnd(focus.node, focus.offset);
1604
+ if (r.collapsed) {
1605
+ r.setStart(focus.node, focus.offset);
1606
+ r.setEnd(anchor.node, anchor.offset);
1607
+ }
1608
+ for (const cr of Array.from(r.getClientRects())) {
1609
+ if (cr.width === 0 || cr.height === 0) continue;
1610
+ selection.push({
1611
+ top: cr.top - rr.top + root.scrollTop,
1612
+ left: cr.left - rr.left + root.scrollLeft,
1613
+ width: cr.width,
1614
+ height: cr.height
1615
+ });
1616
+ }
1617
+ } catch {
1618
+ }
1619
+ }
1620
+ }
1621
+ out.push({ clientId, name, color, caret, selection });
1622
+ });
1623
+ setViews(out);
1624
+ }, [rootRef, doc, awareness]);
1625
+ const scheduleMeasure = (0, import_react7.useCallback)(() => {
1626
+ if (rafRef.current != null) return;
1627
+ const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(() => cb(0), 16);
1628
+ rafRef.current = raf(() => {
1629
+ rafRef.current = null;
1630
+ measure();
1631
+ });
1632
+ }, [measure]);
1633
+ (0, import_react7.useEffect)(() => {
1634
+ const onChange = () => scheduleMeasure();
1635
+ awareness.on("change", onChange);
1636
+ scheduleMeasure();
1637
+ return () => awareness.off("change", onChange);
1638
+ }, [awareness, scheduleMeasure]);
1639
+ (0, import_react7.useEffect)(() => {
1640
+ scheduleMeasure();
1641
+ }, [revision, scheduleMeasure]);
1642
+ (0, import_react7.useEffect)(() => {
1643
+ const root = rootRef.current;
1644
+ if (!root) return;
1645
+ const onScroll = () => scheduleMeasure();
1646
+ root.addEventListener("scroll", onScroll, { passive: true });
1647
+ let ro = null;
1648
+ if (typeof ResizeObserver !== "undefined") {
1649
+ ro = new ResizeObserver(() => scheduleMeasure());
1650
+ ro.observe(root);
1651
+ }
1652
+ return () => {
1653
+ root.removeEventListener("scroll", onScroll);
1654
+ ro?.disconnect();
1655
+ };
1656
+ }, [rootRef, scheduleMeasure]);
1657
+ if (views.length === 0) return null;
1658
+ const layer = {
1659
+ position: "absolute",
1660
+ inset: 0,
1661
+ pointerEvents: "none",
1662
+ zIndex: 6
1663
+ };
1664
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ed-remote-cursors", "aria-hidden": true, style: layer, children: views.map((v) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1665
+ v.selection.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1666
+ "div",
1667
+ {
1668
+ style: {
1669
+ position: "absolute",
1670
+ top: r.top,
1671
+ left: r.left,
1672
+ width: r.width,
1673
+ height: r.height,
1674
+ background: v.color,
1675
+ opacity: 0.22,
1676
+ borderRadius: 2
1677
+ }
1678
+ },
1679
+ i
1680
+ )),
1681
+ v.caret && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1682
+ "div",
1683
+ {
1684
+ style: {
1685
+ position: "absolute",
1686
+ top: v.caret.top,
1687
+ left: v.caret.left,
1688
+ height: v.caret.height,
1689
+ width: 2,
1690
+ background: v.color
1691
+ },
1692
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1693
+ "span",
1694
+ {
1695
+ style: {
1696
+ position: "absolute",
1697
+ top: -15,
1698
+ left: -1,
1699
+ fontSize: 10,
1700
+ lineHeight: "14px",
1701
+ padding: "0 4px",
1702
+ borderRadius: 3,
1703
+ color: "#fff",
1704
+ background: v.color,
1705
+ whiteSpace: "nowrap",
1706
+ fontFamily: "system-ui, sans-serif",
1707
+ userSelect: "none"
1708
+ },
1709
+ children: v.name
1710
+ }
1711
+ )
1712
+ }
1713
+ )
1714
+ ] }, v.clientId)) });
1715
+ }
1716
+
1156
1717
  // src/NodeView.tsx
1157
- var import_react8 = require("react");
1158
- var import_core3 = require("@sofereditor/core");
1718
+ var import_react10 = require("react");
1719
+ var import_core4 = require("@sofereditor/core");
1159
1720
 
1160
1721
  // src/renderInline.tsx
1161
- var import_react6 = require("react");
1162
- var import_core2 = require("@sofereditor/core");
1163
- var import_jsx_runtime6 = require("react/jsx-runtime");
1722
+ var import_react8 = require("react");
1723
+ var import_core3 = require("@sofereditor/core");
1724
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1164
1725
  function renderInline(delta, keyPrefix) {
1165
1726
  if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
1166
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("br", { "data-empty": "true" });
1727
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", { "data-empty": "true" });
1167
1728
  }
1168
1729
  let offset = 0;
1169
1730
  const wrapAnchors = [];
@@ -1173,17 +1734,18 @@ function renderInline(delta, keyPrefix) {
1173
1734
  const text = op.insert;
1174
1735
  if (text.length === 0) continue;
1175
1736
  const key = `${keyPrefix}-${offset}`;
1176
- body.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react6.Fragment, { children: wrap(text, op.attributes) }, key));
1737
+ body.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: wrap(text, op.attributes) }, key));
1177
1738
  offset += text.length;
1178
- } else if ((0, import_core2.isImageEmbed)(op.insert)) {
1739
+ } else if ((0, import_core3.isImageEmbed)(op.insert)) {
1179
1740
  const key = `${keyPrefix}-${offset}`;
1180
1741
  const layout = op.insert.layout ?? "inline";
1742
+ const commentMarkId = op.attributes?.comment?.markId;
1181
1743
  if (layout === "wrap-left" || layout === "wrap-right") {
1182
1744
  wrapAnchors.push(
1183
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1745
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
1184
1746
  );
1185
1747
  body.push(
1186
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1748
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1187
1749
  "span",
1188
1750
  {
1189
1751
  "data-embed-phantom": "true",
@@ -1195,14 +1757,21 @@ function renderInline(delta, keyPrefix) {
1195
1757
  )
1196
1758
  );
1197
1759
  } else {
1198
- body.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageEmbedView, { embed: op.insert, offset }, key));
1760
+ const imgNode = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ImageEmbedView, { embed: op.insert, offset }, key);
1761
+ if (commentMarkId) {
1762
+ body.push(
1763
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1764
+ );
1765
+ } else {
1766
+ body.push(imgNode);
1767
+ }
1199
1768
  }
1200
1769
  offset += 1;
1201
1770
  } else if (op.insert != null) {
1202
1771
  offset += 1;
1203
1772
  }
1204
1773
  }
1205
- if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("br", { "data-empty": "true" });
1774
+ if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", { "data-empty": "true" });
1206
1775
  return [...wrapAnchors, ...body];
1207
1776
  }
1208
1777
  var PHANTOM_STYLE = {
@@ -1212,6 +1781,11 @@ var PHANTOM_STYLE = {
1212
1781
  overflow: "hidden",
1213
1782
  verticalAlign: "baseline"
1214
1783
  };
1784
+ var LINK_STYLE = {
1785
+ color: "#2563eb",
1786
+ textDecoration: "underline",
1787
+ cursor: "text"
1788
+ };
1215
1789
  function imageEmbedPropsEqual(a, b) {
1216
1790
  if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;
1217
1791
  const x = a.embed;
@@ -1222,7 +1796,7 @@ function imageEmbedPropsEqual(a, b) {
1222
1796
  // because Y.js stores the embed in its content map and re-exposes it.
1223
1797
  x.src === y.src;
1224
1798
  }
1225
- var ImageEmbedView = (0, import_react6.memo)(ImageEmbedViewImpl, imageEmbedPropsEqual);
1799
+ var ImageEmbedView = (0, import_react8.memo)(ImageEmbedViewImpl, imageEmbedPropsEqual);
1226
1800
  function ImageEmbedViewImpl({
1227
1801
  embed,
1228
1802
  offset,
@@ -1277,8 +1851,12 @@ function ImageEmbedViewImpl({
1277
1851
  };
1278
1852
  break;
1279
1853
  }
1280
- const imgStyle = hasCaption ? { width: embed.width, height: embed.height, display: "block" } : outerStyle;
1281
- const img = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1854
+ const imgStyle = {
1855
+ width: embed.width,
1856
+ height: embed.height,
1857
+ display: "block"
1858
+ };
1859
+ const img = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1282
1860
  "img",
1283
1861
  {
1284
1862
  src: embed.src,
@@ -1286,6 +1864,8 @@ function ImageEmbedViewImpl({
1286
1864
  height: embed.height,
1287
1865
  contentEditable: false,
1288
1866
  draggable: false,
1867
+ decoding: "sync",
1868
+ loading: "eager",
1289
1869
  "data-embed": "image",
1290
1870
  "data-embed-offset": offset,
1291
1871
  "data-embed-align": align ?? "",
@@ -1295,19 +1875,18 @@ function ImageEmbedViewImpl({
1295
1875
  alt: ""
1296
1876
  }
1297
1877
  );
1298
- if (!hasCaption) return img;
1299
1878
  const captionAlign = embed.captionAlign ?? "center";
1300
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1879
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1301
1880
  "figure",
1302
1881
  {
1303
1882
  className: "ed-figure",
1304
1883
  contentEditable: false,
1305
- "data-embed-figure": "true",
1884
+ "data-embed-figure": hasCaption ? "true" : void 0,
1306
1885
  "data-embed-layout": layout,
1307
1886
  style: outerStyle,
1308
1887
  children: [
1309
1888
  img,
1310
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1889
+ hasCaption && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1311
1890
  "figcaption",
1312
1891
  {
1313
1892
  className: "ed-figcaption",
@@ -1323,34 +1902,38 @@ function ImageEmbedViewImpl({
1323
1902
  function wrap(text, attrs) {
1324
1903
  let node = text;
1325
1904
  if (!attrs) return node;
1326
- if (attrs.bold) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: node });
1327
- if (attrs.italic) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { children: node });
1328
- if (attrs.underline) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("u", { children: node });
1329
- if (attrs.strike) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("s", { children: node });
1905
+ if (attrs.bold) node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: node });
1906
+ if (attrs.italic) node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("em", { children: node });
1907
+ if (attrs.underline) node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("u", { children: node });
1908
+ if (attrs.strike) node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("s", { children: node });
1330
1909
  const styleParts = {};
1331
1910
  if (attrs.color) styleParts.color = attrs.color;
1332
1911
  if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;
1333
1912
  if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;
1334
1913
  if (Object.keys(styleParts).length > 0) {
1335
- node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styleParts, children: node });
1914
+ node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styleParts, children: node });
1336
1915
  }
1337
1916
  if (attrs.link?.href) {
1338
- node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1917
+ node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1339
1918
  "a",
1340
1919
  {
1341
1920
  href: attrs.link.href,
1342
1921
  title: attrs.link.title,
1343
1922
  rel: "noopener noreferrer",
1344
1923
  target: "_blank",
1924
+ style: LINK_STYLE,
1345
1925
  onClick: (e) => {
1346
- if (!(e.metaKey || e.ctrlKey)) e.preventDefault();
1926
+ e.preventDefault();
1927
+ if (hasOpenModifier(e) && attrs.link?.href) {
1928
+ window.open(attrs.link.href, "_blank", "noopener,noreferrer");
1929
+ }
1347
1930
  },
1348
1931
  children: node
1349
1932
  }
1350
1933
  );
1351
1934
  }
1352
1935
  if (attrs.comment?.markId) {
1353
- node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
1936
+ node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
1354
1937
  }
1355
1938
  return node;
1356
1939
  }
@@ -1394,14 +1977,14 @@ function sliceDelta(delta, start, end) {
1394
1977
  }
1395
1978
 
1396
1979
  // src/TableResizeOverlay.tsx
1397
- var import_react7 = require("react");
1398
- var import_jsx_runtime7 = require("react/jsx-runtime");
1980
+ var import_react9 = require("react");
1981
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1399
1982
  function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1400
1983
  const editor = useEditorContext();
1401
- const [positions, setPositions] = (0, import_react7.useState)(null);
1402
- const [layout, setLayout] = (0, import_react7.useState)(null);
1403
- const draggingRef = (0, import_react7.useRef)(null);
1404
- const measure = (0, import_react7.useCallback)(() => {
1984
+ const [positions, setPositions] = (0, import_react9.useState)(null);
1985
+ const [layout, setLayout] = (0, import_react9.useState)(null);
1986
+ const draggingRef = (0, import_react9.useRef)(null);
1987
+ const measure = (0, import_react9.useCallback)(() => {
1405
1988
  const table = tableRef.current;
1406
1989
  if (!table) return;
1407
1990
  const tableRect = table.getBoundingClientRect();
@@ -1431,17 +2014,17 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1431
2014
  }
1432
2015
  setLayout({ rights, height: tableRect.height });
1433
2016
  }, [cols, tableRef]);
1434
- (0, import_react7.useLayoutEffect)(() => {
2017
+ (0, import_react9.useLayoutEffect)(() => {
1435
2018
  measure();
1436
2019
  }, [measure]);
1437
- (0, import_react7.useEffect)(() => {
2020
+ (0, import_react9.useEffect)(() => {
1438
2021
  const table = tableRef.current;
1439
2022
  if (!table) return;
1440
2023
  const ro = new ResizeObserver(() => measure());
1441
2024
  ro.observe(table);
1442
2025
  return () => ro.disconnect();
1443
2026
  }, [measure, tableRef]);
1444
- const onPointerDown = (0, import_react7.useCallback)(
2027
+ const onPointerDown = (0, import_react9.useCallback)(
1445
2028
  (col) => (e) => {
1446
2029
  e.preventDefault();
1447
2030
  e.stopPropagation();
@@ -1455,7 +2038,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1455
2038
  },
1456
2039
  [layout, tableRef]
1457
2040
  );
1458
- const onPointerMove = (0, import_react7.useCallback)(
2041
+ const onPointerMove = (0, import_react9.useCallback)(
1459
2042
  (e) => {
1460
2043
  const d = draggingRef.current;
1461
2044
  if (!d) return;
@@ -1465,7 +2048,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1465
2048
  },
1466
2049
  [blockIndex, editor]
1467
2050
  );
1468
- const onPointerUp = (0, import_react7.useCallback)((e) => {
2051
+ const onPointerUp = (0, import_react9.useCallback)((e) => {
1469
2052
  draggingRef.current = null;
1470
2053
  setPositions(null);
1471
2054
  try {
@@ -1484,7 +2067,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1484
2067
  zIndex: 5
1485
2068
  });
1486
2069
  void positions;
1487
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: layout.rights.map((x, c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2070
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: layout.rights.map((x, c) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1488
2071
  "div",
1489
2072
  {
1490
2073
  contentEditable: false,
@@ -1501,10 +2084,10 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1501
2084
  }
1502
2085
 
1503
2086
  // src/NodeView.tsx
1504
- var import_jsx_runtime8 = require("react/jsx-runtime");
2087
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1505
2088
  function NodeView({ block, index, children, fragment, tableFragment }) {
1506
2089
  if (block.type === "table") {
1507
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableView, { block, index, tableFragment });
2090
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TableView, { block, index, tableFragment });
1508
2091
  }
1509
2092
  const inline = fragment ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index) : renderInline(block.delta, index);
1510
2093
  const common = commonBlockProps(block.attrs, index, block.type, fragment);
@@ -1512,7 +2095,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1512
2095
  case "heading": {
1513
2096
  const level = clampLevel(block.attrs.level);
1514
2097
  const Tag = `h${level}`;
1515
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2098
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1516
2099
  Tag,
1517
2100
  {
1518
2101
  ...common,
@@ -1522,7 +2105,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1522
2105
  );
1523
2106
  }
1524
2107
  case "blockquote":
1525
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2108
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1526
2109
  "blockquote",
1527
2110
  {
1528
2111
  ...common,
@@ -1531,18 +2114,18 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1531
2114
  }
1532
2115
  );
1533
2116
  case "codeBlock":
1534
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1535
2118
  "pre",
1536
2119
  {
1537
2120
  ...common,
1538
2121
  "data-language": block.attrs.language ?? void 0,
1539
2122
  className: `ed-block ed-codeblock${alignClass(block.attrs.align)}`,
1540
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: inline })
2123
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: inline })
1541
2124
  }
1542
2125
  );
1543
2126
  case "listItem": {
1544
2127
  const level = clampListLevel(block.attrs.listLevel);
1545
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2128
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1546
2129
  "li",
1547
2130
  {
1548
2131
  ...common,
@@ -1558,7 +2141,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1558
2141
  }
1559
2142
  case "paragraph":
1560
2143
  default:
1561
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2144
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1562
2145
  "div",
1563
2146
  {
1564
2147
  ...common,
@@ -1603,18 +2186,18 @@ function TableView({ block, index, tableFragment }) {
1603
2186
  const cols = clampPositive(block.attrs.cols);
1604
2187
  const cells = block.cells ?? [];
1605
2188
  const widths = readColWidths(block.attrs.colWidths, cols);
1606
- const tableRef = (0, import_react8.useRef)(null);
2189
+ const tableRef = (0, import_react10.useRef)(null);
1607
2190
  const rowStart = tableFragment?.rowStart ?? 0;
1608
2191
  const rowEnd = tableFragment?.rowEnd ?? rows;
1609
2192
  const isFirstFragment = !tableFragment || tableFragment.index === 0;
1610
2193
  const editor = useEditorContext();
1611
- const rect = (0, import_react8.useMemo)(() => {
2194
+ const rect = (0, import_react10.useMemo)(() => {
1612
2195
  if (editor.selection.anchor.blockIndex !== index) return null;
1613
2196
  if (editor.selection.focus.blockIndex !== index) return null;
1614
- return (0, import_core3.tableRectSelection)(editor.doc, editor.selection);
2197
+ return (0, import_core4.tableRectSelection)(editor.doc, editor.selection);
1615
2198
  }, [editor.doc, editor.selection, index]);
1616
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ed-table-wrap", children: [
1617
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2199
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ed-table-wrap", children: [
2200
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1618
2201
  "table",
1619
2202
  {
1620
2203
  ref: tableRef,
@@ -1622,10 +2205,10 @@ function TableView({ block, index, tableFragment }) {
1622
2205
  "data-block-type": "table",
1623
2206
  className: "ed-block ed-table",
1624
2207
  children: [
1625
- widths && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
1626
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
2208
+ widths && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
1627
2210
  const r = rowStart + i;
1628
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tr", { "data-cell-row": r, children: Array.from({ length: cols }, (_2, c) => {
2211
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { "data-cell-row": r, children: Array.from({ length: cols }, (_2, c) => {
1629
2212
  const flat = r * cols + c;
1630
2213
  const cell = cells[flat];
1631
2214
  if (cell?.attrs.covered === true) return null;
@@ -1633,7 +2216,7 @@ function TableView({ block, index, tableFragment }) {
1633
2216
  const colspan = spanAttr(cell?.attrs.colspan);
1634
2217
  const delta = cell?.delta ?? [];
1635
2218
  const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
1636
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2219
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1637
2220
  "td",
1638
2221
  {
1639
2222
  "data-cell-index": flat,
@@ -1643,6 +2226,7 @@ function TableView({ block, index, tableFragment }) {
1643
2226
  "data-cell-colspan": colspan,
1644
2227
  rowSpan: rowspan > 1 ? rowspan : void 0,
1645
2228
  colSpan: colspan > 1 ? colspan : void 0,
2229
+ style: cell?.attrs.align ? { textAlign: cell.attrs.align } : void 0,
1646
2230
  className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
1647
2231
  children: renderInline(delta, `t${index}-c${flat}`)
1648
2232
  },
@@ -1653,7 +2237,7 @@ function TableView({ block, index, tableFragment }) {
1653
2237
  ]
1654
2238
  }
1655
2239
  ),
1656
- isFirstFragment && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableResizeOverlay, { tableRef, blockIndex: index, cols })
2240
+ isFirstFragment && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TableResizeOverlay, { tableRef, blockIndex: index, cols })
1657
2241
  ] });
1658
2242
  }
1659
2243
  function readColWidths(raw, cols) {
@@ -1675,7 +2259,7 @@ function clampPositive(n) {
1675
2259
  }
1676
2260
 
1677
2261
  // src/usePagination.ts
1678
- var import_react9 = require("react");
2262
+ var import_react11 = require("react");
1679
2263
  var A4_PAGE = {
1680
2264
  width: 794,
1681
2265
  height: 1123,
@@ -1684,8 +2268,9 @@ var A4_PAGE = {
1684
2268
  marginLeft: 96,
1685
2269
  marginRight: 96
1686
2270
  };
1687
- function contentHeight(g) {
1688
- return g.height - g.marginTop - g.marginBottom;
2271
+ function contentHeight(g, pageIndex = 0) {
2272
+ const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;
2273
+ return g.height - g.marginTop - g.marginBottom - extra;
1689
2274
  }
1690
2275
  function contentWidth(g) {
1691
2276
  return g.width - g.marginLeft - g.marginRight;
@@ -1700,17 +2285,22 @@ function defaultPageLayout(topLevelCount) {
1700
2285
  };
1701
2286
  }
1702
2287
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1703
- const [phase, setPhase] = (0, import_react9.useState)("measure");
1704
- const [layout, setLayout] = (0, import_react9.useState)(() => defaultPageLayout(topLevelCount));
1705
- const lastDepsRef = (0, import_react9.useRef)([]);
1706
- const currentDeps = [...deps, topLevelCount, geometry];
1707
- if (!shallowArrayEqual(lastDepsRef.current, currentDeps)) {
2288
+ const [phase, setPhase] = (0, import_react11.useState)("measure");
2289
+ const [layout, setLayout] = (0, import_react11.useState)(() => defaultPageLayout(topLevelCount));
2290
+ const lastDepsRef = (0, import_react11.useRef)(null);
2291
+ (0, import_react11.useLayoutEffect)(() => {
2292
+ const currentDeps = [...deps, topLevelCount, geometry];
2293
+ if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
2294
+ return;
2295
+ }
1708
2296
  lastDepsRef.current = currentDeps;
1709
- if (phase !== "measure") setPhase("measure");
1710
- const next = defaultPageLayout(topLevelCount);
1711
- if (!layoutsDeepEqual(layout, next)) setLayout(next);
1712
- }
1713
- (0, import_react9.useLayoutEffect)(() => {
2297
+ setLayout((prev) => {
2298
+ const next = defaultPageLayout(topLevelCount);
2299
+ return layoutsDeepEqual(prev, next) ? prev : next;
2300
+ });
2301
+ setPhase("measure");
2302
+ });
2303
+ (0, import_react11.useLayoutEffect)(() => {
1714
2304
  if (phase !== "measure") return;
1715
2305
  const root = rootRef.current;
1716
2306
  if (!root) return;
@@ -1719,19 +2309,20 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1719
2309
  if (!layoutsDeepEqual(layout, next)) setLayout(next);
1720
2310
  setPhase("stable");
1721
2311
  }, [phase, layout, geometry, topLevelCount, rootRef]);
1722
- return layout;
2312
+ return { layout, phase };
1723
2313
  }
1724
2314
  function isUnfragmented(layout) {
1725
2315
  return layout.pages.length === 1 && layout.pages[0].slots.every(
1726
- (s) => s.fragment === void 0 && s.tableFragment === void 0
2316
+ (s) => s.fragment === void 0 && s.tableFragment === void 0 && s.listFragment === void 0
1727
2317
  );
1728
2318
  }
1729
2319
  function computeLayout(root, geometry, topLevelCount) {
1730
2320
  const tops = collectTopLevelElements(root);
1731
2321
  if (tops.length === 0) return defaultPageLayout(topLevelCount);
1732
- const limit = contentHeight(geometry);
2322
+ const limitFor = (pageIndex) => contentHeight(geometry, pageIndex);
1733
2323
  const pages = [{ slots: [] }];
1734
2324
  let currentPage = pages[0];
2325
+ let limit = limitFor(0);
1735
2326
  let used = 0;
1736
2327
  const cap = Math.min(tops.length, topLevelCount);
1737
2328
  for (let i = 0; i < cap; i++) {
@@ -1743,14 +2334,23 @@ function computeLayout(root, geometry, topLevelCount) {
1743
2334
  continue;
1744
2335
  }
1745
2336
  if (isFragmentable(el)) {
1746
- const result = placeFragmentedBlock(el, i, pages, used, limit);
2337
+ const result = placeFragmentedBlock(el, i, pages, used, limitFor);
1747
2338
  currentPage = pages[pages.length - 1];
2339
+ limit = limitFor(pages.length - 1);
1748
2340
  used = result.lastUsed;
1749
2341
  continue;
1750
2342
  }
1751
2343
  if (isTableTopLevel(el)) {
1752
- const result = placeFragmentedTable(el, i, pages, used, limit);
2344
+ const result = placeFragmentedTable(el, i, pages, used, limitFor);
2345
+ currentPage = pages[pages.length - 1];
2346
+ limit = limitFor(pages.length - 1);
2347
+ used = result.lastUsed;
2348
+ continue;
2349
+ }
2350
+ if (isListTopLevel(el)) {
2351
+ const result = placeFragmentedList(el, i, pages, used, limitFor);
1753
2352
  currentPage = pages[pages.length - 1];
2353
+ limit = limitFor(pages.length - 1);
1754
2354
  used = result.lastUsed;
1755
2355
  continue;
1756
2356
  }
@@ -1758,10 +2358,12 @@ function computeLayout(root, geometry, topLevelCount) {
1758
2358
  currentPage.slots.push({ topLevelIndex: i });
1759
2359
  pages.push({ slots: [] });
1760
2360
  currentPage = pages[pages.length - 1];
2361
+ limit = limitFor(pages.length - 1);
1761
2362
  used = 0;
1762
2363
  } else {
1763
2364
  pages.push({ slots: [] });
1764
2365
  currentPage = pages[pages.length - 1];
2366
+ limit = limitFor(pages.length - 1);
1765
2367
  currentPage.slots.push({ topLevelIndex: i });
1766
2368
  used = h;
1767
2369
  }
@@ -1769,7 +2371,8 @@ function computeLayout(root, geometry, topLevelCount) {
1769
2371
  if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();
1770
2372
  return { pages };
1771
2373
  }
1772
- function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
2374
+ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limitFor) {
2375
+ let limit = limitFor(pages.length - 1);
1773
2376
  const totalChars = getBlockTextLength(el);
1774
2377
  if (totalChars === 0) {
1775
2378
  const h = elTotalHeight(el);
@@ -1777,6 +2380,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1777
2380
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1778
2381
  pages.push({ slots: [] });
1779
2382
  currentPage2 = pages[pages.length - 1];
2383
+ limit = limitFor(pages.length - 1);
1780
2384
  startUsed = 0;
1781
2385
  }
1782
2386
  currentPage2.slots.push({ topLevelIndex });
@@ -1789,6 +2393,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1789
2393
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1790
2394
  pages.push({ slots: [] });
1791
2395
  currentPage2 = pages[pages.length - 1];
2396
+ limit = limitFor(pages.length - 1);
1792
2397
  startUsed = 0;
1793
2398
  }
1794
2399
  currentPage2.slots.push({ topLevelIndex });
@@ -1803,6 +2408,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1803
2408
  if (available <= 0) {
1804
2409
  pages.push({ slots: [] });
1805
2410
  currentPage = pages[pages.length - 1];
2411
+ limit = limitFor(pages.length - 1);
1806
2412
  used = 0;
1807
2413
  continue;
1808
2414
  }
@@ -1819,6 +2425,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1819
2425
  } else {
1820
2426
  pages.push({ slots: [] });
1821
2427
  currentPage = pages[pages.length - 1];
2428
+ limit = limitFor(pages.length - 1);
1822
2429
  used = 0;
1823
2430
  continue;
1824
2431
  }
@@ -1836,6 +2443,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1836
2443
  if (lineIdx < lines.length) {
1837
2444
  pages.push({ slots: [] });
1838
2445
  currentPage = pages[pages.length - 1];
2446
+ limit = limitFor(pages.length - 1);
1839
2447
  used = 0;
1840
2448
  }
1841
2449
  }
@@ -1924,7 +2532,8 @@ function isFragmentable(el) {
1924
2532
  function isTableTopLevel(el) {
1925
2533
  return el.querySelector(':scope > table[data-block-type="table"]') !== null;
1926
2534
  }
1927
- function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
2535
+ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limitFor) {
2536
+ let limit = limitFor(pages.length - 1);
1928
2537
  const table = el.querySelector(':scope > table[data-block-type="table"]');
1929
2538
  const tbody = table?.querySelector(":scope > tbody");
1930
2539
  const trs = tbody ? Array.from(tbody.children) : [];
@@ -1934,6 +2543,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1934
2543
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1935
2544
  pages.push({ slots: [] });
1936
2545
  currentPage2 = pages[pages.length - 1];
2546
+ limit = limitFor(pages.length - 1);
1937
2547
  startUsed = 0;
1938
2548
  }
1939
2549
  currentPage2.slots.push({ topLevelIndex });
@@ -1965,6 +2575,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1965
2575
  if (available <= 0) {
1966
2576
  pages.push({ slots: [] });
1967
2577
  currentPage = pages[pages.length - 1];
2578
+ limit = limitFor(pages.length - 1);
1968
2579
  used = 0;
1969
2580
  continue;
1970
2581
  }
@@ -1983,6 +2594,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1983
2594
  } else {
1984
2595
  pages.push({ slots: [] });
1985
2596
  currentPage = pages[pages.length - 1];
2597
+ limit = limitFor(pages.length - 1);
1986
2598
  used = 0;
1987
2599
  continue;
1988
2600
  }
@@ -2000,6 +2612,77 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
2000
2612
  if (rowIdx < trs.length) {
2001
2613
  pages.push({ slots: [] });
2002
2614
  currentPage = pages[pages.length - 1];
2615
+ limit = limitFor(pages.length - 1);
2616
+ used = 0;
2617
+ }
2618
+ }
2619
+ return { lastUsed: used };
2620
+ }
2621
+ function isListTopLevel(el) {
2622
+ if (el.tagName !== "OL" && el.tagName !== "UL") return false;
2623
+ return el.classList.contains("ed-list");
2624
+ }
2625
+ function placeFragmentedList(el, topLevelIndex, pages, startUsed, limitFor) {
2626
+ let limit = limitFor(pages.length - 1);
2627
+ const items = [];
2628
+ for (const c of Array.from(el.children)) {
2629
+ if (c instanceof HTMLLIElement && c.classList.contains("ed-listitem")) {
2630
+ items.push(c);
2631
+ }
2632
+ }
2633
+ if (items.length === 0) {
2634
+ const h = elTotalHeight(el);
2635
+ let currentPage2 = pages[pages.length - 1];
2636
+ if (startUsed + h > limit && currentPage2.slots.length > 0) {
2637
+ pages.push({ slots: [] });
2638
+ currentPage2 = pages[pages.length - 1];
2639
+ limit = limitFor(pages.length - 1);
2640
+ startUsed = 0;
2641
+ }
2642
+ currentPage2.slots.push({ topLevelIndex });
2643
+ return { lastUsed: startUsed + h };
2644
+ }
2645
+ const heights = items.map((li) => elTotalHeight(li));
2646
+ const sumHeights = heights.reduce((a, b) => a + b, 0);
2647
+ const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);
2648
+ let i = 0;
2649
+ let currentPage = pages[pages.length - 1];
2650
+ let used = startUsed;
2651
+ let fragIndex = 0;
2652
+ while (i < items.length) {
2653
+ const available = Math.max(0, limit - used);
2654
+ const isFirstFragment = fragIndex === 0;
2655
+ let bestK = -1;
2656
+ let runningH = isFirstFragment ? wrapperOverhead : 0;
2657
+ for (let k = i; k < items.length; k++) {
2658
+ runningH += heights[k];
2659
+ if (runningH <= available) bestK = k;
2660
+ else break;
2661
+ }
2662
+ if (bestK < 0) {
2663
+ if (currentPage.slots.length === 0) {
2664
+ bestK = i;
2665
+ } else {
2666
+ pages.push({ slots: [] });
2667
+ currentPage = pages[pages.length - 1];
2668
+ limit = limitFor(pages.length - 1);
2669
+ used = 0;
2670
+ continue;
2671
+ }
2672
+ }
2673
+ currentPage.slots.push({
2674
+ topLevelIndex,
2675
+ listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 }
2676
+ });
2677
+ let consumed = isFirstFragment ? wrapperOverhead : 0;
2678
+ for (let k = i; k <= bestK; k++) consumed += heights[k];
2679
+ used += consumed;
2680
+ i = bestK + 1;
2681
+ fragIndex++;
2682
+ if (i < items.length) {
2683
+ pages.push({ slots: [] });
2684
+ currentPage = pages[pages.length - 1];
2685
+ limit = limitFor(pages.length - 1);
2003
2686
  used = 0;
2004
2687
  }
2005
2688
  }
@@ -2075,54 +2758,62 @@ function layoutsDeepEqual(a, b) {
2075
2758
  return false;
2076
2759
  }
2077
2760
  }
2761
+ const lA = sA[j].listFragment;
2762
+ const lB = sB[j].listFragment;
2763
+ if (lA || lB) {
2764
+ if (!lA || !lB) return false;
2765
+ if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {
2766
+ return false;
2767
+ }
2768
+ }
2078
2769
  }
2079
2770
  }
2080
2771
  return true;
2081
2772
  }
2082
2773
 
2083
2774
  // src/useEditor.ts
2084
- var import_react11 = require("react");
2775
+ var import_react13 = require("react");
2085
2776
 
2086
2777
  // src/usePageSettings.ts
2087
- var import_react10 = require("react");
2778
+ var import_react12 = require("react");
2088
2779
  function usePageSettings(doc) {
2089
- const cacheRef = (0, import_react10.useRef)(null);
2090
- const subscribe = (0, import_react10.useCallback)(
2780
+ const cacheRef = (0, import_react12.useRef)(null);
2781
+ const subscribe = (0, import_react12.useCallback)(
2091
2782
  (notify) => doc.observePageSettings(notify),
2092
2783
  [doc]
2093
2784
  );
2094
- const getSnapshot = (0, import_react10.useCallback)(() => {
2785
+ const getSnapshot = (0, import_react12.useCallback)(() => {
2095
2786
  const next = doc.getPageSettings();
2096
2787
  const prev = cacheRef.current;
2097
2788
  if (prev && shallowEqual(prev, next)) return prev;
2098
2789
  cacheRef.current = next;
2099
2790
  return next;
2100
2791
  }, [doc]);
2101
- return (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
2792
+ return (0, import_react12.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
2102
2793
  }
2103
2794
  function shallowEqual(a, b) {
2104
- 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;
2795
+ 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;
2105
2796
  }
2106
2797
 
2107
2798
  // src/useEditor.ts
2108
- var import_core4 = require("@sofereditor/core");
2799
+ var import_core5 = require("@sofereditor/core");
2109
2800
  var MAX_INSERT_WIDTH = 600;
2110
2801
  function useEditor(opts = {}) {
2111
- const doc = (0, import_react11.useMemo)(() => opts.document ?? new import_core4.EditorDocument(), [opts.document]);
2112
- const history = (0, import_react11.useMemo)(() => new import_core4.EditorHistory(doc), [doc]);
2113
- const [snapshot, setSnapshot] = (0, import_react11.useState)(() => doc.toJSON());
2114
- const [selection, setSelectionState] = (0, import_react11.useState)(
2115
- () => (0, import_core4.collapsedSelection)({ blockIndex: 0, offset: 0 })
2802
+ const doc = (0, import_react13.useMemo)(() => opts.document ?? new import_core5.EditorDocument(), [opts.document]);
2803
+ const history = (0, import_react13.useMemo)(() => new import_core5.EditorHistory(doc), [doc]);
2804
+ const [snapshot, setSnapshot] = (0, import_react13.useState)(() => doc.toJSON());
2805
+ const [selection, setSelectionState] = (0, import_react13.useState)(
2806
+ () => (0, import_core5.collapsedSelection)({ blockIndex: 0, offset: 0 })
2116
2807
  );
2117
- const selectionRef = (0, import_react11.useRef)(selection);
2808
+ const selectionRef = (0, import_react13.useRef)(selection);
2118
2809
  selectionRef.current = selection;
2119
- const pendingMarksRef = (0, import_react11.useRef)({});
2120
- const [pendingMarks, setPendingMarksState] = (0, import_react11.useState)({});
2121
- const setPendingMarks = (0, import_react11.useCallback)((next) => {
2810
+ const pendingMarksRef = (0, import_react13.useRef)({});
2811
+ const [pendingMarks, setPendingMarksState] = (0, import_react13.useState)({});
2812
+ const setPendingMarks = (0, import_react13.useCallback)((next) => {
2122
2813
  pendingMarksRef.current = next;
2123
2814
  setPendingMarksState(next);
2124
2815
  }, []);
2125
- (0, import_react11.useEffect)(() => {
2816
+ (0, import_react13.useEffect)(() => {
2126
2817
  let scheduled = false;
2127
2818
  let cancelled = false;
2128
2819
  let frame = 0;
@@ -2149,8 +2840,8 @@ function useEditor(opts = {}) {
2149
2840
  doc.ydoc.off("afterTransaction", schedule);
2150
2841
  };
2151
2842
  }, [doc]);
2152
- const getSelection = (0, import_react11.useCallback)(() => selectionRef.current, []);
2153
- const setSelection = (0, import_react11.useCallback)(
2843
+ const getSelection = (0, import_react13.useCallback)(() => selectionRef.current, []);
2844
+ const setSelection = (0, import_react13.useCallback)(
2154
2845
  (sel) => {
2155
2846
  const prev = selectionRef.current;
2156
2847
  selectionRef.current = sel;
@@ -2165,19 +2856,19 @@ function useEditor(opts = {}) {
2165
2856
  },
2166
2857
  []
2167
2858
  );
2168
- const ctxRef = (0, import_react11.useRef)({ doc, getSelection, setSelection });
2859
+ const ctxRef = (0, import_react13.useRef)({ doc, getSelection, setSelection });
2169
2860
  ctxRef.current = { doc, getSelection, setSelection };
2170
- const consumePendingMarks = (0, import_react11.useCallback)(() => {
2861
+ const consumePendingMarks = (0, import_react13.useCallback)(() => {
2171
2862
  const current = pendingMarksRef.current;
2172
2863
  if (Object.keys(current).length === 0) return void 0;
2173
2864
  pendingMarksRef.current = {};
2174
2865
  setPendingMarksState({});
2175
2866
  return current;
2176
2867
  }, []);
2177
- const isMarkActive = (0, import_react11.useCallback)(
2868
+ const isMarkActive = (0, import_react13.useCallback)(
2178
2869
  (name, value) => {
2179
2870
  const sel = selectionRef.current;
2180
- const { start, end } = (0, import_core4.orderedRange)(sel);
2871
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2181
2872
  if (start.blockIndex === end.blockIndex && start.offset === end.offset) {
2182
2873
  const pending = pendingMarksRef.current[name];
2183
2874
  if (pending !== void 0) {
@@ -2186,7 +2877,7 @@ function useEditor(opts = {}) {
2186
2877
  }
2187
2878
  const yText2 = doc.getBlockText(start.blockIndex);
2188
2879
  if (!yText2 || start.offset === 0) return false;
2189
- return (0, import_core4.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
2880
+ return (0, import_core5.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
2190
2881
  }
2191
2882
  if (start.blockIndex !== end.blockIndex) {
2192
2883
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
@@ -2195,19 +2886,19 @@ function useEditor(opts = {}) {
2195
2886
  const s = i === start.blockIndex ? start.offset : 0;
2196
2887
  const e = i === end.blockIndex ? end.offset : yText2.length;
2197
2888
  if (s >= e) continue;
2198
- if (!(0, import_core4.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
2889
+ if (!(0, import_core5.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
2199
2890
  }
2200
2891
  return true;
2201
2892
  }
2202
2893
  const yText = doc.getBlockText(start.blockIndex);
2203
2894
  if (!yText) return false;
2204
- return (0, import_core4.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
2895
+ return (0, import_core5.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
2205
2896
  },
2206
2897
  [doc]
2207
2898
  );
2208
- const getActiveMarks = (0, import_react11.useCallback)(() => {
2899
+ const getActiveMarks = (0, import_react13.useCallback)(() => {
2209
2900
  const sel = selectionRef.current;
2210
- const { start, end } = (0, import_core4.orderedRange)(sel);
2901
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2211
2902
  if (start.blockIndex !== end.blockIndex) {
2212
2903
  return {};
2213
2904
  }
@@ -2215,14 +2906,14 @@ function useEditor(opts = {}) {
2215
2906
  if (!yText) return {};
2216
2907
  if (start.offset === end.offset) {
2217
2908
  if (start.offset === 0) return {};
2218
- return (0, import_core4.getMarksInRange)(yText, start.offset - 1, start.offset);
2909
+ return (0, import_core5.getMarksInRange)(yText, start.offset - 1, start.offset);
2219
2910
  }
2220
- return (0, import_core4.getMarksInRange)(yText, start.offset, end.offset);
2911
+ return (0, import_core5.getMarksInRange)(yText, start.offset, end.offset);
2221
2912
  }, [doc]);
2222
- const toggleMark = (0, import_react11.useCallback)(
2913
+ const toggleMark = (0, import_react13.useCallback)(
2223
2914
  (name, value) => {
2224
2915
  const sel = selectionRef.current;
2225
- const { start, end } = (0, import_core4.orderedRange)(sel);
2916
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2226
2917
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2227
2918
  if (isCollapsed) {
2228
2919
  const next = { ...pendingMarksRef.current };
@@ -2235,39 +2926,39 @@ function useEditor(opts = {}) {
2235
2926
  setPendingMarks(next);
2236
2927
  return;
2237
2928
  }
2238
- (0, import_core4.toggleMark)(ctxRef.current, name, value);
2929
+ (0, import_core5.toggleMark)(ctxRef.current, name, value);
2239
2930
  },
2240
2931
  [isMarkActive, setPendingMarks]
2241
2932
  );
2242
- const setMark = (0, import_react11.useCallback)(
2933
+ const setMark = (0, import_react13.useCallback)(
2243
2934
  (name, value) => {
2244
2935
  const sel = selectionRef.current;
2245
- const { start, end } = (0, import_core4.orderedRange)(sel);
2936
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2246
2937
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2247
2938
  if (isCollapsed) {
2248
2939
  setPendingMarks({ ...pendingMarksRef.current, [name]: value });
2249
2940
  return;
2250
2941
  }
2251
- (0, import_core4.setMark)(ctxRef.current, name, value);
2942
+ (0, import_core5.setMark)(ctxRef.current, name, value);
2252
2943
  },
2253
2944
  [setPendingMarks]
2254
2945
  );
2255
- const removeMark = (0, import_react11.useCallback)(
2946
+ const removeMark = (0, import_react13.useCallback)(
2256
2947
  (name) => {
2257
2948
  const sel = selectionRef.current;
2258
- const { start, end } = (0, import_core4.orderedRange)(sel);
2949
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2259
2950
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2260
2951
  if (isCollapsed) {
2261
2952
  setPendingMarks({ ...pendingMarksRef.current, [name]: null });
2262
2953
  return;
2263
2954
  }
2264
- (0, import_core4.removeMark)(ctxRef.current, name);
2955
+ (0, import_core5.removeMark)(ctxRef.current, name);
2265
2956
  },
2266
2957
  [setPendingMarks]
2267
2958
  );
2268
- const getBlockType = (0, import_react11.useCallback)(() => {
2959
+ const getBlockType = (0, import_react13.useCallback)(() => {
2269
2960
  const sel = selectionRef.current;
2270
- const { start, end } = (0, import_core4.orderedRange)(sel);
2961
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2271
2962
  const first = doc.getBlockType(start.blockIndex);
2272
2963
  if (first === void 0) return "paragraph";
2273
2964
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
@@ -2275,10 +2966,10 @@ function useEditor(opts = {}) {
2275
2966
  }
2276
2967
  return first;
2277
2968
  }, [doc]);
2278
- const getBlockAttr = (0, import_react11.useCallback)(
2969
+ const getBlockAttr = (0, import_react13.useCallback)(
2279
2970
  (key) => {
2280
2971
  const sel = selectionRef.current;
2281
- const { start, end } = (0, import_core4.orderedRange)(sel);
2972
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2282
2973
  const first = doc.getBlockAttrs(start.blockIndex)[key];
2283
2974
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
2284
2975
  const next = doc.getBlockAttrs(i)[key];
@@ -2288,19 +2979,32 @@ function useEditor(opts = {}) {
2288
2979
  },
2289
2980
  [doc]
2290
2981
  );
2291
- const setBlockType = (0, import_react11.useCallback)((type, attrs) => {
2292
- (0, import_core4.setBlockType)(ctxRef.current, type, attrs);
2982
+ const setBlockType = (0, import_react13.useCallback)((type, attrs) => {
2983
+ (0, import_core5.setBlockType)(ctxRef.current, type, attrs);
2293
2984
  }, []);
2294
- const setBlockAttr = (0, import_react11.useCallback)(
2985
+ const setBlockAttr = (0, import_react13.useCallback)(
2295
2986
  (key, value) => {
2296
- (0, import_core4.setBlockAttr)(ctxRef.current, key, value);
2987
+ (0, import_core5.setBlockAttr)(ctxRef.current, key, value);
2297
2988
  },
2298
2989
  []
2299
2990
  );
2300
- const isListActive = (0, import_react11.useCallback)(
2991
+ const setAlign = (0, import_react13.useCallback)((value) => {
2992
+ const sel = selectionRef.current;
2993
+ const inCell = sel.focus.cellIndex != null;
2994
+ if (inCell) (0, import_core5.setCellAttr)(ctxRef.current, "align", value);
2995
+ else (0, import_core5.setBlockAttr)(ctxRef.current, "align", value);
2996
+ }, []);
2997
+ const getAlign = (0, import_react13.useCallback)(() => {
2998
+ const sel = selectionRef.current;
2999
+ if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {
3000
+ return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).align;
3001
+ }
3002
+ return getBlockAttr("align");
3003
+ }, [doc, getBlockAttr]);
3004
+ const isListActive = (0, import_react13.useCallback)(
2301
3005
  (kind) => {
2302
3006
  const sel = selectionRef.current;
2303
- const { start, end } = (0, import_core4.orderedRange)(sel);
3007
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2304
3008
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
2305
3009
  if (doc.getBlockType(i) !== "listItem") return false;
2306
3010
  if (doc.getBlockAttrs(i).listKind !== kind) return false;
@@ -2309,110 +3013,116 @@ function useEditor(opts = {}) {
2309
3013
  },
2310
3014
  [doc]
2311
3015
  );
2312
- const toggleList = (0, import_react11.useCallback)((kind) => {
2313
- (0, import_core4.toggleList)(ctxRef.current, kind);
3016
+ const toggleList = (0, import_react13.useCallback)((kind) => {
3017
+ (0, import_core5.toggleList)(ctxRef.current, kind);
2314
3018
  }, []);
2315
- const indentList = (0, import_react11.useCallback)(() => {
2316
- (0, import_core4.indentList)(ctxRef.current);
3019
+ const indentList = (0, import_react13.useCallback)(() => {
3020
+ (0, import_core5.indentList)(ctxRef.current);
2317
3021
  }, []);
2318
- const dedentList = (0, import_react11.useCallback)(() => {
2319
- (0, import_core4.dedentList)(ctxRef.current);
3022
+ const dedentList = (0, import_react13.useCallback)(() => {
3023
+ (0, import_core5.dedentList)(ctxRef.current);
2320
3024
  }, []);
2321
- const splitListItem = (0, import_react11.useCallback)(() => {
2322
- return (0, import_core4.splitListItem)(ctxRef.current);
3025
+ const splitListItem = (0, import_react13.useCallback)(() => {
3026
+ return (0, import_core5.splitListItem)(ctxRef.current);
2323
3027
  }, []);
2324
- const isInTable = (0, import_react11.useCallback)(() => {
3028
+ const isInTable = (0, import_react13.useCallback)(() => {
2325
3029
  return selectionRef.current.focus.cellIndex != null;
2326
3030
  }, []);
2327
- const getTableLocation = (0, import_react11.useCallback)(() => {
2328
- return (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3031
+ const getTableLocation = (0, import_react13.useCallback)(() => {
3032
+ return (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2329
3033
  }, [doc]);
2330
- const insertTable = (0, import_react11.useCallback)((rows, cols) => {
2331
- (0, import_core4.insertTable)(ctxRef.current, rows, cols);
3034
+ const insertTable = (0, import_react13.useCallback)((rows, cols) => {
3035
+ (0, import_core5.insertTable)(ctxRef.current, rows, cols);
2332
3036
  }, []);
2333
- const deleteTable = (0, import_react11.useCallback)((blockIndex) => {
3037
+ const deleteTable = (0, import_react13.useCallback)((blockIndex) => {
2334
3038
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
2335
- (0, import_core4.deleteTable)(ctxRef.current, idx);
3039
+ (0, import_core5.deleteTable)(ctxRef.current, idx);
2336
3040
  }, []);
2337
- const insertRowAbove = (0, import_react11.useCallback)(() => {
2338
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3041
+ const insertRowAbove = (0, import_react13.useCallback)(() => {
3042
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2339
3043
  if (!loc) return;
2340
- (0, import_core4.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
3044
+ (0, import_core5.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
2341
3045
  }, [doc]);
2342
- const insertRowBelow = (0, import_react11.useCallback)(() => {
2343
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3046
+ const insertRowBelow = (0, import_react13.useCallback)(() => {
3047
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2344
3048
  if (!loc) return;
2345
- (0, import_core4.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
3049
+ (0, import_core5.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
2346
3050
  }, [doc]);
2347
- const deleteCurrentRow = (0, import_react11.useCallback)(() => {
2348
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3051
+ const deleteCurrentRow = (0, import_react13.useCallback)(() => {
3052
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2349
3053
  if (!loc) return;
2350
- (0, import_core4.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
3054
+ (0, import_core5.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
2351
3055
  }, [doc]);
2352
- const insertColumnLeft = (0, import_react11.useCallback)(() => {
2353
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3056
+ const insertColumnLeft = (0, import_react13.useCallback)(() => {
3057
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2354
3058
  if (!loc) return;
2355
- (0, import_core4.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
3059
+ (0, import_core5.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
2356
3060
  }, [doc]);
2357
- const insertColumnRight = (0, import_react11.useCallback)(() => {
2358
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3061
+ const insertColumnRight = (0, import_react13.useCallback)(() => {
3062
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2359
3063
  if (!loc) return;
2360
- (0, import_core4.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
3064
+ (0, import_core5.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
2361
3065
  }, [doc]);
2362
- const deleteCurrentColumn = (0, import_react11.useCallback)(() => {
2363
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3066
+ const deleteCurrentColumn = (0, import_react13.useCallback)(() => {
3067
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2364
3068
  if (!loc) return;
2365
- (0, import_core4.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
3069
+ (0, import_core5.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
2366
3070
  }, [doc]);
2367
- const moveToNextCell = (0, import_react11.useCallback)(() => {
2368
- (0, import_core4.moveToNextCell)(ctxRef.current);
3071
+ const moveToNextCell = (0, import_react13.useCallback)(() => {
3072
+ (0, import_core5.moveToNextCell)(ctxRef.current);
2369
3073
  }, []);
2370
- const moveToPrevCell = (0, import_react11.useCallback)(() => {
2371
- (0, import_core4.moveToPrevCell)(ctxRef.current);
3074
+ const moveToPrevCell = (0, import_react13.useCallback)(() => {
3075
+ (0, import_core5.moveToPrevCell)(ctxRef.current);
2372
3076
  }, []);
2373
- const mergeRight = (0, import_react11.useCallback)(() => {
2374
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3077
+ const mergeRight = (0, import_react13.useCallback)(() => {
3078
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2375
3079
  if (!loc) return false;
2376
- return (0, import_core4.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3080
+ return (0, import_core5.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2377
3081
  }, [doc]);
2378
- const mergeDown = (0, import_react11.useCallback)(() => {
2379
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3082
+ const mergeDown = (0, import_react13.useCallback)(() => {
3083
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2380
3084
  if (!loc) return false;
2381
- return (0, import_core4.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3085
+ return (0, import_core5.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2382
3086
  }, [doc]);
2383
- const splitCell = (0, import_react11.useCallback)(() => {
2384
- const loc = (0, import_core4.tableLocationOf)(doc, selectionRef.current.focus);
3087
+ const splitCell = (0, import_react13.useCallback)(() => {
3088
+ const loc = (0, import_core5.tableLocationOf)(doc, selectionRef.current.focus);
2385
3089
  if (!loc) return false;
2386
- return (0, import_core4.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3090
+ return (0, import_core5.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
2387
3091
  }, [doc]);
2388
- const setColumnWidth = (0, import_react11.useCallback)(
3092
+ const setColumnWidth = (0, import_react13.useCallback)(
2389
3093
  (blockIndex, col, widthPx) => {
2390
- (0, import_core4.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
3094
+ (0, import_core5.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
2391
3095
  },
2392
3096
  []
2393
3097
  );
2394
- const getTableRect = (0, import_react11.useCallback)(
2395
- () => (0, import_core4.tableRectSelection)(doc, selectionRef.current),
3098
+ const getTableRect = (0, import_react13.useCallback)(
3099
+ () => (0, import_core5.tableRectSelection)(doc, selectionRef.current),
2396
3100
  [doc]
2397
3101
  );
2398
- const hasTableRectSelection = (0, import_react11.useCallback)(() => {
2399
- return (0, import_core4.tableRectSelection)(doc, selectionRef.current) !== null;
3102
+ const hasTableRectSelection = (0, import_react13.useCallback)(() => {
3103
+ return (0, import_core5.tableRectSelection)(doc, selectionRef.current) !== null;
2400
3104
  }, [doc]);
2401
- const mergeSelection = (0, import_react11.useCallback)(() => {
2402
- return (0, import_core4.mergeSelection)(ctxRef.current);
3105
+ const mergeSelection = (0, import_react13.useCallback)(() => {
3106
+ return (0, import_core5.mergeSelection)(ctxRef.current);
2403
3107
  }, []);
2404
- const insertImage = (0, import_react11.useCallback)((embed) => {
2405
- (0, import_core4.insertImage)(ctxRef.current, embed);
3108
+ const insertImage = (0, import_react13.useCallback)((embed) => {
3109
+ (0, import_core5.insertImage)(ctxRef.current, embed);
2406
3110
  }, []);
2407
- const setImageAttrs = (0, import_react11.useCallback)(
3111
+ const setImageAttrs = (0, import_react13.useCallback)(
2408
3112
  (blockIndex, offset, partial, cellIndex, newOffset) => {
2409
- (0, import_core4.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3113
+ (0, import_core5.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3114
+ },
3115
+ []
3116
+ );
3117
+ const moveEmbedAnchor = (0, import_react13.useCallback)(
3118
+ (from, to, newOffsetX, newOffsetY) => {
3119
+ (0, import_core5.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
2410
3120
  },
2411
3121
  []
2412
3122
  );
2413
- const uploadImageRef = (0, import_react11.useRef)(opts.uploadImage);
3123
+ const uploadImageRef = (0, import_react13.useRef)(opts.uploadImage);
2414
3124
  uploadImageRef.current = opts.uploadImage;
2415
- const insertImageFromFile = (0, import_react11.useCallback)(async (file) => {
3125
+ const insertImageFromFile = (0, import_react13.useCallback)(async (file) => {
2416
3126
  if (!file.type.startsWith("image/")) return;
2417
3127
  const dataUrl = await readAsDataURL(file);
2418
3128
  const dims = await readImageDimensions(dataUrl);
@@ -2424,9 +3134,9 @@ function useEditor(opts = {}) {
2424
3134
  }
2425
3135
  const upload = uploadImageRef.current;
2426
3136
  const src = upload ? await upload(file) : dataUrl;
2427
- (0, import_core4.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
3137
+ (0, import_core5.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
2428
3138
  }, []);
2429
- const getSelectedEmbed = (0, import_react11.useCallback)(() => {
3139
+ const getSelectedEmbed = (0, import_react13.useCallback)(() => {
2430
3140
  const sel = selectionRef.current;
2431
3141
  if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;
2432
3142
  if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;
@@ -2443,7 +3153,7 @@ function useEditor(opts = {}) {
2443
3153
  cursor += op.insert.length;
2444
3154
  continue;
2445
3155
  }
2446
- if (cursor === start && (0, import_core4.isImageEmbed)(op.insert)) {
3156
+ if (cursor === start && (0, import_core5.isImageEmbed)(op.insert)) {
2447
3157
  return {
2448
3158
  blockIndex: sel.anchor.blockIndex,
2449
3159
  cellIndex: sel.anchor.cellIndex,
@@ -2455,39 +3165,48 @@ function useEditor(opts = {}) {
2455
3165
  }
2456
3166
  return null;
2457
3167
  }, [doc]);
2458
- const [linkRequest, setLinkRequest] = (0, import_react11.useState)(null);
2459
- const requestLink = (0, import_react11.useCallback)((initialHref = "") => {
3168
+ const [linkRequest, setLinkRequest] = (0, import_react13.useState)(null);
3169
+ const linkRequestRef = (0, import_react13.useRef)(null);
3170
+ const requestLink = (0, import_react13.useCallback)((initialHref = "") => {
2460
3171
  return new Promise((resolve) => {
2461
- setLinkRequest({ initialHref, resolve });
2462
- });
2463
- }, []);
2464
- const resolveLinkRequest = (0, import_react11.useCallback)((href) => {
2465
- setLinkRequest((prev) => {
2466
- if (prev) prev.resolve(href);
2467
- return null;
3172
+ const req = { initialHref, resolve, selection: selectionRef.current };
3173
+ linkRequestRef.current = req;
3174
+ setLinkRequest(req);
2468
3175
  });
2469
3176
  }, []);
3177
+ const resolveLinkRequest = (0, import_react13.useCallback)(
3178
+ (href) => {
3179
+ const req = linkRequestRef.current;
3180
+ linkRequestRef.current = null;
3181
+ setLinkRequest(null);
3182
+ if (req) {
3183
+ setSelection(req.selection);
3184
+ req.resolve(href);
3185
+ }
3186
+ },
3187
+ [setSelection]
3188
+ );
2470
3189
  const pageSettings = usePageSettings(doc);
2471
- const setPageSettings = (0, import_react11.useCallback)(
3190
+ const setPageSettings = (0, import_react13.useCallback)(
2472
3191
  (partial) => {
2473
3192
  doc.setPageSettings(partial);
2474
3193
  },
2475
3194
  [doc]
2476
3195
  );
2477
- const [pageConfigRequest, setPageConfigRequest] = (0, import_react11.useState)(null);
2478
- const requestPageConfig = (0, import_react11.useCallback)(() => {
3196
+ const [pageConfigRequest, setPageConfigRequest] = (0, import_react13.useState)(null);
3197
+ const requestPageConfig = (0, import_react13.useCallback)(() => {
2479
3198
  return new Promise((resolve) => {
2480
3199
  setPageConfigRequest({ initial: doc.getPageSettings(), resolve });
2481
3200
  });
2482
3201
  }, [doc]);
2483
- const resolvePageConfigRequest = (0, import_react11.useCallback)((applied) => {
3202
+ const resolvePageConfigRequest = (0, import_react13.useCallback)((applied) => {
2484
3203
  setPageConfigRequest((prev) => {
2485
3204
  if (prev) prev.resolve(applied);
2486
3205
  return null;
2487
3206
  });
2488
3207
  }, []);
2489
- const [imageCaptionRequest, setImageCaptionRequest] = (0, import_react11.useState)(null);
2490
- const requestImageCaption = (0, import_react11.useCallback)(
3208
+ const [imageCaptionRequest, setImageCaptionRequest] = (0, import_react13.useState)(null);
3209
+ const requestImageCaption = (0, import_react13.useCallback)(
2491
3210
  (initialCaption = "", initialAlign = "center") => {
2492
3211
  return new Promise((resolve) => {
2493
3212
  setImageCaptionRequest({ initialCaption, initialAlign, resolve });
@@ -2495,7 +3214,7 @@ function useEditor(opts = {}) {
2495
3214
  },
2496
3215
  []
2497
3216
  );
2498
- const resolveImageCaptionRequest = (0, import_react11.useCallback)((result) => {
3217
+ const resolveImageCaptionRequest = (0, import_react13.useCallback)((result) => {
2499
3218
  setImageCaptionRequest((prev) => {
2500
3219
  if (prev) prev.resolve(result);
2501
3220
  return null;
@@ -2519,6 +3238,8 @@ function useEditor(opts = {}) {
2519
3238
  getBlockAttr,
2520
3239
  setBlockType,
2521
3240
  setBlockAttr,
3241
+ setAlign,
3242
+ getAlign,
2522
3243
  isListActive,
2523
3244
  toggleList,
2524
3245
  indentList,
@@ -2548,6 +3269,7 @@ function useEditor(opts = {}) {
2548
3269
  mergeSelection,
2549
3270
  insertImage,
2550
3271
  setImageAttrs,
3272
+ moveEmbedAnchor,
2551
3273
  insertImageFromFile,
2552
3274
  getSelectedEmbed,
2553
3275
  pageSettings,
@@ -2589,54 +3311,99 @@ function sameValue(a, b) {
2589
3311
  }
2590
3312
 
2591
3313
  // src/Editor.tsx
2592
- var import_jsx_runtime9 = require("react/jsx-runtime");
3314
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2593
3315
  var defaultFooter = ({ pageNumber, pageCount }) => `${pageNumber} / ${pageCount}`;
2594
3316
  function Editor({
2595
3317
  editor: providedEditor,
2596
3318
  className,
2597
3319
  pageGeometry,
2598
3320
  renderPageHeader,
2599
- renderPageFooter = defaultFooter
3321
+ renderPageFooter = defaultFooter,
3322
+ awareness
2600
3323
  }) {
2601
3324
  const internal = useEditor();
2602
3325
  const editor = providedEditor ?? internal;
2603
3326
  const { doc, history, snapshot, getSelection, setSelection } = editor;
2604
- const rootRef = (0, import_react12.useRef)(null);
2605
- const isComposingRef = (0, import_react12.useRef)(false);
2606
- const suppressSelectionSyncRef = (0, import_react12.useRef)(false);
2607
- const ctxRef = (0, import_react12.useRef)({ doc, getSelection, setSelection });
3327
+ const rootRef = (0, import_react14.useRef)(null);
3328
+ const isComposingRef = (0, import_react14.useRef)(false);
3329
+ const [hoveredBehind, setHoveredBehind] = (0, import_react14.useState)(null);
3330
+ const hoveredBehindRef = (0, import_react14.useRef)(null);
3331
+ const [hoveredLink, setHoveredLink] = (0, import_react14.useState)(null);
3332
+ const hoveredLinkElRef = (0, import_react14.useRef)(null);
3333
+ const suppressSelectionSyncRef = (0, import_react14.useRef)(false);
3334
+ (0, import_react14.useEffect)(() => {
3335
+ if (!awareness) return;
3336
+ const root = rootRef.current;
3337
+ if (!root) return;
3338
+ let raf = null;
3339
+ const publish = () => {
3340
+ raf = null;
3341
+ const sel = readDomSelection(root);
3342
+ awareness.setLocalStateField(
3343
+ "cursor",
3344
+ sel ? (0, import_core6.encodeSelection)(doc, sel) ?? null : null
3345
+ );
3346
+ };
3347
+ const onSelChange = () => {
3348
+ const s = document.getSelection();
3349
+ if (!s || s.rangeCount === 0) return;
3350
+ if (s.anchorNode && !root.contains(s.anchorNode)) return;
3351
+ if (raf != null) return;
3352
+ raf = requestAnimationFrame(publish);
3353
+ };
3354
+ const onBlur = () => awareness.setLocalStateField("cursor", null);
3355
+ document.addEventListener("selectionchange", onSelChange);
3356
+ root.addEventListener("blur", onBlur, true);
3357
+ return () => {
3358
+ document.removeEventListener("selectionchange", onSelChange);
3359
+ root.removeEventListener("blur", onBlur, true);
3360
+ if (raf != null) cancelAnimationFrame(raf);
3361
+ awareness.setLocalStateField("cursor", null);
3362
+ };
3363
+ }, [awareness, doc]);
3364
+ const ctxRef = (0, import_react14.useRef)({ doc, getSelection, setSelection });
2608
3365
  ctxRef.current = { doc, getSelection, setSelection };
2609
- const historyRef = (0, import_react12.useRef)(history);
3366
+ const historyRef = (0, import_react14.useRef)(history);
2610
3367
  historyRef.current = history;
2611
- const editorRef = (0, import_react12.useRef)(editor);
3368
+ const editorRef = (0, import_react14.useRef)(editor);
2612
3369
  editorRef.current = editor;
2613
- (0, import_react12.useLayoutEffect)(() => {
3370
+ (0, import_react14.useLayoutEffect)(() => {
2614
3371
  const root = rootRef.current;
2615
3372
  if (!root) return;
2616
3373
  if (isComposingRef.current) return;
2617
3374
  if (document.activeElement !== root) return;
2618
3375
  const current = readDomSelection(root);
2619
3376
  if (current && selectionsEqual(current, editor.selection)) return;
3377
+ if (isTableRectSelection(editor.selection)) {
3378
+ applyDomSelection(root, editor.selection);
3379
+ suppressSelectionSyncRef.current = false;
3380
+ return;
3381
+ }
2620
3382
  suppressSelectionSyncRef.current = true;
2621
3383
  applyDomSelection(root, editor.selection);
2622
- queueMicrotask(() => {
2623
- suppressSelectionSyncRef.current = false;
2624
- });
2625
3384
  });
2626
- (0, import_react12.useEffect)(() => {
3385
+ (0, import_react14.useEffect)(() => {
2627
3386
  const root = rootRef.current;
2628
3387
  if (!root) return;
2629
3388
  const handler = () => {
2630
- if (suppressSelectionSyncRef.current) return;
2631
3389
  if (isComposingRef.current) return;
2632
- if (document.activeElement !== root) return;
3390
+ if (document.activeElement !== root) {
3391
+ suppressSelectionSyncRef.current = false;
3392
+ return;
3393
+ }
2633
3394
  const modelSel = readDomSelection(root);
3395
+ if (suppressSelectionSyncRef.current) {
3396
+ if (modelSel && selectionsEqual(modelSel, editorRef.current.getSelection())) {
3397
+ suppressSelectionSyncRef.current = false;
3398
+ }
3399
+ return;
3400
+ }
2634
3401
  if (modelSel) setSelection(modelSel);
2635
3402
  };
2636
3403
  document.addEventListener("selectionchange", handler);
2637
3404
  return () => document.removeEventListener("selectionchange", handler);
2638
3405
  }, [setSelection]);
2639
- (0, import_react12.useEffect)(() => {
3406
+ (0, import_react14.useEffect)(() => {
2640
3407
  const root = rootRef.current;
2641
3408
  if (!root) return;
2642
3409
  let drag = null;
@@ -2707,7 +3474,7 @@ function Editor({
2707
3474
  document.removeEventListener("pointerup", onPointerUp);
2708
3475
  };
2709
3476
  }, []);
2710
- (0, import_react12.useEffect)(() => {
3477
+ (0, import_react14.useEffect)(() => {
2711
3478
  const root = rootRef.current;
2712
3479
  if (!root) return;
2713
3480
  const onDragOver = (e) => {
@@ -2745,7 +3512,7 @@ function Editor({
2745
3512
  root.removeEventListener("drop", onDrop);
2746
3513
  };
2747
3514
  }, []);
2748
- (0, import_react12.useEffect)(() => {
3515
+ (0, import_react14.useEffect)(() => {
2749
3516
  const root = rootRef.current;
2750
3517
  if (!root) return;
2751
3518
  const onPointerDown = (e) => {
@@ -2773,7 +3540,95 @@ function Editor({
2773
3540
  root.addEventListener("pointerdown", onPointerDown);
2774
3541
  return () => root.removeEventListener("pointerdown", onPointerDown);
2775
3542
  }, []);
2776
- (0, import_react12.useEffect)(() => {
3543
+ (0, import_react14.useEffect)(() => {
3544
+ const root = rootRef.current;
3545
+ if (!root) return;
3546
+ const same = (a, b) => a === b || !!a && !!b && a.blockIndex === b.blockIndex && a.offset === b.offset && (a.cellIndex ?? -1) === (b.cellIndex ?? -1);
3547
+ const set = (next) => {
3548
+ if (same(next, hoveredBehindRef.current)) return;
3549
+ hoveredBehindRef.current = next;
3550
+ setHoveredBehind(next);
3551
+ };
3552
+ let raf = 0;
3553
+ const onMove = (e) => {
3554
+ if (raf) return;
3555
+ const x = e.clientX;
3556
+ const y = e.clientY;
3557
+ raf = requestAnimationFrame(() => {
3558
+ raf = 0;
3559
+ const imgs = root.querySelectorAll(
3560
+ 'img[data-embed="image"][data-embed-layout="behind"]'
3561
+ );
3562
+ let hit = null;
3563
+ for (const img of imgs) {
3564
+ const r = img.getBoundingClientRect();
3565
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {
3566
+ hit = img;
3567
+ break;
3568
+ }
3569
+ }
3570
+ if (!hit) {
3571
+ set(null);
3572
+ return;
3573
+ }
3574
+ const blockEl = hit.closest("[data-block-index]");
3575
+ const offsetAttr = hit.dataset.embedOffset;
3576
+ if (!blockEl || offsetAttr == null) {
3577
+ set(null);
3578
+ return;
3579
+ }
3580
+ const blockIndex = Number.parseInt(blockEl.dataset.blockIndex, 10);
3581
+ const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? "0", 10) || 0;
3582
+ const cellEl = hit.closest("[data-cell-index]");
3583
+ const cellIndex = cellEl ? Number.parseInt(cellEl.dataset.cellIndex, 10) : void 0;
3584
+ set({ blockIndex, offset: fragmentStart + Number.parseInt(offsetAttr, 10), cellIndex });
3585
+ });
3586
+ };
3587
+ const onLeave = () => set(null);
3588
+ root.addEventListener("pointermove", onMove);
3589
+ root.addEventListener("pointerleave", onLeave);
3590
+ return () => {
3591
+ root.removeEventListener("pointermove", onMove);
3592
+ root.removeEventListener("pointerleave", onLeave);
3593
+ if (raf) cancelAnimationFrame(raf);
3594
+ };
3595
+ }, []);
3596
+ (0, import_react14.useEffect)(() => {
3597
+ const root = rootRef.current;
3598
+ if (!root) return;
3599
+ const clear = () => {
3600
+ if (hoveredLinkElRef.current) {
3601
+ hoveredLinkElRef.current = null;
3602
+ setHoveredLink(null);
3603
+ }
3604
+ };
3605
+ const onOver = (e) => {
3606
+ const target = e.target;
3607
+ const a = target?.closest?.("a[href]");
3608
+ if (a && root.contains(a)) {
3609
+ if (hoveredLinkElRef.current === a) return;
3610
+ hoveredLinkElRef.current = a;
3611
+ const r = a.getBoundingClientRect();
3612
+ setHoveredLink({
3613
+ href: a.getAttribute("href") ?? "",
3614
+ rect: { top: r.top, left: r.left, bottom: r.bottom, width: r.width }
3615
+ });
3616
+ } else {
3617
+ clear();
3618
+ }
3619
+ };
3620
+ root.addEventListener("mouseover", onOver);
3621
+ root.addEventListener("mouseleave", clear);
3622
+ root.addEventListener("scroll", clear, true);
3623
+ window.addEventListener("scroll", clear, true);
3624
+ return () => {
3625
+ root.removeEventListener("mouseover", onOver);
3626
+ root.removeEventListener("mouseleave", clear);
3627
+ root.removeEventListener("scroll", clear, true);
3628
+ window.removeEventListener("scroll", clear, true);
3629
+ };
3630
+ }, []);
3631
+ (0, import_react14.useEffect)(() => {
2777
3632
  const root = rootRef.current;
2778
3633
  if (!root) return;
2779
3634
  const handler = (e) => {
@@ -2787,12 +3642,37 @@ function Editor({
2787
3642
  const data = e.data ?? "";
2788
3643
  if (data.length > 0) {
2789
3644
  e.preventDefault();
2790
- (0, import_core5.insertText)(ctx, data, ed.consumePendingMarks());
3645
+ (0, import_core6.insertText)(ctx, data, ed.consumePendingMarks());
2791
3646
  }
2792
3647
  return;
2793
3648
  }
2794
- case "insertParagraph":
2795
3649
  case "insertLineBreak": {
3650
+ e.preventDefault();
3651
+ if (ed.getBlockType() === "listItem") {
3652
+ (0, import_core6.insertText)(ctx, "\n", ed.consumePendingMarks());
3653
+ return;
3654
+ }
3655
+ const selEmbed = ed.getSelectedEmbed();
3656
+ if (selEmbed) {
3657
+ const off = selEmbed.offset + 1;
3658
+ ctx.setSelection({
3659
+ anchor: {
3660
+ blockIndex: selEmbed.blockIndex,
3661
+ cellIndex: selEmbed.cellIndex,
3662
+ offset: off
3663
+ },
3664
+ focus: {
3665
+ blockIndex: selEmbed.blockIndex,
3666
+ cellIndex: selEmbed.cellIndex,
3667
+ offset: off
3668
+ }
3669
+ });
3670
+ }
3671
+ if (ed.splitListItem()) return;
3672
+ (0, import_core6.insertParagraph)(ctx);
3673
+ return;
3674
+ }
3675
+ case "insertParagraph": {
2796
3676
  e.preventDefault();
2797
3677
  const selectedEmbed2 = ed.getSelectedEmbed();
2798
3678
  if (selectedEmbed2) {
@@ -2811,35 +3691,19 @@ function Editor({
2811
3691
  });
2812
3692
  }
2813
3693
  if (ed.splitListItem()) return;
2814
- (0, import_core5.insertParagraph)(ctx);
3694
+ (0, import_core6.insertParagraph)(ctx);
2815
3695
  return;
2816
3696
  }
2817
3697
  case "insertReplacementText": {
2818
3698
  const text = e.data ?? e.dataTransfer?.getData("text/plain") ?? "";
2819
3699
  if (text.length > 0) {
2820
3700
  e.preventDefault();
2821
- (0, import_core5.insertText)(ctx, text, ed.consumePendingMarks());
3701
+ (0, import_core6.insertText)(ctx, text, ed.consumePendingMarks());
2822
3702
  }
2823
3703
  return;
2824
3704
  }
2825
3705
  case "insertFromPaste": {
2826
3706
  e.preventDefault();
2827
- const images = Array.from(e.dataTransfer?.files ?? []).filter(
2828
- (f) => f.type.startsWith("image/")
2829
- );
2830
- if (images.length > 0) {
2831
- void (async () => {
2832
- for (const f of images) await editorRef.current.insertImageFromFile(f);
2833
- })();
2834
- return;
2835
- }
2836
- const text = e.dataTransfer?.getData("text/plain") ?? "";
2837
- if (text.length === 0) return;
2838
- const lines = text.split(/\r\n|\r|\n/);
2839
- lines.forEach((line, i) => {
2840
- if (i > 0) (0, import_core5.insertParagraph)(ctx);
2841
- if (line.length > 0) (0, import_core5.insertText)(ctx, line);
2842
- });
2843
3707
  return;
2844
3708
  }
2845
3709
  case "deleteContentBackward":
@@ -2847,7 +3711,7 @@ function Editor({
2847
3711
  case "deleteSoftLineBackward":
2848
3712
  case "deleteHardLineBackward": {
2849
3713
  e.preventDefault();
2850
- (0, import_core5.deleteBackward)(ctx);
3714
+ (0, import_core6.deleteBackward)(ctx);
2851
3715
  return;
2852
3716
  }
2853
3717
  case "deleteContentForward":
@@ -2855,7 +3719,7 @@ function Editor({
2855
3719
  case "deleteSoftLineForward":
2856
3720
  case "deleteHardLineForward": {
2857
3721
  e.preventDefault();
2858
- (0, import_core5.deleteForward)(ctx);
3722
+ (0, import_core6.deleteForward)(ctx);
2859
3723
  return;
2860
3724
  }
2861
3725
  case "historyUndo": {
@@ -2877,7 +3741,67 @@ function Editor({
2877
3741
  root.addEventListener("beforeinput", handler);
2878
3742
  return () => root.removeEventListener("beforeinput", handler);
2879
3743
  }, []);
2880
- const onKeyDown = (0, import_react12.useCallback)((e) => {
3744
+ (0, import_react14.useEffect)(() => {
3745
+ const root = rootRef.current;
3746
+ if (!root) return;
3747
+ const writeSlice = (e) => {
3748
+ const ctx = ctxRef.current;
3749
+ const slice = (0, import_core6.serializeSelection)(ctx.doc, ctx.getSelection());
3750
+ if (!slice || !e.clipboardData) return false;
3751
+ e.clipboardData.setData(import_core6.SOFER_MIME, JSON.stringify(slice));
3752
+ e.clipboardData.setData("text/plain", (0, import_core6.sliceToText)(slice));
3753
+ return true;
3754
+ };
3755
+ const onCopy = (e) => {
3756
+ if (writeSlice(e)) e.preventDefault();
3757
+ };
3758
+ const onCut = (e) => {
3759
+ e.preventDefault();
3760
+ if (writeSlice(e)) (0, import_core6.deleteSelection)(ctxRef.current);
3761
+ };
3762
+ const onPaste = (e) => {
3763
+ const ctx = ctxRef.current;
3764
+ const cd = e.clipboardData;
3765
+ if (!cd) return;
3766
+ const raw = cd.getData(import_core6.SOFER_MIME);
3767
+ if (raw) {
3768
+ try {
3769
+ const slice = JSON.parse(raw);
3770
+ if (slice && Array.isArray(slice.blocks)) {
3771
+ e.preventDefault();
3772
+ (0, import_core6.insertSlice)(ctx, slice);
3773
+ return;
3774
+ }
3775
+ } catch {
3776
+ }
3777
+ }
3778
+ const images = Array.from(cd.files ?? []).filter((f) => f.type.startsWith("image/"));
3779
+ if (images.length > 0) {
3780
+ e.preventDefault();
3781
+ void (async () => {
3782
+ for (const f of images) await editorRef.current.insertImageFromFile(f);
3783
+ })();
3784
+ return;
3785
+ }
3786
+ const text = cd.getData("text/plain");
3787
+ if (text.length === 0) return;
3788
+ e.preventDefault();
3789
+ const lines = text.split(/\r\n|\r|\n/);
3790
+ lines.forEach((line, i) => {
3791
+ if (i > 0) (0, import_core6.insertParagraph)(ctx);
3792
+ if (line.length > 0) (0, import_core6.insertText)(ctx, line);
3793
+ });
3794
+ };
3795
+ root.addEventListener("copy", onCopy);
3796
+ root.addEventListener("cut", onCut);
3797
+ root.addEventListener("paste", onPaste);
3798
+ return () => {
3799
+ root.removeEventListener("copy", onCopy);
3800
+ root.removeEventListener("cut", onCut);
3801
+ root.removeEventListener("paste", onPaste);
3802
+ };
3803
+ }, []);
3804
+ const onKeyDown = (0, import_react14.useCallback)((e) => {
2881
3805
  const ed = editorRef.current;
2882
3806
  const mod = e.metaKey || e.ctrlKey;
2883
3807
  if (e.key === "Tab") {
@@ -2891,6 +3815,20 @@ function Editor({
2891
3815
  else ed.indentList();
2892
3816
  return;
2893
3817
  }
3818
+ if (!mod && (e.key === "Home" || e.key === "End")) {
3819
+ const root = rootRef.current;
3820
+ const sel = window.getSelection();
3821
+ const sm = sel?.modify;
3822
+ if (root && sel && sel.rangeCount > 0 && typeof sm === "function") {
3823
+ e.preventDefault();
3824
+ const alter = e.shiftKey ? "extend" : "move";
3825
+ const direction = e.key === "Home" ? "left" : "right";
3826
+ sm.call(sel, alter, direction, "lineboundary");
3827
+ const modelSel = readDomSelection(root);
3828
+ if (modelSel) ctxRef.current.setSelection(modelSel);
3829
+ }
3830
+ return;
3831
+ }
2894
3832
  if (!mod) return;
2895
3833
  const key = e.key.toLowerCase();
2896
3834
  if (!e.shiftKey && !e.altKey && key === "z") {
@@ -2937,37 +3875,58 @@ function Editor({
2937
3875
  });
2938
3876
  }
2939
3877
  }, []);
2940
- const onCompositionStart = (0, import_react12.useCallback)(() => {
3878
+ const onCompositionStart = (0, import_react14.useCallback)(() => {
2941
3879
  isComposingRef.current = true;
2942
3880
  }, []);
2943
- const onCompositionEnd = (0, import_react12.useCallback)((e) => {
3881
+ const onCompositionEnd = (0, import_react14.useCallback)((e) => {
2944
3882
  isComposingRef.current = false;
2945
3883
  if (e.data && e.data.length > 0) {
2946
- (0, import_core5.insertText)(ctxRef.current, e.data);
3884
+ (0, import_core6.insertText)(ctxRef.current, e.data);
2947
3885
  }
2948
3886
  }, []);
2949
- const topLevels = (0, import_react12.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
3887
+ const topLevels = (0, import_react14.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
3888
+ const topLevelsStructuralKey = (0, import_react14.useMemo)(
3889
+ () => topLevels.map(
3890
+ (t) => t.kind === "list" ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}` : `B:${t.block.type}:${t.block.attrs.level ?? ""}`
3891
+ ).join("|"),
3892
+ [topLevels]
3893
+ );
2950
3894
  const docSettings = usePageSettings(editor.doc);
2951
3895
  const propIsSet = pageGeometry !== void 0;
2952
3896
  const geom = propIsSet ? pageGeometry ?? A4_PAGE : docSettings;
2953
3897
  const paginated = pageGeometry !== null;
2954
3898
  const selectedEmbed = editor.getSelectedEmbed();
2955
- const layout = usePageLayout(
3899
+ const { layout, phase: paginationPhase } = usePageLayout(
2956
3900
  rootRef,
2957
3901
  geom,
2958
3902
  topLevels.length,
2959
- [topLevels, pageGeometry]
3903
+ // Usar a chave estrutural (string) em vez do array `topLevels` direto:
3904
+ // o array reference muda a cada keystroke, mas a chave só muda quando
3905
+ // a SHAPE dos top-levels muda. `usePageLayout` compara deps via
3906
+ // `shallowArrayEqual` — string equality cobre isso.
3907
+ [topLevelsStructuralKey, pageGeometry]
2960
3908
  );
2961
3909
  const effectiveLayout = paginated ? layout : defaultPageLayout(topLevels.length);
2962
- const pageStyle = paginated ? {
2963
- "--ed-page-width": `${geom.width}px`,
2964
- "--ed-page-height": `${geom.height}px`,
2965
- "--ed-page-margin-top": `${geom.marginTop}px`,
2966
- "--ed-page-margin-bottom": `${geom.marginBottom}px`,
2967
- "--ed-page-margin-left": `${geom.marginLeft}px`,
2968
- "--ed-page-margin-right": `${geom.marginRight}px`
2969
- } : void 0;
2970
- const body = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3910
+ const pageStyle = (0, import_react14.useMemo)(
3911
+ () => paginated ? {
3912
+ "--ed-page-width": `${geom.width}px`,
3913
+ "--ed-page-height": `${geom.height}px`,
3914
+ "--ed-page-margin-top": `${geom.marginTop}px`,
3915
+ "--ed-page-margin-bottom": `${geom.marginBottom}px`,
3916
+ "--ed-page-margin-left": `${geom.marginLeft}px`,
3917
+ "--ed-page-margin-right": `${geom.marginRight}px`
3918
+ } : void 0,
3919
+ [
3920
+ paginated,
3921
+ geom.width,
3922
+ geom.height,
3923
+ geom.marginTop,
3924
+ geom.marginBottom,
3925
+ geom.marginLeft,
3926
+ geom.marginRight
3927
+ ]
3928
+ );
3929
+ const body = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2971
3930
  "div",
2972
3931
  {
2973
3932
  ref: rootRef,
@@ -2979,6 +3938,7 @@ function Editor({
2979
3938
  role: "textbox",
2980
3939
  "aria-multiline": "true",
2981
3940
  className: (className ?? "ed-root") + (paginated ? " ed-root--paged" : " ed-root--flat"),
3941
+ "data-pagination-phase": paginated ? paginationPhase : void 0,
2982
3942
  style: pageStyle,
2983
3943
  onKeyDown,
2984
3944
  onCompositionStart,
@@ -2989,22 +3949,26 @@ function Editor({
2989
3949
  pageNumber: pi + 1,
2990
3950
  pageCount: effectiveLayout.pages.length
2991
3951
  };
2992
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3952
+ const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
3953
+ "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
3954
+ } : void 0;
3955
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2993
3956
  "div",
2994
3957
  {
2995
3958
  className: "ed-page",
2996
3959
  "data-page-number": ctx.pageNumber,
2997
3960
  "data-page-total": ctx.pageCount,
3961
+ style: pageInlineStyle,
2998
3962
  children: [
2999
- renderPageHeader && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3000
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3001
- renderPageFooter && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
3963
+ renderPageHeader && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3964
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3965
+ renderPageFooter && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
3002
3966
  ]
3003
3967
  },
3004
3968
  `page-${pi}`
3005
3969
  );
3006
3970
  }) : topLevels.map((t) => renderTopLevel(t)),
3007
- selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3971
+ selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3008
3972
  ImageResizeOverlay,
3009
3973
  {
3010
3974
  rootRef,
@@ -3023,13 +3987,54 @@ function Editor({
3023
3987
  selectedEmbed.offset,
3024
3988
  { offsetX: ox, offsetY: oy },
3025
3989
  selectedEmbed.cellIndex
3990
+ ),
3991
+ onReanchor: (to, ox, oy) => editor.moveEmbedAnchor(
3992
+ {
3993
+ blockIndex: selectedEmbed.blockIndex,
3994
+ offset: selectedEmbed.offset,
3995
+ cellIndex: selectedEmbed.cellIndex
3996
+ },
3997
+ to,
3998
+ ox,
3999
+ oy
3026
4000
  )
3027
4001
  }
4002
+ ),
4003
+ hoveredBehind && !(selectedEmbed && selectedEmbed.blockIndex === hoveredBehind.blockIndex && selectedEmbed.offset === hoveredBehind.offset && (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4004
+ BehindImageSelectAffordance,
4005
+ {
4006
+ rootRef,
4007
+ blockIndex: hoveredBehind.blockIndex,
4008
+ offset: hoveredBehind.offset,
4009
+ cellIndex: hoveredBehind.cellIndex,
4010
+ onSelect: () => setSelection({
4011
+ anchor: {
4012
+ blockIndex: hoveredBehind.blockIndex,
4013
+ cellIndex: hoveredBehind.cellIndex,
4014
+ offset: hoveredBehind.offset
4015
+ },
4016
+ focus: {
4017
+ blockIndex: hoveredBehind.blockIndex,
4018
+ cellIndex: hoveredBehind.cellIndex,
4019
+ offset: hoveredBehind.offset + 1
4020
+ }
4021
+ })
4022
+ }
4023
+ ),
4024
+ hoveredLink && hoveredLink.href && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LinkHoverTooltip, { href: hoveredLink.href, rect: hoveredLink.rect }),
4025
+ awareness && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4026
+ RemoteCursorsOverlay,
4027
+ {
4028
+ rootRef,
4029
+ doc,
4030
+ awareness,
4031
+ revision: snapshot
4032
+ }
3028
4033
  )
3029
4034
  ]
3030
4035
  }
3031
4036
  );
3032
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EditorProvider, { editor, children: body });
4037
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EditorProvider, { editor, children: body });
3033
4038
  }
3034
4039
  function groupTopLevels(snapshot) {
3035
4040
  const out = [];
@@ -3040,11 +4045,29 @@ function groupTopLevels(snapshot) {
3040
4045
  const groupStart = i;
3041
4046
  const items = [];
3042
4047
  const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
3043
- while (i < snapshot.length && snapshot[i].type === "listItem" && (snapshot[i].attrs.listKind ?? "bullet") === kind) {
3044
- items.push({ block: snapshot[i], index: i });
4048
+ const groupStyle = block.attrs.listStyle;
4049
+ while (i < snapshot.length) {
4050
+ const b = snapshot[i];
4051
+ if (b.type !== "listItem") break;
4052
+ if ((b.attrs.listKind ?? "bullet") !== kind) break;
4053
+ if (i > groupStart) {
4054
+ if (typeof b.attrs.listStart === "number") break;
4055
+ const itemStyle = b.attrs.listStyle;
4056
+ if (itemStyle !== void 0 && itemStyle !== groupStyle) break;
4057
+ }
4058
+ items.push({ block: b, index: i });
3045
4059
  i++;
3046
4060
  }
3047
- out.push({ kind: "list", items, listKind: kind, key: groupStart });
4061
+ const firstAttrs = items[0].block.attrs;
4062
+ const ordinalStart = typeof firstAttrs.listStart === "number" && firstAttrs.listStart > 0 ? firstAttrs.listStart : 1;
4063
+ out.push({
4064
+ kind: "list",
4065
+ items,
4066
+ listKind: kind,
4067
+ ordinalStart,
4068
+ listStyle: groupStyle,
4069
+ key: groupStart
4070
+ });
3048
4071
  continue;
3049
4072
  }
3050
4073
  out.push({ kind: "block", block, blockIndex: i, key: i });
@@ -3061,7 +4084,7 @@ function renderSlot(slot, topLevels) {
3061
4084
  start: slot.fragment.start,
3062
4085
  end: slot.fragment.end
3063
4086
  };
3064
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4087
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3065
4088
  NodeView,
3066
4089
  {
3067
4090
  block: top.block,
@@ -3072,7 +4095,7 @@ function renderSlot(slot, topLevels) {
3072
4095
  );
3073
4096
  }
3074
4097
  if (slot.tableFragment && top.kind === "block" && top.block.type === "table") {
3075
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4098
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3076
4099
  NodeView,
3077
4100
  {
3078
4101
  block: top.block,
@@ -3082,14 +4105,42 @@ function renderSlot(slot, topLevels) {
3082
4105
  `${top.key}-tf${slot.tableFragment.index}`
3083
4106
  );
3084
4107
  }
4108
+ if (slot.listFragment && top.kind === "list") {
4109
+ return renderListFragment(top, slot.listFragment);
4110
+ }
3085
4111
  return renderTopLevel(top);
3086
4112
  }
3087
4113
  function renderTopLevel(top) {
3088
4114
  if (top.kind === "list") {
3089
4115
  const tree = buildListTree(top.items);
3090
- return renderListTree(tree, top.listKind, `list-${top.key}`);
4116
+ return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
3091
4117
  }
3092
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NodeView, { block: top.block, index: top.blockIndex }, top.key);
4118
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeView, { block: top.block, index: top.blockIndex }, top.key);
4119
+ }
4120
+ function renderListFragment(top, frag) {
4121
+ const ranges = topLevelItemRanges(top.items);
4122
+ const startRange = ranges[frag.itemStart];
4123
+ const endRange = ranges[frag.itemEnd - 1];
4124
+ if (!startRange || !endRange) return renderTopLevel(top);
4125
+ const sliced = top.items.slice(startRange[0], endRange[1]);
4126
+ const ordinalStart = top.ordinalStart + frag.itemStart;
4127
+ const key = `list-${top.key}-f${frag.index}`;
4128
+ const slicedTop = { ...top, items: sliced };
4129
+ const tree = buildListTree(sliced);
4130
+ return renderListTree(tree, slicedTop, ordinalStart, key);
4131
+ }
4132
+ function topLevelItemRanges(items) {
4133
+ const out = [];
4134
+ let currentStart = -1;
4135
+ items.forEach((it, idx) => {
4136
+ const level = clampListLevel2(it.block.attrs.listLevel);
4137
+ if (level === 0) {
4138
+ if (currentStart >= 0) out.push([currentStart, idx]);
4139
+ currentStart = idx;
4140
+ }
4141
+ });
4142
+ if (currentStart >= 0) out.push([currentStart, items.length]);
4143
+ return out;
3093
4144
  }
3094
4145
  function buildListTree(items) {
3095
4146
  const roots = [];
@@ -3103,9 +4154,28 @@ function buildListTree(items) {
3103
4154
  }
3104
4155
  return roots;
3105
4156
  }
3106
- function renderListTree(tree, kind, key) {
4157
+ function renderListTree(tree, top, start, key) {
4158
+ const className = `ed-list ed-list-${top.listKind}`;
4159
+ const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
4160
+ const items = tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(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));
4161
+ if (top.listKind === "ordered") {
4162
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4163
+ "ol",
4164
+ {
4165
+ className,
4166
+ "data-list-kind": "ordered",
4167
+ start: start > 1 ? start : void 0,
4168
+ style,
4169
+ children: items
4170
+ },
4171
+ key
4172
+ );
4173
+ }
4174
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
4175
+ }
4176
+ function renderNestedListTree(tree, kind, key) {
3107
4177
  const Tag = kind === "ordered" ? "ol" : "ul";
3108
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(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);
4178
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(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);
3109
4179
  }
3110
4180
  function clampListLevel2(l) {
3111
4181
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
@@ -3133,8 +4203,8 @@ function caretRangeFromPoint(x, y) {
3133
4203
  }
3134
4204
 
3135
4205
  // src/Toolbar.tsx
3136
- var import_react13 = require("react");
3137
- var import_jsx_runtime10 = require("react/jsx-runtime");
4206
+ var import_react15 = require("react");
4207
+ var import_jsx_runtime13 = require("react/jsx-runtime");
3138
4208
  var FONT_FAMILIES = ["Arial"];
3139
4209
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
3140
4210
  var BLOCK_OPTIONS = [
@@ -3174,6 +4244,8 @@ function Toolbar({ className }) {
3174
4244
  getBlockAttr,
3175
4245
  setBlockType,
3176
4246
  setBlockAttr,
4247
+ setAlign,
4248
+ getAlign,
3177
4249
  isListActive,
3178
4250
  toggleList,
3179
4251
  indentList,
@@ -3182,7 +4254,7 @@ function Toolbar({ className }) {
3182
4254
  const active = getActiveMarks();
3183
4255
  const blockType = getBlockType();
3184
4256
  const blockLevel = getBlockAttr("level");
3185
- const blockAlign = getBlockAttr("align");
4257
+ const blockAlign = getAlign();
3186
4258
  const blockDir = getBlockAttr("dir");
3187
4259
  const stop = (e) => {
3188
4260
  const t = e.target;
@@ -3225,16 +4297,16 @@ function Toolbar({ className }) {
3225
4297
  );
3226
4298
  return;
3227
4299
  }
3228
- setBlockAttr("align", value);
4300
+ setAlign(value);
3229
4301
  };
3230
- const onInsertImageClick = (0, import_react13.useCallback)(
4302
+ const onInsertImageClick = (0, import_react15.useCallback)(
3231
4303
  (e) => {
3232
4304
  e.preventDefault();
3233
4305
  imageInputRef.current?.click();
3234
4306
  },
3235
4307
  []
3236
4308
  );
3237
- const onImageInputChange = (0, import_react13.useCallback)(
4309
+ const onImageInputChange = (0, import_react15.useCallback)(
3238
4310
  (e) => {
3239
4311
  const file = e.target.files?.[0];
3240
4312
  if (file) void editor.insertImageFromFile(file);
@@ -3242,14 +4314,14 @@ function Toolbar({ className }) {
3242
4314
  },
3243
4315
  [editor]
3244
4316
  );
3245
- const imageInputRef = (0, import_react13.useRef)(null);
4317
+ const imageInputRef = (0, import_react15.useRef)(null);
3246
4318
  const onToggleDir = (e) => {
3247
4319
  e.preventDefault();
3248
4320
  const next = blockDir === "rtl" ? "ltr" : "rtl";
3249
4321
  setBlockAttr("dir", next);
3250
4322
  };
3251
4323
  const linkActive = isMarkActive("link");
3252
- const onLinkClick = (0, import_react13.useCallback)(
4324
+ const onLinkClick = (0, import_react15.useCallback)(
3253
4325
  (e) => {
3254
4326
  e.preventDefault();
3255
4327
  const currentHref = active.link && typeof active.link === "object" && "href" in active.link ? active.link.href : "";
@@ -3279,7 +4351,7 @@ function Toolbar({ className }) {
3279
4351
  sel.cellIndex
3280
4352
  );
3281
4353
  };
3282
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4354
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3283
4355
  "div",
3284
4356
  {
3285
4357
  className: className ?? "ed-toolbar",
@@ -3287,7 +4359,7 @@ function Toolbar({ className }) {
3287
4359
  "aria-label": "Editor toolbar",
3288
4360
  onMouseDown: stop,
3289
4361
  children: [
3290
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4362
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3291
4363
  "select",
3292
4364
  {
3293
4365
  className: "ed-toolbar-select",
@@ -3296,23 +4368,23 @@ function Toolbar({ className }) {
3296
4368
  onMouseDown: stop,
3297
4369
  "aria-label": "Tipo de bloco",
3298
4370
  children: [
3299
- blockValue === "" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "\u2014 (misto)" }),
3300
- BLOCK_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: o.value, children: o.label }, o.value))
4371
+ blockValue === "" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: "\u2014 (misto)" }),
4372
+ BLOCK_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: o.value, children: o.label }, o.value))
3301
4373
  ]
3302
4374
  }
3303
4375
  ) }),
3304
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3305
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "B" }) }),
3306
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("em", { children: "I" }) }),
3307
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("u", { children: "U" }) }),
3308
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("s", { children: "S" }) })
4376
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4377
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: "B" }) }),
4378
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("em", { children: "I" }) }),
4379
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("u", { children: "U" }) }),
4380
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("s", { children: "S" }) })
3309
4381
  ] }),
3310
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3311
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "ed-toolbar-label", children: [
3312
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
3313
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
4382
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4383
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "ed-toolbar-label", children: [
4384
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
4385
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
3314
4386
  ] }),
3315
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4387
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3316
4388
  "button",
3317
4389
  {
3318
4390
  type: "button",
@@ -3327,8 +4399,8 @@ function Toolbar({ className }) {
3327
4399
  }
3328
4400
  )
3329
4401
  ] }),
3330
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3331
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4402
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4403
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3332
4404
  "select",
3333
4405
  {
3334
4406
  className: "ed-toolbar-select",
@@ -3337,12 +4409,12 @@ function Toolbar({ className }) {
3337
4409
  onMouseDown: stop,
3338
4410
  "aria-label": "Fam\xEDlia da fonte",
3339
4411
  children: [
3340
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "Fonte\u2026" }),
3341
- FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: f, children: f }, f))
4412
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: "Fonte\u2026" }),
4413
+ FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: f, children: f }, f))
3342
4414
  ]
3343
4415
  }
3344
4416
  ),
3345
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4417
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3346
4418
  "select",
3347
4419
  {
3348
4420
  className: "ed-toolbar-select",
@@ -3351,13 +4423,13 @@ function Toolbar({ className }) {
3351
4423
  onMouseDown: stop,
3352
4424
  "aria-label": "Tamanho da fonte",
3353
4425
  children: [
3354
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "Tamanho\u2026" }),
3355
- FONT_SIZES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: s, children: s }, s))
4426
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: "Tamanho\u2026" }),
4427
+ FONT_SIZES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: s, children: s }, s))
3356
4428
  ]
3357
4429
  }
3358
4430
  )
3359
4431
  ] }),
3360
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4432
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3361
4433
  "button",
3362
4434
  {
3363
4435
  type: "button",
@@ -3370,7 +4442,7 @@ function Toolbar({ className }) {
3370
4442
  },
3371
4443
  a.value
3372
4444
  )) }),
3373
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4445
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3374
4446
  "button",
3375
4447
  {
3376
4448
  type: "button",
@@ -3382,8 +4454,8 @@ function Toolbar({ className }) {
3382
4454
  children: blockDir === "rtl" ? "RTL" : "LTR"
3383
4455
  }
3384
4456
  ) }),
3385
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3386
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4457
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4458
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3387
4459
  "button",
3388
4460
  {
3389
4461
  type: "button",
@@ -3398,7 +4470,7 @@ function Toolbar({ className }) {
3398
4470
  children: "\u2022"
3399
4471
  }
3400
4472
  ),
3401
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4473
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3402
4474
  "button",
3403
4475
  {
3404
4476
  type: "button",
@@ -3413,7 +4485,7 @@ function Toolbar({ className }) {
3413
4485
  children: "1."
3414
4486
  }
3415
4487
  ),
3416
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4488
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3417
4489
  "button",
3418
4490
  {
3419
4491
  type: "button",
@@ -3427,7 +4499,7 @@ function Toolbar({ className }) {
3427
4499
  children: "\u21E4"
3428
4500
  }
3429
4501
  ),
3430
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4502
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3431
4503
  "button",
3432
4504
  {
3433
4505
  type: "button",
@@ -3442,7 +4514,7 @@ function Toolbar({ className }) {
3442
4514
  }
3443
4515
  )
3444
4516
  ] }),
3445
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4517
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3446
4518
  "button",
3447
4519
  {
3448
4520
  type: "button",
@@ -3454,9 +4526,9 @@ function Toolbar({ className }) {
3454
4526
  children: "\u{1F517}"
3455
4527
  }
3456
4528
  ) }),
3457
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TableMenu, {}) }),
3458
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3459
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4529
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TableMenu, {}) }),
4530
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4531
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3460
4532
  "button",
3461
4533
  {
3462
4534
  type: "button",
@@ -3467,7 +4539,7 @@ function Toolbar({ className }) {
3467
4539
  children: "\u{1F5BC}"
3468
4540
  }
3469
4541
  ),
3470
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4542
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3471
4543
  "input",
3472
4544
  {
3473
4545
  ref: imageInputRef,
@@ -3478,8 +4550,8 @@ function Toolbar({ className }) {
3478
4550
  }
3479
4551
  )
3480
4552
  ] }),
3481
- selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3482
- IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4553
+ selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4554
+ IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3483
4555
  "button",
3484
4556
  {
3485
4557
  type: "button",
@@ -3492,7 +4564,7 @@ function Toolbar({ className }) {
3492
4564
  },
3493
4565
  opt.value
3494
4566
  )),
3495
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4567
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3496
4568
  "button",
3497
4569
  {
3498
4570
  type: "button",
@@ -3522,7 +4594,7 @@ function Toolbar({ className }) {
3522
4594
  }
3523
4595
  )
3524
4596
  ] }),
3525
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4597
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3526
4598
  "button",
3527
4599
  {
3528
4600
  type: "button",
@@ -3543,9 +4615,9 @@ function Toolbar({ className }) {
3543
4615
  function TableMenu() {
3544
4616
  const editor = useEditorContext();
3545
4617
  const inTable = editor.isInTable();
3546
- const [open, setOpen] = (0, import_react13.useState)(false);
3547
- const rootRef = (0, import_react13.useRef)(null);
3548
- (0, import_react13.useEffect)(() => {
4618
+ const [open, setOpen] = (0, import_react15.useState)(false);
4619
+ const rootRef = (0, import_react15.useRef)(null);
4620
+ (0, import_react15.useEffect)(() => {
3549
4621
  if (!open) return;
3550
4622
  const onDown = (e) => {
3551
4623
  if (!rootRef.current) return;
@@ -3555,8 +4627,8 @@ function TableMenu() {
3555
4627
  document.addEventListener("mousedown", onDown);
3556
4628
  return () => document.removeEventListener("mousedown", onDown);
3557
4629
  }, [open]);
3558
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
3559
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4630
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
4631
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3560
4632
  "button",
3561
4633
  {
3562
4634
  type: "button",
@@ -3571,7 +4643,7 @@ function TableMenu() {
3571
4643
  children: "\u25A6"
3572
4644
  }
3573
4645
  ),
3574
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4646
+ open && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3575
4647
  "div",
3576
4648
  {
3577
4649
  className: "ed-table-popover",
@@ -3583,7 +4655,7 @@ function TableMenu() {
3583
4655
  }
3584
4656
  },
3585
4657
  children: [
3586
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4658
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3587
4659
  TableSizePicker,
3588
4660
  {
3589
4661
  onPick: (rows, cols) => {
@@ -3592,34 +4664,34 @@ function TableMenu() {
3592
4664
  }
3593
4665
  }
3594
4666
  ),
3595
- inTable && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ed-table-actions", children: [
3596
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("hr", {}),
3597
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4667
+ inTable && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ed-table-actions", children: [
4668
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("hr", {}),
4669
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3598
4670
  setOpen(false);
3599
4671
  editor.insertRowAbove();
3600
4672
  }, children: "Inserir linha acima" }),
3601
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4673
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3602
4674
  setOpen(false);
3603
4675
  editor.insertRowBelow();
3604
4676
  }, children: "Inserir linha abaixo" }),
3605
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4677
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3606
4678
  setOpen(false);
3607
4679
  editor.insertColumnLeft();
3608
4680
  }, children: "Inserir coluna \xE0 esquerda" }),
3609
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4681
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3610
4682
  setOpen(false);
3611
4683
  editor.insertColumnRight();
3612
4684
  }, children: "Inserir coluna \xE0 direita" }),
3613
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4685
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3614
4686
  setOpen(false);
3615
4687
  editor.deleteCurrentRow();
3616
4688
  }, children: "Excluir linha" }),
3617
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4689
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3618
4690
  setOpen(false);
3619
4691
  editor.deleteCurrentColumn();
3620
4692
  }, children: "Excluir coluna" }),
3621
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("hr", {}),
3622
- editor.hasTableRectSelection() && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4693
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("hr", {}),
4694
+ editor.hasTableRectSelection() && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3623
4695
  "button",
3624
4696
  {
3625
4697
  type: "button",
@@ -3630,19 +4702,19 @@ function TableMenu() {
3630
4702
  children: "Mesclar c\xE9lulas selecionadas"
3631
4703
  }
3632
4704
  ),
3633
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4705
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3634
4706
  setOpen(false);
3635
4707
  editor.mergeRight();
3636
4708
  }, children: "Mesclar com c\xE9lula \xE0 direita" }),
3637
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4709
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3638
4710
  setOpen(false);
3639
4711
  editor.mergeDown();
3640
4712
  }, children: "Mesclar com c\xE9lula abaixo" }),
3641
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4713
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3642
4714
  setOpen(false);
3643
4715
  editor.splitCell();
3644
4716
  }, children: "Dividir c\xE9lulas mescladas" }),
3645
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4717
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3646
4718
  "button",
3647
4719
  {
3648
4720
  type: "button",
@@ -3663,11 +4735,11 @@ function TableMenu() {
3663
4735
  var PICKER_MAX_ROWS = 8;
3664
4736
  var PICKER_MAX_COLS = 10;
3665
4737
  function TableSizePicker({ onPick }) {
3666
- const [hover, setHover] = (0, import_react13.useState)(null);
4738
+ const [hover, setHover] = (0, import_react15.useState)(null);
3667
4739
  const label = hover ? `${hover.r + 1} \xD7 ${hover.c + 1}` : "Inserir tabela";
3668
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ed-table-picker", children: [
3669
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ed-table-picker-label", children: label }),
3670
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4740
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ed-table-picker", children: [
4741
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ed-table-picker-label", children: label }),
4742
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3671
4743
  "div",
3672
4744
  {
3673
4745
  className: "ed-table-picker-grid",
@@ -3680,7 +4752,7 @@ function TableSizePicker({ onPick }) {
3680
4752
  { length: PICKER_MAX_ROWS },
3681
4753
  (_, r) => Array.from({ length: PICKER_MAX_COLS }, (_2, c) => {
3682
4754
  const filled = hover != null && r <= hover.r && c <= hover.c;
3683
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4755
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3684
4756
  "button",
3685
4757
  {
3686
4758
  type: "button",
@@ -3710,10 +4782,10 @@ function blockSelectValue(type, level) {
3710
4782
  return type;
3711
4783
  }
3712
4784
  function Group({ children }) {
3713
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ed-toolbar-group", children });
4785
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ed-toolbar-group", children });
3714
4786
  }
3715
4787
  function MarkButton({ title, pressed, onClick, children }) {
3716
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4788
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3717
4789
  "button",
3718
4790
  {
3719
4791
  type: "button",
@@ -3735,6 +4807,7 @@ function MarkButton({ title, pressed, onClick, children }) {
3735
4807
  LinkDialog,
3736
4808
  NodeView,
3737
4809
  PageConfigDialog,
4810
+ RemoteCursorsOverlay,
3738
4811
  Toolbar,
3739
4812
  applyDomSelection,
3740
4813
  contentHeight,
@@ -3746,6 +4819,7 @@ function MarkButton({ title, pressed, onClick, children }) {
3746
4819
  getCellElement,
3747
4820
  getFragmentForOffset,
3748
4821
  isTableRectSelection,
4822
+ locatePoint,
3749
4823
  readDomSelection,
3750
4824
  renderInline,
3751
4825
  selectionsEqual,