इस पेज का अनुवाद मशीन द्वारा किया गया है और इसमें त्रुटियाँ हो सकती हैं। मूल अंग्रेज़ी पढ़ें

एलिमेंट

Input

Input एक native text field है: iOS और Mac Catalyst पर UITextField (single line) या UITextView (multiline), और Android पर EditText। टाइपिंग, caret, selection, autocorrection और autofill प्लेटफ़ॉर्म के अपने हैं। Rust में इसे nsh_base::input() से बनाया जाता है, और TSX में nsh/base से <Input> द्वारा।

el-input.tsx
el-input.tsxLive
import { type InputRef, type JSX, mount, signal, Text, View } from "nsh";
import { Input } from "nsh/base";
import { button, buttonText, field, Inspector, Panel, Stage, ui, wide } from "./palette";

function App() {
  const name = signal("");
  const password = signal("");
  const notes = signal("");
  const submitted = signal("");
  let passwordInput!: InputRef;
  const signIn = () => submitted.set(`Signed in as ${name() || "nobody"}`);
  const nameField = () => (
    <Input
      {...field()}
      value={name()}
      onChange={({ value }) => name.set(value)}
      placeholder="Ada Lovelace"
      autoCapitalize="words"
      maxLength={20}
      returnKeyType="next"
      onSubmit={() => passwordInput.focus()}
    />
  );
  const count = () => <Text style={{ fontSize: 12, color: ui().muted }}>{name().length} / 20</Text>;
  const passwordField = () => (
    <Input
      ref={passwordInput}
      {...field()}
      value={password()}
      onChange={({ value }) => password.set(value)}
      masked
      autoComplete="current-password"
      returnKeyType="done"
      onSubmit={signIn}
    />
  );
  const notesField = () => (
    <Input
      {...field({ style: { height: wide() ? 80 : 100 } })}
      multiline
      value={notes()}
      onChange={({ value }) => notes.set(value)}
      placeholder="Anything else?"
    />
  );
  const signInButton = () => (
    <View onPress={signIn} disabled={password().length === 0} {...button("primary", { style: { marginTop: 4 } })}>
      <Text style={buttonText("primary")}>Sign in</Text>
    </View>
  );
  /** A label above its field, and what describes it below. */
  const group = (label: string, input: JSX.Element, after?: JSX.Element) => (
    <View style={{ gap: 6 }}>
      <Text style={{ fontSize: 13, color: ui().muted }}>{label}</Text>
      {input}
      {after}
    </View>
  );

  return (
    <View style={{ flex: 1, backgroundColor: ui().page }}>
      {() =>
        wide() ? (
          <View style={{ flex: 1, padding: 20, paddingTop: 24, gap: 14 }}>
            <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>input</Text>
            <Text style={{ color: ui().muted }}>Tab moves between the fields; Return in the name goes to the password</Text>
            <View style={{ flex: 1, flexDirection: "row", gap: 16 }}>
              <Stage width={340} gap={16}>
                {group("Name (controlled, maxLength 20)", nameField(), count())}
                {group("Password", passwordField())}
                {group("Notes (multiline)", notesField())}
                {signInButton()}
              </Stage>
              <Inspector>
                <Panel title="value">
                  <Text style={{ fontSize: 13, color: ui().text }}>name {name() ? `“${name()}”` : "—"}</Text>
                  <Text style={{ fontSize: 13, color: ui().text, fontVariant: ["tabular-nums"] }}>password {password().length} characters</Text>
                  <Text style={{ fontSize: 13, color: ui().text, fontVariant: ["tabular-nums"] }}>notes {notes().length} characters</Text>
                </Panel>
                <Panel title="onSubmit" grow>
                  <Text style={{ fontSize: 13, color: ui().up }}>{submitted()}</Text>
                </Panel>
              </Inspector>
            </View>
          </View>
        ) : (
          <View style={{ flex: 1, width: "100%", maxWidth: 480, alignSelf: "center", padding: 20, paddingTop: 24, gap: 10 }}>
            <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>input</Text>

            <Text style={{ color: ui().muted }}>Name (controlled, maxLength 20)</Text>
            {nameField()}
            {count()}

            <Text style={{ color: ui().muted }}>Password</Text>
            {passwordField()}

            <Text style={{ color: ui().muted }}>Notes (multiline)</Text>
            {notesField()}

            {signInButton()}
            <Text style={{ color: ui().up }}>{submitted()}</Text>
          </View>
        )
      }
    </View>
  );
}

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

