تُرجمت هذه الصفحة آليًا وقد تحتوي على أخطاء. اقرأ الأصل الإنجليزي

التوثيق

النص

يُعرض كل النص عبر عناصر النص: text(..) في Rust، و<Text> في TSX. عنصر النص هو فقرة واحدة، يتولى محرك النص في المنصة (CoreText على منصات Apple، وStaticLayout على Android) تنسيقها على خيط المحرك عند إجراء التخطيط، ولا تُرسم إلا على الخيط الرئيسي. عناصر النص المتداخلة هي spans ضمن الفقرة نفسها، وليست views منفصلة.

text("By continuing you agree to the ")
    .text_size(px(16.0))
    .line_height(px(24.0))
    .text_color(rgb(0x1f2328))
    .child(
        text("Terms of service")
            .text_color(rgb(0x0969da))
            .underline()
            .on_press(open_terms),
    )
    .child(".")

العنصر نفسه موثّق في text؛ أما هذه الصفحة فتتناول طريقة استخدامه.

#السلاسل النصية والمسافات البيضاء

في Rust، محتوى النص سلسلة نصية تُعرض كما كُتبت: \n يكسر السطر. أما المحتوى الذي يقرأ signals فيكون closure، ويتحدّث النص عند تغيّرها. في TSX، يتبع نص JSX القواعد نفسها كما في React: يُقصّ كل سطر، وتُحذف الأسطر التي تحتوي على مسافات بيضاء فقط، وتُدمج الأسطر المتبقية بمسافة واحدة. تُحفظ المسافات البيضاء داخل السطر الواحد، لذا يحتفظ {first} {last} بمسافته. استخدم {" "} لإضافة مسافة في بداية السطر أو نهايته، و{"\n"} لكسر السطر:

text(move || format!("Hello, {}!\nWelcome back.", name.get()))

تتبع التعبيرات داخل النص ما تقرؤه: يتحدّث text(move || format!("{} items", count.get())) و<Text>{count()} items</Text> عندما يتغيّر count.

#الـ spans والوراثة

النص داخل نص آخر هو span. يرث نمط النص من أصله ويتجاوز ما يحدّده بنفسه:

text("")
    .text_size(px(17.0))
    .text_color(rgb(0x1f2328))
    .child(text("Light ").font_weight(FontWeight::LIGHT))
    .child(text("Bold ").font_weight(FontWeight::BOLD))
    .child(text("Italic ").italic())
    .child(text("Spaced").letter_spacing(px(4.0)))

تنتقل أنماط النص أيضًا من الـ views إلى أبنائها، كما في CSS: يطبّق view().text_color(white()).text_sm() في Rust و<View class="text-white text-sm"> في TSX النمط على عناصر النص والإدخال داخلها.

#الروابط

الـ span الذي يملك معالج ضغط (.on_press(..) أو .on_long_press(..)؛ onPress أو onLongPress) يكون رابطًا: يذهب الضغط على حروفه إلى الـ span، ويذهب الضغط في أي مكان آخر إلى الفقرة. وتعمل الروابط في الـ spans المتداخلة أيضًا.

text("Read the ")
    .on_press(move || tapped.set("the sentence"))
    .child(text("terms").text_color(rgb(0x0969da)).on_press(move || tapped.set("terms")))
    .child(" first.")

#خلفيات الـ spans

يرسم لون خلفية الـ span ونصف قطر زواياه مربعًا خلف حروفه في كل سطر يمتد إليه، بارتفاع خطه؛ ويبقى تخطيط النص كما هو وينسخ كاملًا، لذا يكون الكود المضمّن span (عنصر النص):

text("Run ")
    .child(text(" npm test ").font_family("ui-monospace").bg(rgb(0xeff1f3)).rounded(px(4.0)))
    .child(" first.")

#الـ views والصور داخل النص

أي عنصر غير النص داخل نص يُخطَّط ضمن السطر، على خط الأساس، ويلتف مع الكلمات. ويمكنه استقبال ضغطاته الخاصة:

text("Made with ")
    .text_size(px(16.0))
    .line_height(px(26.0))
    .child(image(LOGO).size(px(18.0)))
    .child(" nsh. Status ")
    .child(
        view()
            .bg(rgb(0x1a7f37))
            .rounded(px(9.0))
            .px(px(7.0))
            .h(px(18.0))
            .justify_center()
            .child(text("LIVE").text_color(white()).text_size(px(11.0)).font_weight(FontWeight::BOLD)),
    )

