Horizontal carousel issue with data refresh and data length shrinking

:warning: Before you continue


Before submitting a bug report, please review our troubleshooting documentation at Troubleshoot Issues | Vega Troubleshooting

If you still want to file a bug report, please make sure to fill in all the details below and provide the necessary information.

NOTE: PLEASE ONLY REPORT A SINGLE BUG USING THIS TEMPLATE.
If you’re experiencing multiple issues, please file a separate report for each.


:backhand_index_pointing_right: Horizontal Carousel does not maintain focus and leaves row blank when a data refresh causes all rendered item to vanish


1. Summary

Provide a brief description of the bug in the SDK and its impact on app functionality.

App Name:
App Link on Amazon Appstore (found through Developer Console → Actions column in App List → View on Amazon.com):

Bug Severity
Select one that applies

  • Impacts operation of app
  • Blocks current development
  • Improvement suggestion
  • Issue with documentation (If selected, please share the doc link and describe the issue)
  • Other

2. Steps to Reproduce

  1. Move as far to right, so that the only remaining item does not remain rendered.Do it before 7 seconds
  2. wait for 7 seconds for refresh to occur

3. Observed Behavior

Explain what actually happened, noting any discrepancies or malfunctions.

nothing is visible on screen

4. Expected Behavior

Describe what you expected the SDK to do under normal operation.

focus should be at nearest item in new data set

4.a Possible Root Cause & Temporary Workaround

Fill out anything you have tried. If you don’t know, N/A is acceptable

<!-- Answer here -->

5. Logs or crash report

(Please make sure to provide relevant logs as attachment)

For crash issues, please refer this guide for faster troubleshooting: Detect Where the App Crash Originates | Design and Develop Vega Apps

  • App/Device Logs

  • Crash Logs

  • Crash Report

  • For issues with Vega Studio Extension, please share log files from below folders:
    For v0.22+:

    ~/.vscode/extensions/amazon.vega-extension-<version>/ExtensionLogs
    ~/.vscode/extensions/amazon.vega-ui-extension-<version>/ExtensionLogs
    

    For v0.21 and earlier:

     ~/.vscode/extensions/amazon.kepler-extension-<version>/ExtensionLogs
     ~/.vscode/extensions/amazon.kepler-ui-extension-<version>/ExtensionLogs
    

6. Environment

Please fill out the fields related to your bug below:

  • SDK Version: 0.23.8128 , Vega carousel version: 0.2.0

  • App State: Foreground

  • OS Information: Please ssh into the device via vega exec vda shell (or kepler exec vda shell for v0.21 and earlier) and copy the output from cat /etc/os-release into the answer section below. Note, if you don’t have a simulator running or device attached, the command will respond with vda: no devices/emulators found

    <!-- Answer here if applicable --> 
    

7. Example Code Snippet / Screenshots / Screengrabs

Include any relevant code or component setup in React Native that can help reproduce the bug.

