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

rework stories and layout #24

Merged
merged 2 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
Loading