refactor(svelte): add zoomActivationKey and allow null for keys #3618 (#3627)

* refactor(keys): add zoomActivationKey and allow null #3618
This commit is contained in:
Moritz Klack
2023-11-15 19:06:49 +01:00
committed by GitHub
parent aeb1c4132f
commit 14caf422c3
8 changed files with 103 additions and 55 deletions

View File

@@ -8,8 +8,8 @@
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"dev": "turbo run dev --parallel --concurrency 12", "dev": "turbo run dev --parallel --concurrency 12",
"dev:svelte": "turbo run dev --filter=svelte --filter=system", "dev:svelte": "turbo run dev --filter=svelte-examples...",
"dev:react": "turbo run dev --filter=react-examples ", "dev:react": "turbo run dev --filter=react-examples...",
"test:svelte": "pnpm --filter=playwright run test:svelte", "test:svelte": "pnpm --filter=playwright run test:svelte",
"test:svelte:ui": "pnpm --filter=playwright run test:svelte:ui", "test:svelte:ui": "pnpm --filter=playwright run test:svelte:ui",
"test:react": "pnpm --filter=playwright run test:react", "test:react": "pnpm --filter=playwright run test:react",

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { shortcut } from '@svelte-put/shortcut'; import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { KeyHandlerProps } from './types'; import type { KeyHandlerProps } from './types';
@@ -12,40 +12,66 @@
export let multiSelectionKey: $$Props['multiSelectionKey'] = isMacOs() ? 'Meta' : 'Control'; export let multiSelectionKey: $$Props['multiSelectionKey'] = isMacOs() ? 'Meta' : 'Control';
export let deleteKey: $$Props['deleteKey'] = 'Backspace'; export let deleteKey: $$Props['deleteKey'] = 'Backspace';
export let panActivationKey: $$Props['panActivationKey'] = ' '; export let panActivationKey: $$Props['panActivationKey'] = ' ';
export let zoomActivationKey: $$Props['zoomActivationKey'] = isMacOs() ? 'Meta' : 'Control';
const { const {
selectionKeyPressed, selectionKeyPressed,
multiselectionKeyPressed, multiselectionKeyPressed,
deleteKeyPressed, deleteKeyPressed,
panActivationKeyPressed panActivationKeyPressed,
zoomActivationKeyPressed
} = useStore(); } = useStore();
function isKeyObject(key?: KeyDefinition): key is KeyDefinitionObject { function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject {
return typeof key === 'object'; return typeof key === 'object';
} }
$: selectionKeyString = typeof selectionKey === 'string' ? selectionKey : selectionKey!.key; function getModifier(key?: KeyDefinition | null): ShortcutModifierDefinition {
$: selectionKeyModifier = isKeyObject(selectionKey) ? selectionKey?.modifier : []; return isKeyObject(key) ? key.modifier || [] : [];
}
$: multiSelectionKeyString = function getKeyString(key?: KeyDefinition | null): string {
typeof multiSelectionKey === 'string' ? multiSelectionKey : multiSelectionKey!.key; if (key === null || key === undefined) {
$: multiSelectionKeyModifier = isKeyObject(multiSelectionKey) ? multiSelectionKey?.modifier : []; // this is a workaround to check if a key is set
// if not we won't call the callback
return '';
}
$: deleteKeyString = typeof deleteKey === 'string' ? deleteKey : deleteKey!.key; return isKeyObject(key) ? key.key : key;
$: deleteKeyModifier = isKeyObject(deleteKey) ? deleteKey?.modifier : []; }
$: panActivationKeyString = $: selectionKeyDefinition = {
typeof panActivationKey === 'string' ? panActivationKey : panActivationKey!.key; key: getKeyString(selectionKey),
$: panActivationKeyModifier = isKeyObject(panActivationKey) ? panActivationKey?.modifier : []; modifier: getModifier(selectionKey)
};
$: multiSelectionKeyDefinition = {
key: getKeyString(multiSelectionKey),
modifier: getModifier(multiSelectionKey)
};
$: deleteKeyDefinition = {
key: getKeyString(deleteKey),
modifier: getModifier(deleteKey)
};
$: panActivationKeyDefinition = {
key: getKeyString(panActivationKey),
modifier: getModifier(panActivationKey)
};
$: zoomActivationKeyDefinition = {
key: getKeyString(zoomActivationKey),
modifier: getModifier(zoomActivationKey)
};
</script> </script>
<svelte:window <svelte:window
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: selectionKeyString, ...selectionKeyDefinition,
modifier: selectionKeyModifier, callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(true)
callback: () => selectionKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -53,9 +79,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: selectionKeyString, ...selectionKeyDefinition,
modifier: selectionKeyModifier, callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(false)
callback: () => selectionKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -63,9 +88,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: multiSelectionKeyString, ...multiSelectionKeyDefinition,
modifier: multiSelectionKeyModifier, callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(true)
callback: () => multiselectionKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -73,9 +97,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: multiSelectionKeyString, ...multiSelectionKeyDefinition,
modifier: multiSelectionKeyModifier, callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(false)
callback: () => multiselectionKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -83,11 +106,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: deleteKeyString, ...deleteKeyDefinition,
modifier: deleteKeyModifier, callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(true)
callback: () => {
deleteKeyPressed.set(true);
}
} }
], ],
type: 'keydown' type: 'keydown'
@@ -95,9 +115,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: deleteKeyString, ...deleteKeyDefinition,
modifier: deleteKeyModifier, callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(false)
callback: () => deleteKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -105,9 +124,8 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: panActivationKeyString, ...panActivationKeyDefinition,
modifier: panActivationKeyModifier, callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(true)
callback: () => panActivationKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -115,9 +133,26 @@
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
key: panActivationKeyString, ...panActivationKeyDefinition,
modifier: panActivationKeyModifier, callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(false)
callback: () => panActivationKeyPressed.set(false) }
],
type: 'keyup'
}}
use:shortcut={{
trigger: [
{
...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(true)
}
],
type: 'keydown'
}}
use:shortcut={{
trigger: [
{
...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'

View File

@@ -1,8 +1,9 @@
import type { KeyDefinition } from '$lib/types'; import type { KeyDefinition } from '$lib/types';
export type KeyHandlerProps = { export type KeyHandlerProps = {
selectionKey?: KeyDefinition; selectionKey?: KeyDefinition | null;
multiSelectionKey?: KeyDefinition; multiSelectionKey?: KeyDefinition | null;
deleteKey?: KeyDefinition; deleteKey?: KeyDefinition | null;
panActivationKey?: KeyDefinition; panActivationKey?: KeyDefinition | null;
zoomActivationKey?: KeyDefinition | null;
}; };

View File

@@ -34,6 +34,8 @@
export let selectionKey: $$Props['selectionKey'] = undefined; export let selectionKey: $$Props['selectionKey'] = undefined;
export let selectionMode: $$Props['selectionMode'] = undefined; export let selectionMode: $$Props['selectionMode'] = undefined;
export let panActivationKey: $$Props['panActivationKey'] = undefined; export let panActivationKey: $$Props['panActivationKey'] = undefined;
export let multiSelectionKey: $$Props['multiSelectionKey'] = undefined;
export let zoomActivationKey: $$Props['zoomActivationKey'] = undefined;
export let nodesDraggable: $$Props['nodesDraggable'] = undefined; export let nodesDraggable: $$Props['nodesDraggable'] = undefined;
export let nodesConnectable: $$Props['nodesConnectable'] = undefined; export let nodesConnectable: $$Props['nodesConnectable'] = undefined;
export let nodeDragThreshold: $$Props['nodeDragThreshold'] = undefined; export let nodeDragThreshold: $$Props['nodeDragThreshold'] = undefined;
@@ -166,7 +168,13 @@
{...$$restProps} {...$$restProps}
role="application" role="application"
> >
<KeyHandler {selectionKey} {deleteKey} {panActivationKey} /> <KeyHandler
{selectionKey}
{deleteKey}
{panActivationKey}
{multiSelectionKey}
{zoomActivationKey}
/>
<Zoom <Zoom
{initialViewport} {initialViewport}
{onMoveStart} {onMoveStart}

View File

@@ -34,9 +34,11 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
edges: Writable<Edge[]>; edges: Writable<Edge[]>;
nodeTypes?: NodeTypes; nodeTypes?: NodeTypes;
edgeTypes?: EdgeTypes; edgeTypes?: EdgeTypes;
selectionKey?: KeyDefinition; selectionKey?: KeyDefinition | null;
panActivationKey?: KeyDefinition; panActivationKey?: KeyDefinition | null;
deleteKey?: KeyDefinition; deleteKey?: KeyDefinition | null;
multiSelectionKey?: KeyDefinition | null;
zoomActivationKey?: KeyDefinition | null;
fitView?: boolean; fitView?: boolean;
fitViewOptions?: FitViewOptions; fitViewOptions?: FitViewOptions;
nodeOrigin?: NodeOrigin; nodeOrigin?: NodeOrigin;

View File

@@ -28,7 +28,8 @@
dragging, dragging,
translateExtent, translateExtent,
lib, lib,
panActivationKeyPressed panActivationKeyPressed,
zoomActivationKeyPressed
} = useStore(); } = useStore();
$: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 }; $: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 };
@@ -55,7 +56,7 @@
panOnDrag: _panOnDrag, panOnDrag: _panOnDrag,
panOnScrollSpeed: 0.5, panOnScrollSpeed: 0.5,
panOnScrollMode: panOnScrollMode || PanOnScrollMode.Free, panOnScrollMode: panOnScrollMode || PanOnScrollMode.Free,
zoomActivationKeyPressed: false, zoomActivationKeyPressed: $zoomActivationKeyPressed,
preventScrolling: typeof preventScrolling === 'boolean' ? preventScrolling : true, preventScrolling: typeof preventScrolling === 'boolean' ? preventScrolling : true,
noPanClassName: 'nopan', noPanClassName: 'nopan',
noWheelClassName: 'nowheel', noWheelClassName: 'nowheel',

