@sofereditor/react 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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,18 +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";
1181
1742
  const commentMarkId = op.attributes?.comment?.markId;
1182
1743
  if (layout === "wrap-left" || layout === "wrap-right") {
1183
1744
  wrapAnchors.push(
1184
- /* @__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`)
1185
1746
  );
1186
1747
  body.push(
1187
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1748
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1188
1749
  "span",
1189
1750
  {
1190
1751
  "data-embed-phantom": "true",
@@ -1196,10 +1757,10 @@ function renderInline(delta, keyPrefix) {
1196
1757
  )
1197
1758
  );
1198
1759
  } else {
1199
- const imgNode = /* @__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);
1200
1761
  if (commentMarkId) {
1201
1762
  body.push(
1202
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1763
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1203
1764
  );
1204
1765
  } else {
1205
1766
  body.push(imgNode);
@@ -1210,7 +1771,7 @@ function renderInline(delta, keyPrefix) {
1210
1771
  offset += 1;
1211
1772
  }
1212
1773
  }
1213
- 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" });
1214
1775
  return [...wrapAnchors, ...body];
1215
1776
  }
1216
1777
  var PHANTOM_STYLE = {
@@ -1220,6 +1781,11 @@ var PHANTOM_STYLE = {
1220
1781
  overflow: "hidden",
1221
1782
  verticalAlign: "baseline"
1222
1783
  };
1784
+ var LINK_STYLE = {
1785
+ color: "#2563eb",
1786
+ textDecoration: "underline",
1787
+ cursor: "text"
1788
+ };
1223
1789
  function imageEmbedPropsEqual(a, b) {
1224
1790
  if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;
1225
1791
  const x = a.embed;
@@ -1230,7 +1796,7 @@ function imageEmbedPropsEqual(a, b) {
1230
1796
  // because Y.js stores the embed in its content map and re-exposes it.
1231
1797
  x.src === y.src;
1232
1798
  }
1233
- var ImageEmbedView = (0, import_react6.memo)(ImageEmbedViewImpl, imageEmbedPropsEqual);
1799
+ var ImageEmbedView = (0, import_react8.memo)(ImageEmbedViewImpl, imageEmbedPropsEqual);
1234
1800
  function ImageEmbedViewImpl({
1235
1801
  embed,
1236
1802
  offset,
@@ -1285,8 +1851,12 @@ function ImageEmbedViewImpl({
1285
1851
  };
1286
1852
  break;
1287
1853
  }
1288
- const imgStyle = hasCaption ? { width: embed.width, height: embed.height, display: "block" } : outerStyle;
1289
- 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)(
1290
1860
  "img",
1291
1861
  {
1292
1862
  src: embed.src,
@@ -1305,19 +1875,18 @@ function ImageEmbedViewImpl({
1305
1875
  alt: ""
1306
1876
  }
1307
1877
  );
1308
- if (!hasCaption) return img;
1309
1878
  const captionAlign = embed.captionAlign ?? "center";
1310
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1879
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1311
1880
  "figure",
1312
1881
  {
1313
1882
  className: "ed-figure",
1314
1883
  contentEditable: false,
1315
- "data-embed-figure": "true",
1884
+ "data-embed-figure": hasCaption ? "true" : void 0,
1316
1885
  "data-embed-layout": layout,
1317
1886
  style: outerStyle,
1318
1887
  children: [
1319
1888
  img,
1320
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1889
+ hasCaption && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1321
1890
  "figcaption",
1322
1891
  {
1323
1892
  className: "ed-figcaption",
@@ -1333,34 +1902,38 @@ function ImageEmbedViewImpl({
1333
1902
  function wrap(text, attrs) {
1334
1903
  let node = text;
1335
1904
  if (!attrs) return node;
1336
- if (attrs.bold) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: node });
1337
- if (attrs.italic) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { children: node });
1338
- if (attrs.underline) node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("u", { children: node });
1339
- 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 });
1340
1909
  const styleParts = {};
1341
1910
  if (attrs.color) styleParts.color = attrs.color;
1342
1911
  if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;
1343
1912
  if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;
1344
1913
  if (Object.keys(styleParts).length > 0) {
1345
- 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 });
1346
1915
  }
1347
1916
  if (attrs.link?.href) {
1348
- node = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1917
+ node = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1349
1918
  "a",
1350
1919
  {
1351
1920
  href: attrs.link.href,
1352
1921
  title: attrs.link.title,
1353
1922
  rel: "noopener noreferrer",
1354
1923
  target: "_blank",
1924
+ style: LINK_STYLE,
1355
1925
  onClick: (e) => {
1356
- 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
+ }
1357
1930
  },
1358
1931
  children: node
1359
1932
  }
1360
1933
  );
1361
1934
  }
1362
1935
  if (attrs.comment?.markId) {
1363
- 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 });
1364
1937
  }
1365
1938
  return node;
1366
1939
  }
@@ -1404,14 +1977,14 @@ function sliceDelta(delta, start, end) {
1404
1977
  }
1405
1978
 
1406
1979
  // src/TableResizeOverlay.tsx
1407
- var import_react7 = require("react");
1408
- var import_jsx_runtime7 = require("react/jsx-runtime");
1980
+ var import_react9 = require("react");
1981
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1409
1982
  function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1410
1983
  const editor = useEditorContext();
1411
- const [positions, setPositions] = (0, import_react7.useState)(null);
1412
- const [layout, setLayout] = (0, import_react7.useState)(null);
1413
- const draggingRef = (0, import_react7.useRef)(null);
1414
- 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)(() => {
1415
1988
  const table = tableRef.current;
1416
1989
  if (!table) return;
1417
1990
  const tableRect = table.getBoundingClientRect();
@@ -1441,17 +2014,17 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1441
2014
  }
1442
2015
  setLayout({ rights, height: tableRect.height });
1443
2016
  }, [cols, tableRef]);
1444
- (0, import_react7.useLayoutEffect)(() => {
2017
+ (0, import_react9.useLayoutEffect)(() => {
1445
2018
  measure();
1446
2019
  }, [measure]);
1447
- (0, import_react7.useEffect)(() => {
2020
+ (0, import_react9.useEffect)(() => {
1448
2021
  const table = tableRef.current;
1449
2022
  if (!table) return;
1450
2023
  const ro = new ResizeObserver(() => measure());
1451
2024
  ro.observe(table);
1452
2025
  return () => ro.disconnect();
1453
2026
  }, [measure, tableRef]);
1454
- const onPointerDown = (0, import_react7.useCallback)(
2027
+ const onPointerDown = (0, import_react9.useCallback)(
1455
2028
  (col) => (e) => {
1456
2029
  e.preventDefault();
1457
2030
  e.stopPropagation();
@@ -1465,7 +2038,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1465
2038
  },
1466
2039
  [layout, tableRef]
1467
2040
  );
1468
- const onPointerMove = (0, import_react7.useCallback)(
2041
+ const onPointerMove = (0, import_react9.useCallback)(
1469
2042
  (e) => {
1470
2043
  const d = draggingRef.current;
1471
2044
  if (!d) return;
@@ -1475,7 +2048,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1475
2048
  },
1476
2049
  [blockIndex, editor]
1477
2050
  );
1478
- const onPointerUp = (0, import_react7.useCallback)((e) => {
2051
+ const onPointerUp = (0, import_react9.useCallback)((e) => {
1479
2052
  draggingRef.current = null;
1480
2053
  setPositions(null);
1481
2054
  try {
@@ -1494,7 +2067,7 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1494
2067
  zIndex: 5
1495
2068
  });
1496
2069
  void positions;
1497
- 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)(
1498
2071
  "div",
1499
2072
  {
1500
2073
  contentEditable: false,
@@ -1511,10 +2084,10 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
1511
2084
  }
1512
2085
 
1513
2086
  // src/NodeView.tsx
1514
- var import_jsx_runtime8 = require("react/jsx-runtime");
2087
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1515
2088
  function NodeView({ block, index, children, fragment, tableFragment }) {
1516
2089
  if (block.type === "table") {
1517
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableView, { block, index, tableFragment });
2090
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TableView, { block, index, tableFragment });
1518
2091
  }
1519
2092
  const inline = fragment ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index) : renderInline(block.delta, index);
1520
2093
  const common = commonBlockProps(block.attrs, index, block.type, fragment);
@@ -1522,7 +2095,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1522
2095
  case "heading": {
1523
2096
  const level = clampLevel(block.attrs.level);
1524
2097
  const Tag = `h${level}`;
1525
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2098
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1526
2099
  Tag,
1527
2100
  {
1528
2101
  ...common,
@@ -1532,7 +2105,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1532
2105
  );
1533
2106
  }
1534
2107
  case "blockquote":
1535
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2108
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1536
2109
  "blockquote",
1537
2110
  {
1538
2111
  ...common,
@@ -1541,18 +2114,18 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1541
2114
  }
1542
2115
  );
1543
2116
  case "codeBlock":
1544
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1545
2118
  "pre",
1546
2119
  {
1547
2120
  ...common,
1548
2121
  "data-language": block.attrs.language ?? void 0,
1549
2122
  className: `ed-block ed-codeblock${alignClass(block.attrs.align)}`,
1550
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: inline })
2123
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: inline })
1551
2124
  }
1552
2125
  );
1553
2126
  case "listItem": {
1554
2127
  const level = clampListLevel(block.attrs.listLevel);
1555
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2128
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1556
2129
  "li",
1557
2130
  {
1558
2131
  ...common,
@@ -1568,7 +2141,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
1568
2141
  }
1569
2142
  case "paragraph":
1570
2143
  default:
1571
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2144
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1572
2145
  "div",
1573
2146
  {
1574
2147
  ...common,
@@ -1613,18 +2186,18 @@ function TableView({ block, index, tableFragment }) {
1613
2186
  const cols = clampPositive(block.attrs.cols);
1614
2187
  const cells = block.cells ?? [];
1615
2188
  const widths = readColWidths(block.attrs.colWidths, cols);
1616
- const tableRef = (0, import_react8.useRef)(null);
2189
+ const tableRef = (0, import_react10.useRef)(null);
1617
2190
  const rowStart = tableFragment?.rowStart ?? 0;
1618
2191
  const rowEnd = tableFragment?.rowEnd ?? rows;
1619
2192
  const isFirstFragment = !tableFragment || tableFragment.index === 0;
1620
2193
  const editor = useEditorContext();
1621
- const rect = (0, import_react8.useMemo)(() => {
2194
+ const rect = (0, import_react10.useMemo)(() => {
1622
2195
  if (editor.selection.anchor.blockIndex !== index) return null;
1623
2196
  if (editor.selection.focus.blockIndex !== index) return null;
1624
- return (0, import_core3.tableRectSelection)(editor.doc, editor.selection);
2197
+ return (0, import_core4.tableRectSelection)(editor.doc, editor.selection);
1625
2198
  }, [editor.doc, editor.selection, index]);
1626
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ed-table-wrap", children: [
1627
- /* @__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)(
1628
2201
  "table",
1629
2202
  {
1630
2203
  ref: tableRef,
@@ -1632,10 +2205,10 @@ function TableView({ block, index, tableFragment }) {
1632
2205
  "data-block-type": "table",
1633
2206
  className: "ed-block ed-table",
1634
2207
  children: [
1635
- 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)) }),
1636
- /* @__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) => {
1637
2210
  const r = rowStart + i;
1638
- 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) => {
1639
2212
  const flat = r * cols + c;
1640
2213
  const cell = cells[flat];
1641
2214
  if (cell?.attrs.covered === true) return null;
@@ -1643,7 +2216,7 @@ function TableView({ block, index, tableFragment }) {
1643
2216
  const colspan = spanAttr(cell?.attrs.colspan);
1644
2217
  const delta = cell?.delta ?? [];
1645
2218
  const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
1646
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2219
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1647
2220
  "td",
1648
2221
  {
1649
2222
  "data-cell-index": flat,
@@ -1653,6 +2226,7 @@ function TableView({ block, index, tableFragment }) {
1653
2226
  "data-cell-colspan": colspan,
1654
2227
  rowSpan: rowspan > 1 ? rowspan : void 0,
1655
2228
  colSpan: colspan > 1 ? colspan : void 0,
2229
+ style: cell?.attrs.align ? { textAlign: cell.attrs.align } : void 0,
1656
2230
  className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
1657
2231
  children: renderInline(delta, `t${index}-c${flat}`)
1658
2232
  },
@@ -1663,7 +2237,7 @@ function TableView({ block, index, tableFragment }) {
1663
2237
  ]
1664
2238
  }
1665
2239
  ),
1666
- 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 })
1667
2241
  ] });
1668
2242
  }
1669
2243
  function readColWidths(raw, cols) {
@@ -1685,7 +2259,7 @@ function clampPositive(n) {
1685
2259
  }
1686
2260
 
1687
2261
  // src/usePagination.ts
1688
- var import_react9 = require("react");
2262
+ var import_react11 = require("react");
1689
2263
  var A4_PAGE = {
1690
2264
  width: 794,
1691
2265
  height: 1123,
@@ -1711,10 +2285,10 @@ function defaultPageLayout(topLevelCount) {
1711
2285
  };
1712
2286
  }
1713
2287
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1714
- const [phase, setPhase] = (0, import_react9.useState)("measure");
1715
- const [layout, setLayout] = (0, import_react9.useState)(() => defaultPageLayout(topLevelCount));
1716
- const lastDepsRef = (0, import_react9.useRef)(null);
1717
- (0, import_react9.useLayoutEffect)(() => {
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)(() => {
1718
2292
  const currentDeps = [...deps, topLevelCount, geometry];
1719
2293
  if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
1720
2294
  return;
@@ -1726,7 +2300,7 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1726
2300
  });
1727
2301
  setPhase("measure");
1728
2302
  });
1729
- (0, import_react9.useLayoutEffect)(() => {
2303
+ (0, import_react11.useLayoutEffect)(() => {
1730
2304
  if (phase !== "measure") return;
1731
2305
  const root = rootRef.current;
1732
2306
  if (!root) return;
@@ -2198,48 +2772,48 @@ function layoutsDeepEqual(a, b) {
2198
2772
  }
2199
2773
 
2200
2774
  // src/useEditor.ts
2201
- var import_react11 = require("react");
2775
+ var import_react13 = require("react");
2202
2776
 
2203
2777
  // src/usePageSettings.ts
2204
- var import_react10 = require("react");
2778
+ var import_react12 = require("react");
2205
2779
  function usePageSettings(doc) {
2206
- const cacheRef = (0, import_react10.useRef)(null);
2207
- const subscribe = (0, import_react10.useCallback)(
2780
+ const cacheRef = (0, import_react12.useRef)(null);
2781
+ const subscribe = (0, import_react12.useCallback)(
2208
2782
  (notify) => doc.observePageSettings(notify),
2209
2783
  [doc]
2210
2784
  );
2211
- const getSnapshot = (0, import_react10.useCallback)(() => {
2785
+ const getSnapshot = (0, import_react12.useCallback)(() => {
2212
2786
  const next = doc.getPageSettings();
2213
2787
  const prev = cacheRef.current;
2214
2788
  if (prev && shallowEqual(prev, next)) return prev;
2215
2789
  cacheRef.current = next;
2216
2790
  return next;
2217
2791
  }, [doc]);
2218
- return (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
2792
+ return (0, import_react12.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
2219
2793
  }
2220
2794
  function shallowEqual(a, b) {
2221
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;
2222
2796
  }
2223
2797
 
2224
2798
  // src/useEditor.ts
2225
- var import_core4 = require("@sofereditor/core");
2799
+ var import_core5 = require("@sofereditor/core");
2226
2800
  var MAX_INSERT_WIDTH = 600;
2227
2801
  function useEditor(opts = {}) {
2228
- const doc = (0, import_react11.useMemo)(() => opts.document ?? new import_core4.EditorDocument(), [opts.document]);
2229
- const history = (0, import_react11.useMemo)(() => new import_core4.EditorHistory(doc), [doc]);
2230
- const [snapshot, setSnapshot] = (0, import_react11.useState)(() => doc.toJSON());
2231
- const [selection, setSelectionState] = (0, import_react11.useState)(
2232
- () => (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 })
2233
2807
  );
2234
- const selectionRef = (0, import_react11.useRef)(selection);
2808
+ const selectionRef = (0, import_react13.useRef)(selection);
2235
2809
  selectionRef.current = selection;
2236
- const pendingMarksRef = (0, import_react11.useRef)({});
2237
- const [pendingMarks, setPendingMarksState] = (0, import_react11.useState)({});
2238
- 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) => {
2239
2813
  pendingMarksRef.current = next;
2240
2814
  setPendingMarksState(next);
2241
2815
  }, []);
2242
- (0, import_react11.useEffect)(() => {
2816
+ (0, import_react13.useEffect)(() => {
2243
2817
  let scheduled = false;
2244
2818
  let cancelled = false;
2245
2819
  let frame = 0;
@@ -2266,8 +2840,8 @@ function useEditor(opts = {}) {
2266
2840
  doc.ydoc.off("afterTransaction", schedule);
2267
2841
  };
2268
2842
  }, [doc]);
2269
- const getSelection = (0, import_react11.useCallback)(() => selectionRef.current, []);
2270
- const setSelection = (0, import_react11.useCallback)(
2843
+ const getSelection = (0, import_react13.useCallback)(() => selectionRef.current, []);
2844
+ const setSelection = (0, import_react13.useCallback)(
2271
2845
  (sel) => {
2272
2846
  const prev = selectionRef.current;
2273
2847
  selectionRef.current = sel;
@@ -2282,19 +2856,19 @@ function useEditor(opts = {}) {
2282
2856
  },
2283
2857
  []
2284
2858
  );
2285
- const ctxRef = (0, import_react11.useRef)({ doc, getSelection, setSelection });
2859
+ const ctxRef = (0, import_react13.useRef)({ doc, getSelection, setSelection });
2286
2860
  ctxRef.current = { doc, getSelection, setSelection };
2287
- const consumePendingMarks = (0, import_react11.useCallback)(() => {
2861
+ const consumePendingMarks = (0, import_react13.useCallback)(() => {
2288
2862
  const current = pendingMarksRef.current;
2289
2863
  if (Object.keys(current).length === 0) return void 0;
2290
2864
  pendingMarksRef.current = {};
2291
2865
  setPendingMarksState({});
2292
2866
  return current;
2293
2867
  }, []);
2294
- const isMarkActive = (0, import_react11.useCallback)(
2868
+ const isMarkActive = (0, import_react13.useCallback)(
2295
2869
  (name, value) => {
2296
2870
  const sel = selectionRef.current;
2297
- const { start, end } = (0, import_core4.orderedRange)(sel);
2871
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2298
2872
  if (start.blockIndex === end.blockIndex && start.offset === end.offset) {
2299
2873
  const pending = pendingMarksRef.current[name];
2300
2874
  if (pending !== void 0) {
@@ -2303,7 +2877,7 @@ function useEditor(opts = {}) {
2303
2877
  }
2304
2878
  const yText2 = doc.getBlockText(start.blockIndex);
2305
2879
  if (!yText2 || start.offset === 0) return false;
2306
- 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);
2307
2881
  }
2308
2882
  if (start.blockIndex !== end.blockIndex) {
2309
2883
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
@@ -2312,19 +2886,19 @@ function useEditor(opts = {}) {
2312
2886
  const s = i === start.blockIndex ? start.offset : 0;
2313
2887
  const e = i === end.blockIndex ? end.offset : yText2.length;
2314
2888
  if (s >= e) continue;
2315
- 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;
2316
2890
  }
2317
2891
  return true;
2318
2892
  }
2319
2893
  const yText = doc.getBlockText(start.blockIndex);
2320
2894
  if (!yText) return false;
2321
- 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);
2322
2896
  },
2323
2897
  [doc]
2324
2898
  );
2325
- const getActiveMarks = (0, import_react11.useCallback)(() => {
2899
+ const getActiveMarks = (0, import_react13.useCallback)(() => {
2326
2900
  const sel = selectionRef.current;
2327
- const { start, end } = (0, import_core4.orderedRange)(sel);
2901
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2328
2902
  if (start.blockIndex !== end.blockIndex) {
2329
2903
  return {};
2330
2904
  }
@@ -2332,14 +2906,14 @@ function useEditor(opts = {}) {
2332
2906
  if (!yText) return {};
2333
2907
  if (start.offset === end.offset) {
2334
2908
  if (start.offset === 0) return {};
2335
- return (0, import_core4.getMarksInRange)(yText, start.offset - 1, start.offset);
2909
+ return (0, import_core5.getMarksInRange)(yText, start.offset - 1, start.offset);
2336
2910
  }
2337
- return (0, import_core4.getMarksInRange)(yText, start.offset, end.offset);
2911
+ return (0, import_core5.getMarksInRange)(yText, start.offset, end.offset);
2338
2912
  }, [doc]);
2339
- const toggleMark = (0, import_react11.useCallback)(
2913
+ const toggleMark = (0, import_react13.useCallback)(
2340
2914
  (name, value) => {
2341
2915
  const sel = selectionRef.current;
2342
- const { start, end } = (0, import_core4.orderedRange)(sel);
2916
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2343
2917
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2344
2918
  if (isCollapsed) {
2345
2919
  const next = { ...pendingMarksRef.current };
@@ -2352,39 +2926,39 @@ function useEditor(opts = {}) {
2352
2926
  setPendingMarks(next);
2353
2927
  return;
2354
2928
  }
2355
- (0, import_core4.toggleMark)(ctxRef.current, name, value);
2929
+ (0, import_core5.toggleMark)(ctxRef.current, name, value);
2356
2930
  },
2357
2931
  [isMarkActive, setPendingMarks]
2358
2932
  );
2359
- const setMark = (0, import_react11.useCallback)(
2933
+ const setMark = (0, import_react13.useCallback)(
2360
2934
  (name, value) => {
2361
2935
  const sel = selectionRef.current;
2362
- const { start, end } = (0, import_core4.orderedRange)(sel);
2936
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2363
2937
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2364
2938
  if (isCollapsed) {
2365
2939
  setPendingMarks({ ...pendingMarksRef.current, [name]: value });
2366
2940
  return;
2367
2941
  }
2368
- (0, import_core4.setMark)(ctxRef.current, name, value);
2942
+ (0, import_core5.setMark)(ctxRef.current, name, value);
2369
2943
  },
2370
2944
  [setPendingMarks]
2371
2945
  );
2372
- const removeMark = (0, import_react11.useCallback)(
2946
+ const removeMark = (0, import_react13.useCallback)(
2373
2947
  (name) => {
2374
2948
  const sel = selectionRef.current;
2375
- const { start, end } = (0, import_core4.orderedRange)(sel);
2949
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2376
2950
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
2377
2951
  if (isCollapsed) {
2378
2952
  setPendingMarks({ ...pendingMarksRef.current, [name]: null });
2379
2953
  return;
2380
2954
  }
2381
- (0, import_core4.removeMark)(ctxRef.current, name);
2955
+ (0, import_core5.removeMark)(ctxRef.current, name);
2382
2956
  },
2383
2957
  [setPendingMarks]
2384
2958
  );
2385
- const getBlockType = (0, import_react11.useCallback)(() => {
2959
+ const getBlockType = (0, import_react13.useCallback)(() => {
2386
2960
  const sel = selectionRef.current;
2387
- const { start, end } = (0, import_core4.orderedRange)(sel);
2961
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2388
2962
  const first = doc.getBlockType(start.blockIndex);
2389
2963
  if (first === void 0) return "paragraph";
2390
2964
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
@@ -2392,10 +2966,10 @@ function useEditor(opts = {}) {
2392
2966
  }
2393
2967
  return first;
2394
2968
  }, [doc]);
2395
- const getBlockAttr = (0, import_react11.useCallback)(
2969
+ const getBlockAttr = (0, import_react13.useCallback)(
2396
2970
  (key) => {
2397
2971
  const sel = selectionRef.current;
2398
- const { start, end } = (0, import_core4.orderedRange)(sel);
2972
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2399
2973
  const first = doc.getBlockAttrs(start.blockIndex)[key];
2400
2974
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
2401
2975
  const next = doc.getBlockAttrs(i)[key];
@@ -2405,19 +2979,32 @@ function useEditor(opts = {}) {
2405
2979
  },
2406
2980
  [doc]
2407
2981
  );
2408
- const setBlockType = (0, import_react11.useCallback)((type, attrs) => {
2409
- (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);
2410
2984
  }, []);
2411
- const setBlockAttr = (0, import_react11.useCallback)(
2985
+ const setBlockAttr = (0, import_react13.useCallback)(
2412
2986
  (key, value) => {
2413
- (0, import_core4.setBlockAttr)(ctxRef.current, key, value);
2987
+ (0, import_core5.setBlockAttr)(ctxRef.current, key, value);
2414
2988
  },
2415
2989
  []
2416
2990
  );
2417
- 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)(
2418
3005
  (kind) => {
2419
3006
  const sel = selectionRef.current;
2420
- const { start, end } = (0, import_core4.orderedRange)(sel);
3007
+ const { start, end } = (0, import_core5.orderedRange)(sel);
2421
3008
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
2422
3009
  if (doc.getBlockType(i) !== "listItem") return false;
2423
3010
  if (doc.getBlockAttrs(i).listKind !== kind) return false;
@@ -2426,110 +3013,116 @@ function useEditor(opts = {}) {
2426
3013
  },
2427
3014
  [doc]
2428
3015
  );
2429
- const toggleList = (0, import_react11.useCallback)((kind) => {
2430
- (0, import_core4.toggleList)(ctxRef.current, kind);
3016
+ const toggleList = (0, import_react13.useCallback)((kind) => {
3017
+ (0, import_core5.toggleList)(ctxRef.current, kind);
2431
3018
  }, []);
2432
- const indentList = (0, import_react11.useCallback)(() => {
2433
- (0, import_core4.indentList)(ctxRef.current);
3019
+ const indentList = (0, import_react13.useCallback)(() => {
3020
+ (0, import_core5.indentList)(ctxRef.current);
2434
3021
  }, []);
2435
- const dedentList = (0, import_react11.useCallback)(() => {
2436
- (0, import_core4.dedentList)(ctxRef.current);
3022
+ const dedentList = (0, import_react13.useCallback)(() => {
3023
+ (0, import_core5.dedentList)(ctxRef.current);
2437
3024
  }, []);
2438
- const splitListItem = (0, import_react11.useCallback)(() => {
2439
- return (0, import_core4.splitListItem)(ctxRef.current);
3025
+ const splitListItem = (0, import_react13.useCallback)(() => {
3026
+ return (0, import_core5.splitListItem)(ctxRef.current);
2440
3027
  }, []);
2441
- const isInTable = (0, import_react11.useCallback)(() => {
3028
+ const isInTable = (0, import_react13.useCallback)(() => {
2442
3029
  return selectionRef.current.focus.cellIndex != null;
2443
3030
  }, []);
2444
- const getTableLocation = (0, import_react11.useCallback)(() => {
2445
- 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);
2446
3033
  }, [doc]);
2447
- const insertTable = (0, import_react11.useCallback)((rows, cols) => {
2448
- (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);
2449
3036
  }, []);
2450
- const deleteTable = (0, import_react11.useCallback)((blockIndex) => {
3037
+ const deleteTable = (0, import_react13.useCallback)((blockIndex) => {
2451
3038
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
2452
- (0, import_core4.deleteTable)(ctxRef.current, idx);
3039
+ (0, import_core5.deleteTable)(ctxRef.current, idx);
2453
3040
  }, []);
2454
- const insertRowAbove = (0, import_react11.useCallback)(() => {
2455
- 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);
2456
3043
  if (!loc) return;
2457
- (0, import_core4.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
3044
+ (0, import_core5.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
2458
3045
  }, [doc]);
2459
- const insertRowBelow = (0, import_react11.useCallback)(() => {
2460
- 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);
2461
3048
  if (!loc) return;
2462
- (0, import_core4.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
3049
+ (0, import_core5.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
2463
3050
  }, [doc]);
2464
- const deleteCurrentRow = (0, import_react11.useCallback)(() => {
2465
- 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);
2466
3053
  if (!loc) return;
2467
- (0, import_core4.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
3054
+ (0, import_core5.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
2468
3055
  }, [doc]);
2469
- const insertColumnLeft = (0, import_react11.useCallback)(() => {
2470
- 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);
2471
3058
  if (!loc) return;
2472
- (0, import_core4.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
3059
+ (0, import_core5.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
2473
3060
  }, [doc]);
2474
- const insertColumnRight = (0, import_react11.useCallback)(() => {
2475
- 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);
2476
3063
  if (!loc) return;
2477
- (0, import_core4.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
3064
+ (0, import_core5.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
2478
3065
  }, [doc]);
2479
- const deleteCurrentColumn = (0, import_react11.useCallback)(() => {
2480
- 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);
2481
3068
  if (!loc) return;
2482
- (0, import_core4.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
3069
+ (0, import_core5.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
2483
3070
  }, [doc]);
2484
- const moveToNextCell = (0, import_react11.useCallback)(() => {
2485
- (0, import_core4.moveToNextCell)(ctxRef.current);
3071
+ const moveToNextCell = (0, import_react13.useCallback)(() => {
3072
+ (0, import_core5.moveToNextCell)(ctxRef.current);
2486
3073
  }, []);
2487
- const moveToPrevCell = (0, import_react11.useCallback)(() => {
2488
- (0, import_core4.moveToPrevCell)(ctxRef.current);
3074
+ const moveToPrevCell = (0, import_react13.useCallback)(() => {
3075
+ (0, import_core5.moveToPrevCell)(ctxRef.current);
2489
3076
  }, []);
2490
- const mergeRight = (0, import_react11.useCallback)(() => {
2491
- 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);
2492
3079
  if (!loc) return false;
2493
- 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);
2494
3081
  }, [doc]);
2495
- const mergeDown = (0, import_react11.useCallback)(() => {
2496
- 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);
2497
3084
  if (!loc) return false;
2498
- 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);
2499
3086
  }, [doc]);
2500
- const splitCell = (0, import_react11.useCallback)(() => {
2501
- 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);
2502
3089
  if (!loc) return false;
2503
- 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);
2504
3091
  }, [doc]);
2505
- const setColumnWidth = (0, import_react11.useCallback)(
3092
+ const setColumnWidth = (0, import_react13.useCallback)(
2506
3093
  (blockIndex, col, widthPx) => {
2507
- (0, import_core4.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
3094
+ (0, import_core5.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
2508
3095
  },
2509
3096
  []
2510
3097
  );
2511
- const getTableRect = (0, import_react11.useCallback)(
2512
- () => (0, import_core4.tableRectSelection)(doc, selectionRef.current),
3098
+ const getTableRect = (0, import_react13.useCallback)(
3099
+ () => (0, import_core5.tableRectSelection)(doc, selectionRef.current),
2513
3100
  [doc]
2514
3101
  );
2515
- const hasTableRectSelection = (0, import_react11.useCallback)(() => {
2516
- 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;
2517
3104
  }, [doc]);
2518
- const mergeSelection = (0, import_react11.useCallback)(() => {
2519
- return (0, import_core4.mergeSelection)(ctxRef.current);
3105
+ const mergeSelection = (0, import_react13.useCallback)(() => {
3106
+ return (0, import_core5.mergeSelection)(ctxRef.current);
2520
3107
  }, []);
2521
- const insertImage = (0, import_react11.useCallback)((embed) => {
2522
- (0, import_core4.insertImage)(ctxRef.current, embed);
3108
+ const insertImage = (0, import_react13.useCallback)((embed) => {
3109
+ (0, import_core5.insertImage)(ctxRef.current, embed);
2523
3110
  }, []);
2524
- const setImageAttrs = (0, import_react11.useCallback)(
3111
+ const setImageAttrs = (0, import_react13.useCallback)(
2525
3112
  (blockIndex, offset, partial, cellIndex, newOffset) => {
2526
- (0, import_core4.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3113
+ (0, import_core5.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
2527
3114
  },
2528
3115
  []
2529
3116
  );
2530
- const uploadImageRef = (0, import_react11.useRef)(opts.uploadImage);
3117
+ const moveEmbedAnchor = (0, import_react13.useCallback)(
3118
+ (from, to, newOffsetX, newOffsetY) => {
3119
+ (0, import_core5.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
3120
+ },
3121
+ []
3122
+ );
3123
+ const uploadImageRef = (0, import_react13.useRef)(opts.uploadImage);
2531
3124
  uploadImageRef.current = opts.uploadImage;
2532
- const insertImageFromFile = (0, import_react11.useCallback)(async (file) => {
3125
+ const insertImageFromFile = (0, import_react13.useCallback)(async (file) => {
2533
3126
  if (!file.type.startsWith("image/")) return;
2534
3127
  const dataUrl = await readAsDataURL(file);
2535
3128
  const dims = await readImageDimensions(dataUrl);
@@ -2541,9 +3134,9 @@ function useEditor(opts = {}) {
2541
3134
  }
2542
3135
  const upload = uploadImageRef.current;
2543
3136
  const src = upload ? await upload(file) : dataUrl;
2544
- (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 });
2545
3138
  }, []);
2546
- const getSelectedEmbed = (0, import_react11.useCallback)(() => {
3139
+ const getSelectedEmbed = (0, import_react13.useCallback)(() => {
2547
3140
  const sel = selectionRef.current;
2548
3141
  if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;
2549
3142
  if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;
@@ -2560,7 +3153,7 @@ function useEditor(opts = {}) {
2560
3153
  cursor += op.insert.length;
2561
3154
  continue;
2562
3155
  }
2563
- if (cursor === start && (0, import_core4.isImageEmbed)(op.insert)) {
3156
+ if (cursor === start && (0, import_core5.isImageEmbed)(op.insert)) {
2564
3157
  return {
2565
3158
  blockIndex: sel.anchor.blockIndex,
2566
3159
  cellIndex: sel.anchor.cellIndex,
@@ -2572,39 +3165,48 @@ function useEditor(opts = {}) {
2572
3165
  }
2573
3166
  return null;
2574
3167
  }, [doc]);
2575
- const [linkRequest, setLinkRequest] = (0, import_react11.useState)(null);
2576
- 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 = "") => {
2577
3171
  return new Promise((resolve) => {
2578
- setLinkRequest({ initialHref, resolve });
2579
- });
2580
- }, []);
2581
- const resolveLinkRequest = (0, import_react11.useCallback)((href) => {
2582
- setLinkRequest((prev) => {
2583
- if (prev) prev.resolve(href);
2584
- return null;
3172
+ const req = { initialHref, resolve, selection: selectionRef.current };
3173
+ linkRequestRef.current = req;
3174
+ setLinkRequest(req);
2585
3175
  });
2586
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
+ );
2587
3189
  const pageSettings = usePageSettings(doc);
2588
- const setPageSettings = (0, import_react11.useCallback)(
3190
+ const setPageSettings = (0, import_react13.useCallback)(
2589
3191
  (partial) => {
2590
3192
  doc.setPageSettings(partial);
2591
3193
  },
2592
3194
  [doc]
2593
3195
  );
2594
- const [pageConfigRequest, setPageConfigRequest] = (0, import_react11.useState)(null);
2595
- const requestPageConfig = (0, import_react11.useCallback)(() => {
3196
+ const [pageConfigRequest, setPageConfigRequest] = (0, import_react13.useState)(null);
3197
+ const requestPageConfig = (0, import_react13.useCallback)(() => {
2596
3198
  return new Promise((resolve) => {
2597
3199
  setPageConfigRequest({ initial: doc.getPageSettings(), resolve });
2598
3200
  });
2599
3201
  }, [doc]);
2600
- const resolvePageConfigRequest = (0, import_react11.useCallback)((applied) => {
3202
+ const resolvePageConfigRequest = (0, import_react13.useCallback)((applied) => {
2601
3203
  setPageConfigRequest((prev) => {
2602
3204
  if (prev) prev.resolve(applied);
2603
3205
  return null;
2604
3206
  });
2605
3207
  }, []);
2606
- const [imageCaptionRequest, setImageCaptionRequest] = (0, import_react11.useState)(null);
2607
- const requestImageCaption = (0, import_react11.useCallback)(
3208
+ const [imageCaptionRequest, setImageCaptionRequest] = (0, import_react13.useState)(null);
3209
+ const requestImageCaption = (0, import_react13.useCallback)(
2608
3210
  (initialCaption = "", initialAlign = "center") => {
2609
3211
  return new Promise((resolve) => {
2610
3212
  setImageCaptionRequest({ initialCaption, initialAlign, resolve });
@@ -2612,7 +3214,7 @@ function useEditor(opts = {}) {
2612
3214
  },
2613
3215
  []
2614
3216
  );
2615
- const resolveImageCaptionRequest = (0, import_react11.useCallback)((result) => {
3217
+ const resolveImageCaptionRequest = (0, import_react13.useCallback)((result) => {
2616
3218
  setImageCaptionRequest((prev) => {
2617
3219
  if (prev) prev.resolve(result);
2618
3220
  return null;
@@ -2636,6 +3238,8 @@ function useEditor(opts = {}) {
2636
3238
  getBlockAttr,
2637
3239
  setBlockType,
2638
3240
  setBlockAttr,
3241
+ setAlign,
3242
+ getAlign,
2639
3243
  isListActive,
2640
3244
  toggleList,
2641
3245
  indentList,
@@ -2665,6 +3269,7 @@ function useEditor(opts = {}) {
2665
3269
  mergeSelection,
2666
3270
  insertImage,
2667
3271
  setImageAttrs,
3272
+ moveEmbedAnchor,
2668
3273
  insertImageFromFile,
2669
3274
  getSelectedEmbed,
2670
3275
  pageSettings,
@@ -2706,54 +3311,99 @@ function sameValue(a, b) {
2706
3311
  }
2707
3312
 
2708
3313
  // src/Editor.tsx
2709
- var import_jsx_runtime9 = require("react/jsx-runtime");
3314
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2710
3315
  var defaultFooter = ({ pageNumber, pageCount }) => `${pageNumber} / ${pageCount}`;
2711
3316
  function Editor({
2712
3317
  editor: providedEditor,
2713
3318
  className,
2714
3319
  pageGeometry,
2715
3320
  renderPageHeader,
2716
- renderPageFooter = defaultFooter
3321
+ renderPageFooter = defaultFooter,
3322
+ awareness
2717
3323
  }) {
2718
3324
  const internal = useEditor();
2719
3325
  const editor = providedEditor ?? internal;
2720
3326
  const { doc, history, snapshot, getSelection, setSelection } = editor;
2721
- const rootRef = (0, import_react12.useRef)(null);
2722
- const isComposingRef = (0, import_react12.useRef)(false);
2723
- const suppressSelectionSyncRef = (0, import_react12.useRef)(false);
2724
- 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 });
2725
3365
  ctxRef.current = { doc, getSelection, setSelection };
2726
- const historyRef = (0, import_react12.useRef)(history);
3366
+ const historyRef = (0, import_react14.useRef)(history);
2727
3367
  historyRef.current = history;
2728
- const editorRef = (0, import_react12.useRef)(editor);
3368
+ const editorRef = (0, import_react14.useRef)(editor);
2729
3369
  editorRef.current = editor;
2730
- (0, import_react12.useLayoutEffect)(() => {
3370
+ (0, import_react14.useLayoutEffect)(() => {
2731
3371
  const root = rootRef.current;
2732
3372
  if (!root) return;
2733
3373
  if (isComposingRef.current) return;
2734
3374
  if (document.activeElement !== root) return;
2735
3375
  const current = readDomSelection(root);
2736
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
+ }
2737
3382
  suppressSelectionSyncRef.current = true;
2738
3383
  applyDomSelection(root, editor.selection);
2739
- queueMicrotask(() => {
2740
- suppressSelectionSyncRef.current = false;
2741
- });
2742
3384
  });
2743
- (0, import_react12.useEffect)(() => {
3385
+ (0, import_react14.useEffect)(() => {
2744
3386
  const root = rootRef.current;
2745
3387
  if (!root) return;
2746
3388
  const handler = () => {
2747
- if (suppressSelectionSyncRef.current) return;
2748
3389
  if (isComposingRef.current) return;
2749
- if (document.activeElement !== root) return;
3390
+ if (document.activeElement !== root) {
3391
+ suppressSelectionSyncRef.current = false;
3392
+ return;
3393
+ }
2750
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
+ }
2751
3401
  if (modelSel) setSelection(modelSel);
2752
3402
  };
2753
3403
  document.addEventListener("selectionchange", handler);
2754
3404
  return () => document.removeEventListener("selectionchange", handler);
2755
3405
  }, [setSelection]);
2756
- (0, import_react12.useEffect)(() => {
3406
+ (0, import_react14.useEffect)(() => {
2757
3407
  const root = rootRef.current;
2758
3408
  if (!root) return;
2759
3409
  let drag = null;
@@ -2824,7 +3474,7 @@ function Editor({
2824
3474
  document.removeEventListener("pointerup", onPointerUp);
2825
3475
  };
2826
3476
  }, []);
2827
- (0, import_react12.useEffect)(() => {
3477
+ (0, import_react14.useEffect)(() => {
2828
3478
  const root = rootRef.current;
2829
3479
  if (!root) return;
2830
3480
  const onDragOver = (e) => {
@@ -2862,7 +3512,7 @@ function Editor({
2862
3512
  root.removeEventListener("drop", onDrop);
2863
3513
  };
2864
3514
  }, []);
2865
- (0, import_react12.useEffect)(() => {
3515
+ (0, import_react14.useEffect)(() => {
2866
3516
  const root = rootRef.current;
2867
3517
  if (!root) return;
2868
3518
  const onPointerDown = (e) => {
@@ -2890,7 +3540,95 @@ function Editor({
2890
3540
  root.addEventListener("pointerdown", onPointerDown);
2891
3541
  return () => root.removeEventListener("pointerdown", onPointerDown);
2892
3542
  }, []);
2893
- (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)(() => {
2894
3632
  const root = rootRef.current;
2895
3633
  if (!root) return;
2896
3634
  const handler = (e) => {
@@ -2904,14 +3642,14 @@ function Editor({
2904
3642
  const data = e.data ?? "";
2905
3643
  if (data.length > 0) {
2906
3644
  e.preventDefault();
2907
- (0, import_core5.insertText)(ctx, data, ed.consumePendingMarks());
3645
+ (0, import_core6.insertText)(ctx, data, ed.consumePendingMarks());
2908
3646
  }
2909
3647
  return;
2910
3648
  }
2911
3649
  case "insertLineBreak": {
2912
3650
  e.preventDefault();
2913
3651
  if (ed.getBlockType() === "listItem") {
2914
- (0, import_core5.insertText)(ctx, "\n", ed.consumePendingMarks());
3652
+ (0, import_core6.insertText)(ctx, "\n", ed.consumePendingMarks());
2915
3653
  return;
2916
3654
  }
2917
3655
  const selEmbed = ed.getSelectedEmbed();
@@ -2931,7 +3669,7 @@ function Editor({
2931
3669
  });
2932
3670
  }
2933
3671
  if (ed.splitListItem()) return;
2934
- (0, import_core5.insertParagraph)(ctx);
3672
+ (0, import_core6.insertParagraph)(ctx);
2935
3673
  return;
2936
3674
  }
2937
3675
  case "insertParagraph": {
@@ -2953,35 +3691,19 @@ function Editor({
2953
3691
  });
2954
3692
  }
2955
3693
  if (ed.splitListItem()) return;
2956
- (0, import_core5.insertParagraph)(ctx);
3694
+ (0, import_core6.insertParagraph)(ctx);
2957
3695
  return;
2958
3696
  }
2959
3697
  case "insertReplacementText": {
2960
3698
  const text = e.data ?? e.dataTransfer?.getData("text/plain") ?? "";
2961
3699
  if (text.length > 0) {
2962
3700
  e.preventDefault();
2963
- (0, import_core5.insertText)(ctx, text, ed.consumePendingMarks());
3701
+ (0, import_core6.insertText)(ctx, text, ed.consumePendingMarks());
2964
3702
  }
2965
3703
  return;
2966
3704
  }
2967
3705
  case "insertFromPaste": {
2968
3706
  e.preventDefault();
2969
- const images = Array.from(e.dataTransfer?.files ?? []).filter(
2970
- (f) => f.type.startsWith("image/")
2971
- );
2972
- if (images.length > 0) {
2973
- void (async () => {
2974
- for (const f of images) await editorRef.current.insertImageFromFile(f);
2975
- })();
2976
- return;
2977
- }
2978
- const text = e.dataTransfer?.getData("text/plain") ?? "";
2979
- if (text.length === 0) return;
2980
- const lines = text.split(/\r\n|\r|\n/);
2981
- lines.forEach((line, i) => {
2982
- if (i > 0) (0, import_core5.insertParagraph)(ctx);
2983
- if (line.length > 0) (0, import_core5.insertText)(ctx, line);
2984
- });
2985
3707
  return;
2986
3708
  }
2987
3709
  case "deleteContentBackward":
@@ -2989,7 +3711,7 @@ function Editor({
2989
3711
  case "deleteSoftLineBackward":
2990
3712
  case "deleteHardLineBackward": {
2991
3713
  e.preventDefault();
2992
- (0, import_core5.deleteBackward)(ctx);
3714
+ (0, import_core6.deleteBackward)(ctx);
2993
3715
  return;
2994
3716
  }
2995
3717
  case "deleteContentForward":
@@ -2997,7 +3719,7 @@ function Editor({
2997
3719
  case "deleteSoftLineForward":
2998
3720
  case "deleteHardLineForward": {
2999
3721
  e.preventDefault();
3000
- (0, import_core5.deleteForward)(ctx);
3722
+ (0, import_core6.deleteForward)(ctx);
3001
3723
  return;
3002
3724
  }
3003
3725
  case "historyUndo": {
@@ -3019,7 +3741,67 @@ function Editor({
3019
3741
  root.addEventListener("beforeinput", handler);
3020
3742
  return () => root.removeEventListener("beforeinput", handler);
3021
3743
  }, []);
3022
- 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) => {
3023
3805
  const ed = editorRef.current;
3024
3806
  const mod = e.metaKey || e.ctrlKey;
3025
3807
  if (e.key === "Tab") {
@@ -3093,17 +3875,17 @@ function Editor({
3093
3875
  });
3094
3876
  }
3095
3877
  }, []);
3096
- const onCompositionStart = (0, import_react12.useCallback)(() => {
3878
+ const onCompositionStart = (0, import_react14.useCallback)(() => {
3097
3879
  isComposingRef.current = true;
3098
3880
  }, []);
3099
- const onCompositionEnd = (0, import_react12.useCallback)((e) => {
3881
+ const onCompositionEnd = (0, import_react14.useCallback)((e) => {
3100
3882
  isComposingRef.current = false;
3101
3883
  if (e.data && e.data.length > 0) {
3102
- (0, import_core5.insertText)(ctxRef.current, e.data);
3884
+ (0, import_core6.insertText)(ctxRef.current, e.data);
3103
3885
  }
3104
3886
  }, []);
3105
- const topLevels = (0, import_react12.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
3106
- const topLevelsStructuralKey = (0, import_react12.useMemo)(
3887
+ const topLevels = (0, import_react14.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
3888
+ const topLevelsStructuralKey = (0, import_react14.useMemo)(
3107
3889
  () => topLevels.map(
3108
3890
  (t) => t.kind === "list" ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}` : `B:${t.block.type}:${t.block.attrs.level ?? ""}`
3109
3891
  ).join("|"),
@@ -3125,7 +3907,7 @@ function Editor({
3125
3907
  [topLevelsStructuralKey, pageGeometry]
3126
3908
  );
3127
3909
  const effectiveLayout = paginated ? layout : defaultPageLayout(topLevels.length);
3128
- const pageStyle = (0, import_react12.useMemo)(
3910
+ const pageStyle = (0, import_react14.useMemo)(
3129
3911
  () => paginated ? {
3130
3912
  "--ed-page-width": `${geom.width}px`,
3131
3913
  "--ed-page-height": `${geom.height}px`,
@@ -3144,7 +3926,7 @@ function Editor({
3144
3926
  geom.marginRight
3145
3927
  ]
3146
3928
  );
3147
- const body = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3929
+ const body = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3148
3930
  "div",
3149
3931
  {
3150
3932
  ref: rootRef,
@@ -3170,7 +3952,7 @@ function Editor({
3170
3952
  const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
3171
3953
  "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
3172
3954
  } : void 0;
3173
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3955
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3174
3956
  "div",
3175
3957
  {
3176
3958
  className: "ed-page",
@@ -3178,15 +3960,15 @@ function Editor({
3178
3960
  "data-page-total": ctx.pageCount,
3179
3961
  style: pageInlineStyle,
3180
3962
  children: [
3181
- renderPageHeader && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3182
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
3183
- 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) })
3184
3966
  ]
3185
3967
  },
3186
3968
  `page-${pi}`
3187
3969
  );
3188
3970
  }) : topLevels.map((t) => renderTopLevel(t)),
3189
- selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3971
+ selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3190
3972
  ImageResizeOverlay,
3191
3973
  {
3192
3974
  rootRef,
@@ -3205,13 +3987,54 @@ function Editor({
3205
3987
  selectedEmbed.offset,
3206
3988
  { offsetX: ox, offsetY: oy },
3207
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
3208
4000
  )
3209
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
+ }
3210
4033
  )
3211
4034
  ]
3212
4035
  }
3213
4036
  );
3214
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EditorProvider, { editor, children: body });
4037
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EditorProvider, { editor, children: body });
3215
4038
  }
3216
4039
  function groupTopLevels(snapshot) {
3217
4040
  const out = [];
@@ -3261,7 +4084,7 @@ function renderSlot(slot, topLevels) {
3261
4084
  start: slot.fragment.start,
3262
4085
  end: slot.fragment.end
3263
4086
  };
3264
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4087
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3265
4088
  NodeView,
3266
4089
  {
3267
4090
  block: top.block,
@@ -3272,7 +4095,7 @@ function renderSlot(slot, topLevels) {
3272
4095
  );
3273
4096
  }
3274
4097
  if (slot.tableFragment && top.kind === "block" && top.block.type === "table") {
3275
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4098
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3276
4099
  NodeView,
3277
4100
  {
3278
4101
  block: top.block,
@@ -3292,7 +4115,7 @@ function renderTopLevel(top) {
3292
4115
  const tree = buildListTree(top.items);
3293
4116
  return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
3294
4117
  }
3295
- 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);
3296
4119
  }
3297
4120
  function renderListFragment(top, frag) {
3298
4121
  const ranges = topLevelItemRanges(top.items);
@@ -3334,9 +4157,9 @@ function buildListTree(items) {
3334
4157
  function renderListTree(tree, top, start, key) {
3335
4158
  const className = `ed-list ed-list-${top.listKind}`;
3336
4159
  const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
3337
- const items = tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime9.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));
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));
3338
4161
  if (top.listKind === "ordered") {
3339
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4162
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3340
4163
  "ol",
3341
4164
  {
3342
4165
  className,
@@ -3348,11 +4171,11 @@ function renderListTree(tree, top, start, key) {
3348
4171
  key
3349
4172
  );
3350
4173
  }
3351
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
4174
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
3352
4175
  }
3353
4176
  function renderNestedListTree(tree, kind, key) {
3354
4177
  const Tag = kind === "ordered" ? "ol" : "ul";
3355
- 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 ? renderNestedListTree(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);
3356
4179
  }
3357
4180
  function clampListLevel2(l) {
3358
4181
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
@@ -3380,8 +4203,8 @@ function caretRangeFromPoint(x, y) {
3380
4203
  }
3381
4204
 
3382
4205
  // src/Toolbar.tsx
3383
- var import_react13 = require("react");
3384
- var import_jsx_runtime10 = require("react/jsx-runtime");
4206
+ var import_react15 = require("react");
4207
+ var import_jsx_runtime13 = require("react/jsx-runtime");
3385
4208
  var FONT_FAMILIES = ["Arial"];
3386
4209
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
3387
4210
  var BLOCK_OPTIONS = [
@@ -3421,6 +4244,8 @@ function Toolbar({ className }) {
3421
4244
  getBlockAttr,
3422
4245
  setBlockType,
3423
4246
  setBlockAttr,
4247
+ setAlign,
4248
+ getAlign,
3424
4249
  isListActive,
3425
4250
  toggleList,
3426
4251
  indentList,
@@ -3429,7 +4254,7 @@ function Toolbar({ className }) {
3429
4254
  const active = getActiveMarks();
3430
4255
  const blockType = getBlockType();
3431
4256
  const blockLevel = getBlockAttr("level");
3432
- const blockAlign = getBlockAttr("align");
4257
+ const blockAlign = getAlign();
3433
4258
  const blockDir = getBlockAttr("dir");
3434
4259
  const stop = (e) => {
3435
4260
  const t = e.target;
@@ -3472,16 +4297,16 @@ function Toolbar({ className }) {
3472
4297
  );
3473
4298
  return;
3474
4299
  }
3475
- setBlockAttr("align", value);
4300
+ setAlign(value);
3476
4301
  };
3477
- const onInsertImageClick = (0, import_react13.useCallback)(
4302
+ const onInsertImageClick = (0, import_react15.useCallback)(
3478
4303
  (e) => {
3479
4304
  e.preventDefault();
3480
4305
  imageInputRef.current?.click();
3481
4306
  },
3482
4307
  []
3483
4308
  );
3484
- const onImageInputChange = (0, import_react13.useCallback)(
4309
+ const onImageInputChange = (0, import_react15.useCallback)(
3485
4310
  (e) => {
3486
4311
  const file = e.target.files?.[0];
3487
4312
  if (file) void editor.insertImageFromFile(file);
@@ -3489,14 +4314,14 @@ function Toolbar({ className }) {
3489
4314
  },
3490
4315
  [editor]
3491
4316
  );
3492
- const imageInputRef = (0, import_react13.useRef)(null);
4317
+ const imageInputRef = (0, import_react15.useRef)(null);
3493
4318
  const onToggleDir = (e) => {
3494
4319
  e.preventDefault();
3495
4320
  const next = blockDir === "rtl" ? "ltr" : "rtl";
3496
4321
  setBlockAttr("dir", next);
3497
4322
  };
3498
4323
  const linkActive = isMarkActive("link");
3499
- const onLinkClick = (0, import_react13.useCallback)(
4324
+ const onLinkClick = (0, import_react15.useCallback)(
3500
4325
  (e) => {
3501
4326
  e.preventDefault();
3502
4327
  const currentHref = active.link && typeof active.link === "object" && "href" in active.link ? active.link.href : "";
@@ -3526,7 +4351,7 @@ function Toolbar({ className }) {
3526
4351
  sel.cellIndex
3527
4352
  );
3528
4353
  };
3529
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4354
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3530
4355
  "div",
3531
4356
  {
3532
4357
  className: className ?? "ed-toolbar",
@@ -3534,7 +4359,7 @@ function Toolbar({ className }) {
3534
4359
  "aria-label": "Editor toolbar",
3535
4360
  onMouseDown: stop,
3536
4361
  children: [
3537
- /* @__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)(
3538
4363
  "select",
3539
4364
  {
3540
4365
  className: "ed-toolbar-select",
@@ -3543,23 +4368,23 @@ function Toolbar({ className }) {
3543
4368
  onMouseDown: stop,
3544
4369
  "aria-label": "Tipo de bloco",
3545
4370
  children: [
3546
- blockValue === "" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "\u2014 (misto)" }),
3547
- 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))
3548
4373
  ]
3549
4374
  }
3550
4375
  ) }),
3551
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3552
- /* @__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" }) }),
3553
- /* @__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" }) }),
3554
- /* @__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" }) }),
3555
- /* @__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" }) })
3556
4381
  ] }),
3557
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3558
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "ed-toolbar-label", children: [
3559
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
3560
- /* @__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" })
3561
4386
  ] }),
3562
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4387
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3563
4388
  "button",
3564
4389
  {
3565
4390
  type: "button",
@@ -3574,8 +4399,8 @@ function Toolbar({ className }) {
3574
4399
  }
3575
4400
  )
3576
4401
  ] }),
3577
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3578
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4402
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4403
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3579
4404
  "select",
3580
4405
  {
3581
4406
  className: "ed-toolbar-select",
@@ -3584,12 +4409,12 @@ function Toolbar({ className }) {
3584
4409
  onMouseDown: stop,
3585
4410
  "aria-label": "Fam\xEDlia da fonte",
3586
4411
  children: [
3587
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "Fonte\u2026" }),
3588
- 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))
3589
4414
  ]
3590
4415
  }
3591
4416
  ),
3592
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4417
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3593
4418
  "select",
3594
4419
  {
3595
4420
  className: "ed-toolbar-select",
@@ -3598,13 +4423,13 @@ function Toolbar({ className }) {
3598
4423
  onMouseDown: stop,
3599
4424
  "aria-label": "Tamanho da fonte",
3600
4425
  children: [
3601
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "Tamanho\u2026" }),
3602
- 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))
3603
4428
  ]
3604
4429
  }
3605
4430
  )
3606
4431
  ] }),
3607
- /* @__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)(
3608
4433
  "button",
3609
4434
  {
3610
4435
  type: "button",
@@ -3617,7 +4442,7 @@ function Toolbar({ className }) {
3617
4442
  },
3618
4443
  a.value
3619
4444
  )) }),
3620
- /* @__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)(
3621
4446
  "button",
3622
4447
  {
3623
4448
  type: "button",
@@ -3629,8 +4454,8 @@ function Toolbar({ className }) {
3629
4454
  children: blockDir === "rtl" ? "RTL" : "LTR"
3630
4455
  }
3631
4456
  ) }),
3632
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3633
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4457
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Group, { children: [
4458
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3634
4459
  "button",
3635
4460
  {
3636
4461
  type: "button",
@@ -3645,7 +4470,7 @@ function Toolbar({ className }) {
3645
4470
  children: "\u2022"
3646
4471
  }
3647
4472
  ),
3648
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4473
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3649
4474
  "button",
3650
4475
  {
3651
4476
  type: "button",
@@ -3660,7 +4485,7 @@ function Toolbar({ className }) {
3660
4485
  children: "1."
3661
4486
  }
3662
4487
  ),
3663
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4488
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3664
4489
  "button",
3665
4490
  {
3666
4491
  type: "button",
@@ -3674,7 +4499,7 @@ function Toolbar({ className }) {
3674
4499
  children: "\u21E4"
3675
4500
  }
3676
4501
  ),
3677
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4502
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3678
4503
  "button",
3679
4504
  {
3680
4505
  type: "button",
@@ -3689,7 +4514,7 @@ function Toolbar({ className }) {
3689
4514
  }
3690
4515
  )
3691
4516
  ] }),
3692
- /* @__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)(
3693
4518
  "button",
3694
4519
  {
3695
4520
  type: "button",
@@ -3701,9 +4526,9 @@ function Toolbar({ className }) {
3701
4526
  children: "\u{1F517}"
3702
4527
  }
3703
4528
  ) }),
3704
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Group, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TableMenu, {}) }),
3705
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3706
- /* @__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)(
3707
4532
  "button",
3708
4533
  {
3709
4534
  type: "button",
@@ -3714,7 +4539,7 @@ function Toolbar({ className }) {
3714
4539
  children: "\u{1F5BC}"
3715
4540
  }
3716
4541
  ),
3717
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4542
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3718
4543
  "input",
3719
4544
  {
3720
4545
  ref: imageInputRef,
@@ -3725,8 +4550,8 @@ function Toolbar({ className }) {
3725
4550
  }
3726
4551
  )
3727
4552
  ] }),
3728
- selectedEmbed && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Group, { children: [
3729
- 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)(
3730
4555
  "button",
3731
4556
  {
3732
4557
  type: "button",
@@ -3739,7 +4564,7 @@ function Toolbar({ className }) {
3739
4564
  },
3740
4565
  opt.value
3741
4566
  )),
3742
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4567
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3743
4568
  "button",
3744
4569
  {
3745
4570
  type: "button",
@@ -3769,7 +4594,7 @@ function Toolbar({ className }) {
3769
4594
  }
3770
4595
  )
3771
4596
  ] }),
3772
- /* @__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)(
3773
4598
  "button",
3774
4599
  {
3775
4600
  type: "button",
@@ -3790,9 +4615,9 @@ function Toolbar({ className }) {
3790
4615
  function TableMenu() {
3791
4616
  const editor = useEditorContext();
3792
4617
  const inTable = editor.isInTable();
3793
- const [open, setOpen] = (0, import_react13.useState)(false);
3794
- const rootRef = (0, import_react13.useRef)(null);
3795
- (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)(() => {
3796
4621
  if (!open) return;
3797
4622
  const onDown = (e) => {
3798
4623
  if (!rootRef.current) return;
@@ -3802,8 +4627,8 @@ function TableMenu() {
3802
4627
  document.addEventListener("mousedown", onDown);
3803
4628
  return () => document.removeEventListener("mousedown", onDown);
3804
4629
  }, [open]);
3805
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
3806
- /* @__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)(
3807
4632
  "button",
3808
4633
  {
3809
4634
  type: "button",
@@ -3818,7 +4643,7 @@ function TableMenu() {
3818
4643
  children: "\u25A6"
3819
4644
  }
3820
4645
  ),
3821
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4646
+ open && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3822
4647
  "div",
3823
4648
  {
3824
4649
  className: "ed-table-popover",
@@ -3830,7 +4655,7 @@ function TableMenu() {
3830
4655
  }
3831
4656
  },
3832
4657
  children: [
3833
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4658
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3834
4659
  TableSizePicker,
3835
4660
  {
3836
4661
  onPick: (rows, cols) => {
@@ -3839,34 +4664,34 @@ function TableMenu() {
3839
4664
  }
3840
4665
  }
3841
4666
  ),
3842
- inTable && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ed-table-actions", children: [
3843
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("hr", {}),
3844
- /* @__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: () => {
3845
4670
  setOpen(false);
3846
4671
  editor.insertRowAbove();
3847
4672
  }, children: "Inserir linha acima" }),
3848
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4673
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3849
4674
  setOpen(false);
3850
4675
  editor.insertRowBelow();
3851
4676
  }, children: "Inserir linha abaixo" }),
3852
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4677
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3853
4678
  setOpen(false);
3854
4679
  editor.insertColumnLeft();
3855
4680
  }, children: "Inserir coluna \xE0 esquerda" }),
3856
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4681
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3857
4682
  setOpen(false);
3858
4683
  editor.insertColumnRight();
3859
4684
  }, children: "Inserir coluna \xE0 direita" }),
3860
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4685
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3861
4686
  setOpen(false);
3862
4687
  editor.deleteCurrentRow();
3863
4688
  }, children: "Excluir linha" }),
3864
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4689
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3865
4690
  setOpen(false);
3866
4691
  editor.deleteCurrentColumn();
3867
4692
  }, children: "Excluir coluna" }),
3868
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("hr", {}),
3869
- 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)(
3870
4695
  "button",
3871
4696
  {
3872
4697
  type: "button",
@@ -3877,19 +4702,19 @@ function TableMenu() {
3877
4702
  children: "Mesclar c\xE9lulas selecionadas"
3878
4703
  }
3879
4704
  ),
3880
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4705
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3881
4706
  setOpen(false);
3882
4707
  editor.mergeRight();
3883
4708
  }, children: "Mesclar com c\xE9lula \xE0 direita" }),
3884
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4709
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3885
4710
  setOpen(false);
3886
4711
  editor.mergeDown();
3887
4712
  }, children: "Mesclar com c\xE9lula abaixo" }),
3888
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => {
4713
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => {
3889
4714
  setOpen(false);
3890
4715
  editor.splitCell();
3891
4716
  }, children: "Dividir c\xE9lulas mescladas" }),
3892
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4717
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3893
4718
  "button",
3894
4719
  {
3895
4720
  type: "button",
@@ -3910,11 +4735,11 @@ function TableMenu() {
3910
4735
  var PICKER_MAX_ROWS = 8;
3911
4736
  var PICKER_MAX_COLS = 10;
3912
4737
  function TableSizePicker({ onPick }) {
3913
- const [hover, setHover] = (0, import_react13.useState)(null);
4738
+ const [hover, setHover] = (0, import_react15.useState)(null);
3914
4739
  const label = hover ? `${hover.r + 1} \xD7 ${hover.c + 1}` : "Inserir tabela";
3915
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ed-table-picker", children: [
3916
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ed-table-picker-label", children: label }),
3917
- /* @__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)(
3918
4743
  "div",
3919
4744
  {
3920
4745
  className: "ed-table-picker-grid",
@@ -3927,7 +4752,7 @@ function TableSizePicker({ onPick }) {
3927
4752
  { length: PICKER_MAX_ROWS },
3928
4753
  (_, r) => Array.from({ length: PICKER_MAX_COLS }, (_2, c) => {
3929
4754
  const filled = hover != null && r <= hover.r && c <= hover.c;
3930
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4755
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3931
4756
  "button",
3932
4757
  {
3933
4758
  type: "button",
@@ -3957,10 +4782,10 @@ function blockSelectValue(type, level) {
3957
4782
  return type;
3958
4783
  }
3959
4784
  function Group({ children }) {
3960
- 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 });
3961
4786
  }
3962
4787
  function MarkButton({ title, pressed, onClick, children }) {
3963
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4788
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3964
4789
  "button",
3965
4790
  {
3966
4791
  type: "button",
@@ -3982,6 +4807,7 @@ function MarkButton({ title, pressed, onClick, children }) {
3982
4807
  LinkDialog,
3983
4808
  NodeView,
3984
4809
  PageConfigDialog,
4810
+ RemoteCursorsOverlay,
3985
4811
  Toolbar,
3986
4812
  applyDomSelection,
3987
4813
  contentHeight,
@@ -3993,6 +4819,7 @@ function MarkButton({ title, pressed, onClick, children }) {
3993
4819
  getCellElement,
3994
4820
  getFragmentForOffset,
3995
4821
  isTableRectSelection,
4822
+ locatePoint,
3996
4823
  readDomSelection,
3997
4824
  renderInline,
3998
4825
  selectionsEqual,