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

Éléments

Tooltip

Un tooltip est une courte indication placée à côté de l’élément qu’elle concerne : ce que fait un bouton à icône, le texte complet d’un libellé tronqué. Sur les ordinateurs de bureau et dans les navigateurs de bureau, il s’affiche une fois que le pointeur est resté sur son déclencheur pendant delay (500 ms), et se masque quand le pointeur le quitte ou appuie sur le déclencheur. Les téléphones et les tablettes n’affichent un tooltip que lorsque l’application l’ouvre (open). Il ne capte jamais le pointeur ni les appuis, de sorte que le déclencheur fonctionne exactement comme sans lui.

el-tooltip.tsx
el-tooltip.tsxLive
import { mount, signal, Text, View } from "nsh";
import { type OpenChangeReason, Tooltip } from "nsh/base";
import { button, buttonText, createPresence, desktop, Inspector, Log, Panel, Stage, ui, wide } from "./palette";

/** An icon button with a hint of the app's look, above or below it. */
function Tool(props: {
  icon: string;
  label: string;
  hint: string;
  placement: "top" | "bottom";
  pinned: boolean;
  onPress: () => void;
  onOpenChange: (e: { open: boolean; reason: OpenChangeReason }) => void;
}) {
  const hovered = signal(false);
  // The bubble stays made between showings: it comes in from its side as it shows.
  const presence = createPresence(props.placement);
  return (
    <View style={{ alignItems: "center", gap: 6 }}>
      <View
        onPress={props.onPress}
        accessibilityLabel={props.label}
        {...button("secondary", { align: "center", style: { width: desktop ? 36 : 52, height: desktop ? 36 : 52, paddingHorizontal: 0 } })}
        tooltip={
          <Tooltip
            open={props.pinned || hovered()}
            placement={props.placement}
            offset={8}
            margin={8}
            delay={400}
            onOpenChange={(e) => {
              hovered.set(e.open);
              props.onOpenChange(e);
            }}
            onOpen={presence.show}
            onClose={presence.hide}
          >
            <View style={{ backgroundColor: ui().text, borderRadius: 7, paddingHorizontal: 10, paddingVertical: 6, ...presence.style }}>
              <Text style={{ fontSize: 13, color: ui().page }}>{props.hint}</Text>
            </View>
          </Tooltip>
        }
      >
        <Text style={{ fontSize: desktop ? 17 : 22, color: ui().text }}>{props.icon}</Text>
      </View>
      <Text style={{ fontSize: 11, color: ui().faint }}>{props.placement}</Text>
    </View>
  );
}

function App() {
  const events = signal<string[]>([]);
  const pressed = signal("—");
  const pinned = signal(false);
  const log = (name: string) => ({ open, reason }: { open: boolean; reason: OpenChangeReason }) =>
    events.set([`${name} ${open ? "shown" : "hidden"} · ${reason}`, ...events()].slice(0, 6));
  const tools = () => (
    <>
      <Tool icon="★" label="Star" hint="Add to favorites" placement="top" pinned={pinned()} onPress={() => pressed.set("Star")} onOpenChange={log("Star")} />
      <Tool icon="↗" label="Share" hint="Share with your team" placement="bottom" pinned={pinned()} onPress={() => pressed.set("Share")} onOpenChange={log("Share")} />
      <Tool icon="✕" label="Delete" hint="Move to the trash" placement="top" pinned={pinned()} onPress={() => pressed.set("Delete")} onOpenChange={log("Delete")} />
    </>
  );
  // The `tooltip` prop of any element: a `Tooltip` with the app's look.
  const pin = () => (
    <View
      tooltip={
        <Tooltip style={{ backgroundColor: ui().text, borderRadius: 7, paddingHorizontal: 10, paddingVertical: 6 }}>
          <Text style={{ fontSize: 13, color: ui().page }}>Shows every tooltip without a pointer</Text>
        </Tooltip>
      }
      onPress={() => pinned.set(!pinned())}
      {...button("secondary", { align: "center", style: wide() ? {} : { flex: 1 } })}
    >
      <Text style={buttonText()}>
        {wide() ? (pinned() ? "Unpin the tooltips" : "Pin the tooltips") : pinned() ? "Unpin" : "Pin"}
      </Text>
    </View>
  );
  const onPress = () => (
    <Panel title="onPress">
      <Text style={{ fontSize: 13, color: ui().text }}>{pressed()}</Text>
    </Panel>
  );
  const changes = () => <Log title="onOpenChange({ open, reason })" lines={events()} minHeight={130} />;

  return (
    <View style={{ flex: 1, backgroundColor: ui().page, padding: 20, paddingTop: 24, gap: 14 }}>
      <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>tooltip</Text>
      <Text style={{ color: ui().muted }}>
        {desktop ? "Rest the pointer on a button; a click still presses it" : "Tooltips follow a pointer: pin them to see them here"}
      </Text>

      {() =>
        wide() ? (
          <View style={{ flex: 1, flexDirection: "row", gap: 16 }}>
            <Stage gap={40}>
              <View style={{ flexDirection: "row", justifyContent: "center", gap: 64 }}>{tools()}</View>
              {pin()}
            </Stage>
            <Inspector>
              {onPress()}
              {changes()}
            </Inspector>
          </View>
        ) : (
          <>
            <View style={{ flex: 1, minHeight: 200, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 28 }}>{tools()}</View>
            <View style={{ flexDirection: "row", gap: 8 }}>{pin()}</View>
            {onPress()}
            {changes()}
          </>
        )
      }
    </View>
  );
}

