@@ -182,6 +182,292 @@ describe("Event firing", () => {
182182 } ) ;
183183} ) ;
184184
185+ describe ( "MultiComboBox RTL/LTR Arrow Navigation" , ( ) => {
186+ it ( "should focus last token on arrow right in RTL mode when input is at start" , ( ) => {
187+ cy . mount (
188+ < div dir = "rtl" >
189+ < MultiComboBox noValidation = { true } >
190+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
191+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
192+ < MultiComboBoxItem selected text = "Token 3" > </ MultiComboBoxItem >
193+ < MultiComboBoxItem text = "Item 4" > </ MultiComboBoxItem >
194+ < MultiComboBoxItem text = "Item 5" > </ MultiComboBoxItem >
195+ </ MultiComboBox >
196+ </ div >
197+ ) ;
198+
199+ cy . get ( "[ui5-multi-combobox]" )
200+ . as ( "mcb" )
201+ . realClick ( ) ;
202+ cy . get ( "@mcb" )
203+ . should ( "be.focused" ) ;
204+
205+ cy . get ( "@mcb" )
206+ . shadow ( )
207+ . find ( "input" )
208+ . as ( "input" )
209+ . then ( ( $input ) => {
210+ ( $input [ 0 ] as HTMLInputElement ) . setSelectionRange ( 0 , 0 ) ;
211+ } )
212+ . should ( ( $input ) => {
213+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionStart ) . to . equal ( 0 ) ;
214+ } ) ;
215+
216+ cy . get ( "@mcb" ) . realPress ( "ArrowRight" ) ;
217+ cy . get ( "@mcb" )
218+ . shadow ( )
219+ . find ( "[ui5-tokenizer]" )
220+ . find ( "[ui5-token]" )
221+ . last ( )
222+ . should ( "be.visible" )
223+ . should ( "be.focused" ) ;
224+ } ) ;
225+
226+ it ( "should focus last token on arrow left in LTR mode when input is at start" , ( ) => {
227+ cy . mount (
228+ < div dir = "ltr" >
229+ < MultiComboBox noValidation = { true } >
230+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
231+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
232+ < MultiComboBoxItem selected text = "Token 3" > </ MultiComboBoxItem >
233+ < MultiComboBoxItem text = "Item 4" > </ MultiComboBoxItem >
234+ < MultiComboBoxItem text = "Item 5" > </ MultiComboBoxItem >
235+ </ MultiComboBox >
236+ </ div >
237+ ) ;
238+
239+ cy . get ( "[ui5-multi-combobox]" )
240+ . as ( "mcb" )
241+ . realClick ( ) ;
242+
243+ cy . get ( "@mcb" )
244+ . should ( "be.focused" ) ;
245+
246+ cy . get ( "@mcb" )
247+ . shadow ( )
248+ . find ( "input" )
249+ . as ( "input" )
250+ . realClick ( )
251+ . should ( "have.focus" )
252+ . then ( ( $input ) => {
253+ ( $input [ 0 ] as HTMLInputElement ) . setSelectionRange ( 0 , 0 ) ;
254+ } )
255+ . should ( ( $input ) => {
256+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionStart ) . to . equal ( 0 ) ;
257+ } ) ;
258+
259+ cy . get ( "@mcb" ) . realPress ( "ArrowLeft" ) ;
260+
261+ cy . get ( "@mcb" )
262+ . shadow ( )
263+ . find ( "[ui5-tokenizer]" )
264+ . find ( "[ui5-token]" )
265+ . last ( )
266+ . should ( "be.visible" )
267+ . should ( "be.focused" ) ;
268+ } ) ;
269+
270+ it ( "should not focus token when cursor is not at start of input in RTL mode" , ( ) => {
271+ cy . mount (
272+ < div dir = "rtl" >
273+ < MultiComboBox noValidation = { true } value = "test text" >
274+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
275+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
276+ < MultiComboBoxItem text = "Item 3" > </ MultiComboBoxItem >
277+ </ MultiComboBox >
278+ </ div >
279+ ) ;
280+
281+ cy . get ( "[ui5-multi-combobox]" )
282+ . as ( "mcb" )
283+ . realClick ( ) ;
284+
285+ cy . get ( "@mcb" ) . should ( "be.focused" ) ;
286+
287+
288+ cy . get ( "@mcb" )
289+ . shadow ( )
290+ . find ( "input" )
291+ . as ( "input" )
292+ . realClick ( )
293+ . should ( "be.focused" )
294+ . then ( ( $input ) => {
295+ ( $input [ 0 ] as HTMLInputElement ) . setSelectionRange ( 2 , 2 ) ;
296+ } ) ;
297+
298+ cy . get ( "@mcb" ) . realPress ( "ArrowRight" ) ;
299+
300+ cy . get ( "@mcb" )
301+ . shadow ( )
302+ . find ( "input" )
303+ . as ( "input" )
304+ . realClick ( ) ;
305+
306+ cy . get ( "@input" )
307+ . should ( "be.focused" )
308+ . should ( ( $input ) => {
309+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionStart ) . to . equal ( 3 ) ;
310+ } ) ;
311+
312+ cy . get ( "@mcb" )
313+ . shadow ( )
314+ . find ( "[ui5-tokenizer]" )
315+ . find ( "[ui5-token]" )
316+ . should ( "not.be.focused" ) ;
317+ } ) ;
318+
319+ it ( "should not focus token when text is selected in RTL mode" , ( ) => {
320+ cy . mount (
321+ < div dir = "rtl" >
322+ < MultiComboBox noValidation = { true } value = "test" >
323+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
324+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
325+ < MultiComboBoxItem text = "Item 3" > </ MultiComboBoxItem >
326+ </ MultiComboBox >
327+ </ div >
328+ ) ;
329+
330+ cy . get ( "[ui5-multi-combobox]" )
331+ . as ( "mcb" )
332+ . realClick ( ) ;
333+
334+ cy . get ( "@mcb" ) . should ( "be.focused" ) ;
335+
336+ cy . get ( "@mcb" )
337+ . shadow ( )
338+ . find ( "input" )
339+ . as ( "input" )
340+ . realClick ( )
341+ . realPress ( [ "Control" , "a" ] ) ;
342+
343+ cy . get ( "@input" )
344+ . should ( ( $input ) => {
345+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionStart ) . to . equal ( 0 ) ;
346+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionEnd ) . to . equal ( 4 ) ;
347+ } ) ;
348+
349+ cy . get ( "@mcb" )
350+ . shadow ( )
351+ . find ( "[ui5-tokenizer]" )
352+ . find ( "[ui5-token]" )
353+ . should ( "not.have.focus" ) ;
354+ } ) ;
355+
356+ it ( "should navigate from last token back to input with arrow left in RTL mode" , ( ) => {
357+ cy . mount (
358+ < div dir = "rtl" >
359+ < MultiComboBox noValidation = { true } >
360+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
361+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
362+ < MultiComboBoxItem selected text = "Token 3" > </ MultiComboBoxItem >
363+ < MultiComboBoxItem text = "Item 4" > </ MultiComboBoxItem >
364+ </ MultiComboBox >
365+ </ div >
366+ ) ;
367+
368+ cy . get ( "[ui5-multi-combobox]" )
369+ . as ( "mcb" )
370+ . realClick ( )
371+
372+ cy . get ( "@mcb" )
373+ . should ( "be.focused" )
374+ . realPress ( "ArrowRight" ) ;
375+
376+ cy . get ( "@mcb" )
377+ . shadow ( )
378+ . find ( "[ui5-tokenizer]" )
379+ . find ( "[ui5-token]" )
380+ . last ( )
381+ . as ( "lastToken" )
382+ . should ( "have.focus" ) ;
383+
384+ cy . get ( "@lastToken" )
385+ . should ( "be.focused" )
386+ . realPress ( "ArrowLeft" ) ;
387+
388+ cy . get ( "@mcb" )
389+ . shadow ( )
390+ . find ( "input" )
391+ . should ( "be.focused" ) ;
392+ } ) ;
393+
394+ it ( "should navigate from last token back to input with arrow right in LTR mode" , ( ) => {
395+ cy . mount (
396+ < div dir = "ltr" >
397+ < MultiComboBox noValidation = { true } >
398+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
399+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
400+ < MultiComboBoxItem selected text = "Token 3" > </ MultiComboBoxItem >
401+ < MultiComboBoxItem text = "Item 4" > </ MultiComboBoxItem >
402+ </ MultiComboBox >
403+ </ div >
404+ ) ;
405+
406+ cy . get ( "[ui5-multi-combobox]" )
407+ . as ( "mcb" )
408+ . realClick ( ) ;
409+
410+ cy . get ( "@mcb" )
411+ . should ( "be.focused" )
412+ . realPress ( "ArrowLeft" ) ;
413+
414+ cy . get ( "@mcb" )
415+ . shadow ( )
416+ . find ( "[ui5-tokenizer]" )
417+ . find ( "[ui5-token]" )
418+ . last ( )
419+ . as ( "lastToken" )
420+ . should ( "be.focused" ) ;
421+
422+ cy . get ( "@lastToken" ) . realPress ( "ArrowRight" ) ;
423+
424+ cy . get ( "@mcb" )
425+ . shadow ( )
426+ . find ( "input" )
427+ . should ( "be.focused" ) ;
428+ } ) ;
429+
430+ it ( "should handle empty input case in RTL mode" , ( ) => {
431+ cy . mount (
432+ < div dir = "rtl" >
433+ < MultiComboBox noValidation = { true } >
434+ < MultiComboBoxItem selected text = "Token 1" > </ MultiComboBoxItem >
435+ < MultiComboBoxItem selected text = "Token 2" > </ MultiComboBoxItem >
436+ < MultiComboBoxItem text = "Item 3" > </ MultiComboBoxItem >
437+ </ MultiComboBox >
438+ </ div >
439+ ) ;
440+
441+ cy . get ( "[ui5-multi-combobox]" )
442+ . as ( "mcb" )
443+ . realClick ( ) ;
444+
445+ cy . get ( "@mcb" ) . should ( "be.focused" ) ;
446+
447+ cy . get ( "@mcb" )
448+ . shadow ( )
449+ . find ( "input" )
450+ . as ( "input" )
451+ . realClick ( )
452+ . should ( "have.focus" )
453+
454+ cy . get ( "@input" )
455+ . should ( "have.value" , "" )
456+ . should ( ( $input ) => {
457+ expect ( ( $input [ 0 ] as HTMLInputElement ) . selectionStart ) . to . equal ( 0 ) ;
458+ } ) ;
459+
460+ cy . get ( "@mcb" ) . realPress ( "ArrowRight" ) ;
461+
462+ cy . get ( "@mcb" )
463+ . shadow ( )
464+ . find ( "[ui5-tokenizer]" )
465+ . find ( "[ui5-token]" )
466+ . last ( )
467+ . should ( "have.focus" ) ;
468+ } ) ;
469+ } ) ;
470+
185471describe ( "Accessibility" , ( ) => {
186472 it ( "should announce the associated label when MultiComboBox is focused" , ( ) => {
187473 const label = "MultiComboBox aria-label" ;
0 commit comments