@olddevs/ui 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,9 +12,10 @@ story: src/components/navigation/MegaMenu.stories.tsx
12
12
  ## Кратко для AI
13
13
 
14
14
  `MegaMenu` — каталог магазина в духе Amazon: слева Столбец категорий, справа от наведённой Категории — её
15
- Витрина с колонками ссылок и любым своим содержимым. Это навигация по ссылкам, а не меню команд: разметка по
15
+ Полка с колонками ссылок и любым своим содержимым. Это навигация по ссылкам, а не меню команд: разметка по
16
16
  шаблону WAI-ARIA Disclosure Navigation (`nav`, кнопки с `aria-expanded`, настоящие `a`). Категории —
17
- `MegaMenuCategory` прямыми детьми, колонки — `MegaMenuGroup`, ссылки — `MegaMenuLink`. Тот же каталог
17
+ `MegaMenuCategory` (прямо или внутри своих компонентов, в том числе серверных), колонки — `MegaMenuGroup`,
18
+ ссылки — `MegaMenuLink`. Текущий раздел и текущая страница — проп `active`, как у `NavItem`. Тот же каталог
18
19
  открывается выпадающим оверлеем от кнопки: `MegaMenuTrigger` с `MegaMenuButton` и неизменным `MegaMenu`.
19
20
 
20
21
  ## Когда использовать
@@ -22,7 +23,7 @@ story: src/components/navigation/MegaMenu.stories.tsx
22
23
  - Каталог с десятком и больше разделов, у каждого — подразделы колонками: магазин, маркетплейс, справочный
23
24
  портал.
24
25
  - Разделы надо показать сразу, а подразделы — по наведению, не уводя пользователя со страницы.
25
- - В Витрине рядом со ссылками нужно своё содержимое: промо-карточка, картинка, подборка.
26
+ - В Полке рядом со ссылками нужно своё содержимое: промо-карточка, картинка, подборка.
26
27
 
27
28
  ## Когда не использовать
28
29
 
@@ -37,10 +38,10 @@ story: src/components/navigation/MegaMenu.stories.tsx
37
38
  import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddevs/ui";
38
39
 
39
40
  <MegaMenu aria-label="Каталог">
40
- <MegaMenuCategory id="computers" label="Компьютеры" href="/computers">
41
+ <MegaMenuCategory id="computers" label="Компьютеры" href="/computers" active>
41
42
  <MegaMenuGroup title="Ноутбуки" href="/computers/laptops">
42
43
  <MegaMenuLink href="/computers/laptops/gaming">Игровые</MegaMenuLink>
43
- <MegaMenuLink href="/computers/laptops/ultrabooks" current>
44
+ <MegaMenuLink href="/computers/laptops/ultrabooks" active>
44
45
  Ультрабуки
45
46
  </MegaMenuLink>
46
47
  </MegaMenuGroup>
@@ -57,62 +58,75 @@ import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddev
57
58
  | ------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------ |
58
59
  | `aria-label` | — | Доступное имя навигации, обязательно: на странице с несколькими `nav` их различают по нему |
59
60
  | `value` / `defaultValue` / `onValueChange` | `null` | Открытая Категория (её `id`) или `null`, управляемо или нет |
60
- | `showcaseWidth` | `"40rem"` | Ширина Витрины, одна на все Категории: каталог не прыгает при переходе между ними |
61
+ | `showcaseWidth` | `"40rem"` | Ширина Полки, одна на все Категории: каталог не прыгает при переходе между ними |
61
62
  | `className` | — | Классы на `nav`; ширина Столбца по умолчанию — `w-64` |
62
63
 
63
- `MegaMenuCategory`: `id` — ключ для `value`; `label` — подпись в Столбце и имя Витрины; `icon`; `href` или
64
- `link` — адрес раздела целиком; `disabled`; дети — содержимое Витрины. У Категории с Витриной адрес становится
65
- заголовком-ссылкой в начале Витрины, у Категории без детей сама строка Столбца — ссылка. `link` — ссылка роутера
64
+ `MegaMenuCategory`: `id` — ключ для `value`; `label` — подпись в Столбце и имя Полки; `icon`; `href` или
65
+ `link` — адрес раздела целиком; `disabled`; `active` — текущая страница лежит в этом разделе; дети —
66
+ содержимое Полки. У Категории с Полкой адрес становится
67
+ заголовком-ссылкой в начале Полки, у Категории без детей сама строка Столбца — ссылка. `link` — ссылка роутера
66
68
  пустым элементом (`link={<Link href="/x" />}`), подпись уезжает внутрь; это отдельный проп, а не `asChild`,
67
- потому что дети Категории — её Витрина.
69
+ потому что дети Категории — её Полка.
68
70
 
69
- `MegaMenuGroup`: `title` — заголовок колонки, он же подпись списка; `href` делает заголовок ссылкой; дети —
70
- `MegaMenuLink`, каждая уезжает в свой пункт списка.
71
+ `active` у Категории ставит `aria-current="true"` и красит подпись акцентным цветом — тем же, что у текущей
72
+ ссылки. Открыта Полка или нет, отметка остаётся: текущий раздел задаёт маршрут, а не наведение. Открытая
73
+ Категория по-прежнему выделена фоном, так что у одной строки бывают оба признака. Пока ни одна Полка не открыта,
74
+ Tab приходит в Столбец на текущий раздел. Какой раздел текущий, решает потребитель, как с `active` у `NavItem`.
71
75
 
72
- `MegaMenuLink`: обычные пропы `a`, `icon`, `current` и `asChild`. `current` ставит `aria-current="page"` и вид
76
+ Категории не обязаны быть прямыми детьми `MegaMenu`: их можно разложить по своим компонентам и рендерить из
77
+ серверного компонента Next.js. Каждая Категория сама сообщает Столбцу о себе, а Столбец не разбирает детей по
78
+ типу — у серверного компонента тип элемента на клиенте другой. До гидратации, пока Категории о себе не сообщили,
79
+ остановка Tab стоит у каждой доступной Категории; после гидратации Столбец снова одна остановка.
80
+
81
+ `MegaMenuGroup`: `title` — заголовок колонки, он же подпись списка; `href` или `link` делают заголовок ссылкой
82
+ (`link` — ссылка роутера пустым элементом, как у Категории); дети — `MegaMenuLink`, каждая уезжает в свой пункт
83
+ списка, в том числе пришедшие фрагментом.
84
+
85
+ `MegaMenuLink`: обычные пропы `a`, `icon`, `active` и `asChild`. `active` ставит `aria-current="page"` и вид
73
86
  текущей: текущую страницу кит не вычисляет, правила сравнения адресов у каждого роутера свои. `asChild` выводит
