Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@babel/runtime": "^7.25.7",
"classnames": "2.x",
"rc-select": "~14.15.2",
"rc-tree": "~5.10.0",
"rc-tree": "~5.10.1",
"rc-util": "^5.43.0"
},
"devDependencies": {
Expand Down
16 changes: 8 additions & 8 deletions src/LegacyContext.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import * as React from 'react';
import type { DataEntity, IconType } from 'rc-tree/lib/interface';
import type { LegacyDataNode, SafeKey } from './interface';
import type { LegacyDataNode, SafeKey, Key } from './interface';

interface LegacyContextProps {
checkable: boolean | React.ReactNode;
checkedKeys: SafeKey[];
halfCheckedKeys: SafeKey[];
treeExpandedKeys: SafeKey[];
treeDefaultExpandedKeys: SafeKey[];
onTreeExpand: (keys: SafeKey[]) => void;
checkedKeys: Key[];
halfCheckedKeys: Key[];
Comment on lines +7 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

checkedKeyshalfCheckedKeys 的类型从 SafeKey[] 更改为 Key[]

在以下文件中仍然存在 SafeKey 的使用,请确保全部替换为 Key 类型以保持一致性:

  • src/interface.ts
  • src/TreeSelect.tsx
  • src/OptionList.tsx
  • src/hooks/useCache.ts
  • src/hooks/useDataEntities.ts
  • src/hooks/useCheckedKeys.ts
  • src/utils/strategyUtil.ts
  • src/utils/valueUtil.ts
  • src/utils/legacyUtil.tsx
🔗 Analysis chain

checkedKeyshalfCheckedKeys 的类型从 SafeKey[] 更改为 Key[]

这个更改看起来是为了统一使用 Key 类型。这是一个好的改进,可以提高代码的一致性和类型安全性。

请运行以下脚本以验证 SafeKeyKey 的更改是否在整个代码库中保持一致:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:验证 SafeKey 到 Key 的更改是否一致

# 测试:搜索 SafeKey 的使用。预期:应该没有剩余的 SafeKey 使用
rg --type typescript 'SafeKey'

# 测试:搜索 Key 的使用。预期:应该看到新的 Key 类型的使用
rg --type typescript '\bKey\b'

Length of output: 225


Script:

#!/bin/bash
# 描述:验证 SafeKey 到 Key 的更改是否一致

# 测试:搜索 SafeKey 的使用。预期:应该没有剩余的 SafeKey 使用
rg --type ts 'SafeKey'
rg --type tsx 'SafeKey'

# 测试:搜索 Key 的使用。预期:应该看到新的 Key 类型的使用
rg --type ts '\bKey\b'
rg --type tsx '\bKey\b'

Length of output: 5200


Script:

#!/bin/bash
# 描述:验证 SafeKey 到 Key 的更改是否一致

# 测试:搜索 SafeKey 的使用。预期:应该没有剩余的 SafeKey 使用
rg 'SafeKey' --glob '*.ts' --glob '*.tsx'

# 测试:搜索 Key 的使用。预期:应该看到新的 Key 类型的使用
rg '\bKey\b' --glob '*.ts' --glob '*.tsx'

Length of output: 5132

treeExpandedKeys: Key[];
treeDefaultExpandedKeys: Key[];
onTreeExpand: (keys: Key[]) => void;
treeDefaultExpandAll: boolean;
treeIcon: IconType;
showTreeIcon: boolean;
switcherIcon: IconType;
treeLine: boolean;
treeNodeFilterProp: string;
treeLoadedKeys: SafeKey[];
treeLoadedKeys: Key[];
treeMotion: any;
loadData: (treeNode: LegacyDataNode) => Promise<unknown>;
onTreeLoad: (loadedKeys: SafeKey[]) => void;
onTreeLoad: (loadedKeys: Key[]) => void;

keyEntities: Record<SafeKey, DataEntity<any>>;
}
Expand Down
18 changes: 9 additions & 9 deletions src/OptionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
import * as React from 'react';
import LegacyContext from './LegacyContext';
import TreeSelectContext from './TreeSelectContext';
import type { SafeKey, TreeDataNode } from './interface';
import type { Key, SafeKey } from './interface';
import { getAllKeys, isCheckDisabled } from './utils/valueUtil';

const HIDDEN_STYLE = {
Expand All @@ -23,7 +23,7 @@ const HIDDEN_STYLE = {
};

interface TreeEventInfo {
node: { key: SafeKey };
node: { key: Key };
selected?: boolean;
checked?: boolean;
}
Expand Down Expand Up @@ -77,8 +77,8 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
);

// ========================== Active ==========================
const [activeKey, setActiveKey] = React.useState<SafeKey>(null);
const activeEntity = keyEntities[activeKey];
const [activeKey, setActiveKey] = React.useState<Key>(null);
const activeEntity = keyEntities[activeKey as SafeKey];
Comment on lines +80 to +81
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

检查 activeKey 的类型转换

虽然将 activeKey 的类型更新为 Key,但在第 81 行,仍将 activeKey 强制转换为 SafeKey (activeKey as SafeKey)。这可能导致类型不一致或隐藏潜在错误。建议检查 keyEntities 的类型定义,确保与 Key 类型兼容,或调整代码以消除不必要的类型转换。


// ========================== Values ==========================
const mergedCheckedKeys = React.useMemo(() => {
Expand Down Expand Up @@ -112,8 +112,8 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
};

// =========================== Keys ===========================
const [expandedKeys, setExpandedKeys] = React.useState<SafeKey[]>(treeDefaultExpandedKeys);
const [searchExpandedKeys, setSearchExpandedKeys] = React.useState<SafeKey[]>(null);
const [expandedKeys, setExpandedKeys] = React.useState<Key[]>(treeDefaultExpandedKeys);
const [searchExpandedKeys, setSearchExpandedKeys] = React.useState<Key[]>(null);

const mergedExpandedKeys = React.useMemo(() => {
if (treeExpandedKeys) {
Expand All @@ -129,7 +129,7 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchValue]);

const onInternalExpand = (keys: SafeKey[]) => {
const onInternalExpand = (keys: Key[]) => {
setExpandedKeys(keys);
setSearchExpandedKeys(keys);

Expand All @@ -143,7 +143,7 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
event.preventDefault();
};

const onInternalSelect = (__: SafeKey[], info: TreeEventInfo) => {
const onInternalSelect = (__: Key[], info: TreeEventInfo) => {
const { node } = info;

if (checkable && isCheckDisabled(node)) {
Expand Down Expand Up @@ -227,7 +227,7 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
ref={treeRef}
focusable={false}
prefixCls={`${prefixCls}-tree`}
treeData={memoTreeData as TreeDataNode[]}
treeData={memoTreeData}
height={listHeight}
itemHeight={listItemHeight}
itemScrollOffset={listItemScrollOffset}
Expand Down
4 changes: 2 additions & 2 deletions src/TreeNode.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* istanbul ignore file */
import type * as React from 'react';
import type { DataNode, SafeKey } from './interface';
import type { DataNode, Key } from './interface';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

类型更改可能影响代码库的其他部分

./interface.ts 中仍然存在 SafeKey 的定义和广泛使用。将 TreeNode.tsx 中的 SafeKey 更改为 Key 可能导致类型不一致或引发其他问题。建议全面检查相关类型定义和使用场景,确保此更改不会影响代码的类型安全和功能。

🔗 Analysis chain

导入语句更新

导入语句已从 SafeKey 更改为 Key。这表明 ./interface 模块中的类型定义可能已更改。

请运行以下脚本以验证 Key 类型的定义和使用:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:验证 Key 类型的定义和使用

# 测试:搜索 Key 类型的定义
echo "Key 类型的定义:"
rg --type typescript "type\s+Key\s*=" ./src

# 测试:搜索 Key 类型的使用
echo "\nKey 类型的使用:"
rg --type typescript "\b(Key|SafeKey)\b" ./src

Length of output: 259


Script:

#!/bin/bash
# 描述:验证 Key 类型的定义和使用

# 搜索 Key 类型的定义
echo "Key 类型的定义:"
rg "type\s+Key\s*=" ./src --glob "*.ts" --glob "*.tsx"

# 搜索 Key 和 SafeKey 类型的使用
echo "\nKey 和 SafeKey 类型的使用:"
rg "\b(Key|SafeKey)\b" ./src --glob "*.ts" --glob "*.tsx"

Length of output: 4993


export interface TreeNodeProps extends Omit<DataNode, 'children'> {
value: SafeKey;
value: Key;
children?: React.ReactNode;
}

Expand Down
95 changes: 22 additions & 73 deletions src/TreeSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,72 +28,21 @@ 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 type { LabeledValueType, SafeKey, SelectSource, DefaultValueType } from './interface';

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

/** @deprecated This is only used for legacy compatible. Not works on new code. */
export interface LegacyCheckedNode {
pos: string;
node: React.ReactElement;
children?: LegacyCheckedNode[];
}

export interface ChangeEventExtra {
/** @deprecated Please save prev value by control logic instead */
preValue: LabeledValueType[];
triggerValue: SafeKey;
/** @deprecated Use `onSelect` or `onDeselect` instead. */
selected?: boolean;
/** @deprecated Use `onSelect` or `onDeselect` instead. */
checked?: boolean;

// Not sure if exist user still use this. We have to keep but not recommend user to use
/** @deprecated This prop not work as react node anymore. */
triggerNode: React.ReactElement;
/** @deprecated This prop not work as react node anymore. */
allCheckedNodes: LegacyCheckedNode[];
}

export interface FieldNames {
value?: string;
label?: string;
children?: string;
}

export interface InternalFieldName extends Omit<FieldNames, 'label'> {
_title: string[];
}

export interface SimpleModeConfig {
id?: SafeKey;
pId?: SafeKey;
rootPId?: SafeKey;
}

export interface BaseOptionType {
disabled?: boolean;
checkable?: boolean;
disableCheckbox?: boolean;
children?: BaseOptionType[];
[name: string]: any;
}

export interface DefaultOptionType extends BaseOptionType {
value?: SafeKey;
title?: React.ReactNode | ((data: DefaultOptionType) => React.ReactNode);
label?: React.ReactNode;
key?: SafeKey;
children?: DefaultOptionType[];
}

export interface LegacyDataNode extends DefaultOptionType {
props: any;
}
export interface TreeSelectProps<
ValueType = any,
OptionType extends BaseOptionType = DefaultOptionType,
> extends Omit<BaseSelectPropsWithoutPrivate, 'mode'> {
import type {
LabeledValueType,
SafeKey,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

持续使用已移除的SafeKey类型

在第28、365、521和535行,代码中仍在使用SafeKey类型。然而,根据更改,SafeKey类型应已被移除并替换为Key类型。请将所有SafeKey替换为Key,以确保类型一致性并避免潜在的类型错误。

Also applies to: 365-365, 521-521, 535-535

Key,
DataNode,
SimpleModeConfig,
ChangeEventExtra,
SelectSource,
DefaultValueType,
FieldNames,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

使用了可能已移除的FieldNames类型

在第35和202行,FieldNames类型被导入并使用。请确认FieldNames类型是否仍然有效,如果已被移除,需更新代码以使用新的类型定义或相应调整逻辑。

Also applies to: 202-202

LegacyDataNode,
} from './interface';
Comment on lines +26 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

移除的类型仍在导入

在第26-37行,从'./interface'中导入了可能已被移除的类型,包括SafeKeyChangeEventExtraSimpleModeConfigFieldNamesLegacyDataNode等。请检查这些类型是否仍在使用,如果不再需要,建议从导入中移除以保持代码清洁。


export interface TreeSelectProps<ValueType = any, OptionType extends DataNode = DataNode>
extends Omit<BaseSelectPropsWithoutPrivate, 'mode'> {
prefixCls?: string;
id?: string;
children?: React.ReactNode;
Expand All @@ -109,7 +58,7 @@ export interface TreeSelectProps<
inputValue?: string;
onSearch?: (value: string) => void;
autoClearSearchValue?: boolean;
filterTreeNode?: boolean | ((inputValue: string, treeNode: DefaultOptionType) => boolean);
filterTreeNode?: boolean | ((inputValue: string, treeNode: DataNode) => boolean);
treeNodeFilterProp?: string;

// >>> Select
Expand Down Expand Up @@ -255,7 +204,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
}

// ========================= FieldNames =========================
const mergedFieldNames: InternalFieldName = React.useMemo(
const mergedFieldNames: FieldNames = React.useMemo(
() => fillFieldNames(fieldNames),
/* eslint-disable react-hooks/exhaustive-deps */
[JSON.stringify(fieldNames)],
Expand Down Expand Up @@ -310,7 +259,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)

// =========================== Label ============================
const getLabel = React.useCallback(
(item: DefaultOptionType) => {
(item: DataNode) => {
if (item) {
if (treeNodeLabelProp) {
return item[treeNodeLabelProp];
Expand Down Expand Up @@ -418,7 +367,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
const displayValues = React.useMemo(() => {
// Collect keys which need to show
const displayKeys = formatStrategyValues(
rawCheckedValues,
rawCheckedValues as SafeKey[],
mergedShowCheckedStrategy,
keyEntities,
mergedFieldNames,
Expand Down Expand Up @@ -574,7 +523,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
const keyList = existRawValues.map(val => valueEntities.get(val).key);

// Conduction by selected or not
let checkedKeys: SafeKey[];
let checkedKeys: Key[];
if (selected) {
({ checkedKeys } = conductCheck(keyList, true, keyEntities));
} else {
Expand All @@ -588,7 +537,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
// Fill back of keys
newRawValues = [
...missingRawValues,
...checkedKeys.map(key => keyEntities[key].node[mergedFieldNames.value]),
...checkedKeys.map(key => keyEntities[key as SafeKey].node[mergedFieldNames.value]),
];
}
triggerChange(newRawValues, { selected, triggerValue: selectedValue }, source || 'option');
Expand Down Expand Up @@ -760,7 +709,7 @@ if (process.env.NODE_ENV !== 'production') {

const GenericTreeSelect = TreeSelect as unknown as (<
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
OptionType extends DataNode = DataNode,
>(
props: React.PropsWithChildren<TreeSelectProps<ValueType, OptionType>> & {
ref?: React.Ref<BaseSelectRef>;
Expand Down
8 changes: 4 additions & 4 deletions src/TreeSelectContext.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import * as React from 'react';
import type { ExpandAction } from 'rc-tree/lib/Tree';
import type { DefaultOptionType, InternalFieldName, OnInternalSelect } from './TreeSelect';
import type { DataNode, FieldNames, Key } from './interface';

export interface TreeSelectContextProps {
virtual?: boolean;
dropdownMatchSelectWidth?: boolean | number;
listHeight: number;
listItemHeight: number;
listItemScrollOffset?: number;
treeData: DefaultOptionType[];
fieldNames: InternalFieldName;
onSelect: OnInternalSelect;
treeData: DataNode[];
fieldNames: FieldNames;
onSelect: (value: Key, info: { selected: boolean }) => void;
treeExpandAction?: ExpandAction;
treeTitleRender?: (node: any) => React.ReactNode;
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
Expand Down
7 changes: 3 additions & 4 deletions src/hooks/useCheckedKeys.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import type { DataEntity } from 'rc-tree/lib/interface';
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
import type { LabeledValueType, SafeKey } from '../interface';
import type { LabeledValueType, SafeKey, Key } from '../interface';

const useCheckedKeys = (
rawLabeledValues: LabeledValueType[],
Expand All @@ -10,13 +10,12 @@ const useCheckedKeys = (
keyEntities: Record<SafeKey, DataEntity>,
) => {
return React.useMemo(() => {
const extractValues = (values: LabeledValueType[]): SafeKey[] =>
values.map(({ value }) => value);
const extractValues = (values: LabeledValueType[]): Key[] => values.map(({ value }) => value);

const checkedKeys = extractValues(rawLabeledValues);
const halfCheckedKeys = extractValues(rawHalfCheckedValues);

const missingValues = checkedKeys.filter(key => !keyEntities[key]);
const missingValues = checkedKeys.filter(key => !keyEntities[key as SafeKey]);

let finalCheckedKeys = checkedKeys;
let finalHalfCheckedKeys = halfCheckedKeys;
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useDataEntities.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as React from 'react';
import { convertDataToEntities } from 'rc-tree/lib/utils/treeUtil';
import type { DataEntity } from 'rc-tree/lib/interface';
import type { FieldNames } from '../TreeSelect';
import type { SafeKey } from '../interface';
import type { SafeKey, FieldNames } from '../interface';
import warning from 'rc-util/lib/warning';
import { isNil } from '../utils/valueUtil';

Expand Down
11 changes: 6 additions & 5 deletions src/hooks/useFilterTreeData.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import * as React from 'react';
import type { DefaultOptionType, InternalFieldName, TreeSelectProps } from '../TreeSelect';
import type { TreeSelectProps } from '../TreeSelect';
import type { DataNode, FieldNames } from '../interface';
import { fillLegacyProps } from '../utils/legacyUtil';

type FilterFn = NonNullable<TreeSelectProps['filterTreeNode']>;

const useFilterTreeData = (
treeData: DefaultOptionType[],
treeData: DataNode[],
searchValue: string,
options: {
fieldNames: InternalFieldName;
fieldNames: FieldNames;
treeNodeFilterProp: string;
filterTreeNode: TreeSelectProps['filterTreeNode'];
},
Expand All @@ -27,8 +28,8 @@ const useFilterTreeData = (
: (_, dataNode) =>
String(dataNode[treeNodeFilterProp]).toUpperCase().includes(searchValue.toUpperCase());

const filterTreeNodes = (nodes: DefaultOptionType[], keepAll = false): DefaultOptionType[] =>
nodes.reduce<DefaultOptionType[]>((filtered, node) => {
const filterTreeNodes = (nodes: DataNode[], keepAll = false): DataNode[] =>
nodes.reduce<DataNode[]>((filtered, node) => {
const children = node[fieldChildren];
const isMatch = keepAll || filterOptionFunc(searchValue, fillLegacyProps(node));
const filteredChildren = filterTreeNodes(children || [], isMatch);
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useTreeData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import type { DataNode, SimpleModeConfig } from '../interface';
import { convertChildrenToData } from '../utils/legacyUtil';
import type { DefaultOptionType } from '../TreeSelect';

function buildTreeStructure(nodes: DataNode[], config: SimpleModeConfig): DataNode[] {
const { id, pId, rootPId } = config;
Expand Down Expand Up @@ -37,7 +36,7 @@ export default function useTreeData(
treeData: DataNode[],
children: React.ReactNode,
simpleMode: boolean | SimpleModeConfig,
): DefaultOptionType[] {
): DataNode[] {
return React.useMemo(() => {
if (treeData) {
if (simpleMode) {
Expand Down
Loading
Loading