@stll/folio-react 0.18.1 → 0.18.2

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.
@@ -55,14 +55,16 @@ import { documentFontsAreLoaded, getDocumentFontSet, waitForInitialLayoutFonts }
55
55
  import { getFootnoteText } from "@stll/folio-core/docx/footnoteParser";
56
56
  import { convertHeaderFooterPmDocToContent, convertHeaderFooterToContent } from "@stll/folio-core/layout-bridge/convert/headerFooterLayout";
57
57
  import { templatePreviewDirtyRange } from "@stll/folio-core/layout-bridge/convert/templatePreviewFlow";
58
- import { clickToPositionDom, findCollapsedLineEdgeCaretTarget } from "@stll/folio-core/layout-bridge/dom/clickToPositionDom";
58
+ import { clickToPositionDom, getCaretPositionFromDom, getSelectionRectsFromDom } from "@stll/folio-core/layout-bridge/dom/clickToPositionDom";
59
+ import { measurePaintedSpanRange } from "@stll/folio-core/layout-bridge/dom/textStreamDom";
59
60
  import { resetImeCaretAnchor, syncImeCaretAnchor } from "@stll/folio-core/layout-bridge/dom/imeCaretAnchor";
60
- import { findBodyEmptyRuns, findBodyPmAnchor, findBodyPmAnchors, findBodyPmSpans } from "@stll/folio-core/layout-bridge/dom/findBodyPmSpans";
61
- import { clickToPositionInHfSlot, findHfCaretSpan, findHfPmSpans, findHfSlotForTarget, findHfSlotKindForTarget } from "@stll/folio-core/layout-bridge/dom/findHfPmSpans";
61
+ import { findBodyPmAnchor, findBodyPmAnchors, findBodyPmSpans } from "@stll/folio-core/layout-bridge/dom/findBodyPmSpans";
62
+ import { clickToPositionInHfSlot, findHfSlotForTarget, findHfSlotKindForTarget } from "@stll/folio-core/layout-bridge/dom/findHfPmSpans";
62
63
  import { findNoteStoryForTarget } from "@stll/folio-core/layout-bridge/dom/noteStoryDom";
63
64
  import { clickToPosition } from "@stll/folio-core/layout-bridge/engine/clickToPosition";
64
65
  import { getPageTop, hitTestFragment, hitTestTableCell } from "@stll/folio-core/layout-bridge/engine/hitTest";
65
66
  import { clearAllCaches, resetCanvasContext } from "@stll/folio-core/layout-bridge/engine/measuring";
67
+ import { resolveHeaderFooterSelectionGeometry } from "@stll/folio-core/render-dom/HeaderFooterSelectionOverlay";
66
68
  import { setEmbeddedFontFamilyMap } from "@stll/folio-core/utils/fontResolver";
67
69
  import { resolveSectionHeaderFooterRefs } from "@stll/folio-core/layout-engine";
68
70
  import { recordLayoutPhase } from "@stll/folio-core/layout-engine/layoutInstrumentation";
@@ -78,12 +80,13 @@ import { flashParagraphFragmentsByParaId } from "@stll/folio-core/paged-layout/p
78
80
  import { DEFAULT_PAGE_HEIGHT_PX, getMargins, getPageSize, twipsToPixels as twipsToPixels$1 } from "@stll/folio-core/paged-layout/sectionGeometry";
79
81
  import { resizeColumnPair } from "@stll/folio-core/paged-layout/tableColumnResize";
80
82
  import { tableInsertButtonOffset } from "@stll/folio-core/paged-layout/tableInsertButtonGeometry";
81
- import { getTransactionDirtyRange } from "@stll/folio-core/paged-layout/transactionDirtyRange";
83
+ import { getTransactionsDirtyRange } from "@stll/folio-core/paged-layout/transactionDirtyRange";
82
84
  import { findStartPosForParaId } from "@stll/folio-core/prosemirror/utils/findParagraphByParaId";
83
85
  import { buildEmbeddedFontFamilyMap, extractEmbeddedFonts } from "@stll/folio-core/fonts/embeddedFonts";
84
86
  import { panic } from "better-result";
85
87
  import { collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState } from "@stll/folio-core/controller/hiddenEditorManager";
86
88
  import { loadCollaborationModules } from "@stll/folio-core/controller/collaborationModules";
89
+ import { createVisualLineState, handleVisualLineKeyDown } from "@stll/folio-core/prosemirror/utils/visualLineNavigation";
87
90
  import { clampRangeToDocSize, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange } from "@stll/folio-core/ai-edits/blockRange";
88
91
  import { getFolioParaIdFromBlockId } from "@stll/folio-core/types/block-id";
89
92
  import { getPageTextFromLayout } from "@stll/folio-core/paged-layout/pageText";
@@ -1265,7 +1268,7 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1265
1268
  getReadOnly: () => readOnlyRef.current,
1266
1269
  getDocumentIdentity: () => documentIdentityRef.current,
1267
1270
  getDocumentContext: () => documentRef.current,
1268
- onTransaction: (transaction, newState) => onTransactionRef.current?.(transaction, newState),
1271
+ onTransaction: (update) => onTransactionRef.current?.(update),
1269
1272
  onSelectionChange: (state) => onSelectionChangeRef.current?.(state),
1270
1273
  onKeyDown: (view, event) => onKeyDownRef.current?.(view, event) ?? false,
1271
1274
  onCopy: () => onCopyRef.current?.(),
@@ -2163,7 +2166,7 @@ const MAX_SPEED = 12;
2163
2166
  /**
2164
2167
  * Find the nearest scrollable ancestor.
2165
2168
  */
