@cloud-ru/ds-drawer 1.0.7-preview-5f569f3c.0 → 1.1.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.
- package/CHANGELOG.md +7 -0
- package/README.md +6 -0
- package/dist/cjs/components/Drawer/styles.module.css +0 -16
- package/dist/cjs/components/Drawer/types.d.ts +7 -3
- package/dist/cjs/components/DrawerCustom/DrawerCustom.d.ts +3 -3
- package/dist/cjs/components/DrawerCustom/DrawerCustom.js +1 -1
- package/dist/cjs/components/DrawerCustom/constants.js +2 -6
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.js +1 -5
- package/dist/cjs/components/DrawerCustom/styles.module.css +117 -123
- package/dist/cjs/constants.d.ts +1 -1
- package/dist/cjs/constants.js +1 -1
- package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
- package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
- package/dist/cjs/helperComponents/DialogSlots.d.ts +25 -4
- package/dist/cjs/helperComponents/DialogSlots.js +32 -3
- package/dist/cjs/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
- package/dist/cjs/helperComponents/DrawerBody/DrawerBody.js +3 -2
- package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
- package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
- package/dist/cjs/helperComponents/styles.module.css +15 -0
- package/dist/cjs/style.css +132 -139
- package/dist/esm/components/Drawer/styles.module.css +0 -16
- package/dist/esm/components/Drawer/types.d.ts +7 -3
- package/dist/esm/components/DrawerCustom/DrawerCustom.d.ts +3 -3
- package/dist/esm/components/DrawerCustom/DrawerCustom.js +1 -1
- package/dist/esm/components/DrawerCustom/constants.js +2 -3
- package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.js +1 -2
- package/dist/esm/components/DrawerCustom/styles.module.css +117 -123
- package/dist/esm/constants.d.ts +1 -1
- package/dist/esm/constants.js +1 -1
- package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
- package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
- package/dist/esm/helperComponents/DialogSlots.d.ts +25 -4
- package/dist/esm/helperComponents/DialogSlots.js +29 -4
- package/dist/esm/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
- package/dist/esm/helperComponents/DrawerBody/DrawerBody.js +4 -3
- package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
- package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
- package/dist/esm/helperComponents/styles.module.css +15 -0
- package/dist/esm/style.css +132 -139
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/components/Drawer/styles.module.scss +0 -19
- package/src/components/Drawer/types.ts +7 -3
- package/src/components/DrawerCustom/DrawerCustom.tsx +1 -1
- package/src/components/DrawerCustom/constants.ts +2 -4
- package/src/components/DrawerCustom/hooks/useDrawerResize.tsx +1 -2
- package/src/components/DrawerCustom/styles.module.scss +42 -60
- package/src/constants.ts +1 -1
- package/src/helperComponents/DesktopDrawer/DesktopDrawer.tsx +18 -27
- package/src/helperComponents/DialogSlots.tsx +74 -3
- package/src/helperComponents/DrawerBody/DrawerBody.tsx +5 -2
- package/src/helperComponents/MobileDrawer/MobileDrawer.tsx +5 -2
- package/src/helperComponents/styles.module.scss +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloud-ru/ds-drawer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Пакет выезжающих панелей — компоненты Drawer и DrawerCustom с едиными токенами позиции и ширины.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"classnames": "^2.5.1",
|
|
41
41
|
"react-remove-scroll": "^2.7.2",
|
|
42
42
|
"tabbable": "^6.5.0",
|
|
43
|
-
"@cloud-ru/ds-adaptive": "1.0.1",
|
|
44
|
-
"@cloud-ru/ds-bottom-sheet": "1.
|
|
45
|
-
"@cloud-ru/ds-materials": "1.0.1",
|
|
46
|
-
"@cloud-ru/ds-popup-private": "1.
|
|
47
|
-
"@cloud-ru/ds-portal-context": "1.0.1",
|
|
48
|
-
"@cloud-ru/ds-scroll": "1.0.2",
|
|
49
|
-
"@cloud-ru/ds-tooltip": "1.0.4",
|
|
50
|
-
"@cloud-ru/ds-utils": "1.1.0"
|
|
43
|
+
"@cloud-ru/ds-adaptive": "^1.0.1",
|
|
44
|
+
"@cloud-ru/ds-bottom-sheet": "^1.1.0",
|
|
45
|
+
"@cloud-ru/ds-materials": "^1.0.1",
|
|
46
|
+
"@cloud-ru/ds-popup-private": "^1.1.0",
|
|
47
|
+
"@cloud-ru/ds-portal-context": "^1.0.1",
|
|
48
|
+
"@cloud-ru/ds-scroll": "^1.0.2",
|
|
49
|
+
"@cloud-ru/ds-tooltip": "^1.0.4",
|
|
50
|
+
"@cloud-ru/ds-utils": "^1.1.0"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -1,26 +1,7 @@
|
|
|
1
1
|
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
-
@use '@cloud-ru/ds-figma-variables/build/scss/components/drawer.module' as drawer;
|
|
3
2
|
|
|
4
3
|
.drawer {
|
|
5
4
|
box-sizing: border-box;
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
.safeAreaTop {
|
|
9
|
-
display: flex;
|
|
10
|
-
flex-direction: column;
|
|
11
|
-
align-items: flex-start;
|
|
12
|
-
align-self: stretch;
|
|
13
|
-
|
|
14
|
-
padding-top: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-top');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.safeAreaBottom {
|
|
18
|
-
display: flex;
|
|
19
|
-
flex-direction: column;
|
|
20
|
-
align-items: flex-start;
|
|
21
|
-
align-self: stretch;
|
|
22
|
-
|
|
23
|
-
padding-bottom: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-bottom');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
7
|
// Desktop-футер: ряд кнопок прижат вправо.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BottomSheetActionButton, BottomSheetProps, FooterActionsOrientation } from '@cloud-ru/ds-bottom-sheet';
|
|
2
2
|
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
-
import { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { ReactElement, ReactNode, Ref } from 'react';
|
|
4
4
|
|
|
5
5
|
import { DialogBodyProps, DialogHeaderProps } from '../../helperComponents';
|
|
6
6
|
import { DrawerCustomProps } from '../DrawerCustom';
|
|
@@ -9,14 +9,18 @@ import { DrawerCustomProps } from '../DrawerCustom';
|
|
|
9
9
|
* Адаптивный Drawer: desktop — боковая/верхняя/нижняя панель, `mobile` — `BottomSheet`.
|
|
10
10
|
*
|
|
11
11
|
* Только desktop: `position`, `width`, `heightAuto`, `nestedDrawer` (на mobile игнорируются).
|
|
12
|
-
* Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`
|
|
12
|
+
* Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`, `withDividers`
|
|
13
13
|
* (на desktop-панели игнорируются — это анатомия `BottomSheet`).
|
|
14
14
|
*/
|
|
15
15
|
export type DrawerProps = WithSupportProps<
|
|
16
16
|
Omit<DrawerCustomProps, 'nestedDrawer' | 'push' | 'resizable'> &
|
|
17
17
|
Pick<BottomSheetProps, 'swipeEnabled' | 'snapPoints' | 'snapIndex' | 'onSnapIndexChange' | 'safeArea'> &
|
|
18
|
-
Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'onBackButtonClick'> &
|
|
18
|
+
Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'slotSecondTitle' | 'onBackButtonClick'> &
|
|
19
19
|
Pick<DialogBodyProps, 'content'> & {
|
|
20
|
+
/** Ссылка на скроллируемый контейнер контента (например, для дозагрузки по скроллу). */
|
|
21
|
+
contentRef?: Ref<HTMLElement>;
|
|
22
|
+
/** Только mobile: разделители между шапкой/контентом/футером sheet'а. @default false */
|
|
23
|
+
withDividers?: boolean;
|
|
20
24
|
/** Текстовая строка-подзаголовок под title. */
|
|
21
25
|
subtitle?: ReactNode;
|
|
22
26
|
/** CSS-класс */
|
|
@@ -118,7 +118,7 @@ function DrawerFrame(props: DrawerCustomProps) {
|
|
|
118
118
|
data-height-auto={heightAutoVertical ? true : undefined}
|
|
119
119
|
data-acrylic-appearance='neutral'
|
|
120
120
|
data-acrylic-level='1Level'
|
|
121
|
-
prefixCls=
|
|
121
|
+
prefixCls='snack-rc-drawer'
|
|
122
122
|
{...(disableMotions ? {} : motionProps)}
|
|
123
123
|
>
|
|
124
124
|
{/*
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { DrawerProps } from '@rc-component/drawer';
|
|
2
2
|
|
|
3
|
-
import styles from './styles.module.scss';
|
|
4
|
-
|
|
5
3
|
export const maskMotion: DrawerProps['maskMotion'] = {
|
|
6
4
|
motionAppear: true,
|
|
7
|
-
motionName:
|
|
5
|
+
motionName: 'maskMotion',
|
|
8
6
|
};
|
|
9
7
|
|
|
10
8
|
export const motion: DrawerProps['motion'] = placement => ({
|
|
11
9
|
motionAppear: true,
|
|
12
10
|
motionDeadline: 300,
|
|
13
|
-
motionName:
|
|
11
|
+
motionName: `panelMotion-${placement}`,
|
|
14
12
|
});
|
|
15
13
|
|
|
16
14
|
export const motionProps: Partial<DrawerProps> = {
|
|
@@ -3,10 +3,9 @@ import { isBrowser } from '@cloud-ru/ds-utils';
|
|
|
3
3
|
import { DrawerProps } from '@rc-component/drawer';
|
|
4
4
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
5
5
|
|
|
6
|
-
import styles from '../styles.module.scss';
|
|
7
6
|
import { DrawerCustomProps } from '../types';
|
|
8
7
|
|
|
9
|
-
const DRAGGER_SELECTOR =
|
|
8
|
+
const DRAGGER_SELECTOR = '.snack-rc-drawer-resizable-dragger';
|
|
10
9
|
|
|
11
10
|
type UseDrawerResizeParams = Pick<DrawerCustomProps, 'position' | 'resizable'>;
|
|
12
11
|
|
|
@@ -10,20 +10,6 @@ $draggerWidth: base.$sn-primitive-dimension-4;
|
|
|
10
10
|
$draggerPosition: calc(drawer.$sn-drawer-anatomy-container-vertical-positionLeft-paddingRight - $draggerWidth - base.$sn-primitive-dimension-6);
|
|
11
11
|
$activeDraggerHeight: calc(base.$sn-primitive-dimension-32 + base.$sn-primitive-dimension-24);
|
|
12
12
|
|
|
13
|
-
// Классы rc-drawer/rc-motion глобальные (css-модуль их не хеширует), поэтому свои — с namespace и
|
|
14
|
-
// версией: оболочка консоли на snack v1 объявляет те же `.maskMotion-*`/`.panelMotion-*` и смещает
|
|
15
|
-
// панель своими правилами. В JS имена отдаёт `:export`. Версию повышать при несовместимом изменении.
|
|
16
|
-
$classVersion: 'v1';
|
|
17
|
-
$prefixCls: 'cloud-ru-ds-drawer-#{$classVersion}';
|
|
18
|
-
$maskMotionName: '#{$prefixCls}-mask-motion';
|
|
19
|
-
$panelMotionName: '#{$prefixCls}-panel-motion';
|
|
20
|
-
|
|
21
|
-
:export {
|
|
22
|
-
maskMotionName: #{$maskMotionName};
|
|
23
|
-
panelMotionName: #{$panelMotionName};
|
|
24
|
-
prefixCls: #{$prefixCls};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
13
|
// placement → offscreen transform для panelMotion-*
|
|
28
14
|
$panelMotions: (
|
|
29
15
|
'left': translateX(-100%),
|
|
@@ -32,18 +18,14 @@ $panelMotions: (
|
|
|
32
18
|
'bottom': translateY(100%),
|
|
33
19
|
);
|
|
34
20
|
|
|
35
|
-
.drawerRoot:global(
|
|
21
|
+
.drawerRoot:global(.snack-rc-drawer) {
|
|
36
22
|
pointer-events: none;
|
|
37
23
|
|
|
38
24
|
position: fixed;
|
|
39
25
|
z-index: initial;
|
|
40
26
|
inset: 0;
|
|
41
27
|
|
|
42
|
-
|
|
43
|
-
// пересчитывать её в главном потоке каждый кадр — на тяжёлом кадре движение дёргается.
|
|
44
|
-
// Корень — `position: fixed`, а фиксированные элементы не участвуют в прокрутке документа,
|
|
45
|
-
// поэтому выехавшая за экран панель полос прокрутки не создаёт.
|
|
46
|
-
overflow: visible;
|
|
28
|
+
overflow: hidden;
|
|
47
29
|
|
|
48
30
|
transition: width 0s ease 0.3s, height 0s ease 0.3s, transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
|
49
31
|
|
|
@@ -51,12 +33,12 @@ $panelMotions: (
|
|
|
51
33
|
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
|
52
34
|
}
|
|
53
35
|
|
|
54
|
-
&:global(
|
|
36
|
+
&:global(.snack-rc-drawer-open) {
|
|
55
37
|
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
|
56
38
|
}
|
|
57
39
|
|
|
58
40
|
:global {
|
|
59
|
-
|
|
41
|
+
.snack-rc-drawer-mask {
|
|
60
42
|
pointer-events: auto;
|
|
61
43
|
|
|
62
44
|
position: absolute;
|
|
@@ -70,27 +52,27 @@ $panelMotions: (
|
|
|
70
52
|
|
|
71
53
|
transition: opacity 0.2s;
|
|
72
54
|
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
&.maskMotion-enter,
|
|
56
|
+
&.maskMotion-appear {
|
|
75
57
|
opacity: 0;
|
|
76
58
|
}
|
|
77
59
|
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
&.maskMotion-enter-active,
|
|
61
|
+
&.maskMotion-appear-active {
|
|
80
62
|
opacity: 1;
|
|
81
63
|
}
|
|
82
64
|
|
|
83
|
-
|
|
65
|
+
&.maskMotion-leave {
|
|
84
66
|
opacity: 1;
|
|
85
67
|
transition: opacity 0.1s;
|
|
86
68
|
}
|
|
87
69
|
|
|
88
|
-
|
|
70
|
+
&.maskMotion-leave-active {
|
|
89
71
|
opacity: 0;
|
|
90
72
|
}
|
|
91
73
|
}
|
|
92
74
|
|
|
93
|
-
|
|
75
|
+
.snack-rc-drawer-section {
|
|
94
76
|
pointer-events: auto;
|
|
95
77
|
|
|
96
78
|
position: relative;
|
|
@@ -108,10 +90,10 @@ $panelMotions: (
|
|
|
108
90
|
box-shadow: base.$sn-boxShadow-elevation-level5;
|
|
109
91
|
}
|
|
110
92
|
|
|
111
|
-
|
|
93
|
+
.snack-rc-drawer-content-wrapper {
|
|
112
94
|
pointer-events: none;
|
|
113
95
|
will-change: transform;
|
|
114
|
-
|
|
96
|
+
|
|
115
97
|
position: absolute;
|
|
116
98
|
z-index: initial;
|
|
117
99
|
|
|
@@ -130,7 +112,7 @@ $panelMotions: (
|
|
|
130
112
|
&[data-position='top'] {
|
|
131
113
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionTop');
|
|
132
114
|
|
|
133
|
-
|
|
115
|
+
.snack-rc-drawer-section {
|
|
134
116
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionTop', 'container');
|
|
135
117
|
}
|
|
136
118
|
}
|
|
@@ -140,7 +122,7 @@ $panelMotions: (
|
|
|
140
122
|
|
|
141
123
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionBottom');
|
|
142
124
|
|
|
143
|
-
|
|
125
|
+
.snack-rc-drawer-section {
|
|
144
126
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionBottom', 'container');
|
|
145
127
|
}
|
|
146
128
|
}
|
|
@@ -152,7 +134,7 @@ $panelMotions: (
|
|
|
152
134
|
|
|
153
135
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionLeft');
|
|
154
136
|
|
|
155
|
-
|
|
137
|
+
.snack-rc-drawer-section {
|
|
156
138
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionLeft', 'container');
|
|
157
139
|
}
|
|
158
140
|
}
|
|
@@ -164,7 +146,7 @@ $panelMotions: (
|
|
|
164
146
|
|
|
165
147
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionRight');
|
|
166
148
|
|
|
167
|
-
|
|
149
|
+
.snack-rc-drawer-section {
|
|
168
150
|
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionRight', 'container');
|
|
169
151
|
}
|
|
170
152
|
}
|
|
@@ -207,32 +189,32 @@ $panelMotions: (
|
|
|
207
189
|
}
|
|
208
190
|
|
|
209
191
|
@each $placement, $offscreen in $panelMotions {
|
|
210
|
-
|
|
211
|
-
|
|
192
|
+
&.panelMotion-#{$placement}-enter,
|
|
193
|
+
&.panelMotion-#{$placement}-appear {
|
|
212
194
|
transform: $offscreen;
|
|
213
195
|
}
|
|
214
196
|
|
|
215
|
-
|
|
216
|
-
|
|
197
|
+
&.panelMotion-#{$placement}-enter-active,
|
|
198
|
+
&.panelMotion-#{$placement}-appear-active {
|
|
217
199
|
transform: translate(0);
|
|
218
200
|
}
|
|
219
201
|
|
|
220
|
-
|
|
202
|
+
&.panelMotion-#{$placement}-leave {
|
|
221
203
|
transform: translate(0);
|
|
222
204
|
}
|
|
223
205
|
|
|
224
|
-
|
|
206
|
+
&.panelMotion-#{$placement}-leave-active {
|
|
225
207
|
transform: $offscreen;
|
|
226
208
|
transition: transform 0.1s ease-out;
|
|
227
209
|
}
|
|
228
210
|
}
|
|
229
211
|
}
|
|
230
212
|
|
|
231
|
-
|
|
213
|
+
.snack-rc-drawer-content-wrapper-hidden {
|
|
232
214
|
display: none;
|
|
233
215
|
}
|
|
234
216
|
|
|
235
|
-
|
|
217
|
+
.snack-rc-drawer-resizable-dragger {
|
|
236
218
|
pointer-events: auto;
|
|
237
219
|
cursor: ew-resize;
|
|
238
220
|
|
|
@@ -266,66 +248,66 @@ $panelMotions: (
|
|
|
266
248
|
}
|
|
267
249
|
}
|
|
268
250
|
|
|
269
|
-
|
|
251
|
+
.snack-rc-drawer-resizable-dragger-left {
|
|
270
252
|
right: $draggerPosition;
|
|
271
253
|
}
|
|
272
254
|
|
|
273
|
-
|
|
255
|
+
.snack-rc-drawer-resizable-dragger-right {
|
|
274
256
|
left: $draggerPosition;
|
|
275
257
|
}
|
|
276
258
|
}
|
|
277
259
|
|
|
278
|
-
&:global(
|
|
279
|
-
&:global(
|
|
260
|
+
&:global(.snack-rc-drawer-left),
|
|
261
|
+
&:global(.snack-rc-drawer-right) {
|
|
280
262
|
top: 0;
|
|
281
263
|
width: 0%;
|
|
282
264
|
height: 100%;
|
|
283
265
|
}
|
|
284
266
|
|
|
285
|
-
&:global(
|
|
267
|
+
&:global(.snack-rc-drawer-left) {
|
|
286
268
|
left: 0;
|
|
287
269
|
}
|
|
288
270
|
|
|
289
|
-
&:global(
|
|
271
|
+
&:global(.snack-rc-drawer-right) {
|
|
290
272
|
right: 0;
|
|
291
273
|
}
|
|
292
274
|
|
|
293
|
-
&:global(
|
|
294
|
-
&:global(
|
|
275
|
+
&:global(.snack-rc-drawer-top),
|
|
276
|
+
&:global(.snack-rc-drawer-bottom) {
|
|
295
277
|
left: 0;
|
|
296
278
|
width: 100%;
|
|
297
279
|
height: 0%;
|
|
298
280
|
}
|
|
299
281
|
|
|
300
|
-
&:global(
|
|
282
|
+
&:global(.snack-rc-drawer-top) {
|
|
301
283
|
top: 0;
|
|
302
284
|
}
|
|
303
285
|
|
|
304
|
-
&:global(
|
|
286
|
+
&:global(.snack-rc-drawer-bottom) {
|
|
305
287
|
bottom: 0;
|
|
306
288
|
}
|
|
307
289
|
|
|
308
|
-
&:has(:global(
|
|
290
|
+
&:has(:global(.snack-rc-drawer-resizable-dragger-dragging)) {
|
|
309
291
|
cursor: ew-resize;
|
|
310
292
|
|
|
311
|
-
:global(
|
|
293
|
+
:global(.snack-rc-drawer-resizable-dragger) {
|
|
312
294
|
height: $activeDraggerHeight;
|
|
313
295
|
}
|
|
314
296
|
}
|
|
315
297
|
|
|
316
298
|
|
|
317
|
-
&:global(
|
|
318
|
-
&:global(
|
|
299
|
+
&:global(.snack-rc-drawer-left.snack-rc-drawer-open),
|
|
300
|
+
&:global(.snack-rc-drawer-right.snack-rc-drawer-open) {
|
|
319
301
|
width: 100%;
|
|
320
302
|
}
|
|
321
303
|
|
|
322
|
-
&:global(
|
|
323
|
-
&:global(
|
|
304
|
+
&:global(.snack-rc-drawer-top.snack-rc-drawer-open),
|
|
305
|
+
&:global(.snack-rc-drawer-bottom.snack-rc-drawer-open) {
|
|
324
306
|
height: 100%;
|
|
325
307
|
}
|
|
326
308
|
}
|
|
327
309
|
|
|
328
|
-
.drawerRoot:global(
|
|
310
|
+
.drawerRoot:global(.snack-rc-drawer .snack-rc-drawer-content-wrapper) {
|
|
329
311
|
@include m.with-material('acrylic', #{drawer});
|
|
330
312
|
}
|
|
331
313
|
|
package/src/constants.ts
CHANGED
|
@@ -11,8 +11,8 @@ export const TEST_IDS = {
|
|
|
11
11
|
footerCancel: 'drawer__footer-cancel',
|
|
12
12
|
footerAdditional: 'drawer__footer-additional',
|
|
13
13
|
nestedDrawer: 'drawer__nested',
|
|
14
|
-
/** Зарезервирован: rc-drawer отдаёт для маски только `classNames`/`styles`, атрибут навесить нечем. */
|
|
15
14
|
overlay: 'drawer__overlay',
|
|
15
|
+
contentWrapper: 'drawer__content-wrapper',
|
|
16
16
|
} as const;
|
|
17
17
|
|
|
18
18
|
export const WIDTH = {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { FooterActions } from '@cloud-ru/ds-bottom-sheet';
|
|
2
1
|
import cn from 'classnames';
|
|
3
2
|
|
|
4
3
|
import { NESTED_DRAWER_PUSH_DISTANCE } from '../../components/Drawer/constants';
|
|
@@ -13,6 +12,7 @@ export function DesktopDrawer({
|
|
|
13
12
|
media,
|
|
14
13
|
title,
|
|
15
14
|
slotAfterTitle,
|
|
15
|
+
slotSecondTitle,
|
|
16
16
|
subtitle,
|
|
17
17
|
onBackButtonClick,
|
|
18
18
|
approveButton,
|
|
@@ -21,28 +21,14 @@ export function DesktopDrawer({
|
|
|
21
21
|
footerActionsOrientation,
|
|
22
22
|
footer,
|
|
23
23
|
nestedDrawer,
|
|
24
|
+
contentRef,
|
|
25
|
+
// `withDividers` — mobile-only (мастер bottomSheet): молча уходит в `rest` и отбрасывается фреймом.
|
|
24
26
|
className,
|
|
25
27
|
...rest
|
|
26
28
|
}: DrawerProps) {
|
|
27
|
-
const showHeader = Boolean(title || subtitle || slotAfterTitle);
|
|
28
|
-
//
|
|
29
|
-
const
|
|
30
|
-
footer ??
|
|
31
|
-
(approveButton || cancelButton || additionalButton ? (
|
|
32
|
-
<FooterActions
|
|
33
|
-
surface='window'
|
|
34
|
-
size='l'
|
|
35
|
-
approveButton={approveButton}
|
|
36
|
-
cancelButton={cancelButton}
|
|
37
|
-
additionalButton={additionalButton}
|
|
38
|
-
footerActionsOrientation={footerActionsOrientation}
|
|
39
|
-
testIds={{
|
|
40
|
-
approve: TEST_IDS.footerApprove,
|
|
41
|
-
cancel: TEST_IDS.footerCancel,
|
|
42
|
-
additional: TEST_IDS.footerAdditional,
|
|
43
|
-
}}
|
|
44
|
-
/>
|
|
45
|
-
) : null);
|
|
29
|
+
const showHeader = Boolean(title || subtitle || slotAfterTitle || slotSecondTitle);
|
|
30
|
+
// Произвольный `footer` приоритетнее кнопок-слотов; раскладку слотов делает сам `DrawerCustom.Footer`.
|
|
31
|
+
const hasFooter = Boolean(footer || approveButton || cancelButton || additionalButton);
|
|
46
32
|
|
|
47
33
|
return (
|
|
48
34
|
<DrawerCustom
|
|
@@ -53,12 +39,11 @@ export function DesktopDrawer({
|
|
|
53
39
|
>
|
|
54
40
|
{media}
|
|
55
41
|
|
|
56
|
-
<div className={styles.safeAreaTop} />
|
|
57
|
-
|
|
58
42
|
{showHeader && (
|
|
59
43
|
<DrawerCustom.Header
|
|
60
44
|
title={title}
|
|
61
45
|
slotAfterTitle={slotAfterTitle}
|
|
46
|
+
slotSecondTitle={slotSecondTitle}
|
|
62
47
|
subtitle={subtitle}
|
|
63
48
|
onBackButtonClick={onBackButtonClick}
|
|
64
49
|
// Сохраняем публичный контракт test-id'ов drawer'а поверх общего `PopupHeader`.
|
|
@@ -71,12 +56,18 @@ export function DesktopDrawer({
|
|
|
71
56
|
/>
|
|
72
57
|
)}
|
|
73
58
|
|
|
74
|
-
<DrawerCustom.Body data-test-id={TEST_IDS.body} content={content} />
|
|
75
|
-
|
|
76
|
-
<div className={styles.safeAreaBottom} />
|
|
59
|
+
<DrawerCustom.Body data-test-id={TEST_IDS.body} innerRef={contentRef} content={content} />
|
|
77
60
|
|
|
78
|
-
{
|
|
79
|
-
<DrawerCustom.Footer
|
|
61
|
+
{hasFooter && (
|
|
62
|
+
<DrawerCustom.Footer
|
|
63
|
+
data-test-id={TEST_IDS.footer}
|
|
64
|
+
approveButton={footer ? undefined : approveButton}
|
|
65
|
+
cancelButton={footer ? undefined : cancelButton}
|
|
66
|
+
additionalButton={footer ? undefined : additionalButton}
|
|
67
|
+
footerActionsOrientation={footerActionsOrientation}
|
|
68
|
+
>
|
|
69
|
+
{footer}
|
|
70
|
+
</DrawerCustom.Footer>
|
|
80
71
|
)}
|
|
81
72
|
|
|
82
73
|
{nestedDrawer}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BottomSheetActionButton,
|
|
3
|
+
FooterActions,
|
|
4
|
+
FooterActionsOrientation,
|
|
2
5
|
OVERLAY_SURFACE,
|
|
3
6
|
SheetBody,
|
|
4
7
|
SheetFooter,
|
|
@@ -8,17 +11,85 @@ import {
|
|
|
8
11
|
useOverlaySurface,
|
|
9
12
|
} from '@cloud-ru/ds-bottom-sheet';
|
|
10
13
|
|
|
14
|
+
import { TEST_IDS } from '../constants';
|
|
11
15
|
import { DrawerBody, DrawerBodyProps } from './DrawerBody';
|
|
16
|
+
import styles from './styles.module.scss';
|
|
12
17
|
|
|
13
18
|
// Header и Footer surface-aware реализует сам `PopupHeader`/`PopupFooter` (`SheetHeader`/`SheetFooter`):
|
|
14
19
|
// он читает `OverlaySurfaceProvider` и рисует window-раскладку на drawer, bottomSheet — на sheet.
|
|
15
20
|
// Свап остаётся только для Body (desktop-frame vs sheet).
|
|
16
21
|
export type DialogHeaderProps = SheetHeaderProps;
|
|
17
22
|
export type DialogBodyProps = DrawerBodyProps;
|
|
18
|
-
export type DialogFooterProps = SheetFooterProps
|
|
23
|
+
export type DialogFooterProps = SheetFooterProps & {
|
|
24
|
+
/** Основная кнопка. Задаёт штатную раскладку футера — вместо `children`. */
|
|
25
|
+
approveButton?: BottomSheetActionButton;
|
|
26
|
+
/** Кнопка отмены. */
|
|
27
|
+
cancelButton?: BottomSheetActionButton;
|
|
28
|
+
/** Дополнительная (третья) кнопка. */
|
|
29
|
+
additionalButton?: BottomSheetActionButton;
|
|
30
|
+
/** Ориентация кнопок при ровно двух действиях. */
|
|
31
|
+
footerActionsOrientation?: FooterActionsOrientation;
|
|
32
|
+
};
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Шапка панели вместе с верхней safe-area.
|
|
36
|
+
*
|
|
37
|
+
* Отступ лежит здесь, а не во фрейме: иначе его теряет ручная композиция из
|
|
38
|
+
* `DrawerCustom.Header/Body/Footer`. На `sheet` не нужен — там свой `padding-top` в токенах.
|
|
39
|
+
*/
|
|
40
|
+
export function DialogHeader(props: DialogHeaderProps) {
|
|
41
|
+
const isSheet = useOverlaySurface() === OVERLAY_SURFACE.Sheet;
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
{!isSheet && <div className={styles.safeAreaTop} />}
|
|
46
|
+
<SheetHeader {...props} />
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Футер панели вместе с зазором от `Body` (нижняя safe-area; на `sheet` его даёт сам мастер).
|
|
53
|
+
*
|
|
54
|
+
* Кнопки-слоты раскладывает `FooterActions`. `children` — для нестандартного содержимого:
|
|
55
|
+
* раскладку в этом случае обеспечивает потребитель.
|
|
56
|
+
*/
|
|
57
|
+
export function DialogFooter({
|
|
58
|
+
approveButton,
|
|
59
|
+
cancelButton,
|
|
60
|
+
additionalButton,
|
|
61
|
+
footerActionsOrientation,
|
|
62
|
+
children,
|
|
63
|
+
...rest
|
|
64
|
+
}: DialogFooterProps) {
|
|
65
|
+
const isSheet = useOverlaySurface() === OVERLAY_SURFACE.Sheet;
|
|
66
|
+
const hasActions = Boolean(approveButton || cancelButton || additionalButton);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
{!isSheet && <div className={styles.safeAreaBottom} />}
|
|
71
|
+
<SheetFooter {...rest}>
|
|
72
|
+
{hasActions ? (
|
|
73
|
+
<FooterActions
|
|
74
|
+
surface={isSheet ? 'bottomSheet' : 'window'}
|
|
75
|
+
size='l'
|
|
76
|
+
approveButton={approveButton}
|
|
77
|
+
cancelButton={cancelButton}
|
|
78
|
+
additionalButton={additionalButton}
|
|
79
|
+
footerActionsOrientation={footerActionsOrientation}
|
|
80
|
+
testIds={{
|
|
81
|
+
approve: TEST_IDS.footerApprove,
|
|
82
|
+
cancel: TEST_IDS.footerCancel,
|
|
83
|
+
additional: TEST_IDS.footerAdditional,
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
) : (
|
|
87
|
+
children
|
|
88
|
+
)}
|
|
89
|
+
</SheetFooter>
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
22
93
|
|
|
23
94
|
export function DialogBody(props: DialogBodyProps) {
|
|
24
95
|
return useOverlaySurface() === OVERLAY_SURFACE.Sheet ? <SheetBody {...props} /> : <DrawerBody {...props} />;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SheetBodyProps, useOverlayBodyHeightAuto } from '@cloud-ru/ds-bottom-sheet';
|
|
2
2
|
import { Scroll } from '@cloud-ru/ds-scroll';
|
|
3
|
-
import { extractSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
import { extractSupportProps, withInnerRefSupport } from '@cloud-ru/ds-utils';
|
|
4
4
|
import cn from 'classnames';
|
|
5
5
|
|
|
6
6
|
import styles from './styles.module.scss';
|
|
@@ -8,11 +8,12 @@ import styles from './styles.module.scss';
|
|
|
8
8
|
export type DrawerBodyProps = SheetBodyProps;
|
|
9
9
|
|
|
10
10
|
/** Body дровера (desktop): `Scroll`; высота-по-контенту — из overlay-контекста. */
|
|
11
|
-
export function DrawerBody({ content, children, bodyPadding = true, className, ...rest }: DrawerBodyProps) {
|
|
11
|
+
export function DrawerBody({ content, children, bodyPadding = true, innerRef, className, ...rest }: DrawerBodyProps) {
|
|
12
12
|
const heightAutoVertical = useOverlayBodyHeightAuto();
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
15
|
<Scroll
|
|
16
|
+
ref={innerRef}
|
|
16
17
|
size='m'
|
|
17
18
|
barHideStrategy='never'
|
|
18
19
|
className={cn(styles.body, heightAutoVertical && styles.bodyHeightAuto, className)}
|
|
@@ -23,3 +24,5 @@ export function DrawerBody({ content, children, bodyPadding = true, className, .
|
|
|
23
24
|
</Scroll>
|
|
24
25
|
);
|
|
25
26
|
}
|
|
27
|
+
|
|
28
|
+
withInnerRefSupport(DrawerBody);
|
|
@@ -14,6 +14,7 @@ export function MobileDrawer({
|
|
|
14
14
|
media,
|
|
15
15
|
title,
|
|
16
16
|
slotAfterTitle,
|
|
17
|
+
slotSecondTitle,
|
|
17
18
|
subtitle,
|
|
18
19
|
onBackButtonClick,
|
|
19
20
|
approveButton,
|
|
@@ -33,19 +34,21 @@ export function MobileDrawer({
|
|
|
33
34
|
snapIndex,
|
|
34
35
|
onSnapIndexChange,
|
|
35
36
|
safeArea,
|
|
37
|
+
withDividers = false,
|
|
36
38
|
...rest
|
|
37
39
|
}: DrawerProps) {
|
|
38
40
|
// Футер собирает сам `BottomSheet`.
|
|
39
41
|
return (
|
|
40
42
|
<BottomSheet
|
|
41
|
-
// Дефолт `withDividers`
|
|
42
|
-
withDividers={
|
|
43
|
+
// Дефолт `withDividers` в sheet'е — `true`; у Drawer'а вид исторически без разделителей.
|
|
44
|
+
withDividers={withDividers}
|
|
43
45
|
open={open}
|
|
44
46
|
onClose={onClose}
|
|
45
47
|
showBackdrop={showBlackout}
|
|
46
48
|
title={title}
|
|
47
49
|
subtitle={subtitle}
|
|
48
50
|
slotAfterTitle={slotAfterTitle}
|
|
51
|
+
slotSecondTitle={slotSecondTitle}
|
|
49
52
|
onBackButtonClick={onBackButtonClick}
|
|
50
53
|
media={media}
|
|
51
54
|
content={content}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/drawer.module' as drawer;
|
|
3
|
+
|
|
4
|
+
// Safe-area окна описана в слотах, а не во фрейме: иначе её теряет ручная композиция из
|
|
5
|
+
// `DrawerCustom.Header/Body/Footer`, и заголовок прилипает к верхней кромке панели.
|
|
6
|
+
.safeAreaTop {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
align-items: flex-start;
|
|
10
|
+
align-self: stretch;
|
|
11
|
+
|
|
12
|
+
padding-top: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-top');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.safeAreaBottom {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
align-items: flex-start;
|
|
19
|
+
align-self: stretch;
|
|
20
|
+
|
|
21
|
+
padding-bottom: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-bottom');
|
|
22
|
+
}
|