@douyinfe/semi-ui 2.1.6-alpha.0 → 2.2.1

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 (97) hide show
  1. package/_base/_story/a11y.jsx +1302 -0
  2. package/_base/_story/a11y.scss +49 -0
  3. package/_base/_story/index.stories.js +3 -1
  4. package/_utils/index.ts +9 -4
  5. package/cascader/__test__/cascader.test.js +221 -0
  6. package/cascader/_story/cascader.stories.js +138 -0
  7. package/cascader/index.tsx +37 -21
  8. package/cascader/item.tsx +4 -2
  9. package/datePicker/__test__/datePicker.test.js +100 -2
  10. package/datePicker/_story/datePicker.stories.js +90 -1
  11. package/datePicker/_story/v2/YearButton.jsx +17 -0
  12. package/datePicker/_story/v2/index.js +1 -0
  13. package/datePicker/datePicker.tsx +3 -0
  14. package/datePicker/monthsGrid.tsx +12 -1
  15. package/datePicker/navigation.tsx +55 -29
  16. package/descriptions/__test__/descriptions.test.js +27 -1
  17. package/descriptions/_story/descriptions.stories.js +52 -2
  18. package/descriptions/item.tsx +1 -1
  19. package/dist/css/semi.css +72 -28
  20. package/dist/css/semi.min.css +1 -1
  21. package/dist/umd/semi-ui.js +1086 -468
  22. package/dist/umd/semi-ui.js.map +1 -1
  23. package/dist/umd/semi-ui.min.js +1 -1
  24. package/dist/umd/semi-ui.min.js.map +1 -1
  25. package/empty/index.tsx +2 -2
  26. package/gulpfile.js +2 -1
  27. package/lib/cjs/_utils/index.d.ts +1 -0
  28. package/lib/cjs/_utils/index.js +12 -5
  29. package/lib/cjs/cascader/index.d.ts +7 -0
  30. package/lib/cjs/cascader/index.js +35 -22
  31. package/lib/cjs/cascader/item.d.ts +2 -0
  32. package/lib/cjs/cascader/item.js +4 -2
  33. package/lib/cjs/datePicker/datePicker.js +4 -0
  34. package/lib/cjs/datePicker/monthsGrid.d.ts +1 -0
  35. package/lib/cjs/datePicker/monthsGrid.js +6 -0
  36. package/lib/cjs/datePicker/navigation.js +47 -7
  37. package/lib/cjs/descriptions/item.js +1 -1
  38. package/lib/cjs/empty/index.d.ts +2 -2
  39. package/lib/cjs/empty/index.js +19 -18
  40. package/lib/cjs/form/baseForm.d.ts +6 -1
  41. package/lib/cjs/form/field.d.ts +6 -1
  42. package/lib/cjs/locale/source/es.d.ts +7 -0
  43. package/lib/cjs/locale/source/es.js +168 -0
  44. package/lib/cjs/rating/item.js +1 -1
  45. package/lib/cjs/select/index.d.ts +9 -0
  46. package/lib/cjs/select/index.js +10 -8
  47. package/lib/cjs/tabs/index.js +3 -7
  48. package/lib/cjs/timeline/item.d.ts +3 -0
  49. package/lib/cjs/timeline/item.js +10 -4
  50. package/lib/cjs/typography/title.d.ts +1 -1
  51. package/lib/cjs/upload/fileCard.d.ts +2 -0
  52. package/lib/cjs/upload/fileCard.js +70 -45
  53. package/lib/cjs/upload/index.d.ts +23 -2
  54. package/lib/cjs/upload/index.js +133 -25
  55. package/lib/cjs/upload/interface.d.ts +3 -0
  56. package/lib/es/_utils/index.d.ts +1 -0
  57. package/lib/es/_utils/index.js +12 -5
  58. package/lib/es/cascader/index.d.ts +7 -0
  59. package/lib/es/cascader/index.js +34 -25
  60. package/lib/es/cascader/item.d.ts +2 -0
  61. package/lib/es/cascader/item.js +4 -2
  62. package/lib/es/datePicker/datePicker.js +4 -0
  63. package/lib/es/datePicker/monthsGrid.d.ts +1 -0
  64. package/lib/es/datePicker/monthsGrid.js +6 -0
  65. package/lib/es/datePicker/navigation.js +48 -8
  66. package/lib/es/descriptions/item.js +1 -1
  67. package/lib/es/empty/index.d.ts +2 -2
  68. package/lib/es/empty/index.js +19 -18
  69. package/lib/es/form/baseForm.d.ts +6 -1
  70. package/lib/es/form/field.d.ts +6 -1
  71. package/lib/es/locale/source/es.d.ts +7 -0
  72. package/lib/es/locale/source/es.js +157 -0
  73. package/lib/es/rating/item.js +1 -1
  74. package/lib/es/select/index.d.ts +9 -0
  75. package/lib/es/select/index.js +14 -8
  76. package/lib/es/tabs/index.js +1 -5
  77. package/lib/es/timeline/item.d.ts +3 -0
  78. package/lib/es/timeline/item.js +9 -4
  79. package/lib/es/typography/title.d.ts +1 -1
  80. package/lib/es/upload/fileCard.d.ts +2 -0
  81. package/lib/es/upload/fileCard.js +69 -44
  82. package/lib/es/upload/index.d.ts +23 -2
  83. package/lib/es/upload/index.js +133 -24
  84. package/lib/es/upload/interface.d.ts +3 -0
  85. package/locale/source/es.ts +160 -0
  86. package/package.json +9 -9
  87. package/popover/Arrow.tsx +1 -1
  88. package/rating/item.tsx +1 -1
  89. package/select/_story/select.stories.js +25 -0
  90. package/select/index.tsx +17 -6
  91. package/tabs/index.tsx +1 -1
  92. package/timeline/_story/timeline.stories.js +50 -0
  93. package/timeline/item.tsx +7 -2
  94. package/upload/__test__/upload.test.js +50 -1
  95. package/upload/fileCard.tsx +110 -95
  96. package/upload/index.tsx +147 -53
  97. package/upload/interface.ts +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-ui",
