@stll/folio-vue 0.8.1 → 0.10.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/ListButtons-BcB7qvzQ.cjs +4 -0
- package/dist/{ListButtons-DXqMvba3.js → ListButtons-rpVlLZJ8.js} +689 -710
- package/dist/SplitCellDialog-B_TOoiMw.cjs +15 -0
- package/dist/{WatermarkDialog-r4wmldt4.js → SplitCellDialog-DRQuZsA3.js} +1537 -1604
- package/dist/components/AutocompleteCaretOverlay.types.d.ts +18 -0
- package/dist/components/DocxEditor/pagedEditorRef.d.ts +16 -3
- package/dist/components/DocxEditor/types.d.ts +27 -0
- package/dist/composables/index.d.ts +2 -2
- package/dist/composables/useColorMode.d.ts +17 -4
- package/dist/composables/useContextMenus.d.ts +3 -0
- package/dist/composables/useDocxEditor.d.ts +47 -0
- package/dist/composables/useDocxEditorRefApi.d.ts +14 -0
- package/dist/composables/useFindReplace.d.ts +24 -22
- package/dist/composables/useFontLifecycle.d.ts +21 -0
- package/dist/composables/useKeyboardShortcuts.d.ts +0 -1
- package/dist/composables/usePagesPointer.d.ts +14 -13
- package/dist/composables/useRemoteSelectionSync.d.ts +10 -0
- package/dist/composables/useSelectionSync.d.ts +17 -30
- package/dist/composables.cjs +2 -2
- package/dist/composables.js +93 -81
- package/dist/dialogs.cjs +1 -1
- package/dist/dialogs.js +2 -2
- package/dist/folio-vue.css +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2249 -1401
- package/dist/renderAsync.d.ts +4 -0
- package/dist/styles/zIndex.d.ts +1 -0
- package/dist/styles.cjs +1 -1
- package/dist/styles.js +1 -1
- package/dist/ui/folio-ui.d.ts +1 -1
- package/dist/ui.cjs +1 -1
- package/dist/ui.js +10 -10
- package/dist/useFindReplace-CL8Rbc3y.js +59 -0
- package/dist/useFindReplace-ZCrdvwEk.cjs +1 -0
- package/dist/useZoom-DBbzwfMG.cjs +1 -0
- package/dist/useZoom-DwDDS7hq.js +749 -0
- package/dist/utils/colorMode.d.ts +3 -4
- package/dist/utils/embeddedFonts.d.ts +7 -0
- package/dist/utils/fontFaces.d.ts +10 -0
- package/dist/utils/hostFonts.d.ts +1 -5
- package/dist/zIndex-CYoLNG_N.cjs +1 -0
- package/dist/{zIndex-BY0qa8Au.js → zIndex-Ei9BbHSW.js} +1 -0
- package/package.json +1 -1
- package/dist/ListButtons-BvsV1yti.cjs +0 -4
- package/dist/WatermarkDialog-DHfk8jrg.cjs +0 -15
- package/dist/components/sidebar/resolveItemPositions.d.ts +0 -22
- package/dist/composables/useHostCallbacks.d.ts +0 -24
- package/dist/composables/useMenuActions.d.ts +0 -36
- package/dist/useZoom-C7jhL696.cjs +0 -1
- package/dist/useZoom-zJvuJlUd.js +0 -615
- package/dist/zIndex-dFsQbASx.cjs +0 -1
|
@@ -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
|
+
};
|
|
@@ -13,9 +13,8 @@ import { Document } from '@stll/folio-core/types/document';
|
|
|
13
13
|
* `useDocxEditorRefApi.ts` synthesizes one from the primitives it already
|
|
14
14
|
* holds (the headless `FolioEditor` controller, `editorView`, `layout`, and
|
|
15
15
|
* the pages-scroll helpers) rather than tearing a component ref off a
|
|
16
|
-
* component that does not exist. `getHfView`
|
|
17
|
-
*
|
|
18
|
-
* Vue) and stays a documented no-op; see its call site for the exact reason.
|
|
16
|
+
* component that does not exist. `getHfView` delegates to the shared
|
|
17
|
+
* persistent header/footer editor manager.
|
|
19
18
|
*
|
|
20
19
|
* TODO(vue): re-home to the Vue PagedEditor component when it lands.
|
|
21
20
|
*/
|
|
@@ -28,6 +27,10 @@ export type PagedEditorRef = {
|
|
|
28
27
|
getState: () => EditorState | null;
|
|
29
28
|
/** Get the ProseMirror EditorView. */
|
|
30
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;
|
|
31
34
|
/**
|
|
32
35
|
* Look up the persistent hidden HF EditorView by `rId`. Returns null when the
|
|
33
36
|
* slot isn't mounted (no HF for that rId, or the hidden host hasn't mounted).
|
|
@@ -71,6 +74,16 @@ export type PagedEditorRef = {
|
|
|
71
74
|
* Returns whether a matching paragraph exists in the ProseMirror document.
|
|
72
75
|
*/
|
|
73
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;
|
|
74
87
|
/**
|
|
75
88
|
* Resolve the page number (1-indexed) that contains the given PM position, or
|
|
76
89
|
* null if no layout is available yet. Works for unrendered pages too via the
|
|
@@ -307,6 +307,21 @@ export type DocxEditorApplyDocumentOperationsOptions = {
|
|
|
307
307
|
batch: FolioDocumentOperationBatch;
|
|
308
308
|
author?: string;
|
|
309
309
|
};
|
|
310
|
+
/**
|
|
311
|
+
* Outcome of {@link DocxEditorRef.highlightPassage}:
|
|
312
|
+
* - `"passage"`: the text matched inside the block; scrolled there and painted
|
|
313
|
+
* the range highlight.
|
|
314
|
+
* - `"block"`: the text did not match but the block resolved; behaved like
|
|
315
|
+
* {@link DocxEditorRef.scrollToBlock} (scroll + whole-paragraph flash where a
|
|
316
|
+
* paraId exists).
|
|
317
|
+
* - `"none"`: the block did not resolve; no-op.
|
|
318
|
+
*/
|
|
319
|
+
export type HighlightPassageResult = "passage" | "block" | "none";
|
|
320
|
+
export type HighlightPassageOptions = {
|
|
321
|
+
blockId: string;
|
|
322
|
+
text: string;
|
|
323
|
+
snapshot?: FolioAIEditSnapshot;
|
|
324
|
+
};
|
|
310
325
|
/**
|
|
311
326
|
* Imperative handle exposed by the DocxEditor component.
|
|
312
327
|
*/
|
|
@@ -411,6 +426,18 @@ export type DocxEditorRef = {
|
|
|
411
426
|
* accept. Without `snapshot`, falls back to a fresh-from-live-doc snapshot.
|
|
412
427
|
*/
|
|
413
428
|
scrollToBlock: (blockId: string, snapshot?: FolioAIEditSnapshot) => boolean;
|
|
429
|
+
/**
|
|
430
|
+
* Resolve a text passage inside a block, scroll to it, and paint a persistent
|
|
431
|
+
* translucent highlight over the matched range. Unlike {@link scrollToBlock},
|
|
432
|
+
* the passage outcome does not move the PM selection, so the highlight is not
|
|
433
|
+
* confused with a selection. Replaces any previous passage highlight. Returns
|
|
434
|
+
* which outcome happened; see {@link HighlightPassageResult}. The highlight is
|
|
435
|
+
* ephemeral view state: cleared on the next doc-changing transaction and by
|
|
436
|
+
* {@link clearPassageHighlight}.
|
|
437
|
+
*/
|
|
438
|
+
highlightPassage: (options: HighlightPassageOptions) => HighlightPassageResult;
|
|
439
|
+
/** Clear the passage highlight painted by {@link highlightPassage}, if any. */
|
|
440
|
+
clearPassageHighlight: () => void;
|
|
414
441
|
/** Resolve a stable block or text-range target and reveal it in the editor. */
|
|
415
442
|
showInDocument: (target: FolioDocumentNavigationTarget, snapshot?: FolioAIEditSnapshot) => boolean;
|
|
416
443
|
/**
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Vue composables mirroring the React `hooks` subpath — history, table
|
|
5
5
|
* selection, find/replace, clipboard, zoom, tracked-changes, visual-line
|
|
6
6
|
* navigation, and the high-level `useDocxEditor` host composable. Only the
|
|
7
|
-
* composables the fork has ported are re-exported
|
|
8
|
-
* `useCommentSidebarItems` have no Vue equivalent yet).
|
|
7
|
+
* composables the fork has ported are re-exported.
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* ```ts
|
|
@@ -16,6 +15,7 @@
|
|
|
16
15
|
* @public
|
|
17
16
|
*/
|
|
18
17
|
export * from './useClipboard';
|
|
18
|
+
export * from './useColorMode';
|
|
19
19
|
export * from './useDocxEditor';
|
|
20
20
|
export * from './useDragAutoScroll';
|
|
21
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
|
-
*
|
|
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(
|
|
20
|
+
export declare function useColorMode(): ComputedRef<boolean>;
|
|
21
|
+
export type { ColorMode } from '../utils/colorMode';
|
|
@@ -2,9 +2,13 @@ import { MaybeRefOrGetter, Ref } from 'vue';
|
|
|
2
2
|
import { EditorState, Plugin } from 'prosemirror-state';
|
|
3
3
|
import { EditorView } from 'prosemirror-view';
|
|
4
4
|
import { FolioEditor } from '@stll/folio-core/controller/folioEditor';
|
|
5
|
+
import { HeaderFooterPartKind } from '@stll/folio-core/controller/headerFooterEditorManager';
|
|
6
|
+
import { NoteStoryKey } from '@stll/folio-core/controller/noteEditorManager';
|
|
7
|
+
import { HiddenProseMirrorCollaboration, HiddenProseMirrorRemoteSelection } from '@stll/folio-core/controller/hiddenEditorManager';
|
|
5
8
|
import { FolioSelectiveSaveFlags } from '@stll/folio-core/docx/selectiveSaveFlags';
|
|
6
9
|
import { TripwireResult } from '@stll/folio-core/docx/selectiveSaveTripwire';
|
|
7
10
|
import { FlowBlock, Layout, Measure } from '@stll/folio-core/layout-engine/types';
|
|
11
|
+
import { LayoutSelectionGate } from '@stll/folio-core/paged-layout/LayoutSelectionGate';
|
|
8
12
|
import { CommandMap } from '@stll/folio-core/prosemirror/extensions/types';
|
|
9
13
|
import { AnonymizationMatch } from '@stll/folio-core/prosemirror/plugins/anonymizationDecorations';
|
|
10
14
|
import { TemplateSlashMenuKeyAction, TemplateSlashMenuState } from '@stll/folio-core/prosemirror/plugins/templateSlashMenu';
|
|
@@ -13,12 +17,20 @@ import { DocxInput } from '@stll/folio-core/utils/docxInput';
|
|
|
13
17
|
export type UseDocxEditorOptions = {
|
|
14
18
|
/** Container element that hosts the off-screen ProseMirror editor. */
|
|
15
19
|
hiddenContainer: Ref<HTMLElement | null>;
|
|
20
|
+
/** Optional separate host for persistent header/footer ProseMirror views. */
|
|
21
|
+
hiddenHeaderFooterContainer?: Ref<HTMLElement | null>;
|
|
22
|
+
/** Visible host for the active footnote or endnote ProseMirror story. */
|
|
23
|
+
noteEditorContainer?: Ref<HTMLElement | null>;
|
|
16
24
|
/** Container element the paginated pages are painted into. */
|
|
17
25
|
pagesContainer: Ref<HTMLElement | null>;
|
|
18
26
|
/** Whether the editor is read-only. Reactive. */
|
|
19
27
|
readOnly?: MaybeRefOrGetter<boolean>;
|
|
20
28
|
/** Gap between pages in pixels. */
|
|
21
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>;
|
|
22
34
|
/**
|
|
23
35
|
* Stable identity of the loaded document (same across internal edits, distinct
|
|
24
36
|
* per loaded file). Threaded to the hidden-editor manager's external-load
|
|
@@ -36,6 +48,8 @@ export type UseDocxEditorOptions = {
|
|
|
36
48
|
author?: MaybeRefOrGetter<string>;
|
|
37
49
|
/** External ProseMirror plugins supplied by the host app. */
|
|
38
50
|
externalPlugins?: Plugin[];
|
|
51
|
+
/** Reactive Yjs collaboration owner and the ProseMirror binding plugins. */
|
|
52
|
+
collaboration?: MaybeRefOrGetter<UseDocxEditorCollaboration | undefined>;
|
|
39
53
|
/**
|
|
40
54
|
* Fires with the anonymization decoration plugin's current match list on
|
|
41
55
|
* mount, term push, and every doc edit. The anonymization plugin is always
|
|
@@ -62,6 +76,12 @@ export type UseDocxEditorOptions = {
|
|
|
62
76
|
onSelectionUpdate?: (state: EditorState) => void;
|
|
63
77
|
/** Callback when the hidden EditorView is created or torn down. */
|
|
64
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;
|
|
65
85
|
/** Callback when a read-only user action would mutate the document. */
|
|
66
86
|
onReadOnlyEditAttempt?: () => void;
|
|
67
87
|
/**
|
|
@@ -77,6 +97,15 @@ export type UseDocxEditorOptions = {
|
|
|
77
97
|
*/
|
|
78
98
|
onSelectiveSaveTripwire?: ((result: TripwireResult) => void) | undefined;
|
|
79
99
|
};
|
|
100
|
+
export type UseDocxEditorCollaboration = HiddenProseMirrorCollaboration & {
|
|
101
|
+
plugins?: Plugin[] | undefined;
|
|
102
|
+
};
|
|
103
|
+
export type HeaderFooterSelectionState = {
|
|
104
|
+
from: number;
|
|
105
|
+
kind: HeaderFooterPartKind;
|
|
106
|
+
rId: string;
|
|
107
|
+
to: number;
|
|
108
|
+
};
|
|
80
109
|
export type UseDocxEditorReturn = {
|
|
81
110
|
/** The headless controller (imperative API + layout access + events). */
|
|
82
111
|
editor: FolioEditor;
|
|
@@ -84,6 +113,12 @@ export type UseDocxEditorReturn = {
|
|
|
84
113
|
editorView: Ref<EditorView | null>;
|
|
85
114
|
/** Latest editor state, updated on each transaction. */
|
|
86
115
|
editorState: Ref<EditorState | null>;
|
|
116
|
+
/** Remote collaborative cursors decoded into body ProseMirror positions. */
|
|
117
|
+
remoteSelections: Ref<HiddenProseMirrorRemoteSelection[]>;
|
|
118
|
+
/** Selection in the currently active persistent header/footer view. */
|
|
119
|
+
headerFooterSelection: Ref<HeaderFooterSelectionState | null>;
|
|
120
|
+
/** The note story currently open in the visible note editor. */
|
|
121
|
+
activeNoteStory: Ref<NoteStoryKey | null>;
|
|
87
122
|
/** True once the hidden view is mounted and a document is loaded. */
|
|
88
123
|
isReady: Ref<boolean>;
|
|
89
124
|
/**
|
|
@@ -101,6 +136,8 @@ export type UseDocxEditorReturn = {
|
|
|
101
136
|
blocks: Ref<FlowBlock[]>;
|
|
102
137
|
/** Measures from the latest layout pass — the range-projection fallback. */
|
|
103
138
|
measures: Ref<Measure[]>;
|
|
139
|
+
/** Gate that schedules overlay work only after the matching layout paint. */
|
|
140
|
+
syncCoordinator: LayoutSelectionGate;
|
|
104
141
|
/** Load a DOCX from a binary buffer / Blob / File. */
|
|
105
142
|
loadBuffer: (buffer: DocxInput) => Promise<void>;
|
|
106
143
|
/** Load an already-parsed `Document` directly. */
|
|
@@ -113,6 +150,16 @@ export type UseDocxEditorReturn = {
|
|
|
113
150
|
getDocument: () => Document | null;
|
|
114
151
|
/** Publish a fresh Document object (e.g. after HF materialisation). */
|
|
115
152
|
setDocument: (doc: Document) => void;
|
|
153
|
+
/** Resolve a persistent header/footer EditorView by relationship id. */
|
|
154
|
+
getHeaderFooterView: (rId: string) => EditorView | null;
|
|
155
|
+
/** Synchronize persistent header/footer views after a document-model change. */
|
|
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;
|
|
116
163
|
/** Access the extension command map for invoking marks / nodes / features. */
|
|
117
164
|
getCommands: () => CommandMap;
|
|
118
165
|
/** Focus the hidden ProseMirror view. */
|
|
@@ -42,6 +42,17 @@ 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
|
/**
|
|
@@ -55,6 +66,9 @@ export type UseDocxEditorRefApiOptions = {
|
|
|
55
66
|
setComments: (comments: Comment[]) => void;
|
|
56
67
|
focus: () => void;
|
|
57
68
|
getDocument: () => Document | null;
|
|
69
|
+
getActiveView: () => EditorView | null;
|
|
70
|
+
closeNoteStory: () => void;
|
|
71
|
+
getHeaderFooterView: (rId: string) => EditorView | null;
|
|
58
72
|
setZoom: (zoom: number) => void;
|
|
59
73
|
/** useDocxEditor.save returns a Blob; the ref surface exposes an ArrayBuffer. */
|
|
60
74
|
save: (options?: {
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { ComputedRef, Ref, ShallowRef } from 'vue';
|
|
2
|
+
import { EditorView } from 'prosemirror-view';
|
|
3
|
+
import { ProseMirrorFindMatch } from '@stll/folio-core/prosemirror/findReplaceSelection';
|
|
4
|
+
import { FindOptions } from '@stll/folio-core/utils/findReplace';
|
|
5
|
+
export type UseFindReplaceOptions = {
|
|
6
|
+
editorView: Readonly<Ref<EditorView | null>>;
|
|
7
|
+
scrollVisiblePositionIntoView?: (pmPos: number) => void;
|
|
8
|
+
};
|
|
9
|
+
export type UseFindReplaceReturn = {
|
|
10
|
+
searchText: Ref<string>;
|
|
11
|
+
replaceText: Ref<string>;
|
|
12
|
+
options: FindOptions;
|
|
13
|
+
matches: ShallowRef<ProseMirrorFindMatch[]>;
|
|
14
|
+
currentIndex: Ref<number>;
|
|
15
|
+
currentMatch: ComputedRef<ProseMirrorFindMatch | null>;
|
|
16
|
+
performSearch: () => ProseMirrorFindMatch[];
|
|
17
|
+
goToMatch: (index: number) => boolean;
|
|
18
|
+
findNext: () => ProseMirrorFindMatch | null;
|
|
19
|
+
findPrevious: () => ProseMirrorFindMatch | null;
|
|
20
|
+
replaceCurrent: () => boolean;
|
|
21
|
+
replaceAll: () => number;
|
|
22
|
+
clear: () => void;
|
|
23
|
+
};
|
|
24
|
+
export declare function useFindReplace({ editorView, scrollVisiblePositionIntoView, }: UseFindReplaceOptions): UseFindReplaceReturn;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { FontDefinition } from '../components/DocxEditor/types';
|
|
3
|
+
export type UseFontLifecycleOptions = {
|
|
4
|
+
isReady: Ref<boolean>;
|
|
5
|
+
getDocument: () => {
|
|
6
|
+
originalBuffer?: ArrayBuffer | null;
|
|
7
|
+
} | null;
|
|
8
|
+
fonts: () => ReadonlyArray<FontDefinition> | undefined;
|
|
9
|
+
remeasure: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type FontLifecycleDependencies = {
|
|
12
|
+
loadEmbedded: (buffer: ArrayBuffer) => Promise<FontFace[]>;
|
|
13
|
+
loadHost: (fonts: ReadonlyArray<FontDefinition> | undefined) => Promise<FontFace[]>;
|
|
14
|
+
remove: (faces: readonly FontFace[]) => void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Register document-embedded and host-provided fonts for the lifetime of their
|
|
18
|
+
* sources. Async results from a stale document or prop value are immediately
|
|
19
|
+
* removed, preventing one editor load from leaking faces into the next.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useFontLifecycle(options: UseFontLifecycleOptions, dependencies?: FontLifecycleDependencies): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Ref, ShallowRef } from 'vue';
|
|
2
2
|
import { Command } from 'prosemirror-state';
|
|
3
3
|
import { EditorView } from 'prosemirror-view';
|
|
4
|
-
import { HeaderFooter, BlockContent } from '@stll/folio-core/types/content';
|
|
5
4
|
import { Document } from '@stll/folio-core/types/document';
|
|
5
|
+
import { NoteStoryKey } from '@stll/folio-core/controller/noteEditorManager';
|
|
6
6
|
import { Layout } from '@stll/folio-core/layout-engine';
|
|
7
7
|
import { ImageSelectionInfo } from '../components/imageSelectionTypes';
|
|
8
8
|
import { HyperlinkPopupData } from '../components/ui/hyperlinkPopupTypes';
|
|
@@ -19,9 +19,10 @@ export type TableInsertButton = {
|
|
|
19
19
|
cellPmPos: number;
|
|
20
20
|
};
|
|
21
21
|
export type HfEditState = {
|
|
22
|
+
isFirstPage: boolean;
|
|
23
|
+
pageNumber: number;
|
|
22
24
|
position: "header" | "footer";
|
|
23
25
|
rId: string | null;
|
|
24
|
-
headerFooter: HeaderFooter | null;
|
|
25
26
|
targetRect: {
|
|
26
27
|
top: number;
|
|
27
28
|
left: number;
|
|
@@ -42,29 +43,29 @@ export type UsePagesPointerOptions = {
|
|
|
42
43
|
imageInteracting: Ref<boolean>;
|
|
43
44
|
hyperlinkPopupData: Ref<HyperlinkPopupData | null>;
|
|
44
45
|
readOnly: Ref<boolean>;
|
|
46
|
+
showHeaderFooterEditing: Ref<boolean>;
|
|
45
47
|
zoom: Ref<number>;
|
|
46
48
|
layout: Ref<Layout | null>;
|
|
47
49
|
tableResize: TableResizeApi;
|
|
48
50
|
getCommands: () => Commands;
|
|
49
51
|
getDocument: () => Document | null;
|
|
50
52
|
reLayout: () => void;
|
|
51
|
-
|
|
53
|
+
onDocumentChange: (document: Document) => void;
|
|
52
54
|
clearOverlay: () => void;
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
* exposed by `useDocxEditor.syncHfPMs`. Called after every save so the
|
|
56
|
-
* persistent PM points at the new HeaderFooter object. Optional so existing
|
|
57
|
-
* consumers can no-op until they wire it through.
|
|
58
|
-
*/
|
|
59
|
-
syncHfPMs?: () => void;
|
|
55
|
+
/** Synchronize persistent header/footer views after document-model changes. */
|
|
56
|
+
syncHfPMs: () => void;
|
|
60
57
|
/** Resolve the persistent EditorView for an HF instance (for click routing). */
|
|
61
|
-
getHfPmView
|
|
58
|
+
getHfPmView: (rId: string) => EditorView | null;
|
|
62
59
|
/**
|
|
63
60
|
* Replace the loaded Document — used by HF materialisation to publish a
|
|
64
61
|
* fresh Document object instead of mutating in place. Optional; if absent,
|
|
65
62
|
* callers fall back to in-place mutation + `syncHfPMs()`.
|
|
66
63
|
*/
|
|
67
|
-
setDocument
|
|
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;
|
|
68
69
|
};
|
|
69
70
|
export type UsePagesPointerReturn = {
|
|
70
71
|
tableInsertButton: Ref<TableInsertButton | null>;
|
|
@@ -80,7 +81,7 @@ export type UsePagesPointerReturn = {
|
|
|
80
81
|
handlePagesDoubleClick: (event: MouseEvent) => void;
|
|
81
82
|
handleTableInsertClick: (event: MouseEvent) => void;
|
|
82
83
|
clearTableInsertTimer: () => void;
|
|
83
|
-
handleHfSave: (
|
|
84
|
+
handleHfSave: () => void;
|
|
84
85
|
handleHfRemove: () => void;
|
|
85
86
|
};
|
|
86
87
|
export declare function usePagesPointer(opts: UsePagesPointerOptions): UsePagesPointerReturn;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { HiddenProseMirrorRemoteSelection } from '@stll/folio-core/controller/hiddenEditorManager';
|
|
3
|
+
import { LayoutSelectionGate } from '@stll/folio-core/paged-layout/LayoutSelectionGate';
|
|
4
|
+
export type UseRemoteSelectionSyncOptions = {
|
|
5
|
+
pagesRef: Ref<HTMLElement | null>;
|
|
6
|
+
remoteSelections: Ref<HiddenProseMirrorRemoteSelection[]>;
|
|
7
|
+
syncCoordinator: LayoutSelectionGate;
|
|
8
|
+
zoom: Ref<number>;
|
|
9
|
+
};
|
|
10
|
+
export declare const useRemoteSelectionSync: (options: UseRemoteSelectionSyncOptions) => void;
|
|
@@ -1,30 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*
|
|
19
|
-
* The DOM primitives it also uses DO resolve, but at drifted paths
|
|
20
|
-
* (`getSelectionRectsFromDom`/`getCaretPositionFromDom` →
|
|
21
|
-
* `@stll/folio-core/layout-bridge/dom/clickToPositionDom`; `findBodyPmAnchor` →
|
|
22
|
-
* `@stll/folio-core/layout-bridge/dom/findBodyPmSpans`). With the four blockers
|
|
23
|
-
* above there is no coherent working subset, so the whole composable is blocked.
|
|
24
|
-
*
|
|
25
|
-
* Unblock: PORT `applyCellSelectionHighlight` and `findImageElement` into core
|
|
26
|
-
* (or a core barrel), then port the `imageSelectionTypes` + `styles/zIndex`
|
|
27
|
-
* Vue-package modules, and re-point the DOM-primitive imports to the drifted
|
|
28
|
-
* paths above.
|
|
29
|
-
*/
|
|
30
|
-
export {};
|
|
1
|
+
import { Ref, ShallowRef } from 'vue';
|
|
2
|
+
import { EditorView } from 'prosemirror-view';
|
|
3
|
+
import { LayoutSelectionGate } from '@stll/folio-core/paged-layout/LayoutSelectionGate';
|
|
4
|
+
import { ImageSelectionInfo } from '../components/imageSelectionTypes';
|
|
5
|
+
export type UseSelectionSyncOptions = {
|
|
6
|
+
editorView: Ref<EditorView | null>;
|
|
7
|
+
pagesRef: Ref<HTMLElement | null>;
|
|
8
|
+
zoom: Ref<number>;
|
|
9
|
+
selectedImage: ShallowRef<ImageSelectionInfo | null>;
|
|
10
|
+
syncCoordinator: LayoutSelectionGate;
|
|
11
|
+
imageInteracting?: Ref<boolean>;
|
|
12
|
+
};
|
|
13
|
+
export type UseSelectionSyncReturn = {
|
|
14
|
+
clearOverlay: () => void;
|
|
15
|
+
updateSelectionOverlay: () => void;
|
|
16
|
+
};
|
|
17
|
+
export declare const useSelectionSync: (opts: UseSelectionSyncOptions) => UseSelectionSyncReturn;
|
package/dist/composables.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useZoom-
|
|
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
|
-
`;
|
|
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;
|