@pygmalionjs/pygmalion 0.18.0 → 0.20.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 (30) hide show
  1. package/README.md +81 -4
  2. package/dist-lib/{CameraLayer-Clqgdcjb.js → CameraLayer-DXeRJvoy.js} +1 -1
  3. package/dist-lib/pygmalion.js +16601 -15855
  4. package/dist-lib/{runtime-B8Qu1ung.js → runtime-DcPbR8PS.js} +3391 -3224
  5. package/dist-lib/style.css +1 -1
  6. package/dist-lib/testing.js +5 -5
  7. package/dist-lib/types/editor/conditionAxes.d.ts +60 -0
  8. package/dist-lib/types/editor/declarations.d.ts +22 -5
  9. package/dist-lib/types/editor/designImport.d.ts +12 -0
  10. package/dist-lib/types/editor/revisionCatalog.d.ts +3 -0
  11. package/dist-lib/types/editor/revisionCatalogInstall.d.ts +2 -0
  12. package/dist-lib/types/editor/store.d.ts +6 -0
  13. package/dist-lib/types/editor/storyboardEnvironment.d.ts +5 -0
  14. package/dist-lib/types/lib.d.ts +9 -0
  15. package/dist-lib/types/token-library/bindings.d.ts +44 -0
  16. package/dist-lib/types/workspace/WorkspaceConditions.d.ts +1 -1
  17. package/dist-lib/types/workspace/edit/ArrangeLayers.d.ts +5 -1
  18. package/dist-lib/types/workspace/edit/CanvasGuides.d.ts +5 -1
  19. package/dist-lib/types/workspace/edit/PrototypeWiring.d.ts +4 -0
  20. package/dist-lib/types/workspace/edit/SelectionHandles.d.ts +10 -2
  21. package/dist-lib/types/workspace/edit/VectorEditor.d.ts +12 -1
  22. package/dist-lib/types/workspace/edit/editorCanvas.d.ts +6 -1
  23. package/dist-lib/types/workspace/edit/geometryHandles.d.ts +13 -1
  24. package/dist-lib/types/workspace/edit/layerArrangement.d.ts +4 -1
  25. package/dist-lib/types/workspace/edit/projection.d.ts +23 -1
  26. package/dist-lib/types/workspace/edit/prototypeWiringModel.d.ts +2 -1
  27. package/dist-lib/types/workspace/edit/textLayoutProjection.d.ts +28 -0
  28. package/dist-lib/types/workspace/edit/useTextLayout.d.ts +19 -0
  29. package/dist-lib/types/workspace/edit/vectorTools.d.ts +9 -5
  30. package/package.json +1 -1
