diff --git a/src/ColumnList/ColumnItem.tsx b/src/ColumnList/ColumnItem.tsx index 3a968457..b5a4f917 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, 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/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/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/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..60a86a10 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'; diff --git a/src/SortableList/demos/useSortableList.tsx b/src/SortableList/demos/useSortableList.tsx index 67879322..6ba55a21 100644 --- a/src/SortableList/demos/useSortableList.tsx +++ b/src/SortableList/demos/useSortableList.tsx @@ -1,18 +1,21 @@ /** * title: useSortableList * description: 在 Item 子组件中使用 `useSortableList()` hook,可以获得当前组件实例 + * compact: true */ import { SortableList } from '@ant-design/pro-editor'; +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'; export default () => { const [listData, setListData] = useState(INIT_VALUES); + const token = useTheme(); return ( -
+ value={listData} onChange={(data) => { @@ -21,6 +24,6 @@ export default () => { }} renderContent={(item, index) => } /> -
+ ); }; diff --git a/src/SortableList/features/DragOverlay.tsx b/src/SortableList/features/DragOverlay.tsx index 83b6c0b6..2bd4c32f 100644 --- a/src/SortableList/features/DragOverlay.tsx +++ b/src/SortableList/features/DragOverlay.tsx @@ -45,6 +45,7 @@ const Overlay: FC = ({ prefixCls }) => { UniqueIdentifier; + /** + * 根据索引获取 id + * @param index + * @returns + */ + getIdByIndex: (index: number) => UniqueIdentifier; /** * 获取当前树的数据 * @returns 当前树的数据 @@ -42,6 +48,10 @@ export const useSortableList = (): SortableListInstance => { const storeApi = useStoreApi(); const getActiveId = useMemoizedFn(() => storeApi.getState().activeId); + const getIdByIndex = useMemoizedFn((index?: number) => { + const indexId = storeApi.getState().value?.[index]?.id || null; + return indexId; + }); const getValue = useMemoizedFn(() => storeApi.getState().value); const addItem = (item?: SortableItem, index?: number) => storeApi.getState().dispatchListData({ type: 'addItem', item, index }); @@ -55,6 +65,7 @@ export const useSortableList = (): SortableListInstance => { getValue, addItem, removeItem, + getIdByIndex, updateItem, }; }; diff --git a/src/SortableList/index.md b/src/SortableList/index.md index 92a6da27..ce717d3d 100644 --- a/src/SortableList/index.md +++ b/src/SortableList/index.md @@ -14,7 +14,7 @@ demo: 针对可排序列表场景提供基础底层封装,可在其上进行进一步自定义,参考 `ColumnList`。 -## 基础使用 +## 使用方式 @@ -22,18 +22,8 @@ demo: - -## 程序化控制 - -使用 `ref` 或者 `useSortableList()` hook 均可获取组件实例,进而自行控制状态变更。 - - -### Provider - -为了方便用户在更高的上下文中通过 `useSortableList()` hook 获得组件实例,我们提供了 `SortableListProvider` 由用户控制 Provider 的作用范围。 - ## API diff --git a/tests/__snapshots__/demo.test.tsx.snap b/tests/__snapshots__/demo.test.tsx.snap index 8f10b33f..005a8d53 100644 --- a/tests/__snapshots__/demo.test.tsx.snap +++ b/tests/__snapshots__/demo.test.tsx.snap @@ -2682,7 +2682,7 @@ exports[` > renders actions.tsx correctly 1`] = ` > > renders actions.tsx correctly 1`] = ` > > renders actions.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders column.tsx correctly 1`] = ` > > renders controlled.tsx correctly 1`] = ` > > renders controlled.tsx correctly 1`] = ` > > renders controlled.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders creatorButtonProps.tsx correctly 1`] = ` > > renders normal.tsx correctly 1`] = ` > > renders normal.tsx correctly 1`] = ` /> > renders normal.tsx correctly 1`] = ` > > renders normal.tsx correctly 1`] = ` /> > renders normal.tsx correctly 1`] = ` > > renders normal.tsx correctly 1`] = ` /> > renders Basic.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; @@ -21774,11 +21761,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); } @@ -21842,10 +21829,10 @@ exports[` > renders Basic.tsx correctly 1`] = ` hello
-
-
@@ -23845,10 +23780,10 @@ exports[` > renders provider.tsx correctly 1`] = `
  • @@ -24512,7 +24446,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 +24454,10 @@ exports[` > renders ref.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
    > renders ref.tsx correctly 1`] = `
  • @@ -24670,7 +24604,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 +24612,10 @@ exports[` > renders ref.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
    > renders ref.tsx correctly 1`] = `
  • @@ -24828,7 +24762,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 +24770,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 +25329,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 +25337,10 @@ exports[` > renders renderContent.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
    > renders renderContent.tsx correctly 1`] = `
  • @@ -25554,7 +25487,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 +25495,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 +26615,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 +26623,10 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
    > renders useSortableList.tsx correctly 1`] = `
  • @@ -26841,7 +26773,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 +26781,10 @@ exports[` > renders useSortableList.tsx correctly 1`] = ` style="background-color: rgb(255, 255, 255);" >
    > renders useSortableList.tsx correctly 1`] = `