import type { ReactNode } from "react"; import type { Actor, ActionsOf, Appearance, GroupInfo, Icon, InputsOf, Mood, Shape, Spec, StateOf, Token, WorldView } from "../spec/index.ts"; export interface Self { id: string; label: string; } /** Run an action of this instance: `act("pair")`, `act("run", { host, command })`. */ export type Act = & string>(key: K, ...inputs: keyof ActionsOf[K] extends never ? [] : [InputsOf[K]>]) => void; /** What a render function for an instance receives. */ export interface NodeProps> { instance: Self; state: Readonly>; /** The display the spec gives it, to build on. */ display: Appearance; world: WorldView; /** False while looking at the past: acting does nothing then. */ live: boolean; act: Act; } /** One instance inside a group node. */ export interface Member { instance: Self; actor: string; state: unknown; display: Appearance; } /** What a render function for a group receives: its members, and the world to read them in. */ export interface GroupProps { /** The node's name: the group's, or the shared part of its members' labels ("Studio"). */ label: string; members: Member[]; /** Its members' displays, merged: their rows and tokens, the most telling mood. */ display: Appearance; world: WorldView; live: boolean; /** The member of an actor, typed: `member(Manager).state.pairings`. */ member>(actor: A): { instance: Self; state: Readonly>; display: Appearance; } | undefined; /** Run an action of one member. */ act(instance: string, key: string, inputs?: Record): void; } export interface TokenProps { token: Token; holder: Self; } export interface LinkStyle { style?: "solid" | "dashed" | "dotted"; /** Dashes that move from the one holding the link, as data would. */ flowing?: boolean; /** "owner": the colour of whose it is; or a mood. */ color?: "owner" | Mood; } /** Room a custom node takes on the map, in pixels. */ export interface Size { w: number; h: number; } export interface ActorPresentation { /** Replaces how the node is drawn; the playground still handles clicks and drops on it. */ node?: (props: NodeProps) => ReactNode; /** Opens beside the node while it returns something: a terminal, a Settings pane. */ panel?: (props: NodeProps) => ReactNode; size?: Size; } export interface GroupPresentation { render?: (props: GroupProps) => ReactNode; panel?: (props: GroupProps) => ReactNode; size?: Size; /** A few words under the name while closed: "1 code waiting". */ status?: (props: GroupProps) => string | null; } export interface Playground { readonly kind: "feynman.playground"; /** The spec's name, so the view pairs them. */ spec: string; /** Groups the playground adds, or redefines (same name as the spec's). */ groups: GroupInfo[]; group: Record; actor: Record; /** Preferred lifeline order in the sequence diagram, by scenario name. */ flowOrder: Record; token: Record ReactNode>; link: Record; } type Actors = Actor[] | Record>; interface GroupOptions extends GroupPresentation { icon?: Icon; shape?: Shape; description?: string; collapsed?: boolean; names?: string[]; } export interface PlayBuilder { /** * Show actors as one node: a list of singletons (the relay), or a record of other actors * grouped by label (`{ app: App, daemon: Axod }`: "Studio app" and "Studio daemon" are one * "Studio"). Without actors, it styles the spec's group of that name. */ group(name: string, actors: Actors, options?: GroupOptions): void; group(name: string, options: GroupOptions): void; actor>(actor: A, presentation: ActorPresentation): void; /** Set the preferred left-to-right actor order in a scenario's sequence diagram, e.g. `play.flow("Import", [Person, Worker, Artifacts])`. */ flow(scenario: string, actors: readonly (Actor | string)[]): void; /** How a token of this kind is drawn, such as a ticket. */ token(kind: string, render: (props: TokenProps) => ReactNode): void; link(kind: string, style: LinkStyle): void; } export declare function definePlayground(spec: S, body: (play: PlayBuilder) => void): Playground; /** Whether a module's default export is a playground. */ export declare function isPlayground(value: unknown): value is Playground; /** The spec's groups with the playground's added or redefined. */ export declare function groupsOf(spec: Spec, playground: Playground | null): GroupInfo[]; export {};