Title a collapsed Variables or Properties node by what it does

Collapsed, the node reads "Set 2 variables", "Get width" or "No properties";
expanded it is always "Variables" / "Properties". The Properties node shows
its object type (and behavior) as a line under the title instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-11 19:53:43 +02:00
1 parent 58f19a3451
commit 0376ae175d
11 files changed
+182 -69

No files matched your search

+11
View File
@@ -51,6 +51,17 @@ export function declaredOn(
return def.declaresPorts === side ? [...ports] : [];
}
/** What a collapsed Variables or Properties node does, since its ports are out of sight. */
export function collapsedTitle(ports: readonly DeclaredPort[], noun: string): string {
const set = ports.filter((p) => p.write);
const get = ports.filter((p) => !p.write);
if (set.length > 1) return `Set ${set.length} ${noun}`;
if (get.length > 1) return `Get ${get.length} ${noun}`;
if (set[0]) return `Set ${set[0].key}`;
if (get[0]) return `Get ${get[0].key}`;
return `No ${noun}`;
}
/** The single start (or end) node of a graph; a second one is ignored. */
export function terminalNode(graph: Graph, type: string): GraphNode | undefined {
return graph.nodes.find((n) => n.type === type);
+7 -7
View File
@@ -1,10 +1,10 @@
import { PROPERTIES } from '../../nested';
import { collapsedTitle, PROPERTIES } from '../../nested';
import type { NodeDef } from '../../NodeRegistry';
import {
OBJECT_BEHAVIOR_SETTING,
OBJECT_TYPE_SETTING,
propertiesTitle,
propertyPort,
propertyTargetOf,
} from '../../propertyPorts';
import { asEntity, writeTyped } from '../../values';
import { exec, obj } from '../shared';
@@ -19,13 +19,13 @@ export const Properties: NodeDef = {
inputs: [obj('object')],
outputs: [],
params: [OBJECT_TYPE_SETTING, OBJECT_BEHAVIOR_SETTING],
// The title names both ("Sprite properties", "Game properties").
hiddenParams: () => [OBJECT_TYPE_SETTING.key, OBJECT_BEHAVIOR_SETTING.key],
hiddenParams: (params) => (propertyTargetOf(params) === 'behavior' ? [] : [OBJECT_BEHAVIOR_SETTING.key]),
declaresPorts: 'both',
declaredPort: (port, node) => propertyPort(port, node.params),
derivePorts: ({ node, behaviors }) => {
const label = propertiesTitle(node, behaviors);
return (node.ports ?? []).some((p) => p.write) ? { label, inputs: [exec()], outputs: [exec()] } : { label };
derivePorts: ({ node }) => {
const ports = node.ports ?? [];
const shape = ports.some((p) => p.write) ? { inputs: [exec()], outputs: [exec()] } : {};
return node.collapsed ? { ...shape, label: collapsedTitle(ports, 'properties') } : shape;
},
read: (_ctx, _params, input) => asEntity(input('object'))?.props ?? {},
run: (_ctx, inputs, _params, def) => {
+2 -3
View File
@@ -1,4 +1,4 @@
import { portDefOf, VARIABLES } from '../../nested';
import { collapsedTitle, portDefOf, VARIABLES } from '../../nested';
import { type NodeDef, withInlineDefault } from '../../NodeRegistry';
import { writeTyped } from '../../values';
import { exec } from '../shared';
@@ -21,9 +21,8 @@ export const Variables: NodeDef = {
declaredPort: (port) => withInlineDefault(portDefOf(port)),
derivePorts: ({ node }) => {
const ports = node.ports ?? [];
const only = ports.length === 1 ? ports[0]?.key : undefined;
const shape = ports.some((p) => p.write) ? { inputs: [exec()], outputs: [exec()] } : {};
return only ? { ...shape, label: only } : shape;
return node.collapsed ? { ...shape, label: collapsedTitle(ports, 'variables') } : shape;
},
read: (ctx) => ctx.variables,
run: (ctx, inputs, _params, def) => {
+1 -9
View File
@@ -1,8 +1,7 @@
import { ASSET_TYPE_LABELS } from '../model/AssetTypes';
import { type PropertyBag, textOf } from '../model/Properties';
import { type PropertyDef, type PropertySchema, schemaFor } from '../properties/PropertySchema';
import type { DeclaredPort, GraphNode } from './Graph';
import type { BehaviorLookup } from './lookup';
import type { DeclaredPort } from './Graph';
import { portDefOf } from './nested';
import { type PortDef, withInlineDefault } from './NodeRegistry';
import { portKindOf } from './variablePorts';
@@ -63,10 +62,3 @@ export function propertyPort(port: DeclaredPort, params: PropertyBag): PortDef {
if (!field || portKindOf(field) !== port.kind) return plain;
return { ...plain, field, default: field.default };
}
export function propertiesTitle(node: GraphNode, behaviors: BehaviorLookup): string {
const target = propertyTargetOf(node.params);
if (target === 'any') return 'Properties';
const behavior = target === 'behavior' ? behaviors(textOf(node.params[OBJECT_BEHAVIOR_PARAM] ?? '')) : null;
return `${behavior?.name ?? targetLabel(target)} properties`;
}