mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-02-21 10:04:44 +08:00
fix: drag providers caused crash (#8906)
* feat(ProviderSettings): 在搜索时禁用列表拖拽功能 当搜索文本不为空时,禁用可拖拽列表的拖拽功能,避免用户在搜索时意外拖动项目 * fix(DraggableList): 修复拖拽列表项在禁用状态下的光标样式 * style(ProviderSettings): 移除列表项的cursor: grab样式 * style(ProviderSettings): 禁止用户选择列表项文本 * fix(ProviderSettings): 为ProviderLogo添加draggable="false"属性防止拖动 * test(DraggableVirtualList): 更新快照测试添加抓取光标样式
This commit is contained in:
parent
ea890c41af
commit
4ce1218d6f
@ -48,6 +48,7 @@ interface DraggableVirtualListProps<T> {
|
||||
overscan?: number
|
||||
header?: React.ReactNode
|
||||
children: (item: T, index: number) => React.ReactNode
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +74,8 @@ function DraggableVirtualList<T>({
|
||||
estimateSize: _estimateSize,
|
||||
overscan = 5,
|
||||
header,
|
||||
children
|
||||
children,
|
||||
disabled
|
||||
}: DraggableVirtualListProps<T>): React.ReactElement {
|
||||
const _onDragEnd = (result: DropResult, provided: ResponderProvided) => {
|
||||
onDragEnd?.(result, provided)
|
||||
@ -157,6 +159,7 @@ function DraggableVirtualList<T>({
|
||||
itemContainerStyle={itemContainerStyle}
|
||||
virtualizer={virtualizer}
|
||||
children={children}
|
||||
disabled={disabled}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@ -172,53 +175,59 @@ function DraggableVirtualList<T>({
|
||||
/**
|
||||
* 渲染单个可拖拽的虚拟列表项,高度为动态测量
|
||||
*/
|
||||
const VirtualRow = memo(({ virtualItem, list, children, itemStyle, itemContainerStyle, virtualizer }: any) => {
|
||||
const item = list[virtualItem.index]
|
||||
const draggableId = String(virtualItem.key)
|
||||
return (
|
||||
<Draggable
|
||||
key={`draggable_${draggableId}_${virtualItem.index}`}
|
||||
draggableId={draggableId}
|
||||
index={virtualItem.index}>
|
||||
{(provided) => {
|
||||
const setDragRefs = (el: HTMLElement | null) => {
|
||||
provided.innerRef(el)
|
||||
virtualizer.measureElement(el)
|
||||
}
|
||||
const VirtualRow = memo(
|
||||
({ virtualItem, list, children, itemStyle, itemContainerStyle, virtualizer, disabled }: any) => {
|
||||
const item = list[virtualItem.index]
|
||||
const draggableId = String(virtualItem.key)
|
||||
return (
|
||||
<Draggable
|
||||
key={`draggable_${draggableId}_${virtualItem.index}`}
|
||||
draggableId={draggableId}
|
||||
isDragDisabled={disabled}
|
||||
index={virtualItem.index}>
|
||||
{(provided) => {
|
||||
const setDragRefs = (el: HTMLElement | null) => {
|
||||
provided.innerRef(el)
|
||||
virtualizer.measureElement(el)
|
||||
}
|
||||
|
||||
const dndStyle = provided.draggableProps.style
|
||||
const virtualizerTransform = `translateY(${virtualItem.start}px)`
|
||||
const dndStyle = provided.draggableProps.style
|
||||
const virtualizerTransform = `translateY(${virtualItem.start}px)`
|
||||
|
||||
// dnd 的 transform 负责拖拽时的位移和让位动画,
|
||||
// virtualizer 的 translateY 负责将项定位到虚拟列表的正确位置,
|
||||
// 它们拼接起来可以同时实现拖拽视觉效果和虚拟化定位。
|
||||
const combinedTransform = dndStyle?.transform
|
||||
? `${dndStyle.transform} ${virtualizerTransform}`
|
||||
: virtualizerTransform
|
||||
// dnd 的 transform 负责拖拽时的位移和让位动画,
|
||||
// virtualizer 的 translateY 负责将项定位到虚拟列表的正确位置,
|
||||
// 它们拼接起来可以同时实现拖拽视觉效果和虚拟化定位。
|
||||
const combinedTransform = dndStyle?.transform
|
||||
? `${dndStyle.transform} ${virtualizerTransform}`
|
||||
: virtualizerTransform
|
||||
|
||||
return (
|
||||
<div
|
||||
{...provided.draggableProps}
|
||||
ref={setDragRefs}
|
||||
className="draggable-item"
|
||||
data-index={virtualItem.index}
|
||||
style={{
|
||||
...itemContainerStyle,
|
||||
...dndStyle,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
transform: combinedTransform
|
||||
}}>
|
||||
<div {...provided.dragHandleProps} className="draggable-content" style={{ ...itemStyle }}>
|
||||
{item && children(item, virtualItem.index)}
|
||||
return (
|
||||
<div
|
||||
{...provided.draggableProps}
|
||||
ref={setDragRefs}
|
||||
className="draggable-item"
|
||||
data-index={virtualItem.index}
|
||||
style={{
|
||||
...itemContainerStyle,
|
||||
...dndStyle,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
transform: combinedTransform
|
||||
}}>
|
||||
<div
|
||||
{...provided.dragHandleProps}
|
||||
className="draggable-content"
|
||||
style={{ ...itemStyle, cursor: disabled ? 'pointer' : 'grab' }}>
|
||||
{item && children(item, virtualItem.index)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Draggable>
|
||||
)
|
||||
})
|
||||
)
|
||||
}}
|
||||
</Draggable>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default DraggableVirtualList
|
||||
|
||||
@ -38,7 +38,7 @@ exports[`DraggableVirtualList > snapshot > should match snapshot with custom sty
|
||||
>
|
||||
<div
|
||||
class="draggable-content"
|
||||
style="background: blue;"
|
||||
style="background: blue; cursor: grab;"
|
||||
>
|
||||
<div>
|
||||
Item A
|
||||
@ -56,7 +56,7 @@ exports[`DraggableVirtualList > snapshot > should match snapshot with custom sty
|
||||
>
|
||||
<div
|
||||
class="draggable-content"
|
||||
style="background: blue;"
|
||||
style="background: blue; cursor: grab;"
|
||||
>
|
||||
<div>
|
||||
Item B
|
||||
@ -74,7 +74,7 @@ exports[`DraggableVirtualList > snapshot > should match snapshot with custom sty
|
||||
>
|
||||
<div
|
||||
class="draggable-content"
|
||||
style="background: blue;"
|
||||
style="background: blue; cursor: grab;"
|
||||
>
|
||||
<div>
|
||||
Item C
|
||||
|
||||
@ -413,12 +413,12 @@ const ProvidersList: FC = () => {
|
||||
const getProviderAvatar = (provider: Provider) => {
|
||||
const logoSrc = getProviderLogo(provider.id)
|
||||
if (logoSrc) {
|
||||
return <ProviderLogo shape="circle" src={logoSrc} size={25} />
|
||||
return <ProviderLogo draggable="false" shape="circle" src={logoSrc} size={25} />
|
||||
}
|
||||
|
||||
const customLogo = providerLogos[provider.id]
|
||||
if (customLogo) {
|
||||
return <ProviderLogo shape="square" src={customLogo} size={25} />
|
||||
return <ProviderLogo draggable="false" shape="square" src={customLogo} size={25} />
|
||||
}
|
||||
|
||||
return (
|
||||
@ -464,6 +464,7 @@ const ProvidersList: FC = () => {
|
||||
onDragStart={() => setDragging(true)}
|
||||
estimateSize={useCallback(() => 40, [])}
|
||||
overscan={3}
|
||||
disabled={searchText !== ''}
|
||||
style={{
|
||||
height: `calc(100% - 2 * ${BUTTON_WRAPPER_HEIGHT}px)`
|
||||
}}
|
||||
@ -525,11 +526,11 @@ const ProviderListItem = styled.div`
|
||||
align-items: center;
|
||||
padding: 5px 10px;
|
||||
width: 100%;
|
||||
cursor: grab;
|
||||
border-radius: var(--list-item-border-radius);
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: 0.5px solid transparent;
|
||||
user-select: none;
|
||||
&:hover {
|
||||
background: var(--color-background-soft);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user