@blade-hq/agent-react 1.2.1-beta.13 → 1.2.1-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ pnpm add @blade-hq/agent-client @blade-hq/agent-react
13
13
  ```tsx
14
14
  import { BladeClient } from "@blade-hq/agent-client"
15
15
  import { BladeProvider, ChatView } from "@blade-hq/agent-react"
16
- import "@blade-hq/agent-react/style.css"
16
+ import "@blade-hq/agent-react/style.full.css"
17
17
 
18
18
  const client = new BladeClient({ baseUrl: "https://blade.example.com" })
19
19
 
@@ -88,7 +88,11 @@ await session?.send("你好")
88
88
 
89
89
  全部 props 见 `ChatViewProps`。样式说明:
90
90
 
91
- - 必须引入 `@blade-hq/agent-react/style.css`。组件自带 `.blade-chat-*` 前缀的自包含样式,宿主没装 Tailwind 也开箱可用;颜色走 CSS 变量,可整体换肤/暗色。
91
+ - 必须引入一份样式,按宿主有没有 Tailwind 二选一:
92
+ - **`style.full.css`**(默认选它):布局兜底 + 编译好的 Tailwind 产物,自包含,宿主没装 Tailwind 也是完整视觉。
93
+ - **`style.css`**:只有 `.blade-chat-*` 布局兜底。宿主自己装了 Tailwind、且 `content` 配了扫描 `node_modules/@blade-hq/agent-react` 时用它,可以少一份重复 CSS。选错不会报错,只是工具块、思考块内部会退化成没有布局的裸 HTML。
94
+ - 两份都不含 Tailwind preflight 这类全局 reset,引入后不会影响宿主页面自己的排版;组件需要的那点重置限定在 `.blade-chat` 子树内(见 `src/scoped-preflight.css`)。Shadow DOM 版(`<blade-chat>`)不受此限,它注入的是带 preflight 的完整产物。
95
+ - 颜色走 CSS 变量,可整体换肤;深色页面要在根元素上写 `data-theme="dark"`,否则拿到的是默认的浅色变量。
92
96
  - `renderers.toolCall` 返回 `null` 时回落到默认工具卡片。
93
97
  - **内边距按容器宽度伸缩**,嵌进窄侧栏(300–400px)时会自动收窄,不看浏览器视口。代价是聊天容器需要有确定宽度——放在 flex/grid 里被拉伸,或显式给宽度都可以;放进 `width: fit-content`、`inline-flex` 这类由内容决定宽度的父容器会塌缩。
94
98
 
@@ -118,17 +122,19 @@ SDK 的 ChatView / `<blade-chat>` 不内置模型选择器(默认用后端配
118
122
 
119
123
  ## 样式定制
120
124
 
121
- 三个层次,按需选用:
125
+ 默认是浅色主题。四个层次,按需选用:
122
126
 
123
- 1. **CSS 变量换肤**(React 与 `<blade-chat>` 通用):所有颜色走 `--primary`、`--background`、`--muted` 等变量(完整清单见 style.css 开头)。页面直接覆盖即可穿透 Shadow DOM:
127
+ 1. **深浅主题**:`<ChatView theme="dark" />` / `<blade-chat theme="dark">` 切内置深色,不传或 `"light"` 为浅色。宿主已经在祖先元素上写了 `data-theme="dark"` 时不用传,`ChatView` 会跟着变。`<blade-chat>` 渲染在 Shadow DOM 内,页面上的 `data-theme` 对它无效,只认 `theme` 属性。
128
+
129
+ 2. **CSS 变量换肤**(React 与 `<blade-chat>` 通用):所有颜色走 `--primary`、`--background`、`--muted` 等变量(完整清单见 style.css 开头)。页面直接覆盖即可穿透 Shadow DOM:
124
130
 
125
131
  ```css
126
132
  blade-chat { --primary: 262 83% 58%; height: 640px; }
127
133
  ```
128
134
 
129
- 2. **classNames props**(React):`ChatView` 的 `classNames` 把自定义 class(含你自己构建的 Tailwind 工具类)挂到根节点、消息区、输入区等关键节点上,见 `ChatViewClassNames`。
135
+ 3. **classNames props**(React):`ChatView` 的 `classNames` 把自定义 class(含你自己构建的 Tailwind 工具类)挂到根节点、消息区、输入区等关键节点上,见 `ChatViewClassNames`。
130
136
 
131
- 3. **内嵌 `<style>`(纯 HTML / Vue)**:`<blade-chat>` 的直接 `<style>` 子元素会被注入 Shadow DOM、排在内置样式之后,可用 `.blade-chat-*` 类名做任意深度定制:
137
+ 4. **内嵌 `<style>`(纯 HTML / Vue)**:`<blade-chat>` 的直接 `<style>` 子元素会被注入 Shadow DOM、排在内置样式之后,可用 `.blade-chat-*` 类名做任意深度定制:
132
138
 
133
139
  ```html
134
140
  <blade-chat base-url="...">
@@ -33,6 +33,8 @@ export interface ChatViewProps {
33
33
  renderers?: ChatViewRenderers;
34
34
  slots?: ChatViewSlots;
35
35
  placeholder?: string;
36
+ /** 配色主题,默认浅色。宿主已经在祖先元素上写了 data-theme 时不用传。 */
37
+ theme?: "light" | "dark";
36
38
  }
37
39
  /**
38
40
  * 开箱即用的聊天界面:连接(或新建)一个会话,渲染消息流与输入框。
@@ -1,6 +1,6 @@
1
1
  import { type AgentSession } from "@blade-hq/agent-client";
2
2
  /**
3
- * `<blade-chat base-url="https://..." session-id="可选">`
3
+ * `<blade-chat base-url="https://..." session-id="可选" theme="light|dark">`
4
4
  *
5
5
  * 纯静态页面的聊天入口:Shadow DOM 内渲染完整 ChatView,
6
6
  * 未登录时组件自带登录引导,不传 session-id 自动建会话。
package/dist/index.js CHANGED
@@ -2223,6 +2223,9 @@ function PlanningDivider({ kind }) {
2223
2223
 
2224
2224
  // src/components/ChatView.tsx
2225
2225
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2226
+ function themeAttr(theme) {
2227
+ return theme === "dark" ? "dark" : void 0;
2228
+ }
2226
2229
  function isUnauthorizedError(error) {
2227
2230
  return error instanceof BladeApiError && error.status === 401;
2228
2231
  }
@@ -2263,16 +2266,23 @@ function ChatView(props) {
2263
2266
  const [attempt, setAttempt] = useState9(0);
2264
2267
  const [needLogin, setNeedLogin] = useState9(() => !client.hasToken());
2265
2268
  if (needLogin) {
2266
- return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root), children: /* @__PURE__ */ jsx14(
2267
- LoginCard,
2269
+ return /* @__PURE__ */ jsx14(
2270
+ "div",
2268
2271
  {
2269
- client,
2270
- onLoggedIn: () => {
2271
- setNeedLogin(false);
2272
- setAttempt((value) => value + 1);
2273
- }
2272
+ "data-theme": themeAttr(props.theme),
2273
+ className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
2274
+ children: /* @__PURE__ */ jsx14(
2275
+ LoginCard,
2276
+ {
2277
+ client,
2278
+ onLoggedIn: () => {
2279
+ setNeedLogin(false);
2280
+ setAttempt((value) => value + 1);
2281
+ }
2282
+ }
2283
+ )
2274
2284
  }
2275
- ) });
2285
+ );
2276
2286
  }
2277
2287
  return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2278
2288
  }
@@ -2286,6 +2296,7 @@ function ChatSessionView({
2286
2296
  renderers,
2287
2297
  slots,
2288
2298
  placeholder,
2299
+ theme,
2289
2300
  onUnauthorized
2290
2301
  }) {
2291
2302
  const { session, state, error } = useAgentSession(sessionId, {
@@ -2344,6 +2355,7 @@ ${content}`);
2344
2355
  return /* @__PURE__ */ jsxs12(
2345
2356
  "div",
2346
2357
  {
2358
+ "data-theme": themeAttr(theme),
2347
2359
  className: cn(
2348
2360
  "blade-chat flex min-h-0 flex-1 flex-col overflow-hidden",
2349
2361
  classNames?.root
@@ -2356,7 +2368,7 @@ ${content}`);
2356
2368
  className: classNames?.banner
2357
2369
  }
2358
2370
  ),
2359
- errorMessage && /* @__PURE__ */ jsxs12("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300", children: [
2371
+ errorMessage && /* @__PURE__ */ jsxs12("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
2360
2372
  /* @__PURE__ */ jsx14(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2361
2373
  /* @__PURE__ */ jsx14("span", { children: errorMessage })
2362
2374
  ] }),