superdoc 2.12.0-next.8 → 2.12.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 (44) hide show
  1. package/dist/chunks/{FindReplaceSurface-40AnrqWk.es.js → FindReplaceSurface-CVKgivXi.es.js} +8 -2
  2. package/dist/chunks/{FindReplaceSurface-0p7EtMZh.cjs → FindReplaceSurface-qi9OhbwN.cjs} +8 -2
  3. package/dist/chunks/{create-super-doc-ui-CBFGggZ2.cjs → create-super-doc-ui-BWWWNPP8.cjs} +180 -84
  4. package/dist/chunks/{create-super-doc-ui-C-AuEM9F.es.js → create-super-doc-ui-FnwgTkUv.es.js} +180 -84
  5. package/dist/collaboration-upgrade-engine.cjs +1 -1
  6. package/dist/collaboration-upgrade-engine.es.js +1 -1
  7. package/dist/layout-engine/contracts/src/column-layout.d.ts +58 -1
  8. package/dist/layout-engine/contracts/src/graphic-placement.d.ts +3 -0
  9. package/dist/layout-engine/contracts/src/index.d.ts +17 -3
  10. package/dist/layout-engine/contracts/src/run-helpers.d.ts +8 -0
  11. package/dist/layout-engine/layout-bridge/src/cache.d.ts +5 -4
  12. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +4 -1
  13. package/dist/layout-engine/layout-bridge/src/note-marker-measure-key.d.ts +3 -0
  14. package/dist/layout-engine/layout-engine/src/column-balancing.d.ts +11 -7
  15. package/dist/layout-engine/layout-engine/src/layout-paragraph.d.ts +2 -6
  16. package/dist/layout-engine/painters/dom/src/derived-run-text-plane.d.ts +9 -0
  17. package/dist/layout-engine/painters/dom/src/index.d.ts +1 -0
  18. package/dist/layout-engine/painters/dom/src/page-content.d.ts +3 -1
  19. package/dist/layout-engine/painters/dom/src/persistent-page-surface.d.ts +2 -0
  20. package/dist/layout-engine/painters/dom/src/renderer.d.ts +9 -16
  21. package/dist/public/ui-react.cjs +18 -1
  22. package/dist/public/ui-react.es.js +18 -2
  23. package/dist/public/ui-vue.cjs +18 -1
  24. package/dist/public/ui-vue.es.js +18 -2
  25. package/dist/public/ui.cjs +1 -1
  26. package/dist/public/ui.es.js +1 -1
  27. package/dist/shared/font-system/src/index.d.ts +1 -1
  28. package/dist/shared/font-system/src/resolver.d.ts +11 -0
  29. package/dist/style.css +40 -40
  30. package/dist/style.layered.css +40 -40
  31. package/dist/superdoc/src/core/types/index.d.ts +20 -12
  32. package/dist/superdoc/src/public/ui/react.d.ts +3 -1
  33. package/dist/superdoc/src/public/ui/types.d.ts +67 -9
  34. package/dist/superdoc/src/public/ui/vue.d.ts +3 -1
  35. package/dist/superdoc/src/public/ui-react.d.cts +1 -0
  36. package/dist/superdoc/src/public/ui-react.d.ts +1 -1
  37. package/dist/superdoc/src/public/ui-vue.d.cts +1 -0
  38. package/dist/superdoc/src/public/ui-vue.d.ts +1 -1
  39. package/dist/superdoc.cjs +138 -12
  40. package/dist/superdoc.es.js +138 -12
  41. package/dist-cdn/style.layered.css +1 -1
  42. package/dist-cdn/superdoc.min.css +1 -1
  43. package/dist-cdn/superdoc.min.js +37 -37
  44. package/package.json +2 -2
@@ -15,6 +15,21 @@ export type ColumnGeometry = {
15
15
  };
16
16
  export type NormalizedColumnLayout = ColumnLayout & {
17
17
  width: number;
18
+ /**
19
+ * The content-area width the layout was normalized against, in px.
20
+ *
21
+ * Only RTL geometry reads it, and it exists because `width` above is the WIDEST column, not the
22
+ * strip: explicit widths are deliberately not scaled to fill the content area (Word renders an
23
+ * authored 2880tw column as 2880tw and leaves the slack), so a strip of explicit columns can be
24
+ * narrower — or wider — than the area it sits in. Mirroring such a strip about its own span would
25
+ * keep it pinned to the LEFT margin and only swap the columns inside it, which is not what Word
26
+ * does: the first column belongs against the RIGHT margin and the slack falls on the left.
27
+ *
28
+ * Optional because `getColumnGeometry` also accepts hand-built layouts (column balancing assembles
29
+ * one directly). When absent, RTL mirrors about the strip's own span, which is exact whenever the
30
+ * columns fill the area — always true in equal mode.
31
+ */
32
+ contentWidth?: number;
18
33
  };
19
34
  export declare function widthsEqual(a?: number[], b?: number[]): boolean;
20
35
  /**
@@ -61,7 +76,49 @@ export declare function getColumnX(geometry: ColumnGeometry[], index: number, or
61
76
  export declare function getColumnGapAfter(geometry: ColumnGeometry[], index: number): number;
62
77
  /** Absolute x of each separator line (only columns that draw one), as `originX + content-relative`. */
63
78
  export declare function getColumnSeparatorPositions(geometry: ColumnGeometry[], originX?: number): number[];
