@fire-spark/storefront convierte ese árbol en secciones. @fire-spark/rn-ui deja la navegación de categorías en la sección que está en pantalla.
@fire-spark/react-ui (web) sigue en el modo por offset. Las listas virtualizadas son un tema de React Native.
Aplana el catálogo
flattenMenuCategories recorre el menú en profundidad. El instanceId de cada sección es la ruta de ids de categoría (food/mains), así la misma categoría puede aparecer bajo dos padres.
Filas para una lista virtualizada
buildMenuRows convierte esas secciones en filas que una lista puede reciclar. No renderiza nada. El tipo del producto es el que guardes en el mapa.
header (sectionId es instanceId). Después van las filas de producto, y index vuelve a 0 en cada sección. Una fila empty se agrega solo cuando la sección no tiene productos ni ítems CATEGORY, así un padre que solo agrupa subcategorías no muestra un estado vacío.
Las claves siguen siendo únicas cuando un producto está en dos secciones:
first es verdadero solo en el primer header.
spanMenuRow pone layout.span en el número de columnas de la lista cuando la fila no es un producto. Las celdas de producto quedan con span uno.
Scroll-spy en un scroll view simple
Pasa los ids de sección y la ref del scroll view.registerCategory guarda el y de cada sección. onScroll elige la última sección cuyo tope está en o sobre la línea del offset. selectCategory se desplaza hasta ahí.
active.registerCategory(section.instanceId) en el onLayout de la sección, y active.onScroll en el scroll view.
Scroll-spy en una lista virtualizada
Las filas fuera de pantalla no están montadas, así que faltan los offsets de layout. Pasa el modo por índice. El hook no importa un paquete de listas. Cualquier ref conscrollToIndex encaja, incluidas FlashList, FlatList y LegendList.
- Spy.
onScrollleelistRef.current.getFirstVisibleIndex()y mapea esa fila arowSectionIds. Puedes llamarlo sin evento. Para FlatList, pasaactive.onViewableItemsChanged. Usa el índice visible más bajo. - Salto.
selectCategory(id)llamascrollToIndex({ index: headerIndex.get(id), animated: true, viewOffset: offset }). No esperes la promesa que devuelve FlashList. - Bloqueo. Mientras el salto se anima, los eventos de scroll no mueven el resaltado. El bloqueo se suelta 140 ms después de que el scroll se detiene, o después de 1 s si la lista nunca se desplaza.
- Deep link.
initialCategoryIdes la sección activa antes del primer scroll. Si ese id sale deheaderIndex, el id activo vuelve a la primera sección.
registerCategory no hace nada en este modo. Los primitivos Category* son vistas simples, así que se renderizan dentro de una celda sin otros cambios.