@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.
Files changed (101) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +70 -0
  3. package/dist/cjs/components/NotificationCard/NotificationCard.d.ts +2 -7
  4. package/dist/cjs/components/NotificationCard/NotificationCard.js +11 -4
  5. package/dist/cjs/components/NotificationCard/components/index.d.ts +0 -1
  6. package/dist/cjs/components/NotificationCard/components/index.js +0 -1
  7. package/dist/cjs/components/NotificationCard/helpers.d.ts +2 -0
  8. package/dist/cjs/components/NotificationCard/helpers.js +4 -0
  9. package/dist/cjs/components/NotificationCard/styles.module.css +10 -9
  10. package/dist/cjs/components/NotificationPanel/NotificationPanel.d.ts +3 -1
  11. package/dist/cjs/components/NotificationPanel/NotificationPanel.js +14 -11
  12. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.d.ts +27 -0
  13. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.js +101 -0
  14. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/hooks.d.ts +12 -0
  15. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/hooks.js +36 -0
  16. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/index.d.ts +1 -0
  17. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/index.js +25 -0
  18. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/styles.module.css +74 -0
  19. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/utils.d.ts +2 -0
  20. package/dist/cjs/components/NotificationPanel/components/NotificationCardStack/utils.js +14 -0
  21. package/dist/cjs/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.js +10 -3
  22. package/dist/cjs/components/NotificationPanel/components/NotificationPanelDivider/styles.module.css +12 -3
  23. package/dist/cjs/components/NotificationPanel/components/index.d.ts +1 -0
  24. package/dist/cjs/components/NotificationPanel/components/index.js +2 -1
  25. package/dist/cjs/components/NotificationPanel/constants.d.ts +6 -0
  26. package/dist/cjs/components/NotificationPanel/constants.js +7 -1
  27. package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/StackTail.d.ts +6 -0
  28. package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/StackTail.js +33 -0
  29. package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/index.d.ts +1 -0
  30. package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/index.js +25 -0
  31. package/dist/cjs/components/NotificationPanel/helperComponents/StackTail/styles.module.css +53 -0
  32. package/dist/cjs/components/NotificationPanel/helperComponents/WithTooltip/WithTooltip.d.ts +1 -1
  33. package/dist/cjs/components/NotificationPanel/styles.module.css +7 -4
  34. package/dist/cjs/helperComponents/ActionsButton/ActionsButton.d.ts +16 -0
  35. package/dist/cjs/helperComponents/ActionsButton/ActionsButton.js +72 -0
  36. package/dist/cjs/helperComponents/ActionsButton/index.d.ts +1 -0
  37. package/dist/cjs/helperComponents/ActionsButton/index.js +25 -0
  38. package/dist/cjs/helperComponents/ActionsButton/styles.module.css +3 -0
  39. package/dist/esm/components/NotificationCard/NotificationCard.d.ts +2 -7
  40. package/dist/esm/components/NotificationCard/NotificationCard.js +6 -3
  41. package/dist/esm/components/NotificationCard/components/index.d.ts +0 -1
  42. package/dist/esm/components/NotificationCard/components/index.js +0 -1
  43. package/dist/esm/components/NotificationCard/helpers.d.ts +2 -0
  44. package/dist/esm/components/NotificationCard/helpers.js +3 -0
  45. package/dist/esm/components/NotificationCard/styles.module.css +10 -9
  46. package/dist/esm/components/NotificationPanel/NotificationPanel.d.ts +3 -1
  47. package/dist/esm/components/NotificationPanel/NotificationPanel.js +3 -2
  48. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.d.ts +27 -0
  49. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.js +28 -0
  50. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/hooks.d.ts +12 -0
  51. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/hooks.js +26 -0
  52. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/index.d.ts +1 -0
  53. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/index.js +1 -0
  54. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/styles.module.css +74 -0
  55. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/utils.d.ts +2 -0
  56. package/dist/esm/components/NotificationPanel/components/NotificationCardStack/utils.js +7 -0
  57. package/dist/esm/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.js +2 -2
  58. package/dist/esm/components/NotificationPanel/components/NotificationPanelDivider/styles.module.css +12 -3
  59. package/dist/esm/components/NotificationPanel/components/index.d.ts +1 -0
  60. package/dist/esm/components/NotificationPanel/components/index.js +1 -0
  61. package/dist/esm/components/NotificationPanel/constants.d.ts +6 -0
  62. package/dist/esm/components/NotificationPanel/constants.js +6 -0
  63. package/dist/esm/components/NotificationPanel/helperComponents/StackTail/StackTail.d.ts +6 -0
  64. package/dist/esm/components/NotificationPanel/helperComponents/StackTail/StackTail.js +5 -0
  65. package/dist/esm/components/NotificationPanel/helperComponents/StackTail/index.d.ts +1 -0
  66. package/dist/esm/components/NotificationPanel/helperComponents/StackTail/index.js +1 -0
  67. package/dist/esm/components/NotificationPanel/helperComponents/StackTail/styles.module.css +53 -0
  68. package/dist/esm/components/NotificationPanel/helperComponents/WithTooltip/WithTooltip.d.ts +1 -1
  69. package/dist/esm/components/NotificationPanel/styles.module.css +7 -4
  70. package/dist/esm/helperComponents/ActionsButton/ActionsButton.d.ts +16 -0
  71. package/dist/esm/helperComponents/ActionsButton/ActionsButton.js +23 -0
  72. package/dist/esm/helperComponents/ActionsButton/index.d.ts +1 -0
  73. package/dist/esm/helperComponents/ActionsButton/index.js +1 -0
  74. package/dist/esm/helperComponents/ActionsButton/styles.module.css +3 -0
  75. package/package.json +4 -3
  76. package/src/components/NotificationCard/NotificationCard.tsx +14 -11
  77. package/src/components/NotificationCard/components/index.ts +0 -1
  78. package/src/components/NotificationCard/helpers.tsx +6 -0
  79. package/src/components/NotificationCard/styles.module.scss +3 -3
  80. package/src/components/NotificationPanel/NotificationPanel.tsx +16 -10
  81. package/src/components/NotificationPanel/components/NotificationCardStack/NotificationCardStack.tsx +107 -0
  82. package/src/components/NotificationPanel/components/NotificationCardStack/hooks.ts +45 -0
  83. package/src/components/NotificationPanel/components/NotificationCardStack/index.ts +1 -0
  84. package/src/components/NotificationPanel/components/NotificationCardStack/styles.module.scss +89 -0
  85. package/src/components/NotificationPanel/components/NotificationCardStack/utils.ts +12 -0
  86. package/src/components/NotificationPanel/components/NotificationPanelDivider/NotificationPanelDivider.tsx +5 -3
  87. package/src/components/NotificationPanel/components/NotificationPanelDivider/styles.module.scss +15 -7
  88. package/src/components/NotificationPanel/components/index.ts +1 -0
  89. package/src/components/NotificationPanel/constants.ts +6 -0
  90. package/src/components/NotificationPanel/helperComponents/StackTail/StackTail.tsx +17 -0
  91. package/src/components/NotificationPanel/helperComponents/StackTail/index.ts +1 -0
  92. package/src/components/NotificationPanel/helperComponents/StackTail/styles.module.scss +77 -0
  93. package/src/components/NotificationPanel/styles.module.scss +6 -6
  94. package/src/helperComponents/ActionsButton/ActionsButton.tsx +65 -0
  95. package/src/helperComponents/ActionsButton/index.ts +1 -0
  96. package/src/helperComponents/ActionsButton/styles.module.scss +3 -0
  97. package/dist/cjs/components/NotificationCard/components/NotificationCardFunction.d.ts +0 -7
  98. package/dist/cjs/components/NotificationCard/components/NotificationCardFunction.js +0 -64
  99. package/dist/esm/components/NotificationCard/components/NotificationCardFunction.d.ts +0 -7
  100. package/dist/esm/components/NotificationCard/components/NotificationCardFunction.js +0 -20
  101. package/src/components/NotificationCard/components/NotificationCardFunction.tsx +0 -43
