.. _spec_ui-components_special-symbols-dialog: Диалог спецсимволов =================== .. versionadded:: 1.27.0-ms14 .. seealso:: :ref:`Редактор форматированного текста ` Назначение ---------- React-компонент :term:`SpecialSymbols`, который оборачивает trigger-элемент (кнопку/иконку) и открывает панель выбора спецсимволов согласно параметру ``mode`` (см. :ref:`раздел «Открытие» `). ``children`` могут включать триггер и связанные элементы, но обязательным остаётся ``triggerRef``. Цели вставки (``targetRef``/``editor``/``onSymbolInsert``) задаются параметрами и могут быть как внутри, так и вне обёртки ``SpecialSymbols``. .. image:: special-symbols-dialog.png :alt: Диалог спецсимволов Параметры --------- Доступные параметры (props) компонента: .. list-table:: :header-rows: 1 :widths: 18 16 14 52 * - Параметр - Тип - По умолчанию - Описание * - ``mode`` - ``'mini' | 'full' | 'both'`` - ``'both'`` - Режим открытия компонента (см. :ref:`«Открытие» `). * - ``miniSlots`` - ``number`` - ``12`` - Количество слотов в mini-поповере для :ref:`«Недавних»`. * - ``triggerRef`` - ``React.RefObject`` - не задано - Ref на интерактивный DOM-элемент триггера. * - ``onSymbolInsert`` - ``(symbol) => void`` - не задано - Внешний обработчик вставки (задаётся хостом). * - ``editor`` - Редактор форматированного текста - не задано - Инстанс редактора для вставки символа. * - ``targetRef`` - ``React.RefObject`` - не задано - Целевое поле ввода (input/textarea). Вставка символа --------------- Компонент поддерживает три способа вставки. Если передано несколько параметров одновременно, используется только один — самый приоритетный. **Приоритеты вставки** Символ вставляется в первую доступную цель согласно списку (порядок задания пропсов не важен): 1. ``onSymbolInsert(symbol)`` — внешний обработчик (логику вставки полностью берет на себя хост). 2. ``editor`` — инстанс редактора форматированного текста. 3. ``targetRef`` — прямая ссылка на ``input`` или ``textarea`` элемент. **Работа с несколькими полями** ``targetRef`` всегда указывает на одно текущее поле ввода. Если на странице несколько ``input/textarea``, хост должен поддерживать ``targetRef`` в актуальном состоянии, передавая ссылку на активный в данный момент элемент ввода. .. tip:: **Рекомендуемый паттерн** Чтобы символ всегда попадал в нужное поле, параметр ``targetRef`` должен обновляться динамически. В каждом целевом поле (``input/textarea``) добавьте обработчик ``onFocus``, который будет перезаписывать ``ref``, передаваемый в компонент. Основные UX-сценарии и поведение -------------------------------- .. _spec_ui-components_special-symbols-dialog_opening: Открытие ~~~~~~~~ Компонент работает в одном из режимов, заданных параметром ``mode``. Открытие инициируется взаимодействием с триггером (:kbd:`ЛКМ` или :kbd:`Enter` при фокусе на триггере): - ``mode='mini'``: открывается :ref:`mini-поповер `. - ``mode='full'``: открывается :ref:`full-диалог `. - ``mode='both'``: открывается mini-поповер, из него доступен переход в full (mini закрывается). Закрытие ~~~~~~~~ Компонент закрывается в зависимости от активного режима: **mini-поповер** Закрывается при: - Нажатии клавиши :kbd:`Escape`. - Клике вне поповера. - Выборе символа (одиночный клик, :kbd:`Enter` или :kbd:`Space`) — символ вставляется, поповер закрывается. - Переходе в full-диалог (режим ``mode='both'``) — mini закрывается. **full-диалог** Закрывается при: - Нажатии клавиши :kbd:`Escape`: если поле фильтрации не пусто - очищает фильтр; если фильтр пуст - закрывает диалог. - Нажатии кнопки «Отмена». - Нажатии кнопки закрытия (крестик). - Клике вне диалога. .. _spec_ui-components_special-symbols-dialog_mini-popover: Mini-поповер ~~~~~~~~~~~~ - Показывает сетку «Недавних» (количество слотов задаётся ``miniSlots``, по умолчанию ``12``; значение нормализуется в диапазон ``[1..48]``). При выходе из диапазона значение приводится к ближайшей границе. - Управление фокусом: - При открытии с клавиатуры: фокус автоматически переводится на кнопку «Другие символы…» (если она доступна), иначе — на первый символ в сетке «Недавних». - При открытии мышью: фокус изначально не переводится и остаётся на элементе‑триггере. При первом нажатии :kbd:`Tab` (или :kbd:`Shift+Tab`) фокус перемещается внутрь панели на первый активный элемент. - Зацикливание: навигация с помощью :kbd:`Tab` / :kbd:`Shift+Tab` ограничена внутри поповера — после последнего элемента фокус снова возвращается к первому. - Навигация по :kbd:`Tab`/:kbd:`Shift+Tab` зациклена внутри поповера. - Кнопка «Другие символы…»: - отображается только в режиме ``mode='both'``. - при нажатии открывает :ref:`full-диалог ` и закрывает mini-поповер. - Выбор символа: - одиночный клик, :kbd:`Enter` или :kbd:`Space` вставляют символ и закрывают поповер. .. _spec_ui-components_special-symbols-dialog_full-dialog: Full-диалог ~~~~~~~~~~~ - При открытии фокус ставится в поле фильтра. - Фильтрация: - результаты фильтра показываются после короткой задержки (debounce). - :kbd:`Escape`: если фильтр не пуст — очищает фильтр, иначе закрывает диалог. - Вкладки групп: - клик по вкладке прокручивает к соответствующей секции. - если активна фильтрация — вкладка сначала очищает фильтр, затем выполняется прокрутка. - Выбор символа: - одиночный клик или :kbd:`Space` — выбрать символ и показать превью (tooltip). - :kbd:`Enter` или двойной клик ЛКМ — вставить символ. - Кнопки действий: - «Вставить» — вставляет выбранный символ в целевое поле/редактор (доступна только при выборе символа). - «Копировать» — копирует выбранный символ в буфер обмена (доступна только при выборе символа). - Фокус в модалке: - :kbd:`Tab`/:kbd:`Shift+Tab` не должны переводить фокус на элементы страницы «под» модалкой (фокус остаётся внутри диалога). .. _spec_ui-components_special-symbols-dialog_recent-symbols: Недавние ~~~~~~~~ - «Недавние» хранятся в ``localStorage`` по ключу ``gs-recent-symbols``. - Синхронизация между вкладками реализована через событие ``storage``: когда в одной вкладке меняется ``localStorage``, остальные вкладки того же origin получают window-событие ``storage`` и могут обновить состояние. .. note:: **Важно:** вкладка, которая выполнила запись, событие ``storage`` не получает - для нее обновление делается напрямую. - Если сохранённых «Недавних» нет, UI использует дефолтный набор как fallback (он не записывается в ``localStorage``). .. _spec_ui-components_special-symbols-dialog_restore-focus-on-close: Фокус после закрытия ~~~~~~~~~~~~~~~~~~~~ После закрытия фокус возвращается туда, где пользователь продолжит работу: 1) Редактор форматированного текста (если доступен и редактируемый). 2) Иначе ``targetRef``. 3) Иначе триггер (``triggerRef``). Глобальный индикатор ~~~~~~~~~~~~~~~~~~~~ На время открытия (mini или full) компонент выставляет ``window.__gsSpecialSymbolsOpen = true/false``. .. note:: ``window.__gsSpecialSymbolsOpen`` — это **boolean-флаг состояния**: компонент выставляет ``true`` на время открытия mini/full и возвращает ``false`` при закрытии. Флаг хранится в ``window``, чтобы его могли прочитать **другие части приложения, не являющиеся потомками React-компонента**. Ограничения и ожидания ---------------------- - ``triggerRef`` обязателен: должен указывать на интерактивный DOM-элемент, который может получать фокус и активироваться пользователем (``click``, :kbd:`Enter`, :kbd:`Space`). Иначе не будет корректной работы с клавиатурой. - Должен быть задан хотя бы один путь вставки: ``onSymbolInsert`` или ``editor`` или ``targetRef``. - Для контролируемых полей (React state) предпочтительнее ``onSymbolInsert``: иначе внешнее состояние может «перезаписать» изменения в ``targetRef``. Чек-лист -------- - Передан ``triggerRef`` и он установлен на DOM-элемент триггера. - Задан один из путей вставки (``onSymbolInsert`` / ``editor`` / ``targetRef``). - Выбран ``mode`` (``mini`` / ``full`` / ``both``) под нужный сценарий.