visio-react-viewer 0.0.2 → 0.1.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 (52) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +10 -0
  3. package/README.md +5 -3
  4. package/dist/assets/edit-worker-DRgXgRud.js +55992 -0
  5. package/dist/assets/parse-worker-B8EBQQpD.js +53971 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +4131 -0
  8. package/dist/types/packages/bindings/src/common.d.ts +29 -0
  9. package/dist/types/packages/bindings/src/react.d.ts +10 -0
  10. package/dist/types/packages/react/src/index.d.ts +3 -0
  11. package/dist/types/src/arrowheads.d.ts +3 -0
  12. package/dist/types/src/binding.d.ts +27 -0
  13. package/dist/types/src/contract.d.ts +32 -0
  14. package/dist/types/src/controller.d.ts +66 -0
  15. package/dist/types/src/demo-document.d.ts +3 -0
  16. package/dist/types/src/diagnostics.d.ts +9 -0
  17. package/dist/types/src/document-history.d.ts +42 -0
  18. package/dist/types/src/document-text-search.d.ts +44 -0
  19. package/dist/types/src/edit-commands.d.ts +3 -0
  20. package/dist/types/src/edit-error.d.ts +4 -0
  21. package/dist/types/src/edit-worker.d.ts +1 -0
  22. package/dist/types/src/export-svg.d.ts +25 -0
  23. package/dist/types/src/foreign-vector-budget.d.ts +24 -0
  24. package/dist/types/src/index.d.ts +14 -0
  25. package/dist/types/src/paragraph-layout.d.ts +18 -0
  26. package/dist/types/src/parse-worker.d.ts +1 -0
  27. package/dist/types/src/print-snapshot.d.ts +87 -0
  28. package/dist/types/src/render-fill.d.ts +2 -0
  29. package/dist/types/src/render-foreign-vector-shape.d.ts +4 -0
  30. package/dist/types/src/render-foreign-vector.d.ts +3 -0
  31. package/dist/types/src/render-image.d.ts +4 -0
  32. package/dist/types/src/render-resources.d.ts +10 -0
  33. package/dist/types/src/render-svg.d.ts +17 -0
  34. package/dist/types/src/render-text.d.ts +4 -0
  35. package/dist/types/src/scene-details.d.ts +7 -0
  36. package/dist/types/src/scene-validation.d.ts +4 -0
  37. package/dist/types/src/shape-inspector.d.ts +5 -0
  38. package/dist/types/src/snapshot-scene.d.ts +8 -0
  39. package/dist/types/src/styles.d.ts +2 -0
  40. package/dist/types/src/text-layout.d.ts +45 -0
  41. package/dist/types/src/viewer-chrome.d.ts +10 -0
  42. package/dist/types/src/viewer-edit-controls.d.ts +12 -0
  43. package/dist/types/src/viewer-element.d.ts +44 -0
  44. package/dist/types/src/viewer-geometry-controls.d.ts +14 -0
  45. package/dist/types/src/viewer-input.d.ts +10 -0
  46. package/dist/types/src/viewer-layer-controls.d.ts +5 -0
  47. package/dist/types/src/viewer-layers.d.ts +22 -0
  48. package/dist/types/src/viewer-search.d.ts +10 -0
  49. package/dist/types/src/worker-editor.d.ts +23 -0
  50. package/dist/types/src/worker-parser.d.ts +13 -0
  51. package/package.json +22 -7
  52. package/index.js +0 -1