74
- ссылку элементом роутера: `<MegaMenuLink asChild><Link href="/x">Подпись</Link></MegaMenuLink>`.
87
+ ссылку элементом роутера: `<MegaMenuLink asChild><Link href="/x">Подпись</Link></MegaMenuLink>`. Прежнее имя
88
+ `current` работает до 5.0 и помечено `@deprecated`: текущий пункт навигации в ките называется `active`.
75
89
 
76
- ## Наведение и Витрина
90
+ ## Наведение и Полка
77
91
 
78
- Наведение мышью на Категорию открывает её Витрину сразу, без задержки. Подсвечена ровно та Категория, чья
79
- Витрина открыта: подсветка идёт по `aria-expanded`, а не по `:hover`. Наведение на Категорию без Витрины
92
+ Наведение мышью на Категорию открывает её Полку сразу, без задержки. Подсвечена ровно та Категория, чья
93
+ Полка открыта: подсветка идёт по `aria-expanded`, а не по `:hover`. Наведение на Категорию без Полки
80
94
  закрывает открытую — с той же оговоркой про Прицел, что ниже.
81
95
 
82
- Витрина закрывается, когда курсор ушёл и со Столбца, и с Витрины, через 150 мс: короткий выход за край не
96
+ Полка закрывается, когда курсор ушёл и со Столбца, и с Полки, через 150 мс: короткий выход за край не
83
97
  сбрасывает каталог. Закрывают её и нажатие указателем вне каталога, и уход фокуса со страницы каталога.
84
98
 
85
- Содержимое Витрины монтируется только у открытой Категории: каталог из сотни ссылок и картинок не грузит всё
99
+ Содержимое Полки монтируется только у открытой Категории: каталог из сотни ссылок и картинок не грузит всё
86
100
  разом. Сам регион есть всегда, скрытым: на него указывает `aria-controls` кнопки.
87
101
 
88
- Витрина — потомок своей Категории в DOM, а не портал. Поэтому порядок Tab идёт «Категория → её ссылки → дальше
89
- по странице», и Витрина встаёт вплотную к Столбцу без расчёта позиции. Предок с `overflow: hidden` её обрежет:
102
+ Полка — потомок своей Категории в DOM, а не портал. Поэтому порядок Tab идёт «Категория → её ссылки → дальше
103
+ по странице», и Полка встаёт вплотную к Столбцу без расчёта позиции. Предок с `overflow: hidden` её обрежет:
90
104
  ставьте каталог туда, где рядом есть место.
91
105
 
92
- Витрина стоит со стороны конца строки — справа, а при письме справа налево слева. Если там не хватает места, а с
106
+ Полка стоит со стороны конца строки — справа, а при письме справа налево слева. Если там не хватает места, а с
93
107
  другой стороны хватает, она переходит на другую сторону; сторону кит меряет заранее и при смене размера окна,
94
- поэтому стрелка «к Витрине» сразу смотрит туда, где Витрина окажется.
108
+ поэтому стрелка «к Полке» сразу смотрит туда, где Полка окажется.
95
109
 
96
110
  ## Касание и узкий экран
97
111
 
98
112
  Касание наведения не знает, поэтому Категорию открывает само касание (`click`), без Прицела. Указатель с
99
- `pointerType` «touch» или «pen» не открывает Категорию наведением и не закрывает Витрину уходом: перо
113
+ `pointerType` «touch» или «pen» не открывает Категорию наведением и не закрывает Полку уходом: перо
100
114
  ведёт себя как палец. Повторное касание открытой Категории её не закрывает и никуда не ведёт: закрывает
101
- Витрину касание вне каталога или Escape.
115
+ Полку касание вне каталога или Escape.
102
116
 
103
117
  Мышь ведёт себя, как раньше: наведение, Прицел и закрытие через 150 мс остаются, пока экран широкий.
104
118
 
105
- На узком экране — меньше 640px, граница та же, что у подменю `Menu` и подменю Редактора, — Витрине некуда
119
+ На узком экране — меньше 640px, граница та же, что у подменю `Menu` и подменю Редактора, — Полке некуда
106
120
  встать сбоку: справа от Столбца её обрезал бы край окна. Поэтому каталог идёт «спуском»:
107
121
 
108
122
  - Столбец занимает всю ширину, подписи Категорий переносятся, а не обрезаются.
109
- - Открытая Категория (касанием, щелчком, Enter или Пробелом) заменяет Столбец своей Витриной. Витрина
123
+ - Открытая Категория (касанием, щелчком, Enter или Пробелом) заменяет Столбец своей Полкой. Полка
110
124
  начинается строкой «Назад» с названием Категории; если у Категории есть своя ссылка, название показывает она,
111
125
  строкой ниже, а не строка «Назад». Ниже — колонки ссылок, одна под другой.
112
126
  - «Назад» возвращает Столбец и ставит фокус на Категорию, из которой человек пришёл. Escape внутри
113
- Витрины работает как «Назад».
127
+ Полки работает как «Назад».
114
128
  - Фокус при спуске переходит на «Назад»: кнопка Категории скрыта вместе со Столбцом, и фокус на ней
115
- пропал бы. Стрелка в сторону Столбца в Витрине на узком экране ничего не делает: Столбца рядом нет.
129
+ пропал бы. Стрелка в сторону Столбца в Полке на узком экране ничего не делает: Столбца рядом нет.
116
130
  - Прицела на узком экране нет, наведение мышью Категорию не открывает, а уход мыши не отменяет спуск:
117
131
  заменять Столбец под курсором значило бы вырывать его из-под руки.
118
132
  - Разметка остаётся по шаблону disclosure: кнопка Категории сохраняет `aria-expanded` и `aria-controls`
@@ -123,25 +137,25 @@ import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddev
123
137
 
124
138
  Ширину кит читает через `matchMedia`, а не через CSS: от неё зависит состав разметки (прячется Столбец), а
125
139
  не только вид. До гидратации и на сервере хук возвращает «широкий» (ADR-0018): сервер ширины не знает, и
126
- разметка с него всегда обычная. На телефоне после гидратации Витрина, открытая `defaultValue`, один раз
140
+ разметка с него всегда обычная. На телефоне после гидратации Полка, открытая `defaultValue`, один раз
127
141
  перерисовывается спуском. На телефоне `nav` занимает всю ширину классом `max-sm:w-full`; `w-*` из `className` действует на
128
142
  широком экране.
129
143
 
130
144
  ## Прицел
131
145
 
132
- Курсор идёт от Категории к её Витрине наискосок и по пути задевает соседние Категории. Если бы наведение
133
- открывало их сразу, Витрина менялась бы у человека под рукой, и до ссылки было бы не дотянуться. Прицел смотрит,
134
- куда движется курсор: пока он идёт в сторону открытой Витрины, соседняя Категория наведение не перехватывает.
146
+ Курсор идёт от Категории к её Полке наискосок и по пути задевает соседние Категории. Если бы наведение
147
+ открывало их сразу, Полка менялась бы у человека под рукой, и до ссылки было бы не дотянуться. Прицел смотрит,
148
+ куда движется курсор: пока он идёт в сторону открытой Полки, соседняя Категория наведение не перехватывает.
135
149
 
136
150
  - Направление последнего шага курсора сравнивается с сектором от его прежней точки к двум углам ближнего края
137
- Витрины — это и есть треугольник Каменса из раздела «Откуда это». Шаг в сектор — курсор целится.
151
+ Полки — это и есть треугольник Каменса из раздела «Откуда это». Шаг в сектор — курсор целится.
138
152
  - Одно движение мимо прощается, два подряд — нет: тогда открывается Категория под курсором.
139
153
  - Курсор остановился на 300 мс — открывается Категория под ним, даже если он целился. Меню не «залипает».
140
- - Курсор дошёл до Витрины — отложенная смена отменяется.
154
+ - Курсор дошёл до Полки — отложенная смена отменяется.
141
155
  - Щелчок по Категории открывает её сразу, мимо Прицела. Клавиатура Прицела не знает вовсе.
142
156
  - Только мышь, и только на широком экране: касание и перо открывают Категорию сразу, а на узком экране
143
157
  Прицела нет вовсе.
144
- - Первое наведение, пока Витрины нет, открывает Категорию без всякой задержки: целиться ещё не во что.
158
+ - Первое наведение, пока Полки нет, открывает Категорию без всякой задержки: целиться ещё не во что.
145
159
 
146
160
  Модель та же, что у подменю react-aria (`Menu` с `SubmenuTrigger`), чтобы два меню кита вели себя одинаково.
147
161
  Отличий два. Смена Категории откладывается, а не гасится `pointer-events: none` на Столбце: иначе пропала бы
@@ -166,6 +180,11 @@ import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddev
166
180
  внутри треугольника значит, что человек ведёт курсор к подменю, и пункты, задетые по пути, его не перехватывают.
167
181
  Курсор вышел из треугольника — подменю меняется сразу. Свой разбор Каменс опубликовал 6 марта 2013 года.
168
182
 
183
+ ![Меню Amazon: треугольник от курсора к верхнему и нижнему углам подменю](https://ui.olddevs.ru/images/mega-menu/amazon-triangle.gif)
184
+
185
+ _Анимация из [поста Бена Каменса](https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown), в
186
+ пересказе на Хабре._
187
+
169
188
  **Плагин и математика.** По этому принципу Каменс написал jQuery-плагин `jQuery-menu-aim` и поставил его в
170
189
  новое меню «Learn» на Khan Academy. Попадание точки в треугольник проверяется векторным произведением — с этой
171
190
  линейной алгеброй ему помогла Софи Алперт, — но в плагине Каменс выбрал способ попроще: сравнение наклонов прямых.
@@ -189,15 +208,20 @@ import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddev
189
208
  ## Клавиатура и имена
190
209
 
191
210
  - Столбец — одна остановка Tab. Стрелки вверх и вниз, Home и End ходят по Категориям; выключенные
192
- пропускаются. Вернувшись Tab'ом, пользователь попадает на ту Категорию, где был.
193
- - Enter, Пробел и стрелка в сторону Витрины открывают её и ставят фокус на первую ссылку. У Категории-ссылки
211
+ пропускаются. Вернувшись Tab'ом, пользователь попадает на ту Категорию, где был; в первый раз — на открытую,
212
+ иначе на текущий раздел (`active`), иначе на первую.
213
+ - Буква на Категории переводит фокус на следующую Категорию, чья подпись с неё начинается, по кругу; та же буква
214
+ ещё раз — на следующую. Буквы, набранные подряд, ищут начало подписи, пауза в полсекунды сбрасывает набранное.
215
+ Пробел посреди набора — часть подписи («Home and garden»), а не открытие Категории.
216
+ Буква с Ctrl, Cmd или Alt — сочетание клавиш, каталог её не трогает.
217
+ - Enter, Пробел и стрелка в сторону Полки открывают её и ставят фокус на первую ссылку. У Категории-ссылки
194
218
  Enter — переход.
195
- - Внутри Витрины работает обычный Tab. Стрелка в сторону Столбца возвращает фокус на Категорию, Escape — тоже,
196
- и закрывает Витрину. Tab за последней ссылкой уходит дальше по странице и закрывает Витрину.
197
- - Пока Витрина открыта, она следует за фокусом стрелок, как следует за наведением.
198
- - Стрелка «к Витрине» — та, что смотрит туда, где Витрина стоит: при письме справа налево и у края экрана
219
+ - Внутри Полки работает обычный Tab. Стрелка в сторону Столбца возвращает фокус на Категорию, Escape — тоже,
220
+ и закрывает Полку. Tab за последней ссылкой уходит дальше по странице и закрывает Полку.
221
+ - Пока Полка открыта, она следует за фокусом стрелок и букв, как следует за наведением.
222
+ - Стрелка «к Полке» — та, что смотрит туда, где Полка стоит: при письме справа налево и у края экрана
199
223
  стрелки меняются местами.
200
- - Скринридер слышит навигацию с именем из `aria-label`, Категории — кнопками «развёрнуто / свёрнуто», Витрину
224
+ - Скринридер слышит навигацию с именем из `aria-label`, Категории — кнопками «развёрнуто / свёрнуто», Полку
201
225
  — регионом с именем Категории, колонку — списком с именем заголовка.
202
226
 
203
227
  ## Выпадающий вид
@@ -237,10 +261,10 @@ import { ListIcon } from "@olddevs/ui/icons";
237
261
  - **Открытие.** Щелчок, Enter, Пробел и стрелка вниз на кнопке. Наведение каталог не открывает: он не должен
238
262
  выпрыгивать от случайного движения мыши.
239
263
  - **Фокус.** При открытии фокус встаёт на первую доступную Категорию (если одна из них уже открыта через `value` или
240
- `defaultValue` — на неё), Витрина закрыта до выбора. Дальше Столбец и Витрина работают как во встроенном виде.
264
+ `defaultValue` — на неё), Полка закрыта до выбора. Дальше Столбец и Полка работают как во встроенном виде.
241
265
  - **Закрытие.** Escape на Категории, нажатие вне каталога, повторный щелчок по кнопке, переход по любой ссылке
