@beyondwork/docx-react-component 1.0.17 → 1.0.19
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/README.md +8 -2
- package/package.json +32 -34
- package/src/api/README.md +5 -1
- package/src/api/public-types.ts +374 -4
- package/src/api/session-state.ts +58 -0
- package/src/core/commands/formatting-commands.ts +1 -0
- package/src/core/commands/image-commands.ts +147 -0
- package/src/core/commands/index.ts +5 -1
- package/src/core/commands/list-commands.ts +231 -36
- package/src/core/commands/paragraph-layout-commands.ts +339 -0
- package/src/core/commands/section-layout-commands.ts +680 -0
- package/src/core/commands/style-commands.ts +262 -0
- package/src/core/search/search-text.ts +329 -0
- package/src/core/selection/mapping.ts +41 -0
- package/src/core/state/editor-state.ts +1 -1
- package/src/index.ts +30 -0
- package/src/io/docx-session.ts +260 -39
- package/src/io/export/serialize-main-document.ts +202 -5
- package/src/io/export/serialize-numbering.ts +28 -7
- package/src/io/normalize/normalize-text.ts +63 -25
- package/src/io/ooxml/numbering-sentinels.ts +44 -0
- package/src/io/ooxml/parse-footnotes.ts +212 -20
- package/src/io/ooxml/parse-headers-footers.ts +229 -25
- package/src/io/ooxml/parse-inline-media.ts +16 -0
- package/src/io/ooxml/parse-main-document.ts +411 -6
- package/src/io/ooxml/parse-numbering.ts +7 -0
- package/src/io/ooxml/parse-settings.ts +184 -0
- package/src/io/ooxml/parse-shapes.ts +25 -0
- package/src/io/ooxml/parse-styles.ts +463 -0
- package/src/io/ooxml/parse-theme.ts +32 -0
- package/src/model/canonical-document.ts +133 -3
- package/src/model/cds-1.0.0.ts +13 -0
- package/src/model/snapshot.ts +2 -1
- package/src/runtime/document-layout.ts +332 -0
- package/src/runtime/document-navigation.ts +564 -0
- package/src/runtime/document-runtime.ts +265 -35
- package/src/runtime/document-search.ts +145 -0
- package/src/runtime/numbering-prefix.ts +47 -26
- package/src/runtime/page-layout-estimation.ts +212 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +1 -0
- package/src/runtime/session-capabilities.ts +2 -0
- package/src/runtime/story-context.ts +164 -0
- package/src/runtime/story-targeting.ts +162 -0
- package/src/runtime/surface-projection.ts +239 -12
- package/src/runtime/table-schema.ts +87 -5
- package/src/runtime/view-state.ts +459 -0
- package/src/ui/WordReviewEditor.tsx +1902 -312
- package/src/ui/browser-export.ts +52 -0
- package/src/ui/headless/preserve-editor-selection.ts +5 -0
- package/src/ui/headless/selection-helpers.ts +20 -0
- package/src/ui/headless/selection-toolbar-model.ts +22 -0
- package/src/ui/headless/use-editor-keyboard.ts +6 -1
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +386 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +125 -14
- package/src/ui-tailwind/editor-surface/perf-probe.ts +107 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +45 -6
- package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +2 -2
- package/src/ui-tailwind/editor-surface/pm-schema.ts +47 -5
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +95 -22
- package/src/ui-tailwind/editor-surface/search-plugin.ts +19 -68
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +11 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +394 -77
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +0 -1
- package/src/ui-tailwind/index.ts +2 -1
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +277 -147
- package/src/ui-tailwind/review/tw-review-rail.tsx +6 -6
- package/src/ui-tailwind/theme/editor-theme.css +123 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +291 -12
- package/src/ui-tailwind/tw-review-workspace.tsx +926 -27
- package/src/validation/compatibility-engine.ts +92 -20
- package/src/validation/diagnostics.ts +1 -0
- package/src/validation/docx-comment-proof.ts +487 -0
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
ThemeColorScheme,
|
|
3
3
|
ThemeDefinition,
|
|
4
4
|
ThemeFontScheme,
|
|
5
|
+
ResolvedTheme,
|
|
5
6
|
} from "../../model/canonical-document.ts";
|
|
6
7
|
|
|
7
8
|
// ---- XML node types (inline, no external dep) ----
|
|
@@ -85,6 +86,37 @@ export function parseThemeXml(xml: string): ThemeDefinition {
|
|
|
85
86
|
return result;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Resolve a ThemeDefinition into flattened runtime theme inputs.
|
|
91
|
+
* Maps OOXML theme slot names to CSS-usable color values and font families.
|
|
92
|
+
*/
|
|
93
|
+
export function resolveTheme(theme: ThemeDefinition): ResolvedTheme {
|
|
94
|
+
const colors: Record<string, string> = {};
|
|
95
|
+
|
|
96
|
+
if (theme.colorScheme?.colors) {
|
|
97
|
+
for (const [slot, value] of Object.entries(theme.colorScheme.colors)) {
|
|
98
|
+
colors[slot] = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
colors,
|
|
104
|
+
majorFont: theme.fontScheme?.majorFont,
|
|
105
|
+
minorFont: theme.fontScheme?.minorFont,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Resolve a theme color reference (e.g. "accent1", "dk1") to a CSS color string.
|
|
111
|
+
* Returns undefined if the theme does not contain the requested slot.
|
|
112
|
+
*/
|
|
113
|
+
export function resolveThemeColor(
|
|
114
|
+
theme: ResolvedTheme | undefined,
|
|
115
|
+
colorSlot: string,
|
|
116
|
+
): string | undefined {
|
|
117
|
+
return theme?.colors[colorSlot];
|
|
118
|
+
}
|
|
119
|
+
|
|
88
120
|
// ---- Internal helpers ----
|
|
89
121
|
|
|
90
122
|
function parseColorScheme(
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
expectExactString,
|
|
9
9
|
expectIso8601UtcTimestamp,
|
|
10
10
|
expectString,
|
|
11
|
+
expectStringAllowEmpty,
|
|
11
12
|
expectUuid,
|
|
12
13
|
stableStringify,
|
|
13
14
|
} from "./cds-1.0.0.ts";
|
|
@@ -79,12 +80,14 @@ export interface StylesCatalog {
|
|
|
79
80
|
characters: Record<string, CharacterStyleDefinition>;
|
|
80
81
|
tables: Record<string, TableStyleDefinition>;
|
|
81
82
|
latentStyles?: Record<string, LatentStyleDefinition>;
|
|
83
|
+
fromPackage?: boolean;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
export interface ParagraphStyleDefinition {
|
|
85
87
|
styleId: string;
|
|
86
88
|
basedOn?: string;
|
|
87
89
|
nextStyle?: string;
|
|
90
|
+
outlineLevel?: number;
|
|
88
91
|
displayName: string;
|
|
89
92
|
kind: "paragraph";
|
|
90
93
|
isDefault: boolean;
|
|
@@ -131,6 +134,8 @@ export interface NumberingLevelDefinition {
|
|
|
131
134
|
text: string;
|
|
132
135
|
startAt?: number;
|
|
133
136
|
paragraphStyleId?: string;
|
|
137
|
+
isLegalNumbering?: boolean;
|
|
138
|
+
suffix?: "tab" | "space" | "nothing";
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
export interface NumberingInstance {
|
|
@@ -155,6 +160,9 @@ export interface MediaItem {
|
|
|
155
160
|
relationshipId?: string;
|
|
156
161
|
packagePartName: string;
|
|
157
162
|
altText?: string;
|
|
163
|
+
display?: "inline" | "floating";
|
|
164
|
+
widthEmu?: number;
|
|
165
|
+
heightEmu?: number;
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
// ---- Sub-part canonical types ----
|
|
@@ -166,6 +174,7 @@ export interface HeaderDocument {
|
|
|
166
174
|
partPath: string;
|
|
167
175
|
relationshipId: string;
|
|
168
176
|
blocks: BlockNode[];
|
|
177
|
+
sectionIndex?: number;
|
|
169
178
|
}
|
|
170
179
|
|
|
171
180
|
export interface FooterDocument {
|
|
@@ -173,6 +182,7 @@ export interface FooterDocument {
|
|
|
173
182
|
partPath: string;
|
|
174
183
|
relationshipId: string;
|
|
175
184
|
blocks: BlockNode[];
|
|
185
|
+
sectionIndex?: number;
|
|
176
186
|
}
|
|
177
187
|
|
|
178
188
|
export interface FootnoteDefinition {
|
|
@@ -203,11 +213,25 @@ export interface ThemeDefinition {
|
|
|
203
213
|
fontScheme?: ThemeFontScheme;
|
|
204
214
|
}
|
|
205
215
|
|
|
216
|
+
export interface DocumentSettings {
|
|
217
|
+
evenAndOddHeaders?: boolean;
|
|
218
|
+
zoomLevel?: "pageWidth" | "onePage" | number;
|
|
219
|
+
}
|
|
220
|
+
|
|
206
221
|
export interface SubPartsCatalog {
|
|
207
222
|
headers: HeaderDocument[];
|
|
208
223
|
footers: FooterDocument[];
|
|
209
224
|
footnoteCollection?: FootnoteCollection;
|
|
210
225
|
theme?: ThemeDefinition;
|
|
226
|
+
finalSectionProperties?: SectionProperties;
|
|
227
|
+
resolvedTheme?: ResolvedTheme;
|
|
228
|
+
settings?: DocumentSettings;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface ResolvedTheme {
|
|
232
|
+
colors: Record<string, string>;
|
|
233
|
+
majorFont?: string;
|
|
234
|
+
minorFont?: string;
|
|
211
235
|
}
|
|
212
236
|
|
|
213
237
|
// ---- Inline footnote reference node ----
|
|
@@ -407,6 +431,23 @@ export interface TableCellNode {
|
|
|
407
431
|
verticalAlign?: "top" | "center" | "bottom";
|
|
408
432
|
}
|
|
409
433
|
|
|
434
|
+
export interface SdtCheckboxState {
|
|
435
|
+
checked: boolean;
|
|
436
|
+
checkedChar?: string;
|
|
437
|
+
uncheckedChar?: string;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export interface SdtDatePickerState {
|
|
441
|
+
fullDate?: string;
|
|
442
|
+
dateFormat?: string;
|
|
443
|
+
lid?: string;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export interface SdtDropdownListItem {
|
|
447
|
+
displayText?: string;
|
|
448
|
+
value: string;
|
|
449
|
+
}
|
|
450
|
+
|
|
410
451
|
export interface SdtNode {
|
|
411
452
|
type: "sdt";
|
|
412
453
|
properties: {
|
|
@@ -415,6 +456,11 @@ export interface SdtNode {
|
|
|
415
456
|
tag?: string;
|
|
416
457
|
lock?: string;
|
|
417
458
|
propertiesXml?: string;
|
|
459
|
+
checkbox?: SdtCheckboxState;
|
|
460
|
+
datePicker?: SdtDatePickerState;
|
|
461
|
+
dropdownList?: SdtDropdownListItem[];
|
|
462
|
+
comboBox?: SdtDropdownListItem[];
|
|
463
|
+
showingPlcHdr?: boolean;
|
|
418
464
|
};
|
|
419
465
|
children: BlockNode[];
|
|
420
466
|
}
|
|
@@ -451,7 +497,86 @@ export interface BookmarkEndNode {
|
|
|
451
497
|
|
|
452
498
|
export interface SectionBreakNode {
|
|
453
499
|
type: "section_break";
|
|
500
|
+
sectionPropertiesXml?: string;
|
|
501
|
+
/**
|
|
502
|
+
* @deprecated Legacy field from older snapshots. New exports should use
|
|
503
|
+
* sectionPropertiesXml and only contain raw <w:sectPr> content.
|
|
504
|
+
*/
|
|
454
505
|
propertiesXml?: string;
|
|
506
|
+
sectionProperties?: SectionProperties;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export interface SectionProperties {
|
|
510
|
+
pageSize?: PageSize;
|
|
511
|
+
pageMargins?: PageMargins;
|
|
512
|
+
columns?: ColumnProperties;
|
|
513
|
+
pageNumbering?: PageNumbering;
|
|
514
|
+
lineNumbering?: SectionLineNumbering;
|
|
515
|
+
pageBorders?: SectionPageBorders;
|
|
516
|
+
documentGrid?: SectionDocumentGrid;
|
|
517
|
+
headerReferences?: HeaderFooterReference[];
|
|
518
|
+
footerReferences?: HeaderFooterReference[];
|
|
519
|
+
sectionType?: "continuous" | "nextPage" | "evenPage" | "oddPage" | "nextColumn";
|
|
520
|
+
titlePage?: boolean;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export interface PageSize {
|
|
524
|
+
width: number;
|
|
525
|
+
height: number;
|
|
526
|
+
orientation?: "portrait" | "landscape";
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export interface PageMargins {
|
|
530
|
+
top: number;
|
|
531
|
+
right: number;
|
|
532
|
+
bottom: number;
|
|
533
|
+
left: number;
|
|
534
|
+
header?: number;
|
|
535
|
+
footer?: number;
|
|
536
|
+
gutter?: number;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface ColumnProperties {
|
|
540
|
+
count?: number;
|
|
541
|
+
space?: number;
|
|
542
|
+
equalWidth?: boolean;
|
|
543
|
+
columns?: Array<{ width: number; space?: number }>;
|
|
544
|
+
separator?: boolean;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export interface PageNumbering {
|
|
548
|
+
format?: string;
|
|
549
|
+
start?: number;
|
|
550
|
+
chapStyle?: string;
|
|
551
|
+
chapSep?: string;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export interface SectionLineNumbering {
|
|
555
|
+
countBy?: number;
|
|
556
|
+
start?: number;
|
|
557
|
+
distance?: number;
|
|
558
|
+
restart?: "newPage" | "newSection" | "continuous";
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export interface SectionPageBorders {
|
|
562
|
+
top?: BorderSpec;
|
|
563
|
+
left?: BorderSpec;
|
|
564
|
+
bottom?: BorderSpec;
|
|
565
|
+
right?: BorderSpec;
|
|
566
|
+
offsetFrom?: "page" | "text";
|
|
567
|
+
display?: "allPages" | "firstPage" | "notFirstPage";
|
|
568
|
+
zOrder?: "front" | "back";
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export interface SectionDocumentGrid {
|
|
572
|
+
type?: "default" | "lines" | "linesAndChars" | "snapToChars";
|
|
573
|
+
linePitch?: number;
|
|
574
|
+
charSpace?: number;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export interface HeaderFooterReference {
|
|
578
|
+
variant: HeaderFooterVariant;
|
|
579
|
+
relationshipId: string;
|
|
455
580
|
}
|
|
456
581
|
|
|
457
582
|
export type InlineNode =
|
|
@@ -587,6 +712,7 @@ export interface ShapeNode {
|
|
|
587
712
|
type: "shape";
|
|
588
713
|
text?: string;
|
|
589
714
|
geometry?: string;
|
|
715
|
+
isTextBox?: boolean;
|
|
590
716
|
rawXml: string;
|
|
591
717
|
}
|
|
592
718
|
|
|
@@ -781,7 +907,7 @@ export interface DiagnosticErrorEntry {
|
|
|
781
907
|
| "internal_invariant";
|
|
782
908
|
message: string;
|
|
783
909
|
isFatal: boolean;
|
|
784
|
-
source: "import" | "runtime" | "validation" | "datastore" | "export";
|
|
910
|
+
source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
|
|
785
911
|
details?: unknown;
|
|
786
912
|
}
|
|
787
913
|
|
|
@@ -1343,7 +1469,11 @@ function validateReviewStore(
|
|
|
1343
1469
|
);
|
|
1344
1470
|
}
|
|
1345
1471
|
if (threadRecord.body !== undefined) {
|
|
1346
|
-
|
|
1472
|
+
expectStringAllowEmpty(
|
|
1473
|
+
threadRecord.body,
|
|
1474
|
+
`${path}.comments.${commentId}.body`,
|
|
1475
|
+
issues,
|
|
1476
|
+
);
|
|
1347
1477
|
}
|
|
1348
1478
|
if (!Array.isArray(threadRecord.warningIds)) {
|
|
1349
1479
|
issues.push({
|
|
@@ -1489,7 +1619,7 @@ function validateCommentEntries(
|
|
|
1489
1619
|
}
|
|
1490
1620
|
expectString(record.entryId, `${path}[${index}].entryId`, issues);
|
|
1491
1621
|
expectString(record.authorId, `${path}[${index}].authorId`, issues);
|
|
1492
|
-
|
|
1622
|
+
expectStringAllowEmpty(record.body, `${path}[${index}].body`, issues);
|
|
1493
1623
|
expectIso8601UtcTimestamp(record.createdAt, `${path}[${index}].createdAt`, issues);
|
|
1494
1624
|
if (record.metadata !== undefined) {
|
|
1495
1625
|
validateCommentEntryMetadata(record.metadata, `${path}[${index}].metadata`, issues);
|
package/src/model/cds-1.0.0.ts
CHANGED
|
@@ -98,6 +98,19 @@ export function expectString(
|
|
|
98
98
|
return value;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
export function expectStringAllowEmpty(
|
|
102
|
+
value: unknown,
|
|
103
|
+
path: string,
|
|
104
|
+
issues: ModelValidationIssue[],
|
|
105
|
+
): string | null {
|
|
106
|
+
if (typeof value !== "string") {
|
|
107
|
+
issues.push({ path, message: "Expected a string." });
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
|
|
101
114
|
export function expectExactString<T extends string>(
|
|
102
115
|
value: unknown,
|
|
103
116
|
expected: T,
|
package/src/model/snapshot.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface EditorError {
|
|
|
62
62
|
code: EditorErrorCode;
|
|
63
63
|
message: string;
|
|
64
64
|
isFatal: boolean;
|
|
65
|
-
source: "import" | "runtime" | "validation" | "datastore" | "export";
|
|
65
|
+
source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
|
|
66
66
|
details?: Record<string, unknown>;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -174,6 +174,7 @@ const EDITOR_ERROR_SOURCES = new Set<EditorError["source"]>([
|
|
|
174
174
|
"runtime",
|
|
175
175
|
"validation",
|
|
176
176
|
"datastore",
|
|
177
|
+
"host",
|
|
177
178
|
"export",
|
|
178
179
|
]);
|
|
179
180
|
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EditorStoryTarget,
|
|
3
|
+
PageLayoutSnapshot,
|
|
4
|
+
} from "../api/public-types";
|
|
5
|
+
import { MAIN_STORY_TARGET } from "../core/selection/mapping.ts";
|
|
6
|
+
import {
|
|
7
|
+
createSelectionSnapshot,
|
|
8
|
+
type CanonicalDocumentEnvelope,
|
|
9
|
+
type EditorState,
|
|
10
|
+
} from "../core/state/editor-state.ts";
|
|
11
|
+
import type {
|
|
12
|
+
FooterDocument,
|
|
13
|
+
HeaderDocument,
|
|
14
|
+
SectionProperties,
|
|
15
|
+
SubPartsCatalog,
|
|
16
|
+
} from "../model/canonical-document.ts";
|
|
17
|
+
import { createEditorSurfaceSnapshot } from "./surface-projection.ts";
|
|
18
|
+
import {
|
|
19
|
+
resolveSectionVariants,
|
|
20
|
+
sectionSupportsStoryTarget,
|
|
21
|
+
} from "./story-context.ts";
|
|
22
|
+
import { storyTargetKey } from "./story-targeting.ts";
|
|
23
|
+
|
|
24
|
+
export interface ResolvedDocumentSection {
|
|
25
|
+
index: number;
|
|
26
|
+
start: number;
|
|
27
|
+
end: number;
|
|
28
|
+
properties?: SectionProperties;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function buildResolvedSections(
|
|
32
|
+
document: CanonicalDocumentEnvelope,
|
|
33
|
+
): ResolvedDocumentSection[] {
|
|
34
|
+
const mainSurface = createEditorSurfaceSnapshot(
|
|
35
|
+
document,
|
|
36
|
+
createSelectionSnapshot(0, 0),
|
|
37
|
+
MAIN_STORY_TARGET,
|
|
38
|
+
);
|
|
39
|
+
const sections: ResolvedDocumentSection[] = [];
|
|
40
|
+
let sectionStart = 0;
|
|
41
|
+
let sectionIndex = 0;
|
|
42
|
+
|
|
43
|
+
for (const [index, block] of document.content.children.entries()) {
|
|
44
|
+
if (block.type !== "section_break") {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const surfaceBlock = mainSurface.blocks[index];
|
|
49
|
+
sections.push({
|
|
50
|
+
index: sectionIndex,
|
|
51
|
+
start: sectionStart,
|
|
52
|
+
end: surfaceBlock?.from ?? sectionStart,
|
|
53
|
+
properties: block.sectionProperties,
|
|
54
|
+
});
|
|
55
|
+
sectionStart = surfaceBlock?.to ?? sectionStart;
|
|
56
|
+
sectionIndex += 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
sections.push({
|
|
60
|
+
index: sectionIndex,
|
|
61
|
+
start: sectionStart,
|
|
62
|
+
end: mainSurface.storySize,
|
|
63
|
+
properties: document.subParts?.finalSectionProperties,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return sections;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function findSectionForPosition(
|
|
70
|
+
sections: ReadonlyArray<ResolvedDocumentSection>,
|
|
71
|
+
position: number,
|
|
72
|
+
): ResolvedDocumentSection {
|
|
73
|
+
for (const section of sections) {
|
|
74
|
+
if (position < section.end) {
|
|
75
|
+
return section;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return sections[sections.length - 1] ?? {
|
|
80
|
+
index: 0,
|
|
81
|
+
start: 0,
|
|
82
|
+
end: 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function buildPageLayoutSnapshot(
|
|
87
|
+
sectionIndex: number,
|
|
88
|
+
properties: SectionProperties | undefined,
|
|
89
|
+
subParts: SubPartsCatalog | undefined,
|
|
90
|
+
): PageLayoutSnapshot {
|
|
91
|
+
const pageSize = properties?.pageSize ?? {
|
|
92
|
+
width: 12240,
|
|
93
|
+
height: 15840,
|
|
94
|
+
orientation: "portrait" as const,
|
|
95
|
+
};
|
|
96
|
+
const margins = properties?.pageMargins ?? {
|
|
97
|
+
top: 1440,
|
|
98
|
+
right: 1440,
|
|
99
|
+
bottom: 1440,
|
|
100
|
+
left: 1440,
|
|
101
|
+
header: 720,
|
|
102
|
+
footer: 720,
|
|
103
|
+
gutter: 0,
|
|
104
|
+
};
|
|
105
|
+
const columns = properties?.columns;
|
|
106
|
+
const explicitColumns = columns?.columns ?? [];
|
|
107
|
+
const differentOddEvenPages = Boolean(subParts?.settings?.evenAndOddHeaders);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
sectionIndex,
|
|
111
|
+
...(properties?.sectionType ? { sectionType: properties.sectionType } : {}),
|
|
112
|
+
pageWidth: pageSize.width,
|
|
113
|
+
pageHeight: pageSize.height,
|
|
114
|
+
marginTop: margins.top,
|
|
115
|
+
marginBottom: margins.bottom,
|
|
116
|
+
marginLeft: margins.left,
|
|
117
|
+
marginRight: margins.right,
|
|
118
|
+
headerMargin: margins.header ?? 720,
|
|
119
|
+
footerMargin: margins.footer ?? 720,
|
|
120
|
+
gutter: margins.gutter ?? 0,
|
|
121
|
+
orientation: pageSize.orientation ?? "portrait",
|
|
122
|
+
columns:
|
|
123
|
+
explicitColumns.length > 0 ? explicitColumns.length : (columns?.count ?? 1),
|
|
124
|
+
differentFirstPage: Boolean(properties?.titlePage),
|
|
125
|
+
differentOddEvenPages,
|
|
126
|
+
...(properties?.pageNumbering
|
|
127
|
+
? {
|
|
128
|
+
pageNumbering: {
|
|
129
|
+
...(properties.pageNumbering.format
|
|
130
|
+
? { format: properties.pageNumbering.format }
|
|
131
|
+
: {}),
|
|
132
|
+
...(properties.pageNumbering.start !== undefined
|
|
133
|
+
? { start: properties.pageNumbering.start }
|
|
134
|
+
: {}),
|
|
135
|
+
...(properties.pageNumbering.chapStyle
|
|
136
|
+
? { chapterStyle: properties.pageNumbering.chapStyle }
|
|
137
|
+
: {}),
|
|
138
|
+
...(properties.pageNumbering.chapSep
|
|
139
|
+
? { chapterSeparator: properties.pageNumbering.chapSep }
|
|
140
|
+
: {}),
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
: {}),
|
|
144
|
+
...(properties?.lineNumbering
|
|
145
|
+
? {
|
|
146
|
+
lineNumbering: {
|
|
147
|
+
...(properties.lineNumbering.countBy !== undefined
|
|
148
|
+
? { countBy: properties.lineNumbering.countBy }
|
|
149
|
+
: {}),
|
|
150
|
+
...(properties.lineNumbering.start !== undefined
|
|
151
|
+
? { start: properties.lineNumbering.start }
|
|
152
|
+
: {}),
|
|
153
|
+
...(properties.lineNumbering.distance !== undefined
|
|
154
|
+
? { distance: properties.lineNumbering.distance }
|
|
155
|
+
: {}),
|
|
156
|
+
...(properties.lineNumbering.restart
|
|
157
|
+
? { restart: properties.lineNumbering.restart }
|
|
158
|
+
: {}),
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
: {}),
|
|
162
|
+
...(properties?.pageBorders
|
|
163
|
+
? {
|
|
164
|
+
pageBorders: {
|
|
165
|
+
...(properties.pageBorders.top
|
|
166
|
+
? { top: { ...properties.pageBorders.top } }
|
|
167
|
+
: {}),
|
|
168
|
+
...(properties.pageBorders.left
|
|
169
|
+
? { left: { ...properties.pageBorders.left } }
|
|
170
|
+
: {}),
|
|
171
|
+
...(properties.pageBorders.bottom
|
|
172
|
+
? { bottom: { ...properties.pageBorders.bottom } }
|
|
173
|
+
: {}),
|
|
174
|
+
...(properties.pageBorders.right
|
|
175
|
+
? { right: { ...properties.pageBorders.right } }
|
|
176
|
+
: {}),
|
|
177
|
+
...(properties.pageBorders.offsetFrom
|
|
178
|
+
? { offsetFrom: properties.pageBorders.offsetFrom }
|
|
179
|
+
: {}),
|
|
180
|
+
...(properties.pageBorders.display
|
|
181
|
+
? { display: properties.pageBorders.display }
|
|
182
|
+
: {}),
|
|
183
|
+
...(properties.pageBorders.zOrder
|
|
184
|
+
? { zOrder: properties.pageBorders.zOrder }
|
|
185
|
+
: {}),
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
: {}),
|
|
189
|
+
...(properties?.documentGrid
|
|
190
|
+
? {
|
|
191
|
+
documentGrid: {
|
|
192
|
+
...(properties.documentGrid.type
|
|
193
|
+
? { type: properties.documentGrid.type }
|
|
194
|
+
: {}),
|
|
195
|
+
...(properties.documentGrid.linePitch !== undefined
|
|
196
|
+
? { linePitch: properties.documentGrid.linePitch }
|
|
197
|
+
: {}),
|
|
198
|
+
...(properties.documentGrid.charSpace !== undefined
|
|
199
|
+
? { charSpace: properties.documentGrid.charSpace }
|
|
200
|
+
: {}),
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
: {}),
|
|
204
|
+
columnDefinitions: explicitColumns,
|
|
205
|
+
equalWidthColumns:
|
|
206
|
+
columns?.equalWidth ??
|
|
207
|
+
(explicitColumns.length === 0 || explicitColumns.length <= 1),
|
|
208
|
+
columnSeparator: Boolean(columns?.separator),
|
|
209
|
+
headerVariants: resolveSectionVariants(
|
|
210
|
+
"header",
|
|
211
|
+
sectionIndex,
|
|
212
|
+
properties?.headerReferences,
|
|
213
|
+
subParts?.headers ?? [],
|
|
214
|
+
),
|
|
215
|
+
footerVariants: resolveSectionVariants(
|
|
216
|
+
"footer",
|
|
217
|
+
sectionIndex,
|
|
218
|
+
properties?.footerReferences,
|
|
219
|
+
subParts?.footers ?? [],
|
|
220
|
+
),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function resolveSectionForStoryTarget(
|
|
225
|
+
document: CanonicalDocumentEnvelope,
|
|
226
|
+
sections: ReadonlyArray<ResolvedDocumentSection>,
|
|
227
|
+
target: EditorStoryTarget,
|
|
228
|
+
): ResolvedDocumentSection | undefined {
|
|
229
|
+
if (target.kind === "main" || sections.length === 0) {
|
|
230
|
+
return sections[0];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (target.kind === "header") {
|
|
234
|
+
if (target.sectionIndex !== undefined) {
|
|
235
|
+
const section = sections.find((candidate) => candidate.index === target.sectionIndex);
|
|
236
|
+
return section &&
|
|
237
|
+
sectionSupportsStoryTarget(document, target.sectionIndex, target)
|
|
238
|
+
? section
|
|
239
|
+
: undefined;
|
|
240
|
+
}
|
|
241
|
+
return (
|
|
242
|
+
findSectionByStoryReference(
|
|
243
|
+
document,
|
|
244
|
+
sections,
|
|
245
|
+
target,
|
|
246
|
+
"header",
|
|
247
|
+
) ?? sections[0]
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (target.kind === "footer") {
|
|
252
|
+
if (target.sectionIndex !== undefined) {
|
|
253
|
+
const section = sections.find((candidate) => candidate.index === target.sectionIndex);
|
|
254
|
+
return section &&
|
|
255
|
+
sectionSupportsStoryTarget(document, target.sectionIndex, target)
|
|
256
|
+
? section
|
|
257
|
+
: undefined;
|
|
258
|
+
}
|
|
259
|
+
return (
|
|
260
|
+
findSectionByStoryReference(
|
|
261
|
+
document,
|
|
262
|
+
sections,
|
|
263
|
+
target,
|
|
264
|
+
"footer",
|
|
265
|
+
) ?? sections[0]
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function resolveActiveSection(
|
|
273
|
+
state: EditorState,
|
|
274
|
+
activeStory: EditorStoryTarget,
|
|
275
|
+
sections: ReadonlyArray<ResolvedDocumentSection>,
|
|
276
|
+
storySelections?: ReadonlyMap<string, EditorState["selection"]>,
|
|
277
|
+
): ResolvedDocumentSection | undefined {
|
|
278
|
+
if (sections.length === 0) {
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (activeStory.kind === "main") {
|
|
283
|
+
return findSectionForPosition(sections, state.selection.head);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const referencedSection = resolveSectionForStoryTarget(
|
|
287
|
+
state.document,
|
|
288
|
+
sections,
|
|
289
|
+
activeStory,
|
|
290
|
+
);
|
|
291
|
+
if (referencedSection) {
|
|
292
|
+
return referencedSection;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const mainSelection =
|
|
296
|
+
storySelections?.get(storyTargetKey(MAIN_STORY_TARGET)) ?? state.selection;
|
|
297
|
+
return findSectionForPosition(sections, mainSelection.head);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function findSectionByStoryReference(
|
|
301
|
+
document: CanonicalDocumentEnvelope,
|
|
302
|
+
sections: ReadonlyArray<ResolvedDocumentSection>,
|
|
303
|
+
target:
|
|
304
|
+
| Extract<EditorStoryTarget, { kind: "header" }>
|
|
305
|
+
| Extract<EditorStoryTarget, { kind: "footer" }>,
|
|
306
|
+
kind: "header" | "footer",
|
|
307
|
+
): ResolvedDocumentSection | undefined {
|
|
308
|
+
const propertyKey =
|
|
309
|
+
kind === "header" ? "headerReferences" : "footerReferences";
|
|
310
|
+
const documents =
|
|
311
|
+
kind === "header"
|
|
312
|
+
? document.subParts?.headers ?? []
|
|
313
|
+
: document.subParts?.footers ?? [];
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
sections.find((section) =>
|
|
317
|
+
section.properties?.[propertyKey]?.some(
|
|
318
|
+
(ref) =>
|
|
319
|
+
ref.relationshipId === target.relationshipId &&
|
|
320
|
+
ref.variant === target.variant,
|
|
321
|
+
),
|
|
322
|
+
) ??
|
|
323
|
+
sections.find((section) =>
|
|
324
|
+
documents.some(
|
|
325
|
+
(entry) =>
|
|
326
|
+
entry.relationshipId === target.relationshipId &&
|
|
327
|
+
entry.variant === target.variant &&
|
|
328
|
+
entry.sectionIndex === section.index,
|
|
329
|
+
),
|
|
330
|
+
)
|
|
331
|
+
);
|
|
332
|
+
}
|