Show content being reordered as user moves around

This commit is contained in:
Sergio Padrino 2023-10-25 18:38:58 +02:00
parent 2afbe53f02
commit d865e8c442
4 changed files with 104 additions and 2 deletions

View file

@ -14,6 +14,11 @@ interface ICommitDragElementProps {
readonly commit: Commit
readonly selectedCommits: ReadonlyArray<Commit>
readonly gitHubRepository: GitHubRepository | null
/**
* Whether or not this is shown for a keyboard-based insertion (like reordering
* commits). Optional. Default: false
*/
readonly isKeyboardInsertion?: boolean
readonly emoji: Map<string, string>
}
@ -168,7 +173,10 @@ export class CommitDragElement extends React.Component<
const { commit, gitHubRepository, selectedCommits, emoji } = this.props
const count = selectedCommits.length
const className = classNames({ 'multiple-selected': count > 1 })
const className = classNames({
'multiple-selected': count > 1,
'keyboard-insertion': this.props.isKeyboardInsertion ?? false,
})
return (
<div id="commit-drag-element" className={className}>
<div className="commit-box">

View file

@ -16,6 +16,8 @@ import {
import { getDotComAPIEndpoint } from '../../lib/api'
import { clipboard } from 'electron'
import { RowIndexPath } from '../lib/list/list-row-index-path'
import { assertNever } from '../../lib/fatal-error'
import { CommitDragElement } from '../drag-elements/commit-drag-element'
const RowHeight = 50
@ -438,6 +440,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
selectionMode="multi"
onScroll={this.onScroll}
keyboardInsertionData={this.props.keyboardReorderData}
keyboardInsertionElementRenderer={this.renderKeyboardInsertionElement}
insertionDragType={
reorderingEnabled === true &&
isMultiCommitOperationInProgress === false
@ -458,6 +461,32 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
)
}
private renderKeyboardInsertionElement = (
data: DragData
): JSX.Element | null => {
const { emoji, gitHubRepository } = this.props
const { commits } = data
if (commits.length === 0) {
return null
}
switch (data.type) {
case DragType.Commit:
return (
<CommitDragElement
gitHubRepository={gitHubRepository}
commit={commits[0]}
selectedCommits={commits}
isKeyboardInsertion={true}
emoji={emoji}
/>
)
default:
return assertNever(data.type, `Unknown drag element type: ${data}`)
}
}
private onRowContextMenu = (
row: number,
event: React.MouseEvent<HTMLDivElement>

View file

@ -294,6 +294,10 @@ interface IListProps {
*/
readonly getRowAriaLabel?: (row: number) => string | undefined
readonly keyboardInsertionElementRenderer?: (
data: DragData
) => JSX.Element | null
readonly onCancelKeyboardInsertion?: () => void
readonly onConfirmKeyboardInsertion?: (
indexPath: RowIndexPath,
@ -334,6 +338,9 @@ export class List extends React.Component<IListProps, IListState> {
private readonly rowRefs = new Map<number, HTMLDivElement>()
private readonly keyboardInsertionElementRef =
React.createRef<HTMLDivElement>()
/**
* The style prop for our child Grid. We keep this here in order
* to not create a new object on each render and thus forcing
@ -1010,6 +1017,13 @@ export class List extends React.Component<IListProps, IListState> {
: { section: 0, row: 0 },
})
}
if (
prevState.keyboardInsertionIndexPath !==
this.state.keyboardInsertionIndexPath
) {
this.updateKeyboardInsertionElementPosition()
}
}
public componentWillMount() {
@ -1183,10 +1197,56 @@ export class List extends React.Component<IListProps, IListState> {
aria-label={this.props.ariaLabel}
>
{content}
{this.renderKeyboardInsertionElement()}
</div>
)
}
private renderKeyboardInsertionElement = () => {
if (
!this.props.keyboardInsertionData ||
!this.state.keyboardInsertionIndexPath
) {
return null
}
return (
<div
style={{
position: 'fixed',
zIndex: 1000,
top: 0,
left: 0,
}}
ref={this.keyboardInsertionElementRef}
>
{this.props.keyboardInsertionElementRenderer?.(
this.props.keyboardInsertionData
)}
</div>
)
}
private updateKeyboardInsertionElementPosition = () => {
const { keyboardInsertionData } = this.props
const { keyboardInsertionIndexPath } = this.state
const element = this.keyboardInsertionElementRef.current
if (!keyboardInsertionData || !keyboardInsertionIndexPath || !element) {
return
}
const rowElement = this.rowRefs.get(keyboardInsertionIndexPath.row)
if (!rowElement) {
return
}
const rowRect = rowElement.getBoundingClientRect()
element.style.top = `${rowRect.top}px`
element.style.left = `${rowRect.right + 20}px`
}
/**
* Renders the react-virtualized Grid component and optionally
* a fake scroll bar component if running on Windows.
@ -1568,6 +1628,8 @@ export class List extends React.Component<IListProps, IListState> {
this.fakeScroll.scrollTop = scrollTop
}
this.updateKeyboardInsertionElementPosition()
}
/**

View file

@ -32,7 +32,6 @@
font-size: 11px;
position: absolute;
top: -22px;
left: 20px;
display: flex;
align-items: center;
justify-content: center;
@ -41,6 +40,10 @@
}
}
&:not(.keyboard-insertion) .commit-box .count {
left: 20px;
}
.tool-tip-contents {
position: absolute;
bottom: -35px;