242
266
  (Категория, заголовок колонки, `MegaMenuLink`, в том числе ссылки роутера) и Tab за последним элементом.
243
- Первый Escape внутри Витрины закрывает только Витрину и возвращает фокус на её Категорию; оверлей закрывает
267
+ Первый Escape внутри Полки закрывает только Полку и возвращает фокус на её Категорию; оверлей закрывает
244
268
  следующий.
245
269
  - **Возврат фокуса.** На кнопку фокус возвращается при Escape и при повторном щелчке. После Tab за последним
246
270
  элементом фокус идёт дальше по странице, за кнопкой; Shift+Tab перед первым элементом возвращает на кнопку. После
@@ -248,10 +272,14 @@ import { ListIcon } from "@olddevs/ui/icons";
248
272
  - **Скринридер.** Кнопка — раскрыватель с `aria-expanded` и `aria-controls`, без `aria-haspopup`: оверлей — не
249
273
  меню и не диалог, а та же навигация с ссылками. Роли `dialog` у оверлея нет.
250
274
  - **Слои.** Оверлей лежит на слое `popover`: выше затемнения открытого `Dialog`, ниже подтверждения. Внутри окна
251
- первый Escape закрывает каталог, следующий — окно. Если фокус в открытой Витрине, самый первый Escape закрывает
275
+ первый Escape закрывает каталог, следующий — окно. Если фокус в открытой Полке, самый первый Escape закрывает
252
276
  только её и возвращает фокус на Категорию.
253
- - **Высота.** Оверлей не выше видимой области от кнопки до края окна. Столбец и Витрина прокручиваются каждый
254
- внутри себя (`overscroll-contain`), а не оверлей целиком: иначе рамка оверлея обрезала бы Витрину, которая
277
+ - **Узкий экран.** Уже 640px оверлей занимает всю ширину окна за вычетом отступов по 8px с краёв, а не сжимается по
278
+ самой длинной подписи: подписи переносятся, длинная не выталкивает каталог за край, и ширина не меняется при
279
+ спуске в Категорию. Спуск, «Назад» и Escape работают внутри оверлея так же, как во встроенном виде: первый
280
+ Escape в Полке возвращает Столбец, следующий закрывает каталог.
281
+ - **Высота.** Оверлей не выше видимой области от кнопки до края окна. Столбец и Полка прокручиваются каждый
282
+ внутри себя (`overscroll-contain`), а не оверлей целиком: иначе рамка оверлея обрезала бы Полку, которая
255
283
  стоит рядом со Столбцом. На iOS высота ограничена `min(24rem, 60dvh)`, как у панели `Menu`.
256
284
  - **Появление.** Плавное, по шкале движения кита; при `prefers-reduced-motion` без анимации.
257
285
  - **Сервер.** На сервере рисуется закрытая кнопка; оверлей монтируется в портале после открытия.
@@ -260,14 +288,16 @@ import { ListIcon } from "@olddevs/ui/icons";
260
288
 
261
289
  - Реализация: `src/components/navigation/MegaMenu.tsx`, Прицел — `src/components/navigation/useMenuAim.ts`.
262
290
  - Тесты: `tests/mega-menu.test.tsx` — роли и `aria-controls`, наведение и монтирование только открытой
263
- Витрины, закрытие с задержкой, roving tabindex, Enter, Escape и стрелки, Tab за последней ссылкой,
264
- Категория-ссылка, выключенная Категория, `current`, `asChild` и `link`, управляемое значение, нажатие вне
265
- каталога, рендер на сервере; `tests/mega-menu-aim.test.tsx` — Прицел на подменённой геометрии и поддельном
291
+ Полки, закрытие с задержкой, roving tabindex, Enter, Escape и стрелки, Tab за последней ссылкой,
292
+ Категория-ссылка, выключенная Категория, `active` и алиас `current`, `asChild` и `link` (у Категории и у
293
+ колонки), фрагменты в колонке, текущий раздел и остановка Tab, поиск по первой букве, Категории в своих
294
+ компонентах, управляемое значение, нажатие вне каталога, рендер на сервере; `tests/mega-menu-aim.test.tsx` — Прицел на подменённой геометрии и поддельном
266
295
  времени, переворот у края; `tests/mega-menu-touch.test.tsx` — касание и перо, подмена `matchMedia`, спуск
267
- вместо Столбца, «Назад» и фокус, Escape, подписи из каталога сообщений, рендер на сервере; браузерный тест `tests-visual/mega-menu.spec.ts` — настоящая мышь наискосок и вниз
268
- по Столбцу.
296
+ вместо Столбца, «Назад» и фокус, Escape, подписи из каталога сообщений, спуск у Категорий в своих
297
+ компонентах, рендер на сервере; браузерный тест `tests-visual/mega-menu.spec.ts` — настоящая мышь наискосок и
298
+ вниз по Столбцу, ширина выпадающего вида на телефоне.
269
299
  - Выпадающий вид: `tests/mega-menu-dropdown.test.tsx` — открытие щелчком и клавишами с фокусом на первой
