Skip to content

Commit

Permalink
Fix/cascader rendertrigger (#2051)
Browse files Browse the repository at this point in the history
* fix: fix the value parameter of triggerRender is incorrect after key composition in keyEntities change

* fix: fix the value parameter of triggerRender is incorrect after key composition in keyEntities change

* fix: remove useless code

* docs: modify example explanation
  • Loading branch information
YyumeiZhang committed Jan 31, 2024
1 parent 6280990 commit 6091967
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 29 deletions.
2 changes: 1 addition & 1 deletion content/input/cascader/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,7 @@ interface TriggerRenderProps {
disabled: boolean;
/**
* 已选中的 node 在 treeData 中的层级位置,如下例子,
* 当选中浙江省-杭州市-萧山区时,此处 value 为 '0-0-0'
* 当选中浙江省-杭州市-萧山区时,此处 value 为 '0-0-1'
*/
value?: string | Set<string>;
/* 当前 Input 框的输入值 */
Expand Down
20 changes: 13 additions & 7 deletions packages/semi-foundation/cascader/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
normalizedArr,
isValid,
calcMergeType,
getKeysByValuePath
getKeysByValuePath,
getKeyByPos
} from './util';
import { strings } from './constants';
import isEnterPress from '../utils/isEnterPress';
Expand Down Expand Up @@ -56,6 +57,8 @@ export interface BasicEntity {
parentKey?: string;
/* key path */
path: Array<string>;
/* pos in treeData */
pos: string;
/* value path */
valuePath: Array<string>
}
Expand Down Expand Up @@ -1026,17 +1029,20 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
this._adapter.notifyListScroll(e, { panelIndex: ind, activeNode: data });
}

handleTagRemove(e: any, tagValuePath: string[]) {
handleTagRemoveByKey = (key: string) => {
const { keyEntities } = this.getStates();
const { disabled } = this.getProps();
if (disabled) {
/* istanbul ignore next */
return;
}
const removedItem = (Object.values(keyEntities) as BasicEntity[])
.filter(item => isEqual(item.valuePath, tagValuePath))[0];
!isEmpty(removedItem) &&
!removedItem.data.disabled &&
this._handleMultipleSelect(removedItem);
const removedItem = keyEntities[key] ?? {};
!removedItem?.data?.disable && this._handleMultipleSelect(removedItem);
}

handleTagRemoveInTrigger = (pos: string) => {
const { treeData } = this.getStates();
const key = getKeyByPos(pos, treeData);
this.handleTagRemoveByKey(key);
}
}
13 changes: 13 additions & 0 deletions packages/semi-foundation/cascader/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ function traverseDataNodes(treeNodes: any, callback: any) {
// Process node if is not root
if (node) {
const key = parent ? `${parent.key}${VALUE_SPLIT}${node.value}` : node.value;
const pos = parent ? getPosition(parent.pos, ind) : `${ind}`;
item = {
data: { ...node },
ind,
key,
pos,
level: parent ? parent.level + 1 : 0,
parentKey: parent ? parent.key : null,
path: parent ? [...parent.path, key] : [key],
Expand Down Expand Up @@ -74,6 +76,17 @@ export function getValuePathByKey(key: string) {
return key.split(VALUE_SPLIT);
}

export function getKeyByPos(pos: string, treeData: any) {
const posArr = pos.split('-').map(item => Number(item));
let resultData = treeData;
let valuePath = [];
posArr.forEach((item, index) => {
resultData = index === 0 ? resultData[item] : resultData?.children?.[item];
valuePath.push(resultData?.value);
});
return getKeyByValuePath(valuePath);
}

export function convertDataToEntities(dataNodes: any) {
const keyEntities: any = {};

Expand Down
4 changes: 2 additions & 2 deletions packages/semi-ui/cascader/__test__/cascader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1257,7 +1257,7 @@ describe('Cascader', () => {
const args = firstCall.args[0];
/* check arguments of triggerRender */
expect(args.value.size).toEqual(1);
expect(args.value).toEqual(new Set(['Asia']));
expect(args.value).toEqual(new Set('0'));
cascaderAutoMerge.unmount();

const spyTriggerRender2 = sinon.spy(() => <span>123</span>);
Expand All @@ -1272,7 +1272,7 @@ describe('Cascader', () => {
const args2 = firstCall2.args[0];
/* check arguments of triggerRender */
expect(args2.value.size).toEqual(4);
expect(args2.value).toEqual(new Set(["Asia","Asia_SEMI_CASCADER_SPLIT_China","Asia_SEMI_CASCADER_SPLIT_China_SEMI_CASCADER_SPLIT_Beijing","Asia_SEMI_CASCADER_SPLIT_China_SEMI_CASCADER_SPLIT_Shanghai"]));
expect(args2.value).toEqual(new Set(['0','0-0','0-0-1','0-0-0']));
cascaderNoAutoMerge.unmount();
});

Expand Down
42 changes: 23 additions & 19 deletions packages/semi-ui/cascader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/con
import { isSet, isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten, isObject } from 'lodash';
import '@douyinfe/semi-foundation/cascader/cascader.scss';
import { IconClear, IconChevronDown } from '@douyinfe/semi-icons';
import { convertDataToEntities, calcMergeType, getKeyByValuePath } from '@douyinfe/semi-foundation/cascader/util';
import { convertDataToEntities, calcMergeType, getKeyByValuePath, getKeyByPos } from '@douyinfe/semi-foundation/cascader/util';
import { calcCheckedKeys, normalizeKeyList, calcDisabledKeys } from '@douyinfe/semi-foundation/tree/treeUtil';
import ConfigContext, { ContextValue } from '../configProvider/context';
import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
Expand Down Expand Up @@ -514,13 +514,14 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
this.foundation.handleInputChange(value);
};

handleTagRemove = (e: any, tagValuePath: Array<string | number>) => {
this.foundation.handleTagRemove(e, tagValuePath);
};
handleTagRemoveInTrigger = (pos: string) => {
this.foundation.handleTagRemoveInTrigger(pos);
}

handleRemoveByKey = (key) => {
const { keyEntities } = this.state;
this.handleTagRemove(null, keyEntities[key].valuePath);
handleTagClose = (tagChildren: React.ReactNode, e: React.MouseEvent<HTMLElement>, tagKey: string | number) => {
// When value has not changed, prevent clicking tag closeBtn to close tag
e.preventDefault();
this.foundation.handleTagRemoveByKey(tagKey);
}

renderTagItem = (nodeKey: string, idx: number) => {
Expand All @@ -542,13 +543,10 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
size={size === 'default' ? 'large' : size}
key={`tag-${nodeKey}-${idx}`}
color="white"
tagKey={nodeKey}
className={tagCls}
closable
onClose={(tagChildren, e) => {
// When value has not changed, prevent clicking tag closeBtn to close tag
e.preventDefault();
this.handleTagRemove(e, keyEntities[nodeKey].valuePath);
}}
onClose={this.handleTagClose}
>
{keyEntities[nodeKey].data[displayProp]}
</Tag>
Expand All @@ -558,6 +556,10 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
return null;
};

onRemoveInTagInput = (v: string) => {
this.foundation.handleTagRemoveByKey(v);
};

renderTagInput() {
const { size, disabled, placeholder, maxTagCount, showRestTagsPopover, restTagsPopoverProps } = this.props;
const { inputValue, checkedKeys, keyEntities, resolvedCheckedKeys } = this.state;
Expand All @@ -573,11 +575,11 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
showRestTagsPopover={showRestTagsPopover}
restTagsPopoverProps={restTagsPopoverProps}
maxTagCount={maxTagCount}
renderTagItem={(value, index) => this.renderTagItem(value, index)}
renderTagItem={this.renderTagItem}
inputValue={inputValue}
onInputChange={this.handleInputChange}
// TODO Modify logic, not modify type
onRemove={v => this.handleTagRemove(null, (v as unknown) as (string | number)[])}
onRemove={this.onRemoveInTagInput}
placeholder={placeholder}
expandRestTagsOnClick={false}
/>
Expand Down Expand Up @@ -834,16 +836,18 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
renderCustomTrigger = () => {
const { disabled, triggerRender, multiple } = this.props;
const { selectedKeys, inputValue, inputPlaceHolder, resolvedCheckedKeys, checkedKeys } = this.state;
const { selectedKeys, inputValue, inputPlaceHolder, resolvedCheckedKeys, checkedKeys, keyEntities } = this.state;
let realValue;
if (multiple) {
if (this.mergeType === strings.NONE_MERGE_TYPE) {
realValue = checkedKeys;
realValue = new Set();
checkedKeys.forEach(key => { realValue.add(keyEntities[key]?.pos); });
} else {
realValue = resolvedCheckedKeys;
realValue = new Set();
resolvedCheckedKeys.forEach(key => { realValue.add(keyEntities[key]?.pos); });
}
} else {
realValue = [...selectedKeys][0];
realValue = keyEntities[[...selectedKeys][0]]?.pos;
}
return (
<Trigger
Expand All @@ -857,7 +861,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
componentName={'Cascader'}
componentProps={{ ...this.props }}
onSearch={this.handleInputChange}
onRemove={this.handleRemoveByKey}
onRemove={this.handleTagRemoveInTrigger}
/>
);
};
Expand Down

0 comments on commit 6091967

Please sign in to comment.