Преглед изворни кода

fix: [DatePicker] range type ui shift bug #1221 (#1398)

Co-authored-by: shijia.me <[email protected]>
走鹃 пре 2 година
родитељ
комит
11ffee650a

+ 30 - 0
cypress/integration/datePicker.spec.js

@@ -604,4 +604,34 @@ describe('DatePicker', () => {
         cy.get('.semi-scrolllist-body .semi-scrolllist-item:nth-child(2) .semi-scrolllist-item-sel').should('contain.text', '1月');
         cy.get('.semi-input').eq(0).should('have.value', '2022-01');
     });
+
+    it('fix dateRange type ui shift', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-range-panel-shift&viewMode=story');
+        cy.get('.semi-input').eq(0).click();
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-day').contains('20').click();
+        cy.get('.semi-datepicker-month-grid-left .semi-datepicker-navigation-month').contains('2019年 7月');
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-navigation-month').contains('2019年 8月');
+    });
+
+    it('fix dateTimeRange type ui shift', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-range-panel-shift&viewMode=story');
+        cy.get('.semi-input').eq(2).click();
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-day').contains('20').click();
+        cy.get('.semi-datepicker-month-grid-left .semi-datepicker-navigation-month').contains('2019年 7月');
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-navigation-month').contains('2019年 8月');
+    });
+
+    it('test dateRange with defaultValue', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-range-panel-shift&viewMode=story');
+        cy.get('.semi-input').eq(4).click();
+        cy.get('.semi-datepicker-month-grid-left .semi-datepicker-day-selected-start');
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-day-selected-end');
+    });
+
+    it('test dateTimeRange with defaultValue', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-range-panel-shift&viewMode=story');
+        cy.get('.semi-input').eq(6).click();
+        cy.get('.semi-datepicker-month-grid-left .semi-datepicker-day-selected-start');
+        cy.get('.semi-datepicker-month-grid-right .semi-datepicker-day-selected-end');
+    });
 });

+ 36 - 15
packages/semi-foundation/datePicker/monthsGridFoundation.ts

@@ -55,7 +55,8 @@ export type YearMonthChangeType = 'prevMonth' | 'nextMonth' | 'prevYear' | 'next
 
 export interface MonthsGridFoundationProps extends MonthsGridElementProps {
     type?: Type;
-    defaultValue?: ValueType;
+    /** may be null if selection is not complete when type is dateRange or dateTimeRange */
+    defaultValue?: (Date | null)[];
     defaultPickerValue?: ValueType;
     multiple?: boolean;
     max?: number;
@@ -96,7 +97,11 @@ export interface MonthsGridFoundationProps extends MonthsGridElementProps {
 }
 
 export interface MonthInfo {
+    /** The date displayed in the current date panel, update when switching year and month */
     pickerDate: Date;
+    /**
+     * Default date or selected date (when selected)
+     */
     showDate: Date;
     isTimePickerOpen: boolean;
     isYearPickerOpen: boolean
@@ -167,22 +172,22 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
         }
     }
 
