Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Layout #15

Merged
merged 2 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Update from notes in PR
  • Loading branch information
sroussey committed Jan 27, 2024
commit 20a880425e321190b342cf5bdae088123c66d8e8
56 changes: 19 additions & 37 deletions lib/NodeGraphEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,50 +24,25 @@ import {
useMemo,
JSX,
CSSProperties,
useState,
useEffect,
} from 'react'
import { defaultEdgeTypes } from './edge-types'
import { IGraphConfig } from './config'
import { useSocketConnect } from './hooks/connect'
import { useHotkeys } from 'react-hotkeys-hook'
import { ClipboardItem } from './clipboard'
import { LayoutEngine, getLayoutFunction, useLayoutEngine } from './layout/layout'

const options = {
includeHiddenNodes: false,
};

export default function useDefaultLayout(layoutFn:((nodes: Node[], edges:Edge[]) => Node[])| undefined) {
const { getNodes, getEdges } = useReactFlow();
const nodesInitialized = useNodesInitialized(options);
const [layoutedNodes, setLayoutedNodes] = useState(getNodes());

useEffect(() => {
if (nodesInitialized && typeof layoutFn == "function") {
const found = !!getNodes().find((node) => node.position == undefined);
if (found) {
setLayoutedNodes(layoutFn(getNodes(), getEdges()));
} else {
setLayoutedNodes(getNodes());
}
}
}, [nodesInitialized]);

return layoutedNodes;
}
import { LayoutEngine, useLayoutEngine } from './layout/layout'

type NodeGraphEditorProps = Omit<FlowProps, 'edges' | 'nodes'> & {
onSave?: (data: any) => void,
defaultLayout?: LayoutEngine,
}

export const NodeGraphEditor = forwardRef<
NodeGraphHandle,
NodeGraphEditorProps
>(
(
{ defaultNodes, defaultEdges, defaultLayout, ...props }: NodeGraphEditorProps,
{ defaultNodes, defaultEdges, layoutEngine, ...props }: NodeGraphEditorProps,
ref,
): JSX.Element => {
const [nodes, , onNodesChange] = useNodesState(defaultNodes ?? [])
Expand All @@ -81,7 +56,6 @@ export const NodeGraphEditor = forwardRef<
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
defaultLayout={defaultLayout}
/>
</ReactFlowProvider>
)
Expand Down Expand Up @@ -110,15 +84,18 @@ export const ExampleNodeGraphEditor = forwardRef<

type FlowProps = ReactFlowProps & {
backgroundStyles?: CSSProperties,
defaultLayout?: LayoutEngine
/**
* The default layout engine to use when nodes are provided without positions.
*/
layoutEngine?: LayoutEngine
}
export type NodeGraphHandle = {
layout: () => void
}

const Flow = forwardRef<NodeGraphHandle, FlowProps>(
(
{ backgroundStyles, defaultLayout, ...props }: FlowProps,
{ backgroundStyles, layoutEngine, ...props }: FlowProps,
ref,
) => {
const nodeTypes = useNodeTypes()
Expand All @@ -127,12 +104,7 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
const [config] = useGraphConfig()
const { getState } = useStoreApi()
const { setNodes, setEdges } = useReactFlow()
const layoutedNodes = useDefaultLayout(getLayoutFunction(defaultLayout))
useEffect(() => {
if (layoutedNodes && defaultLayout !== undefined) {
setNodes(layoutedNodes)
}
}, [layoutedNodes])


// Handle clipboard events
useHotkeys(
Expand All @@ -145,7 +117,7 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
)

// Provide methods to parent components
const layout = useLayoutEngine(LayoutEngine.Dagre)
const layout = useLayoutEngine(layoutEngine ?? LayoutEngine.Dagre)
useImperativeHandle(
ref,
() => ({
Expand All @@ -154,6 +126,16 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
[],
)

const initialized = useNodesInitialized()
useEffect(() => {
const shouldLayout = !!getState().nodes.find(
(node) => node.position == undefined,
)
if (initialized && shouldLayout) {
layout()
}
}, [initialized])

return (
<div
style={{
Expand Down
9 changes: 4 additions & 5 deletions lib/NodeGraphEditorInputGroups.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { useBuildGraphConfig } from './hooks/config.ts'
import { InputProps } from './config.ts'
import { Wheel } from '@uiw/react-color'
import { useNodeFieldValue } from './hooks/node.ts'
import { LayoutEngine } from './layout/layout.ts'

const meta = {
title: 'Node Graph Editor',
Expand Down Expand Up @@ -202,7 +201,7 @@ const meta = {
)
return (
<GraphConfigProvider defaultConfig={config}>
<NodeGraphEditor defaultNodes={nodes} defaultEdges={edges} defaultLayout={LayoutEngine.Dagre}>
<NodeGraphEditor defaultNodes={nodes} defaultEdges={edges}>
<Background color="#52525b" variant={BackgroundVariant.Dots} />
</NodeGraphEditor>
</GraphConfigProvider>
Expand Down Expand Up @@ -237,19 +236,19 @@ export const InputGroups: Story = {
{
id: '2',
type: 'number',
// position: { x: 100, y: 100 },
position: { x: 100, y: 100 },
data: {},
},
{
id: '3',
type: 'number',
// position: { x: 100, y: 200 },
position: { x: 100, y: 200 },
data: {},
},
{
id: '4',
type: 'color',
// position: { x: 100, y: 300 },
position: { x: 100, y: 300 },
data: {},
},
] as Node[],
Expand Down
Loading