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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user