diff --git a/packages/@lightningjs/ui-components/src/mixins/withEditItems/index.js b/packages/@lightningjs/ui-components/src/mixins/withEditItems/index.js index 91aea939c..302f0ad94 100644 --- a/packages/@lightningjs/ui-components/src/mixins/withEditItems/index.js +++ b/packages/@lightningjs/ui-components/src/mixins/withEditItems/index.js @@ -4,7 +4,6 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software @@ -37,60 +36,69 @@ export default function (Base) { super._unfocus(); } + _selectedChange(selected, prevSelected) { + if (this.isEditing) return; + this._render(selected, prevSelected); + this.signal('selectedChange', selected, prevSelected); + } + get selectedIndex() { - return this._selectedIndex; + return super.selectedIndex; } + set selectedIndex(index) { if (!this.isEditing) { super.selectedIndex = index; return; } + if ( this.selectedIndex >= this.items.length - 1 && index > this.selectedIndex ) { return; } + const currentItem = this.selected; this.prevSelected = currentItem; const nextItem = this.items[index]; const previousIndex = this.selectedIndex; - const oldPosX = currentItem.transition('x') - ? currentItem.transition('x').targetValue - : currentItem.x; - const oldPosY = currentItem.transition('y') - ? currentItem.transition('y').targetValue - : currentItem.y; - const newPosX = nextItem.transition('x') - ? nextItem.transition('x').targetValue - : nextItem.x; - const newPosY = nextItem.transition('y') - ? nextItem.transition('y').targetValue - : nextItem.y; + + const getPositionValue = (item, axis) => + item.transition(axis) ? item.transition(axis).targetValue : item[axis]; + const oldPos = { + x: getPositionValue(currentItem, 'x'), + y: getPositionValue(currentItem, 'y') + }; + const newPos = { + x: getPositionValue(nextItem, 'x'), + y: getPositionValue(nextItem, 'y') + }; this._swapItemArrayPos(this.items, index, previousIndex); + currentItem.setSmooth('x', newPos.x); + currentItem.setSmooth('y', newPos.y); + nextItem.setSmooth('x', oldPos.x); + nextItem.setSmooth('y', oldPos.y); + + const waitForTransition = (item, axis) => + new Promise(resolve => item._getTransition(axis).on('finish', resolve)); - // self invoking async function that waits for setSmooth calls to complete before triggering - // render and signaling selected changed event. - // This allows time for items to be in their final position before the row component check world context - // to identify items off screen to trigger scrolling (async () => { - await currentItem.setSmooth('x', newPosX); - await currentItem.setSmooth('y', newPosY); - await nextItem.setSmooth('x', oldPosX); - await nextItem.setSmooth('y', oldPosY); + await Promise.all([ + waitForTransition(currentItem, 'x'), + waitForTransition(currentItem, 'y'), + waitForTransition(nextItem, 'x'), + waitForTransition(nextItem, 'y') + ]); + if ( !this.Items.children.length || - !this.Items.children[index] || - !this.Items.children[index].skipFocus + !this.Items.children[index]?.skipFocus ) { - if (this.selected) { - this._selectedIndex = index; - this._render(this.selected, this.prevSelected); - this.signal('selectedChange', this.selected, this.prevSelected); - } - // Don't call refocus until after a new render in case of a situation like Plinko nav - // where we don't want to focus the previously selected item and need to get the new one first + this._selectedIndex = index; + this._render(this.selected, this.prevSelected); + this.signal('selectedChange', this.selected, this.prevSelected); this._refocus(); } })();