Éléments
AlertDialog
AlertDialog affiche l’alerte ou la feuille d’actions propre à la plateforme : UIAlertController sur iOS et Mac Catalyst, un
AlertDialog (ou une boîte de dialogue de type liste pour une feuille d’actions) sur Android, et une alerte dans l’apparence de dialogue de la plateforme sur les
autres plateformes. AlertDialog.show (alert_dialog() de .show() en Rust) renvoie une promesse (un future en Rust) qui se résout avec { action } : le id de l’action choisie par l’utilisateur.
Chaque libellé vient de l’application : une alerte dit donc ce que dit votre application, dans sa langue.
import { mount, signal, Text, View } from "nsh";
import { AlertDialog, Button } from "nsh/base";
import { button, buttonText, desktop, focusRing, hoverFill, Inspector, Panel, size, Stage, ui, wide } from "./palette";
type Options = Parameters<typeof AlertDialog.show>[0];
// What each button shows, and what it is about.
const alerts: { label: string; detail: string; danger?: boolean; options: Options }[] = [
{
label: "Delete…",
detail: "cancel + destructive roles",
danger: true,
options: {
title: "Delete the photo?",
description: "This cannot be undone.",
actions: [
{ label: "Cancel", role: "cancel", id: "cancel" },
{ label: "Delete", role: "destructive", id: "delete" },
],
},
},
{
label: "Save changes…",
detail: "three actions, closeOnEscape",
options: {
title: "Save changes?",
description: "Your edits to “Trip notes” are not saved yet.",
actions: [
{ label: "Don't save", role: "destructive", id: "discard" },
{ label: "Cancel", role: "cancel", id: "cancel" },
{ label: "Save", id: "save" },
],
closeOnEscape: true,
},
},
{
label: "Share…",
detail: 'presentation "actionSheet"',
options: {
title: "Share the photo",
presentation: "actionSheet",
actions: [
{ label: "Copy link", id: "copy" },
{ label: "Save", id: "save" },
{ label: "Delete", role: "destructive", id: "delete" },
{ label: "Cancel", role: "cancel", id: "cancel" },
],
},
},
];
function App() {
const answer = signal("–");
const shown = signal(0);
const show = async (options: Options) => {
shown.update((n) => n + 1);
const { action } = await AlertDialog.show(options);
answer.set(action === null ? "{ action: null } (closed without an action)" : `{ action: ${JSON.stringify(action)} }`);
};
const row = () => ({ ...ui().row, borderRadius: 12, padding: 14, gap: 2 });
const hint = desktop ? "Escape or a click outside the action sheet closes it with { action: null }." : "A tap outside the action sheet closes it with { action: null }.";
return (
<View style={{ flex: 1, backgroundColor: ui().page, padding: 20, paddingTop: 24, gap: 12 }}>
<Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>alert-dialog</Text>
<Text style={{ color: ui().muted }}>The platform's own alert; every label comes from the app.</Text>
{() =>
wide() ? (
<View style={{ flex: 1, flexDirection: "row", gap: 16 }}>
{/* A row per alert: what it shows, and a button as wide as its label at the end. */}
<Stage width={400}>
<View style={{ ...ui().card, borderRadius: 14, overflow: "hidden" }}>
<Each of={alerts}>
{(a, i) => (
<>
{i() > 0 ? <View style={{ height: 1, marginLeft: 12, backgroundColor: ui().line }} /> : null}
<View style={{ flexDirection: "row", alignItems: "center", gap: 12, height: size.row + 4, paddingHorizontal: 12 }}>
<Text style={{ flex: 1, fontSize: 13, color: ui().muted }}>{a().detail}</Text>
<Button onPress={() => show(a().options)} {...button()}>
<Text style={{ ...buttonText(), color: a().danger ? ui().down : ui().text }}>{a().label}</Text>
</Button>
</View>
</>
)}
</Each>
</View>
</Stage>
<Inspector>
<Panel title={`AlertDialog.show resolved with (${shown()} shown)`}>
<Text style={{ color: ui().accent, fontSize: 14, fontWeight: "600" }}>{answer()}</Text>
</Panel>
<Text style={{ color: ui().faint, fontSize: 12 }}>{hint}</Text>
</Inspector>
</View>
) : (
<View style={{ gap: 10 }}>
<Each of={alerts}>
{(a) => (
<Button onPress={() => show(a().options)} style={row()} activeStyle={{ opacity: 0.7 }} hoverStyle={hoverFill()} focusStyle={focusRing()}>
<Text style={{ color: a().danger ? ui().down : ui().text, fontSize: 16, fontWeight: "600" }}>{a().label}</Text>
<Text style={{ color: ui().muted, fontSize: 13 }}>{a().detail}</Text>
</Button>
)}
</Each>
<View style={{ ...ui().inset, borderRadius: 12, padding: 14, gap: 4, marginTop: 4 }}>
<Text style={{ color: ui().muted, fontSize: 13 }}>AlertDialog.show resolved with ({shown()} shown)</Text>
<Text style={{ color: ui().accent, fontSize: 16, fontWeight: "600" }}>{answer()}</Text>
</View>
<Text style={{ color: ui().faint, fontSize: 13 }}>{hint}</Text>
</View>
)
}
</View>
);
}
mount(App);use nsh_base::{alert_dialog, button};
use nsh_core::prelude::*;
fn app() -> impl IntoElement {
let answer = signal(SharedString::from("–"));
let confirm = move || {
spawn(async move {
let choice = alert_dialog()
.title("Delete the photo?")
.description("This cannot be undone.")
.cancel("cancel", "Cancel")
.destructive("delete", "Delete")
.show()
.await;
let deleted = matches!(choice, Ok(r) if r.action.as_deref() == Some("delete"));
answer.set(if deleted { "deleted" } else { "kept" }.into());
});
};
view()
.flex_1()
.p_4()
.pt(px(48.0))
.gap_3()
.child(
button()
.on_press(confirm)
.rounded_lg()
.bg(rgb(0xdc2626))
.px_4()
.py_3()
.child(text("Delete…").text_color(white()).font_weight(FontWeight::SEMIBOLD)),
)
.child(text(answer))
}import { mount, signal, Text, View } from "nsh";
import { AlertDialog, Button } from "nsh/base";
function App() {
const answer = signal("–");
const confirm = async () => {
const { action } = await AlertDialog.show({
title: "Delete the photo?",
description: "This cannot be undone.",
actions: [
{ label: "Cancel", role: "cancel", id: "cancel" },
{ label: "Delete", role: "destructive", id: "delete" },
],
});
answer.set(action === "delete" ? "deleted" : "kept");
};
return (
<View style={{ flex: 1, padding: 16, paddingTop: 48, gap: 12 }}>
<Button onPress={confirm} class="rounded-lg bg-red-600 px-4 py-3 active:bg-red-700">
<Text class="text-center font-semibold text-white">Delete…</Text>
</Button>
<Text>{answer()}</Text>
</View>
);
}
mount(App);Pour des dialogues avec une apparence qui vous est propre (une carte, une feuille, un parcours en plein écran), utilisez Dialog.
#AlertDialog.show
AlertDialog.show(options: AlertDialogOptions): Promise<AlertDialogResult>
alert_dialog().title(..).description(..).action(..).cancel(..).destructive(..).show()
-> impl Future<Output = Result<AlertDialogResult, String>>
Le résultat est { action } (AlertDialogResult) : le id de l’action choisie, ou null (None) lorsque le dialogue s’est fermé
sans action : un appui en dehors de celui-ci, Échap ou le bouton retour, là où
closeOnBackdropPress et closeOnEscape le permettent. Sans actions, la promesse est rejetée avec une TypeError (une Err
en Rust). En Rust, nsh_base::alert_dialog() configure le dialogue avec une méthode par option et par action, dans l’ordre
d’affichage des actions, et .show() l’affiche ; attendez sa réponse dans une tâche (spawn).
#Feuilles d’actions
Une feuille d’actions accepte les mêmes options avec la présentation "actionSheet" :
use nsh_base::alert_dialog;
use nsh_core::prelude::*;
fn share() {
spawn(async move {
let choice = alert_dialog()
.title("Share the photo")
.action_sheet()
.action("copy", "Copy link")
.action("save", "Save")
.destructive("delete", "Delete")
.cancel("cancel", "Cancel")
.show()
.await;
match choice.ok().and_then(|r| r.action).as_deref() {
Some("copy") => { /* … */ }
Some("save") => { /* … */ }
Some("delete") => { /* … */ }
_ => {} // "cancel", or closed without an action.
}
});
}const { action } = await AlertDialog.show({
title: "Share the photo",
presentation: "actionSheet",
actions: [
{ label: "Copy link", id: "copy" },
{ label: "Save", id: "save" },
{ label: "Delete", role: "destructive", id: "delete" },
{ label: "Cancel", role: "cancel", id: "cancel" },
],
});#AlertDialogOptions
| Champ | Rust | Type | Par défaut | Description |
|---|---|---|---|---|
title | .title(..) | string | null | aucun | Au-dessus de la description. |
description | .description(..) | string | null | aucun | Sous le titre. |
actions | .action(..), .cancel(..), .destructive(..), une par action | AlertDialogAction[] | obligatoire | Les actions, dans l’ordre (au moins une ; au plus trois dans une alerte Android). |
presentation | .action_sheet() | "alert" | "actionSheet" | "alert" | Une alerte au centre, ou une feuille d’actions depuis le bas (une boîte de dialogue de type liste sur Android). |
closeOnEscape | .close_on_escape(..) | boolean | null | false pour une alerte, true pour une feuille d’actions | Échap et le bouton retour d’Android la ferment sans action. |
closeOnBackdropPress | .close_on_backdrop_press(..) | boolean | null | false pour une alerte, true pour une feuille d’actions | Un appui en dehors la ferme sans action. |
#AlertDialogResult
| Champ | Rust | Type | Description |
|---|---|---|---|
action | action | string | null (Option<SharedString>) | Le id de l’action choisie, ou null lorsque le dialogue s’est fermé sans action. |
#AlertDialogAction
| Champ | Rust | Type | Par défaut | Description |
|---|---|---|---|---|
id | le premier argument de la méthode | string | obligatoire | Ce que show renvoie comme action lorsqu’elle est choisie : le nom que l’application lui donne, qui reste identique quelle que soit la langue des libellés. |
label | le deuxième argument de la méthode | string | obligatoire | Ce qu’elle affiche. |
role | .action(..), .cancel(..), .destructive(..) | "default" | "cancel" | "destructive" | "default" | Ce qu’elle signifie : la plateforme la place et la dessine selon son rôle (une action destructive est rouge sur iOS). |
#Notes par plateforme
- iOS :
UIAlertControllerorganise les actions. Une action avec le rôle"cancel"est placée là où iOS met les actions d’annulation, et une feuille d’actions l’affiche séparément en bas. Sur iPad et Mac Catalyst, la feuille d’actions est une popover, avec une action d’annulation sans titre : un appui en dehors la ferme, etactionvautnull. - Android : un
AlertDialogaffiche jusqu’à trois actions, associées selon leur position : la dernière action est le bouton positif, celle d’avant le bouton négatif, et celle d’avant le bouton neutre. Une feuille d’actions est une liste des actions dans une boîte de dialogue, avec un appui en dehors ou le bouton retour à la place de son action d’annulation (actionvaut alorsnull). La boîte de dialogue de type liste affiche letitle, ou ledescriptionlorsque la feuille n’a pas de titre. - Windows, Linux, GPUI et le web : NSH dessine l’alerte ou la feuille d’actions dans l’apparence de dialogue de la plateforme.