@unif/react-native-chat 3.7.0 → 4.0.0

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.
Files changed (78) hide show
  1. package/lib/module/components/Attachments/AttachmentItem.js +13 -12
  2. package/lib/module/components/Attachments/AttachmentItem.js.map +1 -1
  3. package/lib/module/components/Attachments/constants.js +5 -4
  4. package/lib/module/components/Attachments/constants.js.map +1 -1
  5. package/lib/module/components/Composer/Composer.js +6 -5
  6. package/lib/module/components/Composer/Composer.js.map +1 -1
  7. package/lib/module/components/Composer/ComposerIconAction.js +3 -3
  8. package/lib/module/components/Composer/ComposerIconAction.js.map +1 -1
  9. package/lib/module/components/Confirmation/Confirmation.js +4 -3
  10. package/lib/module/components/Confirmation/Confirmation.js.map +1 -1
  11. package/lib/module/components/Feedback/Feedback.js +4 -3
  12. package/lib/module/components/Feedback/Feedback.js.map +1 -1
  13. package/lib/module/components/Feedback/constants.js +5 -4
  14. package/lib/module/components/Feedback/constants.js.map +1 -1
  15. package/lib/module/components/Message/MarkdownContent/MarkdownImage/MarkdownImage.js +6 -3
  16. package/lib/module/components/Message/MarkdownContent/MarkdownImage/MarkdownImage.js.map +1 -1
  17. package/lib/module/components/Message/Message.js +2 -1
  18. package/lib/module/components/Message/Message.js.map +1 -1
  19. package/lib/module/components/MessageList/MessageListEndButton.js +2 -1
  20. package/lib/module/components/MessageList/MessageListEndButton.js.map +1 -1
  21. package/lib/module/components/Process/Process.js +4 -3
  22. package/lib/module/components/Process/Process.js.map +1 -1
  23. package/lib/module/components/Process/ProcessCompactStep.js +11 -10
  24. package/lib/module/components/Process/ProcessCompactStep.js.map +1 -1
  25. package/lib/module/components/Process/ProcessTimelineStep.js +3 -3
  26. package/lib/module/components/Process/ProcessTimelineStep.js.map +1 -1
  27. package/lib/module/components/Process/constants.js +6 -5
  28. package/lib/module/components/Process/constants.js.map +1 -1
  29. package/lib/module/components/Sources/Sources.js +6 -3
  30. package/lib/module/components/Sources/Sources.js.map +1 -1
  31. package/lib/module/components/Suggestions/Suggestions.js +2 -3
  32. package/lib/module/components/Suggestions/Suggestions.js.map +1 -1
  33. package/lib/typescript/src/actions/types.d.ts +3 -2
  34. package/lib/typescript/src/actions/types.d.ts.map +1 -1
  35. package/lib/typescript/src/components/Attachments/AttachmentItem.d.ts.map +1 -1
  36. package/lib/typescript/src/components/Attachments/constants.d.ts +3 -2
  37. package/lib/typescript/src/components/Attachments/constants.d.ts.map +1 -1
  38. package/lib/typescript/src/components/Composer/Composer.d.ts.map +1 -1
  39. package/lib/typescript/src/components/Composer/types.d.ts +4 -2
  40. package/lib/typescript/src/components/Composer/types.d.ts.map +1 -1
  41. package/lib/typescript/src/components/Confirmation/Confirmation.d.ts.map +1 -1
  42. package/lib/typescript/src/components/Feedback/Feedback.d.ts.map +1 -1
  43. package/lib/typescript/src/components/Feedback/constants.d.ts +3 -2
  44. package/lib/typescript/src/components/Feedback/constants.d.ts.map +1 -1
  45. package/lib/typescript/src/components/Message/MarkdownContent/MarkdownImage/MarkdownImage.d.ts.map +1 -1
  46. package/lib/typescript/src/components/Message/Message.d.ts.map +1 -1
  47. package/lib/typescript/src/components/MessageList/MessageListEndButton.d.ts.map +1 -1
  48. package/lib/typescript/src/components/Process/Process.d.ts.map +1 -1
  49. package/lib/typescript/src/components/Process/ProcessCompactStep.d.ts.map +1 -1
  50. package/lib/typescript/src/components/Process/constants.d.ts +3 -2
  51. package/lib/typescript/src/components/Process/constants.d.ts.map +1 -1
  52. package/lib/typescript/src/components/Process/types.d.ts +4 -0
  53. package/lib/typescript/src/components/Process/types.d.ts.map +1 -1
  54. package/lib/typescript/src/components/Sources/Sources.d.ts.map +1 -1
  55. package/lib/typescript/src/components/Suggestions/Suggestions.d.ts.map +1 -1
  56. package/lib/typescript/src/components/Suggestions/types.d.ts +3 -2
  57. package/lib/typescript/src/components/Suggestions/types.d.ts.map +1 -1
  58. package/package.json +5 -3
  59. package/src/actions/types.ts +3 -2
  60. package/src/components/Attachments/AttachmentItem.tsx +14 -20
  61. package/src/components/Attachments/constants.ts +14 -6
  62. package/src/components/Composer/Composer.tsx +14 -5
  63. package/src/components/Composer/ComposerIconAction.tsx +3 -3
  64. package/src/components/Composer/types.ts +4 -2
  65. package/src/components/Confirmation/Confirmation.tsx +12 -12
  66. package/src/components/Feedback/Feedback.tsx +3 -2
  67. package/src/components/Feedback/constants.ts +16 -6
  68. package/src/components/Message/MarkdownContent/MarkdownImage/MarkdownImage.tsx +4 -2
  69. package/src/components/Message/Message.tsx +2 -1
  70. package/src/components/MessageList/MessageListEndButton.tsx +2 -1
  71. package/src/components/Process/Process.tsx +4 -3
  72. package/src/components/Process/ProcessCompactStep.tsx +26 -20
  73. package/src/components/Process/ProcessTimelineStep.tsx +2 -2
  74. package/src/components/Process/constants.ts +16 -7
  75. package/src/components/Process/types.ts +5 -0
  76. package/src/components/Sources/Sources.tsx +6 -2
  77. package/src/components/Suggestions/Suggestions.tsx +2 -6
  78. package/src/components/Suggestions/types.ts +4 -2
