Esta página se tradujo automáticamente y puede contener errores. Leer el original en inglés

Elementos

Elementos

Native Shell construye cada pantalla a partir de un pequeño conjunto de elementos: primitivas como View, Text y Image, y componentes base como Button, Dialog y NavStack. Cada primitiva es una vista nativa (una subclase de UIView en iOS y Mac Catalyst, un View de Android, una vista de AppKit, GTK o Win32 en los escritorios), creada y maquetada por el runtime de NSH. Todo lo que muestra una app está hecho con ellos: los botones, tarjetas, filas y pantallas de una app son sus propios componentes, dibujados con estos elementos y con el estilo que les da la app, de modo que su aspecto es enteramente suyo.

Cada ejemplo de estas páginas viene en Rust y TSX: elige una pestaña y todos los ejemplos de la página la siguen.

use nsh_core::prelude::*;

fn app() -> impl IntoElement {
    let count = signal(0_u32);
    view()
        .flex_1()
        .items_center()
        .justify_center()
        .gap_3()
        .child(text(move || format!("Tapped {} times", count.get())).text_2xl())
        .child(
            view()
                .rounded_lg()
                .bg(rgb(0x2563eb))
                .px_4()
                .py_2()
                .active(|s| s.opacity(0.6))
                .on_press(move || count.update(|n| *n += 1))
                .child(text("Tap").text_color(white())),
        )
}

En Rust, las primitivas son funciones de nsh_core::prelude (view(), text(..), image(..)) y los componentes base provienen del crate nsh_base. Los estilos son métodos tipados (.flex_1(), .gap_3(), .px(px(20.0)), .bg(..)), los estilos de estado reciben un closure (.active(|s| s.opacity(0.6))), los listeners son closures de su evento (.on_press(move || ..), .on_change(move |text: &str| ..)) y .child(..) añade hijos. Un fragmento de UI es una función simple que devuelve impl IntoElement; se ejecuta una sola vez, y los signals que lee dentro de closures (text(move || ..), .bg(move || ..)) actualizan aquello a lo que están enlazados. Consulta Building with Rust.

En TSX, cada etiqueta va en PascalCase y nombra un binding en el ámbito: las primitivas provienen de nsh y los componentes base de nsh/base. Solo <If> y <Each> son globales que no necesitan importación. Una etiqueta en minúsculas como <view> es un error de compilación, porque TypeScript la comprobaría contra un tipo global por nombre, y componentes genéricos como List y Each no podrían inferir el tipo de sus elementos. El compilador reconoce los elementos por sus importaciones y crea las vistas nativas en el sitio, así que importarlos no cuesta nada en tiempo de ejecución. Consulta JSX and components.

import { Canvas, Image, List, Overlay, Scroll, Shader, Text, Video, View, WebView } from "nsh";
import { Button, Dialog, Menu, NavPage, NavStack, Popover, Sheet, Tooltip, Input } from "nsh/base";

#Primitivas

Se importan de nsh en TSX y de nsh_core::prelude en Rust.

Elemento Rust Vista nativa (iOS / Android) Página
<View> view() UIView / ViewGroup; con selectable, los textos que contiene se seleccionan juntos View, Text selection
<Text> text(content) vista CoreText / vista StaticLayout Text
<Image> image(src) una vista con una capa de imagen / una vista de imagen Image
<Scroll> scroll() UIScrollView / ScrollView Scroll
<List> virtual_list(count, |at| row) UIScrollView / ScrollView con celdas recicladas List
<Canvas> canvas(painter) una vista que reproduce un dibujo 2D Canvas
<Shader> shader(program) una vista cuya caja dibuja en la GPU un programa WGSL, debajo de sus hijos Shader
<WebView> web_view(url), web_view_html(html, base) WKWebView / android.webkit.WebView WebView
<Video> video(url) AVPlayerLayer / MediaPlayer sobre un TextureView Video
<Overlay> overlay() una vista sobre la ventana (o el diálogo en el que está), colocada respecto a un ancla Overlay
<If>, <Each> when(..), each(..), dynamic(..) control de flujo: los elementos que eligen Control flow
<InputAccessoryView> (nsh/mobile) input_accessory_view(id) una barra sobre el teclado en iOS InputAccessoryView

El padding y el margin mantienen el contenido alejado de la interfaz del sistema con el env() de CSS: env(safe-area-inset-top) y los demás bordes (Safe area) y env(keyboard-inset-height) (Keyboard).

