@matthewgapp/solidjs-flow
Version:
React Flow - A highly customizable React library for building node-based editors and interactive flow charts.
76 lines (67 loc) • 2.62 kB
text/typescript
// import { useEffect, useRef } from 'react';
import type { InternalNode } from '../../types';
import { useStoreApi } from '../../hooks/useStore';
import { useRef } from '../../utils/hooks';
import { createEffect, onCleanup } from 'solid-js';
// TODO: this seems wrong - nodeRef is never updated?
/**
* Hook to handle the resize observation + internal updates for the passed node.
*
* @internal
* @returns nodeRef - reference to the node element
*/
export function useNodeObserver({
node: getNode,
nodeType: getNodeType,
hasDimensions,
resizeObserver: getResizeObserver,
}: {
node: () => InternalNode;
nodeType: () => string;
hasDimensions: () => boolean;
resizeObserver: () => ResizeObserver | null;
}) {
const store = useStoreApi();
const nodeRef = useRef<HTMLDivElement | null>(null);
const observedNode = useRef<HTMLDivElement | null>(null);
const prevSourcePosition = useRef(getNode().sourcePosition);
const prevTargetPosition = useRef(getNode().targetPosition);
const prevType = useRef(getNodeType());
const isInitialized = () => hasDimensions() && !!getNode().internals.handleBounds && !getNode().hidden;
createEffect(() => {
const resizeObserver = getResizeObserver();
if (nodeRef.current && (!isInitialized() || observedNode.current !== nodeRef.current)) {
if (observedNode.current) {
resizeObserver?.unobserve(observedNode.current);
}
resizeObserver?.observe(nodeRef.current);
observedNode.current = nodeRef.current;
}
});
onCleanup(() => {
const resizeObserver = getResizeObserver();
if (observedNode.current) {
resizeObserver?.unobserve(observedNode.current);
observedNode.current = null;
}
});
createEffect(() => {
const node = getNode();
const nodeType = getNodeType();
if (nodeRef.current) {
// when the user programmatically changes the source or handle position, we need to update the internals
// to make sure the edges are updated correctly
const typeChanged = prevType.current !== nodeType;
const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
if (typeChanged || sourcePosChanged || targetPosChanged) {
prevType.current = nodeType;
prevSourcePosition.current = node.sourcePosition;
prevTargetPosition.current = node.targetPosition;
store
.updateNodeInternals(new Map([[node.id, { id: node.id, nodeElement: nodeRef.current, force: true }]]));
}
}
});
return nodeRef;
}