@stll/folio-core 0.57.0 → 0.58.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/ai-edits/apply.js +77 -8
  2. package/dist/ai-edits/headless.js +7 -3
  3. package/dist/controller/canonicalClipboard.d.ts +3 -1
  4. package/dist/controller/canonicalClipboard.js +24 -12
  5. package/dist/controller/canonicalComposition.d.ts +13 -4
  6. package/dist/controller/canonicalComposition.js +82 -9
  7. package/dist/controller/canonicalInput.d.ts +1 -1
  8. package/dist/controller/canonicalInput.js +4 -3
  9. package/dist/controller/canonicalSelection.js +10 -1
  10. package/dist/controller/canonicalSession.d.ts +1 -1
  11. package/dist/controller/canonicalSession.js +59 -23
  12. package/dist/controller/canonicalStoryEditor.d.ts +1 -1
  13. package/dist/controller/canonicalStoryEditor.js +1 -1
  14. package/dist/controller/canonicalStructure.js +8 -3
  15. package/dist/controller/hiddenEditorApi.js +1 -1
  16. package/dist/controller/hiddenEditorManager.js +1 -1
  17. package/dist/docx/headerFooterVerbatim.d.ts +15 -3
  18. package/dist/docx/headerFooterVerbatim.js +50 -8
  19. package/dist/docx/listRendering.d.ts +18 -0
  20. package/dist/{prosemirror/conversion/listRenderingDefinition.js → docx/listRendering.js} +17 -3
  21. package/dist/docx/parser.js +1 -1
  22. package/dist/docx/server/materializeYjsDocx.js +1 -1
  23. package/dist/markdown/internals.js +7 -0
  24. package/dist/markdown/renderParagraph.js +11 -12
  25. package/dist/markdown/renderRuns.js +2 -2
  26. package/dist/markdown/types.d.ts +3 -0
  27. package/dist/prosemirror/attrs/index.js +4 -0
  28. package/dist/prosemirror/conversion/fromProseDoc.d.ts +16 -1
  29. package/dist/prosemirror/conversion/fromProseDoc.js +149 -27
  30. package/dist/prosemirror/conversion/toProseDoc.js +10 -23
  31. package/dist/prosemirror/extensions/nodes/ImageExtension.js +8 -1
  32. package/dist/prosemirror/imagePictureNames.d.ts +12 -0
  33. package/dist/prosemirror/imagePictureNames.js +20 -0
  34. package/dist/prosemirror/paragraphFormattingProvenance.js +1 -0
  35. package/dist/prosemirror/runStyleFormatting.d.ts +72 -2
  36. package/dist/prosemirror/runStyleFormatting.js +18 -1
  37. package/dist/prosemirror/schema/nodes.d.ts +1 -0
  38. package/dist/prosemirror/styles/styleResolver.d.ts +4 -1
  39. package/dist/prosemirror/styles/styleResolver.js +32 -11
  40. package/dist/types/canonicalCapabilities.d.ts +15 -1
  41. package/dist/types/canonicalCapabilities.js +15 -1
  42. package/package.json +2 -2
  43. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +0 -6
@@ -1,6 +1,7 @@
1
1
  import { joinCommentRangesAcrossParagraphs } from "../../docx/commentRangeJoin.js";
2
2
  import { completeCommentReferences } from "../../docx/commentReferenceCompletion.js";
3
3
  import { normalizeFoldedListNumbers } from "../../docx/foldedListNumberFields.js";
4
+ import { getDocumentSourceStyles } from "../../docx/headerFooterVerbatim.js";
4
5
  import { EDITED_PREVIEW_FINGERPRINT, imageRawXmlFingerprint } from "../../docx/imageRawXml.js";
5
6
  import { isInlineSdtContent, isSimpleFieldContent } from "../../docx/inlineWrapperContent.js";
6
7
  import { paragraphNumberingReferenceId as paragraphNumberingReferenceId$1, sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "../../docx/numberingReference.js";
@@ -43,7 +44,7 @@ import { expectRangeAnchorAttrs } from "../rangeAnchorAttrs.js";
43
44
  import { marksToTextFormatting, sameFormattingValue } from "../runFormattingFromMarks.js";
44
45
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
45
46
  import { RUN_IDENTITY_MARK_NAME } from "../runIdentity.js";
46
- import { paragraphFormattingForRun, paragraphRunStyleContext, resolveEffectiveRunStyleFormatting } from "../runStyleFormatting.js";
47
+ import { paragraphFormattingForRun, paragraphRunStyleContext, resolveEffectiveRunStyleFormatting, resolveParagraphInheritedRunFormatting } from "../runStyleFormatting.js";
47
48
  import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
48
49
  import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
49
50
  import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
@@ -52,7 +53,7 @@ import { enclosingInsertionAncestors, inlineWrapperStackOf } from "../trackedRev
52
53
  import { assertValidProseMirrorDocument } from "../validation.js";
53
54
  import { hasSinkChildren } from "./preservedSinkCarriers.js";
54
55
  import { decodeSdtListItems, sdtPropertiesFromAttrs, sdtPropertiesMatchAttrs } from "./sdtAttrs.js";
55
- import { panic } from "better-result";
56
+ import { TaggedError, panic } from "better-result";
56
57
  import { DRAWING_RAW_XML_MODES, relationshipIdOf } from "@stll/docx-core/model";
57
58
  import { Fragment } from "prosemirror-model";
58
59
  //#region src/prosemirror/conversion/fromProseDoc.ts
@@ -270,8 +271,103 @@ const restoreLinkedParagraphPropertySources = (content) => {
270
271
  sources: new Set(targetsBySource.keys())
271
272
  };
272
273
  };
