npm package: @lujichu/image-viewer
Description: Lightweight zero-dependency TypeScript image viewer with zoom, drag, rotate, thumbnails, keyboard navigation.
Author: jichulu
Latest version: 1.0.8

# Image Viewer

A lightweight, zero‑dependency TypeScript image viewer: modal overlay, zoom, drag/pan, thumbnails, rotation, keyboard navigation.

<p>
  <a href="https://www.npmjs.com/package/@lujichu/image-viewer"><img src="https://img.shields.io/npm/v/@lujichu/image-viewer.svg?style=flat&color=33a" alt="npm version" /></a>
  <a href="https://www.npmjs.com/package/@lujichu/image-viewer"><img src="https://img.shields.io/npm/dm/@lujichu/image-viewer.svg?color=4a7" alt="downloads" /></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="license" /></a>
</p>

## Features
- Auto-detect images within a given DOM scope and open on click
- Zoom via buttons / mouse wheel / pinch (no need to hold Ctrl/⌘)
- Pan by mouse drag or single-finger touch drag
- Rotate left / right in 90° steps, plus reset
- Thumbnail strip with auto-centering and quick navigation
- Keyboard shortcuts: ← / → navigate, ESC close, + / − zoom, 0 reset
- Zoom range 0.25x – 8x with smooth interpolation
- Live detection of newly added images (MutationObserver)
- Optional explicit images array (skip DOM scan)
- Tiny, framework-agnostic, full TypeScript types

## Live Demo
https://jichulu.github.io/imageViewer/

![ImageViewer](image.jpg)

## Install
```bash
npm i @lujichu/image-viewer
# or
pnpm add @lujichu/image-viewer
# or
yarn add @lujichu/image-viewer
```

## Basic Usage (bundler / ESM)
```ts
import { createImageViewer } from '@lujichu/image-viewer';
// Choose ONE of the following (depending on your bundler configuration):
// If respecting the "exports" map (recommended):
import '@lujichu/image-viewer/viewer.css';
// Or direct path (works universally):
// import '@lujichu/image-viewer/dist/css/viewer.css';

createImageViewer({ scope: 'article' });
```

Providing your own image list:
```ts
createImageViewer({
  images: [
    { src: '/a.jpg', alt: 'A' },
    { src: '/b.jpg', title: 'Image B' }
  ],
  thumbnails: true
});
```

## Direct Browser (CDN / ESM) Example
```html
<link rel="stylesheet" href="https://unpkg.com/@lujichu/image-viewer/dist/css/viewer.css" />
<article>
  <img src="/demo/1.jpg" />
  <img src="/demo/2.jpg" />
</article>
<script type="module">
  import { createImageViewer } from 'https://unpkg.com/@lujichu/image-viewer/dist/js/viewer.js';
  createImageViewer({ scope: 'article' });
</script>
```

## IIFE (Global) Usage (no modules / legacy script tag)
Use the pre-bundled IIFE build which exposes a global `ImageViewer` object containing the factory function.

```html
<link rel="stylesheet" href="https://unpkg.com/@lujichu/image-viewer/dist/css/viewer.css" />
<article id="gallery">
  <img src="/demo/1.jpg" alt="One" />
  <img src="/demo/2.jpg" alt="Two" />
</article>

<!-- Load AFTER the images / or place before </body> -->
<script src="https://unpkg.com/@lujichu/image-viewer/dist/js/viewer.global.js"></script>
<script>
  // Use factory
  ImageViewer.createImageViewer({ scope: '#gallery' });
</script>
```

Notes:
- Global name: `ImageViewer`
- Available: `ImageViewer.createImageViewer` (the class itself is intentionally not exposed)
- Include the CSS file separately (not inlined)
- Call after DOM is ready (e.g. `DOMContentLoaded`) if script is in `<head>`

### Minimal inline example
```html
<link rel="stylesheet" href="https://unpkg.com/@lujichu/image-viewer/dist/css/viewer.css" />
<img src="/demo/1.jpg" />
<img src="/demo/2.jpg" />
<script src="https://unpkg.com/@lujichu/image-viewer/dist/js/viewer.global.js"></script>
<script>ImageViewer.createImageViewer();</script>
```

## Local Dev (clone repo)
```powershell
npm install
# Development (watch):
npm run dev
# Production build:
npm run build
```
Build output is in `dist/` (JS + CSS).

## API
```ts
createImageViewer(options?: ViewerOptions): ImageViewer

interface ViewerOptions {
  scope?: string | HTMLElement;                 // DOM scan scope (default: document)
  thumbnails?: boolean;                         // Show thumbnail strip (default true)
  keyboard?: boolean;                           // Enable keyboard navigation (default true)
  wheelZoom?: boolean;                          // Mouse wheel / touchpad direct zoom (default true)
  className?: string;                           // Extra class(es) on root element
  onOpen?: () => void;                          // Callback when viewer opens
  onClose?: () => void;                         // Callback when viewer closes
  images?: { src: string; alt?: string; title?: string }[]; // Provide images directly (skips DOM scan)
  filter?: (img: HTMLImageElement) => boolean;  // Filter which <img> elements are included
  minZoom?: number;                             // Minimum zoom (default 0.25)
  maxZoom?: number;                             // Maximum zoom (default 8)
}
```

### Notes
- Multiple independent instances can be created (factory is not a singleton).
- `images` array order defines navigation order when provided.
- When scanning the DOM, dynamically added/removed images are tracked automatically.

## License
MIT