@jekrch/react-viewport-lightbox 0.1.0 → 0.3.0

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/dist/styles.css CHANGED
@@ -14,9 +14,25 @@
14
14
  --rvl-bar-fg-faint: rgba(255, 255, 255, 0.3);
15
15
  --rvl-btn-bg: rgba(255, 255, 255, 0.1);
16
16
  --rvl-btn-bg-hover: rgba(255, 255, 255, 0.2);
17
+ /* Toggled (`is-active`) button fill. Left undeclared so the active rule's
18
+ `var(--rvl-accent)` fallback resolves at the button (picking up an accent
19
+ overridden on an ancestor). Override it (e.g. to a translucent
20
+ `color-mix(in srgb, var(--rvl-accent) 20%, transparent)`) for a subtler
21
+ wash; setting it to `var(--rvl-accent)` here would re-freeze it to the
22
+ :root accent. */
23
+ /* Monospace stack for the counter / zoom-scale readout. Override to theme it
24
+ with an app font (e.g. a custom monospace face). */
25
+ --rvl-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
17
26
  --rvl-radius: 4px;
18
27
  --rvl-anim-duration: 250ms;
19
28
  --rvl-z: 50;
29
+ /* Size of the bottom prev/next nav arrows. Settable via the `navHeight` prop.
30
+ Defaults to 38px to match the comic-snaps viewer. */
31
+ --rvl-nav-height: 2.375rem;
32
+ /* Gap between the bottom nav controls and the viewport's bottom edge. Settable
33
+ via the `navInset` prop; floored by the device safe-area inset. Defaults to
34
+ 1.3rem to match the comic-snaps viewer. */
35
+ --rvl-nav-inset: 1.3rem;
20
36
  }
21
37
 
22
38
  /* Root overlay -------------------------------------------------------------- */
@@ -75,7 +91,7 @@
75
91
  .rvl-bottom-bar {
76
92
  bottom: 0;
77
93
  padding-top: 1rem;
78
- padding-bottom: max(0.3rem, env(safe-area-inset-bottom));
94
+ padding-bottom: max(var(--rvl-nav-inset), env(safe-area-inset-bottom));
79
95
  opacity: 0;
80
96
  transform: translateY(0.5rem);
81
97
  }
@@ -151,11 +167,25 @@
151
167
  }
152
168
  .rvl-btn.is-active {
153
169
  color: #fff;
154
- background: var(--rvl-accent);
170
+ background: var(--rvl-btn-bg-active, var(--rvl-accent));
155
171
  }
156
172
  .rvl-btn-scale {
157
173
  font-variant-numeric: tabular-nums;
158
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
174
+ font-family: var(--rvl-font-mono);
175
+ }
176
+
177
+ /* Icons inherit their button's color so currentColor-based glyphs (e.g. lucide)
178
+ track the button's resting/hover/active color. The whole icon subtree is
179
+ covered, not just the root <svg>: a consumer's global `* { color }` rule sets
180
+ a color on the inner <path>/<line> nodes, and currentColor (the lucide stroke)
181
+ re-resolves against each node's own color — so without forcing the children to
182
+ inherit too, the strokes stay stuck at that color (looking permanently
183
+ "hovered" and the wrong hue). */
184
+ .rvl-btn svg,
185
+ .rvl-btn svg *,
186
+ .rvl-nav-btn svg,
187
+ .rvl-nav-btn svg * {
188
+ color: inherit;
159
189
  }
160
190
 
161
191
  /* Image stage --------------------------------------------------------------- */
@@ -183,6 +213,14 @@
183
213
  .rvl-root.rvl-visible .rvl-track {
184
214
  opacity: 1;
185
215
  }
216
+ /* Opaque from the first frame. During a thumbnail zoom this is applied at mount
217
+ (before `rvl-visible`), so the image flies in crisply on the FLIP instead of
218
+ the opacity ramp cross-fading over the top of the expand — which otherwise
219
+ reads as the picture expanding twice. On a plain (non-zoom) open the class is
220
+ only added once `visible` flips, so it still fades in from the base opacity:0. */
221
+ .rvl-track-visible {
222
+ opacity: 1;
223
+ }
186
224
 
