one-design-next 0.0.46 → 0.0.47

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.
@@ -1,71 +1,40 @@
1
1
  import * as React from 'react';
2
2
  import './style';
3
3
  export type ApprovalDecision = 'approve' | 'reject';
4
- /** 参数来源:已获取 / AI 推测 / 待用户填 */
5
- export type ApprovalFieldSource = 'fetched' | 'inferred' | 'user';
6
- export type ApprovalFieldControl = 'text' | 'number' | 'textarea' | 'select' | 'radio' | 'multi-select' | 'date' | 'date-range' | 'switch' | 'custom'
7
- /** 复合对象:嵌套分组,自身无值 */
8
- | 'group'
9
- /** 复合列表:按 itemFields 重复;values 用扁平点路径 `listKey.i.relKey` */
10
- | 'list';
11
- export interface ApprovalFieldOption {
12
- value: string;
13
- label: string;
14
- }
15
- export interface ApprovalField {
16
- key: string;
4
+ /** 参数摘要一行:Host 已格式化的 label 展示文案(可含换行) */
5
+ export interface ApprovalSummaryItem {
17
6
  label: string;
18
- control: ApprovalFieldControl;
19
- source: ApprovalFieldSource;
20
- required?: boolean;
21
- readOnly?: boolean;
22
- options?: ApprovalFieldOption[];
23
- placeholder?: string;
24
- /** control='group':子节点(完整 key,如 tag_insight_content.audience_id) */
25
- children?: ApprovalField[];
26
- /** control='list':单项字段 schema(相对 key,如 tag_id) */
27
- itemFields?: ApprovalField[];
28
- /** control='list':最少行数,默认 1 */
29
- minItems?: number;
30
- /** control='list':最多行数 */
31
- maxItems?: number;
32
- /** control='custom' 时由消费方渲染 */
33
- render?: (ctx: {
34
- value: unknown;
35
- onChange: (next: unknown) => void;
36
- readOnly: boolean;
37
- }) => React.ReactNode;
7
+ value: string;
38
8
  }
39
9
  export interface ApprovalSpec {
40
- /** 待授权动作说明 */
10
+ /** 待授权动作说明(标题);14px / regular / black-12;原样展示,Host 自行决定是否带问号 */
41
11
  description: string;
42
- /** 写操作工具 / 任务短名;有 fields 时显示在标题下辅助描述中 */
12
+ /** 写操作工具名;可选元数据,UI 不渲染 */
43
13
  title?: string;
44
14
  actionLabel: string;
45
15
  rejectLabel?: string;
46
16
  destructive?: boolean;
17
+ /** 同意锁态文案;省略时由 description「确认…」推导为「已确认…」 */
47
18
  resolvedLabel?: string;
19
+ /** 拒绝锁态文案;省略时由 description「确认创建…」推导为「暂不创建…」 */
48
20
  rejectedLabel?: string;
49
21
  /**
50
- * 当前步可见的参数树。分支 / 条件显隐由 Host 算好再传入;
51
- * 组件不内置业务路由引擎。
22
+ * 参数摘要。Clarify 收齐后由 **Host 格式化**再传入;
23
+ * 组件不解析原始 tool args。省略或空数组 = 轻量 yes/no。
24
+ * 未决:默认展开;锁态:默认折叠,右侧可展开回看。
52
25
  */
53
- fields?: ApprovalField[];
26
+ summary?: ApprovalSummaryItem[];
54
27
  }
55
28
  export interface ApprovalResolvePayload {
56
29
  decision: ApprovalDecision;
57
- values?: Record<string, unknown>;
58
30
  }
59
31
  export interface ApprovalProps {
60
32
  spec: ApprovalSpec;
61
- values?: Record<string, unknown>;
62
- defaultValues?: Record<string, unknown>;
63
- onValuesChange?: (values: Record<string, unknown>) => void;
64
33
  resolved?: ApprovalDecision | null;
65
34
  onResolve?: (payload: ApprovalResolvePayload) => void;
66
35
  className?: string;
67
36
  }
68
- export declare function Approval({ spec, values: valuesProp, defaultValues, onValuesChange, resolved: resolvedProp, onResolve, className, }: ApprovalProps): React.JSX.Element;
37
+ export declare function Approval({ spec, resolved: resolvedProp, onResolve, className, }: ApprovalProps): React.JSX.Element;
69
38
  export declare namespace Approval {
70
39
  var displayName: string;
71
40
  }
@@ -1,592 +1,207 @@
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 _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
- 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."); }
4
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
6
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7
1
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
2
  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."); }
9
3
  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); }
10
4
  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; }
11
5
  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; } }
12
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
13
- 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; }
14
- 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; }
15
- 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; }
16
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
17
- 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); }
18
7
  import * as React from 'react';
19
8
  import clsx from 'clsx';
20
9
  import Button from "../button";
21
- import DatePicker from "../date-picker";
22
- import DateRangePicker from "../date-range-picker";
23
10
  import Icon from "../icon";
24
- import Input from "../input";
25
- import InputNumber from "../input-number";
26
- import Select from "../select";
27
- import Switch from "../switch";
28
- import Radio from "../radio";
29
11
  import "./style";
30
12
 
31
13
  /* ------------------------------------------------------------------ */
32
14
  /* Types */
33
15
  /* ------------------------------------------------------------------ */
34
16
 
35
- /** 参数来源:已获取 / AI 推测 / 待用户填 */
17
+ /** 参数摘要一行:Host 已格式化的 label 展示文案(可含换行) */
36
18
 
