• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / ui5-webcomponents-react / 14170380248

31 Mar 2025 11:22AM CUT coverage: 88.191% (+0.7%) from 87.483%
14170380248

Pull #7150

github

web-flow
Merge 097519048 into f9557b7a0
Pull Request #7150: fix(ObjectPage): improve focus and scroll behavior

3145 of 4129 branches covered (76.17%)

40 of 77 new or added lines in 2 files covered. (51.95%)

7 existing lines in 1 file now uncovered.

5325 of 6038 relevant lines covered (88.19%)

163483.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/packages/main/src/components/ObjectPage/useHandleTabSelect.ts
1
import type { debounce } from '@ui5/webcomponents-react-base';
2
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
3
import type { Dispatch, JSXElementConstructor, ReactElement, RefObject, SetStateAction } from 'react';
4
import { isValidElement, useEffect, useState } from 'react';
5
import { ObjectPageMode } from '../../enums/ObjectPageMode.js';
6
import type { TabContainerPropTypes } from '../../webComponents/TabContainer/index.js';
7
import type { ObjectPageSectionPropTypes } from '../ObjectPageSection/index.js';
8
import type { ObjectPageDomRef, ObjectPagePropTypes } from './types/index.js';
9

10
interface UseHandleTabSelectProps {
11
  onBeforeNavigate: ObjectPagePropTypes['onBeforeNavigate'];
12
  headerPinned: boolean;
13
  mode: ObjectPagePropTypes['mode'];
14
  setHeaderCollapsedInternal: Dispatch<SetStateAction<boolean>>;
15
  setScrolledHeaderExpanded: Dispatch<SetStateAction<boolean>>;
16
  childrenArray: ReactElement<ObjectPageSectionPropTypes, string | JSXElementConstructor<any>>[];
17
  handleOnSectionSelected: any;
18

19
  isProgrammaticallyScrolled: RefObject<boolean>;
20
  setInternalSelectedSectionId: Dispatch<SetStateAction<string>>;
21
  objectPageRef: RefObject<ObjectPageDomRef>;
22
  debouncedOnSectionChange: ReturnType<typeof debounce>;
23
  scrollTimeout: RefObject<number>;
24
  setSelectedSubSectionId: Dispatch<SetStateAction<string>>;
25
}
26

27
export const useHandleTabSelect = ({
426✔
28
  onBeforeNavigate,
29
  headerPinned,
30
  mode,
31
  setHeaderCollapsedInternal,
32
  setScrolledHeaderExpanded,
33
  childrenArray,
34
  handleOnSectionSelected,
35

36
  isProgrammaticallyScrolled,
37
  setInternalSelectedSectionId,
38
  objectPageRef,
39
  debouncedOnSectionChange,
40
  scrollTimeout,
41
  setSelectedSubSectionId
42
}: UseHandleTabSelectProps) => {
NEW
43
  const [onSectionSelectedArgs, setOnSectionSelectedArgs] = useState<
18,978✔
44
    | false
45
    | [
46
        Parameters<TabContainerPropTypes['onTabSelect']>[0],
47
        undefined | string,
48
        string,
49
        ReactElement<ObjectPageSectionPropTypes>
50
      ]
51
  >(false);
52

NEW
53
  const handleOnSubSectionSelected = (e) => {
18,978✔
NEW
54
    isProgrammaticallyScrolled.current = true;
115✔
NEW
55
    if (mode === ObjectPageMode.IconTabBar) {
115✔
NEW
56
      const sectionId = e.detail.sectionId;
48✔
NEW
57
      setInternalSelectedSectionId(sectionId);
48✔
NEW
58
      const sectionNodes = objectPageRef.current?.querySelectorAll('section[data-component-name="ObjectPageSection"]');
48✔
NEW
59
      const currentIndex = childrenArray.findIndex((objectPageSection) => {
48✔
NEW
60
        return (
150✔
61
          isValidElement(objectPageSection) &&
300✔
62
          (objectPageSection as ReactElement<ObjectPagePropTypes>).props?.id === sectionId
63
        );
64
      });
NEW
65
      debouncedOnSectionChange(e, currentIndex, sectionId, sectionNodes[currentIndex]);
48✔
66
    }
NEW
67
    const subSectionId = e.detail.subSectionId;
115✔
NEW
68
    scrollTimeout.current = performance.now() + 200;
115✔
NEW
69
    setSelectedSubSectionId(subSectionId);
115✔
70
  };
71

NEW
72
  const handleTabItemSelect: TabContainerPropTypes['onTabSelect'] = (event) => {
18,978✔
NEW
73
    if (typeof onBeforeNavigate === 'function') {
476✔
NEW
74
      const selectedTabDataset = event.detail.tab.dataset;
14✔
NEW
75
      const sectionIndex = parseInt(selectedTabDataset.index, 10);
14✔
NEW
76
      const sectionId = selectedTabDataset.parentId ?? selectedTabDataset.sectionId;
14✔
NEW
77
      const subSectionId = Object.prototype.hasOwnProperty.call(selectedTabDataset, 'isSubTab')
14✔
78
        ? selectedTabDataset.sectionId
79
        : undefined;
NEW
80
      onBeforeNavigate(
14✔
81
        enrichEventWithDetails(event, {
82
          sectionIndex,
83
          sectionId,
84
          subSectionId
85
        })
86
      );
NEW
87
      if (event.defaultPrevented) {
14✔
NEW
88
        return;
14✔
89
      }
90
    }
NEW
91
    event.preventDefault();
462✔
NEW
92
    const { sectionId, index, isSubTab, parentId } = event.detail.tab.dataset;
462✔
NEW
93
    if (parseInt(index) !== 0 && !headerPinned && mode !== ObjectPageMode.IconTabBar) {
462✔
NEW
94
      setHeaderCollapsedInternal(true);
222✔
95
    }
NEW
96
    setScrolledHeaderExpanded(false);
462✔
NEW
97
    if (isSubTab !== undefined) {
462✔
NEW
98
      handleOnSubSectionSelected(enrichEventWithDetails(event, { sectionId: parentId, subSectionId: sectionId }));
115✔
99
    } else {
NEW
100
      const section = childrenArray.find((el) => {
347✔
NEW
101
        return el.props.id == sectionId;
1,291✔
102
      });
NEW
103
      setOnSectionSelectedArgs([event, section?.props?.id, index, section]);
347✔
104
    }
105
  };
106
  // effect required - if event is called in `handleTabItemSelect` it's invoked twice in StrictMode
NEW
107
  useEffect(() => {
18,978✔
NEW
108
    if (onSectionSelectedArgs) {
1,892✔
NEW
109
      handleOnSectionSelected(...onSectionSelectedArgs);
347✔
NEW
110
      setOnSectionSelectedArgs(false);
347✔
111
    }
112
  }, [onSectionSelectedArgs]);
113

NEW
114
  return handleTabItemSelect;
18,978✔
115
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc