@stll/folio-react 0.28.0 → 0.29.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/README.md CHANGED
@@ -45,6 +45,38 @@ export function Editor({ docx }: { docx: ArrayBuffer }) {
45
45
  The editor renders to the DOM; under SSR, load it from a client-only/dynamic
46
46
  import.
47
47
 
48
+ ## Read-only review views
49
+
50
+ ```tsx
51
+ <DocxEditor
52
+ documentBuffer={docx}
53
+ readOnly
54
+ reviewDisplayMode="final"
55
+ showCommentHighlights={false}
56
+ />
57
+ ```
58
+
59
+ `reviewDisplayMode` accepts `all-markup` (the default), `final` (all pending
60
+ changes accepted for display), or `original` (all pending changes rejected for
61
+ display). It controls the displayed text, formatting, numbering, table rows,
62
+ pagination and search. The controlled prop updates the view without reparsing.
63
+ Omit it to let the editor's review selector control the view.
64
+
65
+ Projected views (`final`, `original`, and Simple Markup in the review selector)
66
+ are read-only: typing and replacement are refused. Switch to `all-markup` to
67
+ edit. `ref.current.getReadOnlyReason()` returns `review-display-mode`,
68
+ `host-read-only`, `viewing-mode`, or `null` when editing is allowed.
69
+ `onReadonlyEditAttempt(reason)` receives the exported `EditorReadOnlyReason`
70
+ when a user attempts an edit.
71
+
72
+ `showCommentHighlights` defaults to `true` and independently hides comment
73
+ highlights in `all-markup`. Highlights are always hidden in `final` and
74
+ `original`. Neither prop changes the document, revisions or comments: saving
75
+ or exporting DOCX preserves the same authored document in every view. The
76
+ Vue `DocxEditor` exposes the same props. `ReviewDisplayMode` is exported by
77
+ both adapters and folio-core; core's `reviewDisplayModeToDisplayMode` selects
78
+ the existing `markupView` layout configuration (`final` uses `no-markup`).
79
+
48
80
  ## Exports
49
81
 
50
82
  | Import | What it is |
@@ -1,10 +1,11 @@
1
- import { f as containedHandler, u as useDrawerFocus } from "./renderAsync-Bh7xudNL.js";
1
+ import { f as containedHandler, u as useDrawerFocus } from "./renderAsync-D3Bxr14I.js";
2
2
  import { useCallback, useEffect, useEffectEvent, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import { CheckIcon, MoreVerticalIcon } from "lucide-react";
4
4
  import { useLocale, useTranslations } from "use-intl";
5
5
  import { scrollEditorTo } from "@stll/folio-core/paged-layout/editorScrollRoot";
6
6
  import { closestHtmlElement, queryHtmlElement } from "@stll/folio-core/utils/domGuards";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { sliceText } from "@stll/folio-core/utils/sliceText";
8
9
  import { PANEL_METRICS } from "@stll/folio-core/panel-layout";
9
10
  import { commentAnchorSelector } from "@stll/folio-core/render-dom/commentAnchorAttributes";
10
11
  //#region src/components/CommentsSidebar.tsx
@@ -35,7 +36,15 @@ function formatDate(dateStr, locale) {
35
36
  }).format(d);
36
37
  }
37
38
  function getInitials(name) {
38
- return name.split(/\s+/u).map((w) => w[0]).join("").toUpperCase().slice(0, 2);
39
+ return sliceText({
40
+ text: name.split(/\s+/u).map((word) => sliceText({
41
+ text: word,
42
+ units: "graphemes",
43
+ end: 1
44
+ })).join("").toUpperCase(),
45
+ units: "graphemes",
46
+ end: 2
47
+ });
39
48
  }
40
49
  function getCommentParentId(comment) {
41
50
  return comment.parentId;
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { c } from "react-compiler-runtime";
4
4
  import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
5
5
  import { ChevronDownIcon, ChevronUpIcon, SearchIcon, XIcon } from "lucide-react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useId, useState } from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useId, useState } from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useId, useState } from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { c as DIALOG_SECONDARY_BUTTON_CLASS, i as DIALOG_INPUT_CLASS, l as DIALOG_TITLE_CLASS, n as DIALOG_BODY_CLASS, o as DIALOG_POPUP_CLASS, r as DIALOG_FOOTER_CLASS, s as DIALOG_PRIMARY_BUTTON_CLASS, t as DIALOG_BACKDROP_CLASS, u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useState } from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useId, useState } from "react";
@@ -1,4 +1,4 @@
1
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
1
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
2
2
  import { a as DIALOG_LABEL_CLASS, c as DIALOG_SECONDARY_BUTTON_CLASS, i as DIALOG_INPUT_CLASS, l as DIALOG_TITLE_CLASS, n as DIALOG_BODY_CLASS, o as DIALOG_POPUP_CLASS, r as DIALOG_FOOTER_CLASS, s as DIALOG_PRIMARY_BUTTON_CLASS, t as DIALOG_BACKDROP_CLASS, u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
3
3
  import { c } from "react-compiler-runtime";
4
4
  import { useId, useState } from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.js";
2
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
2
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
3
3
  import { u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
4
4
  import { c } from "react-compiler-runtime";
5
5
  import { useId, useState } from "react";
@@ -1,4 +1,4 @@
1
- import { c as DocxEditorRef, i as renderAsync, n as EditorHandle, r as RenderAsyncOptions, s as DocxEditorProps, t as DocxEditorHandle } from "../renderAsync-BVAgBXCL.js";
1
+ import { c as DocxEditorRef, i as renderAsync, n as EditorHandle, r as RenderAsyncOptions, s as DocxEditorProps, t as DocxEditorHandle } from "../renderAsync-DsMKdbU5.js";
2
2
  import { ReactNode } from "react";
3
3
  import { CreateEmptyDocumentOptions, createDocumentWithText, createEmptyDocument } from "@stll/folio-core/utils/createDocument";
4
4
  //#region src/compat/eigenpal.d.ts
@@ -1,4 +1,4 @@
1
- import { n as DocxEditor$1, t as renderAsync } from "../renderAsync-Bh7xudNL.js";
1
+ import { n as DocxEditor$1, t as renderAsync } from "../renderAsync-D3Bxr14I.js";
2
2
  import { t as messages_exports } from "../messages.js";
3
3
  import { c } from "react-compiler-runtime";
4
4
  import { forwardRef } from "react";
@@ -1,4 +1,4 @@
1
- import { r as useFolioUI } from "./folio-ui-rCHqCEG6.js";
1
+ import { r as useFolioUI } from "./folio-ui-ruRywxeb.js";
2
2
  import { a as DIALOG_LABEL_CLASS, c as DIALOG_SECONDARY_BUTTON_CLASS, i as DIALOG_INPUT_CLASS, l as DIALOG_TITLE_CLASS, n as DIALOG_BODY_CLASS, o as DIALOG_POPUP_CLASS, r as DIALOG_FOOTER_CLASS, s as DIALOG_PRIMARY_BUTTON_CLASS, t as DIALOG_BACKDROP_CLASS, u as useCloseOnDialogOpenChange } from "./dialogChrome-BoGYPgeu.js";
3
3
  import { c } from "react-compiler-runtime";
4
4
  import { useId, useState } from "react";
package/dist/dialogs.js CHANGED
@@ -1,9 +1,9 @@
1
- import { t as FindReplaceDialog } from "./FindReplaceDialog-LlVMe3EW.js";
2
- import { t as FootnotePropertiesDialog } from "./FootnotePropertiesDialog-D73t3LNP.js";
3
- import { a as InsertImageDialog, i as InsertTableDialog, n as SplitCellDialog, o as HyperlinkDialog, r as PasteSpecialDialog, t as WatermarkDialog } from "./dialogs-De-oslzU.js";
4
- import { t as ImagePositionDialog } from "./ImagePositionDialog-Cwt6R8iM.js";
5
- import { t as ImagePropertiesDialog } from "./ImagePropertiesDialog-GNZLBFLB.js";
6
- import { t as InsertSymbolDialog } from "./InsertSymbolDialog-CeEhkEvc.js";
7
- import { t as PageSetupDialog } from "./PageSetupDialog-DD6IEZAo.js";
8
- import { t as TablePropertiesDialog } from "./TablePropertiesDialog-Vu0HXQz6.js";
1
+ import { t as FindReplaceDialog } from "./FindReplaceDialog-CUd8xdgd.js";
2
+ import { t as FootnotePropertiesDialog } from "./FootnotePropertiesDialog-BEs7N62_.js";
3
+ import { a as InsertImageDialog, i as InsertTableDialog, n as SplitCellDialog, o as HyperlinkDialog, r as PasteSpecialDialog, t as WatermarkDialog } from "./dialogs-DGrcp10A.js";
4
+ import { t as ImagePositionDialog } from "./ImagePositionDialog-Oap9knQ-.js";
5
+ import { t as ImagePropertiesDialog } from "./ImagePropertiesDialog-lLMKHv0u.js";
6
+ import { t as InsertSymbolDialog } from "./InsertSymbolDialog-Drm40-9j.js";
7
+ import { t as PageSetupDialog } from "./PageSetupDialog-DTWCdPkX.js";
8
+ import { t as TablePropertiesDialog } from "./TablePropertiesDialog-uSTmyEcu.js";
9
9
  export { FindReplaceDialog, FootnotePropertiesDialog, HyperlinkDialog, ImagePositionDialog, ImagePropertiesDialog, InsertImageDialog, InsertSymbolDialog, InsertTableDialog, PageSetupDialog, PasteSpecialDialog, SplitCellDialog, TablePropertiesDialog, WatermarkDialog };
@@ -4,6 +4,7 @@ import { useTranslations } from "use-intl";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Checkbox } from "@base-ui/react/checkbox";
6
6
  import { Popover } from "@base-ui/react/popover";
7
+ import { sliceText } from "@stll/folio-core/utils/sliceText";
7
8
  import { Dialog } from "@base-ui/react/dialog";
8
9
  import { Input } from "@base-ui/react/input";
9
10
  import { Menu } from "@base-ui/react/menu";
@@ -210,7 +211,11 @@ function ColorSwatch(t0) {
210
211
  const toISODate = (value) => {
211
212
  if (value === null) return "";
212
213
  if (value instanceof Date) return `${value.getFullYear().toString().padStart(4, "0")}-${(value.getMonth() + 1).toString().padStart(2, "0")}-${value.getDate().toString().padStart(2, "0")}`;
213
- return value.length >= 10 ? value.slice(0, 10) : value;
214
+ return value.length >= 10 ? sliceText({
215
+ text: value,
216
+ units: "codeUnits",
217
+ end: 10
218
+ }) : value;
214
219
  };
215
220
  function DefaultDatePickerPopover({ value, onChange, defaultOpen = false }) {
216
221
  return /* @__PURE__ */ jsx("input", {
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import { _ as FolioUIProvider, a as DocxEditorApplyDocumentOperationsOptions, c as DocxEditorRef, d as ToolbarProps, f as EditorMode, g as FolioUIComponents, h as FolioButtonProps, i as renderAsync, l as HighlightPassageOptions, m as ColorPreset, n as EditorHandle, o as DocxEditorCollaboration, p as FontOption, r as RenderAsyncOptions, s as DocxEditorProps, t as DocxEditorHandle, u as HighlightPassageResult, v as OutlineItem, y as FontDefinition } from "./renderAsync-BVAgBXCL.js";
1
+ import { _ as FolioUIProvider, a as DocxEditorApplyDocumentOperationsOptions, c as DocxEditorRef, d as ToolbarProps, f as EditorMode, g as FolioUIComponents, h as FolioButtonProps, i as renderAsync, l as HighlightPassageOptions, m as ColorPreset, n as EditorHandle, o as DocxEditorCollaboration, p as FontOption, r as RenderAsyncOptions, s as DocxEditorProps, t as DocxEditorHandle, u as HighlightPassageResult, v as OutlineItem, y as FontDefinition } from "./renderAsync-DsMKdbU5.js";
2
2
  import { A as HyperlinkDialog, C as ImagePropertiesData, D as ImagePositionDialog, E as ImagePositionData, F as FindReplaceDialog, I as FindReplaceDialogProps, M as HyperlinkDialogProps, N as FootnotePropertiesDialog, O as ImagePositionDialogProps, P as FootnotePropertiesDialogProps, S as InsertImageDialogProps, T as ImagePropertiesDialogProps, _ as InsertTableStyleOption, a as TablePropertiesDialogProps, b as InsertImageDialog, c as SplitCellDialogProps, d as PasteSpecialMode, f as PageSetupDialog, g as InsertTableDialogProps, h as InsertTableDialogData, i as TablePropertiesDialog, j as HyperlinkDialogData, k as HyperlinkBookmarkOption, l as PasteSpecialDialog, m as InsertTableDialog, n as WatermarkDialogProps, o as SplitCellDialog, p as PageSetupDialogProps, r as TableProperties, s as SplitCellDialogData, t as WatermarkDialog, u as PasteSpecialDialogProps, v as InsertSymbolDialog, w as ImagePropertiesDialog, x as InsertImageDialogData, y as InsertSymbolDialogProps } from "./dialogs-BENP66Ly.js";
3
3
  import React, { CSSProperties, ReactNode, RefObject } from "react";
4
4
  import { CreateEmptyDocumentOptions, createEmptyDocument } from "@stll/folio-core/utils/createDocument";
5
5
  import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty, WordDiffSegment, applyFolioAIEditOperations, createFolioAIEditSnapshot, diffWordSegments, hashFolioAIBlockText, normalizeFolioAIBlockText } from "@stll/folio-core/ai-edits";
6
6
  import { KeyboardShortcutScope, KeyboardShortcutScope as KeyboardShortcutScope$1 } from "@stll/folio-core/managers/editorShortcuts";
7
+ import { EditorReadOnlyReason } from "@stll/folio-core/managers/EditorModeManager";
8
+ import { ReviewDisplayMode } from "@stll/folio-core/managers/reviewDisplayMode";
7
9
  import { DocxCompatibility } from "@stll/folio-core/docx/compatibility";
8
10
  import { insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView } from "@stll/folio-core/prosemirror";
9
11
  import { FolioSuggestion, SuggestionAppliedAs, SuggestionKind } from "@stll/folio-core/prosemirror/commands/comments";
@@ -201,4 +203,4 @@ type AutocompleteCaretOverlayProps = {
201
203
  };
202
204
  declare const AutocompleteCaretOverlay: ({ caret, text, isStreaming }: AutocompleteCaretOverlayProps) => React.JSX.Element | null;
203
205
  //#endregion
204
- export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyResult, AutocompleteCaretOverlay, type AutocompleteCaretOverlayProps, type AutocompleteCaretRect, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, type ColorPreset, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, DocxEditor, type DocxEditorApplyDocumentOperationsOptions, type DocxEditorCollaboration, type DocxEditorHandle, type DocxEditorProps, type DocxEditorRef, type EditorHandle, type EditorMode, type ExtractDocumentStyleSetOptions, FindReplaceDialog, type FindReplaceDialogProps, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioButtonProps, type FolioSuggestion, type FolioUIComponents, FolioUIProvider, type FontDefinition, type FontOption, FootnotePropertiesDialog, type FootnotePropertiesDialogProps, FormattingBar, type FormattingBarProps, type HighlightPassageOptions, type HighlightPassageResult, type HyperlinkBookmarkOption, HyperlinkDialog, type HyperlinkDialogData, type HyperlinkDialogProps, type ImageMeta, type ImagePositionData, ImagePositionDialog, type ImagePositionDialogProps, type ImagePropertiesData, ImagePropertiesDialog, type ImagePropertiesDialogProps, type ImageRef, InsertImageDialog, type InsertImageDialogData, type InsertImageDialogProps, InsertSymbolDialog, type InsertSymbolDialogProps, InsertTableDialog, type InsertTableDialogData, type InsertTableDialogProps, type InsertTableStyleOption, type KeyboardShortcutScope, type MarkdownOptions, type MarkdownResult, type OutlineDepth, type OutlineItem, PageSetupDialog, type PageSetupDialogProps, PasteSpecialDialog, type PasteSpecialDialogProps, type PasteSpecialMode, type PictureWatermark, type PositionalText, type RenderAsyncOptions, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type ScrollToParaIdOptions, SplitCellDialog, type SplitCellDialogData, type SplitCellDialogProps, type SuggestionAppliedAs, type SuggestionKind, type TableProperties, TablePropertiesDialog, type TablePropertiesDialogProps, type TemplatePreviewHiddenRange, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, type TextWatermark, type UseWheelZoomOptions, type UseWheelZoomReturn, type Watermark, WatermarkDialog, type WatermarkDialogProps, type WordDiffSegment, ZOOM_PRESETS, ZoomControl, type ZoomControlProps, type ZoomLevel, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clampZoom, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, finishAutocompleteSuggestion, formatZoom, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getDocumentWatermark, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView, inspectDocumentStyles, inspectDocumentStylesFromDocx, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, parseZoom, renderAsync, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setDocumentWatermark, setFocusedSuggestionMeta, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult, useWheelZoom };
206
+ export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyResult, AutocompleteCaretOverlay, type AutocompleteCaretOverlayProps, type AutocompleteCaretRect, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, type ColorPreset, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, DocxEditor, type DocxEditorApplyDocumentOperationsOptions, type DocxEditorCollaboration, type DocxEditorHandle, type DocxEditorProps, type DocxEditorRef, type EditorHandle, type EditorMode, type EditorReadOnlyReason, type ExtractDocumentStyleSetOptions, FindReplaceDialog, type FindReplaceDialogProps, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioButtonProps, type FolioSuggestion, type FolioUIComponents, FolioUIProvider, type FontDefinition, type FontOption, FootnotePropertiesDialog, type FootnotePropertiesDialogProps, FormattingBar, type FormattingBarProps, type HighlightPassageOptions, type HighlightPassageResult, type HyperlinkBookmarkOption, HyperlinkDialog, type HyperlinkDialogData, type HyperlinkDialogProps, type ImageMeta, type ImagePositionData, ImagePositionDialog, type ImagePositionDialogProps, type ImagePropertiesData, ImagePropertiesDialog, type ImagePropertiesDialogProps, type ImageRef, InsertImageDialog, type InsertImageDialogData, type InsertImageDialogProps, InsertSymbolDialog, type InsertSymbolDialogProps, InsertTableDialog, type InsertTableDialogData, type InsertTableDialogProps, type InsertTableStyleOption, type KeyboardShortcutScope, type MarkdownOptions, type MarkdownResult, type OutlineDepth, type OutlineItem, PageSetupDialog, type PageSetupDialogProps, PasteSpecialDialog, type PasteSpecialDialogProps, type PasteSpecialMode, type PictureWatermark, type PositionalText, type RenderAsyncOptions, type ResolvedAnchor, type ReviewDisplayMode, STELLA_STYLE_SET_NAME, type ScrollToParaIdOptions, SplitCellDialog, type SplitCellDialogData, type SplitCellDialogProps, type SuggestionAppliedAs, type SuggestionKind, type TableProperties, TablePropertiesDialog, type TablePropertiesDialogProps, type TemplatePreviewHiddenRange, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, type TextWatermark, type UseWheelZoomOptions, type UseWheelZoomReturn, type Watermark, WatermarkDialog, type WatermarkDialogProps, type WordDiffSegment, ZOOM_PRESETS, ZoomControl, type ZoomControlProps, type ZoomLevel, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clampZoom, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, finishAutocompleteSuggestion, formatZoom, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getDocumentWatermark, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView, inspectDocumentStyles, inspectDocumentStylesFromDocx, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, parseZoom, renderAsync, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setDocumentWatermark, setFocusedSuggestionMeta, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult, useWheelZoom };
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { a as formatZoom, c as FormattingBar, d as AutocompleteCaretOverlay, i as clampZoom, l as ZoomControl, n as DocxEditor, o as parseZoom, r as ZOOM_PRESETS, s as useWheelZoom, t as renderAsync } from "./renderAsync-Bh7xudNL.js";
2
- import { n as FolioUIProvider } from "./folio-ui-rCHqCEG6.js";
3
- import { t as FindReplaceDialog } from "./FindReplaceDialog-LlVMe3EW.js";
4
- import { t as FootnotePropertiesDialog } from "./FootnotePropertiesDialog-D73t3LNP.js";
5
- import { a as InsertImageDialog, i as InsertTableDialog, n as SplitCellDialog, o as HyperlinkDialog, r as PasteSpecialDialog, t as WatermarkDialog } from "./dialogs-De-oslzU.js";
6
- import { t as ImagePositionDialog } from "./ImagePositionDialog-Cwt6R8iM.js";
7
- import { t as ImagePropertiesDialog } from "./ImagePropertiesDialog-GNZLBFLB.js";
8
- import { t as InsertSymbolDialog } from "./InsertSymbolDialog-CeEhkEvc.js";
9
- import { t as PageSetupDialog } from "./PageSetupDialog-DD6IEZAo.js";
10
- import { t as TablePropertiesDialog } from "./TablePropertiesDialog-Vu0HXQz6.js";
1
+ import { a as formatZoom, c as FormattingBar, d as AutocompleteCaretOverlay, i as clampZoom, l as ZoomControl, n as DocxEditor, o as parseZoom, r as ZOOM_PRESETS, s as useWheelZoom, t as renderAsync } from "./renderAsync-D3Bxr14I.js";
2
+ import { n as FolioUIProvider } from "./folio-ui-ruRywxeb.js";
3
+ import { t as FindReplaceDialog } from "./FindReplaceDialog-CUd8xdgd.js";
4
+ import { t as FootnotePropertiesDialog } from "./FootnotePropertiesDialog-BEs7N62_.js";
5
+ import { a as InsertImageDialog, i as InsertTableDialog, n as SplitCellDialog, o as HyperlinkDialog, r as PasteSpecialDialog, t as WatermarkDialog } from "./dialogs-DGrcp10A.js";
6
+ import { t as ImagePositionDialog } from "./ImagePositionDialog-Oap9knQ-.js";
7
+ import { t as ImagePropertiesDialog } from "./ImagePropertiesDialog-lLMKHv0u.js";
8
+ import { t as InsertSymbolDialog } from "./InsertSymbolDialog-Drm40-9j.js";
9
+ import { t as PageSetupDialog } from "./PageSetupDialog-DTWCdPkX.js";
10
+ import { t as TablePropertiesDialog } from "./TablePropertiesDialog-uSTmyEcu.js";
11
11
  import { applyFolioAIEditOperations, createFolioAIEditSnapshot, diffWordSegments, hashFolioAIBlockText, normalizeFolioAIBlockText } from "@stll/folio-core/ai-edits";
12
12
  import { insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView } from "@stll/folio-core/prosemirror";
13
13
  import { createAICitationDecorationsPlugin, setAICitationsMeta, setActiveCitationMeta } from "@stll/folio-core/prosemirror/plugins/aiCitationDecorations";
@@ -1,6 +1,7 @@
1
- import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-rCHqCEG6.js";
1
+ import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-ruRywxeb.js";
2
2
  import { t as messages_exports } from "./messages.js";
3
3
  import { c } from "react-compiler-runtime";
4
+ import { readBlobText } from "@stll/folio-core/utils/textEncoding";
4
5
  import { CANONICAL_GAP, canonicalRefusalMessage, usesCanonicalSession } from "@stll/folio-core/types/canonicalCapabilities";
5
6
  import * as React$1 from "react";
6
7
  import React, { Component, Suspense, cloneElement, createContext, forwardRef, isValidElement, lazy, memo, useCallback, useEffect, useEffectEvent, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
@@ -30,7 +31,7 @@ import { executeEditorCommand, executeFirstEditorCommand } from "@stll/folio-cor
30
31
  import { insertPageBreak } from "@stll/folio-core/prosemirror/commands/pageBreak";
31
32
  import { clearTrackedChanges, getChangedParagraphIds, hasStructuralChanges, hasUntrackedChanges, repackWithEditorSectionRemovals } from "@stll/folio-core/prosemirror/extensions/features/ParagraphChangeTrackerExtension";
32
33
  import { createStarterKit } from "@stll/folio-core/prosemirror/extensions/StarterKit";
33
- import { resolveFindMatchRange } from "@stll/folio-core/prosemirror/findReplaceSelection";
34
+ import { findInMarkupView, resolveFindMatchRange } from "@stll/folio-core/prosemirror/findReplaceSelection";
34
35
  import { createAICitationDecorationsPlugin } from "@stll/folio-core/prosemirror/plugins/aiCitationDecorations";
35
36
  import { AI_SUGGESTION_SEVERITY_CLASS, aiSuggestionDecorationsKey, createAISuggestionDecorationsPlugin } from "@stll/folio-core/prosemirror/plugins/aiSuggestionDecorations";
36
37
  import { anonymizationDecorationsKey, createAnonymizationDecorationsPlugin, slugAnonymizationLabel } from "@stll/folio-core/prosemirror/plugins/anonymizationDecorations";
@@ -112,7 +113,8 @@ import { ErrorManager } from "@stll/folio-core/managers/ErrorManager";
112
113
  import { ContextMenuManager } from "@stll/folio-core/managers/ContextMenuManager";
113
114
  import { DocumentLoaderManager } from "@stll/folio-core/managers/DocumentLoaderManager";
114
115
  import { getDocumentLoadSource } from "@stll/folio-core/utils/documentLoaderBehavior";
115
- import { DISPLAY_MODES, EditorModeManager, isReadOnlyMode, isTrackChangesMode, toggledTrackChangesMode } from "@stll/folio-core/managers/EditorModeManager";
116
+ import { DISPLAY_MODES, EditorModeManager, getEditorReadOnlyReason, getReviewViewReadOnlyReason, isTrackChangesMode, toggledTrackChangesMode } from "@stll/folio-core/managers/EditorModeManager";
117
+ import { reviewDisplayModeToDisplayMode } from "@stll/folio-core/managers/reviewDisplayMode";
116
118
  import { FindReplaceManager } from "@stll/folio-core/managers/FindReplaceManager";
117
119
  import { createEmptyHeaderFooter, pickActiveHeaderFooterRId, removeHeaderFooter, resolveEffectiveSectionProperties, resolveHeaderFooterContent, saveHeaderFooterContent } from "@stll/folio-core/utils/headerFooter";
118
120
  import { createCanonicalHeaderFooterOperation, removeCanonicalHeaderFooterOperations } from "@stll/folio-core/controller/canonicalOperations";
@@ -354,9 +356,10 @@ const HOST_STYLES = {
354
356
  zIndex: -1,
355
357
  pointerEvents: "none"
356
358
  };
357
- const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ document, styles, theme, onTransaction, experimentalSession, getCanonicalApi, onSessionRefusal }, ref) {
359
+ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ document, readOnly, styles, theme, onTransaction, experimentalSession, getCanonicalApi, onSessionRefusal }, ref) {
358
360
  const hostRef = useRef(null);
359
361
  const documentRef = useRef(document);
362
+ const readOnlyRef = useRef(readOnly);
360
363
  const stylesRef = useRef(styles);
361
364
  const themeRef = useRef(theme);
362
365
  const onTransactionRef = useRef(onTransaction);
@@ -366,6 +369,7 @@ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ d
366
369
  const managerRef = useRef(null);
367
370
  useLayoutEffect(() => {
368
371
  documentRef.current = document;
372
+ readOnlyRef.current = readOnly;
369
373
  stylesRef.current = styles;
370
374
  themeRef.current = theme;
371
375
  onTransactionRef.current = onTransaction;
@@ -375,6 +379,7 @@ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ d
375
379
  managerRef.current ??= createHeaderFooterEditorManager({
376
380
  getHost: () => hostRef.current,
377
381
  getDocument: () => documentRef.current,
382
+ getReadOnly: () => readOnlyRef.current ?? false,
378
383
  getStyles: () => stylesRef.current,
379
384
  getTheme: () => themeRef.current,
380
385
  getCanonicalApi: () => canonicalApiRef.current?.() ?? null,
@@ -384,8 +389,10 @@ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ d
384
389
  onTransactionRef.current?.(rId, kind, view, docChanged, selectionChanged);
385
390
  }
386
391
  });
392
+ managerRef.current.sync();
387
393
  }, [
388
394
  document,
395
+ readOnly,
389
396
  styles,
390
397
  theme,
391
398
  onTransaction,
@@ -393,9 +400,6 @@ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ d
393
400
  experimentalSession,
394
401
  onSessionRefusal
395
402
  ]);
396
- useEffect(() => {
397
- managerRef.current?.sync();
398
- });
399
403
  useEffect(() => () => {
400
404
  managerRef.current?.destroy();
401
405
  }, []);
@@ -3044,7 +3048,7 @@ function buildFootnoteRenderItems(pageFootnoteMap, footnoteContentMap, doc) {
3044
3048
  * PagedEditor - Main paginated editing component.
3045
3049
  */
3046
3050
  const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3047
- const { document, documentIO, documentIdentity, experimentalSession, fonts: hostFonts, styles, theme: _theme, sectionProperties, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, readOnly = false, pageGap = 24, zoom = 1, pageRenderer, markupView, showMarginGuides = false, marginGuideColor, onDocumentChange, onReadOnlyEditAttempt, onCopy, onCut, onPaste, onSelectionChange, onSelectionTextChange, onEditorViewReady, externalPlugins = EMPTY_PLUGINS, showTemplateDirectives = true, collaboration, extensionManager, suggestionModeActive = false, suggestionAuthor, onActiveNoteStoryChange, onHeaderFooterDoubleClick, hfEditMode, activeHeaderFooterRId, onBodyClick, className, style, pageEndGutter = 0, sidebarOverlay, scrollContainerRef: scrollContainerRefProp, onHyperlinkClick, onContextMenu, onAnchorPositionsChange, onTotalPagesChange, onError, anchorPositionMode = "comments-and-revisions", onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq } = props;
3051
+ const { document, documentIO, documentIdentity, experimentalSession, fonts: hostFonts, styles, theme: _theme, sectionProperties, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, readOnly = false, pageGap = 24, zoom = 1, pageRenderer, markupView, showCommentHighlights = true, showMarginGuides = false, marginGuideColor, onDocumentChange, onReadOnlyEditAttempt, onCopy, onCut, onPaste, onSelectionChange, onSelectionTextChange, onEditorViewReady, externalPlugins = EMPTY_PLUGINS, showTemplateDirectives = true, collaboration, extensionManager, suggestionModeActive = false, suggestionAuthor, onActiveNoteStoryChange, onHeaderFooterDoubleClick, hfEditMode, activeHeaderFooterRId, onBodyClick, className, style, pageEndGutter = 0, sidebarOverlay, scrollContainerRef: scrollContainerRefProp, onHyperlinkClick, onContextMenu, onAnchorPositionsChange, onTotalPagesChange, onError, anchorPositionMode = "comments-and-revisions", onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq } = props;
3048
3052
  const getScrollContainer = useCallback(() => {
3049
3053
  if (scrollContainerRefProp && typeof scrollContainerRefProp === "object") return getEditorScrollRoot(scrollContainerRefProp.current);
3050
3054
  return getEditorScrollRoot(containerRef.current);
@@ -3321,6 +3325,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3321
3325
  const layoutInputSignature = useMemo(() => buildLayoutInputSignature({
3322
3326
  columns,
3323
3327
  markupView,
3328
+ showCommentHighlights,
3324
3329
  contentWidth,
3325
3330
  defaultTabStop,
3326
3331
  mirrorMargins,
@@ -3342,6 +3347,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3342
3347
  }), [
3343
3348
  columns,
3344
3349
  markupView,
3350
+ showCommentHighlights,
3345
3351
  contentWidth,
3346
3352
  defaultTabStop,
3347
3353
  mirrorMargins,
@@ -3416,7 +3422,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3416
3422
  emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES,
3417
3423
  emptyTemplatePreviewHidden: EMPTY_TEMPLATE_PREVIEW_HIDDEN,
3418
3424
  hyphenationReadiness,
3419
- markupView
3425
+ markupView,
3426
+ showCommentHighlights
3420
3427
  }, state, options);
3421
3428
  if (outcome.blocks) setBlocks(outcome.blocks);
3422
3429
  if (outcome.measures !== void 0) setMeasures(outcome.measures);
@@ -3453,6 +3460,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3453
3460
  mirrorMargins,
3454
3461
  styles,
3455
3462
  markupView,
3463
+ showCommentHighlights,
3456
3464
  layoutInputSignature,
3457
3465
  hyphenationReadiness
3458
3466
  ]);
@@ -5532,7 +5540,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5532
5540
  setIsFocused(true);
5533
5541
  });
