@cloud-ru/ds-drawer 1.0.6 → 1.0.7-preview-0a01eea8.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 (37) hide show
  1. package/README.md +6 -0
  2. package/dist/cjs/components/Drawer/styles.module.css +0 -16
  3. package/dist/cjs/components/Drawer/types.d.ts +7 -3
  4. package/dist/cjs/components/DrawerCustom/DrawerCustom.d.ts +3 -3
  5. package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
  6. package/dist/cjs/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
  7. package/dist/cjs/helperComponents/DialogSlots.d.ts +25 -4
  8. package/dist/cjs/helperComponents/DialogSlots.js +32 -3
  9. package/dist/cjs/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
  10. package/dist/cjs/helperComponents/DrawerBody/DrawerBody.js +3 -2
  11. package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
  12. package/dist/cjs/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
  13. package/dist/cjs/helperComponents/styles.module.css +15 -0
  14. package/dist/cjs/style.css +15 -16
  15. package/dist/esm/components/Drawer/styles.module.css +0 -16
  16. package/dist/esm/components/Drawer/types.d.ts +7 -3
  17. package/dist/esm/components/DrawerCustom/DrawerCustom.d.ts +3 -3
  18. package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.d.ts +1 -1
  19. package/dist/esm/helperComponents/DesktopDrawer/DesktopDrawer.js +8 -12
  20. package/dist/esm/helperComponents/DialogSlots.d.ts +25 -4
  21. package/dist/esm/helperComponents/DialogSlots.js +29 -4
  22. package/dist/esm/helperComponents/DrawerBody/DrawerBody.d.ts +1 -1
  23. package/dist/esm/helperComponents/DrawerBody/DrawerBody.js +4 -3
  24. package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.d.ts +1 -1
  25. package/dist/esm/helperComponents/MobileDrawer/MobileDrawer.js +4 -4
  26. package/dist/esm/helperComponents/styles.module.css +15 -0
  27. package/dist/esm/style.css +15 -16
  28. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  29. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  30. package/package.json +9 -9
  31. package/src/components/Drawer/styles.module.scss +0 -19
  32. package/src/components/Drawer/types.ts +7 -3
  33. package/src/helperComponents/DesktopDrawer/DesktopDrawer.tsx +18 -27
  34. package/src/helperComponents/DialogSlots.tsx +74 -3
  35. package/src/helperComponents/DrawerBody/DrawerBody.tsx +5 -2
  36. package/src/helperComponents/MobileDrawer/MobileDrawer.tsx +5 -2
  37. package/src/helperComponents/styles.module.scss +22 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-ru/ds-drawer",
3
- "version": "1.0.6",
3
+ "version": "1.0.7-preview-0a01eea8.0",
4
4
  "description": "Пакет выезжающих панелей — компоненты Drawer и DrawerCustom с едиными токенами позиции и ширины.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,13 +40,13 @@
40
40
  "classnames": "^2.5.1",
41
41
  "react-remove-scroll": "^2.7.2",
42
42
  "tabbable": "^6.5.0",
43
- "@cloud-ru/ds-adaptive": "^1.0.1",
44
- "@cloud-ru/ds-popup-private": "^1.0.4",
45
- "@cloud-ru/ds-portal-context": "^1.0.1",
46
- "@cloud-ru/ds-tooltip": "^1.0.4",
47
- "@cloud-ru/ds-scroll": "^1.0.2",
48
- "@cloud-ru/ds-materials": "^1.0.1",
49
- "@cloud-ru/ds-utils": "^1.1.0",
50
- "@cloud-ru/ds-bottom-sheet": "^1.0.5"
43
+ "@cloud-ru/ds-materials": "1.0.1",
44
+ "@cloud-ru/ds-adaptive": "1.0.1",
45
+ "@cloud-ru/ds-bottom-sheet": "1.0.6-preview-0a01eea8.0",
46
+ "@cloud-ru/ds-utils": "1.1.0",
47
+ "@cloud-ru/ds-tooltip": "1.0.4",
48
+ "@cloud-ru/ds-popup-private": "1.0.5-preview-0a01eea8.0",
49
+ "@cloud-ru/ds-portal-context": "1.0.1",
50
+ "@cloud-ru/ds-scroll": "1.0.2"
51
51
  }
52
52
  }
@@ -1,26 +1,7 @@
1
1
  @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
- @use '@cloud-ru/ds-figma-variables/build/scss/components/drawer.module' as drawer;
3
2
 
4
3
  .drawer {
5
4
  box-sizing: border-box;
6
5
  }
7
6
 
