fix: node resize
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import type { ComponentProps, ReactNode } from "react";
|
||||
import { NodeResizeControl } from "@xyflow/react";
|
||||
import { NodeResizer } from "@xyflow/react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/** Default min size for resizable nodes (used by NodeResizer). */
|
||||
export const RESIZE_MIN_WIDTH = 120;
|
||||
export const RESIZE_MIN_HEIGHT = 80;
|
||||
|
||||
export type BaseNodeProps = ComponentProps<"div"> & {
|
||||
/** When true, shows a bottom-right resize handle. Requires nodeId when used inside React Flow. */
|
||||
/** When true, shows resize handles on corners/edges (via NodeResizer). Requires nodeId when used inside React Flow. */
|
||||
resizable?: boolean;
|
||||
/** Node id for the resize control (required when resizable is true). */
|
||||
nodeId?: string;
|
||||
@@ -14,6 +18,8 @@ export type BaseNodeProps = ComponentProps<"div"> & {
|
||||
dimensions?: { width: number; height: number };
|
||||
/** When true, node is selected (from React Flow NodeProps). Used for visible selected state. */
|
||||
selected?: boolean;
|
||||
/** Optional min/max for NodeResizer. Omit to use RESIZE_MIN_WIDTH / RESIZE_MIN_HEIGHT. */
|
||||
resizeConstraints?: { minWidth?: number; minHeight?: number; maxWidth?: number; maxHeight?: number };
|
||||
};
|
||||
|
||||
export function BaseNode({
|
||||
@@ -25,6 +31,7 @@ export function BaseNode({
|
||||
handles,
|
||||
children,
|
||||
selected,
|
||||
resizeConstraints,
|
||||
...props
|
||||
}: BaseNodeProps) {
|
||||
const hasSize =
|
||||
@@ -46,6 +53,9 @@ export function BaseNode({
|
||||
? { ...style, display: "flex", flexDirection: "column" as const }
|
||||
: undefined;
|
||||
|
||||
const minW = resizeConstraints?.minWidth ?? RESIZE_MIN_WIDTH;
|
||||
const minH = resizeConstraints?.minHeight ?? RESIZE_MIN_HEIGHT;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -66,19 +76,16 @@ export function BaseNode({
|
||||
{children}
|
||||
</div>
|
||||
{resizable && nodeId && (
|
||||
<NodeResizeControl
|
||||
<NodeResizer
|
||||
nodeId={nodeId}
|
||||
position="bottom-right"
|
||||
minWidth={120}
|
||||
minHeight={80}
|
||||
className={cn(
|
||||
"!border-0 !bg-transparent !rounded-none !p-0",
|
||||
"absolute bottom-0 right-0 w-8 h-8 cursor-se-resize select-none",
|
||||
"nodrag nopan touch-none",
|
||||
)}
|
||||
style={{ margin: 0, touchAction: "none", userSelect: "none" }}
|
||||
>
|
||||
</NodeResizeControl>
|
||||
isVisible={selected}
|
||||
minWidth={minW}
|
||||
minHeight={minH}
|
||||
maxWidth={resizeConstraints?.maxWidth}
|
||||
maxHeight={resizeConstraints?.maxHeight}
|
||||
color="transparent"
|
||||
handleClassName="base-node-resize-handle nodrag nopan"
|
||||
/>
|
||||
)}
|
||||
{handles}
|
||||
</div>
|
||||
|
||||
@@ -142,18 +142,36 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* Resize control: snappy drag, no transition or selection delay */
|
||||
.react-flow__resize-control.bottom.right {
|
||||
cursor: se-resize;
|
||||
/* NodeResizer: snappy drag; no border/background on handles; keep resize cursors. */
|
||||
.react-flow__resize-control {
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.react-flow__resize-control.bottom.right,
|
||||
.react-flow__resize-control.bottom.right * {
|
||||
.react-flow__resize-control,
|
||||
.react-flow__resize-control * {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/* Subtle resize handles so they don’t compete with the selected-node ring (primary). Shown only when node is selected. */
|
||||
/* Single bottom-right resize handle: no border, transparent so only the corner grab area remains. */
|
||||
/* Handles: invisible (no border/background); cursor unchanged so resize cursors stay. */
|
||||
.base-node-resize-handle,
|
||||
.base-node-resize-handle * {
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Resize cursor per position (keep cursor style change on hover). */
|
||||
.react-flow__resize-control.top.left { cursor: nw-resize; }
|
||||
.react-flow__resize-control.top.right { cursor: ne-resize; }
|
||||
.react-flow__resize-control.bottom.left { cursor: sw-resize; }
|
||||
.react-flow__resize-control.bottom.right { cursor: se-resize; }
|
||||
.react-flow__resize-control.top { cursor: n-resize; }
|
||||
.react-flow__resize-control.right { cursor: e-resize; }
|
||||
.react-flow__resize-control.bottom { cursor: s-resize; }
|
||||
.react-flow__resize-control.left { cursor: w-resize; }
|
||||
|
||||
/* Small helper for monospace pre output */
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', 'Courier New', monospace;
|
||||
|
||||
Reference in New Issue
Block a user