@vscode/markdown-editor 0.0.2-1 → 0.0.2-11

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.
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ export declare abstract class AstNode {
31
31
  * instances — keeping this O(children), not O(subtree). Leaves have no
32
32
  * children, so {@link _localEquals} is their whole comparison.
33
33
  */
34
- structurallyEqual(other: AstNode): boolean;
34
+ equalsShallow(other: AstNode): boolean;
35
35
  /** Compares only this node's own scalar fields (kind/length already match). */
36
36
  protected _localEquals(_other: this): boolean;
37
37
  /**
@@ -54,8 +54,41 @@ declare interface AstVisualizationNode {
54
54
  children?: AstVisualizationNode[];
55
55
  }
56
56
 
57
+ /**
58
+ * Strategy for hosts that never deliver native clipboard events to the editor
59
+ * — most importantly VS Code webviews, whose preload calls `preventDefault()`
60
+ * on the Ctrl/Cmd+C/X/V keydowns, so no `copy`/`cut`/`paste` event is ever
61
+ * dispatched. Here the keystrokes are the only signal, so this strategy
62
+ * listens for them directly and drives the async {@link Clipboard} API
63
+ * (`navigator.clipboard`), which webviews are granted.
64
+ *
65
+ * Cut deletes synchronously once the text is captured; the clipboard write is
66
+ * fire-and-forget. Paste must wait for the async read before inserting.
67
+ */
68
+ export declare class AsyncClipboardStrategy implements IClipboardStrategy {
69
+ private readonly _clipboard;
70
+ constructor(_clipboard?: Clipboard);
71
+ connect(context: IClipboardContext): IDisposable;
72
+ }
73
+
57
74
  export declare type BlockAstNode = HeadingAstNode | ParagraphAstNode | CodeBlockAstNode | MathBlockAstNode | ThematicBreakAstNode | BlockQuoteAstNode | ListAstNode | TableAstNode;
58
75
 
76
+ /**
77
+ * A block-level node. Every block may carry a {@link leadingTrivia} glue — the
78
+ * whitespace that precedes it on its own line (a nested list's indentation, the
79
+ * leading space of a continued paragraph). It is owned by the block it precedes
80
+ * (not the one it trails), so the view reveals it exactly when *this* block is
81
+ * active, and it tiles at the block's front: {@link children} prepends it to the
82
+ * block's own content while `content` stays the block's real payload.
83
+ */
84
+ declare abstract class BlockAstNodeBase extends AstNode {
85
+ abstract readonly leadingTrivia?: GlueAstNode;
86
+ /** This block with its leading trivia replaced — re-homes a leading glue onto it. */
87
+ abstract withLeadingTrivia(trivia: GlueAstNode | undefined): BlockAstNode;
88
+ /** Prepends {@link leadingTrivia}, if any, ahead of the block's own children. */
89
+ protected _withLeading(own: readonly AstNode[]): readonly AstNode[];
90
+ }
91
+
59
92
  /**
60
93
  * One block's place in the rendered document.
61
94
  *
@@ -79,13 +112,15 @@ export declare interface BlockMeasurement {
79
112
  readonly viewNode: ViewNode | undefined;
80
113
  }
81
114
 
82
- export declare class BlockQuoteAstNode extends AstNode {
115
+ export declare class BlockQuoteAstNode extends BlockAstNodeBase {
83
116
  readonly content: readonly (MarkerAstNode | BlockAstNode | GlueAstNode)[];
117
+ readonly leadingTrivia?: GlueAstNode | undefined;
84
118
  readonly kind = "blockQuote";
85
- constructor(content: readonly (MarkerAstNode | BlockAstNode | GlueAstNode)[]);
119
+ constructor(content: readonly (MarkerAstNode | BlockAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
86
120
  get children(): readonly AstNode[];
87
121
  get blocks(): readonly BlockAstNode[];
88
122
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
123
+ withLeadingTrivia(trivia: GlueAstNode | undefined): BlockQuoteAstNode;
89
124
  }
90
125
 
91
126
  declare class BlockQuoteViewData {
@@ -163,13 +198,14 @@ export declare interface BlockViewOptions {
163
198
  readonly renderMath?: (request: MathRenderRequest) => MathRendering | undefined;
164
199
  }
165
200
 
166
- export declare class CodeBlockAstNode extends AstNode {
201
+ export declare class CodeBlockAstNode extends BlockAstNodeBase {
167
202
  readonly language: string;
168
203
  readonly content: readonly (MarkerAstNode | GlueAstNode)[];
204
+ readonly leadingTrivia?: GlueAstNode | undefined;
169
205
  readonly kind = "codeBlock";
170
206
  private _previous?;
171
207
  private _contentEdit?;
172
- constructor(language: string, content: readonly (MarkerAstNode | GlueAstNode)[]);
208
+ constructor(language: string, content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
173
209
  get children(): readonly AstNode[];
174
210
  get openFence(): MarkerAstNode | undefined;
175
211
  get closeFence(): MarkerAstNode | undefined;
@@ -177,6 +213,7 @@ export declare class CodeBlockAstNode extends AstNode {
177
213
  /** Relative start offset of the {@link code} marker within this block. */
178
214
  get codeOffset(): number;
179
215
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
216
+ withLeadingTrivia(trivia: GlueAstNode | undefined): CodeBlockAstNode;
180
217
  protected _localEquals(o: this): boolean;
181
218
  /**
182
219
  * A copy of this block carrying an incremental link to `previous`:
@@ -301,6 +338,13 @@ export declare class CursorView extends Disposable {
301
338
  export declare interface CursorViewOptions {
302
339
  readonly offset: IObservable<SourceOffset | undefined>;
303
340
  readonly visualLineMap: IObservable<VisualLineMap>;
341
+ /**
342
+ * When set, the caret is drawn over the transient empty paragraph instead
343
+ * of at {@link offset} — its rect (in client coordinates) comes straight
344
+ * from that synthetic element's geometry, since it has no visual-line-map
345
+ * entry. Takes priority over the normal offset-based placement.
346
+ */
347
+ readonly pendingCaretRect?: IObservable<Rect2D | undefined>;
304
348
  }