64
- /** Index of the column containing absolute `x` (clicks in a gap map to the preceding column). */
79
+ /**
80
+ * Index of the column whose OWN span contains absolute `x`, or `null` when `x` lies in no column at
81
+ * all — a gutter, the page margins, or something that is not column flow in the first place.
82
+ *
83
+ * This is the strict counterpart to `getColumnAtX` below, and the two exist because paint-time and
84
+ * hit-testing want opposite answers. A click has to select something, so `getColumnAtX` clamps and
85
+ * hands a gap to its neighbouring column. Asking "is there content in a later column" must not
86
+ * clamp: `page.items` carries page-anchored objects, and a full-width watermark belongs to no
87
+ * column, so answering with one makes it evidence for chrome Word does not draw.
88
+ *
89
+ * Direction-agnostic by construction. It tests containment in each column's own span instead of
90
+ * comparing against a boundary, so it does not care whether `x` ascends or descends with the index,
91
+ * and — unlike an edge test — it is not fooled by a fragment WIDER than its column. An over-wide
92
+ * table is placed at its column's left edge and overflows rightward in both directions, so its
93
+ * origin still identifies its column while its trailing edge does not.
94
+ *
95
+ * Spans are half-open — `[x, x + width)` — so that adjacent columns authored with no gutter at all
96
+ * (`w:space="0"`) do not both claim the boundary they share. That boundary is exactly where the
97
+ * later column's own content is placed, and an inclusive upper bound would hand it to the earlier
98
+ * column instead. Columns are scanned in fill order and the first containing span wins, which
99
+ * after that only matters for an overfull explicit strip whose columns genuinely overlap.
100
+ */
101
+ export declare function findColumnContaining(geometry: ColumnGeometry[], x: number, originX?: number): number | null;
102
+ /**
103
+ * Index of the column containing absolute `x` (clicks in a gap map to the preceding column).
104
+ *
105
+ * The walk is direction-aware and cannot assume ascending `x`: in an RTL section column 0 sits on
106
+ * the right, so `x` DESCENDS with the index. The mirrored branch keeps the same rule the LTR branch
107
+ * states — a point in a gap belongs to the column that precedes it in FILL order — which is what
108
+ * makes a drag that crosses the gutter keep extending from the column it is leaving instead of
109
+ * jumping. Direction is read off the geometry rather than taken as an argument, so every existing
110
+ * caller keeps working unchanged.
111
+ *
112
+ * Both branches test a HALF-OPEN span, so this agrees with `findColumnContaining` on every boundary
113
+ * the two can both answer. The LTR branch gets that from `cx >= col.x`: a point on a shared edge is
114
+ * the later column's, because that is where the later column's content begins. The mirrored branch
115
+ * has to say the same thing from the other side — the shared edge is the EARLIER fill column's left
116
+ * edge there — which is `cx < col.x + col.width`, exclusive. An inclusive bound handed that point to
117
+ * the later column, contradicting the half-open span the geometry places content in, and it also
118
+ * pulled in the point one pixel-width past a column's trailing edge, which is gutter and belongs to
119
+ * the preceding column. With `w:space="0"` the two coincide and every column boundary in an RTL
120
+ * section resolved one column too far.
121
+ */
65
122
  export declare function getColumnAtX(geometry: ColumnGeometry[], x: number, originX?: number): number;
66
123
  /** Structural equality of two column layouts, including per-column `gaps`. */
67
124
  export declare function columnLayoutsEqual(a?: ColumnLayout, b?: ColumnLayout): boolean;
@@ -1,3 +1,4 @@
1
+ import { BaseDirection } from './direction-context.js';
1
2
  /** ECMA-376 Part 1 §20.4.3.4 (`ST_RelFromH`). */
2
3
  export declare const ANCHOR_H_RELATIVE_VALUES: readonly ["margin", "page", "column", "character", "leftMargin", "rightMargin", "insideMargin", "outsideMargin"];
3
4
  /** ECMA-376 Part 1 §20.4.3.5 (`ST_RelFromV`). */
@@ -52,6 +53,8 @@ export type ColumnLayoutForAnchor = {
52
53
  count: number;
53
54
  widths?: number[];
54
55
  gaps?: number[];
56
+ direction?: BaseDirection;
57
+ contentWidth?: number;
55
58
  };
