Improve return type of useNodesdata
This commit is contained in:
8
.changeset/old-laws-melt.md
Normal file
8
.changeset/old-laws-melt.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@xyflow/react': patch
|
||||
'@xyflow/svelte': patch
|
||||
'@xyflow/system': patch
|
||||
---
|
||||
|
||||
Improve return type of useNodesData. Now you can narrow down the data type by checking the node type.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { memo, useState } from 'react';
|
||||
import { Position, NodeProps, Handle, useReactFlow } from '@xyflow/react';
|
||||
import type { TextNode } from '.';
|
||||
|
||||
function TextNode({ id, data }: NodeProps) {
|
||||
function TextNode({ id, data }: NodeProps<TextNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
const [text, setText] = useState(data.text);
|
||||
const updateText = (text: string) => {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { memo, useEffect } from 'react';
|
||||
import { Position, NodeProps, useReactFlow, Handle, useNodeConnections, useNodesData } from '@xyflow/react';
|
||||
import { isTextNode, type TextNode, type MyNode } from '.';
|
||||
import { isTextNode, type TextNode, type MyNode, type UppercaseNode } from '.';
|
||||
|
||||
function UppercaseNode({ id }: NodeProps) {
|
||||
function UppercaseNode({ id }: NodeProps<UppercaseNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
const connections = useNodeConnections({
|
||||
handleType: 'target',
|
||||
});
|
||||
const nodesData = useNodesData<MyNode>(connections[0]?.source);
|
||||
const textNode = isTextNode(nodesData) ? nodesData : null;
|
||||
|
||||
useEffect(() => {
|
||||
updateNodeData(id, { text: textNode?.data.text.toUpperCase() });
|
||||
}, [textNode]);
|
||||
const text = nodesData?.type === 'text' ? nodesData?.data.text.toUpperCase() : undefined;
|
||||
updateNodeData(id, { text });
|
||||
}, [nodesData]);
|
||||
|
||||
return (
|
||||
<div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}>
|
||||
|
||||
@@ -8,22 +8,21 @@
|
||||
type Node,
|
||||
type NodeProps
|
||||
} from '@xyflow/svelte';
|
||||
import { isTextNode, type MyNode } from './+page.svelte';
|
||||
import { type MyNode } from './+page.svelte';
|
||||
|
||||
let { id }: NodeProps<Node<{ text: string }>> = $props();
|
||||
|
||||
const { updateNodeData } = useSvelteFlow();
|
||||
const connections = useNodeConnections({
|
||||
id: id,
|
||||
handleType: 'target'
|
||||
});
|
||||
|
||||
let nodeData = $derived(useNodesData<MyNode>(connections.current[0]?.source));
|
||||
let textNodeData = $derived(isTextNode(nodeData.current) ? nodeData.current.data.text : null);
|
||||
let nodesData = $derived(useNodesData<MyNode>(connections.current[0]?.source));
|
||||
|
||||
$effect.pre(() => {
|
||||
const input = textNodeData?.toUpperCase() ?? '';
|
||||
updateNodeData(id, { text: input });
|
||||
const text =
|
||||
nodesData.current?.type === 'text' ? nodesData.current?.data.text.toUpperCase() : undefined;
|
||||
updateNodeData(id, { text });
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { shallowNodeData } from '@xyflow/system';
|
||||
import { DistributivePick, shallowNodeData } from '@xyflow/system';
|
||||
|
||||
import { useStore } from '../hooks/useStore';
|
||||
import type { Node } from '../types';
|
||||
@@ -25,11 +25,11 @@ import type { Node } from '../types';
|
||||
export function useNodesData<NodeType extends Node = Node>(
|
||||
/** The id of the node to get the data from. */
|
||||
nodeId: string
|
||||
): Pick<NodeType, 'id' | 'type' | 'data'> | null;
|
||||
): DistributivePick<NodeType, 'id' | 'type' | 'data'> | null;
|
||||
export function useNodesData<NodeType extends Node = Node>(
|
||||
/** The ids of the nodes to get the data from. */
|
||||
nodeIds: string[]
|
||||
): Pick<NodeType, 'id' | 'type' | 'data'>[];
|
||||
): DistributivePick<NodeType, 'id' | 'type' | 'data'>[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function useNodesData(nodeIds: any): any {
|
||||
const nodesData = useStore(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { shallowNodeData } from '@xyflow/system';
|
||||
import { shallowNodeData, type DistributivePick } from '@xyflow/system';
|
||||
|
||||
import type { Node } from '$lib/types';
|
||||
import { useStore } from '$lib/store';
|
||||
@@ -12,10 +12,10 @@ import { useStore } from '$lib/store';
|
||||
*/
|
||||
export function useNodesData<NodeType extends Node = Node>(
|
||||
nodeId: string
|
||||
): { current: Pick<NodeType, 'id' | 'data' | 'type'> | null };
|
||||
): { current: DistributivePick<NodeType, 'id' | 'data' | 'type'> | null };
|
||||
export function useNodesData<NodeType extends Node = Node>(
|
||||
nodeIds: string[]
|
||||
): { current: Pick<NodeType, 'id' | 'data' | 'type'>[] };
|
||||
): { current: DistributivePick<NodeType, 'id' | 'data' | 'type'>[] };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function useNodesData(nodeIds: any): any {
|
||||
const { nodes, nodeLookup } = $derived(useStore());
|
||||
|
||||
@@ -56,3 +56,10 @@ export type Transform = [number, number, number];
|
||||
* to represent an unbounded extent.
|
||||
*/
|
||||
export type CoordinateExtent = [[number, number], [number, number]];
|
||||
|
||||
/**
|
||||
* Using Pick with a union type (e.g. `NodeType`) will merge every property type along all union members.
|
||||
* See https://github.com/microsoft/TypeScript/issues/28339#issuecomment-463577347
|
||||
* Note: Currently you are able to Pick properties that are not in the type without error.
|
||||
*/
|
||||
export type DistributivePick<T, K extends string> = T extends unknown ? { [P in Extract<keyof T, K>]: T[P] } : never;
|
||||
|
||||
Reference in New Issue
Block a user