change all store states to state.raw to prevent proxying all objects
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
import InitTracker from './InitTracker.svelte';
|
import InitTracker from './InitTracker.svelte';
|
||||||
|
import TriggerConnection from './TriggerConnection.svelte';
|
||||||
|
|
||||||
const nodeTypes: NodeTypes = {
|
const nodeTypes: NodeTypes = {
|
||||||
custom: CustomNode,
|
custom: CustomNode,
|
||||||
@@ -243,6 +244,7 @@
|
|||||||
}));
|
}));
|
||||||
}}>left-right</button
|
}}>left-right</button
|
||||||
>
|
>
|
||||||
|
<TriggerConnection />
|
||||||
</Panel>
|
</Panel>
|
||||||
<InitTracker />
|
<InitTracker />
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { useConnection, useViewport } from '@xyflow/svelte';
|
||||||
|
|
||||||
|
const connection = useConnection();
|
||||||
|
const viewport = useViewport();
|
||||||
|
let blockMouseUp = true;
|
||||||
|
|
||||||
|
// Replace this with the flowId of your flow (default is 1)
|
||||||
|
const flowId = 1;
|
||||||
|
|
||||||
|
/** Replace this selector with the handle of your choice.
|
||||||
|
* Take a look at the DOM structure to see what how the data-*
|
||||||
|
* attributes are structured for handles
|
||||||
|
*/
|
||||||
|
const fromHandleSelector = '[data-nodeid="1"].svelte-flow__handle';
|
||||||
|
|
||||||
|
function createPointerEvent(type: string, element: HTMLElement) {
|
||||||
|
const { left, top } = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
return new PointerEvent(type, {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
pointerId: 1,
|
||||||
|
pointerType: 'mouse',
|
||||||
|
clientX: left + element.offsetWidth / 2,
|
||||||
|
clientY: top + element.offsetHeight / 2,
|
||||||
|
button: 0,
|
||||||
|
buttons: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDownBlocker(event: MouseEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUpBlocker(event: MouseEvent) {
|
||||||
|
// we only want to block the original mouseUpEvent
|
||||||
|
if (!blockMouseUp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
connectionFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEventListeners() {
|
||||||
|
document.addEventListener('mousedown', mouseDownBlocker, true);
|
||||||
|
document.addEventListener('mouseup', mouseUpBlocker, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeEventListeners() {
|
||||||
|
document.removeEventListener('mousedown', mouseDownBlocker, true);
|
||||||
|
document.removeEventListener('mouseup', mouseUpBlocker, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectionFinish() {
|
||||||
|
blockMouseUp = false;
|
||||||
|
const { inProgress, isValid, toHandle } = connection.current;
|
||||||
|
if (inProgress && isValid && toHandle) {
|
||||||
|
const toHandleElement = document.querySelector(
|
||||||
|
`[data-id="${flowId}-${toHandle.nodeId}-${toHandle.id ?? null}-${toHandle.type}"].svelte-flow__handle`
|
||||||
|
) as HTMLElement | null;
|
||||||
|
|
||||||
|
if (toHandleElement) {
|
||||||
|
const mouseupEvent = createPointerEvent('mouseup', toHandleElement);
|
||||||
|
const success = toHandleElement.dispatchEvent(mouseupEvent);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
removeEventListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectionStart() {
|
||||||
|
const fromHandle = document.querySelector(fromHandleSelector) as HTMLElement | null;
|
||||||
|
|
||||||
|
if (fromHandle) {
|
||||||
|
const mousedownEvent = createPointerEvent('mousedown', fromHandle);
|
||||||
|
const success = fromHandle.dispatchEvent(mousedownEvent);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
blockMouseUp = true;
|
||||||
|
addEventListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectionCancel() {
|
||||||
|
const fromHandle = document.querySelector(fromHandleSelector) as HTMLElement | null;
|
||||||
|
|
||||||
|
if (fromHandle) {
|
||||||
|
const mouseUpEvent = createPointerEvent('mouseup', fromHandle);
|
||||||
|
fromHandle.dispatchEvent(mouseUpEvent);
|
||||||
|
}
|
||||||
|
removeEventListeners();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- onclick works as well -->
|
||||||
|
<button onpointerdown={connectionStart}>trigger-connection</button>
|
||||||
@@ -110,10 +110,10 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
// Inline classes have some performance implications but we just call it once (max twice).
|
// Inline classes have some performance implications but we just call it once (max twice).
|
||||||
class SvelteFlowStore {
|
class SvelteFlowStore {
|
||||||
flowId: string = $derived(signals.props.id ?? '1');
|
flowId: string = $derived(signals.props.id ?? '1');
|
||||||
domNode = $state<HTMLDivElement | null>(null);
|
domNode = $state.raw<HTMLDivElement | null>(null);
|
||||||
panZoom: PanZoomInstance | null = $state(null);
|
panZoom: PanZoomInstance | null = $state.raw(null);
|
||||||
width = $state<number>(signals.width ?? 0);
|
width = $state.raw<number>(signals.width ?? 0);
|
||||||
height = $state<number>(signals.height ?? 0);
|
height = $state.raw<number>(signals.height ?? 0);
|
||||||
|
|
||||||
nodesInitialized: boolean = $derived.by(() => {
|
nodesInitialized: boolean = $derived.by(() => {
|
||||||
const nodesInitialized = adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
|
const nodesInitialized = adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
|
||||||
@@ -293,16 +293,16 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
|
|
||||||
snapGrid: SnapGrid | null = $derived(signals.props.snapGrid ?? null);
|
snapGrid: SnapGrid | null = $derived(signals.props.snapGrid ?? null);
|
||||||
|
|
||||||
dragging: boolean = $state(false);
|
dragging: boolean = $state.raw(false);
|
||||||
selectionRect: SelectionRect | null = $state(null);
|
selectionRect: SelectionRect | null = $state.raw(null);
|
||||||
|
|
||||||
selectionKeyPressed: boolean = $state(false);
|
selectionKeyPressed: boolean = $state.raw(false);
|
||||||
multiselectionKeyPressed: boolean = $state(false);
|
multiselectionKeyPressed: boolean = $state.raw(false);
|
||||||
deleteKeyPressed: boolean = $state(false);
|
deleteKeyPressed: boolean = $state.raw(false);
|
||||||
panActivationKeyPressed: boolean = $state(false);
|
panActivationKeyPressed: boolean = $state.raw(false);
|
||||||
zoomActivationKeyPressed: boolean = $state(false);
|
zoomActivationKeyPressed: boolean = $state.raw(false);
|
||||||
selectionRectMode: string | null = $state(null);
|
selectionRectMode: string | null = $state.raw(null);
|
||||||
ariaLiveMessage = $state<string>('');
|
ariaLiveMessage = $state.raw<string>('');
|
||||||
selectionMode: SelectionMode = $derived(signals.props.selectionMode ?? SelectionMode.Partial);
|
selectionMode: SelectionMode = $derived(signals.props.selectionMode ?? SelectionMode.Partial);
|
||||||
|
|
||||||
nodeTypes: NodeTypes = $derived({ ...initialNodeTypes, ...signals.props.nodeTypes });
|
nodeTypes: NodeTypes = $derived({ ...initialNodeTypes, ...signals.props.nodeTypes });
|
||||||
@@ -317,7 +317,7 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
|
|
||||||
// _viewport is the internal viewport.
|
// _viewport is the internal viewport.
|
||||||
// when binding to viewport, we operate on signals.viewport instead
|
// when binding to viewport, we operate on signals.viewport instead
|
||||||
_viewport: Viewport = $state(
|
_viewport: Viewport = $state.raw(
|
||||||
getInitialViewport(
|
getInitialViewport(
|
||||||
this.nodesInitialized,
|
this.nodesInitialized,
|
||||||
signals.props.fitView,
|
signals.props.fitView,
|
||||||
@@ -338,7 +338,7 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
}
|
}
|
||||||
|
|
||||||
// _connection is viewport independent and originating from XYHandle
|
// _connection is viewport independent and originating from XYHandle
|
||||||
_connection: ConnectionState = $state(initialConnection);
|
_connection: ConnectionState = $state.raw(initialConnection);
|
||||||
// We derive a viewport dependent connection here
|
// We derive a viewport dependent connection here
|
||||||
connection: ConnectionState = $derived.by(() => {
|
connection: ConnectionState = $derived.by(() => {
|
||||||
if (this._connection.inProgress) {
|
if (this._connection.inProgress) {
|
||||||
@@ -392,7 +392,7 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
clickConnect?: boolean = $derived(signals.props.clickConnect ?? true);
|
clickConnect?: boolean = $derived(signals.props.clickConnect ?? true);
|
||||||
onclickconnectstart?: OnConnectStart = $derived(signals.props.onclickconnectstart);
|
onclickconnectstart?: OnConnectStart = $derived(signals.props.onclickconnectstart);
|
||||||
onclickconnectend?: OnConnectEnd = $derived(signals.props.onclickconnectend);
|
onclickconnectend?: OnConnectEnd = $derived(signals.props.onclickconnectend);
|
||||||
clickConnectStartHandle: Pick<Handle, 'id' | 'nodeId' | 'type'> | null = $state(null);
|
clickConnectStartHandle: Pick<Handle, 'id' | 'nodeId' | 'type'> | null = $state.raw(null);
|
||||||
|
|
||||||
onselectiondrag?: OnSelectionDrag<NodeType> = $derived(signals.props.onselectiondrag);
|
onselectiondrag?: OnSelectionDrag<NodeType> = $derived(signals.props.onselectiondrag);
|
||||||
onselectiondragstart?: OnSelectionDrag<NodeType> = $derived(signals.props.onselectiondragstart);
|
onselectiondragstart?: OnSelectionDrag<NodeType> = $derived(signals.props.onselectiondragstart);
|
||||||
|
|||||||
Reference in New Issue
Block a user