Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can we dismiss the toast programmatically? toast.dismiss() does not work #50

Open
thoriqadillah opened this issue Feb 17, 2024 · 16 comments

Comments

@thoriqadillah
Copy link

thoriqadillah commented Feb 17, 2024

i am working on GUI using wails, and I tried to make my own toast because somehow the toast can't be styled using the toast option you provided using tailwind. and the toast itself is not really match up the design of my app, so i need to make my own anyway

the problem is, when i tried to use my own component, the value from the option somehow still appearing outside my component. and i am struggling to dismiss the toast because toast.dismiss() is not working. i don't know if this has something to do with wails or not

btw, i use vue-shadcn port
here is my implementation

// some imports

export type ToastOption = Omit<ExternalToast, 'invert' | 'icon' | 'important' | 'style' | 'unstyled' | 'descriptionClassName' | 'className' | 'promise' /** | 'action' */ > & {
    type?: NonNullable<Parameters<typeof toastVariants>[0]>['text']
    action?: {
        label?: string,
        icon?: Component,
        onClick: () => void
    }
}

export type ToastProps = ToastOption & {
    title: string
}

export function toast(title: string, data?: ToastOption) {    
    callToast(markRaw(
        defineComponent({ render: () => h(Toast, { title, ...data }) })), 
        { 
            ...data,
            // description: undefined,
            // onAutoClose: data?.onAutoClose,
            // onDismiss: data?.onDismiss,
            // duration: data?.duration,
            // cancel: data?.cancel,
            // id: data?.id || new Date().getTime().toString(),
        }
    )
}

image

@thoriqadillah
Copy link
Author

i found the answer. after looking trough your code, it turns it will close the sonner after the custom component emits closeToast event

can you at least give us more concise documentation about this component so that we don't have to look deeper into your code? I think diving deeper to the code is not really necessary if we have good documentation

@ishaiavrahami
Copy link

ishaiavrahami commented Apr 3, 2024

Hi, did you find the solution to this? When i dismiss my custom toast it throws an error in the console that breaks it.

Please help if you can @thoriqadillah

@thoriqadillah
Copy link
Author

Just create emitter with name closeToast. For closing the toast, just emit it like this, after that the vue-sonner will take care of closing the toast

const props = defineProps<ToastProps>()
const emit = defineEmits<{
    (e: 'closeToast'): void
}>()

function dismiss() {
    if (props.onDismiss) props.onDismiss({ id: props.id! })
    emit('closeToast')
}

function click() {
    if (props.action) props.action.onClick()
    emit('closeToast')
}

@ishaiavrahami
Copy link

ishaiavrahami commented Apr 4, 2024

I’m not sure I understand. I use the standard toast.dismiss() but it throws an error. What example did you provide me above. PS I’m using Js not Ts @thoriqadillah

@thoriqadillah
Copy link
Author

If you create your custom toast, toast.dismiss will not work (i forgot the reason tho). I think the toast.dismiss only close the original toast, not our custom toast.

Vue sonner do not provide clear api to close the toast. After going deeper into the code, it turns out that to close the toast, we need to create emitter named closeToast and then emit it. Just try it out, and see if that works

@ishaiavrahami
Copy link

I understand now. Where should I create the emitter?

@thoriqadillah
Copy link
Author

Inside your toast

@ishaiavrahami
Copy link

ishaiavrahami commented Apr 5, 2024

Screenshot 2024-04-05 at 3 11 45 PM still getting this error after adding. Screenshot 2024-04-05 at 3 12 04 PM

maybe im not getting you

@thoriqadillah
Copy link
Author

thoriqadillah commented Apr 5, 2024

Take a look at my code (might as well shameless plug my project lol)

In Toast.vue is my custom toast using the vue-sonner
In index.ts is how i define the composable (function that calls the toast)

I'm using typescript tho, so i hope you understand some typescript, and i think you should start using typescript at some point

But, the most important thing is in Toast.vue. There, you define your emitter named closeToast. And when the user click close button or something, emit the closeToast to close the vue-sonner

@ishaiavrahami
Copy link

Got it to work and i want to personally thank you! @thoriqadillah

@vinaysudani
Copy link

Emiting closeToast from custom component works.
Thanks @thoriqadillah for writing it here, it helped me.

Mentioning it in documentation would be helpful to others.

@KodyaTemirov
Copy link

I still don't understand how this works. Can someone write a proper instruction?

@CMarzin
Copy link
Contributor

CMarzin commented Oct 21, 2024

I have made a PR for fixing the dismiss function, and a test example to show how the dismiss work.

You can check here #91

Maybe you can close the issue @xiaoluoboding when you will create a new tag/release for the 1.2.3 ?

@CMarzin
Copy link
Contributor

CMarzin commented Oct 21, 2024

Hey @xiaoluoboding, when do you think you can make a new release with the fix ?

@xiaoluoboding
Copy link
Owner

Hey @xiaoluoboding, when do you think you can make a new release with the fix ?

Released https://github.com/xiaoluoboding/vue-sonner/releases/tag/v1.2.3

@mrcego
Copy link

mrcego commented Oct 22, 2024

What if I have created my custom toast component with its own close button? How to get close event emit if I'm using toastservice for Alert component?

Example:

import Alert from './components/Alert.vue';
import { Toaster, toast } from 'vue-sonner';

const toastQueue = ref([]);

function callAlert() {
  const toastId = toast.custom(markRaw(Alert), {
    componentProps: {
      title: 'This is a title',
      body: 'This is a body text',
    },
    duration: 999999,
  });

  toastQueue.value.push(toastId);
}
</script>

<template>
  <Toaster position="top-center" />

  <button @click="callAlert" @close="">Call Alert</button>
</template>

Alert.vue

<script setup lang="ts">
import { EmitterEvents } from '@utils/components';
import { PropType } from 'vue';

import IconCheck from './Icons/IconCheck.vue';
import IconInfo from './Icons/IconInfo.vue';
import IconError from './Icons/IconError.vue';
import IconClose from './Icons/IconClose.vue';

const props = defineProps({
  title: { type: String, default: '' },
  body: { type: String, default: '' },
  width: { type: String, default: 'w-full' },
  close: { type: Boolean, default: false },
  timeout: { type: Number, default: 5 },
  icon: {
    type: String as PropType<'info' | 'error' | 'warning'>,
    default: 'info',
  },
});

const emit = defineEmits<{
  close: [];
}>();
</script>

<template>
  <div
    class="flex bg-white shadow rounded-md py-5 pl-6 pr-8 border border-primary-200"
    :class="[width]"
  >
    <!-- APPEND -->
    <slot name="append">
      <div class="flex grow-0 items-center">
        <IconInfo v-if="icon == 'info'" class="mr-2" />
        <IconCheck
          height="24"
          width="24"
          icon-color="#22C55E"
          v-else-if="icon == 'success'"
          class="mr-2"
        />
        <IconError
          height="24"
          width="24"
          circle-color="#EF4444"
          icon-color="#EF4444"
          v-else-if="icon == 'error'"
          class="mr-2"
        />
      </div>
    </slot>
    <!-- CONTENT -->
    <div class="flex flex-col grow">
      <p
        class="font-bold text-sm text-grayscale-400 leading-5 tracking-[-.02em] truncate"
      >
        {{ title }}
      </p>
      <span
        class="font-bold text-xs text-grayscale-300 leading-4 tracking-[.004em] truncate break-words whitespace-normal"
      >
        {{ body }}
      </span>
    </div>

    <div class="flex grow-0 items-center duration-300" @click="emit('close')">
      <IconClose
        height="24"
        width="24"
        class="cursor-pointer hover:bg-gray-200 duration-300 rounded-full p-1"
      />
    </div>
  </div>
</template>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants