@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/editor.css +1 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +237 -46
- package/dist/messages.d.ts +1 -13
- package/dist/messages.js +33 -2
- package/dist/standalone.css +1 -1
- package/package.json +3 -2
- package/dist/messages-heGr9XLo.js +0 -2827
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 {
|
|
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,
|
|
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
|
|
1453
|
+
const RAIL_WIDTH = 2.5;
|
|
1454
|
+
/** Horizontal gap between adjacent nesting depths' rails. */
|
|
1454
1455
|
const RAIL_DEPTH_GAP = 5;
|
|
1455
|
-
|
|
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
|
-
*
|
|
1458
|
-
*
|
|
1459
|
-
*
|
|
1460
|
-
* the
|
|
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
|
|
1464
|
-
const
|
|
1465
|
-
|
|
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
|
|
1468
|
-
if (BLOCK_OPENERS.has(
|
|
1519
|
+
for (const range of blocks) {
|
|
1520
|
+
if (BLOCK_OPENERS.has(range.kind)) {
|
|
1469
1521
|
stack.push({
|
|
1470
|
-
|
|
1522
|
+
range,
|
|
1471
1523
|
depth: stack.length
|
|
1472
1524
|
});
|
|
1473
1525
|
continue;
|
|
1474
1526
|
}
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1494
|
-
|
|
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:
|
|
1639
|
+
top: segment.top,
|
|
1498
1640
|
width: RAIL_WIDTH,
|
|
1499
|
-
height: Math.max(0,
|
|
1500
|
-
}
|
|
1501
|
-
}, `rail:${
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
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 [
|
|
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
|
-
|
|
3410
|
+
setDirectiveGutter(null);
|
|
3259
3411
|
return;
|
|
3260
3412
|
}
|
|
3261
|
-
|
|
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
|
-
|
|
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,
|
package/dist/messages.d.ts
CHANGED
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
2
|
-
|
|
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 };
|