Merge branch 'next' into svelte-edge-type-change

This commit is contained in:
Moritz Klack
2024-04-03 16:57:47 +02:00
committed by GitHub
21 changed files with 136 additions and 198 deletions
@@ -189,6 +189,7 @@
autoPanOnNodeDrag autoPanOnNodeDrag
connectionMode={ConnectionMode.Strict} connectionMode={ConnectionMode.Strict}
attributionPosition={'top-center'} attributionPosition={'top-center'}
deleteKey={['Backspace', 'd']}
> >
<Controls> <Controls>
<ControlButton slot="before">xy</ControlButton> <ControlButton slot="before">xy</ControlButton>
+2
View File
@@ -109,11 +109,13 @@ export function useKeyPress(
target?.addEventListener('keydown', downHandler as EventListenerOrEventListenerObject); target?.addEventListener('keydown', downHandler as EventListenerOrEventListenerObject);
target?.addEventListener('keyup', upHandler as EventListenerOrEventListenerObject); target?.addEventListener('keyup', upHandler as EventListenerOrEventListenerObject);
window.addEventListener('blur', resetHandler); window.addEventListener('blur', resetHandler);
window.addEventListener('contextmenu', resetHandler);
return () => { return () => {
target?.removeEventListener('keydown', downHandler as EventListenerOrEventListenerObject); target?.removeEventListener('keydown', downHandler as EventListenerOrEventListenerObject);
target?.removeEventListener('keyup', upHandler as EventListenerOrEventListenerObject); target?.removeEventListener('keyup', upHandler as EventListenerOrEventListenerObject);
window.removeEventListener('blur', resetHandler); window.removeEventListener('blur', resetHandler);
window.removeEventListener('contextmenu', resetHandler);
}; };
} }
}, [keyCode, setKeyPressed]); }, [keyCode, setKeyPressed]);
+1
View File
@@ -2,6 +2,7 @@
node_modules node_modules
/build /build
/.svelte-kit /.svelte-kit
dist
/package /package
.env .env
.env.* .env.*
-1
View File
@@ -3,6 +3,5 @@
"trailingComma": "none", "trailingComma": "none",
"printWidth": 100, "printWidth": 100,
"plugins": ["prettier-plugin-svelte"], "plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
} }
+3 -16
View File
@@ -38,17 +38,11 @@ You only need a few lines to get a fully interactive (e.g. select and drag nodes
```svelte ```svelte
<script lang="ts"> <script lang="ts">
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import { import { SvelteFlow, Controls, Background, BackgroundVariant, MiniMap } from '@xyflow/svelte';
SvelteFlow,
Controls,
Background,
BackgroundVariant,
MiniMap,
} from '@xyflow/svelte';
// you need to import the styles for Svelte Flow to work // you need to import the styles for Svelte Flow to work
// if you just want to load the basic styleds, you can import '@xyflow/svelte/dist/base.css' // if you just want to load the basic styleds, you can import '@xyflow/svelte/dist/base.css'
import '@xyflow/svelte/dist/style.css' import '@xyflow/svelte/dist/style.css';
// We are using writables for the nodes and edges to sync them easily. When a user drags a node for example, Svelte Flow updates its position. This also makes it easier to update nodes in user land. // We are using writables for the nodes and edges to sync them easily. When a user drags a node for example, Svelte Flow updates its position. This also makes it easier to update nodes in user land.
const nodes = writable([ const nodes = writable([
@@ -78,12 +72,7 @@ You only need a few lines to get a fully interactive (e.g. select and drag nodes
]); ]);
</script> </script>
<SvelteFlow <SvelteFlow {nodes} {edges} fitView on:nodeclick={(event) => console.log('on node click', event)}>
{nodes}
{edges}
fitView
on:nodeclick={(event) => console.log('on node click', event)}
>
<Controls /> <Controls />
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
<MiniMap /> <MiniMap />
@@ -102,7 +91,6 @@ You only need a few lines to get a fully interactive (e.g. select and drag nodes
And of course, we love Github stars ⭐ And of course, we love Github stars ⭐
## Development ## Development
If you want to check out the current version you need to run the following command from the root directory: If you want to check out the current version you need to run the following command from the root directory:
@@ -113,7 +101,6 @@ If you want to check out the current version you need to run the following comma
You can now access the examples under http://127.0.0.1:5173 You can now access the examples under http://127.0.0.1:5173
## Maintainers ## Maintainers
Svelte Flow is maintained by the team behind [xyflow](https://xyflow.com). If you need help or want to talk to us about a collaboration, reach out through our [contact form](https://xyflow.com/contact) or by joining our [Discord Server](https://discord.gg/Bqt6xrs). Svelte Flow is maintained by the team behind [xyflow](https://xyflow.com). If you need help or want to talk to us about a collaboration, reach out through our [contact form](https://xyflow.com/contact) or by joining our [Discord Server](https://discord.gg/Bqt6xrs).
@@ -4,8 +4,8 @@
type $$Props = AttributionProps; type $$Props = AttributionProps;
export let proOptions: AttributionProps['proOptions'] = undefined; export let proOptions: $$Props['proOptions'] = undefined;
export let position: AttributionProps['position'] = 'bottom-right'; export let position: $$Props['position'] = 'bottom-right';
</script> </script>
{#if !proOptions?.hideAttribution} {#if !proOptions?.hideAttribution}
@@ -2,8 +2,6 @@
import portal from '$lib/actions/portal'; import portal from '$lib/actions/portal';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
type $$Props = {};
const { domNode } = useStore(); const { domNode } = useStore();
</script> </script>
@@ -80,7 +80,7 @@
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
{#if !hidden} {#if !hidden}
<svg style:zIndex> <svg style:z-index={zIndex}>
<g <g
class={cc(['svelte-flow__edge', className])} class={cc(['svelte-flow__edge', className])}
class:animated class:animated
@@ -1,5 +1,9 @@
<script lang="ts"> <script lang="ts">
import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut'; import {
shortcut,
type ShortcutEventDetail,
type ShortcutModifierDefinition
} from '@svelte-put/shortcut';
import { isInputDOMNode, isMacOs } from '@xyflow/system'; import { isInputDOMNode, isMacOs } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
@@ -19,7 +23,8 @@
multiselectionKeyPressed, multiselectionKeyPressed,
deleteKeyPressed, deleteKeyPressed,
panActivationKeyPressed, panActivationKeyPressed,
zoomActivationKeyPressed zoomActivationKeyPressed,
selectionRect
} = useStore(); } = useStore();
function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject { function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject {
@@ -40,140 +45,81 @@
return isKeyObject(key) ? key.key : key; return isKeyObject(key) ? key.key : key;
} }
$: selectionKeyDefinition = { function getShortcutTrigger(
key: getKeyString(selectionKey), key: KeyDefinition | KeyDefinition[] | null | undefined,
modifier: getModifier(selectionKey) callback: (detail: ShortcutEventDetail) => void
}; ) {
const keys = Array.isArray(key) ? key : [key];
return keys.map((_key) => {
const keyString = getKeyString(_key);
return {
key: keyString,
modifier: getModifier(_key),
enabled: keyString !== null,
callback
};
});
}
$: multiSelectionKeyDefinition = { function resetKeysAndSelection() {
key: getKeyString(multiSelectionKey), selectionRect.set(null);
modifier: getModifier(multiSelectionKey) selectionKeyPressed.set(false);
}; multiselectionKeyPressed.set(false);
deleteKeyPressed.set(false);
$: deleteKeyDefinition = { panActivationKeyPressed.set(false);
key: getKeyString(deleteKey), zoomActivationKeyPressed.set(false);
modifier: getModifier(deleteKey) }
};
$: panActivationKeyDefinition = {
key: getKeyString(panActivationKey),
modifier: getModifier(panActivationKey)
};
$: zoomActivationKeyDefinition = {
key: getKeyString(zoomActivationKey),
modifier: getModifier(zoomActivationKey)
};
</script> </script>
<svelte:window <svelte:window
on:blur={resetKeysAndSelection}
on:contextmenu={resetKeysAndSelection}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(selectionKey, () => selectionKeyPressed.set(true)),
{
...selectionKeyDefinition,
enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(true)
}
],
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(selectionKey, () => selectionKeyPressed.set(false)),
{
...selectionKeyDefinition,
enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(false)
}
],
type: 'keyup' type: 'keyup'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(multiSelectionKey, () => multiselectionKeyPressed.set(true)),
{
...multiSelectionKeyDefinition,
enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(true)
}
],
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(multiSelectionKey, () => multiselectionKeyPressed.set(false)),
{
...multiSelectionKeyDefinition,
enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(false)
}
],
type: 'keyup' type: 'keyup'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(deleteKey, (detail) => {
{ const isModifierKey =
...deleteKeyDefinition, detail.originalEvent.ctrlKey ||
enabled: deleteKeyDefinition.key !== null, detail.originalEvent.metaKey ||
callback: (detail) => { detail.originalEvent.shiftKey;
const isModifierKey = if (!isModifierKey && !isInputDOMNode(detail.originalEvent)) {
detail.originalEvent.ctrlKey || deleteKeyPressed.set(true);
detail.originalEvent.metaKey ||
detail.originalEvent.shiftKey;
if (!isModifierKey && !isInputDOMNode(detail.originalEvent)) {
deleteKeyPressed.set(true);
}
}
} }
], }),
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(deleteKey, () => deleteKeyPressed.set(false)),
{
...deleteKeyDefinition,
enabled: deleteKeyDefinition.key !== null,
callback: () => deleteKeyPressed.set(false)
}
],
type: 'keyup' type: 'keyup'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(panActivationKey, () => panActivationKeyPressed.set(true)),
{
...panActivationKeyDefinition,
enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(true)
}
],
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(panActivationKey, () => panActivationKeyPressed.set(false)),
{
...panActivationKeyDefinition,
enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(false)
}
],
type: 'keyup' type: 'keyup'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(zoomActivationKey, () => zoomActivationKeyPressed.set(true)),
{
...zoomActivationKeyDefinition,
enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(true)
}
],
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: getShortcutTrigger(zoomActivationKey, () => zoomActivationKeyPressed.set(false)),
{
...zoomActivationKeyDefinition,
enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(false)
}
],
type: 'keyup' type: 'keyup'
}} }}
/> />
@@ -1,9 +1,9 @@
import type { KeyDefinition } from '$lib/types'; import type { KeyDefinition } from '$lib/types';
export type KeyHandlerProps = { export type KeyHandlerProps = {
selectionKey?: KeyDefinition | null; selectionKey?: KeyDefinition | KeyDefinition[] | null;
multiSelectionKey?: KeyDefinition | null; multiSelectionKey?: KeyDefinition | KeyDefinition[] | null;
deleteKey?: KeyDefinition | null; deleteKey?: KeyDefinition | KeyDefinition[] | null;
panActivationKey?: KeyDefinition | null; panActivationKey?: KeyDefinition | KeyDefinition[] | null;
zoomActivationKey?: KeyDefinition | null; zoomActivationKey?: KeyDefinition | KeyDefinition[] | null;
}; };
@@ -1,7 +1,7 @@
<svelte:options immutable /> <svelte:options immutable />
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, setContext, onDestroy } from 'svelte'; import { setContext, onDestroy } from 'svelte';
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import cc from 'classcat'; import cc from 'classcat';
import { errorMessages, Position } from '@xyflow/system'; import { errorMessages, Position } from '@xyflow/system';
@@ -10,40 +10,39 @@
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte'; import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import type { NodeWrapperProps } from './types'; import type { NodeWrapperProps } from './types';
import type { Node } from '$lib/types';
import { getNodeInlineStyleDimensions } from './utils'; import { getNodeInlineStyleDimensions } from './utils';
import { createNodeEventDispatcher } from '$lib'; import { createNodeEventDispatcher } from '$lib';
interface $$Props extends NodeWrapperProps {} interface $$Props extends NodeWrapperProps {}
export let node: NodeWrapperProps['node']; export let node: $$Props['node'];
export let id: NodeWrapperProps['id']; export let id: $$Props['id'];
export let data: NodeWrapperProps['data'] = {}; export let data: $$Props['data'] = {};
export let selected: NodeWrapperProps['selected'] = false; export let selected: $$Props['selected'] = false;
export let draggable: NodeWrapperProps['draggable'] = undefined; export let draggable: $$Props['draggable'] = undefined;
export let selectable: NodeWrapperProps['selectable'] = undefined; export let selectable: $$Props['selectable'] = undefined;
export let connectable: NodeWrapperProps['connectable'] = true; export let connectable: $$Props['connectable'] = true;
export let hidden: NodeWrapperProps['hidden'] = false; export let hidden: $$Props['hidden'] = false;
export let dragging: boolean = false; export let dragging: boolean = false;
export let resizeObserver: NodeWrapperProps['resizeObserver'] = null; export let resizeObserver: $$Props['resizeObserver'] = null;
export let style: NodeWrapperProps['style'] = undefined; export let style: $$Props['style'] = undefined;
export let type: NodeWrapperProps['type'] = 'default'; export let type: $$Props['type'] = 'default';
export let isParent: NodeWrapperProps['isParent'] = false; export let isParent: $$Props['isParent'] = false;
export let positionX: NodeWrapperProps['positionX']; export let positionX: $$Props['positionX'];
export let positionY: NodeWrapperProps['positionY']; export let positionY: $$Props['positionY'];
export let positionOriginX: NodeWrapperProps['positionOriginX']; export let positionOriginX: $$Props['positionOriginX'];
export let positionOriginY: NodeWrapperProps['positionOriginY']; export let positionOriginY: $$Props['positionOriginY'];
export let sourcePosition: NodeWrapperProps['sourcePosition'] = undefined; export let sourcePosition: $$Props['sourcePosition'] = undefined;
export let targetPosition: NodeWrapperProps['targetPosition'] = undefined; export let targetPosition: $$Props['targetPosition'] = undefined;
export let zIndex: NodeWrapperProps['zIndex']; export let zIndex: $$Props['zIndex'];
export let computedWidth: NodeWrapperProps['computedWidth'] = undefined; export let computedWidth: $$Props['computedWidth'] = undefined;
export let computedHeight: NodeWrapperProps['computedHeight'] = undefined; export let computedHeight: $$Props['computedHeight'] = undefined;
export let initialWidth: NodeWrapperProps['initialWidth'] = undefined; export let initialWidth: $$Props['initialWidth'] = undefined;
export let initialHeight: NodeWrapperProps['initialHeight'] = undefined; export let initialHeight: $$Props['initialHeight'] = undefined;
export let width: NodeWrapperProps['width'] = undefined; export let width: $$Props['width'] = undefined;
export let height: NodeWrapperProps['height'] = undefined; export let height: $$Props['height'] = undefined;
export let dragHandle: NodeWrapperProps['dragHandle'] = undefined; export let dragHandle: $$Props['dragHandle'] = undefined;
export let initialized: NodeWrapperProps['initialized'] = false; export let initialized: $$Props['initialized'] = false;
let className: string = ''; let className: string = '';
export { className as class }; export { className as class };
@@ -57,7 +56,15 @@
} = store; } = store;
let nodeRef: HTMLDivElement; let nodeRef: HTMLDivElement;
let prevNodeRef: HTMLDivElement; let prevNodeRef: HTMLDivElement | null = null;
const nodeTypeValid = !!$nodeTypes[nodeType];
if (!nodeTypeValid) {
console.warn('003', errorMessages['error003'](type!));
}
const nodeComponent = $nodeTypes[nodeType] || DefaultNode;
const dispatchNodeEvent = createNodeEventDispatcher(); const dispatchNodeEvent = createNodeEventDispatcher();
const connectableStore = writable(connectable); const connectableStore = writable(connectable);
let prevType: string | undefined = undefined; let prevType: string | undefined = undefined;
@@ -121,20 +128,17 @@
setContext('svelteflow__node_connectable', connectableStore); setContext('svelteflow__node_connectable', connectableStore);
$: { $: {
if (nodeRef) { if (resizeObserver && nodeRef !== prevNodeRef) {
if (!prevNodeRef) { prevNodeRef && resizeObserver.unobserve(prevNodeRef);
resizeObserver?.observe(nodeRef); nodeRef && resizeObserver.observe(nodeRef);
prevNodeRef = nodeRef; prevNodeRef = nodeRef;
} else if (prevNodeRef !== nodeRef || (!computedWidth && !computedHeight)) {
resizeObserver?.unobserve(prevNodeRef);
resizeObserver?.observe(nodeRef);
prevNodeRef = nodeRef;
}
} }
} }
onDestroy(() => { onDestroy(() => {
resizeObserver?.unobserve(nodeRef); if (prevNodeRef) {
resizeObserver?.unobserve(prevNodeRef);
}
}); });
function onSelectNodeHandler(event: MouseEvent | TouchEvent) { function onSelectNodeHandler(event: MouseEvent | TouchEvent) {
@@ -2,8 +2,6 @@
import portal from '$lib/actions/portal'; import portal from '$lib/actions/portal';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
type $$Props = {};
const { domNode } = useStore(); const { domNode } = useStore();
</script> </script>
@@ -178,7 +178,7 @@
// onSelectionEnd?.(event); // onSelectionEnd?.(event);
} }
const onMouseLeave = (event: MouseEvent) => { const onMouseLeave = () => {
if ($selectionRectMode === 'user') { if ($selectionRectMode === 'user') {
selectionRectMode.set(selectedNodes.length > 0 ? 'nodes' : null); selectionRectMode.set(selectedNodes.length > 0 ? 'nodes' : null);
// onSelectionEnd?.(event); // onSelectionEnd?.(event);
@@ -86,27 +86,27 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
/** Pressing down this key you can select multiple elements with a selection box. /** Pressing down this key you can select multiple elements with a selection box.
* @default 'Shift' * @default 'Shift'
*/ */
selectionKey?: KeyDefinition | null; selectionKey?: KeyDefinition | KeyDefinition[] | null;
/** If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false. /** If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false.
* *
* By setting this prop to null you can disable this functionality. * By setting this prop to null you can disable this functionality.
* @default 'Space' * @default 'Space'
*/ */
panActivationKey?: KeyDefinition | null; panActivationKey?: KeyDefinition | KeyDefinition[] | null;
/** Pressing down this key deletes all selected nodes & edges. /** Pressing down this key deletes all selected nodes & edges.
* @default 'Backspace' * @default 'Backspace'
*/ */
deleteKey?: KeyDefinition | null; deleteKey?: KeyDefinition | KeyDefinition[] | null;
/** Pressing down this key you can select multiple elements by clicking. /** Pressing down this key you can select multiple elements by clicking.
* @default 'Meta' for macOS, "Ctrl" for other systems * @default 'Meta' for macOS, "Ctrl" for other systems
*/ */
multiSelectionKey?: KeyDefinition | null; multiSelectionKey?: KeyDefinition | KeyDefinition[] | null;
/** If a key is set, you can zoom the viewport while that key is held down even if panOnScroll is set to false. /** If a key is set, you can zoom the viewport while that key is held down even if panOnScroll is set to false.
* *
* By setting this prop to null you can disable this functionality. * By setting this prop to null you can disable this functionality.
* @default 'Meta' for macOS, "Ctrl" for other systems * @default 'Meta' for macOS, "Ctrl" for other systems
* */ * */
zoomActivationKey?: KeyDefinition | null; zoomActivationKey?: KeyDefinition | KeyDefinition[] | null;
/** If set, initial viewport will show all nodes & edges */ /** If set, initial viewport will show all nodes & edges */
fitView?: boolean; fitView?: boolean;
/** Options to be used in combination with fitView /** Options to be used in combination with fitView
@@ -76,8 +76,7 @@ export function updateStoreByKeys(store: SvelteFlowStore, keys: UpdatableStorePr
getKeys(keys).forEach((prop) => { getKeys(keys).forEach((prop) => {
const update = keys[prop]; const update = keys[prop];
if (update !== undefined) { if (update !== undefined) {
// @todo: how to fix this TS error? // @ts-expect-error @todo: how to fix this TS error?
// @ts-ignore
store[prop].set(update); store[prop].set(update);
} }
}); });
@@ -20,7 +20,8 @@ export function useNodesData<NodeType extends Node = Node>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any { export function useNodesData(nodeIds: any): any {
const { nodes, nodeLookup } = useStore(); const { nodes, nodeLookup } = useStore();
let prevNodesData: any = []; // eslint-disable-next-line @typescript-eslint/no-explicit-any
let prevNodesData: any[] = [];
return derived([nodes, nodeLookup], ([, nodeLookup], set) => { return derived([nodes, nodeLookup], ([, nodeLookup], set) => {
const nextNodesData = []; const nextNodesData = [];
@@ -1,6 +1,6 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
declare const window: any; declare const window: Window | undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getAttrFunction = (func: any): GetMiniMapNodeAttribute => const getAttrFunction = (func: any): GetMiniMapNodeAttribute =>
func instanceof Function ? func : () => func; func instanceof Function ? func : () => func;
</script> </script>
@@ -61,6 +61,7 @@
const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor); const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
const nodeClassFunc = getAttrFunction(nodeClass); const nodeClassFunc = getAttrFunction(nodeClass);
const shapeRendering = const shapeRendering =
// @ts-expect-error - TS doesn't know about chrome
typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'; typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision';
const labelledBy = `svelte-flow__minimap-desc-${$flowId}`; const labelledBy = `svelte-flow__minimap-desc-${$flowId}`;
@@ -52,7 +52,7 @@
$: colorStyleProp = variant === ResizeControlVariant.Line ? 'border-color' : 'background-color'; $: colorStyleProp = variant === ResizeControlVariant.Line ? 'border-color' : 'background-color';
$: _style = style ?? ''; $: _style = style ?? '';
$: controlStyle = !!color ? `${_style} ${colorStyleProp}: ${color};` : _style; $: controlStyle = color ? `${_style} ${colorStyleProp}: ${color};` : _style;
onMount(() => { onMount(() => {
if (resizeControlRef) { if (resizeControlRef) {
@@ -6,7 +6,8 @@ import {
ConnectionLineType, ConnectionLineType,
ConnectionMode, ConnectionMode,
Position, Position,
internalsSymbol internalsSymbol,
type HandleElement
} from '@xyflow/system'; } from '@xyflow/system';
import type { SvelteFlowStoreState } from './types'; import type { SvelteFlowStoreState } from './types';
@@ -68,16 +69,16 @@ export function getDerivedConnectionProps(
const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds; const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds;
const handleBoundsStrict = const handleBoundsStrict =
fromHandleBounds?.[connection.connectionStartHandle.type || 'source'] || []; fromHandleBounds?.[connection.connectionStartHandle.type || 'source'] || [];
const handleBoundsLoose = handleBoundsStrict const handleBoundsLoose: HandleElement[] | undefined | null = handleBoundsStrict
? handleBoundsStrict ? handleBoundsStrict
: fromHandleBounds?.[ : fromHandleBounds?.[
connection?.connectionStartHandle?.type === 'source' ? 'target' : 'source' connection?.connectionStartHandle?.type === 'source' ? 'target' : 'source'
]!; ];
const handleBounds = const handleBounds =
connectionMode === ConnectionMode.Strict ? handleBoundsStrict : handleBoundsLoose; connectionMode === ConnectionMode.Strict ? handleBoundsStrict : handleBoundsLoose;
const fromHandle = connection.connectionStartHandle?.handleId const fromHandle = connection.connectionStartHandle?.handleId
? handleBounds.find((d) => d.id === connection.connectionStartHandle?.handleId) ? handleBounds?.find((d) => d.id === connection.connectionStartHandle?.handleId)
: handleBounds[0]; : handleBounds?.[0];
const fromHandleX = fromHandle const fromHandleX = fromHandle
? fromHandle.x + fromHandle.width / 2 ? fromHandle.x + fromHandle.width / 2
: (fromNode?.computed?.width ?? 0) / 2; : (fromNode?.computed?.width ?? 0) / 2;