on main help sign in
fix(tui): fix list wrap behave when it has unfocusable items (#1312)
commitcc08edc9b388af373404b339d138607b39b1681e authordawndiy <dawndiy.dev@gmail.com> dateFri 12 Dec 2025, 20:32 (1 year ago) parentc5d2ccb
1 file changed+19−3
internal/tui/exp/list/list.go+19−3
internal/tui/exp/list/list.go+19−3
@@ -864,6 +864,7 @@ func (l *list[T]) selectLastItem() {
864864}
865865
866866func (l *list[T]) firstSelectableItemAbove(inx int) int {
867+ unfocusableCount := 0
867868 for i := inx - 1; i >= 0; i-- {
868869 if i < 0 || i >= len(l.items) {
869870 continue
@@ -873,14 +874,16 @@ func (l *list[T]) firstSelectableItemAbove(inx int) int {
873874 if _, ok := any(item).(layout.Focusable); ok {
874875 return i
875876 }
877+ unfocusableCount++
876878 }
877− if inx == 0 && l.wrap {
879+ if unfocusableCount == inx && l.wrap {
878880 return l.firstSelectableItemAbove(len(l.items))
879881 }
880882 return ItemNotFound
881883}
882884
883885func (l *list[T]) firstSelectableItemBelow(inx int) int {
886+ unfocusableCount := 0
884887 itemsLen := len(l.items)
885888 for i := inx + 1; i < itemsLen; i++ {
886889 if i < 0 || i >= len(l.items) {
@@ -891,8 +894,9 @@ func (l *list[T]) firstSelectableItemBelow(inx int) int {
891894 if _, ok := any(item).(layout.Focusable); ok {
892895 return i
893896 }
897+ unfocusableCount++
894898 }
895− if inx == itemsLen-1 && l.wrap {
899+ if unfocusableCount == itemsLen-inx-1 && l.wrap {
896900 return l.firstSelectableItemBelow(-1)
897901 }
898902 return ItemNotFound
@@ -1352,6 +1356,14 @@ func (l *list[T]) SelectItemAbove() tea.Cmd {
13521356 }
13531357 // Pre-allocate with expected capacity
13541358 cmds := make([]tea.Cmd, 0, 2)
1359+ if newIndex > l.selectedItemIdx && l.selectedItemIdx > 0 && l.offset > 0 {
1360+ // this means there is a section above and not showing on the top, move to the top
1361+ newIndex = l.selectedItemIdx
1362+ cmd := l.GoToTop()
1363+ if cmd != nil {
1364+ cmds = append(cmds, cmd)
1365+ }
1366+ }
13551367 if newIndex == 1 {
13561368 peakAboveIndex := l.firstSelectableItemAbove(newIndex)
13571369 if peakAboveIndex == ItemNotFound {
@@ -1383,12 +1395,16 @@ func (l *list[T]) SelectItemBelow() tea.Cmd {
13831395
13841396 newIndex := l.firstSelectableItemBelow(l.selectedItemIdx)
13851397 if newIndex == ItemNotFound {
1386− // no item above
1398+ // no item below
13871399 return nil
13881400 }
13891401 if newIndex < 0 || newIndex >= len(l.items) {
13901402 return nil
13911403 }
1404+ if newIndex < l.selectedItemIdx {
1405+ // reset offset when wrap to the top to show the top section if it exists
1406+ l.offset = 0
1407+ }
13921408 l.prevSelectedItemIdx = l.selectedItemIdx
13931409 l.selectedItemIdx = newIndex
13941410 l.movingByItem = true