flowcloudai-ui 0.1.0 → 0.1.1

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.cjs CHANGED
@@ -38,16 +38,20 @@ __export(index_exports, {
38
38
  Card: () => Card,
39
39
  Chat: () => Chat,
40
40
  CheckButton: () => CheckButton,
41
+ ContextMenuProvider: () => ContextMenuProvider,
41
42
  DeleteDialog: () => DeleteDialog,
42
43
  Input: () => Input,
43
44
  ListGroup: () => ListGroup,
44
45
  ListGroupItem: () => ListGroupItem,
46
+ MarkdownEditor: () => MarkdownEditor,
45
47
  OrphanDialog: () => OrphanDialog,
46
48
  RollingBox: () => RollingBox,
47
49
  Select: () => Select,
48
50
  SideBar: () => SideBar,
49
51
  Slider: () => Slider,
50
- Tabs: () => Tabs,
52
+ SmartMessage: () => SmartMessage,
53
+ TabBar: () => TabBar,
54
+ TagItem: () => TagItem,
51
55
  ThemeProvider: () => ThemeProvider,
52
56
  Tree: () => Tree,
53
57
  VirtualList: () => VirtualList,
@@ -56,6 +60,7 @@ __export(index_exports, {
56
60
  isDescendantOf: () => isDescendantOf,
57
61
  lazyLoad: () => lazyLoad,
58
62
  useAlert: () => useAlert,
63
+ useContextMenu: () => useContextMenu,
59
64
  useTheme: () => useTheme
60
65
  });
61
66
  module.exports = __toCommonJS(index_exports);
@@ -111,10 +116,39 @@ function Button({
111
116
  iconOnly = false,
112
117
  iconLeft,
113
118
  iconRight,
119
+ background,
120
+ hoverBackground,
121
+ activeBackground,
122
+ color,
123
+ hoverColor,
124
+ activeColor,
125
+ borderColor,
126
+ hoverBorderColor,
114
127
  className,
128
+ style,
115
129
  children,
116
130
  ...props
117
131
  }) {
132
+ const colorVars = {
133
+ "--btn-bg": background,
134
+ "--btn-bg-hover": hoverBackground,
135
+ "--btn-bg-active": activeBackground,
136
+ "--btn-color": color,
137
+ "--btn-color-hover": hoverColor,
138
+ "--btn-color-active": activeColor,
139
+ "--btn-border": borderColor,
140
+ "--btn-border-hover": hoverBorderColor
141
+ };
142
+ const overrideStyle = {};
143
+ for (const [key, value] of Object.entries(colorVars)) {
144
+ if (value !== void 0) {
145
+ overrideStyle[key] = value;
146
+ }
147
+ }
148
+ const mergedStyle = {
149
+ ...overrideStyle,
150
+ ...style
151
+ };
118
152
  const classNames = [
119
153
  "fc-btn",
120
154
  `fc-btn--${variant}`,
@@ -131,6 +165,7 @@ function Button({
131
165
  {
132
166
  className: classNames,
133
167
  disabled: disabled || loading,
168
+ style: mergedStyle,
134
169
  ...props,
135
170
  children: [
136
171
  iconLeft && !loading && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fc-btn__icon fc-btn__icon--left", children: iconLeft }),
@@ -169,6 +204,11 @@ function CheckButton({
169
204
  size = "md",
170
205
  labelLeft,
171
206
  labelRight,
207
+ trackBackground,
208
+ checkedTrackBackground,
209
+ thumbBackground,
210
+ thumbDotColor,
211
+ labelColor,
172
212
  className = "",
173
213
  style
174
214
  }) {
@@ -187,6 +227,23 @@ function CheckButton({
187
227
  toggle();
188
228
  }
189
229
  };
230
+ const colorVars = {
231
+ "--check-track-bg": trackBackground,
232
+ "--check-track-bg-checked": checkedTrackBackground,
233
+ "--check-thumb-bg": thumbBackground,
234
+ "--check-thumb-dot-color": thumbDotColor,
235
+ "--check-label-color": labelColor
236
+ };
237
+ const overrideStyle = {};
238
+ for (const [key, value] of Object.entries(colorVars)) {
239
+ if (value !== void 0) {
240
+ overrideStyle[key] = value;
241
+ }
242
+ }
243
+ const mergedStyle = {
244
+ ...overrideStyle,
245
+ ...style
246
+ };
190
247
  const cls = [
191
248
  "fc-check",
192
249
  `fc-check--${size}`,
@@ -198,7 +255,7 @@ function CheckButton({
198
255
  "div",
199
256
  {
200
257
  className: cls,
201
- style,
258
+ style: mergedStyle,
202
259
  role: "switch",
203
260
  "aria-checked": checked,
204
261
  tabIndex: disabled ? -1 : 0,
@@ -224,8 +281,26 @@ function RollingBox({
224
281
  showTrack = false,
225
282
  children,
226
283
  className,
284
+ thumbColor,
285
+ thumbHoverColor,
286
+ thumbActiveColor,
287
+ trackColor,
288
+ style,
227
289
  ...props
228
290
  }) {
291
+ const colorVars = {
292
+ "--roll-thumb": thumbColor,
293
+ "--roll-thumb-hover": thumbHoverColor,
294
+ "--roll-thumb-active": thumbActiveColor,
295
+ "--roll-track": trackColor
296
+ };
297
+ const overrideStyle = {};
298
+ for (const [key, value] of Object.entries(colorVars)) {
299
+ if (value !== void 0) {
300
+ overrideStyle[key] = value;
301
+ }
302
+ }
303
+ const mergedStyle = { ...overrideStyle, ...style };
229
304
  const containerRef = React2.useRef(null);
230
305
  const [isScrolling, setIsScrolling] = React2.useState(false);
231
306
  const scrollTimeoutRef = React2.useRef(null);
@@ -261,6 +336,7 @@ function RollingBox({
261
336
  {
262
337
  ref: containerRef,
263
338
  className: classNames,
339
+ style: mergedStyle,
264
340
  onScroll: handleScroll,
265
341
  ...props,
266
342
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "fc-roll__content", children })
@@ -269,134 +345,100 @@ function RollingBox({
269
345
  }
270
346
 
271
347
  // src/components/Bar/SideBar.tsx
272
- var React3 = __toESM(require("react"), 1);
348
+ var import_react2 = require("react");
273
349
  var import_jsx_runtime5 = require("react/jsx-runtime");
274
- function SideBar({
275
- items,
276
- selectedKeys: controlledSelected,
277
- defaultSelectedKeys = [],
278
- openKeys: controlledOpen,
279
- defaultOpenKeys = [],
280
- onSelect,
281
- onOpenChange,
282
- collapsed: controlledCollapsed,
283
- defaultCollapsed = false,
284
- onCollapse,
285
- className,
286
- width = 240,
287
- collapsedWidth = 64
288
- }) {
289
- const [internalSelected, setInternalSelected] = React3.useState(defaultSelectedKeys);
290
- const [internalOpen, setInternalOpen] = React3.useState(defaultOpenKeys);
291
- const [internalCollapsed, setInternalCollapsed] = React3.useState(defaultCollapsed);
292
- const currentSelected = controlledSelected ?? internalSelected;
293
- const currentOpen = controlledOpen ?? internalOpen;
294
- const currentCollapsed = controlledCollapsed ?? internalCollapsed;
295
- const updateOpen = React3.useCallback((next) => {
296
- if (controlledOpen === void 0) setInternalOpen(next);
297
- onOpenChange?.(next);
298
- }, [controlledOpen, onOpenChange]);
299
- const toggleOpen = React3.useCallback((key) => {
300
- const next = currentOpen.includes(key) ? currentOpen.filter((k) => k !== key) : [...currentOpen, key];
301
- updateOpen(next);
302
- }, [currentOpen, updateOpen]);
303
- const handleSelect = React3.useCallback((key, item) => {
304
- if (item.disabled) return;
305
- const next = [key];
306
- if (controlledSelected === void 0) setInternalSelected(next);
307
- onSelect?.(next);
308
- }, [controlledSelected, onSelect]);
309
- const toggleCollapse = React3.useCallback(() => {
310
- const next = !currentCollapsed;
311
- if (controlledCollapsed === void 0) setInternalCollapsed(next);
312
- onCollapse?.(next);
313
- }, [currentCollapsed, controlledCollapsed, onCollapse]);
314
- const handleItemClick = React3.useCallback((item) => {
315
- if (item.children?.length) {
316
- toggleOpen(item.key);
317
- } else {
318
- handleSelect(item.key, item);
319
- }
320
- }, [toggleOpen, handleSelect]);
321
- const handleItemKeyDown = React3.useCallback((e, item) => {
322
- if (e.key === "Enter" || e.key === " ") {
323
- e.preventDefault();
324
- handleItemClick(item);
325
- }
326
- }, [handleItemClick]);
327
- const renderMenuItem = (item, level = 0) => {
328
- const hasChildren = (item.children?.length ?? 0) > 0;
329
- const isOpen = currentOpen.includes(item.key);
330
- const isSelected = currentSelected.includes(item.key);
331
- const itemClassName = [
332
- "fc-sidebar__item",
333
- `fc-sidebar__item--level-${level}`,
334
- hasChildren && "fc-sidebar__item--parent",
335
- isOpen && "fc-sidebar__item--open",
336
- isSelected && "fc-sidebar__item--selected",
337
- item.disabled && "fc-sidebar__item--disabled"
338
- ].filter(Boolean).join(" ");
339
- const Tag = item.href ? "a" : "div";
340
- const interactiveProps = {
341
- role: hasChildren ? "treeitem" : "menuitem",
342
- tabIndex: item.disabled ? -1 : 0,
343
- "aria-selected": isSelected || void 0,
344
- "aria-expanded": hasChildren ? isOpen : void 0,
345
- "aria-disabled": item.disabled || void 0,
346
- onClick: () => handleItemClick(item),
347
- onKeyDown: (e) => handleItemKeyDown(e, item),
348
- ...item.href ? { href: item.href } : {}
349
- };
350
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "fc-sidebar__item-wrapper", children: [
351
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Tag, { className: itemClassName, ...interactiveProps, children: [
352
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fc-sidebar__icon", "aria-hidden": "true", children: item.icon }),
353
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fc-sidebar__label", children: item.label }),
354
- hasChildren && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fc-sidebar__arrow", "aria-hidden": "true", children: "\u25B6" })
355
- ] }),
356
- hasChildren && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
357
- "div",
358
- {
359
- className: [
360
- "fc-sidebar__submenu",
361
- isOpen && "fc-sidebar__submenu--open"
362
- ].filter(Boolean).join(" "),
363
- role: "group",
364
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fc-sidebar__submenu-inner", children: item.children.map((child) => renderMenuItem(child, level + 1)) })
365
- }
366
- )
367
- ] }, item.key);
368
- };
369
- const sidebarStyle = {
370
- "--sidebar-width": `${currentCollapsed ? collapsedWidth : width}px`,
371
- "--sidebar-collapsed-width": `${collapsedWidth}px`
372
- };
350
+ var SideBarItemView = (0, import_react2.memo)(({ item, isSelected, onClick }) => {
351
+ const classes = [
352
+ "fc-sidebar__item",
353
+ isSelected && "fc-sidebar__item--selected",
354
+ item.disabled && "fc-sidebar__item--disabled"
355
+ ].filter(Boolean).join(" ");
356
+ const Tag = item.href ? "a" : "div";
357
+ const linkProps = item.href ? { href: item.href } : {};
373
358
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
374
- "aside",
359
+ Tag,
375
360
  {
376
- className: [
377
- "fc-sidebar",
378
- currentCollapsed && "fc-sidebar--collapsed",
379
- className
380
- ].filter(Boolean).join(" "),
381
- style: sidebarStyle,
382
- role: "navigation",
383
- "aria-label": "Sidebar",
361
+ className: classes,
362
+ onClick: () => !item.disabled && onClick(item.key),
363
+ ...linkProps,
384
364
  children: [
385
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fc-sidebar__header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
386
- "button",
387
- {
388
- className: "fc-sidebar__collapse-btn",
389
- onClick: toggleCollapse,
390
- "aria-label": currentCollapsed ? "\u5C55\u5F00\u4FA7\u680F" : "\u6536\u8D77\u4FA7\u680F",
391
- "aria-expanded": !currentCollapsed,
392
- children: currentCollapsed ? "\u2192" : "\u2190"
393
- }
394
- ) }),
395
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: "fc-sidebar__menu", role: "tree", children: items.map((item) => renderMenuItem(item)) })
365
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fc-sidebar__icon", children: item.icon }),
366
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fc-sidebar__label", children: item.label })
396
367
  ]
397
368
  }
398
369
  );
399
- }
370
+ });
371
+ SideBarItemView.displayName = "SideBarItemView";
372
+ var SideBar = (0, import_react2.memo)(({
373
+ items,
374
+ selectedKey,
375
+ collapsed,
376
+ width = 240,
377
+ collapsedWidth = 64,
378
+ onSelect,
379
+ onCollapse,
380
+ className = "",
381
+ style
382
+ }) => {
383
+ const handleClick = (0, import_react2.useCallback)(
384
+ (key) => onSelect(key),
385
+ [onSelect]
386
+ );
387
+ const toggleCollapse = (0, import_react2.useCallback)(
388
+ () => onCollapse(!collapsed),
389
+ [collapsed, onCollapse]
390
+ );
391
+ const rootClasses = [
392
+ "fc-sidebar",
393
+ collapsed && "fc-sidebar--collapsed",
394
+ className
395
+ ].filter(Boolean).join(" ");
396
+ const rootStyle = {
397
+ "--sidebar-width": `${collapsed ? collapsedWidth : width}px`,
398
+ "--sidebar-collapsed-width": `${collapsedWidth}px`,
399
+ ...style
400
+ };
401
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: rootClasses, style: rootStyle, children: [
402
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fc-sidebar__header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
403
+ "button",
404
+ {
405
+ className: "fc-sidebar__collapse-btn",
406
+ onClick: toggleCollapse,
407
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
408
+ "svg",
409
+ {
410
+ className: "fc-sidebar__collapse-icon",
411
+ width: "16",
412
+ height: "16",
413
+ viewBox: "0 0 16 16",
414
+ fill: "none",
415
+ xmlns: "http://www.w3.org/2000/svg",
416
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
417
+ "path",
418
+ {
419
+ d: collapsed ? "M6 3L11 8L6 13" : "M10 3L5 8L10 13",
420
+ stroke: "currentColor",
421
+ strokeWidth: "1.5",
422
+ strokeLinecap: "round",
423
+ strokeLinejoin: "round"
424
+ }
425
+ )
426
+ }
427
+ )
428
+ }
429
+ ) }),
430
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: "fc-sidebar__menu", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
431
+ SideBarItemView,
432
+ {
433
+ item,
434
+ isSelected: selectedKey === item.key,
435
+ onClick: handleClick
436
+ },
437
+ item.key
438
+ )) })
439
+ ] });
440
+ });
441
+ SideBar.displayName = "SideBar";
400
442
 
