Files
timeline-frontend/src/pages/story/components/SortableTimelineGridItem.tsx

160 lines
4.1 KiB
TypeScript
Raw Normal View History

/**
* SortableTimelineGridItem - 线
*
*
* TimelineGridItem
* 使 dnd-kit useSortable Hook
*
*
* 1. 使 useSortable Hook
* 2. CSS transform
* 3.
* 4.
*
* @author Timeline Team
* @date 2024
*/
import { StoryItem } from '@/pages/story/data';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { DragOutlined } from '@ant-design/icons';
import React, { memo, CSSProperties } from 'react';
import TimelineGridItem from './TimelineGridItem';
/**
*
* @property item - 线
* @property disabled -
* @property handleOption -
* @property onOpenDetail -
* @property refresh -
* @property disableEdit -
*/
interface SortableTimelineGridItemProps {
item: StoryItem;
disabled?: boolean;
handleOption: (item: StoryItem, option: 'add' | 'edit' | 'addSubItem' | 'editSubItem') => void;
onOpenDetail: (item: StoryItem) => void;
refresh: () => void;
disableEdit?: boolean;
}
/**
* SortableTimelineGridItem
* 线
*/
const SortableTimelineGridItem: React.FC<SortableTimelineGridItemProps> = memo(({
item,
disabled = false,
handleOption,
onOpenDetail,
refresh,
disableEdit = false,
}) => {
/**
* useSortable Hook
* - attributes: 可访问性属性 tabindex
* - listeners: 拖拽事件监听器
* - setNodeRef: 设置 DOM
* - transform: CSS transform
* - transition: CSS transition
* - isDragging: 是否正在拖拽
*/
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging,
} = useSortable({
id: item.instanceId,
disabled: disabled,
data: {
type: 'timeline-item',
item,
},
});
/**
*
* - transform: 应用拖拽位移和缩放
* - transition: 平滑过渡动画
* - opacity: 拖拽时降低透明度
* - zIndex: 拖拽时提升层级
*/
const style: CSSProperties = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
zIndex: isDragging ? 1000 : 'auto',
position: 'relative' as const,
};
return (
<div
ref={setNodeRef}
style={style}
className="sortable-timeline-item-wrapper"
>
{/* 拖拽手柄 - 仅在非禁用状态显示 */}
{!disabled && !disableEdit && (
<div
className="drag-handle"
{...attributes}
{...listeners}
style={{
position: 'absolute',
top: 8,
left: 8,
zIndex: 20,
cursor: 'grab',
padding: '4px 8px',
background: 'rgba(0, 0, 0, 0.6)',
borderRadius: 4,
opacity: 0,
transition: 'opacity 0.2s ease',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
onClick={(e) => e.stopPropagation()}
>
<DragOutlined style={{ color: '#fff', fontSize: 14 }} />
</div>
)}
{/* 原有组件 */}
<TimelineGridItem
item={item}
handleOption={handleOption}
onOpenDetail={onOpenDetail}
refresh={refresh}
disableEdit={disableEdit}
/>
{/* 拖拽时的视觉反馈 */}
{isDragging && (
<div
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
border: '2px dashed #1890ff',
borderRadius: 8,
pointerEvents: 'none',
background: 'rgba(24, 144, 255, 0.1)',
}}
/>
)}
</div>
);
});
SortableTimelineGridItem.displayName = 'SortableTimelineGridItem';
export default SortableTimelineGridItem;