274
+ var SaveStylesheetSourceMismatch = class extends TaggedError("SaveStylesheetSourceMismatch") {};
275
+ const parsedPackageStyles = (document, liveStyles) => {
276
+ const source = getDocumentSourceStyles(document, liveStyles);
277
+ switch (source.type) {
278
+ case "captured": {
279
+ if (source.styles !== void 0 && source.additions.length === 0) return source.styles;
280
+ const addedIds = /* @__PURE__ */ new Set();
281
+ for (const addition of source.additions) {
282
+ if (addedIds.has(addition.styleId)) throw new SaveStylesheetSourceMismatch({
283
+ message: `Duplicate added style ID: ${addition.styleId}.`,
284
+ divergences: [{
285
+ type: "style",
286
+ styleId: addition.styleId
287
+ }]
288
+ });
289
+ addedIds.add(addition.styleId);
290
+ }
291
+ if (source.styles === void 0) return liveStyles === void 0 ? void 0 : structuredClone(liveStyles);
292
+ return {
293
+ ...source.styles,
294
+ styles: [...source.styles.styles, ...structuredClone(source.additions)]
295
+ };
296
+ }
297
+ case "missing":
298
+ case "mismatch": throw new SaveStylesheetSourceMismatch({
299
+ message: "The parsed package stylesheet source is unavailable.",
300
+ divergences: [{ type: "sourceUnavailable" }]
301
+ });
302
+ default: return panic(`Unexpected stylesheet source capture: ${JSON.stringify(source)}`);
303
+ }
304
+ };
305
+ const assertSuppliedStylesMatchSource = (styles, baseDocument) => {
306
+ if (!baseDocument?.originalBuffer) return;
307
+ const sourceStyles = parsedPackageStyles(baseDocument);
308
+ if (!sourceStyles) return;
309
+ const suppliedById = new Map(styles.styles.map((style) => [style.styleId, style]));
310
+ const sourceById = new Map(sourceStyles.styles.map((style) => [style.styleId, style]));
311
+ const divergentIds = /* @__PURE__ */ new Set();
312
+ for (const style of sourceStyles.styles) if (canonicalJson(style) !== canonicalJson(suppliedById.get(style.styleId))) divergentIds.add(style.styleId);
313
+ for (const style of styles.styles) if (canonicalJson(style) !== canonicalJson(suppliedById.get(style.styleId))) divergentIds.add(style.styleId);
314
+ const persistedStyles = {
315
+ ...sourceStyles,
316
+ styles: [...sourceStyles.styles, ...styles.styles.filter(({ styleId }) => !sourceById.has(styleId))]
317
+ };
318
+ const suppliedResolver = createStyleEngine(styles);
319
+ const persistedResolver = createStyleEngine(persistedStyles);
320
+ for (const [supplied, persisted] of [
321
+ [suppliedResolver.getDefaultParagraphStyle(), persistedResolver.getDefaultParagraphStyle()],
322
+ [suppliedResolver.getDefaultCharacterStyle(), persistedResolver.getDefaultCharacterStyle()],
323
+ [suppliedResolver.getDefaultTableStyle(), persistedResolver.getDefaultTableStyle()]
324
+ ]) {
325
+ if (supplied?.styleId === persisted?.styleId) continue;
326
+ if (supplied) divergentIds.add(supplied.styleId);
327
+ if (persisted) divergentIds.add(persisted.styleId);
328
+ }
329
+ const divergences = [];
330
+ for (const styleId of divergentIds) divergences.push({
331
+ type: "style",
332
+ styleId
333
+ });
334
+ if (canonicalJson(styles.docDefaults) !== canonicalJson(sourceStyles.docDefaults)) divergences.push({ type: "docDefaults" });
335
+ if (divergences.length === 0) return;
336
+ throw new SaveStylesheetSourceMismatch({
337
+ message: `Supplied stylesheet differs from the parsed package: ${[...divergentIds, ...divergences.some(({ type }) => type === "docDefaults") ? ["docDefaults"] : []].join(", ")}.`,
338
+ divergences
339
+ });
340
+ };
341
+ const saveStylesheet = (source, baseDocument) => {
342
+ switch (source.type) {
343
+ case "package":
344
+ if (!baseDocument?.originalBuffer) return baseDocument?.package.styles;
345
+ return parsedPackageStyles(baseDocument, baseDocument.package.styles);
346
+ case "supplied":
347
+ assertSuppliedStylesMatchSource(source.styles, baseDocument);
348
+ return source.styles;
349
+ default: return panic(`Unexpected stylesheet source: ${JSON.stringify(source)}`);
350
+ }
351
+ };
352
+ var MissingSaveStylesheet = class extends TaggedError("MissingSaveStylesheet") {};
353
+ const assertSaveStylesheetAvailable = ({ pmDoc, styles, baseDocument, stylesheetSource }) => {
354
+ if (styles !== void 0) return;
355
+ if (stylesheetSource.type === "package" && baseDocument !== void 0) return;
356
+ pmDoc.descendants((node) => {
357
+ if ((() => {
358
+ switch (node.type.name) {
359
+ case "paragraph": {
360
+ const attrs = expectParagraphAttrs(node);
361
+ return attrs.styleId ?? attrs._originalFormatting?.runProperties?.styleId;
362
+ }
363
+ case "table": return expectTableAttrs(node).styleId;
364
+ default: return;
365
+ }
366
+ })() != null || node.marks.some(({ type }) => type.name === "characterStyle")) throw new MissingSaveStylesheet({ message: "Saving style-dependent content requires its authoritative stylesheet." });
367
+ });
368
+ };
273
369
  /** Convert a ProseMirror document to the document model. */
