@stll/folio-core 0.57.0 → 0.58.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 (39) hide show
  1. package/dist/ai-edits/apply.js +77 -8
  2. package/dist/controller/canonicalClipboard.d.ts +3 -1
  3. package/dist/controller/canonicalClipboard.js +24 -12
  4. package/dist/controller/canonicalComposition.d.ts +13 -4
  5. package/dist/controller/canonicalComposition.js +82 -9
  6. package/dist/controller/canonicalInput.d.ts +1 -1
  7. package/dist/controller/canonicalInput.js +4 -3
  8. package/dist/controller/canonicalSelection.js +10 -1
  9. package/dist/controller/canonicalSession.d.ts +1 -1
  10. package/dist/controller/canonicalSession.js +59 -23
  11. package/dist/controller/canonicalStoryEditor.d.ts +1 -1
  12. package/dist/controller/canonicalStoryEditor.js +1 -1
  13. package/dist/controller/canonicalStructure.js +8 -3
  14. package/dist/controller/hiddenEditorApi.js +1 -1
  15. package/dist/controller/hiddenEditorManager.js +1 -1
  16. package/dist/docx/listRendering.d.ts +18 -0
  17. package/dist/{prosemirror/conversion/listRenderingDefinition.js → docx/listRendering.js} +17 -3
  18. package/dist/docx/server/materializeYjsDocx.js +1 -1
  19. package/dist/markdown/internals.js +7 -0
  20. package/dist/markdown/renderParagraph.js +11 -12
  21. package/dist/markdown/renderRuns.js +2 -2
  22. package/dist/markdown/types.d.ts +3 -0
  23. package/dist/prosemirror/attrs/index.js +4 -0
  24. package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -1
  25. package/dist/prosemirror/conversion/fromProseDoc.js +128 -27
  26. package/dist/prosemirror/conversion/toProseDoc.js +10 -23
  27. package/dist/prosemirror/extensions/nodes/ImageExtension.js +8 -1
  28. package/dist/prosemirror/imagePictureNames.d.ts +12 -0
  29. package/dist/prosemirror/imagePictureNames.js +20 -0
  30. package/dist/prosemirror/paragraphFormattingProvenance.js +1 -0
  31. package/dist/prosemirror/runStyleFormatting.d.ts +72 -2
  32. package/dist/prosemirror/runStyleFormatting.js +18 -1
  33. package/dist/prosemirror/schema/nodes.d.ts +1 -0
  34. package/dist/prosemirror/styles/styleResolver.d.ts +4 -1
  35. package/dist/prosemirror/styles/styleResolver.js +32 -11
  36. package/dist/types/canonicalCapabilities.d.ts +15 -1
  37. package/dist/types/canonicalCapabilities.js +15 -1
  38. package/package.json +2 -2
  39. 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 { getDocumentSourceBaseline } 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,89 @@ const restoreLinkedParagraphPropertySources = (content) => {
270
271
  sources: new Set(targetsBySource.keys())
271
272
  };
272
273
  };
