diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index face29cea3..92ec49599e 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -43,6 +43,7 @@ In order to provide a first version of those capabilities, some additional coupl This coupling will be removed in the near future as a consequence, the dependencies of this code will change and some APIs of the reference widget will be broken in the near future. - https://github.com/eclipse-sirius/sirius-web/issues/2380[#2380] [diagram] Add typing to reactflow hooks - https://github.com/eclipse-sirius/sirius-web/issues/2430[#2430] [diagram] Improve fit to screen feature to zoom on selected nodes +- https://github.com/eclipse-sirius/sirius-web/issues/2288[#2288] [diagram] Make IconLabel a react flow node == v2023.10.0 @@ -189,7 +190,6 @@ To illustrate this new feature, we contribute a new tool on the _Papaya Diagram_ These color palettes are accessible in studio projects but are not visible in the Explorer view. - https://github.com/eclipse-sirius/sirius-web/issues/2371[#2371] [view] Add new validation rules about colors for View diagrams & forms. - == v2023.8.0 === Shapes diff --git a/integration-tests/cypress/e2e/project/react-flow/diagram.reactflow.cy.js b/integration-tests/cypress/e2e/project/react-flow/diagram.reactflow.cy.js index 485f973f2a..4feec88835 100644 --- a/integration-tests/cypress/e2e/project/react-flow/diagram.reactflow.cy.js +++ b/integration-tests/cypress/e2e/project/react-flow/diagram.reactflow.cy.js @@ -37,9 +37,11 @@ describe('/projects/:projectId/edit - Diagram', () => { cy.getByTestId('rf__wrapper').should('exist'); cy.get('.react-flow__edgelabel-renderer').children().should('have.length', 7); - cy.get('.react-flow__nodes').children().should('have.length', 14); + cy.get('.react-flow__nodes').children().should('have.length', 18); cy.get('.react-flow__node-rectangularNode').should('have.length', 2); cy.get('.react-flow__node-imageNode').should('have.length', 10); + cy.get('.react-flow__node-listNode').should('have.length', 2); + cy.get('.react-flow__node-iconLabelNode').should('have.length', 4); }); it('can share the representation', () => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/converter/convertDiagram.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/converter/convertDiagram.ts index de59de3cf6..5c3b005ef4 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/converter/convertDiagram.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/converter/convertDiagram.ts @@ -15,6 +15,7 @@ import { Edge, Node, XYPosition } from 'reactflow'; import { GQLDiagram } from '../graphql/subscription/diagramFragment.types'; import { GQLLabel, GQLLabelStyle } from '../graphql/subscription/labelFragment.types'; import { + GQLIconLabelNodeStyle, GQLImageNodeStyle, GQLNode, GQLRectangularNodeStyle, @@ -22,8 +23,9 @@ import { } from '../graphql/subscription/nodeFragment.types'; import { Diagram, Label, NodeData } from '../renderer/DiagramRenderer.types'; import { MultiLabelEdgeData } from '../renderer/edge/MultiLabelEdge.types'; +import { IconLabelNodeData } from '../renderer/node/IconsLabelNode.types'; import { ImageNodeData } from '../renderer/node/ImageNode.types'; -import { ListItemData, ListNodeData } from '../renderer/node/ListNode.types'; +import { ListNodeData } from '../renderer/node/ListNode.types'; import { DiagramNodeType } from '../renderer/node/NodeTypes.types'; import { RectangularNodeData } from '../renderer/node/RectangularNode.types'; @@ -105,34 +107,50 @@ const toRectangularNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Nod return node; }; -const toListNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node => { - const style = gqlNode.style as GQLRectangularNodeStyle; - const labelStyle = gqlNode.label.style; +const toIconLabelNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node => { + const { targetObjectId, targetObjectLabel, targetObjectKind } = gqlNode; + const style = gqlNode.style as GQLIconLabelNodeStyle; + const { id, label } = gqlNode; + const labelStyle = label.style; - const listItems: ListItemData[] = (gqlNode.childNodes ?? []).map((gqlChildNode) => { - const { id, label } = gqlChildNode; - return { - id, - label: { - id: label.id, - text: label.text, - iconURL: null, - style: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'flex-start', - gap: '8px', - padding: '4px 8px', - }, - }, + const data: IconLabelNodeData = { + targetObjectId, + targetObjectLabel, + targetObjectKind, + style: { + textAlign: 'left', + backgroundColor: style.backgroundColor, + }, + label: { + id: label.id, + text: label.text, style: { - textAlign: 'left', - ...convertLabelStyle(label.style), + ...convertLabelStyle(labelStyle), }, - hidden: gqlChildNode.state === GQLViewModifier.Hidden, - }; - }); + iconURL: labelStyle.iconURL, + }, + faded: gqlNode.state === GQLViewModifier.Faded, + }; + + const node: Node = { + id, + type: 'iconLabelNode', + data, + position: defaultPosition, + hidden: gqlNode.state === GQLViewModifier.Hidden, + }; + + if (gqlParentNode) { + node.parentNode = gqlParentNode.id; + node.extent = 'parent'; + } + + return node; +}; + +const toListNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node => { + const style = gqlNode.style as GQLRectangularNodeStyle; + const labelStyle = gqlNode.label.style; const { targetObjectId, targetObjectLabel, targetObjectKind } = gqlNode; const data: ListNodeData = { @@ -155,14 +173,12 @@ const toListNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node convertNode(gqlBorderNode, gqlNode, nodes)); (gqlNode.childNodes ?? []).forEach((gqlChildNode) => convertNode(gqlChildNode, gqlNode, nodes)); + } else if (gqlNode.style.__typename === 'IconLabelNodeStyle') { + nodes.push(toIconLabelNode(gqlNode, parentNode)); } }; diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/graphql/subscription/nodeFragment.types.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/graphql/subscription/nodeFragment.types.ts index b42fd64540..a3c8cf59f5 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/graphql/subscription/nodeFragment.types.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/graphql/subscription/nodeFragment.types.ts @@ -61,4 +61,6 @@ export interface GQLImageNodeStyle extends GQLNodeStyle { imageURL: string; } -export interface GQLIconLabelNodeStyle extends GQLNodeStyle {} +export interface GQLIconLabelNodeStyle extends GQLNodeStyle { + backgroundColor: string; +} diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx index e110c453f9..a50dd3d248 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx @@ -39,7 +39,9 @@ import { useDiagramDirectEdit } from './direct-edit/useDiagramDirectEdit'; import { useDrop } from './drop/useDrop'; import { edgeTypes } from './edge/EdgeTypes'; import { MultiLabelEdgeData } from './edge/MultiLabelEdge.types'; +import { useLayout } from './layout/useLayout'; import { nodeTypes } from './node/NodeTypes'; +import { DiagramNodeType } from './node/NodeTypes.types'; import { DiagramPalette } from './palette/DiagramPalette'; import { useDiagramPalette } from './palette/useDiagramPalette'; import { useEdgePalette } from './palette/useEdgePalette'; @@ -47,8 +49,6 @@ import { DiagramPanel } from './panel/DiagramPanel'; import { useReconnectEdge } from './reconnect-edge/useReconnectEdge'; import 'reactflow/dist/style.css'; -import { useLayout } from './layout/useLayout'; -import { DiagramNodeType } from './node/NodeTypes.types'; const isNodeSelectChange = (change: NodeChange): change is NodeSelectionChange => change.type === 'select'; const isEdgeSelectChange = (change: EdgeChange): change is EdgeSelectionChange => change.type === 'select'; diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/Label.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/Label.tsx index bad7c268bb..151bec4eae 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/Label.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/Label.tsx @@ -22,9 +22,10 @@ const labelStyle = ( theme: Theme, style: React.CSSProperties, faded: Boolean, - transform: string + transform: string, + hasIcon: boolean ): React.CSSProperties => { - return { + const labelStyle: React.CSSProperties = { transform, opacity: faded ? '0.4' : '', pointerEvents: 'all', @@ -35,6 +36,12 @@ const labelStyle = ( ...style, color: style.color ? getCSSColor(String(style.color), theme) : undefined, }; + + if (hasIcon) { + labelStyle.gap = '8px'; + } + + return labelStyle; }; export const Label = memo(({ diagramElementId, label, faded, transform }: LabelProps) => { @@ -59,12 +66,13 @@ export const Label = memo(({ diagramElementId, label, faded, transform }: LabelP ); } + return (
{label.iconURL ? : ''} {label.text} diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/IconLabelNodeLayoutHandler.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/IconLabelNodeLayoutHandler.ts new file mode 100644 index 0000000000..04377a7a25 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/IconLabelNodeLayoutHandler.ts @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2023 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +import { Node } from 'reactflow'; +import { Diagram, NodeData } from '../DiagramRenderer.types'; +import { IconLabelNodeData } from '../node/IconsLabelNode.types'; +import { DiagramNodeType } from '../node/NodeTypes.types'; +import { ILayoutEngine, INodeLayoutHandler } from './LayoutEngine.types'; + +export class IconLabelNodeLayoutHandler implements INodeLayoutHandler { + canHandle(node: Node) { + return node.type === 'iconLabelNode'; + } + handle( + _layoutEngine: ILayoutEngine, + _previousDiagram: Diagram | null, + node: Node, + visibleNodes: Node[], + _directChildren: Node[] + ) { + const nodeIndex = this.findNodeIndex(visibleNodes, node.id); + const labelElement = document.getElementById(`${node.id}-label-${nodeIndex}`); + + node.width = labelElement?.getBoundingClientRect().width; + node.height = labelElement?.getBoundingClientRect().height; + } + + private findNodeIndex(nodes: Node[], nodeId: string): number { + return nodes.findIndex((node) => node.id === nodeId); + } +} diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/LayoutEngine.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/LayoutEngine.ts index fb9fbfb035..0775d49104 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/LayoutEngine.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/LayoutEngine.ts @@ -14,6 +14,7 @@ import { Node } from 'reactflow'; import { Diagram, NodeData } from '../DiagramRenderer.types'; import { DiagramNodeType } from '../node/NodeTypes.types'; +import { IconLabelNodeLayoutHandler } from './IconLabelNodeLayoutHandler'; import { ImageNodeLayoutHandler } from './ImageNodeLayoutHandler'; import { ILayoutEngine, INodeLayoutHandler } from './LayoutEngine.types'; import { ListNodeLayoutHandler } from './ListNodeLayoutHandler'; @@ -24,6 +25,7 @@ export class LayoutEngine implements ILayoutEngine { new RectangleNodeLayoutHandler(), new ListNodeLayoutHandler(), new ImageNodeLayoutHandler(), + new IconLabelNodeLayoutHandler(), ]; public layoutNodes( diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/ListNodeLayoutHandler.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/ListNodeLayoutHandler.ts index 9cf82830dc..a2b318000b 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/ListNodeLayoutHandler.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/ListNodeLayoutHandler.ts @@ -11,12 +11,13 @@ * Obeo - initial API and implementation *******************************************************************************/ -import { Node } from 'reactflow'; +import { Box, Node, Rect, boxToRect, rectToBox } from 'reactflow'; import { Diagram, NodeData } from '../DiagramRenderer.types'; import { ListNodeData } from '../node/ListNode.types'; import { DiagramNodeType } from '../node/NodeTypes.types'; import { ILayoutEngine, INodeLayoutHandler } from './LayoutEngine.types'; +const rectangularNodePadding = 8; const defaultWidth = 150; const defaultHeight = 70; @@ -26,22 +27,112 @@ export class ListNodeLayoutHandler implements INodeLayoutHandler { } public handle( - _layoutEngine: ILayoutEngine, + layoutEngine: ILayoutEngine, + previousDiagram: Diagram | null, + node: Node, + visibleNodes: Node[], + directChildren: Node[] + ) { + const nodeIndex = this.findNodeIndex(visibleNodes, node.id); + const nodeElement = document.getElementById(`${node.id}-listNode-${nodeIndex}`)?.children[0]; + const borderWidth = nodeElement ? parseFloat(window.getComputedStyle(nodeElement).borderWidth) : 0; + + if (directChildren.length > 0) { + this.handleParentNode(layoutEngine, previousDiagram, node, visibleNodes, directChildren, borderWidth); + } else { + this.handleLeafNode(previousDiagram, node, visibleNodes, borderWidth); + } + } + handleLeafNode( _previousDiagram: Diagram | null, node: Node, + _visibleNodes: Node[], + _borderWidth: number + ) { + node.width = this.getNodeOrMinWidth(undefined); + node.height = this.getNodeOrMinHeight(undefined); + } + private handleParentNode( + layoutEngine: ILayoutEngine, + previousDiagram: Diagram | null, + node: Node, visibleNodes: Node[], - _directChildren: Node[] + directChildren: Node[], + borderWidth: number ) { - const nodeList = document.getElementById(`${node.id}-${this.findNodeIndex(visibleNodes, node.id)}`)?.children[0]; + layoutEngine.layoutNodes(previousDiagram, visibleNodes, directChildren); - node.width = this.getNodeOrMinWidth(nodeList?.getBoundingClientRect().width); - node.height = this.getNodeOrMinHeight(nodeList?.getBoundingClientRect().height); + const nodeIndex = this.findNodeIndex(visibleNodes, node.id); + const labelElement = document.getElementById(`${node.id}-label-${nodeIndex}`); + + const iconLabelNodes = directChildren.filter((child) => child.type === 'iconLabelNode'); + iconLabelNodes.forEach((child, index) => { + child.position = { + x: 0, + y: (labelElement?.getBoundingClientRect().height ?? 0) + rectangularNodePadding, + }; + const previousSibling = iconLabelNodes[index - 1]; + if (previousSibling) { + child.position = { ...child.position, y: previousSibling.position.y + (previousSibling.height ?? 0) }; + } + }); + + const childrenFootprint = this.getChildrenFootprint(iconLabelNodes); + const childrenAwareNodeWidth = childrenFootprint.x + childrenFootprint.width + rectangularNodePadding; + const labelOnlyWidth = + rectangularNodePadding + (labelElement?.getBoundingClientRect().width ?? 0) + rectangularNodePadding; + const nodeWidth = Math.max(childrenAwareNodeWidth, labelOnlyWidth) + borderWidth * 2; + node.width = this.getNodeOrMinWidth(nodeWidth); + node.height = this.getNodeOrMinHeight( + (labelElement?.getBoundingClientRect().height ?? 0) + + rectangularNodePadding + + childrenFootprint.height + + borderWidth * 2 + ); + + if (nodeWidth > childrenAwareNodeWidth) { + // we need to adjust the width of children + iconLabelNodes.forEach((child) => { + child.width = nodeWidth; + child.style = { + ...child.style, + width: `${nodeWidth}px`, + }; + }); + } } private findNodeIndex(nodes: Node[], nodeId: string): number { return nodes.findIndex((node) => node.id === nodeId); } + private getChildrenFootprint(children: Node[]): Rect { + const footPrint: Box = children.reduce( + (currentFootPrint, node) => { + const { x, y } = node.position; + const nodeBox = rectToBox({ + x, + y, + width: node.width ?? 0, + height: node.height ?? 0, + }); + + return this.getBoundsOfBoxes(currentFootPrint, nodeBox); + }, + { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity } + ); + return boxToRect(footPrint); + } + + private getBoundsOfBoxes(box1: Box, box2: Box): Box { + return { + x: Math.min(box1.x, box2.x), + y: Math.min(box1.y, box2.y), + x2: Math.max(box1.x2, box2.x2), + y2: Math.max(box1.y2, box2.y2), + }; + } + private getNodeOrMinWidth(nodeWidth: number | undefined): number { return Math.max(nodeWidth ?? -Infinity, defaultWidth); } diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/RectangleNodeLayoutHandler.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/RectangleNodeLayoutHandler.ts index c1e5afa7b1..d92b499627 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/RectangleNodeLayoutHandler.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/RectangleNodeLayoutHandler.ts @@ -19,7 +19,6 @@ import { ILayoutEngine, INodeLayoutHandler } from './LayoutEngine.types'; const gap = 20; const rectangularNodePadding = 8; -const borderLeftAndRight = 2; const defaultWidth = 150; const defaultHeight = 70; @@ -35,10 +34,14 @@ export class RectangleNodeLayoutHandler implements INodeLayoutHandler[], directChildren: Node[] ) { + const nodeIndex = this.findNodeIndex(visibleNodes, node.id); + const nodeElement = document.getElementById(`${node.id}-rectangularNode-${nodeIndex}`)?.children[0]; + const borderWidth = nodeElement ? parseFloat(window.getComputedStyle(nodeElement).borderWidth) : 0; + if (directChildren.length > 0) { - this.handleParentNode(layoutEngine, previousDiagram, node, visibleNodes, directChildren); + this.handleParentNode(layoutEngine, previousDiagram, node, visibleNodes, directChildren, borderWidth); } else { - this.handleLeafNode(previousDiagram, node, visibleNodes); + this.handleLeafNode(previousDiagram, node, visibleNodes, borderWidth); } } @@ -47,7 +50,8 @@ export class RectangleNodeLayoutHandler implements INodeLayoutHandler, visibleNodes: Node[], - directChildren: Node[] + directChildren: Node[], + borderWidth: number ) { layoutEngine.layoutNodes(previousDiagram, visibleNodes, directChildren); @@ -72,21 +76,23 @@ export class RectangleNodeLayoutHandler implements INodeLayoutHandler, - visibleNodes: Node[] + visibleNodes: Node[], + borderWidth: number ) { const nodeIndex = this.findNodeIndex(visibleNodes, node.id); const labelElement = document.getElementById(`${node.id}-label-${nodeIndex}`); @@ -95,7 +101,7 @@ export class RectangleNodeLayoutHandler implements INodeLayoutHandler void): HTMLDivElement => { +const isListNode = (node: Node): node is Node => node.type === 'listNode'; +const isRectangularNode = (node: Node): node is Node => node.type === 'rectangularNode'; + +export const prepareLayoutArea = (diagram: Diagram, renderCallback: () => void, httpOrigin: string): HTMLDivElement => { const hiddenContainer: HTMLDivElement = document.createElement('div'); hiddenContainer.id = 'hidden-container'; hiddenContainer.style.display = 'inline-block'; @@ -55,6 +64,12 @@ export const prepareLayoutArea = (diagram: Diagram, renderCallback: () => void): const visibleNodes = diagram.nodes.filter((node) => !node.hidden); // Render all label first + /** + * WARN: The height label computed in the hidden-container will be slightly different from the label rendered in the reactflow diagram. + * This difference is due to the line-height which is set in `variables.css` to 1.5 globaly but in `reset.css` the line-height is + * overridden to `normal` for element with [role=button] which seem to be the case for all reactflow nodes. + * That should not impact the node size since it is calculated with the higher value of line-height. + */ const labelElements: JSX.Element[] = []; visibleNodes.forEach((node, index) => { if (hiddenContainer && node.data.label) { @@ -90,37 +105,50 @@ export const prepareLayoutArea = (diagram: Diagram, renderCallback: () => void): }); elements.push(labelContainerElement); - // then, render list node with list item only - const listNodeElements: JSX.Element[] = []; + const nodeElements: JSX.Element[] = []; visibleNodes.forEach((node, index) => { - if (hiddenContainer && node.type === 'listNode') { - const data = node.data as ListNodeData; - const listNode = createElement(ListNode, { - ...emptyListNodeProps, - id: node.id, - data, - key: `${node.id}-${index}`, - }); - - const element: JSX.Element = createElement('div', { - id: `${node.id}-${index}`, - key: node.id, - children: listNode, - }); - listNodeElements.push(element); + if (hiddenContainer && node) { + const children: JSX.Element[] = []; + if (isRectangularNode(node)) { + const element = createElement(RectangularNode, { + ...emptyRectangularNodeProps, + id: node.id, + data: node.data, + key: `${node.id}-${index}`, + }); + children.push(element); + } + if (isListNode(node)) { + const element = createElement(ListNode, { + ...emptyListNodeProps, + id: node.id, + data: node.data, + key: `${node.id}-${index}`, + }); + children.push(element); + } + if (children.length > 0) { + const elementWrapper: JSX.Element = createElement('div', { + id: `${node.id}-${node.type}-${index}`, + key: node.id, + children, + }); + nodeElements.push(elementWrapper); + } } }); - const nodeListContainerElement: JSX.Element = createElement('div', { - id: 'hidden-nodeList-container', - key: 'hidden-nodeList-container', + + const nodeContainerElement: JSX.Element = createElement('div', { + id: 'hidden-node-container', + key: 'hidden-node-container', style: { display: 'flex', flexWrap: 'wrap', alignItems: 'flex-start', }, - children: listNodeElements, + children: nodeElements, }); - elements.push(nodeListContainerElement); + elements.push(nodeContainerElement); const hiddenContainerContentElements: JSX.Element = createElement(Fragment, { children: elements }); @@ -128,7 +156,7 @@ export const prepareLayoutArea = (diagram: Diagram, renderCallback: () => void): - + {} }}> {hiddenContainerContentElements} diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/useLayout.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/useLayout.ts index 04734d3cf0..5912392d0c 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/useLayout.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/layout/useLayout.ts @@ -11,7 +11,8 @@ * Obeo - initial API and implementation *******************************************************************************/ -import { useEffect, useState } from 'react'; +import { ServerContext, ServerContextValue } from '@eclipse-sirius/sirius-components-core'; +import { useContext, useEffect, useState } from 'react'; import { Diagram } from '../DiagramRenderer.types'; import { cleanLayoutArea, layout, performDefaultAutoLayout, prepareLayoutArea } from './layout'; import { UseLayoutState, UseLayoutValue } from './useLayout.types'; @@ -26,6 +27,7 @@ const initialState: UseLayoutState = { }; export const useLayout = (): UseLayoutValue => { + const { httpOrigin } = useContext(ServerContext); const [state, setState] = useState(initialState); const layoutAreaPrepared = () => { @@ -51,7 +53,7 @@ export const useLayout = (): UseLayoutValue => { useEffect(() => { if (state.currentStep === 'BEFORE_LAYOUT' && !state.hiddenContainer && state.diagramToLayout) { - const layoutArea = prepareLayoutArea(state.diagramToLayout, layoutAreaPrepared); + const layoutArea = prepareLayoutArea(state.diagramToLayout, layoutAreaPrepared, httpOrigin); setState((prevState) => ({ ...prevState, hiddenContainer: layoutArea, diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconLabelNode.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconLabelNode.tsx new file mode 100644 index 0000000000..86080d27e8 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconLabelNode.tsx @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2023 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +import { Theme, useTheme } from '@material-ui/core/styles'; +import { memo } from 'react'; +import { NodeProps } from 'reactflow'; +import { Label } from '../Label'; +import { NodePalette } from '../palette/NodePalette'; +import { IconLabelNodeData } from './IconsLabelNode.types'; + +const iconlabelStyle = ( + style: React.CSSProperties, + theme: Theme, + selected: boolean, + faded: boolean +): React.CSSProperties => { + const iconLabelNodeStyle: React.CSSProperties = { + opacity: faded ? '0.4' : '', + marginLeft: '8px', + ...style, + }; + + if (selected) { + iconLabelNodeStyle.outline = `${theme.palette.primary.main} solid 1px`; + } + + return iconLabelNodeStyle; +}; + +export const IconLabelNode = memo(({ data, id, selected }: NodeProps) => { + const theme = useTheme(); + return ( +
+ {data.label ?
+ ); +}); diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconsLabelNode.types.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconsLabelNode.types.ts new file mode 100644 index 0000000000..34ba99bf03 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/IconsLabelNode.types.ts @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2023 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +import { NodeData } from '../DiagramRenderer.types'; + +export interface IconLabelNodeData extends NodeData { + style: React.CSSProperties; +} diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/ListNode.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/ListNode.tsx index 4d9cbf013f..7046c9c1c9 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/ListNode.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/node/ListNode.tsx @@ -61,15 +61,6 @@ export const ListNode = memo(({ data, isConnectable, id, selected }: NodeProps {data.label ?