#Base

Se importan de nsh/base en TSX y del crate nsh_base en Rust. Poseen el comportamiento, el estado, el foco y la accesibilidad, y toman su aspecto de la app.

Componente Rust Qué hace Página
AlertDialog nsh_base::alert_dialog() La alerta y la hoja de acciones del sistema AlertDialog
<Accordion> y sus partes nsh_base::accordion(), accordion_item(), … Secciones apiladas que se expanden y se contraen bajo sus encabezados, de una en una o varias a la vez Accordion
<Avatar>, <AvatarGroup> nsh_base::avatar(), avatar_group() La imagen de una persona, o un sustituto mientras carga o si falla, y una fila de ellas que muestra las primeras Avatar
<Button> nsh_base::button() Un control pulsable con sus estados y su rol Button
<Carousel> y sus partes nsh_base::carousel(), carousel_content(), … Diapositivas mostradas de una en una, con deslizamiento nativo, anterior / siguiente, una paginación, las teclas y un bucle continuo Carousel
<Checkbox> nsh_base::checkbox() Un control marcado, desmarcado o indeterminado con un indicador Checkbox
<Collapsible> nsh_base::collapsible() Una región cuyo contenido se expande y se contrae Collapsible
<Command> nsh_base::command() Una paleta de comandos: un campo de búsqueda sobre comandos filtrados de forma nativa, una lista virtualizada y las teclas de una paleta Cmd+K Command
<DataTable> nsh_base::data_table() Una tabla de filas y columnas en cualquier cantidad, seleccionable, ordenable, con columnas redimensionables y movibles DataTable
<Dialog> nsh_base::dialog() Presenta a sus hijos por encima de todo lo demás Dialog
<DiffView> nsh_base::diff_view() Los cambios entre dos textos o de un parche, en vista dividida o unificada DiffView
<DockArea> nsh_base::dock_area() Un espacio de trabajo de divisiones, grupos de pestañas y docks en los bordes que el usuario organiza Dock
<Editor> nsh_base::editor() Un editor de código con resaltado, varios cursores, plegado y búsqueda Editor
<HoverCard> nsh_base::hover_card() Una vista previa de aquello a lo que apunta su trigger, mientras el puntero reposa sobre él HoverCard
<Input> nsh_base::input() El campo de texto nativo (UITextField o UITextView / EditText) Input
<Link> nsh_base::link() Un objetivo de pulsación que abre una página, un sitio o una ruta de la app Link
<Menu>, <ContextMenu>, <MenuItem>, <MenuSeparator>, <Submenu> nsh_base::menu(), … Menús: popups con submenús en cascada en los escritorios, hojas en los teléfonos Menu
<NavStack>, <NavPage> nsh_base::nav_stack(), nsh_base::nav_page() Navegación nativa: una pila de páginas con el encabezado y los gestos de retroceso de la plataforma NavStack
<NumberInput> nsh_base::number_input() Un número escrito en un campo o ajustado con botones y teclas NumberInput
<OtpInput> nsh_base::otp_input() Un código de un solo uso con un número fijo de dígitos, escrito, pegado o autocompletado en celdas OtpInput
<Pagination> nsh_base::pagination() Las páginas de un conjunto: Anterior, las páginas alrededor de la actual, puntos suspensivos y Siguiente Pagination
<Tree> nsh_base::tree() Elementos que contienen elementos, expandidos y contraídos, con uno seleccionado: virtualizado, una sola parada del foco del teclado Tree
<Plot>, <Line>, <Area>, <Bar>, <Grid>, <Pie>, <Arc> (nsh/base/plot) nsh_base::plot::{plot, line, area, bar, grid, pie, arc} El marco de un gráfico y sus marcas, dibujados de forma nativa a partir de las filas de la app Plot
<Popover> nsh_base::popover() Contenido anclado a un trigger, por encima de todo Popover
<Progress> nsh_base::progress() Una barra de progreso: cuánto avanzó una tarea, o que está en curso Progress
<Radio>, <RadioGroup> nsh_base::radio(), radio_group() Una opción de un conjunto del que el usuario elige una, y el conjunto Radio
<ResizablePanelGroup>, <ResizablePanel> nsh_base::h_resizable(), resizable_panel() Paneles uno junto a otro o apilados, con tiradores que los redimensionan Resizable
<Scrollbar> nsh_base::scrollbar() Una barra de desplazamiento con el aspecto propio de la app para una vista de scroll o una lista Scrollbar
<Select> nsh_base::select() Un valor elegido de una lista de elementos, con teclado, búsqueda y secciones Select
<Sheet> nsh_base::sheet() Un panel en un borde de la pantalla sobre un fondo Sheet
<Slider> nsh_base::slider() Un valor, o un rango de dos, elegido a lo largo de una pista Slider
<Switch> nsh_base::switch() Un control de activado / desactivado con una pista y un pulgar Switch
<Table> y sus partes nsh_base::table(), table_row(), … Una tabla con las filas y celdas propias de la app, con los roles de una tabla Table
<Tab>, <Tabs> nsh_base::tab(), tabs() Una pestaña de una lista de pestañas, y la lista Tabs
<TextView> nsh_base::text_view() Muestra un documento Markdown o HTML con textos y vistas TextView
<Toast>, <ToastStack> nsh_base::toast(), toast_stack() La raíz semántica de un toast; toasts dispuestos como capas desde un borde Toast
<Toggle>, <ToggleGroup> nsh_base::toggle(), toggle_group() Un botón que está activado o desactivado, y una barra de herramientas de ellos Toggle
<Toolbar>, <ToolbarGroup>, <ToolbarSeparator> nsh_base::toolbar(), toolbar_group(), toolbar_separator() Una barra de botones, toggles y enlaces, una sola parada del foco del teclado Toolbar
<Tooltip> nsh_base::tooltip() Una pista junto a su trigger, al pasar el puntero o al mantener el dedo Tooltip

