Перейти к содержанию
Mercury
Русский
Дизайн книга
Меню
Русский

UI5, обратная связь и отображение данных

Компоненты обратной связи и отображения данных Mercury UI отвечают за представление. Alert не удаляет себя, Toast не управляет таймером, Table не сортирует строки. Приложение хранит состояние; компоненты корректно сообщают о нём.

Эти два семейства сообщают читателю о происходящем и показывают данные. Их объединяет одно правило: компоненты представляют состояние и объявляют его, а хранит состояние приложение. Ни один компонент этой главы не запускает таймер, не сортирует список и не удаляет себя.

Alert

Alert — сообщение в потоке страницы с одним из четырёх тонов:

tone Значок Роль
info (по умолчанию) i status
success ✓ status
warning ! status
danger × alert

Только danger объявляется немедленно: вспомогательные технологии прерывают текущую речь, тогда как остальные три тона объявляются без прерывания. Выбирайте danger для настоящей ошибки, а не ради акцента.

Компонент принимает title, который выводится как h4, сообщение в дочернем содержимом и строку actions под ним. dismissible выводит кнопку закрытия с именем «Dismiss», вызывающую onDismiss. Alert не удаляет себя — это делает ваш обработчик.

Toast и его части

Toast — одно уведомление. У него те же тона и значки, что у Alert, а также:

  • priority: urgent объявляется немедленно (role="alert"), normal — без прерывания (role="status"). По умолчанию используется urgent для danger и normal для остальных.
  • onDismiss(reason): вызывается с close при закрытии кнопкой либо с swipe после завершённого смахивания. Элемент закрытия выводится всегда, поэтому смахивание не бывает единственным способом закрыть уведомление. Его имя задаёт closeLabel, по умолчанию «Dismiss».
  • swipeDirection, swipeThreshold: позволяют закрыть уведомление смахиванием указателя в заданном направлении, по умолчанию после 50 px. Жест, начатый на кнопке, ссылке или поле, относится к нажатию этого элемента, а не к перетаскиванию.

У компонента нет таймера. Когда уведомление истекает и приостанавливает ли наведение отсчёт — решает модель приложения; Toast лишь сообщает о закрытии.

Собирайте уведомление из частей:

  • ToastViewport: область уведомлений, по умолчанию с именем «Notifications». Она целиком может получать фокус, чтобы сочетание клавиш могло перевести его туда. Положение задаёте вы.
  • ToastTitle, ToastDescription: заголовок и сообщение.
  • ToastAction: необязательное действие, по умолчанию маленькая вторичная Button. Свойство altText обязательно: оно объясняет, как сделать то же без уведомления, для вспомогательных технологий и на случай, если уведомление уже исчезло. Например: «Отменить в панели истории».

Progress

Progress — полоса прогресса с известным либо неизвестным объёмом работы.

  • value, min, max: границы по умолчанию равны 0 и 100, значение ограничивается ими. Полоса сообщает собственные границы, по которым вспомогательные технологии вычисляют процент. valueText задаёт произносимое значение, например «3 из 10 файлов».
  • indeterminate: общий объём неизвестен, поэтому полоса вовсе не сообщает текущее значение вместо вводящих в заблуждение 0 или 100.
  • label либо aria-labelledby: имя, например файл, к которому относится передача.
  • variant: brand (по умолчанию), positive, negative, caution либо info; size: sm, md либо lg.

Завершение не определяется автоматически: вы передаёте конечное значение. Progress без значения и без признака неопределённого прогресса сообщает 0 и выдаёт диагностику в режиме разработки; некорректные границы также вызывают диагностику.

Card

Card — поверхность. variant принимает flat (по умолчанию), raised или floating; padding по умолчанию равен 20. Передайте title или actions, и над дочерним содержимым появится строка заголовка. Без обоих свойств заголовка нет.

Table

Table выводит записи как нативную таблицу. Каждый элемент columns имеет тип Column:

  • key задаёт поле, ячейка показывает row[key], если у столбца нет render(row);
  • label — заголовок; align — left либо right;
  • sortable добавляет в заголовок кнопку сортировки; resizable — элемент изменения ширины с minWidth, maxWidth и defaultWidth (по умолчанию 48, 960 и 160 px);
  • required сохраняет столбец видимым независимо от hiddenColumns.

Таблица принимает data, caption, striped, getRowKey (без него ключом строки служит индекс), emptyState (по умолчанию «No results») и loading, который помечает таблицу занятой, отключает элементы управления и показывает «Loading…» в пустом теле.

