@pygmalionjs/pygmalion 0.13.0 → 0.15.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 (40) hide show
  1. package/dist-lib/{CameraLayer-CGW_FPQS.js → CameraLayer-CWrlA9D-.js} +10 -10
  2. package/dist-lib/pygmalion.js +15264 -12990
  3. package/dist-lib/{runtime-DkCf4iKe.js → runtime-7no5RTHJ.js} +1917 -1877
  4. package/dist-lib/style.css +1 -1
  5. package/dist-lib/testing.js +8 -8
  6. package/dist-lib/types/document/appearance.d.ts +5 -2
  7. package/dist-lib/types/document/assets.d.ts +12 -4
  8. package/dist-lib/types/document/imagePaintGeometry.d.ts +23 -0
  9. package/dist-lib/types/document/pages.d.ts +48 -0
  10. package/dist-lib/types/document/pagesMetadata.d.ts +16 -0
  11. package/dist-lib/types/lib.d.ts +3 -0
  12. package/dist-lib/types/workspace/contracts.d.ts +6 -0
  13. package/dist-lib/types/workspace/controller.d.ts +1 -0
  14. package/dist-lib/types/workspace/edit/AppearancePanel.d.ts +3 -1
  15. package/dist-lib/types/workspace/edit/ArrangeLayers.d.ts +2 -1
  16. package/dist-lib/types/workspace/edit/AssetsPanel.d.ts +3 -2
  17. package/dist-lib/types/workspace/edit/CanvasGuides.d.ts +6 -3
  18. package/dist-lib/types/workspace/edit/EditViewport.d.ts +31 -0
  19. package/dist-lib/types/workspace/edit/EditorCommandMenu.d.ts +18 -0
  20. package/dist-lib/types/workspace/edit/EditorToolbar.d.ts +19 -0
  21. package/dist-lib/types/workspace/edit/ImageCropEditor.d.ts +13 -0
  22. package/dist-lib/types/workspace/edit/LayerTree.d.ts +5 -1
  23. package/dist-lib/types/workspace/edit/LayoutPanel.d.ts +2 -1
  24. package/dist-lib/types/workspace/edit/NodeExportPanel.d.ts +10 -0
  25. package/dist-lib/types/workspace/edit/PagesPanel.d.ts +12 -0
  26. package/dist-lib/types/workspace/edit/PanelResizeHandle.d.ts +12 -0
  27. package/dist-lib/types/workspace/edit/PrototypePanel.d.ts +5 -1
  28. package/dist-lib/types/workspace/edit/PrototypeWiring.d.ts +18 -0
  29. package/dist-lib/types/workspace/edit/SelectionHandles.d.ts +8 -4
  30. package/dist-lib/types/workspace/edit/canvasGuideModel.d.ts +16 -0
  31. package/dist-lib/types/workspace/edit/clipboard.d.ts +1 -0
  32. package/dist-lib/types/workspace/edit/editViewportModel.d.ts +20 -0
  33. package/dist-lib/types/workspace/edit/editorCanvas.d.ts +27 -0
  34. package/dist-lib/types/workspace/edit/geometryHandles.d.ts +10 -3
  35. package/dist-lib/types/workspace/edit/prototypeWiringModel.d.ts +47 -0
  36. package/dist-lib/types/workspace/edit/rasterExport.d.ts +5 -0
  37. package/dist-lib/types/workspace/view/prototypeMotionInterruption.d.ts +37 -0
  38. package/dist-lib/types/workspace/view/prototypePlayback.d.ts +8 -0
  39. package/dist-lib/types/workspace/view/storyboardCanvas.d.ts +16 -1
  40. package/package.json +1 -1
