Skip to content

Commit

Permalink
refactor(core): replace types in NodeWrapper and default nodes
Browse files Browse the repository at this point in the history
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
  • Loading branch information
bcakmakoglu committed Aug 19, 2024
1 parent 6b5644e commit 02efdff
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 90 deletions.
17 changes: 7 additions & 10 deletions packages/core/src/components/Nodes/DefaultNode.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import type { Component, FunctionalComponent } from 'vue'
import { h } from 'vue'
import Handle from '../Handle/Handle.vue'
import type { NodeProps } from '../../types'
import type { Node, NodeProps } from '../../types'
import { Position } from '../../types'

const DefaultNode: FunctionalComponent<NodeProps<{ label: any }>> = function ({
const DefaultNode: FunctionalComponent<NodeProps<Node<{ label: any }, 'default'>>> = function ({
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label: _label,
connectable = true,
isValidTargetPos,
isValidSourcePos,
isConnectable = true,
data,
}) {
const label = data.label || _label
const label = data.label

return [
h(Handle as Component, { type: 'target', position: targetPosition, connectable, isValidConnection: isValidTargetPos }),
h(Handle as Component, { type: 'target', position: targetPosition, isConnectable }),
typeof label !== 'string' && label ? h(label) : h('div', { innerHTML: label }),
h(Handle as Component, { type: 'source', position: sourcePosition, connectable, isValidConnection: isValidSourcePos }),
h(Handle as Component, { type: 'source', position: sourcePosition, isConnectable }),
]
}

DefaultNode.props = ['sourcePosition', 'targetPosition', 'label', 'isValidTargetPos', 'isValidSourcePos', 'connectable', 'data']
DefaultNode.props = ['sourcePosition', 'targetPosition', 'isConnectable', 'data']
DefaultNode.inheritAttrs = false
DefaultNode.compatConfig = { MODE: 3 }

Expand Down
14 changes: 6 additions & 8 deletions packages/core/src/components/Nodes/InputNode.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import type { Component, FunctionalComponent } from 'vue'
import { h } from 'vue'
import Handle from '../Handle/Handle.vue'
import type { NodeProps } from '../../types'
import type { Node, NodeProps } from '../../types'
import { Position } from '../../types'

const InputNode: FunctionalComponent<NodeProps<{ label: any }>> = function ({
const InputNode: FunctionalComponent<NodeProps<Node<{ label: any }, 'input'>>> = function ({
sourcePosition = Position.Bottom,
label: _label,
connectable = true,
isValidSourcePos,
isConnectable = true,
data,
}) {
const label = data.label || _label
const label = data.label

return [
typeof label !== 'string' && label ? h(label) : h('div', { innerHTML: label }),
h(Handle as Component, { type: 'source', position: sourcePosition, connectable, isValidConnection: isValidSourcePos }),
h(Handle as Component, { type: 'source', position: sourcePosition, isConnectable }),
]
}

InputNode.props = ['sourcePosition', 'label', 'isValidSourcePos', 'connectable', 'data']
InputNode.props = ['sourcePosition', 'isConnectable', 'data']
InputNode.inheritAttrs = false
InputNode.compatConfig = { MODE: 3 }

Expand Down
107 changes: 48 additions & 59 deletions packages/core/src/components/Nodes/NodeWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const NodeWrapper = defineComponent({

const isFocusable = toRef(() => (typeof node.focusable === 'undefined' ? nodesFocusable.value : node.focusable))

const isInit = toRef(() => !!node.dimensions.width && !!node.dimensions.height)
const isInit = toRef(() => !!node.measured.width && !!node.measured.height)

const nodeCmp = computed(() => {
const name = node.type || 'default'
Expand All @@ -92,7 +92,7 @@ const NodeWrapper = defineComponent({
return slot
}

let nodeType = node.template || getNodeTypes.value[name]
let nodeType = getNodeTypes.value[name]

if (typeof nodeType === 'string') {
if (instance) {
Expand All @@ -112,7 +112,7 @@ const NodeWrapper = defineComponent({
return false
})

const { emit, on } = useNodeHooks(node, emits)
const { emit } = useNodeHooks(node, emits)

const dragging = useDrag({
id: props.id,
Expand All @@ -134,26 +134,7 @@ const NodeWrapper = defineComponent({
},
})

const getClass = computed(() => (node.class instanceof Function ? node.class(node) : node.class))

const getStyle = computed(() => {
const styles = (node.style instanceof Function ? node.style(node) : node.style) || {}

const width = node.width instanceof Function ? node.width(node) : node.width
const height = node.height instanceof Function ? node.height(node) : node.height

if (width) {
styles.width = typeof width === 'string' ? width : `${width}px`
}

if (height) {
styles.height = typeof height === 'string' ? height : `${height}px`
}

return styles
})

const zIndex = toRef(() => Number(node.zIndex ?? getStyle.value.zIndex ?? 0))
const zIndex = toRef(() => Number(node.zIndex ?? node.style?.zIndex ?? 0))

onUpdateNodeInternals((updateIds) => {
// when no ids are passed, update all nodes
Expand Down Expand Up @@ -191,27 +172,38 @@ const NodeWrapper = defineComponent({
[
() => node.position.x,
() => node.position.y,
() => parentNode.value?.computedPosition.x,
() => parentNode.value?.computedPosition.y,
() => parentNode.value?.computedPosition.z,
() => parentNode.value?.internals.positionAbsolute.x,
() => parentNode.value?.internals.positionAbsolute.y,
() => parentNode.value?.internals.z,
zIndex,
() => node.selected,
() => node.dimensions.height,
() => node.dimensions.width,
() => parentNode.value?.dimensions.height,
() => parentNode.value?.dimensions.width,
() => node.measured.height,
() => node.measured.width,
() => parentNode.value?.measured.height,
() => parentNode.value?.measured.width,
],
([newX, newY, parentX, parentY, parentZ, nodeZIndex]) => {
const xyzPos = {
x: newX,
y: newY,
z: nodeZIndex + (elevateNodesOnSelect.value ? (node.selected ? 1000 : 0) : 0),
}
const nextZ = nodeZIndex + (elevateNodesOnSelect.value ? (node.selected ? 1000 : 0) : 0)

if (typeof parentX !== 'undefined' && typeof parentY !== 'undefined') {
node.computedPosition = getXYZPos({ x: parentX, y: parentY, z: parentZ! }, xyzPos)
const {
x: absoluteX,
y: absoluteY,
z,
} = getXYZPos(
{ x: parentX, y: parentY, z: parentZ! },
{
x: newX,
y: newY,
z: nextZ,
},
)

node.internals.positionAbsolute = { x: absoluteX, y: absoluteY }
node.internals.z = z
} else {
node.computedPosition = xyzPos
node.internals.positionAbsolute = { x: newX, y: newY }
node.internals.z = nextZ
}
},
{ flush: 'post', immediate: true },
Expand Down Expand Up @@ -258,17 +250,18 @@ const NodeWrapper = defineComponent({
draggable: isDraggable.value,
selected: node.selected,
selectable: isSelectable.value,
parent: node.isParent,
},
getClass.value,
node.class,
],
'style': [
{
visibility: isInit.value ? 'visible' : 'hidden',
zIndex: node.internals.z ?? zIndex.value,
transform: `translate(${node.internals.positionAbsolute.x}px,${node.internals.positionAbsolute.y}px)`,
pointerEvents: isSelectable.value || isDraggable.value ? 'all' : 'none',
},
node.style,
],
'style': {
visibility: isInit.value ? 'visible' : 'hidden',
zIndex: node.computedPosition.z ?? zIndex.value,
transform: `translate(${node.computedPosition.x}px,${node.computedPosition.y}px)`,
pointerEvents: isSelectable.value || isDraggable.value ? 'all' : 'none',
...getStyle.value,
},
'tabIndex': isFocusable.value ? 0 : undefined,
'role': isFocusable.value ? 'button' : undefined,
'aria-describedby': disableKeyboardA11y.value ? undefined : `${ARIA_NODE_DESC_KEY}-${vueFlowId}`,
Expand All @@ -286,21 +279,17 @@ const NodeWrapper = defineComponent({
id: node.id,
type: node.type,
data: node.data,
events: { ...node.events, ...on },
selected: node.selected,
resizing: node.resizing,
dragging: dragging.value,
connectable: isConnectable.value,
position: node.computedPosition,
dimensions: node.dimensions,
isValidTargetPos: node.isValidTargetPos,
isValidSourcePos: node.isValidSourcePos,
parent: node.parentNode,
parentNodeId: node.parentNode,
zIndex: node.computedPosition.z ?? zIndex.value,
positionAbsoluteX: node.internals.positionAbsolute.x,
positionAbsoluteY: node.internals.positionAbsolute.y,
width: node.measured.width,
height: node.measured.height,
parentId: node.parentId,
zIndex: node.internals.z ?? zIndex.value,
targetPosition: node.targetPosition,
sourcePosition: node.sourcePosition,
label: node.label,
dragHandle: node.dragHandle,
onUpdateNodeInternals: updateInternals,
}),
Expand All @@ -309,7 +298,7 @@ const NodeWrapper = defineComponent({
}
/** this re-calculates the current position, necessary for clamping by a node's extent */
function clampPosition() {
const nextPos = node.computedPosition
const nextPos = node.internals.positionAbsolute

if (snapToGrid.value) {
nextPos.x = snapGrid.value[0] * Math.round(nextPos.x / snapGrid.value[0])
Expand All @@ -319,8 +308,8 @@ const NodeWrapper = defineComponent({
const { computedPosition, position } = calcNextPosition(node, nextPos, emits.error, nodeExtent.value, parentNode.value)

// only overwrite positions if there are changes when clamping
if (node.computedPosition.x !== computedPosition.x || node.computedPosition.y !== computedPosition.y) {
node.computedPosition = { ...node.computedPosition, ...computedPosition }
if (nextPos.x !== computedPosition.x || nextPos.y !== computedPosition.y) {
node.internals.positionAbsolute = { ...nextPos, ...computedPosition }
}

if (node.position.x !== position.x || node.position.y !== position.y) {
Expand Down
14 changes: 6 additions & 8 deletions packages/core/src/components/Nodes/OutputNode.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import type { Component, FunctionalComponent } from 'vue'
import { h } from 'vue'
import Handle from '../Handle/Handle.vue'
import type { NodeProps } from '../../types'
import type { Node, NodeProps } from '../../types'
import { Position } from '../../types'

const OutputNode: FunctionalComponent<NodeProps<{ label: any }>> = function ({
const OutputNode: FunctionalComponent<NodeProps<Node<{ label: any }, 'output'>>> = function ({
targetPosition = Position.Top,
label: _label,
connectable = true,
isValidTargetPos,
isConnectable = true,
data,
}) {
const label = data.label || _label
const label = data.label

return [
h(Handle as Component, { type: 'target', position: targetPosition, connectable, isValidConnection: isValidTargetPos }),
h(Handle as Component, { type: 'target', position: targetPosition, isConnectable }),
typeof label !== 'string' && label ? h(label) : h('div', { innerHTML: label }),
]
}

OutputNode.props = ['targetPosition', 'label', 'isValidTargetPos', 'connectable', 'data']
OutputNode.props = ['targetPosition', 'isConnectable', 'data']
OutputNode.inheritAttrs = false
OutputNode.compatConfig = { MODE: 3 }

Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/composables/useNode.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { computed, inject, ref } from 'vue'
import type { NodeBase } from '@xyflow/system'
import { ErrorCode, VueFlowError, getConnectedEdges } from '../utils'
import { NodeRef } from '../context'
import type { GraphNode, Node } from '../types'
import { useVueFlow } from './useVueFlow'
import { useNodeId } from './useNodeId'

Expand All @@ -16,13 +16,13 @@ import { useNodeId } from './useNodeId'
* @param id - The id of the node to access
* @returns the node id, the node, the node dom element, it's parent and connected edges
*/
export function useNode<NodeType extends NodeBase = NodeBase>(id?: string) {
export function useNode<NodeType extends Node = Node>(id?: string) {
const nodeId = id ?? useNodeId() ?? ''
const nodeEl = inject(NodeRef, ref(null))

const { findNode, edges, emits } = useVueFlow()
const { getNode, edges, emits } = useVueFlow()

const node = findNode<NodeType>(nodeId)!
const node = getNode(nodeId) as GraphNode<NodeType>

if (!node) {
emits.error(new VueFlowError(ErrorCode.NODE_NOT_FOUND, nodeId))
Expand All @@ -32,7 +32,7 @@ export function useNode<NodeType extends NodeBase = NodeBase>(id?: string) {
id: nodeId,
nodeEl,
node,
parentNode: computed(() => findNode(node.parentId)),
parentNode: computed(() => getNode(node.parentId)),
connectedEdges: computed(() => getConnectedEdges([node], edges.value)),
}
}
2 changes: 2 additions & 0 deletions packages/core/src/types/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface Node<NodeData extends ElementData = ElementData, NodeType exten
extends Omit<NodeBase<NodeData, NodeType>, 'connectable' | 'extent' | 'origin'> {
/** Disable/enable connecting node */
connectable?: HandleConnectable
/** Disable/enable focusing node */
focusable?: boolean
/** define node extent, i.e. area in which node can be moved */
extent?: CoordinateExtent | CoordinateExtentRange | 'parent'
/** Additional class names, can be a string or a callback returning a string (receives current flow element) */
Expand Down

0 comments on commit 02efdff

Please sign in to comment.