Остальные возможности включаются явно:

  • Столбцы: columnOrder, hiddenColumns; ширины управляются через columnWidths либо получают начальное значение из defaultColumnWidths. onColumnWidthsChange вызывается один раз на изменение размера, при его подтверждении.
  • Клавиатура: keyboardNavigation превращает таблицу в grid со стрелочной навигацией между ячейками тела.
  • Раскрытие: expansion принимает { mode: "detail", renderDetail } для области под строкой либо { mode: "treegrid", getChildren, hasChildren?, loadChildren? } для вложенных записей с уровнями; отклонённый loadChildren оставляет строку раскрываемой с возможностью повторной попытки. expandedKeys и onExpandedChange управляют открытыми строками.

Сортировка и выбор — ответственность вызывающего кода

Заголовок сортируемого столбца показывает его состояние через aria-sort, а кнопка вызывает onSortChange со следующим порядком: сначала по возрастанию, затем по убыванию. Таблица никогда не переставляет data. Строки выводятся в переданном порядке, поэтому сортирует приложение — в том числе на сервере.

Выбор устроен так же. При selectionMode="single" каждая строка получает радиокнопку, при multiple — флажок, а заголовок — флажок «выбрать все строки этой страницы». selectedKeys хранит выбор, onSelectionChange(keys) сообщает об изменении; без onSelectionChange элементы выбора отключены. isRowDisabled исключает строку из выбора, а getRowLabel задаёт имя элемента выбора каждой строки.

DataGrid

DataGrid — интерактивная сетка над окном строк для редактирования на месте.

  • Столбцы: DataGridColumn содержит key, label (также доступное имя редактора ячейки), align, render, editable и getValue для начального текста редактора.
  • Режим навигации: стрелки перемещают между ячейками (лево и право зеркально меняются для ячейки с направлением письма справа налево), Home и End ведут к первому и последнему столбцу, а вместе с Ctrl — к первой и последней строке.
  • Режим редактирования: Enter или F2 в редактируемой ячейке открывает текстовый редактор. Он получает все клавиши, пока Enter не подтвердит значение через onCellCommit({ rowKey, column, value }) либо Escape не отменит ввод. Затем фокус возвращается в ячейку.
  • Окно, а не весь список: rows — выведенное окно; startIndex либо getRowIndex задаёт положение каждой строки в полной коллекции; total — общее количество либо null, если оно неизвестно владельцу данных. Встроенного виртуализатора нет: окно предоставляет вызывающий код. Когда строка с фокусом исчезает, фокус переходит в тот же столбец следующей сохранившейся строки.

getRowKey обязателен: сетка отслеживает идентичность строк при смене окон.

Таблица загрузок

import { useState } from "@fiberfx/hyperscript/hooks";
import { Progress, Table } from "@fiberfx/ui";
import type { Column, TableSort } from "@fiberfx/ui";

type Upload = { id: string; name: string; size: number; done: number };

const columns: Column<Upload>[] = [
  { key: "name", label: "File", sortable: true },
  { key: "size", label: "Size (KB)", align: "right", sortable: true },
  { key: "done", label: "Progress", render: (row) => <Progress value={row.done} label={`${row.name} upload`} size="sm" /> },
];

export function Uploads({ uploads }: { uploads: Upload[] }) {
  const [sort, setSort] = useState<TableSort | null>(null);
  const rows = sort === null ? uploads : [...uploads].sort((a, b) => {
    const x = a[sort.key as keyof Upload];
    const y = b[sort.key as keyof Upload];
    const order = x < y ? -1 : x > y ? 1 : 0;
    return sort.direction === "ascending" ? order : -order;
  });
  return <Table columns={columns} data={rows} getRowKey={(row) => row.id} caption="Uploads" sort={sort} onSortChange={setSort} />;
}

Table сообщает, какой столбец и направление запросил читатель; сортирует компонент из примера. Каждая полоса названа по своему файлу, чтобы программа чтения с экрана могла различить даже двадцать полос.

Остальные компоненты двух семейств

Компонент Назначение
Callout блок для выделения сообщения в потоке страницы
Meter именованная величина с границами
PasswordStrength подписанный индикатор надёжности пароля
Skeleton пульсирующий заполнитель содержимого
Spinner индикатор загрузки с неизвестным объёмом
Avatar изображение пользователя либо круг с инициалами
Badge счётчик либо маркер статуса
Blockquote цитата, выделенная линией со стороны начала строки
Chart кривая либо область SVG, оформленная токенами
Checklist список выполненных и невыполненных требований
Chip компактная округлая метка в цвете статуса
Code строчный либо блочный моноширинный код
DataList пары ключей и значений в списке описаний
GridList интерактивные коллекции элементов с вложенными действиями
Kbd изображение клавиши
ListRow горизонтальная строка элемента
Stat плитка показателя
Tag метка статуса с точкой
Virtualizer ограниченные окна больших коллекций с ключами по идентичности элементов