274
+ var SaveStylesheetSourceMismatch = class extends TaggedError("SaveStylesheetSourceMismatch") {};
275
+ const assertSuppliedStylesMatchSource = (styles, baseDocument) => {
276
+ if (!baseDocument?.originalBuffer) return;
277
+ const source = getDocumentSourceBaseline(baseDocument);
278
+ switch (source.type) {
279
+ case "missing":
280
+ case "mismatch": throw new SaveStylesheetSourceMismatch({
281
+ message: "The parsed package stylesheet source is unavailable.",
282
+ divergences: [{ type: "sourceUnavailable" }]
283
+ });
284
+ case "captured": {
285
+ const sourceStyles = source.resourceStyles;
286
+ if (!sourceStyles) return;
287
+ const suppliedById = new Map(styles.styles.map((style) => [style.styleId, style]));
288
+ const sourceById = new Map(sourceStyles.styles.map((style) => [style.styleId, style]));
289
+ const divergentIds = /* @__PURE__ */ new Set();
290
+ for (const style of sourceStyles.styles) if (canonicalJson(style) !== canonicalJson(suppliedById.get(style.styleId))) divergentIds.add(style.styleId);
291
+ for (const style of styles.styles) if (canonicalJson(style) !== canonicalJson(suppliedById.get(style.styleId))) divergentIds.add(style.styleId);
292
+ const persistedStyles = {
293
+ ...sourceStyles,
294
+ styles: [...sourceStyles.styles, ...styles.styles.filter(({ styleId }) => !sourceById.has(styleId))]
295
+ };
296
+ const suppliedResolver = createStyleEngine(styles);
297
+ const persistedResolver = createStyleEngine(persistedStyles);
298
+ for (const [supplied, persisted] of [
299
+ [suppliedResolver.getDefaultParagraphStyle(), persistedResolver.getDefaultParagraphStyle()],
300
+ [suppliedResolver.getDefaultCharacterStyle(), persistedResolver.getDefaultCharacterStyle()],
301
+ [suppliedResolver.getDefaultTableStyle(), persistedResolver.getDefaultTableStyle()]
302
+ ]) {
303
+ if (supplied?.styleId === persisted?.styleId) continue;
304
+ if (supplied) divergentIds.add(supplied.styleId);
305
+ if (persisted) divergentIds.add(persisted.styleId);
306
+ }
307
+ const divergences = [];
308
+ for (const styleId of divergentIds) divergences.push({
309
+ type: "style",
310
+ styleId
311
+ });
312
+ if (canonicalJson(styles.docDefaults) !== canonicalJson(sourceStyles.docDefaults)) divergences.push({ type: "docDefaults" });
313
+ if (divergences.length === 0) return;
314
+ throw new SaveStylesheetSourceMismatch({
315
+ message: `Supplied stylesheet differs from the parsed package: ${[...divergentIds, ...divergences.some(({ type }) => type === "docDefaults") ? ["docDefaults"] : []].join(", ")}.`,
316
+ divergences
317
+ });
318
+ }
319
+ default: return panic(`Unexpected stylesheet source baseline: ${JSON.stringify(source)}`);
320
+ }
321
+ };
322
+ const saveStylesheet = (source, baseDocument) => {
323
+ switch (source.type) {
324
+ case "package": return baseDocument?.package.styles;
325
+ case "supplied":
326
+ assertSuppliedStylesMatchSource(source.styles, baseDocument);
327
+ return source.styles;
328
+ default: return panic(`Unexpected stylesheet source: ${JSON.stringify(source)}`);
329
+ }
330
+ };
331
+ var MissingSaveStylesheet = class extends TaggedError("MissingSaveStylesheet") {};
332
+ const assertSaveStylesheetAvailable = ({ pmDoc, styles, baseDocument, stylesheetSource }) => {
333
+ if (styles !== void 0) return;
334
+ if (stylesheetSource.type === "package" && baseDocument !== void 0) return;
335
+ pmDoc.descendants((node) => {
336
+ if ((() => {
337
+ switch (node.type.name) {
338
+ case "paragraph": {
339
+ const attrs = expectParagraphAttrs(node);
340
+ return attrs.styleId ?? attrs._originalFormatting?.runProperties?.styleId;
341
+ }
342
+ case "table": return expectTableAttrs(node).styleId;
343
+ default: return;
344
+ }
345
+ })() != null || node.marks.some(({ type }) => type.name === "characterStyle")) throw new MissingSaveStylesheet({ message: "Saving style-dependent content requires its authoritative stylesheet." });
346
+ });
347
+ };
273
348
  /** Convert a ProseMirror document to the document model. */
274
- function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
349
+ function fromProseDoc(pmDoc, baseDocument, { stylesheetSource, reuse = "none" }) {
350
+ const styles = saveStylesheet(stylesheetSource, baseDocument);
351
+ assertSaveStylesheetAvailable({
352
+ pmDoc,
353
+ styles,
354
+ baseDocument,
355
+ stylesheetSource
356
+ });
275
357
  assertNoteReferenceOccurrences(pmDoc);
276
358
  switch (reuse) {
277
359
  case "none": break;
@@ -284,7 +366,7 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
284
366
  const proseContract = getProseDocumentParagraphPropertySourceContract(pmDoc);
285
367
  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
368
  const tokenSources = baseContract && proseContract && baseDocument ? validateParagraphPropertySourceTokens(pmDoc, baseDocument, baseContract) : null;
287
- const blocks = extractBlocks(pmDoc, "resolve", baseDocument?.package.styles ? createStyleEngine(baseDocument.package.styles) : null);
369
+ const blocks = extractBlocks(pmDoc, "resolve", createStyleEngine(styles));
288
370
  joinCommentRangesAcrossParagraphs(blocks);
289
371
  completeCommentReferences(blocks);
290
372
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
@@ -302,6 +384,7 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
302
384
  package: {
303
385
  ...baseDocument.package,
304
386
  document: documentBody,
387
+ ...styles ? { styles } : {},
305
388
  ...numbering ? { numbering } : {}
306
389
  }
307
390
  };
@@ -310,6 +393,7 @@ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
310
393
  }
