Refactor: CSS handling (#2344)
* refactor(css): only load base styles, add css task, cleanup exports * style(base): add edge label bg * refactor(css): use css-utils * feat(core): add Panel component * refactor(background): cleanup * refactor(css-handling): cleanup
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-flow/background",
|
||||
"version": "11.0.0",
|
||||
"description": "A background component for React Flow",
|
||||
"description": "Background component with different variants for React Flow",
|
||||
"main": "dist/react-flow-background.cjs.js",
|
||||
"module": "dist/react-flow-background.esm.js",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { memo, FC, useRef, useId } from 'react';
|
||||
import React, { memo, useRef, useId } from 'react';
|
||||
import cc from 'classcat';
|
||||
import { useStore, ReactFlowState } from '@react-flow/core';
|
||||
|
||||
import { BackgroundProps, BackgroundVariant } from './types';
|
||||
import { DotPattern, LinePattern } from './utils';
|
||||
import { DotPattern, LinePattern } from './Patterns';
|
||||
|
||||
const defaultColors = {
|
||||
const defaultColor = {
|
||||
[BackgroundVariant.Dots]: '#91919a',
|
||||
[BackgroundVariant.Lines]: '#eee',
|
||||
[BackgroundVariant.Cross]: '#e2e2e2',
|
||||
@@ -34,8 +34,8 @@ function Background({
|
||||
const patternId = useId();
|
||||
const [tX, tY, tScale] = useStore(transformSelector);
|
||||
|
||||
const patternColor = color ? color : defaultColors[variant];
|
||||
const patternSize = size ? size : defaultSize[variant];
|
||||
const patternColor = color || defaultColor[variant];
|
||||
const patternSize = size || defaultSize[variant];
|
||||
const isDots = variant === BackgroundVariant.Dots;
|
||||
const isCross = variant === BackgroundVariant.Cross;
|
||||
const gapXY: [number, number] = Array.isArray(gap) ? gap : [gap, gap];
|
||||
@@ -55,15 +55,14 @@ function Background({
|
||||
|
||||
return (
|
||||
<svg
|
||||
className={cc([
|
||||
'react-flow__background',
|
||||
'react-flow__container',
|
||||
className,
|
||||
])}
|
||||
className={cc(['react-flow__background', className])}
|
||||
style={{
|
||||
...style,
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Background, default } from './Background';
|
||||
export { default as Background } from './Background';
|
||||
export * from './types';
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "@react-flow/controls",
|
||||
"version": "11.0.0",
|
||||
"description": "A component that controls the viewport of React Flow",
|
||||
"description": "A component to control the viewport of a React Flow instance",
|
||||
"main": "dist/react-flow-controls.cjs.js",
|
||||
"module": "dist/react-flow-controls.esm.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-flow/core": "11.0.0",
|
||||
"@react-flow/core": "^11.0.0",
|
||||
"@react-flow/css-utils": "^11.0.0",
|
||||
"classcat": "^5.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React, { FC, PropsWithChildren } from 'react';
|
||||
import cc from 'classcat';
|
||||
|
||||
import { ControlButtonProps } from './types';
|
||||
|
||||
const ControlButton: FC<PropsWithChildren<ControlButtonProps>> = ({
|
||||
children,
|
||||
className,
|
||||
...rest
|
||||
}) => (
|
||||
<button
|
||||
type="button"
|
||||
className={cc(['react-flow__controls-button', className])}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
ControlButton.displayName = 'ControlButton';
|
||||
|
||||
export default ControlButton;
|
||||
@@ -5,31 +5,21 @@ import {
|
||||
useStoreApi,
|
||||
useReactFlow,
|
||||
ReactFlowState,
|
||||
Panel,
|
||||
} from '@react-flow/core';
|
||||
import { injectStyle } from '@react-flow/css-utils';
|
||||
|
||||
import PlusIcon from './Icons/Plus';
|
||||
import MinusIcon from './Icons/Minus';
|
||||
import FitviewIcon from './Icons/FitView';
|
||||
import LockIcon from './Icons/Lock';
|
||||
import UnlockIcon from './Icons/Unlock';
|
||||
import ControlButton from './ControlButton';
|
||||
import baseStyle from './style';
|
||||
|
||||
import { ControlProps, ControlButtonProps } from './types';
|
||||
import { ControlProps } from './types';
|
||||
|
||||
import './style.css';
|
||||
|
||||
export const ControlButton: FC<PropsWithChildren<ControlButtonProps>> = ({
|
||||
children,
|
||||
className,
|
||||
...rest
|
||||
}) => (
|
||||
<button
|
||||
type='button'
|
||||
className={cc(['react-flow__controls-button', className])}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
injectStyle(baseStyle);
|
||||
|
||||
const isInteractiveSelector = (s: ReactFlowState) =>
|
||||
s.nodesDraggable && s.nodesConnectable && s.elementsSelectable;
|
||||
@@ -46,6 +36,7 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
||||
onInteractiveChange,
|
||||
className,
|
||||
children,
|
||||
position = 'bottom-left',
|
||||
}) => {
|
||||
const store = useStoreApi();
|
||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||
@@ -86,22 +77,26 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cc(['react-flow__controls', className])} style={style}>
|
||||
<Panel
|
||||
className={cc(['react-flow__controls', className])}
|
||||
position={position}
|
||||
style={style}
|
||||
>
|
||||
{showZoom && (
|
||||
<>
|
||||
<ControlButton
|
||||
onClick={onZoomInHandler}
|
||||
className='react-flow__controls-zoomin'
|
||||
title='zoom in'
|
||||
aria-label='zoom in'
|
||||
className="react-flow__controls-zoomin"
|
||||
title="zoom in"
|
||||
aria-label="zoom in"
|
||||
>
|
||||
<PlusIcon />
|
||||
</ControlButton>
|
||||
<ControlButton
|
||||
onClick={onZoomOutHandler}
|
||||
className='react-flow__controls-zoomout'
|
||||
title='zoom out'
|
||||
aria-label='zoom out'
|
||||
className="react-flow__controls-zoomout"
|
||||
title="zoom out"
|
||||
aria-label="zoom out"
|
||||
>
|
||||
<MinusIcon />
|
||||
</ControlButton>
|
||||
@@ -109,26 +104,26 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
||||
)}
|
||||
{showFitView && (
|
||||
<ControlButton
|
||||
className='react-flow__controls-fitview'
|
||||
className="react-flow__controls-fitview"
|
||||
onClick={onFitViewHandler}
|
||||
title='fit view'
|
||||
aria-label='fit view'
|
||||
title="fit view"
|
||||
aria-label="fit view"
|
||||
>
|
||||
<FitviewIcon />
|
||||
</ControlButton>
|
||||
)}
|
||||
{showInteractive && (
|
||||
<ControlButton
|
||||
className='react-flow__controls-interactive'
|
||||
className="react-flow__controls-interactive"
|
||||
onClick={onToggleInteractivity}
|
||||
title='toggle interactivity'
|
||||
aria-label='toggle interactivity'
|
||||
title="toggle interactivity"
|
||||
aria-label="toggle interactivity"
|
||||
>
|
||||
{isInteractive ? <UnlockIcon /> : <LockIcon />}
|
||||
</ControlButton>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { default as default } from './Controls';
|
||||
export { default as Controls } from './Controls';
|
||||
export { default as ControlButton } from './ControlButton';
|
||||
export * from './types';
|
||||
export * from './Controls';
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
.react-flow__controls {
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
bottom: 20px;
|
||||
left: 15px;
|
||||
|
||||
&-button {
|
||||
border: none;
|
||||
background: #fefefe;
|
||||
border-bottom: 1px solid #eee;
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 5px;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
max-width: 12px;
|
||||
max-height: 12px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
const style = `
|
||||
.react-flow__controls {
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.react-flow__controls-button {
|
||||
border: none;
|
||||
background: #fefefe;
|
||||
border-bottom: 1px solid #eee;
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.react-flow__controls-button svg {
|
||||
width: 100%;
|
||||
max-width: 12px;
|
||||
max-height: 12px;
|
||||
}
|
||||
|
||||
.react-flow__controls-button:hover {
|
||||
background: #f4f4f4;
|
||||
}`;
|
||||
|
||||
export default style;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ButtonHTMLAttributes, HTMLAttributes } from 'react';
|
||||
import { FitViewOptions } from '@react-flow/core';
|
||||
import { FitViewOptions, PanelPosition } from '@react-flow/core';
|
||||
|
||||
export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
|
||||
showZoom?: boolean;
|
||||
@@ -10,6 +10,7 @@ export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
|
||||
onZoomOut?: () => void;
|
||||
onFitView?: () => void;
|
||||
onInteractiveChange?: (interactiveStatus: boolean) => void;
|
||||
position?: PanelPosition;
|
||||
}
|
||||
|
||||
export interface ControlButtonProps
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 30">
|
||||
<path d="M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 463 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 32">
|
||||
<path d="M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 530 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 5">
|
||||
<path d="M0 0h32v4.2H0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 96 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<path d="M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 152 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 32">
|
||||
<path d="M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 472 B |
Generated
-19621
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,12 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/wbkd/react-flow.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "postcss src/styles/*.css --config ../../tooling/postcss.config.json --dir dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.0",
|
||||
"@react-flow/css-utils": "^11.0.0",
|
||||
"classcat": "^5.0.3",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-selection": "^3.0.0",
|
||||
@@ -30,6 +34,11 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/react": "^18.0.15"
|
||||
"@types/react": "^18.0.15",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-cli": "^10.0.0",
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-nested": "^5.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import cc from 'classcat';
|
||||
|
||||
import { AttributionPosition, ProOptions } from '../../types';
|
||||
import Panel from '../Panel';
|
||||
import { PanelPosition, ProOptions } from '../../types';
|
||||
|
||||
type AttributionProps = {
|
||||
proOptions?: ProOptions;
|
||||
position?: AttributionPosition;
|
||||
position?: PanelPosition;
|
||||
};
|
||||
|
||||
function Attribution({ proOptions, position = 'bottom-right' }: AttributionProps) {
|
||||
@@ -13,17 +13,16 @@ function Attribution({ proOptions, position = 'bottom-right' }: AttributionProps
|
||||
return null;
|
||||
}
|
||||
|
||||
const positionClasses = `${position}`.split('-');
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cc(['react-flow__attribution', ...positionClasses])}
|
||||
<Panel
|
||||
position={position}
|
||||
className="react-flow__attribution"
|
||||
data-message="Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev"
|
||||
>
|
||||
<a href="https://reactflow.dev" target="_blank" rel="noopener noreferrer" aria-label="React Flow attribution">
|
||||
React Flow
|
||||
</a>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ export default ({
|
||||
|
||||
return (
|
||||
<g className="react-flow__connection">
|
||||
<path d={dAttr} className="react-flow__connection-path" style={connectionLineStyle} />
|
||||
<path d={dAttr} fill="none" className="react-flow__connection-path" style={connectionLineStyle} />
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -32,7 +32,14 @@ export default ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<path style={style} d={path} className="react-flow__edge-path" markerEnd={markerEnd} markerStart={markerStart} />
|
||||
<path
|
||||
style={style}
|
||||
d={path}
|
||||
fill="none"
|
||||
className="react-flow__edge-path"
|
||||
markerEnd={markerEnd}
|
||||
markerStart={markerStart}
|
||||
/>
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { HTMLAttributes, ReactNode } from 'react';
|
||||
import cc from 'classcat';
|
||||
|
||||
import { PanelPosition } from '../../types';
|
||||
|
||||
export type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
||||
position: PanelPosition;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
function Panel({ position, children, className, ...rest }: PanelProps) {
|
||||
const positionClasses = `${position}`.split('-');
|
||||
|
||||
return (
|
||||
<div className={cc(['react-flow__panel', className, ...positionClasses])} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Panel;
|
||||
@@ -9,6 +9,7 @@ import UserSelection from '../../components/UserSelection';
|
||||
import NodesSelection from '../../components/NodesSelection';
|
||||
|
||||
import { ReactFlowState } from '../../types';
|
||||
import { containerStyle } from '../../styles';
|
||||
|
||||
export type FlowRendererProps = Omit<
|
||||
GraphViewProps,
|
||||
@@ -104,13 +105,14 @@ const FlowRenderer = ({
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className="react-flow__pane react-flow__container"
|
||||
className="react-flow__pane"
|
||||
onClick={onClick}
|
||||
onMouseEnter={onPaneMouseEnter}
|
||||
onMouseMove={onPaneMouseMove}
|
||||
onMouseLeave={onPaneMouseLeave}
|
||||
onContextMenu={onContextMenu}
|
||||
onWheel={onWheel}
|
||||
style={containerStyle}
|
||||
/>
|
||||
</ZoomPane>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import shallow from 'zustand/shallow';
|
||||
|
||||
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
||||
import { useStore } from '../../store';
|
||||
import { containerStyle } from '../../styles';
|
||||
import { NodeMouseHandler, NodeTypesWrapped, Position, ReactFlowState, WrapNodeProps } from '../../types';
|
||||
import { internalsSymbol } from '../../utils';
|
||||
|
||||
@@ -61,7 +62,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="react-flow__nodes react-flow__container">
|
||||
<div className="react-flow__nodes" style={containerStyle}>
|
||||
{nodes.map((node) => {
|
||||
let nodeType = node.type || 'default';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { forwardRef, useId } from 'react';
|
||||
import React, { CSSProperties, forwardRef, useId } from 'react';
|
||||
import cc from 'classcat';
|
||||
import { injectStyle } from '@react-flow/css-utils';
|
||||
|
||||
import Attribution from '../../components/Attribution';
|
||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges';
|
||||
@@ -8,9 +9,9 @@ import InputNode from '../../components/Nodes/InputNode';
|
||||
import OutputNode from '../../components/Nodes/OutputNode';
|
||||
import SelectionListener from '../../components/SelectionListener';
|
||||
import StoreUpdater from '../../components/StoreUpdater';
|
||||
import baseStyle from '../../styles/base';
|
||||
|
||||
import '../../style.css';
|
||||
import '../../theme-default.css';
|
||||
injectStyle(baseStyle);
|
||||
|
||||
import {
|
||||
ConnectionLineType,
|
||||
@@ -48,6 +49,13 @@ const defaultEdgeTypes: EdgeTypes = {
|
||||
const initSnapGrid: [number, number] = [15, 15];
|
||||
const initDefaultViewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
||||
|
||||
const wrapperStyle: CSSProperties = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
};
|
||||
|
||||
const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
(
|
||||
{
|
||||
@@ -143,6 +151,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
defaultEdgeOptions,
|
||||
elevateEdgesOnSelect = false,
|
||||
disableKeyboardA11y = false,
|
||||
style,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -152,7 +161,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
const rfId = useId();
|
||||
|
||||
return (
|
||||
<div {...rest} ref={ref} className={cc(['react-flow', className])}>
|
||||
<div {...rest} style={{ ...style, ...wrapperStyle }} ref={ref} className={cc(['react-flow', className])}>
|
||||
<Wrapper>
|
||||
<GraphView
|
||||
onInit={onInit}
|
||||
|
||||
@@ -9,6 +9,7 @@ import useResizeHandler from '../../hooks/useResizeHandler';
|
||||
import { useStore, useStoreApi } from '../../store';
|
||||
import { Viewport, PanOnScrollMode, ReactFlowState } from '../../types';
|
||||
import { FlowRendererProps } from '../FlowRenderer';
|
||||
import { containerStyle } from '../../styles';
|
||||
|
||||
type ZoomPaneProps = Omit<
|
||||
FlowRendererProps,
|
||||
@@ -253,7 +254,7 @@ const ZoomPane = ({
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="react-flow__renderer react-flow__container" ref={zoomPane}>
|
||||
<div className="react-flow__renderer" ref={zoomPane} style={containerStyle}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import ReactFlow from './container/ReactFlow';
|
||||
|
||||
export default ReactFlow;
|
||||
|
||||
export { default as ReactFlow } from './container/ReactFlow';
|
||||
export { default as Handle } from './components/Handle';
|
||||
export { default as EdgeText } from './components/Edges/EdgeText';
|
||||
export { default as StraightEdge } from './components/Edges/StraightEdge';
|
||||
@@ -18,7 +15,7 @@ export {
|
||||
} from './components/Edges/SimpleBezierEdge';
|
||||
export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge';
|
||||
|
||||
export { internalsSymbol } from './utils';
|
||||
export { internalsSymbol, rectToBox, boxToRect, getBoundsOfRects } from './utils';
|
||||
export {
|
||||
isNode,
|
||||
isEdge,
|
||||
@@ -33,6 +30,7 @@ export {
|
||||
export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
|
||||
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils';
|
||||
export { default as ReactFlowProvider } from './components/ReactFlowProvider';
|
||||
export { default as Panel } from './components/Panel';
|
||||
|
||||
export { default as useReactFlow } from './hooks/useReactFlow';
|
||||
export { default as useUpdateNodeInternals } from './hooks/useUpdateNodeInternals';
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
.react-flow {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.react-flow__container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.react-flow__pane {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.react-flow__viewport {
|
||||
transform-origin: 0 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.react-flow__renderer {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.react-flow__selectionpane {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.react-flow .react-flow__edges {
|
||||
pointer-events: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.react-flow .react-flow__connectionline {
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.react-flow__edge {
|
||||
pointer-events: visibleStroke;
|
||||
|
||||
&.inactive {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dashdraw {
|
||||
from {
|
||||
stroke-dashoffset: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__edge-path {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.react-flow__edge-textwrapper {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.react-flow__edge-text {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.react-flow__connection {
|
||||
pointer-events: none;
|
||||
|
||||
.animated {
|
||||
stroke-dasharray: 5;
|
||||
animation: dashdraw 0.5s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__connection-path {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.react-flow__nodes {
|
||||
pointer-events: none;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.react-flow__node {
|
||||
position: absolute;
|
||||
user-select: none;
|
||||
pointer-events: all;
|
||||
transform-origin: 0 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.react-flow__nodesselection {
|
||||
z-index: 3;
|
||||
transform-origin: left top;
|
||||
pointer-events: none;
|
||||
|
||||
&-rect {
|
||||
position: absolute;
|
||||
pointer-events: all;
|
||||
cursor: grab;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__handle {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
|
||||
&.connectable {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__handle-bottom {
|
||||
top: auto;
|
||||
left: 50%;
|
||||
bottom: -4px;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.react-flow__handle-top {
|
||||
left: 50%;
|
||||
top: -4px;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.react-flow__handle-left {
|
||||
top: 50%;
|
||||
left: -4px;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.react-flow__handle-right {
|
||||
right: -4px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.react-flow__edgeupdater {
|
||||
cursor: move;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.react-flow__attribution {
|
||||
font-size: 10px;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
padding: 2px 3px;
|
||||
color: #999;
|
||||
|
||||
a {
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.top {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
&.left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&.center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
const style = `
|
||||
.react-flow__container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.react-flow__pane {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.react-flow__viewport {
|
||||
transform-origin: 0 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.react-flow__renderer {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.react-flow__selectionpane {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.react-flow__nodesselection-rect,
|
||||
.react-flow__selection {
|
||||
background: rgba(150, 150, 180, 0.1);
|
||||
border: 1px dotted rgba(155, 155, 155, 0.8);
|
||||
}
|
||||
|
||||
.react-flow__nodesselection-rect:focus,
|
||||
.react-flow__nodesselection-rect:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.react-flow .react-flow__edges {
|
||||
pointer-events: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.react-flow__connection {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.react-flow__connection.animated {
|
||||
stroke-dasharray: 5;
|
||||
animation: dashdraw 0.5s linear infinite;
|
||||
}
|
||||
|
||||
.react-flow .react-flow__connectionline {
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.react-flow__connectionline path, .react-flow__edge path {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.react-flow__edge-path, .react-flow__connection-path {
|
||||
stroke: #b1b1b7;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.react-flow__edge {
|
||||
pointer-events: visibleStroke;
|
||||
}
|
||||
|
||||
.react-flow__edge.animated path {
|
||||
stroke-dasharray: 5;
|
||||
animation: dashdraw 0.5s linear infinite;
|
||||
}
|
||||
|
||||
.react-flow__edge.inactive {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.react-flow__edge.selected, .react-flow__edge:focus, .react-flow__edge:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.react-flow__edge.selected .react-flow__edge-path,
|
||||
.react-flow__edge:focus .react-flow__edge-path,
|
||||
.react-flow__edge:focus-visible .react-flow__edge-path {
|
||||
stroke: #555;
|
||||
}
|
||||
|
||||
@keyframes dashdraw {
|
||||
from {
|
||||
stroke-dashoffset: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__edge-textwrapper {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.react-flow__edge-text {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.react-flow__edge-textbg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.react-flow__nodes {
|
||||
pointer-events: none;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.react-flow__node {
|
||||
position: absolute;
|
||||
user-select: none;
|
||||
pointer-events: all;
|
||||
transform-origin: 0 0;
|
||||
box-sizing: border-box;
|
||||
background-color: white;
|
||||
cursor: grab;
|
||||
border: 1px solid #bbb;
|
||||
}
|
||||
|
||||
.react-flow__node.selected,
|
||||
.react-flow__node:focus,
|
||||
.react-flow__node:focus-visible {
|
||||
outline: none;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
|
||||
.react-flow__nodesselection {
|
||||
z-index: 3;
|
||||
transform-origin: left top;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.react-flow__nodesselection-rect {
|
||||
position: absolute;
|
||||
pointer-events: all;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.react-flow__handle {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
min-width: 5px;
|
||||
min-height: 5px;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.react-flow__handle.connectable {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.react-flow__handle-bottom {
|
||||
top: auto;
|
||||
left: 50%;
|
||||
bottom: -4px;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.react-flow__handle-top {
|
||||
left: 50%;
|
||||
top: -4px;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.react-flow__handle-left {
|
||||
top: 50%;
|
||||
left: -4px;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.react-flow__handle-right {
|
||||
right: -4px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.react-flow__edgeupdater {
|
||||
cursor: move;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.react-flow__panel {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.react-flow__panel.top {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.react-flow__panel.bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.react-flow__panel.left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.react-flow__panel.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.react-flow__panel.center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.react-flow__attribution {
|
||||
font-size: 10px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
padding: 2px 3px;
|
||||
color: #999;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.react-flow__attribution a {
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default style;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
export const containerStyle: CSSProperties = {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
@@ -1,18 +1,4 @@
|
||||
.react-flow__edge {
|
||||
&.selected,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
.react-flow__edge-path {
|
||||
stroke: #555;
|
||||
}
|
||||
}
|
||||
|
||||
&.animated path {
|
||||
stroke-dasharray: 5;
|
||||
animation: dashdraw 0.5s linear infinite;
|
||||
}
|
||||
|
||||
&.updating {
|
||||
.react-flow__edge-path {
|
||||
stroke: #777;
|
||||
@@ -20,28 +6,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__edge-path {
|
||||
stroke: #b1b1b7;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.react-flow__edge-text {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.react-flow__edge-textbg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.react-flow__connection-path {
|
||||
stroke: #b1b1b7;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.react-flow__node {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.react-flow__node-default,
|
||||
.react-flow__node-input,
|
||||
.react-flow__node-output,
|
||||
@@ -54,12 +22,12 @@
|
||||
text-align: center;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
background: #fff;
|
||||
border-color: #1a192b;
|
||||
|
||||
&.selected,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
border: none;
|
||||
box-shadow: 0 0 0 0.5px #1a192b;
|
||||
outline: none;
|
||||
}
|
||||
@@ -80,8 +48,9 @@
|
||||
&.selected,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
border: none;
|
||||
box-shadow: 0 0 0 0.5px #1a192b;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,13 +221,7 @@ export type OnSelectionChangeParams = {
|
||||
|
||||
export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void;
|
||||
|
||||
export type AttributionPosition =
|
||||
| 'top-left'
|
||||
| 'top-center'
|
||||
| 'top-right'
|
||||
| 'bottom-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-right';
|
||||
export type PanelPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
||||
|
||||
export type ProOptions = {
|
||||
hideAttribution: boolean;
|
||||
|
||||
@@ -36,7 +36,7 @@ export const boxToRect = ({ x, y, x2, y2 }: Box): Rect => ({
|
||||
height: y2 - y,
|
||||
});
|
||||
|
||||
export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
|
||||
export const getBoundsOfRects = (rect1: Rect, rect2: Rect): Rect =>
|
||||
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
||||
|
||||
export const isNumeric = (n: any): n is number => !isNaN(n) && isFinite(n);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "@react-flow/css-utils",
|
||||
"version": "11.0.0",
|
||||
"description": "Utils for handling styles.",
|
||||
"main": "dist/react-flow-css-utils.cjs.js",
|
||||
"module": "dist/react-flow-css-utils.esm.js",
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export function injectStyle(css: string) {
|
||||
if (typeof document === 'undefined') return;
|
||||
|
||||
const head = document.head || document.getElementsByTagName('head')[0];
|
||||
const style = document.createElement('style');
|
||||
|
||||
head.prepend(style);
|
||||
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
@@ -6,18 +6,13 @@
|
||||
"module": "dist/react-flow-minimap.esm.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-flow/core": "11.0.0",
|
||||
"@react-flow/core": "^11.0.0",
|
||||
"@react-flow/css-utils": "^11.0.0",
|
||||
"classcat": "^5.0.3",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-selection": "^3.0.0",
|
||||
"zustand": "^3.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.1.0",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/d3-drag": "^3.0.1",
|
||||
"@types/d3-selection": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,18 @@ import shallow from 'zustand/shallow';
|
||||
import {
|
||||
useStore,
|
||||
getRectOfNodes,
|
||||
Box,
|
||||
ReactFlowState,
|
||||
Rect,
|
||||
Panel,
|
||||
getBoundsOfRects,
|
||||
} from '@react-flow/core';
|
||||
import { injectStyle } from '@react-flow/css-utils';
|
||||
|
||||
import MiniMapNode from './MiniMapNode';
|
||||
import MiniMapDrag from './MiniMapDrag';
|
||||
import { MiniMapProps, GetMiniMapNodeAttribute } from './types';
|
||||
import baseStyle from './style';
|
||||
|
||||
import './style.css';
|
||||
injectStyle(baseStyle);
|
||||
|
||||
declare const window: any;
|
||||
|
||||
@@ -30,30 +32,6 @@ const selector = (s: ReactFlowState) => ({
|
||||
const getAttrFunction = (func: any): GetMiniMapNodeAttribute =>
|
||||
func instanceof Function ? func : () => func;
|
||||
|
||||
export const getBoundsOfBoxes = (box1: Box, box2: Box): Box => ({
|
||||
x: Math.min(box1.x, box2.x),
|
||||
y: Math.min(box1.y, box2.y),
|
||||
x2: Math.max(box1.x2, box2.x2),
|
||||
y2: Math.max(box1.y2, box2.y2),
|
||||
});
|
||||
|
||||
export const rectToBox = ({ x, y, width, height }: Rect): Box => ({
|
||||
x,
|
||||
y,
|
||||
x2: x + width,
|
||||
y2: y + height,
|
||||
});
|
||||
|
||||
export const boxToRect = ({ x, y, x2, y2 }: Box): Rect => ({
|
||||
x,
|
||||
y,
|
||||
width: x2 - x,
|
||||
height: y2 - y,
|
||||
});
|
||||
|
||||
export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
|
||||
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
||||
|
||||
const ARIA_LABEL_KEY = 'react-flow__minimap-desc';
|
||||
|
||||
function MiniMap({
|
||||
@@ -65,6 +43,7 @@ function MiniMap({
|
||||
nodeBorderRadius = 5,
|
||||
nodeStrokeWidth = 2,
|
||||
maskColor = 'rgb(240, 242, 243, 0.7)',
|
||||
position = 'bottom-right',
|
||||
}: MiniMapProps) {
|
||||
const minimapId = useId();
|
||||
const {
|
||||
@@ -85,7 +64,7 @@ function MiniMap({
|
||||
height: containerHeight / transform[2],
|
||||
};
|
||||
const boundingRect =
|
||||
nodes.length > 0 ? getBoundsofRects(getRectOfNodes(nodes), viewBB) : viewBB;
|
||||
nodes.length > 0 ? getBoundsOfRects(getRectOfNodes(nodes), viewBB) : viewBB;
|
||||
const scaledWidth = boundingRect.width / elementWidth;
|
||||
const scaledHeight = boundingRect.height / elementHeight;
|
||||
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||
@@ -103,54 +82,52 @@ function MiniMap({
|
||||
const labelledBy = `${ARIA_LABEL_KEY}-${minimapId}`;
|
||||
|
||||
return (
|
||||
<svg
|
||||
width={elementWidth}
|
||||
height={elementHeight}
|
||||
viewBox={`${x} ${y} ${width} ${height}`}
|
||||
<Panel
|
||||
position={position}
|
||||
style={style}
|
||||
className={cc(['react-flow__minimap', className])}
|
||||
role="img"
|
||||
aria-labelledby={labelledBy}
|
||||
>
|
||||
<title id={labelledBy}>React Flow mini map</title>
|
||||
{nodes
|
||||
.filter((node) => !node.hidden && node.width && node.height)
|
||||
.map((node) => {
|
||||
return (
|
||||
<MiniMapNode
|
||||
key={node.id}
|
||||
x={node.positionAbsolute?.x ?? 0}
|
||||
y={node.positionAbsolute?.y ?? 0}
|
||||
width={node.width!}
|
||||
height={node.height!}
|
||||
style={node.style}
|
||||
className={nodeClassNameFunc(node)}
|
||||
color={nodeColorFunc(node)}
|
||||
borderRadius={nodeBorderRadius}
|
||||
strokeColor={nodeStrokeColorFunc(node)}
|
||||
strokeWidth={nodeStrokeWidth}
|
||||
shapeRendering={shapeRendering}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<MiniMapDrag
|
||||
x={viewBB.x}
|
||||
y={viewBB.y}
|
||||
width={viewBB.width}
|
||||
height={viewBB.height}
|
||||
/>
|
||||
<path
|
||||
className="react-flow__minimap-mask"
|
||||
d={`M${x - offset},${y - offset}h${width + offset * 2}v${
|
||||
height + offset * 2
|
||||
}h${-width - offset * 2}z
|
||||
<svg
|
||||
width={elementWidth}
|
||||
height={elementHeight}
|
||||
viewBox={`${x} ${y} ${width} ${height}`}
|
||||
role="img"
|
||||
aria-labelledby={labelledBy}
|
||||
>
|
||||
<title id={labelledBy}>React Flow mini map</title>
|
||||
{nodes
|
||||
.filter((node) => !node.hidden && node.width && node.height)
|
||||
.map((node) => {
|
||||
return (
|
||||
<MiniMapNode
|
||||
key={node.id}
|
||||
x={node.positionAbsolute?.x ?? 0}
|
||||
y={node.positionAbsolute?.y ?? 0}
|
||||
width={node.width!}
|
||||
height={node.height!}
|
||||
style={node.style}
|
||||
className={nodeClassNameFunc(node)}
|
||||
color={nodeColorFunc(node)}
|
||||
borderRadius={nodeBorderRadius}
|
||||
strokeColor={nodeStrokeColorFunc(node)}
|
||||
strokeWidth={nodeStrokeWidth}
|
||||
shapeRendering={shapeRendering}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<path
|
||||
className="react-flow__minimap-mask"
|
||||
d={`M${x - offset},${y - offset}h${width + offset * 2}v${
|
||||
height + offset * 2
|
||||
}h${-width - offset * 2}z
|
||||
M${viewBB.x},${viewBB.y}h${viewBB.width}v${
|
||||
viewBB.height
|
||||
}h${-viewBB.width}z`}
|
||||
fill={maskColor}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
viewBB.height
|
||||
}h${-viewBB.width}z`}
|
||||
fill={maskColor}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { drag, D3DragEvent, SubjectPosition } from 'd3-drag';
|
||||
import { select } from 'd3-selection';
|
||||
import { useReactFlow } from '@react-flow/core';
|
||||
|
||||
function MiniMapDrag({ x = 0, y = 0, width = 0, height = 0 }) {
|
||||
const dragRef = useRef<SVGRectElement>(null);
|
||||
const { getViewport, setViewport } = useReactFlow();
|
||||
|
||||
useEffect(() => {
|
||||
if (dragRef.current) {
|
||||
const onDrag = (
|
||||
evt: D3DragEvent<SVGRectElement, null, SubjectPosition>
|
||||
) => {
|
||||
const { x, y, zoom } = getViewport();
|
||||
setViewport({ x: x - evt.dx * zoom, y: y - evt.dy * zoom, zoom });
|
||||
};
|
||||
|
||||
const selection = select(dragRef.current as Element);
|
||||
const dragBehaviour = drag().on('drag', onDrag);
|
||||
|
||||
selection.call(dragBehaviour);
|
||||
|
||||
return () => {
|
||||
selection.on('.drag', null);
|
||||
};
|
||||
}
|
||||
}, [getViewport, setViewport]);
|
||||
|
||||
return (
|
||||
<rect
|
||||
ref={dragRef}
|
||||
fill='rgba(255, 0,0,.5)'
|
||||
x={x}
|
||||
y={y}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default MiniMapDrag;
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from './types';
|
||||
export { default as MiniMap, default } from './MiniMap';
|
||||
export { default as MiniMap } from './MiniMap';
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.react-flow__minimap {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
bottom: 20px;
|
||||
right: 15px;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
const style = `
|
||||
.react-flow__minimap {
|
||||
background-color: #fff;
|
||||
}`;
|
||||
|
||||
export default style;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { HTMLAttributes } from 'react';
|
||||
import { Node } from '@react-flow/core';
|
||||
import { Node, PanelPosition } from '@react-flow/core';
|
||||
|
||||
export type GetMiniMapNodeAttribute<NodeData = any> = (
|
||||
node: Node<NodeData>
|
||||
@@ -13,4 +13,5 @@ export interface MiniMapProps<NodeData = any>
|
||||
nodeBorderRadius?: number;
|
||||
nodeStrokeWidth?: number;
|
||||
maskColor?: string;
|
||||
position?: PanelPosition;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@react-flow/renderer",
|
||||
"version": "11.0.0",
|
||||
"description": "The main React Flow package that comes with all the essentials.",
|
||||
"main": "dist/react-flow-renderer.cjs.js",
|
||||
"module": "dist/react-flow-renderer.esm.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "postcss src/*.css --config ../../tooling/postcss.config.json --dir dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-flow/background": "11.0.0",
|
||||
"@react-flow/controls": "11.0.0",
|
||||
"@react-flow/core": "11.0.0",
|
||||
"@react-flow/minimap": "11.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.1.0",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.8",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-cli": "^10.0.0",
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-nested": "^5.0.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from '@react-flow/core';
|
||||
export * from '@react-flow/minimap';
|
||||
export * from '@react-flow/controls';
|
||||
export * from '@react-flow/background';
|
||||
@@ -0,0 +1 @@
|
||||
@import '@react-flow/core/dist/theme-default.css';
|
||||
Reference in New Issue
Block a user