@stll/folio-core 0.44.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.js +2 -2
  2. package/dist/ai-edits/apply.js +59 -19
  3. package/dist/ai-edits/headless.js +2 -1
  4. package/dist/compare/compare.js +2 -5
  5. package/dist/compare/content-alignment.js +78 -53
  6. package/dist/compare/inline-atoms.js +34 -20
  7. package/dist/compare/scenario.js +2 -5
  8. package/dist/compare/types.d.ts +9 -1
  9. package/dist/compare/types.js +12 -1
  10. package/dist/compat/eigenpal.d.ts +2 -1
  11. package/dist/compat/eigenpal.js +2 -1
  12. package/dist/content-controls/checkboxDisplay.d.ts +11 -0
  13. package/dist/content-controls/checkboxDisplay.js +40 -0
  14. package/dist/content-controls/findContentControls.js +3 -1
  15. package/dist/content-controls/mutateContentControls.js +21 -4
  16. package/dist/controller/contentControlWidgetController.d.ts +1 -0
  17. package/dist/controller/contentControlWidgetController.js +3 -0
  18. package/dist/controller/hiddenEditorApi.js +3 -1
  19. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  20. package/dist/controller/hiddenEditorManager.js +6 -3
  21. package/dist/display-list/build/buildDisplayList.js +20 -1
  22. package/dist/display-list/build/imagePrimitives.d.ts +1 -1
  23. package/dist/display-list/build/imagePrimitives.js +3 -1
  24. package/dist/display-list/build/paragraphPrimitives.js +21 -2
  25. package/dist/display-list/dom/renderDisplayListToDom.js +18 -10
  26. package/dist/display-list/types.d.ts +17 -0
  27. package/dist/document-operations.js +14 -3
  28. package/dist/docx/attributeRemainder.d.ts +43 -0
  29. package/dist/docx/attributeRemainder.js +65 -0
  30. package/dist/docx/blockContentParser.d.ts +1 -1
  31. package/dist/docx/blockContentParser.js +87 -63
  32. package/dist/docx/blockPlainText.d.ts +3 -4
  33. package/dist/docx/blockPlainText.js +1 -0
  34. package/dist/docx/bookmarkPlacement.js +2 -0
  35. package/dist/docx/borderParser.js +5 -5
  36. package/dist/docx/commentAnchorIndex.d.ts +30 -0
  37. package/dist/docx/commentAnchorIndex.js +50 -0
  38. package/dist/docx/commentParser.d.ts +1 -1
  39. package/dist/docx/commentParser.js +78 -50
  40. package/dist/docx/commentRangeIntegrity.d.ts +16 -1
  41. package/dist/docx/commentRangeIntegrity.js +42 -1
  42. package/dist/docx/commentRangeJoin.d.ts +9 -0
  43. package/dist/docx/commentRangeJoin.js +33 -0
  44. package/dist/docx/commentReferenceCompletion.d.ts +9 -0
  45. package/dist/docx/commentReferenceCompletion.js +47 -0
  46. package/dist/docx/commentReferenceNormalization.js +1 -0
  47. package/dist/docx/commentReplyMarkers.js +11 -19
  48. package/dist/docx/commentThreadKey.d.ts +18 -0
  49. package/dist/docx/commentThreadKey.js +22 -0
  50. package/dist/docx/compatibility.js +1 -0
  51. package/dist/docx/containerChildren.d.ts +111 -0
  52. package/dist/docx/containerChildren.gen.d.ts +28 -0
  53. package/dist/docx/containerChildren.gen.js +246 -0
  54. package/dist/docx/containerChildren.js +103 -0
  55. package/dist/docx/diagramPreview.js +87 -27
  56. package/dist/docx/documentParser.d.ts +1 -1
  57. package/dist/docx/documentParser.js +3 -3
  58. package/dist/docx/ensureParaIds.js +17 -7
  59. package/dist/docx/fieldParser.d.ts +1 -1
  60. package/dist/docx/fieldParser.js +4 -4
  61. package/dist/docx/fieldState.d.ts +26 -0
  62. package/dist/docx/fieldState.js +53 -0
  63. package/dist/docx/footnoteParser.d.ts +1 -1
  64. package/dist/docx/graphicFrameLocks.d.ts +16 -4
  65. package/dist/docx/graphicFrameLocks.js +19 -6
  66. package/dist/docx/groupDrawingParser.js +3 -3
  67. package/dist/docx/headerFooterParser.js +1 -1
  68. package/dist/docx/headerFooterReferenceNormalization.js +1 -0
  69. package/dist/docx/hyperlinkParser.d.ts +27 -8
  70. package/dist/docx/hyperlinkParser.js +78 -20
  71. package/dist/docx/imageParser.d.ts +9 -1
  72. package/dist/docx/imageParser.js +91 -20
  73. package/dist/docx/imageRawXml.d.ts +14 -1
  74. package/dist/docx/imageRawXml.js +30 -6
  75. package/dist/docx/inlineWrapperContent.d.ts +85 -0
  76. package/dist/docx/inlineWrapperContent.js +84 -0
  77. package/dist/docx/mathToMathml.js +12 -14
  78. package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
  79. package/dist/docx/nonVisualDrawingProps.js +46 -0
  80. package/dist/docx/normalizeBaseDirection.js +10 -1
  81. package/dist/docx/paraIdAttribute.d.ts +21 -0
  82. package/dist/docx/paraIdAttribute.js +64 -0
  83. package/dist/docx/paragraphParser.d.ts +1 -1
  84. package/dist/docx/paragraphParser.js +277 -168
  85. package/dist/docx/paragraphPropertySource.js +5 -1
  86. package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
  87. package/dist/docx/paragraphTextBoxEnrichment.js +9 -52
  88. package/dist/docx/paragraphTraversal.js +7 -4
  89. package/dist/docx/parseWarningMessage.js +2 -1
  90. package/dist/docx/parser.js +2 -2
  91. package/dist/docx/preservedRunContent.d.ts +32 -0
  92. package/dist/docx/preservedRunContent.js +86 -0
  93. package/dist/docx/previewBudget.d.ts +64 -0
  94. package/dist/docx/previewBudget.js +88 -0
  95. package/dist/docx/renderedPageBreakNormalization.js +2 -4
  96. package/dist/docx/revisionIdNormalization.js +17 -5
  97. package/dist/docx/rezip.js +91 -36
  98. package/dist/docx/runParser.d.ts +1 -1
  99. package/dist/docx/runParser.js +16 -12
  100. package/dist/docx/sdtPropertiesPatch.js +24 -18
  101. package/dist/docx/sectionParser.js +8 -1
  102. package/dist/docx/sectionReferenceHistory.js +2 -2
  103. package/dist/docx/selectiveSave.js +6 -6
  104. package/dist/docx/selectiveXmlPatch.d.ts +46 -2
  105. package/dist/docx/selectiveXmlPatch.js +86 -39
  106. package/dist/docx/serializer/blockSdtSerializer.js +38 -26
  107. package/dist/docx/serializer/borderSerializer.d.ts +1 -1
  108. package/dist/docx/serializer/borderSerializer.js +15 -14
  109. package/dist/docx/serializer/commentSerializer.d.ts +41 -16
  110. package/dist/docx/serializer/commentSerializer.js +87 -92
  111. package/dist/docx/serializer/documentSerializer.js +8 -11
  112. package/dist/docx/serializer/fontTableSerializer.js +6 -6
  113. package/dist/docx/serializer/headerFooterSerializer.js +12 -14
  114. package/dist/docx/serializer/markupRangeAttributes.js +2 -2
  115. package/dist/docx/serializer/noteSerializer.js +8 -8
  116. package/dist/docx/serializer/numberingSerializer.js +7 -6
  117. package/dist/docx/serializer/paragraphSerializer.js +93 -72
  118. package/dist/docx/serializer/partNamespaces.js +2 -2
  119. package/dist/docx/serializer/runSerializer.js +73 -44
  120. package/dist/docx/serializer/sectionPropertiesSerializer.js +19 -14
  121. package/dist/docx/serializer/settingsSerializer.js +4 -3
  122. package/dist/docx/serializer/stylesSerializer.js +6 -6
  123. package/dist/docx/serializer/tableSerializer.js +28 -17
  124. package/dist/docx/serializer/textFormattingSerializer.js +29 -28
  125. package/dist/docx/serializer/themeSerializer.js +6 -6
  126. package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
  127. package/dist/docx/serializer/xmlUtils.d.ts +1 -2
  128. package/dist/docx/serializer/xmlUtils.js +1 -13
  129. package/dist/docx/server/boundedArchive.d.ts +12 -0
  130. package/dist/docx/server/boundedArchive.js +20 -1
  131. package/dist/docx/server/createBilingualDocument.js +3 -1
  132. package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
  133. package/dist/docx/server/materializeYjsDocx.js +9 -1
  134. package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
  135. package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
  136. package/dist/docx/server/validateDocxConformance.js +22 -1
  137. package/dist/docx/shapeParser.js +12 -10
  138. package/dist/docx/tableParser.d.ts +1 -1
  139. package/dist/docx/tableParser.js +206 -85
  140. package/dist/docx/textBoxParser.d.ts +25 -2
  141. package/dist/docx/textBoxParser.js +59 -4
  142. package/dist/docx/unzip.d.ts +23 -0
  143. package/dist/docx/unzip.js +37 -26
  144. package/dist/docx/verbatimCapture.js +1 -1
  145. package/dist/docx/vmlImageParser.d.ts +17 -1
  146. package/dist/docx/vmlImageParser.js +20 -3
  147. package/dist/docx/vmlPreview.d.ts +1 -3
  148. package/dist/docx/vmlPreview.js +2 -30
  149. package/dist/docx/xmlEncoding.d.ts +5 -0
  150. package/dist/docx/xmlEncoding.js +12 -0
  151. package/dist/docx/xmlParser.d.ts +26 -2
  152. package/dist/docx/xmlParser.js +70 -27
  153. package/dist/docx/xmlResourceLimits.d.ts +89 -9
  154. package/dist/docx/xmlResourceLimits.js +105 -24
  155. package/dist/headless-layout.js +10 -1
  156. package/dist/index.d.ts +2 -1
  157. package/dist/index.js +2 -1
  158. package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
  159. package/dist/internal/paragraphFormattingSerialization.js +3 -2
  160. package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
  161. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  162. package/dist/layout-engine/measure/tableCellFloating.js +2 -0
  163. package/dist/layout-engine/types.d.ts +23 -1
  164. package/dist/layout-painter/renderImage.d.ts +5 -1
  165. package/dist/layout-painter/renderImage.js +14 -6
  166. package/dist/layout-painter/renderPage.d.ts +2 -0
  167. package/dist/layout-painter/renderPage.js +4 -0
  168. package/dist/layout-painter/renderParagraph.d.ts +13 -1
  169. package/dist/layout-painter/renderParagraph.js +26 -6
  170. package/dist/managers/autoSaveCodec.d.ts +9 -1
  171. package/dist/managers/autoSaveCodec.js +14 -12
  172. package/dist/markdown/images.js +1 -4
  173. package/dist/markdown/renderBlock.js +1 -0
  174. package/dist/markdown/renderRuns.d.ts +1 -1
  175. package/dist/markdown/renderRuns.js +28 -5
  176. package/dist/markdown/renderTable.js +22 -5
  177. package/dist/markdown/trailers.js +4 -1
  178. package/dist/pdf/images.js +142 -6
  179. package/dist/prosemirror/attrs/index.d.ts +14 -3
  180. package/dist/prosemirror/attrs/index.js +224 -2
  181. package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
  182. package/dist/prosemirror/authoredTransformAttrs.js +64 -0
  183. package/dist/prosemirror/commands/contentControls.js +10 -2
  184. package/dist/prosemirror/commands/image.d.ts +9 -2
  185. package/dist/prosemirror/commands/image.js +43 -28
  186. package/dist/prosemirror/commands/pageBreak.js +1 -1
  187. package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
  188. package/dist/prosemirror/commentReferenceAttrs.js +33 -0
  189. package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
  190. package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
  191. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  192. package/dist/prosemirror/conversion/fromProseDoc.js +338 -99
  193. package/dist/prosemirror/conversion/index.d.ts +2 -2
  194. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
  195. package/dist/prosemirror/conversion/toProseDoc.js +551 -327
  196. package/dist/prosemirror/extensions/StarterKit.js +8 -58
  197. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  198. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
  199. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
  200. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
  201. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
  202. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
  203. package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
  204. package/dist/prosemirror/extensions/markRegistry.js +75 -0
  205. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
  206. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
  207. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
  208. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  209. package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
  210. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
  211. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
  212. package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
  213. package/dist/prosemirror/extensions/nodes/ImageExtension.js +20 -0
  214. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
  215. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
  216. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
  217. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
  218. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +10 -2
  219. package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
  220. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +13 -5
  221. package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
  222. package/dist/prosemirror/inlineWrapperStack.js +75 -0
  223. package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
  224. package/dist/prosemirror/pageBreakRunProjection.js +19 -9
  225. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
  226. package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
  227. package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
  228. package/dist/prosemirror/replacedAnnotations.js +165 -0
  229. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
  230. package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
  231. package/dist/prosemirror/schema/index.d.ts +3 -3
  232. package/dist/prosemirror/schema/marks.d.ts +25 -1
  233. package/dist/prosemirror/schema/nodes.d.ts +139 -3
  234. package/dist/prosemirror/schema/nodes.js +16 -1
  235. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
  236. package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
  237. package/dist/prosemirror/validation.js +16 -2
  238. package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
  239. package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
  240. package/dist/prosemirror/zeroWidthAnchors.js +2 -0
  241. package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
  242. package/dist/render-dom/commentAnchorAttributes.js +54 -0
  243. package/dist/server.d.ts +3 -1
  244. package/dist/server.js +3 -1
  245. package/dist/types/content.d.ts +2 -2
  246. package/dist/utils/base64.d.ts +36 -0
  247. package/dist/utils/base64.js +40 -0
  248. package/dist/utils/clipboard.d.ts +9 -1
  249. package/dist/utils/clipboard.js +29 -2
  250. package/dist/utils/findReplace.js +1 -1
  251. package/dist/utils/imageLuminance.d.ts +15 -0
  252. package/dist/utils/imageLuminance.js +32 -0
  253. package/dist/utils/mergeDocumentContent.js +7 -17
  254. package/dist/utils/replaceText.js +1 -0
  255. package/dist/utils/units.d.ts +10 -1
  256. package/dist/utils/units.js +12 -1
  257. package/dist/utils/urlSecurity.d.ts +8 -2
  258. package/dist/utils/urlSecurity.js +21 -3
  259. package/package.json +2 -2
  260. package/dist/docx/blockRangeMarkers.d.ts +0 -36
  261. package/dist/docx/blockRangeMarkers.js +0 -59
  262. package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
  263. package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
