@snack-uikit/drawer 0.4.6-preview-85c5f47b.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 +256 -0
- package/LICENSE +201 -0
- package/README.md +81 -0
- package/dist/components/Drawer/Drawer.d.ts +28 -0
- package/dist/components/Drawer/Drawer.js +25 -0
- package/dist/components/Drawer/index.d.ts +1 -0
- package/dist/components/Drawer/index.js +1 -0
- package/dist/components/Drawer/styles.module.css +3 -0
- package/dist/components/DrawerCustom/DrawerCustom.d.ts +44 -0
- package/dist/components/DrawerCustom/DrawerCustom.js +34 -0
- package/dist/components/DrawerCustom/constants.d.ts +5 -0
- package/dist/components/DrawerCustom/constants.js +13 -0
- package/dist/components/DrawerCustom/index.d.ts +1 -0
- package/dist/components/DrawerCustom/index.js +1 -0
- package/dist/components/DrawerCustom/motion.css +63 -0
- package/dist/components/DrawerCustom/styles.module.css +53 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.js +32 -0
- package/dist/helperComponents/Body/Body.d.ts +10 -0
- package/dist/helperComponents/Body/Body.js +21 -0
- package/dist/helperComponents/Body/index.d.ts +1 -0
- package/dist/helperComponents/Body/index.js +1 -0
- package/dist/helperComponents/Body/styles.module.css +8 -0
- package/dist/helperComponents/ButtonClose/ButtonClose.d.ts +5 -0
- package/dist/helperComponents/ButtonClose/ButtonClose.js +7 -0
- package/dist/helperComponents/ButtonClose/index.d.ts +1 -0
- package/dist/helperComponents/ButtonClose/index.js +1 -0
- package/dist/helperComponents/ButtonClose/styles.module.css +35 -0
- package/dist/helperComponents/Footer/Footer.d.ts +10 -0
- package/dist/helperComponents/Footer/Footer.js +21 -0
- package/dist/helperComponents/Footer/index.d.ts +1 -0
- package/dist/helperComponents/Footer/index.js +1 -0
- package/dist/helperComponents/Footer/styles.module.css +17 -0
- package/dist/helperComponents/Header/Header.d.ts +20 -0
- package/dist/helperComponents/Header/Header.js +23 -0
- package/dist/helperComponents/Header/index.d.ts +1 -0
- package/dist/helperComponents/Header/index.js +1 -0
- package/dist/helperComponents/Header/styles.module.css +35 -0
- package/dist/helperComponents/index.d.ts +4 -0
- package/dist/helperComponents/index.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +46 -0
- package/src/components/Drawer/Drawer.tsx +95 -0
- package/src/components/Drawer/index.ts +1 -0
- package/src/components/Drawer/styles.module.scss +3 -0
- package/src/components/DrawerCustom/DrawerCustom.tsx +117 -0
- package/src/components/DrawerCustom/constants.ts +18 -0
- package/src/components/DrawerCustom/index.ts +1 -0
- package/src/components/DrawerCustom/motion.css +63 -0
- package/src/components/DrawerCustom/styles.module.scss +64 -0
- package/src/components/index.ts +2 -0
- package/src/constants.ts +34 -0
- package/src/helperComponents/Body/Body.tsx +23 -0
- package/src/helperComponents/Body/index.ts +1 -0
- package/src/helperComponents/Body/styles.module.scss +10 -0
- package/src/helperComponents/ButtonClose/ButtonClose.tsx +21 -0
- package/src/helperComponents/ButtonClose/index.ts +1 -0
- package/src/helperComponents/ButtonClose/styles.module.scss +44 -0
- package/src/helperComponents/Footer/Footer.tsx +25 -0
- package/src/helperComponents/Footer/index.ts +1 -0
- package/src/helperComponents/Footer/styles.module.scss +17 -0
- package/src/helperComponents/Header/Header.tsx +64 -0
- package/src/helperComponents/Header/index.ts +1 -0
- package/src/helperComponents/Header/styles.module.scss +36 -0
- package/src/helperComponents/index.ts +4 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ButtonFilled,
|
|
5
|
+
ButtonFilledProps,
|
|
6
|
+
ButtonOutline,
|
|
7
|
+
ButtonOutlineProps,
|
|
8
|
+
ButtonSimple,
|
|
9
|
+
ButtonSimpleProps,
|
|
10
|
+
} from '@snack-uikit/button';
|
|
11
|
+
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
12
|
+
|
|
13
|
+
import { Mode, NESTED_DRAWER_PUSH_DISTANCE, Position, Size, TEST_IDS } from '../../constants';
|
|
14
|
+
import { DrawerBodyProps, DrawerHeaderProps } from '../../helperComponents';
|
|
15
|
+
import { DrawerCustom, DrawerCustomProps } from '../DrawerCustom';
|
|
16
|
+
|
|
17
|
+
export type DrawerProps = Omit<DrawerCustomProps, 'size' | 'children' | 'nestedDrawer' | 'push'> &
|
|
18
|
+
Pick<DrawerHeaderProps, 'titleTooltip' | 'image'> &
|
|
19
|
+
Pick<DrawerBodyProps, 'content'> & {
|
|
20
|
+
/** Заголовок */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Подзаголовок */
|
|
23
|
+
subtitle?: string;
|
|
24
|
+
/** Размер */
|
|
25
|
+
size?: Size;
|
|
26
|
+
/** Основная кнопка */
|
|
27
|
+
approveButton?: Omit<ButtonFilledProps, 'size' | 'data-test-id'>;
|
|
28
|
+
/** Кнопка отмены */
|
|
29
|
+
cancelButton?: Omit<ButtonOutlineProps, 'size' | 'data-test-id'>;
|
|
30
|
+
/** Дополнительная кнопка */
|
|
31
|
+
additionalButton?: Omit<ButtonSimpleProps, 'size' | 'data-test-id'>;
|
|
32
|
+
/** Вложенный Drawer */
|
|
33
|
+
nestedDrawer?: ReactElement<DrawerProps>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Готовый компонент Drawer */
|
|
37
|
+
export function Drawer({
|
|
38
|
+
title,
|
|
39
|
+
titleTooltip,
|
|
40
|
+
subtitle,
|
|
41
|
+
image,
|
|
42
|
+
content,
|
|
43
|
+
approveButton,
|
|
44
|
+
cancelButton,
|
|
45
|
+
additionalButton,
|
|
46
|
+
nestedDrawer,
|
|
47
|
+
...rest
|
|
48
|
+
}: DrawerProps) {
|
|
49
|
+
const needFooter = Boolean(approveButton) || Boolean(cancelButton) || Boolean(additionalButton);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<DrawerCustom {...rest} push={Boolean(nestedDrawer) && { distance: NESTED_DRAWER_PUSH_DISTANCE }}>
|
|
53
|
+
<DrawerCustom.Header
|
|
54
|
+
title={<TruncateString text={title} />}
|
|
55
|
+
titleTooltip={titleTooltip}
|
|
56
|
+
subtitle={subtitle}
|
|
57
|
+
image={image}
|
|
58
|
+
data-test-id={TEST_IDS.header}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<DrawerCustom.Body content={content} data-test-id={TEST_IDS.content} />
|
|
62
|
+
|
|
63
|
+
{needFooter && (
|
|
64
|
+
<DrawerCustom.Footer
|
|
65
|
+
data-test-id={TEST_IDS.footer}
|
|
66
|
+
actions={
|
|
67
|
+
<>
|
|
68
|
+
{approveButton && (
|
|
69
|
+
<ButtonFilled {...approveButton} size={ButtonFilled.sizes.M} data-test-id={TEST_IDS.approveButton} />
|
|
70
|
+
)}
|
|
71
|
+
|
|
72
|
+
{cancelButton && (
|
|
73
|
+
<ButtonOutline {...cancelButton} size={ButtonOutline.sizes.M} data-test-id={TEST_IDS.cancelButton} />
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
{additionalButton && (
|
|
77
|
+
<ButtonSimple
|
|
78
|
+
{...additionalButton}
|
|
79
|
+
size={ButtonSimple.sizes.M}
|
|
80
|
+
data-test-id={TEST_IDS.additionalButton}
|
|
81
|
+
/>
|
|
82
|
+
)}
|
|
83
|
+
</>
|
|
84
|
+
}
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
{nestedDrawer}
|
|
89
|
+
</DrawerCustom>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Drawer.modes = Mode;
|
|
94
|
+
Drawer.sizes = Size;
|
|
95
|
+
Drawer.positions = Position;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Drawer';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import 'rc-drawer/assets/index.css';
|
|
2
|
+
|
|
3
|
+
import cn from 'classnames';
|
|
4
|
+
import RcDrawer, { DrawerProps as RcDrawerProps } from 'rc-drawer';
|
|
5
|
+
import { PropsWithChildren, ReactElement } from 'react';
|
|
6
|
+
|
|
7
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
8
|
+
|
|
9
|
+
import { Mode, Position, Size, SIZE_AS_VALUES } from '../../constants';
|
|
10
|
+
import {
|
|
11
|
+
ButtonClose,
|
|
12
|
+
DrawerBody,
|
|
13
|
+
DrawerBodyProps,
|
|
14
|
+
DrawerFooter,
|
|
15
|
+
DrawerFooterProps,
|
|
16
|
+
DrawerHeader,
|
|
17
|
+
DrawerHeaderProps,
|
|
18
|
+
} from '../../helperComponents';
|
|
19
|
+
import { motionProps } from './constants';
|
|
20
|
+
import styles from './styles.module.scss';
|
|
21
|
+
|
|
22
|
+
export type DrawerCustomProps = WithSupportProps<
|
|
23
|
+
PropsWithChildren<{
|
|
24
|
+
/** Управление состоянием показан/не показан. */
|
|
25
|
+
open: boolean;
|
|
26
|
+
/** Колбэк закрытия */
|
|
27
|
+
onClose(): void;
|
|
28
|
+
/** Режим отображения */
|
|
29
|
+
mode?: Mode;
|
|
30
|
+
/** Расположение открытого Drawer */
|
|
31
|
+
position?: Position;
|
|
32
|
+
/** CSS-класс для элемента с контентом */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** CSS-класс для корневого элемента */
|
|
35
|
+
rootClassName?: string;
|
|
36
|
+
/** Размер */
|
|
37
|
+
size?: Size | string | number;
|
|
38
|
+
/** Смещение при открытии "вложенного" компонента */
|
|
39
|
+
push?: RcDrawerProps['push'];
|
|
40
|
+
/** Контейнер в котором будет рендерится Drawer. По-умолчанию - body */
|
|
41
|
+
container?: string | HTMLElement;
|
|
42
|
+
/** Вложенный Drawer */
|
|
43
|
+
nestedDrawer?: ReactElement<DrawerCustomProps>;
|
|
44
|
+
}>
|
|
45
|
+
>;
|
|
46
|
+
|
|
47
|
+
function DrawerCustomComponent({
|
|
48
|
+
open,
|
|
49
|
+
mode = Mode.Regular,
|
|
50
|
+
position = Position.Right,
|
|
51
|
+
onClose,
|
|
52
|
+
rootClassName,
|
|
53
|
+
className,
|
|
54
|
+
size = Size.S,
|
|
55
|
+
push,
|
|
56
|
+
container,
|
|
57
|
+
children,
|
|
58
|
+
nestedDrawer,
|
|
59
|
+
...rest
|
|
60
|
+
}: DrawerCustomProps) {
|
|
61
|
+
const isRegular = mode === Mode.Regular;
|
|
62
|
+
const isPredefinedSize = typeof size === 'string' && SIZE_AS_VALUES.includes(size);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<RcDrawer
|
|
66
|
+
mask={isRegular}
|
|
67
|
+
maskClosable={isRegular}
|
|
68
|
+
maskClassName={styles.mask}
|
|
69
|
+
keyboard={isRegular}
|
|
70
|
+
width={isPredefinedSize ? 'null' : size}
|
|
71
|
+
open={open}
|
|
72
|
+
placement={position}
|
|
73
|
+
destroyOnClose={true}
|
|
74
|
+
push={push}
|
|
75
|
+
onClose={onClose}
|
|
76
|
+
getContainer={container}
|
|
77
|
+
className={cn(styles.drawer, className)}
|
|
78
|
+
rootClassName={cn(styles.drawerRoot, rootClassName)}
|
|
79
|
+
{...extractSupportProps(rest)}
|
|
80
|
+
data-content-wrapper={true}
|
|
81
|
+
data-size={isPredefinedSize ? size : undefined}
|
|
82
|
+
data-mode={mode}
|
|
83
|
+
{...motionProps}
|
|
84
|
+
>
|
|
85
|
+
<div className={styles.headerElements}>
|
|
86
|
+
<ButtonClose onClick={onClose} />
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{children}
|
|
90
|
+
|
|
91
|
+
{nestedDrawer}
|
|
92
|
+
</RcDrawer>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Компонент-конструктор */
|
|
97
|
+
export const DrawerCustom = DrawerCustomComponent as typeof DrawerCustomComponent & {
|
|
98
|
+
modes: typeof Mode;
|
|
99
|
+
positions: typeof Position;
|
|
100
|
+
sizes: typeof Size;
|
|
101
|
+
Header: typeof DrawerHeader;
|
|
102
|
+
Body: typeof DrawerBody;
|
|
103
|
+
Footer: typeof DrawerFooter;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
DrawerCustom.modes = Mode;
|
|
107
|
+
DrawerCustom.positions = Position;
|
|
108
|
+
DrawerCustom.sizes = Size;
|
|
109
|
+
DrawerCustom.Header = DrawerHeader;
|
|
110
|
+
DrawerCustom.Body = DrawerBody;
|
|
111
|
+
DrawerCustom.Footer = DrawerFooter;
|
|
112
|
+
|
|
113
|
+
export namespace DrawerCustom {
|
|
114
|
+
export type HeaderProps = DrawerHeaderProps;
|
|
115
|
+
export type BodyProps = DrawerBodyProps;
|
|
116
|
+
export type FooterProps = DrawerFooterProps;
|
|
117
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import './motion.css';
|
|
2
|
+
|
|
3
|
+
import type { DrawerProps } from 'rc-drawer';
|
|
4
|
+
|
|
5
|
+
export const maskMotion: DrawerProps['maskMotion'] = {
|
|
6
|
+
motionAppear: true,
|
|
7
|
+
motionName: 'maskMotion',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const motion: DrawerProps['motion'] = placement => ({
|
|
11
|
+
motionAppear: true,
|
|
12
|
+
motionName: `panelMotion-${placement}`,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const motionProps: Partial<DrawerProps> = {
|
|
16
|
+
maskMotion,
|
|
17
|
+
motion,
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DrawerCustom';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
.maskMotion {
|
|
2
|
+
opacity: unset;
|
|
3
|
+
}
|
|
4
|
+
.maskMotion-enter, .maskMotion-appear {
|
|
5
|
+
opacity: 0;
|
|
6
|
+
}
|
|
7
|
+
.maskMotion-enter-active, .maskMotion-appear-active {
|
|
8
|
+
opacity: 1;
|
|
9
|
+
transition: opacity 0.2s;
|
|
10
|
+
}
|
|
11
|
+
.maskMotion-leave {
|
|
12
|
+
opacity: 1;
|
|
13
|
+
}
|
|
14
|
+
.maskMotion-leave-active {
|
|
15
|
+
opacity: 0;
|
|
16
|
+
transition: opacity 0.1s;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.panelMotion {
|
|
20
|
+
transform: unset;
|
|
21
|
+
}
|
|
22
|
+
.panelMotion-left-enter-start, .panelMotion-left-appear-start, .panelMotion-left-leave-start {
|
|
23
|
+
transition: none !important;
|
|
24
|
+
}
|
|
25
|
+
.panelMotion-left-enter-active, .panelMotion-left-appear-active {
|
|
26
|
+
transition: transform 0.2s ease-in-out;
|
|
27
|
+
}
|
|
28
|
+
.panelMotion-left-leave-active {
|
|
29
|
+
transition: transform 0.1s ease-out;
|
|
30
|
+
}
|
|
31
|
+
.panelMotion-left-enter, .panelMotion-left-appear {
|
|
32
|
+
transform: translateX(-100%);
|
|
33
|
+
}
|
|
34
|
+
.panelMotion-left-enter-active, .panelMotion-left-appear-active {
|
|
35
|
+
transform: translateX(0);
|
|
36
|
+
}
|
|
37
|
+
.panelMotion-left-leave {
|
|
38
|
+
transform: translateX(0);
|
|
39
|
+
}
|
|
40
|
+
.panelMotion-left-leave-active {
|
|
41
|
+
transform: translateX(-100%) !important;
|
|
42
|
+
}
|
|
43
|
+
.panelMotion-right-enter-start, .panelMotion-right-appear-start, .panelMotion-right-leave-start {
|
|
44
|
+
transition: none !important;
|
|
45
|
+
}
|
|
46
|
+
.panelMotion-right-enter-active, .panelMotion-right-appear-active {
|
|
47
|
+
transition: transform 0.2s ease-in-out;
|
|
48
|
+
}
|
|
49
|
+
.panelMotion-right-leave-active {
|
|
50
|
+
transition: transform 0.1s ease-out;
|
|
51
|
+
}
|
|
52
|
+
.panelMotion-right-enter, .panelMotion-right-appear {
|
|
53
|
+
transform: translateX(100%);
|
|
54
|
+
}
|
|
55
|
+
.panelMotion-right-enter-active, .panelMotion-right-appear-active {
|
|
56
|
+
transform: translateX(0);
|
|
57
|
+
}
|
|
58
|
+
.panelMotion-right-leave {
|
|
59
|
+
transform: translateX(0);
|
|
60
|
+
}
|
|
61
|
+
.panelMotion-right-leave-active {
|
|
62
|
+
transform: translateX(100%) !important;
|
|
63
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-drawer';
|
|
2
|
+
|
|
3
|
+
$sizes: ('s', 'm', 'l');
|
|
4
|
+
$modes: ('regular', 'soft');
|
|
5
|
+
$drawer-background-color: (
|
|
6
|
+
'regular': $sys-neutral-background1-level,
|
|
7
|
+
'soft': $sys-neutral-background2-level,
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
.drawerRoot {
|
|
11
|
+
z-index: auto !important; /* stylelint-disable-line declaration-no-important */
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
div[data-content-wrapper='true'] {
|
|
15
|
+
will-change: transform;
|
|
16
|
+
|
|
17
|
+
z-index: auto;
|
|
18
|
+
|
|
19
|
+
overflow: unset;
|
|
20
|
+
|
|
21
|
+
max-width: calc(100% - $space-drawer-outside-gap);
|
|
22
|
+
height: 100%;
|
|
23
|
+
|
|
24
|
+
@each $size in $sizes {
|
|
25
|
+
&[data-size='#{$size}'] {
|
|
26
|
+
@include composite-var($drawer, 'window', $size);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@each $mode in $modes {
|
|
31
|
+
&[data-mode='#{$mode}'] {
|
|
32
|
+
.drawer {
|
|
33
|
+
background-color: simple-var($drawer-background-color, $mode);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.drawer {
|
|
40
|
+
overflow: unset;
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
|
|
46
|
+
box-shadow: simple-var($box-shadow-elevation-level5);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.headerElements {
|
|
50
|
+
@include composite-var($drawer-header-elements-container);
|
|
51
|
+
@include composite-var($drawer-header-elements-elements-layout);
|
|
52
|
+
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
right: 0;
|
|
56
|
+
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.mask {
|
|
62
|
+
z-index: auto !important; /* stylelint-disable-line declaration-no-important */
|
|
63
|
+
background-color: simple-var($sys-blackout);
|
|
64
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export enum Size {
|
|
2
|
+
S = 's',
|
|
3
|
+
M = 'm',
|
|
4
|
+
L = 'l',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const SIZE_AS_VALUES: string[] = Object.values(Size);
|
|
8
|
+
|
|
9
|
+
export enum Mode {
|
|
10
|
+
Regular = 'regular',
|
|
11
|
+
Soft = 'soft',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export enum Position {
|
|
15
|
+
Right = 'right',
|
|
16
|
+
Left = 'left',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const NESTED_DRAWER_PUSH_DISTANCE = 24;
|
|
20
|
+
|
|
21
|
+
export const TEST_IDS = {
|
|
22
|
+
closeButton: 'drawer__close-button',
|
|
23
|
+
header: 'drawer__header',
|
|
24
|
+
title: 'drawer__title',
|
|
25
|
+
tooltip: 'drawer__title-tooltip',
|
|
26
|
+
subtitle: 'drawer__subtitle',
|
|
27
|
+
image: 'drawer__image',
|
|
28
|
+
content: 'drawer__body',
|
|
29
|
+
footer: 'drawer__footer',
|
|
30
|
+
footerActions: 'drawer__footer-actions',
|
|
31
|
+
approveButton: 'drawer__approve-button',
|
|
32
|
+
cancelButton: 'drawer__cancel-button',
|
|
33
|
+
additionalButton: 'drawer__additional-button',
|
|
34
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { Scroll } from '@snack-uikit/scroll';
|
|
5
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
6
|
+
|
|
7
|
+
import styles from './styles.module.scss';
|
|
8
|
+
|
|
9
|
+
export type DrawerBodyProps = WithSupportProps<{
|
|
10
|
+
/** Контент */
|
|
11
|
+
content: ReactNode;
|
|
12
|
+
/** CSS-класс */
|
|
13
|
+
className?: string;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
/** Вспомогательный компонент для добавления "тела" в DrawerCustom */
|
|
17
|
+
export function DrawerBody({ content, className, ...rest }: DrawerBodyProps) {
|
|
18
|
+
return (
|
|
19
|
+
<Scroll size={Scroll.sizes.M} className={cn(styles.drawerBody, className)} {...extractSupportProps(rest)}>
|
|
20
|
+
{content}
|
|
21
|
+
</Scroll>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Body';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CrossSVG } from '@snack-uikit/icons';
|
|
2
|
+
|
|
3
|
+
import { TEST_IDS } from '../../constants';
|
|
4
|
+
import styles from './styles.module.scss';
|
|
5
|
+
|
|
6
|
+
type ButtonCloseProps = {
|
|
7
|
+
onClick(): void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function ButtonClose({ onClick }: ButtonCloseProps) {
|
|
11
|
+
return (
|
|
12
|
+
<button
|
|
13
|
+
className={styles.buttonClose}
|
|
14
|
+
onClick={onClick}
|
|
15
|
+
aria-label='close drawer'
|
|
16
|
+
data-test-id={TEST_IDS.closeButton}
|
|
17
|
+
>
|
|
18
|
+
<CrossSVG />
|
|
19
|
+
</button>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ButtonClose';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-drawer';
|
|
2
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
|
|
3
|
+
|
|
4
|
+
.buttonClose {
|
|
5
|
+
@include composite-var($drawer-button-close);
|
|
6
|
+
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
|
|
17
|
+
color: simple-var($sys-neutral-text-support);
|
|
18
|
+
|
|
19
|
+
background-color: simple-var($sys-neutral-decor-default);
|
|
20
|
+
border: 0 solid transparent;
|
|
21
|
+
outline: 0;
|
|
22
|
+
outline-offset: $spacing-state-focus-offset;
|
|
23
|
+
|
|
24
|
+
&:hover, &:focus-visible {
|
|
25
|
+
color: simple-var($sys-neutral-text-main);
|
|
26
|
+
background-color: simple-var($sys-neutral-decor-hovered);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:focus-visible {
|
|
30
|
+
@include outline-var($container-focused-s);
|
|
31
|
+
|
|
32
|
+
outline-color: $sys-available-complementary;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:active {
|
|
36
|
+
color: simple-var($sys-neutral-text-main);
|
|
37
|
+
background-color: simple-var($sys-neutral-decor-activated);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
svg {
|
|
41
|
+
width: $icon-s !important; /* stylelint-disable-line declaration-no-important */
|
|
42
|
+
height: $icon-s !important; /* stylelint-disable-line declaration-no-important */
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
5
|
+
|
|
6
|
+
import { TEST_IDS } from '../../constants';
|
|
7
|
+
import styles from './styles.module.scss';
|
|
8
|
+
|
|
9
|
+
export type DrawerFooterProps = WithSupportProps<{
|
|
10
|
+
/** Слот для добавления кнопок-действий */
|
|
11
|
+
actions: ReactNode;
|
|
12
|
+
/** CSS-класс */
|
|
13
|
+
className?: string;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
/** Вспомогательный компонент для добавления "футера" в DrawerCustom */
|
|
17
|
+
export function DrawerFooter({ actions, className, ...rest }: DrawerFooterProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div className={cn(styles.footer, className)} {...extractSupportProps(rest)}>
|
|
20
|
+
<div className={styles.footerActions} data-test-id={TEST_IDS.footerActions}>
|
|
21
|
+
{actions}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Footer';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-drawer';
|
|
2
|
+
|
|
3
|
+
.footer {
|
|
4
|
+
@include composite-var($drawer-footer);
|
|
5
|
+
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.footerActions {
|
|
11
|
+
@include composite-var($drawer-action-row);
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: row-reverse;
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
align-items: center;
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { QuestionTooltip, TooltipProps } from '@snack-uikit/tooltip';
|
|
5
|
+
import { Typography } from '@snack-uikit/typography';
|
|
6
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
7
|
+
|
|
8
|
+
import { TEST_IDS } from '../../constants';
|
|
9
|
+
import styles from './styles.module.scss';
|
|
10
|
+
|
|
11
|
+
export type DrawerHeaderProps = WithSupportProps<{
|
|
12
|
+
/** Изображение */
|
|
13
|
+
image?: {
|
|
14
|
+
src: string;
|
|
15
|
+
alt: string;
|
|
16
|
+
};
|
|
17
|
+
/** Заголовок */
|
|
18
|
+
title: ReactNode;
|
|
19
|
+
/** Тултип для заголовка */
|
|
20
|
+
titleTooltip?: TooltipProps['tip'];
|
|
21
|
+
/** Подзаголовок */
|
|
22
|
+
subtitle?: ReactNode;
|
|
23
|
+
/** CSS-класс */
|
|
24
|
+
className?: string;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
/** Вспомогательный компонент для добавления "шапки" в DrawerCustom */
|
|
28
|
+
export function DrawerHeader({ title, titleTooltip, subtitle, image, className, ...rest }: DrawerHeaderProps) {
|
|
29
|
+
return (
|
|
30
|
+
<div className={cn(styles.drawerHeader, className)} {...extractSupportProps(rest)}>
|
|
31
|
+
{image && <img src={image.src} alt={image.alt} className={styles.image} data-test-id={TEST_IDS.image} />}
|
|
32
|
+
|
|
33
|
+
<div className={styles.headlineLayout}>
|
|
34
|
+
<div className={styles.headline}>
|
|
35
|
+
<Typography
|
|
36
|
+
family={Typography.families.Sans}
|
|
37
|
+
role={Typography.roles.Headline}
|
|
38
|
+
size={Typography.sizes.S}
|
|
39
|
+
className={styles.title}
|
|
40
|
+
data-test-id={TEST_IDS.title}
|
|
41
|
+
>
|
|
42
|
+
{title}
|
|
43
|
+
</Typography>
|
|
44
|
+
|
|
45
|
+
{titleTooltip && (
|
|
46
|
+
<QuestionTooltip tip={titleTooltip} size={QuestionTooltip.sizes.S} data-test-id={TEST_IDS.tooltip} />
|
|
47
|
+
)}
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{subtitle && (
|
|
51
|
+
<Typography
|
|
52
|
+
family={Typography.families.Sans}
|
|
53
|
+
role={Typography.roles.Body}
|
|
54
|
+
size={Typography.sizes.M}
|
|
55
|
+
className={styles.subtitle}
|
|
56
|
+
data-test-id={TEST_IDS.subtitle}
|
|
57
|
+
>
|
|
58
|
+
{subtitle}
|
|
59
|
+
</Typography>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Header';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-drawer';
|
|
2
|
+
|
|
3
|
+
.drawerHeader {
|
|
4
|
+
/* stub for proper typings */
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.image {
|
|
8
|
+
@include composite-var($drawer-image);
|
|
9
|
+
|
|
10
|
+
display: block;
|
|
11
|
+
width: 100%;
|
|
12
|
+
object-fit: cover;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.headlineLayout {
|
|
16
|
+
@include composite-var($drawer-headline-layout);
|
|
17
|
+
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.headline {
|
|
23
|
+
@include composite-var($drawer-headline);
|
|
24
|
+
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.title {
|
|
30
|
+
display: grid;
|
|
31
|
+
color: $sys-neutral-text-main;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.subtitle {
|
|
35
|
+
color: $sys-neutral-text-support;
|
|
36
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components';
|