5534
5542
  };
5535
- if (layoutSessionRef.current.lastPmDoc?.eq(view_24.state.doc) && layoutSessionRef.current.lastMeasureInputs?.markupView === markupView) {
5543
+ if (layoutSessionRef.current.lastPmDoc?.eq(view_24.state.doc) && layoutSessionRef.current.lastMeasureInputs?.markupView === markupView && layoutSessionRef.current.lastMeasureInputs?.showCommentHighlights === (showCommentHighlights && markupView !== "no-markup" && markupView !== "original")) {
5536
5544
  const lastPreview = layoutSessionRef.current.lastTemplatePreview;
5537
5545
  if (templatePreviewRef.current.mode !== lastPreview.mode || templatePreviewDirtyRange(lastPreview, templatePreviewRef.current) !== null) runLayoutPipeline$1(view_24.state, { reason: "manual" });
5538
5546
  updateSelectionOverlay(view_24.state);
@@ -5573,7 +5581,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5573
5581
  updateAutocompleteOverlay,
5574
5582
  readOnly,
5575
5583
  refreshBodyImeCaretAnchor,
5576
- markupView
5584
+ markupView,
5585
+ showCommentHighlights
5577
5586
  ]);
5578
5587
  const handleEditorViewDestroy = useCallback(() => {
5579
5588
  onEditorViewReadyRef.current?.(null);
@@ -5961,6 +5970,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5961
5970
  /* @__PURE__ */ jsx(HiddenHeaderFooterPMs, {
5962
5971
  ref: hfPMsRef,
5963
5972
  document,
5973
+ readOnly,
5964
5974
  onTransaction: handleHfPmTransaction,
5965
5975
  getCanonicalApi,
5966
5976
  onSessionRefusal: handleSessionRefusal,
@@ -8338,14 +8348,14 @@ function _temp$10(heading) {
8338
8348
  }
8339
8349
  //#endregion
8340
8350
  //#region src/components/DocxEditorDialogs.tsx
8341
- const FindReplaceDialog = lazy(() => import("./FindReplaceDialog-LlVMe3EW.js").then((n) => n.n).then((m) => ({ default: m.FindReplaceDialog })));
8342
- const TablePropertiesDialog = lazy(() => import("./TablePropertiesDialog-Vu0HXQz6.js").then((n) => n.n).then((m) => ({ default: m.TablePropertiesDialog })));
8343
- const ImagePositionDialog = lazy(() => import("./ImagePositionDialog-Cwt6R8iM.js").then((n) => n.n).then((m) => ({ default: m.ImagePositionDialog })));
8344
- const ImagePropertiesDialog = lazy(() => import("./ImagePropertiesDialog-GNZLBFLB.js").then((n) => n.n).then((m) => ({ default: m.ImagePropertiesDialog })));
8345
- const FootnotePropertiesDialog = lazy(() => import("./FootnotePropertiesDialog-D73t3LNP.js").then((n) => n.n).then((m) => ({ default: m.FootnotePropertiesDialog })));
8346
- const PageSetupDialog = lazy(() => import("./PageSetupDialog-DD6IEZAo.js").then((n) => n.n).then((m) => ({ default: m.PageSetupDialog })));
8347
- const SetNumberingValueDialog = lazy(() => import("./SetNumberingValueDialog-CDQGDvP1.js").then((m) => ({ default: m.SetNumberingValueDialog })));
8348
- const InsertSymbolDialog = lazy(() => import("./InsertSymbolDialog-CeEhkEvc.js").then((n) => n.n).then((m) => ({ default: m.InsertSymbolDialog })));
8351
+ const FindReplaceDialog = lazy(() => import("./FindReplaceDialog-CUd8xdgd.js").then((n) => n.n).then((m) => ({ default: m.FindReplaceDialog })));
8352
+ const TablePropertiesDialog = lazy(() => import("./TablePropertiesDialog-uSTmyEcu.js").then((n) => n.n).then((m) => ({ default: m.TablePropertiesDialog })));
8353
+ const ImagePositionDialog = lazy(() => import("./ImagePositionDialog-Oap9knQ-.js").then((n) => n.n).then((m) => ({ default: m.ImagePositionDialog })));
8354
+ const ImagePropertiesDialog = lazy(() => import("./ImagePropertiesDialog-lLMKHv0u.js").then((n) => n.n).then((m) => ({ default: m.ImagePropertiesDialog })));
8355
+ const FootnotePropertiesDialog = lazy(() => import("./FootnotePropertiesDialog-BEs7N62_.js").then((n) => n.n).then((m) => ({ default: m.FootnotePropertiesDialog })));
8356
+ const PageSetupDialog = lazy(() => import("./PageSetupDialog-DTWCdPkX.js").then((n) => n.n).then((m) => ({ default: m.PageSetupDialog })));
8357
+ const SetNumberingValueDialog = lazy(() => import("./SetNumberingValueDialog-twVIZMLc.js").then((m) => ({ default: m.SetNumberingValueDialog })));
8358
+ const InsertSymbolDialog = lazy(() => import("./InsertSymbolDialog-Drm40-9j.js").then((n) => n.n).then((m) => ({ default: m.InsertSymbolDialog })));
8349
8359
  function DocxEditorDialogs(t0) {
8350
8360
  const $ = c(52);
8351
8361
  const { findReplace, tableProperties, imagePosition, imageProperties, pageSetup, footnoteProperties, insertSymbol, setNumberingValue } = t0;
@@ -10785,8 +10795,8 @@ const useDocumentLoader = (t0) => {
10785
10795
  * editing mode does not switch the display mode.
10786
10796
  */
10787
10797
  function useEditorMode(t0) {
10788
- const $ = c(24);
10789
- const { modeProp, onModeChange, readOnlyProp } = t0;
10798
+ const $ = c(28);
10799
+ const { modeProp, onModeChange, readOnlyProp, reviewDisplayMode } = t0;
10790
10800
  let t1;
10791
10801
  if ($[0] !== modeProp) {
10792
10802
  t1 = () => new EditorModeManager(modeProp ?? "editing");
@@ -10808,60 +10818,75 @@ function useEditorMode(t0) {
10808
10818
  $[5] = t2;
10809
10819
  } else t2 = $[5];
10810
10820
  const setEditingMode = t2;
10821
+ let effectiveDisplayMode;
10811
10822
  let t3;
10812
- if ($[6] !== editingMode || $[7] !== readOnlyProp) {
10813
- t3 = isReadOnlyMode(editingMode, readOnlyProp);
10814
- $[6] = editingMode;
10815
- $[7] = readOnlyProp;
10816
- $[8] = t3;
10817
- } else t3 = $[8];
10818
- const readOnly = t3;
10823
+ if ($[6] !== displayMode || $[7] !== editingMode || $[8] !== readOnlyProp || $[9] !== reviewDisplayMode) {
10824
+ effectiveDisplayMode = reviewDisplayMode === void 0 ? displayMode : reviewDisplayModeToDisplayMode(reviewDisplayMode);
10825
+ t3 = getEditorReadOnlyReason({
10826
+ editingMode,
10827
+ readOnlyProp,
10828
+ displayMode: effectiveDisplayMode
10829
+ });
10830
+ $[6] = displayMode;
10831
+ $[7] = editingMode;
10832
+ $[8] = readOnlyProp;
10833
+ $[9] = reviewDisplayMode;
10834
+ $[10] = effectiveDisplayMode;
10835
+ $[11] = t3;
10836
+ } else {
10837
+ effectiveDisplayMode = $[10];
10838
+ t3 = $[11];
10839
+ }
10840
+ const readOnlyReason = t3;
10841
+ const readOnly = readOnlyReason !== null;
10819
10842
  let t4;
10820
- if ($[9] !== editingMode) {
10843
+ if ($[12] !== editingMode) {
10821
10844
  t4 = isTrackChangesMode(editingMode);
10822
- $[9] = editingMode;
10823
- $[10] = t4;
10824
- } else t4 = $[10];
10845
+ $[12] = editingMode;
10846
+ $[13] = t4;
10847
+ } else t4 = $[13];
10825
10848
  const trackChangesOn = t4;
10826
10849
  let t5;
10827
- if ($[11] !== editingMode || $[12] !== setEditingMode) {
10850
+ if ($[14] !== editingMode || $[15] !== setEditingMode) {
10828
10851
  t5 = () => {
10829
10852
  setEditingMode(toggledTrackChangesMode(editingMode));
10830
10853
  };
10831
- $[11] = editingMode;
10832
- $[12] = setEditingMode;
10833
- $[13] = t5;
10834
- } else t5 = $[13];
10854
+ $[14] = editingMode;
10855
+ $[15] = setEditingMode;
10856
+ $[16] = t5;
10857
+ } else t5 = $[16];
10835
10858
  const toggleTrackChanges = t5;
10836
10859
  let t6;
10837
- if ($[14] !== manager) {
10860
+ if ($[17] !== manager) {
10838
10861
  t6 = (mode_0) => {
10839
10862
  manager.setDisplayMode(mode_0);
10840
10863
  };
10841
- $[14] = manager;
10842
- $[15] = t6;
10843
- } else t6 = $[15];
10864
+ $[17] = manager;
10865
+ $[18] = t6;
10866
+ } else t6 = $[18];
10844
10867
  const setDisplayMode = t6;
10845
10868
  let t7;
10846
- if ($[16] !== displayMode || $[17] !== editingMode || $[18] !== readOnly || $[19] !== setDisplayMode || $[20] !== setEditingMode || $[21] !== toggleTrackChanges || $[22] !== trackChangesOn) {
10869
+ if ($[19] !== editingMode || $[20] !== effectiveDisplayMode || $[21] !== readOnly || $[22] !== readOnlyReason || $[23] !== setDisplayMode || $[24] !== setEditingMode || $[25] !== toggleTrackChanges || $[26] !== trackChangesOn) {
10847
10870
  t7 = {
10848
10871
  editingMode,
10849
10872
  setEditingMode,
10850
10873
  readOnly,
10874
+ readOnlyReason,
10851
10875
  trackChangesOn,
10852
10876
  toggleTrackChanges,
10853
- displayMode,
10877
+ displayMode: effectiveDisplayMode,
10854
10878
  setDisplayMode
10855
10879
  };
10856
- $[16] = displayMode;
10857
- $[17] = editingMode;
10858
- $[18] = readOnly;
10859
- $[19] = setDisplayMode;
10860
- $[20] = setEditingMode;
10861
- $[21] = toggleTrackChanges;
10862
- $[22] = trackChangesOn;
10863
- $[23] = t7;
10864
- } else t7 = $[23];
10880
+ $[19] = editingMode;
10881
+ $[20] = effectiveDisplayMode;
10882
+ $[21] = readOnly;
10883
+ $[22] = readOnlyReason;
10884
+ $[23] = setDisplayMode;
10885
+ $[24] = setEditingMode;
10886
+ $[25] = toggleTrackChanges;
10887
+ $[26] = trackChangesOn;
10888
+ $[27] = t7;
10889
+ } else t7 = $[27];
10865
10890
  return t7;
10866
10891
  }
10867
10892
  //#endregion
@@ -10879,71 +10904,130 @@ function useEditorMode(t0) {
10879
10904
  * from `dialogs/useFindReplace.ts`; this hook layers the document-aware
10880
10905
  * operations (find, replace, scroll-to-match) on top.
10881
10906
  */
10907
+ const toEditorFindMatch = ({ from, to, ...match }) => ({
10908
+ ...match,
10909
+ contentIndex: 0,
10910
+ authoredRange: {
10911
+ from,
10912
+ to
10913
+ }
10914
+ });
10882
10915
  function useFindReplace(t0) {
10883
- const $ = c(35);
10884
- const { documentState, getDocumentState, containerRef, handleDocumentChange, findReplace, selectMatch } = t0;
10916
+ const $ = c(49);
10917
+ const { documentState, getDocumentState, getEditorState, markupView: markupViewProp, containerRef, handleDocumentChange, findReplace, selectMatch, readOnlyReason, onReadonlyEditAttempt } = t0;
10918
+ const markupView = markupViewProp ?? "all-markup";
10885
10919
  let t1;
10886
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
10887
- t1 = new FindReplaceManager();
10888
- $[0] = t1;
10889
- } else t1 = $[0];
10890
- const manager = t1;
10920
+ if ($[0] !== markupView || $[1] !== readOnlyReason) {
10921
+ t1 = getReviewViewReadOnlyReason(markupView) ?? readOnlyReason ?? null;
10922
+ $[0] = markupView;
10923
+ $[1] = readOnlyReason;
10924
+ $[2] = t1;
10925
+ } else t1 = $[2];
10926
+ const replacementRefusal = t1;
10927
+ let t2;
10928
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
10929
+ t2 = new FindReplaceManager();
10930
+ $[3] = t2;
10931
+ } else t2 = $[3];
10932
+ const manager = t2;
10891
10933
  const [currentResult, setCurrentResult] = useState(null);
10934
+ const activeSearch = useRef(null);
10892
10935
  const { setMatches, goToMatch } = findReplace;
10893
- let t2;
10894
- if ($[1] !== setMatches) {
10895
- t2 = () => {
10936
+ let t3;
10937
+ if ($[4] !== setMatches) {
10938
+ t3 = () => {
10939
+ activeSearch.current = null;
10896
10940
  manager.clear();
10897
10941
  setCurrentResult(null);
10898
10942
  setMatches([], 0);
10899
10943
  };
10900
- $[1] = setMatches;
10901
- $[2] = t2;
10902
- } else t2 = $[2];
10903
- const resetFindResult = t2;
10904
- let t3;
10905
- if ($[3] !== documentState || $[4] !== getDocumentState) {
10906
- t3 = () => getDocumentState?.() ?? documentState ?? null;
10907
- $[3] = documentState;
10908
- $[4] = getDocumentState;
10944
+ $[4] = setMatches;
10909
10945
  $[5] = t3;
10910
10946
  } else t3 = $[5];
10911
- const readDocumentState = t3;
10947
+ const resetFindResult = t3;
10912
10948
  let t4;
10913
- if ($[6] !== containerRef || $[7] !== selectMatch) {
10914
- t4 = (match) => {
10915
- if (!selectMatch?.(match) && containerRef.current) scrollToMatch(containerRef.current, match);
10916
- };
10917
- $[6] = containerRef;
10918
- $[7] = selectMatch;
10949
+ if ($[6] !== documentState || $[7] !== getDocumentState) {
10950
+ t4 = () => getDocumentState?.() ?? documentState ?? null;
10951
+ $[6] = documentState;
10952
+ $[7] = getDocumentState;
10919
10953
  $[8] = t4;
10920
10954
  } else t4 = $[8];
10921
- const revealMatch = t4;
10955
+ const readDocumentState = t4;
10922
10956
  let t5;
10923
- if ($[9] !== readDocumentState || $[10] !== resetFindResult || $[11] !== revealMatch || $[12] !== setMatches) {
10924
- t5 = (searchText, options) => {
10957
+ if ($[9] !== containerRef || $[10] !== selectMatch) {
10958
+ t5 = (match) => {
10959
+ if (!selectMatch?.(match) && containerRef.current) scrollToMatch(containerRef.current, match);
10960
+ };
10961
+ $[9] = containerRef;
10962
+ $[10] = selectMatch;
10963
+ $[11] = t5;
10964
+ } else t5 = $[11];
10965
+ const revealMatch = t5;
10966
+ let t6;
10967
+ if ($[12] !== getEditorState || $[13] !== markupView || $[14] !== readDocumentState || $[15] !== resetFindResult || $[16] !== revealMatch || $[17] !== setMatches) {
10968
+ t6 = (searchText, options) => {
10925
10969
  const currentDocument = readDocumentState();
10926
10970
  if (!currentDocument || !searchText.trim()) {
10927
10971
  resetFindResult();
10928
10972
  return null;
10929
10973
  }
10930
- const matches = findInDocument(currentDocument, searchText, options);
10974
+ const editorState = getEditorState?.();
10975
+ let matches;
10976
+ if (markupView === "all-markup") matches = findInDocument(currentDocument, searchText, options);
10977
+ else {
10978
+ if (!editorState) {
10979
+ resetFindResult();
10980
+ return null;
10981
+ }
10982
+ matches = findInMarkupView({
10983
+ state: editorState,
10984
+ markupView,
10985
+ searchText,
10986
+ options
10987
+ }).map(toEditorFindMatch);
10988
+ }
10989
+ activeSearch.current = {
10990
+ searchText,
10991
+ options
10992
+ };
10931
10993
  const result = manager.setMatches(matches);
10932
10994
  setCurrentResult(result);
10933
10995
  setMatches(matches, 0);
10934
10996
  if (matches.length > 0) revealMatch(matches[0]);
10935
10997
  return result;
10936
10998
  };
10937
- $[9] = readDocumentState;
10938
- $[10] = resetFindResult;
10939
- $[11] = revealMatch;
10940
- $[12] = setMatches;
10941
- $[13] = t5;
10942
- } else t5 = $[13];
10943
- const handleFind = t5;
10944
- let t6;
10945
- if ($[14] !== goToMatch || $[15] !== revealMatch) {
10946
- t6 = () => {
10999
+ $[12] = getEditorState;
11000
+ $[13] = markupView;
11001
+ $[14] = readDocumentState;
11002
+ $[15] = resetFindResult;
11003
+ $[16] = revealMatch;
11004
+ $[17] = setMatches;
11005
+ $[18] = t6;
11006
+ } else t6 = $[18];
11007
+ const handleFind = t6;
11008
+ const previousMarkupView = useRef(markupView);
11009
+ let t7;
11010
+ let t8;
11011
+ if ($[19] !== handleFind || $[20] !== markupView) {
11012
+ t7 = () => {
11013
+ if (previousMarkupView.current === markupView) return;
11014
+ previousMarkupView.current = markupView;
11015
+ const search = activeSearch.current;
11016
+ if (search) handleFind(search.searchText, search.options);
11017
+ };
11018
+ t8 = [markupView, handleFind];
11019
+ $[19] = handleFind;
11020
+ $[20] = markupView;
11021
+ $[21] = t7;
11022
+ $[22] = t8;
11023
+ } else {
11024
+ t7 = $[21];
11025
+ t8 = $[22];
11026
+ }
11027
+ useEffect(t7, t8);
11028
+ let t9;
11029
+ if ($[23] !== goToMatch || $[24] !== revealMatch) {
11030
+ t9 = () => {
10947
11031
  const stepped = manager.navigate("next");
10948
11032
  if (!stepped) return null;
10949
11033
  setCurrentResult(manager.getResult());
@@ -10951,14 +11035,14 @@ function useFindReplace(t0) {
10951
11035
  revealMatch(stepped.match);
10952
11036
  return stepped.match;
10953
11037
  };
10954
- $[14] = goToMatch;
10955
- $[15] = revealMatch;
10956
- $[16] = t6;
10957
- } else t6 = $[16];
10958
- const handleFindNext = t6;
10959
- let t7;
10960
- if ($[17] !== goToMatch || $[18] !== revealMatch) {
10961
- t7 = () => {
11038
+ $[23] = goToMatch;
11039
+ $[24] = revealMatch;
11040
+ $[25] = t9;
11041
+ } else t9 = $[25];
11042
+ const handleFindNext = t9;
11043
+ let t10;
11044
+ if ($[26] !== goToMatch || $[27] !== revealMatch) {
11045
+ t10 = () => {
10962
11046
  const stepped_0 = manager.navigate("previous");
10963
11047
  if (!stepped_0) return null;
10964
11048
  setCurrentResult(manager.getResult());
@@ -10966,14 +11050,14 @@ function useFindReplace(t0) {
10966
11050
  revealMatch(stepped_0.match);
10967
11051
  return stepped_0.match;
10968
11052
  };
10969
- $[17] = goToMatch;
10970
- $[18] = revealMatch;
10971
- $[19] = t7;
10972
- } else t7 = $[19];
10973
- const handleFindPrevious = t7;
10974
- let t8;
10975
- if ($[20] !== handleDocumentChange || $[21] !== readDocumentState) {
10976
- t8 = (replaceText) => {
11053
+ $[26] = goToMatch;
11054
+ $[27] = revealMatch;
11055
+ $[28] = t10;
11056
+ } else t10 = $[28];
11057
+ const handleFindPrevious = t10;
11058
+ let t11;
11059
+ if ($[29] !== handleDocumentChange || $[30] !== readDocumentState) {
11060
+ t11 = (replaceText) => {
10977
11061
  const currentDocument_0 = readDocumentState();
10978
11062
  if (!currentDocument_0) return false;
10979
11063
  const newDoc = manager.replaceCurrent(currentDocument_0, replaceText);
@@ -10981,14 +11065,14 @@ function useFindReplace(t0) {
10981
11065
  handleDocumentChange(newDoc);
10982
11066
  return true;
10983
11067
  };
10984
- $[20] = handleDocumentChange;
10985
- $[21] = readDocumentState;
10986
- $[22] = t8;
10987
- } else t8 = $[22];
10988
- const handleReplace = t8;
10989
- let t9;
10990
- if ($[23] !== handleDocumentChange || $[24] !== readDocumentState || $[25] !== resetFindResult) {
10991
- t9 = (searchText_0, replaceText_0, options_0) => {
11068
+ $[29] = handleDocumentChange;
11069
+ $[30] = readDocumentState;
11070
+ $[31] = t11;
11071
+ } else t11 = $[31];
11072
+ const handleReplace = t11;
11073
+ let t12;
11074
+ if ($[32] !== handleDocumentChange || $[33] !== readDocumentState || $[34] !== resetFindResult) {
11075
+ t12 = (searchText_0, replaceText_0, options_0) => {
10992
11076
  const currentDocument_1 = readDocumentState();
10993
11077
  if (!currentDocument_1 || !searchText_0.trim()) return 0;
10994
11078
  const matches_0 = findInDocument(currentDocument_1, searchText_0, options_0);
@@ -10998,33 +11082,56 @@ function useFindReplace(t0) {
10998
11082
  resetFindResult();
10999
11083
  return outcome.replacedCount;
11000
11084
  };
11001
- $[23] = handleDocumentChange;
11002
- $[24] = readDocumentState;
11003
- $[25] = resetFindResult;
11004
- $[26] = t9;
11005
- } else t9 = $[26];
11006
- const handleReplaceAll = t9;
11007
- let t10;
11008
- if ($[27] !== currentResult || $[28] !== handleFind || $[29] !== handleFindNext || $[30] !== handleFindPrevious || $[31] !== handleReplace || $[32] !== handleReplaceAll || $[33] !== resetFindResult) {
11009
- t10 = {
11085
+ $[32] = handleDocumentChange;
11086
+ $[33] = readDocumentState;
11087
+ $[34] = resetFindResult;
11088
+ $[35] = t12;
11089
+ } else t12 = $[35];
11090
+ const handleReplaceAll = t12;
11091
+ let t13;
11092
+ if ($[36] !== onReadonlyEditAttempt || $[37] !== replacementRefusal) {
11093
+ t13 = () => {
11094
+ if (replacementRefusal) onReadonlyEditAttempt?.(replacementRefusal);
11095
+ return false;
11096
+ };
11097
+ $[36] = onReadonlyEditAttempt;
11098
+ $[37] = replacementRefusal;
11099
+ $[38] = t13;
11100
+ } else t13 = $[38];
11101
+ const refuseReplace = t13;
11102
+ let t14;
11103
+ if ($[39] !== refuseReplace) {
11104
+ t14 = () => {
11105
+ refuseReplace();
11106
+ return 0;
11107
+ };
11108
+ $[39] = refuseReplace;
11109
+ $[40] = t14;
11110
+ } else t14 = $[40];
11111
+ const refuseReplaceAll = t14;
11112
+ const t15 = replacementRefusal ? refuseReplace : handleReplace;
11113
+ const t16 = replacementRefusal ? refuseReplaceAll : handleReplaceAll;
11114
+ let t17;
11115
+ if ($[41] !== currentResult || $[42] !== handleFind || $[43] !== handleFindNext || $[44] !== handleFindPrevious || $[45] !== resetFindResult || $[46] !== t15 || $[47] !== t16) {
11116
+ t17 = {
11010
11117
  currentResult,
11011
11118
  resetFindResult,
11012
11119
  handleFind,
11013
11120
  handleFindNext,
11014
11121
  handleFindPrevious,
11015
- handleReplace,
11016
- handleReplaceAll
11122
+ handleReplace: t15,
11123
+ handleReplaceAll: t16
11017
11124
  };
11018
- $[27] = currentResult;
11019
- $[28] = handleFind;
11020
- $[29] = handleFindNext;
11021
- $[30] = handleFindPrevious;
11022
- $[31] = handleReplace;
11023
- $[32] = handleReplaceAll;
11024
- $[33] = resetFindResult;
11025
- $[34] = t10;
11026
- } else t10 = $[34];
11027
- return t10;
11125
+ $[41] = currentResult;
11126
+ $[42] = handleFind;
11127
+ $[43] = handleFindNext;
11128
+ $[44] = handleFindPrevious;
11129
+ $[45] = resetFindResult;
11130
+ $[46] = t15;
11131
+ $[47] = t16;
11132
+ $[48] = t17;
11133
+ } else t17 = $[48];
11134
+ return t17;
11028
11135
  }
11029
11136
  //#endregion
11030
11137
  //#region src/components/hooks/useHeaderFooterEditor.ts
@@ -13818,7 +13925,7 @@ function _temp(id_4) {
13818
13925
  */
13819
13926
  /** No headings to track while the outline is not shown. */
13820
13927
  const NO_HEADINGS = [];
13821
- const CommentsSidebar = lazy(() => import("./CommentsSidebar-mv0x1JQX.js").then((m) => ({ default: m.CommentsSidebar })));
13928
+ const CommentsSidebar = lazy(() => import("./CommentsSidebar-D7eTgHpL.js").then((m) => ({ default: m.CommentsSidebar })));
13822
13929
  const TextContextMenu = lazy(() => import("./TextContextMenu-DZ3AUFKh.js").then((m) => ({ default: m.TextContextMenu })));
13823
13930
  const loadAttemptSelectiveSave = async () => {
13824
13931
  const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
@@ -13920,7 +14027,7 @@ const createPagedEditorBinding = () => {
13920
14027
  /**
13921
14028
  * DocxEditor - Complete DOCX editor component
13922
14029
  */
13923
- const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, document: initialDocument, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, pageRenderer, showMarginGuides = false, marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, keyboardShortcuts = DEFAULT_KEYBOARD_SHORTCUT_SCOPE, hostShortcuts: hostShortcutsProp, readOnly: readOnlyProp = false, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, outlineDepth: outlineDepthProp, onOutlineDepthChange, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy, onCut, onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, comments: commentsProp, onCommentsChange, collaboration, plugins, featureFlags, experimentalSession, onSelectiveSaveTripwire }, ref) {
14030
+ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, document: initialDocument, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, pageRenderer, showMarginGuides = false, marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, keyboardShortcuts = DEFAULT_KEYBOARD_SHORTCUT_SCOPE, hostShortcuts: hostShortcutsProp, readOnly: readOnlyProp = false, reviewDisplayMode, showCommentHighlights = true, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, outlineDepth: outlineDepthProp, onOutlineDepthChange, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy, onCut, onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, comments: commentsProp, onCommentsChange, collaboration, plugins, featureFlags, experimentalSession, onSelectiveSaveTripwire }, ref) {
13924
14031
  const pagedEditorRef = useRef(null);
13925
14032
  const [pagedEditorBinding] = useState(createPagedEditorBinding);
13926
14033
  const scrollContainerRef = useRef(null);
@@ -13975,10 +14082,11 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13975
14082
  setTrackedChangeEntries(entries);
13976
14083
  }, []);
13977
14084
  const [anchorPositions, setAnchorPositions] = useState(EMPTY_ANCHOR_POSITIONS);
13978
- const { editingMode, readOnly, trackChangesOn, toggleTrackChanges, displayMode, setDisplayMode } = useEditorMode({
14085
+ const { editingMode, readOnly, readOnlyReason, trackChangesOn, toggleTrackChanges, displayMode, setDisplayMode } = useEditorMode({
13979
14086
  modeProp,
13980
14087
  onModeChange,
13981
- readOnlyProp
14088
+ readOnlyProp,
14089
+ ...reviewDisplayMode === void 0 ? {} : { reviewDisplayMode }
13982
14090
  });
13983
14091
  useEffect(() => {
13984
14092
  pagedEditorRef.current?.getEditor().setCanonicalMode(editingMode === "suggesting" ? {
@@ -14321,6 +14429,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14321
14429
  ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
14322
14430
  getHfView: pagedEditorBinding.getHfView
14323
14431
  });
14432
+ useLayoutEffect(() => {
14433
+ if (readOnly && hfEditPosition) handleBodyClick();
14434
+ }, [
14435
+ readOnly,
14436
+ hfEditPosition,
14437
+ handleBodyClick
14438
+ ]);
14324
14439
  let activeHfRId = hfEditIsFirstPage ? activeFirstFooterRId : activeFooterRId;
14325
14440
  if (hfEditPosition === "header") activeHfRId = hfEditIsFirstPage ? activeFirstHeaderRId : activeHeaderRId;
14326
14441
  const visibleOutlineHeadings = useMemo(() => filterHeadingsByDepth(outlineHeadings, outlineDepth), [outlineDepth, outlineHeadings]);
@@ -14670,23 +14785,31 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14670
14785
  canonicalCommentsSerialized,
14671
14786
  onCommentsChange
14672
14787
  ]);
14788
+ const selectFindMatch = useCallback((match) => {
14789
+ const editor_1 = pagedEditorRef.current;
14790
+ const view_8 = editor_1?.getView();
14791
+ if (!editor_1 || !view_8) return false;
14792
+ const range = match.authoredRange ?? resolveFindMatchRange(view_8.state.doc, match);
14793
+ if (!range) return false;
14794
+ editor_1.setSelection(range.from, range.to);
14795
+ requestAnimationFrame(() => {
14796
+ editor_1.scrollToPosition(range.from);
14797
+ });
14798
+ return true;
14799
+ }, []);
14800
+ const notifyReadonlyEditAttempt = useCallback(() => {
14801
+ if (readOnlyReason) onReadonlyEditAttempt?.(readOnlyReason);
14802
+ }, [readOnlyReason, onReadonlyEditAttempt]);
14673
14803
  const { currentResult: currentFindResult, resetFindResult, handleFind, handleFindNext, handleFindPrevious, handleReplace, handleReplaceAll } = useFindReplace({
14674
14804
  getDocumentState: buildCurrentDocument,
14805
+ getEditorState: () => pagedEditorRef.current?.getView()?.state ?? null,
14806
+ markupView: displayMode,
14675
14807
  containerRef,
14676
14808
  handleDocumentChange,
14677
14809
  findReplace,
14678
- selectMatch: useCallback((match) => {
14679
- const editor_1 = pagedEditorRef.current;
14680
- const view_8 = editor_1?.getView();
14681
- if (!editor_1 || !view_8) return false;
14682
- const range = resolveFindMatchRange(view_8.state.doc, match);
14683
- if (!range) return false;
14684
- editor_1.setSelection(range.from, range.to);
14685
- requestAnimationFrame(() => {
14686
- editor_1.scrollToPosition(range.from);
14687
- });
14688
- return true;
14689
- }, [])
14810
+ selectMatch: selectFindMatch,
14811
+ readOnlyReason,
14812
+ onReadonlyEditAttempt
14690
14813
  });
14691
14814
  useLayoutEffect(() => {
14692
14815
  resetFindResultRef.current = resetFindResult;
@@ -15479,8 +15602,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15479
15602
  let html = "";
15480
15603
  let text_1 = "";
15481
15604
  for (const item_1 of items_0) {
15482
- if (item_1.types.includes("text/html")) html = await (await item_1.getType("text/html")).text();
15483
- if (item_1.types.includes("text/plain")) text_1 = await (await item_1.getType("text/plain")).text();
15605
+ if (item_1.types.includes("text/html")) html = await readBlobText(await item_1.getType("text/html"));
15606
+ if (item_1.types.includes("text/plain")) text_1 = await readBlobText(await item_1.getType("text/plain"));
15484
15607
  }
15485
15608
  const dt = new DataTransfer();
15486
15609
  if (html) dt.items.add(html, "text/html");
@@ -15785,6 +15908,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15785
15908
  onError?.(error_1);
15786
15909
  }, [onError]);
15787
15910
  useImperativeHandle(ref, () => ({
15911
+ getReadOnlyReason: () => readOnlyReason,
15788
15912
  getDocument: () => buildCurrentDocument(),
15789
15913
  hasPendingChanges: () => {
15790
15914
  const view_21 = pagedEditorRef.current?.getView();
@@ -15811,6 +15935,10 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15811
15935
  openFind(readFindSelectionSeed());
15812
15936
  },
15813
15937
  openReplace: () => {
15938
+ if (readOnlyReason) {
15939
+ notifyReadonlyEditAttempt();
15940
+ return;
15941
+ }
15814
15942
  openReplace(readFindSelectionSeed());
15815
15943
  },
15816
15944
  loadDocument: (document_0) => {
@@ -16233,7 +16361,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16233
16361
  getPageText: (page_1) => {
16234
16362
  const view_44 = pagedEditorRef.current?.getView();
16235
16363
  if (!view_44) return null;
16236
- return getPageTextFromLayout(pagedEditorRef.current?.getEditor()?.getLayout() ?? null, view_44.state.doc, page_1);
16364
+ return getPageTextFromLayout({
16365
+ layout: pagedEditorRef.current?.getEditor()?.getLayout() ?? null,
16366
+ doc: view_44.state.doc,
16367
+ page: page_1,
16368
+ projection: projectMarkupView(view_44.state, displayMode)
16369
+ });
16237
16370
  },
16238
16371
  getTargetPage: (target_2, snapshot_6) => {
16239
16372
  const view_45 = pagedEditorRef.current?.getView();
@@ -16303,6 +16436,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16303
16436
  }), [
16304
16437
  author,
16305
16438
  buildCurrentDocument,
16439
+ displayMode,
16440
+ readOnlyReason,
16441
+ notifyReadonlyEditAttempt,
16306
16442
  scrollPageInfo,
16307
16443
  handleSave,
16308
16444
  setZoomWithViewportAnchor,
@@ -17241,6 +17377,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
17241
17377
  documentIO,
17242
17378
  documentIdentity: loadedDocumentIdentity,
17243
17379
  markupView: displayMode,
17380
+ showCommentHighlights,
17244
17381
  ...fonts !== void 0 ? { fonts } : {},
17245
17382
  theme: history.state.package.theme || theme || null,
17246
17383
  sectionProperties: effectiveSectionProperties ?? null,
@@ -17271,7 +17408,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
17271
17408
  ...onCopy !== void 0 ? { onCopy } : {},
17272
17409
  ...onCut !== void 0 ? { onCut } : {},
17273
17410
  ...onPaste !== void 0 ? { onPaste } : {},
17274
- ...onReadonlyEditAttempt !== void 0 ? { onReadOnlyEditAttempt: onReadonlyEditAttempt } : {},
17411
+ ...onReadonlyEditAttempt !== void 0 ? { onReadOnlyEditAttempt: notifyReadonlyEditAttempt } : {},
17275
17412
  onSelectionChange: handlePagedSelectionChange,
17276
17413
  ...onSelectionTextChange !== void 0 ? { onSelectionTextChange } : {},
17277
17414
  onEditorViewReady: handleBodyViewReady,
@@ -7,6 +7,8 @@ import { FolioDocumentOperationBatch, FolioDocumentOperationResult, FolioDocumen
7
7
  import { ContentControlFilter, SetContentControlContentInput, SetContentControlValueInput } from "@stll/folio-core/content-controls";
8
8
  import { PageRendererName } from "@stll/folio-core/display-list/editor/pageRenderer";
9
9
  import { HostShortcut, KeyboardShortcutScope } from "@stll/folio-core/managers/editorShortcuts";
10
+ import { EditorMode, EditorReadOnlyReason } from "@stll/folio-core/managers/EditorModeManager";
11
+ import { ReviewDisplayMode } from "@stll/folio-core/managers/reviewDisplayMode";
10
12
  import { FolioEditor } from "@stll/folio-core/controller/folioEditor";
11
13
  import { DocxCompatibility } from "@stll/folio-core/docx/compatibility";
12
14
  import { FolioSelectiveSaveFlags } from "@stll/folio-core/docx/selectiveSaveFlags";
@@ -20,7 +22,6 @@ import { Comment } from "@stll/folio-core/types/content";
20
22
  import { DocxInput } from "@stll/folio-core/utils/docxInput";
21
23
  import { ScrollToParaIdOptions } from "@stll/folio-core/paged-layout/paragraphFlash";
22
24
  import { BlockRect } from "@stll/folio-core/paged-layout/blockGeometry";
23
- import { EditorMode } from "@stll/folio-core/managers/EditorModeManager";
24
25
  import "@stll/folio-core/controller/noteEditorManager";
25
26
  import { Layout } from "@stll/folio-core/layout-engine/types";
26
27
  import "@stll/folio-core/prosemirror/extensions/ExtensionManager";
@@ -749,6 +750,10 @@ type DocxEditorProps = {
749
750
  hostShortcuts?: readonly HostShortcut[];
750
751
  /** Whether the editor is read-only. When true, hides toolbar and rulers */
751
752
  readOnly?: boolean;
753
+ /** Controlled review view. Defaults to all-markup; saving preserves all revisions. */
754
+ reviewDisplayMode?: ReviewDisplayMode;
755
+ /** Show comment highlights in all-markup (default: true); hidden in final/original. */
756
+ showCommentHighlights?: boolean;
752
757
  /**
753
758
  * Whether the comments sidebar opens when a document with open comment
754
759
  * threads loads (default: true). It stays closed when it would be empty:
@@ -830,7 +835,7 @@ type DocxEditorProps = {
830
835
  /** Callback when the editing mode changes */
831
836
  onModeChange?: (mode: EditorMode) => void;
832
837
  /** Callback when a readonly user action would mutate the document. */
833
- onReadonlyEditAttempt?: () => void;
838
+ onReadonlyEditAttempt?: (reason: EditorReadOnlyReason) => void;
834
839
  /**
835
840
  * Controlled comments array. When provided, the editor reads comment thread
836
841
  * metadata from this prop and emits every change through `onCommentsChange`.
@@ -969,6 +974,8 @@ type HighlightPassageOptions = {
969
974
  * Imperative handle exposed by the DocxEditor component.
970
975
  */
971
976
  type DocxEditorRef = {
977
+ /** Current reason user editing is refused, or null in an editable view. */
978
+ getReadOnlyReason: () => EditorReadOnlyReason | null;
972
979
  /** Get the current document */
973
980
  getDocument: () => Document | null;
974
981
  /** Whether the live ProseMirror state has edits that have not been serialized. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-react",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "React editor for folio: a Word-document (.docx) editor for the browser, built on @stll/folio-core and ProseMirror.",
5
5
  "keywords": [
6
6
  "document-editor",
@@ -37,23 +37,28 @@
37
37
  "exports": {
38
38
  ".": {
39
39
  "types": "./dist/index.d.ts",
40
- "import": "./dist/index.js"
40
+ "import": "./dist/index.js",
41
+ "default": "./dist/index.js"
41
42
  },
42
43
  "./compat/eigenpal": {
43
44
  "types": "./dist/compat/eigenpal.d.ts",
44
- "import": "./dist/compat/eigenpal.js"
45
+ "import": "./dist/compat/eigenpal.js",
46
+ "default": "./dist/compat/eigenpal.js"
45
47
  },
46
48
  "./dialogs": {
47
49
  "types": "./dist/dialogs.d.ts",
48
- "import": "./dist/dialogs.js"
50
+ "import": "./dist/dialogs.js",
51
+ "default": "./dist/dialogs.js"
49
52
  },
50
53
  "./messages/*": {
51
54
  "types": "./dist/i18n/messages/*.d.ts",
52
- "import": "./dist/i18n/messages/*.js"
55
+ "import": "./dist/i18n/messages/*.js",
56
+ "default": "./dist/i18n/messages/*.js"
53
57
  },
54
58
  "./messages": {
55
59
  "types": "./dist/messages.d.ts",
56
- "import": "./dist/messages.js"
60
+ "import": "./dist/messages.js",
61
+ "default": "./dist/messages.js"
57
62
  },
58
63
  "./editor.css": "./dist/editor.css",
59
64
  "./standalone.css": "./dist/standalone.css"
@@ -79,7 +84,10 @@
79
84
  "@fontsource/noto-sans-arabic": "^5.2.7",
80
85
  "@fontsource/source-sans-3": "^5.2.9",
81
86
  "@fontsource/tinos": "^5.2.7",
82
- "@stll/folio-core": "^0.60.0",
87
+ "@stll/folio-core": "^0.61.0",
88
+ "@stll/utf8-boundaries": "0.1.0",
89
+ "@types/react": "^19.2.17",
90
+ "@types/react-dom": "^19.2.3",
83
91
  "better-result": "3.0.1",
84
92
  "lucide-react": "1.24.0",
85
93
  "react-compiler-runtime": "^1.0.0"
@@ -96,14 +104,22 @@
96
104
  "yjs": "^13.6.31"
97
105
  },
98
106
  "peerDependencies": {
107
+ "prosemirror-commands": "^1.7.1",
108
+ "prosemirror-dropcursor": "^1.8.2",
109
+ "prosemirror-gapcursor": "^1.4.1",
99
110
  "prosemirror-history": "^1.5.0",
111
+ "prosemirror-inputrules": "^1.5.0",
112
+ "prosemirror-keymap": "^1.2.3",
100
113
  "prosemirror-model": "^1.25.9",
101
114
  "prosemirror-state": "^1.4.4",
102
115
  "prosemirror-tables": "^1.8.5",
116
+ "prosemirror-transform": "^1.12.0",
103
117
  "prosemirror-view": "^1.42.6",
104
118
  "react": "^19.2.0",
105
119
  "react-dom": "^19.2.0",
106
120
  "use-intl": ">=4.0.0",
121
+ "y-prosemirror": "^1.3.7",
122
+ "y-protocols": "^1.0.6",
107
123
  "yjs": "^13.6.31"
108
124
  },
109
125
  "main": "./dist/index.js",