@@ -0,0 +1,53 @@
1
+ import { parseOnOffAttribute } from "./xmlParser.js";
2
+ //#region src/docx/fieldState.ts
3
+ /**
4
+ * `@w:fldLock` and `@w:dirty`, the two `ST_OnOff` attributes every field form
5
+ * carries.
6
+ *
7
+ * A simple field states them on `<w:fldSimple>`; a complex field states them on
8
+ * the `<w:fldChar w:fldCharType="begin"/>` that opens it, and folio hoists them
9
+ * from there onto the assembled `ComplexField`. Neither attribute has an XSD
10
+ * default, so a field states one of three things about each: nothing, an
11
+ * explicit off, an explicit on. `w:dirty="0"` on a field inside a `TOC` result
12
+ * is the case that matters: it says "do not recompute this", which is not what
13
+ * an absent attribute says.
14
+ *
15
+ * Three readers and three writers had drifted into the same `=== true` /
16
+ * truthiness collapse, so both directions live here instead.
17
+ */
18
+ /** Read both attributes off a `w:fldSimple` or `w:fldChar`, keeping an explicit off. */
19
+ const parseFieldState = (element) => {
20
+ const state = {};
21
+ const fldLock = parseOnOffAttribute(element, "w", "fldLock");
22
+ if (fldLock !== void 0) state.fldLock = fldLock;
23
+ const dirty = parseOnOffAttribute(element, "w", "dirty");
24
+ if (dirty !== void 0) state.dirty = dirty;
25
+ return state;
26
+ };
27
+ /**
28
+ * The stated flags of a field, without the rest of it.
29
+ *
30
+ * The complex-field assembly carries the begin `w:fldChar`'s state across the
31
+ * runs between `begin` and `end`, and this is the one place that knows which
32
+ * fields that state is made of.
33
+ */
34
+ const fieldStateOf = ({ fldLock, dirty }) => {
35
+ const state = {};
36
+ if (fldLock !== void 0) state.fldLock = fldLock;
37
+ if (dirty !== void 0) state.dirty = dirty;
38
+ return state;
39
+ };
40
+ /**
41
+ * The attributes to write for a field's stated flags, in schema order.
42
+ *
43
+ * `1`/`0` is what Word writes and what the table, section and border
44
+ * serializers write.
45
+ */
46
+ const fieldStateAttributes = ({ fldLock, dirty }) => {
47
+ const attrs = [];
48
+ if (fldLock !== void 0) attrs.push(`w:fldLock="${fldLock ? "1" : "0"}"`);
49
+ if (dirty !== void 0) attrs.push(`w:dirty="${dirty ? "1" : "0"}"`);
50
+ return attrs;
51
+ };
52
+ //#endregion
53
+ export { fieldStateAttributes, fieldStateOf, parseFieldState };
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { NumberingMap } from "./numberingParser.js";
3
- import { StyleMap } from "./styleParser.js";
4
3
  import { ParseContext } from "./parseContext.js";
