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

Éléments

Link

Un lien emmène l’utilisateur quelque part : une page web, une autre app (mailto:, tel:) ou un écran de l’app elle-même. Il prend en charge le comportement : les appuis, Entrée et Espace lorsqu’il a le focus clavier, l’état désactivé et le rôle de lien pour les lecteurs d’écran. L’apparence revient à l’app : un Link n’a ni couleur, ni soulignement, ni libellé propre, et ce sont ses enfants qui s’affichent. href indique où il mène ; c’est une donnée destinée à l’ouverture, jamais un texte affiché à l’écran.

el-link.tsx
use nsh_base::{link, theme};
use nsh_core::prelude::*;

fn docs() -> impl IntoElement {
    link()
        .href("https://example.com/docs")
        .text_color(move || theme().primary)
        .underline()
        .hover(|s| s.opacity(0.8))
        .focus(|s| s.rounded_sm().outline(px(2.0)).outline_color(move || theme().ring))
        .child(text("Read the docs"))
}

Link provient de nsh/base, le crate nsh-base en Rust. En Rust, link() en crée un avec un setter par prop (.href(..), .open_with(..)), un écouteur par événement (.on_open(..), .on_press(..)), les méthodes de style typées pour le lien et .child(..) pour son contenu.

#Ouverture

Un appui, un clic, ou Entrée ou Espace sur le lien qui a le focus ouvre son href :

  1. onOpen({ href }) signale où il mène.
  2. Avec openWith="system" (la valeur par défaut), une URL d’une autre app ou d’un autre site, c’est-à-dire avec un schéma (https:, mailto:, tel:, un schéma enregistré par une autre app), s’ouvre en dehors de l’app, comme openUrl l’ouvre : le routeur de l’app hôte la prend d’abord, puis le système. Tout autre href, un chemin de l’app (/orders/42) ou #anchor, est signalé et reste géré par l’app.
  3. onPress() signale l’appui.

Avec openWith="app", c’est le gestionnaire onOpen de l’app qui décide de la façon dont le lien s’ouvre : une route qui lui est propre, une page dans une web view intégrée, une confirmation préalable.

import { Link } from "nsh/base";

<Link href={`/orders/${order.id}`} openWith="app" onOpen={({ href }) => router.push(href)} class="text-primary">
  <Text>Order #{order.id}</Text>
</Link>

L’ouverture d’une URL en dehors de l’app requiert la capability openUrl lorsque l’app déclare ses capabilities dans nsh.json ("openUrl": true ou { "schemes": ["https", "mailto"] }).

#Props

PropRustTypeDéfautDescription
href.href(..)stringaucunOù mène le lien : une URL ou un chemin de l’app. Signalé avec onOpen, jamais affiché.
openWith.open_with(LinkOpenWith::App)"system" | "app" (LinkOpenWith)"system"Qui ouvre href : le système ouvre une URL d’une autre app ou d’un autre site ; "app" en laisse la charge à onOpen.
disabled.disabled(..)booleanfalseAucun appui, aucun retour visuel à l’appui, aucun focus clavier ; les styles disabled: s’appliquent et les lecteurs d’écran indiquent qu’il est grisé.
current.current(..)booleanfalseLe lien vers la page où se trouve l’utilisateur, dans une navigation ou un fil d’Ariane : les lecteurs d’écran indiquent qu’il s’agit de la page courante.
accessibilityLabel.accessibility_label(..)stringaucunCe que disent les lecteurs d’écran, lorsque le contenu en dit trop peu (une icône).
hitSlop.hit_slop(..)number | Partial<Edges>aucunJusqu’où, au-delà de ses limites, les appuis comptent encore, en points : un seul nombre pour tous les côtés, ou les côtés nommés. Comme le hitSlop d’une vue.
children.child(..)JSX.ElementaucunLe contenu : un libellé, une icône, tout ce que l’app affiche.
class, styleméthodes de stylestring, StyleProp<ViewStyle>aucunL’apparence du lien : sa couleur, son soulignement, son padding ; les propriétés de texte sont transmises aux textes qu’il contient.
activeStyle, hoverStyle, focusStyle, disabledStyle.active(|s| ..), .hover(..), .focus(..), .disabled_style(..)StyleProp<ViewStyle>aucunLe style du lien lorsqu’il est pressé, survolé, focalisé ou désactivé, comme les classes <state>:.

