1
- import { AlwatrSignal , AlwatrTrigger } from '@alwatr/flux' ;
2
1
import { createLogger } from '@alwatr/logger' ;
3
- import { parseDuration , type Duration } from '@alwatr/parse-duration' ;
2
+ import { parseDuration } from '@alwatr/parse-duration' ;
4
3
import { waitForTimeout } from '@alwatr/wait' ;
5
4
6
- import type { SnackbarComponent } from './element.js' ;
5
+ import { snackbarActionButtonClickedSignal , snackbarSignal } from './signal.js' ;
6
+
7
+ import type { SnackbarElement } from './element.js' ;
8
+ import type { SnackbarOptions } from './type.js' ;
7
9
8
10
const logger = /* @__PURE__ */ createLogger ( `${ __package_name__ } /handler` ) ;
9
11
10
12
/**
11
- * @property content - Content to be displayed in the snackbar.
12
- * @property {action } - The action button configuration.
13
- * @property action.label - The label for the action button.
14
- * @property action.handler - The handler function for the action button.
15
- * @property duration - Duration for which the snackbar is displayed. `infinite` for infinite duration.
16
- * Duration for which the snackbar is displayed.
17
- * `infinite` for infinite duration.
18
- * @property addCloseButton - Whether to add a close button to the snackbar.
13
+ * Store the function to close the last snackbar.
19
14
*/
20
- export type SnackbarOptions = {
21
- content : string ;
22
- action ?: {
23
- label : string ;
24
- handler : ( ) => void ;
25
- } ;
26
- duration ?: Duration | 'infinite' ;
27
- addCloseButton ?: boolean ;
28
- } ;
15
+ let closeLastSnackbar : ( ( ) => Promise < void > ) | null = null ;
29
16
30
17
/**
31
- * Signal for when the snackbar action button is clicked.
18
+ * Store the function to unsubscribe the action button handler after close or action button clicked.
32
19
*/
33
- export const snackbarActionButtonClickedSignal = new AlwatrTrigger ( {
34
- name : 'snackbar-action-button-clicked' ,
35
- } ) ;
20
+ let unsubscribeActionButtonHandler : ( ( ) => void ) | null = null ;
36
21
37
22
/**
38
- * Signal for displaying the snackbar .
23
+ * Create snackbar element with given options .
39
24
*
40
- * @example
41
- * import {snackbarSignal} from '@nexim/snackbar';
25
+ * @param options - Options for configuring the snackbar.
26
+ * @returns The created snackbar element.
27
+ */
28
+ function createSnackbarElement ( options : SnackbarOptions ) : SnackbarElement {
29
+ const element = document . createElement ( 'snack-bar' ) ;
30
+ element . setAttribute ( 'content' , options . content ) ;
31
+
32
+ if ( options . addCloseButton === true ) {
33
+ element . setAttribute ( 'add-close-button' , '' ) ;
34
+ }
35
+
36
+ if ( options . action != null ) {
37
+ element . setAttribute ( 'action-button-label' , options . action . label ) ;
38
+ }
39
+
40
+ return element ;
41
+ }
42
+
43
+ /**
44
+ * Handle action button click.
42
45
*
43
- * snackbarSignal.notify({
44
- * content: 'This is a snackbar message',
45
- * // The following properties are optional.
46
- * action: {
47
- * label: 'Undo',
48
- * handler: () => {
49
- * console.log('Action button clicked');
50
- * },
51
- * },
52
- * duration: '4s',
53
- * addCloseButton: true,
54
- * });
46
+ * @param options - Options for configuring the snackbar.
47
+ * @param closeSnackbar - Function to close the snackbar.
55
48
*/
56
- export const snackbarSignal = /* @__PURE__ */ new AlwatrSignal < SnackbarOptions > ( { name : 'snackbar' } ) ;
49
+ function handleActionButtonClick ( closeSnackbar : ( ) => Promise < void > ) : void {
50
+ const actionButtonClickHandler = ( ) => {
51
+ logger . logOther ?.( 'Snackbar action button clicked.' ) ;
57
52
58
- // Subscribe to the snackbar signal to show the snackbar when the signal is emitted.
59
- snackbarSignal . subscribe ( ( options ) => {
60
- showSnackbar ( options ) ;
61
- } ) ;
53
+ return closeSnackbar ( ) ;
54
+ } ;
62
55
63
- let closeLastSnackbar : ( ( ) => Promise < void > ) | null = null ;
64
- let unsubscribeActionButtonHandler : ( ( ) => void ) | null = null ;
56
+ // Subscribe to the action button click
57
+ unsubscribeActionButtonHandler = snackbarActionButtonClickedSignal . subscribe ( actionButtonClickHandler . bind ( null ) , {
58
+ once : true ,
59
+ } ) . unsubscribe ;
60
+ }
65
61
66
62
/**
67
63
* Displays the snackbar with the given options.
64
+ *
68
65
* @param options - Options for configuring the snackbar.
69
66
*/
70
67
async function showSnackbar ( options : SnackbarOptions ) : Promise < void > {
71
68
logger . logMethodArgs ?.( 'showSnackbar' , { options} ) ;
72
69
73
- // Parse the duration
74
-
75
70
// Set default duration if not provided
76
- options . duration ??= '4s' ;
77
-
78
- const element = document . createElement ( 'snack-bar' ) as SnackbarComponent ;
71
+ options . duration ??= '5s' ;
79
72
80
- element . setAttribute ( 'content' , options . content ) ;
81
-
82
- if ( options . addCloseButton === true ) {
83
- element . setAttribute ( 'add-close-button' , '' ) ;
84
- }
85
-
86
- if ( options . action != null ) {
87
- element . setAttribute ( 'action-button-label' , options . action . label ) ;
88
-
89
- // Subscribe to the action button click
90
- unsubscribeActionButtonHandler = snackbarActionButtonClickedSignal . subscribe ( ( ) => {
91
- options . action ! . handler ( ) ;
92
-
93
- return closeSnackbar_ ( ) ;
94
- } ) . unsubscribe ;
95
- }
73
+ const element = createSnackbarElement ( options ) ;
96
74
97
75
let closed = false ;
98
- const closeSnackbar_ = async ( ) => {
76
+ const closeSnackbar = async ( ) => {
99
77
if ( closed === true ) return ;
100
78
logger . logMethodArgs ?.( 'closeSnackbar' , { options} ) ;
101
79
@@ -104,13 +82,22 @@ async function showSnackbar(options: SnackbarOptions): Promise<void> {
104
82
closed = true ;
105
83
} ;
106
84
85
+ if ( options . action != null ) {
86
+ handleActionButtonClick ( closeSnackbar ) ;
87
+ }
88
+
107
89
// Close the last snackbar if it exists
108
90
await closeLastSnackbar ?.( ) ;
109
- closeLastSnackbar = closeSnackbar_ ;
91
+ closeLastSnackbar = closeSnackbar ;
110
92
document . body . appendChild ( element ) ;
111
93
112
94
// Set a timeout to close the snackbar if duration is not infinite
113
95
if ( options . duration !== 'infinite' ) {
114
- waitForTimeout ( parseDuration ( options . duration ) ) . then ( closeSnackbar_ ) ;
96
+ waitForTimeout ( parseDuration ( options . duration ) ) . then ( closeSnackbar ) ;
115
97
}
116
98
}
99
+
100
+ // Subscribe to the snackbar signal to show the snackbar when the signal is emitted.
101
+ snackbarSignal . subscribe ( ( options ) => {
102
+ showSnackbar ( options ) ;
103
+ } ) ;
0 commit comments