@@ -1,9 +1,10 @@
1
- import type { IconName } from '@unif/react-native-design';
1
+ import type { ComponentType } from 'react';
2
+ import type { IconProps } from '@unif/react-native-icons';
2
3
 
3
4
  export interface ChatAction {
4
5
  id: string;
5
6
  label: string;
6
- icon?: IconName;
7
+ icon?: ComponentType<IconProps>;
7
8
  disabled?: boolean;
8
9
  loading?: boolean;
9
10
  accessibilityHint?: string;
@@ -1,9 +1,13 @@
1
+ import {
2
+ CloseOutlined,
3
+ EyeOutlined,
4
+ RefreshOutlined,
5
+ } from '@unif/react-native-icons';
1
6
  import { Pressable, Text, View } from 'react-native';
2
7
  import {
3
8
  Button,
4
9
  CircularProgress,
5
10
  GlassLayer,
6
- Icon,
7
11
  IconButton,
8
12
  radius,
9
13
  Spinner,
@@ -55,12 +59,7 @@ export function AttachmentItem({
55
59
  const removable = item.removable && onRemove;
56
60
  const singleAction = item.actions?.length === 1 ? item.actions[0] : undefined;
57
61
  const retry =
58
- failed &&
59
- !caption &&
60
- singleAction &&
61
- (singleAction.id === 'retry' ||
62
- singleAction.icon === 'retry' ||
63
- singleAction.icon === 'refresh')
62
+ failed && !caption && singleAction?.id === 'retry'
64
63
  ? singleAction
65
64
  : undefined;
66
65
  const statusLeft = (imageSize - ATTACHMENT_STATUS_OWNER_SIZE) / 2;
@@ -73,9 +72,8 @@ export function AttachmentItem({
73
72
  ATTACHMENT_STATUS_OWNER_SIZE
74
73
  )
75
74
  : statusLeft;
76
- const icon = (
77
- <Icon name={ATTACHMENT_ICONS[item.kind ?? 'file']} size={ROW_IMAGE_SIZE} />
78
- );
75
+ const Glyph = ATTACHMENT_ICONS[item.kind ?? 'file'];
76
+ const icon = <Glyph size={ROW_IMAGE_SIZE} color={colors.foregroundMuted} />;
79
77
  const thumbnail = item.thumbnail ? (
80
78
  <Thumbnail
81
79
  source={item.thumbnail}
@@ -91,16 +89,13 @@ export function AttachmentItem({
91
89
  {icon}
92
90
  </View>
93
91
  );
92
+ const Glyph2 = retry?.icon ?? RefreshOutlined;
94
93
  const statusVisual =
95
94
  busy || failed ? (
96
95
  <View style={styles.statusVisual}>
97
96
  <GlassLayer colorScheme="dark" style={styles.circleGlass} />
98
97
  {failed ? (
99
- <Icon
100
- name={retry?.icon ?? 'refresh'}
101
- size={16}
102
- color={colors.onPrimary}
103
- />
98
+ <Glyph2 size={16} color={colors.onPrimary} />
104
99
  ) : progress !== undefined ? (
105
100
  <CircularProgress
106
101
  value={progress}
@@ -225,7 +220,7 @@ export function AttachmentItem({
225
220
  <View style={styles.actions}>
226
221
  {previewable && retry ? (
227
222
  <IconButton
228
- icon="eye"
223
+ icon={EyeOutlined}
229
224
  size="sm"
230
225
  accessibilityLabel={`预览${name}`}
231
226
  onPress={() => onPreview?.(item)}
@@ -233,7 +228,7 @@ export function AttachmentItem({
233
228
  ) : null}
234
229
  {removable ? (
235
230
  <IconButton
236
- icon="close"
231
+ icon={CloseOutlined}
237
232
  size="sm"
238
233
  accessibilityLabel={`移除${name}`}
239
234
  disabled={item.removeDisabled}
@@ -332,8 +327,7 @@ export function AttachmentItem({
332
327
  {!failed ? (
333
328
  <GlassLayer colorScheme="dark" style={styles.circleGlass} />
334
329
  ) : null}
335
- <Icon
336
- name="close"
330
+ <CloseOutlined
337
331
  size={preview ? 12 : 10}
338
332
  color={colors.onPrimary}
339
333
  strokeWidth={2.5}
@@ -363,7 +357,7 @@ export function AttachmentItem({
363
357
  {separatePreview ? (
364
358
  <View style={[styles.previewAction, { width: imageSize }]}>
365
359
  <IconButton
366
- icon="eye"
360
+ icon={EyeOutlined}
367
361
  size="sm"
368
362
  accessibilityLabel={`预览${name}`}
369
363
  onPress={() => onPreview?.(item)}
@@ -1,5 +1,13 @@
1
+ import {
2
+ FileOutlined,
3
+ ImageOutlined,
4
+ PlayOutlined,
5
+ SoundOutlined,
6
+ } from '@unif/react-native-icons';
7
+ import type { ComponentType } from 'react';
8
+ import type { IconProps } from '@unif/react-native-icons';
1
9
  import { icon, r } from '@unif/react-native-design';
2
- import type { IconName } from '@unif/react-native-design';
10
+
3
11
  import type { ChatAttachmentItem } from './types';
4
12
 
5
13
  export const CARD_WIDTH = r(76);
@@ -15,12 +23,12 @@ export const ATTACHMENT_STATUS_OWNER_SIZE = Math.max(
15
23
  export const ATTACHMENT_REMOVE_OWNER_SIZE = 44;
16
24
  export const ATTACHMENT_ICONS: Record<
17
25
  NonNullable<ChatAttachmentItem['kind']>,
18
- IconName
26
+ ComponentType<IconProps>
19
27
  > = {
20
- image: 'image',
21
- file: 'file',
22
- audio: 'sound',
23
- video: 'play',
28
+ image: ImageOutlined,
29
+ file: FileOutlined,
30
+ audio: SoundOutlined,
31
+ video: PlayOutlined,
24
32
  };
25
33
  export const STATUS_LABELS = {
26
34
  idle: '',
@@ -1,3 +1,10 @@
1
+ import {
2
+ CloseOutlined,
3
+ MicOutlined,
4
+ PlusOutlined,
5
+ SendOutlined,
6
+ StopFilled,
7
+ } from '@unif/react-native-icons';
1
8
  import {
2
9
  forwardRef,
3
10
  useEffect,
@@ -119,7 +126,7 @@ export const Composer = forwardRef<ComposerHandle, ComposerProps>(
119
126
  const moreAction =
120
127
  actions.length > 0 ? (
121
128
  <ComposerIconAction
122
- icon="plus"
129
+ icon={PlusOutlined}
123
130
  label="更多操作"
124
131
  expanded={menuOpen}
125
132
  disabled={moreDisabled}
@@ -243,7 +250,7 @@ export const Composer = forwardRef<ComposerHandle, ComposerProps>(
243
250
  <View style={styles.trailingActions}>
244
251
  {voice ? (
245
252
  <ComposerIconAction
246
- icon="mic"
253
+ icon={MicOutlined}
247
254
  label="开始语音输入"
248
255
  disabled={disabled || voice.disabled}
249
256
  onPress={() => {
@@ -254,7 +261,9 @@ export const Composer = forwardRef<ComposerHandle, ComposerProps>(
254
261
  ) : null}
255
262
  {showPrimary ? (
256
263
  <ComposerIconAction
257
- icon={primaryAction.kind === 'send' ? 'send' : 'stop'}
264
+ icon={
265
+ primaryAction.kind === 'send' ? SendOutlined : StopFilled
266
+ }
258
267
  label={primaryLabel}
259
268
  visual="primary"
260
269
  disabled={primaryDisabled}
@@ -276,7 +285,7 @@ export const Composer = forwardRef<ComposerHandle, ComposerProps>(
276
285
  {voice && voice.status !== 'idle' ? (
277
286
  <View style={styles.voice}>
278
287
  <ComposerIconAction
279
- icon="close"
288
+ icon={CloseOutlined}
280
289
  visual="cancel"
281
290
  label="取消语音输入"
282
291
  disabled={disabled || voice.disabled}
@@ -300,7 +309,7 @@ export const Composer = forwardRef<ComposerHandle, ComposerProps>(
300
309
  </View>
301
310
  {voice.status === 'listening' || voice.status === 'finishing' ? (
302
311
  <ComposerIconAction
303
- icon="stop"
312
+ icon={StopFilled}
304
313
  visual="primary"
305
314
  label="停止语音输入"
306
315
  disabled={
@@ -1,5 +1,5 @@
1
1
  import { ActivityIndicator, Pressable, View } from 'react-native';
2
- import { Icon, useColors, useThemedStyles } from '@unif/react-native-design';
2
+ import { useColors, useThemedStyles } from '@unif/react-native-design';
3
3
  import {
4
4
  COMPOSER_ACTION_ICON_SIZE,
5
5
  COMPOSER_PRIMARY_ICON_SIZE,
@@ -28,6 +28,7 @@ export function ComposerIconAction({
28
28
  ? colors.foregroundSubtle
29
29
  : colors.onPrimary
30
30
  : colors.foregroundMuted;
31
+ const Glyph = icon;
31
32
  return (
32
33
  <Pressable
33
34
  accessibilityRole="button"
@@ -54,8 +55,7 @@ export function ComposerIconAction({
54
55
  {busy ? (
55
56
  <ActivityIndicator size="small" color={color} />
56
57
  ) : (
57
- <Icon
58
- name={icon}
58
+ <Glyph
59
59
  size={
60
60
  primary
61
61
  ? COMPOSER_PRIMARY_ICON_SIZE
@@ -1,6 +1,8 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { IconProps } from '@unif/react-native-icons';
1
3
  import type { ReactNode } from 'react';
2
4
  import type { StyleProp, ViewStyle } from 'react-native';
3
- import type { IconName, TextFieldHandle } from '@unif/react-native-design';
5
+ import type { TextFieldHandle } from '@unif/react-native-design';
4
6
  import type { ChatAction } from '../../actions';
5
7
 
6
8
  export interface ComposerSendAction {
@@ -65,7 +67,7 @@ export interface ComposerProps {
65
67
  export type ComposerHandle = TextFieldHandle;
66
68
 
67
69
  export interface ComposerIconActionProps {
68
- icon: IconName;
70
+ icon: ComponentType<IconProps>;
69
71
  label: string;
70
72
  onPress?(): void;
71
73
  disabled?: boolean;
@@ -1,7 +1,11 @@
1
+ import {
2
+ CheckOutlined,
3
+ CloseOutlined,
4
+ WarningOutlined,
5
+ } from '@unif/react-native-icons';
1
6
  import { Text, View } from 'react-native';
2
7
  import {
3
8
  Button,
4
- Icon,
5
9
  Spinner,
6
10
  useColors,
7
11
  useThemedStyles,
@@ -44,23 +48,19 @@ export function Confirmation({
44
48
  ? statusText
45
49
  : (statusText ?? CONFIRMATION_STATUS_TEXT[status]);
46
50
 
51
+ const Glyph =
52
+ status === 'confirmed'
53
+ ? CheckOutlined
54
+ : status === 'cancelled'
55
+ ? CloseOutlined
56
+ : WarningOutlined;
47
57
  return (
48
58
  <View style={[styles.root, { borderColor }, style]} testID={testID}>
49
59
  <View style={styles.heading}>
50
60
  {status === 'processing' ? (
51
61
  <Spinner size={14} color={tint} />
52
62
  ) : (
53
- <Icon
54
- name={
55
- status === 'confirmed'
56
- ? 'check'
57
- : status === 'cancelled'
58
- ? 'close'
59
- : 'warning'
60
- }
61
- size={14}
62
- color={tint}
63
- />
63
+ <Glyph size={14} color={tint} />
64
64
  )}
65
65
  <Text
66
66
  style={[styles.title, status === 'cancelled' && styles.cancelled]}
@@ -1,7 +1,7 @@
1
1
  import { Text, View } from 'react-native';
2
2
  import {
3
3
  Button,
4
- Icon,
4
+ r,
5
5
  useColors,
6
6
  useThemedStyles,
7
7
  } from '@unif/react-native-design';
@@ -48,6 +48,7 @@ export function Feedback({
48
48
  const toneLabel = FEEDBACK_TONE_LABELS[tone];
49
49
  const accessibilityLabel = `${toneLabel}:${title ? `${title}。` : ''}${message}`;
50
50
 
51
+ const Glyph = FEEDBACK_TONE_ICONS[tone];
51
52
  return (
52
53
  <View
53
54
  style={[
@@ -57,7 +58,7 @@ export function Feedback({
57
58
  ]}
58
59
  testID={testID}
59
60
  >
60
- <Icon name={FEEDBACK_TONE_ICONS[tone]} color={toneColors.iconColor} />
61
+ <Glyph size={r(18)} color={toneColors.iconColor} />
61
62
  <View style={styles.content}>
62
63
  <View accessible accessibilityLabel={accessibilityLabel}>
63
64
  {title ? (
@@ -1,4 +1,12 @@
1
- import type { IconName } from '@unif/react-native-design';
1
+ import {
2
+ ErrorOutlined,
3
+ InfoOutlined,
4
+ SuccessOutlined,
5
+ WarningOutlined,
6
+ } from '@unif/react-native-icons';
7
+ import type { ComponentType } from 'react';
8
+ import type { IconProps } from '@unif/react-native-icons';
9
+
2
10
  import type { FeedbackTone } from './types';
3
11
 
4
12
  export const FEEDBACK_TONE_LABELS: Readonly<Record<FeedbackTone, string>> = {
@@ -8,9 +16,11 @@ export const FEEDBACK_TONE_LABELS: Readonly<Record<FeedbackTone, string>> = {
8
16
  error: '错误',
9
17
  };
10
18
 
11
- export const FEEDBACK_TONE_ICONS: Readonly<Record<FeedbackTone, IconName>> = {
12
- info: 'info',
13
- success: 'success',
14
- warning: 'warning',
15
- error: 'error',
19
+ export const FEEDBACK_TONE_ICONS: Readonly<
20
+ Record<FeedbackTone, ComponentType<IconProps>>
21
+ > = {
22
+ info: InfoOutlined,
23
+ success: SuccessOutlined,
24
+ warning: WarningOutlined,
25
+ error: ErrorOutlined,
16
26
  };
@@ -1,10 +1,12 @@
1
+ import { ImageOutlined } from '@unif/react-native-icons';
1
2
  import { useEffect, useState } from 'react';
2
3
  import { Image, View } from 'react-native';
3
- import { Icon, Thumbnail } from '@unif/react-native-design';
4
+ import { Thumbnail, r, useColors } from '@unif/react-native-design';
4
5
  import { styles } from './styles';
5
6
  import type { ImageRatio, MarkdownImageProps } from './types';
6
7
 
7
8
  export function MarkdownImage({ uri, label }: MarkdownImageProps) {
9
+ const colors = useColors();
8
10
  const [width, setWidth] = useState(1);
9
11
  const [ratio, setRatio] = useState<ImageRatio | undefined>(undefined);
10
12
  useEffect(() => {
@@ -44,7 +46,7 @@ export function MarkdownImage({ uri, label }: MarkdownImageProps) {
44
46
  borderRadius: 0,
45
47
  }}
46
48
  resizeMode="contain"
47
- fallback={<Icon name="image" />}
49
+ fallback={<ImageOutlined size={r(18)} color={colors.foregroundMuted} />}
48
50
  accessibilityLabel={label || '图片'}
49
51
  />
50
52
  </View>
@@ -1,3 +1,4 @@
1
+ import { AlertOutlined } from '@unif/react-native-icons';
1
2
  import { Pressable, Text, View } from 'react-native';
2
3
  import {
3
4
  Button,
@@ -142,7 +143,7 @@ export function Message(props: MessageProps) {
142
143
  <View style={[styles.failureRow, placement === 'end' && styles.end]}>
143
144
  {bubble}
144
145
  <IconButton
145
- icon="alert"
146
+ icon={AlertOutlined}
146
147
  size="sm"
147
148
  variant="ghost"
148
149
  color={colors.error}
@@ -1,3 +1,4 @@
1
+ import { ArrowDownOutlined } from '@unif/react-native-icons';
1
2
  import { useEffect, useRef } from 'react';
2
3
  import { Animated, View } from 'react-native';
3
4
  import {
@@ -39,7 +40,7 @@ export function MessageListEndButton({
39
40
  </View>
40
41
  ) : null}
41
42
  <IconButton
42
- icon="arrow-down"
43
+ icon={ArrowDownOutlined}
43
44
  accessibilityLabel={busy ? '回到最新消息,正在处理' : '回到最新消息'}
44
45
  variant="glass"
45
46
  size="md"
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
2
2
  import { Text, View } from 'react-native';
3
3
  import {
4
4
  Button,
5
- Icon,
5
+ r,
6
6
  useColors,
7
7
  useThemedStyles,
8
8
  } from '@unif/react-native-design';
@@ -130,6 +130,7 @@ export function Process(props: ProcessProps): React.JSX.Element {
130
130
  onToggle={() => toggleDetails(step.id)}
131
131
  />
132
132
  );
133
+ const Glyph = PROCESS_STATUS_ICONS[step.status];
133
134
  return (
134
135
  <View
135
136
  key={step.id}
@@ -150,8 +151,8 @@ export function Process(props: ProcessProps): React.JSX.Element {
150
151
  accessible
151
152
  accessibilityLabel={`${step.title},${statusLabel}`}
152
153
  >
153
- <Icon
154
- name={PROCESS_STATUS_ICONS[step.status]}
154
+ <Glyph
155
+ size={r(18)}
155
156
  color={
156
157
  step.status === 'failed'
157
158
  ? colors.error
@@ -1,7 +1,11 @@
1
+ import {
2
+ ChevronDownOutlined,
3
+ ChevronUpOutlined,
4
+ SparkOutlined,
5
+ } from '@unif/react-native-icons';
1
6
  import { Pressable, ScrollView, Text, View } from 'react-native';
2
7
  import {
3
8
  Button,
4
- Icon,
5
9
  Pulse,
6
10
  Reveal,
7
11
  motion,
@@ -32,24 +36,28 @@ export function ProcessCompactStep({
32
36
  : step.status === 'failed'
33
37
  ? colors.error
34
38
  : colors.foregroundMuted;
35
- const icon = (
36
- <Icon
37
- name={
38
- running || step.status === 'completed'
39
- ? 'spark'
40
- : PROCESS_STATUS_ICONS[step.status]
41
- }
42
- size={14}
43
- color={color}
44
- />
45
- );
39
+ const Glyph =
40
+ step.icon ??
41
+ (running || step.status === 'completed'
42
+ ? SparkOutlined
43
+ : PROCESS_STATUS_ICONS[step.status]);
44
+ const icon =
45
+ step.icon === null ? null : (
46
+ <Glyph
47
+ size={14}
48
+ color={step.icon === undefined ? color : colors.foregroundMuted}
49
+ />
50
+ );
51
+ const Glyph2 = expanded ? ChevronUpOutlined : ChevronDownOutlined;
46
52
  return (
47
53
  <View>
48
54
  <Pressable
49
55
  testID={`process-step-${step.id}-toggle`}
50
56
  accessible
51
57
  accessibilityRole={hasDetails ? 'button' : undefined}
52
- accessibilityLabel={`${step.title},${statusText}${elapsed ? `,${elapsed}` : ''}`}
58
+ accessibilityLabel={[step.title, statusText, elapsed]
59
+ .filter(Boolean)
60
+ .join(',')}
53
61
  accessibilityState={hasDetails ? { expanded } : undefined}
54
62
  disabled={!hasDetails}
55
63
  hitSlop={10}
@@ -65,7 +73,7 @@ export function ProcessCompactStep({
65
73
  <View style={styles.spacer} />
66
74
  </>
67
75
  ) : null}
68
- {running ? (
76
+ {running && icon ? (
69
77
  <Pulse from={0.4} duration={motion.pulse / 2}>
70
78
  {icon}
71
79
  </Pulse>
@@ -81,14 +89,12 @@ export function ProcessCompactStep({
81
89
  {step.title}
82
90
  </Text>
83
91
  ) : null}
84
- <Text style={styles.compactStatus}>{statusText}</Text>
92
+ {statusText ? (
93
+ <Text style={styles.compactStatus}>{statusText}</Text>
94
+ ) : null}
85
95
  {elapsed ? <Text style={styles.elapsed}>{elapsed}</Text> : null}
86
96
  {hasDetails ? (
87
- <Icon
88
- name={expanded ? 'chevron-up' : 'chevron-down'}
89
- size={14}
90
- color={colors.foregroundSubtle}
91
- />
97
+ <Glyph2 size={14} color={colors.foregroundSubtle} />
92
98
  ) : null}
93
99
  </Pressable>
94
100
  {step.description ? (
@@ -1,7 +1,7 @@
1
+ import { CloseOutlined } from '@unif/react-native-icons';
1
2
  import { Text, View } from 'react-native';
2
3
  import {
3
4
  Button,
4
- Icon,
5
5
  StatusDot,
6
6
  icon,
7
7
  useColors,
@@ -35,7 +35,7 @@ export function ProcessTimelineStep({
35
35
  >
36
36
  <View style={styles.timelineGutter}>
37
37
  {step.status === 'cancelled' ? (
38
- <Icon name="close" size={icon.xs} color={colors.foregroundSubtle} />
38
+ <CloseOutlined size={icon.xs} color={colors.foregroundSubtle} />
39
39
  ) : (
40
40
  <StatusDot
41
41
  status={status}
@@ -1,4 +1,13 @@
1
- import type { IconName } from '@unif/react-native-design';
1
+ import {
2
+ CircleMinusOutlined,
3
+ CloseOutlined,
4
+ ErrorOutlined,
5
+ SuccessOutlined,
6
+ ThinkingOutlined,
7
+ } from '@unif/react-native-icons';
8
+ import type { ComponentType } from 'react';
9
+ import type { IconProps } from '@unif/react-native-icons';
10
+
2
11
  import type { ProcessStepStatus } from './types';
3
12
 
4
13
  export const PROCESS_STATUS_LABELS: Readonly<
@@ -12,11 +21,11 @@ export const PROCESS_STATUS_LABELS: Readonly<
12
21
  };
13
22
 
14
23
  export const PROCESS_STATUS_ICONS: Readonly<
15
- Record<ProcessStepStatus, IconName>
24
+ Record<ProcessStepStatus, ComponentType<IconProps>>
16
25
  > = {
17
- pending: 'circle-minus',
18
- running: 'thinking',
19
- completed: 'success',
20
- failed: 'error',
21
- cancelled: 'close',
26
+ pending: CircleMinusOutlined,
27
+ running: ThinkingOutlined,
28
+ completed: SuccessOutlined,
29
+ failed: ErrorOutlined,
30
+ cancelled: CloseOutlined,
22
31
  };
@@ -1,4 +1,7 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { IconProps } from '@unif/react-native-icons';
1
3
  import type { ReactNode } from 'react';
4
+
2
5
  import type { StyleProp, ViewStyle } from 'react-native';
3
6
  import type { ChatAction } from '../../actions';
4
7
 
@@ -9,6 +12,8 @@ export interface ProcessStep {
9
12
  id: string;
10
13
  title: string;
11
14
  status: ProcessStepStatus;
15
+ /** compact 的活动图标;null 不显示,省略时沿状态呈现。 */
16
+ icon?: ComponentType<IconProps> | null;
12
17
  /** 调用者提供的状态显示文案;不改变 status 的语义。 */
13
18
  statusText?: string;
14
19
  description?: string;
@@ -1,5 +1,6 @@
1
+ import { ChevronRightOutlined } from '@unif/react-native-icons';
1
2
  import { Pressable, Text, View } from 'react-native';
2
- import { Icon, useThemedStyles } from '@unif/react-native-design';
3
+ import { r, useColors, useThemedStyles } from '@unif/react-native-design';
3
4
  import { DEFAULT_SOURCES_TITLE } from './constants';
4
5
  import { createStyles } from './styles';
5
6
  import type { SourceItem, SourcesProps } from './types';
@@ -12,6 +13,7 @@ export function Sources({
12
13
  testID,
13
14
  }: SourcesProps): React.JSX.Element | null {
14
15
  const styles = useThemedStyles(createStyles);
16
+ const colors = useColors();
15
17
 
16
18
  if (items.length === 0) return null;
17
19
 
@@ -26,7 +28,9 @@ export function Sources({
26
28
  <Text style={styles.description}>{item.description}</Text>
27
29
  ) : null}
28
30
  </View>
29
- {showChevron ? <Icon name="chevron-right" /> : null}
31
+ {showChevron ? (
32
+ <ChevronRightOutlined size={r(18)} color={colors.foregroundMuted} />
33
+ ) : null}
30
34
  </>
31
35
  );
32
36
 
@@ -1,5 +1,5 @@
1
1
  import { View } from 'react-native';
2
- import { Chip, Icon, useColors } from '@unif/react-native-design';
2
+ import { Chip, useColors } from '@unif/react-native-design';
3
3
  import { SUGGESTION_ICON_SIZE } from './constants';
4
4
  import { styles } from './styles';
5
5
  import type { SuggestionsProps } from './types';
@@ -29,11 +29,7 @@ export function Suggestions({
29
29
  disabled={item.disabled}
30
30
  leading={
31
31
  item.icon ? (
32
- <Icon
33
- name={item.icon}
34
- size={SUGGESTION_ICON_SIZE}
35
- color={colors.primary}
36
- />
32
+ <item.icon size={SUGGESTION_ICON_SIZE} color={colors.primary} />
37
33
  ) : undefined
38
34
  }
39
35
  onPress={onSelect ? () => onSelect(item) : undefined}
@@ -1,11 +1,13 @@
1
- import type { IconName } from '@unif/react-native-design';
1
+ import type { ComponentType } from 'react';
2
+ import type { IconProps } from '@unif/react-native-icons';
3
+
2
4
  import type { StyleProp, ViewStyle } from 'react-native';
3
5
 
4
6
  export interface SuggestionItem {
5
7
  id: string;
6
8
  label: string;
7
9
  /** 14 布局单位的主题主色图标,普通与选中状态保持相同图标样式。 */
8
- icon?: IconName;
10
+ icon?: ComponentType<IconProps>;
9
11
  selected?: boolean;
10
12
  loading?: boolean;
11
13
  disabled?: boolean;