@cloud-ru/ds-drawer 2.0.1-preview-20b4671f.0 → 2.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 +6 -0
- package/README.md +4 -2
- package/dist/cjs/components/DrawerCustom/DrawerCustom.js +2 -2
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.d.ts +2 -0
- package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.js +21 -10
- package/dist/cjs/components/DrawerCustom/styles.module.css +4 -0
- package/dist/cjs/components/DrawerCustom/types.d.ts +6 -3
- package/dist/cjs/constants.d.ts +4 -0
- package/dist/cjs/constants.js +5 -1
- package/dist/cjs/style.css +4 -0
- package/dist/cjs/types.d.ts +2 -1
- package/dist/esm/components/DrawerCustom/DrawerCustom.js +2 -2
- package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.d.ts +2 -0
- package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.js +21 -10
- package/dist/esm/components/DrawerCustom/styles.module.css +4 -0
- package/dist/esm/components/DrawerCustom/types.d.ts +6 -3
- package/dist/esm/constants.d.ts +4 -0
- package/dist/esm/constants.js +4 -0
- package/dist/esm/style.css +4 -0
- package/dist/esm/types.d.ts +2 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/components/DrawerCustom/DrawerCustom.tsx +2 -0
- package/src/components/DrawerCustom/hooks/useDrawerResize.tsx +26 -9
- package/src/components/DrawerCustom/styles.module.scss +12 -0
- package/src/components/DrawerCustom/types.ts +6 -3
- package/src/constants.ts +6 -0
- package/src/types.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloud-ru/ds-drawer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.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-
|
|
44
|
-
"@cloud-ru/ds-
|
|
45
|
-
"@cloud-ru/ds-
|
|
46
|
-
"@cloud-ru/ds-
|
|
47
|
-
"@cloud-ru/ds-
|
|
48
|
-
"@cloud-ru/ds-
|
|
49
|
-
"@cloud-ru/ds-
|
|
50
|
-
"@cloud-ru/ds-
|
|
43
|
+
"@cloud-ru/ds-adaptive": "^1.0.2",
|
|
44
|
+
"@cloud-ru/ds-materials": "^2.0.1",
|
|
45
|
+
"@cloud-ru/ds-popup-private": "^1.1.10",
|
|
46
|
+
"@cloud-ru/ds-portal-context": "^1.0.2",
|
|
47
|
+
"@cloud-ru/ds-bottom-sheet": "^2.0.1",
|
|
48
|
+
"@cloud-ru/ds-scroll": "^1.0.5",
|
|
49
|
+
"@cloud-ru/ds-tooltip": "^1.0.12",
|
|
50
|
+
"@cloud-ru/ds-utils": "^1.2.0"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -54,6 +54,7 @@ function DrawerFrame(props: DrawerCustomProps) {
|
|
|
54
54
|
checkElement,
|
|
55
55
|
width: userWidth,
|
|
56
56
|
resizable: drawerResizable,
|
|
57
|
+
isResizing,
|
|
57
58
|
} = useDrawerResize({
|
|
58
59
|
resizable,
|
|
59
60
|
position,
|
|
@@ -112,6 +113,7 @@ function DrawerFrame(props: DrawerCustomProps) {
|
|
|
112
113
|
}}
|
|
113
114
|
size={isPredefinedWidth ? 'null' : width}
|
|
114
115
|
{...extractSupportProps(rest)}
|
|
116
|
+
data-resizing={isResizing || undefined}
|
|
115
117
|
data-content-wrapper
|
|
116
118
|
data-position={position}
|
|
117
119
|
data-width={isPredefinedWidth ? width : undefined}
|
|
@@ -3,6 +3,7 @@ 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 { RESIZABLE_MAX_FULL } from '../../../constants';
|
|
6
7
|
import styles from '../styles.module.scss';
|
|
7
8
|
import { DrawerCustomProps } from '../types';
|
|
8
9
|
|
|
@@ -19,8 +20,12 @@ type UseDrawerResizeResult = {
|
|
|
19
20
|
resizable: DrawerProps['resizable'];
|
|
20
21
|
/** Ширина ползунка в пикселях */
|
|
21
22
|
width?: number;
|
|
23
|
+
/** Флаг, указывающий, что дровер в процессе ресайза */
|
|
24
|
+
isResizing: boolean;
|
|
22
25
|
};
|
|
23
26
|
|
|
27
|
+
const getFullMaxWidth = () => (isBrowser() ? Math.max(0, document.documentElement.clientWidth) : Infinity);
|
|
28
|
+
|
|
24
29
|
export function useDrawerResize({ position, resizable: resizableProp }: UseDrawerResizeParams): UseDrawerResizeResult {
|
|
25
30
|
const targetRef = useRef<HTMLElement | null>(null);
|
|
26
31
|
const targetRefCallbackRef = useRef<(node: HTMLElement) => void | undefined>();
|
|
@@ -56,31 +61,43 @@ export function useDrawerResize({ position, resizable: resizableProp }: UseDrawe
|
|
|
56
61
|
</Tooltip>
|
|
57
62
|
) : null;
|
|
58
63
|
|
|
64
|
+
const { onResize, onResizeEnd, max, min } = resizableProp ?? {};
|
|
65
|
+
const resizeEnabled = Boolean(resizableProp);
|
|
66
|
+
// Сколько стартовой ширины, которую держит rc-drawer, не помещается в окно: оно могло сузиться, пока дровер
|
|
67
|
+
// был закрыт или открыт. CSS обрезает панель визуально, а rc-drawer считает ресайз от «виртуальной» ширины.
|
|
68
|
+
const excessRef = useRef(0);
|
|
69
|
+
|
|
59
70
|
const resizable = useMemo(
|
|
60
71
|
() =>
|
|
61
|
-
|
|
72
|
+
resizeEnabled
|
|
62
73
|
? ({
|
|
63
|
-
onResize:
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
onResize: rawValue => {
|
|
75
|
+
// Смещение мыши rc-drawer прибавляет к устаревшей стартовой ширине: вычитаем лишнее.
|
|
76
|
+
const limit = max === RESIZABLE_MAX_FULL ? getFullMaxWidth() : max;
|
|
77
|
+
const value = Math.min(rawValue - excessRef.current, limit ?? Infinity);
|
|
78
|
+
|
|
79
|
+
if (value < (min || 0)) return;
|
|
66
80
|
|
|
67
81
|
setWidth(value);
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
onResize?.(value);
|
|
70
84
|
},
|
|
71
85
|
onResizeEnd: () => {
|
|
72
86
|
setOpen(false);
|
|
73
87
|
setMuted(false);
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
onResizeEnd?.(width ?? 0);
|
|
76
90
|
},
|
|
77
|
-
|
|
91
|
+
// rc-drawer передаёт во время выполнения реальную стартовую ширину (в типах аргумента нет).
|
|
92
|
+
onResizeStart: (startSize?: number) => {
|
|
93
|
+
excessRef.current =
|
|
94
|
+
max === RESIZABLE_MAX_FULL && startSize !== undefined ? Math.max(0, startSize - getFullMaxWidth()) : 0;
|
|
78
95
|
setMuted(true);
|
|
79
96
|
},
|
|
80
97
|
} satisfies DrawerProps['resizable'])
|
|
81
98
|
: undefined,
|
|
82
|
-
[
|
|
99
|
+
[width, max, min, onResize, onResizeEnd, resizeEnabled],
|
|
83
100
|
);
|
|
84
101
|
|
|
85
|
-
return { tooltip, checkElement, resizable, width };
|
|
102
|
+
return { tooltip, checkElement, resizable, width, isResizing: muted };
|
|
86
103
|
}
|
|
@@ -175,6 +175,12 @@ $panelMotions: (
|
|
|
175
175
|
// Ширина в макете — это ширина самой панели; горизонтальный паддинг обёртки
|
|
176
176
|
// (зона перетаскивания) лежит снаружи и не должен её сужать.
|
|
177
177
|
box-sizing: content-box;
|
|
178
|
+
|
|
179
|
+
// `max-width: 100%` у обёртки считается по контенту, а паддинг (зона перетаскивания и отступ
|
|
180
|
+
// до края) лежит снаружи — вычитаем его, иначе панель упирается в край экрана.
|
|
181
|
+
max-width: calc(
|
|
182
|
+
100% - #{drawer.$sn-drawer-anatomy-container-vertical-positionLeft-paddingLeft} - #{drawer.$sn-drawer-anatomy-container-vertical-positionLeft-paddingRight}
|
|
183
|
+
);
|
|
178
184
|
height: 100%;
|
|
179
185
|
|
|
180
186
|
@each $width in $widthSizes {
|
|
@@ -206,6 +212,12 @@ $panelMotions: (
|
|
|
206
212
|
inset: auto 0 0;
|
|
207
213
|
}
|
|
208
214
|
|
|
215
|
+
&[data-resizing] {
|
|
216
|
+
* {
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
209
221
|
@each $placement, $offscreen in $panelMotions {
|
|
210
222
|
&.#{$panelMotionName}-#{$placement}-enter,
|
|
211
223
|
&.#{$panelMotionName}-#{$placement}-appear {
|
|
@@ -3,7 +3,7 @@ import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
|
3
3
|
import { DrawerProps as RcDrawerProps } from '@rc-component/drawer';
|
|
4
4
|
import { PropsWithChildren, ReactElement } from 'react';
|
|
5
5
|
|
|
6
|
-
import { Position, Width } from '../../types';
|
|
6
|
+
import { Position, ResizableMax, Width } from '../../types';
|
|
7
7
|
|
|
8
8
|
export type DrawerCustomProps = WithSupportProps<
|
|
9
9
|
PropsWithChildren<{
|
|
@@ -60,8 +60,11 @@ export type DrawerCustomProps = WithSupportProps<
|
|
|
60
60
|
resizable?: {
|
|
61
61
|
/** Минимальная доступная ширина */
|
|
62
62
|
min: number;
|
|
63
|
-
/**
|
|
64
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Максимальная доступная ширина: число в px либо `'full'` — вся ширина окна за вычетом 48px
|
|
65
|
+
* (двойной отступ обёртки).
|
|
66
|
+
*/
|
|
67
|
+
max?: ResizableMax;
|
|
65
68
|
/** Ширина по умолчанию */
|
|
66
69
|
default?: number;
|
|
67
70
|
/** Колбэк на изменение размера */
|
package/src/constants.ts
CHANGED
|
@@ -29,3 +29,9 @@ export const POSITION = {
|
|
|
29
29
|
Top: 'top',
|
|
30
30
|
Bottom: 'bottom',
|
|
31
31
|
} as const;
|
|
32
|
+
|
|
33
|
+
/** Значение `resizable.max`: растягивать до ширины окна за вычетом двойного отступа обёртки. */
|
|
34
|
+
export const RESIZABLE_MAX_FULL = 'full';
|
|
35
|
+
|
|
36
|
+
/** Горизонтальный отступ `content-wrapper`. */
|
|
37
|
+
export const FULL_WIDTH_OFFSET = 24;
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ValueOf } from '@cloud-ru/ds-utils';
|
|
2
2
|
|
|
3
|
-
import { POSITION, WIDTH } from './constants';
|
|
3
|
+
import { POSITION, RESIZABLE_MAX_FULL, WIDTH } from './constants';
|
|
4
4
|
|
|
5
5
|
export type Width = ValueOf<typeof WIDTH>;
|
|
6
6
|
export type Position = ValueOf<typeof POSITION>;
|
|
7
|
+
export type ResizableMax = number | typeof RESIZABLE_MAX_FULL;
|