oscript-ui
oscript-ui

Меню

Меню прячет действия за одной кнопкой: шестерёнкой в строке таблицы или именем вошедшего в шапке. На широком экране панель выпадает у самой кнопки, на телефоне встаёт нижним листом у края окна.

Когда использовать#

  • У строки таблицы больше двух действий, и кнопкам рядом с данными не хватает места.
  • Действия нужны редко: настройки, права, перенос — а не то, ради чего человек пришёл на экран.
  • Учётка в шапке: имя вошедшего, кабинет, выход.

Не берите меню для одного действия — поставьте кнопку. Не прячьте в меню главное действие экрана: его должно быть видно сразу. Навигация инсталляции живёт в едином меню, а не в этом компоненте.

В дереве холста меню собирается словами: подпись позицией, пункты — детьми, учётка и счётчик — словами (см. Язык узлов).

Узлом холста — словами

HTML = Кит.Меню("Меню учётки", Кит.ПунктМеню("Кабинет", "/кабинет").Иконка("аккаунт"), Кит.ФормаБезТокена("/выход", Кит.Кнопка("Выйти").Иконка("выход")).Вид("меню")) .Аккаунт("а.иванова").Рендер();

Как оно устроено#

Меню — кнопка-открывашка и панель пунктов при ней. Панель лежит в верхнем слое браузера (атрибут popover), поэтому строка таблицы от неё не растёт, а обёртка прокрутки её не обрезает. Открытие, закрытие щелчком мимо и по Esc, возврат фокуса на кнопку делает сам браузер: скрипта у меню нет.

На широком экране панель висит под кнопкой и растёт влево от её правого края: меню обычно стоит в последней колонке. Кнопка — якорь панели (anchor()); не хватит места снизу или слева — браузер отзеркалит панель. Появляется она из угла, как Grow в MUI.

На телефоне (до 900 пикселей) панель к кнопке не привязана: она выезжает листом от нижнего края окна, с ручкой сверху, затемнением под собой и заголовком — подписью меню. Пункты становятся строками под палец, по 56 пикселей.

Действия строки — шестерёнка открывает панель

Пункты = Новый Массив(); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Настройки", "/настройки", "шестерёнка")); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Права", "/настройки/доступ", "замок")); Пункты.Добавить(Новый Структура("HTML", Набор.Кнопка().Отрисовать( Новый Структура("Подпись, Вариант, Размер", "Сделать основным", "вторичная", "малый")))); HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты", "Меню строки «Альфа»", Пункты));

Пункты#

Пункт — либо ссылка (Подпись, Адрес, Иконка), либо готовый фрагмент в поле HTML: кнопка окна, форма из одной кнопки, примечание. Пункт без адреса и без HTML пропускается.

Вид пунктов задаёт меню, а не вызывающий. Ссылка, кнопка и форма из одной кнопки выглядят одинаково — строкой списка Material высотой 48 пикселей с иконкой слева, какой бы вариант кнопки ни пришёл. В примере выше «Сделать основным» передан вторичной кнопкой, а в панели стоит такой же строкой, как ссылки.

Действие, которое меняет данные, — форма из одной кнопки. Опасный пункт узнаётся красной подписью и иконкой, а не заливкой: залитая кнопка перекрикивала бы весь список.

Опасный пункт — форма из одной кнопки

Пункты = Новый Массив(); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Скачать выгрузку", "/проекты/альфа/выгрузка", "скачать")); Токен = "токен-сессии"; // CSRF-токен текущей сессии Удаление = Кит.Форма("/проекты/альфа/удалить", Кит.Кнопка("Удалить").Опасная().Иконка("корзина")).Токен(Токен).Вид("меню"); Пункты.Добавить(Новый Структура("HTML", Удаление.Рендер())); HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты", "Меню проекта «Альфа»", Пункты));

Форма с полями внутри меню остаётся маленькой формой: её кнопка не превращается в строку списка.

Несколько меню на странице#

В таблице меню столько же, сколько строк. Идентификатор связи кнопки с панелью кит выдаёт сам, порядковым номером: из данных в него ничего не попадает, и два похожих имени не откроют чужую панель.

Соседнее меню — свой идентификатор

Пункты = Новый Массив(); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Настройки", "/настройки", "шестерёнка")); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Права", "/настройки/доступ", "замок")); Пункты.Добавить(Новый Структура("HTML", Набор.Кнопка().Отрисовать( Новый Структура("Подпись, Вариант, Размер", "Сделать основным", "вторичная", "малый")))); HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты", "Меню строки «Бета»", Пункты));

Меню учётки#

Задано поле Аккаунт — открывашка печатается учёткой: значок, имя вошедшего и шеврон раскрытия, который переворачивается, пока панель открыта. Без него меню остаётся кнопкой-значком.

Счётчик показывает на кнопке, сколько ждёт человека. Ноль бейджа не печатает. ПодписьСчётчика называет число словами для скринридера и обязательна, когда бейдж есть.

Учётка — имя, счётчик и шеврон раскрытия

Пункты = Новый Массив(); Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Кабинет", "/кабинет", "аккаунт")); Пункты.Добавить(Новый Структура("HTML", Набор.Кнопка().Отрисовать( Новый Структура("Подпись, Вариант, Размер, Иконка", "Выйти", "ссылка", "малый", "выход")))); HTML = Набор.Меню().Отрисовать(Новый Структура( "Подпись, Аккаунт, Счётчик, ПодписьСчётчика, Пункты", "Меню учётки", "а.иванова", 3, "3 непрочитанных", Пункты));

