iamhosseindhv / notistack

Highly customizable notification snackbars (toasts) that can be stacked on top of each other
https://notistack.com
Other
3.93k stars 298 forks source link

Error snackbar does not dissapear upon clicking the cross icon #567

Open ghost opened 1 year ago

ghost commented 1 year ago

Expected Behavior

Upon clicking the close button, snackbar should disappear (This is the behavior seen in other libraries)

Current Behavior

Nothing happens the cross icon just confuses the user into believing it has some actions.

Context

I did hack the solution by myself, but I'd like this case to be covered in the documentation

Your Environment

Tech Version
Notistack v3.0.1
React 18.2
Browser Chrome

Demo

animation

Codesanbox

https://codesandbox.io/s/nostalgic-jennings-p60v3x?file=/MessageButtons.js

olabisi09 commented 1 year ago

This is because the close button isn't actually a close button; it's an icon that describes what type of snackbar pops up. If you do want the snackbar to close, you can use the action prop and pass in a function that closes it.

Here's a part of the documentation that shows how to do that: https://notistack.com/features/basic#actions

ghost commented 1 year ago

This is what I actually did

But this imperative way feels hacky

import { Box } from '@mui/material';
import { SnackbarKey, useSnackbar } from 'notistack';
import { useEffect, useRef } from 'react';

interface Props {
  snackbarKey: SnackbarKey;
}

const CloseSnackbarAction = ({ snackbarKey }: Props) => {
  const { closeSnackbar } = useSnackbar();

  const snackbarRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClick = () => closeSnackbar(snackbarKey);

    const snackbarParent = snackbarRef.current?.parentElement?.parentElement;

    if (snackbarParent && snackbarParent.className.includes('variantError')) {
      const snackBarSvgIcon = snackbarParent.childNodes[0]?.childNodes[0];
      snackBarSvgIcon?.addEventListener('click', handleClick);

      return () => snackBarSvgIcon?.removeEventListener('click', handleClick);
    }
  }, [closeSnackbar, snackbarKey]);

  return <Box ref={snackbarRef} />;
};

export default CloseSnackbarAction;

Feels like there should have been a better built in setup for this or something

mapsmarketing commented 11 months ago

This is what I actually did

But this imperative way feels hacky

import { Box } from '@mui/material';
import { SnackbarKey, useSnackbar } from 'notistack';
import { useEffect, useRef } from 'react';

interface Props {
  snackbarKey: SnackbarKey;
}

const CloseSnackbarAction = ({ snackbarKey }: Props) => {
  const { closeSnackbar } = useSnackbar();

  const snackbarRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClick = () => closeSnackbar(snackbarKey);

    const snackbarParent = snackbarRef.current?.parentElement?.parentElement;

    if (snackbarParent && snackbarParent.className.includes('variantError')) {
      const snackBarSvgIcon = snackbarParent.childNodes[0]?.childNodes[0];
      snackBarSvgIcon?.addEventListener('click', handleClick);

      return () => snackBarSvgIcon?.removeEventListener('click', handleClick);
    }
  }, [closeSnackbar, snackbarKey]);

  return <Box ref={snackbarRef} />;
};

export default CloseSnackbarAction;

Feels like there should have been a better built in setup for this or something

Very hacky. I think they forgot about the close/dismiss. It should be an option e.g.:

enqueueSnackbar("This is a success message!", { variant: "success", closeable: true });