このページは機械翻訳のため、誤りを含む場合があります。 英語の原文を読む

要素

要素

Native Shell は、すべての画面を少数の要素から構築します。View、Text、Image などのプリミティブと、Button、Dialog、NavStack などのベースコンポーネントです。各プリミティブはネイティブビューです(iOS と Mac Catalyst では UIView のサブクラス、Android では View、デスクトップでは AppKit、GTK、Win32 のビュー)。ビューの作成とレイアウトは NSH ランタイムが行います。アプリが表示するものはすべてこれらで構成されます。アプリのボタン、カード、行、画面はアプリ自身のコンポーネントであり、これらの要素で描画され、アプリがスタイルを定めるため、見た目は完全にアプリ独自のものになります。

このページのすべての例は Rust と TSX の両方で示されます。タブを選ぶと、ページ内のすべての例が切り替わります。

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

Rust では、プリミティブは nsh_core::prelude の関数(view()、text(..)、image(..))であり、ベースコンポーネントは nsh_base クレートから提供されます。スタイルは型付きメソッド(.flex_1()、.gap_3()、.px(px(20.0))、.bg(..))で指定し、状態スタイルはクロージャ(.active(|s| s.opacity(0.6)))を取ります。リスナーはそのイベントを受け取るクロージャ(.on_press(move || ..)、.on_change(move |text: &str| ..))で、.child(..) で子要素を追加します。UI の断片は impl IntoElement を返す通常の関数で、一度だけ実行されます。クロージャ内(text(move || ..)、.bg(move || ..))で読み取られたシグナルは、バインドされた対象を更新します。Building with Rust を参照してください。

TSX では、すべてのタグは PascalCase で、スコープ内のバインディングの名前になります。プリミティブは nsh から、ベースコンポーネントは nsh/base から提供されます。インポートが不要なグローバルは <If> と <Each> だけです。<view> のような小文字のタグはビルドエラーになります。TypeScript が名前ごとに 1 つのグローバル型に照らして検査することになり、List や Each のようなジェネリックコンポーネントはアイテムの型を推論できないためです。コンパイラはインポートを通じて要素を認識し、ネイティブビューをその場で生成するため、インポートに実行時のコストはかかりません。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";

#プリミティブ

TSX では nsh から、Rust では nsh_core::prelude からインポートします。

要素Rustネイティブビュー (iOS / Android)ページ
<View>view()UIView / ViewGroup。selectable を指定すると、内部のテキストがまとめて選択されるView、Text selection
<Text>text(content)CoreText view / StaticLayout viewText
<Image>image(src)画像レイヤーを持つビュー / イメージビューImage
<Scroll>scroll()UIScrollView / ScrollViewScroll
<List>virtual_list(count, |at| row)セルをリサイクルする UIScrollView / ScrollViewList
<Canvas>canvas(painter)2D 描画を再生するビューCanvas
<Shader>shader(program)WGSL プログラムが子要素の下に GPU でボックスを描画するビューShader
<WebView>web_view(url)、web_view_html(html, base)WKWebView / android.webkit.WebViewWebView
<Video>video(url)AVPlayerLayer / TextureView 上の MediaPlayerVideo
<Overlay>overlay()ウィンドウ(またはそれが含まれるダイアログ)の最前面に、アンカーを基準に配置されるビューOverlay
<If>、<Each>when(..)、each(..)、dynamic(..)制御フロー。選択された要素を表示するControl flow
<InputAccessoryView> (nsh/mobile)input_accessory_view(id)iOS でキーボードの上に表示されるバーInputAccessoryView

パディングとマージンは、CSS の env() によってシステム UI を避けます。env(safe-area-inset-top) とその他の辺(Safe area)、および env(keyboard-inset-height)(Keyboard)が使えます。

#ベース

TSX では nsh/base から、Rust では nsh_base クレートからインポートします。これらは動作、状態、フォーカス、アクセシビリティを担い、見た目はアプリから与えられます。