56
59
  /**
57
60
  * Inputs for resolving the paint Y of an anchored image, drawing, or floating table.
@@ -2,7 +2,7 @@ import { TabStop } from './engines/tabs.js';
2
2
  import { PageNumberChapterSeparator, PageNumberFieldFormat, PageNumberFormat } from './page-number-formatting.js';
3
3
  import { TrackedChangeSemanticColorKey } from './semantic-colors.js';
4
4
  import { AnchorAlignH, AnchorAlignV, AnchorHRelative, AnchorVRelative } from './graphic-placement.js';
5
- import { ParagraphDirectionContext, RunBidiContext, RunScriptContext, TableDirectionContext } from './direction-context.js';
5
+ import { BaseDirection, ParagraphDirectionContext, RunBidiContext, RunScriptContext, TableDirectionContext } from './direction-context.js';
6
6
  import { LayoutSourceIdentity } from './layout-identity.js';
7
7
  export { computeTabStops, layoutWithTabs, calculateTabWidth } from './engines/tabs.js';
8
8
  export type { TabStop };
@@ -23,7 +23,7 @@ export { LAYOUT_BOUNDARY_SCHEMA, bodyStoryLocator, namedStoryLocator, computeLay
23
23
  export type { LayoutBlockRef, LayoutFragmentId, LayoutPartialRowIdentity, LayoutSourceIdentity, LayoutStoryKind, LayoutStoryLocator, } from './layout-identity.js';
24
24
  export { LAYOUT_SEGMENT_GEOMETRY_SCHEMA } from './segment-geometry.js';
25
25
  export type { NeutralTextDirection, NeutralSegmentGeometry, NeutralLineGeometryFlags, NeutralLineGeometry, NeutralGeometryDiagnostic, NeutralFragmentGeometry, NeutralSegmentGeometryReadback, } from './segment-geometry.js';
26
- export { cloneColumnLayout, columnLayoutsEqual, columnRenderLayoutsEqual, getColumnAtX, getColumnGapAfter, getColumnGeometry, getColumnSeparatorPositions, getColumnWidth, getColumnX, normalizeColumnLayout, resolveColumnCount, resolveColumnLayout, resolveColumnMode, widthsEqual, } from './column-layout.js';
26
+ export { cloneColumnLayout, columnLayoutsEqual, columnRenderLayoutsEqual, findColumnContaining, getColumnAtX, getColumnGapAfter, getColumnGeometry, getColumnSeparatorPositions, getColumnWidth, getColumnX, normalizeColumnLayout, resolveColumnCount, resolveColumnLayout, resolveColumnMode, widthsEqual, } from './column-layout.js';
27
27
  export type { ColumnGeometry, NormalizedColumnLayout } from './column-layout.js';
28
28
  export { authorFromTrackedChangeMeta, authorIdentityKey, composeAuthorColorResolver, fallbackAuthorColor, stampTrackedChangeColors, } from './author-colors.js';
29
29
  export type { AuthorColorsConfig, TrackChangeAuthorColorResolver } from './author-colors.js';
@@ -2094,6 +2094,20 @@ export type ColumnLayout = {
2094
2094
  * mode uses the scalar `gap`. When absent, consumers fall back to the uniform `gap`. (SD-2629)
2095
2095
  */
2096
2096
  gaps?: number[];
2097
+ /**
2098
+ * Section page direction, from `w:sectPr/w:bidi`. Decides which side the FIRST column sits on:
2099
+ * `'ltr'` (default) fills left to right, `'rtl'` fills right to left, matching Word.
2100
+ *
2101
+ * Per ECMA-376 §17.6.1 a section's `w:bidi` governs section-level chrome — page numbers, gutters
2102
+ * and columns — and is independent of the paragraph inline direction (§17.3.1.6). It is carried
2103
+ * here, on the column layout itself, because `getColumnGeometry` is the single source every
2104
+ * column consumer reads for positioning (fill, hit testing, separators, balancing, floating
2105
+ * anchors, footnotes); threading the axis alongside the widths keeps those consumers from having
2106
+ * to re-derive it, and keeps them from disagreeing.
2107
+ *
2108
+ * Absent means `'ltr'`. Every existing producer therefore keeps its current geometry unchanged.
2109
+ */
2110
+ direction?: BaseDirection;
2097
2111
  };
2098
2112
  /**
2099
2113
  * A vertical region of a page that shares a single column configuration.
@@ -2836,7 +2850,7 @@ export declare const extractHeaderFooterSpace: (margins?: PageMargins | null) =>
2836
2850
  };
2837
2851
  export type { ResolvedLayout, ResolvedPage, ResolvedPaintItem, ResolvedGroupItem, ResolvedFragmentItem, ResolvedParagraphContent, ResolvedTextLineItem, ResolvedDropCapItem, ResolvedListMarkerItem, ResolvedTableItem, ResolvedImageItem, ResolvedDrawingItem, ResolvedHeaderFooterPage, ResolvedHeaderFooterLayout, } from './resolved-layout.js';
2838
2852
  export { isResolvedTableItem, isResolvedImageItem, isResolvedDrawingItem } from './resolved-layout.js';
2839
- export { expandRunsForInlineNewlines, isEmptyInlineSdtPlaceholderRun, isEmptySdtPlaceholderRun, sliceRunsForLine, usesPositionedTextGeometry, } from './run-helpers.js';
2853
+ export { expandRunsForInlineNewlines, isBodyNoteReferenceRun, isNoteLabelRun, isNumberedNoteMarkerRun, isEmptyInlineSdtPlaceholderRun, isEmptySdtPlaceholderRun, NOTE_LABEL_MARKER_ATTR, NOTE_REFERENCE_MARKER_ATTR, sliceRunsForLine, usesPositionedTextGeometry, } from './run-helpers.js';
2840
2854
  export { INLINE_OBJECT_REPLACEMENT_CHARACTER, flattenParagraphVisibleText, mapVisibleRangeToRunSlices, type ParagraphVisibleRunSlice, } from './paragraph-visible-text.js';
2841
2855
  export { inlineBoxStyleSignature, isFiniteNonNegativeInteger, normalizeInlineBoxLogicalSides, type InlineBoxLogicalSides, type ResolvedInlineBoxLogicalSides, } from './inline-box.js';
2842
2856
  export { INCREMENTAL_DEPENDENCY_CERTIFICATE_CLASSES, PAGE_CHECKPOINT_DEPENDENCY_CLASSES, areValidPageCheckpointDependencyClasses, isValidIncrementalDependencyOwnerVersion, isValidNonFlowingPageRelativeAnchorDependencyProof, isValidPageCheckpointDependencyCertificate, type IncrementalDependencyCertificateClass, type IncrementalDependencyOwnerVersion, type NonFlowingPageRelativeAnchorDependencyProof, type PageCheckpointDependencyCertificate, type PageCheckpointDependencyClass, } from './incremental-dependency.js';
@@ -1,4 +1,12 @@
1
1
  import { FlowBlock, Line, Run, TextRun } from './index.js';
2
+ export declare const NOTE_REFERENCE_MARKER_ATTR = "data-v2-note-ref";
3
+ export declare const NOTE_LABEL_MARKER_ATTR = "data-v2-note-label";
4
+ /** Body note markers paint text but occupy one source-coordinate unit. */
5
+ export declare function isBodyNoteReferenceRun(run: Run): boolean;
6
+ /** Synthetic note-band or appended-endnote label keyed to its source note. */
7
+ export declare function isNoteLabelRun(run: Run): boolean;
8
+ /** Numbered marker text whose measurement identity can use digit capabilities. */
9
+ export declare function isNumberedNoteMarkerRun(run: Run): boolean;
2
10
  export declare function isEmptySdtPlaceholderRun(run: Run): run is TextRun & {
3
11
  visualPlaceholder: 'emptyInlineSdt' | 'emptyBlockSdt';
4
12
  };
