Визуальная индикация типов

Визуальная индикация типов в Awesomplete строится вокруг переопределения стандартного способа рендеринга элемента списка. Библиотека по умолчанию выводит строки, но архитектура предусматривает замену функции формирования DOM-узла, что позволяет внедрять любые метки типа: категории, уровни, статусы, происхождение данных.

Ключевая точка расширения — функция item, отвечающая за создание элемента списка.


Структура данных для типизированных подсказок

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

Типичная структура:

const list = [
  { label: "Apple", type: "fruit" },
  { label: "Carrot", type: "vegetable" },
  { label: "Salmon", type: "fish" }
];

Минимально необходимое поле — label, поскольку именно оно используется Awesomplete для фильтрации и подстановки. Остальные поля служат исключительно для визуального оформления.

При этом можно расширять модель:

{
  label: "Tesla Model S",
  type: "car",
  category: "electric",
  popularity: "high"
}

Переопределение функции item для визуального рендеринга

Основной механизм индикации типов заключается в кастомизации функции item.

new Awesomplete(input, {
  list: list,
  item: function(text, input) {
    const li = document.createElement("li");

    const span = document.createElement("span");
    span.textContent = text.label;

    const badge = document.createElement("span");
    badge.textContent = text.type;
    badge.className = "aw-type aw-type-" + text.type;

    li.appendChild(span);
    li.appendChild(badge);

    return li;
  }
});

В данном случае каждый элемент списка превращается в составной DOM-узел:

  • основной текст
  • визуальный бейдж типа

Awesomplete не ограничивает структуру элемента, поэтому возможно добавление любых вложенных узлов.


CSS-уровень индикации типов

После внедрения DOM-разметки ключевая роль переходит к стилям.

Базовое оформление контейнера типа

.aw-type {
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 10px;
  margin-left: 8px;
  display: inline-block;
}

Цветовая дифференциация типов

Типизация чаще всего реализуется через модификаторы классов:

.aw-type-fruit {
  background: #ffeb3b;
  color: #000;
}

.aw-type-vegetable {
  background: #4caf50;
  color: #fff;
}

.aw-type-fish {
  background: #03a9f4;
  color: #fff;
}

Такой подход обеспечивает масштабируемость: добавление нового типа не требует изменения JS-логики, достаточно добавить CSS-правило.


Использование иконок как индикаторов типа

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

const icons = {
  fruit: "?",
  vegetable: "?",
  fish: "?"
};

item: function(text) {
  const li = document.createElement("li");

  li.innerHTML = `
    <span class="label">${text.label}</span>
    <span class="icon">${icons[text.type] || ""}</span>
  `;

  return li;
}

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


Индикация типа через цветовую полосу

Альтернативный визуальный паттерн — левый маркер.

item: function(text) {
  const li = document.createElement("li");
  li.className = "item item-" + text.type;

  li.textContent = text.label;
  return li;
}
.item {
  padding-left: 10px;
}

.item-fruit {
  border-left: 4px solid #ffeb3b;
}

.item-vegetable {
  border-left: 4px solid #4caf50;
}

.item-fish {
  border-left: 4px solid #03a9f4;
}

Такой подход особенно эффективен в плотных списках, где важно сохранить компактность интерфейса.


Комбинированная модель визуальной типизации

На практике используется сочетание нескольких сигналов одновременно: цвет, иконка и текстовый бейдж.

item: function(text) {
  const li = document.createElement("li");

  const icon = document.createElement("span");
  icon.className = "icon";
  icon.textContent = icons[text.type];

  const label = document.createElement("span");
  label.className = "label";
  label.textContent = text.label;

  const type = document.createElement("span");
  type.className = "type";
  type.textContent = text.type;

  li.appendChild(icon);
  li.appendChild(label);
  li.appendChild(type);

  return li;
}

Такой вариант позволяет пользователю считывать тип сразу на нескольких уровнях восприятия.


Контекстная типизация через данные ввода

Awesomplete поддерживает доступ к текущему вводу через аргумент input, что позволяет изменять визуализацию в зависимости от контекста поиска.

item: function(text, input) {
  const li = document.createElement("li");

  if (input.value.startsWith("#")) {
    li.className = "hashtag-mode";
  }

  li.textContent = text.label;
  return li;
}

Таким образом тип может быть не только свойством данных, но и функцией контекста.


Группировка как расширение визуальной типизации

Хотя Awesomplete не имеет встроенных групп, визуальная группировка может быть реализована через специальные элементы-разделители.

const list = [
  { label: "Fruits", group: true },
  { label: "Apple", type: "fruit" },
  { label: "Banana", type: "fruit" }
];
item: function(text) {
  const li = document.createElement("li");

  if (text.group) {
    li.className = "group-header";
    li.textContent = text.label;
    return li;
  }

  li.textContent = text.label;
  li.className = "item item-" + text.type;

  return li;
}
.group-header {
  font-weight: bold;
  background: #f5f5f5;
  cursor: default;
}

Управление состояниями типов при фильтрации

Фильтрация Awesomplete не учитывает визуальные признаки, поэтому типы должны сохраняться независимо от поиска.

При необходимости можно модифицировать filter:

filter: function(text, input) {
  return text.label.toLowerCase().includes(input.value.toLowerCase());
}

Дополнительная логика может учитывать тип:

filter: function(text, input) {
  if (input.value.startsWith("@")) {
    return text.type === "user";
  }
  return true;
}

Повышение производительности при сложной визуализации

При большом количестве типов и сложной DOM-структуре возникает необходимость оптимизации:

  • избегается использование innerHTML при частых обновлениях
  • переиспользуются DOM-элементы при кастомной реализации
  • минимизируется количество вложенных узлов
  • стили выносятся в CSS вместо inline-стилей

Дополнительный эффект дает кэширование вычисленных элементов:

const cache = new Map();

function renderItem(text) {
  if (cache.has(text.label)) return cache.get(text.label);

  const li = document.createElement("li");
  li.textContent = text.label;

  cache.set(text.label, li);
  return li;
}

Итоговая архитектурная модель визуальной типизации

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

  • Данные — расширенные объекты с полями типа
  • Логика — кастомизация item, filter, частично sort
  • Представление — CSS-классы, иконки, бейджи, маркеры

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