187
225
  .rvl-adjacent {
188
226
  position: absolute;
@@ -216,6 +254,31 @@
216
254
  will-change: transform;
217
255
  }
218
256
 
257
+ /* Loading spinner: shown only when the opening image is slow to load. Centered
258
+ over the stage; the image itself is held hidden until it has decoded. */
259
+ .rvl-spinner {
260
+ position: absolute;
261
+ top: 50%;
262
+ left: 50%;
263
+ transform: translate(-50%, -50%);
264
+ z-index: 11;
265
+ pointer-events: none;
266
+ }
267
+ .rvl-spinner-ring {
268
+ display: block;
269
+ width: 2.25rem;
270
+ height: 2.25rem;
271
+ border-radius: 50%;
272
+ border: 3px solid rgba(255, 255, 255, 0.25);
273
+ border-top-color: rgba(255, 255, 255, 0.9);
274
+ animation: rvl-spin 0.7s linear infinite;
275
+ }
276
+ @keyframes rvl-spin {
277
+ to {
278
+ transform: rotate(360deg);
279
+ }
280
+ }
281
+
219
282
  /* Bottom nav row ------------------------------------------------------------ */
220
283
 
221
284
  .rvl-nav-row {
@@ -261,6 +324,19 @@
261
324
  right: 0;
262
325
  }
263
326
 
327
+ /* Inline placement (`navSlotPlacement="inline"`): the nav slots sit directly
328
+ flanking the prev/counter/next group as one centered cluster, so an
329
+ info/details toggle hugs the arrows instead of being flung to the row edges.
330
+ The slots become normal flex children laid out by the inner's gap. */
331
+ .rvl-nav-inner.rvl-nav-inline {
332
+ gap: 0.75rem;
333
+ }
334
+ .rvl-nav-inline .rvl-nav-start,
335
+ .rvl-nav-inline .rvl-nav-end {
336
+ position: static;
337
+ transform: none;
338
+ }
339
+
264
340
  .rvl-nav-btn {
265
341
  display: inline-flex;
266
342
  align-items: center;
@@ -273,11 +349,18 @@
273
349
  color: rgba(255, 255, 255, 0.4);
274
350
  transition: color 0.15s ease-out;
275
351
  }
352
+ /* Drive the arrow glyph size from the theme var so `navHeight` resizes the
353
+ default (and any consumer-supplied) nav icons. CSS wins over the SVG's own
354
+ width/height attributes. */
355
+ .rvl-nav-btn svg {
356
+ width: var(--rvl-nav-height);
357
+ height: var(--rvl-nav-height);
358
+ }
276
359
  .rvl-nav-btn:hover:not(:disabled) {
277
- color: rgba(255, 255, 255, 0.7);
360
+ color: rgba(255, 255, 255, 0.6);
278
361
  }
279
362
  .rvl-nav-btn:active:not(:disabled) {
280
- color: rgba(255, 255, 255, 0.85);
363
+ color: rgba(255, 255, 255, 0.8);
281
364
  }
282
365
  .rvl-nav-btn:disabled {
283
366
  color: rgba(255, 255, 255, 0.1);
@@ -291,11 +374,14 @@
291
374
  .rvl-counter {
292
375
  display: inline-block;
293
376
  text-align: center;
294
- font-size: 0.6875rem;
377
+ /* Scale the counter with the nav arrows so the whole cluster grows together
378
+ (0.29 ≈ 11px at the 38px default, matching comic-snaps). Set the
379
+ `counterFontSize` prop / `--rvl-counter-font-size` to override the ratio. */
380
+ font-size: var(--rvl-counter-font-size, calc(var(--rvl-nav-height) * 0.29));
295
381
  letter-spacing: 0.02em;
296
382
  color: var(--rvl-bar-fg-muted);
297
383
  font-variant-numeric: tabular-nums;
298
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
384
+ font-family: var(--rvl-font-mono);
299
385
  user-select: none;
300
386
  }
301
387
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jekrch/react-viewport-lightbox",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "A headless-capable, touch-friendly React image viewer and lightbox with zoom, pan, and swipe.",
5
5
  "type": "module",
6
6
  "sideEffects": [