@douyinfe/semi-ui 2.1.5 → 2.2.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 (104) 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 +85 -2
  10. package/datePicker/_story/datePicker.stories.js +29 -1
  11. package/datePicker/_story/v2/YearButton.jsx +17 -0
  12. package/datePicker/_story/v2/index.js +1 -0
  13. package/datePicker/monthsGrid.tsx +12 -1
  14. package/datePicker/navigation.tsx +55 -29
  15. package/descriptions/__test__/descriptions.test.js +27 -1
  16. package/descriptions/_story/descriptions.stories.js +52 -2
  17. package/descriptions/item.tsx +1 -1
  18. package/dist/css/semi.css +49 -25
  19. package/dist/css/semi.min.css +1 -1
  20. package/dist/umd/semi-ui.js +839 -253
  21. package/dist/umd/semi-ui.js.map +1 -1
  22. package/dist/umd/semi-ui.min.js +1 -1
  23. package/dist/umd/semi-ui.min.js.map +1 -1
  24. package/empty/index.tsx +2 -2
  25. package/form/_story/form.stories.js +0 -67
  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/monthsGrid.d.ts +1 -0
  34. package/lib/cjs/datePicker/monthsGrid.js +6 -0
  35. package/lib/cjs/datePicker/navigation.js +47 -7
  36. package/lib/cjs/descriptions/item.js +1 -1
  37. package/lib/cjs/empty/index.d.ts +2 -2
  38. package/lib/cjs/empty/index.js +19 -18
  39. package/lib/cjs/form/baseForm.d.ts +5 -0
  40. package/lib/cjs/form/field.d.ts +5 -0
  41. package/lib/cjs/locale/source/es.d.ts +7 -0
  42. package/lib/cjs/locale/source/es.js +168 -0
  43. package/lib/cjs/pagination/index.js +9 -4
  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 +13 -9
  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/upload/fileCard.d.ts +2 -0
  51. package/lib/cjs/upload/fileCard.js +70 -45
  52. package/lib/cjs/upload/index.d.ts +23 -2
  53. package/lib/cjs/upload/index.js +133 -25
  54. package/lib/cjs/upload/interface.d.ts +3 -0
  55. package/lib/es/_utils/index.d.ts +1 -0
  56. package/lib/es/_utils/index.js +12 -5
  57. package/lib/es/cascader/index.d.ts +7 -0
  58. package/lib/es/cascader/index.js +34 -25
  59. package/lib/es/cascader/item.d.ts +2 -0
  60. package/lib/es/cascader/item.js +4 -2
  61. package/lib/es/datePicker/monthsGrid.d.ts +1 -0
  62. package/lib/es/datePicker/monthsGrid.js +6 -0
  63. package/lib/es/datePicker/navigation.js +48 -8
  64. package/lib/es/descriptions/item.js +1 -1
  65. package/lib/es/empty/index.d.ts +2 -2
  66. package/lib/es/empty/index.js +19 -18
  67. package/lib/es/form/baseForm.d.ts +5 -0
  68. package/lib/es/form/field.d.ts +5 -0
  69. package/lib/es/locale/source/es.d.ts +7 -0
  70. package/lib/es/locale/source/es.js +157 -0
  71. package/lib/es/pagination/index.js +8 -4
  72. package/lib/es/rating/item.js +1 -1
  73. package/lib/es/select/index.d.ts +9 -0
  74. package/lib/es/select/index.js +17 -9
  75. package/lib/es/tabs/index.js +1 -5
  76. package/lib/es/timeline/item.d.ts +3 -0
  77. package/lib/es/timeline/item.js +9 -4
  78. package/lib/es/upload/fileCard.d.ts +2 -0
  79. package/lib/es/upload/fileCard.js +69 -44
  80. package/lib/es/upload/index.d.ts +23 -2
  81. package/lib/es/upload/index.js +133 -24
  82. package/lib/es/upload/interface.d.ts +3 -0
  83. package/locale/source/es.ts +160 -0
  84. package/navigation/__test__/navigation.test.js +4 -4
  85. package/navigation/_story/AutoOpen/index.js +1 -1
  86. package/navigation/_story/WithChildren/index.js +1 -1
  87. package/navigation/_story/navigation.stories.js +1 -1
  88. package/navigation/_story/navigation.stories.tsx +4 -4
  89. package/package.json +17 -9
  90. package/pagination/_story/pagination.stories.js +11 -0
  91. package/pagination/index.tsx +9 -4
  92. package/popover/Arrow.tsx +1 -1
  93. package/rating/item.tsx +1 -1
  94. package/select/_story/select.stories.js +39 -14
  95. package/select/index.tsx +18 -7
  96. package/table/_story/DynamicFilters/index.js +13 -16
  97. package/tabs/index.tsx +1 -1
  98. package/timeline/_story/timeline.stories.js +70 -6
  99. package/timeline/item.tsx +7 -2
  100. package/tooltip/_story/tooltip.stories.js +1 -1
  101. package/upload/__test__/upload.test.js +50 -1
  102. package/upload/fileCard.tsx +110 -95
  103. package/upload/index.tsx +147 -53
  104. package/upload/interface.ts +3 -0