#Props comunes

Toda primitiva acepta las props siguientes (el tipo CommonProps en TSX; los traits Styled, Interactive y Accessible en Rust). Las páginas de cada elemento solo enumeran sus propias props. La columna Rust nombra el método del builder.

#Estilos

Prop Rust Tipo Descripción
style métodos Styled tipados; .inline_style(style) StyleProp<ViewStyle> (TextStyle para <Text> y <Input>, ImageStyle para <Image>) Estilo en línea, o un array de estilos combinados de izquierda a derecha (se omiten las entradas falsy; los arrays pueden anidarse, por lo que style={[base, props.style]} acepta un props.style que a su vez sea un array). Prevalece sobre class. Consulta la referencia de estilos.
class métodos Styled tipados (.flex_row().gap_2().p_4()) string Clases de Tailwind, resueltas de forma nativa ("flex-row gap-2 p-4 dark:bg-zinc-900"). Las clases posteriores prevalecen sobre las anteriores. Consulta Tailwind.
classList .style_when(when, |s| ..) Record<string, boolean | null | undefined> Clases aplicadas mientras su valor sea truthy ({ "opacity-50": busy() }).
disabled .disabled(..) boolean Ignora las pulsaciones (tampoco da respuesta visual de pulsación), aplica los estilos disabled:, deshabilita controles como los inputs, y los lectores de pantalla indican que está deshabilitado (accessibilityState.disabled).

#Pulsaciones y respuesta visual

El manejo de las pulsaciones se ejecuta de forma nativa: la plataforma reconoce la pulsación y aplica los estilos de pulsación de la app, y el código de la app solo se entera después. Solo responde la vista pulsable más interna; dentro de las vistas de scroll, el inicio de una pulsación espera unos 130 ms para que un desplazamiento pueda comenzar primero.

Prop Rust Tipo Valor por defecto Descripción
onPress .on_press(..) (e: PressEvent) => void Un toque terminó dentro de la vista.
onLongPress .on_long_press(..) (e: PressEvent) => void El dedo permaneció apoyado durante delayLongPress.
onPressDown .on_press_down(..) (e: PressEvent) => void Un dedo se apoyó sobre la vista.
onPressUp .on_press_up(..) (e: PressEvent) => void El dedo se levantó o salió.
delayLongPress .long_press_delay(ms) number 500 Milisegundos antes de que una pulsación se convierta en pulsación larga.
hitSlop .hit_slop(EdgeInsets::all(px(8.0))) number | Partial<Edges> Amplía el área táctil más allá de los límites, en puntos.

PressEvent es { position, pagePosition, modifiers, clickCount }: dónde estaba el puntero en la vista y en su vista raíz (Points), las teclas modificadoras mantenidas cuando comenzó la pulsación y los clics consecutivos (2 para un doble clic). Cuando la plataforma no informa de ningún puntero, es el origen de la vista, sin teclas y con un clic.

