feat: add useStore and useHooks composables that provide default store/hooks

This commit is contained in:
Braks
2021-10-20 22:39:54 +02:00
parent 61dc9dea33
commit b2b1fe822f
27 changed files with 174 additions and 128 deletions
+13 -3
View File
@@ -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) {
+2 -1
View File
@@ -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
+4 -5
View File
@@ -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 })
+6 -6
View File
@@ -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) =>
+5 -4
View File
@@ -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) => {
+2
View File
@@ -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'
+8 -7
View File
@@ -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,
+25 -8
View File
@@ -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
}
+18
View File
@@ -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
}
+3 -3
View File
@@ -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 -4
View File
@@ -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])
+4 -2
View File
@@ -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),
+2 -3
View File
@@ -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(
+5 -17
View File
@@ -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 -2
View File
@@ -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)
+3 -4
View File
@@ -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)
+2 -2
View File
@@ -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')
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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