@stll/folio-core 0.42.0 → 0.43.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 (46) hide show
  1. package/dist/compat/eigenpal.d.ts +2 -2
  2. package/dist/controller/layoutPipeline.d.ts +2 -1
  3. package/dist/controller/layoutPipeline.js +5 -2
  4. package/dist/controller/layoutSession.d.ts +2 -1
  5. package/dist/controller/layoutSession.js +1 -0
  6. package/dist/docx/blockContentParser.js +2 -1
  7. package/dist/docx/commentIdNormalization.d.ts +8 -0
  8. package/dist/docx/commentIdNormalization.js +16 -0
  9. package/dist/docx/defaultParagraphStyle.d.ts +22 -0
  10. package/dist/docx/defaultParagraphStyle.js +32 -0
  11. package/dist/docx/footnoteParser.js +2 -0
  12. package/dist/docx/headerFooterRefParser.d.ts +12 -1
  13. package/dist/docx/headerFooterRefParser.js +9 -2
  14. package/dist/docx/numberingParser.js +2 -1
  15. package/dist/docx/numberingReference.d.ts +21 -0
  16. package/dist/docx/numberingReference.js +21 -0
  17. package/dist/docx/numberingReferenceNormalization.d.ts +11 -2
  18. package/dist/docx/numberingReferenceNormalization.js +32 -9
  19. package/dist/docx/paragraphParser.js +3 -2
  20. package/dist/docx/parser.js +10 -2
  21. package/dist/docx/rezip.js +22 -5
  22. package/dist/docx/server/createBilingualDocument.js +5 -4
  23. package/dist/docx/styleParser.js +2 -2
  24. package/dist/index.d.ts +2 -2
  25. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +2 -0
  26. package/dist/internal/pageBreakRunSourceDescendantIndex.js +7 -5
  27. package/dist/layout-bridge/convert/templatePreviewFlow.d.ts +19 -11
  28. package/dist/layout-bridge/convert/templatePreviewFlow.js +103 -38
  29. package/dist/layout-bridge/convert/toFlowBlocks.js +12 -3
  30. package/dist/prosemirror/commands/pageBreak.js +12 -1
  31. package/dist/prosemirror/conversion/fromProseDoc.js +2 -1
  32. package/dist/prosemirror/conversion/toProseDoc.js +27 -12
  33. package/dist/prosemirror/extensions/features/ListExtension.js +42 -4
  34. package/dist/prosemirror/listMarker.js +2 -1
  35. package/dist/prosemirror/numberedRefFields.js +2 -1
  36. package/dist/prosemirror/pageBreakRunProjection.d.ts +11 -3
  37. package/dist/prosemirror/pageBreakRunProjection.js +16 -8
  38. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +42 -1
  39. package/dist/prosemirror/plugins/templatePreviewValues.js +217 -14
  40. package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -1
  41. package/dist/prosemirror/styles/styleResolver.js +3 -6
  42. package/dist/prosemirror/utils/visualLineNavigation.d.ts +22 -2
  43. package/dist/prosemirror/utils/visualLineNavigation.js +80 -63
  44. package/dist/style-engine/styleEngine.d.ts +1 -1
  45. package/dist/style-sets/extract.js +57 -11
  46. package/package.json +2 -1
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ import { getFolioCaretViewportRect, getFolioSelectionViewportRect } from "./page
30
30
  import { AICitationRange, createAICitationDecorationsPlugin, setAICitationsMeta, setActiveCitationMeta } from "./prosemirror/plugins/aiCitationDecorations.js";
31
31
  import { AnonymizationMatch, AnonymizationTerm, anonymizationDecorationsKey, getAnonymizationMatches, setAnonymizationTermsMeta } from "./prosemirror/plugins/anonymizationDecorations.js";
32
32
  import { DirectiveKind, DirectiveRange, getTemplateDirectives, scanDirectives } from "./prosemirror/plugins/templateDirectives.js";
33
- import { TemplatePreviewSpan, TemplatePreviewValue, TemplatePreviewValues, setTemplatePreviewValues } from "./prosemirror/plugins/templatePreviewValues.js";
33
+ import { TemplatePreviewHiddenRange, TemplatePreviewSpan, TemplatePreviewValue, TemplatePreviewValues, setTemplatePreviewValues } from "./prosemirror/plugins/templatePreviewValues.js";
34
34
  import { TemplateSlashMenuKeyAction, TemplateSlashMenuState, clearTemplateSlashMenu, consumeTemplateSlashQuery, getTemplateSlashMenu, resetTemplateSlashQuery, templateSlashMenuKey } from "./prosemirror/plugins/templateSlashMenu.js";
35
35
  import { AcceptAutocompleteResult, AutocompleteSuggestionPluginOptions, AutocompleteSuggestionState, AutocompleteSuggestionStatus, AutocompleteTriggerCheck, AutocompleteTriggerOptions, AutocompleteTriggerSkipReason, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acceptAutocompleteWord, appendAutocompleteToken, autocompleteSuggestionKey, autocompleteSuggestionPlugin, clearAutocompleteSuggestion, finishAutocompleteSuggestion, getAutocompleteSuggestion, shouldTriggerAutocomplete, startAutocompleteSuggestion } from "./prosemirror/plugins/autocompleteSuggestion.js";
36
36
  import { ImageMeta, ImageRef, MarkdownOptions, MarkdownResult } from "./markdown/types.js";
@@ -41,4 +41,4 @@ import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled
41
41
  import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
42
42
  type Document = document_d_exports.Document;
43
43
  type DocxConformanceClass = document_d_exports.DocxConformanceClass;
44
- export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareCompatibility, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFolioRequirement, type CompareResult, type CompareRevisionFormat, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentPropertiesOptions, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type DocxDrawingClassification, type DrawingSafetyClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineComparisonResult, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, FolioContentInlinePresentationProjectionError, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphKind, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
44
+ export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareCompatibility, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFolioRequirement, type CompareResult, type CompareRevisionFormat, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentPropertiesOptions, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type DocxDrawingClassification, type DrawingSafetyClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineComparisonResult, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, FolioContentInlinePresentationProjectionError, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphKind, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewHiddenRange, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -2,6 +2,8 @@ import { document_d_exports } from "../types/document.js";
2
2
  //#region src/internal/pageBreakRunSourceDescendantIndex.d.ts
3
3
  type PageBreakRunSourceDescendantIndex = {
4
4
  containsPageBreakRun: (content: readonly document_d_exports.BlockContent[]) => boolean;
5
+ /** The same question about one block, so a caller can ask it per sibling. */
6
+ blockContainsPageBreakRun: (block: document_d_exports.BlockContent) => boolean;
5
7
  paragraphFeatures: (paragraph: document_d_exports.Paragraph) => PageBreakRunSourceParagraphFeatures;
6
8
  };