274
- function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
370
+ function fromProseDoc(pmDoc, baseDocument, { stylesheetSource, reuse = "none" }) {
275
371
  assertNoteReferenceOccurrences(pmDoc);
276
372
  switch (reuse) {
277
373
  case "none": break;
@@ -284,7 +380,14 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
284
380
  const proseContract = getProseDocumentParagraphPropertySourceContract(pmDoc);
285
381
  if (proseContractAttribute !== null && proseContractAttribute !== void 0 && proseContract === null || (baseContract ?? null) !== proseContract) throw sourceValidationError("contract_mismatch", "The ProseMirror document does not match its paragraph-property source document.");
286
382
  const tokenSources = baseContract && proseContract && baseDocument ? validateParagraphPropertySourceTokens(pmDoc, baseDocument, baseContract) : null;
287
- const blocks = extractBlocks(pmDoc, "resolve", baseDocument?.package.styles ? createStyleEngine(baseDocument.package.styles) : null);
383
+ const styles = saveStylesheet(stylesheetSource, baseDocument);
384
+ assertSaveStylesheetAvailable({
385
+ pmDoc,
386
+ styles,
387
+ baseDocument,
388
+ stylesheetSource
389
+ });
390
+ const blocks = extractBlocks(pmDoc, "resolve", createStyleEngine(styles));
288
391
  joinCommentRangesAcrossParagraphs(blocks);
289
392
  completeCommentReferences(blocks);
290
393
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
@@ -302,6 +405,7 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
302
405
  package: {
303
406
  ...baseDocument.package,
304
407
  document: documentBody,
408
+ styles,
305
409
  ...numbering ? { numbering } : {}
306
410
  }
307
411
  };
@@ -310,6 +414,7 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
310
414
  }
311
415
  return { package: {
312
416
  document: documentBody,
417
+ ...styles ? { styles } : {},
313
418
  ...numbering ? { numbering } : {}
314
419
  } };
315
420
  }
