Улучшил работу, мелкие фиксы
This commit is contained in:
+33
-29
@@ -77,9 +77,9 @@ interface Box {
|
||||
const SNAP_THRESHOLD = 6;
|
||||
|
||||
/**
|
||||
* Compares the dragged box's edges/center against every other box on the same
|
||||
* level and, for the first close-enough match on each axis, snaps to it and
|
||||
* records a guide line to draw across the canvas.
|
||||
* Compares the dragged box's center against every other box's center on the
|
||||
* same level and, for the first close-enough match on each axis, snaps to it
|
||||
* and records a guide line to draw across the canvas.
|
||||
*/
|
||||
function computeSnapAndGuides(dragged: Box, others: Box[]): { x: number; y: number; guides: AlignmentGuide[] } {
|
||||
const guides: AlignmentGuide[] = [];
|
||||
@@ -87,36 +87,24 @@ function computeSnapAndGuides(dragged: Box, others: Box[]): { x: number; y: numb
|
||||
let snappedY = dragged.y;
|
||||
let matchedX = false;
|
||||
let matchedY = false;
|
||||
const draggedCenterX = dragged.x + dragged.width / 2;
|
||||
const draggedCenterY = dragged.y + dragged.height / 2;
|
||||
|
||||
for (const other of others) {
|
||||
if (!matchedX) {
|
||||
const xCandidates: [number, number][] = [
|
||||
[dragged.x, other.x],
|
||||
[dragged.x + dragged.width, other.x + other.width],
|
||||
[dragged.x + dragged.width / 2, other.x + other.width / 2],
|
||||
];
|
||||
for (const [dValue, oValue] of xCandidates) {
|
||||
if (Math.abs(dValue - oValue) <= SNAP_THRESHOLD) {
|
||||
snappedX = dragged.x + (oValue - dValue);
|
||||
guides.push({ axis: 'x', position: oValue });
|
||||
const otherCenterX = other.x + other.width / 2;
|
||||
if (Math.abs(draggedCenterX - otherCenterX) <= SNAP_THRESHOLD) {
|
||||
snappedX = dragged.x + (otherCenterX - draggedCenterX);
|
||||
guides.push({ axis: 'x', position: otherCenterX });
|
||||
matchedX = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matchedY) {
|
||||
const yCandidates: [number, number][] = [
|
||||
[dragged.y, other.y],
|
||||
[dragged.y + dragged.height, other.y + other.height],
|
||||
[dragged.y + dragged.height / 2, other.y + other.height / 2],
|
||||
];
|
||||
for (const [dValue, oValue] of yCandidates) {
|
||||
if (Math.abs(dValue - oValue) <= SNAP_THRESHOLD) {
|
||||
snappedY = dragged.y + (oValue - dValue);
|
||||
guides.push({ axis: 'y', position: oValue });
|
||||
const otherCenterY = other.y + other.height / 2;
|
||||
if (Math.abs(draggedCenterY - otherCenterY) <= SNAP_THRESHOLD) {
|
||||
snappedY = dragged.y + (otherCenterY - draggedCenterY);
|
||||
guides.push({ axis: 'y', position: otherCenterY });
|
||||
matchedY = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,8 +295,21 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
|
||||
);
|
||||
if (isHistoryWorthy) pushHistory(nodes, edges);
|
||||
const next = applyNodeChanges(adjustedChanges, nodes);
|
||||
|
||||
// React Flow's own keyboard delete dispatches node and edge removal as
|
||||
// separate change events that race through the same debounced
|
||||
// emitChange — filtering edges here too (redundantly with onEdgesChange)
|
||||
// guarantees a removed node never leaves a dangling edge behind.
|
||||
const removedIds = new Set(
|
||||
filteredChanges.filter((change) => change.type === 'remove').map((change) => change.id),
|
||||
);
|
||||
const nextEdges = removedIds.size
|
||||
? edges.filter((edge) => !removedIds.has(edge.source) && !removedIds.has(edge.target))
|
||||
: edges;
|
||||
|
||||
setNodes(next);
|
||||
emitChange(next, edges);
|
||||
if (nextEdges !== edges) setEdges(nextEdges);
|
||||
emitChange(next, nextEdges);
|
||||
},
|
||||
[nodes, edges, emitChange, pushHistory, alignmentGuides],
|
||||
);
|
||||
@@ -327,7 +328,10 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
|
||||
const onConnect: OnConnect = useCallback(
|
||||
(connection) => {
|
||||
pushHistory(nodes, edges);
|
||||
const next = addEdge({ ...connection, type: DEFAULT_EDGE_TYPE, markerEnd: DEFAULT_MARKER_END }, edges);
|
||||
const next = addEdge(
|
||||
{ ...connection, id: crypto.randomUUID(), type: DEFAULT_EDGE_TYPE, markerEnd: DEFAULT_MARKER_END },
|
||||
edges,
|
||||
);
|
||||
setEdges(next);
|
||||
emitChange(nodes, next);
|
||||
},
|
||||
@@ -397,7 +401,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
|
||||
const addNode = useCallback(
|
||||
(kind: NodeKind) => {
|
||||
nodeCounter.current += 1;
|
||||
const id = `${kind}-${nodeCounter.current}`;
|
||||
const id = crypto.randomUUID();
|
||||
const center = getViewportCenter();
|
||||
const fanOut = nodeCounter.current;
|
||||
const size = DEFAULT_NODE_SIZE[kind];
|
||||
@@ -431,7 +435,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
|
||||
const source = clipboardRef.current;
|
||||
if (!source) return;
|
||||
nodeCounter.current += 1;
|
||||
const newId = `${source.type}-${nodeCounter.current}`;
|
||||
const newId = crypto.randomUUID();
|
||||
const { parentId: _sourceParentId, selected: _sourceSelected, ...restSource } = source;
|
||||
const newNode: Node = {
|
||||
...restSource,
|
||||
|
||||
+10
-3
@@ -1,11 +1,18 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ mode }) => {
|
||||
// VITE_BASE_PATH is read here (config/Node context), so it needs an explicit
|
||||
// loadEnv call — unlike VITE_BITRIX_ORIGIN, which Vite injects into
|
||||
// import.meta.env automatically because it's only read from app code.
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
|
||||
return {
|
||||
// Needed when the build is served from a subpath (e.g. local/diagram-app/
|
||||
// inside the Bitrix docroot) instead of domain root — see
|
||||
// docs/bitrix-integration.md §7.
|
||||
base: process.env.VITE_BASE_PATH || '/',
|
||||
base: env.VITE_BASE_PATH || '/',
|
||||
plugins: [react()],
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user