Cette page a été traduite automatiquement et peut contenir des erreurs. Lire l'original en anglais

É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.

el-alert-dialog.tsx
el-alert-dialog.tsxLive
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))
}

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.
        }
    });
}

#AlertDialogOptions

ChampRustTypePar défautDescription
title.title(..)string | nullaucunAu-dessus de la description.
description.description(..)string | nullaucunSous le titre.
actions.action(..), .cancel(..), .destructive(..), une par actionAlertDialogAction[]obligatoireLes 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 | nullfalse 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 | nullfalse pour une alerte, true pour une feuille d’actionsUn appui en dehors la ferme sans action.

#AlertDialogResult

ChampRustTypeDescription
actionactionstring | null (Option<SharedString>)Le id de l’action choisie, ou null lorsque le dialogue s’est fermé sans action.

#AlertDialogAction

ChampRustTypePar défautDescription
idle premier argument de la méthodestringobligatoireCe 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.
labelle deuxième argument de la méthodestringobligatoireCe 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 : UIAlertController organise 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, et action vaut null.
  • Android : un AlertDialog affiche 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 (action vaut alors null). La boîte de dialogue de type liste affiche le title, ou le description lorsque 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.