diff --git a/CHANGELOG.md b/CHANGELOG.md index 529eecc2..3fcbf83b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,92 @@ # Changelog +## [Version 0.16.0](https://github.com/ant-design/pro-editor/compare/v0.15.0...v0.16.0) + +Released on **2023-08-31** + +#### ✨ 新特性 + +- 支持传入 getId 方法自定义 id 生成规则. + +#### 🐛 修复 + +- DispatchListData error, 修复控制台报错, 去除自动生成 ID 的逻辑,改为由用户自行传递 ID. + +
+ +
+Improvements and Fixes + +#### What's improved + +- 支持传入 getId 方法自定义 id 生成规则 ([74016a8](https://github.com/ant-design/pro-editor/commit/74016a8)) + +#### What's fixed + +- DispatchListData error ([2852524](https://github.com/ant-design/pro-editor/commit/2852524)) +- 修复控制台报错 ([dadf4b3](https://github.com/ant-design/pro-editor/commit/dadf4b3)) +- 去除自动生成 ID 的逻辑,改为由用户自行传递 ID ([9026256](https://github.com/ant-design/pro-editor/commit/9026256)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +## [Version 0.15.0](https://github.com/ant-design/pro-editor/compare/v0.14.1...v0.15.0) + +Released on **2023-08-30** + +#### ✨ 新特性 + +- Doc update. + +
+ +
+Improvements and Fixes + +#### What's improved + +- Doc update ([01f6325](https://github.com/ant-design/pro-editor/commit/01f6325)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ +### [Version 0.14.1](https://github.com/ant-design/pro-editor/compare/v0.14.0...v0.14.1) + +Released on **2023-08-29** + +#### 🐛 修复 + +- Drag over index lost, 修复 sortableList item 样式问题 && 更新文档, 多实例时的定位错误问题. + +
+ +
+Improvements and Fixes + +#### What's fixed + +- Drag over index lost ([75752fe](https://github.com/ant-design/pro-editor/commit/75752fe)) +- 修复 sortableList item 样式问题 && 更新文档 ([850cbe7](https://github.com/ant-design/pro-editor/commit/850cbe7)) +- 多实例时的定位错误问题 ([f3b38ba](https://github.com/ant-design/pro-editor/commit/f3b38ba)) + +
+ +
+ +[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top) + +
+ ## [Version 0.14.0](https://github.com/ant-design/pro-editor/compare/v0.13.1...v0.14.0) Released on **2023-08-29** diff --git a/README.md b/README.md index a4acae2e..4026faa1 100644 --- a/README.md +++ b/README.md @@ -153,12 +153,12 @@ Open your browser and visit http://localhost:8000 - - - + + + diff --git a/package.json b/package.json index fb5c9044..f4a9cc27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ant-design/pro-editor", - "version": "0.14.0", + "version": "0.16.0", "description": "🌟 Lightweight Editor UI Framework", "homepage": "https://github.com/ant-design/pro-editor", "bugs": { @@ -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", @@ -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", @@ -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", diff --git a/src/ActionGroup/demos/basic.tsx b/src/ActionGroup/demos/basic.tsx index 281124b8..961d7446 100644 --- a/src/ActionGroup/demos/basic.tsx +++ b/src/ActionGroup/demos/basic.tsx @@ -1,3 +1,6 @@ +/** + * title: 基础使用 + */ import { ActionGroup } from '@ant-design/pro-editor'; export default () => { diff --git a/src/ActionGroup/demos/config.tsx b/src/ActionGroup/demos/config.tsx index 52c05314..91341701 100644 --- a/src/ActionGroup/demos/config.tsx +++ b/src/ActionGroup/demos/config.tsx @@ -1,3 +1,7 @@ +/** + * title: 配置使用 + * description: 通过配置 `items` 渲染整个内容 + */ import { CopyOutlined, DragOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; import { ActionGroup } from '@ant-design/pro-editor'; import { message } from 'antd'; diff --git a/src/ActionGroup/demos/custom.tsx b/src/ActionGroup/demos/custom.tsx index a650b04e..723548d3 100644 --- a/src/ActionGroup/demos/custom.tsx +++ b/src/ActionGroup/demos/custom.tsx @@ -1,3 +1,7 @@ +/** + * title: 自定义 + * description: 通过 `render` 可以自定义渲染特殊的操作内容 + */ import { ActionGroup, ActionIcon } from '@ant-design/pro-editor'; import { Card, Input, Rate, Switch } from 'antd'; diff --git a/src/ActionGroup/demos/dropMenu.tsx b/src/ActionGroup/demos/dropMenu.tsx index a4d7a967..fbc44e12 100644 --- a/src/ActionGroup/demos/dropMenu.tsx +++ b/src/ActionGroup/demos/dropMenu.tsx @@ -1,3 +1,8 @@ +/** + * title: dropdown + * description: 通过配置 `dropdownMenu` 可以在尾部渲染一个下拉内容 + */ + import { CopyOutlined, DragOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; import { ActionGroup } from '@ant-design/pro-editor'; import { message } from 'antd'; diff --git a/src/ActionGroup/demos/type.tsx b/src/ActionGroup/demos/type.tsx index 97f12db6..4968cfaf 100644 --- a/src/ActionGroup/demos/type.tsx +++ b/src/ActionGroup/demos/type.tsx @@ -1,4 +1,7 @@ import { CopyOutlined, DragOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; +/** + * title: 模式配置 + */ import { ActionGroup } from '@ant-design/pro-editor'; import { InputNumber, Segmented, Space } from 'antd'; import { useState } from 'react'; diff --git a/src/ActionGroup/demos/withPanel.tsx b/src/ActionGroup/demos/withPanel.tsx index 8a0a12fd..05eefce2 100644 --- a/src/ActionGroup/demos/withPanel.tsx +++ b/src/ActionGroup/demos/withPanel.tsx @@ -1,3 +1,8 @@ +/** + * title: 浮动面板中使用 + * description: 配合 DraggablePanel 可以使得整个面板可浮动拖拽 + */ + import type { Position } from '@ant-design/pro-editor'; import { ActionGroup, DraggablePanel } from '@ant-design/pro-editor'; import { useLocalStorageState } from 'ahooks'; diff --git a/src/ActionGroup/index.md b/src/ActionGroup/index.md index d5ff2174..9537f8b9 100644 --- a/src/ActionGroup/index.md +++ b/src/ActionGroup/index.md @@ -2,6 +2,8 @@ title: ActionGroup 工具面板 atomId: ActionGroup group: 基础组件 +demo: + cols: 2 --- # ActionGroup 工具面板 @@ -12,28 +14,11 @@ group: 基础组件 ## 代码演示 -### 基础 - - -### 使用配置 - - -### 使用 dropdownMenu 扩展更多内容 - - -### 类型、大小和方向调整 - - -### 高度自定义 - - -### 使用浮动面板 - ## API diff --git a/src/ColumnList/ColumnItem.tsx b/src/ColumnList/ColumnItem.tsx index 3a968457..2685935d 100644 --- a/src/ColumnList/ColumnItem.tsx +++ b/src/ColumnList/ColumnItem.tsx @@ -2,6 +2,7 @@ import { ColumnItemList, DeleteAction, HandleAction, + SortableItem, useSortableList, } from '@ant-design/pro-editor'; import { createStyles } from 'antd-style'; @@ -68,7 +69,7 @@ const useStyle = createStyles(({ css, cx }, prefixCls) => { }; }); -interface ItemRenderProps { +interface ItemRenderProps { columns: ColumnItemList; item: T; index: number; @@ -98,6 +99,7 @@ const ColumnItem = memo( const props = { dataIndex: col.dataIndex, value: item[col.dataIndex], + id: item.id, index, prefixCls, style, @@ -121,6 +123,7 @@ const ColumnItem = memo( return Custom ? ( { instance.updateItem({ [col.dataIndex]: value }, index); diff --git a/src/ColumnList/ColumnList.tsx b/src/ColumnList/ColumnList.tsx index a3f1ffb7..80d997db 100644 --- a/src/ColumnList/ColumnList.tsx +++ b/src/ColumnList/ColumnList.tsx @@ -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 { - /** - * 生成初始值逻辑 - */ - record: (index: number) => Partial; - /** - * 新增一行按钮文案 - */ - creatorButtonText?: string; -} - -export interface ColumnListProps extends SortableListProps { +export interface ColumnListProps + extends SortableListProps { columns: ColumnItemList; } -/** - * 供外部使用的 ref 方法 - */ -export interface ColumnListRef { - addItem: (item?: SortableItem, index?: number) => void; - removeItem: (index: number) => void; - updateItem: (item: SortableItem, index: number) => void; -} - -const ColumnList: (props: ColumnListProps) => ReactNode = forwardRef< - ColumnListRef, +const ColumnList: (props: ColumnListProps) => 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 }) => ( - - ), - [prefixCls, columns], - ); + const renderItem = useCallback( + (item, { index, listeners }) => ( + + ), + [prefixCls, columns], + ); - return ( - <> -
- ({ - id: genUniqueID({}, index), - }), - }} - {...props} - /> - - ); - }, -); + return ( + <> +
+ ({ + id: genUniqueId('column-list'), + }), + }} + {...props} + /> + + ); +}); export default ColumnList; diff --git a/src/ColumnList/demos/actions.tsx b/src/ColumnList/demos/actions.tsx index 5e790cc5..27cb810d 100644 --- a/src/ColumnList/demos/actions.tsx +++ b/src/ColumnList/demos/actions.tsx @@ -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'; @@ -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', diff --git a/src/ColumnList/demos/column.tsx b/src/ColumnList/demos/column.tsx index 6a698ea0..57e3068f 100644 --- a/src/ColumnList/demos/column.tsx +++ b/src/ColumnList/demos/column.tsx @@ -2,7 +2,7 @@ * 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'; @@ -10,7 +10,7 @@ type SchemaItem = { title: string; valueType: string; dataIndex: string; -}; +} & SortableItem; const initialValues = [ { id: 'orderId', dataIndex: 'orderId', valueType: 'text', title: '订单id', color: undefined }, diff --git a/src/ColumnList/demos/controlled.tsx b/src/ColumnList/demos/controlled.tsx index 35c634d6..2e935147 100644 --- a/src/ColumnList/demos/controlled.tsx +++ b/src/ColumnList/demos/controlled.tsx @@ -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'; @@ -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', @@ -45,7 +45,7 @@ const columns: ColumnItemList = [ ]; export default () => { - const [value, setValue] = useState(INIT_VALUES); + const [value, setValue] = useState(INIT_VALUES); return ( diff --git a/src/ColumnList/demos/creatorButtonProps.tsx b/src/ColumnList/demos/creatorButtonProps.tsx index 1a1432de..537cee6f 100644 --- a/src/ColumnList/demos/creatorButtonProps.tsx +++ b/src/ColumnList/demos/creatorButtonProps.tsx @@ -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'; @@ -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 }, @@ -81,7 +81,7 @@ const INIT_VALUES = [ ]; /** - * 创建一个随机的索引标记符 + * 创建一个随机的索引标记符,请勿在生产环境使用 */ export const randomIndex = () => Math.random() * 10000; diff --git a/src/ColumnList/demos/empty.tsx b/src/ColumnList/demos/empty.tsx index bd6a6bac..e407aa08 100644 --- a/src/ColumnList/demos/empty.tsx +++ b/src/ColumnList/demos/empty.tsx @@ -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'; @@ -13,7 +13,7 @@ type SchemaItem = { title: string; valueType: string; dataIndex: string; -}; +} & SortableItem; const columns: ColumnItemList = [ { @@ -35,7 +35,7 @@ const columns: ColumnItemList = [ ]; export default () => { - const [value, setValue] = useState(null); + const [value, setValue] = useState([]); return ( columns={columns} diff --git a/src/ColumnList/demos/normal.tsx b/src/ColumnList/demos/normal.tsx index 048c87c8..37892f15 100644 --- a/src/ColumnList/demos/normal.tsx +++ b/src/ColumnList/demos/normal.tsx @@ -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' }, diff --git a/src/ColumnList/index.md b/src/ColumnList/index.md index bb0e6335..61a28c25 100644 --- a/src/ColumnList/index.md +++ b/src/ColumnList/index.md @@ -26,9 +26,9 @@ demo: 提供封装的 `columns` 配置,其他属性参考 `SortableList` -| 属性名 | 类型 | 描述 | -| ------- | ----------------- | -------- | -| columns | `ColumnItem[]` | 列配置项 | +| 属性名 | 类型 | 描述 | +| ------- | ---------------------------- | -------- | +| columns | `ColumnItem[]` | 列配置项 | ### ColumnItem @@ -62,7 +62,7 @@ demo: | 属性名 | 类型 | 描述 | | -------- | ---------------------- | -------------- | -| item | `T` | 当前项数据 | +| item | `SortableItem` | 当前项数据 | | value | `any` | 当前值 | | onChange | `(value: any) => void` | 值变化回调函数 | | column | `ColumnItem` | 对应列信息 | diff --git a/src/ColumnList/renderItem/Input.tsx b/src/ColumnList/renderItem/Input.tsx index d2d005df..f243bebc 100644 --- a/src/ColumnList/renderItem/Input.tsx +++ b/src/ColumnList/renderItem/Input.tsx @@ -1,8 +1,8 @@ -import { useSortableList } from '@ant-design/pro-editor'; +import { genUniqueId, useSortableList } from '@ant-design/pro-editor'; +import { UniqueIdentifier } from '@dnd-kit/core'; import { Input } from 'antd'; import { createStyles } from 'antd-style'; import { CSSProperties, memo, useRef, useState } from 'react'; -import { genUniqueID } from '../utils'; const useStyle = createStyles(({ css, cx }, prefixCls) => { const prefix = `${prefixCls}-content`; @@ -20,13 +20,14 @@ interface ItemRenderProps { dataIndex: string; value: string; index: number; + id: UniqueIdentifier; prefixCls: string; style: CSSProperties; placeholder?: string; } const ControlInput = memo( - ({ dataIndex, placeholder, value, index, prefixCls, style }) => { + ({ dataIndex, placeholder, value, index, prefixCls, style, id }) => { const instance = useSortableList(); const [innerValue, setInnerValue] = useState(value); @@ -39,18 +40,19 @@ const ControlInput = memo( setChanged(false); }; - const customListId = (index) => `column-list-index-${index}`; + const customListId = (index, id) => `column-list-${index}-${id}`; const handleNextFocus = () => { const value = instance.getValue() || []; // 如果是最后一个节点,按下回车后,会自动添加一个新的节点 if (index + 1 === value.length) { - // TODO:create 项时 新建项的预填充内容 - instance.addItem({ id: genUniqueID(value, value.length), [dataIndex]: '' }); + instance.addItem({ id: genUniqueId(value.length.toString()), [dataIndex]: '' }); } setTimeout(() => { - const nextNodeEl = document.getElementById(customListId(index + 1)); + const nextNodeEl = document.getElementById( + customListId(index + 1, instance.getIdByIndex(index + 1)), + ); nextNodeEl?.focus(); }, 200); }; @@ -60,7 +62,7 @@ const ControlInput = memo( size={'small'} value={innerValue} style={style} - id={customListId(index)} + id={customListId(index, id)} onCompositionStart={() => { shouldChange.current = false; }} diff --git a/src/ColumnList/utils.tsx b/src/ColumnList/utils.tsx deleted file mode 100644 index 1c9654d4..00000000 --- a/src/ColumnList/utils.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import hash from 'object-hash'; - -export const genUniqueID = (item, index) => { - return `columnlist_${index}_${hash(item).slice(-6)}`; -}; diff --git a/src/SortableList/components/Item/index.tsx b/src/SortableList/components/Item/index.tsx index b76426d9..09c7c504 100644 --- a/src/SortableList/components/Item/index.tsx +++ b/src/SortableList/components/Item/index.tsx @@ -125,7 +125,7 @@ const Item = memo( )} diff --git a/src/SortableList/components/Item/style.ts b/src/SortableList/components/Item/style.ts index f57f2052..58375cfd 100644 --- a/src/SortableList/components/Item/style.ts +++ b/src/SortableList/components/Item/style.ts @@ -150,19 +150,5 @@ export const useStyle = createStyles(({ css, cx, token }, prefixCls: string) => } `, ), - actionsRight: cx( - `${prefix}-actions-right`, - css` - position: absolute; - top: 1px; - right: 1px; - align-self: flex-end; - overflow: hidden; - border-radius: 1px; - // 采用背景模糊来解决多种背景色下覆盖内容的问题 TODO:FireFox 兼容 - backdrop-filter: blur(5px); - //background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, @bg-2 10%, @bg-2 100%); - `, - ), }; }); diff --git a/src/SortableList/container/App.tsx b/src/SortableList/container/App.tsx index 013240d6..7905ef69 100644 --- a/src/SortableList/container/App.tsx +++ b/src/SortableList/container/App.tsx @@ -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 { /** * 类名 @@ -55,9 +54,9 @@ export interface AppProps { } const App: FC = ({ 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); @@ -85,7 +84,13 @@ const App: FC = ({ className, style, prefixCls: customPrefixCls }) => onDragCancel={handleDragCancel} modifiers={[restrictToVerticalAxis, restrictToWindowEdges]} > - + ({ + ...item, + id: getId(item, index), + }))} + strategy={verticalListSortingStrategy} + > {overlay} diff --git a/src/SortableList/container/StoreUpdater.tsx b/src/SortableList/container/StoreUpdater.tsx index eea02e67..ef8fa38f 100644 --- a/src/SortableList/container/StoreUpdater.tsx +++ b/src/SortableList/container/StoreUpdater.tsx @@ -14,6 +14,7 @@ const StoreUpdater = forwardRef( renderItem, renderContent, getItemStyles, + getId, creatorButtonProps, hideRemove, }: StoreUpdaterProps, @@ -23,9 +24,9 @@ const StoreUpdater = forwardRef( const useStoreUpdater = createStoreUpdater(storeApi); useStoreUpdater('value', initialValues, []); - useStoreUpdater('initialValues', initialValues); - useStoreUpdater('value', value); + useStoreUpdater('value', value, []); useStoreUpdater('actions', actions); + useStoreUpdater('getId', getId); useStoreUpdater('onChange', onChange); useStoreUpdater('renderItem', renderItem); useStoreUpdater('renderContent', renderContent); diff --git a/src/SortableList/demos/Basic.tsx b/src/SortableList/demos/Basic.tsx index 026b92eb..b845ce74 100644 --- a/src/SortableList/demos/Basic.tsx +++ b/src/SortableList/demos/Basic.tsx @@ -1,5 +1,6 @@ /** * title: 默认使用 + * description: 默认内容区域渲染 `id`,可通过 `renderContent` 来自定义渲染内容。 * compact: true */ import { SortableList } from '@ant-design/pro-editor'; diff --git a/src/SortableList/demos/_ItemRender.tsx b/src/SortableList/demos/_ItemRender.tsx index 5b6b7f32..d36c9554 100644 --- a/src/SortableList/demos/_ItemRender.tsx +++ b/src/SortableList/demos/_ItemRender.tsx @@ -1,12 +1,12 @@ import { useSortableList } from '@ant-design/pro-editor'; import { Input, Select } from 'antd'; -import { useState } from 'react'; +import { memo, useState } from 'react'; import { Flexbox } from 'react-layout-kit'; import { ItemRenderProps, fieldStyle, tableColumnValueOptions } from './data'; export const randomIndex = () => Math.random() * 10000; -const ItemRender = ({ item, index, compact = false }: ItemRenderProps) => { +const ItemRender = memo(({ item, index, compact = false }: ItemRenderProps) => { const instance = useSortableList(); const [title, setTitle] = useState(item?.title); const [changed, setChanged] = useState(false); @@ -63,6 +63,6 @@ const ItemRender = ({ item, index, compact = false }: ItemRenderProps) => { ); -}; +}); export default ItemRender; diff --git a/src/SortableList/demos/getId.tsx b/src/SortableList/demos/getId.tsx new file mode 100644 index 00000000..098a7924 --- /dev/null +++ b/src/SortableList/demos/getId.tsx @@ -0,0 +1,30 @@ +/** + * title: 自定义 Id 生成规则 + * description: 如果传入的数据中没有 `id` 字段,可以通过 `getId` 指定获取唯一值的方法 + * compact: true + */ +import { SortableList } from '@ant-design/pro-editor'; +import { useTheme } from 'antd-style'; +import { Flexbox } from 'react-layout-kit'; + +const list = [ + { text: 'hello', dataIndex: 'foo' }, + { text: 'world', dataIndex: 'bar' }, +]; + +const Demo = () => { + const token = useTheme(); + return ( + + item.dataIndex} + onChange={(value) => { + console.log('value', value); + }} + /> + + ); +}; + +export default Demo; diff --git a/src/SortableList/demos/provider.tsx b/src/SortableList/demos/provider.tsx index d51d9106..240b6a05 100644 --- a/src/SortableList/demos/provider.tsx +++ b/src/SortableList/demos/provider.tsx @@ -1,8 +1,13 @@ +/** + * title: Provider + * description: 为了方便用户在更高的上下文中通过 `useSortableList()` hook 获得组件实例,我们提供了 `SortableListProvider` 由用户控制 Provider 的作用范围。 + * compact: true + */ import { SortableList, SortableListProvider, useSortableList } from '@ant-design/pro-editor'; import { Button, message } from 'antd'; +import { useTheme } from 'antd-style'; import { useState } from 'react'; import { Flexbox } from 'react-layout-kit'; - import ItemRender from './_ItemRender'; import { INIT_VALUES, SchemaItem } from './data'; @@ -10,32 +15,42 @@ const App = () => { const [listData, setListData] = useState(INIT_VALUES); return ( - - - value={listData} - onChange={(data) => { - console.log('data', data); - setListData(data); - }} - renderContent={(item, index) => } - SHOW_STORE_IN_DEVTOOLS // 用于显示 Redux Devtools - /> - + + value={listData} + onChange={(data) => { + console.log('data', data); + setListData(data); + }} + renderContent={(item, index) => } + SHOW_STORE_IN_DEVTOOLS // 用于显示 Redux Devtools + /> ); }; const Extra = () => { const instance = useSortableList(); return ( -
- -
+ ); }; -export default () => ( - - - - -); +export default () => { + const token = useTheme(); + + return ( + + + + + + + ); +}; diff --git a/src/SortableList/demos/ref.tsx b/src/SortableList/demos/ref.tsx index 3e9572e3..47af51cb 100644 --- a/src/SortableList/demos/ref.tsx +++ b/src/SortableList/demos/ref.tsx @@ -1,9 +1,11 @@ /** * title: 使用 ref 获得实例 * description: 提供传统的 `ref` 方式关联组件实例,可实现自定义功能,如将添加按钮渲染到组件右上方。 + * compact: true */ import { PlusCircleFilled } from '@ant-design/icons'; import { ActionIcon, SortableList, SortableListRef } from '@ant-design/pro-editor'; +import { useTheme } from 'antd-style'; import { useRef, useState } from 'react'; import { Flexbox } from 'react-layout-kit'; import ItemRender from './_ItemRender'; @@ -17,9 +19,10 @@ export const randomIndex = () => Math.random() * 10000; export default () => { const [listData, setListData] = useState(INIT_VALUES); const ref = useRef>(null); + const token = useTheme(); return ( -
+
列配置项
{ }} renderContent={(item, index) => } /> -
+ ); }; diff --git a/src/SortableList/demos/renderContent.tsx b/src/SortableList/demos/renderContent.tsx index 320663f0..54080280 100644 --- a/src/SortableList/demos/renderContent.tsx +++ b/src/SortableList/demos/renderContent.tsx @@ -1,14 +1,18 @@ /** * title: 自定义列表项内容 * description: 提供 `renderContent` 由用户自定义除拖拽等操作外的列表项内容。 + * compact: true */ import { SortableList } from '@ant-design/pro-editor'; +import { useTheme } from 'antd-style'; +import { Flexbox } from 'react-layout-kit'; import ItemRender from './_ItemRender'; import { INIT_VALUES, SchemaItem } from './data'; export default () => { + const token = useTheme(); return ( -
+ initialValues={INIT_VALUES} onChange={(data, event) => { @@ -16,6 +20,6 @@ export default () => { }} renderContent={(item, index) => } /> -
+ ); }; diff --git a/src/SortableList/demos/renderItem.tsx b/src/SortableList/demos/renderItem.tsx index e7bb907f..144ca0bd 100644 --- a/src/SortableList/demos/renderItem.tsx +++ b/src/SortableList/demos/renderItem.tsx @@ -1,6 +1,7 @@ /** * title: 自定义排序项 * description: 通过 `renderItem` 可以自定义每个排序项,相比于 `renderContent` 提供的自由度更大 + * compact: true */ import { SortableList, SortableListRef } from '@ant-design/pro-editor'; import { Badge, Button } from 'antd'; @@ -29,26 +30,26 @@ const Demo = () => { +
+ hello +
+
+ +
+ + + +
  • +
    +
    + +
    + world +
    +
    + +
    +
    +
    +
  • + + +
    +
    + + +`; + +exports[` > renders controlled.tsx correctly 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + padding: 24px; +} + +.emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} + +.emotion-2 { + list-style: none; + display: grid; + grid-auto-rows: max-content; + grid-gap: 2px; + grid-template-columns: repeat(var(--columns, 1), 1fr); + width: 100%; + margin: 0; + padding: 0; + border-radius: 4px; + -webkit-transition: background-color 350ms ease; + transition: background-color 350ms ease; +} + +.emotion-3 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + -webkit-transform: translate3d(var(--translate-x, 0), var(--translate-y, 0), 0) scaleX(var(--scale-x, 1)) scaleY(var(--scale-y, 1)); + -moz-transform: translate3d(var(--translate-x, 0), var(--translate-y, 0), 0) scaleX(var(--scale-x, 1)) scaleY(var(--scale-y, 1)); + -ms-transform: translate3d(var(--translate-x, 0), var(--translate-y, 0), 0) scaleX(var(--scale-x, 1)) scaleY(var(--scale-y, 1)); + transform: translate3d(var(--translate-x, 0), var(--translate-y, 0), 0) scaleX(var(--scale-x, 1)) scaleY(var(--scale-y, 1)); + transform-origin: 0 0; + touch-action: manipulation; +} + +.emotion-3:not(:last-child) { + margin-bottom: 2px; +} + +.emotion-4 { + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + box-sizing: border-box; + padding: 1px 0; + color: rgba(0, 0, 0, 0.65); + font-size: 12px; + white-space: nowrap; + list-style: none; + border-radius: 4px; + outline: none; + -webkit-transform: scale(var(--scale, 1)); + -moz-transform: scale(var(--scale, 1)); + -ms-transform: scale(var(--scale, 1)); + transform: scale(var(--scale, 1)); + transform-origin: 50% 50%; + -webkit-transition: box-shadow 200ms cubic-bezier(0.18, 0.67, 0.6, 1.22); + transition: box-shadow 200ms cubic-bezier(0.18, 0.67, 0.6, 1.22); + -webkit-tap-highlight-color: transparent; +} + +.emotion-4:focus-visible { + box-shadow: 0 0 4px 1px #4c9ffe,0 0 0 calc(1px / var(--scale-x, 1)) rgba(0, 0, 0, 0.05) 0 1px calc(3px / var(--scale-x, 1)) 0 rgba(0, 0, 0, 0.15); +} + +.emotion-4:not(.studio-sortable-list-item-withHandle) { + cursor: -webkit-grab; + cursor: grab; + -webkit-user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + touch-action: none; +} + +.emotion-4-dragging:not(.studio-sortable-list-item-dragOverlay) { + z-index: 0; + opacity: var(--dragging-opacity, 0.5); +} + +.emotion-4-dragging:not(.studio-sortable-list-item-dragOverlay):focus { + box-shadow: 0 0 0 calc(1px / var(--scale-x, 1)) rgba(0, 0, 0, 0.05) 0 1px calc(3px / var(--scale-x, 1)) 0 rgba(0, 0, 0, 0.15); +} + +.emotion-5 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.emotion-6 { + position: relative; + width: 100%; + height: 24px; + border-radius: 2px; + min-width: 48px; +} + +.emotion-6:hover .studio-sortable-list-item-actions { + opacity: 1; +} + +.emotion-7 { + z-index: 10; + color: hsla(0, 0, 0, 0.45); + opacity: 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-transition: color 600ms cubic-bezier(0.215, 0.61, 0.355, 1),scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1),background-color 100ms cubic-bezier(0.215, 0.61, 0.355, 1); + transition: color 600ms cubic-bezier(0.215, 0.61, 0.355, 1),scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1),background-color 100ms cubic-bezier(0.215, 0.61, 0.355, 1); +} + +.emotion-7:hover { + color: rgba(0, 0, 0, 0.88)!important; +} + +.emotion-7:active { + scale: 0.8; + color: rgba(0, 0, 0, 0.88); +} + +.emotion-8 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } -.emotion-12 { +.emotion-10 { + z-index: 10; + color: hsla(0, 0, 0, 0.45); + opacity: 0; +} + +.emotion-11 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -21774,11 +22175,11 @@ exports[` > renders Basic.tsx correctly 1`] = ` transition: color 600ms cubic-bezier(0.215, 0.61, 0.355, 1),scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1),background-color 100ms cubic-bezier(0.215, 0.61, 0.355, 1); } -.emotion-12:hover { +.emotion-11:hover { color: rgba(0, 0, 0, 0.88)!important; } -.emotion-12:active { +.emotion-11:active { scale: 0.8; color: rgba(0, 0, 0, 0.88); } @@ -21798,7 +22199,7 @@ exports[` > renders Basic.tsx correctly 1`] = `
  • > renders Basic.tsx correctly 1`] = ` hello
    `; -exports[` > renders controlled.tsx correctly 1`] = ` +exports[` > renders creatorButtonProps.tsx correctly 1`] = ` .emotion-0 { display: -webkit-box; display: -webkit-flex; @@ -22172,19 +22573,6 @@ exports[` > renders controlled.tsx correctly 1`] = ` } .emotion-11 { - position: absolute; - top: 1px; - right: 1px; - -webkit-align-self: flex-end; - -ms-flex-item-align: flex-end; - align-self: flex-end; - overflow: hidden; - border-radius: 1px; - -webkit-backdrop-filter: blur(5px); - backdrop-filter: blur(5px); -} - -.emotion-12 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -22201,15 +22589,38 @@ exports[` > renders controlled.tsx correctly 1`] = ` transition: color 600ms cubic-bezier(0.215, 0.61, 0.355, 1),scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1),background-color 100ms cubic-bezier(0.215, 0.61, 0.355, 1); } -.emotion-12:hover { +.emotion-11:hover { color: rgba(0, 0, 0, 0.88)!important; } -.emotion-12:active { +.emotion-11:active { scale: 0.8; color: rgba(0, 0, 0, 0.88); } +.emotion-21 { + height: 24px; + padding-block: 2px; + margin-top: 4px; + margin-bottom: 4px; + color: rgba(0, 0, 0, 0.65); + background: rgba(0, 0, 0, 0.02); + border-color: transparent; +} + +.emotion-21:hover { + color: rgba(0, 0, 0, 0.88)!important; + background: rgba(0, 0, 0, 0.06)!important; + border-color: transparent!important; +} + +.emotion-21:focus { + color: rgba(0, 0, 0, 0.65); + background: rgba(0, 0, 0, 0.02); + border-color: transparent; + border-color: #1677ff!important; +} +
    > renders controlled.tsx correctly 1`] = ` hello
  • + `; -exports[` > renders creatorButtonProps.tsx correctly 1`] = ` +exports[` > renders getId.tsx correctly 1`] = ` .emotion-0 { display: -webkit-box; display: -webkit-flex; @@ -22599,19 +23044,6 @@ exports[` > renders creatorButtonProps.tsx correctly 1`] = ` } .emotion-11 { - position: absolute; - top: 1px; - right: 1px; - -webkit-align-self: flex-end; - -ms-flex-item-align: flex-end; - align-self: flex-end; - overflow: hidden; - border-radius: 1px; - -webkit-backdrop-filter: blur(5px); - backdrop-filter: blur(5px); -} - -.emotion-12 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -22628,38 +23060,15 @@ exports[` > renders creatorButtonProps.tsx correctly 1`] = ` transition: color 600ms cubic-bezier(0.215, 0.61, 0.355, 1),scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1),background-color 100ms cubic-bezier(0.215, 0.61, 0.355, 1); } -.emotion-12:hover { +.emotion-11:hover { color: rgba(0, 0, 0, 0.88)!important; } -.emotion-12:active { +.emotion-11:active { scale: 0.8; color: rgba(0, 0, 0, 0.88); } -.emotion-23 { - height: 24px; - padding-block: 2px; - margin-top: 4px; - margin-bottom: 4px; - color: rgba(0, 0, 0, 0.65); - background: rgba(0, 0, 0, 0.02); - border-color: transparent; -} - -.emotion-23:hover { - color: rgba(0, 0, 0, 0.88)!important; - background: rgba(0, 0, 0, 0.06)!important; - border-color: transparent!important; -} - -.emotion-23:focus { - color: rgba(0, 0, 0, 0.65); - background: rgba(0, 0, 0, 0.02); - border-color: transparent; - border-color: #1677ff!important; -} -
    > renders creatorButtonProps.tsx correctly 1`] = `
  • > renders creatorButtonProps.tsx correctly 1`] = ` aria-roledescription="sortable" class="studio-sortable-list-item emotion-4 studio-sortable-list-item-withHandle" data-cypress="draggable-item" - data-id="hello" + data-id="foo" data-index="0" role="button" style="background-color: rgb(255, 255, 255);" @@ -22716,13 +23125,13 @@ exports[` > renders creatorButtonProps.tsx correctly 1`] = ` class="layoutkit-flexbox emotion-8" style="padding-left: 4px;" > - hello + foo
  • -
    -
    -
    @@ -23845,10 +24194,10 @@ exports[` > renders provider.tsx correctly 1`] = `
    • @@ -24512,7 +24860,7 @@ exports[` > renders ref.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-9" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-5 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-6 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="index" data-index="0" @@ -24520,10 +24868,10 @@ exports[` > renders ref.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders ref.tsx correctly 1`] = `
    • @@ -24670,7 +25018,7 @@ exports[` > renders ref.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-9" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-5 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-6 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authName" data-index="1" @@ -24678,10 +25026,10 @@ exports[` > renders ref.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders ref.tsx correctly 1`] = `
    • @@ -24828,7 +25176,7 @@ exports[` > renders ref.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-9" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-5 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-6 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authedName" data-index="2" @@ -24836,10 +25184,10 @@ exports[` > renders ref.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders ref.tsx correctly 1`] = `
      > renders renderContent.tsx correctly 1`] = `
    • @@ -25396,7 +25743,7 @@ exports[` > renders renderContent.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-8" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-3 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-4 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authName" data-index="1" @@ -25404,10 +25751,10 @@ exports[` > renders renderContent.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders renderContent.tsx correctly 1`] = `
    • @@ -25554,7 +25901,7 @@ exports[` > renders renderContent.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-8" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-3 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-4 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authedName" data-index="2" @@ -25562,10 +25909,10 @@ exports[` > renders renderContent.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders renderContent.tsx correctly 1`] = `
      > renders useSortableList.tsx correctly 1`] = `
    • @@ -26683,7 +27029,7 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-6" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-3 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-4 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authName" data-index="1" @@ -26691,10 +27037,10 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders useSortableList.tsx correctly 1`] = `
    • @@ -26841,7 +27187,7 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` aria-describedby="DndDescribedBy-6" aria-disabled="false" aria-roledescription="sortable" - class="studio-sortable-list-item emotion-3 studio-sortable-list-item-withHandle" + class="studio-sortable-list-item emotion-4 studio-sortable-list-item-withHandle" data-cypress="draggable-item" data-id="authedName" data-index="2" @@ -26849,10 +27195,10 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
      > renders useSortableList.tsx correctly 1`] = `