@pactor-app/ui 1.21.0 → 1.23.0

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.
@@ -486,6 +486,7 @@ var ICONS = {
486
486
  "file-text": import_lucide_react2.FileText,
487
487
  "panel-left": import_lucide_react2.PanelLeft,
488
488
  "panel-right-open": import_lucide_react2.PanelRightOpen,
489
+ "panel-right-close": import_lucide_react2.PanelRightClose,
489
490
  square: import_lucide_react2.Square,
490
491
  history: import_lucide_react2.History,
491
492
  "rotate-ccw": import_lucide_react2.RotateCcw,
@@ -3053,6 +3054,7 @@ function ChatInput({
3053
3054
  toolbarEnd,
3054
3055
  header,
3055
3056
  footer,
3057
+ field,
3056
3058
  onChange,
3057
3059
  onSubmit,
3058
3060
  className,
@@ -3063,6 +3065,8 @@ function ChatInput({
3063
3065
  const [draft, setDraft] = (0, import_react14.useState)("");
3064
3066
  const text = controlled ? value : draft;
3065
3067
  const canSubmit = !disabled && text.trim() !== "";
3068
+ const customField = field !== void 0 && field !== null;
3069
+ const renderSlot = (slot) => (0, import_react14.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
3066
3070
  const composingRef = (0, import_react14.useRef)(false);
3067
3071
  const handleChange = (next) => {
3068
3072
  if (!controlled) {
@@ -3098,8 +3102,8 @@ function ChatInput({
3098
3102
  ),
3099
3103
  style,
3100
3104
  children: [
3101
- header ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "px-3 pt-3", children: renderChildren([header]) }) : null,
3102
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3105
+ header ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "px-3 pt-3", children: renderSlot(header) }) : null,
3106
+ customField ? field : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3103
3107
  Textarea,
3104
3108
  {
3105
3109
  value: text,
@@ -3114,9 +3118,9 @@ function ChatInput({
3114
3118
  }
3115
3119
  ),
3116
3120
  toolbarStart || toolbarEnd || !hideSend ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-1 px-2 pb-2", children: [
3117
- toolbarStart ? renderChildren([toolbarStart]) : null,
3121
+ toolbarStart ? renderSlot(toolbarStart) : null,
3118
3122
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "flex-1" }),
3119
- toolbarEnd ? renderChildren([toolbarEnd]) : null,
3123
+ toolbarEnd ? renderSlot(toolbarEnd) : null,
3120
3124
  hideSend ? null : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3121
3125
  Button,
3122
3126
  {
@@ -3130,7 +3134,7 @@ function ChatInput({
3130
3134
  }
3131
3135
  )
3132
3136
  ] }) : null,
3133
- footer ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "border-t border-border px-3 py-2", children: renderChildren([footer]) }) : null
3137
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "border-t border-border px-3 py-2", children: renderSlot(footer) }) : null
3134
3138
  ]
3135
3139
  }
3136
3140
  );
@@ -3682,7 +3686,8 @@ function DatePicker(props) {
3682
3686
  onSelect: handleRangeDaySelect,
3683
3687
  modifiers: rangeModifiers,
3684
3688
  modifiersClassNames: rangeModifierClassNames,
3685
- locale: dfLocale
3689
+ locale: dfLocale,
3690
+ showOutsideDays: false
3686
3691
  }
3687
3692
  )
3688
3693
  }
@@ -3696,7 +3701,8 @@ function DatePicker(props) {
3696
3701
  onSelect: handleRangeDaySelect,
3697
3702
  modifiers: rangeModifiers,
3698
3703
  modifiersClassNames: rangeModifierClassNames,
3699
- locale: dfLocale
3704
+ locale: dfLocale,
3705
+ showOutsideDays: false
3700
3706
  }
3701
3707
  ) })
3702
3708
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
@@ -11735,7 +11741,14 @@ function ArtifactTreeRow({
11735
11741
  className: "flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-accent",
11736
11742
  onClick: () => setOpen((value) => !value),
11737
11743
  children: [
11738
- /* @__PURE__ */ (0, import_jsx_runtime170.jsx)("span", { className: "inline-flex transition-transform data-[open=true]:rotate-90", "data-open": open, children: /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(Icon, { name: "chevron-right", size: 12 }) }),
11744
+ /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(
11745
+ "span",
11746
+ {
11747
+ className: "inline-flex transition-transform data-[open=true]:rotate-90",
11748
+ "data-open": open,
11749
+ children: /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(Icon, { name: "chevron-right", size: 12 })
11750
+ }
11751
+ ),
11739
11752
  /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(Icon, { name: "folder", size: 13 }),
11740
11753
  /* @__PURE__ */ (0, import_jsx_runtime170.jsx)("span", { className: "min-w-0 flex-1 truncate", children: node.name })
11741
11754
  ]
@@ -11867,6 +11880,7 @@ function ArtifactPanel({
11867
11880
  icon: "download",
11868
11881
  variant: "text",
11869
11882
  tooltip: "\u4E0B\u8F7D\u4EA7\u7269",
11883
+ className: "px-2",
11870
11884
  onClick: () => onDownload ? onDownload(artifact) : void downloadArtifact(artifact)
11871
11885
  }
11872
11886
  ) : null,
@@ -11876,11 +11890,12 @@ function ArtifactPanel({
11876
11890
  icon: "x",
11877
11891
  variant: "text",
11878
11892
  tooltip: "\u6536\u8D77\u4EA7\u7269\u533A",
11893
+ className: "px-2",
11879
11894
  onClick: () => onClose?.()
11880
11895
  }
11881
11896
  )
11882
11897
  ] }),
11883
- /* @__PURE__ */ (0, import_jsx_runtime170.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-4", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(
11898
+ /* @__PURE__ */ (0, import_jsx_runtime170.jsx)("div", { className: "scrollbar-subtle min-h-0 flex-1 overflow-auto p-4", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime170.jsx)(
11884
11899
  ArtifactListView,
11885
11900
  {
11886
11901
  nodes: buildArtifactTree(artifacts),
@@ -12138,7 +12153,7 @@ function Thinking({
12138
12153
  {
12139
12154
  "data-slot": "thinking",
12140
12155
  "data-status": status,
12141
- className: cn("w-full overflow-hidden rounded-md border border-border bg-muted/50", className),
12156
+ className: cn("w-full", className),
12142
12157
  style,
12143
12158
  children: [
12144
12159
  /* @__PURE__ */ (0, import_jsx_runtime176.jsxs)(
@@ -12147,12 +12162,12 @@ function Thinking({
12147
12162
  type: "button",
12148
12163
  "data-slot": "thinking-trigger",
12149
12164
  "aria-expanded": isExpanded,
12150
- className: "flex w-full items-center gap-2 px-3 py-2 text-left text-sm",
12165
+ className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
12151
12166
  onClick: toggle,
12152
12167
  children: [
12153
12168
  /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: cn("text-muted-foreground", status === "thinking" && "animate-pulse motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: "brain", size: "sm" }) }),
12154
- /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { "data-slot": "thinking-title", className: "flex-1 text-muted-foreground", children: resolvedTitle }),
12155
- /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: isExpanded ? "chevron-down" : "chevron-right", size: "sm" })
12169
+ /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { "data-slot": "thinking-title", className: "text-muted-foreground", children: resolvedTitle }),
12170
+ /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: isExpanded ? "chevron-down" : "chevron-right", size: "sm" }) })
12156
12171
  ]
12157
12172
  }
12158
12173
  ),
@@ -12160,7 +12175,7 @@ function Thinking({
12160
12175
  "div",
12161
12176
  {
12162
12177
  "data-slot": "thinking-content",
12163
- className: "border-t border-border px-3 py-2 text-sm whitespace-pre-wrap text-muted-foreground",
12178
+ className: "py-1 pl-6 text-sm whitespace-pre-wrap text-muted-foreground",
12164
12179
  children: content
12165
12180
  }
12166
12181
  ) : null
@@ -12190,42 +12205,51 @@ function ToolCall({ name, params, status = "done", result, durationMs, defaultEx
12190
12205
  const [expanded, setExpanded] = (0, import_react62.useState)(defaultExpanded ?? status === "running");
12191
12206
  const meta = statusIcon3[status];
12192
12207
  const paramsText = renderValue(params);
12208
+ const hasDetail = Boolean(paramsText) || Boolean(result);
12209
+ const headerInner = /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)(import_jsx_runtime177.Fragment, { children: [
12210
+ /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: "terminal", size: "sm" }) }),
12211
+ /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { "data-slot": "tool-call-name", className: "min-w-0 truncate font-medium", children: name ?? "\u5DE5\u5177\u8C03\u7528" }),
12212
+ /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: cn("shrink-0", meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: meta.icon, size: "sm" }) }),
12213
+ durationMs !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
12214
+ (durationMs / 1e3).toFixed(1),
12215
+ "s"
12216
+ ] }) : null,
12217
+ hasDetail ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: expanded ? "chevron-down" : "chevron-right", size: "sm" }) }) : null
12218
+ ] });
12193
12219
  return /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)(
12194
12220
  "div",
12195
12221
  {
12196
12222
  "data-slot": "tool-call",
12197
12223
  "data-status": status,
12198
- className: cn("w-full overflow-hidden rounded-md border border-border", className),
12224
+ className: cn("w-full", className),
12199
12225
  style,
12200
12226
  children: [
12201
- /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)(
12227
+ hasDetail ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(
12202
12228
  "button",
12203
12229
  {
12204
12230
  type: "button",
12205
12231
  "data-slot": "tool-call-trigger",
12206
12232
  "aria-expanded": expanded,
12207
- className: "flex w-full items-center gap-2 px-3 py-2 text-left text-sm",
12233
+ className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
12208
12234
  onClick: () => setExpanded((value) => !value),
12209
- children: [
12210
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: "terminal", size: "sm" }) }),
12211
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { "data-slot": "tool-call-name", className: "min-w-0 flex-1 truncate font-medium", children: name ?? "\u5DE5\u5177\u8C03\u7528" }),
12212
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: cn("shrink-0", meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: meta.icon, size: "sm" }) }),
12213
- durationMs !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
12214
- (durationMs / 1e3).toFixed(1),
12215
- "s"
12216
- ] }) : null,
12217
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: expanded ? "chevron-down" : "chevron-right", size: "sm" })
12218
- ]
12235
+ children: headerInner
12236
+ }
12237
+ ) : /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(
12238
+ "div",
12239
+ {
12240
+ "data-slot": "tool-call-trigger",
12241
+ className: "flex w-full items-center gap-2 py-1 text-left text-sm",
12242
+ children: headerInner
12219
12243
  }
12220
12244
  ),
12221
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { "data-slot": "tool-call-body", className: "flex flex-col gap-2 border-t border-border px-3 py-2", children: [
12245
+ hasDetail && expanded ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { "data-slot": "tool-call-body", className: "flex flex-col gap-2 py-1 pl-6", children: [
12222
12246
  paramsText ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { children: [
12223
12247
  /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("div", { className: "text-xs font-medium text-muted-foreground", children: "\u53C2\u6570" }),
12224
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("pre", { "data-slot": "tool-call-params", className: "mt-1 overflow-x-auto rounded-sm bg-muted p-2 text-xs whitespace-pre-wrap", children: paramsText })
12248
+ /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("pre", { "data-slot": "tool-call-params", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: paramsText })
12225
12249
  ] }) : null,
12226
12250
  result ? /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { children: [
12227
12251
  /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("div", { className: "text-xs font-medium text-muted-foreground", children: "\u7ED3\u679C" }),
12228
- /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("pre", { "data-slot": "tool-call-result", className: "mt-1 overflow-x-auto rounded-sm bg-muted p-2 text-xs whitespace-pre-wrap", children: result })
12252
+ /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("pre", { "data-slot": "tool-call-result", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: result })
12229
12253
  ] }) : null
12230
12254
  ] }) : null
12231
12255
  ]
@@ -12235,12 +12259,26 @@ function ToolCall({ name, params, status = "done", result, durationMs, defaultEx
12235
12259
 
12236
12260
  // src/components/chat/ChatMessage/index.tsx
12237
12261
  var import_jsx_runtime178 = require("react/jsx-runtime");
12238
- function PartView({ part, role }) {
12262
+ function PartView({
12263
+ part,
12264
+ role,
12265
+ onOpenArtifacts
12266
+ }) {
12267
+ if (role === "system" && (part.type === "text" || part.type === "markdown")) {
12268
+ return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
12269
+ "div",
12270
+ {
12271
+ "data-slot": "chat-message-system-part",
12272
+ className: "w-full text-center text-xs text-muted-foreground",
12273
+ children: part.type === "markdown" ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(import_markdown2.MarkdownDslComponent, { content: part.content }) : part.content
12274
+ }
12275
+ );
12276
+ }
12239
12277
  switch (part.type) {
12240
12278
  case "text":
12241
12279
  return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "muted", children: /* @__PURE__ */ (0, import_jsx_runtime178.jsx)("span", { className: "text-sm whitespace-pre-wrap", children: part.content }) });
12242
12280
  case "markdown":
12243
- return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(import_markdown2.MarkdownDslComponent, { content: part.content, className: "text-sm" }) });
12281
+ return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(import_markdown2.MarkdownDslComponent, { content: part.content }) });
12244
12282
  case "thinking":
