Выбор цветов

Выбор цветов в Tom Select реализуется через комбинацию кастомных значений опций, переопределения рендеринга элементов и управления вводом новых значений. Библиотека не предоставляет встроенный color picker, но позволяет легко построить полноценный интерфейс выбора цветов поверх стандартного механизма тегов и селектов.

Основная идея заключается в том, что цвет представляется как строковое значение (обычно HEX, реже RGB или HSL), а визуальное отображение формируется через кастомные шаблоны render.option и render.item. Это позволяет превращать обычный select в компонент, визуально похожий на палитру.


Tom Select работает с унифицированными значениями опций. Для цветов чаще всего используется HEX-формат:

{
  value: "#ff0000",
  text: "Красный"
}

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

При работе с динамическими палитрами значения могут формироваться на лету:

const colors = [
  { value: "#1abc9c", text: "Turquoise" },
  { value: "#2ecc71", text: "Emerald" },
  { value: "#3498db", text: "Peter River" }
];

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

Для поддержки произвольного ввода цветов используется режим создания новых элементов:

new TomSelect("#color-select", {
  persist: false,
  create: true
});

В этом режиме любое введённое значение становится новым элементом списка. При работе с цветами это позволяет вводить HEX-коды вручную, например #a1b2c3.

Часто добавляется дополнительная нормализация ввода, чтобы гарантировать корректность формата:

create: function(input) {
  const isValidHex = /^#([0-9a-fA-F]{6})$/.test(input);
  if (!isValidHex) return false;

  return {
    value: input,
    text: input
  };
}

Визуализация цветовых опций

Ключевой аспект работы с цветами — переопределение отображения элементов списка. Для этого используется render.option:

new TomSelect("#color-select", {
  options: colors,
  valueField: "value",
  labelField: "text",
  searchField: "text",

  render: {
    option: function(data, escape) {
      return `
        <div class="color-option">
          <span class="color-swatch" style="background:${escape(data.value)}"></span>
          <span class="color-label">${escape(data.text)}</span>
        </div>
      `;
    },

    item: function(data, escape) {
      return `
        <div class="color-item">
          <span class="color-swatch" style="background:${escape(data.value)}"></span>
          <span>${escape(data.value)}</span>
        </div>
      `;
    }
  }
});

Такой подход разделяет визуальную и текстовую части: цвет отображается через inline-стиль, а текст используется только для идентификации.


Стилизация цветовых свотчей

CSS-часть играет ключевую роль в восприятии компонента. Обычно используется минималистичная круглая или квадратная индикация:

.color-option,
.color-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.color-swatch {
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid rgba(0,0,0,0.1);
}

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

.color-swatch {
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.08);
}

Поддержка множественного выбора цветов

Tom Select изначально поддерживает мультивыбор, что особенно полезно для палитр:

new TomSelect("#color-select", {
  plugins: ["remove_button"],
  maxItems: null
});

В этом режиме выбранные цвета отображаются как отдельные элементы, каждый из которых можно стилизовать независимо. Это позволяет реализовать интерфейсы тегирования цветами, например подбор палитры для дизайна.


Генерация цветов и палитры

Часто цвета не вводятся вручную, а генерируются автоматически. Например, палитра может формироваться на основе алгоритма равномерного распределения оттенков:

function generatePalette(n) {
  const colors = [];
  for (let i = 0; i < n; i++) {
    const hue = Math.round((360 / n) * i);
    colors.push({
      value: `hsl(${hue}, 70%, 50%)`,
      text: `Hue ${hue}`
    });
  }
  return colors;
}

Такая модель удобна для UI-конструкторов, где важно быстро предложить визуально различимые варианты.


Валидация цветовых значений

При работе с пользовательским вводом необходимо ограничивать допустимые форматы. Помимо HEX, часто поддерживаются RGB и HSL, однако внутри системы обычно выполняется приведение к единому виду.

Простейшая проверка:

function normalizeColor(input) {
  const hex = input.trim();

  if (/^#([0-9a-f]{6})$/i.test(hex)) return hex;

  return null;
}

Более сложные реализации могут включать конвертацию через временный DOM-элемент или canvas.


Интеграция с внешним color picker

Tom Select часто используется совместно с отдельными библиотеками выбора цвета. В этом случае select служит контейнером для сохранения результата:

const select = new TomSelect("#color-select", {
  create: true
});

someColorPicker.on("change", (color) => {
  select.addOption({ value: color.hex, text: color.hex });
  select.addItem(color.hex);
});

Такой подход разделяет ответственность: picker отвечает за выбор, Tom Select — за хранение и отображение.


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

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

new TomSelect("#color-select", {
  searchField: ["text", "value"]
});

При этом можно реализовать приоритет поиска по названию, а не по HEX-коду, чтобы ускорить выбор.


Динамическое обновление палитры

Цветовые наборы могут изменяться в зависимости от состояния приложения:

const control = new TomSelect("#color-select", {
  options: []
});

function updatePalette(newColors) {
  control.clearOptions();
  control.addOptions(newColors);
  control.refreshOptions(false);
}

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


Поведение выбранных значений

Внутренне Tom Select хранит выбранные цвета как массив значений. Это позволяет легко сериализовать результат:

const selected = control.getValue(); 
// ["#ff0000", "#00ff00"]

При отправке формы значения могут напрямую использоваться в API, где цвет уже интерпретируется как параметр визуального оформления.


Расширение через кастомные данные

Для сложных интерфейсов цвет может быть не просто строкой, а объектом:

{
  value: "#ff0000",
  text: "Red",
  meta: {
    contrast: "high",
    category: "primary"
  }
}

Отображение при этом адаптируется:

render: {
  option: function(data, escape) {
    return `
      <div>
        <span style="background:${escape(data.value)}" class="swatch"></span>
        <span>${escape(data.text)}</span>
        <small>${escape(data.meta.category)}</small>
      </div>
    `;
  }
}

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