Skip to content

Commit

Permalink
rework stories and layout (#24)
Browse files Browse the repository at this point in the history
* rework stories and layout

* Add registerLayoutEngine to lib
  • Loading branch information
sroussey authored Feb 4, 2024
1 parent 8d649b0 commit 50df550
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 76 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,5 @@ dist
.pnp.*

storybook-static/
stories/

stats.html
43 changes: 8 additions & 35 deletions lib/NodeGraphEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
Background,
BackgroundVariant,
Edge,
Node,
ReactFlow,
ReactFlowProps,
ReactFlowProvider,
Expand All @@ -12,12 +8,9 @@ import {
useReactFlow,
useStoreApi,
} from '@xyflow/react'
import {
GraphConfigProvider,
useGraphConfig,
} from './context/GraphConfigContext'
import { useGraphConfig } from './context/GraphConfigContext'
import '@xyflow/react/dist/style.css'
import { useBuildGraphConfig, useNodeTypes } from './hooks/config'
import { useNodeTypes } from './hooks/config'
import {
forwardRef,
useImperativeHandle,
Expand All @@ -27,7 +20,6 @@ import {
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'
Expand Down Expand Up @@ -62,26 +54,6 @@ export const NodeGraphEditor = forwardRef<
},
)

type ExampleNodeGraphEditorProps = {
nodes: Node[]
edges: Edge[]
config: IGraphConfig
}

export const ExampleNodeGraphEditor = forwardRef<
NodeGraphHandle,
ExampleNodeGraphEditorProps
>(({ nodes, edges, config: _config }: ExampleNodeGraphEditorProps, ref) => {
const config = useBuildGraphConfig(_config)
return (
<GraphConfigProvider defaultConfig={config}>
<NodeGraphEditor ref={ref} defaultNodes={nodes} defaultEdges={edges}>
<Background color="#52525b" variant={BackgroundVariant.Dots} />
</NodeGraphEditor>
</GraphConfigProvider>
)
})

type FlowProps = ReactFlowProps & {
backgroundStyles?: CSSProperties,
/**
Expand All @@ -90,7 +62,7 @@ type FlowProps = ReactFlowProps & {
layoutEngine?: LayoutEngine
}
export type NodeGraphHandle = {
layout: () => void
layout: (engine?: LayoutEngine) => void
}

const Flow = forwardRef<NodeGraphHandle, FlowProps>(
Expand All @@ -117,7 +89,8 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
)

// Provide methods to parent components
const layout = useLayoutEngine(layoutEngine ?? LayoutEngine.Dagre)
const layout = useLayoutEngine()

useImperativeHandle(
ref,
() => ({
Expand All @@ -131,10 +104,10 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
const shouldLayout = !!getState().nodes.find(
(node) => node.position == undefined,
)
if (initialized && shouldLayout) {
layout()
if (initialized && shouldLayout && layoutEngine) {
layout(layoutEngine)
}
}, [initialized])
}, [initialized, layoutEngine])

return (
<div
Expand Down
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export { NodeSelectField } from './components/NodeSelectField.tsx'
export { NodeDenseLinkedField } from './components/NodeDenseLinkedField.tsx'
export { NodeLinkedField } from './components/NodeLinkedField.tsx'
export { NodeOutputField } from './components/NodeOutputField.tsx'
export { registerLayoutEngine } from './layout/layout.ts'
32 changes: 19 additions & 13 deletions lib/layout/layout.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { useCallback } from 'react'
import { computeDagreLayout } from './dagre'
import { Edge, Instance, Node, useReactFlow } from '@xyflow/react'

export enum LayoutEngine {
Dagre,
}
export type LayoutEngine = string

type LayoutFunc = () => void
export type LayoutFunc = (nodes: Node[], edges: Edge[]) => Node[]

export function useLayoutEngine(engine: LayoutEngine): LayoutFunc {
export function useLayoutEngine() {
const { getNodes, getEdges, setNodes } = useReactFlow()
return useCallback(() => {
return useCallback((engine?: LayoutEngine) => {
if (!engine) return
setNodes(computeLayout(engine, getNodes, getEdges))
}, [engine])
}, [])
}

function computeLayout(
Expand All @@ -25,11 +23,19 @@ function computeLayout(
return layoutFn(getNodes(), getEdges())
}

const layoutEngines: Record<LayoutEngine, LayoutFunc> = {}

export function registerLayoutEngine(
engine: LayoutEngine,
layoutFn: LayoutFunc,
) {
layoutEngines[engine] = layoutFn
}

export function getLayoutFunction(
engine: LayoutEngine | undefined,
engine: LayoutEngine,
): ((nodes: Node[], edges: Edge[]) => Node[]) | undefined {
switch (engine) {
case LayoutEngine.Dagre:
return computeDagreLayout
}
const layoutFn = layoutEngines[engine]
if (!layoutFn) throw new Error(`Unknown layout engine ${engine}`)
return layoutFn
}
33 changes: 33 additions & 0 deletions lib/stories/ExampleNodeGraphEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Background,
BackgroundVariant,
Edge,
Node,
} from '@xyflow/react'
import { forwardRef } from "react"
import { NodeGraphEditor, NodeGraphHandle } from "../NodeGraphEditor"
import { GraphConfigProvider } from "../context/GraphConfigContext"
import { useBuildGraphConfig } from '../hooks/config'
import { IGraphConfig } from "../config"

type ExampleNodeGraphEditorProps = {
nodes: Node[]
edges: Edge[]
config: IGraphConfig
}

export const ExampleNodeGraphEditor = forwardRef<
NodeGraphHandle,
ExampleNodeGraphEditorProps
>(({ nodes, edges, config: _config }: ExampleNodeGraphEditorProps, ref) => {
const config = useBuildGraphConfig(_config)
return (
<GraphConfigProvider defaultConfig={config}>
<NodeGraphEditor ref={ref} defaultNodes={nodes} defaultEdges={edges}>
<Background color="#52525b" variant={BackgroundVariant.Dots} />
</NodeGraphEditor>
</GraphConfigProvider>
)
})


Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ExampleNodeGraphEditor } from './NodeGraphEditor'
import { ExampleNodeGraphEditor } from './ExampleNodeGraphEditor'
import { Meta, StoryObj } from '@storybook/react'
import { IGraphConfig } from './config'
import { IGraphConfig } from '../config'

const simpleConfig: IGraphConfig = {
valueTypes: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { NodeGraphEditor } from './NodeGraphEditor'
import { NodeGraphEditor } from '../NodeGraphEditor.tsx'
import { Meta, StoryObj } from '@storybook/react'
import { GraphConfigProvider } from './context/GraphConfigContext'
import { GraphConfigProvider } from '../context/GraphConfigContext.tsx'
import {
Background,
BackgroundVariant,
Edge,
Node,
} from '@xyflow/react'
import { useBuildGraphConfig } from './hooks/config.ts'
import { NodeInputField } from './components/NodeInputField.tsx'
import { InputProps } from './config.ts'
import { useBuildGraphConfig } from '../hooks/config.ts'
import { NodeInputField } from '../components/NodeInputField.tsx'
import { InputProps } from '../config.ts'

const meta = {
title: 'Node Graph Editor',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NodeGraphEditor } from './NodeGraphEditor'
import { NodeGraphEditor } from '../NodeGraphEditor'
import { Meta, StoryObj } from '@storybook/react'
import { GraphConfigProvider } from './context/GraphConfigContext'
import { GraphConfig } from './config'
import { GraphConfigProvider } from '../context/GraphConfigContext'
import { GraphConfig } from '../config'
import { useMemo } from 'react'
import {
Background,
Expand All @@ -10,9 +10,9 @@ import {
Node,
Position,
} from '@xyflow/react'
import { NodeContainer } from './components/NodeContainer'
import { useFocusBlur } from './hooks/focus'
import { Handle } from './components/Handle'
import { NodeContainer } from '../components/NodeContainer'
import { useFocusBlur } from '../hooks/focus'
import { Handle } from '../components/Handle'

const meta = {
title: 'Node Graph Editor',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { NodeGraphEditor } from './NodeGraphEditor'
import { NodeGraphEditor } from '../NodeGraphEditor.tsx'
import { Meta, StoryObj } from '@storybook/react'
import { GraphConfigProvider } from './context/GraphConfigContext'
import { GraphConfigProvider } from '../context/GraphConfigContext.tsx'
import {
Background,
BackgroundVariant,
Edge,
Node,
} from '@xyflow/react'
import { useBuildGraphConfig } from './hooks/config.ts'
import { InputProps } from './config.ts'
import { useBuildGraphConfig } from '../hooks/config.ts'
import { InputProps } from '../config.ts'
import { Wheel } from '@uiw/react-color'
import { useNodeFieldValue } from './hooks/node.ts'
import { useNodeFieldValue } from '../hooks/node.ts'
import { registerLayoutEngine } from '../layout/layout.ts'
import { computeDagreLayout } from '../layout/dagre.ts'

registerLayoutEngine('dagre', computeDagreLayout)

const meta = {
title: 'Node Graph Editor',
Expand Down Expand Up @@ -201,8 +205,8 @@ const meta = {
)
return (
<GraphConfigProvider defaultConfig={config}>
<NodeGraphEditor defaultNodes={nodes} defaultEdges={edges}>
<Background color="#52525b" variant={BackgroundVariant.Dots} />
<NodeGraphEditor defaultNodes={nodes} defaultEdges={edges} layoutEngine="dagre">
<Background color="#52525b" variant={BackgroundVariant.Dots}/>
</NodeGraphEditor>
</GraphConfigProvider>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { ExampleNodeGraphEditor, NodeGraphHandle } from './NodeGraphEditor'
import { ExampleNodeGraphEditor } from './ExampleNodeGraphEditor'
import { NodeGraphHandle } from '../NodeGraphEditor'
import { Meta, StoryObj } from '@storybook/react'
import { useRef } from 'react'
import { registerLayoutEngine } from '../layout/layout'
import { computeDagreLayout } from '../layout/dagre'

registerLayoutEngine('dagre', computeDagreLayout)

const meta = {
title: 'Node Graph Editor',
component: ({ config, nodes, edges }) => {
const ref = useRef<NodeGraphHandle>(null)
return (
<div style={{ width: '100%', height: '100%' }}>
<button
style={{ position: 'absolute', top: 10, left: 10, zIndex: 1000 }}
onClick={() => ref.current!.layout()}
>
Layout
</button>
<div style={{position: 'absolute', top: 10, left: 10, zIndex: 1000}}>
<button
style={{ }}
onClick={() => ref.current!.layout('dagre')}
>
Dagre Layout
</button>
</div>
<ExampleNodeGraphEditor
ref={ref}
config={config}
Expand Down

0 comments on commit 50df550

Please sign in to comment.