@douyinfe/semi-ui 2.2.0-beta.0 → 2.2.2

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 (40) hide show
  1. package/_utils/index.ts +7 -3
  2. package/datePicker/__test__/datePicker.test.js +126 -0
  3. package/datePicker/_story/datePicker.stories.js +171 -1
  4. package/datePicker/datePicker.tsx +5 -0
  5. package/datePicker/monthsGrid.tsx +2 -1
  6. package/dist/css/semi.css +34 -8
  7. package/dist/css/semi.min.css +1 -1
  8. package/dist/umd/semi-ui.js +423 -324
  9. package/dist/umd/semi-ui.js.map +1 -1
  10. package/dist/umd/semi-ui.min.js +1 -1
  11. package/dist/umd/semi-ui.min.js.map +1 -1
  12. package/empty/index.tsx +2 -2
  13. package/gulpfile.js +2 -1
  14. package/inputNumber/_story/inputNumber.stories.js +12 -0
  15. package/inputNumber/index.tsx +5 -1
  16. package/lib/cjs/_utils/index.js +9 -3
  17. package/lib/cjs/datePicker/datePicker.js +8 -2
  18. package/lib/cjs/datePicker/monthsGrid.d.ts +1 -0
  19. package/lib/cjs/datePicker/monthsGrid.js +2 -1
  20. package/lib/cjs/empty/index.d.ts +2 -2
  21. package/lib/cjs/empty/index.js +19 -18
  22. package/lib/cjs/inputNumber/index.d.ts +13 -12
  23. package/lib/cjs/inputNumber/index.js +5 -1
  24. package/lib/cjs/tabs/index.js +3 -7
  25. package/lib/cjs/transfer/index.d.ts +1 -1
  26. package/lib/cjs/transfer/index.js +3 -3
  27. package/lib/es/_utils/index.js +9 -3
  28. package/lib/es/datePicker/datePicker.js +8 -2
  29. package/lib/es/datePicker/monthsGrid.d.ts +1 -0
  30. package/lib/es/datePicker/monthsGrid.js +2 -1
  31. package/lib/es/empty/index.d.ts +2 -2
  32. package/lib/es/empty/index.js +19 -18
  33. package/lib/es/inputNumber/index.d.ts +13 -12
  34. package/lib/es/inputNumber/index.js +5 -1
  35. package/lib/es/tabs/index.js +1 -5
  36. package/lib/es/transfer/index.d.ts +1 -1
  37. package/lib/es/transfer/index.js +3 -3
  38. package/package.json +9 -9
  39. package/tabs/index.tsx +1 -1
  40. package/transfer/index.tsx +3 -3
package/_utils/index.ts CHANGED
@@ -125,10 +125,14 @@ export const registerMediaQuery = (media: string, { match, unmatch, callInInit =
125
125
  }
126
126
  }
127
127
  callInInit && handlerMediaChange(mediaQueryList);
128
- mediaQueryList.addEventListener('change', handlerMediaChange);
129
- 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);
130
134
  }
131
- return null;
135
+ return () => undefined;
132
136
  };