import { Carousel } from '@amazon-devices/vega-carousel'
import { useEffect, useMemo, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'

/**
 * Repro: a horizontal Carousel with selectionStrategy="pinned" scrolls off-screen
 * when the backing data is refreshed down to a single item.Same bug exists with anchor
 *
 * On refresh the adapter is replaced with one that has ONLY the first item left
 * (count 20 -> 1). That surviving item keeps its original key (`Item 0`). If a high
 * index was selected, its key no longer exists in the data.
 *
 * Expected: the carousel clamps its selection to the new valid range (index 0, the
 * only item) and keeps it visible.
 *
 * Actual: the carousel keeps its stale selected index and pinned-start scrolls the
 * row so the single remaining item ends up off-screen / blank.
 *
 * Steps:
 *   1. Launch — the carousel shows 20 items, focus starts on item 0.
 *   2. Arrow RIGHT to the last item (item 19).
 *   3. Wait ~7s. The data refreshes to just the first item.
 *   -> BUG: the row is blank / scrolled off-screen
 */

const FULL_COUNT = 18

const ITEM_WIDTH = 400
const ITEM_HEIGHT = 140
const GAP = 20

type DataType = { key: string; label: string }

//data set (20 items)
const FULL_DATA: DataType[] = Array.from({ length: FULL_COUNT }, (_, i) => ({
  key: `item-${i}`,
  label: `Item ${i}`,
}))

// after refresh: only the first item remains, keeping its original key
const REFRESHED_DATA: DataType[] = [FULL_DATA[0]]

const Item = ({
  label,
  index,
  onFocus,
}: {
  label: string
  index: number
  onFocus: (index: number) => void
}) => {
  const [isFocused, setIsFocused] = useState(false)
  return (
    <Pressable
      style={[styles.item, isFocused && styles.itemFocused]}
      onFocus={() => {
        setIsFocused(true)
        onFocus(index)
      }}
      onBlur={() => setIsFocused(false)}
    >
      <Text style={styles.text}>{label}</Text>
    </Pressable>
  )
}

export const ShrinkBug = () => {
  const [refreshed, setRefreshed] = useState(false)
  const [focusedIndex, setFocusedIndex] = useState(0)

  // refresh the data after a delay so there's time to move focus so far such that remaining item after refresh is not rendered
  useEffect(() => {
    const timeout = setTimeout(() => setRefreshed(true), 7000)
    return () => clearTimeout(timeout)
  }, [])

  const data = refreshed ? REFRESHED_DATA : FULL_DATA
  const dataAdapter = useMemo(
    () => ({
      getItem: (index: number) => data[index],
      getItemCount: () => data.length,
      getItemKey: ({ item }: { item: DataType }) => item.key,
      notifyDataError: () => false,
    }),
    [data],
  )

  return (
    <View style={styles.container}>
      <Text style={styles.status}>
        refreshed: {String(refreshed)} · last focused index: {focusedIndex}
      </Text>
      <Text style={styles.hint}>
        Move to the last item for instance, then wait ~7s. On refresh every key changes
        except the first item's.
      </Text>
      <Carousel
        hasPreferredFocus
        orientation="horizontal"
        containerStyle={styles.carousel}
        dataAdapter={dataAdapter}
        itemStyle={{ itemPadding: GAP, pressedItemScaleFactor: 1 }}
        selectionStrategy="anchored"
        trapSelectionOnOrientation
        pinnedSelectedItemOffset="start"
        renderItem={({ item, index }) => (
          <Item label={item.label} index={index} onFocus={setFocusedIndex} />
         )}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    width: '100%',
    height: 400,
    padding: 50,
  },
  status: {
    color: 'white',
    fontSize: 28,
    marginBottom: 8,
  },
  hint: {
    color: 'green',
    fontSize: 22,
    marginBottom: 18,
  },
  carousel: {
    width: '100%',
    height: ITEM_HEIGHT + 20,
  },
  item: {
    width: ITEM_WIDTH,
    height: ITEM_HEIGHT,
    backgroundColor: '#444444',
    alignItems: 'center',
    justifyContent: 'center',
  },
  itemFocused: {
    backgroundColor: 'red',
  },
  text: {
    color: 'white',
    fontSize: 35,
  },
})


:backhand_index_pointing_right: Playback Issues


If this is a playback issue, please provide your content URL, any pre-conditions (like geo-location), and let us know if it’s x86 or arm7.


<!-- Describe your playback issue if applicable -->

Please share the following details in addition:_

  • Player SDK: [Bitmovin, Shaka, ...]
  • Player SDK Version: [e.g. 1.23]
    • Audio Codecs: [AAC, ...]
    • Video Codecs: [h.264, mp4]
    • Manifest Types: [m3u8, dash, etc ..]

Q: If applicable, please provide your media/content url
If this is created dynamically, tokenized, etc please provide a way for us to access it

[N/A or Content / Media Url for testing]

Q: Are there any special headers required to reproduce the issue you are facing?

[N/A or Insert Headers]

Additionally please provide the following if possible
Provide Screenshots / Screengrabs / Logs. Please include as much information as you can that will help debug.

<!-- Answer here if applicable --> 

:backhand_index_pointing_right: Additional Context


Any Additional Context you would like to provide?
Add any other relevant information, such as recent updates to the SDK, dependencies, or device OS that may affect the bug.

<!-- Answer here if applicable  --> 

This bug is also present in VUIC carousel..

Selection strategy=“pinned”, pinnedFocusOffset=“start” also produces the bug..This is a bug also present in vertical carousels.

Hi @Rishabh_Ritweek ,

Thank you for raising this bug and providing the details.

I have reported this to our component team to look into.

Thanks,
Rohit

Thanks @Amz_Rsk , there is another bug that I have identified.May be, the root cause are related: Vega carousel starts to behave anchored when item is removed, selection strategy is pinned and pinned focus offset is start