@olddevs/ui 4.2.2 → 4.4.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.
- package/CHANGELOG.md +39 -0
- package/dist/components/navigation/MegaMenu.d.ts +43 -23
- package/dist/components/navigation/MegaMenu.d.ts.map +1 -1
- package/dist/components/navigation/MegaMenu.js +110 -47
- package/dist/components/navigation/MegaMenu.js.map +1 -1
- package/dist/components/navigation/useMenuAim.d.ts +8 -8
- package/dist/components/navigation/useMenuAim.d.ts.map +1 -1
- package/dist/components/overlays/Menu.d.ts +4 -2
- package/dist/components/overlays/Menu.d.ts.map +1 -1
- package/dist/components/overlays/Menu.js.map +1 -1
- package/dist/editor/RichTextEditor.d.ts.map +1 -1
- package/dist/editor/RichTextEditor.js +38 -4
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/editor/core/handle.d.ts +1 -5
- package/dist/editor/core/handle.d.ts.map +1 -1
- package/dist/editor/core/handle.js +1 -13
- package/dist/editor/core/handle.js.map +1 -1
- package/dist/editor/core/handleWatchers.d.ts +6 -0
- package/dist/editor/core/handleWatchers.d.ts.map +1 -0
- package/dist/editor/core/handleWatchers.js +14 -0
- package/dist/editor/core/handleWatchers.js.map +1 -0
- package/dist/editor/core/tools.d.ts +7 -2
- package/dist/editor/core/tools.d.ts.map +1 -1
- package/dist/editor/core/tools.js +2 -1
- package/dist/editor/core/tools.js.map +1 -1
- package/dist/editor/features/toc/RichTextToc.d.ts +63 -0
- package/dist/editor/features/toc/RichTextToc.d.ts.map +1 -0
- package/dist/editor/features/toc/RichTextToc.js +372 -0
- package/dist/editor/features/toc/RichTextToc.js.map +1 -0
- package/dist/editor/features/toc/headings.d.ts +31 -0
- package/dist/editor/features/toc/headings.d.ts.map +1 -0
- package/dist/editor/features/toc/headings.js +25 -0
- package/dist/editor/features/toc/headings.js.map +1 -0
- package/dist/editor/features/toc/stickyOffset.d.ts +3 -0
- package/dist/editor/features/toc/stickyOffset.d.ts.map +1 -0
- package/dist/editor/features/toc/stickyOffset.js +14 -0
- package/dist/editor/features/toc/stickyOffset.js.map +1 -0
- package/dist/editor/index.d.ts +2 -0
- package/dist/editor/index.d.ts.map +1 -1
- package/dist/editor/index.js +1 -0
- package/dist/editor/index.js.map +1 -1
- package/dist/i18n/defaults.d.ts.map +1 -1
- package/dist/i18n/defaults.js +1 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/messages.d.ts +5 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/locales/ru.d.ts.map +1 -1
- package/dist/locales/ru.js +1 -0
- package/dist/locales/ru.js.map +1 -1
- package/docs/api/messages.en.md +743 -0
- package/docs/api/messages.md +1 -0
- package/docs/api/utilities.en.md +233 -0
- package/docs/components/content/rich-text-toc.en.md +130 -0
- package/docs/components/content/rich-text-toc.md +129 -0
- package/docs/components/index.en.md +3 -2
- package/docs/components/index.md +2 -1
- package/docs/components/inputs/rich-text-editor.en.md +52 -34
- package/docs/components/inputs/rich-text-editor.md +20 -2
- package/docs/components/navigation/mega-menu.en.md +86 -61
- package/docs/components/navigation/mega-menu.md +81 -56
- package/docs/components/overlays/menu.en.md +8 -4
- package/docs/components/overlays/menu.md +6 -3
- package/docs/conventions.en.md +318 -0
- package/docs/getting-started.en.md +5 -5
- package/docs/getting-started.md +4 -4
- package/docs/glossary.en.md +24 -23
- package/docs/glossary.md +23 -22
- package/docs/index.en.md +53 -0
- package/llms.txt +2 -1
- package/package.json +1 -1
- package/src/components/navigation/MegaMenu.tsx +300 -140
- package/src/components/navigation/useMenuAim.ts +19 -19
- package/src/components/overlays/Menu.tsx +12 -2
- package/src/editor/RichTextEditor.tsx +107 -3
- package/src/editor/core/handle.ts +2 -23
- package/src/editor/core/handleWatchers.ts +27 -0
- package/src/editor/core/tools.ts +9 -2
- package/src/editor/features/toc/RichTextToc.tsx +712 -0
- package/src/editor/features/toc/headings.ts +70 -0
- package/src/editor/features/toc/stickyOffset.ts +21 -0
- package/src/editor/index.ts +2 -0
- package/src/i18n/defaults.ts +1 -0
- package/src/i18n/messages.ts +5 -0
- package/src/locales/ru.ts +1 -0
|
@@ -37,7 +37,7 @@ category: inputs
|
|
|
37
37
|
status: stable
|
|
38
38
|
source: src/editor/RichTextEditor.tsx
|
|
39
39
|
story: src/editor/RichTextEditor.stories.tsx
|
|
40
|
-
sourceHash:
|
|
40
|
+
sourceHash: 3eaf71d10511
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
# RichTextEditor
|
|
@@ -305,43 +305,44 @@ The `link` Tool: the "Link" button on the Toolbar and `Ctrl/⌘+K` open a popove
|
|
|
305
305
|
|
|
306
306
|
## Tools and Presets
|
|
307
307
|
|
|
308
|
-
`preset="full"` (default) is everything in the release. `preset="basic"` is for comments and short descriptions. `tools` is an exact list and takes precedence over a Preset; descriptions of custom Tools can be mixed in with the kit's names (see the "Custom Tool" section). The type of a `tools` element is `Tool` (a kit name or a `CustomTool`), the type of a kit name is `ToolName`; both are exported from `@olddevs/ui/editor`.
|
|
308
|
+
`preset="full"` (default) is everything in the release except the Table of contents `toc`: it changes the layout of the field, so it is switched on only explicitly. `preset="basic"` is for comments and short descriptions. `tools` is an exact list and takes precedence over a Preset; descriptions of custom Tools can be mixed in with the kit's names (see the "Custom Tool" section). The type of a `tools` element is `Tool` (a kit name or a `CustomTool`), the type of a kit name is `ToolName`; both are exported from `@olddevs/ui/editor`.
|
|
309
309
|
|
|
310
310
|
Presets are also exported as arrays of names — `RICH_TEXT_PRESETS.full` and `RICH_TEXT_PRESETS.basic` — so that you can assemble your own set from them: `tools={[...RICH_TEXT_PRESETS.full, mergeTagTool]}`. The arrays are frozen. A Preset's content is "what the kit considers the full set", not a frozen list: a new built-in Tool arrives in a Preset in a minor version. If you need a stable set, pass an exact list of names.
|
|
311
311
|
|
|
312
312
|
**A disabled Tool removes both the button and the Schema extension.** Its Block or Mark cannot be created with a keyboard shortcut, a Markdown shortcut or a paste, and from `value` they arrive without Block markup, and the text stays.
|
|
313
313
|
|
|
314
|
-
| `Tool` | Button
|
|
315
|
-
| ----------------- |
|
|
316
|
-
| `heading` | "¶": Heading 2–4
|
|
317
|
-
| `heading1` | "¶": adds Heading 1
|
|
318
|
-
| `history` | Undo, Redo
|
|
319
|
-
| `bold` | Bold
|
|
320
|
-
| `italic` | Italic
|
|
321
|
-
| `underline` | "…": Underline
|
|
322
|
-
| `strike` | Strikethrough
|
|
323
|
-
| `code` | "…": Inline code
|
|
324
|
-
| `superscript` | "…": Superscript
|
|
325
|
-
| `subscript` | "…": Subscript
|
|
326
|
-
| `clearFormatting` | "…": Clear formatting
|
|
327
|
-
| `link` | Link (address popover)
|
|
328
|
-
| `color` | Color ▾ (Selection menu): "Text color"
|
|
329
|
-
| `highlight` | Highlight ▾ (Toolbar), "Color ▾"
|
|
330
|
-
| `align` | Alignment ▾ (menu)
|
|
331
|
-
| `bulletList` | Lists ▾: Bulleted list
|
|
332
|
-
| `orderedList` | Lists ▾: Numbered list
|
|
333
|
-
| `taskList` | Lists ▾: Checklist
|
|
334
|
-
| `blockquote` | "…": Quote
|
|
335
|
-
| `codeBlock` | "…": Code block
|
|
336
|
-
| `horizontalRule` | "+": Divider
|
|
337
|
-
| `table` | Table ▾ (menu)
|
|
338
|
-
| `image` | Image (address popover)
|
|
339
|
-
| `emoji` | Emoji (popover with a grid)
|
|
340
|
-
| `source` | HTML (mode toggle)
|
|
341
|
-
| `search` | Find (find and replace panel)
|
|
342
|
-
| `layout` | "+": Layout
|
|
343
|
-
| `wrapper` | "+": Wrapper
|
|
344
|
-
| `insertMenu` | "+" Insert menu
|
|
314
|
+
| `Tool` | Button | Markup | Shortcut | Markdown while typing | `basic` |
|
|
315
|
+
| ----------------- | ---------------------------------------------------- | ----------------------------------------- | ------------------------------------------------- | ---------------------- | ------- |
|
|
316
|
+
| `heading` | "¶": Heading 2–4 | `h2`, `h3`, `h4` | `Ctrl/⌘+Alt+2…4` | `## `, `### `, `#### ` | — |
|
|
317
|
+
| `heading1` | "¶": adds Heading 1 | `h1` | `Ctrl/⌘+Alt+1` | `# ` | — |
|
|
318
|
+
| `history` | Undo, Redo | — | `Ctrl/⌘+Z`, `+Shift+Z` | — | yes |
|
|
319
|
+
| `bold` | Bold | `strong` | `Ctrl/⌘+B` | `**text**` | yes |
|
|
320
|
+
| `italic` | Italic | `em` | `Ctrl/⌘+I` | `*text*` | yes |
|
|
321
|
+
| `underline` | "…": Underline | `u` | `Ctrl/⌘+U` | — | — |
|
|
322
|
+
| `strike` | Strikethrough | `s` | `Ctrl/⌘+Shift+S` | `~~text~~` | yes |
|
|
323
|
+
| `code` | "…": Inline code | `code` | `Ctrl/⌘+E` | `` `text` `` | yes |
|
|
324
|
+
| `superscript` | "…": Superscript | `sup` | `Ctrl/⌘+.` | — | — |
|
|
325
|
+
| `subscript` | "…": Subscript | `sub` | `Ctrl/⌘+,` | — | — |
|
|
326
|
+
| `clearFormatting` | "…": Clear formatting | — (removes Marks) | `Ctrl/⌘+\` | — | — |
|
|
327
|
+
| `link` | Link (address popover) | `a[href]` | `Ctrl/⌘+K` | `[text](url)` on paste | yes |
|
|
328
|
+
| `color` | Color ▾ (Selection menu): "Text color" | `span[data-color]`, `span[style]` | — | — | — |
|
|
329
|
+
| `highlight` | Highlight ▾ (Toolbar), "Color ▾" | `mark[data-color]`, `mark[style]` | — | — | — |
|
|
330
|
+
| `align` | Alignment ▾ (menu) | `p`, `h2`–`h4` with `data-align` | `Ctrl/⌘+Shift+L`, `+E`, `+R` | — | — |
|
|
331
|
+
| `bulletList` | Lists ▾: Bulleted list | `ul`, `li` | `Ctrl/⌘+Shift+8` | `- ` or `* ` | yes |
|
|
332
|
+
| `orderedList` | Lists ▾: Numbered list | `ol`, `li` | `Ctrl/⌘+Shift+7` | `1. ` | yes |
|
|
333
|
+
| `taskList` | Lists ▾: Checklist | `ul[data-type=taskList]` and items | `Ctrl/⌘+Shift+9` | `[ ] ` or `[x] ` | — |
|
|
334
|
+
| `blockquote` | "…": Quote | `blockquote` | `Ctrl/⌘+Shift+B` | `> ` | yes |
|
|
335
|
+
| `codeBlock` | "…": Code block | `pre`, `code class="language-*"` | `Ctrl/⌘+Alt+C` | ` ``` ` | — |
|
|
336
|
+
| `horizontalRule` | "+": Divider | `hr` | — | `---` | — |
|
|
337
|
+
| `table` | Table ▾ (menu) | `table`, `tbody`, `tr`, `th`, `td` | `Tab`, `Shift+Tab`, `Alt+↓` in a table | — | — |
|
|
338
|
+
| `image` | Image (address popover) | `figure`, `img`, `figcaption` | — | `` on paste | — |
|
|
339
|
+
| `emoji` | Emoji (popover with a grid) | — (plain text) | — | — | — |
|
|
340
|
+
| `source` | HTML (mode toggle) | — (edits the Document's HTML) | — | — | — |
|
|
341
|
+
| `search` | Find (find and replace panel) | — (searches the Document) | `Ctrl/⌘+F`, `Ctrl/⌘+Alt+F` | — | yes |
|
|
342
|
+
| `layout` | "+": Layout | `div` with `data-block` and `data-layout` | `Tab`, `Shift+Tab`, arrow keys at the column edge | — | — |
|
|
343
|
+
| `wrapper` | "+": Wrapper | `div[data-block=wrapper]` | `Enter` in an empty last paragraph — exit | — | — |
|
|
344
|
+
| `insertMenu` | "+" Insert menu | — (Blocks of other Tools) | — | `/` | — |
|
|
345
|
+
| `toc` | Table of contents in the left gutter (not in `full`) | — (reads the headings) | — | — | — |
|
|
345
346
|
|
|
346
347
|
A paragraph is always there; a soft line break is `Shift+Enter`. `insertMenu` and `emoji`, like `clearFormatting`, have no markup of their own: `insertMenu` provides access to other Tools' Blocks, and it is disabled where `/` is an ordinary character (paths, "and/or"); `basic` lacks it for the same reason. `emoji` inserts plain text — the Schema, the sanitizer and Markdown do not change because of it (see the "Emoji" section); `basic` lacks it: in a comment the OS's own palette is easier to reach, and a button would take up room in a short row. `source` is the HTML mode (see the "HTML mode" section): it has no markup of its own either, an HTML edit goes through the same Schema as `value`, and it cannot be used to get around the set of Tools; `basic` lacks it — in a comment an "HTML" button is superfluous unless the screen explicitly asks for it.
|
|
347
348
|
|
|
@@ -349,7 +350,7 @@ A paragraph is always there; a soft line break is `Shift+Enter`. `insertMenu` an
|
|
|
349
350
|
|
|
350
351
|
Earlier, "no H1 in the Document" was a kit decision (the page heading sits outside the Editor); now it is the screen's decision — ADR-0053 revises the earlier decision, and ADR-0050 links to ADR-0053.
|
|
351
352
|
|
|
352
|
-
A name enters the `Tool` type together with the Tool itself, not earlier: widening the input type does not break the consumer, whereas a name without an implementation would compile and do nothing. That is how `link` arrived — straight into the `basic` Preset too — and `color`, `highlight`, `align`, `table`, `image`, `emoji`, `layout`, `wrapper`, `source`; there are no reserved names now. Unknown names in `tools` (from JS without types) are dropped silently.
|
|
353
|
+
A name enters the `Tool` type together with the Tool itself, not earlier: widening the input type does not break the consumer, whereas a name without an implementation would compile and do nothing. That is how `link` arrived — straight into the `basic` Preset too — and `color`, `highlight`, `align`, `table`, `image`, `emoji`, `layout`, `wrapper`, `source`, `toc`; there are no reserved names now. Unknown names in `tools` (from JS without types) are dropped silently.
|
|
353
354
|
|
|
354
355
|
`preset` and `tools` are read **when the engine is created**: the Schema of a live ProseMirror cannot be changed. To change the set on a mounted field, remount it with a key (`key`) — the edit history is lost in the process.
|
|
355
356
|
|
|
@@ -1170,6 +1171,23 @@ The `search` Tool (present in `full` and in `basic`) is find and replace over th
|
|
|
1170
1171
|
|
|
1171
1172
|
Message catalog strings: `editor.search` (the button and the `Ctrl/⌘+F` Shortcuts reference row), `searchReplace` (`Ctrl/⌘+Alt+F`), `searchPanel`, `searchField`, `replaceField`, `searchPrevious`, `searchNext`, `searchClose`, `searchMatchCase`, `searchWholeWord`, `searchRegex`, `replaceOne`, `replaceAll`, `searchCount({ current, total })`, `searchNoMatches`, `searchInvalid`.
|
|
1172
1173
|
|
|
1174
|
+
## Table of contents
|
|
1175
|
+
|
|
1176
|
+
The `toc` Tool puts the Table of contents of the Document in the Editor's left gutter: the same strip of strokes and the same list as [`RichTextToc`](../content/rich-text-toc.md), but the Editor holds the place itself (ADR-0068). It is in neither Preset, `full` or `basic`: the Table of contents moves the text, and a kit update does not change the layout of screens that did not ask for it. Switch it on by name:
|
|
1177
|
+
|
|
1178
|
+
```tsx
|
|
1179
|
+
<RichTextEditor tools={[...RICH_TEXT_PRESETS.full, "toc"]} defaultValue={html} />
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
- **Place.** A column to the left of the Document, inside the field frame. It exists only while there is a strip, from two `h1`–`h4` headings at the top level and in Wrappers: with the second heading the text moves right; without it the text stays at the edge, as without the Tool. The first stroke is level with the first line of the first heading.
|
|
1183
|
+
- **Stickiness.** The strip sticks under the fixed Toolbar (and under the app header: `--topbar-h`, ADR-0016); without a Toolbar, to the edge of the window. In a field with `maxHeight` or `resizable` it sticks to the top of the scrolling area, and the highlight and the jump count from there; the page does not scroll.
|
|
1184
|
+
- **The list** works as in `RichTextToc`: hover opens it to the right of the strip, Enter and Space open it from the keyboard, arrows move between items, Escape closes it; the current section is highlighted in the strip and in the list; the width is 240px, and a long heading is cut with an ellipsis. A click on an item does not close the list: moving the pointer away does.
|
|
1185
|
+
- **A jump while editing** puts the caret at the end of the heading, so you can type right away, as in the document outline of Google Docs; the Table of contents does the scrolling, and the heading flashes a fading background. In `readOnly` there is no caret, so focus goes to the heading itself.
|
|
1186
|
+
- **A live Document.** The list is rebuilt shortly after each edit: a new, renamed or removed heading shows in the strip. In HTML mode there is no Table of contents, because the Document is hidden.
|
|
1187
|
+
- **No Toolbar button.** To show or hide the Table of contents, the screen changes `tools` (and remounts the field with a `key`, as for any set of Tools).
|
|
1188
|
+
|
|
1189
|
+
Message catalog string: `editor.toc` ("Table of contents"), the name of the strip and the label of the list.
|
|
1190
|
+
|
|
1173
1191
|
## Status line and Field notice
|
|
1174
1192
|
|
|
1175
1193
|
Under the field inside the frame there are two independent areas. The **Status line** is what the screen puts there itself: "Saved", a word count, a co-author. The **Field notice** is what the kit and Tools report: an upload result, a paste rejection. The first is a React node in the `status` prop, the second is data and an engine command.
|
|
@@ -304,7 +304,7 @@ import { RichTextEditor } from "@olddevs/ui/editor";
|
|
|
304
304
|
|
|
305
305
|
## Инструменты и Пресеты
|
|
306
306
|
|
|
307
|
-
`preset="full"` (по умолчанию) — всё, что есть в
|
|
307
|
+
`preset="full"` (по умолчанию) — всё, что есть в выпуске, кроме Оглавления `toc`: оно меняет раскладку поля, и его включают только явно. `preset="basic"` — для комментариев и коротких описаний. `tools` — точный список, сильнее Пресета; в нём вперемешку с именами кита стоят описания своих Инструментов (раздел «Свой Инструмент»). Тип элемента `tools` — `Tool` (имя кита или `CustomTool`), тип имени кита — `ToolName`; оба экспортируются из `@olddevs/ui/editor`.
|
|
308
308
|
|
|
309
309
|
Пресеты экспортируются и массивами имён — `RICH_TEXT_PRESETS.full` и `RICH_TEXT_PRESETS.basic`, чтобы собирать из них свой набор: `tools={[...RICH_TEXT_PRESETS.full, mergeTagTool]}`. Массивы заморожены. Состав Пресета — «то, что кит считает полным набором», а не замороженный список: новый встроенный Инструмент приходит в Пресет minor-версией. Нужен стабильный состав — передайте точный список имён.
|
|
310
310
|
|
|
@@ -341,6 +341,7 @@ import { RichTextEditor } from "@olddevs/ui/editor";
|
|
|
341
341
|
| `layout` | «+»: Раскладка | `div` с `data-block` и `data-layout` | `Tab`, `Shift+Tab`, стрелки у края колонки | — | — |
|
|
342
342
|
| `wrapper` | «+»: Обёртка | `div[data-block=wrapper]` | `Enter` в пустом последнем абзаце — выход | — | — |
|
|
343
343
|
| `insertMenu` | «+» Меню вставки | — (Блоки других Инструментов) | — | `/` | — |
|
|
344
|
+
| `toc` | Оглавление в левом поле (не в `full`) | — (читает заголовки) | — | — | — |
|
|
344
345
|
|
|
345
346
|
Абзац есть всегда, мягкий перенос строки — `Shift+Enter`. `insertMenu` и `emoji`, как и `clearFormatting`, своей разметки не имеют: `insertMenu` даёт доступ к Блокам других Инструментов, а выключают его там, где `/` — обычный символ (пути, «и/или»); в `basic` его нет по той же причине. `emoji` вставляет обычный текст — Схема, санитайзер и Markdown от него не меняются (раздел «Эмодзи»); в `basic` его нет: в комментарии системная палитра ОС удобнее, а кнопка занимала бы место у короткого ряда. `source` — HTML-режим (раздел «HTML-режим»): своей разметки у него тоже нет, правка HTML проходит ту же Схему, что `value`, и обойти набор Инструментов им нельзя; в `basic` его нет — в комментарии кнопка «HTML» лишняя, если экран её не просил.
|
|
346
347
|
|
|
@@ -348,7 +349,7 @@ import { RichTextEditor } from "@olddevs/ui/editor";
|
|
|
348
349
|
|
|
349
350
|
Раньше «H1 в Документе нет» было решением кита (заголовок страницы стоит вне Редактора); теперь это решение экрана — ADR-0053 пересматривает прежнее решение; ссылка на ADR-0053 стоит в ADR-0050.
|
|
350
351
|
|
|
351
|
-
Имя приходит в тип `Tool` вместе с самим Инструментом, не раньше: расширение входного типа потребителя не ломает, а имя без реализации компилировалось бы и ничего не давало. Так пришли `link` — сразу и в Пресет `basic` — и `color`, `highlight`, `align`, `table`, `image`, `emoji`, `layout`, `wrapper`, `source`; зарезервированных имён сейчас нет. Неизвестные имена в `tools` (из JS без типов) отбрасываются молча.
|
|
352
|
+
Имя приходит в тип `Tool` вместе с самим Инструментом, не раньше: расширение входного типа потребителя не ломает, а имя без реализации компилировалось бы и ничего не давало. Так пришли `link` — сразу и в Пресет `basic` — и `color`, `highlight`, `align`, `table`, `image`, `emoji`, `layout`, `wrapper`, `source`, `toc`; зарезервированных имён сейчас нет. Неизвестные имена в `tools` (из JS без типов) отбрасываются молча.
|
|
352
353
|
|
|
353
354
|
`preset` и `tools` читаются **при создании движка**: Схему живого ProseMirror не поменять. Чтобы сменить набор у смонтированного поля, перемонтируйте его ключом (`key`) — история правок при этом теряется.
|
|
354
355
|
|
|
@@ -1169,6 +1170,23 @@ ARIA сетки — шаблон `grid` из APG: `role="grid"` → `row` → `g
|
|
|
1169
1170
|
|
|
1170
1171
|
Строки каталога сообщений: `editor.search` (кнопка и строка Справочника сочетаний `Ctrl/⌘+F`), `searchReplace` (`Ctrl/⌘+Alt+F`), `searchPanel`, `searchField`, `replaceField`, `searchPrevious`, `searchNext`, `searchClose`, `searchMatchCase`, `searchWholeWord`, `searchRegex`, `replaceOne`, `replaceAll`, `searchCount({ current, total })`, `searchNoMatches`, `searchInvalid`.
|
|
1171
1172
|
|
|
1173
|
+
## Оглавление
|
|
1174
|
+
|
|
1175
|
+
Инструмент `toc` — Оглавление Документа в левом поле Редактора: та же полоса штрихов и тот же список, что у [`RichTextToc`](../content/rich-text-toc.md), но место держит сам Редактор (ADR-0068). В Пресеты он не входит — ни в `full`, ни в `basic`: Оглавление сдвигает текст, и обновление кита не меняет раскладку экранов, которые его не просили. Включают его именем:
|
|
1176
|
+
|
|
1177
|
+
```tsx
|
|
1178
|
+
<RichTextEditor tools={[...RICH_TEXT_PRESETS.full, "toc"]} defaultValue={html} />
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
- **Место.** Колонка слева от Документа внутри рамки поля. Она есть, только пока есть полоса — от двух заголовков `h1`–`h4` на верхнем уровне и в Обёртке: со вторым заголовком текст сдвигается вправо, без него стоит у края, как без Инструмента. Первый штрих стоит на уровне первой строки первого заголовка.
|
|
1182
|
+
- **Липкость.** Полоса липнет под фиксированной Панелью (и под шапкой приложения: `--topbar-h`, ADR-0016), без Панели — к краю окна. В поле с `maxHeight` или `resizable` она липнет к верху прокручиваемой области, а подсветка и переход считают от неё — страница при этом не прокручивается.
|
|
1183
|
+
- **Список** — как у `RichTextToc`: наведение раскрывает его справа от полосы, Enter и Space — с клавиатуры, стрелки ходят по пунктам, Escape закрывает; текущий раздел подсвечен в полосе и в списке; ширина 240px, длинный заголовок обрезан многоточием. Клик по пункту список не закрывает: его закрывает уход курсора.
|
|
1184
|
+
- **Переход в правке** ставит каретку в конец заголовка — можно сразу писать, как в структуре документа Google Docs; прокрутку делает Оглавление, заголовок подсвечивается гаснущим фоном. В `readOnly` каретки нет — фокус встаёт на сам заголовок.
|
|
1185
|
+
- **Живой Документ.** Список пересобирается на правке с короткой задержкой: новый заголовок, переименование и удаление видны в полосе. В HTML-режиме Оглавления нет — Документ скрыт.
|
|
1186
|
+
- **Кнопки на Панели нет.** Показать или спрятать Оглавление — смена `tools` экраном (с перемонтажом ключом, как у любого набора Инструментов).
|
|
1187
|
+
|
|
1188
|
+
Строка каталога сообщений — `editor.toc` («Оглавление»): имя полосы и подпись списка.
|
|
1189
|
+
|
|
1172
1190
|
## Строка статуса и Сообщение поля
|
|
1173
1191
|
|
|
1174
1192
|
Под полем внутри рамки две независимые области. **Строка статуса** — то, что экран кладёт сам: «Сохранено», число слов, соавтор. **Сообщение поля** — то, что сообщают кит и Инструменты: результат загрузки, отказ вставки. Первое — React-узел пропа `status`, второе — данные и команда движка.
|
|
@@ -5,7 +5,7 @@ category: navigation
|
|
|
5
5
|
status: stable
|
|
6
6
|
source: src/components/navigation/MegaMenu.tsx
|
|
7
7
|
story: src/components/navigation/MegaMenu.stories.tsx
|
|
8
|
-
sourceHash:
|
|
8
|
+
sourceHash: 42179963266b
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# MegaMenu
|
|
@@ -13,10 +13,11 @@ sourceHash: 4c7401326a3f
|
|
|
13
13
|
## Summary for AI
|
|
14
14
|
|
|
15
15
|
`MegaMenu` is an Amazon-style store catalog: a category column on the left and, next to the hovered
|
|
16
|
-
category, its
|
|
16
|
+
category, its flyout with columns of links and any content of your own. It is link navigation, not a command
|
|
17
17
|
menu: the markup follows the WAI-ARIA Disclosure Navigation pattern (`nav`, buttons with `aria-expanded`, real
|
|
18
|
-
`a` elements). Categories are `MegaMenuCategory`
|
|
19
|
-
|
|
18
|
+
`a` elements). Categories are `MegaMenuCategory` (directly or inside your own components, server components
|
|
19
|
+
included), columns are `MegaMenuGroup`, links are `MegaMenuLink`. The current section and the current page are
|
|
20
|
+
marked with the `active` prop, as on `NavItem`. The same catalog opens as a dropdown overlay from a button: `MegaMenuTrigger` with
|
|
20
21
|
`MegaMenuButton` and an unchanged `MegaMenu`.
|
|
21
22
|
|
|
22
23
|
## When to use
|
|
@@ -24,7 +25,7 @@ menu: the markup follows the WAI-ARIA Disclosure Navigation pattern (`nav`, butt
|
|
|
24
25
|
- A catalog with ten or more sections, each with subsections in columns: a store, a marketplace, a help portal.
|
|
25
26
|
- The sections should be visible at once and the subsections should appear on hover, without taking the user
|
|
26
27
|
off the page.
|
|
27
|
-
- The
|
|
28
|
+
- The flyout needs content of its own next to the links: a promo card, an image, a selection.
|
|
28
29
|
|
|
29
30
|
## When not to use
|
|
30
31
|
|
|
@@ -39,10 +40,10 @@ menu: the markup follows the WAI-ARIA Disclosure Navigation pattern (`nav`, butt
|
|
|
39
40
|
import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddevs/ui";
|
|
40
41
|
|
|
41
42
|
<MegaMenu aria-label="Catalog">
|
|
42
|
-
<MegaMenuCategory id="computers" label="Computers" href="/computers">
|
|
43
|
+
<MegaMenuCategory id="computers" label="Computers" href="/computers" active>
|
|
43
44
|
<MegaMenuGroup title="Laptops" href="/computers/laptops">
|
|
44
45
|
<MegaMenuLink href="/computers/laptops/gaming">Gaming</MegaMenuLink>
|
|
45
|
-
<MegaMenuLink href="/computers/laptops/ultrabooks"
|
|
46
|
+
<MegaMenuLink href="/computers/laptops/ultrabooks" active>
|
|
46
47
|
Ultrabooks
|
|
47
48
|
</MegaMenuLink>
|
|
48
49
|
</MegaMenuGroup>
|
|
@@ -59,67 +60,80 @@ import { MegaMenu, MegaMenuCategory, MegaMenuGroup, MegaMenuLink } from "@olddev
|
|
|
59
60
|
| ------------------------------------------ | --------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
60
61
|
| `aria-label` | — | The accessible name of the navigation. Required: on a page with several `nav` elements, the name tells them apart |
|
|
61
62
|
| `value` / `defaultValue` / `onValueChange` | `null` | The open category (its `id`) or `null`, controlled or uncontrolled |
|
|
62
|
-
| `showcaseWidth` | `"40rem"` | The width of the
|
|
63
|
+
| `showcaseWidth` | `"40rem"` | The width of the flyout, shared by all categories so that the catalog does not jump between them |
|
|
63
64
|
| `className` | — | Classes for the `nav`; the default width of the category column is `w-64` |
|
|
64
65
|
|
|
65
66
|
`MegaMenuCategory`: `id` is the key for `value`; `label` is the text in the category column and the name of the
|
|
66
|
-
|
|
67
|
-
the
|
|
67
|
+
flyout; `icon`; `href` or `link` is the address of the whole section; `disabled`; `active` means the current page is in
|
|
68
|
+
this section; the children are the content of the flyout. For a category with a flyout, the address becomes a title link at the top of the flyout; for a
|
|
68
69
|
category without children, the row in the category column is itself the link. `link` is a router link passed as an
|
|
69
70
|
empty element (`link={<Link href="/x" />}`), and the label moves inside it. It is a separate prop rather than
|
|
70
|
-
`asChild` because the children of a category are its
|
|
71
|
+
`asChild` because the children of a category are its flyout.
|
|
71
72
|
|
|
72
|
-
`
|
|
73
|
-
|
|
73
|
+
`active` on a category sets `aria-current="true"` and gives the label the accent color, the same one a current
|
|
74
|
+
link gets. The mark stays whether or not the flyout is open: the route decides the current section, not hover. The
|
|
75
|
+
open category is still marked with a background, so one row can carry both. While no flyout is open, Tab enters the
|
|
76
|
+
category column on the current section. Your code decides which section is current, as with `active` on `NavItem`.
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
Categories don't have to be direct children of `MegaMenu`: you can split them across your own components and render
|
|
79
|
+
them from a Next.js server component. Each category reports itself to the column, and the column doesn't inspect its
|
|
80
|
+
children by type, because a server component's element arrives on the client with a different type. Before
|
|
81
|
+
hydration, while the categories haven't reported themselves yet, every available category is a Tab stop; after
|
|
82
|
+
hydration the column is a single stop again.
|
|
83
|
+
|
|
84
|
+
`MegaMenuGroup`: `title` is the title of the column and the name of its list; `href` or `link` turns the title into
|
|
85
|
+
a link (`link` is a router link passed as an empty element, as on a category); the children are `MegaMenuLink`
|
|
86
|
+
elements, and each one is placed in its own list item, including those passed in a fragment.
|
|
87
|
+
|
|
88
|
+
`MegaMenuLink`: the usual `a` props, `icon`, `active` and `asChild`. `active` sets `aria-current="page"` and the
|
|
76
89
|
look of the current link. The kit does not work out the current page itself, because every router compares
|
|
77
90
|
addresses by its own rules. `asChild` renders the link as a router element:
|
|
78
|
-
`<MegaMenuLink asChild><Link href="/x">Label</Link></MegaMenuLink>`.
|
|
91
|
+
`<MegaMenuLink asChild><Link href="/x">Label</Link></MegaMenuLink>`. The old name, `current`, works until 5.0 and is
|
|
92
|
+
marked `@deprecated`: the kit calls the current navigation item `active`.
|
|
79
93
|
|
|
80
|
-
## Hover and the
|
|
94
|
+
## Hover and the flyout
|
|
81
95
|
|
|
82
|
-
Hovering a category with the mouse opens its
|
|
83
|
-
the one whose
|
|
84
|
-
|
|
96
|
+
Hovering a category with the mouse opens its flyout at once, with no delay. Exactly one category is highlighted,
|
|
97
|
+
the one whose flyout is open: the highlight follows `aria-expanded`, not `:hover`. Hovering a category without a
|
|
98
|
+
flyout closes the open one, with the same caveat about aim as below.
|
|
85
99
|
|
|
86
|
-
The
|
|
100
|
+
The flyout closes 150 ms after the pointer has left both the category column and the flyout, so a brief
|
|
87
101
|
excursion past the edge does not reset the catalog. It also closes on a pointer press outside the catalog and when
|
|
88
102
|
focus leaves the catalog.
|
|
89
103
|
|
|
90
|
-
The content of a
|
|
104
|
+
The content of a flyout is mounted only for the open category, so a catalog of a hundred links and images does
|
|
91
105
|
not load everything at once. The region itself is always there, hidden: the button's `aria-controls` points to it.
|
|
92
106
|
|
|
93
|
-
The
|
|
94
|
-
links, then on down the page", and why the
|
|
107
|
+
The flyout is a DOM descendant of its category, not a portal. That is why the Tab order runs "category, its
|
|
108
|
+
links, then on down the page", and why the flyout sits flush against the category column without any position
|
|
95
109
|
calculation. An ancestor with `overflow: hidden` clips it, so put the catalog where there is room beside it.
|
|
96
110
|
|
|
97
|
-
The
|
|
111
|
+
The flyout sits on the end side of the line: on the right, or on the left in right-to-left writing. If there is
|
|
98
112
|
not enough room there and there is enough on the other side, it moves to the other side. The kit measures the side
|
|
99
|
-
ahead of time and again when the window is resized, so the arrow key that points "toward the
|
|
100
|
-
points to where the
|
|
113
|
+
ahead of time and again when the window is resized, so the arrow key that points "toward the flyout" already
|
|
114
|
+
points to where the flyout will appear.
|
|
101
115
|
|
|
102
116
|
## Touch and narrow screens
|
|
103
117
|
|
|
104
118
|
Touch has no hover, so the touch itself (`click`) opens a category, without aim. A pointer whose `pointerType` is
|
|
105
|
-
"touch" or "pen" neither opens a category on hover nor closes the
|
|
106
|
-
finger. Touching an open category again neither closes it nor goes anywhere. The
|
|
119
|
+
"touch" or "pen" neither opens a category on hover nor closes the flyout when it leaves: a pen behaves like a
|
|
120
|
+
finger. Touching an open category again neither closes it nor goes anywhere. The flyout closes on a touch outside
|
|
107
121
|
the catalog or on Escape.
|
|
108
122
|
|
|
109
123
|
The mouse behaves as before: hover, aim and closing after 150 ms all remain while the screen is wide.
|
|
110
124
|
|
|
111
125
|
On a narrow screen, under 640px (the same breakpoint as `Menu` submenus and Editor submenus), there is no room beside
|
|
112
|
-
the category column for the
|
|
126
|
+
the category column for the flyout: the edge of the window would cut it off on the right. So the catalog works as a
|
|
113
127
|
drill-down:
|
|
114
128
|
|
|
115
129
|
- The category column takes the full width, and category labels wrap instead of being truncated.
|
|
116
|
-
- An open category (by touch, click, Enter or Space) replaces the category column with its
|
|
130
|
+
- An open category (by touch, click, Enter or Space) replaces the category column with its flyout. The flyout
|
|
117
131
|
starts with a "Back" row that shows the category name. If the category has a link of its own, the link shows the
|
|
118
132
|
name, on the row below, instead of the "Back" row. Below that, the columns of links follow, one under another.
|
|
119
|
-
- "Back" returns the category column and puts focus on the category the person came from. Escape inside the
|
|
133
|
+
- "Back" returns the category column and puts focus on the category the person came from. Escape inside the flyout
|
|
120
134
|
works like "Back".
|
|
121
135
|
- When you drill down, focus moves to "Back": the category button is hidden along with the category column, and focus
|
|
122
|
-
left on it would be lost. In the
|
|
136
|
+
left on it would be lost. In the flyout on a narrow screen, the arrow key toward the category column does
|
|
123
137
|
nothing, because the column is not beside it.
|
|
124
138
|
- There is no aim on a narrow screen: hovering with the mouse does not open a category, and moving the mouse away does
|
|
125
139
|
not cancel the drill-down. Replacing the column under the cursor would pull it out from under the person's hand.
|
|
@@ -133,25 +147,25 @@ catalog supplies "Назад".
|
|
|
133
147
|
The kit reads the width through `matchMedia`, not through CSS, because the width determines the contents of the
|
|
134
148
|
markup (the category column is hidden), not just the look. Before hydration and on the server, the hook reports a wide
|
|
135
149
|
screen (ADR-0018): the server does not know the width, and the markup it produces is always the regular one. On a phone,
|
|
136
|
-
after hydration, a
|
|
150
|
+
after hydration, a flyout opened by `defaultValue` is re-rendered once as a drill-down. On a phone the `nav` takes
|
|
137
151
|
the full width through the `max-sm:w-full` class; a `w-*` class from `className` applies on a wide screen.
|
|
138
152
|
|
|
139
153
|
## Aim
|
|
140
154
|
|
|
141
|
-
On its way from a category to its
|
|
142
|
-
categories. If hover opened them at once, the
|
|
143
|
-
out of reach. Aim watches where the pointer is heading: while it moves toward the open
|
|
155
|
+
On its way from a category to its flyout, the pointer cuts diagonally and brushes against the neighboring
|
|
156
|
+
categories. If hover opened them at once, the flyout would change under the person's hand, and the links would be
|
|
157
|
+
out of reach. Aim watches where the pointer is heading: while it moves toward the open flyout, a neighboring
|
|
144
158
|
category does not take over the hover.
|
|
145
159
|
|
|
146
160
|
- The direction of the pointer's last step is compared with the wedge from its previous position to the two corners
|
|
147
|
-
of the
|
|
161
|
+
of the flyout's near edge: Kamens's triangle from "Where it comes from". A step into the wedge means the pointer
|
|
148
162
|
is aiming.
|
|
149
163
|
- One movement off course is forgiven; two in a row are not, and then the category under the pointer opens.
|
|
150
164
|
- If the pointer stops for 300 ms, the category under it opens even if it was aiming. The menu does not get stuck.
|
|
151
|
-
- When the pointer reaches the
|
|
165
|
+
- When the pointer reaches the flyout, the deferred switch is canceled.
|
|
152
166
|
- Clicking a category opens it at once, bypassing aim. The keyboard knows nothing about aim.
|
|
153
167
|
- Mouse only, and only on a wide screen: touch and pen open a category at once, and a narrow screen has no aim at all.
|
|
154
|
-
- The first hover, while there is no
|
|
168
|
+
- The first hover, while there is no flyout yet, opens the category with no delay at all: there is nothing to aim at.
|
|
155
169
|
|
|
156
170
|
The model is the same as for react-aria submenus (`Menu` with `SubmenuTrigger`), so that the two menus of the kit
|
|
157
171
|
behave alike. There are two differences. The category switch is deferred, not suppressed with `pointer-events: none`
|
|
@@ -208,16 +222,21 @@ Primary sources:
|
|
|
208
222
|
## Keyboard and names
|
|
209
223
|
|
|
210
224
|
- The category column is a single Tab stop. The Up and Down arrows, Home and End move through the categories;
|
|
211
|
-
disabled ones are skipped. When the user comes back with Tab, they land on the category they were on
|
|
212
|
-
|
|
225
|
+
disabled ones are skipped. When the user comes back with Tab, they land on the category they were on; the first
|
|
226
|
+
time, on the open one, otherwise on the current section (`active`), otherwise on the first one.
|
|
227
|
+
- Typing a letter on a category moves focus to the next category whose label starts with it, wrapping around; the
|
|
228
|
+
same letter again moves to the one after. Letters typed in quick succession match the start of a label, and a
|
|
229
|
+
half-second pause clears them. A Space in the middle of typing is part of the label ("Home and garden"), not a
|
|
230
|
+
key that opens the category. A letter with Ctrl, Cmd or Alt is a keyboard shortcut, and the catalog leaves it alone.
|
|
231
|
+
- Enter, Space and the arrow toward the flyout open it and put focus on the first link. On a category that is a
|
|
213
232
|
link, Enter follows it.
|
|
214
|
-
- Inside the
|
|
215
|
-
does Escape, which also closes the
|
|
216
|
-
- While the
|
|
217
|
-
- The arrow "toward the
|
|
233
|
+
- Inside the flyout, plain Tab works. The arrow toward the category column returns focus to the category, and so
|
|
234
|
+
does Escape, which also closes the flyout. Tab past the last link moves on down the page and closes the flyout.
|
|
235
|
+
- While the flyout is open, it follows focus moved by arrows and letters the way it follows hover.
|
|
236
|
+
- The arrow "toward the flyout" is the one that points to where the flyout sits: in right-to-left writing and at
|
|
218
237
|
the edge of the screen, the arrows swap places.
|
|
219
238
|
- A screen reader hears a navigation with the name from `aria-label`, the categories as expand/collapse buttons, the
|
|
220
|
-
|
|
239
|
+
flyout as a region named after the category, and a column as a list named after its title.
|
|
221
240
|
|
|
222
241
|
## Dropdown mode
|
|
223
242
|
|
|
@@ -257,11 +276,11 @@ into one. `MegaMenuButton` accepts the kit's button look (`variant`, `tone`, `si
|
|
|
257
276
|
- **Opening.** Click, Enter, Space and the Down arrow on the button. Hover does not open the catalog: it should not
|
|
258
277
|
jump out at a stray mouse movement.
|
|
259
278
|
- **Focus.** On opening, focus goes to the first available category (or, if one is already open through `value` or
|
|
260
|
-
`defaultValue`, to that one), and the
|
|
261
|
-
and the
|
|
279
|
+
`defaultValue`, to that one), and the flyout stays closed until a category is chosen. After that the category column
|
|
280
|
+
and the flyout work as in the embedded mode.
|
|
262
281
|
- **Closing.** Escape on a category, a press outside the catalog, a second click on the button, following any link (a
|
|
263
282
|
category, a column title, a `MegaMenuLink`, router links included) and Tab past the last element.
|
|
264
|
-
The first Escape inside a
|
|
283
|
+
The first Escape inside a flyout closes only the flyout and returns focus to its category; the next one closes
|
|
265
284
|
the overlay.
|
|
266
285
|
- **Returning focus.** Focus returns to the button on Escape and on a second click. After Tab past the last element,
|
|
267
286
|
focus moves on down the page, past the button; Shift+Tab before the first element returns it to the button. After a
|
|
@@ -270,10 +289,14 @@ into one. `MegaMenuButton` accepts the kit's button look (`variant`, `tone`, `si
|
|
|
270
289
|
overlay is neither a menu nor a dialog, but the same navigation with links. The overlay has no `dialog` role.
|
|
271
290
|
- **Layers.** The overlay sits on the `popover` layer: above the scrim of an open `Dialog`, below the confirmation.
|
|
272
291
|
Inside a dialog, the first Escape closes the catalog and the next one closes the dialog. If focus is in an open
|
|
273
|
-
|
|
292
|
+
flyout, the very first Escape closes only the flyout and returns focus to its category.
|
|
293
|
+
- **Narrow screens.** Under 640px the overlay spans the window, minus 8px at each edge, instead of shrinking to the
|
|
294
|
+
longest label: labels wrap, a long one can't push the catalog off screen, and the width stays put when you drill
|
|
295
|
+
into a category. The drill-down, "Back" and Escape work inside the overlay just as in the embedded mode: the first
|
|
296
|
+
Escape in a flyout brings the column back, the next one closes the catalog.
|
|
274
297
|
- **Height.** The overlay is no taller than the visible area from the button to the edge of the window. The category
|
|
275
|
-
column and the
|
|
276
|
-
overlay's frame would clip the
|
|
298
|
+
column and the flyout each scroll within themselves (`overscroll-contain`), not the overlay as a whole: otherwise the
|
|
299
|
+
overlay's frame would clip the flyout, which stands beside the category column. On iOS the height is capped at
|
|
277
300
|
`min(24rem, 60dvh)`, like the `Menu` panel.
|
|
278
301
|
- **Appearance.** Smooth, on the kit's motion scale; with `prefers-reduced-motion`, no animation.
|
|
279
302
|
- **Server.** The server renders a closed button; the overlay is mounted in a portal after opening.
|
|
@@ -282,15 +305,17 @@ into one. `MegaMenuButton` accepts the kit's button look (`variant`, `tone`, `si
|
|
|
282
305
|
|
|
283
306
|
- Implementation: `src/components/navigation/MegaMenu.tsx`; aim is in `src/components/navigation/useMenuAim.ts`.
|
|
284
307
|
- Tests: `tests/mega-menu.test.tsx` covers roles and `aria-controls`, hover and mounting only the open
|
|
285
|
-
|
|
286
|
-
a category that is a link, a disabled category, `current
|
|
287
|
-
|
|
308
|
+
flyout, closing with a delay, roving tabindex, Enter, Escape and the arrows, Tab past the last link,
|
|
309
|
+
a category that is a link, a disabled category, `active` and the `current` alias, `asChild` and `link` (on a
|
|
310
|
+
category and on a column), fragments in a column, the current section and the Tab stop, typeahead, categories
|
|
311
|
+
inside your own components, the controlled value, a press outside the catalog and server rendering; `tests/mega-menu-aim.test.tsx` covers aim on mocked geometry and fake
|
|
288
312
|
time, and the flip at the edge; `tests/mega-menu-touch.test.tsx` covers touch and pen, a mocked `matchMedia`,
|
|
289
|
-
the drill-down in place of the category column, "Back" and focus, Escape, labels from the message catalog
|
|
290
|
-
|
|
291
|
-
the category column
|
|
313
|
+
the drill-down in place of the category column, "Back" and focus, Escape, labels from the message catalog, the
|
|
314
|
+
drill-down with categories inside your own components and server rendering; the browser test
|
|
315
|
+
`tests-visual/mega-menu.spec.ts` uses a real mouse moving diagonally and down the category column, and checks the
|
|
316
|
+
width of the dropdown on a phone.
|
|
292
317
|
- Dropdown mode: `tests/mega-menu-dropdown.test.tsx` covers opening by click and keys with focus on the first
|
|
293
|
-
category, every way of closing and returning focus, Escape in the
|
|
294
|
-
`popover` layer, the order of Escape inside a `Dialog
|
|
318
|
+
category, every way of closing and returning focus, Escape in the flyout, `open` / `defaultOpen` / `onOpenChange`, the
|
|
319
|
+
`popover` layer, the order of Escape inside a `Dialog`, the drill-down on a narrow screen and server rendering.
|
|
295
320
|
- Story: `src/components/navigation/MegaMenu.stories.tsx`, including `DropdownInTopBar`, a mega menu in a top bar; at phone
|
|
296
|
-
width, `PhoneColumn` and `
|
|
321
|
+
width, `PhoneColumn`, `PhoneDrillDown`, `PhoneDropdown` and `PhoneDropdownDrillDown`.
|