コンポーネントRust役割ページ
AlertDialognsh_base::alert_dialog()システムのアラートとアクションシートAlertDialog
<Accordion> とその部品nsh_base::accordion()、accordion_item()、…見出しの下で展開・折りたたみができる積み重ねられたセクション。一度に 1 つまたは複数を開けるAccordion
<Avatar>、<AvatarGroup>nsh_base::avatar()、avatar_group()人物の画像、または読み込み中や失敗時のフォールバックと、先頭の数件を表示する Avatar の列Avatar
<Button>nsh_base::button()状態とロールを持つ押下可能なコントロールButton
<Carousel> とその部品nsh_base::carousel()、carousel_content()、…一度に 1 か所ずつ表示され、ネイティブにスワイプできるスライド。前へ / 次へ、ページネーション、キー操作、シームレスなループを備えるCarousel
<Checkbox>nsh_base::checkbox()チェック済み、未チェック、不確定の状態とインジケーターを持つコントロールCheckbox
<Collapsible>nsh_base::collapsible()内容が展開・折りたたまれる領域Collapsible
<Command>nsh_base::command()コマンドパレット。ネイティブに絞り込まれるコマンド上の検索フィールド、仮想化されたリスト、Cmd+K パレットのキー操作を備えるCommand
<DataTable>nsh_base::data_table()任意の数の行と列を持つテーブル。選択、並べ替えができ、列のサイズ変更と移動が可能DataTable
<Dialog>nsh_base::dialog()子要素を他のすべての上に表示するDialog
<DiffView>nsh_base::diff_view()2 つのテキスト間、またはパッチの変更点を、分割表示または統合表示で示すDiffView
<DockArea>nsh_base::dock_area()ユーザーが配置を変えられる、分割、タブグループ、端のドックからなるワークスペースDock
<Editor>nsh_base::editor()シンタックスハイライト、複数キャレット、折りたたみ、検索を備えたコードエディターEditor
<HoverCard>nsh_base::hover_card()ポインターが乗っている間、トリガーが指す対象をプレビューするHoverCard
<Input>nsh_base::input()ネイティブのテキスト入力(UITextField または UITextView / EditText)Input
<Link>nsh_base::link()ページ、サイト、アプリのルートを開く押下ターゲットLink
<Menu>、<ContextMenu>、<MenuItem>、<MenuSeparator>、<Submenu>nsh_base::menu()、…メニュー。デスクトップではカスケード式のサブメニューを持つポップアップ、スマートフォンではシートMenu
<NavStack>、<NavPage>nsh_base::nav_stack()、nsh_base::nav_page()ネイティブのナビゲーション。プラットフォームのヘッダーと戻るジェスチャーを備えたページのスタックNavStack
<NumberInput>nsh_base::number_input()フィールドに入力するか、ボタンやキーで増減させる数値NumberInput
<OtpInput>nsh_base::otp_input()固定桁数のワンタイムコード。入力、貼り付け、自動入力でセルに入るOtpInput
<Pagination>nsh_base::pagination()セットのページ。前へ、現在のページ前後のページ、省略記号、次へPagination
<Tree>nsh_base::tree()アイテムを含むアイテム。展開・折りたたみができ、1 つが選択される。仮想化されており、キーボードフォーカスの停止位置は 1 つTree
<Plot>、<Line>、<Area>、<Bar>、<Grid>、<Pie>、<Arc> (nsh/base/plot)nsh_base::plot::{plot, line, area, bar, grid, pie, arc}アプリの行からネイティブに描画される、チャートのフレームとマークPlot
<Popover>nsh_base::popover()トリガーに固定され、他のすべての上に表示されるコンテンツPopover
<Progress>nsh_base::progress()プログレスバー。タスクの進捗、または処理中であることを示すProgress
<Radio>、<RadioGroup>nsh_base::radio()、radio_group()ユーザーが 1 つを選ぶセットの選択肢 1 つと、そのセットRadio
<ResizablePanelGroup>、<ResizablePanel>nsh_base::h_resizable()、resizable_panel()横または縦に並べられ、ハンドルでサイズを変更できるパネルResizable
<Scrollbar>nsh_base::scrollbar()スクロールビューまたはリスト用の、アプリ独自の見た目のスクロールバーScrollbar
<Select>nsh_base::select()アイテムのリストから 1 つの値を選ぶ。キーボード、検索、セクションに対応Select
<Sheet>nsh_base::sheet()背景の上に、画面の端に表示されるパネルSheet
<Slider>nsh_base::slider()トラック上で選ぶ 1 つの値、または 2 つの値による範囲Slider
<Switch>nsh_base::switch()トラックとつまみを持つオン / オフのコントロールSwitch
<Table> とその部品nsh_base::table()、table_row()、…テーブルのロールを持つ、アプリ独自の行とセルのテーブルTable
<Tab>、<Tabs>nsh_base::tab()、tabs()タブリストの 1 つのタブと、そのリストTabs
<TextView>nsh_base::text_view()Markdown または HTML ドキュメントを、テキストとビューで表示するTextView
<Toast>、<ToastStack>nsh_base::toast()、toast_stack()トーストのセマンティックなルートと、端からレイヤーとして配置されるトーストToast
<Toggle>、<ToggleGroup>nsh_base::toggle()、toggle_group()オンまたはオフのボタンと、それらのツールバーToggle
<Toolbar>、<ToolbarGroup>、<ToolbarSeparator>nsh_base::toolbar()、toolbar_group()、toolbar_separator()ボタン、トグル、リンクのバー。キーボードフォーカスの停止位置は 1 つToolbar
<Tooltip>nsh_base::tooltip()ホバー時または指を置いている間に、トリガーの隣に表示されるヒントTooltip

