react-pic-gallery 1.5.16 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,105 +1,215 @@
1
- # react-pic-gallery
2
-
3
- >
4
-
5
- [![NPM](https://img.shields.io/npm/v/react-pic-gallery.svg)](https://www.npmjs.com/package/react-pic-gallery)
6
-
7
- React library for a simple image gallery with lightbox implemented.
8
-
9
- ## Features
10
-
11
- - 📱 Responsive
12
- - 🚵 Lazy load on pictures
13
- - ✏ Buttons and CSS customization classes are accessible
14
- - 💡 Lightbox implemented with pinch zoom by [react-zoom-pan-pinch](https://www.npmjs.com/package/react-zoom-pan-pinch)
15
-
16
- ## Demo
17
-
18
- https://marcelrsoub.github.io/react-pic-gallery/
19
-
20
- ![demo gif](https://i.imgur.com/qMhra73.gif)
21
-
22
- ## Install
23
-
24
- ```bash
25
- npm install --save react-pic-gallery
26
- ```
27
-
28
- or with yarn:
29
-
30
- ```bash
31
- yarn add react-pic-gallery
32
- ```
33
-
34
- ## Usage
35
-
36
- A list of objects containing a thumbnail source and the full source is the only needed parameter.
37
-
38
- ```jsx
39
- import React from 'react'
40
- import PicGallery from 'react-pic-gallery'
41
-
42
- const listOfImages = [
43
- {
44
- thumbnailSrc: 'https://picsum.photos/id/237/200/300',
45
- fullSrc: 'https://picsum.photos/id/237/800/600'
46
- },
47
- {
48
- thumbnailSrc: 'https://picsum.photos/id/154/200/150',
49
- fullSrc: 'https://picsum.photos/id/154/200/150'
50
- }
51
- ]
52
-
53
- const App = () => {
54
- return (
55
- <div>
56
- <PicGallery imgList={listOfImages} />
57
- </div>
58
- )
59
- }
60
-
61
- export default App
62
- ```
63
-
64
- ## Options
65
-
66
- The options interface can be imported from the library and the object can be passed in the main component:
67
-
68
- ```tsx
69
- import React from 'react'
70
- import PicGallery from 'react-pic-gallery'
71
-
72
- const listOfImages = [
73
- {
74
- thumbnailSrc: 'https://picsum.photos/id/237/200/300',
75
- fullSrc: 'https://picsum.photos/id/237/800/600',
76
- description: 'A Dog standing on a wooden floor'
77
- },
78
- {
79
- thumbnailSrc: 'https://picsum.photos/id/154/200/150',
80
- fullSrc: 'https://picsum.photos/id/154/200/150'
81
- }
82
- ]
83
-
84
- const options = {
85
- // customLoadComponent: () => <h3>Loading</h3>,
86
- // hidePagination: false,
87
- // externalLightbox: true,
88
- // rowHeight: '100px',
89
- // picsPerRow:3
90
- }
91
-
92
- const App = () => {
93
- return (
94
- <div>
95
- <PicGallery imgList={listOfImages} options={options} />
96
- </div>
97
- )
98
- }
99
-
100
- export default App
101
- ```
102
-
103
- ## License
104
-
105
- MIT © [marcelrsoub](https://github.com/marcelrsoub)
1
+ # react-pic-gallery
2
+
3
+ Small, accessible React image gallery and lightbox with a polished default UI and typed escape hatches for custom controls.
4
+
5
+ [![NPM](https://img.shields.io/npm/v/react-pic-gallery.svg)](https://www.npmjs.com/package/react-pic-gallery)
6
+
7
+ [Live playground and docs](https://marcelrsoub.github.io/react-pic-gallery/)
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install react-pic-gallery
13
+ ```
14
+
15
+ ```bash
16
+ pnpm add react-pic-gallery
17
+ yarn add react-pic-gallery
18
+ bun add react-pic-gallery
19
+ ```
20
+
21
+ React 18.3+ and React 19 are supported. The [Quick start docs](https://marcelrsoub.github.io/react-pic-gallery/docs/getting-started/) provide these commands in a package-manager switcher.
22
+
23
+ The package is intentionally lightweight: it has no runtime dependencies, React is a peer dependency, and the built JavaScript and CSS together are about **5.9 KB gzipped** (4.0 KB JS + 1.9 KB CSS).
24
+
25
+ ## Why react-pic-gallery
26
+
27
+ - **Tiny by design** — no runtime dependencies, no context providers, no polyfills; ~5.9 KB gzipped total.
28
+ - **Simple by default** — one component, one stylesheet import, sensible accessible defaults.
29
+ - **Yours when needed** — typed `renderActions`, `renderCaption`, and `renderControls` callbacks let you add custom UI without rebuilding the lightbox; extra fields on your image objects flow through fully typed.
30
+ - **Accessible** — native modal `<dialog>`, focus containment and restoration, Escape to close, screen-reader announcements, `prefers-reduced-motion` support.
31
+ - **Keyboard and touch friendly** — arrow-key navigation in the grid (roving tabindex) and in the lightbox, Enter to open, swipe navigation on touch devices.
32
+ - **Themeable** — namespaced classes and CSS variables (`--gallery-accent`, `--gallery-overlay`, `--gallery-motion`, …).
33
+
34
+ ## Quick start
35
+
36
+ ```tsx
37
+ import { PicGallery } from 'react-pic-gallery'
38
+ import 'react-pic-gallery/styles.css'
39
+
40
+ const images = [
41
+ {
42
+ src: 'https://example.com/photo-large.jpg',
43
+ thumbnailSrc: 'https://example.com/photo-thumb.jpg',
44
+ alt: 'A mountain reflected in a lake',
45
+ caption: 'Morning at the lake'
46
+ }
47
+ ]
48
+
49
+ export function App() {
50
+ return <PicGallery images={images} />
51
+ }
52
+ ```
53
+
54
+ `src` and `alt` are required. `id`, `thumbnailSrc`, `caption`, `width`, and `height` are optional. Image objects can include application-specific fields; those fields remain available in renderer callbacks when using TypeScript generics.
55
+
56
+ ## Custom UI
57
+
58
+ Add actions without rebuilding the lightbox:
59
+
60
+ ```tsx
61
+ <PicGallery
62
+ images={images}
63
+ renderActions={({ image }) => (
64
+ <button type='button' onClick={() => saveImage(image)}>
65
+ Save
66
+ </button>
67
+ )}
68
+ />
69
+ ```
70
+
71
+ Every renderer receives:
72
+
73
+ ```ts
74
+ {
75
+ image,
76
+ index,
77
+ count,
78
+ close,
79
+ next,
80
+ previous,
81
+ canGoNext,
82
+ canGoPrevious
83
+ }
84
+ ```
85
+
86
+ Use `renderCaption` to replace the caption, or `renderControls` to replace the complete default control layer. When `renderControls` is provided, your controls are responsible for rendering close and navigation actions.
87
+
88
+ ## Standalone components
89
+
90
+ Use the thumbnail grid and lightbox separately when your application owns selection state:
91
+
92
+ ```tsx
93
+ import { useState } from 'react'
94
+ import { Gallery, Lightbox } from 'react-pic-gallery'
95
+
96
+ export function CustomViewer({ images }) {
97
+ const [index, setIndex] = useState<number | null>(null)
98
+
99
+ return (
100
+ <>
101
+ <Gallery images={images} onImageClick={setIndex} />
102
+ <Lightbox images={images} index={index} onIndexChange={setIndex} />
103
+ </>
104
+ )
105
+ }
106
+ ```
107
+
108
+ ## Lightbox behavior
109
+
110
+ The lightbox uses the native modal `<dialog>` element and includes:
111
+
112
+ - Keyboard navigation, Escape-to-close, focus containment, and focus restoration.
113
+ - Backdrop closing with stable page width while scrolling is locked.
114
+ - Native lazy loading for thumbnails and explicit image loading/error states.
115
+ - Horizontal swipe navigation on touch devices.
116
+ - Instagram-Stories-style edge taps on touch screens: tap the right edge of the image to go forward, the left edge to go back (navigation buttons are hidden on small screens where tap zones take over).
117
+ - Reduced-motion support, safe-area padding, rounded image surfaces, and animated transitions.
118
+
119
+ The thumbnail grid supports arrow-key navigation with a roving tabindex: Tab once to enter the grid, then move with Arrow keys (Left/Right step, Up/Down jump a row, Home/End jump to the ends), Enter to open, and focus is restored to the same tile when the lightbox closes.
120
+
121
+ Native modal behavior targets modern browsers: Chrome 37+, Edge 79+, Firefox 98+, and Safari/iOS 15.4+. The package does not ship a dialog polyfill.
122
+
123
+ ## Styling
124
+
125
+ The stylesheet uses namespaced classes and CSS variables. Import it once, then override variables globally or on the lightbox class:
126
+
127
+ ```css
128
+ :root,
129
+ .react-pic-gallery__lightbox {
130
+ --gallery-accent: #ff7a59;
131
+ --gallery-overlay: rgba(10, 10, 14, 0.98);
132
+ --gallery-control-size: 3rem;
133
+ --gallery-motion: 240ms;
134
+ }
135
+ ```
136
+
137
+ The default gallery uses three columns. Pass `columns` for a different fixed count; `rowHeight` accepts CSS height values or numeric pixels.
138
+
139
+ ## API
140
+
141
+ ### `PicGallery`
142
+
143
+ | Prop | Type | Description |
144
+ | --- | --- | --- |
145
+ | `images` | `readonly GalleryImage[]` | Images to display. |
146
+ | `columns` | `number` | Optional fixed column count. The default is three columns. |
147
+ | `rowHeight` | `CSSProperties['height']` | Thumbnail height. |
148
+ | `renderActions` | `LightboxRenderer` | Adds controls to the default toolbar. |
149
+ | `renderCaption` | `LightboxRenderer` | Replaces the current caption. |
150
+ | `renderControls` | `LightboxRenderer` | Replaces the complete default control layer. |
151
+ | `showCounter` | `boolean` | Shows the current image count. Defaults to `true`. |
152
+ | `showNavigation` | `boolean` | Shows previous/next controls. Defaults to `true`. |
153
+
154
+ `Gallery` accepts `images`, `onImageClick`, `columns`, `rowHeight`, `className`, and `style`.
155
+
156
+ `Lightbox` accepts `images`, controlled `index`, `onIndexChange`, the renderer props, `showCounter`, `showNavigation`, and `className`.
157
+
158
+ ## Migrating from v1
159
+
160
+ v2 intentionally removes the old configuration and external lightbox workaround.
161
+
162
+ | v1 | v2 |
163
+ | --- | --- |
164
+ | `imgList` | `images` |
165
+ | `fullSrc` | `src` |
166
+ | `thumbnailSrc` | `thumbnailSrc` |
167
+ | `description` | `caption` |
168
+ | default import | named `PicGallery` import (default import remains available) |
169
+ | `options.picsPerRow` | `columns` |
170
+ | `options.rowHeight` | `rowHeight` |
171
+ | `topCustomContent` / `bottomCustomContent` | `renderActions`, `renderCaption`, or `renderControls` |
172
+ | `externalLightbox` / `setExtLightboxChildren` | controlled `Lightbox` |
173
+ | `customLoadComponent` | CSS overrides or your own `Gallery` composition |
174
+ | `react-zoom-pan-pinch` | removed dependency; native lightbox pinch zoom |
175
+
176
+ Before:
177
+
178
+ ```tsx
179
+ <PicGallery
180
+ imgList={[{ fullSrc, thumbnailSrc }]}
181
+ options={{ picsPerRow: 4 }}
182
+ />
183
+ ```
184
+
185
+ After:
186
+
187
+ ```tsx
188
+ <PicGallery
189
+ images={[{ src: fullSrc, thumbnailSrc, alt: 'Description' }]}
190
+ columns={4}
191
+ />
192
+ ```
193
+
194
+ The package is ESM-only in v2. Import `styles.css` explicitly in applications that do not automatically process CSS imported by JavaScript.
195
+
196
+ ## Development
197
+
198
+ Node 22.12+ is required for the Astro documentation workflow.
199
+
200
+ ```bash
201
+ npm install
202
+ npm run dev
203
+ npm run dev:library
204
+ npm test
205
+ npm run typecheck
206
+ npm run build
207
+ npm run build:docs
208
+ npm pack --dry-run
209
+ ```
210
+
211
+ `npm run dev` starts the Astro playground and docs site. `npm run dev:library` starts the standalone Vite library demo. Publishing runs the package build automatically through `prepack`.
212
+
213
+ ## License
214
+
215
+ MIT © [marcelrsoub](https://github.com/marcelrsoub)
@@ -0,0 +1,4 @@
1
+ import { GalleryImage, GalleryProps } from './types';
2
+ declare function GalleryComponent<T extends GalleryImage>({ images, onImageClick, columns, rowHeight, className, style }: GalleryProps<T>): import('react').JSX.Element;
3
+ export declare const Gallery: typeof GalleryComponent;
4
+ export {};
@@ -0,0 +1,16 @@
1
+ import { AnimationEventHandler, CSSProperties } from 'react';
2
+ type ImageProps = {
3
+ src: string;
4
+ alt: string;
5
+ className?: string;
6
+ imageClassName?: string;
7
+ style?: CSSProperties;
8
+ imageStyle?: CSSProperties;
9
+ onAnimationEnd?: AnimationEventHandler<HTMLSpanElement>;
10
+ eager?: boolean;
11
+ objectFit?: 'cover' | 'contain';
12
+ width?: number;
13
+ height?: number;
14
+ };
15
+ export declare function Image({ src, alt, className, imageClassName, style, imageStyle, onAnimationEnd, eager, objectFit, width, height }: ImageProps): import('react').JSX.Element;
16
+ export {};
@@ -0,0 +1,2 @@
1
+ import { GalleryImage, LightboxProps } from './types';
2
+ export declare function Lightbox<T extends GalleryImage>({ images, index, onIndexChange, renderActions, renderCaption, renderControls, showCounter, showNavigation, className }: LightboxProps<T>): import('react').ReactPortal | null;
@@ -0,0 +1,2 @@
1
+ import { GalleryImage, PicGalleryProps } from './types';
2
+ export declare function PicGallery<T extends GalleryImage>({ images, columns, rowHeight, className, galleryClassName, style, renderActions, renderCaption, renderControls, showCounter, showNavigation }: PicGalleryProps<T>): import('react').JSX.Element;
@@ -0,0 +1,5 @@
1
+ export { Gallery } from './Gallery';
2
+ export { Lightbox } from './Lightbox';
3
+ export { PicGallery } from './PicGallery';
4
+ export type { GalleryImage, GalleryProps, LightboxContext, LightboxProps, LightboxRenderer, PicGalleryProps } from './types';
5
+ export { PicGallery as default } from './PicGallery';