refactor(styling): use css for default styles (#259)
* refactor(minimap): use css for default styles * refactor(controls): use css for default styles * refactor(background): use css for default styles * refactor(edges): add edge type class name * refactor(nodes): use css for default styles * refactor(outputnode): add display name * refactor(wrapnode): cleanup * refactor(rollup): minimize css for prod build * refactor(additional-comps): extract css * test(graphs): adjust for new markup
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import React, { memo, HTMLAttributes, CSSProperties } from 'react';
|
||||
import React, { memo, HTMLAttributes } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
import { BackgroundVariant } from '../../types';
|
||||
import { createGridLinesPath, createGridDotsPath } from './utils';
|
||||
|
||||
import './style.css';
|
||||
|
||||
interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
||||
variant?: BackgroundVariant;
|
||||
gap?: number;
|
||||
@@ -12,19 +14,13 @@ interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const baseStyles: CSSProperties = {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
const defaultColors = {
|
||||
[BackgroundVariant.Dots]: '#999',
|
||||
[BackgroundVariant.Lines]: '#eee',
|
||||
};
|
||||
|
||||
const Background = memo(
|
||||
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style = {}, className = '' }: BackgroundProps) => {
|
||||
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style, className }: BackgroundProps) => {
|
||||
const width = useStoreState((s) => s.width);
|
||||
const height = useStoreState((s) => s.height);
|
||||
const [x, y, scale] = useStoreState((s) => s.transform);
|
||||
@@ -42,7 +38,7 @@ const Background = memo(
|
||||
const stroke = isLines ? bgColor : 'none';
|
||||
|
||||
return (
|
||||
<svg width={width} height={height} style={{ ...baseStyles, ...style }} className={bgClasses}>
|
||||
<svg width={width} height={height} style={style} className={bgClasses}>
|
||||
<path fill={fill} stroke={stroke} strokeWidth={size} d={path} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.react-flow__background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
||||
@@ -10,12 +10,7 @@ import FitviewIcon from '../../../assets/icons/fitview.svg';
|
||||
import LockIcon from '../../../assets/icons/lock.svg';
|
||||
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
||||
|
||||
const baseStyle: CSSProperties = {
|
||||
position: 'absolute',
|
||||
zIndex: 5,
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
};
|
||||
import './style.css';
|
||||
|
||||
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
showZoom?: boolean;
|
||||
@@ -26,16 +21,10 @@ interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||
const mapClasses: string = classnames('react-flow__controls', className);
|
||||
const mapClasses = classnames('react-flow__controls', className);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={mapClasses}
|
||||
style={{
|
||||
...baseStyle,
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
<div className={mapClasses} style={style}>
|
||||
{showZoom && (
|
||||
<>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={zoomIn}>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
.react-flow__controls {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
|
||||
&-button {
|
||||
background: #fefefe;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 5px;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ const MiniMapNode = ({ node, color, borderRadius }: MiniMapNodeProps) => {
|
||||
} = node.__rg;
|
||||
const { background, backgroundColor } = node.style || {};
|
||||
const fill = (background || backgroundColor || color) as string;
|
||||
|
||||
return (
|
||||
<rect
|
||||
className="react-flow__minimap-node"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
@@ -6,6 +6,8 @@ import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
|
||||
import { Node, Rect } from '../../types';
|
||||
import MiniMapNode from './MiniMapNode';
|
||||
|
||||
import './style.css';
|
||||
|
||||
type StringFunc = (node: Node) => string;
|
||||
|
||||
interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
||||
@@ -14,14 +16,8 @@ interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
||||
maskColor?: string;
|
||||
}
|
||||
|
||||
const baseStyle: CSSProperties = {
|
||||
position: 'absolute',
|
||||
zIndex: 5,
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
width: 200,
|
||||
height: 150,
|
||||
};
|
||||
const defaultWidth = 200;
|
||||
const defaultHeight = 150;
|
||||
|
||||
const MiniMap = ({
|
||||
style = { backgroundColor: '#f8f8f8' },
|
||||
@@ -36,11 +32,10 @@ const MiniMap = ({
|
||||
const nodes = useStoreState((s) => s.nodes);
|
||||
|
||||
const mapClasses = classnames('react-flow__minimap', className);
|
||||
const elementWidth = (style.width || baseStyle.width)! as number;
|
||||
const elementHeight = (style.height || baseStyle.height)! as number;
|
||||
const elementWidth = (style.width || defaultWidth)! as number;
|
||||
const elementHeight = (style.height || defaultHeight)! as number;
|
||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
||||
const hasNodes = nodes && nodes.length;
|
||||
|
||||
const bb = getRectOfNodes(nodes);
|
||||
const viewBB: Rect = {
|
||||
x: -tX / tScale,
|
||||
@@ -48,17 +43,13 @@ const MiniMap = ({
|
||||
width: containerWidth / tScale,
|
||||
height: containerHeight / tScale,
|
||||
};
|
||||
|
||||
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
||||
|
||||
const scaledWidth = boundingRect.width / elementWidth;
|
||||
const scaledHeight = boundingRect.height / elementHeight;
|
||||
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||
const viewWidth = viewScale * elementWidth;
|
||||
const viewHeight = viewScale * elementHeight;
|
||||
|
||||
const offset = 5 * viewScale;
|
||||
|
||||
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
||||
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
||||
const width = viewWidth + offset * 2;
|
||||
@@ -69,10 +60,7 @@ const MiniMap = ({
|
||||
width={elementWidth}
|
||||
height={elementHeight}
|
||||
viewBox={`${x} ${y} ${width} ${height}`}
|
||||
style={{
|
||||
...baseStyle,
|
||||
...style,
|
||||
}}
|
||||
style={style}
|
||||
className={mapClasses}
|
||||
>
|
||||
{nodes.map((node) => (
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.react-flow__minimap {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export default memo(
|
||||
labelStyle,
|
||||
labelShowBg,
|
||||
labelBgStyle,
|
||||
style = {},
|
||||
style,
|
||||
}: EdgeBezierProps) => {
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||
|
||||
@@ -4,7 +4,7 @@ import EdgeText from './EdgeText';
|
||||
import { EdgeProps } from '../../types';
|
||||
|
||||
export default memo(
|
||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
|
||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => {
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import EdgeText from './EdgeText';
|
||||
import { EdgeProps } from '../../types';
|
||||
|
||||
export default memo(
|
||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
|
||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => {
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ interface EdgeWrapperProps {
|
||||
labelStyle?: CSSProperties;
|
||||
labelShowBg?: boolean;
|
||||
labelBgStyle: CSSProperties;
|
||||
className?: string;
|
||||
onClick?: (edge: Edge) => void;
|
||||
animated: boolean;
|
||||
animated?: boolean;
|
||||
selected: boolean;
|
||||
isInteractive: boolean;
|
||||
}
|
||||
@@ -34,9 +35,10 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
labelStyle,
|
||||
labelShowBg,
|
||||
labelBgStyle,
|
||||
className,
|
||||
...rest
|
||||
}: EdgeWrapperProps) => {
|
||||
const edgeClasses = cx('react-flow__edge', { selected, animated });
|
||||
const edgeClasses = cx('react-flow__edge', `react-flow__edge-${type}`, className, { selected, animated });
|
||||
const edgeGroupStyle: CSSProperties = {
|
||||
pointerEvents: isInteractive ? 'all' : 'none',
|
||||
};
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, Position } from '../../types';
|
||||
|
||||
const nodeStyles: CSSProperties = {
|
||||
background: '#ff6060',
|
||||
padding: 10,
|
||||
borderRadius: 5,
|
||||
width: 150,
|
||||
};
|
||||
|
||||
export default ({ data, targetPosition = Position.Top, sourcePosition = Position.Bottom, style }: NodeProps) => (
|
||||
<div style={{ ...nodeStyles, ...style }}>
|
||||
const DefaultNode = ({ data, targetPosition = Position.Top, sourcePosition = Position.Bottom }: NodeProps) => (
|
||||
<>
|
||||
<Handle type="target" position={targetPosition} />
|
||||
{data.label}
|
||||
<Handle type="source" position={sourcePosition} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
DefaultNode.displayName = 'DefaultNode';
|
||||
|
||||
export default DefaultNode;
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, Position } from '../../types';
|
||||
|
||||
const nodeStyles: CSSProperties = {
|
||||
background: '#9999ff',
|
||||
padding: 10,
|
||||
borderRadius: 5,
|
||||
width: 150,
|
||||
};
|
||||
|
||||
export default ({ data, style, sourcePosition = Position.Bottom }: NodeProps) => (
|
||||
<div style={{ ...nodeStyles, ...style }}>
|
||||
const InputNode = ({ data, sourcePosition = Position.Bottom }: NodeProps) => (
|
||||
<>
|
||||
{data.label}
|
||||
<Handle type="source" position={sourcePosition} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
InputNode.displayName = 'InputNode';
|
||||
|
||||
export default InputNode;
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, Position } from '../../types';
|
||||
|
||||
const nodeStyles: CSSProperties = {
|
||||
background: '#55dd99',
|
||||
padding: 10,
|
||||
borderRadius: 5,
|
||||
width: 150,
|
||||
};
|
||||
|
||||
export default ({ data, style, targetPosition = Position.Top }: NodeProps) => (
|
||||
<div style={{ ...nodeStyles, ...style }}>
|
||||
const OutputNode = ({ data, targetPosition = Position.Top }: NodeProps) => (
|
||||
<>
|
||||
<Handle type="target" position={targetPosition} />
|
||||
{data.label}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
OutputNode.displayName = 'OutputNode';
|
||||
|
||||
export default OutputNode;
|
||||
|
||||
@@ -158,23 +158,16 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
zIndex: selected ? 10 : 3,
|
||||
transform: `translate(${xPos}px,${yPos}px)`,
|
||||
pointerEvents: isInteractive ? 'all' : 'none',
|
||||
};
|
||||
|
||||
const updateNode = (): void => {
|
||||
if (!nodeElement.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current });
|
||||
...style,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeElement.current) {
|
||||
updateNode();
|
||||
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current });
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let _ of entries) {
|
||||
updateNode();
|
||||
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current! });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -188,7 +181,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
}
|
||||
|
||||
return;
|
||||
}, []);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<DraggableCore
|
||||
@@ -219,7 +212,6 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
id={id}
|
||||
data={data}
|
||||
type={type}
|
||||
style={style}
|
||||
selected={selected}
|
||||
sourcePosition={sourcePosition}
|
||||
targetPosition={targetPosition}
|
||||
|
||||
+26
-35
@@ -60,6 +60,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dashdraw {
|
||||
from {
|
||||
stroke-dashoffset: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__connection {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -85,12 +91,6 @@
|
||||
fill: white;
|
||||
}
|
||||
|
||||
@keyframes dashdraw {
|
||||
from {
|
||||
stroke-dashoffset: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__nodes {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -110,13 +110,17 @@
|
||||
pointer-events: all;
|
||||
transform-origin: 0 0;
|
||||
cursor: grab;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
width: 150px;
|
||||
background: #eee;
|
||||
|
||||
&.selected > *,
|
||||
&.selected:hover > * {
|
||||
&.selected,
|
||||
&.selected:hover {
|
||||
box-shadow: 0 0 0 2px #555;
|
||||
}
|
||||
|
||||
&:hover > * {
|
||||
&:hover {
|
||||
box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
@@ -125,6 +129,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__node-default {
|
||||
background: #ff6060;
|
||||
}
|
||||
|
||||
.react-flow__node-input {
|
||||
background: #9999ff;
|
||||
}
|
||||
|
||||
.react-flow__node-output {
|
||||
background: #55dd99;
|
||||
}
|
||||
|
||||
.react-flow__handle {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
@@ -173,29 +189,4 @@
|
||||
border: 1px dotted rgba(0, 89, 220, 0.8);
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
.react-flow__controls {
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
|
||||
&-button {
|
||||
background: #fefefe;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 5px;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,6 @@ export interface NodeProps {
|
||||
selected: boolean;
|
||||
targetPosition?: Position;
|
||||
sourcePosition?: Position;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export interface NodeComponentProps {
|
||||
|
||||
Reference in New Issue
Block a user