@@ -73,11 +73,119 @@ pub(super) struct SelectContext {
7373 pub typeahead_clear_task : Signal < Option < Task > > ,
7474 /// Timeout before clearing typeahead buffer
7575 pub typeahead_timeout : ReadSignal < Duration > ,
76- /// The initial element to focus once the list is rendered
77- pub initial_focus : Signal < Option < usize > > ,
76+
77+ /// The initial element to focus once the list is rendered<br>
78+ /// true: last element<br>
79+ /// false: first element
80+ pub initial_focus_last : Signal < Option < bool > > ,
7881}
7982
8083impl SelectContext {
84+ /// custom implementation for `FocusState::focus_next`
85+ pub ( crate ) fn focus_next ( & mut self ) {
86+ let current_focus = self . focus_state . recent_focus ( ) ;
87+ let mut new_focus = current_focus. unwrap_or_default ( ) ;
88+ let start_focus = current_focus. unwrap_or_default ( ) ;
89+ let item_count = ( self . focus_state . item_count ) ( ) ;
90+ let roving_loop = ( self . focus_state . roving_loop ) ( ) ;
91+ let options = self . options . read ( ) ;
92+
93+ loop {
94+ new_focus = new_focus. saturating_add ( 1 ) ;
95+ if new_focus >= item_count {
96+ new_focus = match roving_loop {
97+ true => 0 ,
98+ false => item_count. saturating_sub ( 1 ) ,
99+ }
100+ }
101+
102+ // get value of the option
103+ let disabled = options. iter ( ) . find ( |opt| opt. tab_index == new_focus) . map ( |e| e. disabled ) . unwrap_or ( false ) ;
104+
105+ // this fails if the current_focus at the start is None
106+ if !disabled || new_focus == start_focus {
107+ break ;
108+ }
109+ }
110+
111+ self . focus_state . set_focus ( Some ( new_focus) ) ;
112+ }
113+
114+ /// custom implementation for `FocusState::focus_prev`
115+ pub ( crate ) fn focus_prev ( & mut self ) {
116+ let current_focus = self . focus_state . recent_focus ( ) ;
117+ let mut new_focus = current_focus. unwrap_or_default ( ) ;
118+ let start_focus = current_focus. unwrap_or_default ( ) ;
119+ let item_count = ( self . focus_state . item_count ) ( ) ;
120+ let roving_loop = ( self . focus_state . roving_loop ) ( ) ;
121+ let options = self . options . read ( ) ;
122+
123+ loop {
124+ let old_focus = new_focus;
125+ new_focus = new_focus. saturating_sub ( 1 ) ;
126+
127+ if old_focus == 0 && roving_loop {
128+ new_focus = item_count. saturating_sub ( 1 ) ;
129+ }
130+
131+ // get value of the option
132+ let disabled = options. iter ( ) . find ( |opt| opt. tab_index == new_focus) . map ( |e| e. disabled ) . unwrap_or ( false ) ;
133+
134+ if !disabled || new_focus == start_focus {
135+ break ;
136+ }
137+ }
138+
139+ self . focus_state . set_focus ( Some ( new_focus) ) ;
140+ }
141+
142+ /// custom implementation for `FocusState::focus_last`
143+ pub ( crate ) fn focus_last ( & mut self ) {
144+ let item_count = ( self . focus_state . item_count ) ( ) ;
145+ let options = self . options . read ( ) ;
146+ let mut new_focus = item_count;
147+
148+ loop {
149+ // If at the start, don't focus anything
150+ if new_focus == 0 {
151+ return ;
152+ }
153+ new_focus = new_focus. saturating_sub ( 1 ) ;
154+
155+ // get value of the option
156+ let disabled = options. iter ( ) . find ( |opt| opt. tab_index == new_focus) . map ( |e| e. disabled ) . unwrap_or ( false ) ;
157+
158+ if !disabled {
159+ break ;
160+ }
161+ }
162+ self . focus_state . set_focus ( Some ( new_focus) ) ;
163+ }
164+
165+ /// custom implementation for `FocusState::focus_first`
166+ pub ( crate ) fn focus_first ( & mut self ) {
167+ let item_count = ( self . focus_state . item_count ) ( ) ;
168+ let options = self . options . read ( ) ;
169+ let mut new_focus = 0 ;
170+
171+ loop {
172+ // get value of the option
173+ let disabled = options. iter ( ) . find ( |opt| opt. tab_index == new_focus) . map ( |e| e. disabled ) . unwrap_or ( false ) ;
174+
175+ if !disabled {
176+ break ;
177+ }
178+
179+ // If at the end, don't focus anything
180+ if new_focus >= item_count {
181+ return ;
182+ }
183+
184+ new_focus = new_focus. saturating_add ( 1 ) ;
185+ }
186+ self . focus_state . set_focus ( Some ( new_focus) ) ;
187+ }
188+
81189 /// Select the currently focused item
82190 pub fn select_current_item ( & mut self ) {
83191 // If the select is open, select the focused item
@@ -154,6 +262,9 @@ pub(super) struct OptionState {
154262 pub text_value : String ,
155263 /// Unique ID for the option
156264 pub id : String ,
265+
266+ /// Whether the option is disabled
267+ pub disabled : bool ,
157268}
158269
159270/// Context for select option components to know if they're selected
0 commit comments