fn name_field() -> impl IntoElement {
    let name = signal(String::new());
    input()
        .value(name)
        .on_change(move |text: &str| name.set(text.to_string()))
        .placeholder("Your name")
        .auto_capitalize(AutoCapitalize::Words)
        .return_key_type(ReturnKeyType::Done)
        .text_base()
        .p_3()
        .border_1()
        .border_color(rgb(0xd0d7de))
        .rounded(px(8.0))
}

#Controlled और uncontrolled

  • Controlled: value पास करें और उसे onChange में अपडेट करें। ऐप उपयोगकर्ता के टाइप किए हुए टेक्स्ट को बदल सकता है (trim करना, format करना): टेक्स्ट में edit तुरंत दिखता है और नया value आते ही उसे सुधार दिया जाता है। हर native edit के साथ एक count होता है, और ऐप से आया value तभी लागू होता है जब वह नवीनतम edit पर आधारित हो, इसलिए नई टाइपिंग हमेशा धीमे अपडेट पर भारी पड़ती है।
  • Uncontrolled: defaultValue पास करें (.default_value(..), या कुछ नहीं) और टेक्स्ट को onChange या onSubmit से पढ़ें।

जो नियम उपयोगकर्ता के टाइप करते समय लागू रहने चाहिए, वे props हैं और native रूप से संभाले जाते हैं: maxLength लंबाई सीमित करता है और submitBehavior तय करता है कि return क्या करेगा। देखें forms और keyboard।

#Props

common props के अलावा (style का type TextStyle है: font, color, alignment और view styles लागू होते हैं):

#Text

PropRustTypeDefaultDescription
value.value(..)stringटेक्स्ट, जिसे ऐप नियंत्रित करता है।
defaultValue.default_value(..)stringशुरुआती टेक्स्ट।
placeholder.placeholder(..)stringinput खाली होने पर दिखता है।
multiline.multiline(..)booleanfalseकई पंक्तियाँ; return line break जोड़ता है, जब तक submitBehavior कुछ और न कहे।
scrollbar.scrollbar(..)boolean | ScrollbarThemetruemultiline input का scroll bar: प्लेटफ़ॉर्म का indicator, या ऐप का built-in bar जब ऐप ने कोई सेट किया हो (Scrollbar); object का अपना अलग theme होता है, false का मतलब कोई नहीं।
maxLength.max_length(..)numberउपयोगकर्ता अधिकतम कितने characters दर्ज कर सकता है।
readonly.readonly(..)booleanfalseउपयोगकर्ता टेक्स्ट select और copy कर सकता है, लेकिन बदल नहीं सकता।
masked.masked(..)booleanfalseटेक्स्ट छिपा रहता है (passwords)।
allowFontScalingbooleantrueसिस्टम के टेक्स्ट आकार का पालन करें।
maxFontSizeMultipliernumber0सिस्टम scale की ऊपरी सीमा (0 का मतलब कोई सीमा नहीं)।

#Keyboard

