@via-profit/ui-kit 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,6 +54,9 @@ const StyledSlide = styled_1.default.div `
54
54
  flex-grow: 0;
55
55
  flex-shrink: 0;
56
56
  flex-basis: calc(100% / ${({ $slidesPerView }) => $slidesPerView});
57
+ /* The size of the slide is set by slidesPerView, not by its content: the track positions rely on it */
58
+ min-width: 0;
59
+ min-height: 0;
57
60
  height: 100%;
58
61
  display: flex;
59
62
  align-items: center;
@@ -14,6 +14,10 @@ export type SwiperSlidesRendererProps = {
14
14
  readonly realSlidesCount: number;
15
15
  readonly getSlideRealIndex: (index: number) => number;
16
16
  readonly slideLabel: (index: number, total: number) => string;
17
+ /**
18
+ * The index of the slide in the DOM shown by the fade effect, `null` for the slide effect
19
+ */
20
+ readonly activeDomIndex?: number | null;
17
21
  };
18
22
  declare const _default: React.NamedExoticComponent<SwiperSlidesRendererProps>;
19
23
  export default _default;
@@ -37,7 +37,7 @@ const React = __importStar(require("react"));
37
37
  // React 19 supports the boolean `inert`, React 18 passes only the string value to the DOM
38
38
  const INERT_VALUE = parseInt(React.version, 10) >= 19 ? true : '';
39
39
  const SwiperSlidesRenderer = props => {
40
- const { slides, slidesPerView, realIndex, realSlidesCount, getSlideRealIndex, slideLabel, firstVisibleIndex = realIndex, visibleCount = slidesPerView, } = props;
40
+ const { slides, slidesPerView, realIndex, realSlidesCount, getSlideRealIndex, slideLabel, firstVisibleIndex = realIndex, visibleCount = Math.ceil(slidesPerView), activeDomIndex = null, } = props;
41
41
  const visibilityMap = React.useMemo(() => {
42
42
  const map = new Map();
43
43
  if (realSlidesCount <= visibleCount) {
@@ -80,6 +80,7 @@ const SwiperSlidesRenderer = props => {
80
80
  'aria-hidden': isClone || !isVisible ? true : undefined,
81
81
  inert: isVisible && !isClone ? undefined : INERT_VALUE,
82
82
  'data-index': i,
83
+ 'data-active': activeDomIndex === null ? undefined : activeDomIndex === i,
83
84
  'data-real-index': slideRealIndex,
84
85
  });
85
86
  })));
@@ -1,6 +1,10 @@
1
1
  import * as React from 'react';
2
2
  export type SwiperTrackProps = React.HTMLAttributes<HTMLDivElement> & {
3
3
  readonly children: React.ReactNode;
4
+ /**
5
+ * The position of the track in slides. It is fractional with a fractional `slidesPerView`
6
+ * and with the centered slides
7
+ */
4
8
  readonly index: number;
5
9
  readonly offset: number;
6
10
  readonly dragging: boolean;
@@ -10,9 +14,19 @@ export type SwiperTrackProps = React.HTMLAttributes<HTMLDivElement> & {
10
14
  */
11
15
  readonly momentum?: boolean;
12
16
  readonly slidesPerView: number;
17
+ readonly vertical?: boolean;
18
+ readonly effect?: 'slide' | 'fade';
19
+ /**
20
+ * The duration of the slide change in milliseconds
21
+ */
22
+ readonly speed?: number;
13
23
  };
14
24
  export declare const SwiperTrack: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
15
25
  readonly children: React.ReactNode;
26
+ /**
27
+ * The position of the track in slides. It is fractional with a fractional `slidesPerView`
28
+ * and with the centered slides
29
+ */
16
30
  readonly index: number;
17
31
  readonly offset: number;
18
32
  readonly dragging: boolean;
@@ -22,5 +36,11 @@ export declare const SwiperTrack: React.ForwardRefExoticComponent<React.HTMLAttr
22
36
  */
23
37
  readonly momentum?: boolean;
24
38
  readonly slidesPerView: number;
39
+ readonly vertical?: boolean;
40
+ readonly effect?: "slide" | "fade";
41
+ /**
42
+ * The duration of the slide change in milliseconds
43
+ */
44
+ readonly speed?: number;
25
45
  } & React.RefAttributes<HTMLDivElement>>;
26
46
  export default SwiperTrack;
@@ -50,21 +50,44 @@ Object.defineProperty(exports, "__esModule", { value: true });
50
50
  exports.SwiperTrack = void 0;
51
51
  const React = __importStar(require("react"));
52
52
  const styled_1 = __importDefault(require("@emotion/styled"));
53
+ const react_1 = require("@emotion/react");
53
54
  const StyledTrack = styled_1.default.div `