270
- Категории, все пути закрытия и возврат фокуса, Escape в Витрине, `open` / `defaultOpen` / `onOpenChange`, слой
271
- `popover`, порядок Escape внутри `Dialog`, рендер на сервере.
300
+ Категории, все пути закрытия и возврат фокуса, Escape в Полке, `open` / `defaultOpen` / `onOpenChange`, слой
301
+ `popover`, порядок Escape внутри `Dialog`, спуск на узком экране, рендер на сервере.
272
302
  - История: `src/components/navigation/MegaMenu.stories.tsx` — в том числе `DropdownInTopBar`, мегаменю в шапке; на ширине
273
- телефона — `PhoneColumn` и `PhoneDrillDown`.
303
+ телефона — `PhoneColumn`, `PhoneDrillDown`, `PhoneDropdown` и `PhoneDropdownDrillDown`.
@@ -5,7 +5,7 @@ category: overlays
5
5
  status: stable
6
6
  source: src/components/overlays/Menu.tsx
7
7
  story: src/components/overlays/Menu.stories.tsx
8
- sourceHash: 473c4ffa0e0a
8
+ sourceHash: e6bb9a14d118
9
9
  ---
10
10
 
11
11
  # Menu
@@ -57,8 +57,11 @@ and `className`; `aria-label` is required if the button has no text, and with
57
57
  `iconOnly` it never does. `Menu` accepts the usual `AriaMenuProps`, plus `offset`,
58
58
  the gap between the panel and the button in pixels (default 6), and `placement`,
59
59
  the side where the panel opens (default for the root menu `bottom start`; also
60
- `bottom end`, `top start`, `top end`, `right top` and `left top`; the submenu
61
- default is described below).
60
+ `bottom end`, `top start`, `top end`, `end top`, `start top`, `right top` and
61
+ `left top`; the submenu default is described below). `end top` and `start top`
62
+ open beside the panel at the end or the start of the line, so they swap sides in
63
+ right-to-left writing; `right top` and `left top` don't depend on the writing
64
+ direction.
62
65
 
63
66
  `MenuItem` accepts the `AriaMenuItem` props, `icon`, `shortcut`, `tone`,
64
67
  `disabled` and `className`; pass the action in `onAction`. `MenuSection` accepts
@@ -72,7 +75,8 @@ the right, react-aria flips it to the left. In a right-to-left layout everything
72
75
  mirrored: the submenu opens to the left of its item. On a narrow screen (up to 639px wide)
73
76
  there is no room on either side, so the submenu opens below its item, over the
74
77
  parent menu. An explicit `placement` on the nested `Menu` wins over the default,
75
- phones included. The root menu opens as before, at `bottom start`. The Editor's
78
+ phones included; to pick the side yourself without breaking right-to-left
79
+ writing, use `end top` or `start top`. The root menu opens as before, at `bottom start`. The Editor's
76
80
  submenus follow the same rule.
77
81
 
78
82
  Moving the pointer diagonally toward a submenu neither closes it nor switches to a
@@ -54,8 +54,10 @@ button look props, `icon`, `children`, `disabled`, `aria-label` и `className`;
54
54
  `aria-label` обязателен, если у кнопки нет подписи; с `iconOnly` её нет всегда.
55
55
  `Menu` принимает обычные `AriaMenuProps`, плюс `offset` — отступ панели от кнопки
56
56
  в пикселях (умолчание 6) и `placement` — сторона раскрытия (умолчание корневого
57
- меню `bottom start`; ещё `bottom end`, `top start`, `top end`, `right top`,
58
- `left top`; умолчание подменю — ниже).
57
+ меню `bottom start`; ещё `bottom end`, `top start`, `top end`, `end top`,
58
+ `start top`, `right top`, `left top`; умолчание подменю — ниже). `end top` и
59
+ `start top` — сбоку по концу и по началу строки: при письме справа налево они
60
+ меняются местами. `right top` и `left top` от направления письма не зависят.
59
61
 
60
62
  `MenuItem` принимает props `AriaMenuItem`, `icon`, `shortcut`, `tone`, `disabled`
61
63
  и `className`; действие передавайте в `onAction`. `MenuSection` принимает
@@ -69,7 +71,8 @@ react-aria переворачивает подменю влево. При пис
69
71
  подменю раскрывается слева от пункта. На узком экране (до 639px шириной) места
70
72
  сбоку нет ни справа, ни слева, и подменю встаёт под своим пунктом, поверх
71
73
  родительского меню. Явный `placement` у вложенного `Menu` побеждает умолчание, в
72
- том числе на телефоне. Корневое меню раскрывается как прежде — `bottom start`.
74
+ том числе на телефоне; чтобы задать сторону самому и не сломать письмо справа
75
+ налево, берите `end top` или `start top`. Корневое меню раскрывается как прежде — `bottom start`.
73
76
  То же правило у подменю Редактора.
74
77
 
75
78
  Движение курсора к подменю по диагонали его не закрывает и не переключает на
@@ -1,5 +1,5 @@
1
1
  ---
2
- sourceHash: 5f89459633fb
2
+ sourceHash: fdfa8cd8c38b
3
3
  ---
4
4
 
5
5
  # Setting up `@olddevs/ui`
@@ -132,7 +132,7 @@ peer dependencies are treated as external, and the metric is gzip:
132
132
  | `cn` and `tableStateToParams` | 0.6 kB |
133
133
  | one `Button` | 1.6 kB |
134
134
  | `DataTable` | 9.0 kB |
135
- | the whole kit (`import *`) | 76.4 kB |
135
+ | the whole kit (`import *`) | 77.1 kB |
136
136
  | `RichTextEditor` from `@olddevs/ui/editor`, without the engine, "start" | 70.6 kB |
137
137
  | `RichTextEditor` with the Tiptap engine, "start" (static graph, `basic`) | 295.3 kB |
138
138
  | `RichTextEditor` with the Tiptap engine, "full" (with all lazy chunks, `full`) | 339.1 kB |
@@ -129,7 +129,7 @@ peer-зависимости внешние, метрика gzip:
129
129
  | `cn` и `tableStateToParams` | 0,6 кБ |
130
130
  | одна `Button` | 1,6 кБ |
131
131
  | `DataTable` | 9,0 кБ |