12245
12283
  return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Thinking, { content: part.content, status: part.status ?? "done" });
12246
12284
  case "tool-call":
@@ -12248,10 +12286,31 @@ function PartView({ part, role }) {
12248
12286
  case "tool-result":
12249
12287
  return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)("pre", { "data-slot": "chat-message-tool-result", className: "overflow-x-auto rounded-md bg-muted p-2 text-xs whitespace-pre-wrap", children: part.content });
12250
12288
  case "status":
12251
- return /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { "data-slot": "chat-message-status", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
12289
+ return /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { "data-slot": "chat-message-status", className: "flex w-fit items-center gap-1.5 text-muted-foreground", children: [
12252
12290
  /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: "clock", size: "sm" }),
12253
12291
  part.text
12254
12292
  ] });
12293
+ case "artifacts": {
12294
+ const artifactsClass = "flex w-fit items-center gap-1.5 text-muted-foreground";
12295
+ const label = `\u5DF2\u751F\u6210 ${part.count} \u4E2A\u4EA7\u7269`;
12296
+ return onOpenArtifacts ? /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)(
12297
+ "button",
12298
+ {
12299
+ type: "button",
12300
+ "data-slot": "chat-message-artifacts",
12301
+ className: cn(artifactsClass, "cursor-pointer hover:text-foreground"),
12302
+ onClick: onOpenArtifacts,
12303
+ children: [
12304
+ /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: "package", size: "sm" }),
12305
+ label,
12306
+ /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: "chevron-right", size: 12 })
12307
+ ]
12308
+ }
12309
+ ) : /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { "data-slot": "chat-message-artifacts", className: artifactsClass, children: [
12310
+ /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: "package", size: "sm" }),
12311
+ label
12312
+ ] });
12313
+ }
12255
12314
  case "error":
12256
12315
  return /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { "data-slot": "chat-message-error", className: "flex items-center gap-1.5 text-sm text-destructive", children: [
12257
12316
  /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: "circle-alert", size: "sm" }),
@@ -12261,19 +12320,31 @@ function PartView({ part, role }) {
12261
12320
  return null;
12262
12321
  }
12263
12322
  }
12323
+ var ACTION_ICON_BY_NAME = {
12324
+ copy: "copy",
12325
+ retry: "rotate-ccw",
12326
+ regenerate: "refresh-ccw",
12327
+ edit: "pencil",
12328
+ like: "thumbs-up",
12329
+ dislike: "thumbs-down",
12330
+ share: "share",
12331
+ delete: "trash"
12332
+ };
12264
12333
  function ChatMessage({
12265
12334
  role = "assistant",
12266
12335
  parts = [],
12267
12336
  status = "completed",
12268
12337
  agent,
12269
12338
  time,
12270
- showSender = true,
12339
+ showSender = false,
12271
12340
  actions = [],
12272
12341
  onAction,
12342
+ onOpenArtifacts,
12273
12343
  className,
12274
12344
  style
12275
12345
  }) {
12276
12346
  const isUser = role === "user";
12347
+ const isSystem = role === "system";
12277
12348
  const senderName = isUser ? "\u6211" : agent?.name ?? "\u52A9\u624B";
12278
12349
  return /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)(
12279
12350
  "div",
@@ -12281,10 +12352,16 @@ function ChatMessage({
12281
12352
  "data-slot": "chat-message",
12282
12353
  "data-role": role,
12283
12354
  "data-status": status,
12284
- className: cn("flex w-full flex-col gap-1.5", isUser && "items-end", className),
12355
+ className: cn(
12356
+ "flex w-full flex-col gap-1.5",
12357
+ isUser && "items-end",
12358
+ // system 居中弱提示(参考 @pactor-app/chat MessageBubble)
12359
+ isSystem && "items-center text-muted-foreground",
12360
+ className
12361
+ ),
12285
12362
  style,
12286
12363
  children: [
12287
- showSender && role !== "system" ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
12364
+ showSender ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
12288
12365
  Sender,
12289
12366
  {
12290
12367
  name: senderName,
@@ -12293,35 +12370,445 @@ function ChatMessage({
12293
12370
  align: isUser ? "end" : "start"
12294
12371
  }
12295
12372
  ) : null,
12296
- /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { className: cn("flex min-w-0 w-full max-w-full flex-col gap-2", isUser && "items-end"), children: [
12297
- parts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(PartView, { part, role }, index)),
12373
+ /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)("div", { className: cn("flex min-w-0 w-full max-w-full flex-col gap-2", isUser && "items-end", isSystem && "items-center"), children: [
12374
+ parts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(PartView, { part, role, onOpenArtifacts }, index)),
12298
12375
  status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(StreamingText, { content: "", streaming: true }) : null
12299
12376
  ] }),
12300
- actions.length > 0 && (status === "completed" || status === "error") ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)("div", { "data-slot": "chat-message-actions", className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime178.jsxs)(
12301
- "button",
12302
- {
12303
- type: "button",
12304
- "data-slot": "chat-message-action",
12305
- "data-action": action.name,
12306
- className: "flex items-center gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
12307
- onClick: () => onAction?.(action.name),
12308
- children: [
12309
- action.icon ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: action.icon, size: "sm" }) : null,
12310
- action.label ?? action.name
12311
- ]
12312
- },
12313
- action.name
12314
- )) }) : null
12377
+ actions.length > 0 && (status === "completed" || status === "error") ? /* @__PURE__ */ (0, import_jsx_runtime178.jsx)("div", { "data-slot": "chat-message-actions", className: "flex items-center gap-1 mt-2", children: actions.map((action) => {
12378
+ const label = action.label ?? action.name;
12379
+ const iconName = action.icon ?? ACTION_ICON_BY_NAME[action.name];
12380
+ if (iconName) {
12381
+ return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Tooltip2, { content: label, side: "top", children: /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
12382
+ "button",
12383
+ {
12384
+ type: "button",
12385
+ "data-slot": "chat-message-action",
12386
+ "data-action": action.name,
12387
+ "aria-label": label,
12388
+ className: "flex cursor-pointer items-center rounded-sm p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
12389
+ onClick: () => onAction?.(action.name),
12390
+ children: /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(Icon, { name: iconName, size: "sm" })
12391
+ }
12392
+ ) }, action.name);
12393
+ }
12394
+ return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
12395
+ "button",
12396
+ {
12397
+ type: "button",
12398
+ "data-slot": "chat-message-action",
12399
+ "data-action": action.name,
12400
+ className: "flex items-center cursor-pointer gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
12401
+ onClick: () => onAction?.(action.name),
12402
+ children: label
12403
+ },
12404
+ action.name
12405
+ );
12406
+ }) }) : null
12315
12407
  ]
12316
12408
  }
12317
12409
  );
12318
12410
  }
12319
12411
 
12320
12412
  // src/components/chat/ChatPage/index.tsx
12321
- var import_react65 = require("react");
12413
+ var import_runtime26 = require("@pactor-app/runtime");
12414
+ var import_react67 = require("react");
12322
12415
 
12323
12416
  // src/components/chat/Composer/index.tsx
12417
+ var import_react64 = require("react");
12418
+
12419
+ // src/components/chat/Composer/mention-input.tsx
12420
+ var import_react63 = require("react");
12421
+ var import_server = require("react-dom/server");
12324
12422
  var import_jsx_runtime179 = require("react/jsx-runtime");