تُخفى العناصر المضمّنة التي يقطعها numberOfLines أو علامة الحذف؛ ولا يتضمنها النص المنسوخ. ويأخذ النص داخل العنصر المضمّن لون النص المحيط به، كما يصل color في CSS إلى inline block، ما لم يحدّد لونه الخاص (كما تفعل الشارة LIVE أعلاه)؛ ويبقى خطه وارتفاع سطره خاصَّين به.

يحدّد مفتاح النمط verticalAlign موضع العنصر المضمّن في سطره، كما يحدّد vertical-align في CSS موضع الصورة: "baseline" (الافتراضي) يضع قاعدته على خط الأساس، ويضع "text-top" و"text-bottom" أعلاه أو أسفله عند أعلى خط النص أو أسفله، ويوسّطه "middle" على ارتفاع نصف ارتفاع x للخط فوق خط الأساس. ويكبر السطر ليتّسع للعنصر حيثما تجاوز الخط، وكذلك مع lineHeight ثابت. الأيقونة في بداية الفقرة التي يجب أن تصطف مع أسفل النص، كما يرسمها ImageSpan في Android، تأخذ "text-bottom". الفئات هي align-baseline وalign-text-top وalign-text-bottom وalign-middle؛ وفي Rust .align_text_bottom() وغيرها بالأسماء نفسها.

<Text style={{ fontSize: 16 }}>
  <Image src={badge} style={{ width: 16, height: 16, verticalAlign: "text-bottom" }} /> Verified seller
</Text>

#أنماط النص

الخاصيةالقيمRust
colorلون. الافتراضي أسود.text_color(..)
fontSizeنقاط. الافتراضي 14.text_size(px(..))، .text_sm()، .text_lg()، …
fontWeight"normal" (400)، "bold" (700)، أو 100–900 (رقم أو سلسلة نصية).font_weight(FontWeight::BOLD)
fontStyle"normal"، "italic": تبقى رموز emoji الملوّنة مستقيمة.italic()
fontFamilyعائلة خطوط النظام، أو عائلة عامة، أو خط مستورد.font_family(..)
lineHeightنقاط.line_height(px(..))
letterSpacingنقاط.letter_spacing(px(..))
textAlign"auto"، "left"، "center"، "right"، "justify"، "start"، "end": يحافظ left وright على جانبيهما الأيمن والأيسر ثابتين، بينما يتبع start وend الاتجاه.text_left()، .text_center()، .text_right()، .text_justify()
textAlignVertical"auto"، "top"، "center"، "bottom": موضع النص الأقصر من صندوقه
textTransform"none"، "uppercase"، "lowercase"، "capitalize".normal_case()، .uppercase()، .lowercase()، .capitalize()
textDecorationLine"none"، "underline"، "line-through"، "underline line-through".no_underline()، .underline()، .line_through()
textDecorationColor، textDecorationStyleلون؛ "solid"، "double"، "dotted"، "dashed"، "wavy".text_decoration_color(..)، .text_decoration_wavy()، …
textDecorationThickness، textUnderlineOffsetنقاط، أو "auto" (والسماكة أيضًا "from-font").text_decoration_thickness(px(..))، .underline_offset(px(..))
textShadowtext-shadow في CSS، ظل خلف الحروف: "2px 2px 4px rgb(0 0 0 / 0.6)" (الإزاحات، التمويه، اللون)، أو طبقاته كأرقام، [{ x: 2, y: 2, blur: 4, color: "#00000099" }]؛ وعند وجود عدة طبقات يُرسم الأوسع.text_shadow([TextShadow { .. }])، .text_shadow_sm()، …، .text_shadow_color(..)
fontVariantميزات OpenType: ["tabular-nums"]، "small-caps"، "oldstyle-nums"، "lining-nums"، "proportional-nums".tabular_nums()، .small_caps()، .oldstyle_nums()، .lining_nums()، .proportional_nums()
writingDirection"auto"، "ltr"، "rtl": الاتجاه الأساسي للفقرة.writing_direction(WritingDirection::Rtl)

عنصر النص هو أيضًا view: فهو يقبل الخلفيات والحدود والزوايا والحشو وبقية أنماط الـ view.

text(move || format!("{:.2}", price.get())).text_size(px(18.0)).tabular_nums()
text("Typo").underline().text_decoration_wavy().text_decoration_color(rgb(0xcf222e))
text("Shadow")
    .text_size(px(26.0))
    .font_weight(FontWeight::EXTRA_BOLD)
    .text_color(white())
    .text_shadow([TextShadow {
        offset_x: px(2.0),
        offset_y: px(2.0),
        radius: px(4.0),
        color: rgba(0x00000099).into(),
    }])

يمنح tabular-nums كل رقم العرض نفسه، مما يمنع العدّادات والأسعار من الاهتزاز عند تغيّرها.

#الاقتطاع

