Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/features/inspector/InspectorPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export default function InspectorPanel() {
const renameDocument = useEditorStore((state) => state.renameDocument);
const addConnectorWaypoint = useEditorStore((state) => state.addConnectorWaypoint);
const removeLastConnectorWaypoint = useEditorStore((state) => state.removeLastConnectorWaypoint);
const materializeConnectorRoute = useEditorStore((state) => state.materializeConnectorRoute);
const setNodeArea = useEditorStore((state) => state.setNodeArea);
const bringToFront = useEditorStore((state) => state.bringToFront);
const sendToBack = useEditorStore((state) => state.sendToBack);
Expand Down Expand Up @@ -394,6 +395,7 @@ export default function InspectorPanel() {
<input type="checkbox" checked={selectedConnector.tunnel ?? false} onChange={(event) => updateConnector(selectedConnector.id, { tunnel: event.target.checked })} />
</label>
<div className="toolbar-group toolbar-group--inspector">
<button className="ui-button" onClick={() => materializeConnectorRoute()}>Edit Path</button>
<button className="ui-button" onClick={addConnectorWaypoint}>Add Bend</button>
<button className="ui-button" onClick={removeLastConnectorWaypoint} disabled={selectedConnector.waypoints.length === 0}>Remove Bend</button>
</div>
Expand Down
27 changes: 27 additions & 0 deletions src/state/useEditorStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { snapToGrid } from '@/lib/geometry/grid';
import { projectIso } from '@/lib/geometry/iso';
import { resizeRectFromHandle, type ResizeHandle } from '@/lib/geometry/resize';
import { containsArea, containsNode, containsPipe, containsText, type SelectionBounds } from '@/lib/geometry/selection';
import { buildConnectorPath } from '@/lib/geometry/routing';
import { companionPalette, hexToRgba, palette } from '@/lib/rendering/tokens';
import { cloneDocument, withCommittedHistory, type HistoryState } from '@/state/history';
import type {
Expand Down Expand Up @@ -85,6 +86,7 @@ interface EditorStore {
addConnectorWaypoint: () => void;
removeLastConnectorWaypoint: () => void;
moveConnectorWaypoint: (index: number, point: Point) => void;
materializeConnectorRoute: () => void;
resizeSelection: (handle: ResizeHandle, point: Point) => void;
selectWithinRect: (bounds: SelectionBounds, additive?: boolean) => void;
selectAtPoint: (point: Point, additive?: boolean) => void;
Expand Down Expand Up @@ -670,6 +672,31 @@ export const useEditorStore = create<EditorStore>((set, get) => ({
return { document };
});
},
materializeConnectorRoute: () => {
set((state) => {
if (state.selection.type !== 'connector' || state.selection.ids.length !== 1) {
return state;
}
const document = cloneDocument(state.document);
const connector = document.connectors.find((item) => item.id === state.selection.ids[0]);
const source = connector ? document.nodes.find((node) => node.id === connector.sourceId) : null;
const target = connector ? document.nodes.find((node) => node.id === connector.targetId) : null;
if (!connector || !source || !target) {
return state;
}
const path = buildConnectorPath(connector, source, target, document.nodes);
const intermediates = path.slice(1, -1);
if (intermediates.length === 0) {
intermediates.push({ x: (path[0].x + path[path.length - 1].x) / 2, y: (path[0].y + path[path.length - 1].y) / 2 });
}
connector.waypoints = intermediates;
return {
document,
history: withCommittedHistory(state.history, state.document),
toasts: [...state.toasts, createToast('Route converted to editable waypoints', 'success')],
};
});
},
resizeSelection: (handle, point) => {
set((state) => {
if (state.selection.ids.length !== 1 || !state.selection.type || state.selection.type === 'connector' || state.selection.type === 'text') {
Expand Down
Loading