Pārlūkot izejas kodu

Merge branch 'main' into release

DaiQiangReal 3 gadi atpakaļ
vecāks
revīzija
8235f05eb6

+ 1 - 1
content/input/input/index-en-US.md

@@ -457,7 +457,7 @@ Answers to some questions:
 
 
 ### InputGroup
 ### InputGroup
 
 
-Common attributes will be set to the child elements of InputGroup, such as disabled, onFocus, etc. If the child sets the same attribute separately, the child has a higher priority.
+Common attributes will be set to the child elements of InputGroup, such as disabled, onFocus, etc. If you set onFocus, onBlur or disabled on the child, it will override the corresponding property value of InputGroup.
 
 
 
 
 | Property      | Instructions                                | Type                                                          | Default |
 | Property      | Instructions                                | Type                                                          | Default |

+ 1 - 1
content/input/input/index.md

@@ -465,7 +465,7 @@ import { Input, Typography, Form, TextArea, Button } from '@douyinfe/semi-ui';
 
 
 ### InputGroup
 ### InputGroup
 
 
-通用属性将设置到 InputGroup 的子级元素上,例如 disabled、onFocus 等,如果子级单独设置了相同属性,子级的优先级更高
+通用属性将设置到 InputGroup 的子级元素上,例如 disabled、onFocus 等。如果你在子级设置了 onFocus、onBlur 或 disabled,会覆盖掉 InputGroup 对应属性值
 
 
 
 
 | 属性          | 说明                           | 类型                                                          | 默认值    |
 | 属性          | 说明                           | 类型                                                          | 默认值    |

+ 11 - 30
cypress/integration/cascader.spec.js

