one-design-next 0.0.9 → 0.0.11

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/README.md CHANGED
@@ -155,11 +155,11 @@ one-design-next/
155
155
 
156
156
  | 阶段 | Skill | 职责 |
157
157
  |:-----|:------|:-----|
158
- | **P1** 需求 | `p1-design-analyst` · `p1-design-spec` | 需求结构化分析、组件级设计说明 |
159
- | **P2** 知识 | `p2-one-design` · `p2-block-catalog` · `p2-business-knowledge` | 组件库知识、区块目录、业务页面知识 |
160
- | **P3** 质量 | `p3-audit` · `p3-polish` | 代码质量审查、发布前精修 |
161
- | **P4** 转化 | `p4-figma-to-block` · `p4-component-update-process` | 设计稿转区块、组件更新流程 |
162
- | **P5** 落地 | `p5-figma-to-page` · `p5-feedback` | 整页拼装、上下文与反馈采集 |
158
+ | **P1** 设计 | `p1-design-analyst` · `p1-design-spec` | 需求结构化分析、组件级设计说明 |
159
+ | **P2** 知识 | `p2-one-design` · `p2-block-catalog` · `p2-business-knowledge` · `p2-page-catalog` | 组件库知识、区块目录、业务页面知识 |
160
+ | **P3** 执行 | `p3-page-implement` | ODN 组件 + 区块拼装页面代码 |
161
+ | **P4** 质量 | `p4-audit` · `p4-polish` | 代码质量审查、发布前精修 |
162
+ | **内部维护** | `p4-figma-to-block` · `p5-figma-to-page` · `p4-component-update-process` · `p5-dmp-web-restore` · `p5-fe-free-trade-restore` | 设计稿转区块/整页、组件更新、线上页面还原(仅维护者本地用) |
163
163
  | **辅助** | `ten-questions` · `philosophy-talks` | 方法论讨论与设计哲学 |
164
164
 
165
165
  ### 多产品 Skill 发布
@@ -61,7 +61,24 @@ export interface SkillItem {
61
61
  export interface SendMeta {
62
62
  attachments?: Attachment[];
63
63
  webSearch?: boolean;
64
- skill?: string;
64
+ /**
65
+ * 编辑器内插入的 chip 列表(按出现顺序)。
66
+ * - 来源包含工具栏按钮、`/` 触发、`@` 触发等
67
+ * - 通过 `kind` 字段区分 skill / mention / 自定义类型
68
+ * - 业务方按需 filter,例如:`meta.chips?.filter(c => c.kind === 'skill')`
69
+ *
70
+ * BREAKING(pre-1.0):取代 v0.0.x 的 `skill?: string` 单值字段。
71
+ * 老业务迁移:`meta.skill` → `meta.chips?.find(c => c.kind === 'skill')?.label`
72
+ */
73
+ chips?: ComposerChipMeta[];
74
+ }
75
+ /** SendMeta.chips 的元素结构;与 components/composer/chip.tsx ChipData 对齐。 */
76
+ export interface ComposerChipMeta {
77
+ id: string;
78
+ skillId: string;
79
+ label: string;
80
+ icon: string;
81
+ kind?: 'skill' | 'mention' | (string & {});
65
82
  }
66
83
  export type AgentEvent = {
67
84
  kind: 'thinking';
@@ -44,12 +44,8 @@ export interface BaseCascaderProps extends Omit<RcCascaderProps<DefaultOptionTyp
44
44
  separator?: string;
45
45
  /** 自定义下拉列表中每一项的渲染(rc-cascader 原生支持) */
46
46
  optionRender?: (option: DefaultOptionType) => React.ReactNode;
47
- /**
48
- * 点击非叶节点内容区域时的行为
49
- * - `true`:选中非叶节点并关闭下拉
50
- * - `'keep-open'`:选中非叶节点并触发 onChange,但保持下拉展开(子菜单继续展开)
51
- */
52
- changeOnSelect?: boolean | 'keep-open';
47
+ /** 点击非叶节点内容区域时也触发 onChange(下拉保持展开,子菜单继续展开) */
48
+ changeOnSelect?: boolean;
53
49
  }
54
50
  export type CascaderProps<V = (string | number)[] | null> = BaseCascaderProps & {
55
51
  mode?: 'single' | 'multiple';
@@ -3,11 +3,10 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
3
3
  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); }
