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

JedWatson / react-select / 9de42ca4-8c55-4031-8310-e7e0a2b0128b

26 Oct 2024 11:27AM CUT coverage: 75.844%. Remained the same
9de42ca4-8c55-4031-8310-e7e0a2b0128b

Pull #5880

circleci

lukebennett88
add box-sizing to border-box for RequiredInput

adding `required` would otherwise cause an extra (unstylable) component to be added which has some implicit padding from the user agent style sheet (inputs have padding) which could cause horizontal scrolling when the whole scroll field is 100% wide.
Pull Request #5880: add box-sizing to border-box for RequiredInput

658 of 1052 branches covered (62.55%)

1033 of 1362 relevant lines covered (75.84%)

1934.69 hits per line

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

25.0
/packages/react-select/src/internal/useScrollCapture.ts
1
import { useCallback, useEffect, useRef } from 'react';
2
import { supportsPassiveEvents } from '../utils';
3

4
const cancelScroll = (event: WheelEvent | TouchEvent) => {
5✔
5
  if (event.cancelable) event.preventDefault();
×
6
  event.stopPropagation();
×
7
};
8

9
interface Options {
10
  readonly isEnabled: boolean;
11
  readonly onBottomArrive?: (event: WheelEvent | TouchEvent) => void;
12
  readonly onBottomLeave?: (event: WheelEvent | TouchEvent) => void;
13
  readonly onTopArrive?: (event: WheelEvent | TouchEvent) => void;
14
  readonly onTopLeave?: (event: WheelEvent | TouchEvent) => void;
15
}
16

17
export default function useScrollCapture({
18
  isEnabled,
19
  onBottomArrive,
20
  onBottomLeave,
21
  onTopArrive,
22
  onTopLeave,
23
}: Options) {
24
  const isBottom = useRef(false);
768✔
25
  const isTop = useRef(false);
768✔
26
  const touchStart = useRef(0);
768✔
27
  const scrollTarget = useRef<HTMLElement | null>(null);
768✔
28

29
  const handleEventDelta = useCallback(
768✔
30
    (event: WheelEvent | TouchEvent, delta: number) => {
31
      if (scrollTarget.current === null) return;
×
32

33
      const { scrollTop, scrollHeight, clientHeight } = scrollTarget.current;
×
34
      const target = scrollTarget.current;
×
35
      const isDeltaPositive = delta > 0;
×
36
      const availableScroll = scrollHeight - clientHeight - scrollTop;
×
37
      let shouldCancelScroll = false;
×
38

39
      // reset bottom/top flags
40
      if (availableScroll > delta && isBottom.current) {
×
41
        if (onBottomLeave) onBottomLeave(event);
×
42
        isBottom.current = false;
×
43
      }
44
      if (isDeltaPositive && isTop.current) {
×
45
        if (onTopLeave) onTopLeave(event);
×
46
        isTop.current = false;
×
47
      }
48

49
      // bottom limit
50
      if (isDeltaPositive && delta > availableScroll) {
×
51
        if (onBottomArrive && !isBottom.current) {
×
52
          onBottomArrive(event);
×
53
        }
54
        target.scrollTop = scrollHeight;
×
55
        shouldCancelScroll = true;
×
56
        isBottom.current = true;
×
57

58
        // top limit
59
      } else if (!isDeltaPositive && -delta > scrollTop) {
×
60
        if (onTopArrive && !isTop.current) {
×
61
          onTopArrive(event);
×
62
        }
63
        target.scrollTop = 0;
×
64
        shouldCancelScroll = true;
×
65
        isTop.current = true;
×
66
      }
67

68
      // cancel scroll
69
      if (shouldCancelScroll) {
×
70
        cancelScroll(event);
×
71
      }
72
    },
73
    [onBottomArrive, onBottomLeave, onTopArrive, onTopLeave]
74
  );
75

76
  const onWheel = useCallback(
768✔
77
    (event: WheelEvent) => {
78
      handleEventDelta(event, event.deltaY);
×
79
    },
80
    [handleEventDelta]
81
  );
82
  const onTouchStart = useCallback((event: TouchEvent) => {
768✔
83
    // set touch start so we can calculate touchmove delta
84
    touchStart.current = event.changedTouches[0].clientY;
×
85
  }, []);
86
  const onTouchMove = useCallback(
768✔
87
    (event: TouchEvent) => {
88
      const deltaY = touchStart.current - event.changedTouches[0].clientY;
×
89
      handleEventDelta(event, deltaY);
×
90
    },
91
    [handleEventDelta]
92
  );
93

94
  const startListening = useCallback(
768✔
95
    (el) => {
96
      // bail early if no element is available to attach to
97
      if (!el) return;
×
98

99
      const notPassive = supportsPassiveEvents ? { passive: false } : false;
×
100
      el.addEventListener('wheel', onWheel, notPassive);
×
101
      el.addEventListener('touchstart', onTouchStart, notPassive);
×
102
      el.addEventListener('touchmove', onTouchMove, notPassive);
×
103
    },
104
    [onTouchMove, onTouchStart, onWheel]
105
  );
106

107
  const stopListening = useCallback(
768✔
108
    (el) => {
109
      // bail early if no element is available to detach from
110
      if (!el) return;
×
111

112
      el.removeEventListener('wheel', onWheel, false);
×
113
      el.removeEventListener('touchstart', onTouchStart, false);
×
114
      el.removeEventListener('touchmove', onTouchMove, false);
×
115
    },
116
    [onTouchMove, onTouchStart, onWheel]
117
  );
118

119
  useEffect(() => {
768✔
120
    if (!isEnabled) return;
169!
121

122
    const element = scrollTarget.current;
×
123
    startListening(element);
×
124

125
    return () => {
×
126
      stopListening(element);
×
127
    };
128
  }, [isEnabled, startListening, stopListening]);
129

130
  return (element: HTMLElement | null) => {
768✔
131
    scrollTarget.current = element;
1,536✔
132
  };
133
}
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