@stll/folio-react 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import { t as containedHandler } from "./contained-handler-4uiqUVRn.js";
2
2
  import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-CA59webC.js";
3
3
  import { i as findInDocument, o as scrollToMatch, t as useFindReplace$1 } from "./useFindReplace-MZ8wi31A.js";
4
- import { n as getFolioMessages } from "./messages-heGr9XLo.js";
4
+ import { t as messages_exports } from "./messages.js";
5
5
  import * as React$1 from "react";
6
6
  import React, { Component, Suspense, cloneElement, createContext, isValidElement, lazy, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
7
7
  import { AlertCircleIcon, AlertTriangleIcon, AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ClipboardCopyIcon, EyeIcon, FileIcon, GlobeIcon, ImageIcon, IndentDecreaseIcon, IndentIncreaseIcon, InfoIcon, ItalicIcon, LinkIcon, ListIcon, ListOrderedIcon, MoreHorizontalIcon, PaintbrushIcon, PenLineIcon, PencilIcon, PilcrowIcon, Redo2Icon, RulerIcon, SeparatorHorizontalIcon, SquarePenIcon, StickyNoteIcon, TableIcon, TableOfContentsIcon, TypeIcon, UnderlineIcon, Undo2Icon, UnlinkIcon, XIcon } from "lucide-react";
8
8
  import { IntlProvider, useTranslations } from "use-intl";
9
- import { applyFolioAIEditOperations, applyFolioAIEditOperations as applyFolioAIEditOperations$1, createFolioAIEditSnapshot, createFolioAIEditSnapshot as createFolioAIEditSnapshot$1, diffWordSegments, hashFolioAIBlockText, normalizeFolioAIBlockText } from "@stll/folio-core/ai-edits";
9
+ import { applyFolioAIEditOperations, applyFolioAIEditOperations as applyFolioAIEditOperations$1, createFolioAIEditSnapshot, createFolioAIEditSnapshot as createFolioAIEditSnapshot$1, diffWordSegments, getCommentAnchorsFromDoc, getTrackedChangesFromDoc, hashFolioAIBlockText, normalizeFolioAIBlockText } from "@stll/folio-core/ai-edits";
10
10
  import { normalizeBaseDirection } from "@stll/folio-core/docx/normalizeBaseDirection";
11
11
  import { getCachedNumberingMap } from "@stll/folio-core/docx/numberingParser";
12
12
  import { computeScrollPageInfo, updateScrollPageTotal } from "@stll/folio-core/paged-layout/scrollPageInfo";
13
- import { TextSelection, addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyFormatMarks, applyStyle, applyTableStyle, autoFitContents, captureFormatMarks, clearFormatting, clearTextColor, createStyleResolver, decreaseIndent, decreaseListLevel, deleteColumn, deleteRow, deleteTable, distributeColumns, extractSelectionState, getTableContext, increaseIndent, increaseListLevel, insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView, mergeCells, removeTabStop, removeTableBorders, schema, selectColumn, selectRow, selectTable, setAlignment, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setFontFamily, setFontSize, setHighlight, setIndentFirstLine, setIndentLeft, setIndentRight, setInsideTableBorders, setLineSpacing, setLtr, setOutsideTableBorders, setRowHeight, setRtl, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableProperties, setTextColor, splitCell, toggleBidi, toggleBold, toggleBulletList, toggleHeaderRow, toggleItalic, toggleNoWrap, toggleNumberedList, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "@stll/folio-core/prosemirror";
13
+ import { TextSelection, addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyFormatMarks, applyStyle, applyTableStyle, autoFitContents, captureFormatMarks, clearFormatting, clearTextColor, createStyleResolver, decreaseIndent, decreaseListLevel, deleteColumn, deleteRow, deleteTable, distributeColumns, extractSelectionState, getSelectedText, getTableContext, increaseIndent, increaseListLevel, insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView, mergeCells, removeTabStop, removeTableBorders, schema, selectColumn, selectRow, selectTable, setAlignment, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setFontFamily, setFontSize, setHighlight, setIndentFirstLine, setIndentLeft, setIndentRight, setInsideTableBorders, setLineSpacing, setLtr, setOutsideTableBorders, setRowHeight, setRtl, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableProperties, setTextColor, splitCell, toggleBidi, toggleBold, toggleBulletList, toggleHeaderRow, toggleItalic, toggleNoWrap, toggleNumberedList, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "@stll/folio-core/prosemirror";
14
14
  import { acceptAIEditRevision, acceptChange, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, rejectAIEditRevision, rejectChange } from "@stll/folio-core/prosemirror/commands/comments";
15
15
  import { blockSdtAttrsToSdtProperties, findBlockSdtMatch, findBlockSdtMatches, removeContentControlTr, setContentControlContentTr, setContentControlValueTr } from "@stll/folio-core/prosemirror/commands/contentControls";
16
16
  import { setContentControlContentBlocksTr } from "@stll/folio-core/prosemirror/commands/contentControlsBlockFill";
@@ -63,7 +63,7 @@ import { recordLayoutPhase } from "@stll/folio-core/layout-engine/layoutInstrume
63
63
  import { LayoutPainter } from "@stll/folio-core/layout-painter";
64
64
  import { PAINTER_PAINTED_EVENT, findPageShellForPmPos } from "@stll/folio-core/layout-painter/renderPage";
65
65
  import { LayoutSelectionGate } from "@stll/folio-core/paged-layout/LayoutSelectionGate";
66
- import { collectRunFontsAtPmPositions, measureContentLeft, projectRangesToRects } from "@stll/folio-core/paged-layout/rangeProjection";
66
+ import { collectRunFontsAtPmPositions, measureDirectiveGutter, projectRangesToRects } from "@stll/folio-core/paged-layout/rangeProjection";
67
67
  import { isReadOnlyEditKey } from "@stll/folio-core/paged-layout/readOnlyEditAttempt";
68
68
  import { getPageScrollTarget, prefersReducedMotionBehavior } from "@stll/folio-core/paged-layout/scrollNavigation";
69
69
  import { PAGES_CONTAINER_CLASS, scrollFolioPositionIntoView, scrollPagesToPmPosition } from "@stll/folio-core/paged-layout/scrollToPmPosition";
@@ -1450,63 +1450,213 @@ const overlayStyles = {
1450
1450
  };
1451
1451
  const BLOCK_OPENERS = /* @__PURE__ */ new Set(["if", "each"]);
1452
1452
  const BLOCK_CLOSERS = /* @__PURE__ */ new Set(["endif", "endeach"]);
1453
- const RAIL_BASE_GUTTER = 12;
1453
+ const RAIL_WIDTH = 2.5;
1454
+ /** Horizontal gap between adjacent nesting depths' rails. */
1454
1455
  const RAIL_DEPTH_GAP = 5;
1455
- const RAIL_WIDTH = 2;
1456
+ /** Minimum clear space between the innermost (deepest) rail and the text edge. */
1457
+ const RAIL_TEXT_CLEARANCE = 6;
1458
+ /** Keep the outermost rail this far off the physical page-left edge. */
1459
+ const RAIL_EDGE_PAD = 2;
1460
+ /** Drop per-page segments thinner than this (sub-pixel slivers at a page seam). */
1461
+ const RAIL_SEGMENT_MIN_HEIGHT = 2;
1462
+ const bandKindOf = (kind) => kind === "each" ? "each" : "if";
1456
1463
  /**
1457
- * Pair opener/closer block directives with a stack so each conditional/loop
1458
- * region knows its top, bottom, and nesting depth (for the gutter rail).
1459
- * Unbalanced directives are skipped. The rail's horizontal position comes from
1460
- * the stable `contentLeft` anchor (not the opener's re-projected rect), so it
1461
- * stays put while text above reflows; only its vertical span tracks the rects.
1464
+ * Deepest nesting level whose rail still fits inside the left margin with a
1465
+ * `RAIL_TEXT_CLEARANCE` gap to the text and a `RAIL_EDGE_PAD` gap to the page
1466
+ * edge. Depths past this reuse the deepest offset, so a 5-level nest can never
1467
+ * march a rail into the text column. Pure function of the measured margin width.
1462
1468
  */
1463
- const computeBands = (groups, contentLeft) => {
1464
- const blocks = groups.filter((g) => g.range.block && (BLOCK_OPENERS.has(g.range.kind) || BLOCK_CLOSERS.has(g.range.kind))).sort((a, b) => a.range.from - b.range.from);
1465
- const bands = [];
1469
+ const railBudgetDepth = (marginWidth) => {
1470
+ const usable = marginWidth - RAIL_TEXT_CLEARANCE - RAIL_WIDTH - RAIL_EDGE_PAD;
1471
+ if (usable <= 0) return 0;
1472
+ return Math.floor(usable / RAIL_DEPTH_GAP);
1473
+ };
1474
+ /**
1475
+ * Left edge (container space) of a depth-`depth` rail. The deepest rail the
1476
+ * budget allows sits `RAIL_TEXT_CLEARANCE + RAIL_WIDTH` left of the text edge;
1477
+ * shallower (outer) blocks fan further left into the margin — nested blocks read
1478
+ * as concentric brackets `[ [ [ text ] ] ]`. Depths beyond the budget clamp to
1479
+ * the deepest offset.
1480
+ */
1481
+ const railXForDepth = (depth, contentLeft, marginWidth) => {
1482
+ const budget = railBudgetDepth(marginWidth);
1483
+ const capped = Math.min(Math.max(0, depth), budget);
1484
+ return contentLeft - RAIL_TEXT_CLEARANCE - RAIL_WIDTH - (budget - capped) * RAIL_DEPTH_GAP;
1485
+ };
1486
+ /**
1487
+ * Clip a band's vertical span to each page's body-content band so a rail is
1488
+ * drawn as one rounded segment per page and never paints across the inter-page
1489
+ * gap, header, or footer. With no page bands (geometry not ready) the whole span
1490
+ * is returned as a single segment so rails still show. Pure math.
1491
+ */
1492
+ const segmentBandByPages = (band, pageBands) => {
1493
+ if (pageBands.length === 0) return band.bottom - band.top >= RAIL_SEGMENT_MIN_HEIGHT ? [band] : [];
1494
+ const segments = [];
1495
+ for (const page of pageBands) {
1496
+ const top = Math.max(band.top, page.top);
1497
+ const bottom = Math.min(band.bottom, page.bottom);
1498
+ if (bottom - top >= RAIL_SEGMENT_MIN_HEIGHT) segments.push({
1499
+ top,
1500
+ bottom
1501
+ });
1502
+ }
1503
+ return segments;
1504
+ };
1505
+ /**
1506
+ * Pair block openers with their closers via a kind-aware stack, so both chips of
1507
+ * a pair share a `blockId`, the rail knows its opener→closer PM span, and each
1508
+ * pairing carries the `depth` recorded in this very walk (never a second,
1509
+ * possibly-divergent depth pass). A closer matches the nearest opener of the same
1510
+ * family ({{/if}} ⇒ {{#if}}, {{/each}} ⇒ {{#each}}) and drops any still-open
1511
+ * openers nested above it; a closer with no matching opener is ignored. This keeps
1512
+ * a mid-edit / unbalanced template from pairing a {{/if}} with an {{#each}}.
1513
+ * Inline (block:false) markers are excluded. Pure function of the ranges.
1514
+ */
1515
+ const pairBlockRanges = (ranges) => {
1516
+ const blocks = ranges.filter((r) => r.block && (BLOCK_OPENERS.has(r.kind) || BLOCK_CLOSERS.has(r.kind))).slice().sort((a, b) => a.from - b.from);
1517
+ const pairings = [];
1466
1518
  const stack = [];
1467
- for (const group of blocks) {
1468
- if (BLOCK_OPENERS.has(group.range.kind)) {
1519
+ for (const range of blocks) {
1520
+ if (BLOCK_OPENERS.has(range.kind)) {
1469
1521
  stack.push({
1470
- group,
1522
+ range,
1471
1523
  depth: stack.length
1472
1524
  });
1473
1525
  continue;
1474
1526
  }
1475
- const open = stack.pop();
1476
- const openerRect = open?.group.rects[0];
1477
- const closerRect = group.rects[0];
1478
- if (!open || !openerRect || !closerRect) continue;
1479
- const railBase = contentLeft ?? openerRect.x;
1480
- bands.push({
1527
+ const wantOpener = range.kind === "endif" ? "if" : "each";
1528
+ let matched;
1529
+ let matchIdx = -1;
1530
+ for (let i = stack.length - 1; i >= 0; i -= 1) {
1531
+ const entry = stack[i];
1532
+ if (entry?.range.kind === wantOpener) {
1533
+ matched = entry;
1534
+ matchIdx = i;
1535
+ break;
1536
+ }
1537
+ }
1538
+ if (!matched) continue;
1539
+ stack.length = matchIdx;
1540
+ pairings.push({
1541
+ blockId: matched.range.from,
1542
+ kind: bandKindOf(matched.range.kind),
1543
+ depth: matched.depth,
1544
+ openerFrom: matched.range.from,
1545
+ closerFrom: range.from,
1546
+ closerTo: range.to,
1547
+ openerExpr: matched.range.expr
1548
+ });
1549
+ }
1550
+ return pairings;
1551
+ };
1552
+ /** Hover hint for a closer chip: what it closes, e.g. `/if · hasVerdicts`. */
1553
+ const closerHintLabel = (kind, openerExpr) => {
1554
+ const head = kind === "each" ? "/each" : "/if";
1555
+ return openerExpr ? `${head} · ${openerExpr}` : head;
1556
+ };
1557
+ /**
1558
+ * Block id of the innermost pairing whose opener→closer span contains `caretPos`
1559
+ * (largest opener position wins), or null. Drives the caret emphasis.
1560
+ */
1561
+ const innermostBlockAt = (pairings, caretPos) => {
1562
+ if (caretPos === null) return null;
1563
+ let bestBlockId = null;
1564
+ let bestOpener = Number.NEGATIVE_INFINITY;
1565
+ for (const pairing of pairings) if (caretPos >= pairing.openerFrom && caretPos <= pairing.closerTo && pairing.openerFrom > bestOpener) {
1566
+ bestOpener = pairing.openerFrom;
1567
+ bestBlockId = pairing.blockId;
1568
+ }
1569
+ return bestBlockId;
1570
+ };
1571
+ /**
1572
+ * Assemble the per-page rail segments for every balanced block: look up
1573
+ * opener/closer rects by `from`, place the rail by the pairing's own budgeted
1574
+ * depth, and clip its span to each page. Depth comes from the pairing (same walk
1575
+ * that matched opener→closer), so a rail's indentation and its span always agree.
1576
+ * O(pairings); all geometry comes from the props.
1577
+ */
1578
+ const computeRailBands = (pairings, groups, gutter) => {
1579
+ const groupByFrom = new Map(groups.map((group) => [group.range.from, group]));
1580
+ const bands = [];
1581
+ for (const pairing of pairings) {
1582
+ const openerRect = groupByFrom.get(pairing.openerFrom)?.rects[0];
1583
+ const closerRect = groupByFrom.get(pairing.closerFrom)?.rects[0];
1584
+ if (!openerRect || !closerRect) continue;
1585
+ const segments = segmentBandByPages({
1481
1586
  top: openerRect.y,
1482
- bottom: closerRect.y + closerRect.height,
1483
- railX: railBase - RAIL_BASE_GUTTER + open.depth * RAIL_DEPTH_GAP
1587
+ bottom: closerRect.y + closerRect.height
1588
+ }, gutter.pageBands);
1589
+ if (segments.length === 0) continue;
1590
+ bands.push({
1591
+ blockId: pairing.blockId,
1592
+ kind: pairing.kind,
1593
+ railX: railXForDepth(pairing.depth, gutter.contentLeft, gutter.marginWidth),
1594
+ segments
1484
1595
  });
1485
1596
  }
1486
1597
  return bands;
1487
1598
  };
1488
- const TemplateDirectivesOverlay = ({ groups, contentLeft }) => {
1599
+ const blockIdFromTarget = (target) => {
1600
+ if (!(target instanceof HTMLElement)) return null;
1601
+ const raw = target.dataset["folioBlockId"];
1602
+ return raw === void 0 ? null : Number(raw);
1603
+ };
1604
+ const TemplateDirectivesOverlay = ({ groups, gutter, caretPos, ranges }) => {
1605
+ const [hoveredBlockId, setHoveredBlockId] = useState(null);
1489
1606
  if (groups.length === 0) return null;
1607
+ const pairings = pairBlockRanges(ranges);
1608
+ const railBands = gutter ? computeRailBands(pairings, groups, gutter) : [];
1609
+ const blockIdByFrom = /* @__PURE__ */ new Map();
1610
+ const closerLabelByFrom = /* @__PURE__ */ new Map();
1611
+ for (const pairing of pairings) {
1612
+ blockIdByFrom.set(pairing.openerFrom, pairing.blockId);
1613
+ blockIdByFrom.set(pairing.closerFrom, pairing.blockId);
1614
+ closerLabelByFrom.set(pairing.closerFrom, closerHintLabel(pairing.kind, pairing.openerExpr));
1615
+ }
1616
+ const caretBlockId = innermostBlockAt(pairings, caretPos);
1617
+ const isActive = (blockId) => blockId === hoveredBlockId || blockId === caretBlockId;
1618
+ const handlePointerOver = (event) => {
1619
+ const blockId = blockIdFromTarget(event.target);
1620
+ if (blockId !== null) setHoveredBlockId(blockId);
1621
+ };
1622
+ const handlePointerOut = (event) => {
1623
+ const from = blockIdFromTarget(event.target);
1624
+ if (from === null) return;
1625
+ const to = blockIdFromTarget(event.relatedTarget);
1626
+ if (to === from) return;
1627
+ setHoveredBlockId((current) => current === from ? to : current);
1628
+ };
1490
1629
  return /* @__PURE__ */ jsxs("div", {
1491
1630
  style: overlayStyles,
1492
1631
  "data-folio-template-directives-overlay": "",
1493
- children: [computeBands(groups, contentLeft).map((band, bandIdx) => /* @__PURE__ */ jsx("div", {
1494
- className: "folio-template-band-rail",
1632
+ onPointerOver: handlePointerOver,
1633
+ onPointerOut: handlePointerOut,
1634
+ children: [railBands.flatMap((band) => band.segments.map((segment, segmentIdx) => /* @__PURE__ */ jsx("div", {
1635
+ className: `folio-template-band-rail folio-template-band-rail--${band.kind}${isActive(band.blockId) ? " folio-template-band-rail--active" : ""}`,
1636
+ "data-folio-block-id": band.blockId,
1495
1637
  style: {
1496
1638
  left: band.railX,
1497
- top: band.top,
1639
+ top: segment.top,
1498
1640
  width: RAIL_WIDTH,
1499
- height: Math.max(0, band.bottom - band.top)
1500
- }
1501
- }, `rail:${bandIdx}`)), groups.flatMap(({ range, rects }, groupIdx) => rects.map((rect, idx) => /* @__PURE__ */ jsx("span", {
1502
- className: `folio-template-directive folio-template-directive--${range.kind}`,
1503
- style: {
1504
- left: rect.x - 1,
1505
- top: rect.y + 1,
1506
- width: rect.width + 2,
1507
- height: Math.max(0, rect.height - 2)
1508
- }
1509
- }, `d:${groupIdx}:${idx}`)))]
1641
+ height: Math.max(0, segment.bottom - segment.top)
1642
+ }
1643
+ }, `rail:${band.blockId}:${segmentIdx}`))), groups.flatMap(({ range, rects }, groupIdx) => {
1644
+ const blockId = range.block ? blockIdByFrom.get(range.from) : void 0;
1645
+ const isBlockChip = range.block && (BLOCK_OPENERS.has(range.kind) || BLOCK_CLOSERS.has(range.kind));
1646
+ const closerLabel = range.block ? closerLabelByFrom.get(range.from) : void 0;
1647
+ const active = blockId !== void 0 && isActive(blockId);
1648
+ return rects.map((rect, idx) => /* @__PURE__ */ jsx("span", {
1649
+ className: `folio-template-directive folio-template-directive--${range.kind}${isBlockChip ? " folio-template-directive--block" : ""}${active ? " folio-template-directive--active" : ""}`,
1650
+ ...blockId !== void 0 ? { "data-folio-block-id": blockId } : {},
1651
+ ...closerLabel !== void 0 ? { title: closerLabel } : {},
1652
+ style: {
1653
+ left: rect.x - 1,
1654
+ top: rect.y + 1,
1655
+ width: rect.width + 2,
1656
+ height: Math.max(0, rect.height - 2)
1657
+ }
1658
+ }, `d:${groupIdx}:${idx}`));
1659
+ })]
1510
1660
  });
1511
1661
  };
1512
1662
  //#endregion
@@ -2564,7 +2714,8 @@ function PagedEditor(props) {
2564
2714
  const [autocompleteText, setAutocompleteText] = useState("");
2565
2715
  const [autocompleteIsStreaming, setAutocompleteIsStreaming] = useState(false);
2566
2716
  const [directiveRectGroups, setDirectiveRectGroups] = useState([]);
2567
- const [directiveContentLeft, setDirectiveContentLeft] = useState(null);
2717
+ const [directiveGutter, setDirectiveGutter] = useState(null);
2718
+ const [directiveCaretPos, setDirectiveCaretPos] = useState(null);
2568
2719
  const directivesRef = useRef([]);
2569
2720
  const directivesOverlayRequestSeqRef = useRef(0);
2570
2721
  const templatePreviewRef = useRef({
@@ -2951,6 +3102,7 @@ function PagedEditor(props) {
2951
3102
  const requestSeq = selectionOverlayRequestSeqRef.current + 1;
2952
3103
  selectionOverlayRequestSeqRef.current = requestSeq;
2953
3104
  const isCurrentRequest = () => selectionOverlayRequestSeqRef.current === requestSeq;
3105
+ if (directivesRef.current.length > 0) setDirectiveCaretPos(state.selection.head);
2954
3106
  onSelectionChangeRef.current?.(from, to);
2955
3107
  folioEmitterRef.current.emit("selectionChange", {
2956
3108
  from,
@@ -3255,10 +3407,10 @@ function PagedEditor(props) {
3255
3407
  const pagesContainer = pagesContainerRef.current;
3256
3408
  if (ranges.length === 0 || !pagesContainer) {
3257
3409
  setDirectiveRectGroups([]);
3258
- setDirectiveContentLeft(null);
3410
+ setDirectiveGutter(null);
3259
3411
  return;
3260
3412
  }
3261
- setDirectiveContentLeft(measureContentLeft(pagesContainer, zoom));
3413
+ setDirectiveGutter(measureDirectiveGutter(pagesContainer, zoom));
3262
3414
  (async () => {
3263
3415
  const projected = await projectRangesToRects(ranges, {
3264
3416
  pagesContainer,
@@ -5167,8 +5319,10 @@ function PagedEditor(props) {
5167
5319
  }),
5168
5320
  /* @__PURE__ */ jsx(AISuggestionRectsOverlay, { groups: aiSuggestionRectGroups }),
5169
5321
  showTemplateDirectives && /* @__PURE__ */ jsx(TemplateDirectivesOverlay, {
5170
- contentLeft: directiveContentLeft,
5171
- groups: directiveRectGroups
5322
+ gutter: directiveGutter,
5323
+ groups: directiveRectGroups,
5324
+ caretPos: directiveCaretPos,
5325
+ ranges: directivesRef.current
5172
5326
  }),
5173
5327
  /* @__PURE__ */ jsx(SelectionOverlay, {
5174
5328
  selectionRects: hfEditMode ? EMPTY_SELECTION_RECTS : selectionRects,
@@ -5988,6 +6142,26 @@ function resolveCommentCreationRange({ docSize, capturedRange, currentRange, sav
5988
6142
  })();
5989
6143
  return range ? clampCommentMarkRange(docSize, range) : null;
5990
6144
  }
6145
+ //#endregion
6146
+ //#region src/components/pageText.ts
6147
+ /**
6148
+ * The plain text of a single rendered page (1-based), read by joining each of
6149
+ * the page's layout fragments' `[pmStart, pmEnd)` document text with a
6150
+ * newline. Fragments with no `pmStart`/`pmEnd` (e.g. a page-shell placeholder)
6151
+ * are skipped. Returns `null` when the layout hasn't been computed yet or the
6152
+ * page number is out of range.
6153
+ */
6154
+ const getPageTextFromLayout = (layout, doc, page) => {
6155
+ if (!layout || !Number.isInteger(page) || page < 1) return null;
6156
+ const layoutPage = layout.pages[page - 1];
6157
+ if (!layoutPage) return null;
6158
+ const fragmentTexts = [];
6159
+ for (const fragment of layoutPage.fragments) {
6160
+ if (typeof fragment.pmStart !== "number" || typeof fragment.pmEnd !== "number") continue;
6161
+ fragmentTexts.push(doc.textBetween(fragment.pmStart, fragment.pmEnd, "\n"));
6162
+ }
6163
+ return fragmentTexts.join("\n");
6164
+ };
5991
6165
  /** Stable empty anchor positions Map used as the initial state. */
5992
6166
  const EMPTY_ANCHOR_POSITIONS = /* @__PURE__ */ new Map();
5993
6167
  let nextCommentId = Date.now();
@@ -11527,6 +11701,23 @@ function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKe
11527
11701
  });
11528
11702
  return true;
11529
11703
  },
11704
+ getTrackedChanges: () => {
11705
+ const view = pagedEditorRef.current?.getView();
11706
+ return view ? getTrackedChangesFromDoc(view.state.doc) : [];
11707
+ },
11708
+ getCommentAnchors: () => {
11709
+ const view = pagedEditorRef.current?.getView();
11710
+ return view ? getCommentAnchorsFromDoc(view.state.doc) : [];
11711
+ },
11712
+ getSelectionText: () => {
11713
+ const view = pagedEditorRef.current?.getView();
11714
+ return view ? getSelectedText(view.state) : "";
11715
+ },
11716
+ getPageText: (page) => {
11717
+ const view = pagedEditorRef.current?.getView();
11718
+ if (!view) return null;
11719
+ return getPageTextFromLayout(pagedEditorRef.current?.getEditor()?.getLayout() ?? null, view.state.doc, page);
11720
+ },
11530
11721
  getContentControls: (filter = {}) => {
11531
11722
  const view = pagedEditorRef.current?.getView();
11532
11723
  if (!view) return [];
@@ -12434,7 +12625,7 @@ const renderAsync = (input, container, options = {}) => {
12434
12625
  };
12435
12626
  const element = /* @__PURE__ */ jsx(IntlProvider, {
12436
12627
  locale,
12437
- messages: getFolioMessages(locale),
12628
+ messages: (0, messages_exports.getFolioMessages)(locale),
12438
12629
  children: /* @__PURE__ */ jsx(DocxEditor, {
12439
12630
  ...editorOptions,
12440
12631
  documentBuffer: input,
@@ -1,13 +1 @@
1
- //#region src/i18n/messages.d.ts
2
- declare const FOLIO_LOCALES: readonly ["en", "de", "fr", "es", "cs", "ar", "et", "he", "hi", "hu", "lt", "lv", "pl", "pt-BR", "sk", "tr", "zh-CN"];
3
- type FolioLocale = (typeof FOLIO_LOCALES)[number];
4
- type FolioMessageTree = {
5
- [key: string]: string | FolioMessageTree;
6
- };
7
- type FolioMessages = {
8
- folio: FolioMessageTree;
9
- };
10
- declare const isFolioLocale: (locale: string) => locale is FolioLocale;
11
- declare const getFolioMessages: (locale: string) => FolioMessages;
12
- //#endregion
13
- export { FOLIO_LOCALES, FolioLocale, FolioMessages, getFolioMessages, isFolioLocale };
1
+ export * from "@stll/folio-core/i18n/messages";
package/dist/messages.js CHANGED
@@ -1,2 +1,33 @@
1
- import { n as getFolioMessages, r as isFolioLocale, t as FOLIO_LOCALES } from "./messages-heGr9XLo.js";
2
- export { FOLIO_LOCALES, getFolioMessages, isFolioLocale };
1
+ export * from "@stll/folio-core/i18n/messages";
2
+ //#region \0rolldown/runtime.js
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __exportAll = (all, no_symbols) => {
8
+ let target = {};
9
+ for (var name in all) __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true
12
+ });
13
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ return target;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
18
+ key = keys[i];
19
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
20
+ get: ((k) => from[k]).bind(null, key),
21
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
22
+ });
23
+ }
24
+ return to;
25
+ };
26
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
27
+ //#endregion
28
+ //#region src/i18n/messages.ts
29
+ var messages_exports = /* @__PURE__ */ __exportAll({});
30
+ import * as import__stll_folio_core_i18n_messages from "@stll/folio-core/i18n/messages";
31
+ __reExport(messages_exports, import__stll_folio_core_i18n_messages);
32
+ //#endregion
33
+ export { messages_exports as t };