@@ -324,12 +429,13 @@ const hasSuggestedInsertion = (marks) => marks.some((mark) => mark.type.name ===
324
429
  * Returns the input array unchanged when there is nothing to strip so callers
325
430
  * can skip rebuilding the node.
326
431
  */
327
- function stripSuggestedInlineMarks(marks, { baseParagraphFormatting, inheritedFormatting, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver }) {
432
+ function stripSuggestedInlineMarks(marks, readFormattingContext) {
328
433
  const hasSuggestedDeletion = marks.some((mark) => mark.type.name === "deletion" && isSuggestedMark(mark));
329
434
  const suggestedRunPropertyChange = marks.find((mark) => mark.type.name === "runPropertyChange" && isSuggestedMark(mark));
330
435
  if (!hasSuggestedDeletion && !suggestedRunPropertyChange) return marks;
331
436
  let next = marks.filter((mark) => !((mark.type.name === "deletion" || mark.type.name === "runPropertyChange") && isSuggestedMark(mark)));
332
437
  if (suggestedRunPropertyChange) {
438
+ const { baseParagraphFormatting, inheritedFormatting, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver } = readFormattingContext();
333
439
  const previousFormatting = expectRunPropertyChangeMarkAttrs(suggestedRunPropertyChange).changes.at(0)?.previousFormatting;
334
440
  const characterStyleMark = marks.find(({ type }) => type.name === "characterStyle");
335
441
  const characterStyleAttrs = characterStyleMark ? expectCharacterStyleMarkAttrs(characterStyleMark) : void 0;
@@ -435,6 +541,21 @@ function isSuggestedInsertedNode(node) {
435
541
  }
436
542
  return false;
437
543
  }
544
+ const savedParagraphRunStyleContext = (paragraph, styleResolver) => {
545
+ const context = paragraphRunStyleContext(paragraph, styleResolver);
546
+ if (paragraph.content.size === 0) return context;
547
+ const attrs = expectParagraphAttrs(paragraph);
548
+ const source = resolveParagraphInheritedRunFormatting({
549
+ styleId: attrs.styleId,
550
+ styleResolver,
551
+ tableRunFormatting: attrs._tableRunFormatting,
552
+ paragraphMarkFormatting: attrs.styleId === void 0 ? context.paragraphMarkFormatting : void 0
553
+ });
554
+ return {
555
+ ...context,
556
+ paragraphFormatting: source.inheritedFormatting
557
+ };
558
+ };
438
559
  /**
439
560
  * Recursively rewrite a ProseMirror node tree, removing every suggested
440
561
  * tracked change. Returns `null` when the node itself must be dropped: a
@@ -442,32 +563,32 @@ function isSuggestedInsertedNode(node) {
442
563
  * Surviving block nodes are rebuilt with their suggested delete/merge markers
443
564
  * cleared and their children stripped.
444
565
  */
445
- function mapSuggestionStrippedNode(node, formattingContext = {
446
- baseParagraphFormatting: void 0,
447
- inheritedFormatting: void 0,
448
- paragraphMarkFormatting: void 0,
449
- paragraphMarkPrecedesStyle: false,
450
- styleResolver: null
451
- }) {
566
+ function mapSuggestionStrippedNode(node, readFormattingContext) {
452
567
  if (node.isInline) {
453
568
  if (hasSuggestedInsertion(node.marks)) return null;
454
- const marks = stripSuggestedInlineMarks(node.marks, formattingContext);
569
+ const marks = stripSuggestedInlineMarks(node.marks, readFormattingContext);
455
570
  return marks === node.marks ? node : node.mark(marks);
456
571
  }
457
572
  if (isSuggestedInsertedNode(node)) return null;
458
573
  const nextAttrs = stripSuggestedNodeAttrs(node);
459
574
  const children = [];
460
575
  let changed = nextAttrs !== null;
461
- const paragraphStyleContext = node.type.name === "paragraph" ? paragraphRunStyleContext(node, formattingContext.styleResolver) : void 0;
462
- const childFormattingContext = paragraphStyleContext ? {
463
- baseParagraphFormatting: paragraphStyleContext.baseParagraphFormatting,
464
- inheritedFormatting: paragraphStyleContext.paragraphFormatting,
465
- paragraphMarkFormatting: paragraphStyleContext.paragraphMarkFormatting,
466
- paragraphMarkPrecedesStyle: paragraphStyleContext.paragraphMarkPrecedesStyle,
467
- styleResolver: formattingContext.styleResolver
468
- } : formattingContext;
576
+ let resolvedChildContext;
577
+ const readChildFormattingContext = node.type.name === "paragraph" ? () => {
578
+ if (resolvedChildContext) return resolvedChildContext;
579
+ const { styleResolver } = readFormattingContext();
580
+ const paragraphStyleContext = savedParagraphRunStyleContext(node, styleResolver);
581
+ resolvedChildContext = {
582
+ baseParagraphFormatting: paragraphStyleContext.baseParagraphFormatting,
583
+ inheritedFormatting: paragraphStyleContext.paragraphFormatting,
584
+ paragraphMarkFormatting: paragraphStyleContext.paragraphMarkFormatting,
585
+ paragraphMarkPrecedesStyle: paragraphStyleContext.paragraphMarkPrecedesStyle,
586
+ styleResolver
587
+ };
588
+ return resolvedChildContext;
589
+ } : readFormattingContext;
469
590
  node.forEach((child) => {
470
- const mapped = mapSuggestionStrippedNode(child, childFormattingContext);
591
+ const mapped = mapSuggestionStrippedNode(child, readChildFormattingContext);
471
592
  if (mapped === null) {
472
593
  changed = true;
473
594
  return;
@@ -488,13 +609,13 @@ function mapSuggestionStrippedNode(node, formattingContext = {
488
609
  * {@link extractBlocks} for why this is the sole serialization boundary.
489
610
  */
490
611
  function stripSuggestedProvenance(doc, styleResolver) {
491
- return mapSuggestionStrippedNode(doc, {
612
+ return mapSuggestionStrippedNode(doc, () => ({
492
613
  baseParagraphFormatting: void 0,
493
614
  inheritedFormatting: void 0,
494
615
  paragraphMarkFormatting: void 0,
495
616
  paragraphMarkPrecedesStyle: false,
496
617
  styleResolver
497
- }) ?? doc;
618
+ })) ?? doc;
498
619
  }
499
620
  function materializeNumberedRefValues(doc) {
500
621
  const results = resolveNumberedRefFields(doc);
@@ -946,7 +1067,7 @@ function appendPageBreaks(paragraph, count) {
946
1067
  */
947
1068
  function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleResolver = null) {
948
1069
  const attrs = expectParagraphAttrs(node);
949
- const paragraphStyleContext = paragraphRunStyleContext(node, styleResolver);
1070
+ const paragraphStyleContext = savedParagraphRunStyleContext(node, styleResolver);
950
1071
  let content = extractParagraphContent(node, documentCounts, attrs._emptyHyperlinks ?? void 0, textBoxAnchorMarkers, attrs.renderedPageBreakBefore === true, {
951
1072
  baseParagraphFormatting: paragraphStyleContext.baseParagraphFormatting,
952
1073
  inheritedFormatting: paragraphStyleContext.paragraphFormatting,
@@ -1394,7 +1515,7 @@ const nestInlineWrapperGroups = (items, groups, hyperlinkIndices, revisionOuterW
1394
1515
  function extractParagraphContent(originalParagraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
1395
1516
  const paragraph = coalesceNoteReferenceOccurrences(originalParagraph);
1396
1517
  const content = [];
1397
- const paragraphStyleContext = paragraph.type.name === "paragraph" ? paragraphRunStyleContext(paragraph) : void 0;
1518
+ const paragraphStyleContext = inheritedFormattingOverride === void 0 && paragraph.type.name === "paragraph" ? savedParagraphRunStyleContext(paragraph) : void 0;
1398
1519
  const formattingContext = inheritedFormattingOverride ?? {
1399
1520
  baseParagraphFormatting: paragraphStyleContext?.baseParagraphFormatting,
1400
1521
  inheritedFormatting: paragraphStyleContext?.paragraphFormatting,
@@ -2597,6 +2718,7 @@ function createImageRun(node) {
2597
2718
  },
2598
2719
  wrap
2599
2720
  };
2721
+ if (attrs.pictureNames != null) image.pictureNames = { ...attrs.pictureNames };
2600
2722
  if (attrs.docPrName != null) image.docPrName = attrs.docPrName;
2601
2723
  if (attrs.alt != null) image.alt = attrs.alt;
2602
2724
  if (attrs.title != null) image.title = attrs.title;
@@ -3327,7 +3449,7 @@ function convertPMTextBox(node, styleResolver = null) {
3327
3449
  * Preserves all non-content parts of the original document
3328
3450
  */
3329
3451
  function updateDocumentContent(originalDocument, pmDoc) {
3330
- return fromProseDoc(pmDoc, originalDocument);
3452
+ return fromProseDoc(pmDoc, originalDocument, { stylesheetSource: { type: "package" } });
3331
3453
  }
3332
3454
  /**
3333
3455
  * Convert a ProseMirror document back to an array of `BlockContent` blocks
@@ -1,7 +1,8 @@
1
1
  import { rangedCommentIds } from "../../docx/commentAnchorIndex.js";
2
2
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
3
3
  import { isInlineSdtContent, isTrackedChangeWrapperChild } from "../../docx/inlineWrapperContent.js";
4
- import { computeListRendering, getCachedNumberingMap } from "../../docx/numberingParser.js";
4
+ import { listRenderingDefinitionsMatch, resolveListRenderingDefinition } from "../../docx/listRendering.js";
5
+ import { getCachedNumberingMap } from "../../docx/numberingParser.js";
5
6
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, paragraphFormattingWithAuthoredIndentation, proseParagraphAttrsWithoutPropertySource, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
6
7
  import { isBaselineVertAlign } from "../../docx/runParser.js";
7
8
  import { replayableShapeAlternateContent } from "../../docx/shapeAlternateContent.js";
@@ -41,7 +42,7 @@ import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
41
42
  import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
42
43
  import { RUN_IDENTITY_MARK_NAME, hasRunIdentityPayload, runIdentityAttrs } from "../runIdentity.js";
43
44
  import { continueRunIdentitiesAcrossRevisions } from "../runIdentityAcrossRevisions.js";
44
- import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
45
+ import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, resolveParagraphInheritedRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
45
46
  import { schema } from "../schema/index.js";
46
47
  import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
47
48
  import { extractTableParagraphOverlay, paragraphStyleCascadeAttrs, resolveRunFormattingWithoutDefaults } from "../styles/paragraphStyleCascade.js";
@@ -52,7 +53,6 @@ import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trac
52
53
  import { assertValidProseMirrorDocument } from "../validation.js";
53
54
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
54
55
  import { HYPHEN_TEXT_CARRIERS } from "./hyphenTextCarriers.js";
55
- import { listRenderingDefinitionsMatch } from "./listRenderingDefinition.js";
56
56
  import { createMarkInterner } from "./markInterner.js";
57
57
  import { hasSinkChildren } from "./preservedSinkCarriers.js";
58
58
  import { sdtAttrsFromProperties } from "./sdtAttrs.js";
@@ -407,13 +407,7 @@ const resolveListRendering = (numPr, context) => {
407
407
  const key = `${numPr.numId}:${numPr.ilvl ?? 0}`;
408
408
  const cached = context.listRenderings.get(key);
409
409
  if (cached !== void 0) return cached;
410
- const numbering = context.numbering;
411
- const rendering = numbering === void 0 ? null : computeListRendering(numPr, numbering);
412
- const nextLevel = numbering?.getLevel(numPr.numId, (numPr.ilvl ?? 0) + 1);
413
- const resolved = {
414
- rendering,
415
- nextSlotOffset: nextLevel?.pPr?.hangingIndent === true && nextLevel.pPr.indentFirstLine !== void 0 && nextLevel.pPr.indentFirstLine < 0 ? -nextLevel.pPr.indentFirstLine : void 0
416
- };
410
+ const resolved = resolveListRenderingDefinition(numPr, context.numbering);
417
411
  context.listRenderings.set(key, resolved);
418
412
  return resolved;
419
413
  };
@@ -436,7 +430,7 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
436
430
  if (directFormatting === void 0) Reflect.deleteProperty(attrs, "_originalFormatting");
437
431
  else attrs._originalFormatting = directFormatting;
438
432
  const numPr = mergeParagraphNumbering(attrs.numPrFromStyle ?? void 0, attrs.numPr ?? void 0);
439
- if (numPr?.kind === "none") Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
433
+ if (numPr?.kind === "none" || paragraph.listRendering !== void 0 && context.numbering !== void 0 && numPr === void 0) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
440
434
  else if (context.numbering !== void 0 && numPr?.kind === "reference") {
441
435
  Object.assign(attrs, listIndentationProvenancePatch({
442
436
  direct: paragraphIndentationFromFormatting(directFormatting),
@@ -480,20 +474,12 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
480
474
  const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
481
475
  let inheritableParagraphRunFormatting;
482
476
  if (paragraphRunFormatting && !isTocParagraph && paragraph.formatting?.styleId === void 0) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
483
- const { baseFormatting: baseRunFormatting, baseToggleCascade: orderedToggleFormatting, defaultFormatting: ordinaryBaseWithDefaultCharacter, defaultToggleCascade: defaultCharacterStyleCascade } = resolveParagraphBodyRunFormatting({
477
+ const { baseFormatting: baseRunFormatting, baseToggleCascade: orderedToggleFormatting, defaultFormatting: ordinaryBaseWithDefaultCharacter, defaultToggleCascade: defaultCharacterStyleCascade, inheritedFormatting: defaultRunFormatting, inheritedToggleCascade: defaultToggleCascade } = resolveParagraphInheritedRunFormatting({
484
478
  styleId: paragraph.formatting?.styleId,
485
479
  tableRunFormatting: extraRunFormatting,
486
- styleResolver
480
+ styleResolver,
481
+ paragraphMarkFormatting: inheritableParagraphRunFormatting
487
482
  });
488
- const ordinaryDefaultRunFormatting = mergeTextFormatting(ordinaryBaseWithDefaultCharacter, inheritableParagraphRunFormatting);
489
- const defaultToggleCascade = cascadeStyleTextFormatting([{
490
- cascade: defaultCharacterStyleCascade,
491
- type: "carried"
492
- }, {
493
- formatting: inheritableParagraphRunFormatting,
494
- type: "direct"
495
- }], { ordinaryFormatting: ordinaryDefaultRunFormatting });
496
- const defaultRunFormatting = defaultToggleCascade.formatting;
497
483
  if (extraRunFormatting !== void 0 || paragraph.content.length > 0) {
498
484
  if (extraRunFormatting !== void 0) attrs._tableRunFormatting = extraRunFormatting;
499
485
  if (defaultRunFormatting) attrs.defaultTextFormatting = defaultRunFormatting;
@@ -808,7 +794,7 @@ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, runS
808
794
  return nodes.map((node) => withTrackedRunMark(node, mark, ancestor));
809
795
  }
810
796
  function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay) {
811
- const formatting = paragraph.formatting;
797
+ const formatting = paragraphFormattingWithAuthoredIndentation(paragraph);
812
798
  const styleId = formatting?.styleId;
813
799
  const styleName = styleId ? styleResolver?.getStyle(styleId)?.name : void 0;
814
800
  const tableOfContentsLevel = tableOfContentsStyleLevel({
@@ -2241,6 +2227,7 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
2241
2227
  src: image.src || "",
2242
2228
  preview: image.preview,
2243
2229
  docPrName: image.docPrName,
2230
+ pictureNames: image.pictureNames === void 0 ? void 0 : { ...image.pictureNames },
2244
2231
  alt: image.alt,
2245
2232
  title: image.title,
2246
2233
  width: widthPx,
@@ -1,5 +1,6 @@
1
1
  import { imageLuminanceFilter } from "../../../utils/imageLuminance.js";
2
2
  import { expectImageAttrs } from "../../attrs/index.js";
3
+ import { pictureNamesDomAttrs, pictureNamesFromDom } from "../../imagePictureNames.js";
3
4
  import { createNodeExtension } from "../create.js";
4
5
  //#region src/prosemirror/extensions/nodes/ImageExtension.ts
5
6
  /**
@@ -17,6 +18,7 @@ const ImageExtension = createNodeExtension({
17
18
  src: {},
18
19
  preview: { default: null },
19
20
  docPrName: { default: null },
21
+ pictureNames: { default: null },
20
22
  alt: { default: null },
21
23
  title: { default: null },
22
24
  width: { default: null },
@@ -73,6 +75,7 @@ const ImageExtension = createNodeExtension({
73
75
  tag: "img[src]",
74
76
  getAttrs(dom) {
75
77
  const element = dom;
78
+ const pictureNames = pictureNamesFromDom(element);
76
79
  const alt = element.getAttribute("alt");
77
80
  const title = element.getAttribute("title");
78
81
  const cssFloat = element.dataset["cssFloat"];
@@ -85,6 +88,8 @@ const ImageExtension = createNodeExtension({
85
88
  const contrast = contrastRaw === void 0 ? NaN : Number(contrastRaw);
86
89
  return {
87
90
  src: element.getAttribute("src") || "",
91
+ ...element.dataset["docPrName"] === void 0 ? {} : { docPrName: element.dataset["docPrName"] },
92
+ ...Object.keys(pictureNames).length > 0 ? { pictureNames } : {},
88
93
  ...alt ? { alt } : {},
89
94
  ...title ? { title } : {},
90
95
  ...element.width ? { width: element.width } : {},
@@ -107,8 +112,10 @@ const ImageExtension = createNodeExtension({
107
112
  const attrs = expectImageAttrs(node);
108
113
  const domAttrs = {
109
114
  src: attrs.src,
110
- class: "docx-image"
115
+ class: "docx-image",
116
+ ...pictureNamesDomAttrs(attrs.pictureNames)
111
117
  };
118
+ if (attrs.docPrName != null) domAttrs["data-doc-pr-name"] = attrs.docPrName;
112
119
  if (attrs.alt) domAttrs["alt"] = attrs.alt;
113
120
  if (attrs.title) domAttrs["title"] = attrs.title;
114
121
  if (attrs.rId) domAttrs["data-rid"] = attrs.rId;
@@ -0,0 +1,12 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/prosemirror/imagePictureNames.d.ts
3
+ declare const PICTURE_NAME_DOM_ATTRIBUTES: {
4
+ readonly name: "data-picture-name";
5
+ readonly alt: "data-picture-alt";
6
+ readonly title: "data-picture-title";
7
+ };
8
+ /** Keep picture metadata separate from the containing drawing's accessibility strings. */
9
+ declare const pictureNamesFromDom: (element: HTMLElement) => document_d_exports.NonVisualDrawingNames;
10
+ declare const pictureNamesDomAttrs: (names: document_d_exports.NonVisualDrawingNames | undefined) => Record<string, string>;
11
+ //#endregion
12
+ export { PICTURE_NAME_DOM_ATTRIBUTES, pictureNamesDomAttrs, pictureNamesFromDom };
@@ -0,0 +1,20 @@
1
+ //#region src/prosemirror/imagePictureNames.ts
2
+ const PICTURE_NAME_DOM_ATTRIBUTES = {
3
+ name: "data-picture-name",
4
+ alt: "data-picture-alt",
5
+ title: "data-picture-title"
6
+ };
7
+ /** Keep picture metadata separate from the containing drawing's accessibility strings. */
8
+ const pictureNamesFromDom = (element) => Object.fromEntries(Object.entries(PICTURE_NAME_DOM_ATTRIBUTES).flatMap(([key, attribute]) => {
9
+ const value = element.getAttribute(attribute);
10
+ return value === null ? [] : [[key, value]];
11
+ }));
12
+ const pictureNamesDomAttrs = (names) => {
13
+ const values = new Map(Object.entries(names ?? {}));
14
+ return Object.fromEntries(Object.entries(PICTURE_NAME_DOM_ATTRIBUTES).flatMap(([key, attribute]) => {
15
+ const value = values.get(key);
16
+ return value === void 0 ? [] : [[attribute, value]];
17
+ }));
18
+ };
19
+ //#endregion
20
+ export { PICTURE_NAME_DOM_ATTRIBUTES, pictureNamesDomAttrs, pictureNamesFromDom };
@@ -113,6 +113,7 @@ const styleResolvedParagraphFormatting = (resolved) => {
113
113
  Reflect.set(governed, field, value);
114
114
  found = true;
115
115
  }
116
+ if (resolved.indentFirstLine !== void 0 && resolved.hangingIndent !== void 0) governed.hangingIndent = resolved.hangingIndent;
116
117
  return found ? governed : void 0;
117
118
  };
118
119
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { StyleEngine } from "../style-engine/styleEngine.js";
3
3
  import "../style-engine/index.js";
4
- import { cascadeStyleTextFormatting } from "./styles/styleToggleCascade.js";
4
+ import { StyleToggleKey, cascadeStyleTextFormatting } from "./styles/styleToggleCascade.js";
5
5
  import { Mark, Node } from "prosemirror-model";
6
6
  //#region src/prosemirror/runStyleFormatting.d.ts
7
7
  declare const hasDirectRunFormatting: (formatting: document_d_exports.TextFormatting | undefined) => boolean;
@@ -41,6 +41,76 @@ declare const resolveParagraphBodyRunFormatting: ({ styleId, styleResolver, tabl
41
41
  defaultFormatting: document_d_exports.TextFormatting | undefined;
42
42
  defaultToggleCascade: ReturnType<typeof cascadeStyleTextFormatting>;
43
43
  };
44
+ type ResolveParagraphInheritedRunFormattingOptions = ResolveParagraphBodyRunFormattingOptions & {
45
+ paragraphMarkFormatting: document_d_exports.TextFormatting | undefined;
46
+ };
47
+ /** One source cascade for imported body runs and the saver inheritance baseline. */
48
+ declare const resolveParagraphInheritedRunFormatting: (options: ResolveParagraphInheritedRunFormattingOptions) => {
49
+ inheritedFormatting: {
50
+ bold?: boolean | undefined;
51
+ boldCs?: boolean | undefined;
52
+ italic?: boolean | undefined;
53
+ italicCs?: boolean | undefined;
54
+ underline?: {
55
+ style: import("@stll/docx-core/model").UnderlineStyle;
56
+ color?: import("@stll/docx-core/model").ColorValue;
57
+ } | undefined;
58
+ strike?: boolean | undefined;
59
+ doubleStrike?: boolean | undefined;
60
+ vertAlign?: "baseline" | "superscript" | "subscript" | undefined;
61
+ smallCaps?: boolean | undefined;
62
+ allCaps?: boolean | undefined;
63
+ hidden?: boolean | undefined;
64
+ noProof?: boolean | undefined;
65
+ color?: import("@stll/docx-core/model").ColorValue | undefined;
66
+ highlight?: "black" | "blue" | "cyan" | "darkBlue" | "darkCyan" | "darkGray" | "darkGreen" | "darkMagenta" | "darkRed" | "darkYellow" | "green" | "lightGray" | "magenta" | "none" | "red" | "white" | "yellow" | undefined;
67
+ shading?: import("@stll/docx-core/model").ShadingProperties | undefined;
68
+ fontSize?: number | undefined;
69
+ fontSizeCs?: number | undefined;
70
+ fontFamily?: {
71
+ ascii?: string;
72
+ hAnsi?: string;
73
+ eastAsia?: string;
74
+ cs?: string;
75
+ hint?: "default" | "eastAsia" | "cs";
76
+ asciiTheme?: "majorAscii" | "majorHAnsi" | "majorEastAsia" | "majorBidi" | "minorAscii" | "minorHAnsi" | "minorEastAsia" | "minorBidi";
77
+ hAnsiTheme?: string;
78
+ eastAsiaTheme?: string;
79
+ csTheme?: string;
80
+ } | undefined;
81
+ language?: {
82
+ val?: string;
83
+ eastAsia?: string;
84
+ bidi?: string;
85
+ } | undefined;
86
+ spacing?: number | undefined;
87
+ position?: number | undefined;
88
+ scale?: number | undefined;
89
+ kerning?: number | undefined;
90
+ effect?: import("@stll/docx-core/model").TextEffect | undefined;
91
+ emphasisMark?: import("@stll/docx-core/model").EmphasisMark | undefined;
92
+ emboss?: boolean | undefined;
93
+ imprint?: boolean | undefined;
94
+ outline?: boolean | undefined;
95
+ shadow?: boolean | undefined;
96
+ rtl?: boolean | undefined;
97
+ cs?: boolean | undefined;
98
+ styleId?: string | undefined;
99
+ preserved?: import("@stll/docx-core/model").PreservedMarkup | undefined;
100
+ } | undefined;
101
+ inheritedToggleCascade: {
102
+ formatting: document_d_exports.TextFormatting | undefined;
103
+ toggleStates: ReadonlyMap<StyleToggleKey, {
104
+ value: boolean;
105
+ defaultsActive: boolean;
106
+ }>;
107
+ type: "styleToggleCascade";
108
+ };
109
+ baseFormatting: document_d_exports.TextFormatting | undefined;
110
+ baseToggleCascade: ReturnType<typeof cascadeStyleTextFormatting>;
111
+ defaultFormatting: document_d_exports.TextFormatting | undefined;
112
+ defaultToggleCascade: ReturnType<typeof cascadeStyleTextFormatting>;
113
+ };
44
114
  declare const paragraphRunStyleContext: (paragraph: Node, styleResolver?: RunStyleResolver | null) => ParagraphRunStyleContext;
45
115
  type ParagraphFormattingForRunOptions = {
46
116
  context: ParagraphRunStyleContext;
@@ -68,4 +138,4 @@ type ResolveEffectiveRunStyleFormattingOptions = {
68
138
  /** Resolve the non-direct run cascade from shared document styles and the current paragraph. */
69
139
  declare const resolveEffectiveRunStyleFormatting: ({ marks, paragraphFormatting, styleResolver }: ResolveEffectiveRunStyleFormattingOptions) => document_d_exports.TextFormatting | undefined;
70
140
  //#endregion
71
- export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
141
+ export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, resolveParagraphInheritedRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -118,6 +118,23 @@ const resolveParagraphBodyRunFormatting = ({ styleId, styleResolver, tableRunFor
118
118
  defaultToggleCascade
119
119
  };
120
120
  };
121
+ /** One source cascade for imported body runs and the saver inheritance baseline. */
122
+ const resolveParagraphInheritedRunFormatting = (options) => {
123
+ const body = resolveParagraphBodyRunFormatting(options);
124
+ const ordinaryFormatting = mergeTextFormatting(body.defaultFormatting, options.paragraphMarkFormatting);
125
+ const inheritedToggleCascade = cascadeStyleTextFormatting([{
126
+ cascade: body.defaultToggleCascade,
127
+ type: "carried"
128
+ }, {
129
+ formatting: options.paragraphMarkFormatting,
130
+ type: "direct"
131
+ }], { ordinaryFormatting });
132
+ return {
133
+ ...body,
134
+ inheritedFormatting: inheritedToggleCascade.formatting,
135
+ inheritedToggleCascade
136
+ };
137
+ };
121
138
  const paragraphRunStyleContext = (paragraph, styleResolver) => {
122
139
  const attrs = expectParagraphAttrs(paragraph);
123
140
  const paragraphMarkFormatting = attrs._originalFormatting?.runProperties;
@@ -184,4 +201,4 @@ const resolveEffectiveRunStyleFormatting = ({ marks, paragraphFormatting, styleR
184
201
  });
185
202
  };
186
203
  //#endregion
187
- export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
204
+ export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, resolveParagraphInheritedRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -405,6 +405,7 @@ type ImageAttrs = {
405
405
  */
406
406
  preview?: document_d_exports.PreviewDescriptor;
407
407
  docPrName?: string;
408
+ pictureNames?: document_d_exports.NonVisualDrawingNames;
408
409
  alt?: string;
409
410
  title?: string;
410
411
  /** Width in pixels (already converted from EMU) */
@@ -81,6 +81,7 @@ declare class StyleResolver {
81
81
  * @returns Resolved paragraph and run formatting
82
82
  */
83
83
  resolveParagraphStyleInTable(styleId: string | undefined | null, tableParagraphOverlay: TableCellParagraphSpacingOverlay | undefined): ResolvedParagraphStyle;
84
+ private resolveParagraphFormatting;
84
85
  private resolveParagraphStyleCascade;
85
86
  /**
86
87
  * Resolve the style applied to the paragraph that follows one styled with
@@ -138,5 +139,7 @@ declare class StyleResolver {
138
139
  * Create a style resolver from document's style definitions
139
140
  */
140
141
  declare function createStyleResolver(styleDefinitions: document_d_exports.StyleDefinitions | undefined): StyleResolver;
142
+ /** The same ordered paragraph tiers, without unrelated run or paragraph fields. */
143
+ declare const resolveStyleParagraphNumbering: (resolver: StyleResolver, styleId: string | undefined | null) => import("@stll/docx-core/model").ParagraphNumberingOverride | undefined;
141
144
  //#endregion
142
- export { ResolvedParagraphStyle, StyleResolver, TableCellParagraphSpacingOverlay, createStyleResolver };
145
+ export { ResolvedParagraphStyle, StyleResolver, TableCellParagraphSpacingOverlay, createStyleResolver, resolveStyleParagraphNumbering };