АРХ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: регламент стандартизации dropdown-окон
This commit is contained in:
parent
6337b6e4ac
commit
7252d26f46
|
|
@ -98,6 +98,7 @@
|
||||||
|
|
||||||
## Dropdown и popup
|
## Dropdown и popup
|
||||||
- Все dropdown/popup приводятся к единому matte glass канону.
|
- Все dropdown/popup приводятся к единому matte glass канону.
|
||||||
|
- Подробный архитектурный и поведенческий регламент dropdown-окон вынесен в [HDROPDOWN-CANON.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/HDROPDOWN-CANON.md).
|
||||||
- Запрещены:
|
- Запрещены:
|
||||||
- квадратные active-box вокруг круглых кнопок
|
- квадратные active-box вокруг круглых кнопок
|
||||||
- жёсткие border-outline
|
- жёсткие border-outline
|
||||||
|
|
@ -167,6 +168,8 @@
|
||||||
- `.nodedc-external-card`
|
- `.nodedc-external-card`
|
||||||
- `.nodedc-external-section`
|
- `.nodedc-external-section`
|
||||||
- `.nodedc-external-content-shell`
|
- `.nodedc-external-content-shell`
|
||||||
|
- Intake filter chips:
|
||||||
|
- `.nodedc-filter-chip`
|
||||||
|
|
||||||
### Anchor snippets
|
### Anchor snippets
|
||||||
```tsx
|
```tsx
|
||||||
|
|
@ -243,6 +246,24 @@
|
||||||
- global sidebar quick action `Новый рабочий элемент` не показывается на маршруте `external-contours`, потому что этот экран уже имеет собственный primary CTA в header
|
- global sidebar quick action `Новый рабочий элемент` не показывается на маршруте `external-contours`, потому что этот экран уже имеет собственный primary CTA в header
|
||||||
- active/passive карточки `Внешних контуров` обязаны брать фон только из `--nodedc-card-active-rgb` и `--nodedc-card-passive-rgb`
|
- active/passive карточки `Внешних контуров` обязаны брать фон только из `--nodedc-card-active-rgb` и `--nodedc-card-passive-rgb`
|
||||||
- header `Внешних контуров` и detail-pane опускаются на единый верхний ритм; нельзя прижимать breadcrumbs, CTA и detail-header к верхней кромке
|
- header `Внешних контуров` и detail-pane опускаются на единый верхний ритм; нельзя прижимать breadcrumbs, CTA и detail-header к верхней кромке
|
||||||
|
- Для `Предложений / Intake` это значит:
|
||||||
|
- правая detail-pane не растягивается на всю свободную ширину экрана; она использует тот же `IssueView` side-peek shell и тот же persisted width, что и `Внутренний контур`
|
||||||
|
- top-toolbar `Предложений` не верстается отдельной локальной шапкой; используется тот же peek header, что и у `Внутреннего контура`, а intake-специфичные actions добавляются только как slot
|
||||||
|
- `Открытые / Закрытые` не живут отдельными tab-кнопками внутри левой колонки; для intake статус — это обычный filter, а не отдельный режим layout
|
||||||
|
- кнопки `Фильтры / Сортировка` не остаются внутри списка intake; они выносятся в верхний header cluster по тому же паттерну, что и у `Внутреннего контура`
|
||||||
|
- dropdown фильтров и сортировки не могут жить под карточками списка; popup обязан иметь верхний z-layer и не конфликтовать со scroll/list слоями
|
||||||
|
- search shell внутри intake filter dropdown использует тот же matte glass, что и остальные dropdown/popup
|
||||||
|
- applied filter chips в intake не используют старые `Tag`-плашки `Plane`; они приводятся к glass-chip канону через `.nodedc-filter-chip`
|
||||||
|
- intake-list использует тот же shared `nodedc-work-item-card` shell, что и карточка `Внутреннего контура`; intake допускает только контекстные отличия в meta/footer, а не отдельную геометрию карточки
|
||||||
|
- правая detail-pane `Предложений` не изобретает собственные section-shell; title, description, properties и activity используют тот же peek/details rhythm, что и `Внутреннем контуре`
|
||||||
|
- режим `full-screen` у detail-pane переводит свойства в правую колонку по тому же принципу, что и в `Внутреннем контуре`
|
||||||
|
- activity/comment composer внутри узкой detail-pane должен использовать compact peek-канон, а не растянутый page-form вид
|
||||||
|
- header intake-detail не использует внешнеконтурный toolbar как есть; sequence pill, status pill и decision buttons собираются в один compact peek-row без вылета за край detail-pane
|
||||||
|
- CTA `Принять / Отклонить` в intake-detail не могут иметь фиксированную ширину, которая ломает side-peek; на светлом accent-fill текст всегда тёмный, hover идёт в более светлый тон того же акцента
|
||||||
|
- модалка `Создать входящий рабочий элемент` центрируется как остальные create/edit modal, использует glass shell, `nodedc-modal-input`, `nodedc-modal-editor`, `nodedc-modal-primary-button` и `nodedc-modal-secondary-button`
|
||||||
|
- quick-actions menu по троеточию на карточке обязано открываться из корректного viewport-anchor без оффсета; если локальный card-layer ломает геометрию, menu возвращается в `body` portal, но сохраняет правильный z-layer и привязку к trigger
|
||||||
|
- quick-actions по троеточию не реализуются как отдельный спец-вид меню; они используют тот же popper/portal dropdown-паттерн, что и рабочие меню `Статус / Приоритет`, чтобы trigger, offset и z-layer вели себя одинаково
|
||||||
|
- реализация quick-actions выносится в shared `ActionDropdown`; карточки и detail-view не держат собственный `isMenuActive`, локальный outside-click и отдельный anchor-state для `...`
|
||||||
- popup выбора `Приоритет / Метки` внутри detail view не рендерится inline в property-row; он обязан уходить в `portal`
|
- popup выбора `Приоритет / Метки` внутри detail view не рендерится inline в property-row; он обязан уходить в `portal`
|
||||||
- секции с dropdown-trigger внутри blur/glass shell обязаны иметь `overflow: visible` и `isolation: isolate`, иначе popup визуально “тонет” внутри блока
|
- секции с dropdown-trigger внутри blur/glass shell обязаны иметь `overflow: visible` и `isolation: isolate`, иначе popup визуально “тонет” внутри блока
|
||||||
- при переключении `Открытые / Закрытые` store обязан очистить stale request list до нового fetch, чтобы пользователь не видел flash старой верстки
|
- при переключении `Открытые / Закрытые` store обязан очистить stale request list до нового fetch, чтобы пользователь не видел flash старой верстки
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,376 @@
|
||||||
|
# HDROPDOWN CANON
|
||||||
|
|
||||||
|
Документ фиксирует единый канон dropdown-окон NODE.DC.
|
||||||
|
|
||||||
|
Цель документа:
|
||||||
|
- убрать локальные самодельные реализации выпадающих окон
|
||||||
|
- перевести dropdown на переиспользуемые shared-компоненты
|
||||||
|
- зафиксировать единый контракт для trigger, portal, placement, стилей и поведения
|
||||||
|
- исключить повторение проблемы, когда соседние controls работают по-разному на одном и том же экране
|
||||||
|
|
||||||
|
## Базовый принцип
|
||||||
|
|
||||||
|
Dropdown в системе не является "локальной маленькой версткой рядом с кнопкой".
|
||||||
|
|
||||||
|
Dropdown это:
|
||||||
|
- отдельный floating-layer
|
||||||
|
- отдельный reusable UI-компонент
|
||||||
|
- предсказуемый контракт открытия и закрытия
|
||||||
|
- единый визуальный канон
|
||||||
|
|
||||||
|
Если на экране есть несколько выпадающих окон, пользователь не должен видеть разные механики:
|
||||||
|
- одно окно открывается по тексту
|
||||||
|
- второе только по стрелке
|
||||||
|
- третье клипается контейнером
|
||||||
|
- четвертое открывается с другим типом привязки
|
||||||
|
|
||||||
|
Это считается дефектом стандартизации.
|
||||||
|
|
||||||
|
## Какие dropdown бывают
|
||||||
|
|
||||||
|
В проекте фиксируются три типа выпадающих окон.
|
||||||
|
|
||||||
|
### 1. Selection dropdown
|
||||||
|
|
||||||
|
Используется там, где пользователь выбирает значение.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- `Статус`
|
||||||
|
- `Приоритет`
|
||||||
|
- `Дата`
|
||||||
|
- `Назначенные`
|
||||||
|
- `Метки`
|
||||||
|
- выбор проекта
|
||||||
|
- выбор модуля
|
||||||
|
|
||||||
|
Смысл:
|
||||||
|
- пользователь выбирает одно или несколько значений
|
||||||
|
- у dropdown есть список опций
|
||||||
|
- часто есть поиск
|
||||||
|
- текущее значение отображается в trigger
|
||||||
|
|
||||||
|
Канонические reference-реализации:
|
||||||
|
- [state/base.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/apps/web/core/components/dropdowns/state/base.tsx:45)
|
||||||
|
- [priority.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/apps/web/core/components/dropdowns/priority.tsx:298)
|
||||||
|
|
||||||
|
### 2. Action dropdown
|
||||||
|
|
||||||
|
Используется там, где пользователь вызывает набор действий.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- `...` на карточке задачи
|
||||||
|
- `...` в detail-header
|
||||||
|
- быстрые действия у рабочего элемента
|
||||||
|
|
||||||
|
Смысл:
|
||||||
|
- dropdown не меняет поле напрямую
|
||||||
|
- dropdown показывает список команд
|
||||||
|
- каждая строка запускает `action`
|
||||||
|
|
||||||
|
Канонический shared-компонент:
|
||||||
|
- [action-dropdown.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/packages/ui/src/dropdowns/action-dropdown.tsx:109)
|
||||||
|
|
||||||
|
### 3. Context menu
|
||||||
|
|
||||||
|
Используется только как контекстное меню, а не как основной UI для кнопки `...`.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- правый клик
|
||||||
|
- context-actions, привязанные к `parentRef`
|
||||||
|
|
||||||
|
Правило:
|
||||||
|
- `ContextMenu` не заменяет основной dropdown по клику на кнопку
|
||||||
|
- если у карточки есть кнопка `...`, основной visible menu должен открываться через `ActionDropdown`
|
||||||
|
- `ContextMenu` допустим как дополнительный способ вызвать те же действия через right click
|
||||||
|
|
||||||
|
## Что запрещено
|
||||||
|
|
||||||
|
Запрещено делать новый dropdown через:
|
||||||
|
- локальный `isOpen` без shared-компонента
|
||||||
|
- локальный `useOutsideClick` внутри карточки
|
||||||
|
- inline absolute-блок внутри карточки
|
||||||
|
- popup, который живет внутри scroll-контейнера
|
||||||
|
- отдельную реализацию `...`, если рядом уже есть рабочий shared-dropdown
|
||||||
|
- другой trigger-контракт для соседних controls на одной оси
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
- делать одну механику для `Статуса`, а другую для `...`
|
||||||
|
- открывать меню только по стрелке, если весь control должен быть кликабельным
|
||||||
|
- класть popup внутрь карточки, detail-pane, sidebar или sticky-header без portal
|
||||||
|
- компенсировать неверную архитектуру случайными `left/right translate`
|
||||||
|
|
||||||
|
## Главный стандарт переиспользования
|
||||||
|
|
||||||
|
Перед созданием нового dropdown нужно ответить только на два вопроса:
|
||||||
|
|
||||||
|
1. Это выбор значения или набор действий?
|
||||||
|
2. Есть ли уже shared-компонент для этого типа?
|
||||||
|
|
||||||
|
Если это выбор значения:
|
||||||
|
- использовать существующий selection-dropdown
|
||||||
|
- расширять existing base-component, а не писать новый popup с нуля
|
||||||
|
|
||||||
|
Если это список действий:
|
||||||
|
- использовать `ActionDropdown`
|
||||||
|
- не создавать отдельную локальную механику для карточки, detail-view или sidebar
|
||||||
|
|
||||||
|
## Канонический стек для dropdown
|
||||||
|
|
||||||
|
Любой новый dropdown должен опираться на один и тот же стек:
|
||||||
|
- реальный `trigger`
|
||||||
|
- `usePopper`
|
||||||
|
- `portal`
|
||||||
|
- `outside click close`
|
||||||
|
- `keyboard close/open`
|
||||||
|
- `preventOverflow`
|
||||||
|
- `flip`
|
||||||
|
|
||||||
|
Для action dropdown текущий канон зафиксирован в:
|
||||||
|
- [action-dropdown.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/packages/ui/src/dropdowns/action-dropdown.tsx:118)
|
||||||
|
|
||||||
|
Для selection dropdown reference-стек уже зафиксирован в:
|
||||||
|
- [state/base.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/apps/web/core/components/dropdowns/state/base.tsx:45)
|
||||||
|
|
||||||
|
## Trigger-правила
|
||||||
|
|
||||||
|
Trigger должен быть реальным интерактивным элементом.
|
||||||
|
|
||||||
|
Правила:
|
||||||
|
- dropdown привязывается к настоящей кнопке или surface-контролу
|
||||||
|
- нельзя заворачивать trigger в лишний интерактивный wrapper без причины
|
||||||
|
- нельзя делать `button` внутри `button`
|
||||||
|
- нельзя вешать отдельный click-interceptor на родительскую карточку так, чтобы он ломал trigger dropdown
|
||||||
|
|
||||||
|
Если control живет внутри кликабельной карточки:
|
||||||
|
- интерактивная зона обязана быть помечена как ignore-area для клика карточки
|
||||||
|
- карточка не должна перехватывать клик у dropdown trigger
|
||||||
|
|
||||||
|
Пример текущего канона для вложенной интерактивной зоны карточки:
|
||||||
|
- `data-control-link-ignore="true"`
|
||||||
|
|
||||||
|
## Portal-правила
|
||||||
|
|
||||||
|
Dropdown нельзя рендерить inline, если control находится внутри:
|
||||||
|
- карточки
|
||||||
|
- kanban-колонки
|
||||||
|
- list-item
|
||||||
|
- detail-pane
|
||||||
|
- sidebar
|
||||||
|
- properties section
|
||||||
|
- sticky toolbar
|
||||||
|
- scrollable container
|
||||||
|
|
||||||
|
В этих случаях popup обязан рендериться через portal на верхнем слое.
|
||||||
|
|
||||||
|
Базовое правило:
|
||||||
|
- `document.body` является стандартным portal target, если нет отдельного системного слоя
|
||||||
|
|
||||||
|
Причина:
|
||||||
|
- иначе будут клиппинг, неправильный z-index, обрезание соседними контейнерами и ложные оффсеты
|
||||||
|
|
||||||
|
## Placement-правила
|
||||||
|
|
||||||
|
Placement выбирается не "на глаз", а по канону control-type.
|
||||||
|
|
||||||
|
### Канон для selection dropdown
|
||||||
|
|
||||||
|
По умолчанию:
|
||||||
|
- `bottom-start`
|
||||||
|
|
||||||
|
Это уже используется соседними controls:
|
||||||
|
- `Статус`
|
||||||
|
- `Приоритет`
|
||||||
|
- `Дата`
|
||||||
|
|
||||||
|
### Канон для action dropdown карточек
|
||||||
|
|
||||||
|
Для quick-actions карточек используется тот же базовый anchor-канон, что и у соседних dropdown на той же верхней оси.
|
||||||
|
|
||||||
|
Текущая фиксация для kanban:
|
||||||
|
- [base-kanban-root.tsx](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx:126)
|
||||||
|
- quick-actions в kanban теперь идут через `bottom-start`
|
||||||
|
|
||||||
|
Смысл:
|
||||||
|
- меню раскрывается относительно trigger по той же логике, что и соседние controls
|
||||||
|
- мы не подгоняем offset вручную под один экран
|
||||||
|
- мы нормализуем сам placement-contract
|
||||||
|
|
||||||
|
### Когда допустим другой placement
|
||||||
|
|
||||||
|
Другой placement допустим только если это диктует layout:
|
||||||
|
- `top-start`, если dropdown открывается из нижней части detail-pane и не должен врезаться в секцию ниже
|
||||||
|
- `top-end`, если control находится у правой кромки и popup иначе уходит за экран
|
||||||
|
|
||||||
|
Но это должно быть обосновано layout-контекстом, а не случайной визуальной подгонкой.
|
||||||
|
|
||||||
|
## Offset-правило
|
||||||
|
|
||||||
|
Offset нужен только для вертикального зазора между trigger и popup.
|
||||||
|
|
||||||
|
Канон:
|
||||||
|
- вертикальный gap небольшой и стабильный
|
||||||
|
- боковой offset по умолчанию не используется
|
||||||
|
|
||||||
|
Если кажется, что popup "смотрит не туда":
|
||||||
|
- сначала проверяется правильность `placement`
|
||||||
|
- потом anchor element
|
||||||
|
- и только в последнюю очередь ручной skidding
|
||||||
|
|
||||||
|
Правило:
|
||||||
|
- нельзя лечить неверный `placement` случайным `left/right offset`
|
||||||
|
|
||||||
|
## Визуальный канон
|
||||||
|
|
||||||
|
Все dropdown и popup подчиняются общему matte glass стилю.
|
||||||
|
|
||||||
|
Обязательные свойства:
|
||||||
|
- темный glass surface
|
||||||
|
- blur
|
||||||
|
- мягкая стеклянная граница
|
||||||
|
- без технических outline
|
||||||
|
- без браузерного синего focus ring
|
||||||
|
- без светлой инородной подложки на темном экране
|
||||||
|
|
||||||
|
Внутренние элементы dropdown:
|
||||||
|
- search shell визуально того же семейства, что и popup
|
||||||
|
- option row того же радиуса, что и системные popup-option
|
||||||
|
- hover мягкий, не кислотный
|
||||||
|
- active/selected state не ломает общую палитру
|
||||||
|
|
||||||
|
## Правила для списка действий
|
||||||
|
|
||||||
|
Action dropdown обязан принимать данные в виде menu items.
|
||||||
|
|
||||||
|
Каждый item:
|
||||||
|
- имеет `key`
|
||||||
|
- может иметь `icon`
|
||||||
|
- может иметь `title`
|
||||||
|
- может иметь `description`
|
||||||
|
- может иметь `disabled`
|
||||||
|
- может иметь `action`
|
||||||
|
|
||||||
|
Правило:
|
||||||
|
- визуальный рендер item делается внутри shared action-dropdown
|
||||||
|
- вызывающий код не рисует popup shell вручную
|
||||||
|
|
||||||
|
## Правила для карточек и detail-view
|
||||||
|
|
||||||
|
Для карточек рабочего элемента:
|
||||||
|
- `...` всегда action dropdown
|
||||||
|
- `Статус` и `Приоритет` всегда selection dropdown
|
||||||
|
- все три control-а на одной оси должны использовать совместимую trigger-геометрию и близкий placement-contract
|
||||||
|
|
||||||
|
Для detail-view:
|
||||||
|
- quick actions сверху не должны использовать отдельный popup-engine
|
||||||
|
- если действия те же, используется тот же `ActionDropdown`
|
||||||
|
|
||||||
|
Для `Внутреннего контура`:
|
||||||
|
- quick-actions карточек больше не живут на отдельной локальной механике
|
||||||
|
- они нормализуются под тот же shared dropdown-stack, что и другие controls
|
||||||
|
|
||||||
|
## Правила для хлебных крошек
|
||||||
|
|
||||||
|
Breadcrumb dropdown тоже подчиняется этому документу.
|
||||||
|
|
||||||
|
Правило:
|
||||||
|
- project breadcrumb это dropdown проектов
|
||||||
|
- module breadcrumb это dropdown модулей проекта
|
||||||
|
- весь breadcrumb-item кликабелен, а не только стрелка
|
||||||
|
- стрелка не может быть единственной интерактивной зоной
|
||||||
|
|
||||||
|
Если breadcrumb открывает список выбора:
|
||||||
|
- это selection dropdown
|
||||||
|
- trigger-контракт должен совпадать на всех проектных экранах
|
||||||
|
|
||||||
|
## Правила для новых экранов
|
||||||
|
|
||||||
|
Новый экран не имеет права изобретать свой тип dropdown, если:
|
||||||
|
- уже существует shared action dropdown
|
||||||
|
- уже существует shared selection dropdown
|
||||||
|
|
||||||
|
Порядок работы:
|
||||||
|
1. определить тип dropdown
|
||||||
|
2. выбрать shared-компонент
|
||||||
|
3. выбрать canonical placement
|
||||||
|
4. открыть popup через portal
|
||||||
|
5. применить glass-канон
|
||||||
|
6. проверить поведение внутри scroll/sticky/detail contexts
|
||||||
|
|
||||||
|
## Что делать, если нужен новый вариант
|
||||||
|
|
||||||
|
Если текущих shared-вариантов не хватает:
|
||||||
|
- сначала расширяется shared-component
|
||||||
|
- потом новый вариант документируется в этом файле
|
||||||
|
- только после этого он применяется на экранах
|
||||||
|
|
||||||
|
Что нельзя делать:
|
||||||
|
- сделать новый локальный dropdown "временно"
|
||||||
|
- спрятать временную логику внутри конкретной карточки
|
||||||
|
- оставлять два разных menu-engine для одинаковой задачи
|
||||||
|
|
||||||
|
## Legacy-правило
|
||||||
|
|
||||||
|
Если в проекте еще остались старые dropdown-механики:
|
||||||
|
- они считаются legacy
|
||||||
|
- новые карточечные quick-actions на них не строятся
|
||||||
|
- при доработке экрана предпочтение отдается переводу на shared-канон, а не лечению локального бага поверх legacy-кода
|
||||||
|
|
||||||
|
Это особенно касается:
|
||||||
|
- локальных `CustomMenu`-вариантов для карточечных `...`
|
||||||
|
- inline popup внутри карточек
|
||||||
|
- отдельных `isMenuActive` состояний в item-компонентах
|
||||||
|
|
||||||
|
## Reference-матрица переиспользования
|
||||||
|
|
||||||
|
Использовать:
|
||||||
|
|
||||||
|
- `ActionDropdown`
|
||||||
|
- для `...`
|
||||||
|
- для быстрых действий карточки
|
||||||
|
- для action-menu detail-header
|
||||||
|
|
||||||
|
- `StateDropdown`
|
||||||
|
- для выбора состояния
|
||||||
|
|
||||||
|
- `PriorityDropdown`
|
||||||
|
- для выбора приоритета
|
||||||
|
|
||||||
|
- `DateDropdown`
|
||||||
|
- для выбора даты
|
||||||
|
|
||||||
|
- `MemberDropdown`
|
||||||
|
- для выбора участников
|
||||||
|
|
||||||
|
- `ContextMenu`
|
||||||
|
- только как дополнительное context-menu по `parentRef`
|
||||||
|
- не как основной visible dropdown у кнопки `...`
|
||||||
|
|
||||||
|
## Минимальный check-list перед merge
|
||||||
|
|
||||||
|
Перед завершением задачи с dropdown надо проверить:
|
||||||
|
- popup открывается по клику на весь intended trigger
|
||||||
|
- popup не клипается родительским контейнером
|
||||||
|
- popup не уезжает за экран
|
||||||
|
- popup не живет на отдельном локальном menu-engine без причины
|
||||||
|
- `Статус / Приоритет / ...` на карточке не конфликтуют по click-handling
|
||||||
|
- карточка не перехватывает клик у trigger
|
||||||
|
- popup визуально соответствует matte glass канону
|
||||||
|
- hover, active и selected состояния выглядят как часть одной системы
|
||||||
|
|
||||||
|
## Канон внедрения
|
||||||
|
|
||||||
|
С этого момента правило простое:
|
||||||
|
|
||||||
|
- одинаковая задача = одинаковый dropdown-engine
|
||||||
|
- одинаковый control-type = одинаковый placement-contract
|
||||||
|
- одинаковый popup-type = одинаковый visual shell
|
||||||
|
|
||||||
|
Нельзя:
|
||||||
|
- лечить оффсет одного окна отдельной заплаткой
|
||||||
|
- оставлять соседние dropdown на разных механиках
|
||||||
|
- дублировать menu-логику в карточке, detail-pane и sidebar
|
||||||
|
|
||||||
|
Нужно:
|
||||||
|
- расширять shared-компонент
|
||||||
|
- переиспользовать его на всех экранах
|
||||||
|
- документировать новый вариант сразу в этом файле
|
||||||
Loading…
Reference in New Issue