La clave de estilo pointerEvents (.pointer_events(PointerEvents::BoxNone) en Rust, las clases pointer-events-*) decide qué toques reciben la vista y las vistas que contiene: "none" ninguna de las dos (una vista interior que establezca "auto" vuelve a recibirlos), "box-none" solo las vistas que contiene, "box-only" solo la propia vista (touch and gestures).

La respuesta visual de la pulsación es de la app: activeStyle (o las clases active:, .active(..) en Rust) se aplica mientras la vista está pulsada, de forma nativa, sin ida y vuelta al código de la app (más abajo).

#Estilos de estado

Estilos que se aplican mientras la vista está en un estado, sobre sus propios estilos, de forma nativa. Cada uno es la forma de objeto de una variante de Tailwind. Los estados posteriores prevalecen (selected, checked e indeterminate, luego hover, focus, active); disabledStyle prevalece sobre todos, y los demás no se aplican mientras la vista está deshabilitada. Cada uno recibe el estilo propio del elemento: un TextStyle en un <Text>, un InputStyle en un <Input>, un ImageStyle en un <Image>, un ViewStyle en cualquier otro.

Prop Rust Variante de clase Se aplica
activeStyle .active(|s| ..) active: Mientras está pulsada.
hoverStyle .hover(|s| ..) hover: Mientras un puntero está sobre la vista.
focusStyle .focus(|s| ..) focus: Mientras la vista tiene el foco.
focusWithinStyle .focus_within(|s| ..) focus-within: Mientras la vista o una vista dentro de ella tiene el foco (el contenido de un Overlay cuenta como dentro de la vista en la que está).
disabledStyle .disabled_style(|s| ..) disabled: Mientras disabled.
checkedStyle .checked(|s| ..), .checked_style(style) checked: Mientras accessibilityState.checked es true (un checkbox, un switch, un radio; "mixed" no está marcado).
indeterminateStyle .indeterminate(|s| ..), .indeterminate_style(style) indeterminate: Mientras accessibilityState.checked es "mixed" (un checkbox que no está ni marcado ni desmarcado).
selectedStyle .selected(|s| ..) selected: Mientras accessibilityState.selected es true (un Button seleccionado, una pestaña).
expandedStyle .expanded(|s| ..), .expanded_style(style) aria-expanded: Mientras accessibilityState.expanded es true (el trigger de un Popover o de un Menu mientras su popup está abierto).
pressedStyle .aria_pressed(|s| ..), .pressed_style(style) aria-pressed: Mientras accessibilityState.pressed es true (un botón toggle que está activado; "mixed" no está pulsado). No es activeStyle, una pulsación en curso.
view()
    .rounded_lg()
    .bg(rgb(0x2563eb))
    .px_4()
    .py_2()
    .active(|s| s.opacity(0.6))
    .hover(|s| s.bg(rgb(0x1d4ed8)))
    .on_press(save)
    .child(text("Save").text_color(white()))

#Hover

La app detecta cuándo el mouse entra en una vista, se mueve sobre ella y la abandona: en macOS, Windows, Linux, el backend de GPUI y en navegadores de escritorio, con el puntero de un iPad o el mouse de un Mac en iOS, y con un mouse o un lápiz en Android. Los estilos de hover (hover:, .hover(..)) dan estilo a las vistas bajo el cursor en esos mismos lugares.

Prop Rust Tipo Descripción
onMouseEnter .on_mouse_enter(..) (e: MouseEvent) => void El mouse entró en la vista o en una vista dentro de ella (el mouseenter del DOM).
onMouseMove .on_mouse_move(..) (e: MouseEvent) => void El mouse se movió sobre la vista (o sobre una vista dentro de ella), con o sin un botón presionado, o se presionó o soltó una tecla modificadora mientras el mouse reposa allí sin ningún botón presionado (el mousemove del DOM).
onMouseLeave .on_mouse_leave(..) (e: MouseEvent) => void El mouse salió de la vista y de las vistas dentro de ella, o de la ventana; e es donde estuvo por última vez (el mouseleave del DOM).