132
- | весь кит целиком (`import *`) | 76,4 кБ |
132
+ | весь кит целиком (`import *`) | 77,1 кБ |
133
133
  | `RichTextEditor` из `@olddevs/ui/editor`, без движка, «старт» | 70,6 кБ |
134
134
  | `RichTextEditor` вместе с движком Tiptap, «старт» (статический граф, `basic`) | 295,3 кБ |
135
135
  | `RichTextEditor` вместе с движком Tiptap, «полный» (со всеми ленивыми чанками, `full`) | 339,1 кБ |
@@ -1,5 +1,5 @@
1
1
  ---
2
- sourceHash: 2524e6589eaa
2
+ sourceHash: eb21f7a757f6
3
3
  ---
4
4
 
5
5
  # Glossary of `@olddevs/ui`
@@ -44,7 +44,7 @@ Prop names are a separate vocabulary:
44
44
  | Term | Meaning | Not to be confused with |
45
45
  | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
46
46
  | **the Reference** | Markdown in the package's `docs/`: component, API and convention pages — the source of truth about the public contract. Ships in the package and is shown on the site as is | The wiki: it retells the Reference for people and is wrong when they disagree. ADRs: they explain why a decision was made |
47
- | **showcase** | The kit's Storybook: stories, snapshots and accessibility checks; published to GitHub Pages | The documentation site: the showcase is a workshop, not text for a reader |
47
+ | **showcase** | The kit's Storybook: stories, snapshots and accessibility checks; published to GitHub Pages | The documentation site: the showcase is a workshop, not text for a reader. The flyout of a mega menu |
48
48
  | **snapshot** | A reference image of a showcase story in `tests-visual/`; taken and compared only locally (ADR-0013) | A screenshot for documentation: it checks nothing |
49
49
  | **gate** | One automatic check that fails the run: the contrast gate (`npm run contrast`), the i18n gate, `format:check` | The release checklist: a gate is one check from its list |
50
50
  | **release checklist** | The full list of checks before a merge and a release — the "Checks" section of `AGENTS.md`. Run locally: CI does not check pushes | A GitHub Actions workflow: it publishes the showcase and the package, but checks nothing |
@@ -108,27 +108,27 @@ The words pages use to describe how a component is operated with a mouse, a fing
108
108
  How a component is named in prose. Do not use the words listed after "Do not write:": readers
109
109
  search for a single word.
110
110
 
111
- | Term | Meaning | Not to be confused with |
112
- | --------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
113
- | **dialog** | `Dialog`: a modal surface with a scrim | A drawer. A browser window, which is simply called a "browser window". Do not write: modal |
114
- | **drawer** | `Drawer`: a modal panel that slides in from an edge | A dialog. Do not write: sheet, slide-out panel |
115
- | **popover** | `Popover`: a non-modal panel next to the button that opened it | A tooltip: it has no interactivity. Do not write: popup |
116
- | **tooltip** | `Tooltip`: short text on hover and focus | A popover |
117
- | **hint** | `hint` on `FormField` and neighboring fields: text under the field that helps to fill it in | A tooltip and a placeholder |
118
- | **placeholder** | `placeholder`: an example value shown in an empty field that disappears on input | A hint and a tooltip |
119
- | **toast** | A global notification `toast()` in `Toaster` | The Editor's Field notice: it is tied to a field |
120
- | **checkbox** | `Checkbox`: a yes/no choice within a set | The `Toggle` switch (`role="switch"`): one boolean property, not a choice within a set |
121
- | **table bar** | The `toolbar` slot of `DataTable`, usually `TableToolbar` | The Editor's Toolbar and the `Toolbar` primitive. Do not write: toolbar |
122
- | **menu trigger** | The button that opens a menu: the right part of `SplitButton`, the `Menu` button | A popover: that is the panel that opened. Do not write: disclosure |
123
- | **segmented control** | `Segmented`: a row of buttons of which exactly one is selected | `Tabs` (they switch panels) and `ToggleGroup` (zero or more selected) |
124
- | **tag** | `Tag` in `TagGroup` and `TagInput`: a compact element with text and an optional remove button | The Editor's Mark and a field label |
125
- | **close button** | The button with an "×" that closes a dialog, drawer, popover or notification; in a search field it is the **clear button** | A "Cancel" button. Do not write: cross |
126
- | **shortcut list** | `ShortcutsHelp`: a dialog with a list of keyboard shortcuts | The Editor's Shortcuts reference: that one opens from the Toolbar and describes the Editor's shortcuts |
127
- | **mega menu** | `MegaMenu`: a category column and the showcase of the hovered category, an Amazon-style catalog | `Menu`: that one is for commands, not navigation. Do not write: mega dropdown |
128
- | **category** | `MegaMenuCategory`: a row of the category column with a label, an icon and its own showcase | A menu item (`MenuItem`) |
129
- | **category column** | The vertical list of categories in a mega menu | `SideNav`: that one expands branches in place |
130
- | **showcase** | The area next to the category column with the open category's content: link columns, promos | The Editor toolbar, a popover |
131
- | **aim** | Deferring the category switch while the pointer cuts diagonally toward the open showcase | An opening delay: aim never slows down a direct hover |
111
+ | Term | Meaning | Not to be confused with |
112
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
113
+ | **dialog** | `Dialog`: a modal surface with a scrim | A drawer. A browser window, which is simply called a "browser window". Do not write: modal |
114
+ | **drawer** | `Drawer`: a modal panel that slides in from an edge | A dialog. Do not write: sheet, slide-out panel |
115
+ | **popover** | `Popover`: a non-modal panel next to the button that opened it | A tooltip: it has no interactivity. Do not write: popup |
116
+ | **tooltip** | `Tooltip`: short text on hover and focus | A popover |
117
+ | **hint** | `hint` on `FormField` and neighboring fields: text under the field that helps to fill it in | A tooltip and a placeholder |
118
+ | **placeholder** | `placeholder`: an example value shown in an empty field that disappears on input | A hint and a tooltip |
119
+ | **toast** | A global notification `toast()` in `Toaster` | The Editor's Field notice: it is tied to a field |
120
+ | **checkbox** | `Checkbox`: a yes/no choice within a set | The `Toggle` switch (`role="switch"`): one boolean property, not a choice within a set |
121
+ | **table bar** | The `toolbar` slot of `DataTable`, usually `TableToolbar` | The Editor's Toolbar and the `Toolbar` primitive. Do not write: toolbar |
122
+ | **menu trigger** | The button that opens a menu: the right part of `SplitButton`, the `Menu` button | A popover: that is the panel that opened. Do not write: disclosure |
123
+ | **segmented control** | `Segmented`: a row of buttons of which exactly one is selected | `Tabs` (they switch panels) and `ToggleGroup` (zero or more selected) |
124
+ | **tag** | `Tag` in `TagGroup` and `TagInput`: a compact element with text and an optional remove button | The Editor's Mark and a field label |
125
+ | **close button** | The button with an "×" that closes a dialog, drawer, popover or notification; in a search field it is the **clear button** | A "Cancel" button. Do not write: cross |
126
+ | **shortcut list** | `ShortcutsHelp`: a dialog with a list of keyboard shortcuts | The Editor's Shortcuts reference: that one opens from the Toolbar and describes the Editor's shortcuts |
127
+ | **mega menu** | `MegaMenu`: a category column and the flyout of the hovered category, an Amazon-style catalog | `Menu`: that one is for commands, not navigation. Do not write: mega dropdown |
128
+ | **category** | `MegaMenuCategory`: a row of the category column with a label, an icon and its own flyout | A menu item (`MenuItem`) |
129
+ | **category column** | The vertical list of categories in a mega menu | `SideNav`: that one expands branches in place |
130
+ | **flyout** | The area next to the category column with the open category's content: link columns, promos. Before 4.3.0 it was called the showcase; the width prop is still `showcaseWidth` | The showcase: that is the kit's Storybook. The Editor toolbar, a popover |
131
+ | **aim** | Deferring the category switch while the pointer cuts diagonally toward the open flyout | An opening delay: aim never slows down a direct hover |
132
132
 