54
55
  display: flex;
56
+ flex-direction: ${({ $vertical }) => ($vertical ? 'column' : 'row')};
55
57
  height: 100%;
56
- transition: ${({ $dragging, $disableAnimation, $momentum }) => {
58
+ transition: ${({ $dragging, $disableAnimation, $momentum, $speed }) => {
57
59
  if ($dragging || $disableAnimation) {
58
60
  return 'none';
59
61
  }
60
- return $momentum ? 'transform 0.6s cubic-bezier(0.25, 1, 0.5, 1)' : 'transform 0.3s ease';
62
+ return $momentum
63
+ ? 'transform 0.6s cubic-bezier(0.25, 1, 0.5, 1)'
64
+ : `transform ${$speed}ms ease`;
61
65
  }};
62
66
  will-change: transform;
63
- transform: ${({ $index, $offset, $slidesPerView }) => `translateX(calc(${-(($index * 100) / $slidesPerView)}% + ${$offset}px))`};
67
+ transform: ${({ $index, $offset, $slidesPerView, $vertical }) => `${$vertical ? 'translateY' : 'translateX'}(calc(${-(($index * 100) / $slidesPerView)}% + ${$offset}px))`};
68
+
69
+ ${({ $fade, $speed }) => $fade &&
70
+ (0, react_1.css) `
71
+ /* The slides lie on top of each other, the current one is opaque */
72
+ display: grid;
73
+ transform: none;
74
+ will-change: auto;
75
+
76
+ & > * {
77
+ grid-area: 1 / 1;
78
+ opacity: 0;
79
+ transition: opacity ${$speed}ms ease;
80
+ }
81
+
82
+ & > [data-active='true'] {
83
+ opacity: 1;
84
+ z-index: 1;
85
+ }
86
+ `}
64
87
  `;
65
88
  exports.SwiperTrack = React.forwardRef((props, ref) => {
66
- const { children, index, offset, dragging, disableAnimation, momentum, slidesPerView } = props, restProps = __rest(props, ["children", "index", "offset", "dragging", "disableAnimation", "momentum", "slidesPerView"]);
67
- return (React.createElement(StyledTrack, Object.assign({ "$dragging": dragging, "$index": index, "$offset": offset, "$disableAnimation": disableAnimation, "$momentum": momentum, "$slidesPerView": slidesPerView }, restProps, { ref: ref }), children));
89
+ const { children, index, offset, dragging, disableAnimation, momentum, slidesPerView, vertical = false, effect = 'slide', speed = 300 } = props, restProps = __rest(props, ["children", "index", "offset", "dragging", "disableAnimation", "momentum", "slidesPerView", "vertical", "effect", "speed"]);
90
+ return (React.createElement(StyledTrack, Object.assign({ "$dragging": dragging, "$index": index, "$offset": offset, "$disableAnimation": disableAnimation, "$momentum": momentum, "$slidesPerView": slidesPerView, "$vertical": vertical, "$fade": effect === 'fade', "$speed": speed }, restProps, { ref: ref }), children));
68
91
  });
69
92
  exports.SwiperTrack.displayName = 'SwiperTrack';
70
93
  exports.default = exports.SwiperTrack;
@@ -2,15 +2,18 @@ import * as React from 'react';
2
2
  export type SwiperWrapperProps = React.HTMLAttributes<HTMLDivElement> & {
3
3
  readonly draggable: boolean;
4
4
  readonly slidesPerView: number;
5
+ readonly vertical?: boolean;
5
6
  };
6
7
  export declare const StyledWrapper: import("@emotion/styled").StyledComponent<{
7
8
  theme?: import("@emotion/react").Theme;
8
9
  as?: React.ElementType;
9
10
  } & {
10
11
  $draggable: boolean;
12
+ $vertical: boolean;
11
13
  }, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
12
14
  declare const SwiperWrapper: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
13
15
  readonly draggable: boolean;
14
16
  readonly slidesPerView: number;
17
+ readonly vertical?: boolean;
15
18
  } & React.RefAttributes<HTMLDivElement>>;
16
19
  export default SwiperWrapper;
@@ -58,9 +58,10 @@ exports.StyledWrapper = styled_1.default.div `
58
58
  overflow: hidden;
59
59
  user-select: none;
60
60
 
61
- ${({ $draggable }) => $draggable &&
61
+ /* The page still scrolls across the swiper on the touch screens */
62
+ ${({ $draggable, $vertical }) => $draggable &&
62
63
  (0, react_1.css) `
63
- touch-action: pan-y;
64
+ touch-action: ${$vertical ? 'pan-x' : 'pan-y'};
64
65
  `};
65
66
 
66
67
  /* Inside: the container clips the outer outline */
@@ -73,8 +74,8 @@ exports.StyledWrapper = styled_1.default.div `
73
74
  const SwiperWrapper = React.forwardRef((props, ref) => {
74
75
  // slidesPerView is for the overrides only, it is not a DOM attribute
75
76
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
76
- const { children, draggable, slidesPerView } = props, restProps = __rest(props, ["children", "draggable", "slidesPerView"]);
77
- return (React.createElement(exports.StyledWrapper, Object.assign({}, restProps, { ref: ref, "$draggable": draggable }), children));
77
+ const { children, draggable, slidesPerView, vertical = false } = props, restProps = __rest(props, ["children", "draggable", "slidesPerView", "vertical"]);
78
+ return (React.createElement(exports.StyledWrapper, Object.assign({}, restProps, { ref: ref, "$draggable": draggable, "$vertical": vertical }), children));
78
79
  });
79
80
  SwiperWrapper.displayName = 'SwiperWrapper';
80
81
  exports.default = SwiperWrapper;
@@ -13,6 +13,84 @@ import React from 'react';
13
13
  import styled from '@emotion/styled';
14
14
  import { css } from '@emotion/react';
15
15
  import ModalInner from '../BaseModal/ModalInner';
16
+ import useSwipeToClose from './useSwipeToClose';
17
+ /**
18
+ * The grip on the side facing the page: shows that the drawer can be swiped
19
+ * and lets a mouse drag it (elsewhere the mouse selects the text)
20
+ */
21
+ const DrawerHandle = styled.div `
22
+ position: absolute;
23
+ z-index: 1;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ cursor: grab;
28
+ touch-action: none;
29
+
30
+ &:active {
31
+ cursor: grabbing;
32
+ }
33
+
34
+ &::before {
35
+ content: '';
36
+ border-radius: 1em;
37
+ background-color: ${({ theme }) => theme.color.textPrimary.alpha(0.24).toString()};
38
+ }
39
+
40
+ ${({ $anchor }) => {
41
+ switch ($anchor) {
42
+ case 'top':
43
+ return css `
44
+ bottom: 0;
45
+ left: 50%;
46
+ transform: translateX(-50%);
47
+ width: 4em;
48
+ height: 1.25em;
49
+ &::before {
50
+ width: 2.5em;
51
+ height: 0.25em;
52
+ }
53
+ `;
54
+ case 'left':
55
+ return css `
56
+ right: 0;
57
+ top: 50%;
58
+ transform: translateY(-50%);
59
+ width: 1.25em;
60
+ height: 4em;
61
+ &::before {
62
+ width: 0.25em;
63
+ height: 2.5em;
64
+ }
65
+ `;
66
+ case 'right':
67
+ return css `
68
+ left: 0;
69
+ top: 50%;
70
+ transform: translateY(-50%);
71
+ width: 1.25em;
72
+ height: 4em;
73
+ &::before {
74
+ width: 0.25em;
75
+ height: 2.5em;
76
+ }
77
+ `;
78
+ case 'bottom':
79
+ default:
80
+ return css `
81
+ top: 0;
82
+ left: 50%;
83
+ transform: translateX(-50%);
84
+ width: 4em;
85
+ height: 1.25em;
86
+ &::before {
87
+ width: 2.5em;
88
+ height: 0.25em;
89
+ }
90
+ `;
91
+ }
92
+ }}
93
+ `;
16
94
  const StyledDrawerBottomInner = styled(ModalInner) `
17
95
  position: fixed;
18
96
  margin: 0;
@@ -126,7 +204,16 @@ const StyledDrawerLeftInner = styled(ModalInner) `
126
204
  `}
127
205
  `;
128
206
  const DrawerInner = (props, ref) => {
129
- const { children, isOpen, anchor, onRequestClose, dialogID } = props, nativeProps = __rest(props, ["children", "isOpen", "anchor", "onRequestClose", "dialogID"]);
207
+ const { children, isOpen, anchor, onRequestClose, dialogID, swipeToClose } = props, nativeProps = __rest(props, ["children", "isOpen", "anchor", "onRequestClose", "dialogID", "swipeToClose"]);
208
+ const elementRef = React.useRef(null);
209
+ React.useImperativeHandle(ref, () => elementRef.current);
210
+ const swipeHandlers = useSwipeToClose({
211
+ elementRef,
212
+ enabled: Boolean(swipeToClose),
213
+ isOpen,
214
+ anchor,
215
+ onClose: onRequestClose,
216
+ });
130
217
  const Element = React.useMemo(() => {
131
218
  switch (anchor) {
132
219
  case 'top':
@@ -140,6 +227,8 @@ const DrawerInner = (props, ref) => {
140
227
  return StyledDrawerBottomInner;
141
228
  }
142
229
  }, [anchor]);
143
- return (React.createElement(Element, Object.assign({ role: "dialog", "aria-modal": "true", isOpen: isOpen, id: `${dialogID}-description`, onRequestClose: onRequestClose }, nativeProps, { ref: ref }), children));
230
+ return (React.createElement(Element, Object.assign({ role: "dialog", "aria-modal": "true", isOpen: isOpen, id: `${dialogID}-description`, onRequestClose: onRequestClose }, nativeProps, swipeHandlers, { ref: elementRef }),
231
+ swipeToClose && React.createElement(DrawerHandle, { "$anchor": anchor, "data-drawer-handle": true, "aria-hidden": "true" }),
232
+ children));
144
233
  };
145
234
  export default React.forwardRef(DrawerInner);
@@ -19,7 +19,7 @@ import Footer from './DrawerFooter';
19
19
  import Overlay from '../BaseModal/ModalOverlay';
20
20
  import useDialogID from '../BaseModal/useDialogID';
21
21
  const Drawer = props => {
22
- const { children, onRequestClose, showCloseButton, header, closeButtonLabel, anchor, toolbar, footer, overrides } = props, otherProps = __rest(props, ["children", "onRequestClose", "showCloseButton", "header", "closeButtonLabel", "anchor", "toolbar", "footer", "overrides"]);
22
+ const { children, onRequestClose, showCloseButton, header, closeButtonLabel, anchor, toolbar, footer, overrides, swipeToClose } = props, otherProps = __rest(props, ["children", "onRequestClose", "showCloseButton", "header", "closeButtonLabel", "anchor", "toolbar", "footer", "overrides", "swipeToClose"]);
23
23
  const hasFooter = React.useMemo(() => typeof footer !== 'undefined' && footer !== null, [footer]);
24
24
  const hasHeader = React.useMemo(() => typeof header !== 'undefined' ||
25
25
  typeof toolbar !== 'undefined' ||
@@ -29,8 +29,8 @@ const Drawer = props => {
29
29
  // Created once: a component created during the render is a new type on every render,
30
30
  // so React would remount the whole drawer content (inputs lose the focus and the state)
31
31
  const Inner = React.useMemo(() => React.forwardRef(function Inner(innerProps, ref) {
32
- return (React.createElement(DrawerInner, Object.assign({ anchor: anchor, dialogID: dialogID, "aria-labelledby": hasTitle ? `${dialogID}-title` : undefined, ref: ref }, innerProps)));
33
- }), [anchor, dialogID, hasTitle]);
32
+ return (React.createElement(DrawerInner, Object.assign({ anchor: anchor, dialogID: dialogID, swipeToClose: swipeToClose, "aria-labelledby": hasTitle ? `${dialogID}-title` : undefined, ref: ref }, innerProps)));
33
+ }), [anchor, dialogID, hasTitle, swipeToClose]);
34
34
  const overridesMap = React.useMemo(() => ({
35
35
  Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || Container,
36
36
  Header: (overrides === null || overrides === void 0 ? void 0 : overrides.Header) || Header,
@@ -0,0 +1,233 @@
1
+ import React from 'react';
2
+ // The finger moves this far before the gesture is recognized as a drag or a scroll
3
+ const SLOP = 6;
4
+ // The drawer is closed when dragged by this part of its size or thrown faster than this
5
+ const CLOSE_RATIO = 0.25;
6
+ const CLOSE_VELOCITY = 0.5; // px per ms
7
+ const RETURN_TRANSITION = 'transform 240ms ease-out';
8
+ const initialState = {
9
+ mode: 'idle',
10
+ pointerId: -1,
11
+ startX: 0,
12
+ startY: 0,
13
+ offset: 0,
14
+ lastOffset: 0,
15
+ lastTime: 0,
16
+ velocity: 0,
17
+ };
18
+ const isVertical = (anchor) => anchor === 'bottom' || anchor === 'top';
19
+ /**
20
+ * The movement of the finger towards the edge of the drawer: positive closes it
21
+ */
22
+ const getClosingDelta = (anchor, dx, dy) => {
23
+ switch (anchor) {
24
+ case 'top':
25
+ return -dy;
26
+ case 'left':
27
+ return -dx;
28
+ case 'right':
29
+ return dx;
30
+ case 'bottom':
31
+ default:
32
+ return dy;
33
+ }
34
+ };
35
+ const getTransform = (anchor, offset) => {
36
+ switch (anchor) {
37
+ case 'top':
38
+ return `translateY(${-offset}px)`;
39
+ case 'left':
40
+ return `translateX(${-offset}px)`;
41
+ case 'right':
42
+ return `translateX(${offset}px)`;
43
+ case 'bottom':
44
+ default:
45
+ return `translateY(${offset}px)`;
46
+ }
47
+ };
48
+ /**
49
+ * Whether an element between the target and the drawer can scroll the way the finger moves.
50
+ * Then the finger scrolls the content: the drawer is dragged only when the content is at its edge
51
+ */
52
+ const canScrollWithGesture = (target, root, anchor) => {
53
+ let element = target instanceof Element ? target : null;
54
+ while (element && element !== root) {
55
+ if (element instanceof HTMLElement) {
56
+ const style = window.getComputedStyle(element);
57
+ const overflow = isVertical(anchor) ? style.overflowY : style.overflowX;
58
+ const scrollable = overflow === 'auto' || overflow === 'scroll';
59
+ if (scrollable) {
60
+ const { scrollTop, scrollLeft, scrollHeight, scrollWidth, clientHeight, clientWidth } = element;
61
+ switch (anchor) {
62
+ case 'bottom':
63
+ if (scrollTop > 0) {
64
+ return true;
65
+ }
66
+ break;
67
+ case 'top':
68
+ if (scrollTop + clientHeight < scrollHeight - 1) {
69
+ return true;
70
+ }
71
+ break;
72
+ case 'left':
73
+ if (scrollLeft + clientWidth < scrollWidth - 1) {
74
+ return true;
75
+ }
76
+ break;
77
+ case 'right':
78
+ if (scrollLeft > 0) {
79
+ return true;
80
+ }
81
+ break;
82
+ default:
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ element = element.parentElement;
88
+ }
89
+ return false;
90
+ };
91
+ /**
92
+ * Closes the drawer by a swipe towards its edge.
93
+ *
94
+ * The pointer events move the drawer. A touch would be taken by the browser for the scroll
95
+ * (and the pointer cancelled), so the native `touchmove` is prevented while the drawer is dragged
96
+ */
97
+ const useSwipeToClose = (options) => {
98
+ const { elementRef, enabled, isOpen, anchor, onClose } = options;
99
+ const stateRef = React.useRef(Object.assign({}, initialState));
100
+ const setOffset = React.useCallback((offset, transition) => {
101
+ const element = elementRef.current;
102
+ if (element) {
103
+ element.style.transition = transition;
104
+ element.style.transform = offset > 0 ? getTransform(anchor, offset) : '';
105
+ }
106
+ }, [anchor, elementRef]);
107
+ const restore = React.useCallback(() => {
108
+ const element = elementRef.current;
109
+ if (element) {
110
+ element.style.transition = '';
111
+ element.style.transform = '';
112
+ }
113
+ }, [elementRef]);
114
+ // A drawer closed by a swipe keeps its offset while it slides out: reset it for the next opening
115
+ React.useEffect(() => {
116
+ if (isOpen) {
117
+ stateRef.current = Object.assign({}, initialState);
118
+ restore();
119
+ }
120
+ }, [isOpen, restore]);
121
+ /**
122
+ * Decides on the first noticeable movement whether it drags the drawer or scrolls the content
123
+ */
124
+ const update = React.useCallback((clientX, clientY, target) => {
125
+ const state = stateRef.current;
126
+ const element = elementRef.current;
127
+ if (!element || (state.mode !== 'pending' && state.mode !== 'drag')) {
128
+ return;
129
+ }
130
+ const dx = clientX - state.startX;
131
+ const dy = clientY - state.startY;
132
+ const closing = getClosingDelta(anchor, dx, dy);
133
+ if (state.mode === 'pending') {
134
+ const main = isVertical(anchor) ? Math.abs(dy) : Math.abs(dx);
135
+ const cross = isVertical(anchor) ? Math.abs(dx) : Math.abs(dy);
136
+ if (main < SLOP && cross < SLOP) {
137
+ return;
138
+ }
139
+ const isDrag = closing > 0 && main >= cross && !canScrollWithGesture(target, element, anchor);
140
+ state.mode = isDrag ? 'drag' : 'scroll';
141
+ if (!isDrag) {
142
+ return;
143
+ }
144
+ // The drag starts from here, without a jump by the slop
145
+ state.startX = clientX;
146
+ state.startY = clientY;
147
+ state.lastTime = performance.now();
148
+ }
149
+ const offset = Math.max(0, getClosingDelta(anchor, clientX - state.startX, clientY - state.startY));
150
+ const now = performance.now();
151
+ const elapsed = now - state.lastTime;
152
+ if (elapsed > 0) {
153
+ state.velocity = (offset - state.lastOffset) / elapsed;
154
+ }
155
+ state.lastOffset = offset;
156
+ state.lastTime = now;
157
+ state.offset = offset;
158
+ setOffset(offset, 'none');
159
+ }, [anchor, elementRef, setOffset]);
160
+ // A non-passive listener: only it may stop the browser from scrolling under the drag
161
+ React.useEffect(() => {
162
+ const element = elementRef.current;
163
+ if (!enabled || !element) {
164
+ return undefined;
165
+ }
166
+ const handleTouchMove = (event) => {
167
+ const touch = event.touches[0];
168
+ if (touch) {
169
+ update(touch.clientX, touch.clientY, event.target);
170
+ }
171
+ if (stateRef.current.mode === 'drag' && event.cancelable) {
172
+ event.preventDefault();
173
+ }
174
+ };
175
+ element.addEventListener('touchmove', handleTouchMove, { passive: false });
176
+ return () => {
177
+ element.removeEventListener('touchmove', handleTouchMove);
178
+ };
179
+ }, [enabled, elementRef, update]);
180
+ const onPointerDown = React.useCallback((event) => {
181
+ if (!event.isPrimary || event.button !== 0) {
182
+ return;
183
+ }
184
+ // A mouse drags only by the handle: everywhere else it selects the text
185
+ const target = event.target instanceof Element ? event.target : null;
186
+ if (event.pointerType === 'mouse') {
187
+ if (!(target === null || target === void 0 ? void 0 : target.closest('[data-drawer-handle]'))) {
188
+ return;
189
+ }
190
+ event.preventDefault();
191
+ event.currentTarget.setPointerCapture(event.pointerId);
192
+ }
193
+ stateRef.current = Object.assign(Object.assign({}, initialState), { mode: 'pending', pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, lastTime: performance.now() });
194
+ }, []);
195
+ const onPointerMove = React.useCallback((event) => {
196
+ if (event.pointerId === stateRef.current.pointerId) {
197
+ update(event.clientX, event.clientY, event.target);
198
+ }
199
+ }, [update]);
200
+ const finish = React.useCallback((event, cancelled) => {
201
+ const state = stateRef.current;
202
+ if (event.pointerId !== state.pointerId) {
203
+ return;
204
+ }
205
+ const wasDragged = state.mode === 'drag';
206
+ const element = elementRef.current;
207
+ const size = element ? (isVertical(anchor) ? element.offsetHeight : element.offsetWidth) : 0;
208
+ const shouldClose = wasDragged &&
209
+ !cancelled &&
210
+ (state.offset > size * CLOSE_RATIO || state.velocity > CLOSE_VELOCITY);
211
+ stateRef.current = Object.assign({}, initialState);
212
+ if (!wasDragged) {
213
+ return;
214
+ }
215
+ if (shouldClose) {
216
+ // The offset is kept: the drawer slides out from where the finger left it.
217
+ // The own transitions of the drawer are back, the drag turned them off
218
+ if (element) {
219
+ element.style.transition = '';
220
+ }
221
+ onClose(event);
222
+ return;
223
+ }
224
+ setOffset(0, RETURN_TRANSITION);
225
+ }, [anchor, elementRef, onClose, setOffset]);
226
+ const onPointerUp = React.useCallback((event) => finish(event, false), [finish]);
227
+ const onPointerCancel = React.useCallback((event) => finish(event, true), [finish]);
228
+ if (!enabled) {
229
+ return {};
230
+ }
231
+ return { onPointerDown, onPointerMove, onPointerUp, onPointerCancel };
232
+ };
233
+ export default useSwipeToClose;