Como :hover en CSS y mouseenter en el DOM, una vista cuenta como en hover mientras el mouse está sobre ella o sobre cualquier elemento dentro de ella, de modo que las vistas que rodean a la que está bajo el mouse también reciben onMouseEnter (de afuera hacia adentro; onMouseLeave de adentro hacia afuera). Los eventos llegan después de ocurrir el hecho y nunca con toques. Una vista que se elimina de debajo del mouse recibe onMouseLeave, en Linux y Windows en el siguiente movimiento del mouse.

MouseEvent indica dónde está el mouse, como lo hace MouseMoveEvent de GPUI: position en la vista (un Point en puntos, con sus transformaciones deshechas), pagePosition en la vista raíz que la contiene, como lo dan los toques, los modifiers presionados (control, alt, shift, platform: Command en las plataformas de Apple, la tecla Windows en las demás), y pressedButton, el botón presionado ("left", "right", "middle", "back" o "forward", el MouseButton de GPUI) o null; en Rust position, page_position, modifiers y pressed_button. En los escritorios y en la web, un arrastre también es un toque (onTouchMove, el responder), y sus movimientos llegan a onMouseMove con pressedButton activado: el feedback que solo sigue al hover los omite; en iOS y Android el hover informa del puntero sin ningún botón presionado. Los movimientos llegan como máximo una vez por fotograma, el más reciente, y siempre antes del onMouseLeave que los sigue, de modo que un manejador puede redibujar en cada movimiento:

// A crosshair over a chart.
let at = signal(None::<Points>);

view()
    .h(px(200.0))
    .on_mouse_move(move |e: &MouseEvent| at.set(Some(e.position.x)))
    .on_mouse_leave(move |_: &MouseEvent| at.set(None))
    .child(when(move || at.get().is_some(), move || {
        view()
            .absolute()
            .left(move || at.get().unwrap_or_default())
            .top_0()
            .bottom_0()
            .w(px(1.0))
            .bg(rgb(0x888888))
    }))

#Tooltips

tooltip da una pista a cualquier elemento, que se muestra encima de él en los escritorios (macOS, Windows, Linux, el backend de GPUI y navegadores de escritorio) cuando el puntero ha reposado sobre él durante medio segundo, hasta que el puntero sale o lo presiona. Los teléfonos y las tabletas no muestran ninguna. La pista nunca captura el puntero ni las pulsaciones, así que el elemento funciona exactamente igual que sin ella.

Prop Rust Tipo Descripción
tooltip .tooltip(..) JSX.Element La pista, un elemento al que la app da estilo: un Tooltip de nsh/base es el propio tooltip, con su ubicación, retardo y eventos; cualquier otro elemento se muestra tal cual.
view()
    .on_press(save)
    .tooltip(
        tooltip()
            .rounded_md()
            .bg(rgb(0x111827))
            .px_2()
            .py_1()
            .child(text("Save the document").text_color(white())),
    )
    .child(text("💾"))

El Tooltip define su propio aspecto, ubicación, retardo y eventos, como lo hace el .tooltip(..) de GPUI. Una app con muchos tooltips mantiene un pequeño componente propio que envuelve un texto en su Tooltip.

#Menús contextuales

onContextMenu indica a una vista que se presionó el botón secundario sobre ella: un clic derecho, Control-clic en macOS, un clic con dos dedos en un touchpad, el clic secundario del puntero de un iPad; en navegadores también la tecla de menú del teclado. Abre ahí el menú propio de la app; en TSX, Menu.popup muestra el del sistema:

// The app's own menu, placed where the click was.
let menu_at = signal(None::<Point<Points>>);

view()
    .on_context_menu(move |e: &ContextMenuEvent| menu_at.set(Some(e.page_position)))
    .child(text(row.name.clone()))
Prop Rust Tipo Descripción
onContextMenu .on_context_menu(..) (e: ContextMenuEvent) => void Se presionó el botón secundario sobre la vista o sobre una vista dentro de ella.

ContextMenuEvent tiene position en la vista, pagePosition en su vista raíz (donde Menu.popup ubica un menú: Menu.popup(items, e.pagePosition)) y los modifiers; en Rust position, page_position y modifiers. La vista más cercana que escucha, desde la que está bajo el puntero hacia afuera, lo recibe. Un campo de texto, o texto seleccionable con un menú de edición (Windows, el backend de GPUI, navegadores), más cercano que esa vista muestra su propio menú en su lugar. La plataforma lo decide en el momento en que el botón baja, a partir de lo que está montado, así que el manejador se entera después de ocurrir el hecho y no hay nada que cancelar. Una vista disabled deja el clic al oyente habilitado más cercano que la rodea. En pantallas táctiles, una pulsación larga abre los menús: maneja onLongPress con la misma función.

