Skip to content

Commit 2142436

Browse files
committed
OP: fix eslint errors & warnings
1 parent ae3727e commit 2142436

File tree

1 file changed

+101
-80
lines changed
  • packages/main/src/components/ObjectPage

1 file changed

+101
-80
lines changed

packages/main/src/components/ObjectPage/index.tsx

Lines changed: 101 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,12 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
118118
}, [mode, children, internalSelectedSectionId]);
119119

120120
const onSelectedSectionChangeRef = useRef(onSelectedSectionChange);
121-
// Keep ref in sync with prop to avoid stale closure in debounced function
122-
// eslint-disable-next-line react-hooks/refs
121+
const onToggleHeaderAreaRef = useRef(onToggleHeaderArea);
122+
const onScrollRef = useRef(rest.onScroll);
123+
// Keep refs in sync with props to avoid stale closure
123124
onSelectedSectionChangeRef.current = onSelectedSectionChange;
125+
onToggleHeaderAreaRef.current = onToggleHeaderArea;
126+
onScrollRef.current = rest.onScroll;
124127

125128
const fireOnSelectedChangedEvent = (targetEvent, index: number | string, id: string, section) => {
126129
if (
@@ -138,14 +141,16 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
138141
prevInternalSelectedSectionId.current = id;
139142
}
140143
};
141-
// Extracting .current immediately is safe - useRef creates stable reference on mount
142-
// eslint-disable-next-line react-hooks/refs
143144
const debouncedOnSectionChange = useRef(debounce(fireOnSelectedChangedEvent, 500)).current;
144145
useEffect(() => {
145146
return () => {
146147
debouncedOnSectionChange.cancel();
147-
clearTimeout(selectionScrollTimeout.current);
148+
if (selectionScrollTimeout.current) {
149+
clearTimeout(selectionScrollTimeout.current);
150+
}
148151
};
152+
// debouncedOnSectionChange and selectionScrollTimeout are stable refs
153+
// eslint-disable-next-line react-hooks/exhaustive-deps
149154
}, []);
150155

151156
// observe heights of header parts
@@ -162,30 +167,33 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
162167
);
163168
const scrollPaddingBlock = `${Math.ceil(12 + topHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT + (!headerCollapsed && headerPinned ? headerContentHeight : 0))}px ${footerArea ? 'calc(var(--_ui5wcr-BarHeight) + 1.25rem)' : 0}`;
164169

165-
const onToggleHeaderContentVisibility = (e) => {
166-
isToggledRef.current = true;
167-
scrollTimeout.current = performance.now() + 500;
168-
setToggledCollapsedHeaderWasVisible(false);
169-
if (!e.detail.visible) {
170-
if (objectPageRef.current.scrollTop <= headerContentHeight) {
171-
setToggledCollapsedHeaderWasVisible(true);
172-
if (firstSectionId === internalSelectedSectionId || mode === ObjectPageMode.IconTabBar) {
173-
objectPageRef.current.scrollTop = 0;
170+
const onToggleHeaderContentVisibility = useCallback(
171+
(e) => {
172+
isToggledRef.current = true;
173+
scrollTimeout.current = performance.now() + 500;
174+
setToggledCollapsedHeaderWasVisible(false);
175+
if (!e.detail.visible) {
176+
if (objectPageRef.current.scrollTop <= headerContentHeight) {
177+
setToggledCollapsedHeaderWasVisible(true);
178+
if (firstSectionId === internalSelectedSectionId || mode === ObjectPageMode.IconTabBar) {
179+
objectPageRef.current.scrollTop = 0;
180+
}
181+
}
182+
setHeaderCollapsedInternal(true);
183+
setScrolledHeaderExpanded(false);
184+
} else {
185+
setHeaderCollapsedInternal(false);
186+
if (objectPageRef.current.scrollTop >= headerContentHeight && objectPageRef.current.scrollTop > 0) {
187+
setScrolledHeaderExpanded(true);
174188
}
175189
}
176-
setHeaderCollapsedInternal(true);
177-
setScrolledHeaderExpanded(false);
178-
} else {
179-
setHeaderCollapsedInternal(false);
180-
if (objectPageRef.current.scrollTop >= headerContentHeight && objectPageRef.current.scrollTop > 0) {
181-
setScrolledHeaderExpanded(true);
182-
}
183-
}
184-
};
190+
},
191+
[headerContentHeight, firstSectionId, internalSelectedSectionId, mode, objectPageRef],
192+
);
185193

186194
useEffect(() => {
187-
if (typeof onToggleHeaderArea === 'function' && isToggledRef.current) {
188-
onToggleHeaderArea(headerCollapsed !== true);
195+
if (typeof onToggleHeaderAreaRef.current === 'function' && isToggledRef.current) {
196+
onToggleHeaderAreaRef.current(headerCollapsed !== true);
189197
}
190198
}, [headerCollapsed]);
191199

@@ -202,7 +210,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
202210
},
203211
});
204212
}
205-
}, [headerCollapsed]);
213+
}, [headerCollapsed, onToggleHeaderContentVisibility, objectPageRef]);
206214

