Breaking changes

Библиотека Pikaday в процессе эволюции претерпела несколько критических изменений, которые затрагивают инициализацию, поведение календаря, работу с датами и интеграцию с внешними библиотеками. Основные breaking changes связаны с переходом от ранних версий, завязанных на Moment.js, к более гибкой архитектуре, а также с переработкой внутренних событий и конфигурационных опций.

Отказ от жёсткой зависимости Moment.js

Одним из ключевых архитектурных изменений стало постепенное отделение Pikaday от обязательной зависимости Moment.js. В ранних версиях Moment.js использовался как основной механизм форматирования и парсинга дат. Это приводило к тесной связке API календаря с объектами Moment, что ограничивало использование стандартного JavaScript Date.

В более поздних версиях:

  • Moment.js перестал быть обязательной зависимостью
  • внутренние преобразования дат перешли на нативный Date
  • форматирование стало опциональным через кастомные функции

Это изменение ломает обратную совместимость для кода, который напрямую использует moment() в конфигурациях toString или parse.

Пример несовместимого подхода:

new Pikaday({
    toString(date) {
        return moment(date).format('YYYY-MM-DD');
    }
});

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

Актуальная замена:

new Pikaday({
    toString(date) {
        return date.toISOString().split('T')[0];
    }
});

Изменение поведения парсинга дат

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

В breaking changes введены следующие ограничения:

  • строковый ввод без parse больше не гарантирует одинаковый результат
  • убрана попытка «угадывания» форматов
  • ответственность за парсинг перенесена на разработчика

Это означает, что следующий код может вести себя непредсказуемо:

new Pikaday({
    field: document.getElementById('input'),
    defaultDate: '01-02-2024'
});

Корректный подход после изменений:

new Pikaday({
    field: document.getElementById('input'),
    parse(dateString) {
        const [day, month, year] = dateString.split('-');
        return new Date(year, month - 1, day);
    }
});

Изменения в API событий

Существенные изменения затронули систему событий календаря. В старых версиях использовались прямые колбэки без стандартизированного контекста вызова. Позднее структура событий была унифицирована.

Изменения:

  • onSelect теперь всегда получает объект Date, а не строку
  • изменён порядок аргументов в некоторых callback-функциях
  • контекст this больше не гарантирован как экземпляр Pikaday

Ранее допустимый код:

new Pikaday({
    onSelect(dateString) {
        console.log(this.getDate(), dateString);
    }
});

После изменений:

new Pikaday({
    onSelect(date) {
        console.log(date);
        console.log(this?.getDate?.());
    }
});

Особенно критично изменение поведения this, так как старые реализации могли полагаться на него для доступа к методам экземпляра.


Удаление и переименование опций конфигурации

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

Основные изменения:

  • bound — изменилось поведение привязки к input-элементу
  • container — переработана логика рендеринга в DOM
  • reposition — изменена стратегия позиционирования
  • keyboardInput — частично ограничена поддержка кастомного ввода

Пример устаревшей конфигурации:

new Pikaday({
    field: input,
    bound: false,
    container: document.getElementById('calendar-container')
});

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


Изменение работы с minDate и maxDate

Логика ограничения диапазона дат была переработана. Ранее допускались строки, числа timestamp и объекты Date без строгой нормализации.

После изменений:

  • принимаются только объекты Date или явно валидируемые значения
  • строки требуют явного парсинга
  • сравнение дат стало происходить без приведения типов

Старый подход:

new Pikaday({
    minDate: '2024-01-01',
    maxDate: '2024-12-31'
});

Новый подход:

new Pikaday({
    minDate: new Date(2024, 0, 1),
    maxDate: new Date(2024, 11, 31)
});

Изменения в форматировании вывода

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

Изменения:

  • удалены встроенные форматы типа YYYY-MM-DD
  • добавлена необходимость явного определения toString
  • изменена логика локализации

Пример старого поведения:

new Pikaday({
    format: 'DD/MM/YYYY'
});

После изменений:

new Pikaday({
    toString(date) {
        return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
    }
});

Переработка механизма рендера календаря

Внутренняя система построения DOM была изменена с императивного на более структурированный рендеринг. Это затронуло:

  • генерацию DOM-узлов
  • классы CSS
  • структуру календарной сетки

Ключевые последствия:

  • пользовательские CSS, завязанные на старую структуру, перестают работать
  • изменились className для дней, заголовков и кнопок навигации
  • изменился порядок элементов внутри контейнера

Пример старого селектора:

.pika-day {
    background: #fff;
}

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

.pika-button.pika-day {
    background: #fff;
}

Изменения поведения выбора даты

Механизм выбора даты стал более строгим в отношении валидных значений:

  • игнорируются даты вне диапазона min/max
  • повторный выбор той же даты может не вызывать событие
  • изменено поведение при клике на уже выбранный день

Ранее повторный выбор мог триггерить onSelect, теперь это поведение зависит от внутреннего состояния и настроек.


Ограничения обратной совместимости при кастомных сборках

При использовании кастомных сборок или бандлинга через Webpack/Rollup появились ограничения:

  • некоторые внутренние модули больше не экспортируются напрямую
  • изменены пути импорта
  • требуется обновление конфигурации сборщика

Пример устаревшего импорта:

import Pikaday from 'pikaday/pikaday';

Актуальный вариант:

import Pikaday from 'pikaday';

Изменения поведения локализации

Система локализации была переработана и стала более декларативной. Старые локали перестали поддерживать автоматическое наследование.

Изменения:

  • удалены неявные fallback-локали
  • требуется явное указание всех строк интерфейса
  • изменён формат объекта i18n

Пример старого подхода:

new Pikaday({
    i18n: {
        previousMonth: 'Prev',
        nextMonth: 'Next'
    }
});

После изменений требуется полный набор ключей:

new Pikaday({
    i18n: {
        previousMonth: 'Prev',
        nextMonth: 'Next',
        months: [...],
        weekdays: [...],
        weekdaysShort: [...]
    }
});