#共通プロパティ

すべてのプリミティブは、以下のプロパティを受け付けます(TSX では CommonProps 型、Rust では Styled、Interactive、Accessible トレイト)。各要素のページには、その要素固有のプロパティのみを記載しています。Rust の列にはビルダーメソッドを示しています。

#スタイリング

プロパティRust型説明
style型付き Styled メソッド、.inline_style(style)StyleProp<ViewStyle>(<Text> と <Input> では TextStyle、<Image> では ImageStyle)インラインスタイル、または左から右へマージされるスタイルの配列(falsy な要素は無視される。配列はネストでき、そのため style={[base, props.style]} はそれ自体が配列である props.style を受け取れる)。class より優先される。style reference を参照。
class型付き Styled メソッド(.flex_row().gap_2().p_4())stringネイティブに解決される Tailwind クラス("flex-row gap-2 p-4 dark:bg-zinc-900")。後のクラスが前のクラスより優先される。Tailwind を参照。
classList.style_when(when, |s| ..)Record<string, boolean | null | undefined>値が truthy の間だけ適用されるクラス({ "opacity-50": busy() })。
disabled.disabled(..)boolean押下を無視し(押下フィードバックも行わない)、disabled: スタイルを適用し、入力などのコントロールを無効にする。スクリーンリーダーは無効であることを読み上げる(accessibilityState.disabled)。

#押下とフィードバック

押下の処理はネイティブに実行されます。プラットフォームが押下を認識してアプリの押下スタイルを適用し、アプリのコードには事後に通知されるだけです。反応するのは最も内側の押下可能なビューだけです。スクロールビュー内では、スクロールを先に開始できるよう、押下の開始が約 130 ms 待機されます。

プロパティRust型デフォルト説明
onPress.on_press(..)(e: PressEvent) => voidビューの内側でタップが終了した。
onLongPress.on_long_press(..)(e: PressEvent) => void指が delayLongPress の間、置かれたままだった。
onPressDown.on_press_down(..)(e: PressEvent) => voidビューに指が触れた。
onPressUp.on_press_up(..)(e: PressEvent) => void指が離れた、または外れた。
delayLongPress.long_press_delay(ms)number500押下が長押しになるまでのミリ秒数。
hitSlop.hit_slop(EdgeInsets::all(px(8.0)))number | Partial<Edges>タッチ領域を境界の外側へポイント単位で拡張する。

PressEvent は { position, pagePosition, modifiers, clickCount } です。ビュー内とそのルートビュー内(Point)でのポインターの位置、押下の開始時に押されていた修飾キー、連続クリック数(ダブルクリックなら 2)を含みます。プラットフォームがポインターを報告しない場合は、ビューの原点、キーなし、クリック 1 回になります。

