瀏覽代碼

feat: DatePicker insetInput support clear icon #1638 (#1639)

Co-authored-by: shijia.me <[email protected]>
Shi Jia 2 年之前
父節點
當前提交
7a4a67f68c

+ 4 - 1
packages/semi-foundation/datePicker/datePicker.scss

@@ -993,13 +993,16 @@ $module-list: #{$prefix}-scrolllist;
             &:hover {
                 .#{$module}-range-input-clearbtn {
                     display: flex;
-                    color: $color-datepicker_range_input_clearbtn-icon-hover;
                     cursor: pointer;
                 }
 
                 .#{$module}-range-input-clearbtn ~ .#{$module}-range-input-suffix {
                     display: none;
                 }
+
+                .#{$module}-range-input-clearbtn:hover {
+                    color: $color-datepicker_range_input_clearbtn-icon-hover;
+                }
             }
 
             &-disabled {

+ 2 - 0
packages/semi-foundation/datePicker/foundation.ts

@@ -617,9 +617,11 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         const inputValue = '';
         if (!this._isControlledComponent('value')) {
             this._updateValueAndInput(value, true, inputValue);
+            this._adapter.updateInsetInputValue(null);
             this.resetCachedSelectedValue(value);
         }
         this._notifyChange(value);
+        this._adapter.setRangeInputFocus(false);
         this._adapter.notifyClear(e);
     }
     // eslint-disable-next-line @typescript-eslint/no-empty-function

+ 1 - 0
packages/semi-foundation/datePicker/inputFoundation.ts

