feat(svelte): add panActivationKey

This commit is contained in:
moklick
2023-08-16 13:56:52 +02:00
parent ab30b1c958
commit a096efbcfe
19 changed files with 128 additions and 25 deletions

View File

@@ -8,6 +8,8 @@
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "turbo run dev --parallel",
"dev:svelte": "turbo run dev --filter=svelte --filter=system",
"dev:react": "turbo run dev --filter=react",
"build": "turbo run build",
"test": "turbo run test",
"lint": "turbo run lint",

View File

@@ -33,7 +33,7 @@
"access": "public"
},
"dependencies": {
"@svelte-put/shortcut": "^2.0.0",
"@svelte-put/shortcut": "^3.0.0",
"@xyflow/system": "workspace:*",
"classcat": "^5.0.4"
},

View File

@@ -6,6 +6,7 @@
'customnode',
'drag-n-drop',
'edges',
'figma',
'interaction',
'overview',
'stress',

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { createEventDispatcher, type SvelteComponentTyped } from 'svelte';
import { createEventDispatcher, SvelteComponent, type ComponentType } from 'svelte';
import { getMarkerId } from '@xyflow/system';
import { useStore } from '$lib/store';
@@ -36,7 +36,7 @@
const { edges, edgeTypes, flowId, addSelectedEdges } = useStore();
const dispatch = createEventDispatcher();
const edgeComponent: typeof SvelteComponentTyped<EdgeProps> = $edgeTypes[type!] || BezierEdge;
const edgeComponent: ComponentType<SvelteComponent<EdgeProps>> = $edgeTypes[type!] || BezierEdge;
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
@@ -52,6 +52,7 @@
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<g
class="svelte-flow__edge"
class:animated

View File

@@ -96,6 +96,8 @@
on:mousedown={onPointerDown}
on:touchstart={onPointerDown}
{style}
role="button"
tabindex="-1"
>
<slot />
</div>

View File

@@ -9,8 +9,9 @@
export let selectionKey: $$Props['selectionKey'] = 'Shift';
export let deleteKey: $$Props['deleteKey'] = 'Backspace';
export let panActivationKey: $$Props['panActivationKey'] = ' ';
const { selectionKeyPressed, deleteKeyPressed } = useStore();
const { selectionKeyPressed, deleteKeyPressed, panActivationKeyPressed } = useStore();
function isKeyObject(key?: KeyDefinition): key is KeyDefinitionObject {
return typeof key === 'object';
@@ -21,6 +22,10 @@
$: deleteKeyString = typeof deleteKey === 'string' ? deleteKey : deleteKey!.key;
$: deleteKeyModifier = isKeyObject(deleteKey) ? deleteKey?.modifier : [];
$: panActivationKeyString =
typeof panActivationKey === 'string' ? panActivationKey : panActivationKey!.key;
$: panActivationKeyModifier = isKeyObject(panActivationKey) ? panActivationKey?.modifier : [];
</script>
<svelte:window
@@ -49,7 +54,10 @@
{
key: deleteKeyString,
modifier: deleteKeyModifier,
callback: () => deleteKeyPressed.set(true)
callback: () => {
console.log('delete');
deleteKeyPressed.set(true);
}
}
],
type: 'keydown'
@@ -64,4 +72,24 @@
],
type: 'keyup'
}}
use:shortcut={{
trigger: [
{
key: panActivationKeyString,
modifier: panActivationKeyModifier,
callback: () => panActivationKeyPressed.set(true)
}
],
type: 'keydown'
}}
use:shortcut={{
trigger: [
{
key: panActivationKeyString,
modifier: panActivationKeyModifier,
callback: () => panActivationKeyPressed.set(false)
}
],
type: 'keyup'
}}
/>

View File

@@ -3,4 +3,5 @@ import type { KeyDefinition } from '$lib/types';
export type KeyHandlerProps = {
selectionKey?: KeyDefinition;
deleteKey?: KeyDefinition;
panActivationKey?: KeyDefinition;
};

View File

