An opinionated toast component for Compose Multiplatform.
This is a Compose implementation of sonner - an excellent toast library by emilkowalski.
Demo
WasmJs Demo
https://dokar3.github.io/compose-sonner/
Video
https://github.com/dokar3/compose-sonner/assets/68095777/ff97c6cc-012e-4152-8c40-0d2ba382c757
Features
- Almost the same as emilkowalski's React implementation: UI, Animations, and even the API.
These include:
- Stacked toasts and expanded toasts
- Different types and rich colors
- Transitions
Roadmaps
Usages
Installation
build.gradle(.kts)
implementation("io.github.dokar3:sonner:<VERSION>")
libs.versions.toml
sonner = { module = "io.github.dokar3:sonner", version = "<VERSION>" }
Basic
val toaster = rememberToasterState()
Button(onClick = { toaster.show("Hello world!") }) {
Text("Show a toast")
}
Toaster(state = toaster)
Types
toaster.show(
message = "Message",
type = ToastType.[Normal | Success | Info | Warning | Error],
)
Dark theme
toaster.show(
message = "Message",
darkTheme = true,
)
Positions
Toaster(
state = toaster,
alignment = Alignment.[TopStart | TopCenter | TopEnd | BottomStart | BottomCener | BottomEnd],
)
Durations
toaster.show(
message = "Message",
duration = [ToasterDefaults.DurationLong | 5000.milliseconds | Duration.INFINITE],
)
Updates
const val TOAST_ID_LOADING = ANYTHING
toaster.show(message = "Loading", id = TOAST_ID_LOADING, duration = Duration.INFINITE)
toaster.show(message = "Success", id = TOAST_ID_LOADING)
Dismiss
toaster.dismiss(id)
toaster.dismiss(toast)
toaster.dismissAll()
Buttons
Toaster(
state = toaster,
showCloseButton = true,
)
toaster.show(
message = "Message",
action = TextToastAction(
text = "Dismiss",
onClick = { toaster.dismiss(it) },
)
)
Icons
Toaster(
state = toaster,
iconSlot = { toast ->
if (toast.icon == ICON_LAODING) {
LoadingIcon()
} else {
ToasterDefaults.iconSlot(toast)
}
},
)
Dismiss pause
Toaster(
state = toaster,
dismissPause = ToastDismissPause.[Never | OnNotFront | OnInvisible],
)
Other
Interact with ViewModel UiState
Define the mapping function
fun UiMessage.toToast(): Toast = when (this) {
is UiMessage.Error -> Toast(id = id, message = message, type = ToastType.Error)
is UiMessage.Success -> Toast(id = id, message = message, type = ToastType.Success)
}
Then
val toaster = rememberToasterState(
onDismissed = { viewModel.removeUiMessageById(it.id as Long) },
)
val uiState by viewModel.uiState.collectAsState()
LaunchedEffect(viewModel, toaster) {
val toastsFlow = viewModel.uiState.map { it.uiMessages.map(UiMessage::toToast) }
toaster.listenMany(toastsFlow)
}
Toaster(state = toaster)
Or use an adapter function
License
Copyright 2024 dokar3
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http:
Unless applicable law agreed to writing, software
distributed under the License distributed an BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
See the License the specific language governing permissions
limitations under the License.