@@ -0,0 +1,60 @@
1
+ import type { StoryboardEnvironment } from './designImport.js';
2
+ /**
3
+ * One value of a catalog condition axis.
4
+ *
5
+ * The environment is what the value means to the browser: boot storage,
6
+ * permissions, devices, an opaque screen preset. It is merged into the
7
+ * storyboard baseline, so every capture fingerprint, flow session and
8
+ * Application run re-resolves under it. An option without an environment is a
9
+ * pure catalog choice and leaves existing capture identities untouched.
10
+ */
11
+ export interface CatalogConditionAxisOptionDef {
12
+ value: string;
13
+ label: string;
14
+ description?: string;
15
+ environment?: StoryboardEnvironment;
16
+ }
17
+ /**
18
+ * One independent condition the whole catalog can be seen under.
19
+ *
20
+ * A session preset is a single runtime choice; a preview environment control
21
+ * dresses only the live preview. Products also have flags that cut across both:
22
+ * a color scheme, an account level, a feature entitlement. Each is its own axis
23
+ * with stable value ids. Screens say in `conditions` which values they exist
24
+ * under; a screen that names no axis exists under every value of it.
25
+ *
26
+ * Without `defaultValue` an unselected axis constrains nothing, the same way the
27
+ * legacy "Default" session shows every runtime. With one, the default is the
28
+ * effective value from the start.
29
+ */
30
+ export interface CatalogConditionAxisDef {
31
+ id: string;
32
+ label: string;
33
+ description?: string;
34
+ defaultValue?: string;
35
+ options: readonly CatalogConditionAxisOptionDef[];
36
+ }
37
+ /** Explicit selections only; defaults stay implicit. */
38
+ export type CatalogConditionSelections = Readonly<Record<string, string>>;
39
+ /** Values, per axis id, a screen exists under. Absent axes mean every value. */
40
+ export type ScreenConditionDeclaration = Readonly<Record<string, readonly string[]>>;
41
+ /**
42
+ * One editor's declared condition axes, the explicit selections, and the
43
+ * environment they contribute to the storyboard baseline.
44
+ */
45
+ export declare function createConditionAxes(deps: {
46
+ setStoryboardBaselineEnvironment(environment?: StoryboardEnvironment): void;
47
+ }): {
48
+ setConditionAxes: (next: readonly CatalogConditionAxisDef[]) => void;
49
+ getConditionAxes: () => readonly CatalogConditionAxisDef[];
50
+ getConditionAxisValue: (axisId: string) => string | null | undefined;
51
+ getConditionAxisSelections: () => CatalogConditionSelections;
52
+ selectConditionAxisValue: (axisId: string, value: string | null) => void;
53
+ clearConditionAxisSelections: () => void;
54
+ getConditionAxesEnvironment: () => StoryboardEnvironment | undefined;
55
+ isInSelectedConditions: (conditions: ScreenConditionDeclaration | undefined) => boolean;
56
+ conditionDeclarationIssues: (conditions: ScreenConditionDeclaration | undefined) => string[];
57
+ subscribeConditionAxes: (listener: () => void) => () => void;
58
+ getConditionAxesRevision: () => number;
59
+ };
60
+ export type ConditionAxes = ReturnType<typeof createConditionAxes>;
@@ -1,11 +1,13 @@
1
+ import { type ScreenConditionDeclaration } from './conditionAxes.js';
2
+ import type { StoryboardEnvironment } from './designImport.js';
1
3
  export declare function createEditorDeclarations(): {
2
4
  setPreviewDependencyDigests: (routes: readonly {
3
5
  path?: string;
4
6
  dependencyDigest?: string;
5
7
  }[] | null) => void;
6
8
  previewDependencyDigest: (route: string) => string | undefined;
7
- routePreviewFrameRecipe: (page: import("./previewBootstrap.js").PreviewFramePage, baselineEnvironment?: import("./designImport.js").StoryboardEnvironment) => import("./previewBootstrap.js").RoutePreviewFrameRecipe;
8
- createRoutePreviewFrameFingerprint: (page: import("./previewBootstrap.js").PreviewFramePage, previewRevision: string, baselineEnvironment?: import("./designImport.js").StoryboardEnvironment) => string;
9
+ routePreviewFrameRecipe: (page: import("./previewBootstrap.js").PreviewFramePage, baselineEnvironment?: StoryboardEnvironment) => import("./previewBootstrap.js").RoutePreviewFrameRecipe;
10
+ createRoutePreviewFrameFingerprint: (page: import("./previewBootstrap.js").PreviewFramePage, previewRevision: string, baselineEnvironment?: StoryboardEnvironment) => string;
9
11
  setDesignImportController: (controller: import("./designImport.js").DesignImportController | null) => void;
10
12
  getDesignImportController: () => import("./designImport.js").DesignImportController | null;
11
13
  setSurfaceClassifications: (classifications: readonly import("./surfaceDemands.js").SurfaceClassification[] | undefined) => void;
@@ -20,17 +22,32 @@ export declare function createEditorDeclarations(): {
20
22
  subscribeStoryboardGraph: (listener: () => void) => () => void;
21
23
  bumpPreviewIdentityEpoch: () => void;
22
24
  getPreviewIdentityEpoch: () => number;
23
- setStoryboardBaselineEnvironment: (environment?: import("./designImport.js").StoryboardEnvironment) => void;
24
- getStoryboardBaselineEnvironment: () => import("./designImport.js").StoryboardEnvironment | undefined;
25
+ setStoryboardBaselineEnvironment: (environment?: StoryboardEnvironment) => void;
26
+ getStoryboardBaselineEnvironment: () => StoryboardEnvironment | undefined;
25
27
  setPreviewEnvironmentControls: (next: readonly import("./previewEnvironmentControls.js").PreviewEnvironmentControlDef[]) => void;
26
28
  getPreviewEnvironmentControls: () => readonly import("./previewEnvironmentControls.js").PreviewEnvironmentControlDef[];
27
29
  getPreviewEnvironmentControlSelections: () => Readonly<Record<string, string>>;
28
30
  getPreviewEnvironmentControlValue: (controlId: string) => string | undefined;
29
31
  setPreviewEnvironmentControlValue: (controlId: string, value: string) => void;
30
32
  clearPreviewEnvironmentControlValues: () => void;
31
- getPreviewEnvironmentOverride: () => import("./designImport.js").StoryboardEnvironment | undefined;
33
+ getPreviewEnvironmentOverride: () => StoryboardEnvironment | undefined;
32
34
  subscribePreviewEnvironmentControls: (listener: () => void) => () => void;
33
35
  getPreviewEnvironmentControlRevision: () => number;
36
+ isPageInSelectedConditions: (page: {
37
+ runtimes?: readonly string[];
38
+ conditions?: ScreenConditionDeclaration;
39
+ }) => boolean;
40
+ setConditionAxes: (next: readonly import("./conditionAxes.js").CatalogConditionAxisDef[]) => void;
41
+ getConditionAxes: () => readonly import("./conditionAxes.js").CatalogConditionAxisDef[];
42
+ getConditionAxisValue: (axisId: string) => string | null | undefined;
43
+ getConditionAxisSelections: () => import("./conditionAxes.js").CatalogConditionSelections;
44
+ selectConditionAxisValue: (axisId: string, value: string | null) => void;
45
+ clearConditionAxisSelections: () => void;
46
+ getConditionAxesEnvironment: () => StoryboardEnvironment | undefined;
47
+ isInSelectedConditions: (conditions: ScreenConditionDeclaration | undefined) => boolean;
48
+ conditionDeclarationIssues: (conditions: ScreenConditionDeclaration | undefined) => string[];
49
+ subscribeConditionAxes: (listener: () => void) => () => void;
50
+ getConditionAxesRevision: () => number;
34
51
  setSessionPresets: (next: readonly import("./sessionPresets.js").SessionPresetDef[]) => void;
35
52
  getSessionPresets: () => import("./sessionPresets.js").SessionPresetDef[];
36
53
  getSelectedSessionPreset: () => number | null;
@@ -258,6 +258,12 @@ export interface DesignImportPage {
258
258
  * runtime — only the screens a runtime cannot reach at all need to say so.
259
259
  */
260
260
  runtimes?: readonly string[];
261
+ /**
262
+ * Values, per condition axis id, this screen exists under. An absent axis
263
+ * means every value of it; unknown ids or values hide the screen and are
264
+ * reported as declaration issues rather than passing silently.
265
+ */
266
+ conditions?: Readonly<Record<string, readonly string[]>>;
261
267
  scenarioId?: string;
262
268
  /**
263
269
  * Every scenario this screen demonstrates. Coverage is the whole set; the
@@ -400,6 +406,12 @@ export interface DesignImportInitialPage {
400
406
  * runtime — only the screens a runtime cannot reach at all need to say so.
401
407
  */
402
408
  runtimes?: readonly string[];
409
+ /**
410
+ * Values, per condition axis id, this screen exists under. An absent axis
411
+ * means every value of it; unknown ids or values hide the screen and are
412
+ * reported as declaration issues rather than passing silently.
413
+ */
414
+ conditions?: Readonly<Record<string, readonly string[]>>;
403
415
  scenarioId?: string;
404
416
  /** Every authored scenario this initial screen demonstrates. */
405
417
  scenarioIds?: readonly string[];
@@ -7,6 +7,7 @@ import type { FrameBranchKindDef, FrameLabelLabels } from './frameLabels.js';
7
7
  import type { ScreenLaneDef } from './frameLanes.js';
8
8
  import { type ScreenStateAxisDef } from './interactiveStates.js';
9
9
  import type { PreviewEnvironmentControlDef } from './previewEnvironmentControls.js';
10
+ import type { CatalogConditionAxisDef } from './conditionAxes.js';
10
11
  import type { RegistryEntry } from './registry.js';
11
12
  import type { ScenarioCoverageClaim } from './scenarioCoverage.js';
12
13
  import type { ScreenCardDef } from './screenCards.js';
@@ -55,6 +56,8 @@ export interface PygmalionRevisionCatalogV1 {
55
56
  viewportPresets?: readonly ViewportPresetDef[];
56
57
  sessionPresets?: readonly SessionPresetDef[];
57
58
  previewEnvironmentControls?: readonly PreviewEnvironmentControlDef[];
59
+ /** Independent catalog conditions every screen, capture and run resolves under. */
60
+ conditionAxes?: readonly CatalogConditionAxisDef[];
58
61
  screenFlows?: readonly ScreenFlowPath[];
59
62
  scenarioCoverage?: readonly ScenarioCoverageClaim[];
60
63
  screenDimensions?: readonly ScreenDimensionDef[];
@@ -4,6 +4,7 @@ import type { FrameBranchKindDef, FrameLabelLabels } from './frameLabels.js';
4
4
  import type { ScreenLaneDef } from './frameLanes.js';
5
5
  import type { ScreenStateAxisDef } from './interactiveStates.js';
6
6
  import type { PreviewEnvironmentControlDef } from './previewEnvironmentControls.js';
7
+ import type { CatalogConditionAxisDef } from './conditionAxes.js';
7
8
  import type { ComponentRegistry, RegistryEntry } from './registry.js';
8
9
  import type { ScenarioCoverageClaim } from './scenarioCoverage.js';
9
10
  import type { ScreenCardDef } from './screenCards.js';
@@ -27,6 +28,7 @@ export interface RevisionCatalogDeclarations {
27
28
  viewportPresets?: readonly ViewportPresetDef[];
28
29
  sessionPresets?: readonly SessionPresetDef[];
29
30
  previewEnvironmentControls?: readonly PreviewEnvironmentControlDef[];
31
+ conditionAxes?: readonly CatalogConditionAxisDef[];
30
32
  screenFlows?: readonly ScreenFlowPath[];
31
33
  scenarioCoverage?: readonly ScenarioCoverageClaim[];
32
34
  screenDimensions?: readonly ScreenDimensionDef[];
@@ -205,6 +205,12 @@ export interface PageModel {
205
205
  * a runtime cannot reach at all need to say so.
206
206
  */
207
207
  runtimes?: readonly string[];
208
+ /**
209
+ * Values, per condition axis id, this screen exists under. An absent axis
210
+ * means every value of it; unknown ids or values hide the screen and are
211
+ * reported as declaration issues rather than passing silently.
212
+ */
213
+ conditions?: Readonly<Record<string, readonly string[]>>;
208
214
  scenarioId?: string;
209
215
  /** Every scenario the screen demonstrates; coverage counts this set. */
210
216
  scenarioIds?: readonly string[];
@@ -2,6 +2,11 @@ import type { StoryboardEnvironment } from './designImport.js';
2
2
  export declare const STORYBOARD_ENVIRONMENT_QUERY: "__pygmalion_environment";
3
3
  export declare const STORYBOARD_ENVIRONMENT_CONTROL: "/__pygmalion-storyboard/environment";
4
4
  export declare function mergeStoryboardEnvironment(base?: StoryboardEnvironment, override?: StoryboardEnvironment): StoryboardEnvironment | undefined;
5
+ /**
6
+ * Drops record keys the merge left empty so a composed environment reads, and
7
+ * hashes, the same as one declared directly. `undefined` when nothing remains.
8
+ */
9
+ export declare function compactStoryboardEnvironment(environment?: StoryboardEnvironment): StoryboardEnvironment | undefined;
5
10
  /**
6
11
  * Boot-time environment derived from a screen preset — parity with the Node
7
12
  * capture runtime's init script, which installs the preset global and seeds
@@ -174,6 +174,8 @@ export { SourceRefControl } from './ui/SourceRefControl.js';
174
174
  export type { SourceRefControlProps } from './ui/SourceRefControl.js';
175
175
  export type { TokenDef } from './editor/tokens.js';
176
176
  import type { SessionPresetDef } from './editor/sessionPresets.js';
177
+ import type { CatalogConditionAxisDef } from './editor/conditionAxes.js';
178
+ export type { CatalogConditionAxisDef, CatalogConditionAxisOptionDef, CatalogConditionSelections, ScreenConditionDeclaration, } from './editor/conditionAxes.js';
177
179
  export type { ViewportPresetDef } from './editor/viewportPresets.js';
178
180
  export type { SessionPresetDef } from './editor/sessionPresets.js';
179
181
  export { GENERIC_ASSERTION_SHARE, MIN_UNVERIFIED_REASON_LENGTH, detectStateGroupCandidates, hooksInSelector, summarizeConditionCoverage, validateHookTargeting, validateScreenConformance, } from './editor/screenConformance.js';
@@ -237,6 +239,13 @@ export interface PygmalionEditorProps {
237
239
  sessionPresets?: readonly SessionPresetDef[];
238
240
  /** Host-declared browser conditions shown in the active frame's Preview inspector. */
239
241
  previewEnvironmentControls?: readonly PreviewEnvironmentControlDef[];
242
+ /**
243
+ * Independent catalog conditions — a color scheme, an account level — that
244
+ * every screen, capture and run resolves under. Screens name the values they
245
+ * exist in through `conditions`; an option's environment joins the storyboard
246
+ * baseline so captures re-resolve when the value changes.
247
+ */
248
+ conditionAxes?: readonly CatalogConditionAxisDef[];
240
249
  /** A public importer that provides unified control over code inventory and importing of entire DOM layers. */
241
250
  designImport?: DesignImportController;
242
251
  /** Called with cumulative changes when editing a token in the Assets panel — the host is responsible for writing back (file saving). */
@@ -8,6 +8,43 @@ export interface VariableBinding {
8
8
  }
9
9
  export type VariableBindings = Record<string, VariableBinding>;
10
10
  export type VariableValueCodec = (library: TokenLibraryDocument, resolved: TokenValueResolution) => VariableScalar;
11
+ export type VariableModeProvider = {
12
+ kind: 'binding';
13
+ } | {
14
+ kind: 'node';
15
+ nodeId: string;
16
+ } | {
17
+ kind: 'instance';
18
+ instanceId: string;
19
+ overrideAddress: string;
20
+ } | {
21
+ kind: 'default';
22
+ };
23
+ export interface VariableModeResolution {
24
+ collectionId: string;
25
+ /** The requested mode, even when an alias is authored in a fallback mode. */
26
+ modeId: string;
27
+ provider: VariableModeProvider;
28
+ visitedNodeIds: readonly string[];
29
+ }
30
+ export interface VariableInstanceAddress {
31
+ instanceId: string;
32
+ overrideAddress: string;
33
+ }
34
+ export type VariableOccurrenceAddress = {
35
+ nodeId: string;
36
+ } | VariableInstanceAddress;
37
+ export interface VariableOccurrencePlan {
38
+ address: VariableOccurrenceAddress;
39
+ property: VariableTarget;
40
+ binding: VariableBinding;
41
+ mode: VariableModeResolution;
42
+ resolved: TokenValueResolution;
43
+ value: VariableScalar;
44
+ before: DocumentValue | undefined;
45
+ /** Literal projection only. Binding identity and transaction ownership stay with the caller. */
46
+ patch: DocumentNodePatch;
47
+ }
11
48
  export interface VariableChange {
12
49
  nodeId: string;
13
50
  overrideAddress?: string;
@@ -50,8 +87,15 @@ export declare function isVariableBinding(value: unknown): value is VariableBind
50
87
  export declare function nodeVariableBindings(node: Pick<DocumentNode, 'properties'>): VariableBindings;
51
88
  /** Built-in values are JSON scalars. Other syntax remains the host codec's responsibility. */
52
89
  export declare function resolveScalarVariable(library: TokenLibraryDocument, resolved: TokenValueResolution, seen?: Set<string>): VariableScalar;
90
+ export declare function resolveVariableModeForNode(document: DesignDocument, nodeId: string, library: TokenLibraryDocument, tokenId: string, explicit?: string): VariableModeResolution;
53
91
  export declare function variableModeForNode(document: DesignDocument, nodeId: string, library: TokenLibraryDocument, tokenId: string, explicit?: string): string;
92
+ /** Resolves an opaque override address through the actual component resolver. */
93
+ export declare function resolveVariableModeForInstance(document: DesignDocument, address: VariableInstanceAddress, library: TokenLibraryDocument, binding: VariableBinding): VariableModeResolution;
54
94
  export declare function variableTargetsForNode(node: DocumentNode): VariableTarget[];
95
+ /** Override projection stays sparse; unrelated inherited properties never become local overrides. */
96
+ export declare function projectVariableScalar(node: DocumentNode, property: VariableTarget, value: VariableScalar, placement: 'own' | 'override'): DocumentNodePatch;
97
+ /** Reads one occurrence without refreshing unrelated nodes or changing either document. */
98
+ export declare function planVariableOccurrence(document: DesignDocument, address: VariableOccurrenceAddress, property: VariableTarget, library: TokenLibraryDocument, codec?: VariableValueCodec): VariableOccurrencePlan;
55
99
  export declare function bindVariablePatch(document: DesignDocument, nodeId: string, property: VariableTarget, library: TokenLibraryDocument, binding: VariableBinding, codec?: VariableValueCodec): DocumentNodePatch;
56
100
  export declare function detachVariablePatch(node: DocumentNode, property: VariableTarget): DocumentNodePatch;
57
101
  /** A refresh plan records all affected nodes before the caller commits one history entry. */
@@ -1,7 +1,7 @@
1
1
  import type { EditorDeclarations } from '../editor/declarations.js';
2
2
 
3
3
  export interface WorkspaceConditionsProps {
4
- declarations: Pick<EditorDeclarations, 'getSessionPresets' | 'getSelectedSessionPreset' | 'selectSessionPreset' | 'subscribeSessionPresets' | 'getPreviewEnvironmentControls' | 'getPreviewEnvironmentControlValue' | 'getPreviewEnvironmentControlSelections' | 'setPreviewEnvironmentControlValue' | 'clearPreviewEnvironmentControlValues' | 'subscribePreviewEnvironmentControls' | 'getPreviewEnvironmentControlRevision'>;
4
+ declarations: Pick<EditorDeclarations, 'getSessionPresets' | 'getSelectedSessionPreset' | 'selectSessionPreset' | 'subscribeSessionPresets' | 'getConditionAxes' | 'getConditionAxisValue' | 'getConditionAxisSelections' | 'selectConditionAxisValue' | 'clearConditionAxisSelections' | 'subscribeConditionAxes' | 'getConditionAxesRevision' | 'getPreviewEnvironmentControls' | 'getPreviewEnvironmentControlValue' | 'getPreviewEnvironmentControlSelections' | 'setPreviewEnvironmentControlValue' | 'clearPreviewEnvironmentControlValues' | 'subscribePreviewEnvironmentControls' | 'getPreviewEnvironmentControlRevision'>;
5
5
  }
6
6
  /** Present declared catalog sessions and preview values without interpreting product policy. */
7
7
  export declare function WorkspaceConditions({ declarations }: WorkspaceConditionsProps): import("react").JSX.Element | null;
@@ -1,10 +1,14 @@
1
1
  import type { DesignDocument, DocumentEngineOptions, DocumentTransaction } from '../../document/contracts.js';
2
+ import type { ProjectedDocumentNode } from './projection.js';
2
3
  import type { DataProjection } from '../../binding/preview.js';
3
4
 
4
- export declare function ArrangeLayers({ document, selected, projection, preflight, act, compact }: {
5
+ export declare function ArrangeLayers({ document, selected, projection, scene, visibleRootIds, isGeometryCurrent, preflight, act, compact }: {
5
6
  document: DesignDocument;
6
7
  selected: readonly string[];
7
8
  projection: DataProjection | null;
9
+ scene?: ProjectedDocumentNode;
10
+ visibleRootIds?: readonly string[];
11
+ isGeometryCurrent?: () => boolean;
8
12
  compact?: boolean;
9
13
  preflight?: DocumentEngineOptions['preflight'];
10
14
  act(label: string, apply: (transaction: DocumentTransaction) => void): boolean;
@@ -1,13 +1,17 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { WorkspaceCamera } from '../contracts.js';
3
+ import { type ProjectedDocumentNode } from './projection.js';
3
4
  import type { DesignDocument, DocumentNode, DocumentTransaction } from '../../document/contracts.js';
4
5
 
5
6
  type Act = (label: string, apply: (transaction: DocumentTransaction) => void) => unknown;
6
7
  /** 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 }: {
8
+ export declare function CanvasGuides({ document, selected, projection, scene, geometryKey, isGeometryCurrent, camera, zoom: suppliedZoom, act, width, height, visibleRootIds }: {
8
9
  document: DesignDocument;
9
10
  selected?: readonly string[];
10
11
  projection?: DataProjection | null;
12
+ scene?: ProjectedDocumentNode;
13
+ geometryKey?: string;
14
+ isGeometryCurrent?: () => boolean;
11
15
  camera?: WorkspaceCamera;
12
16
  zoom?: number;
13
17
  act: Act;
@@ -1,3 +1,4 @@
1
+ import type { ProjectedDocumentNode } from './projection.js';
1
2
  import type { DataProjection } from '../../binding/preview.js';
2
3
  import type { DesignDocument, DocumentTransaction } from '../../document/contracts.js';
3
4
  import { type PrototypeConnectionSelection } from './prototypeWiringModel.js';
@@ -8,6 +9,9 @@ export interface PrototypeWiringProps {
8
9
  selected: readonly string[];
9
10
  projection: DataProjection | null;
10
11
  zoom: number;
12
+ scene?: ProjectedDocumentNode;
13
+ geometryKey?: string;
14
+ isGeometryCurrent?: () => boolean;
11
15
  visibleRootIds?: readonly string[];
12
16
  selectedConnection: PrototypeConnectionSelection | null;
13
17
  onSelectConnection(value: PrototypeConnectionSelection | null): void;
@@ -1,5 +1,6 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { DesignDocument, DocumentTransaction } from '../../document/contracts.js';
3
+ import type { ProjectedDocumentNode } from './projection.js';
3
4
  import { type LayerPlacement, type SnapGuide } from './geometryHandles.js';
4
5
 
5
6
  type Act = (label: string, apply: (transaction: DocumentTransaction) => void) => boolean;
@@ -11,6 +12,11 @@ export interface SelectionHandlesProps {
11
12
  selected: readonly string[];
12
13
  visibleRootIds?: readonly string[];
13
14
  projection: DataProjection | null;
15
+ scene?: ProjectedDocumentNode;
16
+ /** Measurement/provider lifetime, including changes that return to the same screen. */
17
+ geometryKey?: string;
18
+ /** Synchronous owner check, captured at gesture start and checked before committing. */
19
+ isGeometryCurrent?: () => boolean;
14
20
  /** Canvas scale; handles keep a constant screen size and snapping a constant screen tolerance. */
15
21
  zoom: number;
16
22
  act: Act;
@@ -41,15 +47,17 @@ export declare const SELECTION_BOX_ID = "selection";
41
47
  * mirroring layer arrangement. The dimension badge follows the live world bounds without
42
48
  * applying its own document changes.
43
49
  */
44
- export declare function SelectionHandles({ document, selected, visibleRootIds, projection, zoom, act, movePreview, movePreviews, onPreview, onPreviewMany }: SelectionHandlesProps): import("react").JSX.Element;
50
+ export declare function SelectionHandles({ document, selected, visibleRootIds, projection, scene, geometryKey, isGeometryCurrent, zoom, act, movePreview, movePreviews, onPreview, onPreviewMany }: SelectionHandlesProps): import("react").JSX.Element;
45
51
  /**
46
52
  * Inspector section: the geometry policy for the whole selection, plus parent-relative rotation
47
53
  * in degrees and resize constraints when exactly one layer is selected.
48
54
  */
49
- export declare function LayerGeometryInspector({ document, selected, projection, act, compact }: {
55
+ export declare function LayerGeometryInspector({ document, selected, projection, scene, isGeometryCurrent, act, compact }: {
50
56
  document: DesignDocument;
51
57
  selected: readonly string[];
52
58
  projection: DataProjection | null;
59
+ scene?: ProjectedDocumentNode;
60
+ isGeometryCurrent?: () => boolean;
53
61
  act: Act;
54
62
  compact?: boolean;
55
63
  }): import("react").JSX.Element | null;
@@ -3,6 +3,7 @@ import type { DataProjection } from '../../binding/preview.js';
3
3
  import type { DesignDocument, DocumentNode, DocumentTransaction } from '../../document/contracts.js';
4
4
  import { type VectorAnchor, type VectorAnchorAddress, type VectorBooleanOperation, type VectorProperties, type VectorShape } from '../../document/vector.js';
5
5
  import { type VectorAnchorAction, type VectorAnchorActions, type VectorBooleanPlan, type VectorEditPlan, type VectorStyle, type VectorTool } from './vectorTools.js';
6
+ import type { ProjectedDocumentNode } from './projection.js';
6
7
 
7
8
  type Act = (label: string, apply: (transaction: DocumentTransaction) => void) => boolean;
8
9
  /** Box geometry a canvas gesture is previewing for one layer; the surface draws it instead of the stored path. */
@@ -13,6 +14,12 @@ export interface VectorGeometryPreview {
13
14
  export interface VectorEditingSession {
14
15
  readonly document: DesignDocument;
15
16
  readonly projection: DataProjection | null;
17
+ /** The same disposable measured scene rendered by the canvas. */
18
+ readonly scene?: ProjectedDocumentNode;
19
+ readonly geometryKey?: string;
20
+ /** Captured at gesture start and checked again before any document command. */
21
+ readonly isGeometryCurrent?: () => boolean;
22
+ readonly visibleRootIds?: readonly string[];
16
23
  readonly selection: readonly string[];
17
24
  readonly tool: VectorTool;
18
25
  setTool(tool: VectorTool): void;
@@ -42,6 +49,10 @@ export interface VectorEditingInput {
42
49
  document: DesignDocument;
43
50
  selection: readonly string[];
44
51
  projection: DataProjection | null;
52
+ scene?: ProjectedDocumentNode;
53
+ geometryKey?: string;
54
+ isGeometryCurrent?: () => boolean;
55
+ visibleRootIds?: readonly string[];
45
56
  act: Act;
46
57
  select(id: string): void;
47
58
  }
@@ -67,7 +78,7 @@ export declare function VectorNodeSurface({ node, width, height, vector }: {
67
78
  * The returned `toolbar` and `inspector` are ready to mount; the canvas mounts `VectorEditor`
68
79
  * with the same session inside the stage.
69
80
  */
70
- export declare function useVectorEditing({ document, selection, projection, act, select }: VectorEditingInput): VectorEditing;
81
+ export declare function useVectorEditing({ document, selection, projection, scene, geometryKey, isGeometryCurrent, visibleRootIds, act, select }: VectorEditingInput): VectorEditing;
71
82
  /**
72
83
  * Canvas overlay inside the scaled stage. With the pen tool it covers the stage and turns
73
84
  * clicks into anchors (a click on the first anchor closes the path, Enter finishes an open
@@ -1,6 +1,7 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { DesignDocument, DocumentNode } from '../../document/contracts.js';
3
3
  import { type VectorShape } from '../../document/vector.js';
4
+ import { type ProjectedDocumentNode } from './projection.js';
4
5
  export interface CanvasBox {
5
6
  x: number;
6
7
  y: number;
@@ -13,7 +14,11 @@ export interface CanvasEntry {
13
14
  topLevel: boolean;
14
15
  }
15
16
  export type DrawingTool = 'frame' | 'text' | VectorShape;
16
- export declare function canvasEntries(document: DesignDocument, projection: DataProjection | null, selected?: readonly string[], visibleRootIds?: readonly string[]): CanvasEntry[];
17
+ /** A selected definition descendant keeps its shared root visible without exposing inactive pages. */
18
+ export declare function selectedSharedRootIds(document: DesignDocument, selected: readonly string[]): readonly string[];
19
+ export declare function canvasEntries(document: DesignDocument, projection: DataProjection | null, selected?: readonly string[], visibleRootIds?: readonly string[], scene?: ProjectedDocumentNode): CanvasEntry[];
20
+ /** A mixed unavailable/preparing scene must not finalize a fit using partial bounds. */
21
+ export declare function canvasGeometryReady(scene: ProjectedDocumentNode): boolean;
17
22
  export declare function canvasBounds(entries: readonly CanvasEntry[]): CanvasBox;
18
23
  export declare function marqueeSelection(document: DesignDocument, entries: readonly CanvasEntry[], box: CanvasBox): readonly string[];
19
24
  export declare function drawingBox(start: {
@@ -1,6 +1,7 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { DesignDocument, DocumentDiagnostic, DocumentMatrix, DocumentNodeConstraints, DocumentTransaction } from '../../document/contracts.js';
3
3
  import { documentTransformedBounds } from '../../document/geometry.js';
4
+ import { type ProjectedDocumentNode } from './projection.js';
4
5
  /**
5
6
  * Pure geometry for the selection handles: which layers may be edited on the
6
7
  * canvas, how a handle drag becomes a new size and placement, how a rotation
@@ -36,6 +37,15 @@ export interface LayerGeometry extends LayerPlacement {
36
37
  readonly width: boolean;
37
38
  readonly height: boolean;
38
39
  };
40
+ /** Canonical sizes are retained even when the disposable scene derives an axis. */
41
+ readonly authoredSize?: {
42
+ readonly width: number;
43
+ readonly height: number;
44
+ };
45
+ readonly derivedAxes?: {
46
+ readonly width: boolean;
47
+ readonly height: boolean;
48
+ };
39
49
  readonly notes: readonly DocumentDiagnostic[];
40
50
  readonly constraints: DocumentNodeConstraints | undefined;
41
51
  /** Constraints only act inside a free-placement container that can itself be resized. */
@@ -95,6 +105,8 @@ export interface SnapResult {
95
105
  readonly guides: readonly SnapGuide[];
96
106
  }
97
107
  export interface SnapCandidateOptions {
108
+ /** The same disposable final scene used by the canvas, including measured text. */
109
+ readonly scene?: ProjectedDocumentNode;
98
110
  /** Ordinary root layers visible on the current page; undefined retains the complete scene. */
99
111
  readonly visibleRootIds?: readonly string[];
100
112
  /** Include the moving layers' own children: right for a resize, wrong for a move (the children travel along). */
@@ -226,6 +238,6 @@ export declare function snapMove(session: MoveSnapSession, delta: {
226
238
  * uses `resize` so child constraints apply, a placement change uses `move`, and a rotation
227
239
  * replaces the transform. Nothing is issued when the placement is unchanged.
228
240
  */
229
- export declare function applyLayerPlacement(transaction: DocumentTransaction, nodeId: string, before: LayerPlacement, after: LayerPlacement): boolean;
241
+ export declare function applyLayerPlacement(transaction: DocumentTransaction, nodeId: string, before: LayerPlacement & Pick<LayerGeometry, 'authoredSize' | 'derivedAxes' | 'resizeAxes'>, after: LayerPlacement): boolean;
230
242
  /** Commit every member of a selection gesture in the caller's transaction; true when any layer changed. */
231
243
  export declare function applySelectionPlacements(transaction: DocumentTransaction, layers: readonly LayerGeometry[], placements: readonly SelectionPlacement[]): boolean;
@@ -1,5 +1,6 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { DesignDocument, DocumentDiagnostic, DocumentEngineOptions, DocumentTransaction } from '../../document/contracts.js';
3
+ import { type ProjectedDocumentNode } from './projection.js';
3
4
  export type DocumentLayerArrangement = 'align-left' | 'align-center-x' | 'align-right' | 'align-top' | 'align-center-y' | 'align-bottom' | 'distribute-horizontal' | 'distribute-vertical';
4
5
  export interface DocumentLayerArrangementRequest {
5
6
  nodeIds: readonly string[];
@@ -7,6 +8,8 @@ export interface DocumentLayerArrangementRequest {
7
8
  }
8
9
  export interface DocumentLayerArrangementOptions extends Pick<DocumentEngineOptions, 'preflight'> {
9
10
  projection?: DataProjection | null;
11
+ scene?: ProjectedDocumentNode;
12
+ visibleRootIds?: readonly string[];
10
13
  }
11
14
  export interface ReadyDocumentLayerArrangement {
12
15
  readonly status: 'ready';
@@ -36,4 +39,4 @@ export type DocumentLayerArrangementPlan = ReadyDocumentLayerArrangement | {
36
39
  */
37
40
  export declare function planDocumentLayerArrangement(document: DesignDocument, request: DocumentLayerArrangementRequest, options?: DocumentLayerArrangementOptions): DocumentLayerArrangementPlan;
38
41
  /** Run as the only move batch in one live transaction; let validation errors roll it back. */
39
- export declare function applyDocumentLayerArrangement(transaction: DocumentTransaction, plan: ReadyDocumentLayerArrangement, currentDocument: DesignDocument, projection?: DataProjection | null): void;
42
+ export declare function applyDocumentLayerArrangement(transaction: DocumentTransaction, plan: ReadyDocumentLayerArrangement, currentDocument: DesignDocument, projection?: DataProjection | null, scene?: ProjectedDocumentNode): void;
@@ -1,6 +1,7 @@
1
1
  import type { BindingRuntimeScope } from '../../binding/contracts.js';
2
2
  import type { DataProjection } from '../../binding/preview.js';
3
- import type { DesignDocument, DocumentNode, DocumentResolveOptions } from '../../document/contracts.js';
3
+ import type { DesignDocument, DocumentDiagnostic, DocumentNode, DocumentResolveOptions } from '../../document/contracts.js';
4
+ import type { TextLayoutSnapshot } from '../../document/textLayout.js';
4
5
  export interface ProjectedDocumentNode {
5
6
  sourceNodeId: string;
6
7
  instanceId?: string;
@@ -9,6 +10,27 @@ export interface ProjectedDocumentNode {
9
10
  rowPath: BindingRuntimeScope['rowPath'];
10
11
  node: DocumentNode;
11
12
  children: ProjectedDocumentNode[];
13
+ /** Disposable measured geometry; never serialized into the authored document. */
14
+ textLayout?: ProjectedTextLayout;
12
15
  }
16
+ export interface ProjectedTextLayout {
17
+ readonly status: 'preparing' | 'ready' | 'unavailable' | 'failed';
18
+ readonly authoredSize: {
19
+ readonly width: number;
20
+ readonly height: number;
21
+ };
22
+ readonly derivedAxes: {
23
+ readonly width: boolean;
24
+ readonly height: boolean;
25
+ };
26
+ readonly diagnostics: readonly DocumentDiagnostic[];
27
+ readonly snapshot?: TextLayoutSnapshot;
28
+ /** Parent bounds may be fixed while unresolved layout changes its child placements. */
29
+ readonly childrenPending?: boolean;
30
+ }
31
+ /** Fixed parent bounds remain usable; only derived size or unresolved ancestor placement is refused. */
32
+ export declare function projectedGeometryDiagnostics(item: ProjectedDocumentNode, ancestors?: readonly ProjectedDocumentNode[]): readonly DocumentDiagnostic[];
33
+ /** Reuses the canonical layout solver on a disposable scene, including repeated index addresses. */
34
+ export declare function reflowProjectedDocumentScene(scene: ProjectedDocumentNode): ProjectedDocumentNode;
13
35
  /** Fixture rows affect this disposable scene only, never canonical document geometry. */
14
36
  export declare function projectDocumentScene(document: DesignDocument, data: DataProjection | null, resolveOptions?: DocumentResolveOptions, resolveRowOptions?: (rowPath: BindingRuntimeScope['rowPath']) => DocumentResolveOptions): ProjectedDocumentNode;
@@ -1,6 +1,7 @@
1
1
  import type { DataProjection } from '../../binding/preview.js';
2
2
  import type { DesignDocument, DocumentTransaction } from '../../document/contracts.js';
3
3
  import { type PrototypeAction, type PrototypeInteraction } from '../../document/prototype.js';
4
+ import { type ProjectedDocumentNode } from './projection.js';
4
5
  export type PrototypeActionPath = readonly (number | 'branches' | 'actions' | 'otherwise')[];
5
6
  export interface PrototypeConnectionSelection {
6
7
  nodeId: string;
@@ -35,7 +36,7 @@ export declare const connectionKey: (value: PrototypeConnectionSelection) => str
35
36
  /** Only explicit destination actions become wires. No flow or action is inferred. */
36
37
  export declare function prototypeConnections(document: DesignDocument): PrototypeConnection[];
37
38
  /** 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
+ export declare function planPrototypeWiring(document: DesignDocument, projection: DataProjection | null, selected?: readonly string[], visibleRootIds?: readonly string[], scene?: ProjectedDocumentNode): PrototypeWiringPlan;
39
40
  /** Builds a complete detached edit before the caller opens its single history transaction. */
40
41
  export declare function preparePrototypeConnection(document: DesignDocument, sourceId: string, destinationId: string | null, selection?: PrototypeConnectionSelection, interactionId?: string): PrototypeInteraction[];
41
42
  export declare function writePrototypeConnection(transaction: DocumentTransaction, document: DesignDocument, sourceId: string, interactions: readonly PrototypeInteraction[]): void;
@@ -0,0 +1,28 @@
1
+ import type { DataProjection } from '../../binding/preview.js';
2
+ import type { DesignDocument, DocumentDiagnostic } from '../../document/contracts.js';
3
+ import { type ProjectedDocumentNode, type ProjectedTextLayout } from './projection.js';
4
+ import type { TextLayoutRuntime } from './textLayoutRuntime.js';
5
+ export interface TextLayoutSceneOptions {
6
+ readonly scene: ProjectedDocumentNode;
7
+ readonly revisionKey: string;
8
+ readonly visibleRootIds?: readonly string[];
9
+ readonly projection?: DataProjection | null;
10
+ readonly sourceMapped?: boolean;
11
+ }
12
+ export interface TextLayoutScene {
13
+ readonly scene: ProjectedDocumentNode;
14
+ readonly status: ProjectedTextLayout['status'];
15
+ readonly diagnostics: readonly DocumentDiagnostic[];
16
+ }
17
+ /** Carries unresolved derived axes to ancestors before any asynchronous work starts. */
18
+ export declare function prepareTextLayoutScene(document: DesignDocument, options: TextLayoutSceneOptions, available?: boolean): TextLayoutScene;
19
+ /** One bounded disposable layout, shared by rendering and every geometry reader. */
20
+ export declare function measureTextLayoutScene(document: DesignDocument, options: TextLayoutSceneOptions & {
21
+ runtime: TextLayoutRuntime;
22
+ signal?: AbortSignal;
23
+ retry?: boolean;
24
+ }): Promise<TextLayoutScene>;
25
+ /** Position-only candidate validation. The caller must also retain the original scene lifetime guard. */
26
+ export declare function reuseTextLayoutScene(document: DesignDocument, options: TextLayoutSceneOptions & {
27
+ measuredScene: ProjectedDocumentNode;
28
+ }): TextLayoutScene;
@@ -0,0 +1,19 @@
1
+ import type { DocumentEngine } from '../../document/contracts.js';
2
+ import { type TextLayoutScene, type TextLayoutSceneOptions } from './textLayoutProjection.js';
3
+ import type { TextLayoutRuntime } from './textLayoutRuntime.js';
4
+ export interface UseTextLayoutOptions extends TextLayoutSceneOptions {
5
+ readonly engine: DocumentEngine;
6
+ readonly runtime?: TextLayoutRuntime | null;
7
+ readonly lifetimeKey: string;
8
+ /** Fires synchronously for target, mode, page or provider transitions, including batched round trips. */
9
+ readonly subscribeLifetime?: (invalidate: () => void) => () => void;
10
+ readonly ownerDocument?: Document;
11
+ }
12
+ export interface TextLayoutState extends TextLayoutScene {
13
+ readonly geometryKey: string;
14
+ /** Capture this function at gesture start; a later render cannot revive that geometry. */
15
+ readonly isCurrent: () => boolean;
16
+ readonly retry: () => void;
17
+ }
18
+ /** One subscription owns the disposable scene and its synchronous invalidation epoch. */
19
+ export declare function useTextLayout(options: UseTextLayoutOptions): TextLayoutState;