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

SAP / ui5-webcomponents-react / 6742804522

03 Nov 2023 08:19AM CUT coverage: 87.72% (+0.07%) from 87.653%
6742804522

Pull #5203

github

web-flow
Merge 01db8c468 into e071424f2
Pull Request #5203: feat(AnalyticalTable): fire `onLoadMore` when resizing in `Interactive` `visibleRowCountMode`

2789 of 3740 branches covered (0.0%)

8 of 9 new or added lines in 3 files covered. (88.89%)

1 existing line in 1 file now uncovered.

5093 of 5806 relevant lines covered (87.72%)

31652.49 hits per line

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

88.89
/packages/main/src/components/AnalyticalTable/VerticalResizer.tsx
1
import { ThemingParameters, useI18nBundle } from '@ui5/webcomponents-react-base';
2
import type { MutableRefObject } from 'react';
3
import React, { useCallback, useEffect, useRef, useState } from 'react';
4
import { createPortal } from 'react-dom';
5
import { createUseStyles } from 'react-jss';
6
import { DRAG_TO_RESIZE } from '../../i18n/i18n-defaults.js';
7
import { useCanRenderPortal } from '../../internal/ssr.js';
8

9
const verticalResizerStyles = {
393✔
10
  container: {
11
    overflow: 'hidden',
12
    position: 'relative',
13
    height: '5px',
14
    textAlign: 'center',
15
    cursor: 'row-resize',
16
    boxSizing: 'border-box',
17
    '&:hover': {
18
      backgroundColor: ThemingParameters.sapContent_DragAndDropActiveColor,
19
      color: ThemingParameters.sapHighlightTextColor
20
    },
21
    '&:before': {
22
      fontSize: '10px',
23
      fontFamily: ThemingParameters.sapFontFamily,
24
      top: 0,
25
      position: 'absolute',
26
      content: '"\u2981\u2981\u2981\u2981"',
27
      lineHeight: '5px',
28
      pointerEvents: 'none'
29
    }
30
  },
31
  resizer: {
32
    position: 'absolute',
33
    opacity: 0.5,
34
    backgroundColor: ThemingParameters.sapContent_DragAndDropActiveColor,
35
    height: '5px'
36
  }
37
};
38

39
const useStyles = createUseStyles(verticalResizerStyles, { name: 'VerticalResizer' });
393✔
40

41
interface VerticalResizerProps {
42
  analyticalTableRef: MutableRefObject<any>;
43
  dispatch: (e: { type: string; payload?: any }) => void;
44
  extensionsHeight: number;
45
  internalRowHeight: number;
46
  hasPopInColumns: boolean;
47
  popInRowHeight: number;
48
  portalContainer: Element;
49
  rowsLength: number;
50
  visibleRows: number;
51
  handleOnLoadMore: (e: Event) => void;
52
}
53

54
const isTouchEvent = (e, touchEvent) => {
393✔
55
  if (e.type === touchEvent) {
246!
56
    return !(e.touches && e.touches.length > 1);
×
57
  }
58
  return false;
246✔
59
};
60

