@portone/docx-editor 0.2.1 → 0.3.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/CHANGELOG.md +109 -0
- package/CONTRIBUTING.md +5 -1
- package/dist/DocxEditor.d.ts +6 -0
- package/dist/DocxEditor.js +12 -29
- package/dist/core.d.ts +23 -8
- package/dist/core.js +9 -4
- package/dist/docx/cloning.d.ts +38 -0
- package/dist/docx/cloning.js +74 -0
- package/dist/docx/commentOnlyChange.d.ts +12 -7
- package/dist/docx/commentOnlyChange.js +9 -156
- package/dist/docx/comments/constants.d.ts +0 -1
- package/dist/docx/comments/constants.js +0 -2
- package/dist/docx/comments/grammar.d.ts +10 -4
- package/dist/docx/comments/grammar.js +12 -2
- package/dist/docx/comments/{verifying.d.ts → parts.d.ts} +26 -18
- package/dist/docx/comments/parts.js +279 -0
- package/dist/docx/comments/people.d.ts +11 -2
- package/dist/docx/comments/people.js +16 -92
- package/dist/docx/comments/policy.d.ts +7 -0
- package/dist/docx/comments/policy.js +43 -0
- package/dist/docx/comments/reading.js +8 -10
- package/dist/docx/comments/writing.d.ts +19 -7
- package/dist/docx/comments/writing.js +52 -111
- package/dist/docx/documentSettings.d.ts +7 -0
- package/dist/docx/documentSettings.js +10 -2
- package/dist/docx/exportDocx.d.ts +40 -5
- package/dist/docx/exportDocx.js +69 -71
- package/dist/docx/exportRefs.d.ts +5 -2
- package/dist/docx/exportRefs.js +3 -1
- package/dist/docx/fidelity.d.ts +43 -0
- package/dist/docx/fidelity.js +64 -0
- package/dist/docx/formatting/attrs.d.ts +27 -0
- package/dist/docx/formatting/attrs.js +31 -0
- package/dist/docx/formatting/context.d.ts +31 -0
- package/dist/docx/formatting/context.js +42 -0
- package/dist/docx/formatting/direct.d.ts +6 -5
- package/dist/docx/formatting/direct.js +52 -78
- package/dist/docx/formatting/resolve.d.ts +45 -0
- package/dist/docx/formatting/resolve.js +140 -0
- package/dist/docx/formatting/runProperties.d.ts +93 -0
- package/dist/docx/formatting/runProperties.js +316 -0
- package/dist/docx/formatting/styles.js +3 -3
- package/dist/docx/formatting/tabStops.js +7 -22
- package/dist/docx/formatting.d.ts +4 -1
- package/dist/docx/formatting.js +4 -1
- package/dist/docx/headersFooters.js +6 -13
- package/dist/docx/identities.d.ts +67 -0
- package/dist/docx/identities.js +174 -0
- package/dist/docx/importDocx.d.ts +12 -1
- package/dist/docx/importDocx.js +72 -79
- package/dist/docx/importParagraph.d.ts +1 -1
- package/dist/docx/importParagraph.js +4 -3
- package/dist/docx/importTable.d.ts +1 -1
- package/dist/docx/importTable.js +17 -1
- package/dist/docx/invariants.d.ts +33 -0
- package/dist/docx/invariants.js +256 -0
- package/dist/docx/media.d.ts +6 -4
- package/dist/docx/media.js +6 -37
- package/dist/docx/newLists.d.ts +20 -0
- package/dist/docx/newLists.js +36 -0
- package/dist/docx/notes.js +3 -7
- package/dist/docx/numberingPlanner.d.ts +8 -0
- package/dist/docx/numberingPlanner.js +19 -0
- package/dist/docx/packageParts.d.ts +42 -0
- package/dist/docx/packageParts.js +135 -0
- package/dist/docx/pageGeometry.d.ts +2 -0
- package/dist/docx/pageGeometry.js +18 -9
- package/dist/docx/paraProps.d.ts +10 -22
- package/dist/docx/paraProps.js +47 -76
- package/dist/docx/partPlan.d.ts +36 -0
- package/dist/docx/partPlan.js +59 -0
- package/dist/docx/protectionPolicy.d.ts +127 -0
- package/dist/docx/protectionPolicy.js +169 -0
- package/dist/docx/relationships.d.ts +1 -1
- package/dist/docx/relationships.js +8 -13
- package/dist/docx/runProps.d.ts +9 -22
- package/dist/docx/runProps.js +15 -168
- package/dist/docx/scan.js +20 -52
- package/dist/docx/sdt.js +9 -34
- package/dist/docx/sdtProps.d.ts +8 -1
- package/dist/docx/sdtProps.js +10 -0
- package/dist/docx/serializeBlock.d.ts +2 -0
- package/dist/docx/serializeBlock.js +8 -5
- package/dist/docx/serializeTable.js +32 -15
- package/dist/docx/session.d.ts +42 -14
- package/dist/docx/session.js +43 -17
- package/dist/docx/tableFormatting/editing.js +108 -139
- package/dist/docx/tableFormatting/reading.d.ts +16 -6
- package/dist/docx/tableFormatting/reading.js +40 -20
- package/dist/docx/tableTemplate.js +18 -7
- package/dist/download.d.ts +8 -5
- package/dist/download.js +2 -0
- package/dist/editor/clipboard/inlineFormatting.js +19 -30
- package/dist/editor/commands/comments/editing.d.ts +6 -2
- package/dist/editor/commands/comments/editing.js +19 -31
- package/dist/editor/commands/exportQueries.d.ts +15 -0
- package/dist/editor/commands/exportQueries.js +14 -0
- package/dist/editor/commands/fidelityQueries.d.ts +12 -0
- package/dist/editor/commands/fidelityQueries.js +8 -0
- package/dist/editor/commands/formatting/editing.d.ts +2 -2
- package/dist/editor/commands/formatting/editing.js +26 -108
- package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
- package/dist/editor/commands/formatting/propertyCommands.js +103 -0
- package/dist/editor/commands/formatting/shared.d.ts +3 -3
- package/dist/editor/commands/formatting/shared.js +5 -2
- package/dist/editor/commands/indentCommands.js +5 -4
- package/dist/editor/commands/index.d.ts +11 -0
- package/dist/editor/commands/index.js +5 -0
- package/dist/editor/commands/linkCommands.js +5 -6
- package/dist/editor/commands/listCommands.js +8 -10
- package/dist/editor/commands/lockCommands.d.ts +7 -1
- package/dist/editor/commands/lockCommands.js +35 -46
- package/dist/editor/commands/paragraphCommands.js +28 -31
- package/dist/editor/commands/spacingCommands.js +1 -1
- package/dist/editor/createEditor.d.ts +17 -29
- package/dist/editor/createEditor.js +58 -58
- package/dist/editor/documentStyles.d.ts +11 -35
- package/dist/editor/documentStyles.js +9 -52
- package/dist/editor/editorDocument.d.ts +56 -0
- package/dist/editor/editorDocument.js +74 -0
- package/dist/editor/externalClipboard.js +16 -45
- package/dist/editor/insertTable.js +4 -3
- package/dist/editor/paragraphEdits.d.ts +11 -18
- package/dist/editor/paragraphEdits.js +7 -16
- package/dist/editor/plugins/displayDerivation.d.ts +47 -0
- package/dist/editor/plugins/displayDerivation.js +78 -0
- package/dist/editor/plugins/imagePaste.js +4 -3
- package/dist/editor/plugins/keymap.js +18 -3
- package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
- package/dist/editor/plugins/numberingDecorations.js +7 -17
- package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
- package/dist/editor/plugins/paragraphDisplay.js +51 -0
- package/dist/editor/plugins/tabLayout.js +1 -1
- package/dist/editor/plugins/tableDisplay.d.ts +6 -0
- package/dist/editor/plugins/tableDisplay.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/model/format.d.ts +30 -8
- package/dist/model/format.js +35 -22
- package/dist/model/tabStops.d.ts +9 -0
- package/dist/model/tabStops.js +18 -0
- package/dist/numbering/listTemplate.js +24 -7
- package/dist/numbering/parseNumbering.d.ts +14 -1
- package/dist/numbering/parseNumbering.js +35 -22
- package/dist/numbering/writeNumbering.d.ts +3 -4
- package/dist/numbering/writeNumbering.js +14 -25
- package/dist/ooxml/childOrder.d.ts +34 -0
- package/dist/ooxml/childOrder.js +496 -0
- package/dist/ooxml/element.d.ts +24 -11
- package/dist/ooxml/element.js +31 -12
- package/dist/ooxml/errors.d.ts +3 -2
- package/dist/ooxml/image.d.ts +4 -0
- package/dist/ooxml/image.js +2 -5
- package/dist/ooxml/partSplice.d.ts +67 -0
- package/dist/ooxml/partSplice.js +169 -0
- package/dist/ooxml/props.d.ts +112 -0
- package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
- package/dist/ooxml/simpleTypes.d.ts +103 -0
- package/dist/ooxml/simpleTypes.js +182 -0
- package/dist/ooxml/tabStops.js +8 -27
- package/dist/ooxml/tagScan.d.ts +34 -0
- package/dist/ooxml/tagScan.js +108 -0
- package/dist/ooxml/units.d.ts +25 -13
- package/dist/ooxml/units.js +65 -31
- package/dist/ooxml/xml.d.ts +27 -6
- package/dist/ooxml/xml.js +37 -5
- package/dist/page/blockKinds.d.ts +61 -0
- package/dist/page/blockKinds.js +11 -0
- package/dist/page/kinds/index.d.ts +6 -0
- package/dist/page/kinds/index.js +10 -0
- package/dist/page/kinds/paragraphKind.d.ts +10 -0
- package/dist/page/kinds/paragraphKind.js +71 -0
- package/dist/page/kinds/tableKind.d.ts +10 -0
- package/dist/page/kinds/tableKind.js +178 -0
- package/dist/page/measureBlocks.d.ts +3 -14
- package/dist/page/measureBlocks.js +24 -45
- package/dist/page/pageDecorations.d.ts +27 -44
- package/dist/page/pageDecorations.js +70 -152
- package/dist/page/pageLayout.d.ts +2 -19
- package/dist/page/pageLayout.js +36 -6
- package/dist/page/usePageLayout.d.ts +2 -17
- package/dist/page/usePageLayout.js +3 -39
- package/dist/schema/attrRoles.d.ts +25 -18
- package/dist/schema/attrRoles.js +102 -67
- package/dist/schema/displayDerivation.d.ts +82 -0
- package/dist/schema/displayDerivation.js +130 -0
- package/dist/schema/docxSchema.d.ts +3 -0
- package/dist/schema/docxSchema.js +26 -14
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.d.ts +37 -14
- package/dist/schema/guards.js +29 -3
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/locks.d.ts +11 -44
- package/dist/schema/locks.js +0 -9
- package/dist/schema/preservedGuards.d.ts +26 -6
- package/dist/schema/preservedGuards.js +31 -1
- package/dist/schema/protection.d.ts +7 -1
- package/dist/schema/protection.js +2 -1
- package/dist/schema/sourceEquality.d.ts +1 -9
- package/dist/schema/sourceEquality.js +1 -27
- package/dist/styles/inlineStyle.js +15 -6
- package/dist/table/cellFormatting.d.ts +8 -1
- package/dist/table/cellFormatting.js +10 -18
- package/dist/table/commands.js +20 -18
- package/dist/table/format.d.ts +3 -0
- package/dist/table/format.js +3 -9
- package/dist/table/gridBorders.d.ts +14 -16
- package/dist/table/gridBorders.js +3 -41
- package/dist/table/merge.d.ts +2 -6
- package/dist/table/merge.js +5 -5
- package/package.json +7 -3
- package/dist/docx/comments/contentTypes.d.ts +0 -7
- package/dist/docx/comments/contentTypes.js +0 -38
- package/dist/docx/comments/verifying.js +0 -206
- package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
- package/dist/docx/formatting/effectiveParagraph.js +0 -81
- package/dist/docx/propsXml.d.ts +0 -67
- package/dist/docx/uniqueControls.d.ts +0 -14
- package/dist/docx/uniqueControls.js +0 -62
- package/dist/editor/plugins/commentReservations.d.ts +0 -5
- package/dist/editor/plugins/commentReservations.js +0 -26
- package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
- package/dist/editor/plugins/styledParagraphs.js +0 -65
- package/dist/page/tableMeasurements.d.ts +0 -18
- package/dist/page/tableMeasurements.js +0 -119
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/ooxml/tagScan.ts
|
|
2
|
+
function skipPast(source, from, marker) {
|
|
3
|
+
const at = source.indexOf(marker, from);
|
|
4
|
+
return at === -1 ? -1 : at + marker.length;
|
|
5
|
+
}
|
|
6
|
+
function otherTag(end) {
|
|
7
|
+
return end === -1 ? null : { kind: "other", name: "", nameEnd: end, end };
|
|
8
|
+
}
|
|
9
|
+
function readTag(source, lt) {
|
|
10
|
+
if (source.startsWith("<?", lt)) return otherTag(skipPast(source, lt, "?>"));
|
|
11
|
+
if (source.startsWith("<!--", lt))
|
|
12
|
+
return otherTag(skipPast(source, lt, "-->"));
|
|
13
|
+
if (source.startsWith("<![CDATA[", lt))
|
|
14
|
+
return otherTag(skipPast(source, lt, "]]>"));
|
|
15
|
+
if (source.startsWith("<!", lt)) return otherTag(skipPast(source, lt, ">"));
|
|
16
|
+
const closing = source.startsWith("</", lt);
|
|
17
|
+
let i = lt + (closing ? 2 : 1);
|
|
18
|
+
const nameStart = i;
|
|
19
|
+
while (i < source.length && !" \r\n/>".includes(source[i])) i += 1;
|
|
20
|
+
const name = source.slice(nameStart, i);
|
|
21
|
+
if (!name) return null;
|
|
22
|
+
const nameEnd = i;
|
|
23
|
+
let quote = null;
|
|
24
|
+
while (i < source.length) {
|
|
25
|
+
const ch = source[i];
|
|
26
|
+
if (quote !== null) {
|
|
27
|
+
if (ch === quote) quote = null;
|
|
28
|
+
} else if (ch === '"' || ch === "'") {
|
|
29
|
+
quote = ch;
|
|
30
|
+
} else if (ch === ">") {
|
|
31
|
+
const selfClosing = source[i - 1] === "/";
|
|
32
|
+
const kind = closing ? "close" : selfClosing ? "empty" : "open";
|
|
33
|
+
return { kind, name, nameEnd, end: i + 1 };
|
|
34
|
+
}
|
|
35
|
+
i += 1;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function rootTagAt(xml) {
|
|
40
|
+
let at = 0;
|
|
41
|
+
for (; ; ) {
|
|
42
|
+
const lt = xml.indexOf("<", at);
|
|
43
|
+
if (lt === -1) return -1;
|
|
44
|
+
const tag = readTag(xml, lt);
|
|
45
|
+
if (!tag) return -1;
|
|
46
|
+
if (tag.kind !== "other") return lt;
|
|
47
|
+
at = tag.end;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var ENTITIES = {
|
|
51
|
+
amp: "&",
|
|
52
|
+
lt: "<",
|
|
53
|
+
gt: ">",
|
|
54
|
+
quot: '"',
|
|
55
|
+
apos: "'"
|
|
56
|
+
};
|
|
57
|
+
var HIGHEST_CODE_POINT = 1114111;
|
|
58
|
+
function referenceText(name) {
|
|
59
|
+
const named = ENTITIES[name];
|
|
60
|
+
if (named !== void 0) return named;
|
|
61
|
+
const numeric = /^#(?:[xX]([0-9a-fA-F]+)|(\d+))$/.exec(name);
|
|
62
|
+
if (!numeric) return null;
|
|
63
|
+
const [, hex, decimal] = numeric;
|
|
64
|
+
const code = Number.parseInt(hex ?? decimal, hex === void 0 ? 10 : 16);
|
|
65
|
+
if (code > HIGHEST_CODE_POINT || code >= 55296 && code <= 57343) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return String.fromCodePoint(code);
|
|
69
|
+
}
|
|
70
|
+
function decodeReferences(value) {
|
|
71
|
+
if (!value.includes("&")) return value;
|
|
72
|
+
let decoded = "";
|
|
73
|
+
let at = 0;
|
|
74
|
+
for (; ; ) {
|
|
75
|
+
const amp = value.indexOf("&", at);
|
|
76
|
+
if (amp === -1) return decoded + value.slice(at);
|
|
77
|
+
const semicolon = value.indexOf(";", amp);
|
|
78
|
+
if (semicolon === -1) return null;
|
|
79
|
+
const text = referenceText(value.slice(amp + 1, semicolon));
|
|
80
|
+
if (text === null) return null;
|
|
81
|
+
decoded += value.slice(at, amp) + text;
|
|
82
|
+
at = semicolon + 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
var ATTRIBUTE = /(\s*)([^\s=/><"']+)\s*=\s*(?:"([^"<]*)"|'([^'<]*)')/y;
|
|
86
|
+
function parseAttrs(raw) {
|
|
87
|
+
const attrs = [];
|
|
88
|
+
const names = /* @__PURE__ */ new Set();
|
|
89
|
+
let at = 0;
|
|
90
|
+
for (; ; ) {
|
|
91
|
+
ATTRIBUTE.lastIndex = at;
|
|
92
|
+
const matched = ATTRIBUTE.exec(raw);
|
|
93
|
+
if (!matched) return raw.slice(at).trim() === "" ? attrs : null;
|
|
94
|
+
const [, separator, name, doubled, singled] = matched;
|
|
95
|
+
if (at > 0 && separator === "") return null;
|
|
96
|
+
if (names.has(name)) return null;
|
|
97
|
+
names.add(name);
|
|
98
|
+
const value = decodeReferences(doubled ?? singled);
|
|
99
|
+
if (value === null) return null;
|
|
100
|
+
attrs.push([name, value]);
|
|
101
|
+
at = ATTRIBUTE.lastIndex;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
parseAttrs,
|
|
106
|
+
readTag,
|
|
107
|
+
rootTagAt
|
|
108
|
+
};
|
package/dist/ooxml/units.d.ts
CHANGED
|
@@ -1,30 +1,42 @@
|
|
|
1
1
|
import { type ParagraphAlign } from "../model/format";
|
|
2
|
+
import { type HexColor } from "./simpleTypes";
|
|
2
3
|
/** The alignment `w:jc` writes down, both for a paragraph and for a table */
|
|
3
4
|
export declare const ALIGN_BY_JC: Record<string, ParagraphAlign>;
|
|
4
5
|
/** A color as the document writes it, six hex digits and no `#`. Null for anything else */
|
|
5
6
|
export declare function normalizeHex(value: string): string | null;
|
|
6
7
|
export declare function wAttr(el: Element, name: string): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Whether a boolean property element states on (§17.17.4).
|
|
10
|
+
*
|
|
11
|
+
* An element carrying no `w:val` states on, and one that is not there at all states nothing, which
|
|
12
|
+
* a caller asking "is this on" reads as off. For malformed values, this project uses the same
|
|
13
|
+
* fallback as an absent attribute. That recovery policy is not a schema or Word guarantee.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isOnElement(el: Element | null): boolean;
|
|
7
16
|
/** `<w:b/>` means on, `<w:b w:val="0"/>` means off */
|
|
8
17
|
export declare function isOn(parent: Element, name: string): boolean;
|
|
9
18
|
export declare function childValue(parent: Element, name: string): string | null;
|
|
10
|
-
export declare function toNumber(value: string | null): number | null;
|
|
11
19
|
/** Cuts off the messy digits after the decimal point so the same input always yields the same value */
|
|
12
20
|
export declare function round(value: number): number;
|
|
13
21
|
/** twip (1/20 of a point) */
|
|
14
|
-
export declare function twipsToPt(
|
|
22
|
+
export declare function twipsToPt(twips: number | null): number | null;
|
|
15
23
|
/** half-point (w:sz 20 = 10pt) */
|
|
16
|
-
export declare function halfPointsToPt(
|
|
17
|
-
/**
|
|
18
|
-
export declare function eighthsToPt(value: string | null): number | null;
|
|
24
|
+
export declare function halfPointsToPt(half: number | null): number | null;
|
|
25
|
+
/** The color as CSS spells it. `auto` is not a color to paint with, so it reads as none */
|
|
19
26
|
export declare function toHexColor(value: string | null): string | null;
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
/** One border side as `CT_Border` records it (§17.3.4) */
|
|
28
|
+
export interface BorderLine {
|
|
29
|
+
/** ST_Border (§17.18.2). `none` states that this side draws nothing */
|
|
30
|
+
val: string;
|
|
31
|
+
/** The thickness, in eighths of a point */
|
|
32
|
+
eighths: number;
|
|
33
|
+
color: HexColor;
|
|
34
|
+
}
|
|
35
|
+
/** The CSS declaration one line is drawn with, and null for a line there is none of */
|
|
36
|
+
export declare function borderLineCss(line: BorderLine | null): string | null;
|
|
37
|
+
/** The line a CSS declaration this module wrote stands for, so no caller reads one back its own way */
|
|
38
|
+
export declare function borderLineOfCss(css: string | null): BorderLine | null;
|
|
39
|
+
/** Moves one border side into a CSS value */
|
|
28
40
|
export declare function borderCss(el: Element | null): string | null;
|
|
29
41
|
/** One side inside `w:tblBorders` or `w:tcBorders` */
|
|
30
42
|
export declare function borderSide(borders: Element | null, side: string): string | null;
|
package/dist/ooxml/units.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// src/ooxml/units.ts
|
|
2
2
|
import { NO_FILL } from "../model/format.js";
|
|
3
|
+
import {
|
|
4
|
+
EIGHTHS_PER_PT,
|
|
5
|
+
HALF_POINTS_PER_PT,
|
|
6
|
+
ST_EighthPointMeasure,
|
|
7
|
+
ST_HexColor,
|
|
8
|
+
ST_OnOff,
|
|
9
|
+
TWIPS_PER_PT
|
|
10
|
+
} from "./simpleTypes.js";
|
|
3
11
|
import { childByLocalName, W_NS } from "./xml.js";
|
|
4
12
|
var ALIGN_BY_JC = {
|
|
5
13
|
left: "left",
|
|
@@ -17,39 +25,29 @@ function normalizeHex(value) {
|
|
|
17
25
|
function wAttr(el, name) {
|
|
18
26
|
return el.getAttributeNS(W_NS, name) ?? el.getAttribute(name);
|
|
19
27
|
}
|
|
20
|
-
function
|
|
21
|
-
const el = childByLocalName(parent, name);
|
|
28
|
+
function isOnElement(el) {
|
|
22
29
|
if (!el) return false;
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
return ST_OnOff.parse(wAttr(el, "val")) ?? true;
|
|
31
|
+
}
|
|
32
|
+
function isOn(parent, name) {
|
|
33
|
+
return isOnElement(childByLocalName(parent, name));
|
|
25
34
|
}
|
|
26
35
|
function childValue(parent, name) {
|
|
27
36
|
const el = childByLocalName(parent, name);
|
|
28
37
|
return el ? wAttr(el, "val") : null;
|
|
29
38
|
}
|
|
30
|
-
function toNumber(value) {
|
|
31
|
-
if (value === null) return null;
|
|
32
|
-
const parsed = Number.parseFloat(value);
|
|
33
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
34
|
-
}
|
|
35
39
|
function round(value) {
|
|
36
40
|
return Math.round(value * 100) / 100;
|
|
37
41
|
}
|
|
38
|
-
function twipsToPt(
|
|
39
|
-
|
|
40
|
-
return twips === null ? null : round(twips / 20);
|
|
41
|
-
}
|
|
42
|
-
function halfPointsToPt(value) {
|
|
43
|
-
const half = toNumber(value);
|
|
44
|
-
return half === null ? null : round(half / 2);
|
|
42
|
+
function twipsToPt(twips) {
|
|
43
|
+
return twips === null ? null : round(twips / TWIPS_PER_PT);
|
|
45
44
|
}
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
return eighths === null ? null : round(eighths / 8);
|
|
45
|
+
function halfPointsToPt(half) {
|
|
46
|
+
return half === null ? null : round(half / HALF_POINTS_PER_PT);
|
|
49
47
|
}
|
|
50
48
|
function toHexColor(value) {
|
|
51
|
-
|
|
52
|
-
return
|
|
49
|
+
const color = ST_HexColor.parse(value);
|
|
50
|
+
return color?.kind === "rgb" ? `#${color.hex}` : null;
|
|
53
51
|
}
|
|
54
52
|
var BORDER_STYLE_BY_VAL = {
|
|
55
53
|
single: "solid",
|
|
@@ -78,17 +76,52 @@ var BORDER_STYLE_BY_VAL = {
|
|
|
78
76
|
dotDotDash: "dashed",
|
|
79
77
|
dashDotStroked: "dashed"
|
|
80
78
|
};
|
|
81
|
-
var
|
|
82
|
-
|
|
79
|
+
var BORDER_VAL_BY_STYLE = {
|
|
80
|
+
solid: "single",
|
|
81
|
+
double: "double",
|
|
82
|
+
dashed: "dashed",
|
|
83
|
+
dotted: "dotted"
|
|
84
|
+
};
|
|
85
|
+
var FALLBACK_BORDER_EIGHTHS = 4;
|
|
86
|
+
var DEFAULT_BORDER_CSS_COLOR = "#000000";
|
|
87
|
+
var NO_LINE = {
|
|
88
|
+
val: "none",
|
|
89
|
+
eighths: 0,
|
|
90
|
+
color: { kind: "auto" }
|
|
91
|
+
};
|
|
92
|
+
function borderLineOf(el) {
|
|
83
93
|
if (!el) return null;
|
|
84
94
|
const val = wAttr(el, "val") ?? "";
|
|
85
|
-
if (val === "nil" || val === "none") return
|
|
86
|
-
|
|
95
|
+
if (val === "nil" || val === "none") return NO_LINE;
|
|
96
|
+
if (!BORDER_STYLE_BY_VAL[val]) return null;
|
|
97
|
+
const written = ST_EighthPointMeasure.parse(wAttr(el, "sz"));
|
|
98
|
+
return {
|
|
99
|
+
val,
|
|
100
|
+
eighths: written === null || written === 0 ? FALLBACK_BORDER_EIGHTHS : written,
|
|
101
|
+
color: ST_HexColor.parse(wAttr(el, "color")) ?? { kind: "auto" }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function borderLineCss(line) {
|
|
105
|
+
if (!line) return null;
|
|
106
|
+
if (line.val === "none") return "none";
|
|
107
|
+
const style = BORDER_STYLE_BY_VAL[line.val];
|
|
87
108
|
if (!style) return null;
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
const color = line.color.kind === "rgb" ? `#${line.color.hex}` : DEFAULT_BORDER_CSS_COLOR;
|
|
110
|
+
return `${round(line.eighths / EIGHTHS_PER_PT)}pt ${style} ${color}`;
|
|
111
|
+
}
|
|
112
|
+
var BORDER_CSS = /^(\d+(?:\.\d+)?)pt (solid|double|dashed|dotted) (#[0-9a-f]{6})$/i;
|
|
113
|
+
function borderLineOfCss(css) {
|
|
114
|
+
if (css === null) return null;
|
|
115
|
+
if (css === "none") return NO_LINE;
|
|
116
|
+
const matched = BORDER_CSS.exec(css);
|
|
117
|
+
if (!matched) return null;
|
|
118
|
+
const eighths = Math.round(Number(matched[1]) * EIGHTHS_PER_PT);
|
|
119
|
+
const color = ST_HexColor.parse(matched[3].slice(1).toUpperCase());
|
|
120
|
+
if (eighths <= 0 || color === null) return null;
|
|
121
|
+
return { val: BORDER_VAL_BY_STYLE[matched[2].toLowerCase()], eighths, color };
|
|
122
|
+
}
|
|
123
|
+
function borderCss(el) {
|
|
124
|
+
return borderLineCss(borderLineOf(el));
|
|
92
125
|
}
|
|
93
126
|
function borderSide(borders, side) {
|
|
94
127
|
return borders ? borderCss(childByLocalName(borders, side)) : null;
|
|
@@ -101,16 +134,17 @@ function shadingOf(parent) {
|
|
|
101
134
|
export {
|
|
102
135
|
ALIGN_BY_JC,
|
|
103
136
|
borderCss,
|
|
137
|
+
borderLineCss,
|
|
138
|
+
borderLineOfCss,
|
|
104
139
|
borderSide,
|
|
105
140
|
childValue,
|
|
106
|
-
eighthsToPt,
|
|
107
141
|
halfPointsToPt,
|
|
108
142
|
isOn,
|
|
143
|
+
isOnElement,
|
|
109
144
|
normalizeHex,
|
|
110
145
|
round,
|
|
111
146
|
shadingOf,
|
|
112
147
|
toHexColor,
|
|
113
|
-
toNumber,
|
|
114
148
|
twipsToPt,
|
|
115
149
|
wAttr
|
|
116
150
|
};
|
package/dist/ooxml/xml.d.ts
CHANGED
|
@@ -29,6 +29,32 @@ export declare function decodeUtf8(bytes: Uint8Array): {
|
|
|
29
29
|
hadBom: boolean;
|
|
30
30
|
};
|
|
31
31
|
export declare function encodeUtf8(text: string, withBom: boolean): Uint8Array;
|
|
32
|
+
/**
|
|
33
|
+
* What reading a package part asks of a runtime: an XML string in, a document out.
|
|
34
|
+
*
|
|
35
|
+
* A browser's `DOMParser` is one, and so is a `DOMParser` from jsdom. The package ships none of
|
|
36
|
+
* them.
|
|
37
|
+
*
|
|
38
|
+
* Markup it cannot read may be answered either way a parser answers one: by handing back a
|
|
39
|
+
* document holding a `parsererror` element, or by throwing. Both are read as `malformed-xml`.
|
|
40
|
+
*/
|
|
41
|
+
export interface XmlParser {
|
|
42
|
+
parseFromString(source: string, type: "application/xml"): Document;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Runs `work` with every `parseXml` inside it reading through the one parser settled on here.
|
|
46
|
+
*
|
|
47
|
+
* Settling it at the boundary rather than at each read is what lets an entry point turn a runtime
|
|
48
|
+
* holding no parser down before it has read anything, instead of wherever the first part happens
|
|
49
|
+
* to be parsed; it also means one parser serves the whole call rather than a fresh `DOMParser`
|
|
50
|
+
* being built for every part.
|
|
51
|
+
*
|
|
52
|
+
* The public entry points are synchronous, so the scope covers exactly the work one of them does
|
|
53
|
+
* and nothing that runs after it. `undefined` keeps the enclosing scope's parser rather than
|
|
54
|
+
* clearing it, which is what lets an entry point opening a file through another one - the verifier
|
|
55
|
+
* running two imports - hand its own parser down without every inner call having to carry it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function withXmlParser<T>(parser: XmlParser | undefined, work: () => T): T;
|
|
32
58
|
export declare function parseXml(source: string): Document;
|
|
33
59
|
/**
|
|
34
60
|
* Gathers the namespace prefixes used in the fragment and declares them.
|
|
@@ -50,12 +76,7 @@ export declare function attributeByLocalName(el: Element, localName: string): st
|
|
|
50
76
|
export declare function childByLocalName(el: Element, name: string): Element | null;
|
|
51
77
|
/** Turns an opening tag's attributes into an `a="b" c="d"` string */
|
|
52
78
|
export declare function attrString(el: Element): string | null;
|
|
53
|
-
/**
|
|
54
|
-
* Whether this node is an element.
|
|
55
|
-
*
|
|
56
|
-
* `Node` is a global a server is asked to install (`site/content/docs/core.mdx`); `Element` is
|
|
57
|
-
* not, so nothing here may reach for it at run time.
|
|
58
|
-
*/
|
|
79
|
+
/** Whether this node is an element */
|
|
59
80
|
export declare function isElement(node: Node): node is Element;
|
|
60
81
|
/**
|
|
61
82
|
* Turns a single element back into an XML string.
|
package/dist/ooxml/xml.js
CHANGED
|
@@ -36,11 +36,38 @@ function declaresDtd(source) {
|
|
|
36
36
|
at = closes;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
var scopedParser;
|
|
40
|
+
function resolveParser(parser) {
|
|
41
|
+
const named = parser ?? scopedParser;
|
|
42
|
+
if (named) return named;
|
|
43
|
+
if (typeof DOMParser === "function") return new DOMParser();
|
|
44
|
+
throw new DocxImportError(
|
|
45
|
+
"no-xml-parser",
|
|
46
|
+
"no XML parser: pass `xmlParser` or install a DOMParser global"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
function withXmlParser(parser, work) {
|
|
50
|
+
const enclosing = scopedParser;
|
|
51
|
+
scopedParser = resolveParser(parser);
|
|
52
|
+
try {
|
|
53
|
+
return work();
|
|
54
|
+
} finally {
|
|
55
|
+
scopedParser = enclosing;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
39
58
|
function parseXml(source) {
|
|
40
59
|
if (declaresDtd(source)) {
|
|
41
60
|
throw new DocxImportError("malformed-xml", "the XML declares a DTD");
|
|
42
61
|
}
|
|
43
|
-
|
|
62
|
+
let doc;
|
|
63
|
+
try {
|
|
64
|
+
doc = resolveParser(void 0).parseFromString(source, "application/xml");
|
|
65
|
+
} catch (cause) {
|
|
66
|
+
if (cause instanceof DocxImportError) throw cause;
|
|
67
|
+
throw new DocxImportError("malformed-xml", "could not parse the XML", {
|
|
68
|
+
cause
|
|
69
|
+
});
|
|
70
|
+
}
|
|
44
71
|
if (doc.getElementsByTagName("parsererror").length > 0) {
|
|
45
72
|
throw new DocxImportError("malformed-xml", "could not parse the XML");
|
|
46
73
|
}
|
|
@@ -75,15 +102,19 @@ function attrString(el) {
|
|
|
75
102
|
if (el.attributes.length === 0) return null;
|
|
76
103
|
return Array.from(el.attributes).map((attr) => `${attr.name}="${escapeXml(attr.value)}"`).join(" ");
|
|
77
104
|
}
|
|
105
|
+
var ELEMENT_NODE = 1;
|
|
106
|
+
var TEXT_NODE = 3;
|
|
107
|
+
var CDATA_SECTION_NODE = 4;
|
|
108
|
+
var COMMENT_NODE = 8;
|
|
78
109
|
function isElement(node) {
|
|
79
|
-
return node.nodeType ===
|
|
110
|
+
return node.nodeType === ELEMENT_NODE;
|
|
80
111
|
}
|
|
81
112
|
function serializeChildNode(node) {
|
|
82
113
|
if (isElement(node)) return serializeXml(node);
|
|
83
|
-
if (node.nodeType ===
|
|
114
|
+
if (node.nodeType === TEXT_NODE || node.nodeType === CDATA_SECTION_NODE) {
|
|
84
115
|
return escapeXml(node.nodeValue ?? "");
|
|
85
116
|
}
|
|
86
|
-
if (node.nodeType ===
|
|
117
|
+
if (node.nodeType === COMMENT_NODE) {
|
|
87
118
|
return `<!--${node.nodeValue ?? ""}-->`;
|
|
88
119
|
}
|
|
89
120
|
throw new DocxImportError(
|
|
@@ -112,5 +143,6 @@ export {
|
|
|
112
143
|
localPart,
|
|
113
144
|
namespaceDecls,
|
|
114
145
|
parseXml,
|
|
115
|
-
serializeXml
|
|
146
|
+
serializeXml,
|
|
147
|
+
withXmlParser
|
|
116
148
|
};
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* A measurer says where a block may be parted and how much of it has to fit on the page it
|
|
5
5
|
* starts on; the layout (`page/pageLayout`) answers with the places it decided to part it at.
|
|
6
6
|
* Neither side names a paragraph or a table.
|
|
7
|
+
*
|
|
8
|
+
* Which measurer a block gets, and what draws the cuts it was given, is the block's kind
|
|
9
|
+
* (`page/kinds`).
|
|
7
10
|
*/
|
|
11
|
+
import type { Node as PMNode } from "prosemirror-model";
|
|
12
|
+
import type { Decoration, EditorView } from "prosemirror-view";
|
|
8
13
|
/** A place inside a block where the next page may, or must, start */
|
|
9
14
|
export interface BreakCandidate {
|
|
10
15
|
/**
|
|
@@ -34,9 +39,65 @@ export interface MeasuredBlock {
|
|
|
34
39
|
candidates: readonly BreakCandidate[];
|
|
35
40
|
/** The smallest piece that has to fit on the page the block starts on */
|
|
36
41
|
minFirstPiece: number;
|
|
42
|
+
/** The document asks for this block to stand on the same page as the start of the block after it */
|
|
43
|
+
keepWithNext: boolean;
|
|
37
44
|
}
|
|
38
45
|
/** A page cut the layout decided on: the space opened before the continued piece */
|
|
39
46
|
export interface PageCut {
|
|
40
47
|
at: number;
|
|
41
48
|
height: number;
|
|
42
49
|
}
|
|
50
|
+
/** One block as it stands on the sheet, handed to the kind about to measure it */
|
|
51
|
+
export interface MeasureTarget {
|
|
52
|
+
view: EditorView;
|
|
53
|
+
node: PMNode;
|
|
54
|
+
pos: number;
|
|
55
|
+
dom: HTMLElement;
|
|
56
|
+
/**
|
|
57
|
+
* Sheet coordinates from viewport coordinates: the visual scale taken out, and everything the
|
|
58
|
+
* engine has opened up above this block taken back off
|
|
59
|
+
*/
|
|
60
|
+
sheetY(viewportY: number): number;
|
|
61
|
+
/** The block's natural top: pushes and spaces opened above it already taken back off */
|
|
62
|
+
top: number;
|
|
63
|
+
/** The visual scale the sheet is drawn at, which a length read off the screen is divided by */
|
|
64
|
+
scale: number;
|
|
65
|
+
}
|
|
66
|
+
/** What a kind has to say about the block it measured */
|
|
67
|
+
export interface KindMeasure {
|
|
68
|
+
candidates: readonly BreakCandidate[];
|
|
69
|
+
/** The smallest piece that has to fit on the page the block starts on */
|
|
70
|
+
minFirstPiece: number;
|
|
71
|
+
/** The block holds a break it could not open a space at, so the next block starts a page */
|
|
72
|
+
breakAfter: boolean;
|
|
73
|
+
/** Height the engine's own marks add inside this block, taken off its measured bottom */
|
|
74
|
+
appliedHeight: number;
|
|
75
|
+
/**
|
|
76
|
+
* Whether the document asks for this block to stand on the same page as the start of the block
|
|
77
|
+
* after it. A kind whose blocks never do leaves it out
|
|
78
|
+
*/
|
|
79
|
+
keepWithNext?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Everything the engine does with one shape of breakable block: how one is measured, and how the
|
|
83
|
+
* cuts the layout gave it are drawn.
|
|
84
|
+
*
|
|
85
|
+
* A shape the engine learns later - a footnote area, a paragraph with a floating object hanging
|
|
86
|
+
* out of it - is one more kind rather than another branch in the measurer, in the decorations
|
|
87
|
+
* and in the plugin state at once.
|
|
88
|
+
*/
|
|
89
|
+
export interface BlockKind {
|
|
90
|
+
readonly name: string;
|
|
91
|
+
matches(node: PMNode): boolean;
|
|
92
|
+
measure(target: MeasureTarget): KindMeasure;
|
|
93
|
+
/** Whether `at` still names a place this kind can cut at in `doc`; a false drops the cut */
|
|
94
|
+
holdsCut(doc: PMNode, at: number): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* The decorations one block of this kind carries: the cuts the layout gave it, plus whatever it
|
|
97
|
+
* needs before any measurement (a paragraph puts an empty space on every page `br`, so the
|
|
98
|
+
* measurement has an element to read it off).
|
|
99
|
+
*/
|
|
100
|
+
decorate(pos: number, node: PMNode, cuts: readonly PageCut[], into: Decoration[]): void;
|
|
101
|
+
}
|
|
102
|
+
/** The first kind whose `matches` answers. The kind registered last has to match every block */
|
|
103
|
+
export declare function blockKindFor(kinds: readonly BlockKind[], node: PMNode): BlockKind;
|
package/dist/page/blockKinds.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/page/blockKinds.ts
|
|
2
|
+
function blockKindFor(kinds, node) {
|
|
3
|
+
const found = kinds.find((kind) => kind.matches(node));
|
|
4
|
+
if (!found) {
|
|
5
|
+
throw new Error(`no block kind matches a ${node.type.name} block`);
|
|
6
|
+
}
|
|
7
|
+
return found;
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
blockKindFor
|
|
11
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BlockKind } from "../blockKinds";
|
|
2
|
+
/**
|
|
3
|
+
* The block shapes the editor pages, in the order they are asked. A new kind goes ahead of the
|
|
4
|
+
* kinds it is narrower than, and the last one claims every block none of the others did.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_BLOCK_KINDS: readonly BlockKind[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kind every block falls back to: a paragraph, and any other shape no kind ahead of it claims.
|
|
3
|
+
*
|
|
4
|
+
* A page `br` is the one place a paragraph is parted at, and the space opened at it is what the
|
|
5
|
+
* measurement reads the break's place off, so every `br` carries a space of its own before
|
|
6
|
+
* anything is measured. A break standing where no space can be opened - inside a table cell,
|
|
7
|
+
* where it would grow the cell rather than the page - is answered by the whole block instead.
|
|
8
|
+
*/
|
|
9
|
+
import type { BlockKind } from "../blockKinds";
|
|
10
|
+
export declare const paragraphKind: BlockKind;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/page/kinds/paragraphKind.ts
|
|
2
|
+
import { Decoration } from "prosemirror-view";
|
|
3
|
+
import { toParagraphFormat } from "../../model/format.js";
|
|
4
|
+
import { docxSchema, isPageBreak } from "../../schema/index.js";
|
|
5
|
+
import { editorAttributes } from "../../styles/classNames.js";
|
|
6
|
+
var PAGE_BREAK_BR = `br[${editorAttributes.breakType}="page"]`;
|
|
7
|
+
var BREAK_SPACE = `[${editorAttributes.pageBreakSpace}]`;
|
|
8
|
+
function spaceStyle(height) {
|
|
9
|
+
return `display:block;height:${height}px`;
|
|
10
|
+
}
|
|
11
|
+
function isPageBreakNode(node) {
|
|
12
|
+
return node?.type === docxSchema.nodes.hardBreak && isPageBreak(node.attrs.brAttrs);
|
|
13
|
+
}
|
|
14
|
+
function pageBreaksIn(block, blockPos) {
|
|
15
|
+
const found = [];
|
|
16
|
+
if (block.type !== docxSchema.nodes.paragraph) return found;
|
|
17
|
+
block.forEach((child, offset) => {
|
|
18
|
+
if (isPageBreakNode(child)) {
|
|
19
|
+
found.push({ at: blockPos + 1 + offset, size: child.nodeSize });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return found;
|
|
23
|
+
}
|
|
24
|
+
var paragraphKind = {
|
|
25
|
+
name: "paragraph",
|
|
26
|
+
matches: () => true,
|
|
27
|
+
measure({ node, pos, dom, sheetY, top, scale }) {
|
|
28
|
+
const breaks = pageBreaksIn(node, pos);
|
|
29
|
+
const candidates = [];
|
|
30
|
+
let appliedHeight = 0;
|
|
31
|
+
dom.querySelectorAll(BREAK_SPACE).forEach((space, index) => {
|
|
32
|
+
const box = space.getBoundingClientRect();
|
|
33
|
+
const found = breaks.at(index);
|
|
34
|
+
if (found) {
|
|
35
|
+
candidates.push({
|
|
36
|
+
at: found.at,
|
|
37
|
+
offset: sheetY(box.top) - appliedHeight - top,
|
|
38
|
+
forced: true,
|
|
39
|
+
repeatHeight: 0
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
appliedHeight += box.height / scale;
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
candidates,
|
|
46
|
+
minFirstPiece: candidates[0]?.offset ?? dom.getBoundingClientRect().height / scale - appliedHeight,
|
|
47
|
+
// A break with no space of its own sits somewhere the space could not be opened. Those
|
|
48
|
+
// still start a new page, but only after the whole block
|
|
49
|
+
breakAfter: dom.querySelectorAll(PAGE_BREAK_BR).length > candidates.length,
|
|
50
|
+
appliedHeight,
|
|
51
|
+
keepWithNext: toParagraphFormat(node.attrs.format)?.keepNext === true
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
holdsCut: (doc, at) => isPageBreakNode(doc.nodeAt(at)),
|
|
55
|
+
decorate(pos, node, cuts, into) {
|
|
56
|
+
const heights = new Map(cuts.map((cut) => [cut.at, cut.height]));
|
|
57
|
+
for (const { at, size } of pageBreaksIn(node, pos)) {
|
|
58
|
+
const height = heights.get(at) ?? 0;
|
|
59
|
+
into.push(
|
|
60
|
+
Decoration.inline(at, at + size, {
|
|
61
|
+
nodeName: "span",
|
|
62
|
+
style: spaceStyle(height),
|
|
63
|
+
[editorAttributes.pageBreakSpace]: `${height}`
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
export {
|
|
70
|
+
paragraphKind
|
|
71
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kind of a table: it is parted between rows, and a continued page opens a spacer row and
|
|
3
|
+
* repeats the headers the table opens with.
|
|
4
|
+
*
|
|
5
|
+
* Both sides read the table as it stands on screen without treating the rows this very engine
|
|
6
|
+
* drew as content: the measurement takes their heights back off, and the projection is derived
|
|
7
|
+
* again from the document, so an edit to a header row redraws it with nothing measured anew.
|
|
8
|
+
*/
|
|
9
|
+
import type { BlockKind } from "../blockKinds";
|
|
10
|
+
export declare const tableKind: BlockKind;
|