Skip to content

Commit

Permalink
read only graph config and remove unsafe register component (#51)
Browse files Browse the repository at this point in the history
* delete register components

* refactor graph config

* sort import

* migrate models

* migrate code

* fix graph config builder

* fix

* fix demo

* fix unit tests
  • Loading branch information
intellild committed Aug 23, 2021
1 parent 35171c3 commit df9ea14
Show file tree
Hide file tree
Showing 57 changed files with 595 additions and 928 deletions.
2 changes: 1 addition & 1 deletion packages/ReactDagEditor/src/built-in/defaultGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { IGroupConfig, IGroupDrawArgs } from "../contexts/GraphConfigContext";
import { IGroupConfig, IGroupDrawArgs } from "../models/config/types";

const Renderer: React.FC<IGroupDrawArgs> = props => (
<rect height={props.height} width={props.width} fill={props.group.fill} />
Expand Down
34 changes: 8 additions & 26 deletions packages/ReactDagEditor/src/built-in/defaultPort.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from "react";
import { IPortConfig, IPortDrawArgs, ITheme } from "../contexts";
import { ICanvasNode } from "../models/node";
import { ICanvasPort } from "../models/port";
import type { ITheme } from "../contexts";
import type { ICanvasNode } from "../models/node";
import type { ICanvasPort } from "../models/port";
import { GraphPortState } from "../models/element-state";
import { GraphModel } from "../models/GraphModel";
import { hasState } from "../utils";
import type { IPortConfig, IPortDrawArgs } from "../models/config/types";

class DefaultPort implements IPortConfig {
public getStyle(
Expand Down Expand Up @@ -39,23 +40,10 @@ class DefaultPort implements IPortConfig {
public render(args: IPortDrawArgs): React.ReactNode {
const { model: port, data, parentNode } = args;

const connectedAsSource = data.isPortConnectedAsSource(
parentNode.id,
port.id
);
const connectedAsTarget = data.isPortConnectedAsTarget(
parentNode.id,
port.id
);
const connectedAsSource = data.isPortConnectedAsSource(parentNode.id, port.id);
const connectedAsTarget = data.isPortConnectedAsTarget(parentNode.id, port.id);

const style = this.getStyle(
port,
parentNode,
data,
args.theme,
connectedAsSource,
connectedAsTarget
);
const style = this.getStyle(port, parentNode, data, args.theme, connectedAsSource, connectedAsTarget);

const { x, y } = args;
const polygonPoints = `${x - 5} ${y}, ${x + 7} ${y}, ${x + 1} ${y + 8}`;
Expand All @@ -65,13 +53,7 @@ class DefaultPort implements IPortConfig {
{connectedAsTarget ? (
<polygon points={polygonPoints} style={style} />
) : (
<circle
key={`${args.parentNode.id}-${args.model.id}`}
r={5}
cx={x}
cy={y}
style={style}
/>
<circle key={`${args.parentNode.id}-${args.model.id}`} r={5} cx={x} cy={y} style={style} />
)}
</>
);
Expand Down
9 changes: 4 additions & 5 deletions packages/ReactDagEditor/src/built-in/line.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import * as React from "react";
import { IEdgeConfig, ITheme } from "../contexts";
import { ICanvasEdge } from "../models/edge";
import type { ITheme } from "../contexts";
import type { IEdgeConfig } from "../models/config/types";
import type { ICanvasEdge } from "../models/edge";
import { GraphEdgeState } from "../models/element-state";
import { getCurvePathD, hasState } from "../utils";

export const line: IEdgeConfig = {
getStyle(edge: ICanvasEdge, theme: ITheme): React.CSSProperties {
return {
cursor: "crosshair",
stroke: hasState(GraphEdgeState.selected)(edge.state)
? theme.edgeColorSelected
: theme.edgeColor,
stroke: hasState(GraphEdgeState.selected)(edge.state) ? theme.edgeColorSelected : theme.edgeColor,
strokeWidth: "2"
};
},
Expand Down
25 changes: 8 additions & 17 deletions packages/ReactDagEditor/src/built-in/rect.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import * as React from "react";
import { INodeDrawArgs, IRectConfig, ITheme } from "../contexts";
import { ICanvasNode } from "../models/node";
import type { ITheme } from "../contexts";
import type { INodeConfig, INodeDrawArgs } from "../models/config/types";
import type { ICanvasNode } from "../models/node";
import { GraphNodeState } from "../models/element-state";
import { hasState } from "../utils";
import { getRectHeight, getRectWidth } from "../utils/layout";
import { RectComponent } from "./RectComponent";

export const rect: IRectConfig<ICanvasNode> = {
export const rect: INodeConfig = {
getMinHeight(): number {
return 150;
},
getMinWidth(): number {
return 150;
},
getStyle(node: ICanvasNode, theme: ITheme): Partial<React.CSSProperties> {
if (
hasState(GraphNodeState.selected | GraphNodeState.activated)(node.state)
) {
if (hasState(GraphNodeState.selected | GraphNodeState.activated)(node.state)) {
return {
fill: theme.nodeActivateFill,
stroke: theme.nodeActivateStroke
Expand All @@ -33,19 +32,11 @@ export const rect: IRectConfig<ICanvasNode> = {
render(args: INodeDrawArgs): React.ReactNode {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const node = args.model as ICanvasNode<any, any>;
const width = getRectWidth<ICanvasNode>(rect, node);
const height = getRectHeight<ICanvasNode>(rect, node);
const width = getRectWidth(rect, node);
const height = getRectHeight(rect, node);
const style = rect.getStyle ? rect.getStyle(node, args.theme) : {};
const textY = node.y + height / 3;

return (
<RectComponent
style={style}
node={node}
width={width}
height={height}
textY={textY}
/>
);
return <RectComponent style={style} node={node} width={width} height={height} textY={textY} />;
}
};
6 changes: 3 additions & 3 deletions packages/ReactDagEditor/src/components/AnimatingNodeGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from "react";
import { useTheme } from "../hooks";
import { useGraphConfig } from "../hooks/context";
import { IDummyNodes } from "../models/dummy-node";
import { GraphModel } from "../models/GraphModel";
import type { IDummyNodes } from "../models/dummy-node";
import type { GraphModel } from "../models/GraphModel";
import { getNodeConfig } from "../utils";

interface IAnimatingNodeGroup {
Expand Down Expand Up @@ -30,7 +30,7 @@ export const AnimatingNodeGroup: React.FunctionComponent<IAnimatingNodeGroup> =
const height = dummyNode.height + dHeight;
const nodeConfig = getNodeConfig(node, graphConfig);

if (nodeConfig.renderDummy) {
if (nodeConfig?.renderDummy) {
return nodeConfig.renderDummy(
{
...node.inner,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from "react";
import { IGraphConfig } from "../../contexts";
import { useConnectingState } from "../../hooks/context";
import { IPoint, IViewport } from "../../models/geometry";
import type { IGraphConfig } from "../../models/config/types";
import type { IPoint, IViewport } from "../../models/geometry";
import { transformPoint } from "../../utils";
import { EventChannel } from "../../utils/eventChannel";
import type { EventChannel } from "../../utils/eventChannel";
import { emptyLine, ILine } from "../Line";
import { ConnectingLine } from "./ConnectingLine";

Expand Down
15 changes: 3 additions & 12 deletions packages/ReactDagEditor/src/components/Graph/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import {
useUpdateViewportCallback,
useWheelHandler
} from "../../hooks";
import { useGraphConfig, useGraphController } from "../../hooks/context";
import { useConst } from "../../hooks/useConst";
import { useEventChannel } from "../../hooks/useEventChannel";
import { useFeatureControl } from "../../hooks/useFeatureControl";
import { useGraphConfig, useGraphController } from "../../hooks/context";
import { GraphCanvasEvent, GraphContextMenuEvent, ICanvasCommonEvent, ICanvasKeyboardEvent } from "../../models/event";
import { IContainerRect, IViewport } from "../../models/geometry";
import type { IContainerRect, IViewport } from "../../models/geometry";
import { GraphBehavior } from "../../models/state";
import { isSelected, isSupported, isViewportComplete } from "../../utils";
import { defaultGetNodeAriaLabel, defaultGetPortAriaLabel } from "../../utils/a11yUtils";
Expand All @@ -35,7 +35,7 @@ import { EdgeTree } from "../tree/EdgeTree";
import { NodeTree } from "../tree/NodeTree";
import { VirtualizationProvider } from "../VirtualizationProvider";
import { getGraphStyles } from "./Graph.styles";
import { IGraphProps } from "./IGraphProps";
import type { IGraphProps } from "./IGraphProps";
import { SelectBox } from "./SelectBox";

export function Graph<NodeData = unknown, EdgeData = unknown, PortData = unknown>(
Expand All @@ -54,10 +54,6 @@ export function Graph<NodeData = unknown, EdgeData = unknown, PortData = unknown
const defaultSVGRef = React.useRef<SVGSVGElement>(null);

const {
defaultNodeShape = "default",
defaultEdgeShape = "default",
defaultPortShape = "default",
defaultGroupShape = "default",
focusCanvasAccessKey = "f",
zoomSensitivity = 0.1,
scrollSensitivity = 0.5,
Expand All @@ -69,11 +65,6 @@ export function Graph<NodeData = unknown, EdgeData = unknown, PortData = unknown
const graphConfig = useGraphConfig();
const featureControl = useFeatureControl(state.settings.features);

graphConfig.defaultNodeShape = defaultNodeShape;
graphConfig.defaultEdgeShape = defaultEdgeShape;
graphConfig.defaultPortShape = defaultPortShape;
graphConfig.defaultGroupShape = defaultGroupShape;

const [curHoverNode, setCurHoverNode] = React.useState<string>();
const [curHoverPort, setCurHoverPort] = React.useState<[string, string] | undefined>(undefined);

Expand Down
38 changes: 20 additions & 18 deletions packages/ReactDagEditor/src/components/Graph/GraphStateStore.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as React from "react";
import { ConnectingState } from "../../ConnectingState";
import { EMPTY_GAP, EMPTY_TRANSFORM_MATRIX, IGraphReducer, ViewportContext } from "../../contexts";
import { EMPTY_GAP, EMPTY_TRANSFORM_MATRIX, GraphConfigContext, IGraphReducer, ViewportContext } from "../../contexts";
import { AlignmentLinesContext } from "../../contexts/AlignmentLinesContext";
import { GraphControllerContext } from "../../contexts/GraphControllerContext";
import { GraphStateContext, GraphValueContext } from "../../contexts/GraphStateContext";
import { GraphController } from "../../controllers/GraphController";
import { defaultFeatures, GraphFeatures } from "../../Features";
import { useConst } from "../../hooks/useConst";
import { useGraphConfig } from "../../hooks/context";
import { useGraphReducer } from "../../hooks/useGraphReducer";
import { IGraphConfig } from "../../models/config/types";
import { IGap, ITransformMatrix } from "../../models/geometry";
import { GraphModel } from "../../models/GraphModel";

Expand All @@ -21,6 +21,7 @@ export interface IGraphStateStoreProps<NodeData = unknown, EdgeData = unknown, P
middleware?: IGraphReducer<NodeData, EdgeData, PortData, Action>;
features?: ReadonlySet<GraphFeatures>;
canvasBoundaryPadding?: IGap;
graphConfig: IGraphConfig;
}

export function GraphStateStore<NodeData = unknown, EdgeData = unknown, PortData = unknown, Action = never>(
Expand All @@ -30,11 +31,10 @@ export function GraphStateStore<NodeData = unknown, EdgeData = unknown, PortData
defaultTransformMatrix = EMPTY_TRANSFORM_MATRIX,
middleware,
features = defaultFeatures,
canvasBoundaryPadding = EMPTY_GAP
canvasBoundaryPadding = EMPTY_GAP,
graphConfig
} = props;

const graphConfig = useGraphConfig();

const [state, dispatch] = useGraphReducer(
{
data: props.data,
Expand Down Expand Up @@ -72,18 +72,20 @@ export function GraphStateStore<NodeData = unknown, EdgeData = unknown, PortData
);

return (
<GraphControllerContext.Provider value={graphController}>
<ConnectingState data={state.data.present} connectState={state.connectState}>
<GraphStateContext.Provider value={contextValue}>
<ViewportContext.Provider value={state.viewport}>
<GraphValueContext.Provider value={state.data.present}>
<AlignmentLinesContext.Provider value={state.alignmentLines}>
{props.children}
</AlignmentLinesContext.Provider>
</GraphValueContext.Provider>
</ViewportContext.Provider>
</GraphStateContext.Provider>
</ConnectingState>
</GraphControllerContext.Provider>
<GraphConfigContext.Provider value={graphConfig}>
<GraphControllerContext.Provider value={graphController}>
<ConnectingState data={state.data.present} connectState={state.connectState}>
<GraphStateContext.Provider value={contextValue}>
<ViewportContext.Provider value={state.viewport}>
<GraphValueContext.Provider value={state.data.present}>
<AlignmentLinesContext.Provider value={state.alignmentLines}>
{props.children}
</AlignmentLinesContext.Provider>
</GraphValueContext.Provider>
</ViewportContext.Provider>
</GraphStateContext.Provider>
</ConnectingState>
</GraphControllerContext.Provider>
</GraphConfigContext.Provider>
);
}
24 changes: 0 additions & 24 deletions packages/ReactDagEditor/src/components/Graph/IGraphProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,6 @@ export interface IGraphProps<NodeData = unknown, EdgeData = unknown, PortData =
* The ref of the svg element
*/
svgRef?: React.RefObject<SVGSVGElement>;
/**
* The default shape of the node
*
* @default "default"
*/
defaultNodeShape?: string;
/**
* The default shape of the edge
*
* @default "default"
*/
defaultEdgeShape?: string;
/**
* The default shape of the port
*
* @default "default"
*/
defaultPortShape?: string;
/**
* The default shape of the group
*
* @default "default"
*/
defaultGroupShape?: string;
/**
* The access key to focus the canvas
*
Expand Down
2 changes: 1 addition & 1 deletion packages/ReactDagEditor/src/components/GraphNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const GraphNode: React.FunctionComponent<IGraphNodeProps> = props => {

const automationId = node.automationId ?? getNodeAutomationId(node);

if (!nodeConfig.render) {
if (!nodeConfig?.render) {
Debug.warn(`Missing "render" method in node config ${shape}`);

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export const GraphNodeControlPoints: React.FunctionComponent<IGraphNodeControlPo
const nodeConfig = getNodeConfig(node, graphConfig);
const graphController = useGraphController();

const minWidth = nodeConfig.getMinWidth(node);
const minHeight = nodeConfig.getMinHeight(node);
const minWidth = nodeConfig?.getMinWidth(node) ?? 0;
const minHeight = nodeConfig?.getMinHeight(node) ?? 0;

const { theme } = useTheme();

Expand Down
10 changes: 5 additions & 5 deletions packages/ReactDagEditor/src/components/ItemPanel/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import * as React from "react";
import * as ReactDOM from "react-dom";
import { v4 as uuid } from "uuid";
import { MouseEventButton } from "../../common/constants";
import { emptyNodeConfig, IRectConfig } from "../../contexts";
import { defaultGetPositionFromEvent, DragController } from "../../controllers";
import { PointerEventProvider } from "../../event-provider/PointerEventProvider";
import { GraphFeatures } from "../../Features";
import { useGraphConfig, useGraphController } from "../../hooks/context";
import { useRefValue } from "../../hooks/useRefValue";
import { INodeConfig } from "../../models/config/types";
import { GraphCanvasEvent } from "../../models/event";
import { IContainerRect, IPoint, ITransformMatrix } from "../../models/geometry";
import { ICanvasNode } from "../../models/node";
Expand Down Expand Up @@ -83,13 +83,13 @@ const adjustedClientPoint = (
};

// adjust position to the middle of the node, and with the correct zoom/pan
const adjustPosition = <T extends { width?: number; height?: number }>(
const adjustPosition = (
clientX: number,
clientY: number,
rect: IContainerRect | undefined,
transformMatrix: ITransformMatrix,
node: T,
nodeConfig: IRectConfig<T>
node: Partial<ICanvasNode>,
nodeConfig: INodeConfig | undefined
): IPoint => {
const rectWidth = getRectWidth(nodeConfig, node);
const rectHeight = getRectHeight(nodeConfig, node);
Expand Down Expand Up @@ -126,7 +126,7 @@ export const Item: React.FunctionComponent<IItemProps> = props => {
return;
}
const shape = props.shape || model.shape;
const nodeConfig = graphConfig.getNodeConfigByName(shape) ?? emptyNodeConfig;
const nodeConfig = graphConfig.getNodeConfigByName(shape);

const node: ICanvasNode = {
...deepClone(model),
Expand Down
6 changes: 3 additions & 3 deletions packages/ReactDagEditor/src/components/NodeTooltips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as React from "react";
import { useGraphConfig } from "../hooks/context";
import { GraphNodeState } from "../models/element-state";
import { useTheme } from "../hooks";
import { IViewport } from "../models/geometry";
import { NodeModel } from "../models/NodeModel";
import type { IViewport } from "../models/geometry";
import type { NodeModel } from "../models/NodeModel";
import { getNodeConfig, hasState } from "../utils";

interface IProps {
Expand All @@ -26,7 +26,7 @@ export const NodeTooltips: React.FunctionComponent<IProps> = props => {

const nodeConfig = getNodeConfig(node, graphConfig);

if (!nodeConfig.renderTooltips) {
if (!nodeConfig?.renderTooltips) {
return null;
}

Expand Down

0 comments on commit df9ea14

Please sign in to comment.