@@ -2,39 +2,27 @@ describe('cascader', () => {
     it('clear when single choose', () => {
     it('clear when single choose', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
         cy.viewport(1500, 1000);
         cy.viewport(1500, 1000);
-
-        cy.get('input').eq(0).click();
-        cy.get('span').contains('Node1').click();
-        cy.get('span').contains('Child Node2').click();
-        cy.get('input').should('have.value', 'Node1 / Child Node2');
-        cy.get('input').eq(0).trigger('mouseover');
-        cy.get('.semi-cascader-clearbtn').click();
-        cy.get('input').should('have.value', '');
-
-        // clear when search
-        cy.get('input').eq(0).click();
-        // wait the panel open
-        cy.wait(100);
+        cy.get('.semi-cascader-selection').eq(0).click();
         cy.get('span').contains('Node1').click();
         cy.get('span').contains('Node1').click();
         cy.get('span').contains('Child Node2').click();
         cy.get('span').contains('Child Node2').click();
-        cy.get('input').eq(0).type('Node1');
-        cy.get('input').eq(0).trigger('mouseover');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('Child Node2').should('exist');
+        cy.get('.semi-cascader-selection').eq(0).trigger('mouseover');
         cy.get('.semi-cascader-clearbtn').click();
         cy.get('.semi-cascader-clearbtn').click();
-        cy.get('input').should('have.attr', 'placeholder', 'Node1 / Child Node2');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('Child Node2').should('not.exist');
     });
     });
 
 
     it('clear by key press', () => {
     it('clear by key press', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
         cy.viewport(1500, 1000);
         cy.viewport(1500, 1000);
 
 
-        cy.get('input').eq(0).click();
+        cy.get('.semi-cascader-selection').eq(0).click();
         cy.get('span').contains('Node1').click();
         cy.get('span').contains('Node1').click();
         cy.get('span').contains('Child Node2').click();
         cy.get('span').contains('Child Node2').click();
-        cy.get('input').should('have.value', 'Node1 / Child Node2');
-        cy.get('input').eq(0).trigger('mouseover');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('Child Node2').should('exist');
+        cy.get('.semi-cascader-selection').eq(0).trigger('mouseover');
         cy.get(".semi-cascader-clearbtn").focus();
         cy.get(".semi-cascader-clearbtn").focus();
         cy.get('.semi-cascader-clearbtn').type('{enter}');
         cy.get('.semi-cascader-clearbtn').type('{enter}');
-        cy.get('input').should('have.value', '');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('Child Node2').should('not.exist');;
         cy.get('#root').click('right');
         cy.get('#root').click('right');
 
 
         cy.get('.semi-cascader').eq(1).click();
         cy.get('.semi-cascader').eq(1).click();
@@ -68,14 +56,7 @@ describe('cascader', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--dynamic-placeholder&args=&viewMode=story');
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--dynamic-placeholder&args=&viewMode=story');
         cy.get('.semi-cascader-selection-placeholder').contains('Please select');
         cy.get('.semi-cascader-selection-placeholder').contains('Please select');
         cy.get('.semi-button-content').contains('Toggle').click();
         cy.get('.semi-button-content').contains('Toggle').click();
-        cy.get('.semi-input-default').should('have.attr', 'placeholder', 'Search something');
-    });
-
-    it('placeholder change', () => {
-        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--dynamic-placeholder&args=&viewMode=story');
-        cy.get('.semi-cascader-selection-placeholder').contains('Please select');
-        cy.get('.semi-button-content').contains('Toggle').click();
-        cy.get('.semi-input-default').should('have.attr', 'placeholder', 'Search something');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('Search something').should('exist');
     });
     });
 
 
     it('load data', () => {
     it('load data', () => {
@@ -112,7 +93,7 @@ describe('cascader', () => {
     it('not exit default value', () => {
     it('not exit default value', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--default-value-not-exist&args=&viewMode=story');
         cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--default-value-not-exist&args=&viewMode=story');
         
         
-        cy.get('input').should('have.value', 'yazhou not exist');
+        cy.get('.semi-cascader-search-wrapper span').eq(0).contains('yazhou not exist').should('exist');
     });
     });
    
    
     it('multiple onChangeWithObject value=undefined', () => {
     it('multiple onChangeWithObject value=undefined', () => {
@@ -121,5 +102,5 @@ describe('cascader', () => {
         cy.get('.semi-cascader').click();
         cy.get('.semi-cascader').click();
         cy.get('.semi-checkbox').eq(0).click();
         cy.get('.semi-checkbox').eq(0).click();
         cy.get('.semi-tag-content').contains('亚洲');
         cy.get('.semi-tag-content').contains('亚洲');
-    })
+    });
 });
 });

+ 20 - 0
packages/semi-foundation/cascader/cascader.scss

@@ -175,6 +175,17 @@ $module: #{$prefix}-cascader;
                 height: $height-cascader_selection_tagInput_input_large;
                 height: $height-cascader_selection_tagInput_input_large;
             }
             }
         }
         }
+
+        &-text {
+
+            &-inactive {
+                color: $color-cascader_selection_text_inactive;
+            }
+
+            &-hide {
+                display: none;
+            }
+        }
     }
     }
 
 
     &-arrow,
     &-arrow,
@@ -294,8 +305,17 @@ $module: #{$prefix}-cascader;
     .#{$module}-selection {
     .#{$module}-selection {
         .#{$module}-search-wrapper {
         .#{$module}-search-wrapper {
             width: 100%;
             width: 100%;
+            height: $height-cascader_selection_wrapper;
+            display: flex;
+            align-items: center;
+            position: relative;
 
 
             .#{$prefix}-input-wrapper {
             .#{$prefix}-input-wrapper {
+                position: absolute;
+                top: 0;
+                left: 0;
+                border: none;
+                background-color: transparent;
                 height: 100%;
                 height: 100%;
                 width: 100%;
                 width: 100%;
                 border: $color-cascader_input-border-default;
                 border: $color-cascader_input-border-default;

+ 20 - 0
packages/semi-foundation/cascader/foundation.ts

@@ -184,6 +184,7 @@ export interface BasicCascaderInnerData {
     isFocus?: boolean;
     isFocus?: boolean;
     isInput?: boolean;
     isInput?: boolean;
     disabledKeys?: Set<string>;
     disabledKeys?: Set<string>;
+    showInput?: boolean;
 }
 }
 
 
 export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, BasicCascaderInnerData> {
 export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, BasicCascaderInnerData> {
@@ -209,6 +210,8 @@ export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, Basi
     notifyOnLoad: (newLoadedKeys: Set<string>, data: BasicCascaderData) => void;
     notifyOnLoad: (newLoadedKeys: Set<string>, data: BasicCascaderData) => void;
     notifyListScroll: (e: any, panel: BasicScrollPanelProps) => void;
     notifyListScroll: (e: any, panel: BasicScrollPanelProps) => void;
     notifyOnExceed: (data: BasicEntity[]) => void;
     notifyOnExceed: (data: BasicEntity[]) => void;
+    toggleInputShow: (show: boolean, cb: () => void) => void;
+    updateFocusState: (focus: boolean) => void,
 }
 }
 
 
 // eslint-disable-next-line max-len
 // eslint-disable-next-line max-len
@@ -485,9 +488,11 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
 
 
     open() {
     open() {
         const filterable = this._isFilterable();
         const filterable = this._isFilterable();
+        const { multiple } = this.getProps();
         this._adapter.openMenu();
         this._adapter.openMenu();
         if (filterable) {
         if (filterable) {
             this._clearInput();
             this._clearInput();
+            !multiple && this.toggle2SearchInput(true);
         }
         }
         if (this._isControlledComponent()) {
         if (this._isControlledComponent()) {
             this.reCalcActiveKeys();
             this.reCalcActiveKeys();
@@ -525,10 +530,25 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
                 inputValue = this.renderDisplayText([...selectedKeys][0]);
                 inputValue = this.renderDisplayText([...selectedKeys][0]);
             }
             }
             this._adapter.updateStates({ inputValue });
             this._adapter.updateStates({ inputValue });
+            !multiple && this.toggle2SearchInput(false);
+            !multiple && this._adapter.updateFocusState(false);
         }
         }
         this._notifyBlur(e);
         this._notifyBlur(e);
     }
     }
 
 