4
+ import { StyleMap } from "./styleParser.js";
5
5
  import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
6
6
  //#region src/docx/footnoteParser.d.ts
7
7
  /**
@@ -12,11 +12,23 @@ declare const GRAPHIC_FRAME_LOCK_KEYS: ("noGrp" | "noDrilldown" | "noSelect" | "
12
12
  */
13
13
  declare const parseGraphicFrameLocks: (parent: XmlElement) => document_d_exports.ImageFrameLocks | undefined;
14
14
  /**
15
- * Emit the whole `wp:cNvGraphicFramePr` element for regenerated DrawingML.
15
+ * The locks folio gives a picture it creates itself, at the insert that creates
16
+ * it: Word writes `noChangeAspect="1"` on a picture inserted through its own
17
+ * UI, and an inserted picture should behave the same in both.
16
18
  *
17
- * Absent locks mean no authored frame was ever parsed (a Folio-created
18
- * picture), which keeps the historical `noChangeAspect="1"`.
19
+ * It lives here because it is a fact about this element, and it is applied at
20
+ * construction rather than at serialization, where "the author wrote no frame"
21
+ * and "folio made this picture" are the same `undefined`.
22
+ */
23
+ declare const FOLIO_INSERTED_PICTURE_FRAME_LOCKS: document_d_exports.ImageFrameLocks;
24
+ /**
25
+ * Emit `wp:cNvGraphicFramePr` for regenerated DrawingML, or nothing.
26
+ *
27
+ * Absent locks are the author's silence, and silence is written back as
28
+ * silence: a frame the source never carried is not invented on the rebuild
29
+ * path, where it would appear on every edited document and on none of the
30
+ * replayed ones.
19
31
  */
