Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ build
lib/*
coverage
yarn.lock
package-lock.json
es/*
17 changes: 7 additions & 10 deletions src/hooks/useKeyValueMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import { FlattenDataNode, Key, RawValueType } from '../interface';

export type SkipType = null | 'select' | 'checkbox';

export function isDisabled(
dataNode: FlattenDataNode,
skipType: SkipType,
): boolean {
export function isDisabled(dataNode: FlattenDataNode, skipType: SkipType): boolean {
if (!dataNode) {
return true;
}
Expand All @@ -27,14 +24,14 @@ export default function useKeyValueMapping(
cacheKeyMap: Map<Key, FlattenDataNode>,
cacheValueMap: Map<RawValueType, FlattenDataNode>,
): [
(key: Key, skipType?: SkipType) => FlattenDataNode,
(value: RawValueType, skipType?: SkipType) => FlattenDataNode,
(key: Key, skipType?: SkipType, ignoreDisabledCheck?: boolean) => FlattenDataNode,
(value: RawValueType, skipType?: SkipType, ignoreDisabledCheck?: boolean) => FlattenDataNode,
] {
const getEntityByKey = React.useCallback(
(key: Key, skipType: SkipType = 'select') => {
(key: Key, skipType: SkipType = 'select', ignoreDisabledCheck?: boolean) => {
const dataNode = cacheKeyMap.get(key);

if (isDisabled(dataNode, skipType)) {
if (!ignoreDisabledCheck && isDisabled(dataNode, skipType)) {
return null;
}

Expand All @@ -44,10 +41,10 @@ export default function useKeyValueMapping(
);

const getEntityByValue = React.useCallback(
(value: RawValueType, skipType: SkipType = 'select') => {
(value: RawValueType, skipType: SkipType = 'select', ignoreDisabledCheck?: boolean) => {
const dataNode = cacheValueMap.get(value);

if (isDisabled(dataNode, skipType)) {
if (!ignoreDisabledCheck && isDisabled(dataNode, skipType)) {
return null;
}

Expand Down
8 changes: 6 additions & 2 deletions src/hooks/useSelectValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ interface Config {
value: DefaultValueType;
showCheckedStrategy: CheckedStrategy;
conductKeyEntities: Record<Key, DataEntity>;
getEntityByKey: (key: Key, skipType?: SkipType) => FlattenDataNode;
getEntityByValue: (value: RawValueType, skipType?: SkipType) => FlattenDataNode;
getEntityByKey: (key: Key, skipType?: SkipType, ignoreDisabledCheck?: boolean) => FlattenDataNode;
getEntityByValue: (
value: RawValueType,
skipType?: SkipType,
ignoreDisabledCheck?: boolean,
) => FlattenDataNode;
getLabelProp: (node: DataNode) => React.ReactNode;
}

Expand Down
16 changes: 3 additions & 13 deletions src/utils/legacyUtil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,7 @@ export function fillAdditionalInfo(
const pos = `${level}-${index}`;
const included = checkedValues.includes(dataNode.value);
const children = dig(dataNode.children || [], pos, included);
const node = (
<TreeNode {...dataNode}>
{children.map(child => child.node)}
</TreeNode>
);
const node = <TreeNode {...dataNode}>{children.map(child => child.node)}</TreeNode>;

// Link with trigger node
if (triggerValue === dataNode.value) {
Expand Down Expand Up @@ -137,21 +133,15 @@ export function fillAdditionalInfo(

Object.defineProperty(extra, 'triggerNode', {
get() {
warning(
false,
'`triggerNode` is deprecated. Please consider decoupling data with node.',
);
warning(false, '`triggerNode` is deprecated. Please consider decoupling data with node.');
generateMap();

return triggerNode;
},
});
Object.defineProperty(extra, 'allCheckedNodes', {
get() {
warning(
false,
'`allCheckedNodes` is deprecated. Please consider decoupling data with node.',
);
warning(false, '`allCheckedNodes` is deprecated. Please consider decoupling data with node.');
generateMap();

if (showPosition) {
Expand Down
16 changes: 5 additions & 11 deletions src/utils/valueUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ export function toArray<T>(value: T | T[]): T[] {
return value !== undefined ? [value] : [];
}

export function findValueOption(
values: RawValueType[],
options: FlattenDataNode[],
): DataNode[] {
export function findValueOption(values: RawValueType[], options: FlattenDataNode[]): DataNode[] {
const optionMap: Map<RawValueType, DataNode> = new Map();

options.forEach(flattenItem => {
Expand All @@ -34,10 +31,7 @@ export function findValueOption(
return values.map(val => fillLegacyProps(optionMap.get(val)));
}

export function isValueDisabled(
value: RawValueType,
options: FlattenDataNode[],
): boolean {
export function isValueDisabled(value: RawValueType, options: FlattenDataNode[]): boolean {
const option = findValueOption([value], options)[0];
if (option) {
return option.disabled;
Expand Down Expand Up @@ -135,8 +129,7 @@ export function filterOptions(
.map(dataNode => {
const { children } = dataNode;

const match =
keepAll || filterOptionFunc(searchValue, fillLegacyProps(dataNode));
const match = keepAll || filterOptionFunc(searchValue, fillLegacyProps(dataNode));
const childList = dig(children || [], match);

if (match || childList.length) {
Expand All @@ -159,6 +152,7 @@ export function getRawValueLabeled(
getEntityByValue: (
value: RawValueType,
skipType?: SkipType,
ignoreDisabledCheck?: boolean,
) => FlattenDataNode,
getLabelProp: (node: DataNode) => React.ReactNode,
): LabelValueType[] {
Expand All @@ -172,7 +166,7 @@ export function getRawValueLabeled(

return values.map(val => {
const item: LabelValueType = { value: val };
const entity = getEntityByValue(val);
const entity = getEntityByValue(val, 'select', true);
const label = entity ? getLabelProp(entity.data) : val;

if (valueMap.has(val)) {
Expand Down
54 changes: 10 additions & 44 deletions tests/Select.props.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { TreeNode } from 'rc-tree';
import TreeSelect, {
SHOW_ALL,
SHOW_CHILD,
SHOW_PARENT,
TreeNode as SelectNode,
} from '../src';
import TreeSelect, { SHOW_ALL, SHOW_CHILD, SHOW_PARENT, TreeNode as SelectNode } from '../src';

// Promisify timeout to let jest catch works
function timeoutPromise(delay = 0) {
Expand Down Expand Up @@ -47,9 +42,7 @@ describe('TreeSelect.props', () => {
function filterTreeNode(input, child) {
return String(child.props.title).indexOf(input) !== -1;
}
const wrapper = mount(
createOpenSelect({ filterTreeNode, showSearch: true }),
);
const wrapper = mount(createOpenSelect({ filterTreeNode, showSearch: true }));
wrapper.search('Title 1');
expect(wrapper.find('List').props().data).toHaveLength(1);

Expand All @@ -58,9 +51,7 @@ describe('TreeSelect.props', () => {
});

it('false', () => {
const wrapper = mount(
createOpenSelect({ filterTreeNode: false, showSearch: true }),
);
const wrapper = mount(createOpenSelect({ filterTreeNode: false, showSearch: true }));
wrapper.search('Title 1');
expect(wrapper.find('List').props().data).toHaveLength(4);
});
Expand Down Expand Up @@ -122,23 +113,15 @@ describe('TreeSelect.props', () => {
placeholder: 'RC Component',
}),
);
expect(wrapper.find('.rc-tree-select-selection-placeholder').text()).toBe(
'RC Component',
);
expect(wrapper.find('.rc-tree-select-selection-placeholder').text()).toBe('RC Component');
});

// https://github.com/ant-design/ant-design/issues/11746
it('async update treeData when has searchInput', () => {
const treeData = [{ title: 'aaa', value: '111' }];
const Wrapper = props => (
<div>
<TreeSelect
treeData={treeData}
searchValue="111"
showSearch
open
{...props}
/>
<TreeSelect treeData={treeData} searchValue="111" showSearch open {...props} />
</div>
);
const wrapper = mount(<Wrapper />);
Expand Down Expand Up @@ -345,16 +328,8 @@ describe('TreeSelect.props', () => {
// Since after click will render new TreeNode
// [Legacy] FIXME: This is so hard to test
wrapper.selectNode(0);
expect(handleChange).toHaveBeenCalledWith(
arg1,
arg2,
expect.anything(),
);
const {
triggerNode,
allCheckedNodes,
...rest
} = handleChange.mock.calls[0][2];
expect(handleChange).toHaveBeenCalledWith(arg1, arg2, expect.anything());
const { triggerNode, allCheckedNodes, ...rest } = handleChange.mock.calls[0][2];
expect({ ...rest, triggerNode, allCheckedNodes }).toEqual(arg3);
});
});
Expand Down Expand Up @@ -448,9 +423,7 @@ describe('TreeSelect.props', () => {
wrapper.find('.rc-tree-select-tree-switcher').simulate('click');

return timeoutPromise().then(() => {
expect(handleLoadData).toHaveBeenCalledWith(
expect.objectContaining({ value: '0-0' }),
);
expect(handleLoadData).toHaveBeenCalledWith(expect.objectContaining({ value: '0-0' }));
expect(called).toBe(1);
expect(wrapper.find('List').props().data).toHaveLength(2);
});
Expand All @@ -469,9 +442,7 @@ describe('TreeSelect.props', () => {
);

expect(loadData).toHaveBeenCalledTimes(1);
expect(loadData).toHaveBeenCalledWith(
expect.objectContaining({ value: '0-1' }),
);
expect(loadData).toHaveBeenCalledWith(expect.objectContaining({ value: '0-1' }));
});

it('getPopupContainer', () => {
Expand All @@ -489,12 +460,7 @@ describe('TreeSelect.props', () => {
const onChange = jest.fn();
const wrapper = mount(
<div>
<TreeSelect
value={['not exist']}
onChange={onChange}
treeCheckable
open
>
<TreeSelect value={['not exist']} onChange={onChange} treeCheckable open>
<SelectNode title="exist" value="exist" />
</TreeSelect>
</div>,
Expand Down
22 changes: 22 additions & 0 deletions tests/Select.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ describe('TreeSelect.basic', () => {
expect(wrapper.getSelection(0).text()).toEqual('label0');
});

it('sets default value(disabled)', () => {
const wrapper = mount(
<TreeSelect
defaultValue="0"
treeData={[{ key: '0', value: '0', title: 'label0', disabled: true }]}
/>,
);
expect(wrapper.getSelection(0).text()).toEqual('label0');
});

it('select value twice', () => {
const onChange = jest.fn();
const wrapper = mount(
Expand Down Expand Up @@ -411,6 +421,14 @@ describe('TreeSelect.basic', () => {
wrapper.update();
}

function keyUp(code) {
wrapper
.find('input')
.first()
.simulate('keyUp', { which: code });
wrapper.update();
}

function matchValue(value) {
expect(onChange).toHaveBeenCalledWith(value, expect.anything(), expect.anything());
onChange.mockReset();
Expand All @@ -419,11 +437,15 @@ describe('TreeSelect.basic', () => {
wrapper.openSelect();

keyDown(KeyCode.DOWN);
keyUp(KeyCode.DOWN);
keyDown(KeyCode.ENTER);
keyUp(KeyCode.ENTER);
matchValue(['parent']);

keyDown(KeyCode.UP);
keyUp(KeyCode.UP);
keyDown(KeyCode.ENTER);
keyUp(KeyCode.ENTER);
matchValue(['parent', 'child']);
});
});
Expand Down
16 changes: 4 additions & 12 deletions tests/Select.tree.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('TreeSelect.tree', () => {
<SelectNode key="0-0-0" value="0-0-0">
<SelectNode key="0-0-0-0" value="0-0-0-0" />
<SelectNode key="0-0-0-1" />
invalid element
</SelectNode>
<SelectNode key="0-0-1" value="0-0-1">
<SelectNode key="0-0-1-0" value="0-0-1-0" />
Expand Down Expand Up @@ -70,11 +71,7 @@ describe('TreeSelect.tree', () => {
it('warning if node key are not same as value', () => {
resetWarned();
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(
<TreeSelect
treeData={[{ title: 'little', value: 'ttt', key: 'little' }]}
/>,
);
mount(<TreeSelect treeData={[{ title: 'little', value: 'ttt', key: 'little' }]} />);
expect(spy).toHaveBeenCalledWith(
'Warning: `key` or `value` with TreeNode must be the same or you can remove one of them. key: little, value: ttt.',
);
Expand All @@ -86,15 +83,10 @@ describe('TreeSelect.tree', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(
<TreeSelect
treeData={[
{ title: 'little', value: 'ttt' },
{ title: 'bamboo', value: 'ttt' },
]}
treeData={[{ title: 'little', value: 'ttt' }, { title: 'bamboo', value: 'ttt' }]}
/>,
);
expect(spy).toHaveBeenCalledWith(
'Warning: Same `value` exist in the tree: ttt',
);
expect(spy).toHaveBeenCalledWith('Warning: Same `value` exist in the tree: ttt');
spy.mockRestore();
});

Expand Down
13 changes: 3 additions & 10 deletions tests/utils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,17 @@ import { isDisabled } from '../src/hooks/useKeyValueMapping';

describe('TreeSelect.util', () => {
it('isValueDisabled', () => {
const options = [
{ data: { value: 'disabled', disabled: true } },
{ data: { value: 'pass' } },
];
const options = [{ data: { value: 'disabled', disabled: true } }, { data: { value: 'pass' } }];
expect(isValueDisabled('disabled', options)).toBeTruthy();
expect(isValueDisabled('pass', options)).toBeFalsy();
expect(isValueDisabled('not-exist', options)).toBeFalsy();
});

it('isDisabled', () => {
expect(isDisabled({ data: { disabled: true } }, 'select')).toBeTruthy();
expect(
isDisabled({ data: { disableCheckbox: true } }, 'select'),
).toBeFalsy();
expect(isDisabled({ data: { disableCheckbox: true } }, 'select')).toBeFalsy();
expect(isDisabled({ data: { disabled: true } }, 'checkbox')).toBeTruthy();
expect(
isDisabled({ data: { disableCheckbox: true } }, 'checkbox'),
).toBeTruthy();
expect(isDisabled({ data: { disableCheckbox: true } }, 'checkbox')).toBeTruthy();
expect(isDisabled({ data: { disabled: true } }, null)).toBeFalsy();
});
});