@@ -0,0 +1,49 @@
1
+ body[data-page="a11y"] {
2
+ overflow: hidden;
3
+
4
+ #root {
5
+ padding: 0 !important;
6
+
7
+ .semi-slider {
8
+ padding: 0;
9
+ }
10
+
11
+ .rows-container > .semi-row {
12
+ margin-bottom: 24px;
13
+ }
14
+
15
+ .mt12 {
16
+ margin-top: 12px;
17
+ }
18
+
19
+ .mb12 {
20
+ margin-bottom: 12px;
21
+ }
22
+ }
23
+
24
+ .grid {
25
+
26
+ .semi-row,
27
+ .semi-row-flex {
28
+ text-align: center;
29
+
30
+ .semi-col {
31
+ min-height: 30px;
32
+ line-height: 30px;
33
+ background: var(--semi-color-primary-light-default);
34
+ outline: 1px solid var(--semi-color-primary-light-active);
35
+ }
36
+ }
37
+
38
+ &.grid-gutter {
39
+
40
+ .semi-col {
41
+
42
+ .gutter-box,
43
+ .col-content {
44
+ background: var(--semi-color-primary-light-hover);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
@@ -1,6 +1,7 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { Button, Typography, Card, Tooltip, Tag, Avatar, Rating, Nav, Layout } from '../../index';
3
3
  import { IconHelpCircle, IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
4
+ import SemiA11y from './a11y';
4
5
  import './index.scss';
5
6
 
6
7
  export default {
@@ -8,7 +9,8 @@ export default {
8
9
  };
9
10
 
10
11
  export {
11
- TestAlwaysDarkLight
12
+ TestAlwaysDarkLight,
13
+ SemiA11y
12
14
  };
13
15
 
14
16
  const TestAlwaysDarkLight = () => {
package/_utils/index.ts CHANGED
@@ -83,7 +83,7 @@ export const getHighLightTextHTML = ({
83
83
  const markEle = option.highlightTag || 'mark';
84
84
  const highlightClassName = option.highlightClassName || '';
85
85
  const highlightStyle = option.highlightStyle || {};
86
- return chunks.map((chunk: HighLightTextHTMLChunk) => {
86
+ return chunks.map((chunk: HighLightTextHTMLChunk, index: number) => {
87
87
  const { end, start, highlight } = chunk;
88
88
  const text = sourceString.substr(start, end - start);
89
89
  if (highlight) {
@@ -92,6 +92,7 @@ export const getHighLightTextHTML = ({
92
92
  {
93
93
  style: highlightStyle,
94
94
  className: highlightClassName,
95
+ key: text + index
95
96
  },
96
97
  text
97
98
  );
@@ -124,10 +125,14 @@ export const registerMediaQuery = (media: string, { match, unmatch, callInInit =
124
125
  }
125
126
  }
126
127
  callInInit && handlerMediaChange(mediaQueryList);
127
- mediaQueryList.addEventListener('change', handlerMediaChange);
128
- return (): void => mediaQueryList.removeEventListener('change', handlerMediaChange);
128
+ if (Object.prototype.hasOwnProperty.call(mediaQueryList, 'addEventListener')) {
129
+ mediaQueryList.addEventListener('change', handlerMediaChange);
130
+ return (): void => mediaQueryList.removeEventListener('change', handlerMediaChange);
131
+ }
132
+ mediaQueryList.addListener(handlerMediaChange);
133
+ return (): void => mediaQueryList.removeListener(handlerMediaChange);
129
134
  }
130
- return null;
135
+ return () => undefined;
131
136
  };
132
137
  export interface GetHighLightTextHTMLProps {
133
138
  sourceString?: string;
@@ -997,6 +997,149 @@ describe('Cascader', () => {
997
997
  ).toEqual('美国');
998
998
  });
999
999
 
1000
+ it('multiple select enableLeafClick', () => {
1001
+ const cascaderWithMultiple = render({
1002
+ multiple: true,
1003
+ enableLeafClick: true,
1004
+ treeData: [
1005
+ {
1006
+ label: '北美洲',
1007
+ value: 'Beimeizhou',
1008
+ key: 'beimeizhou',
1009
+ children: [
1010
+ {
1011
+ label: '美国',
1012
+ value: 'Meiguo',
1013
+ key: 'meiguo',
1014
+ },
1015
+ {
1016
+ label: '加拿大',
1017
+ value: 'Jianada',
1018
+ key: 'jianada',
1019
+ },
1020
+ ],
1021
+ },
1022
+ {
1023
+ label: '南美洲',
1024
+ value: 'Nanmeiguo',
1025
+ key: 'Nanmeiguo',
1026
+ }
1027
+ ]
1028
+ })
1029
+ const selectBox = cascaderWithMultiple.find(`.${BASE_CLASS_PREFIX}-cascader-selection`).at(0);
1030
+ selectBox.simulate('click');
1031
+ // click checkbox
1032
+ cascaderWithMultiple
1033
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1034
+ .at(0)
1035
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1036
+ .at(1)
1037
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-label`)
1038
+ .at(0)
1039
+ .find(`.${BASE_CLASS_PREFIX}-checkbox`)
1040
+ .at(0)
1041
+ .simulate('click');
1042
+ expect(cascaderWithMultiple.state().checkedKeys.size).toEqual(1);
1043
+ // click option cancel checked
1044
+ cascaderWithMultiple
1045
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1046
+ .at(0)
1047
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1048
+ .at(1)
1049
+ .simulate('click')
1050
+ expect(cascaderWithMultiple.state().checkedKeys.size).toEqual(0);
1051
+ // click option select
1052
+ cascaderWithMultiple
1053
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1054
+ .at(0)
1055
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1056
+ .at(0)
1057
+ .simulate('click')
1058
+ cascaderWithMultiple
1059
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1060
+ .at(1)
1061
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1062
+ .at(0)
1063
+ .simulate('click')
1064
+ expect(cascaderWithMultiple.state().checkedKeys.size).toEqual(1);
1065
+ const states = cascaderWithMultiple.state()
1066
+ cascaderWithMultiple.unmount();
1067
+ })
1068
+
1069
+ it('multiple select disable enableLeafClick', () => {
1070
+ const cascaderWithMultiple = render({
1071
+ multiple: true,
1072
+ treeData: [
1073
+ {
1074
+ label: '北美洲',
1075
+ value: 'Beimeizhou',
1076
+ key: 'beimeizhou',
1077
+ children: [
1078
+ {
1079
+ label: '美国',
1080
+ value: 'Meiguo',
1081
+ key: 'meiguo',
1082
+ },
1083
+ {
1084
+ label: '加拿大',
1085
+ value: 'Jianada',
1086
+ key: 'jianada',
1087
+ },
1088
+ ],
1089
+ },
1090
+ {
1091
+ label: '南美洲',
1092
+ value: 'Nanmeiguo',
1093
+ key: 'Nanmeiguo',
1094
+ }
1095
+ ]
1096
+ })
1097
+ const selectBox = cascaderWithMultiple.find(`.${BASE_CLASS_PREFIX}-cascader-selection`).at(0);
1098
+ selectBox.simulate('click');
1099
+ // click checkbox
1100
+ cascaderWithMultiple
1101
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1102
+ .at(0)
1103
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1104
+ .at(1)
1105
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-label`)
1106
+ .at(0)
1107
+ .find(`.${BASE_CLASS_PREFIX}-checkbox`)
1108
+ .at(0)
1109
+ .simulate('click');
1110
+ expect(cascaderWithMultiple.state().checkedKeys.size).toEqual(1);
1111
+ // click option can't cancel checked
1112
+ cascaderWithMultiple
1113
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list`)
1114
+ .at(0)
1115
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option`)
1116
+ .at(1)
1117
+ .simulate('click')
1118
+ expect(cascaderWithMultiple.state().checkedKeys.size).toEqual(1);
1119
+ cascaderWithMultiple.unmount();
1120
+ })
1121
+
1122
+ it('separator', () => {
1123
+ const cascader = render({
1124
+ filterTreeNode: true,
1125
+ defaultValue: ['Yazhou', 'Zhongguo', 'Beijing'],
1126
+ separator: ' > ',
1127
+ defaultOpen: true,
1128
+ });
1129
+ const input = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection input`);
1130
+ expect(input.props().placeholder).toEqual('亚洲 > 中国 > 北京');
1131
+ const event = { target: { value: '中国' } };
1132
+ input.simulate('change', event);
1133
+ expect(
1134
+ cascader
1135
+ .find(`.${BASE_CLASS_PREFIX}-cascader-option-list li`)
1136
+ .at(0)
1137
+ .getDOMNode()
1138
+ .textContent
1139
+ ).toEqual('亚洲 > 中国 > 北京');
1140
+ cascader.unmount();
1141
+ });
1142
+
1000
1143
  it('triggerRender', () => {
1001
1144
  const spyTriggerRender = sinon.spy(() => <span>123</span>);
1002
1145
  const cascaderAutoMerge = render({
@@ -1027,4 +1170,82 @@ describe('Cascader', () => {
1027
1170
  expect(args2.value).toEqual(new Set(['0','0-0','0-0-1','0-0-0']));
1028
1171
  cascaderNoAutoMerge.unmount();
1029
1172
  });
1173
+
1174
+ it('autoMergeValue', () => {
1175
+ const cascader = render({
1176
+ multiple: true,
1177
+ autoMergeValue: false,
1178
+ defaultValue: 'Yazhou',
1179
+ });
1180
+ const tags = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1181
+ expect(tags.length).toEqual(4);
1182
+ cascader.unmount();
1183
+
1184
+ const cascaderAutoMerge = render({
1185
+ multiple: true,
1186
+ autoMergeValue: true,
1187
+ defaultValue: 'Yazhou',
1188
+ });
1189
+ const tags2 = cascaderAutoMerge.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1190
+ expect(tags2.length).toEqual(1);
1191
+ expect(
1192
+ tags2
1193
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
1194
+ .getDOMNode()
1195
+ .textContent
1196
+ ).toEqual('亚洲');
1197
+ cascaderAutoMerge.unmount();
1198
+ });
1199
+
1200
+ it('leafOnly', () => {
1201
+ /* autoMergeValue and leafOnly are both false */
1202
+ const cascader = render({
1203
+ multiple: true,
1204
+ autoMergeValue: false,
1205
+ leafOnly: false,
1206
+ defaultValue: 'Yazhou',
1207
+ });
1208
+ const tags = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1209
+ expect(tags.length).toEqual(4);
1210
+ cascader.unmount();
1211
+
1212
+ /* autoMergeValue and leafOnly are both true */
1213
+ const cascader2 = render({
1214
+ multiple: true,
1215
+ autoMergeValue: true,
1216
+ leafOnly: true,
1217
+ defaultValue: 'Yazhou',
1218
+ });
1219
+ const tags2 = cascader2.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1220
+ expect(tags2.length).toEqual(2);
1221
+ cascader2.unmount();
1222
+
1223
+ /* autoMergeValue is false, leafOnly is true */
1224
+ const cascader3 = render({
1225
+ multiple: true,
1226
+ autoMergeValue: false,
1227
+ leafOnly: true,
1228
+ defaultValue: 'Yazhou',
1229
+ });
1230
+ const tags3 = cascader3.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1231
+ expect(tags3.length).toEqual(2);
1232
+ cascader3.unmount();
1233
+
1234
+ /* autoMergeValue is true, leafOnly is false */
1235
+ const cascader4 = render({
1236
+ multiple: true,
1237
+ autoMergeValue: true,
1238
+ leafOnly: false,
1239
+ defaultValue: 'Yazhou',
1240
+ });
1241
+ const tags4 = cascader4.find(`.${BASE_CLASS_PREFIX}-cascader-selection .${BASE_CLASS_PREFIX}-tag`)
1242
+ expect(tags4.length).toEqual(1);
1243
+ expect(
1244
+ tags4
1245
+ .find(`.${BASE_CLASS_PREFIX}-tag-content`)
1246
+ .getDOMNode()
1247
+ .textContent
1248
+ ).toEqual('亚洲');
1249
+ cascader4.unmount();
1250
+ });
1030
1251
  });
@@ -273,6 +273,25 @@ export const _Cascader = () => {
273
273
  />
274
274
  <br />
275
275
  <br />
276
+ <Cascader
277
+ style={{ width: 300 }}
278
+ treeData={treeData1}
279
+ placeholder="Multiple select"
280
+ multiple
281
+ motion={false}
282
+ />
283
+ <br />
284
+ <br />
285
+ <Cascader
286
+ style={{ width: 300 }}
287
+ treeData={treeData1}
288
+ placeholder="Multiple select enableLeafClick"
289
+ multiple
290
+ enableLeafClick
291
+ motion={false}
292
+ />
293
+ <br />
294
+ <br />
276
295
  <Cascader
277
296
  style={{ width: 300 }}
278
297
  treeData={[]}
@@ -374,6 +393,23 @@ export const Disabled = () => {
374
393
  filterTreeNode
375
394
  disabled
376
395
  />
396
+ <br /><br />
397
+ <Cascader
398
+ defaultValue={['yazhou', 'zhongguo']}
399
+ style={{ width: 300 }}
400
+ treeData={treeData2}
401
+ multiple
402
+ filterTreeNode
403
+ disabled
404
+ />
405
+ <br /><br />
406
+ <Cascader
407
+ defaultValue={['yazhou', 'zhongguo']}
408
+ style={{ width: 300 }}
409
+ treeData={treeData2}
410
+ multiple
411
+ disabled
412
+ />
377
413
  </div>
378
414
  );
379
415
  };
@@ -420,6 +456,20 @@ export const DisabledOption = () => {
420
456
  defaultValue={['yazhou', 'riben']}
421
457
  placeholder="Japan node is disabled"
422
458
  />
459
+ <br />
460
+ <br />
461
+ <div>multiple selection + filterTreeNode + defaultValue is disabled option</div>
462
+ <Cascader
463
+ filterTreeNode
464
+ multiple
465
+ style={{ width: 300 }}
466
+ treeData={treeData2}
467
+ defaultValue={[
468
+ ['yazhou', 'riben'],
469
+ ['beimeizhou', 'jianada']
470
+ ]}
471
+ placeholder="Japan node is disabled"
472
+ />
423
473
  </div>
424
474
  );
425
475
  };
@@ -1211,3 +1261,91 @@ export const OnChangeWithObject = () => (
1211
1261
  />
1212
1262
  </>
1213
1263
  );
1264
+
1265
+ export const LeafOnly = () => {
1266
+ const [value, setValue] = useState([])
1267
+ return (
1268
+ <div>
1269
+ <div>autoMergeValue=false,leafOnly=false</div>
1270
+ <Cascader
1271
+ style={{ width: 300 }}
1272
+ treeData={treeData4}
1273
+ placeholder="请选择所在地区"
1274
+ multiple
1275
+ autoMergeValue={false}
1276
+ leafOnly={false}
1277
+ defaultValue={['zhejiang']}
1278
+ />
1279
+ <br />
1280
+ <br />
1281
+ <div>autoMergeValue=false,leafOnly=true, leafOnly生效</div>
1282
+ <Cascader
1283
+ style={{ width: 300 }}
1284
+ treeData={treeData4}
1285
+ placeholder="请选择所在地区"
1286
+ multiple
1287
+ autoMergeValue={false}
1288
+ leafOnly={true}
1289
+ defaultValue={['zhejiang']}
1290
+ />
1291
+ <br />
1292
+ <br />
1293
+ <div>受控,autoMergeValue=false,leafOnly=true, leafOnly生效</div>
1294
+ <Cascader
1295
+ style={{ width: 300 }}
1296
+ treeData={treeData4}
1297
+ placeholder="请选择所在地区"
1298
+ multiple
1299
+ onChange={v=>{
1300
+ console.log(v);
1301
+ setValue(v)
1302
+ }}
1303
+ autoMergeValue={false}
1304
+ leafOnly={true}
1305
+ value={value}
1306
+ />
1307
+ <br />
1308
+ <br />
1309
+ <div>受控 onChangeWithObject, autoMergeValue=false,leafOnly=true, leafOnly生效</div>
1310
+ <Cascader
1311
+ style={{ width: 300 }}
1312
+ treeData={treeData4}
1313
+ placeholder="请选择所在地区"
1314
+ multiple
1315
+ onChange={v=>{
1316
+ console.log(v);
1317
+ setValue(v)
1318
+ }}
1319
+ onChangeWithObject
1320
+ autoMergeValue={false}
1321
+ leafOnly={true}
1322
+ value={value}
1323
+ />
1324
+ <br />
1325
+ <br />
1326
+ <div>autoMergeValue=true,leafOnly=false</div>
1327
+ <Cascader
1328
+ style={{ width: 300 }}
1329
+ treeData={treeData4}
1330
+ placeholder="请选择所在地区"
1331
+ multiple
1332
+ autoMergeValue={true}
1333
+ leafOnly={false}
1334
+ defaultValue={['zhejiang']}
1335
+ />
1336
+ <br />
1337
+ <br />
1338
+ <br />
1339
+ <div>autoMergeValue=true,leafOnly=true</div>
1340
+ <Cascader
1341
+ style={{ width: 300 }}
1342
+ treeData={treeData4}
1343
+ placeholder="请选择所在地区"
1344
+ multiple
1345
+ autoMergeValue={true}
1346
+ leafOnly={true}
1347
+ defaultValue={['zhejiang']}
1348
+ />
1349
+ </div>
1350
+ );
1351
+ }
@@ -14,10 +14,10 @@ import CascaderFoundation, {
14
14
  } from '@douyinfe/semi-foundation/cascader/foundation';
15
15
  import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
16
16
  import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
17
- import { isEqual, isString, isEmpty, isFunction, isNumber, noop } from 'lodash';
17
+ import { isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten } from 'lodash';
18
18
  import '@douyinfe/semi-foundation/cascader/cascader.scss';
19
19
  import { IconClear, IconChevronDown } from '@douyinfe/semi-icons';
20
- import { findKeysForValues, convertDataToEntities } from '@douyinfe/semi-foundation/cascader/util';
20
+ import { findKeysForValues, convertDataToEntities, calcMergeType } from '@douyinfe/semi-foundation/cascader/util';
21
21
  import { calcCheckedKeys, normalizeKeyList, calcDisabledKeys } from '@douyinfe/semi-foundation/tree/treeUtil';
22
22
  import ConfigContext from '../configProvider/context';
23
23
  import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
@@ -143,15 +143,19 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
143
143
  showRestTagsPopover: PropTypes.bool,
144
144
  restTagsPopoverProps: PropTypes.object,
145
145
  max: PropTypes.number,
146
+ separator: PropTypes.string,
146
147
  onExceed: PropTypes.func,
147
148
  onClear: PropTypes.func,
148
149
  loadData: PropTypes.func,
149
150
  onLoad: PropTypes.func,
150
151
  loadedKeys: PropTypes.array,
151
152
  disableStrictly: PropTypes.bool,
153
+ leafOnly: PropTypes.bool,
154
+ enableLeafClick: PropTypes.bool,
152
155
  };
153
156
 
154
157
  static defaultProps = {
158
+ leafOnly: false,
155
159
  arrowIcon: <IconChevronDown />,
156
160
  stopPropagation: true,
157
161
  motion: true,
@@ -168,6 +172,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
168
172
  filterLeafOnly: true,
169
173
  showRestTagsPopover: false,
170
174
  restTagsPopoverProps: {},
175
+ separator: ' / ',
171
176
  size: 'default' as const,
172
177
  treeNodeFilterProp: 'label' as const,
173
178
  displayProp: 'label' as const,
@@ -177,6 +182,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
177
182
  onClear: noop,
178
183
  onDropdownVisibleChange: noop,
179
184
  onListScroll: noop,
185
+ enableLeafClick: false,
180
186
  };
181
187
 
182
188
  options: any;
@@ -185,6 +191,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
185
191
  triggerRef: React.RefObject<HTMLDivElement>;
186
192
  optionsRef: React.RefObject<any>;
187
193
  clickOutsideHandler: any;
194
+ mergeType: string;
188
195
 
189
196
  constructor(props: CascaderProps) {
190
197
  super(props);
@@ -215,8 +222,8 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
215
222
  checkedKeys: new Set([]),
216
223
  /* Key of half checked node, when multiple */
217
224
  halfCheckedKeys: new Set([]),
218
- /* Auto merged checkedKeys, when multiple */
219
- mergedCheckedKeys: new Set([]),
225
+ /* Auto merged checkedKeys or leaf checkedKeys, when multiple */
226
+ resolvedCheckedKeys: new Set([]),
220
227
  /* Keys of loaded item */
221
228
  loadedKeys: new Set(),
222
229
  /* Keys of loading item */
@@ -226,6 +233,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
226
233
  };
227
234
  this.options = {};
228
235
  this.isEmpty = false;
236
+ this.mergeType = calcMergeType(props.autoMergeValue, props.leafOnly);
229
237
  this.inputRef = React.createRef();
230
238
  this.triggerRef = React.createRef();
231
239
  this.optionsRef = React.createRef();
@@ -346,7 +354,9 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
346
354
  multiple,
347
355
  value,
348
356
  defaultValue,
349
- onChangeWithObject
357
+ onChangeWithObject,
358
+ leafOnly,
359
+ autoMergeValue,
350
360
  } = props;
351
361
  const { prevProps } = prevState;
352
362
  let keyEntities = prevState.keyEntities || {};
@@ -402,21 +412,18 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
402
412
  });
403
413
  realKeys = formatKeys;
404
414
  }
405
- let checkedKeys = new Set([]);
406
- let halfCheckedKeys = new Set([]);
407
- realKeys.forEach(v => {
408
- const calRes = calcCheckedKeys(v, keyEntities);
409
- checkedKeys = new Set([...checkedKeys, ...calRes.checkedKeys]);
410
- halfCheckedKeys = new Set([...halfCheckedKeys, ...calRes.halfCheckedKeys]);
411
- });
415
+ const calRes = calcCheckedKeys(flatten(realKeys as string[]), keyEntities);
416
+ const checkedKeys = new Set(calRes.checkedKeys);
417
+ const halfCheckedKeys = new Set(calRes.halfCheckedKeys);
412
418
  // disableStrictly
413
419
  if (props.disableStrictly) {
414
420
  newState.disabledKeys = calcDisabledKeys(keyEntities);
415
421
  }
422
+ const isLeafOnlyMerge = calcMergeType(autoMergeValue, leafOnly) === strings.LEAF_ONLY_MERGE_TYPE;
416
423
  newState.prevProps = props;
417
424
  newState.checkedKeys = checkedKeys;
418
425
  newState.halfCheckedKeys = halfCheckedKeys;
419
- newState.mergedCheckedKeys = new Set(normalizeKeyList(checkedKeys, keyEntities));
426
+ newState.resolvedCheckedKeys = new Set(normalizeKeyList(checkedKeys, keyEntities, isLeafOnlyMerge));
420
427
  }
421
428
  }
422
429
  return newState;
@@ -493,7 +500,6 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
493
500
  const {
494
501
  size,
495
502
  disabled,
496
- autoMergeValue,
497
503
  placeholder,
498
504
  maxTagCount,
499
505
  showRestTagsPopover,
@@ -503,11 +509,13 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
503
509
  inputValue,
504
510
  checkedKeys,
505
511
  keyEntities,
506
- mergedCheckedKeys
512
+ resolvedCheckedKeys
507
513
  } = this.state;
508
514
  const tagInputcls = cls(`${prefixcls}-tagInput-wrapper`);
509
515
  const tagValue: Array<Array<string>> = [];
510
- const realKeys = autoMergeValue ? mergedCheckedKeys : checkedKeys;
516
+ const realKeys = this.mergeType === strings.NONE_MERGE_TYPE
517
+ ? checkedKeys
518
+ : resolvedCheckedKeys;
511
519
  [...realKeys].forEach(checkedKey => {
512
520
  if (!isEmpty(keyEntities[checkedKey])) {
513
521
  tagValue.push(keyEntities[checkedKey].valuePath);
@@ -592,6 +600,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
592
600
  dropdownStyle,
593
601
  loadData,
594
602
  emptyContent,
603
+ separator,
595
604
  topSlot,
596
605
  bottomSlot,
597
606
  showNext,
@@ -606,6 +615,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
606
615
  <Item
607
616
  activeKeys={activeKeys}
608
617
  selectedKeys={selectedKeys}
618
+ separator={separator}
609
619
  loadedKeys={loadedKeys}
610
620
  loadingKeys={loadingKeys}
611
621
  onItemClick={this.handleItemClick}
@@ -658,8 +668,10 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
658
668
 
659
669
  renderMultipleTags = () => {
660
670
  const { autoMergeValue, maxTagCount } = this.props;
661
- const { checkedKeys, mergedCheckedKeys } = this.state;
662
- const realKeys = autoMergeValue ? mergedCheckedKeys : checkedKeys;
671
+ const { checkedKeys, resolvedCheckedKeys } = this.state;
672
+ const realKeys = this.mergeType === strings.NONE_MERGE_TYPE
673
+ ? checkedKeys
674
+ : resolvedCheckedKeys;
663
675
  const displayTag: Array<ReactNode> = [];
664
676
  const hiddenTag: Array<ReactNode> = [];
665
677
  [...realKeys].forEach((checkedKey, idx) => {
@@ -729,11 +741,15 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
729
741
  };
730
742
 
731
743
  renderCustomTrigger = () => {
732
- const { disabled, triggerRender, multiple, autoMergeValue } = this.props;
733
- const { selectedKeys, inputValue, inputPlaceHolder, mergedCheckedKeys, checkedKeys } = this.state;
744
+ const { disabled, triggerRender, multiple } = this.props;
745
+ const { selectedKeys, inputValue, inputPlaceHolder, resolvedCheckedKeys, checkedKeys } = this.state;
734
746
  let realValue;
735
747
  if (multiple) {
736
- realValue = autoMergeValue ? mergedCheckedKeys : checkedKeys;
748
+ if (this.mergeType === strings.NONE_MERGE_TYPE) {
749
+ realValue = checkedKeys;
750
+ } else {
751
+ realValue = resolvedCheckedKeys;
752
+ }
737
753
  } else {
738
754
  realValue = [...selectedKeys][0];
739
755
  }