スタイルキー pointerEvents(Rust では .pointer_events(PointerEvents::BoxNone)、クラスでは pointer-events-*)は、そのビューとその内部のビューがどのタッチを受け取るかを決めます。"none" はどちらも受け取らず(内部で "auto" を設定したビューは再び受け取ります)、"box-none" は内部のビューのみ、"box-only" はビュー自身のみが受け取ります(touch and gestures)。

押下フィードバックはアプリ側で定義します。activeStyle(または active: クラス、Rust では .active(..))は、ビューが押されている間、アプリのコードへ往復することなくネイティブに適用されます(後述)。

#状態スタイル

ビューがある状態にある間、ビュー自身のスタイルの上にネイティブに適用されるスタイルです。それぞれ Tailwind バリアントのオブジェクト形式です。後の状態が優先されます(selected、checked と indeterminate、次に hover、focus、active の順)。disabledStyle はすべてに優先し、それ以外はビューが無効の間は適用されません。それぞれ要素自身のスタイルを取ります。<Text> では TextStyle、<Input> では InputStyle、<Image> では ImageStyle、それ以外では ViewStyle です。

プロパティRustクラスバリアント適用される場面
activeStyle.active(|s| ..)active:押されている間。
hoverStyle.hover(|s| ..)hover:ポインターがビューの上にある間。
focusStyle.focus(|s| ..)focus:ビューがフォーカスを持つ間。
focusWithinStyle.focus_within(|s| ..)focus-within:ビューまたはその内部のビューがフォーカスを持つ間(Overlay のコンテンツは、それが置かれているビューの内部とみなされる)。
disabledStyle.disabled_style(|s| ..)disabled:disabled の間。
checkedStyle.checked(|s| ..)、.checked_style(style)checked:accessibilityState.checked が true の間(チェックボックス、スイッチ、ラジオ。"mixed" はチェックされていない)。
indeterminateStyle.indeterminate(|s| ..)、.indeterminate_style(style)indeterminate:accessibilityState.checked が "mixed" の間(チェック済みでも未チェックでもないチェックボックス)。
selectedStyle.selected(|s| ..)selected:accessibilityState.selected が true の間(選択された Button、タブ)。
expandedStyle.expanded(|s| ..)、.expanded_style(style)aria-expanded:accessibilityState.expanded が true の間(ポップアップが開いている間の Popover または Menu のトリガー)。
pressedStyle.aria_pressed(|s| ..)、.pressed_style(style)aria-pressed:accessibilityState.pressed が true の間(オンになっているトグルボタン。"mixed" は押されていない)。進行中の押下である activeStyle ではない。
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

アプリは、マウスがビューの上に来たこと、ビューの上を動いたこと、ビューから離れたことを受け取れます。対応するのは、macOS、Windows、Linux、GPUI バックエンド、デスクトップブラウザー、iOS での iPad のポインターまたは Mac のマウス、Android でのマウスまたはスタイラスです。ホバースタイル(hover:、.hover(..))は、同じ環境でホバーされたビューにスタイルを適用します。

PropRust型説明
onMouseEnter.on_mouse_enter(..)(e: MouseEvent) => voidマウスがビュー、またはビュー内のビューの上に来ました(DOM の mouseenter)。
onMouseMove.on_mouse_move(..)(e: MouseEvent) => voidマウスがビュー(またはビュー内のビュー)の上を動きました。ボタンが押されているかどうかは問いません。また、ボタンが押されていない状態でマウスが止まっている間に修飾キーが押された、または離された場合も発火します(DOM の mousemove)。
onMouseLeave.on_mouse_leave(..)(e: MouseEvent) => voidマウスがビューとその内側のビュー、またはウィンドウから離れました。e は最後にあった位置です(DOM の mouseleave)。

CSS の :hover や DOM の mouseenter と同様に、マウスがビューの上、またはビュー内の何かの上にある間、そのビューはホバーされているものとして扱われます。そのため、マウスの真下にあるビューの周囲のビューにも onMouseEnter が届きます(外側から内側の順。onMouseLeave は内側から外側の順)。イベントは事後に届き、タッチでは発生しません。マウスの下から取り除かれたビューには onMouseLeave が届きます。Linux と Windows では、次にマウスが動いたときです。

MouseEvent は、GPUI の MouseMoveEvent と同様にマウスの位置を表します。ビュー内での position(ポイント単位の Point。変換は打ち消されています)、属するルートビュー内での pagePosition(タッチと同じ形式)、押されている modifiers(control、alt、shift、platform:Apple プラットフォームでは Command、それ以外では Windows キー)、そして押されているボタンを示す pressedButton("left"、"right"、"middle"、"back" または "forward"。GPUI の MouseButton)、または null です。Rust では position、page_position、modifiers、pressed_button です。デスクトップとウェブでは、ドラッグもタッチ(onTouchMove、レスポンダー)であり、その移動は pressedButton が設定された状態で onMouseMove にも届きます。ホバーだけを追うフィードバックでは、これらを無視してください。iOS と Android では、ホバーはボタンが押されていないポインターを報告します。移動イベントは 1 フレームにつき最大 1 回、最新のものだけが届き、後に続く onMouseLeave より必ず前に届くので、ハンドラーは移動のたびに再描画できます。

// 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 は、任意の要素にヒントを付けます。デスクトップ(macOS、Windows、Linux、GPUI バックエンド、デスクトップブラウザー)では、ポインターが要素の上に 0.5 秒間とどまると要素の上にヒントが表示され、ポインターが離れるか要素が押されるまで表示されます。スマートフォンとタブレットでは表示されません。ヒントがポインターや押下を受け取ることはないため、要素はヒントがない場合とまったく同じように動作します。

PropRust型説明
tooltip.tooltip(..)JSX.Elementヒント。アプリがスタイルを設定する要素です。nsh/base の Tooltip はツールチップそのものであり、配置、遅延、イベントを持ちます。それ以外の要素はそのまま表示されます。
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("💾"))

Tooltip は、GPUI の .tooltip(..) がそうであるように、見た目、配置、遅延、イベントを自分で設定します。ツールチップを多く使うアプリでは、テキストを Tooltip で包む小さな独自コンポーネントを 1 つ用意しておくとよいでしょう。

#Context menus

onContextMenu は、ビューの上でセカンダリボタンが押されたことを伝えます。右クリック、macOS での Control-click、タッチパッドでの 2 本指クリック、iPad のポインターのセカンダリクリックが該当し、ブラウザーではキーボードのメニューキーも該当します。ここでアプリ独自のメニューを開きます。TSX では、Menu.popup がシステムのメニューを表示します。

// 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()))
PropRust型説明
onContextMenu.on_context_menu(..)(e: ContextMenuEvent) => voidビュー、またはビュー内のビューの上でセカンダリボタンが押されました。

ContextMenuEvent には、ビュー内での position、ルートビュー内での pagePosition(Menu.popup がメニューを配置する基準:Menu.popup(items, e.pagePosition))、そして modifiers が含まれます。Rust では position、page_position、modifiers です。リスナーを持つ最も近いビュー(ポインターの下のビューから外側へ向かって探します)がイベントを受け取ります。そのビューよりも近くにテキスト入力、または編集メニューを持つ選択可能なテキスト(Windows、GPUI バックエンド、ブラウザー)がある場合は、代わりにそちらが独自のメニューを表示します。これはボタンが押された時点で、マウントされているものをもとにプラットフォームが判断します。そのためハンドラーには事後に通知され、何かをキャンセルする必要はありません。disabled のビューは、クリックを周囲にある最も近い有効なリスナーに任せます。タッチスクリーンでは長押しでメニューが開くので、同じ関数で onLongPress を処理してください。

#Keyboard focus

macOS とウェブでは、Tab キーでキーボードフォーカスがツリー順にストップ間を移動します。ストップとなるのは、入力、押下を受け取るビュー、そしてすべての focusable ビューです。フォーカススタイル(focus:、.focus(..))はフォーカスされたビューにスタイルを適用し、押下を受け取るビューでは Return または Space でそのビューが押されます。クリックはビューにフォーカスを移さずに押下するため、フォーカススタイルが表示されるのはキーボードフォーカスのときだけです。