@@ -261,6 +261,7 @@ export default class InputFoundation extends BaseFoundation<DateInputAdapter> {
             case 'dateTime':
             case 'dateTimeRange':
                 [datePlaceholder, timePlaceholder] = insetInputFormat.split(' ');
+                break;
             case 'monthRange':
                 datePlaceholder = insetInputFormat + rangeSeparator + insetInputFormat;
                 break;

+ 2 - 2
packages/semi-foundation/input/foundation.ts

@@ -270,8 +270,8 @@ class InputFoundation extends BaseFoundation<InputAdapter> {
 
     isAllowClear() {
         const { value, isFocus, isHovering } = this._adapter.getStates();
-        const { showClear, disabled } = this._adapter.getProps();
-        const allowClear = value && showClear && !disabled && (isFocus || isHovering);
+        const { showClear, disabled, showClearIgnoreDisabled } = this._adapter.getProps();
+        const allowClear = value && showClear && (!disabled || showClearIgnoreDisabled) && (isFocus || isHovering);
         return allowClear;
     }
 

+ 2 - 1
packages/semi-ui/datePicker/_story/datePicker.stories.jsx

@@ -67,7 +67,8 @@ export {
     FixNeedConfirmInTabs,
     DynamicDisabledDate,
     FeatEtcGMT,
-    FixDisabledDate
+    FixDisabledDate,
+    FeatInsetInputShowClear
 } from './v2';
 
 

+ 17 - 0
packages/semi-ui/datePicker/_story/v2/FeatInsetInputShowClear.tsx

@@ -0,0 +1,17 @@
+import React from "react";
+import { DatePicker, Space, Input } from "@douyinfe/semi-ui";
+
+export default function App() {
+    const props = {
+        insetInput: true,
+        showClear: true,
+        position: "topLeft"
+    } as const;
+    return (
+        <Space vertical align="start">
+            <DatePicker {...props} />
+            <DatePicker {...props} type="dateRange" />
+            <DatePicker {...props} type="dateTimeRange" />
+        </Space>
+    );
+}

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

@@ -25,3 +25,4 @@ export { default as DynamicDisabledDate } from './dynamicDisabledDate';
 export { default as FeatEtcGMT } from './FeatEtcGMT';
 export { default as FixDisabledDate } from './FixDisabledDate';
 export { default as FeatYearScrollRange } from './FeatYearScrollRange';
+export { default as FeatInsetInputShowClear } from './FeatInsetInputShowClear';

+ 10 - 6
packages/semi-ui/datePicker/dateInput.tsx

@@ -38,7 +38,8 @@ export interface DateInputProps extends DateInputFoundationProps, BaseProps {
     value?: Date[];
     inputRef?: React.RefObject<HTMLInputElement>;
     rangeInputStartRef?: React.RefObject<HTMLInputElement>;
-    rangeInputEndRef?: React.RefObject<HTMLInputElement>
+    rangeInputEndRef?: React.RefObject<HTMLInputElement>;
+    showClearIgnoreDisabled?: boolean
 }
 
 // eslint-disable-next-line @typescript-eslint/ban-types
@@ -200,15 +201,16 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
     }
 
     renderRangeClearBtn(rangeStart: string, rangeEnd: string) {
-        const { showClear, prefixCls, disabled, clearIcon } = this.props;
-        const allowClear = (rangeStart || rangeEnd) && showClear;
-        return allowClear && !disabled ? (
+        const { showClear, prefixCls, disabled, clearIcon, showClearIgnoreDisabled } = this.props;
+        const isRealDisabled = disabled && !showClearIgnoreDisabled;
+        const allowClear = (rangeStart || rangeEnd) && showClear && !isRealDisabled;
+        return allowClear ? (
             <div
                 role="button"
                 tabIndex={0}
                 aria-label="Clear range input value"
                 className={`${prefixCls}-range-input-clearbtn`}
-                onMouseDown={e => !disabled && this.handleRangeInputClear(e)}>
+                onMouseDown={e => this.handleRangeInputClear(e)}>
                 {clearIcon ? clearIcon : <IconClear aria-hidden />}
             </div>
         ) : null;
@@ -360,7 +362,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
                     onChange={this.handleInsetInputChange}
                     onFocus={handleInsetTimeFocus}
                 />
-                { this.isRenderMultipleInputs() && (
+                {this.isRenderMultipleInputs() && (
                     <>
                         <div className={separatorCls}>{density === 'compact' ? null : '-'}</div>
                         <InsetDateInput
@@ -420,6 +422,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
             insetInput,
             insetInputValue,
             defaultPickerValue,
+            showClearIgnoreDisabled,
             ...rest
         } = this.props;
         const dateIcon = <IconCalendar aria-hidden />;
@@ -448,6 +451,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
                 ref={inputRef}
                 insetLabel={insetLabel}
                 disabled={disabled}
+                showClearIgnoreDisabled={showClearIgnoreDisabled}
                 readonly={inputReadOnly}
                 className={inputCls}
                 style={inputStyle}

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

@@ -584,7 +584,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             defaultPickerValue
         };
 
-        return insetInput ? <DateInput {...props} insetInput={insetInput}/> : null;
+        return insetInput ? <DateInput {...props} insetInput={insetInput} /> : null;
     }
 
     handleOpenPanel = () => this.foundation.openPanel();
@@ -666,6 +666,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
         // These values should be passed to triggerRender, do not delete any key if it is not necessary
         const props = {
             ...extraProps,
+            showClearIgnoreDisabled: Boolean(insetInput),
             placeholder: phText,
             clearIcon,
             disabled: inputDisabled,

+ 7 - 10
packages/semi-ui/input/index.tsx

@@ -66,7 +66,9 @@ export interface InputProps extends
     inputStyle?: React.CSSProperties;
     getValueLength?: (value: string) => number;
     forwardRef?: ((instance: any) => void) | React.MutableRefObject<any> | null;
-    preventScroll?: boolean
+    preventScroll?: boolean;
+    /** internal prop, DatePicker use it */
+    showClearIgnoreDisabled?: boolean
 }
 
 export interface InputState {
@@ -309,7 +311,7 @@ class Input extends BaseComponent<InputProps, InputState> {
                     className={clearCls}
                     onMouseDown={this.handleClear}
                 >
-                    { clearIcon ? clearIcon : <IconClear />}
+                    {clearIcon ? clearIcon : <IconClear />}
                 </div>
             );
         }
@@ -370,12 +372,6 @@ class Input extends BaseComponent<InputProps, InputState> {
         );
     }
 
-    showClearBtn() {
-        const { value, isFocus, isHovering } = this.state;
-        const { disabled, showClear } = this.props;
-        return Boolean(value) && showClear && !disabled && (isFocus || isHovering);
-    }
-
     renderSuffix(suffixAllowClear: boolean) {
         const { suffix, hideSuffix } = this.props;
         if (!suffix) {
@@ -406,7 +402,7 @@ class Input extends BaseComponent<InputProps, InputState> {
             if (typeof forwardRef === 'function') {
                 return (node: HTMLInputElement) => {
                     forwardRef(node);
-                    this.inputRef = { current: node } ;
+                    this.inputRef = { current: node };
                 };
             } else if (Object.prototype.toString.call(forwardRef) === '[object Object]') {
                 this.inputRef = forwardRef;
@@ -446,10 +442,11 @@ class Input extends BaseComponent<InputProps, InputState> {
             getValueLength,
             preventScroll,
             borderless,
+            showClearIgnoreDisabled,
             ...rest
         } = this.props;
         const { value, isFocus, minLength: stateMinLength } = this.state;
-        const suffixAllowClear = this.showClearBtn();
+        const suffixAllowClear = this.foundation.isAllowClear();
         const suffixIsIcon = isSemiIcon(suffix);
         const ref = this.getInputRef();
         const wrapperPrefix = `${prefixCls}-wrapper`;