@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +6 -0
  3. package/dist/cjs/components/Drawer/styles.module.css +0 -16
  4. package/dist/cjs/components/Drawer/types.d.ts +7 -3
  5. package/dist/cjs/components/DrawerCustom/DrawerCustom.d.ts +3 -3
  6. package/dist/cjs/components/DrawerCustom/DrawerCustom.js +1 -1
  7. package/dist/cjs/components/DrawerCustom/constants.js +2 -6
  8. package/dist/cjs/components/DrawerCustom/hooks/useDrawerResize.js +1 -5
  9. package/dist/cjs/components/DrawerCustom/styles.module.css +117 -123
  10. package/dist/cjs/constants.d.ts +1 -1
  11. package/dist/cjs/constants.js +1 -1
  12. package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
  13. package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
  14. package/dist/cjs/helperComponents/DialogSlots.d.ts +25 -4
  15. package/dist/cjs/helperComponents/DialogSlots.js +32 -3
  16. package/dist/cjs/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
  17. package/dist/cjs/helperComponents/DrawerBody/DrawerBody.js +3 -2
  18. package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
  19. package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
  20. package/dist/cjs/helperComponents/styles.module.css +15 -0
  21. package/dist/cjs/style.css +132 -139
  22. package/dist/esm/components/Drawer/styles.module.css +0 -16
  23. package/dist/esm/components/Drawer/types.d.ts +7 -3
  24. package/dist/esm/components/DrawerCustom/DrawerCustom.d.ts +3 -3
  25. package/dist/esm/components/DrawerCustom/DrawerCustom.js +1 -1
  26. package/dist/esm/components/DrawerCustom/constants.js +2 -3
  27. package/dist/esm/components/DrawerCustom/hooks/useDrawerResize.js +1 -2
  28. package/dist/esm/components/DrawerCustom/styles.module.css +117 -123
  29. package/dist/esm/constants.d.ts +1 -1
  30. package/dist/esm/constants.js +1 -1
  31. package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
  32. package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
  33. package/dist/esm/helperComponents/DialogSlots.d.ts +25 -4
  34. package/dist/esm/helperComponents/DialogSlots.js +29 -4
  35. package/dist/esm/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
  36. package/dist/esm/helperComponents/DrawerBody/DrawerBody.js +4 -3
  37. package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
  38. package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
  39. package/dist/esm/helperComponents/styles.module.css +15 -0
  40. package/dist/esm/style.css +132 -139
  41. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  42. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  43. package/package.json +9 -9
  44. package/src/components/Drawer/styles.module.scss +0 -19
  45. package/src/components/Drawer/types.ts +7 -3
  46. package/src/components/DrawerCustom/DrawerCustom.tsx +1 -1
  47. package/src/components/DrawerCustom/constants.ts +2 -4
  48. package/src/components/DrawerCustom/hooks/useDrawerResize.tsx +1 -2
  49. package/src/components/DrawerCustom/styles.module.scss +42 -60
  50. package/src/constants.ts +1 -1
  51. package/src/helperComponents/DesktopDrawer/DesktopDrawer.tsx +18 -27
  52. package/src/helperComponents/DialogSlots.tsx +74 -3
  53. package/src/helperComponents/DrawerBody/DrawerBody.tsx +5 -2
  54. package/src/helperComponents/MobileDrawer/MobileDrawer.tsx +5 -2
  55. package/src/helperComponents/styles.module.scss +22 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 1.1.0 (2026-09-01)