フォーカスと押下は別のものです。フォーカスがある間にキーを受け取るビュー(チャート、スライダー、矢印キーで選択を移動するリストなど)は、focusable を設定し、フォーカス中のキーをバインドします(keymap と組み合わせた onFocus / onBlur)。そのビューへの押下は、周囲にある押下可能なビュー、たとえばページを開くカードにも引き続き届きます。

ref の focus() は、Tab と同じようにキーボードフォーカスをストップに移します(フォーカススタイルが表示され、onFocus が発火します)。たとえば、閉じたポップアップのトリガーにフォーカスを戻すときに使います。blur() はフォーカスを外します。

フォーカスの周囲にあるビューは、フォーカスがそのビュー自身、またはその内側のいずれかのビューにある間、focus-within:(focusWithinStyle、.focus_within(..))で自身のスタイルを設定できます。たとえば、編集中の入力を囲むフィールドの枠や、ボタンの 1 つにフォーカスがある間のツールバーです。Overlay の内容は、実際の表示位置にかかわらず、オーバーレイが置かれているビューの内側にあるものとして扱われます。そのため、ポップアップはトリガーを持つビューの一部として数えられます。Rust では、コンポーネントは ref の on_focus_in(..) と on_focus_out(..) によって、フォーカスが要素に入ったこと、出たことを受け取ります。要素の内側のビュー間での移動は、そのどちらにも当たりません。

PropRust型デフォルト説明
focusable.focusable(..)boolean押下を受け取るビューでは trueビューが Tab のストップかどうか。true を指定すると、押下を受け取るビューでも、周囲のビューに任せるビューでも、任意のビューがストップになります。false を指定すると、押下可能なビューはポインター専用になります(ポップオーバーを閉じるバックドロップ、矢印キーで移動する行など)。
onFocus.on_focus(..)() => voidTab(または focus())でビューにキーボードフォーカスが移りました。
onBlur.on_blur(..)() => voidキーボードフォーカスがビューから離れました。
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 and identity

PropRust型説明
onLayout.on_layout(|frame: &Bounds<Points>| ..)(e: { bounds: Bounds }) => voidbounds は、レイアウトで変化するたびに通知される、親に対するビューのフレーム({ origin, size })です。
ref.element_ref(&handle)ViewRef | (node: ViewRef) => void要素の ref(ref メソッドを参照):ViewRef、またはそれに重ねた要素自身の型。ref={el} は変数に代入し、ref={fn} は関数を呼び出します。
nativeID.native_id(id)string他の要素から参照できるようにビューに名前を付けます。たとえば、入力が参照する InputAccessoryView です。
testID.test_id(id)stringUI テスト用の識別子(Android ではビューのリソース ID)。
key.key(key)string兄弟要素の中での要素の識別子。

#Gestures driving animated values

これらの Prop は、ジェスチャーを、UI スレッド上で動くネイティブのアニメーション値にバインドします。フレームごとのアプリコードによる処理は不要です。タッチとジェスチャーも参照してください。

PropRust型説明
pan.pan_values(Some(&x), Some(&y)){ x?: AnimatedValue; y?: AnimatedValue }ドラッグがこれらの値(ポイント)を動かします。
onPanStart.on_pan_start(..)(e: PanEvent) => voidドラッグが始まりました。
onPanEnd.on_pan_end(..)(e: PanEvent) => voidドラッグが終わりました。離したときの速度が付きます(たとえば decay を開始するときに使います)。
pinch.pinch_value(&scale){ scale?: AnimatedValue }2 本指のピンチが scale を動かします。
onPinchStart / onPinchEnd.on_pinch_start(..) / .on_pinch_end(..)(e: { scale: number; velocity: number }) => voidピンチが始まりました / 終わりました。
rotation.rotation_value(&angle){ angle?: AnimatedValue }2 本指の回転が angle(度)を動かします。
onRotationStart / onRotationEnd.on_rotation_start(..) / .on_rotation_end(..)(e: { rotation: number; velocity: number }) => void回転が始まりました / 終わりました。

PanEvent は { cancelled, translation, velocity, value? } です(Rust では cancelled、translation、velocity_x、velocity_y、value_x、value_y)。システムがドラッグをキャンセルしたかどうか、開始からの移動量、秒あたりのポイントで表した速度(Point)、そしてその時点でのバインドされた値が含まれます。バインドされた値は、pan がバインドする軸については { x?, y? } です(ドラッグはアニメーション中の値をつかむことができます)。

#Raw touches and the responder system

上の Prop ではカバーできないジェスチャーのために、すべての要素がタッチ系とレスポンダー系の Prop を受け付けます。onTouchStart、onTouchMove、onTouchEnd、onTouchCancel(およびその …Capture 形式)、onStartShouldSetResponder、onMoveShouldSetResponder(および …Capture)、onResponderGrant、onResponderReject、onResponderStart、onResponderMove、onResponderEnd、onResponderRelease、onResponderTerminate、onResponderTerminationRequest です。各ハンドラーは GestureResponderEvent を受け取ります({ identifier, locationX, locationY, pageX, pageY, target, timestamp, touches, changedTouches, nativeEvent, stopPropagation() }); the …ShouldSetResponder handlers also get a gestureState (dx, dy, vx, vy, …)。onResponderGrant から true を返すと、ネイティブのスクロールビューがタッチを奪わなくなります。panActivation({ activeOffsetX, activeOffsetY, failOffsetX, failOffsetY })は、プラットフォームがパンを有効にした後にはじめてビューをレスポンダーにするため、スクロールビュー内でのドラッグでは、もう一方の軸がスクロールビューに任されます(タッチとジェスチャー)。PanResponder の PanResponder は、これらをもとに作られています。Rust では、.on_touch(..) がすべてのタッチを受け取り(TouchEvent)、.claim_touches(..) がビューがタッチを引き受けるタイミングを決め、.on_responder_grant(..)、.on_responder_move(..)、.on_responder_release(..) などがレスポンダーに従います。

#Accessibility

PropRust型説明
accessible.accessible(..)booleanビューは支援技術にとって 1 つの要素となり、その子は個別には公開されません。
accessibilityLabel.label(..)stringスクリーンリーダーが読み上げる内容。ラベルのないビューは、中のテキストが読み上げられます。
accessibilityHint.hint(..)string要素を操作したときに何が起こるか。
role.role(AccessibilityRole::Button)AccessibilityRole要素が何であるか("button"、"header"、"link"、"switch" など)。
accessibilityState.accessibility_state(..){ disabled?, selected?, checked?, busy?, expanded?, pressed?, current? }支援技術が報告する状態(checked と pressed は "mixed" にできます。current は true または "page"、"step"、"location"、"date"、"time")。
accessibilityLevel.accessibility_level(..)number見出しのレベル(1 が最上位)、ツリー項目の深さ(1 が最上位)。
accessibilityValue.accessibility_value(..){ min?, max?, now?, text? }範囲要素またはテキスト要素の値。
accessibilityElementsHiddenbooleanビューとそのサブツリーを支援技術から隠します。
importantForAccessibility"auto" | "yes" | "no" | "no-hide-descendants"ビューを公開するかどうか。
accessibilityActions{ name: string; label?: string }[]支援技術に提供するカスタムアクション。
onAccessibilityAction.on_accessibility_action(..)(e: { actionName: string }) => voidユーザーが accessibilityActions のいずれかを実行しました。

アクセシビリティを参照してください。

#Platform-only props

1 つのプラットフォームにしかない Prop は、TSX ではそのプラットフォーム名のオブジェクトに入れるため、共通の Prop はどこでも同じままです。送られるのは現在のプラットフォームのオブジェクトだけで、それ以外は無視されます。Rust のビルダーでは、これらはメソッドとして用意され、該当するプラットフォームでのみ適用されます。

