Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into fix-issue-antd-42663
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Sep 1, 2023
2 parents 25275ab + f647626 commit 340fc01
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 158 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "CodeQL"

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "41 11 * * 2"

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ javascript ]

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality

- name: Autobuild
uses: github/codeql-action/autobuild@v2

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ online example: https://tree-select-react-component.vercel.app/
|loadData | load data asynchronously | function(node) | - |
|getPopupContainer | container which popup select menu rendered into | function(trigger:Node):Node | function(){return document.body;} |
|autoClearSearchValue | auto clear search input value when multiple select is selected/deselected | boolean | true |
| inputIcon | specify the select arrow icon | ReactNode \| (props: TreeProps) => ReactNode | - |
| suffixIcon | specify the select arrow icon | ReactNode \| (props: TreeProps) => ReactNode | - |
| clearIcon | specify the clear icon | ReactNode \| (props: TreeProps) => ReactNode | - |
| removeIcon | specify the remove icon | ReactNode \| (props: TreeProps) => ReactNode | - |
|switcherIcon| specify the switcher icon | ReactNode \| (props: TreeProps) => ReactNode | - |
Expand Down
6 changes: 3 additions & 3 deletions examples/custom-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,19 @@ const switcherIcon = obj => {
);
};

const inputIcon = getSvg(bubblePath);
const suffixIcon = getSvg(bubblePath);
const clearIcon = getSvg(clearPath);
const removeIcon = getSvg(clearPath);

const iconProps = {
inputIcon,
suffixIcon,
clearIcon,
removeIcon,
switcherIcon,
};

const iconPropsFunction = {
inputIcon: () => inputIcon,
suffixIcon: () => suffixIcon,
clearIcon: () => clearIcon,
removeIcon: () => removeIcon,
switcherIcon,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rc-tree-select",
"version": "5.9.0",
"version": "5.12.0",
"description": "tree-select ui component for react",
"keywords": [
"react",
Expand Down Expand Up @@ -72,7 +72,7 @@
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-select": "~14.5.0",
"rc-select": "~14.8.0",
"rc-tree": "~5.7.0",
"rc-util": "^5.16.1"
}
Expand Down
80 changes: 46 additions & 34 deletions src/TreeSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import * as React from 'react';
import { BaseSelect } from 'rc-select';
import type { IconType } from 'rc-tree/lib/interface';
import type { ExpandAction } from 'rc-tree/lib/Tree';
import type {
BaseSelectRef,
BaseSelectPropsWithoutPrivate,
BaseSelectProps,
BaseSelectPropsWithoutPrivate,
BaseSelectRef,
SelectProps,
} from 'rc-select';
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
import { BaseSelect } from 'rc-select';
import useId from 'rc-select/lib/hooks/useId';
import type { IconType } from 'rc-tree/lib/interface';
import type { ExpandAction } from 'rc-tree/lib/Tree';
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import warning from 'rc-util/lib/warning';
import * as React from 'react';
import useCache from './hooks/useCache';
import useCheckedKeys from './hooks/useCheckedKeys';
import useDataEntities from './hooks/useDataEntities';
import useFilterTreeData from './hooks/useFilterTreeData';
import useRefFunc from './hooks/useRefFunc';
import useTreeData from './hooks/useTreeData';
import LegacyContext from './LegacyContext';
import OptionList from './OptionList';
import TreeNode from './TreeNode';
import { formatStrategyValues, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './utils/strategyUtil';
import type { CheckedStrategy } from './utils/strategyUtil';
import TreeSelectContext from './TreeSelectContext';
import type { TreeSelectContextProps } from './TreeSelectContext';
import LegacyContext from './LegacyContext';
import useTreeData from './hooks/useTreeData';
import { toArray, fillFieldNames, isNil } from './utils/valueUtil';
import useCache from './hooks/useCache';
import useRefFunc from './hooks/useRefFunc';
import useDataEntities from './hooks/useDataEntities';
import TreeSelectContext from './TreeSelectContext';
import { fillAdditionalInfo, fillLegacyProps } from './utils/legacyUtil';
import useCheckedKeys from './hooks/useCheckedKeys';
import useFilterTreeData from './hooks/useFilterTreeData';
import type { CheckedStrategy } from './utils/strategyUtil';
import { formatStrategyValues, SHOW_ALL, SHOW_CHILD, SHOW_PARENT } from './utils/strategyUtil';
import { fillFieldNames, isNil, toArray } from './utils/valueUtil';
import warningProps from './utils/warningPropsUtil';
import warning from 'rc-util/lib/warning';

export type OnInternalSelect = (value: RawValueType, info: { selected: boolean }) => void;

Expand Down Expand Up @@ -105,7 +105,7 @@ export interface LegacyDataNode extends DefaultOptionType {
}
export interface TreeSelectProps<
ValueType = any,
OptionType extends BaseOptionType = DefaultOptionType
OptionType extends BaseOptionType = DefaultOptionType,
> extends Omit<BaseSelectPropsWithoutPrivate, 'mode'> {
prefixCls?: string;
id?: string;
Expand Down Expand Up @@ -194,7 +194,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
treeNodeFilterProp = 'value',

// Selector
showCheckedStrategy = SHOW_CHILD,
showCheckedStrategy,
treeNodeLabelProp,

// Mode
Expand Down Expand Up @@ -246,6 +246,15 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)

const [internalValue, setInternalValue] = useMergedState(defaultValue, { value });

// `multiple` && `!treeCheckable` should be show all
const mergedShowCheckedStrategy = React.useMemo(() => {
if (!treeCheckable) {
return SHOW_ALL;
}

return showCheckedStrategy || SHOW_CHILD;
}, [showCheckedStrategy, treeCheckable]);

// ========================== Warning ===========================
if (process.env.NODE_ENV !== 'production') {
warningProps(props);
Expand Down Expand Up @@ -357,7 +366,9 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
rawDisabled = entity.node.disabled;
} else if (rawLabel === undefined) {
// We try to find in current `labelInValue` value
const labelInValueItem = toLabeledValues(internalValue).find(labeledItem => labeledItem.value === rawValue);
const labelInValueItem = toLabeledValues(internalValue).find(
labeledItem => labeledItem.value === rawValue,
);
rawLabel = labelInValueItem.label;
}

Expand All @@ -373,10 +384,10 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
);

// =========================== Values ===========================
const rawMixedLabeledValues = React.useMemo(() => toLabeledValues(internalValue), [
toLabeledValues,
internalValue,
]);
const rawMixedLabeledValues = React.useMemo(
() => toLabeledValues(internalValue),
[toLabeledValues, internalValue],
);

// Split value into full check and half check
const [rawLabeledValues, rawHalfLabeledValues] = React.useMemo(() => {
Expand All @@ -395,9 +406,10 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
}, [rawMixedLabeledValues]);

// const [mergedValues] = useCache(rawLabeledValues);
const rawValues = React.useMemo(() => rawLabeledValues.map(item => item.value), [
rawLabeledValues,
]);
const rawValues = React.useMemo(
() => rawLabeledValues.map(item => item.value),
[rawLabeledValues],
);

// Convert value to key. Will fill missed keys for conduct check.
const [rawCheckedValues, rawHalfCheckedValues] = useCheckedKeys(
Expand All @@ -412,7 +424,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
// Collect keys which need to show
const displayKeys = formatStrategyValues(
rawCheckedValues,
showCheckedStrategy,
mergedShowCheckedStrategy,
keyEntities,
mergedFieldNames,
);
Expand Down Expand Up @@ -447,7 +459,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
rawCheckedValues,
rawLabeledValues,
convert2LabelValues,
showCheckedStrategy,
mergedShowCheckedStrategy,
keyEntities,
]);

Expand All @@ -474,7 +486,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
if (treeConduction) {
const formattedKeyList = formatStrategyValues(
newRawValues,
showCheckedStrategy,
mergedShowCheckedStrategy,
keyEntities,
mergedFieldNames,
);
Expand Down Expand Up @@ -743,9 +755,9 @@ if (process.env.NODE_ENV !== 'production') {
TreeSelect.displayName = 'TreeSelect';
}

const GenericTreeSelect = (TreeSelect as unknown) as (<
const GenericTreeSelect = TreeSelect as unknown as (<
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
>(
props: React.PropsWithChildren<TreeSelectProps<ValueType, OptionType>> & {
ref?: React.Ref<BaseSelectRef>;
Expand Down
32 changes: 15 additions & 17 deletions src/hooks/useFilterTreeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,21 @@ export default (
}

function dig(list: DefaultOptionType[], keepAll: boolean = false) {
return list
.map(dataNode => {
const children = dataNode[fieldChildren];

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

if (match || childList.length) {
return {
...dataNode,
isLeaf: undefined,
[fieldChildren]: childList,
};
}
return null;
})
.filter(node => node);
return list.reduce((total, dataNode) => {
const children = dataNode[fieldChildren];

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

if (match || childList.length) {
total.push({
...dataNode,
isLeaf: undefined,
[fieldChildren]: childList,
});
}
return total;
}, []);
}

return dig(treeData);
Expand Down
33 changes: 32 additions & 1 deletion tests/Select.multiple.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable no-undef */
import React from 'react';
import { render } from '@testing-library/react';
import { mount } from 'enzyme';
import KeyCode from 'rc-util/lib/KeyCode';
import React from 'react';
import TreeSelect, { TreeNode } from '../src';
import focusTest from './shared/focusTest';

Expand Down Expand Up @@ -279,4 +280,34 @@ describe('TreeSelect.multiple', () => {
expect(onChange).toHaveBeenCalledWith([], expect.anything(), expect.anything());
expect(onDeselect).toHaveBeenCalledWith('not-exist', undefined);
});

it('should not omit value', () => {
const { container } = render(
<TreeSelect
value={['child1', 'child2', 'parent']}
multiple
treeData={[
{
label: 'parent',
value: 'parent',
children: [
{
label: 'child1',
value: 'child1',
},
{
label: 'child2',
value: 'child2',
},
],
},
]}
/>,
);

const values = Array.from(
container.querySelectorAll('.rc-tree-select-selection-item-content'),
).map(ele => ele.textContent);
expect(values).toEqual(['child1', 'child2', 'parent']);
});
});
2 changes: 1 addition & 1 deletion tests/Select.props.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ describe('TreeSelect.props', () => {
});

it('showArrow', () => {
const wrapper = mount(createOpenSelect({ showArrow: false }));
const wrapper = mount(createOpenSelect({ suffixIcon: null }));
expect(wrapper.find('.rc-tree-select-arrow').length).toBeFalsy();
});

Expand Down
Loading

0 comments on commit 340fc01

Please sign in to comment.