401
443
  // src/components/Input/Input.tsx
402
444
  var React4 = __toESM(require("react"), 1);
@@ -464,8 +506,8 @@ var Input = React4.forwardRef(({
464
506
  );
465
507
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: classNames, children: [
466
508
  addonBefore && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fc-input__addon fc-input__addon--before", children: addonBefore }),
467
- prefix && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fc-input__prefix", children: prefix }),
468
509
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "fc-input__wrapper", children: [
510
+ prefix && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "fc-input__prefix", children: prefix }),
469
511
  input,
470
512
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "fc-input__actions", children: [
471
513
  showClear && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -512,7 +554,16 @@ function Slider({
512
554
  disabled = false,
513
555
  marks,
514
556
  tooltip = false,
515
- className = ""
557
+ className = "",
558
+ style,
559
+ trackBackground,
560
+ fillBackground,
561
+ thumbBackground,
562
+ thumbBorderColor,
563
+ markDotColor,
564
+ markLabelColor,
565
+ tooltipBackground,
566
+ tooltipColor
516
567
  }) {
517
568
  const trackRef = React5.useRef(null);
518
569
  const draggingRef = React5.useRef(null);
@@ -521,6 +572,23 @@ function Slider({
521
572
  const [internalValue, setInternalValue] = React5.useState(initialValue);
522
573
  const isControlled = controlledValue !== void 0;
523
574
  const currentValue = isControlled ? controlledValue : internalValue;
575
+ const colorVars = {
576
+ "--slider-track-bg": trackBackground,
577
+ "--slider-fill-bg": fillBackground,
578
+ "--slider-thumb-bg": thumbBackground,
579
+ "--slider-thumb-border": thumbBorderColor,
580
+ "--slider-mark-dot-bg": markDotColor,
581
+ "--slider-mark-label-color": markLabelColor,
582
+ "--slider-tooltip-bg": tooltipBackground,
583
+ "--slider-tooltip-color": tooltipColor
584
+ };
585
+ const overrideStyle = {};
586
+ for (const [key, value] of Object.entries(colorVars)) {
587
+ if (value !== void 0) {
588
+ overrideStyle[key] = value;
589
+ }
590
+ }
591
+ const mergedStyle = { ...overrideStyle, ...style };
524
592
  const getPercent = (val) => Math.max(0, Math.min(100, (val - min) / (max - min) * 100));
525
593
  const getValueFromPercent = (percent) => {
526
594
  const raw = min + percent / 100 * (max - min);
@@ -574,7 +642,7 @@ function Slider({
574
642
  dragging !== null && "fc-slider--dragging",
575
643
  className
576
644
  ].filter(Boolean).join(" ");
577
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cls, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
645
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cls, style: mergedStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
578
646
  "div",
579
647
  {
580
648
  ref: trackRef,
@@ -636,10 +704,30 @@ function Select({
636
704
  multiple = false,
637
705
  disabled = false,
638
706
  className = "",
707
+ style,
639
708
  virtualScroll = false,
640
709
  virtualItemHeight = 32,
641
- maxHeight = 256
710
+ maxHeight = 256,
711
+ triggerBackground,
712
+ triggerBorderColor,
713
+ selectedColor,
714
+ selectedBackground,
715
+ hoverBackground
642
716
  }) {
717
+ const colorVars = {
718
+ "--select-trigger-bg": triggerBackground,
719
+ "--select-trigger-border": triggerBorderColor,
720
+ "--select-option-selected-color": selectedColor,
721
+ "--select-option-selected-bg": selectedBackground,
722
+ "--select-option-hover-bg": hoverBackground
723
+ };
724
+ const overrideStyle = {};
725
+ for (const [key, value] of Object.entries(colorVars)) {
726
+ if (value !== void 0) {
727
+ overrideStyle[key] = value;
728
+ }
729
+ }
730
+ const mergedStyle = { ...overrideStyle, ...style };
643
731
  const [isOpen, setIsOpen] = React6.useState(false);
644
732
  const [searchValue, setSearchValue] = React6.useState("");
645
733
  const [highlightedIndex, setHighlightedIndex] = React6.useState(0);
@@ -713,14 +801,14 @@ function Select({
713
801
  disabled && "fc-select--disabled",
714
802
  className
715
803
  ].filter(Boolean).join(" ");
716
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: containerRef, className: classNames, children: [
804
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: containerRef, className: classNames, style: mergedStyle, children: [
717
805
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
718
806
  "div",
719
807
  {
720
808
  className: "fc-select__trigger",
721
809
  onClick: () => !disabled && setIsOpen(!isOpen),
722
810
  children: [
723
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `fc-select__value ${!currentValue && "fc-select__value--placeholder"}`, children: displayLabel() }),
811
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `fc-select__value ${(currentValue === void 0 || currentValue === null || multiple && !currentValue.length) && "fc-select__value--placeholder"}`, children: displayLabel() }),
724
812
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "fc-select__arrow", children: "\u25BC" })
725
813
  ]
726
814
  }
@@ -787,7 +875,8 @@ function Select({
787
875
  }
788
876
  function highlightText(text, highlight) {
789
877
  if (!highlight) return text;
790
- const parts = text.split(new RegExp(`(${highlight})`, "gi"));
878
+ const escaped = highlight.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
879
+ const parts = text.split(new RegExp(`(${escaped})`, "gi"));
791
880
  return parts.map(
792
881
  (part, i) => part.toLowerCase() === highlight.toLowerCase() ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("mark", { className: "fc-select__highlight", children: part }, i) : part
793
882
  );
@@ -795,15 +884,15 @@ function Select({
795
884
  }
796
885
 
797
886
  // src/components/Tree/Tree.tsx
798
- var import_react3 = require("react");
887
+ var import_react4 = require("react");
799
888
  var import_core = require("@dnd-kit/core");
800
889
 
801
890
  // src/components/Tree/DeleteDialog.tsx
802
- var import_react2 = require("react");
891
+ var import_react3 = require("react");
803
892
  var import_jsx_runtime9 = require("react/jsx-runtime");
804
893
  function DeleteDialog({ node, onClose, onDelete }) {
805
- const [phase, setPhase] = (0, import_react2.useState)("choose");
806
- const [loading, setLoading] = (0, import_react2.useState)(false);
894
+ const [phase, setPhase] = (0, import_react3.useState)("choose");
895
+ const [loading, setLoading] = (0, import_react3.useState)(false);
807
896
  if (!node) return null;
808
897
  const reset = () => {
809
898
  setPhase("choose");
@@ -962,14 +1051,14 @@ function isDescendantOf(roots, ancestorKey, targetKey) {
962
1051
 
963
1052
  // src/components/Tree/Tree.tsx
964
1053
  var import_jsx_runtime10 = require("react/jsx-runtime");
965
- var TreeActionsCtx = (0, import_react3.createContext)(null);
966
- var TreeStateCtx = (0, import_react3.createContext)(null);
967
- var DndStateCtx = (0, import_react3.createContext)(null);
968
- var CollapsePanel = (0, import_react3.memo)(function CollapsePanel2({ open, children }) {
969
- const innerRef = (0, import_react3.useRef)(null);
970
- const [height, setHeight] = (0, import_react3.useState)(0);
971
- const [ready, setReady] = (0, import_react3.useState)(false);
972
- (0, import_react3.useEffect)(() => {
1054
+ var TreeActionsCtx = (0, import_react4.createContext)(null);
1055
+ var TreeStateCtx = (0, import_react4.createContext)(null);
1056
+ var DndStateCtx = (0, import_react4.createContext)(null);
1057
+ var CollapsePanel = (0, import_react4.memo)(function CollapsePanel2({ open, children }) {
1058
+ const innerRef = (0, import_react4.useRef)(null);
1059
+ const [height, setHeight] = (0, import_react4.useState)(0);
1060
+ const [ready, setReady] = (0, import_react4.useState)(false);
1061
+ (0, import_react4.useEffect)(() => {
973
1062
  const el = innerRef.current;
974
1063
  if (!el) return;
975
1064
  const ro = new ResizeObserver(() => setHeight(el.offsetHeight));
@@ -984,39 +1073,39 @@ var CollapsePanel = (0, import_react3.memo)(function CollapsePanel2({ open, chil
984
1073
  transition: ready ? "height 0.12s ease-out" : "none"
985
1074
  }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: innerRef, children }) });
986
1075
  });
987
- var DndSlot = (0, import_react3.memo)(function DndSlot2({
1076
+ var DndSlot = (0, import_react4.memo)(function DndSlot2({
988
1077
  nodeKey,
989
1078
  disabled,
990
1079
  children
991
1080
  }) {
992
- const dndState = (0, import_react3.useContext)(DndStateCtx);
1081
+ const dndState = (0, import_react4.useContext)(DndStateCtx);
993
1082
  const isDropTarget = dndState.dropTargetKey === nodeKey;
994
1083
  const dropPosition = isDropTarget ? dndState.dropPosition : null;
995
1084
  const isDragSource = dndState.dragKey === nodeKey;
996
1085
  const { attributes, listeners, setNodeRef: setDragRef, isDragging } = (0, import_core.useDraggable)({ id: nodeKey, disabled });
997
1086
  const { setNodeRef: setDropRef } = (0, import_core.useDroppable)({ id: nodeKey, disabled });
998
- const setRef = (0, import_react3.useCallback)((el) => {
1087
+ const setRef = (0, import_react4.useCallback)((el) => {
999
1088
  setDragRef(el);
1000
1089
  setDropRef(el);
1001
1090
  }, [setDragRef, setDropRef]);
1002
- const handleProps = (0, import_react3.useMemo)(
1091
+ const handleProps = (0, import_react4.useMemo)(
1003
1092
  () => ({ ...attributes, ...listeners }),
1004
1093
  [attributes, listeners]
1005
1094
  );
1006
1095
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: children({ setRef, handleProps, isDragging, isDragSource, dropPosition }) });
1007
1096
  });
1008
- var TreeNodeItem = (0, import_react3.memo)(function TreeNodeItem2({ node, level, hidden = false }) {
1009
- const actions = (0, import_react3.useContext)(TreeActionsCtx);
1010
- const state = (0, import_react3.useContext)(TreeStateCtx);
1097
+ var TreeNodeItem = (0, import_react4.memo)(function TreeNodeItem2({ node, level, hidden = false }) {
1098
+ const actions = (0, import_react4.useContext)(TreeActionsCtx);
1099
+ const state = (0, import_react4.useContext)(TreeStateCtx);
1011
1100
  const isExpanded = state.expandedKeys.has(node.key);
1012
1101
  const isEditing = state.editingKey === node.key;
1013
1102
  const hasChildren = node.children.length > 0;
1014
1103
  const indent = level * 20 + 12;
1015
- const [localEdit, setLocalEdit] = (0, import_react3.useState)("");
1016
- (0, import_react3.useEffect)(() => {
1104
+ const [localEdit, setLocalEdit] = (0, import_react4.useState)("");
1105
+ (0, import_react4.useEffect)(() => {
1017
1106
  if (isEditing) setLocalEdit(node.title);
1018
1107
  }, [isEditing, node.title]);
1019
- const handleEditKeyDown = (0, import_react3.useCallback)((e) => {
1108
+ const handleEditKeyDown = (0, import_react4.useCallback)((e) => {
1020
1109
  e.stopPropagation();
1021
1110
  if (e.key === "Enter") actions.commitEdit(node.key, localEdit).then();
1022
1111
  if (e.key === "Escape") actions.cancelEdit();
@@ -1139,18 +1228,18 @@ function Tree({
1139
1228
  scrollHeight = "400px",
1140
1229
  className = ""
1141
1230
  }) {
1142
- const [expandedKeys, setExpandedKeys] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
1143
- const [editingKey, setEditingKey] = (0, import_react3.useState)(null);
1144
- const [deleteTarget, setDeleteTarget] = (0, import_react3.useState)(null);
1145
- const [searchValue, setSearchValue] = (0, import_react3.useState)("");
1146
- const [dndState, setDndState] = (0, import_react3.useState)({
1231
+ const [expandedKeys, setExpandedKeys] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
1232
+ const [editingKey, setEditingKey] = (0, import_react4.useState)(null);
1233
+ const [deleteTarget, setDeleteTarget] = (0, import_react4.useState)(null);
1234
+ const [searchValue, setSearchValue] = (0, import_react4.useState)("");
1235
+ const [dndState, setDndState] = (0, import_react4.useState)({
1147
1236
  dropTargetKey: null,
1148
1237
  dropPosition: null,
1149
1238
  dragKey: null
1150
1239
  });
1151
- const dropRef = (0, import_react3.useRef)({ key: null, pos: null });
1152
- const pointerYRef = (0, import_react3.useRef)(0);
1153
- (0, import_react3.useEffect)(() => {
1240
+ const dropRef = (0, import_react4.useRef)({ key: null, pos: null });
1241
+ const pointerYRef = (0, import_react4.useRef)(0);
1242
+ (0, import_react4.useEffect)(() => {
1154
1243
  const handler = (e) => {
1155
1244
  pointerYRef.current = e.clientY;
1156
1245
  };
@@ -1160,39 +1249,39 @@ function Tree({
1160
1249
  const sensors = (0, import_core.useSensors)(
1161
1250
  (0, import_core.useSensor)(import_core.PointerSensor, { activationConstraint: { distance: 8 } })
1162
1251
  );
1163
- const toggleExpand = (0, import_react3.useCallback)((key) => {
1252
+ const toggleExpand = (0, import_react4.useCallback)((key) => {
1164
1253
  setExpandedKeys((prev) => {
1165
1254
  const next = new Set(prev);
1166
1255
  next.has(key) ? next.delete(key) : next.add(key);
1167
1256
  return next;
1168
1257
  });
1169
1258
  }, []);
1170
- const select = (0, import_react3.useCallback)((key) => onSelect?.(key), [onSelect]);
1171
- const startEdit = (0, import_react3.useCallback)((key) => setEditingKey(key), []);
1172
- const cancelEdit = (0, import_react3.useCallback)(() => setEditingKey(null), []);
1173
- const commitEdit = (0, import_react3.useCallback)(async (key, newTitle) => {
1259
+ const select = (0, import_react4.useCallback)((key) => onSelect?.(key), [onSelect]);
1260
+ const startEdit = (0, import_react4.useCallback)((key) => setEditingKey(key), []);
1261
+ const cancelEdit = (0, import_react4.useCallback)(() => setEditingKey(null), []);
1262
+ const commitEdit = (0, import_react4.useCallback)(async (key, newTitle) => {
1174
1263
  setEditingKey(null);
1175
1264
  const trimmed = newTitle.trim();
1176
1265
  if (trimmed && onRename) await onRename(key, trimmed);
1177
1266
  }, [onRename]);
1178
- const requestCreate = (0, import_react3.useCallback)(async (parentKey) => {
1267
+ const requestCreate = (0, import_react4.useCallback)(async (parentKey) => {
1179
1268
  if (!onCreate) return;
1180
1269
  const newKey = await onCreate(parentKey);
1181
1270
  if (parentKey) setExpandedKeys((prev) => /* @__PURE__ */ new Set([...prev, parentKey]));
1182
1271
  setEditingKey(newKey);
1183
1272
  }, [onCreate]);
1184
- const requestDelete = (0, import_react3.useCallback)((node) => {
1273
+ const requestDelete = (0, import_react4.useCallback)((node) => {
1185
1274
  setDeleteTarget(node);
1186
1275
  }, []);
1187
- const treeDataRef = (0, import_react3.useRef)(treeData);
1188
- const expandedRef = (0, import_react3.useRef)(expandedKeys);
1276
+ const treeDataRef = (0, import_react4.useRef)(treeData);
1277
+ const expandedRef = (0, import_react4.useRef)(expandedKeys);
1189
1278
  treeDataRef.current = treeData;
1190
1279
  expandedRef.current = expandedKeys;
1191
- const handleDragStart = (0, import_react3.useCallback)(({ active }) => {
1280
+ const handleDragStart = (0, import_react4.useCallback)(({ active }) => {
1192
1281
  dropRef.current = { key: null, pos: null };
1193
1282
  setDndState({ dropTargetKey: null, dropPosition: null, dragKey: active.id });
1194
1283
  }, []);
1195
- const handleDragMove = (0, import_react3.useCallback)(({ over, active }) => {
1284
+ const handleDragMove = (0, import_react4.useCallback)(({ over, active }) => {
1196
1285
  if (!over || over.id === active.id) {
1197
1286
  if (dropRef.current.key !== null) {
1198
1287
  dropRef.current = { key: null, pos: null };
@@ -1219,18 +1308,18 @@ function Tree({
1219
1308
  dropRef.current = { key: targetKey, pos: position };
1220
1309
  setDndState((prev) => ({ ...prev, dropTargetKey: targetKey, dropPosition: position }));
1221
1310
  }, []);
1222
- const handleDragEnd = (0, import_react3.useCallback)(({ active }) => {
1311
+ const handleDragEnd = (0, import_react4.useCallback)(({ active }) => {
1223
1312
  const { key: target, pos: position } = dropRef.current;
1224
1313
  dropRef.current = { key: null, pos: null };
1225
1314
  setDndState({ dropTargetKey: null, dropPosition: null, dragKey: null });
1226
1315
  if (!target || !position || active.id === target) return;
1227
1316
  onMove?.(active.id, target, position);
1228
1317
  }, [onMove]);
1229
- const handleDragCancel = (0, import_react3.useCallback)(() => {
1318
+ const handleDragCancel = (0, import_react4.useCallback)(() => {
1230
1319
  dropRef.current = { key: null, pos: null };
1231
1320
  setDndState({ dropTargetKey: null, dropPosition: null, dragKey: null });
1232
1321
  }, []);
1233
- const displayData = (0, import_react3.useMemo)(() => {
1322
+ const displayData = (0, import_react4.useMemo)(() => {
1234
1323
  if (!searchValue) return treeData;
1235
1324
  const kw = searchValue.toLowerCase();
1236
1325
  const filter = (nodes) => nodes.reduce((acc, node) => {
@@ -1242,7 +1331,7 @@ function Tree({
1242
1331
  }, []);
1243
1332
  return filter(treeData);
1244
1333
  }, [treeData, searchValue]);
1245
- const actionsValue = (0, import_react3.useMemo)(() => ({
1334
+ const actionsValue = (0, import_react4.useMemo)(() => ({
1246
1335
  toggleExpand,
1247
1336
  select,
1248
1337
  startEdit,
@@ -1251,7 +1340,7 @@ function Tree({
1251
1340
  requestCreate,
1252
1341
  requestDelete
1253
1342
  }), [toggleExpand, select, startEdit, commitEdit, cancelEdit, requestCreate, requestDelete]);
1254
- const stateValue = (0, import_react3.useMemo)(() => ({
1343
+ const stateValue = (0, import_react4.useMemo)(() => ({
1255
1344
  expandedKeys,
1256
1345
  selectedKey: selectedKey ?? null,
1257
1346
  editingKey
@@ -1309,10 +1398,10 @@ function Tree({
1309
1398
  }
1310
1399
 
1311
1400
  // src/components/Tree/OrphanDialog.tsx
1312
- var import_react4 = require("react");
1401
+ var import_react5 = require("react");
1313
1402
  var import_jsx_runtime11 = require("react/jsx-runtime");
1314
1403
  function OrphanDialog({ orphans, onResolve, onClose }) {
1315
- const [resolutions, setResolutions] = (0, import_react4.useState)(
1404
+ const [resolutions, setResolutions] = (0, import_react5.useState)(
1316
1405
  () => Object.fromEntries(orphans.map((o) => [o.key, "lift"]))
1317
1406
  );
1318
1407
  if (orphans.length === 0) return null;
@@ -1376,7 +1465,7 @@ function OrphanDialog({ orphans, onResolve, onClose }) {
1376
1465
  }
1377
1466
 
1378
1467
  // src/components/Avatar/Avatar.tsx
1379
- var import_react5 = require("react");
1468
+ var import_react6 = require("react");
1380
1469
  var import_jsx_runtime12 = require("react/jsx-runtime");
1381
1470
  var SIZE_MAP = {
1382
1471
  xs: 20,
@@ -1387,7 +1476,7 @@ var SIZE_MAP = {
1387
1476
  };
1388
1477
  var DEFAULT_ICON = "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z";
1389
1478
  var useAvatarStyles = (size, shape, bordered, onClick, loadState, src, children, colorVariant, className, color, customStyle) => {
1390
- const classes = (0, import_react5.useMemo)(() => {
1479
+ const classes = (0, import_react6.useMemo)(() => {
1391
1480
  const classNames = [
1392
1481
  "ui-avatar",
1393
1482
  `ui-avatar-${size}`,
@@ -1401,7 +1490,7 @@ var useAvatarStyles = (size, shape, bordered, onClick, loadState, src, children,
1401
1490
  ];
1402
1491
  return classNames.filter(Boolean).join(" ");
1403
1492
  }, [size, shape, bordered, onClick, loadState, src, children, colorVariant, className]);
1404
- const style = (0, import_react5.useMemo)(() => ({
1493
+ const style = (0, import_react6.useMemo)(() => ({
1405
1494
  width: SIZE_MAP[size],
1406
1495
  height: SIZE_MAP[size],
1407
1496
  fontSize: `${SIZE_MAP[size] * 0.4}px`,
@@ -1411,20 +1500,20 @@ var useAvatarStyles = (size, shape, bordered, onClick, loadState, src, children,
1411
1500
  return { classes, style };
1412
1501
  };
1413
1502
  var useImageLoader = (src, fallbackSrc, onImageLoad, onImageError, onStateChange) => {
1414
- const [loadState, setLoadState] = (0, import_react5.useState)("idle");
1415
- const [currentSrc, setCurrentSrc] = (0, import_react5.useState)(src);
1416
- (0, import_react5.useEffect)(() => {
1503
+ const [loadState, setLoadState] = (0, import_react6.useState)("idle");
1504
+ const [currentSrc, setCurrentSrc] = (0, import_react6.useState)(src);
1505
+ (0, import_react6.useEffect)(() => {
1417
1506
  setCurrentSrc(src);
1418
1507
  setLoadState(src ? "loading" : "idle");
1419
1508
  }, [src]);
1420
- (0, import_react5.useEffect)(() => {
1509
+ (0, import_react6.useEffect)(() => {
1421
1510
  onStateChange?.(loadState);
1422
1511
  }, [loadState, onStateChange]);
1423
- const handleLoad = (0, import_react5.useCallback)(() => {
1512
+ const handleLoad = (0, import_react6.useCallback)(() => {
1424
1513
  setLoadState("loaded");
1425
1514
  onImageLoad?.();
1426
1515
  }, [onImageLoad]);
1427
- const handleError = (0, import_react5.useCallback)((e) => {
1516
+ const handleError = (0, import_react6.useCallback)((e) => {
1428
1517
  if (fallbackSrc && currentSrc !== fallbackSrc) {
1429
1518
  setCurrentSrc(fallbackSrc);
1430
1519
  setLoadState("loading");
@@ -1441,7 +1530,7 @@ var useImageLoader = (src, fallbackSrc, onImageLoad, onImageError, onStateChange
1441
1530
  };
1442
1531
  };
1443
1532
  var useKeyboardInteraction = (onClick) => {
1444
- const handleKeyDown = (0, import_react5.useCallback)((e) => {
1533
+ const handleKeyDown = (0, import_react6.useCallback)((e) => {
1445
1534
  if (onClick && (e.key === "Enter" || e.key === " ")) {
1446
1535
  e.preventDefault();
1447
1536
  onClick(e);
@@ -1481,7 +1570,7 @@ var useAriaAttributes = (onClick, loadState, alt) => {
1481
1570
  "data-load-state": loadState
1482
1571
  };
1483
1572
  };
1484
- var Avatar = (0, import_react5.forwardRef)(
1573
+ var Avatar = (0, import_react6.forwardRef)(
1485
1574
  ({
1486
1575
  children,
1487
1576
  src,
@@ -1551,12 +1640,12 @@ var Avatar = (0, import_react5.forwardRef)(
1551
1640
  Avatar.displayName = "Avatar";
1552
1641
 
1553
1642
  // src/components/ListGroup/ListGroup.tsx
1554
- var import_react6 = require("react");
1643
+ var import_react7 = require("react");
1555
1644
  var import_jsx_runtime13 = require("react/jsx-runtime");
1556
1645
  var combineClassNames = (...classNames) => {
1557
1646
  return classNames.filter(Boolean).join(" ");
1558
1647
  };
1559
- var ListGroupItem = (0, import_react6.forwardRef)(
1648
+ var ListGroupItem = (0, import_react7.forwardRef)(
1560
1649
  ({
1561
1650
  active = false,
1562
1651
  disabled = false,
@@ -1565,11 +1654,11 @@ var ListGroupItem = (0, import_react6.forwardRef)(
1565
1654
  children,
1566
1655
  ...props
1567
1656
  }, ref) => {
1568
- const handleClick = (0, import_react6.useCallback)((e) => {
1657
+ const handleClick = (0, import_react7.useCallback)((e) => {
1569
1658
  if (disabled) return;
1570
1659
  onClick?.(e);
1571
1660
  }, [disabled, onClick]);
1572
- const classNames = (0, import_react6.useMemo)(() => {
1661
+ const classNames = (0, import_react7.useMemo)(() => {
1573
1662
  return combineClassNames(
1574
1663
  "fc-list-group-item",
1575
1664
  active && "fc-list-group-item--active",
@@ -1594,7 +1683,7 @@ var ListGroupItem = (0, import_react6.forwardRef)(
1594
1683
  }
1595
1684
  );
1596
1685
  ListGroupItem.displayName = "ListGroupItem";
1597
- var ListGroup = (0, import_react6.forwardRef)(
1686
+ var ListGroup = (0, import_react7.forwardRef)(
1598
1687
  ({
1599
1688
  bordered = true,
1600
1689
  flush = false,
@@ -1602,7 +1691,7 @@ var ListGroup = (0, import_react6.forwardRef)(
1602
1691
  children,
1603
1692
  ...props
1604
1693
  }, ref) => {
1605
- const classNames = (0, import_react6.useMemo)(() => {
1694
+ const classNames = (0, import_react7.useMemo)(() => {
1606
1695
  return combineClassNames(
1607
1696
  "fc-list-group",
1608
1697
  bordered && "fc-list-group--bordered",
@@ -1625,8 +1714,10 @@ var ListGroup = (0, import_react6.forwardRef)(
1625
1714
  ListGroup.displayName = "ListGroup";
1626
1715
 
1627
1716
  // src/components/VirtualList/VirtualList.tsx
1628
- var import_react7 = require("react");
1717
+ var import_react8 = require("react");
1629
1718
  var import_jsx_runtime14 = require("react/jsx-runtime");
1719
+ var VirtualItem = (0, import_react8.memo)(({ children, height }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fc-virtual-list__item", style: { height: `${height}px` }, children }));
1720
+ VirtualItem.displayName = "VirtualItem";
1630
1721
  function VirtualList({
1631
1722
  data,
1632
1723
  height,
@@ -1638,10 +1729,10 @@ function VirtualList({
1638
1729
  onScrollEnd,
1639
1730
  style
1640
1731
  }) {
1641
- const containerRef = (0, import_react7.useRef)(null);
1642
- const [scrollTop, setScrollTop] = (0, import_react7.useState)(0);
1732
+ const containerRef = (0, import_react8.useRef)(null);
1733
+ const [scrollTop, setScrollTop] = (0, import_react8.useState)(0);
1643
1734
  const totalHeight = data.length * itemHeight;
1644
- const handleScroll = (0, import_react7.useCallback)((e) => {
1735
+ const handleScroll = (0, import_react8.useCallback)((e) => {
1645
1736
  const newScrollTop = e.currentTarget.scrollTop;
1646
1737
  setScrollTop(newScrollTop);
1647
1738
  if (onScrollEnd) {
@@ -1652,7 +1743,7 @@ function VirtualList({
1652
1743
  }
1653
1744
  }
1654
1745
  }, [onScrollEnd]);
1655
- const visibleRange = (0, import_react7.useMemo)(() => {
1746
+ const visibleRange = (0, import_react8.useMemo)(() => {
1656
1747
  const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
1657
1748
  const endIndex = Math.min(
1658
1749
  data.length,
@@ -1660,15 +1751,10 @@ function VirtualList({
1660
1751
  );
1661
1752
  return { startIndex, endIndex };
1662
1753
  }, [scrollTop, height, itemHeight, data.length, overscan]);
1663
- const visibleData = (0, import_react7.useMemo)(() => {
1754
+ const visibleData = (0, import_react8.useMemo)(() => {
1664
1755
  return data.slice(visibleRange.startIndex, visibleRange.endIndex);
1665
1756
  }, [data, visibleRange]);
1666
1757
  const offsetY = visibleRange.startIndex * itemHeight;
1667
- (0, import_react7.useEffect)(() => {
1668
- if (!showScrollbar && containerRef.current) {
1669
- containerRef.current.style.scrollbarWidth = "none";
1670
- }
1671
- }, [showScrollbar]);
1672
1758
  const classNames = [
1673
1759
  "fc-virtual-list",
1674
1760
  !showScrollbar && "fc-virtual-list--hide-scrollbar",
@@ -1693,15 +1779,7 @@ function VirtualList({
1693
1779
  style: { transform: `translateY(${offsetY}px)` },
1694
1780
  children: visibleData.map((item, idx) => {
1695
1781
  const actualIndex = visibleRange.startIndex + idx;
1696
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1697
- "div",
1698
- {
1699
- className: "fc-virtual-list__item",
1700
- style: { height: `${itemHeight}px` },
1701
- children: renderItem(item, actualIndex)
1702
- },
1703
- actualIndex
1704
- );
1782
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VirtualItem, { height: itemHeight, children: renderItem(item, actualIndex) }, actualIndex);
1705
1783
  })
1706
1784
  }
1707
1785
  )
@@ -1712,9 +1790,9 @@ function VirtualList({
1712
1790
  }
1713
1791
 
1714
1792
  // src/components/Alert/AlertContext.tsx
1715
- var import_react8 = require("react");
1793
+ var import_react9 = require("react");
1716
1794
  var import_jsx_runtime15 = require("react/jsx-runtime");
1717
- var AlertContext = (0, import_react8.createContext)(null);
1795
+ var AlertContext = (0, import_react9.createContext)(null);
1718
1796
  var ICONS = {
1719
1797
  success: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1720
1798
  "svg",
@@ -1788,65 +1866,82 @@ var ICONS = {
1788
1866
  }
1789
1867
  )
1790
1868
  };
1791
- function AlertProvider({ children }) {
1792
- const [props, setProps] = (0, import_react8.useState)({
1869
+ function AlertProvider({ children, background, borderColor }) {
1870
+ const [alert, setAlert] = (0, import_react9.useState)({
1793
1871
  msg: "",
1794
1872
  type: "info",
1873
+ mode: "alert",
1795
1874
  visible: false,
1796
1875
  choice: () => {
1797
1876
  }
1798
1877
  });
1799
- const showAlert = (msg, type, confirm = false) => new Promise((resolve) => {
1800
- setProps({
1878
+ const showAlert = (msg, type, mode = "alert", duration) => new Promise((resolve) => {
1879
+ setAlert({
1801
1880
  msg,
1802
1881
  type,
1882
+ mode,
1803
1883
  visible: true,
1804
- confirm,
1884
+ duration,
1805
1885
  choice: (res) => {
1806
- setProps((p) => ({ ...p, visible: false }));
1886
+ setAlert((p) => ({ ...p, visible: false }));
1807
1887
  resolve(res);
1808
1888
  }
1809
1889
  });
1810
1890
  });
1891
+ (0, import_react9.useEffect)(() => {
1892
+ if (!alert.visible || !alert.duration) return;
1893
+ const timer = setTimeout(() => alert.choice("auto"), alert.duration);
1894
+ return () => clearTimeout(timer);
1895
+ }, [alert.visible, alert.duration]);
1896
+ const overrideStyle = {};
1897
+ if (background !== void 0) overrideStyle["--alert-bg"] = background;
1898
+ if (borderColor !== void 0) overrideStyle["--alert-border"] = borderColor;
1811
1899
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(AlertContext.Provider, { value: { showAlert }, children: [
1812
1900
  children,
1813
- props.visible && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fc-alert-overlay", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `fc-alert fc-alert--${props.type}`, children: [
1814
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fc-alert__header", children: [
1815
- ICONS[props.type],
1816
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fc-alert__title", children: "\u63D0\u793A" })
1817
- ] }),
1818
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RollingBox, { className: "fc-alert__msg", children: props.msg }),
1819
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fc-alert__footer", children: [
1820
- props.confirm && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1821
- Button,
1822
- {
1823
- variant: "secondary",
1824
- size: "sm",
1825
- onClick: () => props.choice("no"),
1826
- children: "\u53D6\u6D88"
1827
- }
1828
- ),
1829
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1830
- Button,
1831
- {
1832
- variant: "primary",
1833
- size: "sm",
1834
- onClick: () => props.choice("yes"),
1835
- children: "\u786E\u5B9A"
1836
- }
1837
- )
1838
- ] })
1839
- ] }) })
1901
+ alert.visible && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fc-alert-overlay", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1902
+ "div",
1903
+ {
1904
+ className: `fc-alert fc-alert--${alert.type} fc-alert--${alert.mode}`,
1905
+ style: overrideStyle,
1906
+ children: [
1907
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fc-alert__header", children: [
1908
+ ICONS[alert.type],
1909
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fc-alert__title", children: "\u63D0\u793A" })
1910
+ ] }),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RollingBox, { className: "fc-alert__msg", children: alert.msg }),
1912
+ alert.mode !== "toast" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fc-alert__footer", children: [
1913
+ alert.mode === "confirm" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1914
+ Button,
1915
+ {
1916
+ variant: "secondary",
1917
+ size: "sm",
1918
+ onClick: () => alert.choice("no"),
1919
+ children: "\u53D6\u6D88"
1920
+ }
1921
+ ),
1922
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1923
+ Button,
1924
+ {
1925
+ variant: "primary",
1926
+ size: "sm",
1927
+ onClick: () => alert.choice("yes"),
1928
+ children: "\u786E\u5B9A"
1929
+ }
1930
+ )
1931
+ ] })
1932
+ ]
1933
+ }
1934
+ ) })
1840
1935
  ] });
1841
1936
  }
1842
- var useAlert = () => (0, import_react8.useContext)(AlertContext);
1937
+ var useAlert = () => (0, import_react9.useContext)(AlertContext);
1843
1938
 
1844
1939
  // src/components/LazyLoad/LazyLoad.tsx
1845
- var import_react9 = require("react");
1940
+ var import_react10 = require("react");
1846
1941
  var import_jsx_runtime16 = require("react/jsx-runtime");
1847
1942
  function lazyLoad(importFn, options = {}) {
1848
1943
  const { fallback = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LazySpinner, {}), timeout = 1e4 } = options;
1849
- const LazyComponent = (0, import_react9.lazy)(() => {
1944
+ const LazyComponent = (0, import_react10.lazy)(() => {
1850
1945
  let timeoutId;
1851
1946
  const loadPromise = Promise.race([
1852
1947
  importFn(),
@@ -1856,7 +1951,7 @@ function lazyLoad(importFn, options = {}) {
1856
1951
  ]).finally(() => clearTimeout(timeoutId));
1857
1952
  return loadPromise;
1858
1953
  });
1859
- return (props) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react9.Suspense, { fallback, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LazyComponent, { ...props }) });
1954
+ return (props) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react10.Suspense, { fallback, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LazyComponent, { ...props }) });
1860
1955
  }
1861
1956
  function LazySpinner() {
1862
1957
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "fc-lazy-spinner", children: [
@@ -1928,344 +2023,779 @@ var Card = ({
1928
2023
  ] });
1929
2024
  };
1930
2025
 
1931
- // src/components/Tabs/Tabs.tsx
1932
- var import_react10 = require("react");
2026
+ // src/components/Bar/TabBar.tsx
2027
+ var import_react11 = require("react");
1933
2028
  var import_jsx_runtime18 = require("react/jsx-runtime");
1934
- var Tabs = ({
2029
+ var TabItemView = (0, import_react11.memo)(({
2030
+ item,
2031
+ isActive,
2032
+ closable,
2033
+ draggable,
2034
+ tabClassName,
2035
+ activeTabClassName,
2036
+ tabStyle,
2037
+ activeTabStyle,
2038
+ renderCloseIcon,
2039
+ onClick,
2040
+ onClose,
2041
+ onDragStart,
2042
+ onDragOver,
2043
+ onDrop,
2044
+ onDragEnd
2045
+ }) => {
2046
+ const showClose = item.closable !== void 0 ? item.closable : closable;
2047
+ const classes = [
2048
+ "fc-tab-bar__tab",
2049
+ isActive && "fc-tab-bar__tab--active",
2050
+ item.disabled && "fc-tab-bar__tab--disabled",
2051
+ draggable && !item.disabled && "fc-tab-bar__tab--draggable",
2052
+ tabClassName,
2053
+ isActive && activeTabClassName
2054
+ ].filter(Boolean).join(" ");
2055
+ const mergedStyle = {
2056
+ ...tabStyle,
2057
+ ...isActive ? activeTabStyle : void 0
2058
+ };
2059
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2060
+ "div",
2061
+ {
2062
+ className: classes,
2063
+ style: mergedStyle,
2064
+ onClick: () => !item.disabled && onClick(item.key),
2065
+ draggable: draggable && !item.disabled,
2066
+ onDragStart: (e) => onDragStart(e, item.key),
2067
+ onDragOver,
2068
+ onDrop: (e) => onDrop(e, item.key),
2069
+ onDragEnd,
2070
+ role: "tab",
2071
+ "aria-selected": isActive,
2072
+ "aria-disabled": item.disabled,
2073
+ tabIndex: item.disabled ? -1 : 0,
2074
+ children: [
2075
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "fc-tab-bar__tab-label", children: item.label }),
2076
+ showClose && !item.disabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2077
+ "span",
2078
+ {
2079
+ className: "fc-tab-bar__tab-close",
2080
+ onClick: (e) => onClose(e, item.key),
2081
+ role: "button",
2082
+ "aria-label": `\u5173\u95ED ${typeof item.label === "string" ? item.label : ""}`,
2083
+ children: renderCloseIcon ? renderCloseIcon(item.key) : "\xD7"
2084
+ }
2085
+ )
2086
+ ]
2087
+ }
2088
+ );
2089
+ });
2090
+ TabItemView.displayName = "TabItemView";
2091
+ var TabBar = (0, import_react11.memo)(({
1935
2092
  items,
1936
- activeKey: controlledActiveKey,
1937
- defaultActiveKey,
2093
+ activeKey,
2094
+ variant = "attached",
1938
2095
  radius = "md",
2096
+ tabRadius,
1939
2097
  closable = false,
1940
2098
  addable = false,
2099
+ draggable = false,
1941
2100
  onChange,
1942
2101
  onClose,
1943
2102
  onAdd,
2103
+ onReorder,
2104
+ tabClassName,
2105
+ activeTabClassName,
2106
+ tabStyle,
2107
+ activeTabStyle,
2108
+ renderCloseIcon,
2109
+ renderAddButton,
1944
2110
  className = "",
1945
- style
2111
+ style,
2112
+ background,
2113
+ tabColor,
2114
+ tabHoverColor,
2115
+ tabHoverBackground,
2116
+ tabActiveColor,
2117
+ tabActiveBackground,
2118
+ activeIndicatorColor
1946
2119
  }) => {
1947
- const [internalActiveKey, setInternalActiveKey] = (0, import_react10.useState)(
1948
- defaultActiveKey || items[0]?.key || ""
1949
- );
1950
- const activeKey = controlledActiveKey !== void 0 ? controlledActiveKey : internalActiveKey;
1951
- const handleTabClick = (key, disabled) => {
1952
- if (disabled) return;
1953
- if (controlledActiveKey === void 0) {
1954
- setInternalActiveKey(key);
1955
- }
1956
- onChange?.(key);
2120
+ const colorVars = {
2121
+ "--tab-bar-bg": background,
2122
+ "--tab-color": tabColor,
2123
+ "--tab-hover-color": tabHoverColor,
2124
+ "--tab-hover-bg": tabHoverBackground,
2125
+ "--tab-active-color": tabActiveColor,
2126
+ "--tab-active-bg": tabActiveBackground,
2127
+ "--tab-active-indicator": activeIndicatorColor
1957
2128
  };
1958
- const handleClose = (e, key) => {
1959
- e.stopPropagation();
1960
- onClose?.(key);
1961
- if (key === activeKey) {
1962
- const currentIndex = items.findIndex((item) => item.key === key);
1963
- const nextItem = items[currentIndex + 1] || items[currentIndex - 1];
1964
- if (nextItem && !nextItem.disabled) {
1965
- handleTabClick(nextItem.key);
1966
- }
2129
+ const overrideStyle = {};
2130
+ for (const [key, value] of Object.entries(colorVars)) {
2131
+ if (value !== void 0) {
2132
+ overrideStyle[key] = value;
1967
2133
  }
1968
- };
1969
- const classes = [
1970
- "fc-tabs",
1971
- `fc-tabs--radius-${radius}`,
2134
+ }
2135
+ const mergedStyle = { ...overrideStyle, ...style };
2136
+ const dragKeyRef = (0, import_react11.useRef)(null);
2137
+ const handleClick = (0, import_react11.useCallback)(
2138
+ (key) => onChange(key),
2139
+ [onChange]
2140
+ );
2141
+ const handleClose = (0, import_react11.useCallback)(
2142
+ (e, key) => {
2143
+ e.stopPropagation();
2144
+ onClose?.(key);
2145
+ },
2146
+ [onClose]
2147
+ );
2148
+ const handleDragStart = (0, import_react11.useCallback)(
2149
+ (e, key) => {
2150
+ dragKeyRef.current = key;
2151
+ e.dataTransfer.effectAllowed = "move";
2152
+ const target = e.currentTarget;
2153
+ requestAnimationFrame(() => target.classList.add("fc-tab-bar__tab--dragging"));
2154
+ },
2155
+ []
2156
+ );
2157
+ const handleDragOver = (0, import_react11.useCallback)((e) => {
2158
+ e.preventDefault();
2159
+ e.dataTransfer.dropEffect = "move";
2160
+ }, []);
2161
+ const handleDrop = (0, import_react11.useCallback)(
2162
+ (e, targetKey) => {
2163
+ e.preventDefault();
2164
+ const dragKey = dragKeyRef.current;
2165
+ if (!dragKey || dragKey === targetKey || !onReorder) return;
2166
+ const fromIndex = items.findIndex((i) => i.key === dragKey);
2167
+ const toIndex = items.findIndex((i) => i.key === targetKey);
2168
+ if (fromIndex === -1 || toIndex === -1) return;
2169
+ const reordered = [...items];
2170
+ const [moved] = reordered.splice(fromIndex, 1);
2171
+ reordered.splice(toIndex, 0, moved);
2172
+ onReorder(reordered);
2173
+ },
2174
+ [items, onReorder]
2175
+ );
2176
+ const handleDragEnd = (0, import_react11.useCallback)((e) => {
2177
+ dragKeyRef.current = null;
2178
+ e.currentTarget.classList.remove("fc-tab-bar__tab--dragging");
2179
+ }, []);
2180
+ const rootClasses = [
2181
+ "fc-tab-bar",
2182
+ `fc-tab-bar--${variant}`,
2183
+ `fc-tab-bar--radius-${radius}`,
2184
+ tabRadius && `fc-tab-bar--tab-radius-${tabRadius}`,
1972
2185
  className
1973
2186
  ].filter(Boolean).join(" ");
1974
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: classes, style, children: [
1975
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fc-tabs__nav", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fc-tabs__nav-wrap", children: [
1976
- items.map((item) => {
1977
- const isActive = activeKey === item.key;
1978
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1979
- "div",
1980
- {
1981
- className: `fc-tabs__tab ${isActive ? "fc-tabs__tab--active" : ""} ${item.disabled ? "fc-tabs__tab--disabled" : ""}`,
1982
- onClick: () => handleTabClick(item.key, item.disabled),
1983
- children: [
1984
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "fc-tabs__tab-label", children: item.label }),
1985
- closable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1986
- "span",
1987
- {
1988
- className: "fc-tabs__tab-close",
1989
- onClick: (e) => handleClose(e, item.key),
1990
- children: "\xD7"
1991
- }
1992
- )
1993
- ]
1994
- },
1995
- item.key
1996
- );
1997
- }),
1998
- addable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fc-tabs__add-btn", onClick: onAdd, children: "+" })
1999
- ] }) }),
2000
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fc-tabs__content", children: items.find((item) => item.key === activeKey)?.content })
2001
- ] });
2002
- };
2187
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: rootClasses, style: mergedStyle, role: "tablist", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fc-tab-bar__nav", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fc-tab-bar__nav-wrap", children: [
2188
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2189
+ TabItemView,
2190
+ {
2191
+ item,
2192
+ isActive: activeKey === item.key,
2193
+ closable,
2194
+ draggable,
2195
+ tabClassName,
2196
+ activeTabClassName,
2197
+ tabStyle,
2198
+ activeTabStyle,
2199
+ renderCloseIcon,
2200
+ onClick: handleClick,
2201
+ onClose: handleClose,
2202
+ onDragStart: handleDragStart,
2203
+ onDragOver: handleDragOver,
2204
+ onDrop: handleDrop,
2205
+ onDragEnd: handleDragEnd
2206
+ },
2207
+ item.key
2208
+ )),
2209
+ addable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2210
+ "div",
2211
+ {
2212
+ className: "fc-tab-bar__add-btn",
2213
+ onClick: onAdd,
2214
+ role: "button",
2215
+ "aria-label": "\u6DFB\u52A0\u6807\u7B7E",
2216
+ children: renderAddButton ? renderAddButton() : "+"
2217
+ }
2218
+ )
2219
+ ] }) }) });
2220
+ });
2221
+ TabBar.displayName = "TabBar";
2003
2222
 
2004
- // src/components/Chat/Chat.tsx
2005
- var import_react11 = require("react");
2223
+ // src/components/Tag/TagItem.tsx
2224
+ var import_react12 = require("react");
2006
2225
  var import_jsx_runtime19 = require("react/jsx-runtime");
2007
- var Chat = ({
2008
- messages = [],
2009
- onSendMessage,
2010
- placeholder = "\u8F93\u5165\u6D88\u606F...",
2011
- title = "AI \u52A9\u624B",
2012
- height = "600px",
2013
- showHeader = true,
2014
- showFooter = true,
2015
- loading = false,
2016
- disabled = false,
2017
- theme: propTheme,
2018
- userName = "\u6211",
2019
- assistantName = "AI\u52A9\u624B",
2020
- onTyping,
2021
- maxInputLength = 2e3,
2022
- autoFocus = true,
2023
- enableCopy = true
2024
- }) => {
2025
- const [inputValue, setInputValue] = (0, import_react11.useState)("");
2026
- const [isTyping, setIsTyping] = (0, import_react11.useState)(false);
2027
- const [isSending, setIsSending] = (0, import_react11.useState)(false);
2028
- const [currentTheme, setCurrentTheme] = (0, import_react11.useState)("light");
2029
- const [copiedMessageId, setCopiedMessageId] = (0, import_react11.useState)(null);
2030
- const [copyError, setCopyError] = (0, import_react11.useState)(null);
2031
- const messagesEndRef = (0, import_react11.useRef)(null);
2032
- const inputRef = (0, import_react11.useRef)(null);
2033
- (0, import_react11.useEffect)(() => {
2034
- if (propTheme) {
2035
- setCurrentTheme(propTheme);
2226
+ function TagItem({
2227
+ schema,
2228
+ value,
2229
+ onChange,
2230
+ mode = "show",
2231
+ background,
2232
+ color,
2233
+ borderColor
2234
+ }) {
2235
+ const [editing, setEditing] = (0, import_react12.useState)(false);
2236
+ const [draft, setDraft] = (0, import_react12.useState)(() => value !== void 0 ? String(value) : "");
2237
+ const inputRef = (0, import_react12.useRef)(null);
2238
+ (0, import_react12.useEffect)(() => {
2239
+ if (!editing) setDraft(value !== void 0 ? String(value) : "");
2240
+ }, [value, editing]);
2241
+ const colorVars = {
2242
+ "--tag-bg": background,
2243
+ "--tag-color": color,
2244
+ "--tag-border": borderColor
2245
+ };
2246
+ const overrideStyle = {};
2247
+ for (const [k, v] of Object.entries(colorVars)) {
2248
+ if (v !== void 0) overrideStyle[k] = v;
2249
+ }
2250
+ if (schema.type === "boolean") {
2251
+ const boolVal = value === true || value === "true";
2252
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2253
+ "span",
2254
+ {
2255
+ className: "fc-tag-item fc-tag-item--boolean",
2256
+ style: overrideStyle,
2257
+ onClick: () => onChange?.(!boolVal),
2258
+ title: "\u70B9\u51FB\u5207\u6362",
2259
+ children: [
2260
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__name", children: schema.name }),
2261
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__sep", children: "\xB7" }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: boolVal ? "fc-tag-item__bool-true" : "fc-tag-item__bool-false", children: boolVal ? "\u2713" : "\u2717" })
2263
+ ]
2264
+ }
2265
+ );
2266
+ }
2267
+ const commit = () => {
2268
+ if (schema.type === "number") {
2269
+ const n = parseFloat(draft);
2270
+ if (!isNaN(n)) {
2271
+ const clamped = schema.range_min != null && n < schema.range_min ? schema.range_min : schema.range_max != null && n > schema.range_max ? schema.range_max : n;
2272
+ onChange?.(clamped);
2273
+ }
2036
2274
  } else {
2037
- const checkTheme = () => {
2038
- const dataTheme = document.documentElement.getAttribute("data-theme");
2039
- if (dataTheme === "dark") {
2040
- setCurrentTheme("dark");
2041
- } else if (dataTheme === "light") {
2042
- setCurrentTheme("light");
2043
- } else {
2044
- const hasDarkClass = document.documentElement.classList.contains("dark") || document.body.classList.contains("dark") || document.documentElement.classList.contains("theme-dark") || document.body.classList.contains("theme-dark");
2045
- setCurrentTheme(hasDarkClass ? "dark" : "light");
2046
- }
2047
- };
2048
- checkTheme();
2049
- const observer = new MutationObserver(checkTheme);
2050
- observer.observe(document.documentElement, {
2051
- attributes: true,
2052
- attributeFilter: ["data-theme", "class"]
2053
- });
2054
- observer.observe(document.body, {
2055
- attributes: true,
2056
- attributeFilter: ["class"]
2057
- });
2058
- return () => observer.disconnect();
2275
+ onChange?.(draft);
2059
2276
  }
2060
- }, [propTheme]);
2061
- (0, import_react11.useEffect)(() => {
2062
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
2063
- }, [messages, loading]);
2064
- (0, import_react11.useEffect)(() => {
2065
- if (autoFocus && !disabled && inputRef.current) {
2066
- inputRef.current.focus();
2067
- }
2068
- }, [autoFocus, disabled]);
2069
- (0, import_react11.useEffect)(() => {
2070
- if (copyError) {
2071
- const timer = setTimeout(() => {
2072
- setCopyError(null);
2073
- }, 2e3);
2074
- return () => clearTimeout(timer);
2277
+ if (mode === "show") setEditing(false);
2278
+ };
2279
+ const cancel = () => {
2280
+ setDraft(value !== void 0 ? String(value) : "");
2281
+ if (mode === "show") setEditing(false);
2282
+ };
2283
+ const isEditing = mode === "edit" || editing;
2284
+ if (isEditing) {
2285
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "fc-tag-item fc-tag-item--editing", style: overrideStyle, children: [
2286
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__name", children: schema.name }),
2287
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__sep", children: "\xB7" }),
2288
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2289
+ "input",
2290
+ {
2291
+ ref: inputRef,
2292
+ className: "fc-tag-item__input",
2293
+ type: schema.type === "number" ? "number" : "text",
2294
+ value: draft,
2295
+ min: schema.range_min ?? void 0,
2296
+ max: schema.range_max ?? void 0,
2297
+ autoFocus: true,
2298
+ onChange: (e) => setDraft(e.target.value),
2299
+ onBlur: commit,
2300
+ onKeyDown: (e) => {
2301
+ if (e.key === "Enter") {
2302
+ e.preventDefault();
2303
+ commit();
2304
+ }
2305
+ if (e.key === "Escape") {
2306
+ e.preventDefault();
2307
+ cancel();
2308
+ }
2309
+ }
2310
+ }
2311
+ )
2312
+ ] });
2313
+ }
2314
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2315
+ "span",
2316
+ {
2317
+ className: "fc-tag-item fc-tag-item--show",
2318
+ style: overrideStyle,
2319
+ onDoubleClick: () => {
2320
+ setDraft(value !== void 0 ? String(value) : "");
2321
+ setEditing(true);
2322
+ setTimeout(() => inputRef.current?.select(), 0);
2323
+ },
2324
+ title: "\u53CC\u51FB\u7F16\u8F91",
2325
+ children: [
2326
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__name", children: schema.name }),
2327
+ value !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2328
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__sep", children: "\xB7" }),
2329
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fc-tag-item__value", children: String(value) })
2330
+ ] })
2331
+ ]
2075
2332
  }
2076
- }, [copyError]);
2077
- const handleCopyMessage = (0, import_react11.useCallback)(async (messageId, content) => {
2078
- if (!navigator.clipboard) {
2079
- setCopyError("\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u590D\u5236\u529F\u80FD");
2080
- return;
2333
+ );
2334
+ }
2335
+
2336
+ // src/components/MarkdownEditor/MarkdownEditor.tsx
2337
+ var import_react_md_editor = __toESM(require("@uiw/react-md-editor"), 1);
2338
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2339
+ var TOOLBAR_COMMANDS = [
2340
+ import_react_md_editor.commands.bold,
2341
+ import_react_md_editor.commands.italic,
2342
+ import_react_md_editor.commands.strikethrough,
2343
+ import_react_md_editor.commands.divider,
2344
+ import_react_md_editor.commands.title1,
2345
+ import_react_md_editor.commands.title2,
2346
+ import_react_md_editor.commands.title3,
2347
+ import_react_md_editor.commands.divider,
2348
+ import_react_md_editor.commands.quote,
2349
+ import_react_md_editor.commands.code,
2350
+ import_react_md_editor.commands.codeBlock,
2351
+ import_react_md_editor.commands.divider,
2352
+ import_react_md_editor.commands.link,
2353
+ import_react_md_editor.commands.unorderedListCommand,
2354
+ import_react_md_editor.commands.orderedListCommand,
2355
+ import_react_md_editor.commands.hr
2356
+ ];
2357
+ function MarkdownEditor({
2358
+ value,
2359
+ onChange,
2360
+ onAiComplete,
2361
+ minHeight = 200,
2362
+ placeholder = "\u5728\u6B64\u8F93\u5165\u5185\u5BB9...",
2363
+ background,
2364
+ toolbarBackground,
2365
+ borderColor
2366
+ }) {
2367
+ const { resolvedTheme } = useTheme();
2368
+ const colorVars = {
2369
+ "--md-bg": background,
2370
+ "--md-toolbar-bg": toolbarBackground,
2371
+ "--md-border": borderColor
2372
+ };
2373
+ const overrideStyle = {};
2374
+ for (const [k, v] of Object.entries(colorVars)) {
2375
+ if (v !== void 0) overrideStyle[k] = v;
2376
+ }
2377
+ const aiCommand = {
2378
+ name: "ai-complete",
2379
+ keyCommand: "ai-complete",
2380
+ buttonProps: { "aria-label": "AI \u8865\u5168", className: "fc-md-ai-btn" },
2381
+ icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "AI \u8865\u5168" }),
2382
+ execute: () => onAiComplete?.()
2383
+ };
2384
+ const extraCommands = onAiComplete ? [import_react_md_editor.commands.divider, aiCommand, import_react_md_editor.commands.fullscreen] : [import_react_md_editor.commands.fullscreen];
2385
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2386
+ "div",
2387
+ {
2388
+ className: "fc-md-wrap",
2389
+ style: overrideStyle,
2390
+ "data-color-mode": resolvedTheme,
2391
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2392
+ import_react_md_editor.default,
2393
+ {
2394
+ value,
2395
+ onChange: (v) => onChange(v ?? ""),
2396
+ commands: TOOLBAR_COMMANDS,
2397
+ extraCommands,
2398
+ height: minHeight,
2399
+ preview: "edit",
2400
+ visibleDragbar: false,
2401
+ textareaProps: { placeholder }
2402
+ }
2403
+ )
2081
2404
  }
2405
+ );
2406
+ }
2407
+
2408
+ // src/components/ContextMenu/ContextMenuContext.tsx
2409
+ var import_react13 = require("react");
2410
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2411
+ var ContextMenuContext = (0, import_react13.createContext)(null);
2412
+ function ContextMenuProvider({
2413
+ children,
2414
+ background,
2415
+ borderColor,
2416
+ hoverBackground
2417
+ }) {
2418
+ const [menu, setMenu] = (0, import_react13.useState)({
2419
+ visible: false,
2420
+ x: 0,
2421
+ y: 0,
2422
+ items: []
2423
+ });
2424
+ const menuRef = (0, import_react13.useRef)(null);
2425
+ const showContextMenu = (e, items) => {
2426
+ e.preventDefault();
2427
+ e.stopPropagation();
2428
+ setMenu({ visible: true, x: e.clientX, y: e.clientY, items });
2429
+ };
2430
+ const hide = () => setMenu((s) => ({ ...s, visible: false }));
2431
+ (0, import_react13.useEffect)(() => {
2432
+ if (!menu.visible) return;
2433
+ const onPointerDown = (e) => {
2434
+ if (menuRef.current && !menuRef.current.contains(e.target)) hide();
2435
+ };
2436
+ const onKeyDown = (e) => {
2437
+ if (e.key === "Escape") hide();
2438
+ };
2439
+ window.addEventListener("pointerdown", onPointerDown);
2440
+ window.addEventListener("keydown", onKeyDown);
2441
+ return () => {
2442
+ window.removeEventListener("pointerdown", onPointerDown);
2443
+ window.removeEventListener("keydown", onKeyDown);
2444
+ };
2445
+ }, [menu.visible]);
2446
+ const getPosition = () => {
2447
+ const W = window.innerWidth;
2448
+ const H = window.innerHeight;
2449
+ const menuW = 180;
2450
+ const menuH = menu.items.length * 32 + 12;
2451
+ return {
2452
+ left: menu.x + menuW > W ? menu.x - menuW : menu.x,
2453
+ top: menu.y + menuH > H ? menu.y - menuH : menu.y
2454
+ };
2455
+ };
2456
+ const colorVars = {
2457
+ "--ctx-bg": background,
2458
+ "--ctx-border": borderColor,
2459
+ "--ctx-item-hover-bg": hoverBackground
2460
+ };
2461
+ const overrideStyle = { ...getPosition() };
2462
+ for (const [k, v] of Object.entries(colorVars)) {
2463
+ if (v !== void 0) overrideStyle[k] = v;
2464
+ }
2465
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(ContextMenuContext.Provider, { value: { showContextMenu }, children: [
2466
+ children,
2467
+ menu.visible && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2468
+ "ul",
2469
+ {
2470
+ ref: menuRef,
2471
+ className: "fc-context-menu",
2472
+ style: overrideStyle,
2473
+ children: menu.items.map((item, i) => {
2474
+ if ("type" in item && item.type === "divider") {
2475
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { className: "fc-context-menu__divider" }, i);
2476
+ }
2477
+ const action = item;
2478
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2479
+ "li",
2480
+ {
2481
+ className: [
2482
+ "fc-context-menu__item",
2483
+ action.danger ? "fc-context-menu__item--danger" : "",
2484
+ action.disabled ? "fc-context-menu__item--disabled" : ""
2485
+ ].filter(Boolean).join(" "),
2486
+ onPointerDown: (e) => e.stopPropagation(),
2487
+ onClick: () => {
2488
+ if (action.disabled) return;
2489
+ action.onClick();
2490
+ hide();
2491
+ },
2492
+ children: [
2493
+ action.icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fc-context-menu__icon", children: action.icon }),
2494
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "fc-context-menu__label", children: action.label })
2495
+ ]
2496
+ },
2497
+ i
2498
+ );
2499
+ })
2500
+ }
2501
+ )
2502
+ ] });
2503
+ }
2504
+ var useContextMenu = () => (0, import_react13.useContext)(ContextMenuContext);
2505
+
2506
+ // src/components/Chat/Chat.tsx
2507
+ var import_react15 = require("react");
2508
+
2509
+ // src/components/SmartMessage/SmartMessage.tsx
2510
+ var import_react14 = require("react");
2511
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2512
+ var SmartMessage = (0, import_react14.memo)(({
2513
+ id,
2514
+ content,
2515
+ role,
2516
+ timestamp,
2517
+ status,
2518
+ toolName,
2519
+ toolResult,
2520
+ onCopy,
2521
+ className = "",
2522
+ style = {}
2523
+ }) => {
2524
+ const [copied, setCopied] = (0, import_react14.useState)(false);
2525
+ const formattedTime = timestamp ? new Date(timestamp).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }) : "";
2526
+ const handleCopy = async () => {
2082
2527
  try {
2083
- await navigator.clipboard.writeText(content);
2084
- setCopiedMessageId(messageId);
2085
- setTimeout(() => {
2086
- setCopiedMessageId(null);
2087
- }, 2e3);
2528
+ let copyContent = content;
2529
+ if (role === "tool" && toolResult) {
2530
+ copyContent = `\u5DE5\u5177: ${toolName || "\u5DE5\u5177\u8C03\u7528"}
2531
+ \u7ED3\u679C: ${JSON.stringify(toolResult, null, 2)}`;
2532
+ }
2533
+ await navigator.clipboard.writeText(copyContent);
2534
+ setCopied(true);
2535
+ onCopy?.(content, role);
2536
+ setTimeout(() => setCopied(false), 2e3);
2088
2537
  } catch (err) {
2089
2538
  console.error("\u590D\u5236\u5931\u8D25:", err);
2090
- if (err instanceof Error) {
2091
- if (err.name === "NotAllowedError") {
2092
- setCopyError("\u9700\u8981\u526A\u8D34\u677F\u6743\u9650\uFF0C\u8BF7\u5141\u8BB8\u540E\u91CD\u8BD5");
2093
- } else if (err.name === "SecurityError") {
2094
- setCopyError("\u51FA\u4E8E\u5B89\u5168\u539F\u56E0\uFF0C\u65E0\u6CD5\u590D\u5236\u5185\u5BB9");
2095
- } else {
2096
- setCopyError("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
2097
- }
2098
- } else {
2099
- setCopyError("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
2100
- }
2101
- setTimeout(() => {
2102
- setCopyError(null);
2103
- }, 3e3);
2104
- }
2105
- }, []);
2106
- const handleSend = (0, import_react11.useCallback)(() => {
2107
- const trimmedMessage = inputValue.trim();
2108
- if (!trimmedMessage || disabled || loading || isSending) return;
2109
- if (trimmedMessage.length > maxInputLength) {
2110
- console.warn(`\u6D88\u606F\u8D85\u8FC7\u6700\u5927\u957F\u5EA6\u9650\u5236: ${maxInputLength}`);
2111
- return;
2112
2539
  }
2113
- setIsSending(true);
2114
- const sendPromise = onSendMessage?.(trimmedMessage);
2115
- if (sendPromise) {
2116
- void sendPromise.then(() => {
2117
- setInputValue("");
2118
- if (inputRef.current) {
2119
- inputRef.current.style.height = "auto";
2120
- }
2121
- if (isTyping) {
2122
- setIsTyping(false);
2123
- onTyping?.(false);
2540
+ };
2541
+ const shouldShowCopyButton = () => {
2542
+ return role === "user" || role === "assistant";
2543
+ };
2544
+ const getContainerClassName = () => {
2545
+ const baseClass = "smart-message";
2546
+ const roleClass = `smart-message-${role}`;
2547
+ const statusClass = status ? `smart-message-${status}` : "";
2548
+ return `${baseClass} ${roleClass} ${statusClass} ${className}`.trim();
2549
+ };
2550
+ const getContentClassName = () => {
2551
+ const baseClass = "smart-message-content";
2552
+ const roleContentClass = `smart-message-content-${role}`;
2553
+ return `${baseClass} ${roleContentClass}`;
2554
+ };
2555
+ const renderSystemMessage = () => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "system-message-wrapper", children: [
2556
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "system-message-icon", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
2557
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }),
2558
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 8V12M12 16H12.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2559
+ ] }) }),
2560
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "system-message-text", children: content }),
2561
+ formattedTime && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "system-message-time", children: formattedTime })
2562
+ ] });
2563
+ const renderToolMessage = () => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tool-message-wrapper", children: [
2564
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tool-message-header", children: [
2565
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "tool-message-icon", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
2566
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M14.7 6.3L19 2L22 5L17.7 9.3L14.7 6.3Z", stroke: "currentColor", strokeWidth: "2" }),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M9.3 17.7L5 22L2 19L6.3 14.7L9.3 17.7Z", stroke: "currentColor", strokeWidth: "2" }),
2568
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 12L14.7 9.3M12 12L9.3 14.7M12 12L8 8M12 12L16 16", stroke: "currentColor", strokeWidth: "2" })
2569
+ ] }) }),
2570
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "tool-message-name", children: toolName || "\u5DE5\u5177\u8C03\u7528" })
2571
+ ] }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tool-message-content", children: [
2573
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tool-message-params", children: [
2574
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { children: "\u53C2\u6570:" }),
2575
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("pre", { children: content })
2576
+ ] }),
2577
+ toolResult && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tool-message-result", children: [
2578
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { children: "\u7ED3\u679C:" }),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("pre", { children: typeof toolResult === "object" ? JSON.stringify(toolResult, null, 2) : toolResult })
2580
+ ] })
2581
+ ] }),
2582
+ formattedTime && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "tool-message-time", children: formattedTime })
2583
+ ] });
2584
+ const renderUserAssistantMessage = () => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2585
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "message-header", children: [
2586
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "message-sender", children: role === "user" ? "\u6211" : "AI\u52A9\u624B" }),
2587
+ formattedTime && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "message-time", children: formattedTime })
2588
+ ] }),
2589
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: getContentClassName(), children: [
2590
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "message-text", children: content }),
2591
+ shouldShowCopyButton() && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2592
+ "button",
2593
+ {
2594
+ className: `copy-btn ${copied ? "copied" : ""}`,
2595
+ onClick: handleCopy,
2596
+ title: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u5185\u5BB9",
2597
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2598
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M20 6L9 17L4 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }),
2599
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: "\u5DF2\u590D\u5236" })
2600
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2601
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: [
2602
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", stroke: "currentColor", strokeWidth: "2" }),
2603
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5 15H4C2.9 15 2 14.1 2 13V4C2 2.9 2.9 2 4 2H13C14.1 2 15 2.9 15 4V5", stroke: "currentColor", strokeWidth: "2" })
2604
+ ] }),
2605
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: "\u590D\u5236" })
2606
+ ] })
2124
2607
  }
2125
- }).catch((error) => {
2126
- console.error("\u53D1\u9001\u6D88\u606F\u5931\u8D25:", error);
2127
- }).finally(() => {
2128
- setIsSending(false);
2129
- });
2130
- } else {
2131
- setInputValue("");
2132
- if (inputRef.current) {
2133
- inputRef.current.style.height = "auto";
2134
- }
2135
- if (isTyping) {
2136
- setIsTyping(false);
2137
- onTyping?.(false);
2138
- }
2139
- setIsSending(false);
2608
+ ),
2609
+ status === "sending" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "message-status sending", children: "\u53D1\u9001\u4E2D..." }),
2610
+ status === "error" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "message-status error", children: "\u53D1\u9001\u5931\u8D25" })
2611
+ ] })
2612
+ ] });
2613
+ const renderMessage = () => {
2614
+ switch (role) {
2615
+ case "system":
2616
+ return renderSystemMessage();
2617
+ case "tool":
2618
+ return renderToolMessage();
2619
+ case "user":
2620
+ case "assistant":
2621
+ default:
2622
+ return renderUserAssistantMessage();
2140
2623
  }
2141
- }, [inputValue, disabled, loading, isSending, onSendMessage, maxInputLength, isTyping, onTyping]);
2142
- const handleKeyDown = (0, import_react11.useCallback)((e) => {
2143
- if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
2144
- e.preventDefault();
2145
- handleSend();
2624
+ };
2625
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: getContainerClassName(), style, "data-message-id": id, children: renderMessage() });
2626
+ });
2627
+ SmartMessage.displayName = "SmartMessage";
2628
+ var SmartMessage_default = SmartMessage;
2629
+
2630
+ // src/components/Chat/Chat.tsx
2631
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2632
+ var Chat = ({
2633
+ messages = [],
2634
+ title = "AI \u52A9\u624B",
2635
+ loading = false,
2636
+ conversations = [],
2637
+ currentConversationId,
2638
+ emptyText = "\u6682\u65E0\u5386\u53F2\u5BF9\u8BDD",
2639
+ newConversationText = "\u65B0\u5EFA\u5BF9\u8BDD",
2640
+ historyTitle = "\u5386\u53F2\u5BF9\u8BDD",
2641
+ showHistoryButton = true,
2642
+ showMinimizeButton = true,
2643
+ showHeader = true,
2644
+ showFooter = false,
2645
+ autoScroll = true,
2646
+ onSwitchConversation,
2647
+ onNewConversation,
2648
+ onDeleteConversation,
2649
+ onMinimize,
2650
+ onRestore,
2651
+ onMessageCopy,
2652
+ className = "",
2653
+ style = {},
2654
+ headerClassName = "",
2655
+ headerStyle = {},
2656
+ messagesClassName = "",
2657
+ messagesStyle = {},
2658
+ bubbleClassName = "",
2659
+ height = "600px",
2660
+ width
2661
+ }) => {
2662
+ const [showHistory, setShowHistory] = (0, import_react15.useState)(false);
2663
+ const [isMinimized, setIsMinimized] = (0, import_react15.useState)(false);
2664
+ const messagesContainerRef = (0, import_react15.useRef)(null);
2665
+ const messagesEndRef = (0, import_react15.useRef)(null);
2666
+ const historyPanelRef = (0, import_react15.useRef)(null);
2667
+ const currentConversation = (0, import_react15.useMemo)(
2668
+ () => conversations.find((c) => c.id === currentConversationId),
2669
+ [conversations, currentConversationId]
2670
+ );
2671
+ const currentTitle = currentConversation?.title || title;
2672
+ (0, import_react15.useEffect)(() => {
2673
+ if (autoScroll && messagesContainerRef.current && !showHistory && !isMinimized) {
2674
+ messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
2146
2675
  }
2147
- }, [handleSend]);
2148
- const handleInputChange = (0, import_react11.useCallback)((e) => {
2149
- const value = e.target.value;
2150
- if (value.length <= maxInputLength) {
2151
- setInputValue(value);
2152
- e.target.style.height = "auto";
2153
- e.target.style.height = `${Math.min(e.target.scrollHeight, 100)}px`;
2154
- const hasContent = value.length > 0;
2155
- if (hasContent !== isTyping) {
2156
- setIsTyping(hasContent);
2157
- onTyping?.(hasContent);
2676
+ }, [messages, loading, showHistory, isMinimized, autoScroll]);
2677
+ (0, import_react15.useEffect)(() => {
2678
+ const handleClickOutside = (event) => {
2679
+ if (showHistory && historyPanelRef.current && !historyPanelRef.current.contains(event.target)) {
2680
+ setShowHistory(false);
2158
2681
  }
2682
+ };
2683
+ document.addEventListener("mousedown", handleClickOutside);
2684
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2685
+ }, [showHistory]);
2686
+ const handleDeleteConversation = (0, import_react15.useCallback)((conversationId) => {
2687
+ onDeleteConversation?.(conversationId);
2688
+ }, [onDeleteConversation]);
2689
+ const handleMinimize = (0, import_react15.useCallback)(() => {
2690
+ setIsMinimized(true);
2691
+ onMinimize?.();
2692
+ }, [onMinimize]);
2693
+ const handleRestore = (0, import_react15.useCallback)(() => {
2694
+ setIsMinimized(false);
2695
+ onRestore?.();
2696
+ }, [onRestore]);
2697
+ const handleCopy = (0, import_react15.useCallback)((content) => {
2698
+ const message = messages.find((m) => m.content === content);
2699
+ if (message) {
2700
+ onMessageCopy?.(message);
2159
2701
  }
2160
- }, [maxInputLength, isTyping, onTyping]);
2161
- const formatTime = (0, import_react11.useCallback)((date) => {
2162
- return new Date(date).toLocaleTimeString("zh-CN", {
2163
- hour: "2-digit",
2164
- minute: "2-digit"
2165
- });
2166
- }, []);
2167
- const renderMessage = (message) => {
2168
- const isUser = message.type === "user";
2169
- const isSystem = message.type === "system";
2170
- const isCopied = copiedMessageId === message.id;
2171
- if (isSystem) {
2172
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-message-system", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "system-content", children: message.content }) }, message.id);
2173
- }
2174
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `chat-message ${isUser ? "user" : "assistant"}`, children: [
2175
- !isUser && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "message-avatar", children: assistantName[0] }),
2176
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "message-content-wrapper", children: [
2177
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "message-header", children: [
2178
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "message-sender", children: isUser ? userName : assistantName }),
2179
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "message-time", children: formatTime(message.timestamp) })
2180
- ] }),
2181
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "message-bubble", children: [
2182
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "message-text", children: message.content }),
2183
- message.status === "sending" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "message-status sending", children: "\u53D1\u9001\u4E2D..." }),
2184
- message.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "message-status error", children: "\u53D1\u9001\u5931\u8D25" })
2185
- ] }),
2186
- enableCopy && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2187
- "button",
2188
- {
2189
- className: `copy-btn ${isCopied ? "copied" : ""}`,
2190
- onClick: () => handleCopyMessage(message.id, message.content),
2191
- title: isCopied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u5185\u5BB9",
2192
- "aria-label": isCopied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u5185\u5BB9",
2193
- children: isCopied ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2194
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M20 6L9 17L4 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2195
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u5DF2\u590D\u5236" })
2196
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2197
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
2198
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", stroke: "currentColor", strokeWidth: "2" }),
2199
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M5 15H4C2.9 15 2 14.1 2 13V4C2 2.9 2.9 2 4 2H13C14.1 2 15 2.9 15 4V5", stroke: "currentColor", strokeWidth: "2" })
2200
- ] }),
2201
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u590D\u5236" })
2202
- ] })
2203
- }
2204
- )
2205
- ] })
2206
- ] }, message.id);
2207
- };
2208
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `chat-container ${currentTheme}`, style: { height }, children: [
2209
- showHeader && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-header", children: [
2210
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-title", children: title }),
2211
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-status", children: [
2212
- (loading || isSending) && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "status-dot" }),
2213
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: loading || isSending ? "AI \u6B63\u5728\u601D\u8003..." : "\u5728\u7EBF" })
2702
+ }, [messages, onMessageCopy]);
2703
+ const containerStyle = (0, import_react15.useMemo)(() => ({
2704
+ height,
2705
+ width,
2706
+ ...style
2707
+ }), [height, width, style]);
2708
+ if (isMinimized) {
2709
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: `chat-container-minimized ${className}`, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "restore-btn-only", onClick: handleRestore, title: "\u5C55\u5F00", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M12 5V19M5 12H19", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) });
2710
+ }
2711
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `chat-container ${className}`, style: containerStyle, children: [
2712
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `chat-header ${headerClassName}`, style: headerStyle, children: [
2713
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "chat-title", children: currentTitle }),
2714
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "chat-header-actions", children: [
2715
+ showHistoryButton && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "history-btn", onClick: () => setShowHistory(!showHistory), title: "\u5386\u53F2\u5BF9\u8BDD", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
2716
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M12 8V12L15 15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2717
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" })
2718
+ ] }) }),
2719
+ showMinimizeButton && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "minimize-btn", onClick: handleMinimize, title: "\u6700\u5C0F\u5316", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M5 12H19", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
2214
2720
  ] })
2215
2721
  ] }),
2216
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-messages", children: [
2217
- messages.map(renderMessage),
2218
- (loading || isSending) && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-message assistant", children: [
2219
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "message-avatar", children: assistantName[0] }),
2220
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "message-content-wrapper", children: [
2221
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "message-header", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "message-sender", children: assistantName }) }),
2222
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "message-bubble", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "typing-indicator", children: [
2223
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {}),
2224
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {}),
2225
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {})
2226
- ] }) })
2227
- ] })
2228
- ] }),
2229
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: messagesEndRef })
2722
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `chat-messages ${messagesClassName}`, ref: messagesContainerRef, style: messagesStyle, children: [
2723
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2724
+ SmartMessage_default,
2725
+ {
2726
+ id: message.id,
2727
+ content: message.content,
2728
+ role: message.type,
2729
+ timestamp: message.timestamp,
2730
+ status: message.status,
2731
+ toolName: message.toolName,
2732
+ toolResult: message.toolResult,
2733
+ onCopy: handleCopy,
2734
+ className: bubbleClassName
2735
+ },
2736
+ message.id
2737
+ )),
2738
+ loading && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "typing-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "typing-indicator", children: [
2739
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", {}),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", {}),
2741
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", {})
2742
+ ] }) }),
2743
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: messagesEndRef })
2230
2744
  ] }),
