dishui 0.0.59 → 0.0.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/components/pro/Flow/Flow.js +517 -543
  2. package/dist/components/pro/Flow/Flow.js.map +1 -1
  3. package/dist/components/pro/Flow/FlowCanvas.js +1092 -947
  4. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  5. package/dist/components/pro/Flow/context/FlowUIContext.d.ts +3 -0
  6. package/dist/components/pro/Flow/context/FlowUIContext.js +67 -64
  7. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  8. package/dist/components/pro/Flow/edges/EdgeRenderer.js +1 -1
  9. package/dist/components/pro/Flow/edges/edgePaths.js +170 -159
  10. package/dist/components/pro/Flow/edges/edgePaths.js.map +1 -1
  11. package/dist/components/pro/Flow/hooks/useDeleteSelection.d.ts +8 -0
  12. package/dist/components/pro/Flow/hooks/useDeleteSelection.js +43 -0
  13. package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -0
  14. package/dist/components/pro/Flow/hooks/useMindMap.js +19 -17
  15. package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
  16. package/dist/components/pro/Flow/lines/LineRenderer.js +1 -1
  17. package/dist/components/pro/Flow/nodes/NodeRenderer.d.ts +2 -0
  18. package/dist/components/pro/Flow/nodes/NodeRenderer.js +174 -145
  19. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  20. package/dist/components/pro/Flow/nodes/shapes.d.ts +20 -0
  21. package/dist/components/pro/Flow/nodes/shapes.js +438 -203
  22. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  23. package/dist/components/pro/Flow/nodes/svgIconTexture.d.ts +4 -0
  24. package/dist/components/pro/Flow/nodes/svgIconTexture.js.map +1 -1
  25. package/dist/components/pro/Flow/panels/FlowToolbar.d.ts +4 -1
  26. package/dist/components/pro/Flow/panels/FlowToolbar.js +106 -100
  27. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  28. package/dist/components/pro/Flow/panels/InspectorPanel.js +739 -476
  29. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  30. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +2 -0
  31. package/dist/components/pro/Flow/panels/toolbarIcons.js +30 -25
  32. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  33. package/dist/components/pro/Flow/types.d.ts +32 -0
  34. package/dist/components/pro/Flow/types.js.map +1 -1
  35. package/dist/dishui.css +1 -1
  36. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"edgePaths.js","names":[],"sources":["../../../../../src/components/pro/Flow/edges/edgePaths.ts"],"sourcesContent":["import type { FlowEdgeTypeName, FlowBezierControl, FlowEdge, FlowNode } from '../types';\nimport { getHandlePositions, type HandleDef } from '../nodes/NodeHandles';\n\n/** Outward unit normal for a handle side */\nconst SIDE_NORMAL: Record<string, { dx: number; dy: number }> = {\n top: { dx: 0, dy: -1 },\n bottom: { dx: 0, dy: 1 },\n left: { dx: -1, dy: 0 },\n right: { dx: 1, dy: 0 },\n};\n\n/** Perpendicular clearance (px) from node edge for step / smoothstep paths */\nconst EDGE_OFFSET = 20;\n/** Bezier control-arm length multiplier (fraction of inter-node distance, clamped) */\nconst BEZ_ARM_MIN = 30;\nconst BEZ_ARM_FRAC = 0.3;\n\nexport interface EdgeEndpoints {\n sx: number; sy: number;\n tx: number; ty: number;\n /** Outward unit-normal at source handle */\n snx: number; sny: number;\n /** Outward unit-normal at target handle */\n tnx: number; tny: number;\n}\n\nexport interface PathSegment {\n type: 'M' | 'L' | 'C' | 'Q';\n x: number; y: number;\n cp1x?: number; cp1y?: number;\n cp2x?: number; cp2y?: number;\n}\n\n/**\n * Build a path (array of segments) for the given edge type.\n * Returns segments that can be drawn with PixiJS Graphics.\n */\nexport function buildEdgePath(\n type: FlowEdgeTypeName,\n endpoints: EdgeEndpoints,\n waypoints?: Array<{ x: number; y: number }>,\n bezierControls?: Array<FlowBezierControl | null> | null,\n): PathSegment[] {\n const src = { x: endpoints.sx, y: endpoints.sy };\n const tgt = { x: endpoints.tx, y: endpoints.ty };\n const wps = waypoints ?? [];\n\n switch (type) {\n case 'straight':\n return buildStraightPath([src, ...wps, tgt]);\n\n case 'step':\n case 'smoothstep': {\n const radius = type === 'smoothstep' ? 8 : 0;\n return buildStepPathWithOffsets(src, tgt, wps, endpoints, radius);\n }\n\n case 'simplebezier':\n return buildBezierPath([src, ...wps, tgt], bezierControls, endpoints);\n\n default:\n return buildStraightPath([src, ...wps, tgt]);\n }\n}\n\nfunction buildStraightPath(points: Array<{ x: number; y: number }>): PathSegment[] {\n const segs: PathSegment[] = [{ type: 'M', x: points[0].x, y: points[0].y }];\n for (let i = 1; i < points.length; i++) {\n segs.push({ type: 'L', x: points[i].x, y: points[i].y });\n }\n return segs;\n}\n\n/**\n * Step path with perpendicular exit / entry offsets.\n *\n * Produces clean orthogonal \"elbow\" routing:\n * 1. source → exit stub (perpendicular to the source face)\n * 2. exit → waypoints → approach (orthogonal)\n * 3. approach stub → target (perpendicular into the target face)\n *\n * The middle routing picks the split axis from the two handle orientations so\n * opposing/aligned handles produce a single clean bend instead of an S/Z jog,\n * and collinear points are collapsed at the end.\n */\nfunction buildStepPathWithOffsets(\n src: { x: number; y: number },\n tgt: { x: number; y: number },\n waypoints: Array<{ x: number; y: number }>,\n ep: EdgeEndpoints,\n borderRadius: number,\n): PathSegment[] {\n const dist = Math.hypot(tgt.x - src.x, tgt.y - src.y);\n const offset = Math.min(EDGE_OFFSET, dist / 4);\n\n const exitPt = { x: src.x + ep.snx * offset, y: src.y + ep.sny * offset };\n const approPt = { x: tgt.x + ep.tnx * offset, y: tgt.y + ep.tny * offset };\n\n const srcVertical = Math.abs(ep.sny) > Math.abs(ep.snx);\n const tgtVertical = Math.abs(ep.tny) > Math.abs(ep.tnx);\n\n // Build the raw corner list (no rounding yet), then simplify + round.\n const corners: Array<{ x: number; y: number }> = [{ x: src.x, y: src.y }, exitPt];\n\n const mids = [exitPt, ...waypoints, approPt];\n for (let i = 0; i < mids.length - 1; i++) {\n const a = mids[i];\n const b = mids[i + 1];\n // Orientation of this leg: first leg follows source, last leg follows target.\n const vertical = i === 0 ? srcVertical : (i === mids.length - 2 ? tgtVertical : srcVertical);\n if (vertical) {\n // V-H-V: go vertically to the mid-Y, across, then down/up.\n const midY = (a.y + b.y) / 2;\n corners.push({ x: a.x, y: midY }, { x: b.x, y: midY });\n } else {\n // H-V-H: go horizontally to the mid-X, vertically, then across.\n const midX = (a.x + b.x) / 2;\n corners.push({ x: midX, y: a.y }, { x: midX, y: b.y });\n }\n corners.push({ x: b.x, y: b.y });\n }\n corners.push({ x: tgt.x, y: tgt.y });\n\n const simplified = simplifyOrthogonal(corners);\n return roundedOrthogonalPath(simplified, borderRadius);\n}\n\n/**\n * Remove collinear / duplicate points from an orthogonal polyline so we don't\n * emit degenerate zero-length jogs (a common source of \"unnatural\" bends).\n */\nfunction simplifyOrthogonal(pts: Array<{ x: number; y: number }>): Array<{ x: number; y: number }> {\n const out: Array<{ x: number; y: number }> = [];\n for (const p of pts) {\n const last = out[out.length - 1];\n if (last && Math.abs(last.x - p.x) < 0.01 && Math.abs(last.y - p.y) < 0.01) continue;\n out.push({ x: p.x, y: p.y });\n }\n // Drop the middle of any 3 collinear points.\n const res: Array<{ x: number; y: number }> = [];\n for (let i = 0; i < out.length; i++) {\n const prev = res[res.length - 1];\n const cur = out[i];\n const next = out[i + 1];\n if (prev && next) {\n const collinearX = Math.abs(prev.x - cur.x) < 0.01 && Math.abs(cur.x - next.x) < 0.01;\n const collinearY = Math.abs(prev.y - cur.y) < 0.01 && Math.abs(cur.y - next.y) < 0.01;\n if (collinearX || collinearY) continue;\n }\n res.push(cur);\n }\n return res;\n}\n\n/**\n * Convert an orthogonal polyline into path segments, rounding each corner.\n */\nfunction roundedOrthogonalPath(\n pts: Array<{ x: number; y: number }>,\n borderRadius: number,\n): PathSegment[] {\n if (pts.length === 0) return [];\n const segs: PathSegment[] = [{ type: 'M', x: pts[0].x, y: pts[0].y }];\n if (pts.length === 1) return segs;\n if (borderRadius <= 0.5) {\n for (let i = 1; i < pts.length; i++) segs.push({ type: 'L', x: pts[i].x, y: pts[i].y });\n return segs;\n }\n for (let i = 1; i < pts.length - 1; i++) {\n const prev = pts[i - 1];\n const cur = pts[i];\n const next = pts[i + 1];\n const inLen = Math.hypot(cur.x - prev.x, cur.y - prev.y);\n const outLen = Math.hypot(next.x - cur.x, next.y - cur.y);\n const r = Math.min(borderRadius, inLen / 2, outLen / 2);\n if (r < 0.5) {\n segs.push({ type: 'L', x: cur.x, y: cur.y });\n continue;\n }\n const inDx = Math.sign(cur.x - prev.x);\n const inDy = Math.sign(cur.y - prev.y);\n const outDx = Math.sign(next.x - cur.x);\n const outDy = Math.sign(next.y - cur.y);\n segs.push({ type: 'L', x: cur.x - inDx * r, y: cur.y - inDy * r });\n segs.push({ type: 'Q', x: cur.x + outDx * r, y: cur.y + outDy * r, cp1x: cur.x, cp1y: cur.y });\n }\n const end = pts[pts.length - 1];\n segs.push({ type: 'L', x: end.x, y: end.y });\n return segs;\n}\n\n/**\n * Cubic bezier path between consecutive points.\n * Uses handle normals on the first / last segment for perpendicular exit/entry.\n */\nfunction buildBezierPath(\n points: Array<{ x: number; y: number }>,\n controls?: Array<FlowBezierControl | null> | null,\n ep?: EdgeEndpoints,\n): PathSegment[] {\n const segs: PathSegment[] = [{ type: 'M', x: points[0].x, y: points[0].y }];\n const lastIdx = points.length - 2;\n\n for (let i = 0; i <= lastIdx; i++) {\n const a = points[i];\n const b = points[i + 1];\n const ctrl = controls?.[i];\n\n if (ctrl) {\n segs.push({\n type: 'C', x: b.x, y: b.y,\n cp1x: ctrl.c1x, cp1y: ctrl.c1y,\n cp2x: ctrl.c2x, cp2y: ctrl.c2y,\n });\n } else {\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n const arm = Math.max(BEZ_ARM_MIN, dist * BEZ_ARM_FRAC);\n\n let c1x: number, c1y: number;\n if (i === 0 && ep) {\n c1x = a.x + ep.snx * arm;\n c1y = a.y + ep.sny * arm;\n } else {\n c1x = a.x + (b.x - a.x) * 0.4;\n c1y = a.y;\n }\n\n let c2x: number, c2y: number;\n if (i === lastIdx && ep) {\n c2x = b.x + ep.tnx * arm;\n c2y = b.y + ep.tny * arm;\n } else {\n c2x = b.x - (b.x - a.x) * 0.4;\n c2y = b.y;\n }\n\n segs.push({\n type: 'C', x: b.x, y: b.y,\n cp1x: c1x, cp1y: c1y,\n cp2x: c2x, cp2y: c2y,\n });\n }\n }\n return segs;\n}\n\n/**\n * Compute the center point of a path (for label placement).\n */\nexport function getPathCenter(segs: PathSegment[]): { x: number; y: number } {\n if (segs.length < 2) return { x: segs[0]?.x ?? 0, y: segs[0]?.y ?? 0 };\n const mid = Math.floor(segs.length / 2);\n const a = segs[mid - 1];\n const b = segs[mid];\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n\n/**\n * Get a point on a path at parameter t (0-1), approximate.\n */\nexport function getPointOnPath(segs: PathSegment[], t: number): { x: number; y: number } {\n if (segs.length < 2) return { x: segs[0]?.x ?? 0, y: segs[0]?.y ?? 0 };\n const totalSegs = segs.length - 1;\n const segIdx = Math.min(Math.floor(t * totalSegs), totalSegs - 1);\n const localT = (t * totalSegs) - segIdx;\n const a = segs[segIdx];\n const b = segs[segIdx + 1];\n return {\n x: a.x + (b.x - a.x) * localT,\n y: a.y + (b.y - a.y) * localT,\n };\n}\n\n/**\n * Resolve source/target anchor positions for an edge.\n * Uses stored handle IDs when available; falls back to closest-handle heuristic.\n */\n/**\n * Transform a handle's local-space position into world space,\n * accounting for the node's rotation (degrees, stored in data.rotation).\n */\nfunction handleToWorld(\n hx: number, hy: number,\n node: FlowNode,\n): { x: number; y: number } {\n const deg = node.data.rotation ?? 0;\n if (deg === 0) {\n return { x: node.position.x + hx, y: node.position.y + hy };\n }\n const rad = (deg * Math.PI) / 180;\n const cx = node.width / 2, cy = node.height / 2;\n const dx = hx - cx, dy = hy - cy;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n x: node.position.x + cx + dx * cos - dy * sin,\n y: node.position.y + cy + dx * sin + dy * cos,\n };\n}\n\n/**\n * Compute the outward unit-normal for a handle, accounting for node rotation.\n */\nfunction handleNormal(h: HandleDef | null, node: FlowNode): { nx: number; ny: number } {\n const base = SIDE_NORMAL[h?.side ?? 'right'] ?? SIDE_NORMAL.right;\n const deg = node.data.rotation ?? 0;\n if (deg === 0) return { nx: base.dx, ny: base.dy };\n const rad = (deg * Math.PI) / 180;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n nx: base.dx * cos - base.dy * sin,\n ny: base.dx * sin + base.dy * cos,\n };\n}\n\nexport function resolveEdgeEndpoints(\n edge: FlowEdge,\n nodeMap: Map<string, FlowNode>,\n): EdgeEndpoints | null {\n const sn = nodeMap.get(edge.source);\n const tn = nodeMap.get(edge.target);\n if (!sn || !tn) return null;\n\n const sHandles = getHandlePositions(sn.width, sn.height);\n const tHandles = getHandlePositions(tn.width, tn.height);\n\n let sx: number, sy: number, sH: HandleDef | null;\n if (edge.sourceHandle) {\n sH = sHandles.find(h => h.id === edge.sourceHandle) ?? null;\n const pos = handleToWorld(sH ? sH.x : sn.width / 2, sH ? sH.y : sn.height / 2, sn);\n sx = pos.x; sy = pos.y;\n } else {\n // Floating anchor: pick the side by direction, then slide the point along\n // that side to align with the target so aligned nodes connect with a\n // straight line instead of a forced mid-handle jog.\n const anchor = floatingAnchor(sn, tn);\n sx = anchor.x; sy = anchor.y; sH = anchor.handleLike;\n }\n\n let tx: number, ty: number, tH: HandleDef | null;\n if (edge.targetHandle) {\n tH = tHandles.find(h => h.id === edge.targetHandle) ?? null;\n const pos = handleToWorld(tH ? tH.x : tn.width / 2, tH ? tH.y : tn.height / 2, tn);\n tx = pos.x; ty = pos.y;\n } else {\n const anchor = floatingAnchor(tn, sn);\n tx = anchor.x; ty = anchor.y; tH = anchor.handleLike;\n }\n\n const sN = handleNormal(sH, sn);\n const tN = handleNormal(tH, tn);\n\n return { sx, sy, tx, ty, snx: sN.nx, sny: sN.ny, tnx: tN.nx, tny: tN.ny };\n}\n\n/**\n * Compute a floating connection anchor on `self` facing `other`.\n * Chooses the side by dominant direction, then slides the anchor along that\n * side to line up with the other node's center (clamped to the side extent).\n * Returns the world point plus a synthetic handle carrying only the `side`\n * (used for the outward normal).\n */\nfunction floatingAnchor(\n self: FlowNode,\n other: FlowNode,\n): { x: number; y: number; handleLike: HandleDef } {\n const sx = self.position.x, sy = self.position.y;\n const sw = self.width, sh = self.height;\n const sCx = sx + sw / 2, sCy = sy + sh / 2;\n const oCx = other.position.x + other.width / 2;\n const oCy = other.position.y + other.height / 2;\n\n const dx = oCx - sCx;\n const dy = oCy - sCy;\n // Inset so the anchor never sits exactly on a corner.\n const inset = Math.min(12, sw / 2 - 1, sh / 2 - 1);\n\n let side: HandleDef['side'];\n let x: number, y: number;\n if (Math.abs(dx) >= Math.abs(dy)) {\n side = dx >= 0 ? 'right' : 'left';\n x = side === 'right' ? sx + sw : sx;\n // Slide vertically to align with the other center, clamped to the side.\n y = Math.max(sy + inset, Math.min(sy + sh - inset, oCy));\n } else {\n side = dy >= 0 ? 'bottom' : 'top';\n y = side === 'bottom' ? sy + sh : sy;\n x = Math.max(sx + inset, Math.min(sx + sw - inset, oCx));\n }\n\n // Rotation: for rotated nodes fall back to the un-slid center of the side to\n // keep the normal math simple (rare case).\n const deg = self.data.rotation ?? 0;\n if (deg !== 0) {\n const cx = side === 'right' ? sx + sw : side === 'left' ? sx : sCx;\n const cy = side === 'bottom' ? sy + sh : side === 'top' ? sy : sCy;\n return { x: cx, y: cy, handleLike: { id: `float_${side}`, x: 0, y: 0, side } };\n }\n\n return { x, y, handleLike: { id: `float_${side}`, x: 0, y: 0, side } };\n}\n\n/**\n * Previously this pinned auto-resolved edges to a fixed middle handle at load\n * time, which forced ugly jogs between misaligned nodes. Edges without an\n * explicit handle are now left \"floating\" and resolved dynamically in\n * `resolveEdgeEndpoints` (see `floatingAnchor`), so this is a no-op that simply\n * preserves any user-pinned handles.\n */\nexport function normalizeEdgeHandles(\n edges: FlowEdge[],\n _nodeMap: Map<string, FlowNode>,\n): FlowEdge[] {\n const legacyOffsets = new Map([\n ['0.25', String(2 / 6)],\n ['0.5', String(3 / 6)],\n ['0.75', String(4 / 6)],\n ]);\n let changed = false;\n const migrate = (handle: string | undefined) => {\n if (!handle) return handle;\n const [side, offset] = handle.split('_');\n const nextOffset = legacyOffsets.get(offset);\n if (!nextOffset || !side) return handle;\n changed = true;\n return `${side}_${nextOffset}`;\n };\n const normalized = edges.map(edge => {\n const sourceHandle = migrate(edge.sourceHandle);\n const targetHandle = migrate(edge.targetHandle);\n return sourceHandle === edge.sourceHandle && targetHandle === edge.targetHandle\n ? edge\n : { ...edge, sourceHandle, targetHandle };\n });\n return changed ? normalized : edges;\n}\n\n/**\n * Convert PathSegments into a polyline by sampling curves.\n */\nexport function linearizeSegments(\n segs: PathSegment[],\n samplesPerCurve = 8,\n): Array<{ x: number; y: number }> {\n const pts: Array<{ x: number; y: number }> = [];\n let cx = 0, cy = 0;\n for (const seg of segs) {\n switch (seg.type) {\n case 'M':\n case 'L':\n cx = seg.x; cy = seg.y;\n pts.push({ x: cx, y: cy });\n break;\n case 'Q': {\n const cpx = seg.cp1x!, cpy = seg.cp1y!;\n for (let i = 1; i <= samplesPerCurve; i++) {\n const t = i / samplesPerCurve, mt = 1 - t;\n pts.push({\n x: mt * mt * cx + 2 * mt * t * cpx + t * t * seg.x,\n y: mt * mt * cy + 2 * mt * t * cpy + t * t * seg.y,\n });\n }\n cx = seg.x; cy = seg.y;\n break;\n }\n case 'C': {\n const c1x = seg.cp1x!, c1y = seg.cp1y!, c2x = seg.cp2x!, c2y = seg.cp2y!;\n for (let i = 1; i <= samplesPerCurve; i++) {\n const t = i / samplesPerCurve, mt = 1 - t;\n pts.push({\n x: mt ** 3 * cx + 3 * mt ** 2 * t * c1x + 3 * mt * t ** 2 * c2x + t ** 3 * seg.x,\n y: mt ** 3 * cy + 3 * mt ** 2 * t * c1y + 3 * mt * t ** 2 * c2y + t ** 3 * seg.y,\n });\n }\n cx = seg.x; cy = seg.y;\n break;\n }\n }\n }\n return pts;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"edgePaths.js","names":[],"sources":["../../../../../src/components/pro/Flow/edges/edgePaths.ts"],"sourcesContent":["import type { FlowEdgeTypeName, FlowBezierControl, FlowEdge, FlowNode } from '../types';\nimport { getHandlePositions, type HandleDef } from '../nodes/NodeHandles';\n\n/** Outward unit normal for a handle side */\nconst SIDE_NORMAL: Record<string, { dx: number; dy: number }> = {\n top: { dx: 0, dy: -1 },\n bottom: { dx: 0, dy: 1 },\n left: { dx: -1, dy: 0 },\n right: { dx: 1, dy: 0 },\n};\n\n/** Perpendicular clearance (px) from node edge for step / smoothstep paths */\nconst EDGE_OFFSET = 20;\n/** Bezier control-arm length multiplier (fraction of inter-node distance, clamped) */\nconst BEZ_ARM_MIN = 30;\nconst BEZ_ARM_FRAC = 0.3;\n\nexport interface EdgeEndpoints {\n sx: number; sy: number;\n tx: number; ty: number;\n /** Outward unit-normal at source handle */\n snx: number; sny: number;\n /** Outward unit-normal at target handle */\n tnx: number; tny: number;\n}\n\nexport interface PathSegment {\n type: 'M' | 'L' | 'C' | 'Q';\n x: number; y: number;\n cp1x?: number; cp1y?: number;\n cp2x?: number; cp2y?: number;\n}\n\n/**\n * Build a path (array of segments) for the given edge type.\n * Returns segments that can be drawn with PixiJS Graphics.\n */\nexport function buildEdgePath(\n type: FlowEdgeTypeName,\n endpoints: EdgeEndpoints,\n waypoints?: Array<{ x: number; y: number }>,\n bezierControls?: Array<FlowBezierControl | null> | null,\n): PathSegment[] {\n const src = { x: endpoints.sx, y: endpoints.sy };\n const tgt = { x: endpoints.tx, y: endpoints.ty };\n const wps = waypoints ?? [];\n\n switch (type) {\n case 'straight':\n return buildStraightPath([src, ...wps, tgt]);\n\n case 'step':\n case 'smoothstep': {\n const radius = type === 'smoothstep' ? 8 : 0;\n return buildStepPathWithOffsets(src, tgt, wps, endpoints, radius);\n }\n\n case 'simplebezier':\n return buildBezierPath([src, ...wps, tgt], bezierControls, endpoints);\n\n default:\n return buildStraightPath([src, ...wps, tgt]);\n }\n}\n\nfunction buildStraightPath(points: Array<{ x: number; y: number }>): PathSegment[] {\n const segs: PathSegment[] = [{ type: 'M', x: points[0].x, y: points[0].y }];\n for (let i = 1; i < points.length; i++) {\n segs.push({ type: 'L', x: points[i].x, y: points[i].y });\n }\n return segs;\n}\n\n/**\n * Step path with perpendicular exit / entry offsets.\n *\n * Produces clean orthogonal \"elbow\" routing:\n * 1. source → exit stub (perpendicular to the source face)\n * 2. exit → waypoints → approach (orthogonal)\n * 3. approach stub → target (perpendicular into the target face)\n *\n * The middle routing picks the split axis from the two handle orientations so\n * opposing/aligned handles produce a single clean bend instead of an S/Z jog,\n * and collinear points are collapsed at the end.\n */\nfunction buildStepPathWithOffsets(\n src: { x: number; y: number },\n tgt: { x: number; y: number },\n waypoints: Array<{ x: number; y: number }>,\n ep: EdgeEndpoints,\n borderRadius: number,\n): PathSegment[] {\n const dist = Math.hypot(tgt.x - src.x, tgt.y - src.y);\n const offset = Math.min(EDGE_OFFSET, dist / 4);\n\n const exitPt = { x: src.x + ep.snx * offset, y: src.y + ep.sny * offset };\n const approPt = { x: tgt.x + ep.tnx * offset, y: tgt.y + ep.tny * offset };\n\n const srcVertical = Math.abs(ep.sny) > Math.abs(ep.snx);\n const tgtVertical = Math.abs(ep.tny) > Math.abs(ep.tnx);\n\n // Build the raw corner list (no rounding yet), then simplify + round.\n const corners: Array<{ x: number; y: number }> = [{ x: src.x, y: src.y }, exitPt];\n\n const mids = [exitPt, ...waypoints, approPt];\n for (let i = 0; i < mids.length - 1; i++) {\n const a = mids[i];\n const b = mids[i + 1];\n // Orientation of this leg: first leg follows source, last leg follows target.\n const vertical = i === 0 ? srcVertical : (i === mids.length - 2 ? tgtVertical : srcVertical);\n if (vertical) {\n // V-H-V: go vertically to the mid-Y, across, then down/up.\n const midY = (a.y + b.y) / 2;\n corners.push({ x: a.x, y: midY }, { x: b.x, y: midY });\n } else {\n // H-V-H: go horizontally to the mid-X, vertically, then across.\n const midX = (a.x + b.x) / 2;\n corners.push({ x: midX, y: a.y }, { x: midX, y: b.y });\n }\n corners.push({ x: b.x, y: b.y });\n }\n corners.push({ x: tgt.x, y: tgt.y });\n\n const simplified = simplifyOrthogonal(corners);\n return roundedOrthogonalPath(simplified, borderRadius);\n}\n\n/**\n * Remove collinear / duplicate points from an orthogonal polyline so we don't\n * emit degenerate zero-length jogs (a common source of \"unnatural\" bends).\n */\nfunction simplifyOrthogonal(pts: Array<{ x: number; y: number }>): Array<{ x: number; y: number }> {\n const out: Array<{ x: number; y: number }> = [];\n for (const p of pts) {\n const last = out[out.length - 1];\n if (last && Math.abs(last.x - p.x) < 0.01 && Math.abs(last.y - p.y) < 0.01) continue;\n out.push({ x: p.x, y: p.y });\n }\n // Drop the middle of any 3 collinear points.\n const res: Array<{ x: number; y: number }> = [];\n for (let i = 0; i < out.length; i++) {\n const prev = res[res.length - 1];\n const cur = out[i];\n const next = out[i + 1];\n if (prev && next) {\n const collinearX = Math.abs(prev.x - cur.x) < 0.01 && Math.abs(cur.x - next.x) < 0.01;\n const collinearY = Math.abs(prev.y - cur.y) < 0.01 && Math.abs(cur.y - next.y) < 0.01;\n if (collinearX || collinearY) continue;\n }\n res.push(cur);\n }\n return res;\n}\n\n/**\n * Convert an orthogonal polyline into path segments, rounding each corner.\n */\nfunction roundedOrthogonalPath(\n pts: Array<{ x: number; y: number }>,\n borderRadius: number,\n): PathSegment[] {\n if (pts.length === 0) return [];\n const segs: PathSegment[] = [{ type: 'M', x: pts[0].x, y: pts[0].y }];\n if (pts.length === 1) return segs;\n if (borderRadius <= 0.5) {\n for (let i = 1; i < pts.length; i++) segs.push({ type: 'L', x: pts[i].x, y: pts[i].y });\n return segs;\n }\n for (let i = 1; i < pts.length - 1; i++) {\n const prev = pts[i - 1];\n const cur = pts[i];\n const next = pts[i + 1];\n const inLen = Math.hypot(cur.x - prev.x, cur.y - prev.y);\n const outLen = Math.hypot(next.x - cur.x, next.y - cur.y);\n const r = Math.min(borderRadius, inLen / 2, outLen / 2);\n if (r < 0.5) {\n segs.push({ type: 'L', x: cur.x, y: cur.y });\n continue;\n }\n const inDx = Math.sign(cur.x - prev.x);\n const inDy = Math.sign(cur.y - prev.y);\n const outDx = Math.sign(next.x - cur.x);\n const outDy = Math.sign(next.y - cur.y);\n segs.push({ type: 'L', x: cur.x - inDx * r, y: cur.y - inDy * r });\n segs.push({ type: 'Q', x: cur.x + outDx * r, y: cur.y + outDy * r, cp1x: cur.x, cp1y: cur.y });\n }\n const end = pts[pts.length - 1];\n segs.push({ type: 'L', x: end.x, y: end.y });\n return segs;\n}\n\n/**\n * Cubic bezier path between consecutive points.\n * Uses handle normals on the first / last segment for perpendicular exit/entry.\n */\nfunction buildBezierPath(\n points: Array<{ x: number; y: number }>,\n controls?: Array<FlowBezierControl | null> | null,\n ep?: EdgeEndpoints,\n): PathSegment[] {\n const segs: PathSegment[] = [{ type: 'M', x: points[0].x, y: points[0].y }];\n const lastIdx = points.length - 2;\n\n for (let i = 0; i <= lastIdx; i++) {\n const a = points[i];\n const b = points[i + 1];\n const ctrl = controls?.[i];\n\n if (ctrl) {\n segs.push({\n type: 'C', x: b.x, y: b.y,\n cp1x: ctrl.c1x, cp1y: ctrl.c1y,\n cp2x: ctrl.c2x, cp2y: ctrl.c2y,\n });\n } else {\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n const arm = Math.max(BEZ_ARM_MIN, dist * BEZ_ARM_FRAC);\n\n let c1x: number, c1y: number;\n if (i === 0 && ep) {\n c1x = a.x + ep.snx * arm;\n c1y = a.y + ep.sny * arm;\n } else {\n c1x = a.x + (b.x - a.x) * 0.4;\n c1y = a.y;\n }\n\n let c2x: number, c2y: number;\n if (i === lastIdx && ep) {\n c2x = b.x + ep.tnx * arm;\n c2y = b.y + ep.tny * arm;\n } else {\n c2x = b.x - (b.x - a.x) * 0.4;\n c2y = b.y;\n }\n\n segs.push({\n type: 'C', x: b.x, y: b.y,\n cp1x: c1x, cp1y: c1y,\n cp2x: c2x, cp2y: c2y,\n });\n }\n }\n return segs;\n}\n\n/**\n * Compute the center point of a path (for label placement).\n */\nexport function getPathCenter(segs: PathSegment[]): { x: number; y: number } {\n if (segs.length < 2) return { x: segs[0]?.x ?? 0, y: segs[0]?.y ?? 0 };\n const mid = Math.floor(segs.length / 2);\n const a = segs[mid - 1];\n const b = segs[mid];\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n\n/**\n * Get a point on a path at parameter t (0-1), approximate.\n */\nexport function getPointOnPath(segs: PathSegment[], t: number): { x: number; y: number } {\n if (segs.length < 2) return { x: segs[0]?.x ?? 0, y: segs[0]?.y ?? 0 };\n const totalSegs = segs.length - 1;\n const segIdx = Math.min(Math.floor(t * totalSegs), totalSegs - 1);\n const localT = (t * totalSegs) - segIdx;\n const a = segs[segIdx];\n const b = segs[segIdx + 1];\n return {\n x: a.x + (b.x - a.x) * localT,\n y: a.y + (b.y - a.y) * localT,\n };\n}\n\n/**\n * Resolve source/target anchor positions for an edge.\n * Uses stored handle IDs when available; falls back to closest-handle heuristic.\n */\n/**\n * Transform a handle's local-space position into world space,\n * accounting for the node's rotation (degrees, stored in data.rotation).\n */\nfunction handleToWorld(\n hx: number, hy: number,\n node: FlowNode,\n): { x: number; y: number } {\n const deg = node.data.rotation ?? 0;\n if (deg === 0) {\n return { x: node.position.x + hx, y: node.position.y + hy };\n }\n const rad = (deg * Math.PI) / 180;\n const cx = node.width / 2, cy = node.height / 2;\n const dx = hx - cx, dy = hy - cy;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n x: node.position.x + cx + dx * cos - dy * sin,\n y: node.position.y + cy + dx * sin + dy * cos,\n };\n}\n\n/**\n * Compute the outward unit-normal for a handle, accounting for node rotation.\n */\nfunction handleNormal(h: HandleDef | null, node: FlowNode): { nx: number; ny: number } {\n const base = SIDE_NORMAL[h?.side ?? 'right'] ?? SIDE_NORMAL.right;\n const deg = node.data.rotation ?? 0;\n if (deg === 0) return { nx: base.dx, ny: base.dy };\n const rad = (deg * Math.PI) / 180;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n nx: base.dx * cos - base.dy * sin,\n ny: base.dx * sin + base.dy * cos,\n };\n}\n\nexport function resolveEdgeEndpoints(\n edge: FlowEdge,\n nodeMap: Map<string, FlowNode>,\n): EdgeEndpoints | null {\n const sn = nodeMap.get(edge.source);\n const tn = nodeMap.get(edge.target);\n if (!sn || !tn) return null;\n\n const sHandles = getHandlePositions(sn.width, sn.height);\n const tHandles = getHandlePositions(tn.width, tn.height);\n\n let sx: number, sy: number, sH: HandleDef | null;\n if (edge.sourceHandle) {\n sH = sHandles.find(h => h.id === edge.sourceHandle) ?? null;\n const pos = handleToWorld(sH ? sH.x : sn.width / 2, sH ? sH.y : sn.height / 2, sn);\n sx = pos.x; sy = pos.y;\n } else {\n // Floating anchor: pick the side by direction, then slide the point along\n // that side to align with the target so aligned nodes connect with a\n // straight line instead of a forced mid-handle jog.\n const anchor = floatingAnchor(sn, tn);\n sx = anchor.x; sy = anchor.y; sH = anchor.handleLike;\n }\n\n let tx: number, ty: number, tH: HandleDef | null;\n if (edge.targetHandle) {\n tH = tHandles.find(h => h.id === edge.targetHandle) ?? null;\n const pos = handleToWorld(tH ? tH.x : tn.width / 2, tH ? tH.y : tn.height / 2, tn);\n tx = pos.x; ty = pos.y;\n } else {\n const anchor = floatingAnchor(tn, sn);\n tx = anchor.x; ty = anchor.y; tH = anchor.handleLike;\n }\n\n const sN = handleNormal(sH, sn);\n const tN = handleNormal(tH, tn);\n\n return { sx, sy, tx, ty, snx: sN.nx, sny: sN.ny, tnx: tN.nx, tny: tN.ny };\n}\n\n/**\n * Compute a floating connection anchor on `self` facing `other`.\n * Chooses the side by dominant direction, then slides the anchor along that\n * side to line up with the other node's center (clamped to the side extent).\n * Returns the world point plus a synthetic handle carrying only the `side`\n * (used for the outward normal).\n */\nfunction floatingAnchor(\n self: FlowNode,\n other: FlowNode,\n): { x: number; y: number; handleLike: HandleDef } {\n const sx = self.position.x, sy = self.position.y;\n const sw = self.width, sh = self.height;\n const sCx = sx + sw / 2, sCy = sy + sh / 2;\n let oCx = other.position.x + other.width / 2;\n let oCy = other.position.y + other.height / 2;\n\n const deg = self.data.rotation ?? 0;\n if (deg !== 0) {\n // Work in the node's local (unrotated) frame: rotate the other node's\n // center into that frame so side-picking and the slide-to-align run in the\n // same space the anchor is computed in. The anchor is mapped back to world\n // space below via `handleToWorld`, so it rides on the rotated border.\n const rad = (deg * Math.PI) / 180;\n const cos = Math.cos(-rad), sin = Math.sin(-rad);\n const dx = oCx - sCx;\n const dy = oCy - sCy;\n oCx = sCx + dx * cos - dy * sin;\n oCy = sCy + dx * sin + dy * cos;\n }\n\n const dx = oCx - sCx;\n const dy = oCy - sCy;\n // Inset so the anchor never sits exactly on a corner.\n const inset = Math.min(12, sw / 2 - 1, sh / 2 - 1);\n\n let side: HandleDef['side'];\n let x: number, y: number;\n if (Math.abs(dx) >= Math.abs(dy)) {\n side = dx >= 0 ? 'right' : 'left';\n x = side === 'right' ? sx + sw : sx;\n // Slide vertically to align with the other center, clamped to the side.\n y = Math.max(sy + inset, Math.min(sy + sh - inset, oCy));\n } else {\n side = dy >= 0 ? 'bottom' : 'top';\n y = side === 'bottom' ? sy + sh : sy;\n x = Math.max(sx + inset, Math.min(sx + sw - inset, oCx));\n }\n\n if (deg !== 0) {\n // Map the (locally chosen) anchor back onto the rotated border.\n const pos = handleToWorld(x - sx, y - sy, self);\n return { x: pos.x, y: pos.y, handleLike: { id: `float_${side}`, x: 0, y: 0, side } };\n }\n\n return { x, y, handleLike: { id: `float_${side}`, x: 0, y: 0, side } };\n}\n\n/**\n * Previously this pinned auto-resolved edges to a fixed middle handle at load\n * time, which forced ugly jogs between misaligned nodes. Edges without an\n * explicit handle are now left \"floating\" and resolved dynamically in\n * `resolveEdgeEndpoints` (see `floatingAnchor`), so this is a no-op that simply\n * preserves any user-pinned handles.\n */\nexport function normalizeEdgeHandles(\n edges: FlowEdge[],\n _nodeMap: Map<string, FlowNode>,\n): FlowEdge[] {\n const legacyOffsets = new Map([\n ['0.25', String(2 / 6)],\n ['0.5', String(3 / 6)],\n ['0.75', String(4 / 6)],\n ]);\n let changed = false;\n const migrate = (handle: string | undefined) => {\n if (!handle) return handle;\n const [side, offset] = handle.split('_');\n const nextOffset = legacyOffsets.get(offset);\n if (!nextOffset || !side) return handle;\n changed = true;\n return `${side}_${nextOffset}`;\n };\n const normalized = edges.map(edge => {\n const sourceHandle = migrate(edge.sourceHandle);\n const targetHandle = migrate(edge.targetHandle);\n return sourceHandle === edge.sourceHandle && targetHandle === edge.targetHandle\n ? edge\n : { ...edge, sourceHandle, targetHandle };\n });\n return changed ? normalized : edges;\n}\n\n/**\n * Convert PathSegments into a polyline by sampling curves.\n */\nexport function linearizeSegments(\n segs: PathSegment[],\n samplesPerCurve = 8,\n): Array<{ x: number; y: number }> {\n const pts: Array<{ x: number; y: number }> = [];\n let cx = 0, cy = 0;\n for (const seg of segs) {\n switch (seg.type) {\n case 'M':\n case 'L':\n cx = seg.x; cy = seg.y;\n pts.push({ x: cx, y: cy });\n break;\n case 'Q': {\n const cpx = seg.cp1x!, cpy = seg.cp1y!;\n for (let i = 1; i <= samplesPerCurve; i++) {\n const t = i / samplesPerCurve, mt = 1 - t;\n pts.push({\n x: mt * mt * cx + 2 * mt * t * cpx + t * t * seg.x,\n y: mt * mt * cy + 2 * mt * t * cpy + t * t * seg.y,\n });\n }\n cx = seg.x; cy = seg.y;\n break;\n }\n case 'C': {\n const c1x = seg.cp1x!, c1y = seg.cp1y!, c2x = seg.cp2x!, c2y = seg.cp2y!;\n for (let i = 1; i <= samplesPerCurve; i++) {\n const t = i / samplesPerCurve, mt = 1 - t;\n pts.push({\n x: mt ** 3 * cx + 3 * mt ** 2 * t * c1x + 3 * mt * t ** 2 * c2x + t ** 3 * seg.x,\n y: mt ** 3 * cy + 3 * mt ** 2 * t * c1y + 3 * mt * t ** 2 * c2y + t ** 3 * seg.y,\n });\n }\n cx = seg.x; cy = seg.y;\n break;\n }\n }\n }\n return pts;\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Delete everything selected on the current canvas (nodes, edges, lines).
3
+ *
4
+ * Shared by the Delete/Backspace keyboard shortcut and the on-canvas delete
5
+ * button, so touch devices (no keyboard) get exactly the same behavior,
6
+ * including the multi-node confirmation prompt.
7
+ */
8
+ export declare function useDeleteSelection(): () => void;
@@ -0,0 +1,43 @@
1
+ import { useFlowContext as I } from "../context/FlowContext.js";
2
+ import { useCallback as l } from "react";
3
+ function p() {
4
+ const { selection: i, setSelection: d, setDoc: r, currentCanvasId: a } = I();
5
+ return l(() => {
6
+ const { nodeIds: s, edgeIds: o, lineIds: c } = i;
7
+ s.size === 0 && o.size === 0 && c.size === 0 || s.size > 1 && !window.confirm(`确定要删除选中的 ${s.size} 个节点吗?`) || (r((t) => {
8
+ const n = t.canvases[a];
9
+ return n ? {
10
+ ...t,
11
+ canvases: {
12
+ ...t.canvases,
13
+ [a]: {
14
+ ...n,
15
+ nodes: n.nodes.filter((e) => !s.has(e.id)).map((e) => e.parentId && s.has(e.parentId) ? {
16
+ ...e,
17
+ parentId: void 0
18
+ } : e),
19
+ edges: n.edges.filter((e) => !o.has(e.id) && !s.has(e.source) && !s.has(e.target)),
20
+ lines: n.lines.filter((e) => !c.has(e.id)).map((e) => e.parentId && s.has(e.parentId) ? {
21
+ ...e,
22
+ parentId: void 0
23
+ } : e)
24
+ }
25
+ }
26
+ } : t;
27
+ }), d({
28
+ nodeIds: /* @__PURE__ */ new Set(),
29
+ edgeIds: /* @__PURE__ */ new Set(),
30
+ lineIds: /* @__PURE__ */ new Set()
31
+ }));
32
+ }, [
33
+ i,
34
+ r,
35
+ a,
36
+ d
37
+ ]);
38
+ }
39
+ export {
40
+ p as useDeleteSelection
41
+ };
42
+
43
+ //# sourceMappingURL=useDeleteSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDeleteSelection.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useDeleteSelection.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\n\n/**\n * Delete everything selected on the current canvas (nodes, edges, lines).\n *\n * Shared by the Delete/Backspace keyboard shortcut and the on-canvas delete\n * button, so touch devices (no keyboard) get exactly the same behavior,\n * including the multi-node confirmation prompt.\n */\nexport function useDeleteSelection() {\n const { selection, setSelection, setDoc, currentCanvasId } = useFlowContext();\n\n return useCallback(() => {\n const { nodeIds, edgeIds, lineIds } = selection;\n if (nodeIds.size === 0 && edgeIds.size === 0 && lineIds.size === 0) return;\n if (nodeIds.size > 1 && !window.confirm(`确定要删除选中的 ${nodeIds.size} 个节点吗?`)) return;\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [currentCanvasId]: {\n ...canvas,\n nodes: canvas.nodes\n .filter(n => !nodeIds.has(n.id))\n .map(n => n.parentId && nodeIds.has(n.parentId) ? { ...n, parentId: undefined } : n),\n edges: canvas.edges.filter(e =>\n !edgeIds.has(e.id) && !nodeIds.has(e.source) && !nodeIds.has(e.target),\n ),\n lines: canvas.lines\n .filter(l => !lineIds.has(l.id))\n .map(l => l.parentId && nodeIds.has(l.parentId) ? { ...l, parentId: undefined } : l),\n },\n },\n };\n });\n setSelection({ nodeIds: new Set(), edgeIds: new Set(), lineIds: new Set() });\n }, [selection, setDoc, currentCanvasId, setSelection]);\n}\n"],"mappings":";;AAUA,SAAgB,IAAqB;AACnC,QAAM,EAAE,WAAA,GAAW,cAAA,GAAc,QAAA,GAAQ,iBAAA,EAAA,IAAoB,EAAe;AAE5E,SAAO,EAAA,MAAkB;AACvB,UAAM,EAAE,SAAA,GAAS,SAAA,GAAS,SAAA,EAAA,IAAY;AACtC,IAAI,EAAQ,SAAS,KAAK,EAAQ,SAAS,KAAK,EAAQ,SAAS,KAC7D,EAAQ,OAAO,KAAK,CAAC,OAAO,QAAQ,YAAY,EAAQ,IAAA,QAAY,MACxE,EAAA,CAAO,MAAQ;AACb,YAAM,IAAS,EAAK,SAAS,CAAA;AAC7B,aAAK,IACE;AAAA,QACL,GAAG;AAAA,QACH,UAAU;AAAA,UACR,GAAG,EAAK;AAAA,WACP,CAAA,GAAkB;AAAA,YACjB,GAAG;AAAA,YACH,OAAO,EAAO,MACX,OAAA,CAAO,MAAK,CAAC,EAAQ,IAAI,EAAE,EAAE,CAAC,EAC9B,IAAA,CAAI,MAAK,EAAE,YAAY,EAAQ,IAAI,EAAE,QAAQ,IAAI;AAAA,cAAE,GAAG;AAAA,cAAG,UAAU;AAAA,YAAU,IAAI,CAAC;AAAA,YACrF,OAAO,EAAO,MAAM,OAAA,CAAO,MACzB,CAAC,EAAQ,IAAI,EAAE,EAAE,KAAK,CAAC,EAAQ,IAAI,EAAE,MAAM,KAAK,CAAC,EAAQ,IAAI,EAAE,MAAM,CACvE;AAAA,YACA,OAAO,EAAO,MACX,OAAA,CAAO,MAAK,CAAC,EAAQ,IAAI,EAAE,EAAE,CAAC,EAC9B,IAAA,CAAI,MAAK,EAAE,YAAY,EAAQ,IAAI,EAAE,QAAQ,IAAI;AAAA,cAAE,GAAG;AAAA,cAAG,UAAU;AAAA,YAAU,IAAI,CAAC;AAAA,UACvF;AAAA,QACF;AAAA,MACF,IAlBoB;AAAA,IAmBtB,CAAC,GACD,EAAa;AAAA,MAAE,SAAS,oBAAI,IAAI;AAAA,MAAG,SAAS,oBAAI,IAAI;AAAA,MAAG,SAAS,oBAAI,IAAI;AAAA,IAAE,CAAC;AAAA,EAC7E,GAAG;AAAA,IAAC;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAiB;AAAA,EAAY,CAAC;AACvD"}
@@ -1,10 +1,10 @@
1
1
  import { DEFAULT_EDGE_DATA as U, DEFAULT_NODE_DATA as _ } from "../constants.js";
2
2
  import { useFlowContext as F } from "../context/FlowContext.js";
3
- import { useFlowUI as O } from "../context/FlowUIContext.js";
3
+ import { useFlowUI as H } from "../context/FlowUIContext.js";
4
4
  import { generateId as R } from "../nodes/nodeUtils.js";
5
5
  import { useCallback as L, useEffect as C } from "react";
6
- var S = 150, z = 52, G = 100, H = 26;
7
- function W(D, P, g) {
6
+ var S = 150, z = 52, O = 100, G = 26;
7
+ function W(D, P, M) {
8
8
  const a = D.nodes.filter((i) => i.data.isMindMapNode), m = new Map(a.map((i) => [i.id, i])), c = /* @__PURE__ */ new Map();
9
9
  for (const i of a) {
10
10
  const p = i.data.mindMapParentId;
@@ -30,10 +30,10 @@ function W(D, P, g) {
30
30
  y: e
31
31
  }), e;
32
32
  };
33
- if (x(u, 0), g) {
34
- const i = I.get(g.id);
33
+ if (x(u, 0), M) {
34
+ const i = I.get(M.id);
35
35
  if (i) {
36
- const p = g.position.x - i.x, t = g.position.y - i.y;
36
+ const p = M.position.x - i.x, t = M.position.y - i.y;
37
37
  for (const [e, n] of I) I.set(e, {
38
38
  x: n.x + p,
39
39
  y: n.y + t
@@ -43,7 +43,7 @@ function W(D, P, g) {
43
43
  return I;
44
44
  }
45
45
  function q() {
46
- const { setEditingNodeId: D, focusOnRect: P, autoFocus: g } = O(), { currentCanvas: a, currentCanvasId: m, selection: c, setSelection: u, setDoc: I } = F(), k = L((t) => {
46
+ const { setEditingNodeId: D, focusOnRect: P, autoFocus: M } = H(), { currentCanvas: a, currentCanvasId: m, selection: c, setSelection: u, setDoc: I } = F(), k = L((t) => {
47
47
  t && window.setTimeout(() => {
48
48
  P(t.position.x, t.position.y, t.width, t.height, {
49
49
  padding: 80,
@@ -60,8 +60,8 @@ function q() {
60
60
  id: s,
61
61
  type: "shapeRoundRect",
62
62
  position: {
63
- x: n.position.x + S + G,
64
- y: n.position.y + z + H
63
+ x: n.position.x + S + O,
64
+ y: n.position.y + z + G
65
65
  },
66
66
  width: S,
67
67
  height: z,
@@ -96,6 +96,8 @@ function q() {
96
96
  id: R("edge"),
97
97
  source: d,
98
98
  target: s,
99
+ sourceHandle: "r_0.5",
100
+ targetHandle: "l_0.5",
99
101
  type: "simplebezier",
100
102
  data: {
101
103
  ...U,
@@ -103,12 +105,12 @@ function q() {
103
105
  strokeWidth: 1.5
104
106
  }
105
107
  }]
106
- }, r = t === "child" ? n : w.nodes.find((o) => o.id === d) ?? n, M = W(b, y, {
108
+ }, r = t === "child" ? n : w.nodes.find((o) => o.id === d) ?? n, g = W(b, y, {
107
109
  id: r.id,
108
110
  position: r.position
109
111
  });
110
112
  return b.nodes = b.nodes.map((o) => {
111
- const N = M.get(o.id);
113
+ const N = g.get(o.id);
112
114
  return N ? {
113
115
  ...o,
114
116
  position: N
@@ -175,13 +177,13 @@ function q() {
175
177
  u
176
178
  ]), p = c.nodeIds.size === 1 ? [...c.nodeIds][0] : null;
177
179
  C(() => {
178
- if (!g || !p) return;
180
+ if (!M || !p) return;
179
181
  const t = a.nodes.find((n) => n.id === p);
180
182
  if (!t) return;
181
183
  const e = window.setTimeout(() => k(t), 20);
182
184
  return () => window.clearTimeout(e);
183
185
  }, [
184
- g,
186
+ M,
185
187
  p,
186
188
  k
187
189
  ]), C(() => {
@@ -208,13 +210,13 @@ function q() {
208
210
  if (e.key === "ArrowLeft" && s.data.mindMapParentId ? h = f.get(s.data.mindMapParentId) : e.key === "ArrowRight" ? h = E[0] : e.key === "ArrowUp" && y > 0 ? h = w[y - 1] : e.key === "ArrowDown" && y >= 0 && y < w.length - 1 && (h = w[y + 1]), !h) {
209
211
  const l = s.position.x + s.width / 2, b = s.position.y + s.height / 2;
210
212
  h = a.nodes.filter((r) => r.id !== s.id && r.type !== "animAnchor").map((r) => {
211
- const M = r.position.x + r.width / 2 - l, o = r.position.y + r.height / 2 - b;
213
+ const g = r.position.x + r.width / 2 - l, o = r.position.y + r.height / 2 - b;
212
214
  return {
213
215
  node: r,
214
- inDirection: e.key === "ArrowLeft" ? M < 0 : e.key === "ArrowRight" ? M > 0 : e.key === "ArrowUp" ? o < 0 : o > 0,
215
- score: (e.key === "ArrowLeft" || e.key === "ArrowRight" ? Math.abs(M) : Math.abs(o)) + (e.key === "ArrowLeft" || e.key === "ArrowRight" ? Math.abs(o) : Math.abs(M)) * 1.75
216
+ inDirection: e.key === "ArrowLeft" ? g < 0 : e.key === "ArrowRight" ? g > 0 : e.key === "ArrowUp" ? o < 0 : o > 0,
217
+ score: (e.key === "ArrowLeft" || e.key === "ArrowRight" ? Math.abs(g) : Math.abs(o)) + (e.key === "ArrowLeft" || e.key === "ArrowRight" ? Math.abs(o) : Math.abs(g)) * 1.75
216
218
  };
217
- }).filter((r) => r.inDirection).sort((r, M) => r.score - M.score)[0]?.node;
219
+ }).filter((r) => r.inDirection).sort((r, g) => r.score - g.score)[0]?.node;
218
220
  }
219
221
  h && (A(), u({
220
222
  nodeIds: /* @__PURE__ */ new Set([h.id]),
@@ -1 +1 @@
1
- {"version":3,"file":"useMindMap.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useMindMap.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { DEFAULT_EDGE_DATA, DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\nimport type { FlowCanvasData, FlowNode } from '../types';\n\nconst NODE_WIDTH = 150;\nconst NODE_HEIGHT = 52;\nconst LEVEL_GAP = 100;\nconst ROW_GAP = 26;\n\nfunction layoutMindMap(\n canvas: FlowCanvasData,\n rootId: string,\n fixed?: { id: string; position: { x: number; y: number } },\n): Map<string, { x: number; y: number }> {\n const nodes = canvas.nodes.filter(node => node.data.isMindMapNode);\n const nodeMap = new Map(nodes.map(node => [node.id, node]));\n const children = new Map<string, FlowNode[]>();\n for (const node of nodes) {\n const parentId = node.data.mindMapParentId;\n if (!parentId || !nodeMap.has(parentId)) continue;\n const list = children.get(parentId) ?? [];\n list.push(node);\n children.set(parentId, list);\n }\n\n const root = nodeMap.get(rootId);\n if (!root) return new Map();\n const positions = new Map<string, { x: number; y: number }>();\n let nextY = root.position.y;\n\n const place = (node: FlowNode, depth: number): number => {\n const kids = children.get(node.id) ?? [];\n let centerY: number;\n if (kids.length === 0) {\n centerY = nextY;\n nextY += NODE_HEIGHT + ROW_GAP;\n } else {\n const childYs = kids.map(child => place(child, depth + 1));\n centerY = (childYs[0] + childYs[childYs.length - 1]) / 2;\n }\n positions.set(node.id, {\n x: root.position.x + depth * (NODE_WIDTH + LEVEL_GAP),\n y: centerY,\n });\n return centerY;\n };\n\n place(root, 0);\n if (fixed) {\n const computed = positions.get(fixed.id);\n if (computed) {\n const dx = fixed.position.x - computed.x;\n const dy = fixed.position.y - computed.y;\n for (const [id, position] of positions) {\n positions.set(id, { x: position.x + dx, y: position.y + dy });\n }\n }\n }\n return positions;\n}\n\nexport function useMindMap() {\n const { setEditingNodeId, focusOnRect, autoFocus } = useFlowUI();\n const { currentCanvas, currentCanvasId, selection, setSelection, setDoc } = useFlowContext();\n\n const focusNode = useCallback((node: FlowNode | undefined) => {\n if (!node) return;\n window.setTimeout(() => {\n focusOnRect(node.position.x, node.position.y, node.width, node.height, {\n padding: 80,\n preserveZoom: true,\n duration: 280,\n });\n }, 0);\n }, [focusOnRect]);\n\n const createNode = useCallback((kind: 'child' | 'sibling-after' | 'sibling-before') => {\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n if (!selected) return;\n\n // A regular Flow node can become the root of a mind map on first use.\n const parentId = kind === 'child' ? selected.id : selected.data.mindMapParentId;\n if (kind !== 'child' && !parentId) return;\n const id = generateId('mind');\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: selected.position.x + NODE_WIDTH + LEVEL_GAP, y: selected.position.y + NODE_HEIGHT + ROW_GAP },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: Math.max(0, ...currentCanvas.nodes.map(item => item.zIndex ?? 0)) + 1,\n data: {\n // Colors follow the theme (`theme:*` tokens from DEFAULT_NODE_DATA) so\n // mind maps re-color automatically when the DishUI theme changes.\n ...DEFAULT_NODE_DATA,\n label: kind === 'child' ? '子主题' : '主题',\n isMindMapNode: true,\n mindMapParentId: parentId,\n },\n };\n\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n const rootId = (() => {\n let cursor = selected;\n const map = new Map(canvas.nodes.map(item => [item.id, item]));\n while (cursor.data.mindMapParentId && map.has(cursor.data.mindMapParentId)) {\n cursor = map.get(cursor.data.mindMapParentId)!;\n }\n return cursor.id;\n })();\n const normalizedNodes = canvas.nodes.map(item => item.id === selected.id && !item.data.isMindMapNode\n ? { ...item, data: { ...item.data, isMindMapNode: true } }\n : item);\n const selectedIndex = normalizedNodes.findIndex(item => item.id === selected.id);\n const insertIndex = kind === 'sibling-before'\n ? selectedIndex\n : selectedIndex + 1;\n normalizedNodes.splice(Math.max(0, insertIndex), 0, node);\n const nextCanvas: FlowCanvasData = {\n ...canvas,\n nodes: normalizedNodes,\n edges: [...canvas.edges, {\n id: generateId('edge'),\n source: parentId!,\n target: id,\n type: 'simplebezier',\n data: { ...DEFAULT_EDGE_DATA, markerEnd: 'none', strokeWidth: 1.5 },\n }],\n };\n // Child insertion keeps the current node fixed. Sibling insertion keeps\n // their shared parent fixed, so adding nodes never makes the parent jump.\n const fixedNode = kind === 'child'\n ? selected\n : canvas.nodes.find(item => item.id === parentId) ?? selected;\n const positions = layoutMindMap(nextCanvas, rootId, {\n id: fixedNode.id,\n position: fixedNode.position,\n });\n nextCanvas.nodes = nextCanvas.nodes.map(item => {\n const pos = positions.get(item.id);\n return pos ? { ...item, position: pos } : item;\n });\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: nextCanvas } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const createRoot = useCallback(() => {\n if (selection.nodeIds.size !== 0) return false;\n const id = generateId('mind');\n const highestZ = Math.max(0, ...currentCanvas.nodes.map(node => node.zIndex ?? 0));\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: 120, y: 120 },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: highestZ + 1,\n // Root keeps a primary-colored outline for hierarchy emphasis; every\n // color is still a theme token, so it follows the active theme.\n data: { ...DEFAULT_NODE_DATA, label: '中心主题', stroke: 'theme:primary', isMindMapNode: true },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: { ...canvas, nodes: [...canvas.nodes, node] } } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n return true;\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const focusedNodeId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n\n // Center only when keyboard focus/selection moves to another node. Node drag\n // updates currentCanvas continuously; depending on currentCanvas here would\n // make the viewport chase the mouse while an object is being repositioned.\n useEffect(() => {\n if (!autoFocus || !focusedNodeId) return;\n const node = currentCanvas.nodes.find(item => item.id === focusedNodeId);\n if (!node) return;\n const timer = window.setTimeout(() => focusNode(node), 20);\n return () => window.clearTimeout(timer);\n // currentCanvas is intentionally excluded: position-only updates must not\n // retrigger viewport focus while dragging.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFocus, focusedNodeId, focusNode]);\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement;\n // Never intercept native editing keys from form controls. In particular,\n // inspector textareas must keep Enter/Tab for multiline media source.\n if (target.matches('input, textarea, select, .flow-label-editor') || target.isContentEditable) return;\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n\n const consume = () => {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n };\n\n if (event.key === 'Tab') {\n consume();\n if (!selected) createRoot();\n else createNode('child');\n } else if (event.key === 'Enter' && selected) {\n consume();\n createNode(event.shiftKey ? 'sibling-before' : 'sibling-after');\n } else if ((event.key === ' ' || event.code === 'Space') && selected) {\n consume();\n setEditingNodeId(selected.id);\n } else if (selected && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {\n const nodeMap = new Map(currentCanvas.nodes.map(node => [node.id, node]));\n const siblings = currentCanvas.nodes.filter(node =>\n node.data.isMindMapNode && node.data.mindMapParentId === selected.data.mindMapParentId,\n );\n const siblingIndex = siblings.findIndex(node => node.id === selected.id);\n const children = currentCanvas.nodes.filter(node => node.data.mindMapParentId === selected.id);\n let targetNode: FlowNode | undefined;\n if (event.key === 'ArrowLeft' && selected.data.mindMapParentId) {\n targetNode = nodeMap.get(selected.data.mindMapParentId);\n } else if (event.key === 'ArrowRight') {\n targetNode = children[0];\n } else if (event.key === 'ArrowUp' && siblingIndex > 0) {\n targetNode = siblings[siblingIndex - 1];\n } else if (event.key === 'ArrowDown' && siblingIndex >= 0 && siblingIndex < siblings.length - 1) {\n targetNode = siblings[siblingIndex + 1];\n }\n\n // Regular Flow nodes have no mind-map relationship metadata. Fall back\n // to spatial navigation, choosing the nearest node in the requested\n // direction. The perpendicular penalty favors visually aligned nodes.\n if (!targetNode) {\n const sx = selected.position.x + selected.width / 2;\n const sy = selected.position.y + selected.height / 2;\n const candidates = currentCanvas.nodes\n .filter(node => node.id !== selected.id && node.type !== 'animAnchor')\n .map(node => {\n const dx = node.position.x + node.width / 2 - sx;\n const dy = node.position.y + node.height / 2 - sy;\n const inDirection = event.key === 'ArrowLeft' ? dx < 0\n : event.key === 'ArrowRight' ? dx > 0\n : event.key === 'ArrowUp' ? dy < 0\n : dy > 0;\n const primary = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dx)\n : Math.abs(dy);\n const perpendicular = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dy)\n : Math.abs(dx);\n return { node, inDirection, score: primary + perpendicular * 1.75 };\n })\n .filter(candidate => candidate.inDirection)\n .sort((a, b) => a.score - b.score);\n targetNode = candidates[0]?.node;\n }\n\n if (targetNode) {\n consume();\n setSelection({ nodeIds: new Set([targetNode.id]), edgeIds: new Set(), lineIds: new Set() });\n }\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [selection, currentCanvas, createNode, createRoot, setEditingNodeId, setSelection]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useMindMap.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useMindMap.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { DEFAULT_EDGE_DATA, DEFAULT_NODE_DATA } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\nimport type { FlowCanvasData, FlowNode } from '../types';\n\nconst NODE_WIDTH = 150;\nconst NODE_HEIGHT = 52;\nconst LEVEL_GAP = 100;\nconst ROW_GAP = 26;\n\nfunction layoutMindMap(\n canvas: FlowCanvasData,\n rootId: string,\n fixed?: { id: string; position: { x: number; y: number } },\n): Map<string, { x: number; y: number }> {\n const nodes = canvas.nodes.filter(node => node.data.isMindMapNode);\n const nodeMap = new Map(nodes.map(node => [node.id, node]));\n const children = new Map<string, FlowNode[]>();\n for (const node of nodes) {\n const parentId = node.data.mindMapParentId;\n if (!parentId || !nodeMap.has(parentId)) continue;\n const list = children.get(parentId) ?? [];\n list.push(node);\n children.set(parentId, list);\n }\n\n const root = nodeMap.get(rootId);\n if (!root) return new Map();\n const positions = new Map<string, { x: number; y: number }>();\n let nextY = root.position.y;\n\n const place = (node: FlowNode, depth: number): number => {\n const kids = children.get(node.id) ?? [];\n let centerY: number;\n if (kids.length === 0) {\n centerY = nextY;\n nextY += NODE_HEIGHT + ROW_GAP;\n } else {\n const childYs = kids.map(child => place(child, depth + 1));\n centerY = (childYs[0] + childYs[childYs.length - 1]) / 2;\n }\n positions.set(node.id, {\n x: root.position.x + depth * (NODE_WIDTH + LEVEL_GAP),\n y: centerY,\n });\n return centerY;\n };\n\n place(root, 0);\n if (fixed) {\n const computed = positions.get(fixed.id);\n if (computed) {\n const dx = fixed.position.x - computed.x;\n const dy = fixed.position.y - computed.y;\n for (const [id, position] of positions) {\n positions.set(id, { x: position.x + dx, y: position.y + dy });\n }\n }\n }\n return positions;\n}\n\nexport function useMindMap() {\n const { setEditingNodeId, focusOnRect, autoFocus } = useFlowUI();\n const { currentCanvas, currentCanvasId, selection, setSelection, setDoc } = useFlowContext();\n\n const focusNode = useCallback((node: FlowNode | undefined) => {\n if (!node) return;\n window.setTimeout(() => {\n focusOnRect(node.position.x, node.position.y, node.width, node.height, {\n padding: 80,\n preserveZoom: true,\n duration: 280,\n });\n }, 0);\n }, [focusOnRect]);\n\n const createNode = useCallback((kind: 'child' | 'sibling-after' | 'sibling-before') => {\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n if (!selected) return;\n\n // A regular Flow node can become the root of a mind map on first use.\n const parentId = kind === 'child' ? selected.id : selected.data.mindMapParentId;\n if (kind !== 'child' && !parentId) return;\n const id = generateId('mind');\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: selected.position.x + NODE_WIDTH + LEVEL_GAP, y: selected.position.y + NODE_HEIGHT + ROW_GAP },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: Math.max(0, ...currentCanvas.nodes.map(item => item.zIndex ?? 0)) + 1,\n data: {\n // Colors follow the theme (`theme:*` tokens from DEFAULT_NODE_DATA) so\n // mind maps re-color automatically when the DishUI theme changes.\n ...DEFAULT_NODE_DATA,\n label: kind === 'child' ? '子主题' : '主题',\n isMindMapNode: true,\n mindMapParentId: parentId,\n },\n };\n\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n const rootId = (() => {\n let cursor = selected;\n const map = new Map(canvas.nodes.map(item => [item.id, item]));\n while (cursor.data.mindMapParentId && map.has(cursor.data.mindMapParentId)) {\n cursor = map.get(cursor.data.mindMapParentId)!;\n }\n return cursor.id;\n })();\n const normalizedNodes = canvas.nodes.map(item => item.id === selected.id && !item.data.isMindMapNode\n ? { ...item, data: { ...item.data, isMindMapNode: true } }\n : item);\n const selectedIndex = normalizedNodes.findIndex(item => item.id === selected.id);\n const insertIndex = kind === 'sibling-before'\n ? selectedIndex\n : selectedIndex + 1;\n normalizedNodes.splice(Math.max(0, insertIndex), 0, node);\n const nextCanvas: FlowCanvasData = {\n ...canvas,\n nodes: normalizedNodes,\n edges: [...canvas.edges, {\n id: generateId('edge'),\n source: parentId!,\n target: id,\n // Mindmap layout grows strictly left-to-right: always connect the\n // side midpoints (parent right-center → child left-center), matching\n // the pinned-handle behavior of manual connections.\n sourceHandle: 'r_0.5',\n targetHandle: 'l_0.5',\n type: 'simplebezier',\n data: { ...DEFAULT_EDGE_DATA, markerEnd: 'none', strokeWidth: 1.5 },\n }],\n };\n // Child insertion keeps the current node fixed. Sibling insertion keeps\n // their shared parent fixed, so adding nodes never makes the parent jump.\n const fixedNode = kind === 'child'\n ? selected\n : canvas.nodes.find(item => item.id === parentId) ?? selected;\n const positions = layoutMindMap(nextCanvas, rootId, {\n id: fixedNode.id,\n position: fixedNode.position,\n });\n nextCanvas.nodes = nextCanvas.nodes.map(item => {\n const pos = positions.get(item.id);\n return pos ? { ...item, position: pos } : item;\n });\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: nextCanvas } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const createRoot = useCallback(() => {\n if (selection.nodeIds.size !== 0) return false;\n const id = generateId('mind');\n const highestZ = Math.max(0, ...currentCanvas.nodes.map(node => node.zIndex ?? 0));\n const node: FlowNode = {\n id,\n type: 'shapeRoundRect',\n position: { x: 120, y: 120 },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n zIndex: highestZ + 1,\n // Root keeps a primary-colored outline for hierarchy emphasis; every\n // color is still a theme token, so it follows the active theme.\n data: { ...DEFAULT_NODE_DATA, label: '中心主题', stroke: 'theme:primary', isMindMapNode: true },\n };\n setDoc(prev => {\n const canvas = prev.canvases[currentCanvasId];\n if (!canvas) return prev;\n return { ...prev, canvases: { ...prev.canvases, [currentCanvasId]: { ...canvas, nodes: [...canvas.nodes, node] } } };\n });\n setSelection({ nodeIds: new Set([id]), edgeIds: new Set(), lineIds: new Set() });\n return true;\n }, [selection, currentCanvas, currentCanvasId, setDoc, setSelection]);\n\n const focusedNodeId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n\n // Center only when keyboard focus/selection moves to another node. Node drag\n // updates currentCanvas continuously; depending on currentCanvas here would\n // make the viewport chase the mouse while an object is being repositioned.\n useEffect(() => {\n if (!autoFocus || !focusedNodeId) return;\n const node = currentCanvas.nodes.find(item => item.id === focusedNodeId);\n if (!node) return;\n const timer = window.setTimeout(() => focusNode(node), 20);\n return () => window.clearTimeout(timer);\n // currentCanvas is intentionally excluded: position-only updates must not\n // retrigger viewport focus while dragging.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFocus, focusedNodeId, focusNode]);\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement;\n // Never intercept native editing keys from form controls. In particular,\n // inspector textareas must keep Enter/Tab for multiline media source.\n if (target.matches('input, textarea, select, .flow-label-editor') || target.isContentEditable) return;\n const selectedId = selection.nodeIds.size === 1 ? [...selection.nodeIds][0] : null;\n const selected = selectedId ? currentCanvas.nodes.find(node => node.id === selectedId) : undefined;\n\n const consume = () => {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n };\n\n if (event.key === 'Tab') {\n consume();\n if (!selected) createRoot();\n else createNode('child');\n } else if (event.key === 'Enter' && selected) {\n consume();\n createNode(event.shiftKey ? 'sibling-before' : 'sibling-after');\n } else if ((event.key === ' ' || event.code === 'Space') && selected) {\n consume();\n setEditingNodeId(selected.id);\n } else if (selected && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {\n const nodeMap = new Map(currentCanvas.nodes.map(node => [node.id, node]));\n const siblings = currentCanvas.nodes.filter(node =>\n node.data.isMindMapNode && node.data.mindMapParentId === selected.data.mindMapParentId,\n );\n const siblingIndex = siblings.findIndex(node => node.id === selected.id);\n const children = currentCanvas.nodes.filter(node => node.data.mindMapParentId === selected.id);\n let targetNode: FlowNode | undefined;\n if (event.key === 'ArrowLeft' && selected.data.mindMapParentId) {\n targetNode = nodeMap.get(selected.data.mindMapParentId);\n } else if (event.key === 'ArrowRight') {\n targetNode = children[0];\n } else if (event.key === 'ArrowUp' && siblingIndex > 0) {\n targetNode = siblings[siblingIndex - 1];\n } else if (event.key === 'ArrowDown' && siblingIndex >= 0 && siblingIndex < siblings.length - 1) {\n targetNode = siblings[siblingIndex + 1];\n }\n\n // Regular Flow nodes have no mind-map relationship metadata. Fall back\n // to spatial navigation, choosing the nearest node in the requested\n // direction. The perpendicular penalty favors visually aligned nodes.\n if (!targetNode) {\n const sx = selected.position.x + selected.width / 2;\n const sy = selected.position.y + selected.height / 2;\n const candidates = currentCanvas.nodes\n .filter(node => node.id !== selected.id && node.type !== 'animAnchor')\n .map(node => {\n const dx = node.position.x + node.width / 2 - sx;\n const dy = node.position.y + node.height / 2 - sy;\n const inDirection = event.key === 'ArrowLeft' ? dx < 0\n : event.key === 'ArrowRight' ? dx > 0\n : event.key === 'ArrowUp' ? dy < 0\n : dy > 0;\n const primary = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dx)\n : Math.abs(dy);\n const perpendicular = event.key === 'ArrowLeft' || event.key === 'ArrowRight'\n ? Math.abs(dy)\n : Math.abs(dx);\n return { node, inDirection, score: primary + perpendicular * 1.75 };\n })\n .filter(candidate => candidate.inDirection)\n .sort((a, b) => a.score - b.score);\n targetNode = candidates[0]?.node;\n }\n\n if (targetNode) {\n consume();\n setSelection({ nodeIds: new Set([targetNode.id]), edgeIds: new Set(), lineIds: new Set() });\n }\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [selection, currentCanvas, createNode, createRoot, setEditingNodeId, setSelection]);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { resolveThemeColor as x } from "../utils/themeColor.js";
2
- import { angleBetween as h, drawMarker as f } from "../edges/edgeMarkers.js";
3
2
  import { drawDashedPolyline as g } from "../utils/dashedLine.js";
3
+ import { angleBetween as h, drawMarker as f } from "../edges/edgeMarkers.js";
4
4
  import { Container as y, Graphics as m } from "pixi.js";
5
5
  function u(n, e = 2) {
6
6
  if (!(!n || n === "solid")) {
@@ -8,6 +8,8 @@ export interface NodeContainer {
8
8
  svgTransform: Container;
9
9
  icon: Sprite;
10
10
  text: Text;
11
+ /** Optional registry glyph rendered beside the title text (left/right). */
12
+ titleIcon: Sprite;
11
13
  /** Optional muted second line (Archify card sublabel). */
12
14
  subtext: Text;
13
15
  /** Optional top-right pill background + label (Archify card tag). */