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:
Moritz Klack
2022-08-05 18:36:32 +02:00
committed by GitHub
parent af28431990
commit 97c22ace71
89 changed files with 1853 additions and 20334 deletions
@@ -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>
);
+3 -5
View File
@@ -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';
-180
View File
@@ -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%);
}
}
+226
View File
@@ -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;
+9
View File
@@ -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;
}
}
+1 -7
View File
@@ -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;
+1 -1
View File
@@ -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);