Toasts and Dialogs
Report a result or ask before acting.
A toast reports something without stopping the user, such as "Copied". A dialog asks before you go on, such as "Reset all settings?".
Quick Start
Each common case is one line. Text is a message key. A key with placeholders takes its values next, as with format.
import { dialogs, toasts } from '@unbound-app/api';
declare const name: string;
declare const error: unknown;
toasts.success('STARRED', { name });
toasts.info('SYNCING');
toasts.warning('OFFLINE', { duration: 0 });
toasts.error(error);
toasts.error('FAILED_TO_SYNC', error);
const confirmed = await dialogs.confirm('DELETE_TITLE', {
titleVars: { name },
body: 'DELETE_BODY',
confirm: 'DELETE',
destructive: true,
});
await dialogs.alert('SYNC_DONE', { body: 'SYNC_DONE_BODY' });Reference
| Function | Does |
|---|---|
toasts.success, info, warning(key, vars?, options?) | A toast with a check, info or warning icon |
toasts.error(error) | Logs the error, then shows "Something went wrong" with its message |
toasts.error(key, vars?, error, options?) | The same, titled by your key |
toasts.show(options) | A toast from text. Returns a handle |
dialogs.confirm(key, options) | Discord's alert with confirm and Cancel. Resolves true or false |
dialogs.alert(key, options?) | Discord's alert with one OK button. Resolves when closed |
dialogs.showDialog(options) | A dialog from text with your own buttons. Returns a handle with dismiss |
dialogs.dismissAll() | Closes every dialog your plugin opened |
A shorthand's options sets icon (replacing the variant's), duration and id, as in show. Full signatures: toasts and dialogs in the SDK reference.
Typed Keys
Your editor knows each key and its placeholders from en-US.json:
import { toasts } from '@unbound-app/api';
toasts.success('SAVED');
toasts.success('SAVED_N', { count: 3 });
// @ts-expect-error Not one of your keys.
toasts.success('Saved!');
// @ts-expect-error SAVED_N needs { count }.
toasts.success('SAVED_N');
// @ts-expect-error SAVED has no placeholders.
toasts.success('SAVED', { count: 3 });ubd build also reports a literal key that en-US.json lacks:
src/settings.tsx:12:17 'SAVD' is not a key in i18n/en-US.json. Fix: add "SAVD" to i18n/en-US.json, or pass a key it has.Error Toasts
toasts.error logs with your plugin's logger, then shows the error's message as the text. Pass whatever was thrown: an Error, a string or anything else.
import { toasts } from '@unbound-app/api';
declare function sync(): Promise<void>;
try {
await sync();
} catch (error) {
toasts.error('FAILED_TO_SYNC', error);
}With one argument, it is always the error. With a key, the key's vars come next, then the error:
import { toasts } from '@unbound-app/api';
declare const file: { name: string };
declare const error: unknown;
toasts.error('FAILED_TO_SAVE', { name: file.name }, error);Confirm and Alert
Both take the title key first. confirm resolves false on Cancel, a tap outside, or a swipe away. alert resolves however it closes.
| Option | What it does |
|---|---|
titleVars | Title placeholder values. Required when it has placeholders |
body | Key of the text under the title |
bodyVars | Body placeholder values. Required when it has placeholders |
confirm | Confirm button key. For alert, optional, default OK |
cancel | confirm only: Cancel button key, default Cancel |
destructive | confirm only: red confirm button. Use it whenever confirming loses data |
Custom Toasts
toasts.show takes text, for a body, buttons or your own icon.
import { toasts } from '@unbound-app/api';
import { messages } from '@unbound-app/i18n';
toasts.show({ title: messages.COPIED, content: messages.COPIED_LINK, icon: 'LinkIcon' });| Option | What it does |
|---|---|
title, content | The bold first line, and the text under it |
icon | An asset name or id |
duration | Milliseconds before closing. 0 keeps it open. Default: the user's setting |
id | A later toast with the same id replaces this one |
buttons | Each with content and onPress |
show and every shorthand return a handle with update and close, for a toast still open:
import { toasts } from '@unbound-app/api';
import { messages } from '@unbound-app/i18n';
const toast = toasts.show({ title: messages.CHECKING, duration: 0 });
const response = await fetch('https://example.com/latest.json');
toast.update({ title: response.ok ? messages.UP_TO_DATE : messages.CHECK_FAILED });
setTimeout(() => toast.close(), 3000);Custom Dialogs
dialogs.showDialog takes text and any number of buttons. A button closes the dialog, then runs its onPress.
import { dialogs, storage } from '@unbound-app/api';
import { messages } from '@unbound-app/i18n';
const settings = storage.getBucket();
dialogs.showDialog({
title: messages.RESET_TITLE,
body: messages.RESET_BODY,
buttons: [
{ label: messages.RESET_COLORS, onPress: () => settings.remove('colors') },
{ label: messages.RESET_ALL, variant: 'destructive', onPress: () => settings.clear() },
],
cancel: true,
onDismiss: () => logger.info('Closed without choosing'),
});| Option | What it does |
|---|---|
cancel | true adds a last Cancel button. A string sets its label |
onDismiss | Runs when it closes without a button |
content | A component for more than text. Gets a dismiss function |