Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix the abnormal expansion status of selected options after sele… #2179

Merged
merged 2 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cypress/e2e/treeSelect.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
})
});

34 changes: 31 additions & 3 deletions packages/semi-foundation/treeSelect/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
setClearInputFlag: (flag: boolean) => void;
getClearInputFlag: () => boolean
}

export default class TreeSelectFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<TreeSelectAdapter<P, S>, P, S> {
Expand Down Expand Up @@ -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);

Expand All @@ -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 {
Expand Down Expand Up @@ -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.setClearInputFlag(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.getClearInputFlag();
filterTreeNode && shouldClear && this.clearInput();
}
}
33 changes: 13 additions & 20 deletions packages/semi-ui/treeSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
onMotionEnd: any;
treeSelectID: string;
context: ContextValue;
clearInputFlag: boolean;

constructor(props: TreeSelectProps) {
super(props);
Expand Down Expand Up @@ -353,6 +354,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
this.triggerRef = React.createRef();
this.optionsRef = React.createRef();
this.clickOutsideHandler = null;
this.clearInputFlag = false;
this.foundation = new TreeSelectFoundation(this.adapter);
this.treeSelectID = Math.random().toString(36).slice(2);
this.onMotionEnd = () => {
Expand Down Expand Up @@ -765,6 +767,12 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
},
updateIsFocus: bool => {
this.setState({ isFocus: bool });
},
setClearInputFlag: (flag: boolean) => {
this.clearInputFlag = flag;
},
getClearInputFlag: () => {
return this.clearInputFlag;
}
};
}
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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}
Expand Down
Loading