@cloud-ru/ds-drawer 2.0.1-preview-20b4671f.0 → 2.0.1-preview-a22f149a.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/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 +7 -7
- 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/README.md
CHANGED
|
@@ -448,7 +448,7 @@ export function CustomComposition() {
|
|
|
448
448
|
| `open` | `boolean` | — | Управление состоянием показан/не показан. |
|
|
449
449
|
| `position` | `"bottom"` \| `"left"` \| `"right"` \| `"top"` | — | Расположение |
|
|
450
450
|
| `push` | `boolean \| PushConfig` | — | Смещение при открытии "вложенного" компонента |
|
|
451
|
-
| `resizable` | `
|
|
451
|
+
| `resizable` | `ResizableMax` | `'s'` | Ширина (только при position: "left" \| "right") |
|
|
452
452
|
| `rootClassName` | `string` | — | CSS-класс для корневого элемента |
|
|
453
453
|
| `safeAreaBottom` | `boolean` | `true` | Нижний safe-area отступ под iOS home-indicator и Android nav-bar. Размер — токен <br/> `safeArea.bottom.minHeight`, на устройстве с большим `env(safe-area-inset-bottom)` — значение inset. |
|
|
454
454
|
| `safeAreaTop` | `boolean` | `true` | Верхний safe-area отступ под iOS notch / status-bar. Размер — токен `safeArea.top.minHeight`, <br/> на устройстве с большим `env(safe-area-inset-top)` — значение inset. Применяется, только когда <br/> sheet раскрыт на полный вьюпорт: у неполного sheet'а верх и так не заходит под notch. |
|
|
@@ -477,7 +477,7 @@ export function CustomComposition() {
|
|
|
477
477
|
| `open` | `boolean` | — | Управление состоянием показан/не показан. |
|
|
478
478
|
| `position` | `"bottom"` \| `"left"` \| `"right"` \| `"top"` | — | Расположение |
|
|
479
479
|
| `push` | `boolean \| PushConfig \| undefined` | — | Смещение при открытии "вложенного" компонента |
|
|
480
|
-
| `resizable` | `
|
|
480
|
+
| `resizable` | `ResizableMax` | — | Ширина (только при position: "left" \| "right") |
|
|
481
481
|
| `rootClassName` | `string \| undefined` | — | CSS-класс для корневого элемента |
|
|
482
482
|
| `safeAreaBottom` | `boolean \| undefined` | — | Нижний safe-area отступ под iOS home-indicator и Android nav-bar. Размер — токен <br/> `safeArea.bottom.minHeight`, на устройстве с большим `env(safe-area-inset-bottom)` — значение inset. |
|
|
483
483
|
| `safeAreaTop` | `boolean \| undefined` | — | Верхний safe-area отступ под iOS notch / status-bar. Размер — токен `safeArea.top.minHeight`, <br/> на устройстве с большим `env(safe-area-inset-top)` — значение inset. Применяется, только когда <br/> sheet раскрыт на полный вьюпорт: у неполного sheet'а верх и так не заходит под notch. |
|
|
@@ -489,4 +489,6 @@ export function CustomComposition() {
|
|
|
489
489
|
|
|
490
490
|
- `Position` = `"bottom"` \| `"left"` \| `"right"` \| `"top"`
|
|
491
491
|
|
|
492
|
+
- `ResizableMax` = `number | "full"`
|
|
493
|
+
|
|
492
494
|
- `Width` = `"l"` \| `"m"` \| `"s"`
|
|
@@ -27,7 +27,7 @@ function DrawerFrame(props) {
|
|
|
27
27
|
const { showBlackout = true, showButtonClosed = true, open, onClose, rootClassName, className, push, container, children, nestedDrawer, closeOnPopstate, position, heightAuto, width: widthProp, resizable: resizableProp, disableMotions = false, ...rest } = props;
|
|
28
28
|
const heightAutoVertical = Boolean(heightAuto && (position === 'top' || position === 'bottom'));
|
|
29
29
|
const resizable = heightAutoVertical ? undefined : resizableProp;
|
|
30
|
-
const { tooltip, checkElement, width: userWidth, resizable: drawerResizable, } = (0, useDrawerResize_1.useDrawerResize)({
|
|
30
|
+
const { tooltip, checkElement, width: userWidth, resizable: drawerResizable, isResizing, } = (0, useDrawerResize_1.useDrawerResize)({
|
|
31
31
|
resizable,
|
|
32
32
|
position,
|
|
33
33
|
});
|
|
@@ -59,7 +59,7 @@ function DrawerFrame(props) {
|
|
|
59
59
|
const resolvedContainer = container ?? (portalContextRef.current ? () => portalContextRef.current : undefined);
|
|
60
60
|
return ((0, jsx_runtime_1.jsx)(RcDrawer, { resizable: drawerResizable, panelRef: checkElement, mask: showBlackout, maskClosable: showBlackout, keyboard: showBlackout, "data-showblackout": showBlackout, open: open, onClose: onClose, push: push, getContainer: resolvedContainer, placement: position, destroyOnHidden: true, rootClassName: (0, classnames_1.default)(styles_module_scss_1.default.drawerRoot, rootClassName), style: drawerPanelStyle, classNames: {
|
|
61
61
|
section: (0, classnames_1.default)(styles_module_scss_1.default.drawer, className),
|
|
62
|
-
}, size: isPredefinedWidth ? 'null' : width, ...(0, utils_1.extractSupportProps)(rest), "data-content-wrapper": true, "data-position": position, "data-width": isPredefinedWidth ? width : undefined, "data-height-auto": heightAutoVertical ? true : undefined, "data-acrylic-appearance": 'neutral', "data-acrylic-level": '1Level', prefixCls: styles_module_scss_1.default.prefixCls, ...(disableMotions ? {} : constants_2.motionProps), children: (0, jsx_runtime_1.jsxs)(react_remove_scroll_1.RemoveScroll, { enabled: showBlackout || outerScrollLock, removeScrollBar: false, ref: focusTrapRef, className: styles_module_scss_1.default.scrollLock, children: [showButtonClosed && ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.showButtonClosedWrapper, children: (0, jsx_runtime_1.jsx)(popup_private_1.PopupCloseButton, { className: styles_module_scss_1.default.showButtonClosed, "aria-label": 'close drawer', "data-test-id": constants_1.TEST_IDS.closeButton, onClick: onClose }) })), (0, jsx_runtime_1.jsx)(bottom_sheet_1.OverlaySurfaceProvider, { surface: bottom_sheet_1.OVERLAY_SURFACE.Drawer, bodyHeightAuto: heightAutoVertical, children: children }), tooltip, nestedDrawer] }) }));
|
|
62
|
+
}, size: isPredefinedWidth ? 'null' : width, ...(0, utils_1.extractSupportProps)(rest), "data-resizing": isResizing || undefined, "data-content-wrapper": true, "data-position": position, "data-width": isPredefinedWidth ? width : undefined, "data-height-auto": heightAutoVertical ? true : undefined, "data-acrylic-appearance": 'neutral', "data-acrylic-level": '1Level', prefixCls: styles_module_scss_1.default.prefixCls, ...(disableMotions ? {} : constants_2.motionProps), children: (0, jsx_runtime_1.jsxs)(react_remove_scroll_1.RemoveScroll, { enabled: showBlackout || outerScrollLock, removeScrollBar: false, ref: focusTrapRef, className: styles_module_scss_1.default.scrollLock, children: [showButtonClosed && ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.showButtonClosedWrapper, children: (0, jsx_runtime_1.jsx)(popup_private_1.PopupCloseButton, { className: styles_module_scss_1.default.showButtonClosed, "aria-label": 'close drawer', "data-test-id": constants_1.TEST_IDS.closeButton, onClick: onClose }) })), (0, jsx_runtime_1.jsx)(bottom_sheet_1.OverlaySurfaceProvider, { surface: bottom_sheet_1.OVERLAY_SURFACE.Drawer, bodyHeightAuto: heightAutoVertical, children: children }), tooltip, nestedDrawer] }) }));
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Адаптивный low-level `DrawerCustom`: на `mobile` — `BottomSheetCustom`, иначе — `DrawerFrame`.
|
|
@@ -10,6 +10,8 @@ type UseDrawerResizeResult = {
|
|
|
10
10
|
resizable: DrawerProps['resizable'];
|
|
11
11
|
/** Ширина ползунка в пикселях */
|
|
12
12
|
width?: number;
|
|
13
|
+
/** Флаг, указывающий, что дровер в процессе ресайза */
|
|
14
|
+
isResizing: boolean;
|
|
13
15
|
};
|
|
14
16
|
export declare function useDrawerResize({ position, resizable: resizableProp }: UseDrawerResizeParams): UseDrawerResizeResult;
|
|
15
17
|
export {};
|
|
@@ -8,8 +8,10 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
8
8
|
const tooltip_1 = require("@cloud-ru/ds-tooltip");
|
|
9
9
|
const utils_1 = require("@cloud-ru/ds-utils");
|
|
10
10
|
const react_1 = require("react");
|
|
11
|
+
const constants_1 = require("../../../constants");
|
|
11
12
|
const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
|
|
12
13
|
const DRAGGER_SELECTOR = `.${styles_module_scss_1.default.prefixCls}-resizable-dragger`;
|
|
14
|
+
const getFullMaxWidth = () => ((0, utils_1.isBrowser)() ? Math.max(0, document.documentElement.clientWidth) : Infinity);
|
|
13
15
|
function useDrawerResize({ position, resizable: resizableProp }) {
|
|
14
16
|
const targetRef = (0, react_1.useRef)(null);
|
|
15
17
|
const targetRefCallbackRef = (0, react_1.useRef)();
|
|
@@ -30,25 +32,34 @@ function useDrawerResize({ position, resizable: resizableProp }) {
|
|
|
30
32
|
return null;
|
|
31
33
|
targetRef.current ? targetRefCallback(targetRef.current) : (targetRefCallbackRef.current = targetRefCallback);
|
|
32
34
|
} })) : null;
|
|
33
|
-
const
|
|
35
|
+
const { onResize, onResizeEnd, max, min } = resizableProp ?? {};
|
|
36
|
+
const resizeEnabled = Boolean(resizableProp);
|
|
37
|
+
// Сколько стартовой ширины, которую держит rc-drawer, не помещается в окно: оно могло сузиться, пока дровер
|
|
38
|
+
// был закрыт или открыт. CSS обрезает панель визуально, а rc-drawer считает ресайз от «виртуальной» ширины.
|
|
39
|
+
const excessRef = (0, react_1.useRef)(0);
|
|
40
|
+
const resizable = (0, react_1.useMemo)(() => resizeEnabled
|
|
34
41
|
? {
|
|
35
|
-
onResize:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
onResize: rawValue => {
|
|
43
|
+
// Смещение мыши rc-drawer прибавляет к устаревшей стартовой ширине: вычитаем лишнее.
|
|
44
|
+
const limit = max === constants_1.RESIZABLE_MAX_FULL ? getFullMaxWidth() : max;
|
|
45
|
+
const value = Math.min(rawValue - excessRef.current, limit ?? Infinity);
|
|
46
|
+
if (value < (min || 0))
|
|
39
47
|
return;
|
|
40
48
|
setWidth(value);
|
|
41
|
-
|
|
49
|
+
onResize?.(value);
|
|
42
50
|
},
|
|
43
51
|
onResizeEnd: () => {
|
|
44
52
|
setOpen(false);
|
|
45
53
|
setMuted(false);
|
|
46
|
-
|
|
54
|
+
onResizeEnd?.(width ?? 0);
|
|
47
55
|
},
|
|
48
|
-
|
|
56
|
+
// rc-drawer передаёт во время выполнения реальную стартовую ширину (в типах аргумента нет).
|
|
57
|
+
onResizeStart: (startSize) => {
|
|
58
|
+
excessRef.current =
|
|
59
|
+
max === constants_1.RESIZABLE_MAX_FULL && startSize !== undefined ? Math.max(0, startSize - getFullMaxWidth()) : 0;
|
|
49
60
|
setMuted(true);
|
|
50
61
|
},
|
|
51
62
|
}
|
|
52
|
-
: undefined, [
|
|
53
|
-
return { tooltip, checkElement, resizable, width };
|
|
63
|
+
: undefined, [width, max, min, onResize, onResizeEnd, resizeEnabled]);
|
|
64
|
+
return { tooltip, checkElement, resizable, width, isResizing: muted };
|
|
54
65
|
}
|
|
@@ -126,6 +126,7 @@
|
|
|
126
126
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right]{
|
|
127
127
|
align-items:stretch;
|
|
128
128
|
box-sizing:content-box;
|
|
129
|
+
max-width:calc(100% - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingLeft, var(--sn-primitive-dimension-0, 0px)) - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingRight, var(--sn-density-spacing-interval-l, var(--sn-platform-comfort-spacing-interval-l, var(--sn-primitive-dimension-32, 32px)))));
|
|
129
130
|
height:100%;
|
|
130
131
|
}
|
|
131
132
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left][data-width=s], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right][data-width=s]{
|
|
@@ -154,6 +155,9 @@
|
|
|
154
155
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=bottom][data-height-auto]{
|
|
155
156
|
inset:auto 0 0;
|
|
156
157
|
}
|
|
158
|
+
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-resizing] *{
|
|
159
|
+
pointer-events:none;
|
|
160
|
+
}
|
|
157
161
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-enter, .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-appear{
|
|
158
162
|
transform:translateX(-100%);
|
|
159
163
|
}
|
|
@@ -2,7 +2,7 @@ import { BottomSheetCustomProps } from '@cloud-ru/ds-bottom-sheet';
|
|
|
2
2
|
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
|
-
import { Position, Width } from '../../types';
|
|
5
|
+
import { Position, ResizableMax, Width } from '../../types';
|
|
6
6
|
export type DrawerCustomProps = WithSupportProps<PropsWithChildren<{
|
|
7
7
|
/** Управление состоянием показан/не показан. */
|
|
8
8
|
open: boolean;
|
|
@@ -57,8 +57,11 @@ export type DrawerCustomProps = WithSupportProps<PropsWithChildren<{
|
|
|
57
57
|
resizable?: {
|
|
58
58
|
/** Минимальная доступная ширина */
|
|
59
59
|
min: number;
|
|
60
|
-
/**
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Максимальная доступная ширина: число в px либо `'full'` — вся ширина окна за вычетом 48px
|
|
62
|
+
* (двойной отступ обёртки).
|
|
63
|
+
*/
|
|
64
|
+
max?: ResizableMax;
|
|
62
65
|
/** Ширина по умолчанию */
|
|
63
66
|
default?: number;
|
|
64
67
|
/** Колбэк на изменение размера */
|
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -26,3 +26,7 @@ export declare const POSITION: {
|
|
|
26
26
|
readonly Top: "top";
|
|
27
27
|
readonly Bottom: "bottom";
|
|
28
28
|
};
|
|
29
|
+
/** Значение `resizable.max`: растягивать до ширины окна за вычетом двойного отступа обёртки. */
|
|
30
|
+
export declare const RESIZABLE_MAX_FULL = "full";
|
|
31
|
+
/** Горизонтальный отступ `content-wrapper`. */
|
|
32
|
+
export declare const FULL_WIDTH_OFFSET = 24;
|
package/dist/cjs/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.POSITION = exports.WIDTH_AS_VALUES = exports.WIDTH = exports.TEST_IDS = void 0;
|
|
3
|
+
exports.FULL_WIDTH_OFFSET = exports.RESIZABLE_MAX_FULL = exports.POSITION = exports.WIDTH_AS_VALUES = exports.WIDTH = exports.TEST_IDS = void 0;
|
|
4
4
|
exports.TEST_IDS = {
|
|
5
5
|
closeButton: 'drawer__close-button',
|
|
6
6
|
header: 'drawer__header',
|
|
@@ -29,3 +29,7 @@ exports.POSITION = {
|
|
|
29
29
|
Top: 'top',
|
|
30
30
|
Bottom: 'bottom',
|
|
31
31
|
};
|
|
32
|
+
/** Значение `resizable.max`: растягивать до ширины окна за вычетом двойного отступа обёртки. */
|
|
33
|
+
exports.RESIZABLE_MAX_FULL = 'full';
|
|
34
|
+
/** Горизонтальный отступ `content-wrapper`. */
|
|
35
|
+
exports.FULL_WIDTH_OFFSET = 24;
|
package/dist/cjs/style.css
CHANGED
|
@@ -129,6 +129,7 @@
|
|
|
129
129
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right]{
|
|
130
130
|
align-items:stretch;
|
|
131
131
|
box-sizing:content-box;
|
|
132
|
+
max-width:calc(100% - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingLeft, var(--sn-primitive-dimension-0, 0px)) - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingRight, var(--sn-density-spacing-interval-l, var(--sn-platform-comfort-spacing-interval-l, var(--sn-primitive-dimension-32, 32px)))));
|
|
132
133
|
height:100%;
|
|
133
134
|
}
|
|
134
135
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left][data-width=s], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right][data-width=s]{
|
|
@@ -157,6 +158,9 @@
|
|
|
157
158
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=bottom][data-height-auto]{
|
|
158
159
|
inset:auto 0 0;
|
|
159
160
|
}
|
|
161
|
+
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-resizing] *{
|
|
162
|
+
pointer-events:none;
|
|
163
|
+
}
|
|
160
164
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-enter, .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-appear{
|
|
161
165
|
transform:translateX(-100%);
|
|
162
166
|
}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ValueOf } from '@cloud-ru/ds-utils';
|
|
2
|
-
import { POSITION, WIDTH } from './constants';
|
|
2
|
+
import { POSITION, RESIZABLE_MAX_FULL, WIDTH } from './constants';
|
|
3
3
|
export type Width = ValueOf<typeof WIDTH>;
|
|
4
4
|
export type Position = ValueOf<typeof POSITION>;
|
|
5
|
+
export type ResizableMax = number | typeof RESIZABLE_MAX_FULL;
|
|
@@ -21,7 +21,7 @@ function DrawerFrame(props) {
|
|
|
21
21
|
const { showBlackout = true, showButtonClosed = true, open, onClose, rootClassName, className, push, container, children, nestedDrawer, closeOnPopstate, position, heightAuto, width: widthProp, resizable: resizableProp, disableMotions = false, ...rest } = props;
|
|
22
22
|
const heightAutoVertical = Boolean(heightAuto && (position === 'top' || position === 'bottom'));
|
|
23
23
|
const resizable = heightAutoVertical ? undefined : resizableProp;
|
|
24
|
-
const { tooltip, checkElement, width: userWidth, resizable: drawerResizable, } = useDrawerResize({
|
|
24
|
+
const { tooltip, checkElement, width: userWidth, resizable: drawerResizable, isResizing, } = useDrawerResize({
|
|
25
25
|
resizable,
|
|
26
26
|
position,
|
|
27
27
|
});
|
|
@@ -53,7 +53,7 @@ function DrawerFrame(props) {
|
|
|
53
53
|
const resolvedContainer = container ?? (portalContextRef.current ? () => portalContextRef.current : undefined);
|
|
54
54
|
return (_jsx(RcDrawer, { resizable: drawerResizable, panelRef: checkElement, mask: showBlackout, maskClosable: showBlackout, keyboard: showBlackout, "data-showblackout": showBlackout, open: open, onClose: onClose, push: push, getContainer: resolvedContainer, placement: position, destroyOnHidden: true, rootClassName: cn(styles.drawerRoot, rootClassName), style: drawerPanelStyle, classNames: {
|
|
55
55
|
section: cn(styles.drawer, className),
|
|
56
|
-
}, size: isPredefinedWidth ? 'null' : width, ...extractSupportProps(rest), "data-content-wrapper": true, "data-position": position, "data-width": isPredefinedWidth ? width : undefined, "data-height-auto": heightAutoVertical ? true : undefined, "data-acrylic-appearance": 'neutral', "data-acrylic-level": '1Level', prefixCls: styles.prefixCls, ...(disableMotions ? {} : motionProps), children: _jsxs(RemoveScroll, { enabled: showBlackout || outerScrollLock, removeScrollBar: false, ref: focusTrapRef, className: styles.scrollLock, children: [showButtonClosed && (_jsx("div", { className: styles.showButtonClosedWrapper, children: _jsx(PopupCloseButton, { className: styles.showButtonClosed, "aria-label": 'close drawer', "data-test-id": TEST_IDS.closeButton, onClick: onClose }) })), _jsx(OverlaySurfaceProvider, { surface: OVERLAY_SURFACE.Drawer, bodyHeightAuto: heightAutoVertical, children: children }), tooltip, nestedDrawer] }) }));
|
|
56
|
+
}, size: isPredefinedWidth ? 'null' : width, ...extractSupportProps(rest), "data-resizing": isResizing || undefined, "data-content-wrapper": true, "data-position": position, "data-width": isPredefinedWidth ? width : undefined, "data-height-auto": heightAutoVertical ? true : undefined, "data-acrylic-appearance": 'neutral', "data-acrylic-level": '1Level', prefixCls: styles.prefixCls, ...(disableMotions ? {} : motionProps), children: _jsxs(RemoveScroll, { enabled: showBlackout || outerScrollLock, removeScrollBar: false, ref: focusTrapRef, className: styles.scrollLock, children: [showButtonClosed && (_jsx("div", { className: styles.showButtonClosedWrapper, children: _jsx(PopupCloseButton, { className: styles.showButtonClosed, "aria-label": 'close drawer', "data-test-id": TEST_IDS.closeButton, onClick: onClose }) })), _jsx(OverlaySurfaceProvider, { surface: OVERLAY_SURFACE.Drawer, bodyHeightAuto: heightAutoVertical, children: children }), tooltip, nestedDrawer] }) }));
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Адаптивный low-level `DrawerCustom`: на `mobile` — `BottomSheetCustom`, иначе — `DrawerFrame`.
|
|
@@ -10,6 +10,8 @@ type UseDrawerResizeResult = {
|
|
|
10
10
|
resizable: DrawerProps['resizable'];
|
|
11
11
|
/** Ширина ползунка в пикселях */
|
|
12
12
|
width?: number;
|
|
13
|
+
/** Флаг, указывающий, что дровер в процессе ресайза */
|
|
14
|
+
isResizing: boolean;
|
|
13
15
|
};
|
|
14
16
|
export declare function useDrawerResize({ position, resizable: resizableProp }: UseDrawerResizeParams): UseDrawerResizeResult;
|
|
15
17
|
export {};
|
|
@@ -2,8 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Tooltip } from '@cloud-ru/ds-tooltip';
|
|
3
3
|
import { isBrowser } from '@cloud-ru/ds-utils';
|
|
4
4
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import { RESIZABLE_MAX_FULL } from '../../../constants.js';
|
|
5
6
|
import styles from '../styles.module.css';
|
|
6
7
|
const DRAGGER_SELECTOR = `.${styles.prefixCls}-resizable-dragger`;
|
|
8
|
+
const getFullMaxWidth = () => (isBrowser() ? Math.max(0, document.documentElement.clientWidth) : Infinity);
|
|
7
9
|
export function useDrawerResize({ position, resizable: resizableProp }) {
|
|
8
10
|
const targetRef = useRef(null);
|
|
9
11
|
const targetRefCallbackRef = useRef();
|
|
@@ -24,25 +26,34 @@ export function useDrawerResize({ position, resizable: resizableProp }) {
|
|
|
24
26
|
return null;
|
|
25
27
|
targetRef.current ? targetRefCallback(targetRef.current) : (targetRefCallbackRef.current = targetRefCallback);
|
|
26
28
|
} })) : null;
|
|
27
|
-
const
|
|
29
|
+
const { onResize, onResizeEnd, max, min } = resizableProp ?? {};
|
|
30
|
+
const resizeEnabled = Boolean(resizableProp);
|
|
31
|
+
// Сколько стартовой ширины, которую держит rc-drawer, не помещается в окно: оно могло сузиться, пока дровер
|
|
32
|
+
// был закрыт или открыт. CSS обрезает панель визуально, а rc-drawer считает ресайз от «виртуальной» ширины.
|
|
33
|
+
const excessRef = useRef(0);
|
|
34
|
+
const resizable = useMemo(() => resizeEnabled
|
|
28
35
|
? {
|
|
29
|
-
onResize:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
onResize: rawValue => {
|
|
37
|
+
// Смещение мыши rc-drawer прибавляет к устаревшей стартовой ширине: вычитаем лишнее.
|
|
38
|
+
const limit = max === RESIZABLE_MAX_FULL ? getFullMaxWidth() : max;
|
|
39
|
+
const value = Math.min(rawValue - excessRef.current, limit ?? Infinity);
|
|
40
|
+
if (value < (min || 0))
|
|
33
41
|
return;
|
|
34
42
|
setWidth(value);
|
|
35
|
-
|
|
43
|
+
onResize?.(value);
|
|
36
44
|
},
|
|
37
45
|
onResizeEnd: () => {
|
|
38
46
|
setOpen(false);
|
|
39
47
|
setMuted(false);
|
|
40
|
-
|
|
48
|
+
onResizeEnd?.(width ?? 0);
|
|
41
49
|
},
|
|
42
|
-
|
|
50
|
+
// rc-drawer передаёт во время выполнения реальную стартовую ширину (в типах аргумента нет).
|
|
51
|
+
onResizeStart: (startSize) => {
|
|
52
|
+
excessRef.current =
|
|
53
|
+
max === RESIZABLE_MAX_FULL && startSize !== undefined ? Math.max(0, startSize - getFullMaxWidth()) : 0;
|
|
43
54
|
setMuted(true);
|
|
44
55
|
},
|
|
45
56
|
}
|
|
46
|
-
: undefined, [
|
|
47
|
-
return { tooltip, checkElement, resizable, width };
|
|
57
|
+
: undefined, [width, max, min, onResize, onResizeEnd, resizeEnabled]);
|
|
58
|
+
return { tooltip, checkElement, resizable, width, isResizing: muted };
|
|
48
59
|
}
|
|
@@ -126,6 +126,7 @@
|
|
|
126
126
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right]{
|
|
127
127
|
align-items:stretch;
|
|
128
128
|
box-sizing:content-box;
|
|
129
|
+
max-width:calc(100% - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingLeft, var(--sn-primitive-dimension-0, 0px)) - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingRight, var(--sn-density-spacing-interval-l, var(--sn-platform-comfort-spacing-interval-l, var(--sn-primitive-dimension-32, 32px)))));
|
|
129
130
|
height:100%;
|
|
130
131
|
}
|
|
131
132
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left][data-width=s], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right][data-width=s]{
|
|
@@ -154,6 +155,9 @@
|
|
|
154
155
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=bottom][data-height-auto]{
|
|
155
156
|
inset:auto 0 0;
|
|
156
157
|
}
|
|
158
|
+
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-resizing] *{
|
|
159
|
+
pointer-events:none;
|
|
160
|
+
}
|
|
157
161
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-enter, .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-appear{
|
|
158
162
|
transform:translateX(-100%);
|
|
159
163
|
}
|
|
@@ -2,7 +2,7 @@ import { BottomSheetCustomProps } from '@cloud-ru/ds-bottom-sheet';
|
|
|
2
2
|
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
|
-
import { Position, Width } from '../../types.js';
|
|
5
|
+
import { Position, ResizableMax, Width } from '../../types.js';
|
|
6
6
|
export type DrawerCustomProps = WithSupportProps<PropsWithChildren<{
|
|
7
7
|
/** Управление состоянием показан/не показан. */
|
|
8
8
|
open: boolean;
|
|
@@ -57,8 +57,11 @@ export type DrawerCustomProps = WithSupportProps<PropsWithChildren<{
|
|
|
57
57
|
resizable?: {
|
|
58
58
|
/** Минимальная доступная ширина */
|
|
59
59
|
min: number;
|
|
60
|
-
/**
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Максимальная доступная ширина: число в px либо `'full'` — вся ширина окна за вычетом 48px
|
|
62
|
+
* (двойной отступ обёртки).
|
|
63
|
+
*/
|
|
64
|
+
max?: ResizableMax;
|
|
62
65
|
/** Ширина по умолчанию */
|
|
63
66
|
default?: number;
|
|
64
67
|
/** Колбэк на изменение размера */
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -26,3 +26,7 @@ export declare const POSITION: {
|
|
|
26
26
|
readonly Top: "top";
|
|
27
27
|
readonly Bottom: "bottom";
|
|
28
28
|
};
|
|
29
|
+
/** Значение `resizable.max`: растягивать до ширины окна за вычетом двойного отступа обёртки. */
|
|
30
|
+
export declare const RESIZABLE_MAX_FULL = "full";
|
|
31
|
+
/** Горизонтальный отступ `content-wrapper`. */
|
|
32
|
+
export declare const FULL_WIDTH_OFFSET = 24;
|
package/dist/esm/constants.js
CHANGED
|
@@ -26,3 +26,7 @@ export const POSITION = {
|
|
|
26
26
|
Top: 'top',
|
|
27
27
|
Bottom: 'bottom',
|
|
28
28
|
};
|
|
29
|
+
/** Значение `resizable.max`: растягивать до ширины окна за вычетом двойного отступа обёртки. */
|
|
30
|
+
export const RESIZABLE_MAX_FULL = 'full';
|
|
31
|
+
/** Горизонтальный отступ `content-wrapper`. */
|
|
32
|
+
export const FULL_WIDTH_OFFSET = 24;
|
package/dist/esm/style.css
CHANGED
|
@@ -129,6 +129,7 @@
|
|
|
129
129
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right]{
|
|
130
130
|
align-items:stretch;
|
|
131
131
|
box-sizing:content-box;
|
|
132
|
+
max-width:calc(100% - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingLeft, var(--sn-primitive-dimension-0, 0px)) - var(--sn-drawer-anatomy-container-vertical-positionLeft-paddingRight, var(--sn-density-spacing-interval-l, var(--sn-platform-comfort-spacing-interval-l, var(--sn-primitive-dimension-32, 32px)))));
|
|
132
133
|
height:100%;
|
|
133
134
|
}
|
|
134
135
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=left][data-width=s], .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=right][data-width=s]{
|
|
@@ -157,6 +158,9 @@
|
|
|
157
158
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-position=bottom][data-height-auto]{
|
|
158
159
|
inset:auto 0 0;
|
|
159
160
|
}
|
|
161
|
+
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper[data-resizing] *{
|
|
162
|
+
pointer-events:none;
|
|
163
|
+
}
|
|
160
164
|
.drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-enter, .drawerRoot:global(.cloud-ru-ds-drawer-v1) :global .cloud-ru-ds-drawer-v1-content-wrapper.cloud-ru-ds-drawer-v1-panel-motion-left-appear{
|
|
161
165
|
transform:translateX(-100%);
|
|
162
166
|
}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ValueOf } from '@cloud-ru/ds-utils';
|
|
2
|
-
import { POSITION, WIDTH } from './constants.js';
|
|
2
|
+
import { POSITION, RESIZABLE_MAX_FULL, WIDTH } from './constants.js';
|
|
3
3
|
export type Width = ValueOf<typeof WIDTH>;
|
|
4
4
|
export type Position = ValueOf<typeof POSITION>;
|
|
5
|
+
export type ResizableMax = number | typeof RESIZABLE_MAX_FULL;
|