8
- .safeAreaTop {
9
- display: flex;
10
- flex-direction: column;
11
- align-items: flex-start;
12
- align-self: stretch;
13
-
14
- padding-top: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-top');
15
- }
16
-
17
- .safeAreaBottom {
18
- display: flex;
19
- flex-direction: column;
20
- align-items: flex-start;
21
- align-self: stretch;
22
-
23
- padding-bottom: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-bottom');
24
- }
25
-
26
7
  // Desktop-футер: ряд кнопок прижат вправо.
@@ -1,6 +1,6 @@
1
1
  import { BottomSheetActionButton, BottomSheetProps, FooterActionsOrientation } from '@cloud-ru/ds-bottom-sheet';
2
2
  import { WithSupportProps } from '@cloud-ru/ds-utils';
3
- import { ReactElement, ReactNode } from 'react';
3
+ import { ReactElement, ReactNode, Ref } from 'react';
4
4
 
5
5
  import { DialogBodyProps, DialogHeaderProps } from '../../helperComponents';
6
6
  import { DrawerCustomProps } from '../DrawerCustom';
@@ -9,14 +9,18 @@ import { DrawerCustomProps } from '../DrawerCustom';
9
9
  * Адаптивный Drawer: desktop — боковая/верхняя/нижняя панель, `mobile` — `BottomSheet`.
10
10
  *
11
11
  * Только desktop: `position`, `width`, `heightAuto`, `nestedDrawer` (на mobile игнорируются).
12
- * Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`
12
+ * Только mobile: `swipeEnabled`, `snapPoints`, `snapIndex`, `onSnapIndexChange`, `safeArea`, `withDividers`
13
13
  * (на desktop-панели игнорируются — это анатомия `BottomSheet`).
14
14
  */
15
15
  export type DrawerProps = WithSupportProps<
16
16
  Omit<DrawerCustomProps, 'nestedDrawer' | 'push' | 'resizable'> &
17
17
  Pick<BottomSheetProps, 'swipeEnabled' | 'snapPoints' | 'snapIndex' | 'onSnapIndexChange' | 'safeArea'> &
18
- Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'onBackButtonClick'> &
18
+ Pick<DialogHeaderProps, 'title' | 'slotAfterTitle' | 'slotSecondTitle' | 'onBackButtonClick'> &
19
19
  Pick<DialogBodyProps, 'content'> & {
20
+ /** Ссылка на скроллируемый контейнер контента (например, для дозагрузки по скроллу). */
21
+ contentRef?: Ref<HTMLElement>;
22
+ /** Только mobile: разделители между шапкой/контентом/футером sheet'а. @default false */
23
+ withDividers?: boolean;
20
24
  /** Текстовая строка-подзаголовок под title. */
21
25
  subtitle?: ReactNode;
22
26
  /** CSS-класс */
@@ -1,4 +1,3 @@
1
- import { FooterActions } from '@cloud-ru/ds-bottom-sheet';
2
1
  import cn from 'classnames';
3
2
 
4
3
  import { NESTED_DRAWER_PUSH_DISTANCE } from '../../components/Drawer/constants';
@@ -13,6 +12,7 @@ export function DesktopDrawer({
13
12
  media,
14
13
  title,
15
14
  slotAfterTitle,
15
+ slotSecondTitle,
16
16
  subtitle,
17
17
  onBackButtonClick,
18
18
  approveButton,
@@ -21,28 +21,14 @@ export function DesktopDrawer({
21
21
  footerActionsOrientation,
22
22
  footer,
23
23
  nestedDrawer,
24
+ contentRef,
25
+ // `withDividers` — mobile-only (мастер bottomSheet): молча уходит в `rest` и отбрасывается фреймом.
24
26
  className,
25
27
  ...rest
26
28
  }: DrawerProps) {
27
- const showHeader = Boolean(title || subtitle || slotAfterTitle);
28
- // Футер: произвольный `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);
29
+ const showHeader = Boolean(title || subtitle || slotAfterTitle || slotSecondTitle);
30
+ // Произвольный `footer` приоритетнее кнопок-слотов; раскладку слотов делает сам `DrawerCustom.Footer`.
31
+ const hasFooter = Boolean(footer || approveButton || cancelButton || additionalButton);
46
32
 