2231
- copyError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "copy-error-toast", children: copyError }),
2232
- showFooter && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-footer", children: [
2233
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-input-wrapper", children: [
2234
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2235
- "textarea",
2236
- {
2237
- ref: inputRef,
2238
- className: "chat-input",
2239
- value: inputValue,
2240
- onChange: handleInputChange,
2241
- onKeyDown: handleKeyDown,
2242
- placeholder,
2243
- disabled: disabled || loading || isSending,
2244
- rows: 1,
2245
- maxLength: maxInputLength,
2246
- spellCheck: false,
2247
- autoCorrect: "off",
2248
- autoCapitalize: "off",
2249
- autoComplete: "off"
2250
- }
2251
- ),
2252
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2253
- "button",
2254
- {
2255
- className: `chat-send-btn ${!inputValue.trim() || disabled || loading || isSending ? "disabled" : ""}`,
2256
- onClick: handleSend,
2257
- disabled: !inputValue.trim() || disabled || loading || isSending,
2258
- children: "\u53D1\u9001"
2259
- }
2260
- )
2745
+ showFooter && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "chat-footer" }),
2746
+ showHistory && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "history-panel", ref: historyPanelRef, children: [
2747
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "history-header", children: [
2748
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { children: historyTitle }),
2749
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "close-history-btn", onClick: () => setShowHistory(false), children: "\u2715" })
2261
2750
  ] }),