20
32
  declare const serializeGraphicFrameLocks: (locks: document_d_exports.ImageFrameLocks | undefined) => string;
21
33
  //#endregion
22
- export { GRAPHIC_FRAME_LOCK_KEYS, parseGraphicFrameLocks, serializeGraphicFrameLocks };
34
+ export { FOLIO_INSERTED_PICTURE_FRAME_LOCKS, GRAPHIC_FRAME_LOCK_KEYS, parseGraphicFrameLocks, serializeGraphicFrameLocks };
@@ -38,18 +38,31 @@ const parseGraphicFrameLocks = (parent) => {
38
38
  return present ? locks : void 0;
39
39
  };
40
40
  /**
41
- * Emit the whole `wp:cNvGraphicFramePr` element for regenerated DrawingML.
41
+ * The locks folio gives a picture it creates itself, at the insert that creates
42
+ * it: Word writes `noChangeAspect="1"` on a picture inserted through its own
43
+ * UI, and an inserted picture should behave the same in both.
42
44
  *
43
- * Absent locks mean no authored frame was ever parsed (a Folio-created
44
- * picture), which keeps the historical `noChangeAspect="1"`.
45
+ * It lives here because it is a fact about this element, and it is applied at
46
+ * construction rather than at serialization, where "the author wrote no frame"
47
+ * and "folio made this picture" are the same `undefined`.
48
+ */
49
+ const FOLIO_INSERTED_PICTURE_FRAME_LOCKS = { noChangeAspect: true };
50
+ /**
51
+ * Emit `wp:cNvGraphicFramePr` for regenerated DrawingML, or nothing.
52
+ *
53
+ * Absent locks are the author's silence, and silence is written back as
54
+ * silence: a frame the source never carried is not invented on the rebuild
55
+ * path, where it would appear on every edited document and on none of the
56
+ * replayed ones.
45
57
  */
46
58
  const serializeGraphicFrameLocks = (locks) => {
47
- const attrs = locks ? GRAPHIC_FRAME_LOCK_KEYS.flatMap((key) => {
59
+ if (!locks) return "";
60
+ const attrs = GRAPHIC_FRAME_LOCK_KEYS.flatMap((key) => {
48
61
  const value = locks[key];
49
62
  return value === void 0 ? [] : [`${GRAPHIC_FRAME_LOCK_ATTRIBUTES[key]}="${value ? "1" : "0"}"`];
50
- }) : ["noChangeAspect=\"1\""];
63
+ });
51
64
  const attrList = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
52
65
  return `<wp:cNvGraphicFramePr><a:graphicFrameLocks ${DRAWINGML_NAMESPACE}${attrList}/></wp:cNvGraphicFramePr>`;
53
66
  };
54
67
  //#endregion
55
- export { GRAPHIC_FRAME_LOCK_KEYS, parseGraphicFrameLocks, serializeGraphicFrameLocks };
68
+ export { FOLIO_INSERTED_PICTURE_FRAME_LOCKS, GRAPHIC_FRAME_LOCK_KEYS, parseGraphicFrameLocks, serializeGraphicFrameLocks };
@@ -1,6 +1,7 @@
1
1
  import { emuToPixels } from "../utils/units.js";
2
2
  import { parseImage, resolveImageData } from "./imageParser.js";
3
3
  import { findAllDeep, findChildByLocalName, findChildrenByLocalName, getAttribute, getChildElements, getLocalName, getTextContent, parseNumericAttribute } from "./xmlParser.js";
4
+ import { escapeXmlAttribute, escapeXmlText } from "@stll/docx-core";
4
5
  //#region src/docx/groupDrawingParser.ts
5
6
  const HEX_COLOR = /^[0-9A-Fa-f]{6}$/u;
6
7
  const DEFAULT_TEXT_COLOR = "000000";
@@ -12,7 +13,6 @@ const CROP_SCALE = 1e5;
12
13
  const MAX_PATH_COMMANDS = 1e4;
13
14
  const MAX_TEXT_CHARACTERS = 2e4;
14
15
  const MAX_SVG_CHARACTERS = 1e6;
