Skip to content

Commit

Permalink
add more control for nodes and edges (#113)
Browse files Browse the repository at this point in the history
* add more control for nodes and edges

* add Edge stories

Co-authored-by: Joshua Weinstein <jweinstein@flashpoint-intel.com>
  • Loading branch information
jweinstein92 and jweinstein92 committed Oct 25, 2021
1 parent fadc022 commit 8e2b45f
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 15 deletions.
15 changes: 11 additions & 4 deletions src/symbols/Edge/Edge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export type EdgeChildrenAsFunction = (
export interface EdgeProps {
id: string;
disabled?: boolean;
removable?: boolean;
selectable?: boolean;
upsertable?: boolean;
source: string;
sourcePort: string;
target: string;
Expand Down Expand Up @@ -93,6 +96,9 @@ export const Edge: FC<Partial<EdgeProps>> = ({
labels,
className,
disabled,
removable = true,
selectable = true,
upsertable = true,
style,
children,
add = <Add />,
Expand All @@ -113,6 +119,7 @@ export const Edge: FC<Partial<EdgeProps>> = ({
? selections.includes(properties?.id)
: false;
const isDisabled = disabled || properties?.disabled;
const canSelect = selectable && !properties.selectionDisabled;

// The "d" attribute defines a path to be drawn. See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
const d = useMemo(() => {
Expand Down Expand Up @@ -169,7 +176,7 @@ export const Edge: FC<Partial<EdgeProps>> = ({
<g
className={classNames(css.edge, {
[css.disabled]: isDisabled,
[css.selectionDisabled]: properties?.selectionDisabled
[css.selectionDisabled]: !canSelect
})}
>
<path
Expand All @@ -189,7 +196,7 @@ export const Edge: FC<Partial<EdgeProps>> = ({
onClick={event => {
event.preventDefault();
event.stopPropagation();
if (!isDisabled) {
if (!isDisabled && canSelect) {
onClick(event, properties);
}
}}
Expand Down Expand Up @@ -228,7 +235,7 @@ export const Edge: FC<Partial<EdgeProps>> = ({
{...(l as LabelProps)}
/>
))}
{!isDisabled && center && !readonly && remove && (
{!isDisabled && center && !readonly && remove && removable && (
<CloneElement<RemoveProps>
element={remove}
{...center}
Expand All @@ -245,7 +252,7 @@ export const Edge: FC<Partial<EdgeProps>> = ({
onLeave={() => setDeleteHovered(false)}
/>
)}
{!isDisabled && center && !readonly && add && (
{!isDisabled && center && !readonly && add && upsertable && (
<CloneElement<AddProps>
element={add}
{...center}
Expand Down
39 changes: 28 additions & 11 deletions src/symbols/Node/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export interface NodeProps extends NodeDragEvents<NodeData, PortData> {
children?: ReactNode | NodeChildrenAsFunction;
parent?: string;
animated?: boolean;
draggable?: boolean;
linkable?: boolean;
selectable?: boolean;
removable?: boolean;
dragType?: NodeDragType;
dragCursor?: string;

Expand Down Expand Up @@ -119,6 +123,10 @@ export const Node: FC<Partial<NodeProps>> = ({
children,
nodes,
edges,
draggable = true,
linkable = true,
selectable = true,
removable = true,
dragType = 'multiportOnly',
dragCursor = 'crosshair',
childEdge = <Edge />,
Expand Down Expand Up @@ -156,6 +164,10 @@ export const Node: FC<Partial<NodeProps>> = ({
dragType === 'multiportOnly' &&
ports?.filter(p => !p.properties?.hidden).length > 1;
const isDisabled = disabled || properties?.disabled;
const canDrag = ['port', 'multiportOnly'].includes(dragType)
? linkable
: draggable;
const canSelect = selectable && !properties?.selectionDisabled;

const getDragType = (hasPort: boolean) => {
let activeDragType: NodeDragType = null;
Expand Down Expand Up @@ -188,16 +200,17 @@ export const Node: FC<Partial<NodeProps>> = ({
y: newY,
height,
width,
disabled: isDisabled || isMultiPort || readonly || dragType === 'port',
disabled:
isDisabled || isMultiPort || readonly || !canDrag || dragType === 'port',
node: properties,
onDrag: (...props) => {
if (!isDisabled) {
if (!isDisabled && canDrag) {
canvas.onDrag(...props);
onDrag(...props);
}
},
onDragStart: (event, coords, node, port) => {
if (!isDisabled) {
if (!isDisabled && canDrag) {
// @ts-ignore
event.dragType = getDragType(false);
// @ts-ignore
Expand All @@ -209,7 +222,7 @@ export const Node: FC<Partial<NodeProps>> = ({
}
},
onDragEnd: (event, coords, node, port) => {
if (!isDisabled) {
if (!isDisabled && canDrag) {
// @ts-ignore
event.dragType = getDragType(false);

Expand Down Expand Up @@ -262,7 +275,7 @@ export const Node: FC<Partial<NodeProps>> = ({
onClick={event => {
event.preventDefault();
event.stopPropagation();
if (!isDisabled) {
if (!isDisabled && canSelect) {
onClick(event, properties);
}
}}
Expand Down Expand Up @@ -291,7 +304,7 @@ export const Node: FC<Partial<NodeProps>> = ({
[css.dragging]: dragging,
[css.children]: nodes?.length > 0,
[css.deleteHovered]: deleteHovered,
[css.selectionDisabled]: properties?.selectionDisabled
[css.selectionDisabled]: !canSelect
})}
style={style}
height={height}
Expand Down Expand Up @@ -332,15 +345,15 @@ export const Node: FC<Partial<NodeProps>> = ({
element={port}
key={p.id}
active={!isMultiPort && dragging}
disabled={isDisabled}
disabled={isDisabled || !linkable}
offsetX={newX}
offsetY={newY}
onDragStart={(
event: DragEvent,
initial: Position,
data: PortData
) => {
if (!isDisabled) {
if (!isDisabled && linkable) {
// @ts-ignore
event.dragType = getDragType(true);
// @ts-ignore
Expand All @@ -352,7 +365,7 @@ export const Node: FC<Partial<NodeProps>> = ({
}
}}
onDrag={(event: DragEvent, initial: Position, data: PortData) => {
if (!isDisabled) {
if (!isDisabled && linkable) {
canvas.onDrag(event, initial, properties, data);
onDrag(event, initial, properties, data);
}
Expand All @@ -362,7 +375,7 @@ export const Node: FC<Partial<NodeProps>> = ({
initial: Position,
data: PortData
) => {
if (!isDisabled) {
if (!isDisabled && linkable) {
// @ts-ignore
event.dragType = getDragType(true);
setDragCursor(null);
Expand All @@ -376,7 +389,7 @@ export const Node: FC<Partial<NodeProps>> = ({
id={`${id}-port-${p.id}`}
/>
))}
{!isDisabled && isActive && !readonly && remove && (
{!isDisabled && isActive && !readonly && remove && removable && (
<CloneElement<RemoveProps>
element={remove}
y={height / 2}
Expand Down Expand Up @@ -425,6 +438,10 @@ export const Node: FC<Partial<NodeProps>> = ({
dragCursor={dragCursor}
dragType={dragType}
childEdge={childEdge}
draggable={draggable}
linkable={linkable}
selectable={selectable}
removable={removable}
onDragStart={onDragStart}
onDrag={onDrag}
onDragEnd={onDragEnd}
Expand Down
159 changes: 159 additions & 0 deletions stories/Edge.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,90 @@ export const Adding = () => {
);
};

export const NotUpsertable = () => {
const [nodes, setNodes] = useState<NodeData[]>([
{
id: '1',
text: 'Node 1'
},
{
id: '2',
text: 'Node 2'
}
]);

const [edges, setEdges] = useState<EdgeData[]>([
{
id: '1-2',
from: '1',
to: '2'
}
]);

return (
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
<Canvas
nodes={nodes}
edges={edges}
edge={
<Edge
add={<Add hidden={false} />}
upsertable={false}
onAdd={(event, edge) => {
const id = `node-${Math.random()}`;
const newNode = {
id,
text: id
};

const results = upsertNode(nodes, edges, edge, newNode);
setNodes(results.nodes);
setEdges(results.edges);
}}
/>
}
onLayoutChange={layout => console.log('Layout', layout)}
/>
</div>
);
};

export const NotSelectable = () => {
const [nodes] = useState<NodeData[]>([
{
id: '1',
text: 'Node 1'
},
{
id: '2',
text: 'Node 2'
}
]);

const [edges] = useState<EdgeData[]>([
{
id: '1-2',
from: '1',
to: '2'
}
]);

return (
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
<Canvas
nodes={nodes}
edges={edges}
edge={
<Edge
selectable={false}
/>
}
onLayoutChange={layout => console.log('Layout', layout)}
/>
</div>
);
};

export const Removeable = () => {
const [selections, setSelections] = useState<string[]>(['1', '1-2']);
const [nodes, setNodes] = useState<NodeData[]>([
Expand Down Expand Up @@ -140,6 +224,81 @@ export const Removeable = () => {
);
};

export const NotRemoveable = () => {
const [selections, setSelections] = useState<string[]>(['1-2']);
const [nodes, setNodes] = useState<NodeData[]>([
{
id: '1',
text: 'Node 1'
},
{
id: '2',
text: 'Node 2'
},
{
id: '3',
text: 'Node 3'
}
]);
const [edges, setEdges] = useState<EdgeData[]>([
{
id: '1-2',
from: '1',
to: '2'
},
{
id: '2-3',
from: '2',
to: '3'
}
]);

return (
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
<Canvas
nodes={nodes}
edges={edges}
selections={selections}
node={
<Node
removable={false}
onClick={(event, node) => {
console.log('Selecting Node', event, node);
setSelections([node.id]);
}}
onRemove={(event, node) => {
console.log('Removing Node', event, node);
const result = removeAndUpsertNodes(nodes, edges, node);
setEdges(result.edges);
setNodes(result.nodes);
setSelections([]);
}}
/>
}
edge={
<Edge
removable={false}
onClick={(event, edge) => {
console.log('Selecting Edge', event, edge);
setSelections([edge.id]);
}}
onRemove={(event, edge) => {
console.log('Removing Edge', event, edge);
setEdges(edges.filter(e => e.id !== edge.id));
setSelections([]);
}}
/>
}
onCanvasClick={(event) => {
console.log('Canvas Clicked', event);
setSelections([]);
}}
onLayoutChange={layout => console.log('Layout', layout)}
/>
</div>
);
};

export const Disabled = () => (
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
<Canvas
Expand Down

0 comments on commit 8e2b45f

Please sign in to comment.