# Окна, dropdown и слои

## Зачем отдельный контракт

В NODE.DC повторяется одна механика: пользователь нажимает trigger, открывается окно или floating surface, взаимодействует и закрывает его. Если каждое приложение реализует outside click, Escape, portal и z-index отдельно, одинаковые окна начинают вести себя по-разному.

## Layer scale

- base: `0`;
- panel: `100`;
- header: `400`;
- overlay/window: `800`;
- dropdown/popover: `900`;
- toast: `950`.

Произвольные значения вроде `30030` допускаются только во временном legacy adapter. Новый код использует scale.

## Dropdown/popover

Обязательное поведение:

1. trigger сообщает `aria-expanded`;
2. surface переносится в body;
3. координаты рассчитываются как fixed;
4. горизонтальная позиция ограничивается viewport;
5. при недостатке места surface меняет bottom/top placement;
6. scroll/resize пересчитывают позицию;
7. outside pointer и Escape закрывают surface;
8. после Escape фокус возвращается на trigger;
9. открытие другого dropdown закрывает предыдущий.

Inline absolute dropdown внутри card/sidebar/sticky container является дефектом.

## Modal window

Обязательное поведение:

1. window рендерится в body;
2. при открытии запоминается текущий focus;
3. focus переносится на первый интерактивный элемент или dialog;
4. Tab не выходит за пределы dialog;
5. Escape закрывает окно, если операция не блокирует закрытие;
6. backdrop закрывает окно только при клике именно на backdrop;
7. body scroll блокируется;
8. после закрытия focus возвращается на предыдущий trigger.

## Карта modal-паттернов

| Тип | Источник | Каноническая реализация |
| --- | --- | --- |
| Form/create/save | Launcher, CMS, BIM | `Window` + Field/Select + footer actions |
| Destructive confirmation | Launcher, Engine, BIM | `ConfirmationModal` |
| Workflow access sharing | новый Engine | `ShareAccessModal` |
| Resource link sharing | BIM Viewer | `ShareLinkModal` / `createShareLinkController` |
| Context actions | BIM measurement/object | `Window size="sm"` + application-owned actions |
| Expandable detail | BIM comment workspace | `Window` или `ApplicationPanel`, domain content остаётся в BIM |
| Large data/history | BIM version history | `Window size="lg"`, data table остаётся domain composition |

Новый тип появляется только если отличается поведением слоя или имеет устойчивую независимую anatomy. Разная таблица, форма или текст внутри Window не создают новую modal-систему.

## Side window / inspector

Side window использует ту же механику, но placement `end` и ограниченную ширину. Это канон для:

- настроек окружения;
- инспектора агентной ноды;
- будущих detail/settings panels;
- CMS/SEO side editors, если они не требуют отдельного полноэкранного workflow.

По умолчанию это modeless-слой: он не затемняет страницу, не перехватывает клики по основной области, не закрывается по backdrop, не блокирует body scroll и не удерживает Tab внутри панели. Escape и кнопка закрытия остаются доступны. Если конкретный workflow должен быть modal, это задаётся явно, а не получается случайно из placement.

## Workspace window

`WorkspaceWindow` отличается от modal и side inspector границей слоя: это inline modeless-окно, ограниченное конкретной рабочей сценой приложения.

Обязательное поведение:

1. окно рендерится внутри bounds-контейнера без portal;
2. приложение контролирует rectangle, maximized-state, visibility, active-state и z-order;
3. drag доступен за header мышью, touch/pen pointer и стрелками клавиатуры;
4. resize выполняется нижней правой ручкой pointer-ом или стрелками клавиатуры;
5. move и resize всегда ограничены текущими размерами workspace;
6. `ResizeObserver` повторно ограничивает rectangle после изменения layout;
7. maximize заполняет только workspace, а restore возвращает сохранённый приложением rectangle;
8. close сообщает intent приложению и не создаёт внутренний store;
9. родительский bounds-контейнер использует `position: relative` и `overflow: hidden`.

Workspace window используется для вспомогательных камер, инструментов и сопоставляемых представлений внутри stage. Оно не заменяет modal `Window`, viewport-level Inspector или `ApplicationPanel`.

## Управление состоянием

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

Stack workspace-окон остаётся контролируемым приложением: оно передаёт active-state и `zIndex`, а компонент отвечает только за одинаковую геометрию и взаимодействие. Глобальный stack viewport-level modeless-окон остаётся отдельным будущим контрактом.
