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