Справочник

Компоненты

Тонкие компоненты поверх общей таблицы стилей: каждый отдаёт одни и те же классы aura-* во всех фреймворках — именно поэтому четыре библиотеки выглядят одинаково. Точки показывают, что реально есть в каждом: ● полностью,◐ есть, но с расхождениями,○ не портирован,▣ класс, обёртка не нужна.

Темизация

Примитивы

Typography

Карта шрифтов. Берёт размер, начертание, трекинг и интерлиньяж из шкалы токенов и рендерит осмысленный элемент под каждый вариант (h1 для `h1`, p для `body`, code для `mono`).

● React● Vue● Svelte● Angular

Button

Кнопка. Две независимые оси: `variant` решает, как применён цвет — заливка (`primary`), обводка (`secondary`), голая подпись в коробке высотой с контрол (`ghost`) или без неё (`text`), — а `tone` решает, каким цветом, из тех же двенадцатиступенчатых шкал, что читают бейджи и алерты. Пробрасывает все нативные атрибуты кнопки.

● React● Vue● Svelte● Angular

Card

Поверхность, приподнятая над холстом: `--surface` на шаг светлее `--canvas` в обеих темах, под ним — тень. `elevation` называет токен тени, а не саму тень: `flat` — это `--shadow-1`, а не её отсутствие. В тёмной теме все три токена переопределены на более плотный чёрный, потому что мягкая сине-серая тень, отделяющая карточку от белого холста, на почти чёрном не видна. Карточка с заголовком — самое частое, что из неё строят, поэтому для неё есть три класса — `.aura-card__header`, `.aura-card__extra` и `.aura-card__footer`, — а не слоты у компонента: они ставятся на ваши собственные `<header>` и `<footer>` и выходят обратно к краям карточки, чтобы линейка под заголовком доходила до обоих краёв, а не обрывалась внутри паддинга.

● React● Vue● Svelte● Angular

Badge

Статусная плашка. `accent` — это базовый класс без модификатора; остальные тона ложатся на семантические цветовые токены. Тон здесь — не палитра, а один цвет и сила его подложки, читаемые через `--aura-badge-color` и `--aura-badge-tint`. Поэтому набор открыт с обеих сторон: `.aura-badge--warning { --aura-badge-tint: 22% }` меняет встроенный тон, не трогая алерты и тосты, которые делят `--warning`, а свой класс, задающий эти два свойства, — это шестой тон, без форка стилей и без нового пропа с нашей стороны.

● React● Vue● Svelte● Angular

IconButton

Квадратная кнопка только с иконкой. Своего набора иконок у Aura нет — передайте свой SVG содержимым.

● React● Vue● Svelte● Angular

Chip

Тег, при желании — удаляемый. Крестик идёт вместе с компонентом; событие удаления во всех четырёх библиотеках называется по-своему.

● React● Vue● Svelte● Angular

Switch

Переключатель с `role="switch"` и `aria-checked` — стили цепляются за ARIA-состояние, а не за класс. Срабатывает по клику и по Space/Enter: это настоящая кнопка.

● React● Vue● Svelte◐ Angular

Field

Текстовое поле с подписью. Если id не передан, подпись связывается с полем через сгенерированный id.

● React● Vue● Svelte● Angular

Scroll

Скроллируемая область. Граница — это проп `maxHeight`: контейнер, свободный расти, никогда не переполнится, поэтому область скролла без высоты — обычный div. Место под скроллбар зарезервировано всегда, поэтому текст не дёргается вбок в момент, когда контент переваливает за границу, а докрутив до конца, область не отдаёт колесо странице позади.

● React● Vue● Svelte● Angular

Checkbox

Настоящий `<input type="checkbox">` под кастомной отрисовкой. Подпись оборачивает input, а не ссылается на него, поэтому id не нужен и два чекбокса на странице не столкнутся.

● React● Vue● Svelte● Angular

RadioGroup

Радиокнопки, которые действительно группа: у них общий `name`, поэтому браузер сам делает их взаимоисключающими и бесплатно даёт навигацию стрелками — которая одновременно и перемещает, и выбирает. `<fieldset role="radiogroup">` с `<legend>` проговаривает название группы с каждым вариантом.

● React● Vue● Svelte● Angular

Radio

Одиночный `<input type="radio">`. Сам по себе нужен редко: радиокнопки взаимоисключающи только при общем `name`, и стрелки ходят внутри этой группы — берите `RadioGroup`, если только не раскладываете группу вручную.

