@stll/folio-react 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { d as containedHandler } from "./renderAsync-a7G-ZAcV.js";
1
+ import { d as containedHandler } from "./renderAsync-CLAjsAP6.js";
2
2
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import { CheckIcon, MoreVerticalIcon } from "lucide-react";
4
4
  import { useLocale, useTranslations } from "use-intl";
@@ -1,4 +1,4 @@
1
- import { n as DocxEditor$1, t as renderAsync } from "../renderAsync-a7G-ZAcV.js";
1
+ import { n as DocxEditor$1, t as renderAsync } from "../renderAsync-CLAjsAP6.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,35 +1,8 @@
1
1
  import React, { CSSProperties } from "react";
2
- import { Document, EndnoteProperties, FootnoteProperties, SectionProperties } from "@stll/folio-core/types/document";
2
+ import { EndnoteProperties, FootnoteProperties, SectionProperties } from "@stll/folio-core/types/document";
3
+ import { FindMatch, FindOptions, FindResult } from "@stll/folio-core/utils/findReplace";
3
4
  import { Watermark } from "@stll/folio-core/watermark";
4
5
 
5
- //#region src/components/dialogs/findReplaceUtils.d.ts
6
- /**
7
- * A single match result in the document
8
- */
9
- type FindMatch = {
10
- /** Index of the paragraph containing the match */paragraphIndex: number; /** Index of the run/content within the paragraph */
11
- contentIndex: number; /** Character offset within the content */
12
- startOffset: number; /** Character offset for end of match */
13
- endOffset: number; /** The matched text */
14
- text: string;
15
- };
16
- /**
17
- * Find options for controlling search behavior
18
- */
19
- type FindOptions = {
20
- /** Whether to match case */matchCase: boolean; /** Whether to match whole words only */
21
- matchWholeWord: boolean; /** Whether to use regular expressions (future) */
22
- useRegex?: boolean;
23
- };
24
- /**
25
- * Find result with all matches
26
- */
27
- type FindResult = {
28
- /** All matches found */matches: FindMatch[]; /** Total match count */
29
- totalCount: number; /** Current match index (0-based) */
30
- currentIndex: number;
31
- };
32
- //#endregion
33
6
  //#region src/components/dialogs/FindReplaceDialog.d.ts
34
7
  /**
35
8
  * Props for the FindReplaceDialog component
package/dist/dialogs.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- 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-DK8OVUT_.js";
1
+ 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-auOIiNGI.js";
2
2
  export { FindReplaceDialog, type FindReplaceDialogProps, FootnotePropertiesDialog, type FootnotePropertiesDialogProps, type HyperlinkBookmarkOption, HyperlinkDialog, type HyperlinkDialogData, type HyperlinkDialogProps, type ImagePositionData, ImagePositionDialog, type ImagePositionDialogProps, type ImagePropertiesData, ImagePropertiesDialog, type ImagePropertiesDialogProps, InsertImageDialog, type InsertImageDialogData, type InsertImageDialogProps, InsertSymbolDialog, type InsertSymbolDialogProps, InsertTableDialog, type InsertTableDialogData, type InsertTableDialogProps, type InsertTableStyleOption, PageSetupDialog, type PageSetupDialogProps, PasteSpecialDialog, type PasteSpecialDialogProps, type PasteSpecialMode, SplitCellDialog, type SplitCellDialogData, type SplitCellDialogProps, type TableProperties, TablePropertiesDialog, type TablePropertiesDialogProps, WatermarkDialog, type WatermarkDialogProps };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as FontDefinition, a as DocxEditorApplyDocumentOperationsOptions, c as DocxEditorRef, d as FontOption, f as ColorPreset, g as OutlineItem, h as FolioUIProvider, i as renderAsync, l as ToolbarProps, m as FolioUIComponents, n as EditorHandle, o as DocxEditorCollaboration, p as FolioButtonProps, r as RenderAsyncOptions, s as DocxEditorProps, t as DocxEditorHandle, u as EditorMode } from "./renderAsync-7RA6LEtu.js";
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-DK8OVUT_.js";
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-auOIiNGI.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";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as formatZoom, c as FormattingBar, i as clampZoom, l as ZoomControl, n as DocxEditor, o as parseZoom, r as ZOOM_PRESETS, s as useWheelZoom, t as renderAsync, u as AutocompleteCaretOverlay } from "./renderAsync-a7G-ZAcV.js";
1
+ import { a as formatZoom, c as FormattingBar, i as clampZoom, l as ZoomControl, n as DocxEditor, o as parseZoom, r as ZOOM_PRESETS, s as useWheelZoom, t as renderAsync, u as AutocompleteCaretOverlay } from "./renderAsync-CLAjsAP6.js";
2
2
  import { n as FolioUIProvider } from "./folio-ui-BgDDRsUX.js";
3
3
  import { t as FindReplaceDialog } from "./FindReplaceDialog-CqKK82nE.js";
4
4
  import { t as FootnotePropertiesDialog } from "./FootnotePropertiesDialog-CixRdIiT.js";
@@ -36,14 +36,9 @@ import { formatPx, pixelsToTwips, pointsToHalfPoints, twipsToPixels } from "@stl
36
36
  import { HistoryManager, classifyHistoryShortcut } from "@stll/folio-core/managers/HistoryManager";
37
37
  import { TableSelectionManager } from "@stll/folio-core/managers/TableSelectionManager";
38
38
  import { createPortal } from "react-dom";
39
- import { EditorState, NodeSelection, Selection, TextSelection as TextSelection$1 } from "prosemirror-state";
39
+ import { NodeSelection, Selection, TextSelection as TextSelection$1 } from "prosemirror-state";
40
40
  import { CellSelection } from "prosemirror-tables";
41
- import { EditorView } from "prosemirror-view";
42
- import { headerFooterToProseDoc } from "@stll/folio-core/prosemirror/conversion/toProseDoc";
43
- import { ensureBaseDirectionInState } from "@stll/folio-core/prosemirror/extensions/features/AutoBidiDetectionExtension";
44
- import { ensureParaIdsInState } from "@stll/folio-core/prosemirror/extensions/features/ParaIdAllocatorExtension";
45
- import { createDocumentStylesPlugin } from "@stll/folio-core/prosemirror/plugins/documentStyles";
46
- import { schema as schema$1 } from "@stll/folio-core/prosemirror/schema";
41
+ import { createHeaderFooterEditorManager } from "@stll/folio-core/controller/headerFooterEditorManager";
47
42
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
48
43
  import { createFolioEditor } from "@stll/folio-core/controller/folioEditor";
49
44
  import { createFolioEditorEmitter } from "@stll/folio-core/controller/folioEditorEvents";
@@ -80,9 +75,11 @@ import { expectImageAttrs, expectTableAttrs, expectTableCellAttrs, mergeImageAtt
80
75
  import { extractEmbeddedFonts } from "@stll/folio-core/fonts/embeddedFonts";
81
76
  import { panic } from "better-result";
82
77
  import { collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState } from "@stll/folio-core/controller/hiddenEditorManager";
78
+ import { loadCollaborationModules } from "@stll/folio-core/controller/collaborationModules";
83
79
  import { clampRangeToDocSize, resolveFolioAIBlockRange, resolveFolioAITextRange } from "@stll/folio-core/ai-edits/blockRange";
84
80
  import { getPageTextFromLayout } from "@stll/folio-core/paged-layout/pageText";
85
81
  import { CONTENT_CONTROL_WIDGET_EVENT_NAME, dispatchDatePick, dispatchDropdownPick } from "@stll/folio-core/prosemirror/plugins/contentControlWidgets";
82
+ import { createDefaultFindOptions, findInDocument } from "@stll/folio-core/utils/findReplace";
86
83
  import { ErrorManager } from "@stll/folio-core/managers/ErrorManager";
87
84
  import { ContextMenuManager } from "@stll/folio-core/managers/ContextMenuManager";
88
85
  import { DocumentLoaderManager } from "@stll/folio-core/managers/DocumentLoaderManager";
@@ -311,54 +308,7 @@ function useTableSelection(t0) {
311
308
  }
312
309
  //#endregion
313
310
  //#region src/components/HiddenHeaderFooterPMs.tsx
314
- /**
315
- * HiddenHeaderFooterPMs — persistent off-screen ProseMirror EditorViews for
316
- * every distinct header/footer part in the loaded document.
317
- *
318
- * Mounts one hidden EditorView per distinct HF `rId` from
319
- * `Document.package.headers ∪ Document.package.footers`. The views never
320
- * become the visible HF renderer — the painter is the sole visible HF
321
- * renderer in both edit and non-edit modes. The persistent views own the
322
- * source of truth for HF content while the document is loaded; the
323
- * painter reads each rId's `view.state.doc` through
324
- * `convertHeaderFooterPmDocToContent`.
325
- *
326
- * Slot keying is by `rId`, NOT by `(hdrFtrType, kind)` — two sections that
327
- * share a header by referencing the same `rId` (ECMA-376 §17.10.1
328
- * sharing-by-reference) share one EditorView, so an edit on any painted
329
- * instance propagates to every painted instance in one layout pass.
330
- *
331
- * Unlike upstream's in-place `hf.content` mutation, folio's history-immutable
332
- * model surfaces every transaction through `onTransaction`; the parent
333
- * (`useHeaderFooterEditor` / `DocxEditor`) is the only place that pushes
334
- * Document changes through history.
335
- */
336
- function buildInitialState(hf, styles, theme, mgr) {
337
- const proseDocOptions = {};
338
- if (styles) proseDocOptions.styles = styles;
339
- if (theme !== void 0) proseDocOptions.theme = theme;
340
- const pmDoc = headerFooterToProseDoc(hf.content, proseDocOptions);
341
- const styleResolverPlugin = createDocumentStylesPlugin(styles);
342
- return ensureBaseDirectionInState(ensureParaIdsInState(EditorState.create({
343
- doc: pmDoc,
344
- schema: schema$1,
345
- plugins: [...mgr.getPlugins(), styleResolverPlugin]
346
- })));
347
- }
348
- function enumerateHfSlotsFromParts({ headers, footers }) {
349
- const out = [];
350
- if (headers) for (const rId of headers.keys()) out.push({
351
- rId,
352
- kind: "header"
353
- });
354
- if (footers) {
355
- for (const rId of footers.keys()) if (!headers || !headers.has(rId)) out.push({
356
- rId,
357
- kind: "footer"
358
- });
359
- }
360
- return out;
361
- }
311
+ /** Thin React binding for core's persistent header/footer editor manager. */
362
312
  const HOST_STYLES = {
363
313
  position: "fixed",
364
314
  left: -9999,
@@ -368,105 +318,41 @@ const HOST_STYLES = {
368
318
  pointerEvents: "none"
369
319
  };
370
320
  const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ document, styles, theme, onTransaction }, ref) {
371
- const onTransactionRef = useRef(onTransaction);
372
- onTransactionRef.current = onTransaction;
373
321
  const hostRef = useRef(null);
374
- const mountedRef = useRef(/* @__PURE__ */ new Map());
375
- const managersRef = useRef(/* @__PURE__ */ new Map());
376
322
  const documentRef = useRef(document);
323
+ const stylesRef = useRef(styles);
324
+ const themeRef = useRef(theme);
325
+ const onTransactionRef = useRef(onTransaction);
377
326
  documentRef.current = document;
378
- const resolveHf = useCallback((rId, kind) => {
379
- const pkg = documentRef.current?.package;
380
- if (!pkg) return null;
381
- return (kind === "header" ? pkg.headers : pkg.footers)?.get(rId) ?? null;
382
- }, []);
327
+ stylesRef.current = styles;
328
+ themeRef.current = theme;
329
+ onTransactionRef.current = onTransaction;
330
+ const managerRef = useRef(null);
331
+ managerRef.current ??= createHeaderFooterEditorManager({
332
+ getHost: () => hostRef.current,
333
+ getDocument: () => documentRef.current,
334
+ getStyles: () => stylesRef.current,
335
+ getTheme: () => themeRef.current,
336
+ onTransaction: ({ rId, kind, view, docChanged, selectionChanged }) => {
337
+ onTransactionRef.current?.(rId, kind, view, docChanged, selectionChanged);
338
+ }
339
+ });
383
340
  const headers = document?.package.headers;
384
341
  const footers = document?.package.footers;
385
- const slots = useMemo(() => enumerateHfSlotsFromParts({
386
- headers,
387
- footers
388
- }), [headers, footers]);
389
342
  useEffect(() => {
390
- if (!hostRef.current) return;
391
- const host = hostRef.current;
392
- const want = new Map(slots.map((s) => [s.rId, s]));
393
- const have = mountedRef.current;
394
- for (const [rId_0, mounted] of have) if (!want.has(rId_0)) {
395
- mounted.view.destroy();
396
- mounted.mountNode.remove();
397
- have.delete(rId_0);
398
- managersRef.current.delete(rId_0);
399
- }
400
- for (const slot of slots) {
401
- const hf = resolveHf(slot.rId, slot.kind);
402
- if (!hf) continue;
403
- const existing = have.get(slot.rId);
404
- if (existing) {
405
- if (existing.appliedHf === hf && existing.appliedContent === hf.content) continue;
406
- const mgr = managersRef.current.get(slot.rId);
407
- if (!mgr) continue;
408
- const newState = buildInitialState(hf, styles, theme, mgr);
409
- existing.view.updateState(newState);
410
- existing.appliedHf = hf;
411
- existing.appliedContent = hf.content;
412
- continue;
413
- }
414
- const mgr_0 = new ExtensionManager(createStarterKit());
415
- mgr_0.buildSchema();
416
- mgr_0.initializeRuntime();
417
- managersRef.current.set(slot.rId, mgr_0);
418
- const node = host.ownerDocument.createElement("div");
419
- node.dataset["hfRId"] = slot.rId;
420
- node.dataset["hfKind"] = slot.kind;
421
- host.append(node);
422
- const state = buildInitialState(hf, styles, theme, mgr_0);
423
- const slotRId = slot.rId;
424
- const slotKind = slot.kind;
425
- const view = new EditorView(node, {
426
- state,
427
- dispatchTransaction(tr) {
428
- const newState_0 = view.state.apply(tr);
429
- view.updateState(newState_0);
430
- onTransactionRef.current?.(slotRId, slotKind, view, tr.docChanged, tr.selectionSet);
431
- }
432
- });
433
- have.set(slot.rId, {
434
- rId: slot.rId,
435
- kind: slot.kind,
436
- view,
437
- mountNode: node,
438
- appliedHf: hf,
439
- appliedContent: hf.content
440
- });
441
- }
343
+ managerRef.current?.sync();
442
344
  }, [
443
- slots,
444
- resolveHf,
345
+ headers,
346
+ footers,
445
347
  styles,
446
348
  theme
447
349
  ]);
448
- useEffect(() => {
449
- const have_0 = mountedRef.current;
450
- const mgrs = managersRef.current;
451
- return () => {
452
- for (const { view: view_0, mountNode } of have_0.values()) {
453
- view_0.destroy();
454
- mountNode.remove();
455
- }
456
- have_0.clear();
457
- mgrs.clear();
458
- };
350
+ useEffect(() => () => {
351
+ managerRef.current?.destroy();
459
352
  }, []);
460
353
  useImperativeHandle(ref, () => ({
461
- getView(rId_1) {
462
- return mountedRef.current.get(rId_1)?.view ?? null;
463
- },
464
- listSlots() {
465
- return [...mountedRef.current.values()].map(({ rId: rId_2, kind: kind_0 }) => ({
466
- rId: rId_2,
467
- kind: kind_0
468
- }));
469
- }
354
+ getView: (rId) => managerRef.current?.getView(rId) ?? null,
355
+ listSlots: () => managerRef.current?.listSlots() ?? []
470
356
  }), []);
471
357
  return /* @__PURE__ */ jsx("div", {
472
358
  ref: hostRef,
@@ -923,17 +809,6 @@ async function loadHostFontFaces(fonts) {
923
809
  * so that ProseMirror's internal measurements stay valid.
924
810
  */
925
811
  const EMPTY_EXTERNAL_PLUGINS = [];
926
- let collaborationModulesPromise = null;
927
- const loadCollaborationModules = () => {
928
- collaborationModulesPromise ??= Promise.all([import("y-prosemirror"), import("yjs")]).then(([yProseMirror, yjs]) => ({
929
- yProseMirror,
930
- yjs
931
- })).catch((error) => {
932
- collaborationModulesPromise = null;
933
- throw error;
934
- });
935
- return collaborationModulesPromise;
936
- };
937
812
  /**
938
813
  * Hidden wrapper styles - visually hidden, focus-safe scroll isolation.
939
814
  *
@@ -6968,209 +6843,13 @@ function ContentControlDropdownItem(t0) {
6968
6843
  }
6969
6844
  //#endregion
6970
6845
  //#region src/components/dialogs/findReplaceUtils.ts
6971
- /**
6972
- * Find & Replace Utility Functions
6973
- *
6974
- * Pure utility functions for text search, pattern matching, and document search.
6975
- * Extracted from FindReplaceDialog.tsx.
6976
- */
6977
- /**
6978
- * Create default find options
6979
- */
6980
- function createDefaultFindOptions() {
6981
- return {
6982
- matchCase: false,
6983
- matchWholeWord: false,
6984
- useRegex: false
6985
- };
6986
- }
6987
- /**
6988
- * Find all matches of search text in content
6989
- */
6990
- function findAllMatches(content, searchText, options) {
6991
- if (!content || !searchText) return [];
6992
- const matches = [];
6993
- let searchFor = searchText;
6994
- if (!options.matchCase) searchFor = searchText.toLowerCase();
6995
- const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
6996
- let pattern;
6997
- if (options.matchWholeWord) pattern = `\\b${escapeRegex(searchFor)}\\b`;
6998
- else pattern = escapeRegex(searchFor);
6999
- const flags = options.matchCase ? "g" : "gi";
7000
- const regex = new RegExp(pattern, flags);
7001
- let match;
7002
- while ((match = regex.exec(content)) !== null) {
7003
- matches.push({
7004
- start: match.index,
7005
- end: match.index + match[0].length
7006
- });
7007
- if (match[0].length === 0) regex.lastIndex++;
7008
- }
7009
- return matches;
7010
- }
7011
- /**
7012
- * Get plain text from a run
7013
- */
7014
- function getRunText(run) {
7015
- let text = "";
7016
- for (const item of run.content) if (item.type === "text") text += item.text;
7017
- else if (item.type === "tab") text += " ";
7018
- else if (item.type === "break" && item.breakType === "textWrapping") text += "\n";
7019
- return text;
7020
- }
7021
- function getHyperlinkText(hyperlink) {
7022
- let text = "";
7023
- for (const child of hyperlink.children) if (child.type === "run") text += getRunText(child);
7024
- return text;
7025
- }
7026
- function getParagraphContentText(content) {
7027
- if (content.type === "run") return getRunText(content);
7028
- if (content.type === "hyperlink") return getHyperlinkText(content);
7029
- if (content.type === "inlineSdt") {
7030
- let text = "";
7031
- for (const child of content.content) text += getParagraphContentText(child);
7032
- return text;
7033
- }
7034
- if (content.type === "simpleField") {
7035
- let text = "";
7036
- for (const child of content.content) {
7037
- if (child.type === "run") {
7038
- text += getRunText(child);
7039
- continue;
7040
- }
7041
- text += getHyperlinkText(child);
7042
- }
7043
- return text;
7044
- }
7045
- if (content.type === "complexField") {
7046
- let text = "";
7047
- for (const run of content.fieldResult) text += getRunText(run);
7048
- return text;
7049
- }
7050
- return "";
7051
- }
7052
- /**
7053
- * Get plain text from a paragraph
7054
- */
7055
- function getParagraphPlainText(paragraph) {
7056
- let text = "";
7057
- for (const item of paragraph.content) text += getParagraphContentText(item);
7058
- return text;
7059
- }
7060
- /**
7061
- * Find all matches in a document
7062
- */
7063
- function findInDocument(document, searchText, options) {
7064
- if (!document || !searchText) return [];
7065
- const matches = [];
7066
- const body = document.package.document;
7067
- if (!isDocumentBody(body)) return matches;
7068
- forEachParagraph(body.content, (block, paragraphIndex) => {
7069
- const paragraphMatches = findInParagraph(block, searchText, options, paragraphIndex);
7070
- matches.push(...paragraphMatches);
7071
- });
7072
- return matches;
7073
- }
7074
- function forEachParagraph(blocks, visit) {
7075
- let paragraphIndex = 0;
7076
- const walkBlocks = (items) => {
7077
- for (const block of items) {
7078
- if (isParagraph(block)) {
7079
- visit(block, paragraphIndex);
7080
- paragraphIndex++;
7081
- continue;
7082
- }
7083
- if (isTable(block)) {
7084
- walkTable(block);
7085
- continue;
7086
- }
7087
- if (isBlockSdt(block)) walkBlocks(block.content);
7088
- }
7089
- };
7090
- const walkTable = (table) => {
7091
- for (const row of table.rows) {
7092
- if (!isTableRow(row)) continue;
7093
- for (const cell of row.cells) {
7094
- if (!isTableCell(cell)) continue;
7095
- walkBlocks(cell.content);
7096
- }
7097
- }
7098
- };
7099
- walkBlocks(blocks);
7100
- }
7101
- function isRecord(value) {
7102
- return typeof value === "object" && value !== null;
7103
- }
7104
- function isDocumentBody(value) {
7105
- return isRecord(value) && Array.isArray(value["content"]);
7106
- }
7107
- function isParagraph(value) {
7108
- return isRecord(value) && value["type"] === "paragraph" && Array.isArray(value["content"]);
7109
- }
7110
- function isTable(value) {
7111
- return isRecord(value) && value["type"] === "table" && Array.isArray(value["rows"]);
7112
- }
7113
- function isTableRow(value) {
7114
- return isRecord(value) && Array.isArray(value["cells"]);
7115
- }
7116
- function isTableCell(value) {
7117
- return isRecord(value) && Array.isArray(value["content"]);
7118
- }
7119
- function isBlockSdt(value) {
7120
- return isRecord(value) && value["type"] === "blockSdt" && Array.isArray(value["content"]);
7121
- }
7122
- /**
7123
- * Find matches in a single paragraph
7124
- */
7125
- function findInParagraph(paragraph, searchText, options, paragraphIndex) {
7126
- const matches = [];
7127
- const paragraphText = getParagraphPlainText(paragraph);
7128
- if (!paragraphText) return matches;
7129
- const textMatches = findAllMatches(paragraphText, searchText, options);
7130
- for (const match of textMatches) {
7131
- const contentInfo = findContentAtOffset(paragraph, match.start);
7132
- matches.push({
7133
- paragraphIndex,
7134
- contentIndex: contentInfo.contentIndex,
7135
- startOffset: match.start,
7136
- endOffset: match.end,
7137
- text: paragraphText.slice(match.start, match.end)
7138
- });
7139
- }
7140
- return matches;
7141
- }
7142
- /**
7143
- * Find the content (run) at a specific character offset in a paragraph
7144
- */
7145
- function findContentAtOffset(paragraph, offset) {
7146
- let currentOffset = 0;
7147
- let contentIndex = 0;
7148
- for (const item of paragraph.content) {
7149
- const itemLength = getParagraphContentText(item).length;
7150
- if (currentOffset + itemLength > offset) return {
7151
- contentIndex,
7152
- runIndex: contentIndex,
7153
- offsetInContent: offset - currentOffset
7154
- };
7155
- currentOffset += itemLength;
7156
- contentIndex++;
7157
- }
7158
- return {
7159
- contentIndex: Math.max(0, paragraph.content.length - 1),
7160
- runIndex: Math.max(0, paragraph.content.length - 1),
7161
- offsetInContent: 0
7162
- };
7163
- }
7164
- /**
7165
- * Scroll to a match in the document
7166
- */
7167
- function scrollToMatch(containerElement, match) {
6846
+ const scrollToMatch = (containerElement, match) => {
7168
6847
  if (!containerElement) return;
7169
6848
  (containerElement.querySelector(`[data-paragraph-index="${match.paragraphIndex}"]`) ?? containerElement.querySelector(`.layout-paragraph[data-block-id="block-${match.paragraphIndex + 1}"]`) ?? containerElement.querySelectorAll(".layout-paragraph").item(match.paragraphIndex)).scrollIntoView({
7170
6849
  behavior: prefersReducedMotionBehavior(),
7171
6850
  block: "center"
7172
6851
  });
7173
- }
6852
+ };
7174
6853
  //#endregion
7175
6854
  //#region src/components/dialogs/useFindReplace.ts
7176
6855
  /**
@@ -12164,7 +11843,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12164
11843
  * - Error boundary
12165
11844
  * - Loading states
12166
11845
  */
12167
- const CommentsSidebar = lazy(() => import("./CommentsSidebar-Bopn32H9.js").then((m) => ({ default: m.CommentsSidebar })));
11846
+ const CommentsSidebar = lazy(() => import("./CommentsSidebar-DOSa22AJ.js").then((m) => ({ default: m.CommentsSidebar })));
12168
11847
  const TextContextMenu = lazy(() => import("./TextContextMenu-Ci7-M4oU.js").then((m) => ({ default: m.TextContextMenu })));
12169
11848
  const loadAttemptSelectiveSave = async () => {
12170
11849
  const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-react",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
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",