@@ -0,0 +1,23 @@
1
+ import type { DocumentMatrix } from './contracts.js';
2
+ export interface ImagePaintPlacement {
3
+ scaleMode: 'fill' | 'fit' | 'crop' | 'tile';
4
+ scale?: number;
5
+ /** Natural image pixels to layer-local pixels. Active in crop mode; resize keeps these coordinates. */
6
+ imageTransform?: DocumentMatrix;
7
+ }
8
+ export interface ImagePaintBox {
9
+ width: number;
10
+ height: number;
11
+ }
12
+ export interface ImagePaintGeometry {
13
+ matrix: DocumentMatrix;
14
+ pattern: ImagePaintBox;
15
+ tiled: boolean;
16
+ }
17
+ export declare function isImageTransform(value: unknown): value is DocumentMatrix;
18
+ /** One projection for box, vector, text and export; explicit crop matrices never resize the asset. */
19
+ export declare function imagePaintGeometry(paint: ImagePaintPlacement, asset: ImagePaintBox, box: ImagePaintBox): ImagePaintGeometry;
20
+ /** A different asset starts from its mode default; selecting the same asset preserves the current crop. */
21
+ export declare function replaceImagePaintAsset<T extends ImagePaintPlacement & {
22
+ assetId: string;
23
+ }>(paint: T, assetId: string): T;
@@ -0,0 +1,48 @@
1
+ import type { DesignDocument, DocumentDuplicateMetadataRemapper, DocumentTransaction } from './contracts.js';
2
+ import { type DocumentPage } from './pagesMetadata.js';
3
+ export { DOCUMENT_PAGES_KEY, IMPLICIT_DOCUMENT_PAGE_ID, documentPageDiagnostics } from './pagesMetadata.js';
4
+ export type { DocumentPage, DocumentPagesMetadata } from './pagesMetadata.js';
5
+ /** Reading a legacy document never writes a sidecar or changes node identities. */
6
+ export declare function documentPages(document: DesignDocument): readonly DocumentPage[];
7
+ export declare function pageRootIds(document: DesignDocument, pageId: string): readonly string[];
8
+ /** Page defaults are presentation values until an explicit edit persists them. */
9
+ export declare function pageAppearance(document: DesignDocument, pageId: string): Readonly<{
10
+ background: string;
11
+ opacity: number;
12
+ }>;
13
+ export declare function pageForNode(document: DesignDocument, nodeId: string): string | null;
14
+ /** Wrap ordinary canvas commands so membership follows structural edits in the same undo step. */
15
+ export declare function applyDocumentPageEdit(transaction: DocumentTransaction, before: DesignDocument, activePageId: string, apply: (transaction: DocumentTransaction) => void): void;
16
+ export type DocumentPageAction = {
17
+ type: 'create';
18
+ id: string;
19
+ name: string;
20
+ index?: number;
21
+ } | {
22
+ type: 'rename';
23
+ pageId: string;
24
+ name: string;
25
+ } | {
26
+ type: 'appearance';
27
+ pageId: string;
28
+ background?: string;
29
+ opacity?: number;
30
+ } | {
31
+ type: 'move';
32
+ pageId: string;
33
+ index: number;
34
+ } | {
35
+ type: 'duplicate';
36
+ pageId: string;
37
+ id: string;
38
+ name?: string;
39
+ } | {
40
+ type: 'delete';
41
+ pageId: string;
42
+ };
43
+ export interface DocumentPageActionOptions {
44
+ allocateNodeId?: (sourceNodeId: string) => string;
45
+ remapMetadata?: DocumentDuplicateMetadataRemapper;
46
+ }
47
+ /** Page mutations use existing engine commands and then replace one same-identity canonical snapshot. */
48
+ export declare function applyDocumentPageAction(transaction: DocumentTransaction, before: DesignDocument, action: DocumentPageAction, options?: DocumentPageActionOptions): void;
@@ -0,0 +1,16 @@
1
+ import type { DesignDocument, DocumentDiagnostic } from './contracts.js';
2
+ export declare const DOCUMENT_PAGES_KEY = "pages";
3
+ export declare const IMPLICIT_DOCUMENT_PAGE_ID = "page:default";
4
+ export interface DocumentPage {
5
+ id: string;
6
+ name: string;
7
+ rootIds: readonly string[];
8
+ background?: string;
9
+ opacity?: number;
10
+ }
11
+ export interface DocumentPagesMetadata {
12
+ version: 1;
13
+ pages: readonly DocumentPage[];
14
+ }
15
+ /** Page membership partitions ordinary root children; component definitions remain shared. */
16
+ export declare function documentPageDiagnostics(document: DesignDocument): DocumentDiagnostic[];
@@ -3,6 +3,7 @@ export * from './token-library/bindings.js';
3
3
  export { STYLE_KINDS, STYLE_SLOTS, STYLE_SLOT_KIND, STYLE_KIND_LABEL, STYLE_SLOT_LABEL, TEXT_STYLE_CHARACTER_KEYS, TEXT_STYLE_PARAGRAPH_KEYS, TEXT_STYLE_KEYS, StyleError, isStylePaint, isTextStyleValue, isStyleEffect, isStyleValue, isDesignStyle, isStylesMetadata, isStyleReferences, validateStyleLibrary, EMPTY_STYLES, documentStyles, documentStyle, documentStylesOfKind, nodeStyleReferences, styleSlotsFor, documentStyleDiagnostics, createStyle, renameStyle, describeStyle, setStyleValue, removeStyle, detachStyleFromLibrary, projectStyle, detachStyleReference, styleValueFromNode, styleConsumers, propagateStyle, applyStylePropagation, writeStyles, applyStylePatch, detachStylePatch, commitCreateStyle, commitStyleValue, commitRenameStyle, commitRemoveStyle, commitApplyStyle, commitDetachStyle, commitStyleFromNode, importLibraryStyle, planStyleLibraryUpdate, commitStyleLibraryUpdate, stylesDuplicateRemapper, STYLES_METADATA_KEY, STYLE_SIDECAR_PROPERTY_KEYS, stylesSourceDiagnostics } from './document/styles.js';
4
4
  export type { StyleKind, StyleSlot, StylePaint, PaintStyleValue, TextStyleValue, StyleEffect, EffectStyleValue, GridStyleValue, StyleValue, StyleValueByKind, StyleOrigin, DesignStyle, StylesMetadata, StyleLibraryDocument, StyleReferences, StyleConsumer, StylePropagation, StyleLibraryChange, StyleLibraryUpdatePlan } from './document/styles.js';
5
5
  export { componentOverrideTarget, remapComponentOverrideAddress } from './document/engine.js';
