@douyinfe/semi-foundation 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 (90) hide show
  1. package/cascader/cascader.scss +1 -1
  2. package/cascader/constants.ts +4 -0
  3. package/cascader/foundation.ts +29 -15
  4. package/cascader/util.ts +13 -0
  5. package/datePicker/_utils/parser.ts +4 -3
  6. package/datePicker/datePicker.scss +29 -0
  7. package/datePicker/foundation.ts +31 -11
  8. package/datePicker/inputFoundation.ts +2 -0
  9. package/datePicker/monthsGridFoundation.ts +101 -8
  10. package/datePicker/rtl.scss +15 -1
  11. package/datePicker/variables.scss +2 -0
  12. package/gulpfile.js +3 -1
  13. package/lib/cjs/cascader/cascader.css +2 -2
  14. package/lib/cjs/cascader/cascader.scss +1 -1
  15. package/lib/cjs/cascader/constants.d.ts +3 -0
  16. package/lib/cjs/cascader/constants.js +6 -1
  17. package/lib/cjs/cascader/foundation.d.ts +4 -1
  18. package/lib/cjs/cascader/foundation.js +24 -11
  19. package/lib/cjs/cascader/util.d.ts +1 -0
  20. package/lib/cjs/cascader/util.js +17 -0
  21. package/lib/cjs/datePicker/_utils/parser.d.ts +6 -1
  22. package/lib/cjs/datePicker/_utils/parser.js +3 -1
  23. package/lib/cjs/datePicker/datePicker.css +32 -3
  24. package/lib/cjs/datePicker/datePicker.scss +29 -0
  25. package/lib/cjs/datePicker/foundation.d.ts +6 -3
  26. package/lib/cjs/datePicker/foundation.js +40 -14
  27. package/lib/cjs/datePicker/inputFoundation.js +3 -0
  28. package/lib/cjs/datePicker/monthsGridFoundation.d.ts +35 -3
  29. package/lib/cjs/datePicker/monthsGridFoundation.js +139 -6
  30. package/lib/cjs/datePicker/rtl.scss +15 -1
  31. package/lib/cjs/datePicker/variables.scss +2 -0
  32. package/lib/cjs/navigation/navigation.css +0 -1
  33. package/lib/cjs/notification/notification.css +8 -4
  34. package/lib/cjs/notification/notification.scss +9 -5
  35. package/lib/cjs/notification/variables.scss +1 -0
  36. package/lib/cjs/select/foundation.d.ts +10 -1
  37. package/lib/cjs/select/foundation.js +11 -9
  38. package/lib/cjs/table/table.css +0 -2
  39. package/lib/cjs/table/table.scss +0 -2
  40. package/lib/cjs/tree/treeUtil.js +14 -14
  41. package/lib/cjs/upload/foundation.d.ts +1 -0
  42. package/lib/cjs/upload/foundation.js +106 -0
  43. package/lib/cjs/upload/rtl.scss +0 -4
  44. package/lib/cjs/upload/upload.css +30 -18
  45. package/lib/cjs/upload/upload.scss +31 -8
  46. package/lib/cjs/upload/variables.scss +5 -1
  47. package/lib/es/cascader/cascader.css +2 -2
  48. package/lib/es/cascader/cascader.scss +1 -1
  49. package/lib/es/cascader/constants.d.ts +3 -0
  50. package/lib/es/cascader/constants.js +6 -1
  51. package/lib/es/cascader/foundation.d.ts +4 -1
  52. package/lib/es/cascader/foundation.js +24 -12
  53. package/lib/es/cascader/util.d.ts +1 -0
  54. package/lib/es/cascader/util.js +14 -0
  55. package/lib/es/datePicker/_utils/parser.d.ts +6 -1
  56. package/lib/es/datePicker/_utils/parser.js +3 -1
  57. package/lib/es/datePicker/datePicker.css +32 -3
  58. package/lib/es/datePicker/datePicker.scss +29 -0
  59. package/lib/es/datePicker/foundation.d.ts +6 -3
  60. package/lib/es/datePicker/foundation.js +40 -14
  61. package/lib/es/datePicker/inputFoundation.js +3 -0
  62. package/lib/es/datePicker/monthsGridFoundation.d.ts +35 -3
  63. package/lib/es/datePicker/monthsGridFoundation.js +139 -6
  64. package/lib/es/datePicker/rtl.scss +15 -1
  65. package/lib/es/datePicker/variables.scss +2 -0
  66. package/lib/es/navigation/navigation.css +0 -1
  67. package/lib/es/notification/notification.css +8 -4
  68. package/lib/es/notification/notification.scss +9 -5
  69. package/lib/es/notification/variables.scss +1 -0
  70. package/lib/es/select/foundation.d.ts +10 -1
  71. package/lib/es/select/foundation.js +12 -9
  72. package/lib/es/table/table.css +0 -2
  73. package/lib/es/table/table.scss +0 -2
  74. package/lib/es/tree/treeUtil.js +13 -12
  75. package/lib/es/upload/foundation.d.ts +1 -0
  76. package/lib/es/upload/foundation.js +107 -0
  77. package/lib/es/upload/rtl.scss +0 -4
  78. package/lib/es/upload/upload.css +30 -18
  79. package/lib/es/upload/upload.scss +31 -8
  80. package/lib/es/upload/variables.scss +5 -1
  81. package/notification/notification.scss +9 -5
  82. package/notification/variables.scss +1 -0
  83. package/package.json +4 -4
  84. package/select/foundation.ts +11 -9
  85. package/table/table.scss +0 -2
  86. package/tree/treeUtil.ts +6 -2
  87. package/upload/foundation.ts +81 -0
  88. package/upload/rtl.scss +0 -4
  89. package/upload/upload.scss +31 -8
  90. package/upload/variables.scss +5 -1
