@pygmalionjs/pygmalion 0.10.0 → 0.11.1

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.
@@ -1,5 +1,5 @@
1
- import { bW as l, T as u } from "./runtime-BOfDlGPR.js";
2
- import { bi as y, cc as b, cd as E, ce as P, be as T, as as $ } from "./runtime-BOfDlGPR.js";
1
+ import { bW as l, T as u } from "./runtime-Bxn8116i.js";
2
+ import { bi as y, cc as b, cd as E, ce as P, be as T, as as $ } from "./runtime-Bxn8116i.js";
3
3
  const v = {
4
4
  mirror: ["status", "refresh", "refs"],
5
5
  session: ["open", "check", "previewVisual", "applyVisual", "revertVisual"],
@@ -158,6 +158,16 @@ export interface ResolvedDocumentNode {
158
158
  }
159
159
  /** Optional presentation-time instance resolution; normal editing uses canonical definitions. */
160
160
  export interface DocumentResolveOptions {
161
+ /**
162
+ * Expand a source occurrence before resolving its component subtree. The
163
+ * continuation retains inherited overrides and cycle checks, skips this
164
+ * occurrence's expansion hook, and accepts callback overrides for its subtree.
165
+ * A definition root is resolved through its instance, not expanded separately.
166
+ */
167
+ expandNode?: (input: {
168
+ node: DocumentNode;
169
+ instancePath: readonly string[];
170
+ }, resolve: (options?: DocumentResolveOptions) => ResolvedDocumentNode) => readonly ResolvedDocumentNode[];
161
171
  resolveInstance?: (input: {
162
172
  node: DocumentNode;
163
173
  /** Outer-to-inner instance IDs. IDs remain opaque, including slashes. */
@@ -8,6 +8,8 @@
8
8
  * side effects a player must perform; time enters only through `now`.
9
9
  */
10
10
  import type { DesignDocument, DocumentDiagnostic, DocumentDuplicateMetadataRemapper, DocumentNode, DocumentResolveOptions, DocumentTransaction, ResolvedDocumentNode } from './contracts.js';
11
+ import type { PrototypeOccurrence, PrototypeRowPath } from './prototypeOccurrence.js';
12
+ export type { PrototypeOccurrence, PrototypeRowPath } from './prototypeOccurrence.js';
11
13
  export declare const PROTOTYPE_METADATA_KEY = "prototype";
12
14
  export declare const PROTOTYPE_INTERACTIONS_PROPERTY = "interactions";
13
15
  /** Upper bound for an authored transition in this player. */
@@ -252,14 +254,28 @@ export interface PrototypeSceneLayer {
252
254
  fill: string | null;
253
255
  node: DocumentNode;
254
256
  depth: number;
257
+ occurrence?: PrototypeOccurrence;
258
+ }
259
+ export interface PrototypeResolvedSceneNode extends Omit<ResolvedDocumentNode, 'children'> {
260
+ rowPath: PrototypeRowPath;
261
+ instancePath?: readonly string[];
262
+ children: PrototypeResolvedSceneNode[];
263
+ }
264
+ /** Supplies the same expanded scene used by the rendering surface, without owning authoring data. */
265
+ export interface PrototypeRuntimeContext {
266
+ resolveScene(document: DesignDocument, state: PrototypeState, rootId: string, sceneId: string): PrototypeResolvedSceneNode;
255
267
  }
256
268
  /** Stable occurrence key. Every ID is opaque; nested instances never share canonical state. */
257
- export declare function prototypeVariantKey(instancePath: readonly string[]): string;
269
+ export declare function prototypeVariantKey(instancePath: readonly string[], occurrence?: PrototypeOccurrence): string;
258
270
  /** Presentation-only variant resolution; neither the document nor shared definitions are changed. */
259
- export declare function prototypeResolveOptions(document: DesignDocument, variants: Readonly<Record<string, string>>): DocumentResolveOptions;
271
+ export declare function prototypeResolveOptions(document: DesignDocument, variants: Readonly<Record<string, string>>, occurrence?: PrototypeOccurrence): DocumentResolveOptions;
260
272
  /** Resolves runtime variants explicitly; invalid choices never silently render canonical state. */
261
273
  export declare function resolvePrototypeScene(document: DesignDocument, rootId: string, variants?: Readonly<Record<string, string>>): ResolvedDocumentNode;
262
- export declare function prototypeSceneLayers(document: DesignDocument, rootId: string, variants?: Readonly<Record<string, string>>): PrototypeSceneLayer[];
274
+ export declare function prototypeSceneLayers(document: DesignDocument, rootId: string, variants?: Readonly<Record<string, string>>, options?: {
275
+ state: PrototypeState;
276
+ sceneId?: string;
277
+ context?: PrototypeRuntimeContext;
278
+ }): PrototypeSceneLayer[];
263
279
  export interface PrototypeSmartAnimatePair {
264
280
  name: string;
265
281
  from: PrototypeSceneLayer;
@@ -301,6 +317,7 @@ export type PrototypeRevert = {
301
317
  export interface PrototypeHold {
302
318
  nodeId: string;
303
319
  trigger: 'hover' | 'press';
320
+ occurrence?: PrototypeOccurrence;
304
321
  /** Screen-space bounds of the hotspot when the hold began; a surface keeps it hit-testable across navigation. */
305
322
  bounds: {
306
323
  sceneId: string;
@@ -327,7 +344,7 @@ export interface PrototypeState {
327
344
  history: string[];
328
345
  overlays: PrototypeOverlayState[];
329
346
  variables: Record<string, PrototypeValue>;
330
- /** Runtime variant choices keyed by prototypeVariantKey(outer-to-inner instance path). */
347
+ /** Runtime variant choices keyed by the authored instance path and optional scene/row occurrence. */
331
348
  variants: Record<string, string>;
332
349
  scroll: Record<string, {
333
350
  x: number;
@@ -338,6 +355,7 @@ export interface PrototypeState {
338
355
  targetId: string;
339
356
  transition: PrototypeTransition;
340
357
  at: number;
358
+ occurrence?: PrototypeOccurrence;
341
359
  } | null;
342
360
  timers: PrototypeTimer[];
343
361
  holds: PrototypeHold[];
@@ -352,6 +370,7 @@ export type PrototypeEvent =
352
370
  {
353
371
  type: PrototypePointerEventType;
354
372
  path: readonly string[];
373
+ occurrence?: PrototypeOccurrence;
355
374
  } | {
356
375
  type: 'key';
357
376
  key: string;
@@ -397,6 +416,7 @@ export type PrototypeEffect = {
397
416
  sceneId: string;
398
417
  targetId: string;
399
418
  transition: PrototypeTransition;
419
+ occurrence?: PrototypeOccurrence;
400
420
  } | {
401
421
  type: 'open-url';
402
422
  url: string;
@@ -415,10 +435,11 @@ export interface PrototypeStartOptions {
415
435
  flowId?: string | null;
416
436
  startingNodeId?: string;
417
437
  now?: number;
438
+ context?: PrototypeRuntimeContext;
418
439
  }
419
440
  /** The initial state of a flow (or of an explicit starting screen); delay triggers on the screen are armed. */
420
441
  export declare function createPrototypeState(document: DesignDocument, options?: PrototypeStartOptions): PrototypeState;
421
442
  /** The earliest moment the state changes without input, or null when it is at rest. */
422
443
  export declare function prototypeNextDeadline(state: PrototypeState): number | null;
423
444
  /** One pure step: the event (or the passage of time) against a frozen document; time is `now`. */
424
- export declare function stepPrototype(document: DesignDocument, previous: PrototypeState, event: PrototypeEvent, now: number): PrototypeStepResult;
445
+ export declare function stepPrototype(document: DesignDocument, previous: PrototypeState, event: PrototypeEvent, now: number, runtime?: PrototypeRuntimeContext): PrototypeStepResult;
@@ -0,0 +1,18 @@
1
+ /** A stable row address, ordered from the outer repeat to the inner repeat. */
2
+ export type PrototypeRowPath = readonly {
3
+ repeatId: string;
4
+ key: string | number;
5
+ }[];
6
+ /** A rendered occurrence. Overlay scene IDs distinguish separate openings of one screen. */
7
+ export interface PrototypeOccurrence {
8
+ sceneId: string;
9
+ rowPath: PrototypeRowPath;
10
+ }
11
+ export declare function prototypeOccurrenceValid(value: unknown): value is PrototypeOccurrence;
12
+ export declare function prototypeRowPathPrefix(prefix: PrototypeRowPath, path: PrototypeRowPath): boolean;
13
+ export declare function prototypeOccurrenceEqual(left: PrototypeOccurrence | undefined, right: PrototypeOccurrence | undefined): boolean;
14
+ export declare function encodePrototypeVariantKey(instancePath: readonly string[], occurrence?: PrototypeOccurrence): string;
15
+ export declare function decodePrototypeVariantKey(key: string): {
16
+ instancePath: string[];
17
+ occurrence?: PrototypeOccurrence;
18
+ } | null;
@@ -424,3 +424,5 @@ export { PrototypePanel } from './workspace/edit/PrototypePanel.js';
424
424
  export { PrototypePlayer } from './workspace/view/PrototypePlayer.js';
425
425
  export type { PrototypePlayerProps } from './workspace/view/PrototypePlayer.js';
426
426
  export * from './workspace/view/prototypePlayback.js';
427
+ export { createPrototypeProjectionContext } from './workspace/edit/prototypeProjection.js';
428
+ export type { PrototypeProjectionContext } from './workspace/edit/prototypeProjection.js';
@@ -22,7 +22,7 @@ export interface PasteDesignResult {
22
22
  nodeIds: Record<string, string>;
23
23
  }
24
24
  /** Pure paste plan; commit the returned same-identity snapshot as one undoable transaction. */
25
- export declare function pasteDesignSubtrees(target: DesignDocument, payload: DesignClipboard, options: {
25
+ export declare function pasteDesignSubtrees(targetInput: DesignDocument, payloadInput: DesignClipboard, options: {
26
26
  parentId: string;
27
27
  allocateId: (sourceId: string) => string;
28
28
  offset?: {
@@ -9,4 +9,4 @@ export interface ProjectedDocumentNode {
9
9
  children: ProjectedDocumentNode[];
10
10
  }
11
11
  /** Fixture rows affect this disposable scene only, never canonical document geometry. */
12
- export declare function projectDocumentScene(document: DesignDocument, data: DataProjection | null, resolveOptions?: DocumentResolveOptions): ProjectedDocumentNode;
12
+ export declare function projectDocumentScene(document: DesignDocument, data: DataProjection | null, resolveOptions?: DocumentResolveOptions, resolveRowOptions?: (rowPath: BindingRuntimeScope['rowPath']) => DocumentResolveOptions): ProjectedDocumentNode;
@@ -0,0 +1,7 @@
1
+ import type { DataProjection } from '../../binding/preview.js';
2
+ import type { PrototypeRuntimeContext } from '../../document/prototype.js';
3
+ export interface PrototypeProjectionContext extends PrototypeRuntimeContext {
4
+ readonly projection: DataProjection | null;
5
+ }
6
+ /** One captured data projection supplies runtime hit testing, layout and presentation rendering. */
7
+ export declare function createPrototypeProjectionContext(data: DataProjection | null): PrototypeProjectionContext;
@@ -1,16 +1,17 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { DesignDocument } from '../../document/contracts.js';
3
- import { type PrototypeState } from '../../document/prototype.js';
3
+ import { type PrototypeRuntimeContext, type PrototypeState } from '../../document/prototype.js';
4
4
  import { type PrototypeClock } from './prototypePlayback.js';
5
5
 
6
6
  export interface PrototypePlayerProps {
7
7
  document: DesignDocument;
8
8
  /** Uses the same document/component renderer as Edit, with authoring controls disabled. */
9
- renderScene(rootId: string, state: PrototypeState): ReactNode;
10
- sceneSize?(rootId: string, state: PrototypeState): {
9
+ renderScene(rootId: string, state: PrototypeState, sceneId?: string): ReactNode;
10
+ sceneSize?(rootId: string, state: PrototypeState, sceneId?: string): {
11
11
  width: number;
12
12
  height: number;
13
13
  } | undefined;
14
+ context?: PrototypeRuntimeContext;
14
15
  onClose(): void;
15
16
  clock?: PrototypeClock;
16
17
  }
@@ -1,5 +1,5 @@
1
1
  import type { DesignDocument, DocumentNode, ResolvedDocumentNode } from '../../document/contracts.js';
2
- import { type PrototypeEffect, type PrototypeEvent, type PrototypeStartOptions, type PrototypeState } from '../../document/prototype.js';
2
+ import { type PrototypeEffect, type PrototypeEvent, type PrototypeRuntimeContext, type PrototypeStartOptions, type PrototypeState } from '../../document/prototype.js';
3
3
  export interface PrototypeClock {
4
4
  now(): number;
5
5
  schedule(callback: () => void, delayMs: number): unknown;
@@ -38,7 +38,7 @@ export interface PrototypePresentationScene {
38
38
  opacity: number;
39
39
  } | null;
40
40
  }
41
- export declare function prototypeScene(document: DesignDocument, state: PrototypeState): PrototypePresentationScene[];
41
+ export declare function prototypeScene(document: DesignDocument, state: PrototypeState, context?: PrototypeRuntimeContext): PrototypePresentationScene[];
42
42
  export declare function prototypeFlowOptions(document: DesignDocument): {
43
43
  id: string;
44
44
  label: string;
@@ -8,6 +8,9 @@ export interface ReconcileSourceProjection { anchors: JsxStructureAnchor[]; node
8
8
  export interface JsxSourceReconcilerOptions {
9
9
  file: string;
10
10
  identityFile: string;
11
+ /** Additional nullable inputs, captured at construction. Each requires an own input key and proof on both sides.
12
+ * Names must be unique, nonblank, and different from file. identityFile is always included and may appear once. Default: []. */
13
+ optionalInputFiles?: readonly string[];
11
14
  rootId: string;
12
15
  definitionId: string;
13
16
  screenId: string;
@@ -19,7 +19,7 @@ const sourceLayout = layout => layout ? { direction: layout.direction, gap: layo
19
19
  export function createJsxSourceReconciler({
20
20
  file, identityFile, rootId, definitionId, screenId, documentId, opaqueNodeIds,
21
21
  projectSource, resolveWrapper = () => undefined, compileDocumentSource,
22
- allowUnchangedIslandRelocation = false,
22
+ allowUnchangedIslandRelocation = false, optionalInputFiles = [],
23
23
  }) {
24
24
  if ([file, identityFile, rootId, definitionId, screenId, documentId].some(value => typeof value !== 'string' || !value)
25
25
  || file === identityFile || !Array.isArray(opaqueNodeIds) || new Set(opaqueNodeIds).size !== opaqueNodeIds.length
@@ -27,13 +27,19 @@ export function createJsxSourceReconciler({
27
27
  || ![projectSource, resolveWrapper, compileDocumentSource].every(value => typeof value === 'function')) {
28
28
  throw new TypeError('A source reconciler requires explicit files, node identities, and projection/compiler callbacks.');
29
29
  }
30
+ const optionalInputs = Array.isArray(optionalInputFiles) ? [...optionalInputFiles] : null;
31
+ if (!optionalInputs || new Set(optionalInputs).size !== optionalInputs.length
32
+ || optionalInputs.some(value => typeof value !== 'string' || !value.trim() || value === file)) {
33
+ throw new TypeError('Optional source inputs must be unique nonempty file names excluding the main source file.');
34
+ }
35
+ const nullableInputs = new Set([identityFile, ...optionalInputs]);
30
36
  opaqueNodeIds = [...opaqueNodeIds];
31
37
  function capturedInputs(value) {
32
- if (!record(value) || Object.keys(value).length > 500 || !Object.hasOwn(value, identityFile)
33
- || typeof value[file] !== 'string' || !value[file]) fail('inputs-invalid', 'Complete source and identity inputs are required.');
38
+ if (!record(value) || Object.keys(value).length > 500 || [...nullableInputs].some(inputFile => !Object.hasOwn(value, inputFile))
39
+ || typeof value[file] !== 'string' || !value[file]) fail('inputs-invalid', 'Complete source, identity, and declared optional inputs are required.');
34
40
  let size = 0;
35
41
  for (const [inputFile, content] of Object.entries(value)) {
36
- if (content === null && inputFile === identityFile) continue;
42
+ if (content === null && nullableInputs.has(inputFile)) continue;
37
43
  if (typeof content !== 'string' || Buffer.from(content).toString('utf8') !== content) fail('inputs-invalid', 'Source inputs must be UTF-8 strings.', inputFile);
38
44
  size += Buffer.byteLength(content);
39
45
  }
@@ -92,7 +98,9 @@ export function createJsxSourceReconciler({
92
98
  }
93
99
  seen.add(proof.file);
94
100
  }
95
- if (!seen.has(file) || !seen.has(identityFile)) fail('proofs-invalid', 'Source and identity proofs are both required.');
101
+ if (!seen.has(file) || [...nullableInputs].some(inputFile => !seen.has(inputFile))) {
102
+ fail('proofs-invalid', 'Source, identity, and declared optional input proofs are required.');
103
+ }
96
104
  }
97
105
  function verifyProjection(document, projection) {
98
106
  for (const node of projection.nodes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pygmalionjs/pygmalion",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Code-backed DOM design sandbox and visual QA editor",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {