refactor(viewpane): accept KeyFilter instead of KeyCode

# What's changed?

* accept type of `KeyFilter` instead of `KeyCode` for zoom/select/delete keypress
* don't filter on input dom elements
This commit is contained in:
braks
2022-08-01 21:10:14 +02:00
committed by Braks
parent a095052c84
commit bd36253cd0
7 changed files with 29 additions and 51 deletions
@@ -1,43 +1,32 @@
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { onKeyDown, onKeyPressed, onKeyUp } from '@vueuse/core' import type { KeyFilter } from '@vueuse/core'
import useWindow from './useWindow' import useWindow from './useWindow'
import type { KeyCode } from '~/types'
import { isInputDOMNode } from '~/utils'
export default (keyCode: Ref<KeyCode>, onChange?: (keyPressed: boolean) => void): Ref<boolean> => { export default (keyFilter: KeyFilter, onChange?: (keyPressed: boolean) => void): Ref<boolean> => {
const window = useWindow() const window = useWindow()
let isPressed = $ref(false) let isPressed = $ref(false)
watchEffect( watch($$(isPressed), () => {
() => { if (onChange && typeof onChange === 'function') onChange(isPressed)
if (onChange && typeof onChange === 'function') onChange(isPressed) })
},
{ flush: 'post' },
)
onKeyPressed( onKeyStroke(
(e) => !isInputDOMNode(e) && (e.key === keyCode.value || e.keyCode === keyCode.value), keyFilter,
(e) => { (e) => {
e.preventDefault() e.preventDefault()
isPressed = true isPressed = true
}, },
{ eventName: 'keydown' },
) )
onKeyDown( onKeyStroke(
(e) => !isInputDOMNode(e) && (e.key === keyCode.value || e.keyCode === keyCode.value), keyFilter,
(e) => {
e.preventDefault()
isPressed = true
},
)
onKeyUp(
(e) => !isInputDOMNode(e) && (e.key === keyCode.value || e.keyCode === keyCode.value),
(e) => { (e) => {
e.preventDefault() e.preventDefault()
isPressed = false isPressed = false
}, },
{ eventName: 'keyup' },
) )
if (typeof window.addEventListener !== 'undefined') { if (typeof window.addEventListener !== 'undefined') {
@@ -1,7 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { EdgeChange, GraphNode, NodeChange } from '../../types' import type { GraphNode } from '../../types'
import { useKeyPress, useVueFlow } from '../../composables' import { useKeyPress, useVueFlow } from '../../composables'
import { getConnectedEdges } from '../../utils'
import { NodesSelection, UserSelection } from '../../components' import { NodesSelection, UserSelection } from '../../components'
const { const {
@@ -41,7 +40,7 @@ const onMouseLeave = (event: MouseEvent) => emits.paneMouseLeave(event)
const onMouseMove = (event: MouseEvent) => emits.paneMouseMove(event) const onMouseMove = (event: MouseEvent) => emits.paneMouseMove(event)
useKeyPress($$(deleteKeyCode), (keyPressed) => { useKeyPress(deleteKeyCode, (keyPressed) => {
const nodesToRemove = getNodes.reduce<GraphNode[]>((res, node) => { const nodesToRemove = getNodes.reduce<GraphNode[]>((res, node) => {
if (!node.selected && node.parentNode && res.find((n) => n.id === node.parentNode)) { if (!node.selected && node.parentNode && res.find((n) => n.id === node.parentNode)) {
res.push(node) res.push(node)
@@ -71,13 +70,13 @@ useKeyPress($$(deleteKeyCode), (keyPressed) => {
} }
}) })
useKeyPress($$(multiSelectionKeyCode), (keyPressed) => { useKeyPress(multiSelectionKeyCode, (keyPressed) => {
setState({ setState({
multiSelectionActive: keyPressed, multiSelectionActive: keyPressed,
}) })
}) })
const selectionKeyPressed = useKeyPress($$(selectionKeyCode), (keyPressed) => { const selectionKeyPressed = useKeyPress(selectionKeyCode, (keyPressed) => {
if (userSelectionActive && keyPressed) return if (userSelectionActive && keyPressed) return
setState({ setState({
userSelectionActive: keyPressed && elementsSelectable, userSelectionActive: keyPressed && elementsSelectable,
@@ -97,7 +97,7 @@ onMounted(() => {
viewportRef: viewportEl.value, viewportRef: viewportEl.value,
}) })
const selectionKeyPressed = useKeyPress($$(selectionKeyCode), (keyPress) => { const selectionKeyPressed = useKeyPress(selectionKeyCode, (keyPress) => {
if (keyPress && !isZoomingOrPanning) { if (keyPress && !isZoomingOrPanning) {
d3Zoom.on('zoom', null) d3Zoom.on('zoom', null)
} else if (!keyPress) { } else if (!keyPress) {
@@ -109,7 +109,7 @@ onMounted(() => {
} }
}) })
const zoomKeyPressed = useKeyPress($$(zoomActivationKeyCode)) const zoomKeyPressed = useKeyPress(zoomActivationKeyCode)
d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => { d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
isZoomingOrPanning = true isZoomingOrPanning = true
+6 -5
View File
@@ -1,8 +1,9 @@
import type { CSSProperties } from 'vue' import type { CSSProperties } from 'vue'
import type { KeyFilter } from '@vueuse/core'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge' import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node' import type { CoordinateExtent, GraphNode, Node } from './node'
import type { ConnectionLineOptions, ConnectionLineType, ConnectionMode, Connector } from './connection' import type { ConnectionLineOptions, ConnectionLineType, ConnectionMode, Connector } from './connection'
import type { KeyCode, PanOnScrollMode } from './zoom' import type { PanOnScrollMode } from './zoom'
import type { EdgeTypesObject, NodeTypesObject } from './components' import type { EdgeTypesObject, NodeTypesObject } from './components'
export type ElementData = any export type ElementData = any
@@ -90,10 +91,10 @@ export interface FlowProps {
/** @deprecated use {@link ConnectionLineOptions.style} */ /** @deprecated use {@link ConnectionLineOptions.style} */
connectionLineStyle?: CSSProperties | null connectionLineStyle?: CSSProperties | null
connectionLineOptions?: ConnectionLineOptions connectionLineOptions?: ConnectionLineOptions
deleteKeyCode?: KeyCode deleteKeyCode?: KeyFilter
selectionKeyCode?: KeyCode selectionKeyCode?: KeyFilter
multiSelectionKeyCode?: KeyCode multiSelectionKeyCode?: KeyFilter
zoomActivationKeyCode?: KeyCode zoomActivationKeyCode?: KeyFilter
snapToGrid?: boolean snapToGrid?: boolean
snapGrid?: SnapGrid snapGrid?: SnapGrid
onlyRenderVisibleElements?: boolean onlyRenderVisibleElements?: boolean
+6 -5
View File
@@ -1,10 +1,11 @@
import type { CSSProperties, ComputedRef, ToRefs } from 'vue' import type { CSSProperties, ComputedRef, ToRefs } from 'vue'
import type { KeyFilter } from '@vueuse/core'
import type { Dimensions, Elements, FlowElements, FlowExportObject, FlowOptions, SnapGrid, XYPosition } from './flow' import type { Dimensions, Elements, FlowElements, FlowExportObject, FlowOptions, SnapGrid, XYPosition } from './flow'
import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components' import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
import type { Connection, ConnectionLineOptions, ConnectionLineType, ConnectionMode, Connector } from './connection' import type { Connection, ConnectionLineOptions, ConnectionLineType, ConnectionMode, Connector } from './connection'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge' import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node' import type { CoordinateExtent, GraphNode, Node } from './node'
import type { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode, Viewport, ViewportFunctions } from './zoom' import type { D3Selection, D3Zoom, D3ZoomHandler, PanOnScrollMode, Viewport, ViewportFunctions } from './zoom'
import type { FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks' import type { FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks'
import type { EdgeChange, NodeChange, NodeDragItem } from './changes' import type { EdgeChange, NodeChange, NodeDragItem } from './changes'
import type { HandleType, StartHandle } from './handle' import type { HandleType, StartHandle } from './handle'
@@ -54,10 +55,10 @@ export interface State extends Omit<FlowOptions, 'id' | 'modelValue'> {
userSelectionActive: boolean userSelectionActive: boolean
multiSelectionActive: boolean multiSelectionActive: boolean
deleteKeyCode: KeyCode deleteKeyCode: KeyFilter
selectionKeyCode: KeyCode selectionKeyCode: KeyFilter
multiSelectionKeyCode: KeyCode multiSelectionKeyCode: KeyFilter
zoomActivationKeyCode: KeyCode zoomActivationKeyCode: KeyFilter
connectionNodeId: string | null connectionNodeId: string | null
connectionHandleId: string | null connectionHandleId: string | null
-2
View File
@@ -12,8 +12,6 @@ export interface Viewport {
zoom: number zoom: number
} }
export type KeyCode = number | string
export enum PanOnScrollMode { export enum PanOnScrollMode {
Free = 'free', Free = 'free',
Vertical = 'vertical', Vertical = 'vertical',
-10
View File
@@ -19,16 +19,6 @@ import type {
} from '~/types' } from '~/types'
import { useWindow } from '~/composables' import { useWindow } from '~/composables'
const isHTMLElement = (el: EventTarget): el is HTMLElement => ('nodeName' || 'hasAttribute') in el
export const isInputDOMNode = (e: KeyboardEvent | MouseEvent): boolean => {
const target = e.target
if (target && isHTMLElement(target)) {
return ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(target.nodeName) || target.hasAttribute('contentEditable')
}
return false
}
export const getDimensions = (node: HTMLElement): Dimensions => ({ export const getDimensions = (node: HTMLElement): Dimensions => ({
width: node.offsetWidth, width: node.offsetWidth,
height: node.offsetHeight, height: node.offsetHeight,