diff --git a/packages/svelte/src/example-components/Header/Header.svelte b/packages/svelte/src/example-components/Header/Header.svelte index 75ec5053..edf34a58 100644 --- a/packages/svelte/src/example-components/Header/Header.svelte +++ b/packages/svelte/src/example-components/Header/Header.svelte @@ -3,7 +3,8 @@ const routes = [ 'overview', - 'stress' + 'stress', + 'usesvelteflow' ]; const onChange = (event: Event) => { diff --git a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte index c4944a02..3de2050c 100644 --- a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte +++ b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte @@ -24,7 +24,7 @@ export let selected: $$Props['selected'] = false; export let label: $$Props['label'] = undefined; - const { edgeTypes, edges } = useStore(); + const { edges, edgeTypes } = useStore(); const dispatch = createEventDispatcher(); const edgeComponent: typeof SvelteComponentTyped = $edgeTypes[type!] || BezierEdge; diff --git a/packages/svelte/src/lib/components/KeyHandler/KeyHandler.svelte b/packages/svelte/src/lib/components/KeyHandler/KeyHandler.svelte index 8f800add..9b2747db 100644 --- a/packages/svelte/src/lib/components/KeyHandler/KeyHandler.svelte +++ b/packages/svelte/src/lib/components/KeyHandler/KeyHandler.svelte @@ -5,13 +5,13 @@ import type { KeyHandlerProps } from './types'; import type { KeyDefinition, KeyDefinitionObject } from '$lib/types'; - const { selectionKeyPressed, deleteKeyPressed } = useStore(); - type $$Props = KeyHandlerProps; export let selectionKey: $$Props['selectionKey'] = 'Shift'; export let deleteKey: $$Props['deleteKey'] = 'Backspace'; + const { selectionKeyPressed, deleteKeyPressed } = useStore(); + function isKeyObject(key?: KeyDefinition): key is KeyDefinitionObject { return typeof key === 'object'; } diff --git a/packages/svelte/src/lib/components/SvelteFlowProvider/SvelteFlowProvider.svelte b/packages/svelte/src/lib/components/SvelteFlowProvider/SvelteFlowProvider.svelte new file mode 100644 index 00000000..ee448ab7 --- /dev/null +++ b/packages/svelte/src/lib/components/SvelteFlowProvider/SvelteFlowProvider.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/svelte/src/lib/components/SvelteFlowProvider/index.ts b/packages/svelte/src/lib/components/SvelteFlowProvider/index.ts new file mode 100644 index 00000000..38389c7b --- /dev/null +++ b/packages/svelte/src/lib/components/SvelteFlowProvider/index.ts @@ -0,0 +1,2 @@ +export { default as SvelteFlowProvider } from './SvelteFlowProvider.svelte'; +export type { SvelteFlowProviderProps } from './types'; diff --git a/packages/svelte/src/lib/components/SvelteFlowProvider/types.ts b/packages/svelte/src/lib/components/SvelteFlowProvider/types.ts new file mode 100644 index 00000000..2b102f3f --- /dev/null +++ b/packages/svelte/src/lib/components/SvelteFlowProvider/types.ts @@ -0,0 +1,6 @@ +import type { SvelteFlowProps } from '$lib/container/SvelteFlow/types'; + +export type SvelteFlowProviderProps = Pick< + SvelteFlowProps, + 'nodes' | 'edges' | 'fitView' | 'nodeTypes' +>; diff --git a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte index c6b74015..4d6432fd 100644 --- a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte +++ b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte @@ -1,12 +1,12 @@ + +{#if hasContext(key)} + + + +{:else} + + + + + +{/if} \ No newline at end of file diff --git a/packages/svelte/src/lib/container/SvelteFlow/index.ts b/packages/svelte/src/lib/container/SvelteFlow/index.ts index eaec432b..e0b8153e 100644 --- a/packages/svelte/src/lib/container/SvelteFlow/index.ts +++ b/packages/svelte/src/lib/container/SvelteFlow/index.ts @@ -1,2 +1,2 @@ -export { default as SvelteFlow } from './SvelteFlow.svelte'; +export { default as SvelteFlow } from './Wrapper.svelte'; export * from './types'; diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts new file mode 100644 index 00000000..60fdd3ef --- /dev/null +++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts @@ -0,0 +1,19 @@ +import type { ZoomInOut } from '@reactflow/system'; + +import { useStore } from '$lib/store'; +import type { FitViewOptions } from '$lib/types'; + +export function useSvelteFlow(): { + zoomIn: ZoomInOut; + zoomOut: ZoomInOut; + fitView: (options?: FitViewOptions) => void; +} { + // how to get the new context here? fit view doesn't work, because the store is not updated (uses old nodes store) + const { zoomIn, zoomOut, fitView } = useStore(); + + return { + zoomIn, + zoomOut, + fitView + }; +} diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index 7cbf7b23..6b1dad92 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -3,6 +3,8 @@ import { SvelteFlow } from '$lib/container/SvelteFlow'; export * from '$lib/container/SvelteFlow'; export * from '$lib/container/Panel'; +export * from '$lib/components/SvelteFlowProvider'; + export * from '$lib/plugins/Controls'; export * from '$lib/plugins/Background'; export * from '$lib/plugins/Minimap'; @@ -10,4 +12,6 @@ export * from '$lib/plugins/Minimap'; export * from '$lib/types'; export * from '$lib/utils'; +export * from '$lib/hooks/useSvelteFlow'; + export default SvelteFlow; diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index ee39094c..1c1f1a43 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -2,11 +2,9 @@ import { getContext } from 'svelte'; import { get } from 'svelte/store'; import { zoomIdentity } from 'd3-zoom'; import { - type Transform, type NodeDragItem, type NodeDimensionUpdate, internalsSymbol, - type NodeOrigin, type ViewportHelperFunctionOptions, type Connection, type XYPosition, @@ -30,30 +28,15 @@ import { initialStoreState } from './initial-store'; import type { SvelteFlowStore } from './types'; -import type { SvelteFlowProps } from '$lib/container/SvelteFlow/types'; export const key = Symbol(); -type CreateStoreProps = { - nodes: SvelteFlowProps['nodes']; - edges: SvelteFlowProps['edges']; - fitView?: boolean; - nodeOrigin?: NodeOrigin; - transform?: Transform; - nodeTypes?: NodeTypes; - edgeTypes?: EdgeTypes; - id?: string; -}; +type CreateStoreParams = Pick & { fitView?: boolean }; -export function createStore({ - fitView: fitViewOnInit = false, - nodes, - edges -}: CreateStoreProps): SvelteFlowStore { +export function createStore(params?: CreateStoreParams): SvelteFlowStore { const store = { ...initialStoreState, - nodes, - edges + ...(params !== undefined ? params : {}) }; let fitViewOnInitDone = false; @@ -105,7 +88,6 @@ export function createStore({ const style = window.getComputedStyle(viewportNode); const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform); - const nextNodes = get(store.nodes).map((node) => { const update = updates.find((u) => u.id === node.id); @@ -139,7 +121,7 @@ export function createStore({ const { zoom: d3Zoom, selection: d3Selection } = get(store.d3); fitViewOnInitDone = - fitViewOnInitDone || (fitViewOnInit && !!d3Zoom && !!d3Selection && fitView()); + fitViewOnInitDone || (!!params?.fitView && !!d3Zoom && !!d3Selection && fitView()); store.nodes.set(nextNodes); } @@ -333,7 +315,13 @@ export function createStore({ } export function useStore(): SvelteFlowStore { - const { getStore } = getContext<{ getStore: () => SvelteFlowStore }>(key); + const store = getContext<{ getStore: () => SvelteFlowStore }>(key); - return getStore(); + if (!store) { + throw new Error( + 'In order to use useStore you need to wrap your component in a ' + ); + } + + return store.getStore(); } diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index 13b407db..ee22e0cf 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -16,7 +16,7 @@ import OutputNode from '$lib/components/nodes/OutputNode.svelte'; import BezierEdge from '$lib/components/edges/BezierEdge.svelte'; import StraightEdge from '$lib/components/edges/StraightEdge.svelte'; import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte'; -import type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted } from '$lib/types'; +import type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted, Edge, Node } from '$lib/types'; export const initConnectionData = { nodeId: null, @@ -40,11 +40,14 @@ export const initialEdgeTypes = { export const initialStoreState = { id: writable(null), + nodes: writable([]), + edges: writable([]), edgesLayouted: readable([]), height: writable(500), width: writable(500), minZoom: writable(0.5), maxZoom: writable(2), + fitViewOnInit: false, nodeOrigin: writable([0, 0]), d3: writable<{ zoom: D3ZoomInstance | null; selection: D3SelectionInstance | null }>({ zoom: null, diff --git a/packages/svelte/src/lib/types/general.ts b/packages/svelte/src/lib/types/general.ts index 7dccd4f2..a329c840 100644 --- a/packages/svelte/src/lib/types/general.ts +++ b/packages/svelte/src/lib/types/general.ts @@ -1,5 +1,7 @@ import type { ShortcutModifierDefinition } from '@svelte-put/shortcut'; -import type { HandleProps, HandleType, XYPosition } from '@reactflow/system'; +import type { FitViewOptionsBase, HandleProps, HandleType, XYPosition } from '@reactflow/system'; + +import type { Node } from './nodes'; export type KeyModifier = ShortcutModifierDefinition; export type KeyDefinitionObject = { key: string; modifier?: KeyModifier }; @@ -17,3 +19,5 @@ export type HandleComponentProps = HandleProps & { class?: string; style?: string; }; + +export type FitViewOptions = FitViewOptionsBase; diff --git a/packages/svelte/src/routes/+layout.svelte b/packages/svelte/src/routes/+layout.svelte index 44117aff..bc95f151 100644 --- a/packages/svelte/src/routes/+layout.svelte +++ b/packages/svelte/src/routes/+layout.svelte @@ -2,5 +2,21 @@ import { Header } from '../example-components/Header' -
- \ No newline at end of file +
+
+
+ +
+
+ + \ No newline at end of file diff --git a/packages/svelte/src/routes/usesvelteflow/+page.svelte b/packages/svelte/src/routes/usesvelteflow/+page.svelte new file mode 100644 index 00000000..c80a3eae --- /dev/null +++ b/packages/svelte/src/routes/usesvelteflow/+page.svelte @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/svelte/src/routes/usesvelteflow/Flow.svelte b/packages/svelte/src/routes/usesvelteflow/Flow.svelte new file mode 100644 index 00000000..58bec508 --- /dev/null +++ b/packages/svelte/src/routes/usesvelteflow/Flow.svelte @@ -0,0 +1,65 @@ + + + + + + + + + + + + diff --git a/packages/utils/src/graph.ts b/packages/utils/src/graph.ts index 165bba31..404c3e75 100644 --- a/packages/utils/src/graph.ts +++ b/packages/utils/src/graph.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { Selection as D3Selection } from 'd3'; import { zoomIdentity } from 'd3-zoom'; import { boxToRect, clamp, devWarn, getBoundsOfBoxes, getOverlappingArea, rectToBox } from './utils'; @@ -11,10 +10,11 @@ import { type XYPosition, type Rect, type NodeOrigin, - BaseNode, - BaseEdge, - FitViewParamsBase, - FitViewOptionsBase, + type BaseNode, + type BaseEdge, + type FitViewParamsBase, + type FitViewOptionsBase, + type D3SelectionInstance, } from '@reactflow/system'; export const isEdgeBase = ( @@ -304,7 +304,7 @@ export const getTransformForBounds = ( return [x, y, clampedZoom]; }; -export const getD3Transition = (selection: D3Selection, duration = 0) => { +export const getD3Transition = (selection: D3SelectionInstance, duration = 0) => { return selection.transition().duration(duration); };