one-design-next 0.0.45 → 0.0.46
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/_interrupt-types.d.ts +26 -0
- package/dist/_interrupt-types.js +1 -0
- package/dist/approval/index.d.ts +72 -0
- package/dist/approval/index.js +607 -0
- package/dist/approval/style/index.css +308 -0
- package/dist/approval/style/index.d.ts +2 -0
- package/dist/approval/style/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interrupt · 对话中断协议(无 UI)
|
|
3
|
+
*
|
|
4
|
+
* Clarify(要信息)与 Approval(要授权)分轨组件,只共享本协议。
|
|
5
|
+
* 见讲演录:interrupt-clarify-approval-split
|
|
6
|
+
*
|
|
7
|
+
* 业界对照:
|
|
8
|
+
* - Claude `canUseTool`(AskUserQuestion vs tool permission)
|
|
9
|
+
* - LangChain `interrupt` + approve/edit/reject/respond
|
|
10
|
+
* - OpenAI Agents `interruption` / `needsApproval`
|
|
11
|
+
*/
|
|
12
|
+
/** 中断意图:收集信息 | 授权副作用 */
|
|
13
|
+
export type InterruptIntent = 'clarify' | 'approve';
|
|
14
|
+
/** 中断生命周期 */
|
|
15
|
+
export type InterruptStatus = 'pending' | 'resolved' | 'skipped';
|
|
16
|
+
/**
|
|
17
|
+
* 中断最小信封。
|
|
18
|
+
* `payload` 由 intent 分发:clarify → Clarify*Spec;approve → ApprovalSpec。
|
|
19
|
+
* 具体 Spec 类型在各组件目录定义,协议层不反向依赖 UI。
|
|
20
|
+
*/
|
|
21
|
+
export interface InterruptBase<TPayload = unknown> {
|
|
22
|
+
id: string;
|
|
23
|
+
intent: InterruptIntent;
|
|
24
|
+
status: InterruptStatus;
|
|
25
|
+
payload: TPayload;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import './style';
|
|
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;
|
|
17
|
+
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;
|
|
38
|
+
}
|
|
39
|
+
export interface ApprovalSpec {
|
|
40
|
+
/** 待授权动作说明 */
|
|
41
|
+
description: string;
|
|
42
|
+
/** 写操作工具 / 任务短名;有 fields 时显示在标题下辅助描述中 */
|
|
43
|
+
title?: string;
|
|
44
|
+
actionLabel: string;
|
|
45
|
+
rejectLabel?: string;
|
|
46
|
+
destructive?: boolean;
|
|
47
|
+
resolvedLabel?: string;
|
|
48
|
+
rejectedLabel?: string;
|
|
49
|
+
/**
|
|
50
|
+
* 当前步可见的参数树。分支 / 条件显隐由 Host 算好再传入;
|
|
51
|
+
* 组件不内置业务路由引擎。
|
|
52
|
+
*/
|
|
53
|
+
fields?: ApprovalField[];
|
|
54
|
+
}
|
|
55
|
+
export interface ApprovalResolvePayload {
|
|
56
|
+
decision: ApprovalDecision;
|
|
57
|
+
values?: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
export interface ApprovalProps {
|
|
60
|
+
spec: ApprovalSpec;
|
|
61
|
+
values?: Record<string, unknown>;
|
|
62
|
+
defaultValues?: Record<string, unknown>;
|
|
63
|
+
onValuesChange?: (values: Record<string, unknown>) => void;
|
|
64
|
+
resolved?: ApprovalDecision | null;
|
|
65
|
+
onResolve?: (payload: ApprovalResolvePayload) => void;
|
|
66
|
+
className?: string;
|
|
67
|
+
}
|
|
68
|
+
export declare function Approval({ spec, values: valuesProp, defaultValues, onValuesChange, resolved: resolvedProp, onResolve, className, }: ApprovalProps): React.JSX.Element;
|
|
69
|
+
export declare namespace Approval {
|
|
70
|
+
var displayName: string;
|
|
71
|
+
}
|
|
72
|
+
export default Approval;
|
|
@@ -0,0 +1,607 @@
|
|
|
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
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
8
|
+
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
|
+
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
|
+
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
|
+
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
|
+
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
|
+
import * as React from 'react';
|
|
19
|
+
import clsx from 'clsx';
|
|
20
|
+
import Button from "../button";
|
|
21
|
+
import DatePicker from "../date-picker";
|
|
22
|
+
import DateRangePicker from "../date-range-picker";
|
|
23
|
+
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
|
+
import "./style";
|
|
30
|
+
|
|
31
|
+
/* ------------------------------------------------------------------ */
|
|
32
|
+
/* Types */
|
|
33
|
+
/* ------------------------------------------------------------------ */
|
|
34
|
+
|
|
35
|
+
/** 参数来源:已获取 / AI 推测 / 待用户填 */
|
|
36
|
+
|
|
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);
|
|
76
|
+
}
|
|
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
|
+
}
|
|
107
|
+
}
|
|
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();
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
|
|
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
|
+
}
|
|
308
|
+
});
|
|
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), '')));
|
|
427
|
+
};
|
|
428
|
+
var removeItem = function removeItem(index) {
|
|
429
|
+
if (locked) return;
|
|
430
|
+
if (length <= minItems) return;
|
|
431
|
+
onPatch(removeListItem(values, field.key, index));
|
|
432
|
+
};
|
|
433
|
+
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
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* ------------------------------------------------------------------ */
|
|
497
|
+
/* Approval */
|
|
498
|
+
/* ------------------------------------------------------------------ */
|
|
499
|
+
|
|
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;
|
|
509
|
+
var _React$useState = React.useState(null),
|
|
510
|
+
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
511
|
+
internalResolved = _React$useState2[0],
|
|
512
|
+
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];
|
|
517
|
+
var isResolvedControlled = resolvedProp !== undefined;
|
|
518
|
+
var isValuesControlled = valuesProp !== undefined;
|
|
519
|
+
var resolved = isResolvedControlled ? resolvedProp : internalResolved;
|
|
520
|
+
var values = isValuesControlled ? valuesProp : internalValues;
|
|
521
|
+
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
|
+
});
|
|
540
|
+
var handleResolve = function handleResolve(decision) {
|
|
541
|
+
if (locked) return;
|
|
542
|
+
if (decision === 'approve' && !canApprove) return;
|
|
543
|
+
if (!isResolvedControlled) setInternalResolved(decision);
|
|
544
|
+
onResolve === null || onResolve === void 0 || onResolve({
|
|
545
|
+
decision: decision,
|
|
546
|
+
values: _objectSpread({}, valuesWithDefaults)
|
|
547
|
+
});
|
|
548
|
+
};
|
|
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;
|
|
552
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
553
|
+
"data-odn-approval": true,
|
|
554
|
+
"data-destructive": spec.destructive || undefined,
|
|
555
|
+
"data-resolved": resolved || undefined,
|
|
556
|
+
"data-has-fields": hasFields || undefined,
|
|
557
|
+
className: clsx(className)
|
|
558
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
559
|
+
"data-odn-approval-body": true
|
|
560
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
561
|
+
"data-odn-approval-heading": true
|
|
562
|
+
}, /*#__PURE__*/React.createElement("p", {
|
|
563
|
+
"data-odn-approval-text": true
|
|
564
|
+
}, resolved ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Icon, {
|
|
565
|
+
name: resolved === 'approve' ? 'check' : 'close',
|
|
566
|
+
size: 14,
|
|
567
|
+
"data-odn-approval-icon": true
|
|
568
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
569
|
+
"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, {
|
|
574
|
+
name: "alert-triangle",
|
|
575
|
+
size: 14,
|
|
576
|
+
"data-odn-approval-icon": true,
|
|
577
|
+
"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", {
|
|
590
|
+
"data-odn-approval-actions": true
|
|
591
|
+
}, spec.rejectLabel ? /*#__PURE__*/React.createElement(Button, {
|
|
592
|
+
size: "small",
|
|
593
|
+
intent: "normal",
|
|
594
|
+
onClick: function onClick() {
|
|
595
|
+
return handleResolve('reject');
|
|
596
|
+
}
|
|
597
|
+
}, spec.rejectLabel) : null, /*#__PURE__*/React.createElement(Button, {
|
|
598
|
+
size: "small",
|
|
599
|
+
intent: spec.destructive ? 'danger' : 'primary',
|
|
600
|
+
disabled: !canApprove,
|
|
601
|
+
onClick: function onClick() {
|
|
602
|
+
return handleResolve('approve');
|
|
603
|
+
}
|
|
604
|
+
}, spec.actionLabel)) : null);
|
|
605
|
+
}
|
|
606
|
+
Approval.displayName = 'Approval';
|
|
607
|
+
export default Approval;
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
/**
|
|
3
|
+
* Approval · 授权确认
|
|
4
|
+
* 轻量态:紧凑横条(文案 + 按钮垂直居中)。
|
|
5
|
+
* 写操作审参(data-has-fields):对齐 Composer box——
|
|
6
|
+
* 圆角 12px、描边 black-6、内边距 10px、底部分割线通栏。
|
|
7
|
+
* destructive 只影响主按钮与警告 icon,不整卡变红。
|
|
8
|
+
*/
|
|
9
|
+
[data-odn-approval] {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
gap: 12px;
|
|
14
|
+
width: 100%;
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
padding: 12px 16px;
|
|
17
|
+
border-radius: 10px;
|
|
18
|
+
border: 1px solid var(--odn-color-black-5);
|
|
19
|
+
background: var(--odn-color-bg-elevated);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* 写操作审参:与 Composer box 同规格 */
|
|
23
|
+
[data-odn-approval][data-has-fields] {
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
align-items: stretch;
|
|
26
|
+
gap: 0;
|
|
27
|
+
padding: 0;
|
|
28
|
+
border-radius: 12px;
|
|
29
|
+
border: 1px solid var(--odn-color-black-6);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[data-odn-approval-body] {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 12px;
|
|
36
|
+
min-width: 0;
|
|
37
|
+
flex: 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[data-odn-approval][data-has-fields] [data-odn-approval-body] {
|
|
41
|
+
padding: 10px;
|
|
42
|
+
flex: none;
|
|
43
|
+
gap: 6px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[data-odn-approval-heading] {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 4px;
|
|
50
|
+
min-width: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
[data-odn-approval-text] {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 6px;
|
|
57
|
+
margin: 0;
|
|
58
|
+
min-width: 0;
|
|
59
|
+
font-size: 14px;
|
|
60
|
+
line-height: 1.5;
|
|
61
|
+
color: var(--odn-color-black-12);
|
|
62
|
+
}
|
|
63
|
+
[data-odn-approval-text] > span {
|
|
64
|
+
min-width: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[data-odn-approval-icon] {
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
color: var(--odn-color-black-9);
|
|
70
|
+
}
|
|
71
|
+
[data-odn-approval-icon][data-destructive] {
|
|
72
|
+
color: var(--odn-color-danger, #dc2626);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
[data-odn-approval-fields] {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
gap: 8px;
|
|
79
|
+
padding-top: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
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;
|
|
91
|
+
}
|
|
92
|
+
|
|
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;
|
|
97
|
+
}
|
|
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;
|
|
110
|
+
}
|
|
111
|
+
|
|
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;
|
|
118
|
+
}
|
|
119
|
+
|
|
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);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[data-odn-approval-group-hint] {
|
|
128
|
+
font-size: 11px;
|
|
129
|
+
line-height: 1.4;
|
|
130
|
+
color: var(--odn-color-black-8);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
[data-odn-approval-group-body],
|
|
134
|
+
[data-odn-approval-list-body] {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: column;
|
|
137
|
+
gap: 8px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[data-odn-approval-list-item] {
|
|
141
|
+
display: flex;
|
|
142
|
+
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;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
[data-odn-approval-list-item-meta] {
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
[data-odn-approval-list-item-index] {
|
|
158
|
+
font-size: 11px;
|
|
159
|
+
color: var(--odn-color-black-8);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[data-odn-approval-list-item-fields] {
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-direction: column;
|
|
165
|
+
gap: 6px;
|
|
166
|
+
}
|
|
167
|
+
|
|
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);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
[data-odn-approval-field-meta] {
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
justify-content: flex-start;
|
|
178
|
+
flex-wrap: wrap;
|
|
179
|
+
gap: 6px;
|
|
180
|
+
}
|
|
181
|
+
|
|
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;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
[data-odn-approval-field-optional] {
|
|
190
|
+
font-size: 12px;
|
|
191
|
+
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
|
+
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
|
+
}
|
|
215
|
+
|
|
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;
|
|
235
|
+
font-size: 12px;
|
|
236
|
+
line-height: 1.5;
|
|
237
|
+
padding: 4px 28px 4px 12px;
|
|
238
|
+
border-radius: 6px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
[data-odn-approval-actions] {
|
|
242
|
+
display: flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
justify-content: flex-end;
|
|
245
|
+
gap: 8px;
|
|
246
|
+
flex-shrink: 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* 通栏分割线;下/左/右 padding 均为 10px,对齐 Composer box */
|
|
250
|
+
[data-odn-approval][data-has-fields] [data-odn-approval-actions] {
|
|
251
|
+
width: 100%;
|
|
252
|
+
box-sizing: border-box;
|
|
253
|
+
margin: 0;
|
|
254
|
+
padding: 10px;
|
|
255
|
+
border-top: 1px solid var(--odn-color-black-4);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* dock 挂载:与 ClarifyDock attach 同规则——
|
|
260
|
+
* 左右 16px 对齐 Composer 外层 padding,使描边与 composer-box 等宽;
|
|
261
|
+
* 与 Composer 间距 4px。
|
|
262
|
+
*/
|
|
263
|
+
[data-odn-approval-attach] {
|
|
264
|
+
padding-left: 16px;
|
|
265
|
+
padding-right: 16px;
|
|
266
|
+
margin-bottom: 4px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* 锁态 */
|
|
270
|
+
[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));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
[data-odn-approval][data-resolved=reject] {
|
|
276
|
+
background: color-mix(in srgb, var(--odn-color-black-3) 60%, var(--odn-color-bg-elevated));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
[data-odn-approval][data-resolved=approve] [data-odn-approval-icon] {
|
|
280
|
+
color: var(--odn-color-brand-6);
|
|
281
|
+
}
|
|
282
|
+
|
|
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);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
[data-odn-approval][data-resolved=reject] [data-odn-approval-resolved-main] {
|
|
293
|
+
color: var(--odn-color-black-11);
|
|
294
|
+
font-weight: 500;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
[data-odn-approval][data-resolved=reject] [data-odn-approval-resolved-summary] {
|
|
298
|
+
color: var(--odn-color-black-9);
|
|
299
|
+
}
|
|
300
|
+
|
|
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;
|
|
308
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +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
60
|
export { default as Artifact, type ArtifactProps } from './artifact';
|
|
60
61
|
export { default as Attachments, type AttachmentsProps } from './attachments';
|
|
61
62
|
export { default as CodeBlock, type CodeBlockProps } from './code-block';
|
|
@@ -78,4 +79,5 @@ export { default as UserBubble, type UserBubbleProps } from './user-bubble';
|
|
|
78
79
|
export { default as Welcome, type WelcomeProps } from './welcome';
|
|
79
80
|
export type { ToolCall, ToolStatus, Source, Attachment, PreviewTarget, PreviewTab, SendMeta, ComposerSegment, ComposerTextSegment, ComposerInvocationSegment, ComposerMentionSegment, TextData, InvocationData, MentionData, InlineRefState, SkillItem, SkillGroup, AgentEvent, Conversation, MessageSnapshot, ChatMessage } from './_genui-types';
|
|
80
81
|
export { ComposerSegmentType } from './_genui-types';
|
|
82
|
+
export type { InterruptIntent, InterruptStatus, InterruptBase, } from './_interrupt-types';
|
|
81
83
|
export { rawValueToSegments, segmentsToReadableText, segmentsHasContent, isTextSegment, isInvocationSegment, isMentionSegment, type SegmentsToReadableTextOptions, } from './composer/segments';
|
package/dist/index.js
CHANGED
|
@@ -62,6 +62,7 @@ export { default as VirtualList } from "./virtual-list";
|
|
|
62
62
|
export { default as ActionBar } from "./action-bar";
|
|
63
63
|
export { default as AgentStep } from "./agent-step";
|
|
64
64
|
export { default as AgentThink } from "./agent-think";
|
|
65
|
+
export { default as Approval } from "./approval";
|
|
65
66
|
export { default as Artifact } from "./artifact";
|
|
66
67
|
export { default as Attachments } from "./attachments";
|
|
67
68
|
export { default as CodeBlock } from "./code-block";
|