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

要素

テキスト選択

selectable を指定した View は、Web ページと同じように、その内部のテキストをまとめて選択できるようにします。1 つの選択が、あるテキストの途中から別のテキストの途中まで、ビュー、Text 要素、TextView をまたいで読み順に続きます。チャットの会話履歴を選択可能にすれば、選択をあるメッセージで始めて次のメッセージで終えることができます。コピーすると選択したテキストがクリップボードに入り、横に並んだテキストはタブで、それ以外は改行で区切られます。Rust では view().selectable(true)、TSX では <View selectable> で設定します。単一のテキストを選択できるかどうかは、その userSelect スタイルで決まります。

el-text-selection.tsx
el-text-selection.tsxLive
import { mount, Scroll, signal, Text, View } from "nsh";
import { Input } from "nsh/base";
import { TextView } from "nsh/base";
import { platform } from "nsh";
import { field, ui } from "./palette";

const NOTES = "- Sync runs **in the background**\n- Conflicts merge *per field*";

function App() {
  const pasted = signal("");
  return (
    <Scroll style={{ flex: 1, backgroundColor: ui().page }}>
      <View style={{ width: "100%", maxWidth: 560, alignSelf: "center", padding: 20, paddingTop: 24, gap: 14 }}>
        <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>selectable view</Text>
        <Text style={{ color: ui().muted, lineHeight: 20 }}>
          {platform.desktop
            ? "Drag with the mouse from the title into the list: one selection runs across them. Double click a word, triple click a paragraph, Ctrl / Cmd+C copies."
            : "Long press a word, then drag the handles across the texts: one selection runs across them. Copy is in the menu."}
        </Text>

        <View selectable style={{ ...ui().card, borderRadius: 16, padding: 16, gap: 10 }}>
          <Text style={{ fontSize: 17, fontWeight: "600", color: ui().text }}>Release notes</Text>
          <Text style={{ color: ui().text, lineHeight: 22 }}>Version 2.4 moves the app to offline sync.</Text>
          <TextView markdown={NOTES} />
          <View style={{ flexDirection: "row", gap: 8 }}>
            <Text style={{ userSelect: "none", color: ui().faint }}>
              Updated (userSelect none)
            </Text>
            <Text style={{ color: ui().text }}>October 21</Text>
          </View>
        </View>

        <Text style={{ fontSize: 12, color: ui().muted }}>Paste what you copied: the label marked userSelect none stays out of it.</Text>
        <Input
          multiline
          value={pasted()}
          onChange={({ value }) => pasted.set(value)}
          placeholder="Paste here"
          {...field({ style: { height: 110 } })}
        />
        <Text style={{ fontSize: 12, color: ui().muted, fontVariant: ["tabular-nums"] }}>
          {pasted().length} characters, {pasted() ? pasted().split("\n").length : 0} lines
        </Text>
      </View>
    </Scroll>
  );
}

mount(App);
use nsh_base::text_view;
use nsh_core::prelude::*;

fn release_notes(notes: &'static str) -> impl IntoElement {
    view()
        .selectable(true)
        .gap_3()
        .p_4()
        .child(text("Release notes").font_weight(FontWeight::SEMIBOLD))
        .child(text_view().markdown(notes))
        .child(
            view()
                .flex_row()
                .gap_2()
                .child(text("Updated").select_none().text_color(rgb(0x737373)))
                .child(text("October 21")),
        )
}

ビューのレイアウトと見た目はアプリのスタイルによるもので、その内容は子要素です。選択そのものはプラットフォームが担い、ビューが選択のために独自に描画するものはありません。

#チャットの会話履歴

1 つの選択可能なビューに入れた会話履歴は、1 つのページとして選択されます。ドラッグをある返信で始めて別の返信で終えると、コピーでその間にあるすべてのメッセージのテキストが取得されます。

use nsh_base::text_view;
use nsh_core::prelude::*;

fn transcript(replies: Signal<Vec<SharedString>>) -> impl IntoElement {
    scroll().flex_1().child(
        view().selectable(true).p_4().gap_4().child(each(
            replies,
            |reply: &SharedString| reply.clone(),
            |reply, _index| text_view().markdown(move || reply.get()),
        )),
    )
}

#選択の方法

プラットフォーム選択の方法
macOS, Windows, Linux, GPUIテキスト上をドラッグします。ダブルクリックで単語、トリプルクリックで段落を選択でき、その後のドラッグは単語単位または段落単位で続きます。Shift+クリックで選択範囲を拡張できます。Ctrl / Cmd+A でビュー内のすべてを選択、Ctrl / Cmd+C でコピー、Escape または外側のクリックで選択を解除します。
iOS, Android長押しで単語を選択します。プラットフォームのハンドルで選択範囲を拡張でき、編集メニューにはコピーとすべてを選択があります。
Webブラウザー標準の選択機能で、そのジェスチャー、メニュー、ショートカットがそのまま使えます。

#選択の対象

  • 対象外のテキスト: userSelect: "none"(Rust では .select_none()、クラスでは select-none)を持つテキスト(ラベルやボタンのキャプションなど)は、選択とそのジェスチャーの対象になりません。
  • ネストしたビュー: 選択可能なビューの内側にある選択可能なビューは外側のビューの一部として扱われ、1 つの選択が両方にまたがります。
  • TextView: selectable を指定した TextView は、それ自体で 1 つのまとまりとして選択されます。段落、リスト項目、セル、コードブロックがまとめて選択されます。選択可能なビューの内側にある場合は、外側の選択に加わります。
  • 単一のテキスト: どの選択可能なビューにも含まれない、userSelect: "text" を持つテキストは、Text で説明されているとおり単独で選択されます。
  • 見た目は、各テキストの selectionColor(selection:text-*)で指定されるプラットフォームのハイライトです。
  • リスト: 仮想化された List では、選択範囲はマウントされている行を対象とします。表示範囲外でリサイクルされた行は選択から外れます。

#関連項目

  • View: selectable プロパティ。
  • Text: userSelect、selectionColor、および単一のテキストの選択。
  • TextView: ブロックがまとめて選択されるドキュメント。