flowcloudai-ui 0.1.2 → 0.1.4

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.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, MouseEvent, CSSProperties } from 'react';
3
+ import React__default, { ReactNode, ComponentType, FC, MouseEvent, CSSProperties } from 'react';
4
4
 
5
5
  type Theme = 'light' | 'dark' | 'system';
6
6
  interface ThemeContextType {
@@ -498,6 +498,12 @@ interface TabBarProps {
498
498
  tabActiveBackground?: string;
499
499
  /** 激活态指示器颜色(attached 模式底线 / floating 模式无效) */
500
500
  activeIndicatorColor?: string;
501
+ /**
502
+ * 将 TabBar 空白区域标记为 Tauri 窗口拖拽区域。
503
+ * 开启后,标签之外的空白处可拖动窗口;标签、关闭、添加按钮已内置 no-drag 保护。
504
+ * @default false
505
+ */
506
+ tauriDragRegion?: boolean;
501
507
  }
502
508
  declare const TabBar: React__default.NamedExoticComponent<TabBarProps>;
503
509
 
@@ -670,7 +676,17 @@ interface RelationProps {
670
676
  enableNodeDrag?: boolean;
671
677
  onNodeContextMenu?: (nodeId: string, nodeData: RelationNodeData) => void;
672
678
  theme?: 'dark' | 'light';
679
+ edgeStyles?: {
680
+ defaultColor?: string;
681
+ hoverColor?: string;
682
+ selectedColor?: string;
683
+ };
684
+ nodeStyles?: {
685
+ borderRadius?: string;
686
+ minWidth?: string;
687
+ };
688
+ showHandles?: boolean;
673
689
  }
674
- declare const Relation: React.FC<RelationProps>;
690
+ declare const Relation: FC<RelationProps>;
675
691
 
676
692
  export { type AlertMode, type AlertProps, AlertProvider, type AlertProviderProps, type AlertType, Avatar, type AvatarProps, type AvatarShape, Button, ButtonGroup, ButtonToolbar, Card, type CardProps, type CategoryTreeNode, Chat, type ChatProps, CheckButton, type ContextMenuAction, type ContextMenuDivider, type ContextMenuItem, ContextMenuProvider, type ContextMenuProviderProps, type Conversation, DeleteDialog, type DeleteMode, type DropPosition, type FlatCategory, type FlatToTreeResult, Input, ListGroup, ListGroupItem, type ListGroupItemProps, type ListGroupProps, MarkdownEditor, type MarkdownEditorProps, type Message, type MessageRole, OrphanDialog, type OrphanResolution, type OrphanResolutionMap, Relation, type RelationEdgeData, type RelationNodeData, type RelationProps, RollingBox, Select, SideBar, type SideBarItem, type SideBarProps, Slider, SmartMessage, type SmartMessageProps, TabBar, type TabBarProps, type TabItem, TagItem, type TagItemProps, type TagSchema, type TagValue, type Theme, ThemeProvider, Tree, type TreeProps, VirtualList, findNodeInfo, flatToTree, isDescendantOf, lazyLoad, useAlert, useContextMenu, useTheme };
package/dist/index.js CHANGED
@@ -2040,7 +2040,7 @@ function useAdaptiveTabLayout(navRef, options) {
2040
2040
  const maxTabWidthRatioRef = useRef7(maxTabWidthRatio);
2041
2041
  maxTabWidthRatioRef.current = maxTabWidthRatio;
2042
2042
  const [layout, setLayout] = useState13({ scrollMode: false, tabWidth: void 0 });
2043
- const calculateTimeoutRef = useRef7(null);
2043
+ const rafRef = useRef7(null);
2044
2044
  const lastLayoutRef = useRef7({ scrollMode: false, tabWidth: void 0 });
2045
2045
  const addBtnWidthRef = useRef7(0);
2046
2046
  const lastAddableRef = useRef7(void 0);
@@ -2073,8 +2073,8 @@ function useAdaptiveTabLayout(navRef, options) {
2073
2073
  const tabGap = navWrap ? parseFloat(getComputedStyle(navWrap).gap) : 0;
2074
2074
  const totalGapWidth = (currentItemsLength - 1) * tabGap;
2075
2075
  const idealW = (navW - totalGapWidth) / currentItemsLength;
2076
- const threshold = window.innerWidth * currentMinWidthRatio;
2077
- const maxAllowedWidth = window.innerWidth * currentMaxTabWidthRatio;
2076
+ const threshold = screen.width * currentMinWidthRatio;
2077
+ const maxAllowedWidth = screen.width * currentMaxTabWidthRatio;
2078
2078
  const minAllowedWidth = 42;
2079
2079
  const prev = lastLayoutRef.current;
2080
2080
  const hysteresisFactor = 1.1;
@@ -2096,20 +2096,26 @@ function useAdaptiveTabLayout(navRef, options) {
2096
2096
  setLayout(newLayout);
2097
2097
  }
2098
2098
  }, [navRef]);
2099
- const calculateDebounced = useCallback8(() => {
2100
- if (calculateTimeoutRef.current) clearTimeout(calculateTimeoutRef.current);
2101
- calculateTimeoutRef.current = setTimeout(calculate, 50);
2102
- }, [calculate]);
2103
- const calculateDebouncedRef = useRef7(calculateDebounced);
2104
- calculateDebouncedRef.current = calculateDebounced;
2099
+ const calculateRef = useRef7(calculate);
2100
+ calculateRef.current = calculate;
2105
2101
  useEffect8(() => {
2106
- const rafId = requestAnimationFrame(calculate);
2107
- const handleResize = () => calculateDebouncedRef.current();
2108
- window.addEventListener("resize", handleResize);
2102
+ const navOuter = navRef.current?.parentElement;
2103
+ if (!navOuter) return;
2104
+ const ro = new ResizeObserver(() => {
2105
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2106
+ rafRef.current = requestAnimationFrame(() => {
2107
+ rafRef.current = null;
2108
+ calculateRef.current();
2109
+ });
2110
+ });
2111
+ ro.observe(navOuter);
2112
+ rafRef.current = requestAnimationFrame(() => {
2113
+ rafRef.current = null;
2114
+ calculateRef.current();
2115
+ });
2109
2116
  return () => {
2110
- cancelAnimationFrame(rafId);
2111
- window.removeEventListener("resize", handleResize);
2112
- if (calculateTimeoutRef.current) clearTimeout(calculateTimeoutRef.current);
2117
+ ro.disconnect();
2118
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2113
2119
  };
2114
2120
  }, []);
2115
2121
  useEffect8(() => {
@@ -2209,6 +2215,7 @@ var TabBar = memo4(({
2209
2215
  renderAddButton,
2210
2216
  className = "",
2211
2217
  style,
2218
+ tauriDragRegion = false,
2212
2219
  background,
2213
2220
  tabColor,
2214
2221
  tabHoverColor,
@@ -2336,7 +2343,8 @@ var TabBar = memo4(({
2336
2343
  children: renderAddButton ? renderAddButton() : "+"
2337
2344
  }
2338
2345
  );
2339
- return /* @__PURE__ */ jsx18("div", { className: rootClasses, style: mergedStyle, role: "tablist", children: /* @__PURE__ */ jsxs13("div", { className: `fc-tab-bar__nav-outer${scrollMode ? " fc-tab-bar__nav-outer--scroll" : ""}`, children: [
2346
+ const dragRegion = tauriDragRegion ? { "data-tauri-drag-region": "" } : {};
2347
+ return /* @__PURE__ */ jsx18("div", { className: rootClasses, style: mergedStyle, role: "tablist", ...dragRegion, children: /* @__PURE__ */ jsxs13("div", { className: `fc-tab-bar__nav-outer${scrollMode ? " fc-tab-bar__nav-outer--scroll" : ""}`, ...dragRegion, children: [
2340
2348
  /* @__PURE__ */ jsx18("div", { className: `fc-tab-bar__nav${scrollMode ? " fc-tab-bar__nav--scroll" : ""}`, ref: navRef, children: scrollMode ? /* @__PURE__ */ jsx18(RollingBox, { horizontal: true, showThumb: "hide", style: { flex: 1, minWidth: 0, height: "auto" }, children: tabList }) : tabList }),
2341
2349
  addBtn
2342
2350
  ] }) });
@@ -2954,7 +2962,7 @@ var Chat = ({
2954
2962
  };
2955
2963
 
2956
2964
  // src/components/Relation/Relation.tsx
2957
- import { useCallback as useCallback12, useEffect as useEffect13 } from "react";
2965
+ import React13, { useCallback as useCallback12, useEffect as useEffect13, memo as memo5 } from "react";
2958
2966
  import {
2959
2967
  ReactFlow,
2960
2968
  useNodesState,
@@ -2968,7 +2976,7 @@ import {
2968
2976
  ReactFlowProvider
2969
2977
  } from "@xyflow/react";
2970
2978
  import "@xyflow/react/dist/style.css";
2971
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
2979
+ import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
2972
2980
  var getIconEmoji = (iconType) => {
2973
2981
  const map = {
2974
2982
  war: "\u2694\uFE0F",
@@ -2990,16 +2998,77 @@ var getStatusColor = (status) => {
2990
2998
  };
2991
2999
  return map[status || "active"];
2992
3000
  };
2993
- var CustomNode = ({ data, theme = "light" }) => {
2994
- const isDark = theme === "dark";
3001
+ var ConnectionHandles = ({ isDark, showHandles }) => {
3002
+ const handleStyle = {
3003
+ background: isDark ? "#ff8e8e" : "#ff6b6b",
3004
+ width: "8px",
3005
+ height: "8px",
3006
+ borderRadius: "50%",
3007
+ border: `1px solid ${isDark ? "#1e293b" : "#ffffff"}`,
3008
+ transition: "all 0.2s ease"
3009
+ };
3010
+ const hiddenHandleStyle = {
3011
+ opacity: 0,
3012
+ width: "0px",
3013
+ height: "0px",
3014
+ pointerEvents: "none"
3015
+ };
3016
+ const actualStyle = showHandles ? handleStyle : hiddenHandleStyle;
3017
+ return /* @__PURE__ */ jsxs18(Fragment5, { children: [
3018
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-left", style: { ...actualStyle, left: "25%" } }),
3019
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-left-source", style: { ...actualStyle, left: "25%" } }),
3020
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-center", style: { ...actualStyle, left: "50%" } }),
3021
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-center-source", style: { ...actualStyle, left: "50%" } }),
3022
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "top-right", style: { ...actualStyle, left: "75%" } }),
3023
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "top-right-source", style: { ...actualStyle, left: "75%" } }),
3024
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-top", style: { ...actualStyle, top: "25%" } }),
3025
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-top-source", style: { ...actualStyle, top: "25%" } }),
3026
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-center", style: { ...actualStyle, top: "50%" } }),
3027
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-center-source", style: { ...actualStyle, top: "50%" } }),
3028
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "right-bottom", style: { ...actualStyle, top: "75%" } }),
3029
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "right-bottom-source", style: { ...actualStyle, top: "75%" } }),
3030
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-left", style: { ...actualStyle, left: "25%" } }),
3031
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-left-source", style: { ...actualStyle, left: "25%" } }),
3032
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-center", style: { ...actualStyle, left: "50%" } }),
3033
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-center-source", style: { ...actualStyle, left: "50%" } }),
3034
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "bottom-right", style: { ...actualStyle, left: "75%" } }),
3035
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "bottom-right-source", style: { ...actualStyle, left: "75%" } }),
3036
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-top", style: { ...actualStyle, top: "25%" } }),
3037
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-top-source", style: { ...actualStyle, top: "25%" } }),
3038
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-center", style: { ...actualStyle, top: "50%" } }),
3039
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-center-source", style: { ...actualStyle, top: "50%" } }),
3040
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "left-bottom", style: { ...actualStyle, top: "75%" } }),
3041
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "left-bottom-source", style: { ...actualStyle, top: "75%" } }),
3042
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "corner-top-left", style: { ...actualStyle, left: "10%" } }),
3043
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "corner-top-left-source", style: { ...actualStyle, left: "10%" } }),
3044
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, id: "corner-top-right", style: { ...actualStyle, left: "90%" } }),
3045
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Top, id: "corner-top-right-source", style: { ...actualStyle, left: "90%" } }),
3046
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "corner-bottom-left", style: { ...actualStyle, left: "10%" } }),
3047
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "corner-bottom-left-source", style: { ...actualStyle, left: "10%" } }),
3048
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Bottom, id: "corner-bottom-right", style: { ...actualStyle, left: "90%" } }),
3049
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, id: "corner-bottom-right-source", style: { ...actualStyle, left: "90%" } }),
3050
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "corner-left-top", style: { ...actualStyle, top: "10%" } }),
3051
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "corner-left-top-source", style: { ...actualStyle, top: "10%" } }),
3052
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Left, id: "corner-left-bottom", style: { ...actualStyle, top: "90%" } }),
3053
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Left, id: "corner-left-bottom-source", style: { ...actualStyle, top: "90%" } }),
3054
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "corner-right-top", style: { ...actualStyle, top: "10%" } }),
3055
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "corner-right-top-source", style: { ...actualStyle, top: "10%" } }),
3056
+ /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Right, id: "corner-right-bottom", style: { ...actualStyle, top: "90%" } }),
3057
+ /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Right, id: "corner-right-bottom-source", style: { ...actualStyle, top: "90%" } })
3058
+ ] });
3059
+ };
3060
+ var CustomNode = memo5(({ data, theme: propTheme }) => {
3061
+ const isDark = (data.theme || propTheme) === "dark";
3062
+ const showHandles = data.showHandles !== void 0 ? data.showHandles : false;
2995
3063
  const nodeStyle = {
2996
3064
  background: isDark ? "linear-gradient(135deg, #1e293b 0%, #0f172a 100%)" : "linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)",
2997
- border: `2px solid ${isDark ? "rgba(255, 255, 255, 0.12)" : "rgba(0, 0, 0, 0.08)"}`,
3065
+ border: `2px solid ${isDark ? "rgba(255, 255, 255, 0.15)" : "rgba(0, 0, 0, 0.08)"}`,
2998
3066
  borderRadius: "14px",
2999
- boxShadow: isDark ? "0 8px 20px rgba(0, 0, 0, 0.25)" : "0 4px 12px rgba(0, 0, 0, 0.08)",
3067
+ boxShadow: isDark ? "0 8px 20px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2)" : "0 4px 12px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.05)",
3000
3068
  minWidth: "240px",
3001
3069
  cursor: "pointer",
3002
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
3070
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
3071
+ position: "relative"
3003
3072
  };
3004
3073
  const iconStyle = {
3005
3074
  width: "52px",
@@ -3008,8 +3077,9 @@ var CustomNode = ({ data, theme = "light" }) => {
3008
3077
  display: "flex",
3009
3078
  alignItems: "center",
3010
3079
  justifyContent: "center",
3011
- background: isDark ? "rgba(255, 255, 255, 0.08)" : "rgba(0, 0, 0, 0.04)",
3012
- transition: "all 0.3s ease"
3080
+ background: isDark ? "linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.05) 100%)" : "linear-gradient(135deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.02) 100%)",
3081
+ transition: "all 0.3s ease",
3082
+ boxShadow: isDark ? "inset 0 1px 1px rgba(255, 255, 255, 0.1)" : "inset 0 1px 1px rgba(0, 0, 0, 0.02)"
3013
3083
  };
3014
3084
  const titleStyle = {
3015
3085
  fontWeight: 700,
@@ -3018,7 +3088,8 @@ var CustomNode = ({ data, theme = "light" }) => {
3018
3088
  whiteSpace: "nowrap",
3019
3089
  overflow: "hidden",
3020
3090
  textOverflow: "ellipsis",
3021
- color: isDark ? "#ffffff" : "#1e293b"
3091
+ color: isDark ? "#ffffff" : "#1e293b",
3092
+ letterSpacing: isDark ? "0.3px" : "normal"
3022
3093
  };
3023
3094
  const subtitleStyle = {
3024
3095
  fontSize: "11px",
@@ -3034,11 +3105,18 @@ var CustomNode = ({ data, theme = "light" }) => {
3034
3105
  textOverflow: "ellipsis",
3035
3106
  color: isDark ? "rgba(255, 255, 255, 0.45)" : "#94a3b8"
3036
3107
  };
3037
- return /* @__PURE__ */ jsxs18("div", { style: nodeStyle, children: [
3038
- /* @__PURE__ */ jsx24(Handle, { type: "target", position: Position.Top, isConnectable: true }),
3108
+ return /* @__PURE__ */ jsxs18("div", { style: nodeStyle, className: "relation-node", children: [
3109
+ /* @__PURE__ */ jsx24(ConnectionHandles, { isDark, showHandles }),
3039
3110
  /* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "center", gap: "14px", padding: "14px 18px" }, children: [
3040
3111
  /* @__PURE__ */ jsxs18("div", { style: { position: "relative", flexShrink: 0 }, children: [
3041
- /* @__PURE__ */ jsx24("div", { style: iconStyle, children: data.imageUrl ? /* @__PURE__ */ jsx24("img", { src: data.imageUrl, alt: data.title, style: { width: "100%", height: "100%", objectFit: "cover", borderRadius: "12px" } }) : /* @__PURE__ */ jsx24("span", { style: { fontSize: "28px" }, children: getIconEmoji(data.iconType) }) }),
3112
+ /* @__PURE__ */ jsx24("div", { style: iconStyle, children: data.imageUrl ? /* @__PURE__ */ jsx24(
3113
+ "img",
3114
+ {
3115
+ src: data.imageUrl,
3116
+ alt: data.title,
3117
+ style: { width: "100%", height: "100%", objectFit: "cover", borderRadius: "12px" }
3118
+ }
3119
+ ) : /* @__PURE__ */ jsx24("span", { style: { fontSize: "28px", filter: isDark ? "drop-shadow(0 1px 2px rgba(0,0,0,0.2))" : "none" }, children: getIconEmoji(data.iconType) }) }),
3042
3120
  data.status && /* @__PURE__ */ jsx24("div", { style: {
3043
3121
  position: "absolute",
3044
3122
  bottom: "-2px",
@@ -3047,7 +3125,9 @@ var CustomNode = ({ data, theme = "light" }) => {
3047
3125
  height: "12px",
3048
3126
  borderRadius: "50%",
3049
3127
  border: `2px solid ${isDark ? "#1e293b" : "#ffffff"}`,
3050
- backgroundColor: getStatusColor(data.status)
3128
+ backgroundColor: getStatusColor(data.status),
3129
+ animation: data.status === "warning" ? "pulse 2s infinite" : "none",
3130
+ boxShadow: isDark ? "0 0 0 1px rgba(0,0,0,0.2)" : "none"
3051
3131
  } })
3052
3132
  ] }),
3053
3133
  /* @__PURE__ */ jsxs18("div", { style: { flex: 1, minWidth: 0 }, children: [
@@ -3055,13 +3135,21 @@ var CustomNode = ({ data, theme = "light" }) => {
3055
3135
  /* @__PURE__ */ jsx24("div", { style: subtitleStyle, children: data.subtitle }),
3056
3136
  data.description && /* @__PURE__ */ jsx24("div", { style: descriptionStyle, children: data.description })
3057
3137
  ] })
3058
- ] }),
3059
- /* @__PURE__ */ jsx24(Handle, { type: "source", position: Position.Bottom, isConnectable: true })
3138
+ ] })
3060
3139
  ] });
3061
- };
3140
+ });
3141
+ CustomNode.displayName = "CustomNode";
3062
3142
  var nodeTypes = {
3063
3143
  custom: CustomNode
3064
3144
  };
3145
+ var getEdgeStyle = (theme, isHovered, isSelected) => {
3146
+ const baseColor = theme === "dark" ? "#7c8ba0" : "#a0aec0";
3147
+ const hoverColor = "#ff8e8e";
3148
+ const selectedColor = "#ff6b6b";
3149
+ if (isSelected) return { stroke: selectedColor, strokeWidth: 2.5 };
3150
+ if (isHovered) return { stroke: hoverColor, strokeWidth: 2.5 };
3151
+ return { stroke: baseColor, strokeWidth: 1.8 };
3152
+ };
3065
3153
  var RelationContent = ({
3066
3154
  nodes: propNodes,
3067
3155
  edges: propEdges,
@@ -3085,9 +3173,12 @@ var RelationContent = ({
3085
3173
  enableEdgeCreation = true,
3086
3174
  enableNodeDrag = true,
3087
3175
  onNodeContextMenu,
3088
- theme: propTheme = "light"
3176
+ theme: propTheme = "light",
3177
+ edgeStyles = {},
3178
+ nodeStyles = {},
3179
+ showHandles = false
3089
3180
  }) => {
3090
- const [nodes, , onNodesChange] = useNodesState(propNodes || []);
3181
+ const [nodes, setNodes, onNodesChange] = useNodesState(propNodes || []);
3091
3182
  const [edges, setEdges, onEdgesChange] = useEdgesState(propEdges || []);
3092
3183
  const { fitView: fitViewFn } = useReactFlow();
3093
3184
  const theme = propTheme;
@@ -3095,18 +3186,31 @@ var RelationContent = ({
3095
3186
  const bgColor = isDark ? "#0f172a" : "#f5f7fa";
3096
3187
  useEffect13(() => {
3097
3188
  if (fitView && fitViewFn && (propNodes?.length || 0) > 0) {
3098
- setTimeout(() => {
3099
- fitViewFn({ duration: 300, ...fitViewOptions }).catch((error) => {
3189
+ const timer = setTimeout(() => {
3190
+ fitViewFn({ duration: 300, padding: 0.2, ...fitViewOptions }).catch((error) => {
3100
3191
  console.warn("Fit view failed:", error);
3101
3192
  });
3102
3193
  }, 100);
3194
+ return () => clearTimeout(timer);
3103
3195
  }
3104
3196
  }, [fitView, fitViewFn, fitViewOptions, propNodes]);
3197
+ useEffect13(() => {
3198
+ if (propNodes) {
3199
+ setNodes(propNodes);
3200
+ }
3201
+ }, [propNodes, setNodes]);
3202
+ useEffect13(() => {
3203
+ if (propEdges) {
3204
+ setEdges(propEdges);
3205
+ }
3206
+ }, [propEdges, setEdges]);
3105
3207
  const handleNodesChange = useCallback12(
3106
3208
  (changes) => {
3107
3209
  onNodesChange(changes);
3108
3210
  if (onNodesChangeProp) {
3109
- onNodesChangeProp(nodes);
3211
+ setTimeout(() => {
3212
+ onNodesChangeProp(nodes);
3213
+ }, 0);
3110
3214
  }
3111
3215
  },
3112
3216
  [onNodesChange, onNodesChangeProp, nodes]
@@ -3115,7 +3219,9 @@ var RelationContent = ({
3115
3219
  (changes) => {
3116
3220
  onEdgesChange(changes);
3117
3221
  if (onEdgesChangeProp) {
3118
- onEdgesChangeProp(edges);
3222
+ setTimeout(() => {
3223
+ onEdgesChangeProp(edges);
3224
+ }, 0);
3119
3225
  }
3120
3226
  },
3121
3227
  [onEdgesChange, onEdgesChangeProp, edges]
@@ -3124,18 +3230,25 @@ var RelationContent = ({
3124
3230
  (params) => {
3125
3231
  const newEdge = {
3126
3232
  ...params,
3127
- id: `edge-${Date.now()}-${Math.random()}`,
3128
- type: "smoothstep",
3129
- style: { stroke: "#ff6b6b", strokeWidth: 2 },
3130
- markerEnd: { type: MarkerType.ArrowClosed, color: "#ff6b6b" },
3131
- label: "\u65B0\u8FDE\u63A5"
3233
+ id: `edge-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
3234
+ type: "straight",
3235
+ style: { stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"), strokeWidth: 1.8 },
3236
+ markerEnd: {
3237
+ type: MarkerType.ArrowClosed,
3238
+ color: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
3239
+ width: 12,
3240
+ height: 12
3241
+ },
3242
+ label: "",
3243
+ labelStyle: { fill: isDark ? "#fff" : "#333", fontSize: 11, fontWeight: 400 },
3244
+ labelBgStyle: { fill: "transparent", fillOpacity: 0 }
3132
3245
  };
3133
3246
  setEdges((eds) => addEdge(newEdge, eds));
3134
3247
  if (onConnectProp) {
3135
3248
  onConnectProp(params);
3136
3249
  }
3137
3250
  },
3138
- [setEdges, onConnectProp]
3251
+ [setEdges, onConnectProp, edgeStyles.defaultColor, isDark]
3139
3252
  );
3140
3253
  const handleNodeClick = useCallback12(
3141
3254
  (_event, node) => {
@@ -3170,18 +3283,107 @@ var RelationContent = ({
3170
3283
  },
3171
3284
  [onEdgeClick]
3172
3285
  );
3173
- const nodesWithTheme = nodes.map((node) => ({
3174
- ...node,
3175
- data: { ...node.data, theme }
3176
- }));
3286
+ const nodesWithTheme = React13.useMemo(() => {
3287
+ return nodes.map((node) => ({
3288
+ ...node,
3289
+ data: {
3290
+ ...node.data,
3291
+ theme,
3292
+ showHandles
3293
+ },
3294
+ className: `relation-node ${node.className || ""}`
3295
+ }));
3296
+ }, [nodes, theme, showHandles]);
3297
+ const edgesWithStyle = React13.useMemo(() => {
3298
+ return edges.map((edge) => ({
3299
+ ...edge,
3300
+ type: edge.type || "straight",
3301
+ style: {
3302
+ ...edge.style,
3303
+ ...getEdgeStyle(theme)
3304
+ },
3305
+ labelStyle: {
3306
+ fill: isDark ? "#fff" : "#333",
3307
+ fontSize: 11,
3308
+ fontWeight: 400,
3309
+ ...edge.labelStyle
3310
+ },
3311
+ labelBgStyle: {
3312
+ fill: "transparent",
3313
+ fillOpacity: 0,
3314
+ ...edge.labelBgStyle
3315
+ },
3316
+ markerEnd: {
3317
+ type: MarkerType.ArrowClosed,
3318
+ color: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
3319
+ width: 12,
3320
+ height: 12,
3321
+ ...edge.markerEnd
3322
+ }
3323
+ }));
3324
+ }, [edges, theme, isDark, edgeStyles.defaultColor]);
3177
3325
  const globalStyle = `
3178
- .react-flow__background,
3179
- .react-flow__pane,
3180
- .react-flow__renderer,
3181
- .react-flow__viewport {
3182
- background-color: ${bgColor} !important;
3183
- }
3184
- `;
3326
+ .relation-container {
3327
+ position: relative;
3328
+ width: 100%;
3329
+ height: 100%;
3330
+ overflow: hidden;
3331
+ }
3332
+ .react-flow__background,
3333
+ .react-flow__pane,
3334
+ .react-flow__renderer,
3335
+ .react-flow__viewport {
3336
+ background-color: ${bgColor} !important;
3337
+ }
3338
+ .relation-node {
3339
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
3340
+ }
3341
+ .relation-node:hover {
3342
+ transform: translateY(-4px) scale(1.02);
3343
+ 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)"};
3344
+ }
3345
+ .react-flow__edge-path {
3346
+ transition: stroke-width 0.2s ease, stroke 0.2s ease;
3347
+ }
3348
+ .react-flow__edge:hover .react-flow__edge-path {
3349
+ stroke-width: 2.5px;
3350
+ stroke: ${edgeStyles.hoverColor || (isDark ? "#ffa5a5" : "#ff8e8e")};
3351
+ }
3352
+ /* \u8FDE\u63A5\u70B9\u60AC\u505C\u6548\u679C */
3353
+ .react-flow__handle {
3354
+ transition: all 0.2s ease;
3355
+ }
3356
+ .react-flow__handle:hover {
3357
+ transform: scale(1.3);
3358
+ background-color: ${isDark ? "#ffa5a5" : "#ff8e8e"} !important;
3359
+ }
3360
+ @keyframes pulse {
3361
+ 0%, 100% {
3362
+ opacity: 1;
3363
+ transform: scale(1);
3364
+ }
3365
+ 50% {
3366
+ opacity: 0.7;
3367
+ transform: scale(1.2);
3368
+ }
3369
+ }
3370
+ /* \u7B80\u7EA6\u6EDA\u52A8\u6761 */
3371
+ .relation-container ::-webkit-scrollbar {
3372
+ width: 6px;
3373
+ height: 6px;
3374
+ }
3375
+ .relation-container ::-webkit-scrollbar-track {
3376
+ background: ${isDark ? "#1e293b" : "#e2e8f0"};
3377
+ border-radius: 3px;
3378
+ }
3379
+ .relation-container ::-webkit-scrollbar-thumb {
3380
+ background: ${isDark ? "#475569" : "#cbd5e1"};
3381
+ border-radius: 3px;
3382
+ }
3383
+ .relation-container ::-webkit-scrollbar-thumb:hover {
3384
+ background: ${isDark ? "#ff8e8e" : "#ff6b6b"};
3385
+ }
3386
+ `;
3185
3387
  return /* @__PURE__ */ jsxs18(
3186
3388
  "div",
3187
3389
  {
@@ -3190,9 +3392,8 @@ var RelationContent = ({
3190
3392
  width,
3191
3393
  height,
3192
3394
  ...style,
3193
- position: "relative",
3194
- overflow: "hidden",
3195
- backgroundColor: bgColor
3395
+ backgroundColor: bgColor,
3396
+ borderRadius: nodeStyles.borderRadius || "12px"
3196
3397
  },
3197
3398
  children: [
3198
3399
  /* @__PURE__ */ jsx24("style", { children: globalStyle }),
@@ -3200,7 +3401,7 @@ var RelationContent = ({
3200
3401
  ReactFlow,
3201
3402
  {
3202
3403
  nodes: nodesWithTheme,
3203
- edges,
3404
+ edges: edgesWithStyle,
3204
3405
  onNodesChange: handleNodesChange,
3205
3406
  onEdgesChange: handleEdgesChange,
3206
3407
  onConnect: enableEdgeCreation ? onConnect : void 0,
@@ -3218,15 +3419,24 @@ var RelationContent = ({
3218
3419
  snapGrid,
3219
3420
  nodesDraggable: enableNodeDrag,
3220
3421
  nodesConnectable: enableEdgeCreation,
3221
- connectionLineType: ConnectionLineType.SmoothStep,
3222
- connectionLineStyle: { stroke: "#ff6b6b", strokeWidth: 2 },
3422
+ connectionLineType: ConnectionLineType.Straight,
3423
+ connectionLineStyle: {
3424
+ stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"),
3425
+ strokeWidth: 1.8
3426
+ },
3223
3427
  attributionPosition: "bottom-right",
3224
3428
  zoomOnScroll: true,
3225
3429
  zoomOnPinch: true,
3226
3430
  zoomOnDoubleClick: false,
3227
3431
  panOnScroll: false,
3228
3432
  panOnDrag: true,
3229
- proOptions: { hideAttribution: true }
3433
+ proOptions: { hideAttribution: true },
3434
+ elevateEdgesOnSelect: true,
3435
+ defaultEdgeOptions: {
3436
+ type: "straight",
3437
+ style: { stroke: edgeStyles.defaultColor || (isDark ? "#7c8ba0" : "#a0aec0"), strokeWidth: 1.8 },
3438
+ markerEnd: { type: MarkerType.ArrowClosed, width: 12, height: 12 }
3439
+ }
3230
3440
  }
3231
3441
  )
3232
3442
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowcloudai-ui",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "author": "flowcloudai",
6
6
  "module": "dist/index.js",
@@ -19,8 +19,8 @@
19
19
  "build": "tsup"
20
20
  },
21
21
  "peerDependencies": {
22
- "react": "^18 || ^19",
23
- "react-dom": "^18 || ^19"
22
+ "react": "^19",
23
+ "react-dom": "^19"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/react": "^19.2.14",