Доработки
This commit is contained in:
+15
-39
@@ -1,4 +1,4 @@
|
||||
import { createContext, useContext, type CSSProperties } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
import { Handle, NodeResizer, Position, type Node, type NodeProps } from '@xyflow/react';
|
||||
import type { DiagramNodeData, NodeKind } from './types';
|
||||
|
||||
@@ -42,33 +42,6 @@ function ShapeHandles() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The diamond div is a rotated square (`transform: rotate(45deg)`). Handles
|
||||
* placed at the square's own corners land on the diamond's tips once rotated
|
||||
* — corners, not `Position.Top/Right/Bottom/Left` (those are edge-midpoints,
|
||||
* which rotate onto the diamond's flat sides instead).
|
||||
*/
|
||||
const DIAMOND_HANDLES: { id: string; position: Position; style: CSSProperties }[] = [
|
||||
{ id: 'top', position: Position.Top, style: { top: 0, left: 0, transform: 'translate(-50%, -50%)' } },
|
||||
{ id: 'right', position: Position.Right, style: { top: 0, left: '100%', transform: 'translate(-50%, -50%)' } },
|
||||
{
|
||||
id: 'bottom',
|
||||
position: Position.Bottom,
|
||||
style: { top: '100%', left: '100%', transform: 'translate(-50%, -50%)' },
|
||||
},
|
||||
{ id: 'left', position: Position.Left, style: { top: '100%', left: 0, transform: 'translate(-50%, -50%)' } },
|
||||
];
|
||||
|
||||
function DiamondHandles() {
|
||||
return (
|
||||
<>
|
||||
{DIAMOND_HANDLES.map(({ id, position, style }) => (
|
||||
<Handle key={id} id={id} type="source" position={position} style={style} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function SubProcessBadge({ id }: { id: string }) {
|
||||
const withChildren = useContext(NodesWithChildrenContext);
|
||||
if (!withChildren.has(id)) return null;
|
||||
@@ -145,19 +118,22 @@ function GatewayNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
|
||||
<div className="diagram-node--gateway-outer">
|
||||
<ShapeResizer selected={selected} minWidth={32} minHeight={32} />
|
||||
{/*
|
||||
The diamond is an inner square inset to 1/sqrt(2) of the outer box and
|
||||
rotated 45deg, so its tips exactly reach the outer box's edges without
|
||||
clipping. The caption sits on the (unrotated) outer box instead of the
|
||||
diamond itself, so it renders upright below the shape.
|
||||
The diamond is drawn with clip-path on a plain (unrotated) box, not
|
||||
`transform: rotate(45deg)` — a rotated element makes React Flow's
|
||||
getBoundingClientRect-based handle measurement pick up sub-pixel
|
||||
rounding from the rotation, which showed up as a visible kink in
|
||||
otherwise-straight horizontal/vertical edges. With clip-path, the
|
||||
standard Position.Top/Right/Bottom/Left handles already land exactly
|
||||
on the diamond's tips (they're at the box's edge midpoints either
|
||||
way), so this reuses the same ShapeHandles as every other shape.
|
||||
Handles/badge/caption are siblings of the clipped div, not children
|
||||
of it, since clip-path would otherwise cut off anything of theirs
|
||||
that renders outside the diamond outline.
|
||||
*/}
|
||||
<div
|
||||
className="diagram-node diagram-node--diamond"
|
||||
style={{ background: data.color ?? DEFAULT_NODE_COLOR[kind] }}
|
||||
>
|
||||
<DiamondHandles />
|
||||
<span className="diagram-node__icon">{GATEWAY_ICON[kind]}</span>
|
||||
</div>
|
||||
<div className="diagram-node--diamond-bg" style={{ background: data.color ?? DEFAULT_NODE_COLOR[kind] }} />
|
||||
<ShapeHandles />
|
||||
<SubProcessBadge id={id} />
|
||||
<span className="diagram-node__icon">{GATEWAY_ICON[kind]}</span>
|
||||
<span className="diagram-node__caption">{data.label}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user