@@ -116,7 +116,7 @@ $module: #{$prefix}-cascader;
116
116
  margin-left: 0;
117
117
  }
118
118
 
119
- &-disabled {
119
+ &-disabled.#{$prefix}-tag {
120
120
  color: $color-cascader_input_disabled-text-default;
121
121
  cursor: not-allowed;
122
122
 
@@ -12,6 +12,10 @@ const strings = {
12
12
  IS_VALUE: 'isValue',
13
13
  SHOW_NEXT_BY_CLICK: 'click',
14
14
  SHOW_NEXT_BY_HOVER: 'hover',
15
+ /* Merge Type */
16
+ LEAF_ONLY_MERGE_TYPE: 'leafOnly',
17
+ AUTO_MERGE_VALUE_MERGE_TYPE: 'autoMergeValue',
18
+ NONE_MERGE_TYPE: 'none',
15
19
  } as const;
16
20
 
17
21
  const numbers = {};
@@ -14,8 +14,11 @@ import {
14
14
  convertDataToEntities,
15
15
  findKeysForValues,
16
16
  normalizedArr,
17
- isValid
17
+ isValid,
18
+ calcMergeType
18
19
  } from './util';
20
+ import { strings } from './constants';
21
+
19
22
  export interface BasicData {
20
23
  data: BasicCascaderData;
21
24
  disabled: boolean;
@@ -99,6 +102,7 @@ export interface BasicScrollPanelProps {
99
102
  export interface BasicCascaderProps {
100
103
  mouseEnterDelay?: number;
101
104
  mouseLeaveDelay?: number;
105
+ separator?: string;
102
106
  arrowIcon?: any;
103
107
  changeOnSelect?: boolean;
104
108
  multiple?: boolean;
@@ -138,6 +142,8 @@ export interface BasicCascaderProps {
138
142
  topSlot?: any;
139
143
  showNext?: ShowNextType;
140
144
  disableStrictly?: boolean;
145
+ leafOnly?: boolean;
146
+ enableLeafClick?: boolean;
141
147
  onClear?: () => void;
142
148
  triggerRender?: (props: BasicTriggerRenderProps) => any;
143
149
  onListScroll?: (e: any, panel: BasicScrollPanelProps) => void;
@@ -168,7 +174,7 @@ export interface BasicCascaderInnerData {
168
174
  isHovering: boolean;
169
175
  checkedKeys: Set<string>;
170
176
  halfCheckedKeys: Set<string>;
171
- mergedCheckedKeys: Set<string>;
177
+ resolvedCheckedKeys: Set<string>;
172
178
  loadedKeys: Set<string>;
173
179
  loadingKeys: Set<string>;
174
180
  loading: boolean;
@@ -601,10 +607,11 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
601
607
  }
602
608
 
603
609
  _defaultRenderText(path: any[], displayRender?: BasicCascaderProps['displayRender']) {
610
+ const separator = this.getProp('separator');
604
611
  if (displayRender && typeof displayRender === 'function') {
605
612
  return displayRender(path);
606
613
  } else {
607
- return path.join(' / ');
614
+ return path.join(separator);
608
615
  }
609
616
  }
610
617
 
@@ -649,7 +656,7 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
649
656
  }
650
657
 
651
658
  handleSingleSelect(e: any, item: BasicEntity | BasicData) {
652
- const { changeOnSelect: allowChange, filterLeafOnly, multiple } = this.getProps();
659
+ const { changeOnSelect: allowChange, filterLeafOnly, multiple, enableLeafClick } = this.getProps();
653
660
  const { keyEntities, selectedKeys, isSearching } = this.getStates();
654
661
  const filterable = this._isFilterable();
655
662
  const { data, key } = item;
@@ -667,6 +674,9 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
667
674
  }
668
675
  if (multiple) {
669
676
  this._adapter.updateStates({ activeKeys: new Set(activeKeys) });
677
+ if (isLeaf && enableLeafClick) {
678
+ this.onItemCheckboxClick(item);
679
+ }
670
680
  } else {
671
681
  this._adapter.notifySelect(data.value);
672
682
  if (hasChanged) {
@@ -703,8 +713,8 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
703
713
 
704
714
  _handleMultipleSelect(item: BasicEntity | BasicData) {
705
715
  const { key } = item;
706
- const { checkedKeys, keyEntities, mergedCheckedKeys } = this.getStates();
707
- const { autoMergeValue, max, disableStrictly } = this.getProps();
716
+ const { checkedKeys, keyEntities, resolvedCheckedKeys } = this.getStates();
717
+ const { autoMergeValue, max, disableStrictly, leafOnly } = this.getProps();
708
718
  // prev checked status
709
719
  const prevCheckedStatus = checkedKeys.has(key);
710
720
  // next checked status
@@ -719,18 +729,22 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
719
729
  this.calcNonDisabedCheckedKeys(key, curCheckedStatus) :
720
730
  this.calcCheckedKeys(key, curCheckedStatus);
721
731
 
722
- const curMergedCheckedKeys = new Set(normalizeKeyList(curCheckedKeys, keyEntities));
732
+ const mergeType = calcMergeType(autoMergeValue, leafOnly);
733
+ const isLeafOnlyMerge = mergeType === strings.LEAF_ONLY_MERGE_TYPE;
734
+ const isNoneMerge = mergeType === strings.NONE_MERGE_TYPE;
735
+
736
+ const curResolvedCheckedKeys = new Set(normalizeKeyList(curCheckedKeys, keyEntities, isLeafOnlyMerge));
723
737
 
724
- const curRealCheckedKeys = autoMergeValue ?
725
- curMergedCheckedKeys :
726
- curCheckedKeys;
738
+ const curRealCheckedKeys = isNoneMerge
739
+ ? curCheckedKeys
740
+ : curResolvedCheckedKeys;
727
741
 
728
742
  if (isNumber(max)) {
729
- if (autoMergeValue) {
743
+ if (!isNoneMerge) {
730
744
  // When it exceeds max, the quantity is allowed to be reduced, and no further increase is allowed
731
- if (mergedCheckedKeys.size < curMergedCheckedKeys.size && curMergedCheckedKeys.size > max) {
745
+ if (resolvedCheckedKeys.size < curResolvedCheckedKeys.size && curResolvedCheckedKeys.size > max) {
732
746
  const checkedEntities: BasicEntity[] = [];
733
- curMergedCheckedKeys.forEach(itemKey => {
747
+ curResolvedCheckedKeys.forEach(itemKey => {
734
748
  checkedEntities.push(keyEntities[itemKey]);
735
749
  });
736
750
  this._adapter.notifyOnExceed(checkedEntities);
@@ -752,7 +766,7 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
752
766
  this._adapter.updateStates({
753
767
  checkedKeys: curCheckedKeys,
754
768
  halfCheckedKeys: curHalfCheckedKeys,
755
- mergedCheckedKeys: curMergedCheckedKeys
769
+ resolvedCheckedKeys: curResolvedCheckedKeys
756
770
  });
757
771
  }
758
772
 
@@ -868,7 +882,7 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
868
882
  newState.halfCheckedKeys = new Set([]);
869
883
  newState.selectedKeys = new Set([]);
870
884
  newState.activeKeys = new Set([]);
871
- newState.mergedCheckedKeys = new Set([]);
885
+ newState.resolvedCheckedKeys = new Set([]);
872
886
  this._adapter.notifyChange([]);
873
887
  } else {
874
888
  // if click clearBtn when not searching, clear selected and active values as well
package/cascader/util.ts CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  isUndefined,
4
4
  isEqual
5
5
  } from 'lodash';
6
+ import { strings } from './constants';
6
7
 
7
8
  function getPosition(level: any, index: any) {
8
9
  return `${level}-${index}`;
@@ -79,4 +80,16 @@ export function findKeysForValues(value: any, keyEntities: any) {
79
80
  .filter((item: any) => isEqual(item.valuePath, valuePath))
80
81
  .map((item: any) => item.key);
81
82
  return res;
83
+ }
84
+
85
+ export function calcMergeType(autoMergeValue: boolean, leafOnly: boolean): string {
86
+ let mergeType: string;
87
+ if (leafOnly) {
88
+ mergeType = strings.LEAF_ONLY_MERGE_TYPE;
89
+ } else if (autoMergeValue) {
90
+ mergeType = strings.AUTO_MERGE_VALUE_MERGE_TYPE;
91
+ } else {
92
+ mergeType = strings.NONE_MERGE_TYPE;
93
+ }
94
+ return mergeType;
82
95
  }
@@ -2,7 +2,7 @@
2
2
  * @file
3
3
  * Various date-related analysis methods
4
4
  */
5
- import { isValid, parseISO, parse } from 'date-fns';
5
+ import { isValid, parseISO, parse, Locale } from 'date-fns';
6
6
 
7
7
  /**
8
8
  * Parsing value to Date object
@@ -11,7 +11,7 @@ export function compatiableParse(
11
11
  value: string,
12
12
  formatToken?: string,
13
13
  baseDate?: Date,
14
- locale?: any
14
+ locale?: Locale
15
15
  ): Date | null {
16
16
  let result = null;
17
17
  if (value) {
@@ -25,7 +25,8 @@ export function compatiableParse(
25
25
  if (!isValid(result)) {
26
26
  result = new Date(Date.parse(value));
27
27
  }
28
- if (!isValid(result)) {
28
+ const yearInvalid = isValid(result) && String(result.getFullYear()).length > 4;
29
+ if (!isValid(result) || yearInvalid) {
29
30
  result = null;
30
31
  }
31
32
  }
@@ -94,6 +94,15 @@ $module: #{$prefix}-datepicker;
94
94
  min-height: $height-datepicker_timepicker_header_min;
95
95
  }
96
96
  }
97
+
98
+ // 为了防止 scrollList 因为 weeks 变化高度发生变化导致年月可能发生滚动
99
+ // In order to prevent scrollList from scrolling due to changes in the height of weeks, the year and month may be scrolled
100
+ &[x-panel-yearandmonth-open-type="left"],
101
+ &[x-panel-yearandmonth-open-type="right"] {
102
+ .#{$module}-weeks {
103
+ min-height: 6 * $width-datepicker_day;
104
+ }
105
+ }
97
106
  }
98
107
 
99
108
  // 年月选择器
@@ -131,6 +140,17 @@ $module: #{$prefix}-datepicker;
131
140
  padding-bottom: $spacing-datepicker_footer-paddingBottom;
132
141
  text-align: right;
133
142
  background-color: $color-datepicker_footer-bg-default;
143
+
144
+ .#{$prefix}-button {
145
+ // cancel button
146
+ &:first-of-type {
147
+ margin-right: $spacing-datepicker_footer_cancel_button-marginRight;
148
+ }
149
+ // confirm button
150
+ &:nth-of-type(2) {
151
+ margin-right: $spacing-datepicker_footer_confirm_button-marginRight;
152
+ }
153
+ }
134
154
  }
135
155
 
136
156
  // 年月选择
@@ -833,6 +853,15 @@ $module: #{$prefix}-datepicker;
833
853
  }
834
854
  }
835
855
  }
856
+
857
+ // 为了防止 scrollList 因为 weeks 变化高度发生变化导致年月可能发生滚动
858
+ // In order to prevent scrollList from scrolling due to changes in the height of weeks, the year and month may be scrolled
859
+ &[x-panel-yearandmonth-open-type="left"],
860
+ &[x-panel-yearandmonth-open-type="right"] {
861
+ .#{$module}-weeks {
862
+ min-height: 6 * $width-datepicker_day_compact;
863
+ }
864
+ }
836
865
  }
837
866
 
838
867
  // 年月选择器
@@ -323,10 +323,8 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
323
323
  * 2. set cachedSelectedValue using given dates(in needConfirm mode)
324
324
  * - directly closePanel without click confirm will set cachedSelectedValue to state value
325
325
  * - select one date(which means that the selection value is incomplete) and click confirm also set cachedSelectedValue to state value
326
- * @param {String} inputValue
327
- * @param {Date[]} dates
328
326
  */
329
- rangeTypeSideEffectsWhenClosePanel(inputValue: string, dates: Date[]) {
327
+ rangeTypeSideEffectsWhenClosePanel(inputValue: string, willUpdateDates: Date[]) {
330
328
  if (this._isRangeType()) {
331
329
  this._adapter.setRangeInputFocus(false);
332
330
  /**
@@ -334,11 +332,29 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
334
332
  * when inputValue is null, picker value will back to last selected value
335
333
  */
336
334
  this.handleInputBlur(inputValue);
337
- const { value, cachedSelectedValue } = this._adapter.getStates();
338
- const newCachedSelectedValue = Array.isArray(dates) && dates.length ? dates : value;
339
- if (!isEqual(newCachedSelectedValue, cachedSelectedValue)) {
340
- this._adapter.updateCachedSelectedValue(newCachedSelectedValue);
341
- }
335
+ this.resetCachedSelectedValue(willUpdateDates);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * clear input value when selected date is not confirmed
341
+ */
342
+ needConfirmSideEffectsWhenClosePanel(willUpdateDates: Date[] | null | undefined) {
343
+ if (this._adapter.needConfirm() && !this._isRangeType()) {
344
+ /**
345
+ * if `null` input element will show `cachedSelectedValue` formatted value(format in DateInput render)
346
+ * if `` input element will show `` directly
347
+ */
348
+ this._adapter.updateInputValue(null);
349
+ this.resetCachedSelectedValue(willUpdateDates);
350
+ }
351
+ }
352
+
353
+ resetCachedSelectedValue(willUpdateDates?: Date[]) {
354
+ const { value, cachedSelectedValue } = this._adapter.getStates();
355
+ const newCachedSelectedValue = Array.isArray(willUpdateDates) ? willUpdateDates : value;
356
+ if (!isEqual(newCachedSelectedValue, cachedSelectedValue)) {
357
+ this._adapter.updateCachedSelectedValue(newCachedSelectedValue);
342
358
  }
343
359
  }
344
360
 
@@ -354,13 +370,16 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
354
370
  * @param {String} inputValue
355
371
  * @param {Date[]} dates
356
372
  */
357
- closePanel(e?: any, inputValue: string = null, dates: Date[] = []) {
373
+ closePanel(e?: any, inputValue: string = null, dates?: Date[]) {
374
+ const { value, cachedSelectedValue } = this._adapter.getStates();
375
+ const willUpdateDates = isNullOrUndefined(dates) ? this._adapter.needConfirm() ? value : cachedSelectedValue : dates;
358
376
  if (!this._isControlledComponent('open')) {
359
377
  this._adapter.togglePanel(false);
360
378
  this._adapter.unregisterClickOutSide();
361
379
  }
362
380
  // range type picker, closing panel requires the following side effects
363
- this.rangeTypeSideEffectsWhenClosePanel(inputValue, dates);
381
+ this.rangeTypeSideEffectsWhenClosePanel(inputValue, willUpdateDates as Date[]);
382
+ this.needConfirmSideEffectsWhenClosePanel(willUpdateDates as Date[]);
364
383
  this._adapter.notifyOpenChange(false);
365
384
  this._adapter.notifyBlur(e);
366
385
  }
@@ -416,7 +435,8 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
416
435
  if (parsedResult && parsedResult.length) {
417
436
  this._updateValueAndInput(parsedResult, input === '');
418
437
  } else if (input === '') {
419
- this._updateValueAndInput('' as any, true);
438
+ // if clear input, set input to `''`
439
+ this._updateValueAndInput('' as any, true, '');
420
440
  } else {
421
441
  this._updateValueAndInput(stateValue);
422
442
  }
@@ -89,6 +89,8 @@ export default class InputFoundation extends BaseFoundation<DateInputAdapter> {
89
89
  }
90
90
 
91
91
  handleRangeInputClear(e: any) {
92
+ // prevent trigger click outside
93
+ this.stopPropagation(e);
92
94
  this._adapter.notifyRangeInputClear(e);
93
95
  }
94
96
 
@@ -47,6 +47,7 @@ interface MonthsGridElementProps {
47
47
  }
48
48
 
49
49
  export type PanelType = 'left' | 'right';
50
+ export type YearMonthChangeType = 'prevMonth' | 'nextMonth' | 'prevYear' | 'nextYear';
50
51
 
51
52
  export interface MonthsGridFoundationProps extends MonthsGridElementProps {
52
53
  type?: Type;
@@ -268,9 +269,65 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
268
269
  // eslint-disable-next-line @typescript-eslint/no-empty-function
269
270
  destroy() { }
270
271
 
272
+ /**
273
+ * sync change another panel month when change months from the else yam panel
274
+ * call it when
275
+ * - current change panel targe date month is same with another panel date
276
+ *
277
+ * @example
278
+ * - panelType=right, target=new Date('2022-09-01') and left panel is in '2022-09' => call it, left panel minus one month to '2022-08'
279
+ * - panelType=left, target=new Date('2021-12-01') and right panel is in '2021-12' => call it, right panel add one month to '2021-01'
280
+ */
281
+ handleSyncChangeMonths(options: { panelType: PanelType, target: Date }) {
282
+ const { panelType, target } = options;
283
+ const { type } = this._adapter.getProps();
284
+ const { monthLeft, monthRight } = this._adapter.getStates();
285
+ if (this.isRangeType(type)) {
286
+ if (panelType === 'right' && differenceInCalendarMonths(target, monthLeft.pickerDate) === 0) {
287
+ this.handleYearOrMonthChange('prevMonth', 'left', 1, true);
288
+ } else if (panelType === 'left' && differenceInCalendarMonths(monthRight.pickerDate, target) === 0) {
289
+ this.handleYearOrMonthChange('nextMonth', 'right', 1, true);
290
+ }
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Get the target date based on the panel type and switch type
296
+ */
297
+ getTargetChangeDate(options: { panelType: PanelType, switchType: YearMonthChangeType }) {
298
+ const { panelType, switchType } = options;
299
+ const { monthRight, monthLeft } = this._adapter.getStates();
300
+ const currentDate = panelType === 'left' ? monthLeft.pickerDate : monthRight.pickerDate;
301
+ let target: Date;
302
+
303
+ switch (switchType) {
304
+ case 'prevMonth':
305
+ target = addMonths(currentDate, -1);
306
+ break;
307
+ case 'nextMonth':
308
+ target = addMonths(currentDate, 1);
309
+ break;
310
+ case 'prevYear':
311
+ target = addYears(currentDate, -1);
312
+ break;
313
+ case 'nextYear':
314
+ target = addYears(currentDate, 1);
315
+ break;
316
+ }
317
+ return target;
318
+ }
319
+
320
+ /**
321
+ * Change month by yam panel
322
+ */
271
323
  toMonth(panelType: PanelType, target: Date) {
324
+ const { type } = this._adapter.getProps();
272
325
  const diff = this._getDiff('month', target, panelType);
273
326
  this.handleYearOrMonthChange(diff < 0 ? 'prevMonth' : 'nextMonth', panelType, Math.abs(diff), false);
327
+
328
+ if (this.isRangeType(type)) {
329
+ this.handleSyncChangeMonths({ panelType, target });
330
+ }
274
331
  }
275
332
 
276
333
  toYear(panelType: PanelType, target: Date) {
@@ -289,30 +346,43 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
289
346
  return typeof realType === 'string' && /range/i.test(realType);
290
347
  }
291
348
 
292
- handleSwitchMonth(switchType: 'prevMonth' | 'nextMonth', panelType: PanelType) {
349
+ handleSwitchMonthOrYear(switchType: YearMonthChangeType, panelType: PanelType) {
293
350
  const { type, syncSwitchMonth } = this.getProps();
294
- if (this.isRangeType(type) && syncSwitchMonth) {
351
+ const rangeType = this.isRangeType(type);
352
+
353
+ // range type and syncSwitchMonth, we should change panels at same time
354
+ if (rangeType && syncSwitchMonth) {
295
355
  this.handleYearOrMonthChange(switchType, 'left', 1, true);
296
356
  this.handleYearOrMonthChange(switchType, 'right', 1, true);
297
357
  } else {
298
358
  this.handleYearOrMonthChange(switchType, panelType);
359
+
360
+ /**
361
+ * default behavior (v2.2.0)
362
+ * In order to prevent the two panels from being the same month, this will confuse the user when selecting the range
363
+ * https://github.com/DouyinFE/semi-design/issues/260
364
+ */
365
+ if (rangeType) {
366
+ const target = this.getTargetChangeDate({ panelType, switchType });
367
+ this.handleSyncChangeMonths({ panelType, target });
368
+ }
299
369
  }
300
370
  }
301
371
 
302
372
  prevMonth(panelType: PanelType) {
303
- this.handleSwitchMonth('prevMonth', panelType);
373
+ this.handleSwitchMonthOrYear('prevMonth', panelType);
304
374
  }
305
375
 
306
376
  nextMonth(panelType: PanelType) {
307
- this.handleSwitchMonth('nextMonth', panelType);
377
+ this.handleSwitchMonthOrYear('nextMonth', panelType);
308
378
  }
309
379
 
310
380
  prevYear(panelType: PanelType) {
311
- this.handleYearOrMonthChange('prevYear', panelType);
381
+ this.handleSwitchMonthOrYear('prevYear', panelType);
312
382
  }
313
383
 
314
384
  nextYear(panelType: PanelType) {
315
- this.handleYearOrMonthChange('nextYear', panelType);
385
+ this.handleSwitchMonthOrYear('nextYear', panelType);
316
386
  }
317
387
 
318
388
  /**
@@ -414,7 +484,7 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
414
484
  }
415
485
 
416
486
  handleYearOrMonthChange(
417
- type: 'prevMonth' | 'nextMonth' | 'prevYear' | 'nextYear',
487
+ type: YearMonthChangeType,
418
488
  panelType: PanelType = strings.PANEL_TYPE_LEFT,
419
489
  step = 1,
420
490
  notSeparateInRange = false
@@ -458,7 +528,7 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
458
528
  * @param {*} targetDate
459
529
  */
460
530
  updateDateAfterChangeYM(
461
- type: 'prevMonth' | 'nextMonth' | 'prevYear' | 'nextYear',
531
+ type: YearMonthChangeType,
462
532
  targetDate: Date
463
533
  ) {
464
534
  const { multiple, disabledDate } = this.getProps();
@@ -839,4 +909,27 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
839
909
  showDatePanel(panelType: PanelType) {
840
910
  this._updatePanelDetail(panelType, { isTimePickerOpen: false, isYearPickerOpen: false });
841
911
  }
912
+
913
+ /**
914
+ * Get year and month panel open type
915
+ *
916
+ * It is useful info to set minHeight of weeks.
917
+ * - When yam open type is 'left' or 'right', weeks minHeight should be set
918
+ * If the minHeight is not set, the change of the number of weeks will cause the scrollList to be unstable
919
+ */
920
+ getYAMOpenType() {
921
+ const { monthLeft, monthRight } = this._adapter.getStates();
922
+ const leftYearPickerOpen = monthLeft.isYearPickerOpen;
923
+ const rightYearPickerOpen = monthRight.isYearPickerOpen;
924
+
925
+ if (leftYearPickerOpen && rightYearPickerOpen) {
926
+ return 'both';
927
+ } else if (leftYearPickerOpen) {
928
+ return 'left';
929
+ } else if (rightYearPickerOpen) {
930
+ return 'right';
931
+ } else {
932
+ return 'none';
933
+ }
934
+ }
842
935
  }
@@ -9,6 +9,18 @@ $module: #{$prefix}-datepicker;
9
9
  padding-right: 0;
10
10
  padding-left: $spacing-datepicker_footer-paddingRight;
11
11
  text-align: left;
12
+
13
+ .#{$prefix}-button {
14
+ &:first-of-type {
15
+ margin-left: 0;
16
+ margin-right: 0;
17
+ }
18
+ // confirm button
19
+ &:nth-of-type(2) {
20
+ margin-right: $spacing-datepicker_footer_cancel_button-marginRight;
21
+ margin-left: 0;
22
+ }
23
+ }
12
24
  }
13
25
 
14
26
  &-day {
@@ -66,7 +78,9 @@ $module: #{$prefix}-datepicker;
66
78
  &-yam {
67
79
  // rtl 对箭头进行翻转
68
80
  .#{$prefix}-icon-chevron_left,
69
- .#{$prefix}-icon-chevron_right {
81
+ .#{$prefix}-icon-chevron_right,
82
+ .#{$prefix}-icon-double_chevron_left,
83
+ .#{$prefix}-icon-double_chevron_right {
70
84
  transform: scaleX(-1);
71
85
  }
72
86
  }
@@ -33,6 +33,8 @@ $spacing-datepicker_scrolllist_body-padding: 0; // 时间选择滚动菜单内
33
33
  $spacing-datepicker_footer-paddingTop: 10px; // 确认选择 footer 顶部内边距
34
34
  $spacing-datepicker_footer-paddingBottom: 10px; // 确认选择 footer 底部内边距
35
35
  $spacing-datepicker_footer-paddingRight: 8px; // 确认选择 footer 右侧内边距
36
+ $spacing-datepicker_footer_cancel_button-marginRight: 12px; // 确认选择 footer 取消按钮右外边距
37
+ $spacing-datepicker_footer_confirm_button-marginRight: 8px; // 确认选择 footer 确认按钮右外边距
36
38
  $spacing-datepicker_navigation-paddingY: $spacing-base-tight; // 年月切换 header 垂直内边距
37
39
  $spacing-datepicker_navigation-paddingX: $spacing-base; // 年月切换 header 水平内边距
38
40
  $spacing-datepicker_month-padding: $spacing-base;
package/gulpfile.js CHANGED
@@ -52,7 +52,9 @@ gulp.task('compileScss', function compileScss() {
52
52
  cb(null, chunk);
53
53
  }
54
54
  ))
55
- .pipe(sass().on('error', sass.logError))
55
+ .pipe(sass({
56
+ charset: false
57
+ }).on('error', sass.logError))
56
58
  .pipe(gulp.dest('lib/es'))
57
59
  .pipe(gulp.dest('lib/cjs'));
58
60
  });
@@ -99,11 +99,11 @@
99
99
  .semi-cascader-selection-tag:first-child {
100
100
  margin-left: 0;
101
101
  }
102
- .semi-cascader-selection-tag-disabled {
102
+ .semi-cascader-selection-tag-disabled.semi-tag {
103
103
  color: var(--semi-color-disabled-text);
104
104
  cursor: not-allowed;
105
105
  }
106
- .semi-cascader-selection-tag-disabled .semi-tag-close {
106
+ .semi-cascader-selection-tag-disabled.semi-tag .semi-tag-close {
107
107
  color: var(--semi-color-disabled-text);
108
108
  cursor: not-allowed;
109
109
  pointer-events: none;
@@ -116,7 +116,7 @@ $module: #{$prefix}-cascader;
116
116
  margin-left: 0;
117
117
  }
118
118
 
119
- &-disabled {
119
+ &-disabled.#{$prefix}-tag {
120
120
  color: $color-cascader_input_disabled-text-default;
121
121
  cursor: not-allowed;
122
122
 
@@ -9,6 +9,9 @@ declare const strings: {
9
9
  readonly IS_VALUE: "isValue";
10
10
  readonly SHOW_NEXT_BY_CLICK: "click";
11
11
  readonly SHOW_NEXT_BY_HOVER: "hover";
12
+ readonly LEAF_ONLY_MERGE_TYPE: "leafOnly";
13
+ readonly AUTO_MERGE_VALUE_MERGE_TYPE: "autoMergeValue";
14
+ readonly NONE_MERGE_TYPE: "none";
12
15
  };
13
16
  declare const numbers: {};
14
17
  export { cssClasses, strings, numbers };
@@ -21,7 +21,12 @@ const strings = {
21
21
  IS_KEY: 'isKey',
22
22
  IS_VALUE: 'isValue',
23
23
  SHOW_NEXT_BY_CLICK: 'click',
24
- SHOW_NEXT_BY_HOVER: 'hover'
24
+ SHOW_NEXT_BY_HOVER: 'hover',
25
+
26
+ /* Merge Type */
27
+ LEAF_ONLY_MERGE_TYPE: 'leafOnly',
28
+ AUTO_MERGE_VALUE_MERGE_TYPE: 'autoMergeValue',
29
+ NONE_MERGE_TYPE: 'none'
25
30
  };
26
31
  exports.strings = strings;
27
32
  const numbers = {};
@@ -57,6 +57,7 @@ export interface BasicScrollPanelProps {
57
57
  export interface BasicCascaderProps {
58
58
  mouseEnterDelay?: number;
59
59
  mouseLeaveDelay?: number;
60
+ separator?: string;
60
61
  arrowIcon?: any;
61
62
  changeOnSelect?: boolean;
62
63
  multiple?: boolean;
@@ -96,6 +97,8 @@ export interface BasicCascaderProps {
96
97
  topSlot?: any;
97
98
  showNext?: ShowNextType;
98
99
  disableStrictly?: boolean;
100
+ leafOnly?: boolean;
101
+ enableLeafClick?: boolean;
99
102
  onClear?: () => void;
100
103
  triggerRender?: (props: BasicTriggerRenderProps) => any;
101
104
  onListScroll?: (e: any, panel: BasicScrollPanelProps) => void;
@@ -125,7 +128,7 @@ export interface BasicCascaderInnerData {
125
128
  isHovering: boolean;
126
129
  checkedKeys: Set<string>;
127
130
  halfCheckedKeys: Set<string>;
128
- mergedCheckedKeys: Set<string>;
131
+ resolvedCheckedKeys: Set<string>;
129
132
  loadedKeys: Set<string>;
130
133
  loadingKeys: Set<string>;
131
134
  loading: boolean;