@@ -31,6 +31,7 @@ const (
31type ListModel interface {
31type ListModel interface {
32 util.Model
32 util.Model
33 layout.Sizeable
33 layout.Sizeable
34 SetItems([]util.Model) tea.Cmd // Replace all items in the list
35 SetItems([]util.Model) tea.Cmd // Replace all items in the list
35 AppendItem(util.Model) tea.Cmd // Add an item to the end of the list
36 AppendItem(util.Model) tea.Cmd // Add an item to the end of the list
36 PrependItem(util.Model) tea.Cmd // Add an item to the beginning of the list
37 PrependItem(util.Model) tea.Cmd // Add an item to the beginning of the list
@@ -40,7 +41,6 @@ type ListModel interface {
40 Items() []util.Model // Get all items in the list
41 Items() []util.Model // Get all items in the list
41 SelectedIndex() int // Get the index of the currently selected item
42 SelectedIndex() int // Get the index of the currently selected item
42 SetSelected(int) tea.Cmd // Set the selected item by index and scroll to it
43 SetSelected(int) tea.Cmd // Set the selected item by index and scroll to it
43− ClearSelection() tea.Cmd // Clear the current selection
44 Filter(string) tea.Cmd // Filter items based on a search term
44 Filter(string) tea.Cmd // Filter items based on a search term
@@ -143,6 +143,8 @@ type model struct {
143 inputStyle lipgloss.Style // Style for the input field
143 inputStyle lipgloss.Style // Style for the input field
144 hideFilterInput bool // Whether to hide the filter input field
144 hideFilterInput bool // Whether to hide the filter input field
145 currentSearch string // Current search term for filtering
145 currentSearch string // Current search term for filtering
147+ isFocused bool // Whether the list is currently focused
148// listOptions is a function type for configuring list options.
150// listOptions is a function type for configuring list options.
@@ -238,6 +240,7 @@ func New(opts ...listOptions) ListModel {
238 selectionState: selectionState{selectedIndex: NoSelection},
240 selectionState: selectionState{selectedIndex: NoSelection},
239 filterPlaceholder: "Type to filter...",
241 filterPlaceholder: "Type to filter...",
240 inputStyle: t.S().Base.Padding(0, 1, 1, 1),
242 inputStyle: t.S().Base.Padding(0, 1, 1, 1),
242 for _, opt := range opts {
245 for _, opt := range opts {
@@ -746,8 +749,10 @@ func (m *model) ensureVisibleReverse(cachedItem renderedItem) {
746func (m *model) goToBottom() tea.Cmd {
749func (m *model) goToBottom() tea.Cmd {
747 cmds := []tea.Cmd{m.blurSelected()}
750 cmds := []tea.Cmd{m.blurSelected()}
748 m.viewState.reverse = true
751 m.viewState.reverse = true
749− m.selectionState.selectedIndex = m.findLastSelectableItem()
753+ m.selectionState.selectedIndex = m.findLastSelectableItem()
750− cmds = append(cmds, m.focusSelected())
754+ cmds = append(cmds, m.focusSelected())
751 m.ResetView()
756 m.ResetView()
752 return tea.Batch(cmds...)
757 return tea.Batch(cmds...)
@@ -774,6 +779,9 @@ func (m *model) ResetView() {
774// focusSelected gives focus to the currently selected item if it supports focus.
779// focusSelected gives focus to the currently selected item if it supports focus.
775// Triggers a re-render of the item to show its focused state.
780// Triggers a re-render of the item to show its focused state.
776func (m *model) focusSelected() tea.Cmd {
781func (m *model) focusSelected() tea.Cmd {
783+ return nil // No focus change if the list is not focused
777 if !m.selectionState.isValidIndex(len(m.filteredItems)) {
785 if !m.selectionState.isValidIndex(len(m.filteredItems)) {
778 return nil
786 return nil
@@ -953,9 +961,7 @@ func (m *model) UpdateItem(inx int, item util.Model) {
954 m.filteredItems[inx] = item
962 m.filteredItems[inx] = item
955 if m.selectionState.selectedIndex == inx {
963 if m.selectionState.selectedIndex == inx {
956− if i, ok := m.filteredItems[m.selectionState.selectedIndex].(layout.Focusable); ok {
964+ m.focusSelected()
960 m.setItemSize(inx)
966 m.setItemSize(inx)
961 m.rerenderItem(inx)
967 m.rerenderItem(inx)
@@ -1334,14 +1340,21 @@ func (m *model) SetSelected(index int) tea.Cmd {
1334 return tea.Batch(cmds...)
1340 return tea.Batch(cmds...)
1337−// ClearSelection clears the current selection and focus.
1343+// Blur implements ListModel.
1338−func (m *model) ClearSelection() tea.Cmd {
1344+func (m *model) Blur() tea.Cmd {
1339− cmds := []tea.Cmd{}
1345+ m.isFocused = false
1340− if m.selectionState.selectedIndex >= 0 && m.selectionState.selectedIndex < len(m.filteredItems) {
1346+ cmd := m.blurSelected()
1341− if i, ok := m.filteredItems[m.selectionState.selectedIndex].(layout.Focusable); ok {
1347+ return cmd
1342− cmds = append(cmds, i.Blur())
1348+}
1344− }
1350+// Focus implements ListModel.
1345− m.selectionState.selectedIndex = NoSelection
1351+func (m *model) Focus() tea.Cmd {
1346− return tea.Batch(cmds...)
1352+ m.isFocused = true
1353+ cmd := m.focusSelected()
1357+// IsFocused implements ListModel.
1358+func (m *model) IsFocused() bool {