diff --git a/src/SortableList/components/Item/style.ts b/src/SortableList/components/Item/style.ts index ef18d87a..f57f2052 100644 --- a/src/SortableList/components/Item/style.ts +++ b/src/SortableList/components/Item/style.ts @@ -68,10 +68,6 @@ export const useStyle = createStyles(({ css, cx, token }, prefixCls: string) => box-shadow: ${boxShadow}; } } - - &:hover .${prefixCls}-item-actions { - opacity: 1; - } `, ), disabled: cx( @@ -148,6 +144,10 @@ export const useStyle = createStyles(({ css, cx, token }, prefixCls: string) => height: 24px; border-radius: 2px; min-width: 48px; + + &:hover .${prefixCls}-item-actions { + opacity: 1; + } `, ), actionsRight: cx( diff --git a/src/SortableList/components/SortableItem.tsx b/src/SortableList/components/SortableItem.tsx index 88f87818..2eb6401d 100644 --- a/src/SortableList/components/SortableItem.tsx +++ b/src/SortableList/components/SortableItem.tsx @@ -2,7 +2,7 @@ import { useSortable } from '@dnd-kit/sortable'; import type { SortableItemProps } from '../type'; import Item from './Item'; -export default function SortableItem({ +export default function SortableItem({ disabled, id, index, @@ -15,7 +15,7 @@ export default function SortableItem({ actions, prefixCls, hideRemove = false, -}: SortableItemProps) { +}: SortableItemProps) { const { attributes, isDragging, diff --git a/src/SortableList/demos/getItemStyles.tsx b/src/SortableList/demos/getItemStyles.tsx index b4807a7f..e97e7bc5 100644 --- a/src/SortableList/demos/getItemStyles.tsx +++ b/src/SortableList/demos/getItemStyles.tsx @@ -19,10 +19,7 @@ const Demo = () => { onChange={setList} style={{ background: 'rgb(255,224,224)', padding: 24, borderRadius: 12 }} className={'custom-class'} - getItemStyles={({ isSorting, isDragging, isDragOverlay }) => { - // overlay 使用默认样式 - if (isDragOverlay) return; - + getItemStyles={({ isSorting, isDragging }) => { return { padding: 24, // 拖拽项修改背景色 diff --git a/src/SortableList/demos/renderContent.tsx b/src/SortableList/demos/renderContent.tsx index bd9ed2c7..320663f0 100644 --- a/src/SortableList/demos/renderContent.tsx +++ b/src/SortableList/demos/renderContent.tsx @@ -1,6 +1,6 @@ /** - * title: renderContent - * description: 提供 `renderContent()` 方法由用户自定义列表项,更加灵活。 + * title: 自定义列表项内容 + * description: 提供 `renderContent` 由用户自定义除拖拽等操作外的列表项内容。 */ import { SortableList } from '@ant-design/pro-editor'; import ItemRender from './_ItemRender'; diff --git a/src/SortableList/demos/renderItem.tsx b/src/SortableList/demos/renderItem.tsx index 72b28736..e7bb907f 100644 --- a/src/SortableList/demos/renderItem.tsx +++ b/src/SortableList/demos/renderItem.tsx @@ -1,3 +1,7 @@ +/** + * title: 自定义排序项 + * description: 通过 `renderItem` 可以自定义每个排序项,相比于 `renderContent` 提供的自由度更大 + */ import { SortableList, SortableListRef } from '@ant-design/pro-editor'; import { Badge, Button } from 'antd'; import { useTheme } from 'antd-style'; @@ -56,7 +60,7 @@ const Demo = () => { ref={ref} onChange={setList} getItemStyles={() => ({ padding: '16px' })} - renderItem={(item: Item, { index }) => { + renderItem={(item: Item, { index, listeners }) => { return ( @@ -110,6 +114,9 @@ const Demo = () => { > 删除 + ); diff --git a/src/SortableList/features/DragOverlay.tsx b/src/SortableList/features/DragOverlay.tsx index 4b83af43..83b6c0b6 100644 --- a/src/SortableList/features/DragOverlay.tsx +++ b/src/SortableList/features/DragOverlay.tsx @@ -15,6 +15,7 @@ const selector = (s: Store) => ({ activeId: s.activeId, hideRemove: s.hideRemove, renderItem: s.renderItem, + renderContent: s.renderContent, getItemStyles: s.getItemStyles, }); @@ -23,7 +24,10 @@ interface OverlayProps { } const Overlay: FC = ({ prefixCls }) => { - const { activeId, renderItem, hideRemove, getItemStyles } = useStore(selector, shallow); + const { activeId, renderItem, hideRemove, getItemStyles, renderContent } = useStore( + selector, + shallow, + ); const items = useStore((s) => s.value, isEqual); const activeIndex = getIndexOfActiveItem(items, activeId); @@ -44,6 +48,7 @@ const Overlay: FC = ({ prefixCls }) => { item={items[activeIndex]} prefixCls={prefixCls} renderItem={renderItem} + renderContent={renderContent} style={getItemStyles({ id: activeId, index: activeIndex, diff --git a/src/SortableList/index.md b/src/SortableList/index.md index 416074bf..3c66de64 100644 --- a/src/SortableList/index.md +++ b/src/SortableList/index.md @@ -20,6 +20,7 @@ demo: + ## 程序化控制 @@ -43,12 +44,100 @@ demo: | value | `T[]` | 值 | | initialValues | `T[]` | 初始值 | | onChange | `(value: T[], event: ListDataDispatchPayload) => void` | 值变化 | -| renderContent | `(item: T, index: number) => ReactNode` | 渲染内容区域 | -| renderItem | `(item: T, options) => ReactNode` | 自定义可排序容器 | +| renderContent | `(item: T, index: number) => ReactNode` | 自定义可排序列表项内容 | +| renderItem | `(item: T, options) => ReactNode` | 自定义可排序列表项 | +| getItemStyle | `(status: GetItemStylesArgs) => ReactNode` | 自定义容器样式 | | ref | `ForwardedRef>` | 对外部暴露方法 | | hideRemove | `boolean` | 是否隐藏删除按钮,默认为 false | | actions | `(item: T, index: number) => ReactNode[]` \| `React.ReactNode[]` | 除列表自带操作之外的其他操作自渲染 | +### GetItemStylesArgs + +`getItemStyle` 用于自定义可排序项的容器样式,其方法定义如下: + +```typescript +interface GetItemStylesArgs { + /** + * 当前列表项索引 + */ + index: number; + /** + * 是否在拖拽中 + */ + isDragging: boolean; + /** + * 当前列表项 ID + */ + id: UniqueIdentifier; + /** + * 是否在排序中 + */ + isSorting: boolean; + /** + * 拖拽覆盖的列表项索引 + */ + overIndex: number; + /** + * 是否是拖拽中的列表项 + */ + isDragOverlay: boolean; +} + +type GetItemStyles = (status: GetItemStylesArgs) => React.CSSProperties; +``` + +### RenderItem 参数 + +`renderItem` 方法用于更大自由度地定义列表项,包括拖拽,删除,添加,列表项内容等部分,其参数暴露如下: + +```typescript +export type RenderItem = ( + item: T, + options: { + /** + * 是否是被拖出的列表项 + */ + dragOverlay: boolean; + /** + * 是否在拖拽中 + */ + dragging: boolean; + /** + * 是否在排序中 + */ + sorting: boolean; + /** + * 当前列表项索引 + */ + index: number | undefined; + /** + * fade 动画 + */ + fadeIn: boolean; + /** + * 拖拽项监听器 + */ + listeners: DraggableSyntheticListeners; + /** + * ref + */ + ref: Ref; + /** + * 当面列表项传入样式 + */ + style: CSSProperties | undefined; + /** + * 当面列表项 transform 动画 + */ + transform: any; + /** + * 当面列表项 transition 动画 + */ + transition: any; + }, +) => ReactElement; +``` + ### SortableListDispatchPayload 组件通过 `onChange` 以及 `ForwardRef` 的方式暴露底层事件,你可以细粒度地控制列表的增删改查,移动,以及根据事件细粒度控制后续的行为链路。 diff --git a/src/SortableList/store/store.ts b/src/SortableList/store/store.ts index 815f822f..d56a2a74 100644 --- a/src/SortableList/store/store.ts +++ b/src/SortableList/store/store.ts @@ -11,10 +11,10 @@ interface Action { handleDragStart: (event: DragStartEvent) => void; handleDragEnd: (event: DragEndEvent) => void; handleDragCancel: () => void; - dispatchListData: (payload: SortableListDispatchPayload) => void; + dispatchListData: (payload: SortableListDispatchPayload) => void; } -export type Store = SortableListState & Action; +export type Store = SortableListState & Action; const vanillaStore: StateCreator = (set, get) => ({ ...initialState, @@ -41,7 +41,7 @@ const vanillaStore: StateCreator = (set, g // ===== 更新 listData 方法 ======= // dispatchListData: (payload) => { const { value, onChange } = get(); - const data = listDataReducer(value, payload) || []; + const data = listDataReducer(value, payload); if (data) { if (isEqual(value, data)) return; set({ value: data }); diff --git a/src/SortableList/type/component.ts b/src/SortableList/type/component.ts index 6a6c1836..f90c86ac 100644 --- a/src/SortableList/type/component.ts +++ b/src/SortableList/type/component.ts @@ -56,30 +56,75 @@ export type RenderContent = (item: T, index: number) => React. export type RenderItem = ( item: T, options: { + /** + * 是否是被拖出的列表项 + */ dragOverlay: boolean; + /** + * 是否在拖拽中 + */ dragging: boolean; + /** + * 是否在排序中 + */ sorting: boolean; + /** + * 当前列表项索引 + */ index: number | undefined; + /** + * fade 动画 + */ fadeIn: boolean; + /** + * 拖拽项监听器 + */ listeners: DraggableSyntheticListeners; + /** + * ref + */ ref: Ref; + /** + * 当面列表项传入样式 + */ style: CSSProperties | undefined; + /** + * 当面列表项 transform 动画 + */ transform: any; + /** + * 当面列表项 transition 动画 + */ transition: any; }, ) => ReactElement; export type { UniqueIdentifier }; -interface GetWrapperStyleArgs { +interface GetItemStylesArgs { + /** + * 当前列表项索引 + */ index: number; + /** + * 是否在拖拽中 + */ isDragging: boolean; + /** + * 当前列表项 ID + */ id: UniqueIdentifier; -} - -interface GetItemStylesArgs extends GetWrapperStyleArgs { + /** + * 是否在排序中 + */ isSorting: boolean; + /** + * 拖拽覆盖的列表项索引 + */ overIndex: number; + /** + * 是否是拖拽中的列表项 + */ isDragOverlay: boolean; }