@kanyun-ai-infra/band-plugin-react 0.1.1 → 0.2.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.
- package/dist/chunk-ER2ITOG5.js +2425 -0
- package/dist/components.d.ts +512 -3
- package/dist/components.js +79 -4
- package/dist/index.d.ts +66 -153
- package/dist/index.js +755 -1238
- package/package.json +5 -5
- package/dist/chunk-ULDBT77D.js +0 -354
package/dist/components.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { MemberView } from '@kanyun-ai-infra/band-plugin-sdk';
|
|
2
|
+
import { ReactNode, Ref, MouseEvent } from 'react';
|
|
3
|
+
import { MemberView, PeopleApi } from '@kanyun-ai-infra/band-plugin-sdk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 一行错误提示:操作失败时显示在面板里。`children` 为空(null、undefined、空串、false)时什么也不渲染。
|
|
@@ -96,4 +96,513 @@ declare function BandMark({ size, className }: {
|
|
|
96
96
|
/** Band 字标(五线谱 + 三个音符 + 「Band」,DESIGN.md「标志」)。样式在 Band Design 的 `.logo`。 */
|
|
97
97
|
declare function LogoLockup(): react.JSX.Element;
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
/** 一次页内跳转的目标:页键与地址参数,由调用方交给宿主。 */
|
|
100
|
+
interface SettingsTarget {
|
|
101
|
+
page: string;
|
|
102
|
+
params?: Record<string, string>;
|
|
103
|
+
}
|
|
104
|
+
/** 导航里的一项(分区导航的链接)。 */
|
|
105
|
+
interface SettingsNavItem extends SettingsTarget {
|
|
106
|
+
slug: string;
|
|
107
|
+
title: string;
|
|
108
|
+
href: string;
|
|
109
|
+
/** 右侧 16px 状态符号(同侧栏),可选。 */
|
|
110
|
+
glyph?: ReactNode;
|
|
111
|
+
}
|
|
112
|
+
interface SettingsGroup {
|
|
113
|
+
group: string;
|
|
114
|
+
sections: readonly SettingsNavItem[];
|
|
115
|
+
}
|
|
116
|
+
/** 页头上方那行返回(`‹ 设置`、`‹ 列表名`)。 */
|
|
117
|
+
interface SettingsBackTarget extends SettingsTarget {
|
|
118
|
+
label: string;
|
|
119
|
+
href: string;
|
|
120
|
+
}
|
|
121
|
+
type Navigate = (target: SettingsTarget) => void;
|
|
122
|
+
/** 只在主键上点(没按修饰键)时走页内跳转;其余交给浏览器(新标签页)。 */
|
|
123
|
+
declare function settingsLinkHandler(go: Navigate | undefined, target: SettingsTarget): (e: MouseEvent<HTMLAnchorElement>) => void;
|
|
124
|
+
/**
|
|
125
|
+
* 四个作用域共用的骨架(稿 §3.1、§3.7):左边分区导航、右边内容。作用域只决定导航头与分区名单;
|
|
126
|
+
* 摆法与手机宽度(600px)下的两页切换不变。导航是链接列表(`aria-current="page"`),不是 tablist。
|
|
127
|
+
*/
|
|
128
|
+
declare function SettingsLayout({ navLabel, title, obj, crumb, groups, current, view, back, backMobile, onNavigate, mainRef, children, }: {
|
|
129
|
+
/** 分区导航的 aria-label(「设置分区」「项目设置分区」)。 */
|
|
130
|
+
navLabel: string;
|
|
131
|
+
title: string;
|
|
132
|
+
/** 导航头第二行(「只有你看得到这里」)。 */
|
|
133
|
+
obj?: ReactNode;
|
|
134
|
+
/** 导航头上方的面包屑;项目、工坊作用域的对象头沿用页面顶栏,一般不传。 */
|
|
135
|
+
crumb?: ReactNode;
|
|
136
|
+
groups: readonly SettingsGroup[];
|
|
137
|
+
/** 当前分区的 slug;目录页不传。 */
|
|
138
|
+
current?: string | undefined;
|
|
139
|
+
view?: "page" | "index";
|
|
140
|
+
/** 详情 / 新增页头上的「‹ 列表名」:宽窄都画(稿 §3.2)。 */
|
|
141
|
+
back?: SettingsBackTarget | undefined;
|
|
142
|
+
/** 分区页给手机宽度的「‹ 设置」:只在窄屏画(稿 §3.7)。 */
|
|
143
|
+
backMobile?: SettingsBackTarget | undefined;
|
|
144
|
+
/** 页内跳转;不给就按普通链接走。 */
|
|
145
|
+
onNavigate?: Navigate;
|
|
146
|
+
/** 内容区的 ref(接线层在上面装未保存离开的守卫)。 */
|
|
147
|
+
mainRef?: Ref<HTMLElement>;
|
|
148
|
+
children: ReactNode;
|
|
149
|
+
}): react.JSX.Element;
|
|
150
|
+
/** 「‹ 列表名」:详情、新增页头上方;`mobileOnly` 是只在手机宽度画的「‹ 设置」。 */
|
|
151
|
+
declare function SettingsBack({ target, onNavigate, mobileOnly, }: {
|
|
152
|
+
target: SettingsBackTarget;
|
|
153
|
+
onNavigate?: Navigate | undefined;
|
|
154
|
+
mobileOnly?: boolean;
|
|
155
|
+
}): react.JSX.Element;
|
|
156
|
+
/** 页头:标题(分区名)+ 一句说明这里管什么、谁看得到 + 主操作(靠右,一页最多一个)。 */
|
|
157
|
+
declare function SettingsHead({ title, desc, action, }: {
|
|
158
|
+
title: ReactNode;
|
|
159
|
+
desc?: ReactNode;
|
|
160
|
+
action?: ReactNode;
|
|
161
|
+
}): react.JSX.Element;
|
|
162
|
+
/** 列表:行不画框不画线,悬停垫浅底;整行进详情。 */
|
|
163
|
+
declare function SettingsRows({ label, children }: {
|
|
164
|
+
label: string;
|
|
165
|
+
children: ReactNode;
|
|
166
|
+
}): react.JSX.Element;
|
|
167
|
+
/**
|
|
168
|
+
* 一行:(可选的头像 / 图标位)名称 + 标记 / 一行元信息 / 右端最多一个快捷操作 + 进详情的箭头。
|
|
169
|
+
* 给了 `onOpen` 时整行可点。
|
|
170
|
+
*/
|
|
171
|
+
declare function SettingsRow({ title, tags, meta, actions, leading, href, onOpen, mono, isNew, extra, }: {
|
|
172
|
+
title: ReactNode;
|
|
173
|
+
tags?: ReactNode;
|
|
174
|
+
meta?: readonly ReactNode[];
|
|
175
|
+
actions?: ReactNode;
|
|
176
|
+
/** 名称左边的头像或图标(成员行用 `Avatar`),占两行高。 */
|
|
177
|
+
leading?: ReactNode;
|
|
178
|
+
href?: string;
|
|
179
|
+
onOpen?: () => void;
|
|
180
|
+
mono?: boolean;
|
|
181
|
+
/** 刚保存的那一行垫 `--ok-soft`(回列表时标出来)。 */
|
|
182
|
+
isNew?: boolean;
|
|
183
|
+
/** 行内展开的一块,占满整行宽。画它时别给 `onOpen`:整行链接会盖住它。 */
|
|
184
|
+
extra?: ReactNode;
|
|
185
|
+
}): react.JSX.Element;
|
|
186
|
+
interface SettingsFact {
|
|
187
|
+
key: string;
|
|
188
|
+
value: ReactNode;
|
|
189
|
+
}
|
|
190
|
+
/** 详情概况:定义列表,不画框。 */
|
|
191
|
+
declare function SettingsFacts({ items }: {
|
|
192
|
+
items: readonly SettingsFact[];
|
|
193
|
+
}): react.JSX.Element;
|
|
194
|
+
/** 一节:`h2` + 可选的一句说明 + 内容;节与节之间留白,不画线、不套卡(稿 §3.1)。 */
|
|
195
|
+
declare function SettingsSection({ title, desc, children, }: {
|
|
196
|
+
title: string;
|
|
197
|
+
desc?: ReactNode;
|
|
198
|
+
children: ReactNode;
|
|
199
|
+
}): react.JSX.Element;
|
|
200
|
+
/**
|
|
201
|
+
* 只有一份设置的分区(提醒、批准):不分节、不画 h2(稿 §3.2),控件、说明与反馈竖排。
|
|
202
|
+
* 名字给 `aria-label`;里面要成组的控件自己放 `fieldset`(组件抹掉它的默认框)。
|
|
203
|
+
*/
|
|
204
|
+
declare function SettingsSingle({ label, children }: {
|
|
205
|
+
label: string;
|
|
206
|
+
children: ReactNode;
|
|
207
|
+
}): react.JSX.Element;
|
|
208
|
+
/** 一排勾选(`.choice`):自动折行。 */
|
|
209
|
+
declare function SettingsChoices({ children }: {
|
|
210
|
+
children: ReactNode;
|
|
211
|
+
}): react.JSX.Element;
|
|
212
|
+
/** 起点选项块的一项:标题加一句说明。 */
|
|
213
|
+
interface SettingsPick<T extends string> {
|
|
214
|
+
value: T;
|
|
215
|
+
label: ReactNode;
|
|
216
|
+
line?: ReactNode;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 选项块(单选):一排块,每块一句标题、一句说明,选中的块 `--accent-soft` 底加 2px `--accent` 内描边;
|
|
220
|
+
* 用在「先选类型,下面再填该填的字段」的表单最前面(设置体系 §4.1;新建工坊的「从哪开始」)。
|
|
221
|
+
* 单选按钮藏起来(`.sr-only`),块本身是 `label`,键盘方向键照原生单选走。≤599 宽一列。
|
|
222
|
+
*/
|
|
223
|
+
declare function SettingsPicks<T extends string>({ label, value, onChange, options, disabled, }: {
|
|
224
|
+
label: ReactNode;
|
|
225
|
+
value: T;
|
|
226
|
+
onChange: (value: T) => void;
|
|
227
|
+
options: readonly SettingsPick<T>[];
|
|
228
|
+
disabled?: boolean;
|
|
229
|
+
}): react.JSX.Element;
|
|
230
|
+
/** 危险操作区:只在详情页最下面,每项一行(动作 + 后果一句 + 按钮),按钮是 `.btn.danger`(稿 §3.6)。 */
|
|
231
|
+
declare function SettingsDanger({ children }: {
|
|
232
|
+
children: ReactNode;
|
|
233
|
+
}): react.JSX.Element;
|
|
234
|
+
declare function SettingsDangerRow({ title, note, action, }: {
|
|
235
|
+
title: ReactNode;
|
|
236
|
+
note: ReactNode;
|
|
237
|
+
action: ReactNode;
|
|
238
|
+
}): react.JSX.Element;
|
|
239
|
+
/** 加载:页头照常画,内容区用 Band Design 的 `.tuning`(五线谱)配「正在读取<什么>…」;不画骨架条(稿 §3.3)。 */
|
|
240
|
+
declare function SettingsLoading({ text }: {
|
|
241
|
+
text: string;
|
|
242
|
+
}): react.JSX.Element;
|
|
243
|
+
/** 空:休止符插画 + 一句「还没有什么、有了能做什么」+ 主操作(没有新增权限时不画按钮)。 */
|
|
244
|
+
declare function SettingsEmpty({ children, action }: {
|
|
245
|
+
children: ReactNode;
|
|
246
|
+
action?: ReactNode;
|
|
247
|
+
}): react.JSX.Element;
|
|
248
|
+
/** 读失败:一行 `ErrorNote`(「<什么>没读出来:<原因>」+「重试」)。 */
|
|
249
|
+
declare function SettingsReadError({ children, retry }: {
|
|
250
|
+
children: ReactNode;
|
|
251
|
+
retry: () => void;
|
|
252
|
+
}): react.JSX.Element;
|
|
253
|
+
/**
|
|
254
|
+
* 没有权限(读 403)与环境没开通:标题、谁能看 / 缺什么、去找谁,一个离开的按钮(可不给);不画重试(稿 §3.3)。
|
|
255
|
+
*/
|
|
256
|
+
declare function SettingsNoAccess({ title, children, action, }: {
|
|
257
|
+
title: string;
|
|
258
|
+
children: ReactNode;
|
|
259
|
+
action?: {
|
|
260
|
+
label: string;
|
|
261
|
+
onClick: () => void;
|
|
262
|
+
} | undefined;
|
|
263
|
+
}): react.JSX.Element;
|
|
264
|
+
/** 保存后的读屏播报(「已保存」「已删除」,不抢眼、不占版面)。 */
|
|
265
|
+
declare function SettingsNotice({ text }: {
|
|
266
|
+
text: string;
|
|
267
|
+
}): react.JSX.Element;
|
|
268
|
+
/** 「已保存」那一句(控件旁或按钮旁,停四拍由调用方的 `useSavedNote` 管)。 */
|
|
269
|
+
declare function SettingsSaved({ text }: {
|
|
270
|
+
text?: ReactNode;
|
|
271
|
+
}): react.JSX.Element;
|
|
272
|
+
/**
|
|
273
|
+
* 确认弹窗(稿 §3.6):`--scrim`、`--shadow-pop`、`--r-xl`;标题问动作,正文列后果,末尾写能不能恢复。
|
|
274
|
+
* 不用输入名字确认:弹窗已列后果,多打一遍字不增加信息。
|
|
275
|
+
*/
|
|
276
|
+
declare function SettingsDialog({ title, children, actions, onClose, }: {
|
|
277
|
+
title: string;
|
|
278
|
+
children: ReactNode;
|
|
279
|
+
actions: ReactNode;
|
|
280
|
+
onClose: () => void;
|
|
281
|
+
}): react.JSX.Element;
|
|
282
|
+
/** 设置里的表单:字段竖排,最宽 560。提交走 `onSubmit`(已 `preventDefault`)。 */
|
|
283
|
+
declare function SettingsForm({ label, onSubmit, children, }: {
|
|
284
|
+
label?: string;
|
|
285
|
+
onSubmit?: () => void;
|
|
286
|
+
children: ReactNode;
|
|
287
|
+
}): react.JSX.Element;
|
|
288
|
+
/** 字段的输入要挂的属性:id、读屏说明、出错标记。 */
|
|
289
|
+
interface SettingsFieldProps {
|
|
290
|
+
id: string;
|
|
291
|
+
"aria-describedby"?: string;
|
|
292
|
+
"aria-invalid"?: true;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 字段行:标签(必填写「必填」)、输入、下一行的提示或出错、计数。提示 / 出错 / 计数用 Band Design 的
|
|
296
|
+
* `.field-note`(出错加 `.err`)与 `.field-count`(DESIGN.md「控件」),出错时输入挂 `aria-invalid`。
|
|
297
|
+
* 输入本身由调用方用 Band Design 的 `.field` 画,组件只摆位置、接好 id 与读屏说明。
|
|
298
|
+
*/
|
|
299
|
+
declare function SettingsField({ label, required, optional, hint, error, count, over, children, }: {
|
|
300
|
+
label: ReactNode;
|
|
301
|
+
required?: boolean;
|
|
302
|
+
/** 选填:标签旁写「选填」(稿 §3.5 的样张两种都标);与 `required` 不同时给。 */
|
|
303
|
+
optional?: boolean;
|
|
304
|
+
hint?: ReactNode;
|
|
305
|
+
/** 出错的话;有它时不画提示。 */
|
|
306
|
+
error?: ReactNode;
|
|
307
|
+
/** 计数(「12 / 200」),靠右。 */
|
|
308
|
+
count?: ReactNode;
|
|
309
|
+
/** 计数超了:计数变红。 */
|
|
310
|
+
over?: boolean;
|
|
311
|
+
children: (props: SettingsFieldProps) => ReactNode;
|
|
312
|
+
}): react.JSX.Element;
|
|
313
|
+
/** 表单末尾的操作行:按钮 + 保存反馈 / 还缺什么。 */
|
|
314
|
+
declare function SettingsActions({ children, end, }: {
|
|
315
|
+
children: ReactNode;
|
|
316
|
+
end?: boolean;
|
|
317
|
+
}): react.JSX.Element;
|
|
318
|
+
/**
|
|
319
|
+
* 保存反馈(稿 §3.5):`saving` 时写在做什么(「正在验证…」那一档的旁注),`saved` 停四拍的「已保存」,
|
|
320
|
+
* `failed` 是贴在按钮旁的整体错误(「没保存:」开头),`missing` 是按钮置灰时缺什么(「还差 key 没填」)。
|
|
321
|
+
* 不用吐司;读屏走 `aria-live`。
|
|
322
|
+
*/
|
|
323
|
+
declare function SettingsSaveState({ saving, saved, failed, missing, }: {
|
|
324
|
+
saving?: ReactNode;
|
|
325
|
+
/** `true` 写「已保存」;给文字或节点就照它写(「已保存,ModelGate 验证通过」)。 */
|
|
326
|
+
saved?: ReactNode;
|
|
327
|
+
failed?: ReactNode;
|
|
328
|
+
missing?: ReactNode;
|
|
329
|
+
}): react.JSX.Element;
|
|
330
|
+
|
|
331
|
+
/** 下拉里的一项。`group` 相同的排在一段,段的顺序按它第一次出现的顺序。 */
|
|
332
|
+
interface ComboboxItem {
|
|
333
|
+
value: string;
|
|
334
|
+
label: string;
|
|
335
|
+
group?: string;
|
|
336
|
+
/** 行尾的补充说明(部门、类型),用等宽字体。 */
|
|
337
|
+
meta?: string;
|
|
338
|
+
/** label 之外用来搜索的文字(部门、拼音备注),不进占位提示。 */
|
|
339
|
+
keywords?: string;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* 可搜索的单选 / 多选(样张 §2「Combobox」)。键盘:↑↓ 移动、回车选中、「空格」在多选里切换选中、
|
|
343
|
+
* Esc 关闭、输入过滤;退格在空输入时删掉最后一个已选。
|
|
344
|
+
*
|
|
345
|
+
* 空格只在查询为空时切换选中:查询里带了字时空格照常输入,否则「Wang Min」这种名字搜不了
|
|
346
|
+
* (样张只演示了空查询下的多选,这一点按能打字优先定)。
|
|
347
|
+
*/
|
|
348
|
+
declare function Combobox({ label, items, value, onChange, multiple, placeholder, emptyText, onCreate, createLabel, disabled, }: {
|
|
349
|
+
/** 输入框的无障碍名,也是空结果那句「没有匹配的<label>」里的名字。 */
|
|
350
|
+
label: string;
|
|
351
|
+
items: readonly ComboboxItem[];
|
|
352
|
+
/** 受控:已选的值,按选中的先后。 */
|
|
353
|
+
value: readonly string[];
|
|
354
|
+
onChange(next: readonly string[]): void;
|
|
355
|
+
/** 多选:回车与空格切换选中、列表不关;单选:回车选中并关闭。 */
|
|
356
|
+
multiple?: boolean;
|
|
357
|
+
placeholder?: string;
|
|
358
|
+
/** 空结果那一行的整句,缺省「没有匹配的<label>」。 */
|
|
359
|
+
emptyText?: string;
|
|
360
|
+
/**
|
|
361
|
+
* 查询非空、且没有名字正好相同的候选时,列表末尾多一行「新建」。选中它时把这句查询交回调用方
|
|
362
|
+
* (建完由调用方把新值放进 `value`)。
|
|
363
|
+
*/
|
|
364
|
+
onCreate?(name: string): void;
|
|
365
|
+
/** 「新建」那行的写法,缺省「新建「<查询>」」。 */
|
|
366
|
+
createLabel?(name: string): string;
|
|
367
|
+
disabled?: boolean;
|
|
368
|
+
}): react.JSX.Element;
|
|
369
|
+
/**
|
|
370
|
+
* 一段文字拆成标签:按逗号(半角、全角)、换行、制表符拆,去掉首尾空白与空串,**不去重**
|
|
371
|
+
* (重复要提示,不能悄悄吃掉)。纯函数,单测与 TagInput 共用。
|
|
372
|
+
*/
|
|
373
|
+
declare function splitTags(text: string): string[];
|
|
374
|
+
/**
|
|
375
|
+
* 数组值(样张 §2「Tag Input」):值受控,回车或逗号确认一个,粘贴带分隔符时整段拆开;重复的值不加入,
|
|
376
|
+
* 已有的那个闪一下红底并在下面写一句(「「x」重复了,已跳过」,1.8 秒后退回);输入框空着时退格删最后一个。
|
|
377
|
+
*
|
|
378
|
+
* 输入法:回车、退格都经 `withImeGuard`——组字中选字的回车不能当成「加一个标签」。
|
|
379
|
+
*/
|
|
380
|
+
declare function TagInput({ label, value, onChange, placeholder, hint, disabled, id, }: {
|
|
381
|
+
/** 输入框的无障碍名。 */
|
|
382
|
+
label: string;
|
|
383
|
+
/** 受控:标签,按加入的先后。 */
|
|
384
|
+
value: readonly string[];
|
|
385
|
+
onChange(next: readonly string[]): void;
|
|
386
|
+
placeholder?: string;
|
|
387
|
+
/** 常态那句说明(「粘贴「五年级, 分数」会拆成两个」);重复时换成提示,1.8 秒后退回这句。 */
|
|
388
|
+
hint?: string;
|
|
389
|
+
disabled?: boolean;
|
|
390
|
+
id?: string;
|
|
391
|
+
}): react.JSX.Element;
|
|
392
|
+
/** 筛选项:一段里的一个值。 */
|
|
393
|
+
interface FilterOption {
|
|
394
|
+
value: string;
|
|
395
|
+
label: string;
|
|
396
|
+
}
|
|
397
|
+
/** 一段筛选:`key` 是行数据里的字段名。 */
|
|
398
|
+
interface FilterGroup {
|
|
399
|
+
key: string;
|
|
400
|
+
label: string;
|
|
401
|
+
options: readonly FilterOption[];
|
|
402
|
+
}
|
|
403
|
+
/** 一行在各分组上的取值(`row[group.key]`)。 */
|
|
404
|
+
type FilterRow = Readonly<Record<string, string>>;
|
|
405
|
+
/** 已选:分组 key → 选中的值(段内是「或」)。 */
|
|
406
|
+
type FilterSelection = Readonly<Record<string, readonly string[]>>;
|
|
407
|
+
/**
|
|
408
|
+
* 计数(样张 §2「Filter Menu」的 faceted 口径):某个选项的计数 = 在**其他**分组的已选条件下还剩多少行,
|
|
409
|
+
* 也带自己这一段——和产物库的「勾了别的组,这一段的数跟着缩」同一口径。纯函数,单测与 FilterMenu 共用。
|
|
410
|
+
*/
|
|
411
|
+
declare function facetedCount(rows: readonly FilterRow[], groups: readonly FilterGroup[], selection: FilterSelection, groupKey: string, value: string): number;
|
|
412
|
+
/** 按已选筛行:每组内是「或」,组之间是「且」。纯函数。 */
|
|
413
|
+
declare function filterRows(rows: readonly FilterRow[], groups: readonly FilterGroup[], selection: FilterSelection): readonly FilterRow[];
|
|
414
|
+
/**
|
|
415
|
+
* 分组筛选(样张 §2「Filter Menu」)。分组可折叠(组标题是按钮,`aria-expanded`),计数按当前其他分组
|
|
416
|
+
* 的已选算(`facetedCount`),已选的做成 chip 可单个移除,右端「清空」。值受控。
|
|
417
|
+
*
|
|
418
|
+
* 键盘:组标题与每个勾选框都在正常的 Tab 顺序里(勾选框是原生 `<input type="checkbox">`),空格切换;
|
|
419
|
+
* 点组标题只折叠/展开,不改筛选。
|
|
420
|
+
*/
|
|
421
|
+
declare function FilterMenu({ groups, rows, value, onChange, emptyText, }: {
|
|
422
|
+
groups: readonly FilterGroup[];
|
|
423
|
+
/** 用来算计数的行(通常是未筛选的全量;传筛过的会让计数越筛越小)。 */
|
|
424
|
+
rows: readonly FilterRow[];
|
|
425
|
+
value: FilterSelection;
|
|
426
|
+
onChange(next: FilterSelection): void;
|
|
427
|
+
/** 一段里一个选项都没有时那一行,缺省「没有可筛的」。 */
|
|
428
|
+
emptyText?: string;
|
|
429
|
+
}): react.JSX.Element;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 页面里的 toast(backlog #5):刚做完一件事的即时回执。宿主(外壳)画唯一一层容器 `ToastHost`,
|
|
433
|
+
* 插件与锁定插件只 import 这里的 `toast()` 入队,不自己画容器——两个插件同时弹也落进同一摞,不会各画一层。
|
|
434
|
+
*
|
|
435
|
+
* 模块级 store 是有意为之:`@kanyun-ai-infra/band-plugin-react` 是宿主提供的共享模块,宿主与每个插件拿到同一个
|
|
436
|
+
* 实例;而每个插件各开一个 React root,React context 跨不过去,ctx 也没有这个能力(加它要改协议)。
|
|
437
|
+
*
|
|
438
|
+
* 规则照样张(docs/design/specimens/band-design-components.html §5,本卡按它实现):
|
|
439
|
+
* - 成功 4 秒自己收;鼠标停在上面时不收,移开后 2 秒再收;
|
|
440
|
+
* - 错误不自己走,要么点「重试」要么关掉(没给动作时容器补一个「关闭」);
|
|
441
|
+
* - 进行中做完在同一条里变成勾(用同一个 id 再调一次 `toast`),不新弹一条;
|
|
442
|
+
* - 同时最多三条,第四条挤掉最早的一条(进行中的先留着)。
|
|
443
|
+
*
|
|
444
|
+
* 模块级状态跟着页面活:测试要清干净用 `dismissAllToasts`。
|
|
445
|
+
*/
|
|
446
|
+
type ToastKind = "ok" | "bad" | "busy";
|
|
447
|
+
/** toast 上的一个动作(错误一般是「重试」)。 */
|
|
448
|
+
interface ToastAction {
|
|
449
|
+
label: string;
|
|
450
|
+
onClick: () => void;
|
|
451
|
+
}
|
|
452
|
+
interface ToastOptions {
|
|
453
|
+
/** 缺省 `ok`。 */
|
|
454
|
+
kind?: ToastKind;
|
|
455
|
+
/** 一行说明。 */
|
|
456
|
+
text: string;
|
|
457
|
+
/** 第二行小字。 */
|
|
458
|
+
detail?: string;
|
|
459
|
+
/** 一个动作;错误的「重试」放这里。 */
|
|
460
|
+
action?: ToastAction;
|
|
461
|
+
/** 传已有的 id:改那一条(进行中做完变成勾),不新弹一条。 */
|
|
462
|
+
id?: string;
|
|
463
|
+
}
|
|
464
|
+
interface ToastItem {
|
|
465
|
+
id: string;
|
|
466
|
+
kind: ToastKind;
|
|
467
|
+
text: string;
|
|
468
|
+
detail?: string;
|
|
469
|
+
action?: ToastAction;
|
|
470
|
+
}
|
|
471
|
+
/** 弹一条;传 `id` 就是改那一条。返回它的 id。 */
|
|
472
|
+
declare function toast(opts: ToastOptions): string;
|
|
473
|
+
/** 收起一条(动作、Esc、关掉都走这里)。 */
|
|
474
|
+
declare function dismissToast(id: string): void;
|
|
475
|
+
/** 全部收掉(换身份、测试收尾)。 */
|
|
476
|
+
declare function dismissAllToasts(): void;
|
|
477
|
+
|
|
478
|
+
/** 宿主画的一次性容器;一页只有一个(`band-shell`)。插件调 `toast()`,不自己画。 */
|
|
479
|
+
declare function ToastHost(): react.JSX.Element;
|
|
480
|
+
|
|
481
|
+
interface ChainedPerson {
|
|
482
|
+
id: string;
|
|
483
|
+
/** 这个人所在部门的链;挂在多个部门时任取其一,判定只看是否在某部门之下。 */
|
|
484
|
+
chain?: string;
|
|
485
|
+
}
|
|
486
|
+
interface Blocked extends ChainedPerson {
|
|
487
|
+
reason: string;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** 一个人。`id` 是 ldap;`path` 是部门路径(「研发中心 / 平台组」),只用来看清是谁。 */
|
|
491
|
+
interface PickerPerson {
|
|
492
|
+
id: string;
|
|
493
|
+
name: string;
|
|
494
|
+
path?: string;
|
|
495
|
+
/** 部门 id 链(「/」隔开,`1/5/9`),算部门勾选态用;推不出时没有。 */
|
|
496
|
+
chain?: string;
|
|
497
|
+
/** false:还没登录过 Band(名字从组织架构来)。不影响能不能选(owner 11-14),只在已选名单里标一句。 */
|
|
498
|
+
inBand?: boolean;
|
|
499
|
+
}
|
|
500
|
+
/** 一个部门。`count` 是含下级部门的总人数;`count` 与 `chain` 都有才画勾选框。 */
|
|
501
|
+
interface PickerOrg {
|
|
502
|
+
id: string;
|
|
503
|
+
name: string;
|
|
504
|
+
path?: string;
|
|
505
|
+
chain?: string;
|
|
506
|
+
count?: number;
|
|
507
|
+
}
|
|
508
|
+
/** 不能选的人:原因写在候选行上;带 `chain` 时从部门的可选人数里扣掉。 */
|
|
509
|
+
type BlockedPerson = Blocked;
|
|
510
|
+
/** 目录的一页:一层部门的下级部门与直属的人,或一次搜索的结果。 */
|
|
511
|
+
interface DirectoryPage {
|
|
512
|
+
orgs: readonly PickerOrg[];
|
|
513
|
+
people: readonly PickerPerson[];
|
|
514
|
+
/** 搜索结果被上游截断了:提示换个更准的词。 */
|
|
515
|
+
truncated?: boolean;
|
|
516
|
+
/** 组织架构读不到、退回了 Band 用户目录:写原因,弹层顶上一直显示。 */
|
|
517
|
+
fallback?: string;
|
|
518
|
+
}
|
|
519
|
+
/** 数据口。所有方法收 `signal`:换词、关弹层时取消上一次。 */
|
|
520
|
+
interface PersonDirectory {
|
|
521
|
+
/** 组织架构现在用不了时的原因(退回了 Band 用户目录):没搜之前也在弹层顶上显示。 */
|
|
522
|
+
unavailable?: string;
|
|
523
|
+
search(q: string, opts: {
|
|
524
|
+
signal: AbortSignal;
|
|
525
|
+
}): Promise<DirectoryPage>;
|
|
526
|
+
/** 按部门浏览;`null` 是根。没有这个方法就只能搜。 */
|
|
527
|
+
browse?(orgId: string | null, opts: {
|
|
528
|
+
signal: AbortSignal;
|
|
529
|
+
chain?: string;
|
|
530
|
+
}): Promise<DirectoryPage>;
|
|
531
|
+
/** 一个部门(含下级)的全部人,最多 `limit` 个;`total` 是真实总数。 */
|
|
532
|
+
members?(orgId: string, opts: {
|
|
533
|
+
signal: AbortSignal;
|
|
534
|
+
limit: number;
|
|
535
|
+
chain?: string;
|
|
536
|
+
}): Promise<{
|
|
537
|
+
people: readonly PickerPerson[];
|
|
538
|
+
total: number;
|
|
539
|
+
}>;
|
|
540
|
+
/** 粘贴多个 ldap 时按 ldap 批量解析;找不到的放 `missing`。 */
|
|
541
|
+
resolve?(ids: readonly string[], opts: {
|
|
542
|
+
signal: AbortSignal;
|
|
543
|
+
}): Promise<{
|
|
544
|
+
people: readonly PickerPerson[];
|
|
545
|
+
missing: readonly string[];
|
|
546
|
+
/** 只能认出一部分人的原因(组织架构读不到):写进提示,免得用户以为 ldap 写错了。 */
|
|
547
|
+
fallback?: string;
|
|
548
|
+
}>;
|
|
549
|
+
}
|
|
550
|
+
interface PersonSearchProps {
|
|
551
|
+
/** 输入框的无障碍名(「添加管理员」「加人」)。 */
|
|
552
|
+
label: string;
|
|
553
|
+
directory: PersonDirectory;
|
|
554
|
+
/** 已选的人:在候选里打勾(多选)或显示在输入框里(单选),不再重复加。 */
|
|
555
|
+
picked: readonly PickerPerson[];
|
|
556
|
+
/** 选中的人(单选一个;多选可能是整个部门或一次粘贴的一批,已按 ldap 去重)。 */
|
|
557
|
+
onPick(people: readonly PickerPerson[]): void;
|
|
558
|
+
/** 取消选中(多选里点已勾的人、取消整个部门;单选里点 ×)。 */
|
|
559
|
+
onUnpick?(ids: readonly string[]): void;
|
|
560
|
+
multiple?: boolean;
|
|
561
|
+
/** 还能再加几个人(名单上限减去已选);不给就不限。 */
|
|
562
|
+
room?: number;
|
|
563
|
+
/** 不能选的人与原因(「已经是管理员」)。 */
|
|
564
|
+
disabled?: readonly BlockedPerson[];
|
|
565
|
+
/** 目录里没有的 ldap 也能加(名字先写 ldap)。 */
|
|
566
|
+
allowUnknown?: boolean;
|
|
567
|
+
placeholder?: string;
|
|
568
|
+
/** 整个控件禁用(保存中)。 */
|
|
569
|
+
busy?: boolean;
|
|
570
|
+
/** 根的名字(浏览时路径的第一段)。 */
|
|
571
|
+
rootLabel?: string;
|
|
572
|
+
/**
|
|
573
|
+
* 取到一个部门的全员时,把带部门链的人交给宿主(宿主拿来给名单里已有、还没链的人补链,省一次解析)。
|
|
574
|
+
* 包括已经在名单里、这次没有新加的人。
|
|
575
|
+
*/
|
|
576
|
+
onLearn?(people: readonly PickerPerson[]): void;
|
|
577
|
+
/** 一开始就展开(样张、设计站用)。 */
|
|
578
|
+
defaultOpen?: boolean;
|
|
579
|
+
/** 一开始的搜索词(样张用)。 */
|
|
580
|
+
defaultQuery?: string;
|
|
581
|
+
/** 一开始浏览到哪(从根往下的部门,样张用)。 */
|
|
582
|
+
defaultTrail?: readonly PickerOrg[];
|
|
583
|
+
}
|
|
584
|
+
/** 搜索框 + 弹层:搜人、按部门逐级进入、勾整个部门、粘贴多个 ldap。 */
|
|
585
|
+
declare function PersonSearch({ label, directory, picked, onPick, onUnpick, multiple, room, disabled, allowUnknown, placeholder, busy, rootLabel, onLearn, defaultOpen, defaultQuery, defaultTrail, }: PersonSearchProps): react.JSX.Element;
|
|
586
|
+
interface PersonPickerProps extends Omit<PersonSearchProps, "picked" | "onPick" | "onUnpick" | "room" | "multiple"> {
|
|
587
|
+
/** 受控:名单上的人,按加入先后。 */
|
|
588
|
+
value: readonly PickerPerson[];
|
|
589
|
+
onChange(next: readonly PickerPerson[]): void;
|
|
590
|
+
/** 名单上限(同服务端)。 */
|
|
591
|
+
max?: number;
|
|
592
|
+
/** 只读:只列名单,没有加人和移出。 */
|
|
593
|
+
readOnly?: boolean;
|
|
594
|
+
/** 移出前在行内再确认一次(改动即时生效的名单用;有「保存」的表单不用)。 */
|
|
595
|
+
confirmRemove?: boolean;
|
|
596
|
+
/** 名单为空时的一句话。 */
|
|
597
|
+
emptyText?: string;
|
|
598
|
+
/** 这些人不能移出与原因(「创建人」);取消整个部门时也不动他们。 */
|
|
599
|
+
locked?: Readonly<Record<string, string>>;
|
|
600
|
+
/** 换掉下面的加人框(一次加一个、要另填角色再提交的地方:放单选的 `PersonSearch` 和提交按钮)。 */
|
|
601
|
+
addSlot?: ReactNode;
|
|
602
|
+
}
|
|
603
|
+
/** 名单 + 加人:已选的人一行一个(头像、名字、ldap、部门),可移出;下面是多选的 `PersonSearch`。 */
|
|
604
|
+
declare function PersonPicker({ value, onChange, max, readOnly, confirmRemove, emptyText, locked, addSlot, label, ...search }: PersonPickerProps): react.JSX.Element;
|
|
605
|
+
/** 把宿主的人员目录(`ctx.people`)接成选择器的数据口。取消信号不往下传:过期的结果组件自己丢掉。 */
|
|
606
|
+
declare function peopleDirectory(api: PeopleApi): PersonDirectory;
|
|
607
|
+
|
|
608
|
+
export { AgentAvatar, Avatar, BandMark, type BlockedPerson, Combobox, type ComboboxItem, type DirectoryPage, ErrorNote, type FilterGroup, FilterMenu, type FilterOption, type FilterRow, type FilterSelection, Glyph, type GlyphKind, INSTRUMENTS, InfoNote, type Instrument, LogoLockup, PaneHeader, type PersonDirectory, PersonPicker, type PersonPickerProps, PersonSearch, type PersonSearchProps, type PickerOrg, type PickerPerson, SettingsActions, SettingsBack, type SettingsBackTarget, SettingsChoices, SettingsDanger, SettingsDangerRow, SettingsDialog, SettingsEmpty, type SettingsFact, SettingsFacts, SettingsField, type SettingsFieldProps, SettingsForm, type SettingsGroup, SettingsHead, SettingsLayout, SettingsLoading, type SettingsNavItem, SettingsNoAccess, SettingsNotice, type SettingsPick, SettingsPicks, SettingsReadError, SettingsRow, SettingsRows, SettingsSaveState, SettingsSaved, SettingsSection, SettingsSingle, type SettingsTarget, TagInput, type ToastAction, ToastHost, type ToastItem, type ToastKind, type ToastOptions, WorkshopEmblem, WorkshopIcon, agentInstrument, avatarInitial, avatarTone, dismissAllToasts, dismissToast, facetedCount, filterRows, instrumentOf, memberOrder, peopleDirectory, settingsLinkHandler, splitTags, toast };
|