dishui 0.0.47 → 0.0.49

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 (82) hide show
  1. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +1 -2
  2. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
  3. package/dist/components/pro/CodeEditor/themes.js +0 -25
  4. package/dist/components/pro/CodeEditor/themes.js.map +1 -1
  5. package/dist/components/pro/CodeEditor/types.d.ts +1 -1
  6. package/dist/components/pro/Flow/Flow.js +500 -483
  7. package/dist/components/pro/Flow/Flow.js.map +1 -1
  8. package/dist/components/pro/Flow/FlowCanvas.js +526 -524
  9. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  10. package/dist/components/pro/Flow/canvas/GridRenderer.d.ts +3 -0
  11. package/dist/components/pro/Flow/canvas/GridRenderer.js +28 -23
  12. package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
  13. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js +18 -17
  14. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
  15. package/dist/components/pro/Flow/canvas/PixiApp.d.ts +2 -0
  16. package/dist/components/pro/Flow/canvas/PixiApp.js +14 -11
  17. package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
  18. package/dist/components/pro/Flow/constants.js +7 -7
  19. package/dist/components/pro/Flow/constants.js.map +1 -1
  20. package/dist/components/pro/Flow/context/FlowAIContext.d.ts +15 -0
  21. package/dist/components/pro/Flow/context/FlowAIContext.js +32 -0
  22. package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -0
  23. package/dist/components/pro/Flow/context/FlowUIContext.d.ts +4 -1
  24. package/dist/components/pro/Flow/context/FlowUIContext.js +58 -55
  25. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  26. package/dist/components/pro/Flow/edges/EdgeRenderer.js +22 -21
  27. package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
  28. package/dist/components/pro/Flow/hooks/useFlowImportExport.js +32 -32
  29. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  30. package/dist/components/pro/Flow/hooks/usePixiApp.d.ts +6 -1
  31. package/dist/components/pro/Flow/hooks/usePixiApp.js +49 -30
  32. package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
  33. package/dist/components/pro/Flow/index.d.ts +2 -0
  34. package/dist/components/pro/Flow/lines/FreehandTool.js +21 -20
  35. package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
  36. package/dist/components/pro/Flow/lines/GeometricLineTool.js +22 -18
  37. package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
  38. package/dist/components/pro/Flow/lines/LineRenderer.js +19 -18
  39. package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
  40. package/dist/components/pro/Flow/nodes/MediaContent.js +143 -124
  41. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  42. package/dist/components/pro/Flow/nodes/MediaOverlay.js +22 -17
  43. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  44. package/dist/components/pro/Flow/nodes/NodeRenderer.js +77 -76
  45. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  46. package/dist/components/pro/Flow/nodes/aiClient.d.ts +22 -0
  47. package/dist/components/pro/Flow/nodes/aiClient.js +107 -54
  48. package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
  49. package/dist/components/pro/Flow/nodes/svgIcons.js +6 -6
  50. package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
  51. package/dist/components/pro/Flow/panels/AIPanel.d.ts +2 -0
  52. package/dist/components/pro/Flow/panels/AIPanel.js +498 -0
  53. package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -0
  54. package/dist/components/pro/Flow/panels/FlowPanelGroup.js +51 -39
  55. package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
  56. package/dist/components/pro/Flow/panels/FlowToolbar.js +91 -85
  57. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  58. package/dist/components/pro/Flow/panels/InspectorPanel.js +372 -332
  59. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  60. package/dist/components/pro/Flow/panels/OutlinePanel.js +28 -27
  61. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  62. package/dist/components/pro/Flow/panels/ShapePalette.js +107 -104
  63. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  64. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
  65. package/dist/components/pro/Flow/panels/toolbarIcons.js +25 -20
  66. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  67. package/dist/components/pro/Flow/types.d.ts +13 -0
  68. package/dist/components/pro/Flow/types.js.map +1 -1
  69. package/dist/components/pro/Flow/utils/themeColor.d.ts +87 -0
  70. package/dist/components/pro/Flow/utils/themeColor.js +212 -0
  71. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -0
  72. package/dist/contexts/AppContext.d.ts +1 -1
  73. package/dist/contexts/AppContext.js +28 -29
  74. package/dist/contexts/AppContext.js.map +1 -1
  75. package/dist/dishui.css +1 -1
  76. package/dist/favicon.svg +10 -0
  77. package/dist/flow.js +56 -51
  78. package/dist/styles/themeStyles.js +6 -11
  79. package/dist/styles/themeStyles.js.map +1 -1
  80. package/dist/utils/themes.js +3 -23
  81. package/dist/utils/themes.js.map +1 -1
  82. package/package.json +17 -18
