التخطّي إلى المحتوى
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
البدءWebReactSwiftUIJetpack ComposeFlutterReact Nativeالإعدادات الجاهزةنظام التصميم الخاص بكاستخدام Tanrei مع وكلاء الذكاء الاصطناعيالعلامة التجاريةرموز التصميمأنظمة التصميم والتخصيصTheme Studioاللونالطباعةالأيقوناتالشكلالارتفاعالحركةحالات التفاعلالسلوكالتخطيطإمكانية الوصولالكلماترموز الألوانرموز السلّم الطباعيرموز الشكلرموز الارتفاعرموز الحركةرموز الحالةرموز التباعد والقياسالمكوّناتالزرزر الإجراء الرئيسيالزر المقسَّممجموعة الأزرارزر مع قائمةشريط الأدواتزر النسخخانة الاختيارزر الاختيارمفتاح التبديلالرقاقةقائمة الخياراتشريط التمريرحقل شريط التمريرالتقويمDateTimePickerمجموعة الحقولمجموعة أزرار الاختيارمجموعة خانات الاختيارعنصر الاختيارحقل الاختيارشريط القوائمرفع الملفاتمنتقي الملفات متقدّمساحة الإفلاتحقل إدخال النص متقدّمحقل النصحقل الرقاقاتالحقلمربع التحرير والسرد متقدّمحقل التحرير والسردحقل إدخال العدد متقدّمحقل العددحقل إدخال اللون متقدّمحقل اللونحقل إدخال الرمز لمرة واحدة متقدّمحقل الرمز لمرة واحدةحقل إدخال النص المدمج متقدّممربع كتابة الرسائلالبطاقةالفاصلالطبقة النمطية متقدّممربع الحوارالقائمة (list)صف القائمةاللوحة السفليةاللوحة الجانبيةالعرض الدوّاركتلة الشيفرةالجدولاللوحة المنبثقةالخطواتالأكورديونقائمة الوصفالشكل التوضيحيهيكل التطبيقرأس الصفحةالعرض الشجريالخط الزمنيمعاينة الصورمقبض تغيير الحجمالإطار القابل لتغيير الحجممنطقة التمريرالشارةمؤشر التقدمالعدّادعارض الأرقام المتحرّكمؤشر التحميلشريط الإشعار (Snackbar)التلميحاختصار لوحة المفاتيحالوسمالشيفرة المضمَّنةالتنويهالصورة الرمزيةالحالة الفارغةمجموعة الوسومهيكل التحميلعنصر الملفمربع اللونالنص المتحركعلامات التبويبعرض التبويباتشريط التطبيقشريط التنقلدرج التنقلالبحثالرابطالتنقل بين الصفحاتروابط السابق والتاليمؤشر الخطواتمسار التنقلجدول المحتوياتبطاقة الرابطقائمة FABالحالةكيف يُبنى Tanreiالمساهمةالترخيص والإسناد
الرئيسيةالمكوّناتشريط الإشعار (Snackbar)

شريط الإشعار (Snackbar)

يخبر الشخص بإيجاز، عند الحافة السفلية للشاشة أو عند طرف حافتها العليا، بما فعله التطبيق للتو، مع إجراء واحد على الأكثر، من دون أن يأخذ التركيز أو يقاطع عمله.

content_copyعرض بتنسيق Markdown
الفئة
التواصل
الرموز
comp.snackbar
المستوى
أساسي

نظرة عامة

Web
tanrei-snackbar
schedule
SwiftUI
TanreiSnackbar
schedule
Jetpack Compose
TanreiSnackbar
schedule
Flutter
TanreiSnackbar
schedule
React Native
Snackbar
schedule

مولَّد من docs/status/status.json, specs/snackbar.spec.json

مواصفة معدَّلة، لم تصل بعد إلى كل منصة

تصف هذه الصفحة شريط الإشعار كما هو في المواصفة الآن: شريط يُرسم على سطح من المخطط اللوني أو معكوسًا (inverse)، وإجراء هادئ من الطراز tonal، وهيئات حالة بصبغات هادئة، وعنوان، ونص يتوسع. الويب يرسم ذلك كله. ويبقى معلَّمًا أعلاه بأنه متأخر إلى أن تُراجَع هيئات الحالة المعكوسة فيه وتُسجَّل صورها المرجعية. أما SwiftUI و Compose و Flutter و React Native فتقدّم مراجعة سابقة، وفيها إجراء من الطراز text، وبلا هيئات حالة ولا عنوان ولا توسيع ولا inverse، وتعرض عيّناتها تلك المراجعة إلى أن تلحق بالمواصفة. والعروض الحية هي مكوّن الويب كما يُقدَّم اليوم.

مرسوم في مكانه: رسالة مع إجراء، وأخرى مع زر إغلاق

الاستخدام

لا تضع شريط الإشعار في مكانه بنفسك، بل تطلب من مضيف (host) أن يعرضه، فيُدرجه المضيف في قائمة الانتظار، ويضعه في أسفل مساحته أو عند طرف أعلاها، ويُنهي مهلته، ويُعلِنه. تُحسم نتيجة show حالما يُغلق ذلك الشريط: بالقيمة action حين يُفعَّل إجراؤه، أو بالقيمة dismiss مع السبب. وهكذا تُقرأ شيفرة «التراجع» من الأعلى إلى الأسفل.

المنصة المضيف عرض شريط إشعار
Web <tanrei-snackbar-host>، يوضع آخر عنصر في الصفحة host.show(options)، وهو وعد (promise)
SwiftUI TanreiSnackbarHost، يُلحق بالمُعدِّل .tanreiSnackbarHost(_:) await host.show(message:…)
Compose TanreiSnackbarHost(hostState)، الأخير في Box مع المحتوى hostState.showSnackbar(message, …)، وهو استدعاء معلِّق (suspending)
Flutter TanreiSnackbarMessenger، حول الصفحة التي يبلّغ عنها TanreiSnackbarMessenger.of(context).show(TanreiSnackbar(…))، وهو متحكِّم (controller) قيمة closed فيه future
React Native يعرضه TanreiProvider في طبقة التراكب الخاصة به useSnackbar().show(options)، وهو وعد

كل مضيف يغلق كذلك الشريط المعروض (dismissCurrent) ويُسقط الأشرطة المنتظرة أيضًا (clear)، وكلاهما بالسبب host. وعنصر شريط الإشعار المرسوم خارج مضيف يُرسم في مكانه، موسَّطًا على العرض المعطى له كما يوسّطه المضيف (أو عند نهاية ذلك العرض حين تكون قيمة placement هي top-end): بلا مهلة ولا قائمة انتظار ولا حركة دخول ولا إعلان. هذه الهيئة لصفحات التوثيق والاختبارات، مثل العرض أعلاه.

<!-- الأخير في الصفحة: موضع المضيف في ترتيب التركيز هو حيث تكون عناصر التحكم في شريط الإشعار. -->
<tanrei-snackbar-host></tanrei-snackbar-host>

<script type="module">
  import '@tanrei/web/components/snackbar';
  const snackbars = document.querySelector('tanrei-snackbar-host');

  async function archive() {
    await archiveConversation();
    // تُحسم النتيجة حالما يُغلق: { result: 'action' } أو { result: 'dismiss', reason }.
    const { result } = await snackbars.show({ message: 'أُرشفت المحادثة', action: 'تراجع' });
    if (result === 'action') await restoreConversation();
  }

  // هيئة حالة: الأيقونة، والحالة بالكلمات للتقنيات المساعدة.
  snackbars.show({
    status: 'error',
    statusLabel: 'خطأ',
    title: 'لم تُرسل الرسالة',
    message: 'أنت غير متصل. ستبقى الرسالة في صندوق الصادر.',
    action: 'إعادة المحاولة',
    expandLabel: 'عرض الرسالة كاملة',
  });

  // يُرسم معكوسًا، أيًّا كان ما يختاره نظام التصميم. اترك `inverse` لتأخذ اختيار النظام.
  snackbars.show({ message: 'نُسخ الرابط', inverse: true });
</script>
import { useRef } from 'react';
import { SnackbarHost } from '@tanrei/react';
import type { TanreiSnackbarHost } from '@tanrei/web';

// المرجع ref هو العنصر نفسه: الدالة show() إحدى دواله.
const snackbars = useRef<TanreiSnackbarHost>(null);

async function archive() {
  await archiveConversation();
  const { result } = await snackbars.current!.show({ message: 'أُرشفت المحادثة', action: 'تراجع' });
  if (result === 'action') await restoreConversation();
}

// هيئة حالة، مع عنوان فوق الرسالة.
snackbars.current?.show({ status: 'error', statusLabel: 'خطأ', title: 'لم تُرسل الرسالة', message: 'أنت غير متصل.', action: 'إعادة المحاولة' });

// يُرسم معكوسًا، أيًّا كان ما يختاره نظام التصميم.
snackbars.current?.show({ message: 'نُسخ الرابط', inverse: true });

// الأخير في الصفحة، بعد المحتوى.
<SnackbarHost ref={snackbars} />
import Tanrei

@State private var snackbars = TanreiSnackbarHost()

// ألحق المضيف بالعرض الذي يستخدم حافته السفلية. يرسم في تراكب، لا في sheet.
ContentView()
    .tanreiSnackbarHost(snackbars)

// يعود حالما يُغلق شريط الإشعار: .action أو .dismissed(reason).
// الطلب الموجَّه إلى مضيف عرضُه ليس على الشاشة ينتظر إلى أن يكون عليها.
let result = await snackbars.show(message: "أُرشفت المحادثة", actionLabel: "تراجع")
if case .action = result { restoreConversation() }
import io.github.chnotchy.tanrei.components.TanreiSnackbarHost
import io.github.chnotchy.tanrei.components.TanreiSnackbarHostState
import io.github.chnotchy.tanrei.components.TanreiSnackbarResult

// مثل SnackbarHostState في Material: showSnackbar يعلِّق إلى أن يُغلق شريط الإشعار.
val snackbars = remember { TanreiSnackbarHostState() }
val scope = rememberCoroutineScope()
Box(Modifier.fillMaxSize()) {
    Content(onArchive = {
        scope.launch {
            when (snackbars.showSnackbar("أُرشفت المحادثة", actionLabel = "تراجع")) {
                TanreiSnackbarResult.ActionPerformed -> unarchive()
                is TanreiSnackbarResult.Dismissed -> Unit
            }
        }
    })
    // الأخير في Box: يُرسم فوق المحتوى، والأخير في ترتيب التركيز.
    TanreiSnackbarHost(snackbars, Modifier.fillMaxSize())
}
import 'package:tanrei/tanrei.dart';

// مثل ScaffoldMessenger. ضعه حول الصفحة، داخل مسارها، ليغطيه مربع حوار يُفتح فوقها.
TanreiSnackbarMessenger(child: page);

Future<void> archive(BuildContext context) async {
  await archiveConversation();
  final TanreiSnackbarController snackbar = TanreiSnackbarMessenger.of(context).show(
    const TanreiSnackbar(message: 'أُرشفت المحادثة', actionLabel: 'تراجع'),
  );
  // يكتمل بالقيمة action أو close أو escape أو timeout أو host.
  if (await snackbar.closed == TanreiSnackbarClosedReason.action) {
    await restoreConversation();
  }
}
import { useSnackbar } from '@tanrei/react-native';

// المضيف يعيش في طبقة التراكب الخاصة بالمكوّن TanreiProvider: ضع provider في جذر تطبيقك.
const snackbar = useSnackbar();

async function archive() {
  await archiveConversation();
  const { result } = await snackbar.show({ message: 'أُرشفت المحادثة', actionLabel: 'تراجع' });
  if (result === 'action') await restoreConversation();
}

المواصفات

رسالة تلتف، وإجراء في صف خاص به

البنية

البنية