PropRustTypeDefaultDescription
keyboardType.keyboard_type(KeyboardType::Email)"default" | "number-pad" | "decimal-pad" | "numeric" | "numbers-and-punctuation" | "email-address" | "phone-pad" | "url""default"keyboard layout (values; iOS पर numbers-and-punctuation में minus sign होता है)।
returnKeyType.return_key_type(ReturnKeyType::Next)"default" | "done" | "go" | "next" | "search" | "send""default"return key का label।
autoCapitalize.auto_capitalize(AutoCapitalize::None)"none" | "sentences" | "words" | "characters""sentences"अपने-आप capitalization।
autoCorrect.auto_correct(..)booleantrueसिस्टम के सुधार।
autoComplete.auto_fill(AutoFill::OneTimeCode)AutoComplete | TextContentTypeinput में क्या है, iOS, Android और web पर autofill के लिए: "username", "current-password", "new-password", "one-time-code", "email", "tel", "postal-code", "cc-number", "off", …
pasteBehavior.paste_behavior(PasteBehavior::Report)"insert" | "report""insert"paste क्या करता है: "insert" paste किया हुआ टेक्स्ट जोड़ता है, "report" कुछ नहीं जोड़ता, ताकि ऐप onPaste की रिपोर्ट को संभाल सके। Images और files कभी नहीं जोड़ी जातीं।
submitBehavior.submit_behavior(SubmitBehavior::Submit)"submit" | "blurAndSubmit" | "newline""blurAndSubmit" (single line), "newline" (multiline)return क्या करता है: "submit" onSubmit रिपोर्ट करता है और focus बनाए रखता है, "blurAndSubmit" focus भी हटा देता है, "newline" line break जोड़ता है (multiline; single line submit करती है)। जो multiline input submit करता है, वह hardware keyboards पर Shift+Return या Option / Alt+Return से line break फिर भी लेता है। "submit" keyboard को ऊपर रखता है (जैसे कई संदेश भेजने के लिए)।
autoFocus.auto_focus(..)booleanfalseदिखते ही focus पा लेता है।

#Caret और selection

PropRustTypeDescription
caret.caret(..)booleancaret बनाया जाता है (default true; false उसे छिपा देता है)।
selectedRange.selected_range((start, end)){ start: number; end?: number }नियंत्रित selection, UTF-16 units में; end का default start है (एक caret)।

caret तब तक blink करता है जब तक उसकी window दिख रही और active है। Linux पर GPUI windows में, GTK ऐप्स की तरह, टाइप करने या उसे हिलाने के दस सेकंड बाद वह स्थिर दिखता रहता है, इसलिए अकेला छोड़ा गया focused field कोई frames खर्च नहीं करता।

#Colors

placeholder, caret और selection highlight के colors style keys हैं, अपनी Tailwind classes के साथ, और Rust में methods हैं (UIKit caret और selection को एक ही color से tint करता है, और caret का color सेट होने पर वही लेता है):

Style keyRustClassDescription
placeholderColor.placeholder_color(..)placeholder:text-*placeholder का color।
caretColor.caret_color(..)caret-*caret का color।
selectionColor.selection_color(..)selection:text-*selection highlight का color।
input()
    .placeholder("Search")
    .text_color(rgb(0x18181b))
    .placeholder_color(rgb(0x9ca3af))
    .caret_color(rgb(0x2563eb))
    .selection_color(rgb(0x93c5fd))

#iOS

ios keyRustTypeDescription
textContentType.auto_fill(..)AutoComplete | TextContentTypeautoComplete के लिए iOS के नाम ("oneTimeCode", "newPassword", …)।
inputAccessoryViewID.input_accessory(id)stringinput के focus में रहते समय keyboard के ऊपर दिखने वाले InputAccessoryView (InputAccessoryView) का nativeID।
keyboardAppearance.keyboard_appearance(KeyboardAppearance::Dark)"default" | "light" | "dark"keyboard का रूप; "default" सिस्टम के appearance का पालन करता है। Android के keyboards सिस्टम के theme का पालन करते हैं।
use nsh_core::element::AutoFill;

input().auto_fill(AutoFill::OneTimeCode).keyboard_type(KeyboardType::Number)

#Events

