@alfalab/core-components-bottom-sheet 3.1.0 → 4.0.1

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.
Files changed (90) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/component-99884ac1.d.ts +181 -0
  3. package/dist/component-99884ac1.js +239 -0
  4. package/dist/component.d.ts +0 -55
  5. package/dist/component.js +18 -144
  6. package/dist/components/backer/Component.d.ts +24 -0
  7. package/dist/components/backer/Component.js +25 -0
  8. package/dist/components/backer/index.css +20 -0
  9. package/dist/components/closer/Component.d.ts +20 -0
  10. package/dist/components/closer/Component.js +30 -0
  11. package/dist/components/closer/index.css +20 -0
  12. package/dist/components/footer/Component.d.ts +4 -0
  13. package/dist/components/footer/Component.js +4 -3
  14. package/dist/components/footer/index.css +14 -8
  15. package/dist/components/header/Component.d.ts +0 -0
  16. package/dist/components/header/Component.js +24 -0
  17. package/dist/components/header/index.css +99 -0
  18. package/dist/components/swipeable-backdrop/Component.d.ts +19 -0
  19. package/dist/components/swipeable-backdrop/Component.js +12 -4
  20. package/dist/cssm/component-1deadd87.d.ts +181 -0
  21. package/dist/cssm/component-1deadd87.js +237 -0
  22. package/dist/cssm/component.d.ts +0 -55
  23. package/dist/cssm/component.js +22 -143
  24. package/dist/cssm/components/backer/Component.d.ts +24 -0
  25. package/dist/cssm/components/backer/Component.js +24 -0
  26. package/dist/cssm/components/backer/index.module.css +19 -0
  27. package/dist/cssm/components/closer/Component.d.ts +20 -0
  28. package/dist/cssm/components/closer/Component.js +29 -0
  29. package/dist/cssm/components/closer/index.module.css +19 -0
  30. package/dist/cssm/components/footer/Component.d.ts +4 -0
  31. package/dist/cssm/components/footer/Component.js +3 -2
  32. package/dist/cssm/components/footer/index.module.css +11 -5
  33. package/dist/cssm/components/header/Component.d.ts +0 -0
  34. package/dist/cssm/components/header/Component.js +29 -0
  35. package/dist/cssm/components/header/index.module.css +98 -0
  36. package/dist/cssm/components/swipeable-backdrop/Component.d.ts +19 -0
  37. package/dist/cssm/components/swipeable-backdrop/Component.js +12 -4
  38. package/dist/cssm/index.d.ts +1 -1
  39. package/dist/cssm/index.js +15 -4
  40. package/dist/cssm/index.module.css +24 -18
  41. package/dist/{Component-843c49d1.d.ts → cssm/tslib.es6-ce870b46.d.ts} +1 -19
  42. package/dist/{Component-843c49d1.js → cssm/tslib.es6-ce870b46.js} +1 -14
  43. package/dist/esm/component-dbec5cad.d.ts +181 -0
  44. package/dist/esm/component-dbec5cad.js +229 -0
  45. package/dist/esm/component.d.ts +0 -55
  46. package/dist/esm/component.js +15 -141
  47. package/dist/esm/components/backer/Component.d.ts +24 -0
  48. package/dist/esm/components/backer/Component.js +16 -0
  49. package/dist/esm/components/backer/index.css +20 -0
  50. package/dist/esm/components/closer/Component.d.ts +20 -0
  51. package/dist/esm/components/closer/Component.js +21 -0
  52. package/dist/esm/components/closer/index.css +20 -0
  53. package/dist/esm/components/footer/Component.d.ts +4 -0
  54. package/dist/esm/components/footer/Component.js +4 -3
  55. package/dist/esm/components/footer/index.css +14 -8
  56. package/dist/esm/components/header/Component.d.ts +0 -0
  57. package/dist/esm/components/header/Component.js +16 -0
  58. package/dist/esm/components/header/index.css +99 -0
  59. package/dist/esm/components/swipeable-backdrop/Component.d.ts +19 -0
  60. package/dist/esm/components/swipeable-backdrop/Component.js +11 -3
  61. package/dist/esm/index.css +36 -30
  62. package/dist/esm/index.d.ts +1 -1
  63. package/dist/esm/index.js +9 -2
  64. package/dist/esm/{Component-4a0a88e8.d.ts → tslib.es6-eedcd3d6.d.ts} +1 -19
  65. package/dist/esm/{Component-4a0a88e8.js → tslib.es6-eedcd3d6.js} +1 -10
  66. package/dist/index.css +36 -30
  67. package/dist/index.d.ts +1 -1
  68. package/dist/index.js +12 -4
  69. package/dist/modern/component-5b171f70.d.ts +181 -0
  70. package/dist/modern/component-5b171f70.js +230 -0
  71. package/dist/modern/component.d.ts +0 -55
  72. package/dist/modern/component.js +14 -143
  73. package/dist/modern/components/backer/Component.d.ts +24 -0
  74. package/dist/modern/components/backer/Component.js +14 -0
  75. package/dist/modern/components/backer/index.css +20 -0
  76. package/dist/modern/components/closer/Component.d.ts +20 -0
  77. package/dist/modern/components/closer/Component.js +19 -0
  78. package/dist/modern/components/closer/index.css +20 -0
  79. package/dist/modern/components/footer/Component.d.ts +4 -0
  80. package/dist/modern/components/footer/Component.js +4 -3
  81. package/dist/modern/components/footer/index.css +14 -8
  82. package/dist/modern/components/header/Component.d.ts +0 -0
  83. package/dist/modern/components/header/Component.js +15 -0
  84. package/dist/modern/components/header/index.css +99 -0
  85. package/dist/modern/index.css +36 -30
  86. package/dist/modern/index.d.ts +1 -1
  87. package/dist/modern/index.js +7 -1
  88. package/dist/{cssm/Component-24200d96.d.ts → tslib.es6-1f6a7f15.d.ts} +1 -19
  89. package/dist/{cssm/Component-24200d96.js → tslib.es6-1f6a7f15.js} +1 -14
  90. package/package.json +6 -4
