@@ -1638,26 +1750,6 @@ describe("List Tests", () => {
.should("have.attr", "tabindex", "0");
});
- it("End marker has correct CSS properties", () => {
- cy.mount(
-
- Laptop Lenovo
- IPhone 3
- HP Monitor 24
- Audio cabel
- DVD set
- HP Monitor 24
- Audio cabel
- Last Item
-
- );
-
- cy.get("[ui5-list]")
- .shadow()
- .find(".ui5-list-end-marker")
- .should("have.css", "display", "inline-block");
- });
-
it("Checks if tooltip property value equals the title of li element", () => {
cy.mount(
diff --git a/packages/main/src/List.ts b/packages/main/src/List.ts
index 195c18227460..976f0d7570a3 100644
--- a/packages/main/src/List.ts
+++ b/packages/main/src/List.ts
@@ -73,7 +73,6 @@ import type CheckBox from "./CheckBox.js";
import type RadioButton from "./RadioButton.js";
import { isInstanceOfListItemGroup } from "./ListItemGroup.js";
import type ListItemGroup from "./ListItemGroup.js";
-import { findVerticalScrollContainer } from "./TableUtils.js";
const INFINITE_SCROLL_DEBOUNCE_RATE = 250; // ms
@@ -525,17 +524,17 @@ class List extends UI5Element {
static i18nBundle: I18nBundle;
_previouslyFocusedItem: ListItemBase | null;
_forwardingFocus: boolean;
- listEndObserved: boolean;
- _handleResizeCallback: ResizeObserverCallback;
- initialIntersection: boolean;
_selectionRequested?: boolean;
_groupCount: number;
_groupItemCount: number;
- growingIntersectionObserver?: IntersectionObserver | null;
+ _endIntersectionObserver?: IntersectionObserver | null;
+ _startIntersectionObserver?: IntersectionObserver | null;
_itemNavigation: ItemNavigation;
_beforeElement?: HTMLElement | null;
_afterElement?: HTMLElement | null;
+ _startMarkerOutOfView: boolean = false;
+ handleResizeCallback: ResizeObserverCallback;
onItemFocusedBound: (e: CustomEvent) => void;
onForwardAfterBound: (e: CustomEvent) => void;
onForwardBeforeBound: (e: CustomEvent) => void;
@@ -551,20 +550,14 @@ class List extends UI5Element {
// Indicates that the List is forwarding the focus before or after the internal ul.
this._forwardingFocus = false;
- // Indicates if the IntersectionObserver started observing the List
- this.listEndObserved = false;
-
this._itemNavigation = new ItemNavigation(this, {
skipItemsSize: PAGE_UP_DOWN_SIZE, // PAGE_UP and PAGE_DOWN will skip trough 10 items
navigationMode: NavigationMode.Vertical,
getItemsCallback: () => this.getEnabledItems(),
});
- this._handleResizeCallback = this._handleResize.bind(this);
+ this.handleResizeCallback = this._handleResize.bind(this);
- // Indicates the List bottom most part has been detected by the IntersectionObserver
- // for the first time.
- this.initialIntersection = true;
this._groupCount = 0;
this._groupItemCount = 0;
@@ -600,13 +593,14 @@ class List extends UI5Element {
onEnterDOM() {
registerUI5Element(this, this._updateAssociatedLabelsTexts.bind(this));
DragRegistry.subscribe(this);
- ResizeHandler.register(this.getDomRef()!, this._handleResizeCallback);
+ ResizeHandler.register(this.getDomRef()!, this.handleResizeCallback);
}
onExitDOM() {
deregisterUI5Element(this);
this.unobserveListEnd();
- ResizeHandler.deregister(this.getDomRef()!, this._handleResizeCallback);
+ this.unobserveListStart();
+ ResizeHandler.deregister(this.getDomRef()!, this.handleResizeCallback);
DragRegistry.unsubscribe(this);
}
@@ -617,11 +611,10 @@ class List extends UI5Element {
onAfterRendering() {
this.attachGroupHeaderEvents();
- if (this.growsOnScroll) {
- this.observeListEnd();
- } else if (this.listEndObserved) {
- this.unobserveListEnd();
- }
+ this.unobserveListEnd();
+ this.unobserveListStart();
+ this.observeListEnd();
+ this.observeListStart();
if (this.grows) {
this.checkListInViewport();
@@ -670,6 +663,10 @@ class List extends UI5Element {
return this.shadowRoot!.querySelector(".ui5-list-end-marker");
}
+ get listStartDOM() {
+ return this.shadowRoot!.querySelector(".ui5-list-start-marker");
+ }
+
get dropIndicatorDOM(): DropIndicator | null {
return this.shadowRoot!.querySelector("[ui5-drop-indicator]");
}
@@ -736,13 +733,9 @@ class List extends UI5Element {
return this.accessibilityAttributes.growingButton?.name ? undefined : `${this._id}-growingButton-text`;
}
- get scrollContainer() {
- return this.shadowRoot!.querySelector(".ui5-list-scroll-container");
- }
-
hasGrowingComponent(): boolean {
- if (this.growsOnScroll && this.scrollContainer) {
- return this.scrollContainer.clientHeight !== this.scrollContainer.scrollHeight;
+ if (this.growsOnScroll) {
+ return this._startMarkerOutOfView;
}
return this.growsWithButton;
@@ -824,26 +817,30 @@ class List extends UI5Element {
}
async observeListEnd() {
- if (!this.listEndObserved) {
- await renderFinished();
- this.getIntersectionObserver().observe(this.listEndDOM!);
- this.listEndObserved = true;
- }
+ await renderFinished();
+ this.getEndIntersectionObserver().observe(this.listEndDOM!);
}
unobserveListEnd() {
- if (this.growingIntersectionObserver) {
- this.growingIntersectionObserver.disconnect();
- this.growingIntersectionObserver = null;
- this.listEndObserved = false;
+ if (this._endIntersectionObserver) {
+ this._endIntersectionObserver.disconnect();
+ this._endIntersectionObserver = null;
}
}
- onInteresection(entries: Array) {
- if (this.initialIntersection) {
- this.initialIntersection = false;
- return;
+ async observeListStart() {
+ await renderFinished();
+ this.getStartIntersectionObserver().observe(this.listStartDOM!);
+ }
+
+ unobserveListStart() {
+ if (this._startIntersectionObserver) {
+ this._startIntersectionObserver.disconnect();
+ this._startIntersectionObserver = null;
}
+ }
+
+ onEndIntersection(entries: Array) {
entries.forEach(entry => {
if (entry.isIntersecting) {
debounce(this.loadMore.bind(this), INFINITE_SCROLL_DEBOUNCE_RATE);
@@ -851,6 +848,12 @@ class List extends UI5Element {
});
}
+ onStartIntersection(entries: Array) {
+ entries.forEach(entry => {
+ this._startMarkerOutOfView = !entry.isIntersecting;
+ });
+ }
+
/*
* ITEM SELECTION BASED ON THE CURRENT MODE
*/
@@ -1443,18 +1446,28 @@ class List extends UI5Element {
return this._beforeElement;
}
- getIntersectionObserver() {
- if (!this.growingIntersectionObserver) {
- const scrollContainer = this.scrollContainer || findVerticalScrollContainer(this.getDomRef()!);
+ getEndIntersectionObserver() {
+ if (!this._endIntersectionObserver) {
+ this._endIntersectionObserver = new IntersectionObserver(this.onEndIntersection.bind(this), {
+ root: null, // null means the viewport
+ rootMargin: "0px",
+ threshold: 1.0,
+ });
+ }
+
+ return this._endIntersectionObserver;
+ }
- this.growingIntersectionObserver = new IntersectionObserver(this.onInteresection.bind(this), {
- root: scrollContainer,
- rootMargin: "5px",
+ getStartIntersectionObserver() {
+ if (!this._startIntersectionObserver) {
+ this._startIntersectionObserver = new IntersectionObserver(this.onStartIntersection.bind(this), {
+ root: null, // null means the viewport
+ rootMargin: "0px",
threshold: 1.0,
});
}
- return this.growingIntersectionObserver;
+ return this._startIntersectionObserver;
}
}
diff --git a/packages/main/src/ListTemplate.tsx b/packages/main/src/ListTemplate.tsx
index d6262b1bdd9d..b3fd20cd80b2 100644
--- a/packages/main/src/ListTemplate.tsx
+++ b/packages/main/src/ListTemplate.tsx
@@ -29,7 +29,10 @@ export default function ListTemplate(this: List) {
active={this.showBusyIndicatorOverlay}
class="ui5-list-busy-indicator"
>
+
+
+
{this.header.length > 0 && }
{this.shouldRenderH1 &&