@stll/folio-vue 0.9.0 → 0.11.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.
Files changed (40) hide show
  1. package/dist/{ListButtons-C1rU_Y1e.cjs → ListButtons-24sQYGSe.cjs} +2 -2
  2. package/dist/{ListButtons-DMnOM2pN.js → ListButtons-CAw3PKiv.js} +388 -384
  3. package/dist/SplitCellDialog-DJ-z75hr.cjs +15 -0
  4. package/dist/{WatermarkDialog-Cf9ISDvv.js → SplitCellDialog-DUzOQhr6.js} +990 -978
  5. package/dist/components/AutocompleteCaretOverlay.types.d.ts +18 -0
  6. package/dist/components/DocxEditor/pagedEditorRef.d.ts +14 -0
  7. package/dist/components/DocxEditor/types.d.ts +60 -0
  8. package/dist/composables/index.d.ts +1 -0
  9. package/dist/composables/useColorMode.d.ts +17 -4
  10. package/dist/composables/useCommentManagement.d.ts +8 -2
  11. package/dist/composables/useContextMenus.d.ts +3 -0
  12. package/dist/composables/useDocxEditor.d.ts +21 -0
  13. package/dist/composables/useDocxEditorRefApi.d.ts +18 -2
  14. package/dist/composables/useFontLifecycle.d.ts +22 -0
  15. package/dist/composables/useKeyboardShortcuts.d.ts +0 -1
  16. package/dist/composables/usePagesPointer.d.ts +5 -0
  17. package/dist/composables.cjs +2 -2
  18. package/dist/composables.js +75 -75
  19. package/dist/dialogs.cjs +1 -1
  20. package/dist/dialogs.js +2 -2
  21. package/dist/folio-vue.css +1 -1
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.d.ts +5 -1
  24. package/dist/index.js +1762 -1278
  25. package/dist/renderAsync.d.ts +4 -0
  26. package/dist/ui/folio-ui.d.ts +1 -1
  27. package/dist/ui.cjs +1 -1
  28. package/dist/ui.js +10 -10
  29. package/dist/useZoom-DBbzwfMG.cjs +1 -0
  30. package/dist/useZoom-DwDDS7hq.js +749 -0
  31. package/dist/utils/colorMode.d.ts +3 -4
  32. package/dist/utils/embeddedFonts.d.ts +20 -0
  33. package/dist/utils/fontFaces.d.ts +10 -0
  34. package/dist/utils/hostFonts.d.ts +1 -5
  35. package/package.json +2 -2
  36. package/dist/WatermarkDialog-ChJtT7Bs.cjs +0 -15
  37. package/dist/composables/useHostCallbacks.d.ts +0 -24
  38. package/dist/composables/useMenuActions.d.ts +0 -36
  39. package/dist/useZoom-BYEcnpS0.cjs +0 -1
  40. package/dist/useZoom-C0p0o54p.js +0 -656