6
+ export * from './document/pages.js';
6
7
  export { ComponentPanel } from './workspace/edit/ComponentPanel.js';
7
8
  export type { ComponentPanelProps } from './workspace/edit/ComponentPanel.js';
8
9
  export { StylesPanel } from './workspace/edit/StylesPanel.js';
@@ -436,3 +437,5 @@ export * from './workspace/view/prototypePlayback.js';
436
437
  export type { PrototypeInputFrame } from './workspace/view/prototypeInputFrame.js';
437
438
  export { createPrototypeProjectionContext } from './workspace/edit/prototypeProjection.js';
438
439
  export type { PrototypeProjectionContext } from './workspace/edit/prototypeProjection.js';
440
+ export * from './workspace/edit/rasterExport.js';
441
+ export * from './document/imagePaintGeometry.js';
@@ -13,6 +13,12 @@ export interface WorkspaceDesignContext {
13
13
  target: WorkspaceTarget;
14
14
  selection: readonly string[];
15
15
  camera: WorkspaceCamera;
16
+ /** Page navigation is view state, separate from the saved design document. */
17
+ pageId?: string;
18
+ pages?: Readonly<Record<string, {
19
+ selection: readonly string[];
20
+ camera: WorkspaceCamera;
21
+ }>>;
16
22
  }
