Smart-вкладки
<sf-tabs> собирает доступную группу вкладок из строки, слотов или данных и
оформляет её как обычный компонент «Вкладки».
Берите его, когда несколько панелей одного уровня занимают одно место и
пользователь смотрит их по очереди.
Пример
Краткая информация о проекте.
Участники и роли команды.
Последние изменения проекта.
Применение
Пункты и панели
Пункты задают строкой items, разделяя их символом |, либо методом
setData(). Содержимое связывают с пунктами слотами panel-0, panel-1 и
далее. Номер панели — номер пункта в объявленном списке: он не меняется,
когда человек переставил или скрыл вкладки. Компонент сам ставит role, aria-selected, aria-controls, держит
одну позицию в порядке Tab и переключает вкладки стрелками. Начальную
вкладку задаёт active-index — тоже номер в объявленном списке, а не место
вкладки в ряду после перестановки.
После :: в пункте перечисляются через запятую его поля. Иконки задают поля
icon-start и icon-end, например
Обзор::icon-start=home|Настройки::icon-start=settings; icon-left и
icon-right — другие имена тех же полей. Строка items несёт только иконки и
disabled; key, count, href и pinned задаёт setItems()
(см. Значок, счётчик и ссылка).
Ряд вкладок рисует код компонента, поэтому до его прихода ряда нет, а панели
слотов — обычные элементы страницы. При первой загрузке страницу закрывает
заставка загрузчика (см. Заготовка до прихода кода). Чтобы панели не
показывались все сразу у вкладок, которые появились позже, скрывайте их
правилом CSS проекта sf-tabs:not(:defined) > [slot] { display: none; } в
слое @layer project. Место под ряд держит заготовка формы block, которую
вкладки объявляют в манифесте: data-sf-skeleton="block" на <sf-tabs> в
разметке сервера; высоту задаёт --sf-skeleton-block-size, по умолчанию это
высота контрола размера 1.
Недоступные, иконочные и вертикальные вкладки
Поле disabled в строке пункта исключает его из навигации. variant="icons"
показывает компактные пункты-иконки с доступными именами, а type="vertical"
меняет ориентацию вместе с направлением клавиатурного управления.
Основные сведения о проекте. Переключайте вкладки стрелками или мышью.
История изменений проекта.
Обзор материалов.
История материалов.
Основные данные проекта.
Параметры доступа к проекту.
Оформление
type="underline", type="pills" и type="full" дают ту же геометрию, что
одноимённые классы обычных вкладок. scheme выбирает вид кнопок пунктов:
default, outline или link; это вид, а не семантический цвет.
Все документы.
Только черновики.
Данные за неделю.
Данные за месяц.
Новые задачи.
Задачи в работе.
Завершённые задачи.
Текстовое оформление пунктов.
Поведение остаётся тем же.
Подчёркнутые вкладки: размеры
У type="underline" вкладка — это подпись и линия под ней, без отступов по
бокам. Между вкладками один промежуток по размеру: 20 px при size="1/2",
24 px при size="1", 32 px при size="2". Высота вкладки — высота контрола
своего размера, 32, 40 и 48 px, и нажимается вся она; линия 2, 2 и 3 px.
Когда вкладки не помещаются
overflow="scroll" (по умолчанию) прокручивает ряд, overflow="wrap"
переносит вкладки на следующие строки. overflow="more" убирает не
поместившиеся вкладки в кнопку «Ещё (n)» в конце ряда; она открывает
стандартное меню с ними. Активная вкладка всегда остаётся на месте, а выбор в
меню делает вкладку активной. Закреплённые вкладки тоже всегда остаются в
ряду, и на узком экране рядом с активной: место им уступают остальные
вкладки. Стрелки ходят по вкладкам в ряду, а после последней из них — на
кнопку «Ещё»; с «Ещё» стрелка назад возвращает к последней вкладке ряда,
стрелка вперёд — к первой.
Значок, счётчик и ссылка
У вкладки, заданной через setItems, бывают icon, count — небольшой
счётчик после подписи — и href. Имя значка берут из
списка иконок. Вкладка с href — ссылка: при выборе она
переходит по адресу, с Cmd или Ctrl — в новой вкладке браузера, а у
активной стоит aria-current="page". key — постоянный идентификатор вкладки
для настроек; без него используется номер.
tabs.setItems([
{key: 'all', label: 'Все', count: 128},
{key: 'mine', label: 'Мои', count: 7, icon: 'person'},
{key: 'archive', label: 'Архив', href: '/archive'},
]);
Настройка вкладок
С атрибутом configurable в конце ряда появляется шестерёнка «Настроить
вкладки». Она открывает меню со списком вкладок: их переставляют мышью,
касанием или клавиатурой и показывают или скрывают флажком. Закреплённую
вкладку (pinned: true) скрыть нельзя: у неё значок булавки вместо флажка.
Закреплённые вкладки всегда стоят первыми, в объявленном порядке: в списке
настройки у них нет ручки перетаскивания, другую вкладку нельзя поставить
перед ними, а order в sf-tabs-settings-change начинается с их ключей.
Сохранённый порядок, в котором закреплённые стоят не первыми, setSettings()
показывает так же — закреплёнными впереди. В «Ещё» закреплённые не уходят
никогда. Изменения применяются сразу, в подвале меню только «Сбросить».
Пример настраиваемых вкладок
Компонент выбор не хранит. Он отправляет sf-tabs-settings-change с
{order, hidden} и sf-tabs-settings-reset, а сохранённое приложение
возвращает через setSettings({order, hidden}):
- ключ, которого уже нет среди вкладок, пропускается;
- вкладка, которой нет в сохранённом порядке, встаёт на своё объявленное место и видна;
- скрытая вкладка в «Ещё» не попадает, её возвращают в настройках; но если скрытая вкладка активна — открыта по ссылке или из кода, — она видна на своём месте, пока активна;
- после сброса компонент показывает объявленный порядок, пока приложение не
ответит через
setSettings; ответить можноsetSettings({order: [], hidden: []})или не отвечать вовсе; reasonвsf-tabs-settings-change—order, если вкладки переставили, иvisibility, если вкладку показали или скрыли;- когда приходит
sf-tabs-settings-change, выбор уже на экране:setSettings()в ответ не нужен, приложение только сохраняет значение.
Чтобы первая отрисовка была уже в порядке человека, вызывайте
setSettings() сразу после setItems(), в той же задаче после
customElements.whenDefined('sf-tabs'). Хранить выбор можно и как
персональный вид: приложение
пишет {v: 1, order, hidden} через SF.Preferences.write('sf-tabs/<ключ>', …) и
читает через SF.Preferences.read().
Вложенные вкладки
Каждый <sf-tabs> управляет только собственными непосредственными пунктами,
поэтому вложенная группа сохраняет независимые выбор, фокус и панели.
Внутренняя группа использует подчёркивание, внешняя — капсулы.
История согласования не меняет выбор внешней вкладки.
Параметры доступа к проекту.
Данные и своё представление пункта
setData() принимает массивы tabs и panels. Пункту можно задать
дескриптор Smart-компонента: внешняя обёртка вкладки остаётся единственным
владельцем доступного имени и фокуса, а вложенное представление работает как
декоративное содержимое.
Переключение из кода
goTo(index) открывает вкладку по номеру в объявленном списке, считая с нуля, — и после того, как человек переставил вкладки; на недоступную вкладку он не переключает.
При переключении элемент отправляет всплывающее событие sf-tab-change с
detail.previous, detail.current, detail.item и detail.items.
previous и current — номера в объявленном списке, item — пункт
целиком, с key, label и count. onTabChange(handler) подписывается на
событие и передаёт обработчику номер новой вкладки первым аргументом.
const tabs = document.querySelector('sf-tabs');
tabs.onTabChange((current) => console.log('Открыта вкладка', current));
tabs.goTo(2);
Чтобы открытая вкладка была в адресе страницы — переживала перезагрузку,
открывалась по ссылке и работала с кнопкой «Назад», — вкладку пишут в адрес
по её key и читают обратно. Стрелки переключают вкладки на каждое нажатие,
поэтому для них подходит replaceState, а для щелчка — pushState:
const keys = tabs.getData().tabs.map((item) => item.key);
const fromAddress = () => Math.max(0, keys.indexOf(new URL(location.href).searchParams.get('tab')));
tabs.goTo(fromAddress());
let byKeyboard = false;
tabs.addEventListener('keydown', () => { byKeyboard = true; });
tabs.addEventListener('pointerdown', () => { byKeyboard = false; });
tabs.addEventListener('sf-tab-change', ({detail}) => {
const url = new URL(location.href);
if (url.searchParams.get('tab') === detail.item.key) return;
url.searchParams.set('tab', detail.item.key);
history[byKeyboard ? 'replaceState' : 'pushState'](null, '', url);
});
window.addEventListener('popstate', () => tabs.goTo(fromAddress()));
Сервер, который знает адрес, ставит active-index сам, и первая отрисовка
уже показывает нужную вкладку.
Доступность
- Каждой группе нужно доступное имя:
aria-labelилиaria-labelledbyна<sf-tabs>. - Группа — одна остановка
Tab. Стрелки по оси группы переходят по кругу по вкладкам в ряду, пропускают недоступные вкладки и вкладки в «Ещё», переносят фокус и открывают вкладку; после последней вкладки ряда стрелка вперёд ведёт на кнопку «Ещё», если она есть. Кнопка «Ещё» и шестерёнка — ещё и отдельные остановкиTab; в горизонтальной группе при письме справа налево направление стрелок зеркалится.HomeиEndпереходят к первой и последней доступной вкладке. - Пункту-иконке в
variant="icons"подпись изitemsслужит доступным именем, поэтому подпись нужна и там, где её не видно. - Счётчик (
count) входит в доступное имя вкладки: вкладка «Диски» со счётчиком 3 называется «Диски 3».
Справочник API
Раздел собран из манифеста компонента выпуска ui-106d5901f8c3 и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест.
Каждому атрибуту соответствует свойство элемента с тем же именем в camelCase: search-placeholder — searchPlaceholder. Свойство атрибута template называется templateName.
| Тег | <sf-tabs> |
| Назначение | Список вкладок, который показывает одну локальную панель за раз: текстовые вкладки или вкладки с иконкой задаются атрибутами, слотами или данными, с перемещаемым фокусом клавиатуры и связанными панелями вкладок. |
| Контракт | smart.tabs, версия 1.0.0 |
| Поставка | выпуск Framework ui-106d5901f8c3 |
| Жизненный цикл | экспериментальный: API может меняться между выпусками |
| Готовность | описан: манифест и сценарий есть, продуктовой приёмки нет |
| Заготовка до прихода кода | сервер пишет data-sf-skeleton="block"; своего скелетона при загрузке данных нет (Заготовка до прихода кода) |
Атрибуты
template—string, по умолчаниюdefault.type—string, по умолчаниюnull.size—string, по умолчанию1.variant—string, по умолчаниюbuttons.scheme—string, по умолчаниюdefault. Встроенный вид кнопки:default,outlineилиlink. Это не выбор семантического цвета. Пользовательские шаблоны могут трактовать его по-своему.top-position—string, по умолчаниюstart.active-index—number, по умолчанию0.items—string, по умолчанию[]. Пункт (задаётся через setItems) может нести key (постоянный идентификатор для настроек; иначе индекс), icon, count (небольшой счётчик после подписи), href (вкладка — ссылка: активация переходит по адресу; у активной aria-current=page) и pinned (никогда не скрывается и неподвижна в настройках).root-class—string, по умолчанию пусто.top-class—string, по умолчанию пусто.panel-class—string, по умолчанию пусто.overflow—string, по умолчаниюscroll, значения:scroll,wrap,more. Что делают вкладки, когда не помещаются: scroll — ряд прокручивается, wrap — переносятся строки, more — не поместившиеся уходят в меню «Ещё (n)» в конце; активная всегда остаётся на месте.configurable—boolean, по умолчаниюfalse. Шестерёнка в конце вкладок («Настроить вкладки») открывает стандартное меню: вкладки списком с перетаскиванием, флажок видимости у каждой (закреплённые неподвижны) и «Сбросить» в подвале. Выбор хранит хост: sf-tabs-settings-change {order, hidden}, sf-tabs-settings-reset, setSettings({order, hidden}).
Методы
getData()— возвращаетobject. Возвращает данные, заданные через setData: {tabs, panels, …}; {tabs: [], panels: []}, если ничего не задано.setData(data: object|function, reason?: string)— возвращаетobject. Объединяет data с текущими данными (функция получает текущие данные и возвращает новые) и перерисовывает. tabs или items становятся вкладками; panels или content — панелями. Значение, не являющееся объектом, игнорируется.setItems(items: array|function, reason?: string)— возвращаетobject. Заменяет вкладки в данных (функция получает текущие вкладки) и перерисовывает.setPanels(panels: array|function, reason?: string)— возвращаетobject. Заменяет панели в данных (функция получает текущие панели) и перерисовывает.setState(nextState: object)— возвращаетobject. Записывает каждый ключ как атрибут в kebab-case; массив (items) сериализуется как записи label::flags, соединённые через |. false, null, undefined или пустое значение удаляет атрибут, true устанавливает его пустым.goTo(index: number|string)— возвращаетobject. Активирует вкладку с индексом index (индекс вне диапазона означает 0); ничего не делает для отключённой или активной вкладки. Устанавливает active-index и отправляет sf-tab-change.onTabChange(handler: function, options?: object|boolean)— возвращаетobject. Добавляет обработчик sf-tab-change; обработчик вызывается с (current, detail, event). Обработчик, не являющийся функцией, игнорируется.setSettings(settings: object)— возвращаетobject. Применяет сохранённую раскладку человека: {order: [keys], hidden: [keys]}. Ключ, которого больше нет среди пунктов, пропускается; пункт, не названный в порядке, встаёт на своё объявленное место видимым; закреплённая вкладка никогда не скрывается; активная вкладка видна на месте, даже если скрыта.
События
Все события приходят на сам элемент и всплывают. Общие события базового элемента перечислены в главе Жизненный цикл → Этапы.
sf-tab-change—detail:{ component: object, tagName: string, template: string, previous: number, current: number, item: object, items: array }.sf-tabs-settings-change—detail:{ order: array, hidden: array, reason?: string }. Человек переставил, показал или скрыл вкладку в настройках; применяется сразу. Хост сохраняет выбор и возвращает его через setSettings.sf-tabs-settings-reset—detail:{ }. Человек попросил вернуть объявленный порядок; компонент показывает его, пока хост не ответит через setSettings.
Доступность
- Роль: список вкладок (
tablist). - Доступное имя: обязательно.
- Клавиши:
Tab,ArrowLeft,ArrowRight,ArrowUp,ArrowDown,Home,End,Enter,Space. - Фокус: Встроенные текстовые вкладки и вкладки с иконкой используют одну доступную нативную точку табуляции и связанные панели. Стрелки навигации учитывают ориентацию и RTL, пропускают отключённые вкладки, переходят по кругу, переносят фокус и активируют вкладку. Перпендикулярные стрелки и клавиши вложенных виджетов обрабатываются локально. Дескриптор пользовательского компонента вкладки отвечает только за отображение: его именованная обёртка остаётся единственной точкой табуляции, а отрисованный Smart-компонент инертен.
Минимальная разметка
<sf-tabs></sf-tabs>
Источник
simai/ui@106d5901f8c3b4f23131ce0e7ede5dbd8abfe4f4:distr/smart/tabssimai/ui@106d5901f8c3b4f23131ce0e7ede5dbd8abfe4f4:distr/rule/rule.json#name=cl-tabs