mount(App);

Tooltip de nsh/base se transmet via la prop tooltip que possède chaque élément (Props communes), comme le .tooltip(..) de GPUI : l’élément est ce sur quoi le pointeur s’arrête et ce contre quoi le tooltip est placé. Le tooltip lui-même est la bulle : stylez-la avec class / style, et ses enfants constituent ce qu’elle dit.

use nsh_base::tooltip;
use nsh_core::prelude::*;

fn save_button(on_save: impl Fn() + 'static) -> impl IntoElement {
    view()
        .on_press(on_save)
        .accessibility_label("Save")
        .p_2()
        .child(text("💾"))
        .tooltip(
            tooltip()
                .placement(Placement::Bottom)
                .rounded_md()
                .bg(rgb(0x111827))
                .px_2()
                .py_1()
                .child(text("Save the document").text_color(white())),
        )
}

Par défaut, il se place au-dessus de son déclencheur (placement), de l’autre côté s’il n’y a pas assez de place, et reste dans la zone de sécurité. Avec open, c’est l’application qui décide quand il s’affiche : il suit onOpenChange, qui signale que le pointeur s’est arrêté sur le déclencheur ou l’a quitté, et il peut s’afficher sur n’importe quel appareil.

Il apparaît et disparaît avec vos transitions : startingClass est son apparence dans sa première image et endingClass son apparence une fois masqué, qu’il conserve pendant l’exécution des classes transition-* de son class ; onClose suit.

<Tooltip
  class="rounded-md bg-gray-900 px-2 py-1 transition-opacity duration-100"
  startingClass="opacity-0"
  endingClass="opacity-0"
>
  <Text class="text-white">Save the document</Text>
</Tooltip>

#Props

PropRustTypeDéfautDescription
children.child(..)JSX.ElementaucunCe qu’il dit.
class, styleméthodes .app_class(..), Styledstring, StyleProp<ViewStyle>aucunL’apparence de la bulle : le tooltip lui-même.
startingClass, startingStyle.starting_class(..), .starting_style(..)string, StyleProp<ViewStyle>aucunSon apparence dans sa première image : ses transitions partent de là.
endingClass, endingStyle.ending_class(..), .ending_style(..)string, StyleProp<ViewStyle>aucunSon apparence une fois masqué : il la conserve pendant l’exécution de ses transitions.
open.open(..)booleanaucunAffiché, contrôlé par l’application.
defaultOpen.default_open(..)booleanfalseAffiché au départ, sans open.
delay.delay(..)number500Millisecondes pendant lesquelles le pointeur reste sur le déclencheur avant l’affichage ; Infinity : jamais de lui-même, uniquement quand l’application l’ouvre.
disabled.disabled(..)booleanfalseIl ne s’affiche jamais.
placement.placement(..)"top" | "bottom" | "left" | "right""top"Le côté du déclencheur où il se place.
align.align(..)"start" | "center" | "end""center"Son alignement sur le déclencheur le long de ce côté.
offset.offset(..)number4L’écart entre le déclencheur et le tooltip.
margin.margin(..)number4La distance qu’il conserve par rapport aux bords de la zone de sécurité.

#Événements

ÉvénementRustDescription
onOpenChange.on_open_change(|e| ..)Le pointeur s’est arrêté sur le déclencheur, l’a quitté ou a appuyé dessus (reason "hover").
onOpen.on_open(|| ..)Il est affiché.
onClose.on_close(|| ..)Il a disparu, après sa sortie ; également lorsque l’application l’a masqué.

#Accessibilité

Un tooltip répète aux lecteurs d’écran ce que dit son déclencheur : donnez aussi un accessibilityLabel au déclencheur, afin que l’indication soit disponible pour tout le monde.