@agentaily/design-system 0.1.1 → 0.3.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.
Files changed (82) hide show
  1. package/DESIGN.md +58 -7
  2. package/README.md +10 -6
  3. package/dist/components/ai/Confirmation.js +58 -22
  4. package/dist/components/ai/Confirmation.js.map +1 -1
  5. package/dist/components/ai/Queue.d.ts +23 -0
  6. package/dist/components/ai/Queue.js +52 -1
  7. package/dist/components/ai/Queue.js.map +1 -1
  8. package/dist/components/ai/ToolCall.js +69 -30
  9. package/dist/components/ai/ToolCall.js.map +1 -1
  10. package/dist/components/auth/AccountControl.d.ts +23 -0
  11. package/dist/components/auth/AccountControl.js +47 -0
  12. package/dist/components/auth/AccountControl.js.map +1 -0
  13. package/dist/components/auth/AuthDialog.d.ts +39 -0
  14. package/dist/components/auth/AuthDialog.js +327 -0
  15. package/dist/components/auth/AuthDialog.js.map +1 -0
  16. package/dist/components/auth/SignInPage.d.ts +48 -0
  17. package/dist/components/auth/SignInPage.js +217 -0
  18. package/dist/components/auth/SignInPage.js.map +1 -0
  19. package/dist/components/chat/CodeBlock.js +3 -2
  20. package/dist/components/chat/CodeBlock.js.map +1 -1
  21. package/dist/components/chat/ConversationThread.d.ts +67 -0
  22. package/dist/components/chat/ConversationThread.js +129 -0
  23. package/dist/components/chat/ConversationThread.js.map +1 -0
  24. package/dist/components/code/Artifact.js +44 -9
  25. package/dist/components/code/Artifact.js.map +1 -1
  26. package/dist/components/code/JSXPreview.js +19 -12
  27. package/dist/components/code/JSXPreview.js.map +1 -1
  28. package/dist/components/code/Snippet.js +2 -2
  29. package/dist/components/code/Snippet.js.map +1 -1
  30. package/dist/components/code/Terminal.js +24 -10
  31. package/dist/components/code/Terminal.js.map +1 -1
  32. package/dist/components/code/WebPreview.js +44 -10
  33. package/dist/components/code/WebPreview.js.map +1 -1
  34. package/dist/components/display/Skeleton.js +17 -4
  35. package/dist/components/display/Skeleton.js.map +1 -1
  36. package/dist/components/display/StatusPill.d.ts +12 -0
  37. package/dist/components/display/StatusPill.js +17 -0
  38. package/dist/components/display/StatusPill.js.map +1 -0
  39. package/dist/components/inputs/Form.d.ts +164 -0
  40. package/dist/components/inputs/Form.js +484 -0
  41. package/dist/components/inputs/Form.js.map +1 -0
  42. package/dist/components/inputs/Input.d.ts +2 -0
  43. package/dist/components/inputs/Input.js +14 -10
  44. package/dist/components/inputs/Input.js.map +1 -1
  45. package/dist/components/inputs/SecretField.d.ts +21 -0
  46. package/dist/components/inputs/SecretField.js +70 -0
  47. package/dist/components/inputs/SecretField.js.map +1 -0
  48. package/dist/components/layout/AppShell.d.ts +30 -0
  49. package/dist/components/layout/AppShell.js +117 -0
  50. package/dist/components/layout/AppShell.js.map +1 -0
  51. package/dist/components/layout/DesignerShell.d.ts +39 -0
  52. package/dist/components/layout/DesignerShell.js +146 -0
  53. package/dist/components/layout/DesignerShell.js.map +1 -0
  54. package/dist/components/layout/DocsLayout.d.ts +24 -0
  55. package/dist/components/layout/DocsLayout.js +113 -0
  56. package/dist/components/layout/DocsLayout.js.map +1 -0
  57. package/dist/components/layout/SettingsPage.d.ts +31 -0
  58. package/dist/components/layout/SettingsPage.js +92 -0
  59. package/dist/components/layout/SettingsPage.js.map +1 -0
  60. package/dist/components/review/MarkupLayer.d.ts +20 -0
  61. package/dist/components/review/MarkupLayer.js +237 -0
  62. package/dist/components/review/MarkupLayer.js.map +1 -0
  63. package/dist/components/settings/HelpSteps.d.ts +20 -0
  64. package/dist/components/settings/HelpSteps.js +40 -0
  65. package/dist/components/settings/HelpSteps.js.map +1 -0
  66. package/dist/components/settings/IntegrationSettings.d.ts +15 -0
  67. package/dist/components/settings/IntegrationSettings.js +630 -0
  68. package/dist/components/settings/IntegrationSettings.js.map +1 -0
  69. package/dist/components/settings/TestRow.d.ts +21 -0
  70. package/dist/components/settings/TestRow.js +66 -0
  71. package/dist/components/settings/TestRow.js.map +1 -0
  72. package/dist/components/utilities/BrandMark.d.ts +17 -0
  73. package/dist/components/utilities/BrandMark.js +43 -0
  74. package/dist/components/utilities/BrandMark.js.map +1 -0
  75. package/dist/components/utilities/Icon.d.ts +28 -0
  76. package/dist/components/utilities/Icon.js +196 -0
  77. package/dist/components/utilities/Icon.js.map +1 -0
  78. package/dist/index.d.ts +23 -0
  79. package/dist/index.js +35 -0
  80. package/dist/index.js.map +1 -1
  81. package/dist/styles.css +67 -64
  82. package/package.json +2 -2
@@ -0,0 +1,217 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import React, { useState } from "react";
3
+ import { BrandMark } from "../utilities/BrandMark.js";
4
+ import { Button } from "../buttons/Button.js";
5
+ import { Icon } from "../utilities/Icon.js";
6
+ import { Input } from "../inputs/Input.js";
7
+ const AX_SIGNIN_CSS = `
8
+ .ax-signin { display: grid; grid-template-columns: 1fr 1fr; height: 100%; background: var(--surface-page); }
9
+ .ax-signin__brand { position: relative; border-right: 1px solid var(--border-default); background: var(--surface-panel);
10
+ background-image: var(--dot-grid); background-size: 24px 24px; padding: 40px; display: flex; flex-direction: column; }
11
+ .ax-signin__brandtop { display: flex; align-items: center; gap: 10px; }
12
+ .ax-signin__mid { margin-top: auto; margin-bottom: auto; max-width: 22ch; }
13
+ .ax-signin__quote { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-medium); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 0; }
14
+ .ax-signin__by { margin: 16px 0 0; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: var(--text-faint); }
15
+ .ax-signin__form { display: flex; align-items: center; justify-content: center; padding: 40px; }
16
+ .ax-signin__card { width: 100%; max-width: 360px; }
17
+ .ax-signin__mbrand { display: none; }
18
+ .ax-signin__h { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-body); }
19
+ .ax-signin__sub { margin: 8px 0 28px; font-size: var(--text-sm); color: var(--text-muted); }
20
+ .ax-signin__fields { display: flex; flex-direction: column; gap: 16px; }
21
+ .ax-signin__row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 7px; }
22
+ .ax-signin__link { font-size: 12px; color: var(--text-muted); text-decoration: none; background: none; border: none; cursor: pointer; font-family: inherit; }
23
+ .ax-signin__link:hover { color: var(--text-body); }
24
+ .ax-signin__submit { margin-top: 22px; }
25
+ .ax-signin__or { display: flex; align-items: center; gap: 12px; margin: 22px 0; }
26
+ .ax-signin__or::before, .ax-signin__or::after { content: ""; flex: 1; height: 1px; background: var(--border-default); }
27
+ .ax-signin__or span { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; color: var(--text-faint); }
28
+ .ax-signin__sso { display: flex; align-items: center; justify-content: center; gap: 9px; width: 100%; height: 40px; border: 1px solid var(--border-default);
29
+ border-radius: var(--radius-2); background: var(--surface-card); color: var(--text-body); font-family: inherit; font-size: var(--text-sm); cursor: pointer; transition: border-color var(--dur-1) var(--ease-out); }
30
+ .ax-signin__sso:hover { border-color: var(--border-strong); }
31
+ .ax-signin__terms { margin: 16px 0 0; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); text-align: center; }
32
+ .ax-signin__terms a, .ax-signin__terms span.lk { color: var(--text-muted); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
33
+ .ax-signin__foot { margin-top: 26px; text-align: center; font-size: var(--text-sm); color: var(--text-muted); }
34
+ .ax-signin__footlink { color: var(--text-body); background: none; border: none; cursor: pointer; font-family: inherit; font-size: var(--text-sm);
35
+ border-bottom: 1px solid var(--border-strong); padding: 0 0 1px; transition: border-color var(--dur-1) var(--ease-out); }
36
+ .ax-signin__footlink:hover { border-color: var(--text-faint); }
37
+ @media (max-width: 860px) { .ax-signin { grid-template-columns: 1fr; } .ax-signin__brand { display: none; } .ax-signin__mbrand { display: flex; margin-bottom: 26px; } }
38
+ `;
39
+ if (typeof document !== "undefined" && !document.getElementById("ax-signin-css")) {
40
+ const s = document.createElement("style");
41
+ s.id = "ax-signin-css";
42
+ s.textContent = AX_SIGNIN_CSS;
43
+ document.head.appendChild(s);
44
+ }
45
+ const DEFAULT_COPY = {
46
+ signin: {
47
+ title: "Sign in",
48
+ subtitle: "Welcome back. Use your work email to continue.",
49
+ submit: "Continue",
50
+ switchText: "No account?",
51
+ switchCta: "Create one"
52
+ },
53
+ signup: {
54
+ title: "Create account",
55
+ subtitle: "Start with your work email — it takes a minute.",
56
+ submit: "Create account",
57
+ switchText: "Already have an account?",
58
+ switchCta: "Sign in"
59
+ }
60
+ };
61
+ function SignInPage({
62
+ mode,
63
+ defaultMode = "signin",
64
+ onModeChange,
65
+ brand,
66
+ copy,
67
+ email,
68
+ password,
69
+ onEmailChange,
70
+ onPasswordChange,
71
+ onSubmit,
72
+ onForgot,
73
+ ssoLabel = "Continue with SSO",
74
+ onSSO,
75
+ terms,
76
+ footer,
77
+ showBrandPanel = true
78
+ }) {
79
+ const [modeI, setModeI] = useState(defaultMode);
80
+ const m = mode !== void 0 ? mode : modeI;
81
+ const isSignup = m === "signup";
82
+ const c = { ...DEFAULT_COPY[m], ...copy && copy[m] };
83
+ const [emailI, setEmailI] = useState("");
84
+ const [pwI, setPwI] = useState("");
85
+ const [confirm, setConfirm] = useState("");
86
+ const [errs, setErrs] = useState({});
87
+ const emailV = email !== void 0 ? email : emailI;
88
+ const pwV = password !== void 0 ? password : pwI;
89
+ const setEmail = (v) => {
90
+ if (onEmailChange) onEmailChange(v);
91
+ else setEmailI(v);
92
+ if (errs.email) setErrs((e) => ({ ...e, email: void 0 }));
93
+ };
94
+ const setPw = (v) => {
95
+ if (onPasswordChange) onPasswordChange(v);
96
+ else setPwI(v);
97
+ if (errs.password) setErrs((e) => ({ ...e, password: void 0 }));
98
+ };
99
+ const setConf = (v) => {
100
+ setConfirm(v);
101
+ if (errs.confirm) setErrs((e) => ({ ...e, confirm: void 0 }));
102
+ };
103
+ const switchMode = () => {
104
+ const next = isSignup ? "signin" : "signup";
105
+ setErrs({});
106
+ setConfirm("");
107
+ if (onModeChange) onModeChange(next);
108
+ if (mode === void 0) setModeI(next);
109
+ };
110
+ const validate = () => {
111
+ const e = {};
112
+ const em = (emailV || "").trim();
113
+ if (!em) e.email = "请输入邮箱";
114
+ else if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(em)) e.email = "邮箱格式不正确";
115
+ if (!pwV) e.password = "请输入密码";
116
+ else if (isSignup && pwV.length < 8) e.password = "密码至少 8 位";
117
+ if (isSignup) {
118
+ if (!confirm) e.confirm = "请再次输入密码";
119
+ else if (confirm !== pwV) e.confirm = "两次输入的密码不一致";
120
+ }
121
+ return e;
122
+ };
123
+ const submit = (ev) => {
124
+ ev.preventDefault();
125
+ const e = validate();
126
+ setErrs(e);
127
+ if (Object.keys(e).some((k) => e[k])) return;
128
+ onSubmit && onSubmit({ mode: m, email: (emailV || "").trim(), password: pwV });
129
+ };
130
+ const termsNode = terms !== void 0 ? terms : /* @__PURE__ */ jsxs(Fragment, { children: [
131
+ "注册即代表你同意 ",
132
+ /* @__PURE__ */ jsx("span", { className: "lk", children: "服务条款" }),
133
+ " 与",
134
+ " ",
135
+ /* @__PURE__ */ jsx("span", { className: "lk", children: "隐私政策" }),
136
+ "。"
137
+ ] });
138
+ return /* @__PURE__ */ jsxs("div", { className: "ax-signin", children: [
139
+ showBrandPanel ? /* @__PURE__ */ jsxs("aside", { className: "ax-signin__brand", children: [
140
+ /* @__PURE__ */ jsx("div", { className: "ax-signin__brandtop", children: brand || /* @__PURE__ */ jsx(BrandMark, { size: 24, wordmark: true }) }),
141
+ /* @__PURE__ */ jsxs("div", { className: "ax-signin__mid", children: [
142
+ /* @__PURE__ */ jsxs("p", { className: "ax-signin__quote", children: [
143
+ "聊天,",
144
+ /* @__PURE__ */ jsx("br", {}),
145
+ "构建万物"
146
+ ] }),
147
+ /* @__PURE__ */ jsx("p", { className: "ax-signin__by", children: "— AGENTAILY" })
148
+ ] })
149
+ ] }) : null,
150
+ /* @__PURE__ */ jsx("main", { className: "ax-signin__form", children: /* @__PURE__ */ jsxs("form", { className: "ax-signin__card", onSubmit: submit, noValidate: true, children: [
151
+ /* @__PURE__ */ jsx("div", { className: "ax-signin__mbrand", children: brand || /* @__PURE__ */ jsx(BrandMark, { size: 22, wordmark: true }) }),
152
+ /* @__PURE__ */ jsx("h1", { className: "ax-signin__h", children: c.title }),
153
+ /* @__PURE__ */ jsx("p", { className: "ax-signin__sub", children: c.subtitle }),
154
+ /* @__PURE__ */ jsxs("div", { className: "ax-signin__fields", children: [
155
+ /* @__PURE__ */ jsx(
156
+ Input,
157
+ {
158
+ label: "EMAIL",
159
+ type: "email",
160
+ autoComplete: "email",
161
+ placeholder: "you@example.com",
162
+ value: emailV,
163
+ error: errs.email,
164
+ onChange: (e) => setEmail(e.target.value)
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxs("div", { children: [
168
+ /* @__PURE__ */ jsxs("div", { className: "ax-signin__row", children: [
169
+ /* @__PURE__ */ jsx("span", { className: "ax-label", children: "PASSWORD" }),
170
+ !isSignup && onForgot ? /* @__PURE__ */ jsx("button", { type: "button", className: "ax-signin__link", onClick: onForgot, children: "Forgot?" }) : null
171
+ ] }),
172
+ /* @__PURE__ */ jsx(
173
+ Input,
174
+ {
175
+ type: "password",
176
+ autoComplete: isSignup ? "new-password" : "current-password",
177
+ placeholder: isSignup ? "至少 8 位" : "••••••••",
178
+ value: pwV,
179
+ error: errs.password,
180
+ onChange: (e) => setPw(e.target.value)
181
+ }
182
+ )
183
+ ] }),
184
+ isSignup ? /* @__PURE__ */ jsx(
185
+ Input,
186
+ {
187
+ label: "CONFIRM PASSWORD",
188
+ type: "password",
189
+ autoComplete: "new-password",
190
+ placeholder: "再次输入密码",
191
+ value: confirm,
192
+ error: errs.confirm,
193
+ onChange: (e) => setConf(e.target.value)
194
+ }
195
+ ) : null
196
+ ] }),
197
+ /* @__PURE__ */ jsx("div", { className: "ax-signin__submit", children: /* @__PURE__ */ jsx(Button, { variant: "primary", full: true, type: "submit", icon: /* @__PURE__ */ jsx(Icon, { name: "arrow", size: 15 }), children: c.submit }) }),
198
+ isSignup ? /* @__PURE__ */ jsx("p", { className: "ax-signin__terms", children: termsNode }) : null,
199
+ onSSO ? /* @__PURE__ */ jsxs(React.Fragment, { children: [
200
+ /* @__PURE__ */ jsx("div", { className: "ax-signin__or", children: /* @__PURE__ */ jsx("span", { children: "OR" }) }),
201
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "ax-signin__sso", onClick: onSSO, children: [
202
+ /* @__PURE__ */ jsx(Icon, { name: "shield", size: 15 }),
203
+ ssoLabel
204
+ ] })
205
+ ] }) : null,
206
+ footer !== void 0 ? footer ? /* @__PURE__ */ jsx("p", { className: "ax-signin__foot", children: footer }) : null : /* @__PURE__ */ jsxs("p", { className: "ax-signin__foot", children: [
207
+ c.switchText,
208
+ " ",
209
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ax-signin__footlink", onClick: switchMode, children: c.switchCta })
210
+ ] })
211
+ ] }) })
212
+ ] });
213
+ }
214
+ export {
215
+ SignInPage
216
+ };
217
+ //# sourceMappingURL=SignInPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInPage.js","sources":["../../../src/components/auth/SignInPage.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\nimport { Button } from \"../buttons/Button.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\nimport { Input } from \"../inputs/Input.jsx\";\n\n// SignInPage — full-page auth: a split brand panel (dot-grid + quote) beside a\n// centered card. One component, two modes (signin / signup) — the brand panel,\n// SSO, and card chrome are shared; only the fields, copy, and footer differ.\n// The footer link flips mode (and fires onModeChange so a router can swap the\n// URL). The full-page sibling of AuthDialog (the modal); same login/register idea.\nconst AX_SIGNIN_CSS = `\n.ax-signin { display: grid; grid-template-columns: 1fr 1fr; height: 100%; background: var(--surface-page); }\n.ax-signin__brand { position: relative; border-right: 1px solid var(--border-default); background: var(--surface-panel);\n background-image: var(--dot-grid); background-size: 24px 24px; padding: 40px; display: flex; flex-direction: column; }\n.ax-signin__brandtop { display: flex; align-items: center; gap: 10px; }\n.ax-signin__mid { margin-top: auto; margin-bottom: auto; max-width: 22ch; }\n.ax-signin__quote { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-medium); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 0; }\n.ax-signin__by { margin: 16px 0 0; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: var(--text-faint); }\n.ax-signin__form { display: flex; align-items: center; justify-content: center; padding: 40px; }\n.ax-signin__card { width: 100%; max-width: 360px; }\n.ax-signin__mbrand { display: none; }\n.ax-signin__h { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-body); }\n.ax-signin__sub { margin: 8px 0 28px; font-size: var(--text-sm); color: var(--text-muted); }\n.ax-signin__fields { display: flex; flex-direction: column; gap: 16px; }\n.ax-signin__row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 7px; }\n.ax-signin__link { font-size: 12px; color: var(--text-muted); text-decoration: none; background: none; border: none; cursor: pointer; font-family: inherit; }\n.ax-signin__link:hover { color: var(--text-body); }\n.ax-signin__submit { margin-top: 22px; }\n.ax-signin__or { display: flex; align-items: center; gap: 12px; margin: 22px 0; }\n.ax-signin__or::before, .ax-signin__or::after { content: \"\"; flex: 1; height: 1px; background: var(--border-default); }\n.ax-signin__or span { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; color: var(--text-faint); }\n.ax-signin__sso { display: flex; align-items: center; justify-content: center; gap: 9px; width: 100%; height: 40px; border: 1px solid var(--border-default);\n border-radius: var(--radius-2); background: var(--surface-card); color: var(--text-body); font-family: inherit; font-size: var(--text-sm); cursor: pointer; transition: border-color var(--dur-1) var(--ease-out); }\n.ax-signin__sso:hover { border-color: var(--border-strong); }\n.ax-signin__terms { margin: 16px 0 0; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); text-align: center; }\n.ax-signin__terms a, .ax-signin__terms span.lk { color: var(--text-muted); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }\n.ax-signin__foot { margin-top: 26px; text-align: center; font-size: var(--text-sm); color: var(--text-muted); }\n.ax-signin__footlink { color: var(--text-body); background: none; border: none; cursor: pointer; font-family: inherit; font-size: var(--text-sm);\n border-bottom: 1px solid var(--border-strong); padding: 0 0 1px; transition: border-color var(--dur-1) var(--ease-out); }\n.ax-signin__footlink:hover { border-color: var(--text-faint); }\n@media (max-width: 860px) { .ax-signin { grid-template-columns: 1fr; } .ax-signin__brand { display: none; } .ax-signin__mbrand { display: flex; margin-bottom: 26px; } }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-signin-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-signin-css\";\n s.textContent = AX_SIGNIN_CSS;\n document.head.appendChild(s);\n}\n\nconst DEFAULT_COPY = {\n signin: {\n title: \"Sign in\",\n subtitle: \"Welcome back. Use your work email to continue.\",\n submit: \"Continue\",\n switchText: \"No account?\",\n switchCta: \"Create one\",\n },\n signup: {\n title: \"Create account\",\n subtitle: \"Start with your work email — it takes a minute.\",\n submit: \"Create account\",\n switchText: \"Already have an account?\",\n switchCta: \"Sign in\",\n },\n};\n\nexport function SignInPage({\n mode,\n defaultMode = \"signin\",\n onModeChange,\n brand,\n copy,\n email,\n password,\n onEmailChange,\n onPasswordChange,\n onSubmit,\n onForgot,\n ssoLabel = \"Continue with SSO\",\n onSSO,\n terms,\n footer,\n showBrandPanel = true,\n}) {\n const [modeI, setModeI] = useState(defaultMode);\n const m = mode !== undefined ? mode : modeI;\n const isSignup = m === \"signup\";\n const c = { ...DEFAULT_COPY[m], ...(copy && copy[m]) };\n\n const [emailI, setEmailI] = useState(\"\");\n const [pwI, setPwI] = useState(\"\");\n const [confirm, setConfirm] = useState(\"\");\n const [errs, setErrs] = useState({});\n const emailV = email !== undefined ? email : emailI;\n const pwV = password !== undefined ? password : pwI;\n const setEmail = (v) => {\n if (onEmailChange) onEmailChange(v);\n else setEmailI(v);\n if (errs.email) setErrs((e) => ({ ...e, email: undefined }));\n };\n const setPw = (v) => {\n if (onPasswordChange) onPasswordChange(v);\n else setPwI(v);\n if (errs.password) setErrs((e) => ({ ...e, password: undefined }));\n };\n const setConf = (v) => {\n setConfirm(v);\n if (errs.confirm) setErrs((e) => ({ ...e, confirm: undefined }));\n };\n\n const switchMode = () => {\n const next = isSignup ? \"signin\" : \"signup\";\n setErrs({});\n setConfirm(\"\");\n if (onModeChange) onModeChange(next);\n if (mode === undefined) setModeI(next);\n };\n\n const validate = () => {\n const e = {};\n const em = (emailV || \"\").trim();\n if (!em) e.email = \"请输入邮箱\";\n else if (!/^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(em)) e.email = \"邮箱格式不正确\";\n if (!pwV) e.password = \"请输入密码\";\n else if (isSignup && pwV.length < 8) e.password = \"密码至少 8 位\";\n if (isSignup) {\n if (!confirm) e.confirm = \"请再次输入密码\";\n else if (confirm !== pwV) e.confirm = \"两次输入的密码不一致\";\n }\n return e;\n };\n\n const submit = (ev) => {\n ev.preventDefault();\n const e = validate();\n setErrs(e);\n if (Object.keys(e).some((k) => e[k])) return;\n onSubmit && onSubmit({ mode: m, email: (emailV || \"\").trim(), password: pwV });\n };\n\n const termsNode =\n terms !== undefined ? (\n terms\n ) : (\n <>\n 注册即代表你同意 <span className=\"lk\">服务条款</span> 与{\" \"}\n <span className=\"lk\">隐私政策</span>。\n </>\n );\n\n return (\n <div className=\"ax-signin\">\n {showBrandPanel ? (\n <aside className=\"ax-signin__brand\">\n <div className=\"ax-signin__brandtop\">{brand || <BrandMark size={24} wordmark />}</div>\n <div className=\"ax-signin__mid\">\n <p className=\"ax-signin__quote\">\n 聊天,\n <br />\n 构建万物\n </p>\n <p className=\"ax-signin__by\">— AGENTAILY</p>\n </div>\n </aside>\n ) : null}\n\n <main className=\"ax-signin__form\">\n <form className=\"ax-signin__card\" onSubmit={submit} noValidate>\n <div className=\"ax-signin__mbrand\">{brand || <BrandMark size={22} wordmark />}</div>\n <h1 className=\"ax-signin__h\">{c.title}</h1>\n <p className=\"ax-signin__sub\">{c.subtitle}</p>\n\n <div className=\"ax-signin__fields\">\n <Input\n label=\"EMAIL\"\n type=\"email\"\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={emailV}\n error={errs.email}\n onChange={(e) => setEmail(e.target.value)}\n />\n <div>\n <div className=\"ax-signin__row\">\n <span className=\"ax-label\">PASSWORD</span>\n {!isSignup && onForgot ? (\n <button type=\"button\" className=\"ax-signin__link\" onClick={onForgot}>\n Forgot?\n </button>\n ) : null}\n </div>\n <Input\n type=\"password\"\n autoComplete={isSignup ? \"new-password\" : \"current-password\"}\n placeholder={isSignup ? \"至少 8 位\" : \"••••••••\"}\n value={pwV}\n error={errs.password}\n onChange={(e) => setPw(e.target.value)}\n />\n </div>\n {isSignup ? (\n <Input\n label=\"CONFIRM PASSWORD\"\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder=\"再次输入密码\"\n value={confirm}\n error={errs.confirm}\n onChange={(e) => setConf(e.target.value)}\n />\n ) : null}\n </div>\n\n <div className=\"ax-signin__submit\">\n <Button variant=\"primary\" full type=\"submit\" icon={<Icon name=\"arrow\" size={15} />}>\n {c.submit}\n </Button>\n </div>\n\n {isSignup ? <p className=\"ax-signin__terms\">{termsNode}</p> : null}\n\n {onSSO ? (\n <React.Fragment>\n <div className=\"ax-signin__or\">\n <span>OR</span>\n </div>\n <button type=\"button\" className=\"ax-signin__sso\" onClick={onSSO}>\n <Icon name=\"shield\" size={15} />\n {ssoLabel}\n </button>\n </React.Fragment>\n ) : null}\n\n {footer !== undefined ? (\n footer ? (\n <p className=\"ax-signin__foot\">{footer}</p>\n ) : null\n ) : (\n <p className=\"ax-signin__foot\">\n {c.switchText}{\" \"}\n <button type=\"button\" className=\"ax-signin__footlink\" onClick={switchMode}>\n {c.switchCta}\n </button>\n </p>\n )}\n </form>\n </main>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -5,9 +5,10 @@ const AX_CODE_CSS = `
5
5
  border: 1px solid var(--border-default);
6
6
  border-radius: var(--radius-2);
7
7
  overflow: hidden;
8
- background: var(--bg-0);
8
+ background: var(--bg-1);
9
9
  }
10
- [data-theme="light"] .ax-code, .ax-code--paper { background: var(--bg-1); }
10
+ [data-theme="dark"] .ax-code { background: var(--bg-0); }
11
+ .ax-code--paper { background: var(--bg-1); }
11
12
  .ax-code__head {
12
13
  display: flex; align-items: center; justify-content: space-between;
13
14
  padding: 6px 12px;
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.js","sources":["../../../src/components/chat/CodeBlock.jsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nconst AX_CODE_CSS = `\n.ax-code {\n border: 1px solid var(--border-default);\n border-radius: var(--radius-2);\n overflow: hidden;\n background: var(--bg-0);\n}\n[data-theme=\"light\"] .ax-code, .ax-code--paper { background: var(--bg-1); }\n.ax-code__head {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 12px;\n border-bottom: 1px solid var(--border-default);\n background: var(--surface-card);\n}\n.ax-code__lang {\n font-family: var(--font-mono); font-size: var(--text-xs);\n letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint);\n}\n.ax-code__copy {\n appearance: none; background: none; border: none; cursor: pointer;\n font-family: var(--font-mono); font-size: var(--text-xs);\n color: var(--text-faint); padding: 2px 6px; border-radius: var(--radius-1);\n transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out);\n}\n.ax-code__copy:hover { color: var(--text-body); background: var(--surface-raised); }\n.ax-code__pre {\n margin: 0; padding: 14px 16px; overflow-x: auto;\n font-family: var(--font-mono); font-size: var(--text-sm);\n line-height: 1.7; color: var(--text-body);\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-code-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-code-css\";\n s.textContent = AX_CODE_CSS;\n document.head.appendChild(s);\n}\n\nexport function CodeBlock({ code = \"\", lang = \"text\", className = \"\", ...rest }) {\n const [copied, setCopied] = useState(false);\n const copy = () => {\n try {\n navigator.clipboard && navigator.clipboard.writeText(code);\n } catch (e) { /* noop */ }\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n return (\n <div className={[\"ax-code\", className].filter(Boolean).join(\" \")} {...rest}>\n <div className=\"ax-code__head\">\n <span className=\"ax-code__lang\">{lang}</span>\n <button type=\"button\" className=\"ax-code__copy\" onClick={copy}>\n {copied ? \"copied ✓\" : \"copy\"}\n </button>\n </div>\n <pre className=\"ax-code__pre\"><code>{code}</code></pre>\n </div>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCpB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,aAAa,GAAG;AAC9E,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU,EAAE,OAAO,IAAI,OAAO,QAAQ,YAAY,IAAI,GAAG,QAAQ;AAC/E,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,OAAO,MAAM;AACjB,QAAI;AACF,gBAAU,aAAa,UAAU,UAAU,UAAU,IAAI;AAAA,IAC3D,SAAS,GAAG;AAAA,IAAa;AACzB,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,EACzC;AACA,SACE,qBAAC,OAAA,EAAI,WAAW,CAAC,WAAW,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MACpE,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,iBACb,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,iBAAiB,UAAA,MAAK;AAAA,MACtC,oBAAC,UAAA,EAAO,MAAK,UAAS,WAAU,iBAAgB,SAAS,MACtD,UAAA,SAAS,aAAa,OAAA,CACzB;AAAA,IAAA,GACF;AAAA,wBACC,OAAA,EAAI,WAAU,gBAAe,UAAA,oBAAC,QAAA,EAAM,gBAAK,EAAA,CAAO;AAAA,EAAA,GACnD;AAEJ;"}
1
+ {"version":3,"file":"CodeBlock.js","sources":["../../../src/components/chat/CodeBlock.jsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nconst AX_CODE_CSS = `\n.ax-code {\n border: 1px solid var(--border-default);\n border-radius: var(--radius-2);\n overflow: hidden;\n background: var(--bg-1);\n}\n[data-theme=\"dark\"] .ax-code { background: var(--bg-0); }\n.ax-code--paper { background: var(--bg-1); }\n.ax-code__head {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 12px;\n border-bottom: 1px solid var(--border-default);\n background: var(--surface-card);\n}\n.ax-code__lang {\n font-family: var(--font-mono); font-size: var(--text-xs);\n letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint);\n}\n.ax-code__copy {\n appearance: none; background: none; border: none; cursor: pointer;\n font-family: var(--font-mono); font-size: var(--text-xs);\n color: var(--text-faint); padding: 2px 6px; border-radius: var(--radius-1);\n transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out);\n}\n.ax-code__copy:hover { color: var(--text-body); background: var(--surface-raised); }\n.ax-code__pre {\n margin: 0; padding: 14px 16px; overflow-x: auto;\n font-family: var(--font-mono); font-size: var(--text-sm);\n line-height: 1.7; color: var(--text-body);\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-code-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-code-css\";\n s.textContent = AX_CODE_CSS;\n document.head.appendChild(s);\n}\n\nexport function CodeBlock({ code = \"\", lang = \"text\", className = \"\", ...rest }) {\n const [copied, setCopied] = useState(false);\n const copy = () => {\n try {\n navigator.clipboard && navigator.clipboard.writeText(code);\n } catch (e) {\n /* noop */\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n return (\n <div className={[\"ax-code\", className].filter(Boolean).join(\" \")} {...rest}>\n <div className=\"ax-code__head\">\n <span className=\"ax-code__lang\">{lang}</span>\n <button type=\"button\" className=\"ax-code__copy\" onClick={copy}>\n {copied ? \"copied ✓\" : \"copy\"}\n </button>\n </div>\n <pre className=\"ax-code__pre\">\n <code>{code}</code>\n </pre>\n </div>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCpB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,aAAa,GAAG;AAC9E,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU,EAAE,OAAO,IAAI,OAAO,QAAQ,YAAY,IAAI,GAAG,QAAQ;AAC/E,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,OAAO,MAAM;AACjB,QAAI;AACF,gBAAU,aAAa,UAAU,UAAU,UAAU,IAAI;AAAA,IAC3D,SAAS,GAAG;AAAA,IAEZ;AACA,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,EACzC;AACA,SACE,qBAAC,OAAA,EAAI,WAAW,CAAC,WAAW,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MACpE,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,iBACb,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,iBAAiB,UAAA,MAAK;AAAA,MACtC,oBAAC,UAAA,EAAO,MAAK,UAAS,WAAU,iBAAgB,SAAS,MACtD,UAAA,SAAS,aAAa,OAAA,CACzB;AAAA,IAAA,GACF;AAAA,wBACC,OAAA,EAAI,WAAU,gBACb,UAAA,oBAAC,QAAA,EAAM,gBAAK,EAAA,CACd;AAAA,EAAA,GACF;AAEJ;"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Pure-render chat surface. State lives OUTSIDE: the caller holds the queue
3
+ * (`const q = Queue.useQueue({ onFirst, onBatch })`) and injects it as
4
+ * `controller`. The composer enqueues into it; the buffer list + busy state read
5
+ * from it; the caller can also enqueue programmatically and read `controller.busy`
6
+ * elsewhere. The component never owns chat state.
7
+ */
8
+ export interface ThreadMessage {
9
+ id?: string | number;
10
+ role: "user" | "assistant";
11
+ /** Plain text for the default renderer; optional when you supply renderTurn. */
12
+ text?: string;
13
+ /** Optional mono timestamp on assistant turns. */
14
+ time?: string;
15
+ /** Per-message streaming flag (read by renderTurn via ctx.streaming). */
16
+ streaming?: boolean;
17
+ /** Free-form turn kind for renderTurn dispatch, e.g. "reasoning" | "tool" | "text". */
18
+ kind?: string;
19
+ /** Any extra fields your renderTurn needs (steps, duration, name, args, result, status, suggestions, …). */
20
+ [key: string]: any;
21
+ }
22
+ export interface TurnContext {
23
+ /** Whether this turn is currently streaming. */
24
+ streaming: boolean;
25
+ /** Whether this is the last turn in the thread. */
26
+ isLast: boolean;
27
+ }
28
+ export interface ConversationThreadProps {
29
+ /** @default "New chat" */
30
+ title?: string;
31
+ /** Model chip + Composer model label. @default "agentaily-2" */
32
+ model?: string;
33
+ /** Header right-side actions (share/settings…). */
34
+ actions?: React.ReactNode;
35
+ messages?: ThreadMessage[];
36
+ draft?: string;
37
+ onDraftChange?: (value: string) => void;
38
+ /** The queue that drives this thread: a Queue.useQueue(...) return value held by the caller. */
39
+ controller?: import("../ai/Queue").UseQueueReturn;
40
+ /** Buffer list title. @default "缓冲区 · 下一轮一起发" */
41
+ queueTitle?: string;
42
+ disabled?: boolean;
43
+ /** Empty-state hint chips. */
44
+ hints?: string[];
45
+ /** Hint-click handler; defaults to sending the hint. */
46
+ onHint?: (hint: string) => void;
47
+ /** @default "有什么要解决的?" */
48
+ emptyTitle?: string;
49
+ /** Composer placeholder when idle. */
50
+ placeholder?: string;
51
+ /** Composer placeholder while the queue is draining (busy). */
52
+ busyPlaceholder?: string;
53
+ /** Mono footer disclaimer; pass "" to hide. */
54
+ note?: string;
55
+ /** Show a Copy tool under assistant turns. */
56
+ onCopy?: (message: ThreadMessage, index: number) => void;
57
+ /** Show a Regenerate tool under assistant turns. */
58
+ onRegenerate?: (message: ThreadMessage, index: number) => void;
59
+ /**
60
+ * Custom turn renderer. When provided, each turn is rendered by this instead of
61
+ * the default plain-text <Message>. Use it for rich turns with Reasoning /
62
+ * ToolCall / Suggestions / Message. Per-message `streaming` is surfaced via
63
+ * ctx.streaming. Omit for the plain-text default.
64
+ */
65
+ renderTurn?: (message: ThreadMessage, index: number, ctx: TurnContext) => React.ReactNode;
66
+ }
67
+ export declare function ConversationThread(props: ConversationThreadProps): JSX.Element;
@@ -0,0 +1,129 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React, { useRef, useEffect } from "react";
3
+ import { Badge } from "../display/Badge.js";
4
+ import { BrandMark } from "../utilities/BrandMark.js";
5
+ import { Composer } from "./Composer.js";
6
+ import { Icon } from "../utilities/Icon.js";
7
+ import { IconButton } from "../buttons/IconButton.js";
8
+ import { Message } from "./Message.js";
9
+ import { Queue } from "../ai/Queue.js";
10
+ const AX_CTHREAD_CSS = `
11
+ .ax-cthread { display: flex; flex-direction: column; height: 100%; background: var(--surface-page); }
12
+ .ax-cthread__head { display: flex; align-items: center; gap: 12px; height: var(--bar-h); padding: 0 20px; border-bottom: 1px solid var(--border-default); flex: none; }
13
+ .ax-cthread__title { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-body); margin: 0; }
14
+ .ax-cthread__sp { flex: 1; }
15
+ .ax-cthread__thread { flex: 1; overflow-y: auto; }
16
+ .ax-cthread__col { max-width: var(--thread-max, 760px); margin: 0 auto; padding: 32px 24px 16px; display: flex; flex-direction: column; gap: 24px; }
17
+ .ax-cthread__turn { display: flex; flex-direction: column; }
18
+ .ax-cthread__tools { display: flex; gap: 2px; margin-top: 6px; opacity: 0; transition: opacity var(--dur-1) var(--ease-out); }
19
+ .ax-cthread__turn:hover .ax-cthread__tools { opacity: 1; }
20
+ .ax-cthread__empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 40px; }
21
+ .ax-cthread__emptyh { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-medium); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 12px 0 0; }
22
+ .ax-cthread__hints { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; justify-content: center; }
23
+ .ax-cthread__hint { appearance: none; cursor: pointer; background: none; border: 1px solid var(--border-default); border-radius: var(--radius-2);
24
+ padding: 7px 12px; font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-muted); transition: border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }
25
+ .ax-cthread__hint:hover { border-color: var(--border-strong); color: var(--text-body); }
26
+ .ax-cthread__foot { padding: 8px 24px 14px; flex: none; }
27
+ .ax-cthread__footcol { max-width: var(--thread-max, 760px); margin: 0 auto; }
28
+ .ax-cthread__queue { margin-bottom: 10px; }
29
+ .ax-cthread__note { text-align: center; font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); margin: 8px 0 0; }
30
+ `;
31
+ if (typeof document !== "undefined" && !document.getElementById("ax-cthread-css")) {
32
+ const s = document.createElement("style");
33
+ s.id = "ax-cthread-css";
34
+ s.textContent = AX_CTHREAD_CSS;
35
+ document.head.appendChild(s);
36
+ }
37
+ function ConversationThread({
38
+ title = "New chat",
39
+ model = "agentaily-2",
40
+ actions,
41
+ messages = [],
42
+ draft = "",
43
+ onDraftChange,
44
+ controller,
45
+ queueTitle = "缓冲区 · 下一轮一起发",
46
+ disabled = false,
47
+ hints = [],
48
+ onHint,
49
+ emptyTitle = "有什么要解决的?",
50
+ placeholder = "Message Agentaily…",
51
+ busyPlaceholder = "可继续输入,会收进缓冲区一起处理…",
52
+ note = "AGENTAILY MAY MAKE MISTAKES · VERIFY CRITICAL OUTPUT",
53
+ onCopy,
54
+ onRegenerate,
55
+ renderTurn
56
+ }) {
57
+ const queue = controller ? controller.queue : [];
58
+ const busy = controller ? controller.busy : false;
59
+ const threadRef = useRef(null);
60
+ useEffect(() => {
61
+ const el = threadRef.current;
62
+ if (el) el.scrollTop = el.scrollHeight;
63
+ }, [messages, queue.length]);
64
+ const send = (text) => {
65
+ const t = (text || "").trim();
66
+ if (!t || !controller) return;
67
+ controller.enqueue(t);
68
+ if (onDraftChange) onDraftChange("");
69
+ };
70
+ const empty = messages.length === 0 && queue.length === 0;
71
+ const showTools = onCopy || onRegenerate;
72
+ return /* @__PURE__ */ jsxs("div", { className: "ax-cthread", children: [
73
+ /* @__PURE__ */ jsxs("header", { className: "ax-cthread__head", children: [
74
+ /* @__PURE__ */ jsx("h1", { className: "ax-cthread__title", children: title }),
75
+ model ? /* @__PURE__ */ jsx(Badge, { variant: "outline", children: model }) : null,
76
+ /* @__PURE__ */ jsx("span", { className: "ax-cthread__sp" }),
77
+ actions
78
+ ] }),
79
+ empty ? /* @__PURE__ */ jsxs("div", { className: "ax-cthread__empty ax-dotgrid", children: [
80
+ /* @__PURE__ */ jsx(BrandMark, { size: 40 }),
81
+ /* @__PURE__ */ jsx("h2", { className: "ax-cthread__emptyh", children: emptyTitle }),
82
+ hints.length ? /* @__PURE__ */ jsx("div", { className: "ax-cthread__hints", children: hints.map((h) => /* @__PURE__ */ jsx(
83
+ "button",
84
+ {
85
+ className: "ax-cthread__hint",
86
+ onClick: () => onHint ? onHint(h) : send(h),
87
+ children: h
88
+ },
89
+ h
90
+ )) }) : null
91
+ ] }) : /* @__PURE__ */ jsx("div", { className: "ax-cthread__thread", ref: threadRef, children: /* @__PURE__ */ jsx("div", { className: "ax-cthread__col", children: messages.map((m, idx) => /* @__PURE__ */ jsx("div", { className: "ax-cthread__turn", children: renderTurn ? renderTurn(m, idx, {
92
+ streaming: !!m.streaming,
93
+ isLast: idx === messages.length - 1
94
+ }) : /* @__PURE__ */ jsxs(React.Fragment, { children: [
95
+ /* @__PURE__ */ jsx(Message, { role: m.role, time: m.time, streaming: !!m.streaming, children: /* @__PURE__ */ jsx("p", { children: m.text }) }),
96
+ m.role === "assistant" && showTools ? /* @__PURE__ */ jsxs("div", { className: "ax-cthread__tools", children: [
97
+ onCopy ? /* @__PURE__ */ jsx(IconButton, { size: "sm", label: "Copy", onClick: () => onCopy(m, idx), children: /* @__PURE__ */ jsx(Icon, { name: "copy", size: 13 }) }) : null,
98
+ onRegenerate ? /* @__PURE__ */ jsx(
99
+ IconButton,
100
+ {
101
+ size: "sm",
102
+ label: "Regenerate",
103
+ onClick: () => onRegenerate(m, idx),
104
+ children: /* @__PURE__ */ jsx(Icon, { name: "refresh", size: 13 })
105
+ }
106
+ ) : null
107
+ ] }) : null
108
+ ] }) }, m.id != null ? m.id : idx)) }) }),
109
+ /* @__PURE__ */ jsx("div", { className: "ax-cthread__foot", children: /* @__PURE__ */ jsxs("div", { className: "ax-cthread__footcol", children: [
110
+ queue.length > 0 ? /* @__PURE__ */ jsx("div", { className: "ax-cthread__queue", children: /* @__PURE__ */ jsx(Queue, { title: queueTitle, items: queue, onRemove: controller.remove }) }) : null,
111
+ /* @__PURE__ */ jsx(
112
+ Composer,
113
+ {
114
+ value: draft,
115
+ onChange: onDraftChange,
116
+ onSend: () => send(draft),
117
+ disabled,
118
+ placeholder: busy ? busyPlaceholder : placeholder,
119
+ model
120
+ }
121
+ ),
122
+ note ? /* @__PURE__ */ jsx("p", { className: "ax-cthread__note", children: note }) : null
123
+ ] }) })
124
+ ] });
125
+ }
126
+ export {
127
+ ConversationThread
128
+ };
129
+ //# sourceMappingURL=ConversationThread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationThread.js","sources":["../../../src/components/chat/ConversationThread.jsx"],"sourcesContent":["import React, { useRef, useEffect } from \"react\";\nimport { Badge } from \"../display/Badge.jsx\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\nimport { Composer } from \"./Composer.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\nimport { IconButton } from \"../buttons/IconButton.jsx\";\nimport { Message } from \"./Message.jsx\";\nimport { Queue } from \"../ai/Queue.jsx\";\n\n// ConversationThread — a pure-render chat surface: header (title · model ·\n// actions), an empty state with hint chips, a scrolling thread of turns, and a\n// pinned Composer. State lives OUTSIDE: the caller holds the queue\n// (Queue.useQueue) and injects it as `controller`. The component only renders.\n//\n// The composer enqueues into the controller; the buffer list, busy state, and\n// \"keep typing while busy\" all flow through it — and because the caller owns the\n// hook, it can also enqueue programmatically and read controller.busy elsewhere.\nconst AX_CTHREAD_CSS = `\n.ax-cthread { display: flex; flex-direction: column; height: 100%; background: var(--surface-page); }\n.ax-cthread__head { display: flex; align-items: center; gap: 12px; height: var(--bar-h); padding: 0 20px; border-bottom: 1px solid var(--border-default); flex: none; }\n.ax-cthread__title { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-body); margin: 0; }\n.ax-cthread__sp { flex: 1; }\n.ax-cthread__thread { flex: 1; overflow-y: auto; }\n.ax-cthread__col { max-width: var(--thread-max, 760px); margin: 0 auto; padding: 32px 24px 16px; display: flex; flex-direction: column; gap: 24px; }\n.ax-cthread__turn { display: flex; flex-direction: column; }\n.ax-cthread__tools { display: flex; gap: 2px; margin-top: 6px; opacity: 0; transition: opacity var(--dur-1) var(--ease-out); }\n.ax-cthread__turn:hover .ax-cthread__tools { opacity: 1; }\n.ax-cthread__empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 40px; }\n.ax-cthread__emptyh { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-medium); letter-spacing: var(--tracking-tight); color: var(--text-body); margin: 12px 0 0; }\n.ax-cthread__hints { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; justify-content: center; }\n.ax-cthread__hint { appearance: none; cursor: pointer; background: none; border: 1px solid var(--border-default); border-radius: var(--radius-2);\n padding: 7px 12px; font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-muted); transition: border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }\n.ax-cthread__hint:hover { border-color: var(--border-strong); color: var(--text-body); }\n.ax-cthread__foot { padding: 8px 24px 14px; flex: none; }\n.ax-cthread__footcol { max-width: var(--thread-max, 760px); margin: 0 auto; }\n.ax-cthread__queue { margin-bottom: 10px; }\n.ax-cthread__note { text-align: center; font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); margin: 8px 0 0; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-cthread-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-cthread-css\";\n s.textContent = AX_CTHREAD_CSS;\n document.head.appendChild(s);\n}\n\nexport function ConversationThread({\n title = \"New chat\",\n model = \"agentaily-2\",\n actions,\n messages = [],\n draft = \"\",\n onDraftChange,\n controller,\n queueTitle = \"缓冲区 · 下一轮一起发\",\n disabled = false,\n hints = [],\n onHint,\n emptyTitle = \"有什么要解决的?\",\n placeholder = \"Message Agentaily…\",\n busyPlaceholder = \"可继续输入,会收进缓冲区一起处理…\",\n note = \"AGENTAILY MAY MAKE MISTAKES · VERIFY CRITICAL OUTPUT\",\n onCopy,\n onRegenerate,\n renderTurn,\n}) {\n const queue = controller ? controller.queue : [];\n const busy = controller ? controller.busy : false;\n\n const threadRef = useRef(null);\n useEffect(() => {\n const el = threadRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }, [messages, queue.length]);\n\n const send = (text) => {\n const t = (text || \"\").trim();\n if (!t || !controller) return;\n controller.enqueue(t);\n if (onDraftChange) onDraftChange(\"\");\n };\n\n const empty = messages.length === 0 && queue.length === 0;\n const showTools = onCopy || onRegenerate;\n\n return (\n <div className=\"ax-cthread\">\n <header className=\"ax-cthread__head\">\n <h1 className=\"ax-cthread__title\">{title}</h1>\n {model ? <Badge variant=\"outline\">{model}</Badge> : null}\n <span className=\"ax-cthread__sp\"></span>\n {actions}\n </header>\n\n {empty ? (\n <div className=\"ax-cthread__empty ax-dotgrid\">\n <BrandMark size={40} />\n <h2 className=\"ax-cthread__emptyh\">{emptyTitle}</h2>\n {hints.length ? (\n <div className=\"ax-cthread__hints\">\n {hints.map((h) => (\n <button\n key={h}\n className=\"ax-cthread__hint\"\n onClick={() => (onHint ? onHint(h) : send(h))}\n >\n {h}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"ax-cthread__thread\" ref={threadRef}>\n <div className=\"ax-cthread__col\">\n {messages.map((m, idx) => (\n <div className=\"ax-cthread__turn\" key={m.id != null ? m.id : idx}>\n {renderTurn ? (\n renderTurn(m, idx, {\n streaming: !!m.streaming,\n isLast: idx === messages.length - 1,\n })\n ) : (\n <React.Fragment>\n <Message role={m.role} time={m.time} streaming={!!m.streaming}>\n <p>{m.text}</p>\n </Message>\n {m.role === \"assistant\" && showTools ? (\n <div className=\"ax-cthread__tools\">\n {onCopy ? (\n <IconButton size=\"sm\" label=\"Copy\" onClick={() => onCopy(m, idx)}>\n <Icon name=\"copy\" size={13} />\n </IconButton>\n ) : null}\n {onRegenerate ? (\n <IconButton\n size=\"sm\"\n label=\"Regenerate\"\n onClick={() => onRegenerate(m, idx)}\n >\n <Icon name=\"refresh\" size={13} />\n </IconButton>\n ) : null}\n </div>\n ) : null}\n </React.Fragment>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"ax-cthread__foot\">\n <div className=\"ax-cthread__footcol\">\n {queue.length > 0 ? (\n <div className=\"ax-cthread__queue\">\n <Queue title={queueTitle} items={queue} onRemove={controller.remove} />\n </div>\n ) : null}\n <Composer\n value={draft}\n onChange={onDraftChange}\n onSend={() => send(draft)}\n disabled={disabled}\n placeholder={busy ? busyPlaceholder : placeholder}\n model={model}\n />\n {note ? <p className=\"ax-cthread__note\">{note}</p> : null}\n </div>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -12,8 +12,8 @@ const AX_ARTIFACT_CSS = `
12
12
  .ax-artifact__tab--active { background: var(--surface-card); color: var(--text-body); }
13
13
  .ax-artifact__actions { display: flex; gap: 2px; }
14
14
  .ax-artifact__body { max-height: 280px; overflow: auto; }
15
- .ax-artifact__preview { padding: 20px; background: var(--bg-0); min-height: 120px; }
16
- [data-theme="light"] .ax-artifact__preview { background: var(--bg-1); }
15
+ .ax-artifact__preview { padding: 20px; background: var(--bg-1); min-height: 120px; }
16
+ [data-theme="dark"] .ax-artifact__preview { background: var(--bg-0); }
17
17
  .ax-artifact__pre { margin: 0; padding: 14px 16px; font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.6; color: var(--text-body); white-space: pre; overflow-x: auto; }
18
18
  `;
19
19
  if (typeof document !== "undefined" && !document.getElementById("ax-artifact-css")) {
@@ -22,11 +22,32 @@ if (typeof document !== "undefined" && !document.getElementById("ax-artifact-css
22
22
  s.textContent = AX_ARTIFACT_CSS;
23
23
  document.head.appendChild(s);
24
24
  }
25
- const Box = /* @__PURE__ */ jsxs("svg", { className: "ax-artifact__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
26
- /* @__PURE__ */ jsx("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }),
27
- /* @__PURE__ */ jsx("path", { d: "m3.3 7 8.7 5 8.7-5M12 22V12" })
28
- ] });
29
- function Artifact({ title = "Artifact", subtitle, code, preview, defaultTab = "preview", actions, className = "", ...rest }) {
25
+ const Box = /* @__PURE__ */ jsxs(
26
+ "svg",
27
+ {
28
+ className: "ax-artifact__icon",
29
+ viewBox: "0 0 24 24",
30
+ fill: "none",
31
+ stroke: "currentColor",
32
+ strokeWidth: "2",
33
+ strokeLinecap: "round",
34
+ strokeLinejoin: "round",
35
+ children: [
36
+ /* @__PURE__ */ jsx("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }),
37
+ /* @__PURE__ */ jsx("path", { d: "m3.3 7 8.7 5 8.7-5M12 22V12" })
38
+ ]
39
+ }
40
+ );
41
+ function Artifact({
42
+ title = "Artifact",
43
+ subtitle,
44
+ code,
45
+ preview,
46
+ defaultTab = "preview",
47
+ actions,
48
+ className = "",
49
+ ...rest
50
+ }) {
30
51
  const [tab, setTab] = useState(preview ? defaultTab : "code");
31
52
  return /* @__PURE__ */ jsxs("div", { className: ["ax-artifact", className].filter(Boolean).join(" "), ...rest, children: [
32
53
  /* @__PURE__ */ jsxs("div", { className: "ax-artifact__head", children: [
@@ -36,8 +57,22 @@ function Artifact({ title = "Artifact", subtitle, code, preview, defaultTab = "p
36
57
  subtitle ? /* @__PURE__ */ jsx("p", { className: "ax-artifact__sub", children: subtitle }) : null
37
58
  ] }),
38
59
  preview && code ? /* @__PURE__ */ jsxs("div", { className: "ax-artifact__tabs", children: [
39
- /* @__PURE__ */ jsx("button", { className: "ax-artifact__tab" + (tab === "preview" ? " ax-artifact__tab--active" : ""), onClick: () => setTab("preview"), children: "Preview" }),
40
- /* @__PURE__ */ jsx("button", { className: "ax-artifact__tab" + (tab === "code" ? " ax-artifact__tab--active" : ""), onClick: () => setTab("code"), children: "Code" })
60
+ /* @__PURE__ */ jsx(
61
+ "button",
62
+ {
63
+ className: "ax-artifact__tab" + (tab === "preview" ? " ax-artifact__tab--active" : ""),
64
+ onClick: () => setTab("preview"),
65
+ children: "Preview"
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ "button",
70
+ {
71
+ className: "ax-artifact__tab" + (tab === "code" ? " ax-artifact__tab--active" : ""),
72
+ onClick: () => setTab("code"),
73
+ children: "Code"
74
+ }
75
+ )
41
76
  ] }) : null,
42
77
  actions ? /* @__PURE__ */ jsx("div", { className: "ax-artifact__actions", children: actions }) : null
43
78
  ] }),
@@ -1 +1 @@
1
- {"version":3,"file":"Artifact.js","sources":["../../../src/components/code/Artifact.jsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nconst AX_ARTIFACT_CSS = `\n.ax-artifact { border: 1px solid var(--border-strong); border-radius: var(--radius-3); overflow: hidden; background: var(--surface-card); }\n.ax-artifact__head { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--border-default); }\n.ax-artifact__icon { width: 16px; height: 16px; flex: none; color: var(--text-faint); }\n.ax-artifact__meta { flex: 1; min-width: 0; }\n.ax-artifact__title { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-body); margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ax-artifact__sub { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); margin-top: 1px; }\n.ax-artifact__tabs { display: flex; gap: 2px; padding: 2px; background: var(--surface-raised); border-radius: var(--radius-2); }\n.ax-artifact__tab { appearance: none; background: none; border: none; cursor: pointer; padding: 4px 10px; border-radius: var(--radius-1); font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }\n.ax-artifact__tab--active { background: var(--surface-card); color: var(--text-body); }\n.ax-artifact__actions { display: flex; gap: 2px; }\n.ax-artifact__body { max-height: 280px; overflow: auto; }\n.ax-artifact__preview { padding: 20px; background: var(--bg-0); min-height: 120px; }\n[data-theme=\"light\"] .ax-artifact__preview { background: var(--bg-1); }\n.ax-artifact__pre { margin: 0; padding: 14px 16px; font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.6; color: var(--text-body); white-space: pre; overflow-x: auto; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-artifact-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-artifact-css\";\n s.textContent = AX_ARTIFACT_CSS;\n document.head.appendChild(s);\n}\n\nconst Box = <svg className=\"ax-artifact__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"></path><path d=\"m3.3 7 8.7 5 8.7-5M12 22V12\"></path></svg>;\n\nexport function Artifact({ title = \"Artifact\", subtitle, code, preview, defaultTab = \"preview\", actions, className = \"\", ...rest }) {\n const [tab, setTab] = useState(preview ? defaultTab : \"code\");\n return (\n <div className={[\"ax-artifact\", className].filter(Boolean).join(\" \")} {...rest}>\n <div className=\"ax-artifact__head\">\n {Box}\n <div className=\"ax-artifact__meta\">\n <p className=\"ax-artifact__title\">{title}</p>\n {subtitle ? <p className=\"ax-artifact__sub\">{subtitle}</p> : null}\n </div>\n {preview && code ? (\n <div className=\"ax-artifact__tabs\">\n <button className={\"ax-artifact__tab\" + (tab === \"preview\" ? \" ax-artifact__tab--active\" : \"\")} onClick={() => setTab(\"preview\")}>Preview</button>\n <button className={\"ax-artifact__tab\" + (tab === \"code\" ? \" ax-artifact__tab--active\" : \"\")} onClick={() => setTab(\"code\")}>Code</button>\n </div>\n ) : null}\n {actions ? <div className=\"ax-artifact__actions\">{actions}</div> : null}\n </div>\n <div className=\"ax-artifact__body\">\n {tab === \"preview\" && preview ? <div className=\"ax-artifact__preview\">{preview}</div> : <pre className=\"ax-artifact__pre\">{code}</pre>}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,iBAAiB,GAAG;AAClF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEA,MAAM,MAAM,qBAAC,OAAA,EAAI,WAAU,qBAAoB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,4HAAA,CAA4H;AAAA,EAAO,oBAAC,QAAA,EAAK,GAAE,8BAAA,CAA8B;AAAA,GAAO;AAEnV,SAAS,SAAS,EAAE,QAAQ,YAAY,UAAU,MAAM,SAAS,aAAa,WAAW,SAAS,YAAY,IAAI,GAAG,QAAQ;AAClI,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,UAAU,aAAa,MAAM;AAC5D,SACE,qBAAC,OAAA,EAAI,WAAW,CAAC,eAAe,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MACxE,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,MAAA;AAAA,MACD,qBAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,QAAA,oBAAC,KAAA,EAAE,WAAU,sBAAsB,UAAA,OAAM;AAAA,QACxC,WAAW,oBAAC,KAAA,EAAE,WAAU,oBAAoB,oBAAS,IAAO;AAAA,MAAA,GAC/D;AAAA,MACC,WAAW,OACV,qBAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,QAAA,oBAAC,UAAA,EAAO,WAAW,sBAAsB,QAAQ,YAAY,8BAA8B,KAAK,SAAS,MAAM,OAAO,SAAS,GAAG,UAAA,WAAO;AAAA,QACzI,oBAAC,UAAA,EAAO,WAAW,sBAAsB,QAAQ,SAAS,8BAA8B,KAAK,SAAS,MAAM,OAAO,MAAM,GAAG,UAAA,OAAA,CAAI;AAAA,MAAA,EAAA,CAClI,IACE;AAAA,MACH,UAAU,oBAAC,OAAA,EAAI,WAAU,wBAAwB,mBAAQ,IAAS;AAAA,IAAA,GACrE;AAAA,wBACC,OAAA,EAAI,WAAU,qBACZ,UAAA,QAAQ,aAAa,UAAU,oBAAC,OAAA,EAAI,WAAU,wBAAwB,mBAAQ,IAAS,oBAAC,SAAI,WAAU,oBAAoB,gBAAK,EAAA,CAClI;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"Artifact.js","sources":["../../../src/components/code/Artifact.jsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nconst AX_ARTIFACT_CSS = `\n.ax-artifact { border: 1px solid var(--border-strong); border-radius: var(--radius-3); overflow: hidden; background: var(--surface-card); }\n.ax-artifact__head { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--border-default); }\n.ax-artifact__icon { width: 16px; height: 16px; flex: none; color: var(--text-faint); }\n.ax-artifact__meta { flex: 1; min-width: 0; }\n.ax-artifact__title { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-body); margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ax-artifact__sub { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); margin-top: 1px; }\n.ax-artifact__tabs { display: flex; gap: 2px; padding: 2px; background: var(--surface-raised); border-radius: var(--radius-2); }\n.ax-artifact__tab { appearance: none; background: none; border: none; cursor: pointer; padding: 4px 10px; border-radius: var(--radius-1); font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }\n.ax-artifact__tab--active { background: var(--surface-card); color: var(--text-body); }\n.ax-artifact__actions { display: flex; gap: 2px; }\n.ax-artifact__body { max-height: 280px; overflow: auto; }\n.ax-artifact__preview { padding: 20px; background: var(--bg-1); min-height: 120px; }\n[data-theme=\"dark\"] .ax-artifact__preview { background: var(--bg-0); }\n.ax-artifact__pre { margin: 0; padding: 14px 16px; font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.6; color: var(--text-body); white-space: pre; overflow-x: auto; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-artifact-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-artifact-css\";\n s.textContent = AX_ARTIFACT_CSS;\n document.head.appendChild(s);\n}\n\nconst Box = (\n <svg\n className=\"ax-artifact__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"></path>\n <path d=\"m3.3 7 8.7 5 8.7-5M12 22V12\"></path>\n </svg>\n);\n\nexport function Artifact({\n title = \"Artifact\",\n subtitle,\n code,\n preview,\n defaultTab = \"preview\",\n actions,\n className = \"\",\n ...rest\n}) {\n const [tab, setTab] = useState(preview ? defaultTab : \"code\");\n return (\n <div className={[\"ax-artifact\", className].filter(Boolean).join(\" \")} {...rest}>\n <div className=\"ax-artifact__head\">\n {Box}\n <div className=\"ax-artifact__meta\">\n <p className=\"ax-artifact__title\">{title}</p>\n {subtitle ? <p className=\"ax-artifact__sub\">{subtitle}</p> : null}\n </div>\n {preview && code ? (\n <div className=\"ax-artifact__tabs\">\n <button\n className={\n \"ax-artifact__tab\" + (tab === \"preview\" ? \" ax-artifact__tab--active\" : \"\")\n }\n onClick={() => setTab(\"preview\")}\n >\n Preview\n </button>\n <button\n className={\"ax-artifact__tab\" + (tab === \"code\" ? \" ax-artifact__tab--active\" : \"\")}\n onClick={() => setTab(\"code\")}\n >\n Code\n </button>\n </div>\n ) : null}\n {actions ? <div className=\"ax-artifact__actions\">{actions}</div> : null}\n </div>\n <div className=\"ax-artifact__body\">\n {tab === \"preview\" && preview ? (\n <div className=\"ax-artifact__preview\">{preview}</div>\n ) : (\n <pre className=\"ax-artifact__pre\">{code}</pre>\n )}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":";;AAEA,MAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBxB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,iBAAiB,GAAG;AAClF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEA,MAAM,MACJ;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,WAAU;AAAA,IACV,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IACZ,eAAc;AAAA,IACd,gBAAe;AAAA,IAEf,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,GAAE,4HAAA,CAA4H;AAAA,MACpI,oBAAC,QAAA,EAAK,GAAE,8BAAA,CAA8B;AAAA,IAAA;AAAA,EAAA;AACxC;AAGK,SAAS,SAAS;AAAA,EACvB,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA,YAAY;AAAA,EACZ,GAAG;AACL,GAAG;AACD,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,UAAU,aAAa,MAAM;AAC5D,SACE,qBAAC,OAAA,EAAI,WAAW,CAAC,eAAe,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MACxE,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,MAAA;AAAA,MACD,qBAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,QAAA,oBAAC,KAAA,EAAE,WAAU,sBAAsB,UAAA,OAAM;AAAA,QACxC,WAAW,oBAAC,KAAA,EAAE,WAAU,oBAAoB,oBAAS,IAAO;AAAA,MAAA,GAC/D;AAAA,MACC,WAAW,OACV,qBAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WACE,sBAAsB,QAAQ,YAAY,8BAA8B;AAAA,YAE1E,SAAS,MAAM,OAAO,SAAS;AAAA,YAChC,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,sBAAsB,QAAQ,SAAS,8BAA8B;AAAA,YAChF,SAAS,MAAM,OAAO,MAAM;AAAA,YAC7B,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MAED,EAAA,CACF,IACE;AAAA,MACH,UAAU,oBAAC,OAAA,EAAI,WAAU,wBAAwB,mBAAQ,IAAS;AAAA,IAAA,GACrE;AAAA,wBACC,OAAA,EAAI,WAAU,qBACZ,UAAA,QAAQ,aAAa,UACpB,oBAAC,OAAA,EAAI,WAAU,wBAAwB,mBAAQ,IAE/C,oBAAC,SAAI,WAAU,oBAAoB,gBAAK,EAAA,CAE5C;AAAA,EAAA,GACF;AAEJ;"}