View File

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

8
pnpm-lock.yaml generated
View File

@@ -3523,7 +3523,6 @@ packages:
version: 8.11.2 version: 8.11.2
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
dev: true
registry.npmjs.org/aggregate-error@3.1.0: registry.npmjs.org/aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz} resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz}
@@ -4395,7 +4394,7 @@ packages:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec@1.4.15 '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec@1.4.15
'@types/estree': registry.npmjs.org/@types/estree@1.0.3 '@types/estree': registry.npmjs.org/@types/estree@1.0.3
acorn: registry.npmjs.org/acorn@8.10.0 acorn: registry.npmjs.org/acorn@8.11.2
estree-walker: registry.npmjs.org/estree-walker@3.0.3 estree-walker: registry.npmjs.org/estree-walker@3.0.3
periscopic: registry.npmjs.org/periscopic@3.1.0 periscopic: registry.npmjs.org/periscopic@3.1.0
@@ -6029,6 +6028,7 @@ packages:
glob-parent: registry.npmjs.org/glob-parent@5.1.2 glob-parent: registry.npmjs.org/glob-parent@5.1.2
merge2: registry.npmjs.org/merge2@1.4.1 merge2: registry.npmjs.org/merge2@1.4.1
micromatch: registry.npmjs.org/micromatch@4.0.5 micromatch: registry.npmjs.org/micromatch@4.0.5
dev: false
registry.npmjs.org/fast-glob@3.3.2: registry.npmjs.org/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz} resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz}
@@ -10957,7 +10957,7 @@ packages:
dependencies: dependencies:
'@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping@0.3.20 '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping@0.3.20
chokidar: registry.npmjs.org/chokidar@3.5.3 chokidar: registry.npmjs.org/chokidar@3.5.3
fast-glob: registry.npmjs.org/fast-glob@3.3.1 fast-glob: registry.npmjs.org/fast-glob@3.3.2
import-fresh: registry.npmjs.org/import-fresh@3.3.0 import-fresh: registry.npmjs.org/import-fresh@3.3.0
picocolors: registry.npmjs.org/picocolors@1.0.0 picocolors: registry.npmjs.org/picocolors@1.0.0
sade: registry.npmjs.org/sade@1.8.1 sade: registry.npmjs.org/sade@1.8.1
@@ -11230,7 +11230,7 @@ packages:
'@ampproject/remapping': registry.npmjs.org/@ampproject/remapping@2.2.1 '@ampproject/remapping': registry.npmjs.org/@ampproject/remapping@2.2.1
'@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec@1.4.15 '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec@1.4.15
'@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping@0.3.20 '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping@0.3.20
acorn: registry.npmjs.org/acorn@8.10.0 acorn: registry.npmjs.org/acorn@8.11.2
aria-query: registry.npmjs.org/aria-query@5.3.0 aria-query: registry.npmjs.org/aria-query@5.3.0
axobject-query: registry.npmjs.org/axobject-query@3.2.1 axobject-query: registry.npmjs.org/axobject-query@3.2.1
code-red: registry.npmjs.org/code-red@1.0.4 code-red: registry.npmjs.org/code-red@1.0.4