7
+
8
+ ### Features
9
+
10
+ - **FF-8873:** align drawer slots with window master and forward second title, content ref and dividers ([2c7dadf](https://github.com/cloud-ru-tech/snack-v2/commit/2c7dadfdb29988c1fa1dc42b4c22bea2419d6e67))
11
+ - **FF-8873:** render popup second-title slot on window surface and add body innerRef ([60771ea](https://github.com/cloud-ru-tech/snack-v2/commit/60771ea6d3ba7fa12deae4a19aba922846383835))
12
+
6
13
  ## 1.0.6 (2026-08-28)
7
14
 
8
15
  **Note:** Version bump only for package @ds/drawer
package/README.md CHANGED
@@ -248,6 +248,7 @@ export function NestedDrawer() {
248
248
  | `closeOnPopstate` | `boolean` | — | Закрывать дровер при перемещении по истории браузера |
249
249
  | `container` | `string \| HTMLElement` | — | Контейнер в котором будет рендерится Drawer. По-умолчанию - body |
250
250
  | `content` | `ReactNode` | — | Содержимое body (альтернатива `children`). |
251
+ | `contentRef` | `Ref<HTMLElement>` | — | Ссылка на скроллируемый контейнер контента (например, для дозагрузки по скроллу). |
251
252
  | `data-test-id` | `string` | — | |
252
253
  | `disableMotions` | `boolean` | `false` | Отключить анимации |
253
254
  | `footer` | `(ReactElement<any, string \| JSXElementConstructor<any>> & (string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<...> \| ReactPortal \| null))` | — | Футер <br/> Произвольный футер. Приоритетнее `approveButton` / `cancelButton` / `additionalButton`. |
@@ -265,12 +266,14 @@ export function NestedDrawer() {
265
266
  | `showBlackout` | `boolean` | `true` | Отображение темной подложки |
266
267
  | `showButtonClosed` | `boolean` | `true` | Отображение кнопки закрытия в шапке дровера |
267
268
  | `slotAfterTitle` | `ReactNode` | — | Slot справа от title (например, `QuestionTooltip` из `@cloud-ru/ds-tooltip`). |
269
+ | `slotSecondTitle` | `ReactNode` | — | Slot под подзаголовком — типично `SearchBar`, `SegmentControl` или `Filter`. <br/> Рендерится на обеих поверхностях: `secondWrapper` в мастере `bottomSheet`, <br/> `subHeadlineWrapper` в мастере `window` (modal / drawer). |
268
270
  | `snapIndex` | `number` | — | Controlled-индекс активного snap'а. Если задан, sheet всегда находится на этом snap'е; <br/> swipe-up/down вызывают `onSnapIndexChange`, но не меняют позицию сами — consumer должен <br/> передать новое значение. |
269
271
  | `snapPoints` | `SnapPoint` | — | Массив фиксированных позиций sheet'а от меньшей к большей. По дефолту `undefined` — <br/> sheet `height: auto` с одним snap'ом по высоте контента. <br/> Пример: `[0.5, 1]` — sheet открывается на половину экрана, drag вверх раскрывает <br/> до full-viewport; drag вниз ниже `0.5` ведёт к закрытию. <br/> Контракт массива (движок не сортирует и не дедуплицирует — порядок и различимость на <br/> стороне потребителя): <br/> - строго по возрастанию: индекс `0` — самая компактная позиция, последний — top / expanded; <br/> - значения должны резолвиться в различные высоты (`['50%', 0.5]` на типичном вьюпорте дадут <br/> одну высоту → дубль-индекс будет недостижим свайпом); <br/> - `'fit-content'` имеет смысл только как ЕДИНСТВЕННЫЙ snap (без `snapPoints`); внутри массива <br/> фиксированных позиций его «контентная» высота не определена. |
270
272
  | `subtitle` | `ReactNode` | — | Текстовая строка-подзаголовок под title. |
271
273
  | `swipeEnabled` | `boolean` | `true` | Включает swipe-down для закрытия / swipe-up для раскрытия на следующий snap-point. <br/> При `swipeEnabled=false` snap-point по-прежнему можно переключить через controlled `snapIndex` prop'ом. |
272
274
  | `title` | `ReactNode` | — | Заголовок. Типографика зависит от поверхности: `title-l` на sheet, `headline-s` на window (modal/drawer). |
273
275
  | `width` | `Width` | `'s'` | Ширина (только при position: "left" \| "right") |
276
+ | `withDividers` | `boolean` | `false` | Только mobile: разделители между шапкой/контентом/футером sheet'а. |
274
277
 
275
278
  ##### Related types
276
279
 
@@ -286,6 +289,7 @@ export function NestedDrawer() {
286
289
  | `closeOnPopstate` | `boolean \| undefined` | — | Закрывать дровер при перемещении по истории браузера |
287
290
  | `container` | `string \| HTMLElement \| undefined` | — | Контейнер в котором будет рендерится Drawer. По-умолчанию - body |
288
291
  | `content` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Содержимое body (альтернатива `children`). |
292
+ | `contentRef` | `Ref<HTMLElement> \| undefined` | — | Ссылка на скроллируемый контейнер контента (например, для дозагрузки по скроллу). |
289
293
  | `data-test-id` | `string \| undefined` | — | |
290
294
  | `disableMotions` | `boolean \| undefined` | — | Отключить анимации |
291
295
  | `footer` | `(ReactElement<any, string \| JSXElementConstructor<any>> & (string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null)) \| undefined` | — | Футер <br/> Произвольный футер. Приоритетнее `approveButton` / `cancelButton` / `additionalButton`. |
@@ -303,12 +307,14 @@ export function NestedDrawer() {
303
307
  | `showBlackout` | `boolean \| undefined` | — | Отображение темной подложки |
304
308
  | `showButtonClosed` | `boolean \| undefined` | — | Отображение кнопки закрытия в шапке дровера |
305
309
  | `slotAfterTitle` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Slot справа от title (например, `QuestionTooltip` из `@cloud-ru/ds-tooltip`). |
310
+ | `slotSecondTitle` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Slot под подзаголовком — типично `SearchBar`, `SegmentControl` или `Filter`. <br/> Рендерится на обеих поверхностях: `secondWrapper` в мастере `bottomSheet`, <br/> `subHeadlineWrapper` в мастере `window` (modal / drawer). |
306
311
  | `snapIndex` | `number \| undefined` | — | Controlled-индекс активного snap'а. Если задан, sheet всегда находится на этом snap'е; <br/> swipe-up/down вызывают `onSnapIndexChange`, но не меняют позицию сами — consumer должен <br/> передать новое значение. |
307
312
  | `snapPoints` | `SnapPoint` | — | Массив фиксированных позиций sheet'а от меньшей к большей. По дефолту `undefined` — <br/> sheet `height: auto` с одним snap'ом по высоте контента. <br/> Пример: `[0.5, 1]` — sheet открывается на половину экрана, drag вверх раскрывает <br/> до full-viewport; drag вниз ниже `0.5` ведёт к закрытию. <br/> Контракт массива (движок не сортирует и не дедуплицирует — порядок и различимость на <br/> стороне потребителя): <br/> - строго по возрастанию: индекс `0` — самая компактная позиция, последний — top / expanded; <br/> - значения должны резолвиться в различные высоты (`['50%', 0.5]` на типичном вьюпорте дадут <br/> одну высоту → дубль-индекс будет недостижим свайпом); <br/> - `'fit-content'` имеет смысл только как ЕДИНСТВЕННЫЙ snap (без `snapPoints`); внутри массива <br/> фиксированных позиций его «контентная» высота не определена. |
308
313
  | `subtitle` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Текстовая строка-подзаголовок под title. |
309
314
  | `swipeEnabled` | `boolean \| undefined` | — | Включает swipe-down для закрытия / swipe-up для раскрытия на следующий snap-point. <br/> При `swipeEnabled=false` snap-point по-прежнему можно переключить через controlled `snapIndex` prop'ом. |
310
315
  | `title` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Заголовок. Типографика зависит от поверхности: `title-l` на sheet, `headline-s` на window (modal/drawer). |
311
316
  | `width` | `Width` | — | Ширина (только при position: "left" \| "right") |
317
+ | `withDividers` | `boolean \| undefined` | — | Только mobile: разделители между шапкой/контентом/футером sheet'а. |
312
318
 
313
319
  - `Position` = `"bottom"` \| `"left"` \| `"right"` \| `"top"`
314
320
 
@@ -1,19 +1,3 @@
1
1
  .drawer{
2
2
  box-sizing:border-box;
3
- }
4
-
5
- .safeAreaTop{
6
- display:flex;
7
- flex-direction:column;
8
- align-items:flex-start;
9
- align-self:stretch;
10
- padding-top:var(--sn-drawer-anatomy-container-safeArea-paddingTop, var(--sn-density-spacing-interval-l, var(--sn-primitive-dimension-24, 24px)));
11
- }
12
-
13
- .safeAreaBottom{
14
- display:flex;
15
- flex-direction:column;
16
- align-items:flex-start;
17
- align-self:stretch;
18
- padding-bottom:var(--sn-drawer-anatomy-container-safeArea-paddingBottom, var(--sn-density-spacing-interval-s, var(--sn-primitive-dimension-8, 8px)));
19
3
  }
@@ -1,16 +1,20 @@
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
  import { DialogBodyProps, DialogHeaderProps } from '../../helperComponents';
5
5
  import { DrawerCustomProps } from '../DrawerCustom';
6
6
  /**
7
7
  * Адаптивный Drawer: desktop — боковая/верхняя/нижняя панель, `mobile` — `BottomSheet`.
8
8
  *
9
9
  * Только desktop: `position`, `width`, `heightAuto`, `nestedDrawer` (на mobile игнорируются).
10
- * Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`
10
+ * Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`, `withDividers`
11
11
  * (на desktop-панели игнорируются — это анатомия `BottomSheet`).
12
12
  */
13
- export type DrawerProps = WithSupportProps<Omit<DrawerCustomProps, 'nestedDrawer' | 'push' | 'resizable'> & Pick<BottomSheetProps, 'swipeEnabled' | 'snapPoints' | 'snapIndex' | 'onSnapIndexChange' | 'safeArea'> & Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'onBackButtonClick'> & Pick<DialogBodyProps, 'content'> & {
13
+ export type DrawerProps = WithSupportProps<Omit<DrawerCustomProps, 'nestedDrawer' | 'push' | 'resizable'> & Pick<BottomSheetProps, 'swipeEnabled' | 'snapPoints' | 'snapIndex' | 'onSnapIndexChange' | 'safeArea'> & Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'slotSecondTitle' | 'onBackButtonClick'> & Pick<DialogBodyProps, 'content'> & {
14
+ /** Ссылка на скроллируемый контейнер контента (например, для дозагрузки по скроллу). */
15
+ contentRef?: Ref<HTMLElement>;
16
+ /** Только mobile: разделители между шапкой/контентом/футером sheet'а. @default false */
17
+ withDividers?: boolean;
14
18
  /** Текстовая строка-подзаголовок под title. */
15
19
  subtitle?: ReactNode;
16
20
  /** CSS-класс */
@@ -1,4 +1,4 @@
1
- import { DialogBody, DialogBodyProps, DialogFooterProps, DialogHeaderProps } from '../../helperComponents';
1
+ import { DialogBody, DialogBodyProps, DialogFooter, DialogFooterProps, DialogHeader, DialogHeaderProps } from '../../helperComponents';
2
2
  import { DrawerCustomProps } from './types';
3
3
  /**
4
4
  * Адаптивный low-level `DrawerCustom`: на `mobile` — `BottomSheetCustom`, иначе — `DrawerFrame`.
@@ -9,7 +9,7 @@ export declare namespace DrawerCustom {
9
9
  type HeaderProps = DialogHeaderProps;
10
10
  type BodyProps = DialogBodyProps;
11
11
  type FooterProps = DialogFooterProps;
12
- const Header: typeof import("@cloud-ru/ds-bottom-sheet").SheetHeader;
12
+ const Header: typeof DialogHeader;
13
13
  const Body: typeof DialogBody;
14
- const Footer: typeof import("@cloud-ru/ds-bottom-sheet").SheetFooter;
14
+ const Footer: typeof DialogFooter;
15
15
  }
@@ -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-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: 'snack-rc-drawer', ...(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`.
@@ -1,18 +1,14 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.motionProps = exports.motion = exports.maskMotion = void 0;
7
- const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
8
4
  exports.maskMotion = {
9
5
  motionAppear: true,
10
- motionName: styles_module_scss_1.default.maskMotionName,
6
+ motionName: 'maskMotion',
11
7
  };
12
8
  const motion = placement => ({
13
9
  motionAppear: true,
14
10
  motionDeadline: 300,
15
- motionName: `${styles_module_scss_1.default.panelMotionName}-${placement}`,
11
+ motionName: `panelMotion-${placement}`,
16
12
  });
17
13
  exports.motion = motion;
18
14
  exports.motionProps = {
@@ -1,15 +1,11 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.useDrawerResize = useDrawerResize;
7
4
  const jsx_runtime_1 = require("react/jsx-runtime");
8
5
  const tooltip_1 = require("@cloud-ru/ds-tooltip");
9
6
  const utils_1 = require("@cloud-ru/ds-utils");
10
7
  const react_1 = require("react");
11
- const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
12
- const DRAGGER_SELECTOR = `.${styles_module_scss_1.default.prefixCls}-resizable-dragger`;
8
+ const DRAGGER_SELECTOR = '.snack-rc-drawer-resizable-dragger';
13
9
  function useDrawerResize({ position, resizable: resizableProp }) {
14
10
  const targetRef = (0, react_1.useRef)(null);
15
11
  const targetRefCallbackRef = (0, react_1.useRef)();