ui: make toasts look more toasty (#2988)

<img width="449" alt="Screenshot 2024-03-11 at 14 03 44"
src="https://github.com/tldraw/tldraw/assets/469604/5b00dafc-abf1-44a3-b6c6-1d16db74b1be">


### Change Type

- [x] `patch` — Bug fix

### Release Notes

- UI: Add severity to toasts.
This commit is contained in:
Mime Čuvalo 2024-03-27 09:41:13 +00:00 committed by GitHub
parent d76d53db95
commit 6def201da2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 167 additions and 11 deletions

View file

@ -16,6 +16,7 @@ export function SneakyOnDropOverride({ isMultiplayer }: { isMultiplayer: boolean
addToast({
title: msg('file-system.shared-document-file-open-error.title'),
description: msg('file-system.shared-document-file-open-error.description'),
severity: 'error',
})
} else {
const shouldOverride = await shouldOverrideDocument(addDialog)

View file

@ -147,6 +147,7 @@ export function useSharing(): TLUiOverrides {
addToast({
title: 'Error',
description: msg('share-menu.upload-failed'),
severity: 'error',
})
}
},
@ -242,6 +243,7 @@ async function getRoomData(
addToast({
title: 'Too big!',
description: msg('share-menu.project-too-large'),
severity: 'warning',
})
trackAnalyticsEvent('shared-fail-too-big', {

View file

@ -44,6 +44,7 @@ export function useFileSystem({ isMultiplayer }: { isMultiplayer: boolean }): TL
addToast({
title: msg('file-system.shared-document-file-open-error.title'),
description: msg('file-system.shared-document-file-open-error.description'),
severity: 'error',
})
return
}

View file

@ -0,0 +1 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.49991 0.877045C3.84222 0.877045 0.877075 3.84219 0.877075 7.49988C0.877075 11.1575 3.84222 14.1227 7.49991 14.1227C11.1576 14.1227 14.1227 11.1575 14.1227 7.49988C14.1227 3.84219 11.1576 0.877045 7.49991 0.877045ZM1.82708 7.49988C1.82708 4.36686 4.36689 1.82704 7.49991 1.82704C10.6329 1.82704 13.1727 4.36686 13.1727 7.49988C13.1727 10.6329 10.6329 13.1727 7.49991 13.1727C4.36689 13.1727 1.82708 10.6329 1.82708 7.49988ZM10.1589 5.53774C10.3178 5.31191 10.2636 5.00001 10.0378 4.84109C9.81194 4.68217 9.50004 4.73642 9.34112 4.96225L6.51977 8.97154L5.35681 7.78706C5.16334 7.59002 4.84677 7.58711 4.64973 7.78058C4.45268 7.97404 4.44978 8.29061 4.64325 8.48765L6.22658 10.1003C6.33054 10.2062 6.47617 10.2604 6.62407 10.2483C6.77197 10.2363 6.90686 10.1591 6.99226 10.0377L10.1589 5.53774Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 973 B

View file

@ -0,0 +1 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.877075 7.49988C0.877075 3.84219 3.84222 0.877045 7.49991 0.877045C11.1576 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1575 0.877075 7.49988ZM7.49991 1.82704C4.36689 1.82704 1.82708 4.36686 1.82708 7.49988C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49988C13.1727 4.36686 10.6329 1.82704 7.49991 1.82704ZM9.85358 5.14644C10.0488 5.3417 10.0488 5.65829 9.85358 5.85355L8.20713 7.49999L9.85358 9.14644C10.0488 9.3417 10.0488 9.65829 9.85358 9.85355C9.65832 10.0488 9.34173 10.0488 9.14647 9.85355L7.50002 8.2071L5.85358 9.85355C5.65832 10.0488 5.34173 10.0488 5.14647 9.85355C4.95121 9.65829 4.95121 9.3417 5.14647 9.14644L6.79292 7.49999L5.14647 5.85355C4.95121 5.65829 4.95121 5.3417 5.14647 5.14644C5.34173 4.95118 5.65832 4.95118 5.85358 5.14644L7.50002 6.79289L9.14647 5.14644C9.34173 4.95118 9.65832 4.95118 9.85358 5.14644Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,4 @@
<!-- MUI, MIT License: https://github.com/mui/material-ui/blob/master/LICENSE -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path>
</svg>

After

Width:  |  Height:  |  Size: 337 B

View file

@ -55,6 +55,7 @@ import iconsAvatar from './icons/icon/avatar.svg'
import iconsBlob from './icons/icon/blob.svg'
import iconsBringForward from './icons/icon/bring-forward.svg'
import iconsBringToFront from './icons/icon/bring-to-front.svg'
import iconsCheckCircle from './icons/icon/check-circle.svg'
import iconsCheck from './icons/icon/check.svg'
import iconsCheckboxChecked from './icons/icon/checkbox-checked.svg'
import iconsCheckboxEmpty from './icons/icon/checkbox-empty.svg'
@ -71,6 +72,7 @@ import iconsCollab from './icons/icon/collab.svg'
import iconsColor from './icons/icon/color.svg'
import iconsComment from './icons/icon/comment.svg'
import iconsCross2 from './icons/icon/cross-2.svg'
import iconsCrossCircle from './icons/icon/cross-circle.svg'
import iconsCross from './icons/icon/cross.svg'
import iconsDashDashed from './icons/icon/dash-dashed.svg'
import iconsDashDotted from './icons/icon/dash-dotted.svg'
@ -85,6 +87,7 @@ import iconsDotsVertical from './icons/icon/dots-vertical.svg'
import iconsDragHandleDots from './icons/icon/drag-handle-dots.svg'
import iconsDuplicate from './icons/icon/duplicate.svg'
import iconsEdit from './icons/icon/edit.svg'
import iconsError from './icons/icon/error.svg'
import iconsExternalLink from './icons/icon/external-link.svg'
import iconsFile from './icons/icon/file.svg'
import iconsFillNone from './icons/icon/fill-none.svg'
@ -271,6 +274,7 @@ export function getAssetUrlsByImport(opts) {
blob: formatAssetUrl(iconsBlob, opts),
'bring-forward': formatAssetUrl(iconsBringForward, opts),
'bring-to-front': formatAssetUrl(iconsBringToFront, opts),
'check-circle': formatAssetUrl(iconsCheckCircle, opts),
check: formatAssetUrl(iconsCheck, opts),
'checkbox-checked': formatAssetUrl(iconsCheckboxChecked, opts),
'checkbox-empty': formatAssetUrl(iconsCheckboxEmpty, opts),
@ -287,6 +291,7 @@ export function getAssetUrlsByImport(opts) {
color: formatAssetUrl(iconsColor, opts),
comment: formatAssetUrl(iconsComment, opts),
'cross-2': formatAssetUrl(iconsCross2, opts),
'cross-circle': formatAssetUrl(iconsCrossCircle, opts),
cross: formatAssetUrl(iconsCross, opts),
'dash-dashed': formatAssetUrl(iconsDashDashed, opts),
'dash-dotted': formatAssetUrl(iconsDashDotted, opts),
@ -301,6 +306,7 @@ export function getAssetUrlsByImport(opts) {
'drag-handle-dots': formatAssetUrl(iconsDragHandleDots, opts),
duplicate: formatAssetUrl(iconsDuplicate, opts),
edit: formatAssetUrl(iconsEdit, opts),
error: formatAssetUrl(iconsError, opts),
'external-link': formatAssetUrl(iconsExternalLink, opts),
file: formatAssetUrl(iconsFile, opts),
'fill-none': formatAssetUrl(iconsFillNone, opts),

View file

@ -55,6 +55,7 @@ import iconsAvatar from './icons/icon/avatar.svg?url'
import iconsBlob from './icons/icon/blob.svg?url'
import iconsBringForward from './icons/icon/bring-forward.svg?url'
import iconsBringToFront from './icons/icon/bring-to-front.svg?url'
import iconsCheckCircle from './icons/icon/check-circle.svg?url'
import iconsCheck from './icons/icon/check.svg?url'
import iconsCheckboxChecked from './icons/icon/checkbox-checked.svg?url'
import iconsCheckboxEmpty from './icons/icon/checkbox-empty.svg?url'
@ -71,6 +72,7 @@ import iconsCollab from './icons/icon/collab.svg?url'
import iconsColor from './icons/icon/color.svg?url'
import iconsComment from './icons/icon/comment.svg?url'
import iconsCross2 from './icons/icon/cross-2.svg?url'
import iconsCrossCircle from './icons/icon/cross-circle.svg?url'
import iconsCross from './icons/icon/cross.svg?url'
import iconsDashDashed from './icons/icon/dash-dashed.svg?url'
import iconsDashDotted from './icons/icon/dash-dotted.svg?url'
@ -85,6 +87,7 @@ import iconsDotsVertical from './icons/icon/dots-vertical.svg?url'
import iconsDragHandleDots from './icons/icon/drag-handle-dots.svg?url'
import iconsDuplicate from './icons/icon/duplicate.svg?url'
import iconsEdit from './icons/icon/edit.svg?url'
import iconsError from './icons/icon/error.svg?url'
import iconsExternalLink from './icons/icon/external-link.svg?url'
import iconsFile from './icons/icon/file.svg?url'
import iconsFillNone from './icons/icon/fill-none.svg?url'
@ -271,6 +274,7 @@ export function getAssetUrlsByImport(opts) {
blob: formatAssetUrl(iconsBlob, opts),
'bring-forward': formatAssetUrl(iconsBringForward, opts),
'bring-to-front': formatAssetUrl(iconsBringToFront, opts),
'check-circle': formatAssetUrl(iconsCheckCircle, opts),
check: formatAssetUrl(iconsCheck, opts),
'checkbox-checked': formatAssetUrl(iconsCheckboxChecked, opts),
'checkbox-empty': formatAssetUrl(iconsCheckboxEmpty, opts),
@ -287,6 +291,7 @@ export function getAssetUrlsByImport(opts) {
color: formatAssetUrl(iconsColor, opts),
comment: formatAssetUrl(iconsComment, opts),
'cross-2': formatAssetUrl(iconsCross2, opts),
'cross-circle': formatAssetUrl(iconsCrossCircle, opts),
cross: formatAssetUrl(iconsCross, opts),
'dash-dashed': formatAssetUrl(iconsDashDashed, opts),
'dash-dotted': formatAssetUrl(iconsDashDotted, opts),
@ -301,6 +306,7 @@ export function getAssetUrlsByImport(opts) {
'drag-handle-dots': formatAssetUrl(iconsDragHandleDots, opts),
duplicate: formatAssetUrl(iconsDuplicate, opts),
edit: formatAssetUrl(iconsEdit, opts),
error: formatAssetUrl(iconsError, opts),
'external-link': formatAssetUrl(iconsExternalLink, opts),
file: formatAssetUrl(iconsFile, opts),
'fill-none': formatAssetUrl(iconsFillNone, opts),

View file

@ -50,6 +50,7 @@ export function getAssetUrls(opts) {
blob: formatAssetUrl('./icons/icon/blob.svg', opts),
'bring-forward': formatAssetUrl('./icons/icon/bring-forward.svg', opts),
'bring-to-front': formatAssetUrl('./icons/icon/bring-to-front.svg', opts),
'check-circle': formatAssetUrl('./icons/icon/check-circle.svg', opts),
check: formatAssetUrl('./icons/icon/check.svg', opts),
'checkbox-checked': formatAssetUrl('./icons/icon/checkbox-checked.svg', opts),
'checkbox-empty': formatAssetUrl('./icons/icon/checkbox-empty.svg', opts),
@ -66,6 +67,7 @@ export function getAssetUrls(opts) {
color: formatAssetUrl('./icons/icon/color.svg', opts),
comment: formatAssetUrl('./icons/icon/comment.svg', opts),
'cross-2': formatAssetUrl('./icons/icon/cross-2.svg', opts),
'cross-circle': formatAssetUrl('./icons/icon/cross-circle.svg', opts),
cross: formatAssetUrl('./icons/icon/cross.svg', opts),
'dash-dashed': formatAssetUrl('./icons/icon/dash-dashed.svg', opts),
'dash-dotted': formatAssetUrl('./icons/icon/dash-dotted.svg', opts),
@ -80,6 +82,7 @@ export function getAssetUrls(opts) {
'drag-handle-dots': formatAssetUrl('./icons/icon/drag-handle-dots.svg', opts),
duplicate: formatAssetUrl('./icons/icon/duplicate.svg', opts),
edit: formatAssetUrl('./icons/icon/edit.svg', opts),
error: formatAssetUrl('./icons/icon/error.svg', opts),
'external-link': formatAssetUrl('./icons/icon/external-link.svg', opts),
file: formatAssetUrl('./icons/icon/file.svg', opts),
'fill-none': formatAssetUrl('./icons/icon/fill-none.svg', opts),

View file

@ -40,6 +40,7 @@ export type AssetUrls = {
blob: string
'bring-forward': string
'bring-to-front': string
'check-circle': string
check: string
'checkbox-checked': string
'checkbox-empty': string
@ -56,6 +57,7 @@ export type AssetUrls = {
color: string
comment: string
'cross-2': string
'cross-circle': string
cross: string
'dash-dashed': string
'dash-dotted': string
@ -70,6 +72,7 @@ export type AssetUrls = {
'drag-handle-dots': string
duplicate: string
edit: string
error: string
'external-link': string
file: string
'fill-none': string

View file

@ -140,6 +140,10 @@ export function getAssetUrlsByMetaUrl(opts) {
new URL('./icons/icon/bring-to-front.svg', import.meta.url).href,
opts
),
'check-circle': formatAssetUrl(
new URL('./icons/icon/check-circle.svg', import.meta.url).href,
opts
),
check: formatAssetUrl(new URL('./icons/icon/check.svg', import.meta.url).href, opts),
'checkbox-checked': formatAssetUrl(
new URL('./icons/icon/checkbox-checked.svg', import.meta.url).href,
@ -186,6 +190,10 @@ export function getAssetUrlsByMetaUrl(opts) {
color: formatAssetUrl(new URL('./icons/icon/color.svg', import.meta.url).href, opts),
comment: formatAssetUrl(new URL('./icons/icon/comment.svg', import.meta.url).href, opts),
'cross-2': formatAssetUrl(new URL('./icons/icon/cross-2.svg', import.meta.url).href, opts),
'cross-circle': formatAssetUrl(
new URL('./icons/icon/cross-circle.svg', import.meta.url).href,
opts
),
cross: formatAssetUrl(new URL('./icons/icon/cross.svg', import.meta.url).href, opts),
'dash-dashed': formatAssetUrl(
new URL('./icons/icon/dash-dashed.svg', import.meta.url).href,
@ -227,6 +235,7 @@ export function getAssetUrlsByMetaUrl(opts) {
),
duplicate: formatAssetUrl(new URL('./icons/icon/duplicate.svg', import.meta.url).href, opts),
edit: formatAssetUrl(new URL('./icons/icon/edit.svg', import.meta.url).href, opts),
error: formatAssetUrl(new URL('./icons/icon/error.svg', import.meta.url).href, opts),
'external-link': formatAssetUrl(
new URL('./icons/icon/external-link.svg', import.meta.url).href,
opts

View file

@ -124,6 +124,10 @@
--color-text-3: hsl(220, 2%, 65%);
--color-text-shadow: hsl(0, 0%, 100%);
--color-primary: hsl(214, 84%, 56%);
--color-success: hsl(123, 46%, 34%);
--color-info: hsl(201, 98%, 41%);
--color-warning: hsl(27, 98%, 47%);
--color-error: hsl(0, 65%, 51%);
--color-warn: hsl(0, 90%, 43%);
--color-text: hsl(0, 0%, 0%);
--color-laser: hsl(0, 100%, 50%);
@ -166,6 +170,10 @@
--color-text-3: hsl(210, 6%, 45%);
--color-text-shadow: hsl(210, 13%, 18%);
--color-primary: hsl(214, 84%, 56%);
--color-success: hsl(123, 38%, 57%);
--color-info: hsl(199, 92%, 56%);
--color-warning: hsl(36, 100%, 57%);
--color-error: hsl(4, 90%, 58%);
--color-warn: hsl(0, 81%, 66%);
--color-text: hsl(210, 17%, 98%);
--color-laser: hsl(0, 100%, 50%);

View file

@ -128,6 +128,9 @@ import { Vec } from '@tldraw/editor';
import { VecLike } from '@tldraw/editor';
import { VecModel } from '@tldraw/editor';
// @public (undocumented)
export type AlertSeverity = 'error' | 'info' | 'success' | 'warning';
// @public (undocumented)
export function AlignMenuItems(): JSX_2.Element;
@ -2134,7 +2137,7 @@ export interface TLUiIconProps extends React.HTMLProps<HTMLDivElement> {
}
// @public (undocumented)
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-cloud' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'status-offline' | 'status-online' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check-circle' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross-circle' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'error' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-cloud' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'status-offline' | 'status-online' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
// @public (undocumented)
export interface TLUiInputProps {
@ -2326,6 +2329,8 @@ export interface TLUiToast {
// (undocumented)
keepOpen?: boolean;
// (undocumented)
severity?: AlertSeverity;
// (undocumented)
title?: string;
}

View file

@ -172,6 +172,32 @@
"name": "",
"preserveMemberOrder": false,
"members": [
{
"kind": "TypeAlias",
"canonicalReference": "tldraw!AlertSeverity:type",
"docComment": "/**\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export type AlertSeverity = "
},
{
"kind": "Content",
"text": "'error' | 'info' | 'success' | 'warning'"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/tldraw/src/lib/ui/context/toasts.tsx",
"releaseTag": "Public",
"name": "AlertSeverity",
"typeTokenRange": {
"startIndex": 1,
"endIndex": 2
}
},
{
"kind": "Function",
"canonicalReference": "tldraw!AlignMenuItems:function(1)",
@ -24086,7 +24112,7 @@
},
{
"kind": "Content",
"text": "'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-cloud' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'status-offline' | 'status-online' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out'"
"text": "'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check-circle' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross-circle' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'error' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-cloud' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'status-offline' | 'status-online' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out'"
},
{
"kind": "Content",
@ -25682,6 +25708,34 @@
"endIndex": 2
}
},
{
"kind": "PropertySignature",
"canonicalReference": "tldraw!TLUiToast#severity:member",
"docComment": "",
"excerptTokens": [
{
"kind": "Content",
"text": "severity?: "
},
{
"kind": "Reference",
"text": "AlertSeverity",
"canonicalReference": "tldraw!AlertSeverity:type"
},
{
"kind": "Content",
"text": ";"
}
],
"isReadonly": false,
"isOptional": true,
"releaseTag": "Public",
"name": "severity",
"propertyTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
}
},
{
"kind": "PropertySignature",
"canonicalReference": "tldraw!TLUiToast#title:member",

View file

@ -76,6 +76,7 @@ export {
} from './lib/ui/context/events'
export {
useToasts,
type AlertSeverity,
type TLUiToast,
type TLUiToastAction,
type TLUiToastsContextType,

View file

@ -128,6 +128,7 @@ export function registerDefaultExternalContentHandlers(
console.error(error)
toasts.addToast({
title: msg('assets.url.failed'),
severity: 'error',
})
meta = { image: '', title: truncateStringWithEllipsis(url, 32), description: '' }
}
@ -250,6 +251,7 @@ export function registerDefaultExternalContentHandlers(
} catch (error) {
toasts.addToast({
title: msg('assets.files.upload-failed'),
severity: 'error',
})
console.error(error)
return null
@ -369,6 +371,7 @@ export function registerDefaultExternalContentHandlers(
} catch (e) {
toasts.addToast({
title: msg('assets.url.failed'),
severity: 'error',
})
return
}

View file

@ -1013,7 +1013,7 @@
}
.tlui-toast__icon {
padding-top: var(--space-4);
padding-top: 11px;
padding-left: var(--space-4);
color: var(--color-text-1);
}
@ -1028,6 +1028,22 @@
font-size: 12px;
}
.tlui-toast__container[data-severity='success'] .tlui-icon {
color: var(--color-success);
}
.tlui-toast__container[data-severity='info'] .tlui-icon {
color: var(--color-info);
}
.tlui-toast__container[data-severity='warning'] .tlui-icon {
color: var(--color-warning);
}
.tlui-toast__container[data-severity='error'] .tlui-icon {
color: var(--color-error);
}
.tlui-toast__main {
flex-grow: 2;
max-width: 280px;
@ -1043,6 +1059,8 @@
.tlui-toast__title {
font-weight: bold;
color: var(--color-text-1);
/* this makes the default toast look better */
line-height: 16px;
}
.tlui-toast__description {

View file

@ -44,9 +44,10 @@ export function DefaultDebugMenuContent() {
onSelect={() => {
addToast({
id: uniqueId(),
title: 'Something happened',
title: 'Something good happened',
description: 'Hey, attend to this thing over here. It might be important!',
keepOpen: true,
severity: 'success',
// icon?: string
// title?: string
// description?: string
@ -57,6 +58,7 @@ export function DefaultDebugMenuContent() {
title: 'Something happened',
description: 'Hey, attend to this thing over here. It might be important!',
keepOpen: true,
severity: 'info',
actions: [
{
label: 'Primary',
@ -87,10 +89,10 @@ export function DefaultDebugMenuContent() {
})
addToast({
id: uniqueId(),
title: 'Something happened',
title: 'Something maybe bad happened',
description: 'Hey, attend to this thing over here. It might be important!',
keepOpen: true,
icon: 'twitter',
severity: 'warning',
actions: [
{
label: 'Primary',
@ -115,6 +117,12 @@ export function DefaultDebugMenuContent() {
},
],
})
addToast({
id: uniqueId(),
title: 'Something bad happened',
severity: 'error',
keepOpen: true,
})
}}
label={untranslated('Show toast')}
/>

View file

@ -1,12 +1,19 @@
import * as T from '@radix-ui/react-toast'
import * as React from 'react'
import { TLUiToast, useToasts } from '../context/toasts'
import { AlertSeverity, TLUiToast, useToasts } from '../context/toasts'
import { useTranslation } from '../hooks/useTranslation/useTranslation'
import { TLUiIconType } from '../icon-types'
import { TldrawUiButton } from './primitives/Button/TldrawUiButton'
import { TldrawUiButtonLabel } from './primitives/Button/TldrawUiButtonLabel'
import { TldrawUiIcon } from './primitives/TldrawUiIcon'
const SEVERITY_TO_ICON: { [msg in AlertSeverity]: TLUiIconType } = {
success: 'check-circle',
warning: 'warning-triangle',
error: 'cross-circle',
info: 'info-circle',
}
function Toast({ toast }: { toast: TLUiToast }) {
const { removeToast } = useToasts()
const msg = useTranslation()
@ -19,15 +26,18 @@ function Toast({ toast }: { toast: TLUiToast }) {
const hasActions = toast.actions && toast.actions.length > 0
const icon = toast.icon || (toast.severity && SEVERITY_TO_ICON[toast.severity])
return (
<T.Root
onOpenChange={onOpenChange}
className="tlui-toast__container"
duration={toast.keepOpen ? Infinity : 5000}
data-severity={toast.severity}
>
{toast.icon && (
{icon && (
<div className="tlui-toast__icon">
<TldrawUiIcon icon={toast.icon as TLUiIconType} />
<TldrawUiIcon icon={icon} />
</div>
)}
<div className="tlui-toast__main">

View file

@ -2,10 +2,14 @@ import { Editor, uniqueId } from '@tldraw/editor'
import { ReactNode, createContext, useCallback, useContext, useState } from 'react'
import { TLUiIconType } from '../icon-types'
/** @public */
export type AlertSeverity = 'success' | 'info' | 'warning' | 'error'
/** @public */
export interface TLUiToast {
id: string
icon?: TLUiIconType
severity?: AlertSeverity
title?: string
description?: string
actions?: TLUiToastAction[]

View file

@ -15,7 +15,7 @@ export function useCopyAs() {
copyAs(editor, ids, format).catch(() => {
addToast({
id: 'copy-fail',
icon: 'warning-triangle',
severity: 'warning',
title: msg('toast.error.copy-fail.title'),
description: msg('toast.error.copy-fail.desc'),
})

View file

@ -12,6 +12,7 @@ export function useEditorEvents() {
addToast({
title: 'Maximum Shapes Reached',
description: `You've reached the maximum number of shapes allowed on ${name} (${count}). Please delete some shapes or move to a different page to continue.`,
severity: 'warning',
})
}

View file

@ -19,9 +19,9 @@ export function useExportAs() {
console.error(e.message)
addToast({
id: 'export-fail',
// icon: 'error',
title: msg('toast.error.export-fail.title'),
description: msg('toast.error.export-fail.desc'),
severity: 'error',
})
})
},

View file

@ -32,6 +32,7 @@ export type TLUiIconType =
| 'blob'
| 'bring-forward'
| 'bring-to-front'
| 'check-circle'
| 'check'
| 'checkbox-checked'
| 'checkbox-empty'
@ -48,6 +49,7 @@ export type TLUiIconType =
| 'color'
| 'comment'
| 'cross-2'
| 'cross-circle'
| 'cross'
| 'dash-dashed'
| 'dash-dotted'
@ -62,6 +64,7 @@ export type TLUiIconType =
| 'drag-handle-dots'
| 'duplicate'
| 'edit'
| 'error'
| 'external-link'
| 'file'
| 'fill-none'
@ -199,6 +202,7 @@ export const iconTypes = [
'blob',
'bring-forward',
'bring-to-front',
'check-circle',
'check',
'checkbox-checked',
'checkbox-empty',
@ -215,6 +219,7 @@ export const iconTypes = [
'color',
'comment',
'cross-2',
'cross-circle',
'cross',
'dash-dashed',
'dash-dotted',
@ -229,6 +234,7 @@ export const iconTypes = [
'drag-handle-dots',
'duplicate',
'edit',
'error',
'external-link',
'file',
'fill-none',

View file

@ -267,6 +267,7 @@ export async function parseAndLoadDocument(
addToast({
title: msg('file-system.file-open-error.title'),
description,
severity: 'error',
})
return