Skip to content

Commit d1c8b9c

Browse files
committed
fix(ui5-list): growing with scroll improved
1 parent b392d46 commit d1c8b9c

File tree

2 files changed

+60
-44
lines changed

2 files changed

+60
-44
lines changed

packages/main/src/List.ts

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ import type CheckBox from "./CheckBox.js";
7373
import type RadioButton from "./RadioButton.js";
7474
import { isInstanceOfListItemGroup } from "./ListItemGroup.js";
7575
import type ListItemGroup from "./ListItemGroup.js";
76-
import { findVerticalScrollContainer } from "./TableUtils.js";
7776

7877
const INFINITE_SCROLL_DEBOUNCE_RATE = 250; // ms
7978

@@ -525,17 +524,17 @@ class List extends UI5Element {
525524
static i18nBundle: I18nBundle;
526525
_previouslyFocusedItem: ListItemBase | null;
527526
_forwardingFocus: boolean;
528-
listEndObserved: boolean;
529-
_handleResizeCallback: ResizeObserverCallback;
530-
initialIntersection: boolean;
531527
_selectionRequested?: boolean;
532528
_groupCount: number;
533529
_groupItemCount: number;
534-
growingIntersectionObserver?: IntersectionObserver | null;
530+
_endIntersectionObserver?: IntersectionObserver | null;
531+
_startIntersectionObserver?: IntersectionObserver | null;
535532
_itemNavigation: ItemNavigation;
536533
_beforeElement?: HTMLElement | null;
537534
_afterElement?: HTMLElement | null;
535+
_startMarkerOutOfView: boolean = false;
538536

537+
handleResizeCallback: ResizeObserverCallback;
539538
onItemFocusedBound: (e: CustomEvent) => void;
540539
onForwardAfterBound: (e: CustomEvent) => void;
541540
onForwardBeforeBound: (e: CustomEvent) => void;
@@ -551,20 +550,14 @@ class List extends UI5Element {
551550
// Indicates that the List is forwarding the focus before or after the internal ul.
552551
this._forwardingFocus = false;
553552

554-
// Indicates if the IntersectionObserver started observing the List
555-
this.listEndObserved = false;
556-
557553
this._itemNavigation = new ItemNavigation(this, {
558554
skipItemsSize: PAGE_UP_DOWN_SIZE, // PAGE_UP and PAGE_DOWN will skip trough 10 items
559555
navigationMode: NavigationMode.Vertical,
560556
getItemsCallback: () => this.getEnabledItems(),
561557
});
562558

563-
this._handleResizeCallback = this._handleResize.bind(this);
559+
this.handleResizeCallback = this._handleResize.bind(this);
564560

565-
// Indicates the List bottom most part has been detected by the IntersectionObserver
566-
// for the first time.
567-
this.initialIntersection = true;
568561
this._groupCount = 0;
569562
this._groupItemCount = 0;
570563

@@ -600,13 +593,14 @@ class List extends UI5Element {
600593
onEnterDOM() {
601594
registerUI5Element(this, this._updateAssociatedLabelsTexts.bind(this));
602595
DragRegistry.subscribe(this);
603-
ResizeHandler.register(this.getDomRef()!, this._handleResizeCallback);
596+
ResizeHandler.register(this.getDomRef()!, this.handleResizeCallback);
604597
}
605598

606599
onExitDOM() {
607600
deregisterUI5Element(this);
608601
this.unobserveListEnd();
609-
ResizeHandler.deregister(this.getDomRef()!, this._handleResizeCallback);
602+
this.unobserveListStart();
603+
ResizeHandler.deregister(this.getDomRef()!, this.handleResizeCallback);
610604
DragRegistry.unsubscribe(this);
611605
}
612606

@@ -617,11 +611,10 @@ class List extends UI5Element {
617611

618612
onAfterRendering() {
619613
this.attachGroupHeaderEvents();
620-
if (this.growsOnScroll) {
621-
this.observeListEnd();
622-
} else if (this.listEndObserved) {
623-
this.unobserveListEnd();
624-
}
614+
this.unobserveListEnd();
615+
this.unobserveListStart();
616+
this.observeListEnd();
617+
this.observeListStart();
625618

626619
if (this.grows) {
627620
this.checkListInViewport();
@@ -670,6 +663,10 @@ class List extends UI5Element {
670663
return this.shadowRoot!.querySelector(".ui5-list-end-marker");
671664
}
672665

666+
get listStartDOM() {
667+
return this.shadowRoot!.querySelector(".ui5-list-start-marker");
668+
}
669+
673670
get dropIndicatorDOM(): DropIndicator | null {
674671
return this.shadowRoot!.querySelector("[ui5-drop-indicator]");
675672
}
@@ -736,13 +733,9 @@ class List extends UI5Element {
736733
return this.accessibilityAttributes.growingButton?.name ? undefined : `${this._id}-growingButton-text`;
737734
}
738735

739-
get scrollContainer() {
740-
return this.shadowRoot!.querySelector<HTMLElement>(".ui5-list-scroll-container");
741-
}
742-
743736
hasGrowingComponent(): boolean {
744-
if (this.growsOnScroll && this.scrollContainer) {
745-
return this.scrollContainer.clientHeight !== this.scrollContainer.scrollHeight;
737+
if (this.growsOnScroll) {
738+
return this._startMarkerOutOfView;
746739
}
747740

748741
return this.growsWithButton;
@@ -824,33 +817,43 @@ class List extends UI5Element {
824817
}
825818

826819
async observeListEnd() {
827-
if (!this.listEndObserved) {
828-
await renderFinished();
829-
this.getIntersectionObserver().observe(this.listEndDOM!);
830-
this.listEndObserved = true;
831-
}
820+
await renderFinished();
821+
this.getIntersectionObserver().observe(this.listEndDOM!);
832822
}
833823

834824
unobserveListEnd() {
835-
if (this.growingIntersectionObserver) {
836-
this.growingIntersectionObserver.disconnect();
837-
this.growingIntersectionObserver = null;
838-
this.listEndObserved = false;
825+
if (this._endIntersectionObserver) {
826+
this._endIntersectionObserver.disconnect();
827+
this._endIntersectionObserver = null;
839828
}
840829
}
841830

842-
onInteresection(entries: Array<IntersectionObserverEntry>) {
843-
if (this.initialIntersection) {
844-
this.initialIntersection = false;
845-
return;
831+
async observeListStart() {
832+
await renderFinished();
833+
this.get_StartIntersectionObserver().observe(this.listStartDOM!);
834+
}
835+
836+
unobserveListStart() {
837+
if (this._startIntersectionObserver) {
838+
this._startIntersectionObserver.disconnect();
839+
this._startIntersectionObserver = null;
846840
}
841+
}
842+
843+
onEndIntersection(entries: Array<IntersectionObserverEntry>) {
847844
entries.forEach(entry => {
848845
if (entry.isIntersecting) {
849846
debounce(this.loadMore.bind(this), INFINITE_SCROLL_DEBOUNCE_RATE);
850847
}
851848
});
852849
}
853850

851+
onStartIntersection(entries: Array<IntersectionObserverEntry>) {
852+
entries.forEach(entry => {
853+
this._startMarkerOutOfView = !entry.isIntersecting;
854+
});
855+
}
856+
854857
/*
855858
* ITEM SELECTION BASED ON THE CURRENT MODE
856859
*/
@@ -1444,17 +1447,27 @@ class List extends UI5Element {
14441447
}
14451448

14461449
getIntersectionObserver() {
1447-
if (!this.growingIntersectionObserver) {
1448-
const scrollContainer = this.scrollContainer || findVerticalScrollContainer(this.getDomRef()!);
1450+
if (!this._endIntersectionObserver) {
1451+
this._endIntersectionObserver = new IntersectionObserver(this.onEndIntersection.bind(this), {
1452+
root: null, // null means the viewport
1453+
rootMargin: "0px",
1454+
threshold: 1.0,
1455+
});
1456+
}
1457+
1458+
return this._endIntersectionObserver;
1459+
}
14491460

1450-
this.growingIntersectionObserver = new IntersectionObserver(this.onInteresection.bind(this), {
1451-
root: scrollContainer,
1452-
rootMargin: "5px",
1461+
get_StartIntersectionObserver() {
1462+
if (!this._startIntersectionObserver) {
1463+
this._startIntersectionObserver = new IntersectionObserver(this.onStartIntersection.bind(this), {
1464+
root: null, // null means the viewport
1465+
rootMargin: "0px",
14531466
threshold: 1.0,
14541467
});
14551468
}
14561469

1457-
return this.growingIntersectionObserver;
1470+
return this._startIntersectionObserver;
14581471
}
14591472
}
14601473

packages/main/src/ListTemplate.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ export default function ListTemplate(this: List) {
2929
active={this.showBusyIndicatorOverlay}
3030
class="ui5-list-busy-indicator"
3131
>
32+
3233
<div class="ui5-list-scroll-container">
34+
<span tabindex={-1} aria-hidden="true" class="ui5-list-start-marker"></span>
35+
3336
{this.header.length > 0 && <slot name="header" />}
3437

3538
{this.shouldRenderH1 &&

0 commit comments

Comments
 (0)