Иконка открывашки по умолчанию — шестерёнка у меню строки и человечек у учётки. Своя задаётся полем Иконка.

Гайдлайны#

ДелайтеОдно действие — кнопкой на виду
Код
HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Размер, Иконка",
	"Настройки", "вторичная", "малый", "шестерёнка"));
Не делайтеМеню из одного пункта: лишний щелчок, и действие не видно
Код
Пункты = Новый Массив();
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Настройки", "/настройки", "шестерёнка"));

HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты",
	"Меню строки «Альфа»", Пункты));
ДелайтеУчётка показывает имя вошедшего
Код
Пункты = Новый Массив();
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Кабинет", "/кабинет", "аккаунт"));

HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Аккаунт, Пункты",
	"Меню учётки", "а.иванова", Пункты));
Не делайтеУчётка безымянным значком: не видно, под кем вошёл
Код
Пункты = Новый Массив();
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Кабинет", "/кабинет", "аккаунт"));

HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Иконка, Пункты",
	"Меню учётки", "аккаунт", Пункты));
ДелайтеПодпись меню называет свою строку
Код
Пункты = Новый Массив();
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Права", "/проекты/альфа/доступ", "замок"));
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Настройки", "/проекты/альфа/настройки", "шестерёнка"));

HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты",
	"Действия проекта «Альфа»", Пункты));
Не делайтеОдна подпись «Меню» во всех строках: скринридер прочтёт десять одинаковых кнопок
Код
Пункты = Новый Массив();
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Права", "/проекты/альфа/доступ", "замок"));
Пункты.Добавить(Новый Структура("Подпись, Адрес, Иконка",
	"Настройки", "/проекты/альфа/настройки", "шестерёнка"));

HTML = Набор.Меню().Отрисовать(Новый Структура("Подпись, Пункты",
	"Меню", Пункты));

Доступность#

  • Подпись обязательна: у кнопки-значка она уходит в aria-label, на телефоне становится заголовком листа. Без неё кит меню не соберёт.
  • У учётки видимый текст — имя, поэтому подпись меню уходит во всплывающую подсказку: скринридер читает то, что человек видит.
  • Состояние «открыто», Esc, щелчок мимо и возврат фокуса на кнопку даёт браузер по связке popovertarget — popover.
  • Открывашка — кнопка типа button: меню внутри формы не отправляет её при открытии.
  • Пустое меню кит не печатает, а кидает исключение: кнопка, открывающая пустоту, — сломанный экран.
  • Браузер без верхнего слоя показывает панель на месте, в потоке, со всеми пунктами — действия остаются доступны.

Узлом холста#

На холсте меню кладут в ячейку таблицы или в шапку объекта. Пункт-ссылка — Кит.ПунктМеню(Подпись, Адрес), любой другой ребёнок (кнопка, форма, примечание) становится пунктом как есть. Учётку задаёт слово .Аккаунт(Имя), бейдж — .Счётчик(Число, Подпись).

Меню узлом дерева

HTML = Кит.Меню("Меню строки «Гамма»", Кит.ПунктМеню("Настройки", "/настройки").Иконка("шестерёнка"), Кит.ПунктМеню("Права", "/настройки/доступ").Иконка("замок"), Кит.Кнопка("Сделать основным").Вторичная().Малая()).Рендер();

Модель#

Поля модели — из комментария в исходнике компонента. Структура с полем Пункты — прежний вид модели: в дереве холста пункты — дети узла Кит.Меню, остальные поля пишут его слова.

Кит.Меню()src/Классы/холст/Кит.os

Меню — кнопка-открывашка и панель пунктов при ней. Пункты — дети узла: Кит.ПунктМеню
становится пунктом-ссылкой, любой другой узел (форма, примечание) — пунктом как есть.
Слова: Иконка, Аккаунт, Счётчик(Число, Подпись).

Параметры:
 Модель - Строка, Структура - подпись меню (имя кнопки для скринридера); Структура —
          прежний вид модели с полем Пункты.
 Р1…Р8  - ЭлементЭкрана - (необязательные) пункты.

Возвращаемое значение:
 ЭлементЭкрана

Кит.ПунктМеню()src/Классы/холст/Кит.os

Пункт меню — ссылка в панели Кит.Меню. Печатается только внутри неё. Слова: Иконка.

Параметры:
 Подпись - Строка - что пункт показывает.
 Адрес   - Строка - куда ведёт.

Возвращаемое значение:
 ЭлементЭкрана

Меню.Отрисовать()src/Классы/компоненты/Меню.os

Отрисовывает меню: кнопку-открывашку и её панель.

Параметры:
 Модель - Структура - Подпись (обязательна: имя кнопки для скринридера и видимый
          заголовок панели там, где она встаёт листом у края окна), Иконка
          (по умолчанию "шестерёнка", у меню учётки — "аккаунт"), Аккаунт (имя,
          которое кнопка показывает ТЕКСТОМ: с ним открывашка печатается учёткой —
          значок, имя и шеврон раскрытия, — а без него остаётся кнопкой-значком),
          Счётчик (число на открывашке; ноль и отсутствие бейджа не печатают),
          ПодписьСчётчика (чем это число называется в речи; обязательна, когда бейдж
          печатается), Пункты (Массив: либо модель кнопки-ссылки — Подпись, Адрес,
          Иконка, — либо структура с полем HTML: ДОВЕРЕННЫЙ фрагмент, например форма
          или примечание. Пункт без Адреса и без HTML пропускается).

Возвращаемое значение:
 Строка - HTML-фрагмент. Кидается исключением, если Подпись пуста либо панель
          осталась пустой.