From f17a9c20dd601102607307dc6d27f329e8ac9384 Mon Sep 17 00:00:00 2001 From: Romain Lejeune Date: Mon, 13 Apr 2026 22:05:45 +0200 Subject: [PATCH 1/3] add wrap-around navigation for media rows --- .../app/src/components/MediaCard/MediaCard.js | 4 +- .../app/src/components/MediaRow/MediaRow.js | 48 ++++++++++++++----- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/packages/app/src/components/MediaCard/MediaCard.js b/packages/app/src/components/MediaCard/MediaCard.js index 1461573..047907b 100644 --- a/packages/app/src/components/MediaCard/MediaCard.js +++ b/packages/app/src/components/MediaCard/MediaCard.js @@ -10,7 +10,7 @@ const SpottableDiv = Spottable('div'); const POSTER_SIZE_MULTIPLIERS = {small: 0.8, default: 1, large: 1.2, xlarge: 1.4}; const BASE_SIZES = {portrait: [240, 360], landscape: [384, 216], square: [240, 240]}; -const MediaCard = ({item, serverUrl, cardType = 'portrait', onSelect, onFocusItem, showServerBadge = false, showOverview = false, eagerLoad = false}) => { +const MediaCard = ({item, serverUrl, cardType = 'portrait', onSelect, onFocusItem, showServerBadge = false, showOverview = false, eagerLoad = false, spotlightId, onSpotlightLeft, onSpotlightRight}) => { const {settings} = useSettings(); const isLandscape = cardType === 'landscape'; const isSquare = cardType === 'square' || (cardType === 'portrait' && (item.Type === 'MusicAlbum' || item.Type === 'MusicArtist' || item.Type === 'Audio')); @@ -132,7 +132,7 @@ const MediaCard = ({item, serverUrl, cardType = 'portrait', onSelect, onFocusIte const imgSizeStyle = sizeMultiplier !== 1 ? {height: cardHeight + 'px'} : undefined; return ( - +
{imageUrl ? ( { + e.preventDefault(); + e.stopPropagation(); + Spotlight.focus(`media-${keyPrefix}-${items[items.length - 1].Id}`); + }, [items, keyPrefix]); + + const handleWrapRight = useCallback((e) => { + e.preventDefault(); + e.stopPropagation(); + Spotlight.focus(`media-${keyPrefix}-${items[0].Id}`); + }, [items, keyPrefix]); + if (!items || items.length === 0) return null; return ( @@ -88,19 +101,28 @@ const MediaRow = ({

{title}

- {items.map((item) => ( - - ))} + {items.map((item, index) => { + const spotlightId = `media-${keyPrefix}-${item.Id}`; + const isFirst = index === 0; + const isLast = index === items.length - 1; + + return ( + + ); + })}
From d30fa69d3ddd7ae93e4660d6244fda619f8ccea4 Mon Sep 17 00:00:00 2001 From: Romain Lejeune Date: Mon, 13 Apr 2026 22:24:57 +0200 Subject: [PATCH 2/3] focus navbar on left-edge navigation --- packages/app/src/components/MediaRow/MediaRow.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/app/src/components/MediaRow/MediaRow.js b/packages/app/src/components/MediaRow/MediaRow.js index ccd246e..65f4417 100644 --- a/packages/app/src/components/MediaRow/MediaRow.js +++ b/packages/app/src/components/MediaRow/MediaRow.js @@ -3,6 +3,7 @@ import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDeco import Spotlight from '@enact/spotlight'; import MediaCard from '../MediaCard'; import {KEYS} from '../../utils/keys'; +import {useSettings} from '../../context/SettingsContext'; import css from './MediaRow.module.less'; @@ -27,6 +28,7 @@ const MediaRow = ({ className, registerRowRef }) => { + const {settings} = useSettings(); const scrollerRef = useRef(null); const scrollTimeoutRef = useRef(null); const rowElementRef = useRef(null); @@ -77,10 +79,14 @@ const MediaRow = ({ }, [rowIndex, onNavigateUp, onNavigateDown]); const handleWrapLeft = useCallback((e) => { - e.preventDefault(); - e.stopPropagation(); - Spotlight.focus(`media-${keyPrefix}-${items[items.length - 1].Id}`); - }, [items, keyPrefix]); + e.preventDefault(); + e.stopPropagation(); + if (settings.navbarPosition === 'left') { + Spotlight.focus('navbar'); + } else { + Spotlight.focus(`media-${keyPrefix}-${items[items.length - 1].Id}`); + } + }, [items, keyPrefix, settings.navbarPosition]); const handleWrapRight = useCallback((e) => { e.preventDefault(); From 338503b26b182aabf313680eaf2f48a7a5cc2768 Mon Sep 17 00:00:00 2001 From: Axl Nunez Date: Fri, 24 Apr 2026 17:46:26 -0400 Subject: [PATCH 3/3] added fallback so focus doesnt get lost in case of transition --- packages/app/src/components/MediaRow/MediaRow.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/app/src/components/MediaRow/MediaRow.js b/packages/app/src/components/MediaRow/MediaRow.js index 65f4417..f248101 100644 --- a/packages/app/src/components/MediaRow/MediaRow.js +++ b/packages/app/src/components/MediaRow/MediaRow.js @@ -82,17 +82,19 @@ const MediaRow = ({ e.preventDefault(); e.stopPropagation(); if (settings.navbarPosition === 'left') { - Spotlight.focus('navbar'); + if (!Spotlight.focus('navbar')) { + Spotlight.move('left'); + } } else { Spotlight.focus(`media-${keyPrefix}-${items[items.length - 1].Id}`); } }, [items, keyPrefix, settings.navbarPosition]); - const handleWrapRight = useCallback((e) => { - e.preventDefault(); - e.stopPropagation(); - Spotlight.focus(`media-${keyPrefix}-${items[0].Id}`); - }, [items, keyPrefix]); + const handleWrapRight = useCallback((e) => { + e.preventDefault(); + e.stopPropagation(); + Spotlight.focus(`media-${keyPrefix}-${items[0].Id}`); + }, [items, keyPrefix]); if (!items || items.length === 0) return null;