text(long_description).number_of_lines(2)
text(file_path).number_of_lines(1).text_overflow(EllipsizeMode::Middle)
مفتاح النمط / الخاصيةRustالوصف
numberOfLines (نمط).number_of_lines(n)أقصى عدد من الأسطر المعروضة؛ 0 (الافتراضي) يعرضها كلها
textOverflow (نمط).text_overflow(EllipsizeMode::Middle)كيفية قطع النص الذي لا يتسع: علامة حذف في النهاية ("ellipsis"، الافتراضي)، أو في البداية ("ellipsis-start")، أو في المنتصف ("ellipsis-middle")، أو "clip"
adjustsFontSizeToFit.shrink_to_fit(min_scale)تصغير الخط حتى يتسع النص لأسطره وصندوقه
minimumFontScaleمدى التصغير المسموح به لـ adjustsFontSizeToFit (0–1)
text(move || total.get())
    .number_of_lines(1)
    .shrink_to_fit(0.5)
    .text_size(px(48.0))
    .w(px(200.0))

تضبط فئات Tailwind ‏line-clamp-* وtext-ellipsis وtext-clip المفاتيح نفسها، ويمثّل truncate (.truncate()) سطرًا واحدًا مقطوعًا بعلامة حذف؛ وبوصفها مفاتيح نمط فإنها تقبل أيضًا أنماط الحالة والمتغيّرات.

#حجم نص النظام

يتبع النص إعداد حجم النص لدى المستخدم (Dynamic Type على iOS، وحجم الخط على Android) افتراضيًا.

الخاصيةRustالوصف
allowFontScaling.allow_font_scaling(false)false يُبقي الحجم ثابتًا. الافتراضي true
maxFontSizeMultiplier.max_font_size_multiplier(1.5)أكبر مقياس يُطبَّق، مثل 1.5. 0 يعني بلا حد

يمثّل font_scale() في Rust وfontScale() من nsh في TSX المقياس الحالي، ويتغيّران عندما يغيّر المستخدم الإعداد. وتقبل حقول الإدخال allowFontScaling وmaxFontSizeMultiplier أيضًا.

text("Tab label").max_font_size_multiplier(1.3).text_size(px(13.0))

يُفضَّل تحديد المقياس على إيقافه: فالنص الكبير إعداد لإمكانية الوصول يعتمد عليه الناس.

#التحديد

يتيح مفتاح النمط userSelect: "text" (.select_text()، والفئة select-text) للمستخدم تحديد النص ونسخه، كما في عروض النص الأصلية في النظام: الضغط المطوّل يحدد الكلمة تحت الإصبع، وتحرّك المقابض طرفي التحديد، وتقدّم قائمة التحرير خيارَي Copy وSelect All (ويضيف iOS خيارات Look Up وTranslate وShare؛ وAndroid خيار Share). يبقى التحديد داخل كتلة نص واحدة. ويلوّن مفتاح النمط selectionColor (.selection_color(..)، selection:text-*) التمييز والمقابض. وما يُضبط بـ userSelect على view يصل إلى النصوص داخله التي لم تضبط شيئًا.

في متصفحات سطح المكتب يكون النص قابلًا للتحديد افتراضيًا، كما في صفحة الويب، باستثناء العناصر التفاعلية (الـ views التي لها معالجات ضغط أو لمس، مثل الأزرار والصفوف القابلة للضغط)؛ ويبقي userSelect: "none" (.select_none()، والفئة select-none) النص غير قابل للتحديد هناك. أما متصفحات الهاتف واللوح فتتبع القاعدة الأصلية.

text(order_number).select_text().selection_color(rgb(0x7c3aed))

للنسخ من الكود (زر Copy) استخدم set_clipboard(..) في Rust أو Clipboard في TSX.

#onTextLayout

يعيد onTextLayout (الحدث TextLayout في Rust) الأسطر المخطَّطة بعد كل تخطيط، ضمن صندوق محتوى النص:

text(move || body.get()).on(EventKind::TextLayout, move |e: &EventPayload| {
    if let EventPayload::TextLayout(laid_out) = e {
        lines.set(laid_out.len());
    }
})

لكل سطر text وx وy وwidth وheight وascender وdescender وcapHeight وxHeight (cap_height وx_height في Rust). استخدمه لإظهار زر “Read more” فقط عندما يُقطع النص، أو لمحاذاة محتوى آخر مع خط أساس.

#إمكانية الوصول

يقرأ قارئ الشاشة عنصر النص بوصفه محتواه. امنح دورًا للنص الذي يعمل كعنوان (.role(AccessibilityRole::Header)، role="header") وللروابط (AccessibilityRole::Link، role="link"). راجع إمكانية الوصول.

#ذات صلة