@marianmeres/stuic 3.129.0 → 3.130.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/README.md CHANGED
@@ -195,7 +195,11 @@ When a stuic app is installed and launched standalone (iOS Home Screen, Android/
195
195
 
196
196
  **Automatic:**
197
197
 
198
- - `Notifications` — the toast stack always keeps clear of the insets in standalone (you never want a toast under the home indicator). No prop needed; no-op in a browser tab.
198
+ - `Notifications` — the toast stack always keeps clear of the insets in standalone (you never want a toast under the home indicator).
199
+ - `Modal` — when full-bleed (below the `md` breakpoint, where it fills the screen), its content is padded by the insets so header / content / footer clear the system UI. Centered desktop modals are untouched.
200
+ - `AssetsPreview` — the lightbox image stays edge-to-edge, but the overlay controls (close, prev/next, dots, filename) are offset so they clear the insets.
201
+
202
+ All three are no-ops in a browser tab and need no prop.
199
203
 
200
204
  **Utility classes** — offset any edge-anchored element without writing your own `env()` rule. They are active in standalone only:
201
205
 
@@ -219,7 +223,7 @@ When a stuic app is installed and launched standalone (iOS Home Screen, Android/
219
223
 
220
224
  **Pick ONE layer.** Don't pad the same edge twice in a nesting chain. E.g. a nav `Drawer` whose content is its own stuic `Header`: put `safeArea` on the inner `Header`, not also on the drawer panel/wrapper.
221
225
 
222
- **Not covered:** other fixed/edge-anchored components (`Modal`/`ModalDialog` full-bleed on mobile, `Float`) do not auto-handle insets — apply a `stuic-safe-area-*` class or the variables to their content as needed.
226
+ **Not covered:** remaining fixed/edge-anchored components (e.g. `Float`, or a bare `ModalDialog` used directly) do not auto-handle insets — apply a `stuic-safe-area-*` class or the variables to their content as needed.
223
227
 
224
228
  ## TypeScript
225
229
 
@@ -45,6 +45,7 @@ interface AssetPreview {
45
45
  - **Touch support**: Touch gestures for pan
46
46
  - **Auto-preload**: Preloads full-resolution images when modal opens
47
47
  - **File type icons**: Displays appropriate icons for non-image files
48
+ - **PWA safe area**: when installed/standalone, the overlay controls (close, prev/next, dots, filename) are automatically offset so they clear the status bar / notch / home indicator. The image itself stays edge-to-edge. Inert in a browser tab (`env()` → `0`); no prop required.
48
49
 
49
50
  ## Translation Keys
50
51
 
@@ -658,8 +658,11 @@
658
658
  <div
659
659
  class={twMerge(
660
660
  "absolute inset-0 flex justify-between pointer-events-none",
661
- prevNextBottom ? "items-end pb-4" : "items-center"
661
+ prevNextBottom ? "items-end" : "items-center"
662
662
  )}
663
+ style="padding-left: var(--stuic-safe-area-left, 0px); padding-right: var(--stuic-safe-area-right, 0px);{prevNextBottom
664
+ ? ' padding-bottom: calc(1rem + var(--stuic-safe-area-bottom, 0px));'
665
+ : ''}"
663
666
  >
664
667
  <Button
665
668
  class={twMerge(BUTTON_CLS, "ml-4", classControls)}
@@ -681,7 +684,17 @@
681
684
  </div>
682
685
  {/if}
683
686
 
684
- <div class="absolute top-4 left-4 right-4 flex items-center justify-between gap-3">
687
+ <!-- Top control bar (close, download, zoom, filename). Offset by the PWA
688
+ safe-area insets when installed/standalone so the controls clear the
689
+ status bar / notch / side notch. The vars are 0px in a browser tab. -->
690
+ <div
691
+ class="absolute flex items-center justify-between gap-3"
692
+ style="
693
+ top: calc(1rem + var(--stuic-safe-area-top, 0px));
694
+ left: calc(1rem + var(--stuic-safe-area-left, 0px));
695
+ right: calc(1rem + var(--stuic-safe-area-right, 0px));
696
+ "
697
+ >
685
698
  {#if !noName && previewAsset?.name}
686
699
  <span class="stuic-assets-preview-label truncate px-1">
687
700
  {previewAsset?.name}
@@ -767,7 +780,8 @@
767
780
  {#if !noDots && assets.length <= 10}
768
781
  {#if !noName && dotTooltip}
769
782
  <div
770
- class="absolute bottom-10 left-0 right-0 text-center"
783
+ class="absolute left-0 right-0 text-center"
784
+ style="bottom: calc(2.5rem + var(--stuic-safe-area-bottom, 0px));"
771
785
  transition:fade={{ duration: 100 }}
772
786
  >
773
787
  <span class="stuic-assets-preview-label p-1">
@@ -775,7 +789,10 @@
775
789
  </span>
776
790
  </div>
777
791
  {/if}
778
- <div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex items-center gap-3">
792
+ <div
793
+ class="absolute left-1/2 -translate-x-1/2 flex items-center gap-3"
794
+ style="bottom: calc(1rem + var(--stuic-safe-area-bottom, 0px));"
795
+ >
779
796
  {#each assets as _, i}
780
797
  <!-- svelte-ignore a11y_mouse_events_have_key_events -->
781
798
  <button
@@ -793,7 +810,10 @@
793
810
  {/each}
794
811
  </div>
795
812
  {:else if !noCurrentOfTotal}
796
- <div class="absolute bottom-4 left-1/2 -translate-x-1/2">
813
+ <div
814
+ class="absolute left-1/2 -translate-x-1/2"
815
+ style="bottom: calc(1rem + var(--stuic-safe-area-bottom, 0px));"
816
+ >
797
817
  <span class="stuic-assets-preview-label px-2 py-1 text-sm opacity-60">
798
818
  {previewIdx + 1} / {assets.length}
799
819
  </span>
@@ -107,6 +107,10 @@ By default, Modal is:
107
107
  - **Mobile**: Full screen with 1rem margins from viewport edges
108
108
  - **Desktop (md+)**: Centered, max-width 768px, auto height with max 80vh
109
109
 
110
+ ### PWA safe area (automatic)
111
+
112
+ When the app runs installed/standalone (display-mode standalone or fullscreen) and the Modal is **full-bleed** (below the `md` breakpoint), its content is automatically padded by the device safe-area insets so the header / content / footer clear the status bar, notch and home indicator. This is **inert in a normal browser tab** (`env()` → `0`) and on **centered desktop** modals (which don't touch the edges). No prop required. To go truly edge-to-edge, override the padding on the inner panel via `class`.
113
+
110
114
  ## CSS Variables
111
115
 
112
116
  Override to customize appearance:
@@ -27,4 +27,24 @@
27
27
  .stuic-modal .main {
28
28
  scrollbar-width: thin;
29
29
  }
30
+
31
+ /* ============================================================================
32
+ SAFE AREA (PWA installed / standalone) — automatic, full-bleed only.
33
+ The Modal is full-screen below the `md` breakpoint (size-full) and a
34
+ centered card at/above it (md:size-auto). Only the full-bleed case touches
35
+ the device edges, so we gate on `width < 48rem` (Tailwind's md) AND
36
+ standalone, and pad the bg-bearing .stuic-modal (a flex column) so its
37
+ header / content / footer clear the status bar, notch and home indicator.
38
+ Centered desktop modals and browser tabs (env → 0) are untouched. A
39
+ consumer wanting true edge-to-edge can override padding via `class`.
40
+ ============================================================================ */
41
+ @media (display-mode: standalone) and (width < 48rem),
42
+ (display-mode: fullscreen) and (width < 48rem) {
43
+ .stuic-modal {
44
+ padding-top: env(safe-area-inset-top);
45
+ padding-right: env(safe-area-inset-right);
46
+ padding-bottom: env(safe-area-inset-bottom);
47
+ padding-left: env(safe-area-inset-left);
48
+ }
49
+ }
30
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.129.0",
3
+ "version": "3.130.0",
4
4
  "packageManager": "pnpm@11.5.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",