[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:slot-based-node-content-and-styles":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Slot-Based Node Content and Styles in a Tree Graph\n\n## What This Example Builds\n\nThis example builds a left-to-right tree graph whose nodes do not share one visual template. Instead, the graph uses a single node slot to render several distinct node bodies: a large root card with a carousel, a video card, rectangular button nodes, circular badges, and translucent pill labels.\n\nThe visible result is a full-height presentation canvas with a lime-green background, semi-transparent white connectors, and a floating white utility window. Users can inspect the graph as a viewer, interact with widgets embedded inside nodes, open the floating settings panel, switch canvas interaction modes, and export the current graph as an image.\n\nThe most important point is not the tree itself. The example shows how one static relation-graph dataset can drive heterogeneous React node content through `RGSlotOnNode`, while SCSS redirects the checked-state styling onto the rendered slot content instead of the library's default node body.\n\n## How the Data Is Organized\n\nThe graph data is created inline as one `RGJsonData` object with `rootId`, `nodes`, and `lines`. There is no fetch, no async transformation pipeline, and no dynamic graph editing after load. The structure is simple:\n\n- `nodes` hold the graph identity and presentation hints.\n- `lines` define the tree relationships.\n- `type` decides which custom node body `MyNodeContent` should render.\n- `data.buttonText` carries per-node payload for button labels.\n- `nodeShape` still matters for relation-graph geometry, even though the visible body is mostly custom slot content.\n\nThere is no separate preprocessing step before `setJsonData()`. The example tags the nodes directly while assembling the JSON literal, so the slot renderer can branch on metadata immediately after the graph loads.\n\nIn a real application, the same pattern could map to organization roles, workflow states, media-rich content cards, KPI badges, alert nodes, or action nodes where each node type needs different HTML structure but still belongs to one graph dataset.\n\n## How relation-graph Is Used\n\nThe graph uses relation-graph as a viewer-oriented tree layout. `MyGraph` configures a `tree` layout that grows from left to right with wide horizontal spacing and tighter vertical spacing, which keeps the mixed node bodies readable. The options also remove most of the default node chrome by setting transparent node fills and a zero-width default border, letting the slot-rendered React content define the look.\n\n`RelationGraph` is wrapped by `RGProvider`, and the demo reads the live graph instance through `RGHooks.useGraphInstance()`. That instance is used for the one-time initialization flow: load data with `setJsonData(...)`, move the viewport to center, and then call `zoomToFit()`. The same hook is reused inside the shared floating helper to update interaction options and run the image-export pipeline.\n\nThe main customization point is `RGSlotOnNode`. Every node passes through one slot function, which forwards the current node object into `MyNodeContent`. That component branches by `node.type` and renders:\n\n- a carousel card for the root node,\n- a video card with built-in media controls,\n- black action buttons for `my-button`,\n- translucent circular badges for `my-circle`,\n- a glass-style pill label for the remaining nodes.\n\nSCSS completes the customization. The stylesheet gives the toolbar a translucent white appearance, removes the default checked-node shadow, and applies the highlight ring to the custom slot wrapper instead. That matters because the visible node body is no longer the default relation-graph box.\n\nThere is no graph editing flow here. The example is firmly in viewer mode, with runtime option changes limited to canvas interaction behavior and export support.\n\n## Key Interactions\n\n- The root node contains a carousel with Previous and Next controls, proving that interactive React widgets can live inside a node body.\n- The video node exposes native media controls, showing that slot content can include rich HTML media rather than only text or icons.\n- The button nodes handle DOM clicks inside node content and log the current node id. This is a small behavior, but it demonstrates that custom node widgets can own their own event handling.\n- The floating utility window can be dragged, minimized, and switched into a settings overlay.\n- The settings overlay changes `wheelEventAction` and `dragEventAction` on the live graph instance, so users can switch between scroll, zoom, selection, move, or no canvas response without reloading data.\n- The same overlay can export the graph to an image by preparing the graph DOM, capturing it with `modern-screenshot`, downloading the blob, and then restoring the graph state.\n\n## Key Code Fragments\n\nThis fragment shows that the example depends on relation-graph layout and option tuning to frame custom node content on a presentation-style canvas.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: true,\n    backgroundColor: 'rgb(101, 163, 13)',\n    defaultLineColor: 'rgba(255, 255, 255, 0.6)',\n    defaultNodeColor: 'transparent',\n    defaultNodeBorderWidth: 0,\n    defaultNodeShape: RGNodeShape.rect,\n    toolBarDirection: 'h',\n    toolBarPositionH: 'right',\n    toolBarPositionV: 'bottom',\n    defaultPolyLineRadius: 10,\n    defaultLineShape: RGLineShape.StandardCurve,\n    defaultJunctionPoint: RGJunctionPoint.lr,\n    layout: {\n        layoutName: 'tree',\n        from: 'left',\n        treeNodeGapH: 200,\n        treeNodeGapV: 30\n    }\n};\n```\n\nThis fragment shows that the graph data itself carries the node-type metadata used by the slot renderer.\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'a',\n    nodes: [\n        { id: 'a', text: 'a', type: 'my-root', nodeShape: RGNodeShape.rect },\n        { id: 'b', text: 'b', type: 'my-circle', nodeShape: RGNodeShape.circle },\n        // ...\n        { id: 'c', text: 'c', type: 'my-video' },\n        { id: 'c1', text: 'c1', type: 'my-button', nodeShape: RGNodeShape.rect, data: { buttonText: 'Button 1' } },\n        { id: 'c2', text: 'c2', type: 'my-button', nodeShape: RGNodeShape.rect, data: { buttonText: 'Button 2' } }\n    ],\n```\n\nThis fragment shows the core slot-rendering technique: one node component branches into multiple node-body implementations.\n\n```tsx\nif (node.type === 'my-root') {\n    return (\n        \u003Cdiv className=\"bg-white rounded\">\n            \u003CSimpleUICarousel contents={nodeContentTypes} width={400} height={200} />\n        \u003C/div>\n    );\n} else if (node.type === 'my-video') {\n    return (\n        \u003Cdiv className=\"relative h-56 w-72 rounded-lg overflow-hidden\">\n            \u003Cvideo playsInline className=\"h-full w-full object-cover overflow-clip-margin-content-box overflow-clip\" controls autoPlay loop muted src=\"https://relation-graph.com/images/video-dribbble.mp4\" />\n```\n\nThis fragment shows how the stylesheet moves the checked-state emphasis from the default library node box onto the custom slot content.\n\n```scss\n.rg-node-peel.rg-node-checked {\n    .rg-node {\n        box-shadow: none;\n\n        & > div {\n            box-shadow: 0 0 0 8px var(--rg-checked-item-bg-color);\n        }\n    }\n}\n```\n\nThis fragment shows that the shared helper changes live graph interaction modes and supports image export through graph-instance APIs.\n\n```tsx\n\u003CSettingRow\n    label=\"Wheel Event:\"\n    options={[\n        { label: 'Scroll', value: 'scroll' },\n        { label: 'Zoom', value: 'zoom' },\n        { label: 'None', value: 'none' },\n    ]}\n    value={wheelMode}\n    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}\n/>\n```\n\n## What Makes This Example Distinct\n\nCompared with nearby examples such as `node-style2`, `node-style3`, and `node-style4`, this one is most useful when the requirement is heterogeneous node-body replacement rather than theme refinement. The comparison data is clear on that point: other examples may also use `RGSlotOnNode`, but they usually apply one repeated visual system or focus on broader style comparison. This example uses one compact tree to place several visibly different content types into nodes at the same time.\n\nThe strongest distinguishing combination is:\n\n- a left-to-right tree layout,\n- transparent default node bodies,\n- semi-transparent white curved connectors,\n- a lime-green full-height canvas,\n- multiple `node.type`-driven slot bodies,\n- checked-state styling that wraps the custom slot content,\n- a reused floating helper for canvas settings and export.\n\nThat combination makes it a stronger starting point than `node-style2` when the built-in node renderer is not enough, and a more focused reference than `node` when the goal is not broad technique comparison but one practical pattern for mixed HTML and media inside nodes.\n\nThe floating helper window should be treated as secondary. The comparison data explicitly warns against presenting it as unique, because that shell is reused across nearby examples. The distinctive lesson here is the slot-based node content system and the styling adjustments required to make selection and chrome still look coherent.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to scenarios where one graph must mix several node presentation modes without changing the graph data contract:\n\n- product or content maps where some nodes are labels, some are media previews, and some are action cards,\n- workflow dashboards where review nodes, decision buttons, and status badges need different HTML bodies,\n- educational or storytelling graphs where root nodes act as feature cards and child nodes act as compact tags or checkpoints,\n- monitoring views where alert nodes, metric pills, and drill-down actions share the same topology but not the same rendering needs.\n\nThe same structure can also be extended by replacing the inline sample data with API data, expanding `node.type` into a richer rendering registry, or connecting embedded node controls to real business actions instead of console logging.\n",false,500,1782615371323]