EventRustPayloadWhen
onChange.on_change(|text: &str| ..){ value }उपयोगकर्ता ने टेक्स्ट बदला: value अब का टेक्स्ट है।
onSubmit.on_submit(|text: &str| ..){ text }उस input में return key दबाई गई जो submit करता है (single line, या submitBehavior "submit" / "blurAndSubmit")।
onFocus / onBlur.on_focus / .on_blurकोई नहींinput को focus मिला / उसने focus खोया।
onSelectionChange.on_selection_change(|s: &Selection| ..){ start, end }caret या selection हिला (UTF-16 units)।
onPaste.on_paste(|e: &PasteEvent| ..){ text, html, files, uris }उपयोगकर्ता ने paste किया: टेक्स्ट, उसकी formatting HTML के रूप में (Linux, web), images (screenshot) File के रूप में, local files के file: URLs। जो टेक्स्ट वह जोड़ता है उसके onChange से पहले (forms और keyboard)।
onCaretMove.on_caret_move(|e: &CaretEvent| ..){ bounds, pageBounds }caret हिला, selection के साथ या टेक्स्ट के scroll या wrap होने पर: bounds input में उसकी जगह है, pageBounds window में, और anchor एक Overlay का (forms और keyboard)।
onKeyPress.on_key_press(|key: &str| ..){ key }टेक्स्ट बदलने से पहले: key टाइप किया गया टेक्स्ट है, "Backspace" या "Enter"।
onContentSizeChange.on_content_size_change(|size: &Size<Points>| ..){ size }टाइप करते समय टेक्स्ट का आकार बदला (multiline होने पर input की चौड़ाई पर); खाली input एक खाली पंक्ति रिपोर्ट करता है, उसका placeholder चाहे जो हो।
onCompositionChange.on_composition_change(|e: &Composition| ..){ composing, text }input method की composition शुरू हुई, बदली या समाप्त हुई: text वह है जो compose हो रहा है (character चुनने से पहले pinyin, conversion से पहले kana), समाप्त होने पर ""। committed टेक्स्ट समाप्ति से पहले onChange तक पहुँचता है।

एक multiline input जो अपने टेक्स्ट के साथ बढ़ता है:

let height = signal(px(40.0));

input()
    .multiline(true)
    .on_content_size_change(move |size: &Size<Points>| {
        height.set(px((size.height.0 + 16.0).clamp(40.0, 120.0)));
    })
    .h(move || height.get())
    .px_3()
    .py_2()

#Ref methods

MethodRustDescription
focus()focus()input को focus करता है और keyboard दिखाता है।
blur()blur()उसका focus हटाता है।
setSelection(start, end?)set_selection(start, end)start..end को select करता है (UTF-16 units); दोनों बराबर हों तो caret।

return पर अगले field पर focus ले जाना:

use nsh_core::element::AutoFill;

let password = element_ref();

view()
    .child(input().return_key_type(ReturnKeyType::Next).on_submit(move |_: &str| password.focus()))
    .child(input().element_ref(&password).masked(true).auto_fill(AutoFill::Password))

nsh का Keyboard.dismiss() (Rust में dismiss_keyboard()) keyboard को छिपा देता है, चाहे वह किसी भी input के पास हो।

#Platform notes

  • macOS पर, single-line टेक्स्ट, placeholders और carets native field के font metrics साझा करते हैं और content box के भीतर साथ-साथ केंद्रित होते हैं। lineHeight layout में भाग लेता है; multiline editors इसे paragraph spacing के लिए भी उपयोग करते हैं।
  • scroll view के अंदर के inputs native रूप से keyboard से दूर रखे जाते हैं। अन्यत्र env(keyboard-inset-height) का bottom padding या margin उपयोग करें।
  • disabled input को disable करता है (कोई focus नहीं) और disabled styles भी लागू करता है; readonly input अपना focus और selection बनाए रखता है।
  • inputAccessoryViewID iOS पर लागू होता है, जहाँ keyboard में accessory bar होती है।