1
- import React from 'react'
1
+ import React , { useEffect , useRef } from 'react'
2
2
import {
3
3
Stack ,
4
4
IconButton ,
@@ -7,40 +7,20 @@ import {
7
7
DefaultButton ,
8
8
PrimaryButton ,
9
9
useTheme ,
10
+ MotionTimings ,
10
11
} from '@fluentui/react'
11
12
import { FontIcon } from '@fluentui/react/lib/Icon'
13
+ import {
14
+ type Notification as NotificationModel ,
15
+ type NotificationAction ,
16
+ NotificationType ,
17
+ } from '~/store/notifications'
12
18
13
19
import './Notification.css'
14
20
15
- export enum NotificationType {
16
- None = '' ,
17
- Info = 'info' ,
18
- Warning = 'warning' ,
19
- Error = 'error' ,
20
- }
21
-
22
- interface ProgressState {
23
- indeterminate ?: boolean
24
- total ?: number
25
- current ?: number
26
- }
27
-
28
- interface NotificationAction {
29
- label : string
30
- key : string
31
- primary ?: boolean
32
- onClick ?: ( ) => void
33
- }
34
-
35
- export interface NotificationProps {
36
- id : number | string
37
- type ?: NotificationType
38
- title : string
39
- description ?: string
40
- canDismiss ?: boolean
41
- progress ?: ProgressState
42
- onClose ?: ( ) => void
43
- actions ?: NotificationAction [ ]
21
+ export interface NotificationProps extends NotificationModel {
22
+ onDismiss ?: ( id : string ) => void
23
+ onDismissed ?: ( id : string ) => void
44
24
}
45
25
46
26
const iconColorPaletteMap : { [ k in NotificationType ] : keyof ISemanticColors } = {
@@ -57,14 +37,18 @@ const statusIconMapping: { [k in NotificationType]: string } = {
57
37
[ NotificationType . None ] : 'info' ,
58
38
}
59
39
40
+ /**
41
+ * Computes current progress percentage and returns float value between 0 and 1.
42
+ *
43
+ * Returns undefined if there is no progress data available.
44
+ */
60
45
const getPercentComplete = ( progress : NotificationProps [ 'progress' ] ) : number | undefined => {
61
46
if ( ! progress || progress ?. indeterminate ) {
62
47
return
63
48
}
64
49
65
50
const { current, total } = progress
66
- const percentage = ( current ! * 100 ) / total !
67
- return percentage / 100
51
+ return current ! / total !
68
52
}
69
53
70
54
const NotificationActionButton : React . FC < Omit < NotificationAction , 'key' > > = ( { label, primary, onClick } ) => {
@@ -79,12 +63,52 @@ export const Notification: React.FunctionComponent<NotificationProps> = ({
79
63
description,
80
64
canDismiss = true ,
81
65
type = NotificationType . Info ,
82
- onClose,
83
66
actions,
67
+ dismissed,
68
+ onDismiss,
69
+ onDismissed,
84
70
} ) => {
71
+ const elementRef = useRef < HTMLDivElement | null > ( null )
85
72
const { semanticColors, fonts, ...theme } = useTheme ( )
73
+
74
+ useEffect ( ( ) => {
75
+ const { current : elem } = elementRef
76
+ if ( ! dismissed || ! elem ) {
77
+ return
78
+ }
79
+
80
+ // Animate element swipe out + shrink space around.
81
+ // Height should be extracted from JS until "calc-size" is not available.
82
+ const height = elem . clientHeight
83
+ const animation = elem . animate (
84
+ [
85
+ {
86
+ opacity : '1' ,
87
+ maxHeight : `${ height } px` ,
88
+ offset : 0 ,
89
+ } ,
90
+ {
91
+ opacity : '0.5' ,
92
+ transform : 'translate3d(120%, 0, 0)' ,
93
+ maxHeight : `${ height } px` ,
94
+ offset : 0.5 ,
95
+ } ,
96
+ {
97
+ opacity : '0' ,
98
+ transform : 'translate3d(120%, 0, 0)' ,
99
+ maxHeight : '0' ,
100
+ offset : 1.0 ,
101
+ } ,
102
+ ] ,
103
+ { duration : 200 , fill : 'forwards' , easing : MotionTimings . standard } ,
104
+ )
105
+
106
+ animation . onfinish = ( ) => onDismissed ?.( id )
107
+ animation . play ( )
108
+ } , [ id , dismissed , elementRef , onDismissed ] )
86
109
return (
87
110
< div
111
+ ref = { elementRef }
88
112
className = "Notification"
89
113
data-notification-id = { id }
90
114
style = { {
@@ -108,7 +132,7 @@ export const Notification: React.FunctionComponent<NotificationProps> = ({
108
132
< IconButton
109
133
title = "Close"
110
134
ariaLabel = "Close notification"
111
- onClick = { onClose }
135
+ onClick = { ( ) => onDismiss ?. ( id ) }
112
136
style = { {
113
137
color : 'inherit' ,
114
138
width : 'auto' ,
@@ -143,7 +167,7 @@ export const Notification: React.FunctionComponent<NotificationProps> = ({
143
167
key = { key }
144
168
onClick = { ( ) => {
145
169
onClick ?.( )
146
- onClose ?.( )
170
+ onDismiss ?.( id )
147
171
} }
148
172
/>
149
173
) ) }
0 commit comments