مرسوم فوق نموذج الاختبار message كما ترسمه حزمة الويب.
الجزء الوصف
1 container The bar that holds the text and the controls, raised above the content of its host. Its color is its form's: a surface of the scheme (the default form, or a faint tint of a status) or, drawn inverse, the opposite scheme's surface or, in a status form, the bar the other theme draws for that status: deep in a light scheme, pale in a dark one.
2 outline · اختياري The edge of a status form: a hairline in the status's color, at the edge's opacity, around the bar where the ring of its elevation is. The default form and the inverse form draw none and keep that ring alone.
3 icon · اختياري The status glyph from the system's icon set, before the text: info, warning, error or check_circle. Drawn only in a status form, a little softer than the text (in the status's own color on a surface and, on an inverse bar, in the status color of the other theme, at the glyph's opacity), and hidden from assistive technology, which hears statusLabel instead.
4 title · اختياري A few words that name what happened, above the message. Up to three lines while collapsed.
5 supporting-text The message: what happened, or with a title the description, which is then drawn a little quieter than the title. Up to three lines while collapsed.
6 action · اختياري One control that undoes or follows up on what happened, drawn as a tonal button with the snackbar's own tokens, as tall as the small Buttons beside it: the color of its own bar with a tonal layer of its label's color over it, so that it stands one quiet step off the bar, the same step in every form.
7 expand · اختياري An icon-only Button of the small size that shows the whole title and message, and hides them again: the glyph expand_more while collapsed and expand_less while expanded. Drawn only while the text is longer than its collapsed limit, and drawn as the close button is (SNK-34).
8 close · اختياري An icon-only Button of the small size showing the icon set's close glyph, which closes the snackbar. The snackbar places it, chooses its variant (comp.snackbar.close-button.variant: tonal in the default system) and gives it its form's tone (BTN-45): the glyph in the bar's message color and, where the variant draws a container, a circle of that color made translucent. Everything else it reads from Button's own tokens.
9 focus-ring · اختياري Gap-then-ring indicator shown for keyboard focus of the action, or of the text while it scrolls, in the color its form gives it so that it shows on that form's bar. The expand and close buttons draw their own, in the same color (SNK-34).

القياسات

القياسات

الطول الرمز القيمة (px)
container padding-inline-start tanrei.comp.snackbar.container.padding-inline-start 16
container padding-inline-end tanrei.comp.snackbar.container.padding-inline-end 16
مرسوم فوق نموذج الاختبار message كما ترسمه حزمة الويب.

الخصائص

الخاصية النوع القيمة الافتراضية الوصف
message string "" What happened; with a title, the description. Required. Plain text: the whole message is announced, even when a collapsed snackbar cuts it.
title string "" A few words above the message that name what happened ("Message not sent"). Empty draws the message alone.
action string "" The label of the one action ("Undo", "View"), drawn as a tonal button that sits one quiet step off the bar, the same step in every form. Empty draws no action.
status default | info | warning | error | success "default" The form of the snackbar. Default is the neutral bar with no glyph; info, warning, error and success draw the bar as a quiet tint of that status (pale on the scheme's surface or, drawn inverse, the bar the other theme draws for that status, with that theme's text, glyph and edge colors), with an edge in the status's color and the status's glyph before the text, and warning and error are announced assertively.
statusLabel string "" The status in words, in the product's language ("Error"), announced before the title and the message so that the status never rests on color and glyph alone. Required while status is not default.
inverse boolean null Whether this snackbar is drawn inverse: in the opposite scheme's colors (a dark bar in a light scheme), so that it stands apart from whatever it lands on. False draws it on a surface of the scheme. Null, the default, takes comp.snackbar.container.inverse, the system's choice, which is off in the default system. It changes colors only (SNK-30).
closable boolean false Draws a close button, for a message that stays until the person closes it or for one they may want gone sooner.
closeLabel string "" The close button's accessible name, in the product's language ("Close"). Required while closable is true.
expanded boolean false Whether the whole title and message show. The person toggles it with the expand button (SNK-24); it has no effect while the text fits within its collapsed limits.
expandLabel string "" The expand button's accessible name, in the product's language ("Show full message"). It stays the same while expanded; the button's expanded state says which way it acts. Required whenever the text can be longer than its collapsed limit.
duration auto | short | long | indefinite "auto" How long the snackbar stays by itself. Auto is short without an action and indefinite with one (WCAG 2.2.1: a person must not be timed out of an action). Short and long close after the snackbar's timeout tokens; indefinite stays until it is closed.
placement bottom | top-end "bottom" Where the host places the snackbar in its area. Bottom, the default, is the bottom edge, centred (SNK-13). Top-end is the top edge at the end side: the top right in a left-to-right layout and the top left in a right-to-left one, and across the top of a compact window (SNK-35). A host may be given one placement for all the snackbars it shows; a snackbar that names its own keeps it. It changes where the snackbar stands and the side it enters from (SNK-36, SNK-37), and nothing else: not its size, its form, its order in the queue, its place in the focus order or its announcement.

الأحداث

الحدث الوصف
action The action was activated. The snackbar closes.
dismiss The snackbar closed without its action; carries the reason: close (the close button), escape, timeout, or host (the product closed it or cleared the queue).
toggle The person expanded or collapsed the text with the expand button; carries the new expanded value. Not emitted when the product sets expanded.

الحالات

السلوك

متطلبات بصيغة EARS. يُختبر تنفيذ كل منصة مقابل هذه المعرّفات. يُعرض نص المتطلبات كما ورد في ملف المواصفة، بالإنجليزية.