@@ -1,5 +1,11 @@
<script lang="ts">
import { createEventDispatcher, onMount, setContext, SvelteComponentTyped } from 'svelte';
import {
createEventDispatcher,
onMount,
setContext,
SvelteComponent,
type ComponentType
} from 'svelte';
import cc from 'classcat';
import { errorMessages, type NodeProps } from '@xyflow/system';
@@ -19,8 +25,6 @@
export let dragging: boolean = false;
export let resizeObserver: NodeWrapperProps['resizeObserver'] = null;
export let style: NodeWrapperProps['style'] = undefined;
export let width: NodeWrapperProps['width'] = undefined;
export let height: NodeWrapperProps['height'] = undefined;
export let type: NodeWrapperProps['type'] = 'default';
export let isParent: NodeWrapperProps['isParent'] = false;
export let positionAbsolute: NodeWrapperProps['positionAbsolute'] = undefined;
@@ -43,7 +47,7 @@
type = 'default';
}
const nodeComponent: typeof SvelteComponentTyped<NodeProps> = $nodeTypes[type!] || DefaultNode;
const nodeComponent: ComponentType<SvelteComponent<NodeProps>> = $nodeTypes[type!] || DefaultNode;
const selectNodesOnDrag = false;
const dispatch = createEventDispatcher();
@@ -74,6 +78,7 @@
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
use:drag={{
nodeId: id,

View File

@@ -55,8 +55,6 @@
positionAbsolute={node.positionAbsolute}
positionOrigin={posOrigin}
isParent={!!node[internalsSymbol]?.isParent}
width={node.width}
height={node.height}
style={node.style}
class={node.class}
type={node.type}

View File

@@ -52,6 +52,7 @@
selectionRectMode,
selectionKeyPressed,
selectionMode,
panActivationKeyPressed,
unselectNodesAndEdges
} = useStore();
@@ -61,6 +62,7 @@
$: isSelecting = $selectionKeyPressed;
$: hasActiveSelection = $elementsSelectable && (isSelecting || $selectionRectMode === 'user');
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
function onClick(event: MouseEvent) {
dispatch('paneclick', event);
@@ -159,7 +161,7 @@
};
const onContextMenu = (event: MouseEvent) => {
if (Array.isArray(panOnDrag) && panOnDrag?.includes(2)) {
if (Array.isArray(_panOnDrag) && _panOnDrag?.includes(2)) {
event.preventDefault();
return;
}
@@ -168,6 +170,8 @@
};
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
bind:this={container}
class="svelte-flow__pane"

View File

@@ -30,6 +30,7 @@
export let edgeTypes: $$Props['edgeTypes'] = undefined;
export let selectionKey: $$Props['selectionKey'] = undefined;
export let selectionMode: $$Props['selectionMode'] = undefined;
export let panActivationKey: $$Props['panActivationKey'] = undefined;
export let nodesDraggable: $$Props['nodesDraggable'] = undefined;
export let nodesConnectable: $$Props['nodesConnectable'] = undefined;
export let elementsSelectable: $$Props['elementsSelectable'] = undefined;
@@ -124,8 +125,9 @@
on:dragover
on:drop
{...$$restProps}
role="application"
>
<KeyHandler {selectionKey} {deleteKey} />
<KeyHandler {selectionKey} {deleteKey} {panActivationKey} />
<Zoom
{initialViewport}
{onMoveStart}
@@ -189,7 +191,7 @@
:root {
--background-color-default: #fff;
--background-pattern-color-default: #eee;
--background-pattern-color-default: #ddd;
--minimap-background-color-default: #fff;
--minimap-mask-color-default: rgb(240, 240, 240, 0.6);

View File

@@ -25,6 +25,7 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
nodeTypes?: NodeTypes;
edgeTypes?: EdgeTypes;
selectionKey?: KeyDefinition;
panActivationKey?: KeyDefinition;
deleteKey?: KeyDefinition;
fitView?: boolean;
nodeOrigin?: NodeOrigin;

View File

@@ -27,10 +27,12 @@
maxZoom,
dragging,
translateExtent,
lib
lib,
panActivationKeyPressed
} = useStore();
$: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 };
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
</script>
<div
@@ -49,7 +51,7 @@
zoomOnDoubleClick,
zoomOnPinch,
panOnScroll,
panOnDrag,
panOnDrag: _panOnDrag,
panOnScrollSpeed: 0.5,
panOnScrollMode: panOnScrollMode || PanOnScrollMode.Free,
zoomActivationKeyPressed: false,

View File

@@ -68,6 +68,7 @@ export const getInitialStore = () => ({
selectionKeyPressed: writable<boolean>(false),
multiselectionKeyPressed: writable<boolean>(false),
deleteKeyPressed: writable<boolean>(false),
panActivationKeyPressed: writable<boolean>(false),
selectionRectMode: writable<string | null>(null),
selectionMode: writable<SelectionMode>(SelectionMode.Partial),
nodeTypes: writable<NodeTypes>(initialNodeTypes),

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { SvelteComponentTyped } from 'svelte';
import type { SvelteComponent, ComponentType } from 'svelte';
import type {
EdgeBase,
BezierPathOptions,
@@ -45,7 +45,7 @@ export type EdgeProps = Omit<Edge, 'sourceHandle' | 'targetHandle'> &
targetHandleId?: string | null;
};
export type EdgeTypes = Record<string, typeof SvelteComponentTyped<EdgeProps>>;
export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>;
export type DefaultEdgeOptions = DefaultEdgeOptionsBase<Edge>;

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { SvelteComponentTyped } from 'svelte';
import type { ComponentType, SvelteComponent } from 'svelte';
import type { NodeBase, NodeProps } from '@xyflow/system';
// @todo: currently the helper function only like Node from '@reactflow/core'
@@ -14,6 +14,6 @@ export type Node<
style?: string;
};
export type NodeTypes = Record<string, typeof SvelteComponentTyped<NodeProps>>;
export type NodeTypes = Record<string, ComponentType<SvelteComponent<NodeProps>>>;
export type DefaultNodeOptions = Partial<Omit<Node, 'id'>>;

View File

@@ -0,0 +1,54 @@
<script lang="ts">
import { writable } from 'svelte/store';
import {
SvelteFlow,
Controls,
Background,
BackgroundVariant,
SelectionMode
} from '../../lib/index';
const onPaneContextMenu = (e: any) => {
e.preventDefault();
console.log('context menu');
};
const panOnDrag = [1, 2];
const onMoveStart = (e: any) => console.log('move start', e);
const onMove = (e: any) => console.log('move', e);
const onMoveEnd = (e: any) => console.log('move end', e);
const nodes = writable([
{
id: '1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
className: 'light'
},
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' }
]);
const edges = writable([
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' }
]);
</script>
<SvelteFlow
{nodes}
{edges}
fitView
selectionMode={SelectionMode.Partial}
panOnScroll
{panOnDrag}
{onMoveStart}
{onMove}
{onMoveEnd}
>
<Controls />
<Background variant={BackgroundVariant.Dots} />
</SvelteFlow>

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { isWrappedWithClass } from './utils';
export type FilterParams = {

10
pnpm-lock.yaml generated
View File

@@ -200,8 +200,8 @@ importers:
packages/svelte:
dependencies:
'@svelte-put/shortcut':
specifier: ^2.0.0
version: registry.npmjs.org/@svelte-put/shortcut@2.0.0
specifier: ^3.0.0
version: registry.npmjs.org/@svelte-put/shortcut@3.0.0
'@xyflow/system':
specifier: workspace:*
version: link:../system
@@ -1797,10 +1797,10 @@ packages:
version: 2.0.0
dev: true
registry.npmjs.org/@svelte-put/shortcut@2.0.0:
resolution: {integrity: sha512-dDyxIFlRz+W6wxwQtl2jUen0rX8ofV2VBWaJdz0QehLb0IMDzP3aWM9W4k8cAZQIGmTT0adr1+Gt7HPPUugcpQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-2.0.0.tgz}
registry.npmjs.org/@svelte-put/shortcut@3.0.0:
resolution: {integrity: sha512-nZg3pwpTi9wUsvQPlqOzEsxZcF2jmY5j+VBq/20IUjjd2OpM92XqZAga0PCCjE6OuEobOt58UMnC2QZgOvk0tQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-3.0.0.tgz}
name: '@svelte-put/shortcut'
version: 2.0.0
version: 3.0.0
dev: false
registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6):