4
4
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
5
5
  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."); }
6
- 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; } }
7
- function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
8
- 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) { function e(_x) { return _e.apply(this, arguments); } e.toString = function () { return _e.toString(); }; return e; }(function (e) { throw e; }), 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 (_e2) { function e(_x2) { return _e2.apply(this, arguments); } e.toString = function () { return _e2.toString(); }; return e; }(function (e) { didErr = true; err = e; }), f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
9
6
  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
7
  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; }
8
+ 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; } }
9
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
11
10
  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; }
12
11
  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; }
13
12
  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; }
@@ -90,41 +89,6 @@ function CascaderInner(_ref) {
90
89
  var processedOptions = React.useMemo(function () {
91
90
  return processOptions(options, mergedFieldNames, optionPopoverProps);
92
91
  }, [options, mergedFieldNames, optionPopoverProps]);
93
-
94
- // 根据完整路径从 processedOptions 中查找对应的 option 对象
95
- var resolvePathOptions = React.useCallback(function (fullPath) {
96
- var result = [];
97
- var currentOptions = processedOptions;
98
- var vField = mergedFieldNames.value || 'value';
99
- var cField = mergedFieldNames.children || 'children';
100
- var _iterator = _createForOfIteratorHelper(fullPath),
101
- _step;
102
- try {
103
- var _loop = function _loop() {
104
- var val = _step.value;
105
- if (!currentOptions) return 0; // break
106
- var found = currentOptions.find(function (opt) {
107
- return opt[vField] === val;
108
- });
109
- if (found) {
110
- result.push(found);
111
- currentOptions = found[cField];
112
- } else {
113
- return 0; // break
114
- }
115
- },
116
- _ret;
117
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
118
- _ret = _loop();
119
- if (_ret === 0) break;
120
- }
121
- } catch (err) {
122
- _iterator.e(err);
123
- } finally {
124
- _iterator.f();
125
- }
126
- return result;
127
- }, [processedOptions, mergedFieldNames]);
128
92
  var prefixCls = 'odn-select';
