mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 07:18:04 +08:00
58 lines
2.9 KiB
TypeScript
58 lines
2.9 KiB
TypeScript
import type { Layout, LayoutGroup, WidgetDiff, WidgetInstance } from "/wrapper/pkg/graphite_wasm_wrapper";
|
|
|
|
type UIItem = Layout | LayoutGroup | WidgetInstance[][] | WidgetInstance[] | WidgetInstance;
|
|
// Updates a widget layout based on a list of updates, giving the new layout by mutating the `layout` argument
|
|
export function patchLayout(layout: /* &mut */ Layout, diffs: WidgetDiff[]) {
|
|
diffs.forEach((update) => {
|
|
// Extract the actual content from the DiffUpdate tagged enum
|
|
const { newValue } = update;
|
|
let newContent: Layout | LayoutGroup | WidgetInstance;
|
|
if ("layout" in newValue) newContent = newValue.layout;
|
|
else if ("layoutGroup" in newValue) newContent = newValue.layoutGroup;
|
|
else if ("widget" in newValue) newContent = newValue.widget;
|
|
else throw new Error("DiffUpdate invalid");
|
|
|
|
// Find the object where the diff applies to
|
|
const diffObject = update.widgetPath.reduce((targetLayout, index: bigint): UIItem | undefined => {
|
|
const i = Number(index);
|
|
|
|
if (targetLayout && "Column" in targetLayout) return targetLayout.Column.columnWidgets[i];
|
|
if (targetLayout && "Row" in targetLayout) return targetLayout.Row.rowWidgets[i];
|
|
if (targetLayout && "Table" in targetLayout) return targetLayout.Table.tableWidgets[i];
|
|
if (targetLayout && "Section" in targetLayout) return targetLayout.Section.layout[i];
|
|
if (targetLayout && "widget" in targetLayout && "widgetId" in targetLayout) {
|
|
if ("PopoverButton" in targetLayout.widget && targetLayout.widget.PopoverButton.popoverLayout) {
|
|
return targetLayout.widget.PopoverButton.popoverLayout[i];
|
|
}
|
|
// eslint-disable-next-line no-console
|
|
console.error("Tried to index widget");
|
|
return targetLayout;
|
|
}
|
|
|
|
return targetLayout?.[i];
|
|
}, layout);
|
|
|
|
// Exit if we failed to produce a valid patch for the existing layout.
|
|
// This means that the backend assumed an existing layout that doesn't exist in the frontend. This can happen, for
|
|
// example, if a panel is destroyed in the frontend but was never cleared in the backend, so the next time the backend
|
|
// tries to update the layout, it attempts to insert only the changes against the old layout that no longer exists.
|
|
if (diffObject === undefined) {
|
|
// eslint-disable-next-line no-console
|
|
console.error("In `patchLayout`, the `diffObject` is undefined. The layout has not been updated. See the source code comment above this error for hints.");
|
|
return;
|
|
}
|
|
|
|
// If this is a list with a length, then set the length to 0 to clear the list
|
|
if ("length" in diffObject) {
|
|
diffObject.length = 0;
|
|
}
|
|
// Remove all of the keys from the old object
|
|
Object.keys(diffObject).forEach((key) => Reflect.deleteProperty(diffObject, key));
|
|
|
|
// Assign keys to the new object
|
|
// `Object.assign` works but `diffObject = update.newValue;` doesn't.
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
Object.assign(diffObject, newContent);
|
|
});
|
|
}
|