@@ -1,4 +1,5 @@
1
1
  import { FlowBlock } from '../../contracts/src/index.js';
2
+ import { FontMeasureCapabilities } from '../../../shared/font-system/src/index.js';
2
3
  /**
3
4
  * Generates a cache key hash from a block's content, incorporating text,
4
5
  * formatting, and embedded block data.
@@ -23,7 +24,7 @@ import { FlowBlock } from '../../contracts/src/index.js';
23
24
  * content component of that key, so adopting a previous measure on hash
24
25
  * equality is exactly as sound as a cache hit.
25
26
  */
26
- export declare const hashMeasureContent: (block: FlowBlock) => string;
27
+ export declare const hashMeasureContent: (block: FlowBlock, capabilities?: FontMeasureCapabilities) => string;
27
28
  /**
28
29
  * Cache statistics with LRU eviction tracking
29
30
  */
@@ -80,12 +81,12 @@ export declare class MeasureCache<T> {
80
81
  * @param height - The height dimension for cache key
81
82
  * @returns The cached value or undefined
82
83
  */
83
- get(block: FlowBlock | null | undefined, width: number, height: number, fontSignature?: string): T | undefined;
84
+ get(block: FlowBlock | null | undefined, width: number, height: number, fontSignature?: string, capabilities?: FontMeasureCapabilities): T | undefined;
84
85
  /**
85
86
  * Compose the complete content, constraint, and font key once for a cache
86
87
  * read followed by an insertion in the same measurement transaction.
87
88
  */
88
- prepareKey(block: FlowBlock | null | undefined, width: number, height: number, fontSignature?: string): PreparedMeasureCacheKey | undefined;
89
+ prepareKey(block: FlowBlock | null | undefined, width: number, height: number, fontSignature?: string, capabilities?: FontMeasureCapabilities): PreparedMeasureCacheKey | undefined;
89
90
  getPrepared(key: PreparedMeasureCacheKey | undefined): T | undefined;
90
91
  /**
91
92
  * Store a measure in the cache for the given block and dimensions.
@@ -96,7 +97,7 @@ export declare class MeasureCache<T> {
96
97
  * @param height - The height dimension for cache key
97
98
  * @param value - The value to cache
98
99
  */
99
- set(block: FlowBlock | null | undefined, width: number, height: number, value: T, fontSignature?: string): void;
100
+ set(block: FlowBlock | null | undefined, width: number, height: number, value: T, fontSignature?: string, capabilities?: FontMeasureCapabilities): void;
100
101
  setPrepared(key: PreparedMeasureCacheKey | undefined, blockId: string | undefined, value: T): void;
101
102
  /**
102
103
  * Invalidates cached measurements for specific block IDs.
@@ -1,5 +1,5 @@
1
1
  import { NonFlowingPageRelativeAnchorDependencyProof, PageCheckpointDependencyClass, FlowBlock, Layout, LayoutBlockResumeCheckpoint, Measure, Page, HeaderFooterLayout, ColumnLayout } from '../../contracts/src/index.js';
2
- import { FontMeasureContext } from '../../../shared/font-system/src/index.js';
2
+ import { FontMeasureCapabilities, FontMeasureContext } from '../../../shared/font-system/src/index.js';
3
3
  import { LayoutOptions, HeaderFooterConstraints, LayoutExecutionCheckpoint } from '../../layout-engine/src/index.js';
4
4
  import { computeDirtyRegions } from './diff.js';
5
5
  import { MeasureCache } from './cache.js';
@@ -534,10 +534,13 @@ export declare function incrementalLayout(previousBlocks: FlowBlock[], _previous
534
534
  }, previousMeasures?: Measure[] | null, fontRuntime?: {
535
535
  fontContext?: FontMeasureContext;
536
536
  previousFontSignature?: string;
537
+ fontCapabilities?: FontMeasureCapabilities;
537
538
  }, warmStart?: {
538
539
  footnoteReserveSeed?: FootnoteReserveSeed | null;
539
540
  /** Host proved the authoritative note projection bundle was retained exactly. */
540
541
  noteMeasurePlaneRetainedExact?: true;
542
+ /** Host proved this seed is an exact, geometry-equivalent subset of the current note plane. */
543
+ noteMeasurePlaneRetainedSubset?: true;
541
544
  /** Extra note/decorative planes paired with the retained note bundle. */
542
545
  retainedFootnoteExtras?: {
543
546
  blocks: FlowBlock[];
@@ -0,0 +1,3 @@
1
+ import { TextRun } from '../../contracts/src/index.js';
2
+ import { FontMeasureCapabilities } from '../../../shared/font-system/src/index.js';
3
+ export declare function noteMarkerMeasureKey(run: TextRun, capabilities?: FontMeasureCapabilities): string;
@@ -1,10 +1,4 @@
1
- /**
2
- * Column Balancing Module
3
- *
4
- * Implements Word-compatible column balancing for section boundaries.
5
- * Column balancing distributes content evenly across columns at section end,
6
- * matching Microsoft Word's behavior.
7
- */
1
+ import { BaseDirection } from '../../contracts/src/index.js';
8
2
  /**
9
3
  * Configuration for column balancing behavior.
10
4
  */
@@ -199,6 +193,16 @@ export interface SectionColumnLayout {
199
193
  */
200
194
  gaps?: number[];
201
195
  equalWidth?: boolean;
196
+ /**
197
+ * Section page direction (`w:sectPr/w:bidi`) and the content width it was normalized against.
198
+ *
199
+ * Declared here — and not left to the structural subset above — because balancing REBUILDS the
200
+ * geometry and then overwrites every fragment's `x` from it. A balanced page that dropped these
201
+ * would be laid out left-to-right while every earlier page of the same RTL section was laid out
202
+ * right-to-left, so the last page of a two-column Hebrew section would visibly flip.
203
+ */
204
+ direction?: BaseDirection;
205
+ contentWidth?: number;
202
206
  }
203
207
  export interface BalanceSectionOnPageArgs {
204
208
  /** All fragments on the target page. Only those belonging to sectionIndex are balanced (mutated in place). */
@@ -1,7 +1,7 @@
1
1
  import { FloatingObjectManager } from './floating-objects.js';
2
2
  import { PageState } from './paginator.js';
3
3
  import { FootnotePageFlow } from './footnote-page-flow.js';
4
- import { PageMargins, ParagraphBlock, ParagraphMeasure, ImageBlock, ImageMeasure, DrawingBlock, DrawingMeasure, ParagraphLineRegion } from '../../contracts/src/index.js';
4
+ import { PageMargins, ParagraphBlock, ParagraphMeasure, ImageBlock, ImageMeasure, DrawingBlock, DrawingMeasure, ParagraphLineRegion, ColumnLayoutForAnchor } from '../../contracts/src/index.js';
5
5
  import { AnchoredTable } from './anchors.js';
6
6
  /**
7
7
  * SD-2656: ordered footnote anchor entry. The body slicer reads the candidate
@@ -102,11 +102,7 @@ export type ParagraphAnchorsContext = {
102
102
  columnWidth: number;
103
103
  pageWidth: number;
104
104
  pageMargins: PageMargins;
105
- columns: {
106
- width: number;
107
- gap: number;
108
- count: number;
109
- };
105
+ columns: ColumnLayoutForAnchor;
110
106
  placedAnchoredIds: Set<string>;
111
107
  };
112
108
  export declare function layoutParagraphBlock(ctx: ParagraphLayoutContext, anchors?: ParagraphAnchorsContext): void;
@@ -0,0 +1,9 @@
1
+ import { FlowBlock, Run } from '../../../contracts/src/index.js';
2
+ export type DerivedRunTextPlane = {
3
+ generation: number;
4
+ revision: string;
5
+ valuesByDataAttribute: ReadonlyMap<string, ReadonlyMap<string, string>>;
6
+ };
7
+ export declare function validateDerivedRunTextPlane(plane: DerivedRunTextPlane | null | undefined, generation: number): void;
8
+ export declare function resolveDerivedRunText(run: Run, plane: DerivedRunTextPlane | null | undefined): string | undefined;
9
+ export declare function blockUsesDerivedRunTextPlane(block: FlowBlock | undefined, plane: DerivedRunTextPlane | null | undefined): boolean;
@@ -15,6 +15,7 @@ export type { RulerDefinition, RulerConfig, RulerConfigPx, RulerTick, CreateRule
15
15
  export type { PaintSnapshot, PaintSnapshotAnnotationEntity, PaintSnapshotStructuredContentBlockEntity, PaintSnapshotStructuredContentInlineEntity, PaintSnapshotImageEntity, PaintSnapshotEntities, } from './renderer.js';
16
16
  export type { DomPainterInput, PositionMapping } from './renderer.js';
17
17
  export type { DomPainterPersistentPacketSource, DomPainterPersistentPageInput, DomPainterPersistentScaffold, DomPainterPersistentScaffoldPage, } from './persistent-page-surface.js';
18
+ export type { DerivedRunTextPlane } from './derived-run-text-plane.js';
18
19
  export type { PaintWorkSummary } from './page-content.js';
19
20
  export type { RenderedLineInfo } from './runs/index.js';
20
21
  export { sanitizeUrl, linkMetrics, applyRunDataAttributes } from './runs/index.js';
@@ -3,6 +3,7 @@ import { FragmentRenderContext, PositionMapping } from './renderer.js';
3
3
  import { SdtBoundaryOptions } from './sdt/container.js';
4
4
  import { BetweenBorderInfo } from './paragraph/borders/index.js';
5
5
  import { PageStyles } from './styles.js';
6
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
6
7
  export type FragmentDomState = {
7
8
  key: string;
8
9
  signature: string;
@@ -116,7 +117,7 @@ export declare function createEmptyPaintWorkSummary(): PaintWorkSummary;
116
117
  * attribute-for-attribute — that exactness is the proof, never normalize it
117
118
  * away at the pass level (only the §7.7 unit tests use the normalized form).
118
119
  */
119
- export declare function persistentPageVersionKey(page: ResolvedPage, totalPages: number, sectionPageCount: number): string | null;
120
+ export declare function persistentPageVersionKey(page: ResolvedPage, totalPages: number, sectionPageCount: number, derivedRunTextPlane?: DerivedRunTextPlane | null): string | null;
120
121
  /**
121
122
  * The class state `renderPage`/`patchPage` consume, made explicit. The
122
123
  * DomPainter builds one per call (values like `totalPages`, `layoutEpoch`,
@@ -130,6 +131,7 @@ export interface PageContentContext {
130
131
  totalPages: number;
131
132
  currentMapping: PositionMapping | null;
132
133
  changedBlocks: ReadonlySet<string>;
134
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
133
135
  /** Record the smallest newly painted subtree for transaction finalization. */
134
136
  recordChangedRoot?(root: HTMLElement): void;
135
137
  sdtLabelsRendered: Set<string>;
@@ -1,4 +1,5 @@
1
1
  import { DocumentBackground, ResolvedPage } from '../../../contracts/src/index.js';
2
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
2
3
  import { PageContentContext, PageDomState, PaintWorkSummary } from './page-content.js';
3
4
  /**
4
5
  * One exact page band of the committed scaffold (numbers-only,
@@ -69,6 +70,7 @@ export type DomPainterPersistentPageInput = {
69
70
  packetsByPageIndex: DomPainterPersistentPacketSource;
70
71
  sectionPageCounts?: Readonly<Record<string, number>>;
71
72
  documentBackground?: DocumentBackground | null;
73
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
72
74
  captureSnapshot?: boolean;
73
75
  };
74
76
  /** Shell registry entry: the persistent page root and its geometry/style reuse key. */
@@ -1,6 +1,7 @@
1
1
  import { FlowMode, Fragment, PageMargins, PageNumberChapterSeparator, PageNumberFormat, SourceAnchor, ResolvedLayout, ResolvedPage, ResolvedPaintItem, LayoutSourceIdentity, LayoutStoryLocator } from '../../../contracts/src/index.js';
2
2
  import { PaintWorkSummary } from './page-content.js';
3
3
  import { DomPainterPersistentPageInput } from './persistent-page-surface.js';
4
+ import { DerivedRunTextPlane } from './derived-run-text-plane.js';
4
5
  import { PageStyles } from './styles.js';
5
6
  import { PaintSnapshotStructuredContentBlockEntity, PaintSnapshotStructuredContentInlineEntity } from './sdt/snapshot.js';
6
7
  import { PositionValidationOptions, PositionValidationSummary } from './pm-position-validation.js';
@@ -143,6 +144,7 @@ export type FragmentRenderContext = {
143
144
  * `totalPages` / `sectionPageCount`. Absent/`true` = exact (default).
144
145
  */
145
146
  pageCountFieldsExact?: boolean;
147
+ derivedRunTextPlane?: DerivedRunTextPlane | null;
146
148
  };
147
149
  export type PaintSnapshotLineStyle = {
148
150
  paddingLeftPx?: number;
@@ -239,21 +241,6 @@ type PersistentPagePainterTransaction = {
239
241
  readFragmentFailures(): readonly PainterFragmentFailure[];
240
242
  readChangedRoots(): readonly HTMLElement[];
241
243
  };
242
- /**
243
- * DOM-based document painter that renders layout fragments to HTML elements.
244
- * One paint entry per mode (painter plan P7): the persistent shell/content
245
- * reconcile owns paginated flow, while `paint()` owns semantic flow.
246
- *
247
- * @class DomPainter
248
- *
249
- * @remarks
250
- * The DomPainter is responsible for:
251
- * - Rendering layout fragments (paragraphs, lists, images, tables, drawings) to DOM elements
252
- * - Managing page-level DOM structure and styling
253
- * - Handling headers and footers via PageDecorationProvider
254
- * - Incremental re-rendering when only specific blocks change
255
- * - Hyperlink rendering with security sanitization and accessibility
256
- */
257
244
  export declare class DomPainter {
258
245
  private readonly options;
259
246
  private mount;
@@ -305,6 +292,7 @@ export declare class DomPainter {
305
292
  * `dispose()` so a stale window value can never leak across modes/mounts.
306
293
  */
307
294
  private persistentDocumentBackground;
295
+ private persistentDerivedRunTextPlane;
308
296
  private paintWork;
309
297
  /**
310
298
  * P5 §4.6 (review fix): per-page attribution arrays are opt-in. Counters
@@ -419,7 +407,12 @@ export declare class DomPainter {
419
407
  */
420
408
  private recordPageWork;
421
409
  private renderColumnSeparators;
422
- private getColumnSeparatorPositions;
410
+ /**
411
+ * The resolved column geometry this region's separators are drawn from, or null when the region
412
+ * draws none. Returns the geometry rather than bare x positions because the gate needs to know
413
+ * WHICH column each separator follows, not only where it sits.
414
+ */
415
+ private resolveSeparatorColumnGeometry;
423
416
  private renderDecorationsForPage;
424
417
  /**
425
418
  * Check if a fragment is vertically anchored to the page.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BWWWNPP8.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let react = require("react");
5
5
  //#region src/public/ui/react.ts
@@ -118,6 +118,22 @@ var EMPTY_SELECTION = {
118
118
  function useSuperDocSelection() {
119
119
  return useSuperDocSlice((ui) => ui.selection, EMPTY_SELECTION);
120
120
  }
121
+ /** Subscribe to the current Search session. */
122
+ function useSuperDocSearch() {
123
+ return useSuperDocSlice((ui) => ui.search, {
124
+ query: "",
125
+ total: 0,
126
+ activeIndex: -1,
127
+ open: false,
128
+ available: false,
129
+ caseSensitive: false,
130
+ includeTrackedDeletions: false,
131
+ includeDeletedText: false,
132
+ regex: false,
133
+ canReplace: false,
134
+ canReplaceAll: false
135
+ });
136
+ }
121
137
  /** Subscribe to the comments slice. */
122
138
  function useSuperDocComments() {
123
139
  return useSuperDocSlice((ui) => ui.comments, {
@@ -238,6 +254,7 @@ exports.useSuperDocDocument = useSuperDocDocument;
238
254
  exports.useSuperDocFontOptions = useSuperDocFontOptions;
239
255
  exports.useSuperDocFontSizeOptions = useSuperDocFontSizeOptions;
240
256
  exports.useSuperDocHost = useSuperDocHost;
257
+ exports.useSuperDocSearch = useSuperDocSearch;
241
258
  exports.useSuperDocSelection = useSuperDocSelection;
242
259
  exports.useSuperDocSlice = useSuperDocSlice;
243
260
  exports.useSuperDocToolbar = useSuperDocToolbar;
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-FnwgTkUv.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
4
4
  //#region src/public/ui/react.ts
@@ -117,6 +117,22 @@ var EMPTY_SELECTION = {
117
117
  function useSuperDocSelection() {
118
118
  return useSuperDocSlice((ui) => ui.selection, EMPTY_SELECTION);
119
119
  }
120
+ /** Subscribe to the current Search session. */
121
+ function useSuperDocSearch() {
122
+ return useSuperDocSlice((ui) => ui.search, {
123
+ query: "",
124
+ total: 0,
125
+ activeIndex: -1,
126
+ open: false,
127
+ available: false,
128
+ caseSensitive: false,
129
+ includeTrackedDeletions: false,
130
+ includeDeletedText: false,
131
+ regex: false,
132
+ canReplace: false,
133
+ canReplaceAll: false
134
+ });
135
+ }
120
136
  /** Subscribe to the comments slice. */
121
137
  function useSuperDocComments() {
122
138
  return useSuperDocSlice((ui) => ui.comments, {
@@ -228,4 +244,4 @@ function useSuperDocZoom() {
228
244
  });
229
245
  }
230
246
  //#endregion
231
- export { SuperDocUIProvider, useSetSuperDoc, useSuperDocCommand, useSuperDocComments, useSuperDocContentControls, useSuperDocDocument, useSuperDocFontOptions, useSuperDocFontSizeOptions, useSuperDocHost, useSuperDocSelection, useSuperDocSlice, useSuperDocToolbar, useSuperDocTrackChanges, useSuperDocUI, useSuperDocZoom };
247
+ export { SuperDocUIProvider, useSetSuperDoc, useSuperDocCommand, useSuperDocComments, useSuperDocContentControls, useSuperDocDocument, useSuperDocFontOptions, useSuperDocFontSizeOptions, useSuperDocHost, useSuperDocSearch, useSuperDocSelection, useSuperDocSlice, useSuperDocToolbar, useSuperDocTrackChanges, useSuperDocUI, useSuperDocZoom };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BWWWNPP8.cjs");
3
3
  const require_slice_source = require("../chunks/slice-source-CFaqq0Vo.cjs");
4
4
  let vue = require("vue");
5
5
  //#region src/public/ui/vue.ts
@@ -189,6 +189,22 @@ var EMPTY_SELECTION = {
189
189
  function useSuperDocSelection() {
190
190
  return useSuperDocSlice((ui) => ui.selection, EMPTY_SELECTION);
191
191
  }
192
+ /** Subscribe to the current Search session. */
193
+ function useSuperDocSearch() {
194
+ return useSuperDocSlice((ui) => ui.search, {
195
+ query: "",
196
+ total: 0,
197
+ activeIndex: -1,
198
+ open: false,
199
+ available: false,
200
+ caseSensitive: false,
201
+ includeTrackedDeletions: false,
202
+ includeDeletedText: false,
203
+ regex: false,
204
+ canReplace: false,
205
+ canReplaceAll: false
206
+ });
207
+ }
192
208
  /** Subscribe to the comments slice. */
193
209
  function useSuperDocComments() {
194
210
  return useSuperDocSlice((ui) => ui.comments, {
@@ -310,6 +326,7 @@ exports.useSuperDocDocument = useSuperDocDocument;
310
326
  exports.useSuperDocFontOptions = useSuperDocFontOptions;
311
327
  exports.useSuperDocFontSizeOptions = useSuperDocFontSizeOptions;
312
328
  exports.useSuperDocHost = useSuperDocHost;
329
+ exports.useSuperDocSearch = useSuperDocSearch;
313
330
  exports.useSuperDocSelection = useSuperDocSelection;
314
331
  exports.useSuperDocSlice = useSuperDocSlice;
315
332
  exports.useSuperDocToolbar = useSuperDocToolbar;
@@ -1,4 +1,4 @@
1
- import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { t as createSuperDocUI } from "../chunks/create-super-doc-ui-FnwgTkUv.es.js";
2
2
  import { t as toSliceSource } from "../chunks/slice-source-gfOhG2MW.es.js";
3
3
  import { computed, inject, onScopeDispose, provide, shallowRef, toRaw, toValue, watch } from "vue";
4
4
  //#region src/public/ui/vue.ts
@@ -188,6 +188,22 @@ var EMPTY_SELECTION = {
188
188
  function useSuperDocSelection() {
189
189
  return useSuperDocSlice((ui) => ui.selection, EMPTY_SELECTION);
190
190
  }
191
+ /** Subscribe to the current Search session. */
192
+ function useSuperDocSearch() {
193
+ return useSuperDocSlice((ui) => ui.search, {
194
+ query: "",
195
+ total: 0,
196
+ activeIndex: -1,
197
+ open: false,
198
+ available: false,
199
+ caseSensitive: false,
200
+ includeTrackedDeletions: false,
201
+ includeDeletedText: false,
202
+ regex: false,
203
+ canReplace: false,
204
+ canReplaceAll: false
205
+ });
206
+ }
191
207
  /** Subscribe to the comments slice. */
192
208
  function useSuperDocComments() {
193
209
  return useSuperDocSlice((ui) => ui.comments, {
@@ -299,4 +315,4 @@ function useSuperDocZoom() {
299
315
  });
300
316
  }
301
317
  //#endregion
302
- export { provideSuperDocUI, useClearSuperDoc, useSetSuperDoc, useSuperDocCommand, useSuperDocComments, useSuperDocContentControls, useSuperDocDocument, useSuperDocFontOptions, useSuperDocFontSizeOptions, useSuperDocHost, useSuperDocSelection, useSuperDocSlice, useSuperDocToolbar, useSuperDocTrackChanges, useSuperDocUI, useSuperDocZoom };
318
+ export { provideSuperDocUI, useClearSuperDoc, useSetSuperDoc, useSuperDocCommand, useSuperDocComments, useSuperDocContentControls, useSuperDocDocument, useSuperDocFontOptions, useSuperDocFontSizeOptions, useSuperDocHost, useSuperDocSearch, useSuperDocSelection, useSuperDocSlice, useSuperDocToolbar, useSuperDocTrackChanges, useSuperDocUI, useSuperDocZoom };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-CBFGggZ2.cjs");
2
+ const require_create_super_doc_ui = require("../chunks/create-super-doc-ui-BWWWNPP8.cjs");
3
3
  exports.BUILT_IN_COMMAND_IDS = require_create_super_doc_ui.BUILT_IN_COMMAND_IDS;
4
4
  exports.createSuperDocUI = require_create_super_doc_ui.createSuperDocUI;
5
5
  exports.shallowEqual = require_create_super_doc_ui.shallowEqual;
@@ -1,2 +1,2 @@
1
- import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-C-AuEM9F.es.js";
1
+ import { n as shallowEqual, r as BUILT_IN_COMMAND_IDS, t as createSuperDocUI } from "../chunks/create-super-doc-ui-FnwgTkUv.es.js";
2
2
  export { BUILT_IN_COMMAND_IDS, createSuperDocUI, shallowEqual };
@@ -15,7 +15,7 @@
15
15
  */
16
16
  export type { FontLoadStatus, FontFaceSource, FontFaceDescriptor, RegisteredFace, RegisterFaceResult, FontLoadResult, FontLoadSummary, FontFaceRequest, FontFaceLoadResult, FontAssetUrlContext, FontAssetUrlResolver, RequiredFace, } from './types.js';
17
17
  export { SETTLED_STATUSES, isSettled } from './types.js';
18
- export type { FontResolution, FontResolutionReason, FaceKey, HasFace, FontMeasureContext, ResolvePhysicalFamily, ResolveNaturalLineMultiplier, } from './resolver.js';
18
+ export type { FontResolution, FontResolutionReason, FaceKey, HasFace, FontMeasureCapabilities, FontMeasureContext, FontMeasureFace, ResolvePhysicalFamily, ResolveNaturalLineMultiplier, } from './resolver.js';
19
19
  export { FontResolver, createFontResolver, insertFontFamilyBeforeGeneric } from './resolver.js';
20
20
  export { resolveFontFamily, resolvePhysicalFamily, resolvePrimaryPhysicalFamily, resolvePhysicalFamilies, resolveFace, DEFAULT_FONT_MEASURE_CONTEXT, } from './resolver.js';
21
21
  export { getFontConfigVersion, bumpFontConfigVersion, __resetFontConfigVersion } from './epoch.js';
@@ -212,6 +212,17 @@ export interface FontMeasureContext {
212
212
  resolveNaturalLineMultiplier?: ResolveNaturalLineMultiplier;
213
213
  fontSignature: string;
214
214
  }
215
+ /** Font face inputs whose measured digit advances can affect layout reuse. */
216
+ export interface FontMeasureFace {
217
+ family: string;
218
+ sizePx: number;
219
+ weight: FaceKey['weight'];
220
+ style: FaceKey['style'];
221
+ }
222
+ /** Immutable, invocation-scoped facts established by the active measurement surface. */
223
+ export interface FontMeasureCapabilities {
224
+ hasTabularDigits(face: FontMeasureFace): boolean;
225
+ }
215
226
  /**
216
227
  * The global-resolver / empty-signature context. The behavior-preserving default for outer entry
217
228
  * points and non-document callers (tests, the global measure path). Frozen so a stray