● React● Vue● Svelte● Angular

Textarea

Близнец поля, только без фиксированной высоты. `resize` только вертикальный: textarea, которую можно растянуть вширь, вылезает из того, что её разложило. `autoGrow` заставляет её вместо этого расти вместе с содержимым, и это чистый CSS: вся реализация — `field-sizing: content`, никакого обработчика нажатий с замером `scrollHeight`, и работает даже в разметке, которая никогда не гидрировалась. Где свойство не поддерживается, поле остаётся фиксированной коробкой со скроллом.

● React● Vue● Svelte● Angular

Select

Селект на настоящем листбоксе: группы, описания и опции, которые вы рисуете сами, — нативный `<select>` не умеет ничего из этого, поэтому в библиотеке именно такой. Триггер — `<button role="combobox">`, и фокус его не покидает: курсор по списку виртуальный, поэтому нечего запирать и нечего возвращать.

● React● Vue● Svelte● Angular

MultiSelect

Выбор нескольких значений. Каждый выбранный становится чипом внутри поля, а само поле — текстовый input, которым список и фильтруется: выбор и поиск происходят в одном месте, а не в двух. `role="combobox"` стоит на этом input, а не на коробке вокруг, — владельцем списка должно объявляться то, где находится курсор. Чипы — это `Chip` размера `sm`. Чего этот паттерн не даёт ни в одном из четырёх пакетов: скринридер на инпуте не зачитывает чипы обратно. У кнопки удаления каждого чипа есть собственное имя («Удалить Apple») — это доступная часть, и у паттерна multiselect в APG форма та же. Записано как есть, а не залатано через `aria-describedby`, который быстро устареет.

● React● Vue● Svelte● Angular

Fieldset

Группирует связанные контролы — настоящая пара `<fieldset>`/`<legend>`, а не div с `role="group"`. Именно нативная пара заставляет скринридер проговаривать легенду с каждым контролом внутри, а `disabled` на ней выключает их все, не трогая ни один.

● React● Vue● Svelte● Angular

Accordion

Раскрывающиеся панели на `<details>`/`<summary>` — без состояния, без обработчиков, без JavaScript. Нативная пара уже является кнопкой, которая сообщает своё состояние, срабатывает по Enter и Space и находится поиском по странице: браузер сам раскроет закрытую панель, чтобы показать совпадение.

● React● Vue● Svelte● Angular

SegmentedControl

Ряд взаимоисключающих вариантов — то есть radiogroup, и сделан именно как radiogroup. Радиокнопки скрыты только отрисовкой, но не `display: none`: это выкинуло бы их из таб-ордера и из группы, по которой ходят стрелки. Браузер по-прежнему даёт исключающий выбор и навигацию, а подпись только рисует.

● React● Vue● Svelte● Angular

Alert

Сообщение, требующее внимания. По умолчанию вежливое: `role="alert"` заставляет скринридер прервать чтение — это верно для только что появившегося сообщения и неверно для того, что было на странице всегда. `urgent` — только для первого случая. Тон — это цвет и сила подложки, читаемые через `--aura-alert-color` и `--aura-alert-tint`, поэтому `.aura-alert--brand { --aura-alert-color: var(--brand) }` — шестой тон без форка стилей.

● React● Vue● Svelte● Angular

Avatar

Лицо — или инициалы вместо него. Имя живёт на корне, а не на картинке: с инициалами никакого `<img>` нет, а сами буквы — украшение: «AB» вслух это шум. Поэтому же `initials` необязателен: имя у аватара уже есть, буквы выводятся из него, а передавать их вручную нужно там, где такой вывод неверен.

● React● Vue● Svelte● Angular

AvatarGroup

Стопка аватаров внахлёст. У каждого остаётся кольцо цвета холста — именно оно не даёт двум соседним лицам слиться в одно пятно. Рисуется box-shadow, поэтому ничего не стоит для раскладки.

● React● Vue● Svelte● Angular

Skeleton

Заглушка для ещё не пришедшего контента. Всегда `aria-hidden`: читать «loading» по разу на каждую заглушку хуже тишины — `aria-busy` вешайте на ожидающий регион, у него есть имя.

● React● Vue● Svelte● Angular

Loader

Индикатор без определённого прогресса. Обёртка — `role="status"` с подписью; кольцо `aria-hidden`, потому что крутящейся рамке нечего сказать. При `prefers-reduced-motion` оно продолжает вращаться: замерший спиннер читается как зависание, а не как спокойствие.

● React● Vue● Svelte● Angular

