@cloud-ru/ds-drawer 1.0.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 +8 -0
- package/LICENSE +201 -0
- package/README.md +480 -0
- package/dist/cjs/components/Drawer/Drawer.d.ts +6 -0
- package/dist/cjs/components/Drawer/Drawer.js +15 -0
- package/dist/cjs/components/Drawer/constants.d.ts +1 -0
- package/dist/cjs/components/Drawer/constants.js +4 -0
- package/dist/cjs/components/Drawer/index.d.ts +2 -0
- package/dist/cjs/components/Drawer/index.js +18 -0
- package/dist/cjs/components/Drawer/styles.module.css +19 -0
- package/dist/cjs/components/Drawer/types.d.ts +35 -0
- package/dist/cjs/components/Drawer/types.js +2 -0
- package/dist/cjs/components/DrawerCustom/DrawerCustom.d.ts +15 -0
- package/dist/cjs/components/DrawerCustom/DrawerCustom.js +76 -0
- package/dist/cjs/components/DrawerCustom/constants.d.ts +4 -0
- package/dist/cjs/components/DrawerCustom/constants.js +17 -0
- package/dist/cjs/components/DrawerCustom/hooks/index.d.ts +1 -0
- package/dist/cjs/components/DrawerCustom/hooks/index.js +17 -0
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerFocusTrap.d.ts +9 -0
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerFocusTrap.js +83 -0
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.d.ts +15 -0
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.js +50 -0
- package/dist/cjs/components/DrawerCustom/index.d.ts +2 -0
- package/dist/cjs/components/DrawerCustom/index.js +17 -0
- package/dist/cjs/components/DrawerCustom/motion.css +93 -0
- package/dist/cjs/components/DrawerCustom/styles.module.css +491 -0
- package/dist/cjs/components/DrawerCustom/types.d.ts +71 -0
- package/dist/cjs/components/DrawerCustom/types.js +2 -0
- package/dist/cjs/components/index.d.ts +2 -0
- package/dist/cjs/components/index.js +18 -0
- package/dist/cjs/constants.d.ts +28 -0
- package/dist/cjs/constants.js +31 -0
- package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +3 -0
- package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.js +32 -0
- package/dist/cjs/helperComponents/DesktopDrawer/index.d.ts +1 -0
- package/dist/cjs/helperComponents/DesktopDrawer/index.js +17 -0
- package/dist/cjs/helperComponents/DialogSlots.d.ts +8 -0
- package/dist/cjs/helperComponents/DialogSlots.js +12 -0
- package/dist/cjs/helperComponents/DrawerBody/DrawerBody.d.ts +4 -0
- package/dist/cjs/helperComponents/DrawerBody/DrawerBody.js +17 -0
- package/dist/cjs/helperComponents/DrawerBody/index.d.ts +1 -0
- package/dist/cjs/helperComponents/DrawerBody/index.js +17 -0
- package/dist/cjs/helperComponents/DrawerBody/styles.module.css +30 -0
- package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.d.ts +7 -0
- package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.js +26 -0
- package/dist/cjs/helperComponents/MobileDrawer/index.d.ts +1 -0
- package/dist/cjs/helperComponents/MobileDrawer/index.js +17 -0
- package/dist/cjs/helperComponents/index.d.ts +8 -0
- package/dist/cjs/helperComponents/index.js +30 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/style.css +633 -0
- package/dist/cjs/types.d.ts +4 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils/interopDefault.d.ts +7 -0
- package/dist/cjs/utils/interopDefault.js +10 -0
- package/dist/esm/components/Drawer/Drawer.d.ts +6 -0
- package/dist/esm/components/Drawer/Drawer.js +12 -0
- package/dist/esm/components/Drawer/constants.d.ts +1 -0
- package/dist/esm/components/Drawer/constants.js +1 -0
- package/dist/esm/components/Drawer/index.d.ts +2 -0
- package/dist/esm/components/Drawer/index.js +2 -0
- package/dist/esm/components/Drawer/styles.module.css +19 -0
- package/dist/esm/components/Drawer/types.d.ts +35 -0
- package/dist/esm/components/Drawer/types.js +1 -0
- package/dist/esm/components/DrawerCustom/DrawerCustom.d.ts +15 -0
- package/dist/esm/components/DrawerCustom/DrawerCustom.js +70 -0
- package/dist/esm/components/DrawerCustom/constants.d.ts +4 -0
- package/dist/esm/components/DrawerCustom/constants.js +13 -0
- package/dist/esm/components/DrawerCustom/hooks/index.d.ts +1 -0
- package/dist/esm/components/DrawerCustom/hooks/index.js +1 -0
- package/dist/esm/components/DrawerCustom/hooks/useDrawerFocusTrap.d.ts +9 -0
- package/dist/esm/components/DrawerCustom/hooks/useDrawerFocusTrap.js +80 -0
- package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.d.ts +15 -0
- package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.js +47 -0
- package/dist/esm/components/DrawerCustom/index.d.ts +2 -0
- package/dist/esm/components/DrawerCustom/index.js +1 -0
- package/dist/esm/components/DrawerCustom/motion.css +93 -0
- package/dist/esm/components/DrawerCustom/styles.module.css +491 -0
- package/dist/esm/components/DrawerCustom/types.d.ts +71 -0
- package/dist/esm/components/DrawerCustom/types.js +1 -0
- package/dist/esm/components/index.d.ts +2 -0
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/constants.d.ts +28 -0
- package/dist/esm/constants.js +28 -0
- package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +3 -0
- package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.js +26 -0
- package/dist/esm/helperComponents/DesktopDrawer/index.d.ts +1 -0
- package/dist/esm/helperComponents/DesktopDrawer/index.js +1 -0
- package/dist/esm/helperComponents/DialogSlots.d.ts +8 -0
- package/dist/esm/helperComponents/DialogSlots.js +8 -0
- package/dist/esm/helperComponents/DrawerBody/DrawerBody.d.ts +4 -0
- package/dist/esm/helperComponents/DrawerBody/DrawerBody.js +11 -0
- package/dist/esm/helperComponents/DrawerBody/index.d.ts +1 -0
- package/dist/esm/helperComponents/DrawerBody/index.js +1 -0
- package/dist/esm/helperComponents/DrawerBody/styles.module.css +30 -0
- package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.d.ts +7 -0
- package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.js +23 -0
- package/dist/esm/helperComponents/MobileDrawer/index.d.ts +1 -0
- package/dist/esm/helperComponents/MobileDrawer/index.js +1 -0
- package/dist/esm/helperComponents/index.d.ts +8 -0
- package/dist/esm/helperComponents/index.js +8 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/style.css +633 -0
- package/dist/esm/types.d.ts +4 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/interopDefault.d.ts +7 -0
- package/dist/esm/utils/interopDefault.js +7 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +51 -0
- package/src/components/Drawer/Drawer.tsx +15 -0
- package/src/components/Drawer/constants.ts +1 -0
- package/src/components/Drawer/index.ts +2 -0
- package/src/components/Drawer/styles.module.scss +26 -0
- package/src/components/Drawer/types.ts +42 -0
- package/src/components/DrawerCustom/DrawerCustom.tsx +197 -0
- package/src/components/DrawerCustom/constants.ts +17 -0
- package/src/components/DrawerCustom/hooks/index.ts +1 -0
- package/src/components/DrawerCustom/hooks/useDrawerFocusTrap.ts +97 -0
- package/src/components/DrawerCustom/hooks/useDrawerResize.tsx +78 -0
- package/src/components/DrawerCustom/index.ts +2 -0
- package/src/components/DrawerCustom/styles.module.scss +330 -0
- package/src/components/DrawerCustom/types.ts +77 -0
- package/src/components/index.ts +2 -0
- package/src/constants.ts +31 -0
- package/src/helperComponents/DesktopDrawer/DesktopDrawer.tsx +85 -0
- package/src/helperComponents/DesktopDrawer/index.ts +1 -0
- package/src/helperComponents/DialogSlots.tsx +25 -0
- package/src/helperComponents/DrawerBody/DrawerBody.tsx +25 -0
- package/src/helperComponents/DrawerBody/index.ts +1 -0
- package/src/helperComponents/DrawerBody/styles.module.scss +32 -0
- package/src/helperComponents/MobileDrawer/MobileDrawer.tsx +75 -0
- package/src/helperComponents/MobileDrawer/index.ts +1 -0
- package/src/helperComponents/index.ts +11 -0
- package/src/index.ts +6 -0
- package/src/types.ts +6 -0
- package/src/utils/interopDefault.ts +7 -0
|
@@ -0,0 +1,330 @@
|
|
|
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
|
+
// Отступ close-кнопки — общий токен «window»-поверхности из коллекции popupPrivate
|
|
4
|
+
// (она несёт и padding ×4, и min-size/border-radius кнопки).
|
|
5
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/popupPrivate.module' as popupPrivate;
|
|
6
|
+
@use '@cloud-ru/ds-materials' as m;
|
|
7
|
+
|
|
8
|
+
$widthSizes: 's', 'm', 'l';
|
|
9
|
+
$draggerWidth: base.$sn-primitive-dimension-4;
|
|
10
|
+
$draggerPosition: calc(drawer.$sn-drawer-anatomy-container-vertical-positionLeft-paddingRight - $draggerWidth - base.$sn-primitive-dimension-6);
|
|
11
|
+
$activeDraggerHeight: calc(base.$sn-primitive-dimension-32 + base.$sn-primitive-dimension-24);
|
|
12
|
+
|
|
13
|
+
// placement → offscreen transform для panelMotion-*
|
|
14
|
+
$panelMotions: (
|
|
15
|
+
'left': translateX(-100%),
|
|
16
|
+
'right': translateX(100%),
|
|
17
|
+
'top': translateY(-100%),
|
|
18
|
+
'bottom': translateY(100%),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
.drawerRoot:global(.snack-rc-drawer) {
|
|
22
|
+
pointer-events: none;
|
|
23
|
+
|
|
24
|
+
position: fixed;
|
|
25
|
+
z-index: initial;
|
|
26
|
+
inset: 0;
|
|
27
|
+
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
|
|
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);
|
|
31
|
+
|
|
32
|
+
&:global(> *) {
|
|
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);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&:global(.snack-rc-drawer-open) {
|
|
37
|
+
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:global {
|
|
41
|
+
.snack-rc-drawer-mask {
|
|
42
|
+
pointer-events: auto;
|
|
43
|
+
|
|
44
|
+
position: absolute;
|
|
45
|
+
z-index: initial;
|
|
46
|
+
inset: 0;
|
|
47
|
+
|
|
48
|
+
opacity: 1;
|
|
49
|
+
background-color: base.$sn-theme-color-blackout;
|
|
50
|
+
|
|
51
|
+
transition: opacity 0.2s;
|
|
52
|
+
|
|
53
|
+
&.maskMotion-enter,
|
|
54
|
+
&.maskMotion-appear {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&.maskMotion-enter-active,
|
|
59
|
+
&.maskMotion-appear-active {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&.maskMotion-leave {
|
|
64
|
+
opacity: 1;
|
|
65
|
+
transition: opacity 0.1s;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&.maskMotion-leave-active {
|
|
69
|
+
opacity: 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.snack-rc-drawer-section {
|
|
74
|
+
pointer-events: auto;
|
|
75
|
+
|
|
76
|
+
position: relative;
|
|
77
|
+
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
flex-grow: 1;
|
|
81
|
+
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
width: 100%;
|
|
84
|
+
// Тень панели из макета (`elevation-level5`). Раньше правило висело на `&:global(...)`,
|
|
85
|
+
// то есть требовало оба класса на одном узле, и не срабатывало никогда.
|
|
86
|
+
box-shadow: base.$sn-boxShadow-elevation-level5;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.snack-rc-drawer-content-wrapper {
|
|
90
|
+
pointer-events: none;
|
|
91
|
+
will-change: transform;
|
|
92
|
+
|
|
93
|
+
position: absolute;
|
|
94
|
+
z-index: initial;
|
|
95
|
+
|
|
96
|
+
overflow: unset;
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
align-items: flex-start;
|
|
100
|
+
|
|
101
|
+
max-width: 100%;
|
|
102
|
+
|
|
103
|
+
background: none;
|
|
104
|
+
box-shadow: none;
|
|
105
|
+
|
|
106
|
+
transition: transform 0.2s ease-in-out;
|
|
107
|
+
|
|
108
|
+
&[data-position='top'] {
|
|
109
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionTop');
|
|
110
|
+
|
|
111
|
+
.snack-rc-drawer-section {
|
|
112
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionTop', 'container');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&[data-position='bottom'] {
|
|
117
|
+
bottom: 0;
|
|
118
|
+
|
|
119
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionBottom');
|
|
120
|
+
|
|
121
|
+
.snack-rc-drawer-section {
|
|
122
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'horizontal', 'positionBottom', 'container');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&[data-position='left'] {
|
|
127
|
+
top: 0;
|
|
128
|
+
bottom: 0;
|
|
129
|
+
left: 0;
|
|
130
|
+
|
|
131
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionLeft');
|
|
132
|
+
|
|
133
|
+
.snack-rc-drawer-section {
|
|
134
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionLeft', 'container');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&[data-position='right'] {
|
|
139
|
+
top: 0;
|
|
140
|
+
right: 0;
|
|
141
|
+
bottom: 0;
|
|
142
|
+
|
|
143
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionRight');
|
|
144
|
+
|
|
145
|
+
.snack-rc-drawer-section {
|
|
146
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'positionRight', 'container');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&[data-position='left'],
|
|
151
|
+
&[data-position='right'] {
|
|
152
|
+
align-items: stretch;
|
|
153
|
+
// Ширина в макете — это ширина самой панели; горизонтальный паддинг обёртки
|
|
154
|
+
// (зона перетаскивания) лежит снаружи и не должен её сужать.
|
|
155
|
+
box-sizing: content-box;
|
|
156
|
+
height: 100%;
|
|
157
|
+
|
|
158
|
+
@each $width in $widthSizes {
|
|
159
|
+
&[data-width='#{$width}'] {
|
|
160
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'width', 'container', $width);
|
|
161
|
+
|
|
162
|
+
width: min(100%, base.simple-var(drawer.$drawer, 'anatomy', 'container', 'vertical', 'width', 'container', $width, 'max-width'));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
&[data-position='top'],
|
|
168
|
+
&[data-position='bottom'] {
|
|
169
|
+
width: 100%;
|
|
170
|
+
height: 100%;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
&[data-position='top'][data-height-auto],
|
|
174
|
+
&[data-position='bottom'][data-height-auto] {
|
|
175
|
+
height: auto;
|
|
176
|
+
max-height: 100%;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
&[data-position='top'][data-height-auto] {
|
|
180
|
+
inset: 0 0 auto;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&[data-position='bottom'][data-height-auto] {
|
|
184
|
+
inset: auto 0 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@each $placement, $offscreen in $panelMotions {
|
|
188
|
+
&.panelMotion-#{$placement}-enter,
|
|
189
|
+
&.panelMotion-#{$placement}-appear {
|
|
190
|
+
transform: $offscreen;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
&.panelMotion-#{$placement}-enter-active,
|
|
194
|
+
&.panelMotion-#{$placement}-appear-active {
|
|
195
|
+
transform: translate(0);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
&.panelMotion-#{$placement}-leave {
|
|
199
|
+
transform: translate(0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&.panelMotion-#{$placement}-leave-active {
|
|
203
|
+
transform: $offscreen;
|
|
204
|
+
transition: transform 0.1s ease-out;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.snack-rc-drawer-content-wrapper-hidden {
|
|
210
|
+
display: none;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.snack-rc-drawer-resizable-dragger {
|
|
214
|
+
pointer-events: auto;
|
|
215
|
+
cursor: ew-resize;
|
|
216
|
+
|
|
217
|
+
position: absolute;
|
|
218
|
+
z-index: 2;
|
|
219
|
+
top: 50%;
|
|
220
|
+
transform: translateY(-50%);
|
|
221
|
+
|
|
222
|
+
width: $draggerWidth;
|
|
223
|
+
height: base.$sn-primitive-dimension-32;
|
|
224
|
+
border-radius: base.$sn-density-radius-2xs;
|
|
225
|
+
|
|
226
|
+
background-color: base.$sn-theme-color-neutral-decor;
|
|
227
|
+
|
|
228
|
+
transition: height ease-in-out 0.2s;
|
|
229
|
+
|
|
230
|
+
&::after {
|
|
231
|
+
content: '';
|
|
232
|
+
|
|
233
|
+
position: absolute;
|
|
234
|
+
top: 50%;
|
|
235
|
+
left: 50%;
|
|
236
|
+
transform: translate(-50%, -50%);
|
|
237
|
+
|
|
238
|
+
width: calc(100% + base.$sn-primitive-dimension-12);
|
|
239
|
+
height: 100vh;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
&:hover {
|
|
243
|
+
height: $activeDraggerHeight;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.snack-rc-drawer-resizable-dragger-left {
|
|
248
|
+
right: $draggerPosition;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.snack-rc-drawer-resizable-dragger-right {
|
|
252
|
+
left: $draggerPosition;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
&:global(.snack-rc-drawer-left),
|
|
257
|
+
&:global(.snack-rc-drawer-right) {
|
|
258
|
+
top: 0;
|
|
259
|
+
width: 0%;
|
|
260
|
+
height: 100%;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
&:global(.snack-rc-drawer-left) {
|
|
264
|
+
left: 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
&:global(.snack-rc-drawer-right) {
|
|
268
|
+
right: 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
&:global(.snack-rc-drawer-top),
|
|
272
|
+
&:global(.snack-rc-drawer-bottom) {
|
|
273
|
+
left: 0;
|
|
274
|
+
width: 100%;
|
|
275
|
+
height: 0%;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
&:global(.snack-rc-drawer-top) {
|
|
279
|
+
top: 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
&:global(.snack-rc-drawer-bottom) {
|
|
283
|
+
bottom: 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
&:has(:global(.snack-rc-drawer-resizable-dragger-dragging)) {
|
|
287
|
+
cursor: ew-resize;
|
|
288
|
+
|
|
289
|
+
:global(.snack-rc-drawer-resizable-dragger) {
|
|
290
|
+
height: $activeDraggerHeight;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
&:global(.snack-rc-drawer-left.snack-rc-drawer-open),
|
|
296
|
+
&:global(.snack-rc-drawer-right.snack-rc-drawer-open) {
|
|
297
|
+
width: 100%;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
&:global(.snack-rc-drawer-top.snack-rc-drawer-open),
|
|
301
|
+
&:global(.snack-rc-drawer-bottom.snack-rc-drawer-open) {
|
|
302
|
+
height: 100%;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.drawerRoot:global(.snack-rc-drawer .snack-rc-drawer-content-wrapper) {
|
|
307
|
+
@include m.with-material('acrylic', #{drawer});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.focusScope {
|
|
311
|
+
display: contents;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.showButtonClosed {
|
|
315
|
+
margin: base.simple-var(popupPrivate.$popupPrivate, 'anatomy', 'window', 'badgeButtonClosed', 'padding-top') base.simple-var(popupPrivate.$popupPrivate, 'anatomy', 'window', 'badgeButtonClosed', 'padding-right') base.simple-var(popupPrivate.$popupPrivate, 'anatomy', 'window', 'badgeButtonClosed', 'padding-bottom') base.simple-var(popupPrivate.$popupPrivate, 'anatomy', 'window', 'badgeButtonClosed', 'padding-left');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.showButtonClosedWrapper {
|
|
319
|
+
position: absolute;
|
|
320
|
+
top: 0;
|
|
321
|
+
right: 0;
|
|
322
|
+
|
|
323
|
+
display: flex;
|
|
324
|
+
flex-direction: column;
|
|
325
|
+
align-items: center;
|
|
326
|
+
justify-content: center;
|
|
327
|
+
|
|
328
|
+
width: 0;
|
|
329
|
+
height: 0;
|
|
330
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BottomSheetCustomProps } from '@cloud-ru/ds-bottom-sheet';
|
|
2
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
import { DrawerProps as RcDrawerProps } from '@rc-component/drawer';
|
|
4
|
+
import { PropsWithChildren, ReactElement } from 'react';
|
|
5
|
+
|
|
6
|
+
import { Position, Width } from '../../types';
|
|
7
|
+
|
|
8
|
+
export type DrawerCustomProps = WithSupportProps<
|
|
9
|
+
PropsWithChildren<{
|
|
10
|
+
/** Управление состоянием показан/не показан. */
|
|
11
|
+
open: boolean;
|
|
12
|
+
/** Колбэк закрытия */
|
|
13
|
+
onClose(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Отображение темной подложки
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
showBlackout?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Отображение кнопки закрытия в шапке дровера
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
showButtonClosed?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Расположение
|
|
26
|
+
*/
|
|
27
|
+
position: Position;
|
|
28
|
+
/**
|
|
29
|
+
* Ширина (только при position: "left" | "right")
|
|
30
|
+
* @default 's'
|
|
31
|
+
*/
|
|
32
|
+
width?: Width | string | number;
|
|
33
|
+
/**
|
|
34
|
+
* Высота панели по контенту (только при `position: "top" | "bottom"`).
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
heightAuto?: boolean;
|
|
38
|
+
/** CSS-класс для элемента с контентом */
|
|
39
|
+
className?: string;
|
|
40
|
+
/** CSS-класс для корневого элемента */
|
|
41
|
+
rootClassName?: string;
|
|
42
|
+
/** Смещение при открытии "вложенного" компонента */
|
|
43
|
+
push?: RcDrawerProps['push'];
|
|
44
|
+
/** Контейнер в котором будет рендерится Drawer. По-умолчанию - body */
|
|
45
|
+
container?: string | HTMLElement;
|
|
46
|
+
/** Вложенный Drawer */
|
|
47
|
+
nestedDrawer?: ReactElement<Omit<DrawerCustomProps, 'resizable'>>;
|
|
48
|
+
/** Закрывать дровер при перемещении по истории браузера */
|
|
49
|
+
closeOnPopstate?: boolean;
|
|
50
|
+
/** Футер */
|
|
51
|
+
footer?: ReactElement;
|
|
52
|
+
/** Отключить анимации
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
disableMotions?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Ширина (только при position: "left" | "right")
|
|
58
|
+
* @default 's'
|
|
59
|
+
*/
|
|
60
|
+
resizable?: {
|
|
61
|
+
/** Минимальная доступная ширина */
|
|
62
|
+
min: number;
|
|
63
|
+
/** Максимальная доступная ширина */
|
|
64
|
+
max?: number;
|
|
65
|
+
/** Ширина по умолчанию */
|
|
66
|
+
default?: number;
|
|
67
|
+
/** Колбэк на изменение размера */
|
|
68
|
+
onResize?: (width: number) => void;
|
|
69
|
+
/** Колбэк на окончание изменения размера */
|
|
70
|
+
onResizeEnd?: (width: number) => void;
|
|
71
|
+
/** Tooltip для элемента dragger */
|
|
72
|
+
draggerTooltip?: string;
|
|
73
|
+
};
|
|
74
|
+
}>
|
|
75
|
+
> &
|
|
76
|
+
// Только mobile: управляют sheet-поверхностью (на desktop игнорируются).
|
|
77
|
+
Pick<BottomSheetCustomProps, 'snapPoints' | 'swipeEnabled' | 'safeArea'>;
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const TEST_IDS = {
|
|
2
|
+
closeButton: 'drawer__close-button',
|
|
3
|
+
header: 'drawer__header',
|
|
4
|
+
title: 'drawer__title',
|
|
5
|
+
image: 'drawer__image',
|
|
6
|
+
tooltip: 'drawer__title-tooltip',
|
|
7
|
+
subtitle: 'drawer__subtitle',
|
|
8
|
+
body: 'drawer__body',
|
|
9
|
+
footer: 'drawer__footer',
|
|
10
|
+
footerApprove: 'drawer__footer-approve',
|
|
11
|
+
footerCancel: 'drawer__footer-cancel',
|
|
12
|
+
footerAdditional: 'drawer__footer-additional',
|
|
13
|
+
nestedDrawer: 'drawer__nested',
|
|
14
|
+
overlay: 'drawer__overlay',
|
|
15
|
+
contentWrapper: 'drawer__content-wrapper',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
export const WIDTH = {
|
|
19
|
+
S: 's',
|
|
20
|
+
M: 'm',
|
|
21
|
+
L: 'l',
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export const WIDTH_AS_VALUES: string[] = Object.values(WIDTH);
|
|
25
|
+
|
|
26
|
+
export const POSITION = {
|
|
27
|
+
Left: 'left',
|
|
28
|
+
Right: 'right',
|
|
29
|
+
Top: 'top',
|
|
30
|
+
Bottom: 'bottom',
|
|
31
|
+
} as const;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { FooterActions } from '@cloud-ru/ds-bottom-sheet';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
|
|
4
|
+
import { NESTED_DRAWER_PUSH_DISTANCE } from '../../components/Drawer/constants';
|
|
5
|
+
import styles from '../../components/Drawer/styles.module.scss';
|
|
6
|
+
import { DrawerProps } from '../../components/Drawer/types';
|
|
7
|
+
import { DrawerCustom } from '../../components/DrawerCustom';
|
|
8
|
+
import { TEST_IDS } from '../../constants';
|
|
9
|
+
|
|
10
|
+
/** Desktop-поверхность Drawer'а: панель (`DrawerCustom`) с пресетной разметкой. Internal. */
|
|
11
|
+
export function DesktopDrawer({
|
|
12
|
+
content,
|
|
13
|
+
media,
|
|
14
|
+
title,
|
|
15
|
+
slotAfterTitle,
|
|
16
|
+
subtitle,
|
|
17
|
+
onBackButtonClick,
|
|
18
|
+
approveButton,
|
|
19
|
+
cancelButton,
|
|
20
|
+
additionalButton,
|
|
21
|
+
footerActionsOrientation,
|
|
22
|
+
footer,
|
|
23
|
+
nestedDrawer,
|
|
24
|
+
className,
|
|
25
|
+
...rest
|
|
26
|
+
}: DrawerProps) {
|
|
27
|
+
const showHeader = Boolean(title || subtitle || slotAfterTitle);
|
|
28
|
+
// Футер: произвольный `footer` (приоритет) либо сборка из слотов через общий `FooterActions`.
|
|
29
|
+
const footerContent =
|
|
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);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<DrawerCustom
|
|
49
|
+
{...rest}
|
|
50
|
+
resizable={undefined}
|
|
51
|
+
className={cn(styles.drawer, className)}
|
|
52
|
+
push={Boolean(nestedDrawer) && { distance: NESTED_DRAWER_PUSH_DISTANCE }}
|
|
53
|
+
>
|
|
54
|
+
{media}
|
|
55
|
+
|
|
56
|
+
<div className={styles.safeAreaTop} />
|
|
57
|
+
|
|
58
|
+
{showHeader && (
|
|
59
|
+
<DrawerCustom.Header
|
|
60
|
+
title={title}
|
|
61
|
+
slotAfterTitle={slotAfterTitle}
|
|
62
|
+
subtitle={subtitle}
|
|
63
|
+
onBackButtonClick={onBackButtonClick}
|
|
64
|
+
// Сохраняем публичный контракт test-id'ов drawer'а поверх общего `PopupHeader`.
|
|
65
|
+
// slotAfterTitle НЕ переопределяем: id тултипа ставит сам потребитель на своём span.
|
|
66
|
+
testIds={{
|
|
67
|
+
header: TEST_IDS.header,
|
|
68
|
+
title: TEST_IDS.title,
|
|
69
|
+
subtitle: TEST_IDS.subtitle,
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
<DrawerCustom.Body data-test-id={TEST_IDS.body} content={content} />
|
|
75
|
+
|
|
76
|
+
<div className={styles.safeAreaBottom} />
|
|
77
|
+
|
|
78
|
+
{footerContent != null && (
|
|
79
|
+
<DrawerCustom.Footer data-test-id={TEST_IDS.footer}>{footerContent}</DrawerCustom.Footer>
|
|
80
|
+
)}
|
|
81
|
+
|
|
82
|
+
{nestedDrawer}
|
|
83
|
+
</DrawerCustom>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DesktopDrawer';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OVERLAY_SURFACE,
|
|
3
|
+
SheetBody,
|
|
4
|
+
SheetFooter,
|
|
5
|
+
SheetFooterProps,
|
|
6
|
+
SheetHeader,
|
|
7
|
+
SheetHeaderProps,
|
|
8
|
+
useOverlaySurface,
|
|
9
|
+
} from '@cloud-ru/ds-bottom-sheet';
|
|
10
|
+
|
|
11
|
+
import { DrawerBody, DrawerBodyProps } from './DrawerBody';
|
|
12
|
+
|
|
13
|
+
// Header и Footer surface-aware реализует сам `PopupHeader`/`PopupFooter` (`SheetHeader`/`SheetFooter`):
|
|
14
|
+
// он читает `OverlaySurfaceProvider` и рисует window-раскладку на drawer, bottomSheet — на sheet.
|
|
15
|
+
// Свап остаётся только для Body (desktop-frame vs sheet).
|
|
16
|
+
export type DialogHeaderProps = SheetHeaderProps;
|
|
17
|
+
export type DialogBodyProps = DrawerBodyProps;
|
|
18
|
+
export type DialogFooterProps = SheetFooterProps;
|
|
19
|
+
|
|
20
|
+
export const DialogHeader = SheetHeader;
|
|
21
|
+
export const DialogFooter = SheetFooter;
|
|
22
|
+
|
|
23
|
+
export function DialogBody(props: DialogBodyProps) {
|
|
24
|
+
return useOverlaySurface() === OVERLAY_SURFACE.Sheet ? <SheetBody {...props} /> : <DrawerBody {...props} />;
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SheetBodyProps, useOverlayBodyHeightAuto } from '@cloud-ru/ds-bottom-sheet';
|
|
2
|
+
import { Scroll } from '@cloud-ru/ds-scroll';
|
|
3
|
+
import { extractSupportProps } from '@cloud-ru/ds-utils';
|
|
4
|
+
import cn from 'classnames';
|
|
5
|
+
|
|
6
|
+
import styles from './styles.module.scss';
|
|
7
|
+
|
|
8
|
+
export type DrawerBodyProps = SheetBodyProps;
|
|
9
|
+
|
|
10
|
+
/** Body дровера (desktop): `Scroll`; высота-по-контенту — из overlay-контекста. */
|
|
11
|
+
export function DrawerBody({ content, children, bodyPadding = true, className, ...rest }: DrawerBodyProps) {
|
|
12
|
+
const heightAutoVertical = useOverlayBodyHeightAuto();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Scroll
|
|
16
|
+
size='m'
|
|
17
|
+
barHideStrategy='never'
|
|
18
|
+
className={cn(styles.body, heightAutoVertical && styles.bodyHeightAuto, className)}
|
|
19
|
+
data-no-padding={bodyPadding === false || undefined}
|
|
20
|
+
{...extractSupportProps(rest)}
|
|
21
|
+
>
|
|
22
|
+
{children ?? content}
|
|
23
|
+
</Scroll>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DrawerBody';
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
// Ветка surface='drawer' (1:1 из `@cloud-ru/ds-drawer` Body).
|
|
5
|
+
.body {
|
|
6
|
+
@include base.composite-var(drawer.$drawer, 'anatomy', 'container', 'bodyWrapper');
|
|
7
|
+
|
|
8
|
+
display: flex;
|
|
9
|
+
flex: 1 0 0;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
align-items: flex-start;
|
|
12
|
+
align-self: stretch;
|
|
13
|
+
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
|
|
16
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
17
|
+
|
|
18
|
+
@include base.composite-var(base.$sn-regular-body-m);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.body[data-no-padding] {
|
|
22
|
+
padding-right: 0;
|
|
23
|
+
padding-left: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* heightAuto + top/bottom: высота по контенту, при переполнении — flex-скролл. */
|
|
27
|
+
.bodyHeightAuto {
|
|
28
|
+
flex: 0 1 auto;
|
|
29
|
+
height: auto !important; /* stylelint-disable-line declaration-no-important */
|
|
30
|
+
min-height: 0;
|
|
31
|
+
max-height: 100%;
|
|
32
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { BottomSheet } from '@cloud-ru/ds-bottom-sheet';
|
|
2
|
+
import { extractSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
|
|
4
|
+
import { DrawerProps } from '../../components/Drawer/types';
|
|
5
|
+
import { TEST_IDS } from '../../constants';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mobile-поверхность Drawer'а: контент в `BottomSheet`, слоты маппятся на API sheet'а
|
|
9
|
+
* (`subtitle` 1:1, `showBlackout→showBackdrop`, остальное 1:1). Internal. Desktop-only пропы
|
|
10
|
+
* уходят в `...rest`.
|
|
11
|
+
*/
|
|
12
|
+
export function MobileDrawer({
|
|
13
|
+
content,
|
|
14
|
+
media,
|
|
15
|
+
title,
|
|
16
|
+
slotAfterTitle,
|
|
17
|
+
subtitle,
|
|
18
|
+
onBackButtonClick,
|
|
19
|
+
approveButton,
|
|
20
|
+
cancelButton,
|
|
21
|
+
additionalButton,
|
|
22
|
+
footerActionsOrientation,
|
|
23
|
+
footer,
|
|
24
|
+
className,
|
|
25
|
+
rootClassName,
|
|
26
|
+
open,
|
|
27
|
+
onClose,
|
|
28
|
+
showBlackout,
|
|
29
|
+
container,
|
|
30
|
+
closeOnPopstate,
|
|
31
|
+
swipeEnabled,
|
|
32
|
+
snapPoints,
|
|
33
|
+
snapIndex,
|
|
34
|
+
onSnapIndexChange,
|
|
35
|
+
safeArea,
|
|
36
|
+
...rest
|
|
37
|
+
}: DrawerProps) {
|
|
38
|
+
// Футер собирает сам `BottomSheet`.
|
|
39
|
+
return (
|
|
40
|
+
<BottomSheet
|
|
41
|
+
// Дефолт `withDividers` сменился на `true` — здесь вид сохраняем прежним.
|
|
42
|
+
withDividers={false}
|
|
43
|
+
open={open}
|
|
44
|
+
onClose={onClose}
|
|
45
|
+
showBackdrop={showBlackout}
|
|
46
|
+
title={title}
|
|
47
|
+
subtitle={subtitle}
|
|
48
|
+
slotAfterTitle={slotAfterTitle}
|
|
49
|
+
onBackButtonClick={onBackButtonClick}
|
|
50
|
+
media={media}
|
|
51
|
+
content={content}
|
|
52
|
+
approveButton={approveButton}
|
|
53
|
+
cancelButton={cancelButton}
|
|
54
|
+
additionalButton={additionalButton}
|
|
55
|
+
footerActionsOrientation={footerActionsOrientation}
|
|
56
|
+
footer={footer}
|
|
57
|
+
// Те же id футера, что у desktop-поверхности — стабильный селектор при свапе surface.
|
|
58
|
+
footerTestIds={{
|
|
59
|
+
approve: TEST_IDS.footerApprove,
|
|
60
|
+
cancel: TEST_IDS.footerCancel,
|
|
61
|
+
additional: TEST_IDS.footerAdditional,
|
|
62
|
+
}}
|
|
63
|
+
className={className}
|
|
64
|
+
rootClassName={rootClassName}
|
|
65
|
+
container={container}
|
|
66
|
+
closeOnPopstate={closeOnPopstate}
|
|
67
|
+
swipeEnabled={swipeEnabled}
|
|
68
|
+
snapPoints={snapPoints}
|
|
69
|
+
snapIndex={snapIndex}
|
|
70
|
+
onSnapIndexChange={onSnapIndexChange}
|
|
71
|
+
safeArea={safeArea}
|
|
72
|
+
{...extractSupportProps(rest)}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './MobileDrawer';
|