Skip to content

Commit

Permalink
fix(context menu): Fix for context menu use when zoomed out (patternf…
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 authored Nov 11, 2024
1 parent 2a1b615 commit 7260458
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const DemoTaskNode: React.FunctionComponent<DemoTaskNodeProps> = ({
};

return (
<Layer id={detailsLevel !== ScaleDetailsLevel.high && hover ? TOP_LAYER : DEFAULT_LAYER}>
<Layer id={detailsLevel !== ScaleDetailsLevel.high && (hover || contextMenuOpen) ? TOP_LAYER : DEFAULT_LAYER}>
<g ref={hoverRef}>
<TaskNode
element={element}
Expand Down
14 changes: 8 additions & 6 deletions packages/demo-app-ts/src/demos/stylesDemo/StyleNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const StyleNode: React.FunctionComponent<StyleNodeProps> = ({
const data = element.getData();
const detailsLevel = element.getGraph().getDetailsLevel();
const [hover, hoverRef] = useHover();
const focused = hover || contextMenuOpen;

const passedData = React.useMemo(() => {
const newData = { ...data };
Expand All @@ -154,18 +155,19 @@ const StyleNode: React.FunctionComponent<StyleNodeProps> = ({

const LabelIcon = passedData.labelIcon;
return (
<Layer id={hover ? TOP_LAYER : DEFAULT_LAYER}>
<Layer id={focused ? TOP_LAYER : DEFAULT_LAYER}>
<g ref={hoverRef}>
<DefaultNode
element={element}
scaleLabel={detailsLevel !== ScaleDetailsLevel.low}
scaleNode={hover && detailsLevel === ScaleDetailsLevel.low}
scaleNode={focused && detailsLevel === ScaleDetailsLevel.low}
raiseLabelOnHover={false}
{...rest}
{...passedData}
dragging={dragging}
regrouping={regrouping}
showLabel={hover || (detailsLevel !== ScaleDetailsLevel.low && showLabel)}
showStatusBackground={!hover && detailsLevel === ScaleDetailsLevel.low}
showLabel={focused || (detailsLevel !== ScaleDetailsLevel.low && showLabel)}
showStatusBackground={!focused && detailsLevel === ScaleDetailsLevel.low}
showStatusDecorator={detailsLevel === ScaleDetailsLevel.high && passedData.showStatusDecorator}
statusDecoratorTooltip={nodeElement.getNodeStatus()}
onContextMenu={data.showContextMenu ? onContextMenu : undefined}
Expand All @@ -174,11 +176,11 @@ const StyleNode: React.FunctionComponent<StyleNodeProps> = ({
onHideCreateConnector={onHideCreateConnector}
labelIcon={LabelIcon && <LabelIcon noVerticalAlign />}
attachments={
(hover || detailsLevel === ScaleDetailsLevel.high) &&
(focused || detailsLevel === ScaleDetailsLevel.high) &&
renderDecorators(nodeElement, passedData, rest.getShapeDecoratorCenter)
}
>
{(hover || detailsLevel !== ScaleDetailsLevel.low) && renderIcon(passedData, nodeElement)}
{(focused || detailsLevel !== ScaleDetailsLevel.low) && renderIcon(passedData, nodeElement)}
</DefaultNode>
</g>
</Layer>
Expand Down
17 changes: 10 additions & 7 deletions packages/demo-app-ts/src/demos/topologyPackageDemo/DemoNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,13 @@ const getShapeComponent = (shape: NodeShape): React.FunctionComponent<ShapeProps
};

const DemoNode: React.FunctionComponent<DemoNodeProps> = observer(
({ element, onContextMenu, dragging, onShowCreateConnector, onHideCreateConnector, ...rest }) => {
({ element, onContextMenu, dragging, contextMenuOpen, onShowCreateConnector, onHideCreateConnector, ...rest }) => {
const options = React.useContext(DemoContext).nodeOptions;
const nodeElement = element as Node;
const data = element.getData() as GeneratedNodeData;
const detailsLevel = element.getGraph().getDetailsLevel();
const [hover, hoverRef] = useHover();
const focused = hover || contextMenuOpen;

React.useEffect(() => {
if (detailsLevel === ScaleDetailsLevel.low) {
Expand All @@ -164,16 +165,18 @@ const DemoNode: React.FunctionComponent<DemoNodeProps> = observer(
const LabelIcon = data.index % 2 === 1 ? (SignOutAltIcon as any) : undefined;

return (
<Layer id={hover ? TOP_LAYER : DEFAULT_LAYER}>
<Layer id={focused ? TOP_LAYER : DEFAULT_LAYER}>
<g ref={hoverRef}>
<DefaultNode
element={element}
scaleLabel={detailsLevel !== ScaleDetailsLevel.low}
scaleNode={hover && detailsLevel === ScaleDetailsLevel.low}
scaleNode={focused && detailsLevel === ScaleDetailsLevel.low}
contextMenuOpen={contextMenuOpen}
{...rest}
dragging={dragging}
showLabel={hover || (detailsLevel !== ScaleDetailsLevel.low && options.labels)}
showStatusBackground={!hover && detailsLevel === ScaleDetailsLevel.low}
showLabel={focused || (detailsLevel !== ScaleDetailsLevel.low && options.labels)}
raiseLabelOnHover={false}
showStatusBackground={!focused && detailsLevel === ScaleDetailsLevel.low}
showStatusDecorator={detailsLevel === ScaleDetailsLevel.high && options.showStatus}
statusDecoratorTooltip={nodeElement.getNodeStatus()}
onContextMenu={options.contextMenus ? onContextMenu : undefined}
Expand All @@ -186,12 +189,12 @@ const DemoNode: React.FunctionComponent<DemoNodeProps> = observer(
getCustomShape={options.showShapes ? () => getShapeComponent(data.shape) : undefined}
badge={options.badges ? data.objectType : undefined}
attachments={
(hover || detailsLevel === ScaleDetailsLevel.high) &&
(focused || detailsLevel === ScaleDetailsLevel.high) &&
options.showDecorators &&
renderDecorators(options, nodeElement, rest.getShapeDecoratorCenter)
}
>
{(hover || detailsLevel !== ScaleDetailsLevel.low) && renderIcon(data, nodeElement)}
{(focused || detailsLevel !== ScaleDetailsLevel.low) && renderIcon(data, nodeElement)}
</DefaultNode>
</g>
</Layer>
Expand Down
128 changes: 71 additions & 57 deletions packages/module/src/components/nodes/DefaultNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ interface DefaultNodeProps {
onContextMenu?: (e: React.MouseEvent) => void;
/** Flag indicating that the context menu for the node is currently open */
contextMenuOpen?: boolean;
/** Flag indicating the label should move to the top layer when the node is hovered, set to `false` if you are already using TOP_LAYER on hover */
raiseLabelOnHover?: boolean; // TODO: Update default to be false, assume demo code will be followed
}

const SCALE_UP_TIME = 200;
Expand Down Expand Up @@ -166,7 +168,8 @@ const DefaultNodeInner: React.FunctionComponent<DefaultNodeInnerProps> = observe
onHideCreateConnector,
onShowCreateConnector,
onContextMenu,
contextMenuOpen
contextMenuOpen,
raiseLabelOnHover = true
}) => {
const [hovered, hoverRef] = useHover();
const status = nodeStatus || element.getNodeStatus();
Expand Down Expand Up @@ -317,23 +320,72 @@ const DefaultNodeInner: React.FunctionComponent<DefaultNodeInnerProps> = observe
return { translateX, translateY };
}, [element, nodeScale, scaleNode]);

let labelX;
let labelY;
const labelPaddingX = 8;
const labelPaddingY = 4;
if (nodeLabelPosition === LabelPosition.right) {
labelX = (width + labelPaddingX) * labelPositionScale;
labelY = height / 2;
} else if (nodeLabelPosition === LabelPosition.left) {
labelX = 0;
labelY = height / 2 - labelPaddingY;
} else if (nodeLabelPosition === LabelPosition.top) {
labelX = width / 2;
labelY = labelPaddingY + labelPaddingY / 2;
} else {
labelX = (width / 2) * labelPositionScale;
labelY = height + labelPaddingY + labelPaddingY / 2;
}
const renderLabel = () => {
if (!showLabel || !(label || element.getLabel())) {
return null;
}

let labelX;
let labelY;
const labelPaddingX = 8;
const labelPaddingY = 4;
if (nodeLabelPosition === LabelPosition.right) {
labelX = (width + labelPaddingX) * labelPositionScale;
labelY = height / 2;
} else if (nodeLabelPosition === LabelPosition.left) {
labelX = 0;
labelY = height / 2 - labelPaddingY;
} else if (nodeLabelPosition === LabelPosition.top) {
labelX = width / 2;
labelY = labelPaddingY + labelPaddingY / 2;
} else {
labelX = (width / 2) * labelPositionScale;
labelY = height + labelPaddingY + labelPaddingY / 2;
}

const nodeLabel = (
<g
transform={
raiseLabelOnHover && isHover
? `${scaleNode ? `translate(${translateX}, ${translateY})` : ''} scale(${nodeScale})`
: undefined
}
>
<g transform={`scale(${labelScale})`}>
<NodeLabel
className={css(styles.topologyNodeLabel, labelClassName)}
x={labelX}
y={labelY * labelPositionScale}
position={nodeLabelPosition}
paddingX={8}
paddingY={4}
secondaryLabel={secondaryLabel}
truncateLength={truncateLength}
status={status}
badge={badge}
badgeColor={badgeColor}
badgeTextColor={badgeTextColor}
badgeBorderColor={badgeBorderColor}
badgeClassName={badgeClassName}
badgeLocation={badgeLocation}
onContextMenu={onContextMenu}
contextMenuOpen={contextMenuOpen}
hover={isHover}
labelIconClass={labelIconClass}
labelIcon={labelIcon}
labelIconPadding={labelIconPadding}
>
{label || element.getLabel()}
</NodeLabel>
</g>
</g>
);
if (isHover && raiseLabelOnHover) {
return <Layer id={TOP_LAYER}>{nodeLabel}</Layer>;
}
return nodeLabel;
};

return (
<g
className={groupClassName}
Expand All @@ -351,45 +403,7 @@ const DefaultNodeInner: React.FunctionComponent<DefaultNodeInnerProps> = observe
filter={filter}
/>
)}
{showLabel && (label || element.getLabel()) && (
<Layer id={isHover ? TOP_LAYER : undefined}>
<g
transform={
isHover
? `${scaleNode ? `translate(${translateX}, ${translateY})` : ''} scale(${nodeScale})`
: undefined
}
>
<g transform={`scale(${labelScale})`}>
<NodeLabel
className={css(styles.topologyNodeLabel, labelClassName)}
x={labelX}
y={labelY * labelPositionScale}
position={nodeLabelPosition}
paddingX={8}
paddingY={4}
secondaryLabel={secondaryLabel}
truncateLength={truncateLength}
status={status}
badge={badge}
badgeColor={badgeColor}
badgeTextColor={badgeTextColor}
badgeBorderColor={badgeBorderColor}
badgeClassName={badgeClassName}
badgeLocation={badgeLocation}
onContextMenu={onContextMenu}
contextMenuOpen={contextMenuOpen}
hover={isHover}
labelIconClass={labelIconClass}
labelIcon={labelIcon}
labelIconPadding={labelIconPadding}
>
{label || element.getLabel()}
</NodeLabel>
</g>
</g>
</Layer>
)}
{renderLabel()}
{children}
</g>
{statusDecorator}
Expand Down
6 changes: 4 additions & 2 deletions packages/module/src/components/nodes/labels/NodeLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
const [labelHover, labelHoverRef] = useHover();
const refs = useCombineRefs(dragRef, typeof truncateLength === 'number' ? labelHoverRef : undefined);

const [textSize, textRef] = useSize([children, truncateLength, className, labelHover]);
const [textSize, textRef] = useSize([children, truncateLength, className, labelHover, contextMenuOpen]);
const [secondaryTextSize, secondaryTextRef] = useSize([secondaryLabel, truncateLength, className, labelHover]);
const [badgeSize, badgeRef] = useSize([badge]);
const [actionSize, actionRef] = useSize([actionIcon, paddingX]);
Expand Down Expand Up @@ -266,7 +266,9 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
/>
)}
<text {...other} ref={textRef} x={iconSpace + badgeSpace + paddingX} y={height / 2} dy="0.35em">
{truncateLength > 0 && !labelHover ? truncateMiddle(children, { length: truncateLength }) : children}
{truncateLength > 0 && !labelHover && !contextMenuOpen
? truncateMiddle(children, { length: truncateLength })
: children}
</text>
{textSize && actionIcon && (
<>
Expand Down

0 comments on commit 7260458

Please sign in to comment.