瀏覽代碼

fix: Fix the abnormal expansion status of selected options after selecting options in single selection, filterTreeNode, and loadData TreeSelect

zhangyumei.0319 1 年之前
父節點
當前提交
6979b04414
共有 3 個文件被更改,包括 57 次插入25 次删除
  1. 13 2
      cypress/e2e/treeSelect.spec.js
  2. 31 3
      packages/semi-foundation/treeSelect/foundation.ts
  3. 13 20
      packages/semi-ui/treeSelect/index.tsx

+ 13 - 2
cypress/e2e/treeSelect.spec.js

@@ -146,9 +146,20 @@ describe('treeSelect', () => {
         cy.get('.semi-tree-select-selection').eq(0).trigger('click');
         cy.wait(1000);
         // 此时展开项目由选中项和原来的 state 中的 expandedKeys 决定
-        cy.get('.semi-tree-option').should('have.length', 4);
+        cy.get('.semi-tree-option').should('have.length', 2);
         cy.get('.semi-icon-tree_triangle_down').eq(0).trigger('click');
-        cy.get('.semi-tree-option').should('have.length', 6);
+        cy.get('.semi-tree-option').should('have.length', 4);
     });
+
+    it.only('filterTreeNode + loadData', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=treeselect--load-data');
+        cy.get('.semi-tree-select-selection').eq(0).trigger('click');
+        cy.wait(1000);
+        cy.get('.semi-tree-option').eq(0).trigger('click');
+        cy.get('.semi-tree-option-list').should('not.exist');
+        cy.get('.semi-tree-select-selection').eq(0).trigger('click');
+        cy.wait(1000);
+        cy.get('.semi-tree-option.semi-tree-option-level-1.semi-tree-option-selected.semi-tree-option-collapsed').should('exist');
+    })
 });
 

+ 31 - 3
packages/semi-foundation/treeSelect/foundation.ts

@@ -199,7 +199,9 @@ export interface TreeSelectAdapter<P = Record<string, any>, S = Record<string, a
     notifyLoad: (newLoadedKeys: Set<string>, data: BasicTreeNodeData) => void;
     updateInputFocus: (bool: boolean) => void;
     updateLoadKeys: (data: BasicTreeNodeData, resolve: (value?: any) => void) => void;
