|
|
|
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types'; |
|
import type { SystemStyleObject } from '@invoke-ai/ui-library'; |
|
import { Box } from '@invoke-ai/ui-library'; |
|
import type { DndListTargetState } from 'features/dnd/types'; |
|
|
|
|
|
|
|
|
|
const line = { |
|
thickness: 2, |
|
backgroundColor: 'base.500', |
|
}; |
|
|
|
type DropIndicatorProps = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
edge: Edge; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gap?: string; |
|
}; |
|
|
|
const lineStyles: SystemStyleObject = { |
|
display: 'block', |
|
position: 'absolute', |
|
zIndex: 1, |
|
borderRadius: 'full', |
|
|
|
|
|
pointerEvents: 'none', |
|
background: line.backgroundColor, |
|
}; |
|
|
|
type Orientation = 'horizontal' | 'vertical'; |
|
|
|
const orientationStyles: Record<Orientation, SystemStyleObject> = { |
|
horizontal: { |
|
height: `${line.thickness}px`, |
|
left: 2, |
|
right: 2, |
|
}, |
|
vertical: { |
|
width: `${line.thickness}px`, |
|
top: 2, |
|
bottom: 2, |
|
}, |
|
}; |
|
|
|
const edgeToOrientationMap: Record<Edge, Orientation> = { |
|
top: 'horizontal', |
|
bottom: 'horizontal', |
|
left: 'vertical', |
|
right: 'vertical', |
|
}; |
|
|
|
const edgeStyles: Record<Edge, SystemStyleObject> = { |
|
top: { |
|
top: 'var(--local-line-offset)', |
|
}, |
|
right: { |
|
right: 'var(--local-line-offset)', |
|
}, |
|
bottom: { |
|
bottom: 'var(--local-line-offset)', |
|
}, |
|
left: { |
|
left: 'var(--local-line-offset)', |
|
}, |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
function DndDropIndicatorInternal({ edge, gap = '0px' }: DropIndicatorProps) { |
|
|
|
|
|
|
|
|
|
const lineOffset = `calc(-0.5 * (${gap} + ${line.thickness}px))`; |
|
|
|
const orientation = edgeToOrientationMap[edge]; |
|
|
|
return ( |
|
<Box |
|
sx={{ ...lineStyles, ...orientationStyles[orientation], ...edgeStyles[edge], '--local-line-offset': lineOffset }} |
|
/> |
|
); |
|
} |
|
|
|
export const DndListDropIndicator = ({ dndState }: { dndState: DndListTargetState }) => { |
|
if (dndState.type !== 'is-dragging-over') { |
|
return null; |
|
} |
|
|
|
if (!dndState.closestEdge) { |
|
return null; |
|
} |
|
|
|
return ( |
|
<DndDropIndicatorInternal |
|
edge={dndState.closestEdge} |
|
// This is the gap between items in the list, used to calculate the position of the drop indicator |
|
gap="var(--invoke-space-2)" |
|
/> |
|
); |
|
}; |
|
|