37
- /* ------------------------------------------------------------------ */
38
- /* Helpers */
39
- /* ------------------------------------------------------------------ */
40
-
41
- var SOURCE_LABEL = {
42
- fetched: '已获取',
43
- inferred: 'AI 推测',
44
- user: '待填写'
45
- };
46
- function isEmptyValue(value) {
47
- if (value === undefined || value === null) return true;
48
- if (typeof value === 'string') return value.trim() === '';
49
- if (Array.isArray(value)) return value.length === 0;
50
- return false;
51
- }
52
- function isContainer(field) {
53
- return field.control === 'group' || field.control === 'list';
54
- }
55
-
56
- /** 保持 Host 声明序(先名称后类型等由 Host 控制,组件不按来源重排) */
57
- function normalizeNodes(fields) {
58
- return fields.map(function (f) {
59
- if (f.control === 'group' && f.children) {
60
- return _objectSpread(_objectSpread({}, f), {}, {
61
- children: normalizeNodes(f.children)
62
- });
63
- }
64
- return f;
65
- });
66
- }
67
- function getListLength(values, listKey, minItems) {
68
- var prefix = "".concat(listKey, ".");
69
- var maxIdx = -1;
70
- for (var _i = 0, _Object$keys = Object.keys(values); _i < _Object$keys.length; _i++) {
71
- var k = _Object$keys[_i];
72
- if (!k.startsWith(prefix)) continue;
73
- var head = k.slice(prefix.length).split('.')[0];
74
- var idx = Number(head);
75
- if (Number.isInteger(idx) && idx >= 0) maxIdx = Math.max(maxIdx, idx);
19
+ function lockedTitle(description, decision, explicit) {
20
+ if (explicit) return explicit;
21
+ var base = description.trim().replace(/[\?\uFF1F]+$/, '');
22
+ if (decision === 'approve') {
23
+ return base.startsWith('确认') ? "\u5DF2".concat(base) : base;
76
24
  }
77
- return Math.max(maxIdx + 1, minItems);
78
- }
79
-
80
- /** 删除 index 行后,将更高下标键前移 */
81
- function removeListItem(values, listKey, index) {
82
- var prefix = "".concat(listKey, ".");
83
- var next = {};
84
- for (var _i2 = 0, _Object$entries = Object.entries(values); _i2 < _Object$entries.length; _i2++) {
85
- var _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2),
86
- k = _Object$entries$_i[0],
87
- v = _Object$entries$_i[1];
88
- if (!k.startsWith(prefix)) {
89
- next[k] = v;
90
- continue;
91
- }
92
- var rest = k.slice(prefix.length);
93
- var dot = rest.indexOf('.');
94
- if (dot < 0) continue;
95
- var idx = Number(rest.slice(0, dot));
96
- var rel = rest.slice(dot + 1);
97
- if (!Number.isInteger(idx) || idx < 0) {
98
- next[k] = v;
99
- continue;
100
- }
101
- if (idx === index) continue;
102
- if (idx > index) {
103
- next["".concat(listKey, ".").concat(idx - 1, ".").concat(rel)] = v;
104
- } else {
105
- next[k] = v;
106
- }
25
+ if (base.startsWith('确认创建')) {
26
+ return "\u6682\u4E0D\u521B\u5EFA".concat(base.slice('确认创建'.length));
107
27
  }
108
- return next;
109
- }
110
- function collectLeafSlots(fields, values) {
111
- var out = [];
112
- var _iterator = _createForOfIteratorHelper(fields),
113
- _step;
114
- try {
115
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
116
- var f = _step.value;
117
- if (f.control === 'group' && f.children) {
118
- out.push.apply(out, _toConsumableArray(collectLeafSlots(f.children, values)));
119
- continue;
120
- }
121
- if (f.control === 'list' && f.itemFields) {
122
- var _f$minItems;
123
- var min = (_f$minItems = f.minItems) !== null && _f$minItems !== void 0 ? _f$minItems : 1;
124
- var len = getListLength(values, f.key, min);
125
- for (var i = 0; i < len; i += 1) {
126
- var _iterator2 = _createForOfIteratorHelper(f.itemFields),
127
- _step2;
128
- try {
129
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
130
- var item = _step2.value;
131
- out.push({
132
- field: item,
133
- key: "".concat(f.key, ".").concat(i, ".").concat(item.key)
134
- });
135
- }
136
- } catch (err) {
137
- _iterator2.e(err);
138
- } finally {
139
- _iterator2.f();
140
- }
141
- }
142
- continue;
143
- }
144
- if (!isContainer(f)) {
145
- out.push({
146
- field: f,
147
- key: f.key
148
- });
149
- }
150
- }
151
- } catch (err) {
152
- _iterator.e(err);
153
- } finally {
154
- _iterator.f();
28
+ if (base.startsWith('确认')) {
29
+ return "\u6682\u4E0D".concat(base.slice('确认'.length));
155
30
  }
156
- return out;
31
+ return base;
157
32
  }
158
33
 
159
- /** radio 未选时默认第一项,写入 values 供校验与提交 */
160
- function applyRadioDefaults(fields, values) {
161
- var next = _objectSpread({}, values);
162
- var changed = false;
163
- var _iterator3 = _createForOfIteratorHelper(collectLeafSlots(fields, values)),
164
- _step3;
165
- try {
166
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
167
- var _slot$field$options;
168
- var slot = _step3.value;
169
- if (slot.field.control !== 'radio') continue;
170
- if (!isEmptyValue(next[slot.key])) continue;
171
- var first = (_slot$field$options = slot.field.options) === null || _slot$field$options === void 0 || (_slot$field$options = _slot$field$options[0]) === null || _slot$field$options === void 0 ? void 0 : _slot$field$options.value;
172
- if (first == null) continue;
173
- next[slot.key] = first;
174
- changed = true;
175
- }
176
- } catch (err) {
177
- _iterator3.e(err);
178
- } finally {
179
- _iterator3.f();
180
- }
181
- return changed ? next : values;
182
- }
183
- function parseDate(value) {
184
- if (value instanceof Date && !Number.isNaN(value.getTime())) return value;
185
- if (typeof value !== 'string' || !value.trim()) return null;
186
- var d = new Date(value);
187
- return Number.isNaN(d.getTime()) ? null : d;
188
- }
189
- function parseDateRange(value) {
190
- if (Array.isArray(value) && value.length === 2) {
191
- var _a = parseDate(value[0]);
192
- var _b = parseDate(value[1]);
193
- if (_a && _b) return [_a, _b];
194
- }
195
- if (typeof value !== 'string' || !value.includes(',')) return null;
196
- var _value$split$map = value.split(',').map(function (x) {
197
- return x.trim();
198
- }),
199
- _value$split$map2 = _slicedToArray(_value$split$map, 2),
200
- s = _value$split$map2[0],
201
- e = _value$split$map2[1];
202
- var a = parseDate(s);
203
- var b = parseDate(e);
204
- if (a && b) return [a, b];
205
- return null;
206
- }
207
-
208
- /* ------------------------------------------------------------------ */
209
- /* Leaf control */
210
- /* ------------------------------------------------------------------ */
211
-
212
- function FieldControl(_ref) {
213
- var _field$placeholder, _field$options, _field$options2, _field$placeholder2;
214
- var field = _ref.field,
215
- value = _ref.value,
216
- _onChange = _ref.onChange,
217
- disabled = _ref.disabled,
218
- controlId = _ref.controlId;
219
- var readOnly = disabled || !!field.readOnly;
220
- if (field.control === 'custom' && field.render) {
221
- return field.render({
222
- value: value,
223
- onChange: _onChange,
224
- readOnly: readOnly
225
- });
226
- }
227
- switch (field.control) {
228
- case 'text':
229
- return /*#__PURE__*/React.createElement(Input, {
230
- id: controlId,
231
- size: "small",
232
- value: typeof value === 'string' ? value : value == null ? '' : String(value),
233
- placeholder: field.placeholder,
234
- disabled: readOnly,
235
- onChange: function onChange(_e, v) {
236
- return _onChange(v);
237
- }
238
- });
239
- case 'number':
240
- return /*#__PURE__*/React.createElement(InputNumber, {
241
- id: controlId,
242
- size: "small",
243
- value: typeof value === 'number' ? value : value == null || value === '' ? null : Number(value),
244
- placeholder: field.placeholder,
245
- disabled: readOnly,
246
- onChange: function onChange(v) {
247
- return _onChange(v);
248
- }
249
- });
250
- case 'textarea':
251
- return /*#__PURE__*/React.createElement(Input.Textarea, {
252
- id: controlId,
253
- size: "small",
254
- value: typeof value === 'string' ? value : value == null ? '' : String(value),
255
- placeholder: field.placeholder,
256
- disabled: readOnly,
257
- autoSize: {
258
- minRows: 2,
259
- maxRows: 6
260
- },
261
- onChange: function onChange(_e, v) {
262
- return _onChange(v);
263
- }
264
- });
265
- case 'select':
266
- return /*#__PURE__*/React.createElement(Select, {
267
- size: "small",
268
- value: value == null || value === '' ? undefined : value,
269
- placeholder: (_field$placeholder = field.placeholder) !== null && _field$placeholder !== void 0 ? _field$placeholder : '请选择',
270
- disabled: readOnly,
271
- options: field.options,
272
- onChange: function onChange(v) {
273
- return _onChange(v);
274
- },
275
- style: {
276
- width: '100%'
277
- }
278
- });
279
- case 'radio':
280
- return /*#__PURE__*/React.createElement(Radio.Group, {
281
- size: "small",
282
- value: value == null || value === '' ? (_field$options = field.options) !== null && _field$options !== void 0 && _field$options[0] ? String(field.options[0].value) : undefined : String(value),
283
- options: (_field$options2 = field.options) === null || _field$options2 === void 0 ? void 0 : _field$options2.map(function (o) {
284
- return {
285
- value: String(o.value),
286
- label: o.label,
287
- disabled: readOnly
288
- };
289
- }),
290
- onChange: function onChange(v) {
291
- return _onChange(v);
292
- }
293
- });
294
- case 'multi-select':
295
- return /*#__PURE__*/React.createElement(Select, {
296
- mode: "multiple",
297
- size: "small",
298
- value: Array.isArray(value) ? value : [],
299
- placeholder: (_field$placeholder2 = field.placeholder) !== null && _field$placeholder2 !== void 0 ? _field$placeholder2 : '请选择',
300
- disabled: readOnly,
301
- options: field.options,
302
- onChange: function onChange(v) {
303
- return _onChange(v);
304
- },
305
- style: {
306
- width: '100%'
307
- }
34
+ /** 单列小票:标签列宽 = 全部标签中最长者 */
35
+ function ApprovalReceipt(_ref) {
36
+ var summary = _ref.summary;
37
+ var rootRef = React.useRef(null);
38
+ React.useLayoutEffect(function () {
39
+ var root = rootRef.current;
40
+ if (!root) return;
41
+ var measure = function measure() {
42
+ var labels = root.querySelectorAll('[data-odn-approval-receipt-label]');
43
+ var max = 0;
44
+ labels.forEach(function (el) {
45
+ el.style.width = 'auto';
46
+ max = Math.max(max, el.getBoundingClientRect().width);
308
47
  });
309
- case 'date':
310
- return /*#__PURE__*/React.createElement(DatePicker, {
311
- value: parseDate(value),
312
- disabled: readOnly,
313
- onChange: function onChange(_date, info) {
314
- return _onChange(info.dateString || '');
315
- }
316
- });
317
- case 'date-range':
318
- return /*#__PURE__*/React.createElement(DateRangePicker, {
319
- value: parseDateRange(value),
320
- disabled: readOnly,
321
- onChange: function onChange(_dates, info) {
322
- return _onChange(info.dateString || '');
323
- }
324
- });
325
- case 'switch':
326
- return /*#__PURE__*/React.createElement(Switch, {
327
- size: "small",
328
- checked: !!value,
329
- disabled: readOnly,
330
- onChange: function onChange(checked) {
331
- return _onChange(checked);
332
- }
333
- });
334
- default:
335
- return null;
336
- }
337
- }
338
- function FieldRow(_ref2) {
339
- var field = _ref2.field,
340
- absKey = _ref2.absKey,
341
- value = _ref2.value,
342
- onChange = _ref2.onChange,
343
- locked = _ref2.locked;
344
- var controlId = "odn-approval-field-".concat(absKey.replace(/\./g, '-'));
345
- return /*#__PURE__*/React.createElement("div", {
346
- "data-odn-approval-field": true,
347
- "data-source": field.source,
348
- "data-control": field.control,
349
- "data-required": field.required || undefined
350
- }, /*#__PURE__*/React.createElement("div", {
351
- "data-odn-approval-field-meta": true
352
- }, /*#__PURE__*/React.createElement("label", {
353
- htmlFor: controlId,
354
- "data-odn-approval-field-label": true
355
- }, field.label), /*#__PURE__*/React.createElement("span", {
356
- "data-odn-approval-field-source": true
357
- }, SOURCE_LABEL[field.source]), !field.required ? /*#__PURE__*/React.createElement("span", {
358
- "data-odn-approval-field-optional": true
359
- }, "\u9009\u586B") : null), /*#__PURE__*/React.createElement("div", {
360
- "data-odn-approval-field-control": true
361
- }, /*#__PURE__*/React.createElement(FieldControl, {
362
- field: field,
363
- value: value,
364
- onChange: onChange,
365
- disabled: locked,
366
- controlId: controlId
367
- })));
368
- }
369
-
370
- /* ------------------------------------------------------------------ */
371
- /* Tree nodes */
372
- /* ------------------------------------------------------------------ */
373
-
374
- function FieldNode(_ref3) {
375
- var field = _ref3.field,
376
- values = _ref3.values,
377
- onPatch = _ref3.onPatch,
378
- locked = _ref3.locked,
379
- depth = _ref3.depth;
380
- if (field.control === 'group') {
381
- var _field$children;
382
- var children = normalizeNodes((_field$children = field.children) !== null && _field$children !== void 0 ? _field$children : []);
383
- var leafSlots = collectLeafSlots([field], values);
384
- var pending = leafSlots.filter(function (s) {
385
- return s.field.source === 'user';
386
- }).length;
387
- return /*#__PURE__*/React.createElement("div", {
388
- "data-odn-approval-group": true,
389
- "data-source": field.source,
390
- "data-depth": depth
391
- }, /*#__PURE__*/React.createElement("div", {
392
- "data-odn-approval-group-header": true
393
- }, /*#__PURE__*/React.createElement("span", {
394
- "data-odn-approval-group-title": true
395
- }, field.label), /*#__PURE__*/React.createElement("span", {
396
- "data-odn-approval-field-source": true
397
- }, SOURCE_LABEL[field.source]), pending > 0 ? /*#__PURE__*/React.createElement("span", {
398
- "data-odn-approval-group-hint": true
399
- }, "\u5F85\u586B ", pending, " \u9879") : /*#__PURE__*/React.createElement("span", {
400
- "data-odn-approval-group-hint": true
401
- }, "\u5DF2\u9F50")), /*#__PURE__*/React.createElement("div", {
402
- "data-odn-approval-group-body": true
403
- }, children.map(function (child) {
404
- return /*#__PURE__*/React.createElement(FieldNode, {
405
- key: child.key,
406
- field: child,
407
- values: values,
408
- onPatch: onPatch,
409
- locked: locked,
410
- depth: depth + 1
411
- });
412
- })));
413
- }
414
- if (field.control === 'list') {
415
- var _field$itemFields, _field$minItems;
416
- var itemFields = (_field$itemFields = field.itemFields) !== null && _field$itemFields !== void 0 ? _field$itemFields : [];
417
- var minItems = (_field$minItems = field.minItems) !== null && _field$minItems !== void 0 ? _field$minItems : 1;
418
- var maxItems = field.maxItems;
419
- var length = getListLength(values, field.key, minItems);
420
- var addItem = function addItem() {
421
- if (locked) return;
422
- if (maxItems != null && length >= maxItems) return;
423
- // 仅靠 length+1:写入占位空串触发长度增长
424
- var first = itemFields[0];
425
- if (!first) return;
426
- onPatch(_objectSpread(_objectSpread({}, values), {}, _defineProperty({}, "".concat(field.key, ".").concat(length, ".").concat(first.key), '')));
48
+ if (max > 0) {
49
+ root.style.setProperty('--odn-approval-label-width', "".concat(Math.ceil(max), "px"));
50
+ }
427
51
  };
428
- var removeItem = function removeItem(index) {
429
- if (locked) return;
430
- if (length <= minItems) return;
431
- onPatch(removeListItem(values, field.key, index));
52
+ measure();
53
+ var ro = new ResizeObserver(measure);
54
+ ro.observe(root);
55
+ return function () {
56
+ return ro.disconnect();
432
57
  };
58
+ }, [summary]);
59
+ return /*#__PURE__*/React.createElement("dl", {
60
+ "data-odn-approval-receipt": true,
61
+ ref: rootRef
62
+ }, summary.map(function (item, index) {
433
63
  return /*#__PURE__*/React.createElement("div", {
434
- "data-odn-approval-list": true,
435
- "data-source": field.source,
436
- "data-depth": depth
437
- }, /*#__PURE__*/React.createElement("div", {
438
- "data-odn-approval-list-header": true
439
- }, /*#__PURE__*/React.createElement("span", {
440
- "data-odn-approval-group-title": true
441
- }, field.label), /*#__PURE__*/React.createElement("span", {
442
- "data-odn-approval-field-source": true
443
- }, SOURCE_LABEL[field.source]), /*#__PURE__*/React.createElement("span", {
444
- "data-odn-approval-group-hint": true
445
- }, length, " \u9879"), !locked ? /*#__PURE__*/React.createElement(Button, {
446
- size: "small",
447
- intent: "normal",
448
- disabled: maxItems != null && length >= maxItems,
449
- onClick: addItem
450
- }, "\u6DFB\u52A0") : null), /*#__PURE__*/React.createElement("div", {
451
- "data-odn-approval-list-body": true
452
- }, Array.from({
453
- length: length
454
- }, function (_, index) {
455
- return /*#__PURE__*/React.createElement("div", {
456
- key: "".concat(field.key, ".").concat(index),
457
- "data-odn-approval-list-item": true
458
- }, /*#__PURE__*/React.createElement("div", {
459
- "data-odn-approval-list-item-meta": true
460
- }, /*#__PURE__*/React.createElement("span", {
461
- "data-odn-approval-list-item-index": true
462
- }, "#", index + 1), !locked && length > minItems ? /*#__PURE__*/React.createElement(Button, {
463
- size: "small",
464
- intent: "normal",
465
- onClick: function onClick() {
466
- return removeItem(index);
467
- }
468
- }, "\u5220\u9664") : null), /*#__PURE__*/React.createElement("div", {
469
- "data-odn-approval-list-item-fields": true
470
- }, itemFields.map(function (item) {
471
- var absKey = "".concat(field.key, ".").concat(index, ".").concat(item.key);
472
- return /*#__PURE__*/React.createElement(FieldRow, {
473
- key: absKey,
474
- field: item,
475
- absKey: absKey,
476
- value: values[absKey],
477
- onChange: function onChange(next) {
478
- return onPatch(_objectSpread(_objectSpread({}, values), {}, _defineProperty({}, absKey, next)));
479
- },
480
- locked: locked
481
- });
482
- })));
483
- })));
484
- }
485
- return /*#__PURE__*/React.createElement(FieldRow, {
486
- field: field,
487
- absKey: field.key,
488
- value: values[field.key],
489
- onChange: function onChange(next) {
490
- return onPatch(_objectSpread(_objectSpread({}, values), {}, _defineProperty({}, field.key, next)));
491
- },
492
- locked: locked
493
- });
64
+ key: "".concat(item.label, "-").concat(index),
65
+ "data-odn-approval-receipt-row": true
66
+ }, /*#__PURE__*/React.createElement("dt", {
67
+ "data-odn-approval-receipt-label": true
68
+ }, item.label), /*#__PURE__*/React.createElement("dd", {
69
+ "data-odn-approval-receipt-value": true,
70
+ "data-multiline": item.value.includes('\n') ? '' : undefined
71
+ }, item.value));
72
+ }));
494
73
  }
495
74
 
496
75
  /* ------------------------------------------------------------------ */
497
76
  /* Approval */
498
77
  /* ------------------------------------------------------------------ */
499
78
 
500
- export function Approval(_ref4) {
501
- var _spec$resolvedLabel, _spec$rejectedLabel;
502
- var spec = _ref4.spec,
503
- valuesProp = _ref4.values,
504
- defaultValues = _ref4.defaultValues,
505
- onValuesChange = _ref4.onValuesChange,
506
- resolvedProp = _ref4.resolved,
507
- onResolve = _ref4.onResolve,
508
- className = _ref4.className;
79
+ export function Approval(_ref2) {
80
+ var _spec$summary;
81
+ var spec = _ref2.spec,
82
+ resolvedProp = _ref2.resolved,
83
+ onResolve = _ref2.onResolve,
84
+ className = _ref2.className;
509
85
  var _React$useState = React.useState(null),
510
86
  _React$useState2 = _slicedToArray(_React$useState, 2),
511
87
  internalResolved = _React$useState2[0],
512
88
  setInternalResolved = _React$useState2[1];
513
- var _React$useState3 = React.useState(defaultValues !== null && defaultValues !== void 0 ? defaultValues : {}),
514
- _React$useState4 = _slicedToArray(_React$useState3, 2),
515
- internalValues = _React$useState4[0],
516
- setInternalValues = _React$useState4[1];
89
+ var resolveLockRef = React.useRef(false);
517
90
  var isResolvedControlled = resolvedProp !== undefined;
518
- var isValuesControlled = valuesProp !== undefined;
519
91
  var resolved = isResolvedControlled ? resolvedProp : internalResolved;
520
- var values = isValuesControlled ? valuesProp : internalValues;
521
92
  var locked = !!resolved;
522
- var fields = React.useMemo(function () {
523
- var _spec$fields;
524
- return normalizeNodes((_spec$fields = spec.fields) !== null && _spec$fields !== void 0 ? _spec$fields : []);
525
- }, [spec.fields]);
526
- var patchValues = function patchValues(next) {
527
- if (!isValuesControlled) setInternalValues(next);
528
- onValuesChange === null || onValuesChange === void 0 || onValuesChange(next);
529
- };
530
- var valuesWithDefaults = React.useMemo(function () {
531
- return applyRadioDefaults(fields, values);
532
- }, [fields, values]);
533
- var leafSlots = React.useMemo(function () {
534
- return collectLeafSlots(fields, valuesWithDefaults);
535
- }, [fields, valuesWithDefaults]);
536
- var canApprove = leafSlots.every(function (slot) {
537
- if (!slot.field.required) return true;
538
- return !isEmptyValue(valuesWithDefaults[slot.key]);
539
- });
93
+ var summary = (_spec$summary = spec.summary) !== null && _spec$summary !== void 0 ? _spec$summary : [];
94
+ var hasSummary = summary.length > 0;
95
+
96
+ /* 未决默认展开;锁态 / 挂载即已决议 → 默认折叠 */
97
+ var _React$useState3 = React.useState(function () {
98
+ return !locked && hasSummary;
99
+ }),
100
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
101
+ summaryExpanded = _React$useState4[0],
102
+ setSummaryExpanded = _React$useState4[1];
103
+ /* 收合动画结束后再卸掉 panel 占位,避免残高顶偏锁态文字;动画中保留 8px 间距 */
104
+ var _React$useState5 = React.useState(function () {
105
+ return !(!locked && hasSummary);
106
+ }),
107
+ _React$useState6 = _slicedToArray(_React$useState5, 2),
108
+ summaryCollapsedSettled = _React$useState6[0],
109
+ setSummaryCollapsedSettled = _React$useState6[1];
110
+ var wasLockedRef = React.useRef(locked);
111
+ React.useEffect(function () {
112
+ if (resolvedProp === null || resolvedProp === undefined) {
113
+ resolveLockRef.current = false;
114
+ }
115
+ }, [resolvedProp]);
116
+ React.useEffect(function () {
117
+ if (locked && !wasLockedRef.current && hasSummary) {
118
+ setSummaryExpanded(false);
119
+ }
120
+ wasLockedRef.current = locked;
121
+ }, [locked, hasSummary]);
122
+ React.useEffect(function () {
123
+ if (summaryExpanded) {
124
+ setSummaryCollapsedSettled(false);
125
+ return;
126
+ }
127
+ var id = window.setTimeout(function () {
128
+ return setSummaryCollapsedSettled(true);
129
+ }, 230);
130
+ return function () {
131
+ return window.clearTimeout(id);
132
+ };
133
+ }, [summaryExpanded]);
540
134
  var handleResolve = function handleResolve(decision) {
541
- if (locked) return;
542
- if (decision === 'approve' && !canApprove) return;
135
+ if (locked || resolveLockRef.current) return;
136
+ resolveLockRef.current = true;
137
+ if (hasSummary) setSummaryExpanded(false);
543
138
  if (!isResolvedControlled) setInternalResolved(decision);
544
139
  onResolve === null || onResolve === void 0 || onResolve({
545
- decision: decision,
546
- values: _objectSpread({}, valuesWithDefaults)
140
+ decision: decision
547
141
  });
548
142
  };
549
- var resolvedMain = resolved === 'approve' ? (_spec$resolvedLabel = spec.resolvedLabel) !== null && _spec$resolvedLabel !== void 0 ? _spec$resolvedLabel : spec.description : resolved === 'reject' ? (_spec$rejectedLabel = spec.rejectedLabel) !== null && _spec$rejectedLabel !== void 0 ? _spec$rejectedLabel : spec.description : null;
550
- var showSummary = !!resolved && !!resolvedMain && resolvedMain !== spec.description;
551
- var hasFields = fields.length > 0;
143
+ var handleToggleSummary = function handleToggleSummary() {
144
+ if (summaryExpanded) {
145
+ setSummaryExpanded(false);
146
+ return;
147
+ }
148
+ setSummaryCollapsedSettled(false);
149
+ requestAnimationFrame(function () {
150
+ return setSummaryExpanded(true);
151
+ });
152
+ };
153
+ var resolvedMain = resolved ? lockedTitle(spec.description, resolved, resolved === 'approve' ? spec.resolvedLabel : spec.rejectedLabel) : null;
552
154
  return /*#__PURE__*/React.createElement("div", {
553
155
  "data-odn-approval": true,
554
156
  "data-destructive": spec.destructive || undefined,
555
157
  "data-resolved": resolved || undefined,
556
- "data-has-fields": hasFields || undefined,
158
+ "data-has-summary": hasSummary || undefined,
159
+ "data-summary-expanded": hasSummary && summaryExpanded ? '' : undefined,
557
160
  className: clsx(className)
558
161
  }, /*#__PURE__*/React.createElement("div", {
559
162
  "data-odn-approval-body": true
560
163
  }, /*#__PURE__*/React.createElement("div", {
561
164
  "data-odn-approval-heading": true
165
+ }, /*#__PURE__*/React.createElement("div", {
166
+ "data-odn-approval-title-row": true
562
167
  }, /*#__PURE__*/React.createElement("p", {
563
168
  "data-odn-approval-text": true
564
169
  }, resolved ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Icon, {
565
- name: resolved === 'approve' ? 'check' : 'close',
170
+ name: resolved === 'approve' ? 'check' : 'x',
566
171
  size: 14,
567
172
  "data-odn-approval-icon": true
568
173
  }), /*#__PURE__*/React.createElement("span", {
569
174
  "data-odn-approval-resolved-main": true
570
- }, resolvedMain), showSummary ? /*#__PURE__*/React.createElement("span", {
571
- "data-odn-approval-resolved-summary": true,
572
- title: spec.description
573
- }, "\xB7 \u539F\u95EE\u9898\uFF1A", spec.description) : null) : /*#__PURE__*/React.createElement(React.Fragment, null, spec.destructive ? /*#__PURE__*/React.createElement(Icon, {
175
+ }, resolvedMain)) : /*#__PURE__*/React.createElement(React.Fragment, null, spec.destructive ? /*#__PURE__*/React.createElement(Icon, {
574
176
  name: "alert-triangle",
575
177
  size: 14,
576
178
  "data-odn-approval-icon": true,
577
179
  "data-destructive": true
578
- }) : null, /*#__PURE__*/React.createElement("span", null, spec.description)))), hasFields && !resolved ? /*#__PURE__*/React.createElement("div", {
579
- "data-odn-approval-fields": true
580
- }, fields.map(function (field) {
581
- return /*#__PURE__*/React.createElement(FieldNode, {
582
- key: field.key,
583
- field: field,
584
- values: valuesWithDefaults,
585
- onPatch: patchValues,
586
- locked: locked,
587
- depth: 0
588
- });
589
- })) : null), !resolved ? /*#__PURE__*/React.createElement("div", {
180
+ }) : null, /*#__PURE__*/React.createElement("span", null, spec.description))), hasSummary ? /*#__PURE__*/React.createElement("button", {
181
+ type: "button",
182
+ "data-odn-approval-summary-toggle": true,
183
+ "aria-expanded": summaryExpanded,
184
+ onClick: handleToggleSummary
185
+ }, /*#__PURE__*/React.createElement("span", null, summaryExpanded ? '收起' : '展开'), /*#__PURE__*/React.createElement(Icon, {
186
+ name: "chevron-down",
187
+ size: 14,
188
+ "data-odn-approval-summary-chevron": true
189
+ })) : null), hasSummary && !resolved ? /*#__PURE__*/React.createElement("span", {
190
+ "data-odn-approval-summary-count": true
191
+ }, summary.length, " \u9879\u53C2\u6570") : null), hasSummary ? /*#__PURE__*/React.createElement("div", {
192
+ "data-odn-approval-summary-panel": true,
193
+ "data-open": summaryExpanded ? 'true' : 'false',
194
+ "data-collapsed-settled": summaryCollapsedSettled ? '' : undefined,
195
+ "aria-hidden": !summaryExpanded
196
+ }, /*#__PURE__*/React.createElement("div", {
197
+ "data-odn-approval-summary-panel-inner": true
198
+ }, /*#__PURE__*/React.createElement("div", {
199
+ "data-odn-approval-summary-surface": true
200
+ }, /*#__PURE__*/React.createElement("div", {
201
+ "data-odn-approval-summary-fade": true
202
+ }, /*#__PURE__*/React.createElement(ApprovalReceipt, {
203
+ summary: summary
204
+ }))))) : null), !resolved ? /*#__PURE__*/React.createElement("div", {
590
205
  "data-odn-approval-actions": true
591
206
  }, spec.rejectLabel ? /*#__PURE__*/React.createElement(Button, {
592
207
  size: "small",
@@ -597,7 +212,6 @@ export function Approval(_ref4) {
597
212
  }, spec.rejectLabel) : null, /*#__PURE__*/React.createElement(Button, {
598
213
  size: "small",
599
214
  intent: spec.destructive ? 'danger' : 'primary',
600
- disabled: !canApprove,
601
215
  onClick: function onClick() {
602
216
  return handleResolve('approve');
603
217
  }
@@ -1,10 +1,8 @@
1
1
  @charset "UTF-8";
2
2
  /**
3
- * Approval · 授权确认
4
- * 轻量态:紧凑横条(文案 + 按钮垂直居中)。
5
- * 写操作审参(data-has-fields):对齐 Composer box——
6
- * 圆角 12px、描边 black-6、内边距 10px、底部分割线通栏。
7
- * destructive 只影响主按钮与警告 icon,不整卡变红。
3
+ * Approval · 授权确认(小票)
4
+ * 轻量态:文案 + 按钮垂直居中。
5
+ * summary:只读参数小票,无编辑;改参走 Composer / Clarify。
8
6
  */
9
7
  [data-odn-approval] {
10
8
  display: flex;
@@ -19,8 +17,7 @@
19
17
  background: var(--odn-color-bg-elevated);
20
18
  }
21
19
 
22
- /* 写操作审参:与 Composer box 同规格 */
23
- [data-odn-approval][data-has-fields] {
20
+ [data-odn-approval][data-has-summary] {
24
21
  flex-direction: column;
25
22
  align-items: stretch;
26
23
  gap: 0;
@@ -37,26 +34,38 @@
37
34
  flex: 1;
38
35
  }
39
36
 
40
- [data-odn-approval][data-has-fields] [data-odn-approval-body] {
41
- padding: 10px;
37
+ [data-odn-approval][data-has-summary] [data-odn-approval-body] {
38
+ padding: 10px 12px 12px;
42
39
  flex: none;
43
- gap: 6px;
40
+ gap: 0;
44
41
  }
45
42
 
46
43
  [data-odn-approval-heading] {
47
44
  display: flex;
48
45
  flex-direction: column;
46
+ align-items: stretch;
49
47
  gap: 4px;
50
48
  min-width: 0;
51
49
  }
52
50
 
51
+ /* 标题与「收起/展开」同一行 */
52
+ [data-odn-approval-title-row] {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ gap: 12px;
57
+ min-width: 0;
58
+ }
59
+
53
60
  [data-odn-approval-text] {
54
61
  display: flex;
55
62
  align-items: center;
56
63
  gap: 6px;
57
64
  margin: 0;
58
65
  min-width: 0;
66
+ flex: 1;
59
67
  font-size: 14px;
68
+ font-weight: 400;
60
69
  line-height: 1.5;
61
70
  color: var(--odn-color-black-12);
62
71
  }
@@ -64,178 +73,157 @@
64
73
  min-width: 0;
65
74
  }
66
75
 
67
- [data-odn-approval-icon] {
76
+ [data-odn-approval-summary-count] {
77
+ font-size: 12px;
78
+ font-weight: 400;
79
+ line-height: 1.4;
80
+ color: var(--odn-color-black-9);
81
+ }
82
+
83
+ [data-odn-approval-summary-toggle] {
84
+ display: inline-flex;
85
+ align-items: center;
86
+ gap: 2px;
68
87
  flex-shrink: 0;
88
+ margin: 0;
89
+ padding: 0;
90
+ border: none;
91
+ background: transparent;
92
+ cursor: pointer;
93
+ font-size: 12px;
94
+ font-weight: 400;
95
+ line-height: 1.4;
69
96
  color: var(--odn-color-black-9);
97
+ white-space: nowrap;
70
98
  }
71
- [data-odn-approval-icon][data-destructive] {
72
- color: var(--odn-color-danger, #dc2626);
99
+ [data-odn-approval-summary-toggle]:hover {
100
+ color: var(--odn-color-black-11);
73
101
  }
74
102
 
75
- [data-odn-approval-fields] {
76
- display: flex;
77
- flex-direction: column;
78
- gap: 8px;
79
- padding-top: 0;
103
+ [data-odn-approval-summary-chevron] {
104
+ transition: transform 0.2s ease-out;
80
105
  }
81
106
 
82
- /* 灰底块包住每个叶子表单项:上下结构(标签 → 控件) */
83
- [data-odn-approval-field] {
84
- display: flex;
85
- flex-direction: column;
86
- gap: 6px;
87
- padding: 10px;
88
- border-radius: 8px;
89
- background: var(--odn-color-black-2);
90
- box-sizing: border-box;
107
+ [data-odn-approval][data-summary-expanded] [data-odn-approval-summary-chevron] {
108
+ transform: rotate(180deg);
91
109
  }
92
110
 
93
- /* radio:选项间距收紧(组件默认横排 gap=24px,审批卡内过疏) */
94
- [data-odn-approval-field][data-control=radio] [data-odn-radio-group] {
95
- --odn-radio-gap-small: 12px;
96
- --odn-radio-gap-medium: 12px;
111
+ [data-odn-approval-icon] {
112
+ flex-shrink: 0;
113
+ color: var(--odn-color-black-9);
97
114
  }
98
-
99
- /* 复合分组 */
100
- [data-odn-approval-group],
101
- [data-odn-approval-list] {
102
- display: flex;
103
- flex-direction: column;
104
- gap: 8px;
105
- padding: 10px;
106
- border-radius: 8px;
107
- border: 1px solid var(--odn-color-black-4);
108
- background: var(--odn-color-bg-elevated);
109
- box-sizing: border-box;
115
+ [data-odn-approval-icon][data-destructive] {
116
+ color: var(--odn-color-danger, #dc2626);
110
117
  }
111
118
 
112
- [data-odn-approval-group-header],
113
- [data-odn-approval-list-header] {
114
- display: flex;
115
- align-items: center;
116
- flex-wrap: wrap;
117
- gap: 6px;
119
+ /**
120
+ * 展开/折叠:grid 0fr→1fr。
121
+ * 标题↔灰底 8px 用 inner::before(裁切层内),折叠归零;
122
+ * 勿用 inner padding(会挡住 0fr)。灰底自然高度、自下裁切,顶边不位移。
123
+ */
124
+ [data-odn-approval-summary-panel] {
125
+ display: grid;
126
+ grid-template-rows: minmax(0, 0fr);
127
+ overflow: hidden;
128
+ transition: grid-template-rows 0.22s ease-out;
118
129
  }
119
130
 
120
- [data-odn-approval-group-title] {
121
- font-size: 12px;
122
- line-height: 1.4;
123
- font-weight: 600;
124
- color: var(--odn-color-black-11);
131
+ [data-odn-approval-summary-panel][data-open=true] {
132
+ grid-template-rows: minmax(0, 1fr);
125
133
  }
126
134
 
127
- [data-odn-approval-group-hint] {
128
- font-size: 11px;
129
- line-height: 1.4;
130
- color: var(--odn-color-black-8);
135
+ /* 动画结束后卸掉内部占位,消除 0fr 残高;收合过程中不改 spacer,灰底不瞬移 */
136
+ [data-odn-approval-summary-panel][data-collapsed-settled] {
137
+ height: 0;
138
+ min-height: 0;
139
+ visibility: hidden;
140
+ pointer-events: none;
131
141
  }
132
142
 
133
- [data-odn-approval-group-body],
134
- [data-odn-approval-list-body] {
135
- display: flex;
136
- flex-direction: column;
137
- gap: 8px;
143
+ [data-odn-approval-summary-panel][data-collapsed-settled] [data-odn-approval-summary-panel-inner] {
144
+ display: none;
138
145
  }
139
146
 
140
- [data-odn-approval-list-item] {
147
+ [data-odn-approval-summary-panel-inner] {
141
148
  display: flex;
142
149
  flex-direction: column;
143
- gap: 6px;
144
- padding: 8px;
145
- border-radius: 6px;
146
- background: var(--odn-color-black-1);
147
- box-sizing: border-box;
150
+ min-height: 0;
151
+ overflow: hidden;
152
+ border-radius: 8px;
148
153
  }
149
154
 
150
- [data-odn-approval-list-item-meta] {
151
- display: flex;
152
- align-items: center;
153
- justify-content: space-between;
154
- gap: 8px;
155
+ [data-odn-approval-summary-panel-inner]::before {
156
+ content: "";
157
+ flex: 0 0 8px;
155
158
  }
156
159
 
157
- [data-odn-approval-list-item-index] {
158
- font-size: 11px;
159
- color: var(--odn-color-black-8);
160
+ [data-odn-approval-summary-surface] {
161
+ flex-shrink: 0;
162
+ box-sizing: border-box;
163
+ border-radius: 8px;
164
+ background: var(--odn-color-black-2);
160
165
  }
161
166
 
162
- [data-odn-approval-list-item-fields] {
163
- display: flex;
164
- flex-direction: column;
165
- gap: 6px;
167
+ [data-odn-approval-summary-fade] {
168
+ transition: opacity 0.18s ease-out;
166
169
  }
167
170
 
168
- /* 嵌套组略缩进 */
169
- [data-odn-approval-group] [data-odn-approval-group],
170
- [data-odn-approval-group] [data-odn-approval-list] {
171
- background: var(--odn-color-black-1);
171
+ /* 折叠中/已折叠:自下而上渐隐文字,灰底仍撑满裁切高度 */
172
+ [data-odn-approval-summary-panel][data-open=false] [data-odn-approval-summary-fade] {
173
+ -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 18%, rgba(0, 0, 0, 0.35) 45%, transparent 78%);
174
+ mask-image: linear-gradient(to bottom, #000 0%, #000 18%, rgba(0, 0, 0, 0.35) 45%, transparent 78%);
175
+ opacity: 0.55;
172
176
  }
173
177
 
174
- [data-odn-approval-field-meta] {
178
+ @media (prefers-reduced-motion: reduce) {
179
+ [data-odn-approval-summary-panel],
180
+ [data-odn-approval-summary-fade],
181
+ [data-odn-approval-summary-chevron] {
182
+ transition: none;
183
+ }
184
+ [data-odn-approval-summary-panel][data-open=false] [data-odn-approval-summary-fade] {
185
+ -webkit-mask-image: none;
186
+ mask-image: none;
187
+ opacity: 0;
188
+ }
189
+ }
190
+ /* 小票:单列;标签宽 = 全部标签最长者(灰底在 surface) */
191
+ [data-odn-approval-receipt] {
175
192
  display: flex;
176
- align-items: center;
177
- justify-content: flex-start;
178
- flex-wrap: wrap;
193
+ flex-direction: column;
179
194
  gap: 6px;
195
+ margin: 0;
196
+ padding: 10px;
197
+ box-sizing: border-box;
180
198
  }
181
199
 
182
- [data-odn-approval-field-label] {
183
- font-size: 12px;
184
- line-height: 1.4;
185
- color: var(--odn-color-black-9);
186
- font-weight: 600;
200
+ [data-odn-approval-receipt-row] {
201
+ display: grid;
202
+ grid-template-columns: var(--odn-approval-label-width, max-content) minmax(0, 1fr);
203
+ column-gap: 12px;
204
+ align-items: baseline;
205
+ min-width: 0;
187
206
  }
188
207
 
189
- [data-odn-approval-field-optional] {
208
+ [data-odn-approval-receipt-label] {
209
+ margin: 0;
190
210
  font-size: 12px;
211
+ line-height: 1.5;
191
212
  font-weight: 400;
192
- color: var(--odn-color-black-8);
193
- }
194
-
195
- [data-odn-approval-field-source] {
196
- flex-shrink: 0;
197
- font-size: 11px;
198
- line-height: 1.4;
199
- padding: 1px 6px;
200
- border-radius: 4px;
201
213
  color: var(--odn-color-black-9);
202
- /* 字段已是 black-2 灰底,徽标用更深一档以免糊在一起 */
203
- background: var(--odn-color-black-3);
204
- }
205
-
206
- [data-odn-approval-field][data-source=user] [data-odn-approval-field-source] {
207
- color: var(--odn-color-brand-8);
208
- background: color-mix(in srgb, var(--odn-color-brand-6) 12%, transparent);
209
- }
210
-
211
- [data-odn-approval-field][data-source=inferred] [data-odn-approval-field-source] {
212
- color: var(--odn-color-black-10);
213
- background: color-mix(in srgb, var(--odn-color-black-4) 80%, transparent);
214
+ white-space: nowrap;
214
215
  }
215
216
 
216
- [data-odn-approval-field-control] {
217
- min-width: 0;
218
- width: 100%;
219
- }
220
- [data-odn-approval-field-control] [data-odn-input],
221
- [data-odn-approval-field-control] [data-odn-input-number],
222
- [data-odn-approval-field-control] [data-odn-select] {
223
- width: 100%;
224
- box-sizing: border-box;
225
- }
226
- [data-odn-approval-field-control] {
227
- /* 与 Input/Select small(约 30px)对齐;DatePicker 默认触发器是 36px */
228
- }
229
- [data-odn-approval-field-control] [data-odn-date-picker-container],
230
- [data-odn-approval-field-control] [data-odn-date-picker-container-range] {
231
- width: 100%;
232
- }
233
- [data-odn-approval-field-control] [data-odn-date-picker-input] {
234
- height: 30px;
217
+ [data-odn-approval-receipt-value] {
218
+ margin: 0;
235
219
  font-size: 12px;
236
220
  line-height: 1.5;
237
- padding: 4px 28px 4px 12px;
238
- border-radius: 6px;
221
+ color: var(--odn-color-black-12);
222
+ word-break: break-word;
223
+ white-space: pre-line;
224
+ }
225
+ [data-odn-approval-receipt-value][data-multiline] {
226
+ line-height: 20px;
239
227
  }
240
228
 
241
229
  [data-odn-approval-actions] {
@@ -246,63 +234,88 @@
246
234
  flex-shrink: 0;
247
235
  }
248
236
 
249
- /* 通栏分割线;下/左/右 padding 均为 10px,对齐 Composer box */
250
- [data-odn-approval][data-has-fields] [data-odn-approval-actions] {
237
+ [data-odn-approval][data-has-summary] [data-odn-approval-actions] {
251
238
  width: 100%;
252
239
  box-sizing: border-box;
253
240
  margin: 0;
254
- padding: 10px;
241
+ padding: 10px 12px;
255
242
  border-top: 1px solid var(--odn-color-black-4);
256
243
  }
257
244
 
258
- /**
259
- * dock 挂载:与 ClarifyDock attach 同规则——
260
- * 左右 16px 对齐 Composer 外层 padding,使描边与 composer-box 等宽;
261
- * 与 Composer 间距 4px。
262
- */
263
245
  [data-odn-approval-attach] {
264
246
  padding-left: 16px;
265
247
  padding-right: 16px;
266
248
  margin-bottom: 4px;
267
249
  }
268
250
 
269
- /* 锁态 */
251
+ /* 锁态:无参仍横条居中;有参保留卡片列,折叠紧凑 / 展开复用小票 */
252
+ [data-odn-approval][data-resolved]:not([data-has-summary]) {
253
+ align-items: center;
254
+ }
255
+
256
+ [data-odn-approval][data-has-summary][data-resolved] {
257
+ flex-direction: column;
258
+ padding: 0;
259
+ border-radius: 12px;
260
+ }
261
+
262
+ [data-odn-approval][data-has-summary][data-resolved] [data-odn-approval-body] {
263
+ padding: 10px 12px;
264
+ gap: 0;
265
+ }
266
+
267
+ [data-odn-approval][data-has-summary][data-resolved][data-summary-expanded] [data-odn-approval-body] {
268
+ padding: 10px 12px 12px;
269
+ }
270
+
271
+ [data-odn-approval][data-resolved] [data-odn-approval-heading] {
272
+ gap: 0;
273
+ }
274
+
275
+ [data-odn-approval][data-resolved] [data-odn-approval-title-row] {
276
+ gap: 12px;
277
+ }
278
+
279
+ [data-odn-approval][data-resolved] [data-odn-approval-text] {
280
+ flex: 1;
281
+ gap: 6px;
282
+ font-size: 13px;
283
+ font-weight: 400;
284
+ line-height: 1.4;
285
+ }
286
+
270
287
  [data-odn-approval][data-resolved=approve] {
271
- border-color: color-mix(in srgb, var(--odn-color-brand-6) 35%, var(--odn-color-black-5));
272
- background: color-mix(in srgb, var(--odn-color-brand-6) 8%, var(--odn-color-bg-elevated));
288
+ border-color: color-mix(in srgb, var(--odn-color-brand-6) 28%, var(--odn-color-black-5));
289
+ background: color-mix(in srgb, var(--odn-color-brand-6) 7%, var(--odn-color-bg-elevated));
290
+ }
291
+
292
+ /* 小票:比锁态底(brand 7%)更深一档的蓝,避免透明 black-2 透底发脏 */
293
+ [data-odn-approval][data-resolved=approve] [data-odn-approval-summary-surface] {
294
+ background: color-mix(in srgb, var(--odn-color-brand-6) 14%, var(--odn-color-bg-elevated));
273
295
  }
274
296
 
275
297
  [data-odn-approval][data-resolved=reject] {
276
- background: color-mix(in srgb, var(--odn-color-black-3) 60%, var(--odn-color-bg-elevated));
298
+ border-color: var(--odn-color-black-5);
299
+ background: color-mix(in srgb, var(--odn-color-black-3) 45%, var(--odn-color-bg-elevated));
277
300
  }
278
301
 
279
302
  [data-odn-approval][data-resolved=approve] [data-odn-approval-icon] {
280
303
  color: var(--odn-color-brand-6);
281
304
  }
282
305
 
283
- [data-odn-approval][data-resolved=approve] [data-odn-approval-resolved-main] {
284
- color: var(--odn-color-brand-8);
285
- font-weight: 500;
286
- }
287
-
288
- [data-odn-approval][data-resolved=approve] [data-odn-approval-resolved-summary] {
289
- color: color-mix(in srgb, var(--odn-color-brand-7) 70%, transparent);
306
+ [data-odn-approval][data-resolved=reject] [data-odn-approval-icon] {
307
+ color: var(--odn-color-black-8);
290
308
  }
291
309
 
292
- [data-odn-approval][data-resolved=reject] [data-odn-approval-resolved-main] {
293
- color: var(--odn-color-black-11);
310
+ [data-odn-approval-resolved-main] {
311
+ flex-shrink: 0;
294
312
  font-weight: 500;
295
313
  }
296
314
 
297
- [data-odn-approval][data-resolved=reject] [data-odn-approval-resolved-summary] {
298
- color: var(--odn-color-black-9);
315
+ [data-odn-approval][data-resolved=approve] [data-odn-approval-resolved-main] {
316
+ color: var(--odn-color-brand-8);
299
317
  }
300
318
 
301
- [data-odn-approval-resolved-summary] {
302
- flex: 1;
303
- min-width: 0;
304
- overflow: hidden;
305
- text-overflow: ellipsis;
306
- white-space: nowrap;
307
- font-size: 13px;
319
+ [data-odn-approval][data-resolved=reject] [data-odn-approval-resolved-main] {
320
+ color: var(--odn-color-black-11);
308
321
  }
package/dist/index.d.ts CHANGED
@@ -56,7 +56,7 @@ export { default as VirtualList, type VirtualListProps } from './virtual-list';
56
56
  export { default as ActionBar, type ActionBarProps } from './action-bar';
57
57
  export { default as AgentStep, type AgentStepProps, type AgentStepGroupProps } from './agent-step';
58
58
  export { default as AgentThink, type AgentThinkProps } from './agent-think';
59
- export { default as Approval, type ApprovalProps, type ApprovalSpec, type ApprovalDecision, type ApprovalResolvePayload, type ApprovalField, type ApprovalFieldSource, type ApprovalFieldControl, type ApprovalFieldOption, } from './approval';
59
+ export { default as Approval, type ApprovalProps, type ApprovalSpec, type ApprovalDecision, type ApprovalResolvePayload, type ApprovalSummaryItem, } from './approval';
60
60
  export { default as Artifact, type ArtifactProps } from './artifact';
61
61
  export { default as Attachments, type AttachmentsProps } from './attachments';
62
62
  export { default as CodeBlock, type CodeBlockProps } from './code-block';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.46",
3
+ "version": "0.0.47",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
5
  "packageManager": "pnpm@11.8.0",
6
6
  "module": "dist/index.js",