#Événements

ÉvénementRustDescription
onOpen.on_open(|href: &SharedString| ..)Le lien ouvre href : avec openWith="app", le gestionnaire l’ouvre ; avec "system", il entend ce que le système a été invité à ouvrir. Il intervient avant onPress.
onPress.on_press(|| ..)Le lien a été pressé : un toucher, un clic, ou Entrée ou Espace lorsqu’il a le focus clavier.

Un lien désactivé ne signale rien, et un appui sur celui-ci n’atteint aucune vue pressable qui l’entoure.

#États

L’app stylise chaque état avec des classes ou des props de style :

<Link
  href="https://example.com/changelog"
  class="self-start text-primary underline decoration-primary/40 transition-colors hover:decoration-primary active:opacity-70 focus:outline-2 focus:outline-ring disabled:text-muted-foreground disabled:no-underline"
>
  <Text>Changelog</Text>
</Link>

Se souvenir d’un lien visité revient à l’app : elle conserve les href qu’elle a ouverts et stylise ces liens selon son propre état.

const visited = signal(new Set<string>());

<Link
  href={href}
  onOpen={({ href }) => visited.set(new Set(visited()).add(href))}
  class={visited().has(href) ? "text-violet-600 underline" : "text-primary underline"}
>
  <Text>{label}</Text>
</Link>

#Dans un texte

Un Link dans un <Text> est une boîte en ligne du paragraphe, comme toute vue placée dans un texte : il s’insère dans la ligne, conserve ses propres états, son focus et son rôle, et reste sur une seule ligne. align-text-bottom place un lien d’une seule ligne de texte sur la ligne de base du paragraphe :

<Text class="text-[15px] text-foreground">
  By continuing you accept the{" "}
  <Link href="https://example.com/terms" class="align-text-bottom">
    <Text class="text-[15px] text-primary underline">terms of service</Text>
  </Link>
  .
</Text>

Un lien qui passe à la ligne avec les lignes du paragraphe est un <Text> imbriqué avec role="link" et onPress (voir Text), comme TextView dessine les liens d’un document.

#Une petite cible avec hitSlop

Un lien peut être plus petit qu’un doigt : une icône, un mot court. hitSlop fait compter les appuis qui tombent près du lien, en points au-delà de chaque côté, sans changer sa mise en page ni son apparence : un seul nombre pour tous les côtés, ou les côtés nommés ({ top: 8, bottom: 8 }), comme le hitSlop d’une vue les accepte.

<Link href="https://example.com/help" hitSlop={12} accessibilityLabel="Help" class="size-5 items-center justify-center">
  <Text>?</Text>
</Link>

#Accessibilité

  • Un lien est un seul élément pour les lecteurs d’écran, avec le rôle "link" ; son libellé est le texte de ses enfants, ou accessibilityLabel. href reste une donnée : les lecteurs d’écran énoncent le libellé.
  • current est énoncé comme la page courante (aria-current="page" d’ARIA), et disabled comme la plateforme énonce un élément grisé.
  • Sur macOS et le web, un lien est un arrêt du focus clavier : Tab l’atteint, Entrée et Espace l’ouvrent, et les styles focus: montrent où se trouve le focus.

Voir Accessibilité pour les libellés, les rôles et les annonces en général.

#Notes par plateforme

  • iOS, Android et Mac Catalyst : un appui est un toucher qui se termine sur le lien.
  • Bureau (macOS, Windows, Linux, GPUI) et web : un appui est un clic. Sur macOS et le web, Entrée et Espace ouvrent aussi le lien qui a le focus clavier.
  • Le web rend un lien sous la forme d’un élément avec role="link".
  • Chaque plateforme dessine ce que l’app stylise.