{
  "$schema": "https://ai.syncfusion.com/schema/registry-item.json",
  "name": "diagram-mind-map",
  "framework": "react",
  "type": "registry:component",
  "component": "Diagram",
  "variant": "mind-map",
  "dependencies": [
    "@syncfusion/ej2-react-diagrams",
    "@syncfusion/ej2-data"
  ],
  "description": "Mind-map diagram with custom user handles to add, branch, and delete nodes.",
  "meta": {
    "essentialStudioRelease": "2026 Volume 2 (v34.1.29)",
    "license": "commercial-or-community",
    "licenseNote": "The Syncfusion package is licensed. The composition in this file is source you own and edit. See https://ai.syncfusion.com/licensing.md",
    "requiresLicenseKey": true,
    "requiresServerEndpoint": false,
    "platformIndex": "https://ai.syncfusion.com/react/llms.txt",
    "skillPack": "syncfusion/react-ui-components-skills",
    "docs": "https://ai.syncfusion.com/gallery/react/js/diagram-mind-map.md"
  },
  "files": [
    {
      "target": "src/components/diagram-mind-map/Diagram.jsx",
      "content": "import { \n// React Diagram components and utilities\nMindMap as MindMapModule, HierarchicalTree, ConnectorConstraints, DiagramConstraints, ToolBase, randomId, PointPort, SelectorConstraints, SnapConstraints, PortVisibility, DiagramComponent, NodeConstraints, Node, DiagramTools, Inject, DataBinding } from \"@syncfusion/ej2-react-diagrams\";\n// Importing base components and data management utilities\nimport { DataManager, Query } from \"@syncfusion/ej2-data\";\n\nlet mindMap = [\n    { id: 1, Label: 'Creativity', fill: 'red', branch: 'Root' },\n    { id: 3, Label: 'Brainstorming', parentId: 1, branch: 'Right', fill: 'red' },\n    { id: 4, Label: 'Complementing', parentId: 1, branch: 'Left', fill: 'red' },\n    { id: 22, Label: 'Sessions', parentId: 3, branch: 'subRight', fill: 'red' },\n    { id: 23, Label: 'Generate', parentId: 3, branch: 'subRight', fill: 'red' },\n    { id: 25, Label: 'Local', parentId: 22, branch: 'subRight' },\n    { id: 26, Label: 'Remote', parentId: 22, branch: 'subRight' },\n    { id: 27, Label: 'Individual', parentId: 22, branch: 'subRight' },\n    { id: 28, Label: 'Teams', parentId: 22, branch: 'subRight' },\n    { id: 29, Label: 'Ideas', parentId: 23, branch: 'subRight' },\n    { id: 30, Label: 'Engagement', parentId: 23, branch: 'subRight' },\n    { id: 31, Label: 'Product', parentId: 29, branch: 'subRight' },\n    { id: 32, Label: 'Service', parentId: 29, branch: 'subRight' },\n    { id: 33, Label: 'Business Direction', parentId: 29, branch: 'subRight' },\n    { id: 34, Label: 'Empowering', parentId: 30, branch: 'subRight' },\n    { id: 35, Label: 'Ownership', parentId: 30, branch: 'subRight' },\n    { id: 50, Label: 'Information', parentId: 4, branch: 'subLeft' },\n    { id: 51, Label: 'Expectations', parentId: 4, branch: 'subLeft' },\n    { id: 53, Label: 'Competitors', parentId: 50, branch: 'subLeft' },\n    { id: 54, Label: 'Products', parentId: 50, branch: 'subLeft' },\n    { id: 55, Label: 'Features', parentId: 50, branch: 'subLeft' },\n    { id: 56, Label: 'Other Data', parentId: 50, branch: 'subLeft' },\n    { id: 59, Label: 'Organization', parentId: 51, branch: 'subLeft' },\n    { id: 60, Label: 'Customer', parentId: 51, branch: 'subLeft' },\n    { id: 61, Label: 'Staff', parentId: 51, branch: 'subLeft' },\n    { id: 62, Label: 'Stakeholders', parentId: 51, branch: 'subLeft' },\n];\n\n// Initialize data manager with mindMap data and query\nlet items = new DataManager(mindMap, new Query().take(7));\nlet diagramInstance;\n// React component for MindMap\nfunction MindMap() {\n    function rendereComplete() {\n        diagramInstance.fitToPage();\n    }\n    //creation of the Ports\n    function getPort() {\n        let port = [\n            {\n                id: \"port1\",\n                offset: { x: 0, y: 0.5 },\n                visibility: PortVisibility.Hidden,\n                style: { fill: \"black\" }\n            },\n            {\n                id: \"port2\",\n                offset: { x: 1, y: 0.5 },\n                visibility: PortVisibility.Hidden,\n                style: { fill: \"black\" }\n            }\n        ];\n        return port;\n    }\n    // Function to add a new node\n    function addNode() {\n        let obj = {};\n        obj.id = randomId();\n        obj.data = {};\n        obj.data.Label = \"Node\";\n        return obj;\n    }\n    // Function to add a connector\n    function addConnector(source, target) {\n        let connector = {};\n        connector.id = randomId();\n        connector.sourceID = source.id;\n        connector.targetID = target.id;\n        return connector;\n    }\n    // Function to get custom tool based on action (leftHandle, rightHandle, delete)\n    function getTool(action) {\n        let tool;\n        if (action === \"leftHandle\") {\n            tool = new LeftExtendTool(diagramInstance.commandHandler);\n        }\n        else if (action === \"rightHandle\") {\n            tool = new RightExtendTool(diagramInstance.commandHandler);\n        }\n        else if (action === \"delete\") {\n            tool = new DeleteClick(diagramInstance.commandHandler);\n        }\n        return tool;\n    }\n    // Custom tool class for left extension tool\n    class LeftExtendTool extends ToolBase {\n        mouseDown(args) {\n            super.mouseDown(args);\n            this.inAction = true;\n        }\n        mouseUp(args) {\n            if (this.inAction) {\n                let selectedObject = this.commandHandler.getSelectedObject();\n                if (selectedObject[0]) {\n                    if (selectedObject[0] instanceof Node) {\n                        let node = addNode();\n                        if (selectedObject[0].data.branch === \"Root\") {\n                            node.data.branch = \"Right\";\n                        }\n                        else if (selectedObject[0].data.branch === \"Right\" ||\n                            selectedObject[0].data.branch === \"subRight\") {\n                            node.data.branch = \"subRight\";\n                        }\n                        getTextEditValue(selectedObject[0], node);\n                    }\n                }\n            }\n        }\n    }\n    // Custom tool class for right extension tool\n    class RightExtendTool extends ToolBase {\n        //mouseDown event\n        mouseDown(args) {\n            super.mouseDown(args);\n            this.inAction = true;\n        }\n        //mouseDown event\n        mouseUp(args) {\n            if (this.inAction) {\n                let selectedObject = this.commandHandler.getSelectedObject();\n                if (selectedObject[0]) {\n                    if (selectedObject[0] instanceof Node) {\n                        let node = addNode();\n                        if (selectedObject[0].data.branch === \"Root\") {\n                            node.data.branch = \"Left\";\n                        }\n                        else if (selectedObject[0].data.branch === \"Left\" ||\n                            selectedObject[0].data.branch === \"subLeft\") {\n                            node.data.branch = \"subLeft\";\n                        }\n                        getTextEditValue(selectedObject[0], node);\n                    }\n                }\n            }\n        }\n    }\n    // Custom tool class for delete tool\n    class DeleteClick extends ToolBase {\n        //mouseDown event\n        mouseDown(args) {\n            super.mouseDown(args);\n            this.inAction = true;\n        }\n        //mouseup event\n        mouseUp(args) {\n            if (this.inAction) {\n                let selectedObject = this.commandHandler.getSelectedObject();\n                if (selectedObject[0]) {\n                    if (selectedObject[0] instanceof Node) {\n                        let node = selectedObject[0];\n                        this.removeSubChild(node);\n                    }\n                    diagramInstance.doLayout();\n                }\n            }\n        }\n        //Function to Remove the subchild Elements\n        removeSubChild(node) {\n            for (let i = node.outEdges.length - 1; i >= 0; i--) {\n                let connector = diagramInstance.getObject(node.outEdges[i]);\n                let childNode = diagramInstance.getObject(connector.targetID);\n                if (childNode.outEdges.length > 0) {\n                    this.removeSubChild(childNode);\n                }\n                else {\n                    diagramInstance.remove(childNode);\n                }\n            }\n            diagramInstance.remove(node);\n        }\n    }\n    //Function to hide the require userhandle.\n    function hideUserHandle(name) {\n        for (let handle of diagramInstance.selectedItems.userHandles) {\n            if (handle.name === name) {\n                handle.visible = false;\n            }\n        }\n    }\n    // Definition of left arrow path,right arrow path,delete icon path for user handle\n    let leftarrow = \"M11.924,6.202 L4.633,6.202 L4.633,9.266 L0,4.633 L4.632,0 L4.632,3.551 L11.923,3.551 L11.923,6.202Z\";\n    let rightarrow = \"M0,3.063 L7.292,3.063 L7.292,0 L11.924,4.633 L7.292,9.266 L7.292,5.714 L0.001,5.714 L0.001,3.063Z\";\n    let deleteicon = \"M 7.04 22.13 L 92.95 22.13 L 92.95 88.8 C 92.95 91.92 91.55 94.58 88.76\" +\n        \"96.74 C 85.97 98.91 82.55 100 78.52 100 L 21.48 100 C 17.45 100 14.03 98.91 11.24 96.74 C 8.45 94.58 7.04\" +\n        \"91.92 7.04 88.8 z M 32.22 0 L 67.78 0 L 75.17 5.47 L 100 5.47 L 100 16.67 L 0 16.67 L 0 5.47 L 24.83 5.47 z\";\n    // Definition of user handles with their respective properties\n    let leftuserhandle = setUserHandle(\n    //it is in dedicated line here.\n    \"leftHandle\", leftarrow, \"Left\", 1, { top: 0, bottom: 0, left: 0, right: 10 }, \"Left\", \"Top\");\n    let rightuserhandle = setUserHandle(\n    //it is in dedicated line here.\n    \"rightHandle\", rightarrow, \"Right\", 1, { top: 0, bottom: 0, left: 10, right: 0 }, \"Right\", \"Top\");\n    let deleteuserhandle = setUserHandle(\n    //it is in dedicated line here.\n    \"delete\", deleteicon, \"Top\", 0.5, { top: 0, bottom: 10, left: 0, right: 0 }, \"Center\", \"Center\");\n    let handle = [\n        leftuserhandle,\n        rightuserhandle,\n        deleteuserhandle\n    ];\n    //set and creation of the Userhandle.\n    function setUserHandle(//it is in dedicated line here.\n    name, pathData, side, offset, margin, HorizontalAlignment, verticalAlignment) {\n        let userhandle = {\n            name: name,\n            pathData: pathData,\n            backgroundColor: \"black\",\n            pathColor: \"white\",\n            side: side,\n            offset: offset,\n            margin: margin,\n            horizontalAlignment: HorizontalAlignment,\n            verticalAlignment: verticalAlignment\n        };\n        return userhandle;\n    }\n    // Function to handle text edit value and add a new node and connector\n    function getTextEditValue(selectObject, node) {\n        let connector = addConnector(selectObject, node);\n        diagramInstance.clearSelection();\n        var newNode = diagramInstance.add(node);\n        diagramInstance.add(connector);\n        diagramInstance.doLayout();\n        diagramInstance.bringIntoView(newNode.wrapper.bounds);\n        diagramInstance.select([diagramInstance.nameTable[newNode.id]]);\n        diagramInstance.startTextEdit(diagramInstance.selectedItems.nodes[0]);\n    }\n    //Change the Position of the UserHandle.\n    function changeUserHandlePosition(change) {\n        for (let handle of diagramInstance.selectedItems.userHandles) {\n            if (handle.name === \"delete\" && change === \"leftHandle\") {\n                applyHandle(handle, \"Left\", 1, { top: 0, bottom: 0, left: 0, right: 10 }, \"Left\", \"Top\");\n            }\n            else if (handle.name === \"delete\" && change === \"rightHandle\") {\n                applyHandle(handle, \"Right\", 1, { top: 0, bottom: 0, left: 10, right: 0 }, \"Right\", \"Top\");\n            }\n        }\n    }\n    //function to set the value for UserHandle element.\n    function applyHandle(//it is in dedicated line here.\n    handle, side, offset, margin, HorizontalAlignment, verticalAlignment) {\n        handle.side = side;\n        handle.offset = offset;\n        handle.margin = margin;\n        handle.horizontalAlignment = HorizontalAlignment;\n        handle.verticalAlignment = verticalAlignment;\n    }\n    return (<div className=\"control-pane\">\n      <div className=\"control-section\">\n        <div style={{ width: \"100%\" }}>\n          <DiagramComponent ref={diagram => (diagramInstance = diagram)} id=\"diagram\" style={{ width: \"74%\", height: \"550px\", float: \"left\" }} width={\"100%\"} height={\"550px\"} constraints={DiagramConstraints.Default & ~DiagramConstraints.UndoRedo} snapSettings={{ constraints: SnapConstraints.None }} tool={DiagramTools.SingleSelect} layout={{\n            type: \"MindMap\",\n            orientation: 'Horizontal',\n            getBranch: (node, nodes) => {\n                return node.data.branch;\n            },\n            horizontalSpacing: 50\n        }} \n    //Selectionchange event for Node and connector\n    selectionChange={(arg) => {\n            if (arg.state === \"Changing\") {\n                if (arg.newValue[0] instanceof Node) {\n                    for (let handle of diagramInstance.selectedItems\n                        .userHandles) {\n                        handle.visible = true;\n                    }\n                    if (arg.newValue[0].data\n                        .branch === \"Left\" ||\n                        arg.newValue[0].data\n                            .branch === \"subLeft\") {\n                        hideUserHandle(\"leftHandle\");\n                        changeUserHandlePosition(\"leftHandle\");\n                    }\n                    else if (arg.newValue[0].data\n                        .branch === \"Right\" ||\n                        arg.newValue[0].data\n                            .branch === \"subRight\") {\n                        hideUserHandle(\"rightHandle\");\n                        changeUserHandlePosition(\"rightHandle\");\n                    }\n                    else if (arg.newValue[0].data\n                        .branch === \"Root\") {\n                        hideUserHandle(\"delete\");\n                    }\n                }\n                else {\n                    hideUserHandle(\"leftHandle\");\n                    hideUserHandle(\"rightHandle\");\n                    hideUserHandle(\"delete\");\n                }\n            }\n        }} selectedItems={{\n            constraints: SelectorConstraints.UserHandle,\n            userHandles: handle\n        }} dataSourceSettings={{\n            id: \"id\",\n            parentId: \"parentId\",\n            dataSource: items,\n            root: String(1)\n        }} \n    //sets node default value\n    getNodeDefaults={(obj) => {\n            obj.constraints =\n                NodeConstraints.Default & ~NodeConstraints.Drag;\n            if (obj.data.branch === \"Left\" ||\n                obj.data.branch === \"Right\" ||\n                obj.data.branch === \"Root\") {\n                obj.shape = { type: \"Basic\", shape: \"Ellipse\" };\n                obj.borderColor =\n                    \"black\"; /* tslint:disable:no-string-literal */\n                obj.style = {\n                    fill: obj.data.branch === \"Root\"\n                        ? \"#E74C3C\"\n                        : \"#F39C12\",\n                    strokeColor: \"none\",\n                    strokeWidth: 2\n                };\n                obj.annotations = [\n                    {\n                        content: obj.data.Label,\n                        margin: { left: 10, right: 10, top: 10, bottom: 10 },\n                        style: { color: \"white\" }\n                    }\n                ];\n                let port = getPort();\n                for (let i = 0; i < port.length; i++) {\n                    obj.ports.push(new PointPort(obj, \"ports\", port[i], true));\n                }\n            }\n            else {\n                let color; /* tslint:disable:no-string-literal */\n                if (obj.data.branch === \"Right\" ||\n                    obj.data.branch === \"subRight\") {\n                    color = \"#8E44AD\";\n                }\n                else {\n                    color = \"#3498DB\";\n                }\n                obj.shape = { type: \"Basic\", shape: \"Rectangle\" };\n                obj.style = { fill: color, strokeWidth: 0 };\n                obj.minWidth = 100;\n                obj.height = 4;\n                let port = getPort();\n                for (let i = 0; i < port.length; i++) {\n                    obj.ports.push(new PointPort(obj, \"ports\", port[i], true));\n                }\n                obj.annotations = [\n                    {\n                        content: obj.data.Label,\n                        offset: { x: 0.5, y: 0 },\n                        verticalAlignment: \"Bottom\"\n                    }\n                ];\n                obj.shape.margin = {\n                    left: 0,\n                    right: 0,\n                    top: 0,\n                    bottom: 0\n                };\n            }\n            return obj;\n        }} \n    //sets connector default value\n    getConnectorDefaults={(connector, diagram) => {\n            connector.type = \"Bezier\";\n            connector.targetDecorator = { shape: \"None\" };\n            let sourceNode = diagram.getObject(connector.sourceID);\n            let targetNode = diagram.getObject(connector.targetID);\n            if (targetNode.data.branch === \"Right\" ||\n                targetNode.data.branch === \"subRight\") {\n                connector.sourcePortID = sourceNode.ports[0].id;\n                connector.targetPortID = targetNode.ports[1].id;\n                connector.style = { strokeWidth: 5, strokeColor: \"#8E44AD\" };\n            }\n            else if (targetNode.data.branch === \"Left\" ||\n                targetNode.data.branch === \"subLeft\") {\n                connector.sourcePortID = sourceNode.ports[1].id;\n                connector.targetPortID = targetNode.ports[0].id;\n                connector.style = { strokeWidth: 5, strokeColor: \"#3498DB\" };\n            }\n            connector.constraints &= ~ConnectorConstraints.Select;\n            return connector;\n        }} created={() => {\n            diagramInstance.fitToPage();\n        }} getCustomTool={getTool} scrollSettings={{\n            //Sets the scroll padding\n            padding: { left: 50, right: 50 }\n        }}>\n            <Inject services={[DataBinding, MindMapModule, HierarchicalTree]}/>\n          </DiagramComponent>\n        </div>\n      </div>\n    </div>);\n}\nexport default MindMap;"
    }
  ]
}