From 0bb1c45ce27e864c5314ccd7b8c1a0bc1f974fa8 Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:42:47 -0500 Subject: [PATCH 1/7] Add on double click back --- app/src/ui/changes/filter-changes-list.tsx | 9 +++------ app/src/ui/lib/augmented-filter-list.tsx | 13 +++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index 11bf498ca48..0b7e9032175 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -1009,11 +1009,8 @@ export class FilterChangesList extends React.Component< ) } - // TBD: make private - public onRowDoubleClick = (row: number) => { - const file = this.props.workingDirectory.files[row] - - this.props.onOpenItemInExternalEditor(file.path) + private onChangedFileDoubleClick = (item: IChangesListItem) => { + this.props.onOpenItemInExternalEditor(item.change.path) } // TBD: make private @@ -1117,8 +1114,8 @@ export class FilterChangesList extends React.Component< selectedItem={this.state.selectedItem} renderItem={this.renderChangedFile} onItemClick={this.onChangedFileClick} + onItemDoubleClick={this.onChangedFileDoubleClick} // selectionMode="multi"... - // onRowDoubleClick={this.onRowDoubleClick} // onRowKeyboardFocus={this.onRowFocus} // onRowBlur={this.onRowBlur} // onScroll={this.onScroll} diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index 7fb6f84e30e..982a3b3807f 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -84,6 +84,8 @@ interface IAugmentedSectionFilterListProps { */ readonly onItemClick?: (item: T, source: ClickSource) => void + readonly onItemDoubleClick?: (item: T, source: ClickSource) => void + /** * This function will be called when the selection changes as a result of a * user keyboard or mouse action (i.e. not when props change). This function @@ -376,6 +378,7 @@ export class AugmentedSectionFilterList< } onSelectedRowChanged={this.onSelectedRowChanged} onRowClick={this.onRowClick} + onRowDoubleClick={this.onRowDoubleClick} onRowKeyDown={this.onRowKeyDown} onRowContextMenu={this.onRowContextMenu} canSelectRow={this.canSelectRow} @@ -483,6 +486,16 @@ export class AugmentedSectionFilterList< } } + private onRowDoubleClick = (index: RowIndexPath, source: ClickSource) => { + if (this.props.onItemDoubleClick) { + const row = this.state.rows[index.section][index.row] + + if (row.kind === 'item') { + this.props.onItemDoubleClick(row.item, source) + } + } + } + private onRowContextMenu = ( index: RowIndexPath, source: React.MouseEvent From 16fb1021cad41042dc6561ed620bdc4cf4e5177b Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:47:06 -0500 Subject: [PATCH 2/7] Finish on context menu wire up --- app/src/ui/changes/filter-changes-list.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index 0b7e9032175..d7eeb54f6b6 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -769,12 +769,10 @@ export class FilterChangesList extends React.Component< } private onItemContextMenu = ( - item: any, + item: IChangesListItem, event: React.MouseEvent ) => { - const row = 0 /// TBD; - const { workingDirectory } = this.props - const file = workingDirectory.files[row] + const file = item.change if (this.props.isCommitting) { return From 14f242d359491204d6b8bd19f39831d08f9896e8 Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:52:55 -0500 Subject: [PATCH 3/7] Add row keyboard function callback --- app/src/ui/changes/filter-changes-list.tsx | 5 ++--- app/src/ui/lib/augmented-filter-list.tsx | 24 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index d7eeb54f6b6..2eb648fafc7 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -1113,8 +1113,8 @@ export class FilterChangesList extends React.Component< renderItem={this.renderChangedFile} onItemClick={this.onChangedFileClick} onItemDoubleClick={this.onChangedFileDoubleClick} + onItemKeyboardFocus={this.onChangedFileFocus} // selectionMode="multi"... - // onRowKeyboardFocus={this.onRowFocus} // onRowBlur={this.onRowBlur} // onScroll={this.onScroll} // setScrollTop={this.props.changesListScrollTop} @@ -1136,8 +1136,7 @@ export class FilterChangesList extends React.Component< ) } - // TBD: Needs private once hooked into list - public onRowFocus = (changeListItem: IChangesListItem) => { + private onChangedFileFocus = (changeListItem: IChangesListItem) => { this.setState({ focusedRow: changeListItem.id }) } diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index 982a3b3807f..540559520dd 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -170,6 +170,12 @@ interface IAugmentedSectionFilterListProps { item: T, event: React.MouseEvent ) => void + + /** This function will be called only when an item obtains focus via keyboard */ + readonly onItemKeyboardFocus?: ( + item: T, + event: React.KeyboardEvent + ) => void } interface IAugmentedSectionFilterListState { @@ -381,6 +387,7 @@ export class AugmentedSectionFilterList< onRowDoubleClick={this.onRowDoubleClick} onRowKeyDown={this.onRowKeyDown} onRowContextMenu={this.onRowContextMenu} + onRowKeyboardFocus={this.onRowKeyboardFocus} canSelectRow={this.canSelectRow} invalidationProps={{ ...this.props, @@ -513,6 +520,23 @@ export class AugmentedSectionFilterList< this.props.onItemContextMenu(row.item, source) } + private onRowKeyboardFocus = ( + index: RowIndexPath, + source: React.KeyboardEvent + ) => { + if (!this.props.onItemKeyboardFocus) { + return + } + + const row = this.state.rows[index.section][index.row] + + if (row.kind !== 'item') { + return + } + + this.props.onItemKeyboardFocus(row.item, source) + } + private onRowKeyDown = ( indexPath: RowIndexPath, event: React.KeyboardEvent From 0b199ea7baff6c2002f9e0212486b645d154d116 Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:05:47 -0500 Subject: [PATCH 4/7] Wire up on blur --- app/src/ui/changes/filter-changes-list.tsx | 12 +++++------ app/src/ui/lib/augmented-filter-list.tsx | 24 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index 2eb648fafc7..384f01d1e99 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -1011,9 +1011,8 @@ export class FilterChangesList extends React.Component< this.props.onOpenItemInExternalEditor(item.change.path) } - // TBD: make private - public onRowKeyDown = ( - _row: number, + private onItemKeyDown = ( + _item: IChangesListItem, event: React.KeyboardEvent ) => { // The commit is already in-flight but this check prevents the @@ -1110,12 +1109,12 @@ export class FilterChangesList extends React.Component< filterText={this.state.filterText} onFilterTextChanged={this.onFilterTextChanged} selectedItem={this.state.selectedItem} + // selectionMode="multi"... renderItem={this.renderChangedFile} onItemClick={this.onChangedFileClick} onItemDoubleClick={this.onChangedFileDoubleClick} onItemKeyboardFocus={this.onChangedFileFocus} - // selectionMode="multi"... - // onRowBlur={this.onRowBlur} + onItemBlur={this.onChangedFileBlur} // onScroll={this.onScroll} // setScrollTop={this.props.changesListScrollTop} // onRowKeyDown={this.onRowKeyDown} @@ -1140,8 +1139,7 @@ export class FilterChangesList extends React.Component< this.setState({ focusedRow: changeListItem.id }) } - // TBD: Needs private once hooked into list - public onRowBlur = (changeListItem: IChangesListItem) => { + private onChangedFileBlur = (changeListItem: IChangesListItem) => { if (this.state.focusedRow === changeListItem.id) { this.setState({ focusedRow: null }) } diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index 540559520dd..6cbc281d6c0 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -176,6 +176,12 @@ interface IAugmentedSectionFilterListProps { item: T, event: React.KeyboardEvent ) => void + + /** This function will be called when a row loses focus */ + readonly onItemBlur?: ( + item: T, + event: React.FocusEvent + ) => void } interface IAugmentedSectionFilterListState { @@ -388,6 +394,7 @@ export class AugmentedSectionFilterList< onRowKeyDown={this.onRowKeyDown} onRowContextMenu={this.onRowContextMenu} onRowKeyboardFocus={this.onRowKeyboardFocus} + onRowBlur={this.onRowBlur} canSelectRow={this.canSelectRow} invalidationProps={{ ...this.props, @@ -537,6 +544,23 @@ export class AugmentedSectionFilterList< this.props.onItemKeyboardFocus(row.item, source) } + private onRowBlur = ( + index: RowIndexPath, + source: React.FocusEvent + ) => { + if (!this.props.onItemBlur) { + return + } + + const row = this.state.rows[index.section][index.row] + + if (row.kind !== 'item') { + return + } + + this.props.onItemBlur(row.item, source) + } + private onRowKeyDown = ( indexPath: RowIndexPath, event: React.KeyboardEvent From 9df0590d04e13752fffdabefbd3ed2c64a78f116 Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:06:13 -0500 Subject: [PATCH 5/7] Wire up on key down on item --- app/src/ui/changes/filter-changes-list.tsx | 4 ++-- app/src/ui/lib/augmented-filter-list.tsx | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index 384f01d1e99..ed466de7c93 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -1117,9 +1117,9 @@ export class FilterChangesList extends React.Component< onItemBlur={this.onChangedFileBlur} // onScroll={this.onScroll} // setScrollTop={this.props.changesListScrollTop} - // onRowKeyDown={this.onRowKeyDown} + onItemKeyDown={this.onItemKeyDown} onSelectionChanged={this.onFileSelectionChanged} - groups={this.state.groups} // + groups={this.state.groups} invalidationProps={{ workingDirectory: workingDirectory, isCommitting: isCommitting, diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index 6cbc281d6c0..c392ec99d4d 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -182,6 +182,8 @@ interface IAugmentedSectionFilterListProps { item: T, event: React.FocusEvent ) => void + + readonly onItemKeyDown?: (item: T, event: React.KeyboardEvent) => void } interface IAugmentedSectionFilterListState { @@ -565,6 +567,16 @@ export class AugmentedSectionFilterList< indexPath: RowIndexPath, event: React.KeyboardEvent ) => { + const row = this.state.rows[indexPath.section][indexPath.row] + + if (row.kind === 'item' && this.props.onItemKeyDown) { + this.props.onItemKeyDown(row.item, event) + } + + if (event.defaultPrevented) { + return + } + const list = this.list if (!list) { return From 8010751aa43dd7da0496acf1ecc432b80f47b45b Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:24:20 -0500 Subject: [PATCH 6/7] Add scroll callbacks --- app/src/ui/changes/filter-changes-list.tsx | 9 ++++----- app/src/ui/lib/augmented-filter-list.tsx | 10 ++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index ed466de7c93..bc280e99f39 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -154,7 +154,7 @@ interface IFilterChangesListProps { readonly onChangesListScrolled: (scrollTop: number) => void /* The scrollTop of the compareList. It is stored to allow for scroll position persistence */ - // TBD: readonly changesListScrollTop?: number + readonly changesListScrollTop?: number /** * Called to open a file in its default application @@ -814,8 +814,7 @@ export class FilterChangesList extends React.Component< } } - // TBD: make private - public onScroll = (scrollTop: number, clientHeight: number) => { + private onScroll = (scrollTop: number, clientHeight: number) => { this.props.onChangesListScrolled(scrollTop) } @@ -1115,8 +1114,8 @@ export class FilterChangesList extends React.Component< onItemDoubleClick={this.onChangedFileDoubleClick} onItemKeyboardFocus={this.onChangedFileFocus} onItemBlur={this.onChangedFileBlur} - // onScroll={this.onScroll} - // setScrollTop={this.props.changesListScrollTop} + onScroll={this.onScroll} + setScrollTop={this.props.changesListScrollTop} onItemKeyDown={this.onItemKeyDown} onSelectionChanged={this.onFileSelectionChanged} groups={this.state.groups} diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index c392ec99d4d..d748fe0f1cc 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -184,6 +184,14 @@ interface IAugmentedSectionFilterListProps { ) => void readonly onItemKeyDown?: (item: T, event: React.KeyboardEvent) => void + + readonly onScroll?: (scrollTop: number, clientHeight: number) => void + + /** + * The number of pixels from the top of the list indicating + * where to scroll do on rendering of the list. + */ + readonly setScrollTop?: number } interface IAugmentedSectionFilterListState { @@ -402,6 +410,8 @@ export class AugmentedSectionFilterList< ...this.props, ...this.props.invalidationProps, }} + onScroll={this.props.onScroll} + setScrollTop={this.props.setScrollTop} /> ) } From 4ba30c6ba7b45b66ba31e13d355d2d32b201ee9c Mon Sep 17 00:00:00 2001 From: tidy-dev <75402236+tidy-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:25:25 -0500 Subject: [PATCH 7/7] Wire up ariaLabel --- app/src/ui/changes/filter-changes-list.tsx | 2 +- app/src/ui/lib/augmented-filter-list.tsx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/ui/changes/filter-changes-list.tsx b/app/src/ui/changes/filter-changes-list.tsx index bc280e99f39..5002efc503c 100644 --- a/app/src/ui/changes/filter-changes-list.tsx +++ b/app/src/ui/changes/filter-changes-list.tsx @@ -1125,7 +1125,7 @@ export class FilterChangesList extends React.Component< focusedRow: this.state.focusedRow, }} onItemContextMenu={this.onItemContextMenu} - // ariaLabel={filesDescription} + ariaLabel={filesDescription} /> {this.renderStashedChanges()} diff --git a/app/src/ui/lib/augmented-filter-list.tsx b/app/src/ui/lib/augmented-filter-list.tsx index d748fe0f1cc..40f56183307 100644 --- a/app/src/ui/lib/augmented-filter-list.tsx +++ b/app/src/ui/lib/augmented-filter-list.tsx @@ -192,6 +192,9 @@ interface IAugmentedSectionFilterListProps { * where to scroll do on rendering of the list. */ readonly setScrollTop?: number + + /** The aria-label attribute for the list component. */ + readonly ariaLabel?: string } interface IAugmentedSectionFilterListState { @@ -412,6 +415,7 @@ export class AugmentedSectionFilterList< }} onScroll={this.props.onScroll} setScrollTop={this.props.setScrollTop} + ariaLabel={this.props.ariaLabel} /> ) }