+    toggle2SearchInput(isShow: boolean) {
+        if (isShow) {
+            this._adapter.toggleInputShow(isShow, () => this.focusInput());
+        } else {
+            this._adapter.toggleInputShow(isShow, () => undefined);
+        }
+    }
+
+    focusInput() {
+        this._adapter.focusInput();
+        this._adapter.updateFocusState(true);
+    }
+
     getMergedMotion = () => {
     getMergedMotion = () => {
         const { motion } = this.getProps();
         const { motion } = this.getProps();
         const { isSearching } = this.getStates();
         const { isSearching } = this.getStates();

+ 2 - 0
packages/semi-foundation/cascader/variables.scss

@@ -54,6 +54,7 @@ $spacing-cascader_clearBtn-marginRight: 12px; // 级联选择触发器清空按
 
 
 $color-cascader_selection_n-text-default: var(--semi-color-text-0); // 超出 maxTagCount 后,+n 的文字默认颜色
 $color-cascader_selection_n-text-default: var(--semi-color-text-0); // 超出 maxTagCount 后,+n 的文字默认颜色
 $color-cascader_selection_n-text-disabled: var(--semi-color-disabled-text); // 超出 maxTagCount 后,+n 的文字disabled颜色
 $color-cascader_selection_n-text-disabled: var(--semi-color-disabled-text); // 超出 maxTagCount 后,+n 的文字disabled颜色
+$color-cascader_selection_text_inactive: var(--semi-color-text-2); // 级联选择单选inpu输入框和text并存时,text颜色
 $color-cascader_selection-text-default: var(--semi-color-text-0); // 级联选择选中项文字颜色
 $color-cascader_selection-text-default: var(--semi-color-text-0); // 级联选择选中项文字颜色
 $color-cascader_placeholder-text-default: var(--semi-color-text-2); // 级联选择未选中项文字颜色
 $color-cascader_placeholder-text-default: var(--semi-color-text-2); // 级联选择未选中项文字颜色
 $color-cascader-icon-default: var(--semi-color-text-2); // 级联选择图标颜色 - 默认
 $color-cascader-icon-default: var(--semi-color-text-2); // 级联选择图标颜色 - 默认
@@ -94,6 +95,7 @@ $height-cascader_option_list: 180px; // 级联选择菜单高度
 $height-cascader_selection_tagInput_input_small: 22px;
 $height-cascader_selection_tagInput_input_small: 22px;
 $height-cascader_selection_tagInput_input_default: 30px;
 $height-cascader_selection_tagInput_input_default: 30px;
 $height-cascader_selection_tagInput_input_large: 38px;
 $height-cascader_selection_tagInput_input_large: 38px;
+$height-cascader_selection_wrapper: 30px;
 
 
 $spacing-cascader_text-marginX: $spacing-base-tight; // 级联选择 prefix/suffix 文字水平内间距
 $spacing-cascader_text-marginX: $spacing-base-tight; // 级联选择 prefix/suffix 文字水平内间距
 $spacing-cascader_icon-marginX: $spacing-tight; // 级联选择 prefix/suffix 图标水平内间距
 $spacing-cascader_icon-marginX: $spacing-tight; // 级联选择 prefix/suffix 图标水平内间距

+ 5 - 1
packages/semi-foundation/treeSelect/foundation.ts

@@ -429,13 +429,17 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
 
 
     handleClick(e: any) {
     handleClick(e: any) {
         const isDisabled = this._isDisabled();
         const isDisabled = this._isDisabled();
-        const { isOpen } = this.getStates();
+        const { isOpen, inputValue } = this.getStates();
+        const { searchPosition } = this.getProps();
         if (isDisabled) {
         if (isDisabled) {
             return;
             return;
         } else if (!isOpen) {
         } else if (!isOpen) {
             this.open();
             this.open();
             this._notifyFocus(e);
             this._notifyFocus(e);
         } else if (isOpen) {
         } else if (isOpen) {
+            if (searchPosition === 'trigger' && inputValue) {
+                return;
+            }
             this.close(e);
             this.close(e);
         }
         }
     }
     }

+ 0 - 1
packages/semi-ui/autoComplete/index.tsx

@@ -169,7 +169,6 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple
         position: 'bottomLeft' as const,
         position: 'bottomLeft' as const,
         data: [] as [],
         data: [] as [],
         showClear: false,
         showClear: false,
-        disabled: false,
         size: 'default' as const,
         size: 'default' as const,
         onFocus: noop,
         onFocus: noop,
         onSearch: noop,
         onSearch: noop,

+ 13 - 10
packages/semi-ui/cascader/__test__/cascader.test.js

@@ -427,10 +427,10 @@ describe('Cascader', () => {
         });
         });
         expect(
         expect(
             cascaderWithSingleFilter
             cascaderWithSingleFilter
-            .find(`.${BASE_CLASS_PREFIX}-cascader-search-wrapper .${BASE_CLASS_PREFIX}-input`)
+            .find(`.${BASE_CLASS_PREFIX}-cascader-search-wrapper span`)
             .getDOMNode()
             .getDOMNode()
-            .getAttribute('value')
-        ).toEqual('亚洲 / 中国');
+            .textContent
+            ).toEqual('亚洲 / 中国');
         cascaderWithSingleFilter.unmount();
         cascaderWithSingleFilter.unmount();
 
 
         const cascaderWithSingleControlled = render({
         const cascaderWithSingleControlled = render({
@@ -550,10 +550,10 @@ describe('Cascader', () => {
         expect(searchWrapper.exists()).toEqual(true);
         expect(searchWrapper.exists()).toEqual(true);
         expect(
         expect(
             searchWrapper
             searchWrapper
-                .find('input')
-                .instance()
-                .getAttribute('placeholder')
-        ).toEqual('placeholder');
+                .find('span')
+                .getDOMNode()
+                .textContent
+            ).toEqual('placeholder');
     });
     });
 
 
     it('onSearch', () => {
     it('onSearch', () => {
@@ -563,10 +563,11 @@ describe('Cascader', () => {
             filterTreeNode: true,
             filterTreeNode: true,
             onSearch: spyOnSearch,
             onSearch: spyOnSearch,
         });
         });
-        const searchWrapper = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-search-wrapper`);
         let searchValue = '${BASE_CLASS_PREFIX}';
         let searchValue = '${BASE_CLASS_PREFIX}';
         let event = { target: { value: searchValue } };
         let event = { target: { value: searchValue } };
-        searchWrapper.find('input').simulate('change', event);
+        cascader.simulate('click');
+        const input = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection input`);
+        input.simulate('change', event);
         expect(spyOnSearch.calledOnce).toBe(true);
         expect(spyOnSearch.calledOnce).toBe(true);
         expect(spyOnSearch.calledWithMatch(searchValue)).toBe(true);
         expect(spyOnSearch.calledWithMatch(searchValue)).toBe(true);
     });
     });