47
33
  return (
48
34
  <DrawerCustom
@@ -53,12 +39,11 @@ export function DesktopDrawer({
53
39
  >
54
40
  {media}
55
41
 
56
- <div className={styles.safeAreaTop} />
57
-
58
42
  {showHeader && (
59
43
  <DrawerCustom.Header
60
44
  title={title}
61
45
  slotAfterTitle={slotAfterTitle}
46
+ slotSecondTitle={slotSecondTitle}
62
47
  subtitle={subtitle}
63
48
  onBackButtonClick={onBackButtonClick}
64
49
  // Сохраняем публичный контракт test-id'ов drawer'а поверх общего `PopupHeader`.
@@ -71,12 +56,18 @@ export function DesktopDrawer({
71
56
  />
72
57
  )}
73
58
 
74
- <DrawerCustom.Body data-test-id={TEST_IDS.body} content={content} />
75
-
76
- <div className={styles.safeAreaBottom} />
59
+ <DrawerCustom.Body data-test-id={TEST_IDS.body} innerRef={contentRef} content={content} />
77
60
 
78
- {footerContent != null && (
79
- <DrawerCustom.Footer data-test-id={TEST_IDS.footer}>{footerContent}</DrawerCustom.Footer>
61
+ {hasFooter && (
62
+ <DrawerCustom.Footer
63
+ data-test-id={TEST_IDS.footer}
64
+ approveButton={footer ? undefined : approveButton}
65
+ cancelButton={footer ? undefined : cancelButton}
66
+ additionalButton={footer ? undefined : additionalButton}
67
+ footerActionsOrientation={footerActionsOrientation}
68
+ >
69
+ {footer}
70
+ </DrawerCustom.Footer>
80
71
  )}
81
72
 
82
73
  {nestedDrawer}
@@ -1,4 +1,7 @@
1
1
  import {
2
+ BottomSheetActionButton,
3
+ FooterActions,
4
+ FooterActionsOrientation,
2
5
  OVERLAY_SURFACE,
3
6
  SheetBody,
4
7
  SheetFooter,
@@ -8,17 +11,85 @@ import {
8
11
  useOverlaySurface,
9
12
  } from '@cloud-ru/ds-bottom-sheet';
10
13
 
14
+ import { TEST_IDS } from '../constants';
11
15
  import { DrawerBody, DrawerBodyProps } from './DrawerBody';
16
+ import styles from './styles.module.scss';
12
17
 
13
18
  // Header и Footer surface-aware реализует сам `PopupHeader`/`PopupFooter` (`SheetHeader`/`SheetFooter`):
14
19
  // он читает `OverlaySurfaceProvider` и рисует window-раскладку на drawer, bottomSheet — на sheet.
15
20
  // Свап остаётся только для Body (desktop-frame vs sheet).
16
21
  export type DialogHeaderProps = SheetHeaderProps;
17
22
  export type DialogBodyProps = DrawerBodyProps;
18
- export type DialogFooterProps = SheetFooterProps;
23
+ export type DialogFooterProps = SheetFooterProps & {
24
+ /** Основная кнопка. Задаёт штатную раскладку футера — вместо `children`. */
25
+ approveButton?: BottomSheetActionButton;
26
+ /** Кнопка отмены. */
27
+ cancelButton?: BottomSheetActionButton;
28
+ /** Дополнительная (третья) кнопка. */
29
+ additionalButton?: BottomSheetActionButton;
30
+ /** Ориентация кнопок при ровно двух действиях. */
31
+ footerActionsOrientation?: FooterActionsOrientation;
32
+ };
19
33
 
20
- export const DialogHeader = SheetHeader;
21
- export const DialogFooter = SheetFooter;
34
+ /**
35
+ * Шапка панели вместе с верхней safe-area.
36
+ *
37
+ * Отступ лежит здесь, а не во фрейме: иначе его теряет ручная композиция из
38
+ * `DrawerCustom.Header/Body/Footer`. На `sheet` не нужен — там свой `padding-top` в токенах.
39
+ */
40
+ export function DialogHeader(props: DialogHeaderProps) {
41
+ const isSheet = useOverlaySurface() === OVERLAY_SURFACE.Sheet;
42
+
43
+ return (
44
+ <>
45
+ {!isSheet && <div className={styles.safeAreaTop} />}
46
+ <SheetHeader {...props} />
47
+ </>
48
+ );
49
+ }
50
+
51
+ /**
52
+ * Футер панели вместе с зазором от `Body` (нижняя safe-area; на `sheet` его даёт сам мастер).
53
+ *
54
+ * Кнопки-слоты раскладывает `FooterActions`. `children` — для нестандартного содержимого:
55
+ * раскладку в этом случае обеспечивает потребитель.
56
+ */
57
+ export function DialogFooter({
58
+ approveButton,
59
+ cancelButton,
60
+ additionalButton,
61
+ footerActionsOrientation,
62
+ children,
63
+ ...rest
64
+ }: DialogFooterProps) {
65
+ const isSheet = useOverlaySurface() === OVERLAY_SURFACE.Sheet;
66
+ const hasActions = Boolean(approveButton || cancelButton || additionalButton);
67
+
68
+ return (
69
+ <>
70
+ {!isSheet && <div className={styles.safeAreaBottom} />}
71
+ <SheetFooter {...rest}>
72
+ {hasActions ? (
73
+ <FooterActions
74
+ surface={isSheet ? 'bottomSheet' : 'window'}
75
+ size='l'
76
+ approveButton={approveButton}
77
+ cancelButton={cancelButton}
78
+ additionalButton={additionalButton}
79
+ footerActionsOrientation={footerActionsOrientation}
80
+ testIds={{
81
+ approve: TEST_IDS.footerApprove,
82
+ cancel: TEST_IDS.footerCancel,
83
+ additional: TEST_IDS.footerAdditional,
84
+ }}
85
+ />
86
+ ) : (
87
+ children
88
+ )}
89
+ </SheetFooter>
90
+ </>
91
+ );
92
+ }
22
93
 
23
94
  export function DialogBody(props: DialogBodyProps) {
24
95
  return useOverlaySurface() === OVERLAY_SURFACE.Sheet ? <SheetBody {...props} /> : <DrawerBody {...props} />;
@@ -1,6 +1,6 @@
1
1
  import { SheetBodyProps, useOverlayBodyHeightAuto } from '@cloud-ru/ds-bottom-sheet';
2
2
  import { Scroll } from '@cloud-ru/ds-scroll';
3
- import { extractSupportProps } from '@cloud-ru/ds-utils';
3
+ import { extractSupportProps, withInnerRefSupport } from '@cloud-ru/ds-utils';
4
4
  import cn from 'classnames';
5
5
 
6
6
  import styles from './styles.module.scss';
@@ -8,11 +8,12 @@ import styles from './styles.module.scss';
8
8
  export type DrawerBodyProps = SheetBodyProps;
9
9
 
10
10
  /** Body дровера (desktop): `Scroll`; высота-по-контенту — из overlay-контекста. */
11
- export function DrawerBody({ content, children, bodyPadding = true, className, ...rest }: DrawerBodyProps) {
11
+ export function DrawerBody({ content, children, bodyPadding = true, innerRef, className, ...rest }: DrawerBodyProps) {
12
12
  const heightAutoVertical = useOverlayBodyHeightAuto();
13
13
 
14
14
  return (
15
15
  <Scroll
16
+ ref={innerRef}
16
17
  size='m'
17
18
  barHideStrategy='never'
18
19
  className={cn(styles.body, heightAutoVertical && styles.bodyHeightAuto, className)}
@@ -23,3 +24,5 @@ export function DrawerBody({ content, children, bodyPadding = true, className, .
23
24
  </Scroll>
24
25
  );
25
26
  }
27
+
28
+ withInnerRefSupport(DrawerBody);
@@ -14,6 +14,7 @@ export function MobileDrawer({
14
14
  media,
15
15
  title,
16
16
  slotAfterTitle,
17
+ slotSecondTitle,
17
18
  subtitle,
18
19
  onBackButtonClick,
19
20
  approveButton,
@@ -33,19 +34,21 @@ export function MobileDrawer({
33
34
  snapIndex,
34
35
  onSnapIndexChange,
35
36
  safeArea,
37
+ withDividers = false,
36
38
  ...rest
37
39
  }: DrawerProps) {
38
40
  // Футер собирает сам `BottomSheet`.
39
41
  return (
40
42
  <BottomSheet
41
- // Дефолт `withDividers` сменился на `true` — здесь вид сохраняем прежним.
42
- withDividers={false}
43
+ // Дефолт `withDividers` в sheet'е — `true`; у Drawer'а вид исторически без разделителей.
44
+ withDividers={withDividers}
43
45
  open={open}
44
46
  onClose={onClose}
45
47
  showBackdrop={showBlackout}
46
48
  title={title}
47
49
  subtitle={subtitle}
48
50
  slotAfterTitle={slotAfterTitle}
51
+ slotSecondTitle={slotSecondTitle}
49
52
  onBackButtonClick={onBackButtonClick}
50
53
  media={media}
51
54
  content={content}
@@ -0,0 +1,22 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/drawer.module' as drawer;
3
+
4
+ // Safe-area окна описана в слотах, а не во фрейме: иначе её теряет ручная композиция из
5
+ // `DrawerCustom.Header/Body/Footer`, и заголовок прилипает к верхней кромке панели.
6
+ .safeAreaTop {
7
+ display: flex;
8
+ flex-direction: column;
9
+ align-items: flex-start;
10
+ align-self: stretch;
11
+
12
+ padding-top: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-top');
13
+ }
14
+
15
+ .safeAreaBottom {
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: flex-start;
19
+ align-self: stretch;
20
+
21
+ padding-bottom: base.simple-var(drawer.$drawer, 'anatomy', 'container', 'safeArea', 'padding-bottom');
22
+ }