61
export const VerticalResizer = (props: VerticalResizerProps) => {
393✔
62
  const {
63
    analyticalTableRef,
64
    dispatch,
65
    extensionsHeight,
66
    internalRowHeight,
67
    hasPopInColumns,
68
    popInRowHeight,
69
    portalContainer,
70
    rowsLength,
71
    visibleRows,
72
    handleOnLoadMore
73
  } = props;
735✔
74
  const classes = useStyles();
735✔
75
  const startY = useRef(null);
735✔
76
  const verticalResizerRef = useRef(null);
735✔
77
  const [resizerPosition, setResizerPosition] = useState(undefined);
735✔
78
  const [isDragging, setIsDragging] = useState(false);
735✔
79
  const [mountTouchEvents, setMountTouchEvents] = useState(false);
735✔
80

81
  const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
735✔
82

83
  const handleResizeStart = useCallback(
735✔
84
    (e) => {
85
      e.preventDefault();
82✔
86
      const touchEvent = isTouchEvent(e, 'touchstart');
82✔
87
      startY.current = touchEvent ? Math.round(e.touches[0].pageY) : e.pageY;
82!
88
      setMountTouchEvents(touchEvent);
82✔
89
      setIsDragging(true);
82✔
90
    },
91
    [startY.current, setIsDragging]
92
  );
93

94
  const handleMove = useCallback(
735✔
95
    (e) => {
96
      setResizerPosition((prev) => ({
82✔
97
        ...prev,
98
        top: isTouchEvent(e, 'touchmove') ? Math.round(e.touches[0].pageY) : e.pageY
82!
99
      }));
100
    },
101
    [setResizerPosition]
102
  );
103
  const handleResizeEnd = useCallback(
735✔
104
    (e) => {
105
      setIsDragging(false);
82✔
106
      const rowCount = Math.floor(
82✔
107
        (analyticalTableRef.current.clientHeight +
108
          (isTouchEvent(e, 'touchend') ? Math.round(e.changedTouches[0].pageY) : e.pageY) -
82!
109
          startY.current -
110
          extensionsHeight -
111
          5) /*resizer height*/ /
112
          popInRowHeight
113
      );
114
      if (hasPopInColumns) {
82!
115
        dispatch({ type: 'INTERACTIVE_ROWS_HAVE_POPIN', payload: true });
×
116
      }
117
      dispatch({
82✔
118
        type: 'VISIBLE_ROWS',
119
        payload: { visibleRows: rowCount }
120
      });
121
    },
122
    [analyticalTableRef.current?.clientHeight, startY.current, extensionsHeight, internalRowHeight, dispatch]
123
  );
124
  useEffect(() => {
735✔
125
    const removeEventListeners = () => {
205✔
126
      if (mountTouchEvents) {
327!
127
        document.removeEventListener('touchmove', handleMove);
×
128
        document.removeEventListener('touchend', handleResizeEnd);
×
129
      } else {
130
        document.removeEventListener('mouseup', handleResizeEnd);
327✔
131
        document.removeEventListener('mousemove', handleMove);
327✔
132
      }
133
    };
134
    if (isDragging) {
205✔
135
      if (mountTouchEvents) {
82!
136
        document.addEventListener('touchmove', handleMove);
×
137
        document.addEventListener('touchend', handleResizeEnd);
×
138
      } else {
139
        document.addEventListener('mousemove', handleMove);
82✔
140
        document.addEventListener('mouseup', handleResizeEnd);
82✔
141
      }
142
    } else {
143
      removeEventListeners();
123✔
144
    }
145
    return () => {
205✔
146
      removeEventListeners();
204✔
147
    };
148
  }, [isDragging]);
149

150
  useEffect(() => {
735✔
151
    const resizerPosTop = verticalResizerRef.current?.getBoundingClientRect()?.top + window.scrollY;
328✔
152
    const resizerPosLeft = verticalResizerRef.current?.getBoundingClientRect()?.left + window.scrollX;
328✔
153
    const resizerPosWidth = verticalResizerRef.current?.getBoundingClientRect()?.width;
328✔
154
    if (!isDragging && resizerPosTop > 0) {
328✔
155
      setResizerPosition({ left: resizerPosLeft, top: resizerPosTop, width: resizerPosWidth });
205✔
156
    }
157
  }, [verticalResizerRef.current?.getBoundingClientRect()?.top, isDragging]);
158

159
  useEffect(() => {
735✔
160
    return () => {
41✔
161
      dispatch({ type: 'WITH_POPIN', payload: false });
40✔
162
    };
163
  }, []);
164

165
  const isInitial = useRef(true);
735✔
166
  useEffect(() => {
735✔
167
    if (!isInitial.current && rowsLength <= visibleRows) {
123!
NEW
168
      handleOnLoadMore({ type: 'tableGrow' } as Event);
×
169
    }
170
    isInitial.current = false;
123✔
171
  }, [rowsLength, visibleRows]);
172

173
  const canRenderPortal = useCanRenderPortal();
735✔
174
  if (!canRenderPortal) {
735✔
175
    return null;
123✔
176
  }
177

178
  return (
612✔
179
    <div
180
      className={classes.container}
181
      ref={verticalResizerRef}
182
      onMouseDown={handleResizeStart}
183
      onTouchStart={handleResizeStart}
184
      role="separator"
185
      title={i18nBundle.getText(DRAG_TO_RESIZE)}
186
    >
187
      {resizerPosition &&
1,306✔
188
        isDragging &&
189
        createPortal(
190
          <div
191
            className={classes.resizer}
192
            style={{ top: resizerPosition.top, left: resizerPosition.left, width: resizerPosition.width }}
193
          />,
194
          portalContainer ?? document.body
328✔
195
        )}
196
    </div>
197
  );
198
};
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