@@ -0,0 +1,18 @@
1
+ export type AutocompleteCaretRect = {
2
+ /** Overlay-relative pixel x. */
3
+ x: number;
4
+ /** Overlay-relative pixel y (top of the cursor line). */
5
+ y: number;
6
+ /** Line height in pixels at the anchor. */
7
+ lineHeight: number;
8
+ /** Available width from the caret to the page's right content edge. */
9
+ maxWidth?: number | undefined;
10
+ };
11
+ export type AutocompleteCaretOverlayProps = {
12
+ /** Position of the autocomplete anchor, or null while idle. */
13
+ caret: AutocompleteCaretRect | null;
14
+ /** The full streamed ghost text so far. */
15
+ text: string;
16
+ /** Whether tokens are still arriving. */
17
+ isStreaming: boolean;
18
+ };
@@ -27,6 +27,10 @@ export type PagedEditorRef = {
27
27
  getState: () => EditorState | null;
28
28
  /** Get the ProseMirror EditorView. */
29
29
  getView: () => EditorView | null;
30
+ /** Get the currently active body, header/footer, or note-story view. */
31
+ getActiveView: () => EditorView | null;
32
+ /** Close the visible note story, if one is active. */
33
+ closeNoteStory: () => void;
30
34
  /**
31
35
  * Look up the persistent hidden HF EditorView by `rId`. Returns null when the
32
36
  * slot isn't mounted (no HF for that rId, or the hidden host hasn't mounted).
@@ -70,6 +74,16 @@ export type PagedEditorRef = {
70
74
  * Returns whether a matching paragraph exists in the ProseMirror document.
71
75
  */
72
76
  scrollToParaId: (paraId: string, options?: ScrollToParaIdOptions) => boolean;
77
+ /**
78
+ * Set (or clear, with `null`) the persistent passage highlight overlay. The
79
+ * range is projected onto the painted pages and painted with a translucent
80
+ * wash; it does not move the PM selection. Replaces any previous highlight.
81
+ * The overlay is cleared automatically on the next doc-changing transaction.
82
+ */
83
+ setPassageHighlight: (range: {
84
+ from: number;
85
+ to: number;
86
+ } | null) => void;
73
87
  /**
74
88
  * Resolve the page number (1-indexed) that contains the given PM position, or
75
89
  * null if no layout is available yet. Works for unrendered pages too via the
@@ -9,6 +9,7 @@ import { DocxCompatibility } from '@stll/folio-core/docx/compatibility';
9
9
  import { FolioSelectiveSaveFlags } from '@stll/folio-core/docx/selectiveSaveFlags';
10
10
  import { TripwireResult } from '@stll/folio-core/docx/selectiveSaveTripwire';
11
11
  import { SelectionState, TableContextInfo } from '@stll/folio-core/prosemirror';
12
+ import { FolioSuggestion, SuggestionAppliedAs } from '@stll/folio-core/prosemirror/commands/comments';
12
13
  import { AnonymizationMatch } from '@stll/folio-core/prosemirror/plugins/anonymizationDecorations';
13
14
  import { TemplateSlashMenuKeyAction, TemplateSlashMenuState } from '@stll/folio-core/prosemirror/plugins/templateSlashMenu';
14
15
  import { Document, ParagraphAlignment, SdtProperties, TabStop, Theme } from '@stll/folio-core/types/document';
@@ -307,6 +308,21 @@ export type DocxEditorApplyDocumentOperationsOptions = {
307
308
  batch: FolioDocumentOperationBatch;
308
309
  author?: string;
309
310
  };
311
+ /**
312
+ * Outcome of {@link DocxEditorRef.highlightPassage}:
313
+ * - `"passage"`: the text matched inside the block; scrolled there and painted
314
+ * the range highlight.
315
+ * - `"block"`: the text did not match but the block resolved; behaved like
316
+ * {@link DocxEditorRef.scrollToBlock} (scroll + whole-paragraph flash where a
317
+ * paraId exists).
318
+ * - `"none"`: the block did not resolve; no-op.
319
+ */
320
+ export type HighlightPassageResult = "passage" | "block" | "none";
321
+ export type HighlightPassageOptions = {
322
+ blockId: string;
323
+ text: string;
324
+ snapshot?: FolioAIEditSnapshot;
325
+ };
310
326
  /**
311
327
  * Imperative handle exposed by the DocxEditor component.
312
328
  */
@@ -411,8 +427,52 @@ export type DocxEditorRef = {
411
427
  * accept. Without `snapshot`, falls back to a fresh-from-live-doc snapshot.
412
428
  */
413
429
  scrollToBlock: (blockId: string, snapshot?: FolioAIEditSnapshot) => boolean;
430
+ /**
431
+ * Resolve a text passage inside a block, scroll to it, and paint a persistent
432
+ * translucent highlight over the matched range. Unlike {@link scrollToBlock},
433
+ * the passage outcome does not move the PM selection, so the highlight is not
434
+ * confused with a selection. Replaces any previous passage highlight. Returns
435
+ * which outcome happened; see {@link HighlightPassageResult}. The highlight is
436
+ * ephemeral view state: cleared on the next doc-changing transaction and by
437
+ * {@link clearPassageHighlight}.
438
+ */
439
+ highlightPassage: (options: HighlightPassageOptions) => HighlightPassageResult;
440
+ /** Clear the passage highlight painted by {@link highlightPassage}, if any. */
441
+ clearPassageHighlight: () => void;
414
442
  /** Resolve a stable block or text-range target and reveal it in the editor. */
415
443
  showInDocument: (target: FolioDocumentNavigationTarget, snapshot?: FolioAIEditSnapshot) => boolean;
444
+ /**
445
+ * The pending suggestions in the live document: AI-proposed tracked changes
446
+ * (provenance "suggested") grouped by suggestionId. Empty before the editor
447
+ * view mounts. Apply suggestions by passing `mode: "suggested"` to
448
+ * {@link applyDocumentOperations}; the result's `applied[].suggestionId`
449
+ * identifies each one.
450
+ */
451
+ getSuggestions: () => FolioSuggestion[];
452
+ /**
453
+ * Accept a suggestion: convert it into a normal tracked change authored by
454
+ * `options.author` (defaults to the editor's configured author). Whole
455
+ * inserted tables apply directly (`appliedAs: "direct"`); everything else
456
+ * becomes a tracked change (`"tracked"`). `accepted` is `false` (and
457
+ * `appliedAs` `null`) when the suggestion is not present.
458
+ */
459
+ acceptSuggestion: (suggestionId: string, options?: {
460
+ author?: string;
461
+ }) => {
462
+ accepted: boolean;
463
+ appliedAs: SuggestionAppliedAs | null;
464
+ };
465
+ /**
466
+ * Reject a suggestion: inverse-apply its marks (remove suggested-inserted
467
+ * text, drop suggested deletions, revert suggested formatting). Returns
468
+ * `false` when the suggestion is not present.
469
+ */
470
+ rejectSuggestion: (suggestionId: string) => boolean;
471
+ /**
472
+ * Scroll the editor viewport so the given suggestion comes into view, and
473
+ * select it. No-op when the suggestion is not present.
474
+ */
475
+ scrollToSuggestion: (suggestionId: string) => boolean;
416
476
  /**
417
477
  * The tracked changes (insertions and deletions) present in the live
418
478
  * document, read from the current ProseMirror `state.doc`. Empty array
@@ -15,6 +15,7 @@
15
15
  * @public
16
16
  */
17
17
  export * from './useClipboard';
18
+ export * from './useColorMode';
18
19
  export * from './useDocxEditor';
19
20
  export * from './useDragAutoScroll';
20
21
  export * from './useFindReplace';
@@ -1,8 +1,21 @@
1
- import { ComputedRef } from 'vue';
1
+ import { App, ComputedRef, MaybeRefOrGetter } from 'vue';
2
2
  import { ColorMode } from '../utils/colorMode';
3
+ /** Color mode used when a host does not provide one. */
4
+ export declare const defaultColorMode: ColorMode;
3
5
  /**
4
- * Resolve the effective dark flag from a reactive `colorMode`. `'system'`
6
+ * Provide a reactive color mode to descendant folio components.
7
+ *
8
+ * Call this from a parent component's setup function. For app-wide setup, use
9
+ * {@link colorModePlugin} instead.
10
+ */
11
+ export declare const provideColorMode: (colorMode?: MaybeRefOrGetter<ColorMode>) => void;
12
+ /** Vue plugin form: `app.use(colorModePlugin, "system")`. */
13
+ export declare const colorModePlugin: {
14
+ install(app: App, colorMode?: MaybeRefOrGetter<ColorMode>): void;
15
+ };
16
+ /**
17
+ * Resolve the effective dark flag from the inherited color mode. `'system'`
5
18
  * follows the OS via `subscribeSystemDark` (SSR-safe; re-syncs on entry).
6
- * Mirrors the React adapter's inline colorMode logic via the shared core helpers.
7
19
  */
8
- export declare function useColorMode(colorMode: () => ColorMode): ComputedRef<boolean>;
20
+ export declare function useColorMode(): ComputedRef<boolean>;
21
+ export type { ColorMode } from '../utils/colorMode';
@@ -26,8 +26,14 @@ export type UseCommentManagementReturn = {
26
26
  commentsDirty: ComputedRef<boolean>;
27
27
  /** Clear {@link commentsDirty} after a successful save. */
28
28
  clearCommentsDirty: () => void;
29
- /** Build a comment with a freshly-allocated, collision-seeded id. */
30
- createComment: (text: string, parentId?: number) => Comment;
29
+ /**
30
+ * Build a comment with a freshly-allocated, collision-seeded id.
31
+ * `authorOverride` lets a caller (AI-edit operations) mint a comment
32
+ * attributed to the resolved operation author instead of the editor's
33
+ * default `options.author()` — mirrors React's `applyAIEditOperations`
34
+ * closure, which creates each comment with the per-call `operationAuthor`.
35
+ */
36
+ createComment: (text: string, parentId?: number, authorOverride?: string) => Comment;
31
37
  /** Append a comment and emit the change. */
32
38
  pushComment: (comment: Comment) => void;
33
39
  /** Replace the whole list and emit the change (uncontrolled also stores it). */
@@ -48,6 +48,9 @@ export type UseContextMenusOptions = {
48
48
  from: number;
49
49
  to: number;
50
50
  }) => void;
51
+ onCopy?: () => void;
52
+ onCut?: () => void;
53
+ onPaste?: () => void;
51
54
  };
52
55
  export type UseContextMenusReturn = {
53
56
  contextMenu: Ref<TextContextMenuState>;
@@ -3,6 +3,7 @@ import { EditorState, Plugin } from 'prosemirror-state';
3
3
  import { EditorView } from 'prosemirror-view';
4
4
  import { FolioEditor } from '@stll/folio-core/controller/folioEditor';
5
5
  import { HeaderFooterPartKind } from '@stll/folio-core/controller/headerFooterEditorManager';
6
+ import { NoteStoryKey } from '@stll/folio-core/controller/noteEditorManager';
6
7
  import { HiddenProseMirrorCollaboration, HiddenProseMirrorRemoteSelection } from '@stll/folio-core/controller/hiddenEditorManager';
7
8
  import { FolioSelectiveSaveFlags } from '@stll/folio-core/docx/selectiveSaveFlags';
8
9
  import { TripwireResult } from '@stll/folio-core/docx/selectiveSaveTripwire';
@@ -18,12 +19,18 @@ export type UseDocxEditorOptions = {
18
19
  hiddenContainer: Ref<HTMLElement | null>;
19
20
  /** Optional separate host for persistent header/footer ProseMirror views. */
20
21
  hiddenHeaderFooterContainer?: Ref<HTMLElement | null>;
22
+ /** Visible host for the active footnote or endnote ProseMirror story. */
23
+ noteEditorContainer?: Ref<HTMLElement | null>;
21
24
  /** Container element the paginated pages are painted into. */
22
25
  pagesContainer: Ref<HTMLElement | null>;
23
26
  /** Whether the editor is read-only. Reactive. */
24
27
  readOnly?: MaybeRefOrGetter<boolean>;
25
28
  /** Gap between pages in pixels. */
26
29
  pageGap?: number;
30
+ /** Whether to paint each page's effective body-content boundary. Reactive. */
31
+ showMarginGuides?: MaybeRefOrGetter<boolean | undefined>;
32
+ /** CSS color used for margin guides. Reactive. */
33
+ marginGuideColor?: MaybeRefOrGetter<string | undefined>;
27
34
  /**
28
35
  * Stable identity of the loaded document (same across internal edits, distinct
29
36
  * per loaded file). Threaded to the hidden-editor manager's external-load
@@ -69,6 +76,12 @@ export type UseDocxEditorOptions = {
69
76
  onSelectionUpdate?: (state: EditorState) => void;
70
77
  /** Callback when the hidden EditorView is created or torn down. */
71
78
  onEditorViewReady?: (view: EditorView | null) => void;
79
+ /** Fires when the editor receives a copy event. */
80
+ onCopy?: () => void;
81
+ /** Fires when an editable editor receives a cut event. */
82
+ onCut?: () => void;
83
+ /** Fires when an editable editor receives a paste event. */
84
+ onPaste?: () => void;
72
85
  /** Callback when a read-only user action would mutate the document. */
73
86
  onReadOnlyEditAttempt?: () => void;
74
87
  /**
@@ -104,6 +117,8 @@ export type UseDocxEditorReturn = {
104
117
  remoteSelections: Ref<HiddenProseMirrorRemoteSelection[]>;
105
118
  /** Selection in the currently active persistent header/footer view. */
106
119
  headerFooterSelection: Ref<HeaderFooterSelectionState | null>;
120
+ /** The note story currently open in the visible note editor. */
121
+ activeNoteStory: Ref<NoteStoryKey | null>;
107
122
  /** True once the hidden view is mounted and a document is loaded. */
108
123
  isReady: Ref<boolean>;
109
124
  /**
@@ -139,6 +154,12 @@ export type UseDocxEditorReturn = {
139
154
  getHeaderFooterView: (rId: string) => EditorView | null;
140
155
  /** Synchronize persistent header/footer views after a document-model change. */
141
156
  syncHeaderFooterViews: () => void;
157
+ /** Open an existing footnote or endnote story. */
158
+ openNoteStory: (story: NoteStoryKey) => void;
159
+ /** Close the visible note-story editor. */
160
+ closeNoteStory: () => void;
161
+ /** Resolve the active note-story view. */
162
+ getActiveNoteView: () => EditorView | null;
142
163
  /** Access the extension command map for invoking marks / nodes / features. */
143
164
  getCommands: () => CommandMap;
144
165
  /** Focus the hidden ProseMirror view. */
@@ -42,19 +42,35 @@ export type UseDocxEditorRefApiOptions = {
42
42
  * Vue analogue of React's `PagedEditorRef.scrollToPosition`.
43
43
  */
44
44
  scrollVisiblePositionIntoView: (pmPos: number) => void;
45
+ /**
46
+ * Set (or clear, with `null`) the persistent passage-highlight range that the
47
+ * `PassageHighlightOverlay` projects and paints. Backs `highlightPassage` /
48
+ * `clearPassageHighlight`; the Vue analogue of React's
49
+ * `PagedEditorRef.setPassageHighlight`. The overlay is cleared automatically
50
+ * on the next doc-changing transaction (owned by DocxEditor.vue).
51
+ */
52
+ setPassageHighlight: (range: {
53
+ from: number;
54
+ to: number;
55
+ } | null) => void;
45
56
  /** Editor author, used as the default operation author for AI edits. */
46
57
  author: () => string;
47
58
  /**
48
59
  * Mint a comment for an AI-edit operation that carries comment text, append
49
60
  * it to the thread list, and return its id (mirrors React's `createCommentId`
50
- * closure over the comment manager). Wired from useCommentManagement.
61
+ * closure over the comment manager). Wired from useCommentManagement. The
62
+ * optional `author` lets each call site attribute the comment to the
63
+ * resolved per-call `operationAuthor` rather than always the editor's
64
+ * default author.
51
65
  */
52
- createAIEditComment: (text: string) => number;
66
+ createAIEditComment: (text: string, author?: string) => number;
53
67
  /** Read and replace the current comment array for transactional undo. */
54
68
  getComments: () => Comment[];
55
69
  setComments: (comments: Comment[]) => void;
56
70
  focus: () => void;
57
71
  getDocument: () => Document | null;
72
+ getActiveView: () => EditorView | null;
73
+ closeNoteStory: () => void;
58
74
  getHeaderFooterView: (rId: string) => EditorView | null;
59
75
  setZoom: (zoom: number) => void;
60
76
  /** useDocxEditor.save returns a Blob; the ref surface exposes an ArrayBuffer. */
@@ -0,0 +1,22 @@
1
+ import { Ref } from 'vue';
2
+ import { FontDefinition } from '../components/DocxEditor/types';
3
+ import { LoadedEmbeddedFonts } from '../utils/embeddedFonts';
4
+ export type UseFontLifecycleOptions = {
5
+ isReady: Ref<boolean>;
6
+ getDocument: () => {
7
+ originalBuffer?: ArrayBuffer | null;
8
+ } | null;
9
+ fonts: () => ReadonlyArray<FontDefinition> | undefined;
10
+ remeasure: () => void;
11
+ };
12
+ export type FontLifecycleDependencies = {
13
+ loadEmbedded: (buffer: ArrayBuffer) => Promise<LoadedEmbeddedFonts>;
14
+ loadHost: (fonts: ReadonlyArray<FontDefinition> | undefined) => Promise<FontFace[]>;
15
+ remove: (faces: readonly FontFace[]) => void;
16
+ };
17
+ /**
18
+ * Register document-embedded and host-provided fonts for the lifetime of their
19
+ * sources. Async results from a stale document or prop value are immediately
20
+ * removed, preventing one editor load from leaking faces into the next.
21
+ */
22
+ export declare function useFontLifecycle(options: UseFontLifecycleOptions, dependencies?: FontLifecycleDependencies): void;
@@ -1,6 +1,5 @@
1
1
  import { Ref } from 'vue';
2
2
  export type UseKeyboardShortcutsOptions = {
3
- showKeyboardShortcuts: Ref<boolean>;
4
3
  showFindReplace: Ref<boolean>;
5
4
  showHyperlink: Ref<boolean>;
6
5
  /** From useZoom — handles Ctrl+= / Ctrl+- / Ctrl+0. */
@@ -2,6 +2,7 @@ import { Ref, ShallowRef } from 'vue';
2
2
  import { Command } from 'prosemirror-state';
3
3
  import { EditorView } from 'prosemirror-view';
4
4
  import { Document } from '@stll/folio-core/types/document';
5
+ import { NoteStoryKey } from '@stll/folio-core/controller/noteEditorManager';
5
6
  import { Layout } from '@stll/folio-core/layout-engine';
6
7
  import { ImageSelectionInfo } from '../components/imageSelectionTypes';
7
8
  import { HyperlinkPopupData } from '../components/ui/hyperlinkPopupTypes';
@@ -61,6 +62,10 @@ export type UsePagesPointerOptions = {
61
62
  * callers fall back to in-place mutation + `syncHfPMs()`.
62
63
  */
63
64
  setDocument: (doc: Document) => void;
65
+ /** Open a footnote or endnote story from a painted reference/body. */
66
+ openNoteStory: (story: NoteStoryKey) => void;
67
+ closeNoteStory: () => void;
68
+ getActiveNoteView: () => EditorView | null;
64
69
  };
65
70
  export type UsePagesPointerReturn = {
66
71
  tableInsertButton: Ref<TableInsertButton | null>;
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useFindReplace-ZCrdvwEk.cjs"),t=require("./useZoom-BYEcnpS0.cjs");let n=require("vue"),r=require("prosemirror-history"),i=require("@stll/folio-core/utils/clipboard"),a=require("@stll/folio-core/managers/ClipboardManager"),o=require("@stll/folio-core/managers/TableSelectionManager"),s=require("@stll/folio-core/prosemirror/utils/visualLineNavigation"),c=require("@stll/folio-core/prosemirror/utils/extractTrackedChanges");function l(e={}){let{onCopy:t,onCut:r,onPaste:a,cleanWordFormatting:o=!0,editable:s=!0,onError:c}=e,l=(0,n.ref)(!1),u=(0,n.ref)(null),d=c?{onError:c}:{};async function f(e){if(l.value)return!1;l.value=!0;try{let n=await(0,i.copyRuns)(e.runs,d);return n&&t?.(e),n}finally{l.value=!1}}async function p(e){if(l.value||!s)return!1;l.value=!0;try{let t=await(0,i.copyRuns)(e.runs,d);return t&&r?.(e),t}finally{l.value=!1}}async function m(e=!1){if(l.value||!s)return null;l.value=!0;try{if(navigator.clipboard&&navigator.clipboard.read){let t=await navigator.clipboard.read(),n=``,r=``;for(let e of t)e.types.includes(`text/html`)&&(n=await(await e.getType(`text/html`)).text()),e.types.includes(`text/plain`)&&(r=await(await e.getType(`text/plain`)).text());e&&(n=``);let s=(0,i.parseClipboardHtml)(n,r,o);return u.value=s,a?.(s,e),s}return null}catch(e){return c?.(e instanceof Error?e:Error(String(e))),null}finally{l.value=!1}}return{copy:f,cut:p,paste:m,isProcessing:l,lastPastedContent:u}}function u({isOpen:e,onClose:t,align:r=`left`}){let i=(0,n.ref)(null),a=(0,n.ref)(null),o=(0,n.ref)({position:`fixed`,top:`0px`,left:`0px`,zIndex:1e4});function s(e,t){o.value={position:`fixed`,top:e+`px`,left:t+`px`,zIndex:1e4}}function c(e){let n=e.target;n instanceof Node&&i.value&&!i.value.contains(n)&&a.value&&!a.value.contains(n)&&t()}function l(e){e.key===`Escape`&&t()}function u(e){let n=e.target;n instanceof Node&&a.value&&a.value.contains(n)||t()}function d(){document.addEventListener(`mousedown`,c),document.addEventListener(`keydown`,l),window.addEventListener(`scroll`,u,!0)}function f(){document.removeEventListener(`mousedown`,c),document.removeEventListener(`keydown`,l),window.removeEventListener(`scroll`,u,!0)}(0,n.watch)(e,e=>{if(!e){f();return}let t=i.value;if(!t)return;let n=t.getBoundingClientRect();r===`right`?requestAnimationFrame(()=>{let e=a.value;if(e){let t=e.getBoundingClientRect();s(n.bottom+4,n.right-t.width)}else s(n.bottom+4,n.left)}):s(n.bottom+4,n.left),d()}),(0,n.onScopeDispose)(f);function p(e){e.preventDefault(),e.stopPropagation()}return{containerRef:i,dropdownRef:a,dropdownStyle:o,handleMouseDown:p}}function d(e,t){let i=(0,n.computed)(()=>{t.value;let n=e.value;return n?(0,r.undoDepth)(n.state)>0:!1}),a=(0,n.computed)(()=>{t.value;let n=e.value;return n?(0,r.redoDepth)(n.state)>0:!1});function o(){let t=e.value;return t?(0,r.undo)(t.state,t.dispatch):!1}function s(){let t=e.value;return t?(0,r.redo)(t.state,t.dispatch):!1}return{canUndo:i,canRedo:a,undo:o,redo:s}}var f={backgroundColor:`rgba(26, 115, 232, 0.3)`,borderRadius:0,zIndex:0,opacity:1,mixBlendMode:`multiply`};function p(e){let t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return[];let n=t.getRangeAt(0);if(e&&!e.contains(n.commonAncestorContainer))return[];let r=0,i=0;if(e){let t=e.getBoundingClientRect();r=t.left+e.scrollLeft,i=t.top+e.scrollTop}let a=[];for(let e of n.getClientRects())e.width===0&&e.height===0||a.push({left:e.left-r,top:e.top-i,width:e.width,height:e.height});return a}function m(e,t=2){if(e.length<=1)return e;let n=[...e].sort((e,n)=>Math.abs(e.top-n.top)<t?e.left-n.left:e.top-n.top),r=n[0];if(!r)return e;let i=[],a={...r};for(let e=1;e<n.length;e++){let r=n[e];if(!r)continue;let o=Math.abs(r.top-a.top)<t,s=r.left<=a.left+a.width+t;if(o&&s){let e=Math.max(a.left+a.width,r.left+r.width);a.width=e-a.left,a.height=Math.max(a.height,r.height)}else i.push(a),a={...r}}return i.push(a),i}function h(e){return m(p(e))}function g(){let e=window.getSelection();return e!==null&&!e.isCollapsed&&e.rangeCount>0}function _(e){let t=window.getSelection();return!t||t.rangeCount===0?!1:e.contains(t.getRangeAt(0).commonAncestorContainer)}var v=`docx-selection-styles`,y=null;function b(){y&&=(y.remove(),null),document.getElementById(v)?.remove()}function x(e=f){b();let t=`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useFindReplace-ZCrdvwEk.cjs"),t=require("./useZoom-DBbzwfMG.cjs");let n=require("vue"),r=require("prosemirror-history"),i=require("@stll/folio-core/utils/clipboard"),a=require("@stll/folio-core/managers/ClipboardManager"),o=require("@stll/folio-core/managers/TableSelectionManager"),s=require("@stll/folio-core/prosemirror/utils/visualLineNavigation"),c=require("@stll/folio-core/prosemirror/utils/extractTrackedChanges");function l(e={}){let{onCopy:t,onCut:r,onPaste:a,cleanWordFormatting:o=!0,editable:s=!0,onError:c}=e,l=(0,n.ref)(!1),u=(0,n.ref)(null),d=c?{onError:c}:{};async function f(e){if(l.value)return!1;l.value=!0;try{let n=await(0,i.copyRuns)(e.runs,d);return n&&t?.(e),n}finally{l.value=!1}}async function p(e){if(l.value||!s)return!1;l.value=!0;try{let t=await(0,i.copyRuns)(e.runs,d);return t&&r?.(e),t}finally{l.value=!1}}async function m(e=!1){if(l.value||!s)return null;l.value=!0;try{if(navigator.clipboard&&navigator.clipboard.read){let t=await navigator.clipboard.read(),n=``,r=``;for(let e of t)e.types.includes(`text/html`)&&(n=await(await e.getType(`text/html`)).text()),e.types.includes(`text/plain`)&&(r=await(await e.getType(`text/plain`)).text());e&&(n=``);let s=(0,i.parseClipboardHtml)(n,r,o);return u.value=s,a?.(s,e),s}return null}catch(e){return c?.(e instanceof Error?e:Error(String(e))),null}finally{l.value=!1}}return{copy:f,cut:p,paste:m,isProcessing:l,lastPastedContent:u}}function u({isOpen:e,onClose:t,align:r=`left`}){let i=(0,n.ref)(null),a=(0,n.ref)(null),o=(0,n.ref)({position:`fixed`,top:`0px`,left:`0px`,zIndex:1e4});function s(e,t){o.value={position:`fixed`,top:e+`px`,left:t+`px`,zIndex:1e4}}function c(e){let n=e.target;n instanceof Node&&i.value&&!i.value.contains(n)&&a.value&&!a.value.contains(n)&&t()}function l(e){e.key===`Escape`&&t()}function u(e){let n=e.target;n instanceof Node&&a.value&&a.value.contains(n)||t()}function d(){document.addEventListener(`mousedown`,c),document.addEventListener(`keydown`,l),window.addEventListener(`scroll`,u,!0)}function f(){document.removeEventListener(`mousedown`,c),document.removeEventListener(`keydown`,l),window.removeEventListener(`scroll`,u,!0)}(0,n.watch)(e,e=>{if(!e){f();return}let t=i.value;if(!t)return;let n=t.getBoundingClientRect();r===`right`?requestAnimationFrame(()=>{let e=a.value;if(e){let t=e.getBoundingClientRect();s(n.bottom+4,n.right-t.width)}else s(n.bottom+4,n.left)}):s(n.bottom+4,n.left),d()}),(0,n.onScopeDispose)(f);function p(e){e.preventDefault(),e.stopPropagation()}return{containerRef:i,dropdownRef:a,dropdownStyle:o,handleMouseDown:p}}function d(e,t){let i=(0,n.computed)(()=>{t.value;let n=e.value;return n?(0,r.undoDepth)(n.state)>0:!1}),a=(0,n.computed)(()=>{t.value;let n=e.value;return n?(0,r.redoDepth)(n.state)>0:!1});function o(){let t=e.value;return t?(0,r.undo)(t.state,t.dispatch):!1}function s(){let t=e.value;return t?(0,r.redo)(t.state,t.dispatch):!1}return{canUndo:i,canRedo:a,undo:o,redo:s}}var f={backgroundColor:`rgba(26, 115, 232, 0.3)`,borderRadius:0,zIndex:0,opacity:1,mixBlendMode:`multiply`};function p(e){let t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return[];let n=t.getRangeAt(0);if(e&&!e.contains(n.commonAncestorContainer))return[];let r=0,i=0;if(e){let t=e.getBoundingClientRect();r=t.left+e.scrollLeft,i=t.top+e.scrollTop}let a=[];for(let e of n.getClientRects())e.width===0&&e.height===0||a.push({left:e.left-r,top:e.top-i,width:e.width,height:e.height});return a}function m(e,t=2){if(e.length<=1)return e;let n=[...e].sort((e,n)=>Math.abs(e.top-n.top)<t?e.left-n.left:e.top-n.top),r=n[0];if(!r)return e;let i=[],a={...r};for(let e=1;e<n.length;e++){let r=n[e];if(!r)continue;let o=Math.abs(r.top-a.top)<t,s=r.left<=a.left+a.width+t;if(o&&s){let e=Math.max(a.left+a.width,r.left+r.width);a.width=e-a.left,a.height=Math.max(a.height,r.height)}else i.push(a),a={...r}}return i.push(a),i}function h(e){return m(p(e))}function g(){let e=window.getSelection();return e!==null&&!e.isCollapsed&&e.rangeCount>0}function _(e){let t=window.getSelection();return!t||t.rangeCount===0?!1:e.contains(t.getRangeAt(0).commonAncestorContainer)}var v=`docx-selection-styles`,y=null;function b(){y&&=(y.remove(),null),document.getElementById(v)?.remove()}function x(e=f){b();let t=`
2
2
  /* DOCX Editor Selection Highlighting */
3
3
 
4
4
  .docx-editor [contenteditable="true"]::selection,
@@ -58,4 +58,4 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
58
58
  background-color: rgba(156, 39, 176, 0.2);
59
59
  border-bottom: 2px dashed rgba(156, 39, 176, 0.6);
60
60
  }
61
- `;y=document.createElement(`style`),y.id=v,y.textContent=t,document.head.appendChild(y)}function S(){return y!==null||document.getElementById(v)!==null}function C(){return window.getSelection()?.toString()??``}function w(e){let{containerRef:t,enabled:r=!0,config:i=f,useOverlay:a=!1,debounceMs:o=16,onSelectionChange:s}=e,c=(0,n.ref)(!1),l=(0,n.ref)(``),u=(0,n.ref)([]),d=(0,n.ref)(!1),p=null,m=0;function v(){let e=t.value,n=g(),r=C(),i=e?_(e):!1;c.value=n,l.value=r,d.value=i,u.value=a&&i&&e?h(e):[],s?.(n&&i,r)}function y(){v()}function b(){let e=performance.now();if(e-m<o){p&&clearTimeout(p),p=setTimeout(()=>{m=performance.now(),v(),p=null},o);return}m=e,v()}function w(e){let t={position:`absolute`,left:`${e.left}px`,top:`${e.top}px`,width:`${e.width}px`,height:`${e.height}px`,backgroundColor:i.backgroundColor,zIndex:i.zIndex??0,pointerEvents:`none`};return i.borderRadius&&(t.borderRadius=`${i.borderRadius}px`),i.borderColor&&(t.border=`1px solid ${i.borderColor}`),t}return(0,n.onMounted)(()=>{r&&(S()||x(i),document.addEventListener(`selectionchange`,b))}),(0,n.onBeforeUnmount)(()=>{document.removeEventListener(`selectionchange`,b),p&&clearTimeout(p)}),(0,n.watch)(t,()=>v()),{hasSelection:(0,n.computed)(()=>c.value),selectedText:(0,n.computed)(()=>l.value),highlightRects:(0,n.computed)(()=>u.value),isSelectionInContainer:(0,n.computed)(()=>d.value),refresh:y,getOverlayStyle:w}}function T(){let e=new o.TableSelectionManager,t=(0,n.ref)(null),r=()=>{let n=e.getSnapshot();t.value=n.tableIndex!==null&&n.rowIndex!==null&&n.columnIndex!==null?{tableIndex:n.tableIndex,rowIndex:n.rowIndex,columnIndex:n.columnIndex}:null},i=e.subscribe(r);r(),(0,n.onScopeDispose)(i);function a(t,n,r){e.selectCellCoordinates({tableIndex:t,rowIndex:n,columnIndex:r})}function s(t,n){let r=(0,o.findTableFromClick)(t,n);if(!r){e.clearSelection();return}e.selectCellCoordinates(r)}function c(){e.clearSelection()}function l(t,n,r){return e.isCellSelected(t,n,r)}return{selectedCell:t,handleCellClick:a,handleClickTarget:s,clearSelection:c,isCellSelected:l}}function E(e){let t=(0,s.createVisualLineState)();function n(t){let n=e.value;return n?(0,s.getCaretClientX)(n,t):null}function r(t){let n=e.value;return n?(0,s.findLineElementAtPosition)(n,t):null}function i(e,t){return(0,s.findPositionOnLineAtClientX)(e,t)}function a(n,r){return(0,s.handleVisualLineKeyDown)(t,n,r,e.value)}return{state:t,getCaretClientX:n,findLineElementAtPosition:r,findPositionOnLineAtClientX:i,handlePMKeyDown:a}}exports.createSelectionFromDOM=a.createSelectionFromDOM,exports.extractTrackedChanges=c.extractTrackedChanges,exports.getSelectionRuns=a.getSelectionRuns,exports.runsToClipboardContent=i.runsToClipboardContent,exports.useClipboard=l,exports.useDocxEditor=t.a,exports.useDragAutoScroll=t.i,exports.useFindReplace=e.t,exports.useFixedDropdown=u,exports.useHistory=d,exports.useSelectionHighlight=w,exports.useTableResize=t.r,exports.useTableSelection=T,exports.useTrackedChanges=t.n,exports.useVisualLineNavigation=E,exports.useWheelZoom=t.t,exports.useZoom=t.t;
61
+ `;y=document.createElement(`style`),y.id=v,y.textContent=t,document.head.appendChild(y)}function S(){return y!==null||document.getElementById(v)!==null}function C(){return window.getSelection()?.toString()??``}function w(e){let{containerRef:t,enabled:r=!0,config:i=f,useOverlay:a=!1,debounceMs:o=16,onSelectionChange:s}=e,c=(0,n.ref)(!1),l=(0,n.ref)(``),u=(0,n.ref)([]),d=(0,n.ref)(!1),p=null,m=0;function v(){let e=t.value,n=g(),r=C(),i=e?_(e):!1;c.value=n,l.value=r,d.value=i,u.value=a&&i&&e?h(e):[],s?.(n&&i,r)}function y(){v()}function b(){let e=performance.now();if(e-m<o){p&&clearTimeout(p),p=setTimeout(()=>{m=performance.now(),v(),p=null},o);return}m=e,v()}function w(e){let t={position:`absolute`,left:`${e.left}px`,top:`${e.top}px`,width:`${e.width}px`,height:`${e.height}px`,backgroundColor:i.backgroundColor,zIndex:i.zIndex??0,pointerEvents:`none`};return i.borderRadius&&(t.borderRadius=`${i.borderRadius}px`),i.borderColor&&(t.border=`1px solid ${i.borderColor}`),t}return(0,n.onMounted)(()=>{r&&(S()||x(i),document.addEventListener(`selectionchange`,b))}),(0,n.onBeforeUnmount)(()=>{document.removeEventListener(`selectionchange`,b),p&&clearTimeout(p)}),(0,n.watch)(t,()=>v()),{hasSelection:(0,n.computed)(()=>c.value),selectedText:(0,n.computed)(()=>l.value),highlightRects:(0,n.computed)(()=>u.value),isSelectionInContainer:(0,n.computed)(()=>d.value),refresh:y,getOverlayStyle:w}}function T(){let e=new o.TableSelectionManager,t=(0,n.ref)(null),r=()=>{let n=e.getSnapshot();t.value=n.tableIndex!==null&&n.rowIndex!==null&&n.columnIndex!==null?{tableIndex:n.tableIndex,rowIndex:n.rowIndex,columnIndex:n.columnIndex}:null},i=e.subscribe(r);r(),(0,n.onScopeDispose)(i);function a(t,n,r){e.selectCellCoordinates({tableIndex:t,rowIndex:n,columnIndex:r})}function s(t,n){let r=(0,o.findTableFromClick)(t,n);if(!r){e.clearSelection();return}e.selectCellCoordinates(r)}function c(){e.clearSelection()}function l(t,n,r){return e.isCellSelected(t,n,r)}return{selectedCell:t,handleCellClick:a,handleClickTarget:s,clearSelection:c,isCellSelected:l}}function E(e){let t=(0,s.createVisualLineState)();function n(t){let n=e.value;return n?(0,s.getCaretClientX)(n,t):null}function r(t){let n=e.value;return n?(0,s.findLineElementAtPosition)(n,t):null}function i(e,t){return(0,s.findPositionOnLineAtClientX)(e,t)}function a(n,r){return(0,s.handleVisualLineKeyDown)(t,n,r,e.value)}return{state:t,getCaretClientX:n,findLineElementAtPosition:r,findPositionOnLineAtClientX:i,handlePMKeyDown:a}}exports.colorModePlugin=t.o,exports.createSelectionFromDOM=a.createSelectionFromDOM,exports.defaultColorMode=t.s,exports.extractTrackedChanges=c.extractTrackedChanges,exports.getSelectionRuns=a.getSelectionRuns,exports.provideColorMode=t.c,exports.runsToClipboardContent=i.runsToClipboardContent,exports.useClipboard=l,exports.useColorMode=t.l,exports.useDocxEditor=t.a,exports.useDragAutoScroll=t.i,exports.useFindReplace=e.t,exports.useFixedDropdown=u,exports.useHistory=d,exports.useSelectionHighlight=w,exports.useTableResize=t.r,exports.useTableSelection=T,exports.useTrackedChanges=t.n,exports.useVisualLineNavigation=E,exports.useWheelZoom=t.t,exports.useZoom=t.t;