Skip to content

Commit

Permalink
fix(ui5-tabcontainer): fix drag and drop issue with home key and fixе…
Browse files Browse the repository at this point in the history
…d tabs (#9812)
  • Loading branch information
dimovpetar authored Sep 9, 2024
1 parent e64c8f1 commit 485fd0d
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 63 deletions.
41 changes: 28 additions & 13 deletions packages/base/src/util/dragAndDrop/findClosestPosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,38 +74,53 @@ const findClosestPosition = (elements: Array<HTMLElement>, point: number, layout
};
};

const findClosestPositionByKey = (elements: Array<HTMLElement>, element: HTMLElement, e: KeyboardEvent) => {
let placement;
const findClosestPositionsByKey = (elements: Array<HTMLElement>, element: HTMLElement, e: KeyboardEvent) => {
let index = elements.indexOf(element);
const positions = [];

switch (e.key) {
case "ArrowLeft":
case "ArrowUp":
placement = MovePlacement.Before;
index--;
if (index >= 0) {
positions.push({
element: elements[index],
placement: MovePlacement.Before,
});
}
break;
case "ArrowRight":
case "ArrowDown":
placement = MovePlacement.After;
index++;
if (index < elements.length) {
positions.push({
element: elements[index],
placement: MovePlacement.After,
});
}
break;
case "Home":
placement = MovePlacement.Before;
index = 0;
elements.forEach(el => {
positions.push({
element: el,
placement: MovePlacement.Before,
});
});
break;
case "End":
placement = MovePlacement.After;
index = elements.length - 1;
elements.reverse().forEach(el => {
positions.push({
element: el,
placement: MovePlacement.After,
});
});
break;
}

return {
element: elements[index],
placement,
};
return positions;
};

export {
findClosestPosition,
findClosestPositionByKey,
findClosestPositionsByKey,
};
34 changes: 18 additions & 16 deletions packages/main/src/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
isCtrl,
} from "@ui5/webcomponents-base/dist/Keys.js";
import DragRegistry from "@ui5/webcomponents-base/dist/util/dragAndDrop/DragRegistry.js";
import { findClosestPosition, findClosestPositionByKey } from "@ui5/webcomponents-base/dist/util/dragAndDrop/findClosestPosition.js";
import { findClosestPosition, findClosestPositionsByKey } from "@ui5/webcomponents-base/dist/util/dragAndDrop/findClosestPosition.js";
import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js";
import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js";
import getNormalizedTarget from "@ui5/webcomponents-base/dist/util/getNormalizedTarget.js";
Expand Down Expand Up @@ -906,27 +906,16 @@ class List extends UI5Element {
return;
}

const { placement, element } = findClosestPositionByKey(this.items, item, e);
const closestPositions = findClosestPositionsByKey(this.items, item, e);