15
- const escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
16
16
  const numericAttr = (element, name) => {
17
17
  const direct = parseNumericAttribute(element, null, name);
18
18
  if (direct !== void 0) return direct;
@@ -108,7 +108,7 @@ const renderTextBox = (wsp) => {
108
108
  const color = colorFrom(findAllDeep(wsp, "w", "color").at(0) ?? null, DEFAULT_TEXT_COLOR);
109
109
  const fontSize = halfPoints * HALF_POINT_TO_EMU;
110
110
  const maxCharacters = Math.max(1, Math.floor(width / (fontSize * .38)));
111
- const lines = paragraphs.flatMap((paragraph) => wrapLine(getTextContent(paragraph).slice(0, MAX_TEXT_CHARACTERS), maxCharacters)).map(escapeXml);
111
+ const lines = paragraphs.flatMap((paragraph) => wrapLine(getTextContent(paragraph).slice(0, MAX_TEXT_CHARACTERS), maxCharacters)).map(escapeXmlText);
112
112
  if (lines.length === 0) return "";
113
113
  const lineHeight = fontSize * 1.15;
114
114
  const svgFontSize = 1e3;
@@ -131,7 +131,7 @@ const renderPicture = (picture, index, rels, media) => {
131
131
  const visibleWidth = 1 - left - right;
132
132
  const visibleHeight = 1 - top - bottom;
133
133
  if (visibleWidth <= 0 || visibleHeight <= 0) return "";
134
- const image = `<image x="${x - width * left / visibleWidth}" y="${y - height * top / visibleHeight}" width="${width / visibleWidth}" height="${height / visibleHeight}" href="${escapeXml(src)}" preserveAspectRatio="none"/>`;
134
+ const image = `<image x="${x - width * left / visibleWidth}" y="${y - height * top / visibleHeight}" width="${width / visibleWidth}" height="${height / visibleHeight}" href="${escapeXmlAttribute(src)}" preserveAspectRatio="none"/>`;
135
135
  if (left === 0 && top === 0 && right === 0 && bottom === 0) return image;
136
136
  const clipId = `group-picture-${index}`;
137
137
  return `<defs><clipPath id="${clipId}"><rect x="${x}" y="${y}" width="${width}" height="${height}"/></clipPath></defs><g clip-path="url(#${clipId})">${image}</g>`;
@@ -155,7 +155,7 @@ function getHeaderFooterText(hf) {
155
155
  function isEmptyHeaderFooter(hf) {
156
156
  if (hf.content.length === 0) return true;
157
157
  for (const item of hf.content) {
158
- if (item.type === "table") return false;
158
+ if (item.type !== "paragraph") return false;
159
159
  if (item.content.length > 0) for (const content of item.content) {
160
160
  if (content.type !== "run") return false;
161
161
  for (const rc of content.content) {
@@ -38,6 +38,7 @@ const normalizeHeaderFooterReferences = ({ documentBody, headers, footers }) =>
38
38
  normalizeTable(block);
39
39
  return;
40
40
  }
41
+ if (block.type === "preservedBlock") return;
41
42
  normalizeBlocks(block.content);
42
43
  };
43
44
  const normalizeBlocks = (blocks) => {
@@ -1,6 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
- import { StyleMap } from "./styleParser.js";
3
2
  import { XmlElement } from "./xmlParser.js";
3
+ import { StyleMap } from "./styleParser.js";
4
+ import { ChildHandlers } from "./containerChildren.js";
4
5
  //#region src/docx/hyperlinkParser.d.ts
5
6
  /**
6
7
  * Parse a hyperlink element (w:hyperlink)
@@ -16,14 +17,32 @@ import { XmlElement } from "./xmlParser.js";
16
17
  * @returns Parsed Hyperlink object
17
18
  */
18
19
  declare function parseHyperlink(node: XmlElement, rels: document_d_exports.RelationshipMap | null, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, media?: Map<string, document_d_exports.MediaFile> | null, rootXmlns?: Record<string, string>): document_d_exports.Hyperlink;
20
+ /** What {@link hyperlinkChildHandlers} needs to read one child of a link. */
21
+ type HyperlinkChildContext = {
22
+ /** Where a parsed or captured child lands, in source order. */
23
+ push: (child: document_d_exports.Hyperlink["children"][number]) => void;
24
+ styles: StyleMap | null;
25
+ theme: document_d_exports.Theme | null;
26
+ rels: document_d_exports.RelationshipMap | null;
27
+ media: Map<string, document_d_exports.MediaFile> | null;
28
+ inScopeXmlns: Record<string, string>;
29
+ };
19
30
  /**
20
- * One `w:hyperlink` child, or `null` for markup the model does not carry.
21
- *
22
- * Exposed so a caller that has to segment a hyperlink — one holding revision
23
- * wrappers, which the model nests the other way round — parses its plain
24
- * children exactly as {@link parseHyperlink} does.
31
+ * What a `w:hyperlink` does with every child its content model declares.
32
+ *
33
+ * `CT_Hyperlink` is `EG_PContent`, so a link may hold a permission range, a
34
+ * proofing error, a nested field or one of the eight custom-XML revision
35
+ * ranges between its runs; folio models three of the thirty-two names and
36
+ * used to drop the other twenty-nine off the end of a `switch`.
37
+ *
38
+ * Two callers read this one map: {@link parseHyperlink}, and the paragraph
39
+ * parser's revision-segmenting walk, which overrides the four
40
+ * `CT_RunTrackChange` wrappers because OOXML nests a revision inside a link
41
+ * and the model nests the link inside the revision. Everything else is
42
+ * decided here once, so a child one caller starts recognising is recognised
43
+ * by both rather than by whichever list somebody remembered to update.
25
44
  */
26
- declare function parseHyperlinkChild(node: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, inScopeXmlns: Record<string, string>): document_d_exports.Hyperlink["children"][number] | null;
45
+ declare const hyperlinkChildHandlers: ({ push, styles, theme, rels, media, inScopeXmlns }: HyperlinkChildContext) => ChildHandlers<"w:hyperlink">;
27
46
  /**
28
47
  * Get the display text of a hyperlink
29
48
  *
@@ -112,4 +131,4 @@ declare function createExternalHyperlink(url: string, children: document_d_expor
112
131
  target?: string;
113
132
  }): document_d_exports.Hyperlink;
114
133
  //#endregion
115
- export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
134
+ export { HyperlinkChildContext, createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, hyperlinkChildHandlers, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
@@ -1,7 +1,9 @@
1
- import { sanitizeExternalUrl, sanitizeLinkTarget } from "../utils/urlSecurity.js";
1
+ import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
2
+ import { CAPTURE, dispatchChildren, withPreservedChildren } from "./containerChildren.js";
3
+ import { preserveInlineChild, preservedInlineCapture } from "./preservedRunContent.js";
2
4
  import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "./relsParser.js";
3
5
  import { parseRun } from "./runParser.js";
4
- import { getAttribute, getChildElements, getLocalName, mergeXmlnsDeclarations, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
6
+ import { getAttribute, mergeXmlnsDeclarations, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
5
7
  //#region src/docx/hyperlinkParser.ts
6
8
  /**
7
9
  * Parse bookmark start (w:bookmarkStart)
@@ -63,32 +65,88 @@ function parseHyperlink(node, rels, styles = null, theme = null, media = null, r
63
65
  const tooltip = getAttribute(node, "w", "tooltip");
64
66
  if (tooltip) hyperlink.tooltip = tooltip;
65
67
  const tgtFrame = getAttribute(node, "w", "tgtFrame");
66
- if (tgtFrame) hyperlink.target = sanitizeLinkTarget(tgtFrame);
68
+ if (tgtFrame) hyperlink.target = tgtFrame;
67
69
  if (parseOnOffAttribute(node, "w", "history") === true) hyperlink.history = true;
68
70
  const docLocation = getAttribute(node, "w", "docLocation");
69
71
  if (docLocation) hyperlink.docLocation = docLocation;
70
72
  const inScopeXmlns = mergeXmlnsDeclarations(rootXmlns, node);
71
- for (const child of getChildElements(node)) {
72
- const parsed = parseHyperlinkChild(child, styles, theme, rels, media, inScopeXmlns);
73
- if (parsed) hyperlink.children.push(parsed);
74
- }
73
+ const children = [];
74
+ hyperlink.children = withPreservedChildren(children, dispatchChildren({
75
+ element: node,
76
+ container: "w:hyperlink",
77
+ modelledCount: () => children.length,
78
+ handlers: hyperlinkChildHandlers({
79
+ push: (child) => {
80
+ children.push(child);
81
+ },
82
+ styles,
83
+ theme,
84
+ rels,
85
+ media,
86
+ inScopeXmlns
87
+ })
88
+ }), preservedInlineCapture);
75
89
  return hyperlink;
76
90
  }
77
91
  /**
78
- * One `w:hyperlink` child, or `null` for markup the model does not carry.
92
+ * What a `w:hyperlink` does with every child its content model declares.
93
+ *
94
+ * `CT_Hyperlink` is `EG_PContent`, so a link may hold a permission range, a
95
+ * proofing error, a nested field or one of the eight custom-XML revision
96
+ * ranges between its runs; folio models three of the thirty-two names and
97
+ * used to drop the other twenty-nine off the end of a `switch`.
79
98
  *
80
- * Exposed so a caller that has to segment a hyperlink — one holding revision
81
- * wrappers, which the model nests the other way round — parses its plain
82
- * children exactly as {@link parseHyperlink} does.
99
+ * Two callers read this one map: {@link parseHyperlink}, and the paragraph
100
+ * parser's revision-segmenting walk, which overrides the four
101
+ * `CT_RunTrackChange` wrappers because OOXML nests a revision inside a link
102
+ * and the model nests the link inside the revision. Everything else is
103
+ * decided here once, so a child one caller starts recognising is recognised
104
+ * by both rather than by whichever list somebody remembered to update.
83
105
  */
84
- function parseHyperlinkChild(node, styles, theme, rels, media, inScopeXmlns) {
85
- switch (getLocalName(node.name)) {
86
- case "r": return parseRun(node, styles, theme, rels, media, inScopeXmlns);
87
- case "bookmarkStart": return parseBookmarkStart(node);
88
- case "bookmarkEnd": return parseBookmarkEnd(node);
89
- default: return null;
90
- }
91
- }
106
+ const hyperlinkChildHandlers = ({ push, styles, theme, rels, media, inScopeXmlns }) => ({
107
+ r: (child) => {
108
+ push(parseRun(child, styles, theme, rels, media, inScopeXmlns));
109
+ },
110
+ bookmarkStart: (child) => {
111
+ push(parseBookmarkStart(child));
112
+ },
113
+ bookmarkEnd: (child) => {
114
+ push(parseBookmarkEnd(child));
115
+ },
116
+ customXml: (child) => {
117
+ push(preserveInlineChild(child));
118
+ },
119
+ smartTag: (child) => {
120
+ push(preserveInlineChild(child));
121
+ },
122
+ del: CAPTURE,
123
+ ins: CAPTURE,
124
+ moveFrom: CAPTURE,
125
+ moveTo: CAPTURE,
126
+ bdo: CAPTURE,
127
+ commentRangeEnd: CAPTURE,
128
+ commentRangeStart: CAPTURE,
129
+ customXmlDelRangeEnd: CAPTURE,
130
+ customXmlDelRangeStart: CAPTURE,
131
+ customXmlInsRangeEnd: CAPTURE,
132
+ customXmlInsRangeStart: CAPTURE,
133
+ customXmlMoveFromRangeEnd: CAPTURE,
134
+ customXmlMoveFromRangeStart: CAPTURE,
135
+ customXmlMoveToRangeEnd: CAPTURE,
136
+ customXmlMoveToRangeStart: CAPTURE,
137
+ dir: CAPTURE,
138
+ fldSimple: CAPTURE,
139
+ hyperlink: CAPTURE,
140
+ moveFromRangeEnd: CAPTURE,
141
+ moveFromRangeStart: CAPTURE,
142
+ moveToRangeEnd: CAPTURE,
143
+ moveToRangeStart: CAPTURE,
144
+ permEnd: CAPTURE,
145
+ permStart: CAPTURE,
146
+ proofErr: CAPTURE,
147
+ sdt: CAPTURE,
148
+ subDoc: CAPTURE
149
+ });
92
150
  /**
93
151
  * Get the display text of a hyperlink
94
152
  *
@@ -219,4 +277,4 @@ function createExternalHyperlink(url, children, options) {
219
277
  };
220
278
  }
221
279
  //#endregion
222
- export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
280
+ export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, hyperlinkChildHandlers, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
@@ -1,6 +1,14 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { XmlElement } from "./xmlParser.js";
3
3
  //#region src/docx/imageParser.d.ts
4
+ /**
5
+ * The `a:ext` uri under which Word records that a drawing is decorative. The
6
+ * extension holds `<adec:decorative val="…"/>`; `CT_NonVisualDrawingProps` has
7
+ * no `@decorative` attribute for it to be written as.
8
+ */
9
+ declare const DECORATIVE_EXTENSION_URI = "{C183D7F6-B498-43B3-948B-1728B52AA6E4}";
10
+ /** The namespace the decorative extension's element is bound to. */
11
+ declare const DECORATIVE_NAMESPACE = "http://schemas.microsoft.com/office/drawing/2017/decorative";
4
12
  /**
5
13
  * Resolve image data from relationships and media map
6
14
  *
@@ -89,4 +97,4 @@ declare function getWrapDistancesPx(image: document_d_exports.Image): {
89
97
  */
90
98
  declare function needsTextWrapping(image: document_d_exports.Image): boolean;
91
99
  //#endregion
92
- export { getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
100
+ export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
@@ -1,12 +1,18 @@
1
+ import { normalizeImageLuminancePercent } from "../utils/imageLuminance.js";
1
2
  import { sanitizeImageSrc } from "../utils/sanitizeImageSrc.js";
2
3
  import { emuToPixels } from "../utils/units.js";
3
4
  import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
4
5
  import { WRAP_ELEMENT_NAMES, parseAnchorBehindDoc, parsePositionH, parsePositionV, parseWrapElement } from "./drawingUtils.js";
5
6
  import { parseGraphicFrameLocks } from "./graphicFrameLocks.js";
7
+ import { parseNonVisualDrawingNames } from "./nonVisualDrawingProps.js";
6
8
  import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "./relsParser.js";
7
9
  import { isTextBoxDrawing } from "./textBoxParser.js";
8
- import { findByFullName, findChild, getAttribute, getChildElements, parseNumericAttribute, parseOnOffValue } from "./xmlParser.js";
10
+ import { percentageSpelling } from "./transitionalSpelling.js";
11
+ import { captureVerbatimXml } from "./verbatimCapture.js";
12
+ import { findByFullName, findChild, findChildByNamespaceUri, findChildrenByNamespaceUri, getAttribute, getChildElements, getLocalName, getNamespaceUri, parseNumericAttribute, parseOnOffAttribute, parseOnOffValue } from "./xmlParser.js";
9
13
  //#region src/docx/imageParser.ts
14
+ const DRAWINGML_MAIN_NAMESPACE_URIS = /* @__PURE__ */ new Set(["http://schemas.openxmlformats.org/drawingml/2006/main", "http://purl.oclc.org/ooxml/drawingml/main"]);
15
+ const FIXED_PERCENTAGE = /^-?\d+$/u;
10
16
  /**
11
17
  * Convert rotation value (1/60000 of a degree) to degrees
12
18
  *
@@ -14,7 +20,7 @@ import { findByFullName, findChild, getAttribute, getChildElements, parseNumeric
14
20
  * @returns Rotation in degrees
15
21
  */
16
22
  function rotToDegrees(rot) {
17
- if (!rot) return;
23
+ if (rot === null || rot === void 0) return;
18
24
  const val = Number.parseInt(rot, 10);
19
25
  if (Number.isNaN(val)) return;
20
26
  return val / 6e4;
@@ -64,6 +70,47 @@ function parseEffectExtent(effectExtent) {
64
70
  };
65
71
  }
66
72
  /**
73
+ * The `a:ext` uri under which Word records that a drawing is decorative. The
74
+ * extension holds `<adec:decorative val="…"/>`; `CT_NonVisualDrawingProps` has
75
+ * no `@decorative` attribute for it to be written as.
76
+ */
77
+ const DECORATIVE_EXTENSION_URI = "{C183D7F6-B498-43B3-948B-1728B52AA6E4}";
78
+ /** The namespace the decorative extension's element is bound to. */
79
+ const DECORATIVE_NAMESPACE = "http://schemas.microsoft.com/office/drawing/2017/decorative";
80
+ /**
81
+ * `wp:docPr`'s extension list is DrawingML's (`a:extLst` holding `a:ext`), in
82
+ * the Transitional or the Strict namespace. Matching on the local name alone
83
+ * would take an `extLst` some other namespace owns and replay its children
84
+ * inside an `a:extLst`, which is a different container than the source wrote.
85
+ */
86
+ const DRAWINGML_NAMESPACE_URIS = /* @__PURE__ */ new Set(["http://schemas.openxmlformats.org/drawingml/2006/main", "http://purl.oclc.org/ooxml/drawingml/main"]);
87
+ /**
88
+ * Read the `wp:docPr` extension list.
89
+ *
90
+ * Only the decorative extension is modeled. The rest — a creation id, a
91
+ * local-DPI hint, whatever a later Word writes — are captured as they were
92
+ * written so the save path can put them back: an extension folio drops is a
93
+ * fact the document had and no longer does.
94
+ */
95
+ const parseDocPropsExtensions = (docPr) => {
96
+ const extLst = findChildByNamespaceUri(docPr, DRAWINGML_NAMESPACE_URIS, "extLst");
97
+ if (!extLst) return { other: [] };
98
+ const result = { other: [] };
99
+ for (const ext of findChildrenByNamespaceUri(extLst, DRAWINGML_NAMESPACE_URIS, "ext")) {
100
+ if (getAttribute(ext, null, "uri")?.toUpperCase() !== "{C183D7F6-B498-43B3-948B-1728B52AA6E4}") {
101
+ result.other.push(captureVerbatimXml(ext));
102
+ continue;
103
+ }
104
+ const flag = getChildElements(ext).find((child) => getLocalName(child.name) === "decorative" && getNamespaceUri(child) === "http://schemas.microsoft.com/office/drawing/2017/decorative");
105
+ if (!flag) {
106
+ result.other.push(captureVerbatimXml(ext));
107
+ continue;
108
+ }
109
+ result.decorative = parseOnOffValue(getAttribute(flag, null, "val")) ?? true;
110
+ }
111
+ return result;
112
+ };
113
+ /**
67
114
  * Parse document properties (wp:docPr)
68
115
  *
69
116
  * @param docPr - wp:docPr element
@@ -72,18 +119,17 @@ function parseEffectExtent(effectExtent) {
72
119
  function parseDocProps(docPr) {
73
120
  if (!docPr) return {};
74
121
  const id = getAttribute(docPr, null, "id");
75
- const name = getAttribute(docPr, null, "name");
76
- const descr = getAttribute(docPr, null, "descr");
77
- const title = getAttribute(docPr, null, "title");
78
- const decorative = parseOnOffValue(getAttribute(docPr, null, "decorative")) === true;
122
+ const names = parseNonVisualDrawingNames(docPr);
123
+ const hidden = parseOnOffAttribute(docPr, null, "hidden");
124
+ const { decorative, other: docPrExtensions } = parseDocPropsExtensions(docPr);
79
125
  const hlinkClickEl = findChild(docPr, "a", "hlinkClick");
80
126
  const hlinkRId = hlinkClickEl ? getAttribute(hlinkClickEl, "r", "id") : null;
81
127
  return {
82
128
  ...id != null ? { id } : {},
83
- ...name != null ? { name } : {},
84
- ...descr != null ? { alt: descr } : {},
85
- ...title != null ? { title } : {},
86
- ...decorative ? { decorative } : {},
129
+ ...names,
130
+ ...decorative === void 0 ? {} : { decorative },
131
+ ...hidden === void 0 ? {} : { hidden },
132
+ ...docPrExtensions.length > 0 ? { docPrExtensions } : {},
87
133
  ...hlinkRId != null ? { hlinkRId } : {}
88
134
  };
89
135
  }
@@ -92,15 +138,14 @@ function parseDocProps(docPr) {
92
138
  */
93
139
  function parseTransform(xfrm) {
94
140
  if (!xfrm) return;
95
- const rot = getAttribute(xfrm, null, "rot");
96
- const flipH = parseOnOffValue(getAttribute(xfrm, null, "flipH")) === true;
97
- const flipV = parseOnOffValue(getAttribute(xfrm, null, "flipV")) === true;
98
- const rotation = rotToDegrees(rot);
99
- if (rotation === void 0 && !flipH && !flipV) return;
141
+ const flipH = parseOnOffValue(getAttribute(xfrm, null, "flipH"));
142
+ const flipV = parseOnOffValue(getAttribute(xfrm, null, "flipV"));
143
+ const rotation = rotToDegrees(getAttribute(xfrm, null, "rot"));
144
+ if (rotation === void 0 && flipH === void 0 && flipV === void 0) return;
100
145
  const transform = {};
101
146
  if (rotation !== void 0) transform.rotation = rotation;
102
- if (flipH) transform.flipH = true;
103
- if (flipV) transform.flipV = true;
147
+ if (flipH !== void 0) transform.flipH = flipH;
148
+ if (flipV !== void 0) transform.flipV = flipV;
104
149
  return transform;
105
150
  }
106
151
  /**
@@ -177,6 +222,24 @@ function parseImageOpacity(blip) {
177
222
  if (amt === void 0 || amt >= 1e5) return;
178
223
  return Math.max(0, amt / 1e5);
179
224
  }
225
+ const parseLuminancePercent = (luminance, attribute) => {
226
+ const raw = getAttribute(luminance, null, attribute);
227
+ if (raw === null) return;
228
+ const percent = percentageSpelling(raw) ?? (FIXED_PERCENTAGE.test(raw.trim()) ? Number(raw) / 1e3 : void 0);
229
+ return percent === void 0 || !Number.isFinite(percent) ? void 0 : normalizeImageLuminancePercent(percent);
230
+ };
231
+ /** Parse DrawingML `a:lum` into signed percentage values, preserving explicit zeroes. */
232
+ function parseImageLuminance(blip) {
233
+ const luminance = findChildByNamespaceUri(blip, DRAWINGML_MAIN_NAMESPACE_URIS, "lum");
234
+ if (!luminance) return;
235
+ const brightness = parseLuminancePercent(luminance, "bright");
236
+ const contrast = parseLuminancePercent(luminance, "contrast");
237
+ if (brightness === void 0 && contrast === void 0) return;
238
+ return {
239
+ ...brightness === void 0 ? {} : { brightness },
240
+ ...contrast === void 0 ? {} : { contrast }
241
+ };
242
+ }
180
243
  /**
181
244
  * Extract rId from a:blip element.
182
245
  *
@@ -308,6 +371,7 @@ function parseInline(inlineEl, rels, media) {
308
371
  const rId = extractBlipRId(blip);
309
372
  const crop = parseImageCrop(blipFill);
310
373
  const opacity = parseImageOpacity(blip);
374
+ const effects = parseImageLuminance(blip);
311
375
  const imageData = resolveImageData(rId, rels, media);
312
376
  const transform = parseTransform(findPictureTransform(inlineEl));
313
377
  const distT = parseNumericAttribute(inlineEl, null, "distT") ?? void 0;
@@ -329,7 +393,9 @@ function parseInline(inlineEl, rels, media) {
329
393
  if (props.name !== void 0) image.docPrName = props.name;
330
394
  if (props.alt !== void 0) image.alt = props.alt;
331
395
  if (props.title !== void 0) image.title = props.title;
332
- if (props.decorative) image.decorative = true;
396
+ if (props.decorative !== void 0) image.decorative = props.decorative;
397
+ if (props.hidden !== void 0) image.hidden = props.hidden;
398
+ if (props.docPrExtensions !== void 0) image.docPrExtensions = props.docPrExtensions;
333
399
  const safeSrc = sanitizeImageSrc(imageData.src);
334
400
  if (safeSrc) image.src = safeSrc;
335
401
  if (imageData.mimeType) image.mimeType = imageData.mimeType;
@@ -338,6 +404,7 @@ function parseInline(inlineEl, rels, media) {
338
404
  if (transform) image.transform = transform;
339
405
  if (crop) image.crop = crop;
340
406
  if (opacity !== void 0) image.opacity = opacity;
407
+ if (effects !== void 0) image.effects = effects;
341
408
  if (frameLocks) image.frameLocks = frameLocks;
342
409
  const hlink = resolveRelationshipIdOfType(rels, props.hlinkRId, RELATIONSHIP_TYPES.hyperlink);
343
410
  if (hlink.status === "resolved") {
@@ -390,6 +457,7 @@ function parseAnchor(anchorEl, rels, media) {
390
457
  const rId = extractBlipRId(blip);
391
458
  const crop = parseImageCrop(blipFill);
392
459
  const opacity = parseImageOpacity(blip);
460
+ const effects = parseImageLuminance(blip);
393
461
  const imageData = resolveImageData(rId, rels, media);
394
462
  const transform = parseTransform(findPictureTransform(anchorEl));
395
463
  const image = {
@@ -402,7 +470,9 @@ function parseAnchor(anchorEl, rels, media) {
402
470
  if (props.name !== void 0) image.docPrName = props.name;
403
471
  if (props.alt !== void 0) image.alt = props.alt;
404
472
  if (props.title !== void 0) image.title = props.title;
405
- if (props.decorative) image.decorative = true;
473
+ if (props.decorative !== void 0) image.decorative = props.decorative;
474
+ if (props.hidden !== void 0) image.hidden = props.hidden;
475
+ if (props.docPrExtensions !== void 0) image.docPrExtensions = props.docPrExtensions;
406
476
  const safeSrc = sanitizeImageSrc(imageData.src);
407
477
  if (safeSrc) image.src = safeSrc;
408
478
  if (imageData.mimeType) image.mimeType = imageData.mimeType;
@@ -412,6 +482,7 @@ function parseAnchor(anchorEl, rels, media) {
412
482
  if (transform) image.transform = transform;
413
483
  if (crop) image.crop = crop;
414
484
  if (opacity !== void 0) image.opacity = opacity;
485
+ if (effects !== void 0) image.effects = effects;
415
486
  if (frameLocks) image.frameLocks = frameLocks;
416
487
  if (layoutInCell !== void 0) image.layoutInCell = layoutInCell;
417
488
  if (allowOverlap !== void 0) image.allowOverlap = allowOverlap;
@@ -537,4 +608,4 @@ function needsTextWrapping(image) {
537
608
  ].includes(image.wrap.type);
538
609
  }
539
610
  //#endregion
540
- export { getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
611
+ export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
@@ -12,7 +12,20 @@ declare const isDrawingRawXmlMode: (value: unknown) => value is document_d_expor
12
12
  declare const EDITED_PREVIEW_FINGERPRINT = "editedPreview";
13
13
  /** Fingerprints modeled image fields which make raw DrawingML stale when edited. */
14
14
  declare const imageRawXmlFingerprint: (image: document_d_exports.Image) => string;
15
- /** Editable raw drawing XML can replay only while its modeled projection is unchanged. */
15
+ /**
16
+ * Whether the serializer writes the captured raw XML back.
17
+ *
18
+ * For an unclassified drawing the capture is a cache of the model, so it
19
+ * replays only while the two agree. For a classified one the capture *is* the
20
+ * drawing: a preserve-only drawing has a placeholder image, and a preview-only
21
+ * group has a raster render of shapes the model cannot hold. Regenerating
22
+ * either writes something the source never contained — for the group, at best
23
+ * the one child picture the rasterizer saw first under that child's
24
+ * relationship, in place of the whole group. So a classified capture is always
25
+ * written back; a stale fingerprint means the edit that made it stale is lost,
26
+ * which {@link classifyDrawingSafety} reports as `opaque`, and never that
27
+ * folio may build a replacement.
28
+ */
16
29
  declare const canReplayEditableImageRawXml: (drawing: document_d_exports.DrawingContent) => boolean;
17
30
  /**
18
31
  * What a drawing costs the document when Folio writes it back.