7
9
  type PageBreakRunSourceParagraphFeatures = {
@@ -105,12 +105,14 @@ const buildPageBreakRunSourceDescendantIndex = (rootContent) => {
105
105
  return flags;
106
106
  }
107
107
  inspectBlocks(rootContent);
108
+ const indexedFlags = (node) => {
109
+ const flags = flagsByObject.get(node);
110
+ if (flags === void 0) panic("Page-break source ownership was queried outside its conversion index");
111
+ return flags;
112
+ };
108
113
  return {
109
- containsPageBreakRun: (content) => {
110
- const flags = flagsByObject.get(content);
111
- if (flags === void 0) panic("Page-break source ownership was queried outside its conversion index");
112
- return hasFlag(flags, SOURCE_FLAGS.containsPageBreak);
113
- },
114
+ containsPageBreakRun: (content) => hasFlag(indexedFlags(content), SOURCE_FLAGS.containsPageBreak),
115
+ blockContainsPageBreakRun: (block) => hasFlag(indexedFlags(block), SOURCE_FLAGS.containsPageBreak),
114
116
  paragraphFeatures: (paragraph) => {
115
117
  const flags = flagsByObject.get(paragraph);
116
118
  if (flags === void 0) panic("Page-break paragraph ownership was queried outside its conversion index");
@@ -1,4 +1,4 @@
1
- import { TemplatePreviewValue } from "../../prosemirror/plugins/templatePreviewValues.js";
1
+ import { TemplatePreviewHiddenRange, TemplatePreviewValue } from "../../prosemirror/plugins/templatePreviewValues.js";
2
2
  import { FlowBlock } from "../../layout-engine/types.js";
3
3
  //#region src/layout-bridge/convert/templatePreviewFlow.d.ts
4
4
  /** One marker→value substitution, in PM doc positions. */
@@ -10,27 +10,35 @@ type TemplatePreviewFlowEntry = {
10
10
  /** The typed value displayed in place of the marker. */
11
11
  value: TemplatePreviewValue;
12
12
  };
13
- type TemplatePreviewFlowOptions = {
13
+ /** What the preview substitutes and what it hides, as the flow stage sees it. */
14
+ type TemplatePreviewFlowState = {
14
15
  entries: readonly TemplatePreviewFlowEntry[];
16
+ /** Conditional spans a `false` condition hides, in PM doc positions. */
17
+ hidden: readonly TemplatePreviewHiddenRange[];
18
+ };
19
+ type TemplatePreviewFlowOptions = TemplatePreviewFlowState & {
15
20
  /** `highlighted` marks substituted runs for the accent-chip CSS. */
16
21
  mode: "highlighted" | "plain";
17
22
  };
18
23
  /**
19
24
  * Replace each entry's marker range with its preview value across the given
20
- * flow blocks (recursing into table cells and text boxes). Returns the input
21
- * array unchanged when there is nothing to substitute.
25
+ * flow blocks (recursing into table cells and text boxes), and drop the blocks
26
+ * a hidden conditional span swallows whole. Returns the input array unchanged
27
+ * when there is nothing to substitute and nothing to hide.
22
28
  */
23
- declare function applyTemplatePreviewToBlocks(blocks: FlowBlock[], { entries, mode }: TemplatePreviewFlowOptions): FlowBlock[];
29
+ declare function applyTemplatePreviewToBlocks(blocks: FlowBlock[], { entries, hidden, mode }: TemplatePreviewFlowOptions): FlowBlock[];
24
30
  /**
25
- * PM range covering every substitution that differs between two preview
26
- * states (changed, added, or removed entries), or `null` when the
27
- * substituted flow content is identical. Feeds the layout pipeline's
31
+ * PM range covering every substitution and every hidden span that differs
32
+ * between two preview states (changed, added, or removed), or `null` when the
33
+ * flow content both produce is identical. Feeds the layout pipeline's
28
34
  * dirty-range invalidation so typing a value re-measures only the blocks
29
- * hosting the affected markers.
35
+ * hosting the affected markers. A hidden span that appears or disappears also
36
+ * changes the block count, which sends the measure path down its full-remeasure
37
+ * branch regardless of how wide this range is.
30
38
  */
31
- declare function templatePreviewDirtyRange(previous: readonly TemplatePreviewFlowEntry[], next: readonly TemplatePreviewFlowEntry[]): {
39
+ declare function templatePreviewDirtyRange(previous: TemplatePreviewFlowState, next: TemplatePreviewFlowState): {
32
40
  from: number;
33
41
  to: number;
34
42
  } | null;
35
43
  //#endregion
36
- export { TemplatePreviewFlowEntry, TemplatePreviewFlowOptions, applyTemplatePreviewToBlocks, templatePreviewDirtyRange };
44
+ export { TemplatePreviewFlowEntry, TemplatePreviewFlowOptions, TemplatePreviewFlowState, applyTemplatePreviewToBlocks, templatePreviewDirtyRange };
@@ -1,16 +1,41 @@
1
- import { templatePreviewValueFingerprint } from "../../prosemirror/plugins/templatePreviewValues.js";
1
+ import { templatePreviewHidesWholeBlock, templatePreviewValueFingerprint } from "../../prosemirror/plugins/templatePreviewValues.js";
2
2
  //#region src/layout-bridge/convert/templatePreviewFlow.ts
3
3
  /**
4
+ * A top-level block a hidden span swallows whole, which therefore leaves the
5
+ * flow. A block the span only partly covers stays: its text is authored content
6
+ * outside the conditional, and dropping the block would take that text with it.
7
+ *
8
+ * A block carrying no PM positions stays too. That is every section break,
9
+ * which is the safe answer rather than an accident: a section break sets the
10
+ * page geometry that follows it, so hiding text must not take it out of the
11
+ * flow. `SectionBreakBlock` is the one `FlowBlock` variant without the fields,
12
+ * hence the `in` test, matching `findDirtyBlockIndexes`.
13
+ */
14
+ const isHiddenWholeBlock = (block, hidden) => {
15
+ const pmStart = "pmStart" in block ? block.pmStart : void 0;
16
+ const pmEnd = "pmEnd" in block ? block.pmEnd : void 0;
17
+ if (pmStart === void 0 || pmEnd === void 0) return false;
18
+ return hidden.some((range) => templatePreviewHidesWholeBlock(range, {
19
+ pmStart,
20
+ pmEnd
21
+ }));
22
+ };
23
+ /**
4
24
  * Replace each entry's marker range with its preview value across the given
5
- * flow blocks (recursing into table cells and text boxes). Returns the input
6
- * array unchanged when there is nothing to substitute.
25
+ * flow blocks (recursing into table cells and text boxes), and drop the blocks
26
+ * a hidden conditional span swallows whole. Returns the input array unchanged
27
+ * when there is nothing to substitute and nothing to hide.
7
28
  */
8
- function applyTemplatePreviewToBlocks(blocks, { entries, mode }) {
9
- if (entries.length === 0) return blocks;
29
+ function applyTemplatePreviewToBlocks(blocks, { entries, hidden, mode }) {
30
+ if (entries.length === 0 && hidden.length === 0) return blocks;
10
31
  const sorted = [...entries].sort((a, b) => a.from - b.from);
11
32
  let changed = false;
12
33
  const next = [];
13
34
  for (const block of blocks) {
35
+ if (isHiddenWholeBlock(block, hidden)) {
36
+ changed = true;
37
+ continue;
38
+ }
14
39
  const transformed = transformBlock(block, sorted, mode);
15
40
  changed ||= transformed !== block;
16
41
  next.push(transformed);
@@ -117,60 +142,100 @@ function sliceTextRun(run, base, from, to) {
117
142
  pmEnd: to
118
143
  };
119
144
  }
145
+ /** Every newline form a host value may carry; `\r\n` counts once. */
146
+ const VALUE_LINE_BREAK_RE = /\r\n|[\n\r]/u;
147
+ /**
148
+ * Push one span of value text, breaking its lines the way the editor does: each
149
+ * newline becomes a `lineBreak` run, which is the `w:br` the measurer starts a
150
+ * new line on. Consecutive newlines emit consecutive breaks, so a blank line
151
+ * stays a blank line; an empty segment contributes no text run of its own.
152
+ *
153
+ * A rich value's spans are one text stream, so a `\r\n` the host split across a
154
+ * formatting boundary is still one break: `pendingCr` carries a `\r` that ended
155
+ * the previous span, and the returned flag carries this span's. Without it the
156
+ * halves would count as two breaks and the value would gain a blank line.
157
+ */
158
+ function pushValueSpan(out, valueRun, pendingCr) {
159
+ const text = pendingCr && valueRun.text.startsWith("\n") ? valueRun.text.slice(1) : valueRun.text;
160
+ const segments = text.split(VALUE_LINE_BREAK_RE);
161
+ for (const [index, segment] of segments.entries()) {
162
+ if (index > 0) out.push({
163
+ kind: "lineBreak",
164
+ pmStart: valueRun.pmStart,
165
+ pmEnd: valueRun.pmEnd
166
+ });
167
+ if (segment !== "") out.push({
168
+ ...valueRun,
169
+ text: segment
170
+ });
171
+ }
172
+ return text.endsWith("\r");
173
+ }
120
174
  /**
121
175
  * The value run(s) replacing a marker. A plain value is one run carrying the
122
176
  * host run's formatting; a rich value emits one run per span, each layering
123
177
  * its own bold/italic over the host formatting (host bold stays bold, a
124
- * span's flags OR in). Every run keeps the marker's full PM range so
125
- * click-to-position keeps resolving into the marker.
178
+ * span's flags OR in). A newline in either splits its span around a line
179
+ * break run. Every run keeps the marker's full PM range so click-to-position
180
+ * keeps resolving into the marker.
126
181
  */
127
182
  function buildValueRuns(host, entry, mode) {
128
- if (typeof entry.value === "string") return [{
183
+ const runs = [];
184
+ const base = {
129
185
  ...host,
130
- text: entry.value,
131
186
  pmStart: entry.from,
132
187
  pmEnd: entry.to,
133
188
  templatePreview: mode
134
- }];
135
- return entry.value.runs.map((span) => {
189
+ };
190
+ if (typeof entry.value === "string") {
191
+ pushValueSpan(runs, {
192
+ ...base,
193
+ text: entry.value
194
+ }, false);
195
+ return runs;
196
+ }
197
+ let pendingCr = false;
198
+ for (const span of entry.value.runs) {
136
199
  const valueRun = {
137
- ...host,
138
- text: span.text,
139
- pmStart: entry.from,
140
- pmEnd: entry.to,
141
- templatePreview: mode
200
+ ...base,
201
+ text: span.text
142
202
  };
143
203
  if (span.bold === true) valueRun.bold = true;
144
204
  if (span.italic === true) valueRun.italic = true;
145
- return valueRun;
146
- });
205
+ pendingCr = pushValueSpan(runs, valueRun, pendingCr);
206
+ }
207
+ return runs;
147
208
  }
148
209
  const entryKey = (entry) => `${entry.from}:${entry.to}:${templatePreviewValueFingerprint(entry.value)}`;
210
+ const hiddenKey = (range) => `${range.from}:${range.to}:${range.expr}`;
211
+ /** Widen `bounds` over every range whose key is absent from `known`. */
212
+ const growOverUnknown = (ranges, key, known, bounds) => {
213
+ for (const range of ranges) {
214
+ if (known.has(key(range))) continue;
215
+ bounds.from = Math.min(bounds.from, range.from);
216
+ bounds.to = Math.max(bounds.to, range.to);
217
+ }
218
+ };
149
219
  /**
150
- * PM range covering every substitution that differs between two preview
151
- * states (changed, added, or removed entries), or `null` when the
152
- * substituted flow content is identical. Feeds the layout pipeline's
220
+ * PM range covering every substitution and every hidden span that differs
221
+ * between two preview states (changed, added, or removed), or `null` when the
222
+ * flow content both produce is identical. Feeds the layout pipeline's
153
223
  * dirty-range invalidation so typing a value re-measures only the blocks
154
- * hosting the affected markers.
224
+ * hosting the affected markers. A hidden span that appears or disappears also
225
+ * changes the block count, which sends the measure path down its full-remeasure
226
+ * branch regardless of how wide this range is.
155
227
  */
156
228
  function templatePreviewDirtyRange(previous, next) {
157
- const previousKeys = new Set(previous.map(entryKey));
158
- const nextKeys = new Set(next.map(entryKey));
159
- let from = Number.POSITIVE_INFINITY;
160
- let to = Number.NEGATIVE_INFINITY;
161
- for (const entry of previous) if (!nextKeys.has(entryKey(entry))) {
162
- from = Math.min(from, entry.from);
163
- to = Math.max(to, entry.to);
164
- }
165
- for (const entry of next) if (!previousKeys.has(entryKey(entry))) {
166
- from = Math.min(from, entry.from);
167
- to = Math.max(to, entry.to);
168
- }
169
- if (from === Number.POSITIVE_INFINITY) return null;
170
- return {
171
- from,
172
- to
229
+ const bounds = {
230
+ from: Number.POSITIVE_INFINITY,
231
+ to: Number.NEGATIVE_INFINITY
173
232
  };
233
+ growOverUnknown(previous.entries, entryKey, new Set(next.entries.map(entryKey)), bounds);
234
+ growOverUnknown(next.entries, entryKey, new Set(previous.entries.map(entryKey)), bounds);
235
+ growOverUnknown(previous.hidden, hiddenKey, new Set(next.hidden.map(hiddenKey)), bounds);
236
+ growOverUnknown(next.hidden, hiddenKey, new Set(previous.hidden.map(hiddenKey)), bounds);
237
+ if (bounds.from === Number.POSITIVE_INFINITY) return null;
238
+ return bounds;
174
239
  }
175
240
  //#endregion
176
241
  export { applyTemplatePreviewToBlocks, templatePreviewDirtyRange };
@@ -1175,6 +1175,15 @@ const runIsZeroWidthBoundaryMarker = (run) => {
1175
1175
  default: return run;
1176
1176
  }
1177
1177
  };
1178
+ /** Every page-break run under a node, nested tables and text boxes included. */
1179
+ const countPageBreakRuns = (node) => {
1180
+ let count = node.type.name === "pageBreakRun" ? 1 : 0;
1181
+ node.descendants((descendant) => {
1182
+ if (descendant.type.name === "pageBreakRun") count += 1;
1183
+ return true;
1184
+ });
1185
+ return count;
1186
+ };
1178
1187
  /** Decide leading-break eligibility from the exact projected runs consumed by layout. */
1179
1188
  const hasSingleLeadingProjectedPageBreak = (runs, pageBreaks) => {
1180
1189
  if (pageBreaks.length !== 1) return false;
@@ -1348,12 +1357,12 @@ function convertTableCell(node, startPos, options, tableCellMargins) {
1348
1357
  const blocks = [];
1349
1358
  let offset = startPos + 1;
1350
1359
  const authoredPageBreakPosition = options.firstPageBreakRunPosition(node);
1351
- const singleParagraph = node.childCount === 1 && node.firstChild?.type.name === "paragraph" ? node.firstChild : void 0;
1352
- if (authoredPageBreakPosition !== void 0 && singleParagraph === void 0) panic(`An explicit page-break run at ${String(authoredPageBreakPosition)} cannot be projected inside a table cell`);
1360
+ const leadingParagraph = node.firstChild?.type.name === "paragraph" ? node.firstChild : void 0;
1361
+ if (authoredPageBreakPosition !== void 0 && (leadingParagraph === void 0 || countPageBreakRuns(node) !== 1 || options.firstPageBreakRunPosition(leadingParagraph) !== authoredPageBreakPosition)) panic(`An explicit page-break run at ${String(authoredPageBreakPosition)} cannot be projected inside a table cell`);
1353
1362
  const pageBreaks = [];
1354
1363
  node.forEach((child) => {
1355
1364
  if (child.type.name === "paragraph") {
1356
- const block = convertParagraph(child, offset, options, child === singleParagraph ? pageBreaks : void 0);
1365
+ const block = convertParagraph(child, offset, options, child === leadingParagraph ? pageBreaks : void 0);
1357
1366
  blocks.push(block);
1358
1367
  } else if (child.type.name === "table") blocks.push(convertTable(child, offset, options));
1359
1368
  else if (child.type.name === "textBox") blocks.push(convertTextBoxNode(child, offset, options));
@@ -5,6 +5,17 @@ const UNSUPPORTED_PAGE_BREAK_RUN_ANCESTORS = /* @__PURE__ */ new Set([
5
5
  "tableHeader",
6
6
  "textBox"
7
7
  ]);
8
+ const hasTextBoxAnchorAtOrAfter = (paragraph, contentStart, position) => {
9
+ let found = false;
10
+ paragraph.descendants((descendant, offset) => {
11
+ if (descendant.type.name === "textBoxAnchor" && contentStart + offset >= position) {
12
+ found = true;
13
+ return false;
14
+ }
15
+ return !found;
16
+ });
17
+ return found;
18
+ };
8
19
  /**
9
20
  * Insert a page-break run at the current text cursor.
10
21
  *
@@ -18,7 +29,7 @@ const insertPageBreak = (state, dispatch) => {
18
29
  const { $from } = state.selection;
19
30
  if (!pageBreakRunType || !state.selection.empty || !$from.parent.isTextblock) return false;
20
31
  for (let depth = $from.depth; depth >= 0; depth--) if (UNSUPPORTED_PAGE_BREAK_RUN_ANCESTORS.has($from.node(depth).type.name)) return false;
21
- if ($from.parent.type.name !== "paragraph" || pageBreakRunParagraphProjectionDisposition($from.parent).status === "unsupported") return false;
32
+ if ($from.parent.type.name !== "paragraph" || pageBreakRunParagraphProjectionDisposition($from.parent).status === "unsupported" || hasTextBoxAnchorAtOrAfter($from.parent, $from.start(), $from.pos)) return false;
22
33
  if (dispatch) {
23
34
  const pageBreak = pageBreakRunType.create();
24
35
  dispatch(state.tr.replaceSelectionWith(pageBreak).scrollIntoView());
@@ -1,4 +1,5 @@
1
1
  import { EDITED_PREVIEW_FINGERPRINT, imageRawXmlFingerprint } from "../../docx/imageRawXml.js";
2
+ import { isNumberingReference } from "../../docx/numberingReference.js";
2
3
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, ParagraphPropertySourceValidationError, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, linkParagraphPropertySourceCandidate, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings } from "../../docx/paragraphPropertySource.js";
3
4
  import { visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
4
5
  import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
@@ -689,7 +690,7 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
689
690
  */
690
691
  function listRenderingFromAttrs(attrs) {
691
692
  const numId = attrs.numPr?.numId;
692
- if (numId === void 0 || numId === 0) return;
693
+ if (!isNumberingReference(numId)) return;
693
694
  if (!(attrs.listMarker != null || attrs.listIsBullet || attrs.listNumFmt != null)) return;
694
695
  return listRenderingFromAttrs$1({
695
696
  attrs,
@@ -1,4 +1,5 @@
1
1
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
2
+ import { isNumberingReference } from "../../docx/numberingReference.js";
2
3
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
3
4
  import { buildPageBreakRunSourceDescendantIndex } from "../../internal/pageBreakRunSourceDescendantIndex.js";
4
5
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
@@ -453,7 +454,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
453
454
  if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
454
455
  if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
455
456
  if (spacingFromDocDefaults.before || spacingFromDocDefaults.after) attrs.spacingFromDocDefaults = spacingFromDocDefaults;
456
- const effectiveIndent = mergeParagraphFormatting(formatting?.numPr?.numId === 0 && stylePpr?.numPr !== void 0 && stylePpr.numPr.numId !== 0 ? void 0 : stylePpr, formatting);
457
+ const effectiveIndent = mergeParagraphFormatting(formatting?.numPr?.numId === 0 && isNumberingReference(stylePpr?.numPr?.numId) ? void 0 : stylePpr, formatting);
457
458
  set("indentLeft", effectiveIndent?.indentLeft);
458
459
  set("indentRight", formatting?.indentRight ?? stylePpr?.indentRight);
459
460
  set("indentFirstLine", effectiveIndent?.indentFirstLine);
@@ -473,7 +474,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
473
474
  set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
474
475
  set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
475
476
  set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 && (styleId === void 0 || paragraph.content.length === 0) }));
476
- if (stylePpr?.numPr && formatting?.numPr?.numId === void 0 && stylePpr.numPr.numId !== 0) {
477
+ if (stylePpr?.numPr && formatting?.numPr?.numId === void 0 && isNumberingReference(stylePpr.numPr.numId)) {
477
478
  attrs.numPr = {
478
479
  ...stylePpr.numPr,
479
480
  ...formatting?.numPr
@@ -1216,19 +1217,27 @@ const PAGE_BREAK_PARAGRAPH_OWNERS = {
1216
1217
  };
1217
1218
  function assertSourceContainerHasNoPageBreakRun(content, owner, sourceDescendants) {
1218
1219
  if (!sourceDescendants.containsPageBreakRun(content)) return;
1219
- if (owner === "table-cell" && hasSingleLeadingTableCellPageBreak(content)) return;
1220
+ if (owner === "table-cell" && hasSingleLeadingTableCellPageBreak(content, sourceDescendants)) return;
1220
1221
  throw new UnsupportedDocxToProseMirrorConversionError({
1221
1222
  message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]} cannot be represented in the editor model`,
1222
1223
  owner,
1223
1224
  contentType: "break"
1224
1225
  });
1225
1226
  }
1226
- /** A leading page-break run in a cell advances the whole row during pagination. This
1227
- * narrow shape has a lossless PM representation and a row-wide layout
1228
- * projection; interior breaks still require table-fragment ownership. */
1229
- function hasSingleLeadingTableCellPageBreak(content) {
1230
- const paragraph = content.length === 1 && content[0]?.type === "paragraph" ? content[0] : void 0;
1231
- return paragraph !== void 0 && hasSingleLeadingParagraphPageBreak(paragraph);
1227
+ /**
1228
+ * A page break opening a cell advances the whole row during pagination.
1229
+ *
1230
+ * Word writes this shape routinely and the row's own `breakBefore` projects it
1231
+ * losslessly, so what follows the break inside the cell rides along: the row
1232
+ * moves as a unit. The break has to be the cell's only one and has to open its
1233
+ * first paragraph; an interior break still requires table-fragment ownership,
1234
+ * which cell-local flow cannot model. `convertTableCell` in the layout bridge
1235
+ * decides the same question over the projected runs.
1236
+ */
1237
+ function hasSingleLeadingTableCellPageBreak(content, sourceDescendants) {
1238
+ const first = content.at(0);
1239
+ if (first?.type !== "paragraph" || !hasSingleLeadingParagraphPageBreak(first)) return false;
1240
+ return !content.slice(1).some((block) => sourceDescendants.blockContainsPageBreakRun(block));
1232
1241
  }
1233
1242
  const scanLeadingPageBreakRun = (run, scan) => {
1234
1243
  for (const content of run.content) {
@@ -1237,6 +1246,7 @@ const scanLeadingPageBreakRun = (run, scan) => {
1237
1246
  scan.pageBreaks += 1;
1238
1247
  continue;
1239
1248
  }
1249
+ if (content.type === "shape" && content.shape.textBody && scan.pageBreaks > 0) scan.textBoxShapeAfterBreak = true;
1240
1250
  if (scan.pageBreaks === 0) scan.contentBeforeBreak = true;
1241
1251
  }
1242
1252
  };
@@ -1276,12 +1286,17 @@ const scanLeadingPageBreakContent = (content, scan) => {
1276
1286
  default: return content;
1277
1287
  }
1278
1288
  };
1279
- const hasSingleLeadingParagraphPageBreak = (paragraph) => {
1289
+ const scanParagraphPageBreaks = (paragraph) => {
1280
1290
  const scan = {
1281
1291
  contentBeforeBreak: false,
1282
- pageBreaks: 0
1292
+ pageBreaks: 0,
1293
+ textBoxShapeAfterBreak: false
1283
1294
  };
1284
1295
  for (const content of paragraph.content) scanLeadingPageBreakContent(content, scan);
1296
+ return scan;
1297
+ };
1298
+ const hasSingleLeadingParagraphPageBreak = (paragraph) => {
1299
+ const scan = scanParagraphPageBreaks(paragraph);
1285
1300
  return !scan.contentBeforeBreak && scan.pageBreaks === 1;
1286
1301
  };
1287
1302
  function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFrame, sourceDescendants }) {
@@ -1290,7 +1305,7 @@ function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFra
1290
1305
  const disposition = pageBreakRunParagraphProjectionDispositionForFeatures({
1291
1306
  attrs,
1292
1307
  effectiveFrame,
1293
- hasTextBoxAnchor: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape
1308
+ textBoxAnchorAfterPageBreak: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape && scanParagraphPageBreaks(paragraph).textBoxShapeAfterBreak
1294
1309
  });
1295
1310
  if (disposition.status === "supported") return;
1296
1311
  if (disposition.reason !== "textBoxAnchor" && hasSingleLeadingParagraphPageBreak(paragraph)) return;
@@ -1,3 +1,4 @@
1
+ import { isNumberingReference } from "../../../docx/numberingReference.js";
1
2
  import { expectParagraphAttrs } from "../../attrs/index.js";
2
3
  import { PPR_CHANGE_SCOPED_ATTR_KEYS, hasSerializableParagraphPropertyChange } from "../../commands/propertyChangeScope.js";
3
4
  import { CLEARED_LIST_RENDERING_ATTRS } from "../../listMarker.js";
@@ -9,6 +10,7 @@ import { createExtension } from "../create.js";
9
10
  import { goToNextCell, goToPrevCell } from "../nodes/TableExtension.js";
10
11
  import { Priority } from "../types.js";
11
12
  import { panic } from "better-result";
13
+ import { InputRule, inputRules, undoInputRule } from "prosemirror-inputrules";
12
14
  //#region src/prosemirror/extensions/features/ListExtension.ts
13
15
  /**
14
16
  * List Extension — list commands + keymaps
@@ -48,9 +50,9 @@ function getPreviousListFormatting(attrs) {
48
50
  }
49
51
  function clearListAttrs(attrs) {
50
52
  const styleNumPr = attrs.numPrFromStyle;
51
- const numPr = styleNumPr?.numId !== void 0 && styleNumPr.numId !== 0 ? {
53
+ const numPr = isNumberingReference(styleNumPr?.numId) ? {
52
54
  numId: 0,
53
- ilvl: attrs.numPr?.ilvl ?? styleNumPr.ilvl ?? 0
55
+ ilvl: attrs.numPr?.ilvl ?? styleNumPr?.ilvl ?? 0
54
56
  } : null;
55
57
  return {
56
58
  ...attrs,
@@ -59,7 +61,7 @@ function clearListAttrs(attrs) {
59
61
  };
60
62
  }
61
63
  function hasActiveListNumbering(attrs) {
62
- return attrs.numPr?.numId !== void 0 && attrs.numPr.numId !== 0;
64
+ return isNumberingReference(attrs.numPr?.numId);
63
65
  }
64
66
  function toggleList(numId) {
65
67
  return (state, dispatch) => {
@@ -293,11 +295,47 @@ function insertTab() {
293
295
  return true;
294
296
  };
295
297
  }
298
+ /**
299
+ * Word's as-you-type markers. Each ends in the space that triggers the rule.
300
+ * `1.` starts a numbered list at one, like the toolbar button; another typed
301
+ * number stays text rather than being silently renumbered.
302
+ */
303
+ const BULLET_AUTOFORMAT = /^[-*] $/u;
304
+ const NUMBERED_AUTOFORMAT = /^1\. $/u;
305
+ const captureTransaction = (command, state) => {
306
+ const captured = { transaction: null };
307
+ command(state, (transaction) => {
308
+ captured.transaction = transaction;
309
+ });
310
+ return captured.transaction;
311
+ };
312
+ /**
313
+ * Replace a typed marker with the list the toolbar button produces. Running the
314
+ * command itself (rather than writing `numPr` here) keeps an autoformatted list
315
+ * identical to a clicked one, down to what the document saves.
316
+ */
317
+ const listAutoformat = (marker, toggleCommand) => new InputRule(marker, (state, _match, start, end) => {
318
+ const { $from } = state.selection;
319
+ if ($from.parent.type.name !== "paragraph") return null;
320
+ if (start !== $from.start()) return null;
321
+ if (expectParagraphAttrs($from.parent).numPr?.numId) return null;
322
+ if (makeRevisionInfo(state)) return null;
323
+ const toggled = captureTransaction(toggleCommand, state);
324
+ if (!toggled) return null;
325
+ const tr = state.tr.delete(start, end);
326
+ for (const step of toggled.steps) {
327
+ const mapped = step.map(tr.mapping);
328
+ if (mapped) tr.step(mapped);
329
+ }
330
+ return tr;
331
+ });
332
+ const listAutoformatRules = () => inputRules({ rules: [listAutoformat(BULLET_AUTOFORMAT, toggleBulletList), listAutoformat(NUMBERED_AUTOFORMAT, toggleNumberedList)] });
296
333
  const ListExtension = createExtension({
297
334
  name: "list",
298
335
  priority: Priority.High,
299
336
  onSchemaReady() {
300
337
  return {
338
+ plugins: [listAutoformatRules()],
301
339
  commands: {
302
340
  toggleBulletList: () => toggleBulletList,
303
341
  toggleNumberedList: () => toggleNumberedList,
@@ -310,7 +348,7 @@ const ListExtension = createExtension({
310
348
  "Shift-Tab": chainCommands(goToPrevCell(), decreaseListIndent()),
311
349
  "Shift-Enter": () => false,
312
350
  Enter: chainCommands(exitListOnEmptyEnter(), splitListItem()),
313
- Backspace: backspaceExitList()
351
+ Backspace: chainCommands(undoInputRule, backspaceExitList())
314
352
  }
315
353
  };
316
354
  }
@@ -1,4 +1,5 @@
1
1
  import { convertBulletToUnicode } from "../docx/bulletMarkers.js";
2
+ import { isNumberingReference } from "../docx/numberingReference.js";
2
3
  import { formatOoxmlCounter } from "../docx/ooxmlCounterFormatter.js";
3
4
  import { LIST_RENDERING_ATTR_KEYS } from "./listRenderingAttrs.js";
4
5
  //#region src/prosemirror/listMarker.ts
@@ -179,7 +180,7 @@ function advanceListMarker(attrs, state) {
179
180
  const level = attrs.numPr?.ilvl ?? 0;
180
181
  if (!Number.isInteger(level) || level < 0 || level > 8) return null;
181
182
  const numId = attrs.numPr?.numId;
182
- if (numId === void 0 || numId === 0) {
183
+ if (!isNumberingReference(numId)) {
183
184
  let marker = null;
184
185
  if (markerTemplate?.includes("%") && !attrs.listIsBullet) {
185
186
  const counters = getLastListCounters(state);
@@ -1,3 +1,4 @@
1
+ import { isNumberingReference } from "../docx/numberingReference.js";
1
2
  import { expectFieldAttrs, expectParagraphAttrs } from "./attrs/index.js";
2
3
  import { expectBookmarkBoundaryAttrs } from "./bookmarkBoundaryAttrs.js";
3
4
  import { advanceVisibleListMarker, createListCounterState, resolveListTemplateWithComponents } from "./listMarker.js";
@@ -79,7 +80,7 @@ function numberTargetForParagraph(node, contextStreams, streams) {
79
80
  }
80
81
  function numberTargetForAdvancedMarker(attrs, resolvedMarker, state, contexts) {
81
82
  const numId = attrs.numPr?.numId;
82
- if (numId === void 0 || numId === 0 || attrs.listIsBullet || attrs.listMarkerHidden || attrs.listNumFmt === "none" || !resolvedMarker) return null;
83
+ if (!isNumberingReference(numId) || attrs.listIsBullet || attrs.listMarkerHidden || attrs.listNumFmt === "none" || !resolvedMarker) return null;
83
84
  const marker = attrs.listMarkerAllCaps ? resolvedMarker.toLocaleUpperCase() : resolvedMarker;
84
85
  const level = attrs.numPr?.ilvl ?? 0;
85
86
  if (!Number.isInteger(level) || level < 0 || level > 8) return null;
@@ -6,7 +6,7 @@ declare const PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES: {
6
6
  readonly borders: "A bordered paragraph containing an explicit page-break run cannot be projected";
7
7
  readonly frame: "A framed paragraph containing an explicit page-break run cannot be projected";
8
8
  readonly outline: "An outline paragraph containing an explicit page-break run cannot be projected";
9
- readonly textBoxAnchor: "A paragraph containing both an explicit page-break run and a text-box anchor cannot be projected";
9
+ readonly textBoxAnchor: "A paragraph whose text-box anchor follows an explicit page-break run cannot be projected";
10
10
  };
11
11
  type PageBreakRunParagraphProjectionReason = keyof typeof PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES;
12
12
  type PageBreakRunParagraphProjectionDisposition = {
@@ -19,10 +19,18 @@ type PageBreakRunParagraphProjectionDisposition = {
19
19
  type PageBreakRunParagraphFeatures = {
20
20
  attrs: ParagraphAttrs;
21
21
  effectiveFrame: document_d_exports.ParagraphFormatting["frame"];
22
- hasTextBoxAnchor: boolean;
22
+ /**
23
+ * A text-box anchor that the paragraph's first page break precedes.
24
+ *
25
+ * Layout splits such a paragraph into fragments at its breaks, and only the
26
+ * first fragment keeps the paragraph's block id, which is what an anchor
27
+ * resolves its host through. An anchor before the first break is therefore
28
+ * projected faithfully; one after it would lose its host.
29
+ */
30
+ textBoxAnchorAfterPageBreak: boolean;
23
31
  };
24
32
  /** Keep source-import and ProseMirror-layout ownership decisions on one predicate. */
25
- declare const pageBreakRunParagraphProjectionDispositionForFeatures: ({ attrs, effectiveFrame, hasTextBoxAnchor }: PageBreakRunParagraphFeatures) => PageBreakRunParagraphProjectionDisposition;
33
+ declare const pageBreakRunParagraphProjectionDispositionForFeatures: ({ attrs, effectiveFrame, textBoxAnchorAfterPageBreak }: PageBreakRunParagraphFeatures) => PageBreakRunParagraphProjectionDisposition;
26
34
  declare const pageBreakRunParagraphProjectionDisposition: (paragraph: Node) => PageBreakRunParagraphProjectionDisposition;
27
35
  //#endregion
28
36
  export { PageBreakRunParagraphProjectionDisposition, PageBreakRunParagraphProjectionReason, pageBreakRunParagraphProjectionDisposition, pageBreakRunParagraphProjectionDispositionForFeatures };