المعرّف المتطلب
SNK-1 WHEN the user activates the action by pointer, touch, Enter or Space THE snackbar SHALL emit action exactly once and close; WHEN the user activates the close button the same way THE snackbar SHALL emit dismiss with the reason close exactly once and close.
SNK-2 WHILE the action is hovered, keyboard-focused or pressed THE snackbar SHALL render the action's container, content color and opacity from the component tokens of the highest-precedence active state of the action, in the snackbar's form (SNK-21, SNK-30), with precedence pressed over focused over hovered; focus gained by pointer or touch SHALL NOT select the focused state. The expand and close buttons answer their states as any Button does (SNK-34).
SNK-3 WHEN the action receives keyboard focus THE snackbar SHALL show the focus ring around it without animation; focus gained by pointer or touch SHALL NOT show it. THE snackbar SHALL draw the outer stroke of that indicator, of the indicator inside the text while it scrolls and has keyboard focus (SNK-25) and, through the tone it gives them (SNK-34), of the indicators of the expand and close buttons, in its form's focus-ring color: comp.snackbar.focus-ring.color in the default form, and the token of that name under the form's prefix in every other (comp.snackbar.info.focus-ring.color, comp.snackbar.inverse.focus-ring.color, comp.snackbar.inverse-info.focus-ring.color, and warning's, error's and success's of the same names), never the system's focus-ring color role read directly. The widths and the offset SHALL stay the system's (sys.focus.outer-width, sys.focus.inner-width, sys.focus.offset), as SHALL the color of an inner stroke where the system draws one; under the glow focus style (SNK-7) the form's color SHALL be the halo's outer color.
SNK-4 WHERE the visual size of the action is below the minimum target THE snackbar SHALL extend the action's hit area on both axes to sys.target.touch for touch input and sys.target.pointer for fine pointers, without changing its visual size; a platform that cannot tell the input type SHALL use sys.target.touch.
SNK-5 WHEN the action is pressed by pointer, touch, Enter or Space THE snackbar SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner.
SNK-6 WHILE the action is pressed THE snackbar SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container of the action at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole action and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; content color, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.snackbar.motion.feedback-duration with comp.snackbar.motion.state-easing, fades over comp.snackbar.motion.state-duration with comp.snackbar.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced.
SNK-7 THE snackbar SHALL ease its container corners and the action's corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0) and show its keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README.
SNK-8 WHILE duration is auto THE snackbar SHALL behave as short when action is empty and as indefinite when action is set. WHILE duration is short or long THE snackbar SHALL close by itself once it has been shown for comp.snackbar.timeout.short or comp.snackbar.timeout.long, and emit dismiss with the reason timeout; WHERE the platform recommends a longer time for the person's accessibility settings (Android's accessibility timeout) it SHALL use that time, and WHERE the platform reports that a screen reader is running a snackbar with an action SHALL NOT close by itself. WHILE duration is indefinite THE snackbar SHALL NOT close by itself.
SNK-9 WHILE the pointer is over the snackbar, focus is inside it, it is expanded, the app's window is hidden or in the background, or a Tanrei modal dialog covers its host THE snackbar SHALL pause its timeout, and WHEN none of these holds any longer SHALL start the timeout again from its whole length.
SNK-10 WHEN a snackbar is shown THE snackbar SHALL have assistive technology announce it once: statusLabel first when status is not default, then the title when it has one, then the whole message (never only the part a collapsed snackbar shows), then the action's label when it has one. It SHALL announce politely (after what is being read) when status is default, info or success, and assertively (interrupting what is being read) when status is warning or error, and SHALL NOT move keyboard or screen-reader focus.
SNK-11 THE snackbar's controls SHALL be reachable in the focus order at the place its host has in that order, in this order whatever row each is drawn on: the text while it scrolls (SNK-25), the action, the expand button, the close button; WHEN the user presses Escape while focus is inside the snackbar THE snackbar SHALL emit dismiss with the reason escape and close; WHEN a snackbar closes while focus is inside it, focus SHALL return to the element that had it before focus entered the snackbar or, where that element no longer exists, to the platform's default.
SNK-12 THE host SHALL show one snackbar at a time, in the order they were requested: WHEN a snackbar is requested while another is showing or closing it SHALL wait until the other has closed, and WHILE a Tanrei modal dialog covers the host a snackbar not yet shown SHALL wait until the dialog closes. Each request SHALL resolve once its snackbar has closed, with action or with dismiss and its reason. WHEN the product closes the showing snackbar THE host SHALL close it and resolve it with dismiss and the reason host, and the next waiting one SHALL then show; WHEN the product clears the queue THE host SHALL also drop every waiting one and resolve each with dismiss and the reason host.
SNK-13 WHILE placement is bottom THE host SHALL place the snackbar at the bottom of its area, centred, comp.snackbar.container.margin above the bottom edge and at least comp.snackbar.container.margin from the side edges, inside the safe area and above the on-screen keyboard; at either placement it SHALL draw the snackbar above its area's content and below a Tanrei modal dialog and its scrim.
SNK-14 THE snackbar SHALL be at least comp.snackbar.container.min-height tall and as wide as its content between comp.snackbar.container.min-width and comp.snackbar.container.max-width, but never wider than its host less comp.snackbar.container.margin on each side. It SHALL draw comp.snackbar.container.color, or its form's container color (SNK-21, SNK-30), with comp.snackbar.container.elevation and comp.snackbar.container.shape corners, and pad its content by comp.snackbar.container.padding-inline-start before the status glyph or, without one, before the text, by comp.snackbar.container.padding-block below the text and by at least as much above it, where SNK-29 places the first line, and after the text by comp.snackbar.container.padding-inline-end when there is no control or by comp.snackbar.container.padding-inline-end-with-controls after the last control. WHILE the action stands on its own row (SNK-16) and no control follows the text on its row, the text SHALL end comp.snackbar.container.padding-inline-end from the end edge, as in a snackbar without controls, and padding-inline-end-with-controls SHALL be the action row's alone.
SNK-15 THE snackbar SHALL draw the message in comp.snackbar.supporting-text.typescale and comp.snackbar.supporting-text.color, or its form's message color (SNK-21, SNK-30), at the opacity SNK-32 gives a message under a title, followed comp.snackbar.container.gap after the text (the title and the message) by the action, the expand button and the close button, in that order, comp.snackbar.controls.gap apart and centred on the text's first line (SNK-29). The action SHALL be drawn as a tonal button, in its form's action colors: a container of comp.snackbar.action.container.color at least comp.snackbar.controls.height tall (the height of a small Button, so that the action stands as tall as the expand and close buttons in its row), the tonal layer over it (SNK-33), and comp.snackbar.controls.padding-inline around its label in comp.snackbar.controls.label.typescale and comp.snackbar.action.content.color, on comp.snackbar.controls.shape corners. The expand and close buttons SHALL be drawn as SNK-34 says.
SNK-16 WHEN the text (the title and the message) would need more than two lines beside the controls, or the action's label would itself wrap, THE snackbar SHALL move the action onto its own row below the text, comp.snackbar.container.gap below it and aligned to the end, with comp.snackbar.container.padding-inline-end-with-controls between that row and the bar's bottom edge, while the expand and close buttons stay at the end of the first row; the text SHALL wrap, and is cut only as SNK-23 says, and the action's label SHALL never wrap or be truncated.
SNK-17 WHEN a snackbar is shown THE snackbar SHALL rise into place from below the bottom edge of its host by its own height plus its margin while fading in (WHILE placement is bottom; at top-end it descends instead, SNK-36), over comp.snackbar.motion.enter-duration with comp.snackbar.motion.enter-easing; WHEN it closes it SHALL fade out in place over comp.snackbar.motion.exit-duration with comp.snackbar.motion.exit-easing, and the host SHALL show the next one only after that. WHERE motion is reduced it SHALL fade in and out without moving, or appear and disappear at once on a platform whose reduced-motion setting removes every animation (Android's).
SNK-18 WHEN the layout direction is right-to-left THE snackbar SHALL mirror its layout (the status glyph and the text at the right, the controls at the left) without mirroring any glyph, and SHALL grow a ripple from the point of contact as in left-to-right.
SNK-19 WHILE a snackbar is drawn outside a host (a snapshot harness, a documentation page) THE snackbar SHALL draw in place at its resting position, centred across the width it is given as SNK-13 centres it in a host (or, WHILE placement is top-end, at the end of that width as SNK-35 places it, and across the whole of it where that width is narrower than comp.snackbar.breakpoint.medium) and at most as tall as the height it is given, the width and the height it is given standing for the host's area in SNK-25 and SNK-35; it SHALL NOT time out, queue, animate its entrance or announce itself, and SHALL still emit action, dismiss and toggle.
SNK-20 WHILE message is empty THE snackbar SHALL still render and in debug builds report the empty message; WHILE closable is true and closeLabel is empty it SHALL still render the close button and in debug builds report that the button has no accessible name; WHILE status is not default and statusLabel is empty it SHALL still render the status form and in debug builds report that the status is not given in words; WHILE the expand button is drawn and expandLabel is empty it SHALL still render it and in debug builds report that it has no accessible name; WHEN duration is short or long and action is set it SHALL, in debug builds, remind the product that a timed action must also be offered elsewhere.
SNK-21 WHILE status is info, warning, error or success THE snackbar SHALL draw that status form: the bar, the title, the message and the status glyph in the status's container, title, supporting-text and icon colors, and every state of the action from the parts prefixed with the status, and give the expand and close buttons the status's tone (SNK-34). For info, while the snackbar is not drawn inverse (SNK-30), these are comp.snackbar.info.container.color, comp.snackbar.info.title.color, comp.snackbar.info.supporting-text.color, comp.snackbar.info.icon.color, comp.snackbar.info.outline.color for its edge (SNK-31), comp.snackbar.action.info.container.color and comp.snackbar.action.info.content.color; warning, error and success read their own tokens of the same names, and a status form drawn inverse reads the tokens SNK-30 names. Before the text it SHALL draw the status's glyph from the system's icon set (info for info, warning for warning, error for error, check_circle for success) at comp.snackbar.icon.size, in its form's icon color drawn at comp.snackbar.icon.opacity (an opacity of the glyph alone, which fades nothing else), comp.snackbar.icon.gap before the text and centred on the text's first line (SNK-29), with the family and fill of an unselected icon, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, never mirrored. The glyph so drawn SHALL keep 3:1 against its bar in every scheme of the default system. The glyph SHALL be hidden from assistive technology, and statusLabel SHALL be exposed as text before the title and the message. WHILE status is default THE snackbar SHALL draw no glyph and read the unprefixed tokens, or drawn inverse the tokens prefixed with inverse (SNK-30).
SNK-22 WHILE title is not empty THE snackbar SHALL draw it above the message in comp.snackbar.title.typescale and comp.snackbar.title.color, or its form's title color (SNK-21, SNK-30), with comp.snackbar.title.gap between the title and the message; WHILE title is empty it SHALL draw the message alone. THE snackbar SHALL set the title's letter-spacing by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them.
SNK-23 WHILE expanded is false THE snackbar SHALL show at most comp.snackbar.title.max-lines lines of the title and at most comp.snackbar.supporting-text.max-lines lines of the message, each ending with an ellipsis where it is cut, at every text size, and the whole of both SHALL still reach assistive technology. WHILE the title or the message is longer than its collapsed limit THE snackbar SHALL draw the expand button, holding expand_more while collapsed and expand_less while expanded; WHILE both fit within their limits it SHALL NOT draw the expand button, and expanded SHALL have no effect. WHILE expanded is true THE snackbar SHALL show the whole title and message.
SNK-24 WHEN the user activates the expand button by pointer, touch, Enter or Space THE snackbar SHALL toggle expanded, emit toggle with the new value exactly once, keep focus on the expand button and stay open; the bar SHALL grow to its expanded height or shrink back over comp.snackbar.motion.expand-duration with comp.snackbar.motion.expand-easing, keeping its bottom edge in place WHILE placement is bottom and its top edge at top-end (SNK-37), and change at once where motion is reduced. The expand button SHALL expose to assistive technology whether the text is expanded and which text it shows and hides, and SHALL keep expandLabel as its name in both states. WHEN the product sets expanded THE snackbar SHALL change the same way without emitting toggle.
SNK-25 WHILE the snackbar is expanded and its whole content would make it taller than its host's area allows (the area's height less comp.snackbar.container.margin above and below, inside the safe area and above the on-screen keyboard) THE snackbar SHALL take that height and scroll its text inside the bar, keeping the status glyph, the controls and an action on its own row in place; WHILE the text scrolls it SHALL be reachable by keyboard (a focus stop, scrolled by the arrow keys, Page Up and Page Down), named by the title when there is one, and scrolled by wheel, trackpad and touch.
SNK-26 WHILE the system's icon set cannot yet draw a glyph of the snackbar (its font is still loading) — the status glyph, or the glyph it gives the expand or the close button — THE snackbar SHALL draw nothing in that glyph's place, never the glyph's name as text, SHALL keep the glyph's box, and SHALL draw the glyph once the set can; statusLabel, expandLabel and closeLabel SHALL still reach assistive technology.
SNK-27 THE snackbar SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the snackbar is shown THE snackbar SHALL draw itself for the new direction at once, without a motion of its own, keeping its open state, the time left before it closes and its focus.
SNK-28 THE snackbar SHALL lay out its title, its message and its action's label as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE snackbar SHALL still place each and align its lines by the layout direction, not by the text's own, and SHALL cut a title or a message cut by a line limit that does not fit (SNK-23) at the end of its own direction, so that a left-to-right label in a right-to-left layout loses its right end and never its beginning.
SNK-29 THE snackbar SHALL align its content to the top of the bar. It SHALL centre the first line of the text (the title's, or the message's without a title) half of comp.snackbar.container.min-height below the bar's top edge, or lower where comp.snackbar.container.padding-block plus half that line's height is more (enlarged text), and SHALL centre the status glyph and every control of the first row (the action while it is beside the text, the expand button and the close button) on that line; every further line of the text follows below it, an action on its own row (SNK-16) follows the text, and any height the bar has beyond its content SHALL lie below the content, never above it. WHEN the bar expands or collapses (SNK-24), and WHEN its text is cut or shown whole (SNK-23), the status glyph, the first line of the title and of the message, and every control of the first row SHALL keep their distance from the bar's top edge, during the motion and after it; an action on its own row SHALL keep its distance from the bar's bottom edge.
SNK-30 THE snackbar SHALL be drawn inverse WHILE inverse is true, or WHILE inverse is null and comp.snackbar.container.inverse is on; otherwise (inverse false, or null where that choice is off) it SHALL be drawn on a surface of the scheme, from the unprefixed tokens or its status form's (SNK-21). WHILE it is drawn inverse and status is default THE snackbar SHALL draw the bar, the title and the message in comp.snackbar.inverse.container.color, comp.snackbar.inverse.title.color and comp.snackbar.inverse.supporting-text.color, and every state of the action from the parts prefixed with inverse (comp.snackbar.action.inverse.container.color and comp.snackbar.action.inverse.content.color), and give the expand and close buttons that form's tone (SNK-34). WHILE it is drawn inverse and status is info, warning, error or success it SHALL draw that status's inverse form the same way, from the parts prefixed with inverse- and the status: for info comp.snackbar.inverse-info.container.color, comp.snackbar.inverse-info.title.color, comp.snackbar.inverse-info.supporting-text.color, comp.snackbar.inverse-info.icon.color, comp.snackbar.inverse-info.outline.color for its edge (SNK-31), comp.snackbar.action.inverse-info.container.color and comp.snackbar.action.inverse-info.content.color, and for warning, error and success their own tokens of the same names. Under the default system each color of a status's inverse form SHALL be the color the same part of that status's form not drawn inverse has in the scheme of the other theme at the same contrast level (light for dark, light-medium for dark-medium, light-high for dark-high, and each the other way): the bar, the title, the message, the glyph, the edge, the focus indicator, every state of the action and the tone of the expand and close buttons, so that the inverse form of a status in one theme and its form on a surface in the other differ only in what lies around the bar. Being drawn inverse SHALL change colors only: the bar's elevation, corners, sizes and layout, the glyphs, the width and the opacity of a status form's edge, the opacities of the glyph, of a message under a title and of the action's tonal layer, the motion, the timing, the announcement and the keyboard behaviour SHALL be those of the same snackbar not drawn inverse. WHEN inverse or the system's choice changes while the snackbar is shown THE snackbar SHALL draw the other form at once, keeping its open state, the time left before it closes and its focus.
SNK-31 WHILE status is info, warning, error or success THE snackbar SHALL draw its form's edge: a line comp.snackbar.outline.width wide around the bar, outside the bar's bounds and following its corners, where the ring of comp.snackbar.container.elevation lies (the layer of that elevation with no offset, no blur and a positive spread), over that ring and above the elevation's shadows, in the form's outline color drawn at comp.snackbar.outline.opacity: comp.snackbar.info.outline.color for info, comp.snackbar.inverse-info.outline.color for info drawn inverse (SNK-30), and warning's, error's and success's tokens of the same names. The edge SHALL NOT change the bar's size or the place of anything inside or around it, and the focus indicator of a control SHALL be drawn above it. WHILE status is default THE snackbar SHALL draw no edge of its own, drawn inverse or not: the ring of its elevation shows alone, as on every raised surface. WHERE comp.snackbar.outline.opacity is 0 a status form SHALL draw no edge either.
SNK-32 WHILE title is not empty THE snackbar SHALL draw the message at comp.snackbar.supporting-text.under-title.opacity: an opacity of the message's text alone, applied to its form's message color (SNK-15), in every form, collapsed and expanded. WHILE title is empty it SHALL draw the message whole, and it SHALL draw the title whole in every form. The message so drawn SHALL keep 4.5:1 against its bar in every scheme of the default system, and 7:1 in its high-contrast schemes; what assistive technology reads SHALL NOT change with it.
SNK-33 THE snackbar SHALL draw the action's tonal layer in every form and in every state of the action: the action's content color of that form and state, at comp.snackbar.action.tonal-layer.opacity, filling the action's container to its corners, above the container color of that state (SNK-2) and above a ripple that grows on it (SNK-6), and under the label. The layer is the action's alone, SHALL NOT take a press or change the action's size, and SHALL NOT be drawn WHERE comp.snackbar.action.tonal-layer.opacity is 0, where the action is its container alone. The label SHALL keep 4.5:1 against the action as drawn (the container color of the state with the layer over it) in every form, state and scheme of the default system, and 7:1 in its high-contrast schemes.
SNK-34 WHILE closable is true, and WHILE the expand button is drawn (SNK-23), THE snackbar SHALL draw that button, in the place SNK-15, SNK-16 and SNK-29 give it, as an icon-only Button of the small size showing a glyph of the system's icon set (close; expand_more or expand_less, SNK-23) and named by closeLabel or expandLabel, in the variant comp.snackbar.close-button.variant names and in the tone of the snackbar's form (BTN-45): the form's message color — comp.snackbar.supporting-text.color in the default form, and the token of that name under the form's prefix in every other (SNK-21, SNK-30) — with the form's focus-ring color (SNK-3) for its focus indicator, both given through the channel a Button reads from the component that places it, and otherwise unrestyled: it reads Button's own tokens for its size, glyph size, corners and state opacities, answers hover, focus and press as any Button does, and keeps its own minimum target (BTN-5). WHEN the snackbar's form changes while it is shown THE snackbar SHALL give the buttons the new form's tone with the new form's colors (SNK-30). THE snackbar SHALL draw no close or expand mark of its own (no path, shape or character of its own), and the expand button SHALL expose to assistive technology whether the text is expanded and which text it shows and hides (SNK-24).
SNK-35 WHILE placement is top-end THE host SHALL place the snackbar at the top of its area, at its end side (the right in a left-to-right layout and the left in a right-to-left one, taken from where the host is used as SNK-27 says), comp.snackbar.container.margin below the top edge and comp.snackbar.container.margin from the end edge, inside the safe area and below what the frame keeps over the top of the area (a sticky header's present height, APS-17), so that it never covers a top app bar; WHILE the area is narrower than comp.snackbar.breakpoint.medium (a compact window) it SHALL draw the snackbar across the top of the area instead, as wide as the area less comp.snackbar.container.margin on each side, within comp.snackbar.container.max-width. WHEN the product asks for a snackbar without a placement THE host SHALL give it the placement the host itself is given, and bottom where it is given none. The placement SHALL NOT change the snackbar's layer (SNK-13), its other size bounds (SNK-14), its place in the focus order (SNK-11) or its announcement (SNK-10), and the host SHALL still show one snackbar at a time, in order (SNK-12): at the top as at the bottom, a snackbar asked for while another shows waits for it to close, and no two are stacked.
SNK-36 WHILE placement is top-end, WHEN a snackbar is shown THE snackbar SHALL descend into place from above the top edge of its host by its own height plus its margin while fading in, over comp.snackbar.motion.enter-duration with comp.snackbar.motion.enter-easing, as SNK-17 rises at the bottom; WHEN it closes it SHALL fade out in place as SNK-17 says, and WHERE motion is reduced it SHALL fade in and out without moving, or appear and disappear at once where the platform removes every animation.
SNK-37 WHILE placement is top-end, WHEN the bar expands or collapses (SNK-24) THE snackbar SHALL grow downward and shrink back with its top edge in place, so that, its content being aligned to the top (SNK-29), nothing of its first row moves on the screen during the motion or after it; WHILE it is expanded it SHALL be at most as tall as SNK-25 allows, the area's height being measured from below what the frame keeps over its top (SNK-35).

مطابقة الأسماء بين المنصات

التكافؤ لا يعني واجهات برمجية متطابقة. تعبّر كل منصة عن العقد نفسه بأسلوبها.

المواصفة Web SwiftUI Jetpack Compose Flutter React Native
المكوّن tanrei-snackbar TanreiSnackbar TanreiSnackbar TanreiSnackbar Snackbar
message · الخاصية message message message message message
title · الخاصية headline title title title title
action · الخاصية action actionLabel actionLabel actionLabel actionLabel
status · الخاصية status status status status status
statusLabel · الخاصية statusLabel statusLabel statusLabel statusLabel statusLabel
inverse · الخاصية inverse inverse inverse inverse inverse
closable · الخاصية closable withCloseButton withDismissAction showCloseIcon closable
closeLabel · الخاصية closeLabel closeLabel closeLabel closeIconLabel closeLabel
expanded · الخاصية expanded isExpanded expanded expanded expanded
expandLabel · الخاصية expandLabel expandLabel expandLabel expandLabel expandLabel
duration · الخاصية duration duration duration duration duration
placement · الخاصية placement placement placement placement placement
action · الحدث action TanreiSnackbarResult.action TanreiSnackbarResult.ActionPerformed TanreiSnackbarClosedReason.action onAction
dismiss · الحدث dismiss TanreiSnackbarResult.dismissed TanreiSnackbarResult.Dismissed TanreiSnackbarClosedReason onDismiss
toggle · الحدث expandedchange onExpandedChange onExpandedChange onExpandedChanged onExpandedChange
ملاحظات title is the headline property and attribute, because HTML's global title attribute would show a tooltip over the whole bar (as the app bar's). closeLabel, statusLabel and expandLabel are the close-label, status-label and expand-label attributes. inverse is a property that is true, false or null (the default); the inverse attribute sets it: absent is null, present (empty or true) is true, and inverse="false" is false, the one way to refuse a system whose choice is on. While it is null the snackbar reads --tanrei-comp-snackbar-container-inverse from the cascade, which carries the choice's name (SNK-30). The opacities of SNK-21, SNK-31, SNK-32 and SNK-33 are applied to the color of the part they name (a mix of that color with transparent), never as an element's opacity, so nothing else fades with it; a status form's edge is a shadow layer of its own before the elevation's, and the tonal layer lies inside the action, under its label. The focus indicator's color is the form's focus-ring-color custom property, handed to the shared focus primitive (SNK-3). The expand and close buttons are <tanrei-button size="small"> elements in the snackbar's shadow root, given the variant --tanrei-comp-snackbar-close-button-variant names and the form's tone through the Button's internal channel (SNK-34); the expand button's expanded state and the text it controls are written on the Button's own native button (aria-expanded, and ariaControlsElements, since an id cannot be named across the Button's shadow root). dismiss is a CustomEvent whose detail.reason is the reason. toggle is the expandedchange CustomEvent, whose detail.expanded is the new value, because a popover element already fires a native toggle when it is shown and hidden. The host (<tanrei-snackbar-host>) queues and places snackbars; show(options) takes title, status, statusLabel, inverse and expandLabel as well; see the accessibility notes. placement is the placement attribute of <tanrei-snackbar> and of <tanrei-snackbar-host>: the host's is the placement of each snackbar whose show() options name none (SNK-35). What the frame keeps over the top of the area is --tanrei-app-shell-scroll-offset on the document's root, which <tanrei-app-shell> sets to its sticky header's height (APS-17) and a product's own frame may set; the safe area is env(safe-area-inset-*). A compact window is one narrower than --tanrei-comp-snackbar-breakpoint-medium, read by the stylesheet itself, with no listener. Snapshot harness: each fixture is a <tanrei-snackbar> rendered outside a host (SNK-19), on a 400 px wide stage; expanded-scrolls on a stage 400 × 240, and top-end and top-end-rtl on a stage 720 wide, wider than a compact window. Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. A host is a @Observable TanreiSnackbarHost attached with .tanreiSnackbarHost(_:) on the view whose bottom edge it uses; await host.show(message:actionLabel:withCloseButton:closeLabel:duration:) returns a TanreiSnackbarResult (.action, or .dismissed(reason)) once the snackbar has closed. It is drawn in an overlay of that view, not in a sheet, which would be modal. Snapshot harness: TanreiSnackbar rendered in place (SNK-19) in a 400-point frame. inverse is a Bool?, nil by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. Shaped like Material's snackbar API: TanreiSnackbarHost(hostState) is placed in the layout (for example a scaffold's snackbar slot), and hostState.showSnackbar(message, actionLabel, withDismissAction, closeLabel, duration) suspends until the snackbar has closed and returns the result; cancelling the coroutine closes it with the reason host. The recommended timeout is AccessibilityManager.calculateRecommendedTimeoutMillis. Snapshot harness: TanreiSnackbar(message = …) rendered in place (SNK-19) in a 400 dp wide box. inverse is a Boolean?, null by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. Shaped like Flutter's ScaffoldMessenger: a TanreiSnackbarMessenger placed around the page, inside its route, hosts the queue (so a Tanrei dialog's route covers it and SNK-12's wait applies), and TanreiSnackbarMessenger.of(context).show(TanreiSnackbar(...)) returns a controller whose closed future completes with a TanreiSnackbarClosedReason (action, close, escape, timeout, host). showCloseIcon is Flutter's own name for the close button. A running screen reader is MediaQuery.accessibleNavigation (as Flutter's own SnackBar reads it); Android's recommended timeout needs a platform channel, since Flutter does not expose it. Snapshot harness: a golden of TanreiSnackbar rendered in place (SNK-19) in a 400-wide surface. inverse is a bool?, null by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. TanreiProvider renders the host in its root overlay layer, not in a Modal (a Modal is modal and takes focus); useSnackbar().show({ message, actionLabel, closable, closeLabel, duration }) returns a promise of the result. A Snackbar element rendered directly is drawn in place (SNK-19). Snapshot harness: Snackbar rendered in place in a 400-wide view. inverse is boolean | null | undefined; both null and undefined take the system's choice. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20).

الرموز

الرمز يشير إلى القيمة المحلولة (فاتح)
--tanrei-comp-snackbar-action-container-color comp.snackbar.container.color #ffffff
--tanrei-comp-snackbar-action-content-color comp.snackbar.supporting-text.color #1b1b1b
--tanrei-comp-snackbar-action-error-container-color comp.snackbar.error.container.color #ffedeb
--tanrei-comp-snackbar-action-error-content-color comp.snackbar.error.supporting-text.color #3a211f
--tanrei-comp-snackbar-action-error-state-layer-color comp.snackbar.action.error.content.color #3a211f
--tanrei-comp-snackbar-action-focused-container-color — #e8e8e8
--tanrei-comp-snackbar-action-focused-content-color — #1b1b1b
--tanrei-comp-snackbar-action-focused-error-container-color — #ebd9d7
--tanrei-comp-snackbar-action-focused-error-content-color — #3a211f
--tanrei-comp-snackbar-action-focused-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-focused-info-container-color — #d9dceb
--tanrei-comp-snackbar-action-focused-info-content-color — #212839
--tanrei-comp-snackbar-action-focused-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-focused-inverse-error-container-color — #4a312f
--tanrei-comp-snackbar-action-focused-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-focused-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-focused-inverse-info-container-color — #303748
--tanrei-comp-snackbar-action-focused-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-focused-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-focused-inverse-success-container-color — #2b3b2b
--tanrei-comp-snackbar-action-focused-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-focused-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-focused-inverse-warning-container-color — #47341f
--tanrei-comp-snackbar-action-focused-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-focused-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-focused-inverse-container-color — #343434
--tanrei-comp-snackbar-action-focused-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-focused-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-focused-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-focused-success-container-color — #cee2cc
--tanrei-comp-snackbar-action-focused-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-focused-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-focused-warning-container-color — #ebdacb
--tanrei-comp-snackbar-action-focused-warning-content-color — #362410
--tanrei-comp-snackbar-action-focused-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-hovered-container-color — #ededed
--tanrei-comp-snackbar-action-hovered-content-color — #1b1b1b
--tanrei-comp-snackbar-action-hovered-error-container-color — #efdddb
--tanrei-comp-snackbar-action-hovered-error-content-color — #3a211f
--tanrei-comp-snackbar-action-hovered-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-hovered-info-container-color — #dde0ef
--tanrei-comp-snackbar-action-hovered-info-content-color — #212839
--tanrei-comp-snackbar-action-hovered-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-hovered-inverse-error-container-color — #462d2b
--tanrei-comp-snackbar-action-hovered-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-hovered-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-hovered-inverse-info-container-color — #2c3344
--tanrei-comp-snackbar-action-hovered-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-hovered-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-hovered-inverse-success-container-color — #273727
--tanrei-comp-snackbar-action-hovered-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-hovered-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-hovered-inverse-warning-container-color — #42301b
--tanrei-comp-snackbar-action-hovered-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-hovered-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-hovered-inverse-container-color — #303030
--tanrei-comp-snackbar-action-hovered-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-hovered-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-hovered-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-hovered-success-container-color — #d2e6cf
--tanrei-comp-snackbar-action-hovered-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-hovered-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-hovered-warning-container-color — #efdecf
--tanrei-comp-snackbar-action-hovered-warning-content-color — #362410
--tanrei-comp-snackbar-action-hovered-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-info-container-color comp.snackbar.info.container.color #edf0ff
--tanrei-comp-snackbar-action-info-content-color comp.snackbar.info.supporting-text.color #212839
--tanrei-comp-snackbar-action-info-state-layer-color comp.snackbar.action.info.content.color #212839
--tanrei-comp-snackbar-action-inverse-error-container-color comp.snackbar.inverse-error.container.color #361d1b
--tanrei-comp-snackbar-action-inverse-error-content-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-action-inverse-error-state-layer-color comp.snackbar.action.inverse-error.content.color #ffe1df
--tanrei-comp-snackbar-action-inverse-info-container-color comp.snackbar.inverse-info.container.color #1c2334
--tanrei-comp-snackbar-action-inverse-info-content-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-action-inverse-info-state-layer-color comp.snackbar.action.inverse-info.content.color #e1e8ff
--tanrei-comp-snackbar-action-inverse-success-container-color comp.snackbar.inverse-success.container.color #172718
--tanrei-comp-snackbar-action-inverse-success-content-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-action-inverse-success-state-layer-color comp.snackbar.action.inverse-success.content.color #daeed6
--tanrei-comp-snackbar-action-inverse-warning-container-color comp.snackbar.inverse-warning.container.color #32200c
--tanrei-comp-snackbar-action-inverse-warning-content-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-action-inverse-warning-state-layer-color comp.snackbar.action.inverse-warning.content.color #ffe3cb
--tanrei-comp-snackbar-action-inverse-container-color comp.snackbar.inverse.container.color #1f1f1f
--tanrei-comp-snackbar-action-inverse-content-color comp.snackbar.inverse.supporting-text.color #f1f1f1
--tanrei-comp-snackbar-action-inverse-state-layer-color comp.snackbar.action.inverse.content.color #f1f1f1
--tanrei-comp-snackbar-action-pressed-container-color — #e8e8e8
--tanrei-comp-snackbar-action-pressed-content-color — #1b1b1b
--tanrei-comp-snackbar-action-pressed-error-container-color — #ebd9d7
--tanrei-comp-snackbar-action-pressed-error-content-color — #3a211f
--tanrei-comp-snackbar-action-pressed-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-pressed-info-container-color — #d9dceb
--tanrei-comp-snackbar-action-pressed-info-content-color — #212839
--tanrei-comp-snackbar-action-pressed-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-pressed-inverse-error-container-color — #4a312f
--tanrei-comp-snackbar-action-pressed-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-pressed-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-pressed-inverse-info-container-color — #303748
--tanrei-comp-snackbar-action-pressed-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-pressed-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-pressed-inverse-success-container-color — #2b3b2b
--tanrei-comp-snackbar-action-pressed-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-pressed-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-pressed-inverse-warning-container-color — #47341f
--tanrei-comp-snackbar-action-pressed-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-pressed-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-pressed-inverse-container-color — #343434
--tanrei-comp-snackbar-action-pressed-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-pressed-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-pressed-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-pressed-success-container-color — #cee2cc
--tanrei-comp-snackbar-action-pressed-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-pressed-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-pressed-warning-container-color — #ebdacb
--tanrei-comp-snackbar-action-pressed-warning-content-color — #362410
--tanrei-comp-snackbar-action-pressed-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-state-layer-color comp.snackbar.action.content.color #1b1b1b
--tanrei-comp-snackbar-action-success-container-color comp.snackbar.success.container.color #e2f6df
--tanrei-comp-snackbar-action-success-content-color comp.snackbar.success.supporting-text.color #1b2c1c
--tanrei-comp-snackbar-action-success-state-layer-color comp.snackbar.action.success.content.color #1b2c1c
--tanrei-comp-snackbar-action-tonal-layer-opacity — 0.12
--tanrei-comp-snackbar-action-warning-container-color comp.snackbar.warning.container.color #ffeee0
--tanrei-comp-snackbar-action-warning-content-color comp.snackbar.warning.supporting-text.color #362410
--tanrei-comp-snackbar-action-warning-state-layer-color comp.snackbar.action.warning.content.color #362410
--tanrei-comp-snackbar-breakpoint-medium sys.breakpoint.medium 600px
--tanrei-comp-snackbar-close-button-variant — 1
--tanrei-comp-snackbar-container-color sys.color.surface-bright #ffffff
--tanrei-comp-snackbar-container-elevation sys.elevation.level3 0px 0px 0px 1px rgb(0 0 0 / 0.08), 0px 1px 1px 0px rgb(0 0 0 / 0.04), 0px 4px 8px -4px rgb(0 0 0 / 0.04), 0px 16px 24px -8px rgb(0 0 0 / 0.06)
--tanrei-comp-snackbar-container-gap sys.space.space100 8px
--tanrei-comp-snackbar-container-inverse — 0
--tanrei-comp-snackbar-container-margin sys.space.space200 16px
--tanrei-comp-snackbar-container-max-width — 560px
--tanrei-comp-snackbar-container-min-height — 48px
--tanrei-comp-snackbar-container-min-width — 288px
--tanrei-comp-snackbar-container-padding-block sys.space.space150 12px
--tanrei-comp-snackbar-container-padding-inline-end sys.space.space200 16px
--tanrei-comp-snackbar-container-padding-inline-end-with-controls sys.space.space100 8px
--tanrei-comp-snackbar-container-padding-inline-start sys.space.space200 16px
--tanrei-comp-snackbar-container-shape sys.shape.corner.medium 8px
--tanrei-comp-snackbar-controls-gap sys.space.space50 4px
--tanrei-comp-snackbar-controls-height comp.button.container.height.small 32px
--tanrei-comp-snackbar-controls-padding-inline sys.space.space175 14px
--tanrei-comp-snackbar-controls-shape sys.shape.corner.full 9999px
--tanrei-comp-snackbar-error-container-color sys.color.error-container #ffedeb
--tanrei-comp-snackbar-error-focus-ring-color sys.color.on-error-container #3a211f
--tanrei-comp-snackbar-error-icon-color sys.color.error #cd262f
--tanrei-comp-snackbar-error-outline-color sys.color.error #cd262f
--tanrei-comp-snackbar-error-supporting-text-color sys.color.on-error-container #3a211f
--tanrei-comp-snackbar-error-title-color comp.snackbar.error.supporting-text.color #3a211f
--tanrei-comp-snackbar-focus-ring-color sys.color.focus-ring #0070ac
--tanrei-comp-snackbar-focused-opacity — 1
--tanrei-comp-snackbar-hovered-opacity — 1
--tanrei-comp-snackbar-icon-gap sys.space.space150 12px
--tanrei-comp-snackbar-icon-opacity — 0.85
--tanrei-comp-snackbar-icon-size sys.icon.medium 24px
--tanrei-comp-snackbar-info-container-color sys.color.info-container #edf0ff
--tanrei-comp-snackbar-info-focus-ring-color sys.color.on-info-container #212839
--tanrei-comp-snackbar-info-icon-color sys.color.info #3066cb
--tanrei-comp-snackbar-info-outline-color sys.color.info #3066cb
--tanrei-comp-snackbar-info-supporting-text-color sys.color.on-info-container #212839
--tanrei-comp-snackbar-info-title-color comp.snackbar.info.supporting-text.color #212839
--tanrei-comp-snackbar-inverse-error-container-color sys.color.on-error-container #361d1b
--tanrei-comp-snackbar-inverse-error-focus-ring-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-inverse-error-icon-color comp.snackbar.inverse-error.supporting-text.color #ff928c
--tanrei-comp-snackbar-inverse-error-outline-color sys.color.error #ff928c
--tanrei-comp-snackbar-inverse-error-supporting-text-color sys.color.error-container #ffe1df
--tanrei-comp-snackbar-inverse-error-title-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-inverse-info-container-color sys.color.on-info-container #1c2334
--tanrei-comp-snackbar-inverse-info-focus-ring-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-inverse-info-icon-color comp.snackbar.inverse-info.supporting-text.color #8eafff
--tanrei-comp-snackbar-inverse-info-outline-color sys.color.info #8eafff
--tanrei-comp-snackbar-inverse-info-supporting-text-color sys.color.info-container #e1e8ff
--tanrei-comp-snackbar-inverse-info-title-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-inverse-success-container-color sys.color.on-success-container #172718
--tanrei-comp-snackbar-inverse-success-focus-ring-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-inverse-success-icon-color comp.snackbar.inverse-success.supporting-text.color #62c572
--tanrei-comp-snackbar-inverse-success-outline-color sys.color.success #62c572
--tanrei-comp-snackbar-inverse-success-supporting-text-color sys.color.success-container #daeed6
--tanrei-comp-snackbar-inverse-success-title-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-inverse-warning-container-color sys.color.on-warning-container #32200c
--tanrei-comp-snackbar-inverse-warning-focus-ring-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-inverse-warning-icon-color comp.snackbar.inverse-warning.supporting-text.color #f39e3a
--tanrei-comp-snackbar-inverse-warning-outline-color sys.color.warning #f39e3a
--tanrei-comp-snackbar-inverse-warning-supporting-text-color sys.color.warning-container #ffe3cb
--tanrei-comp-snackbar-inverse-warning-title-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-inverse-container-color sys.color.inverse-surface #1f1f1f
--tanrei-comp-snackbar-inverse-focus-ring-color sys.color.inverse-on-surface #f1f1f1
--tanrei-comp-snackbar-inverse-supporting-text-color sys.color.inverse-on-surface #f1f1f1
--tanrei-comp-snackbar-inverse-title-color comp.snackbar.inverse.supporting-text.color #f1f1f1
--tanrei-comp-snackbar-motion-enter-duration sys.motion.role.appear.toast.enter 350ms
--tanrei-comp-snackbar-motion-enter-easing sys.motion.easing.enter cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-motion-exit-duration sys.motion.role.appear.toast.exit 300ms
--tanrei-comp-snackbar-motion-exit-easing sys.motion.easing.exit cubic-bezier(0.3, 0, 1, 1)
--tanrei-comp-snackbar-motion-expand-duration sys.motion.role.resize.large 400ms
--tanrei-comp-snackbar-motion-expand-easing sys.motion.easing.spatial cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-motion-feedback-duration sys.motion.role.feedback 450ms
--tanrei-comp-snackbar-motion-state-duration sys.motion.role.state.default 250ms
--tanrei-comp-snackbar-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-outline-opacity — 0.4
--tanrei-comp-snackbar-outline-width sys.border.hairline 1px
--tanrei-comp-snackbar-pressed-opacity — 1
--tanrei-comp-snackbar-success-container-color sys.color.success-container #e2f6df
--tanrei-comp-snackbar-success-focus-ring-color sys.color.on-success-container #1b2c1c
--tanrei-comp-snackbar-success-icon-color sys.color.success #077b32
--tanrei-comp-snackbar-success-outline-color sys.color.success #077b32
--tanrei-comp-snackbar-success-supporting-text-color sys.color.on-success-container #1b2c1c
--tanrei-comp-snackbar-success-title-color comp.snackbar.success.supporting-text.color #1b2c1c
--tanrei-comp-snackbar-supporting-text-color sys.color.on-surface #1b1b1b
--tanrei-comp-snackbar-supporting-text-max-lines — 3
--tanrei-comp-snackbar-supporting-text-under-title-opacity — 0.8
--tanrei-comp-snackbar-timeout-long — 10000ms
--tanrei-comp-snackbar-timeout-short — 4000ms
--tanrei-comp-snackbar-title-color comp.snackbar.supporting-text.color #1b1b1b
--tanrei-comp-snackbar-title-gap sys.space.space50 4px
--tanrei-comp-snackbar-title-max-lines — 3
--tanrei-comp-snackbar-warning-container-color sys.color.warning-container #ffeee0
--tanrei-comp-snackbar-warning-focus-ring-color sys.color.on-warning-container #362410
--tanrei-comp-snackbar-warning-icon-color sys.color.warning #9b5c00
--tanrei-comp-snackbar-warning-outline-color sys.color.warning #9b5c00
--tanrei-comp-snackbar-warning-supporting-text-color sys.color.on-warning-container #362410
--tanrei-comp-snackbar-warning-title-color comp.snackbar.warning.supporting-text.color #362410
--tanrei-comp-snackbar-controls-label-typescale sys.typescale.label 500 14px/1.4286
--tanrei-comp-snackbar-supporting-text-typescale sys.typescale.body 400 14px/1.5714
--tanrei-comp-snackbar-title-typescale sys.typescale.heading-6 500 14px/1.4286

نماذج الاختبار

عروض مرجعية. تلتقط كل المنصات لقطة لكل نموذج بالمعرّف نفسه حتى يمكن مقارنة النتائج.

مولَّد من specs/snackbar.spec.json, tokens/comp/snackbar.tokens.json, design/tokens/

الإرشادات

متى يُستخدم

استخدم شريط الإشعار لتأكيد شيء فعله الشخص للتو، حين ينتهي من دون شاشة خاصة به: «أُرشفت المحادثة»، «نُسخ الرابط»، «حُفظت الصورة». اعرض إجراءً واحدًا على الأكثر يتراجع عنه أو يتابعه.

شريط الإشعار يُبلِّغ؛ ولا يسأل. الاختيار بين إجراءين، أو خطأ يحجب عمل الشخص، أو أي شيء يجب أن يقرّ به، مكانه في مربع حوار أو بجانب ما يتعلق به. وهيئة الخطأ هي لإخفاق يستطيع الشخص أن يعود إليه، مثل «لم تُرسل الرسالة» مع «إعادة المحاولة».

شريط إشعار أم مربع حوار

كلاهما يظهر فوق الصفحة، وهما يؤديان عملين متعاكسين.

الجانب شريط الإشعار مربع الحوار
ما يفعله يُبلِّغ عن شيء حدث من قبل. يطلب قرارًا، أو إقرارًا بشيء، قبل أن يستمر العمل.
التركيز لا ينتقل أبدًا. يواصل الشخص عمله. ينتقل إلى داخل مربع الحوار. الصفحة التي خلفه لا يمكن استخدامها.
كم يبقى بضع ثوانٍ، أو إلى أن يُستخدم إجراؤه أو زر إغلاقه. إلى أن يجيب الشخص.
الإجراءات واحد على الأكثر، والرسالة مكتملة من دونه. أجوبة سؤاله.

إن كان الناس يستطيعون تجاهل الرسالة من دون أن يسوء شيء، فهو شريط إشعار. وإن كان التطبيق لا يستطيع أن يستمر من دون جواب، فهو مربع حوار. والرسالة التي تنتمي إلى جزء واحد من الشاشة ويجب أن تبقى مرئية، مثل بيان الخطأ في حقل، توضع في ذلك المكان، في صورة النص المساعد للحقل مثلًا.

الأجزاء

الجزء يُضبط بـ ملاحظات
الشريط inverse سطح مرفوع من المخطط اللوني افتراضيًّا، أو ألوان المخطط المقابل؛ انظر على سطح أو بألوان معكوسة.
أيقونة الحالة status و statusLabel اختيارية. هيئة الحالة ترسم أيقونتها قبل النص؛ انظر هيئات الحالة.
العنوان title (على الويب headline) اختياري. عنوان قصير فوق الرسالة، بنمط أثقل وزنًا وبحجم الرسالة نفسه. من دونه تقف الرسالة وحدها.
الرسالة message مطلوبة. نص مجرّد، جملة أو جملتان قصيرتان، يُعلَن كاملًا. ومع العنوان هي الوصف، وتُرسم أهدأ قليلًا من العنوان.
الإجراء action (التسمية) اختياري: «تراجع»، «عرض»، «إعادة المحاولة». يُرسم زرًّا من الطراز tonal: كبسولة تبتعد عن شريطها درجة هادئة واحدة، وتسميتها بلون نص الشريط. يرسمه شريط الإشعار برموزه (tokens) الخاصة، لا في صورة Button، بارتفاع أزرار Button الصغيرة التي بجانبه. وينتقل إلى صف خاص به حين يحتاج النص إلى أكثر من سطرين بجانبه، بعدّ أسطر العنوان والرسالة معًا، أو حين تكاد تسميته تلتف.
زر التوسيع expandLabel، expanded زر Button صغير بأيقونة وحدها، يُرسم كما يُرسم زر الإغلاق. لا يُرسم إلا ما دام العنوان أو الرسالة أطول من ثلاثة أسطر. والقيمة expandLabel هي اسمه المتاح للتقنيات المساعدة، مثل «عرض الرسالة كاملة».
زر الإغلاق closable و closeLabel اختياري. زر Button صغير بأيقونة وحدها. لرسالة تبقى إلى أن تُغلق، أو لرسالة قد يريد الناس زوالها أبكر. والقيمة closeLabel هي اسمه المتاح للتقنيات المساعدة، بلغة منتجك.

يقع الإجراء وزر التوسيع وزر الإغلاق بجانب السطر الأول من النص، والثلاثة بارتفاع زر Button صغير.

زرّا التوسيع والإغلاق

زرّا التوسيع والإغلاق زرّا Button صغيران بأيقونة وحدها، يحملان الرسوم expand_more و expand_less و close من مجموعة الأيقونات. وهما من الطراز tonal، ككل أزرار الإغلاق في Tanrei، ويأخذان لونهما من الشريط: الرسم بلون نص الشريط، وتحته دائرة من اللون نفسه صارت شبه شفافة. لذلك يُقرآن عنصرَي تحكم على كل هيئة، سطحًا كانت أو صبغة حالة أو شريطًا معكوسًا، ولا يأتيان بلون ليس في الشريط أصلًا. والتحويم والتركيز والضغط عليهما هي التي لزر Button، فوق اللون نفسه، وحلقة التركيز عليهما بلون التركيز الخاص بالشريط.

يمكن للمنتج أن يرسمهما رسمًا وحده بدلًا من ذلك. ويفعل ذلك مرة واحدة، لكل أشرطة الإشعار، في طبقة نظام التصميم الخاص به، بأن يجعل comp.snackbar.close-button.variant الطراز text؛ وهذا بالضبط ما يفعله إعدادا Material و Cupertino المسبقان، ليحتفظا بالرسم وحده الذي في أصليهما.

الإجراء

الإجراء زر من الطراز tonal يقع على شريطه. حاويته هي لون الشريط نفسه وفوقه طبقة خفيفة من لون التسمية، فيبتعد عن الشريط الدرجة الهادئة نفسها في كل هيئة: على سطح أو معكوسًا، بحالة أو من دونها. والتسمية بلون نص الشريط.

وهو من الطراز tonal لأنه في العادة تراجع، والشخص الذي أخطأ للتو يجب أن يرى فورًا أن هناك زرًّا. والتسمية النصية المجرّدة يسهل ألا تُلاحظ على الشريط.

لا تجعله زرًّا من الطراز filled أبدًا. الإجراء المهم إلى حد أنه يبدو محتاجًا إلى زر filled ليس مكانه شريط الإشعار، الذي يختفي ويُوصل إليه أخيرًا في ترتيب التركيز. ضعه خلف الإجراء الرئيسي للشاشة، في لوحة سفلية.

يجوز للمنتج أن يعطي الإجراء مظهرًا آخر. يفعل ذلك مرة واحدة، لكل أشرطة الإشعار، في طبقة نظام تصميمه، بإعطاء رموز لون الإجراء وعتامة طبقته اللونية قيمًا أخرى؛ ولا يوجد طراز لكل شريط على حدة. الإعدادان الجاهزان Material و Cupertino يفعلان ذلك بالضبط، ليحتفظا بالإجراء من الطراز text الذي في أصليهما.

هيئات الحالة

status الأيقونة طريقة الإعلان يُستخدم لـ
default لا شيء بتهذيب (polite) معظم الرسائل: ما فعله التطبيق للتو.
info info بتهذيب شيء يستحق أن يُعرف وليس نتيجة فعل الشخص.
success check_circle بتهذيب مهمة انتهت على خير، حيث كان الشخص ينتظرها.
warning warning بإلحاح (assertive) شيء قد يسوء ما لم يتصرف الشخص.
error error بإلحاح إخفاق يستطيع الشخص أن يعود إليه، مع إجراء يعيد المحاولة أو يشرح.

هيئات الحالة: info و success و warning و error

ترسم هيئة الحالة شريطها بصبغة هادئة من الحالة، وحوله حافة من خط رفيع بلون الحالة، وأيقونة الحالة بذلك اللون قبل النص. الحافة لا تأخذ حيّزًا. والهيئة الافتراضية ليس لها حافة خاصة بها، بل الحافة التي يرسمها ارتفاعها فقط. لا تُعرف هيئة الحالة باللون وحده أبدًا: شكل الأيقونة يفرّق بين الهيئات، والقيمة statusLabel تعطي الحالة بالكلمات، بلغة منتجك («خطأ»). تُقرأ هذه التسمية قبل العنوان والرسالة. والتحذير والخطأ يقاطعان ما يُقرأ؛ أما الهيئات الأخرى فتنتظره.

على سطح أو بألوان معكوسة

يُرسم شريط الإشعار افتراضيًّا على سطح مرفوع من المخطط اللوني: السطح الساطع، الذي يرفعه ارتفاعه، والذي تقف عليه مربعات الحوار أيضًا، مع لون نص المخطط. وحين يُرسم معكوسًا يأخذ ألوان المخطط المقابل، شريطًا داكنًا في مخطط فاتح، ليتميز عن أي شيء يحطّ عليه.

مرسوم معكوسًا: الهيئة الافتراضية وهيئات الحالة الأربع

inverse كيف يُرسم
غير مضبوطة (null، الافتراضي) كما يختار نظام التصميم. النظام الافتراضي يختار سطحًا؛ والإعداد الجاهز m3-like يختار الرسم المعكوس.
true معكوسًا.
false على سطح، حتى في نظام اختياره الرسم المعكوس.

على الويب تقول خاصية HTML (attribute) أيّ الثلاث هي: إن تُركت فهي غير مضبوطة، و inverse هي true، و inverse="false" هي false. والدالة show() تأخذ inverse خيارًا.

هيئة الحالة المرسومة معكوسةً هي هيئة تلك الحالة من السمة الأخرى، جزءًا بجزء. في سمة فاتحة، شريط info المعكوس هو شريط info الذي ترسمه سمة داكنة، بنص تلك السمة وأيقونتها وحافتها وإجرائها؛ وفي سمة داكنة هو شريط السمة الفاتحة. ويصح الشيء نفسه عند كل مستوى تباين. وهكذا لا تستخدم هيئة الحالة المعكوسة لونًا لا يرسمه المنتج أصلًا في موضع آخر، وأيقونتها وحافتها زاهيتان كما هما على سطح.

الرسم المعكوس يغيّر الألوان ولا شيء غيرها: الحجم والزوايا والارتفاع والتخطيط والأيقونات والحركة والتوقيت والإعلان والمفاتيح تبقى كما هي. هو مظهر، لا معنى. لا تستخدمه لتقول إن رسالة مهمة؛ هيئات الحالة والقيمة statusLabel تقول ذلك. والأفضل أن تقرره مرة واحدة للمنتج، في طبقة نظام تصميمه، ليبدو كل شريط إشعار من النوع نفسه من الرسائل.

النص الطويل

ما دام الشريط مطويًّا، يعرض كل من العنوان والرسالة ثلاثة أسطر على الأكثر، وينتهي بعلامة الحذف (…) حيث يُقتطع. ويظهر حينئذ زر توسيع بين الإجراء وزر الإغلاق. تفعيله يعرض النص كله، ويُصدر الحدث toggle مع القيمة الجديدة للخاصية expanded (وهو expandedchange على الويب)، ويُبقي التركيز على الزر، ولا يغلق شريط الإشعار. يكبر الشريط إلى الأعلى من حافته السفلية (أو إلى الأسفل من حافته العليا حين يوضع عند طرف الأعلى)، وفورًا حيث تُقلَّل الحركة. محتواه محاذى إلى الأعلى، فتحتفظ الأيقونة والسطر الأول وعناصر التحكم المجاورة له ببعدها عن الحافة العليا حين يكبر الشريط أو يصغر، ويحتفظ الإجراء الذي في صف خاص به ببعده عن الحافة السفلية. ويجوز لشيفرتك أيضًا أن تضبط expanded، وهذا لا يُصدر شيئًا.

إن كان النص الموسَّع ما زال أطول من الحيّز المتاح للمضيف، أخذ الشريط ذلك الارتفاع ومُرِّر نصه في داخله، وبقيت الأيقونة وعناصر التحكم في مكانها. والتقنيات المساعدة تحصل دائمًا على النص كله، اقتُطع أم لم يُقتطع.

الموضع

placement أين يقف الشريط متى يُستخدم
bottom (الافتراضي) في أسفل النافذة، في الوسط، بهامش فوق الحافة السفلية. معظم المنتجات، وكل منتج على الهاتف.
top-end في أعلى النافذة عند جهة النهاية: أعلى اليمين في تخطيط من اليسار إلى اليمين، وأعلى اليسار في تخطيط من اليمين إلى اليسار. وفي النافذة المضغوطة (compact، أضيق من 600 في النظام الافتراضي) يمتد بدلًا من ذلك على عرض الأعلى كله. شاشات سطح المكتب في تطبيقات الأعمال، حيث أسفل الشاشة هو موضع العمل.

اختر موضعًا واحدًا للمنتج كله وأعطه للمضيف، كي يتعلّم الناس أين تظهر الرسائل: الخاصية placement على <tanrei-snackbar-host> تسري على كل شريط إشعار يعرضه، وشريط الإشعار الذي يُطلب بقيمة placement خاصة به يحتفظ بها. على الهاتف أبقِه في الأسفل، حيث يضع Material شريط الإشعار وحيث الإبهام. وفي شاشات سطح المكتب في تطبيقات الأعمال، مثل لوحة المتابعة أو وحدة الإدارة أو محرّر يقع شريط أدواته أو شريط حالته أو ترقيم صفحات جدوله في الأسفل، استخدم top-end، حيث يضع Carbon وFluent إشعاراتهما.

عند طرف الأعلى يقف الشريط بهامش عن الحافة العليا وعن حافة النهاية، داخل المنطقة الآمنة وتحت الترويسة الثابتة، فلا يغطي أبدًا شريط التطبيق العلوي. على الويب يقرأ ارتفاع الترويسة من --tanrei-app-shell-scroll-offset، الذي يضبطه هيكل التطبيق على جذر المستند؛ والمنتج الذي له إطار خاص به يضبط هذه الخاصية على ارتفاع ترويسته الثابتة. وينزل إلى موضعه من فوق الحافة العليا بدلًا من أن يرتفع من الأسفل، ويكبر الشريط الموسَّع إلى الأسفل. ولا يتغير شيء غير ذلك: يبقى شريط إشعار واحد في كل مرة ولا تتكدس الأشرطة أبدًا، وتُبلَغ عناصر تحكمه في موضع المضيف من ترتيب التركيز، ويُعلَن بالطريقة نفسها.

<!-- كل شريط إشعار يعرضه هذا المضيف يقف عند طرف الأعلى. -->
<tanrei-snackbar-host placement="top-end"></tanrei-snackbar-host>

<script type="module">
  const snackbars = document.querySelector('tanrei-snackbar-host');
  snackbars.show({ message: 'Report exported', action: 'Open' });
  // شريط إشعار يُطلب في الأسفل يحتفظ بموضعه.
  snackbars.show({ message: 'Photo saved', placement: 'bottom' });
</script>
<SnackbarHost ref={snackbars} placement="top-end" />

لا يتوفر الموضع عند طرف الأعلى بعدُ في SwiftUI وCompose وFlutter وReact Native: أشرطة الإشعار فيها تقف في الأسفل.

المدة

duration كم يبقى من تلقاء نفسه
auto (الافتراضي) مثل short حين لا يوجد إجراء. ومع إجراء لا تنتهي مهلته أبدًا، فلا يفوت الإجراء أحدًا بانتهاء المهلة (WCAG 2.2.1).
short يُغلق بعد المهلة القصيرة (4 ثوانٍ في النظام الافتراضي).
long يُغلق بعد المهلة الطويلة (10 ثوانٍ في النظام الافتراضي).
indefinite يبقى إلى أن يغلقه الشخص أو شيفرتك.

شريط الإشعار الموقوت يتوقف مؤقتًا ما دام المؤشر فوقه، وما دام التركيز في داخله، وما دام موسَّعًا، وما دام التطبيق مخفيًّا أو في الخلفية، وما دام مربع حوار نمطي (modal) من Tanrei يغطيه. ثم يبدأ من جديد بمدته كاملة. ومهلة إمكانية الوصول في Android تطيله حين تكون أطول، وشريط الإشعار الذي له إجراء لا تنتهي مهلته أبدًا ما دام قارئ شاشة يعمل. إن جعلت لشريط إشعار له إجراء مهلة، فاعرض ذلك الإجراء في موضع آخر أيضًا، مثل «تراجع» في قائمة خيارات. وبنيات التنقيح (debug) تذكّرك.

العرض والتركيز والإغلاق

شريط الإشعار تراكب قراءة. الناس يتلقون رسالته، فعرضه لا ينقل التركيز أبدًا.

  • واحد في كل مرة. يعرض المضيف أشرطة الإشعار بترتيب طلبها. ينتظر التالي إلى أن يختفي السابق تدريجيًّا. وشريط الإشعار الذي يُطلب ومربع حوار نمطي من Tanrei مفتوح ينتظر إلى أن يُغلق مربع الحوار.
  • الموضع. في وسط الأسفل، بهامش فوق الحافة السفلية وعن الجانبين، داخل المنطقة الآمنة وفوق لوحة المفاتيح الظاهرة على الشاشة؛ أو، مع placement="top-end"، عند طرف الأعلى تحت الترويسة الثابتة (انظر الموضع). وفي الحالتين يُرسم فوق محتوى مساحته وتحت مربع الحوار النمطي وحجابه (scrim).
  • الإعلان. حين يظهر، تقرأ التقنيات المساعدة تسمية الحالة والعنوان والرسالة مرة واحدة، تتبعها تسمية الإجراء: بتهذيب، بعد ما يُقرأ، أو بإلحاح للتحذير والخطأ. ولا شيء يأخذ تركيز لوحة المفاتيح أو قارئ الشاشة.
  • التركيز. يُوصل إلى الإجراء وزر التوسيع وزر الإغلاق بالمفتاح Tab عند موضع المضيف في ترتيب التركيز، ولهذا يوضع المضيف أخيرًا. الشريط نفسه ليس موضع توقف للمفتاح Tab، إلا نصه ما دام شريط موسَّع يمرّره.
  • الإغلاق. يُغلق شريط الإشعار حين يُفعَّل إجراؤه (action)، أو من دونه (dismiss)، لأحد هذه الأسباب:
السبب متى
close فُعِّل زر الإغلاق.
escape ضُغط المفتاح Escape والتركيز داخل شريط الإشعار.
timeout انتهى وقت شريط إشعار مدته short أو long.
host أغلقته شيفرتك أو أفرغت قائمة الانتظار.
  • عودة التركيز. حين يُغلق شريط الإشعار والتركيز في داخله، يعود التركيز إلى العنصر الذي كان عليه قبل أن يدخل التركيز شريط الإشعار.
  • الحركة. يرتفع إلى موضعه من تحت الحافة السفلية (أو ينزل من فوق الحافة العليا عند طرف الأعلى) وهو يظهر تدريجيًّا، ويختفي تدريجيًّا في مكانه. وحيث تُقلَّل الحركة يظهر ويختفي تدريجيًّا من دون أن يتحرك؛ وعلى Android، الذي يزيل إعدادُه كل حركة، يظهر ويختفي فورًا.

افعل

  • قل ما حدث بصيغة الماضي: «أُرسلت الرسالة»، «نُقلت 3 ملفات».
  • أعطِ الإجراء تسمية قصيرة تدل على فعل يتوقعه الناس بعد الرسالة: «تراجع»، «عرض»، «إعادة المحاولة».
  • اختر الحالة التي تطابق ما حدث، وأعطِ كل هيئة حالة قيمة للخاصية statusLabel.
  • قرر مرة واحدة، للمنتج كله، هل تُرسم أشرطة الإشعار على سطح أم معكوسةً، وأين تقف.
  • أبقِ النص قصيرًا بحيث يندر أن يحتاج إلى زر التوسيع.
  • أبقِ المدة الافتراضية auto ما لم يكن لديك سبب. هي لا تفوّت على أحد إجراءً أبدًا.
  • ضع المضيف أخيرًا في الصفحة أو في التخطيط، لتأتي عناصر التحكم فيه أخيرًا في ترتيب التركيز.

لا تفعل

  • لا تستخدم شريط الإشعار لأخطاء تحجب المهمة ولا لأسئلة. استخدم مربع الحوار.
  • لا تضع إجراءين في شريط إشعار. فيه متسع لواحد.
  • لا تجعل الإجراء زرًّا من الطراز filled، ولا تضع في شريط إشعار إجراءً يبدو محتاجًا إلى زر كهذا. استخدم لوحة سفلية تُفتح من الإجراء الرئيسي.
  • لا تستخدم هيئة التحذير أو الخطأ للتأكيدات المعتادة، فهما تقاطعان قارئ الشاشة.
  • لا ترسم شريط الإشعار معكوسًا لتدلّ على أنه مهم. الرسم المعكوس يغيّر الألوان فقط؛ والحالة تقول أي نوع من الرسائل هو.
  • لا تعرض شريط إشعار لشيء تُظهره الشاشة بوضوح أصلًا.
  • لا تنقل التركيز إلى شريط الإشعار ولا إلى إجرائه. يجب ألا يصرف الناس عن عملهم.

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

الدور
status
التسمية
The snackbar is a live region: polite in the default, info and success forms (the status role on the web) and assertive in the warning and error forms (the alert role on the web). When it appears it announces, once, statusLabel, the title, the whole message and the action's label. The status glyph is hidden from assistive technology; statusLabel gives the status in words. The action's name is its label; the close button's name is closeLabel; the expand button's name is expandLabel, and it exposes whether the text is expanded. The bar itself is not a tab stop; its text is one only while it scrolls.
الحد الأدنى للهدف
تستوفي مساحة اللمس الحد الأدنى لحجم الهدف حتى لو كان الحجم المرئي أصغر. minimum 32px · pointer 44px · spacing 8px · touch 48px

لوحة المفاتيح

المفاتيح الإجراء
Tab Reaches, at the host's place in the focus order, the text while it scrolls, then the action, the expand button and the close button. Showing a snackbar never moves focus.
Enter / Space Activates the focused action, expand button or close button.
Arrow keys, Page Up, Page Down While the expanded text scrolls and has focus, scroll it.
Escape While focus is inside the snackbar, closes it (dismiss, reason escape).

ملاحظات

  • WCAG 2.2.1 (timing adjustable): by default (auto) a snackbar with an action never times out. A product may time one out (short or long), but then the action must also be available elsewhere (Undo in a menu or a history), because a person who is slow, zoomed-in or using a screen reader may not reach it in time. The timeout pauses while the snackbar is hovered, focused or expanded, and Android's accessibility timeout lengthens it.
  • A snackbar reports; it does not ask. A choice between two actions, an error that blocks the person's work, or anything they must acknowledge belongs in a dialog or next to what it is about. The error form is for a failure the person can come back to (a message not sent, with Retry).
  • The action is a tonal button so that an undo is seen at once: its label is the strongest thing in it (at least 9.1:1 on the action at rest and 6.9:1 in its weakest state, in every form and scheme of the default system), and the action is one quiet step off its bar, the same step in every form (1.25–1.45:1 against the bar in all ten forms and six schemes), so it never outweighs the message and never weighs more on one status than on another. A button with a visible label needs no boundary contrast (WCAG 1.4.11). An action important enough to seem to want a filled button does not belong in a snackbar: put a Main Action Button in a bottom sheet instead.
  • WCAG 2.4.13 and 1.4.11 (focus appearance, non-text contrast): the focus indicator is drawn on the bar, so its color is the form's (SNK-3). On the default form's surface it is the system's focus color, which the build holds against every surface role; on a status bar and on an inverse bar it is that bar's content color, which the build holds against the bar at 4.5:1 or more. The system's focus color alone is held against no status bar and falls under 3:1 on the inverse surface in five of the six schemes.
  • Drawn inverse or not, a snackbar is the same message: the role, the announcement, the focus order and the timing do not change with its colors (SNK-30). A product should not use inverse to mean something (an inverse bar for important messages): that is what the status forms and statusLabel are for.
  • WCAG 1.4.1 (use of color): a status form is never told by color alone. It draws the status's glyph, a shape of the icon set, and gives statusLabel, the status in words, to assistive technology (SNK-21).
  • WCAG 1.4.3 and 1.4.11 (contrast): three parts are drawn at an opacity of their own color, so their contrast is that of the color as drawn, not of the role. In the default system the message under a title keeps at least 7.1:1 on its bar (7.6:1 in the high-contrast schemes) and the status glyph at least 3.6:1, in every form and scheme (SNK-32, SNK-21); a status form's edge is decoration beside the glyph and statusLabel and is held to nothing (SNK-31). A system that changes one of these opacities, or the colors under them, must keep 4.5:1 for the message and 3:1 for the glyph.
  • WCAG 1.4.11 (non-text contrast): the expand and close buttons are Buttons in the form's tone (SNK-34): the glyph is the bar's message color, and the circle under it is that color at comp.button.tone.container.opacity over the bar. In the default system the glyph keeps at least 8.0:1 against its circle at rest and 6.2:1 in its weakest states (focused and pressed), in all ten forms and six schemes — well above the 3:1 a glyph without a label needs. A system that changes the tone's opacity, the state-layer opacities or a form's colors must keep 3:1 for the glyph against the circle in every state.
  • Text size never hides text for good: a collapsed title or message ends with an ellipsis at its line limit and the expand button shows the rest (SNK-23); the action moves to its own row (SNK-16); an expanded bar taller than the window scrolls inside it (SNK-25).
  • Web: `<tanrei-snackbar-host>` is placed by the product, normally as the last element of the page (its place in the focus order). It shows `<tanrei-snackbar>` elements as `popover="manual"`, so they are in the top layer, and exposes `show(options): Promise<{ result: 'action' | 'dismiss', reason? }>` (whose options include `inverse`), `dismissCurrent()` and `clear()`. The live regions are the host's two, which are always in the document, so screen readers register them before the first message is inserted: one with the status role (polite) for the default, info and success forms, one with the alert role (assertive) for warning and error. The expand button carries `aria-expanded` and `aria-controls` naming the text.
  • SwiftUI, Compose, Flutter and React Native announce with the platform's own call, at default priority for the polite forms and at high priority for warning and error: AccessibilityNotification.Announcement with the speech announcement priority, a polite or assertive liveRegion, SemanticsService.announce with its assertiveness, and AccessibilityInfo.announceForAccessibility (announceForAccessibilityWithOptions with queue off for assertive on iOS). None of them takes focus. The expand button's state is the platform's expanded/collapsed semantics (Compose's expand and collapse actions, Flutter's expanded flag, React Native's accessibilityState.expanded, and on Apple platforms the expanded and collapsed value VoiceOver reads for a disclosure).
  • How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.

مولَّد من specs/snackbar.spec.json, tokens/sys/measure.tokens.json

ما يتكفل به المكوّن

  • يُعلَن شريط الإشعار عبر منطقة حيّة (live region): منطقة مهذَّبة (الدور status على الويب) للهيئات الافتراضية و info و success، ومنطقة ملحّة (الدور alert) للتحذير والخطأ. تسمية حالته وعنوانه ورسالته، ثم تسمية إجرائه، تُعلَن مرة واحدة حين يظهر، وكاملةً دائمًا، حتى حين يُقتطع النص. وعلى SwiftUI و Compose و Flutter و React Native يُستخدم إعلان المنصة نفسها، بأولوية عالية للتحذير والخطأ، ولا يأخذ أي منها التركيز.
  • لا تُعرف هيئة الحالة باللون وحده أبدًا: فهي ترسم أيقونة الحالة وتقدّم قيمة statusLabel نصًّا قبل العنوان. والأيقونة نفسها مخفية عن التقنيات المساعدة، وكذلك أيقونتا التوسيع والإغلاق.
  • اسم الإجراء تسميته، واسم زر التوسيع قيمة expandLabel، واسم زر الإغلاق قيمة closeLabel. يُوصل إليها كلها بالمفتاح Tab عند موضع المضيف في ترتيب التركيز، وتُفعَّل بالمفتاح Enter أو Space.
  • يعرّف زر التوسيع بحالة النص، موسَّعًا أو مطويًّا، ويحتفظ بالاسم نفسه في الحالتين. والشريط الموسَّع الذي يُمرَّر نصه يجعل النص موضع توقف للتركيز، اسمه العنوان ويُمرَّر بمفاتيح الأسهم وبالمفتاحين Page Up و Page Down.
  • المفتاح Escape يغلق شريط الإشعار ما دام التركيز في داخله. وحين يُغلق والتركيز في داخله، يعود التركيز إلى حيث كان من قبل.
  • موضع الشريط لا يغيّر شيئًا آخر. شريط الإشعار عند طرف الأعلى يُبلَغ بالمفتاح Tab في موضع المضيف من ترتيب التركيز، ويُعلَن تمامًا كما يُعلَن الذي في الأسفل، ولا يغطي الترويسة الثابتة أبدًا.
  • شريط الإشعار الذي له إجراء لا تنتهي مهلته افتراضيًّا. والأشرطة الموقوتة تتوقف مؤقتًا عند التحويم أو التركيز أو التوسيع، وتطول إلى مهلة إمكانية الوصول في Android، ومع إجراء لا تنتهي مهلتها أبدًا ما دام قارئ شاشة يعمل.
  • الإجراء يستوفي الحد الأدنى للهدف على المحورين من دون تغيير حجمه المرسوم، وزرّا التوسيع والإغلاق، وهما من نوع Button، يحتفظان بحدّهما الخاص. وكل حلقة تركيز تظهر لتركيز لوحة المفاتيح فقط، بلون من هيئة شريط الإشعار، لتكون مرئية على كل شريط: سطح، وصبغة حالة، وشريط معكوس.
  • رسما التوسيع والإغلاق يحافظان على 3:1 على الأقل مقابل دائرتهما في كل حالة وهيئة. وفي النظام الافتراضي يحافظان على 8.0:1 على الأقل في السكون، و6.2:1 عند التركيز أو الضغط.
  • الأجزاء التي تُرسم أنعم تحتفظ بتباينها مع الشريط في كل مخطط لوني من النظام الافتراضي: أيقونة الحالة 3:1 على الأقل، والرسالة تحت عنوان 4.5:1 على الأقل، أو 7:1 في مخططات التباين العالي. والتنعيم مسألة لون فقط؛ ما تقرؤه التقنيات المساعدة لا يتغير، ولا يتغير كذلك حين يُرسم شريط الإشعار معكوسًا.
  • النص الأكبر لا يخفي نصًّا إلى غير رجعة أبدًا: العنوان أو الرسالة في الحالة المطوية ينتهي بعلامة الحذف عند ثلاثة أسطر وزر التوسيع يعرض الباقي، وينتقل الإجراء إلى صف خاص به، والشريط الموسَّع الأطول من النافذة يُمرَّر.
  • قبل أن يُحمَّل خط الأيقونات، لا يُرسم اسم أي أيقونة نصًّا أبدًا: يبقى مكان الأيقونة فارغًا إلى أن يستطيع الخط رسمها.
  • تبلّغ بنيات التنقيح عن رسالة فارغة، وعن زر إغلاق بلا closeLabel، وعن هيئة حالة بلا statusLabel، وعن زر توسيع بلا expandLabel، وعن شريط إشعار موقوت له إجراء.