-    updateSelectedFromProps(values: ValueType, refreshPicker = true) {
+    updateSelectedFromProps(values: (Date | null)[], refreshPicker = true) {
         const type: Type = this.getProp('type');
         const { selected, rangeStart, rangeEnd } = this.getStates();
-        if (values && (values as BaseValueType[]).length) {
+        if (values && values?.length) {
             switch (type) {
                 case 'date':
-                    this._initDatePickerFromValue(values as BaseValueType[], refreshPicker);
+                    this._initDatePickerFromValue(values, refreshPicker);
                     break;
                 case 'dateRange':
-                    this._initDateRangePickerFromValue(values as BaseValueType[]);
+                    this._initDateRangePickerFromValue(values);
                     break;
                 case 'dateTime':
-                    this._initDateTimePickerFromValue(values as BaseValueType[]);
+                    this._initDateTimePickerFromValue(values);
                     break;
                 case 'dateTimeRange':
-                    this._initDateTimeRangePickerFormValue(values as BaseValueType[]);
+                    this._initDateTimeRangePickerFormValue(values);
                     break;
                 default:
                     break;
@@ -222,7 +227,7 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
         }
     }
 
-    _initDatePickerFromValue(values: BaseValueType[], refreshPicker = true) {
+    _initDatePickerFromValue(values: Date[], refreshPicker = true) {
         const monthLeft = this.getState('monthLeft');
         const newMonthLeft = { ...monthLeft };
         // REMOVE:
@@ -244,16 +249,32 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
         this._adapter.updateDaySelected(newSelected);
     }
 
-    _initDateRangePickerFromValue(values: BaseValueType[], withTime = false) {
+    _initDateRangePickerFromValue(values: (Date | null)[], withTime = false) {
         // init month panel
-        const monthLeft = this.getState('monthLeft');
-        const monthRight = this.getState('monthRight');
+        const monthLeft = this.getState('monthLeft') as MonthsGridFoundationState['monthLeft'];
+        const monthRight = this.getState('monthRight') as MonthsGridFoundationState['monthRight'];
         const adjustResult = this._autoAdjustMonth(
             { ...monthLeft, pickerDate: values[0] || monthLeft.pickerDate },
             { ...monthRight, pickerDate: values[1] || monthRight.pickerDate }
         );
-        this.handleShowDateAndTime(strings.PANEL_TYPE_LEFT, adjustResult.monthLeft.pickerDate);
-        this.handleShowDateAndTime(strings.PANEL_TYPE_RIGHT, adjustResult.monthRight.pickerDate);
+
+        const validValue = Array.isArray(values) && values.filter(item => item).length > 1;
+        if (validValue) {
+            this.handleShowDateAndTime(strings.PANEL_TYPE_LEFT, adjustResult.monthLeft.pickerDate);
+            this.handleShowDateAndTime(strings.PANEL_TYPE_RIGHT, adjustResult.monthRight.pickerDate);
+        } else {
+            const selectedDate = values.find(item => item) as Date;
+            // 如果日期不完整且输入日期不在面板范围内,则更新面板
+            if (selectedDate) {                
+                const notLeftMonth = selectedDate?.getMonth() !== monthLeft.pickerDate.getMonth();
+                const notRightMonth = selectedDate?.getMonth() !== monthRight.pickerDate.getMonth();
+    
+                if (notLeftMonth && notRightMonth) {
+                    this.handleShowDateAndTime(strings.PANEL_TYPE_LEFT, adjustResult.monthLeft.pickerDate);
+                    this.handleShowDateAndTime(strings.PANEL_TYPE_RIGHT, adjustResult.monthRight.pickerDate);
+                }
+            }
+        }
 
         // init range
         const formatToken = withTime ? strings.FORMAT_DATE_TIME : strings.FORMAT_FULL_DATE;
@@ -268,11 +289,11 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
         this._adapter.setHoverDay(rangeEnd);
     }
 
-    _initDateTimePickerFromValue(values: BaseValueType[]) {
+    _initDateTimePickerFromValue(values: Date[]) {
         this._initDatePickerFromValue(values);
     }
 
-    _initDateTimeRangePickerFormValue(values: BaseValueType[]) {
+    _initDateTimeRangePickerFormValue(values: (Date | null)[]) {
         this._initDateRangePickerFromValue(values, true);
     }
 

+ 24 - 0
packages/semi-ui/datePicker/_story/v2/FixRangePanelShift.jsx

@@ -0,0 +1,24 @@
+import React from 'react';
+import DatePicker from '../../index';
+
+/**
+ * test with cypress
+ * 
+ * fix issue 1221
+ * @see https://github.com/DouyinFE/semi-design/issues/1221
+ */
+export default function App() {
+    return (
+        <div>
+            <DatePicker type="dateRange" defaultPickerValue={'2019-07-01'} style={{ width: 260 }} onChange={console.log} />
+            <br /><br />
+            <DatePicker type="dateTimeRange" defaultPickerValue={'2019-07-01'} style={{ width: 260 }} onChange={console.log} />
+            <br /><br />
+            <DatePicker type="dateRange" defaultValue={['2019-07-01', '2019-08-02']} style={{ width: 260 }} onChange={console.log} />
+            <br /><br />
+            <DatePicker type="dateTimeRange" defaultValue={['2019-07-01', '2019-08-02']} style={{ width: 260 }} onChange={console.log} />
+        </div>
+    );
+}
+
+App.storyName = '修复范围面板漂移问题';

+ 1 - 0
packages/semi-ui/datePicker/_story/v2/index.js

@@ -11,3 +11,4 @@ export { default as InputFormatConfirm } from './InputFormatConfirm';
 export { default as FixedTriggerRender } from './FixTriggerRender';
 export { default as DisabledRange } from './DisabledRange';
 export { default as FixDisabledMonth } from './FixDisabledMonth';
+export { default as FixRangePanelShift } from './FixRangePanelShift';

+ 1 - 1
packages/semi-ui/datePicker/monthsGrid.tsx

@@ -38,7 +38,7 @@ export type MonthsGridState = MonthsGridFoundationState;
 export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGridState> {
     static propTypes = {
         type: PropTypes.oneOf(strings.TYPE_SET),
-        defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object, PropTypes.array]),
+        defaultValue: PropTypes.array,
         defaultPickerValue: PropTypes.oneOfType([
             PropTypes.string,
             PropTypes.number,