@douyinfe/semi-ui 2.1.4-alpha.0 → 2.2.0-beta.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 (162) hide show
  1. package/_base/_story/a11y.jsx +1302 -0
  2. package/_base/_story/a11y.scss +49 -0
  3. package/_base/_story/index.scss +1 -0
  4. package/_base/_story/index.stories.js +3 -1
  5. package/_utils/index.ts +2 -1
  6. package/button/Button.tsx +1 -0
  7. package/button/__test__/button.test.js +15 -0
  8. package/button/_story/button.stories.js +13 -0
  9. package/button/buttonGroup.tsx +6 -4
  10. package/cascader/__test__/cascader.test.js +221 -0
  11. package/cascader/_story/cascader.stories.js +138 -0
  12. package/cascader/index.tsx +37 -21
  13. package/cascader/item.tsx +7 -2
  14. package/checkbox/__test__/checkboxGroup.test.js +37 -5
  15. package/checkbox/_story/checkbox.stories.js +78 -6
  16. package/checkbox/checkbox.tsx +3 -0
  17. package/checkbox/checkboxGroup.tsx +3 -2
  18. package/datePicker/__test__/datePicker.test.js +67 -2
  19. package/datePicker/_story/datePicker.stories.js +3 -1
  20. package/datePicker/_story/v2/YearButton.jsx +17 -0
  21. package/datePicker/_story/v2/index.js +1 -0
  22. package/datePicker/monthsGrid.tsx +12 -1
  23. package/datePicker/navigation.tsx +55 -29
  24. package/descriptions/__test__/descriptions.test.js +27 -1
  25. package/descriptions/_story/descriptions.stories.js +52 -2
  26. package/descriptions/item.tsx +1 -1
  27. package/dist/css/semi.css +105 -32
  28. package/dist/css/semi.min.css +1 -1
  29. package/dist/umd/semi-ui.js +801 -227
  30. package/dist/umd/semi-ui.js.map +1 -1
  31. package/dist/umd/semi-ui.min.js +1 -1
  32. package/dist/umd/semi-ui.min.js.map +1 -1
  33. package/form/_story/form.stories.js +0 -67
  34. package/form/_story/form.stories.tsx +2 -2
  35. package/form/hoc/withField.tsx +2 -2
  36. package/lib/cjs/_base/base.css +2 -2
  37. package/lib/cjs/_utils/index.d.ts +1 -0
  38. package/lib/cjs/_utils/index.js +3 -2
  39. package/lib/cjs/button/Button.d.ts +1 -0
  40. package/lib/cjs/button/buttonGroup.js +11 -3
  41. package/lib/cjs/cascader/index.d.ts +7 -0
  42. package/lib/cjs/cascader/index.js +35 -22
  43. package/lib/cjs/cascader/item.d.ts +2 -0
  44. package/lib/cjs/cascader/item.js +9 -2
  45. package/lib/cjs/checkbox/checkbox.js +4 -1
  46. package/lib/cjs/checkbox/checkboxGroup.d.ts +1 -0
  47. package/lib/cjs/checkbox/checkboxGroup.js +3 -1
  48. package/lib/cjs/datePicker/dateInput.d.ts +1 -1
  49. package/lib/cjs/datePicker/datePicker.d.ts +1 -1
  50. package/lib/cjs/datePicker/monthsGrid.d.ts +2 -1
  51. package/lib/cjs/datePicker/monthsGrid.js +6 -0
  52. package/lib/cjs/datePicker/navigation.js +47 -7
  53. package/lib/cjs/descriptions/item.js +1 -1
  54. package/lib/cjs/form/baseForm.d.ts +6 -0
  55. package/lib/cjs/form/field.d.ts +6 -0
  56. package/lib/cjs/form/hoc/withField.js +3 -1
  57. package/lib/cjs/locale/source/es.d.ts +7 -0
  58. package/lib/cjs/locale/source/es.js +168 -0
  59. package/lib/cjs/modal/Modal.d.ts +8 -8
  60. package/lib/cjs/modal/Modal.js +4 -4
  61. package/lib/cjs/modal/confirm.d.ts +10 -10
  62. package/lib/cjs/navigation/index.d.ts +2 -2
  63. package/lib/cjs/pagination/index.js +9 -4
  64. package/lib/cjs/radio/radio.d.ts +1 -1
  65. package/lib/cjs/radio/radio.js +1 -0
  66. package/lib/cjs/radio/radioGroup.d.ts +1 -1
  67. package/lib/cjs/rating/item.js +3 -2
  68. package/lib/cjs/select/index.d.ts +10 -0
  69. package/lib/cjs/select/index.js +15 -9
  70. package/lib/cjs/table/Table.d.ts +1 -1
  71. package/lib/cjs/timePicker/TimePicker.d.ts +2 -2
  72. package/lib/cjs/timePicker/TimeShape.d.ts +1 -1
  73. package/lib/cjs/timePicker/index.d.ts +2 -2
  74. package/lib/cjs/timeline/item.d.ts +5 -2
  75. package/lib/cjs/timeline/item.js +13 -7
  76. package/lib/cjs/tree/treeNode.js +0 -2
  77. package/lib/cjs/treeSelect/index.js +1 -0
  78. package/lib/cjs/typography/title.d.ts +1 -1
  79. package/lib/cjs/upload/fileCard.d.ts +2 -0
  80. package/lib/cjs/upload/fileCard.js +70 -45
  81. package/lib/cjs/upload/index.d.ts +34 -4
  82. package/lib/cjs/upload/index.js +141 -25
  83. package/lib/cjs/upload/interface.d.ts +3 -0
  84. package/lib/es/_base/base.css +2 -2
  85. package/lib/es/_utils/index.d.ts +1 -0
  86. package/lib/es/_utils/index.js +3 -2
  87. package/lib/es/button/Button.d.ts +1 -0
  88. package/lib/es/button/buttonGroup.js +3 -3
  89. package/lib/es/cascader/index.d.ts +7 -0
  90. package/lib/es/cascader/index.js +34 -25
  91. package/lib/es/cascader/item.d.ts +2 -0
  92. package/lib/es/cascader/item.js +9 -2
  93. package/lib/es/checkbox/checkbox.js +4 -1
  94. package/lib/es/checkbox/checkboxGroup.d.ts +1 -0
  95. package/lib/es/checkbox/checkboxGroup.js +3 -1
  96. package/lib/es/datePicker/dateInput.d.ts +1 -1
  97. package/lib/es/datePicker/datePicker.d.ts +1 -1
  98. package/lib/es/datePicker/monthsGrid.d.ts +2 -1
  99. package/lib/es/datePicker/monthsGrid.js +6 -0
  100. package/lib/es/datePicker/navigation.js +48 -8
  101. package/lib/es/descriptions/item.js +1 -1
  102. package/lib/es/form/baseForm.d.ts +6 -0
  103. package/lib/es/form/field.d.ts +6 -0
  104. package/lib/es/form/hoc/withField.js +3 -1
  105. package/lib/es/locale/source/es.d.ts +7 -0
  106. package/lib/es/locale/source/es.js +157 -0
  107. package/lib/es/modal/Modal.d.ts +8 -8
  108. package/lib/es/modal/Modal.js +4 -4
  109. package/lib/es/modal/confirm.d.ts +10 -10
  110. package/lib/es/navigation/index.d.ts +2 -2
  111. package/lib/es/pagination/index.js +8 -4
  112. package/lib/es/radio/radio.d.ts +1 -1
  113. package/lib/es/radio/radio.js +1 -0
  114. package/lib/es/radio/radioGroup.d.ts +1 -1
  115. package/lib/es/rating/item.js +3 -2
  116. package/lib/es/select/index.d.ts +10 -0
  117. package/lib/es/select/index.js +19 -9
  118. package/lib/es/table/Table.d.ts +1 -1
  119. package/lib/es/timePicker/TimePicker.d.ts +2 -2
  120. package/lib/es/timePicker/TimeShape.d.ts +1 -1
  121. package/lib/es/timePicker/index.d.ts +2 -2
  122. package/lib/es/timeline/item.d.ts +5 -2
  123. package/lib/es/timeline/item.js +12 -7
  124. package/lib/es/tree/treeNode.js +0 -2
  125. package/lib/es/treeSelect/index.js +1 -0
  126. package/lib/es/typography/title.d.ts +1 -1
  127. package/lib/es/upload/fileCard.d.ts +2 -0
  128. package/lib/es/upload/fileCard.js +69 -44
  129. package/lib/es/upload/index.d.ts +34 -4
  130. package/lib/es/upload/index.js +141 -24
  131. package/lib/es/upload/interface.d.ts +3 -0
  132. package/locale/source/es.ts +160 -0
  133. package/modal/Modal.tsx +6 -6
  134. package/navigation/__test__/navigation.test.js +4 -4
  135. package/navigation/_story/AutoOpen/index.js +1 -1
  136. package/navigation/_story/WithChildren/index.js +1 -1
  137. package/navigation/_story/navigation.stories.js +1 -1
  138. package/navigation/_story/navigation.stories.tsx +4 -4
  139. package/navigation/index.tsx +2 -2
  140. package/package.json +16 -8
  141. package/pagination/_story/pagination.stories.js +11 -0
  142. package/pagination/index.tsx +9 -4
  143. package/popover/Arrow.tsx +1 -1
  144. package/radio/__test__/radioGroup.test.jsx +41 -6
  145. package/radio/_story/radio.stories.js +22 -11
  146. package/radio/radio.tsx +1 -0
  147. package/rating/item.tsx +2 -1
  148. package/select/_story/select.stories.js +39 -14
  149. package/select/index.tsx +21 -7
  150. package/table/_story/DynamicFilters/index.js +13 -16
  151. package/timeline/__test__/timeline.test.js +17 -1
  152. package/timeline/_story/timeline.stories.js +70 -6
  153. package/timeline/item.tsx +11 -6
  154. package/tooltip/_story/tooltip.stories.js +1 -1
  155. package/tree/_story/tree.stories.js +2 -2
  156. package/tree/treeNode.tsx +0 -2
  157. package/treeSelect/index.tsx +3 -2
  158. package/tsconfig.json +2 -1
  159. package/upload/__test__/upload.test.js +50 -1
  160. package/upload/fileCard.tsx +110 -95
  161. package/upload/index.tsx +155 -54
  162. package/upload/interface.ts +3 -0
