From 9dbab4064e048701f5bd2edfd390b3d07711c716 Mon Sep 17 00:00:00 2001 From: bashbunni Date: Thu, 25 Jul 2024 10:38:02 -0700 Subject: [PATCH] fix: set YOffset + cursor based on first selected item --- field_multiselect.go | 26 +++++++++++++++++++++----- field_select.go | 10 ++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/field_multiselect.go b/field_multiselect.go index ce150b7..07ea321 100644 --- a/field_multiselect.go +++ b/field_multiselect.go @@ -127,17 +127,24 @@ func (m *MultiSelect[T]) Options(options ...Option[T]) *MultiSelect[T] { return m } + minSelected := len(options) - 1 for i, o := range options { - for _, v := range m.accessor.Get() { - if o.Value == v { - options[i].selected = true - break + if o.selected { + options[i].selected = true + if i < minSelected { + minSelected = i } + break } } + // No selected items... Start cursor at the beginning. + if minSelected == len(options)-1 { + minSelected = 0 + } m.options.val = options m.filteredOptions = options m.updateViewportHeight() + m.cursor = minSelected return m } @@ -549,11 +556,20 @@ func (m *MultiSelect[T]) optionsView() string { return sb.String() } +// centerYOffsetToSelected sets the YOffset so the selected element is in the +// middle of the list. +func (m *MultiSelect[T]) centerYOffsetToSelected() { + if m.cursor > m.viewport.YOffset+m.viewport.Height { + // Start with the selected value in the middle of the viewport. + m.viewport.SetYOffset(m.cursor - (m.viewport.Height+m.viewport.YOffset)/2) + } +} + // View renders the multi-select field. func (m *MultiSelect[T]) View() string { styles := m.activeStyles() - m.viewport.SetContent(m.optionsView()) + m.centerYOffsetToSelected() var sb strings.Builder if m.title.val != "" || m.title.fn != nil { diff --git a/field_select.go b/field_select.go index 81e57d9..40b3075 100644 --- a/field_select.go +++ b/field_select.go @@ -588,10 +588,20 @@ func (s *Select[T]) optionsView() string { return sb.String() } +// centerYOffsetToSelected sets the YOffset so the selected element is in the +// middle of the list. +func (s *Select[T]) centerYOffsetToSelected() { + if s.selected > s.viewport.YOffset+s.viewport.Height { + // Start with the selected value in the middle of the viewport. + s.viewport.SetYOffset(s.selected - (s.viewport.Height+s.viewport.YOffset)/2) + } +} + // View renders the select field. func (s *Select[T]) View() string { styles := s.activeStyles() s.viewport.SetContent(s.optionsView()) + s.centerYOffsetToSelected() var sb strings.Builder if s.title.val != "" || s.title.fn != nil {