@portone/docx-editor 0.5.1 → 0.6.1
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/CHANGELOG.md +47 -0
- package/CONTRIBUTING.md +8 -2
- package/README.md +1 -1
- package/dist/DocxEditor.js +87 -29
- package/dist/docx/exportDocx.d.ts +2 -1
- package/dist/docx/exportDocx.js +3 -9
- package/dist/docx/headersFooters.js +35 -23
- package/dist/docx/identities.d.ts +28 -0
- package/dist/docx/identities.js +42 -10
- package/dist/docx/importDocx.js +25 -26
- package/dist/docx/importParagraph.d.ts +1 -4
- package/dist/docx/importParagraph.js +4 -18
- package/dist/docx/invariants.d.ts +1 -1
- package/dist/docx/invariants.js +45 -4
- package/dist/docx/notes/newNote.d.ts +39 -0
- package/dist/docx/notes/newNote.js +122 -0
- package/dist/docx/notes/numbering.d.ts +27 -0
- package/dist/docx/notes/numbering.js +120 -0
- package/dist/docx/notes/reading.d.ts +58 -0
- package/dist/docx/notes/reading.js +98 -0
- package/dist/docx/notes/writing.d.ts +19 -0
- package/dist/docx/notes/writing.js +96 -0
- package/dist/docx/partPlan.d.ts +3 -0
- package/dist/docx/partPlanners.d.ts +13 -0
- package/dist/docx/partPlanners.js +48 -0
- package/dist/docx/sections.d.ts +5 -0
- package/dist/docx/sections.js +7 -2
- package/dist/docx/serializeParagraph.js +7 -2
- package/dist/docx/session.d.ts +5 -0
- package/dist/docx/session.js +6 -0
- package/dist/docx/storyParts.d.ts +112 -0
- package/dist/docx/storyParts.js +289 -0
- package/dist/editor/clipboard/htmlReader.d.ts +24 -4
- package/dist/editor/clipboard/htmlReader.js +39 -4
- package/dist/editor/clipboard/internalChannel.d.ts +30 -3
- package/dist/editor/clipboard/internalChannel.js +43 -3
- package/dist/editor/clipboard/normalizers.d.ts +35 -8
- package/dist/editor/clipboard/normalizers.js +60 -11
- package/dist/editor/clipboard/plugin.js +42 -22
- package/dist/editor/commands/comments/editing.d.ts +4 -1
- package/dist/editor/commands/comments/editing.js +1 -3
- package/dist/editor/commands/comments/model.d.ts +7 -0
- package/dist/editor/commands/index.d.ts +1 -0
- package/dist/editor/commands/index.js +18 -0
- package/dist/editor/commands/noteCommands.d.ts +47 -0
- package/dist/editor/commands/noteCommands.js +95 -0
- package/dist/editor/commands/noteQueries.d.ts +22 -3
- package/dist/editor/commands/noteQueries.js +21 -13
- package/dist/editor/createEditor.js +25 -3
- package/dist/editor/documentStyles.d.ts +3 -0
- package/dist/editor/documentStyles.js +2 -1
- package/dist/editor/editorDocument.d.ts +24 -0
- package/dist/editor/editorDocument.js +34 -4
- package/dist/editor/notes/noteSurface.d.ts +53 -0
- package/dist/editor/notes/noteSurface.js +246 -0
- package/dist/editor/plugins/commentDecorations.js +5 -4
- package/dist/editor/plugins/commentRestoration.d.ts +20 -0
- package/dist/editor/plugins/commentRestoration.js +168 -0
- package/dist/editor/plugins/compositionSelection.d.ts +20 -0
- package/dist/editor/plugins/compositionSelection.js +19 -0
- package/dist/editor/plugins/keymap.d.ts +14 -0
- package/dist/editor/plugins/keymap.js +13 -1
- package/dist/editor/plugins/noteLifecycle.d.ts +18 -0
- package/dist/editor/plugins/noteLifecycle.js +117 -0
- package/dist/editor/plugins/noteNavigation.d.ts +45 -0
- package/dist/editor/plugins/noteNavigation.js +86 -0
- package/dist/editor/plugins/noteNumbering.d.ts +13 -0
- package/dist/editor/plugins/noteNumbering.js +58 -0
- package/dist/editor/plugins/rowResize.js +2 -7
- package/dist/editor/plugins/tabLayout.js +2 -7
- package/dist/editor/stories/storyMarkup.d.ts +24 -0
- package/dist/editor/stories/storyMarkup.js +35 -0
- package/dist/editor/stories/storyState.d.ts +34 -0
- package/dist/editor/stories/storyState.js +74 -0
- package/dist/editor/stories/storyView.d.ts +115 -0
- package/dist/editor/stories/storyView.js +144 -0
- package/dist/numbering/spellers.d.ts +1 -1
- package/dist/numbering/spellers.js +6 -1
- package/dist/page/blockKinds.d.ts +23 -4
- package/dist/page/demands/footnoteDemands.d.ts +18 -0
- package/dist/page/demands/footnoteDemands.js +51 -0
- package/dist/page/demands/index.d.ts +43 -0
- package/dist/page/demands/index.js +8 -0
- package/dist/page/kinds/paragraphKind.js +7 -1
- package/dist/page/kinds/tableKind.js +9 -1
- package/dist/page/measureBlocks.d.ts +2 -0
- package/dist/page/measureBlocks.js +31 -10
- package/dist/page/pageDecorations.d.ts +9 -2
- package/dist/page/pageDecorations.js +18 -5
- package/dist/page/pageLayout.d.ts +77 -1
- package/dist/page/pageLayout.js +186 -9
- package/dist/page/usePageLayout.d.ts +57 -2
- package/dist/page/usePageLayout.js +50 -5
- package/dist/schema/attrRoles.js +3 -2
- package/dist/schema/docxSchema.js +5 -2
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.js +1 -2
- package/dist/schema/preservedGuards.d.ts +4 -6
- package/dist/schema/preservedGuards.js +0 -9
- package/dist/schema/stories.d.ts +34 -2
- package/dist/schema/stories.js +22 -5
- package/dist/styles/classNames.d.ts +23 -6
- package/dist/styles/classNames.js +23 -6
- package/dist/styles/inlineStyle.d.ts +7 -0
- package/dist/styles/inlineStyle.js +11 -5
- package/dist/styles/visualScale.d.ts +19 -0
- package/dist/styles/visualScale.js +26 -0
- package/dist/styles.css +96 -36
- package/dist/ui/CommentsPanel.d.ts +6 -1
- package/dist/ui/CommentsPanel.js +26 -8
- package/dist/ui/InsertImageButton.d.ts +3 -1
- package/dist/ui/InsertImageButton.js +3 -2
- package/dist/ui/TableMenu.d.ts +5 -2
- package/dist/ui/TableMenu.js +18 -1
- package/dist/ui/TextMenu.d.ts +5 -2
- package/dist/ui/TextMenu.js +21 -6
- package/dist/ui/Toolbar.d.ts +17 -2
- package/dist/ui/Toolbar.js +23 -10
- package/dist/ui/comments/useCommentRailLayout.js +2 -4
- package/dist/ui/noteItems.d.ts +21 -0
- package/dist/ui/noteItems.js +30 -0
- package/dist/ui/notes/NoteAreas.d.ts +73 -0
- package/dist/ui/notes/NoteAreas.js +131 -0
- package/dist/ui/notes/NoteList.d.ts +25 -0
- package/dist/ui/notes/NoteList.js +58 -0
- package/dist/ui/notes/StoryRow.d.ts +75 -0
- package/dist/ui/notes/StoryRow.js +122 -0
- package/dist/ui/notes/noteBands.d.ts +100 -0
- package/dist/ui/notes/noteBands.js +142 -0
- package/dist/ui/notes/noteHeights.d.ts +10 -0
- package/dist/ui/notes/noteHeights.js +24 -0
- package/dist/ui/notes/noteSeparator.d.ts +12 -0
- package/dist/ui/notes/noteSeparator.js +9 -0
- package/dist/ui/notes/useStorySurface.d.ts +68 -0
- package/dist/ui/notes/useStorySurface.js +95 -0
- package/dist/ui/runCommand.d.ts +8 -1
- package/dist/ui/runCommand.js +2 -2
- package/dist/ui/shortcutLabels.d.ts +16 -0
- package/dist/ui/shortcutLabels.js +9 -0
- package/dist/ui/usePageRoom.d.ts +13 -0
- package/dist/ui/usePageRoom.js +31 -0
- package/package.json +2 -1
- package/dist/docx/notes.d.ts +0 -27
- package/dist/docx/notes.js +0 -55
- package/dist/ui/NotesPanel.d.ts +0 -6
- package/dist/ui/NotesPanel.js +0 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# @portone/docx-editor
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#137](https://github.com/portone-io/docx-editor/pull/137) [`a2f1a96`](https://github.com/portone-io/docx-editor/commit/a2f1a96a97c9dd45e07c962ae4a85e8d6954f657) Thanks [@Deea222](https://github.com/Deea222)! - Typing with an IME over a selection that begins at a footnote's number now replaces the selection. Selecting the whole of a footnote and typing over it left its words standing behind the composed text.
|
|
8
|
+
|
|
9
|
+
- [#138](https://github.com/portone-io/docx-editor/pull/138) [`16467c2`](https://github.com/portone-io/docx-editor/commit/16467c21934d9659f6e0b85d2094277cfcaa7366) Thanks [@Deea222](https://github.com/Deea222)! - Edit, insert, delete, and copy endnotes the way footnotes are, and draw them after the last paragraph of the document.
|
|
10
|
+
|
|
11
|
+
- [#137](https://github.com/portone-io/docx-editor/pull/137) [`a2f1a96`](https://github.com/portone-io/docx-editor/commit/a2f1a96a97c9dd45e07c962ae4a85e8d6954f657) Thanks [@Deea222](https://github.com/Deea222)! - Paste a copied footnote reference with a copy of its footnote.
|
|
12
|
+
|
|
13
|
+
- [#137](https://github.com/portone-io/docx-editor/pull/137) [`a2f1a96`](https://github.com/portone-io/docx-editor/commit/a2f1a96a97c9dd45e07c962ae4a85e8d6954f657) Thanks [@Deea222](https://github.com/Deea222)! - Edit footnotes in place: insert one from the right-click menu or with Mod+Alt+F, open it by clicking its number, and leave it with Escape.
|
|
14
|
+
|
|
15
|
+
- [#136](https://github.com/portone-io/docx-editor/pull/136) [`3c74b87`](https://github.com/portone-io/docx-editor/commit/3c74b87e52233b990e820752d50383411032e81d) Thanks [@Deea222](https://github.com/Deea222)! - Add the `insertFootnote`, `canInsertFootnote`, and `setFootnoteBody` commands, and delete a footnote together with its last reference, so one undo brings both back.
|
|
16
|
+
|
|
17
|
+
- [#136](https://github.com/portone-io/docx-editor/pull/136) [`3c74b87`](https://github.com/portone-io/docx-editor/commit/3c74b87e52233b990e820752d50383411032e81d) Thanks [@Deea222](https://github.com/Deea222)! - Draw footnotes at the foot of the page that refers to them, with the page ending above them, and list endnotes with their formatting after the last page, in place of the plain-text notes list.
|
|
18
|
+
|
|
19
|
+
- [#135](https://github.com/portone-io/docx-editor/pull/135) [`d6c701e`](https://github.com/portone-io/docx-editor/commit/d6c701ee3ce60b52772c7413e9f003fc717dbd77) Thanks [@Deea222](https://github.com/Deea222)! - Number footnotes and endnotes in the document's own format, starting number, and section restarts, and renumber them after every edit. A reference that carries its own mark, such as a dagger, is announced by its kind alone rather than by a number it does not have.
|
|
20
|
+
|
|
21
|
+
- [#135](https://github.com/portone-io/docx-editor/pull/135) [`d6c701e`](https://github.com/portone-io/docx-editor/commit/d6c701ee3ce60b52772c7413e9f003fc717dbd77) Thanks [@Deea222](https://github.com/Deea222)! - Save an edited, added, or deleted footnote or endnote into the file, creating the notes part where the document had none. An export that changed something nothing writes back yet, such as a note separator, is refused rather than saved without the change.
|
|
22
|
+
|
|
23
|
+
- [#140](https://github.com/portone-io/docx-editor/pull/140) [`a35b24c`](https://github.com/portone-io/docx-editor/commit/a35b24ccbac8cbc9d851381290e0e469a4abc6f1) Thanks [@Deea222](https://github.com/Deea222)! - Fix arrow navigation entering page-break spacing near footnotes, where typed text could appear without being saved in the document.
|
|
24
|
+
|
|
25
|
+
- [#139](https://github.com/portone-io/docx-editor/pull/139) [`0e8c474`](https://github.com/portone-io/docx-editor/commit/0e8c474a913c5dba8f40cdc539c401782fba5c64) Thanks [@Deea222](https://github.com/Deea222)! - A document breaks into the same pages at every zoom and window width. Below a zoom of about 0.8, a document sitting close to a page boundary could gain a page and its pages could move as the window narrowed; a scale an application puts around the editor, such as a dialog that opens on a scale, no longer moves them either.
|
|
26
|
+
|
|
27
|
+
## 0.6.0
|
|
28
|
+
|
|
29
|
+
### Minor Changes
|
|
30
|
+
|
|
31
|
+
- [#131](https://github.com/portone-io/docx-editor/pull/131) [`5dd468a`](https://github.com/portone-io/docx-editor/commit/5dd468ae14d6210070ab6c8275d16e03b20cf64c) Thanks [@Deea222](https://github.com/Deea222)! - A comment now outlives the text it was written for, and a resolved one stops marking the page.
|
|
32
|
+
|
|
33
|
+
Deleting commented text used to delete the comment and everything said under it. The thread now
|
|
34
|
+
stays. Trim the highlighted text - type over part of it, backspace through its edge - and the
|
|
35
|
+
comment follows what is left. Delete all of it and the comment comes back detached: no longer drawn
|
|
36
|
+
beside the page, since there is nothing to draw it next to, and listed under All comments marked
|
|
37
|
+
"Original content deleted". Cutting commented text leaves it behind the same way instead of dropping
|
|
38
|
+
it. Word has no detached state, so such a comment reaches the saved file as an ordinary comment
|
|
39
|
+
sitting where the deleted text was. Deleting a comment from its own Delete button still deletes it,
|
|
40
|
+
and undo and redo still take a deletion back and make it again.
|
|
41
|
+
|
|
42
|
+
Resolving a thread now takes its highlight off the text, and reopening puts it back. Clicking a
|
|
43
|
+
resolved comment's card in All comments selects the text it was written about and scrolls it into
|
|
44
|
+
view, which `selectComment` now does for every caller.
|
|
45
|
+
|
|
46
|
+
`documentComments` reports a new `anchored` field on every comment, `false` for one that no longer
|
|
47
|
+
marks a stretch of the document. Its existing fields are unchanged, so a panel of your own keeps
|
|
48
|
+
working and can read the new field to decide what a click on a card should do.
|
|
49
|
+
|
|
3
50
|
## 0.5.1
|
|
4
51
|
|
|
5
52
|
### Patch Changes
|
package/CONTRIBUTING.md
CHANGED
|
@@ -44,22 +44,28 @@ Run a specialized check when your change affects its area:
|
|
|
44
44
|
pnpm test:package
|
|
45
45
|
pnpm verify:package
|
|
46
46
|
pnpm test:e2e
|
|
47
|
+
pnpm bench
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
A pull request that changes performance-sensitive code attaches its `pnpm bench` output to the description.
|
|
51
|
+
|
|
49
52
|
[Testing](https://github.com/portone-io/docx-editor/blob/main/docs/testing.md) explains the scope and prerequisites of every check.
|
|
53
|
+
CI runs `pnpm test:package` on every pull request in a separate job; it is not part of the local `pnpm check` command.
|
|
50
54
|
|
|
51
55
|
A command added to `./commands` or `./table` needs a writer probe in `src/docx/__testing__/writerProbes.ts` with a `check` of its immediate effect, so its export is validated before another command can overwrite it, or an entry in `NOT_A_WRITER` giving the reason it reaches no writer.
|
|
52
56
|
|
|
53
57
|
## Changesets
|
|
54
58
|
|
|
55
|
-
If you changed
|
|
59
|
+
If you changed production code under `src/`, run `pnpm changeset` and commit the file it writes.
|
|
56
60
|
It becomes the CHANGELOG entry, so write it for someone reading release notes rather than the diff.
|
|
61
|
+
Changes limited to tests, fixtures, scripts, or documentation do not need a changeset.
|
|
57
62
|
|
|
58
|
-
The public API is the exported names and types of the four entry points - `.`, `./core`, `./commands`, and `./table` - together with the parts of the document model that [What a plugin may rely on](https://docx-editor.portone.io/docs/
|
|
63
|
+
The public API is the exported names and types of the four entry points - `.`, `./core`, `./commands`, and `./table` - together with the parts of the document model that [What a plugin may rely on](https://docx-editor.portone.io/docs/editor-api/plugins-and-presets#what-a-plugin-may-rely-on) calls stable.
|
|
59
64
|
An attr that page calls internal is not part of it, and neither is anything under `src/` that no entry point reaches.
|
|
60
65
|
|
|
61
66
|
Choose `patch` unless the change adds to that surface, takes something out of it, or changes what a part of it means.
|
|
62
67
|
Those are `minor` while the package is below 1.0.
|
|
68
|
+
A diff to `src/schema/attrRoles.ts` is where to check this: a change to a stable document-model attr is `minor` even when the declaration reports do not change.
|
|
63
69
|
A declaration added, removed, or rewritten in `etc/*.api.md` after running `pnpm api:update` is what that looks like; a line that only gains or loses an `(undocumented)` marker is not.
|
|
64
70
|
Commit the regenerated report in the same commit as the changeset.
|
|
65
71
|
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ export function Editor({
|
|
|
47
47
|
- Preserves document structures and package parts across edits, and records who wrote each comment.
|
|
48
48
|
- Reads document styles, theme fonts, page layout, and CJK font information for display.
|
|
49
49
|
|
|
50
|
-
See [Feature support](https://docx-editor.portone.io/docs/features) for the support matrix. Build [
|
|
50
|
+
See [Feature support](https://docx-editor.portone.io/docs/features) for the support matrix. Build controls of your own with the [Editor API](https://docx-editor.portone.io/docs/editor-api) or use [programmatic DOCX import and export](https://docx-editor.portone.io/docs/core).
|
|
51
51
|
|
|
52
52
|
The full [documentation](https://docx-editor.portone.io/docs) lives on the documentation site.
|
|
53
53
|
|
package/dist/DocxEditor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/DocxEditor.tsx
|
|
2
2
|
import {
|
|
3
3
|
forwardRef,
|
|
4
|
+
useCallback,
|
|
4
5
|
useEffect,
|
|
5
6
|
useImperativeHandle,
|
|
6
7
|
useLayoutEffect,
|
|
@@ -15,6 +16,13 @@ import { exportProblems } from "./docx/invariants.js";
|
|
|
15
16
|
import { sectionIn, sectionsOf } from "./docx/sections.js";
|
|
16
17
|
import { activeLinkSpan } from "./editor/commands/linkCommands.js";
|
|
17
18
|
import { createEditorView, editorStateForSession } from "./editor/createEditor.js";
|
|
19
|
+
import { sectionGeometryAt } from "./editor/documentStyles.js";
|
|
20
|
+
import { storyDocument } from "./editor/editorDocument.js";
|
|
21
|
+
import {
|
|
22
|
+
noteExtensions,
|
|
23
|
+
noteHost,
|
|
24
|
+
returnToReference
|
|
25
|
+
} from "./editor/notes/noteSurface.js";
|
|
18
26
|
import {
|
|
19
27
|
closeCommentComposer,
|
|
20
28
|
isCommentComposerOpen
|
|
@@ -22,6 +30,10 @@ import {
|
|
|
22
30
|
import { commentProjection } from "./editor/plugins/commentDecorations.js";
|
|
23
31
|
import { setProtection } from "./editor/plugins/documentProtection.js";
|
|
24
32
|
import { isLinkPanelOpen } from "./editor/plugins/linkPanel.js";
|
|
33
|
+
import {
|
|
34
|
+
openNoteCommand,
|
|
35
|
+
requestedNote
|
|
36
|
+
} from "./editor/plugins/noteNavigation.js";
|
|
25
37
|
import { tableMenuAnchor } from "./editor/plugins/tableContextMenu.js";
|
|
26
38
|
import { textMenuAnchor } from "./editor/plugins/textContextMenu.js";
|
|
27
39
|
import { DocxImportError } from "./ooxml/errors.js";
|
|
@@ -31,19 +43,35 @@ import { usePageLayout } from "./page/usePageLayout.js";
|
|
|
31
43
|
import { editingProtection, protectionOf } from "./schema/protectionState.js";
|
|
32
44
|
import { storyNodeOf } from "./schema/stories.js";
|
|
33
45
|
import { editorClassNames } from "./styles/classNames.js";
|
|
34
|
-
import { CommentsPanel } from "./ui/CommentsPanel.js";
|
|
46
|
+
import { CommentsPanel, shownBesideThePage } from "./ui/CommentsPanel.js";
|
|
35
47
|
import { LinkCard } from "./ui/LinkCard.js";
|
|
36
48
|
import { LinkPanel } from "./ui/LinkPanel.js";
|
|
37
|
-
import {
|
|
49
|
+
import { NotesAroundPage, useNoteBands } from "./ui/notes/noteBands.js";
|
|
50
|
+
import {
|
|
51
|
+
useStorySurface
|
|
52
|
+
} from "./ui/notes/useStorySurface.js";
|
|
38
53
|
import { TableMenu } from "./ui/TableMenu.js";
|
|
39
54
|
import { TextMenu } from "./ui/TextMenu.js";
|
|
40
55
|
import { Toolbar } from "./ui/Toolbar.js";
|
|
41
56
|
import { useFitWidthZoom } from "./ui/useFitWidthZoom.js";
|
|
57
|
+
import { usePageRoom } from "./ui/usePageRoom.js";
|
|
42
58
|
import { normalizeZoom } from "./ui/zoom.js";
|
|
43
59
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
44
60
|
function runOn(view, command) {
|
|
45
61
|
command(view.state, (transaction) => view.dispatch(transaction));
|
|
46
62
|
}
|
|
63
|
+
var NOTE_SURFACE = {
|
|
64
|
+
hostOf: noteHost,
|
|
65
|
+
extensionsOf: (main, row) => noteExtensions(main, row.key, () => row.label),
|
|
66
|
+
// The paper a note wraps at is the paper of the section its reference stands in, which a story
|
|
67
|
+
// holds no section of its own to say (`editor/documentStyles`)
|
|
68
|
+
documentFor: (main, snapshot, row) => storyDocument(snapshot, sectionGeometryAt(main, row.referencePos)),
|
|
69
|
+
requestedIn: requestedNote,
|
|
70
|
+
// The kind's own public command is what a consumer calls; here the kind is a value the row
|
|
71
|
+
// carries, so the factory behind the two takes it
|
|
72
|
+
openIn: (main, row) => runOn(main, openNoteCommand(row.kind, row.id)),
|
|
73
|
+
returnFrom: (main, row) => returnToReference(main, row.key)
|
|
74
|
+
};
|
|
47
75
|
function affordancesOf(mode) {
|
|
48
76
|
switch (mode.kind) {
|
|
49
77
|
case "readOnly":
|
|
@@ -169,6 +197,12 @@ function DocxEditorSurface({
|
|
|
169
197
|
);
|
|
170
198
|
const viewRef = useRef(null);
|
|
171
199
|
const [live, setLive] = useState(null);
|
|
200
|
+
const [pageBox, setPageBox] = useState(null);
|
|
201
|
+
const [pageLayer, setPageLayer] = useState(null);
|
|
202
|
+
const holdPageLayer = useCallback((node) => {
|
|
203
|
+
layerRef.current = node;
|
|
204
|
+
setPageLayer(node);
|
|
205
|
+
}, []);
|
|
172
206
|
const [commentsOpen, setCommentsOpen] = useState(false);
|
|
173
207
|
const [uncontrolledZoom, setUncontrolledZoom] = useState(
|
|
174
208
|
() => normalizeZoom(defaultZoom)
|
|
@@ -179,6 +213,7 @@ function DocxEditorSurface({
|
|
|
179
213
|
const page = opened?.status === "opened" ? pagePixels(opened.session.geometry) : A4_PAGE_PIXELS;
|
|
180
214
|
const fitWidth = useFitWidthZoom(rootRef, page.pageWidth);
|
|
181
215
|
const effectiveZoom = selectedZoom === "fit-width" ? fitWidth : selectedZoom;
|
|
216
|
+
usePageRoom(pageBox, pageLayer, effectiveZoom);
|
|
182
217
|
const changeZoom = (next) => {
|
|
183
218
|
const normalized = normalizeZoom(next);
|
|
184
219
|
if (zoom === void 0) setUncontrolledZoom(normalized);
|
|
@@ -254,12 +289,27 @@ function DocxEditorSurface({
|
|
|
254
289
|
() => sections === null ? void 0 : sectionPixels(sections),
|
|
255
290
|
[sections]
|
|
256
291
|
);
|
|
292
|
+
const notes = useNoteBands({
|
|
293
|
+
state: live?.state ?? null,
|
|
294
|
+
of: opened,
|
|
295
|
+
fontFallbacks: mountedFontFallbacks
|
|
296
|
+
});
|
|
297
|
+
const surface = useStorySurface({
|
|
298
|
+
main: live,
|
|
299
|
+
rows: notes.rows,
|
|
300
|
+
binding: NOTE_SURFACE
|
|
301
|
+
});
|
|
257
302
|
const overlay = usePageLayout({
|
|
258
303
|
view: live?.view ?? null,
|
|
259
304
|
layer: layerRef,
|
|
260
305
|
enabled: showPageGuides,
|
|
261
306
|
revision: live?.state.doc,
|
|
262
|
-
sections: sectionPapers
|
|
307
|
+
sections: sectionPapers,
|
|
308
|
+
bands: notes.bands,
|
|
309
|
+
trailing: notes.trailing,
|
|
310
|
+
// A page laid out again draws the row the open note stands in wherever it now lands, which
|
|
311
|
+
// would take its composition down with it
|
|
312
|
+
composing: surface.composing
|
|
263
313
|
});
|
|
264
314
|
const headersFootersFor = useMemo(() => {
|
|
265
315
|
if (doc === null || session === null || sections === null) return void 0;
|
|
@@ -280,9 +330,9 @@ function DocxEditorSurface({
|
|
|
280
330
|
const tableAnchor = live && !textAnchor ? tableMenuAnchor(live.state) : null;
|
|
281
331
|
const linkAtCursor = live && !live.view.composing && !isLinkPanelOpen(live.state) ? activeLinkSpan(live.state) : null;
|
|
282
332
|
const comments = live?.state === void 0 ? [] : commentProjection.read(live.state).comments;
|
|
283
|
-
const
|
|
333
|
+
const hasRailComments = comments.some(shownBesideThePage);
|
|
284
334
|
const composerOpen = live !== null && isCommentComposerOpen(live.state);
|
|
285
|
-
const showComments = live !== null && (commentsOpen || composerOpen ||
|
|
335
|
+
const showComments = live !== null && (commentsOpen || composerOpen || hasRailComments);
|
|
286
336
|
const commentsPanel = live && showComments && /* @__PURE__ */ jsx(
|
|
287
337
|
CommentsPanel,
|
|
288
338
|
{
|
|
@@ -299,11 +349,11 @@ function DocxEditorSurface({
|
|
|
299
349
|
className: [editorClassNames.frame, className].filter(Boolean).join(" "),
|
|
300
350
|
style,
|
|
301
351
|
children: [
|
|
302
|
-
live && toolbar && /* @__PURE__ */ jsx(
|
|
352
|
+
live && toolbar && surface.active && /* @__PURE__ */ jsx(
|
|
303
353
|
Toolbar,
|
|
304
354
|
{
|
|
305
|
-
|
|
306
|
-
|
|
355
|
+
main: live,
|
|
356
|
+
active: surface.active,
|
|
307
357
|
fontFallbacks: mountedFontFallbacks,
|
|
308
358
|
presets,
|
|
309
359
|
commentsOpen,
|
|
@@ -333,25 +383,31 @@ function DocxEditorSurface({
|
|
|
333
383
|
}
|
|
334
384
|
),
|
|
335
385
|
/* @__PURE__ */ jsxs("div", { ref: rootRef, className: editorClassNames.root, children: [
|
|
336
|
-
/* @__PURE__ */ jsxs(
|
|
337
|
-
"div",
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
386
|
+
/* @__PURE__ */ jsx("div", { ref: setPageBox, className: editorClassNames.pageBox, children: /* @__PURE__ */ jsxs("div", { ref: holdPageLayer, className: editorClassNames.pageLayer, children: [
|
|
387
|
+
/* @__PURE__ */ jsx("div", { ref: mountRef }),
|
|
388
|
+
overlay && /* @__PURE__ */ jsx(
|
|
389
|
+
PageGuides,
|
|
390
|
+
{
|
|
391
|
+
overlay,
|
|
392
|
+
headersFootersFor
|
|
393
|
+
}
|
|
394
|
+
),
|
|
395
|
+
/* @__PURE__ */ jsx(
|
|
396
|
+
NotesAroundPage,
|
|
397
|
+
{
|
|
398
|
+
notes,
|
|
399
|
+
overlay,
|
|
400
|
+
page,
|
|
401
|
+
zoom: effectiveZoom,
|
|
402
|
+
open: surface.open,
|
|
403
|
+
editing: surface.editing,
|
|
404
|
+
readOnly: surface.readOnly,
|
|
405
|
+
revision: live?.state,
|
|
406
|
+
onOpen: surface.onOpen,
|
|
407
|
+
onReturn: surface.onReturn
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
] }) }),
|
|
355
411
|
!commentsOpen && commentsPanel
|
|
356
412
|
] }),
|
|
357
413
|
commentsOpen && commentsPanel
|
|
@@ -368,21 +424,23 @@ function DocxEditorSurface({
|
|
|
368
424
|
},
|
|
369
425
|
linkAtCursor.from
|
|
370
426
|
),
|
|
371
|
-
live && textAnchor && /* @__PURE__ */ jsx(
|
|
427
|
+
live && textAnchor && surface.active && /* @__PURE__ */ jsx(
|
|
372
428
|
TextMenu,
|
|
373
429
|
{
|
|
374
430
|
view: live.view,
|
|
375
431
|
state: live.state,
|
|
376
432
|
anchor: textAnchor,
|
|
433
|
+
takes: surface.active.takes,
|
|
377
434
|
allowLocking: locking
|
|
378
435
|
}
|
|
379
436
|
),
|
|
380
|
-
live && tableAnchor && /* @__PURE__ */ jsx(
|
|
437
|
+
live && tableAnchor && surface.active && /* @__PURE__ */ jsx(
|
|
381
438
|
TableMenu,
|
|
382
439
|
{
|
|
383
440
|
view: live.view,
|
|
384
441
|
state: live.state,
|
|
385
442
|
anchor: tableAnchor,
|
|
443
|
+
takes: surface.active.takes,
|
|
386
444
|
allowLocking: locking
|
|
387
445
|
}
|
|
388
446
|
)
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* The body (document.xml) is always rebuilt from preserved and edited blocks. Every other part is
|
|
5
5
|
* written by a planner (`./partPlan`) that answers only when the document gives it something to
|
|
6
6
|
* write: numbering.xml when a list was newly started, the comment parts when comments changed,
|
|
7
|
-
*
|
|
7
|
+
* a header, a footer, or the Footnotes part when a story it holds changed, media parts when an
|
|
8
|
+
* image was inserted. Content types and relationships change only when one
|
|
8
9
|
* of those additions declares itself through the context every planner shares.
|
|
9
10
|
*
|
|
10
11
|
* The body is written before that relationships part, because a link asks for its relationship as
|
package/dist/docx/exportDocx.js
CHANGED
|
@@ -10,22 +10,20 @@ import {
|
|
|
10
10
|
W_NS,
|
|
11
11
|
withXmlParser
|
|
12
12
|
} from "../ooxml/xml.js";
|
|
13
|
-
import { commentsPlanner } from "./comments.js";
|
|
14
13
|
import { repackParts } from "./container.js";
|
|
15
14
|
import {
|
|
16
15
|
fidelityNotesOf
|
|
17
16
|
} from "./fidelity.js";
|
|
18
|
-
import { headerFooterPlanner } from "./headersFooters.js";
|
|
19
17
|
import { hyperlinkRefs } from "./hyperlink.js";
|
|
20
18
|
import { withUniqueIdentities } from "./identities.js";
|
|
21
19
|
import { problemsOf } from "./invariants.js";
|
|
22
20
|
import { NO_IMAGE_REFS, planImageMedia } from "./media.js";
|
|
23
|
-
import { numberingPlanner } from "./numberingPlanner.js";
|
|
24
21
|
import { CONTENT_TYPES_PATH, contentTypeWriter } from "./packageParts.js";
|
|
25
22
|
import {
|
|
26
23
|
assertPartsParse,
|
|
27
24
|
runPartPlanners
|
|
28
25
|
} from "./partPlan.js";
|
|
26
|
+
import { PART_PLANNERS } from "./partPlanners.js";
|
|
29
27
|
import {
|
|
30
28
|
readRelationships,
|
|
31
29
|
relationshipWriter,
|
|
@@ -105,11 +103,6 @@ function assertMainPart(documentXml, wroteLinks) {
|
|
|
105
103
|
}
|
|
106
104
|
}
|
|
107
105
|
var LINK_MARKUP = { namespaces: { r: R_NS } };
|
|
108
|
-
var PART_PLANNERS = [
|
|
109
|
-
numberingPlanner,
|
|
110
|
-
commentsPlanner,
|
|
111
|
-
headerFooterPlanner
|
|
112
|
-
];
|
|
113
106
|
function exportDocx(doc, session, options) {
|
|
114
107
|
return exportDocxReport(doc, session, options).bytes;
|
|
115
108
|
}
|
|
@@ -141,7 +134,8 @@ function writeDocx(doc, store, notes, planners) {
|
|
|
141
134
|
const relsPath = relsPathOf(store.mainPartPath);
|
|
142
135
|
const context = {
|
|
143
136
|
relationships: relationshipWriter(readRelationships(store.parts, relsPath)),
|
|
144
|
-
contentTypes: contentTypeWriter(store.parts)
|
|
137
|
+
contentTypes: contentTypeWriter(store.parts),
|
|
138
|
+
notes
|
|
145
139
|
};
|
|
146
140
|
const media = planImageMedia(doc, store, context);
|
|
147
141
|
const links = hyperlinkRefs(context.relationships);
|
|
@@ -7,10 +7,13 @@ import {
|
|
|
7
7
|
import { isOnElement } from "../ooxml/units.js";
|
|
8
8
|
import { decodeUtf8, encodeUtf8, parseXml, R_NS, W_NS } from "../ooxml/xml.js";
|
|
9
9
|
import { docxSchema } from "../schema/index.js";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
HEADER_FOOTER_KINDS,
|
|
12
|
+
storyKey
|
|
13
|
+
} from "../schema/stories.js";
|
|
12
14
|
import { NO_EXPORT_REFS } from "./exportRefs.js";
|
|
13
15
|
import { fieldSpans, isFieldCharacter } from "./fields.js";
|
|
16
|
+
import { withUniqueStoryIdentities } from "./identities.js";
|
|
14
17
|
import { relatedPartPath } from "./packageParts.js";
|
|
15
18
|
import { readRelationships, relsPathOf, resolveTarget } from "./relationships.js";
|
|
16
19
|
import {
|
|
@@ -21,12 +24,16 @@ import {
|
|
|
21
24
|
readStory,
|
|
22
25
|
storyLeafText
|
|
23
26
|
} from "./story.js";
|
|
27
|
+
import { storyChangesOf } from "./storyParts.js";
|
|
24
28
|
var EMPTY_VARIANTS = {
|
|
25
29
|
default: null,
|
|
26
30
|
first: null,
|
|
27
31
|
even: null
|
|
28
32
|
};
|
|
29
|
-
var PART_ROOT = {
|
|
33
|
+
var PART_ROOT = {
|
|
34
|
+
header: "hdr",
|
|
35
|
+
footer: "ftr"
|
|
36
|
+
};
|
|
30
37
|
function settingsEvenAndOdd(parts, mainPartPath) {
|
|
31
38
|
const path = relatedPartPath(parts, mainPartPath, `${R_NS}/settings`);
|
|
32
39
|
const bytes = path === null ? void 0 : parts.get(path);
|
|
@@ -36,9 +43,9 @@ function settingsEvenAndOdd(parts, mainPartPath) {
|
|
|
36
43
|
return isOnElement(setting);
|
|
37
44
|
}
|
|
38
45
|
function kindOf(relationshipType) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
return HEADER_FOOTER_KINDS.find(
|
|
47
|
+
(kind) => relationshipType === `${R_NS}/${kind}`
|
|
48
|
+
) ?? null;
|
|
42
49
|
}
|
|
43
50
|
function readHeaderFooterStories(parts, mainPartPath, referenced, depsFor) {
|
|
44
51
|
const keyByRelId = /* @__PURE__ */ new Map();
|
|
@@ -166,29 +173,34 @@ function headerFooterText(story, page, totalPages) {
|
|
|
166
173
|
return lines.join("\n");
|
|
167
174
|
}
|
|
168
175
|
var HEADER_MARKUP = { namespaces: { w: NAMESPACES.w } };
|
|
169
|
-
function
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
if (imported.kind !== "header" && imported.kind !== "footer") continue;
|
|
173
|
-
const current = storyNodeOf(doc, key);
|
|
174
|
-
if (current === null || sameSource(current, imported.doc)) continue;
|
|
175
|
-
const written = serializeStory(current, imported, imported, {
|
|
176
|
+
function writtenPart(imported, current, session, notes) {
|
|
177
|
+
const written = withUniqueStoryIdentities([{ story: current, frozen: false }]).map(
|
|
178
|
+
(story) => serializeStory(story, imported, imported, {
|
|
176
179
|
...NO_EXPORT_REFS,
|
|
180
|
+
notes,
|
|
177
181
|
session
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
|
|
182
|
+
})
|
|
183
|
+
).join("");
|
|
184
|
+
const hadBom = decodeUtf8(
|
|
185
|
+
session.parts.get(imported.partPath) ?? new Uint8Array()
|
|
186
|
+
).hadBom;
|
|
187
|
+
return encodeUtf8(ensureRootDeclarations(written, HEADER_MARKUP), hadBom);
|
|
188
|
+
}
|
|
189
|
+
function rewrittenParts(doc, session, notes) {
|
|
190
|
+
const edited = HEADER_FOOTER_KINDS.flatMap(
|
|
191
|
+
(kind) => storyChangesOf(doc, session, kind)
|
|
192
|
+
).flatMap((change) => change.change === "edited" ? [change] : []);
|
|
193
|
+
if (edited.length === 0) return null;
|
|
194
|
+
return new Map(
|
|
195
|
+
edited.map(({ imported, current }) => [
|
|
183
196
|
imported.partPath,
|
|
184
|
-
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
return parts.size === 0 ? null : parts;
|
|
197
|
+
writtenPart(imported, current, session, notes)
|
|
198
|
+
])
|
|
199
|
+
);
|
|
188
200
|
}
|
|
189
201
|
var headerFooterPlanner = {
|
|
190
202
|
name: "headers and footers",
|
|
191
|
-
plan: (doc, session) => rewrittenParts(doc, session)
|
|
203
|
+
plan: (doc, session, context) => rewrittenParts(doc, session, context.notes)
|
|
192
204
|
};
|
|
193
205
|
export {
|
|
194
206
|
displayPageNumber,
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
* and throws over a block that cannot yield, and `identityProblems` runs the same walk for
|
|
15
15
|
* `docx/invariants` and lists those blocks instead, so what the query reports and what the write
|
|
16
16
|
* refuses cannot come apart.
|
|
17
|
+
*
|
|
18
|
+
* A side story is settled by its part rather than by the document: `w14:paraId` is unique within a
|
|
19
|
+
* part (Part 1 §11.3), so `withUniqueStoryIdentities` walks the stories one part holds as one run
|
|
20
|
+
* of blocks, and a name the body or another part holds is not compared. A story the part writes as
|
|
21
|
+
* the bytes it arrived as keeps every name it holds, since no later claimant of one could give it
|
|
22
|
+
* up in bytes nothing rewrites.
|
|
17
23
|
*/
|
|
18
24
|
import { type Node as PMNode } from "prosemirror-model";
|
|
19
25
|
import { type DocxExportErrorCode } from "../ooxml/errors";
|
|
@@ -65,3 +71,25 @@ export declare function withUniqueIdentities(doc: PMNode, rules?: readonly Ident
|
|
|
65
71
|
* document is dropped, so a caller asking ahead of the write reads the same refusal it would throw.
|
|
66
72
|
*/
|
|
67
73
|
export declare function identityProblems(doc: PMNode, rules?: readonly IdentityRule[]): readonly IdentityProblem[];
|
|
74
|
+
/** A block of a side story that cannot yield */
|
|
75
|
+
export interface StoryIdentityProblem extends IdentityProblem {
|
|
76
|
+
/** The story's place in the list the part was handed over as; `pos` stands inside that story */
|
|
77
|
+
readonly story: number;
|
|
78
|
+
}
|
|
79
|
+
/** One story as its part hands it over to the pass */
|
|
80
|
+
export interface StoryToSettle {
|
|
81
|
+
readonly story: PMNode;
|
|
82
|
+
/**
|
|
83
|
+
* Whether the part writes this story as the bytes it arrived as. A frozen story cannot give a
|
|
84
|
+
* name up, since nothing rewrites what it goes out as, so it claims its names ahead of every
|
|
85
|
+
* story that can.
|
|
86
|
+
*/
|
|
87
|
+
readonly frozen: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The stories one part holds, in the order the part writes them, with every later claimant of a
|
|
91
|
+
* name released. A story holding no such claimant is handed back as the very same node.
|
|
92
|
+
*/
|
|
93
|
+
export declare function withUniqueStoryIdentities(entries: readonly StoryToSettle[], rules?: readonly IdentityRule[]): readonly PMNode[];
|
|
94
|
+
/** Every block `withUniqueStoryIdentities` would refuse over, in the order the part writes them */
|
|
95
|
+
export declare function identityProblemsInStories(entries: readonly StoryToSettle[], rules?: readonly IdentityRule[]): readonly StoryIdentityProblem[];
|
package/dist/docx/identities.js
CHANGED
|
@@ -130,12 +130,7 @@ function rewriteBlock(block, pos, walk) {
|
|
|
130
130
|
});
|
|
131
131
|
return changed ? visited.copy(Fragment.fromArray(children)) : visited;
|
|
132
132
|
}
|
|
133
|
-
function
|
|
134
|
-
const walk = {
|
|
135
|
-
rules,
|
|
136
|
-
written: rules.map(() => /* @__PURE__ */ new Set()),
|
|
137
|
-
refuse
|
|
138
|
-
};
|
|
133
|
+
function settle(doc, walk) {
|
|
139
134
|
const blocks = [];
|
|
140
135
|
let changed = false;
|
|
141
136
|
doc.forEach((block, offset) => {
|
|
@@ -145,21 +140,58 @@ function walkBlocks(doc, rules, refuse) {
|
|
|
145
140
|
});
|
|
146
141
|
return changed ? doc.copy(Fragment.fromArray(blocks)) : doc;
|
|
147
142
|
}
|
|
143
|
+
function unwritten(rules) {
|
|
144
|
+
return rules.map(() => /* @__PURE__ */ new Set());
|
|
145
|
+
}
|
|
146
|
+
function refuseExport(problem) {
|
|
147
|
+
throw new DocxExportError(problem.code, problem.message);
|
|
148
|
+
}
|
|
148
149
|
function withUniqueIdentities(doc, rules = IDENTITY_RULES) {
|
|
149
|
-
return
|
|
150
|
-
|
|
150
|
+
return settle(doc, {
|
|
151
|
+
rules,
|
|
152
|
+
written: unwritten(rules),
|
|
153
|
+
refuse: refuseExport
|
|
151
154
|
});
|
|
152
155
|
}
|
|
153
156
|
function identityProblems(doc, rules = IDENTITY_RULES) {
|
|
154
157
|
const problems = [];
|
|
155
|
-
|
|
158
|
+
settle(doc, {
|
|
159
|
+
rules,
|
|
160
|
+
written: unwritten(rules),
|
|
161
|
+
refuse: (problem) => problems.push(problem)
|
|
162
|
+
});
|
|
163
|
+
return problems;
|
|
164
|
+
}
|
|
165
|
+
var CLAIMS_ONLY = () => {
|
|
166
|
+
};
|
|
167
|
+
function settleStories(entries, rules, refuse) {
|
|
168
|
+
const written = unwritten(rules);
|
|
169
|
+
for (const { story, frozen } of entries) {
|
|
170
|
+
if (frozen) settle(story, { rules, written, refuse: CLAIMS_ONLY });
|
|
171
|
+
}
|
|
172
|
+
return entries.map(
|
|
173
|
+
({ story, frozen }, index) => frozen ? story : settle(story, {
|
|
174
|
+
rules,
|
|
175
|
+
written,
|
|
176
|
+
refuse: (problem) => refuse({ ...problem, story: index })
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function withUniqueStoryIdentities(entries, rules = IDENTITY_RULES) {
|
|
181
|
+
return settleStories(entries, rules, refuseExport);
|
|
182
|
+
}
|
|
183
|
+
function identityProblemsInStories(entries, rules = IDENTITY_RULES) {
|
|
184
|
+
const problems = [];
|
|
185
|
+
settleStories(entries, rules, (problem) => problems.push(problem));
|
|
156
186
|
return problems;
|
|
157
187
|
}
|
|
158
188
|
export {
|
|
159
189
|
IDENTITY_RULES,
|
|
160
190
|
controlRule,
|
|
161
191
|
identityProblems,
|
|
192
|
+
identityProblemsInStories,
|
|
162
193
|
paragraphIdRule,
|
|
163
194
|
sourceBlockRule,
|
|
164
|
-
withUniqueIdentities
|
|
195
|
+
withUniqueIdentities,
|
|
196
|
+
withUniqueStoryIdentities
|
|
165
197
|
};
|