@@ -81,8 +81,21 @@ export const Mode = () => (
81
81
  }}
82
82
  >
83
83
  <Timeline mode="alternate">
84
- <Timeline.Item time="2015-09-01">创建服务现场</Timeline.Item>
85
- <Timeline.Item time="2015-09-01">初步排除网络异常</Timeline.Item>
84
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>创建服务现场</Timeline.Item>
85
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>初步排除网络异常</Timeline.Item>
86
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>技术测试异常</Timeline.Item>
87
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>网络异常正在修复</Timeline.Item>
88
+ </Timeline>
89
+ </div>
90
+ <br />
91
+ <div
92
+ style={{
93
+ width: '300px',
94
+ }}
95
+ >
96
+ <Timeline mode="right">
97
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>创建服务现场</Timeline.Item>
98
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>初步排除网络异常</Timeline.Item>
86
99
  <Timeline.Item time="2015-09-01">技术测试异常</Timeline.Item>
87
100
  <Timeline.Item time="2015-09-01">网络异常正在修复</Timeline.Item>
88
101
  </Timeline>
@@ -93,9 +106,9 @@ export const Mode = () => (
93
106
  width: '300px',
94
107
  }}
95
108
  >
96
- <Timeline mode="right">
97
- <Timeline.Item time="2015-09-01">创建服务现场</Timeline.Item>
98
- <Timeline.Item time="2015-09-01">初步排除网络异常</Timeline.Item>
109
+ <Timeline mode="left">
110
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>创建服务现场</Timeline.Item>
111
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>初步排除网络异常</Timeline.Item>
99
112
  <Timeline.Item time="2015-09-01">技术测试异常</Timeline.Item>