فجوات معروفة في المنصات:

  • الويب: لا يقول المتصفح هل قارئ شاشة يعمل وليس فيه مهلة لإمكانية الوصول، فلا يطيل أي منهما شريط إشعار موقوتًا. والمدة الافتراضية auto هي ما يُبقي الوصول إلى الإجراء ممكنًا.
  • الويب: الابتعاد عن لوحة المفاتيح الظاهرة على الشاشة لم يُفحص بعد على جهاز فيه لوحة كهذه.
  • لا يستطيع SwiftUI أن يعيد التركيز إلى العنصر الذي كان عليه: حين يُغلق شريط إشعار والتركيز في داخله، يذهب التركيز حيث ينقله SwiftUI لعرض أُزيل. والمضيف الذي داخل عرض تستضيفه خارج مشهد (scene)، مثل NSHostingView خاص بك، لا يشغّل مهلاته أبدًا.
  • لا يستطيع Compose أن يسمّي العنصر الذي كان عليه التركيز قبل أن يدخل شريط الإشعار. حين يُغلق شريط الإشعار والتركيز فيه، يخرج التركيز عائدًا من الطريق التي دخل منها: بعد الدخول بالمفتاح Tab، إلى العنصر الذي قبل المضيف. وحين تغلقه شيفرتك والتركيز في داخله، لا يتحرك التركيز.
  • على Compose: الإطالة إلى مهلة إمكانية الوصول في Android والتوقف المؤقت ما دامت النافذة مخفية لا يغطيهما اختبار بعد.
  • على Compose: الإعلان المهذَّب، والتوقف المؤقت ما دامت النافذة بلا تركيز، ومهلة إمكانية الوصول اختُبرت على Robolectric فقط، لا على جهاز بعد.
  • لا يطيل Flutter بعدُ شريط إشعار موقوتًا إلى مهلة إمكانية الوصول في Android، وهي مهلة لا يتيحها Flutter.
  • لا يستطيع React Native أن يعرف أي عنصر كان عليه التركيز من قبل. حين يُغلق شريط إشعار والتركيز في داخله، يذهب التركيز حيث تضعه المنصة.
  • ليس في React Native واجهة برمجية خاصة به للمنطقة الآمنة. لا يبقى شريط الإشعار داخل المنطقة الآمنة إلا حين تمرّر هوامش النافذة (insets) إلى TanreiProvider؛ ومن دونها، على هاتف فيه مؤشر الشاشة الرئيسية، قد يغطيه جزئيًّا.
  • يقرر React Native أن الإجراء ينتقل إلى صف خاص به من الأسطر بعد تخطيطها، فيحدث الانتقال بعد جولة التخطيط الأولى.
  • على React Native: الإعلان المهذَّب، والبقاء فوق لوحة المفاتيح، والتوقف المؤقت للخلفية وللمؤشر لم تُفحص بعد على جهاز.

ما عليك فعله

  • اكتب الرسالة نصًّا مجرّدًا يُفهم وحده حين يُقرأ بصوت مسموع.
  • أعطِ زر الإغلاق قيمة للخاصية closeLabel، وهيئة الحالة قيمة للخاصية statusLabel، وشريط الإشعار الذي قد يطول نصه قيمة للخاصية expandLabel، وكلها بلغة منتجك.
  • ضع المضيف أخيرًا في الصفحة، أو أخيرًا في التخطيط على Compose.
  • على React Native، مرِّر الهوامش insets للنافذة إلى TanreiProvider، ليبتعد شريط الإشعار عن أشرطة النظام.
  • إن اخترت short أو long لشريط إشعار له إجراء، فاعرض الإجراء نفسه في موضع لا تنتهي مهلته.
  • ضع كل ما يجب أن يتصرف الناس بشأنه في مربع حوار، لا في شريط إشعار.