one-design-next 0.0.86 → 0.0.88

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,10 +1,12 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type ChatItemProps } from '../chat-item';
3
3
  import './style';
4
- /** 按会话时间筛选:全部 / 今天 / 近 7 天 / 近 30 天。 */
4
+ /** 按会话时间筛选(面板不含时间组;`filterTime` 仅受控 API)。 */
5
5
  export type ChatListFilterTime = 'all' | 'today' | '7d' | '30d';
6
- /** 按会话类型筛选:全部 / AI / 人工客服。 */
6
+ /** 按会话类型筛选:全部 / AI 任务 / 人工客服。 */
7
7
  export type ChatListFilterType = 'all' | 'ai' | 'human';
8
+ /** 按会话状态筛选:全部 / 生成中 / 待回复 / 未读 / 任务报错。 */
9
+ export type ChatListFilterStatus = 'all' | 'generating' | 'waiting' | 'unread' | 'error';
8
10
  export type ChatListItem = Pick<ChatItemProps, 'id' | 'title' | 'active' | 'type' | 'status' | 'pinned' | 'time'>;
9
11
  export interface ChatListProps {
10
12
  items: ChatListItem[];
@@ -20,7 +22,7 @@ export interface ChatListProps {
20
22
  */
21
23
  recentSectionTitle?: ReactNode | null;
22
24
  /**
23
- * 受控:时间筛选。`'all'` | `'today'` | `'7d'` | `'30d'`。
25
+ * 受控:时间筛选。筛选面板不含时间组,仅 API 可用。
24
26
  */
25
27
  filterTime?: ChatListFilterTime;
26
28
  /** 非受控:初始时间筛选。默认 `'all'`。 */
@@ -33,6 +35,13 @@ export interface ChatListProps {
33
35
  /** 非受控:初始类型筛选。默认 `'all'`。 */
34
36
  defaultFilterType?: ChatListFilterType;
35
37
  onFilterTypeChange?: (value: ChatListFilterType) => void;
38
+ /**
39
+ * 受控:状态筛选。`'all'` | `'generating'` | `'waiting'` | `'unread'` | `'error'`。
40
+ */
41
+ filterStatus?: ChatListFilterStatus;
42
+ /** 非受控:初始状态筛选。默认 `'all'`。 */
43
+ defaultFilterStatus?: ChatListFilterStatus;
44
+ onFilterStatusChange?: (value: ChatListFilterStatus) => void;
36
45
  /** 受控:筛选选择器是否展开 */
37
46
  filterOpen?: boolean;
38
47
  defaultFilterOpen?: boolean;
@@ -59,7 +68,9 @@ export interface ChatListProps {
59
68
  export declare function matchChatListFilterTime(time: ChatListItem['time'], filter: ChatListFilterTime, now?: number): boolean;
60
69
  /** 按类型筛选项判断会话是否命中。缺省 `type` 视为 `'ai'`。 */
61
70
  export declare function matchChatListFilterType(type: ChatListItem['type'], filter: ChatListFilterType): boolean;
62
- export declare function ChatList({ items, title, pinnedSectionTitle, recentSectionTitle, filterTime: filterTimeProp, defaultFilterTime, onFilterTimeChange, filterType: filterTypeProp, defaultFilterType, onFilterTypeChange, filterOpen: filterOpenProp, defaultFilterOpen, onFilterOpenChange, empty, actionMenuZIndex, filterMenuZIndex, className, onItemClick, onRename, onPin, onDelete, renderItem, renderRestScroll, }: ChatListProps): import("react").JSX.Element;
71
+ /** 按状态筛选项判断会话是否命中。无 `status` 时仅在「全部」下保留。 */
72
+ export declare function matchChatListFilterStatus(status: ChatListItem['status'], filter: ChatListFilterStatus): boolean;
73
+ export declare function ChatList({ items, title, pinnedSectionTitle, recentSectionTitle, filterTime: filterTimeProp, defaultFilterTime, filterType: filterTypeProp, defaultFilterType, onFilterTypeChange, filterStatus: filterStatusProp, defaultFilterStatus, onFilterStatusChange, filterOpen: filterOpenProp, defaultFilterOpen, onFilterOpenChange, empty, actionMenuZIndex, filterMenuZIndex, className, onItemClick, onRename, onPin, onDelete, renderItem, renderRestScroll, }: ChatListProps): import("react").JSX.Element;
63
74
  export declare namespace ChatList {
64
75
  var displayName: string;
65
76
  }
@@ -6,32 +6,37 @@ import Dropdown from "../dropdown";
6
6
  import Icon from "../icon";
7
7
  import "./style";
8
8
 
9
- /** 按会话时间筛选:全部 / 今天 / 近 7 天 / 近 30 天。 */
9
+ /** 按会话时间筛选(面板不含时间组;`filterTime` 仅受控 API)。 */
10
10
 
11
- /** 按会话类型筛选:全部 / AI / 人工客服。 */
11
+ /** 按会话类型筛选:全部 / AI 任务 / 人工客服。 */
12
12
 
13
- var TIME_OPTIONS = [{
13
+ /** 按会话状态筛选:全部 / 生成中 / 待回复 / 未读 / 任务报错。 */
14
+
15
+ var TYPE_OPTIONS = [{
14
16
  value: 'all',
15
17
  label: '全部'
16
18
  }, {
17
- value: 'today',
18
- label: '今天'
19
- }, {
20
- value: '7d',
21
- label: '近 7 天'
19
+ value: 'ai',
20
+ label: 'AI 任务'
22
21
  }, {
23
- value: '30d',
24
- label: '近 30 天'
22
+ value: 'human',
23
+ label: '人工客服'
25
24
  }];
26
- var TYPE_OPTIONS = [{
25
+ var STATUS_OPTIONS = [{
27
26
  value: 'all',
28
27
  label: '全部'
29
28
  }, {
30
- value: 'ai',
31
- label: 'AI 对话'
29
+ value: 'generating',
30
+ label: '生成中'
32
31
  }, {
33
- value: 'human',
34
- label: '人工客服'
32
+ value: 'waiting',
33
+ label: '待回复'
34
+ }, {
35
+ value: 'unread',
36
+ label: '未读'
37
+ }, {
38
+ value: 'error',
39
+ label: '任务报错'
35
40
  }];
36
41
  function parseItemTime(time) {
37
42
  if (time === null || time === undefined) return null;
@@ -62,6 +67,12 @@ export function matchChatListFilterType(type, filter) {
62
67
  if (filter === 'all') return true;
63
68
  return (type !== null && type !== void 0 ? type : 'ai') === filter;
64
69
  }
70
+
71
+ /** 按状态筛选项判断会话是否命中。无 `status` 时仅在「全部」下保留。 */
72
+ export function matchChatListFilterStatus(status, filter) {
73
+ if (filter === 'all') return true;
74
+ return status === filter;
75
+ }
65
76
  function useControllable(controlled, defaultValue, onChange) {
66
77
  var _useState = useState(defaultValue),
67
78
  _useState2 = _slicedToArray(_useState, 2),
@@ -84,33 +95,33 @@ function filterOptionLabel(label, selected) {
84
95
  "data-odn-chat-list-filter-option-label": true
85
96
  }, label), selected ? /*#__PURE__*/React.createElement(Icon, {
86
97
  name: "check",
87
- size: 14,
98
+ size: 12,
88
99
  "data-odn-chat-list-filter-option-check": true
89
100
  }) : null);
90
101
  }
91
- function buildFilterMenu(filterTime, filterType) {
102
+ function buildFilterMenu(filterType, filterStatus) {
92
103
  return [{
93
104
  type: 'label',
94
- label: '时间'
105
+ label: '类型'
95
106
  }, {
96
107
  type: 'group',
97
- children: TIME_OPTIONS.map(function (opt) {
108
+ children: TYPE_OPTIONS.map(function (opt) {
98
109
  return {
99
- value: "time:".concat(opt.value),
100
- label: filterOptionLabel(opt.label, filterTime === opt.value)
110
+ value: "type:".concat(opt.value),
111
+ label: filterOptionLabel(opt.label, filterType === opt.value)
101
112
  };
102
113
  })
103
114
  }, {
104
115
  type: 'separator'
105
116
  }, {
106
117
  type: 'label',
107
- label: '类型'
118
+ label: '状态'
108
119
  }, {
109
120
  type: 'group',
110
- children: TYPE_OPTIONS.map(function (opt) {
121
+ children: STATUS_OPTIONS.map(function (opt) {
111
122
  return {
112
- value: "type:".concat(opt.value),
113
- label: filterOptionLabel(opt.label, filterType === opt.value)
123
+ value: "status:".concat(opt.value),
124
+ label: filterOptionLabel(opt.label, filterStatus === opt.value)
114
125
  };
115
126
  })
116
127
  }];
@@ -126,11 +137,14 @@ export function ChatList(_ref) {
126
137
  filterTimeProp = _ref.filterTime,
127
138
  _ref$defaultFilterTim = _ref.defaultFilterTime,
128
139
  defaultFilterTime = _ref$defaultFilterTim === void 0 ? 'all' : _ref$defaultFilterTim,
129
- onFilterTimeChange = _ref.onFilterTimeChange,
130
140
  filterTypeProp = _ref.filterType,
131
141
  _ref$defaultFilterTyp = _ref.defaultFilterType,
132
142
  defaultFilterType = _ref$defaultFilterTyp === void 0 ? 'all' : _ref$defaultFilterTyp,
133
143
  onFilterTypeChange = _ref.onFilterTypeChange,
144
+ filterStatusProp = _ref.filterStatus,
145
+ _ref$defaultFilterSta = _ref.defaultFilterStatus,
146
+ defaultFilterStatus = _ref$defaultFilterSta === void 0 ? 'all' : _ref$defaultFilterSta,
147
+ onFilterStatusChange = _ref.onFilterStatusChange,
134
148
  filterOpenProp = _ref.filterOpen,
135
149
  _ref$defaultFilterOpe = _ref.defaultFilterOpen,
136
150
  defaultFilterOpen = _ref$defaultFilterOpe === void 0 ? false : _ref$defaultFilterOpe,
@@ -146,23 +160,24 @@ export function ChatList(_ref) {
146
160
  _ref$renderItem = _ref.renderItem,
147
161
  renderItem = _ref$renderItem === void 0 ? defaultRenderItem : _ref$renderItem,
148
162
  renderRestScroll = _ref.renderRestScroll;
149
- var _useControllable = useControllable(filterTimeProp, defaultFilterTime, onFilterTimeChange),
163
+ var filterTime = filterTimeProp !== null && filterTimeProp !== void 0 ? filterTimeProp : defaultFilterTime;
164
+ var _useControllable = useControllable(filterTypeProp, defaultFilterType, onFilterTypeChange),
150
165
  _useControllable2 = _slicedToArray(_useControllable, 2),
151
- filterTime = _useControllable2[0],
152
- setFilterTime = _useControllable2[1];
153
- var _useControllable3 = useControllable(filterTypeProp, defaultFilterType, onFilterTypeChange),
166
+ filterType = _useControllable2[0],
167
+ setFilterType = _useControllable2[1];
168
+ var _useControllable3 = useControllable(filterStatusProp, defaultFilterStatus, onFilterStatusChange),
154
169
  _useControllable4 = _slicedToArray(_useControllable3, 2),
155
- filterType = _useControllable4[0],
156
- setFilterType = _useControllable4[1];
170
+ filterStatus = _useControllable4[0],
171
+ setFilterStatus = _useControllable4[1];
157
172
  var _useControllable5 = useControllable(filterOpenProp, defaultFilterOpen, onFilterOpenChange),
158
173
  _useControllable6 = _slicedToArray(_useControllable5, 2),
159
174
  filterOpen = _useControllable6[0],
160
175
  setFilterOpen = _useControllable6[1];
161
176
  var filteredItems = useMemo(function () {
162
177
  return items.filter(function (item) {
163
- return matchChatListFilterTime(item.time, filterTime) && matchChatListFilterType(item.type, filterType);
178
+ return matchChatListFilterTime(item.time, filterTime) && matchChatListFilterType(item.type, filterType) && matchChatListFilterStatus(item.status, filterStatus);
164
179
  });
165
- }, [items, filterTime, filterType]);
180
+ }, [items, filterTime, filterType, filterStatus]);
166
181
  var pinnedItems = useMemo(function () {
167
182
  return filteredItems.filter(function (item) {
168
183
  return item.pinned;
@@ -174,8 +189,8 @@ export function ChatList(_ref) {
174
189
  });
175
190
  }, [filteredItems]);
176
191
  var filterMenu = useMemo(function () {
177
- return buildFilterMenu(filterTime, filterType);
178
- }, [filterTime, filterType]);
192
+ return buildFilterMenu(filterType, filterStatus);
193
+ }, [filterType, filterStatus]);
179
194
  var renderChatItem = function renderChatItem(item) {
180
195
  var node = /*#__PURE__*/React.createElement(ChatItem, {
181
196
  key: item.id,
@@ -229,13 +244,13 @@ export function ChatList(_ref) {
229
244
  onVisibleChange: setFilterOpen,
230
245
  menu: filterMenu,
231
246
  onSelect: function onSelect(value) {
232
- if (value.startsWith('time:')) {
233
- setFilterTime(value.slice(5));
247
+ if (value.startsWith('type:')) {
248
+ setFilterType(value.slice(5));
234
249
  setFilterOpen(false);
235
250
  return;
236
251
  }
237
- if (value.startsWith('type:')) {
238
- setFilterType(value.slice(5));
252
+ if (value.startsWith('status:')) {
253
+ setFilterStatus(value.slice(7));
239
254
  setFilterOpen(false);
240
255
  }
241
256
  }
@@ -15,8 +15,8 @@
15
15
  gap: 8px;
16
16
  min-height: 32px;
17
17
  min-width: 0;
18
- /* ChatItem / 分区标题左缘统一 12px */
19
- padding: 0 12px;
18
+ /* 左缘与 ChatItem / 分区标题 12px 对齐;右侧贴齐,筛选项不再多 12px */
19
+ padding: 0 4px 0 12px;
20
20
  background: transparent;
21
21
  }
22
22
 
@@ -90,9 +90,38 @@
90
90
  color: var(--odn-color-black-8);
91
91
  }
92
92
 
93
+ [data-odn-dropdown-content].odn-chat-list-filter-menu {
94
+ /* 比默认 Dropdown 小一号:对齐 popup 字号 + Select small 行高 */
95
+ --odn-font-size: var(--odn-popup-font-size);
96
+ --odn-line-height: var(--odn-popup-line-height);
97
+ --odn-popup-control-height: 28px;
98
+ }
99
+ [data-odn-dropdown-content].odn-chat-list-filter-menu [data-odn-dropdown-label] {
100
+ height: auto;
101
+ padding: 0 12px 2px;
102
+ }
103
+ [data-odn-dropdown-content].odn-chat-list-filter-menu {
104
+ /* hover 不通栏:左右各缩 4px,圆角 4px;padding 8px 使文案仍落在 12px */
105
+ }
106
+ [data-odn-dropdown-content].odn-chat-list-filter-menu [data-odn-dropdown-item] {
107
+ margin: 0 4px;
108
+ padding-inline: 8px;
109
+ border-radius: 4px;
110
+ }
93
111
  [data-odn-dropdown-content].odn-chat-list-filter-menu [data-odn-dropdown-item-label] {
94
112
  overflow: visible;
95
113
  }
114
+ [data-odn-dropdown-content].odn-chat-list-filter-menu {
115
+ /* 组间线:上下各 8px padding,线画在 content-box,左右内缩 */
116
+ }
117
+ [data-odn-dropdown-content].odn-chat-list-filter-menu [data-odn-dropdown-separator] {
118
+ box-sizing: content-box;
119
+ height: 1px;
120
+ margin: 0 12px;
121
+ padding: 8px 0;
122
+ background-color: var(--odn-color-black-5);
123
+ background-clip: content-box;
124
+ }
96
125
 
97
126
  [data-odn-chat-list-body] {
98
127
  display: flex;
@@ -30,6 +30,8 @@ export interface ComposerEditorTriggerInfo {
30
30
  */
31
31
  rect: DOMRect;
32
32
  }
33
+ /** 编辑器 10 行真实高度,缩放按钮在内容达到此高度后隐藏。 */
34
+ export declare const COMPOSER_EDITOR_MAX_ROWS_PX: number;
33
35
  export interface ComposerEditorAutoSize {
34
36
  minRows?: number;
35
37
  maxRows?: number;
@@ -79,7 +81,8 @@ export interface ComposerEditorProps {
79
81
  onTriggerKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => boolean | void;
80
82
  /**
81
83
  * 编辑器可视高度变化回调。
82
- * height = editor.offsetHeight(受 max-height clamp);atMax 表示触顶。
84
+ * height = 内容自然高度(scrollHeight,未 clamp);atMax 表示已超过 10 行
85
+ * 真实高度。若整框被 50vh 挤矮,则以盒内分给编辑器的剩余高度为准。
83
86
  * Composer 的 lite 升格逻辑、scrollbar 显隐都用这个。
84
87
  */
85
88
  onHeightChange?: (height: number, atMax: boolean) => void;
@@ -77,7 +77,14 @@ var scrollCaretIntoView = function scrollCaretIntoView(viewport) {
77
77
  }
78
78
  };
79
79
  var LINE_HEIGHT = 24;
80
- var PADDING_Y = 4;
80
+ /** SCSS `padding: 2px … 0` 对齐。10 行 = 10 * 24 + 2 = 242px。 */
81
+ var EDITOR_PADDING_BLOCK = 2;
82
+ var contentHeightForRows = function contentHeightForRows(rows) {
83
+ return rows * LINE_HEIGHT + EDITOR_PADDING_BLOCK;
84
+ };
85
+
86
+ /** 编辑器 10 行真实高度,缩放按钮在内容达到此高度后隐藏。 */
87
+ export var COMPOSER_EDITOR_MAX_ROWS_PX = contentHeightForRows(10);
81
88
  export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref, ref) {
82
89
  var _autoSize$minRows;
83
90
  var valueProp = _ref.value,
@@ -110,11 +117,15 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
110
117
  return (_scrollRef$current$vi = (_scrollRef$current = scrollRef.current) === null || _scrollRef$current === void 0 ? void 0 : _scrollRef$current.viewport) !== null && _scrollRef$current$vi !== void 0 ? _scrollRef$current$vi : null;
111
118
  }, []);
112
119
  var isComposingRef = useRef(false);
120
+ var onTriggerChangeRef = useRef(onTriggerChange);
121
+ onTriggerChangeRef.current = onTriggerChange;
113
122
  var isControlled = valueProp !== undefined;
114
123
  var minRows = (_autoSize$minRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.minRows) !== null && _autoSize$minRows !== void 0 ? _autoSize$minRows : 1;
115
124
  var maxRows = autoSize === null || autoSize === void 0 ? void 0 : autoSize.maxRows;
116
- var minHeightPx = minRows * LINE_HEIGHT + PADDING_Y * 2;
117
- var maxHeightPx = maxRows !== undefined ? maxRows * LINE_HEIGHT + PADDING_Y * 2 : undefined;
125
+ var minHeightPx = contentHeightForRows(minRows);
126
+ var rowContentPx = maxRows !== undefined ? contentHeightForRows(maxRows) : undefined;
127
+ /** 仅 10 行封顶(242px);50vh 由外层 box 负责。 */
128
+ var maxHeightPx = rowContentPx;
118
129
 
119
130
  /** 当前活动 trigger probe;null 表示无触发态。 */
120
131
  var triggerRef = useRef(null);
@@ -179,17 +190,22 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
179
190
  * 主动调 syncHeight(确保升格判定能拿到 scrollHeight)。
180
191
  * ───────────────────────────────────── */
181
192
  var syncHeight = useCallback(function () {
182
- var _onHeightChangeRef$cu;
193
+ var _getViewport, _box$getBoundingClien, _onHeightChangeRef$cu;
183
194
  var el = editorRef.current;
184
195
  if (!el) return;
185
196
  var natural = Math.ceil(el.scrollHeight);
186
197
  var clamped = Math.max(minHeightPx, maxHeightPx !== undefined ? Math.min(natural, maxHeightPx) : natural);
187
- var overflow = maxHeightPx !== undefined && natural > maxHeightPx + 1;
198
+ var allocated = (_getViewport = getViewport()) === null || _getViewport === void 0 ? void 0 : _getViewport.clientHeight;
199
+ var box = el.closest('[data-odn-composer-box]');
200
+ var boxH = (_box$getBoundingClien = box === null || box === void 0 ? void 0 : box.getBoundingClientRect().height) !== null && _box$getBoundingClien !== void 0 ? _box$getBoundingClien : 0;
201
+ var vhCap = typeof window === 'undefined' ? Number.POSITIVE_INFINITY : window.innerHeight * 0.5;
202
+ var boxAtVhCap = boxH > 0 && boxH >= vhCap - 2;
203
+ var overflow = boxAtVhCap ? allocated !== undefined && allocated > 0 && natural > allocated + 1 : rowContentPx !== undefined && natural > rowContentPx + 1;
188
204
  setScrollHeight(function (prev) {
189
205
  return prev === clamped ? prev : clamped;
190
206
  });
191
207
  (_onHeightChangeRef$cu = onHeightChangeRef.current) === null || _onHeightChangeRef$cu === void 0 || _onHeightChangeRef$cu.call(onHeightChangeRef, natural, overflow);
192
- }, [minHeightPx, maxHeightPx]);
208
+ }, [getViewport, minHeightPx, maxHeightPx, rowContentPx]);
193
209
  var shouldShowPlaceholder = useCallback(function (el) {
194
210
  if (!isEditorEmpty(el)) return false;
195
211
  // placeholder 仅在「单行且空内容」展示。
@@ -472,10 +488,12 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
472
488
  syncHeight();
473
489
  var ro = new ResizeObserver(syncHeight);
474
490
  ro.observe(el);
491
+ var vp = getViewport();
492
+ if (vp) ro.observe(vp);
475
493
  return function () {
476
494
  return ro.disconnect();
477
495
  };
478
- }, [syncHeight]);
496
+ }, [getViewport, syncHeight]);
479
497
 
480
498
  /* ─────────────────────────────────────
481
499
  * 受控同步:仅在外部 value 变化,或输入后延迟校验 tick 变化时校验 DOM。
@@ -518,12 +536,13 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
518
536
  resetChips();
519
537
  setEmpty(shouldShowPlaceholder(el));
520
538
  if (triggerRef.current) {
539
+ var _onTriggerChangeRef$c;
521
540
  triggerRef.current = null;
522
- onTriggerChange === null || onTriggerChange === void 0 || onTriggerChange(null);
541
+ (_onTriggerChangeRef$c = onTriggerChangeRef.current) === null || _onTriggerChangeRef$c === void 0 || _onTriggerChangeRef$c.call(onTriggerChangeRef, null);
523
542
  }
524
543
  syncHeight();
525
544
  }
526
- }, [controlledSyncTick, valueProp, isControlled, resetChips, onTriggerChange, shouldShowPlaceholder, syncHeight]);
545
+ }, [controlledSyncTick, valueProp, isControlled, resetChips, shouldShowPlaceholder, syncHeight]);
527
546
 
528
547
  /* ─────────────────────────────────────
529
548
  * 输入事件