feat: introdce store
This commit is contained in:
@@ -15,8 +15,9 @@
|
||||
* component, then export const MyNode = createAbstractNodeComponent('MyNode', MyNodeComponent).
|
||||
*/
|
||||
|
||||
import React, { useCallback, useContext, useMemo, useRef } from 'react'
|
||||
import { GraphContext, ConnectionPathContext } from './flowContext'
|
||||
import React, { useCallback, useContext, useMemo } from 'react'
|
||||
import { GraphContext } from './flowContext'
|
||||
import { dispatchCanvasCommand } from '@/app/canvas/canvasStore'
|
||||
import { nodePropsAreEqual } from './flowUtils'
|
||||
import type { AppNode } from './nodeTypes'
|
||||
|
||||
@@ -81,9 +82,6 @@ export function useAbstractNode<TData = Record<string, unknown>>(
|
||||
data: TData
|
||||
): AbstractNodeContext<TData> {
|
||||
const graphCtx = useContext(GraphContext)
|
||||
const pathCtx = useContext(ConnectionPathContext)
|
||||
const addTriggerRef = useRef(pathCtx?.addConnectionPathTrigger)
|
||||
addTriggerRef.current = pathCtx?.addConnectionPathTrigger
|
||||
const nodes = graphCtx?.graphRef?.current?.nodes ?? []
|
||||
const edges = graphCtx?.edges ?? []
|
||||
const setNodes = graphCtx?.setNodes
|
||||
@@ -97,7 +95,7 @@ export function useAbstractNode<TData = Record<string, unknown>>(
|
||||
n.id === id ? { ...n, data: { ...(n.data as object), ...partial } } : n
|
||||
) as AppNode[]
|
||||
)
|
||||
addTriggerRef.current?.(id)
|
||||
dispatchCanvasCommand({ type: 'path/addTrigger', payload: id })
|
||||
},
|
||||
[id, setNodes]
|
||||
)
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* ## State flow
|
||||
*
|
||||
* Nodes report lifecycle (updating / error / paused) via useSyncConnectionStatus(id, state).
|
||||
* This hook updates FlowContext sets; edges read them via getConnectionStatus() in connectionStatus.ts.
|
||||
* See lib/graph/state.ts for the overall state flow (graph state, connection path state).
|
||||
* This hook dispatches to the canvas store; edges read path state via selectors.
|
||||
*
|
||||
* ## Lifecycle phases (conceptual)
|
||||
*
|
||||
@@ -19,14 +18,14 @@
|
||||
* Priority for edge status: error > paused > updating > default.
|
||||
*/
|
||||
|
||||
import { useContext, useEffect, useRef } from 'react'
|
||||
import { ConnectionPathContext } from './flowContext'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { dispatchCanvasCommand } from '@/app/canvas/canvasStore'
|
||||
|
||||
export type NodeLifecyclePhase = 'idle' | 'trigger' | 'updating' | 'paused' | 'error'
|
||||
|
||||
/**
|
||||
* State that drives connection status for this node.
|
||||
* Pass the current values from your node; the hook syncs them to FlowContext.
|
||||
* Pass the current values from your node; the hook syncs them to the canvas store.
|
||||
*/
|
||||
export type NodeConnectionStatusState = {
|
||||
/** Node is doing async work (e.g. loading, running). Incoming/outgoing path edges show blue. */
|
||||
@@ -38,9 +37,9 @@ export type NodeConnectionStatusState = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs this node's lifecycle state to FlowContext so connection status (edge colors)
|
||||
* Syncs this node's lifecycle state to the canvas store so connection status (edge colors)
|
||||
* and path animation are correct. Call once per node with the current updating/error/paused
|
||||
* state; the hook will add/remove this node from the appropriate sets.
|
||||
* state; the hook will dispatch path commands to add/remove this node from the appropriate sets.
|
||||
*
|
||||
* Use in any node that can be updating, in error, or paused:
|
||||
*
|
||||
@@ -53,39 +52,33 @@ export function useSyncConnectionStatus(
|
||||
nodeId: string,
|
||||
state: NodeConnectionStatusState
|
||||
): void {
|
||||
const ctx = useContext(ConnectionPathContext)
|
||||
const ctxRef = useRef(ctx)
|
||||
ctxRef.current = ctx
|
||||
const { updating, error, paused } = state
|
||||
const prevRef = useRef({ updating: false, error: false, paused: false })
|
||||
|
||||
useEffect(() => {
|
||||
const pathCtx = ctxRef.current
|
||||
const prev = prevRef.current
|
||||
const nowUpdating = Boolean(updating)
|
||||
const nowError = Boolean(error)
|
||||
const nowPaused = Boolean(paused)
|
||||
|
||||
if (prev.updating !== nowUpdating) {
|
||||
if (nowUpdating) pathCtx?.startConnectionPathUpdate?.(nodeId)
|
||||
else pathCtx?.endConnectionPathUpdate?.(nodeId)
|
||||
if (nowUpdating) dispatchCanvasCommand({ type: 'path/startUpdate', payload: nodeId })
|
||||
else dispatchCanvasCommand({ type: 'path/endUpdate', payload: nodeId })
|
||||
prev.updating = nowUpdating
|
||||
}
|
||||
if (prev.error !== nowError) {
|
||||
if (nowError) pathCtx?.addConnectionPathError?.(nodeId)
|
||||
else pathCtx?.removeConnectionPathError?.(nodeId)
|
||||
dispatchCanvasCommand({ type: 'path/setError', payload: { nodeId, error: nowError } })
|
||||
prev.error = nowError
|
||||
}
|
||||
if (prev.paused !== nowPaused) {
|
||||
if (nowPaused) pathCtx?.addConnectionPathPausedNode?.(nodeId)
|
||||
else pathCtx?.removeConnectionPathPausedNode?.(nodeId)
|
||||
dispatchCanvasCommand({ type: 'path/setPaused', payload: { nodeId, paused: nowPaused } })
|
||||
prev.paused = nowPaused
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (prevRef.current.updating) pathCtx?.endConnectionPathUpdate?.(nodeId)
|
||||
if (prevRef.current.error) pathCtx?.removeConnectionPathError?.(nodeId)
|
||||
if (prevRef.current.paused) pathCtx?.removeConnectionPathPausedNode?.(nodeId)
|
||||
if (prevRef.current.updating) dispatchCanvasCommand({ type: 'path/endUpdate', payload: nodeId })
|
||||
if (prevRef.current.error) dispatchCanvasCommand({ type: 'path/setError', payload: { nodeId, error: false } })
|
||||
if (prevRef.current.paused) dispatchCanvasCommand({ type: 'path/setPaused', payload: { nodeId, paused: false } })
|
||||
prevRef.current = { updating: false, error: false, paused: false }
|
||||
}
|
||||
}, [nodeId, updating, error, paused])
|
||||
|
||||
Reference in New Issue
Block a user