@@ -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;
@@ -0,0 +1,7 @@
1
+ import { cloneElement, isValidElement } from 'react';
2
+ export const cloneCard = (element, props) => {
3
+ if (!isValidElement(element)) {
4
+ return element;
5
+ }
6
+ return cloneElement(element, Object.assign(Object.assign({}, element.props), props));
7
+ };
@@ -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 (_jsx(Typography.LightLabelS, Object.assign({ className: cn(styles.notificationPanelDivider, className) }, extractSupportProps(rest), { children: text })));
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
  }
@@ -1,10 +1,19 @@
1
- .notificationPanelDivider{
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;
@@ -1,2 +1,3 @@
1
1
  export * from './NotificationPanelSettings';
2
2
  export * from './NotificationPanelBlank';
3
+ export * from './NotificationCardStack';
@@ -1,2 +1,3 @@
1
1
  export * from './NotificationPanelSettings';
2
2
  export * from './NotificationPanelBlank';
3
+ export * from './NotificationCardStack';
@@ -9,4 +9,10 @@ export declare const TEST_IDS: {
9
9
  readAll: string;
10
10
  footerButton: string;
11
11
  skeleton: string;
12
+ cardStack: {
13
+ headline: string;
14
+ wrapper: string;
15
+ title: string;
16
+ openButton: string;
17
+ };
12
18
  };
@@ -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,6 @@
1
+ type StackTailProps = {
2
+ open: boolean;
3
+ count: number;
4
+ };
5
+ export declare function StackTail({ open, count }: StackTailProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -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 | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
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';
@@ -0,0 +1,3 @@
1
+ .container{
2
+ display:flex;
3
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Notification",
7
- "version": "0.13.25",
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": "84371bbf91915f650a852df849cd71d416c5b7b2"
56
+ "gitHead": "e247cdff4704598b6b9197e0570d480f81095d80"
56
57
  }
@@ -1,24 +1,19 @@
1
1
  import cn from 'classnames';
2
- import { ElementType, MouseEventHandler, ReactElement, ReactNode, useEffect, useMemo, useRef, useState } from 'react';
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 { NotificationCardFunction } from './components';
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
- <NotificationCardFunction actions={actions} open={isDroplistOpen} setDroplistOpen={setDroplistOpen} />
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
- <div className={styles.notificationCardButtons}>
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,2 +1 @@
1
- export * from './NotificationCardFunction';
2
1
  export * from './NotificationCardSkeleton';
@@ -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-bottom-color: styles-tokens-notification-notificationCard.$sys-neutral-decor-default;
44
- border-bottom-style: solid;
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-bottom-color: transparent;
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' className={styles.notificationPanelBody} ref={scrollContainerRef}>
114
- {content}
115
- {loading && (
116
- <SkeletonContextProvider loading={loading || false}>
117
- {skeletons.map(skeleton => (
118
- <WithSkeleton key={skeleton} skeleton={<NotificationCardSkeleton />} />
119
- ))}
120
- </SkeletonContextProvider>
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
- <div className={styles.scrollStub} ref={scrollEndRef} />
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
  }
@@ -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';