3
- "version": "2.1.6-alpha.0",
3
+ "version": "2.2.1",
4
4
  "description": "",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/es/index.js",
@@ -14,11 +14,11 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@babel/runtime-corejs3": "^7.15.4",
17
- "@douyinfe/semi-animation-react": "2.1.5",
18
- "@douyinfe/semi-foundation": "2.1.6-alpha.0",
19
- "@douyinfe/semi-icons": "2.1.6-alpha.0",
20
- "@douyinfe/semi-illustrations": "2.1.5",
21
- "@douyinfe/semi-theme-default": "2.1.5",
17
+ "@douyinfe/semi-animation-react": "2.2.1",
18
+ "@douyinfe/semi-foundation": "2.2.1",
19
+ "@douyinfe/semi-icons": "2.2.1",
20
+ "@douyinfe/semi-illustrations": "2.2.1",
21
+ "@douyinfe/semi-theme-default": "2.2.1",
22
22
  "@types/react-window": "^1.8.2",
23
23
  "async-validator": "^3.5.0",
24
24
  "classnames": "^2.2.6",
@@ -68,13 +68,13 @@
68
68
  ],
69
69
  "author": "",
70
70
  "license": "MIT",
71
- "gitHead": "6721f8e4f803913529db3c51d6d0af5dfe616938",
71
+ "gitHead": "6d8bb9dd22bf199225fa2a0dda4f8524a4b97f6f",
72
72
  "devDependencies": {
73
73
  "@babel/plugin-proposal-decorators": "^7.15.8",
74
74
  "@babel/plugin-transform-runtime": "^7.15.8",
75
75
  "@babel/preset-env": "^7.15.8",
76
76
  "@babel/preset-react": "^7.14.5",
77
- "@douyinfe/semi-scss-compile": "2.1.6-alpha.0",
77
+ "@douyinfe/semi-scss-compile": "2.2.1",
78
78
  "@storybook/addon-knobs": "^6.3.1",
79
79
  "@types/lodash": "^4.14.176",
80
80
  "babel-loader": "^8.2.2",
@@ -99,7 +99,7 @@
99
99
  "react-storybook-addon-props-combinations": "^1.1.0",
100
100
  "react-virtualized": "^9.22.3",
101
101
  "rimraf": "^3.0.2",
102
- "sass": "1.32.13",
102
+ "sass": "1.45.0",
103
103
  "sinon": "^6.3.5",
104
104
  "terser-webpack-plugin": "^4.2.3",
105
105
  "through2": "^4.0.2",
package/popover/Arrow.tsx CHANGED
@@ -55,7 +55,7 @@ const Arrow: React.FC<ArrowProps> = (props = {}) => {
55
55
  <path d="M0 0L1 0C1 4, 2 5.5, 4 7.5S7,10 7,12S6 14.5, 4 16.5S1,20 1,24L0 24L0 0z" fill={bgColor} />
56
56
  </svg>
57
57
  );
58
- }
58
+ };
59
59
 