@@ -0,0 +1,181 @@
1
+ /// <reference types="react-transition-group" />
2
+ /// <reference types="react" />
3
+ import React from "react";
4
+ import { FC, ReactNode } from "react";
5
+ import { BottomSheetTitleAlign } from "./index";
6
+ import { TransitionProps } from 'react-transition-group/Transition';
7
+ type HeaderProps = {
8
+ /**
9
+ * Заголовок
10
+ */
11
+ title?: ReactNode;
12
+ /**
13
+ * Дополнительный класс
14
+ */
15
+ className?: string;
16
+ /**
17
+ * Дополнительный класс для аддонов
18
+ */
19
+ addonClassName?: string;
20
+ /**
21
+ * Дополнительный класс для компонента крестика
22
+ */
23
+ closerClassName?: string;
24
+ /**
25
+ * Дополнительный класс для компонента стрелки назад
26
+ */
27
+ backerClassName?: string;
28
+ /**
29
+ * Слот слева
30
+ */
31
+ leftAddons?: ReactNode;
32
+ /**
33
+ * Слот справа
34
+ */
35
+ rightAddons?: ReactNode;
36
+ /**
37
+ * Наличие компонента крестика
38
+ */
39
+ hasCloser?: boolean;
40
+ /**
41
+ * Наличие компонента стрелки назад
42
+ */
43
+ hasBacker?: boolean;
44
+ /**
45
+ * Выравнивание заголовка
46
+ */
47
+ titleAlign?: BottomSheetTitleAlign;
48
+ /**
49
+ * Будет ли обрезан заголовок
50
+ */
51
+ trimTitle?: boolean;
52
+ /**
53
+ * Фиксирует шапку
54
+ */
55
+ sticky?: boolean;
56
+ /**
57
+ * Обработчик нажатия на стрелку назад
58
+ */
59
+ onBack?: () => void;
60
+ };
61
+ declare const Header: FC<HeaderProps>;
62
+ type BottomSheetTitleAlign$0 = 'center' | 'left';
63
+ type BottomSheetProps = {
64
+ /**
65
+ * Контент
66
+ */
67
+ children?: ReactNode;
68
+ /**
69
+ * Управление видимостью
70
+ */
71
+ open: boolean;
72
+ /**
73
+ * Заголовок
74
+ */
75
+ title?: ReactNode;
76
+ /**
77
+ * Кнопка действия (обычно, это кнопка закрытия)
78
+ */
79
+ actionButton?: ReactNode;
80
+ /**
81
+ * Дополнительный класс
82
+ */
83
+ className?: string;
84
+ /**
85
+ * Дополнительный класс
86
+ */
87
+ contentClassName?: string;
88
+ /**
89
+ * Дополнительный класс шапки
90
+ */
91
+ headerClassName?: string;
92
+ /**
93
+ * Дополнительный класс для аддонов
94
+ */
95
+ addonClassName?: string;
96
+ /**
97
+ * Дополнительный класс для компонента крестика
98
+ */
99
+ closerClassName?: string;
100
+ /**
101
+ * Дополнительный класс для компонента стрелки назад
102
+ */
103
+ backerClassName?: string;
104
+ /**
105
+ * TransitionProps, прокидываются в компонент CSSTransitionProps.
106
+ */
107
+ transitionProps?: Partial<TransitionProps>;
108
+ /**
109
+ * Идентификатор для систем автоматизированного тестирования
110
+ */
111
+ dataTestId?: string;
112
+ /**
113
+ * z-index компонента
114
+ */
115
+ zIndex?: number;
116
+ /**
117
+ * Будет ли свайпаться шторка
118
+ * @default true
119
+ */
120
+ swipeable?: boolean;
121
+ /**
122
+ * Слот слева
123
+ */
124
+ leftAddons?: ReactNode;
125
+ /**
126
+ * Слот справа
127
+ */
128
+ rightAddons?: ReactNode;
129
+ /**
130
+ * Наличие компонента крестика
131
+ */
132
+ hasCloser?: boolean;
133
+ /**
134
+ * Наличие компонента стрелки назад
135
+ */
136
+ hasBacker?: boolean;
137
+ /**
138
+ * Выравнивание заголовка
139
+ */
140
+ titleAlign?: BottomSheetTitleAlign$0;
141
+ /**
142
+ * Фиксирует шапку
143
+ */
144
+ stickyHeader?: boolean;
145
+ /**
146
+ * Фиксирует футер
147
+ */
148
+ stickyFooter?: boolean;
149
+ /**
150
+ * Высота шторки
151
+ */
152
+ initialHeight?: 'default' | 'full';
153
+ /**
154
+ * Будет ли виден оверлэй
155
+ */
156
+ hideOverlay?: boolean;
157
+ /**
158
+ * Будет ли видна шапка
159
+ */
160
+ hideHeader?: boolean;
161
+ /**
162
+ * Будет ли обрезан заголовок
163
+ */
164
+ trimTitle?: boolean;
165
+ /**
166
+ * Запретить закрытие шторки кликом на оверлэй
167
+ */
168
+ disableOverlayClick?: boolean;
169
+ /**
170
+ * Обработчик закрытия
171
+ */
172
+ onClose: () => void;
173
+ /**
174
+ * Обработчик нажатия на стрелку назад
175
+ */
176
+ onBack?: () => void;
177
+ };
178
+ declare const HEADER_OFFSET = 24;
179
+ declare const CLOSE_OFFSET = 0.2;
180
+ declare const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<HTMLDivElement>>;
181
+ export { HeaderProps, Header, BottomSheetTitleAlign$0 as BottomSheetTitleAlign, BottomSheetProps, HEADER_OFFSET, CLOSE_OFFSET, BottomSheet };
@@ -0,0 +1,230 @@
1
+ import React, { useContext, useEffect, forwardRef, useState, useRef, useCallback } from 'react';
2
+ import cn from 'classnames';
3
+ import { use100vh } from 'react-div-100vh';
4
+ import { useSwipeable } from 'react-swipeable';
5
+ import { BaseModalContext, BaseModal } from '@alfalab/core-components-base-modal/dist/modern';
6
+ import { Typography } from '@alfalab/core-components-typography/dist/modern';
7
+ import { Closer } from './components/closer/Component.js';
8
+ import { Backer } from './components/backer/Component.js';
9
+ import { Footer } from './components/footer/Component.js';
10
+ import { SwipeableBackdrop } from './components/swipeable-backdrop/Component.js';
11
+
12
+ var styles = {"header":"bottom-sheet__header_1qzdw","sticky":"bottom-sheet__sticky_1qzdw","highlighted":"bottom-sheet__highlighted_1qzdw","justifyEnd":"bottom-sheet__justifyEnd_1qzdw","addon":"bottom-sheet__addon_1qzdw","addonFixed":"bottom-sheet__addonFixed_1qzdw","addonLeft":"bottom-sheet__addonLeft_1qzdw","addonRight":"bottom-sheet__addonRight_1qzdw","title":"bottom-sheet__title_1qzdw","titleCenter":"bottom-sheet__titleCenter_1qzdw","titleLeft":"bottom-sheet__titleLeft_1qzdw","trimTitle":"bottom-sheet__trimTitle_1qzdw","titleBigIndentHorizontal":"bottom-sheet__titleBigIndentHorizontal_1qzdw","titleIndentRight":"bottom-sheet__titleIndentRight_1qzdw","titleIndentLeft":"bottom-sheet__titleIndentLeft_1qzdw"};
13
+ require('./components/header/index.css')
14
+
15
+ const Header = ({ title, className, addonClassName, closerClassName, backerClassName, leftAddons, rightAddons, hasCloser, hasBacker, titleAlign, trimTitle, sticky, onBack, }) => {
16
+ const { headerHighlighted, setHasHeader, setHeaderOffset } = useContext(BaseModalContext);
17
+ const hasLeftPart = hasBacker || leftAddons || titleAlign === 'center';
18
+ const hasRightPart = hasCloser || rightAddons || titleAlign === 'center';
19
+ const hasHeaderContent = title || hasBacker || hasCloser;
20
+ useEffect(() => {
21
+ setHasHeader(true);
22
+ }, [setHasHeader]);
23
+ useEffect(() => {
24
+ setHeaderOffset(HEADER_OFFSET);
25
+ }, [setHeaderOffset]);
26
+ const getTitleIndent = () => {
27
+ const titleAlignedCenter = titleAlign === 'center';
28
+ const hasLeftPart = hasBacker || leftAddons;
29
+ const hasRightPart = hasCloser || rightAddons;
30
+ return cn({
31
+ [styles.titleBigIndentHorizontal]: !sticky && titleAlignedCenter && (hasLeftPart || hasRightPart),
32
+ [styles.titleIndentLeft]: !sticky && !titleAlignedCenter && hasLeftPart,
33
+ [styles.titleIndentRight]: !sticky && !titleAlignedCenter && hasRightPart,
34
+ });
35
+ };
36
+ return (React.createElement("div", { className: cn(styles.header, className, {
37
+ [styles.justifyEnd]: !title,
38
+ [styles.highlighted]: headerHighlighted && sticky,
39
+ [styles.sticky]: sticky,
40
+ }) },
41
+ hasLeftPart && (React.createElement("div", { className: cn(styles.addon, addonClassName, {
42
+ [styles.addonFixed]: !sticky,
43
+ [styles.addonLeft]: !sticky,
44
+ }) }, hasBacker ? (React.createElement(Backer, { className: backerClassName, onClick: onBack })) : (leftAddons))),
45
+ hasHeaderContent && (React.createElement(Typography.Text, { view: 'primary-large', weight: 'bold', className: cn(styles.title, getTitleIndent(), {
46
+ [styles.titleCenter]: titleAlign === 'center',
47
+ [styles.titleLeft]: titleAlign === 'left',
48
+ [styles.trimTitle]: trimTitle,
49
+ }), color: 'primary' }, title)),
50
+ hasRightPart && (React.createElement("div", { className: cn(styles.addon, addonClassName, {
51
+ [styles.addonFixed]: !sticky,
52
+ [styles.addonRight]: !sticky,
53
+ }) }, hasCloser ? React.createElement(Closer, { className: closerClassName }) : rightAddons))));
54
+ };
55
+
56
+ var styles$1 = {"modal":"bottom-sheet__modal_b5hs7","component":"bottom-sheet__component_b5hs7","withTransition":"bottom-sheet__withTransition_b5hs7","scrollableContainer":"bottom-sheet__scrollableContainer_b5hs7","marker":"bottom-sheet__marker_b5hs7","content":"bottom-sheet__content_b5hs7","noHeader":"bottom-sheet__noHeader_b5hs7","noFooter":"bottom-sheet__noFooter_b5hs7","scrollLocked":"bottom-sheet__scrollLocked_b5hs7","appear":"bottom-sheet__appear_b5hs7","enter":"bottom-sheet__enter_b5hs7","appearActive":"bottom-sheet__appearActive_b5hs7","enterActive":"bottom-sheet__enterActive_b5hs7","enterDone":"bottom-sheet__enterDone_b5hs7","appearDone":"bottom-sheet__appearDone_b5hs7","exit":"bottom-sheet__exit_b5hs7","exitActive":"bottom-sheet__exitActive_b5hs7"};
57
+ require('./index.css')
58
+
59
+ const TIMEOUT = 300;
60
+ const SWIPE_CLOSE_VELOCITY = 0.4;
61
+ const MIN_BACKDROP_OPACITY = 0.2;
62
+ const HEADER_HEIGHT = 56;
63
+ const MARKET_HEIGHT = 24;
64
+ /* Верхний отступ шторки, если она открыта на максимальную высоту */
65
+ const HEADER_OFFSET = 24;
66
+ const CLOSE_OFFSET = 0.2;
67
+ const BottomSheet = forwardRef(({ open, title, actionButton, contentClassName, headerClassName, addonClassName, closerClassName, backerClassName, className, leftAddons, rightAddons, hasCloser, hasBacker, titleAlign = 'left', trimTitle, stickyHeader, stickyFooter = true, initialHeight = 'default', hideOverlay, hideHeader, disableOverlayClick, children, zIndex, transitionProps = {}, dataTestId, swipeable = true, onClose, onBack, }, ref) => {
68
+ const [sheetOffset, setSheetOffset] = useState(0);
69
+ const [backdropOpacity, setBackdropOpacity] = useState(1);
70
+ const [scrollLocked, setScrollLocked] = useState(false);
71
+ const sheetHeight = useRef(0);
72
+ const scrollableContainer = useRef(null);
73
+ const scrollableContainerScrollValue = useRef(0);
74
+ const emptyHeader = !hasCloser && !hasBacker && !leftAddons && !rightAddons && !title;
75
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
76
+ const fullHeight = use100vh();
77
+ const targetHeight = `${fullHeight - HEADER_OFFSET}px`;
78
+ const headerProps = {
79
+ title,
80
+ headerClassName,
81
+ addonClassName,
82
+ closerClassName,
83
+ backerClassName,
84
+ leftAddons,
85
+ rightAddons,
86
+ hasCloser,
87
+ hasBacker,
88
+ titleAlign,
89
+ trimTitle,
90
+ sticky: stickyHeader,
91
+ onBack,
92
+ };
93
+ const getBackdropOpacity = (offset) => {
94
+ if (sheetHeight.current === 0)
95
+ return MIN_BACKDROP_OPACITY;
96
+ const opacity = 1 - (1 - MIN_BACKDROP_OPACITY) * (offset / sheetHeight.current);
97
+ return Number(opacity.toFixed(2));
98
+ };
99
+ const getSheetOffset = (deltaY) => {
100
+ let offset = deltaY > 0 ? 0 : -deltaY;
101
+ offset -= scrollableContainerScrollValue.current;
102
+ return Math.floor(Math.max(0, offset));
103
+ };
104
+ /**
105
+ * Если контент внутри шторки скроллится - то шторка не должна свайпаться
106
+ * Если шапка внутри шторки зафиксирована - то шторка должна свайпаться только в области шапки
107
+ */
108
+ const shouldSkipSwiping = (offsetY) => {
109
+ if (!swipeable)
110
+ return true;
111
+ if (!scrollableContainer.current ||
112
+ (stickyHeader && offsetY <= HEADER_HEIGHT + HEADER_OFFSET) ||
113
+ (!stickyHeader && offsetY <= MARKET_HEIGHT + HEADER_OFFSET)) {
114
+ return false;
115
+ }
116
+ if (!scrollableContainerScrollValue.current) {
117
+ scrollableContainerScrollValue.current = Math.floor(scrollableContainer.current.scrollTop);
118
+ }
119
+ return scrollableContainer.current.scrollTop > 0;
120
+ };
121
+ const handleBackdropSwipedDown = ({ velocity }) => {
122
+ if (velocity > SWIPE_CLOSE_VELOCITY) {
123
+ onClose();
124
+ }
125
+ };
126
+ const handleSheetSwipedDown = ({ velocity, initial }) => {
127
+ const offsetY = initial[1];
128
+ if (shouldSkipSwiping(offsetY)) {
129
+ return;
130
+ }
131
+ const shouldClose = sheetOffset > sheetHeight.current * CLOSE_OFFSET || velocity > SWIPE_CLOSE_VELOCITY;
132
+ if (shouldClose) {
133
+ onClose();
134
+ }
135
+ else {
136
+ setSheetOffset(0);
137
+ setBackdropOpacity(1);
138
+ }
139
+ };
140
+ const handleSheetSwiped = () => {
141
+ setScrollLocked(false);
142
+ scrollableContainerScrollValue.current = 0;
143
+ };
144
+ const handleSheetSwiping = ({ deltaY, initial }) => {
145
+ const offsetY = initial[1];
146
+ if (shouldSkipSwiping(offsetY)) {
147
+ return;
148
+ }
149
+ const offset = getSheetOffset(deltaY);
150
+ const opacity = getBackdropOpacity(offset);
151
+ setSheetOffset(offset);
152
+ setBackdropOpacity(opacity);
153
+ /**
154
+ * Если шторка начинает свайпаться, то блокируем скролл внутри нее
155
+ */
156
+ if (offset > 0) {
157
+ setScrollLocked(true);
158
+ }
159
+ };
160
+ const backdropSwipeablehandlers = useSwipeable({
161
+ onSwipedDown: handleBackdropSwipedDown,
162
+ delta: 100,
163
+ trackMouse: swipeable,
164
+ });
165
+ const sheetSwipeablehandlers = useSwipeable({
166
+ onSwiping: handleSheetSwiping,
167
+ onSwipedDown: handleSheetSwipedDown,
168
+ onSwiped: handleSheetSwiped,
169
+ delta: 5,
170
+ trackMouse: swipeable,
171
+ });
172
+ const handleExited = useCallback(node => {
173
+ setBackdropOpacity(1);
174
+ if (transitionProps.onExited) {
175
+ transitionProps.onExited(node);
176
+ }
177
+ }, [transitionProps]);
178
+ const handleEntered = useCallback((node, isAppearing) => {
179
+ if (!sheetHeight.current) {
180
+ sheetHeight.current = node.getBoundingClientRect().height;
181
+ }
182
+ setBackdropOpacity(1);
183
+ if (transitionProps.onEntered) {
184
+ transitionProps.onEntered(node, isAppearing);
185
+ }
186
+ }, [transitionProps]);
187
+ useEffect(() => {
188
+ if (!open) {
189
+ setSheetOffset(0);
190
+ }
191
+ }, [open]);
192
+ const getSwipeStyles = () => ({
193
+ transform: sheetOffset ? `translateY(${sheetOffset}px)` : '',
194
+ });
195
+ const getHeightStyles = () => ({
196
+ height: initialHeight === 'full' ? targetHeight : 'unset',
197
+ maxHeight: targetHeight,
198
+ });
199
+ return (React.createElement(BaseModal, { open: open, ref: ref, dataTestId: dataTestId, zIndex: zIndex, onClose: onClose, scrollHandler: scrollableContainer, Backdrop: SwipeableBackdrop, backdropProps: {
200
+ opacity: backdropOpacity,
201
+ handlers: swipeable ? backdropSwipeablehandlers : false,
202
+ opacityTimeout: TIMEOUT,
203
+ invisible: initialHeight === 'full' ? false : hideOverlay,
204
+ }, disableBackdropClick: hideOverlay ? true : disableOverlayClick, className: styles$1.modal, transitionProps: {
205
+ appear: true,
206
+ timeout: TIMEOUT,
207
+ classNames: styles$1,
208
+ ...transitionProps,
209
+ onExited: handleExited,
210
+ onEntered: handleEntered,
211
+ } },
212
+ React.createElement("div", Object.assign({ className: cn(styles$1.component, className, {
213
+ [styles$1.withTransition]: !sheetOffset,
214
+ }), style: {
215
+ ...getSwipeStyles(),
216
+ ...getHeightStyles(),
217
+ } }, sheetSwipeablehandlers),
218
+ React.createElement("div", { className: cn(styles$1.scrollableContainer, {
219
+ [styles$1.scrollLocked]: scrollLocked,
220
+ }), ref: scrollableContainer },
221
+ swipeable && React.createElement("div", { className: cn(styles$1.marker) }),
222
+ !hideHeader && !emptyHeader && React.createElement(Header, Object.assign({}, headerProps)),
223
+ React.createElement("div", { className: cn(styles$1.content, contentClassName, {
224
+ [styles$1.noHeader]: hideHeader || emptyHeader,
225
+ [styles$1.noFooter]: !actionButton,
226
+ }) }, children),
227
+ actionButton && React.createElement(Footer, { sticky: stickyFooter }, actionButton)))));
228
+ });
229
+
230
+ export { BottomSheet as B, CLOSE_OFFSET as C, HEADER_OFFSET as H, Header as a };
@@ -1,55 +0,0 @@
1
- /// <reference types="react-transition-group" />
2
- /// <reference types="react" />
3
- import React from 'react';
4
- import { ReactNode } from "react";
5
- import { TransitionProps } from 'react-transition-group/Transition';
6
- type BottomSheetProps = {
7
- /**
8
- * Контент
9
- */
10
- children?: ReactNode;
11
- /**
12
- * Управление видимостью
13
- */
14
- open: boolean;
15
- /**
16
- * Заголовок
17
- */
18
- title?: ReactNode;
19
- /**
20
- * Кнопка действия (обычно, это кнопка закрытия)
21
- */
22
- actionButton?: ReactNode;
23
- /**
24
- * Дополнительный класс
25
- */
26
- className?: string;
27
- /**
28
- * Дополнительный класс
29
- */
30
- contentClassName?: string;
31
- /**
32
- * TransitionProps, прокидываются в компонент CSSTransitionProps.
33
- */
34
- transitionProps?: Partial<TransitionProps>;
35
- /**
36
- * Идентификатор для систем автоматизированного тестирования
37
- */
38
- dataTestId?: string;
39
- /**
40
- * z-index компонента
41
- */
42
- zIndex?: number;
43
- /**
44
- * Будет ли свайпаться на десктопе
45
- * @default false
46
- */
47
- desktopSwipeable?: boolean;
48
- /**
49
- * Обработчик закрытия
50
- */
51
- onClose: () => void;
52
- };
53
- declare const CLOSE_OFFSET = 0.2;
54
- declare const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<HTMLDivElement>>;
55
- export { BottomSheetProps, CLOSE_OFFSET, BottomSheet };
@@ -1,144 +1,15 @@
1
- import React, { forwardRef, useState, useRef, useCallback, useEffect } from 'react';
2
- import cn from 'classnames';
3
- import { useSwipeable } from 'react-swipeable';
4
- import { BaseModal } from '@alfalab/core-components-base-modal/dist/modern';
5
- import { Typography } from '@alfalab/core-components-typography/dist/modern';
6
- import { Footer } from './components/footer/Component.js';
1
+ import 'react';
2
+ import 'classnames';
3
+ import 'react-div-100vh';
4
+ import 'react-swipeable';
5
+ import '@alfalab/core-components-base-modal/dist/modern';
6
+ import '@alfalab/core-components-typography/dist/modern';
7
+ import '@alfalab/core-components-icon-button/dist/modern';
8
+ import '@alfalab/icons-glyph/CrossMIcon';
9
+ import './components/closer/Component.js';
10
+ import '@alfalab/icons-glyph/ArrowBackMIcon';
11
+ import './components/backer/Component.js';
12
+ export { B as BottomSheet, C as CLOSE_OFFSET, H as HEADER_OFFSET } from './component-5b171f70.js';
13
+ import './components/footer/Component.js';
7
14
  import '@alfalab/core-components-backdrop/dist/modern';