100
113
  <Timeline.Item time="2015-09-01">网络异常正在修复</Timeline.Item>
101
114
  </Timeline>
@@ -108,7 +121,7 @@ export const Mode = () => (
108
121
  >
109
122
  <Timeline mode="center">
110
123
  <Timeline.Item time="2015-09-01">创建服务现场</Timeline.Item>
111
- <Timeline.Item time="2015-09-01">初步排除网络异常</Timeline.Item>
124
+ <Timeline.Item time="2015-09-01" dot={<IconAlertTriangle />}>初步排除网络异常</Timeline.Item>
112
125
  <Timeline.Item time="2015-09-01">技术测试异常</Timeline.Item>
113
126
  <Timeline.Item time="2015-09-01">网络异常正在修复</Timeline.Item>
114
127
  </Timeline>
@@ -152,6 +165,7 @@ const data = [
152
165
  time: '2019-05-09 09:12',
153
166
  extra: '节点辅助说明信息',
154
167
  content: '网络异常正在修复',
168
+ dot: <IconAlertTriangle />,
155
169
  type: 'success',
156
170
  },
157
171
  ];
@@ -169,3 +183,53 @@ export const DataSource = () => (
169
183
  DataSource.story = {
170
184
  name: 'dataSource',
171
185
  };
186
+
187
+ const dataWithOnClick = [
188
+ {
189
+ time: '2019-07-14 10:35',
190
+ extra: '节点辅助说明信息',
191
+ content: '创建服务现场',
192
+ type: 'ongoing',
193
+ onClick: e => console.log(e, '创建服务现场'),
194
+ },
195
+ {
196
+ time: '2019-06-13 16:17',
197
+ extra: '节点辅助说明信息',
198
+ content: <span style={{ fontSize: '18px' }}>初步排除网络异常</span>,
199
+ color: 'pink',
200
+ onClick: e => console.log(e, '初步排除网络异常'),
201
+ },
202
+ {
203
+ time: '2019-05-14 18:34',
204
+ extra: '节点辅助说明信息',
205
+ dot: <Icon type="alert_triangle" />,
206
+ content: '技术测试异常',
207
+ type: 'warning',
208
+ onClick: e => console.log(e, '技术测试异常'),
209
+ },
210
+ {
211
+ time: '2019-05-09 09:12',
212
+ extra: '节点辅助说明信息',
213
+ content: '网络异常正在修复',
214
+ type: 'success',
215
+ onClick: e => console.log(e, '网络异常正在修复'),
216
+ }
217
+ ];
218
+
219
+ export const OnClickDemo = () => (
220
+ <div style={{ width: '400px' }}>
221
+ <div style={{ width: '300px' }}>
222
+ <Timeline mode='center'>
223
+ <Timeline.Item time='2015-09-01' onClick={e=>console.log(e, '创建服务现场')}>创建服务现场</Timeline.Item>
224
+ <Timeline.Item time='2015-09-01' onClick={e=>console.log(e, '初步排除网络异常')}>初步排除网络异常</Timeline.Item>
225
+ <Timeline.Item time='2015-09-01' onClick={e=>console.log(e, '技术测试异常')}>技术测试异常</Timeline.Item>
226
+ <Timeline.Item time='2015-09-01' onClick={e=>console.log(e, '网络异常正在修复')}>网络异常正在修复</Timeline.Item>
227
+ </Timeline>
228
+ <Timeline mode='alternate' dataSource={dataWithOnClick} />
229
+ </div>
230
+ </div>
231
+ );
232
+
233
+ OnClickDemo.story = {
234
+ name: 'onClick',
235
+ };
package/timeline/item.tsx CHANGED
@@ -1,18 +1,20 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import cls from 'classnames';
3
+ import { noop } from 'lodash';
3
4
  import PropTypes from 'prop-types';
4
5
  import { cssClasses, strings } from '@douyinfe/semi-foundation/timeline/constants';
5
6
  import '@douyinfe/semi-foundation/timeline/timeline.scss';
6
7
 
7
8
  export interface TimelineItemProps {
8
9
  color?: string;
9
- time?: string;
10
+ time?: React.ReactNode;
10
11
  type?: 'default' | 'ongoing' | 'success' | 'warning' | 'error';
11
12
  dot?: React.ReactNode;
12
13
  extra?: React.ReactNode;
13
14
  position?: 'left' | 'right';
14
15
  className?: string;
15
16
  style?: React.CSSProperties;
17
+ onClick?: React.MouseEventHandler<HTMLLIElement>;
16
18
  }
17
19
 
18
20
  const prefixCls = cssClasses.ITEM;
@@ -20,18 +22,20 @@ const prefixCls = cssClasses.ITEM;
20
22
  export default class Item extends PureComponent<TimelineItemProps> {
21
23
  static propTypes = {
22
24
  color: PropTypes.string,
23
- time: PropTypes.string,
25
+ time: PropTypes.node,
24
26
  type: PropTypes.oneOf(strings.ITEM_TYPE),
25
27
  dot: PropTypes.node,
26
28
  extra: PropTypes.node,
27
29
  position: PropTypes.oneOf(strings.ITEM_POS),
28
30
  className: PropTypes.string,
29
31
  style: PropTypes.object,
32
+ onClick: PropTypes.func,
30
33
  };
31
34
 
32
35
  static defaultProps = {
33
36
  type: 'default',
34
37
  time: '',
38
+ onClick: noop,
35
39
  };
36
40
 
37
41
  render() {
@@ -43,7 +47,8 @@ export default class Item extends PureComponent<TimelineItemProps> {
43
47
  type,
44
48
  style,
45
49
  time,
46
- extra
50
+ extra,
51
+ onClick,
47
52
  } = this.props;
48
53
 
49
54
  const itemCls = cls(prefixCls,
@@ -57,7 +62,7 @@ export default class Item extends PureComponent<TimelineItemProps> {
57
62
  });
58
63
  const dotStyle = color ? { style: { backgroundColor: color } } : null;
59
64
  return (
60
- <li className={itemCls} style={style}>
65
+ <li className={itemCls} style={style} onClick={onClick}>
61
66
  <div className={`${prefixCls}-tail`} />
62
67
  <div
63
68
  className={dotCls}
@@ -67,8 +72,8 @@ export default class Item extends PureComponent<TimelineItemProps> {
67
72
  </div>
68
73
  <div className={`${prefixCls}-content`}>
69
74
  {children}
70
- {extra ? <div className={`${prefixCls}-content-extra`}>{extra}</div> : null}
71
- <div className={`${prefixCls}-content-time`}>{time}</div>
75
+ {extra && <div className={`${prefixCls}-content-extra`}>{extra}</div>}
76
+ {time && <div className={`${prefixCls}-content-time`}>{time}</div>}
72
77
  </div>
73
78
  </li>
74
79
  );
@@ -652,7 +652,7 @@ export const ShowArrow = () => {
652
652
  return (
653
653
  <div>
654
654
  <h4>should show content and arrow when click</h4>
655
- <Tooltip showArrow trigger="click" content={'hi bytedance'}>
655
+ <Tooltip style={{ maxWidth: 320 }} showArrow trigger='custom' visible content={'hi semi semi semi semi semi semi semi'} position='right'>
656
656
  <Test />
657
657
  </Tooltip>
658
658
  </div>
@@ -251,7 +251,7 @@ export const SimpleTree = () => (
251
251
  // onExpand={(e, { expanded, node }) => console.log('expand', e, expanded, node)}
252
252
  // onSelect={(e, bool, node) => console.log('select', e, bool, node)}
253
253
  // onChange={e => console.log('change', e)}
254
- onRightClick={(e, node) => console.log(e.currentTarget, node)}
254
+ onContextMenu={(e, node) => console.log(e.currentTarget, node)}
255
255
  onDoubleClick={(e, node) => console.log(e, node)}
256
256
  motion={true}
257
257
  />
@@ -268,7 +268,7 @@ export const MultipleTree = () => (
268
268
  labelInValue
269
269
  // onExpand={(e, { expanded, node }) => console.log('expand', e, expanded, node)}
270
270
  // onSelect={(e, bool) => console.log('select', e, bool)}
271
- onRightClick={(e, node) => console.log(e, node)}
271
+ onContextMenu={(e, node) => console.log(e, node)}
272
272
  onDoubleClick={(e, node) => console.log(e, node)}
273
273
  onChange={e => console.log('change', e)}
274
274
  />
package/tree/treeNode.tsx CHANGED
@@ -75,8 +75,6 @@ export default class TreeNode extends PureComponent<TreeNodeProps, TreeNodeState
75
75
 
76
76
  onContextMenu = (e: React.MouseEvent) => {
77
77
  const { onNodeRightClick } = this.context;
78
- e.stopPropagation();
79
- e.nativeEvent.stopImmediatePropagation();
80
78
  onNodeRightClick(e, this.props);
81
79
  };
82
80
 
@@ -27,7 +27,7 @@ import {
27
27
  } from '@douyinfe/semi-foundation/tree/treeUtil';
28
28
  import { cssClasses, strings } from '@douyinfe/semi-foundation/treeSelect/constants';
29
29
  import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
30
- import { FixedSizeList as VirtualList } from 'react-window';
30
+ import { FixedSizeList as VirtualList, ListItemKeySelector } from 'react-window';
31
31
  import '@douyinfe/semi-foundation/tree/tree.scss';
32
32
  import '@douyinfe/semi-foundation/treeSelect/treeSelect.scss';
33
33
  import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
@@ -1166,7 +1166,8 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
1166
1166
  itemSize={virtualize.itemSize}
1167
1167
  height={height}
1168
1168
  width={width}
1169
- itemKey={this.itemKey}
1169
+ // @ts-ignore avoid strict check of itemKey
1170
+ itemKey={this.itemKey as ListItemKeySelector<TreeNodeData>}
1170
1171
  itemData={flattenNodes as any}
1171
1172
  className={`${prefixTree}-virtual-list`}
1172
1173
  style={{ direction }}
package/tsconfig.json CHANGED
@@ -25,7 +25,8 @@
25
25
  "esModuleInterop": true,
26
26
  "skipLibCheck": true,
27
27
  "declaration": true,
28
- "strictNullChecks": false
28
+ "strictNullChecks": false,
29
+ "strict": true
29
30
  },
30
31
  "include": ["**/*.tsx", "**/*.ts"],
31
32
  "exclude": ["node_modules", "packages/rollup-plugin-semi-svg"]
@@ -869,7 +869,7 @@ describe('Upload', () => {
869
869
  beforeClear: () => Promise.reject(),
870
870
  onChange: spyOnChangeReject,
871
871
  onClear: spyOnClearReject,
872
- })
872
+ });
873
873
 
874
874
  const clearBtn = upload.find(`.${BASE_CLASS_PREFIX}-upload-file-list-title-clear`).at(0);
875
875
  const clearBtnPass = uploadPass.find(`.${BASE_CLASS_PREFIX}-upload-file-list-title-clear`).at(0);
@@ -893,4 +893,53 @@ describe('Upload', () => {
893
893
  expect(spyOnClearReject.callCount).toEqual(0);
894
894
  });
895
895
  });
896
+
897
+ it('insert method', () => {
898
+ const props = {
899
+ defaultFileList: [],
900
+ };
901
+ const upload = getUpload(props);
902
+ const uploadInstance = upload.instance();
903
+
904
+ const file_0 = new File([new ArrayBuffer(1024)], 'chucknorris_0.png', { type: 'image/png' });
905
+ const file_1 = new File([new ArrayBuffer(1024)], 'chucknorris_1.png', { type: 'image/png' });
906
+ const file_2 = new File([new ArrayBuffer(1024)], 'chucknorris_2.png', { type: 'image/png' });
907
+
908
+ expect(uploadInstance instanceof Upload).toEqual(true);
909
+ expect(Object.prototype.hasOwnProperty.call(uploadInstance, 'insert')).toEqual(true);
910
+
911
+ /**
912
+ * test fileList state should be [] => [file_0] => [file_1, file_0] => [file_1, file_2, file_0]
913
+ */
914
+ upload.instance().insert([file_0]);
915
+ upload.instance().insert([file_1], 0);
916
+ upload.instance().insert([file_2], 1);
917
+
918
+ expect(Array.isArray(upload.state('fileList'))).toEqual(true);
919
+ expect(upload.state('fileList').length).toEqual(3);
920
+ expect(upload.state('fileList')[0].name).toEqual('chucknorris_1.png');
921
+ expect(upload.state('fileList')[1].name).toEqual('chucknorris_2.png');
922
+ expect(upload.state('fileList')[2].name).toEqual('chucknorris_0.png');
923
+ });
924
+
925
+ it('showPicInfo works', () => {
926
+ const props = {
927
+ listType: 'picture',
928
+ defaultFileList: [
929
+ {
930
+ uid: '1',
931
+ name: 'jiafang1.jpeg',
932
+ status: 'success',
933
+ size: '130kb',
934
+ url: 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
935
+ },
936
+ ],
937
+ showPicInfo: true,
938
+ };
939
+ const upload = getUpload(props);
940
+
941
+ expect(upload.exists(`.${BASE_CLASS_PREFIX}-upload`)).toEqual(true);
942
+ expect(upload.exists(`.${BASE_CLASS_PREFIX}-upload-file-list-main`)).toEqual(true);
943
+ expect(upload.exists(`.${BASE_CLASS_PREFIX}-upload-picture-file-card-pic-info`)).toEqual(true);
944
+ });
896
945
  });
@@ -3,7 +3,7 @@ import cls from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
  import { cssClasses, strings } from '@douyinfe/semi-foundation/upload/constants';
5
5
  import { getFileSize } from '@douyinfe/semi-foundation/upload/utils';
6
- import { BaseFileItem } from '@douyinfe/semi-foundation/upload/foundation';
6
+ import { IconAlertCircle, IconClose, IconFile, IconRefresh } from '@douyinfe/semi-icons';
7
7
  import LocaleConsumer from '../locale/localeConsumer';
8
8
  import { Locale } from '../locale/interface';
9
9
 
@@ -13,7 +13,6 @@ import Tooltip from '../tooltip/index';
13
13
  import Spin from '../spin/index';
14
14
  import { isElement } from '../_base/reactUtils';
15
15
  import { RenderFileItemProps } from './interface';
16
- import { IconAlertCircle, IconClose, IconFile, IconRefresh } from '@douyinfe/semi-icons';
17
16
 
18
17
  const prefixCls = cssClasses.PREFIX;
19
18
 
@@ -69,6 +68,7 @@ class FileCard extends PureComponent<FileCardProps> {
69
68
  style: PropTypes.object,
70
69
  url: PropTypes.string,
71
70
  validateMessage: PropTypes.node,
71
+ index: PropTypes.number
72
72
  };
73
73
 
74
74
  static defaultProps = {
@@ -92,10 +92,10 @@ class FileCard extends PureComponent<FileCardProps> {
92
92
  let content = null;
93
93
  switch (true) {
94
94
  case typeof validateMessage === 'string' && status === strings.FILE_STATUS_VALIDATING:
95
- content = (<><Spin size="small" wrapperClassName={`${prefixCls }-file-card-icon-loading`} />{validateMessage}</>);
95
+ content = (<><Spin size="small" wrapperClassName={`${prefixCls}-file-card-icon-loading`} />{validateMessage}</>);
96
96
  break;
97
97
  case typeof validateMessage === 'string':
98
- content = (<><IconAlertCircle className={`${prefixCls }-file-card-icon-error`} />{validateMessage}</>);
98
+ content = (<><IconAlertCircle className={`${prefixCls}-file-card-icon-error`} />{validateMessage}</>);
99
99
  break;
100
100
  case isElement(validateMessage):
101
101
  content = validateMessage;
@@ -111,10 +111,10 @@ class FileCard extends PureComponent<FileCardProps> {
111
111
  let icon = null;
112
112
  switch (true) {
113
113
  case validateMessage && status === strings.FILE_STATUS_VALIDATING:
114
- icon = (<Spin size="small" wrapperClassName={`${prefixCls }-picture-file-card-icon-loading`} />);
114
+ icon = (<Spin size="small" wrapperClassName={`${prefixCls}-picture-file-card-icon-loading`} />);
115
115
  break;
116
116
  case validateMessage && (status === strings.FILE_STATUS_VALID_FAIL || status === strings.FILE_STATUS_UPLOAD_FAIL):
117
- icon = (<div className={`${prefixCls }-picture-file-card-icon-error`}><ErrorSvg /></div>);
117
+ icon = (<div className={`${prefixCls}-picture-file-card-icon-error`}><ErrorSvg /></div>);
118
118
  break;
119
119
  default:
120
120
  break;
@@ -123,41 +123,50 @@ class FileCard extends PureComponent<FileCardProps> {
123
123
  }
124
124
 
125
125
  renderPic(locale: Locale['Upload']): ReactNode {
126
- const { url, percent, status, disabled, style, onPreviewClick } = this.props;
127
- const filePicCardCls = cls({
128
- [`${prefixCls }-picture-file-card`]: true,
129
- [`${prefixCls }-picture-file-card-disabled`]: disabled,
130
- [`${prefixCls }-picture-file-card-show-pointer`]: typeof onPreviewClick !== 'undefined',
131
- });
126
+ const { url, percent, status, disabled, style, onPreviewClick, showPicInfo, renderPicInfo, renderThumbnail, name, index } = this.props;
132
127
  const showProgress = status === strings.FILE_STATUS_UPLOADING && percent !== 100;
133
128
  const showRetry = status === strings.FILE_STATUS_UPLOAD_FAIL && this.props.showRetry;
134
129
  const showReplace = status === strings.FILE_STATUS_SUCCESS && this.props.showReplace;
135
- const closeCls = `${prefixCls }-picture-file-card-close`;
130
+ const filePicCardCls = cls({
131
+ [`${prefixCls}-picture-file-card`]: true,
132
+ [`${prefixCls}-picture-file-card-disabled`]: disabled,
133
+ [`${prefixCls}-picture-file-card-show-pointer`]: typeof onPreviewClick !== 'undefined',
134
+ [`${prefixCls}-picture-file-card-error`]: status === strings.FILE_STATUS_UPLOAD_FAIL,
135
+ [`${prefixCls}-picture-file-card-uploading`]: showProgress
136
+ });
137
+ const closeCls = `${prefixCls}-picture-file-card-close`;
136
138
  const retry = (
137
139
  <div
138
- className={`${prefixCls }-picture-file-card-retry`} onClick={e => this.onRetry(e)}>
139
- <IconRefresh className={`${prefixCls }-picture-file-card-icon-retry`} />
140
+ className={`${prefixCls}-picture-file-card-retry`} onClick={e => this.onRetry(e)}>
141
+ <IconRefresh className={`${prefixCls}-picture-file-card-icon-retry`} />
140
142
  </div>
141
143
  );
142
144
  const replace = (
143
145
  <Tooltip trigger="hover" position="top" content={locale.replace} showArrow={false} spacing={4}>
144
146
  <div
145
- className={`${prefixCls }-picture-file-card-replace`} onClick={(e): void => this.onReplace(e)}>
146
- <ReplaceSvg className={`${prefixCls }-picture-file-card-icon-replace`} />
147
+ className={`${prefixCls}-picture-file-card-replace`} onClick={(e): void => this.onReplace(e)}>
148
+ <ReplaceSvg className={`${prefixCls}-picture-file-card-icon-replace`} />
147
149
  </div>
148
150
  </Tooltip>
149
151
 
150
152
  );
151
153
 
154
+ const picInfo = typeof renderPicInfo === 'function' ? renderPicInfo(this.props) : (
155
+ <div className={`${prefixCls }-picture-file-card-pic-info`}>{index + 1}</div>
156
+ );
157
+
158
+ const thumbnail = typeof renderThumbnail === 'function' ? renderThumbnail(this.props) : <img src={url} alt={`picture of ${name}`} />;
159
+
152
160
  return (
153
161
  <div className={filePicCardCls} style={style} onClick={onPreviewClick}>
154
- <img src={url} />
162
+ {thumbnail}
155
163
  {showProgress ? <Progress percent={percent} type="circle" size="small" orbitStroke={'#FFF'} /> : null}
156
164
  {showRetry ? retry : null}
157
165
  {showReplace && replace}
158
- {disabled ? null : (
159
- <div className={closeCls} onClick={e => this.onRemove(e)}>
160
- <IconClose size="extra-small" />
166
+ {showPicInfo && picInfo}
167
+ {!disabled && (
168
+ <div className={closeCls}>
169
+ <IconClose size="extra-small" onClick={e => this.onRemove(e)} />
161
170
  </div>
162
171
  )}
163
172
  {this.renderPicValidateMsg()}
@@ -165,6 +174,77 @@ class FileCard extends PureComponent<FileCardProps> {
165
174
  );
166
175
  }
167
176
 
177
+ renderFile(locale: Locale["Upload"]) {
178
+ const { name, size, percent, url, showRetry: propsShowRetry, showReplace: propsShowReplace, preview, previewFile, status, style, onPreviewClick } = this.props;
179
+ const fileCardCls = cls({
180
+ [`${prefixCls}-file-card`]: true,
181
+ [`${prefixCls}-file-card-fail`]: status === strings.FILE_STATUS_VALID_FAIL || status === strings.FILE_STATUS_UPLOAD_FAIL,
182
+ [`${prefixCls}-file-card-show-pointer`]: typeof onPreviewClick !== 'undefined',
183
+ });
184
+ const previewCls = cls({
185
+ [`${prefixCls}-file-card-preview`]: true,
186
+ [`${prefixCls}-file-card-preview-placeholder`]: !preview || previewFile
187
+ });
188
+ const infoCls = `${prefixCls}-file-card-info`;
189
+ const closeCls = `${prefixCls}-file-card-close`;
190
+ const replaceCls = `${prefixCls}-file-card-replace`;
191
+ const showProgress = !(percent === 100 || typeof percent === 'undefined') && status === strings.FILE_STATUS_UPLOADING;
192
+ // only show retry when upload fail & showRetry is true, no need to show during validate fail
193
+ const showRetry = status === strings.FILE_STATUS_UPLOAD_FAIL && propsShowRetry;
194
+ const showReplace = status === strings.FILE_STATUS_SUCCESS && propsShowReplace;
195
+ const fileSize = this.transSize(size);
196
+ let previewContent: ReactNode = preview ? (<img src={url} />) : (<IconFile size="large" />);
197
+ if (previewFile) {
198
+ previewContent = previewFile(this.props);
199
+ }
200
+ return (
201
+ <div className={fileCardCls} style={style} onClick={onPreviewClick}>
202
+ <div className={previewCls}>
203
+ {previewContent}
204
+ </div>
205
+ <div className={`${infoCls}-main`}>
206
+ <div className={`${infoCls}-main-text`}>
207
+ <span className={`${infoCls}-name`}>
208
+ {name}
209
+ </span>
210
+ <span>
211
+ <span className={`${infoCls}-size`}>{fileSize}</span>
212
+ {showReplace && (
213
+ <Tooltip trigger="hover" position="top" showArrow={false} content={locale.replace}>
214
+ <IconButton
215
+ onClick={e => this.onReplace(e)}
216
+ type="tertiary"
217
+ theme="borderless"
218
+ size="small"
219
+ icon={<DirectorySvg />}
220
+ className={replaceCls}
221
+ />
222
+ </Tooltip>
223
+ )}
224
+
225
+ </span>
226
+
227
+ </div>
228
+ {showProgress ? (<Progress percent={percent} style={{ width: '100%' }} />) : null}
229
+ <div className={`${infoCls}-main-control`}>
230
+ <span className={`${infoCls}-validate-message`}>
231
+ {this.renderValidateMessage()}
232
+ </span>
233
+ {showRetry ? <span className={`${infoCls}-retry`} onClick={e => this.onRetry(e)}>{locale.retry}</span> : null}
234
+ </div>
235
+ </div>
236
+ <IconButton
237
+ onClick={e => this.onRemove(e)}
238
+ type="tertiary"
239
+ icon={<IconClose />}
240
+ theme="borderless"
241
+ size="small"
242
+ className={closeCls}
243
+ />
244
+ </div>
245
+ );
246
+ }
247
+
168
248
  onRemove(e: MouseEvent): void {
169
249
  e.stopPropagation();
170
250
  this.props.onRemove(this.props, e);
@@ -181,89 +261,24 @@ class FileCard extends PureComponent<FileCardProps> {
181
261
  }
182
262
 
183
263
  render() {
184
- const { name, size, percent, url, listType, preview, previewFile, status, style, onPreviewClick } = this.props;
185
- const fileCardCls = cls({
186
- [`${prefixCls}-file-card`]: true,
187
- [`${prefixCls}-file-card-fail`]: status === strings.FILE_STATUS_VALID_FAIL || status === strings.FILE_STATUS_UPLOAD_FAIL,
188
- [`${prefixCls}-file-card-show-pointer`]: typeof onPreviewClick !== 'undefined',
189
- });
190
- const previewCls = cls({
191
- [`${prefixCls}-file-card-preview`]: true,
192
- [`${prefixCls}-file-card-preview-placeholder`]: !preview || previewFile
193
- });
194
- const infoCls = `${prefixCls}-file-card-info`;
195
- const closeCls = `${prefixCls}-file-card-close`;
196
- const replaceCls = `${prefixCls}-file-card-replace`;
197
- const showProgress = !(percent === 100 || typeof percent === 'undefined') && status === strings.FILE_STATUS_UPLOADING;
198
- // only show retry when upload fail & showRetry is true, no need to show during validate fail
199
- const showRetry = status === strings.FILE_STATUS_UPLOAD_FAIL && this.props.showRetry;
200
- const showReplace = status === strings.FILE_STATUS_SUCCESS && this.props.showReplace;
201
-
264
+ const { listType } = this.props;
202
265
  if (listType === strings.FILE_LIST_PIC) {
203
266
  return (
204
267
  <LocaleConsumer componentName="Upload">
205
- {(locale: Locale['Upload']): ReactNode => (this.renderPic(locale))}
268
+ {(locale: Locale["Upload"]) => (this.renderPic(locale))}
206
269
  </LocaleConsumer>
207
270
  );
208
271
  }
209
272
 
210
- const fileSize = this.transSize(size);
211
- let previewContent: ReactNode = preview ? (<img src={url} />) : (<IconFile size="large" />);
212
- if (previewFile) {
213
- previewContent = previewFile(this.props);
273
+ if (listType === strings.FILE_LIST_DEFAULT) {
274
+ return (
275
+ <LocaleConsumer componentName="Upload">
276
+ {(locale: Locale["Upload"]) => (this.renderFile(locale))}
277
+ </LocaleConsumer>
278
+ );
214
279
  }
215
- return (
216
- <LocaleConsumer componentName="Upload">
217
- {(locale: Locale['Upload']): ReactNode => (
218
- <div className={fileCardCls} style={style} onClick={onPreviewClick}>
219
- {/* <a target='_blank' href={url} className={infoCls} rel="noopener noreferrer"> */}
220
- <div className={previewCls}>
221
- {previewContent}
222
- </div>
223
- <div className={`${infoCls}-main`}>
224
- <div className={`${infoCls}-main-text`}>
225
- <span className={`${infoCls}-name`}>
226
- {name}
227
- </span>
228
- <span>
229
- <span className={`${infoCls}-size`}>{fileSize}</span>
230
- {showReplace && (
231
- <Tooltip trigger="hover" position="top" showArrow={false} content={locale.replace}>
232
- <IconButton
233
- onClick={(e): void => this.onReplace(e)}
234
- type="tertiary"
235
- theme="borderless"
236
- size="small"
237
- icon={<DirectorySvg />}
238
- className={replaceCls}
239
- />
240
- </Tooltip>
241
- )}
242
280
 
243
- </span>
244
-
245
- </div>
246
- {showProgress ? (<Progress percent={percent} style={{ width: '100%' }} />) : null}
247
- <div className={`${infoCls}-main-control`}>
248
- <span className={`${infoCls}-validate-message`}>
249
- {this.renderValidateMessage()}
250
- </span>
251
- {showRetry ? <span className={`${infoCls}-retry`} onClick={e => this.onRetry(e)}>{locale.retry}</span> : null}
252
- </div>
253
- </div>
254
- {/* </a> */}
255
- <IconButton
256
- onClick={(e): void => this.onRemove(e)}
257
- type="tertiary"
258
- icon={<IconClose />}
259
- theme="borderless"
260
- size="small"
261
- className={closeCls}
262
- />
263
- </div>
264
- )}
265
- </LocaleConsumer>
266
- );
281
+ return null;
267
282
  }
268
283
  }
269
284