Fix findUsages/undo/node-lookup bugs, split Viewport and Editor, share command and inspector helpers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-08 09:22:49 +02:00
1 parent 1eb28314cf
commit f140c2fd77
58 files changed
+1969 -1171

No files matched your search

+19 -45
View File
@@ -21,11 +21,12 @@ import type { Axis, PropertyValue } from '../../core/model/Properties';
import { findAsset, findScene, type Project } from '../../core/model/Project';
import type { SceneObject } from '../../core/model/SceneObject';
import { COMMON_PROPS, isCommonProp, type PropertyDef, schemaForAsset } from '../../core/properties/PropertySchema';
import { deviatesFromAsset, deviatesFromTemplate, isOverridden, resolveSceneObjectProps } from '../../core/properties/resolve';
import { deviatesFromAsset, deviatesFromTemplate, resolveSceneObjectProps } from '../../core/properties/resolve';
import { Button, Menu, type MenuItem, TextField } from '../../ui';
import { addCollider, createContainer, removeObjects } from '../actions';
import { createFieldRow, type FieldActions, type FieldRow, labelledRow } from './fieldFactory';
import { addGap, addNote, addTitle, type InspectorHost } from './host';
import { previewingHandlers } from './previewHandlers';
const POSITION_AXES: readonly Axis[] = ['x', 'y', 'z'];
const OFFSET_AXES = ['x', 'y'] as const;
@@ -180,32 +181,22 @@ interface ComponentSpec<V extends object> {
/**
* A number row editing one component of a vector on the object (position, editor offset).
* Scrubbing previews straight into the model; the command is built from the value before the
* preview so undo returns there, not to the last previewed frame.
* The row edits one axis, the command carries the whole vector: the other components come
* from the target after the preview was taken back, so they are the pre-preview ones.
*/
function componentRow<V extends object>(host: InspectorHost, sceneId: string, objectId: string, value: number, spec: ComponentSpec<V>): void {
let original: V | undefined;
const withAxis = (vector: V, next: PropertyValue): V => ({ ...vector, [spec.axis]: Number(next) });
const row = createFieldRow(
{ key: spec.key, label: spec.label, kind: 'number', default: 0, step: 1 },
value,
{
onInput: (next) => {
const target = currentObject(host.state, sceneId, objectId);
if (!target) return;
if (!original) original = { ...spec.read(target) };
spec.write(target, withAxis(spec.read(target), next));
host.state.preview();
},
onChange: (next) => {
const target = currentObject(host.state, sceneId, objectId);
if (!target) return;
const previous = original ?? { ...spec.read(target) };
if (original) spec.write(target, { ...original });
original = undefined;
host.state.execute(spec.command(withAxis(previous, next)));
},
},
previewingHandlers<SceneObject, V>(host, {
target: () => currentObject(host.state, sceneId, objectId),
// Copied: the snapshot outlives the scrub, the vector in the model does not.
read: (object) => ({ ...spec.read(object) }),
write: spec.write,
toModel: (next, object) => withAxis(spec.read(object), next),
commit: spec.command,
}),
spec.reset,
spec.apply,
);
@@ -224,34 +215,17 @@ function componentRow<V extends object>(host: InspectorHost, sceneId: string, ob
* the container is placed, never at draw time.
*/
function propertyRow(host: InspectorHost, sceneId: string, objectId: string, def: PropertyDef, values: Record<string, PropertyValue>): FieldRow {
let original: PropertyValue | undefined;
let hadOverride = false;
const bases = () => deviations(host.state, sceneId, objectId, def.key);
const row = createFieldRow(
def,
values[def.key] ?? def.default,
{
onInput: (value) => {
const target = currentObject(host.state, sceneId, objectId);
if (!target) return;
if (original === undefined) {
hadOverride = isOverridden(target, def.key);
original = target.overrides[def.key] ?? values[def.key] ?? def.default;
}
target.overrides[def.key] = value;
host.state.preview();
},
onChange: (value) => {
const target = currentObject(host.state, sceneId, objectId);
if (!target) return;
if (original !== undefined) {
if (hadOverride) target.overrides[def.key] = original;
else delete target.overrides[def.key];
}
original = undefined;
host.state.execute(new SetOverrideCommand(sceneId, objectId, def.key, value));
},
},
previewingHandlers<SceneObject>(host, {
target: () => currentObject(host.state, sceneId, objectId),
read: (object) => object.overrides[def.key],
write: (object, value) => (object.overrides[def.key] = value),
remove: (object) => delete object.overrides[def.key],
commit: (value) => new SetOverrideCommand(sceneId, objectId, def.key, value),
}),
() => {
const { template, asset } = bases();
return [