Apply/revert buttons for overrides, container instances and child positions
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b78382bcc
commit
3379232e64
7 files changed
+544
-37
No files matched your search
@@ -22,12 +22,21 @@ export interface FieldRow {
|
||||
|
||||
export const FIELD_LABEL_WIDTH = 64;
|
||||
|
||||
/** One way of writing a changed value back to its source ("Apply to asset", "Apply to container"). */
|
||||
export interface ApplyAction {
|
||||
label: string;
|
||||
onSelect: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps one PropertySchema entry to a labelled row containing the matching widget.
|
||||
* The inspector is entirely generated through this function: adding a new property
|
||||
* kind means adding a case here, adding a property means adding a schema line.
|
||||
*
|
||||
* A modified row shows its actions at the right: ↺ resets to the base value, ↑ applies the
|
||||
* value to its source – directly with one action, via a menu (↑ ▾) with several.
|
||||
*/
|
||||
export function createFieldRow(def: PropertyDef, value: PropertyValue, handlers: FieldHandlers, onReset?: () => void): FieldRow {
|
||||
export function createFieldRow(def: PropertyDef, value: PropertyValue, handlers: FieldHandlers, onReset?: () => void, apply?: ApplyAction[]): FieldRow {
|
||||
const row = new HStack({ gap: Theme.gap, align: 'center' });
|
||||
row.minHeight = Theme.rowHeight;
|
||||
const label = new Label(def.label, { style: 'muted' });
|
||||
@@ -38,11 +47,21 @@ export function createFieldRow(def: PropertyDef, value: PropertyValue, handlers:
|
||||
row.add(field.widget, field.grow ? 1 : 0);
|
||||
if (!field.grow) row.add(new Label(''), 1);
|
||||
|
||||
let reset: Button | null = null;
|
||||
if (onReset) {
|
||||
reset = new Button('↺', { variant: 'ghost', width: Theme.controlHeight, onClick: onReset });
|
||||
reset.visible = false;
|
||||
row.add(reset);
|
||||
const actions: Button[] = [];
|
||||
if (apply && apply.length > 0) {
|
||||
const single = apply.length === 1;
|
||||
const button = new Button(single ? '↑' : '↑ ▾', { variant: 'ghost', width: single ? Theme.controlHeight : undefined });
|
||||
button.onClick = () => {
|
||||
if (single) return apply[0]!.onSelect();
|
||||
const g = button.getGlobalPosition();
|
||||
new Menu(apply.map((a) => ({ label: a.label, onSelect: a.onSelect }))).open(g.x, g.y + button.h + 2);
|
||||
};
|
||||
actions.push(button);
|
||||
}
|
||||
if (onReset) actions.push(new Button('↺', { variant: 'ghost', width: Theme.controlHeight, onClick: onReset }));
|
||||
for (const button of actions) {
|
||||
button.visible = false;
|
||||
row.add(button);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -50,8 +69,8 @@ export function createFieldRow(def: PropertyDef, value: PropertyValue, handlers:
|
||||
setValue: field.setValue,
|
||||
setModified(modified) {
|
||||
label.setStyle(modified ? 'bodyBold' : 'muted');
|
||||
if (reset && reset.visible !== modified) {
|
||||
reset.visible = modified;
|
||||
if (actions.length > 0 && actions[0]!.visible !== modified) {
|
||||
for (const button of actions) button.visible = modified;
|
||||
row.relayout();
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user