@stll/folio-react 0.1.1 → 0.2.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/{FindReplaceDialog-CG1VKA_g.js → FindReplaceDialog-EFjmqEbg.js} +1 -1
- package/dist/{FootnotePropertiesDialog-MuW4D3gt.js → FootnotePropertiesDialog-VfF7SQo2.js} +1 -1
- package/dist/{ImagePositionDialog-BQnOnDf4.js → ImagePositionDialog-FGLCOf0Q.js} +1 -1
- package/dist/{ImagePropertiesDialog-Dn4N7qZv.js → ImagePropertiesDialog-Baokui4M.js} +2 -2
- package/dist/{PageSetupDialog-CxJUEkoC.js → PageSetupDialog-Df2HjHiu.js} +1 -1
- package/dist/{TablePropertiesDialog-mQMnGfHu.js → TablePropertiesDialog-ZmzjSqME.js} +1 -1
- package/dist/{TextContextMenu-DzTbp2sn.js → TextContextMenu-CG0V37wi.js} +5 -1
- package/dist/editor.css +1 -1
- package/dist/{folio-ui-o_rftArH.js → folio-ui-CA59webC.js} +13 -6
- package/dist/index.d.ts +51 -3
- package/dist/index.js +187 -44
- package/dist/messages-heGr9XLo.js +2827 -0
- package/dist/messages.d.ts +1 -1
- package/dist/messages.js +1 -2166
- package/dist/standalone.css +1 -0
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { t as containedHandler } from "./contained-handler-4uiqUVRn.js";
|
|
2
|
-
import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-
|
|
2
|
+
import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-CA59webC.js";
|
|
3
3
|
import { i as findInDocument, o as scrollToMatch, t as useFindReplace$1 } from "./useFindReplace-MZ8wi31A.js";
|
|
4
|
+
import { n as getFolioMessages } from "./messages-heGr9XLo.js";
|
|
4
5
|
import * as React$1 from "react";
|
|
5
|
-
import { Component, Suspense, cloneElement, createContext, isValidElement, lazy, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
+
import React, { Component, Suspense, cloneElement, createContext, isValidElement, lazy, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
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";
|
|
7
|
-
import { useTranslations } from "use-intl";
|
|
8
|
+
import { IntlProvider, useTranslations } from "use-intl";
|
|
8
9
|
import { applyFolioAIEditOperations, applyFolioAIEditOperations as applyFolioAIEditOperations$1, createFolioAIEditSnapshot, createFolioAIEditSnapshot as createFolioAIEditSnapshot$1, diffWordSegments, hashFolioAIBlockText, normalizeFolioAIBlockText } from "@stll/folio-core/ai-edits";
|
|
9
10
|
import { normalizeBaseDirection } from "@stll/folio-core/docx/normalizeBaseDirection";
|
|
10
11
|
import { getCachedNumberingMap } from "@stll/folio-core/docx/numberingParser";
|
|
@@ -66,16 +67,17 @@ import { collectRunFontsAtPmPositions, measureContentLeft, projectRangesToRects
|
|
|
66
67
|
import { isReadOnlyEditKey } from "@stll/folio-core/paged-layout/readOnlyEditAttempt";
|
|
67
68
|
import { getPageScrollTarget, prefersReducedMotionBehavior } from "@stll/folio-core/paged-layout/scrollNavigation";
|
|
68
69
|
import { PAGES_CONTAINER_CLASS, scrollFolioPositionIntoView, scrollPagesToPmPosition } from "@stll/folio-core/paged-layout/scrollToPmPosition";
|
|
70
|
+
import { flashParagraphFragmentsByParaId } from "@stll/folio-core/paged-layout/paragraphFlash";
|
|
69
71
|
import { DEFAULT_PAGE_HEIGHT_PX, getMargins, getPageSize, twipsToPixels as twipsToPixels$1 } from "@stll/folio-core/paged-layout/sectionGeometry";
|
|
70
72
|
import { resizeColumnPair } from "@stll/folio-core/paged-layout/tableColumnResize";
|
|
71
73
|
import { tableInsertButtonOffset } from "@stll/folio-core/paged-layout/tableInsertButtonGeometry";
|
|
72
74
|
import { getTransactionDirtyRange } from "@stll/folio-core/paged-layout/transactionDirtyRange";
|
|
75
|
+
import { findParagraphByParaId, findStartPosForParaId } from "@stll/folio-core/prosemirror/utils/findParagraphByParaId";
|
|
73
76
|
import { expectFontFamilyMarkAttrs, expectImageAttrs, expectTableAttrs, expectTableCellAttrs, mergeImageAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs } from "@stll/folio-core/prosemirror/attrs";
|
|
74
77
|
import { extractEmbeddedFonts } from "@stll/folio-core/fonts/embeddedFonts";
|
|
75
78
|
import { panic } from "better-result";
|
|
76
79
|
import { collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState } from "@stll/folio-core/controller/hiddenEditorManager";
|
|
77
80
|
import { createFolioAIEditSnapshot as createFolioAIEditSnapshot$2 } from "@stll/folio-core/ai-edits/snapshot";
|
|
78
|
-
import { findParagraphByParaId } from "@stll/folio-core/prosemirror/utils/findParagraphByParaId";
|
|
79
81
|
import { deriveBlockId, getFolioParaIdFromBlockId, getFolioParaIdFromBlockId as getFolioParaIdFromBlockId$1, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "@stll/folio-core/types/block-id";
|
|
80
82
|
import { CONTENT_CONTROL_WIDGET_EVENT_NAME, dispatchDatePick, dispatchDropdownPick } from "@stll/folio-core/prosemirror/plugins/contentControlWidgets";
|
|
81
83
|
import { ErrorManager } from "@stll/folio-core/managers/ErrorManager";
|
|
@@ -91,6 +93,7 @@ import { applyImagePosition, applyImageProperties, applyImageTransform, applyIma
|
|
|
91
93
|
import { classifyEditorKeydown, deleteSelectedTable, isFocusInInputLike, isMacPlatform } from "@stll/folio-core/managers/editorShortcuts";
|
|
92
94
|
import { getScrollTopForZoomAnchor, getViewportCenterZoomAnchorForZoomChange } from "@stll/folio-core/paged-layout/zoomScrollAnchor";
|
|
93
95
|
import { redo, undo } from "prosemirror-history";
|
|
96
|
+
import { createRoot } from "react-dom/client";
|
|
94
97
|
import { createEmptyDocument } from "@stll/folio-core/utils/createDocument";
|
|
95
98
|
import { createDocx } from "@stll/folio-core/docx/rezip";
|
|
96
99
|
import { DEFAULT_AI_SUGGESTION_PRESETS } from "@stll/folio-core/ai-suggestions/types";
|
|
@@ -3569,6 +3572,24 @@ function PagedEditor(props) {
|
|
|
3569
3572
|
inline: "nearest"
|
|
3570
3573
|
});
|
|
3571
3574
|
}, [layout, scrollToPositionImpl]);
|
|
3575
|
+
const scrollToParaIdImpl = useCallback((paraId, options) => {
|
|
3576
|
+
const state = hiddenPMRef.current?.getState();
|
|
3577
|
+
if (!state) return false;
|
|
3578
|
+
const startPos = findStartPosForParaId(state.doc, paraId);
|
|
3579
|
+
if (startPos == null || startPos < 0) return false;
|
|
3580
|
+
scrollToPositionImpl(startPos);
|
|
3581
|
+
requestAnimationFrame(() => {
|
|
3582
|
+
if (options?.highlight) {
|
|
3583
|
+
const pages = pagesContainerRef.current;
|
|
3584
|
+
if (pages) flashParagraphFragmentsByParaId(pages, paraId, options.highlight);
|
|
3585
|
+
}
|
|
3586
|
+
const targetNode = state.doc.nodeAt(startPos);
|
|
3587
|
+
const inner = targetNode?.isTextblock === true ? Math.min(startPos + 1 + targetNode.content.size, state.doc.content.size) : Math.min(startPos + 1, state.doc.content.size);
|
|
3588
|
+
hiddenPMRef.current?.setSelection(inner);
|
|
3589
|
+
hiddenPMRef.current?.focus();
|
|
3590
|
+
});
|
|
3591
|
+
return true;
|
|
3592
|
+
}, [scrollToPositionImpl]);
|
|
3572
3593
|
const focusHiddenEditor = useCallback(() => {
|
|
3573
3594
|
if (readOnly) {
|
|
3574
3595
|
containerRef.current?.focus({ preventScroll: true });
|
|
@@ -4989,6 +5010,7 @@ function PagedEditor(props) {
|
|
|
4989
5010
|
},
|
|
4990
5011
|
scrollToPosition: scrollToPositionImpl,
|
|
4991
5012
|
scrollToPage: scrollToPageImpl,
|
|
5013
|
+
scrollToParaId: scrollToParaIdImpl,
|
|
4992
5014
|
getPageNumberForPmPos(pmPos) {
|
|
4993
5015
|
const container = pagesContainerRef.current;
|
|
4994
5016
|
if (!container) return null;
|
|
@@ -5028,6 +5050,7 @@ function PagedEditor(props) {
|
|
|
5028
5050
|
ensureHiddenEditorView,
|
|
5029
5051
|
folioEditor,
|
|
5030
5052
|
scrollToPageImpl,
|
|
5053
|
+
scrollToParaIdImpl,
|
|
5031
5054
|
scrollToPositionImpl
|
|
5032
5055
|
]);
|
|
5033
5056
|
useEffect(() => {
|
|
@@ -6238,30 +6261,34 @@ function ContentControlWidgetsOverlay({ getEditorView }) {
|
|
|
6238
6261
|
if (liveView && value.length > 0) dispatchDatePick(liveView, open.pmPos, value);
|
|
6239
6262
|
close();
|
|
6240
6263
|
};
|
|
6241
|
-
return createPortal(/* @__PURE__ */
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
className: "
|
|
6249
|
-
children: open.
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6264
|
+
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
6265
|
+
className: "folio-root",
|
|
6266
|
+
style: { display: "contents" },
|
|
6267
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
6268
|
+
role: "dialog",
|
|
6269
|
+
"aria-label": open.kind === "dropdown" ? t("contentControlDropdownAriaLabel") : t("contentControlDateAriaLabel"),
|
|
6270
|
+
style,
|
|
6271
|
+
className: "bg-popover text-popover-foreground min-w-[10rem] rounded-md border p-1 shadow-md",
|
|
6272
|
+
children: [open.kind === "dropdown" && /* @__PURE__ */ jsx("div", {
|
|
6273
|
+
role: "menu",
|
|
6274
|
+
className: "flex flex-col",
|
|
6275
|
+
children: open.items.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
6276
|
+
className: "text-muted-foreground px-2 py-1 text-sm",
|
|
6277
|
+
children: t("contentControlDropdownNoOptions")
|
|
6278
|
+
}) : open.items.map((item) => /* @__PURE__ */ jsx(MenuItem, {
|
|
6279
|
+
onClick: () => onDropdownPick(item.value),
|
|
6280
|
+
children: item.displayText
|
|
6281
|
+
}, `${item.value}::${item.displayText}`))
|
|
6282
|
+
}), open.kind === "date" && /* @__PURE__ */ jsx(DatePickerPopover, {
|
|
6283
|
+
clearLabel: t("clearDate"),
|
|
6284
|
+
defaultOpen: true,
|
|
6285
|
+
onChange: (value) => {
|
|
6286
|
+
if (value) onDatePick(value);
|
|
6287
|
+
},
|
|
6288
|
+
showIcon: false,
|
|
6289
|
+
value: null
|
|
6290
|
+
})]
|
|
6291
|
+
})
|
|
6265
6292
|
}), document.body);
|
|
6266
6293
|
}
|
|
6267
6294
|
//#endregion
|
|
@@ -6345,12 +6372,12 @@ const DocumentOutline = ({ headings, scrollContainerRef, topOffset, docSize, onH
|
|
|
6345
6372
|
};
|
|
6346
6373
|
//#endregion
|
|
6347
6374
|
//#region src/components/DocxEditorDialogs.tsx
|
|
6348
|
-
const FindReplaceDialog = lazy(() => import("./FindReplaceDialog-
|
|
6349
|
-
const TablePropertiesDialog = lazy(() => import("./TablePropertiesDialog-
|
|
6350
|
-
const ImagePositionDialog = lazy(() => import("./ImagePositionDialog-
|
|
6351
|
-
const ImagePropertiesDialog = lazy(() => import("./ImagePropertiesDialog-
|
|
6352
|
-
const FootnotePropertiesDialog = lazy(() => import("./FootnotePropertiesDialog-
|
|
6353
|
-
const PageSetupDialog = lazy(() => import("./PageSetupDialog-
|
|
6375
|
+
const FindReplaceDialog = lazy(() => import("./FindReplaceDialog-EFjmqEbg.js").then((m) => ({ default: m.FindReplaceDialog })));
|
|
6376
|
+
const TablePropertiesDialog = lazy(() => import("./TablePropertiesDialog-ZmzjSqME.js").then((m) => ({ default: m.TablePropertiesDialog })));
|
|
6377
|
+
const ImagePositionDialog = lazy(() => import("./ImagePositionDialog-FGLCOf0Q.js").then((m) => ({ default: m.ImagePositionDialog })));
|
|
6378
|
+
const ImagePropertiesDialog = lazy(() => import("./ImagePropertiesDialog-Baokui4M.js").then((m) => ({ default: m.ImagePropertiesDialog })));
|
|
6379
|
+
const FootnotePropertiesDialog = lazy(() => import("./FootnotePropertiesDialog-VfF7SQo2.js").then((m) => ({ default: m.FootnotePropertiesDialog })));
|
|
6380
|
+
const PageSetupDialog = lazy(() => import("./PageSetupDialog-Df2HjHiu.js").then((m) => ({ default: m.PageSetupDialog })));
|
|
6354
6381
|
function DocxEditorDialogs({ findReplace, tableProperties, imagePosition, imageProperties, pageSetup, footnoteProperties }) {
|
|
6355
6382
|
return /* @__PURE__ */ jsxs(Suspense, {
|
|
6356
6383
|
fallback: null,
|
|
@@ -6672,7 +6699,7 @@ function ToolbarButton({ active = false, disabled = false, title, onClick, onDou
|
|
|
6672
6699
|
};
|
|
6673
6700
|
const button = /* @__PURE__ */ jsx("button", {
|
|
6674
6701
|
type: "button",
|
|
6675
|
-
className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-md", "transition-colors duration-100", "
|
|
6702
|
+
className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-md", "transition-colors duration-100", "antialiased", "text-[var(--doc-text-muted)] hover:bg-[var(--doc-primary-light)] hover:text-[var(--doc-text)]", active && "bg-[var(--doc-primary-light)] text-[var(--doc-text)] hover:bg-[var(--doc-primary-light)]", disabled && "cursor-not-allowed text-[var(--doc-text-subtle)] opacity-[0.16] disabled:hover:bg-transparent disabled:hover:text-[var(--doc-text-subtle)]", className),
|
|
6676
6703
|
onMouseDown: handleMouseDown,
|
|
6677
6704
|
onClick: disabled ? void 0 : onClick,
|
|
6678
6705
|
onDoubleClick: disabled ? void 0 : onDoubleClick,
|
|
@@ -9691,21 +9718,32 @@ const getBuiltinTableStyle = (styleId) => BUILTIN_STYLES.find((s) => s.id === st
|
|
|
9691
9718
|
* (`replaceComments`/`updateComments`) stay in the component because they
|
|
9692
9719
|
* depend on its document-build pipeline.
|
|
9693
9720
|
*/
|
|
9694
|
-
function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorContentRef }) {
|
|
9721
|
+
function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorContentRef, commentsProp, onCommentsChange }) {
|
|
9695
9722
|
const [showCommentsSidebar, setShowCommentsSidebar] = useState(false);
|
|
9696
9723
|
const [visibleCommentAuthors, setVisibleCommentAuthors] = useState(null);
|
|
9697
9724
|
const [activeCommentId, setActiveCommentId] = useState(null);
|
|
9698
|
-
const [
|
|
9725
|
+
const [internalComments, setInternalComments] = useState([]);
|
|
9726
|
+
const isControlledComments = commentsProp !== void 0;
|
|
9727
|
+
const comments = isControlledComments ? commentsProp : internalComments;
|
|
9699
9728
|
const commentsDirtyRef = useRef(false);
|
|
9700
|
-
const commentsRef = useRef(
|
|
9729
|
+
const commentsRef = useRef(comments);
|
|
9701
9730
|
commentsRef.current = comments;
|
|
9731
|
+
const onCommentsChangeRef = useRef(onCommentsChange);
|
|
9732
|
+
onCommentsChangeRef.current = onCommentsChange;
|
|
9733
|
+
const setComments = useCallback((next) => {
|
|
9734
|
+
const resolved = typeof next === "function" ? next(commentsRef.current) : next;
|
|
9735
|
+
if (resolved === commentsRef.current) return;
|
|
9736
|
+
commentsRef.current = resolved;
|
|
9737
|
+
if (!isControlledComments) setInternalComments(resolved);
|
|
9738
|
+
onCommentsChangeRef.current?.(resolved);
|
|
9739
|
+
}, [isControlledComments]);
|
|
9702
9740
|
const [isAddingComment, setIsAddingComment] = useState(false);
|
|
9703
9741
|
const [commentSelectionRange, setCommentSelectionRange] = useState(null);
|
|
9704
9742
|
const [addCommentYPosition, setAddCommentYPosition] = useState(null);
|
|
9705
9743
|
const [floatingCommentBtn, setFloatingCommentBtn] = useState(null);
|
|
9706
9744
|
const commentsLoadedRef = useRef(false);
|
|
9707
9745
|
useEffect(() => {
|
|
9708
|
-
if (commentsLoadedRef.current) return;
|
|
9746
|
+
if (isControlledComments || commentsLoadedRef.current) return;
|
|
9709
9747
|
if (!doc) return;
|
|
9710
9748
|
const bodyComments = doc.package.document.comments;
|
|
9711
9749
|
if (bodyComments && bodyComments.length > 0) {
|
|
@@ -9715,7 +9753,12 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
|
|
|
9715
9753
|
if (autoOpenReviewSidebar) setShowCommentsSidebar(true);
|
|
9716
9754
|
commentsLoadedRef.current = true;
|
|
9717
9755
|
}
|
|
9718
|
-
}, [
|
|
9756
|
+
}, [
|
|
9757
|
+
autoOpenReviewSidebar,
|
|
9758
|
+
doc,
|
|
9759
|
+
isControlledComments,
|
|
9760
|
+
setComments
|
|
9761
|
+
]);
|
|
9719
9762
|
const commentAuthors = useMemo(() => {
|
|
9720
9763
|
const seen = /* @__PURE__ */ new Set();
|
|
9721
9764
|
const authors = [];
|
|
@@ -9801,6 +9844,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
|
|
|
9801
9844
|
return {
|
|
9802
9845
|
comments,
|
|
9803
9846
|
setComments,
|
|
9847
|
+
isControlledComments,
|
|
9804
9848
|
commentsRef,
|
|
9805
9849
|
commentsDirtyRef,
|
|
9806
9850
|
commentsLoadedRef,
|
|
@@ -9836,7 +9880,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
|
|
|
9836
9880
|
* - Loading states
|
|
9837
9881
|
*/
|
|
9838
9882
|
const CommentsSidebar = lazy(() => import("./CommentsSidebar-BsYOInaX.js").then((m) => ({ default: m.CommentsSidebar })));
|
|
9839
|
-
const TextContextMenu = lazy(() => import("./TextContextMenu-
|
|
9883
|
+
const TextContextMenu = lazy(() => import("./TextContextMenu-CG0V37wi.js").then((m) => ({ default: m.TextContextMenu })));
|
|
9840
9884
|
const loadAttemptSelectiveSave = async () => {
|
|
9841
9885
|
const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
|
|
9842
9886
|
return attemptSelectiveSave;
|
|
@@ -9915,7 +9959,7 @@ function areActiveTrackedChangesEqual(a, b) {
|
|
|
9915
9959
|
/**
|
|
9916
9960
|
* DocxEditor - Complete DOCX editor component
|
|
9917
9961
|
*/
|
|
9918
|
-
function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKey, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, showMarginGuides: _showMarginGuides = false, marginGuideColor: _marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, readOnly: readOnlyProp = false, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy: _onCopy, onCut: _onCut, onPaste: _onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, collaboration, featureFlags, onSelectiveSaveTripwire }) {
|
|
9962
|
+
function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKey, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, showMarginGuides: _showMarginGuides = false, marginGuideColor: _marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, readOnly: readOnlyProp = false, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy: _onCopy, onCut: _onCut, onPaste: _onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, comments: commentsProp, onCommentsChange, collaboration, featureFlags, onSelectiveSaveTripwire }) {
|
|
9919
9963
|
const t = useTranslations("folio");
|
|
9920
9964
|
useEffect(() => {
|
|
9921
9965
|
const onClipboardReadError = () => {
|
|
@@ -10129,7 +10173,9 @@ function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKe
|
|
|
10129
10173
|
doc: history.state,
|
|
10130
10174
|
autoOpenReviewSidebar,
|
|
10131
10175
|
anchorPositions,
|
|
10132
|
-
editorContentRef
|
|
10176
|
+
editorContentRef,
|
|
10177
|
+
commentsProp,
|
|
10178
|
+
onCommentsChange
|
|
10133
10179
|
});
|
|
10134
10180
|
const styleResolverCacheRef = useRef(null);
|
|
10135
10181
|
const getCachedStyleResolver = useCallback((styles) => {
|
|
@@ -11390,6 +11436,7 @@ function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKe
|
|
|
11390
11436
|
scrollToPage: (pageNumber) => {
|
|
11391
11437
|
pagedEditorRef.current?.scrollToPage(pageNumber);
|
|
11392
11438
|
},
|
|
11439
|
+
scrollToParaId: (paraId, options) => pagedEditorRef.current?.scrollToParaId(paraId, options) ?? false,
|
|
11393
11440
|
openPrintPreview: handleDirectPrint,
|
|
11394
11441
|
print: handleDirectPrint,
|
|
11395
11442
|
loadDocument: loadParsedDocument,
|
|
@@ -12318,4 +12365,100 @@ function DocxEditor({ ref, documentBuffer, document: initialDocument, documentKe
|
|
|
12318
12365
|
});
|
|
12319
12366
|
}
|
|
12320
12367
|
//#endregion
|
|
12321
|
-
|
|
12368
|
+
//#region src/renderAsync.tsx
|
|
12369
|
+
/**
|
|
12370
|
+
* Imperative API for mounting a DOCX editor into a DOM element.
|
|
12371
|
+
*
|
|
12372
|
+
* Returns a framework-agnostic {@link EditorHandle} extended with zoom and
|
|
12373
|
+
* scroll helpers. Wraps the editor in `IntlProvider` so `use-intl` works
|
|
12374
|
+
* without extra host setup.
|
|
12375
|
+
*
|
|
12376
|
+
* ```ts
|
|
12377
|
+
* import { renderAsync } from "@stll/folio-react";
|
|
12378
|
+
* import "@stll/folio-react/standalone.css";
|
|
12379
|
+
*
|
|
12380
|
+
* const editor = await renderAsync(buffer, document.getElementById("host")!, {
|
|
12381
|
+
* readOnly: false,
|
|
12382
|
+
* showToolbar: true,
|
|
12383
|
+
* });
|
|
12384
|
+
*
|
|
12385
|
+
* const blob = await editor.save();
|
|
12386
|
+
* editor.destroy();
|
|
12387
|
+
* ```
|
|
12388
|
+
*/
|
|
12389
|
+
/**
|
|
12390
|
+
* Render a DOCX editor into a container element.
|
|
12391
|
+
*
|
|
12392
|
+
* Resolves once the document has parsed and the first `onChange` fires.
|
|
12393
|
+
* Rejects if `onError` runs before that milestone.
|
|
12394
|
+
*/
|
|
12395
|
+
const renderAsync = (input, container, options = {}) => {
|
|
12396
|
+
const { locale = "en", ...editorOptions } = options;
|
|
12397
|
+
return new Promise((resolve, reject) => {
|
|
12398
|
+
const ref = React.createRef();
|
|
12399
|
+
let root = null;
|
|
12400
|
+
let settled = false;
|
|
12401
|
+
try {
|
|
12402
|
+
root = createRoot(container);
|
|
12403
|
+
} catch (error) {
|
|
12404
|
+
reject(error);
|
|
12405
|
+
return;
|
|
12406
|
+
}
|
|
12407
|
+
const handle = {
|
|
12408
|
+
save: async () => {
|
|
12409
|
+
const buffer = await (ref.current?.save() ?? Promise.resolve(null));
|
|
12410
|
+
if (!buffer) return null;
|
|
12411
|
+
return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
|
|
12412
|
+
},
|
|
12413
|
+
getDocument: () => ref.current?.getDocument() ?? null,
|
|
12414
|
+
focus: () => {
|
|
12415
|
+
ref.current?.focus();
|
|
12416
|
+
},
|
|
12417
|
+
setZoom: (zoom) => {
|
|
12418
|
+
ref.current?.setZoom(zoom);
|
|
12419
|
+
},
|
|
12420
|
+
scrollToPosition: (pmPos) => {
|
|
12421
|
+
ref.current?.getEditorRef()?.scrollToPosition(pmPos);
|
|
12422
|
+
},
|
|
12423
|
+
scrollToPage: (pageNumber) => {
|
|
12424
|
+
ref.current?.scrollToPage(pageNumber);
|
|
12425
|
+
},
|
|
12426
|
+
destroy: () => {
|
|
12427
|
+
if (!settled) {
|
|
12428
|
+
settled = true;
|
|
12429
|
+
reject(/* @__PURE__ */ new Error("Editor was destroyed before mounting completed."));
|
|
12430
|
+
}
|
|
12431
|
+
root?.unmount();
|
|
12432
|
+
root = null;
|
|
12433
|
+
}
|
|
12434
|
+
};
|
|
12435
|
+
const element = /* @__PURE__ */ jsx(IntlProvider, {
|
|
12436
|
+
locale,
|
|
12437
|
+
messages: getFolioMessages(locale),
|
|
12438
|
+
children: /* @__PURE__ */ jsx(DocxEditor, {
|
|
12439
|
+
...editorOptions,
|
|
12440
|
+
documentBuffer: input,
|
|
12441
|
+
onError: (error) => {
|
|
12442
|
+
editorOptions["onError"]?.(error);
|
|
12443
|
+
if (!settled) {
|
|
12444
|
+
settled = true;
|
|
12445
|
+
root?.unmount();
|
|
12446
|
+
root = null;
|
|
12447
|
+
reject(error);
|
|
12448
|
+
}
|
|
12449
|
+
},
|
|
12450
|
+
onChange: (doc) => {
|
|
12451
|
+
editorOptions["onChange"]?.(doc);
|
|
12452
|
+
if (!settled) {
|
|
12453
|
+
settled = true;
|
|
12454
|
+
resolve(handle);
|
|
12455
|
+
}
|
|
12456
|
+
},
|
|
12457
|
+
ref
|
|
12458
|
+
})
|
|
12459
|
+
});
|
|
12460
|
+
root.render(element);
|
|
12461
|
+
});
|
|
12462
|
+
};
|
|
12463
|
+
//#endregion
|
|
12464
|
+
export { AutocompleteCaretOverlay, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DocxEditor, FolioUIProvider, FormattingBar, ZOOM_PRESETS, ZoomControl, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clampZoom, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, finishAutocompleteSuggestion, formatZoom, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, parseZoom, renderAsync, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult, useWheelZoom };
|