@@ -23,7 +23,6 @@ type HasAnim interface {
2323 Item
2424 Spinning() bool
2525}
26−type renderedMsg struct{}
2726
2827type List[T Item] interface {
2928 util.Model
@@ -77,6 +76,7 @@ type confOptions struct {
7776 selectedItem string
7877 focused bool
7978 resize bool
79+ enableMouse bool
8080}
8181
8282type list[T Item] struct {
@@ -156,6 +156,12 @@ func WithResizeByList() ListOption {
156156 }
157157}
158158
159+func WithEnableMouse() ListOption {
160+ return func(l *confOptions) {
161+ l.enableMouse = true
162+ }
163+}
164+
159165func New[T Item](items []T, opts ...ListOption) List[T] {
160166 list := &list[T]{
161167 confOptions: &confOptions{
@@ -188,6 +194,11 @@ func (l *list[T]) Init() tea.Cmd {
188194// Update implements List.
189195func (l *list[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
190196 switch msg := msg.(type) {
197+ case tea.MouseWheelMsg:
198+ if l.enableMouse {
199+ return l.handleMouseWheel(msg)
200+ }
201+ return l, nil
191202 case anim.StepMsg:
192203 var cmds []tea.Cmd
193204 for _, item := range l.items.Slice() {
@@ -229,6 +240,17 @@ func (l *list[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
229240 return l, nil
230241}
231242
243+func (l *list[T]) handleMouseWheel(msg tea.MouseWheelMsg) (tea.Model, tea.Cmd) {
244+ var cmd tea.Cmd
245+ switch msg.Button {
246+ case tea.MouseWheelDown:
247+ cmd = l.MoveDown(ViewportDefaultScrollSize)
248+ case tea.MouseWheelUp:
249+ cmd = l.MoveUp(ViewportDefaultScrollSize)
250+ }
251+ return l, cmd
252+}
253+
232254// View implements List.
233255func (l *list[T]) View() string {
234256 if l.height <= 0 || l.width <= 0 {
@@ -292,9 +314,8 @@ func (l *list[T]) render() tea.Cmd {
292314 }
293315 // we are not rendering the first time
294316 if l.rendered != "" {
295− l.rendered = ""
296317 // rerender everything will mostly hit cache
297− _ = l.renderIterator(0, false)
318+ l.rendered, _ = l.renderIterator(0, false, "")
298319 if l.direction == DirectionBackward {
299320 l.recalculateItemPositions()
300321 }
@@ -304,14 +325,17 @@ func (l *list[T]) render() tea.Cmd {
304325 }
305326 return focusChangeCmd
306327 }
307− finishIndex := l.renderIterator(0, true)
328+ rendered, finishIndex := l.renderIterator(0, true, "")
329+ l.rendered = rendered
330+
308331 // recalculate for the initial items
309332 if l.direction == DirectionBackward {
310333 l.recalculateItemPositions()
311334 }
312335 renderCmd := func() tea.Msg {
336+ l.offset = 0
313337 // render the rest
314− _ = l.renderIterator(finishIndex, false)
338+ l.rendered, _ = l.renderIterator(finishIndex, false, l.rendered)
315339 // needed for backwards
316340 if l.direction == DirectionBackward {
317341 l.recalculateItemPositions()
@@ -321,7 +345,7 @@ func (l *list[T]) render() tea.Cmd {
321345 l.scrollToSelection()
322346 }
323347
324− return renderedMsg{}
348+ return nil
325349 }
326350 return tea.Batch(focusChangeCmd, renderCmd)
327351}
@@ -568,13 +592,14 @@ func (l *list[T]) blurSelectedItem() tea.Cmd {
568592}
569593
570594// render iterator renders items starting from the specific index and limits hight if limitHeight != -1
571−// returns the last index
572−func (l *list[T]) renderIterator(startInx int, limitHeight bool) int {
573− currentContentHeight := lipgloss.Height(l.rendered) - 1
595+// returns the last index and the rendered content so far
596+// we pass the rendered content around and don't use l.rendered to prevent jumping of the content
597+func (l *list[T]) renderIterator(startInx int, limitHeight bool, rendered string) (string, int) {
598+ currentContentHeight := lipgloss.Height(rendered) - 1
574599 itemsLen := l.items.Len()
575600 for i := startInx; i < itemsLen; i++ {
576601 if currentContentHeight >= l.height && limitHeight {
577− return i
602+ return rendered, i
578603 }
579604 // cool way to go through the list in both directions
580605 inx := i
@@ -602,13 +627,13 @@ func (l *list[T]) renderIterator(startInx int, limitHeight bool) int {
602627 }
603628
604629 if l.direction == DirectionForward {
605− l.rendered += rItem.view + strings.Repeat("\n", gap)
630+ rendered += rItem.view + strings.Repeat("\n", gap)
606631 } else {
607− l.rendered = rItem.view + strings.Repeat("\n", gap) + l.rendered
632+ rendered = rItem.view + strings.Repeat("\n", gap) + rendered
608633 }
609634 currentContentHeight = rItem.end + 1 + l.gap
610635 }
611− return itemsLen
636+ return rendered, itemsLen
612637}
613638
614639func (l *list[T]) renderItem(item Item) renderedItem {