flowcloudai-ui 0.1.7 → 0.1.8
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.
- package/dist/index.css +7 -3
- package/dist/index.d.ts +25 -52
- package/dist/index.js +405 -504
- package/package.json +3 -1
package/dist/index.css
CHANGED
|
@@ -467,7 +467,7 @@
|
|
|
467
467
|
display: flex;
|
|
468
468
|
flex-direction: column;
|
|
469
469
|
width: var(--sidebar-width);
|
|
470
|
-
height:
|
|
470
|
+
height: 100%;
|
|
471
471
|
background: var(--fc-color-bg-secondary);
|
|
472
472
|
border-right: 1px solid var(--fc-color-border);
|
|
473
473
|
overflow: hidden;
|
|
@@ -507,6 +507,7 @@
|
|
|
507
507
|
padding: var(--fc-space-sm, 8px) 0;
|
|
508
508
|
}
|
|
509
509
|
.fc-sidebar__footer {
|
|
510
|
+
flex-shrink: 0;
|
|
510
511
|
padding: var(--fc-space-sm, 8px) 0;
|
|
511
512
|
border-top: 1px solid var(--fc-color-border);
|
|
512
513
|
}
|
|
@@ -2037,10 +2038,13 @@
|
|
|
2037
2038
|
-webkit-app-region: no-drag;
|
|
2038
2039
|
}
|
|
2039
2040
|
.fc-tab-bar__tab--draggable {
|
|
2040
|
-
cursor:
|
|
2041
|
+
cursor: grab;
|
|
2042
|
+
will-change: transform;
|
|
2041
2043
|
}
|
|
2042
2044
|
.fc-tab-bar__tab--dragging {
|
|
2043
2045
|
opacity: 0.4;
|
|
2046
|
+
cursor: grabbing;
|
|
2047
|
+
z-index: 1;
|
|
2044
2048
|
}
|
|
2045
2049
|
.fc-tab-bar__tab-close {
|
|
2046
2050
|
display: inline-flex;
|
|
@@ -2074,7 +2078,7 @@
|
|
|
2074
2078
|
color: var(--fc-color-text-secondary);
|
|
2075
2079
|
cursor: pointer;
|
|
2076
2080
|
transition: all var(--fc-transition, 150ms ease);
|
|
2077
|
-
border-radius: var(--fc-radius-sm,
|
|
2081
|
+
border-radius: var(--fc-radius-sm, 2px);
|
|
2078
2082
|
background-color: var(--tab-bar-bg);
|
|
2079
2083
|
}
|
|
2080
2084
|
.fc-tab-bar__add-btn:hover {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React$1 from 'react';
|
|
3
|
-
import React__default, { ReactNode, ComponentType, FC
|
|
3
|
+
import React__default, { ReactNode, ComponentType, FC } from 'react';
|
|
4
4
|
|
|
5
5
|
type Theme = 'light' | 'dark' | 'system';
|
|
6
6
|
interface ThemeContextType {
|
|
@@ -455,17 +455,17 @@ interface TabBarProps {
|
|
|
455
455
|
/** 是否启用拖拽排序 */
|
|
456
456
|
draggable?: boolean;
|
|
457
457
|
/**
|
|
458
|
-
* Tab
|
|
458
|
+
* Tab 最小宽度,支持任意 CSS 长度值(如 "8rem"、"120px")。
|
|
459
459
|
* Tab 压缩至此宽度后触发横向滚动。
|
|
460
|
-
* @default
|
|
460
|
+
* @default "80px"
|
|
461
461
|
*/
|
|
462
|
-
|
|
462
|
+
minTabWidth?: string;
|
|
463
463
|
/**
|
|
464
|
-
* Tab
|
|
464
|
+
* Tab 最大宽度,支持任意 CSS 长度值(如 "16rem"、"200px")。
|
|
465
465
|
* Tab 较少时不超过此宽度。
|
|
466
|
-
* @default
|
|
466
|
+
* @default "200px"
|
|
467
467
|
*/
|
|
468
|
-
|
|
468
|
+
maxTabWidth?: string;
|
|
469
469
|
/**
|
|
470
470
|
* 控制 Tab 是否自动填充容器宽度。
|
|
471
471
|
* - true: flex: 1 1 0,Tab 会自动拉伸填满导航栏(默认行为)
|
|
@@ -641,59 +641,32 @@ interface ChatProps {
|
|
|
641
641
|
declare const Chat: React__default.FC<ChatProps>;
|
|
642
642
|
|
|
643
643
|
interface RelationNodeData {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
644
|
+
id: string;
|
|
645
|
+
name: string;
|
|
646
|
+
type?: 'person' | 'organization' | 'event' | 'location' | 'concept';
|
|
647
647
|
description?: string;
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
metadata?: Record<string, any>;
|
|
648
|
+
avatar?: string;
|
|
649
|
+
importance?: number;
|
|
651
650
|
}
|
|
652
651
|
interface RelationEdgeData {
|
|
652
|
+
source: string;
|
|
653
|
+
target: string;
|
|
653
654
|
label?: string;
|
|
654
|
-
type?: '
|
|
655
|
-
|
|
656
|
-
animated?: boolean;
|
|
657
|
-
metadata?: Record<string, any>;
|
|
655
|
+
type?: 'friend' | 'enemy' | 'subordinate' | 'superior' | 'neutral';
|
|
656
|
+
strength?: number;
|
|
658
657
|
}
|
|
659
658
|
interface RelationProps {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
onNodeDoubleClick?: (nodeId: string, nodeData: RelationNodeData) => void;
|
|
664
|
-
onEdgeClick?: (edgeId: string, edgeData?: RelationEdgeData) => void;
|
|
665
|
-
onConnect?: (connection: any) => void;
|
|
666
|
-
onNodesChange?: (nodes: any[]) => void;
|
|
667
|
-
onEdgesChange?: (edges: any[]) => void;
|
|
668
|
-
fitView?: boolean;
|
|
669
|
-
fitViewOptions?: any;
|
|
670
|
-
className?: string;
|
|
671
|
-
style?: CSSProperties;
|
|
672
|
-
height?: string | number;
|
|
673
|
-
width?: string | number;
|
|
674
|
-
defaultViewport?: {
|
|
675
|
-
x: number;
|
|
676
|
-
y: number;
|
|
677
|
-
zoom: number;
|
|
659
|
+
data?: {
|
|
660
|
+
nodes: RelationNodeData[];
|
|
661
|
+
edges: RelationEdgeData[];
|
|
678
662
|
};
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
snapToGrid?: boolean;
|
|
682
|
-
snapGrid?: [number, number];
|
|
683
|
-
enableEdgeCreation?: boolean;
|
|
684
|
-
enableNodeDrag?: boolean;
|
|
685
|
-
onNodeContextMenu?: (nodeId: string, nodeData: RelationNodeData) => void;
|
|
663
|
+
onNodeClick?: (node: RelationNodeData) => void;
|
|
664
|
+
onEdgeClick?: (edge: RelationEdgeData) => void;
|
|
686
665
|
theme?: 'dark' | 'light';
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
};
|
|
692
|
-
nodeStyles?: {
|
|
693
|
-
borderRadius?: string;
|
|
694
|
-
minWidth?: string;
|
|
695
|
-
};
|
|
696
|
-
showHandles?: boolean;
|
|
666
|
+
height?: string | number;
|
|
667
|
+
width?: string | number;
|
|
668
|
+
className?: string;
|
|
669
|
+
style?: React__default.CSSProperties;
|
|
697
670
|
}
|
|
698
671
|
declare const Relation: FC<RelationProps>;
|
|
699
672
|
|
package/dist/index.js
CHANGED
|
@@ -2025,8 +2025,37 @@ var Card = ({
|
|
|
2025
2025
|
};
|
|
2026
2026
|
|
|
2027
2027
|
// src/components/Bar/TabBar.tsx
|
|
2028
|
-
import { useRef as useRef7, useCallback as useCallback8, memo as memo4, useEffect as useEffect8 } from "react";
|
|
2028
|
+
import { useRef as useRef7, useCallback as useCallback8, memo as memo4, useEffect as useEffect8, useMemo as useMemo5 } from "react";
|
|
2029
|
+
import {
|
|
2030
|
+
DndContext as DndContext2,
|
|
2031
|
+
closestCenter,
|
|
2032
|
+
PointerSensor as PointerSensor2,
|
|
2033
|
+
useSensor as useSensor2,
|
|
2034
|
+
useSensors as useSensors2
|
|
2035
|
+
} from "@dnd-kit/core";
|
|
2036
|
+
import {
|
|
2037
|
+
SortableContext,
|
|
2038
|
+
useSortable,
|
|
2039
|
+
horizontalListSortingStrategy,
|
|
2040
|
+
arrayMove
|
|
2041
|
+
} from "@dnd-kit/sortable";
|
|
2042
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
2029
2043
|
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2044
|
+
function useContainerBoundModifier(containerRef) {
|
|
2045
|
+
return useMemo5(() => ({ transform, activeNodeRect }) => {
|
|
2046
|
+
if (!containerRef.current || !activeNodeRect) {
|
|
2047
|
+
return { ...transform, y: 0 };
|
|
2048
|
+
}
|
|
2049
|
+
const { left, right } = containerRef.current.getBoundingClientRect();
|
|
2050
|
+
const minX = left - activeNodeRect.left;
|
|
2051
|
+
const maxX = right - activeNodeRect.right;
|
|
2052
|
+
return {
|
|
2053
|
+
...transform,
|
|
2054
|
+
y: 0,
|
|
2055
|
+
x: Math.min(Math.max(transform.x, minX), maxX)
|
|
2056
|
+
};
|
|
2057
|
+
}, [containerRef]);
|
|
2058
|
+
}
|
|
2030
2059
|
var TabItemView = memo4(({
|
|
2031
2060
|
item,
|
|
2032
2061
|
isActive,
|
|
@@ -2038,36 +2067,44 @@ var TabItemView = memo4(({
|
|
|
2038
2067
|
activeTabStyle,
|
|
2039
2068
|
renderCloseIcon,
|
|
2040
2069
|
onClick,
|
|
2041
|
-
onClose
|
|
2042
|
-
onDragStart,
|
|
2043
|
-
onDragOver,
|
|
2044
|
-
onDrop,
|
|
2045
|
-
onDragEnd
|
|
2070
|
+
onClose
|
|
2046
2071
|
}) => {
|
|
2072
|
+
const {
|
|
2073
|
+
attributes,
|
|
2074
|
+
listeners,
|
|
2075
|
+
setNodeRef,
|
|
2076
|
+
transform,
|
|
2077
|
+
transition,
|
|
2078
|
+
isDragging
|
|
2079
|
+
} = useSortable({
|
|
2080
|
+
id: item.key,
|
|
2081
|
+
disabled: !draggable || !!item.disabled
|
|
2082
|
+
});
|
|
2047
2083
|
const showClose = item.closable !== void 0 ? item.closable : closable;
|
|
2048
2084
|
const classes = [
|
|
2049
2085
|
"fc-tab-bar__tab",
|
|
2050
2086
|
isActive && "fc-tab-bar__tab--active",
|
|
2051
2087
|
item.disabled && "fc-tab-bar__tab--disabled",
|
|
2052
2088
|
draggable && !item.disabled && "fc-tab-bar__tab--draggable",
|
|
2089
|
+
isDragging && "fc-tab-bar__tab--dragging",
|
|
2053
2090
|
tabClassName,
|
|
2054
2091
|
isActive && activeTabClassName
|
|
2055
2092
|
].filter(Boolean).join(" ");
|
|
2056
2093
|
const mergedStyle = {
|
|
2094
|
+
transform: CSS.Transform.toString(transform),
|
|
2095
|
+
transition,
|
|
2057
2096
|
...tabStyle,
|
|
2058
2097
|
...isActive ? activeTabStyle : void 0
|
|
2059
2098
|
};
|
|
2060
2099
|
return /* @__PURE__ */ jsxs13(
|
|
2061
2100
|
"div",
|
|
2062
2101
|
{
|
|
2102
|
+
ref: setNodeRef,
|
|
2063
2103
|
className: classes,
|
|
2064
2104
|
style: mergedStyle,
|
|
2065
2105
|
onClick: () => !item.disabled && onClick(item.key),
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
onDragOver,
|
|
2069
|
-
onDrop: (e) => onDrop(e, item.key),
|
|
2070
|
-
onDragEnd,
|
|
2106
|
+
...attributes,
|
|
2107
|
+
...listeners,
|
|
2071
2108
|
role: "tab",
|
|
2072
2109
|
"aria-selected": isActive,
|
|
2073
2110
|
"aria-disabled": item.disabled,
|
|
@@ -2078,6 +2115,7 @@ var TabItemView = memo4(({
|
|
|
2078
2115
|
"span",
|
|
2079
2116
|
{
|
|
2080
2117
|
className: "fc-tab-bar__tab-close",
|
|
2118
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
2081
2119
|
onClick: (e) => onClose(e, item.key),
|
|
2082
2120
|
role: "button",
|
|
2083
2121
|
"aria-label": "\u5173\u95ED",
|
|
@@ -2098,8 +2136,8 @@ var TabBar = memo4(({
|
|
|
2098
2136
|
closable = false,
|
|
2099
2137
|
addable = false,
|
|
2100
2138
|
draggable = false,
|
|
2101
|
-
|
|
2102
|
-
|
|
2139
|
+
minTabWidth = "80px",
|
|
2140
|
+
maxTabWidth = "200px",
|
|
2103
2141
|
fillWidth = true,
|
|
2104
2142
|
onChange,
|
|
2105
2143
|
onClose,
|
|
@@ -2138,8 +2176,8 @@ var TabBar = memo4(({
|
|
|
2138
2176
|
}
|
|
2139
2177
|
}
|
|
2140
2178
|
const mergedStyle = { ...overrideStyle, ...style };
|
|
2141
|
-
const dragKeyRef = useRef7(null);
|
|
2142
2179
|
const navRef = useRef7(null);
|
|
2180
|
+
const boundModifier = useContainerBoundModifier(navRef);
|
|
2143
2181
|
const prevItemsLengthRef = useRef7(items.length);
|
|
2144
2182
|
useEffect8(() => {
|
|
2145
2183
|
const prev = prevItemsLengthRef.current;
|
|
@@ -2173,38 +2211,19 @@ var TabBar = memo4(({
|
|
|
2173
2211
|
},
|
|
2174
2212
|
[onClose]
|
|
2175
2213
|
);
|
|
2176
|
-
const
|
|
2177
|
-
(
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
const target = e.currentTarget;
|
|
2181
|
-
requestAnimationFrame(() => target.classList.add("fc-tab-bar__tab--dragging"));
|
|
2182
|
-
},
|
|
2183
|
-
[]
|
|
2214
|
+
const sensors = useSensors2(
|
|
2215
|
+
useSensor2(PointerSensor2, {
|
|
2216
|
+
activationConstraint: { distance: 5 }
|
|
2217
|
+
})
|
|
2184
2218
|
);
|
|
2185
|
-
const
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
(
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
if (!dragKey || dragKey === targetKey || !onReorder) return;
|
|
2194
|
-
const fromIndex = items.findIndex((i) => i.key === dragKey);
|
|
2195
|
-
const toIndex = items.findIndex((i) => i.key === targetKey);
|
|
2196
|
-
if (fromIndex === -1 || toIndex === -1) return;
|
|
2197
|
-
const reordered = [...items];
|
|
2198
|
-
const [moved] = reordered.splice(fromIndex, 1);
|
|
2199
|
-
reordered.splice(toIndex, 0, moved);
|
|
2200
|
-
onReorder(reordered);
|
|
2201
|
-
},
|
|
2202
|
-
[items, onReorder]
|
|
2203
|
-
);
|
|
2204
|
-
const handleDragEnd = useCallback8((e) => {
|
|
2205
|
-
dragKeyRef.current = null;
|
|
2206
|
-
e.currentTarget.classList.remove("fc-tab-bar__tab--dragging");
|
|
2207
|
-
}, []);
|
|
2219
|
+
const handleDragEnd = useCallback8((event) => {
|
|
2220
|
+
const { active, over } = event;
|
|
2221
|
+
if (!over || active.id === over.id || !onReorder) return;
|
|
2222
|
+
const fromIndex = items.findIndex((i) => i.key === active.id);
|
|
2223
|
+
const toIndex = items.findIndex((i) => i.key === over.id);
|
|
2224
|
+
if (fromIndex === -1 || toIndex === -1) return;
|
|
2225
|
+
onReorder(arrayMove(items, fromIndex, toIndex));
|
|
2226
|
+
}, [items, onReorder]);
|
|
2208
2227
|
const rootClasses = [
|
|
2209
2228
|
"fc-tab-bar",
|
|
2210
2229
|
`fc-tab-bar--${variant}`,
|
|
@@ -2213,33 +2232,46 @@ var TabBar = memo4(({
|
|
|
2213
2232
|
className
|
|
2214
2233
|
].filter(Boolean).join(" ");
|
|
2215
2234
|
const navWrapStyle = {
|
|
2216
|
-
"--tab-min-width":
|
|
2217
|
-
"--tab-max-width":
|
|
2235
|
+
"--tab-min-width": minTabWidth,
|
|
2236
|
+
"--tab-max-width": maxTabWidth,
|
|
2218
2237
|
"--tab-fill-width": fillWidth ? "1" : "0"
|
|
2219
2238
|
};
|
|
2220
2239
|
const dragRegion = tauriDragRegion ? { "data-tauri-drag-region": "" } : {};
|
|
2240
|
+
const tabItems = items.map((item) => /* @__PURE__ */ jsx18(
|
|
2241
|
+
TabItemView,
|
|
2242
|
+
{
|
|
2243
|
+
item,
|
|
2244
|
+
isActive: activeKey === item.key,
|
|
2245
|
+
closable,
|
|
2246
|
+
draggable,
|
|
2247
|
+
tabClassName,
|
|
2248
|
+
activeTabClassName,
|
|
2249
|
+
tabStyle,
|
|
2250
|
+
activeTabStyle,
|
|
2251
|
+
renderCloseIcon,
|
|
2252
|
+
onClick: handleClick,
|
|
2253
|
+
onClose: handleClose
|
|
2254
|
+
},
|
|
2255
|
+
item.key
|
|
2256
|
+
));
|
|
2221
2257
|
return /* @__PURE__ */ jsx18("div", { className: rootClasses, style: mergedStyle, role: "tablist", ...dragRegion, children: /* @__PURE__ */ jsx18("div", { className: "fc-tab-bar__nav-outer", ...dragRegion, children: /* @__PURE__ */ jsxs13("div", { className: "fc-tab-bar__nav-wrap", ref: navRef, style: navWrapStyle, children: [
|
|
2222
|
-
|
|
2223
|
-
|
|
2258
|
+
/* @__PURE__ */ jsx18(
|
|
2259
|
+
DndContext2,
|
|
2224
2260
|
{
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
onDragEnd: handleDragEnd
|
|
2240
|
-
},
|
|
2241
|
-
item.key
|
|
2242
|
-
)),
|
|
2261
|
+
sensors,
|
|
2262
|
+
collisionDetection: closestCenter,
|
|
2263
|
+
modifiers: [boundModifier],
|
|
2264
|
+
onDragEnd: handleDragEnd,
|
|
2265
|
+
children: /* @__PURE__ */ jsx18(
|
|
2266
|
+
SortableContext,
|
|
2267
|
+
{
|
|
2268
|
+
items: items.map((i) => i.key),
|
|
2269
|
+
strategy: horizontalListSortingStrategy,
|
|
2270
|
+
children: tabItems
|
|
2271
|
+
}
|
|
2272
|
+
)
|
|
2273
|
+
}
|
|
2274
|
+
),
|
|
2243
2275
|
addable && /* @__PURE__ */ jsx18(
|
|
2244
2276
|
"div",
|
|
2245
2277
|
{
|
|
@@ -2555,7 +2587,7 @@ function ContextMenuProvider({
|
|
|
2555
2587
|
var useContextMenu = () => useContext4(ContextMenuContext);
|
|
2556
2588
|
|
|
2557
2589
|
// src/components/Chat/Chat.tsx
|
|
2558
|
-
import { useState as useState17, useRef as useRef10, useEffect as useEffect11, useCallback as useCallback10, useMemo as
|
|
2590
|
+
import { useState as useState17, useRef as useRef10, useEffect as useEffect11, useCallback as useCallback10, useMemo as useMemo6 } from "react";
|
|
2559
2591
|
|
|
2560
2592
|
// src/components/SmartMessage/SmartMessage.tsx
|
|
2561
2593
|
import { useState as useState16, useCallback as useCallback9 } from "react";
|
|
@@ -2665,7 +2697,7 @@ var Chat = ({
|
|
|
2665
2697
|
const messagesContainerRef = useRef10(null);
|
|
2666
2698
|
const messagesEndRef = useRef10(null);
|
|
2667
2699
|
const historyPanelRef = useRef10(null);
|
|
2668
|
-
const currentConversation =
|
|
2700
|
+
const currentConversation = useMemo6(
|
|
2669
2701
|
() => conversations.find((c) => c.id === currentConversationId),
|
|
2670
2702
|
[conversations, currentConversationId]
|
|
2671
2703
|
);
|
|
@@ -2693,7 +2725,7 @@ var Chat = ({
|
|
|
2693
2725
|
onMessageCopy?.(message);
|
|
2694
2726
|
}
|
|
2695
2727
|
}, [messages, onMessageCopy]);
|
|
2696
|
-
const containerStyle =
|
|
2728
|
+
const containerStyle = useMemo6(() => ({
|
|
2697
2729
|
height,
|
|
2698
2730
|
width,
|
|
2699
2731
|
...style
|
|
@@ -2865,484 +2897,353 @@ var Chat = ({
|
|
|
2865
2897
|
};
|
|
2866
2898
|
|
|
2867
2899
|
// src/components/Relation/Relation.tsx
|
|
2868
|
-
import
|
|
2900
|
+
import { useEffect as useEffect12, useState as useState18, useCallback as useCallback11, useRef as useRef11 } from "react";
|
|
2869
2901
|
import {
|
|
2870
2902
|
ReactFlow,
|
|
2871
2903
|
useNodesState,
|
|
2872
2904
|
useEdgesState,
|
|
2873
|
-
addEdge,
|
|
2874
|
-
Handle,
|
|
2875
|
-
Position,
|
|
2876
2905
|
MarkerType,
|
|
2877
|
-
ConnectionLineType,
|
|
2878
2906
|
useReactFlow,
|
|
2879
|
-
ReactFlowProvider
|
|
2907
|
+
ReactFlowProvider,
|
|
2908
|
+
Background,
|
|
2909
|
+
Position,
|
|
2910
|
+
Handle
|
|
2880
2911
|
} from "@xyflow/react";
|
|
2881
2912
|
import "@xyflow/react/dist/style.css";
|
|
2882
|
-
import {
|
|
2883
|
-
var
|
|
2884
|
-
const
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
default: "
|
|
2891
|
-
user: "\u{1F464}",
|
|
2892
|
-
shield: "\u{1F6E1}\uFE0F"
|
|
2913
|
+
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2914
|
+
var getNodeColor = (type, isDark) => {
|
|
2915
|
+
const colors = {
|
|
2916
|
+
person: isDark ? "#60a5fa" : "#3b82f6",
|
|
2917
|
+
organization: isDark ? "#34d399" : "#10b981",
|
|
2918
|
+
event: isDark ? "#f472b6" : "#ec4899",
|
|
2919
|
+
location: isDark ? "#fb923c" : "#f97316",
|
|
2920
|
+
concept: isDark ? "#a78bfa" : "#8b5cf6",
|
|
2921
|
+
default: isDark ? "#94a3b8" : "#64748b"
|
|
2893
2922
|
};
|
|
2894
|
-
return
|
|
2923
|
+
return colors[type] || colors.default;
|
|
2895
2924
|
};
|
|
2896
|
-
var
|
|
2897
|
-
const
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2925
|
+
var getEdgeColor = (type, isDark) => {
|
|
2926
|
+
const colors = {
|
|
2927
|
+
friend: isDark ? "#34d399" : "#10b981",
|
|
2928
|
+
enemy: isDark ? "#f87171" : "#ef4444",
|
|
2929
|
+
subordinate: isDark ? "#60a5fa" : "#3b82f6",
|
|
2930
|
+
superior: isDark ? "#a78bfa" : "#8b5cf6",
|
|
2931
|
+
neutral: isDark ? "#94a3b8" : "#64748b",
|
|
2932
|
+
default: isDark ? "#94a3b8" : "#64748b"
|
|
2901
2933
|
};
|
|
2902
|
-
return
|
|
2934
|
+
return colors[type] || colors.default;
|
|
2903
2935
|
};
|
|
2904
|
-
var
|
|
2905
|
-
const
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
};
|
|
2913
|
-
const hiddenHandleStyle = {
|
|
2914
|
-
opacity: 0,
|
|
2915
|
-
width: "0px",
|
|
2916
|
-
height: "0px",
|
|
2917
|
-
pointerEvents: "none"
|
|
2936
|
+
var getIconForType = (type) => {
|
|
2937
|
+
const icons = {
|
|
2938
|
+
person: "\u{1F464}",
|
|
2939
|
+
organization: "\u{1F3E2}",
|
|
2940
|
+
event: "\u{1F4C5}",
|
|
2941
|
+
location: "\u{1F4CD}",
|
|
2942
|
+
concept: "\u{1F4A1}",
|
|
2943
|
+
default: "\u{1F517}"
|
|
2918
2944
|
};
|
|
2919
|
-
|
|
2920
|
-
return /* @__PURE__ */ jsxs18(Fragment5, { children: [
|
|
2921
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-left", style: { ...actualStyle, left: "25%" } }),
|
|
2922
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-left-source", style: { ...actualStyle, left: "25%" } }),
|
|
2923
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-center", style: { ...actualStyle, left: "50%" } }),
|
|
2924
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-center-source", style: { ...actualStyle, left: "50%" } }),
|
|
2925
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-right", style: { ...actualStyle, left: "75%" } }),
|
|
2926
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-right-source", style: { ...actualStyle, left: "75%" } }),
|
|
2927
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-top", style: { ...actualStyle, top: "25%" } }),
|
|
2928
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-top-source", style: { ...actualStyle, top: "25%" } }),
|
|
2929
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-center", style: { ...actualStyle, top: "50%" } }),
|
|
2930
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-center-source", style: { ...actualStyle, top: "50%" } }),
|
|
2931
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-bottom", style: { ...actualStyle, top: "75%" } }),
|
|
2932
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-bottom-source", style: { ...actualStyle, top: "75%" } }),
|
|
2933
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-left", style: { ...actualStyle, left: "25%" } }),
|
|
2934
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-left-source", style: { ...actualStyle, left: "25%" } }),
|
|
2935
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-center", style: { ...actualStyle, left: "50%" } }),
|
|
2936
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-center-source", style: { ...actualStyle, left: "50%" } }),
|
|
2937
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-right", style: { ...actualStyle, left: "75%" } }),
|
|
2938
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-right-source", style: { ...actualStyle, left: "75%" } }),
|
|
2939
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-top", style: { ...actualStyle, top: "25%" } }),
|
|
2940
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-top-source", style: { ...actualStyle, top: "25%" } }),
|
|
2941
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-center", style: { ...actualStyle, top: "50%" } }),
|
|
2942
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-center-source", style: { ...actualStyle, top: "50%" } }),
|
|
2943
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-bottom", style: { ...actualStyle, top: "75%" } }),
|
|
2944
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-bottom-source", style: { ...actualStyle, top: "75%" } }),
|
|
2945
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "corner-top-left", style: { ...actualStyle, left: "10%" } }),
|
|
2946
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "corner-top-left-source", style: { ...actualStyle, left: "10%" } }),
|
|
2947
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "corner-top-right", style: { ...actualStyle, left: "90%" } }),
|
|
2948
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "corner-top-right-source", style: { ...actualStyle, left: "90%" } }),
|
|
2949
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "corner-bottom-left", style: { ...actualStyle, left: "10%" } }),
|
|
2950
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "corner-bottom-left-source", style: { ...actualStyle, left: "10%" } }),
|
|
2951
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "corner-bottom-right", style: { ...actualStyle, left: "90%" } }),
|
|
2952
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "corner-bottom-right-source", style: { ...actualStyle, left: "90%" } }),
|
|
2953
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "corner-left-top", style: { ...actualStyle, top: "10%" } }),
|
|
2954
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "corner-left-top-source", style: { ...actualStyle, top: "10%" } }),
|
|
2955
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "corner-left-bottom", style: { ...actualStyle, top: "90%" } }),
|
|
2956
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "corner-left-bottom-source", style: { ...actualStyle, top: "90%" } }),
|
|
2957
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "corner-right-top", style: { ...actualStyle, top: "10%" } }),
|
|
2958
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "corner-right-top-source", style: { ...actualStyle, top: "10%" } }),
|
|
2959
|
-
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "corner-right-bottom", style: { ...actualStyle, top: "90%" } }),
|
|
2960
|
-
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "corner-right-bottom-source", style: { ...actualStyle, top: "90%" } })
|
|
2961
|
-
] });
|
|
2945
|
+
return icons[type] || icons.default;
|
|
2962
2946
|
};
|
|
2963
|
-
var CustomNode =
|
|
2964
|
-
const isDark =
|
|
2965
|
-
const
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
2947
|
+
var CustomNode = ({ data }) => {
|
|
2948
|
+
const isDark = data.theme === "dark";
|
|
2949
|
+
const nodeColor = getNodeColor(data.type || "default", isDark);
|
|
2950
|
+
return /* @__PURE__ */ jsxs18(
|
|
2951
|
+
"div",
|
|
2952
|
+
{
|
|
2953
|
+
style: {
|
|
2954
|
+
background: isDark ? "#1e293b" : "#ffffff",
|
|
2955
|
+
border: `2px solid ${nodeColor}`,
|
|
2956
|
+
borderRadius: "12px",
|
|
2957
|
+
padding: "8px 12px",
|
|
2958
|
+
minWidth: "140px",
|
|
2959
|
+
cursor: "pointer",
|
|
2960
|
+
boxShadow: isDark ? "0 4px 12px rgba(0,0,0,0.3)" : "0 2px 8px rgba(0,0,0,0.1)",
|
|
2961
|
+
transition: "all 0.2s ease"
|
|
2962
|
+
},
|
|
2963
|
+
onMouseEnter: (e) => {
|
|
2964
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
2965
|
+
e.currentTarget.style.boxShadow = isDark ? "0 6px 16px rgba(0,0,0,0.4)" : "0 4px 12px rgba(0,0,0,0.15)";
|
|
2966
|
+
},
|
|
2967
|
+
onMouseLeave: (e) => {
|
|
2968
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
2969
|
+
e.currentTarget.style.boxShadow = isDark ? "0 4px 12px rgba(0,0,0,0.3)" : "0 2px 8px rgba(0,0,0,0.1)";
|
|
2970
|
+
},
|
|
2971
|
+
children: [
|
|
2972
|
+
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, style: { opacity: 0 } }),
|
|
2973
|
+
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, style: { opacity: 0 } }),
|
|
2974
|
+
/* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, style: { opacity: 0 } }),
|
|
2975
|
+
/* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, style: { opacity: 0 } }),
|
|
2976
|
+
/* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
2977
|
+
/* @__PURE__ */ jsx24(
|
|
2978
|
+
"div",
|
|
2979
|
+
{
|
|
2980
|
+
style: {
|
|
2981
|
+
width: "32px",
|
|
2982
|
+
height: "32px",
|
|
2983
|
+
borderRadius: "50%",
|
|
2984
|
+
background: `linear-gradient(135deg, ${nodeColor}20, ${nodeColor}40)`,
|
|
2985
|
+
display: "flex",
|
|
2986
|
+
alignItems: "center",
|
|
2987
|
+
justifyContent: "center",
|
|
2988
|
+
fontSize: "16px"
|
|
2989
|
+
},
|
|
2990
|
+
children: getIconForType(data.type || "default")
|
|
2991
|
+
}
|
|
2992
|
+
),
|
|
2993
|
+
/* @__PURE__ */ jsxs18("div", { children: [
|
|
2994
|
+
/* @__PURE__ */ jsx24(
|
|
2995
|
+
"div",
|
|
2996
|
+
{
|
|
2997
|
+
style: {
|
|
2998
|
+
fontWeight: 600,
|
|
2999
|
+
fontSize: "12px",
|
|
3000
|
+
color: isDark ? "#ffffff" : "#1e293b"
|
|
3001
|
+
},
|
|
3002
|
+
children: data.name
|
|
3003
|
+
}
|
|
3004
|
+
),
|
|
3005
|
+
data.description && /* @__PURE__ */ jsx24(
|
|
3006
|
+
"div",
|
|
3007
|
+
{
|
|
3008
|
+
style: {
|
|
3009
|
+
fontSize: "10px",
|
|
3010
|
+
color: isDark ? "#94a3b8" : "#64748b",
|
|
3011
|
+
marginTop: "2px"
|
|
3012
|
+
},
|
|
3013
|
+
children: data.description
|
|
3014
|
+
}
|
|
3015
|
+
)
|
|
3016
|
+
] })
|
|
3017
|
+
] })
|
|
3018
|
+
]
|
|
3019
|
+
}
|
|
3020
|
+
);
|
|
3021
|
+
};
|
|
3022
|
+
var nodeTypes = { custom: CustomNode };
|
|
3023
|
+
var SmartEdge = ({ id, sourceX, sourceY, targetX, targetY, style = {}, markerEnd, data }) => {
|
|
3024
|
+
const dx = targetX - sourceX;
|
|
3025
|
+
const dy = targetY - sourceY;
|
|
3026
|
+
const offsetX = dx * 0.2;
|
|
3027
|
+
const offsetY = dy * 0.2;
|
|
3028
|
+
const path = `M ${sourceX} ${sourceY} C ${sourceX + offsetX} ${sourceY + offsetY}, ${targetX - offsetX} ${targetY - offsetY}, ${targetX} ${targetY}`;
|
|
3029
|
+
const midX = (sourceX + targetX) / 2;
|
|
3030
|
+
const midY = (sourceY + targetY) / 2;
|
|
3031
|
+
const getLabelStyle = () => {
|
|
3032
|
+
if (style.stroke === "#ef4444") return { bg: "#fee2e2", color: "#dc2626" };
|
|
3033
|
+
if (style.stroke === "#10b981") return { bg: "#d1fae5", color: "#065f46" };
|
|
3034
|
+
return { bg: "#e2e8f0", color: "#475569" };
|
|
3010
3035
|
};
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
/* @__PURE__ */
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
backgroundColor: getStatusColor(data.status),
|
|
3032
|
-
animation: data.status === "warning" ? "pulse 2s infinite" : "none",
|
|
3033
|
-
boxShadow: isDark ? "0 0 0 1px rgba(0,0,0,0.2)" : "none"
|
|
3034
|
-
} })
|
|
3035
|
-
] }),
|
|
3036
|
-
/* @__PURE__ */ jsxs18("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3037
|
-
/* @__PURE__ */ jsx24("div", { style: titleStyle, children: data.title }),
|
|
3038
|
-
/* @__PURE__ */ jsx24("div", { style: subtitleStyle, children: data.subtitle }),
|
|
3039
|
-
data.description && /* @__PURE__ */ jsx24("div", { style: descriptionStyle, children: data.description })
|
|
3040
|
-
] })
|
|
3041
|
-
] })
|
|
3036
|
+
const labelStyle = getLabelStyle();
|
|
3037
|
+
return /* @__PURE__ */ jsxs18("g", { children: [
|
|
3038
|
+
/* @__PURE__ */ jsx24("path", { id, style, className: "react-flow__edge-path", d: path, markerEnd, fill: "none" }),
|
|
3039
|
+
data?.label && /* @__PURE__ */ jsx24("foreignObject", { x: midX - 30, y: midY - 10, width: 60, height: 20, style: { overflow: "visible" }, children: /* @__PURE__ */ jsx24(
|
|
3040
|
+
"div",
|
|
3041
|
+
{
|
|
3042
|
+
style: {
|
|
3043
|
+
background: labelStyle.bg,
|
|
3044
|
+
padding: "2px 6px",
|
|
3045
|
+
borderRadius: "10px",
|
|
3046
|
+
fontSize: "10px",
|
|
3047
|
+
fontWeight: 500,
|
|
3048
|
+
color: labelStyle.color,
|
|
3049
|
+
textAlign: "center",
|
|
3050
|
+
whiteSpace: "nowrap",
|
|
3051
|
+
pointerEvents: "none"
|
|
3052
|
+
},
|
|
3053
|
+
children: data.label
|
|
3054
|
+
}
|
|
3055
|
+
) })
|
|
3042
3056
|
] });
|
|
3043
|
-
});
|
|
3044
|
-
CustomNode.displayName = "CustomNode";
|
|
3045
|
-
var nodeTypes = {
|
|
3046
|
-
custom: CustomNode
|
|
3047
3057
|
};
|
|
3048
|
-
var
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
const
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3058
|
+
var edgeTypes = { smart: SmartEdge };
|
|
3059
|
+
var calculateTreeLayout = (nodes, edges) => {
|
|
3060
|
+
if (nodes.length === 0) return [];
|
|
3061
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
3062
|
+
const parentMap = /* @__PURE__ */ new Map();
|
|
3063
|
+
edges.forEach((edge) => {
|
|
3064
|
+
if (!childrenMap.has(edge.source)) childrenMap.set(edge.source, []);
|
|
3065
|
+
childrenMap.get(edge.source).push(edge.target);
|
|
3066
|
+
parentMap.set(edge.target, edge.source);
|
|
3067
|
+
});
|
|
3068
|
+
const roots = nodes.filter((n) => !parentMap.has(n.id));
|
|
3069
|
+
const actualRoots = roots.length > 0 ? roots : [nodes[0]];
|
|
3070
|
+
const positioned = [];
|
|
3071
|
+
const levelNodes = /* @__PURE__ */ new Map();
|
|
3072
|
+
const queue = actualRoots.map((r) => ({ id: r.id, level: 0 }));
|
|
3073
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3074
|
+
while (queue.length > 0) {
|
|
3075
|
+
const item = queue.shift();
|
|
3076
|
+
if (visited.has(item.id)) continue;
|
|
3077
|
+
visited.add(item.id);
|
|
3078
|
+
if (!levelNodes.has(item.level)) levelNodes.set(item.level, []);
|
|
3079
|
+
levelNodes.get(item.level).push(item.id);
|
|
3080
|
+
const children = childrenMap.get(item.id) || [];
|
|
3081
|
+
children.forEach((childId) => {
|
|
3082
|
+
if (!visited.has(childId)) {
|
|
3083
|
+
queue.push({ id: childId, level: item.level + 1 });
|
|
3084
|
+
}
|
|
3085
|
+
});
|
|
3086
|
+
}
|
|
3087
|
+
const startX = 50;
|
|
3088
|
+
const startY = 50;
|
|
3089
|
+
const levelHeight = 120;
|
|
3090
|
+
const nodeWidth = 180;
|
|
3091
|
+
const nodeGap = 30;
|
|
3092
|
+
for (const [level, nodeIds] of levelNodes.entries()) {
|
|
3093
|
+
const totalWidth = nodeIds.length * nodeWidth + (nodeIds.length - 1) * nodeGap;
|
|
3094
|
+
let currentX = startX + (800 - totalWidth) / 2;
|
|
3095
|
+
nodeIds.forEach((nodeId, index) => {
|
|
3096
|
+
const node = nodes.find((n) => n.id === nodeId);
|
|
3097
|
+
if (node) {
|
|
3098
|
+
positioned.push({
|
|
3099
|
+
...node,
|
|
3100
|
+
position: {
|
|
3101
|
+
x: currentX + index * (nodeWidth + nodeGap),
|
|
3102
|
+
y: startY + level * levelHeight
|
|
3103
|
+
}
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
3108
|
+
const positionedIds = new Set(positioned.map((p) => p.id));
|
|
3109
|
+
const remaining = nodes.filter((n) => !positionedIds.has(n.id));
|
|
3110
|
+
remaining.forEach((node, idx) => {
|
|
3111
|
+
positioned.push({
|
|
3112
|
+
...node,
|
|
3113
|
+
position: { x: 50 + idx % 3 * 200, y: 500 + Math.floor(idx / 3) * 100 }
|
|
3114
|
+
});
|
|
3115
|
+
});
|
|
3116
|
+
return positioned;
|
|
3055
3117
|
};
|
|
3056
3118
|
var RelationContent = ({
|
|
3057
|
-
|
|
3058
|
-
edges: propEdges,
|
|
3119
|
+
data,
|
|
3059
3120
|
onNodeClick,
|
|
3060
|
-
onNodeDoubleClick,
|
|
3061
3121
|
onEdgeClick,
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
onEdgesChange: onEdgesChangeProp,
|
|
3065
|
-
fitView = true,
|
|
3066
|
-
fitViewOptions,
|
|
3067
|
-
className = "",
|
|
3068
|
-
style = {},
|
|
3069
|
-
height = "70vh",
|
|
3122
|
+
theme = "light",
|
|
3123
|
+
height = "600px",
|
|
3070
3124
|
width = "100%",
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
maxZoom = 2,
|
|
3074
|
-
snapToGrid = false,
|
|
3075
|
-
snapGrid = [15, 15],
|
|
3076
|
-
enableEdgeCreation = true,
|
|
3077
|
-
enableNodeDrag = true,
|
|
3078
|
-
onNodeContextMenu,
|
|
3079
|
-
theme: propTheme = "light",
|
|
3080
|
-
edgeStyles = {},
|
|
3081
|
-
nodeStyles = {},
|
|
3082
|
-
showHandles = false
|
|
3125
|
+
className = "",
|
|
3126
|
+
style = {}
|
|
3083
3127
|
}) => {
|
|
3084
|
-
const [nodes, setNodes, onNodesChange] = useNodesState(
|
|
3085
|
-
const [edges, setEdges, onEdgesChange] = useEdgesState(
|
|
3086
|
-
const { fitView
|
|
3087
|
-
const
|
|
3128
|
+
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
3129
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
3130
|
+
const { fitView } = useReactFlow();
|
|
3131
|
+
const [isReady, setIsReady] = useState18(false);
|
|
3132
|
+
const isInitialized = useRef11(false);
|
|
3088
3133
|
const isDark = theme === "dark";
|
|
3089
|
-
const bgColor = isDark ? "#0f172a" : "#
|
|
3090
|
-
useEffect12(() => {
|
|
3091
|
-
if (fitView && fitViewFn && (propNodes?.length || 0) > 0) {
|
|
3092
|
-
const timer = setTimeout(() => {
|
|
3093
|
-
fitViewFn({ duration: 300, padding: 0.2, ...fitViewOptions }).catch((error) => {
|
|
3094
|
-
console.warn("Fit view failed:", error);
|
|
3095
|
-
});
|
|
3096
|
-
}, 100);
|
|
3097
|
-
return () => clearTimeout(timer);
|
|
3098
|
-
}
|
|
3099
|
-
}, [fitView, fitViewFn, fitViewOptions, propNodes]);
|
|
3134
|
+
const bgColor = isDark ? "#0f172a" : "#f8fafc";
|
|
3100
3135
|
useEffect12(() => {
|
|
3101
|
-
if (
|
|
3102
|
-
setNodes(
|
|
3136
|
+
if (!data?.nodes?.length) {
|
|
3137
|
+
setNodes([]);
|
|
3138
|
+
setEdges([]);
|
|
3139
|
+
setIsReady(false);
|
|
3140
|
+
return;
|
|
3103
3141
|
}
|
|
3104
|
-
|
|
3142
|
+
const positionedNodes = calculateTreeLayout(data.nodes, data.edges);
|
|
3143
|
+
setNodes(
|
|
3144
|
+
positionedNodes.map((node) => ({
|
|
3145
|
+
id: node.id,
|
|
3146
|
+
type: "custom",
|
|
3147
|
+
position: node.position,
|
|
3148
|
+
data: {
|
|
3149
|
+
...node,
|
|
3150
|
+
theme
|
|
3151
|
+
}
|
|
3152
|
+
}))
|
|
3153
|
+
);
|
|
3154
|
+
setEdges(
|
|
3155
|
+
data.edges.map((edge) => {
|
|
3156
|
+
const edgeColor = getEdgeColor(edge.type || "neutral", isDark);
|
|
3157
|
+
return {
|
|
3158
|
+
id: `${edge.source}-${edge.target}`,
|
|
3159
|
+
source: edge.source,
|
|
3160
|
+
target: edge.target,
|
|
3161
|
+
type: "smart",
|
|
3162
|
+
label: edge.label,
|
|
3163
|
+
data: { label: edge.label },
|
|
3164
|
+
style: { stroke: edgeColor, strokeWidth: 2 },
|
|
3165
|
+
markerEnd: { type: MarkerType.ArrowClosed, width: 12, height: 12, color: edgeColor }
|
|
3166
|
+
};
|
|
3167
|
+
})
|
|
3168
|
+
);
|
|
3169
|
+
setIsReady(true);
|
|
3170
|
+
isInitialized.current = false;
|
|
3171
|
+
}, [data, theme, setNodes, setEdges]);
|
|
3105
3172
|
useEffect12(() => {
|
|
3106
|
-
if (
|
|
3107
|
-
|
|
3173
|
+
if (isReady && fitView && !isInitialized.current) {
|
|
3174
|
+
isInitialized.current = true;
|
|
3175
|
+
setTimeout(() => {
|
|
3176
|
+
fitView({ duration: 300, padding: 0.15 }).catch(() => {
|
|
3177
|
+
});
|
|
3178
|
+
}, 100);
|
|
3108
3179
|
}
|
|
3109
|
-
}, [
|
|
3110
|
-
const handleNodesChange = useCallback11(
|
|
3111
|
-
(changes) => {
|
|
3112
|
-
onNodesChange(changes);
|
|
3113
|
-
if (onNodesChangeProp) {
|
|
3114
|
-
setTimeout(() => {
|
|
3115
|
-
onNodesChangeProp(nodes);
|
|
3116
|
-
}, 0);
|
|
3117
|
-
}
|
|
3118
|
-
},
|
|
3119
|
-
[onNodesChange, onNodesChangeProp, nodes]
|
|
3120
|
-
);
|
|
3121
|
-
const handleEdgesChange = useCallback11(
|
|
3122
|
-
(changes) => {
|
|
3123
|
-
onEdgesChange(changes);
|
|
3124
|
-
if (onEdgesChangeProp) {
|
|
3125
|
-
setTimeout(() => {
|
|
3126
|
-
onEdgesChangeProp(edges);
|
|
3127
|
-
}, 0);
|
|
3128
|
-
}
|
|
3129
|
-
},
|
|
3130
|
-
[onEdgesChange, onEdgesChangeProp, edges]
|
|
3131
|
-
);
|
|
3132
|
-
const onConnect = useCallback11(
|
|
3133
|
-
(params) => {
|
|
3134
|
-
const newEdge = {
|
|
3135
|
-
...params,
|
|
3136
|
-
id: `edge-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
|
|
3137
|
-
type: "straight",
|
|
3138
|
-
style: { stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"), strokeWidth: 1.8 },
|
|
3139
|
-
markerEnd: {
|
|
3140
|
-
type: MarkerType.ArrowClosed,
|
|
3141
|
-
color: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
|
|
3142
|
-
width: 12,
|
|
3143
|
-
height: 12
|
|
3144
|
-
},
|
|
3145
|
-
label: "",
|
|
3146
|
-
labelStyle: { fill: isDark ? "#fff" : "#333", fontSize: 11, fontWeight: 400 },
|
|
3147
|
-
labelBgStyle: { fill: "transparent", fillOpacity: 0 }
|
|
3148
|
-
};
|
|
3149
|
-
setEdges((eds) => addEdge(newEdge, eds));
|
|
3150
|
-
if (onConnectProp) {
|
|
3151
|
-
onConnectProp(params);
|
|
3152
|
-
}
|
|
3153
|
-
},
|
|
3154
|
-
[setEdges, onConnectProp, edgeStyles.defaultColor, isDark]
|
|
3155
|
-
);
|
|
3180
|
+
}, [isReady, fitView]);
|
|
3156
3181
|
const handleNodeClick = useCallback11(
|
|
3157
3182
|
(_event, node) => {
|
|
3158
3183
|
if (onNodeClick && node.data) {
|
|
3159
|
-
|
|
3184
|
+
const { id, name, type, description, avatar, importance } = node.data;
|
|
3185
|
+
onNodeClick({ id, name, type, description, avatar, importance });
|
|
3160
3186
|
}
|
|
3161
3187
|
},
|
|
3162
3188
|
[onNodeClick]
|
|
3163
3189
|
);
|
|
3164
|
-
const handleNodeDoubleClick = useCallback11(
|
|
3165
|
-
(_event, node) => {
|
|
3166
|
-
if (onNodeDoubleClick && node.data) {
|
|
3167
|
-
onNodeDoubleClick(node.id, node.data);
|
|
3168
|
-
}
|
|
3169
|
-
},
|
|
3170
|
-
[onNodeDoubleClick]
|
|
3171
|
-
);
|
|
3172
|
-
const handleNodeContextMenu = useCallback11(
|
|
3173
|
-
(event, node) => {
|
|
3174
|
-
event.preventDefault();
|
|
3175
|
-
if (onNodeContextMenu && node.data) {
|
|
3176
|
-
onNodeContextMenu(node.id, node.data);
|
|
3177
|
-
}
|
|
3178
|
-
},
|
|
3179
|
-
[onNodeContextMenu]
|
|
3180
|
-
);
|
|
3181
3190
|
const handleEdgeClick = useCallback11(
|
|
3182
3191
|
(_event, edge) => {
|
|
3183
|
-
if (onEdgeClick) {
|
|
3184
|
-
|
|
3192
|
+
if (onEdgeClick && data?.edges) {
|
|
3193
|
+
const edgeData = data.edges.find((e) => `${e.source}-${e.target}` === edge.id);
|
|
3194
|
+
if (edgeData) onEdgeClick(edgeData);
|
|
3185
3195
|
}
|
|
3186
3196
|
},
|
|
3187
|
-
[onEdgeClick]
|
|
3197
|
+
[onEdgeClick, data]
|
|
3188
3198
|
);
|
|
3189
|
-
|
|
3190
|
-
return
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
},
|
|
3208
|
-
labelStyle: {
|
|
3209
|
-
fill: isDark ? "#fff" : "#333",
|
|
3210
|
-
fontSize: 11,
|
|
3211
|
-
fontWeight: 400,
|
|
3212
|
-
...edge.labelStyle
|
|
3213
|
-
},
|
|
3214
|
-
labelBgStyle: {
|
|
3215
|
-
fill: "transparent",
|
|
3216
|
-
fillOpacity: 0,
|
|
3217
|
-
...edge.labelBgStyle
|
|
3218
|
-
},
|
|
3219
|
-
markerEnd: {
|
|
3220
|
-
type: MarkerType.ArrowClosed,
|
|
3221
|
-
color: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
|
|
3222
|
-
width: 12,
|
|
3223
|
-
height: 12,
|
|
3224
|
-
...edge.markerEnd
|
|
3199
|
+
if (!data?.nodes?.length) {
|
|
3200
|
+
return /* @__PURE__ */ jsx24(
|
|
3201
|
+
"div",
|
|
3202
|
+
{
|
|
3203
|
+
style: {
|
|
3204
|
+
width,
|
|
3205
|
+
height,
|
|
3206
|
+
backgroundColor: bgColor,
|
|
3207
|
+
borderRadius: "12px",
|
|
3208
|
+
display: "flex",
|
|
3209
|
+
alignItems: "center",
|
|
3210
|
+
justifyContent: "center",
|
|
3211
|
+
color: isDark ? "#94a3b8" : "#64748b"
|
|
3212
|
+
},
|
|
3213
|
+
children: /* @__PURE__ */ jsxs18("div", { style: { textAlign: "center" }, children: [
|
|
3214
|
+
/* @__PURE__ */ jsx24("div", { style: { fontSize: "48px", marginBottom: "16px" }, children: "\u{1F4CA}" }),
|
|
3215
|
+
/* @__PURE__ */ jsx24("div", { children: "\u6682\u65E0\u5173\u7CFB\u6570\u636E" })
|
|
3216
|
+
] })
|
|
3225
3217
|
}
|
|
3226
|
-
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
.relation-container {
|
|
3230
|
-
position: relative;
|
|
3231
|
-
width: 100%;
|
|
3232
|
-
height: 100%;
|
|
3233
|
-
overflow: hidden;
|
|
3234
|
-
}
|
|
3235
|
-
.react-flow__background,
|
|
3236
|
-
.react-flow__pane,
|
|
3237
|
-
.react-flow__renderer,
|
|
3238
|
-
.react-flow__viewport {
|
|
3239
|
-
background-color: ${bgColor} !important;
|
|
3240
|
-
}
|
|
3241
|
-
.relation-node {
|
|
3242
|
-
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
|
|
3243
|
-
}
|
|
3244
|
-
.relation-node:hover {
|
|
3245
|
-
transform: translateY(-4px) scale(1.02);
|
|
3246
|
-
box-shadow: ${isDark ? "0 12px 28px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.2)" : "0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.05)"};
|
|
3247
|
-
}
|
|
3248
|
-
.react-flow__edge-path {
|
|
3249
|
-
transition: stroke-width 0.2s ease, stroke 0.2s ease;
|
|
3250
|
-
}
|
|
3251
|
-
.react-flow__edge:hover .react-flow__edge-path {
|
|
3252
|
-
stroke-width: 2.5px;
|
|
3253
|
-
stroke: ${edgeStyles.hoverColor || (isDark ? "#ffa5a5" : "#ff8e8e")};
|
|
3254
|
-
}
|
|
3255
|
-
/* \u8FDE\u63A5\u70B9\u60AC\u505C\u6548\u679C */
|
|
3256
|
-
.react-flow__handle {
|
|
3257
|
-
transition: all 0.2s ease;
|
|
3258
|
-
}
|
|
3259
|
-
.react-flow__handle:hover {
|
|
3260
|
-
transform: scale(1.3);
|
|
3261
|
-
background-color: ${isDark ? "#ffa5a5" : "#ff8e8e"} !important;
|
|
3262
|
-
}
|
|
3263
|
-
@keyframes pulse {
|
|
3264
|
-
0%, 100% {
|
|
3265
|
-
opacity: 1;
|
|
3266
|
-
transform: scale(1);
|
|
3267
|
-
}
|
|
3268
|
-
50% {
|
|
3269
|
-
opacity: 0.7;
|
|
3270
|
-
transform: scale(1.2);
|
|
3271
|
-
}
|
|
3272
|
-
}
|
|
3273
|
-
/* \u7B80\u7EA6\u6EDA\u52A8\u6761 */
|
|
3274
|
-
.relation-container ::-webkit-scrollbar {
|
|
3275
|
-
width: 6px;
|
|
3276
|
-
height: 6px;
|
|
3277
|
-
}
|
|
3278
|
-
.relation-container ::-webkit-scrollbar-track {
|
|
3279
|
-
background: ${isDark ? "#1e293b" : "#e2e8f0"};
|
|
3280
|
-
border-radius: 3px;
|
|
3281
|
-
}
|
|
3282
|
-
.relation-container ::-webkit-scrollbar-thumb {
|
|
3283
|
-
background: ${isDark ? "#475569" : "#cbd5e1"};
|
|
3284
|
-
border-radius: 3px;
|
|
3285
|
-
}
|
|
3286
|
-
.relation-container ::-webkit-scrollbar-thumb:hover {
|
|
3287
|
-
background: ${isDark ? "#ff8e8e" : "#ff6b6b"};
|
|
3288
|
-
}
|
|
3289
|
-
`;
|
|
3290
|
-
return /* @__PURE__ */ jsxs18(
|
|
3218
|
+
);
|
|
3219
|
+
}
|
|
3220
|
+
return /* @__PURE__ */ jsx24(
|
|
3291
3221
|
"div",
|
|
3292
3222
|
{
|
|
3293
3223
|
className: `relation-container ${className}`,
|
|
3294
|
-
style: {
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
fitViewOptions,
|
|
3318
|
-
defaultViewport,
|
|
3319
|
-
minZoom,
|
|
3320
|
-
maxZoom,
|
|
3321
|
-
snapToGrid,
|
|
3322
|
-
snapGrid,
|
|
3323
|
-
nodesDraggable: enableNodeDrag,
|
|
3324
|
-
nodesConnectable: enableEdgeCreation,
|
|
3325
|
-
connectionLineType: ConnectionLineType.Straight,
|
|
3326
|
-
connectionLineStyle: {
|
|
3327
|
-
stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
|
|
3328
|
-
strokeWidth: 1.8
|
|
3329
|
-
},
|
|
3330
|
-
attributionPosition: "bottom-right",
|
|
3331
|
-
zoomOnScroll: true,
|
|
3332
|
-
zoomOnPinch: true,
|
|
3333
|
-
zoomOnDoubleClick: false,
|
|
3334
|
-
panOnScroll: false,
|
|
3335
|
-
panOnDrag: true,
|
|
3336
|
-
proOptions: { hideAttribution: true },
|
|
3337
|
-
elevateEdgesOnSelect: true,
|
|
3338
|
-
defaultEdgeOptions: {
|
|
3339
|
-
type: "straight",
|
|
3340
|
-
style: { stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"), strokeWidth: 1.8 },
|
|
3341
|
-
markerEnd: { type: MarkerType.ArrowClosed, width: 12, height: 12 }
|
|
3342
|
-
}
|
|
3343
|
-
}
|
|
3344
|
-
)
|
|
3345
|
-
]
|
|
3224
|
+
style: { width, height, ...style, backgroundColor: bgColor, borderRadius: "12px", overflow: "hidden" },
|
|
3225
|
+
children: /* @__PURE__ */ jsx24(
|
|
3226
|
+
ReactFlow,
|
|
3227
|
+
{
|
|
3228
|
+
nodes,
|
|
3229
|
+
edges,
|
|
3230
|
+
onNodesChange,
|
|
3231
|
+
onEdgesChange,
|
|
3232
|
+
onNodeClick: handleNodeClick,
|
|
3233
|
+
onEdgeClick: handleEdgeClick,
|
|
3234
|
+
nodeTypes,
|
|
3235
|
+
edgeTypes,
|
|
3236
|
+
nodesDraggable: false,
|
|
3237
|
+
nodesConnectable: false,
|
|
3238
|
+
fitView: false,
|
|
3239
|
+
minZoom: 0.3,
|
|
3240
|
+
maxZoom: 2,
|
|
3241
|
+
zoomOnScroll: true,
|
|
3242
|
+
panOnDrag: true,
|
|
3243
|
+
proOptions: { hideAttribution: true },
|
|
3244
|
+
children: /* @__PURE__ */ jsx24(Background, { color: isDark ? "#1e293b" : "#e2e8f0", gap: 20, size: 1 })
|
|
3245
|
+
}
|
|
3246
|
+
)
|
|
3346
3247
|
}
|
|
3347
3248
|
);
|
|
3348
3249
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowcloudai-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "flowcloudai",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@dnd-kit/core": "^6.3.1",
|
|
38
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
39
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
38
40
|
"@uiw/react-md-editor": "^4.0.4",
|
|
39
41
|
"@xyflow/react": "^12.10.2"
|
|
40
42
|
}
|