@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/cascader/item.tsx CHANGED
@@ -54,6 +54,7 @@ export interface CascaderItemProps {
54
54
  emptyContent: React.ReactNode;
55
55
  loadData: (selectOptions: CascaderData[]) => Promise<void>;
56
56
  data: Array<Data | Entity>;
57
+ separator: string;
57
58
  multiple: boolean;
58
59
  checkedKeys: Set<string>;
59
60
  halfCheckedKeys: Set<string>;
@@ -75,6 +76,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
75
76
  checkedKeys: PropTypes.object,
76
77
  halfCheckedKeys: PropTypes.object,
77
78
  onItemCheckboxClick: PropTypes.func,
79
+ separator: PropTypes.string,
78
80
  keyword: PropTypes.string
79
81
  };
80
82
 
@@ -142,7 +144,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
142
144
 
143
145
  highlight = (searchText: React.ReactNode[]) => {
144
146
  const content: React.ReactNode[] = [];
145
- const { keyword } = this.props;
147
+ const { keyword, separator } = this.props;
146
148
  searchText.forEach((item, idx) => {
147
149
  if (typeof item === 'string' && includes(item, keyword)) {
148
150
  item.split(keyword).forEach((node, index) => {
@@ -159,7 +161,7 @@ export default class Item extends PureComponent<CascaderItemProps> {
159
161
  content.push(item);
160
162
  }
161
163
  if (idx !== searchText.length - 1) {
162
- content.push(' / ');
164
+ content.push(separator);
163
165
  }
164
166
  });
165
167
  return content;
@@ -191,12 +191,27 @@ describe(`DatePicker`, () => {
191
191
  btns[0].click();
192
192
  await sleep();
193
193
  expect(_.first(elem.state('value')).getDate() === currentValue.getDate()).toBeTruthy();
194
+ expect(_.isEqual(elem.state('cachedSelectedValue'), [currentValue])).toBe(true);
194
195
 
195
196
  /**
196
197
  * click ensure button
197
198
  */
198
199
  btns[1].click();
199
200
  await sleep();
201
+ expect(_.first(elem.state('value')).getDate() === currentValue.getDate()).toBe(true);
202
+
203
+ /**
204
+ * re click next day
205
+ */
206
+ nextOffsetDayElem.click();
207
+ await sleep();
208
+ expect(_.first(elem.state('value')).getDate() === currentValue.getDate()).toBeTruthy();
209
+
210
+ /**
211
+ * re click ensure button
212
+ */
213
+ btns[1].click();
214
+ await sleep();
200
215
  expect(_.first(elem.state('value')).getDate() - currentValue.getDate()).toBe(dayOffset);
201
216
 
202
217
  demo.unmount();
@@ -280,10 +295,12 @@ describe(`DatePicker`, () => {
280
295
  const rightPanel = document.querySelector(`.${BASE_CLASS_PREFIX}-datepicker-month-grid-right`);
281
296
  const rightNavBtns = rightPanel.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-navigation .${BASE_CLASS_PREFIX}-button`);
282
297
 
283
- _.get(rightNavBtns, 1).click();
298
+ // 点击右边面板下一月
299
+ _.get(rightNavBtns, 2).click();
284
300
  await sleep();
285
301
 
286
- _.times(leftPrevClickTimes).forEach(() => _.first(leftNavBtns).click());
302
+ // 点击左边面板上一月
303
+ _.times(leftPrevClickTimes).forEach(() => _.get(leftNavBtns, 1).click());
287
304
 
288
305
  const leftSecondWeek = leftPanel.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-week`)[1];
289
306
  const leftSecondWeekDays = leftSecondWeek.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-day`);
@@ -870,4 +887,85 @@ describe(`DatePicker`, () => {
870
887
  expect(allSeparators[0].textContent.trim()).toBe(rangeSeparator);
871
888
  expect(allSeparators[1].textContent.trim()).toBe(rangeSeparator);
872
889
  });
890
+
891
+ /**
892
+ * fix https://github.com/DouyinFE/semi-design/issues/422
893
+ */
894
+ it('test input year length larger than 4', async () => {
895
+ const props = {
896
+ motion: false,
897
+ defaultOpen: true,
898
+ defaultValue: '2021-12-21',
899
+ };
900
+ const handleChange = sinon.spy();
901
+ const elem = mount(
902
+ <DatePicker {...props} onChange={handleChange} />
903
+ );
904
+
905
+ elem.find('input').simulate('change', { target: { value: '20221-12-21' }});
906
+ expect(handleChange.called).toBeFalsy();
907
+ });
908
+
909
+ it('test click next/prev year buttons', () => {
910
+ let props = {
911
+ type: 'dateRange',
912
+ motion: false,
913
+ style: { width: 300 },
914
+ defaultPickerValue: new Date('2021-12-01'),
915
+ defaultOpen: true,
916
+ };
917
+ const elem = mount(<DatePicker {...props} />);
918
+
919
+ const leftPanel = document.querySelector(`.semi-datepicker-month-grid-left`);
920
+ const leftNavBtns = leftPanel.querySelector(`.semi-datepicker-navigation`).children;
921
+ const rightPanel = document.querySelector(`.semi-datepicker-month-grid-right`);
922
+ const rightNavBtns = rightPanel.querySelector(`.semi-datepicker-navigation`).children;
923
+
924
+ // 点击左边面板上一年
925
+ _.get(leftNavBtns, 0).click();
926
+ expect(document.querySelector(`.semi-datepicker-month-grid-left .semi-datepicker-navigation-month`).textContent).toBe('2020年 12月');
927
+ // 点击左边面板下一年
928
+ _.get(leftNavBtns, 4).click();
929
+ expect(document.querySelector(`.semi-datepicker-month-grid-left .semi-datepicker-navigation-month`).textContent).toBe('2021年 12月');
930
+
931
+ // 点击右边面板下一年
932
+ _.get(rightNavBtns, 4).click();
933
+ expect(document.querySelector(`.semi-datepicker-month-grid-right .semi-datepicker-navigation-month`).textContent).toBe('2023年 1月');
934
+ // 点击右边面板上一年
935
+ _.get(rightNavBtns, 0).click();
936
+ expect(document.querySelector(`.semi-datepicker-month-grid-right .semi-datepicker-navigation-month`).textContent).toBe('2022年 1月');
937
+ });
938
+
939
+ const testMonthSyncChange = type => {
940
+ let props = {
941
+ type,
942
+ motion: false,
943
+ style: { width: 300 },
944
+ defaultPickerValue: new Date('2021-12-01'),
945
+ defaultOpen: true,
946
+ };
947
+ const elem = mount(<DatePicker {...props} />);
948
+
949
+ const leftPanel = document.querySelector(`.semi-datepicker-month-grid-left`);
950
+ const leftNavBtns = leftPanel.querySelector(`.semi-datepicker-navigation`).children;
951
+ const rightPanel = document.querySelector(`.semi-datepicker-month-grid-right`);
952
+ const rightNavBtns = rightPanel.querySelector(`.semi-datepicker-navigation`).children;
953
+
954
+ // 点击左边面板下一月,自动切换右面板
955
+ _.get(leftNavBtns, 3).click();
956
+ expect(document.querySelector(`.semi-datepicker-month-grid-left .semi-datepicker-navigation-month`).textContent).toBe('2022年 1月');
957
+ expect(document.querySelector(`.semi-datepicker-month-grid-right .semi-datepicker-navigation-month`).textContent).toBe('2022年 2月');
958
+ // 点击右边面板上一月,自动切换左面板
959
+ _.get(rightNavBtns, 1).click();
960
+ expect(document.querySelector(`.semi-datepicker-month-grid-left .semi-datepicker-navigation-month`).textContent).toBe('2021年 12月');
961
+ expect(document.querySelector(`.semi-datepicker-month-grid-right .semi-datepicker-navigation-month`).textContent).toBe('2022年 1月');
962
+
963
+ // 点击左边面板上一月,不需要自动切换右面板
964
+ _.get(leftNavBtns, 1).click();
965
+ expect(document.querySelector(`.semi-datepicker-month-grid-left .semi-datepicker-navigation-month`).textContent).toBe('2021年 11月');
966
+ elem.unmount();
967
+ }
968
+
969
+ it('test month sync change dateRange type', () => { testMonthSyncChange('dateRange') });
970
+ it('test month sync change dateTimeRange type', () => { testMonthSyncChange('dateTimeRange')});
873
971
  });
@@ -36,6 +36,7 @@ import DatePickerSlot from './DatePickerSlot';
36
36
  import DatePickerTimeZone from './DatePickerTimeZone';
37
37
  import BetterRangePicker from './BetterRangePicker';
38
38
  import SyncSwitchMonth from './SyncSwitchMonth';
39
+ import { YearButton } from './v2';
39
40
 
40
41
  export default {
41
42
  title: 'DatePicker',
@@ -65,7 +66,8 @@ export {
65
66
  DatePickerSlot,
66
67
  DatePickerTimeZone,
67
68
  BetterRangePicker,
68
- SyncSwitchMonth
69
+ SyncSwitchMonth,
70
+ YearButton
69
71
  }
70
72
 
71
73
  const demoDiv = {
@@ -634,3 +636,90 @@ export const RangeSeparator = () => (
634
636
  </div>
635
637
  </Space>
636
638
  );
639
+
640
+ /**
641
+ * 修复输入 '20221-12-20' 类似这种年份的日期会崩溃问题
642
+ * https://github.com/DouyinFE/semi-design/issues/422
643
+ *
644
+ * 非法日期的来源
645
+ * - 用户输入
646
+ * - 受控传入
647
+ * @returns
648
+ */
649
+ export const FixParseISOBug = () => (
650
+ <div>
651
+ <label>
652
+ <div>选择一个合法值,然后输入一个非法年份</div>
653
+ <DatePicker defaultValue={'2021-12-20'} onChange={v => console.log('onChange', v)} />
654
+ </label>
655
+ <label>
656
+ <div>defaultValue='20221-12-20'</div>
657
+ <DatePicker defaultValue={'20221-12-20'} defaultOpen={true} motion={false} onChange={v => console.log('onChange', v)} />
658
+ </label>
659
+ </div>
660
+ );
661
+ FixParseISOBug.storyName = '修复 parseISO bug';
662
+ FixParseISOBug.parameters = {
663
+ chromatic: { disableSnapshot: false },
664
+ };
665
+
666
+ export const FixNeedConfirm = () => {
667
+ const defaultDate = '2021-12-27 10:37:13';
668
+ const defaultDateRange = ['2021-12-27 10:37:13', '2022-01-28 10:37:13' ];
669
+ const props = {
670
+ needConfirm: true,
671
+ onConfirm: (...args) => {
672
+ console.log('Confirmed: ', ...args);
673
+ },
674
+ onChange: (...args) => {
675
+ console.log('Changed: ', ...args);
676
+ },
677
+ onCancel: (...args) => {
678
+ console.log('Canceled: ', ...args);
679
+ },
680
+ };
681
+
682
+ return (
683
+ <div>
684
+ <div data-cy="1">
685
+ <span>dateTime + needConfirm + defaultValue</span>
686
+ <div>
687
+ <DatePicker
688
+ type="dateTime"
689
+ defaultValue={defaultDate}
690
+ {...props}
691
+ />
692
+ </div>
693
+ </div>
694
+ <div data-cy="2">
695
+ <span>dateTime + needConfirm</span>
696
+ <div>
697
+ <DatePicker
698
+ type="dateTime"
699
+ {...props}
700
+ />
701
+ </div>
702
+ </div>
703
+ <div data-cy="3">
704
+ <span>dateTimeRange + needConfirm + defaultValue</span>
705
+ <div>
706
+ <DatePicker
707
+ type="dateTimeRange"
708
+ defaultValue={defaultDateRange}
709
+ {...props}
710
+ />
711
+ </div>
712
+ </div>
713
+ <div data-cy="4">
714
+ <span>dateTimeRange + needConfirm</span>
715
+ <div>
716
+ <DatePicker
717
+ type="dateTimeRange"
718
+ {...props}
719
+ />
720
+ </div>
721
+ </div>
722
+ </div>
723
+ )
724
+ }
725
+ FixNeedConfirm.storyName = '修复 needConfirm 取消后输入框显示错误';
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { DatePicker } from '../../../index';
3
+
4
+ export default function App() {
5
+ return (
6
+ <div>
7
+ <h4>type=date</h4>
8
+ <DatePicker />
9
+ <h4>type=dateRange</h4>
10
+ <DatePicker type="dateRange" defaultPickerValue="2021-12" />
11
+ <h4>type=dateTimeRange</h4>
12
+ <DatePicker type="dateTimeRange" />
13
+ <h4>type=dateRange + compact</h4>
14
+ <DatePicker type="dateRange" density="compact" />
15
+ </div>
16
+ );
17
+ }
@@ -0,0 +1 @@
1
+ export { default as YearButton } from './YearButton';
@@ -206,6 +206,9 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
206
206
  this.clickOutSideHandler = null;
207
207
  }
208
208
  this.clickOutSideHandler = e => {
209
+ if (this.adapter.needConfirm()) {
210
+ return;
211
+ }
209
212
  const triggerEl = this.triggerElRef && this.triggerElRef.current;
210
213
  const panelEl = this.panelRef && this.panelRef.current;
211
214
  const isInTrigger = triggerEl && triggerEl.contains(e.target as Node);
@@ -446,6 +446,10 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
446
446
  });
447
447
  };
448
448
 
449
+ getYAMOpenType = () => {
450
+ return this.foundation.getYAMOpenType();
451
+ }
452
+
449
453
  renderTimePicker(panelType: PanelType, panelDetail: MonthInfo) {
450
454
  const { type, locale, format, hideDisabledOptions, timePickerOpts, dateFnsLocale } = this.props;
451
455
  const { pickerDate } = panelDetail;
@@ -606,8 +610,15 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
606
610
  } else if (type === 'year' || type === 'month') {
607
611
  content = 'year month';
608
612
  }
613
+ const yearOpenType = this.getYAMOpenType();
614
+
609
615
  return (
610
- <div className={monthGridCls} x-type={type} ref={current => this.cacheRefCurrent('monthGrid', current)}>
616
+ <div
617
+ className={monthGridCls}
618
+ x-type={type}
619
+ x-panel-yearandmonth-open-type={yearOpenType}
620
+ ref={current => this.cacheRefCurrent('monthGrid', current)}
621
+ >
611
622
  {content}
612
623
  </div>
613
624
  );
@@ -6,7 +6,7 @@ import { noop } from 'lodash';
6
6
  import IconButton from '../iconButton';
7
7
  import Button from '../button';
8
8
  import { cssClasses, strings } from '@douyinfe/semi-foundation/datePicker/constants';
9
- import { IconChevronLeft, IconChevronRight } from '@douyinfe/semi-icons';
9
+ import { IconChevronLeft, IconChevronRight, IconDoubleChevronLeft, IconDoubleChevronRight } from '@douyinfe/semi-icons';
10
10
  import { PanelType } from '@douyinfe/semi-foundation/datePicker/monthsGridFoundation';
11
11
 
12
12
  const prefixCls = cssClasses.NAVIGATION;
@@ -68,6 +68,8 @@ export default class Navigation extends PureComponent<NavigationProps> {
68
68
  onMonthClick,
69
69
  onNextMonth,
70
70
  onPrevMonth,
71
+ onPrevYear,
72
+ onNextYear,
71
73
  density,
72
74
  shouldBimonthSwitch,
73
75
  panelType
@@ -77,43 +79,67 @@ export default class Navigation extends PureComponent<NavigationProps> {
77
79
  const iconBtnSize = density === 'compact' ? 'default' : 'large';
78
80
  const btnNoHorizontalPadding = true;
79
81
  const buttonSize = density === 'compact' ? 'small' : 'default';
80
- // Enable dual-panel synchronous switching, and the current panel is the left panel
81
- const bimonthSwitchWithLeftPanel = shouldBimonthSwitch && panelType === strings.PANEL_TYPE_LEFT;
82
- // Enable dual-panel synchronous switching, and the current panel is the right panel
83
- const bimonthSwitchWithRightPanel = shouldBimonthSwitch && panelType === strings.PANEL_TYPE_RIGHT;
82
+ const isLeftPanel = panelType === strings.PANEL_TYPE_LEFT;
83
+ const isRightPanel = panelType === strings.PANEL_TYPE_RIGHT;
84
+
85
+ // syncSwitchMonth and the current panel is the left
86
+ const hiddenLeftPanelRightButtons = shouldBimonthSwitch && isLeftPanel;
87
+ // syncSwitchMonth and the current panel is the right
88
+ const hiddenRightPanelLeftButtons = shouldBimonthSwitch && isRightPanel;
89
+ // `visibility: hidden` will keep the icon in position
90
+ const leftButtonStyle: React.CSSProperties = {};
91
+ const rightButtonStyle: React.CSSProperties = {};
92
+ if (hiddenRightPanelLeftButtons) {
93
+ leftButtonStyle.visibility = 'hidden';
94
+ }
95
+ if (hiddenLeftPanelRightButtons) {
96
+ rightButtonStyle.visibility = 'hidden';
97
+ }
84
98
 
85
99
  const ref = forwardRef || this.navRef;
86
100
  return (
87
101
  <div className={prefixCls} ref={ref}>
88
- {
89
- !bimonthSwitchWithRightPanel &&
90
- (
91
- <IconButton
92
- icon={<IconChevronLeft size={iconBtnSize} />}
93
- size={buttonSize}
94
- onClick={onPrevMonth}
95
- theme={btnTheme}
96
- noHorizontalPadding={btnNoHorizontalPadding}
97
- />
98
- )
99
- }
102
+ <IconButton
103
+ key="double-chevron-left"
104
+ icon={<IconDoubleChevronLeft size={iconBtnSize}/>}
105
+ size={buttonSize}
106
+ theme={btnTheme}
107
+ noHorizontalPadding={btnNoHorizontalPadding}
108
+ onClick={onPrevYear}
109
+ style={leftButtonStyle}
110
+ />
111
+ <IconButton
112
+ key="chevron-left"
113
+ icon={<IconChevronLeft size={iconBtnSize} />}
114
+ size={buttonSize}
115
+ onClick={onPrevMonth}
116
+ theme={btnTheme}
117
+ noHorizontalPadding={btnNoHorizontalPadding}
118
+ style={leftButtonStyle}
119
+ />
100
120
  <div className={`${prefixCls}-month`}>
101
121
  <Button onClick={onMonthClick} theme={btnTheme} size={buttonSize}>
102
122
  <span>{monthText}</span>
103
123
  </Button>
104
124
  </div>
105
- {
106
- !bimonthSwitchWithLeftPanel &&
107
- (
108
- <IconButton
109
- icon={<IconChevronRight size={iconBtnSize} />}
110
- size={buttonSize}
111
- onClick={onNextMonth}
112
- theme={btnTheme}
113
- noHorizontalPadding={btnNoHorizontalPadding}
114
- />
115
- )
116
- }
125
+ <IconButton
126
+ key="chevron-right"
127
+ icon={<IconChevronRight size={iconBtnSize} />}
128
+ size={buttonSize}
129
+ onClick={onNextMonth}
130
+ theme={btnTheme}
131
+ noHorizontalPadding={btnNoHorizontalPadding}
132
+ style={rightButtonStyle}
133
+ />
134
+ <IconButton
135
+ key="double-chevron-right"
136
+ icon={<IconDoubleChevronRight size={iconBtnSize}/>}
137
+ size={buttonSize}
138
+ theme={btnTheme}
139
+ noHorizontalPadding={btnNoHorizontalPadding}
140
+ onClick={onNextYear}
141
+ style={rightButtonStyle}
142
+ />
117
143
  </div>
118
144
  );
119
145
  }
@@ -17,6 +17,14 @@ const dataWithHide = [
17
17
  { key: '认证状态', value: '未认证' },
18
18
  ];
19
19
 
20
+ const dataWithKeyIsNode = [
21
+ { key: <strong>实际用户数量</strong>, value: '1,480,000' },
22
+ { key: '7天留存', value: '98%' },
23
+ { key: '安全等级', value: '3级' },
24
+ { key: '垂类标签', value: <Tag>电商</Tag> },
25
+ { key: '认证状态', value: '未认证' },
26
+ ];
27
+
20
28
  function renderDescriptions(props) {
21
29
  const realProps = {
22
30
  data,
@@ -134,7 +142,6 @@ describe('Descriptions', () => {
134
142
  largeDesc.unmount();
135
143
  });
136
144
 
137
-
138
145
  it('Descriptions with jsx', () => {
139
146
  const desc = mount(
140
147
  <Descriptions>
@@ -164,4 +171,23 @@ describe('Descriptions', () => {
164
171
  ).toEqual('1,480,000');
165
172
  desc.unmount();
166
173
  });
174
+
175
+ it('Descriptions with key is node', () => {
176
+ const desc = renderDescriptions({ data: dataWithKeyIsNode });
177
+ expect(
178
+ desc
179
+ .find(`.${BASE_CLASS_PREFIX}-descriptions-key strong`)
180
+ .at(0)
181
+ .getDOMNode()
182
+ .textContent
183
+ ).toEqual('实际用户数量');
184
+ expect(
185
+ desc
186
+ .find(`.${BASE_CLASS_PREFIX}-descriptions-key`)
187
+ .at(1)
188
+ .getDOMNode()
189
+ .textContent
190
+ ).toEqual('7天留存');
191
+ desc.unmount();
192
+ });
167
193
  })
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
- // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
3
-
4
2
  import Descriptions from '../index';
3
+ import Tag from '../../tag';
5
4
 
6
5
  export default {
7
6
  title: 'Descriptions',
@@ -93,3 +92,54 @@ export const DescriptionsItem = () => (
93
92
  </div>
94
93
  );
95
94
 
95
+ export const DescriptionsKeyIsNode = () => {
96
+ const data = [
97
+ { key: <strong style={{color: 'red'}}>实际用户数量</strong>, value: '1,480,000' },
98
+ { key: '7天留存', value: '98%' },
99
+ { key: '安全等级', value: '3级' },
100
+ { key: '垂类标签', value: <Tag style={{ margin: 0 }}>电商</Tag> },
101
+ { key: '认证状态', value: '未认证' },
102
+ ];
103
+ const style = {
104
+ boxShadow: 'var(--shadow-elevated)',
105
+ backgroundColor: 'var(--color-bg-2)',
106
+ borderRadius: '4px',
107
+ padding: '10px',
108
+ margin: '10px',
109
+ width: '200px',
110
+ };
111
+ return (
112
+ <>
113
+ <div>data 传入的写法</div>
114
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
115
+ <Descriptions align="center" data={data} style={style} />
116
+ <Descriptions align="justify" data={data} style={style} />
117
+ <Descriptions align="left" data={data} style={style} />
118
+ <Descriptions align="plain" data={data} style={style} />
119
+ </div>
120
+ <div>JSX 写法</div>
121
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
122
+ <Descriptions style={style} align="center" >
123
+ <Descriptions.Item itemKey={<strong style={{ color: 'red' }}>实际用户数量</strong>}>1,480,000</Descriptions.Item>
124
+ <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
125
+ <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
126
+ </Descriptions>
127
+ <Descriptions style={style} align="justify">
128
+ <Descriptions.Item itemKey={<strong style={{ color: 'red' }}>实际用户数量</strong>}>1,480,000</Descriptions.Item>
129
+ <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
130
+ <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
131
+ </Descriptions>
132
+ <Descriptions style={style} align="left">
133
+ <Descriptions.Item itemKey={<strong style={{ color: 'red' }}>实际用户数量</strong>}>1,480,000</Descriptions.Item>
134
+ <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
135
+ <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
136
+ </Descriptions>
137
+ <Descriptions style={style} align="plain">
138
+ <Descriptions.Item itemKey={<strong style={{ color: 'red' }}>实际用户数量</strong>}>1,480,000</Descriptions.Item>
139
+ <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
140
+ <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
141
+ </Descriptions>
142
+ </div>
143
+ </>
144
+ );
145
+ };
@@ -36,7 +36,7 @@ export default class Item extends PureComponent<DescriptionsItemProps> {
36
36
  <tr className={className} style={style}>
37
37
  <td className={`${prefixCls}-item`}>
38
38
  <span className={keyCls}>
39
- {`${itemKey}:`}
39
+ {itemKey}:
40
40
  </span>
41
41
  <span className={valCls}>
42
42
  {typeof children === 'function' ? children() : children}