Progress

Полоса с известным прогрессом. Число указывается один раз и отрисовывается дважды из одного источника: элемент несёт `--aura-value`, стили превращают его в ширину, а `aria-valuenow` сообщает то же самое. Значения зажимаются: полоса за собственный край — баг, который вызывающий не должен увидеть.

● React● Vue● Svelte● Angular

Code

Инлайновый код и его блочный близнец. «Пилюля» — для фрагмента внутри строки прозы; у блока заливка уступает место рамке, потому что фон под многими строками борется с текстом, который должен держать.

▣ React▣ Vue▣ Svelte▣ Angular

Blockquote

Цитата, отмеченная акцентной линией сбоку, а не курсивом: целый абзац курсивом читается хуже, а не «цитатнее».

▣ React▣ Vue▣ Svelte▣ Angular

List

Список, упорядоченный или нет, с приглушёнными маркерами. `--plain` убирает их совсем — для списка, который список семантически, но не визуально: навигация, лента, стопка карточек.

● React● Vue● Svelte● Angular

Mark

Выделенный текст — акцентная подложка под словами. Цвет самого текста сознательно не трогается: если перекрасить и его, выделение станет нечитаемым.

▣ React▣ Vue▣ Svelte▣ Angular

Anchor

Ссылка. Подчёркнута по умолчанию, и это не украшение: один только цвет не является affordance — ссылка, отличающаяся от текста лишь оттенком, исчезает для тех, кто этот оттенок не различает.

▣ React▣ Vue▣ Svelte▣ Angular

Indicator

Точка в углу чего-либо — непрочитано, онлайн, требует внимания. Обёртка задаёт только контекст позиционирования и не трогает раскладку того, что оборачивает. Если внутри число, точка вырастает в «пилюлю», а не обрезает его.

● React● Vue● Svelte● Angular

RingProgress

Детерминированное кольцо — та же роль `progressbar`, что у `Progress`, но нарисованная одним conic-gradient, без SVG. `label` даёт ему имя, а дети заполняют середину: кольцо с надписью «70%» всё ещё обязано сказать, чего именно 70%.

● React● Vue● Svelte● Angular

Toast

Стопка исчезающих сообщений и первое в библиотеке, у чего есть настоящий уход. Область — это live-регион, и она рендерится даже пустой: регион, добавленный на страницу одновременно с первым сообщением, — это регион, за которым вспомогательные технологии не следили, и сообщение просто теряется.

● React● Vue● Svelte● Angular

Tabs

Полоса вкладок и её панели. SegmentedControl выглядит похоже и устроен иначе: это радиогруппа на настоящих инпутах, поэтому исключающий выбор, стрелки и переходящий tabindex браузер даёт даром. У вкладки нативного элемента нет, поэтому клавиатура написана вручную — она лежит в `@ilomee/aura-core/listbox`, рядом с курсором, общим у полосы вкладок, листбокса и меню.

● React● Vue● Svelte● Angular

Dialog

Модальный диалог: затемнение, карточка по центру, ловушка фокуса и блокировка прокрутки. Всё это уже существовало — внутри рецепта FormDialog, из-за чего рецепт был единственным способом получить модалку, и диалог, не являющийся формой, означал заново написанные ловушку, блокировку, клик по затемнению и aria. После выделения примитива от рецепта остался Dialog с формой внутри, а это пример, а не компонент. Диалог с заголовком и рядом кнопок внизу собирается из тех же трёх композиционных классов, что и карточка, — `.aura-card__header`, `.aura-card__extra` и `.aura-card__footer` — на ваших собственных `<header>` и `<footer>` внутри слота по умолчанию. Имена «карточные», потому что `.aura-dialog` носит `.aura-card`: второго набора учить не нужно, а отрицательный маргин, выводящий линейку к краям панели, — это и есть причина, по которой они существуют.

● React● Vue● Svelte● Angular

Popover

Панель с произвольным содержимым, привязанная к элементу, — карточка внутри попапа, ровно как и записано в комментарии к `.aura-popup`. От тултипа отличается не формой, а тем, что с ней можно делать: тултип это подпись, он закрывается при уходе указателя, а поповер держит то, с чем взаимодействуют, поэтому открывается по клику, сохраняет фокус и закрывается по Escape или клику снаружи. Привязка — единственное, что каждый пакет пишет по-своему: React клонирует элемент триггера, Vue — vnode, Svelte отдаёт триггеру пропсы для раскрытия, Angular — директива, принимающая панель как шаблон. Ни один не добавляет элемента: обёртка портировалась бы всюду и встала бы между триггером и его раскладкой.

