Describe every value kind in one table instead of spreading it over the code
A kind like colour or texture used to be spelled out in five parallel lists, its port type, its empty value, its glyph, its label and its list tag - 22 literal places for texture alone. core/properties/kinds.ts now holds one row per kind and the rest is derived from it, so adding a kind is one row. The five literal nodes collapse into literals.ts, the six kind menus into one helper. Number, Text, Boolean is now the one order everywhere; the variable and port menus used to list Boolean before Text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8a7185948d
commit
3ed8b68ecf
39 files changed
+699
-565
No files matched your search
@@ -18,33 +18,39 @@ import {
|
||||
VStack,
|
||||
type Widget,
|
||||
} from '../../ui';
|
||||
import { type FieldValue, type ListValue, type PropertyValue, textOf } from '../../core/model/Properties';
|
||||
import {
|
||||
type FieldValue,
|
||||
type ListValue,
|
||||
type PropertyValue,
|
||||
textOf,
|
||||
untag,
|
||||
} from '../../core/model/Properties';
|
||||
import { nextFieldName } from '../../core/commands/naming';
|
||||
import {
|
||||
FIELD_KINDS,
|
||||
type FieldKind,
|
||||
kindMark,
|
||||
LIST_ITEM_KINDS,
|
||||
type ListItemKind,
|
||||
} from '../../core/properties/PropertySchema';
|
||||
} from '../../core/properties/kinds';
|
||||
import {
|
||||
type ListItem,
|
||||
itemKindOf,
|
||||
itemValue,
|
||||
makeFlatItem,
|
||||
makeItem,
|
||||
structItemFields,
|
||||
structItemOf,
|
||||
} from '../../core/properties/listItems';
|
||||
import { flatDef } from '../../core/properties/PropertySchema';
|
||||
import {
|
||||
addValue,
|
||||
createField,
|
||||
type FieldContext,
|
||||
NAME_WIDTH,
|
||||
primitiveDef,
|
||||
READ_ONLY,
|
||||
removeButton,
|
||||
} from '../inspector/fieldFactory';
|
||||
import { KIND_LABELS, kindMark, markPicker } from '../inspector/variableRows';
|
||||
import { kindMenu, markPicker } from '../inspector/variableRows';
|
||||
import type { EditorState } from '../state';
|
||||
import { type ListAccess, resolveList } from './slot';
|
||||
|
||||
@@ -103,9 +109,7 @@ export class ListEditor extends VStack {
|
||||
// Built on click, not once: which kinds fit depends on the list the tab is showing.
|
||||
this.addButton.onClick = () => {
|
||||
const kinds = this.access()?.kinds ?? LIST_ITEM_KINDS;
|
||||
new Menu(
|
||||
kinds.map((kind) => ({ label: KIND_LABELS[kind], onSelect: () => this.addItem(kind) })),
|
||||
).openBelow(this.addButton);
|
||||
new Menu(kindMenu(kinds, (kind) => this.addItem(kind))).openBelow(this.addButton);
|
||||
};
|
||||
footer.add(this.addButton);
|
||||
footer.add(new Spacer(), 1);
|
||||
@@ -210,13 +214,11 @@ export class ListEditor extends VStack {
|
||||
row.add(label);
|
||||
const mark = markPicker(
|
||||
kindMark(kind),
|
||||
access.kinds
|
||||
.filter((next) => next !== kind)
|
||||
.map((next) => ({
|
||||
label: KIND_LABELS[next],
|
||||
// Through `itemValue`, so a color keeps its number when it becomes one.
|
||||
onSelect: () => this.replaceItem(access, index, makeItem(next, itemValue(item))),
|
||||
})),
|
||||
// Through `untag`, so a color keeps its number when it becomes one.
|
||||
kindMenu(
|
||||
access.kinds.filter((next) => next !== kind),
|
||||
(next) => this.replaceItem(access, index, makeItem(next, untag(item))),
|
||||
),
|
||||
);
|
||||
if (tall) mark.minHeight = Theme.rowHeight;
|
||||
row.add(mark);
|
||||
@@ -224,12 +226,12 @@ export class ListEditor extends VStack {
|
||||
else {
|
||||
const field = createField(
|
||||
this.ctx,
|
||||
primitiveDef(String(index), kind),
|
||||
itemValue(item) ?? '',
|
||||
flatDef(String(index), kind),
|
||||
untag(item) ?? '',
|
||||
access.itemHandlers(index),
|
||||
);
|
||||
addValue(row, field);
|
||||
this.setters.push((next) => field.setValue(itemValue(next) ?? ''));
|
||||
this.setters.push((next) => field.setValue(untag(next) ?? ''));
|
||||
this.rowWidgets.push(rowWidgets(mark, field.widget));
|
||||
}
|
||||
row.add(removeButton(() => access.replace(access.value.filter((_, i) => i !== index))));
|
||||
@@ -255,14 +257,14 @@ export class ListEditor extends VStack {
|
||||
line.minHeight = Theme.rowHeight;
|
||||
const fieldMark = markPicker(
|
||||
kindMark(field.kind),
|
||||
FIELD_KINDS.filter((next) => next !== field.kind).map((next) => ({
|
||||
label: KIND_LABELS[next],
|
||||
onSelect: () =>
|
||||
kindMenu(
|
||||
FIELD_KINDS.filter((next) => next !== field.kind),
|
||||
(next) =>
|
||||
this.replaceItem(access, index, {
|
||||
...bundle,
|
||||
[field.key]: makeFlatItem(next, itemValue(bundle[field.key])),
|
||||
[field.key]: makeFlatItem(next, untag(bundle[field.key])),
|
||||
}),
|
||||
})),
|
||||
),
|
||||
);
|
||||
const name = nameField(field.key, (to) => {
|
||||
if (to && to !== field.key) this.replaceItem(access, index, renamedField(bundle, field.key, to));
|
||||
@@ -271,8 +273,8 @@ export class ListEditor extends VStack {
|
||||
line.add(name);
|
||||
const sub = createField(
|
||||
this.ctx,
|
||||
primitiveDef(field.key, field.kind),
|
||||
itemValue(bundle[field.key]) ?? '',
|
||||
flatDef(field.key, field.kind),
|
||||
untag(bundle[field.key]) ?? '',
|
||||
handlers.structFieldHandlers?.(field) ?? READ_ONLY,
|
||||
);
|
||||
setters.set(field.key, addValue(line, sub));
|
||||
@@ -290,7 +292,7 @@ export class ListEditor extends VStack {
|
||||
row.add(stack, 1);
|
||||
this.setters.push((next) => {
|
||||
const now = structItemOf(next);
|
||||
for (const field of fields) setters.get(field.key)?.(itemValue(now[field.key]) ?? '');
|
||||
for (const field of fields) setters.get(field.key)?.(untag(now[field.key]) ?? '');
|
||||
});
|
||||
this.rowWidgets.push(widgets);
|
||||
}
|
||||
@@ -319,11 +321,7 @@ function nameField(key: string, rename: (next: string) => void): TextField {
|
||||
|
||||
function addFieldMenu(add: (kind: FieldKind) => void): Dropdown {
|
||||
const button = new Dropdown('+ Field', { variant: 'ghost' });
|
||||
button.onClick = () => {
|
||||
new Menu(FIELD_KINDS.map((kind) => ({ label: KIND_LABELS[kind], onSelect: () => add(kind) }))).openBelow(
|
||||
button,
|
||||
);
|
||||
};
|
||||
button.onClick = () => new Menu(kindMenu(FIELD_KINDS, add)).openBelow(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,15 +10,9 @@ import { behaviorLookup } from '../../core/model/behaviorPrograms';
|
||||
import type { ObjectRef } from '../../core/model/instance';
|
||||
import { isList, type ListValue, type PropertyValue, type StructValue } from '../../core/model/Properties';
|
||||
import { findAsset } from '../../core/model/Project';
|
||||
import { FIELD_KINDS, LIST_ITEM_KINDS, type ListItemKind } from '../../core/properties/kinds';
|
||||
import { fieldLike, type ListItem, itemLike, structItemOf } from '../../core/properties/listItems';
|
||||
import {
|
||||
FIELD_KINDS,
|
||||
LIST_ITEM_KINDS,
|
||||
type ListItemKind,
|
||||
type PropertyDef,
|
||||
schemaForAsset,
|
||||
structOf,
|
||||
} from '../../core/properties/PropertySchema';
|
||||
import { type PropertyDef, schemaForAsset, structOf } from '../../core/properties/PropertySchema';
|
||||
import { resolveAssetProps } from '../../core/properties/resolve';
|
||||
import type { FieldHandlers } from '../inspector/fieldFactory';
|
||||
import { currentProps, currentRef } from '../inspector/objectQueries';
|
||||
|
||||
Reference in new issue
Block a user