305
349
 
306
350
  export declare class CursorViewRendering {
@@ -346,13 +390,14 @@ declare interface DocumentBlockViewData {
346
390
  readonly view: BlockViewData;
347
391
  }
348
392
 
349
- /** A mounted document child: a block or a run of inter-block glue. */
393
+ /** A mounted document child: a block, a run of inter-block glue, or the
394
+ * transient empty paragraph (see {@link PendingParagraphViewData}). */
350
395
  declare interface DocumentChildViewData {
351
396
  readonly absoluteStart: number;
352
- /** For a block: selection reaches it. For glue: a neighbouring block is active. */
397
+ /** For a block: selection reaches it. For glue: always false (unowned, hidden). */
353
398
  readonly isActive: boolean;
354
- readonly view: BlockViewData | GlueViewData;
355
- readonly kind: 'block' | 'glue';
399
+ readonly view: BlockViewData | GlueViewData | PendingParagraphViewData;
400
+ readonly kind: 'block' | 'glue' | 'pendingParagraph';
356
401
  }
357
402
 
358
403
  /**
@@ -408,6 +453,8 @@ declare class DocumentViewData {
408
453
  */
409
454
  export declare class DocumentViewNode extends ViewNode {
410
455
  readonly blocks: readonly DocumentBlock[];
456
+ /** The transient empty-paragraph element, when one is armed. */
457
+ readonly pendingElement?: HTMLElement | undefined;
411
458
  static create(viewData: DocumentViewData, options: BlockViewOptions | undefined, previous: DocumentViewNode | undefined): DocumentViewNode;
412
459
  private constructor();
413
460
  /** The stable content element this document mounts its children into. */
@@ -442,7 +489,7 @@ export declare class EditorController extends Disposable {
442
489
  private readonly _model;
443
490
  private readonly _view;
444
491
  private _desiredColumn;
445
- constructor(_model: EditorModel, _view: EditorView);
492
+ constructor(_model: EditorModel, _view: EditorView, options?: EditorControllerOptions);
446
493
  private readonly _handleTextUpdate;
447
494
  private readonly _handleMouseDown;
448
495
  private _makeCursorContext;
@@ -454,11 +501,25 @@ export declare class EditorController extends Disposable {
454
501
  cursorDown(extend?: boolean): void;
455
502
  /** Move the cursor up one visual line (Arrow Up). */
456
503
  cursorUp(extend?: boolean): void;
457
- private readonly _handleCopy;
458
- private readonly _handleCut;
459
- private readonly _handlePaste;
460
504
  private _selectedText;
505
+ private readonly _updateModifierState;
506
+ private readonly _clearModifierState;
461
507
  private readonly _handleKeyDown;
508
+ /**
509
+ * Context-aware Enter: splits / line-breaks via {@link insertSmartEnter}, or
510
+ * arms a transient empty paragraph when at the end of a paragraph.
511
+ */
512
+ private _smartEnter;
513
+ }
514
+
515
+ /** Options for an {@link EditorController}. */
516
+ export declare interface EditorControllerOptions {
517
+ /**
518
+ * How copy/cut/paste is handled. Defaults to {@link NativeClipboardStrategy},
519
+ * which reads the browser's native clipboard events — pass a different
520
+ * strategy (e.g. `AsyncClipboardStrategy`) in hosts that swallow them.
521
+ */
522
+ readonly clipboardStrategy?: IClipboardStrategy;
462
523
  }
463
524
 
464
525
  export declare class EditorModel {
@@ -476,6 +537,20 @@ export declare class EditorModel {
476
537
  * (e.g. an inactive/unfocused rendering).
477
538
  */
478
539
  readonly selection: ISettableObservable<Selection_2 | undefined, void>;
540
+ /**
541
+ * Whether a Ctrl/Cmd modifier is currently held. Set by the controller from
542
+ * live keyboard state; the view reads it to show the link-open affordance
543
+ * (underline + pointer cursor) only while a Ctrl/Cmd+click would open a link
544
+ * whose block is active.
545
+ */
546
+ readonly ctrlOrMetaDown: ISettableObservable<boolean, void>;
547
+ /**
548
+ * Gutter markers (source-control style change indicators) painted in the
549
+ * left gutter. Each entry maps a source {@link OffsetRange} to a change kind
550
+ * — see {@link GutterMarker}. Purely decorative: markers never affect the
551
+ * parsed {@link document}, selection, or layout. Empty by default.
552
+ */
553
+ readonly gutterMarkers: ISettableObservable<readonly GutterMarker[], void>;
479
554
  /**
480
555
  * Forces the rendered active-block set. `undefined` (the default)
481
556
  * derives the set from the current selection range (see
@@ -484,6 +559,13 @@ export declare class EditorModel {
484
559
  * collapsed/inactive rendering.
485
560
  */
486
561
  readonly activeBlocksOverride: ISettableObservable<readonly BlockAstNode[] | typeof NO_ACTIVE_BLOCKS | undefined, void>;
562
+ /**
563
+ * The transient empty-paragraph editing state, or `undefined` when none is
564
+ * armed. See {@link PendingParagraph}. This is *not* document data — it is
565
+ * cleared by any source edit and lives only between the Enter that armed it
566
+ * and the next keystroke.
567
+ */
568
+ readonly pendingParagraph: ISettableObservable<PendingParagraph | undefined, void>;
487
569
  readonly cursorOffset: IObservableWithChange<number | undefined, void>;
488
570
  /**
489
571
  * The parsed document. Threads the previous document into the parser so
@@ -507,6 +589,24 @@ export declare class EditorModel {
507
589
  * collapsed this is a one-element set holding {@link activeBlock}.
508
590
  */
509
591
  readonly activeBlocks: IObservableWithChange<Set<BlockAstNode>, void>;
592
+ /**
593
+ * Arm a {@link PendingParagraph} at the given gap, minting a fresh synthetic
594
+ * AST node for it, and park the caret at the gap start. No source edit is
595
+ * applied — the blank line exists only in the view until it is materialized.
596
+ */
597
+ armPendingParagraph(req: {
598
+ anchorBlock: BlockAstNode;
599
+ replaceRange: OffsetRange;
600
+ atEof: boolean;
601
+ }): void;
602
+ /** Discard the pending paragraph (if any) without touching the source. */
603
+ cancelPendingParagraph(): void;
604
+ /**
605
+ * Turn the pending paragraph into real source: rewrite its gap so the typed
606
+ * `text` becomes its own paragraph, separated from its neighbours by blank
607
+ * lines, and place the caret after the inserted text.
608
+ */
609
+ materializePendingParagraph(text: string): void;
510
610
  applyEdit(edit: StringEdit): void;
511
611
  applyEditForSelection(edit: StringEdit): void;
512
612
  }
@@ -540,8 +640,16 @@ export declare class EditorView extends Disposable {
540
640
  readonly element: HTMLElement;
541
641
  readonly editContext: EditContext;
542
642
  readonly measuredLayout: MeasuredLayoutModel;
643
+ /**
644
+ * Inner container that holds the rendered document and the cursor/selection
645
+ * overlays. The outer {@link element} spans the full width; this container
646
+ * is what limited-width mode caps and centers, so the overlays (which anchor
647
+ * to their parent's box) stay aligned with the content.
648
+ */
649
+ private readonly _contentContainer;
543
650
  private readonly _cursorView;
544
651
  private readonly _selectionView;
652
+ private readonly _gutterMarkersView;
545
653
  /**
546
654
  * The mounted block sequence, in source order. Rebuilt (not mutated) each
547
655
  * frame by {@link DocumentViewNode.create}; the view just swaps one
@@ -561,6 +669,13 @@ export declare class EditorView extends Disposable {
561
669
  /** The current view-data tree (AST overlaid with selection flags), for debugging. */
562
670
  private readonly _viewData;
563
671
  get viewData(): IObservable<DocumentViewData | undefined>;
672
+ /**
673
+ * Caret rect (client coords) for the transient empty paragraph, or
674
+ * `undefined` when none is armed. Set each frame from the synthetic
675
+ * paragraph element's geometry and fed to the {@link CursorView}, which has
676
+ * no visual-line-map entry to place the caret from otherwise.
677
+ */
678
+ private readonly _pendingCaretRect;
564
679
  /**
565
680
  * The block cache projected for views (selection painting) that need to
566
681
  * react to mount/unmount. Derived from {@link _document}, so it stays in
@@ -568,6 +683,13 @@ export declare class EditorView extends Disposable {
568
683
  */
569
684
  private readonly _selectionBlocksObs;
570
685
  constructor(_model: EditorModel, _options?: EditorViewOptions | undefined);
686
+ /**
687
+ * Mirrors the model's live Ctrl/Cmd state onto the editor root as
688
+ * `.md-mod-down` so CSS can show the link-open underline and pointer cursor
689
+ * only while a click would actually open the link: an inactive link opens on
690
+ * a plain click, but an active link only opens with the modifier held.
691
+ */
692
+ private _setupModifierTracking;
571
693
  focus(): void;
572
694
  /**
573
695
  * Client coordinates → absolute source offset (any block). Used during
@@ -603,6 +725,16 @@ export declare interface EditorViewOptions extends BlockViewOptions {
603
725
  * only) unless a theme class is supplied.
604
726
  */
605
727
  readonly classNames?: readonly string[];
728
+ /**
729
+ * Controls "limited width mode". The observable yields the maximum content
730
+ * width in pixels, or `undefined` to let the content fill the available
731
+ * width. When the option is omitted, the width is capped at
732
+ * {@link DEFAULT_LIMITED_WIDTH}px (limited mode is on by default).
733
+ *
734
+ * The cap and centering apply to an inner content container; the editor
735
+ * root ({@link element}) always spans the full available width.
736
+ */
737
+ readonly limitedWidth?: IObservable<number | undefined>;
606
738
  }
607
739
 
608
740
  export declare class EmphasisAstNode extends AstNode {
@@ -670,14 +802,39 @@ declare class GlueViewData {
670
802
  decorateNewline: boolean);
671
803
  }
672
804
 
673
- export declare class HeadingAstNode extends AstNode {
805
+ /**
806
+ * A single gutter marker: a source {@link OffsetRange} tagged with a
807
+ * {@link GutterMarkerType}. The view resolves the range to the visual lines it
808
+ * covers and paints a bar (or, for `deleted`, a wedge at the range position) in
809
+ * the left gutter.
810
+ *
811
+ * A `deleted` marker is normally an empty range (`range.isEmpty`) sitting at the
812
+ * boundary where the removed text used to be — there is nothing left to span,
813
+ * so it is drawn as a caret between lines rather than a bar.
814
+ */
815
+ export declare interface GutterMarker {
816
+ readonly range: OffsetRange;
817
+ readonly type: GutterMarkerType;
818
+ }
819
+
820
+ /**
821
+ * The kind of change a gutter marker represents, mirroring the three states a
822
+ * source-control diff distinguishes (the git change markers in the editor
823
+ * gutter): a freshly inserted region, an edited region, and a point where
824
+ * content was removed.
825
+ */
826
+ export declare type GutterMarkerType = 'added' | 'modified' | 'deleted';
827
+
828
+ export declare class HeadingAstNode extends BlockAstNodeBase {
674
829
  readonly level: 1 | 2 | 3 | 4 | 5 | 6;
675
830
  readonly marker: MarkerAstNode;
676
831
  readonly content: readonly (InlineAstNode | GlueAstNode)[];
832
+ readonly leadingTrivia?: GlueAstNode | undefined;
677
833
  readonly kind = "heading";
678
- constructor(level: 1 | 2 | 3 | 4 | 5 | 6, marker: MarkerAstNode, content: readonly (InlineAstNode | GlueAstNode)[]);
834
+ constructor(level: 1 | 2 | 3 | 4 | 5 | 6, marker: MarkerAstNode, content: readonly (InlineAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
679
835
  get children(): readonly AstNode[];
680
836
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
837
+ withLeadingTrivia(trivia: GlueAstNode | undefined): HeadingAstNode;
681
838
  protected _localEquals(o: this): boolean;
682
839
  }
683
840
 
@@ -688,6 +845,42 @@ declare class HeadingViewData {
688
845
  constructor(ast: HeadingAstNode, content: readonly AnyViewData[]);
689
846
  }
690
847
 
848
+ /**
849
+ * The editor operations a clipboard strategy drives. The strategy never
850
+ * touches the model or the DOM directly — it asks through this seam, so the
851
+ * same strategy works regardless of how the editor is wired up.
852
+ */
853
+ export declare interface IClipboardContext {
854
+ /** The element that owns focus and receives clipboard/keyboard events. */
855
+ readonly element: HTMLElement;
856
+ /** The selected source text, or `undefined` when the selection is empty. */
857
+ getSelectedText(): string | undefined;
858
+ /** Delete the current selection (the cut half of cut). */
859
+ deleteSelection(): void;
860
+ /** Insert text at the caret, replacing any selection (the paste action). */
861
+ insertText(text: string): void;
862
+ }
863
+
864
+ /**
865
+ * How copy/cut/paste intent reaches the editor. Host environments deliver it
866
+ * differently, so the controller owns no clipboard logic itself — it
867
+ * {@link connect}s a strategy and lets it install whatever listeners it needs.
868
+ *
869
+ * Two implementations ship:
870
+ * - {@link NativeClipboardStrategy} (default) reads the browser's native
871
+ * `copy`/`cut`/`paste` events and their synchronous `clipboardData`.
872
+ * - {@link AsyncClipboardStrategy} drives the async `navigator.clipboard` API
873
+ * from Ctrl/Cmd+C/X/V keystrokes, for hosts (e.g. VS Code webviews) that
874
+ * swallow the native clipboard events before they reach the editor.
875
+ */
876
+ export declare interface IClipboardStrategy {
877
+ /**
878
+ * Wire up clipboard handling against `context`. The returned disposable
879
+ * tears down every listener the strategy installed.
880
+ */
881
+ connect(context: IClipboardContext): IDisposable;
882
+ }
883
+
691
884
  /** The Monarch language definitions the default highlighter wires up. */
692
885
  export declare interface IDefaultMonarchGrammars {
693
886
  typescript: unknown;
@@ -782,6 +975,21 @@ export declare const insertLineBreak: EditCommand;
782
975
 
783
976
  export declare const insertParagraph: EditCommand;
784
977
 
978
+ /**
979
+ * Context-aware Enter. The behaviour is chosen from the active block:
980
+ * - paragraph / heading / thematic break — the "rich text" thing: at the
981
+ * block's end arm a transient empty paragraph (see {@link SmartEnterResult});
982
+ * elsewhere split into two paragraphs (`\n\n`).
983
+ * - code block — insert a newline that preserves the current line's indentation,
984
+ * staying inside the fence.
985
+ * - block quote — continue the quote (`\n> `); an empty quote line exits it.
986
+ * - list — continue the list with the next marker (incrementing ordered
987
+ * numbers, re-emitting task checkboxes); an empty item exits the list.
988
+ * A non-collapsed selection, or any other block, falls back to a plain soft line
989
+ * break, preserving today's behaviour.
990
+ */
991
+ export declare const insertSmartEnter: (ctx: CursorCommandContext) => SmartEnterResult;
992
+
785
993
  export declare function insertText(text: string): EditCommand;
786
994
 
787
995
  /**
@@ -886,14 +1094,16 @@ declare class LinkViewData {
886
1094
  constructor(ast: LinkAstNode, content: readonly AnyViewData[]);
887
1095
  }
888
1096
 
889
- export declare class ListAstNode extends AstNode {
1097
+ export declare class ListAstNode extends BlockAstNodeBase {
890
1098
  readonly ordered: boolean;
891
1099
  readonly content: readonly (ListItemAstNode | GlueAstNode)[];
1100
+ readonly leadingTrivia?: GlueAstNode | undefined;
892
1101
  readonly kind = "list";
893
- constructor(ordered: boolean, content: readonly (ListItemAstNode | GlueAstNode)[]);
1102
+ constructor(ordered: boolean, content: readonly (ListItemAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
894
1103
  get children(): readonly AstNode[];
895
1104
  get items(): readonly ListItemAstNode[];
896
1105
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1106
+ withLeadingTrivia(trivia: GlueAstNode | undefined): ListAstNode;
897
1107
  protected _localEquals(o: this): boolean;
898
1108
  }
899
1109
 
@@ -907,6 +1117,7 @@ export declare class ListItemAstNode extends AstNode {
907
1117
  get children(): readonly AstNode[];
908
1118
  get blocks(): readonly BlockAstNode[];
909
1119
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1120
+ withLeadingTrivia(trivia: GlueAstNode | undefined): ListItemAstNode;
910
1121
  protected _localEquals(o: this): boolean;
911
1122
  }
912
1123
 
@@ -960,13 +1171,15 @@ declare class MarkerViewData {
960
1171
  constructor(ast: MarkerAstNode, visible: boolean);
961
1172
  }
962
1173
 
963
- export declare class MathBlockAstNode extends AstNode {
1174
+ export declare class MathBlockAstNode extends BlockAstNodeBase {
964
1175
  readonly content: readonly (MarkerAstNode | GlueAstNode)[];
1176
+ readonly leadingTrivia?: GlueAstNode | undefined;
965
1177
  readonly kind = "mathBlock";
966
- constructor(content: readonly (MarkerAstNode | GlueAstNode)[]);
1178
+ constructor(content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
967
1179
  get children(): readonly AstNode[];
968
1180
  get code(): MarkerAstNode | undefined;
969
1181
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1182
+ withLeadingTrivia(trivia: GlueAstNode | undefined): MathBlockAstNode;
970
1183
  }
971
1184
 
972
1185
  declare class MathBlockViewData {
@@ -1129,6 +1342,17 @@ export declare class MonacoSyntaxHighlighter implements ISyntaxHighlighter {
1129
1342
  private _tokenizerFor;
1130
1343
  }
1131
1344
 
1345
+ /**
1346
+ * Default strategy: handle the browser's native `copy`/`cut`/`paste` events,
1347
+ * reading and writing the synchronous {@link ClipboardEvent.clipboardData}.
1348
+ * This is the standard rich-editor approach and works wherever the browser
1349
+ * actually dispatches those events to the focused element (e.g. a standalone
1350
+ * web page).
1351
+ */
1352
+ export declare class NativeClipboardStrategy implements IClipboardStrategy {
1353
+ connect(context: IClipboardContext): IDisposable;
1354
+ }
1355
+
1132
1356
  /**
1133
1357
  * Move the cursor one position left or right, skipping over hidden marker
1134
1358
  * ranges in inactive blocks (and inactive items of an active list).
@@ -1164,12 +1388,14 @@ export declare class OffsetRange {
1164
1388
  toString(): string;
1165
1389
  }
1166
1390
 
1167
- export declare class ParagraphAstNode extends AstNode {
1391
+ export declare class ParagraphAstNode extends BlockAstNodeBase {
1168
1392
  readonly content: readonly (InlineAstNode | GlueAstNode)[];
1393
+ readonly leadingTrivia?: GlueAstNode | undefined;
1169
1394
  readonly kind = "paragraph";
1170
- constructor(content: readonly (InlineAstNode | GlueAstNode)[]);
1395
+ constructor(content: readonly (InlineAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
1171
1396
  get children(): readonly AstNode[];
1172
1397
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1398
+ withLeadingTrivia(trivia: GlueAstNode | undefined): ParagraphAstNode;
1173
1399
  }
1174
1400
 
1175
1401
  declare class ParagraphViewData {
@@ -1179,6 +1405,45 @@ declare class ParagraphViewData {
1179
1405
  constructor(ast: ParagraphAstNode, content: readonly AnyViewData[]);
1180
1406
  }
1181
1407
 
1408
+ /**
1409
+ * A *transient* editing state: the empty paragraph the user conjured by
1410
+ * pressing Enter at the end of a paragraph. Markdown has no empty-paragraph
1411
+ * node, so this never lives in {@link EditorModel.sourceText} or the parsed
1412
+ * {@link EditorModel.document} — it is pure edit intent that the view renders
1413
+ * as a synthetic blank line and that the controller either *materializes* (the
1414
+ * user types) or *cancels* (the user navigates away / backspaces).
1415
+ */
1416
+ declare interface PendingParagraph {
1417
+ /** The paragraph the blank line is rendered directly after. */
1418
+ readonly anchorBlock: BlockAstNode;
1419
+ /**
1420
+ * Source region rewritten when the pending paragraph is materialized — the
1421
+ * gap between {@link anchorBlock}'s text and whatever follows it.
1422
+ */
1423
+ readonly replaceRange: OffsetRange;
1424
+ /** Whether {@link replaceRange} ends at the end of the document. */
1425
+ readonly atEof: boolean;
1426
+ /**
1427
+ * A throwaway AST node that exists only to give the synthetic view child a
1428
+ * stable identity across render frames (the view pairs nodes by `ast.id`).
1429
+ * It is never part of {@link document}.
1430
+ */
1431
+ readonly syntheticAst: ParagraphAstNode;
1432
+ }
1433
+
1434
+ /**
1435
+ * View-data for the transient empty paragraph (see `PendingParagraph` in the
1436
+ * model). It carries only the throwaway {@link ParagraphAstNode} that gives the
1437
+ * rendered blank line a stable identity across frames; it has no content and is
1438
+ * never measured or part of the selection geometry — the caret is positioned
1439
+ * over it via a dedicated rect, not via the visual-line map.
1440
+ */
1441
+ declare class PendingParagraphViewData {
1442
+ readonly ast: ParagraphAstNode;
1443
+ readonly kind = "pendingParagraph";
1444
+ constructor(ast: ParagraphAstNode);
1445
+ }
1446
+
1182
1447
  /**
1183
1448
  * Immutable point in 2D space, in CSS-pixel client coordinates.
1184
1449
  */
@@ -1296,6 +1561,25 @@ export declare class SelectionViewRendering {
1296
1561
 
1297
1562
  export declare const selectWord: SelectionCommand;
1298
1563
 
1564
+ /**
1565
+ * The outcome of {@link insertSmartEnter}: either a concrete source edit (the
1566
+ * ordinary cases), or a request to arm a transient empty paragraph (Enter at
1567
+ * the very end of a paragraph), which the controller turns into
1568
+ * {@link EditorModel.armPendingParagraph} rather than a source edit. Modelling
1569
+ * the empty paragraph as state instead of source keeps the document valid
1570
+ * Markdown — which has no empty-paragraph node — until the user actually types.
1571
+ */
1572
+ export declare type SmartEnterResult = {
1573
+ readonly kind: 'edit';
1574
+ readonly edit: StringEdit;
1575
+ readonly selection: Selection_2;
1576
+ } | {
1577
+ readonly kind: 'pending';
1578
+ readonly anchorBlock: BlockAstNode;
1579
+ readonly replaceRange: OffsetRange;
1580
+ readonly atEof: boolean;
1581
+ };
1582
+
1299
1583
  /**
1300
1584
  * A run of {@link Token}s together with the exact {@link OffsetRange} they
1301
1585
  * cover.
@@ -1381,16 +1665,18 @@ declare class StrongViewData {
1381
1665
  constructor(ast: StrongAstNode, content: readonly AnyViewData[]);
1382
1666
  }
1383
1667
 
1384
- export declare class TableAstNode extends AstNode {
1668
+ export declare class TableAstNode extends BlockAstNodeBase {
1385
1669
  readonly content: readonly (TableRowAstNode | GlueAstNode)[];
1670
+ readonly leadingTrivia?: GlueAstNode | undefined;
1386
1671
  readonly kind = "table";
1387
- constructor(content: readonly (TableRowAstNode | GlueAstNode)[]);
1672
+ constructor(content: readonly (TableRowAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
1388
1673
  get children(): readonly AstNode[];
1389
1674
  private get _rows();
1390
1675
  get headerRow(): TableRowAstNode | undefined;
1391
1676
  get delimiterRow(): TableRowAstNode | undefined;
1392
1677
  get bodyRows(): readonly TableRowAstNode[];
1393
1678
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1679
+ withLeadingTrivia(trivia: GlueAstNode | undefined): TableAstNode;
1394
1680
  }
1395
1681
 
1396
1682
  export declare class TableCellAstNode extends AstNode {
@@ -1472,13 +1758,15 @@ declare class TextViewData {
1472
1758
  constructor(ast: TextAstNode, showWhitespace: boolean, leftWordBoundary?: boolean, rightWordBoundary?: boolean);
1473
1759
  }
1474
1760
 
1475
- export declare class ThematicBreakAstNode extends AstNode {
1761
+ export declare class ThematicBreakAstNode extends BlockAstNodeBase {
1476
1762
  readonly content: readonly (MarkerAstNode | GlueAstNode)[];
1763
+ readonly leadingTrivia?: GlueAstNode | undefined;
1477
1764
  readonly kind = "thematicBreak";
1478
- constructor(content: readonly (MarkerAstNode | GlueAstNode)[]);
1765
+ constructor(content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
1479
1766
  get children(): readonly AstNode[];
1480
1767
  get marker(): MarkerAstNode | undefined;
1481
1768
  mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1769
+ withLeadingTrivia(trivia: GlueAstNode | undefined): ThematicBreakAstNode;
1482
1770
  }
1483
1771
 
1484
1772
  declare class ThematicBreakViewData {