2262
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-tips", children: [
2263
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u6309 Enter \u53D1\u9001\uFF0CShift + Enter \u6362\u884C" }),
2264
- maxInputLength && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "char-count", children: [
2265
- inputValue.length,
2266
- "/",
2267
- maxInputLength
2268
- ] })
2751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "history-list", children: [
2752
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { className: "new-conversation-btn-large", onClick: () => {
2753
+ onNewConversation?.();
2754
+ setShowHistory(false);
2755
+ }, children: [
2756
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M12 5V19M5 12H19", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }),
2757
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: newConversationText })
2758
+ ] }),
2759
+ conversations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "empty-history", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: emptyText }) }) : conversations.map((conv) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2760
+ "div",
2761
+ {
2762
+ className: `history-item ${currentConversationId === conv.id ? "active" : ""}`,
2763
+ onClick: () => {
2764
+ onSwitchConversation?.(conv.id);
2765
+ setShowHistory(false);
2766
+ },
2767
+ children: [
2768
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "history-item-content", children: [
2769
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "history-item-title", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: conv.title }) }),
2770
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "history-item-preview", children: conv.lastMessage }),
2771
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "history-item-meta", children: [
2772
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: new Date(conv.timestamp).toLocaleDateString() }),
2773
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { children: [
2774
+ conv.messages.length,
2775
+ "\u6761\u6D88\u606F"
2776
+ ] })
2777
+ ] })
2778
+ ] }),
2779
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "history-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2780
+ "button",
2781
+ {
2782
+ className: "delete-conversation-btn",
2783
+ onClick: (e) => {
2784
+ e.stopPropagation();
2785
+ handleDeleteConversation(conv.id);
2786
+ },
2787
+ title: "\u5220\u9664\u5BF9\u8BDD",
2788
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: [
2789
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M3 6H21", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
2790
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M19 6V20C19 21.1 18.1 22 17 22H7C5.9 22 5 21.1 5 20V6", stroke: "currentColor", strokeWidth: "2" }),
2791
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M8 6V4C8 2.9 8.9 2 10 2H14C15.1 2 16 2.9 16 4V6", stroke: "currentColor", strokeWidth: "2" })
2792
+ ] })
2793
+ }
2794
+ ) })
2795
+ ]
2796
+ },
2797
+ conv.id
2798
+ ))
2269
2799
  ] })
2270
2800
  ] })
2271
2801
  ] });
@@ -2280,16 +2810,20 @@ var Chat = ({
2280
2810
  Card,
2281
2811
  Chat,
2282
2812
  CheckButton,
2813
+ ContextMenuProvider,
2283
2814
  DeleteDialog,
2284
2815
  Input,
2285
2816
  ListGroup,
2286
2817
  ListGroupItem,
2818
+ MarkdownEditor,
2287
2819
  OrphanDialog,
2288
2820
  RollingBox,
2289
2821
  Select,
2290
2822
  SideBar,
2291
2823
  Slider,
2292
- Tabs,
2824
+ SmartMessage,
2825
+ TabBar,
2826
+ TagItem,
2293
2827
  ThemeProvider,
2294
2828
  Tree,
2295
2829
  VirtualList,
@@ -2298,5 +2832,6 @@ var Chat = ({
2298
2832
  isDescendantOf,
2299
2833
  lazyLoad,
2300
2834
  useAlert,
2835
+ useContextMenu,
2301
2836
  useTheme
2302
2837
  });