@@ -1,92 +1,95 @@
1
- import { createContext as ce, useCallback as o, useContext as ie, useMemo as ue, useRef as u, useState as e } from "react";
2
- import { jsx as ae } from "react/jsx-runtime";
3
- var G = ce(null);
4
- function he() {
5
- const n = ie(G);
1
+ import { createContext as ae, useCallback as o, useContext as le, useMemo as we, useRef as i, useState as e } from "react";
2
+ import { jsx as de } from "react/jsx-runtime";
3
+ var G = ae(null);
4
+ function fe() {
5
+ const n = le(G);
6
6
  if (!n) throw new Error("useFlowUI must be used within FlowUIProvider");
7
7
  return n;
8
8
  }
9
- function ge({ showMiniMap: n = !0, showGrid: b = !0, gridSize: y = 20, children: A }) {
10
- const [a, E] = e("select"), [l, V] = e("smoothstep"), [d, w] = e({
9
+ function Se({ showMiniMap: n = !0, showGrid: b = !0, gridSize: y = 20, showAI: E = !0, children: V }) {
10
+ const [a, J] = e("select"), [l, j] = e("smoothstep"), [w, d] = e({
11
11
  x: 0,
12
12
  y: 0,
13
13
  zoom: 1
14
- }), h = u(0), J = o((t) => {
15
- h.current += 1, w(t);
16
- }, []), j = o((t) => {
17
- w(t);
18
- }, []), [g, k] = e(!1), [p, q] = e(null), r = u(0), [c, f] = e(!1), S = o(() => {
14
+ }), h = i(0), k = o((t) => {
15
+ h.current += 1, d(t);
16
+ }, []), q = o((t) => {
17
+ d(t);
18
+ }, []), [g, B] = e(!1), [p, H] = e(null), r = i(0), [c, f] = e(!1), S = o(() => {
19
19
  r.current += 1, c || f(!0);
20
- }, [c]), M = o(() => {
20
+ }, [c]), I = o(() => {
21
21
  r.current = Math.max(0, r.current - 1), r.current === 0 && f(!1);
22
- }, []), [m, B] = e(!0), [x, H] = e(!0), [I, K] = e(!0), [P, L] = e(!0), [R, Q] = e(n), [F, W] = e(b), [v, X] = e(!0), [C, Y] = e(y), [D, Z] = e(null), [N, _] = e(null), [O, $] = e(null), [T, ee] = e(/* @__PURE__ */ new Set()), U = o((t) => {
23
- ee((i) => {
24
- const s = new Set(i);
22
+ }, []), [M, K] = e(!0), [m, L] = e(!0), [x, Q] = e(!0), [P, W] = e(!0), [R, X] = e(E), [F, Y] = e(n), [v, Z] = e(b), [A, _] = e(!0), [C, $] = e(y), [D, ee] = e(null), [N, te] = e(null), [O, oe] = e(null), [T, se] = e(/* @__PURE__ */ new Set()), U = o((t) => {
23
+ se((u) => {
24
+ const s = new Set(u);
25
25
  return s.has(t) ? s.delete(t) : s.add(t), s;
26
26
  });
27
- }, []), z = u(() => {
28
- }), te = o((t, i, s, ne, re) => {
29
- z.current(t, i, s, ne, re);
30
- }, []), oe = o((t) => {
27
+ }, []), z = i(() => {
28
+ }), ne = o((t, u, s, ue, ie) => {
29
+ z.current(t, u, s, ue, ie);
30
+ }, []), re = o((t) => {
31
31
  z.current = t;
32
- }, []), se = ue(() => ({
32
+ }, []), ce = we(() => ({
33
33
  toolMode: a,
34
- setToolMode: E,
34
+ setToolMode: J,
35
35
  edgeType: l,
36
- setEdgeType: V,
37
- viewport: d,
38
- setViewport: J,
39
- setViewportInternal: j,
36
+ setEdgeType: j,
37
+ viewport: w,
38
+ setViewport: k,
39
+ setViewportInternal: q,
40
40
  viewportReqRef: h,
41
- focusOnRect: te,
42
- setFocusOnRect: oe,
41
+ focusOnRect: ne,
42
+ setFocusOnRect: re,
43
43
  autoFocus: g,
44
- setAutoFocus: k,
44
+ setAutoFocus: B,
45
45
  editingNodeId: p,
46
- setEditingNodeId: q,
46
+ setEditingNodeId: H,
47
47
  isNodeDragging: c,
48
48
  beginNodeDrag: S,
49
- endNodeDrag: M,
50
- showPalette: m,
51
- setShowPalette: B,
52
- showInspector: x,
53
- setShowInspector: H,
54
- showOutline: I,
55
- setShowOutline: K,
49
+ endNodeDrag: I,
50
+ showPalette: M,
51
+ setShowPalette: K,
52
+ showInspector: m,
53
+ setShowInspector: L,
54
+ showOutline: x,
55
+ setShowOutline: Q,
56
56
  showJson: P,
57
- setShowJson: L,
58
- showMiniMap: R,
59
- setShowMiniMap: Q,
60
- showGrid: F,
61
- setShowGrid: W,
62
- showAnchors: v,
63
- setShowAnchors: X,
57
+ setShowJson: W,
58
+ showAI: R,
59
+ setShowAI: X,
60
+ showMiniMap: F,
61
+ setShowMiniMap: Y,
62
+ showGrid: v,
63
+ setShowGrid: Z,
64
+ showAnchors: A,
65
+ setShowAnchors: _,
64
66
  gridSize: C,
65
- setGridSize: Y,
67
+ setGridSize: $,
66
68
  pendingPlacement: D,
67
- setPendingPlacement: Z,
69
+ setPendingPlacement: ee,
68
70
  contextMenu: N,
69
- setContextMenu: _,
71
+ setContextMenu: te,
70
72
  presentation: O,
71
- setPresentation: $,
73
+ setPresentation: oe,
72
74
  detachedTabs: T,
73
75
  toggleDetach: U
74
76
  }), [
75
77
  a,
76
78
  l,
77
- d,
79
+ w,
78
80
  g,
79
81
  p,
80
82
  c,
81
83
  S,
84
+ I,
82
85
  M,
83
86
  m,
84
87
  x,
85
- I,
86
88
  P,
87
89
  R,
88
90
  F,
89
91
  v,
92
+ A,
90
93
  C,
91
94
  D,
92
95
  N,
@@ -94,14 +97,14 @@ function ge({ showMiniMap: n = !0, showGrid: b = !0, gridSize: y = 20, children:
94
97
  T,
95
98
  U
96
99
  ]);
97
- return /* @__PURE__ */ ae(G.Provider, {
98
- value: se,
99
- children: A
100
+ return /* @__PURE__ */ de(G.Provider, {
101
+ value: ce,
102
+ children: V
100
103
  });
101
104
  }
102
105
  export {
103
- ge as FlowUIProvider,
104
- he as useFlowUI
106
+ Se as FlowUIProvider,
107
+ fe as useFlowUI
105
108
  };
106
109
 
107
110
  //# sourceMappingURL=FlowUIContext.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FlowUIContext.js","names":[],"sources":["../../../../../src/components/pro/Flow/context/FlowUIContext.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo, useState, useRef, useCallback } from 'react';\nimport type { FlowToolMode, FlowEdgeTypeName, FlowShapeType, FlowNodeData, ViewportState } from '../types';\n\nexport interface ContextMenuState {\n x: number;\n y: number;\n nodeId: string | null;\n}\n\nexport interface FocusOnRectOptions {\n /** Screen-space padding around the focused rectangle, in pixels. */\n padding?: number;\n /** Maximum zoom allowed for this focus operation. */\n maxZoom?: number;\n /** Viewport transition duration in milliseconds. */\n duration?: number;\n /** Keep the current zoom and only animate the focused rectangle to center. */\n preserveZoom?: boolean;\n}\n\nexport interface FlowUIContextValue {\n toolMode: FlowToolMode;\n setToolMode: (mode: FlowToolMode) => void;\n edgeType: FlowEdgeTypeName;\n setEdgeType: (type: FlowEdgeTypeName) => void;\n viewport: ViewportState;\n setViewport: (v: ViewportState) => void;\n /** Internal VM→React bridge setter (does not request a VM apply). */\n setViewportInternal: (v: ViewportState) => void;\n /** Monotonic counter of external viewport commands. */\n viewportReqRef: React.MutableRefObject<number>;\n focusOnRect: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void;\n setFocusOnRect: (fn: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void) => void;\n autoFocus: boolean;\n setAutoFocus: (v: boolean) => void;\n editingNodeId: string | null;\n setEditingNodeId: (id: string | null) => void;\n /** True while any node/line is being dragged. Used to suppress interactive\n * DOM overlays (e.g. HTML iframes) that would otherwise swallow pointerup. */\n isNodeDragging: boolean;\n beginNodeDrag: () => void;\n endNodeDrag: () => void;\n showPalette: boolean;\n setShowPalette: (v: boolean) => void;\n showInspector: boolean;\n setShowInspector: (v: boolean) => void;\n showOutline: boolean;\n setShowOutline: (v: boolean) => void;\n showJson: boolean;\n setShowJson: (v: boolean) => void;\n showMiniMap: boolean;\n setShowMiniMap: (v: boolean) => void;\n showGrid: boolean;\n setShowGrid: (v: boolean) => void;\n /** Global editor-only visibility for animation anchor objects. */\n showAnchors: boolean;\n setShowAnchors: (v: boolean) => void;\n gridSize: number;\n setGridSize: (s: number) => void;\n pendingPlacement: PendingPlacement | null;\n setPendingPlacement: (p: PendingPlacement | null) => void;\n contextMenu: ContextMenuState | null;\n setContextMenu: (m: ContextMenuState | null) => void;\n detachedTabs: Set<string>;\n toggleDetach: (tabId: string) => void;\n /** PPT-style presentation mode. When set, the overlay animates the viewport\n * between animation anchors, navigable via arrow keys. */\n presentation: PresentationState | null;\n setPresentation: (p: PresentationState | null) => void;\n}\n\nexport interface PresentationState {\n /** Index into the anchor sequence (0-based). */\n current: number;\n /** Whether to show the active anchor frame and sequence badge in preview. */\n showAnchor?: boolean;\n}\n\nexport interface PendingPlacement {\n type: FlowShapeType;\n width: number;\n height: number;\n data: FlowNodeData;\n}\n\nconst FlowUIContext = createContext<FlowUIContextValue | null>(null);\n\nexport function useFlowUI(): FlowUIContextValue {\n const ctx = useContext(FlowUIContext);\n if (!ctx) throw new Error('useFlowUI must be used within FlowUIProvider');\n return ctx;\n}\n\nexport interface FlowUIProviderProps {\n showMiniMap?: boolean;\n showGrid?: boolean;\n gridSize?: number;\n children: React.ReactNode;\n}\n\nexport function FlowUIProvider({ showMiniMap: initMiniMap = true, showGrid: initGrid = true, gridSize: initGridSize = 20, children }: FlowUIProviderProps) {\n const [toolMode, setToolMode] = useState<FlowToolMode>('select');\n const [edgeType, setEdgeType] = useState<FlowEdgeTypeName>('smoothstep');\n const [viewport, setViewportState] = useState<ViewportState>({ x: 0, y: 0, zoom: 1 });\n // Distinguishes EXTERNAL viewport commands (toolbar, minimap, outline) from\n // internal echoes emitted by the ViewportManager. Only external commands\n // should be pushed back into the VM; echoing VM changes causes jitter.\n const viewportReqRef = useRef(0);\n const setViewport = useCallback((v: ViewportState) => {\n viewportReqRef.current += 1;\n setViewportState(v);\n }, []);\n // Internal setter used by the VM→React bridge; does NOT bump the request\n // counter, so the sync effect will not echo it back to the VM.\n const setViewportInternal = useCallback((v: ViewportState) => {\n setViewportState(v);\n }, []);\n const [autoFocus, setAutoFocus] = useState(false);\n const [editingNodeId, setEditingNodeId] = useState<string | null>(null);\n // Counter so concurrent drags (multi-node) don't flip the flag early.\n const dragCountRef = useRef(0);\n const [isNodeDragging, setIsNodeDragging] = useState(false);\n const beginNodeDrag = useCallback(() => {\n dragCountRef.current += 1;\n if (!isNodeDragging) setIsNodeDragging(true);\n }, [isNodeDragging]);\n const endNodeDrag = useCallback(() => {\n dragCountRef.current = Math.max(0, dragCountRef.current - 1);\n if (dragCountRef.current === 0) setIsNodeDragging(false);\n }, []);\n const [showPalette, setShowPalette] = useState(true);\n const [showInspector, setShowInspector] = useState(true);\n const [showOutline, setShowOutline] = useState(true);\n const [showJson, setShowJson] = useState(true);\n const [showMiniMap, setShowMiniMap] = useState(initMiniMap);\n const [showGrid, setShowGrid] = useState(initGrid);\n const [showAnchors, setShowAnchors] = useState(true);\n const [gridSize, setGridSize] = useState(initGridSize);\n const [pendingPlacement, setPendingPlacement] = useState<PendingPlacement | null>(null);\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n const [presentation, setPresentation] = useState<PresentationState | null>(null);\n const [detachedTabs, setDetachedTabs] = useState<Set<string>>(new Set());\n const toggleDetach = useCallback((tabId: string) => {\n setDetachedTabs(prev => {\n const next = new Set(prev);\n if (next.has(tabId)) next.delete(tabId); else next.add(tabId);\n return next;\n });\n }, []);\n\n const focusOnRectRef = useRef<(wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void>(() => {});\n const focusOnRect = useCallback((wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => {\n focusOnRectRef.current(wx, wy, ww, wh, options);\n }, []);\n const setFocusOnRect = useCallback((fn: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void) => {\n focusOnRectRef.current = fn;\n }, []);\n\n const value = useMemo<FlowUIContextValue>(() => ({\n toolMode, setToolMode,\n edgeType, setEdgeType,\n viewport, setViewport,\n setViewportInternal,\n viewportReqRef,\n focusOnRect, setFocusOnRect,\n autoFocus, setAutoFocus,\n editingNodeId, setEditingNodeId,\n isNodeDragging, beginNodeDrag, endNodeDrag,\n showPalette, setShowPalette,\n showInspector, setShowInspector,\n showOutline, setShowOutline,\n showJson, setShowJson,\n showMiniMap, setShowMiniMap,\n showGrid, setShowGrid,\n showAnchors, setShowAnchors,\n gridSize, setGridSize,\n pendingPlacement, setPendingPlacement,\n contextMenu, setContextMenu,\n presentation, setPresentation,\n detachedTabs, toggleDetach,\n }), [toolMode, edgeType, viewport, autoFocus, editingNodeId, isNodeDragging, beginNodeDrag, endNodeDrag, showPalette, showInspector, showOutline, showJson, showMiniMap, showGrid, showAnchors, gridSize, pendingPlacement, contextMenu, presentation, detachedTabs, toggleDetach]);\n\n return <FlowUIContext.Provider value={value}>{children}</FlowUIContext.Provider>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FlowUIContext.js","names":[],"sources":["../../../../../src/components/pro/Flow/context/FlowUIContext.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo, useState, useRef, useCallback } from 'react';\nimport type { FlowToolMode, FlowEdgeTypeName, FlowShapeType, FlowNodeData, ViewportState } from '../types';\n\nexport interface ContextMenuState {\n x: number;\n y: number;\n nodeId: string | null;\n}\n\nexport interface FocusOnRectOptions {\n /** Screen-space padding around the focused rectangle, in pixels. */\n padding?: number;\n /** Maximum zoom allowed for this focus operation. */\n maxZoom?: number;\n /** Viewport transition duration in milliseconds. */\n duration?: number;\n /** Keep the current zoom and only animate the focused rectangle to center. */\n preserveZoom?: boolean;\n}\n\nexport interface FlowUIContextValue {\n toolMode: FlowToolMode;\n setToolMode: (mode: FlowToolMode) => void;\n edgeType: FlowEdgeTypeName;\n setEdgeType: (type: FlowEdgeTypeName) => void;\n viewport: ViewportState;\n setViewport: (v: ViewportState) => void;\n /** Internal VM→React bridge setter (does not request a VM apply). */\n setViewportInternal: (v: ViewportState) => void;\n /** Monotonic counter of external viewport commands. */\n viewportReqRef: React.MutableRefObject<number>;\n focusOnRect: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void;\n setFocusOnRect: (fn: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void) => void;\n autoFocus: boolean;\n setAutoFocus: (v: boolean) => void;\n editingNodeId: string | null;\n setEditingNodeId: (id: string | null) => void;\n /** True while any node/line is being dragged. Used to suppress interactive\n * DOM overlays (e.g. HTML iframes) that would otherwise swallow pointerup. */\n isNodeDragging: boolean;\n beginNodeDrag: () => void;\n endNodeDrag: () => void;\n showPalette: boolean;\n setShowPalette: (v: boolean) => void;\n showInspector: boolean;\n setShowInspector: (v: boolean) => void;\n showOutline: boolean;\n setShowOutline: (v: boolean) => void;\n showJson: boolean;\n setShowJson: (v: boolean) => void;\n showAI: boolean;\n setShowAI: (v: boolean) => void;\n showMiniMap: boolean;\n setShowMiniMap: (v: boolean) => void;\n showGrid: boolean;\n setShowGrid: (v: boolean) => void;\n /** Global editor-only visibility for animation anchor objects. */\n showAnchors: boolean;\n setShowAnchors: (v: boolean) => void;\n gridSize: number;\n setGridSize: (s: number) => void;\n pendingPlacement: PendingPlacement | null;\n setPendingPlacement: (p: PendingPlacement | null) => void;\n contextMenu: ContextMenuState | null;\n setContextMenu: (m: ContextMenuState | null) => void;\n detachedTabs: Set<string>;\n toggleDetach: (tabId: string) => void;\n /** PPT-style presentation mode. When set, the overlay animates the viewport\n * between animation anchors, navigable via arrow keys. */\n presentation: PresentationState | null;\n setPresentation: (p: PresentationState | null) => void;\n}\n\nexport interface PresentationState {\n /** Index into the anchor sequence (0-based). */\n current: number;\n /** Whether to show the active anchor frame and sequence badge in preview. */\n showAnchor?: boolean;\n}\n\nexport interface PendingPlacement {\n type: FlowShapeType;\n width: number;\n height: number;\n data: FlowNodeData;\n}\n\nconst FlowUIContext = createContext<FlowUIContextValue | null>(null);\n\nexport function useFlowUI(): FlowUIContextValue {\n const ctx = useContext(FlowUIContext);\n if (!ctx) throw new Error('useFlowUI must be used within FlowUIProvider');\n return ctx;\n}\n\nexport interface FlowUIProviderProps {\n showMiniMap?: boolean;\n showGrid?: boolean;\n gridSize?: number;\n showAI?: boolean;\n children: React.ReactNode;\n}\n\nexport function FlowUIProvider({ showMiniMap: initMiniMap = true, showGrid: initGrid = true, gridSize: initGridSize = 20, showAI: initShowAI = true, children }: FlowUIProviderProps) {\n const [toolMode, setToolMode] = useState<FlowToolMode>('select');\n const [edgeType, setEdgeType] = useState<FlowEdgeTypeName>('smoothstep');\n const [viewport, setViewportState] = useState<ViewportState>({ x: 0, y: 0, zoom: 1 });\n // Distinguishes EXTERNAL viewport commands (toolbar, minimap, outline) from\n // internal echoes emitted by the ViewportManager. Only external commands\n // should be pushed back into the VM; echoing VM changes causes jitter.\n const viewportReqRef = useRef(0);\n const setViewport = useCallback((v: ViewportState) => {\n viewportReqRef.current += 1;\n setViewportState(v);\n }, []);\n // Internal setter used by the VM→React bridge; does NOT bump the request\n // counter, so the sync effect will not echo it back to the VM.\n const setViewportInternal = useCallback((v: ViewportState) => {\n setViewportState(v);\n }, []);\n const [autoFocus, setAutoFocus] = useState(false);\n const [editingNodeId, setEditingNodeId] = useState<string | null>(null);\n // Counter so concurrent drags (multi-node) don't flip the flag early.\n const dragCountRef = useRef(0);\n const [isNodeDragging, setIsNodeDragging] = useState(false);\n const beginNodeDrag = useCallback(() => {\n dragCountRef.current += 1;\n if (!isNodeDragging) setIsNodeDragging(true);\n }, [isNodeDragging]);\n const endNodeDrag = useCallback(() => {\n dragCountRef.current = Math.max(0, dragCountRef.current - 1);\n if (dragCountRef.current === 0) setIsNodeDragging(false);\n }, []);\n const [showPalette, setShowPalette] = useState(true);\n const [showInspector, setShowInspector] = useState(true);\n const [showOutline, setShowOutline] = useState(true);\n const [showJson, setShowJson] = useState(true);\n const [showAI, setShowAI] = useState(initShowAI);\n const [showMiniMap, setShowMiniMap] = useState(initMiniMap);\n const [showGrid, setShowGrid] = useState(initGrid);\n const [showAnchors, setShowAnchors] = useState(true);\n const [gridSize, setGridSize] = useState(initGridSize);\n const [pendingPlacement, setPendingPlacement] = useState<PendingPlacement | null>(null);\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n const [presentation, setPresentation] = useState<PresentationState | null>(null);\n const [detachedTabs, setDetachedTabs] = useState<Set<string>>(new Set());\n const toggleDetach = useCallback((tabId: string) => {\n setDetachedTabs(prev => {\n const next = new Set(prev);\n if (next.has(tabId)) next.delete(tabId); else next.add(tabId);\n return next;\n });\n }, []);\n\n const focusOnRectRef = useRef<(wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void>(() => {});\n const focusOnRect = useCallback((wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => {\n focusOnRectRef.current(wx, wy, ww, wh, options);\n }, []);\n const setFocusOnRect = useCallback((fn: (wx: number, wy: number, ww: number, wh: number, options?: FocusOnRectOptions) => void) => {\n focusOnRectRef.current = fn;\n }, []);\n\n const value = useMemo<FlowUIContextValue>(() => ({\n toolMode, setToolMode,\n edgeType, setEdgeType,\n viewport, setViewport,\n setViewportInternal,\n viewportReqRef,\n focusOnRect, setFocusOnRect,\n autoFocus, setAutoFocus,\n editingNodeId, setEditingNodeId,\n isNodeDragging, beginNodeDrag, endNodeDrag,\n showPalette, setShowPalette,\n showInspector, setShowInspector,\n showOutline, setShowOutline,\n showJson, setShowJson,\n showAI, setShowAI,\n showMiniMap, setShowMiniMap,\n showGrid, setShowGrid,\n showAnchors, setShowAnchors,\n gridSize, setGridSize,\n pendingPlacement, setPendingPlacement,\n contextMenu, setContextMenu,\n presentation, setPresentation,\n detachedTabs, toggleDetach,\n }), [toolMode, edgeType, viewport, autoFocus, editingNodeId, isNodeDragging, beginNodeDrag, endNodeDrag, showPalette, showInspector, showOutline, showJson, showAI, showMiniMap, showGrid, showAnchors, gridSize, pendingPlacement, contextMenu, presentation, detachedTabs, toggleDetach]);\n\n return <FlowUIContext.Provider value={value}>{children}</FlowUIContext.Provider>;\n}\n"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
- import { buildEdgePath as v, getPathCenter as B, resolveEdgeEndpoints as T } from "./edgePaths.js";
1
+ import { resolveThemeColor as E } from "../utils/themeColor.js";
2
+ import { buildEdgePath as T, getPathCenter as B, resolveEdgeEndpoints as M } from "./edgePaths.js";
2
3
  import { angleBetween as k, drawMarker as _ } from "./edgeMarkers.js";
3
4
  import { drawDashedPath as y } from "../utils/dashedLine.js";
4
- import { Container as E, Graphics as x, Text as M, TextStyle as L } from "pixi.js";
5
- function O(e, l, a = 2) {
5
+ import { Container as v, Graphics as x, Text as L, TextStyle as O } from "pixi.js";
6
+ function P(e, l, a = 2) {
6
7
  if (!(!e || e === "solid"))
7
8
  return e === "dynamic" ? [a * 4, a * 3] : [e === "dotted" ? a : a * 3, l === "dense" ? a : l === "sparse" ? a * 4 : a * 2];
8
9
  }
9
- var F = class {
10
+ var R = class {
10
11
  world;
11
12
  edgeLayer;
12
13
  edges = /* @__PURE__ */ new Map();
@@ -15,13 +16,13 @@ var F = class {
15
16
  this._dynamicOffset = (this._dynamicOffset + e * 0.06) % 1e3;
16
17
  }
17
18
  constructor(e) {
18
- this.world = e, this.edgeLayer = new E({ label: "edges" }), this.world.addChildAt(this.edgeLayer, 0);
19
+ this.world = e, this.edgeLayer = new v({ label: "edges" }), this.world.addChildAt(this.edgeLayer, 0);
19
20
  }
20
21
  sync(e, l, a, i, c) {
21
22
  const g = /* @__PURE__ */ new Set();
22
23
  for (const r of e) {
23
24
  g.add(r.id);
24
- const t = T(r, l);
25
+ const t = M(r, l);
25
26
  if (!t) continue;
26
27
  let h = this.edges.get(r.id);
27
28
  h || (h = this._createEdge(r), this.edges.set(r.id, h)), this._updateEdge(h, r, t, a.has(r.id), i === r.id, c?.presentation ?? !1);
@@ -29,7 +30,7 @@ var F = class {
29
30
  for (const [r, t] of this.edges) g.has(r) || (this.edgeLayer.removeChild(t.container), t.container.destroy({ children: !0 }), this.edges.delete(r));
30
31
  }
31
32
  _createEdge(e) {
32
- const l = new E({ label: `edge-${e.id}` }), a = new x();
33
+ const l = new v({ label: `edge-${e.id}` }), a = new x();
33
34
  a.label = "edge-hitarea", a.eventMode = "static", a.cursor = "pointer", a.alpha = 0, l.addChild(a);
34
35
  const i = new x();
35
36
  i.label = "edge-line", l.addChild(i);
@@ -45,8 +46,8 @@ var F = class {
45
46
  };
46
47
  }
47
48
  _updateEdge(e, l, a, i, c, g) {
48
- const { line: r, animation: t, hitArea: h } = e, o = l.data, b = i ? "#3b82f6" : o.strokeColor ?? "#374151", f = o.strokeWidth ?? 2, s = v(l.type, a, o.waypoints, o.bezierControls);
49
- if (r.clear(), this._drawPath(r, s, b, f, o.lineStyle, o.dashDensity), t.clear(), g && o.animated) {
49
+ const { line: r, animation: t, hitArea: h } = e, o = l.data, m = i ? "#3b82f6" : E(o.strokeColor, "#374151"), f = o.strokeWidth ?? 2, s = T(l.type, a, o.waypoints, o.bezierControls);
50
+ if (r.clear(), this._drawPath(r, s, m, f, o.lineStyle, o.dashDensity), t.clear(), g && o.animated) {
50
51
  const n = [Math.max(18, f * 12), Math.max(90, f * 45)];
51
52
  y(t, s, n, -this._dynamicOffset * 2.2), t.stroke({
52
53
  color: 6333946,
@@ -66,33 +67,33 @@ var F = class {
66
67
  });
67
68
  }
68
69
  if (o.markerStart && o.markerStart !== "none" && s.length >= 2) {
69
- const n = s[0], d = s[1], m = k(d.type === "C" ? d.cp1x : d.x, d.type === "C" ? d.cp1y : d.y, n.x, n.y);
70
- _(r, o.markerStart, n.x, n.y, m, b);
70
+ const n = s[0], d = s[1], b = k(d.type === "C" ? d.cp1x : d.x, d.type === "C" ? d.cp1y : d.y, n.x, n.y);
71
+ _(r, o.markerStart, n.x, n.y, b, m);
71
72
  }
72
73
  if (o.markerEnd && o.markerEnd !== "none" && s.length >= 2) {
73
74
  const n = s[s.length - 1], d = k(n.type === "C" ? n.cp2x : s[s.length - 2].x, n.type === "C" ? n.cp2y : s[s.length - 2].y, n.x, n.y);
74
- _(r, o.markerEnd, n.x, n.y, d, b);
75
+ _(r, o.markerEnd, n.x, n.y, d, m);
75
76
  }
76
77
  if (h.clear(), this._drawPath(h, s, "#000000", Math.max(f + 10, 14), "solid"), h.alpha = 1e-3, o.labelText) {
77
78
  const n = B(s);
78
79
  if (!e.label) {
79
80
  const p = new x();
80
81
  p.label = "edge-label-bg", e.container.addChild(p), e.labelBg = p;
81
- const u = new L({
82
+ const u = new O({
82
83
  fontFamily: o.labelFontFamily ?? "system-ui, -apple-system, sans-serif",
83
84
  fontSize: o.labelFontSize ?? 12,
84
- fill: b
85
+ fill: m
85
86
  });
86
- e.label = new M({
87
+ e.label = new L({
87
88
  text: o.labelText,
88
89
  style: u
89
90
  }), e.label.anchor.set(0.5, 0.5), e.container.addChild(e.label);
90
91
  }
91
92
  e.label.text = o.labelText;
92
- const d = n.x, m = n.y - 10;
93
- if (e.label.position.set(d, m), e.label.style.fill = b, e.labelBg) {
94
- const w = e.label.width + 10, C = e.label.height + 4;
95
- e.labelBg.clear(), e.labelBg.roundRect(d - w / 2, m - C / 2, w, C, 4).fill({
93
+ const d = n.x, b = n.y - 10;
94
+ if (e.label.position.set(d, b), e.label.style.fill = m, e.labelBg) {
95
+ const C = e.label.width + 10, w = e.label.height + 4;
96
+ e.labelBg.clear(), e.labelBg.roundRect(d - C / 2, b - w / 2, C, w, 4).fill({
96
97
  color: 16777215,
97
98
  alpha: 0.92
98
99
  });
@@ -101,7 +102,7 @@ var F = class {
101
102
  e.label && (e.label.text = ""), e.labelBg && e.labelBg.clear();
102
103
  }
103
104
  _drawPath(e, l, a, i, c, g) {
104
- const r = O(c, g, i);
105
+ const r = P(c, g, i);
105
106
  if (r)
106
107
  y(e, l, r, c === "dynamic" ? this._dynamicOffset : 0), e.stroke({
107
108
  color: a,
@@ -135,7 +136,7 @@ var F = class {
135
136
  }
136
137
  };
137
138
  export {
138
- F as EdgeRenderer
139
+ R as EdgeRenderer
139
140
  };
140
141
 
141
142
  //# sourceMappingURL=EdgeRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EdgeRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/edges/EdgeRenderer.ts"],"sourcesContent":["import { Container, Graphics, Text, TextStyle } from 'pixi.js';\nimport type { FlowEdge, FlowNode } from '../types';\nimport { buildEdgePath, getPathCenter, resolveEdgeEndpoints, type PathSegment, type EdgeEndpoints } from './edgePaths';\nimport { drawMarker, angleBetween } from './edgeMarkers';\nimport { drawDashedPath, type PathSeg } from '../utils/dashedLine';\n\ninterface EdgeDisplay {\n container: Container;\n line: Graphics;\n animation: Graphics;\n hitArea: Graphics;\n labelBg: Graphics | null;\n label: Text | null;\n edgeId: string;\n}\n\nfunction getDashPattern(style?: string, density?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n const base = style === 'dotted' ? width : width * 3;\n const gap = density === 'dense' ? width : density === 'sparse' ? width * 4 : width * 2;\n return [base, gap];\n}\n\n/**\n * Manages PixiJS display objects for all edges.\n */\nexport class EdgeRenderer {\n private world: Container;\n private edgeLayer: Container;\n private edges = new Map<string, EdgeDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.edgeLayer = new Container({ label: 'edges' });\n // Edges below nodes\n this.world.addChildAt(this.edgeLayer, 0);\n }\n\n sync(\n flowEdges: FlowEdge[],\n nodeMap: Map<string, FlowNode>,\n selectedIds: Set<string>,\n hoveredId: string | null,\n options?: { presentation?: boolean },\n ): void {\n const seen = new Set<string>();\n\n for (const edge of flowEdges) {\n seen.add(edge.id);\n const endpoints = resolveEdgeEndpoints(edge, nodeMap);\n if (!endpoints) continue;\n\n let display = this.edges.get(edge.id);\n if (!display) {\n display = this._createEdge(edge);\n this.edges.set(edge.id, display);\n }\n this._updateEdge(\n display,\n edge,\n endpoints,\n selectedIds.has(edge.id),\n hoveredId === edge.id,\n options?.presentation ?? false,\n );\n }\n\n for (const [id, display] of this.edges) {\n if (!seen.has(id)) {\n this.edgeLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.edges.delete(id);\n }\n }\n }\n\n private _createEdge(edge: FlowEdge): EdgeDisplay {\n const container = new Container({ label: `edge-${edge.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'edge-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0;\n container.addChild(hitArea);\n\n const line = new Graphics();\n line.label = 'edge-line';\n container.addChild(line);\n\n const animation = new Graphics();\n animation.label = 'edge-animation';\n container.addChild(animation);\n\n this.edgeLayer.addChild(container);\n return { container, line, animation, hitArea, labelBg: null, label: null, edgeId: edge.id };\n }\n\n private _updateEdge(\n display: EdgeDisplay,\n edge: FlowEdge,\n endpoints: EdgeEndpoints,\n selected: boolean,\n hovered: boolean,\n presentation: boolean,\n ): void {\n const { line, animation, hitArea } = display;\n const data = edge.data;\n const color = selected ? '#3b82f6' : (data.strokeColor ?? '#374151');\n const width = data.strokeWidth ?? 2;\n\n const segments = buildEdgePath(edge.type, endpoints, data.waypoints, data.bezierControls);\n\n // Draw visible line\n line.clear();\n this._drawPath(line, segments, color, width, data.lineStyle, data.dashDensity);\n\n // Presentation animation: a bright gradient-like pulse travels from source\n // to target. A short dashed segment plus soft outer stroke gives the pulse\n // a leading highlight and fading tail without requiring SVG filters.\n animation.clear();\n if (presentation && data.animated) {\n const pattern = [Math.max(18, width * 12), Math.max(90, width * 45)];\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0x60a5fa, width: width + 5, alpha: 0.18, cap: 'round' as const });\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0x38bdf8, width: width + 2, alpha: 0.55, cap: 'round' as const });\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0xffffff, width: Math.max(1, width * 0.7), alpha: 0.9, cap: 'round' as const });\n }\n\n // Draw markers — use curve tangent for accurate arrow direction\n if (data.markerStart && data.markerStart !== 'none' && segments.length >= 2) {\n const tip = segments[0];\n const next = segments[1];\n // For curves the tangent at t=0 is tip→cp1; for lines it's tip→next\n const fromX = next.type === 'C' ? next.cp1x! : next.x;\n const fromY = next.type === 'C' ? next.cp1y! : next.y;\n const angle = angleBetween(fromX, fromY, tip.x, tip.y);\n drawMarker(line, data.markerStart, tip.x, tip.y, angle, color);\n }\n if (data.markerEnd && data.markerEnd !== 'none' && segments.length >= 2) {\n const tip = segments[segments.length - 1];\n // For curves the tangent at t=1 is cp2→endpoint\n const fromX = tip.type === 'C' ? tip.cp2x! : segments[segments.length - 2].x;\n const fromY = tip.type === 'C' ? tip.cp2y! : segments[segments.length - 2].y;\n const angle = angleBetween(fromX, fromY, tip.x, tip.y);\n drawMarker(line, data.markerEnd, tip.x, tip.y, angle, color);\n }\n\n // Wider invisible hit area\n hitArea.clear();\n this._drawPath(hitArea, segments, '#000000', Math.max(width + 10, 14), 'solid');\n hitArea.alpha = 0.001;\n\n // Edge label\n if (data.labelText) {\n const center = getPathCenter(segments);\n if (!display.label) {\n // Background chip drawn first so it sits behind the text.\n const labelBg = new Graphics();\n labelBg.label = 'edge-label-bg';\n display.container.addChild(labelBg);\n display.labelBg = labelBg;\n\n const style = new TextStyle({\n fontFamily: data.labelFontFamily ?? 'system-ui, -apple-system, sans-serif',\n fontSize: data.labelFontSize ?? 12,\n fill: color,\n });\n display.label = new Text({ text: data.labelText, style });\n display.label.anchor.set(0.5, 0.5);\n display.container.addChild(display.label);\n }\n display.label.text = data.labelText;\n const lx = center.x;\n const ly = center.y - 10;\n display.label.position.set(lx, ly);\n (display.label.style as TextStyle).fill = color;\n\n // Draw a rounded background chip behind the label so the line / waypoints\n // don't show through the text.\n if (display.labelBg) {\n const padX = 5;\n const padY = 2;\n const tw = display.label.width + padX * 2;\n const th = display.label.height + padY * 2;\n display.labelBg.clear();\n display.labelBg\n .roundRect(lx - tw / 2, ly - th / 2, tw, th, 4)\n .fill({ color: 0xffffff, alpha: 0.92 });\n }\n } else {\n if (display.label) display.label.text = '';\n if (display.labelBg) display.labelBg.clear();\n }\n }\n\n private _drawPath(\n g: Graphics,\n segs: PathSegment[],\n color: string,\n width: number,\n lineStyle?: string,\n dashDensity?: string,\n ): void {\n const dash = getDashPattern(lineStyle, dashDensity, width);\n if (dash) {\n const offset = lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n drawDashedPath(g, segs as PathSeg[], dash, offset);\n g.stroke({ color, width, cap: 'round' as const });\n } else {\n for (const seg of segs) {\n switch (seg.type) {\n case 'M': g.moveTo(seg.x, seg.y); break;\n case 'L': g.lineTo(seg.x, seg.y); break;\n case 'C': g.bezierCurveTo(seg.cp1x!, seg.cp1y!, seg.cp2x!, seg.cp2y!, seg.x, seg.y); break;\n case 'Q': g.quadraticCurveTo(seg.cp1x!, seg.cp1y!, seg.x, seg.y); break;\n }\n }\n g.stroke({ color, width });\n }\n }\n\n destroy(): void {\n for (const [, display] of this.edges) {\n display.container.destroy({ children: true });\n }\n this.edges.clear();\n this.edgeLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EdgeRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/edges/EdgeRenderer.ts"],"sourcesContent":["import { Container, Graphics, Text, TextStyle } from 'pixi.js';\nimport type { FlowEdge, FlowNode } from '../types';\nimport { buildEdgePath, getPathCenter, resolveEdgeEndpoints, type PathSegment, type EdgeEndpoints } from './edgePaths';\nimport { drawMarker, angleBetween } from './edgeMarkers';\nimport { drawDashedPath, type PathSeg } from '../utils/dashedLine';\nimport { resolveThemeColor } from '../utils/themeColor';\n\ninterface EdgeDisplay {\n container: Container;\n line: Graphics;\n animation: Graphics;\n hitArea: Graphics;\n labelBg: Graphics | null;\n label: Text | null;\n edgeId: string;\n}\n\nfunction getDashPattern(style?: string, density?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n const base = style === 'dotted' ? width : width * 3;\n const gap = density === 'dense' ? width : density === 'sparse' ? width * 4 : width * 2;\n return [base, gap];\n}\n\n/**\n * Manages PixiJS display objects for all edges.\n */\nexport class EdgeRenderer {\n private world: Container;\n private edgeLayer: Container;\n private edges = new Map<string, EdgeDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.edgeLayer = new Container({ label: 'edges' });\n // Edges below nodes\n this.world.addChildAt(this.edgeLayer, 0);\n }\n\n sync(\n flowEdges: FlowEdge[],\n nodeMap: Map<string, FlowNode>,\n selectedIds: Set<string>,\n hoveredId: string | null,\n options?: { presentation?: boolean },\n ): void {\n const seen = new Set<string>();\n\n for (const edge of flowEdges) {\n seen.add(edge.id);\n const endpoints = resolveEdgeEndpoints(edge, nodeMap);\n if (!endpoints) continue;\n\n let display = this.edges.get(edge.id);\n if (!display) {\n display = this._createEdge(edge);\n this.edges.set(edge.id, display);\n }\n this._updateEdge(\n display,\n edge,\n endpoints,\n selectedIds.has(edge.id),\n hoveredId === edge.id,\n options?.presentation ?? false,\n );\n }\n\n for (const [id, display] of this.edges) {\n if (!seen.has(id)) {\n this.edgeLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.edges.delete(id);\n }\n }\n }\n\n private _createEdge(edge: FlowEdge): EdgeDisplay {\n const container = new Container({ label: `edge-${edge.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'edge-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0;\n container.addChild(hitArea);\n\n const line = new Graphics();\n line.label = 'edge-line';\n container.addChild(line);\n\n const animation = new Graphics();\n animation.label = 'edge-animation';\n container.addChild(animation);\n\n this.edgeLayer.addChild(container);\n return { container, line, animation, hitArea, labelBg: null, label: null, edgeId: edge.id };\n }\n\n private _updateEdge(\n display: EdgeDisplay,\n edge: FlowEdge,\n endpoints: EdgeEndpoints,\n selected: boolean,\n hovered: boolean,\n presentation: boolean,\n ): void {\n const { line, animation, hitArea } = display;\n const data = edge.data;\n const color = selected ? '#3b82f6' : resolveThemeColor(data.strokeColor, '#374151');\n const width = data.strokeWidth ?? 2;\n\n const segments = buildEdgePath(edge.type, endpoints, data.waypoints, data.bezierControls);\n\n // Draw visible line\n line.clear();\n this._drawPath(line, segments, color, width, data.lineStyle, data.dashDensity);\n\n // Presentation animation: a bright gradient-like pulse travels from source\n // to target. A short dashed segment plus soft outer stroke gives the pulse\n // a leading highlight and fading tail without requiring SVG filters.\n animation.clear();\n if (presentation && data.animated) {\n const pattern = [Math.max(18, width * 12), Math.max(90, width * 45)];\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0x60a5fa, width: width + 5, alpha: 0.18, cap: 'round' as const });\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0x38bdf8, width: width + 2, alpha: 0.55, cap: 'round' as const });\n drawDashedPath(animation, segments as PathSeg[], pattern, -this._dynamicOffset * 2.2);\n animation.stroke({ color: 0xffffff, width: Math.max(1, width * 0.7), alpha: 0.9, cap: 'round' as const });\n }\n\n // Draw markers — use curve tangent for accurate arrow direction\n if (data.markerStart && data.markerStart !== 'none' && segments.length >= 2) {\n const tip = segments[0];\n const next = segments[1];\n // For curves the tangent at t=0 is tip→cp1; for lines it's tip→next\n const fromX = next.type === 'C' ? next.cp1x! : next.x;\n const fromY = next.type === 'C' ? next.cp1y! : next.y;\n const angle = angleBetween(fromX, fromY, tip.x, tip.y);\n drawMarker(line, data.markerStart, tip.x, tip.y, angle, color);\n }\n if (data.markerEnd && data.markerEnd !== 'none' && segments.length >= 2) {\n const tip = segments[segments.length - 1];\n // For curves the tangent at t=1 is cp2→endpoint\n const fromX = tip.type === 'C' ? tip.cp2x! : segments[segments.length - 2].x;\n const fromY = tip.type === 'C' ? tip.cp2y! : segments[segments.length - 2].y;\n const angle = angleBetween(fromX, fromY, tip.x, tip.y);\n drawMarker(line, data.markerEnd, tip.x, tip.y, angle, color);\n }\n\n // Wider invisible hit area\n hitArea.clear();\n this._drawPath(hitArea, segments, '#000000', Math.max(width + 10, 14), 'solid');\n hitArea.alpha = 0.001;\n\n // Edge label\n if (data.labelText) {\n const center = getPathCenter(segments);\n if (!display.label) {\n // Background chip drawn first so it sits behind the text.\n const labelBg = new Graphics();\n labelBg.label = 'edge-label-bg';\n display.container.addChild(labelBg);\n display.labelBg = labelBg;\n\n const style = new TextStyle({\n fontFamily: data.labelFontFamily ?? 'system-ui, -apple-system, sans-serif',\n fontSize: data.labelFontSize ?? 12,\n fill: color,\n });\n display.label = new Text({ text: data.labelText, style });\n display.label.anchor.set(0.5, 0.5);\n display.container.addChild(display.label);\n }\n display.label.text = data.labelText;\n const lx = center.x;\n const ly = center.y - 10;\n display.label.position.set(lx, ly);\n (display.label.style as TextStyle).fill = color;\n\n // Draw a rounded background chip behind the label so the line / waypoints\n // don't show through the text.\n if (display.labelBg) {\n const padX = 5;\n const padY = 2;\n const tw = display.label.width + padX * 2;\n const th = display.label.height + padY * 2;\n display.labelBg.clear();\n display.labelBg\n .roundRect(lx - tw / 2, ly - th / 2, tw, th, 4)\n .fill({ color: 0xffffff, alpha: 0.92 });\n }\n } else {\n if (display.label) display.label.text = '';\n if (display.labelBg) display.labelBg.clear();\n }\n }\n\n private _drawPath(\n g: Graphics,\n segs: PathSegment[],\n color: string,\n width: number,\n lineStyle?: string,\n dashDensity?: string,\n ): void {\n const dash = getDashPattern(lineStyle, dashDensity, width);\n if (dash) {\n const offset = lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n drawDashedPath(g, segs as PathSeg[], dash, offset);\n g.stroke({ color, width, cap: 'round' as const });\n } else {\n for (const seg of segs) {\n switch (seg.type) {\n case 'M': g.moveTo(seg.x, seg.y); break;\n case 'L': g.lineTo(seg.x, seg.y); break;\n case 'C': g.bezierCurveTo(seg.cp1x!, seg.cp1y!, seg.cp2x!, seg.cp2y!, seg.x, seg.y); break;\n case 'Q': g.quadraticCurveTo(seg.cp1x!, seg.cp1y!, seg.x, seg.y); break;\n }\n }\n g.stroke({ color, width });\n }\n }\n\n destroy(): void {\n for (const [, display] of this.edges) {\n display.container.destroy({ children: true });\n }\n this.edges.clear();\n this.edgeLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
@@ -45,15 +45,15 @@ function O(s) {
45
45
  const a = [], e = (i) => {
46
46
  const l = (i.data.label ?? "").trim();
47
47
  return l ? l.replace(/\s+/g, " ") : i.type === "mediaNode" ? `(${i.data.mediaKind ?? "media"})` : `(${i.type})`;
48
- }, n = (i, l, u) => {
48
+ }, n = (i, l, h) => {
49
49
  const m = s.canvases[i];
50
50
  if (!m) return;
51
- const w = new Map(m.nodes.map((t) => [t.id, t])), o = /* @__PURE__ */ new Map();
51
+ const b = new Map(m.nodes.map((t) => [t.id, t])), o = /* @__PURE__ */ new Map();
52
52
  for (const t of m.nodes) {
53
- const r = t.parentId && w.has(t.parentId) ? t.parentId : void 0, d = o.get(r) ?? [];
53
+ const r = t.parentId && b.has(t.parentId) ? t.parentId : void 0, d = o.get(r) ?? [];
54
54
  d.push(t), o.set(r, d);
55
55
  }
56
- const f = (t, r) => {
56
+ const p = (t, r) => {
57
57
  const d = " ".repeat(r), c = t.data.isGroup || t.type === "flowGroup" || t.type === "geometryGroup" ? `**${e(t)}**` : e(t);
58
58
  if (a.push(`${d}- ${c}`), t.type === "mediaNode" && t.data.mediaKind) {
59
59
  const g = t.data.mediaKind;
@@ -67,24 +67,24 @@ function O(s) {
67
67
  }
68
68
  }
69
69
  const v = o.get(t.id) ?? [];
70
- for (const g of v) f(g, r + 1);
71
- const b = t.data.childCanvasId;
72
- b && s.canvases[b] && !u.has(b) && (u.add(b), n(b, l + 1, u));
73
- }, h = o.get(void 0) ?? [];
74
- for (const t of h) f(t, 0);
70
+ for (const g of v) p(g, r + 1);
71
+ const w = t.data.childCanvasId;
72
+ w && s.canvases[w] && !h.has(w) && (h.add(w), n(w, l + 1, h));
73
+ }, u = o.get(void 0) ?? [];
74
+ for (const t of u) p(t, 0);
75
75
  if (m.edges.length > 0) {
76
76
  a.push(""), a.push(`${"#".repeat(Math.min(6, l + 1))} 连接关系`);
77
77
  for (const t of m.edges) {
78
- const r = w.get(t.source), d = w.get(t.target);
78
+ const r = b.get(t.source), d = b.get(t.target);
79
79
  if (!r || !d) continue;
80
80
  const c = t.data.labelText ? ` (${t.data.labelText})` : "";
81
81
  a.push(`- ${e(r)} → ${e(d)}${c}`);
82
82
  }
83
83
  }
84
- }, p = /* @__PURE__ */ new Set([$]);
85
- a.push("# 流程图"), a.push(""), n($, 1, p);
84
+ }, f = /* @__PURE__ */ new Set([$]);
85
+ a.push("# 流程图"), a.push(""), n($, 1, f);
86
86
  for (const i of Object.keys(s.canvases))
87
- p.has(i) || (p.add(i), a.push(""), a.push(`## 画布 ${i}`), a.push(""), n(i, 2, p));
87
+ f.has(i) || (f.add(i), a.push(""), a.push(`## 画布 ${i}`), a.push(""), n(i, 2, f));
88
88
  return a.join(`
89
89
  `).replace(/\n{3,}/g, `
90
90
 
@@ -94,16 +94,16 @@ function O(s) {
94
94
  function R(s) {
95
95
  const a = s.split(`
96
96
  `).map((o) => o.trim()).filter((o) => o && !o.startsWith("%%")), e = /* @__PURE__ */ new Map(), n = [];
97
- let p = !1;
97
+ let f = !1;
98
98
  for (const o of a) {
99
99
  if (/^(graph|flowchart)\s+(LR|RL)/i.test(o)) {
100
- p = !0;
100
+ f = !0;
101
101
  continue;
102
102
  }
103
103
  if (/^(graph|flowchart)\s+/i.test(o)) continue;
104
- const f = o.match(/^(\w+)(?:\[([^\]]*)\])?\s*(-->|---|-\.->|==>)(?:\|([^|]*)\|)?\s*(\w+)(?:\[([^\]]*)\])?/);
105
- if (f) {
106
- const [, t, r, , d, c, v] = f;
104
+ const p = o.match(/^(\w+)(?:\[([^\]]*)\])?\s*(-->|---|-\.->|==>)(?:\|([^|]*)\|)?\s*(\w+)(?:\[([^\]]*)\])?/);
105
+ if (p) {
106
+ const [, t, r, , d, c, v] = p;
107
107
  r && !e.has(t) && e.set(t, {
108
108
  id: t,
109
109
  label: r
@@ -123,45 +123,45 @@ function R(s) {
123
123
  });
124
124
  continue;
125
125
  }
126
- const h = o.match(/^(\w+)\[([^\]]*)\]/);
127
- if (h) {
128
- const [, t, r] = h;
126
+ const u = o.match(/^(\w+)\[([^\]]*)\]/);
127
+ if (u) {
128
+ const [, t, r] = u;
129
129
  e.has(t) || e.set(t, {
130
130
  id: t,
131
131
  label: r
132
132
  });
133
133
  }
134
134
  }
135
- const i = [...e.keys()], l = p ? i.length : Math.ceil(Math.sqrt(i.length)), u = {
135
+ const i = [...e.keys()], l = f ? i.length : Math.ceil(Math.sqrt(i.length)), h = {
136
136
  x: 200,
137
137
  y: 120
138
- }, m = i.map((o, f) => {
139
- const h = f % l, t = Math.floor(f / l), r = e.get(o);
138
+ }, m = i.map((o, p) => {
139
+ const u = p % l, t = Math.floor(p / l), r = e.get(o);
140
140
  return {
141
141
  id: r.id,
142
142
  type: "shapeRoundRect",
143
143
  position: {
144
- x: 100 + h * u.x,
145
- y: 100 + t * u.y
144
+ x: 100 + u * h.x,
145
+ y: 100 + t * h.y
146
146
  },
147
147
  width: 140,
148
148
  height: 60,
149
149
  data: {
150
150
  label: r.label,
151
- fill: "#ffffff",
152
- stroke: "#374151",
151
+ fill: "theme:base-100",
152
+ stroke: "theme:base-content",
153
153
  strokeWidth: 2,
154
- color: "#111827",
154
+ color: "theme:base-content",
155
155
  fontSize: 14
156
156
  }
157
157
  };
158
- }), w = n.map((o) => ({
158
+ }), b = n.map((o) => ({
159
159
  id: N("edge"),
160
160
  source: o.from,
161
161
  target: o.to,
162
162
  type: "smoothstep",
163
163
  data: {
164
- strokeColor: "#374151",
164
+ strokeColor: "theme:base-content",
165
165
  strokeWidth: 2,
166
166
  lineStyle: "solid",
167
167
  markerEnd: "arrowclosed",
@@ -171,7 +171,7 @@ function R(s) {
171
171
  return {
172
172
  canvases: { [$]: {
173
173
  nodes: m,
174
- edges: w,
174
+ edges: b,
175
175
  lines: []
176
176
  } },
177
177
  stack: [$]
@@ -1 +1 @@
1
- {"version":3,"file":"useFlowImportExport.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useFlowImportExport.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowDocument, FlowCanvasData, FlowNode, FlowEdge, FlowLine } from '../types';\nimport { createEmptyDocument, ROOT_CANVAS_ID } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\n\nconst PERSIST_VERSION = 1;\n\ninterface SerializedDocument {\n version: number;\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n title?: string;\n}\n\n/**\n * Sanitize a project title into a safe file base name, falling back to a\n * default when empty. Shared by all export paths so filenames stay consistent.\n */\nexport function safeFileBaseName(title: string | undefined, fallback = 'flowchart'): string {\n const name = (title ?? '').trim().replace(/[\\\\/:*?\"<>|]+/g, '-').replace(/\\s+/g, ' ').trim();\n return name || fallback;\n}\n\n/**\n * Serialize/deserialize FlowDocument to/from JSON.\n * Also includes Mermaid flowchart import.\n */\nexport function useFlowImportExport() {\n const { doc, setDoc } = useFlowContext();\n\n const exportJSON = useCallback((): string => {\n const serialized: SerializedDocument = {\n version: PERSIST_VERSION,\n canvases: doc.canvases,\n stack: doc.stack,\n title: doc.title,\n };\n return JSON.stringify(serialized, null, 2);\n }, [doc]);\n\n const importJSON = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as SerializedDocument;\n if (!parsed.canvases || !parsed.stack) throw new Error('Invalid document format');\n setDoc({\n canvases: parsed.canvases,\n stack: parsed.stack,\n title: parsed.title,\n });\n } catch (err) {\n console.error('Failed to import JSON:', err);\n }\n }, [setDoc]);\n\n const importMermaid = useCallback((mermaidCode: string) => {\n const doc = parseMermaidFlowchart(mermaidCode);\n setDoc(doc);\n }, [setDoc]);\n\n const exportMarkdown = useCallback((): string => {\n return documentToMarkdown(doc);\n }, [doc]);\n\n const clearDocument = useCallback(() => {\n setDoc(createEmptyDocument());\n }, [setDoc]);\n\n return { exportJSON, importJSON, importMermaid, exportMarkdown, clearDocument };\n}\n\n/**\n * Render a FlowDocument as a Markdown outline describing the node hierarchy\n * and connections. Groups become sections with their children nested beneath;\n * edges are listed as a connection summary per canvas. Sub-canvases (drill-down\n * nodes) are rendered as nested sections.\n */\nfunction documentToMarkdown(doc: FlowDocument): string {\n const lines: string[] = [];\n\n const nodeLabel = (n: FlowNode): string => {\n const raw = (n.data.label ?? '').trim();\n if (raw) return raw.replace(/\\s+/g, ' ');\n if (n.type === 'mediaNode') return `(${n.data.mediaKind ?? 'media'})`;\n return `(${n.type})`;\n };\n\n const renderCanvas = (canvasId: string, headingLevel: number, seenCanvases: Set<string>) => {\n const canvas = doc.canvases[canvasId];\n if (!canvas) return;\n\n // Index nodes by id and by parent for hierarchy traversal.\n const byId = new Map(canvas.nodes.map((n) => [n.id, n]));\n const childrenOf = new Map<string | undefined, FlowNode[]>();\n for (const n of canvas.nodes) {\n const key = n.parentId && byId.has(n.parentId) ? n.parentId : undefined;\n const list = childrenOf.get(key) ?? [];\n list.push(n);\n childrenOf.set(key, list);\n }\n\n const emitNode = (node: FlowNode, depth: number) => {\n const indent = ' '.repeat(depth);\n const isGroup = node.data.isGroup || node.type === 'flowGroup' || node.type === 'geometryGroup';\n const bullet = isGroup ? `**${nodeLabel(node)}**` : nodeLabel(node);\n lines.push(`${indent}- ${bullet}`);\n\n // Media content (markdown/data/etc.) as a short description line.\n if (node.type === 'mediaNode' && node.data.mediaKind) {\n const kind = node.data.mediaKind;\n if (kind === 'data' && node.data.dataConfig) {\n const cfg = node.data.dataConfig;\n const cols = cfg.columns.map((c) => c.label ?? c.key).join(', ');\n lines.push(`${indent} - 数据表:${cfg.rows.length} 行 · 列(${cols})`);\n } else if (node.data.mediaContent && kind !== 'image' && kind !== 'model3d') {\n const preview = node.data.mediaContent.trim().split('\\n')[0].slice(0, 80);\n if (preview) lines.push(`${indent} - ${kind}: ${preview}`);\n }\n }\n\n // Recurse into visual group children.\n const kids = childrenOf.get(node.id) ?? [];\n for (const kid of kids) emitNode(kid, depth + 1);\n\n // Recurse into a drill-down sub-canvas, if any.\n const childCanvasId = node.data.childCanvasId;\n if (childCanvasId && doc.canvases[childCanvasId] && !seenCanvases.has(childCanvasId)) {\n seenCanvases.add(childCanvasId);\n renderCanvas(childCanvasId, headingLevel + 1, seenCanvases);\n }\n };\n\n const roots = childrenOf.get(undefined) ?? [];\n for (const root of roots) emitNode(root, 0);\n\n // Connections summary.\n if (canvas.edges.length > 0) {\n lines.push('');\n lines.push(`${'#'.repeat(Math.min(6, headingLevel + 1))} 连接关系`);\n for (const edge of canvas.edges) {\n const from = byId.get(edge.source);\n const to = byId.get(edge.target);\n if (!from || !to) continue;\n const edgeLabel = edge.data.labelText ? ` (${edge.data.labelText})` : '';\n lines.push(`- ${nodeLabel(from)} → ${nodeLabel(to)}${edgeLabel}`);\n }\n }\n };\n\n const seen = new Set<string>([ROOT_CANVAS_ID]);\n lines.push('# 流程图');\n lines.push('');\n renderCanvas(ROOT_CANVAS_ID, 1, seen);\n\n // Any orphan canvases not reached via drill-down nodes.\n for (const canvasId of Object.keys(doc.canvases)) {\n if (seen.has(canvasId)) continue;\n seen.add(canvasId);\n lines.push('');\n lines.push(`## 画布 ${canvasId}`);\n lines.push('');\n renderCanvas(canvasId, 2, seen);\n }\n\n return lines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim() + '\\n';\n}\n\n/**\n * Simple Mermaid flowchart parser.\n * Handles basic `graph TD` / `flowchart LR` syntax with node definitions and edges.\n */\nfunction parseMermaidFlowchart(code: string): FlowDocument {\n const lines = code.split('\\n').map(l => l.trim()).filter(l => l && !l.startsWith('%%'));\n\n const nodeMap = new Map<string, { id: string; label: string }>();\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n\n let isHorizontal = false;\n\n for (const line of lines) {\n // Detect direction\n if (/^(graph|flowchart)\\s+(LR|RL)/i.test(line)) {\n isHorizontal = true;\n continue;\n }\n if (/^(graph|flowchart)\\s+/i.test(line)) continue;\n\n // Edge patterns: A --> B, A -->|label| B, A --- B\n const edgeMatch = line.match(/^(\\w+)(?:\\[([^\\]]*)\\])?\\s*(-->|---|-\\.->|==>)(?:\\|([^|]*)\\|)?\\s*(\\w+)(?:\\[([^\\]]*)\\])?/);\n if (edgeMatch) {\n const [, fromId, fromLabel, , edgeLabel, toId, toLabel] = edgeMatch;\n if (fromLabel && !nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromLabel });\n if (toLabel && !nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toLabel });\n if (!nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromId });\n if (!nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toId });\n edges.push({ from: fromId, to: toId, label: edgeLabel?.trim() });\n continue;\n }\n\n // Standalone node: A[Label]\n const nodeMatch = line.match(/^(\\w+)\\[([^\\]]*)\\]/);\n if (nodeMatch) {\n const [, id, label] = nodeMatch;\n if (!nodeMap.has(id)) nodeMap.set(id, { id, label });\n }\n }\n\n // Layout: simple grid placement\n const nodeIds = [...nodeMap.keys()];\n const cols = isHorizontal ? nodeIds.length : Math.ceil(Math.sqrt(nodeIds.length));\n const spacing = { x: 200, y: 120 };\n\n const nodes: FlowNode[] = nodeIds.map((id, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const data = nodeMap.get(id)!;\n return {\n id: data.id,\n type: 'shapeRoundRect' as const,\n position: { x: 100 + col * spacing.x, y: 100 + row * spacing.y },\n width: 140,\n height: 60,\n data: {\n label: data.label,\n fill: '#ffffff',\n stroke: '#374151',\n strokeWidth: 2,\n color: '#111827',\n fontSize: 14,\n },\n };\n });\n\n const flowEdges: FlowEdge[] = edges.map((e) => ({\n id: generateId('edge'),\n source: e.from,\n target: e.to,\n type: 'smoothstep' as const,\n data: {\n strokeColor: '#374151',\n strokeWidth: 2,\n lineStyle: 'solid' as const,\n markerEnd: 'arrowclosed' as const,\n labelText: e.label,\n },\n }));\n\n return {\n canvases: {\n [ROOT_CANVAS_ID]: { nodes, edges: flowEdges, lines: [] },\n },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Export the PixiJS canvas as PNG data URL.\n */\nexport async function exportCanvasToPNG(canvas: HTMLCanvasElement): Promise<string> {\n return canvas.toDataURL('image/png');\n}\n\n/**\n * Download a data URL as a file.\n */\nexport function downloadDataURL(dataUrl: string, filename: string): void {\n const a = document.createElement('a');\n a.href = dataUrl;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useFlowImportExport.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useFlowImportExport.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowDocument, FlowCanvasData, FlowNode, FlowEdge, FlowLine } from '../types';\nimport { createEmptyDocument, ROOT_CANVAS_ID } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\n\nconst PERSIST_VERSION = 1;\n\ninterface SerializedDocument {\n version: number;\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n title?: string;\n}\n\n/**\n * Sanitize a project title into a safe file base name, falling back to a\n * default when empty. Shared by all export paths so filenames stay consistent.\n */\nexport function safeFileBaseName(title: string | undefined, fallback = 'flowchart'): string {\n const name = (title ?? '').trim().replace(/[\\\\/:*?\"<>|]+/g, '-').replace(/\\s+/g, ' ').trim();\n return name || fallback;\n}\n\n/**\n * Serialize/deserialize FlowDocument to/from JSON.\n * Also includes Mermaid flowchart import.\n */\nexport function useFlowImportExport() {\n const { doc, setDoc } = useFlowContext();\n\n const exportJSON = useCallback((): string => {\n const serialized: SerializedDocument = {\n version: PERSIST_VERSION,\n canvases: doc.canvases,\n stack: doc.stack,\n title: doc.title,\n };\n return JSON.stringify(serialized, null, 2);\n }, [doc]);\n\n const importJSON = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as SerializedDocument;\n if (!parsed.canvases || !parsed.stack) throw new Error('Invalid document format');\n setDoc({\n canvases: parsed.canvases,\n stack: parsed.stack,\n title: parsed.title,\n });\n } catch (err) {\n console.error('Failed to import JSON:', err);\n }\n }, [setDoc]);\n\n const importMermaid = useCallback((mermaidCode: string) => {\n const doc = parseMermaidFlowchart(mermaidCode);\n setDoc(doc);\n }, [setDoc]);\n\n const exportMarkdown = useCallback((): string => {\n return documentToMarkdown(doc);\n }, [doc]);\n\n const clearDocument = useCallback(() => {\n setDoc(createEmptyDocument());\n }, [setDoc]);\n\n return { exportJSON, importJSON, importMermaid, exportMarkdown, clearDocument };\n}\n\n/**\n * Render a FlowDocument as a Markdown outline describing the node hierarchy\n * and connections. Groups become sections with their children nested beneath;\n * edges are listed as a connection summary per canvas. Sub-canvases (drill-down\n * nodes) are rendered as nested sections.\n */\nfunction documentToMarkdown(doc: FlowDocument): string {\n const lines: string[] = [];\n\n const nodeLabel = (n: FlowNode): string => {\n const raw = (n.data.label ?? '').trim();\n if (raw) return raw.replace(/\\s+/g, ' ');\n if (n.type === 'mediaNode') return `(${n.data.mediaKind ?? 'media'})`;\n return `(${n.type})`;\n };\n\n const renderCanvas = (canvasId: string, headingLevel: number, seenCanvases: Set<string>) => {\n const canvas = doc.canvases[canvasId];\n if (!canvas) return;\n\n // Index nodes by id and by parent for hierarchy traversal.\n const byId = new Map(canvas.nodes.map((n) => [n.id, n]));\n const childrenOf = new Map<string | undefined, FlowNode[]>();\n for (const n of canvas.nodes) {\n const key = n.parentId && byId.has(n.parentId) ? n.parentId : undefined;\n const list = childrenOf.get(key) ?? [];\n list.push(n);\n childrenOf.set(key, list);\n }\n\n const emitNode = (node: FlowNode, depth: number) => {\n const indent = ' '.repeat(depth);\n const isGroup = node.data.isGroup || node.type === 'flowGroup' || node.type === 'geometryGroup';\n const bullet = isGroup ? `**${nodeLabel(node)}**` : nodeLabel(node);\n lines.push(`${indent}- ${bullet}`);\n\n // Media content (markdown/data/etc.) as a short description line.\n if (node.type === 'mediaNode' && node.data.mediaKind) {\n const kind = node.data.mediaKind;\n if (kind === 'data' && node.data.dataConfig) {\n const cfg = node.data.dataConfig;\n const cols = cfg.columns.map((c) => c.label ?? c.key).join(', ');\n lines.push(`${indent} - 数据表:${cfg.rows.length} 行 · 列(${cols})`);\n } else if (node.data.mediaContent && kind !== 'image' && kind !== 'model3d') {\n const preview = node.data.mediaContent.trim().split('\\n')[0].slice(0, 80);\n if (preview) lines.push(`${indent} - ${kind}: ${preview}`);\n }\n }\n\n // Recurse into visual group children.\n const kids = childrenOf.get(node.id) ?? [];\n for (const kid of kids) emitNode(kid, depth + 1);\n\n // Recurse into a drill-down sub-canvas, if any.\n const childCanvasId = node.data.childCanvasId;\n if (childCanvasId && doc.canvases[childCanvasId] && !seenCanvases.has(childCanvasId)) {\n seenCanvases.add(childCanvasId);\n renderCanvas(childCanvasId, headingLevel + 1, seenCanvases);\n }\n };\n\n const roots = childrenOf.get(undefined) ?? [];\n for (const root of roots) emitNode(root, 0);\n\n // Connections summary.\n if (canvas.edges.length > 0) {\n lines.push('');\n lines.push(`${'#'.repeat(Math.min(6, headingLevel + 1))} 连接关系`);\n for (const edge of canvas.edges) {\n const from = byId.get(edge.source);\n const to = byId.get(edge.target);\n if (!from || !to) continue;\n const edgeLabel = edge.data.labelText ? ` (${edge.data.labelText})` : '';\n lines.push(`- ${nodeLabel(from)} → ${nodeLabel(to)}${edgeLabel}`);\n }\n }\n };\n\n const seen = new Set<string>([ROOT_CANVAS_ID]);\n lines.push('# 流程图');\n lines.push('');\n renderCanvas(ROOT_CANVAS_ID, 1, seen);\n\n // Any orphan canvases not reached via drill-down nodes.\n for (const canvasId of Object.keys(doc.canvases)) {\n if (seen.has(canvasId)) continue;\n seen.add(canvasId);\n lines.push('');\n lines.push(`## 画布 ${canvasId}`);\n lines.push('');\n renderCanvas(canvasId, 2, seen);\n }\n\n return lines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim() + '\\n';\n}\n\n/**\n * Simple Mermaid flowchart parser.\n * Handles basic `graph TD` / `flowchart LR` syntax with node definitions and edges.\n */\nfunction parseMermaidFlowchart(code: string): FlowDocument {\n const lines = code.split('\\n').map(l => l.trim()).filter(l => l && !l.startsWith('%%'));\n\n const nodeMap = new Map<string, { id: string; label: string }>();\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n\n let isHorizontal = false;\n\n for (const line of lines) {\n // Detect direction\n if (/^(graph|flowchart)\\s+(LR|RL)/i.test(line)) {\n isHorizontal = true;\n continue;\n }\n if (/^(graph|flowchart)\\s+/i.test(line)) continue;\n\n // Edge patterns: A --> B, A -->|label| B, A --- B\n const edgeMatch = line.match(/^(\\w+)(?:\\[([^\\]]*)\\])?\\s*(-->|---|-\\.->|==>)(?:\\|([^|]*)\\|)?\\s*(\\w+)(?:\\[([^\\]]*)\\])?/);\n if (edgeMatch) {\n const [, fromId, fromLabel, , edgeLabel, toId, toLabel] = edgeMatch;\n if (fromLabel && !nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromLabel });\n if (toLabel && !nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toLabel });\n if (!nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromId });\n if (!nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toId });\n edges.push({ from: fromId, to: toId, label: edgeLabel?.trim() });\n continue;\n }\n\n // Standalone node: A[Label]\n const nodeMatch = line.match(/^(\\w+)\\[([^\\]]*)\\]/);\n if (nodeMatch) {\n const [, id, label] = nodeMatch;\n if (!nodeMap.has(id)) nodeMap.set(id, { id, label });\n }\n }\n\n // Layout: simple grid placement\n const nodeIds = [...nodeMap.keys()];\n const cols = isHorizontal ? nodeIds.length : Math.ceil(Math.sqrt(nodeIds.length));\n const spacing = { x: 200, y: 120 };\n\n const nodes: FlowNode[] = nodeIds.map((id, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const data = nodeMap.get(id)!;\n return {\n id: data.id,\n type: 'shapeRoundRect' as const,\n position: { x: 100 + col * spacing.x, y: 100 + row * spacing.y },\n width: 140,\n height: 60,\n data: {\n label: data.label,\n fill: 'theme:base-100',\n stroke: 'theme:base-content',\n strokeWidth: 2,\n color: 'theme:base-content',\n fontSize: 14,\n },\n };\n });\n\n const flowEdges: FlowEdge[] = edges.map((e) => ({\n id: generateId('edge'),\n source: e.from,\n target: e.to,\n type: 'smoothstep' as const,\n data: {\n strokeColor: 'theme:base-content',\n strokeWidth: 2,\n lineStyle: 'solid' as const,\n markerEnd: 'arrowclosed' as const,\n labelText: e.label,\n },\n }));\n\n return {\n canvases: {\n [ROOT_CANVAS_ID]: { nodes, edges: flowEdges, lines: [] },\n },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Export the PixiJS canvas as PNG data URL.\n */\nexport async function exportCanvasToPNG(canvas: HTMLCanvasElement): Promise<string> {\n return canvas.toDataURL('image/png');\n}\n\n/**\n * Download a data URL as a file.\n */\nexport function downloadDataURL(dataUrl: string, filename: string): void {\n const a = document.createElement('a');\n a.href = dataUrl;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n}\n"],"mappings":"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"}