12423
+ var NBSP = "\xA0";
12424
+ var CHIP_ATTR = "data-mention-chip";
12425
+ function escapeRegExp(text) {
12426
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12427
+ }
12428
+ function isChipElement(node) {
12429
+ return node instanceof HTMLElement && node.hasAttribute(CHIP_ATTR);
12430
+ }
12431
+ function serializeNode(node) {
12432
+ let out = "";
12433
+ node.childNodes.forEach((child) => {
12434
+ if (child.nodeType === Node.TEXT_NODE) {
12435
+ out += (child.textContent ?? "").replace(/\u00A0/g, " ");
12436
+ } else if (isChipElement(child)) {
12437
+ out += `${child.dataset["trigger"] ?? ""}${child.dataset["label"] ?? ""}`;
12438
+ } else if (child instanceof HTMLBRElement) {
12439
+ out += "\n";
12440
+ } else if (child instanceof HTMLElement) {
12441
+ const inner = serializeNode(child).replace(/\n$/, "");
12442
+ out += (out === "" || out.endsWith("\n") ? "" : "\n") + inner + "\n";
12443
+ }
12444
+ });
12445
+ return out;
12446
+ }
12447
+ function collectChips(field) {
12448
+ return Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).map((el) => ({
12449
+ id: el.dataset["id"] ?? "",
12450
+ label: el.dataset["label"] ?? "",
12451
+ trigger: el.dataset["trigger"] ?? ""
12452
+ }));
12453
+ }
12454
+ function detectActiveMention(field, sources) {
12455
+ const selection = window.getSelection();
12456
+ if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) {
12457
+ return null;
12458
+ }
12459
+ const anchor = selection.anchorNode;
12460
+ if (!anchor || anchor.nodeType !== Node.TEXT_NODE || !field.contains(anchor)) {
12461
+ return null;
12462
+ }
12463
+ const caretOffset = selection.anchorOffset;
12464
+ const beforeCaret = (anchor.textContent ?? "").slice(0, caretOffset);
12465
+ for (const source of sources) {
12466
+ const trigger = source.trigger;
12467
+ const match = new RegExp(
12468
+ `(?:^|\\s)${escapeRegExp(trigger)}([^\\s${escapeRegExp(trigger)}]*)$`
12469
+ ).exec(beforeCaret);
12470
+ if (match) {
12471
+ const query = match[1] ?? "";
12472
+ return {
12473
+ source,
12474
+ query,
12475
+ node: anchor,
12476
+ triggerStart: caretOffset - query.length - trigger.length,
12477
+ caretOffset
12478
+ };
12479
+ }
12480
+ }
12481
+ return null;
12482
+ }
12483
+ function chipIcon(item, source) {
12484
+ return item.icon ?? source.icon ?? (source.trigger === "@" ? "user" : "file-text");
12485
+ }
12486
+ var MentionInput = (0, import_react63.forwardRef)(
12487
+ function MentionInput2({
12488
+ value,
12489
+ placeholder,
12490
+ disabled,
12491
+ sources,
12492
+ chips,
12493
+ onChipsChange,
12494
+ onChange,
12495
+ onSubmit,
12496
+ className,
12497
+ style
12498
+ }, ref) {
12499
+ const fieldRef = (0, import_react63.useRef)(null);
12500
+ const [menu, setMenu] = (0, import_react63.useState)(null);
12501
+ const [empty, setEmpty] = (0, import_react63.useState)(true);
12502
+ const suppressSyncRef = (0, import_react63.useRef)(false);
12503
+ const composingRef = (0, import_react63.useRef)(false);
12504
+ const emitChips = () => {
12505
+ if (suppressSyncRef.current || !fieldRef.current) {
12506
+ return;
12507
+ }
12508
+ onChipsChange?.(collectChips(fieldRef.current));
12509
+ };
12510
+ const serialize = () => fieldRef.current ? serializeNode(fieldRef.current).replace(/\n$/, "") : "";
12511
+ const buildChipElement = (item, source) => {
12512
+ const chip = document.createElement("span");
12513
+ chip.setAttribute(CHIP_ATTR, "");
12514
+ chip.dataset["id"] = item.id;
12515
+ chip.dataset["label"] = item.label;
12516
+ chip.dataset["trigger"] = item.trigger ?? source.trigger;
12517
+ chip.contentEditable = "false";
12518
+ chip.className = "mx-0.5 inline-flex items-center gap-1 rounded-md bg-muted px-1.5 py-0.5 align-middle text-xs text-foreground";
12519
+ const iconMarkup = (0, import_server.renderToStaticMarkup)(
12520
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(Icon, { name: chipIcon(item, source), size: 12 })
12521
+ );
12522
+ const label = document.createElement("span");
12523
+ label.textContent = item.label;
12524
+ chip.innerHTML = iconMarkup;
12525
+ chip.appendChild(label);
12526
+ return chip;
12527
+ };
12528
+ const insertChipElement = (item, source, replace) => {
12529
+ const field = fieldRef.current;
12530
+ if (!field) {
12531
+ return;
12532
+ }
12533
+ const chip = buildChipElement(item, source);
12534
+ let caretNode;
12535
+ if (replace) {
12536
+ const { node, start, end } = replace;
12537
+ const text = node.textContent ?? "";
12538
+ node.textContent = text.slice(0, start);
12539
+ caretNode = document.createTextNode(`${NBSP}${text.slice(end)}`);
12540
+ node.after(chip, caretNode);
12541
+ } else {
12542
+ caretNode = document.createTextNode(NBSP);
12543
+ const selection2 = window.getSelection();
12544
+ if (selection2 && selection2.rangeCount > 0 && selection2.anchorNode !== null && field.contains(selection2.anchorNode)) {
12545
+ const range = selection2.getRangeAt(0);
12546
+ range.deleteContents();
12547
+ range.insertNode(caretNode);
12548
+ range.insertNode(chip);
12549
+ } else {
12550
+ field.append(chip, caretNode);
12551
+ }
12552
+ }
12553
+ const selection = window.getSelection();
12554
+ if (selection) {
12555
+ const range = document.createRange();
12556
+ range.setStart(caretNode, 1);
12557
+ range.collapse(true);
12558
+ selection.removeAllRanges();
12559
+ selection.addRange(range);
12560
+ }
12561
+ setEmpty(false);
12562
+ onChange?.(serialize());
12563
+ emitChips();
12564
+ };
12565
+ (0, import_react63.useImperativeHandle)(ref, () => ({
12566
+ insertChip: (item, source) => {
12567
+ fieldRef.current?.focus();
12568
+ insertChipElement(item, source);
12569
+ },
12570
+ focus: () => fieldRef.current?.focus()
12571
+ }));
12572
+ (0, import_react63.useEffect)(() => {
12573
+ const field = fieldRef.current;
12574
+ if (field && value === "" && serializeNode(field).trim() !== "") {
12575
+ suppressSyncRef.current = true;
12576
+ field.innerHTML = "";
12577
+ setEmpty(true);
12578
+ setMenu(null);
12579
+ suppressSyncRef.current = false;
12580
+ }
12581
+ }, [value]);
12582
+ (0, import_react63.useEffect)(() => {
12583
+ const field = fieldRef.current;
12584
+ if (!field) {
12585
+ return;
12586
+ }
12587
+ const keep = new Set(chips.map((chip) => `${chip.trigger}:${chip.id}`));
12588
+ const stale = Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).filter(
12589
+ (el) => !keep.has(
12590
+ `${el.dataset["trigger"]}:${el.dataset["id"]}`
12591
+ )
12592
+ );
12593
+ if (stale.length > 0) {
12594
+ suppressSyncRef.current = true;
12595
+ stale.forEach((el) => el.remove());
12596
+ suppressSyncRef.current = false;
12597
+ setEmpty(serializeNode(field).trim() === "");
12598
+ }
12599
+ }, [chips]);
12600
+ const closeMenu = () => setMenu(null);
12601
+ const filteredItems = (state) => state.query ? state.source.items.filter((item) => item.label.includes(state.query)) : state.source.items;
12602
+ const refreshMenu = () => {
12603
+ const field = fieldRef.current;
12604
+ if (!field) {
12605
+ return;
12606
+ }
12607
+ const active = detectActiveMention(field, sources);
12608
+ if (!active) {
12609
+ setMenu(null);
12610
+ return;
12611
+ }
12612
+ const range = document.createRange();
12613
+ range.setStart(active.node, active.triggerStart);
12614
+ range.setEnd(active.node, active.caretOffset);
12615
+ const rect = typeof range.getBoundingClientRect === "function" ? range.getBoundingClientRect() : field.getBoundingClientRect();
12616
+ setMenu((prev) => ({
12617
+ source: active.source,
12618
+ query: active.query,
12619
+ left: rect.left,
12620
+ top: rect.top,
12621
+ // 过滤结果变化后候选下标钳制在有效范围内(DSL 每次渲染产出新
12622
+ // props 对象,source 按 trigger 比较而非引用)
12623
+ activeIndex: Math.min(
12624
+ prev?.source.trigger === active.source.trigger ? prev.activeIndex : 0,
12625
+ Math.max(filteredItems({ source: active.source, query: active.query, left: 0, top: 0, activeIndex: 0 }).length - 1, 0)
12626
+ )
12627
+ }));
12628
+ };
12629
+ const selectMenuItem = (item) => {
12630
+ const field = fieldRef.current;
12631
+ if (!field || !menu) {
12632
+ return;
12633
+ }
12634
+ const active = detectActiveMention(field, sources);
12635
+ insertChipElement(
12636
+ { ...item, trigger: item.trigger ?? menu.source.trigger },
12637
+ menu.source,
12638
+ active && active.source.trigger === menu.source.trigger ? { node: active.node, start: active.triggerStart, end: active.caretOffset } : void 0
12639
+ );
12640
+ setMenu(null);
12641
+ };
12642
+ const handleInput = () => {
12643
+ const field = fieldRef.current;
12644
+ if (!field) {
12645
+ return;
12646
+ }
12647
+ if ((field.textContent ?? "") === "" && field.querySelector(`[${CHIP_ATTR}]`) === null) {
12648
+ field.innerHTML = "";
12649
+ }
12650
+ setEmpty(serializeNode(field).trim() === "");
12651
+ onChange?.(serialize());
12652
+ refreshMenu();
12653
+ };
12654
+ const handleKeyDown = (event) => {
12655
+ if (menu) {
12656
+ const items = filteredItems(menu);
12657
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
12658
+ event.preventDefault();
12659
+ if (items.length > 0) {
12660
+ const delta = event.key === "ArrowDown" ? 1 : -1;
12661
+ setMenu({
12662
+ ...menu,
12663
+ activeIndex: (menu.activeIndex + delta + items.length) % items.length
12664
+ });
12665
+ }
12666
+ return;
12667
+ }
12668
+ if (event.key === "Enter" && !composingRef.current && !event.nativeEvent.isComposing) {
12669
+ event.preventDefault();
12670
+ const item = items[Math.min(menu.activeIndex, items.length - 1)];
12671
+ if (item) {
12672
+ selectMenuItem(item);
12673
+ } else {
12674
+ closeMenu();
12675
+ }
12676
+ return;
12677
+ }
12678
+ if (event.key === "Escape") {
12679
+ event.preventDefault();
12680
+ closeMenu();
12681
+ return;
12682
+ }
12683
+ }
12684
+ if (event.key === "Enter" && !event.shiftKey && !composingRef.current && !event.nativeEvent.isComposing) {
12685
+ event.preventDefault();
12686
+ const text = serialize();
12687
+ if (text.trim() !== "" && !disabled) {
12688
+ onSubmit?.(text);
12689
+ }
12690
+ return;
12691
+ }
12692
+ if (event.key === "Backspace") {
12693
+ const selection = window.getSelection();
12694
+ const field = fieldRef.current;
12695
+ if (!selection || !selection.isCollapsed || !field) {
12696
+ return;
12697
+ }
12698
+ let chip = null;
12699
+ const anchor = selection.anchorNode;
12700
+ if (anchor === field && selection.anchorOffset > 0) {
12701
+ const before = field.childNodes[selection.anchorOffset - 1];
12702
+ if (isChipElement(before)) {
12703
+ chip = before;
12704
+ }
12705
+ } else if (anchor?.nodeType === Node.TEXT_NODE && selection.anchorOffset === 0) {
12706
+ if (isChipElement(anchor.previousSibling)) {
12707
+ chip = anchor.previousSibling;
12708
+ }
12709
+ }
12710
+ if (chip) {
12711
+ event.preventDefault();
12712
+ chip.remove();
12713
+ onChange?.(serialize());
12714
+ emitChips();
12715
+ setEmpty(serializeNode(field).trim() === "");
12716
+ }
12717
+ }
12718
+ };
12719
+ const menuItems = menu ? filteredItems(menu) : [];
12720
+ const activeIndex = Math.min(menu?.activeIndex ?? 0, Math.max(menuItems.length - 1, 0));
12721
+ return /* @__PURE__ */ (0, import_jsx_runtime179.jsxs)("div", { className: "relative", children: [
12722
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(
12723
+ "div",
12724
+ {
12725
+ ref: fieldRef,
12726
+ "data-slot": "mention-input",
12727
+ role: "textbox",
12728
+ "aria-multiline": "true",
12729
+ "aria-placeholder": placeholder,
12730
+ contentEditable: !disabled,
12731
+ suppressContentEditableWarning: true,
12732
+ className: cn(
12733
+ "min-h-[60px] w-full px-4 pt-3 pb-1 text-sm whitespace-pre-wrap break-words outline-none",
12734
+ className
12735
+ ),
12736
+ style,
12737
+ onInput: handleInput,
12738
+ onKeyDown: handleKeyDown,
12739
+ onCompositionStart: () => {
12740
+ composingRef.current = true;
12741
+ },
12742
+ onCompositionEnd: () => {
12743
+ composingRef.current = false;
12744
+ },
12745
+ onPaste: (event) => {
12746
+ event.preventDefault();
12747
+ const text = event.clipboardData?.getData("text/plain") ?? "";
12748
+ if (text) {
12749
+ document.execCommand("insertText", false, text);
12750
+ }
12751
+ }
12752
+ }
12753
+ ),
12754
+ empty && placeholder !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime179.jsx)("span", { className: "pointer-events-none absolute top-3 left-4 text-sm text-muted-foreground", children: placeholder }) : null,
12755
+ menu ? /* @__PURE__ */ (0, import_jsx_runtime179.jsxs)(import_jsx_runtime179.Fragment, { children: [
12756
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(
12757
+ "div",
12758
+ {
12759
+ className: "fixed inset-0 z-40",
12760
+ onMouseDown: (event) => {
12761
+ event.preventDefault();
12762
+ closeMenu();
12763
+ }
12764
+ }
12765
+ ),
12766
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsxs)(
12767
+ "div",
12768
+ {
12769
+ "data-slot": "mention-menu",
12770
+ role: "listbox",
12771
+ className: "scrollbar-subtle fixed z-50 max-h-72 w-64 overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
12772
+ style: {
12773
+ left: menu.left,
12774
+ bottom: typeof window === "undefined" ? void 0 : window.innerHeight - menu.top + 6
12775
+ },
12776
+ children: [
12777
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: menu.source.label }),
12778
+ menuItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime179.jsx)("div", { className: "px-2 py-2 text-xs text-muted-foreground", children: "\u65E0\u5339\u914D\u9879" }) : menuItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime179.jsxs)(
12779
+ "button",
12780
+ {
12781
+ type: "button",
12782
+ role: "option",
12783
+ "aria-selected": index === activeIndex,
12784
+ className: cn(
12785
+ "flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm",
12786
+ index === activeIndex ? "bg-accent" : "hover:bg-accent"
12787
+ ),
12788
+ onMouseDown: (event) => {
12789
+ event.preventDefault();
12790
+ selectMenuItem(item);
12791
+ },
12792
+ children: [
12793
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(Icon, { name: chipIcon(item, menu.source), size: "sm" }),
12794
+ /* @__PURE__ */ (0, import_jsx_runtime179.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.label })
12795
+ ]
12796
+ },
12797
+ item.id
12798
+ ))
12799
+ ]
12800
+ }
12801
+ )
12802
+ ] }) : null
12803
+ ] });
12804
+ }
12805
+ );
12806
+
12807
+ // src/components/chat/Composer/index.tsx
12808
+ var import_jsx_runtime180 = require("react/jsx-runtime");
12809
+ var toolButtonClass3 = "flex cursor-pointer items-center rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground";
12810
+ var popoverPanelClass = "absolute bottom-full left-0 z-50 mb-2 max-h-72 w-64 overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md";
12811
+ var popoverItemClass = "flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent";
12325
12812
  function Composer({
12326
12813
  value,
12327
12814
  placeholder,
@@ -12331,35 +12818,238 @@ function Composer({
12331
12818
  attachments = [],
12332
12819
  onRemoveAttachment,
12333
12820
  onRetryAttachment,
12821
+ onAttachFiles,
12334
12822
  onChange,
12335
12823
  onSubmit,
12824
+ models,
12825
+ model,
12826
+ onModelChange,
12827
+ contexts,
12828
+ contextItems,
12829
+ onContextItemsChange,
12830
+ footer,
12336
12831
  className,
12337
12832
  style
12338
12833
  }) {
12339
- return /* @__PURE__ */ (0, import_jsx_runtime179.jsxs)("div", { "data-slot": "composer", className: cn("flex w-full flex-col gap-2", className), style, children: [
12340
- attachments.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(Attachment, { items: attachments, onRemove: onRemoveAttachment, onRetry: onRetryAttachment }) : null,
12341
- /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(
12342
- ChatInput,
12834
+ const textControlled = value !== void 0;
12835
+ const [innerText, setInnerText] = (0, import_react64.useState)("");
12836
+ const text = textControlled ? value : innerText;
12837
+ const [dragOver, setDragOver] = (0, import_react64.useState)(false);
12838
+ const [plusOpen, setPlusOpen] = (0, import_react64.useState)(false);
12839
+ const [modelOpen, setModelOpen] = (0, import_react64.useState)(false);
12840
+ const fileInputRef = (0, import_react64.useRef)(null);
12841
+ const mentionRef = (0, import_react64.useRef)(null);
12842
+ const sources = contexts ?? [];
12843
+ const rich = sources.length > 0;
12844
+ const plusSources = sources.filter((s) => s.trigger === "+");
12845
+ const plusEnabled = plusSources.length > 0;
12846
+ const modelEnabled = models !== void 0 && models.length > 0;
12847
+ const currentModel = models?.find((m) => m.value === model) ?? models?.[0];
12848
+ const chips = contextItems ?? [];
12849
+ const closePopovers = () => {
12850
+ setPlusOpen(false);
12851
+ setModelOpen(false);
12852
+ };
12853
+ const handleChange = (next) => {
12854
+ if (!textControlled) {
12855
+ setInnerText(next);
12856
+ }
12857
+ onChange?.(next);
12858
+ };
12859
+ const handleSubmit = (submitted) => {
12860
+ onSubmit?.(submitted);
12861
+ if (!textControlled) {
12862
+ setInnerText("");
12863
+ }
12864
+ closePopovers();
12865
+ };
12866
+ const selectContext = (item, source) => {
12867
+ if (rich) {
12868
+ mentionRef.current?.insertChip(item, source);
12869
+ } else {
12870
+ const chip = { ...item, trigger: item.trigger ?? source.trigger };
12871
+ const duplicated = chips.some(
12872
+ (existing) => existing.id === chip.id && existing.trigger === chip.trigger
12873
+ );
12874
+ if (!duplicated) {
12875
+ onContextItemsChange?.([...chips, chip]);
12876
+ }
12877
+ }
12878
+ closePopovers();
12879
+ };
12880
+ const emitFiles = (files) => {
12881
+ if (files.length > 0 && onAttachFiles) {
12882
+ onAttachFiles(files);
12883
+ }
12884
+ };
12885
+ const handleDrop = (event) => {
12886
+ if (!onAttachFiles) {
12887
+ return;
12888
+ }
12889
+ event.preventDefault();
12890
+ setDragOver(false);
12891
+ emitFiles(Array.from(event.dataTransfer?.files ?? []));
12892
+ };
12893
+ const toolbarStart = plusEnabled || onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(import_jsx_runtime180.Fragment, { children: [
12894
+ plusEnabled ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
12895
+ "button",
12896
+ {
12897
+ type: "button",
12898
+ "aria-label": "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
12899
+ title: "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
12900
+ className: toolButtonClass3,
12901
+ onClick: () => {
12902
+ setPlusOpen((prev) => !prev);
12903
+ setModelOpen(false);
12904
+ },
12905
+ children: /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "plus", size: "sm" })
12906
+ }
12907
+ ) : null,
12908
+ onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
12909
+ "button",
12343
12910
  {
12344
- value,
12345
- placeholder,
12346
- disabled: disabled || loading,
12347
- rows,
12348
- onChange,
12349
- onSubmit
12911
+ type: "button",
12912
+ "aria-label": "\u6DFB\u52A0\u9644\u4EF6",
12913
+ title: "\u6DFB\u52A0\u9644\u4EF6",
12914
+ className: toolButtonClass3,
12915
+ onClick: () => fileInputRef.current?.click(),
12916
+ children: /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "paperclip", size: "sm" })
12350
12917
  }
12351
- )
12352
- ] });
12918
+ ) : null
12919
+ ] }) : void 0;
12920
+ const toolbarEnd = modelEnabled ? /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
12921
+ "button",
12922
+ {
12923
+ type: "button",
12924
+ "aria-label": "\u9009\u62E9\u6A21\u578B",
12925
+ title: "\u9009\u62E9\u6A21\u578B",
12926
+ className: "flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
12927
+ onClick: () => {
12928
+ setModelOpen((prev) => !prev);
12929
+ setPlusOpen(false);
12930
+ },
12931
+ children: [
12932
+ currentModel?.label,
12933
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "chevrons-up-down", size: 12 })
12934
+ ]
12935
+ }
12936
+ ) : void 0;
12937
+ const activePopover = plusOpen ? "plus" : modelOpen ? "model" : null;
12938
+ return /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
12939
+ "div",
12940
+ {
12941
+ "data-slot": "composer",
12942
+ className: cn("relative flex w-full flex-col gap-2", className),
12943
+ style,
12944
+ onDragOver: (event) => {
12945
+ if (onAttachFiles) {
12946
+ event.preventDefault();
12947
+ setDragOver(true);
12948
+ }
12949
+ },
12950
+ onDragLeave: () => setDragOver(false),
12951
+ onDrop: handleDrop,
12952
+ onPaste: (event) => {
12953
+ const files = Array.from(event.clipboardData?.files ?? []);
12954
+ if (files.length > 0 && onAttachFiles) {
12955
+ event.preventDefault();
12956
+ emitFiles(files);
12957
+ }
12958
+ },
12959
+ children: [
12960
+ attachments.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Attachment, { items: attachments, onRemove: onRemoveAttachment, onRetry: onRetryAttachment }) : null,
12961
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: cn(dragOver && "rounded-xl ring-2 ring-ring/50"), children: /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
12962
+ ChatInput,
12963
+ {
12964
+ value: text,
12965
+ placeholder,
12966
+ disabled: disabled || loading,
12967
+ rows,
12968
+ toolbarStart,
12969
+ toolbarEnd,
12970
+ footer,
12971
+ field: rich ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
12972
+ MentionInput,
12973
+ {
12974
+ ref: mentionRef,
12975
+ value: text,
12976
+ placeholder,
12977
+ disabled: disabled || loading,
12978
+ sources,
12979
+ chips,
12980
+ onChipsChange: onContextItemsChange,
12981
+ onChange: handleChange,
12982
+ onSubmit: handleSubmit
12983
+ }
12984
+ ) : void 0,
12985
+ onChange: handleChange,
12986
+ onSubmit: handleSubmit
12987
+ }
12988
+ ) }),
12989
+ onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
12990
+ "input",
12991
+ {
12992
+ ref: fileInputRef,
12993
+ type: "file",
12994
+ multiple: true,
12995
+ hidden: true,
12996
+ onChange: (event) => {
12997
+ emitFiles(Array.from(event.target.files ?? []));
12998
+ event.target.value = "";
12999
+ }
13000
+ }
13001
+ ) : null,
13002
+ activePopover !== null ? /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(import_jsx_runtime180.Fragment, { children: [
13003
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: "fixed inset-0 z-40", onClick: closePopovers }),
13004
+ activePopover === "model" ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { "data-slot": "composer-model-popover", className: cn(popoverPanelClass, "right-0 left-auto w-48"), role: "listbox", children: models.map((option) => /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
13005
+ "button",
13006
+ {
13007
+ type: "button",
13008
+ role: "option",
13009
+ "aria-selected": option.value === currentModel?.value,
13010
+ className: popoverItemClass,
13011
+ onClick: () => {
13012
+ onModelChange?.(option.value);
13013
+ closePopovers();
13014
+ },
13015
+ children: [
13016
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
13017
+ option.value === currentModel?.value ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "check", size: 14 }) : null
13018
+ ]
13019
+ },
13020
+ option.value
13021
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { "data-slot": "composer-context-popover", className: popoverPanelClass, role: "listbox", children: plusSources.map(
13022
+ (source) => source.items.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)("div", { children: [
13023
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: source.label }),
13024
+ source.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
13025
+ "button",
13026
+ {
13027
+ type: "button",
13028
+ className: popoverItemClass,
13029
+ onClick: () => selectContext(item, source),
13030
+ children: [
13031
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: item.icon ?? source.icon ?? "file-text", size: "sm" }),
13032
+ /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.label })
13033
+ ]
13034
+ },
13035
+ item.id
13036
+ ))
13037
+ ] }, source.trigger)
13038
+ ) })
13039
+ ] }) : null
13040
+ ]
13041
+ }
13042
+ );
12353
13043
  }
12354
13044
 
12355
13045
  // src/components/chat/ConversationList/index.tsx
12356
- var import_react63 = require("react");
12357
- var import_jsx_runtime180 = require("react/jsx-runtime");
13046
+ var import_react65 = require("react");
13047
+ var import_jsx_runtime181 = require("react/jsx-runtime");
12358
13048
  function ConversationList({ items = [], activeId, searchable, onSelect, onDelete, className, style }) {
12359
- const [innerActive, setInnerActive] = (0, import_react63.useState)();
12360
- const [keyword, setKeyword] = (0, import_react63.useState)("");
13049
+ const [innerActive, setInnerActive] = (0, import_react65.useState)();
13050
+ const [keyword, setKeyword] = (0, import_react65.useState)("");
12361
13051
  const active = activeId ?? innerActive;
12362
- const filtered = (0, import_react63.useMemo)(() => {
13052
+ const filtered = (0, import_react65.useMemo)(() => {
12363
13053
  const query = keyword.trim().toLowerCase();
12364
13054
  if (!query) return items;
12365
13055
  return items.filter(
@@ -12372,10 +13062,10 @@ function ConversationList({ items = [], activeId, searchable, onSelect, onDelete
12372
13062
  }
12373
13063
  onSelect?.(id);
12374
13064
  };
12375
- return /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)("div", { "data-slot": "conversation-list", className: cn("flex w-full flex-col gap-1", className), style, children: [
12376
- searchable ? /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)("div", { className: "relative mb-1", children: [
12377
- /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { className: "absolute top-1/2 left-2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "search", size: "sm" }) }),
12378
- /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
13065
+ return /* @__PURE__ */ (0, import_jsx_runtime181.jsxs)("div", { "data-slot": "conversation-list", className: cn("flex w-full flex-col gap-1", className), style, children: [
13066
+ searchable ? /* @__PURE__ */ (0, import_jsx_runtime181.jsxs)("div", { className: "relative mb-1", children: [
13067
+ /* @__PURE__ */ (0, import_jsx_runtime181.jsx)("span", { className: "absolute top-1/2 left-2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(Icon, { name: "search", size: "sm" }) }),
13068
+ /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(
12379
13069
  "input",
12380
13070
  {
12381
13071
  "data-slot": "conversation-list-search",
@@ -12386,7 +13076,7 @@ function ConversationList({ items = [], activeId, searchable, onSelect, onDelete
12386
13076
  }
12387
13077
  )
12388
13078
  ] }) : null,
12389
- filtered.map((item) => /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
13079
+ filtered.map((item) => /* @__PURE__ */ (0, import_jsx_runtime181.jsxs)(
12390
13080
  "div",
12391
13081
  {
12392
13082
  "data-slot": "conversation-list-item",
@@ -12397,12 +13087,12 @@ function ConversationList({ items = [], activeId, searchable, onSelect, onDelete
12397
13087
  ),
12398
13088
  onClick: () => select(item.id),
12399
13089
  children: [
12400
- /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)("div", { className: "min-w-0 flex-1", children: [
12401
- /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: cn("truncate text-sm", item.id === active && "font-medium"), children: item.title }),
12402
- item.description ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: item.description }) : null
13090
+ /* @__PURE__ */ (0, import_jsx_runtime181.jsxs)("div", { className: "min-w-0 flex-1", children: [
13091
+ /* @__PURE__ */ (0, import_jsx_runtime181.jsx)("div", { className: cn("truncate text-sm", item.id === active && "font-medium"), children: item.title }),
13092
+ item.description ? /* @__PURE__ */ (0, import_jsx_runtime181.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: item.description }) : null
12403
13093
  ] }),
12404
- item.time ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.time }) : null,
12405
- onDelete ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(
13094
+ item.time ? /* @__PURE__ */ (0, import_jsx_runtime181.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.time }) : null,
13095
+ onDelete ? /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(
12406
13096
  "button",
12407
13097
  {
12408
13098
  type: "button",
@@ -12413,41 +13103,42 @@ function ConversationList({ items = [], activeId, searchable, onSelect, onDelete
12413
13103
  event.stopPropagation();
12414
13104
  onDelete(item.id);
12415
13105
  },
12416
- children: /* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Icon, { name: "trash-2", size: "sm" })
13106
+ children: /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(Icon, { name: "trash-2", size: "sm" })
12417
13107
  }
12418
13108
  ) : null
12419
13109
  ]
12420
13110
  },
12421
13111
  item.id
12422
13112
  )),
12423
- filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("div", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: "\u65E0\u5339\u914D\u4F1A\u8BDD" }) : null
13113
+ filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime181.jsx)("div", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: "\u65E0\u5339\u914D\u4F1A\u8BDD" }) : null
12424
13114
  ] });
12425
13115
  }
12426
13116
 
12427
13117
  // src/components/chat/MessageList/index.tsx
12428
- var import_react64 = require("react");
12429
- var import_jsx_runtime181 = require("react/jsx-runtime");
12430
- function MessageList({ messages = [], autoScroll = true, onAction, className, style }) {
12431
- const listRef = (0, import_react64.useRef)(null);
12432
- (0, import_react64.useEffect)(() => {
13118
+ var import_react66 = require("react");
13119
+ var import_jsx_runtime182 = require("react/jsx-runtime");
13120
+ function MessageList({ messages = [], autoScroll = true, onAction, onOpenArtifacts, className, style }) {
13121
+ const listRef = (0, import_react66.useRef)(null);
13122
+ (0, import_react66.useEffect)(() => {
12433
13123
  if (!autoScroll) return;
12434
13124
  const el = listRef.current;
12435
13125
  if (el) {
12436
13126
  el.scrollTop = el.scrollHeight;
12437
13127
  }
12438
13128
  }, [messages, autoScroll]);
12439
- return /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(
13129
+ return /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(
12440
13130
  "div",
12441
13131
  {
12442
13132
  ref: listRef,
12443
13133
  "data-slot": "message-list",
12444
13134
  className: cn("flex w-full flex-col gap-4 overflow-y-auto", className),
12445
13135
  style,
12446
- children: messages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(
13136
+ children: messages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(
12447
13137
  ChatMessage,
12448
13138
  {
12449
13139
  ...message,
12450
- onAction: (action) => onAction?.({ id: message.id, action })
13140
+ onAction: (action) => onAction?.({ id: message.id, action }),
13141
+ onOpenArtifacts: onOpenArtifacts ? () => onOpenArtifacts({ id: message.id }) : void 0
12451
13142
  },
12452
13143
  message.id ?? index
12453
13144
  ))
@@ -12456,9 +13147,9 @@ function MessageList({ messages = [], autoScroll = true, onAction, className, st
12456
13147
  }
12457
13148
 
12458
13149
  // src/components/chat/Prompt/index.tsx
12459
- var import_jsx_runtime182 = require("react/jsx-runtime");
13150
+ var import_jsx_runtime183 = require("react/jsx-runtime");
12460
13151
  function Prompt({ title, description, icon, value, disabled, onSelect, className, style }) {
12461
- return /* @__PURE__ */ (0, import_jsx_runtime182.jsxs)(
13152
+ return /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)(
12462
13153
  "button",
12463
13154
  {
12464
13155
  type: "button",
@@ -12471,10 +13162,10 @@ function Prompt({ title, description, icon, value, disabled, onSelect, className
12471
13162
  style,
12472
13163
  onClick: () => onSelect?.(value ?? title ?? ""),
12473
13164
  children: [
12474
- icon ? /* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { className: "mt-0.5 shrink-0 text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(Icon, { name: icon, size: "sm" }) }) : null,
12475
- /* @__PURE__ */ (0, import_jsx_runtime182.jsxs)("span", { className: "min-w-0", children: [
12476
- /* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { "data-slot": "prompt-title", className: "block text-sm font-medium", children: title }),
12477
- description ? /* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { "data-slot": "prompt-description", className: "mt-0.5 block text-xs text-muted-foreground", children: description }) : null
13165
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { className: "mt-0.5 shrink-0 text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(Icon, { name: icon, size: "sm" }) }) : null,
13166
+ /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("span", { className: "min-w-0", children: [
13167
+ /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { "data-slot": "prompt-title", className: "block text-sm font-medium", children: title }),
13168
+ description ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { "data-slot": "prompt-description", className: "mt-0.5 block text-xs text-muted-foreground", children: description }) : null
12478
13169
  ] })
12479
13170
  ]
12480
13171
  }
@@ -12482,7 +13173,7 @@ function Prompt({ title, description, icon, value, disabled, onSelect, className
12482
13173
  }
12483
13174
 
12484
13175
  // src/components/chat/Welcome/index.tsx
12485
- var import_jsx_runtime183 = require("react/jsx-runtime");
13176
+ var import_jsx_runtime184 = require("react/jsx-runtime");
12486
13177
  function Welcome({
12487
13178
  title = "\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u4F60\uFF1F",
12488
13179
  description,
@@ -12492,19 +13183,19 @@ function Welcome({
12492
13183
  className,
12493
13184
  style
12494
13185
  }) {
12495
- return /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)(
13186
+ return /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
12496
13187
  "div",
12497
13188
  {
12498
13189
  "data-slot": "welcome",
12499
13190
  className: cn("flex w-full flex-col items-center gap-4 py-10 text-center", className),
12500
13191
  style,
12501
13192
  children: [
12502
- /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { "data-slot": "welcome-icon", className: "text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(Icon, { name: icon, size: "lg" }) }),
12503
- /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("div", { children: [
12504
- /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("div", { "data-slot": "welcome-title", className: "text-xl font-semibold", children: title }),
12505
- description ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("div", { "data-slot": "welcome-description", className: "mt-1 text-sm text-muted-foreground", children: description }) : null
13193
+ /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("span", { "data-slot": "welcome-icon", className: "text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: icon, size: "lg" }) }),
13194
+ /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { children: [
13195
+ /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { "data-slot": "welcome-title", className: "text-xl font-semibold", children: title }),
13196
+ description ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { "data-slot": "welcome-description", className: "mt-1 text-sm text-muted-foreground", children: description }) : null
12506
13197
  ] }),
12507
- prompts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("div", { "data-slot": "welcome-prompts", className: "grid w-full max-w-xl grid-cols-1 gap-3 text-left sm:grid-cols-2", children: prompts.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(
13198
+ prompts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { "data-slot": "welcome-prompts", className: "grid w-full max-w-xl grid-cols-1 gap-3 text-left sm:grid-cols-2", children: prompts.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
12508
13199
  Prompt,
12509
13200
  {
12510
13201
  title: item.title,
@@ -12521,7 +13212,7 @@ function Welcome({
12521
13212
  }
12522
13213
 
12523
13214
  // src/components/chat/ChatPage/index.tsx
12524
- var import_jsx_runtime184 = require("react/jsx-runtime");
13215
+ var import_jsx_runtime185 = require("react/jsx-runtime");
12525
13216
  function ChatPage({
12526
13217
  brand,
12527
13218
  menuItems = [],
@@ -12547,12 +13238,26 @@ function ChatPage({
12547
13238
  defaultFooterSectionCollapsed = false,
12548
13239
  onFooterSectionToggle,
12549
13240
  conversationTitle,
13241
+ conversationHeaderAction,
13242
+ onConversationHeaderAction,
12550
13243
  messages = [],
12551
13244
  sending,
12552
13245
  composerPlaceholder,
12553
13246
  welcome,
12554
13247
  onSend,
12555
13248
  onMessageAction,
13249
+ models,
13250
+ model,
13251
+ onModelChange,
13252
+ contexts,
13253
+ contextItems,
13254
+ onContextItemsChange,
13255
+ attachments,
13256
+ onAttachFiles,
13257
+ onRemoveAttachment,
13258
+ onRetryAttachment,
13259
+ composerFooter,
13260
+ composerBottom,
12556
13261
  artifactTitle = "\u4EA7\u7269",
12557
13262
  artifacts = [],
12558
13263
  activeArtifactId,
@@ -12563,20 +13268,22 @@ function ChatPage({
12563
13268
  artifactViewers,
12564
13269
  onDownloadArtifact,
12565
13270
  artifactOpen,
12566
- defaultArtifactOpen = true,
13271
+ defaultArtifactOpen = false,
12567
13272
  onArtifactOpenChange,
12568
13273
  className,
12569
13274
  style
12570
13275
  }) {
12571
13276
  const controlled = artifactOpen !== void 0;
12572
- const [innerOpen, setInnerOpen] = (0, import_react65.useState)(defaultArtifactOpen);
13277
+ const [innerOpen, setInnerOpen] = (0, import_react67.useState)(defaultArtifactOpen);
12573
13278
  const open = controlled ? artifactOpen === true : innerOpen;
12574
13279
  const setOpen = (next) => {
12575
13280
  if (!controlled) setInnerOpen(next);
12576
13281
  onArtifactOpenChange?.(next);
12577
13282
  };
13283
+ const { renderChildren } = (0, import_runtime26.useRenderer)();
13284
+ const renderSlot = (slot) => (0, import_react67.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
12578
13285
  const convCollControlled = conversationSectionCollapsed !== void 0;
12579
- const [convCollapsedInner, setConvCollapsedInner] = (0, import_react65.useState)(
13286
+ const [convCollapsedInner, setConvCollapsedInner] = (0, import_react67.useState)(
12580
13287
  defaultConversationSectionCollapsed
12581
13288
  );
12582
13289
  const convCollapsed = convCollControlled ? conversationSectionCollapsed === true : convCollapsedInner;
@@ -12586,7 +13293,7 @@ function ChatPage({
12586
13293
  onConversationSectionToggle?.(next);
12587
13294
  };
12588
13295
  const footerCollControlled = footerSectionCollapsed !== void 0;
12589
- const [footerCollapsedInner, setFooterCollapsedInner] = (0, import_react65.useState)(
13296
+ const [footerCollapsedInner, setFooterCollapsedInner] = (0, import_react67.useState)(
12590
13297
  defaultFooterSectionCollapsed
12591
13298
  );
12592
13299
  const footerCollapsed = footerCollControlled ? footerSectionCollapsed === true : footerCollapsedInner;
@@ -12596,7 +13303,7 @@ function ChatPage({
12596
13303
  onFooterSectionToggle?.(next);
12597
13304
  };
12598
13305
  const railVisible = railItems.length > 0 || railFooterItems.length > 0;
12599
- const railButton = (item) => /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Tooltip2, { content: item.label, side: "right", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13306
+ const railButton = (item) => /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Tooltip2, { content: item.label, side: "right", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12600
13307
  Button2,
12601
13308
  {
12602
13309
  icon: item.icon,
@@ -12604,17 +13311,25 @@ function ChatPage({
12604
13311
  onClick: () => onMenuSelect?.(item.key)
12605
13312
  }
12606
13313
  ) }, item.key);
12607
- const chatArea = /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { "data-slot": "chat-page-conversation", className: "flex h-full min-w-0 flex-1 flex-col", children: [
12608
- /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13314
+ const chatArea = /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)("div", { "data-slot": "chat-page-conversation", className: "flex h-full min-w-0 flex-1 flex-col", children: [
13315
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12609
13316
  "div",
12610
13317
  {
12611
13318
  className: "flex shrink-0 items-center justify-between border-b border-border px-4 py-2.5",
12612
13319
  children: [
12613
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Text, { text: conversationTitle, strong: true }),
12614
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Tooltip2, { content: artifactTitle, side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13320
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Text, { text: conversationTitle, strong: true }),
13321
+ conversationHeaderAction ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Tooltip2, { content: conversationHeaderAction.tooltip ?? conversationHeaderAction.label, side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13322
+ Button2,
13323
+ {
13324
+ text: conversationHeaderAction.label,
13325
+ icon: conversationHeaderAction.icon,
13326
+ variant: "text",
13327
+ onClick: () => onConversationHeaderAction?.()
13328
+ }
13329
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Tooltip2, { content: open ? "\u6536\u8D77\u4EA7\u7269\u533A" : artifactTitle, side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12615
13330
  Button2,
12616
13331
  {
12617
- icon: "panel-right-open",
13332
+ icon: open ? "panel-right-close" : "panel-right-open",
12618
13333
  variant: "text",
12619
13334
  onClick: () => setOpen(!open)
12620
13335
  }
@@ -12622,40 +13337,63 @@ function ChatPage({
12622
13337
  ]
12623
13338
  }
12624
13339
  ),
12625
- messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
12626
- Welcome,
12627
- {
12628
- title: welcome?.title,
12629
- description: welcome?.description,
12630
- prompts: welcome?.prompts,
12631
- style: { flex: 1 },
12632
- onSelect: (value) => onSend?.(value)
12633
- }
12634
- ) : /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
12635
- MessageList,
12636
- {
12637
- messages,
12638
- style: { flex: 1, minHeight: 0, padding: 16 },
12639
- onAction: onMessageAction
12640
- }
12641
- ),
12642
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
12643
- Composer,
13340
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
13341
+ "div",
12644
13342
  {
12645
- placeholder: composerPlaceholder,
12646
- loading: sending,
12647
- style: { padding: 16, borderTop: "1px solid var(--border)", flexShrink: 0 },
12648
- onSubmit: (text) => onSend?.(text)
13343
+ "data-slot": "chat-page-conversation-body",
13344
+ className: "mx-auto flex min-h-0 w-[61.8cqw] max-w-full flex-1 flex-col",
13345
+ children: [
13346
+ messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13347
+ Welcome,
13348
+ {
13349
+ title: welcome?.title,
13350
+ description: welcome?.description,
13351
+ prompts: welcome?.prompts,
13352
+ style: { flex: 1 },
13353
+ onSelect: (value) => onSend?.(value)
13354
+ }
13355
+ ) : /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13356
+ MessageList,
13357
+ {
13358
+ messages,
13359
+ className: "scrollbar-subtle",
13360
+ style: { flex: 1, minHeight: 0, padding: 16 },
13361
+ onAction: onMessageAction,
13362
+ onOpenArtifacts: () => setOpen(true)
13363
+ }
13364
+ ),
13365
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13366
+ Composer,
13367
+ {
13368
+ placeholder: composerPlaceholder,
13369
+ loading: sending,
13370
+ models,
13371
+ model,
13372
+ contexts,
13373
+ contextItems,
13374
+ attachments,
13375
+ footer: composerFooter,
13376
+ style: { padding: 16, paddingBottom: composerBottom ? 8 : 16, flexShrink: 0 },
13377
+ onModelChange,
13378
+ onContextItemsChange,
13379
+ onAttachFiles,
13380
+ onRemoveAttachment,
13381
+ onRetryAttachment,
13382
+ onSubmit: (text) => onSend?.(text)
13383
+ }
13384
+ ),
13385
+ composerBottom ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { "data-slot": "chat-page-composer-bottom", className: "shrink-0 px-4 pb-2 text-center", children: renderSlot(composerBottom) }) : null
13386
+ ]
12649
13387
  }
12650
13388
  )
12651
13389
  ] });
12652
13390
  const activeArtifact = artifacts.find((item) => item.id === activeArtifactId) ?? (activeArtifactId === void 0 || activeArtifactId === "" ? artifacts[artifacts.length - 1] : void 0);
12653
- const artifactPanel = /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13391
+ const artifactPanel = /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12654
13392
  "div",
12655
13393
  {
12656
13394
  "data-slot": "chat-page-artifact",
12657
13395
  className: "flex h-full min-w-0 flex-col border-l border-border bg-muted",
12658
- children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13396
+ children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12659
13397
  ArtifactPanel,
12660
13398
  {
12661
13399
  artifact: activeArtifact,
@@ -12673,37 +13411,37 @@ function ChatPage({
12673
13411
  )
12674
13412
  }
12675
13413
  );
12676
- return /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13414
+ return /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12677
13415
  "div",
12678
13416
  {
12679
13417
  "data-slot": "chat-page",
12680
13418
  className: cn("flex w-full overflow-hidden", className),
12681
13419
  style: { height: "100vh", ...style },
12682
13420
  children: [
12683
- railVisible ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13421
+ railVisible ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12684
13422
  "div",
12685
13423
  {
12686
13424
  "data-slot": "chat-page-rail",
12687
13425
  className: "flex h-full w-[52px] shrink-0 flex-col items-center gap-1 border-r border-border py-2.5",
12688
13426
  children: [
12689
13427
  railItems.map(railButton),
12690
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { className: "flex-1" }),
13428
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "flex-1" }),
12691
13429
  railFooterItems.map(railButton)
12692
13430
  ]
12693
13431
  }
12694
13432
  ) : null,
12695
- /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13433
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12696
13434
  "div",
12697
13435
  {
12698
13436
  "data-slot": "chat-page-menu",
12699
- className: "flex h-full w-[264px] shrink-0 flex-col gap-2 overflow-auto border-r border-border px-2 py-3",
13437
+ className: "flex h-full w-[264px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
12700
13438
  children: [
12701
- brand ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { className: "flex items-center justify-between px-2", children: [
12702
- /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
12703
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Text, { text: brand.title, strong: true, size: "large" }),
12704
- brand.version !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Text, { text: brand.version, type: "secondary", size: "small" }) : null
13439
+ brand ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)("div", { className: "flex shrink-0 items-center justify-between px-2", children: [
13440
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
13441
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Text, { text: brand.title, strong: true, size: "large" }),
13442
+ brand.version !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Text, { text: brand.version, type: "secondary", size: "small" }) : null
12705
13443
  ] }),
12706
- menuAction ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13444
+ menuAction ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12707
13445
  Button2,
12708
13446
  {
12709
13447
  text: menuAction.label,
@@ -12713,24 +13451,24 @@ function ChatPage({
12713
13451
  }
12714
13452
  ) : null
12715
13453
  ] }) : null,
12716
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13454
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "scrollbar-subtle max-h-[40%] min-h-0 shrink-0 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12717
13455
  Menu2,
12718
13456
  {
12719
13457
  items: menuItems,
12720
13458
  selectedKey: activeMenuKey,
12721
13459
  onSelect: (key) => onMenuSelect?.(key)
12722
13460
  }
12723
- ),
12724
- conversationSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13461
+ ) }),
13462
+ conversationSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12725
13463
  "button",
12726
13464
  {
12727
13465
  type: "button",
12728
13466
  "data-slot": "chat-page-section-toggle",
12729
13467
  "aria-expanded": !convCollapsed,
12730
- className: "flex w-full cursor-pointer items-center justify-between px-2 pt-2",
13468
+ className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
12731
13469
  onClick: toggleConvSection,
12732
13470
  children: [
12733
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13471
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12734
13472
  Text,
12735
13473
  {
12736
13474
  text: `${conversationSectionTitle} (${conversations.length})`,
@@ -12739,48 +13477,50 @@ function ChatPage({
12739
13477
  strong: true
12740
13478
  }
12741
13479
  ),
12742
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: convCollapsed ? "chevron-right" : "chevron-down", size: 14 })
13480
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Icon, { name: convCollapsed ? "chevron-right" : "chevron-down", size: 14 })
12743
13481
  ]
12744
13482
  }
12745
13483
  ) : null,
12746
- !convCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
12747
- ConversationList,
12748
- {
12749
- items: conversations,
12750
- activeId: activeConversationId,
12751
- onSelect: (id) => onSelectConversation?.(id),
12752
- onDelete: (id) => onDeleteConversation?.(id)
12753
- }
12754
- ) : null,
12755
- !convCollapsed && moreLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Button2, { text: `${moreLabel} >>`, variant: "link", size: "small", onClick: () => onMore?.() }) }) : null,
12756
- footerSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
13484
+ !convCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle flex min-h-0 flex-1 flex-col overflow-y-auto", children: [
13485
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13486
+ ConversationList,
13487
+ {
13488
+ items: conversations,
13489
+ activeId: activeConversationId,
13490
+ onSelect: (id) => onSelectConversation?.(id),
13491
+ onDelete: (id) => onDeleteConversation?.(id)
13492
+ }
13493
+ ),
13494
+ moreLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Button2, { text: `${moreLabel} >>`, variant: "link", size: "small", onClick: () => onMore?.() }) }) : null
13495
+ ] }) : null,
13496
+ footerSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
12757
13497
  "button",
12758
13498
  {
12759
13499
  type: "button",
12760
13500
  "data-slot": "chat-page-section-toggle",
12761
13501
  "aria-expanded": !footerCollapsed,
12762
- className: "flex w-full cursor-pointer items-center justify-between px-2 pt-2",
13502
+ className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
12763
13503
  onClick: toggleFooterSection,
12764
13504
  children: [
12765
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Text, { text: footerSectionTitle, type: "secondary", className: "text-sm", strong: true }),
12766
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: footerCollapsed ? "chevron-right" : "chevron-down", size: 14 })
13505
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Text, { text: footerSectionTitle, type: "secondary", className: "text-sm", strong: true }),
13506
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Icon, { name: footerCollapsed ? "chevron-right" : "chevron-down", size: 14 })
12767
13507
  ]
12768
13508
  }
12769
13509
  ) : null,
12770
- !footerCollapsed && footerItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
13510
+ !footerCollapsed && footerItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
12771
13511
  Menu2,
12772
13512
  {
12773
13513
  items: footerItems,
12774
13514
  onSelect: (key) => onMenuSelect?.(key)
12775
13515
  }
12776
- ) : null
13516
+ ) }) : null
12777
13517
  ]
12778
13518
  }
12779
13519
  ),
12780
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { className: "h-full min-w-0 flex-1", children: open ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
12781
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Panel, { defaultSize: "62%", children: chatArea }),
12782
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(ResizableHandle, { withHandle: true }),
12783
- /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Panel, { defaultSize: "38%", minSize: "320px", maxSize: "760px", children: artifactPanel })
13520
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "@container h-full min-w-0 flex-1", children: open ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
13521
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Panel, { defaultSize: "62%", children: chatArea }),
13522
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(ResizableHandle, { withHandle: true }),
13523
+ /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Panel, { defaultSize: "38%", minSize: "380px", maxSize: "760px", children: artifactPanel })
12784
13524
  ] }) : chatArea })
12785
13525
  ]
12786
13526
  }
@@ -12788,10 +13528,10 @@ function ChatPage({
12788
13528
  }
12789
13529
 
12790
13530
  // src/components/chat/Citation/index.tsx
12791
- var import_jsx_runtime185 = require("react/jsx-runtime");
13531
+ var import_jsx_runtime186 = require("react/jsx-runtime");
12792
13532
  function Citation({ items = [], start = 1, className, style }) {
12793
- return /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("span", { "data-slot": "citation", className: cn("inline-flex gap-1 align-super", className), style, children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(HoverCard, { children: [
12794
- /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
13533
+ return /* @__PURE__ */ (0, import_jsx_runtime186.jsx)("span", { "data-slot": "citation", className: cn("inline-flex gap-1 align-super", className), style, children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(HoverCard, { children: [
13534
+ /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
12795
13535
  HoverCardTrigger,
12796
13536
  {
12797
13537
  "data-slot": "citation-marker",
@@ -12803,10 +13543,10 @@ function Citation({ items = [], start = 1, className, style }) {
12803
13543
  ]
12804
13544
  }
12805
13545
  ),
12806
- /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(HoverCardContent, { "data-slot": "citation-card", className: "w-72", children: [
12807
- /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "text-sm font-medium", children: item.title }),
12808
- item.snippet ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "mt-1 line-clamp-3 text-xs text-muted-foreground", children: item.snippet }) : null,
12809
- item.url ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
13546
+ /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(HoverCardContent, { "data-slot": "citation-card", className: "w-72", children: [
13547
+ /* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { className: "text-sm font-medium", children: item.title }),
13548
+ item.snippet ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { className: "mt-1 line-clamp-3 text-xs text-muted-foreground", children: item.snippet }) : null,
13549
+ item.url ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
12810
13550
  "a",
12811
13551
  {
12812
13552
  href: item.url,
@@ -12821,13 +13561,13 @@ function Citation({ items = [], start = 1, className, style }) {
12821
13561
  }
12822
13562
 
12823
13563
  // src/components/chat/Suggestion/index.tsx
12824
- var import_jsx_runtime186 = require("react/jsx-runtime");
13564
+ var import_jsx_runtime187 = require("react/jsx-runtime");
12825
13565
  function normalize(item) {
12826
13566
  if (typeof item === "string") return { label: item, value: item };
12827
13567
  return { label: item.label, value: item.value ?? item.label, icon: item.icon };
12828
13568
  }
12829
13569
  function Suggestion({ items = [], justify = "start", onSelect, className, style }) {
12830
- return /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
13570
+ return /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(
12831
13571
  "div",
12832
13572
  {
12833
13573
  "data-slot": "suggestion",
@@ -12835,7 +13575,7 @@ function Suggestion({ items = [], justify = "start", onSelect, className, style
12835
13575
  style,
12836
13576
  children: items.map((item, index) => {
12837
13577
  const { label, value, icon } = normalize(item);
12838
- return /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
13578
+ return /* @__PURE__ */ (0, import_jsx_runtime187.jsxs)(
12839
13579
  "button",
12840
13580
  {
12841
13581
  type: "button",
@@ -12844,7 +13584,7 @@ function Suggestion({ items = [], justify = "start", onSelect, className, style
12844
13584
  className: "flex items-center gap-1.5 rounded-full border border-border px-3 py-1 text-sm transition-colors hover:bg-accent",
12845
13585
  onClick: () => onSelect?.(value),
12846
13586
  children: [
12847
- icon ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: icon, size: "sm" }) : null,
13587
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(Icon, { name: icon, size: "sm" }) : null,
12848
13588
  label
12849
13589
  ]
12850
13590
  },
@@ -12856,7 +13596,7 @@ function Suggestion({ items = [], justify = "start", onSelect, className, style
12856
13596
  }
12857
13597
 
12858
13598
  // src/components/chart/EChartBase/index.tsx
12859
- var import_react66 = require("react");
13599
+ var import_react68 = require("react");
12860
13600
 
12861
13601
  // src/components/chart/echarts-modules.ts
12862
13602
  var echarts = __toESM(require("echarts/core"), 1);
@@ -12887,7 +13627,7 @@ echarts.use([
12887
13627
  ]);
12888
13628
 
12889
13629
  // src/components/chart/EChartBase/index.tsx
12890
- var import_jsx_runtime187 = require("react/jsx-runtime");
13630
+ var import_jsx_runtime188 = require("react/jsx-runtime");
12891
13631
  function EChartBase({
12892
13632
  option,
12893
13633
  height = 256,
@@ -12896,12 +13636,12 @@ function EChartBase({
12896
13636
  style,
12897
13637
  slot
12898
13638
  }) {
12899
- const hostRef = (0, import_react66.useRef)(null);
12900
- const chartRef = (0, import_react66.useRef)(null);
12901
- const onSelectRef = (0, import_react66.useRef)(onSelect);
13639
+ const hostRef = (0, import_react68.useRef)(null);
13640
+ const chartRef = (0, import_react68.useRef)(null);
13641
+ const onSelectRef = (0, import_react68.useRef)(onSelect);
12902
13642
  onSelectRef.current = onSelect;
12903
- const [failed, setFailed] = (0, import_react66.useState)(false);
12904
- (0, import_react66.useEffect)(() => {
13643
+ const [failed, setFailed] = (0, import_react68.useState)(false);
13644
+ (0, import_react68.useEffect)(() => {
12905
13645
  const host = hostRef.current;
12906
13646
  if (!host) return;
12907
13647
  let chart = null;
@@ -12920,22 +13660,22 @@ function EChartBase({
12920
13660
  dataIndex: params.dataIndex
12921
13661
  });
12922
13662
  });
12923
- const observer = new ResizeObserver(() => chart?.resize());
12924
- observer.observe(host);
13663
+ const observer2 = new ResizeObserver(() => chart?.resize());
13664
+ observer2.observe(host);
12925
13665
  return () => {
12926
- observer.disconnect();
13666
+ observer2.disconnect();
12927
13667
  chart?.dispose();
12928
13668
  chartRef.current = null;
12929
13669
  };
12930
13670
  }, []);
12931
- (0, import_react66.useEffect)(() => {
13671
+ (0, import_react68.useEffect)(() => {
12932
13672
  try {
12933
13673
  chartRef.current?.setOption(option, { notMerge: true });
12934
13674
  } catch {
12935
13675
  }
12936
13676
  }, [option]);
12937
13677
  if (failed) {
12938
- return /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(
13678
+ return /* @__PURE__ */ (0, import_jsx_runtime188.jsx)(
12939
13679
  "div",
12940
13680
  {
12941
13681
  "data-slot": "chart-fallback",
@@ -12948,7 +13688,7 @@ function EChartBase({
12948
13688
  }
12949
13689
  );
12950
13690
  }
12951
- return /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(
13691
+ return /* @__PURE__ */ (0, import_jsx_runtime188.jsx)(
12952
13692
  "div",
12953
13693
  {
12954
13694
  ref: hostRef,
@@ -13384,6 +14124,9 @@ function buildComposedOption(input, theme) {
13384
14124
  };
13385
14125
  }
13386
14126
 
14127
+ // src/components/chart/lib/use-chart-theme.ts
14128
+ var import_react69 = require("react");
14129
+
13387
14130
  // src/components/chart/lib/color.ts
13388
14131
  var LPAREN = String.fromCharCode(40);
13389
14132
  var RPAREN = String.fromCharCode(41);
@@ -13480,9 +14223,67 @@ function getChartTheme() {
13480
14223
  return FALLBACK_THEME;
13481
14224
  }
13482
14225
  }
14226
+ function resetChartTheme() {
14227
+ cached = null;
14228
+ }
14229
+ var CHART_SKIN_CHANGE_EVENT = "pactor:skin-change";
14230
+ var listeners = /* @__PURE__ */ new Set();
14231
+ var observer = null;
14232
+ var scheduled = false;
14233
+ function scheduleNotify() {
14234
+ if (scheduled) return;
14235
+ scheduled = true;
14236
+ const enqueue = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
14237
+ enqueue(() => {
14238
+ scheduled = false;
14239
+ resetChartTheme();
14240
+ for (const listener of [...listeners]) {
14241
+ listener();
14242
+ }
14243
+ });
14244
+ }
14245
+ function handleResourceLoad(event) {
14246
+ const target = event.target;
14247
+ if (target instanceof HTMLLinkElement || target instanceof HTMLStyleElement) {
14248
+ scheduleNotify();
14249
+ }
14250
+ }
14251
+ function subscribeChartTheme(listener) {
14252
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
14253
+ return () => {
14254
+ };
14255
+ }
14256
+ listeners.add(listener);
14257
+ if (!observer) {
14258
+ observer = new MutationObserver(scheduleNotify);
14259
+ observer.observe(document.documentElement, { attributes: true });
14260
+ observer.observe(document.head, {
14261
+ attributes: true,
14262
+ childList: true,
14263
+ characterData: true,
14264
+ subtree: true
14265
+ });
14266
+ document.addEventListener("load", handleResourceLoad, true);
14267
+ window.addEventListener(CHART_SKIN_CHANGE_EVENT, scheduleNotify);
14268
+ }
14269
+ return () => {
14270
+ listeners.delete(listener);
14271
+ if (listeners.size === 0 && observer) {
14272
+ observer.disconnect();
14273
+ observer = null;
14274
+ document.removeEventListener("load", handleResourceLoad, true);
14275
+ window.removeEventListener(CHART_SKIN_CHANGE_EVENT, scheduleNotify);
14276
+ }
14277
+ };
14278
+ }
14279
+
14280
+ // src/components/chart/lib/use-chart-theme.ts
14281
+ function useChartTheme() {
14282
+ return (0, import_react69.useSyncExternalStore)(subscribeChartTheme, getChartTheme, getChartTheme);
14283
+ }
13483
14284
 
13484
14285
  // src/components/chart/AreaChart/index.tsx
13485
- var import_jsx_runtime188 = require("react/jsx-runtime");
14286
+ var import_jsx_runtime189 = require("react/jsx-runtime");
13486
14287
  function AreaChart({
13487
14288
  data = [],
13488
14289
  xKey,
@@ -13498,9 +14299,9 @@ function AreaChart({
13498
14299
  }) {
13499
14300
  const option = buildAreaOption(
13500
14301
  { data, xKey, yKeys, stacked, fillOpacity, colors, title },
13501
- getChartTheme()
14302
+ useChartTheme()
13502
14303
  );
13503
- return /* @__PURE__ */ (0, import_jsx_runtime188.jsx)(
14304
+ return /* @__PURE__ */ (0, import_jsx_runtime189.jsx)(
13504
14305
  EChartBase,
13505
14306
  {
13506
14307
  slot: "area-chart",
@@ -13514,7 +14315,7 @@ function AreaChart({
13514
14315
  }
13515
14316
 
13516
14317
  // src/components/chart/BarChart/index.tsx
13517
- var import_jsx_runtime189 = require("react/jsx-runtime");
14318
+ var import_jsx_runtime190 = require("react/jsx-runtime");
13518
14319
  function BarChart2({
13519
14320
  data = [],
13520
14321
  yKey,
@@ -13529,9 +14330,9 @@ function BarChart2({
13529
14330
  }) {
13530
14331
  const option = buildBarOption(
13531
14332
  { data, yKey, yKeys: xKeys, stacked, colors, title },
13532
- getChartTheme()
14333
+ useChartTheme()
13533
14334
  );
13534
- return /* @__PURE__ */ (0, import_jsx_runtime189.jsx)(
14335
+ return /* @__PURE__ */ (0, import_jsx_runtime190.jsx)(
13535
14336
  EChartBase,
13536
14337
  {
13537
14338
  slot: "bar-chart",
@@ -13545,7 +14346,7 @@ function BarChart2({
13545
14346
  }
13546
14347
 
13547
14348
  // src/components/chart/BubbleChart/index.tsx
13548
- var import_jsx_runtime190 = require("react/jsx-runtime");
14349
+ var import_jsx_runtime191 = require("react/jsx-runtime");
13549
14350
  function BubbleChart({
13550
14351
  data = [],
13551
14352
  xKey,
@@ -13561,9 +14362,9 @@ function BubbleChart({
13561
14362
  }) {
13562
14363
  const option = buildBubbleOption(
13563
14364
  { data, xKey, yKey, sizeKey, seriesKey, colors, title },
13564
- getChartTheme()
14365
+ useChartTheme()
13565
14366
  );
13566
- return /* @__PURE__ */ (0, import_jsx_runtime190.jsx)(
14367
+ return /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
13567
14368
  EChartBase,
13568
14369
  {
13569
14370
  slot: "bubble-chart",
@@ -13577,7 +14378,7 @@ function BubbleChart({
13577
14378
  }
13578
14379
 
13579
14380
  // src/components/chart/ColumnChart/index.tsx
13580
- var import_jsx_runtime191 = require("react/jsx-runtime");
14381
+ var import_jsx_runtime192 = require("react/jsx-runtime");
13581
14382
  function ColumnChart({
13582
14383
  data = [],
13583
14384
  xKey,
@@ -13592,9 +14393,9 @@ function ColumnChart({
13592
14393
  }) {
13593
14394
  const option = buildColumnOption(
13594
14395
  { data, xKey, yKeys, stacked, colors, title },
13595
- getChartTheme()
14396
+ useChartTheme()
13596
14397
  );
13597
- return /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
14398
+ return /* @__PURE__ */ (0, import_jsx_runtime192.jsx)(
13598
14399
  EChartBase,
13599
14400
  {
13600
14401
  slot: "column-chart",
@@ -13608,7 +14409,7 @@ function ColumnChart({
13608
14409
  }
13609
14410
 
13610
14411
  // src/components/chart/ComposedChart/index.tsx
13611
- var import_jsx_runtime192 = require("react/jsx-runtime");
14412
+ var import_jsx_runtime193 = require("react/jsx-runtime");
13612
14413
  function ComposedChart({
13613
14414
  data = [],
13614
14415
  xKey,
@@ -13622,9 +14423,9 @@ function ComposedChart({
13622
14423
  }) {
13623
14424
  const option = buildComposedOption(
13624
14425
  { data, xKey, series, colors, title },
13625
- getChartTheme()
14426
+ useChartTheme()
13626
14427
  );
13627
- return /* @__PURE__ */ (0, import_jsx_runtime192.jsx)(
14428
+ return /* @__PURE__ */ (0, import_jsx_runtime193.jsx)(
13628
14429
  EChartBase,
13629
14430
  {
13630
14431
  slot: "composed-chart",
@@ -13638,7 +14439,7 @@ function ComposedChart({
13638
14439
  }
13639
14440
 
13640
14441
  // src/components/chart/DonutChart/index.tsx
13641
- var import_jsx_runtime193 = require("react/jsx-runtime");
14442
+ var import_jsx_runtime194 = require("react/jsx-runtime");
13642
14443
  function DonutChart({
13643
14444
  data = [],
13644
14445
  nameKey,
@@ -13668,9 +14469,9 @@ function DonutChart({
13668
14469
  colors,
13669
14470
  title
13670
14471
  },
13671
- getChartTheme()
14472
+ useChartTheme()
13672
14473
  );
13673
- return /* @__PURE__ */ (0, import_jsx_runtime193.jsx)(
14474
+ return /* @__PURE__ */ (0, import_jsx_runtime194.jsx)(
13674
14475
  EChartBase,
13675
14476
  {
13676
14477
  slot: "donut-chart",
@@ -13684,7 +14485,7 @@ function DonutChart({
13684
14485
  }
13685
14486
 
13686
14487
  // src/components/chart/FunnelChart/index.tsx
13687
- var import_jsx_runtime194 = require("react/jsx-runtime");
14488
+ var import_jsx_runtime195 = require("react/jsx-runtime");
13688
14489
  function FunnelChart2({
13689
14490
  data = [],
13690
14491
  nameKey,
@@ -13699,9 +14500,9 @@ function FunnelChart2({
13699
14500
  }) {
13700
14501
  const option = buildFunnelOption(
13701
14502
  { data, nameKey, valueKey, sort, colors, title },
13702
- getChartTheme()
14503
+ useChartTheme()
13703
14504
  );
13704
- return /* @__PURE__ */ (0, import_jsx_runtime194.jsx)(
14505
+ return /* @__PURE__ */ (0, import_jsx_runtime195.jsx)(
13705
14506
  EChartBase,
13706
14507
  {
13707
14508
  slot: "funnel-chart",
@@ -13715,7 +14516,7 @@ function FunnelChart2({
13715
14516
  }
13716
14517
 
13717
14518
  // src/components/chart/GaugeChart/index.tsx
13718
- var import_jsx_runtime195 = require("react/jsx-runtime");
14519
+ var import_jsx_runtime196 = require("react/jsx-runtime");
13719
14520
  function GaugeChart2({
13720
14521
  value = 0,
13721
14522
  min,
@@ -13730,9 +14531,9 @@ function GaugeChart2({
13730
14531
  }) {
13731
14532
  const option = buildGaugeOption(
13732
14533
  { value, min, max, thresholds, unit, title },
13733
- getChartTheme()
14534
+ useChartTheme()
13734
14535
  );
13735
- return /* @__PURE__ */ (0, import_jsx_runtime195.jsx)(
14536
+ return /* @__PURE__ */ (0, import_jsx_runtime196.jsx)(
13736
14537
  EChartBase,
13737
14538
  {
13738
14539
  slot: "gauge-chart",
@@ -13746,7 +14547,7 @@ function GaugeChart2({
13746
14547
  }
13747
14548
 
13748
14549
  // src/components/chart/Heatmap/index.tsx
13749
- var import_jsx_runtime196 = require("react/jsx-runtime");
14550
+ var import_jsx_runtime197 = require("react/jsx-runtime");
13750
14551
  function Heatmap({
13751
14552
  data = [],
13752
14553
  xKey,
@@ -13760,9 +14561,9 @@ function Heatmap({
13760
14561
  }) {
13761
14562
  const option = buildHeatmapOption(
13762
14563
  { data, xKey, yKey, valueKey, title },
13763
- getChartTheme()
14564
+ useChartTheme()
13764
14565
  );
13765
- return /* @__PURE__ */ (0, import_jsx_runtime196.jsx)(
14566
+ return /* @__PURE__ */ (0, import_jsx_runtime197.jsx)(
13766
14567
  EChartBase,
13767
14568
  {
13768
14569
  slot: "heatmap",
@@ -13776,7 +14577,7 @@ function Heatmap({
13776
14577
  }
13777
14578
 
13778
14579
  // src/components/chart/LineChart/index.tsx
13779
- var import_jsx_runtime197 = require("react/jsx-runtime");
14580
+ var import_jsx_runtime198 = require("react/jsx-runtime");
13780
14581
  function LineChart2({
13781
14582
  data = [],
13782
14583
  xKey,
@@ -13793,9 +14594,9 @@ function LineChart2({
13793
14594
  }) {
13794
14595
  const option = buildLineOption(
13795
14596
  { data, xKey, yKeys, smooth, showArea, stacked, colors, title },
13796
- getChartTheme()
14597
+ useChartTheme()
13797
14598
  );
13798
- return /* @__PURE__ */ (0, import_jsx_runtime197.jsx)(
14599
+ return /* @__PURE__ */ (0, import_jsx_runtime198.jsx)(
13799
14600
  EChartBase,
13800
14601
  {
13801
14602
  slot: "line-chart",
@@ -13809,8 +14610,8 @@ function LineChart2({
13809
14610
  }
13810
14611
 
13811
14612
  // src/components/chart/MapChart/index.tsx
13812
- var import_react67 = require("react");
13813
- var import_jsx_runtime198 = require("react/jsx-runtime");
14613
+ var import_react70 = require("react");
14614
+ var import_jsx_runtime199 = require("react/jsx-runtime");
13814
14615
  var fetchedMaps = /* @__PURE__ */ new Set();
13815
14616
  function hasRegisteredMap(mapName) {
13816
14617
  try {
@@ -13832,7 +14633,8 @@ function MapChart2({
13832
14633
  className,
13833
14634
  style
13834
14635
  }) {
13835
- const [loadState, setLoadState] = (0, import_react67.useState)(
14636
+ const theme = useChartTheme();
14637
+ const [loadState, setLoadState] = (0, import_react70.useState)(
13836
14638
  () => geoJson || !geoJsonUrl || hasRegisteredMap(mapName) ? "idle" : "loading"
13837
14639
  );
13838
14640
  if (geoJson) {
@@ -13841,7 +14643,7 @@ function MapChart2({
13841
14643
  } catch {
13842
14644
  }
13843
14645
  }
13844
- (0, import_react67.useEffect)(() => {
14646
+ (0, import_react70.useEffect)(() => {
13845
14647
  if (geoJson || !geoJsonUrl || hasRegisteredMap(mapName) || fetchedMaps.has(mapName)) {
13846
14648
  setLoadState("idle");
13847
14649
  return;
@@ -13866,7 +14668,7 @@ function MapChart2({
13866
14668
  };
13867
14669
  }, [geoJson, geoJsonUrl, mapName]);
13868
14670
  if (geoJsonUrl && !geoJson && loadState === "loading") {
13869
- return /* @__PURE__ */ (0, import_jsx_runtime198.jsx)(
14671
+ return /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(
13870
14672
  "div",
13871
14673
  {
13872
14674
  "data-slot": "map-chart-loading",
@@ -13876,7 +14678,7 @@ function MapChart2({
13876
14678
  );
13877
14679
  }
13878
14680
  if (!geoJson && loadState === "error") {
13879
- return /* @__PURE__ */ (0, import_jsx_runtime198.jsx)(
14681
+ return /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(
13880
14682
  Empty2,
13881
14683
  {
13882
14684
  title: "\u5730\u56FE\u52A0\u8F7D\u5931\u8D25",
@@ -13888,7 +14690,7 @@ function MapChart2({
13888
14690
  }
13889
14691
  if (!geoJson && !hasRegisteredMap(mapName)) {
13890
14692
  console.warn(`[MapChart] \u5730\u56FE "${mapName}" \u672A\u6CE8\u518C\uFF1A\u8BF7\u4F20\u5165 geoJson / geoJsonUrl\uFF0C\u6216\u5728\u5E94\u7528\u542F\u52A8\u65F6 echarts.registerMap`);
13891
- return /* @__PURE__ */ (0, import_jsx_runtime198.jsx)(
14693
+ return /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(
13892
14694
  Empty2,
13893
14695
  {
13894
14696
  title: "\u5730\u56FE\u672A\u6CE8\u518C",
@@ -13898,8 +14700,8 @@ function MapChart2({
13898
14700
  }
13899
14701
  );
13900
14702
  }
13901
- const option = buildMapOption({ mapName, data, nameKey, valueKey, title }, getChartTheme());
13902
- return /* @__PURE__ */ (0, import_jsx_runtime198.jsx)(
14703
+ const option = buildMapOption({ mapName, data, nameKey, valueKey, title }, theme);
14704
+ return /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(
13903
14705
  EChartBase,
13904
14706
  {
13905
14707
  slot: "map-chart",
@@ -13914,7 +14716,7 @@ function MapChart2({
13914
14716
 
13915
14717
  // src/components/chart/MetricCard/index.tsx
13916
14718
  var import_lucide_react37 = require("lucide-react");
13917
- var import_jsx_runtime199 = require("react/jsx-runtime");
14719
+ var import_jsx_runtime200 = require("react/jsx-runtime");
13918
14720
  function MetricCard({
13919
14721
  title,
13920
14722
  value,
@@ -13927,15 +14729,15 @@ function MetricCard({
13927
14729
  }) {
13928
14730
  const showTrend = typeof trend === "number" && trend !== 0;
13929
14731
  const rising = (trend ?? 0) > 0;
13930
- return /* @__PURE__ */ (0, import_jsx_runtime199.jsxs)(
14732
+ return /* @__PURE__ */ (0, import_jsx_runtime200.jsxs)(
13931
14733
  "div",
13932
14734
  {
13933
14735
  "data-slot": "metric-card",
13934
14736
  className: cn("rounded-lg border bg-card p-4 text-card-foreground shadow-sm", className),
13935
14737
  style,
13936
14738
  children: [
13937
- title ? /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("div", { "data-slot": "metric-card-title", className: "text-sm text-muted-foreground", children: title }) : null,
13938
- /* @__PURE__ */ (0, import_jsx_runtime199.jsxs)(
14739
+ title ? /* @__PURE__ */ (0, import_jsx_runtime200.jsx)("div", { "data-slot": "metric-card-title", className: "text-sm text-muted-foreground", children: title }) : null,
14740
+ /* @__PURE__ */ (0, import_jsx_runtime200.jsxs)(
13939
14741
  "div",
13940
14742
  {
13941
14743
  "data-slot": "metric-card-value",
@@ -13947,7 +14749,7 @@ function MetricCard({
13947
14749
  ]
13948
14750
  }
13949
14751
  ),
13950
- showTrend ? /* @__PURE__ */ (0, import_jsx_runtime199.jsxs)(
14752
+ showTrend ? /* @__PURE__ */ (0, import_jsx_runtime200.jsxs)(
13951
14753
  "div",
13952
14754
  {
13953
14755
  "data-slot": "metric-card-trend",
@@ -13957,10 +14759,10 @@ function MetricCard({
13957
14759
  rising ? "text-success" : "text-destructive"
13958
14760
  ),
13959
14761
  children: [
13960
- rising ? /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(import_lucide_react37.ArrowUpRight, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime199.jsx)(import_lucide_react37.ArrowDownRight, { className: "size-4" }),
14762
+ rising ? /* @__PURE__ */ (0, import_jsx_runtime200.jsx)(import_lucide_react37.ArrowUpRight, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime200.jsx)(import_lucide_react37.ArrowDownRight, { className: "size-4" }),
13961
14763
  Math.abs(trend ?? 0),
13962
14764
  "%",
13963
- trendLabel ? /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("span", { className: "ml-1 text-muted-foreground", children: trendLabel }) : null
14765
+ trendLabel ? /* @__PURE__ */ (0, import_jsx_runtime200.jsx)("span", { className: "ml-1 text-muted-foreground", children: trendLabel }) : null
13964
14766
  ]
13965
14767
  }
13966
14768
  ) : null
@@ -13970,7 +14772,7 @@ function MetricCard({
13970
14772
  }
13971
14773
 
13972
14774
  // src/components/chart/PieChart/index.tsx
13973
- var import_jsx_runtime200 = require("react/jsx-runtime");
14775
+ var import_jsx_runtime201 = require("react/jsx-runtime");
13974
14776
  function PieChart2({
13975
14777
  data = [],
13976
14778
  nameKey,
@@ -13985,9 +14787,9 @@ function PieChart2({
13985
14787
  }) {
13986
14788
  const option = buildPieOption(
13987
14789
  { data, nameKey, valueKey, showLabel, colors, title },
13988
- getChartTheme()
14790
+ useChartTheme()
13989
14791
  );
13990
- return /* @__PURE__ */ (0, import_jsx_runtime200.jsx)(
14792
+ return /* @__PURE__ */ (0, import_jsx_runtime201.jsx)(
13991
14793
  EChartBase,
13992
14794
  {
13993
14795
  slot: "pie-chart",
@@ -14001,7 +14803,7 @@ function PieChart2({
14001
14803
  }
14002
14804
 
14003
14805
  // src/components/chart/RadarChart/index.tsx
14004
- var import_jsx_runtime201 = require("react/jsx-runtime");
14806
+ var import_jsx_runtime202 = require("react/jsx-runtime");
14005
14807
  function RadarChart2({
14006
14808
  data = [],
14007
14809
  indicatorKey,
@@ -14015,9 +14817,9 @@ function RadarChart2({
14015
14817
  }) {
14016
14818
  const option = buildRadarOption(
14017
14819
  { data, indicatorKey, yKeys, colors, title },
14018
- getChartTheme()
14820
+ useChartTheme()
14019
14821
  );
14020
- return /* @__PURE__ */ (0, import_jsx_runtime201.jsx)(
14822
+ return /* @__PURE__ */ (0, import_jsx_runtime202.jsx)(
14021
14823
  EChartBase,
14022
14824
  {
14023
14825
  slot: "radar-chart",
@@ -14031,7 +14833,7 @@ function RadarChart2({
14031
14833
  }
14032
14834
 
14033
14835
  // src/components/chart/SankeyChart/index.tsx
14034
- var import_jsx_runtime202 = require("react/jsx-runtime");
14836
+ var import_jsx_runtime203 = require("react/jsx-runtime");
14035
14837
  function SankeyChart2({
14036
14838
  nodes = [],
14037
14839
  links = [],
@@ -14041,8 +14843,8 @@ function SankeyChart2({
14041
14843
  className,
14042
14844
  style
14043
14845
  }) {
14044
- const option = buildSankeyOption({ nodes, links, title }, getChartTheme());
14045
- return /* @__PURE__ */ (0, import_jsx_runtime202.jsx)(
14846
+ const option = buildSankeyOption({ nodes, links, title }, useChartTheme());
14847
+ return /* @__PURE__ */ (0, import_jsx_runtime203.jsx)(
14046
14848
  EChartBase,
14047
14849
  {
14048
14850
  slot: "sankey-chart",
@@ -14056,7 +14858,7 @@ function SankeyChart2({
14056
14858
  }
14057
14859
 
14058
14860
  // src/components/chart/ScatterChart/index.tsx
14059
- var import_jsx_runtime203 = require("react/jsx-runtime");
14861
+ var import_jsx_runtime204 = require("react/jsx-runtime");
14060
14862
  function ScatterChart2({
14061
14863
  data = [],
14062
14864
  xKey,
@@ -14071,9 +14873,9 @@ function ScatterChart2({
14071
14873
  }) {
14072
14874
  const option = buildScatterOption(
14073
14875
  { data, xKey, yKey, seriesKey, colors, title },
14074
- getChartTheme()
14876
+ useChartTheme()
14075
14877
  );
14076
- return /* @__PURE__ */ (0, import_jsx_runtime203.jsx)(
14878
+ return /* @__PURE__ */ (0, import_jsx_runtime204.jsx)(
14077
14879
  EChartBase,
14078
14880
  {
14079
14881
  slot: "scatter-chart",
@@ -14087,7 +14889,7 @@ function ScatterChart2({
14087
14889
  }
14088
14890
 
14089
14891
  // src/components/chart/TreeChart/index.tsx
14090
- var import_jsx_runtime204 = require("react/jsx-runtime");
14892
+ var import_jsx_runtime205 = require("react/jsx-runtime");
14091
14893
  function TreeChart2({
14092
14894
  data = [],
14093
14895
  title,
@@ -14101,9 +14903,9 @@ function TreeChart2({
14101
14903
  }) {
14102
14904
  const option = buildTreeOption(
14103
14905
  { data, title, orient, edgeShape, initialTreeDepth },
14104
- getChartTheme()
14906
+ useChartTheme()
14105
14907
  );
14106
- return /* @__PURE__ */ (0, import_jsx_runtime204.jsx)(
14908
+ return /* @__PURE__ */ (0, import_jsx_runtime205.jsx)(
14107
14909
  EChartBase,
14108
14910
  {
14109
14911
  slot: "tree-chart",