#Foco del teclado

En macOS y en la web, Tab mueve el foco del teclado entre sus paradas en el orden del árbol: los campos de texto, las vistas que aceptan pulsaciones y cada vista focusable. Los estilos de foco (focus:, .focus(..)) dan estilo a la vista con el foco, y Return o Espacio la presionan cuando acepta pulsaciones. Un clic presiona una vista sin darle el foco, de modo que los estilos de foco se muestran solo para el foco del teclado.

El foco y las pulsaciones son cosas distintas. Una vista que recibe teclas mientras tiene el foco (un gráfico, un slider, una lista que mueve su selección con las teclas de flecha) define focusable y enlaza sus teclas mientras tiene el foco (onFocus / onBlur con keymap); una pulsación sobre ella sigue llegando a un elemento presionable que la rodea, como una tarjeta que abre una página.

El focus() de una ref mueve el foco del teclado a una parada como lo hace Tab (se muestran sus estilos de foco y se dispara onFocus), por ejemplo para devolverlo al disparador de un popup que se cerró, y blur() lo quita.

Una vista que rodea al foco se da estilo a sí misma con focus-within: (focusWithinStyle, .focus_within(..)) mientras el foco está en ella o en cualquier vista dentro de ella: el marco de un campo alrededor del input que edita, una barra de herramientas mientras uno de sus botones tiene el foco. El contenido de un Overlay está dentro de la vista en la que está el overlay, se muestre donde se muestre, así que un popup cuenta como parte de la vista que contiene su disparador. En Rust, un componente detecta cuándo el foco entra en un elemento y sale de él con los on_focus_in(..) y on_focus_out(..) de su ref: moverse entre vistas dentro de él no es ninguna de las dos cosas.

Prop Rust Tipo Valor por defecto Descripción
focusable .focusable(..) boolean true para las vistas que aceptan pulsaciones Si la vista es una parada de Tab. true convierte cualquier vista en una, ya acepte pulsaciones o las deje a las vistas que la rodean; false deja un elemento presionable solo al puntero (un fondo que cierra un popover, filas entre las que se mueven las teclas de flecha).
onFocus .on_focus(..) () => void Tab (o focus()) dio a la vista el foco del teclado.
onBlur .on_blur(..) () => void El foco del teclado salió de la vista.
view()
    .rounded_lg()
    .p_3()
    .focus(|s| s.bg(rgb(0xe0f2fe)))
    .on_press(open)
    .child(text("Open"))

// An overlay's backdrop: a click closes it, Tab goes past it to the content.
view().absolute().inset_0().focusable(false).on_press(close)

// A chart in a card: Tab stops at the chart, a click opens the card's page.
view().on_press(open_page).child(
    view()
        .h(px(160.0))
        .focusable(true)
        .focus(|s| s.bg(rgb(0xe0f2fe)))
        .on_focus(move || focused.set(true))
        .on_blur(move || focused.set(false)),
)

#Layout e identidad

Prop Rust Tipo Descripción
onLayout .on_layout(|frame: &Bounds<Points>| ..) (e: { bounds: Bounds }) => void bounds es el marco de la vista relativo a su padre, { origin, size }, después de cada layout que lo cambia.
ref .element_ref(&handle) ViewRef | (node: ViewRef) => void La ref del elemento (consulta los métodos de ref): ViewRef, o el tipo propio del elemento sobre ella. ref={el} asigna una variable, ref={fn} llama a una función.
nativeID .native_id(id) string Da un nombre a la vista para otros, p. ej. el InputAccessoryView al que se refiere un input.
testID .test_id(id) string Un identificador para pruebas de UI (en Android, el resource id de la vista).
key .key(key) string La identidad del elemento entre sus hermanos.

#Gestos que controlan valores animados

Estas props enlazan un gesto a valores animados nativos que se mueven en el hilo de la UI, sin trabajo en el código de la app en cada fotograma. Consulta toques y gestos.

Prop Rust Tipo Descripción
pan .pan_values(Some(&x), Some(&y)) { x?: AnimatedValue; y?: AnimatedValue } Los arrastres controlan estos valores (puntos).
onPanStart .on_pan_start(..) (e: PanEvent) => void Comenzó un arrastre.
onPanEnd .on_pan_end(..) (e: PanEvent) => void Terminó un arrastre, con la velocidad de liberación (p. ej. para iniciar un decay).
pinch .pinch_value(&scale) { scale?: AnimatedValue } Los gestos de pellizco con dos dedos controlan scale.
onPinchStart / onPinchEnd .on_pinch_start(..) / .on_pinch_end(..) (e: { scale: number; velocity: number }) => void Un pellizco comenzó / terminó.
rotation .rotation_value(&angle) { angle?: AnimatedValue } Las rotaciones con dos dedos controlan angle (grados).
onRotationStart / onRotationEnd .on_rotation_start(..) / .on_rotation_end(..) (e: { rotation: number; velocity: number }) => void Una rotación comenzó / terminó.

PanEvent es { cancelled, translation, velocity, value? } (en Rust cancelled, translation, velocity_x, velocity_y, value_x, value_y): si el sistema canceló el arrastre, la traslación desde el inicio y la velocidad en puntos por segundo (Points), y los valores enlazados en ese momento, { x?, y? } para los ejes que enlaza pan (un arrastre puede tomar un valor en mitad de una animación).

#Toques sin procesar y el sistema responder

Para los gestos que las props anteriores no cubren, cada elemento acepta las props de toque y de responder: onTouchStart, onTouchMove, onTouchEnd, onTouchCancel (y sus formas …Capture), onStartShouldSetResponder, onMoveShouldSetResponder (y …Capture), onResponderGrant, onResponderReject, onResponderStart, onResponderMove, onResponderEnd, onResponderRelease, onResponderTerminate y onResponderTerminationRequest. Cada manejador recibe un GestureResponderEvent ({ identifier, locationX, locationY, pageX, pageY, target, timestamp, touches, changedTouches, nativeEvent, stopPropagation() }); the …ShouldSetResponder handlers also get a gestureState (dx, dy, vx, vy, …). Devolver true desde onResponderGrant impide que las scroll views nativas se queden con los toques. panActivation ({ activeOffsetX, activeOffsetY, failOffsetX, failOffsetY }) convierte a la vista en responder solo cuando la plataforma activa su pan, de modo que los arrastres dentro de scroll views dejan el otro eje a estas (Toques y gestos). PanResponder en PanResponder se construye sobre ellos. En Rust, .on_touch(..) recibe cada toque (TouchEvent), .claim_touches(..) decide cuándo la vista los toma, y .on_responder_grant(..), .on_responder_move(..), .on_responder_release(..) y los demás siguen al responder.

#Accesibilidad

Prop Rust Tipo Descripción
accessible .accessible(..) boolean La vista es un solo elemento para las tecnologías de asistencia; sus hijos no se exponen por separado.
accessibilityLabel .label(..) string Lo que leen los lectores de pantalla. Las vistas sin etiqueta leen sus textos.
accessibilityHint .hint(..) string Lo que hace activar el elemento.
role .role(AccessibilityRole::Button) AccessibilityRole Lo que es el elemento ("button", "header", "link", "switch", …).
accessibilityState .accessibility_state(..) { disabled?, selected?, checked?, busy?, expanded?, pressed?, current? } El estado que informan las tecnologías de asistencia (checked y pressed pueden ser "mixed"; current es true o "page", "step", "location", "date", "time").
accessibilityLevel .accessibility_level(..) number El nivel de un encabezado (1 el más alto), la profundidad de un elemento de árbol (1 en la cima).
accessibilityValue .accessibility_value(..) { min?, max?, now?, text? } El valor de un elemento de rango o de texto.
accessibilityElementsHidden boolean Oculta la vista y su subárbol a las tecnologías de asistencia.
importantForAccessibility "auto" | "yes" | "no" | "no-hide-descendants" Si la vista está expuesta.
accessibilityActions { name: string; label?: string }[] Acciones personalizadas ofrecidas a las tecnologías de asistencia.
onAccessibilityAction .on_accessibility_action(..) (e: { actionName: string }) => void El usuario invocó una de las accessibilityActions.

Consulta accesibilidad.

#Props específicas de una plataforma

Las props que existen en una sola plataforma van en un objeto con su nombre en TSX, de modo que las props compartidas sean las mismas en todas partes. Solo se envía el objeto de la plataforma actual; los demás se ignoran. Los builders de Rust las aceptan como métodos que se aplican en su plataforma.