if (!element || !placement) {
if (!closestPositions.length) {
return;
}

e.preventDefault();

const placementAccepted = !this.fireEvent<ListMoveEventDetail>("move-over", {
originalEvent: e,
source: {
element: item,
},
destination: {
element,
placement,
},
}, true);

if (placementAccepted) {
this.fireEvent<ListMoveEventDetail>("move", {
const acceptedPosition = closestPositions.find(({ element, placement }) => {
return !this.fireEvent<ListMoveEventDetail>("move-over", {
originalEvent: e,
source: {
element: item,
Expand All @@ -935,6 +924,19 @@ class List extends UI5Element {
element,
placement,
},
}, true);
});

if (acceptedPosition) {
this.fireEvent<ListMoveEventDetail>("move", {
originalEvent: e,
source: {
element: item,
},
destination: {
element: acceptedPosition.element,
placement: acceptedPosition.placement,
},
});

item.focus();
Expand Down
70 changes: 37 additions & 33 deletions packages/main/src/TabContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { getScopedVarName } from "@ui5/webcomponents-base/dist/CustomElementsSco
import "@ui5/webcomponents-icons/dist/slim-arrow-up.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
import arraysAreEqual from "@ui5/webcomponents-base/dist/util/arraysAreEqual.js";
import { findClosestPosition, findClosestPositionByKey } from "@ui5/webcomponents-base/dist/util/dragAndDrop/findClosestPosition.js";
import { findClosestPosition, findClosestPositionsByKey } from "@ui5/webcomponents-base/dist/util/dragAndDrop/findClosestPosition.js";
import Orientation from "@ui5/webcomponents-base/dist/types/Orientation.js";
import DragRegistry from "@ui5/webcomponents-base/dist/util/dragAndDrop/DragRegistry.js";
import type { SetDraggedElementFunction } from "@ui5/webcomponents-base/dist/util/dragAndDrop/DragRegistry.js";
Expand Down Expand Up @@ -615,46 +615,48 @@ class TabContainer extends UI5Element {
return;
}

const headerItems = this.items.map(item => item.getDomRefInStrip()).filter((item): item is TabInStrip => !item?.hasAttribute("hidden"));
let { placement, element } = findClosestPositionByKey(headerItems, tab.getDomRefInStrip()!, e);
const headerItems = this.items.map(item => item.getDomRefInStrip())
.filter((item): item is TabInStrip => !item?.hasAttribute("hidden"));
let positions = findClosestPositionsByKey(headerItems, tab.getDomRefInStrip()!, e);

if (!element || !placement) {
return;
}

while (element && (element as TabInStrip).realTabReference.hasAttribute("ui5-tab-separator") && placement === MovePlacement.Before) {
element = element.previousElementSibling as HTMLElement;
placement = MovePlacement.After;
}

while (element && (element as TabInStrip).realTabReference.hasAttribute("ui5-tab-separator") && placement === MovePlacement.After) {
element = element.nextElementSibling as HTMLElement;
placement = MovePlacement.Before;
}
positions = positions.map(({ element, placement }) => {
while (element && (element as TabInStrip).realTabReference.hasAttribute("ui5-tab-separator") && placement === MovePlacement.Before) {
element = headerItems.at(headerItems.indexOf(element as TabInStrip) - 1) as HTMLElement;
placement = MovePlacement.After;
}

if (!element) {
return;
}
while (element && (element as TabInStrip).realTabReference.hasAttribute("ui5-tab-separator") && placement === MovePlacement.After) {
element = headerItems.at(headerItems.indexOf(element as TabInStrip) + 1) as HTMLElement;
placement = MovePlacement.Before;
}

const placementAccepted = !this.fireEvent<TabContainerMoveEventDetail>("move-over", {
source: {
element: tab,
},
destination: {
element: (element as TabInStrip).realTabReference,
return {
element,
placement,
},
}, true);
};
});

if (placementAccepted) {
this.fireEvent<TabContainerMoveEventDetail>("move", {
const acceptedPosition = positions.find(({ element, placement }) => {
return !this.fireEvent<TabContainerMoveEventDetail>("move-over", {
source: {
element: tab,
},
destination: {
element: (element as TabInStrip).realTabReference,
placement,
},
}, true);
});

if (acceptedPosition) {
this.fireEvent<TabContainerMoveEventDetail>("move", {
source: {
element: tab,
},
destination: {
element: (acceptedPosition.element as TabInStrip).realTabReference,
placement: acceptedPosition.placement,
},
});

tab.focus();
Expand All @@ -674,6 +676,7 @@ class TabContainer extends UI5Element {
const draggedElement = DragRegistry.getDraggedElement()!;
let destinationElement: HTMLElement = (destination.element as TabInStrip | TabSeparatorInStrip).realTabReference;

// workaround to simulate tree behavior
if (e.detail.originalEvent instanceof KeyboardEvent) {
const realTabReference = (source.element as TabInOverflow).realTabReference;
const siblings = this._findSiblings(realTabReference);
Expand All @@ -685,8 +688,8 @@ class TabContainer extends UI5Element {
});
}

const nextPlacement = findClosestPositionByKey(items, realTabReference, e.detail.originalEvent);
destinationElement = nextPlacement.element;
const nextPosition = findClosestPositionsByKey(items, realTabReference, e.detail.originalEvent);
destinationElement = nextPosition[0]?.element;
}

if (!destinationElement) {
Expand Down Expand Up @@ -723,6 +726,7 @@ class TabContainer extends UI5Element {
const draggedElement = DragRegistry.getDraggedElement()!;
let destinationElement: HTMLElement = (destination.element as TabInStrip).realTabReference;

// Workaround to simulate tree behavior
if (e.detail.originalEvent instanceof KeyboardEvent) {
const realTabReference = (source.element as TabInOverflow).realTabReference;
const siblings = this._findSiblings(realTabReference);
Expand All @@ -734,8 +738,8 @@ class TabContainer extends UI5Element {
});
}

const nextPlacement = findClosestPositionByKey(items, realTabReference, e.detail.originalEvent);
destinationElement = nextPlacement.element;
const nextPosition = findClosestPositionsByKey(items, realTabReference, e.detail.originalEvent);
destinationElement = nextPosition[0]?.element;
}

if (!destinationElement) {
Expand Down
2 changes: 1 addition & 1 deletion packages/main/test/pages/TabContainerDragAndDrop.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ <h2>Fixed Tabs</h2>
<ui5-tab-separator id="fixedTabsSeparatorOne"></ui5-tab-separator>
<ui5-tab movable text="Four"></ui5-tab>
<ui5-tab movable text="Five"></ui5-tab>
<ui5-tab movable text="Six"></ui5-tab>
<ui5-tab id="fixedTabsTabSix" movable text="Six"></ui5-tab>
<ui5-tab id="fixedTabsTabSeven" movable text="Seven"></ui5-tab>
<ui5-tab movable design="Positive" text="Eight"></ui5-tab>
<ui5-tab movable design="Negative" text="Nine"></ui5-tab>
Expand Down
7 changes: 7 additions & 0 deletions packages/main/test/specs/TabContainerDragAndDrop.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,5 +344,12 @@ describe("Keyboard drag and drop tests", () => {

assert.strictEqual(await browser.$("#fixedTabsTabSeven").previousElement().getAttribute("id"), "fixedTabsSeparatorOne", "Tab seven has stopped when reached fixed tabs");
});

it("Moving strip item with Home", async () => {
await tabContainer.focusItem("fixedTabsTabSix");
await browser.keys(["Control", "Home"]);

assert.strictEqual(await browser.$("#fixedTabsTabSix").previousElement().getAttribute("id"), "fixedTabsSeparatorOne", "Tab six is placed after fixed tabs");
});
});
});

0 comments on commit 485fd0d

Please sign in to comment.