Skip to content

Commit

Permalink
Merge pull request #71 from ant-design/feat/sortable-list
Browse files Browse the repository at this point in the history
feat: SortableList and ColumnList 去除初始化逻辑,支持 id 通过 getId 方法获取
  • Loading branch information
ONLY-yours authored Aug 31, 2023
2 parents 1a220f6 + 59f1b55 commit a43ce91
Show file tree
Hide file tree
Showing 29 changed files with 678 additions and 253 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
},
"dependencies": {
"@ant-design/icons": "^5.2.5",
"@ant-design/pro-components": "^2.6.13",
"@ant-design/pro-components": "^2.6.15",
"@antv/dw-random": "^1.1.7",
"@babel/runtime": "^7.22.11",
"@dnd-kit/core": "^6.0.8",
Expand Down Expand Up @@ -93,7 +93,6 @@
"lodash.unionby": "^4.8.0",
"lodash.uniq": "^4.5.0",
"mockjs": "^1.1.0",
"object-hash": "^3.0.0",
"polished": "^4.2.2",
"prettier": "^2.8.8",
"re-resizable": "^6.9.11",
Expand Down Expand Up @@ -124,7 +123,7 @@
"@types/react-dom": "^18.2.7",
"@umijs/lint": "^4.0.78",
"@vitest/coverage-v8": "latest",
"antd": "^5.8.4",
"antd": "^5.8.5",
"antd-style": "^3.4.4",
"babel-plugin-antd-style": "^1.0.4",
"commitlint": "^17.7.1",
Expand Down
1 change: 1 addition & 0 deletions src/ColumnList/ColumnItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const ColumnItem = memo<ItemRenderProps>(
return Custom ? (
<Custom
item={item}
key={`${item?.dataIndex}-${colIndex}`}
column={col}
onChange={(value) => {
instance.updateItem({ [col.dataIndex]: value }, index);
Expand Down
138 changes: 41 additions & 97 deletions src/ColumnList/ColumnList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,59 @@ import {
SortableItem,
SortableList,
SortableListProps,
SortableListRef,
genUniqueId,
getPrefixCls,
} from '@ant-design/pro-editor';
import { ReactNode, forwardRef, useCallback, useMemo } from 'react';
import { ReactNode, forwardRef, useCallback } from 'react';
import ColumnItem from './ColumnItem';
import { Header } from './Header';
import { useStyle } from './style';
import { ColumnItemList } from './types';
import { genUniqueID } from './utils';

export interface CreatorButtonProps<T> {
/**
* 生成初始值逻辑
*/
record: (index: number) => Partial<T>;
/**
* 新增一行按钮文案
*/
creatorButtonText?: string;
}

export interface ColumnListProps<T = any> extends SortableListProps<T> {
export interface ColumnListProps<T extends SortableItem = SortableItem>
extends SortableListProps<T> {
columns: ColumnItemList<T>;
}

/**
* 供外部使用的 ref 方法
*/
export interface ColumnListRef<T = any> {
addItem: (item?: SortableItem<T>, index?: number) => void;
removeItem: (index: number) => void;
updateItem: (item: SortableItem<T>, index: number) => void;
}

const ColumnList: <T>(props: ColumnListProps<T>) => ReactNode = forwardRef<
ColumnListRef,
const ColumnList: <T extends SortableItem>(props: ColumnListProps<T>) => ReactNode = forwardRef<
SortableListRef,
ColumnListProps
>(
(
{
prefixCls: customPrefixCls,
className,
columns,
value,
initialValues,
actions,
hideRemove,
...props
},
ref,
) => {
const prefixCls = getPrefixCls('column-list', customPrefixCls);
const { cx } = useStyle(prefixCls);
// 校验是否传入 ID,如果没有传入 ID,就生成一个 ID
const parsedValue = useMemo(
() =>
value
? value.map((item, index) => ({
id: genUniqueID(item, index),
...item,
}))
: undefined,
[value],
);
// 校验是否传入 ID,如果没有传入 ID,就生成一个 ID
const parsedInitialValues = useMemo(
() =>
initialValues
? initialValues.map((item, index) => ({
id: genUniqueID(item, index),
...item,
}))
: undefined,
[initialValues],
);
>(({ prefixCls: customPrefixCls, className, columns, actions, hideRemove, ...props }, ref) => {
const prefixCls = getPrefixCls('column-list', customPrefixCls);
const { cx } = useStyle(prefixCls);

const renderItem = useCallback(
(item, { index, listeners }) => (
<ColumnItem
columns={columns}
item={item}
listeners={listeners}
index={index}
prefixCls={prefixCls}
actions={typeof actions === 'function' ? actions(item, index) : actions}
hideRemove={hideRemove}
/>
),
[prefixCls, columns],
);
const renderItem = useCallback(
(item, { index, listeners }) => (
<ColumnItem
columns={columns}
item={item}
listeners={listeners}
index={index}
prefixCls={prefixCls}
actions={typeof actions === 'function' ? actions(item, index) : actions}
hideRemove={hideRemove}
/>
),
[prefixCls, columns],
);

return (
<>
<Header prefixCls={prefixCls} columns={columns} />
<SortableList
ref={ref}
renderItem={renderItem}
value={parsedValue}
initialValues={parsedInitialValues}
className={cx(prefixCls, className)}
creatorButtonProps={{
record: (index) => ({
id: genUniqueID({}, index),
}),
}}
{...props}
/>
</>
);
},
);
return (
<>
<Header prefixCls={prefixCls} columns={columns} />
<SortableList
ref={ref}
renderItem={renderItem}
className={cx(prefixCls, className)}
creatorButtonProps={{
record: () => ({
id: genUniqueId('column-list'),
}),
}}
{...props}
/>
</>
);
});

export default ColumnList;
6 changes: 3 additions & 3 deletions src/ColumnList/demos/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* description: 可以通过 `actions` 属性自定义操作列
*/
import { EditFilled } from '@ant-design/icons';
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ActionIcon, ColumnList } from '@ant-design/pro-editor';
import { message } from 'antd';
import { tableColumnValueOptions } from './mock_data/options';
Expand All @@ -12,9 +12,9 @@ type SchemaItem = {
title: string;
valueType: string;
dataIndex: string;
};
} & SortableItem;

const initialValues = [
const initialValues: SchemaItem[] = [
{ id: 'index', title: '序号', valueType: 'indexBorder', dataIndex: 'index' },
{
id: 'name',
Expand Down
4 changes: 2 additions & 2 deletions src/ColumnList/demos/column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
* title: 自定义表单
* description: 目前支持 `input` 和 `select`, `custom` 三种表单类型.
*/
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ColorPicker, ColumnList } from '@ant-design/pro-editor';
import { tableColumnValueOptions } from './mock_data/options';

type SchemaItem = {
title: string;
valueType: string;
dataIndex: string;
};
} & SortableItem;

const initialValues = [
{ id: 'orderId', dataIndex: 'orderId', valueType: 'text', title: '订单id', color: undefined },
Expand Down
8 changes: 4 additions & 4 deletions src/ColumnList/demos/controlled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* title: 受控模式
* description: 表单可通过 `value` 受控
*/
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ColumnList } from '@ant-design/pro-editor';
import { useState } from 'react';

Expand All @@ -12,9 +12,9 @@ type SchemaItem = {
title: string;
valueType: string;
dataIndex: string;
};
} & SortableItem;

const INIT_VALUES = [
const INIT_VALUES: SchemaItem[] = [
{ id: 'index', title: '序号', valueType: 'indexBorder', dataIndex: 'index' },
{
id: 'name',
Expand Down Expand Up @@ -45,7 +45,7 @@ const columns: ColumnItemList<SchemaItem> = [
];

export default () => {
const [value, setValue] = useState<SchemaItem[]>(INIT_VALUES);
const [value, setValue] = useState(INIT_VALUES);

return (
<ColumnList<SchemaItem>
Expand Down
8 changes: 4 additions & 4 deletions src/ColumnList/demos/creatorButtonProps.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* title: 自定义初始化
* description: 可通过 `creatorButtonProps` 来自定义初始化逻辑
* description: 可通过 `creatorButtonProps` 来自定义初始化逻辑,id 的生成逻辑是必须的。
*/
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ColumnList } from '@ant-design/pro-editor';

import { tableColumnValueOptions } from './mock_data/options';
Expand All @@ -11,7 +11,7 @@ type SchemaItem = {
title: string;
valueType?: string;
dataIndex: string;
};
} & SortableItem;

const INIT_VALUES = [
{ id: 'orderId', dataIndex: 'orderId', valueType: 'text', title: '订单id', color: undefined },
Expand Down Expand Up @@ -81,7 +81,7 @@ const INIT_VALUES = [
];

/**
* 创建一个随机的索引标记符
* 创建一个随机的索引标记符,请勿在生产环境使用
*/
export const randomIndex = () => Math.random() * 10000;

Expand Down
6 changes: 3 additions & 3 deletions src/ColumnList/demos/empty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* description: 当表单值为空时,会渲染空状态
*/
import { EditFilled } from '@ant-design/icons';
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ActionIcon, ColumnList } from '@ant-design/pro-editor';
import { message } from 'antd';
import { useState } from 'react';
Expand All @@ -13,7 +13,7 @@ type SchemaItem = {
title: string;
valueType: string;
dataIndex: string;
};
} & SortableItem;

const columns: ColumnItemList<SchemaItem> = [
{
Expand All @@ -35,7 +35,7 @@ const columns: ColumnItemList<SchemaItem> = [
];

export default () => {
const [value, setValue] = useState(null);
const [value, setValue] = useState([]);
return (
<ColumnList<SchemaItem>
columns={columns}
Expand Down
5 changes: 3 additions & 2 deletions src/ColumnList/demos/normal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
* title: 基础使用
* description: 通过配置 `columns` 渲染排序表单
*/
import type { ColumnItemList } from '@ant-design/pro-editor';
import type { ColumnItemList, SortableItem } from '@ant-design/pro-editor';
import { ColumnList } from '@ant-design/pro-editor';

type SchemaItem = {
title: string;
dataIndex: string;
};
} & SortableItem;

const initialValues = [
{ id: 'index', title: '序号', valueType: 'indexBorder', dataIndex: 'index' },
Expand Down
8 changes: 4 additions & 4 deletions src/ColumnList/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ demo:

提供封装的 `columns` 配置,其他属性参考 `SortableList`

| 属性名 | 类型 | 描述 |
| ------- | ----------------- | -------- |
| columns | `ColumnItem<T>[]` | 列配置项 |
| 属性名 | 类型 | 描述 |
| ------- | ---------------------------- | -------- |
| columns | `ColumnItem<SortableItem>[]` | 列配置项 |

### ColumnItem

Expand Down Expand Up @@ -62,7 +62,7 @@ demo:

| 属性名 | 类型 | 描述 |
| -------- | ---------------------- | -------------- |
| item | `T` | 当前项数据 |
| item | `SortableItem` | 当前项数据 |
| value | `any` | 当前值 |
| onChange | `(value: any) => void` | 值变化回调函数 |
| column | `ColumnItem<T>` | 对应列信息 |
Expand Down
5 changes: 0 additions & 5 deletions src/ColumnList/utils.tsx

This file was deleted.

15 changes: 10 additions & 5 deletions src/SortableList/container/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ const selector = (s: Store) => ({
handleDragStart: s.handleDragStart,
handleDragCancel: s.handleDragCancel,
handleDragEnd: s.handleDragEnd,
getId: s.getId,
});

const dataSelector = (s: Store) => s.value;

export interface AppProps {
/**
* 类名
Expand All @@ -55,9 +54,9 @@ export interface AppProps {
}

const App: FC<AppProps> = ({ className, style, prefixCls: customPrefixCls }) => {
const { handleDragStart, handleDragCancel, handleDragEnd } = useStore(selector, shallow);
const { handleDragStart, handleDragCancel, handleDragEnd, getId } = useStore(selector, shallow);

const items = useStore(dataSelector, isEqual);
const items = useStore((s) => s.value, isEqual);

const prefixCls = getPrefixCls('sortable-list', customPrefixCls);

Expand Down Expand Up @@ -85,7 +84,13 @@ const App: FC<AppProps> = ({ className, style, prefixCls: customPrefixCls }) =>
onDragCancel={handleDragCancel}
modifiers={[restrictToVerticalAxis, restrictToWindowEdges]}
>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
<SortableContext
items={items.map((item, index) => ({
...item,
id: getId(item, index),
}))}
strategy={verticalListSortingStrategy}
>
<SortList prefixCls={prefixCls} />
{overlay}
</SortableContext>
Expand Down
Loading

0 comments on commit a43ce91

Please sign in to comment.