| 1 | # ADR 0070: Command Palette как прямой overlay surface, маршрутизируемый в активный TopLevel |
| 2 | |
| 3 | **Статус:** Accepted · Implemented |
| 4 | **Дата:** 2026-04-19 |
| 5 | |
| 6 | ## Связанные ADR |
| 7 | |
| 8 | | ADR | Роль | |
| 9 | |-----|------| |
| 10 | | [0013](0013-command-surface-and-discoverability.md) | палитра и discoverability | |
| 11 | | [0017](0017-multi-window-workspace-and-agent-surfaces.md) | несколько `TopLevel` и фокус | |
| 12 | | [0021](0021-pfd-mfd-cockpit-attention-model.md) | модель внимания | |
| 13 | | [0060](0060-keyboard-chord-stack-fms-tactical-strategic.md) | keyboard-first и overlay-подсказки | |
| 14 | | [0066](0066-cockpit-ui-vs-ide-presentation-layer.md) | shell chrome vs cockpit UI | |
| 15 | |
| 16 | ## Резюме |
| 17 | |
| 18 | - Command Palette — **прямой overlay** в host, не `ModalOverlay` baseline. |
| 19 | - Маршрутизация в активный `TopLevel`; связь с [0112](0112-command-palette-query-modes-strategy.md). |
| 20 | |
| 21 | |
| 22 | --- |
| 23 | ## Контекст |
| 24 | |
| 25 | Командная палитра уже была канонической surface в [0013](0013-command-surface-and-discoverability.md), но её конкретный render-host оставался незафиксированным. Практика показала, что композиция через общий `ModalOverlay` оказалась хрупкой для multi-window topology: |
| 26 | |
| 27 | 1. overlay мог не материализоваться в нужном `TopLevel`, хотя хоткей и состояние VM уже сработали; |
| 28 | 2. при мультиоконности палитра могла визуально появляться не в том хосте или дублироваться; |
| 29 | 3. keyboard-first UX ломался именно в критическом месте discoverability: у пользователя создавалось ощущение, что `Ctrl+Q` ничего не делает. |
| 30 | |
| 31 | Проблема оказалась не в самой палитре как продуктовой идее, а в фундаменте surface: общий модальный compose-path был слишком неявным для keyboard-first overlay, который обязан быть привязан к активному окну и фокусу. |
| 32 | |
| 33 | --- |
| 34 | |
| 35 | ## Решение |
| 36 | |
| 37 | <a id="adr0070-p1"></a> |
| 38 | |
| 39 | ### 1. Базовый surface палитры |
| 40 | |
| 41 | Command Palette рендерится как **прямой overlay surface** внутри конкретного host view, а не как обязательная композиция через общий `ModalOverlay`. |
| 42 | |
| 43 | Это означает: |
| 44 | |
| 45 | - корневой визуал палитры сам содержит dimmer/panel; |
| 46 | - палитра сама управляет видимостью, фокусом и keyboard routing; |
| 47 | - `ModalOverlay` остаётся общей UI-инфраструктурой, но больше **не считается каноническим фундаментом** для палитры. |
| 48 | |
| 49 | <a id="adr0070-p2"></a> |
| 50 | |
| 51 | ### 2. Маршрутизация в активный TopLevel |
| 52 | |
| 53 | При открытии палитра должна быть видима **ровно в одном активном host window**: |
| 54 | |
| 55 | - `MainWindow` |
| 56 | - `PfdHostWindow` |
| 57 | - `MfdHostWindow` |
| 58 | |
| 59 | Источник истины для выбора host — состояние shell/VM, отражающее активный `TopLevel` и источник последнего keyboard entry. Overlay не должен “угадывать” по глобальному статическому состоянию вне текущего окна. |
| 60 | |
| 61 | <a id="adr0070-p3"></a> |
| 62 | |
| 63 | ### 3. Keyboard-first инварианты |
| 64 | |
| 65 | Для палитры обязательны следующие инварианты: |
| 66 | |
| 67 | - открытие по хоткею должно работать из дочерних контролов и редактора; |
| 68 | - при открытии фокус переходит в строку поиска; |
| 69 | - при закрытии фокус возвращается в предыдущий элемент текущего host; |
| 70 | - `Esc`, `Enter`, `Up/Down`, `PageUp/PageDown` обрабатываются на уровне самой палитры; |
| 71 | - overlay не должен зависеть от того, есть ли в конкретной раскладке дополнительные chrome/composition wrappers. |
| 72 | |
| 73 | <a id="adr0070-p4"></a> |
| 74 | |
| 75 | ### 4. Граница решения |
| 76 | |
| 77 | Этот ADR фиксирует только baseline surface для **Command Palette**. |
| 78 | |
| 79 | Он **не** означает, что: |
| 80 | |
| 81 | - любой modal/dimmer в IDE должен быть переписан под ту же схему; |
| 82 | - `ModalOverlay` запрещён; |
| 83 | - overlay-подсказки chord-системы из [0060](0060-keyboard-chord-stack-fms-tactical-strategic.md) обязаны использовать тот же visual tree. |
| 84 | |
| 85 | Но для палитры правило по умолчанию теперь однозначно: **прямой overlay в нужном host**. |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## Последствия |
| 90 | |
| 91 | - Поведение палитры становится предсказуемым в multi-window topology. |
| 92 | - Тесты должны страховать не только hotkey routing, но и host routing: палитра видна только в ожидаемом `TopLevel`. |
| 93 | - Документация по keyboard-first теперь может опираться на конкретный baseline, а не на “историческую” реализацию через `ModalOverlay`. |
| 94 | |
| 95 | --- |
| 96 | |
| 97 | ## Отклонённые альтернативы |
| 98 | |
| 99 | 1. **Оставить `ModalOverlay` каноном и чинить частные баги вокруг него.** |
| 100 | Отклонено: причина поломки не локальная, а архитектурная для multi-window keyboard-first surface. |
| 101 | |
| 102 | 2. **Глобальный singleton-overlay поверх всех окон.** |
| 103 | Отклонено: нарушает модель фокуса и внимания из [0017](0017-multi-window-workspace-and-agent-surfaces.md) и [0021](0021-pfd-mfd-cockpit-attention-model.md). |
| 104 | |
| 105 | 3. **Привязывать палитру только к `MainWindow`, а host-окна заставлять проксировать ввод назад.** |
| 106 | Отклонено: пользователь ожидает, что discoverability surface появится именно там, где сейчас работает. |
| 107 | |