Prop説明
ios={{…}}iOS と Mac Catalyst。<Input>、Dialog、WebView は独自のキーを追加します。
android={{…}}Android。すべての要素が ripple、elevation、accessibilityLiveRegion(下記)を受け付けます。
desktop={{…}}デスクトッププラットフォームとデスクトップブラウザー。モバイルでは無視されます。すべての要素が windowDrag(下記)を受け付けます。
web={{…}}ブラウザー。それ以外では無視されます。
android のキーRust型説明
ripple.ripple(Ripple { .. }){ color?, borderless?, radius?, foreground? }押されている間のマテリアルのリップル。
elevation.elevation(px(2.0))numberビューの形状から作られるマテリアルの影(ポイント)。
accessibilityLiveRegion"none" | "polite" | "assertive"ビューの変化を TalkBack にどのように通知するか。
desktop のキーRust型説明
windowDrag.window_drag(..)booleanビューを押すと、タイトルバーと同じようにウィンドウをドラッグします。false は、ドラッグ可能なビューの一部をクリック可能なままにします。独自のタイトルバーを参照してください。
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"))

プラットフォーム固有のコードを参照してください。

#Ref メソッド

TSX では、ref は要素の ref を受け取ります。その型は要素固有のものです。View、Text、Image、Canvas、Overlay、Shader には ViewRef(focus、blur、measure)が使われ、それ以外の要素には、その要素のメソッドを持つ ViewRef ベースの型が使われます。具体的には InputRef(Input)、ScrollRef(Scroll)、ListRef(List)、WebViewRef(WebView)、VideoRef(Video)、NativeComponentRef(ネイティブコンポーネント)です。Rust では、element_ref() が ElementRef ハンドルを作成し、.element_ref(&handle) がそれをアタッチします。これらのメソッドは、ネイティブビューにコマンドを送ります。コマンドは、同じターン内でそれより前に行われた変更と同じ順序で送られます。各要素のページに、その要素で使えるメソッドが記載されています。ref 変数には、その要素固有の型(<Input> なら let field!: InputRef)を指定してください。ViewRef 型の変数は、固有のメソッドを持つ ref の要素には適合しません。

メソッドRustRef説明
focus() / blur()focus() / blur()ViewRef<Input> にフォーカスを当てる(キーボードを表示する)、または、プレスを受け取るビューにキーボードフォーカスを与える/フォーカスを外します。
measure()measure()ViewRefビューの位置。
setSelection(start, end?)set_selection(start, end)InputRefUTF-16 単位で start..end を選択します。end がない場合はキャレットになります。
scrollTo({ x?, y?, animated? })scroll_to(point, animated)ScrollRef、ListRefオフセットまでスクロールします。
zoomTo({ scale, x?, y?, animated? })zoom_to(scale, center, animated)ScrollRef(ズーム可能な <Scroll>)コンテンツ上の点を中心に scale までズームします。
scrollToOffset({ offset, animated? })scroll_to_offset(offset, animated)ListRefリストの軸方向のオフセットまでスクロールします。
scrollToIndex({ index, animated?, viewPosition?, viewOffset? })scroll_to_index(index, position, offset, animated)ListRefアイテムが見える位置までスクロールします。
scrollToEnd({ animated? })scroll_to_end(animated)ScrollRef、ListRefコンテンツの末尾までスクロールします。
reload()、goBack()、goForward()、stopLoading()、injectJavaScript(script)、postMessage(data)reload()、go_back()、go_forward()、stop_loading()、inject_java_script(..)、post_message(..)WebViewRefページを制御します。
seek(seconds)seek(seconds)VideoRef指定した時間へジャンプします。
command(name, args?)command(name, args)NativeComponentRef登録済みのネイティブコンポーネントのコマンドを呼び出します(nativeComponent)。
let field = element_ref();

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

#ハンドラが UI をブロックしない理由

メインスレッドは、アプリのコードを待つことはありません。システムがその場で答えを必要とする場合(このテキストを変更してよいか、戻るボタンで pop してよいか、このシートを閉じてよいか)、NSH は事前に設定された props(maxLength、popOnBack、closeOnSwipe など)に基づいてネイティブ側で応答し、イベントはその後でアプリに届きます。このような動作が、ハンドラの戻り値ではなく prop になっているのはそのためです。