Основные типы и интерфейсы

Архитектура библиотеки опирается на несколько ключевых абстракций, которые определяют поведение компонента, структуру данных и взаимодействие с DOM. Основные типы формируют контракт между пользовательским кодом, внутренним состоянием и внешними источниками данных.

Тип Option

Option представляет единицу выбора в выпадающем списке. Это фундаментальная структура, из которой строится весь набор доступных значений.

Типовая форма:

interface Option {
  value: string | number
  text: string
  disabled?: boolean
  $order?: number
  [key: string]: any
}

Ключевые особенности:

  • value — уникальный идентификатор опции, используемый для хранения выбранного состояния
  • text — отображаемая строка
  • disabled — флаг недоступности выбора
  • расширяемость через индексную сигнатуру позволяет добавлять произвольные поля (например, метаданные для рендера)

В контексте асинхронной загрузки данные часто нормализуются к этой структуре перед попаданием в компонент.


Тип Item

Item — это выбранная сущность, отражающая текущее состояние выбора. Внутренне Item тесно связан с Option, но представляет уже активное состояние.

type Item = string

или в расширенных реализациях:

type Item = string | number

Особенности:

  • хранится в списке выбранных значений
  • соответствует value из Option
  • не содержит UI-метаданных
  • используется как минимальная единица состояния

Внутреннее представление всегда стремится к примитивному типу для упрощения сериализации и сравнения.


OptGroup и группировка данных

Группировка опций реализуется через OptGroup, который описывает логическую категорию элементов.

interface OptGroup {
  label: string
  value?: string
  disabled?: boolean
  optgroup: true
  [key: string]: any
}

Структурные свойства:

  • label — заголовок группы
  • optgroup — маркер типа
  • дополнительные поля используются для кастомного рендера или фильтрации

Опции внутри группы не изменяют свою природу — они остаются Option, но связываются с группой через optgroup или вложенную структуру данных.


Тип Settings

Конфигурация компонента определяется через большой интерфейс Settings, который управляет логикой поведения, рендерингом и источниками данных.

interface Settings {
  valueField: string
  labelField: string
  searchField: string | string[]

  options: Option[]
  items: Item[]

  placeholder?: string
  maxItems?: number

  create?: boolean | ((input: string) => boolean)

  persist?: boolean

  loadThrottle?: number

  preload?: boolean | "focus"

  [key: string]: any
}

Ключевые аспекты:

  • разделение valueField и labelField позволяет работать с произвольными структурами данных
  • searchField определяет поля для фильтрации
  • create включает режим создания новых элементов
  • maxItems ограничивает множественный выбор
  • loadThrottle регулирует частоту асинхронных запросов

Расширяемость настроек является критической частью архитектуры, позволяя внедрять плагины и пользовательские расширения без изменения ядра.


Интерфейс экземпляра TomSelect

Экземпляр компонента представляет собой объект с состоянием, методами управления и API для внешнего взаимодействия.

interface TomSelectInstance {
  settings: Settings
  options: Record<string, Option>
  items: Item[]

  addOption(data: Option): void
  addItem(value: string | number, silent?: boolean): void
  removeItem(value: string | number): void

  clear(): void
  clearOptions(): void

  focus(): void
  blur(): void

  destroy(): void

  refreshOptions(triggerDropdown?: boolean): void
}

Поведенческие особенности:

  • addItem синхронизирует состояние UI и внутренний массив items
  • removeItem влияет как на DOM, так и на модель данных
  • clear сбрасывает текущее состояние без удаления конфигурации
  • destroy полностью освобождает ресурсы и возвращает исходный DOM

Внутренняя реализация обычно включает дополнительные приватные методы, не входящие в публичный контракт.


Событийная модель

Система событий строится вокруг стандартного паттерна publish/subscribe.

Основные события:

interface TomSelectEvents {
  "item_add": (value: Item) => void
  "item_remove": (value: Item) => void
  "option_add": (option: Option) => void
  "dropdown_open": () => void
  "dropdown_close": () => void
  "change": (value: Item[]) => void
  "type": (query: string) => void
}

Особенности:

  • события разделены по уровню абстракции (UI и data layer)
  • change агрегирует состояние items
  • type используется для отслеживания ввода и триггера поиска
  • события могут подавляться через silent режим методов API

Типы DOM-элементов

Компонент взаимодействует с DOM через набор строго определённых ссылок на элементы.

interface TomSelectControl {
  input: HTMLInputElement
  dropdown: HTMLElement
  control: HTMLElement
  dropdown_content: HTMLElement
  wrapper: HTMLElement
}

Назначение:

  • input — точка ввода текста
  • dropdown — контейнер списка
  • control — основная область взаимодействия
  • dropdown_content — динамически обновляемая часть списка
  • wrapper — корневой контейнер компонента

Эти ссылки используются для оптимизированных операций обновления без полной перерисовки.


Типы поиска и фильтрации

Поисковый механизм опирается на функцию фильтрации, тип которой определяется как:

type ScoreFunction = (search: string, option: Option) => number

или более сложная форма:

type FilterFunction = (item: Option, query: string) => boolean

Использование:

  • ScoreFunction применяется для ранжирования результатов
  • FilterFunction используется для бинарного включения/исключения

Фильтрация может быть переопределена через настройки, что позволяет реализовать кастомные алгоритмы поиска (например, fuzzy search или поиск по токенам).


Типы асинхронной загрузки

Для работы с удалёнными источниками данных используется контракт загрузчика:

type LoadCallback = (query: string, callback: (options: Option[]) => void) => void

и альтернативная Promise-форма:

type LoadFunction = (query: string) => Promise<Option[]>

Поведение:

  • LoadCallback используется для legacy API
  • LoadFunction предпочтителен для современных реализаций
  • результат всегда нормализуется в Option[]
  • асинхронные данные проходят этап кеширования и дедупликации

Типы создания новых элементов

Механизм создания новых значений определяется функцией:

type CreateFilter = (input: string) => boolean

и генератором:

type CreateFunction = (input: string) => Option

Особенности:

  • фильтр определяет допустимость создания
  • генератор формирует структуру нового Option
  • новые элементы интегрируются в основной список и становятся частью items

Внутренние служебные типы

Для обеспечения работы UI используются дополнительные типы:

interface ActiveItem {
  value: Item
  $el: HTMLElement
}

interface HighlightState {
  index: number
  lastQuery: string
}

Назначение:

  • ActiveItem связывает данные и DOM-узел
  • HighlightState управляет состоянием навигации по списку

Эти структуры не входят в публичное API, но определяют поведение навигации и визуального выделения.


Типизация плагинов

Плагины расширяют функциональность через единый контракт:

interface TomSelectPlugin {
  initialize?: (instance: TomSelectInstance) => void
  destroy?: () => void
}

Принципы:

  • initialize получает доступ к экземпляру компонента
  • destroy используется для очистки подписок и состояния
  • плагины могут модифицировать settings, DOM и события

Система плагинов проектируется как слабосвязанная, позволяя накладывать расширения без изменения ядра.


Обобщённая модель типов

Вся система типов формирует замкнутый цикл данных:

  • Option определяет исходный набор
  • Item фиксирует выбранное состояние
  • Settings управляет поведением
  • TomSelectInstance связывает всё в единый API
  • события синхронизируют изменения между слоями
  • DOM-типы обеспечивают визуализацию

Эта структура обеспечивает предсказуемость состояния и стабильность взаимодействия между слоями компонента без необходимости прямого управления DOM извне.