# Announcement — логика компонента

## Что делает компонент

Информационное сообщение с иконкой, текстом и кнопкой закрытия.
Если текст не помещается в `collapsedHeight` (по умолчанию 4.5em) —
автоматически добавляется кнопка «развернуть / свернуть».

---

## Файлы

| Файл | Назначение |
|---|---|
| `Announcement.js` | Dojo-виджет, логика |
| `announcement.html` | Шаблон (attach points) |
| `announcement.less` | Все стили, анимации, состояния |

---

## CSS-классы на корневом элементе (domNode)

| Класс | Когда | Что даёт |
|---|---|---|
| `officeAnnouncement-collapsible` | JS: текст переполняет высоту | Показывает кнопку toggle через CSS |
| `officeAnnouncement-expanded` | JS: пользователь развернул | Прячет icon-cell, разворачивает шеврон |
| `blue` / `warning` / … | Через `set("color", …)` | Цветовая схема |

**Правило**: JS только добавляет/убирает эти классы.
Всё, что можно — делает CSS (анимация иконки, поворот шеврона, видимость кнопки).

---

## Жизненный цикл: когда текст сжимается

```
startup()
  └─ _checkCollapsible()
        │
        ├─ scrollHeight === 0?  ──► retry через 200 мс
        │   (виджет в скрытой вкладке / ещё не отрисован)
        │
        ├─ Временно отключить CSS-transition
        ├─ Установить maxHeight: collapsedHeight
        ├─ Прочитать scrollH vs clientH
        ├─ Восстановить transition
        │
        ├─ overflow?  ──► добавить COLLAPSIBLE_CLASS
        │                  CSS сам покажет кнопку toggle
        └─ no overflow ──► убрать COLLAPSIBLE_CLASS + maxHeight: none

_setTextAttr() (при каждом set("text", …) после startup)
  ├─ pre-constrain: maxHeight = collapsedHeight (без transition, до рендера текста)
  └─ _checkCollapsible()   ← тот же путь
```

**Pre-constraint в `_setTextAttr`**: `maxHeight: collapsedHeight` ставится
**до** `translate()` — до того, как текст попадает в DOM. Браузер впервые рисует
виджет уже в сжатом состоянии, flash не возникает. Если текст короткий —
`_checkCollapsible` тут же снимает ограничение в else-ветке.

**Retry**: если `scrollHeight === 0` при первом вызове (панель ещё не видна,
идёт анимация), через 200 мс делается одна повторная попытка.
Флаг `_collapsibleRetry` предотвращает накопление таймеров при нескольких
последовательных `set("text")`.

**Зачем подавлять transition**: без этого установка `maxHeight: collapsedHeight`
при первоначальной проверке запускала бы видимую анимацию сжатия при загрузке страницы.

---

## Expand / Collapse (кнопка toggle)

```
_toggleExpand()
  └─ expanded = !expanded
  └─ _applyExpandedState(instant=false)
```

### Expand (разворачивание)

1. `domClass.add(domNode, EXPANDED_CLASS)` — запускает CSS-анимации:
   - icon-cell: `max-width → 0`, `opacity → 0` (transition в .less)
   - шеврон: `transform: rotate(-135deg)` (transition в .less)
2. `bodyNode.maxHeight = scrollHeight + "px"` — задаёт конкретную точку старта,
   иначе transition от `"none"` не работает
3. Через `BODY_ANIM_MS + 20` мс: `maxHeight = "none"` — убирает ограничение
   после окончания анимации (виджет не обрежет текст при изменении размера окна)

### Collapse (сворачивание)

1. `domClass.remove(domNode, EXPANDED_CLASS)` — запускает CSS-анимации обратно
2. `bodyNode.maxHeight = scrollHeight + "px"` — снова конкретная точка старта
3. Форсированный reflow (`offsetHeight`)
4. `bodyNode.maxHeight = collapsedHeight` — CSS-transition анимирует сжатие

**Почему body-анимация в JS, а не CSS**: CSS-transition на `max-height` не умеет
анимировать переход из `none` (нет числового значения). JS устанавливает
промежуточное пиксельное значение, чтобы дать transition конкретный start/end.

---

## Кнопка закрытия (×)

`_hide()` → `hide()` → `fx.animateProperty` на `opacity` 0→1 → `destroyRecursive()`.
Если задан `onHide` callback — вызывается перед уничтожением.

---

## Параметры виджета

| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `text` | String / Object | — | Текст (строка или `{RU: "…", EN: "…"}`) |
| `color` | String | `"blue"` | CSS-класс цветовой схемы |
| `icon` | String | `"info"` | Иконка: `info`, `smile`, `sad`, `confused`, `bullhorn`, `warning`, `blocked` |
| `collapsedHeight` | String | `"4.5em"` | Макс. высота в свёрнутом состоянии |
| `readOnly` | Boolean | `null` | Если true — скрывает кнопку × |
| `onHide` | Function | `null` | Callback после закрытия |

---

## Зависимости от CSS (announcement.less)

Компонент **требует** актуального `announcement.css` (скомпилированного из `.less`).
Без него:
- Раскладка строки (flex) не работает
- Иконка не анимируется при expand/collapse
- Кнопка toggle не видна
- Градиент-fade не показывается

JS специально **не дублирует** эти стили inline — это осознанный выбор после
рефакторинга (была версия с inline-страховкой, убрана как лишняя сложность).