-    updateIsFocus: (bool: boolean) => void
+    updateIsFocus: (bool: boolean) => void;
+    setClearInputSign: (sign: boolean) => void;
+    getClearInputSign: () => boolean
 }
 
 export default class TreeSelectFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<TreeSelectAdapter<P, S>, P, S> {
@@ -588,7 +590,7 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         const { keyMaps } = this.getProps();
         const newExpandedKeys: Set<string> = new Set(expandedKeys);
         const isExpandControlled = this._isExpandControlled();
-        const expandedOptsKeys = findAncestorKeys(selectedKeys, keyEntities);
+        const expandedOptsKeys = findAncestorKeys(selectedKeys, keyEntities, false);
         expandedOptsKeys.forEach(item => newExpandedKeys.add(item));
         const newFlattenNodes = flattenTreeData(treeData, newExpandedKeys, keyMaps);
 
@@ -615,7 +617,7 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         let newFlattenNodes = [];
         let filteredShownKeys = new Set([]);
         if (!sugInput) {
-            expandedOptsKeys = findAncestorKeys(selectedKeys, keyEntities);
+            expandedOptsKeys = findAncestorKeys(selectedKeys, keyEntities, false);
             expandedOptsKeys.forEach(item => newExpandedKeys.add(item));
             newFlattenNodes = flattenTreeData(treeData, newExpandedKeys, keyMaps);
         } else {
@@ -880,4 +882,30 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
     setLoadKeys(data: BasicTreeNodeData, resolve: (value?: any) => void) {
         this._adapter.updateLoadKeys(data, resolve);
     }
+
+    handlePopoverVisibleChange(isVisible: boolean) {
+        const { filterTreeNode, searchAutoFocus, searchPosition } = this.getProps();
+        const inputValue = this.getState('inputValue');
+        // 将 inputValue 清空,如果有选中值的话,选中项能够快速回显
+        // Clear the inputValue. If there is a selected value, the selected item can be quickly echoed.
+        if (isVisible === false && filterTreeNode) {
+            inputValue && this._adapter.setClearInputSign(true);
+            this.clearInputValue(); 
+        }
+        if (filterTreeNode && searchPosition === strings.SEARCH_POSITION_DROPDOWN && isVisible && searchAutoFocus) {
+            this.focusInput(true);
+        }
+    }
+
+    handleAfterClose() {
+        // flattenNode 的变化将导致弹出层面板中的选项数目变化
+        // 在弹层完全收起之后,再通过 clearInput 重新计算 state 中的 expandedKey, flattenNode
+        // 防止在弹出层未收起时弹层面板中选项数目变化导致视觉上出现弹层闪动问题
+        // Changes to flattenNode will cause the number of options in the popup panel to change
+        // After the pop-up layer is completely closed, recalculate the expandedKey and flattenNode in the state through clearInput.
+        // Prevent the pop-up layer from flickering visually due to changes in the number of options in the pop-up panel when the pop-up layer is not collapsed.
+        const { filterTreeNode } = this.getProps();
+        const shouldClear = this._adapter.getClearInputSign();
+        filterTreeNode && shouldClear && this.clearInput();
+    }
 }

+ 13 - 20
packages/semi-ui/treeSelect/index.tsx

@@ -316,6 +316,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
     onMotionEnd: any;
     treeSelectID: string;
     context: ContextValue;
+    clearInputSign: boolean;
 
     constructor(props: TreeSelectProps) {
         super(props);
@@ -353,6 +354,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
         this.triggerRef = React.createRef();
         this.optionsRef = React.createRef();
         this.clickOutsideHandler = null;
+        this.clearInputSign = false;
         this.foundation = new TreeSelectFoundation(this.adapter);
         this.treeSelectID = Math.random().toString(36).slice(2);
         this.onMotionEnd = () => {
@@ -765,6 +767,12 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
             },
             updateIsFocus: bool => {
                 this.setState({ isFocus: bool });
+            },
+            setClearInputSign: (sign: boolean) => {
+                this.clearInputSign = sign;
+            },
+            getClearInputSign: () => {
+                return this.clearInputSign;
             }
         };
     }
@@ -1400,28 +1408,13 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
         return key;
     };
 
-    /* Event handler function after popover is closed */
-    handlePopoverClose = isVisible => {
-        const { filterTreeNode, searchAutoFocus, searchPosition } = this.props;
-        // 将 inputValue 清空,如果有选中值的话,选中项能够快速回显
-        // Clear the inputValue. If there is a selected value, the selected item can be quickly echoed.
-        if (isVisible === false && filterTreeNode) {
-            this.foundation.clearInputValue();
-        }
-        if (filterTreeNode && searchPosition === strings.SEARCH_POSITION_DROPDOWN && isVisible && searchAutoFocus) {
-            this.foundation.focusInput(true);
-        }
+    /* Event handler function after popover visible change */
+    handlePopoverVisibleChange = isVisible => {
+        this.foundation.handlePopoverVisibleChange(isVisible);
     }
 
     afterClose = () => {
-        // flattenNode 的变化将导致弹出层面板中的选项数目变化
-        // 在弹层完全收起之后,再通过 clearInput 重新计算 state 中的 expandedKey, flattenNode
-        // 防止在弹出层未收起时弹层面板中选项数目变化导致视觉上出现弹层闪动问题
-        // Changes to flattenNode will cause the number of options in the popup panel to change
-        // After the pop-up layer is completely closed, recalculate the expandedKey and flattenNode in the state through clearInput.
-        // Prevent the pop-up layer from flickering visually due to changes in the number of options in the pop-up panel when the pop-up layer is not collapsed.
-        const { filterTreeNode } = this.props;
-        filterTreeNode && this.foundation.clearInput();
+        this.foundation.handleAfterClose();
     }
 
     renderTreeNode = (treeNode: FlattenNode, ind: number, style: React.CSSProperties) => {
@@ -1605,7 +1598,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
                 autoAdjustOverflow={autoAdjustOverflow}
                 mouseLeaveDelay={mouseLeaveDelay}
                 mouseEnterDelay={mouseEnterDelay}
-                onVisibleChange={this.handlePopoverClose}
+                onVisibleChange={this.handlePopoverVisibleChange}
                 afterClose={this.afterClose}
             >
                 {selection}