Введение

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

Загвоздка? Количество колонок было динамическим, меняющимся в зависимости от набора данных. Более того, некоторые колонки содержали очень длинный текст, который ломал любой макет, который я пробовал. И вот в чем дело — мы даже не знали точные колонки заранее, только их типы (текст, число, email, дата, дата и время).

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

Поэтому я решил создать собственное решение. Так родился AutoFitGrid.

Проблема

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

Если вы поместите это в обычную HTML таблицу:

  • Колонки выходят за пределы, заставляя появляться горизонтальную прокрутку.
  • Малые значения, такие как числа, в итоге занимают много места.

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

Решение: AutoFitGrid

AutoFitGrid строит сетку, исходя из двух вещей:

  1. Объявленный тип каждой колонки (текст, число, email, дата, дата и время).
  2. Фактические значения внутри ячеек (короткое против длинного содержимого).

Исходя из этого, он автоматически рассчитывает ширину, применяет выравнивание и позволяет содержимому оборачиваться, чтобы сетка оставалась адаптивной. Вам не нужно устанавливать ширину или знать количество колонок заранее — библиотека справляется с этим.

Как я обрабатываю длинный текст (сложная часть)

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

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

Вот логика:

  1. Посчитайте слова в тексте.
  2. Классифицируйте текст как короткий, средний или длинный.
  3. Выберите целевое соотношение в зависимости от категории (короткий текст = более узкий прямоугольник, длинный текст = более широкий прямоугольник).
  4. Рассчитайте подходящие ширину и высоту, чтобы текст аккуратно оборачивался внутри.

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

Инициализация с HTML/JavaScript

Вот как вы объявляете сетку в HTML. Обратите внимание, что нет ширин — только типы.

HTML

<div class="grid-container">
  <div class="grid-header" data-type="text">Описание задачи</div>
  <div class="grid-header" data-type="text">Назначено</div>
  <div class="grid-header" data-type="email">Email</div>
  <div class="grid-header" data-type="datetime">Дата начала</div>
  <div class="grid-header" data-type="datetime">Срок</div>
  <div class="grid-header" data-type="number">Приоритет</div>
  <div class="grid-header" data-type="number">Оценочные часы</div>

  <div class="grid-item">
    Реализуйте очень длинное описание, чтобы протестировать, как макет сетки подстраивается
    и оборачивает текст динамически на нескольких строках.
  </div>
  <div class="grid-item">Джейн Доу</div>
  <div class="grid-item">jane.doe@example.com</div>
  <div class="grid-item">2024-01-15 08:30:00</div>
  <div class="grid-item">2024-07-15 17:00:00</div>
  <div class="grid-item">1</div>
  <div class="grid-item">100</div>
</div>

JavaScript

Как только ваш разметка готова, вы даете сетке немного интеллекта с помощью одного вызова инициализации.

new AutoFitGrid({
  container: document.querySelector('.grid-container'),
  defaultMinWidth: 50,
  defaultMaxWidth: Infinity,
  adjustmentThreshold: 200,
  headerSelector: '.grid-header',
  columnSelector: '.grid-item',
  showDebug: false
});

Если вы включите showDebug: true, вы увидите логи, показывающие, как AutoFitGrid измеряет и подстраивает колонки.

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

import React, { useEffect, useRef } from 'react';
import AutoFitGrid from 'auto-fit-grid';

function MyGrid() {
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current) {
      new AutoFitGrid({
        container: ref.current,
        headerSelector: '.grid-header',
        columnSelector: '.grid-item'
      });
    }
  }, []);

  return (
    <div className="grid-container" ref={ref}>
      <div className="grid-header" data-type="text">Имя</div>
      <div className="grid-header" data-type="email">Email</div>
      <div className="grid-header" data-type="number">Оценка</div>

      <div className="grid-item">Алиса Вондерленд</div>
      <div className="grid-item">alice@example.com</div>
      <div className="grid-item">88</div>

      <div className="grid-item">Боб Бобсон</div>
      <div className="grid-item">bob@example.com</div>
      <div className="grid-item">95</div>
    </div>
  );
}

Установка и тестирование

Вы можете установить AutoFitGrid из npm:

npm install auto-fit-grid

Или посмотрите живые примеры и документацию: