@agentaily/design-system 0.4.0 → 0.6.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.
@@ -0,0 +1,65 @@
1
+ /**
2
+ * FeishuCard — a **pure-display** connection card for a Feishu (Lark) Bitable
3
+ * data sink.
4
+ *
5
+ * It renders one card (header · App ID · App Secret · share link · parsed
6
+ * App-Token/table read-out · security note · optional field-mapping table ·
7
+ * help · TestRow) and nothing else. **No state, no localStorage, no save bar, no
8
+ * gating** — props in, events out. The caller owns the config object,
9
+ * persistence, the Save button, backend-error display, and the "both connected?"
10
+ * gate. The only thing the card derives locally is the App-Token / table read-out
11
+ * parsed from the share link (pure display).
12
+ *
13
+ * `status` / `result` are caller-controlled: run your probe on `onTest`, then
14
+ * push `status` + `result` back. Reset `status` to `"idle"` from your change
15
+ * handlers to clear a green pill after an edit.
16
+ */
17
+ import type { ConnectionHelp } from "./DeepSeekCard";
18
+ export interface FeishuFieldMapRow {
19
+ /** Source field label, or null for an auto-filled column. */
20
+ from: string | null;
21
+ /** Destination Bitable column. */
22
+ to: string;
23
+ /** Small mono tag after the column, e.g. "单选" | "自动". */
24
+ tag?: string | null;
25
+ }
26
+ export interface FeishuCardProps {
27
+ /** Feishu app id (public). */
28
+ appId?: string;
29
+ onAppIdChange?: (value: string) => void;
30
+ /** Feishu app secret. Empty while a stored secret is `masked` + untouched. */
31
+ secret?: string;
32
+ onSecretChange?: (value: string) => void;
33
+ /** Bitable share URL — App Token + table id are auto-parsed for the read-out. */
34
+ link?: string;
35
+ onLinkChange?: (value: string) => void;
36
+ /** Connection status — caller-controlled; drives the StatusPill, card tint, and TestRow. @default "idle" */
37
+ status?: "idle" | "testing" | "ok" | "error";
38
+ /** Result line shown in the TestRow for ok / error. */
39
+ result?: string;
40
+ /** Fires when the user clicks Test — run your probe and push `status`/`result` back. */
41
+ onTest?: () => void;
42
+ /**
43
+ * A secret is already stored server-side. While true and `secret` is empty, the
44
+ * field shows a masked placeholder and still counts as present for the Test
45
+ * button. Typing overrides. @default false
46
+ */
47
+ masked?: boolean;
48
+ /** Field-level errors (e.g. backend 400s) under the matching inputs. */
49
+ appIdError?: string;
50
+ secretError?: string;
51
+ linkError?: string;
52
+ /** Rows for the auto field-mapping table. @default a 7-row RSVP sample */
53
+ fieldMap?: FeishuFieldMapRow[];
54
+ /** Show the field-mapping table. @default true once `status === "ok"` */
55
+ showMapping?: boolean;
56
+ /** Override the "如何获取…" guide — a `{title, steps, link}` object or a ready React node. */
57
+ help?: ConnectionHelp | React.ReactNode;
58
+ /** Override the derived Test-enabled state. Default: App ID + (secret or masked) + a parseable link. */
59
+ canTest?: boolean;
60
+ /** Idle hint in the TestRow before the first test. */
61
+ idleHint?: string;
62
+ }
63
+ export declare function FeishuCard(props: FeishuCardProps): JSX.Element;
64
+ /** Parse `{ token, table }` out of a Bitable share URL (table may be ""). Returns null if no app_token. */
65
+ export declare function parseFeishuLink(url: string): { token: string; table: string } | null;
@@ -0,0 +1,271 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { HelpSteps } from "./HelpSteps.js";
4
+ import { Icon } from "../utilities/Icon.js";
5
+ import { SecretField } from "../inputs/SecretField.js";
6
+ import { StatusPill } from "../display/StatusPill.js";
7
+ import { TestRow } from "./TestRow.js";
8
+ const AX_FEISHUCARD_CSS = `
9
+ .s-detect { display: flex; flex-direction: column; gap: 9px; padding: 13px 14px; border: 1px solid var(--border-default);
10
+ border-radius: var(--radius-2); background: var(--surface-page); }
11
+ .s-detect__row { display: flex; align-items: center; gap: 10px; }
12
+ .s-detect__k { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label); text-transform: uppercase;
13
+ color: var(--text-faint); width: 84px; flex: none; }
14
+ .s-detect__v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); word-break: break-all; flex: 1; }
15
+ .s-detect__ok { color: var(--ok); display: flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10px;
16
+ letter-spacing: var(--tracking-label); text-transform: uppercase; flex: none; }
17
+ .s-map { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }
18
+ .s-map th { text-align: left; font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label);
19
+ text-transform: uppercase; color: var(--text-faint); font-weight: 500; padding: 0 0 8px; }
20
+ .s-map td { padding: 7px 0; border-top: 1px solid var(--border-default); color: var(--text-body); vertical-align: middle; }
21
+ .s-map__from { color: var(--text-muted); }
22
+ .s-map__arrow { width: 36px; color: var(--text-faint); }
23
+ .s-map__col { font-family: var(--font-mono); }
24
+ .s-map__tag { font-family: var(--font-mono); font-size: 9px; letter-spacing: var(--tracking-label); text-transform: uppercase;
25
+ color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; margin-left: 7px; }
26
+ .s-sub { display: flex; align-items: center; gap: 8px; }
27
+ .s-sub__line { flex: 1; height: 1px; background: var(--border-default); }
28
+ `;
29
+ const AX_CONNCARD_CSS_FS = `
30
+ .s-card { position: relative; background: var(--surface-card); border: 1px solid var(--border-default);
31
+ border-radius: var(--radius-3); overflow: hidden; transition: border-color var(--dur-2) var(--ease-out); }
32
+ .s-card.is-ok { border-color: rgba(62, 207, 142, 0.4); }
33
+ .s-card.is-error { border-color: rgba(229, 72, 77, 0.4); }
34
+ .s-card__head { padding: 20px 24px 18px; }
35
+ .s-card__toprow { display: flex; align-items: center; gap: 11px; margin-bottom: 15px; }
36
+ .s-card__icon { flex: none; width: 30px; height: 30px; border-radius: var(--radius-2);
37
+ border: 1px solid var(--border-strong); background: var(--surface-raised); color: var(--text-body);
38
+ display: flex; align-items: center; justify-content: center; }
39
+ .s-card__eyebrow { color: var(--text-faint); }
40
+ .s-card__status { margin-left: auto; flex: none; }
41
+ .s-card__title { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 500;
42
+ letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--text-body); margin: 0; }
43
+ .s-card__desc { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); margin: 9px 0 0; max-width: 58ch; }
44
+ .s-card__body { padding: 4px 24px 22px; display: flex; flex-direction: column; gap: 18px; }
45
+ .s-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
46
+ @media (max-width: 560px) { .s-row2 { grid-template-columns: 1fr; } }
47
+ .s-lock { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); }
48
+ .s-lock svg { flex: none; margin-top: 1px; color: var(--text-muted); }
49
+ .s-lock strong { color: var(--text-muted); font-weight: 500; }
50
+ `;
51
+ function fs_injectCss(id, css) {
52
+ if (typeof document === "undefined" || document.getElementById(id)) return;
53
+ const s = document.createElement("style");
54
+ s.id = id;
55
+ s.textContent = css;
56
+ document.head.appendChild(s);
57
+ }
58
+ fs_injectCss("ax-conncard-css", AX_CONNCARD_CSS_FS);
59
+ fs_injectCss("ax-feishucard-css", AX_FEISHUCARD_CSS);
60
+ function parseFeishuLink(url) {
61
+ if (!url) return null;
62
+ const tokenM = url.match(/\/base\/([A-Za-z0-9]+)/) || url.match(/[?&]app_token=([A-Za-z0-9]+)/);
63
+ const tableM = url.match(/[?&]table=([A-Za-z0-9]+)/);
64
+ if (!tokenM) return null;
65
+ return { token: tokenM[1], table: tableM ? tableM[1] : "" };
66
+ }
67
+ const FS_DEFAULT_FIELD_MAP = [
68
+ { from: "姓名", to: "姓名", tag: null },
69
+ { from: "手机号", to: "手机号", tag: null },
70
+ { from: "邮箱", to: "邮箱", tag: null },
71
+ { from: "报名场次", to: "场次", tag: "单选" },
72
+ { from: "备注", to: "备注", tag: null },
73
+ { from: null, to: "提交时间", tag: "自动" },
74
+ { from: null, to: "来源链接", tag: "自动" }
75
+ ];
76
+ const FS_DEFAULT_HELP = {
77
+ title: "如何获取飞书应用凭证?",
78
+ steps: [
79
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
80
+ "打开飞书开放平台 ",
81
+ /* @__PURE__ */ jsx("code", { children: "open.feishu.cn" }),
82
+ ",创建一个「企业自建应用」。"
83
+ ] }),
84
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
85
+ "在「凭证与基础信息」中复制 ",
86
+ /* @__PURE__ */ jsx("code", { children: "App ID" }),
87
+ " 与 ",
88
+ /* @__PURE__ */ jsx("code", { children: "App Secret" }),
89
+ "。"
90
+ ] }),
91
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
92
+ "到「权限管理」开通多维表格读写权限 ",
93
+ /* @__PURE__ */ jsx("code", { children: "bitable:app" }),
94
+ ",并发布版本。"
95
+ ] }),
96
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
97
+ "在目标多维表格里,把这个应用添加为",
98
+ /* @__PURE__ */ jsx("strong", { children: "可编辑协作者" }),
99
+ "。"
100
+ ] }),
101
+ /* @__PURE__ */ jsx(React.Fragment, { children: "复制该多维表格的分享链接,粘贴到上方「多维表格链接」。" })
102
+ ],
103
+ link: { href: "https://open.feishu.cn", label: "打开飞书开放平台" }
104
+ };
105
+ function FeishuCard({
106
+ appId = "",
107
+ onAppIdChange,
108
+ secret = "",
109
+ onSecretChange,
110
+ link = "",
111
+ onLinkChange,
112
+ status = "idle",
113
+ result,
114
+ onTest,
115
+ masked = false,
116
+ appIdError,
117
+ secretError,
118
+ linkError,
119
+ fieldMap = FS_DEFAULT_FIELD_MAP,
120
+ showMapping,
121
+ help,
122
+ canTest,
123
+ idleHint = "填写凭证与链接后测试写入权限"
124
+ }) {
125
+ const parsed = parseFeishuLink(link);
126
+ const maskedNow = masked && !(secret || "").trim();
127
+ const testDisabled = canTest !== void 0 ? !canTest : !(appId || "").trim() || !(secret || "").trim() && !masked || !parsed;
128
+ const showMap = showMapping !== void 0 ? showMapping : status === "ok";
129
+ const help_ = help || FS_DEFAULT_HELP;
130
+ return /* @__PURE__ */ jsxs(
131
+ "section",
132
+ {
133
+ className: "s-card" + (status === "ok" ? " is-ok" : status === "error" ? " is-error" : ""),
134
+ children: [
135
+ /* @__PURE__ */ jsxs("div", { className: "s-card__head", children: [
136
+ /* @__PURE__ */ jsxs("div", { className: "s-card__toprow", children: [
137
+ /* @__PURE__ */ jsx("div", { className: "s-card__icon", children: /* @__PURE__ */ jsx(Icon, { name: "table", size: 16 }) }),
138
+ /* @__PURE__ */ jsx("span", { className: "ax-label s-card__eyebrow", children: "数据写入 · FEISHU BITABLE" }),
139
+ /* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status }) })
140
+ ] }),
141
+ /* @__PURE__ */ jsx("h2", { className: "s-card__title", children: "飞书多维表格" }),
142
+ /* @__PURE__ */ jsx("p", { className: "s-card__desc", children: "每次提交后,数据自动写入指定多维表格的一行。需要一个飞书自建应用的凭证,以及目标表格的链接。" })
143
+ ] }),
144
+ /* @__PURE__ */ jsxs("div", { className: "s-card__body", children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "s-row2", children: [
146
+ /* @__PURE__ */ jsxs("div", { children: [
147
+ /* @__PURE__ */ jsx("label", { className: "s-field__label ax-label", children: "App ID" }),
148
+ /* @__PURE__ */ jsx(
149
+ "input",
150
+ {
151
+ className: "ax-input ax-input--mono" + (appIdError ? " ax-input--error" : ""),
152
+ type: "text",
153
+ value: appId,
154
+ spellCheck: "false",
155
+ placeholder: "cli_xxxxxxxxxxxx",
156
+ onChange: (e) => onAppIdChange && onAppIdChange(e.target.value)
157
+ }
158
+ ),
159
+ appIdError ? /* @__PURE__ */ jsx("p", { className: "s-field__hint s-field__hint--err", children: appIdError }) : /* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "应用标识,可公开。" })
160
+ ] }),
161
+ /* @__PURE__ */ jsx(
162
+ SecretField,
163
+ {
164
+ label: "App Secret",
165
+ value: secret,
166
+ onChange: onSecretChange,
167
+ placeholder: maskedNow ? "已保存 ········ · 留空则保持不变" : "••••••••••••••••",
168
+ hint: maskedNow ? "已存密钥 · 留空表示不修改" : "应用密钥,加密存储。",
169
+ error: secretError
170
+ }
171
+ )
172
+ ] }),
173
+ /* @__PURE__ */ jsxs("div", { children: [
174
+ /* @__PURE__ */ jsx("label", { className: "s-field__label ax-label", children: "多维表格链接" }),
175
+ /* @__PURE__ */ jsx(
176
+ "input",
177
+ {
178
+ className: "ax-input" + (linkError ? " ax-input--error" : ""),
179
+ type: "text",
180
+ value: link,
181
+ spellCheck: "false",
182
+ placeholder: "https://your-team.feishu.cn/base/bascn…?table=tbl…",
183
+ onChange: (e) => onLinkChange && onLinkChange(e.target.value)
184
+ }
185
+ ),
186
+ linkError ? /* @__PURE__ */ jsx("p", { className: "s-field__hint s-field__hint--err", children: linkError }) : /* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "在多维表格右上角「分享」中复制链接粘贴即可,App Token 与数据表会自动识别。" })
187
+ ] }),
188
+ parsed ? /* @__PURE__ */ jsxs("div", { className: "s-detect", children: [
189
+ /* @__PURE__ */ jsxs("div", { className: "s-detect__row", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "s-detect__k", children: "App Token" }),
191
+ /* @__PURE__ */ jsx("span", { className: "s-detect__v", children: parsed.token }),
192
+ /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", children: [
193
+ /* @__PURE__ */ jsx(Icon, { name: "check", size: 12 }),
194
+ "已识别"
195
+ ] })
196
+ ] }),
197
+ /* @__PURE__ */ jsxs("div", { className: "s-detect__row", children: [
198
+ /* @__PURE__ */ jsx("span", { className: "s-detect__k", children: "数据表" }),
199
+ /* @__PURE__ */ jsx("span", { className: "s-detect__v", children: parsed.table || "—" }),
200
+ parsed.table ? /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", children: [
201
+ /* @__PURE__ */ jsx(Icon, { name: "check", size: 12 }),
202
+ "已识别"
203
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", style: { color: "var(--warn)" }, children: [
204
+ /* @__PURE__ */ jsx(Icon, { name: "warn", size: 12 }),
205
+ "缺失"
206
+ ] })
207
+ ] })
208
+ ] }) : null,
209
+ /* @__PURE__ */ jsxs("div", { className: "s-lock", children: [
210
+ /* @__PURE__ */ jsx(Icon, { name: "shield", size: 14 }),
211
+ /* @__PURE__ */ jsxs("span", { children: [
212
+ /* @__PURE__ */ jsx("strong", { children: "凭证加密存储" }),
213
+ ",仅服务端用于写入数据。用户",
214
+ /* @__PURE__ */ jsx("strong", { children: "无法接触你的飞书凭证或表格权限。" })
215
+ ] })
216
+ ] }),
217
+ showMap ? /* @__PURE__ */ jsxs("div", { children: [
218
+ /* @__PURE__ */ jsxs("div", { className: "s-sub", style: { marginBottom: 12 }, children: [
219
+ /* @__PURE__ */ jsx("span", { className: "ax-label", children: "字段映射 · 自动" }),
220
+ /* @__PURE__ */ jsx("span", { className: "s-sub__line" })
221
+ ] }),
222
+ /* @__PURE__ */ jsxs("table", { className: "s-map", children: [
223
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
224
+ /* @__PURE__ */ jsx("th", { children: "字段" }),
225
+ /* @__PURE__ */ jsx("th", { className: "s-map__arrow" }),
226
+ /* @__PURE__ */ jsx("th", { children: "表格列" })
227
+ ] }) }),
228
+ /* @__PURE__ */ jsx("tbody", { children: fieldMap.map((m, i) => /* @__PURE__ */ jsxs("tr", { children: [
229
+ /* @__PURE__ */ jsx("td", { className: "s-map__from", children: m.from || /* @__PURE__ */ jsx("span", { style: { color: "var(--text-faint)" }, children: "—" }) }),
230
+ /* @__PURE__ */ jsx("td", { className: "s-map__arrow", children: /* @__PURE__ */ jsx(Icon, { name: "arrow", size: 14 }) }),
231
+ /* @__PURE__ */ jsxs("td", { children: [
232
+ /* @__PURE__ */ jsx("span", { className: "s-map__col", children: m.to }),
233
+ m.tag ? /* @__PURE__ */ jsx("span", { className: "s-map__tag", children: m.tag }) : null
234
+ ] })
235
+ ] }, i)) })
236
+ ] })
237
+ ] }) : null,
238
+ /* @__PURE__ */ jsx(FeishuHelpSlot, { help: help_ })
239
+ ] }),
240
+ /* @__PURE__ */ jsx(
241
+ TestRow,
242
+ {
243
+ status,
244
+ result,
245
+ onTest,
246
+ disabled: testDisabled,
247
+ idleHint
248
+ }
249
+ )
250
+ ]
251
+ }
252
+ );
253
+ }
254
+ function FeishuHelpSlot({ help }) {
255
+ if (!help) return null;
256
+ if (React.isValidElement(help)) return help;
257
+ return /* @__PURE__ */ jsx(
258
+ HelpSteps,
259
+ {
260
+ title: help.title,
261
+ steps: help.steps,
262
+ link: help.link,
263
+ defaultOpen: help.defaultOpen
264
+ }
265
+ );
266
+ }
267
+ export {
268
+ FeishuCard,
269
+ parseFeishuLink
270
+ };
271
+ //# sourceMappingURL=FeishuCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeishuCard.js","sources":["../../../src/components/settings/FeishuCard.jsx"],"sourcesContent":["import React from \"react\";\nimport { HelpSteps } from \"./HelpSteps.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\nimport { SecretField } from \"../inputs/SecretField.jsx\";\nimport { StatusPill } from \"../display/StatusPill.jsx\";\nimport { TestRow } from \"./TestRow.jsx\";\n\n// FeishuCard — a PURE-DISPLAY connection card for a Feishu (Lark) Bitable data\n// sink. Props in (appId / secret / link, status, result, masked, errors,\n// fieldMap, help…), events out (onAppIdChange / onSecretChange / onLinkChange /\n// onTest). Zero state, zero localStorage, zero save bar, zero gating — the\n// caller owns all of that. The only thing it derives locally is the App\n// Token / table read-out parsed from the share link (pure display). Composes\n// SecretField / StatusPill / TestRow / HelpSteps.\nconst AX_FEISHUCARD_CSS = `\n.s-detect { display: flex; flex-direction: column; gap: 9px; padding: 13px 14px; border: 1px solid var(--border-default);\n border-radius: var(--radius-2); background: var(--surface-page); }\n.s-detect__row { display: flex; align-items: center; gap: 10px; }\n.s-detect__k { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint); width: 84px; flex: none; }\n.s-detect__v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); word-break: break-all; flex: 1; }\n.s-detect__ok { color: var(--ok); display: flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10px;\n letter-spacing: var(--tracking-label); text-transform: uppercase; flex: none; }\n.s-map { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }\n.s-map th { text-align: left; font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label);\n text-transform: uppercase; color: var(--text-faint); font-weight: 500; padding: 0 0 8px; }\n.s-map td { padding: 7px 0; border-top: 1px solid var(--border-default); color: var(--text-body); vertical-align: middle; }\n.s-map__from { color: var(--text-muted); }\n.s-map__arrow { width: 36px; color: var(--text-faint); }\n.s-map__col { font-family: var(--font-mono); }\n.s-map__tag { font-family: var(--font-mono); font-size: 9px; letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; margin-left: 7px; }\n.s-sub { display: flex; align-items: center; gap: 8px; }\n.s-sub__line { flex: 1; height: 1px; background: var(--border-default); }\n`;\n\n// Shared connection-card shell, mirrored from DeepSeekCard so this card renders\n// correctly when mounted on its own. Guarded by a single id — first writer wins.\nconst AX_CONNCARD_CSS_FS = `\n.s-card { position: relative; background: var(--surface-card); border: 1px solid var(--border-default);\n border-radius: var(--radius-3); overflow: hidden; transition: border-color var(--dur-2) var(--ease-out); }\n.s-card.is-ok { border-color: rgba(62, 207, 142, 0.4); }\n.s-card.is-error { border-color: rgba(229, 72, 77, 0.4); }\n.s-card__head { padding: 20px 24px 18px; }\n.s-card__toprow { display: flex; align-items: center; gap: 11px; margin-bottom: 15px; }\n.s-card__icon { flex: none; width: 30px; height: 30px; border-radius: var(--radius-2);\n border: 1px solid var(--border-strong); background: var(--surface-raised); color: var(--text-body);\n display: flex; align-items: center; justify-content: center; }\n.s-card__eyebrow { color: var(--text-faint); }\n.s-card__status { margin-left: auto; flex: none; }\n.s-card__title { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 500;\n letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--text-body); margin: 0; }\n.s-card__desc { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); margin: 9px 0 0; max-width: 58ch; }\n.s-card__body { padding: 4px 24px 22px; display: flex; flex-direction: column; gap: 18px; }\n.s-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n@media (max-width: 560px) { .s-row2 { grid-template-columns: 1fr; } }\n.s-lock { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); }\n.s-lock svg { flex: none; margin-top: 1px; color: var(--text-muted); }\n.s-lock strong { color: var(--text-muted); font-weight: 500; }\n`;\n\nfunction fs_injectCss(id, css) {\n if (typeof document === \"undefined\" || document.getElementById(id)) return;\n const s = document.createElement(\"style\");\n s.id = id;\n s.textContent = css;\n document.head.appendChild(s);\n}\nfs_injectCss(\"ax-conncard-css\", AX_CONNCARD_CSS_FS);\nfs_injectCss(\"ax-feishucard-css\", AX_FEISHUCARD_CSS);\n\n// Parse the App Token + data-table id out of a Bitable share URL — pure display.\nexport function parseFeishuLink(url) {\n if (!url) return null;\n const tokenM = url.match(/\\/base\\/([A-Za-z0-9]+)/) || url.match(/[?&]app_token=([A-Za-z0-9]+)/);\n const tableM = url.match(/[?&]table=([A-Za-z0-9]+)/);\n if (!tokenM) return null;\n return { token: tokenM[1], table: tableM ? tableM[1] : \"\" };\n}\n\nconst FS_DEFAULT_FIELD_MAP = [\n { from: \"姓名\", to: \"姓名\", tag: null },\n { from: \"手机号\", to: \"手机号\", tag: null },\n { from: \"邮箱\", to: \"邮箱\", tag: null },\n { from: \"报名场次\", to: \"场次\", tag: \"单选\" },\n { from: \"备注\", to: \"备注\", tag: null },\n { from: null, to: \"提交时间\", tag: \"自动\" },\n { from: null, to: \"来源链接\", tag: \"自动\" },\n];\n\nconst FS_DEFAULT_HELP = {\n title: \"如何获取飞书应用凭证?\",\n steps: [\n <React.Fragment>\n 打开飞书开放平台 <code>open.feishu.cn</code>,创建一个「企业自建应用」。\n </React.Fragment>,\n <React.Fragment>\n 在「凭证与基础信息」中复制 <code>App ID</code> 与 <code>App Secret</code>。\n </React.Fragment>,\n <React.Fragment>\n 到「权限管理」开通多维表格读写权限 <code>bitable:app</code>,并发布版本。\n </React.Fragment>,\n <React.Fragment>\n 在目标多维表格里,把这个应用添加为<strong>可编辑协作者</strong>。\n </React.Fragment>,\n <React.Fragment>复制该多维表格的分享链接,粘贴到上方「多维表格链接」。</React.Fragment>,\n ],\n link: { href: \"https://open.feishu.cn\", label: \"打开飞书开放平台\" },\n};\n\nexport function FeishuCard({\n appId = \"\",\n onAppIdChange,\n secret = \"\",\n onSecretChange,\n link = \"\",\n onLinkChange,\n status = \"idle\",\n result,\n onTest,\n masked = false,\n appIdError,\n secretError,\n linkError,\n fieldMap = FS_DEFAULT_FIELD_MAP,\n showMapping,\n help,\n canTest,\n idleHint = \"填写凭证与链接后测试写入权限\",\n}) {\n const parsed = parseFeishuLink(link);\n // Masked echo is derived from props (no state): stored secret + empty field →\n // masked placeholder, still counts as \"present\" for the Test button.\n const maskedNow = masked && !(secret || \"\").trim();\n const testDisabled =\n canTest !== undefined\n ? !canTest\n : !(appId || \"\").trim() || (!(secret || \"\").trim() && !masked) || !parsed;\n const showMap = showMapping !== undefined ? showMapping : status === \"ok\";\n const help_ = help || FS_DEFAULT_HELP;\n\n return (\n <section\n className={\"s-card\" + (status === \"ok\" ? \" is-ok\" : status === \"error\" ? \" is-error\" : \"\")}\n >\n <div className=\"s-card__head\">\n <div className=\"s-card__toprow\">\n <div className=\"s-card__icon\">\n <Icon name=\"table\" size={16} />\n </div>\n <span className=\"ax-label s-card__eyebrow\">数据写入 · FEISHU BITABLE</span>\n <span className=\"s-card__status\">\n <StatusPill status={status} />\n </span>\n </div>\n <h2 className=\"s-card__title\">飞书多维表格</h2>\n <p className=\"s-card__desc\">\n 每次提交后,数据自动写入指定多维表格的一行。需要一个飞书自建应用的凭证,以及目标表格的链接。\n </p>\n </div>\n\n <div className=\"s-card__body\">\n <div className=\"s-row2\">\n <div>\n <label className=\"s-field__label ax-label\">App ID</label>\n <input\n className={\"ax-input ax-input--mono\" + (appIdError ? \" ax-input--error\" : \"\")}\n type=\"text\"\n value={appId}\n spellCheck=\"false\"\n placeholder=\"cli_xxxxxxxxxxxx\"\n onChange={(e) => onAppIdChange && onAppIdChange(e.target.value)}\n />\n {appIdError ? (\n <p className=\"s-field__hint s-field__hint--err\">{appIdError}</p>\n ) : (\n <p className=\"s-field__hint\">应用标识,可公开。</p>\n )}\n </div>\n <SecretField\n label=\"App Secret\"\n value={secret}\n onChange={onSecretChange}\n placeholder={maskedNow ? \"已保存 ········ · 留空则保持不变\" : \"••••••••••••••••\"}\n hint={maskedNow ? \"已存密钥 · 留空表示不修改\" : \"应用密钥,加密存储。\"}\n error={secretError}\n />\n </div>\n\n <div>\n <label className=\"s-field__label ax-label\">多维表格链接</label>\n <input\n className={\"ax-input\" + (linkError ? \" ax-input--error\" : \"\")}\n type=\"text\"\n value={link}\n spellCheck=\"false\"\n placeholder=\"https://your-team.feishu.cn/base/bascn…?table=tbl…\"\n onChange={(e) => onLinkChange && onLinkChange(e.target.value)}\n />\n {linkError ? (\n <p className=\"s-field__hint s-field__hint--err\">{linkError}</p>\n ) : (\n <p className=\"s-field__hint\">\n 在多维表格右上角「分享」中复制链接粘贴即可,App Token 与数据表会自动识别。\n </p>\n )}\n </div>\n\n {parsed ? (\n <div className=\"s-detect\">\n <div className=\"s-detect__row\">\n <span className=\"s-detect__k\">App Token</span>\n <span className=\"s-detect__v\">{parsed.token}</span>\n <span className=\"s-detect__ok\">\n <Icon name=\"check\" size={12} />\n 已识别\n </span>\n </div>\n <div className=\"s-detect__row\">\n <span className=\"s-detect__k\">数据表</span>\n <span className=\"s-detect__v\">{parsed.table || \"—\"}</span>\n {parsed.table ? (\n <span className=\"s-detect__ok\">\n <Icon name=\"check\" size={12} />\n 已识别\n </span>\n ) : (\n <span className=\"s-detect__ok\" style={{ color: \"var(--warn)\" }}>\n <Icon name=\"warn\" size={12} />\n 缺失\n </span>\n )}\n </div>\n </div>\n ) : null}\n\n <div className=\"s-lock\">\n <Icon name=\"shield\" size={14} />\n <span>\n <strong>凭证加密存储</strong>,仅服务端用于写入数据。用户\n <strong>无法接触你的飞书凭证或表格权限。</strong>\n </span>\n </div>\n\n {showMap ? (\n <div>\n <div className=\"s-sub\" style={{ marginBottom: 12 }}>\n <span className=\"ax-label\">字段映射 · 自动</span>\n <span className=\"s-sub__line\"></span>\n </div>\n <table className=\"s-map\">\n <thead>\n <tr>\n <th>字段</th>\n <th className=\"s-map__arrow\"></th>\n <th>表格列</th>\n </tr>\n </thead>\n <tbody>\n {fieldMap.map((m, i) => (\n <tr key={i}>\n <td className=\"s-map__from\">\n {m.from || <span style={{ color: \"var(--text-faint)\" }}>—</span>}\n </td>\n <td className=\"s-map__arrow\">\n <Icon name=\"arrow\" size={14} />\n </td>\n <td>\n <span className=\"s-map__col\">{m.to}</span>\n {m.tag ? <span className=\"s-map__tag\">{m.tag}</span> : null}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : null}\n\n <FeishuHelpSlot help={help_} />\n </div>\n\n <TestRow\n status={status}\n result={result}\n onTest={onTest}\n disabled={testDisabled}\n idleHint={idleHint}\n />\n </section>\n );\n}\n\nfunction FeishuHelpSlot({ help }) {\n if (!help) return null;\n if (React.isValidElement(help)) return help;\n return (\n <HelpSteps\n title={help.title}\n steps={help.steps}\n link={help.link}\n defaultOpen={help.defaultOpen}\n />\n );\n}\n"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ export interface BrandMarkProps {
8
8
  size?: number;