60
60
  Arrow.propTypes = {
61
61
  position: PropTypes.string,
package/rating/item.tsx CHANGED
@@ -88,7 +88,7 @@ export default class Item extends PureComponent<RatingItemProps> {
88
88
  height: size,
89
89
  fontSize: size
90
90
  } : {};
91
- const iconSize = size === 'small' ? 'default' : 'extra-large';
91
+ const iconSize = isCustomSize ? 'inherit' : (size === 'small' ? 'default' : 'extra-large');
92
92
  const content = character ? character : <IconStar size={iconSize} />;
93
93
  return (
94
94
  <li className={starCls} style={{ ...sizeStyle }}>
@@ -2850,3 +2850,28 @@ export const ScrollIntoView = () => (
2850
2850
  ScrollIntoView.story = {
2851
2851
  name: 'scroll into view',
2852
2852
  };
2853
+
2854
+
2855
+ export const SelectInputPropsDemo = () => {
2856
+
2857
+ const inputProps = {
2858
+ className: 'ttt',
2859
+ onCompositionEnd: (v) => console.log(v.target.value)
2860
+ };
2861
+
2862
+ return (
2863
+ <Select
2864
+ // onSearch={(v) => console.log(v)}
2865
+ optionList={list}
2866
+ inputProps={inputProps}
2867
+ multiple
2868
+ filter
2869
+ style={{ width: 200 }}
2870
+ >
2871
+ </Select>
2872
+ )
2873
+ };
2874
+ SelectInputPropsDemo.story = {
2875
+ name: 'inputProps',
2876
+ };
2877
+
package/select/index.tsx CHANGED
@@ -18,13 +18,14 @@ import { FixedSizeList as List } from 'react-window';
18
18
  import { getOptionsFromGroup } from './utils';
19
19
  import VirtualRow from './virtualRow';
20
20
 
21
- import Input from '../input/index';
21
+ import Input, { InputProps } from '../input/index';
22
22
  import Option, { OptionProps } from './option';
23
23
  import OptionGroup from './optionGroup';
24
24
  import Spin from '../spin';
25
25
  import Trigger from '../trigger';
26
26
  import { IconChevronDown, IconClear } from '@douyinfe/semi-icons';
27
27
  import { isSemiIcon } from '../_utils';
28
+ import { Subtract } from 'utility-types';
28
29
 
29
30
  import warning from '@douyinfe/semi-foundation/utils/warning';
30
31
 
@@ -40,6 +41,12 @@ const prefixcls = cssClasses.PREFIX;
40
41
 
41
42
  const key = 0;
42
43
 
44
+ type ExcludeInputType = {
45
+ value?: InputProps['value'];
46
+ onFocus?: InputProps['onFocus'];
47
+ onChange?: InputProps['onChange'];
48
+ }
49
+
43
50
  type OnChangeValueType = string | number | Record<string, any>;
44
51
  export interface optionRenderProps {
45
52
  key?: any;
@@ -115,6 +122,7 @@ export type SelectProps = {
115
122
  suffix?: React.ReactNode;
116
123
  prefix?: React.ReactNode;
117
124
  insetLabel?: React.ReactNode;
125
+ inputProps?: Subtract<InputProps, ExcludeInputType>;
118
126
  showClear?: boolean;
119
127
  showArrow?: boolean;
120
128
  renderSelectedItem?: RenderSelectedItemFn;
@@ -200,6 +208,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
200
208
  dropdownStyle: PropTypes.object,
201
209
  outerTopSlot: PropTypes.node,
202
210
  innerTopSlot: PropTypes.node,
211
+ inputProps: PropTypes.object,
203
212
  outerBottomSlot: PropTypes.node,
204
213
  innerBottomSlot: PropTypes.node, // Options slot
205
214
  optionList: PropTypes.array,
@@ -558,18 +567,20 @@ class Select extends BaseComponent<SelectProps, SelectState> {
558
567
  handleInputChange = (value: string) => this.foundation.handleInputChange(value);
559
568
 
560
569
  renderInput() {
561
- const { size, multiple, disabled } = this.props;
570
+ const { size, multiple, disabled, inputProps } = this.props;
571
+ const inputPropsCls = get(inputProps, 'className');
562
572
  const inputcls = cls(`${prefixcls}-input`, {
563
573
  [`${prefixcls}-input-single`]: !multiple,
564
574
  [`${prefixcls}-input-multiple`]: multiple,
565
- });
575
+ }, inputPropsCls);
566
576
  const { inputValue } = this.state;
567
577
 
568
- const inputProps: Record<string, any> = {
578
+ const selectInputProps: Record<string, any> = {
569
579
  value: inputValue,
570
580
  disabled,
571
581
  className: inputcls,
572
582
  onChange: this.handleInputChange,
583
+ ...inputProps,
573
584
  };
574
585
 
575
586
  let style = {};
@@ -578,18 +589,18 @@ class Select extends BaseComponent<SelectProps, SelectState> {
578
589
  style = {
579
590
  width: inputValue ? `${inputValue.length * 16}px` : '2px',
580
591
  };
581
- inputProps.style = style;
592
+ selectInputProps.style = style;
582
593
  }
583
594
  return (
584
595
  <Input
585
596
  ref={this.inputRef as any}
586
597
  size={size}
587
- {...inputProps}
588
598
  onFocus={(e: React.FocusEvent<HTMLInputElement>) => {
589
599
  // prevent event bubbling which will fire trigger onFocus event
590
600
  e.stopPropagation();
591
601
  // e.nativeEvent.stopImmediatePropagation();
592
602
  }}
603
+ {...selectInputProps}
593
604
  />
594
605
  );
595
606
  }
package/tabs/index.tsx CHANGED
@@ -15,7 +15,7 @@ import TabPane from './TabPane';
15
15
  import TabsContext from './tabs-context';
16
16
  import { TabsProps, PlainTab, TabBarProps } from './interface';
17
17
 
18
- const panePickKeys = Object.keys(omit(TabPane.propTypes, ['children']));
18
+ const panePickKeys = ['className', 'style', 'disabled', 'itemKey', 'tab', 'icon'];
19
19
 
20
20
  export * from './interface';
21
21
 
@@ -183,3 +183,53 @@ export const DataSource = () => (
183
183
  DataSource.story = {
184
184
  name: 'dataSource',
185
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,5 +1,6 @@
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';
@@ -13,6 +14,7 @@ export interface TimelineItemProps {
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;
@@ -27,11 +29,13 @@ export default class Item extends PureComponent<TimelineItemProps> {
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}
@@ -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