update!: graphnode and node typing
* graphnode is a node containing internal Vue Flow data * move util files to util directory * move flow actions type into store file * rename panel type file to zoom * rename types file to flow * Rename Node to NodeWrapper * Rename Edge to EdgeWrapper Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { rectToBox } from './graph'
|
||||
import { Edge, EdgePositions, ElementId, GraphNode, HandleElement, Position, Transform, XYPosition } from '~/types'
|
||||
|
||||
export function getHandlePosition(position: Position, node: GraphNode, handle: any | null = null): XYPosition {
|
||||
const x = (handle?.x || 0) + node.__vf.position.x
|
||||
const y = (handle?.y || 0) + node.__vf.position.y
|
||||
const width = handle?.width || node.__vf.width
|
||||
const height = handle?.height || node.__vf.height
|
||||
|
||||
switch (position) {
|
||||
case Position.Top:
|
||||
return {
|
||||
x: x + width / 2,
|
||||
y,
|
||||
}
|
||||
case Position.Right:
|
||||
return {
|
||||
x: x + width,
|
||||
y: y + height / 2,
|
||||
}
|
||||
case Position.Bottom:
|
||||
return {
|
||||
x: x + width / 2,
|
||||
y: y + height,
|
||||
}
|
||||
case Position.Left:
|
||||
return {
|
||||
x,
|
||||
y: y + height / 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | undefined {
|
||||
if (!bounds) return undefined
|
||||
|
||||
// there is no handleId when there are no multiple handles/ handles with ids
|
||||
// so we just pick the first one
|
||||
let handle
|
||||
if (bounds.length === 1 || !handleId) {
|
||||
handle = bounds[0]
|
||||
} else if (handleId) {
|
||||
handle = bounds.find((d) => d.id === handleId)
|
||||
}
|
||||
|
||||
return typeof handle === 'undefined' ? undefined : handle
|
||||
}
|
||||
|
||||
export const getEdgePositions = (
|
||||
sourceNode: GraphNode,
|
||||
sourceHandle: HandleElement | unknown,
|
||||
sourcePosition: Position,
|
||||
targetNode: GraphNode,
|
||||
targetHandle: HandleElement | unknown,
|
||||
targetPosition: Position,
|
||||
): EdgePositions => {
|
||||
const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle)
|
||||
const targetHandlePos = getHandlePosition(targetPosition, targetNode, targetHandle)
|
||||
|
||||
return {
|
||||
sourceX: sourceHandlePos.x,
|
||||
sourceY: sourceHandlePos.y,
|
||||
targetX: targetHandlePos.x,
|
||||
targetY: targetHandlePos.y,
|
||||
}
|
||||
}
|
||||
|
||||
interface IsEdgeVisibleParams {
|
||||
sourcePos: XYPosition
|
||||
targetPos: XYPosition
|
||||
width: number
|
||||
height: number
|
||||
transform: Transform
|
||||
}
|
||||
|
||||
export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }: IsEdgeVisibleParams): boolean {
|
||||
const edgeBox = {
|
||||
x: Math.min(sourcePos.x, targetPos.x),
|
||||
y: Math.min(sourcePos.y, targetPos.y),
|
||||
x2: Math.max(sourcePos.x, targetPos.x),
|
||||
y2: Math.max(sourcePos.y, targetPos.y),
|
||||
}
|
||||
|
||||
if (edgeBox.x === edgeBox.x2) {
|
||||
edgeBox.x2 += 1
|
||||
}
|
||||
|
||||
if (edgeBox.y === edgeBox.y2) {
|
||||
edgeBox.y2 += 1
|
||||
}
|
||||
|
||||
const viewBox = rectToBox({
|
||||
x: (0 - transform[0]) / transform[2],
|
||||
y: (0 - transform[1]) / transform[2],
|
||||
width: width / transform[2],
|
||||
height: height / transform[2],
|
||||
})
|
||||
|
||||
const xOverlap = Math.max(0, Math.min(viewBox.x2, edgeBox.x2) - Math.max(viewBox.x, edgeBox.x))
|
||||
const yOverlap = Math.max(0, Math.min(viewBox.y2, edgeBox.y2) - Math.max(viewBox.y, edgeBox.y))
|
||||
const overlappingArea = Math.ceil(xOverlap * yOverlap)
|
||||
|
||||
return overlappingArea > 0
|
||||
}
|
||||
|
||||
type SourceTargetNode = {
|
||||
sourceNode: GraphNode
|
||||
targetNode: GraphNode
|
||||
}
|
||||
|
||||
export const getSourceTargetNodes = (edge: Edge, nodes: GraphNode[]): SourceTargetNode => {
|
||||
return nodes.reduce(
|
||||
(res, node) => {
|
||||
if (node.id === edge.source) {
|
||||
res.sourceNode = node
|
||||
}
|
||||
if (node.id === edge.target) {
|
||||
res.targetNode = node
|
||||
}
|
||||
return res
|
||||
},
|
||||
{ sourceNode: null, targetNode: null } as any,
|
||||
)
|
||||
}
|
||||
+42
-45
@@ -12,12 +12,20 @@ import {
|
||||
NodeExtent,
|
||||
Dimensions,
|
||||
FlowStore,
|
||||
GraphNode,
|
||||
FlowElements,
|
||||
FlowElement,
|
||||
} from '~/types'
|
||||
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 as HTMLElement
|
||||
return ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(target.nodeName) || target.hasAttribute('contentEditable')
|
||||
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 => ({
|
||||
@@ -40,40 +48,30 @@ export const getHostForElement = (element: HTMLElement): Document => {
|
||||
else return window.document
|
||||
}
|
||||
|
||||
export const isEdge = (element: Node | Connection | Edge): element is Edge =>
|
||||
export const isEdge = (element: Node | FlowElement | Connection): element is Edge =>
|
||||
'id' in element && 'source' in element && 'target' in element
|
||||
|
||||
export const isNode = (element: Node | Connection | Edge): element is Node =>
|
||||
export const isNode = (element: Node | FlowElement | Connection): element is Node =>
|
||||
'id' in element && !('source' in element) && !('target' in element)
|
||||
|
||||
export const getOutgoers = (node: Node, elements: Elements): Node[] => {
|
||||
if (!isNode(node)) {
|
||||
return []
|
||||
}
|
||||
export const isGraphNode = (element: Node | FlowElement | Connection): element is GraphNode =>
|
||||
isNode(element) && '__vf' in element
|
||||
|
||||
const outgoerIds = elements.filter((e) => isEdge(e) && e.source === node.id).map((e) => (e as Edge).target)
|
||||
return elements.filter((e) => outgoerIds.includes(e.id)) as Node[]
|
||||
const getConnectedElements = (node: GraphNode, elements: Elements, dir: 'source' | 'target') => {
|
||||
if (!isNode(node)) return []
|
||||
const ids = elements.filter((e) => isEdge(e) && e.source === node.id).map((e) => isEdge(e) && e[dir])
|
||||
return elements.filter((e) => ids.includes(e.id))
|
||||
}
|
||||
export const getOutgoers = (node: GraphNode, elements: Elements) => getConnectedElements(node, elements, 'target')
|
||||
|
||||
export const getIncomers = (node: Node, elements: Elements): Node[] => {
|
||||
if (!isNode(node)) {
|
||||
return []
|
||||
}
|
||||
export const getIncomers = (node: GraphNode, elements: Elements) => getConnectedElements(node, elements, 'source')
|
||||
|
||||
const incomersIds = elements.filter((e) => isEdge(e) && e.target === node.id).map((e) => (e as Edge).source)
|
||||
return elements.filter((e) => incomersIds.includes(e.id)) as Node[]
|
||||
}
|
||||
|
||||
export const removeElements = (elementsToRemove: Elements, elements: Elements): Elements => {
|
||||
export const removeElements = (elementsToRemove: Elements, elements: Elements) => {
|
||||
const nodeIdsToRemove = elementsToRemove.map((n) => n.id)
|
||||
|
||||
return elements.filter((element) => {
|
||||
const edgeElement = element as Edge
|
||||
return !(
|
||||
nodeIdsToRemove.includes(element.id) ||
|
||||
nodeIdsToRemove.includes(edgeElement.target) ||
|
||||
nodeIdsToRemove.includes(edgeElement.source)
|
||||
)
|
||||
const { target, source } = isEdge(element) ? element : { target: '', source: '' }
|
||||
return !(nodeIdsToRemove.includes(element.id) || nodeIdsToRemove.includes(target) || nodeIdsToRemove.includes(source))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -91,13 +89,13 @@ const connectionExists = (edge: Edge, elements: Elements) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elements => {
|
||||
export const addEdge = (edgeParams: Edge | Connection, elements: Elements) => {
|
||||
if (!edgeParams.source || !edgeParams.target) {
|
||||
console.log("Can't create edge. An edge needs a source and a target.")
|
||||
return elements
|
||||
}
|
||||
|
||||
let edge: Edge
|
||||
let edge
|
||||
if (isEdge(edgeParams)) {
|
||||
edge = { ...edgeParams }
|
||||
} else {
|
||||
@@ -114,13 +112,13 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elem
|
||||
return elements.concat(edge)
|
||||
}
|
||||
|
||||
export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: Elements): Elements => {
|
||||
export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: Elements) => {
|
||||
if (!newConnection.source || !newConnection.target) {
|
||||
console.warn("Can't create new edge. An edge needs a source and a target.")
|
||||
return elements
|
||||
}
|
||||
|
||||
const foundEdge = elements.find((e) => isEdge(e) && e.id === oldEdge.id) as Edge
|
||||
const foundEdge = elements.find((e) => isEdge(e) && e.id === oldEdge.id)
|
||||
|
||||
if (!foundEdge) {
|
||||
console.warn(`The old edge with id=${oldEdge.id} does not exist.`)
|
||||
@@ -128,14 +126,14 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: E
|
||||
}
|
||||
|
||||
// Remove old edge and create the new edge with parameters of old edge.
|
||||
const edge = {
|
||||
const edge: Edge = {
|
||||
...oldEdge,
|
||||
id: getEdgeId(newConnection),
|
||||
source: newConnection.source,
|
||||
target: newConnection.target,
|
||||
sourceHandle: newConnection.sourceHandle,
|
||||
targetHandle: newConnection.targetHandle,
|
||||
} as Edge
|
||||
}
|
||||
|
||||
return elements.filter((e) => e.id !== oldEdge.id).concat(edge)
|
||||
}
|
||||
@@ -145,7 +143,7 @@ export const pointToRendererPoint = (
|
||||
[tx, ty, tScale]: Transform,
|
||||
snapToGrid: boolean,
|
||||
[snapX, snapY]: [number, number],
|
||||
): XYPosition => {
|
||||
) => {
|
||||
const position: XYPosition = {
|
||||
x: (x - tx) / tScale,
|
||||
y: (y - ty) / tScale,
|
||||
@@ -161,12 +159,10 @@ export const pointToRendererPoint = (
|
||||
return position
|
||||
}
|
||||
|
||||
export const onLoadProject =
|
||||
(currentStore: FlowStore) =>
|
||||
(position: XYPosition): XYPosition =>
|
||||
pointToRendererPoint(position, currentStore.transform, currentStore.snapToGrid, currentStore.snapGrid)
|
||||
export const onLoadProject = (currentStore: FlowStore) => (position: XYPosition) =>
|
||||
pointToRendererPoint(position, currentStore.transform, currentStore.snapToGrid, currentStore.snapGrid)
|
||||
|
||||
export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => ({
|
||||
export const parseNode = (node: Node, nodeExtent: NodeExtent): GraphNode => ({
|
||||
...node,
|
||||
id: node.id.toString(),
|
||||
type: node.type || 'default',
|
||||
@@ -174,7 +170,10 @@ export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => ({
|
||||
position: clampPosition(node.position, nodeExtent),
|
||||
width: 0,
|
||||
height: 0,
|
||||
handleBounds: {},
|
||||
handleBounds: {
|
||||
source: null,
|
||||
target: null,
|
||||
},
|
||||
isDragging: false,
|
||||
},
|
||||
})
|
||||
@@ -210,10 +209,9 @@ export const boxToRect = ({ x, y, x2, y2 }: Box): Rect => ({
|
||||
height: y2 - y,
|
||||
})
|
||||
|
||||
export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
|
||||
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)))
|
||||
export const getBoundsofRects = (rect1: Rect, rect2: Rect) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)))
|
||||
|
||||
export const getRectOfNodes = (nodes: Node[]): Rect => {
|
||||
export const getRectOfNodes = (nodes: GraphNode[]) => {
|
||||
const box = nodes.reduce(
|
||||
(currBox, { __vf: { position = { x: 0, y: 0 }, width = 0, height = 0 } = {} }) =>
|
||||
getBoundsOfBoxes(
|
||||
@@ -235,7 +233,7 @@ export const graphPosToZoomedPos = ({ x, y }: XYPosition, [tx, ty, tScale]: Tran
|
||||
y: y * tScale + ty,
|
||||
})
|
||||
|
||||
export const getNodesInside = (nodes: Node[], rect: Rect, [tx, ty, tScale]: Transform = [0, 0, 1], partially = false): Node[] => {
|
||||
export const getNodesInside = (nodes: GraphNode[], rect: Rect, [tx, ty, tScale]: Transform = [0, 0, 1], partially = false) => {
|
||||
const rBox = rectToBox({
|
||||
x: (rect.x - tx) / tScale,
|
||||
y: (rect.y - ty) / tScale,
|
||||
@@ -266,13 +264,12 @@ export const getNodesInside = (nodes: Node[], rect: Rect, [tx, ty, tScale]: Tran
|
||||
})
|
||||
}
|
||||
|
||||
export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
||||
export const getConnectedEdges = (nodes: GraphNode[], edges: Edge[]) => {
|
||||
const nodeIds = nodes.map((node) => node.id)
|
||||
|
||||
return edges.filter((edge) => nodeIds.includes(edge.source) || nodeIds.includes(edge.target))
|
||||
}
|
||||
|
||||
export const onLoadGetElements = (currentStore: FlowStore) => (): Elements => currentStore.elements
|
||||
export const onLoadGetElements = (currentStore: FlowStore) => (): FlowElements => currentStore.elements
|
||||
|
||||
export const onLoadToObject = (currentStore: FlowStore) => (): FlowExportObject => {
|
||||
// we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export * from './edge'
|
||||
export * from './graph'
|
||||
export * from './node'
|
||||
export * from './store'
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { HandleElement, Position } from '~/types'
|
||||
import { getDimensions } from '~/utils/graph'
|
||||
|
||||
export const getHandleBoundsByHandleType = (
|
||||
selector: string,
|
||||
nodeElement: HTMLDivElement,
|
||||
parentBounds: ClientRect | DOMRect,
|
||||
k: number,
|
||||
): HandleElement[] | null => {
|
||||
const handles = nodeElement.querySelectorAll(selector)
|
||||
|
||||
if (!handles || !handles.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const handlesArray = Array.from(handles) as HTMLDivElement[]
|
||||
|
||||
return handlesArray.map((handle): HandleElement => {
|
||||
const bounds = handle.getBoundingClientRect()
|
||||
const dimensions = getDimensions(handle)
|
||||
const handleId = handle.getAttribute('data-handleid')
|
||||
const handlePosition = handle.getAttribute('data-handlepos') as Position
|
||||
|
||||
return {
|
||||
id: handleId,
|
||||
position: handlePosition,
|
||||
x: (bounds.left - parentBounds.left) / k,
|
||||
y: (bounds.top - parentBounds.top) / k,
|
||||
...dimensions,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const getHandleBounds = (nodeElement: HTMLDivElement, scale: number) => {
|
||||
const bounds = nodeElement.getBoundingClientRect()
|
||||
|
||||
return {
|
||||
source: getHandleBoundsByHandleType('.source', nodeElement, bounds, scale),
|
||||
target: getHandleBoundsByHandleType('.target', nodeElement, bounds, scale),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
import { Component } from 'vue'
|
||||
import { isEdge, isNode, parseEdge, parseNode } from './graph'
|
||||
import {
|
||||
ConnectionMode,
|
||||
Edge,
|
||||
EdgeProps,
|
||||
Elements,
|
||||
FlowState,
|
||||
NextElements,
|
||||
NodeExtent,
|
||||
GraphNode,
|
||||
NodeProps,
|
||||
PanOnScrollMode,
|
||||
} from '~/types'
|
||||
import { DefaultNode, InputNode, OutputNode, BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components'
|
||||
import { createHooks } from '~/composables'
|
||||
|
||||
export const defaultNodeTypes: Record<string, Component<NodeProps>> = {
|
||||
input: InputNode,
|
||||
default: DefaultNode,
|
||||
output: OutputNode,
|
||||
}
|
||||
|
||||
export const defaultEdgeTypes: Record<string, Component<EdgeProps>> = {
|
||||
default: BezierEdge,
|
||||
straight: StraightEdge,
|
||||
step: StepEdge,
|
||||
smoothstep: SmoothStepEdge,
|
||||
}
|
||||
|
||||
export const initialState = (): FlowState => ({
|
||||
dimensions: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
transform: [0, 0, 1],
|
||||
elements: [],
|
||||
nodes: [],
|
||||
edges: [],
|
||||
selectedElements: undefined,
|
||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||
|
||||
d3Zoom: undefined,
|
||||
d3Selection: undefined,
|
||||
d3ZoomHandler: undefined,
|
||||
minZoom: 0.5,
|
||||
maxZoom: 2,
|
||||
translateExtent: [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
|
||||
nodeExtent: [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
zoomOnScroll: true,
|
||||
zoomOnPinch: true,
|
||||
zoomOnDoubleClick: true,
|
||||
panOnScroll: false,
|
||||
panOnScrollSpeed: 0.5,
|
||||
panOnScrollMode: PanOnScrollMode.Free,
|
||||
paneMoveable: true,
|
||||
edgeUpdaterRadius: 10,
|
||||
|
||||
nodesSelectionActive: false,
|
||||
selectionActive: false,
|
||||
|
||||
userSelectionRect: {
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
draw: false,
|
||||
},
|
||||
|
||||
arrowHeadColor: '#b1b1b7',
|
||||
connectionNodeId: undefined,
|
||||
connectionHandleId: undefined,
|
||||
connectionHandleType: 'source',
|
||||
connectionPosition: { x: NaN, y: NaN },
|
||||
connectionMode: ConnectionMode.Loose,
|
||||
|
||||
snapGrid: [15, 15],
|
||||
snapToGrid: false,
|
||||
|
||||
nodesDraggable: true,
|
||||
nodesConnectable: true,
|
||||
elementsSelectable: true,
|
||||
|
||||
multiSelectionActive: false,
|
||||
|
||||
isReady: false,
|
||||
hooks: createHooks(),
|
||||
loading: false,
|
||||
|
||||
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
||||
})
|
||||
|
||||
export const parseElements = async (elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent) =>
|
||||
new Promise<NextElements>((resolve) => {
|
||||
const nextElements: NextElements = {
|
||||
nextNodes: [],
|
||||
nextEdges: [],
|
||||
}
|
||||
for (const element of elements) {
|
||||
if (isNode(element)) {
|
||||
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
|
||||
|
||||
if (storeNode) {
|
||||
const updatedNode: GraphNode = {
|
||||
...storeNode,
|
||||
...element,
|
||||
}
|
||||
if (!updatedNode.__vf) updatedNode.__vf = {} as any
|
||||
|
||||
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
||||
updatedNode.__vf!.position = element.position
|
||||
}
|
||||
|
||||
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
||||
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
||||
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
||||
updatedNode.__vf!.width = 0
|
||||
}
|
||||
|
||||
nextElements.nextNodes.push(updatedNode)
|
||||
} else {
|
||||
nextElements.nextNodes.push(parseNode(element, nodeExtent))
|
||||
}
|
||||
} else if (isEdge(element)) {
|
||||
const storeEdge = edges[edges.map((x) => x.id).indexOf(element.id)]
|
||||
|
||||
if (storeEdge) {
|
||||
nextElements.nextEdges.push({
|
||||
...storeEdge,
|
||||
...element,
|
||||
})
|
||||
} else {
|
||||
nextElements.nextEdges.push(parseEdge(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve(nextElements)
|
||||
})
|
||||
|
||||
const isObject = (val: any) => val !== null && typeof val === 'object'
|
||||
const isArray = Array.isArray
|
||||
|
||||
const smartUnref = (val: any) => {
|
||||
if (val !== null && !isRef(val) && typeof val === 'object') {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
return deepUnref(val)
|
||||
}
|
||||
|
||||
return unref(val)
|
||||
}
|
||||
|
||||
const unrefArray = (arr: any[]) => {
|
||||
const unreffed: any[] = []
|
||||
|
||||
arr.forEach((val) => {
|
||||
unreffed.push(smartUnref(val))
|
||||
})
|
||||
|
||||
return unreffed
|
||||
}
|
||||
|
||||
const unrefObject = (obj: Record<string, any>) => {
|
||||
const unreffed: Record<string, any> = {}
|
||||
|
||||
Object.keys(obj).forEach((key) => {
|
||||
unreffed[key] = smartUnref(obj[key])
|
||||
})
|
||||
|
||||
return unreffed
|
||||
}
|
||||
|
||||
export const deepUnref = (val: any) => {
|
||||
const checkedVal = isRef(val) ? unref(val) : val
|
||||
|
||||
if (!isObject(checkedVal)) {
|
||||
return checkedVal
|
||||
}
|
||||
|
||||
if (isArray(checkedVal)) {
|
||||
return unrefArray(checkedVal)
|
||||
}
|
||||
|
||||
return unrefObject(checkedVal)
|
||||
}
|
||||
Reference in New Issue
Block a user