● React● Vue● Svelte● Angular

Menu

Список команд, привязанный к тому, что его открыло. Третье, что висит на `place()`, и отличие от двух других — в том, что читатель с ним делает: тултип читают, в поповере работают, а из меню запускают команду и оно исчезает, поэтому любая строка его закрывает. Это и не Select: селект сообщает выбранное значение и объявляет его выбранным, меню же запускает и не сообщает ничего — потому здесь ни одна строка не бывает `aria-selected`, а в списке нет галочки. Фокус — вторая половина того же отличия. Селект держит фокус на триггере и указывает оттуда `aria-activedescendant`; меню переносит фокус внутрь списка, а Tab его закрывает, а не гоняет по кругу: меню, из которого нельзя выйти вперёд, — это ловушка, а не меню. Передайте `point`, и оно откроется по координатам, а не рядом с триггером, — это и есть контекстное меню.

● React● Vue● Svelte● Angular

Tooltip

Пояснение, появляющееся рядом с элементом по наведению или фокусу. Указатель ждёт задержку — задержаться на чём-то ещё не значит захотеть подсказку, — а клавиатура открывает сразу: придя по Tab, читатель уже выбрал. Собственного элемента у тултипа нет, поэтому каждый пакет цепляет его так, чтобы ничего не добавить в дерево: React клонирует ребёнка, Vue — vnode, Svelte цепляется к узлу, Angular — директива, снимающая собственный атрибут после сопоставления. Обёртка портировалась бы всюду и была бы хуже: на flex-элементе она меняла бы вёрстку, которую должна была только пояснить. ⚠️ Тултип на `disabled`-контроле не открывается никогда, и никакая обёртка с нашей стороны этого не изменит: отключённый элемент вообще не шлёт pointer-события, открывать нечем. Ровно наоборот тому, что нужно: подсказка на отключённой кнопке — это как раз та, что объясняет, *почему* она отключена. Ответ — `aria-disabled="true"` вместо `disabled` плюс ранний выход в собственном обработчике. Контрол остаётся фокусируемым и наводимым, объявляет себя отключённым и поддаётся объяснению; стили рисуют его инертным и — с тех пор как это проверили — больше не дают ему подпрыгивать, менять цвет и вдавливаться под указателем.

● React● Vue● Svelte● Angular

HabitHeatmap

Тепловая карта в стиле карты вкладов. Интенсивность выводится из самих значений, настраивать цвета не нужно.

● React● Vue● Svelte● Angular

DataTable

Таблица, описываемая конфигом. У каждой колонки свой рендерер, поэтому таблица остаётся обобщённой по типу строки.

● React● Vue● Svelte● Angular

StepWizard

Шапка пошагового мастера с отметкой текущего шага. Содержимое шагов — на вас.

● React● Vue● Svelte● Angular

TimeGrid

Недельная сетка календаря с живой линией «сейчас».

● React● Vue● Svelte● Angular

Лэйаут

Stack

Флекс-контейнер, по умолчанию вертикальный. Рабочая лошадка: большинство лэйаутов в Aura — это Stack из Group-ов.

● React● Vue● Svelte● Angular

Flex

Флекс-контейнер, по умолчанию горизонтальный. Ручки те же, что у Stack, но `direction` принимает любое значение CSS flex-direction.

● React● Vue● Svelte● Angular

Group

Строка, которая переносится. Для списков тегов, рядов кнопок — всего, что должно перетекать, а не вылезать за край.

● React● Vue● Svelte● Angular

Grid

CSS-грид в двух режимах: фиксированное или адаптивное число колонок, либо авто-подгонка через `minItemWidth`. Брейкпоинты считаются чистым CSS — никакого JS с медиазапросами.

● React● Vue● Svelte● Angular

Container

Центрированная колонка страницы с максимальной шириной и боковыми отступами.

● React● Vue● Svelte● Angular

Masonry

Кладка в колонки. Сейчас работает на CSS-колонках и сама переключается на нативный grid-masonry через `@supports` там, где браузер его умеет.

● React● Vue● Svelte● Angular

Divider

Разделитель. В React рендерит настоящий `<hr>`, поэтому для скринридеров это ориентир, а не декоративный div.

● React● Vue● Svelte◐ Angular

Spacer

Распорка на `flex: 1`, растаскивающая соседей по краям. Для скринридеров скрыта.

▣ React▣ Vue▣ Svelte▣ Angular