17
23
  export interface WorkspaceApplicationSurface {
18
24
  /** An implementation URL or a built draft URL supplied by the host. */
@@ -17,6 +17,7 @@ export declare class WorkspaceController {
17
17
  edit(target?: WorkspaceTarget | null): void;
18
18
  setMode(mode: Exclude<WorkspaceMode, 'application'>): void;
19
19
  setSelection(selection: readonly string[]): void;
20
+ setDesignPage(pageId: string, currentPageId?: string): void;
20
21
  setCamera(mode: 'view' | 'edit', next: WorkspaceCamera): void;
21
22
  beginApplication(request: WorkspaceRunRequest): number;
22
23
  private startApplication;
@@ -1,12 +1,14 @@
1
1
  import type { DesignDocument, DocumentEngine, DocumentNode } from '../../document/contracts.js';
2
2
  import { appearanceToCss } from '../../document/appearance.js';
3
3
 
4
+
4
5
  export interface AppearancePanelProps {
5
6
  engine: DocumentEngine;
6
7
  nodeId: string;
7
8
  disabled?: boolean;
9
+ compact?: boolean;
8
10
  }
9
- export declare function AppearancePanel({ engine, nodeId, disabled }: AppearancePanelProps): import("react").JSX.Element | null;
11
+ export declare function AppearancePanel({ engine, nodeId, disabled, compact }: AppearancePanelProps): import("react").JSX.Element | null;
10
12
  /** Separate decorative layers preserve each paint's opacity independently of the content. */
11
13
  export declare function AppearanceSurface({ node, document }: {
12
14
  node: DocumentNode;
@@ -1,10 +1,11 @@
1
1
  import type { DesignDocument, DocumentEngineOptions, DocumentTransaction } from '../../document/contracts.js';
2
2
  import type { DataProjection } from '../../binding/preview.js';
3
3
 
4
- export declare function ArrangeLayers({ document, selected, projection, preflight, act }: {
4
+ export declare function ArrangeLayers({ document, selected, projection, preflight, act, compact }: {
5
5
  document: DesignDocument;
6
6
  selected: readonly string[];
7
7
  projection: DataProjection | null;
8
+ compact?: boolean;
8
9
  preflight?: DocumentEngineOptions['preflight'];
9
10
  act(label: string, apply: (transaction: DocumentTransaction) => void): boolean;
10
11
  }): import("react").JSX.Element;
@@ -1,8 +1,9 @@
1
1
  import type { DocumentEngine } from '../../document/contracts.js';
2
- import { type DesignExportArtifact, type RasterExportRenderer } from '../../document/exportSettings.js';
2
+ import type { DesignExportArtifact, RasterExportRenderer } from '../../document/exportSettings.js';
3
3
 
4
4
  export interface AssetsPanelProps {
5
5
  engine: DocumentEngine;
6
+ pageId?: string;
6
7
  parentId?: string;
7
8
  selectedNodeId?: string;
8
9
  allocateId: (sourceId: string) => string;
@@ -11,6 +12,6 @@ export interface AssetsPanelProps {
11
12
  rasterRenderer?: RasterExportRenderer;
12
13
  disabled?: boolean;
13
14
  }
14
- export declare function AssetsPanel({ engine, parentId, selectedNodeId, allocateId, onSelect, onExport, rasterRenderer, disabled }: AssetsPanelProps): import("react").JSX.Element;
15
+ export declare function AssetsPanel({ engine, pageId, parentId, selectedNodeId, allocateId, onSelect, onExport, rasterRenderer, disabled }: AssetsPanelProps): import("react").JSX.Element;
15
16
  /** Explicit local download callback for the panel; raster output still needs a separate host renderer. */
16
17
  export declare function downloadDesignArtifact(artifact: DesignExportArtifact): void;
@@ -1,16 +1,19 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
+ import type { WorkspaceCamera } from '../contracts.js';
2
3
  import type { DesignDocument, DocumentNode, DocumentTransaction } from '../../document/contracts.js';
3
4
 
4
5
  type Act = (label: string, apply: (transaction: DocumentTransaction) => void) => unknown;
5
- /** Rulers and persisted guide/grid overlays use canvas units inside the scaled stage. */
6
- export declare function CanvasGuides({ document, selected, projection, zoom, act, width, height }: {
6
+ /** A camera mounts rulers in viewport pixels and transforms document annotations exactly once. */
7
+ export declare function CanvasGuides({ document, selected, projection, camera, zoom: suppliedZoom, act, width, height, visibleRootIds }: {
7
8
  document: DesignDocument;
8
9
  selected?: readonly string[];
9
10
  projection?: DataProjection | null;
10
- zoom: number;
11
+ camera?: WorkspaceCamera;
12
+ zoom?: number;
11
13
  act: Act;
12
14
  width?: number;
13
15
  height?: number;
16
+ visibleRootIds?: readonly string[];
14
17
  }): import("react").JSX.Element;
15
18
  export declare function CanvasGuidesPanel({ node, act }: {
16
19
  node: DocumentNode;
@@ -0,0 +1,31 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { WorkspaceCamera } from '../contracts.js';
3
+ import { type EditViewportBounds } from './editViewportModel.js';
4
+
5
+ export interface EditViewportHandle {
6
+ fitAll(): void;
7
+ fitSelection(): void;
8
+ actualSize(): void;
9
+ zoomIn(): void;
10
+ zoomOut(): void;
11
+ }
12
+ export interface EditViewportProps {
13
+ children: ReactNode;
14
+ camera: WorkspaceCamera;
15
+ onCameraChange(camera: WorkspaceCamera): void;
16
+ bounds: EditViewportBounds;
17
+ selectionBounds?: EditViewportBounds;
18
+ documentKey: string;
19
+ hand: boolean;
20
+ /** Captured once per document entry; false preserves a restored camera. */
21
+ initialFit?: boolean;
22
+ /** Wait for asynchronously projected geometry before the initial fit. */
23
+ ready?: boolean;
24
+ /** Viewport furniture stays outside the transformed document stage. */
25
+ overlay?(viewport: {
26
+ camera: WorkspaceCamera;
27
+ width: number;
28
+ height: number;
29
+ }): ReactNode;
30
+ }
31
+ export declare const EditViewport: import("react").ForwardRefExoticComponent<EditViewportProps & import("react").RefAttributes<EditViewportHandle>>;
@@ -0,0 +1,18 @@
1
+
2
+ export interface EditorMenuCommand {
3
+ id: string;
4
+ label: string;
5
+ shortcut?: string;
6
+ disabled?: boolean;
7
+ reason?: string;
8
+ group: string;
9
+ run(): void;
10
+ }
11
+ /** One keyboard-accessible command surface for both the file and layer menus. */
12
+ export declare function EditorCommandMenu({ x, y, label, commands, onClose }: {
13
+ x: number;
14
+ y: number;
15
+ label: string;
16
+ commands: readonly EditorMenuCommand[];
17
+ onClose(): void;
18
+ }): import("react").ReactPortal;
@@ -0,0 +1,19 @@
1
+
2
+ export type EditorTool = 'select' | 'hand' | 'frame' | 'text' | 'rectangle' | 'ellipse' | 'line' | 'polygon' | 'star' | 'arc' | 'pen' | 'marquee';
3
+ export interface EditorToolbarProps {
4
+ tool: EditorTool;
5
+ onToolChange(tool: EditorTool): void;
6
+ canUndo: boolean;
7
+ canRedo: boolean;
8
+ onUndo(): void;
9
+ onRedo(): void;
10
+ canGroup: boolean;
11
+ canDuplicate: boolean;
12
+ duplicateDisabledReason?: string;
13
+ onGroup(): void;
14
+ onDuplicate(): void;
15
+ canDelete?: boolean;
16
+ onDelete?(): void;
17
+ }
18
+ /** Tool selection and editor commands only; the canvas owns gestures and document transactions. */
19
+ export declare function EditorToolbar(props: EditorToolbarProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { DocumentMatrix } from '../../document/contracts.js';
2
+ import type { DocumentAsset, ImagePaint } from '../../document/assets.js';
3
+
4
+ export interface ImageCropEditorProps {
5
+ asset: DocumentAsset;
6
+ paint: ImagePaint;
7
+ width: number;
8
+ height: number;
9
+ onApply(matrix: DocumentMatrix): void;
10
+ onCancel(): void;
11
+ }
12
+ /** This local preview keeps asset bytes and canonical history unchanged until Apply. */
13
+ export declare function ImageCropEditor({ asset, paint, width, height, onApply, onCancel }: ImageCropEditorProps): import("react").JSX.Element;
@@ -1,3 +1,4 @@
1
+ import type { MouseEvent } from 'react';
1
2
  import type { DesignDocument, DocumentEngineOptions, DocumentTransaction } from '../../document/contracts.js';
2
3
  import type { HostDataCapabilities } from '../../binding/contracts.js';
3
4
 
@@ -9,6 +10,9 @@ export interface LayerTreeProps {
9
10
  preflight?: DocumentEngineOptions['preflight'];
10
11
  /** With host declarations, a drop blocked only by a data-scope escape asks for explicit binding decisions. */
11
12
  capabilities?: HostDataCapabilities;
13
+ /** Undefined preserves the full document tree; an empty array shows an empty page. */
14
+ rootIds?: readonly string[];
15
+ onContextMenu?(event: MouseEvent<HTMLDivElement>, nodeId: string): void;
12
16
  }
13
17
  /** A document-owned tree gesture always commits through the existing document transaction. */
14
- export declare function LayerTree({ document, selected, onSelectionChange, act, preflight, capabilities }: LayerTreeProps): import("react").JSX.Element;
18
+ export declare function LayerTree({ document, selected, onSelectionChange, act, preflight, capabilities, rootIds, onContextMenu }: LayerTreeProps): import("react").JSX.Element;
@@ -7,7 +7,8 @@ export interface LayoutPanelProps {
7
7
  act: Act;
8
8
  sourceGroup?: boolean;
9
9
  intrinsic?: boolean;
10
+ compact?: boolean;
10
11
  }
11
12
  /** Authored layout controls. Source wrappers retain host-declared spacing spellings on review. */
12
- export declare function LayoutPanel({ document, node, act, sourceGroup, intrinsic }: LayoutPanelProps): import("react").JSX.Element;
13
+ export declare function LayoutPanel({ document, node, act, sourceGroup, intrinsic, compact }: LayoutPanelProps): import("react").JSX.Element;
13
14
  export {};
@@ -0,0 +1,10 @@
1
+ import type { DocumentEngine } from '../../document/contracts.js';
2
+ import { type DesignExportArtifact, type RasterExportRenderer } from '../../document/exportSettings.js';
3
+ /** The inspector and asset browser share one persisted export-settings editor. */
4
+ export declare function NodeExportPanel({ engine, nodeId, onExport, rasterRenderer, disabled }: {
5
+ engine: DocumentEngine;
6
+ nodeId?: string;
7
+ onExport?(artifact: DesignExportArtifact): void | Promise<void>;
8
+ rasterRenderer?: RasterExportRenderer;
9
+ disabled?: boolean;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { DesignDocument, DocumentDuplicateMetadataRemapper, DocumentTransaction } from '../../document/contracts.js';
2
+
3
+ export interface PagesPanelProps {
4
+ document: DesignDocument;
5
+ activePageId: string;
6
+ onPageChange(pageId: string): void;
7
+ act(label: string, apply: (transaction: DocumentTransaction) => void): boolean;
8
+ duplicateMetadata?: DocumentDuplicateMetadataRemapper;
9
+ allocateId?(): string;
10
+ }
11
+ /** Page selection is UI state; only explicit page edits create document history. */
12
+ export declare function PagesPanel({ document, activePageId, onPageChange, act, duplicateMetadata, allocateId }: PagesPanelProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+
2
+ export interface PanelResizeHandleProps {
3
+ side: 'left' | 'right';
4
+ width: number;
5
+ min: number;
6
+ max: number;
7
+ defaultWidth: number;
8
+ onWidthChange(width: number): void;
9
+ label?: string;
10
+ }
11
+ /** Panel layout only. Live widths are controlled; cancellation restores the starting width. */
12
+ export declare function PanelResizeHandle({ side, width, min, max, defaultWidth, onWidthChange, label }: PanelResizeHandleProps): import("react").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import type { DocumentEngine } from '../../document/contracts.js';
2
+ import type { PrototypeConnectionSelection } from './prototypeWiringModel.js';
2
3
 
3
4
  export declare function PrototypeField({ label, value, onCommit, numeric }: {
4
5
  label: string;
@@ -6,7 +7,10 @@ export declare function PrototypeField({ label, value, onCommit, numeric }: {
6
7
  onCommit(value: string): void;
7
8
  numeric?: boolean;
8
9
  }): import("react").JSX.Element;
9
- export declare function PrototypePanel({ engine, nodeId }: {
10
+ export declare function PrototypePanel({ engine, nodeId, selectedConnection, onSelectConnection, compact }: {
11
+ compact?: boolean;
10
12
  engine: DocumentEngine;
11
13
  nodeId: string | null;
14
+ selectedConnection?: PrototypeConnectionSelection | null;
15
+ onSelectConnection?(value: PrototypeConnectionSelection | null): void;
12
16
  }): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import type { DataProjection } from '../../binding/preview.js';
2
+ import type { DesignDocument, DocumentTransaction } from '../../document/contracts.js';
3
+ import { type PrototypeConnectionSelection } from './prototypeWiringModel.js';
4
+
5
+ export type { PrototypeConnectionSelection } from './prototypeWiringModel.js';
6
+ export interface PrototypeWiringProps {
7
+ document: DesignDocument;
8
+ selected: readonly string[];
9
+ projection: DataProjection | null;
10
+ zoom: number;
11
+ visibleRootIds?: readonly string[];
12
+ selectedConnection: PrototypeConnectionSelection | null;
13
+ onSelectConnection(value: PrototypeConnectionSelection | null): void;
14
+ onSelect(nodeId: string): void;
15
+ act(label: string, apply: (transaction: DocumentTransaction) => void): boolean;
16
+ }
17
+ /** An authoring overlay in page coordinates. Browsing or dragging never runs a prototype action. */
18
+ export declare function PrototypeWiring(props: PrototypeWiringProps): import("react").JSX.Element | null;
@@ -9,6 +9,7 @@ export interface LayerGeometryPreview extends LayerPlacement {
9
9
  export interface SelectionHandlesProps {
10
10
  document: DesignDocument;
11
11
  selected: readonly string[];
12
+ visibleRootIds?: readonly string[];
12
13
  projection: DataProjection | null;
13
14
  /** Canvas scale; handles keep a constant screen size and snapping a constant screen tolerance. */
14
15
  zoom: number;
@@ -20,6 +21,8 @@ export interface SelectionHandlesProps {
20
21
  readonly y: number;
21
22
  readonly guides?: readonly SnapGuide[];
22
23
  } | null;
24
+ /** Pending canvas placements for a move involving several layers. */
25
+ movePreviews?: readonly LayerGeometryPreview[] | null;
23
26
  /** Lets the canvas render the layer with in-gesture geometry; `null` ends the preview. */
24
27
  onPreview?(preview: LayerGeometryPreview | null): void;
25
28
  /** Same for a selection box gesture, which previews several layers at once; `null` ends the preview. */
@@ -35,18 +38,19 @@ export declare const SELECTION_BOX_ID = "selection";
35
38
  * constant on screen. Every gesture becomes one document transaction on release; Escape cancels
36
39
  * it with the document untouched. Layers the geometry policy refuses (auto layout children,
37
40
  * source layout, repeated rows) get no handles; the inspector section reports the diagnostic,
38
- * mirroring layer arrangement, so the canvas DOM carries no text beyond the transient gesture
39
- * feedback.
41
+ * mirroring layer arrangement. The dimension badge follows the live world bounds without
42
+ * applying its own document changes.
40
43
  */
41
- export declare function SelectionHandles({ document, selected, projection, zoom, act, movePreview, onPreview, onPreviewMany }: SelectionHandlesProps): import("react").JSX.Element;
44
+ export declare function SelectionHandles({ document, selected, visibleRootIds, projection, zoom, act, movePreview, movePreviews, onPreview, onPreviewMany }: SelectionHandlesProps): import("react").JSX.Element;
42
45
  /**
43
46
  * Inspector section: the geometry policy for the whole selection, plus parent-relative rotation
44
47
  * in degrees and resize constraints when exactly one layer is selected.
45
48
  */
46
- export declare function LayerGeometryInspector({ document, selected, projection, act }: {
49
+ export declare function LayerGeometryInspector({ document, selected, projection, act, compact }: {
47
50
  document: DesignDocument;
48
51
  selected: readonly string[];
49
52
  projection: DataProjection | null;
50
53
  act: Act;
54
+ compact?: boolean;
51
55
  }): import("react").JSX.Element | null;
52
56
  export {};
@@ -45,11 +45,20 @@ export interface LayoutGridGeometry {
45
45
  readonly axis: GuideAxis;
46
46
  readonly tracks: readonly LayoutGridTrack[];
47
47
  }
48
+ /** An origin-zero pixel lattice, clipped to its owner's local box; no individual lines are allocated. */
49
+ export interface LayoutGridLattice {
50
+ readonly axis: GuideAxis;
51
+ readonly step: number;
52
+ readonly extent: number;
53
+ }
48
54
  export interface RulerTick {
49
55
  readonly position: number;
50
56
  readonly major: boolean;
51
57
  readonly label?: string;
52
58
  }
59
+ export interface ViewportRulerTick extends RulerTick {
60
+ readonly screen: number;
61
+ }
53
62
  export interface RulerScale {
54
63
  readonly major: number;
55
64
  readonly minor: number;
@@ -64,6 +73,7 @@ export declare const LAYOUT_GRID_DEFAULT_COLOR = "#ff4d4d1a";
64
73
  export declare const PIXEL_GRID_DEFAULT_COLOR = "#0000000f";
65
74
  /** Screen pixels between two labelled ruler ticks, at least. */
66
75
  export declare const RULER_LABEL_SPACING = 60;
76
+ export declare const RULER_THICKNESS = 18;
67
77
  export declare function isCanvasGuide(value: unknown): value is CanvasGuide;
68
78
  /** Strict structural check of a stored layout grid; unknown keys and non-finite numbers are rejected. */
69
79
  export declare function isLayoutGrid(value: unknown): value is LayoutGrid;
@@ -94,9 +104,15 @@ export declare function layoutGridTracks(grid: LayoutGridTracks, length: number)
94
104
  export declare function layoutGridGeometry(grid: LayoutGrid, width: number, height: number): LayoutGridGeometry | null;
95
105
  /** Distinct track edges of every visible column and row grid on a node, by axis, for snapping. */
96
106
  export declare function layoutGridSnapLines(grids: readonly LayoutGrid[], width: number, height: number): CanvasGuide[];
107
+ /** Two constant-size descriptors per visible pixel grid, including subpixel and very dense grids. */
108
+ export declare function layoutGridSnapLattices(grids: readonly LayoutGrid[], width: number, height: number): readonly LayoutGridLattice[];
109
+ /** Nearest visible line, with the lower line winning a midpoint tie. Work is independent of line count. */
110
+ export declare function nearestLayoutGridLine(lattice: Pick<LayoutGridLattice, 'step' | 'extent'>, position: number): number | null;
97
111
  /** Labelled step and tick step for a ruler at a zoom: labels stay at least `RULER_LABEL_SPACING` screen pixels apart. */
98
112
  export declare function rulerScale(zoom: number, labelSpacing?: number): RulerScale;
99
113
  /** Ticks covering `[from, to]` canvas units; every `major` multiple carries its value as the label. */
100
114
  export declare function rulerTicks(zoom: number, from: number, to: number, labelSpacing?: number): RulerTick[];
101
115
  /** Canvas position under a ruler pointer: `screen` is measured from the ruler's zero corner, `origin` is where canvas 0 sits on that ruler. */
102
116
  export declare function rulerPointToCanvas(screen: number, origin: number, zoom: number): number;
117
+ /** Camera origin is viewport-local; only ticks outside the fixed corner are displayed. */
118
+ export declare function viewportRulerTicks(zoom: number, origin: number, length: number): ViewportRulerTick[];
@@ -29,6 +29,7 @@ export declare function pasteDesignSubtrees(targetInput: DesignDocument, payload
29
29
  x: number;
30
30
  y: number;
31
31
  };
32
+ pageId?: string;
32
33
  }): PasteDesignResult;
33
34
  export declare function applyDesignPaste(transaction: Pick<DocumentTransaction, 'replaceDocument'>, plan: PasteDesignResult): void;
34
35
  export declare function exportDesignInterchange(document: DesignDocument): string;
@@ -0,0 +1,20 @@
1
+ import type { WorkspaceCamera } from '../contracts.js';
2
+ export interface EditViewportBounds {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface EditViewportSize {
9
+ width: number;
10
+ height: number;
11
+ }
12
+ export declare function validEditCamera(camera: WorkspaceCamera): boolean;
13
+ /** A hidden viewport or invalid geometry must never replace a usable camera. */
14
+ export declare function fitEditViewport(bounds: EditViewportBounds, viewport: EditViewportSize): WorkspaceCamera | null;
15
+ /** Preserve the world point under a viewport-local pointer or viewport center. */
16
+ export declare function zoomEditViewport(camera: WorkspaceCamera, anchor: {
17
+ x: number;
18
+ y: number;
19
+ }, requestedZoom: number): WorkspaceCamera | null;
20
+ export declare function panEditViewport(camera: WorkspaceCamera, dx: number, dy: number): WorkspaceCamera | null;
@@ -0,0 +1,27 @@
1
+ import type { DataProjection } from '../../binding/preview.js';
2
+ import type { DesignDocument, DocumentNode } from '../../document/contracts.js';
3
+ import { type VectorShape } from '../../document/vector.js';
4
+ export interface CanvasBox {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ }
10
+ export interface CanvasEntry {
11
+ id: string;
12
+ box: CanvasBox;
13
+ topLevel: boolean;
14
+ }
15
+ export type DrawingTool = 'frame' | 'text' | VectorShape;
16
+ export declare function canvasEntries(document: DesignDocument, projection: DataProjection | null, selected?: readonly string[], visibleRootIds?: readonly string[]): CanvasEntry[];
17
+ export declare function canvasBounds(entries: readonly CanvasEntry[]): CanvasBox;
18
+ export declare function marqueeSelection(document: DesignDocument, entries: readonly CanvasEntry[], box: CanvasBox): readonly string[];
19
+ export declare function drawingBox(start: {
20
+ x: number;
21
+ y: number;
22
+ }, end: {
23
+ x: number;
24
+ y: number;
25
+ }, square?: boolean): CanvasBox;
26
+ /** New free layers are created in page space. Source components retain their owned geometry. */
27
+ export declare function drawnNode(tool: DrawingTool, id: string, box: CanvasBox, reverseLine?: boolean): DocumentNode;
@@ -73,7 +73,7 @@ export interface SnapGap {
73
73
  export interface SnapGuide {
74
74
  readonly axis: 'x' | 'y';
75
75
  readonly position: number;
76
- /** `edge` and `center` come from boxes, `guide` from persisted guides, `grid` from layout grid tracks, `spacing` from equal sibling distances. */
76
+ /** `edge` and `center` come from boxes, `guide` from persisted guides, `grid` from layout grids, `spacing` from equal sibling distances. */
77
77
  readonly kind: 'edge' | 'center' | 'guide' | 'grid' | 'spacing';
78
78
  readonly nodeId: string;
79
79
  /** Extent along the other axis, for drawing the guide line; equal values mean "the moving box only". */
@@ -83,6 +83,11 @@ export interface SnapGuide {
83
83
  readonly reference?: SnapReference;
84
84
  /** The equal distances a `spacing` candidate reproduces, for drawing. */
85
85
  readonly gaps?: readonly SnapGap[];
86
+ /** Candidate-only pixel lattice, starting at `position`; resolved feedback never contains this field. */
87
+ readonly lattice?: {
88
+ readonly step: number;
89
+ readonly extent: number;
90
+ };
86
91
  }
87
92
  export interface SnapResult {
88
93
  readonly dx: number;
@@ -90,6 +95,8 @@ export interface SnapResult {
90
95
  readonly guides: readonly SnapGuide[];
91
96
  }
92
97
  export interface SnapCandidateOptions {
98
+ /** Ordinary root layers visible on the current page; undefined retains the complete scene. */
99
+ readonly visibleRootIds?: readonly string[];
93
100
  /** Include the moving layers' own children: right for a resize, wrong for a move (the children travel along). */
94
101
  readonly children?: boolean;
95
102
  }
@@ -105,7 +112,7 @@ export interface MoveSnapSession {
105
112
  * refused with a diagnostic instead of guessed bounds. Derived sizes keep move and
106
113
  * rotation but drop the resize handles.
107
114
  */
108
- export declare function planSelectionHandles(document: DesignDocument, nodeIds: readonly string[], projection: DataProjection | null): SelectionHandlesPlan;
115
+ export declare function planSelectionHandles(document: DesignDocument, nodeIds: readonly string[], projection: DataProjection | null, options?: SnapCandidateOptions): SelectionHandlesPlan;
109
116
  export declare function layerResizeHandles(layer: Pick<LayerGeometry, 'resizable' | 'resizeAxes'>): readonly GeometryHandle[];
110
117
  /**
111
118
  * Turn a handle drag into a new local size and placement. The handle's opposite edge or
@@ -202,7 +209,7 @@ export declare function snapResizeGesture(layer: LayerPlacement & {
202
209
  * Snapshot for a move gesture: the moving box, its candidates (siblings, parent, guides, grids,
203
210
  * and equal sibling distances for this box size), and the zoom-aware tolerance.
204
211
  */
205
- export declare function beginMoveSnap(document: DesignDocument, nodeIds: readonly string[], projection: DataProjection | null, zoom: number): MoveSnapSession | null;
212
+ export declare function beginMoveSnap(document: DesignDocument, nodeIds: readonly string[], projection: DataProjection | null, zoom: number, options?: SnapCandidateOptions): MoveSnapSession | null;
206
213
  /** Adjust world pointer travel so the moving box snaps; exact in one pass because only translation changes. */
207
214
  export declare function snapMove(session: MoveSnapSession, delta: {
208
215
  x: number;
@@ -0,0 +1,47 @@
1
+ import type { DataProjection } from '../../binding/preview.js';
2
+ import type { DesignDocument, DocumentTransaction } from '../../document/contracts.js';
3
+ import { type PrototypeAction, type PrototypeInteraction } from '../../document/prototype.js';
4
+ export type PrototypeActionPath = readonly (number | 'branches' | 'actions' | 'otherwise')[];
5
+ export interface PrototypeConnectionSelection {
6
+ nodeId: string;
7
+ interactionId: string;
8
+ actionPath: PrototypeActionPath;
9
+ }
10
+ export interface PrototypeConnection extends PrototypeConnectionSelection {
11
+ destinationId: string;
12
+ action: PrototypeAction;
13
+ label: string;
14
+ }
15
+ export interface WiringPoint {
16
+ x: number;
17
+ y: number;
18
+ }
19
+ export interface WiringBounds extends WiringPoint {
20
+ width: number;
21
+ height: number;
22
+ }
23
+ export interface PrototypeWiringLayer {
24
+ nodeId: string;
25
+ name: string;
26
+ bounds: WiringBounds;
27
+ rootId: string;
28
+ visible: boolean;
29
+ }
30
+ export interface PrototypeWiringPlan {
31
+ layers: readonly PrototypeWiringLayer[];
32
+ diagnostics: readonly string[];
33
+ }
34
+ export declare const connectionKey: (value: PrototypeConnectionSelection) => string;
35
+ /** Only explicit destination actions become wires. No flow or action is inferred. */
36
+ export declare function prototypeConnections(document: DesignDocument): PrototypeConnection[];
37
+ /** Canonical, uniquely placed layers only; projected rows and instance leaves cannot acquire shared actions accidentally. */
38
+ export declare function planPrototypeWiring(document: DesignDocument, projection: DataProjection | null, selected?: readonly string[], visibleRootIds?: readonly string[]): PrototypeWiringPlan;
39
+ /** Builds a complete detached edit before the caller opens its single history transaction. */
40
+ export declare function preparePrototypeConnection(document: DesignDocument, sourceId: string, destinationId: string | null, selection?: PrototypeConnectionSelection, interactionId?: string): PrototypeInteraction[];
41
+ export declare function writePrototypeConnection(transaction: DocumentTransaction, document: DesignDocument, sourceId: string, interactions: readonly PrototypeInteraction[]): void;
42
+ export declare function prototypeWireCurve(source: WiringBounds, target: WiringBounds, lane: number, zoom: number, loop?: boolean): {
43
+ path: string;
44
+ start: WiringPoint;
45
+ end: WiringPoint;
46
+ middle: WiringPoint;
47
+ };