Prop Descripción
ios={{…}} iOS y Mac Catalyst. <Input>, Dialog y WebView añaden sus propias claves.
android={{…}} Android. Cada elemento acepta ripple, elevation y accessibilityLiveRegion (abajo).
desktop={{…}} Plataformas de escritorio y navegadores de escritorio; se ignora en móviles. Cada elemento acepta windowDrag (abajo).
web={{…}} Navegadores; se ignora en el resto.
Clave de android Rust Tipo Descripción
ripple .ripple(Ripple { .. }) { color?, borderless?, radius?, foreground? } El efecto ripple de Material mientras se presiona.
elevation .elevation(px(2.0)) number La sombra de Material (puntos), a partir de la forma de la vista.
accessibilityLiveRegion "none" | "polite" | "assertive" Cómo se anuncian a TalkBack los cambios de la vista.
Clave de desktop Rust Tipo Descripción
windowDrag .window_drag(..) boolean Presionar la vista arrastra la ventana, como lo haría su barra de título; false mantiene clicable una parte de una vista arrastrable. Consulta una barra de título propia.
use nsh_core::Ripple;

view()
    .rounded_lg()
    .bg(white())
    .p_4()
    .elevation(px(2.0))
    .ripple(Ripple { color: Some(rgba(0x00000022).into()), ..Ripple::default() })
    .on_press(save)
    .child(text("Save"))

Consulta código específico de plataforma.

#Métodos de ref

En TSX, ref recibe la ref del elemento, cuyo tipo es el propio del elemento: ViewRef (focus, blur, measure) para View, Text, Image, Canvas, Overlay y Shader, y un tipo sobre ViewRef con los métodos del elemento para los demás: InputRef (Input), ScrollRef (Scroll), ListRef (List), WebViewRef (WebView), VideoRef (Video) y NativeComponentRef (componentes nativos). En Rust, element_ref() crea un handle ElementRef que .element_ref(&handle) adjunta. Sus métodos envían comandos a la vista nativa, en orden con los cambios realizados antes de ellos en el mismo turno. La página de cada elemento indica cuáles le corresponden. Tipa una variable de ref con el tipo propio de su elemento (let field!: InputRef para un <Input>): una variable tipada como ViewRef no encaja con un elemento cuya ref tiene métodos propios.

Método Rust Ref Descripción
focus() / blur() focus() / blur() ViewRef Enfoca un <Input> (muestra el teclado), o da el foco del teclado a una vista que recibe pulsaciones / lo quita.
measure() measure() ViewRef Dónde está la vista.
setSelection(start, end?) set_selection(start, end) InputRef Selecciona start..end en unidades UTF-16; un cursor sin end.
scrollTo({ x?, y?, animated? }) scroll_to(point, animated) ScrollRef, ListRef Se desplaza a un offset.
zoomTo({ scale, x?, y?, animated? }) zoom_to(scale, center, animated) ScrollRef (un <Scroll> con zoom) Aplica zoom a scale alrededor de un punto del contenido.
scrollToOffset({ offset, animated? }) scroll_to_offset(offset, animated) ListRef Se desplaza a un offset a lo largo del eje de la lista.
scrollToIndex({ index, animated?, viewPosition?, viewOffset? }) scroll_to_index(index, position, offset, animated) ListRef Desplaza un elemento hasta hacerlo visible.
scrollToEnd({ animated? }) scroll_to_end(animated) ScrollRef, ListRef Se desplaza al final del contenido.
reload(), goBack(), goForward(), stopLoading(), injectJavaScript(script), postMessage(data) reload(), go_back(), go_forward(), stop_loading(), inject_java_script(..), post_message(..) WebViewRef Controla la página.
seek(seconds) seek(seconds) VideoRef Salta a un instante.
command(name, args?) command(name, args) NativeComponentRef Llama a un comando de un componente nativo registrado (nativeComponent).
let field = element_ref();

view()
    .on_press(move || field.focus())
    .child(input().element_ref(&field).placeholder("Tap the row to type"))

#Por qué los manejadores nunca bloquean la UI

El hilo principal nunca espera al código de la app. Cuando el sistema necesita una respuesta al instante (si puede cambiar este texto, si el botón de retroceso puede quitar la pantalla, si se puede cerrar esta hoja), NSH la responde de forma nativa a partir de props definidas de antemano (maxLength, popOnBack, closeOnSwipe, …), y el evento llega a la app después. Por eso ese comportamiento es una prop y no el valor de retorno de un manejador.