Merge pull request #4037 from xyflow/svelte-multiple-key-handler
Svelte Flow: add multiple keys
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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,150 +45,81 @@
|
|||||||
return isKeyObject(key) ? key.key : key;
|
return isKeyObject(key) ? key.key : key;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetAll() {
|
function getShortcutTrigger(
|
||||||
|
key: KeyDefinition | KeyDefinition[] | null | undefined,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetKeysAndSelection() {
|
||||||
|
selectionRect.set(null);
|
||||||
selectionKeyPressed.set(false);
|
selectionKeyPressed.set(false);
|
||||||
multiselectionKeyPressed.set(false);
|
multiselectionKeyPressed.set(false);
|
||||||
deleteKeyPressed.set(false);
|
deleteKeyPressed.set(false);
|
||||||
panActivationKeyPressed.set(false);
|
panActivationKeyPressed.set(false);
|
||||||
zoomActivationKeyPressed.set(false);
|
zoomActivationKeyPressed.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: selectionKeyDefinition = {
|
|
||||||
key: getKeyString(selectionKey),
|
|
||||||
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
|
||||||
on:blur={resetAll}
|
on:blur={resetKeysAndSelection}
|
||||||
on:contextmenu={resetAll}
|
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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user