8
- import { SwipeableBackdrop } from './components/swipeable-backdrop/Component.js';
9
-
10
- var styles = {"modal":"bottom-sheet__modal_1umf1","component":"bottom-sheet__component_1umf1","withTransition":"bottom-sheet__withTransition_1umf1","marker":"bottom-sheet__marker_1umf1","scrollableContainer":"bottom-sheet__scrollableContainer_1umf1","withPadding":"bottom-sheet__withPadding_1umf1","content":"bottom-sheet__content_1umf1","title":"bottom-sheet__title_1umf1","scrollLocked":"bottom-sheet__scrollLocked_1umf1","appear":"bottom-sheet__appear_1umf1","enter":"bottom-sheet__enter_1umf1","appearActive":"bottom-sheet__appearActive_1umf1","enterActive":"bottom-sheet__enterActive_1umf1","enterDone":"bottom-sheet__enterDone_1umf1","appearDone":"bottom-sheet__appearDone_1umf1","exit":"bottom-sheet__exit_1umf1","exitActive":"bottom-sheet__exitActive_1umf1"};
11
- require('./index.css')
12
-
13
- const TIMEOUT = 300;
14
- const SWIPE_CLOSE_VELOCITY = 0.4;
15
- const MIN_BACKDROP_OPACITY = 0.2;
16
- const CLOSE_OFFSET = 0.2;
17
- const BottomSheet = forwardRef(({ open, title, actionButton, contentClassName, className, children, zIndex, transitionProps = {}, dataTestId, desktopSwipeable: trackMouse = false, onClose, }, ref) => {
18
- const [sheetOffset, setSheetOffset] = useState(0);
19
- const [backdropOpacity, setBackdropOpacity] = useState(1);
20
- const [scrollLocked, setScrollLocked] = useState(false);
21
- const sheetHeight = useRef(0);
22
- const scrollableContainer = useRef(null);
23
- const scrollableContainerScrollValue = useRef(0);
24
- const getBackdropOpacity = (offset) => {
25
- if (sheetHeight.current === 0)
26
- return MIN_BACKDROP_OPACITY;
27
- const opacity = 1 - (1 - MIN_BACKDROP_OPACITY) * (offset / sheetHeight.current);
28
- return Number(opacity.toFixed(2));
29
- };
30
- const getSheetOffset = (deltaY) => {
31
- let offset = deltaY > 0 ? 0 : -deltaY;
32
- offset -= scrollableContainerScrollValue.current;
33
- return Math.floor(Math.max(0, offset));
34
- };
35
- /**
36
- * Если контент внутри шторки скроллится - то шторка не должна свайпаться
37
- */
38
- const shouldSkipSwiping = () => {
39
- if (!scrollableContainer.current) {
40
- return false;
41
- }
42
- if (!scrollableContainerScrollValue.current) {
43
- scrollableContainerScrollValue.current = Math.floor(scrollableContainer.current.scrollTop);
44
- }
45
- return scrollableContainer.current.scrollTop > 0;
46
- };
47
- const handleBackdropSwipedDown = ({ velocity }) => {
48
- if (velocity > SWIPE_CLOSE_VELOCITY) {
49
- onClose();
50
- }
51
- };
52
- const handleSheetSwipedDown = ({ velocity }) => {
53
- if (shouldSkipSwiping()) {
54
- return;
55
- }
56
- const shouldClose = sheetOffset > sheetHeight.current * CLOSE_OFFSET || velocity > SWIPE_CLOSE_VELOCITY;
57
- if (shouldClose) {
58
- onClose();
59
- }
60
- else {
61
- setSheetOffset(0);
62
- setBackdropOpacity(1);
63
- }
64
- };
65
- const handleSheetSwiped = () => {
66
- setScrollLocked(false);
67
- scrollableContainerScrollValue.current = 0;
68
- };
69
- const handleSheetSwiping = ({ deltaY }) => {
70
- if (shouldSkipSwiping()) {
71
- return;
72
- }
73
- const offset = getSheetOffset(deltaY);
74
- const opacity = getBackdropOpacity(offset);
75
- setSheetOffset(offset);
76
- setBackdropOpacity(opacity);
77
- /**
78
- * Если шторка начинает свайпаться, то блокируем скролл внутри нее
79
- */
80
- if (offset > 0) {
81
- setScrollLocked(true);
82
- }
83
- };
84
- const backdropSwipeablehandlers = useSwipeable({
85
- onSwipedDown: handleBackdropSwipedDown,
86
- delta: 100,
87
- trackMouse,
88
- });
89
- const sheetSwipeablehandlers = useSwipeable({
90
- onSwiping: handleSheetSwiping,
91
- onSwipedDown: handleSheetSwipedDown,
92
- onSwiped: handleSheetSwiped,
93
- delta: 5,
94
- trackMouse,
95
- });
96
- const handleExited = useCallback(node => {
97
- setBackdropOpacity(1);
98
- if (transitionProps.onExited) {
99
- transitionProps.onExited(node);
100
- }
101
- }, [transitionProps]);
102
- const handleEntered = useCallback((node, isAppearing) => {
103
- if (!sheetHeight.current) {
104
- sheetHeight.current = node.getBoundingClientRect().height;
105
- }
106
- setBackdropOpacity(1);
107
- if (transitionProps.onEntered) {
108
- transitionProps.onEntered(node, isAppearing);
109
- }
110
- }, [transitionProps]);
111
- useEffect(() => {
112
- if (!open) {
113
- setSheetOffset(0);
114
- }
115
- }, [open]);
116
- const getSwipeStyles = () => ({
117
- transform: sheetOffset ? `translateY(${sheetOffset}px)` : '',
118
- });
119
- return (React.createElement(BaseModal, { open: open, ref: ref, dataTestId: dataTestId, zIndex: zIndex, onClose: onClose, scrollHandler: scrollableContainer, Backdrop: SwipeableBackdrop, backdropProps: {
120
- opacity: backdropOpacity,
121
- handlers: backdropSwipeablehandlers,
122
- opacityTimeout: TIMEOUT,
123
- }, className: styles.modal, transitionProps: {
124
- appear: true,
125
- timeout: TIMEOUT,
126
- classNames: styles,
127
- ...transitionProps,
128
- onExited: handleExited,
129
- onEntered: handleEntered,
130
- } },
131
- React.createElement("div", Object.assign({ className: cn(styles.component, className, {
132
- [styles.withTransition]: !sheetOffset,
133
- }), style: getSwipeStyles() }, sheetSwipeablehandlers),
134
- React.createElement("div", { className: styles.marker }),
135
- React.createElement("div", { className: cn(styles.scrollableContainer, {
136
- [styles.scrollLocked]: scrollLocked,
137
- [styles.withPadding]: !actionButton,
138
- }), ref: scrollableContainer },
139
- title && (React.createElement(Typography.Title, { view: 'small', font: 'system', tag: 'h2', className: styles.title, color: 'primary' }, title)),
140
- React.createElement("div", { className: cn(styles.content, contentClassName) }, children),
141
- actionButton && React.createElement(Footer, null, actionButton)))));
142
- });
143
-
144
- export { BottomSheet, CLOSE_OFFSET };
15
+ import './components/swipeable-backdrop/Component.js';
@@ -0,0 +1,24 @@
1
+ /// <reference types="react" />
2
+ import React from 'react';
3
+ import { ButtonHTMLAttributes, ElementType } from "react";
4
+ import { IconButtonProps } from "@alfalab/core-components-icon-button";
5
+ type BackerProps = ButtonHTMLAttributes<HTMLButtonElement> & {
6
+ /**
7
+ * Дополнительный класс
8
+ */
9
+ className?: string;
10
+ /**
11
+ * Размер кнопки
12
+ */
13
+ size?: IconButtonProps['size'];
14
+ /**
15
+ * Иконка
16
+ */
17
+ icon?: ElementType;
18
+ /**
19
+ * Обработчик нажатия
20
+ */
21
+ onClick?: () => void;
22
+ };
23
+ declare const Backer: React.FC<BackerProps>;
24
+ export { BackerProps, Backer };
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import cn from 'classnames';
3
+ import { IconButton } from '@alfalab/core-components-icon-button/dist/modern';
4
+ import { ArrowBackMIcon } from '@alfalab/icons-glyph/ArrowBackMIcon';
5
+
6
+ var styles = {"backer":"bottom-sheet__backer_1wvld","button":"bottom-sheet__button_1wvld"};
7
+ require('./index.css')
8
+
9
+ const Backer = ({ className, size = 'xs', icon = ArrowBackMIcon, onClick, ...restProps }) => {
10
+ return (React.createElement("div", { className: cn(styles.backer, className) },
11
+ React.createElement(IconButton, Object.assign({ size: size, className: styles.button, "aria-label": '\u043D\u0430\u0437\u0430\u0434', onClick: onClick, icon: icon }, restProps))));
12
+ };
13
+
14
+ export { Backer };