one-design-next 0.0.47 → 0.0.49

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,747 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
8
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
9
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
10
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
11
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
12
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
14
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
15
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
16
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
17
+ import * as React from 'react';
18
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
19
+ import Button from "../button";
20
+ import DatePicker from "../date-picker";
21
+ import HoverFill from "../hover-fill";
22
+ import Icon from "../icon";
23
+ import Input from "../input";
24
+ import Pagination from "../pagination";
25
+ import { toISODate } from "./types";
26
+ import "./style";
27
+
28
+ /* ------------------------------------------------------------------ */
29
+ /* ClarifyDock */
30
+ /* ------------------------------------------------------------------ */
31
+ /*
32
+ * 真实形态:Trigger 在 AI 消息正文里,Panel 通过 Host 的 dock slot 吸附在
33
+ * Composer 上方——而不是 Trigger + Panel 同框。
34
+ *
35
+ * 导出三件套:
36
+ * - <ClarifyDockTrigger />:Approval 式锁态卡(折叠 + 展开题→答)
37
+ * - <ClarifyDockPanel />:多题分页 form 面板
38
+ * - useClarifyDockState(messages):派生 pending / answered
39
+ *
40
+ * 多题节奏:一次只问一题;底栏左 Pagination simple(仅页码),右「上一题 / 下一题|确认」。
41
+ * 全部必答。单选 / 多选末项「其他」由 allowOther 注入。
42
+ */
43
+
44
+ /** 整卷提交:自然语言摘要 + 结构化 data + 锁态小票行。 */
45
+
46
+ /** Host 消息最小形状——hook 只认 assistant + clarify-dock instance。 */
47
+
48
+ /* ================================================================== */
49
+ /* Trigger · Approval 式锁态卡(折叠默认 + 展开题→答) */
50
+ /* ================================================================== */
51
+
52
+ /** 题面「?」→「:」后与答案拼成一行,如「需要拆解哪些维度:素材」。 */
53
+ function formatLockedLine(label, answer) {
54
+ var stem = label.replace(/[??]\s*$/, '');
55
+ return "".concat(stem, "\uFF1A").concat(answer);
56
+ }
57
+ export function ClarifyDockTrigger(_ref) {
58
+ var items = _ref.items;
59
+ var _useState = useState(false),
60
+ _useState2 = _slicedToArray(_useState, 2),
61
+ expanded = _useState2[0],
62
+ setExpanded = _useState2[1];
63
+ /* 收合动画结束后再卸掉 panel 占位(对齐 Approval summaryCollapsedSettled) */
64
+ var _useState3 = useState(true),
65
+ _useState4 = _slicedToArray(_useState3, 2),
66
+ collapsedSettled = _useState4[0],
67
+ setCollapsedSettled = _useState4[1];
68
+ useEffect(function () {
69
+ if (expanded) {
70
+ setCollapsedSettled(false);
71
+ return;
72
+ }
73
+ var id = window.setTimeout(function () {
74
+ return setCollapsedSettled(true);
75
+ }, 230);
76
+ return function () {
77
+ return window.clearTimeout(id);
78
+ };
79
+ }, [expanded]);
80
+ if (!items || items.length === 0) return null;
81
+ var multi = items.length > 1;
82
+ var mainLabel = multi ? "\u5DF2\u786E\u8BA4 ".concat(items.length, " \u9898") : formatLockedLine(items[0].label, items[0].answer);
83
+ var handleToggle = function handleToggle() {
84
+ if (expanded) {
85
+ setExpanded(false);
86
+ return;
87
+ }
88
+ setCollapsedSettled(false);
89
+ requestAnimationFrame(function () {
90
+ return setExpanded(true);
91
+ });
92
+ };
93
+ return /*#__PURE__*/React.createElement("div", {
94
+ "data-odn-clarify-dock-locked": true,
95
+ "data-resolved": true,
96
+ "data-summary-expanded": expanded ? '' : undefined
97
+ }, /*#__PURE__*/React.createElement("div", {
98
+ "data-odn-clarify-dock-locked-body": true
99
+ }, /*#__PURE__*/React.createElement("div", {
100
+ "data-odn-clarify-dock-locked-heading": true
101
+ }, /*#__PURE__*/React.createElement("div", {
102
+ "data-odn-clarify-dock-locked-title-row": true
103
+ }, /*#__PURE__*/React.createElement("p", {
104
+ "data-odn-clarify-dock-locked-text": true
105
+ }, /*#__PURE__*/React.createElement(Icon, {
106
+ name: "check",
107
+ size: 14,
108
+ "data-odn-clarify-dock-locked-icon": true
109
+ }), /*#__PURE__*/React.createElement("span", {
110
+ "data-odn-clarify-dock-locked-main": true
111
+ }, mainLabel)), multi ? /*#__PURE__*/React.createElement("button", {
112
+ type: "button",
113
+ "data-odn-clarify-dock-locked-toggle": true,
114
+ "aria-expanded": expanded,
115
+ onClick: handleToggle
116
+ }, /*#__PURE__*/React.createElement("span", null, expanded ? '收起' : '展开'), /*#__PURE__*/React.createElement(Icon, {
117
+ name: "chevron-down",
118
+ size: 14,
119
+ "data-odn-clarify-dock-locked-chevron": true
120
+ })) : null)), multi ? /*#__PURE__*/React.createElement("div", {
121
+ "data-odn-clarify-dock-locked-panel": true,
122
+ "data-open": expanded ? 'true' : 'false',
123
+ "data-collapsed-settled": collapsedSettled ? '' : undefined,
124
+ "aria-hidden": !expanded
125
+ }, /*#__PURE__*/React.createElement("div", {
126
+ "data-odn-clarify-dock-locked-panel-inner": true
127
+ }, /*#__PURE__*/React.createElement("div", {
128
+ "data-odn-clarify-dock-locked-receipt": true
129
+ }, items.map(function (item) {
130
+ return /*#__PURE__*/React.createElement("p", {
131
+ key: item.key,
132
+ "data-odn-clarify-dock-locked-line": true
133
+ }, formatLockedLine(item.label, item.answer));
134
+ })))) : null));
135
+ }
136
+
137
+ /* ================================================================== */
138
+ /* Panel · 多题分页 */
139
+ /* ================================================================== */
140
+
141
+ /** 单题暂存答案。 */
142
+
143
+ var OTHER_VALUE = '__other__';
144
+
145
+ /** 多选已选 8% 底上的 hover 增量(叠后约 12% brand)——供 HoverFill 位移层使用 */
146
+ var MULTI_SELECTED_HOVER_FILL = 'rgba(41, 107, 239, 0.04)';
147
+ var MULTI_UNSELECTED_HOVER_FILL = 'rgba(33, 34, 38, 0.05)';
148
+ var MULTI_UNSELECTED_ACTIVE_FILL = 'rgba(33, 34, 38, 0.08)';
149
+
150
+ /**
151
+ * 单题选项上限(含「其他」),与 A–E 徽标一一对应。
152
+ * 超过时截断业务选项,优先保留末位「其他」。
153
+ */
154
+ export var CLARIFY_DOCK_MAX_OPTIONS = 5;
155
+ var LETTER_BADGES = ['A', 'B', 'C', 'D', 'E'];
156
+ export function ClarifyDockPanel(_ref2) {
157
+ var msgId = _ref2.msgId,
158
+ spec = _ref2.spec,
159
+ onResolve = _ref2.onResolve;
160
+ var total = spec.questions.length;
161
+ var _useState5 = useState(0),
162
+ _useState6 = _slicedToArray(_useState5, 2),
163
+ page = _useState6[0],
164
+ setPage = _useState6[1];
165
+ var _useState7 = useState(function () {
166
+ return new Array(total).fill(undefined);
167
+ }),
168
+ _useState8 = _slicedToArray(_useState7, 2),
169
+ answers = _useState8[0],
170
+ setAnswers = _useState8[1];
171
+ var _useState9 = useState(''),
172
+ _useState10 = _slicedToArray(_useState9, 2),
173
+ otherDraft = _useState10[0],
174
+ setOtherDraft = _useState10[1];
175
+ var _useState11 = useState(null),
176
+ _useState12 = _slicedToArray(_useState11, 2),
177
+ dateDraft = _useState12[0],
178
+ setDateDraft = _useState12[1];
179
+ var question = spec.questions[page];
180
+ var answer = answers[page];
181
+ var input = question.input;
182
+
183
+ /* 切页:回显 other / date 草稿 */
184
+ useEffect(function () {
185
+ if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options' || (answer === null || answer === void 0 ? void 0 : answer.kind) === 'options-multi') {
186
+ var _answer$otherText;
187
+ setOtherDraft((_answer$otherText = answer.otherText) !== null && _answer$otherText !== void 0 ? _answer$otherText : '');
188
+ } else {
189
+ setOtherDraft('');
190
+ }
191
+ if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'date') {
192
+ setDateDraft(answer.value ? new Date("".concat(answer.value, "T00:00:00")) : null);
193
+ } else {
194
+ setDateDraft(null);
195
+ }
196
+ }, [page, answer]);
197
+ var setAnswerForPage = function setAnswerForPage(next) {
198
+ setAnswers(function (prev) {
199
+ var copy = _toConsumableArray(prev);
200
+ copy[page] = next;
201
+ return copy;
202
+ });
203
+ };
204
+ var canAdvance = useMemo(function () {
205
+ if (!answer) return false;
206
+ switch (answer.kind) {
207
+ case 'options':
208
+ if (answer.value === OTHER_VALUE) return otherDraft.trim().length > 0;
209
+ return true;
210
+ case 'options-multi':
211
+ {
212
+ var hasRegular = answer.values.some(function (v) {
213
+ return v !== OTHER_VALUE;
214
+ });
215
+ var hasOther = answer.values.includes(OTHER_VALUE);
216
+ if (hasOther && otherDraft.trim().length === 0) return false;
217
+ return hasRegular || hasOther;
218
+ }
219
+ case 'date':
220
+ case 'text':
221
+ return answer.value.trim().length > 0;
222
+ default:
223
+ return false;
224
+ }
225
+ }, [answer, otherDraft]);
226
+ var isLastPage = page === total - 1;
227
+ var isFirstPage = page === 0;
228
+ var formatAnswer = function formatAnswer(q, ans) {
229
+ if (!ans) return '(未答)';
230
+ switch (ans.kind) {
231
+ case 'options':
232
+ {
233
+ var _ans$otherText;
234
+ if (ans.value === OTHER_VALUE) return (_ans$otherText = ans.otherText) !== null && _ans$otherText !== void 0 ? _ans$otherText : '其他';
235
+ if (q.input.kind === 'options') {
236
+ var _q$input$options$find, _q$input$options$find2;
237
+ return (_q$input$options$find = (_q$input$options$find2 = q.input.options.find(function (o) {
238
+ return o.value === ans.value;
239
+ })) === null || _q$input$options$find2 === void 0 ? void 0 : _q$input$options$find2.label) !== null && _q$input$options$find !== void 0 ? _q$input$options$find : ans.value;
240
+ }
241
+ return ans.value;
242
+ }
243
+ case 'options-multi':
244
+ {
245
+ if (q.input.kind !== 'options-multi') return ans.values.join('、');
246
+ var opts = q.input.options;
247
+ var labels = ans.values.filter(function (v) {
248
+ return v !== OTHER_VALUE;
249
+ }).map(function (v) {
250
+ var _opts$find$label, _opts$find;
251
+ return (_opts$find$label = (_opts$find = opts.find(function (o) {
252
+ return o.value === v;
253
+ })) === null || _opts$find === void 0 ? void 0 : _opts$find.label) !== null && _opts$find$label !== void 0 ? _opts$find$label : v;
254
+ });
255
+ if (ans.values.includes(OTHER_VALUE) && ans.otherText) {
256
+ labels.push(ans.otherText);
257
+ }
258
+ return labels.join('、');
259
+ }
260
+ case 'date':
261
+ case 'text':
262
+ return ans.value;
263
+ default:
264
+ return '(未答)';
265
+ }
266
+ };
267
+ var syncCurrentDraftIntoAnswers = function syncCurrentDraftIntoAnswers() {
268
+ return answers.map(function (a, i) {
269
+ if (i !== page || !a) return a;
270
+ if (a.kind === 'options' && a.value === OTHER_VALUE) {
271
+ return _objectSpread(_objectSpread({}, a), {}, {
272
+ otherText: otherDraft
273
+ });
274
+ }
275
+ if (a.kind === 'options-multi' && a.values.includes(OTHER_VALUE)) {
276
+ return _objectSpread(_objectSpread({}, a), {}, {
277
+ otherText: otherDraft
278
+ });
279
+ }
280
+ if (a.kind === 'date' && dateDraft) {
281
+ return {
282
+ kind: 'date',
283
+ value: toISODate(dateDraft)
284
+ };
285
+ }
286
+ return a;
287
+ });
288
+ };
289
+ var submit = function submit(finalAnswers) {
290
+ var data = {};
291
+ spec.questions.forEach(function (q, i) {
292
+ var _a$otherText;
293
+ var a = finalAnswers[i];
294
+ if (!a) return;
295
+ switch (a.kind) {
296
+ case 'options':
297
+ data[q.key] = a.value === OTHER_VALUE ? ((_a$otherText = a.otherText) !== null && _a$otherText !== void 0 ? _a$otherText : otherDraft).trim() : a.value;
298
+ break;
299
+ case 'options-multi':
300
+ {
301
+ var values = a.values.filter(function (v) {
302
+ return v !== OTHER_VALUE;
303
+ });
304
+ if (a.values.includes(OTHER_VALUE)) {
305
+ var _a$otherText2;
306
+ var t = ((_a$otherText2 = a.otherText) !== null && _a$otherText2 !== void 0 ? _a$otherText2 : otherDraft).trim();
307
+ if (t) values.push(t);
308
+ }
309
+ data[q.key] = values;
310
+ break;
311
+ }
312
+ case 'date':
313
+ case 'text':
314
+ data[q.key] = a.value;
315
+ break;
316
+ }
317
+ });
318
+ var items = spec.questions.map(function (q, i) {
319
+ return {
320
+ key: q.key,
321
+ label: q.label,
322
+ answer: formatAnswer(q, finalAnswers[i])
323
+ };
324
+ });
325
+ var text = items.map(function (it) {
326
+ return formatLockedLine(it.label, it.answer);
327
+ }).join(';');
328
+ onResolve({
329
+ text: text,
330
+ data: data,
331
+ items: items
332
+ });
333
+ };
334
+ var handleContinue = function handleContinue() {
335
+ if (!canAdvance) return;
336
+ var synced = syncCurrentDraftIntoAnswers();
337
+ setAnswers(synced);
338
+ if (isLastPage) submit(synced);else setPage(function (p) {
339
+ return Math.min(p + 1, total - 1);
340
+ });
341
+ };
342
+ var handlePrev = function handlePrev() {
343
+ if (isFirstPage) return;
344
+ var synced = syncCurrentDraftIntoAnswers();
345
+ setAnswers(synced);
346
+ setPage(function (p) {
347
+ return Math.max(0, p - 1);
348
+ });
349
+ };
350
+ return /*#__PURE__*/React.createElement("div", {
351
+ "data-odn-clarify-dock": true,
352
+ "data-odn-clarify-msg-id": msgId,
353
+ "aria-label": "\u6F84\u6E05\u95EE\u9898 ".concat(page + 1, " / ").concat(total)
354
+ }, /*#__PURE__*/React.createElement("div", {
355
+ "data-odn-clarify-dock-body": true
356
+ }, spec.title ? /*#__PURE__*/React.createElement("div", {
357
+ "data-odn-clarify-dock-heading": true
358
+ }, /*#__PURE__*/React.createElement("div", {
359
+ "data-odn-clarify-dock-title-row": true
360
+ }, /*#__PURE__*/React.createElement("p", {
361
+ "data-odn-clarify-dock-title": true
362
+ }, spec.title))) : null, /*#__PURE__*/React.createElement("div", {
363
+ "data-odn-clarify-dock-content": true
364
+ }, /*#__PURE__*/React.createElement("div", {
365
+ "data-odn-clarify-dock-q-row": true
366
+ }, /*#__PURE__*/React.createElement("div", {
367
+ "data-odn-clarify-dock-q": true
368
+ }, question.label), input.kind === 'options' ? /*#__PURE__*/React.createElement("span", {
369
+ "data-odn-clarify-dock-q-hint": true
370
+ }, "\u5355\u9009") : input.kind === 'options-multi' ? /*#__PURE__*/React.createElement("span", {
371
+ "data-odn-clarify-dock-q-hint": true
372
+ }, "\u53EF\u591A\u9009") : null), /*#__PURE__*/React.createElement(QuestionInput, {
373
+ input: input,
374
+ answer: answer,
375
+ otherDraft: otherDraft,
376
+ dateDraft: dateDraft,
377
+ onOtherDraftChange: function onOtherDraftChange(v) {
378
+ setOtherDraft(v);
379
+ if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options' && answer.value === OTHER_VALUE) {
380
+ setAnswerForPage({
381
+ kind: 'options',
382
+ value: OTHER_VALUE,
383
+ otherText: v
384
+ });
385
+ } else if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options-multi') {
386
+ setAnswerForPage({
387
+ kind: 'options-multi',
388
+ values: answer.values,
389
+ otherText: v
390
+ });
391
+ }
392
+ },
393
+ onDateChange: function onDateChange(d) {
394
+ setDateDraft(d);
395
+ setAnswerForPage(d ? {
396
+ kind: 'date',
397
+ value: toISODate(d)
398
+ } : undefined);
399
+ },
400
+ onPickSingle: function onPickSingle(opt) {
401
+ if (opt.value === OTHER_VALUE) {
402
+ setAnswerForPage({
403
+ kind: 'options',
404
+ value: OTHER_VALUE,
405
+ otherText: otherDraft
406
+ });
407
+ } else if (!((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options' && answer.value === opt.value)) {
408
+ setAnswerForPage({
409
+ kind: 'options',
410
+ value: opt.value
411
+ });
412
+ }
413
+ },
414
+ onToggleMulti: function onToggleMulti(opt) {
415
+ var prev = (answer === null || answer === void 0 ? void 0 : answer.kind) === 'options-multi' ? answer.values : [];
416
+ var has = prev.includes(opt.value);
417
+ var next = has ? prev.filter(function (v) {
418
+ return v !== opt.value;
419
+ }) : [].concat(_toConsumableArray(prev), [opt.value]);
420
+ setAnswerForPage({
421
+ kind: 'options-multi',
422
+ values: next,
423
+ otherText: otherDraft
424
+ });
425
+ }
426
+ }))), /*#__PURE__*/React.createElement("div", {
427
+ "data-odn-clarify-dock-actions": true
428
+ }, total > 1 ? /*#__PURE__*/React.createElement(Pagination, {
429
+ type: "simple",
430
+ value: page + 1,
431
+ totalSize: total,
432
+ pageSize: 1,
433
+ showPrevNext: false,
434
+ showFirstLast: false,
435
+ "data-odn-clarify-dock-page-indicator": true
436
+ }) : /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement("div", {
437
+ "data-odn-clarify-dock-actions-right": true
438
+ }, !isFirstPage ? /*#__PURE__*/React.createElement(Button, {
439
+ size: "small",
440
+ intent: "normal",
441
+ onClick: handlePrev
442
+ }, "\u4E0A\u4E00\u9898") : null, /*#__PURE__*/React.createElement(Button, {
443
+ intent: "primary",
444
+ size: "small",
445
+ onClick: handleContinue,
446
+ disabled: !canAdvance,
447
+ "data-odn-clarify-dock-continue": true
448
+ }, isLastPage ? '确认' : '下一题'))));
449
+ }
450
+
451
+ /* ================================================================== */
452
+ /* 单题输入区 */
453
+ /* ================================================================== */
454
+
455
+ /**
456
+ * 组装选项列表并强制 ≤ CLARIFY_DOCK_MAX_OPTIONS。
457
+ * allowOther 时末位固定为「其他」,业务选项占前 N-1 席。
458
+ */
459
+ function withOtherOption(options, allowOther) {
460
+ if (allowOther) {
461
+ var withoutDup = options.filter(function (o) {
462
+ return o.value !== OTHER_VALUE;
463
+ });
464
+ var capped = withoutDup.slice(0, CLARIFY_DOCK_MAX_OPTIONS - 1);
465
+ return [].concat(_toConsumableArray(capped), [{
466
+ value: OTHER_VALUE,
467
+ label: '其他'
468
+ }]);
469
+ }
470
+ return options.slice(0, CLARIFY_DOCK_MAX_OPTIONS);
471
+ }
472
+ function QuestionInput(_ref3) {
473
+ var input = _ref3.input,
474
+ answer = _ref3.answer,
475
+ otherDraft = _ref3.otherDraft,
476
+ dateDraft = _ref3.dateDraft,
477
+ onOtherDraftChange = _ref3.onOtherDraftChange,
478
+ onDateChange = _ref3.onDateChange,
479
+ onPickSingle = _ref3.onPickSingle,
480
+ onToggleMulti = _ref3.onToggleMulti;
481
+ if (input.kind === 'options' || input.kind === 'options-multi') {
482
+ return /*#__PURE__*/React.createElement(OptionsList, {
483
+ options: withOtherOption(input.options, input.allowOther),
484
+ multi: input.kind === 'options-multi',
485
+ answer: answer,
486
+ otherDraft: otherDraft,
487
+ otherPlaceholder: input.otherPlaceholder,
488
+ onOtherDraftChange: onOtherDraftChange,
489
+ onPickSingle: onPickSingle,
490
+ onToggleMulti: onToggleMulti
491
+ });
492
+ }
493
+ if (input.kind === 'date') {
494
+ return /*#__PURE__*/React.createElement("div", {
495
+ "data-odn-clarify-dock-input-row": true
496
+ }, /*#__PURE__*/React.createElement(DatePicker, {
497
+ value: dateDraft,
498
+ onChange: function onChange(d) {
499
+ return onDateChange(d);
500
+ }
501
+ }));
502
+ }
503
+ return /*#__PURE__*/React.createElement("div", {
504
+ "data-odn-clarify-dock-hint": true
505
+ }, "\u6682\u4E0D\u652F\u6301\u7684\u8F93\u5165\u7C7B\u578B\uFF1A", input.kind);
506
+ }
507
+
508
+ /* ------------------------------------------------------------------ */
509
+ /* OptionsList · A–E 徽标 + ↑↓ 框选(焦点隔离,不抢 Composer) */
510
+ /* ------------------------------------------------------------------ */
511
+
512
+ function OptionsList(_ref4) {
513
+ var options = _ref4.options,
514
+ multi = _ref4.multi,
515
+ answer = _ref4.answer,
516
+ otherDraft = _ref4.otherDraft,
517
+ otherPlaceholder = _ref4.otherPlaceholder,
518
+ onOtherDraftChange = _ref4.onOtherDraftChange,
519
+ onPickSingle = _ref4.onPickSingle,
520
+ onToggleMulti = _ref4.onToggleMulti;
521
+ var optionRefs = useRef([]);
522
+ var optionKey = options.map(function (o) {
523
+ return o.value;
524
+ }).join('|');
525
+
526
+ /* 切题时把焦点放到首项/已选项,便于立刻 ↑↓ */
527
+ useEffect(function () {
528
+ var selectedIdx = options.findIndex(function (o) {
529
+ if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options') return answer.value === o.value;
530
+ if ((answer === null || answer === void 0 ? void 0 : answer.kind) === 'options-multi') return answer.values.includes(o.value);
531
+ return false;
532
+ });
533
+ var focusIdx = selectedIdx >= 0 ? selectedIdx : 0;
534
+ var id = window.requestAnimationFrame(function () {
535
+ var _optionRefs$current$f;
536
+ (_optionRefs$current$f = optionRefs.current[focusIdx]) === null || _optionRefs$current$f === void 0 || _optionRefs$current$f.focus();
537
+ });
538
+ return function () {
539
+ return window.cancelAnimationFrame(id);
540
+ };
541
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- 只在选项集切换时重聚焦
542
+ }, [optionKey]);
543
+ var focusAt = function focusAt(idx) {
544
+ var _optionRefs$current$n;
545
+ var next = Math.max(0, Math.min(options.length - 1, idx));
546
+ (_optionRefs$current$n = optionRefs.current[next]) === null || _optionRefs$current$n === void 0 || _optionRefs$current$n.focus();
547
+ };
548
+ var handleOptionKeyDown = function handleOptionKeyDown(idx, opt) {
549
+ return function (e) {
550
+ if (e.key === 'ArrowDown') {
551
+ e.preventDefault();
552
+ e.stopPropagation();
553
+ var next = (idx + 1) % options.length;
554
+ focusAt(next);
555
+ if (!multi) onPickSingle(options[next]);
556
+ return;
557
+ }
558
+ if (e.key === 'ArrowUp') {
559
+ e.preventDefault();
560
+ e.stopPropagation();
561
+ var _next = (idx - 1 + options.length) % options.length;
562
+ focusAt(_next);
563
+ if (!multi) onPickSingle(options[_next]);
564
+ return;
565
+ }
566
+ if (e.key === 'Enter' || e.key === ' ') {
567
+ e.preventDefault();
568
+ e.stopPropagation();
569
+ if (multi) onToggleMulti(opt);else onPickSingle(opt);
570
+ }
571
+ };
572
+ };
573
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
574
+ "data-odn-clarify-dock-options": true,
575
+ "data-multi": multi || undefined,
576
+ role: multi ? 'group' : 'radiogroup',
577
+ "aria-label": "\u6F84\u6E05\u9009\u9879"
578
+ }, options.map(function (opt, idx) {
579
+ var _LETTER_BADGES$idx;
580
+ var active = (answer === null || answer === void 0 ? void 0 : answer.kind) === 'options' ? answer.value === opt.value : (answer === null || answer === void 0 ? void 0 : answer.kind) === 'options-multi' ? answer.values.includes(opt.value) : false;
581
+ var isOther = opt.value === OTHER_VALUE;
582
+ var letter = (_LETTER_BADGES$idx = LETTER_BADGES[idx]) !== null && _LETTER_BADGES$idx !== void 0 ? _LETTER_BADGES$idx : '';
583
+ if (isOther && active) {
584
+ var editingRow = /*#__PURE__*/React.createElement("div", {
585
+ "data-odn-clarify-dock-option": true,
586
+ "data-active": true,
587
+ "data-other": true,
588
+ "data-editing": true
589
+ }, multi ? /*#__PURE__*/React.createElement("span", {
590
+ role: "button",
591
+ tabIndex: 0,
592
+ "data-odn-clarify-dock-option-letter": true,
593
+ "data-odn-clarify-dock-option-toggle": true,
594
+ "aria-label": "\u53D6\u6D88\u9009\u62E9\u5176\u4ED6",
595
+ onClick: function onClick() {
596
+ return onToggleMulti(opt);
597
+ },
598
+ onKeyDown: function onKeyDown(e) {
599
+ if (e.key === 'Enter' || e.key === ' ') {
600
+ e.preventDefault();
601
+ onToggleMulti(opt);
602
+ }
603
+ }
604
+ }, letter) : /*#__PURE__*/React.createElement("span", {
605
+ "data-odn-clarify-dock-option-letter": true,
606
+ "aria-hidden": true
607
+ }, letter), /*#__PURE__*/React.createElement(Input, {
608
+ value: otherDraft,
609
+ onChange: function onChange(_, value) {
610
+ return onOtherDraftChange(value);
611
+ },
612
+ onKeyDown: function onKeyDown(e) {
613
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
614
+ e.preventDefault();
615
+ var otherIdx = options.findIndex(function (o) {
616
+ return o.value === OTHER_VALUE;
617
+ });
618
+ var next = e.key === 'ArrowDown' ? (otherIdx + 1) % options.length : (otherIdx - 1 + options.length) % options.length;
619
+ if (!multi) {
620
+ onPickSingle(options[next]);
621
+ }
622
+ requestAnimationFrame(function () {
623
+ return focusAt(next);
624
+ });
625
+ }
626
+ if (multi && e.key === 'Escape') {
627
+ e.preventDefault();
628
+ onToggleMulti(opt);
629
+ }
630
+ },
631
+ placeholder: otherPlaceholder !== null && otherPlaceholder !== void 0 ? otherPlaceholder : '请描述你的情况…',
632
+ size: "small",
633
+ light: true,
634
+ autoFocus: true
635
+ }));
636
+ if (multi) {
637
+ return /*#__PURE__*/React.createElement(HoverFill, {
638
+ key: opt.value,
639
+ hoverColor: MULTI_SELECTED_HOVER_FILL,
640
+ activeColor: MULTI_SELECTED_HOVER_FILL,
641
+ "data-odn-clarify-dock-option-fill": true
642
+ }, editingRow);
643
+ }
644
+ return /*#__PURE__*/React.createElement(React.Fragment, {
645
+ key: opt.value
646
+ }, editingRow);
647
+ }
648
+ var optionContent = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
649
+ "data-odn-clarify-dock-option-letter": true,
650
+ "aria-hidden": true
651
+ }, letter), /*#__PURE__*/React.createElement("span", {
652
+ "data-odn-clarify-dock-option-label": true
653
+ }, opt.label));
654
+
655
+ /* 不用 data-odn-button:避免 Button small 固定 height 把通栏选项撑坏 */
656
+ if (active && !multi) {
657
+ return /*#__PURE__*/React.createElement("button", {
658
+ key: opt.value,
659
+ type: "button",
660
+ ref: function ref(el) {
661
+ optionRefs.current[idx] = el;
662
+ },
663
+ role: "radio",
664
+ "aria-checked": true,
665
+ tabIndex: idx === 0 ? 0 : -1,
666
+ onClick: function onClick() {
667
+ return onPickSingle(opt);
668
+ },
669
+ onKeyDown: handleOptionKeyDown(idx, opt),
670
+ "data-odn-clarify-dock-option": true,
671
+ "data-active": true,
672
+ "data-other": isOther || undefined
673
+ }, optionContent);
674
+ }
675
+ return /*#__PURE__*/React.createElement(HoverFill, {
676
+ key: opt.value,
677
+ hoverColor: multi ? active ? MULTI_SELECTED_HOVER_FILL : MULTI_UNSELECTED_HOVER_FILL : MULTI_UNSELECTED_HOVER_FILL,
678
+ activeColor: multi ? active ? MULTI_SELECTED_HOVER_FILL : MULTI_UNSELECTED_ACTIVE_FILL : MULTI_UNSELECTED_ACTIVE_FILL,
679
+ "data-odn-clarify-dock-option-fill": true
680
+ }, /*#__PURE__*/React.createElement("button", {
681
+ type: "button",
682
+ ref: function ref(el) {
683
+ optionRefs.current[idx] = el;
684
+ },
685
+ role: multi ? 'checkbox' : 'radio',
686
+ "aria-checked": active,
687
+ tabIndex: idx === 0 ? 0 : -1,
688
+ onClick: function onClick() {
689
+ return multi ? onToggleMulti(opt) : onPickSingle(opt);
690
+ },
691
+ onKeyDown: handleOptionKeyDown(idx, opt),
692
+ "data-odn-clarify-dock-option": true,
693
+ "data-active": active || undefined,
694
+ "data-other": isOther || undefined
695
+ }, optionContent));
696
+ })));
697
+ }
698
+
699
+ /* ================================================================== */
700
+ /* Hook · 派生 dock 状态 */
701
+ /* ================================================================== */
702
+
703
+ /**
704
+ * 收 ClarifyDock 的派生态:
705
+ * - thread 最后一条 assistant 带 clarify-dock 且未答 → pending
706
+ * - recordAnswer 后 Panel 消失,Trigger 切 Approval 式锁态卡
707
+ */
708
+ export function useClarifyDockState(messages, sessionKey, resetVer) {
709
+ var _useState13 = useState({}),
710
+ _useState14 = _slicedToArray(_useState13, 2),
711
+ answers = _useState14[0],
712
+ setAnswers = _useState14[1];
713
+
714
+ /* 切换会话或点「重置」时清空已答标记,避免 Panel / Trigger 状态脱节 */
715
+ useEffect(function () {
716
+ setAnswers({});
717
+ }, [sessionKey, resetVer]);
718
+ var latest = useMemo(function () {
719
+ var _last$instance;
720
+ if (messages.length === 0) return null;
721
+ var last = messages[messages.length - 1];
722
+ if (last.role !== 'assistant') return null;
723
+ if (((_last$instance = last.instance) === null || _last$instance === void 0 ? void 0 : _last$instance.type) !== 'clarify-dock') return null;
724
+ return {
725
+ msgId: last.id,
726
+ spec: last.instance.spec
727
+ };
728
+ }, [messages]);
729
+ var pending = latest && !(latest.msgId in answers) ? latest : null;
730
+ var getMessageState = useCallback(function (msgId) {
731
+ return {
732
+ items: answers[msgId]
733
+ };
734
+ }, [answers]);
735
+ var recordAnswer = useCallback(function (msgId, items) {
736
+ setAnswers(function (m) {
737
+ return _objectSpread(_objectSpread({}, m), {}, _defineProperty({}, msgId, items));
738
+ });
739
+ }, []);
740
+ return {
741
+ pending: pending,
742
+ getMessageState: getMessageState,
743
+ recordAnswer: recordAnswer
744
+ };
745
+ }
746
+ ClarifyDockTrigger.displayName = 'ClarifyDockTrigger';
747
+ ClarifyDockPanel.displayName = 'ClarifyDockPanel';