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 InitTracker from './InitTracker.svelte';
|
||||
import TriggerConnection from './TriggerConnection.svelte';
|
||||
|
||||
const nodeTypes: NodeTypes = {
|
||||
custom: CustomNode,
|
||||
@@ -243,6 +244,7 @@
|
||||
}));
|
||||
}}>left-right</button
|
||||
>
|
||||
<TriggerConnection />
|
||||
</Panel>
|
||||
<InitTracker />
|
||||
</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).
|
||||
class SvelteFlowStore {
|
||||
flowId: string = $derived(signals.props.id ?? '1');
|
||||
domNode = $state<HTMLDivElement | null>(null);
|
||||
panZoom: PanZoomInstance | null = $state(null);
|
||||
width = $state<number>(signals.width ?? 0);
|
||||
height = $state<number>(signals.height ?? 0);
|
||||
domNode = $state.raw<HTMLDivElement | null>(null);
|
||||
panZoom: PanZoomInstance | null = $state.raw(null);
|
||||
width = $state.raw<number>(signals.width ?? 0);
|
||||
height = $state.raw<number>(signals.height ?? 0);
|
||||
|
||||
nodesInitialized: boolean = $derived.by(() => {
|
||||
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);
|
||||
|
||||
dragging: boolean = $state(false);
|
||||
selectionRect: SelectionRect | null = $state(null);
|
||||
dragging: boolean = $state.raw(false);
|
||||
selectionRect: SelectionRect | null = $state.raw(null);
|
||||
|
||||
selectionKeyPressed: boolean = $state(false);
|
||||
multiselectionKeyPressed: boolean = $state(false);
|
||||
deleteKeyPressed: boolean = $state(false);
|
||||
panActivationKeyPressed: boolean = $state(false);
|
||||
zoomActivationKeyPressed: boolean = $state(false);
|
||||
selectionRectMode: string | null = $state(null);
|
||||
ariaLiveMessage = $state<string>('');
|
||||
selectionKeyPressed: boolean = $state.raw(false);
|
||||
multiselectionKeyPressed: boolean = $state.raw(false);
|
||||
deleteKeyPressed: boolean = $state.raw(false);
|
||||
panActivationKeyPressed: boolean = $state.raw(false);
|
||||
zoomActivationKeyPressed: boolean = $state.raw(false);
|
||||
selectionRectMode: string | null = $state.raw(null);
|
||||
ariaLiveMessage = $state.raw<string>('');
|
||||
selectionMode: SelectionMode = $derived(signals.props.selectionMode ?? SelectionMode.Partial);
|
||||
|
||||
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.
|
||||
// when binding to viewport, we operate on signals.viewport instead
|
||||
_viewport: Viewport = $state(
|
||||
_viewport: Viewport = $state.raw(
|
||||
getInitialViewport(
|
||||
this.nodesInitialized,
|
||||
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: ConnectionState = $state(initialConnection);
|
||||
_connection: ConnectionState = $state.raw(initialConnection);
|
||||
// We derive a viewport dependent connection here
|
||||
connection: ConnectionState = $derived.by(() => {
|
||||
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);
|
||||
onclickconnectstart?: OnConnectStart = $derived(signals.props.onclickconnectstart);
|
||||
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);
|
||||
onselectiondragstart?: OnSelectionDrag<NodeType> = $derived(signals.props.onselectiondragstart);
|
||||
|
||||
Reference in New Issue
Block a user