@volter/editor-game 0.5.65 → 0.5.66
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.
- package/contributions/generation.service.ts +2 -2
- package/contributions/generations.status.tsx +1 -1
- package/contributions/godot.palette.json +99 -0
- package/contributions/godot.style.ts +62 -0
- package/contributions/godot.view.ts +69 -0
- package/contributions/ingest.service.ts +3 -3
- package/contributions/play.command.ts +1 -1
- package/contributions/react/react-inspector.service.ts +2 -2
- package/contributions/scene-document.service.ts +3 -3
- package/contributions/three/component-verbs.command.ts +3 -3
- package/contributions/unity.palette.json +102 -0
- package/contributions/unity.style.ts +62 -0
- package/contributions/unity.view.ts +76 -0
- package/contributions/unreal.palette.json +105 -0
- package/contributions/unreal.style.ts +58 -0
- package/contributions/unreal.view.ts +88 -0
- package/dist-node/serving.mjs +16 -0
- package/package.json +21 -14
- package/serving/index.ts +27 -0
- package/src/asset-budget/asset-budget-model.ts +3 -3
- package/src/asset-budget/optimize-apply.ts +7 -7
- package/src/bridge/dispatch.ts +2 -2
- package/src/bridge/screenshot.ts +3 -3
- package/src/coverage/live-authoring-surface.ts +1 -1
- package/src/coverage/live-project-verbs.ts +1 -1
- package/src/coverage/native-system-coverage.ts +1 -1
- package/src/coverage/session-coverage.ts +2 -2
- package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +10 -50
- package/src/game-document/GameCaptureFrameButton.tsx +1 -1
- package/src/game-document/GamePanel.tsx +4 -4
- package/src/generation/GenerationActivity.tsx +3 -5
- package/src/generation/generation-documents.tsx +3 -3
- package/src/generation/generation-jobs.ts +1 -1
- package/src/generation/generation-presentation.ts +1 -1
- package/src/host/adapter-reach.ts +1 -1
- package/src/host/adapter-runtime-bindings.ts +1 -1
- package/src/host/api/configurations.ts +2 -2
- package/src/host/authoring/babylon-authoring-adapter.ts +2 -2
- package/src/host/authoring/contract-hierarchy-authoring.ts +1 -1
- package/src/host/authoring/contract-scenes-stories.ts +1 -1
- package/src/host/authoring/creation-site-related.ts +2 -2
- package/src/host/authoring/ephemeral-persistence.ts +1 -1
- package/src/host/authoring/gesture-persist.ts +1 -1
- package/src/host/authoring/ingest-source-persistence.ts +4 -4
- package/src/host/authoring/mount-isolated-pixi-screen.ts +1 -1
- package/src/host/authoring/pixi-authoring-adapter.ts +2 -2
- package/src/host/authoring/pixi-live-write-target.ts +3 -3
- package/src/host/authoring/pixi-still-presentation.ts +1 -1
- package/src/host/authoring/pixi-structure-history.ts +1 -1
- package/src/host/authoring/source-persistence-backend.ts +3 -3
- package/src/host/authoring/struct-write-pipe.ts +2 -2
- package/src/host/browser-transpile.ts +1 -1
- package/src/host/canvas-entry-runtime.ts +1 -1
- package/src/host/components/HeaderTelemetry.tsx +5 -12
- package/src/host/components/PixiIsolationSceneContent.tsx +8 -7
- package/src/host/components/ThreeIsolationSceneContent.tsx +2 -2
- package/src/host/components/scene-document.tsx +15 -47
- package/src/host/components/world-root-stage-binding.tsx +6 -15
- package/src/host/components/world-root-stage.ts +60 -14
- package/src/host/coverage/capability-coverage.ts +13 -1
- package/src/host/coverage/game-contract-seam-evidence.ts +1 -1
- package/src/host/coverage/project-verb-coverage.ts +2 -17
- package/src/host/coverage/system-adapter-coverage.ts +1 -1
- package/src/host/design-system-stories/fixtures/editor-runtime.tsx +9 -1
- package/src/host/document-preview-three.ts +1 -1
- package/src/host/game-module-access.ts +1 -1
- package/src/host/game-realm-page.ts +15 -7
- package/src/host/game-realm-reclaim.ts +1 -1
- package/src/host/gated-globals.ts +4 -4
- package/src/host/history/json-history-resource.ts +2 -2
- package/src/host/instance-extract-actions.ts +1 -1
- package/src/host/instance-fork-actions.ts +1 -1
- package/src/host/projection/dom.ts +2 -2
- package/src/host/projection/pixi.ts +1 -1
- package/src/host/r3f-entry-runtime.ts +1 -1
- package/src/host/react-mount-runtime.ts +1 -1
- package/src/host/realm-services.ts +1 -1
- package/src/host/roots/module-root.ts +1 -1
- package/src/host/scene-view-drawability.ts +2 -2
- package/src/host/server-log-bridge.ts +1 -1
- package/src/host/three-ingest-runtime.ts +1 -1
- package/src/host/use-active-performance-source.ts +1 -1
- package/src/ingest/active-ingest.ts +1 -1
- package/src/ingest/authoring/ingest-root-adapter.ts +5 -5
- package/src/ingest/capture-wait-report.ts +1 -1
- package/src/ingest/deferred-ingest-play.ts +5 -4
- package/src/ingest/ingest-boot-viewport.ts +4 -6
- package/src/ingest/ingest-canvas-scene-document.tsx +9 -8
- package/src/ingest/ingest-canvas-scene.ts +2 -5
- package/src/ingest/ingest-play-control.ts +3 -3
- package/src/ingest/ingest-render-debug.ts +1 -1
- package/src/ingest/ingest-siblings.ts +3 -3
- package/src/ingest/module-mode.ts +4 -5
- package/src/ingest/mount-canvas-ingest-root.ts +6 -6
- package/src/ingest/mount-coverage.ts +2 -2
- package/src/ingest/mount-dom-ingest-root.ts +5 -5
- package/src/ingest/mount-ingest-root.ts +7 -7
- package/src/ingest/mount-three-ingest-root.ts +4 -4
- package/src/ingest/unmount-ingest-root.ts +2 -2
- package/src/play/play-mode.ts +30 -16
- package/src/play/play-recording.ts +1 -1
- package/src/profiler/PerformancePanel.tsx +1 -1
- package/src/react/design-time-react-mount.ts +17 -23
- package/src/react/dom-authoring-adapter.ts +2 -2
- package/src/react/react-inspector-section.tsx +8 -8
- package/src/react/react-world-authoring-adapter.ts +20 -132
- package/src/react/story-documents/story-documents.tsx +9 -13
- package/src/react/ui-board-document.tsx +3 -4
- package/src/react/ui-component-board.ts +3 -3
- package/src/three/authoring/camera-runtime-inspector-section.tsx +1 -1
- package/src/three/authoring/constraint-inspector-section.tsx +3 -3
- package/src/three/authoring/model-asset-inspector-section.tsx +7 -11
- package/src/three/authoring/oid-source-persistence.ts +6 -6
- package/src/three/authoring/r3f-design-session.ts +21 -7
- package/src/three/authoring/r3f-source-authoring-adapter.ts +17 -17
- package/src/three/authoring/reflection-probe-inspector-section.tsx +3 -3
- package/src/three/authoring/spatial-joint-handles.ts +1 -1
- package/src/three/authoring/spatial-lod-handles.ts +1 -1
- package/src/three/authoring/spatial-particle-handles.ts +1 -1
- package/src/three/authoring/three-authoring-adapter.ts +4 -4
- package/src/three/component-verbs/extract-menu.ts +1 -1
- package/src/three/component-verbs/fork-menu.ts +1 -1
- package/src/three/component-verbs/internals-menu.ts +1 -1
- package/src/three/drei-asset-caches.ts +13 -0
- package/src/three/story-documents/three-story-documents.tsx +11 -21
- package/src/three/three-board/ThreeBoardDocument.tsx +12 -13
- package/src/three/three-board/board-scene.ts +1 -1
- package/src/three/three-board/three-component-board.ts +3 -3
- package/contributions/react/pasteboard.action.ts +0 -41
- package/contributions/xstate-behavior.action.ts +0 -42
- package/contributions/xstate-behavior.document.tsx +0 -73
- package/contributions/xstate-behavior.inspector.tsx +0 -28
- package/contributions/xstate-behavior.menu.ts +0 -23
- package/src/react/pasteboard-materialize.ts +0 -154
- package/src/xstate/XStateBehaviorSection.tsx +0 -130
- package/src/xstate/XStateMachineInspector.tsx +0 -566
- package/src/xstate/character-animation-machine.fixture.ts +0 -74
- package/src/xstate/live-behaviors.ts +0 -106
- package/src/xstate/use-live-actor-state.ts +0 -44
- package/src/xstate/xstate-graph.ts +0 -235
- package/src/xstate/xstate-layout.ts +0 -76
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* "MATERIALIZE PASTEBOARD" (queue item 4): turn the UI board's DERIVED,
|
|
3
|
-
* ephemeral auto-grid into an AUTHORED pasteboard `.tsx` — the one action the
|
|
4
|
-
* ratified design names ("ephemeral auto-grid when no file; one action
|
|
5
|
-
* materializes it"). The generated file is ordinary project source: it
|
|
6
|
-
* imports each board story's OWNER COMPONENT and places it under `<At x y>`
|
|
7
|
-
* at the position the auto-grid gave its frame, so the derived layout becomes
|
|
8
|
-
* literals a drag can then rewrite. Nothing regenerates the file afterwards —
|
|
9
|
-
* it is the project's, exactly like every `vgai add` copy.
|
|
10
|
-
*
|
|
11
|
-
* Refusals are loud and name their remedy: no open project, no storage, no
|
|
12
|
-
* pasteboard helpers (`vgai add pasteboard`), a file already at the target
|
|
13
|
-
* path, or a board with nothing on it. A story whose owner component cannot
|
|
14
|
-
* be resolved to an importable export is SKIPPED BY NAME in the returned
|
|
15
|
-
* sentence rather than emitting an import that does not compile.
|
|
16
|
-
*
|
|
17
|
-
* ## Why it is this package's
|
|
18
|
-
*
|
|
19
|
-
* Its subject is THE UI BOARD — the design-time surface `@volter/editor-game` registers
|
|
20
|
-
* a mount for (`design-time-react-mount.ts`, unit 12) — and it reads that
|
|
21
|
-
* board's own frame placements. It stayed a host file only because its one
|
|
22
|
-
* caller was a host `action-registry.ts` row; the action POINT
|
|
23
|
-
* (`@volter/editor-sdk/chrome`, `workspace.action`) is what that row becomes,
|
|
24
|
-
* and `contributions/pasteboard.action.ts` is the row now. Unit 12's header
|
|
25
|
-
* called this file "NOT the dom lane's" on the strength of that caller; the
|
|
26
|
-
* caller is what moved (WORK.md §The open-source launch item 17, the edge map
|
|
27
|
-
* in `scripts/validate-editor-closure.mjs`).
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
import { commandLine } from '@volter/editor-core/product-command';
|
|
31
|
-
import { listProjectComponents } from '@volter/editor-core/api/assets';
|
|
32
|
-
import type { ProjectComponentEntry } from '@volter/editor-core/asset-workflow/project-content';
|
|
33
|
-
import { reactStoryBoardFramePlacements } from '@volter/editor-core/authoring/react-story-board';
|
|
34
|
-
import { getProjectPreviewStories } from '@volter/editor-core/stories/story-registry';
|
|
35
|
-
import { domStoryBoardMembers } from '@volter/editor-core/stories/three-story-model';
|
|
36
|
-
import { createProjectSourceFile } from '@volter/editor-core/ui-source/source-write-backend';
|
|
37
|
-
|
|
38
|
-
export const PASTEBOARD_HELPERS_PATH = 'src/lib/pasteboard/pasteboard.tsx';
|
|
39
|
-
export const MATERIALIZED_PASTEBOARD_PATH = 'src/design/pasteboard.tsx';
|
|
40
|
-
|
|
41
|
-
/** The story's owner-module convention: `Hud.stories.tsx` → `Hud.tsx`. */
|
|
42
|
-
function storyOwnerModulePath(storyModulePath: string): string {
|
|
43
|
-
return storyModulePath.replace(/\.stories(?=\.[^.]+$)/, '');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Relative import specifier from `src/design/` to a project-relative path. */
|
|
47
|
-
function importSpecifierFromDesign(componentPath: string): string {
|
|
48
|
-
const withoutExtension = componentPath.replace(/\.[cm]?[jt]sx?$/, '');
|
|
49
|
-
return `../${withoutExtension.replace(/^src\//, '')}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function componentForOwnerModule(
|
|
53
|
-
components: readonly ProjectComponentEntry[],
|
|
54
|
-
ownerModulePath: string,
|
|
55
|
-
): ProjectComponentEntry | null {
|
|
56
|
-
const inModule = components.filter(
|
|
57
|
-
(entry) => entry.path === ownerModulePath && (entry.exported || entry.defaultExport),
|
|
58
|
-
);
|
|
59
|
-
return (
|
|
60
|
-
inModule.find((entry) => entry.defaultExport) ?? (inModule.length === 1 ? inModule[0]! : null)
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function materializePasteboard(): Promise<string> {
|
|
65
|
-
const helpers = await fetch('/__ui-source/read', {
|
|
66
|
-
method: 'POST',
|
|
67
|
-
headers: { 'Content-Type': 'application/json' },
|
|
68
|
-
body: JSON.stringify({ file: PASTEBOARD_HELPERS_PATH }),
|
|
69
|
-
});
|
|
70
|
-
if (!helpers.ok) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
`Materialize pasteboard needs the pasteboard helpers at ${PASTEBOARD_HELPERS_PATH} — ` +
|
|
73
|
-
`run ${commandLine('add pasteboard')} first.`,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
const layer = document.querySelector<HTMLElement>('[data-vgai-react-story-board="true"]');
|
|
77
|
-
const placements = reactStoryBoardFramePlacements(layer);
|
|
78
|
-
if (!placements || placements.length === 0) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
'Materialize pasteboard reads the live UI board and it has no frames — open the UI ' +
|
|
81
|
-
'document (a project with dom stories) first.',
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
const stories = domStoryBoardMembers(getProjectPreviewStories());
|
|
85
|
-
const listing = await listProjectComponents();
|
|
86
|
-
const components = listing.ok ? listing.entries : [];
|
|
87
|
-
const placed: Array<{ importLine: string; name: string; x: number; y: number }> = [];
|
|
88
|
-
const skipped: string[] = [];
|
|
89
|
-
const importsBySpecifier = new Map<string, string>();
|
|
90
|
-
for (const placement of placements) {
|
|
91
|
-
const story = stories.find((candidate) => candidate.id === placement.storyId);
|
|
92
|
-
if (!story) continue;
|
|
93
|
-
const owner = storyOwnerModulePath(story.modulePath);
|
|
94
|
-
const component = componentForOwnerModule(components, owner);
|
|
95
|
-
if (!component) {
|
|
96
|
-
skipped.push(story.label ?? story.id);
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const specifier = importSpecifierFromDesign(component.path);
|
|
100
|
-
const importLine = component.defaultExport
|
|
101
|
-
? `import ${component.name} from '${specifier}';`
|
|
102
|
-
: `import { ${component.name} } from '${specifier}';`;
|
|
103
|
-
importsBySpecifier.set(specifier, importLine);
|
|
104
|
-
placed.push({ importLine, name: component.name, x: placement.x, y: placement.y });
|
|
105
|
-
}
|
|
106
|
-
if (placed.length === 0) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
'Materialize pasteboard resolved no importable owner component for any board frame ' +
|
|
109
|
-
`(skipped: ${skipped.join(', ') || 'none'}). A story's owner module must export the ` +
|
|
110
|
-
'component its frames render.',
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
const width = Math.max(...placed.map((entry) => entry.x)) + 960;
|
|
114
|
-
const height = Math.max(...placed.map((entry) => entry.y)) + 720;
|
|
115
|
-
const body = placed
|
|
116
|
-
.map(
|
|
117
|
-
(entry) => ` <At x={${entry.x}} y={${entry.y}}>\n <${entry.name} />\n </At>`,
|
|
118
|
-
)
|
|
119
|
-
.join('\n');
|
|
120
|
-
const code = `${[...importsBySpecifier.values()].sort().join('\n')}
|
|
121
|
-
import { At, Pasteboard } from '../lib/pasteboard/pasteboard';
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Materialized from the UI board's derived auto-grid — this file is now the
|
|
125
|
-
* AUTHORED canvas: edit freely, and a drag in the editor writes each At's
|
|
126
|
-
* x/y literals right here.
|
|
127
|
-
*/
|
|
128
|
-
export default function DesignPasteboard() {
|
|
129
|
-
return (
|
|
130
|
-
<Pasteboard width={${width}} height={${height}}>
|
|
131
|
-
${body}
|
|
132
|
-
</Pasteboard>
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
`;
|
|
136
|
-
const created = await createProjectSourceFile(MATERIALIZED_PASTEBOARD_PATH, code);
|
|
137
|
-
if (!created.created) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
created.error ??
|
|
140
|
-
`${MATERIALIZED_PASTEBOARD_PATH} already exists — the pasteboard is already authored; ` +
|
|
141
|
-
'edit it directly (there is deliberately no regeneration).',
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
// The AssetBrowser owns asset-open routing; the event is its documented door.
|
|
145
|
-
window.dispatchEvent(
|
|
146
|
-
new CustomEvent('editor:open-project-asset', {
|
|
147
|
-
detail: { path: MATERIALIZED_PASTEBOARD_PATH, kind: 'source' },
|
|
148
|
-
}),
|
|
149
|
-
);
|
|
150
|
-
return (
|
|
151
|
-
`Materialized ${placed.length} frame(s) into ${MATERIALIZED_PASTEBOARD_PATH}` +
|
|
152
|
-
(skipped.length > 0 ? ` (skipped, no importable owner component: ${skipped.join(', ')})` : '')
|
|
153
|
-
);
|
|
154
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The compact **Behavior** Inspector section (§4.3): the selected entity's
|
|
3
|
-
* live machine — its id, where the actor IS, the machine's FULL state chart
|
|
4
|
-
* with the active path marked, and the way into the Behavior document.
|
|
5
|
-
*
|
|
6
|
-
* It renders ONLY when `xstate-behavior.inspector.tsx`'s `match` found a real
|
|
7
|
-
* live behavior mark on the selected node, so a template entity (no machine)
|
|
8
|
-
* never sees it.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { Button, themeVars } from '@volter/editor-sdk/widgets';
|
|
12
|
-
import {
|
|
13
|
-
subscribeXStateBehaviorInspections,
|
|
14
|
-
xstateBehaviorInspectionsVersion,
|
|
15
|
-
} from '@volter/threejs-runtime/behavior/xstate-inspection';
|
|
16
|
-
import { useSyncExternalStore } from 'react';
|
|
17
|
-
import type { AnyStateMachine, AnyStateNode } from 'xstate';
|
|
18
|
-
import { liveBehaviorFor, openBehaviorDocument } from './live-behaviors';
|
|
19
|
-
import { useLiveActorState } from './use-live-actor-state';
|
|
20
|
-
|
|
21
|
-
/** Every descendant state node of the machine (depth-first, root excluded),
|
|
22
|
-
* for the full-state-list readout below — the same direct `.states` walk
|
|
23
|
-
* `xstate-graph.ts` documents as the sanctioned traversal. */
|
|
24
|
-
function allMachineStates(machine: AnyStateMachine): AnyStateNode[] {
|
|
25
|
-
const out: AnyStateNode[] = [];
|
|
26
|
-
const visit = (node: AnyStateNode): void => {
|
|
27
|
-
for (const child of Object.values(node.states)) {
|
|
28
|
-
out.push(child);
|
|
29
|
-
visit(child);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
visit(machine.root);
|
|
33
|
-
return out;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function XStateMachineSection({ nodeId }: { nodeId: string | null }) {
|
|
37
|
-
useSyncExternalStore(
|
|
38
|
-
subscribeXStateBehaviorInspections,
|
|
39
|
-
xstateBehaviorInspectionsVersion,
|
|
40
|
-
xstateBehaviorInspectionsVersion,
|
|
41
|
-
);
|
|
42
|
-
const behavior = nodeId ? liveBehaviorFor(nodeId) : undefined;
|
|
43
|
-
const machine = behavior?.machine;
|
|
44
|
-
// Follow live transitions (re-render per snapshot) — the state list and
|
|
45
|
-
// layer readout below re-derive from each.
|
|
46
|
-
const activeIds = useLiveActorState(machine as AnyStateMachine, behavior?.actor);
|
|
47
|
-
if (!behavior || !machine || !nodeId) return null;
|
|
48
|
-
const activeIdSet = new Set(activeIds ?? []);
|
|
49
|
-
const states = allMachineStates(machine);
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
data-testid="inspector-xstate-section"
|
|
53
|
-
style={{
|
|
54
|
-
pointerEvents: 'auto',
|
|
55
|
-
padding: 8,
|
|
56
|
-
borderBottom: `1px solid ${themeVars.boundary.default}`,
|
|
57
|
-
}}
|
|
58
|
-
>
|
|
59
|
-
<div
|
|
60
|
-
style={{
|
|
61
|
-
fontSize: 11,
|
|
62
|
-
color: themeVars.content.dim,
|
|
63
|
-
textTransform: 'uppercase',
|
|
64
|
-
marginBottom: 4,
|
|
65
|
-
}}
|
|
66
|
-
>
|
|
67
|
-
Behavior
|
|
68
|
-
</div>
|
|
69
|
-
<div
|
|
70
|
-
style={{ fontSize: 11, color: themeVars.content.primary, fontWeight: 600, marginBottom: 2 }}
|
|
71
|
-
>
|
|
72
|
-
{machine.id}
|
|
73
|
-
</div>
|
|
74
|
-
<div style={{ fontSize: 10, color: themeVars.content.muted, marginBottom: 4 }}>
|
|
75
|
-
<span style={{ color: themeVars.semantic.success, fontWeight: 700 }}>●</span> Live —{' '}
|
|
76
|
-
{activeIds?.map((stateId, index) => (
|
|
77
|
-
<span key={stateId}>
|
|
78
|
-
{index > 0 && ' · '}
|
|
79
|
-
<span
|
|
80
|
-
style={{ fontFamily: themeVars.typography.mono, color: themeVars.accent.default }}
|
|
81
|
-
>
|
|
82
|
-
{stateId.startsWith(`${machine.id}.`)
|
|
83
|
-
? stateId.slice(machine.id.length + 1)
|
|
84
|
-
: stateId}
|
|
85
|
-
</span>
|
|
86
|
-
</span>
|
|
87
|
-
))}
|
|
88
|
-
</div>
|
|
89
|
-
{/* The FULL state chart, active path highlighted — the section must
|
|
90
|
-
show what the machine can do, not only where it is (owner
|
|
91
|
-
feedback, 2026-08-06). */}
|
|
92
|
-
<div data-testid="xstate-section-states" style={{ marginBottom: 6 }}>
|
|
93
|
-
{states.map((state) => {
|
|
94
|
-
const relative = state.id.startsWith(`${machine.root.id}.`)
|
|
95
|
-
? state.id.slice(machine.root.id.length + 1)
|
|
96
|
-
: state.id;
|
|
97
|
-
const depth = relative.split('.').length - 1;
|
|
98
|
-
const active = activeIdSet.has(state.id);
|
|
99
|
-
return (
|
|
100
|
-
<div
|
|
101
|
-
key={state.id}
|
|
102
|
-
data-testid={`xstate-section-state-${relative}`}
|
|
103
|
-
style={{
|
|
104
|
-
paddingLeft: 4 + depth * 12,
|
|
105
|
-
fontSize: 10,
|
|
106
|
-
lineHeight: 1.7,
|
|
107
|
-
fontFamily: themeVars.typography.mono,
|
|
108
|
-
color: active ? themeVars.accent.default : themeVars.content.muted,
|
|
109
|
-
fontWeight: active ? 700 : 400,
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
112
|
-
{active ? '● ' : '○ '}
|
|
113
|
-
{state.key}
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
116
|
-
})}
|
|
117
|
-
</div>
|
|
118
|
-
<div style={{ fontSize: 10, color: themeVars.content.dim, marginBottom: 6 }}>
|
|
119
|
-
Source: hand-authored XState TypeScript — inspect-only.
|
|
120
|
-
</div>
|
|
121
|
-
<Button
|
|
122
|
-
size="compact"
|
|
123
|
-
data-testid="xstate-open-graph"
|
|
124
|
-
onClick={() => void openBehaviorDocument(nodeId)}
|
|
125
|
-
>
|
|
126
|
-
Inspect Behavior
|
|
127
|
-
</Button>
|
|
128
|
-
</div>
|
|
129
|
-
);
|
|
130
|
-
}
|