@mdzip/editor 1.3.21 → 1.4.4
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/README.md +62 -0
- package/dist/archive-utils.d.ts.map +1 -1
- package/dist/archive-utils.js +16 -2
- package/dist/archive-utils.js.map +1 -1
- package/dist/asset-cache.d.ts +14 -0
- package/dist/asset-cache.d.ts.map +1 -1
- package/dist/asset-cache.js +57 -0
- package/dist/asset-cache.js.map +1 -1
- package/dist/front-matter-extension.d.ts +45 -0
- package/dist/front-matter-extension.d.ts.map +1 -0
- package/dist/front-matter-extension.js +114 -0
- package/dist/front-matter-extension.js.map +1 -0
- package/dist/front-matter.d.ts +18 -0
- package/dist/front-matter.d.ts.map +1 -0
- package/dist/front-matter.js +48 -0
- package/dist/front-matter.js.map +1 -0
- package/dist/highlight-core.d.ts +3 -0
- package/dist/highlight-core.d.ts.map +1 -0
- package/dist/highlight-core.js +53 -0
- package/dist/highlight-core.js.map +1 -0
- package/dist/image-edit.d.ts +26 -0
- package/dist/image-edit.d.ts.map +1 -0
- package/dist/image-edit.js +195 -0
- package/dist/image-edit.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/library-info.d.ts +2 -2
- package/dist/library-info.js +2 -2
- package/dist/library-info.js.map +1 -1
- package/dist/mdz-archive-worker-protocol.d.ts +36 -0
- package/dist/mdz-archive-worker-protocol.d.ts.map +1 -0
- package/dist/mdz-archive-worker-protocol.js +2 -0
- package/dist/mdz-archive-worker-protocol.js.map +1 -0
- package/dist/mdz-archive.worker-client.d.ts +30 -0
- package/dist/mdz-archive.worker-client.d.ts.map +1 -0
- package/dist/mdz-archive.worker-client.js +97 -0
- package/dist/mdz-archive.worker-client.js.map +1 -0
- package/dist/mdz-archive.worker.d.ts +2 -0
- package/dist/mdz-archive.worker.d.ts.map +1 -0
- package/dist/mdz-archive.worker.js +8870 -0
- package/dist/mdz-archive.worker.js.map +1 -0
- package/dist/mermaid.d.ts.map +1 -1
- package/dist/mermaid.js +60 -41
- package/dist/mermaid.js.map +1 -1
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +12 -2
- package/dist/metadata.js.map +1 -1
- package/dist/preview.d.ts +1 -0
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +1 -0
- package/dist/preview.js.map +1 -1
- package/dist/rendering.d.ts +114 -0
- package/dist/rendering.d.ts.map +1 -1
- package/dist/rendering.js +153 -1
- package/dist/rendering.js.map +1 -1
- package/dist/stats.d.ts +23 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +31 -0
- package/dist/stats.js.map +1 -0
- package/dist/view-css.d.ts.map +1 -1
- package/dist/view-css.js +112 -0
- package/dist/view-css.js.map +1 -1
- package/dist/view.d.ts +421 -1
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +2219 -410
- package/dist/view.js.map +1 -1
- package/dist/workspace.d.ts +14 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +53 -41
- package/dist/workspace.js.map +1 -1
- package/package.json +11 -5
package/dist/view.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { MdzWorkspace, MdzWorkspaceAsset } from '@mdzip/core-js';
|
|
|
2
2
|
import { type MdzipAssetCache } from './asset-cache.js';
|
|
3
3
|
import type { MdzipDocumentChangeEvent, MdzipEditorSnapshot, MdzipRemoveAssetOptions, MdzipWorkspaceOpenOptions } from './workspace.js';
|
|
4
4
|
import { type MdzipEntryRenderer, type MdzipMarkdownRenderer, type MdzipMarkdownRenderExtension } from './rendering.js';
|
|
5
|
+
import { type MdzipFrontMatterOptions } from './front-matter-extension.js';
|
|
5
6
|
import type { MdzipWorkspaceSnapshot } from './workspace.js';
|
|
6
7
|
export declare const DEFAULT_CODE_BLOCK_LANGUAGES: readonly MdzipCodeBlockLanguage[];
|
|
7
8
|
export type MdzipWorkspaceLayout = 'preview' | 'source' | 'split';
|
|
@@ -38,6 +39,28 @@ export interface MdzipImageInsertDecision {
|
|
|
38
39
|
position?: MdzipImagePosition;
|
|
39
40
|
}
|
|
40
41
|
export type MdzipImageInsertHandler = (request: MdzipImageInsertRequest) => MdzipImageInsertDecision | null | undefined | Promise<MdzipImageInsertDecision | null | undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* Parsed from the image reference (Markdown or raw HTML) currently under an
|
|
44
|
+
* edit-affordance click.
|
|
45
|
+
*/
|
|
46
|
+
export interface MdzipImageEditRequest {
|
|
47
|
+
src: string;
|
|
48
|
+
altText: string;
|
|
49
|
+
width?: number;
|
|
50
|
+
height?: number;
|
|
51
|
+
position?: MdzipImagePosition;
|
|
52
|
+
/** Which form the image is currently written in. */
|
|
53
|
+
mode: MdzipImageInsertOutputMode;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Host-owned async UI for editing an existing image's alt/size/position.
|
|
57
|
+
* Invoked when the user clicks an existing image's edit affordance in the
|
|
58
|
+
* source editor; returning `null`/`undefined` cancels, leaving the image
|
|
59
|
+
* untouched. Reuses `MdzipImageInsertDecision` as its resolution shape.
|
|
60
|
+
* Fully opt-in: with no `imageEditHandler` set, no affordance ever appears
|
|
61
|
+
* and clicking an image does nothing — there is no built-in fallback dialog.
|
|
62
|
+
*/
|
|
63
|
+
export type MdzipImageEditHandler = (request: MdzipImageEditRequest) => MdzipImageInsertDecision | null | undefined | Promise<MdzipImageInsertDecision | null | undefined>;
|
|
41
64
|
export type MdzipEditorCommand = 'bold' | 'italic' | 'strikethrough' | 'highlight' | 'paragraph' | `heading-${MdzipHeadingLevel}` | 'bullet-list' | 'ordered-list' | 'inline-code' | 'code-block' | 'blockquote' | 'insert-line-break' | 'link' | 'insert-image';
|
|
42
65
|
export type MdzipConversionAction = {
|
|
43
66
|
kind: 'navigation';
|
|
@@ -228,6 +251,19 @@ export interface MdzipWorkspaceViewOptions {
|
|
|
228
251
|
* not (see {@link MdzipWorkspaceView.setPreviewMaxWidth}).
|
|
229
252
|
*/
|
|
230
253
|
previewMaxWidth?: MdzipPreviewMaxWidth;
|
|
254
|
+
/**
|
|
255
|
+
* Opt-in: render+mount the preview in chunks near the viewport instead of
|
|
256
|
+
* the whole document at once. For very large documents (e.g. a chat
|
|
257
|
+
* export with thousands of message rows) this keeps first-paint cost
|
|
258
|
+
* proportional to what's visible instead of the whole document's size —
|
|
259
|
+
* `marked`/DOMPurify otherwise run once, synchronously, over the entire
|
|
260
|
+
* rendered HTML before anything is mounted, which can block the main
|
|
261
|
+
* thread for seconds on real-world large files. Defaults to `false`.
|
|
262
|
+
* Only takes effect with the default marked-based renderer — a
|
|
263
|
+
* host-supplied custom {@link MdzipMarkdownRenderer} has no token
|
|
264
|
+
* structure to chunk by, so this option is silently ignored for it.
|
|
265
|
+
*/
|
|
266
|
+
progressiveTextRendering?: boolean;
|
|
231
267
|
/**
|
|
232
268
|
* Controls the progressive preview image reveal animation. Use `'off'` in
|
|
233
269
|
* live-editing hosts to prevent images from pulsing/sliding. Use `'initial'`
|
|
@@ -248,6 +284,14 @@ export interface MdzipWorkspaceViewOptions {
|
|
|
248
284
|
* the insertion cleanly.
|
|
249
285
|
*/
|
|
250
286
|
imageInsertHandler?: MdzipImageInsertHandler;
|
|
287
|
+
/**
|
|
288
|
+
* Optional host-owned async UI for editing an existing image (alt/size/
|
|
289
|
+
* position), opened by clicking that image's edit affordance in the
|
|
290
|
+
* source editor. Unset by default — with no handler, no affordance
|
|
291
|
+
* appears at all; there is no built-in fallback dialog like
|
|
292
|
+
* `imageInsertMode: 'ask'` provides for insertion.
|
|
293
|
+
*/
|
|
294
|
+
imageEditHandler?: MdzipImageEditHandler;
|
|
251
295
|
/**
|
|
252
296
|
* Languages offered in the context menu's Code Block submenu. Each entry's
|
|
253
297
|
* `id` becomes the fence info string (e.g. ```` ```ts ````); an empty `id`
|
|
@@ -337,6 +381,14 @@ export interface MdzipWorkspaceViewOptions {
|
|
|
337
381
|
* the fallback. Handles are destroyed on selection change and destroy().
|
|
338
382
|
*/
|
|
339
383
|
entryRenderers?: readonly MdzipEntryRenderer[];
|
|
384
|
+
/**
|
|
385
|
+
* Controls how a leading `---`-delimited YAML front matter block renders
|
|
386
|
+
* in the preview — display (table/raw), the collapsible expander, and its
|
|
387
|
+
* label. Unlike `markdownExtensions` (which is entirely opt-in), front
|
|
388
|
+
* matter handling is always registered; this only configures it. See
|
|
389
|
+
* {@link MdzipFrontMatterOptions}.
|
|
390
|
+
*/
|
|
391
|
+
frontMatter?: MdzipFrontMatterOptions;
|
|
340
392
|
}
|
|
341
393
|
/** Options accepted by {@link MdzipWorkspaceView.setRenderingOptions}. */
|
|
342
394
|
export interface MdzipRenderingOptions {
|
|
@@ -344,6 +396,7 @@ export interface MdzipRenderingOptions {
|
|
|
344
396
|
markdownRenderer?: MdzipMarkdownRenderer | null;
|
|
345
397
|
markdownExtensions?: readonly MdzipMarkdownRenderExtension[];
|
|
346
398
|
entryRenderers?: readonly MdzipEntryRenderer[];
|
|
399
|
+
frontMatter?: MdzipFrontMatterOptions;
|
|
347
400
|
}
|
|
348
401
|
export declare function resolveMdzipControlPolicy(controls: MdzipControlPreset | MdzipControlPolicy | undefined): MdzipResolvedControlPolicy;
|
|
349
402
|
export declare class MdzipWorkspaceView {
|
|
@@ -354,6 +407,7 @@ export declare class MdzipWorkspaceView {
|
|
|
354
407
|
private controlPolicy;
|
|
355
408
|
private readonly navigationMode;
|
|
356
409
|
private imageHydrationAnimation;
|
|
410
|
+
private readonly progressiveTextRendering;
|
|
357
411
|
private toolbarDensity;
|
|
358
412
|
private contentDensity;
|
|
359
413
|
private previewMaxWidth;
|
|
@@ -368,6 +422,11 @@ export declare class MdzipWorkspaceView {
|
|
|
368
422
|
private conversionAction;
|
|
369
423
|
private imageInsertDialogState;
|
|
370
424
|
private packFilesDialogState;
|
|
425
|
+
private chunkedRenderState;
|
|
426
|
+
private chunkHtmlCache;
|
|
427
|
+
private copyRenderDialogState;
|
|
428
|
+
private copyReadyState;
|
|
429
|
+
private copyRenderDoneState;
|
|
371
430
|
private navPaneWidth;
|
|
372
431
|
private splitRatio;
|
|
373
432
|
private resizing;
|
|
@@ -384,6 +443,9 @@ export declare class MdzipWorkspaceView {
|
|
|
384
443
|
private tooltipState;
|
|
385
444
|
private tooltipShowTimer;
|
|
386
445
|
private tooltipHideTimer;
|
|
446
|
+
private copyToastHideTimer;
|
|
447
|
+
private clipboardWriteTimeoutMs;
|
|
448
|
+
private clipboardFallbackWriteTimeoutMs;
|
|
387
449
|
private cmEditor;
|
|
388
450
|
private readonly readOnlyCompartment;
|
|
389
451
|
private readonly lineNumbersCompartment;
|
|
@@ -392,8 +454,17 @@ export declare class MdzipWorkspaceView {
|
|
|
392
454
|
private syncing;
|
|
393
455
|
private lastSyncedEditorScrollTop;
|
|
394
456
|
private lastSyncedPreviewScrollTop;
|
|
457
|
+
private lastContentChangeTime;
|
|
458
|
+
private static readonly SCROLL_SYNC_SETTLE_MS;
|
|
459
|
+
private lastEditorGestureTime;
|
|
460
|
+
private lastPreviewGestureTime;
|
|
461
|
+
private static readonly SCROLL_SYNC_GESTURE_WINDOW_MS;
|
|
462
|
+
private pendingPreviewScrollRestore;
|
|
463
|
+
private bottomDrainGeneration;
|
|
464
|
+
private scrollCatchUpState;
|
|
395
465
|
private markdownRenderer?;
|
|
396
466
|
private markdownExtensions;
|
|
467
|
+
private frontMatterOptions;
|
|
397
468
|
private entryRenderers;
|
|
398
469
|
private renderingService;
|
|
399
470
|
private previewMemo;
|
|
@@ -462,6 +533,17 @@ export declare class MdzipWorkspaceView {
|
|
|
462
533
|
private readonly elPackFilesModeProject;
|
|
463
534
|
private readonly elPackFilesEntrySelect;
|
|
464
535
|
private readonly elPackFilesConfirmBtn;
|
|
536
|
+
private readonly elCopyRenderDialog;
|
|
537
|
+
private readonly elCopyRenderHeading;
|
|
538
|
+
private readonly elCopyRenderProgressSection;
|
|
539
|
+
private readonly elCopyRenderProgressBar;
|
|
540
|
+
private readonly elCopyRenderProgressText;
|
|
541
|
+
private readonly elCopyRenderReadyText;
|
|
542
|
+
private readonly elCopyRenderDoneText;
|
|
543
|
+
private readonly elCopyRenderCancelBtn;
|
|
544
|
+
private readonly elCopyRenderReadyCancelBtn;
|
|
545
|
+
private readonly elCopyRenderConfirmBtn;
|
|
546
|
+
private readonly elCopyRenderDismissBtn;
|
|
465
547
|
private readonly elNavMenu;
|
|
466
548
|
private readonly elNameDialog;
|
|
467
549
|
private readonly elNameDialogHeading;
|
|
@@ -473,6 +555,7 @@ export declare class MdzipWorkspaceView {
|
|
|
473
555
|
private readonly elDeleteConfirmBtn;
|
|
474
556
|
private readonly elReplaceInput;
|
|
475
557
|
private readonly elTooltip;
|
|
558
|
+
private readonly elCopyToast;
|
|
476
559
|
private readonly elEmptyState;
|
|
477
560
|
constructor(container: HTMLElement, options?: MdzipWorkspaceViewOptions);
|
|
478
561
|
/**
|
|
@@ -545,6 +628,26 @@ export declare class MdzipWorkspaceView {
|
|
|
545
628
|
* renderer re-match.
|
|
546
629
|
*/
|
|
547
630
|
setRenderingOptions(options: MdzipRenderingOptions): void;
|
|
631
|
+
/**
|
|
632
|
+
* The extensions actually handed to `MdzipRenderingService`: the front
|
|
633
|
+
* matter extension first (always on — see `frontMatterOptions`), then
|
|
634
|
+
* whatever extensions the host passed via `markdownExtensions`. A fresh
|
|
635
|
+
* front matter extension instance is created each time this runs (view
|
|
636
|
+
* construction, `setRenderingOptions`), which is fine — its per-render
|
|
637
|
+
* state lives in a `WeakMap` keyed by the render context, not on the
|
|
638
|
+
* extension instance across renders.
|
|
639
|
+
*/
|
|
640
|
+
private pipelineMarkdownExtensions;
|
|
641
|
+
/**
|
|
642
|
+
* Chunking options combining every registered extension's
|
|
643
|
+
* {@link MdzipMarkdownRenderExtension.shouldIsolateChunk} — see that doc
|
|
644
|
+
* comment for why a token an extension owns needs its own chunk regardless
|
|
645
|
+
* of the size budget — with the same treatment built in for any token that
|
|
646
|
+
* embeds an image ({@link tokenEmbedsImage}'s doc comment), plus a forced
|
|
647
|
+
* chunk boundary at every heading ({@link tokenIsHeading}'s doc comment)
|
|
648
|
+
* so unrelated sections never share a chunk.
|
|
649
|
+
*/
|
|
650
|
+
private chunkOptions;
|
|
548
651
|
/**
|
|
549
652
|
* Replaces the view control policy without recreating the workspace or
|
|
550
653
|
* CodeMirror editor. In particular, `lineNumbers` is reconfigured through a
|
|
@@ -562,6 +665,7 @@ export declare class MdzipWorkspaceView {
|
|
|
562
665
|
*/
|
|
563
666
|
setPreviewMaxWidth(value: MdzipPreviewMaxWidth | undefined): void;
|
|
564
667
|
setImageInsertOptions(options: Pick<MdzipWorkspaceViewOptions, 'imageInsertMode' | 'imageInsertHandler'>): void;
|
|
668
|
+
setImageEditOptions(options: Pick<MdzipWorkspaceViewOptions, 'imageEditHandler'>): void;
|
|
565
669
|
private applyDensityClasses;
|
|
566
670
|
/**
|
|
567
671
|
* Tears down all custom rendering state: aborts in-flight renders, destroys
|
|
@@ -572,6 +676,8 @@ export declare class MdzipWorkspaceView {
|
|
|
572
676
|
private replaceAssetSession;
|
|
573
677
|
private resetPreviewState;
|
|
574
678
|
private destroyPreviewHandles;
|
|
679
|
+
/** True when `this.previewMemo` — and by extension `this.previewGeneration` — still represents `snapshot`: nothing that feeds the preview (path, pathType, text, colorScheme) has changed since it was last rendered. */
|
|
680
|
+
private previewMemoMatchesSnapshot;
|
|
575
681
|
private updatePreview;
|
|
576
682
|
private applyPreviewHtml;
|
|
577
683
|
private shouldAnimateImageHydration;
|
|
@@ -583,6 +689,160 @@ export declare class MdzipWorkspaceView {
|
|
|
583
689
|
* has resolved and had its final `src` assigned (or there are none).
|
|
584
690
|
*/
|
|
585
691
|
private mountProgressivePreview;
|
|
692
|
+
/**
|
|
693
|
+
* Cheap, attribute-only pass over every `<img>` under `roots`: no DOM tree
|
|
694
|
+
* mutation. Archive-relative sources have their `src` stripped here
|
|
695
|
+
* (immediately, so the browser never fires a bad network request for the
|
|
696
|
+
* archive-relative path) and are returned for {@link hydrateImages};
|
|
697
|
+
* external/data/fragment sources are left untouched (just get their align
|
|
698
|
+
* class, if any — they never get a slot). Returns `[]` without touching
|
|
699
|
+
* anything when there's no asset session to resolve archive images
|
|
700
|
+
* against, matching `mountPreviewHtml`'s no-op image handling.
|
|
701
|
+
*
|
|
702
|
+
* An image this session has *already* resolved once (e.g. it was already
|
|
703
|
+
* on screen before an edit elsewhere caused its chunk to remount) is
|
|
704
|
+
* applied immediately here via `resolveKnownImage` — no slot, no loading
|
|
705
|
+
* class, no `hydrateImages`/`IntersectionObserver` round trip — instead of
|
|
706
|
+
* being handed to the async placeholder-then-swap path meant for an image
|
|
707
|
+
* that's genuinely being resolved for the first time. Skipping that path
|
|
708
|
+
* for a re-mount of an already-known image is what actually avoids the
|
|
709
|
+
* visible flash; still going through it (even instantly) briefly blanks
|
|
710
|
+
* the image, since a fresh `<img>` element never carries over its
|
|
711
|
+
* predecessor's already-resolved `src`.
|
|
712
|
+
*/
|
|
713
|
+
private collectPendingImages;
|
|
714
|
+
/**
|
|
715
|
+
* Slot-wraps and resolves `pending` images (from {@link collectPendingImages}),
|
|
716
|
+
* only decompressing/resolving ones near the viewport up front — a
|
|
717
|
+
* document with a few hundred distinct embedded images would otherwise
|
|
718
|
+
* decompress and blob-URL every one of them synchronously, freezing the UI
|
|
719
|
+
* for as long as that takes. Falls back to eager resolution when
|
|
720
|
+
* IntersectionObserver isn't available (e.g. non-browser hosts). Calls
|
|
721
|
+
* `onSettled` once every image in `pending` has resolved (or immediately
|
|
722
|
+
* if `pending` is empty) — callers that want a single "hydrated" signal
|
|
723
|
+
* for a whole preview pass `pending` from every root at once; callers
|
|
724
|
+
* mounting one chunk among several within the same generation (see
|
|
725
|
+
* {@link mountChunkBatch}) pass a no-op instead, so the signal only fires
|
|
726
|
+
* once, for the batch it's semantically tied to.
|
|
727
|
+
*/
|
|
728
|
+
private hydrateImages;
|
|
729
|
+
/**
|
|
730
|
+
* Opt-in (`progressiveTextRendering`) alternative to the whole-document
|
|
731
|
+
* `renderMarkdown()` path above: tokenizes the markdown once, then renders
|
|
732
|
+
* and mounts it in chunks near the viewport instead of all at once — see
|
|
733
|
+
* {@link mountChunkedPreview}. Only reachable when
|
|
734
|
+
* `renderingService.supportsChunking` is true (the default marked-based
|
|
735
|
+
* renderer); the caller already checked that.
|
|
736
|
+
*/
|
|
737
|
+
private renderChunkedPreview;
|
|
738
|
+
/**
|
|
739
|
+
* Same-document, text-only-edit counterpart to {@link renderChunkedPreview}:
|
|
740
|
+
* tokenizes the new text, then reconciles against the *previous* render's
|
|
741
|
+
* records (`priorState`) instead of tearing everything down. Only reachable
|
|
742
|
+
* when `updatePreview` determined the prior chunked structure is still
|
|
743
|
+
* reuse-eligible (same path/pathType/colorScheme); the caller already
|
|
744
|
+
* checked that.
|
|
745
|
+
*/
|
|
746
|
+
private reconcileChunkedPreview;
|
|
747
|
+
/** Destroys one chunk record's mounted DOM and handles (but not the record object itself). */
|
|
748
|
+
private teardownChunkRecord;
|
|
749
|
+
/**
|
|
750
|
+
* Diffs the new tokenize pass's chunks against `priorState.records` by
|
|
751
|
+
* source-text identity (`chunkSourceKey`) and reconciles: chunks in the
|
|
752
|
+
* matched leading/trailing run keep their existing DOM and handles
|
|
753
|
+
* untouched (never re-rendered, never re-mounted — see
|
|
754
|
+
* `chunkSourceKey`'s doc comment for why that matters for extensions like
|
|
755
|
+
* mermaid); only the "middle" range that actually changed is torn down and
|
|
756
|
+
* remounted. Uses prefix/suffix matching rather than a general LCS — a
|
|
757
|
+
* text editor's edits are localized, so this is both simpler and correct
|
|
758
|
+
* for the real-world case.
|
|
759
|
+
*/
|
|
760
|
+
private applyChunkReconciliation;
|
|
761
|
+
/**
|
|
762
|
+
* Mounts a reconciliation's replacement "middle" range in full (uncapped —
|
|
763
|
+
* a single edit only ever touches 1-2 chunks in practice; see the plan's
|
|
764
|
+
* disclosed v1 risk for the pathological large-paste case), then carries
|
|
765
|
+
* forward however much of the surviving suffix was already mounted before
|
|
766
|
+
* reconciling, and re-arms the sentinel for whatever's still left.
|
|
767
|
+
*/
|
|
768
|
+
private mountReconciledMiddle;
|
|
769
|
+
/**
|
|
770
|
+
* Groups tokens into chunks and mounts them: an initial batch synchronously
|
|
771
|
+
* (enough for a small document to behave exactly like the non-chunked
|
|
772
|
+
* path), then the rest as the user scrolls near a trailing sentinel
|
|
773
|
+
* element, via the same `IntersectionObserver` + time-budgeted-rAF pattern
|
|
774
|
+
* already used for image hydration — just for "need more text" instead of
|
|
775
|
+
* "need this image". `onAssetsHydrated` fires once for the initial batch's
|
|
776
|
+
* images only (not re-fired per later chunk) — `onPreviewRendered` still
|
|
777
|
+
* means "the initial batch is in the DOM", same intent as the non-chunked
|
|
778
|
+
* path, just proportional to the viewport instead of the whole document.
|
|
779
|
+
*/
|
|
780
|
+
private mountChunkedPreview;
|
|
781
|
+
/**
|
|
782
|
+
* Mounts every chunk of a non-progressive (`progressiveTextRendering:
|
|
783
|
+
* false`) document up front — same end state as the old monolithic
|
|
784
|
+
* non-chunked path (the whole document mounted before `onPreviewRendered`
|
|
785
|
+
* fires), but yielding a frame between batches (mirroring
|
|
786
|
+
* `drainRemainingChunks`) instead of blocking the main thread for one
|
|
787
|
+
* giant synchronous render.
|
|
788
|
+
*/
|
|
789
|
+
private mountAllChunksEagerly;
|
|
790
|
+
/**
|
|
791
|
+
* Updates `chunkedRenderState.cursor` after a batch mounts. A no-op if a
|
|
792
|
+
* newer render generation has already superseded this one. Deliberately
|
|
793
|
+
* never nulls `chunkedRenderState` out just because `cursor` reached
|
|
794
|
+
* `records.length` — the records stay alive for the whole generation so a
|
|
795
|
+
* later same-document edit can reconcile against them (see
|
|
796
|
+
* `applyChunkReconciliation`). Callers that need "is there still an
|
|
797
|
+
* unmounted lazy tail" (Copy All's instant path, the scroll-to-bottom fast
|
|
798
|
+
* path) check `cursor < records.length` directly instead of this field's
|
|
799
|
+
* truthiness.
|
|
800
|
+
*/
|
|
801
|
+
private recordChunkProgress;
|
|
802
|
+
/**
|
|
803
|
+
* Renders+appends chunks starting at `startCursor` up to a char budget
|
|
804
|
+
* (enough for one screenful, roughly) *or* a wall-clock time budget,
|
|
805
|
+
* whichever comes first — char count alone is a poor proxy for cost on a
|
|
806
|
+
* document where some chunks are plain text and others are dense with
|
|
807
|
+
* `<img>` tags (parsing + sanitizing + inserting into an already-huge
|
|
808
|
+
* `elPreviewContent` gets measurably more expensive per chunk as an
|
|
809
|
+
* image-heavy document's accumulated DOM grows); the time budget catches
|
|
810
|
+
* what the char budget alone misses. Mounts extensions/code-block controls
|
|
811
|
+
* for exactly the chunks it appended (never re-scanning earlier ones), and
|
|
812
|
+
* returns the cursor to resume from plus those chunks' roots (for the
|
|
813
|
+
* caller to run `collectPendingImages` on). Shared by every caller that
|
|
814
|
+
* mounts chunk batches — the initial batch, every later sentinel-triggered
|
|
815
|
+
* continuation, and Copy All's drain — image hydration itself is *not*
|
|
816
|
+
* included here; see {@link mountChunkBatch} and
|
|
817
|
+
* {@link drainRemainingChunks} for the two different ways callers pace it.
|
|
818
|
+
*/
|
|
819
|
+
private renderAndMountChunkBatch;
|
|
820
|
+
/**
|
|
821
|
+
* `renderAndMountChunkBatch` plus its own immediate, independent
|
|
822
|
+
* `hydrateImages` pass — the shape every caller except Copy All's drain
|
|
823
|
+
* wants: mount a batch, then hydrate whatever images it contained,
|
|
824
|
+
* decoupled from mounting the next batch. Scroll-paced callers (the
|
|
825
|
+
* initial batch, every sentinel continuation) are naturally rate-limited
|
|
826
|
+
* by how fast the user scrolls, so one independent hydration loop per
|
|
827
|
+
* batch never has a chance to pile up against another.
|
|
828
|
+
*/
|
|
829
|
+
private mountChunkBatch;
|
|
830
|
+
/**
|
|
831
|
+
* Wraps one chunk's rendered HTML in a mount boundary and appends it (or,
|
|
832
|
+
* given `beforeNode`, splices it in ahead of that still-attached node —
|
|
833
|
+
* used by reconciliation to insert a replacement chunk ahead of a
|
|
834
|
+
* surviving mounted suffix). See the `.mdzip-chunk` CSS rules for why.
|
|
835
|
+
*/
|
|
836
|
+
private appendChunkHtml;
|
|
837
|
+
/**
|
|
838
|
+
* Appends a trailing sentinel and mounts the next chunk batch once it's
|
|
839
|
+
* within `rootMargin` of the viewport — a larger margin than images'
|
|
840
|
+
* (`hydrateImages`' 600px) since keeping text ahead of scroll is cheap
|
|
841
|
+
* relative to keeping images ahead. Re-arms itself after each batch until
|
|
842
|
+
* every chunk is mounted. Falls back to mounting everything immediately
|
|
843
|
+
* when IntersectionObserver isn't available, matching `hydrateImages`.
|
|
844
|
+
*/
|
|
845
|
+
private armChunkSentinel;
|
|
586
846
|
/**
|
|
587
847
|
* Reveals a collapsed image slot. Flushing layout before toggling the class
|
|
588
848
|
* lets the `0fr -> 1fr` grid transition run from the collapsed state instead
|
|
@@ -601,6 +861,13 @@ export declare class MdzipWorkspaceView {
|
|
|
601
861
|
*/
|
|
602
862
|
private attachImageLoadHandlers;
|
|
603
863
|
private reportImageLoadFailure;
|
|
864
|
+
/**
|
|
865
|
+
* `root` scopes extension `mount()` calls to a specific chunk instead of
|
|
866
|
+
* the whole preview — used by chunked rendering (see
|
|
867
|
+
* {@link mountChunkedPreview}), where extensions run once per newly
|
|
868
|
+
* appended chunk rather than once over the whole document. Defaults to
|
|
869
|
+
* the whole preview content, matching the non-chunked path exactly.
|
|
870
|
+
*/
|
|
604
871
|
private mountPreviewExtensions;
|
|
605
872
|
/**
|
|
606
873
|
* Built-in preview affordances for rendered code blocks: a language-name
|
|
@@ -611,6 +878,9 @@ export declare class MdzipWorkspaceView {
|
|
|
611
878
|
* extension) — every consumer gets this automatically, gated by policy
|
|
612
879
|
* rather than opt-in wiring. Runs after `mountPreviewExtensions` so any
|
|
613
880
|
* extension-provided `pre > code` blocks already exist in the DOM. See #29.
|
|
881
|
+
*
|
|
882
|
+
* `root` scopes the scan to a specific chunk instead of the whole preview
|
|
883
|
+
* — see {@link mountPreviewExtensions} for why.
|
|
614
884
|
*/
|
|
615
885
|
private mountCodeBlockControls;
|
|
616
886
|
/**
|
|
@@ -621,6 +891,8 @@ export declare class MdzipWorkspaceView {
|
|
|
621
891
|
*/
|
|
622
892
|
private enhanceCodeBlock;
|
|
623
893
|
private firePreviewRendered;
|
|
894
|
+
/** See `pendingPreviewScrollRestore`'s doc comment. */
|
|
895
|
+
private restorePendingPreviewScroll;
|
|
624
896
|
private fireAssetsHydrated;
|
|
625
897
|
private flushRenderedWaiters;
|
|
626
898
|
/**
|
|
@@ -656,6 +928,8 @@ export declare class MdzipWorkspaceView {
|
|
|
656
928
|
private showTooltipForElementNow;
|
|
657
929
|
private showTooltip;
|
|
658
930
|
private hideTooltip;
|
|
931
|
+
/** Briefly shows a status message (e.g. "Text copied to clipboard") near the bottom of the view, auto-hiding after a couple of seconds. */
|
|
932
|
+
private showCopyToast;
|
|
659
933
|
private save;
|
|
660
934
|
private downloadSavedBlob;
|
|
661
935
|
private saveTitle;
|
|
@@ -688,6 +962,13 @@ export declare class MdzipWorkspaceView {
|
|
|
688
962
|
private handlePaste;
|
|
689
963
|
private insertImageFile;
|
|
690
964
|
private insertImageBytes;
|
|
965
|
+
/**
|
|
966
|
+
* Handles a click on an existing image's edit affordance (see
|
|
967
|
+
* `imageEditAffordanceField`/the `click` domEventHandler in
|
|
968
|
+
* createCmEditor). Only reachable when `imageEditHandler` is set — the
|
|
969
|
+
* click handler that dispatches the affordance already gates on that.
|
|
970
|
+
*/
|
|
971
|
+
private openImageEditFlow;
|
|
691
972
|
private resolveImageInsertDecision;
|
|
692
973
|
private openImageInsertDialog;
|
|
693
974
|
private resolveImageInsertDialog;
|
|
@@ -698,8 +979,126 @@ export declare class MdzipWorkspaceView {
|
|
|
698
979
|
private handleEditorMenuAction;
|
|
699
980
|
private previewMenuItems;
|
|
700
981
|
private handlePreviewMenuAction;
|
|
982
|
+
/**
|
|
983
|
+
* Shows the copy confirmation either as a brief auto-hiding toast (an
|
|
984
|
+
* instant copy — nothing for the user to have looked away from) or, if
|
|
985
|
+
* the render dialog was showing, by switching that same dialog into a
|
|
986
|
+
* dismissable "done" state instead of hiding it — a copy that took long
|
|
987
|
+
* enough to need a progress dialog shouldn't end in a 2-second toast the
|
|
988
|
+
* user may not be looking at. `outcome` null means there was nothing to
|
|
989
|
+
* copy (empty selection) — silently clean up the dialog if one was
|
|
990
|
+
* showing, no confirmation needed. An `error` outcome carries the actual
|
|
991
|
+
* failure text inline (`onFailed` is a host callback with no guaranteed
|
|
992
|
+
* visible surface — this component has no other way to guarantee the
|
|
993
|
+
* user ever sees why it failed).
|
|
994
|
+
*/
|
|
995
|
+
private finishCopyNotification;
|
|
996
|
+
/** Switches the render dialog into its "ready to copy" state, holding `perform` until the user clicks Copy — see `copyReadyState` for why the write can't just happen automatically here. */
|
|
997
|
+
private armCopyReady;
|
|
998
|
+
/** Runs the held write from `copyReadyState` — called directly from the dialog's Copy button click, which is what makes the write's own user-activation check pass. */
|
|
999
|
+
private performReadyCopy;
|
|
1000
|
+
/**
|
|
1001
|
+
* Races `promise` against a timer, rejecting with `timeoutMessage` if the
|
|
1002
|
+
* timer wins. The async Clipboard API has no built-in timeout, and a
|
|
1003
|
+
* write large enough to strain a real OS clipboard (a document with
|
|
1004
|
+
* thousands of embedded images can build a HTML payload well over
|
|
1005
|
+
* 100MB) can apparently hang indefinitely on some machines rather than
|
|
1006
|
+
* rejecting — without this, that leaves the operation permanently
|
|
1007
|
+
* pending, and the progress dialog never resolves into either a done or
|
|
1008
|
+
* a failure state.
|
|
1009
|
+
*/
|
|
1010
|
+
private withTimeout;
|
|
1011
|
+
/** Writes `text` to the clipboard. Returns null if there was nothing to copy (a true no-op, not a failure); otherwise a success message or the failure text (also reported via `onFailed`, but that's a host callback with no guaranteed visible surface — the caller needs the text itself to show the user). */
|
|
701
1012
|
private copyPreviewSelection;
|
|
702
|
-
|
|
1013
|
+
/** Syncs just the copy-render dialog's progress bar/text from `copyRenderDialogState` — see `copyAllPreviewContent` for why this bypasses `render()`. No-op while the dialog isn't showing. */
|
|
1014
|
+
private updateCopyRenderDialogProgress;
|
|
1015
|
+
/**
|
|
1016
|
+
* Copies the entire rendered document as plain text (same fidelity as
|
|
1017
|
+
* `copyPreviewSelection` — no HTML, no `ClipboardItem`), regardless of how
|
|
1018
|
+
* much of it is currently mounted under progressive rendering. If
|
|
1019
|
+
* everything's already mounted (small doc, eager/non-progressive mount, or
|
|
1020
|
+
* the user already scrolled through it) this is instant —
|
|
1021
|
+
* `chunkedRenderState` is either null (no markdown open, or a non-default
|
|
1022
|
+
* renderer) or has nothing left to mount (`cursor >= records.length`) in
|
|
1023
|
+
* exactly that case. Otherwise it force-drains the rest first, showing a
|
|
1024
|
+
* cancelable progress dialog once the wait clears a short debounce so fast
|
|
1025
|
+
* documents never flicker it into view.
|
|
1026
|
+
*/
|
|
1027
|
+
private copyAllPreviewContent;
|
|
1028
|
+
/**
|
|
1029
|
+
* Renders the *entire* current document to one HTML string, independent
|
|
1030
|
+
* of whatever's mounted in `elPreviewContent` — no DOM reads or writes.
|
|
1031
|
+
* Copy All with Images needs pristine `<img src="original/path">` markup
|
|
1032
|
+
* to hand to `MdzipAssetSession.rewriteHtmlEmbeddingImages`, and an
|
|
1033
|
+
* already-mounted, possibly-hydrated `<img>` in the live preview may have
|
|
1034
|
+
* had its `src` swapped for a `blob:` URL or stripped entirely pending lazy
|
|
1035
|
+
* load — either way the original archive path is gone. Time-budgeted and
|
|
1036
|
+
* yielded like `renderAndMountChunkBatch`, for the same reason: some
|
|
1037
|
+
* chunks cost far more to render+sanitize than others. Extension `mount()`
|
|
1038
|
+
* hooks are not run — they render into a live DOM (e.g. mermaid diagrams
|
|
1039
|
+
* turning marked-up code fences into SVG), which this never touches, so a
|
|
1040
|
+
* mermaid diagram will paste as its pre-render markup, not a rendered
|
|
1041
|
+
* diagram. Only reachable when `renderingService.supportsChunking` is
|
|
1042
|
+
* true; the caller checks that first.
|
|
1043
|
+
*/
|
|
1044
|
+
private renderFullDocumentHtml;
|
|
1045
|
+
/**
|
|
1046
|
+
* Like `copyAllPreviewContent`, but writes a rich `text/html` clipboard
|
|
1047
|
+
* representation (alongside the same `text/plain` fallback) with every
|
|
1048
|
+
* archive image re-embedded as a self-contained `data:` URL — the format
|
|
1049
|
+
* an external app like Word needs, since this document's own `blob:` URLs
|
|
1050
|
+
* only resolve inside this tab. Two phases share one debounced, cancelable
|
|
1051
|
+
* dialog: render the document fresh (`renderFullDocumentHtml`), then embed
|
|
1052
|
+
* its images (`rewriteHtmlEmbeddingImages`). Falls back to
|
|
1053
|
+
* `copyAllPreviewContent`'s plain-text-only behavior when there's no
|
|
1054
|
+
* default renderer to re-render from (a host-supplied custom renderer,
|
|
1055
|
+
* the same escape hatch `progressiveTextRendering` already has) — or, if
|
|
1056
|
+
* the clipboard rejects the rich write for any reason (unsupported
|
|
1057
|
+
* browser, payload too large), falls back to a plain-text write so the
|
|
1058
|
+
* user still gets *something* rather than nothing.
|
|
1059
|
+
*/
|
|
1060
|
+
private copyAllWithImagesPreviewContent;
|
|
1061
|
+
/**
|
|
1062
|
+
* Writes an HTML+plain-text `ClipboardItem` when the browser supports it,
|
|
1063
|
+
* falling back to a plain-text-only `writeText` (same as
|
|
1064
|
+
* `copyPreviewSelection`, which reports itself as "Plain text") when it
|
|
1065
|
+
* doesn't, or if the rich write itself throws (e.g. a payload too large
|
|
1066
|
+
* for the OS clipboard) — either way the user ends up with *something* on
|
|
1067
|
+
* their clipboard rather than nothing. Returns the confirmation message
|
|
1068
|
+
* for the caller to show (see `finishCopyNotification`), naming the
|
|
1069
|
+
* actual MIME type that ended up on the clipboard ("HTML" for a
|
|
1070
|
+
* successful rich write, "Plain text" for the fallback) so the user knows
|
|
1071
|
+
* what they're about to paste — `imageCount` only adds to the "HTML"
|
|
1072
|
+
* wording, since even a rich write with zero images is still HTML, not
|
|
1073
|
+
* plain text.
|
|
1074
|
+
*/
|
|
1075
|
+
private writeRichClipboard;
|
|
1076
|
+
/**
|
|
1077
|
+
* Mounts every chunk from `state.cursor` onward, yielding to a fresh
|
|
1078
|
+
* animation frame between batches (unlike the sentinel path's rAF-time-
|
|
1079
|
+
* budgeted-per-batch loop, this has no viewport to wait on — it has to
|
|
1080
|
+
* plow through the whole rest of the document, so the explicit yield is
|
|
1081
|
+
* what keeps a huge draw from locking up the tab while it does). Stops
|
|
1082
|
+
* early if `signal` aborts, a newer render generation supersedes this one,
|
|
1083
|
+
* or the chunk state's own render context aborts.
|
|
1084
|
+
*
|
|
1085
|
+
* Deliberately uses `renderAndMountChunkBatch` instead of `mountChunkBatch`
|
|
1086
|
+
* and defers image hydration until the whole drain finishes, running it
|
|
1087
|
+
* once over every image the drain mounted, instead of once per batch:
|
|
1088
|
+
* Copy All only needs the mounted chunks' *text* (`elPreviewContent
|
|
1089
|
+
* .textContent`, which images never contribute to), so there's no reason
|
|
1090
|
+
* to wait on `hydrateImages`' async image resolution at all here — and
|
|
1091
|
+
* racing through batches as fast as this loop can while each one fires
|
|
1092
|
+
* its own independent, un-awaited `hydrateImages` background loop (as
|
|
1093
|
+
* `mountChunkBatch` does for the scroll-paced callers, where that's fine —
|
|
1094
|
+
* scrolling naturally rate-limits how many can ever be in flight at once)
|
|
1095
|
+
* lets dozens of those loops pile up concurrently on an image-heavy
|
|
1096
|
+
* document, each spending its own `CHUNK_BUDGET_MS` in the same frame —
|
|
1097
|
+
* measured 100-200ms frame gaps on a 15,000-image document. One combined
|
|
1098
|
+
* pass over every image at the end avoids the pile-up entirely, without
|
|
1099
|
+
* making Copy All wait on it.
|
|
1100
|
+
*/
|
|
1101
|
+
private drainRemainingChunks;
|
|
703
1102
|
private insertCodeBlock;
|
|
704
1103
|
private clearSelectionFormatting;
|
|
705
1104
|
private editorClipboard;
|
|
@@ -758,5 +1157,26 @@ export declare class MdzipWorkspaceView {
|
|
|
758
1157
|
private validLayoutForSnapshot;
|
|
759
1158
|
private syncScrollFromPreview;
|
|
760
1159
|
private syncScrollToPreview;
|
|
1160
|
+
/**
|
|
1161
|
+
* Handles syncScrollToPreview's bottom edge when the preview still has
|
|
1162
|
+
* unmounted chunks: force-mounts the rest (same drain Copy All uses) so
|
|
1163
|
+
* the preview's scrollHeight reflects the whole document, then jumps to
|
|
1164
|
+
* its real bottom — instead of the ordinary ratio-based jump, which would
|
|
1165
|
+
* only land at the bottom of whatever was mounted the instant the sync
|
|
1166
|
+
* fired. Re-checks that the editor is still at its bottom and the document
|
|
1167
|
+
* hasn't changed before applying the jump, since the drain can take long
|
|
1168
|
+
* enough on a huge document for either to no longer hold.
|
|
1169
|
+
*
|
|
1170
|
+
* On the most extreme real documents this drain has been measured at
|
|
1171
|
+
* ~106s (thousands of chunks, tens of thousands of images each needing a
|
|
1172
|
+
* real DOM slot + IntersectionObserver registration) — long enough that a
|
|
1173
|
+
* silent wait looks indistinguishable from a frozen preview pane. Past a
|
|
1174
|
+
* short debounce (so ordinary documents never see it), a small status
|
|
1175
|
+
* toast shows progress, reusing the same element Copy All's confirmation
|
|
1176
|
+
* messages use.
|
|
1177
|
+
*/
|
|
1178
|
+
private syncScrollToPreviewBottom;
|
|
1179
|
+
/** Syncs the catch-up toast's text from `scrollCatchUpState`, bypassing `render()` — see `updateCopyRenderDialogProgress` for why. No-op while the toast isn't showing. */
|
|
1180
|
+
private updateScrollCatchUpToast;
|
|
761
1181
|
}
|
|
762
1182
|
//# sourceMappingURL=view.d.ts.map
|