@@ -0,0 +1,29 @@
1
+ import { mountViewer, type MountedViewer } from '../../../src/binding.js';
2
+ import { eventKeys, propertyKeys, type ViewerCallbacks, type ViewerOptions, type ViewerProperties } from '../../../src/contract.js';
3
+ /** Framework props permit undefined; omitted values preserve the shared binding's state. */
4
+ export type ViewerProps = {
5
+ [K in keyof ViewerProperties]?: ViewerProperties[K] | undefined;
6
+ } & {
7
+ events?: ViewerCallbacks | undefined;
8
+ };
9
+ export type ViewerHandle = Pick<MountedViewer, 'element' | 'controller' | 'load' | 'applyEdits' | 'replacePlainText' | 'undo' | 'redo' | 'cancelEdit' | 'exportVsdx' | 'fit' | 'setLayerVisibility' | 'resetLayerVisibility' | 'exportSvg' | 'createPrintSnapshot'>;
10
+ /** One mapping for every property and event, shared by every framework adapter. */
11
+ export declare function viewerOptions(props: ViewerProps): ViewerOptions;
12
+ /**
13
+ * Native props are snapshots, while the browser binding accepts explicit patches. Forward only
14
+ * changed properties so a callback/class update cannot undo an imperative load or user zoom.
15
+ */
16
+ export declare function mountFrameworkViewer(container: HTMLElement, initial: ViewerOptions): MountedViewer;
17
+ /** Lazy imperative methods reject both before mount and after unmount. */
18
+ export declare function viewerHandle(current: () => MountedViewer | undefined): ViewerHandle;
19
+ /** Native framework emits and callback-map props share one complete event inventory. */
20
+ export declare function withEventEmitter(props: ViewerProps, emit: (name: keyof ViewerCallbacks, value: unknown) => void): ViewerOptions;
21
+ export { mountViewer };
22
+ export type { MountedViewer, ViewerCallbacks, ViewerOptions, ViewerProperties };
23
+ export { eventKeys, propertyKeys };
24
+ export type { ViewerEvents, VsdxSource } from '../../../src/contract.js';
25
+ export { ViewerController, type ViewerState } from '../../../src/controller.js';
26
+ export type { SvgExportOptions, SvgExportResult } from '../../../src/export-svg.js';
27
+ export type { CurrentPagePrintSnapshotOptions, PrintSnapshot, PrintSnapshotPage, PrintSnapshotOptions, PrintSnapshotLimits, PrintSnapshotUsage, } from '../../../src/print-snapshot.js';
28
+ export type { ViewerEditState, VsdxExportResult } from '../../../src/document-history.js';
29
+ export type { VisioEdit, VisioGeometryEdit } from 'ooxml-core/visio';
@@ -0,0 +1,10 @@
1
+ import { type CSSProperties } from 'react';
2
+ import { type ViewerHandle, type ViewerProps } from './common.js';
3
+ export interface VisioViewerProps extends ViewerProps {
4
+ className?: string | undefined;
5
+ style?: CSSProperties | undefined;
6
+ 'aria-label'?: string | undefined;
7
+ }
8
+ /** React owns only the host and lifecycle; the shared element owns all viewer behavior. */
9
+ export declare const VisioViewer: import("react").ForwardRefExoticComponent<VisioViewerProps & import("react").RefAttributes<ViewerHandle>>;
10
+ export type { ViewerHandle, ViewerCallbacks, ViewerOptions, ViewerEvents, ViewerEditState, VsdxExportResult, } from './common.js';
@@ -0,0 +1,3 @@
1
+ export * from '../../../src/index.js';
2
+ export * from 'visio-core';
3
+ export * from '../../bindings/src/react.js';
@@ -0,0 +1,3 @@
1
+ import type { VisioStyle } from 'ooxml-core/visio';
2
+ /** Common Visio line/triangle and concave arrow styles. Sizes remain a documented visual approximation. */
3
+ export declare function applyArrowheads(path: SVGPathElement, style: VisioStyle, defs: SVGDefsElement, warnings: Set<string>): void;
@@ -0,0 +1,27 @@
1
+ import type { VisioEdit } from 'ooxml-core/visio';
2
+ import type { ViewerOptions, VsdxSource } from './contract.js';
3
+ import { type VisioViewerElement } from './viewer-element.js';
4
+ import type { ViewerController } from './controller.js';
5
+ import type { SvgExportOptions, SvgExportResult } from './export-svg.js';
6
+ import type { CurrentPagePrintSnapshotOptions, PrintSnapshot } from './print-snapshot.js';
7
+ import type { VsdxExportResult } from './document-history.js';
8
+ export interface MountedViewer {
9
+ readonly element: VisioViewerElement;
10
+ readonly controller: ViewerController;
11
+ update(options: ViewerOptions): void;
12
+ load(source: VsdxSource): Promise<void>;
13
+ applyEdits(edits: readonly VisioEdit[]): Promise<void>;
14
+ replacePlainText(pageId: string, shapeId: string, text: string): Promise<void>;
15
+ undo(): Promise<void>;
16
+ redo(): Promise<void>;
17
+ cancelEdit(): void;
18
+ exportVsdx(): VsdxExportResult;
19
+ fit(): void;
20
+ setLayerVisibility(pageId: string, layerId: string, visible: boolean | null): void;
21
+ resetLayerVisibility(pageId?: string): void;
22
+ exportSvg(options?: SvgExportOptions): SvgExportResult;
23
+ createPrintSnapshot(options?: CurrentPagePrintSnapshotOptions): PrintSnapshot;
24
+ destroy(): void;
25
+ }
26
+ /** One client-only lifecycle adapter; framework wrappers forward to this implementation. */
27
+ export declare function mountViewer(container: HTMLElement, initial?: ViewerOptions): MountedViewer;
@@ -0,0 +1,32 @@
1
+ import type { VisioDocument } from 'ooxml-core/visio';
2
+ export interface ViewerProperties {
3
+ document: VisioDocument | null;
4
+ pageIndex: number;
5
+ zoom: number;
6
+ showToolbar: boolean;
7
+ }
8
+ export interface ViewerEvents {
9
+ 'document-load': VisioDocument;
10
+ 'document-change': {
11
+ document: VisioDocument;
12
+ dirty: boolean;
13
+ kind: 'edit' | 'undo' | 'redo';
14
+ };
15
+ 'document-error': Error;
16
+ 'page-change': number;
17
+ 'zoom-change': number;
18
+ 'shape-select': {
19
+ id: string;
20
+ name: string;
21
+ pageId?: string;
22
+ } | null;
23
+ }
24
+ export type ViewerCallbacks = {
25
+ [K in keyof ViewerEvents]?: (detail: ViewerEvents[K]) => void;
26
+ };
27
+ export declare const propertyKeys: readonly ["document", "pageIndex", "zoom", "showToolbar"];
28
+ export declare const eventKeys: readonly ["document-load", "document-change", "document-error", "page-change", "zoom-change", "shape-select"];
29
+ export type VsdxSource = ArrayBuffer | Uint8Array | Blob;
30
+ export interface ViewerOptions extends Partial<ViewerProperties> {
31
+ events?: ViewerCallbacks;
32
+ }
@@ -0,0 +1,66 @@
1
+ import { type ViewerEditState, type VsdxExportResult } from './document-history.js';
2
+ import { type CancellableEditor } from './worker-editor.js';
3
+ import { type VisioDocument, type VisioEdit } from 'ooxml-core/visio';
4
+ import { type LayerVisibilityOverride } from './viewer-layers.js';
5
+ import type { CancellableParser } from './worker-parser.js';
6
+ import type { ViewerEvents } from './contract.js';
7
+ import { type TextSearchState } from './document-text-search.js';
8
+ export interface ViewerState {
9
+ readonly document: VisioDocument | null;
10
+ readonly edit: ViewerEditState;
11
+ readonly pageIndex: number;
12
+ readonly zoom: number;
13
+ readonly loading: boolean;
14
+ readonly error: Error | null;
15
+ readonly search: TextSearchState;
16
+ /** Viewer-only display overrides, independent of saved model and print policy. */
17
+ readonly layerVisibilityOverrides: readonly LayerVisibilityOverride[];
18
+ readonly selectedShape: {
19
+ id: string;
20
+ name: string;
21
+ pageId?: string;
22
+ } | null;
23
+ }
24
+ type Parser = CancellableParser;
25
+ type EventListener = <K extends keyof ViewerEvents>(name: K, detail: ViewerEvents[K]) => void;
26
+ export declare class ViewerController {
27
+ #private;
28
+ private readonly parser;
29
+ private readonly listenerError;
30
+ private readonly editor;
31
+ constructor(parser?: Parser, listenerError?: (error: unknown) => void, editor?: CancellableEditor);
32
+ get state(): ViewerState;
33
+ /** Accepted document replacements, including the same object, invalidate captured artifacts. */
34
+ get documentGeneration(): number;
35
+ /** Accepted source/model replacements invalidate drafts; edit/undo/redo keep this source epoch. */
36
+ get sourceGeneration(): number;
37
+ subscribe(listener: (state: ViewerState) => void): () => void;
38
+ onEvent(listener: EventListener): () => void;
39
+ setDocument(document: VisioDocument | null): void;
40
+ setPage(index: number): void;
41
+ setZoom(zoom: number): void;
42
+ selectShape(shape: ViewerState['selectedShape']): void;
43
+ /** Override one source-page layer for viewing. null restores its saved display flag. */
44
+ setLayerVisibility(pageId: string, layerId: string, visible: boolean | null): void;
45
+ /** Reset a source page, or all pages when omitted. Does not modify the document. */
46
+ resetLayerVisibility(pageId?: string): void;
47
+ /** Search does not change the page or selection until explicit result navigation. */
48
+ setSearchQuery(query: string): void;
49
+ selectSearchResult(index: number): void;
50
+ nextSearchResult(): void;
51
+ previousSearchResult(): void;
52
+ load(bytes: Uint8Array | ArrayBuffer): Promise<void>;
53
+ /** Reading bytes shares the same request epoch and error state as parsing them. */
54
+ loadSource(read: () => Uint8Array | ArrayBuffer | Promise<Uint8Array | ArrayBuffer>): Promise<void>;
55
+ cancelLoad(): void;
56
+ destroy(): void;
57
+ /** Replace one source-backed local plain-text target. Core decides target support. */
58
+ replacePlainText(pageId: string, shapeId: string, text: string): Promise<void>;
59
+ /** Atomic source-backed edits. Core owns protection, dependency and target validation. */
60
+ applyEdits(edits: readonly VisioEdit[]): Promise<void>;
61
+ undo(): Promise<void>;
62
+ redo(): Promise<void>;
63
+ cancelEdit(): void;
64
+ exportVsdx(): VsdxExportResult;
65
+ }
66
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { VisioDocument } from 'ooxml-core/visio';
2
+ /** Original sample scene, not a Visio-authored reference fixture. */
3
+ export declare const demoDocument: VisioDocument;
@@ -0,0 +1,9 @@
1
+ import type { VisioDiagnostic } from 'ooxml-core/visio';
2
+ export interface CompatibilityNote {
3
+ message: string;
4
+ count: number;
5
+ severity: 'info' | 'warning';
6
+ }
7
+ /** Presentation-only grouping keeps repeated per-shape diagnostics readable without losing counts. */
8
+ export declare function compatibilityNotes(diagnostics: readonly VisioDiagnostic[], renderWarnings?: readonly string[]): CompatibilityNote[];
9
+ export declare function compatibilityText(note: CompatibilityNote): string;
@@ -0,0 +1,42 @@
1
+ /** Source snapshots only. No document model is serialized by the viewer. */
2
+ export interface EditDiagnostic {
3
+ readonly code: string;
4
+ readonly message: string;
5
+ }
6
+ export interface VsdxExportResult {
7
+ bytes: Uint8Array;
8
+ dirty: boolean;
9
+ diagnostics: readonly EditDiagnostic[];
10
+ }
11
+ export interface ViewerEditState {
12
+ readonly sourceAvailable: boolean;
13
+ readonly busy: boolean;
14
+ readonly dirty: boolean;
15
+ readonly canUndo: boolean;
16
+ readonly canRedo: boolean;
17
+ readonly historyTruncated: boolean;
18
+ readonly error: Error | null;
19
+ readonly diagnostics: readonly EditDiagnostic[];
20
+ }
21
+ export declare const EMPTY_EDIT_STATE: ViewerEditState;
22
+ export declare const EDIT_HISTORY_LIMITS: Readonly<{
23
+ maxBytes: number;
24
+ maxEntries: 20;
25
+ }>;
26
+ export interface SourceSnapshot {
27
+ readonly bytes: Uint8Array;
28
+ readonly diagnostics: readonly EditDiagnostic[];
29
+ }
30
+ /** Private controller-owned bytes; transient worker copies and models are separate from this budget. */
31
+ export declare class DocumentHistory {
32
+ #private;
33
+ readonly original: SourceSnapshot;
34
+ constructor(bytes: Uint8Array);
35
+ get current(): SourceSnapshot;
36
+ get undoTarget(): SourceSnapshot | undefined;
37
+ get redoTarget(): SourceSnapshot | undefined;
38
+ get state(): ViewerEditState;
39
+ append(bytes: Uint8Array, diagnostics: readonly EditDiagnostic[]): void;
40
+ move(target: SourceSnapshot): void;
41
+ export(): VsdxExportResult;
42
+ }
@@ -0,0 +1,44 @@
1
+ import type { VisioDocument, VisioShape } from 'ooxml-core/visio';
2
+ /** UTF-16 character bounds, applied before copying or case conversion. */
3
+ export declare const TEXT_SEARCH_LIMITS: Readonly<{
4
+ queryCharacters: 256;
5
+ results: 500;
6
+ indexedCharacters: 2000000;
7
+ shapeCharacters: 32768;
8
+ previewCharacters: 160;
9
+ shapes: 25000;
10
+ depth: 64;
11
+ }>;
12
+ export interface TextSearchResult {
13
+ readonly pageIndex: number;
14
+ readonly pageId: string;
15
+ readonly pageName: string;
16
+ readonly shapeId: string;
17
+ readonly shapeName: string;
18
+ /** Bounded start-of-text preview, not a match offset or highlighted excerpt. */
19
+ readonly preview: string;
20
+ }
21
+ export interface TextSearchState {
22
+ readonly query: string;
23
+ readonly results: readonly TextSearchResult[];
24
+ /** -1 until the user explicitly navigates, or after manual page/shape selection. */
25
+ readonly activeIndex: number;
26
+ readonly indexTruncated: boolean;
27
+ readonly resultsTruncated: boolean;
28
+ }
29
+ interface SearchEntry {
30
+ readonly result: TextSearchResult;
31
+ readonly foldedText: string;
32
+ }
33
+ export interface DocumentTextIndex {
34
+ readonly entries: readonly SearchEntry[];
35
+ readonly truncated: boolean;
36
+ }
37
+ export declare const EMPTY_TEXT_SEARCH: TextSearchState;
38
+ /** Index canonical text for the current display state. No XML, DOM or layout parsing. */
39
+ export declare function indexDocumentText(model: VisioDocument | null, isVisible?: (shape: VisioShape) => boolean): DocumentTextIndex;
40
+ export declare function validateSearchQuery(query: string): void;
41
+ /** One match per shape, literal ECMAScript lowercase comparison; no regex or language collation. */
42
+ export declare function searchDocumentText(index: DocumentTextIndex, query: string): TextSearchState;
43
+ export declare function textSearchStatus(search: TextSearchState): string;
44
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { VisioEdit } from 'ooxml-core/visio';
2
+ /** Bound cloning and strip arbitrary host properties. Semantic validation belongs to core. */
3
+ export declare function snapshotEdits(edits: readonly VisioEdit[]): VisioEdit[];
@@ -0,0 +1,4 @@
1
+ /** Core error codes remain visible for a refused transaction; document content is plain text. */
2
+ export declare function editErrorMessage(error: unknown): string;
3
+ /** Superseded worker/load operations are cancellation, not a refused document edit. */
4
+ export declare function isEditCancellation(error: unknown): boolean;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { type VisioDocument, type VisioPage } from 'ooxml-core/visio';
2
+ import { type CompatibilityNote } from './diagnostics.js';
3
+ export declare const MAX_SVG_EXPORT_BYTES: number;
4
+ export interface SvgExportOptions {
5
+ /** UTF-8 output ceiling. May lower, but never raise, the 16 MiB safety limit. */
6
+ maxBytes?: number;
7
+ }
8
+ export interface SvgExportResult {
9
+ readonly svg: string;
10
+ readonly byteLength: number;
11
+ readonly pageIndex: number;
12
+ readonly pageName: string;
13
+ /** Saved page dimensions in inches, independent of viewport zoom. */
14
+ readonly width: number;
15
+ readonly height: number;
16
+ readonly diagnostics: CompatibilityNote[];
17
+ }
18
+ /**
19
+ * Export one page through the shared renderer, including its resolved backgrounds.
20
+ * Requires a browser DOM at call time, never uploads, downloads or mutates viewer state.
21
+ * Conservative preflight limits can reject a page whose eventual serialization would be smaller.
22
+ */
23
+ export declare function exportPageSvg(model: VisioDocument, pageIndex?: number, options?: SvgExportOptions): SvgExportResult;
24
+ /** @internal Call only after canonical scene validation. Shared conservative allocation preflight. */
25
+ export declare function estimatePageSvgBytes(model: VisioDocument, page: VisioPage, maxBytes: number): number;
@@ -0,0 +1,24 @@
1
+ import { type VisioForeignVector } from 'ooxml-core/visio';
2
+ /** UI allocation limits, charged for every instance, including repeated shared resources. */
3
+ export declare const FOREIGN_VECTOR_SCENE_LIMITS: Readonly<{
4
+ maxNodes: 100000;
5
+ maxCommands: 400000;
6
+ maxOperands: 1000000;
7
+ }>;
8
+ export interface ForeignVectorResource {
9
+ readonly vector: VisioForeignVector;
10
+ readonly nodes: number;
11
+ readonly commands: number;
12
+ readonly operands: number;
13
+ readonly svgBytes: number;
14
+ readonly validationWork: number;
15
+ }
16
+ /** Count work only after canonical validation. Interpretation and safety remain in core. */
17
+ export declare function inspectForeignVectorResource(source: unknown): ForeignVectorResource;
18
+ /** Invocation-local budget. Never trusts frozen host objects or caches across calls. */
19
+ export declare class ForeignVectorBudget {
20
+ private nodes;
21
+ private commands;
22
+ private operands;
23
+ take(source: unknown): ForeignVectorResource;
24
+ }
@@ -0,0 +1,14 @@
1
+ export { ViewerController, type ViewerState } from './controller.js';
2
+ export { mountViewer, type MountedViewer } from './binding.js';
3
+ export { VisioViewerElement, registerVisioViewer } from './viewer-element.js';
4
+ export { renderPage, type RenderResult, type RenderOptions } from './render-svg.js';
5
+ export { exportPageSvg, MAX_SVG_EXPORT_BYTES, type SvgExportOptions, type SvgExportResult, } from './export-svg.js';
6
+ export { createPrintSnapshot, PRINT_SNAPSHOT_LIMITS, type PrintSnapshot, type PrintSnapshotPage, type PrintSnapshotOptions, type PrintSnapshotLimits, type PrintSnapshotUsage, type CurrentPagePrintSnapshotOptions, } from './print-snapshot.js';
7
+ export { eventKeys, propertyKeys, type ViewerProperties, type ViewerEvents, type ViewerCallbacks, type ViewerOptions, type VsdxSource, } from './contract.js';
8
+ export type { VisioDocument, VisioPage, VisioShape, VisioDiagnostic } from 'ooxml-core/visio';
9
+ export { createWorkerParser, type CancellableParser } from './worker-parser.js';
10
+ export { compatibilityNotes, compatibilityText, type CompatibilityNote } from './diagnostics.js';
11
+ export { TEXT_SEARCH_LIMITS, type TextSearchResult, type TextSearchState, } from './document-text-search.js';
12
+ export { VIEWER_LAYER_LIMITS, type LayerVisibilityOverride } from './viewer-layers.js';
13
+ export type { ViewerEditState, VsdxExportResult } from './document-history.js';
14
+ export type { VisioEdit, VisioGeometryEdit } from 'ooxml-core/visio';
@@ -0,0 +1,18 @@
1
+ import type { VisioParagraph, VisioText } from 'ooxml-core/visio';
2
+ import { type TextLayoutBudget, type MeasureText, type TextLine } from './text-layout.js';
3
+ export interface PositionedLine extends TextLine {
4
+ x: number;
5
+ y: number;
6
+ availableWidth: number;
7
+ align: VisioParagraph['horizontalAlign'];
8
+ direction: 'ltr' | 'rtl';
9
+ last: boolean;
10
+ bullet?: NonNullable<VisioParagraph['bullet']> & {
11
+ x: number;
12
+ };
13
+ }
14
+ export interface ParagraphLayout {
15
+ lines: PositionedLine[];
16
+ height: number;
17
+ }
18
+ export declare function layoutParagraphs(text: VisioText, measure?: MeasureText, budget?: TextLayoutBudget): ParagraphLayout;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,87 @@
1
+ import { type VisioDocument } from 'ooxml-core/visio';
2
+ import type { CompatibilityNote } from './diagnostics.js';
3
+ /** Application guardrails, not printer capabilities or Microsoft Visio limits. */
4
+ export declare const PRINT_SNAPSHOT_LIMITS: Readonly<{
5
+ maxPages: 32;
6
+ maxTotalBytes: number;
7
+ maxPageBytes: number;
8
+ maxShapeInstances: 100000;
9
+ maxGeometryInstances: 100000;
10
+ maxPathCharacters: 16000000;
11
+ maxTextCharacters: 1000000;
12
+ maxTextRuns: 100000;
13
+ maxImageBytes: number;
14
+ maxUniqueImagePixels: 64000000;
15
+ maxImageInstancePixels: 256000000;
16
+ maxVectorNodes: 100000;
17
+ maxVectorCommands: 400000;
18
+ maxVectorOperands: 1000000;
19
+ maxPageAxisCssPixels: 4096;
20
+ maxPageAreaCssPixels: 16000000;
21
+ maxTotalAreaCssPixels: 64000000;
22
+ maxValidationShapeVisits: 1000000;
23
+ maxValidationWork: number;
24
+ }>;
25
+ export type PrintSnapshotLimits = {
26
+ -readonly [K in keyof typeof PRINT_SNAPSHOT_LIMITS]: number;
27
+ };
28
+ export interface PrintSnapshotOptions {
29
+ /** Explicit output order. Background pages are included as sheets only when selected. */
30
+ readonly pageIndices: readonly number[];
31
+ /** Positive integer limits may lower, but never raise, the hard ceilings. */
32
+ readonly limits?: Partial<PrintSnapshotLimits>;
33
+ }
34
+ /** Viewer handles always capture exactly the current page. */
35
+ export type CurrentPagePrintSnapshotOptions = Omit<PrintSnapshotOptions, 'pageIndices'>;
36
+ export interface PrintSnapshotPage {
37
+ readonly pageIndex: number;
38
+ readonly pageId: string;
39
+ readonly pageName: string;
40
+ /** Saved drawing dimensions, not printer paper, margins, orientation or scale. */
41
+ readonly drawingSize: Readonly<{
42
+ width: number;
43
+ height: number;
44
+ unit: 'in';
45
+ }>;
46
+ /** An isolated SVG document. Do not concatenate page trees with colliding resource IDs. */
47
+ readonly svg: string;
48
+ readonly byteLength: number;
49
+ readonly diagnostics: readonly Readonly<CompatibilityNote>[];
50
+ }
51
+ export interface PrintSnapshotUsage {
52
+ readonly estimatedSvgBytes: number;
53
+ readonly svgBytes: number;
54
+ readonly shapeInstances: number;
55
+ readonly geometryInstances: number;
56
+ readonly pathCharacters: number;
57
+ readonly textCharacters: number;
58
+ readonly textRuns: number;
59
+ /** Raw resources counted once per byte identity per output page, including backgrounds. */
60
+ readonly imageBytes: number;
61
+ readonly uniqueImagePixels: number;
62
+ readonly imageInstancePixels: number;
63
+ /** Includes all clip reference expansions and repeated/background vector instances. */
64
+ readonly vectorNodes: number;
65
+ readonly vectorCommands: number;
66
+ readonly vectorOperands: number;
67
+ readonly totalAreaCssPixels: number;
68
+ readonly validationShapeVisits: number;
69
+ /** Conservative bytes, characters and records across validation and the private copy pass. */
70
+ readonly validationWork: number;
71
+ }
72
+ export interface PrintSnapshot {
73
+ readonly appearance: 'saved-display';
74
+ readonly pageIndices: readonly number[];
75
+ readonly pages: readonly PrintSnapshotPage[];
76
+ readonly byteLength: number;
77
+ readonly limits: Readonly<PrintSnapshotLimits>;
78
+ readonly usage: PrintSnapshotUsage;
79
+ readonly limitations: readonly string[];
80
+ }
81
+ /**
82
+ * Synchronously prepare bounded, immutable page artifacts through the shared SVG renderer.
83
+ * Requires its DOM/serializer, but never mounts nodes, downloads, fetches, opens frames or prints.
84
+ * Canonical scene/raster validation is repeated on every call. No source object is frozen.
85
+ * Conservative budgets include hidden content and can reject otherwise exportable individual pages.
86
+ */
87
+ export declare function createPrintSnapshot(model: VisioDocument, options: PrintSnapshotOptions): PrintSnapshot;
@@ -0,0 +1,2 @@
1
+ import type { VisioStyle } from 'ooxml-core/visio';
2
+ export declare function fillPaint(style: VisioStyle, defs: SVGDefsElement): string;
@@ -0,0 +1,4 @@
1
+ import type { VisioShape } from 'ooxml-core/visio';
2
+ import type { ForeignVectorBudget } from './foreign-vector-budget.js';
3
+ /** Core supplies shape-local placement; converter coordinates have a downward Y axis. */
4
+ export declare function renderForeignVectorShape(shape: VisioShape, budget: ForeignVectorBudget): SVGGElement | undefined;
@@ -0,0 +1,3 @@
1
+ import { ForeignVectorBudget } from './foreign-vector-budget.js';
2
+ /** Render an independently validated inert scene. Never forwards source tags, IDs or attributes. */
3
+ export declare function renderForeignVector(source: unknown, owner?: Document, budget?: ForeignVectorBudget): SVGSVGElement;
@@ -0,0 +1,4 @@
1
+ import type { VisioShape } from 'ooxml-core/visio';
2
+ import type { RenderResources } from './render-resources.js';
3
+ /** URLs are created only from bounded embedded raster bytes, never from document strings. */
4
+ export declare function renderImage(shape: VisioShape, resources: RenderResources): SVGGElement | undefined;
@@ -0,0 +1,10 @@
1
+ import type { VisioImage } from 'ooxml-core/visio';
2
+ /** One reference per shared core image resource, with explicit per-render disposal. */
3
+ export declare class RenderResources {
4
+ #private;
5
+ private readonly definitions?;
6
+ constructor(definitions?: SVGDefsElement | undefined);
7
+ get portable(): boolean;
8
+ imageUrl(image: VisioImage): string;
9
+ dispose(): void;
10
+ }
@@ -0,0 +1,17 @@
1
+ import { type VisioDocument, type VisioPage, type VisioMatrix } from 'ooxml-core/visio';
2
+ import { type LayerVisibilityOverride } from './viewer-layers.js';
3
+ export declare function svgElement<K extends keyof SVGElementTagNameMap>(name: K): SVGElementTagNameMap[K];
4
+ export declare function safeColor(value: string, fallback?: string): string;
5
+ export declare function matrix(value: VisioMatrix): string;
6
+ export interface RenderResult {
7
+ svg: SVGSVGElement;
8
+ warnings: string[];
9
+ dispose(): void;
10
+ }
11
+ export interface RenderOptions {
12
+ /** Static output embeds rasters and omits viewer selection semantics. Prefer exportPageSvg for bounded serialization. */
13
+ static?: boolean;
14
+ /** Optional viewer display state. Export/print snapshot APIs deliberately use saved display. */
15
+ layerVisibilityOverrides?: readonly LayerVisibilityOverride[];
16
+ }
17
+ export declare function renderPage(model: VisioDocument, page: VisioPage, options?: RenderOptions): RenderResult;
@@ -0,0 +1,4 @@
1
+ import type { VisioText } from 'ooxml-core/visio';
2
+ import type { TextLayoutBudget } from './text-layout.js';
3
+ /** Browser-font layout is approximate until compared with the licensed Visio reference corpus. */
4
+ export declare function renderText(text: VisioText, warnings: Set<string>, budget?: TextLayoutBudget): SVGGElement;
@@ -0,0 +1,7 @@
1
+ import type { VisioShape } from 'ooxml-core/visio';
2
+ export interface DetailBudget {
3
+ rows: number;
4
+ characters: number;
5
+ }
6
+ /** Runtime model checks prevent implicit DOM stringification of host-provided objects. */
7
+ export declare function assertShapeDetails(shape: VisioShape, budget: DetailBudget): void;
@@ -0,0 +1,4 @@
1
+ import { type VisioDocument } from 'ooxml-core/visio';
2
+ export declare const MAX_INPUT_BYTES: number;
3
+ /** Defensive display limits also protect callers supplying their own typed scenes. */
4
+ export declare function assertViewableDocument(model: VisioDocument): void;
@@ -0,0 +1,5 @@
1
+ import type { VisioDocument, VisioShape } from 'ooxml-core/visio';
2
+ import type { ViewerState } from './controller.js';
3
+ export declare function selectedShape(document: VisioDocument | null, selection: ViewerState['selectedShape'], pageIndex: number): VisioShape | undefined;
4
+ export declare function safeExternalHref(value: string): string | undefined;
5
+ export declare function shapeDetails(shape: VisioShape): DocumentFragment;
@@ -0,0 +1,8 @@
1
+ import type { VisioDocument } from 'ooxml-core/visio';
2
+ /**
3
+ * @internal Copy a canonically validated scene without retaining any renderer-used mutable input.
4
+ * The caller validates the result before use. Independent allocation caps also bound a host that
5
+ * changes its arrays while fields are read. Shared raster buffers are copied once per invocation.
6
+ * Inspector metadata, connectors, layers and unknown host properties are not used by static SVG.
7
+ */
8
+ export declare function copySnapshotScene(model: VisioDocument): VisioDocument;
@@ -0,0 +1,2 @@
1
+ /** Inherited public tokens use local fallback aliases so host themes are never shadowed. */
2
+ export declare const viewerStyles = "\n:host {\n --_vv-bg:var(--vv-background,#eceae8); --_vv-surface:var(--vv-surface,#fff);\n --_vv-secondary:var(--vv-secondary,#f3f2f1); --_vv-ink:var(--vv-ink,#1f1f1f);\n --_vv-muted:var(--vv-muted,#605e5c); --_vv-border:var(--vv-border,#e1dfdd);\n --_vv-accent:var(--vv-accent,#3955a3); --_vv-accent-soft:var(--vv-accent-soft,rgba(57,85,163,.10));\n display:flex; flex-direction:column; min-width:0; min-height:320px; height:100%; overflow:hidden;\n color:var(--_vv-ink); background:var(--_vv-bg); font:12px/1.5 \"Segoe UI\",Arial,sans-serif; contain:layout;\n}\n* { box-sizing:border-box; }\n[hidden] { display:none !important; }\nbutton,select,input,textarea { font:inherit; color:inherit; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; min-height:28px; padding:3px 8px; }\nbutton { cursor:pointer; }\nbutton:hover:enabled { background:var(--_vv-accent-soft); border-color:var(--_vv-accent); }\nbutton:disabled { opacity:.4; cursor:default; }\nbutton:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible { outline:2px solid var(--vv-focus,var(--_vv-accent)); outline-offset:2px; }\nbutton[aria-pressed=\"true\"] { color:var(--_vv-accent); background:var(--_vv-accent-soft); }\n.toolbar { flex:none; min-width:0; border-bottom:1px solid var(--_vv-border); background:var(--_vv-surface); }\n.ribbon-primary { height:32px; display:flex; align-items:center; gap:6px; padding:2px 8px; }\n.page-picker { display:flex; min-width:0; align-items:center; gap:8px; color:var(--_vv-muted); font-size:11px; }\n.page-picker select { width:190px; max-width:42vw; height:26px; min-height:26px; padding:2px 6px; font-size:11px; color:var(--_vv-ink); }\n.page-stepper { display:flex; align-items:center; gap:2px; }\n.page-stepper button { width:26px; height:26px; min-height:26px; padding:0; font-size:18px; line-height:22px; background:transparent; border-color:transparent; }\n.spacer { flex:1; }\n.local-label { color:var(--_vv-muted); font-size:10px; white-space:nowrap; }\n.ribbon-tabs { height:35px; display:flex; align-items:stretch; padding:0 4px; border-bottom:1px solid var(--_vv-border); }\n.ribbon-tabs button { position:relative; min-height:34px; padding:7px 14px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); font-size:12px; font-weight:500; }\n.ribbon-tabs button[aria-selected=\"true\"] { color:var(--_vv-accent); }\n.ribbon-tabs button[aria-selected=\"true\"]::after { content:\"\"; position:absolute; inset:auto 0 -1px; height:2.5px; background:var(--_vv-accent); }\n.ribbon-content { min-height:82px; display:flex; align-items:stretch; gap:0; padding:2px 4px; overflow-x:auto; }\n.ribbon-group { display:flex; flex-direction:column; justify-content:space-between; flex:none; gap:2px; padding:3px 10px 4px; border-right:1px solid var(--_vv-border); }\n.group-label { font-size:10px; line-height:12px; color:var(--_vv-muted); text-align:center; }\n.ribbon-actions { display:flex; align-items:stretch; gap:2px; flex:1; }\n.ribbon-command { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:2px; min-width:70px; padding:2px 6px; border-color:transparent; background:transparent; font-size:11px; white-space:nowrap; }\n.command-icon { display:grid; place-items:center; width:26px; height:26px; color:var(--_vv-accent); }\n.command-icon::before { content:\"\"; width:24px; height:24px; background:currentColor; mask:var(--command-symbol) center / contain no-repeat; }\n[data-icon=\"selection\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m5%203%2013%209-6%201-3%206z%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"edit\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%205h16M12%205v14M8%2019h8%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"layers\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m3%208%209-5%209%205-9%205zM3%2012l9%205%209-5M3%2016l9%205%209-5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"pages\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%225%22%20y%3D%223%22%20width%3D%2214%22%20height%3D%2218%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h8M8%2016h5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"inspector\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%223%22%20y%3D%224%22%20width%3D%2218%22%20height%3D%2216%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M14%204v16M17%208h1M17%2012h1M17%2016h1%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"notes\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%204h16v12H9l-5%204z%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h5%22%2F%3E%3C%2Fsvg%3E\"); }\n.ribbon-command[data-chrome=\"edit\"] .command-icon { font-family:ui-serif,Georgia,serif; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }\n.ribbon-hint { align-self:center; flex:none; margin:0; padding:0 16px; font-size:11px; line-height:18px; color:var(--_vv-muted); }\n.search-group { width:330px; }\n.search-controls { display:flex; align-items:center; gap:4px; flex-wrap:wrap; }\n.search-controls label { display:flex; align-items:center; min-width:0; gap:6px; flex:1; font-size:11px; }\n.search-controls input { width:100%; min-width:0; padding:3px 6px; font-size:11px; }\n.search-controls button { padding:3px 6px; font-size:10px; background:var(--_vv-secondary); }\n.search-controls [role=\"status\"] { display:block; width:100%; min-height:15px; font-size:10px; line-height:15px; color:var(--_vv-muted); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.workspace { position:relative; display:flex; flex:1; min-width:0; min-height:0; overflow:hidden; }\n.page-rail { flex:0 0 180px; width:180px; min-width:0; overflow:auto; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.pane-heading { height:37px; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:8px 10px; border-bottom:1px solid var(--_vv-border); font-size:11px; font-weight:600; }\n.pane-heading [data-page-count],.inspector-kind { color:var(--_vv-muted); font-size:10px; font-weight:400; }\n.page-list { list-style:none; padding:8px 5px; margin:0; display:flex; flex-direction:column; gap:4px; }\n.page-link { display:flex; align-items:center; position:relative; width:100%; min-width:0; gap:4px; padding:4px 5px 4px 2px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); text-align:left; }\n.page-link[aria-current=\"page\"] { background:var(--_vv-accent-soft); }\n.page-link[aria-current=\"page\"]::before { content:\"\"; position:absolute; left:0; top:4px; bottom:4px; width:3px; border-radius:0 2px 2px 0; background:var(--_vv-accent); }\n.page-number { flex:0 0 20px; width:20px; padding-right:3px; font-size:10px; text-align:right; }\n.page-card { display:flex; flex-direction:column; align-items:flex-start; min-width:0; width:100%; min-height:98px; gap:3px; padding:10px; border:1px solid var(--_vv-border); border-radius:2px; background:var(--_vv-surface); }\n.page-link[aria-current=\"page\"] .page-card { border-color:var(--_vv-accent); }\n.page-link[aria-current=\"page\"] .page-number { color:var(--_vv-accent); font-weight:600; }\n.page-mark { color:var(--_vv-muted); font-size:20px; line-height:23px; }\n.page-name { color:var(--_vv-ink); font-size:11px; font-weight:500; line-height:16px; overflow-wrap:anywhere; }\n.page-meta { color:var(--_vv-muted); font-size:9px; line-height:14px; }\n.page-empty { margin:12px; color:var(--_vv-muted); font-size:11px; }\n.viewport { position:relative; display:flex; flex-direction:column; flex:1; overflow:auto; min-width:0; min-height:0; padding:16px 4px; background:var(--_vv-bg); }\n.paper { display:block; flex:none; background:white; box-shadow:var(--vv-shadow,0 2px 8px rgb(0 0 0 / 14%)); margin:auto; }\n.paper [data-shape-id] { cursor:pointer; }\n.paper [data-selected=\"true\"] > [data-geometry] { stroke:var(--_vv-accent) !important; stroke-width:.025 !important; }\n.inspector-pane { flex:0 0 288px; width:288px; min-width:0; overflow:auto; border-left:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.inspector-body { display:flex; flex-direction:column; gap:12px; padding:12px 10px; }\n.inspector-card,.edit-controls,.layer-controls { min-width:0; padding:8px; margin:0; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); font-size:11px; line-height:17px; }\n.document-card h2 { margin:0 0 8px; font-size:10px; font-weight:500; letter-spacing:.5px; text-transform:uppercase; color:var(--_vv-muted); }\n.current-page-name { margin:0 0 8px; font-size:12px; font-weight:500; overflow-wrap:anywhere; }\n.document-card dl { display:grid; grid-template-columns:1fr auto; gap:4px 10px; margin:0; font-size:11px; }\n.document-card dt { color:var(--_vv-muted); }\n.document-card dd { margin:0; text-align:right; overflow-wrap:anywhere; }\n.selection-hint { margin:0; padding:0 2px; color:var(--_vv-muted); font-size:11px; }\nsummary { cursor:pointer; min-height:22px; line-height:22px; font-weight:500; }\nsummary::marker { color:var(--_vv-muted); font-size:10px; }\n.shape-inspector div { max-height:260px; overflow:auto; }\n.shape-inspector p { margin:6px 0; overflow-wrap:anywhere; }\n.shape-inspector dl { display:grid; grid-template-columns:minmax(60px,1fr) 1.5fr; gap:6px 10px; }\n.shape-inspector dt { font-weight:500; }\n.shape-inspector dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; }\n.shape-inspector h3 { margin:12px 0 5px; font-size:11px; }\n.shape-inspector a { color:var(--_vv-accent); overflow-wrap:anywhere; }\n.edit-controls p,.layer-controls p { margin:6px 0; color:var(--_vv-muted); overflow-wrap:anywhere; }\n.edit-controls textarea { display:block; width:100%; resize:vertical; max-height:180px; margin-top:4px; background:var(--_vv-secondary); }\n.edit-controls label { display:block; margin-top:8px; }\n.edit-actions { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }\n.edit-actions button { font-size:11px; padding:3px 7px; }\n.edit-actions [data-edit=\"apply\"]:enabled { background:var(--_vv-accent); border-color:var(--_vv-accent); color:var(--vv-accent-ink,#fff); }\n.edit-controls [data-geometry] { min-width:0; margin:8px 0 0; padding:6px; border:1px solid var(--_vv-border); }\n.edit-controls [data-geometry-field] { display:block; width:100%; min-width:0; margin-top:4px; }\n.edit-controls [data-geometry-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-diagnostics] { max-height:100px; overflow:auto; padding-left:16px; }\n.layer-controls [data-layer-list] { max-height:240px; overflow:auto; }\n.layer-controls fieldset { border:1px solid var(--_vv-border); margin:6px 0; padding:6px; min-width:0; }\n.layer-controls legend { max-width:100%; overflow-wrap:anywhere; }\n.layer-controls fieldset div { display:flex; align-items:center; gap:6px; margin:3px 0; }\n.layer-controls label { display:flex; align-items:center; gap:6px; overflow-wrap:anywhere; }\n.layer-controls input { flex-shrink:0; width:16px; height:16px; min-height:16px; padding:0; accent-color:var(--_vv-accent); }\n.notes ul { max-height:220px; overflow:auto; padding-left:17px; margin:6px 0 0; color:var(--_vv-muted); }\n.notes li { margin:5px 0; overflow-wrap:anywhere; }\n.notes-strip { flex:none; display:flex; align-items:center; justify-content:space-between; min-height:25.5px; padding:0 12px; border-top:1px solid var(--_vv-border); background:var(--_vv-bg); color:var(--_vv-muted); font-size:10px; }\n.notes-strip button { min-height:24.5px; padding:2px 0; border:0; background:transparent; color:var(--_vv-muted); font-size:11px; }\n.notes-strip button::before { content:\"\u25B8\"; margin-right:6px; }\n.notes-strip button[aria-expanded=\"true\"]::before { content:\"\u25BE\"; }\n.status { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; min-height:29px; padding:0 8px 0 12px; border-top:1px solid var(--_vv-border); color:var(--_vv-muted); background:var(--_vv-surface); font-size:10px; }\n.status-message { display:flex; gap:16px; min-width:0; }\n.status-message span { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.zoom-controls { display:flex; flex:none; align-items:center; gap:3px; }\n.zoom-controls button { min-height:24px; height:24px; padding:1px 6px; border-color:transparent; background:transparent; font-size:10px; }\n.zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:24px; padding:0; font-size:17px; line-height:20px; }\n.zoom-divider { width:1px; height:14px; background:var(--_vv-border); margin:0 3px; }\n.zoom { min-width:40px; font-size:10px; text-align:center; font-variant-numeric:tabular-nums; }\n.empty { max-width:360px; margin:60px auto; padding:16px; text-align:center; color:var(--_vv-muted); font-size:12px; }\n.empty strong { display:block; color:var(--_vv-ink); font-size:18px; font-weight:500; margin-bottom:8px; }\n@media(max-width:1100px) { .ribbon-hint { display:none; } [data-diagnostics] { display:none; } }\n@media(max-width:760px) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary { min-height:44px; line-height:44px; }\n .ribbon-primary { height:52px; padding:4px 8px; }\n .page-picker { flex:1; }\n .page-picker select { width:100%; max-width:none; min-height:44px; height:44px; font-size:12px; }\n .page-stepper button { width:44px; min-height:44px; height:44px; }\n .local-label,.ribbon-primary>.spacer { display:none; }\n .ribbon-tabs { height:44px; }\n .ribbon-tabs button { min-height:44px; padding:8px 16px; }\n .ribbon-content { min-height:86px; }\n .ribbon-group { padding:4px 8px; }\n .search-group { width:100%; border-right:0; }\n .search-controls { gap:4px; }\n .search-controls label { font-size:12px; }\n .search-controls input { font-size:12px; }\n .search-controls button { min-width:44px; font-size:0; padding:3px; }\n .search-controls [data-action=\"search-previous\"]::before { content:\"\u2039\"; font-size:22px; }\n .search-controls [data-action=\"search-next\"]::before { content:\"\u203A\"; font-size:22px; }\n #home-panel>.ribbon-group:not(.search-group) { display:none; }\n .ribbon-command { min-width:90px; }\n .workspace { display:block; overflow:auto; }\n .page-rail { width:100%; max-height:190px; border-right:0; border-bottom:1px solid var(--_vv-border); }\n .page-list { flex-direction:row; overflow-x:auto; }\n .page-list li { flex:0 0 155px; }\n .page-card { min-height:86px; }\n .viewport { height:340px; min-height:260px; padding:16px 4px; }\n .inspector-pane { width:100%; overflow:visible; border-left:0; border-top:1px solid var(--_vv-border); }\n .inspector-body { gap:8px; padding:10px; }\n .inspector-card,.edit-controls,.layer-controls { font-size:12px; }\n .layer-controls label { min-height:44px; }\n .layer-controls input { min-width:20px; width:20px; height:20px; min-height:20px; }\n .notes-strip { min-height:44px; padding:0 10px; }\n .notes-strip button { min-height:44px; }\n .status { flex-wrap:wrap; gap:0; padding:4px 8px; }\n .status-message { width:100%; min-height:18px; }\n .zoom-controls { justify-content:flex-end; width:100%; }\n .zoom-controls button { min-height:44px; height:44px; min-width:44px; font-size:11px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; font-size:20px; }\n .zoom { font-size:11px; }\n}\n@media(pointer:coarse) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary,.layer-controls label { min-height:44px; line-height:44px; }\n .ribbon-primary { min-height:52px; height:52px; }\n .page-picker select,.page-stepper button { min-height:44px; height:44px; }\n .page-stepper button { min-width:44px; }\n .ribbon-tabs { min-height:44px; height:44px; }\n .ribbon-tabs button { min-height:44px; }\n .ribbon-content { min-height:96px; }\n .search-group { width:380px; max-width:100%; }\n .zoom-controls button,.notes-strip button { min-height:44px; height:44px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; }\n .layer-controls input { min-height:20px; }\n}\n@media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }\n";