react-pic-gallery 2.0.0 → 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 +13 -2
- package/dist/react-pic-gallery.js +171 -208
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,16 @@ bun add react-pic-gallery
|
|
|
20
20
|
|
|
21
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
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
|
|
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`, …).
|
|
24
33
|
|
|
25
34
|
## Quick start
|
|
26
35
|
|
|
@@ -104,9 +113,11 @@ The lightbox uses the native modal `<dialog>` element and includes:
|
|
|
104
113
|
- Backdrop closing with stable page width while scrolling is locked.
|
|
105
114
|
- Native lazy loading for thumbnails and explicit image loading/error states.
|
|
106
115
|
- Horizontal swipe navigation on touch devices.
|
|
107
|
-
-
|
|
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).
|
|
108
117
|
- Reduced-motion support, safe-area padding, rounded image surfaces, and animated transitions.
|
|
109
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
|
+
|
|
110
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.
|
|
111
122
|
|
|
112
123
|
## Styling
|
|
@@ -45,21 +45,49 @@ function l({ src: e, alt: t, className: r = "", imageClassName: c = "", style: l
|
|
|
45
45
|
}
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region src/lib/Gallery.tsx
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
var u = 3;
|
|
49
|
+
function d({ images: e, onImageClick: n, columns: r, rowHeight: s, className: c = "", style: d }) {
|
|
50
|
+
let f = i([]), [p, m] = a(0), h = r && r > 0 ? r : u, g = e.length - 1, _ = Math.min(p, Math.max(g, 0)), v = t((e) => {
|
|
51
|
+
m(e), f.current[e]?.focus();
|
|
52
|
+
}, []), y = t((e, t) => {
|
|
53
|
+
let n = {
|
|
54
|
+
ArrowRight: 1,
|
|
55
|
+
ArrowLeft: -1,
|
|
56
|
+
ArrowDown: h,
|
|
57
|
+
ArrowUp: -h
|
|
58
|
+
}[e.key], r = null;
|
|
59
|
+
if (n !== void 0) {
|
|
60
|
+
let e = t + n;
|
|
61
|
+
e >= 0 && e <= g && (r = e);
|
|
62
|
+
} else if (e.key === "Home") r = 0;
|
|
63
|
+
else if (e.key === "End") r = g;
|
|
64
|
+
else return;
|
|
65
|
+
r !== null && r !== t && (e.preventDefault(), v(r));
|
|
66
|
+
}, [
|
|
67
|
+
h,
|
|
68
|
+
g,
|
|
69
|
+
v
|
|
70
|
+
]), b = typeof s == "number" ? `${s}px` : s, x = {
|
|
71
|
+
...d,
|
|
72
|
+
...r ? { gridTemplateColumns: `repeat(${r}, minmax(0, 1fr))` } : {},
|
|
73
|
+
...b ? { "--gallery-row-height": b } : {}
|
|
53
74
|
};
|
|
54
75
|
return /* @__PURE__ */ o("div", {
|
|
55
|
-
className: `react-pic-gallery__grid ${
|
|
56
|
-
style:
|
|
76
|
+
className: `react-pic-gallery__grid ${c}`.trim(),
|
|
77
|
+
style: x,
|
|
57
78
|
"data-testid": "react-pic-gallery-grid",
|
|
58
|
-
children: e.map((e,
|
|
79
|
+
children: e.map((e, t) => /* @__PURE__ */ o("button", {
|
|
59
80
|
className: "react-pic-gallery__tile",
|
|
60
81
|
type: "button",
|
|
61
|
-
disabled: !
|
|
62
|
-
|
|
82
|
+
disabled: !n,
|
|
83
|
+
tabIndex: t === _ ? 0 : -1,
|
|
84
|
+
ref: (e) => {
|
|
85
|
+
f.current[t] = e;
|
|
86
|
+
},
|
|
87
|
+
onKeyDown: (e) => y(e, t),
|
|
88
|
+
onClick: () => {
|
|
89
|
+
m(t), n?.(t);
|
|
90
|
+
},
|
|
63
91
|
"aria-label": `Open ${e.alt}`,
|
|
64
92
|
children: /* @__PURE__ */ o(l, {
|
|
65
93
|
src: e.thumbnailSrc ?? e.src,
|
|
@@ -68,40 +96,37 @@ function u({ images: e, onImageClick: t, columns: n, rowHeight: r, className: i
|
|
|
68
96
|
width: e.width,
|
|
69
97
|
height: e.height
|
|
70
98
|
})
|
|
71
|
-
}, e.id ?? `${e.src}-${
|
|
99
|
+
}, e.id ?? `${e.src}-${t}`))
|
|
72
100
|
});
|
|
73
101
|
}
|
|
74
|
-
var
|
|
75
|
-
function
|
|
76
|
-
return e instanceof Element && e.closest(
|
|
77
|
-
}
|
|
78
|
-
function v(e, t, n) {
|
|
79
|
-
return Math.min(Math.max(e, t), n);
|
|
102
|
+
var f = e(d), p = /* @__PURE__ */ new Set(), m = null, h = "a[href], button, input, select, textarea, [role=\"combobox\"], [role=\"menu\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"tab\"]", g = "input, select, textarea, [role=\"combobox\"], [role=\"menu\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"tab\"]", _ = "(max-width: 600px), (pointer: coarse)", v = .3;
|
|
103
|
+
function y(e) {
|
|
104
|
+
return e instanceof Element && e.closest(h) !== null;
|
|
80
105
|
}
|
|
81
|
-
function
|
|
82
|
-
if (!
|
|
83
|
-
if (
|
|
106
|
+
function b(e) {
|
|
107
|
+
if (!p.has(e)) {
|
|
108
|
+
if (p.size === 0) {
|
|
84
109
|
let e = document.body, t = window.innerWidth - document.documentElement.clientWidth, n = Number.parseFloat(window.getComputedStyle(e).paddingRight) || 0;
|
|
85
|
-
|
|
110
|
+
m = {
|
|
86
111
|
overflow: e.style.overflow,
|
|
87
112
|
paddingRight: e.style.paddingRight
|
|
88
113
|
}, e.style.overflow = "hidden", t > 0 && (e.style.paddingRight = `${n + t}px`);
|
|
89
114
|
}
|
|
90
|
-
|
|
115
|
+
p.add(e);
|
|
91
116
|
}
|
|
92
117
|
}
|
|
93
|
-
function
|
|
94
|
-
return
|
|
118
|
+
function x(e) {
|
|
119
|
+
return p.delete(e), p.size > 0 || !m ? !1 : (document.body.style.overflow = m.overflow, document.body.style.paddingRight = m.paddingRight, m = null, !0);
|
|
95
120
|
}
|
|
96
|
-
function
|
|
121
|
+
function S(e) {
|
|
97
122
|
let t = e.trim();
|
|
98
123
|
return t.endsWith("ms") ? Number.parseFloat(t) : t.endsWith("s") ? Number.parseFloat(t) * 1e3 : 0;
|
|
99
124
|
}
|
|
100
|
-
function
|
|
125
|
+
function ee(e) {
|
|
101
126
|
let t = window.getComputedStyle(e), n = t.animationDuration.split(","), r = t.animationDelay.split(",");
|
|
102
|
-
return Math.max(...n.map((e, t) =>
|
|
127
|
+
return Math.max(...n.map((e, t) => S(e) + S(r[t % r.length] ?? "0s")), 0);
|
|
103
128
|
}
|
|
104
|
-
function
|
|
129
|
+
function C() {
|
|
105
130
|
return /* @__PURE__ */ o("svg", {
|
|
106
131
|
viewBox: "0 0 24 24",
|
|
107
132
|
"aria-hidden": "true",
|
|
@@ -109,7 +134,7 @@ function re() {
|
|
|
109
134
|
children: /* @__PURE__ */ o("path", { d: "M6 6l12 12M18 6L6 18" })
|
|
110
135
|
});
|
|
111
136
|
}
|
|
112
|
-
function
|
|
137
|
+
function w({ direction: e }) {
|
|
113
138
|
return /* @__PURE__ */ o("svg", {
|
|
114
139
|
viewBox: "0 0 24 24",
|
|
115
140
|
"aria-hidden": "true",
|
|
@@ -117,171 +142,113 @@ function b({ direction: e }) {
|
|
|
117
142
|
children: /* @__PURE__ */ o("path", { d: e === "left" ? "M14.5 5l-7 7 7 7" : "M9.5 5l7 7-7 7" })
|
|
118
143
|
});
|
|
119
144
|
}
|
|
120
|
-
function
|
|
145
|
+
function T(...e) {
|
|
121
146
|
return e.filter(Boolean).join(" ");
|
|
122
147
|
}
|
|
123
|
-
function
|
|
124
|
-
let
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}, []), Y = t(() => {
|
|
132
|
-
let e = O.current;
|
|
133
|
-
if (e !== null && D.current === null) {
|
|
148
|
+
function E({ images: e, index: u, onIndexChange: d, renderActions: f, renderCaption: p, renderControls: m, showCounter: h = !0, showNavigation: S = !0, className: E }) {
|
|
149
|
+
let D = i(null), O = i(d), k = i(null), A = i(null), j = i(null), M = i(!1), N = i(!1), P = i({}), F = i(e), I = i(null), L = r(), [R, z] = a(!1), [B, V] = a(null), H = u !== null && u >= 0 && u < e.length ? u : null, U = H === null ? void 0 : e[H];
|
|
150
|
+
O.current = d, j.current = H, M.current = R, F.current = e;
|
|
151
|
+
let W = t(() => {
|
|
152
|
+
k.current !== null && (window.clearTimeout(k.current), k.current = null), A.current = null;
|
|
153
|
+
}, []), G = t(() => {
|
|
154
|
+
let e = j.current;
|
|
155
|
+
if (e !== null && A.current === null) {
|
|
134
156
|
if (typeof window < "u" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
|
135
|
-
|
|
157
|
+
O.current(null);
|
|
136
158
|
return;
|
|
137
159
|
}
|
|
138
|
-
|
|
160
|
+
A.current = { index: e }, M.current = !0, z(!0);
|
|
139
161
|
}
|
|
140
|
-
}, []),
|
|
141
|
-
let e =
|
|
142
|
-
!
|
|
143
|
-
}, []),
|
|
144
|
-
let e =
|
|
145
|
-
!
|
|
146
|
-
}, []),
|
|
147
|
-
let e =
|
|
148
|
-
|
|
149
|
-
}, []),
|
|
150
|
-
let e =
|
|
151
|
-
|
|
152
|
-
}, []),
|
|
153
|
-
e.preventDefault(),
|
|
154
|
-
}, [
|
|
155
|
-
let e =
|
|
162
|
+
}, []), K = t(() => {
|
|
163
|
+
let e = j.current;
|
|
164
|
+
!M.current && e !== null && e > 0 && O.current(e - 1);
|
|
165
|
+
}, []), q = t(() => {
|
|
166
|
+
let e = j.current;
|
|
167
|
+
!M.current && e !== null && e < F.current.length - 1 && O.current(e + 1);
|
|
168
|
+
}, []), J = t(() => {
|
|
169
|
+
let e = j.current;
|
|
170
|
+
M.current || e === null || e === 0 || (V("previous"), O.current(e - 1));
|
|
171
|
+
}, []), Y = t(() => {
|
|
172
|
+
let e = j.current;
|
|
173
|
+
M.current || e === null || e >= F.current.length - 1 || (V("next"), O.current(e + 1));
|
|
174
|
+
}, []), te = t((e) => {
|
|
175
|
+
e.preventDefault(), G();
|
|
176
|
+
}, [G]), X = t(() => {
|
|
177
|
+
let e = A.current;
|
|
156
178
|
if (e) {
|
|
157
|
-
if (
|
|
158
|
-
|
|
179
|
+
if (j.current !== e.index) {
|
|
180
|
+
W(), M.current = !1, z(!1);
|
|
159
181
|
return;
|
|
160
182
|
}
|
|
161
|
-
|
|
183
|
+
W(), M.current = !1, z(!1), O.current(null);
|
|
162
184
|
}
|
|
163
|
-
}, [
|
|
185
|
+
}, [W]), ne = t((e) => {
|
|
164
186
|
if (e.defaultPrevented) return;
|
|
165
187
|
let t = e.target;
|
|
166
|
-
t instanceof HTMLElement && (t.isContentEditable || t.closest(
|
|
167
|
-
}, [
|
|
168
|
-
if (
|
|
169
|
-
|
|
188
|
+
t instanceof HTMLElement && (t.isContentEditable || t.closest(g)) || (e.key === "ArrowLeft" ? (e.preventDefault(), K()) : e.key === "ArrowRight" && (e.preventDefault(), q()));
|
|
189
|
+
}, [q, K]), re = t((e) => {
|
|
190
|
+
if (e.touches.length !== 1 || y(e.target)) {
|
|
191
|
+
I.current = null;
|
|
170
192
|
return;
|
|
171
193
|
}
|
|
172
194
|
let t = e.touches[0];
|
|
173
|
-
|
|
195
|
+
I.current = {
|
|
174
196
|
x: t.clientX,
|
|
175
197
|
y: t.clientY
|
|
176
198
|
};
|
|
177
|
-
}, [
|
|
178
|
-
let t =
|
|
179
|
-
if (
|
|
199
|
+
}, []), ie = t((e) => {
|
|
200
|
+
let t = I.current;
|
|
201
|
+
if (I.current = null, !t || e.changedTouches.length === 0) return;
|
|
180
202
|
let n = e.changedTouches[0], r = n.clientX - t.x, i = n.clientY - t.y, a = Math.abs(r);
|
|
181
|
-
a < 48 || a <= Math.abs(i) || (r < 0 ?
|
|
182
|
-
}, [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
H
|
|
186
|
-
]), pe = t(() => {
|
|
187
|
-
N.current = null;
|
|
188
|
-
}, []), me = t((e) => {
|
|
189
|
-
if (!(e.target instanceof Element) || e.target.closest(h) === null || e.pointerType === "mouse" && e.button !== 0) return;
|
|
190
|
-
let t = P.current;
|
|
191
|
-
if (t.set(e.pointerId, {
|
|
192
|
-
x: e.clientX,
|
|
193
|
-
y: e.clientY
|
|
194
|
-
}), e.currentTarget.setPointerCapture?.(e.pointerId), t.size === 2) {
|
|
195
|
-
let [n, r] = [...t.values()], i = Math.hypot(r.x - n.x, r.y - n.y), a = e.currentTarget.querySelector(h)?.getBoundingClientRect(), o = (n.x + r.x) / 2, s = (n.y + r.y) / 2;
|
|
196
|
-
a && a.width > 0 && a.height > 0 && oe(`${v((o - a.left) / a.width * 100, 0, 100)}% ${v((s - a.top) / a.height * 100, 0, 100)}%`), F.current = {
|
|
197
|
-
distance: Math.max(i, 1),
|
|
198
|
-
scale: H,
|
|
199
|
-
offset: W
|
|
200
|
-
}, I.current = null;
|
|
201
|
-
} else H > 1 && (I.current = {
|
|
202
|
-
x: e.clientX,
|
|
203
|
-
y: e.clientY,
|
|
204
|
-
offset: W
|
|
205
|
-
});
|
|
206
|
-
}, [W, H]), he = t((e) => {
|
|
207
|
-
let t = P.current;
|
|
208
|
-
if (t.has(e.pointerId)) {
|
|
209
|
-
if (t.set(e.pointerId, {
|
|
210
|
-
x: e.clientX,
|
|
211
|
-
y: e.clientY
|
|
212
|
-
}), t.size >= 2 && F.current) {
|
|
213
|
-
let [n, r] = [...t.values()], i = Math.max(Math.hypot(r.x - n.x, r.y - n.y), 1), a = v(F.current.scale * (i / F.current.distance), 1, g);
|
|
214
|
-
U(a), G(F.current.offset), e.preventDefault();
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
if (t.size === 1 && I.current && H > 1) {
|
|
218
|
-
let t = e.currentTarget.querySelector(h), n = t?.clientWidth ?? 0, r = t?.clientHeight ?? 0, i = Math.max(0, n * (H - 1) / 2), a = Math.max(0, r * (H - 1) / 2), o = I.current.offset.x + e.clientX - I.current.x, s = I.current.offset.y + e.clientY - I.current.y;
|
|
219
|
-
G({
|
|
220
|
-
x: v(o, -i, i),
|
|
221
|
-
y: v(s, -a, a)
|
|
222
|
-
}), e.preventDefault();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}, [H]), ge = t((e) => {
|
|
226
|
-
if (P.current.delete(e.pointerId), e.currentTarget.hasPointerCapture?.(e.pointerId) && e.currentTarget.releasePointerCapture(e.pointerId), P.current.size < 2 && (F.current = null), P.current.size === 1 && H > 1) {
|
|
227
|
-
let [e] = [...P.current.values()];
|
|
228
|
-
I.current = {
|
|
229
|
-
x: e.x,
|
|
230
|
-
y: e.y,
|
|
231
|
-
offset: W
|
|
232
|
-
};
|
|
233
|
-
} else I.current = null;
|
|
234
|
-
}, [W, H]), _e = t((e) => {
|
|
203
|
+
a < 48 || a <= Math.abs(i) || (r < 0 ? Y() : J());
|
|
204
|
+
}, [Y, J]), ae = t(() => {
|
|
205
|
+
I.current = null;
|
|
206
|
+
}, []), oe = t((e) => {
|
|
235
207
|
e.target === e.currentTarget && V(null);
|
|
236
|
-
}, []),
|
|
237
|
-
e.target === e.currentTarget && e.animationName === "react-pic-gallery-fade-out" &&
|
|
238
|
-
}, [
|
|
239
|
-
|
|
240
|
-
}, [
|
|
208
|
+
}, []), se = t((e) => {
|
|
209
|
+
e.target === e.currentTarget && e.animationName === "react-pic-gallery-fade-out" && X();
|
|
210
|
+
}, [X]), ce = t(() => {
|
|
211
|
+
N.current || (W(), M.current = !1, z(!1), j.current !== null && O.current(null));
|
|
212
|
+
}, [W]);
|
|
241
213
|
if (n(() => {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}, [K, J]), n(() => {
|
|
250
|
-
if (!R || !D.current || !w.current) return;
|
|
251
|
-
let e = ne(w.current);
|
|
252
|
-
return E.current = window.setTimeout(Q, e), () => {
|
|
253
|
-
E.current !== null && (window.clearTimeout(E.current), E.current = null);
|
|
214
|
+
let e = A.current;
|
|
215
|
+
e && H !== e.index && (W(), M.current = !1, z(!1));
|
|
216
|
+
}, [H, W]), n(() => {
|
|
217
|
+
if (!R || !A.current || !D.current) return;
|
|
218
|
+
let e = ee(D.current);
|
|
219
|
+
return k.current = window.setTimeout(X, e), () => {
|
|
220
|
+
k.current !== null && (window.clearTimeout(k.current), k.current = null);
|
|
254
221
|
};
|
|
255
|
-
}, [
|
|
256
|
-
if (
|
|
257
|
-
let e =
|
|
222
|
+
}, [X, R]), n(() => {
|
|
223
|
+
if (H === null) return;
|
|
224
|
+
let e = D.current;
|
|
258
225
|
if (!e) return;
|
|
259
226
|
let t = document.activeElement;
|
|
260
|
-
return
|
|
261
|
-
|
|
227
|
+
return b(P.current), e.open || e.showModal(), () => {
|
|
228
|
+
W(), N.current = !0, e.open && e.close(), N.current = !1, x(P.current) && t?.isConnected && t.focus();
|
|
262
229
|
};
|
|
263
|
-
}, [
|
|
264
|
-
let
|
|
265
|
-
image:
|
|
266
|
-
index:
|
|
230
|
+
}, [H !== null, W]), H === null || !U || typeof document > "u") return null;
|
|
231
|
+
let Z = {
|
|
232
|
+
image: U,
|
|
233
|
+
index: H,
|
|
267
234
|
count: e.length,
|
|
268
|
-
close:
|
|
269
|
-
next:
|
|
270
|
-
previous:
|
|
271
|
-
canGoNext:
|
|
272
|
-
canGoPrevious:
|
|
273
|
-
},
|
|
274
|
-
e.target === e.currentTarget &&
|
|
235
|
+
close: G,
|
|
236
|
+
next: q,
|
|
237
|
+
previous: K,
|
|
238
|
+
canGoNext: H < e.length - 1,
|
|
239
|
+
canGoPrevious: H > 0
|
|
240
|
+
}, le = S && !m && Z.canGoPrevious, ue = S && !m && Z.canGoNext, Q = S && !m && e.length > 1, $ = (e) => {
|
|
241
|
+
e.target === e.currentTarget && G();
|
|
275
242
|
};
|
|
276
243
|
return c(/* @__PURE__ */ s("dialog", {
|
|
277
|
-
ref:
|
|
278
|
-
className:
|
|
244
|
+
ref: D,
|
|
245
|
+
className: T("react-pic-gallery__lightbox", R ? "react-pic-gallery__lightbox--closing" : void 0, E),
|
|
279
246
|
"aria-labelledby": L,
|
|
280
|
-
onAnimationEnd:
|
|
281
|
-
onClose:
|
|
282
|
-
onMouseDown:
|
|
283
|
-
onCancel:
|
|
284
|
-
onKeyDown:
|
|
247
|
+
onAnimationEnd: se,
|
|
248
|
+
onClose: ce,
|
|
249
|
+
onMouseDown: $,
|
|
250
|
+
onCancel: te,
|
|
251
|
+
onKeyDown: ne,
|
|
285
252
|
children: [
|
|
286
253
|
/* @__PURE__ */ o("h2", {
|
|
287
254
|
className: "react-pic-gallery__sr-only",
|
|
@@ -292,9 +259,9 @@ function S({ images: e, index: u, onIndexChange: d, renderActions: f, renderCapt
|
|
|
292
259
|
className: "react-pic-gallery__sr-only",
|
|
293
260
|
"aria-live": "polite",
|
|
294
261
|
children: [
|
|
295
|
-
|
|
262
|
+
U.alt,
|
|
296
263
|
", image ",
|
|
297
|
-
|
|
264
|
+
H + 1,
|
|
298
265
|
" of ",
|
|
299
266
|
e.length
|
|
300
267
|
]
|
|
@@ -302,74 +269,70 @@ function S({ images: e, index: u, onIndexChange: d, renderActions: f, renderCapt
|
|
|
302
269
|
/* @__PURE__ */ s("div", {
|
|
303
270
|
className: "react-pic-gallery__lightbox-content",
|
|
304
271
|
children: [
|
|
305
|
-
|
|
272
|
+
m ? /* @__PURE__ */ o("div", {
|
|
306
273
|
className: "react-pic-gallery__custom-controls",
|
|
307
|
-
children:
|
|
274
|
+
children: m(Z)
|
|
308
275
|
}) : /* @__PURE__ */ s("div", {
|
|
309
276
|
className: "react-pic-gallery__toolbar",
|
|
310
277
|
children: [/* @__PURE__ */ s("div", {
|
|
311
278
|
className: "react-pic-gallery__toolbar-actions",
|
|
312
|
-
children: [
|
|
279
|
+
children: [h && /* @__PURE__ */ s("span", {
|
|
313
280
|
"aria-live": "polite",
|
|
314
281
|
children: [
|
|
315
|
-
|
|
282
|
+
H + 1,
|
|
316
283
|
" / ",
|
|
317
284
|
e.length
|
|
318
285
|
]
|
|
319
|
-
}), f?.(
|
|
286
|
+
}), f?.(Z)]
|
|
320
287
|
}), /* @__PURE__ */ o("button", {
|
|
321
288
|
className: "react-pic-gallery__control",
|
|
322
289
|
type: "button",
|
|
323
|
-
onClick:
|
|
290
|
+
onClick: G,
|
|
324
291
|
"aria-label": "Close image viewer",
|
|
325
|
-
children: /* @__PURE__ */ o(
|
|
292
|
+
children: /* @__PURE__ */ o(C, {})
|
|
326
293
|
})]
|
|
327
294
|
}),
|
|
328
295
|
/* @__PURE__ */ s("div", {
|
|
329
|
-
className:
|
|
330
|
-
onMouseDown:
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
296
|
+
className: T("react-pic-gallery__viewport", Q ? "react-pic-gallery__viewport--has-navigation" : void 0),
|
|
297
|
+
onMouseDown: $,
|
|
298
|
+
onClick: (e) => {
|
|
299
|
+
if (!Q || M.current || !(e.target instanceof Element) || e.target.closest("button") || window.matchMedia?.(_)?.matches !== !0) return;
|
|
300
|
+
let t = e.currentTarget.getBoundingClientRect();
|
|
301
|
+
if (t.width <= 0) return;
|
|
302
|
+
let n = (e.clientX - t.left) / t.width;
|
|
303
|
+
n < v ? K() : n > .7 && q();
|
|
304
|
+
},
|
|
305
|
+
onTouchCancel: ae,
|
|
306
|
+
onTouchEnd: ie,
|
|
307
|
+
onTouchStart: re,
|
|
338
308
|
children: [
|
|
339
|
-
|
|
309
|
+
le && /* @__PURE__ */ o("button", {
|
|
340
310
|
className: "react-pic-gallery__control react-pic-gallery__control--previous",
|
|
341
311
|
type: "button",
|
|
342
|
-
onClick:
|
|
312
|
+
onClick: K,
|
|
343
313
|
"aria-label": "Previous image",
|
|
344
|
-
children: /* @__PURE__ */ o(
|
|
314
|
+
children: /* @__PURE__ */ o(w, { direction: "left" })
|
|
345
315
|
}),
|
|
346
316
|
/* @__PURE__ */ o(l, {
|
|
347
|
-
src:
|
|
348
|
-
alt:
|
|
317
|
+
src: U.src,
|
|
318
|
+
alt: U.alt,
|
|
349
319
|
eager: !0,
|
|
350
320
|
objectFit: "contain",
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
transform: `translate3d(${W.x}px, ${W.y}px, 0) scale(${H})`,
|
|
356
|
-
transformOrigin: ae,
|
|
357
|
-
transition: P.current.size > 0 ? "none" : void 0
|
|
358
|
-
},
|
|
359
|
-
onAnimationEnd: _e
|
|
360
|
-
}, q.src),
|
|
361
|
-
xe && /* @__PURE__ */ o("button", {
|
|
321
|
+
className: T("react-pic-gallery__lightbox-image", B ? `react-pic-gallery__lightbox-image--swipe-${B}` : void 0),
|
|
322
|
+
onAnimationEnd: oe
|
|
323
|
+
}, U.src),
|
|
324
|
+
ue && /* @__PURE__ */ o("button", {
|
|
362
325
|
className: "react-pic-gallery__control react-pic-gallery__control--next",
|
|
363
326
|
type: "button",
|
|
364
|
-
onClick:
|
|
327
|
+
onClick: q,
|
|
365
328
|
"aria-label": "Next image",
|
|
366
|
-
children: /* @__PURE__ */ o(
|
|
329
|
+
children: /* @__PURE__ */ o(w, { direction: "right" })
|
|
367
330
|
})
|
|
368
331
|
]
|
|
369
332
|
}),
|
|
370
|
-
(p ||
|
|
333
|
+
(p || U.caption) && /* @__PURE__ */ o("div", {
|
|
371
334
|
className: "react-pic-gallery__caption",
|
|
372
|
-
children: p ? p(
|
|
335
|
+
children: p ? p(Z) : U.caption
|
|
373
336
|
})
|
|
374
337
|
]
|
|
375
338
|
})
|
|
@@ -378,28 +341,28 @@ function S({ images: e, index: u, onIndexChange: d, renderActions: f, renderCapt
|
|
|
378
341
|
}
|
|
379
342
|
//#endregion
|
|
380
343
|
//#region src/lib/PicGallery.tsx
|
|
381
|
-
function
|
|
344
|
+
function D({ images: e, columns: t, rowHeight: n, className: r, galleryClassName: i, style: c, renderActions: l, renderCaption: u, renderControls: d, showCounter: p, showNavigation: m }) {
|
|
382
345
|
let [h, g] = a(null);
|
|
383
346
|
return /* @__PURE__ */ s("div", {
|
|
384
347
|
className: `react-pic-gallery ${r ?? ""}`.trim(),
|
|
385
348
|
style: c,
|
|
386
|
-
children: [/* @__PURE__ */ o(
|
|
349
|
+
children: [/* @__PURE__ */ o(f, {
|
|
387
350
|
images: e,
|
|
388
351
|
columns: t,
|
|
389
352
|
rowHeight: n,
|
|
390
353
|
className: i,
|
|
391
354
|
onImageClick: g
|
|
392
|
-
}), /* @__PURE__ */ o(
|
|
355
|
+
}), /* @__PURE__ */ o(E, {
|
|
393
356
|
images: e,
|
|
394
357
|
index: h,
|
|
395
358
|
onIndexChange: g,
|
|
396
359
|
renderActions: l,
|
|
397
360
|
renderCaption: u,
|
|
398
|
-
renderControls:
|
|
361
|
+
renderControls: d,
|
|
399
362
|
showCounter: p,
|
|
400
363
|
showNavigation: m
|
|
401
364
|
})]
|
|
402
365
|
});
|
|
403
366
|
}
|
|
404
367
|
//#endregion
|
|
405
|
-
export {
|
|
368
|
+
export { f as Gallery, E as Lightbox, D as PicGallery, D as default };
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
:where(.react-pic-gallery,.react-pic-gallery__lightbox){--gallery-gap:.75rem;--gallery-radius:1rem;--gallery-row-height:12rem;--gallery-accent:#9ef01a;--gallery-overlay:#070b10f0;--gallery-control-size:2.75rem;--gallery-motion:.18s;color:#f8fafc}.react-pic-gallery{width:100%;min-width:0}.react-pic-gallery__grid{gap:var(--gallery-gap);grid-template-columns:repeat(3,minmax(0,1fr));width:100%;display:grid}.react-pic-gallery__tile{min-width:0;height:var(--gallery-row-height);cursor:pointer;border-radius:var(--gallery-radius);isolation:isolate;background:#e2e8f0;border:0;padding:0;position:relative;overflow:hidden}.react-pic-gallery__tile:after{content:"";pointer-events:none;border-radius:inherit;transition:border-color var(--gallery-motion) ease;border:2px solid #0000;position:absolute;inset:0}.react-pic-gallery__tile:hover .react-pic-gallery__image-element,.react-pic-gallery__tile:focus-visible .react-pic-gallery__image-element{transform:scale(1.04)}.react-pic-gallery__tile:focus-visible{outline:3px solid var(--gallery-accent);outline-offset:3px}.react-pic-gallery__tile:focus-visible:after{border-color:var(--gallery-accent)}.react-pic-gallery__tile:disabled{cursor:default}.react-pic-gallery__image{background:linear-gradient(135deg,#e2e8f0,#cbd5e1);width:100%;height:100%;display:block;position:relative;overflow:hidden}.react-pic-gallery__image-element{width:100%;height:100%;transition:transform var(--gallery-motion) ease, opacity var(--gallery-motion) ease;display:block}.react-pic-gallery__image-loader,.react-pic-gallery__image-error{place-items:center;display:grid;position:absolute;inset:0}.react-pic-gallery__image-loader:after{content:"";border:2px solid #0f172a29;border-top-color:var(--gallery-accent);border-radius:50%;width:1.5rem;height:1.5rem;animation:.7s linear infinite react-pic-gallery-spin}.react-pic-gallery__image-error{color:#475569;text-align:center;background:#e2e8f0e6;padding:1rem;font-size:.875rem}:where(dialog.react-pic-gallery__lightbox){z-index:1000;box-sizing:border-box;width:100%;max-width:none;height:
|
|
1
|
+
:where(.react-pic-gallery,.react-pic-gallery__lightbox){--gallery-gap:.75rem;--gallery-radius:1rem;--gallery-row-height:12rem;--gallery-accent:#9ef01a;--gallery-overlay:#070b10f0;--gallery-control-size:2.75rem;--gallery-motion:.18s;color:#f8fafc}.react-pic-gallery{width:100%;min-width:0}.react-pic-gallery__grid{gap:var(--gallery-gap);grid-template-columns:repeat(3,minmax(0,1fr));width:100%;display:grid}.react-pic-gallery__tile{min-width:0;height:var(--gallery-row-height);cursor:pointer;border-radius:var(--gallery-radius);isolation:isolate;background:#e2e8f0;border:0;padding:0;position:relative;overflow:hidden}.react-pic-gallery__tile:after{content:"";pointer-events:none;border-radius:inherit;transition:border-color var(--gallery-motion) ease;border:2px solid #0000;position:absolute;inset:0}.react-pic-gallery__tile:hover .react-pic-gallery__image-element,.react-pic-gallery__tile:focus-visible .react-pic-gallery__image-element{transform:scale(1.04)}.react-pic-gallery__tile:focus-visible{outline:3px solid var(--gallery-accent);outline-offset:3px}.react-pic-gallery__tile:focus-visible:after{border-color:var(--gallery-accent)}.react-pic-gallery__tile:disabled{cursor:default}.react-pic-gallery__image{background:linear-gradient(135deg,#e2e8f0,#cbd5e1);width:100%;height:100%;display:block;position:relative;overflow:hidden}.react-pic-gallery__image-element{width:100%;height:100%;transition:transform var(--gallery-motion) ease, opacity var(--gallery-motion) ease;display:block}.react-pic-gallery__image-loader,.react-pic-gallery__image-error{place-items:center;display:grid;position:absolute;inset:0}.react-pic-gallery__image-loader:after{content:"";border:2px solid #0f172a29;border-top-color:var(--gallery-accent);border-radius:50%;width:1.5rem;height:1.5rem;animation:.7s linear infinite react-pic-gallery-spin}.react-pic-gallery__image-error{color:#475569;text-align:center;background:#e2e8f0e6;padding:1rem;font-size:.875rem}:where(dialog.react-pic-gallery__lightbox){z-index:1000;box-sizing:border-box;width:100%;max-width:none;height:100dvh;max-height:none;padding:max(1rem, env(safe-area-inset-top)) max(1rem, env(safe-area-inset-right)) max(1rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));color:#f8fafc;background:var(--gallery-overlay);animation:react-pic-gallery-fade-in var(--gallery-motion) ease both;border:0;place-items:center;margin:0;display:grid;position:fixed;inset:0;overflow:hidden}dialog.react-pic-gallery__lightbox:not([open]){display:none}dialog.react-pic-gallery__lightbox::backdrop{background:0 0}.react-pic-gallery__lightbox--closing{animation:react-pic-gallery-fade-out var(--gallery-motion) ease both}.react-pic-gallery__lightbox-content{box-sizing:border-box;width:min(90rem,100vw - 2rem);min-width:0;max-width:100%;height:min(54rem,100dvh - 2rem);min-height:0;max-height:100%;animation:react-pic-gallery-rise-in var(--gallery-motion) ease both;flex-direction:column;display:flex}.react-pic-gallery__lightbox--closing .react-pic-gallery__lightbox-content{animation:react-pic-gallery-rise-out var(--gallery-motion) ease both}.react-pic-gallery__toolbar,.react-pic-gallery__custom-controls{flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:1rem;min-height:3.5rem;display:flex}.react-pic-gallery__toolbar-actions{color:#cbd5e1;align-items:center;gap:.75rem;min-width:0;font-size:.875rem;display:flex}.react-pic-gallery__control{width:var(--gallery-control-size);height:var(--gallery-control-size);color:#f8fafc;cursor:pointer;transition:background var(--gallery-motion) ease, color var(--gallery-motion) ease, transform var(--gallery-motion) ease;background:0 0;border:0;border-radius:.7rem;flex:none;place-items:center;padding:0;font-size:1.4rem;line-height:1;display:inline-grid}.react-pic-gallery__control:hover{background:#f8fafc24}.react-pic-gallery__control:focus-visible{outline:3px solid var(--gallery-accent);outline-offset:3px}.react-pic-gallery__control svg{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.8px;width:1.25rem;height:1.25rem}.react-pic-gallery__viewport{touch-action:pan-y pinch-zoom;flex:1 1 0;place-items:center;min-width:0;min-height:0;padding:.75rem;display:grid;position:relative;overflow:hidden}.react-pic-gallery__viewport--has-navigation{padding-inline:3.5rem}.react-pic-gallery__viewport--has-navigation .react-pic-gallery__lightbox-image{inset-inline:3.5rem}.react-pic-gallery__lightbox-image{pointer-events:none;width:auto;min-width:0;max-width:82rem;height:auto;min-height:0;max-height:none;animation:react-pic-gallery-image-in var(--gallery-motion) ease both;background:0 0;border-radius:0;grid-template-rows:minmax(0,1fr);grid-template-columns:minmax(0,1fr);place-items:center;margin-inline:auto;display:grid;position:absolute;inset:.75rem;overflow:visible}.react-pic-gallery__lightbox-image .react-pic-gallery__image-element{pointer-events:auto;touch-action:inherit;border-radius:var(--gallery-radius);background:0 0;width:auto;max-width:100%;height:auto;max-height:100%;object-fit:contain!important}.react-pic-gallery__lightbox-image .react-pic-gallery__image-loader{pointer-events:none;background:0 0}.react-pic-gallery__lightbox-image .react-pic-gallery__image-error{pointer-events:none}.react-pic-gallery__lightbox-image--swipe-next{animation-name:react-pic-gallery-slide-in-from-right}.react-pic-gallery__lightbox-image--swipe-previous{animation-name:react-pic-gallery-slide-in-from-left}.react-pic-gallery__control--previous,.react-pic-gallery__control--next{z-index:1;position:absolute;top:50%;transform:translateY(-50%)}.react-pic-gallery__control--previous{left:0}.react-pic-gallery__control--next{right:0}.react-pic-gallery__caption{color:#cbd5e1;text-align:center;flex:none;max-height:8rem;padding:.75rem 0 0;font-size:.95rem;line-height:1.4;overflow:hidden}.react-pic-gallery__sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;padding:0;position:absolute;overflow:hidden}@keyframes react-pic-gallery-spin{to{transform:rotate(360deg)}}@keyframes react-pic-gallery-fade-in{0%{opacity:0}to{opacity:1}}@keyframes react-pic-gallery-fade-out{0%{opacity:1}to{opacity:0}}@keyframes react-pic-gallery-rise-in{0%{opacity:0;transform:translateY(.5rem)scale(.99)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes react-pic-gallery-rise-out{0%{opacity:1;transform:translateY(0)scale(1)}to{opacity:0;transform:translateY(.5rem)scale(.99)}}@keyframes react-pic-gallery-image-in{0%{opacity:0;transform:scale(.985)}to{opacity:1;transform:scale(1)}}@keyframes react-pic-gallery-slide-in-from-right{0%{opacity:0;transform:translate(18%)}to{opacity:1;transform:translate(0)}}@keyframes react-pic-gallery-slide-in-from-left{0%{opacity:0;transform:translate(-18%)}to{opacity:1;transform:translate(0)}}@media (width<=600px){:where(.react-pic-gallery,.react-pic-gallery__lightbox){--gallery-gap:.5rem;--gallery-radius:.75rem;--gallery-row-height:8rem}:where(dialog.react-pic-gallery__lightbox){padding:max(.375rem, env(safe-area-inset-top)) max(.375rem, env(safe-area-inset-right)) max(.375rem, env(safe-area-inset-bottom)) max(.375rem, env(safe-area-inset-left))}.react-pic-gallery__lightbox-content{width:min(90rem,100vw - .75rem);height:min(54rem,100dvh - .75rem)}.react-pic-gallery__toolbar,.react-pic-gallery__custom-controls{min-height:3rem}.react-pic-gallery__viewport{padding:.25rem}.react-pic-gallery__lightbox-image{inset:.25rem}.react-pic-gallery__viewport--has-navigation .react-pic-gallery__lightbox-image{inset-inline:.25rem}.react-pic-gallery__control--previous,.react-pic-gallery__control--next{display:none}}@media (height<=600px){:where(dialog.react-pic-gallery__lightbox){padding:max(.25rem, env(safe-area-inset-top)) max(1rem, env(safe-area-inset-right)) max(.25rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left))}.react-pic-gallery__lightbox-content{height:min(54rem,100dvh - .5rem)}.react-pic-gallery__toolbar,.react-pic-gallery__custom-controls{min-height:2.25rem}.react-pic-gallery__caption{max-height:4rem;padding:.35rem 0 0;font-size:.85rem}.react-pic-gallery__viewport{padding:.25rem}.react-pic-gallery__lightbox-image{inset:.25rem}}@media (prefers-reduced-motion:reduce){:where(.react-pic-gallery,.react-pic-gallery__lightbox){--gallery-motion:0s}.react-pic-gallery__image-loader:after{animation:none}}
|
|
2
2
|
/*$vite$:1*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-pic-gallery",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Small, accessible React image gallery and lightbox.",
|
|
5
5
|
"author": "marcelrsoub",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"dev:docs": "astro dev --config docs-site/astro.config.mjs",
|
|
37
37
|
"build:docs": "astro build --config docs-site/astro.config.mjs",
|
|
38
38
|
"preview:docs": "astro preview --config docs-site/astro.config.mjs",
|
|
39
|
-
"github-pages": "npm run build:docs && gh-pages -d build",
|
|
39
|
+
"github-pages": "npm run build:docs && gh-pages -d build --dotfiles",
|
|
40
40
|
"prepack": "npm run build"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|