129
93
  var _useIcons = useIcons(_objectSpread(_objectSpread({}, restProps), {}, {
130
94
  hasFeedback: false,
@@ -211,70 +175,6 @@ function CascaderInner(_ref) {
211
175
  }
212
176
  };
213
177
 
214
- // 单选模式下 pathKey → 带类型的 fullPath 映射,用于事件委托时还原路径
215
- var pathKeyMap = React.useMemo(function () {
216
- if (mode !== 'single') return null;
217
- var SPLIT = '__RC_CASCADER_SPLIT__';
218
- var map = new Map();
219
- var traverse = function traverse(opts) {
220
- if (!opts) return;
221
- var _iterator2 = _createForOfIteratorHelper(opts),
222
- _step2;
223
- try {
224
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
225
- var opt = _step2.value;
226
- var fullPath = opt.__fullPath__;
227
- if (fullPath) {
228
- map.set(fullPath.join(SPLIT), fullPath);
229
- }
230
- var cField = mergedFieldNames.children || 'children';
231
- var children = opt[cField];
232
- if (children && Array.isArray(children)) traverse(children);
233
- }
234
- } catch (err) {
235
- _iterator2.e(err);
236
- } finally {
237
- _iterator2.f();
238
- }
239
- };
240
- traverse(processedOptions);
241
- return map;
242
- }, [mode, processedOptions, mergedFieldNames]);
243
-
244
- // 单选模式下:通过 onClickCapture 在 dropdown 层面拦截点击
245
- // 点击展开图标区域 → 放行,由 rc-cascader 处理展开
246
- // 点击其他区域(内容 / padding) → 拦截,手动选中 + 关闭
247
- var handleSingleSelectCapture = React.useCallback(function (e) {
248
- if (!pathKeyMap) return;
249
- var target = e.target;
250
- var expandIcon = target.closest('.odn-cascader-menu-item-expand-icon');
251
- var menuItem = target.closest('.odn-cascader-menu-item');
252
- if (!menuItem || expandIcon) return;
253
- if (menuItem.classList.contains('odn-cascader-menu-item-disabled')) return;
254
- if (menuItem.getAttribute('title') === 'divider') return;
255
- var pathKey = menuItem.getAttribute('data-path-key');
256
- if (!pathKey) return;
257
- var fullPath = pathKeyMap.get(pathKey);
258
- if (!fullPath) return;
259
- var pathOptions = resolvePathOptions(fullPath);
260
- var lastOption = pathOptions[pathOptions.length - 1];
261
- if (!lastOption) return;
262
- var cField = mergedFieldNames.children || 'children';
263
- var hasChildren = lastOption[cField] && Array.isArray(lastOption[cField]) && lastOption[cField].length > 0;
264
-
265
- // 非叶节点仅在 changeOnSelect 时才可点击选中
266
- if (hasChildren && !changeOnSelectProp) return;
267
-
268
- // keep-open:触发 onChange 但不关闭下拉,让 rc-cascader 继续展开子菜单
269
- if (hasChildren && changeOnSelectProp === 'keep-open') {
270
- handleChange(fullPath, pathOptions, e);
271
- return;
272
- }
273
- e.stopPropagation();
274
- handleChange(fullPath, pathOptions, e);
275
- handleVisibleChange(false);
276
- }, [pathKeyMap, mergedFieldNames, changeOnSelectProp, resolvePathOptions, handleChange, handleVisibleChange]);
277
-
278
178
  // 转换 value 类型以兼容 rc-cascader
279
179
  var rcValue = value === null ? undefined : value;
280
180
  var rcDefaultValue = defaultValue === null ? undefined : defaultValue;
@@ -371,49 +271,34 @@ function CascaderInner(_ref) {
371
271
  },
372
272
  dropdownMatchSelectWidth: dropdownMatchSelectWidth,
373
273
  optionRender: optionRenderProp,
374
- // 单选模式不传 changeOnSelect 给 rc-cascader,
375
- // 使展开图标点击时 isSelectable 对非叶节点返回 false,只触发展开
376
- changeOnSelect: mode === 'single' ? false : !!changeOnSelectProp
274
+ changeOnSelect: !!changeOnSelectProp
377
275
  });
378
- var dropdownRender = React.useMemo(function () {
379
- var searchRenderFn = showInnerSearch ? function (menu) {
380
- var searchNode = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
381
- className: "odn-select-dropdown-search"
382
- }, /*#__PURE__*/React.createElement(Icon, {
383
- name: "search",
384
- className: "odn-select-dropdown-search-icon"
385
- }), /*#__PURE__*/React.createElement("input", {
386
- ref: dropdownSearchInputRef,
387
- className: "odn-select-dropdown-search-input",
388
- placeholder: "\u8BF7\u8F93\u5165",
389
- value: searchValue,
390
- onChange: function onChange(e) {
391
- var value = e.target.value;
392
- if (searchValueProp === undefined) {
393
- setSearchValue(value);
394
- }
395
- if (_onSearch) {
396
- _onSearch(value);
397
- }
398
- },
399
- onKeyDown: function onKeyDown(e) {
400
- e.stopPropagation();
276
+ var dropdownRender = showInnerSearch ? function (menu) {
277
+ var searchNode = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
278
+ className: "odn-select-dropdown-search"
279
+ }, /*#__PURE__*/React.createElement(Icon, {
280
+ name: "search",
281
+ className: "odn-select-dropdown-search-icon"
282
+ }), /*#__PURE__*/React.createElement("input", {
283
+ ref: dropdownSearchInputRef,
284
+ className: "odn-select-dropdown-search-input",
285
+ placeholder: "\u8BF7\u8F93\u5165",
286
+ value: searchValue,
287
+ onChange: function onChange(e) {
288
+ var value = e.target.value;
289
+ if (searchValueProp === undefined) {
290
+ setSearchValue(value);
401
291
  }
402
- })));
403
- return /*#__PURE__*/React.createElement(React.Fragment, null, searchNode, menu);
404
- } : undefined;
405
-
406
- // 单选模式:在 dropdown 层面用 onClickCapture 拦截内容区域点击
407
- if (mode === 'single') {
408
- return function (menu) {
409
- var rendered = searchRenderFn ? searchRenderFn(menu) : menu;
410
- return /*#__PURE__*/React.createElement("div", {
411
- onClickCapture: handleSingleSelectCapture
412
- }, rendered);
413
- };
414
- }
415
- return searchRenderFn;
416
- }, [showInnerSearch, searchValue, searchValueProp, _onSearch, mode, handleSingleSelectCapture]);
292
+ if (_onSearch) {
293
+ _onSearch(value);
294
+ }
295
+ },
296
+ onKeyDown: function onKeyDown(e) {
297
+ e.stopPropagation();
298
+ }
299
+ })));
300
+ return /*#__PURE__*/React.createElement(React.Fragment, null, searchNode, menu);
301
+ } : undefined;
417
302
  if (mode === 'multiple') {
418
303
  return /*#__PURE__*/React.createElement(RcCascader, _extends({}, commonProps, {
419
304
  value: rcValue,
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Composer · 编辑器内的 chip 视觉
3
+ *
4
+ * 当前形态极简:[icon][label][×]
5
+ * - hover 时 icon 变 ×(左槽位互斥),节省横向空间
6
+ * - × 用 onMouseDown preventDefault 防止 contenteditable 把焦点吃过去
7
+ *
8
+ * 视觉是 inline-flex 的 atomic 元素;其 DOM 容器(host span)由 useChipManager
9
+ * 创建并维护 contentEditable=false / data-mention-id;这里只渲染 host 内的内容。
10
+ */
11
+ /// <reference types="react" />
12
+ /** chip 渲染所需的最小数据结构。 */
13
+ export interface ChipData {
14
+ /** chip 实例唯一 id(与 value marker 中的 id 对应) */
15
+ id: string;
16
+ /** 业务定义 id(如 skill id / mention 对象 id),业务方在 onSend 时反查源数据用 */
17
+ skillId: string;
18
+ /** chip 显示文本 */
19
+ label: string;
20
+ /** chip 显示 icon name */
21
+ icon: string;
22
+ /**
23
+ * chip 语义来源标记,业务方自定义。Composer 内部不消费 kind,
24
+ * 仅原样透传到 onSend(meta.chips),方便业务方按 kind 分类。
25
+ * 约定:'skill' = 工具栏按钮 / `/` 触发选出来的能力;
26
+ * 'mention' = `@` 触发的对象引用;
27
+ * 其他自定义字符串业务方自行解释。
28
+ */
29
+ kind?: 'skill' | 'mention' | (string & {});
30
+ }
31
+ export interface ChipProps {
32
+ data: ChipData;
33
+ onRemove: () => void;
34
+ }
35
+ export declare function Chip({ data, onRemove }: ChipProps): import("react").JSX.Element;
36
+ export default Chip;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Composer · 编辑器内的 chip 视觉
3
+ *
4
+ * 当前形态极简:[icon][label][×]
5
+ * - hover 时 icon 变 ×(左槽位互斥),节省横向空间
6
+ * - × 用 onMouseDown preventDefault 防止 contenteditable 把焦点吃过去
7
+ *
8
+ * 视觉是 inline-flex 的 atomic 元素;其 DOM 容器(host span)由 useChipManager
9
+ * 创建并维护 contentEditable=false / data-mention-id;这里只渲染 host 内的内容。
10
+ */
11
+
12
+ import Icon from "../icon";
13
+
14
+ /** chip 渲染所需的最小数据结构。 */
15
+
16
+ export function Chip(_ref) {
17
+ var data = _ref.data,
18
+ onRemove = _ref.onRemove;
19
+ return /*#__PURE__*/React.createElement("span", {
20
+ "data-odn-composer-chip": true,
21
+ "data-state": "valid"
22
+ }, /*#__PURE__*/React.createElement("span", {
23
+ "data-odn-composer-chip-icon": true,
24
+ "aria-hidden": true
25
+ }, /*#__PURE__*/React.createElement(Icon, {
26
+ name: data.icon,
27
+ size: 12
28
+ })), /*#__PURE__*/React.createElement("button", {
29
+ type: "button",
30
+ "data-odn-composer-chip-remove": true,
31
+ "aria-label": "\u79FB\u9664 ".concat(data.label),
32
+ onMouseDown: function onMouseDown(e) {
33
+ // 阻止 contenteditable 把焦点拽走 / 光标错位
34
+ e.preventDefault();
35
+ e.stopPropagation();
36
+ },
37
+ onClick: function onClick(e) {
38
+ e.preventDefault();
39
+ e.stopPropagation();
40
+ onRemove();
41
+ }
42
+ }, /*#__PURE__*/React.createElement(Icon, {
43
+ name: "x",
44
+ size: 12
45
+ })), /*#__PURE__*/React.createElement("span", {
46
+ "data-odn-composer-chip-label": true
47
+ }, data.label));
48
+ }
49
+ export default Chip;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Composer · 编辑器(contenteditable 实现)
3
+ *
4
+ * 替代 Input.Textarea 在 Composer 内部承担"输入区"角色。
5
+ *
6
+ * 阶段(按 MR 拆分):
7
+ * - [step 2] 基础壳:纯文本输入 + autoSize + Enter 自插 br + IME 短路
8
+ * - [step 3] chip 命令式 API + Portal 渲染 + Backspace 整块删
9
+ * - [step 4] @ + / 触发判定 + 浮层信号 + replaceTriggerWithChip ← 当前
10
+ *
11
+ * 与 Input.Textarea 的对外 API 尽量对齐:
12
+ * value / defaultValue / onChange / placeholder / autoSize / onPressEnter
13
+ *
14
+ * chip 模型(hybrid):
15
+ * - DOM 由 contenteditable 自治:每个 chip 是 contentEditable=false 的 span(host),带 data-mention-id
16
+ * - 视觉由 React Portal 注入到 host 内:chip.tsx 负责
17
+ * - chip 状态(id ↔ host)由 useChipManager 维护
18
+ */
19
+ /// <reference types="react" />
20
+ import { type ChipData } from './chip';
21
+ /** Composer editor 触发态对外信号——告诉父组件该弹浮层选 skill 了。 */
22
+ export interface ComposerEditorTriggerInfo {
23
+ /** 触发字符(@ 或 /) */
24
+ trigger: string;
25
+ /** 触发字符之后到 caret 的查询串 */
26
+ query: string;
27
+ /**
28
+ * 触发字符 + query 整段的 client rect。父组件用它定位浮层。
29
+ * 滚动 / resize 后如需最新位置,可重新调用 ref.getTriggerRect()。
30
+ */
31
+ rect: DOMRect;
32
+ }
33
+ export interface ComposerEditorAutoSize {
34
+ minRows?: number;
35
+ maxRows?: number;
36
+ }
37
+ export interface ComposerEditorProps {
38
+ /** 受控值。string,未来会含 marker(chip 序列化为 `\u200b\u2063id\u2063\u200b`)。 */
39
+ value?: string;
40
+ /** 非受控初始值。 */
41
+ defaultValue?: string;
42
+ /** 值变化回调;参数是 raw string,含 marker。 */
43
+ onChange?: (value: string) => void;
44
+ placeholder?: string;
45
+ autoSize?: ComposerEditorAutoSize;
46
+ /**
47
+ * Enter 键回调。
48
+ * - 返回 `false` 阻止默认行为
49
+ * - 调用 `e.preventDefault()` 同样阻止
50
+ * - 默认行为(未阻止)= 自插 `<br>` 换行
51
+ *
52
+ * 父组件(Composer)在这里根据 submitType 决定 Enter 是"发送"还是"让默认换行"。
53
+ */
54
+ onPressEnter?: (e: React.KeyboardEvent<HTMLDivElement>) => void | false;
55
+ /**
56
+ * 启用的触发字符。默认 `['@', '/']`。
57
+ * 设为空数组可禁用触发判定。
58
+ */
59
+ triggers?: readonly string[];
60
+ /**
61
+ * 触发态变化回调:
62
+ * - 进入触发态 → 传入 info
63
+ * - 仍在触发态但 query / rect 变化 → 传入新 info
64
+ * - 退出触发态(按 Esc 之外的方式:删触发字符、空格隔断、光标移开等)→ 传入 null
65
+ * IME 合成期间不会触发。
66
+ */
67
+ onTriggerChange?: (info: ComposerEditorTriggerInfo | null) => void;
68
+ /**
69
+ * 仅当 trigger 处于活动态(triggerRef.current 非空)时调用:
70
+ * 把 ↑↓ Enter Esc Tab 等导航键先丢给父组件让它驱动浮层选择。
71
+ * - 返回 `true` → editor 视为父已处理,不再走自身换行 / 提交逻辑
72
+ * - 返回 `false / undefined` → editor 走原默认(onPressEnter / 换行 / 删 chip 等)
73
+ *
74
+ * 父组件如需 preventDefault,请在 handler 内自己调用——editor 不会替父代劳,
75
+ * 避免某些导航键(如 Tab)在父决定让默认通过时误吃。
76
+ */
77
+ onTriggerKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => boolean | void;
78
+ /**
79
+ * 编辑器可视高度变化回调。
80
+ * height = editor.offsetHeight(受 max-height clamp);atMax 表示触顶。
81
+ * Composer 的 lite 升格逻辑、scrollbar 显隐都用这个。
82
+ */
83
+ onHeightChange?: (height: number, atMax: boolean) => void;
84
+ /**
85
+ * 剪贴板含文件(如截图、资源管理器复制文件)时回调;由上层转为附件等。
86
+ * 若提供且 `files.length > 0`,编辑器会 `preventDefault` 且不再插入纯文本。
87
+ */
88
+ onPasteFiles?: (files: File[]) => void;
89
+ className?: string;
90
+ style?: React.CSSProperties;
91
+ }
92
+ export interface ComposerEditorRef {
93
+ focus: (options?: FocusOptions) => void;
94
+ blur: () => void;
95
+ /** 清空:文本 + 全部 chip + 抛 onChange('') */
96
+ clear: () => void;
97
+ /** 在当前光标位置插入 chip;多次调用产生多个 chip。 */
98
+ insertChip: (data: ChipData) => void;
99
+ /** 按 chip id 移除(也可由 chip 上的 × 自行触发)。 */
100
+ removeChip: (id: string) => void;
101
+ /**
102
+ * 把当前 trigger 区段(含触发字符 + query)替换为 chip。
103
+ * 如果当前没有活动 trigger,退化为 insertChip 在光标位置插入。
104
+ * 配合浮层"用户选了某个 skill"的回调使用。
105
+ */
106
+ replaceTriggerWithChip: (data: ChipData) => void;
107
+ /** 主动取消当前触发态(不修改 DOM,只清状态 + 抛 onTriggerChange(null))。 */
108
+ cancelTrigger: () => void;
109
+ /** 取最新的 trigger rect,便于浮层在滚动 / resize 时刷新位置。 */
110
+ getTriggerRect: () => DOMRect | null;
111
+ /**
112
+ * 取当前编辑器内全部 chip 的快照(按 DOM 出现顺序)。
113
+ * 父组件 onSend 时用,避免自行 parse value marker。
114
+ */
115
+ getChips: () => ChipData[];
116
+ /** 底层 contenteditable 元素 */
117
+ nativeElement: HTMLDivElement | null;
118
+ }
119
+ export declare const ComposerEditor: import("react").ForwardRefExoticComponent<ComposerEditorProps & import("react").RefAttributes<ComposerEditorRef>>;
120
+ export default ComposerEditor;