Diese Seite wurde maschinell übersetzt und kann Fehler enthalten. Das englische Original lesen

Elemente

Tooltip

Ein Tooltip ist ein kurzer Hinweis neben dem Element, auf das er sich bezieht: was ein Icon-Button tut oder der vollständige Text eines abgeschnittenen Labels. Auf Desktops und in Desktop-Browsern erscheint er, sobald der Zeiger delay (500 ms) auf seinem Trigger verweilt hat, und verschwindet wieder, wenn der Zeiger den Trigger verlässt oder darauf drückt. Smartphones und Tablets zeigen einen Tooltip nur, wenn die App ihn öffnet (open). Er fängt weder den Zeiger noch Klicks ab, sodass der Trigger genau so funktioniert wie ohne ihn.

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 aus nsh/base wird als Prop tooltip übergeben, die jedes Element hat (Gemeinsame Props), als GPUIs .tooltip(..): Das Element ist das, worauf der Zeiger verweilt und woran der Tooltip ausgerichtet wird. Der Tooltip selbst ist die Sprechblase: Style sie mit class / style, und ihre Kinder sind das, was sie sagt.

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())),
        )
}

Standardmäßig steht er über seinem Trigger (placement), bei zu wenig Platz auf der gegenüberliegenden Seite, und bleibt innerhalb der Safe Area. Mit open entscheidet die App, wann er erscheint. Dazu dient onOpenChange: Es meldet, wenn der Zeiger auf dem Trigger verweilt oder ihn verlässt, und der Tooltip lässt sich auf jedem Gerät anzeigen.

Er erscheint und verschwindet mit den Transitions: startingClass ist sein Aussehen im ersten Frame und endingClass sein Aussehen im ausgeblendeten Zustand, das er beibehält, solange die transition-*-Klassen seines class laufen; danach folgt onClose.

<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

Prop Rust Typ Standard Beschreibung
children .child(..) JSX.Element keiner Was er sagt.
class, style .app_class(..), Styled Methoden string, StyleProp<ViewStyle> keiner Das Aussehen der Sprechblase: der Tooltip selbst.
startingClass, startingStyle .starting_class(..), .starting_style(..) string, StyleProp<ViewStyle> keiner Sein Aussehen im ersten Frame: Seine Transitions laufen von dort aus.
endingClass, endingStyle .ending_class(..), .ending_style(..) string, StyleProp<ViewStyle> keiner Sein Aussehen im ausgeblendeten Zustand: Es bleibt bestehen, solange seine Transitions laufen.
open .open(..) boolean keiner Angezeigt, von der App gesteuert.
defaultOpen .default_open(..) boolean false Anfangs angezeigt, ohne open.
delay .delay(..) number 500 Millisekunden, die der Zeiger auf dem Trigger verweilt, bevor er erscheint; Infinity: nie von selbst, nur wenn die App ihn öffnet.
disabled .disabled(..) boolean false Er wird nie angezeigt.
placement .placement(..) "top" | "bottom" | "left" | "right" "top" Die Seite des Triggers, auf der er steht.
align .align(..) "start" | "center" | "end" "center" Wie er sich entlang dieser Seite am Trigger ausrichtet.
offset .offset(..) number 4 Der Abstand zwischen Trigger und Tooltip.
margin .margin(..) number 4 Der Abstand, den er zu den Rändern der Safe Area einhält.

#Ereignisse

Ereignis Rust Beschreibung
onOpenChange .on_open_change(|e| ..) Der Zeiger verweilt auf dem Trigger, hat ihn verlassen oder darauf gedrückt (reason "hover").
onOpen .on_open(|| ..) Er wird angezeigt.
onClose .on_close(|| ..) Er ist verschwunden, nach seiner Exit-Transition; auch wenn die App ihn ausgeblendet hat.

#Barrierefreiheit

Ein Tooltip wiederholt gegenüber Screenreadern, was sein Trigger aussagt: Gib dem Trigger zusätzlich accessibilityLabel, damit der Hinweis für alle verfügbar ist.