@omg-dev/pwa 0.4.34 → 0.4.37

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/auto.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as countVisit, c as isInIframe, f as setAutoShown, l as isIosInstallPlatform, m as wasAutoShown, n as VibesInstallPrompt, o as detectPlatform, s as isDismissed, u as isStandalone } from "./react-FTnyFbZ_.mjs";
1
+ import { a as countVisit, c as isInIframe, f as setAutoShown, l as isIosInstallPlatform, m as wasAutoShown, n as VibesInstallPrompt, o as detectPlatform, s as isDismissed, u as isStandalone } from "./react-BHavFwjG.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { createRoot } from "react-dom/client";
4
4
  //#region src/auto.tsx
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as countVisit, c as isInIframe, d as promptNativeInstall, i as useInstallPrompt, l as isIosInstallPlatform, n as VibesInstallPrompt, o as detectPlatform, p as setDismissed, r as defaultAppName, s as isDismissed, t as InstallGuide, u as isStandalone } from "./react-FTnyFbZ_.mjs";
1
+ import { a as countVisit, c as isInIframe, d as promptNativeInstall, i as useInstallPrompt, l as isIosInstallPlatform, n as VibesInstallPrompt, o as detectPlatform, p as setDismissed, r as defaultAppName, s as isDismissed, t as InstallGuide, u as isStandalone } from "./react-BHavFwjG.mjs";
2
2
  export { InstallGuide, VibesInstallPrompt, countVisit, defaultAppName, detectPlatform, isDismissed, isInIframe, isIosInstallPlatform, isStandalone, promptNativeInstall, setDismissed, useInstallPrompt };
@@ -262,13 +262,36 @@ const CSS = `
262
262
  display: flex; flex-direction: column; align-items: center; gap: 10px;
263
263
  margin: 0; padding: 0;
264
264
  }
265
- .vpwa-video {
266
- display: block; width: auto; max-width: 100%;
267
- height: min(56dvh, 520px); max-height: 520px;
265
+ .vpwa-video-frame {
266
+ position: relative; overflow: hidden;
267
+ width: min(100%, 31.5dvh, 292.5px);
268
+ aspect-ratio: 9 / 16;
268
269
  border: 1px solid var(--border, var(--vpwa-border)); border-radius: 18px;
269
- background: #000; object-fit: contain;
270
+ background: #000;
270
271
  box-shadow: 0 14px 38px rgba(0, 0, 0, 0.24);
271
272
  }
273
+ .vpwa-video {
274
+ display: block; width: 100%; height: 100%;
275
+ object-fit: cover;
276
+ }
277
+ .vpwa-video-loading {
278
+ position: absolute; inset: 0;
279
+ display: flex; align-items: flex-end; justify-content: center;
280
+ padding: 20px;
281
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.48), transparent 42%);
282
+ pointer-events: none;
283
+ }
284
+ .vpwa-video-loading span {
285
+ color: transparent; font-size: 12px; font-weight: 600; line-height: 1;
286
+ letter-spacing: 0.01em;
287
+ background: linear-gradient(100deg, rgba(255,255,255,0.46) 20%, #fff 45%, rgba(255,255,255,0.46) 70%);
288
+ background-size: 220% 100%; background-clip: text; -webkit-background-clip: text;
289
+ animation: vpwa-text-shimmer 1.6s ease-in-out infinite;
290
+ }
291
+ @keyframes vpwa-text-shimmer {
292
+ from { background-position: 100% 0; }
293
+ to { background-position: -100% 0; }
294
+ }
272
295
  .vpwa-video-guide figcaption {
273
296
  max-width: 32rem; color: var(--muted-foreground, var(--vpwa-muted));
274
297
  font-size: 12px; line-height: 1.45; text-align: center;
@@ -314,6 +337,7 @@ const CSS = `
314
337
  }
315
338
  @media (prefers-reduced-motion: reduce) {
316
339
  .vpwa-target { animation: none; }
340
+ .vpwa-video-loading span { animation: none; color: rgba(255,255,255,0.82); }
317
341
  .vpwa-sheet, .vpwa-backdrop, .vpwa-banner { transition: none; }
318
342
  }
319
343
 
@@ -711,17 +735,19 @@ function stepsFor(platform) {
711
735
  case "unsupported": return null;
712
736
  }
713
737
  }
