refactor(useSetNodeData): put function in useReactFlow/useSvelteFlow
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
// Shortcut action is copied and slightly adjusted from https://github.com/vnphanquang/svelte-put/tree/main/packages/actions/shortcut
|
||||
// If this discussion https://github.com/vnphanquang/svelte-put/discussions/256 gets resolved, we will use the original action again.
|
||||
|
||||
export interface ShortcutEventDetail {
|
||||
event: KeyboardEvent;
|
||||
trigger: ShortcutTrigger;
|
||||
}
|
||||
|
||||
export type ShortcutModifier = 'alt' | 'ctrl' | 'meta' | 'shift';
|
||||
|
||||
export type ShortcutModifierDefinition =
|
||||
| ShortcutModifier
|
||||
| ShortcutModifier[]
|
||||
| ShortcutModifier[][];
|
||||
|
||||
export type ShortcutTrigger = {
|
||||
enabled?: boolean;
|
||||
modifier?: ShortcutModifierDefinition;
|
||||
id?: string;
|
||||
key: string;
|
||||
callback?: (detail: ShortcutEventDetail) => void;
|
||||
preventDefault?: boolean;
|
||||
};
|
||||
|
||||
export type ShortcutParameter = {
|
||||
enabled?: boolean;
|
||||
trigger: Array<ShortcutTrigger> | ShortcutTrigger;
|
||||
type?: 'keydown' | 'keyup';
|
||||
};
|
||||
|
||||
export function shortcut(node: Window, param: ShortcutParameter) {
|
||||
let { enabled = true, trigger, type = 'keydown' } = param;
|
||||
|
||||
function handler(event: KeyboardEvent) {
|
||||
const normalizedTriggers = Array.isArray(trigger) ? trigger : [trigger];
|
||||
const modifiedMap = {
|
||||
alt: event.altKey,
|
||||
ctrl: event.ctrlKey,
|
||||
shift: event.shiftKey,
|
||||
meta: event.metaKey
|
||||
};
|
||||
for (const trigger of normalizedTriggers) {
|
||||
const mergedTrigger = {
|
||||
modifier: [],
|
||||
preventDefault: false,
|
||||
enabled: true,
|
||||
...trigger
|
||||
};
|
||||
const { modifier, key, callback, preventDefault, enabled: triggerEnabled } = mergedTrigger;
|
||||
if (triggerEnabled) {
|
||||
if (modifier.length) {
|
||||
const modifierDefs = (Array.isArray(modifier) ? modifier : [modifier]).map((def) =>
|
||||
typeof def === 'string' ? [def] : def
|
||||
);
|
||||
const modified = modifierDefs.some((def) =>
|
||||
def.every((modifier) => modifiedMap[modifier])
|
||||
);
|
||||
if (!modified) continue;
|
||||
}
|
||||
if (event.key === key) {
|
||||
if (preventDefault) event.preventDefault();
|
||||
const detail = { event, trigger: mergedTrigger };
|
||||
callback?.(detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled) node.addEventListener(type, handler);
|
||||
|
||||
return {
|
||||
update: (update: ShortcutParameter) => {
|
||||
const { enabled: newEnabled = true, type: newType = 'keydown' } = update;
|
||||
|
||||
if (enabled && (!newEnabled || type !== newType)) {
|
||||
node.removeEventListener(type, handler);
|
||||
} else if (!enabled && newEnabled) {
|
||||
node.addEventListener(newType, handler);
|
||||
}
|
||||
|
||||
enabled = newEnabled;
|
||||
type = newType;
|
||||
trigger = update.trigger;
|
||||
},
|
||||
destroy: () => {
|
||||
node.removeEventListener(type, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut';
|
||||
import { isInputDOMNode, isMacOs } from '@xyflow/system';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { KeyHandlerProps } from './types';
|
||||
import type { KeyDefinition, KeyDefinitionObject } from '$lib/types';
|
||||
import { shortcut, type ShortcutModifierDefinition } from '../../actions/shortcut';
|
||||
|
||||
type $$Props = KeyHandlerProps;
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
{
|
||||
...deleteKeyDefinition,
|
||||
enabled: deleteKeyDefinition.key !== null,
|
||||
callback: (detail) => !isInputDOMNode(detail.event) && deleteKeyPressed.set(true)
|
||||
callback: (detail) => !isInputDOMNode(detail.originalEvent) && deleteKeyPressed.set(true)
|
||||
}
|
||||
],
|
||||
type: 'keydown'
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { useStore } from '$lib/store';
|
||||
import type { Node } from '$lib/types';
|
||||
|
||||
export function useSetNodeData<NodeType extends Node = Node>() {
|
||||
const { nodes } = useStore();
|
||||
|
||||
const setNodeData = (
|
||||
id: string,
|
||||
dataUpdate: object | ((node: NodeType) => object),
|
||||
options: { replace: boolean } = { replace: true }
|
||||
) => {
|
||||
nodes.update((nds) =>
|
||||
nds.map((node) => {
|
||||
if (node.id === id) {
|
||||
const nextData =
|
||||
typeof dataUpdate === 'function' ? dataUpdate(node as NodeType) : dataUpdate;
|
||||
return options.replace
|
||||
? { ...node, data: nextData }
|
||||
: { ...node, data: { ...node.data, ...nextData } };
|
||||
}
|
||||
|
||||
return node;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return setNodeData;
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { get, type Writable } from 'svelte/store';
|
||||
import {
|
||||
getIncomersBase,
|
||||
getOutgoersBase,
|
||||
getOverlappingArea,
|
||||
isRectObject,
|
||||
nodeToRect,
|
||||
@@ -20,6 +18,7 @@ import {
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { Edge, FitViewOptions, Node } from '$lib/types';
|
||||
import { isNode } from '$lib/utils';
|
||||
|
||||
export function useSvelteFlow(): {
|
||||
zoomIn: ZoomInOut;
|
||||
@@ -48,9 +47,16 @@ export function useSvelteFlow(): {
|
||||
screenToFlowPosition: (position: XYPosition) => XYPosition;
|
||||
flowToScreenPosition: (position: XYPosition) => XYPosition;
|
||||
viewport: Writable<Viewport>;
|
||||
getConnectedEdges: (id: string | (Node | { id: Node['id'] })[]) => Edge[];
|
||||
getIncomers: (node: string | Node | { id: Node['id'] }) => Node[];
|
||||
getOutgoers: (node: string | Node | { id: Node['id'] }) => Node[];
|
||||
updateNode: (
|
||||
id: string,
|
||||
nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
|
||||
options?: { replace: boolean }
|
||||
) => void;
|
||||
updateNodeData: (
|
||||
id: string,
|
||||
dataUpdate: object | ((node: Node) => object),
|
||||
options?: { replace: boolean }
|
||||
) => void;
|
||||
toObject: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport };
|
||||
} {
|
||||
const {
|
||||
@@ -84,6 +90,24 @@ export function useSvelteFlow(): {
|
||||
return [nodeRect, node, isRect];
|
||||
};
|
||||
|
||||
const updateNode = (
|
||||
id: string,
|
||||
nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
|
||||
options: { replace: boolean } = { replace: false }
|
||||
) => {
|
||||
nodes.update((nds) =>
|
||||
nds.map((node) => {
|
||||
if (node.id === id) {
|
||||
const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node as Node) : nodeUpdate;
|
||||
|
||||
return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
|
||||
}
|
||||
|
||||
return node;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
@@ -232,29 +256,6 @@ export function useSvelteFlow(): {
|
||||
y: rendererPosition.y + domY
|
||||
};
|
||||
},
|
||||
getConnectedEdges: (node) => {
|
||||
const nodeIds = new Set();
|
||||
|
||||
if (typeof node === 'string') {
|
||||
nodeIds.add(node);
|
||||
} else if (node.length >= 1) {
|
||||
node.forEach((n) => {
|
||||
nodeIds.add(n.id);
|
||||
});
|
||||
}
|
||||
|
||||
return get(edges).filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
|
||||
},
|
||||
getIncomers: (node) => {
|
||||
const _node = typeof node === 'string' ? { id: node } : node;
|
||||
|
||||
return getIncomersBase(_node, get(nodes), get(edges));
|
||||
},
|
||||
getOutgoers: (node) => {
|
||||
const _node = typeof node === 'string' ? { id: node } : node;
|
||||
|
||||
return getOutgoersBase(_node, get(nodes), get(edges));
|
||||
},
|
||||
toObject: () => {
|
||||
return {
|
||||
nodes: get(nodes).map((node) => ({
|
||||
@@ -268,6 +269,16 @@ export function useSvelteFlow(): {
|
||||
viewport: { ...get(viewport) }
|
||||
};
|
||||
},
|
||||
updateNode,
|
||||
updateNodeData: (id, dataUpdate, options) => {
|
||||
updateNode(id, (node) => {
|
||||
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
|
||||
|
||||
return options?.replace
|
||||
? { ...node, data: nextData }
|
||||
: { ...node, data: { ...node.data, ...nextData } };
|
||||
});
|
||||
},
|
||||
viewport
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ export * from '$lib/hooks/useConnection';
|
||||
export * from '$lib/hooks/useNodesEdges';
|
||||
export * from '$lib/hooks/useHandleConnections';
|
||||
export * from '$lib/hooks/useNodesData';
|
||||
export * from '$lib/hooks/useSetNodeData';
|
||||
|
||||
// types
|
||||
export type {
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
|
||||
import type { Edge, Node } from '$lib/types';
|
||||
|
||||
export const isNode = isNodeBase<Node, Edge>;
|
||||
export const isEdge = isEdgeBase<Node, Edge>;
|
||||
export const isNode = isNodeBase<Node>;
|
||||
export const isEdge = isEdgeBase<Edge>;
|
||||
export const getOutgoers = getOutgoersBase<Node, Edge>;
|
||||
export const getIncomers = getIncomersBase<Node, Edge>;
|
||||
export const addEdge = addEdgeBase<Edge>;
|
||||
|
||||
Reference in New Issue
Block a user