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

type: revert SafeKey and upgrade rc-tree #586

Merged
merged 8 commits into from
Oct 16, 2024
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