133
133
  ## Editor
134
134
 
package/docs/glossary.md CHANGED
@@ -40,7 +40,7 @@
40
40
  | Термин | Значение | Не путать с |
41
41
  | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
42
42
  | **Справочник** | Markdown в `docs/` пакета: страницы компонентов, API и соглашения — источник правды о публичном контракте. Едет в пакете и показывается на сайте без правок | Вики: та пересказывает для людей и при расхождении неправа. ADR: те объясняют, почему так решено |
43
- | **Витрина** | Storybook кита: истории, снимки и проверки доступности; публикуется на GitHub Pages | Сайтом документации: витрина — мастерская, а не текст для читателя |
43
+ | **Витрина** | Storybook кита: истории, снимки и проверки доступности; публикуется на GitHub Pages | Сайтом документации: витрина — мастерская, а не текст для читателя. Полкой мегаменю |
44
44
  | **Снимок** | Эталонная картинка истории витрины в `tests-visual/`; снимается и сверяется только локально (ADR-0013) | Скриншотом для документации: он ничего не проверяет |
45
45
  | **Гейт** | Одна автоматическая проверка, которая роняет прогон: гейт контраста (`npm run contrast`), гейт i18n, `format:check` | Воротами: гейт — одна проверка из их списка |
46
46
  | **Ворота** | Полный список проверок перед слиянием и релизом — раздел «Checks» в `AGENTS.md`. Запускаются локально: CI пуши не проверяет | Воркфлоу GitHub Actions: те публикуют витрину и пакет, но не проверяет |
@@ -104,27 +104,27 @@
104
104
  Как компонент называется по-русски в прозе. Слова после «Не пишем:» в тексте не употребляются: читатель
105
105
  ищет по одному слову.
106
106
 
