@shelamkoff/cropper
v1.0.0
Published
Framework-agnostic image cropper with owned modal lifecycle
Maintainers
Readme
@shelamkoff/cropper
Независимый от фреймворков компонент кадрирования изображений с собственным модальным окном, неизменяемым состоянием преобразования, заменяемыми формами и обработчиками ввода, а также выводом через canvas. Версия 1.0.0 поставляется как ESM-пакет для современных браузеров.
Установка
npm install @shelamkoff/cropper @shelamkoff/event-busОдин раз подключите стили:
import '@shelamkoff/cropper/styles.css'@shelamkoff/event-bus является обязательной зависимостью времени выполнения. Для динамического создания <link> пакет экспортирует cropperStylesUrl.
Быстрый старт с модальным окном
CropperDialog управляет затемнением, фокусом, кнопками, экземпляром кадрирования и очисткой ресурсов:
import { CropperDialog } from '@shelamkoff/cropper'
import '@shelamkoff/cropper/styles.css'
const dialog = new CropperDialog(file, {
shape: { type: 'circle' },
output: {
width: 512,
format: 'image/webp',
quality: 0.85,
},
})
dialog.open()
const blob = await dialog.result
if (blob) uploadAvatar(blob)
dialog.destroy()result завершается ровно один раз. Подтверждение возвращает Blob, а отмена, срабатывание signal или уничтожение — null.
Встраиваемый компонент
Используйте Cropper, когда окружающий интерфейс принадлежит приложению:
import { Cropper } from '@shelamkoff/cropper'
const cropper = new Cropper({
source: file,
container,
viewportSize: { width: 640, height: 360 },
shape: { type: 'rectangle', aspectRatio: 16 / 9 },
limits: { minScale: 0.5, maxScale: 6, allowRotation: true },
})
await new Promise((resolve, reject) => {
if (cropper.ready) return resolve()
cropper.once('ready', resolve)
cropper.once('error', ({ error }) => reject(error))
})
cropper.setTransform({ scale: 1.5, rotation: 15 })
const blob = await cropper.crop()
cropper.destroy()Вызов crop() до события ready отклоняет обещание с ошибкой Image not loaded.
Конфигурация
| Параметр | Тип | По умолчанию | Назначение |
| --- | --- | --- | --- |
| source | File \| Blob \| string \| HTMLImageElement | обязательный | Исходное изображение. Строка должна содержать непустой URL или data URL. |
| container | HTMLElement | отсутствует | Необязательный контейнер. Экземпляр также можно смонтировать позже. |
| shape | ShapeConfig | { type: 'circle' } | Встроенная форма circle, rectangle или free. Для прямоугольника применяется aspectRatio. |
| output | Partial<OutputConfig> | { width: 512, height: width, format: 'image/webp', quality: 0.85, fillColor: '#000' } | Размеры и кодирование результата. |
| limits | Partial<TransformLimits> | { minScale: 0.2, maxScale: 10, allowRotation: false } | Диапазон масштаба и разрешение поворота. |
| initialTransform | Partial<Transform> | изображение вписано | Начальные x, y, scale и rotation. |
| viewportSize | number \| { width, height } | 360 | Сторона квадратной или размеры прямоугольной области в CSS-пикселях. |
| interactions | Array<'drag' \| 'wheel' \| 'pinch' \| 'keyboard'> | все четыре | Включённые встроенные способы управления. |
| shapeStrategy | IShapeStrategy | создаётся из shape | Пользовательская стратегия маски и области кадрирования. Заменяет shape. |
| customInteractions | IInteractionHandler[] | [] | Дополнительные обработчики ввода. |
| theme | 'light' \| 'dark' | 'dark' | Тема компонента. |
| locale | Partial<CropperLocale> | английские строки | Переопределяет видимые подписи. |
CropperDialog принимает те же параметры, кроме source и container, а также toolbar, confirmText, cancelText, title и принадлежащий приложению AbortSignal.
API экземпляров
Cropper
| Член API | Описание |
| --- | --- |
| element | Элемент рабочей области, доступный после события ready. |
| ready | Признак завершённой загрузки и инициализации. |
| on, off, once | Методы подписки на типизированные события. on() и once() возвращают функцию отписки. |
| getTransform() | Возвращает текущее преобразование. |
| setTransform(partial) | Применяет частичное преобразование с проверкой и ограничением значений. |
| reset() | Возвращает преобразование вписанного изображения. |
| crop() | Создаёт закодированный Blob согласно output. |
| mount(container) | Монтирует ещё не смонтированный экземпляр. |
| destroy() | Освобождает объектные URL, загрузку изображения, обработчики, DOM и подписки. |
CropperDialog
| Член API | Описание |
| --- | --- |
| result | Promise<Blob \| null> одной модальной сессии. |
| element | Элемент затемнения, отсоединённый до open(). |
| state | 'idle', 'open', 'closed' или 'destroyed'. |
| open(container?) | Монтирует окно в переданный контейнер или document.body и возвращает диалог. |
| cancel() | Закрывает сессию и завершает result значением null. |
| destroy() | Безопасно освобождает диалог и его компонент при повторных вызовах. |
События
| Событие | Данные | Значение |
| --- | --- | --- |
| ready | { imageSize } | Исходник декодирован, обработчики подключены. |
| change | { transform } | Текущее преобразование изменилось. |
| crop | { blob, transform } | Кодирование результата завершено. |
| error | { error } | Ошибка загрузки, проверки, отрисовки или кодирования. |
| destroy | нет | Экземпляр освободил ресурсы. |
Контракты расширения
Реализуйте IShapeStrategy, чтобы добавить собственную маску и область кадрирования. Реализуйте IInteractionHandler, чтобы добавить способ управления: attach(context) получает доступ к преобразованию, размерам изображения и области, ограничениям и DOM-элементу, а detach() обязан освободить все принадлежащие обработчику ресурсы. Встроенные реализации экспортируются как примеры: CircleShape, RectangleShape, FreeShape, DragHandler, WheelZoomHandler, PinchZoomHandler и KeyboardHandler.
Проверки, ограничения и безопасность
- Конструктор отклоняет некорректные размеры, ограничения, качество, формат, цвет фона и неправильные контракты расширений.
- До создания canvas результат ограничивается
16384пикселями на сторону и67 108 864пикселями суммарно. - Для удалённого изображения сервер должен разрешать CORS, иначе защита canvas в браузере приведёт к ошибке
crop(). - Приложение само определяет доверие к удалённым URL. Пакет не передаёт учётные данные и не загружает результат на сервер.
- Вызывайте
destroy()при уничтожении владельца, включая ветви ошибки и отмены.
Демо
Выполните npm run demo в каталоге пакета или npm run demo:cropper из корня рабочего пространства.
Точки входа пакета
@shelamkoff/cropper— компонент, диалог, типы, стратегии, обработчики, отрисовщик, панель управления и URL стилей.@shelamkoff/cropper/styles.css— стили компонента.
Лицензия
MIT.