133
137
  export interface GetHighLightTextHTMLProps {
134
138
  sourceString?: string;
@@ -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();
@@ -873,6 +888,24 @@ describe(`DatePicker`, () => {
873
888
  expect(allSeparators[1].textContent.trim()).toBe(rangeSeparator);
874
889
  });
875
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
+
876
909
  it('test click next/prev year buttons', () => {
877
910
  let props = {
878
911
  type: 'dateRange',
@@ -935,4 +968,97 @@ describe(`DatePicker`, () => {
935
968
 
936
969
  it('test month sync change dateRange type', () => { testMonthSyncChange('dateRange') });
937
970
  it('test month sync change dateTimeRange type', () => { testMonthSyncChange('dateTimeRange')});
971
+
972
+ it(`test preset given null`, async () => {
973
+ const props = {
974
+ presets: [
975
+ {
976
+ text: 'Today',
977
+ start: null,
978
+ end: null,
979
+ }
980
+ ],
981
+ defaultValue: baseDate,
982
+ defaultOpen: true,
983
+ motion: false,
984
+ type: 'dateRange'
985
+ }
986
+ const handleChange = sinon.spy();
987
+ const demo = mount(<DatePicker {...props} onChange={handleChange} />);
988
+ const elem = demo.find(BaseDatePicker);
989
+
990
+ const btns = document.querySelectorAll('.semi-datepicker-quick-control-item');
991
+
992
+ btns[0].click();
993
+ expect(handleChange.called).toBeTruthy();
994
+ const args = handleChange.getCall(0).args;
995
+ expect(args[0].length).toEqual(0);
996
+ expect(elem.state('panelShow')).toBeFalsy();
997
+ });
998
+
999
+ it(`test preset given null + needConfirm`, async () => {
1000
+ const props = {
1001
+ presets: [
1002
+ {
1003
+ text: 'Today',
1004
+ start: null,
1005
+ end: null,
1006
+ }
1007
+ ],
1008
+ defaultValue: baseDate,
1009
+ defaultOpen: true,
1010
+ motion: false,
1011
+ type: 'dateTimeRange',
1012
+ needConfirm: true,
1013
+ }
1014
+ const handleChange = sinon.spy();
1015
+ const handleConfirm = sinon.spy();
1016
+ const demo = mount(<DatePicker {...props} onChange={handleChange} onConfirm={handleConfirm} />);
1017
+ const elem = demo.find(BaseDatePicker);
1018
+
1019
+ const btns = document.querySelectorAll('.semi-datepicker-quick-control-item');
1020
+
1021
+ // 点击 preset
1022
+ btns[0].click();
1023
+ expect(handleChange.called).toBe(true);
1024
+ const argsChange = handleChange.getCall(0).args;
1025
+ expect(argsChange[0].length).toBe(0);
1026
+ expect(elem.state('panelShow')).toBe(true);
1027
+ // 点击确定
1028
+ const footerBtns = document.querySelectorAll('.semi-datepicker-footer .semi-button');
1029
+ footerBtns[1].click();
1030
+ expect(handleConfirm.called).toBe(true);
1031
+ const argsConfirm = handleConfirm.getCall(0).args;
1032
+ expect(argsConfirm[0].length).toBe(0);
1033
+ expect(elem.state('panelShow')).toBe(false);
1034
+ });
1035
+
1036
+ it('test dateRange triggerRender', async () => {
1037
+ const elem = mount(
1038
+ <DatePicker
1039
+ motion={false}
1040
+ // defaultOpen
1041
+ type="dateRange"
1042
+ triggerRender={({ placeholder }) => (
1043
+ <button>
1044
+ {placeholder}
1045
+ </button>
1046
+ )}
1047
+ />
1048
+ );
1049
+ const trigger = document.querySelector('button');
1050
+ trigger.click();
1051
+ await sleep();
1052
+ const leftPanel = document.querySelector(`.${BASE_CLASS_PREFIX}-datepicker-month-grid-left`);
1053
+ const leftSecondWeek = leftPanel.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-week`)[1];
1054
+ const leftSecondWeekDays = leftSecondWeek.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-day`);
1055
+ const rightPanel = document.querySelector(`.${BASE_CLASS_PREFIX}-datepicker-month-grid-right`);
1056
+ const rightSecondWeek = rightPanel.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-week`)[1];
1057
+ const rightSecondWeekDays = rightSecondWeek.querySelectorAll(`.${BASE_CLASS_PREFIX}-datepicker-day`);
1058
+ leftSecondWeekDays[0].click();
1059
+ rightSecondWeekDays[0].click();
1060
+
1061
+ const baseElem = elem.find(BaseDatePicker);
1062
+ expect(baseElem.state('panelShow')).toBeFalsy();
1063
+ });
938
1064
  });
@@ -10,7 +10,7 @@ import {
10
10
  startOfWeek,
11
11
  endOfWeek,
12
12
  } from 'date-fns';
13
- import { Space, ConfigProvider, InputGroup, InputNumber, Form, withField } from '../../index';
13
+ import { Space, ConfigProvider, InputGroup, InputNumber, Form, withField, Button } from '../../index';
14
14
 
15
15
  // stores
16
16
  import NeedConfirmDemo from './NeedConfirm';
@@ -636,3 +636,173 @@ export const RangeSeparator = () => (
636
636
  </div>
637
637
  </Space>
638
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 取消后输入框显示错误';
726
+
727
+ /**
728
+ * fix https://github.com/DouyinFE/semi-design/issues/388
729
+ */
730
+ export const FixPresetsClick = () => {
731
+ const presets = [
732
+ {
733
+ text: '清空',
734
+ start: '',
735
+ end: '',
736
+ },
737
+ {
738
+ text: 'Tomorrow',
739
+ start: new Date(new Date().valueOf() + 1000 * 3600 * 24),
740
+ end: new Date(new Date().valueOf() + 1000 * 3600 * 24),
741
+ },
742
+ ];
743
+
744
+ const handleChange = v => {
745
+ console.log('change', v);
746
+ };
747
+
748
+ const handleConfirm = v => {
749
+ console.log('confirm', v);
750
+ }
751
+
752
+ return (
753
+ <div>
754
+ <div>
755
+ <label>
756
+ <span>不设置 needConfirm</span>
757
+ <DatePicker onChange={console.log} type="dateRange" presets={presets} />
758
+ </label>
759
+ </div>
760
+ <div>
761
+ <label>
762
+ <span>设置 needConfirm</span>
763
+ <DatePicker needConfirm onChange={handleChange} onConfirm={handleConfirm} type="dateTimeRange" presets={presets} />
764
+ </label>
765
+ </div>
766
+ </div>
767
+ );
768
+ };
769
+ FixPresetsClick.storyName = '修复 presets 点击后不收起问题';
770
+
771
+ /**
772
+ * fix https://github.com/DouyinFE/semi-design/issues/410
773
+ */
774
+ export const FixTriggerRenderClosePanel = () => {
775
+ const [value, setValue] = useState([]);
776
+
777
+ const handleChange = v => {
778
+ console.log('change', v);
779
+ setValue(v);
780
+ };
781
+
782
+ const formatValue = (dates) => {
783
+ const dateStrs = dates.map(v => String(v));
784
+ return dateStrs.join(' ~ ');
785
+ };
786
+
787
+ const showClear = Array.isArray(value) && value.length > 1;
788
+
789
+ return (
790
+ <Space>
791
+ <DatePicker
792
+ value={value}
793
+ type="dateRange"
794
+ onChange={handleChange}
795
+ motion={false}
796
+ triggerRender={({ placeholder }) => (
797
+ <Button>
798
+ {(value && formatValue(value)) || placeholder}
799
+ </Button>
800
+ )}
801
+ />
802
+ {showClear && (
803
+ <Button onClick={() => setValue([])}>清除</Button>
804
+ )}
805
+ </Space>
806
+ );
807
+ };
808
+ FixTriggerRenderClosePanel.storyName = "fix triggerRender close bug"
@@ -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);
@@ -360,6 +363,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
360
363
  syncSwitchMonth,
361
364
  onPanelChange,
362
365
  timeZone,
366
+ triggerRender
363
367
  } = this.props;
364
368
  const { value, cachedSelectedValue, motionEnd, rangeInputFocus } = this.state;
365
369
 
@@ -405,6 +409,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
405
409
  onPanelChange={onPanelChange}
406
410
  timeZone={timeZone}
407
411
  focusRecordsRef={this.focusRecordsRef}
412
+ triggerRender={triggerRender}
408
413
  />
409
414
  );
410
415
  }
@@ -71,7 +71,8 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
71
71
  syncSwitchMonth: PropTypes.bool,
72
72
  // Callback function for panel date switching
73
73
  onPanelChange: PropTypes.func,
74
- focusRecordsRef: PropTypes.object
74
+ focusRecordsRef: PropTypes.object,
75
+ triggerRender: PropTypes.func,
75
76
  };
76
77
 
77
78
  static defaultProps = {
package/dist/css/semi.css CHANGED
@@ -3524,6 +3524,12 @@ body[theme-mode=dark], body .semi-always-dark {
3524
3524
  text-align: right;
3525
3525
  background-color: var(--semi-color-fill-0);
3526
3526
  }
3527
+ .semi-datepicker-footer .semi-button:first-of-type {
3528
+ margin-right: 12px;
3529
+ }
3530
+ .semi-datepicker-footer .semi-button:nth-of-type(2) {
3531
+ margin-right: 8px;
3532
+ }
3527
3533
  .semi-datepicker-yam {
3528
3534
  position: absolute;
3529
3535
  top: 0;
@@ -4131,6 +4137,16 @@ body[theme-mode=dark], body .semi-always-dark {
4131
4137
  padding-left: 8px;
4132
4138
  text-align: left;
4133
4139
  }
4140
+ .semi-rtl .semi-datepicker-footer .semi-button:first-of-type,
4141
+ .semi-portal-rtl .semi-datepicker-footer .semi-button:first-of-type {
4142
+ margin-left: 0;
4143
+ margin-right: 0;
4144
+ }
4145
+ .semi-rtl .semi-datepicker-footer .semi-button:nth-of-type(2),
4146
+ .semi-portal-rtl .semi-datepicker-footer .semi-button:nth-of-type(2) {
4147
+ margin-right: 12px;
4148
+ margin-left: 0;
4149
+ }
4134
4150
  .semi-rtl .semi-datepicker-day-offsetrange-start .semi-datepicker-day-main,
4135
4151
  .semi-portal-rtl .semi-datepicker-day-offsetrange-start .semi-datepicker-day-main {
4136
4152
  border-radius: 0 var(--semi-border-radius-small) var(--semi-border-radius-small) 0;
@@ -4166,12 +4182,20 @@ body[theme-mode=dark], body .semi-always-dark {
4166
4182
  margin-right: 8px;
4167
4183
  }
4168
4184
  .semi-rtl .semi-datepicker-navigation .semi-icon-chevron_left,
4169
- .semi-rtl .semi-datepicker-navigation .semi-icon-chevron_right, .semi-rtl .semi-datepicker-yam .semi-icon-chevron_left,
4185
+ .semi-rtl .semi-datepicker-navigation .semi-icon-chevron_right,
4186
+ .semi-rtl .semi-datepicker-navigation .semi-icon-double_chevron_left,
4187
+ .semi-rtl .semi-datepicker-navigation .semi-icon-double_chevron_right, .semi-rtl .semi-datepicker-yam .semi-icon-chevron_left,
4170
4188
  .semi-rtl .semi-datepicker-yam .semi-icon-chevron_right,
4189
+ .semi-rtl .semi-datepicker-yam .semi-icon-double_chevron_left,
4190
+ .semi-rtl .semi-datepicker-yam .semi-icon-double_chevron_right,
4171
4191
  .semi-portal-rtl .semi-datepicker-navigation .semi-icon-chevron_left,
4172
4192
  .semi-portal-rtl .semi-datepicker-navigation .semi-icon-chevron_right,
4193
+ .semi-portal-rtl .semi-datepicker-navigation .semi-icon-double_chevron_left,
4194
+ .semi-portal-rtl .semi-datepicker-navigation .semi-icon-double_chevron_right,
4173
4195
  .semi-portal-rtl .semi-datepicker-yam .semi-icon-chevron_left,
4174
- .semi-portal-rtl .semi-datepicker-yam .semi-icon-chevron_right {
4196
+ .semi-portal-rtl .semi-datepicker-yam .semi-icon-chevron_right,
4197
+ .semi-portal-rtl .semi-datepicker-yam .semi-icon-double_chevron_left,
4198
+ .semi-portal-rtl .semi-datepicker-yam .semi-icon-double_chevron_right {
4175
4199
  transform: scaleX(-1);
4176
4200
  }
4177
4201
  .semi-rtl .semi-datepicker-range-input-prefix,
@@ -13031,19 +13055,23 @@ body[theme-mode=dark], body .semi-always-dark {
13031
13055
  color: var(--semi-color-success);
13032
13056
  }
13033
13057
  .semi-notification-notice-light.semi-notification-notice-warning {
13034
- background-color: var(--semi-color-warning-light-default);
13058
+ background-image: linear-gradient(0deg, var(--semi-color-warning-light-default), var(--semi-color-warning-light-default));
13059
+ background-color: var(--semi-color-bg-0);
13035
13060
  border: 1px solid var(--semi-color-warning);
13036
13061
  }
13037
13062
  .semi-notification-notice-light.semi-notification-notice-success {
13038
- background-color: var(--semi-color-success-light-default);
13063
+ background-image: linear-gradient(0deg, var(--semi-color-success-light-default), var(--semi-color-success-light-default));
13064
+ background-color: var(--semi-color-bg-0);
13039
13065
  border: 1px solid var(--semi-color-success);
13040
13066
  }
13041
13067
  .semi-notification-notice-light.semi-notification-notice-info, .semi-notification-notice-light.semi-notification-notice-default {
13042
- background-color: var(--semi-color-info-light-default);
13068
+ background-image: linear-gradient(0deg, var(--semi-color-info-light-default), var(--semi-color-info-light-default));
13069
+ background-color: var(--semi-color-bg-0);
13043
13070
  border: 1px solid var(--semi-color-info);
13044
13071
  }
13045
13072
  .semi-notification-notice-light.semi-notification-notice-error {
13046
- background-color: var(--semi-color-danger-light-default);
13073
+ background-image: linear-gradient(0deg, var(--semi-color-danger-light-default), var(--semi-color-danger-light-default));
13074
+ background-color: var(--semi-color-bg-0);
13047
13075
  border: 1px solid var(--semi-color-danger);
13048
13076
  }
13049
13077
  .semi-notification-notice-title {
@@ -16100,12 +16128,10 @@ body[theme-mode=dark], body .semi-always-dark {
16100
16128
  color: var(--semi-color-text-0);
16101
16129
  width: 100%;
16102
16130
  }
16103
- .semi-table-middle .semi-table-thead > .semi-table-row > .semi-table-row-head,
16104
16131
  .semi-table-middle .semi-table-tbody > .semi-table-row > .semi-table-row-cell {
16105
16132
  padding-top: 12px;
16106
16133
  padding-bottom: 12px;
16107
16134
  }
16108
- .semi-table-small .semi-table-thead > .semi-table-row > .semi-table-row-head,
16109
16135
  .semi-table-small .semi-table-tbody > .semi-table-row > .semi-table-row-cell {
16110
16136
  padding-top: 8px;
16111
16137
  padding-bottom: 8px;