107
- | Термин | Значение | Не путать с |
108
- | -------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
109
- | **Окно** | `Dialog`: модальная поверхность с затемнением | Ящиком. Окном браузера — его так и называем: «окно браузера». Не пишем: модалка |
110
- | **Ящик** | `Drawer`: модальная панель, которая выезжает от края | Окном. Не пишем: шторка, выдвижная панель |
111
- | **Поповер** | `Popover`: немодальная панель у кнопки, которая её открыла | Подсказкой: в той нет интерактива. Не пишем: попап |
112
- | **Подсказка** | `Tooltip`: короткий текст при наведении и фокусе | Поповером. Не пишем: тултип |
113
- | **Пояснение** | `hint` у `FormField` и соседних полей: текст под полем, который помогает его заполнить | Подсказкой (`Tooltip`) и плейсхолдером. Не пишем: подсказка поля |
114
- | **Плейсхолдер** | `placeholder`: пример значения, который виден в пустом поле и исчезает при вводе | Пояснением и подсказкой. Не пишем: подсказка в поле |
115
- | **Тост** | Глобальное уведомление `toast()` в `Toaster` | Сообщением поля Редактора: то привязано к полю |
116
- | **Флажок** | `Checkbox`: выбор «да / нет» в наборе | Переключателем `Toggle` (`role="switch"`): одно булево свойство, а не выбор в наборе. Не пишем: чекбокс |
117
- | **Полоса над таблицей** | Слот `toolbar` у `DataTable`, обычно `TableToolbar` | Панелью Редактора и примитивом `Toolbar`. Не пишем: тулбар |
118
- | **Раскрыватель** | Кнопка, которая раскрывает меню: правая часть `SplitButton`, кнопка `Menu` | Поповером: тот — сама раскрывшаяся панель. Не пишем: disclosure, стрелка-меню |
119
- | **Сегментированный выбор** | `Segmented`: ряд кнопок, из которых выбрана ровно одна | Вкладками `Tabs` (те переключают панели) и `ToggleGroup` (там выбрано ноль или несколько) |
120
- | **Тег** | `Tag` в `TagGroup` и `TagInput`: компактный элемент с текстом и необязательной кнопкой удаления | Меткой Редактора (`Mark`) и подписью поля. Не пишем: таг |
121
- | **Кнопка закрытия** | Кнопка с иконкой «×», которая закрывает окно, ящик, поповер или уведомление; у поля поиска — **кнопка очистки** | Кнопкой «Отмена». Не пишем: крестик |
122
- | **Свод сочетаний** | `ShortcutsHelp`: окно со списком сочетаний клавиш | Справочником Редактора: тот открывается из Панели и описывает сочетания Редактора |
123
- | **Мегаменю** | `MegaMenu`: Столбец категорий и Витрина наведённой Категории — каталог в духе Amazon | `Menu`: тот для команд, а не для навигации. Не пишем: мега-дропдаун |
124
- | **Категория** | `MegaMenuCategory`: строка Столбца с подписью, иконкой и своей Витриной | Пунктом меню (`MenuItem`) |
125
- | **Столбец категорий** | Вертикальный список Категорий Мегаменю | `SideNav`: тот раскрывает ветки на месте |
126
- | **Витрина** | Область рядом со Столбцом с содержимым открытой Категории: колонки ссылок, промо | Панелью Редактора и поповером |
127
- | **Прицел** | Отложенная смена Категории, пока курсор идёт наискосок к открытой Витрине | Задержкой открытия: прямое наведение Прицел не тормозит |
107
+ | Термин | Значение | Не путать с |
108
+ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
109
+ | **Окно** | `Dialog`: модальная поверхность с затемнением | Ящиком. Окном браузера — его так и называем: «окно браузера». Не пишем: модалка |
110
+ | **Ящик** | `Drawer`: модальная панель, которая выезжает от края | Окном. Не пишем: шторка, выдвижная панель |
111
+ | **Поповер** | `Popover`: немодальная панель у кнопки, которая её открыла | Подсказкой: в той нет интерактива. Не пишем: попап |
112
+ | **Подсказка** | `Tooltip`: короткий текст при наведении и фокусе | Поповером. Не пишем: тултип |
113
+ | **Пояснение** | `hint` у `FormField` и соседних полей: текст под полем, который помогает его заполнить | Подсказкой (`Tooltip`) и плейсхолдером. Не пишем: подсказка поля |
114
+ | **Плейсхолдер** | `placeholder`: пример значения, который виден в пустом поле и исчезает при вводе | Пояснением и подсказкой. Не пишем: подсказка в поле |
115
+ | **Тост** | Глобальное уведомление `toast()` в `Toaster` | Сообщением поля Редактора: то привязано к полю |
116
+ | **Флажок** | `Checkbox`: выбор «да / нет» в наборе | Переключателем `Toggle` (`role="switch"`): одно булево свойство, а не выбор в наборе. Не пишем: чекбокс |
117
+ | **Полоса над таблицей** | Слот `toolbar` у `DataTable`, обычно `TableToolbar` | Панелью Редактора и примитивом `Toolbar`. Не пишем: тулбар |
118
+ | **Раскрыватель** | Кнопка, которая раскрывает меню: правая часть `SplitButton`, кнопка `Menu` | Поповером: тот — сама раскрывшаяся панель. Не пишем: disclosure, стрелка-меню |
119
+ | **Сегментированный выбор** | `Segmented`: ряд кнопок, из которых выбрана ровно одна | Вкладками `Tabs` (те переключают панели) и `ToggleGroup` (там выбрано ноль или несколько) |
120
+ | **Тег** | `Tag` в `TagGroup` и `TagInput`: компактный элемент с текстом и необязательной кнопкой удаления | Меткой Редактора (`Mark`) и подписью поля. Не пишем: таг |
121
+ | **Кнопка закрытия** | Кнопка с иконкой «×», которая закрывает окно, ящик, поповер или уведомление; у поля поиска — **кнопка очистки** | Кнопкой «Отмена». Не пишем: крестик |
122
+ | **Свод сочетаний** | `ShortcutsHelp`: окно со списком сочетаний клавиш | Справочником Редактора: тот открывается из Панели и описывает сочетания Редактора |
123
+ | **Мегаменю** | `MegaMenu`: Столбец категорий и Полка наведённой Категории — каталог в духе Amazon | `Menu`: тот для команд, а не для навигации. Не пишем: мега-дропдаун |
124
+ | **Категория** | `MegaMenuCategory`: строка Столбца с подписью, иконкой и своей Полкой | Пунктом меню (`MenuItem`) |
125
+ | **Столбец категорий** | Вертикальный список Категорий Мегаменю | `SideNav`: тот раскрывает ветки на месте |
126
+ | **Полка** | Область рядом со Столбцом с содержимым открытой Категории: колонки ссылок, промо. До 4.3.0 — «Витрина»; проп ширины по-прежнему `showcaseWidth` | Витриной — это Storybook кита; Панелью Редактора и поповером |
127
+ | **Прицел** | Отложенная смена Категории, пока курсор идёт наискосок к открытой Полке | Задержкой открытия: прямое наведение Прицел не тормозит |
128
128
 
129
129
  ## Редактор
130
130
 
package/llms.txt CHANGED
@@ -108,7 +108,7 @@
108
108
  - [Breadcrumbs](docs/components/navigation/breadcrumbs.md): `Breadcrumbs` показывает путь до текущей страницы.
109
109
  - [Pagination](docs/components/navigation/pagination.md): `Pagination` — controlled pagination для уже разбитой на страницы коллекции.
110
110
  - [Stepper](docs/components/navigation/stepper.md): `Stepper` показывает порядок шагов мастера; текущий индекс задаёт родитель (controlled).
111
- - [MegaMenu](docs/components/navigation/mega-menu.md): `MegaMenu` — каталог магазина в духе Amazon: слева Столбец категорий, справа от наведённой Категории — её Витрина с колонками ссылок и любым своим содержимым.
111
+ - [MegaMenu](docs/components/navigation/mega-menu.md): `MegaMenu` — каталог магазина в духе Amazon: слева Столбец категорий, справа от наведённой Категории — её Полка с колонками ссылок и любым своим содержимым.
112
112
  - [TreeView](docs/components/navigation/tree-view.md): Иерархия с раскрытием, выбором и клавиатурой на `Tree` из react-aria.
113
113
  - [SelectionBar и useStickyOffset](docs/components/navigation/selection-bar.md): `SelectionBar` — полоса массовых действий: «Выбрано 12» и что с этим можно сделать.
114
114
  - [ContextualSaveBar](docs/components/navigation/contextual-save-bar.md): Полоса несохранённых изменений: появляется с первой правкой формы, показывает «есть несохранённые изменения» (или их число) и две кнопки — сохранить и отменить.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olddevs/ui",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "Olddevs UI — design system: tokens, themes and accessible UI primitives",
5
5
  "license": "MIT",
6
6
  "private": false,