714
- function InstallGuide({ open, onClose, appName, iosVideoSrc }) {
738
+ function InstallGuide({ open, onClose, appName, iosVideoSrc, iosVideoPoster }) {
715
739
  const { platform, canPrompt, installed, promptInstall } = useInstallPrompt();
716
740
  const name = appName ?? defaultAppName();
717
741
  const [mounted, setMounted] = useState(open);
718
742
  const [shown, setShown] = useState(false);
719
743
  const [videoFailed, setVideoFailed] = useState(false);
744
+ const [videoLoading, setVideoLoading] = useState(true);
720
745
  useEffect(() => {
721
746
  ensureStyles();
722
747
  if (open) {
723
748
  setMounted(true);
724
749
  setVideoFailed(false);
750
+ setVideoLoading(true);
725
751
  const raf = requestAnimationFrame(() => requestAnimationFrame(() => setShown(true)));
726
752
  return () => cancelAnimationFrame(raf);
727
753
  }
@@ -771,19 +797,29 @@ function InstallGuide({ open, onClose, appName, iosVideoSrc }) {
771
797
  });
772
798
  else if (isIosInstallPlatform(platform) && iosVideoSrc && !videoFailed) body = /* @__PURE__ */ jsxs("figure", {
773
799
  className: "vpwa-video-guide",
774
- children: [/* @__PURE__ */ jsx("video", {
775
- className: "vpwa-video",
776
- src: iosVideoSrc,
777
- autoPlay: true,
778
- controls: true,
779
- controlsList: "nodownload noremoteplayback",
780
- disablePictureInPicture: true,
781
- loop: true,
782
- muted: true,
783
- playsInline: true,
784
- preload: "auto",
785
- "aria-label": "iOS Add to Home Screen walkthrough",
786
- onError: () => setVideoFailed(true)
800
+ children: [/* @__PURE__ */ jsxs("div", {
801
+ className: "vpwa-video-frame",
802
+ children: [/* @__PURE__ */ jsx("video", {
803
+ className: "vpwa-video",
804
+ src: iosVideoSrc,
805
+ poster: iosVideoPoster,
806
+ autoPlay: true,
807
+ disablePictureInPicture: true,
808
+ loop: true,
809
+ muted: true,
810
+ playsInline: true,
811
+ preload: "auto",
812
+ "aria-label": "iOS Add to Home Screen walkthrough",
813
+ onCanPlay: () => setVideoLoading(false),
814
+ onPlaying: () => setVideoLoading(false),
815
+ onWaiting: () => setVideoLoading(true),
816
+ onError: () => setVideoFailed(true)
817
+ }), videoLoading ? /* @__PURE__ */ jsx("div", {
818
+ className: "vpwa-video-loading",
819
+ role: "status",
820
+ "aria-label": "Loading walkthrough video",
821
+ children: /* @__PURE__ */ jsx("span", { children: "Loading walkthrough…" })
822
+ }) : null]
787
823
  }), /* @__PURE__ */ jsx("figcaption", { children: "Open your browser’s Share menu, choose Add to Home Screen, then tap Add." })]
788
824
  });
789
825
  else if (steps) body = /* @__PURE__ */ jsx("ol", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/pwa",
3
- "version": "0.4.34",
3
+ "version": "0.4.37",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/react.tsx CHANGED
@@ -171,12 +171,15 @@ export function InstallGuide({
171
171
  onClose,
172
172
  appName,
173
173
  iosVideoSrc,
174
+ iosVideoPoster,
174
175
  }: {
175
176
  open: boolean
176
177
  onClose: () => void
177
178
  appName?: string
178
179
  /** Optional iOS walkthrough video. Static steps remain the load-failure fallback. */
179
180
  iosVideoSrc?: string
181
+ /** Optional poster shown while the iOS walkthrough video loads. */
182
+ iosVideoPoster?: string
180
183
  }) {
181
184
  const { platform, canPrompt, installed, promptInstall } = useInstallPrompt()
182
185
  const name = appName ?? defaultAppName()
@@ -185,12 +188,14 @@ export function InstallGuide({
185
188
  const [mounted, setMounted] = useState(open)
186
189
  const [shown, setShown] = useState(false)
187
190
  const [videoFailed, setVideoFailed] = useState(false)
191
+ const [videoLoading, setVideoLoading] = useState(true)
188
192
 
189
193
  useEffect(() => {
190
194
  ensureStyles()
191
195
  if (open) {
192
196
  setMounted(true)
193
197
  setVideoFailed(false)
198
+ setVideoLoading(true)
194
199
  const raf = requestAnimationFrame(() => requestAnimationFrame(() => setShown(true)))
195
200
  return () => cancelAnimationFrame(raf)
196
201
  }
@@ -244,20 +249,29 @@ export function InstallGuide({
244
249
  } else if (isIosInstallPlatform(platform) && iosVideoSrc && !videoFailed) {
245
250
  body = (
246
251
  <figure className="vpwa-video-guide">
247
- <video
248
- className="vpwa-video"
249
- src={iosVideoSrc}
250
- autoPlay
251
- controls
252
- controlsList="nodownload noremoteplayback"
253
- disablePictureInPicture
254
- loop
255
- muted
256
- playsInline
257
- preload="auto"
258
- aria-label="iOS Add to Home Screen walkthrough"
259
- onError={() => setVideoFailed(true)}
260
- />
252
+ <div className="vpwa-video-frame">
253
+ <video
254
+ className="vpwa-video"
255
+ src={iosVideoSrc}
256
+ poster={iosVideoPoster}
257
+ autoPlay
258
+ disablePictureInPicture
259
+ loop
260
+ muted
261
+ playsInline
262
+ preload="auto"
263
+ aria-label="iOS Add to Home Screen walkthrough"
264
+ onCanPlay={() => setVideoLoading(false)}
265
+ onPlaying={() => setVideoLoading(false)}
266
+ onWaiting={() => setVideoLoading(true)}
267
+ onError={() => setVideoFailed(true)}
268
+ />
269
+ {videoLoading ? (
270
+ <div className="vpwa-video-loading" role="status" aria-label="Loading walkthrough video">
271
+ <span>Loading walkthrough…</span>
272
+ </div>
273
+ ) : null}
274
+ </div>
261
275
  <figcaption>
262
276
  Open your browser’s Share menu, choose Add to Home Screen, then tap Add.
263
277
  </figcaption>
package/src/styles.ts CHANGED
@@ -115,13 +115,36 @@ const CSS = `
115
115
  display: flex; flex-direction: column; align-items: center; gap: 10px;
116
116
  margin: 0; padding: 0;
117
117
  }
118
- .vpwa-video {
119
- display: block; width: auto; max-width: 100%;
120
- height: min(56dvh, 520px); max-height: 520px;
118
+ .vpwa-video-frame {
119
+ position: relative; overflow: hidden;
120
+ width: min(100%, 31.5dvh, 292.5px);
121
+ aspect-ratio: 9 / 16;
121
122
  border: 1px solid var(--border, var(--vpwa-border)); border-radius: 18px;
122
- background: #000; object-fit: contain;
123
+ background: #000;
123
124
  box-shadow: 0 14px 38px rgba(0, 0, 0, 0.24);
124
125
  }
126
+ .vpwa-video {
127
+ display: block; width: 100%; height: 100%;
128
+ object-fit: cover;
129
+ }
130
+ .vpwa-video-loading {
131
+ position: absolute; inset: 0;
132
+ display: flex; align-items: flex-end; justify-content: center;
133
+ padding: 20px;
134
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.48), transparent 42%);
135
+ pointer-events: none;
136
+ }
137
+ .vpwa-video-loading span {
138
+ color: transparent; font-size: 12px; font-weight: 600; line-height: 1;
139
+ letter-spacing: 0.01em;
140
+ background: linear-gradient(100deg, rgba(255,255,255,0.46) 20%, #fff 45%, rgba(255,255,255,0.46) 70%);
141
+ background-size: 220% 100%; background-clip: text; -webkit-background-clip: text;
142
+ animation: vpwa-text-shimmer 1.6s ease-in-out infinite;
143
+ }
144
+ @keyframes vpwa-text-shimmer {
145
+ from { background-position: 100% 0; }
146
+ to { background-position: -100% 0; }
147
+ }
125
148
  .vpwa-video-guide figcaption {
126
149
  max-width: 32rem; color: var(--muted-foreground, var(--vpwa-muted));
127
150
  font-size: 12px; line-height: 1.45; text-align: center;
@@ -167,6 +190,7 @@ const CSS = `
167
190
  }
168
191
  @media (prefers-reduced-motion: reduce) {
169
192
  .vpwa-target { animation: none; }
193
+ .vpwa-video-loading span { animation: none; color: rgba(255,255,255,0.82); }
170
194
  .vpwa-sheet, .vpwa-backdrop, .vpwa-banner { transition: none; }
171
195
  }
172
196