2166
- function findScrollParent$1(el) {
2169
+ function findScrollParent(el) {
2167
2170
  let parent = el.parentElement;
2168
2171
  while (parent && parent !== document.documentElement) {
2169
2172
  const { overflowY } = getComputedStyle(parent);
@@ -2184,7 +2187,7 @@ function useDragAutoScroll({ pagesContainerRef, onScrollExtendSelection }) {
2184
2187
  if (scrollParentRef.current) return scrollParentRef.current;
2185
2188
  const pages = pagesContainerRef.current;
2186
2189
  if (!pages) return null;
2187
- scrollParentRef.current = findScrollParent$1(pages);
2190
+ scrollParentRef.current = findScrollParent(pages);
2188
2191
  return scrollParentRef.current;
2189
2192
  }, [pagesContainerRef]);
2190
2193
  const stopAutoScroll = useCallback(() => {
@@ -2237,246 +2240,30 @@ function useDragAutoScroll({ pagesContainerRef, onScrollExtendSelection }) {
2237
2240
  }
2238
2241
  //#endregion
2239
2242
  //#region src/paged-editor/useVisualLineNavigation.ts
2240
- /**
2241
- * Visual Line Navigation Hook
2242
- *
2243
- * Implements visual-line-aware ArrowUp/ArrowDown navigation with sticky X.
2244
- * Extracted from PagedEditor.tsx for better separation of concerns.
2245
- *
2246
- * This hook provides:
2247
- * - getCaretClientX: Get the screen X of the caret at a PM position
2248
- * - findLineElementAtPosition: Find the .layout-line element for a PM position
2249
- * - findPositionOnLineAtClientX: Find a PM position on a line at a given screen X
2250
- * - handlePMKeyDown: Key handler for ArrowUp/ArrowDown with sticky X
2251
- */
2252
- /** Only match lines inside page body content, skipping header/footer lines. */
2253
- const CONTENT_LINE_SELECTOR = ".layout-page-content .layout-line";
2254
- /**
2255
- * Find the nearest ancestor that actually scrolls (overflow auto/scroll
2256
- * and scrollHeight > clientHeight).
2257
- */
2258
- function findScrollParent(el) {
2259
- let parent = el.parentElement;
2260
- while (parent && parent !== document.documentElement) {
2261
- const { overflowY } = getComputedStyle(parent);
2262
- if ((overflowY === "auto" || overflowY === "scroll") && parent.scrollHeight > parent.clientHeight) return parent;
2263
- parent = parent.parentElement;
2264
- }
2265
- return null;
2266
- }
2267
- /**
2268
- * Scroll the nearest scrollable ancestor so that the target element is visible.
2269
- * Uses manual scroll math because `scrollIntoView` misbehaves when the
2270
- * content is inside a CSS `transform: scale()` viewport.
2271
- */
2272
- function scrollIntoViewIfNeeded(el) {
2273
- const container = findScrollParent(el);
2274
- if (!container) return;
2275
- const elRect = el.getBoundingClientRect();
2276
- const containerRect = container.getBoundingClientRect();
2277
- const margin = 40;
2278
- if (elRect.bottom > containerRect.bottom - margin) container.scrollTop += elRect.bottom - containerRect.bottom + margin;
2279
- else if (elRect.top < containerRect.top + margin) container.scrollTop -= containerRect.top - elRect.top + margin;
2280
- }
2281
- function useVisualLineNavigation({ pagesContainerRef }) {
2282
- const stickyXRef = useRef(null);
2283
- const lastVisualLineIndexRef = useRef(-1);
2284
- /**
2285
- * Get the client X coordinate of the caret at a PM position.
2286
- */
2287
- const getCaretClientX = useCallback((pmPos) => {
2288
- if (!pagesContainerRef.current) return null;
2289
- const spans = findBodyPmSpans(pagesContainerRef.current);
2290
- for (const spanEl of spans) {
2291
- const pmStart = Number(spanEl.dataset["pmStart"]);
2292
- const pmEnd = Number(spanEl.dataset["pmEnd"]);
2293
- if (spanEl.classList.contains("layout-run-tab")) {
2294
- if (pmPos >= pmStart && pmPos < pmEnd) return spanEl.getBoundingClientRect().left;
2295
- continue;
2296
- }
2297
- if (pmPos >= pmStart && pmPos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
2298
- const textNode = spanEl.firstChild;
2299
- const charIndex = Math.min(pmPos - pmStart, textNode.length);
2300
- const range = spanEl.ownerDocument.createRange();
2301
- range.setStart(textNode, charIndex);
2302
- range.setEnd(textNode, charIndex);
2303
- return range.getBoundingClientRect().left;
2304
- }
2305
- if (pmPos >= pmStart && pmPos <= pmEnd) return spanEl.getBoundingClientRect().left;
2306
- }
2307
- const emptyRuns = findBodyEmptyRuns(pagesContainerRef.current);
2308
- for (const emptyRun of emptyRuns) {
2309
- const paragraph = closestHtmlElement(emptyRun, ".layout-paragraph");
2310
- if (!paragraph) continue;
2311
- const pmStart_0 = Number(paragraph.dataset["pmStart"]);
2312
- const pmEnd_0 = Number(paragraph.dataset["pmEnd"]);
2313
- if (pmPos >= pmStart_0 && pmPos <= pmEnd_0) return emptyRun.getBoundingClientRect().left;
2314
- }
2315
- return null;
2316
- }, [pagesContainerRef]);
2317
- /**
2318
- * Find the visual line element (.layout-line) containing a PM position.
2319
- */
2320
- const findLineElementAtPosition = useCallback((pmPos_0) => {
2321
- if (!pagesContainerRef.current) return null;
2322
- const allLines = htmlQueryAll(pagesContainerRef.current, CONTENT_LINE_SELECTOR);
2323
- for (const lineEl of allLines) {
2324
- const spans_0 = htmlQueryAll(lineEl, "span[data-pm-start][data-pm-end]");
2325
- for (const span of spans_0) {
2326
- const start = Number(span.dataset["pmStart"]);
2327
- const end = Number(span.dataset["pmEnd"]);
2328
- if (pmPos_0 >= start && pmPos_0 <= end) return lineEl;
2329
- }
2330
- }
2331
- for (const lineEl_0 of allLines) {
2332
- const paragraph_0 = closestHtmlElement(lineEl_0, ".layout-paragraph");
2333
- if (!paragraph_0) continue;
2334
- const pStart = Number(paragraph_0.dataset["pmStart"]);
2335
- const pEnd = Number(paragraph_0.dataset["pmEnd"]);
2336
- if (pmPos_0 >= pStart && pmPos_0 <= pEnd) {
2337
- if (paragraph_0.querySelector(".layout-line") === lineEl_0) return lineEl_0;
2338
- }
2339
- }
2340
- return null;
2341
- }, [pagesContainerRef]);
2342
- /**
2343
- * Find the PM position on a visual line closest to a client X coordinate.
2344
- */
2345
- const findPositionOnLineAtClientX = useCallback((lineEl_1, clientX) => {
2346
- const spans_1 = htmlQueryAll(lineEl_1, "span[data-pm-start][data-pm-end]");
2347
- const emptyRun_0 = lineEl_1.querySelector(".layout-empty-run");
2348
- if (emptyRun_0) {
2349
- if (emptyRun_0 instanceof HTMLElement && emptyRun_0.dataset["pmStart"]) return Number(emptyRun_0.dataset["pmStart"]);
2350
- const paragraph_1 = closestHtmlElement(lineEl_1, ".layout-paragraph");
2351
- if (paragraph_1?.dataset["pmStart"]) return Number(paragraph_1.dataset["pmStart"]) + 1;
2352
- return null;
2353
- }
2354
- if (spans_1.length === 0) {
2355
- const paragraph_2 = closestHtmlElement(lineEl_1, ".layout-paragraph");
2356
- if (paragraph_2?.dataset["pmStart"]) return Number(paragraph_2.dataset["pmStart"]) + 1;
2357
- return null;
2358
- }
2359
- for (const spanEl_0 of spans_1) {
2360
- const rect = spanEl_0.getBoundingClientRect();
2361
- const pmStart_1 = Number(spanEl_0.dataset["pmStart"]);
2362
- const pmEnd_1 = Number(spanEl_0.dataset["pmEnd"]);
2363
- if (spanEl_0.classList.contains("layout-run-tab")) {
2364
- if (clientX >= rect.left && clientX <= rect.right) return clientX < (rect.left + rect.right) / 2 ? pmStart_1 : pmEnd_1;
2365
- continue;
2366
- }
2367
- if (clientX >= rect.left && clientX <= rect.right) {
2368
- const textNode_0 = spanEl_0.firstChild;
2369
- if (!textNode_0 || textNode_0.nodeType !== Node.TEXT_NODE) return pmStart_1;
2370
- const text = textNode_0;
2371
- const ownerDoc_0 = spanEl_0.ownerDocument;
2372
- let lo = 0;
2373
- let hi = text.length;
2374
- while (lo < hi) {
2375
- const mid_0 = Math.floor((lo + hi) / 2);
2376
- const r = ownerDoc_0.createRange();
2377
- r.setStart(text, mid_0);
2378
- r.setEnd(text, mid_0);
2379
- if (clientX < r.getBoundingClientRect().left) hi = mid_0;
2380
- else lo = mid_0 + 1;
2381
- }
2382
- if (lo > 0 && lo <= text.length) {
2383
- const r_0 = ownerDoc_0.createRange();
2384
- r_0.setStart(text, lo - 1);
2385
- r_0.setEnd(text, lo - 1);
2386
- const leftX = r_0.getBoundingClientRect().left;
2387
- r_0.setStart(text, Math.min(lo, text.length));
2388
- r_0.setEnd(text, Math.min(lo, text.length));
2389
- const rightX = r_0.getBoundingClientRect().left;
2390
- if (Math.abs(clientX - leftX) < Math.abs(clientX - rightX)) return pmStart_1 + (lo - 1);
2391
- }
2392
- return pmStart_1 + Math.min(lo, pmEnd_1 - pmStart_1);
2393
- }
2394
- }
2395
- let closestSpan = null;
2396
- let closestDist = Infinity;
2397
- for (const span_0 of spans_1) {
2398
- const rect_0 = span_0.getBoundingClientRect();
2399
- const dist = clientX < rect_0.left ? rect_0.left - clientX : clientX - rect_0.right;
2400
- if (dist < closestDist) {
2401
- closestDist = dist;
2402
- closestSpan = span_0;
2403
- }
2404
- }
2405
- if (!closestSpan) return null;
2406
- return clientX < closestSpan.getBoundingClientRect().left ? Number(closestSpan.dataset["pmStart"]) : Number(closestSpan.dataset["pmEnd"]);
2407
- }, []);
2408
- return {
2409
- stickyXRef,
2410
- lastVisualLineIndexRef,
2411
- getCaretClientX,
2412
- findLineElementAtPosition,
2413
- findPositionOnLineAtClientX,
2414
- handlePMKeyDown: useCallback((view, event) => {
2415
- if (event.key !== "ArrowUp" && event.key !== "ArrowDown") {
2416
- if ([
2417
- "ArrowLeft",
2418
- "ArrowRight",
2419
- "Home",
2420
- "End"
2421
- ].includes(event.key) || event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
2422
- stickyXRef.current = null;
2423
- lastVisualLineIndexRef.current = -1;
2424
- }
2425
- return false;
2426
- }
2427
- if (event.ctrlKey || event.metaKey) {
2428
- stickyXRef.current = null;
2429
- lastVisualLineIndexRef.current = -1;
2430
- return false;
2431
- }
2432
- if (!pagesContainerRef.current) return false;
2433
- const allLines_0 = htmlQueryAll(pagesContainerRef.current, CONTENT_LINE_SELECTOR);
2434
- if (allLines_0.length === 0) return false;
2435
- const { from, anchor } = view.state.selection;
2436
- if (stickyXRef.current === null) {
2437
- const clientX_0 = getCaretClientX(from);
2438
- if (clientX_0 === null) return false;
2439
- stickyXRef.current = clientX_0;
2440
- }
2441
- let currentIndex;
2442
- if (lastVisualLineIndexRef.current >= 0 && lastVisualLineIndexRef.current < allLines_0.length) currentIndex = lastVisualLineIndexRef.current;
2443
- else {
2444
- const currentLine = findLineElementAtPosition(from);
2445
- if (!currentLine) return false;
2446
- currentIndex = allLines_0.indexOf(currentLine);
2447
- if (currentIndex === -1) return false;
2448
- }
2449
- const targetIndex = event.key === "ArrowUp" ? currentIndex - 1 : currentIndex + 1;
2450
- if (targetIndex < 0 || targetIndex >= allLines_0.length) {
2451
- lastVisualLineIndexRef.current = -1;
2452
- return false;
2453
- }
2454
- const targetLine = allLines_0[targetIndex];
2455
- if (!targetLine) return false;
2456
- const newPos = findPositionOnLineAtClientX(targetLine, stickyXRef.current);
2457
- if (newPos === null) return false;
2458
- lastVisualLineIndexRef.current = targetIndex;
2459
- const { state, dispatch } = view;
2460
- const clampedPos = Math.max(0, Math.min(newPos, state.doc.content.size));
2461
- const clampedAnchor = Math.max(0, Math.min(anchor, state.doc.content.size));
2462
- try {
2463
- const $newPos_0 = state.doc.resolve(clampedPos);
2464
- const sel_0 = event.shiftKey ? TextSelection$1.between(state.doc.resolve(clampedAnchor), $newPos_0) : Selection.near($newPos_0);
2465
- dispatch(state.tr.setSelection(sel_0));
2466
- } catch {
2467
- const $newPos = state.doc.resolve(clampedPos);
2468
- const sel = event.shiftKey ? TextSelection$1.between(state.doc.resolve(clampedAnchor), $newPos) : Selection.near($newPos);
2469
- dispatch(state.tr.setSelection(sel));
2470
- }
2471
- scrollIntoViewIfNeeded(targetLine);
2472
- return true;
2473
- }, [
2474
- pagesContainerRef,
2475
- getCaretClientX,
2476
- findLineElementAtPosition,
2477
- findPositionOnLineAtClientX
2478
- ])
2479
- };
2243
+ /** Bind the framework-neutral visual-line navigation state to React. */
2244
+ function useVisualLineNavigation(t0) {
2245
+ const $ = c(5);
2246
+ const { pagesContainerRef } = t0;
2247
+ let t1;
2248
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
2249
+ t1 = createVisualLineState();
2250
+ $[0] = t1;
2251
+ } else t1 = $[0];
2252
+ const stateRef = useRef(t1);
2253
+ let t2;
2254
+ if ($[1] !== pagesContainerRef) {
2255
+ t2 = (view, event) => handleVisualLineKeyDown(stateRef.current, view, event, pagesContainerRef.current);
2256
+ $[1] = pagesContainerRef;
2257
+ $[2] = t2;
2258
+ } else t2 = $[2];
2259
+ const handlePMKeyDown = t2;
2260
+ let t3;
2261
+ if ($[3] !== handlePMKeyDown) {
2262
+ t3 = { handlePMKeyDown };
2263
+ $[3] = handlePMKeyDown;
2264
+ $[4] = t3;
2265
+ } else t3 = $[4];
2266
+ return t3;
2480
2267
  }
2481
2268
  /** Distance in px from a row/column boundary that triggers the insert button */
2482
2269
  /** Distance in px from the table edge where boundary detection is active */
@@ -2566,15 +2353,6 @@ const getPageIndex = (el) => {
2566
2353
  const raw = pageEl.dataset["pageNumber"];
2567
2354
  return raw ? Number(raw) - 1 : 0;
2568
2355
  };
2569
- /**
2570
- * Get the line height for a node by climbing to its `.layout-line`
2571
- * ancestor and reading `offsetHeight`. Returns `fallback` if no
2572
- * ancestor is found.
2573
- */
2574
- const getLineHeight = (el, fallback = 16) => {
2575
- const lineEl = closestHtmlElement(el, ".layout-line");
2576
- return lineEl ? lineEl.offsetHeight : fallback;
2577
- };
2578
2356
  const containerStyles = {
2579
2357
  position: "relative",
2580
2358
  width: "100%",
@@ -2600,7 +2378,7 @@ const loadSelectionGeometry = () => {
2600
2378
  return selectionGeometryPromise;
2601
2379
  };
2602
2380
  function HfCaretOverlay(t0) {
2603
- const $ = c(22);
2381
+ const $ = c(27);
2604
2382
  const { selection, pagesContainer, hiddenHost, editorView, zoom } = t0;
2605
2383
  const [caret, setCaret] = useState(null);
2606
2384
  let t1;
@@ -2610,62 +2388,24 @@ function HfCaretOverlay(t0) {
2610
2388
  } else t1 = $[0];
2611
2389
  const [rangeRects, setRangeRects] = useState(t1);
2612
2390
  let t2;
2613
- let t3;
2614
- if ($[1] !== editorView || $[2] !== hiddenHost || $[3] !== pagesContainer || $[4] !== selection.from || $[5] !== selection.kind || $[6] !== selection.pageNumber || $[7] !== selection.rId || $[8] !== selection.to || $[9] !== zoom) {
2391
+ if ($[1] !== editorView || $[2] !== hiddenHost || $[3] !== pagesContainer || $[4] !== selection || $[5] !== zoom) {
2615
2392
  t2 = () => {
2616
2393
  if (!pagesContainer) return;
2617
2394
  const recompute = () => {
2618
2395
  const cr = pagesContainer.getBoundingClientRect();
2619
2396
  const zoomDivisor = zoom !== 0 ? zoom : 1;
2620
- const pageScope = selection.pageNumber ? pagesContainer.querySelector(`.layout-page[data-page-number="${selection.pageNumber}"]`) ?? pagesContainer : pagesContainer;
2621
- if (selection.from === selection.to) {
2622
- const hit = findHfCaretSpan(pageScope, selection.kind, selection.rId, selection.from);
2623
- if (!hit) {
2624
- syncImeCaretAnchor({
2625
- hiddenHost,
2626
- editorView,
2627
- visibleCaret: null
2628
- });
2629
- setCaret(null);
2630
- setRangeRects([]);
2631
- return;
2632
- }
2633
- const ar = hit.element.getBoundingClientRect();
2634
- let absX = hit.edge === "right" ? ar.right : ar.left;
2635
- let absY = ar.top;
2636
- let absHeight = ar.height || 16;
2637
- const pmStartStr = hit.element.dataset.pmStart;
2638
- const pmEndStr = hit.element.dataset.pmEnd;
2639
- const pmStart = pmStartStr ? Number.parseInt(pmStartStr, 10) : NaN;
2640
- const pmEnd = pmEndStr ? Number.parseInt(pmEndStr, 10) : NaN;
2641
- const textNode = hit.element.firstChild;
2642
- if (textNode && textNode.nodeType === Node.TEXT_NODE && Number.isFinite(pmStart) && Number.isFinite(pmEnd)) {
2643
- const textContent = textNode.textContent ?? "";
2644
- const charOffset = Math.min(Math.max(0, selection.from - pmStart), textContent.length);
2645
- const range = hit.element.ownerDocument.createRange();
2646
- range.setStart(textNode, charOffset);
2647
- range.setEnd(textNode, charOffset);
2648
- const rRect = range.getBoundingClientRect();
2649
- if (rRect.height > 0 || rRect.width > 0 || rRect.left > 0) {
2650
- absX = rRect.left;
2651
- absY = rRect.top;
2652
- absHeight = rRect.height || absHeight;
2653
- }
2654
- }
2655
- setCaret({
2656
- x: (absX - cr.left) / zoomDivisor,
2657
- y: (absY - cr.top) / zoomDivisor,
2658
- height: absHeight / zoomDivisor
2659
- });
2397
+ const geometry = resolveHeaderFooterSelectionGeometry(pagesContainer, selection, zoomDivisor);
2398
+ setCaret(geometry.caret);
2399
+ setRangeRects(geometry.ranges);
2400
+ if (geometry.caret) {
2660
2401
  syncImeCaretAnchor({
2661
2402
  hiddenHost,
2662
2403
  editorView,
2663
2404
  visibleCaret: {
2664
- left: absX,
2665
- top: absY
2405
+ left: cr.left + geometry.caret.x * zoomDivisor,
2406
+ top: cr.top + geometry.caret.y * zoomDivisor
2666
2407
  }
2667
2408
  });
2668
- setRangeRects([]);
2669
2409
  return;
2670
2410
  }
2671
2411
  syncImeCaretAnchor({
@@ -2673,41 +2413,6 @@ function HfCaretOverlay(t0) {
2673
2413
  editorView,
2674
2414
  visibleCaret: null
2675
2415
  });
2676
- const spans = findHfPmSpans(pageScope, selection.kind, selection.rId);
2677
- const rects = [];
2678
- for (const span of spans) {
2679
- const spanStart = Number.parseInt(span.dataset.pmStart ?? "", 10);
2680
- const spanEnd = Number.parseInt(span.dataset.pmEnd ?? "", 10);
2681
- if (!Number.isFinite(spanStart) || !Number.isFinite(spanEnd)) continue;
2682
- if (spanEnd <= selection.from || spanStart >= selection.to) continue;
2683
- const textNode_0 = span.firstChild;
2684
- if (textNode_0 && textNode_0.nodeType === Node.TEXT_NODE) {
2685
- const textContent_0 = textNode_0.textContent ?? "";
2686
- const startChar = Math.max(0, selection.from - spanStart);
2687
- const endChar = Math.min(textContent_0.length, selection.to - spanStart);
2688
- if (startChar < endChar) {
2689
- const range_0 = span.ownerDocument.createRange();
2690
- range_0.setStart(textNode_0, startChar);
2691
- range_0.setEnd(textNode_0, endChar);
2692
- for (const cRect of Array.from(range_0.getClientRects())) rects.push({
2693
- x: (cRect.left - cr.left) / zoomDivisor,
2694
- y: (cRect.top - cr.top) / zoomDivisor,
2695
- width: cRect.width / zoomDivisor,
2696
- height: cRect.height / zoomDivisor
2697
- });
2698
- continue;
2699
- }
2700
- }
2701
- const r = span.getBoundingClientRect();
2702
- rects.push({
2703
- x: (r.left - cr.left) / zoomDivisor,
2704
- y: (r.top - cr.top) / zoomDivisor,
2705
- width: r.width / zoomDivisor,
2706
- height: r.height / zoomDivisor
2707
- });
2708
- }
2709
- setRangeRects(rects);
2710
- setCaret(null);
2711
2416
  };
2712
2417
  recompute();
2713
2418
  const onPainted = () => recompute();
@@ -2732,6 +2437,15 @@ function HfCaretOverlay(t0) {
2732
2437
  resetImeCaretAnchor(hiddenHost);
2733
2438
  };
2734
2439
  };
2440
+ $[1] = editorView;
2441
+ $[2] = hiddenHost;
2442
+ $[3] = pagesContainer;
2443
+ $[4] = selection;
2444
+ $[5] = zoom;
2445
+ $[6] = t2;
2446
+ } else t2 = $[6];
2447
+ let t3;
2448
+ if ($[7] !== editorView || $[8] !== hiddenHost || $[9] !== pagesContainer || $[10] !== selection.from || $[11] !== selection.kind || $[12] !== selection.pageNumber || $[13] !== selection.rId || $[14] !== selection.to || $[15] !== zoom) {
2735
2449
  t3 = [
2736
2450
  selection.rId,
2737
2451
  selection.kind,
@@ -2743,31 +2457,27 @@ function HfCaretOverlay(t0) {
2743
2457
  editorView,
2744
2458
  zoom
2745
2459
  ];
2746
- $[1] = editorView;
2747
- $[2] = hiddenHost;
2748
- $[3] = pagesContainer;
2749
- $[4] = selection.from;
2750
- $[5] = selection.kind;
2751
- $[6] = selection.pageNumber;
2752
- $[7] = selection.rId;
2753
- $[8] = selection.to;
2754
- $[9] = zoom;
2755
- $[10] = t2;
2756
- $[11] = t3;
2757
- } else {
2758
- t2 = $[10];
2759
- t3 = $[11];
2760
- }
2460
+ $[7] = editorView;
2461
+ $[8] = hiddenHost;
2462
+ $[9] = pagesContainer;
2463
+ $[10] = selection.from;
2464
+ $[11] = selection.kind;
2465
+ $[12] = selection.pageNumber;
2466
+ $[13] = selection.rId;
2467
+ $[14] = selection.to;
2468
+ $[15] = zoom;
2469
+ $[16] = t3;
2470
+ } else t3 = $[16];
2761
2471
  useEffect(t2, t3);
2762
2472
  if (!pagesContainer) return null;
2763
2473
  let t4;
2764
- if ($[12] !== rangeRects) {
2474
+ if ($[17] !== rangeRects) {
2765
2475
  t4 = rangeRects.map(_temp$8);
2766
- $[12] = rangeRects;
2767
- $[13] = t4;
2768
- } else t4 = $[13];
2476
+ $[17] = rangeRects;
2477
+ $[18] = t4;
2478
+ } else t4 = $[18];
2769
2479
  let t5;
2770
- if ($[14] !== caret) {
2480
+ if ($[19] !== caret) {
2771
2481
  t5 = caret && /* @__PURE__ */ jsx("div", {
2772
2482
  "data-testid": "hf-caret",
2773
2483
  style: {
@@ -2782,39 +2492,39 @@ function HfCaretOverlay(t0) {
2782
2492
  animation: "folio-caret-blink 1060ms steps(1, end) infinite"
2783
2493
  }
2784
2494
  });
2785
- $[14] = caret;
2786
- $[15] = t5;
2787
- } else t5 = $[15];
2495
+ $[19] = caret;
2496
+ $[20] = t5;
2497
+ } else t5 = $[20];
2788
2498
  let t6;
2789
- if ($[16] !== t4 || $[17] !== t5) {
2499
+ if ($[21] !== t4 || $[22] !== t5) {
2790
2500
  t6 = /* @__PURE__ */ jsxs(Fragment, { children: [t4, t5] });
2791
- $[16] = t4;
2792
- $[17] = t5;
2793
- $[18] = t6;
2794
- } else t6 = $[18];
2501
+ $[21] = t4;
2502
+ $[22] = t5;
2503
+ $[23] = t6;
2504
+ } else t6 = $[23];
2795
2505
  let t7;
2796
- if ($[19] !== pagesContainer || $[20] !== t6) {
2506
+ if ($[24] !== pagesContainer || $[25] !== t6) {
2797
2507
  t7 = createPortal(t6, pagesContainer);
2798
- $[19] = pagesContainer;
2799
- $[20] = t6;
2800
- $[21] = t7;
2801
- } else t7 = $[21];
2508
+ $[24] = pagesContainer;
2509
+ $[25] = t6;
2510
+ $[26] = t7;
2511
+ } else t7 = $[26];
2802
2512
  return t7;
2803
2513
  }
2804
- function _temp$8(r_0, i) {
2514
+ function _temp$8(r, i) {
2805
2515
  return /* @__PURE__ */ jsx("div", {
2806
2516
  "data-testid": "hf-selection-rect",
2807
2517
  style: {
2808
2518
  position: "absolute",
2809
- left: r_0.x,
2810
- top: r_0.y,
2811
- width: r_0.width,
2812
- height: r_0.height,
2519
+ left: r.x,
2520
+ top: r.y,
2521
+ width: r.width,
2522
+ height: r.height,
2813
2523
  backgroundColor: "var(--doc-selection, rgba(66, 133, 244, 0.3))",
2814
2524
  pointerEvents: "none",
2815
2525
  zIndex: 10
2816
2526
  }
2817
- }, `hf-sel-${i}-${r_0.x}-${r_0.y}-${r_0.width}`);
2527
+ }, `hf-sel-${i}-${r.x}-${r.y}-${r.width}`);
2818
2528
  }
2819
2529
  function renderHfFromContentOrPm(hf, rId, hfPMs, contentWidth, metrics, options) {
2820
2530
  if (!hf) return;
@@ -3548,87 +3258,17 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3548
3258
  * This uses the browser's text rendering to get precise pixel positions.
3549
3259
  */
3550
3260
  const getCaretFromDom = useCallback((pmPos_0, currentZoom = 1) => {
3551
- if (!pagesContainerRef.current) return null;
3552
- const overlay = pagesContainerRef.current.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3261
+ const pagesContainer = pagesContainerRef.current;
3262
+ if (!pagesContainer) return null;
3263
+ const overlay = pagesContainer.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3553
3264
  if (!overlay) return null;
3554
- const overlayRect = overlay.getBoundingClientRect();
3555
- const spans = findBodyPmSpans(pagesContainerRef.current);
3556
- const collapsedTarget = findCollapsedLineEdgeCaretTarget(spans, pmPos_0);
3557
- if (collapsedTarget) return {
3558
- x: (collapsedTarget.geometry.left - overlayRect.left) / currentZoom,
3559
- y: (collapsedTarget.geometry.top - overlayRect.top) / currentZoom,
3560
- height: getLineHeight(collapsedTarget.span),
3561
- pageIndex: getPageIndex(collapsedTarget.span)
3562
- };
3563
- for (const spanEl of spans) {
3564
- const pmStart = Number(spanEl.dataset["pmStart"]);
3565
- const pmEnd = Number(spanEl.dataset["pmEnd"]);
3566
- if (spanEl.classList.contains("layout-run-tab")) {
3567
- if (pmPos_0 >= pmStart && pmPos_0 < pmEnd) {
3568
- const spanRect = spanEl.getBoundingClientRect();
3569
- return {
3570
- x: (spanRect.left - overlayRect.left) / currentZoom,
3571
- y: (spanRect.top - overlayRect.top) / currentZoom,
3572
- height: getLineHeight(spanEl),
3573
- pageIndex: getPageIndex(spanEl)
3574
- };
3575
- }
3576
- continue;
3577
- }
3578
- if (spanEl.classList.contains("layout-empty-run") && pmPos_0 >= pmStart && pmPos_0 <= pmEnd) {
3579
- const spanRect_0 = spanEl.getBoundingClientRect();
3580
- return {
3581
- x: (spanRect_0.left - overlayRect.left) / currentZoom,
3582
- y: (spanRect_0.top - overlayRect.top) / currentZoom,
3583
- height: getLineHeight(spanEl, Math.max(16, spanRect_0.height)),
3584
- pageIndex: getPageIndex(spanEl)
3585
- };
3586
- }
3587
- if (pmPos_0 >= pmStart && pmPos_0 <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
3588
- const textNode = spanEl.firstChild;
3589
- const charIndex = Math.min(pmPos_0 - pmStart, textNode.length);
3590
- const range = spanEl.ownerDocument.createRange();
3591
- range.setStart(textNode, charIndex);
3592
- range.setEnd(textNode, charIndex);
3593
- const rangeRect = range.getBoundingClientRect();
3594
- const spanRect_1 = spanEl.getBoundingClientRect();
3595
- const useSpanStart = charIndex === 0 || rangeRect.width === 0 && rangeRect.left < spanRect_1.left;
3596
- const caretLeft = useSpanStart ? spanRect_1.left : rangeRect.left;
3597
- const caretTop = rangeRect.height > 0 && !useSpanStart ? rangeRect.top : spanRect_1.top;
3598
- return {
3599
- x: (caretLeft - overlayRect.left) / currentZoom,
3600
- y: (caretTop - overlayRect.top) / currentZoom,
3601
- height: getLineHeight(spanEl),
3602
- pageIndex: getPageIndex(spanEl)
3603
- };
3604
- }
3605
- if (pmPos_0 >= pmStart && pmPos_0 <= pmEnd) {
3606
- const spanRect_2 = spanEl.getBoundingClientRect();
3607
- return {
3608
- x: (spanRect_2.left - overlayRect.left) / currentZoom,
3609
- y: (spanRect_2.top - overlayRect.top) / currentZoom,
3610
- height: getLineHeight(spanEl, Math.max(16, spanRect_2.height)),
3611
- pageIndex: getPageIndex(spanEl)
3612
- };
3613
- }
3614
- }
3615
- const emptyRuns = findBodyEmptyRuns(pagesContainerRef.current);
3616
- for (const emptyRun of emptyRuns) {
3617
- const paragraph = closestHtmlElement(emptyRun, ".layout-paragraph");
3618
- if (!paragraph) continue;
3619
- const pmStart_0 = Number(paragraph.dataset["pmStart"]);
3620
- const pmEnd_0 = Number(paragraph.dataset["pmEnd"]);
3621
- if (pmPos_0 >= pmStart_0 && pmPos_0 <= pmEnd_0) {
3622
- const runRect = emptyRun.getBoundingClientRect();
3623
- return {
3624
- x: (runRect.left - overlayRect.left) / currentZoom,
3625
- y: (runRect.top - overlayRect.top) / currentZoom,
3626
- height: getLineHeight(emptyRun),
3627
- pageIndex: getPageIndex(paragraph)
3628
- };
3629
- }
3630
- }
3631
- return null;
3265
+ const caret = getCaretPositionFromDom(pagesContainer, pmPos_0, overlay.getBoundingClientRect());
3266
+ return caret ? {
3267
+ x: caret.x / currentZoom,
3268
+ y: caret.y / currentZoom,
3269
+ height: caret.height / currentZoom,
3270
+ pageIndex: caret.pageIndex
3271
+ } : null;
3632
3272
  }, []);
3633
3273
  const refreshBodyImeCaretAnchor = useCallback(() => {
3634
3274
  const view_1 = hiddenPMRef.current?.getView();
@@ -3727,12 +3367,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3727
3367
  setCaretPosition(null);
3728
3368
  loadSelectionGeometry().then(({ getCaretPosition }) => {
3729
3369
  if (!isCurrentRequest()) return;
3730
- const caret = getCaretPosition(layout, blocks, measures, from);
3731
- if (caret) {
3370
+ const caret_0 = getCaretPosition(layout, blocks, measures, from);
3371
+ if (caret_0) {
3732
3372
  const fallbackCaret = {
3733
- ...caret,
3734
- x: caret.x + (pageRect.left - overlayRect_2.left) / zoom,
3735
- y: caret.y + (pageRect.top - overlayRect_2.top) / zoom
3373
+ ...caret_0,
3374
+ x: caret_0.x + (pageRect.left - overlayRect_2.left) / zoom,
3375
+ y: caret_0.y + (pageRect.top - overlayRect_2.top) / zoom
3736
3376
  };
3737
3377
  setCaretPosition(fallbackCaret);
3738
3378
  syncImeCaretAnchor({
@@ -3780,45 +3420,13 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3780
3420
  const overlay_3 = pagesContainerRef.current?.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3781
3421
  if (overlay_3 && pagesContainerRef.current) {
3782
3422
  const overlayRect_3 = overlay_3.getBoundingClientRect();
3783
- const domRects = [];
3784
- const spans_0 = findBodyPmSpans(pagesContainerRef.current);
3785
- for (const spanEl_0 of spans_0) {
3786
- const pmStart_1 = Number(spanEl_0.dataset["pmStart"]);
3787
- if (Number(spanEl_0.dataset["pmEnd"]) > from && pmStart_1 < to) {
3788
- if (spanEl_0.classList.contains("layout-run-tab")) {
3789
- const spanRect_3 = spanEl_0.getBoundingClientRect();
3790
- domRects.push({
3791
- x: (spanRect_3.left - overlayRect_3.left) / zoom,
3792
- y: (spanRect_3.top - overlayRect_3.top) / zoom,
3793
- width: spanRect_3.width / zoom,
3794
- height: spanRect_3.height / zoom,
3795
- pageIndex: getPageIndex(spanEl_0)
3796
- });
3797
- continue;
3798
- }
3799
- let textNode_0 = null;
3800
- if (spanEl_0.firstChild?.nodeType === Node.TEXT_NODE) textNode_0 = spanEl_0.firstChild;
3801
- else if (spanEl_0.firstChild instanceof HTMLElement && spanEl_0.firstChild.tagName === "A" && spanEl_0.firstChild.firstChild?.nodeType === Node.TEXT_NODE) textNode_0 = spanEl_0.firstChild.firstChild;
3802
- if (!textNode_0) continue;
3803
- const ownerDoc_0 = spanEl_0.ownerDocument;
3804
- const startChar = Math.max(0, from - pmStart_1);
3805
- const endChar = Math.min(textNode_0.length, to - pmStart_1);
3806
- if (startChar < endChar) {
3807
- const range_0 = ownerDoc_0.createRange();
3808
- range_0.setStart(textNode_0, startChar);
3809
- range_0.setEnd(textNode_0, endChar);
3810
- const clientRects = range_0.getClientRects();
3811
- const pageIndex = getPageIndex(spanEl_0);
3812
- for (const rect_0 of Array.from(clientRects)) domRects.push({
3813
- x: (rect_0.left - overlayRect_3.left) / zoom,
3814
- y: (rect_0.top - overlayRect_3.top) / zoom,
3815
- width: rect_0.width / zoom,
3816
- height: rect_0.height / zoom,
3817
- pageIndex
3818
- });
3819
- }
3820
- }
3821
- }
3423
+ const domRects = getSelectionRectsFromDom(pagesContainerRef.current, from, to, overlayRect_3).map((rect_0) => ({
3424
+ pageIndex: rect_0.pageIndex,
3425
+ x: rect_0.x / zoom,
3426
+ y: rect_0.y / zoom,
3427
+ width: rect_0.width / zoom,
3428
+ height: rect_0.height / zoom
3429
+ }));
3822
3430
  if (domRects.length > 0) setSelectionRects(domRects);
3823
3431
  else {
3824
3432
  const firstPage_0 = pagesContainerRef.current.querySelector(".layout-page");
@@ -3855,6 +3463,24 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3855
3463
  ]);
3856
3464
  const updateSelectionOverlayRef = useRef(updateSelectionOverlay);
3857
3465
  updateSelectionOverlayRef.current = updateSelectionOverlay;
3466
+ useEffect(() => {
3467
+ const pagesContainer_0 = pagesContainerRef.current;
3468
+ if (!pagesContainer_0) return void 0;
3469
+ let animationFrame = null;
3470
+ const repaintSelection = () => {
3471
+ if (animationFrame !== null) cancelAnimationFrame(animationFrame);
3472
+ animationFrame = requestAnimationFrame(() => {
3473
+ animationFrame = null;
3474
+ const state_4 = hiddenPMRef.current?.getState();
3475
+ if (state_4) updateSelectionOverlayRef.current(state_4);
3476
+ });
3477
+ };
3478
+ pagesContainer_0.addEventListener(PAINTER_PAINTED_EVENT, repaintSelection);
3479
+ return () => {
3480
+ if (animationFrame !== null) cancelAnimationFrame(animationFrame);
3481
+ pagesContainer_0.removeEventListener(PAINTER_PAINTED_EVENT, repaintSelection);
3482
+ };
3483
+ }, []);
3858
3484
  const updateAnonymizationOverlay = useCallback(() => {
3859
3485
  const isCurrentRequest_0 = anonymizationOverlayRequestGate.begin();
3860
3486
  const matches = anonymizationMatchesRef.current;
@@ -3862,13 +3488,13 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3862
3488
  setAnonymizationRectGroups([]);
3863
3489
  return;
3864
3490
  }
3865
- const pagesContainer = pagesContainerRef.current;
3866
- if (!pagesContainer) {
3491
+ const pagesContainer_1 = pagesContainerRef.current;
3492
+ if (!pagesContainer_1) {
3867
3493
  setAnonymizationRectGroups([]);
3868
3494
  return;
3869
3495
  }
3870
- const overlay_4 = pagesContainer.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3871
- const firstPage_1 = pagesContainer.querySelector(".layout-page");
3496
+ const overlay_4 = pagesContainer_1.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3497
+ const firstPage_1 = pagesContainer_1.querySelector(".layout-page");
3872
3498
  if (!overlay_4 || !firstPage_1) {
3873
3499
  setAnonymizationRectGroups([]);
3874
3500
  return;
@@ -3877,42 +3503,21 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3877
3503
  const pageRect_1 = firstPage_1.getBoundingClientRect();
3878
3504
  const pageOffsetX_0 = (pageRect_1.left - overlayRect_4.left) / zoom;
3879
3505
  const pageOffsetY_0 = (pageRect_1.top - overlayRect_4.top) / zoom;
3880
- const pmSpans = findBodyPmSpans(pagesContainer);
3506
+ const pmSpans = findBodyPmSpans(pagesContainer_1);
3881
3507
  const layoutFallbackMatches = [];
3882
3508
  const rectsForMatch = (match, from_0, to_0) => {
3883
3509
  const domRects_0 = [];
3884
- for (const spanEl_1 of pmSpans) {
3885
- const pmStart_2 = Number(spanEl_1.dataset["pmStart"]);
3886
- if (!(Number(spanEl_1.dataset["pmEnd"]) > from_0 && pmStart_2 < to_0)) continue;
3887
- if (spanEl_1.classList.contains("layout-run-tab")) {
3888
- const spanRect_4 = spanEl_1.getBoundingClientRect();
3889
- domRects_0.push({
3890
- x: (spanRect_4.left - overlayRect_4.left) / zoom,
3891
- y: (spanRect_4.top - overlayRect_4.top) / zoom,
3892
- width: spanRect_4.width / zoom,
3893
- height: spanRect_4.height / zoom,
3894
- pageIndex: getPageIndex(spanEl_1)
3895
- });
3896
- continue;
3897
- }
3898
- let textNode_1 = null;
3899
- if (spanEl_1.firstChild?.nodeType === Node.TEXT_NODE) textNode_1 = spanEl_1.firstChild;
3900
- else if (spanEl_1.firstChild instanceof HTMLElement && spanEl_1.firstChild.tagName === "A" && spanEl_1.firstChild.firstChild?.nodeType === Node.TEXT_NODE) textNode_1 = spanEl_1.firstChild.firstChild;
3901
- if (!textNode_1) continue;
3902
- const ownerDoc_1 = spanEl_1.ownerDocument;
3903
- const startChar_0 = Math.max(0, from_0 - pmStart_2);
3904
- const endChar_0 = Math.min(textNode_1.length, to_0 - pmStart_2);
3905
- if (startChar_0 >= endChar_0) continue;
3906
- const range_1 = ownerDoc_1.createRange();
3907
- range_1.setStart(textNode_1, startChar_0);
3908
- range_1.setEnd(textNode_1, endChar_0);
3909
- const pageIndex_0 = getPageIndex(spanEl_1);
3910
- for (const rect_2 of Array.from(range_1.getClientRects())) domRects_0.push({
3510
+ for (const spanEl of pmSpans) {
3511
+ const measurement = measurePaintedSpanRange(spanEl, from_0, to_0);
3512
+ if (measurement.type === "outside") continue;
3513
+ const pageIndex = getPageIndex(spanEl);
3514
+ const measuredRects = measurement.type === "element" ? [measurement.rect] : measurement.rects;
3515
+ for (const rect_2 of measuredRects) domRects_0.push({
3911
3516
  x: (rect_2.left - overlayRect_4.left) / zoom,
3912
3517
  y: (rect_2.top - overlayRect_4.top) / zoom,
3913
3518
  width: rect_2.width / zoom,
3914
3519
  height: rect_2.height / zoom,
3915
- pageIndex: pageIndex_0
3520
+ pageIndex
3916
3521
  });
3917
3522
  }
3918
3523
  if (domRects_0.length > 0) return domRects_0;
@@ -3971,15 +3576,15 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3971
3576
  const anchor_0 = current.anchor;
3972
3577
  loadSelectionGeometry().then(({ getCaretPosition: getCaretPosition_0 }) => {
3973
3578
  if (!isCurrentRequest_1()) return;
3974
- const caret_0 = getCaretPosition_0(layout, blocks, measures, anchor_0);
3579
+ const caret_1 = getCaretPosition_0(layout, blocks, measures, anchor_0);
3975
3580
  if (!isCurrentRequest_1()) return;
3976
- if (caret_0 === null) {
3581
+ if (caret_1 === null) {
3977
3582
  setAutocompleteCaret(null);
3978
3583
  return;
3979
3584
  }
3980
- const pagesContainer_0 = pagesContainerRef.current;
3981
- const overlay_5 = pagesContainer_0?.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3982
- const firstPage_2 = pagesContainer_0?.querySelector(".layout-page");
3585
+ const pagesContainer_2 = pagesContainerRef.current;
3586
+ const overlay_5 = pagesContainer_2?.parentElement?.querySelector("[data-testid=\"selection-overlay\"]");
3587
+ const firstPage_2 = pagesContainer_2?.querySelector(".layout-page");
3983
3588
  if (!overlay_5 || !firstPage_2) {
3984
3589
  setAutocompleteCaret(null);
3985
3590
  return;
@@ -3989,12 +3594,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3989
3594
  const pageOffsetX_1 = (pageRect_2.left - overlayRect_5.left) / zoom;
3990
3595
  const pageOffsetY_1 = (pageRect_2.top - overlayRect_5.top) / zoom;
3991
3596
  if (!isCurrentRequest_1()) return;
3992
- const caretPage = layout.pages.at(caret_0.pageIndex);
3993
- const maxWidth = caretPage ? Math.max(AUTOCOMPLETE_GHOST_MIN_WIDTH, caretPage.size.w - caretPage.margins.right - caret_0.x) : void 0;
3597
+ const caretPage = layout.pages.at(caret_1.pageIndex);
3598
+ const maxWidth = caretPage ? Math.max(AUTOCOMPLETE_GHOST_MIN_WIDTH, caretPage.size.w - caretPage.margins.right - caret_1.x) : void 0;
3994
3599
  setAutocompleteCaret({
3995
- x: caret_0.x + pageOffsetX_1,
3996
- y: caret_0.y + pageOffsetY_1,
3997
- lineHeight: caret_0.height,
3600
+ x: caret_1.x + pageOffsetX_1,
3601
+ y: caret_1.y + pageOffsetY_1,
3602
+ lineHeight: caret_1.height,
3998
3603
  maxWidth
3999
3604
  });
4000
3605
  setAutocompleteText(current.text);
@@ -4010,17 +3615,17 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4010
3615
  const updateDirectivesOverlay = useCallback(() => {
4011
3616
  const isCurrentRequest_2 = directivesOverlayRequestGate.begin();
4012
3617
  const previewedStarts = new Set(templatePreviewRef.current.entries.map((entry) => entry.from));
4013
- const ranges = directivesRef.current.filter((range_2) => !(range_2.kind === "placeholder" && previewedStarts.has(range_2.from)));
4014
- const pagesContainer_1 = pagesContainerRef.current;
4015
- if (ranges.length === 0 || !pagesContainer_1) {
3618
+ const ranges = directivesRef.current.filter((range) => !(range.kind === "placeholder" && previewedStarts.has(range.from)));
3619
+ const pagesContainer_3 = pagesContainerRef.current;
3620
+ if (ranges.length === 0 || !pagesContainer_3) {
4016
3621
  setDirectiveRectGroups([]);
4017
3622
  setDirectiveGutter(null);
4018
3623
  return;
4019
3624
  }
4020
- setDirectiveGutter(measureDirectiveGutter(pagesContainer_1, zoom));
3625
+ setDirectiveGutter(measureDirectiveGutter(pagesContainer_3, zoom));
4021
3626
  (async () => {
4022
3627
  const projected = await projectRangesToRects(ranges, {
4023
- pagesContainer: pagesContainer_1,
3628
+ pagesContainer: pagesContainer_3,
4024
3629
  zoom,
4025
3630
  layout,
4026
3631
  blocks,
@@ -4039,8 +3644,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4039
3644
  const isCurrentRequest_3 = aiSuggestionsOverlayRequestGate.begin();
4040
3645
  const { suggestions, focusedId } = aiSuggestionsRef.current;
4041
3646
  const pending = suggestions.filter((suggestion) => suggestion.status === "pending" && suggestion.range.from >= 0 && suggestion.range.to > suggestion.range.from);
4042
- const pagesContainer_2 = pagesContainerRef.current;
4043
- if (pending.length === 0 || !pagesContainer_2) {
3647
+ const pagesContainer_4 = pagesContainerRef.current;
3648
+ if (pending.length === 0 || !pagesContainer_4) {
4044
3649
  setAiSuggestionRectGroups((prev) => prev.length === 0 ? prev : []);
4045
3650
  return;
4046
3651
  }
@@ -4050,20 +3655,20 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4050
3655
  to: suggestion_0.range.to,
4051
3656
  suggestion: suggestion_0
4052
3657
  })), {
4053
- pagesContainer: pagesContainer_2,
3658
+ pagesContainer: pagesContainer_4,
4054
3659
  zoom,
4055
3660
  layout,
4056
3661
  blocks,
4057
3662
  measures
4058
3663
  });
4059
3664
  if (!isCurrentRequest_3()) return;
4060
- const focused = projected_0.find(({ range: range_3 }) => range_3.suggestion.id === focusedId);
4061
- const fonts = collectRunFontsAtPmPositions(pagesContainer_2, focused ? [focused.range.from] : []);
4062
- setAiSuggestionRectGroups(projected_0.map(({ range: range_4, rects: rects_2 }) => ({
4063
- suggestion: range_4.suggestion,
3665
+ const focused = projected_0.find(({ range: range_0 }) => range_0.suggestion.id === focusedId);
3666
+ const fonts = collectRunFontsAtPmPositions(pagesContainer_4, focused ? [focused.range.from] : []);
3667
+ setAiSuggestionRectGroups(projected_0.map(({ range: range_1, rects: rects_2 }) => ({
3668
+ suggestion: range_1.suggestion,
4064
3669
  rects: rects_2,
4065
- focused: range_4.suggestion.id === focusedId,
4066
- font: range_4.suggestion.id === focusedId ? fonts.get(range_4.from) ?? null : null
3670
+ focused: range_1.suggestion.id === focusedId,
3671
+ font: range_1.suggestion.id === focusedId ? fonts.get(range_1.from) ?? null : null
4067
3672
  })));
4068
3673
  })();
4069
3674
  }, [
@@ -4075,15 +3680,15 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4075
3680
  ]);
4076
3681
  const updatePassageHighlightOverlay = useCallback(() => {
4077
3682
  const isCurrentRequest_4 = passageHighlightOverlayRequestGate.begin();
4078
- const range_5 = passageHighlightRangeRef.current;
4079
- const pagesContainer_3 = pagesContainerRef.current;
4080
- if (range_5 === null || !pagesContainer_3) {
3683
+ const range_2 = passageHighlightRangeRef.current;
3684
+ const pagesContainer_5 = pagesContainerRef.current;
3685
+ if (range_2 === null || !pagesContainer_5) {
4081
3686
  setPassageHighlightRects((prev_0) => prev_0.length === 0 ? prev_0 : []);
4082
3687
  return;
4083
3688
  }
4084
3689
  (async () => {
4085
- const projected_1 = await projectRangesToRects([range_5], {
4086
- pagesContainer: pagesContainer_3,
3690
+ const projected_1 = await projectRangesToRects([range_2], {
3691
+ pagesContainer: pagesContainer_5,
4087
3692
  zoom,
4088
3693
  layout,
4089
3694
  blocks,
@@ -4099,16 +3704,16 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4099
3704
  measures,
4100
3705
  zoom
4101
3706
  ]);
4102
- const setPassageHighlightImpl = useCallback((range_6) => {
4103
- passageHighlightRangeRef.current = range_6;
4104
- if (range_6 === null) {
3707
+ const setPassageHighlightImpl = useCallback((range_3) => {
3708
+ passageHighlightRangeRef.current = range_3;
3709
+ if (range_3 === null) {
4105
3710
  passageHighlightOverlayRequestGate.invalidate();
4106
3711
  setPassageHighlightRects((prev_1) => prev_1.length === 0 ? prev_1 : []);
4107
3712
  return;
4108
3713
  }
4109
3714
  updatePassageHighlightOverlay();
4110
3715
  }, [passageHighlightOverlayRequestGate, updatePassageHighlightOverlay]);
4111
- const hideSelectionOverlayDuringInput = useCallback((state_4) => {
3716
+ const hideSelectionOverlayDuringInput = useCallback((state_5) => {
4112
3717
  selectionOverlayRequestGate.invalidate();
4113
3718
  suppressSelectionOverlayRef.current = true;
4114
3719
  setCaretPosition(null);
@@ -4117,7 +3722,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4117
3722
  revealSelectionOverlayTimerRef.current = window.setTimeout(() => {
4118
3723
  revealSelectionOverlayTimerRef.current = null;
4119
3724
  suppressSelectionOverlayRef.current = false;
4120
- updateSelectionOverlay(hiddenPMRef.current?.getState() ?? state_4);
3725
+ updateSelectionOverlay(hiddenPMRef.current?.getState() ?? state_5);
4121
3726
  }, SELECTION_REVEAL_AFTER_INPUT_DELAY);
4122
3727
  }, [selectionOverlayRequestGate, updateSelectionOverlay]);
4123
3728
  useEffect(() => () => {
@@ -4142,7 +3747,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4142
3747
  /**
4143
3748
  * Handle PM transaction - re-layout on content/selection change.
4144
3749
  */
4145
- const handleTransaction = useCallback((transaction, newState) => {
3750
+ const handleTransaction = useCallback(({ transactions, newState, docChanged }) => {
4146
3751
  const nextMatches = anonymizationDecorationsKey.getState(newState)?.matches ?? [];
4147
3752
  const matchesChanged = nextMatches !== anonymizationMatchesRef.current;
4148
3753
  anonymizationMatchesRef.current = nextMatches;
@@ -4155,7 +3760,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4155
3760
  const nextDirectives = templateDirectivesKey.getState(newState)?.ranges ?? [];
4156
3761
  if (nextDirectives !== directivesRef.current) {
4157
3762
  directivesRef.current = nextDirectives;
4158
- if (!transaction.docChanged) updateDirectivesOverlay();
3763
+ if (!docChanged) updateDirectivesOverlay();
4159
3764
  }
4160
3765
  const nextPreviewState = templatePreviewValuesKey.getState(newState);
4161
3766
  const nextPreviewEntries = nextPreviewState?.entries ?? EMPTY_TEMPLATE_PREVIEW_ENTRIES;
@@ -4166,7 +3771,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4166
3771
  entries: nextPreviewEntries,
4167
3772
  mode: nextPreviewMode
4168
3773
  };
4169
- if (!transaction.docChanged) if (nextPreviewMode !== previousPreview.mode) scheduleLayout(newState, null);
3774
+ if (!docChanged) if (nextPreviewMode !== previousPreview.mode) scheduleLayout(newState, null);
4170
3775
  else {
4171
3776
  const previewDirty = templatePreviewDirtyRange(previousPreview.entries, nextPreviewEntries);
4172
3777
  if (previewDirty) scheduleLayout(newState, previewDirty);
@@ -4180,9 +3785,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4180
3785
  suggestions: nextAiSuggestions,
4181
3786
  focusedId: nextAiFocusedId
4182
3787
  };
4183
- if (!transaction.docChanged) updateAISuggestionsOverlay();
3788
+ if (!docChanged) updateAISuggestionsOverlay();
4184
3789
  }
4185
- if (transaction.docChanged) {
3790
+ if (docChanged) {
4186
3791
  syncCoordinator.incrementStateSeq();
4187
3792
  if (passageHighlightRangeRef.current !== null) {
4188
3793
  passageHighlightRangeRef.current = null;
@@ -4190,11 +3795,11 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4190
3795
  setPassageHighlightRects((prev_2) => prev_2.length === 0 ? prev_2 : []);
4191
3796
  }
4192
3797
  hideSelectionOverlayDuringInput(newState);
4193
- scheduleLayout(newState, getTransactionDirtyRange(transaction));
3798
+ scheduleLayout(newState, getTransactionsDirtyRange(transactions));
4194
3799
  scheduleDocumentChangeNotification();
4195
3800
  }
4196
3801
  syncCoordinator.requestRender();
4197
- if (!transaction.docChanged) updateSelectionOverlay(newState);
3802
+ if (!docChanged) updateSelectionOverlay(newState);
4198
3803
  }, [
4199
3804
  scheduleLayout,
4200
3805
  scheduleDocumentChangeNotification,
@@ -4224,8 +3829,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4224
3829
  */
4225
3830
  const [hfCaretSelection, setHfCaretSelection] = useState(null);
4226
3831
  const activeHfPageNumberRef = useRef(null);
4227
- const handleHfPmTransaction = useCallback((rId, kind, view_2, docChanged, selectionChanged) => {
4228
- if (docChanged) {
3832
+ const handleHfPmTransaction = useCallback((rId, kind, view_2, docChanged_0, selectionChanged) => {
3833
+ if (docChanged_0) {
4229
3834
  let bodyState = hiddenPMRef.current?.getState();
4230
3835
  if (!bodyState && precomputedInitialStateRef.current) bodyState = precomputedInitialStateRef.current;
4231
3836
  if (!bodyState) {
@@ -4234,7 +3839,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4234
3839
  }
4235
3840
  if (bodyState) scheduleLayout(bodyState, null);
4236
3841
  }
4237
- if (docChanged || selectionChanged) {
3842
+ if (docChanged_0 || selectionChanged) {
4238
3843
  const { from: from_1, to: to_1 } = view_2.state.selection;
4239
3844
  const pageNumber = activeHfPageNumberRef.current;
4240
3845
  setHfCaretSelection({
@@ -4251,12 +3856,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4251
3856
  });
4252
3857
  }
4253
3858
  }, [scheduleLayout, ensureHiddenEditorView]);
4254
- const handleNoteStoryTransaction = useCallback((view_3, docChanged_0, selectionChanged_0) => {
4255
- if (docChanged_0) {
3859
+ const handleNoteStoryTransaction = useCallback((view_3, docChanged_1, selectionChanged_0) => {
3860
+ if (docChanged_1) {
4256
3861
  const bodyState_0 = hiddenPMRef.current?.getState();
4257
3862
  if (bodyState_0) scheduleLayout(bodyState_0, null);
4258
3863
  }
4259
- if (docChanged_0 || selectionChanged_0) {
3864
+ if (docChanged_1 || selectionChanged_0) {
4260
3865
  const { from: from_2, to: to_2 } = view_3.state.selection;
4261
3866
  onSelectionChangeRef.current?.(from_2, to_2);
4262
3867
  folioEmitterRef.current.emit("selectionChange", {
@@ -4278,12 +3883,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4278
3883
  /**
4279
3884
  * Handle selection change from PM.
4280
3885
  */
4281
- const handleSelectionChange = useCallback((state_5) => {
4282
- const { selection: selection_2 } = state_5;
3886
+ const handleSelectionChange = useCallback((state_6) => {
3887
+ const { selection: selection_2 } = state_6;
4283
3888
  if (selection_2 instanceof NodeSelection && selection_2.node.type.name === "image") {
4284
3889
  setSelectionRects([]);
4285
3890
  setCaretPosition(null);
4286
- } else if (syncCoordinator.isSafeToRender()) updateSelectionOverlay(state_5);
3891
+ } else if (syncCoordinator.isSafeToRender()) updateSelectionOverlay(state_6);
4287
3892
  requestAnimationFrame(() => {
4288
3893
  const view_4 = hiddenPMRef.current?.getView();
4289
3894
  if (!view_4) {
@@ -4405,9 +4010,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4405
4010
  });
4406
4011
  }, [layout, scrollToPositionImpl]);
4407
4012
  const scrollToParaIdImpl = useCallback((paraId, options_2) => {
4408
- const state_6 = hiddenPMRef.current?.getState();
4409
- if (!state_6) return false;
4410
- const startPos = findStartPosForParaId(state_6.doc, paraId);
4013
+ const state_7 = hiddenPMRef.current?.getState();
4014
+ if (!state_7) return false;
4015
+ const startPos = findStartPosForParaId(state_7.doc, paraId);
4411
4016
  if (startPos == null || startPos < 0) return false;
4412
4017
  scrollToPositionImpl(startPos);
4413
4018
  requestAnimationFrame(() => {
@@ -4415,8 +4020,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4415
4020
  const pages = pagesContainerRef.current;
4416
4021
  if (pages) flashParagraphFragmentsByParaId(pages, paraId, options_2.highlight);
4417
4022
  }
4418
- const targetNode = state_6.doc.nodeAt(startPos);
4419
- const inner = targetNode?.isTextblock === true ? Math.min(startPos + 1 + targetNode.content.size, state_6.doc.content.size) : Math.min(startPos + 1, state_6.doc.content.size);
4023
+ const targetNode = state_7.doc.nodeAt(startPos);
4024
+ const inner = targetNode?.isTextblock === true ? Math.min(startPos + 1 + targetNode.content.size, state_7.doc.content.size) : Math.min(startPos + 1, state_7.doc.content.size);
4420
4025
  hiddenPMRef.current?.setSelection(inner);
4421
4026
  hiddenPMRef.current?.focus();
4422
4027
  });
@@ -4671,9 +4276,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4671
4276
  if (!readOnly && imageEl) {
4672
4277
  e.preventDefault();
4673
4278
  e.stopPropagation();
4674
- const pmStart_3 = imageEl.dataset["pmStart"];
4675
- if (pmStart_3 !== void 0) {
4676
- const pos_1 = Number.parseInt(pmStart_3, 10);
4279
+ const pmStart = imageEl.dataset["pmStart"];
4280
+ if (pmStart !== void 0) {
4281
+ const pos_1 = Number.parseInt(pmStart, 10);
4677
4282
  const hfSlot = hfEditMode ? findHfSlotForTarget(imageEl) : null;
4678
4283
  const hfView_0 = hfSlot ? hfPMsRef.current?.getView(hfSlot.rId) : null;
4679
4284
  if (hfView_0) {
@@ -4857,10 +4462,10 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4857
4462
  const view_12 = (resizingHfSurfaceRef.current ? hfPMsRef.current?.getView(resizingHfSurfaceRef.current.rId) : hiddenPMRef.current?.getView()) ?? null;
4858
4463
  resizingHfSurfaceRef.current = null;
4859
4464
  if (view_12) {
4860
- const pmStart_4 = resizeTablePmStartRef.current;
4465
+ const pmStart_0 = resizeTablePmStartRef.current;
4861
4466
  const colIdx = resizeColumnIndexRef.current;
4862
4467
  const { left: newLeft, right: newRight } = resizeOrigWidthsRef.current;
4863
- const $pos_5 = view_12.state.doc.resolve(pmStart_4 + 1);
4468
+ const $pos_5 = view_12.state.doc.resolve(pmStart_0 + 1);
4864
4469
  for (let d_3 = $pos_5.depth; d_3 >= 0; d_3--) {
4865
4470
  const node_4 = $pos_5.node(d_3);
4866
4471
  if (node_4.type.name === "table") {
@@ -4907,10 +4512,10 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4907
4512
  const view_13 = (resizingHfSurfaceRef.current ? hfPMsRef.current?.getView(resizingHfSurfaceRef.current.rId) : hiddenPMRef.current?.getView()) ?? null;
4908
4513
  resizingHfSurfaceRef.current = null;
4909
4514
  if (view_13) {
4910
- const pmStart_5 = resizeRowTablePmStartRef.current;
4515
+ const pmStart_1 = resizeRowTablePmStartRef.current;
4911
4516
  const rowIdx = resizeRowIndexRef.current;
4912
4517
  const newHeight_0 = resizeRowOrigHeightRef.current;
4913
- const $pos_6 = view_13.state.doc.resolve(pmStart_5 + 1);
4518
+ const $pos_6 = view_13.state.doc.resolve(pmStart_1 + 1);
4914
4519
  for (let d_4 = $pos_6.depth; d_4 >= 0; d_4--) {
4915
4520
  const node_5 = $pos_6.node(d_4);
4916
4521
  if (node_5.type.name === "table") {
@@ -4942,10 +4547,10 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4942
4547
  const view_14 = (resizingHfSurfaceRef.current ? hfPMsRef.current?.getView(resizingHfSurfaceRef.current.rId) : hiddenPMRef.current?.getView()) ?? null;
4943
4548
  resizingHfSurfaceRef.current = null;
4944
4549
  if (view_14) {
4945
- const pmStart_6 = resizeRightEdgePmStartRef.current;
4550
+ const pmStart_2 = resizeRightEdgePmStartRef.current;
4946
4551
  const colIdx_0 = resizeRightEdgeColIndexRef.current;
4947
4552
  const newWidth_1 = resizeRightEdgeOrigWidthRef.current;
4948
- const $pos_7 = view_14.state.doc.resolve(pmStart_6 + 1);
4553
+ const $pos_7 = view_14.state.doc.resolve(pmStart_2 + 1);
4949
4554
  for (let d_5 = $pos_7.depth; d_5 >= 0; d_5--) {
4950
4555
  const node_6 = $pos_7.node(d_5);
4951
4556
  if (node_6.type.name === "table") {
@@ -5809,8 +5414,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5809
5414
  const container = containerRef.current;
5810
5415
  if (!container) return;
5811
5416
  const observer = new ResizeObserver(() => {
5812
- const state_7 = hiddenPMRef.current?.getState();
5813
- if (state_7) updateSelectionOverlay(state_7);
5417
+ const state_8 = hiddenPMRef.current?.getState();
5418
+ if (state_8) updateSelectionOverlay(state_8);
5814
5419
  });
5815
5420
  observer.observe(container);
5816
5421
  return () => observer.disconnect();
@@ -5818,11 +5423,11 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5818
5423
  useEffect(() => {
5819
5424
  const hiddenHost = hiddenPMRef.current?.getHostElement();
5820
5425
  if (!hiddenHost) return;
5821
- let animationFrame = null;
5426
+ let animationFrame_0 = null;
5822
5427
  const scheduleRefresh = () => {
5823
- if (animationFrame !== null) cancelAnimationFrame(animationFrame);
5824
- animationFrame = requestAnimationFrame(() => {
5825
- animationFrame = null;
5428
+ if (animationFrame_0 !== null) cancelAnimationFrame(animationFrame_0);
5429
+ animationFrame_0 = requestAnimationFrame(() => {
5430
+ animationFrame_0 = null;
5826
5431
  refreshBodyImeCaretAnchor();
5827
5432
  });
5828
5433
  };
@@ -5831,7 +5436,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5831
5436
  hiddenHost.addEventListener("compositionend", scheduleRefresh);
5832
5437
  window.addEventListener("scroll", scheduleRefresh, true);
5833
5438
  return () => {
5834
- if (animationFrame !== null) cancelAnimationFrame(animationFrame);
5439
+ if (animationFrame_0 !== null) cancelAnimationFrame(animationFrame_0);
5835
5440
  hiddenHost.removeEventListener("focusin", refreshOnFocus);
5836
5441
  hiddenHost.removeEventListener("compositionend", scheduleRefresh);
5837
5442
  window.removeEventListener("scroll", scheduleRefresh, true);
@@ -5947,33 +5552,33 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5947
5552
  return bestNumber;
5948
5553
  },
5949
5554
  getBlockRect(blockId) {
5950
- const state_8 = folioEditor.getState();
5951
- const pagesContainer_4 = pagesContainerRef.current;
5555
+ const state_9 = folioEditor.getState();
5556
+ const pagesContainer_6 = pagesContainerRef.current;
5952
5557
  const scrollRoot = getScrollContainer();
5953
- if (!state_8 || !pagesContainer_4 || !scrollRoot) return null;
5558
+ if (!state_9 || !pagesContainer_6 || !scrollRoot) return null;
5954
5559
  return readBlockRects({
5955
5560
  blockIds: [blockId],
5956
- snapshot: createFolioAIEditSnapshot$1(state_8.doc),
5957
- pagesContainer: pagesContainer_4,
5561
+ snapshot: createFolioAIEditSnapshot$1(state_9.doc),
5562
+ pagesContainer: pagesContainer_6,
5958
5563
  scrollRoot
5959
5564
  }).get(blockId) ?? null;
5960
5565
  },
5961
5566
  getBlockRects(blockIds) {
5962
- const state_9 = folioEditor.getState();
5963
- const pagesContainer_5 = pagesContainerRef.current;
5567
+ const state_10 = folioEditor.getState();
5568
+ const pagesContainer_7 = pagesContainerRef.current;
5964
5569
  const scrollRoot_0 = getScrollContainer();
5965
- if (!state_9 || !pagesContainer_5 || !scrollRoot_0) return /* @__PURE__ */ new Map();
5570
+ if (!state_10 || !pagesContainer_7 || !scrollRoot_0) return /* @__PURE__ */ new Map();
5966
5571
  return readBlockRects({
5967
5572
  blockIds,
5968
- snapshot: createFolioAIEditSnapshot$1(state_9.doc),
5969
- pagesContainer: pagesContainer_5,
5573
+ snapshot: createFolioAIEditSnapshot$1(state_10.doc),
5574
+ pagesContainer: pagesContainer_7,
5970
5575
  scrollRoot: scrollRoot_0
5971
5576
  });
5972
5577
  },
5973
5578
  getScrollRoot: getScrollContainer,
5974
5579
  onLayoutChange(listener) {
5975
- const pagesContainer_6 = pagesContainerRef.current;
5976
- return pagesContainer_6 ? onPaintedLayoutChange(pagesContainer_6, listener) : () => {};
5580
+ const pagesContainer_8 = pagesContainerRef.current;
5581
+ return pagesContainer_8 ? onPaintedLayoutChange(pagesContainer_8, listener) : () => {};
5977
5582
  }
5978
5583
  }), [
5979
5584
  ensureHiddenEditorView,
@@ -5994,8 +5599,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5994
5599
  onTotalPagesChangeRef.current?.(totalPages);
5995
5600
  }, [layout]);
5996
5601
  useEffect(() => {
5997
- const state_10 = hiddenPMRef.current?.getState();
5998
- if (layout && state_10) updateSelectionOverlay(state_10);
5602
+ const state_11 = hiddenPMRef.current?.getState();
5603
+ if (layout && state_11) updateSelectionOverlay(state_11);
5999
5604
  }, [layout, updateSelectionOverlay]);
6000
5605
  const totalHeight = useMemo(() => {
6001
5606
  if (!layout) return DEFAULT_PAGE_HEIGHT_PX + 48;
@@ -12699,7 +12304,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12699
12304
  * - Error boundary
12700
12305
  * - Loading states
12701
12306
  */
12702
- const CommentsSidebar = lazy(() => import("./CommentsSidebar-DWEKDq08.js").then((m) => ({ default: m.CommentsSidebar })));
12307
+ const CommentsSidebar = lazy(() => import("./CommentsSidebar-Bvlu7MpL.js").then((m) => ({ default: m.CommentsSidebar })));
12703
12308
  const TextContextMenu = lazy(() => import("./TextContextMenu-Ci7-M4oU.js").then((m) => ({ default: m.TextContextMenu })));
12704
12309
  const loadAttemptSelectiveSave = async () => {
12705
12310
  const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
@@ -12960,7 +12565,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
12960
12565
  const scrollContainerRef = useRef(null);
12961
12566
  const [formatPainterMode, setFormatPainterModeState] = useState("off");
12962
12567
  const formatPainterModeRef = useRef("off");
12963
- const capturedFormatMarksRef = useRef([]);
12568
+ const capturedFormatMarksRef = useRef(null);
12964
12569
  const setFormatPainterMode = useCallback((next) => {
12965
12570
  formatPainterModeRef.current = next;
12966
12571
  setFormatPainterModeState(next);
@@ -13827,7 +13432,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13827
13432
  }, [getActiveEditorView, getCachedStyleResolver]);
13828
13433
  const captureFormatPainter = useCallback(() => {
13829
13434
  const view_10 = getActiveEditorView();
13830
- capturedFormatMarksRef.current = view_10 ? captureFormatMarks(view_10.state) : [];
13435
+ capturedFormatMarksRef.current = view_10 ? captureFormatMarks(view_10.state) : null;
13831
13436
  }, [getActiveEditorView]);
13832
13437
  const paintFormatToSelection = useCallback(() => {
13833
13438
  const view_11 = getActiveEditorView();
@@ -13838,7 +13443,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13838
13443
  }, [getActiveEditorView]);
13839
13444
  const handleFormatPainter = useCallback((sticky) => {
13840
13445
  if (formatPainterModeRef.current !== "off") {
13841
- capturedFormatMarksRef.current = [];
13446
+ capturedFormatMarksRef.current = null;
13842
13447
  setFormatPainterMode("off");
13843
13448
  return;
13844
13449
  }
@@ -13861,11 +13466,11 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13861
13466
  const handleKeyDown = (event_0) => {
13862
13467
  if (event_0.key === "Escape") {
13863
13468
  const armed = formatPainterModeRef.current !== "off";
13864
- const hasCopiedFormat = capturedFormatMarksRef.current.length > 0;
13469
+ const hasCopiedFormat = capturedFormatMarksRef.current !== null;
13865
13470
  if (!armed && !hasCopiedFormat) return;
13866
13471
  event_0.preventDefault();
13867
13472
  event_0.stopPropagation();
13868
- capturedFormatMarksRef.current = [];
13473
+ capturedFormatMarksRef.current = null;
13869
13474
  if (armed) setFormatPainterMode("off");
13870
13475
  return;
13871
13476
  }