311
394
  return { package: {
312
395
  document: documentBody,
396
+ ...styles ? { styles } : {},
313
397
  ...numbering ? { numbering } : {}
314
398
  } };
315
399
  }
@@ -324,12 +408,13 @@ const hasSuggestedInsertion = (marks) => marks.some((mark) => mark.type.name ===
324
408
  * Returns the input array unchanged when there is nothing to strip so callers
325
409
  * can skip rebuilding the node.
326
410
  */
327
- function stripSuggestedInlineMarks(marks, { baseParagraphFormatting, inheritedFormatting, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver }) {
411
+ function stripSuggestedInlineMarks(marks, readFormattingContext) {
328
412
  const hasSuggestedDeletion = marks.some((mark) => mark.type.name === "deletion" && isSuggestedMark(mark));
329
413
  const suggestedRunPropertyChange = marks.find((mark) => mark.type.name === "runPropertyChange" && isSuggestedMark(mark));
330
414
  if (!hasSuggestedDeletion && !suggestedRunPropertyChange) return marks;
331
415
  let next = marks.filter((mark) => !((mark.type.name === "deletion" || mark.type.name === "runPropertyChange") && isSuggestedMark(mark)));
332
416
  if (suggestedRunPropertyChange) {
417
+ const { baseParagraphFormatting, inheritedFormatting, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver } = readFormattingContext();
333
418
  const previousFormatting = expectRunPropertyChangeMarkAttrs(suggestedRunPropertyChange).changes.at(0)?.previousFormatting;
334
419
  const characterStyleMark = marks.find(({ type }) => type.name === "characterStyle");
335
420
  const characterStyleAttrs = characterStyleMark ? expectCharacterStyleMarkAttrs(characterStyleMark) : void 0;
@@ -435,6 +520,21 @@ function isSuggestedInsertedNode(node) {
435
520
  }
436
521
  return false;
437
522
  }
523
+ const savedParagraphRunStyleContext = (paragraph, styleResolver) => {
524
+ const context = paragraphRunStyleContext(paragraph, styleResolver);
525
+ if (paragraph.content.size === 0) return context;
526
+ const attrs = expectParagraphAttrs(paragraph);
527
+ const source = resolveParagraphInheritedRunFormatting({
528
+ styleId: attrs.styleId,
529
+ styleResolver,
530
+ tableRunFormatting: attrs._tableRunFormatting,
531
+ paragraphMarkFormatting: attrs.styleId === void 0 ? context.paragraphMarkFormatting : void 0
532
+ });
533
+ return {
534
+ ...context,
535
+ paragraphFormatting: source.inheritedFormatting
536
+ };
537
+ };
438
538
  /**
439
539
  * Recursively rewrite a ProseMirror node tree, removing every suggested
440
540
  * tracked change. Returns `null` when the node itself must be dropped: a
@@ -442,32 +542,32 @@ function isSuggestedInsertedNode(node) {
442
542
  * Surviving block nodes are rebuilt with their suggested delete/merge markers
443
543
  * cleared and their children stripped.
444
544
  */
445
- function mapSuggestionStrippedNode(node, formattingContext = {
446
- baseParagraphFormatting: void 0,
447
- inheritedFormatting: void 0,
448
- paragraphMarkFormatting: void 0,
449
- paragraphMarkPrecedesStyle: false,
450
- styleResolver: null
451
- }) {
545
+ function mapSuggestionStrippedNode(node, readFormattingContext) {
452
546
  if (node.isInline) {
453
547
  if (hasSuggestedInsertion(node.marks)) return null;
454
- const marks = stripSuggestedInlineMarks(node.marks, formattingContext);
548
+ const marks = stripSuggestedInlineMarks(node.marks, readFormattingContext);
455
549
  return marks === node.marks ? node : node.mark(marks);
456
550
  }
457
551
  if (isSuggestedInsertedNode(node)) return null;
458
552
  const nextAttrs = stripSuggestedNodeAttrs(node);
459
553
  const children = [];
460
554
  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;
555
+ let resolvedChildContext;
556
+ const readChildFormattingContext = node.type.name === "paragraph" ? () => {
557
+ if (resolvedChildContext) return resolvedChildContext;
558
+ const { styleResolver } = readFormattingContext();
559
+ const paragraphStyleContext = savedParagraphRunStyleContext(node, styleResolver);
560
+ resolvedChildContext = {
561
+ baseParagraphFormatting: paragraphStyleContext.baseParagraphFormatting,
562
+ inheritedFormatting: paragraphStyleContext.paragraphFormatting,
563
+ paragraphMarkFormatting: paragraphStyleContext.paragraphMarkFormatting,
564
+ paragraphMarkPrecedesStyle: paragraphStyleContext.paragraphMarkPrecedesStyle,
565
+ styleResolver
566
+ };
567
+ return resolvedChildContext;
568
+ } : readFormattingContext;
469
569
  node.forEach((child) => {
470
- const mapped = mapSuggestionStrippedNode(child, childFormattingContext);
570
+ const mapped = mapSuggestionStrippedNode(child, readChildFormattingContext);
471
571
  if (mapped === null) {
472
572
  changed = true;
473
573
  return;
@@ -488,13 +588,13 @@ function mapSuggestionStrippedNode(node, formattingContext = {
488
588
  * {@link extractBlocks} for why this is the sole serialization boundary.
489
589
  */
490
590
  function stripSuggestedProvenance(doc, styleResolver) {
491
- return mapSuggestionStrippedNode(doc, {
591
+ return mapSuggestionStrippedNode(doc, () => ({
492
592
  baseParagraphFormatting: void 0,
493
593
  inheritedFormatting: void 0,
494
594
  paragraphMarkFormatting: void 0,
495
595
  paragraphMarkPrecedesStyle: false,
496
596
  styleResolver
497
- }) ?? doc;
597
+ })) ?? doc;
498
598
  }
499
599
  function materializeNumberedRefValues(doc) {
500
600
  const results = resolveNumberedRefFields(doc);
@@ -946,7 +1046,7 @@ function appendPageBreaks(paragraph, count) {
946
1046
  */
947
1047
  function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleResolver = null) {
948
1048
  const attrs = expectParagraphAttrs(node);
949
- const paragraphStyleContext = paragraphRunStyleContext(node, styleResolver);
1049
+ const paragraphStyleContext = savedParagraphRunStyleContext(node, styleResolver);
950
1050
  let content = extractParagraphContent(node, documentCounts, attrs._emptyHyperlinks ?? void 0, textBoxAnchorMarkers, attrs.renderedPageBreakBefore === true, {
951
1051
  baseParagraphFormatting: paragraphStyleContext.baseParagraphFormatting,
952
1052
  inheritedFormatting: paragraphStyleContext.paragraphFormatting,
@@ -1394,7 +1494,7 @@ const nestInlineWrapperGroups = (items, groups, hyperlinkIndices, revisionOuterW
1394
1494
  function extractParagraphContent(originalParagraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
1395
1495
  const paragraph = coalesceNoteReferenceOccurrences(originalParagraph);
1396
1496
  const content = [];
1397
- const paragraphStyleContext = paragraph.type.name === "paragraph" ? paragraphRunStyleContext(paragraph) : void 0;
1497
+ const paragraphStyleContext = inheritedFormattingOverride === void 0 && paragraph.type.name === "paragraph" ? savedParagraphRunStyleContext(paragraph) : void 0;
1398
1498
  const formattingContext = inheritedFormattingOverride ?? {
1399
1499
  baseParagraphFormatting: paragraphStyleContext?.baseParagraphFormatting,
1400
1500
  inheritedFormatting: paragraphStyleContext?.paragraphFormatting,
@@ -2597,6 +2697,7 @@ function createImageRun(node) {
2597
2697
  },
2598
2698
  wrap
2599
2699
  };
2700
+ if (attrs.pictureNames != null) image.pictureNames = { ...attrs.pictureNames };
2600
2701
  if (attrs.docPrName != null) image.docPrName = attrs.docPrName;
2601
2702
  if (attrs.alt != null) image.alt = attrs.alt;
2602
2703
  if (attrs.title != null) image.title = attrs.title;
@@ -3327,7 +3428,7 @@ function convertPMTextBox(node, styleResolver = null) {
3327
3428
  * Preserves all non-content parts of the original document
3328
3429
  */
3329
3430
  function updateDocumentContent(originalDocument, pmDoc) {
3330
- return fromProseDoc(pmDoc, originalDocument);
3431
+ return fromProseDoc(pmDoc, originalDocument, { stylesheetSource: { type: "package" } });
3331
3432
  }
3332
3433
  /**
3333
3434
  * 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 };