207215
const avatar = useMemo(() => {
208216
if (!image) {
@@ -228,52 +236,59 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
228236
}
229237
}, [image, imageShapeCircle]);
230238

231-
const scrollToSectionById = (id: string | undefined, isSubSection = false) => {
232-
const scroll = () => {
233-
const section = getSectionElementById(objectPageRef.current, isSubSection, id);
234-
scrollTimeout.current = performance.now() + 500;
235-
if (section) {
236-
const safeTopHeaderHeight = topHeaderHeight || prevTopHeaderHeight.current;
237-
238-
const scrollMargin =
239-
-1 /* reduce margin-block so that intersection observer detects correct section*/ +
240-
safeTopHeaderHeight +
241-
TAB_CONTAINER_HEADER_HEIGHT +
242-
(headerPinned && !headerCollapsed ? headerContentHeight : 0);
243-
section.style.scrollMarginBlockStart = scrollMargin + 'px';
244-
if (isSubSection) {
245-
section.focus();
246-
}
239+
const scrollToSectionById = useCallback(
240+
(id: string | undefined, isSubSection = false) => {
241+
const scroll = () => {
242+
const section = getSectionElementById(objectPageRef.current, isSubSection, id);
243+
scrollTimeout.current = performance.now() + 500;
244+
if (section) {
245+
const safeTopHeaderHeight = topHeaderHeight || prevTopHeaderHeight.current;
246+
247+
const scrollMargin =
248+
-1 /* reduce margin-block so that intersection observer detects correct section*/ +
249+
safeTopHeaderHeight +
250+
TAB_CONTAINER_HEADER_HEIGHT +
251+
(headerPinned && !headerCollapsed ? headerContentHeight : 0);
252+
section.style.scrollMarginBlockStart = scrollMargin + 'px';
253+
if (isSubSection) {
254+
section.focus();
255+
}
247256

248-
const sectionRect = section.getBoundingClientRect();
249-
const objectPageElement = objectPageRef.current;
250-
const objectPageRect = objectPageElement.getBoundingClientRect();
257+
const sectionRect = section.getBoundingClientRect();
258+
const objectPageElement = objectPageRef.current;
259+
const objectPageRect = objectPageElement.getBoundingClientRect();
251260

252-
// Calculate the top position of the section relative to the container
253-
objectPageElement.scrollTop = sectionRect.top - objectPageRect.top + objectPageElement.scrollTop - scrollMargin;
261+
// Calculate the top position of the section relative to the container
262+
objectPageElement.scrollTop =
263+
sectionRect.top - objectPageRect.top + objectPageElement.scrollTop - scrollMargin;
254264

255-
section.style.scrollMarginBlockStart = '';
265+
section.style.scrollMarginBlockStart = '';
266+
}
267+
};
268+
// In TabBar mode the section is only rendered when selected: delay scroll for subsection
269+
if (mode === ObjectPageMode.IconTabBar && isSubSection) {
270+
setTimeout(scroll, 300);
271+
} else {
272+
scroll();
256273
}
257-
};
258-
// In TabBar mode the section is only rendered when selected: delay scroll for subsection
259-
if (mode === ObjectPageMode.IconTabBar && isSubSection) {
260-
setTimeout(scroll, 300);
261-
} else {
262-
scroll();
263-
}
264-
};
274+
},
275+
[mode, topHeaderHeight, headerPinned, headerCollapsed, headerContentHeight, objectPageRef],
276+
);
265277

266-
const scrollToSection = (sectionId?: string) => {
267-
if (!sectionId) {
268-
return;
269-
}
270-
if (firstSectionId === sectionId) {
271-
objectPageRef.current?.scrollTo({ top: 0 });
272-
} else {
273-
scrollToSectionById(sectionId);
274-
}
275-
isProgrammaticallyScrolled.current = false;
276-
};
278+
const scrollToSection = useCallback(
279+
(sectionId?: string) => {
280+
if (!sectionId) {
281+
return;
282+
}
283+
if (firstSectionId === sectionId) {
284+
objectPageRef.current?.scrollTo({ top: 0 });
285+
} else {
286+
scrollToSectionById(sectionId);
287+
}
288+
isProgrammaticallyScrolled.current = false;
289+
},
290+
[firstSectionId, scrollToSectionById, objectPageRef],
291+
);
277292

278293
// section was selected by clicking on the tab bar buttons
279294
const handleOnSectionSelected: HandleOnSectionSelectedType = (targetEvent, newSelectionSectionId, index, section) => {
@@ -325,15 +340,15 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
325340
if (mode === ObjectPageMode.Default && isProgrammaticallyScrolled.current === true && !selectedSubSectionId) {
326341
scrollToSection(internalSelectedSectionId);
327342
}
328-
}, [internalSelectedSectionId, mode, selectedSubSectionId]);
343+
}, [internalSelectedSectionId, mode, selectedSubSectionId, scrollToSection]);
329344

330345
// Scrolling for Sub Section Selection
331346
useEffect(() => {
332347
if (selectedSubSectionId && isProgrammaticallyScrolled.current === true) {
333348
scrollToSectionById(selectedSubSectionId, true);
334349
isProgrammaticallyScrolled.current = false;
335350
}
336-
}, [selectedSubSectionId, sectionSpacer]);
351+
}, [selectedSubSectionId, sectionSpacer, scrollToSectionById]);
337352

338353
useEffect(() => {
339354
if (headerPinnedProp !== undefined) {
@@ -342,7 +357,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
342357
if (headerPinnedProp) {
343358
onToggleHeaderContentVisibility({ detail: { visible: true } });
344359
}
345-
}, [headerPinnedProp]);
360+
}, [headerPinnedProp, onToggleHeaderContentVisibility]);
346361

347362
const prevHeaderPinned = useRef(headerPinned);
348363
useEffect(() => {
@@ -353,7 +368,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
353368
if (!prevHeaderPinned.current && headerPinned) {
354369
prevHeaderPinned.current = true;
355370
}
356-
}, [headerPinned, topHeaderHeight]);
371+
}, [headerPinned, topHeaderHeight, onToggleHeaderContentVisibility, objectPageRef]);
357372

358373
const isInitialTabBarMode = useRef(true);
359374
useEffect(() => {
@@ -394,7 +409,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
394409
}
395410
}
396411
isInitialTabBarMode.current = false;
397-
}, [props.selectedSubSectionId, isMounted]);
412+
}, [props.selectedSubSectionId, isMounted, childrenArray, debouncedOnSectionChange, mode]);
398413

399414
const tabContainerContainerRef = useRef(null);
400415
const isHeaderPinnedAndExpanded = headerPinned && !headerCollapsed;
@@ -457,7 +472,15 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
457472
return () => {
458473
observer.disconnect();
459474
};
460-
}, [topHeaderHeight, headerContentHeight, currentTabModeSection, children, mode, isHeaderPinnedAndExpanded]);
475+
}, [
476+
topHeaderHeight,
477+
headerContentHeight,
478+
currentTabModeSection,
479+
children,
480+
mode,
481+
isHeaderPinnedAndExpanded,
482+
objectPageRef,
483+
]);
461484

462485
const { onScroll: _0, selectedSubSectionId: _1, ...propsWithoutOmitted } = rest;
463486

@@ -519,6 +542,8 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
519542
childrenArray.length,
520543
scrolledHeaderExpanded,
521544
mode,
545+
objectPageRef,
546+
debouncedOnSectionChange,
522547
]);
523548

524549
const onTitleClick = (e) => {
@@ -568,8 +593,8 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
568593
}
569594
setToggledCollapsedHeaderWasVisible(false);
570595
scrollEvent.current = e;
571-
if (typeof props.onScroll === 'function') {
572-
props.onScroll(e);
596+
if (typeof onScrollRef.current === 'function') {
597+
onScrollRef.current(e);
573598
}
574599
if (selectedSubSectionId) {
575600
setSelectedSubSectionId(undefined);
@@ -591,7 +616,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
591616
setScrolledHeaderExpanded(false);
592617
}
593618
},
594-
[topHeaderHeight, headerPinned, props.onScroll, scrolledHeaderExpanded, selectedSubSectionId],
619+
[headerPinned, scrolledHeaderExpanded, selectedSubSectionId, objectPageRef, scrollEndHandler],
595620
);
596621

597622
const onHoverToggleButton: MouseEventHandler<HTMLHeadElement> = useCallback((e) => {
@@ -602,8 +627,6 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
602627
}
603628
}, []);
604629

605-
// Passing refs to custom hooks is normal React usage
606-
// eslint-disable-next-line react-hooks/refs
607630
const handleTabSelect = useHandleTabSelect({
608631
onBeforeNavigate,
609632
headerPinned,
@@ -692,8 +715,6 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
692715
data-component-name="ObjectPageTitleAreaClickElement"
693716
/>
694717
{titleArea &&
695-
// Passing props (including refs via cloneElement) is normal React usage
696-
// eslint-disable-next-line react-hooks/refs
697718
cloneElement(titleArea as ReactElement<ObjectPageTitlePropsWithDataAttributes>, {
698719
className: clsx(titleArea?.props?.className),
699720
onToggleHeaderContentVisibility: onTitleClick,

0 commit comments

Comments
 (0)