Механизм расширений в Flatpickr построен вокруг концепции плагинов как функций, модифицирующих поведение экземпляра календаря через стандартный жизненный цикл. Плагин представляет собой чистую функцию, которая получает доступ к экземпляру календаря и возвращает объект с хуками или модификациями состояния.
Ключевая особенность системы расширений заключается в том, что ядро календаря остаётся неизменным, а вся дополнительная логика внедряется через публичные API и события. Это обеспечивает предсказуемость поведения и совместимость между расширениями.
Базовая структура плагина:
function myPlugin(pluginConfig) {
return function (fp) {
return {
onReady() {},
onChange() {},
onOpen() {},
onClose() {},
onDestroy() {}
};
};
}
Плагин регистрируется через опцию plugins:
flatpickr("#input", {
plugins: [myPlugin({ option: true })]
});
Экземпляр Flatpickr передаётся в плагин как аргумент fp.
Этот объект содержит состояние календаря, DOM-структуру, методы
управления и внутренние параметры.
Основные области доступа:
fp.input — исходный input-элементfp.calendarContainer — контейнер календаряfp.selectedDates — массив выбранных датfp.config — конфигурацияfp.setDate() — программная установка датыfp.close() / fp.open() — управление
видимостьюПлагин должен работать в рамках этих API, избегая прямого вмешательства во внутренние приватные структуры.
Плагины в Flatpickr синхронизированы с жизненным циклом экземпляра календаря.
Основные хуки:
Вызывается после полной инициализации календаря и построения DOM.
onReady() {
this.fp.calendarContainer.classList.add("plugin-ready");
}
Типичное применение:
Используются для реагирования на открытие и закрытие календаря.
onOpen() {
console.log("calendar opened");
}
onClose() {
console.log("calendar closed");
}
Часто применяются для:
Срабатывает при изменении выбранной даты.
onChange(selectedDates, dateStr) {
console.log(selectedDates, dateStr);
}
Позволяет реализовать:
Используется для очистки ресурсов.
onDestroy() {
this.cleanup?.();
}
Одной из типичных задач является изменение визуального представления календаря Flatpickr.
Пример плагина, добавляющего дополнительную панель информации:
function infoPanelPlugin(config) {
return function(fp) {
let panel;
return {
onReady() {
panel = document.createElement("div");
panel.className = "fp-info-panel";
panel.textContent = config.text || "Выберите дату";
fp.calendarContainer.appendChild(panel);
},
onChange(selectedDates) {
if (selectedDates.length) {
panel.textContent = `Выбрано: ${selectedDates[0].toLocaleDateString()}`;
}
},
onDestroy() {
panel?.remove();
}
};
};
}
Такой подход демонстрирует принцип расширяемости: логика не изменяет ядро, а дополняет DOM-структуру.
Плагины в Flatpickr часто принимают конфигурационные параметры, позволяющие переиспользовать один и тот же код в разных сценариях.
function highlightRangePlugin(config) {
return function(fp) {
return {
onDayCreate(dObj, dStr, fpInstance, dayElem) {
if (config.highlightWeekends && [0,6].includes(dObj.getDay())) {
dayElem.classList.add("is-weekend");
}
}
};
};
}
Передача конфигурации:
flatpickr("#input", {
plugins: [
highlightRangePlugin({
highlightWeekends: true
})
]
});
Один из наиболее мощных инструментов расширений в Flatpickr — перехват создания ячеек календаря.
onDayCreate(dObj, dStr, fp, dayElem) {
if (dObj.getDate() === 1) {
dayElem.classList.add("first-day");
}
}
Аргументы:
dObj — объект Date текущего дняdStr — строковое представлениеfp — экземпляр календаряdayElem — DOM-элемент ячейкиЭтот хук позволяет реализовать:
Плагин может читать и изменять состояние экземпляра Flatpickr.
Пример синхронизации внешнего состояния:
function syncPlugin(store) {
return function(fp) {
return {
onChange(selectedDates) {
store.value = selectedDates;
},
onReady() {
if (store.value?.length) {
fp.setDate(store.value);
}
}
};
};
}
Ключевой принцип — односторонняя или контролируемая синхронизация, чтобы избежать конфликтов между UI и внешним состоянием.
Плагины могут расширять API экземпляра календаря Flatpickr, добавляя новые методы.
function extendApiPlugin() {
return function(fp) {
fp.jumpToToday = function() {
fp.setDate(new Date());
fp.open();
};
return {};
};
}
Использование:
const instance = flatpickr("#input", {
plugins: [extendApiPlugin()]
});
instance.jumpToToday();
Такой подход требует аккуратности, так как прямое расширение API может создавать конфликты при использовании нескольких плагинов.
Плагины в Flatpickr часто взаимодействуют с DOM напрямую, но должны соблюдать изоляцию:
Пример корректной изоляции:
onReady() {
const wrapper = document.createElement("div");
wrapper.className = "my-plugin-wrapper";
wrapper.appendChild(document.createTextNode("Custom UI"));
this.fp.calendarContainer.appendChild(wrapper);
}
Корректное управление событиями критично для предотвращения утечек памяти в Flatpickr.
function eventPlugin() {
return function(fp) {
const handler = () => console.log("click");
return {
onReady() {
fp.calendarContainer.addEventListener("click", handler);
},
onDestroy() {
fp.calendarContainer.removeEventListener("click", handler);
}
};
};
}
Обязательная практика — хранение ссылок на обработчики вне хуков, чтобы обеспечить их корректное удаление.
Flatpickr поддерживает использование нескольких расширений одновременно. Плагины выполняются последовательно, что требует учёта возможных пересечений логики.
flatpickr("#input", {
plugins: [
pluginA(),
pluginB(),
pluginC()
]
});
Рекомендации по совместимости:
В экосистеме Flatpickr часто применяются следующие архитектурные подходы:
Позволяет создавать конфигурируемые экземпляры:
const createPlugin = (options) => (fp) => ({
onReady() {
if (options.enabled) {
fp.calendarContainer.classList.add("enabled");
}
}
});
Расширяет существующую логику:
function decoratorPlugin(fp) {
const originalSetDate = fp.setDate;
fp.setDate = function(...args) {
console.log("date changed");
return originalSetDate.apply(this, args);
};
return {};
}
Основано на реакциях на события календаря:
function eventDrivenPlugin() {
return function(fp) {
return {
onChange(dates) {
if (dates.length > 1) {
console.log("range selected");
}
}
};
};
}
При разработке расширений для Flatpickr часто возникают типовые проблемы:
Корректная архитектура требует строгого следования хукам и изоляции состояния внутри плагина.