@snack-uikit/notification 0.13.25 → 0.13.26
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 +8 -0
- package/README.md +70 -0
- package/dist/cjs/components/NotificationCard/NotificationCard.d.ts +2 -7
- package/dist/cjs/components/NotificationCard/NotificationCard.js +11 -4
- package/dist/cjs/components/NotificationCard/components/index.d.ts +0 -1
- package/dist/cjs/components/NotificationCard/components/index.js +0 -1
- package/dist/cjs/components/NotificationCard/helpers.d.ts +2 -0
- package/dist/cjs/components/NotificationCard/helpers.js +4 -0
- package/dist/cjs/components/NotificationCard/styles.module.css +10 -9
- package/dist/cjs/components/NotificationPanel/NotificationPanel.d.ts +3 -1
- package/dist/cjs/components/NotificationPanel/NotificationPanel.js +14 -11
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.d.ts +27 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.js +101 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/hooks.d.ts +12 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/hooks.js +36 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/index.d.ts +1 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/index.js +25 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/styles.module.css +74 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/utils.d.ts +2 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/utils.js +14 -0
- package/dist/cjs/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.js +10 -3
- package/dist/cjs/components/NotificationPanel/components/NotificationPanelDivider/styles.module.css +12 -3
- package/dist/cjs/components/NotificationPanel/components/index.d.ts +1 -0
- package/dist/cjs/components/NotificationPanel/components/index.js +2 -1
- package/dist/cjs/components/NotificationPanel/constants.d.ts +6 -0
- package/dist/cjs/components/NotificationPanel/constants.js +7 -1
- package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/StackTail.d.ts +6 -0
- package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/StackTail.js +33 -0
- package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/index.d.ts +1 -0
- package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/index.js +25 -0
- package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/styles.module.css +53 -0
- package/dist/cjs/components/NotificationPanel/helperComponents/WithTooltip/WithTooltip.d.ts +1 -1
- package/dist/cjs/components/NotificationPanel/styles.module.css +7 -4
- package/dist/cjs/helperComponents/ActionsButton/ActionsButton.d.ts +16 -0
- package/dist/cjs/helperComponents/ActionsButton/ActionsButton.js +72 -0
- package/dist/cjs/helperComponents/ActionsButton/index.d.ts +1 -0
- package/dist/cjs/helperComponents/ActionsButton/index.js +25 -0
- package/dist/cjs/helperComponents/ActionsButton/styles.module.css +3 -0
- package/dist/esm/components/NotificationCard/NotificationCard.d.ts +2 -7
- package/dist/esm/components/NotificationCard/NotificationCard.js +6 -3
- package/dist/esm/components/NotificationCard/components/index.d.ts +0 -1
- package/dist/esm/components/NotificationCard/components/index.js +0 -1
- package/dist/esm/components/NotificationCard/helpers.d.ts +2 -0
- package/dist/esm/components/NotificationCard/helpers.js +3 -0
- package/dist/esm/components/NotificationCard/styles.module.css +10 -9
- package/dist/esm/components/NotificationPanel/NotificationPanel.d.ts +3 -1
- package/dist/esm/components/NotificationPanel/NotificationPanel.js +3 -2
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.d.ts +27 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.js +28 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/hooks.d.ts +12 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/hooks.js +26 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/index.d.ts +1 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/index.js +1 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/styles.module.css +74 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/utils.d.ts +2 -0
- package/dist/esm/components/NotificationPanel/components/NotificationCardStack/utils.js +7 -0
- package/dist/esm/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.js +2 -2
- package/dist/esm/components/NotificationPanel/components/NotificationPanelDivider/styles.module.css +12 -3
- package/dist/esm/components/NotificationPanel/components/index.d.ts +1 -0
- package/dist/esm/components/NotificationPanel/components/index.js +1 -0
- package/dist/esm/components/NotificationPanel/constants.d.ts +6 -0
- package/dist/esm/components/NotificationPanel/constants.js +6 -0
- package/dist/esm/components/NotificationPanel/helperComponents/StackTail/StackTail.d.ts +6 -0
- package/dist/esm/components/NotificationPanel/helperComponents/StackTail/StackTail.js +5 -0
- package/dist/esm/components/NotificationPanel/helperComponents/StackTail/index.d.ts +1 -0
- package/dist/esm/components/NotificationPanel/helperComponents/StackTail/index.js +1 -0
- package/dist/esm/components/NotificationPanel/helperComponents/StackTail/styles.module.css +53 -0
- package/dist/esm/components/NotificationPanel/helperComponents/WithTooltip/WithTooltip.d.ts +1 -1
- package/dist/esm/components/NotificationPanel/styles.module.css +7 -4
- package/dist/esm/helperComponents/ActionsButton/ActionsButton.d.ts +16 -0
- package/dist/esm/helperComponents/ActionsButton/ActionsButton.js +23 -0
- package/dist/esm/helperComponents/ActionsButton/index.d.ts +1 -0
- package/dist/esm/helperComponents/ActionsButton/index.js +1 -0
- package/dist/esm/helperComponents/ActionsButton/styles.module.css +3 -0
- package/package.json +4 -3
- package/src/components/NotificationCard/NotificationCard.tsx +14 -11
- package/src/components/NotificationCard/components/index.ts +0 -1
- package/src/components/NotificationCard/helpers.tsx +6 -0
- package/src/components/NotificationCard/styles.module.scss +3 -3
- package/src/components/NotificationPanel/NotificationPanel.tsx +16 -10
- package/src/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.tsx +107 -0
- package/src/components/NotificationPanel/components/NotificationCardStack/hooks.ts +45 -0
- package/src/components/NotificationPanel/components/NotificationCardStack/index.ts +1 -0
- package/src/components/NotificationPanel/components/NotificationCardStack/styles.module.scss +89 -0
- package/src/components/NotificationPanel/components/NotificationCardStack/utils.ts +12 -0
- package/src/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.tsx +5 -3
- package/src/components/NotificationPanel/components/NotificationPanelDivider/styles.module.scss +15 -7
- package/src/components/NotificationPanel/components/index.ts +1 -0
- package/src/components/NotificationPanel/constants.ts +6 -0
- package/src/components/NotificationPanel/helperComponents/StackTail/StackTail.tsx +17 -0
- package/src/components/NotificationPanel/helperComponents/StackTail/index.ts +1 -0
- package/src/components/NotificationPanel/helperComponents/StackTail/styles.module.scss +77 -0
- package/src/components/NotificationPanel/styles.module.scss +6 -6
- package/src/helperComponents/ActionsButton/ActionsButton.tsx +65 -0
- package/src/helperComponents/ActionsButton/index.ts +1 -0
- package/src/helperComponents/ActionsButton/styles.module.scss +3 -0
- package/dist/cjs/components/NotificationCard/components/NotificationCardFunction.d.ts +0 -7
- package/dist/cjs/components/NotificationCard/components/NotificationCardFunction.js +0 -64
- package/dist/esm/components/NotificationCard/components/NotificationCardFunction.d.ts +0 -7
- package/dist/esm/components/NotificationCard/components/NotificationCardFunction.js +0 -20
- package/src/components/NotificationCard/components/NotificationCardFunction.tsx +0 -43
package/dist/esm/components/NotificationPanel/components/NotificationCardStack/styles.module.css
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
.container{
|
|
2
|
+
gap:var(--space-notification-panel-card-stack-container, 4px);
|
|
3
|
+
display:flex;
|
|
4
|
+
flex-direction:column;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header{
|
|
8
|
+
gap:var(--space-notification-panel-card-stack-header-gap, 4px);
|
|
9
|
+
padding-bottom:var(--space-notification-panel-card-stack-header-padding-bottom, 4px);
|
|
10
|
+
display:flex;
|
|
11
|
+
flex-direction:row;
|
|
12
|
+
align-items:center;
|
|
13
|
+
color:var(var(--sys-neutral-text-main, #41424e));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.title{
|
|
17
|
+
font-family:var(--sans-title-s-font-family, SB Sans Interface);
|
|
18
|
+
font-weight:var(--sans-title-s-font-weight, Semibold);
|
|
19
|
+
line-height:var(--sans-title-s-line-height, 20px);
|
|
20
|
+
font-size:var(--sans-title-s-font-size, 14px);
|
|
21
|
+
letter-spacing:var(--sans-title-s-letter-spacing, 0.15px);
|
|
22
|
+
paragraph-spacing:var(--sans-title-s-paragraph-spacing, 7.7px);
|
|
23
|
+
overflow:hidden;
|
|
24
|
+
flex-grow:1;
|
|
25
|
+
flex-shrink:1;
|
|
26
|
+
text-overflow:ellipsis;
|
|
27
|
+
white-space:nowrap;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.right{
|
|
31
|
+
gap:var(--space-notification-panel-card-stack-header-gap, 4px);
|
|
32
|
+
display:flex;
|
|
33
|
+
flex-direction:row;
|
|
34
|
+
flex-grow:0;
|
|
35
|
+
flex-shrink:0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.first{
|
|
39
|
+
display:flex;
|
|
40
|
+
flex-direction:column-reverse;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.stack{
|
|
44
|
+
position:relative;
|
|
45
|
+
overflow:visible;
|
|
46
|
+
height:auto;
|
|
47
|
+
transition:overflow var(--snack-notification-stack-animation-duration) allow-discrete step-end;
|
|
48
|
+
}
|
|
49
|
+
.stack:not([data-open]){
|
|
50
|
+
overflow:hidden;
|
|
51
|
+
transition:height var(--snack-notification-stack-animation-duration) allow-discrete step-end;
|
|
52
|
+
}
|
|
53
|
+
.stack:not([data-open])[data-tail-size]{
|
|
54
|
+
height:8px;
|
|
55
|
+
}
|
|
56
|
+
.stack:not([data-open])[data-tail-size="1"]{
|
|
57
|
+
height:4px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.animationContainer{
|
|
61
|
+
translate:0 -100%;
|
|
62
|
+
scale:0.98;
|
|
63
|
+
display:flex;
|
|
64
|
+
flex-direction:column;
|
|
65
|
+
gap:var(--space-notification-panel-container-body-stack-cards, 4px);
|
|
66
|
+
margin-top:var(--space-notification-panel-container-body-stack-cards, 4px);
|
|
67
|
+
opacity:0;
|
|
68
|
+
transition:scale var(--snack-notification-stack-animation-duration), translate var(--snack-notification-stack-animation-duration), opacity var(--snack-notification-stack-animation-duration);
|
|
69
|
+
}
|
|
70
|
+
[data-open] .animationContainer{
|
|
71
|
+
translate:0 0;
|
|
72
|
+
scale:1;
|
|
73
|
+
opacity:1;
|
|
74
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export declare const cloneCard: (element: ReactNode, props: Record<string, unknown>) => string | number | boolean | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined;
|
|
@@ -9,7 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import cn from 'classnames';
|
|
14
14
|
import { Typography } from '@snack-uikit/typography';
|
|
15
15
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
@@ -17,5 +17,5 @@ import styles from './styles.module.css';
|
|
|
17
17
|
/** Разделитель для группировки или разделения карточек в списке */
|
|
18
18
|
export function NotificationPanelDivider(_a) {
|
|
19
19
|
var { text, className } = _a, rest = __rest(_a, ["text", "className"]);
|
|
20
|
-
return (
|
|
20
|
+
return (_jsxs("div", Object.assign({ className: cn(styles.container, className) }, extractSupportProps(rest), { children: [_jsx("div", { className: styles.line }), _jsx(Typography.LightLabelS, { className: styles.text, children: text }), _jsx("div", { className: styles.line })] })));
|
|
21
21
|
}
|
package/dist/esm/components/NotificationPanel/components/NotificationPanelDivider/styles.module.css
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
.
|
|
2
|
-
height:var(--size-notification-panel-readed-divider, 32px);
|
|
3
|
-
border-bottom-width:var(--border-width-notification-panel-container, 1px);
|
|
1
|
+
.container{
|
|
4
2
|
display:flex;
|
|
3
|
+
gap:var(--space-notification-panel-divider-gap, 8px);
|
|
5
4
|
align-items:center;
|
|
6
5
|
justify-content:center;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.text{
|
|
9
|
+
flex-grow:0;
|
|
10
|
+
flex-shrink:0;
|
|
7
11
|
color:var(--sys-neutral-text-light, #8b8e9b);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.line{
|
|
15
|
+
flex-grow:1;
|
|
16
|
+
flex-shrink:1;
|
|
8
17
|
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
9
18
|
border-bottom-color:var(--sys-neutral-decor-default, #dde0ea);
|
|
10
19
|
border-bottom-style:solid;
|
|
@@ -9,4 +9,10 @@ export const TEST_IDS = {
|
|
|
9
9
|
readAll: 'notification-panel__readAll',
|
|
10
10
|
footerButton: 'notification-panel__footerButton',
|
|
11
11
|
skeleton: 'notification-panel__skeleton',
|
|
12
|
+
cardStack: {
|
|
13
|
+
headline: 'notification-panel__card-stack__headline',
|
|
14
|
+
wrapper: 'notification-panel__card-stack__wrapper',
|
|
15
|
+
title: 'notification-panel__card-stack__title',
|
|
16
|
+
openButton: 'notification-panel__card-stack__open-button',
|
|
17
|
+
},
|
|
12
18
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import styles from './styles.module.css';
|
|
3
|
+
export function StackTail({ open, count }) {
|
|
4
|
+
return (_jsx("div", { className: styles.container, "data-open": open || undefined, children: _jsxs("div", { className: styles.animationContainer, children: [count > 1 && _jsx("div", { className: styles.card, "data-level": '3' }), _jsx("div", { className: styles.card, "data-level": '2' })] }) }));
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StackTail';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StackTail';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.container{
|
|
2
|
+
position:relative;
|
|
3
|
+
height:0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.animationContainer{
|
|
7
|
+
position:absolute;
|
|
8
|
+
top:0;
|
|
9
|
+
bottom:calc(-1 * var(--space-notification-panel-card-stack-stack3-level-horizontal-padding, 8px));
|
|
10
|
+
overflow:hidden;
|
|
11
|
+
width:100%;
|
|
12
|
+
transition:bottom calc(var(--snack-notification-stack-animation-duration) / 2) calc(var(--snack-notification-stack-animation-duration) / 2 / 1.7) ease-out;
|
|
13
|
+
}
|
|
14
|
+
[data-open] .animationContainer{
|
|
15
|
+
bottom:-416px;
|
|
16
|
+
transition:bottom calc(var(--snack-notification-stack-animation-duration) / 2) ease-out;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.card{
|
|
20
|
+
position:absolute;
|
|
21
|
+
overflow:hidden;
|
|
22
|
+
height:200px;
|
|
23
|
+
background-color:var(--sys-neutral-background2-level, #ffffff);
|
|
24
|
+
border:var(--border-width-notification-panel-card, 1px) solid var(--sys-neutral-decor-default, #dde0ea);
|
|
25
|
+
border-radius:var(--radius-notification-panel-card, 4px);
|
|
26
|
+
transition:left calc(var(--snack-notification-stack-animation-duration) / 2) calc(var(--snack-notification-stack-animation-duration) / 2) ease, right calc(var(--snack-notification-stack-animation-duration) / 2) calc(var(--snack-notification-stack-animation-duration) / 2) ease, opacity calc(var(--snack-notification-stack-animation-duration) / 2) calc(var(--snack-notification-stack-animation-duration) / 2) ease;
|
|
27
|
+
}
|
|
28
|
+
.card::after{
|
|
29
|
+
content:"";
|
|
30
|
+
position:absolute;
|
|
31
|
+
top:0;
|
|
32
|
+
right:0;
|
|
33
|
+
bottom:0;
|
|
34
|
+
left:0;
|
|
35
|
+
opacity:var(--opacity-a008, 0.08);
|
|
36
|
+
background-color:var(--sys-neutral-accent-default, #787b8a);
|
|
37
|
+
}
|
|
38
|
+
[data-open] .card{
|
|
39
|
+
right:0;
|
|
40
|
+
left:0;
|
|
41
|
+
opacity:0;
|
|
42
|
+
transition:left calc(var(--snack-notification-stack-animation-duration) / 2) ease, right calc(var(--snack-notification-stack-animation-duration) / 2) ease, opacity calc(var(--snack-notification-stack-animation-duration) / 2) ease;
|
|
43
|
+
}
|
|
44
|
+
.card[data-level="2"]{
|
|
45
|
+
right:var(--space-notification-panel-card-stack-stack2-level-horizontal-padding, 4px);
|
|
46
|
+
bottom:50%;
|
|
47
|
+
left:var(--space-notification-panel-card-stack-stack2-level-horizontal-padding, 4px);
|
|
48
|
+
}
|
|
49
|
+
.card[data-level="3"]{
|
|
50
|
+
right:var(--space-notification-panel-card-stack-stack3-level-horizontal-padding, 8px);
|
|
51
|
+
bottom:0;
|
|
52
|
+
left:var(--space-notification-panel-card-stack-stack3-level-horizontal-padding, 8px);
|
|
53
|
+
}
|
|
@@ -3,5 +3,5 @@ import { TooltipProps } from '@snack-uikit/tooltip';
|
|
|
3
3
|
type WithTooltipProps = PropsWithChildren<{
|
|
4
4
|
tooltip?: TooltipProps;
|
|
5
5
|
}>;
|
|
6
|
-
export declare function WithTooltip({ tooltip, children }: WithTooltipProps): string | number | boolean |
|
|
6
|
+
export declare function WithTooltip({ tooltip, children }: WithTooltipProps): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | null | undefined;
|
|
7
7
|
export {};
|
|
@@ -32,14 +32,17 @@
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.notificationPanelBody{
|
|
35
|
+
padding-top:var(--space-notification-panel-body-vertical-padding, 16px);
|
|
36
|
+
padding-bottom:var(--space-notification-panel-body-vertical-padding, 16px);
|
|
37
|
+
padding-left:var(--space-notification-panel-body-horizontal-padding, 16px);
|
|
38
|
+
padding-right:var(--space-notification-panel-body-horizontal-padding, 16px);
|
|
39
|
+
display:flex;
|
|
35
40
|
flex:1 1 auto;
|
|
41
|
+
flex-direction:column;
|
|
42
|
+
gap:var(--space-notification-panel-container-body-gap, 16px);
|
|
36
43
|
min-height:0;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
.notificationPanelCard:last-of-type{
|
|
40
|
-
border-bottom:none;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
46
|
.notificationPanelFooterButton{
|
|
44
47
|
border-top-width:var(--border-width-notification-panel-container, 1px);
|
|
45
48
|
border-bottom-right-radius:var(--radius-notification-panel-footer-radius-bottom, 4px);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Dispatch, ReactElement, SetStateAction } from 'react';
|
|
2
|
+
import { BaseItemProps } from '@snack-uikit/list';
|
|
3
|
+
import { NotificationCardProps } from '../../components/NotificationCard/NotificationCard';
|
|
4
|
+
export type Action = {
|
|
5
|
+
icon?: ReactElement;
|
|
6
|
+
tagLabel?: string;
|
|
7
|
+
} & Pick<BaseItemProps, 'content' | 'onClick' | 'disabled'>;
|
|
8
|
+
export type NotificationCardFunctionProps = Required<Pick<NotificationCardProps, 'actions'>> & {
|
|
9
|
+
actions: Action[];
|
|
10
|
+
open: boolean;
|
|
11
|
+
setDroplistOpen: Dispatch<SetStateAction<boolean>>;
|
|
12
|
+
size: 's' | 'xs';
|
|
13
|
+
icon: ReactElement;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function ActionsButton({ actions, open, setDroplistOpen, size, icon, className, }: NotificationCardFunctionProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { ButtonFunction } from '@snack-uikit/button';
|
|
4
|
+
import { Droplist } from '@snack-uikit/list';
|
|
5
|
+
import { Tag } from '@snack-uikit/tag';
|
|
6
|
+
import { TEST_IDS } from '../../components/NotificationCard/constants';
|
|
7
|
+
import { stopPropagationClick } from '../../components/NotificationCard/helpers';
|
|
8
|
+
import styles from './styles.module.css';
|
|
9
|
+
export function ActionsButton({ actions, open, setDroplistOpen, size, icon, className, }) {
|
|
10
|
+
return (
|
|
11
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
12
|
+
_jsx("div", { className: cn(styles.container, className), "data-test-id": TEST_IDS.actions.wrapper, onClick: stopPropagationClick, children: _jsx(Droplist, { trigger: 'clickAndFocusVisible', open: open, onOpenChange: setDroplistOpen, placement: 'bottom-end', scroll: true, "data-test-id": TEST_IDS.actions.droplist, items: actions.map(({ onClick, disabled, content, tagLabel, icon }) => ({
|
|
13
|
+
onClick: e => {
|
|
14
|
+
setDroplistOpen(false);
|
|
15
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(e);
|
|
16
|
+
},
|
|
17
|
+
disabled,
|
|
18
|
+
content,
|
|
19
|
+
beforeContent: icon,
|
|
20
|
+
afterContent: tagLabel ? _jsx(Tag, { label: tagLabel }) : undefined,
|
|
21
|
+
'data-test-id': TEST_IDS.actions.droplistAction,
|
|
22
|
+
})), children: _jsx(ButtonFunction, { size: size, icon: icon, "data-test-id": TEST_IDS.actions.droplistTrigger }) }) }));
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ActionsButton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ActionsButton';
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Notification",
|
|
7
|
-
"version": "0.13.
|
|
7
|
+
"version": "0.13.26",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"@snack-uikit/truncate-string": "0.7.7",
|
|
51
51
|
"@snack-uikit/typography": "0.8.12",
|
|
52
52
|
"@snack-uikit/utils": "4.0.1",
|
|
53
|
-
"classnames": "2.5.1"
|
|
53
|
+
"classnames": "2.5.1",
|
|
54
|
+
"uncontrollable": "9.0.0"
|
|
54
55
|
},
|
|
55
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "e247cdff4704598b6b9197e0570d480f81095d80"
|
|
56
57
|
}
|
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
import cn from 'classnames';
|
|
2
|
-
import { ElementType, MouseEventHandler,
|
|
2
|
+
import { ElementType, MouseEventHandler, ReactNode, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
import { ButtonSimple, ButtonSimpleProps, ButtonTonal, ButtonTonalProps } from '@snack-uikit/button';
|
|
5
|
+
import { KebabSVG } from '@snack-uikit/icons';
|
|
5
6
|
import { Link, PickLinkProps } from '@snack-uikit/link';
|
|
6
|
-
import { BaseItemProps } from '@snack-uikit/list';
|
|
7
7
|
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
8
8
|
import { Typography } from '@snack-uikit/typography';
|
|
9
9
|
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { type Action, ActionsButton } from '../../helperComponents/ActionsButton';
|
|
12
12
|
import { APPEARANCE, TEST_IDS } from './constants';
|
|
13
|
-
import { getIcon } from './helpers';
|
|
13
|
+
import { getIcon, stopPropagationClick } from './helpers';
|
|
14
14
|
import styles from './styles.module.scss';
|
|
15
15
|
import { Appearance } from './types';
|
|
16
16
|
|
|
17
|
-
type Action = {
|
|
18
|
-
icon?: ReactElement;
|
|
19
|
-
tagLabel?: string;
|
|
20
|
-
} & Pick<BaseItemProps, 'content' | 'onClick' | 'disabled'>;
|
|
21
|
-
|
|
22
17
|
export type NotificationCardProps<LinkElement extends ElementType = 'a'> = WithSupportProps<{
|
|
23
18
|
/** Идентификатор уведомления */
|
|
24
19
|
id: string;
|
|
@@ -122,7 +117,14 @@ export function NotificationCard<LinkElement extends ElementType = 'a'>({
|
|
|
122
117
|
className={cn(styles.notificationCard, className)}
|
|
123
118
|
>
|
|
124
119
|
{actions?.length && (
|
|
125
|
-
<
|
|
120
|
+
<ActionsButton
|
|
121
|
+
className={styles.notificationCardFunction}
|
|
122
|
+
actions={actions}
|
|
123
|
+
open={isDroplistOpen}
|
|
124
|
+
setDroplistOpen={setDroplistOpen}
|
|
125
|
+
size='s'
|
|
126
|
+
icon={<KebabSVG />}
|
|
127
|
+
/>
|
|
126
128
|
)}
|
|
127
129
|
|
|
128
130
|
{label && (
|
|
@@ -146,7 +148,8 @@ export function NotificationCard<LinkElement extends ElementType = 'a'>({
|
|
|
146
148
|
)}
|
|
147
149
|
|
|
148
150
|
{(primaryButton || secondaryButton) && (
|
|
149
|
-
|
|
151
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
152
|
+
<div className={styles.notificationCardButtons} onClick={stopPropagationClick}>
|
|
150
153
|
{secondaryButton && (
|
|
151
154
|
<ButtonSimple {...secondaryButton} appearance='neutral' size='s' data-test-id={TEST_IDS.primaryButton} />
|
|
152
155
|
)}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { MouseEvent } from 'react';
|
|
2
|
+
|
|
1
3
|
import { AlarmFilledSVG, CheckFilledSVG, CrossFilledSVG, InfoFilledSVG } from '@snack-uikit/icons';
|
|
2
4
|
|
|
3
5
|
import { APPEARANCE } from './constants';
|
|
@@ -18,3 +20,7 @@ export function getIcon(appearance: Appearance) {
|
|
|
18
20
|
return null;
|
|
19
21
|
}
|
|
20
22
|
}
|
|
23
|
+
|
|
24
|
+
export function stopPropagationClick(e: MouseEvent<HTMLElement>) {
|
|
25
|
+
e.stopPropagation();
|
|
26
|
+
}
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
box-sizing: border-box;
|
|
41
41
|
max-width: 100%;
|
|
42
42
|
|
|
43
|
-
border-
|
|
44
|
-
border-
|
|
43
|
+
border-color: styles-tokens-notification-notificationCard.$sys-neutral-decor-default;
|
|
44
|
+
border-style: solid;
|
|
45
45
|
|
|
46
46
|
&::before {
|
|
47
47
|
pointer-events: none;
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
&:focus-visible {
|
|
63
63
|
@include styles-tokens-notification-notificationCard.outline-var(styles-tokens-element.$container-focused-s);
|
|
64
64
|
|
|
65
|
-
border-
|
|
65
|
+
border-color: transparent;
|
|
66
66
|
outline-color: styles-tokens-notification-notificationCard.$sys-available-complementary;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -12,6 +12,8 @@ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
|
12
12
|
|
|
13
13
|
import { NotificationCardSkeleton } from '../NotificationCard/components';
|
|
14
14
|
import {
|
|
15
|
+
NotificationCardStack,
|
|
16
|
+
NotificationCardStackProps,
|
|
15
17
|
NotificationPanelBlank,
|
|
16
18
|
NotificationPanelBlankProps,
|
|
17
19
|
NotificationPanelSettings,
|
|
@@ -110,17 +112,19 @@ export function NotificationPanel({
|
|
|
110
112
|
</div>
|
|
111
113
|
</div>
|
|
112
114
|
|
|
113
|
-
<Scroll size='m'
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
<Scroll size='m' ref={scrollContainerRef}>
|
|
116
|
+
<div className={styles.notificationPanelBody}>
|
|
117
|
+
{content}
|
|
118
|
+
{loading && (
|
|
119
|
+
<SkeletonContextProvider loading={loading || false}>
|
|
120
|
+
{skeletons.map(skeleton => (
|
|
121
|
+
<WithSkeleton key={skeleton} skeleton={<NotificationCardSkeleton />} />
|
|
122
|
+
))}
|
|
123
|
+
</SkeletonContextProvider>
|
|
124
|
+
)}
|
|
122
125
|
|
|
123
|
-
|
|
126
|
+
<div className={styles.scrollStub} ref={scrollEndRef} />
|
|
127
|
+
</div>
|
|
124
128
|
</Scroll>
|
|
125
129
|
|
|
126
130
|
{footerButton && (
|
|
@@ -142,4 +146,6 @@ export namespace NotificationPanel {
|
|
|
142
146
|
export type BlankProps = NotificationPanelBlankProps;
|
|
143
147
|
export const Divider: typeof NotificationPanelDivider = NotificationPanelDivider;
|
|
144
148
|
export type DividerProps = NotificationPanelDividerProps;
|
|
149
|
+
export const Stack: typeof NotificationCardStack = NotificationCardStack;
|
|
150
|
+
export type StackProps = NotificationCardStackProps;
|
|
145
151
|
}
|
package/src/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.tsx
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Children, ReactNode, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ButtonFunction } from '@snack-uikit/button';
|
|
4
|
+
import { ChevronDownSVG, ChevronUpSVG, KebabSVG } from '@snack-uikit/icons';
|
|
5
|
+
|
|
6
|
+
import { Action, ActionsButton } from '../../../../helperComponents/ActionsButton';
|
|
7
|
+
import { TEST_IDS } from '../../constants';
|
|
8
|
+
import { StackTail } from '../../helperComponents/StackTail';
|
|
9
|
+
import { useAnimatedOpening } from './hooks';
|
|
10
|
+
import styles from './styles.module.scss';
|
|
11
|
+
import { cloneCard } from './utils';
|
|
12
|
+
|
|
13
|
+
export type NotificationCardStackProps = {
|
|
14
|
+
/**
|
|
15
|
+
* Заголовок стопки карточек
|
|
16
|
+
*/
|
|
17
|
+
title: string;
|
|
18
|
+
/**
|
|
19
|
+
* Состояние открыт/закрыт по умолчанию
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
defaultOpen?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Колбек смены состояния открыт/закрыт
|
|
25
|
+
* @type (open: boolean) => void
|
|
26
|
+
*/
|
|
27
|
+
onOpenChanged?: (open: boolean) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Карточки в стопке, видна первая карточка, остальные схлопываются под нее.
|
|
30
|
+
*/
|
|
31
|
+
children: Iterable<ReactNode>;
|
|
32
|
+
/**
|
|
33
|
+
* Список действий в выпадающем меню
|
|
34
|
+
*/
|
|
35
|
+
actions?: Action[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const ANIMATION_DURATION = 0.3;
|
|
39
|
+
|
|
40
|
+
export function NotificationCardStack({
|
|
41
|
+
children,
|
|
42
|
+
defaultOpen,
|
|
43
|
+
onOpenChanged,
|
|
44
|
+
title,
|
|
45
|
+
actions,
|
|
46
|
+
}: NotificationCardStackProps) {
|
|
47
|
+
const [actionsOpen, setActionsOpen] = useState(false);
|
|
48
|
+
const { open, toggleOpen, isVisible } = useAnimatedOpening({
|
|
49
|
+
defaultOpen,
|
|
50
|
+
onOpenChanged,
|
|
51
|
+
duration: ANIMATION_DURATION * 1000,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const [first, ...stack] = useMemo(() => Children.toArray(children), [children]);
|
|
55
|
+
|
|
56
|
+
if (!first) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!stack.length) {
|
|
61
|
+
return <>{first}</>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const firstCardElement = open ? first : cloneCard(first, { onClick: toggleOpen });
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
className={styles.container}
|
|
69
|
+
style={{ '--snack-notification-stack-animation-duration': `${ANIMATION_DURATION}s` }}
|
|
70
|
+
data-test-id={TEST_IDS.cardStack.wrapper}
|
|
71
|
+
>
|
|
72
|
+
<div className={styles.header} data-test-id={TEST_IDS.cardStack.headline}>
|
|
73
|
+
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
|
|
74
|
+
<label className={styles.title} onClick={toggleOpen} data-test-id={TEST_IDS.cardStack.title}>
|
|
75
|
+
{title}
|
|
76
|
+
</label>
|
|
77
|
+
<div className={styles.right}>
|
|
78
|
+
{actions && actions.length > 0 && (
|
|
79
|
+
<ActionsButton
|
|
80
|
+
actions={actions}
|
|
81
|
+
open={actionsOpen}
|
|
82
|
+
setDroplistOpen={setActionsOpen}
|
|
83
|
+
size='xs'
|
|
84
|
+
icon={<KebabSVG />}
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
<ButtonFunction
|
|
88
|
+
size='xs'
|
|
89
|
+
onClick={toggleOpen}
|
|
90
|
+
data-test-id={TEST_IDS.cardStack.openButton}
|
|
91
|
+
icon={open ? <ChevronUpSVG /> : <ChevronDownSVG />}
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div className={styles.cards}>
|
|
96
|
+
<div className={styles.first}>
|
|
97
|
+
{/* there is column-reverse because of card focus outline should be placed over stack tail */}
|
|
98
|
+
<StackTail open={open} count={stack.length} />
|
|
99
|
+
{firstCardElement}
|
|
100
|
+
</div>
|
|
101
|
+
<div className={styles.stack} data-open={open || undefined} data-tail-size={stack.length}>
|
|
102
|
+
<div className={styles.animationContainer}>{isVisible ? stack : []}</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
3
|
+
|
|
4
|
+
type UseAnimatedOpeningProps = {
|
|
5
|
+
defaultOpen?: boolean;
|
|
6
|
+
onOpenChanged?: (open: boolean) => void;
|
|
7
|
+
duration: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type UseAnimatedOpeningResult = {
|
|
11
|
+
open: boolean;
|
|
12
|
+
isVisible: boolean;
|
|
13
|
+
toggleOpen(): void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function useAnimatedOpening({
|
|
17
|
+
defaultOpen = false,
|
|
18
|
+
onOpenChanged,
|
|
19
|
+
duration,
|
|
20
|
+
}: UseAnimatedOpeningProps): UseAnimatedOpeningResult {
|
|
21
|
+
const [open, setOpen] = useUncontrolledProp(undefined, defaultOpen, onOpenChanged);
|
|
22
|
+
const [isVisible, setIsVisible] = useState(open);
|
|
23
|
+
const timeout = useRef<NodeJS.Timeout>();
|
|
24
|
+
|
|
25
|
+
const toggleOpen = useCallback(() => {
|
|
26
|
+
setOpen(!open);
|
|
27
|
+
}, [open, setOpen]);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
clearTimeout(timeout.current);
|
|
31
|
+
if (open) {
|
|
32
|
+
setIsVisible(true);
|
|
33
|
+
} else {
|
|
34
|
+
timeout.current = setTimeout(() => {
|
|
35
|
+
setIsVisible(false);
|
|
36
|
+
}, duration);
|
|
37
|
+
}
|
|
38
|
+
}, [open, duration]);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
toggleOpen,
|
|
42
|
+
open,
|
|
43
|
+
isVisible,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './NotificationCardStack';
|