@@ -1228,8 +1229,10 @@ describe('Cascader', () => {
             separator: ' > ',
             separator: ' > ',
             defaultOpen: true,
             defaultOpen: true,
         });
         });
+        const span = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection span`);
+        expect(span.getDOMNode().textContent).toEqual('亚洲 > 中国 > 北京'); 
+        cascader.simulate('click');
         const input = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection input`);
         const input = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection input`);
-        expect(input.props().placeholder).toEqual('亚洲 > 中国 > 北京'); 
         const event = { target: { value: '中国' } };
         const event = { target: { value: '中国' } };
         input.simulate('change', event);
         input.simulate('change', event);
         expect(
         expect(

+ 22 - 0
packages/semi-ui/cascader/_story/cascader.stories.js

@@ -396,6 +396,28 @@ Searchable.parameters = {
   chromatic: { disableSnapshot: false },
   chromatic: { disableSnapshot: false },
 }
 }
 
 
+export const filterTreeNodeAndDisplayRender = () => {
+  return (
+    <>
+      <div>
+          filterTreeNode=true,配合displayRender 使用,回显到input的内容也是符合预期
+      </div>
+      <Cascader
+        filterTreeNode
+        style={{ width: 300 }}
+        treeData={treeData4}
+        placeholder="自定义回填时显示数据的格式"
+        defaultValue={['zhejiang', 'ningbo', 'jiangbei']}
+        displayRender={(item) => {
+          console.log('item', item);
+          return <div>
+              {'已选择:' + item.join(' -> ')}
+          </div>;}}
+      />
+    </>
+  );
+};
+
 export const Disabled = () => {
 export const Disabled = () => {
   return (
   return (
     <div>
     <div>

+ 27 - 11
packages/semi-ui/cascader/index.tsx

@@ -181,7 +181,6 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         showClear: false,
         showClear: false,
         autoClearSearchValue: true,
         autoClearSearchValue: true,
         changeOnSelect: false,
         changeOnSelect: false,
-        disabled: false,
         disableStrictly: false,
         disableStrictly: false,
         autoMergeValue: true,
         autoMergeValue: true,
         multiple: false,
         multiple: false,
@@ -249,6 +248,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
             loadingKeys: new Set(),
             loadingKeys: new Set(),
             /* Mark whether this rendering has triggered asynchronous loading of data */
             /* Mark whether this rendering has triggered asynchronous loading of data */
             loading: false,
             loading: false,
+            showInput: false,
         };
         };
         this.options = {};
         this.options = {};
         this.isEmpty = false;
         this.isEmpty = false;
@@ -365,6 +365,14 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
             },
             },
             notifyOnExceed: data => this.props.onExceed(data),
             notifyOnExceed: data => this.props.onExceed(data),
             notifyClear: () => this.props.onClear(),
             notifyClear: () => this.props.onClear(),
+            toggleInputShow: (showInput: boolean, cb: (...args: any) => void) => {
+                this.setState({ showInput }, () => {
+                    cb();
+                });
+            },
+            updateFocusState: (isFocus: boolean) => {
+                this.setState({ isFocus });
+            },
         };
         };
     }
     }
 
 
@@ -544,20 +552,28 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
     renderInput() {
     renderInput() {
         const { size, disabled } = this.props;
         const { size, disabled } = this.props;
         const inputcls = cls(`${prefixcls}-input`);
         const inputcls = cls(`${prefixcls}-input`);
-        const { inputValue, inputPlaceHolder } = this.state;
+        const { inputValue, inputPlaceHolder, showInput } = this.state;
         const inputProps = {
         const inputProps = {
             disabled,
             disabled,
             value: inputValue,
             value: inputValue,
             className: inputcls,
             className: inputcls,
             onChange: this.handleInputChange,
             onChange: this.handleInputChange,
-            placeholder: inputPlaceHolder,
         };
         };
         const wrappercls = cls({
         const wrappercls = cls({
             [`${prefixcls}-search-wrapper`]: true,
             [`${prefixcls}-search-wrapper`]: true,
         });
         });
+
+        const displayText = this.renderDisplayText();
+        const spanCls = cls({
+            [`${prefixcls}-selection-placeholder`]: !displayText,
+            [`${prefixcls}-selection-text-hide`]: showInput && inputValue,
+            [`${prefixcls}-selection-text-inactive`]: showInput && !inputValue,
+        });
+
         return (
         return (
             <div className={wrappercls}>
             <div className={wrappercls}>
-                <Input ref={this.inputRef as any} size={size} {...inputProps} />
+                <span className={spanCls}>{displayText ? displayText : inputPlaceHolder}</span>
+                {showInput && <Input ref={this.inputRef as any} size={size} {...inputProps} />}
             </div>
             </div>
         );
         );
     }
     }
@@ -868,9 +884,9 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         const { isOpen, isFocus, isInput, checkedKeys } = this.state;
         const { isOpen, isFocus, isInput, checkedKeys } = this.state;
         const filterable = Boolean(filterTreeNode);
         const filterable = Boolean(filterTreeNode);
         const useCustomTrigger = typeof triggerRender === 'function';
         const useCustomTrigger = typeof triggerRender === 'function';
-        const classNames = useCustomTrigger
-            ? cls(className)
-            : cls(prefixcls, className, {
+        const classNames = useCustomTrigger ?
+            cls(className) :
+            cls(prefixcls, className, {
                 [`${prefixcls}-focus`]: isFocus || (isOpen && !isInput),
                 [`${prefixcls}-focus`]: isFocus || (isOpen && !isInput),
                 [`${prefixcls}-disabled`]: disabled,
                 [`${prefixcls}-disabled`]: disabled,
                 [`${prefixcls}-single`]: true,
                 [`${prefixcls}-single`]: true,
@@ -882,12 +898,12 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                 [`${prefixcls}-with-prefix`]: prefix || insetLabel,
                 [`${prefixcls}-with-prefix`]: prefix || insetLabel,
                 [`${prefixcls}-with-suffix`]: suffix,
                 [`${prefixcls}-with-suffix`]: suffix,
             });
             });
-        const mouseEvent = showClear
-            ? {
+        const mouseEvent = showClear ?
+            {
                 onMouseEnter: () => this.handleMouseOver(),
                 onMouseEnter: () => this.handleMouseOver(),
                 onMouseLeave: () => this.handleMouseLeave(),
                 onMouseLeave: () => this.handleMouseLeave(),
-            }
-            : {};
+            } :
+            {};
         const sectionCls = cls(`${prefixcls}-selection`, {
         const sectionCls = cls(`${prefixcls}-selection`, {
             [`${prefixcls}-selection-multiple`]: multiple && !isEmpty(checkedKeys),
             [`${prefixcls}-selection-multiple`]: multiple && !isEmpty(checkedKeys),
         });
         });

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

@@ -139,7 +139,6 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
         type: 'date',
         type: 'date',
         size: 'default',
         size: 'default',
         density: 'default',
         density: 'default',
-        disabled: false,
         multiple: false,
         multiple: false,
         defaultOpen: false,
         defaultOpen: false,
         disabledHours: noop,
         disabledHours: noop,

+ 31 - 0
packages/semi-ui/input/__test__/input.test.js

@@ -3,6 +3,7 @@ import Icon from '../../icons/index';
 import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
 import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
 import GraphemeSplitter from 'grapheme-splitter';
 import GraphemeSplitter from 'grapheme-splitter';
 import { isString, isFunction } from 'lodash';
 import { isString, isFunction } from 'lodash';
+import { InputGroup, InputNumber } from '../../index';
 
 
 function getValueLength(str) {
 function getValueLength(str) {
   if (isString(str)) {
   if (isString(str)) {
@@ -251,4 +252,34 @@ describe('Input', () => {
       expect(truncateValue(value, length, fc)).toBe(result);
       expect(truncateValue(value, length, fc)).toBe(result);
     }
     }
   })
   })
+
+  it('input group', () => {
+    const groupFocus = sinon.spy(() => {
+      console.log('group focus');
+    });
+    const groupBlur = sinon.spy(() => {
+      console.log('group focus');
+    });
+    const inputFocus = sinon.spy(() => {
+      console.log('input focus');
+    });
+    const inputBlur = sinon.spy(() => {
+      console.log('input blur');
+    });
+    const inputGroup = mount(
+      <InputGroup disabled={true} onFocus={groupFocus} onBlur={groupBlur}>
+          <Input disabled={false} onFocus={inputFocus} onBlur={inputBlur} placeholder="Name" style={{ width: 100 }} />
+          <InputNumber placeholder="Score" style={{ width: 140 }} />
+      </InputGroup>
+    );
+
+    inputGroup.find('input').at(0).simulate('focus');
+    expect(inputFocus.called).toBe(true);
+    expect(groupFocus.called).toBe(true);
+    inputGroup.find('input').at(0).simulate('blur');
+    expect(inputBlur.called).toBe(true);
+    expect(groupBlur.called).toBe(true);
+    expect(inputGroup.find('input').at(0).instance().disabled).toBe(false);
+    expect(inputGroup.find('input').at(1).instance().disabled).toBe(true);
+  })
 });
 });

+ 24 - 1
packages/semi-ui/input/_story/input.stories.js

@@ -22,7 +22,8 @@ import {
   Switch,
   Switch,
   Form,
   Form,
   Space,
   Space,
-  Radio
+  Radio,
+  InputNumber
 } from '../../index';
 } from '../../index';
 import './input.scss';
 import './input.scss';
 import RTLWrapper from '../../configProvider/_story/RTLDirection/RTLWrapper';
 import RTLWrapper from '../../configProvider/_story/RTLDirection/RTLWrapper';
@@ -936,3 +937,25 @@ export const InputA11y = () => {
   );
   );
 }
 }
 InputA11y.storyName = "input a11y";
 InputA11y.storyName = "input a11y";
+
+export const FixInputGroup = () => {
+  const groupFocus = () => {
+    console.log('group focus');
+  }
+  const groupBlur = () => {
+    console.log('group blur');
+  }
+  const inputFocus = () => {
+    console.log('input focus');
+  }
+  const inputBlur = () => {
+    console.log('input blur');
+  }
+
+  return (
+    <InputGroup disabled={true} onFocus={groupFocus} onBlur={groupBlur}>
+        <Input disabled={false} onFocus={inputFocus} onBlur={inputBlur} placeholder="Name" style={{ width: 100 }} />
+        <InputNumber placeholder="Score" style={{ width: 140 }} />
+    </InputGroup>
+  );
+}

+ 0 - 1
packages/semi-ui/input/index.tsx

@@ -126,7 +126,6 @@ class Input extends BaseComponent<InputProps, InputState> {
         addonAfter: '',
         addonAfter: '',
         prefix: '',
         prefix: '',
         suffix: '',
         suffix: '',
-        disabled: false,
         readonly: false,
         readonly: false,
         type: 'text',
         type: 'text',
         showClear: false,
         showClear: false,

+ 7 - 6
packages/semi-ui/input/inputGroup.tsx

@@ -7,7 +7,7 @@ import BaseComponent from '../_base/baseComponent';
 import Label, { LabelProps } from '../form/label';
 import Label, { LabelProps } from '../form/label';
 
 
 import { noop } from '@douyinfe/semi-foundation/utils/function';
 import { noop } from '@douyinfe/semi-foundation/utils/function';
-import { isFunction } from 'lodash';
+import { get, isFunction } from 'lodash';
 
 
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 const sizeSet = strings.SIZE;
 const sizeSet = strings.SIZE;
@@ -84,7 +84,7 @@ export default class inputGroup extends BaseComponent<InputGroupProps, InputGrou
     }
     }
 
 
     render() {
     render() {
-        const { size, style, className, children, label, onBlur: groupOnBlur, onFocus: groupOnFocus, ...rest } = this.props;
+        const { size, style, className, children, label, onBlur: groupOnBlur, onFocus: groupOnFocus, disabled: groupDisabled, ...rest } = this.props;
         const groupCls = cls(
         const groupCls = cls(
             `${prefixCls}-group`,
             `${prefixCls}-group`,
             {
             {
@@ -96,10 +96,11 @@ export default class inputGroup extends BaseComponent<InputGroupProps, InputGrou
         if (children) {
         if (children) {
             inner = (Array.isArray(children) ? children : [children]).map((item, index) => {
             inner = (Array.isArray(children) ? children : [children]).map((item, index) => {
                 if (item) {
                 if (item) {
-                    const { onBlur: itemOnBlur, onFocus: itemOnFocus } = (item as any).props;
-                    const onBlur = isFunction(itemOnBlur) ? itemOnBlur : groupOnBlur;
-                    const onFocus = isFunction(itemOnFocus) ? itemOnFocus : groupOnFocus;
-                    return React.cloneElement(item as any, { key: index, size, onBlur, onFocus, ...rest });
+                    const { onBlur: itemOnBlur, onFocus: itemOnFocus, disabled: itemDisabled } = (item as any).props;
+                    const onBlur = isFunction(itemOnBlur) && get(itemOnBlur, 'name') !== 'noop'  ? itemOnBlur : groupOnBlur;
+                    const onFocus = isFunction(itemOnFocus) && get(itemOnFocus, 'name') !== 'noop' ? itemOnFocus : groupOnFocus;
+                    const disabled = typeof itemDisabled === 'boolean' ? itemDisabled : groupDisabled;
+                    return React.cloneElement(item as any, { key: index, ...rest, size, onBlur, onFocus, disabled });
                 }
                 }
                 return null;
                 return null;
             });
             });

+ 0 - 1
packages/semi-ui/inputNumber/index.tsx

@@ -99,7 +99,6 @@ class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
     };
     };
 
 
     static defaultProps: InputNumberProps = {
     static defaultProps: InputNumberProps = {
-        disabled: false,
         forwardedRef: noop,
         forwardedRef: noop,
         innerButtons: false,
         innerButtons: false,
         keepFocus: false,
         keepFocus: false,

+ 4 - 1
packages/semi-ui/treeSelect/index.tsx

@@ -265,7 +265,6 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
         motionExpand: true,
         motionExpand: true,
         expandAll: false,
         expandAll: false,
         zIndex: popoverNumbers.DEFAULT_Z_INDEX,
         zIndex: popoverNumbers.DEFAULT_Z_INDEX,
-        disabled: false,
         disableStrictly: false,
         disableStrictly: false,
         multiple: false,
         multiple: false,
         filterTreeNode: false,
         filterTreeNode: false,
@@ -864,6 +863,10 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
     };
     };
 
 
     search = (value: string) => {
     search = (value: string) => {
+        const { isOpen } = this.state;
+        if (!isOpen) {
+            this.foundation.open();
+        }
         this.foundation.handleInputChange(value);
         this.foundation.handleInputChange(value);
     };
     };