on main help sign in
fix(ui): list: move focused logic to render callback
dd9e8caAyman Bagabas
internal/ui/dialog/models_list.go+1
@@ -26,6 +26,7 @@ func NewModelsList(sty *styles.Styles, groups ...ModelGroup) *ModelsList {
26 groups: groups,
26 groups: groups,
27 t: sty,
27 t: sty,
28 }
28 }
29+ f.RegisterRenderCallback(list.FocusedRenderCallback(f.List))
29 return f
30 return f
30}
31}
31
32
internal/ui/list/filterable.go+1
@@ -31,6 +31,7 @@ func NewFilterableList(items ...FilterableItem) *FilterableList {
31 List: NewList(),
31 List: NewList(),
32 items: items,
32 items: items,
33 }
33 }
34+ f.RegisterRenderCallback(FocusedRenderCallback(f.List))
34 f.SetItems(items...)
35 f.SetItems(items...)
35 return f
36 return f
36}
37}
internal/ui/list/focus.gonew file+13
@@ -0,0 +1,13 @@
1+package list
2+
3+// FocusedRenderCallback is a helper function that returns a render callback
4+// that marks items as focused during rendering.
5+func FocusedRenderCallback(list *List) RenderCallback {
6+ return func(idx, selectedIdx int, item Item) Item {
7+ if focusable, ok := item.(Focusable); ok {
8+ focusable.SetFocused(list.Focused() && idx == selectedIdx)
9+ return focusable.(Item)
10+ }
11+ return item
12+ }
13+}
internal/ui/list/list.go+15−5
@@ -49,9 +49,13 @@ func NewList(items ...Item) *List {
49 return l
49 return l
50}
50}
51
51
52+// RenderCallback defines a function that can modify an item before it is
53+// rendered.
54+type RenderCallback func(idx, selectedIdx int, item Item) Item
55+
52// RegisterRenderCallback registers a callback to be called when rendering
56// RegisterRenderCallback registers a callback to be called when rendering
53// items. This can be used to modify items before they are rendered.
57// items. This can be used to modify items before they are rendered.
54−func (l *List) RegisterRenderCallback(cb func(idx, selectedIdx int, item Item) Item) {
58+func (l *List) RegisterRenderCallback(cb RenderCallback) {
55 l.renderCallbacks = append(l.renderCallbacks, cb)
59 l.renderCallbacks = append(l.renderCallbacks, cb)
56}
60}
57
61
@@ -66,6 +70,11 @@ func (l *List) SetGap(gap int) {
66 l.gap = gap
70 l.gap = gap
67}
71}
68
72
73+// Gap returns the gap between items.
74+func (l *List) Gap() int {
75+ return l.gap
76+}
77+
69// SetReverse shows the list in reverse order.
78// SetReverse shows the list in reverse order.
70func (l *List) SetReverse(reverse bool) {
79func (l *List) SetReverse(reverse bool) {
71 l.reverse = reverse
80 l.reverse = reverse
@@ -101,10 +110,6 @@ func (l *List) getItem(idx int) renderedItem {
101 }
110 }
102 }
111 }
103
112
104− if focusable, isFocusable := item.(Focusable); isFocusable {
105− focusable.SetFocused(l.focused && idx == l.selectedIdx)
106− }
107−
108 rendered := item.Render(l.width)
113 rendered := item.Render(l.width)
109 rendered = strings.TrimRight(rendered, "\n")
114 rendered = strings.TrimRight(rendered, "\n")
110 height := countLines(rendered)
115 height := countLines(rendered)
@@ -348,6 +353,11 @@ func (l *List) RemoveItem(idx int) {
348 }
353 }
349}
354}
350
355
356+// Focused returns whether the list is focused.
357+func (l *List) Focused() bool {
358+ return l.focused
359+}
360+
351// Focus sets the focus state of the list.
361// Focus sets the focus state of the list.
352func (l *List) Focus() {
362func (l *List) Focus() {
353 l.focused = true
363 l.focused = true