-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use
children
in Edge/Port components to display custom components (#4)
- Loading branch information
1 parent
b72130b
commit 1a7d418
Showing
11 changed files
with
256 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Tooltip } from '@chakra-ui/react'; | ||
import { css } from '@emotion/react'; | ||
import React from 'react'; | ||
import { useRecoilState } from 'recoil'; | ||
import { absoluteTooltipState } from '../../states/absoluteTooltipState'; | ||
|
||
type Props = {}; | ||
|
||
/** | ||
* Tooltip displayed in absolute position. | ||
* | ||
* Displays on top of the canvas. | ||
*/ | ||
export const AbsoluteTooltip: React.FunctionComponent<Props> = (props) => { | ||
const [tooltip, setTooltip] = useRecoilState(absoluteTooltipState); | ||
|
||
return ( | ||
<div | ||
className={'absolute-tooltip'} | ||
css={css` | ||
// ChakraUI Tooltip component doesn't support absolute position natively | ||
// This component wraps the <Tooltip> component and display it in absolute position | ||
position: absolute; | ||
left: ${(tooltip?.x || 0)}px; | ||
top: ${(tooltip?.y || 0)}px; | ||
`} | ||
> | ||
{ | ||
tooltip?.isDisplayed && ( | ||
<Tooltip | ||
label={tooltip?.text} | ||
// Automatically opens the tooltip (uncontrolled) | ||
isOpen={true} | ||
> | ||
| ||
</Tooltip> | ||
) | ||
} | ||
</div> | ||
); | ||
}; | ||
|
||
export default AbsoluteTooltip; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { css } from '@emotion/react'; | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||
import React from 'react'; | ||
import { | ||
useRecoilState, | ||
useSetRecoilState, | ||
} from 'recoil'; | ||
import { absoluteTooltipState } from '../../states/absoluteTooltipState'; | ||
import { edgesSelector } from '../../states/edgesState'; | ||
import BaseEdgeData from '../../types/BaseEdgeData'; | ||
import BasePortChildProps from '../../types/BasePortChildProps'; | ||
import { translateXYToCanvasPosition } from '../../utils/canvas'; | ||
|
||
/** | ||
* Each <BasePort> component contains on <BasePortChild> component provided through the "PortChildComponent" property. | ||
* | ||
* The BasePortChild is a <foreignObject> which displays additional content, such as: | ||
* - A warning when an entry port is not reachable. | ||
* - A warning when an output port is not connected. | ||
*/ | ||
const BasePortChild: React.FunctionComponent<BasePortChildProps> = (props) => { | ||
const { | ||
isNodeReachable, | ||
port, | ||
isDragging, | ||
x, | ||
y, | ||
} = props; | ||
const setTooltip = useSetRecoilState(absoluteTooltipState); | ||
const [edges, setEdges] = useRecoilState(edgesSelector); | ||
const links: BaseEdgeData[] | undefined = edges?.filter((edge: BaseEdgeData) => port?.side === 'WEST' ? edge?.toPort === port?.id : edge?.fromPort === port?.id); | ||
const shouldDisplayUnreachableWarning = port?.side === 'WEST' && !isNodeReachable; | ||
const shouldDisplayUnlinkedWarning = port?.side === 'EAST' && !links?.length && !isDragging; | ||
const hasContentToDisplay = shouldDisplayUnreachableWarning || shouldDisplayUnlinkedWarning; | ||
|
||
let warning: string; | ||
|
||
if (shouldDisplayUnreachableWarning) { | ||
warning = `This node is not reachable because there are no edge connected to its entry port.`; | ||
} else if (shouldDisplayUnlinkedWarning) { | ||
warning = `This port is not linked to any other node.`; | ||
} | ||
|
||
// Don't render content if there are no content to display | ||
if (!hasContentToDisplay) { | ||
return null; | ||
} | ||
|
||
// Move the content a bit to the left for the West port, and to the right for the right port | ||
const newX = x + (port?.side === 'WEST' ? -40 : 20); | ||
const newY = y - 10; | ||
|
||
return ( | ||
<foreignObject | ||
// Content width/height will be limited by the width of the foreignObject | ||
width={30} | ||
height={30} | ||
x={newX} | ||
y={newY} | ||
css={css` | ||
position: absolute; | ||
color: black; | ||
z-index: 1; | ||
.port-content { | ||
position: fixed; | ||
cursor: help; | ||
pointer-events: auto; | ||
} | ||
.svg-inline--fa { | ||
color: orange; | ||
} | ||
`} | ||
> | ||
<div | ||
className={'port-content'} | ||
onMouseEnter={(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => { | ||
const [x, y] = translateXYToCanvasPosition(event.clientX, event.clientY); | ||
|
||
// Displays a tooltip in absolute position based on the X/Y position of the targeted element | ||
setTooltip({ | ||
isDisplayed: true, | ||
text: warning, | ||
x, | ||
y, | ||
}); | ||
}} | ||
onMouseLeave={(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => { | ||
// Hides the tooltip | ||
setTooltip({ | ||
isDisplayed: false, | ||
}); | ||
}} | ||
> | ||
<FontAwesomeIcon | ||
icon={['fas', 'exclamation-triangle']} | ||
/> | ||
</div> | ||
|
||
|
||
</foreignObject> | ||
); | ||
}; | ||
|
||
export default BasePortChild; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { atom } from 'recoil'; | ||
import { AbsoluteTooltipContent } from '../types/AbsoluteTooltipContent'; | ||
|
||
/** | ||
* Used to know the state of the tooltip currently being displayed. | ||
* | ||
* The tooltip will be displayed in absolute position. | ||
*/ | ||
export const absoluteTooltipState = atom<AbsoluteTooltipContent | undefined>({ | ||
key: 'absoluteTooltipState', | ||
default: undefined, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export type AbsoluteTooltipContent = { | ||
isDisplayed: boolean; | ||
text?: string; | ||
x?: number; | ||
y?: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { PortChildProps } from 'reaflow'; | ||
import BaseNodeData from './BaseNodeData'; | ||
|
||
/** | ||
* Additional properties that will be passed down to the PortChildComponent component. | ||
*/ | ||
export type AdditionalPortChildProps = { | ||
fromNode: BaseNodeData; | ||
isNodeReachable: boolean; | ||
} | ||
|
||
/** | ||
* Base port child properties provided to any instance of the PortChildComponent component. | ||
* | ||
* It inherits from Reaflow "PortChildProps" and add other custom properties on top of them. | ||
*/ | ||
export type BasePortChildProps = PortChildProps & AdditionalPortChildProps; | ||
|
||
export default BasePortChildProps; |
Oops, something went wrong.
1a7d418
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: