feat: add useStore and useHooks composables that provide default store/hooks
This commit is contained in:
@@ -1,5 +1,15 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getEdgeCenter, getBezierPath, getMarkerEnd, ArrowHeadType, EdgeProps, ElementId, Position, Hooks, Store } from '~/index'
|
import {
|
||||||
|
useHooks,
|
||||||
|
useStore,
|
||||||
|
getEdgeCenter,
|
||||||
|
getBezierPath,
|
||||||
|
getMarkerEnd,
|
||||||
|
ArrowHeadType,
|
||||||
|
EdgeProps,
|
||||||
|
ElementId,
|
||||||
|
Position,
|
||||||
|
} from '~/index'
|
||||||
|
|
||||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||||
id: ElementId
|
id: ElementId
|
||||||
@@ -15,8 +25,8 @@ interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<CustomEdgeProps>()
|
const props = defineProps<CustomEdgeProps>()
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
const onEdgeClick = (evt: Event, id: string) => {
|
const onEdgeClick = (evt: Event, id: string) => {
|
||||||
const edge = store.edges.find((edge) => edge.id === id)
|
const edge = store.edges.find((edge) => edge.id === id)
|
||||||
if (edge) {
|
if (edge) {
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import Flow, {
|
|||||||
FlowElement,
|
FlowElement,
|
||||||
Node,
|
Node,
|
||||||
OnLoadParams,
|
OnLoadParams,
|
||||||
|
addEdge,
|
||||||
|
removeElements,
|
||||||
} from '~/index'
|
} from '~/index'
|
||||||
import { addEdge, removeElements } from '~/utils/graph'
|
|
||||||
|
|
||||||
const elements = ref<Elements>([])
|
const elements = ref<Elements>([])
|
||||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { HTMLAttributes } from 'vue'
|
import { HTMLAttributes } from 'vue'
|
||||||
import { BackgroundVariant } from '~/types'
|
import { BackgroundVariant } from '~/types'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
export interface BackgroundProps extends HTMLAttributes {
|
export interface BackgroundProps extends HTMLAttributes {
|
||||||
variant?: BackgroundVariant
|
variant?: BackgroundVariant
|
||||||
@@ -21,7 +21,7 @@ const defaultColors: Record<BackgroundVariant, string> = {
|
|||||||
[BackgroundVariant.Lines]: '#eee',
|
[BackgroundVariant.Lines]: '#eee',
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
|
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
|
||||||
|
|
||||||
const bgClasses = ['revue-flow__background']
|
const bgClasses = ['revue-flow__background']
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import Fitview from '@/assets/icons/fitview.svg'
|
|||||||
import Lock from '@/assets/icons/lock.svg'
|
import Lock from '@/assets/icons/lock.svg'
|
||||||
import Unlock from '@/assets/icons/unlock.svg'
|
import Unlock from '@/assets/icons/unlock.svg'
|
||||||
import { FitViewParams } from '~/types'
|
import { FitViewParams } from '~/types'
|
||||||
import useZoomPanHelper from '~/composables/useZoomPanHelper'
|
import { useZoomPanHelper, useStore } from '~/composables'
|
||||||
import { Store } from '~/context'
|
|
||||||
|
|
||||||
export interface ControlProps extends HTMLAttributes {
|
export interface ControlProps extends HTMLAttributes {
|
||||||
showZoom?: boolean
|
showZoom?: boolean
|
||||||
@@ -27,7 +26,7 @@ const props = withDefaults(defineProps<ControlProps>(), {
|
|||||||
showInteractive: true,
|
showInteractive: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const { zoomIn, zoomOut, fitView } = useZoomPanHelper()
|
const { zoomIn, zoomOut, fitView } = useZoomPanHelper()
|
||||||
|
|
||||||
const isInteractive = store.nodesDraggable && store.nodesConnectable && store.elementsSelectable
|
const isInteractive = store.nodesDraggable && store.nodesConnectable && store.elementsSelectable
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { HTMLAttributes } from 'vue'
|
import { HTMLAttributes } from 'vue'
|
||||||
import MiniMapNode from './MiniMapNode.vue'
|
import MiniMapNode from './MiniMapNode.vue'
|
||||||
import { getBoundsofRects, getRectOfNodes } from '~/utils/graph'
|
import { getBoundsofRects, getRectOfNodes } from '~/utils'
|
||||||
import { Node } from '~/types'
|
import { Node } from '~/types'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
type StringFunc = (node: Node) => string
|
type StringFunc = (node: Node) => string
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ declare const window: any
|
|||||||
const defaultWidth = 200
|
const defaultWidth = 200
|
||||||
const defaultHeight = 150
|
const defaultHeight = 150
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
|
|
||||||
const elementWidth = attrs.style?.width ?? defaultWidth
|
const elementWidth = attrs.style?.width ?? defaultWidth
|
||||||
const elementHeight = attrs.style?.height ?? defaultHeight
|
const elementHeight = attrs.style?.height ?? defaultHeight
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { ConnectionLineType, HandleElement, Node, Position } from '~/types'
|
import { ConnectionLineType, HandleElement, Node, Position } from '~/types'
|
||||||
import { getBezierPath, getSmoothStepPath } from '~/components/Edges/utils'
|
import { getBezierPath, getSmoothStepPath } from '~/components/Edges/utils'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
interface ConnectionLineProps {
|
interface ConnectionLineProps {
|
||||||
sourceNode: Node
|
sourceNode: Node
|
||||||
@@ -15,7 +15,7 @@ const props = withDefaults(defineProps<ConnectionLineProps>(), {
|
|||||||
connectionLineStyle: () => ({}),
|
connectionLineStyle: () => ({}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
|
|
||||||
const sourceHandle =
|
const sourceHandle =
|
||||||
store.connectionHandleId && store.connectionHandleType
|
store.connectionHandleId && store.connectionHandleType
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
import EdgeAnchor from './EdgeAnchor.vue'
|
import EdgeAnchor from './EdgeAnchor.vue'
|
||||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
|
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
|
||||||
import { isEdge } from '~/utils/graph'
|
import { isEdge } from '~/utils/graph'
|
||||||
import { ConnectionMode, Edge, EdgeType, HandleElement, Position, EdgePositions } from '~/types'
|
import { ConnectionMode, Edge, EdgeType, Position } from '~/types'
|
||||||
import { Hooks, Store } from '~/context'
|
import { useHandle, useHooks, useStore } from '~/composables'
|
||||||
import { useHandle } from '~/composables'
|
|
||||||
|
|
||||||
interface EdgeProps {
|
interface EdgeProps {
|
||||||
type: EdgeType
|
type: EdgeType
|
||||||
@@ -15,8 +14,8 @@ interface EdgeProps {
|
|||||||
|
|
||||||
const props = withDefaults(defineProps<EdgeProps>(), {})
|
const props = withDefaults(defineProps<EdgeProps>(), {})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
|
|
||||||
hooks.connect.on((connection) => {
|
hooks.connect.on((connection) => {
|
||||||
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ElementId, Position, ValidConnectionFunc } from '~/types'
|
import { Position, ValidConnectionFunc } from '~/types'
|
||||||
import { Hooks, Store } from '~/context'
|
import { NodeIdContextKey } from '~/context'
|
||||||
import { useHandle } from '~/composables'
|
import { useHandle, useHooks, useStore } from '~/composables'
|
||||||
|
|
||||||
interface HandleProps {
|
interface HandleProps {
|
||||||
id?: string
|
id?: string
|
||||||
@@ -18,9 +18,9 @@ const props = withDefaults(defineProps<HandleProps>(), {
|
|||||||
connectable: true,
|
connectable: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
const nodeId = inject<ElementId>('NodeIdContext')!
|
const nodeId = inject(NodeIdContextKey)!
|
||||||
|
|
||||||
const handler = useHandle()
|
const handler = useHandle()
|
||||||
const onMouseDownHandler = (event: MouseEvent) =>
|
const onMouseDownHandler = (event: MouseEvent) =>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { DraggableEventListener } from '@braks/revue-draggable'
|
import { DraggableEventListener } from '@braks/revue-draggable'
|
||||||
import { Node, NodeDimensionUpdate, NodeType, SnapGrid } from '~/types'
|
import { Node, NodeDimensionUpdate, NodeType, SnapGrid } from '~/types'
|
||||||
import { Hooks, Store } from '~/context'
|
import { NodeIdContextKey } from '~/context'
|
||||||
|
import { useHooks, useStore } from '~/composables'
|
||||||
|
|
||||||
interface NodeProps {
|
interface NodeProps {
|
||||||
node: Node
|
node: Node
|
||||||
@@ -24,9 +25,9 @@ const props = withDefaults(defineProps<NodeProps>(), {
|
|||||||
scale: 1,
|
scale: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
provide('NodeIdContext', props.node.id)
|
provide(NodeIdContextKey, props.node.id)
|
||||||
|
|
||||||
const nodeElement = templateRef<HTMLDivElement>('node-element', null)
|
const nodeElement = templateRef<HTMLDivElement>('node-element', null)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { DraggableEventListener } from '@braks/revue-draggable'
|
import { DraggableEventListener } from '@braks/revue-draggable'
|
||||||
import { Node } from '~/types'
|
import { Node } from '~/types'
|
||||||
import { isNode } from '~/utils/graph'
|
import { isNode } from '~/utils/graph'
|
||||||
import { Hooks, Store } from '~/context'
|
import { useHooks, useStore } from '~/composables'
|
||||||
|
|
||||||
interface NodesSelectionProps {
|
interface NodesSelectionProps {
|
||||||
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void
|
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void
|
||||||
@@ -13,8 +13,8 @@ interface NodesSelectionProps {
|
|||||||
|
|
||||||
const props = defineProps<NodesSelectionProps>()
|
const props = defineProps<NodesSelectionProps>()
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
|
|
||||||
const selectedNodes = computed(() =>
|
const selectedNodes = computed(() =>
|
||||||
store.selectedElements
|
store.selectedElements
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import SelectionRect from './SelectionRect.vue'
|
import SelectionRect from './SelectionRect.vue'
|
||||||
import { getMousePosition } from '~/components/UserSelection/utils'
|
import { getMousePosition } from '~/components/UserSelection/utils'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const el = templateRef('user-selection', null)
|
const el = templateRef('user-selection', null)
|
||||||
|
|
||||||
const onMouseDown = (event: MouseEvent) => {
|
const onMouseDown = (event: MouseEvent) => {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
export { default as useHandle } from './useHandle'
|
export { default as useHandle } from './useHandle'
|
||||||
export { default as useHooks } from './useHooks'
|
export { default as useHooks } from './useHooks'
|
||||||
|
export * from './useHooks'
|
||||||
export { default as useKeyPress } from './useKeyPress'
|
export { default as useKeyPress } from './useKeyPress'
|
||||||
export { default as useUpdateNodeInternals } from './useUpdateNodeInternals'
|
export { default as useUpdateNodeInternals } from './useUpdateNodeInternals'
|
||||||
export { default as useZoom } from './useZoom'
|
export { default as useZoom } from './useZoom'
|
||||||
export { default as useZoomPanHelper } from './useZoomPanHelper'
|
export { default as useZoomPanHelper } from './useZoomPanHelper'
|
||||||
|
export { default as useStore } from './useStore'
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { getHostForElement } from '~/utils'
|
import { getHostForElement } from '~/utils'
|
||||||
import { Hooks, Store } from '~/context'
|
|
||||||
import { Connection, ConnectionMode, ElementId, HandleType, ValidConnectionFunc } from '~/types'
|
import { Connection, ConnectionMode, ElementId, HandleType, ValidConnectionFunc } from '~/types'
|
||||||
|
import useStore from '~/composables/useStore'
|
||||||
|
import useHooks from '~/composables/useHooks'
|
||||||
|
|
||||||
type Result = {
|
type Result = {
|
||||||
elementBelow: Element | null
|
elementBelow: Element | null
|
||||||
@@ -10,7 +11,7 @@ type Result = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
|
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
|
||||||
export function checkElementBelowIsValid(
|
export const checkElementBelowIsValid = (
|
||||||
event: MouseEvent,
|
event: MouseEvent,
|
||||||
connectionMode: ConnectionMode,
|
connectionMode: ConnectionMode,
|
||||||
isTarget: boolean,
|
isTarget: boolean,
|
||||||
@@ -18,7 +19,7 @@ export function checkElementBelowIsValid(
|
|||||||
handleId: ElementId | null,
|
handleId: ElementId | null,
|
||||||
isValidConnection: ValidConnectionFunc,
|
isValidConnection: ValidConnectionFunc,
|
||||||
doc: Document,
|
doc: Document,
|
||||||
) {
|
) => {
|
||||||
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
|
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
|
||||||
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false
|
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false
|
||||||
const elementBelowIsSource = elementBelow?.classList.contains('source') || false
|
const elementBelowIsSource = elementBelow?.classList.contains('source') || false
|
||||||
@@ -62,14 +63,14 @@ export function checkElementBelowIsValid(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetRecentHandle(hoveredHandle: Element): void {
|
const resetRecentHandle = (hoveredHandle: Element): void => {
|
||||||
hoveredHandle?.classList.remove('revue-flow__handle-valid')
|
hoveredHandle?.classList.remove('revue-flow__handle-valid')
|
||||||
hoveredHandle?.classList.remove('revue-flow__handle-connecting')
|
hoveredHandle?.classList.remove('revue-flow__handle-connecting')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function () {
|
export default () => {
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
event: MouseEvent,
|
event: MouseEvent,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// global hooks
|
import { Connection, Edge, Elements, EmitFunc, FlowHooks, FlowTransform, Node, OnConnectStartParams, OnLoadParams } from '~/types'
|
||||||
import { Connection, Edge, Elements, FlowHooks, FlowTransform, Node, OnConnectStartParams, OnLoadParams } from '~/types'
|
import { Hooks } from '~/context'
|
||||||
|
|
||||||
export default (): FlowHooks & { bind: (emit: (event: string, ...args: any[]) => void) => FlowHooks } => {
|
// flow event hooks
|
||||||
const eventHooks: FlowHooks = {
|
const hooks = (): FlowHooks => {
|
||||||
|
return {
|
||||||
elementClick: createEventHook<{ event: MouseEvent; element: Node | Edge }>(),
|
elementClick: createEventHook<{ event: MouseEvent; element: Node | Edge }>(),
|
||||||
elementsRemove: createEventHook<Elements>(),
|
elementsRemove: createEventHook<Elements>(),
|
||||||
nodeDoubleClick: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeDoubleClick: createEventHook<{ event: MouseEvent; node: Node }>(),
|
||||||
@@ -43,11 +44,13 @@ export default (): FlowHooks & { bind: (emit: (event: string, ...args: any[]) =>
|
|||||||
edgeUpdateStart: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeUpdateStart: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
||||||
edgeUpdateEnd: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeUpdateEnd: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const bind = (emit: (event: string, args: any) => void) => {
|
export const createHooks = (): FlowHooks & { bind: (emit: EmitFunc) => FlowHooks } => {
|
||||||
|
const eventHooks = hooks()
|
||||||
|
const bind = (emit: EmitFunc) => {
|
||||||
for (const [key, value] of Object.entries(eventHooks)) {
|
for (const [key, value] of Object.entries(eventHooks)) {
|
||||||
value.on((data: any) => {
|
value.on((data: unknown) => {
|
||||||
emit(key, data)
|
emit(key as keyof FlowHooks, data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,3 +62,17 @@ export default (): FlowHooks & { bind: (emit: (event: string, ...args: any[]) =>
|
|||||||
bind,
|
bind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default (emit?: EmitFunc) => {
|
||||||
|
let hooks = inject(Hooks)!
|
||||||
|
if (!hooks) {
|
||||||
|
console.warn('hooks context not found; creating default hooks')
|
||||||
|
if (!emit) console.error('no emit function found for hook context.')
|
||||||
|
else {
|
||||||
|
hooks = createHooks().bind(emit)
|
||||||
|
provide(Hooks, hooks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { FlowOptions } from '~/types'
|
||||||
|
import useFlowStore from '~/store/useFlowStore'
|
||||||
|
import { initialState } from '~/store'
|
||||||
|
import { Store } from '~/context'
|
||||||
|
|
||||||
|
export default (options?: Partial<FlowOptions>) => {
|
||||||
|
let store = inject(Store)!
|
||||||
|
if (!store) {
|
||||||
|
console.warn('store context not found; creating default store')
|
||||||
|
store = useFlowStore({
|
||||||
|
...initialState(),
|
||||||
|
...options,
|
||||||
|
})()
|
||||||
|
provide(Store, store)
|
||||||
|
}
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ElementId, UpdateNodeInternals } from '~/types'
|
import { ElementId, UpdateNodeInternals } from '~/types'
|
||||||
import { Store } from '~/context'
|
import useStore from '~/composables/useStore'
|
||||||
|
|
||||||
export default function (): UpdateNodeInternals {
|
export default (): UpdateNodeInternals => {
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
|
|
||||||
return (id: ElementId) => {
|
return (id: ElementId) => {
|
||||||
const nodeElement: HTMLDivElement | null = document.querySelector(`.revue-flow__node[data-id="${id}"]`)
|
const nodeElement: HTMLDivElement | null = document.querySelector(`.revue-flow__node[data-id="${id}"]`)
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { get } from '@vueuse/core'
|
|||||||
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
||||||
import { clamp } from '~/utils'
|
import { clamp } from '~/utils'
|
||||||
import useKeyPress from '~/composables/useKeyPress'
|
import useKeyPress from '~/composables/useKeyPress'
|
||||||
import { Hooks, Store } from '~/context'
|
import useHooks from '~/composables/useHooks'
|
||||||
|
import useStore from '~/composables/useStore'
|
||||||
|
|
||||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||||
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
||||||
@@ -16,7 +17,7 @@ const eventToFlowTransform = (eventTransform: ZoomTransform): FlowTransform => (
|
|||||||
zoom: eventTransform.k,
|
zoom: eventTransform.k,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZoom {
|
export default (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZoom => {
|
||||||
const {
|
const {
|
||||||
selectionKeyCode = 'Shift',
|
selectionKeyCode = 'Shift',
|
||||||
zoomActivationKeyCode = 'Meta',
|
zoomActivationKeyCode = 'Meta',
|
||||||
@@ -30,8 +31,8 @@ export default function (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZ
|
|||||||
panOnScrollMode = PanOnScrollMode.Free,
|
panOnScrollMode = PanOnScrollMode.Free,
|
||||||
paneMoveable = true,
|
paneMoveable = true,
|
||||||
} = options
|
} = options
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const prevTransform = ref<FlowTransform>({ x: 0, y: 0, zoom: 0 })
|
const prevTransform = ref<FlowTransform>({ x: 0, y: 0, zoom: 0 })
|
||||||
|
|
||||||
const clampedX = clamp(defaultPosition[0], store.translateExtent[0][0], store.translateExtent[1][0])
|
const clampedX = clamp(defaultPosition[0], store.translateExtent[0][0], store.translateExtent[1][0])
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { zoomIdentity } from 'd3-zoom'
|
import { zoomIdentity } from 'd3-zoom'
|
||||||
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils/graph'
|
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils/graph'
|
||||||
import { FitViewParams, FlowTransform, Rect, UseZoomPanHelper, XYPosition } from '~/types'
|
import { FitViewParams, FlowTransform, Rect, UseZoomPanHelper, XYPosition } from '~/types'
|
||||||
import { Store } from '~/context'
|
import useStore from '~/composables/useStore'
|
||||||
|
|
||||||
const DEFAULT_PADDING = 0.1
|
const DEFAULT_PADDING = 0.1
|
||||||
|
|
||||||
export default function (store = inject(Store)!): UseZoomPanHelper {
|
export default (): UseZoomPanHelper => {
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
zoomIn: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1.2),
|
zoomIn: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1.2),
|
||||||
zoomOut: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1 / 1.2),
|
zoomOut: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1 / 1.2),
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { getSourceTargetNodes } from './utils'
|
|
||||||
import MarkerDefinitions from './MarkerDefinitions.vue'
|
import MarkerDefinitions from './MarkerDefinitions.vue'
|
||||||
import Edge from '~/components/Edges/Edge.vue'
|
import Edge from '~/components/Edges/Edge.vue'
|
||||||
import ConnectionLine from '~/components/ConnectionLine/ConnectionLine.vue'
|
import ConnectionLine from '~/components/ConnectionLine/ConnectionLine.vue'
|
||||||
import { ConnectionLineType, EdgeType } from '~/types'
|
import { ConnectionLineType, EdgeType } from '~/types'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
interface EdgeRendererProps {
|
interface EdgeRendererProps {
|
||||||
edgeTypes: Record<string, EdgeType>
|
edgeTypes: Record<string, EdgeType>
|
||||||
@@ -22,7 +21,7 @@ const props = withDefaults(defineProps<EdgeRendererProps>(), {
|
|||||||
edgeUpdaterRadius: 10,
|
edgeUpdaterRadius: 10,
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
|
|
||||||
const sourceNode = computed(() => store.nodes.find((n) => n.id === store.connectionNodeId))
|
const sourceNode = computed(() => store.nodes.find((n) => n.id === store.connectionNodeId))
|
||||||
const connectionLineVisible = computed(
|
const connectionLineVisible = computed(
|
||||||
|
|||||||
@@ -17,14 +17,11 @@ import {
|
|||||||
TranslateExtent,
|
TranslateExtent,
|
||||||
NodeExtent,
|
NodeExtent,
|
||||||
} from '~/types'
|
} from '~/types'
|
||||||
import useFlowStore from '~/store/useFlowStore'
|
|
||||||
import { initialState } from '~/store'
|
|
||||||
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
|
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
|
||||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
||||||
import { createEdgeTypes } from '~/container/EdgeRenderer/utils'
|
import { createEdgeTypes } from '~/container/EdgeRenderer/utils'
|
||||||
import { createNodeTypes } from '~/container/NodeRenderer/utils'
|
import { createNodeTypes } from '~/container/NodeRenderer/utils'
|
||||||
import { useHooks } from '~/composables'
|
import { useHooks, useStore, createHooks } from '~/composables'
|
||||||
import { Hooks, Store } from '~/context'
|
|
||||||
|
|
||||||
export interface FlowProps {
|
export interface FlowProps {
|
||||||
elements: Elements
|
elements: Elements
|
||||||
@@ -99,7 +96,7 @@ const props = withDefaults(defineProps<FlowProps>(), {
|
|||||||
paneMoveable: true,
|
paneMoveable: true,
|
||||||
edgeUpdaterRadius: 10,
|
edgeUpdaterRadius: 10,
|
||||||
})
|
})
|
||||||
const emit = defineEmits(Object.keys(useHooks()))
|
const emit = defineEmits(Object.keys(createHooks()))
|
||||||
|
|
||||||
const defaultNodeTypes: Record<string, NodeType> = {
|
const defaultNodeTypes: Record<string, NodeType> = {
|
||||||
input: InputNode as NodeType,
|
input: InputNode as NodeType,
|
||||||
@@ -114,14 +111,8 @@ const defaultEdgeTypes: Record<string, EdgeType> = {
|
|||||||
smoothstep: SmoothStepEdge as EdgeType,
|
smoothstep: SmoothStepEdge as EdgeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
let store = inject(Store)!
|
const store = useStore(props)
|
||||||
if (!store) {
|
const hooks = useHooks(emit)
|
||||||
store = useFlowStore({
|
|
||||||
...initialState,
|
|
||||||
...props,
|
|
||||||
})()
|
|
||||||
provide(Store, store)
|
|
||||||
}
|
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
store.$state = { ...store.$state, ...props }
|
store.$state = { ...store.$state, ...props }
|
||||||
@@ -137,9 +128,6 @@ onBeforeUnmount(() => store?.$dispose())
|
|||||||
onUpdated(() => init())
|
onUpdated(() => init())
|
||||||
init()
|
init()
|
||||||
|
|
||||||
const hooks = useHooks().bind(emit)
|
|
||||||
provide(Hooks, hooks)
|
|
||||||
|
|
||||||
const nodeTypes = createNodeTypes({ ...defaultNodeTypes, ...props.nodeTypes })
|
const nodeTypes = createNodeTypes({ ...defaultNodeTypes, ...props.nodeTypes })
|
||||||
const edgeTypes = createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })
|
const edgeTypes = createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })
|
||||||
</script>
|
</script>
|
||||||
@@ -184,6 +172,6 @@ const edgeTypes = createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })
|
|||||||
</EdgeRenderer>
|
</EdgeRenderer>
|
||||||
</SelectionPane>
|
</SelectionPane>
|
||||||
</ZoomPane>
|
</ZoomPane>
|
||||||
<slot></slot>
|
<slot v-bind="{ flowProps: props, store, hooks }"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Node from '~/components/Nodes/Node.vue'
|
import Node from '~/components/Nodes/Node.vue'
|
||||||
import { NodeType, Node as TNode } from '~/types'
|
import { NodeType, Node as TNode } from '~/types'
|
||||||
import { getNodesInside } from '~/utils/graph'
|
import { getNodesInside } from '~/utils/graph'
|
||||||
import { Store } from '~/context'
|
import { useStore } from '~/composables'
|
||||||
|
|
||||||
interface NodeRendererProps {
|
interface NodeRendererProps {
|
||||||
nodeTypes: Record<string, NodeType>
|
nodeTypes: Record<string, NodeType>
|
||||||
@@ -10,7 +10,7 @@ interface NodeRendererProps {
|
|||||||
|
|
||||||
const props = defineProps<NodeRendererProps>()
|
const props = defineProps<NodeRendererProps>()
|
||||||
|
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
|
|
||||||
const getNodes = computed(() =>
|
const getNodes = computed(() =>
|
||||||
store.onlyRenderVisibleElements
|
store.onlyRenderVisibleElements
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import useKeyPress from '~/composables/useKeyPress'
|
|||||||
import { ElementId, FlowElement, KeyCode } from '~/types'
|
import { ElementId, FlowElement, KeyCode } from '~/types'
|
||||||
import NodesSelection from '~/components/NodesSelection/NodesSelection.vue'
|
import NodesSelection from '~/components/NodesSelection/NodesSelection.vue'
|
||||||
import UserSelection from '~/components/UserSelection/UserSelection.vue'
|
import UserSelection from '~/components/UserSelection/UserSelection.vue'
|
||||||
import { Hooks, Store } from '~/context'
|
|
||||||
import { getConnectedEdges, isNode } from '~/utils/graph'
|
import { getConnectedEdges, isNode } from '~/utils/graph'
|
||||||
|
import { useHooks, useStore } from '~/composables'
|
||||||
|
|
||||||
interface SelectionPaneProps {
|
interface SelectionPaneProps {
|
||||||
selectionKeyCode?: KeyCode
|
selectionKeyCode?: KeyCode
|
||||||
@@ -16,8 +16,8 @@ const props = withDefaults(defineProps<SelectionPaneProps>(), {
|
|||||||
deleteKeyCode: 'Backspace',
|
deleteKeyCode: 'Backspace',
|
||||||
multiSelectionKeyCode: 'Meta',
|
multiSelectionKeyCode: 'Meta',
|
||||||
})
|
})
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
|
|
||||||
const onClick = (event: MouseEvent) => {
|
const onClick = (event: MouseEvent) => {
|
||||||
hooks.paneClick.trigger(event)
|
hooks.paneClick.trigger(event)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { KeyCode, PanOnScrollMode } from '~/types'
|
import { KeyCode, PanOnScrollMode } from '~/types'
|
||||||
import { useZoom, useZoomPanHelper } from '~/composables'
|
import { useHooks, useStore, useZoom, useZoomPanHelper } from '~/composables'
|
||||||
import { Hooks, Store } from '~/context'
|
|
||||||
import { onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils/graph'
|
import { onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils/graph'
|
||||||
|
|
||||||
interface ZoomPaneProps {
|
interface ZoomPaneProps {
|
||||||
@@ -31,8 +30,8 @@ const props = withDefaults(defineProps<ZoomPaneProps>(), {
|
|||||||
panOnScrollMode: PanOnScrollMode.Free,
|
panOnScrollMode: PanOnScrollMode.Free,
|
||||||
paneMoveable: true,
|
paneMoveable: true,
|
||||||
})
|
})
|
||||||
const store = inject(Store)!
|
const store = useStore()
|
||||||
const hooks = inject(Hooks)!
|
const hooks = useHooks()
|
||||||
|
|
||||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
||||||
const { transform } = useZoom(zoomPaneEl, props)
|
const { transform } = useZoom(zoomPaneEl, props)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { InjectionKey } from 'vue'
|
import { InjectionKey } from 'vue'
|
||||||
import { FlowHooks, FlowStore } from '~/types'
|
import { ElementId, FlowHooks, FlowStore } from '~/types'
|
||||||
|
|
||||||
export const Store: InjectionKey<FlowStore> = Symbol('store')
|
export const Store: InjectionKey<FlowStore> = Symbol('store')
|
||||||
export const Hooks: InjectionKey<FlowHooks> = Symbol('hooks')
|
export const Hooks: InjectionKey<FlowHooks> = Symbol('hooks')
|
||||||
export const NodeIdContextKey: InjectionKey<string> = Symbol('NodeIdContext')
|
export const NodeIdContextKey: InjectionKey<ElementId> = Symbol('NodeIdContext')
|
||||||
|
|||||||
@@ -14,9 +14,13 @@ export {
|
|||||||
updateEdge,
|
updateEdge,
|
||||||
getTransformForBounds,
|
getTransformForBounds,
|
||||||
getRectOfNodes,
|
getRectOfNodes,
|
||||||
|
isInputDOMNode,
|
||||||
} from './utils/graph'
|
} from './utils/graph'
|
||||||
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
||||||
export { default as useUpdateNodeInternals } from './composables/useUpdateNodeInternals'
|
export { default as useUpdateNodeInternals } from './composables/useUpdateNodeInternals'
|
||||||
|
export { default as useStore } from './composables/useStore'
|
||||||
|
export { default as useHooks } from './composables/useHooks'
|
||||||
|
export { default as useHandle } from './composables/useHandle'
|
||||||
|
|
||||||
export * from './additional-components'
|
export * from './additional-components'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,6 @@
|
|||||||
import { ConnectionMode, FlowState } from '~/types'
|
import { ConnectionMode, FlowState } from '~/types'
|
||||||
|
|
||||||
export const initialState: FlowState = {
|
export const initialState = (): FlowState => ({
|
||||||
dimensions: {
|
dimensions: {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
@@ -54,4 +54,6 @@ export const initialState: FlowState = {
|
|||||||
multiSelectionActive: false,
|
multiSelectionActive: false,
|
||||||
|
|
||||||
revueFlowVersion: typeof __REVUE_FLOW_VERSION__ !== 'undefined' ? __REVUE_FLOW_VERSION__ : '-',
|
revueFlowVersion: typeof __REVUE_FLOW_VERSION__ !== 'undefined' ? __REVUE_FLOW_VERSION__ : '-',
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export { default as useFlowStore } from './useFlowStore'
|
||||||
|
|||||||
+40
-37
@@ -1,45 +1,48 @@
|
|||||||
// global hooks
|
|
||||||
import { EventHook } from '@vueuse/core'
|
import { EventHook } from '@vueuse/core'
|
||||||
import { Connection, Edge, Elements, FlowTransform, Node, OnConnectStartParams, OnLoadParams } from '../types'
|
import { Connection, Edge, Elements, FlowTransform, Node, OnConnectStartParams, OnLoadParams } from '../types'
|
||||||
|
|
||||||
|
export type FlowHook<T = any> = EventHook<T>
|
||||||
|
|
||||||
export interface FlowHooks {
|
export interface FlowHooks {
|
||||||
elementClick: EventHook<{ event: MouseEvent; element: Node | Edge }>
|
elementClick: FlowHook<{ event: MouseEvent; element: Node | Edge }>
|
||||||
elementsRemove: EventHook<Elements>
|
elementsRemove: FlowHook<Elements>
|
||||||
nodeDoubleClick: EventHook<{ event: MouseEvent; node: Node }>
|
nodeDoubleClick: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeClick: EventHook<{ event: MouseEvent; node: Node }>
|
nodeClick: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeMouseEnter: EventHook<{ event: MouseEvent; node: Node }>
|
nodeMouseEnter: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeMouseMove: EventHook<{ event: MouseEvent; node: Node }>
|
nodeMouseMove: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeMouseLeave: EventHook<{ event: MouseEvent; node: Node }>
|
nodeMouseLeave: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeContextMenu: EventHook<{ event: MouseEvent; node: Node }>
|
nodeContextMenu: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeDragStart: EventHook<{ event: MouseEvent; node: Node }>
|
nodeDragStart: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeDrag: EventHook<{ event: MouseEvent; node: Node }>
|
nodeDrag: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
nodeDragStop: EventHook<{ event: MouseEvent; node: Node }>
|
nodeDragStop: FlowHook<{ event: MouseEvent; node: Node }>
|
||||||
connect: EventHook<Connection>
|
connect: FlowHook<Connection>
|
||||||
connectStart: EventHook<{
|
connectStart: FlowHook<{
|
||||||
event: MouseEvent
|
event: MouseEvent
|
||||||
params: OnConnectStartParams
|
params: OnConnectStartParams
|
||||||
}>
|
}>
|
||||||
connectStop: EventHook<MouseEvent>
|
connectStop: FlowHook<MouseEvent>
|
||||||
connectEnd: EventHook<MouseEvent>
|
connectEnd: FlowHook<MouseEvent>
|
||||||
load: EventHook<OnLoadParams>
|
load: FlowHook<OnLoadParams>
|
||||||
move: EventHook<FlowTransform | undefined>
|
move: FlowHook<FlowTransform | undefined>
|
||||||
moveStart: EventHook<FlowTransform | undefined>
|
moveStart: FlowHook<FlowTransform | undefined>
|
||||||
moveEnd: EventHook<FlowTransform | undefined>
|
moveEnd: FlowHook<FlowTransform | undefined>
|
||||||
selectionChange: EventHook<Elements | null>
|
selectionChange: FlowHook<Elements | null>
|
||||||
selectionDragStart: EventHook<{ event: MouseEvent; nodes: Node[] }>
|
selectionDragStart: FlowHook<{ event: MouseEvent; nodes: Node[] }>
|
||||||
selectionDrag: EventHook<{ event: MouseEvent; nodes: Node[] }>
|
selectionDrag: FlowHook<{ event: MouseEvent; nodes: Node[] }>
|
||||||
selectionDragStop: EventHook<{ event: MouseEvent; nodes: Node[] }>
|
selectionDragStop: FlowHook<{ event: MouseEvent; nodes: Node[] }>
|
||||||
selectionContextMenu: EventHook<{ event: MouseEvent; nodes: Node[] }>
|
selectionContextMenu: FlowHook<{ event: MouseEvent; nodes: Node[] }>
|
||||||
paneScroll: EventHook<WheelEvent | undefined>
|
paneScroll: FlowHook<WheelEvent | undefined>
|
||||||
paneClick: EventHook<MouseEvent>
|
paneClick: FlowHook<MouseEvent>
|
||||||
paneContextMenu: EventHook<MouseEvent>
|
paneContextMenu: FlowHook<MouseEvent>
|
||||||
edgeUpdate: EventHook<{ edge: Edge; connection: Connection }>
|
edgeUpdate: FlowHook<{ edge: Edge; connection: Connection }>
|
||||||
edgeContextMenu: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeContextMenu: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeMouseEnter: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeMouseEnter: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeMouseMove: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeMouseMove: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeMouseLeave: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeMouseLeave: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeDoubleClick: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeDoubleClick: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeClick: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeClick: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeUpdateStart: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeUpdateStart: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
edgeUpdateEnd: EventHook<{ event: MouseEvent; edge: Edge }>
|
edgeUpdateEnd: FlowHook<{ event: MouseEvent; edge: Edge }>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EmitFunc<T extends FlowHooks = FlowHooks> = (name: keyof T, ...args: any[]) => void
|
||||||
|
|||||||
Reference in New Issue
Block a user