9
9
  /** Render the "agentaily" wordmark after the mark. @default false */
10
10
  wordmark?: boolean;
11
- /** Show the blinking block cursor after the wordmark. @default true */
11
+ /** Show the block cursor after the wordmark. Off by default in lockups; opt in for the liveness motif. @default false */
12
12
  cursor?: boolean;
13
13
  /** Animate the cursor (blink). Set false for a solid, static cursor. @default true */
14
14
  blink?: boolean;
@@ -19,7 +19,7 @@ if (typeof document !== "undefined" && !document.getElementById("ax-brandmark-cs
19
19
  function BrandMark({
20
20
  size = 20,
21
21
  wordmark = false,
22
- cursor = true,
22
+ cursor = false,
23
23
  blink = true,
24
24
  className = "",
25
25
  ...rest
@@ -1 +1 @@
1
- {"version":3,"file":"BrandMark.js","sources":["../../../src/components/utilities/BrandMark.jsx"],"sourcesContent":["import React from \"react\";\n\n// BrandMark — the agentaily mark (cursor block inside corner ticks) and optional\n// typed wordmark. Monochrome, drawn in currentColor so it inverts with the theme.\n// Used in auth modals, settings headers, top bars. Never recolor with a hue.\nconst AX_BRANDMARK_CSS = `\n.ax-brandmark { display: inline-flex; align-items: center; gap: 9px; color: var(--text-body); }\n.ax-brandmark__mark { display: inline-flex; flex: none; }\n.ax-brandmark__word {\n font-family: var(--font-mono); font-weight: var(--weight-medium);\n letter-spacing: -0.02em; color: var(--text-body);\n display: inline-flex; align-items: baseline; line-height: 1;\n}\n.ax-brandmark__word .ax-cursor { margin-left: 1px; width: 0.42em; height: 0.92em; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-brandmark-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-brandmark-css\";\n s.textContent = AX_BRANDMARK_CSS;\n document.head.appendChild(s);\n}\n\nexport function BrandMark({\n size = 20,\n wordmark = false,\n cursor = true,\n blink = true,\n className = \"\",\n ...rest\n}) {\n const stroke = Math.max(2, Math.round((size / 32) * 2.4 * 10) / 10);\n return (\n <span className={[\"ax-brandmark\", className].filter(Boolean).join(\" \")} {...rest}>\n <span className=\"ax-brandmark__mark\" aria-hidden=\"true\">\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M2 10 V2 H10\" stroke=\"currentColor\" strokeWidth={stroke} />\n <path d=\"M22 30 H30 V22\" stroke=\"currentColor\" strokeWidth={stroke} />\n <rect x=\"12\" y=\"9\" width=\"8\" height=\"14\" fill=\"currentColor\" />\n </svg>\n </span>\n {wordmark ? (\n <span className=\"ax-brandmark__word\" style={{ fontSize: Math.round(size * 0.75) }}>\n agentaily\n {cursor ? (\n <i className=\"ax-cursor\" style={blink ? undefined : { animation: \"none\" }}></i>\n ) : null}\n </span>\n ) : null}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAKA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU;AAAA,EACxB,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,GAAG;AACL,GAAG;AACD,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAO,OAAO,KAAM,MAAM,EAAE,IAAI,EAAE;AAClE,SACE,qBAAC,QAAA,EAAK,WAAW,CAAC,gBAAgB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MAC1E,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,WAAU,sBAAqB,eAAY,QAC/C,UAAA,qBAAC,OAAA,EAAI,OAAO,MAAM,QAAQ,MAAM,SAAQ,aAAY,MAAK,QACvD,UAAA;AAAA,MAAA,oBAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAa,QAAQ;AAAA,0BACjE,QAAA,EAAK,GAAE,kBAAiB,QAAO,gBAAe,aAAa,QAAQ;AAAA,MACpE,oBAAC,QAAA,EAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,MAAK,MAAK,eAAA,CAAe;AAAA,IAAA,EAAA,CAC/D,EAAA,CACF;AAAA,IACC,WACC,qBAAC,QAAA,EAAK,WAAU,sBAAqB,OAAO,EAAE,UAAU,KAAK,MAAM,OAAO,IAAI,KAAK,UAAA;AAAA,MAAA;AAAA,MAEhF,SACC,oBAAC,KAAA,EAAE,WAAU,aAAY,OAAO,QAAQ,SAAY,EAAE,WAAW,OAAA,EAAO,CAAG,IACzE;AAAA,IAAA,EAAA,CACN,IACE;AAAA,EAAA,GACN;AAEJ;"}
1
+ {"version":3,"file":"BrandMark.js","sources":["../../../src/components/utilities/BrandMark.jsx"],"sourcesContent":["import React from \"react\";\n\n// BrandMark — the agentaily mark (cursor block inside corner ticks) and optional\n// typed wordmark. Monochrome, drawn in currentColor so it inverts with the theme.\n// Used in auth modals, settings headers, top bars. Never recolor with a hue.\nconst AX_BRANDMARK_CSS = `\n.ax-brandmark { display: inline-flex; align-items: center; gap: 9px; color: var(--text-body); }\n.ax-brandmark__mark { display: inline-flex; flex: none; }\n.ax-brandmark__word {\n font-family: var(--font-mono); font-weight: var(--weight-medium);\n letter-spacing: -0.02em; color: var(--text-body);\n display: inline-flex; align-items: baseline; line-height: 1;\n}\n.ax-brandmark__word .ax-cursor { margin-left: 1px; width: 0.42em; height: 0.92em; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-brandmark-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-brandmark-css\";\n s.textContent = AX_BRANDMARK_CSS;\n document.head.appendChild(s);\n}\n\nexport function BrandMark({\n size = 20,\n wordmark = false,\n cursor = false,\n blink = true,\n className = \"\",\n ...rest\n}) {\n const stroke = Math.max(2, Math.round((size / 32) * 2.4 * 10) / 10);\n return (\n <span className={[\"ax-brandmark\", className].filter(Boolean).join(\" \")} {...rest}>\n <span className=\"ax-brandmark__mark\" aria-hidden=\"true\">\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M2 10 V2 H10\" stroke=\"currentColor\" strokeWidth={stroke} />\n <path d=\"M22 30 H30 V22\" stroke=\"currentColor\" strokeWidth={stroke} />\n <rect x=\"12\" y=\"9\" width=\"8\" height=\"14\" fill=\"currentColor\" />\n </svg>\n </span>\n {wordmark ? (\n <span className=\"ax-brandmark__word\" style={{ fontSize: Math.round(size * 0.75) }}>\n agentaily\n {cursor ? (\n <i className=\"ax-cursor\" style={blink ? undefined : { animation: \"none\" }}></i>\n ) : null}\n </span>\n ) : null}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAKA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU;AAAA,EACxB,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,GAAG;AACL,GAAG;AACD,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAO,OAAO,KAAM,MAAM,EAAE,IAAI,EAAE;AAClE,SACE,qBAAC,QAAA,EAAK,WAAW,CAAC,gBAAgB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MAC1E,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,WAAU,sBAAqB,eAAY,QAC/C,UAAA,qBAAC,OAAA,EAAI,OAAO,MAAM,QAAQ,MAAM,SAAQ,aAAY,MAAK,QACvD,UAAA;AAAA,MAAA,oBAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAa,QAAQ;AAAA,0BACjE,QAAA,EAAK,GAAE,kBAAiB,QAAO,gBAAe,aAAa,QAAQ;AAAA,MACpE,oBAAC,QAAA,EAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,MAAK,MAAK,eAAA,CAAe;AAAA,IAAA,EAAA,CAC/D,EAAA,CACF;AAAA,IACC,WACC,qBAAC,QAAA,EAAK,WAAU,sBAAqB,OAAO,EAAE,UAAU,KAAK,MAAM,OAAO,IAAI,KAAK,UAAA;AAAA,MAAA;AAAA,MAEhF,SACC,oBAAC,KAAA,EAAE,WAAU,aAAY,OAAO,QAAQ,SAAY,EAAE,WAAW,OAAA,EAAO,CAAG,IACzE;AAAA,IAAA,EAAA,CACN,IACE;AAAA,EAAA,GACN;AAEJ;"}
package/dist/index.d.ts CHANGED
@@ -121,8 +121,9 @@ export * from "./components/overlay/Sheet";
121
121
  export * from "./components/review/MarkupLayer";
122
122
 
123
123
  // settings
124
+ export * from "./components/settings/DeepSeekCard";
125
+ export * from "./components/settings/FeishuCard";
124
126
  export * from "./components/settings/HelpSteps";
125
- export * from "./components/settings/IntegrationSettings";
126
127
  export * from "./components/settings/TestRow";
127
128
 
128
129
  // utilities
package/dist/index.js CHANGED
@@ -96,8 +96,9 @@ import { NavigationMenu } from "./components/overlay/NavigationMenu.js";
96
96
  import { Popover } from "./components/overlay/Popover.js";
97
97
  import { Sheet } from "./components/overlay/Sheet.js";
98
98
  import { MarkupLayer } from "./components/review/MarkupLayer.js";
99
+ import { DeepSeekCard } from "./components/settings/DeepSeekCard.js";
100
+ import { FeishuCard, parseFeishuLink } from "./components/settings/FeishuCard.js";
99
101
  import { HelpSteps } from "./components/settings/HelpSteps.js";
100
- import { IntegrationSettings } from "./components/settings/IntegrationSettings.js";
101
102
  import { TestRow } from "./components/settings/TestRow.js";
102
103
  import { BrandMark } from "./components/utilities/BrandMark.js";
103
104
  import { Icon } from "./components/utilities/Icon.js";
@@ -153,6 +154,7 @@ export {
153
154
  ConversationThread,
154
155
  DataTable,
155
156
  DatePicker,
157
+ DeepSeekCard,
156
158
  DesignerShell,
157
159
  Dialog,
158
160
  DocsLayout,
@@ -160,6 +162,7 @@ export {
160
162
  Edge,
161
163
  Empty,
162
164
  EnvironmentVariables,
165
+ FeishuCard,
163
166
  Field,
164
167
  FieldGroup,
165
168
  FileTree,
@@ -174,7 +177,6 @@ export {
174
177
  Input,
175
178
  InputGroup,
176
179
  InputOTP,
177
- IntegrationSettings,
178
180
  Item,
179
181
  JSXPreview,
180
182
  Kbd,
@@ -240,6 +242,7 @@ export {
240
242
  Transcription,
241
243
  Typography,
242
244
  VoiceSelector,
243
- WebPreview
245
+ WebPreview,
246
+ parseFeishuLink
244
247
  };
245
248
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agentaily/design-system",
3
- "version": "0.4.0",
4
- "description": "Agentaily design system — light-first monochrome React component library (113 components) + Storybook.",
3
+ "version": "0.6.0",
4
+ "description": "Agentaily design system — light-first monochrome React component library (114 components) + Storybook.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "author": "Agentaily",
@@ -1,15 +0,0 @@
1
- /**
2
- * Fullscreen integration modal: connect a DeepSeek key (conversation engine) and
3
- * a Feishu Bitable (data sink). Self-persists to localStorage, reports a 0/2
4
- * readiness state, and gates Save until both connect. Composes SecretField,
5
- * StatusPill, TestRow, HelpSteps. The monthly usage-cap block is opt-in.
6
- */
7
- export interface IntegrationSettingsProps {
8
- /** Close handler (Esc + the × button + overlay). */
9
- onClose?: () => void;
10
- /** Show the DeepSeek monthly usage-cap warning + toggle. @default true */
11
- showUsageCap?: boolean;
12
- /** localStorage key for the persisted config. @default "agentaily.integrations.v1" */
13
- storageKey?: string;
14
- }
15
- export declare function IntegrationSettings(props: IntegrationSettingsProps): JSX.Element;