@omg-dev/pwa 0.4.33 → 0.4.34

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, d as setAutoShown, l as isStandalone, n as VibesInstallPrompt, o as detectPlatform, p as wasAutoShown, s as isDismissed } from "./react-BYbYeTts.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-FTnyFbZ_.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { createRoot } from "react-dom/client";
4
4
  //#region src/auto.tsx
@@ -8,7 +8,7 @@ function shouldAutoShow() {
8
8
  if (isStandalone()) return false;
9
9
  if (isDismissed() || wasAutoShown()) return false;
10
10
  const platform = detectPlatform();
11
- if (platform !== "ios-safari" && platform !== "ios-chrome" && platform !== "ios-other" && platform !== "android") return false;
11
+ if (!isIosInstallPlatform(platform) && platform !== "android") return false;
12
12
  return countVisit() >= 2;
13
13
  }
14
14
  function mount() {
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as countVisit, c as isInIframe, f as setDismissed, i as useInstallPrompt, l as isStandalone, n as VibesInstallPrompt, o as detectPlatform, r as defaultAppName, s as isDismissed, t as InstallGuide, u as promptNativeInstall } from "./react-BYbYeTts.mjs";
2
- export { InstallGuide, VibesInstallPrompt, countVisit, defaultAppName, detectPlatform, isDismissed, isInIframe, isStandalone, promptNativeInstall, setDismissed, useInstallPrompt };
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";
2
+ export { InstallGuide, VibesInstallPrompt, countVisit, defaultAppName, detectPlatform, isDismissed, isInIframe, isIosInstallPlatform, isStandalone, promptNativeInstall, setDismissed, useInstallPrompt };
@@ -2,6 +2,9 @@ import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from
2
2
  import { createPortal } from "react-dom";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/core.ts
5
+ function isIosInstallPlatform(platform) {
6
+ return platform === "ios-safari" || platform === "ios-chrome" || platform === "ios-other";
7
+ }
5
8
  function detectPlatform() {
6
9
  if (typeof navigator === "undefined") return "unsupported";
7
10
  const ua = navigator.userAgent;
@@ -198,6 +201,7 @@ const CSS = `
198
201
  .vpwa-open .vpwa-backdrop { opacity: 1; }
199
202
  .vpwa-sheet {
200
203
  position: relative; width: 100%; max-width: 430px;
204
+ max-height: calc(100dvh - 12px); overflow-y: auto; overscroll-behavior: contain;
201
205
  background: var(--card, var(--vpwa-bg));
202
206
  color: var(--card-foreground, var(--vpwa-fg));
203
207
  border: 1px solid var(--border, var(--vpwa-border)); border-bottom: none;
@@ -253,6 +257,23 @@ const CSS = `
253
257
  .vpwa-steptext { font-size: 14px; font-weight: 500; }
254
258
  .vpwa-stepcap { font-weight: 400; color: var(--muted-foreground, var(--vpwa-muted)); }
255
259
 
260
+ /* ── iOS walkthrough video ──────────────────────────────────────────── */
261
+ .vpwa-video-guide {
262
+ display: flex; flex-direction: column; align-items: center; gap: 10px;
263
+ margin: 0; padding: 0;
264
+ }
265
+ .vpwa-video {
266
+ display: block; width: auto; max-width: 100%;
267
+ height: min(56dvh, 520px); max-height: 520px;
268
+ border: 1px solid var(--border, var(--vpwa-border)); border-radius: 18px;
269
+ background: #000; object-fit: contain;
270
+ box-shadow: 0 14px 38px rgba(0, 0, 0, 0.24);
271
+ }
272
+ .vpwa-video-guide figcaption {
273
+ max-width: 32rem; color: var(--muted-foreground, var(--vpwa-muted));
274
+ font-size: 12px; line-height: 1.45; text-align: center;
275
+ }
276
+
256
277
  /* ── mocks ───────────────────────────────────────────────────────────── */
257
278
  .vpwa-toolbar {
258
279
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
@@ -690,15 +711,17 @@ function stepsFor(platform) {
690
711
  case "unsupported": return null;
691
712
  }
692
713
  }
693
- function InstallGuide({ open, onClose, appName }) {
714
+ function InstallGuide({ open, onClose, appName, iosVideoSrc }) {
694
715
  const { platform, canPrompt, installed, promptInstall } = useInstallPrompt();
695
716
  const name = appName ?? defaultAppName();
696
717
  const [mounted, setMounted] = useState(open);
697
718
  const [shown, setShown] = useState(false);
719
+ const [videoFailed, setVideoFailed] = useState(false);
698
720
  useEffect(() => {
699
721
  ensureStyles();
700
722
  if (open) {
701
723
  setMounted(true);
724
+ setVideoFailed(false);
702
725
  const raf = requestAnimationFrame(() => requestAnimationFrame(() => setShown(true)));
703
726
  return () => cancelAnimationFrame(raf);
704
727
  }
@@ -746,6 +769,23 @@ function InstallGuide({ open, onClose, appName }) {
746
769
  children: "Not now"
747
770
  })]
748
771
  });
772
+ else if (isIosInstallPlatform(platform) && iosVideoSrc && !videoFailed) body = /* @__PURE__ */ jsxs("figure", {
773
+ 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)
787
+ }), /* @__PURE__ */ jsx("figcaption", { children: "Open your browser’s Share menu, choose Add to Home Screen, then tap Add." })]
788
+ });
749
789
  else if (steps) body = /* @__PURE__ */ jsx("ol", {
750
790
  className: "vpwa-steps",
751
791
  children: steps.map((step, i) => /* @__PURE__ */ jsxs("li", {
@@ -872,4 +912,4 @@ function VibesInstallPrompt({ appName, variant = "inline", className }) {
872
912
  })] });
873
913
  }
874
914
  //#endregion
875
- export { countVisit as a, isInIframe as c, setAutoShown as d, setDismissed as f, useInstallPrompt as i, isStandalone as l, VibesInstallPrompt as n, detectPlatform as o, wasAutoShown as p, defaultAppName as r, isDismissed as s, InstallGuide as t, promptNativeInstall as u };
915
+ export { countVisit as a, isInIframe as c, promptNativeInstall as d, setAutoShown as f, useInstallPrompt as i, isIosInstallPlatform as l, wasAutoShown as m, VibesInstallPrompt as n, detectPlatform as o, setDismissed as p, defaultAppName as r, isDismissed as s, InstallGuide as t, isStandalone as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/pwa",
3
- "version": "0.4.33",
3
+ "version": "0.4.34",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/auto.tsx CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  detectPlatform,
19
19
  isDismissed,
20
20
  isInIframe,
21
+ isIosInstallPlatform,
21
22
  isStandalone,
22
23
  setAutoShown,
23
24
  wasAutoShown,
@@ -30,7 +31,7 @@ function shouldAutoShow(): boolean {
30
31
  if (isStandalone()) return false
31
32
  if (isDismissed() || wasAutoShown()) return false
32
33
  const platform = detectPlatform()
33
- if (platform !== "ios-safari" && platform !== "ios-chrome" && platform !== "ios-other" && platform !== "android") {
34
+ if (!isIosInstallPlatform(platform) && platform !== "android") {
34
35
  return false
35
36
  }
36
37
  return countVisit() >= 2
package/src/core.ts CHANGED
@@ -20,6 +20,12 @@ export type InstallPlatform =
20
20
  | "desktop-safari" // macOS Safari — File → Add to Dock
21
21
  | "unsupported" // desktop Firefox, webviews, …
22
22
 
23
+ export function isIosInstallPlatform(
24
+ platform: InstallPlatform,
25
+ ): platform is "ios-safari" | "ios-chrome" | "ios-other" {
26
+ return platform === "ios-safari" || platform === "ios-chrome" || platform === "ios-other"
27
+ }
28
+
23
29
  export function detectPlatform(): InstallPlatform {
24
30
  if (typeof navigator === "undefined") return "unsupported"
25
31
  const ua = navigator.userAgent
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export {
9
9
  detectPlatform,
10
10
  isStandalone,
11
11
  isInIframe,
12
+ isIosInstallPlatform,
12
13
  promptNativeInstall,
13
14
  isDismissed,
14
15
  setDismissed,
package/src/react.tsx CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  getServerInstallState,
14
14
  isDismissed,
15
15
  isInIframe,
16
+ isIosInstallPlatform,
16
17
  promptNativeInstall,
17
18
  setDismissed,
18
19
  subscribeInstallState,
@@ -169,10 +170,13 @@ export function InstallGuide({
169
170
  open,
170
171
  onClose,
171
172
  appName,
173
+ iosVideoSrc,
172
174
  }: {
173
175
  open: boolean
174
176
  onClose: () => void
175
177
  appName?: string
178
+ /** Optional iOS walkthrough video. Static steps remain the load-failure fallback. */
179
+ iosVideoSrc?: string
176
180
  }) {
177
181
  const { platform, canPrompt, installed, promptInstall } = useInstallPrompt()
178
182
  const name = appName ?? defaultAppName()
@@ -180,11 +184,13 @@ export function InstallGuide({
180
184
  // `shown` drives the CSS open state one frame after mount.
181
185
  const [mounted, setMounted] = useState(open)
182
186
  const [shown, setShown] = useState(false)
187
+ const [videoFailed, setVideoFailed] = useState(false)
183
188
 
184
189
  useEffect(() => {
185
190
  ensureStyles()
186
191
  if (open) {
187
192
  setMounted(true)
193
+ setVideoFailed(false)
188
194
  const raf = requestAnimationFrame(() => requestAnimationFrame(() => setShown(true)))
189
195
  return () => cancelAnimationFrame(raf)
190
196
  }
@@ -235,6 +241,28 @@ export function InstallGuide({
235
241
  </button>
236
242
  </div>
237
243
  )
244
+ } else if (isIosInstallPlatform(platform) && iosVideoSrc && !videoFailed) {
245
+ body = (
246
+ <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
+ />
261
+ <figcaption>
262
+ Open your browser’s Share menu, choose Add to Home Screen, then tap Add.
263
+ </figcaption>
264
+ </figure>
265
+ )
238
266
  } else if (steps) {
239
267
  body = (
240
268
  <ol className="vpwa-steps">
package/src/styles.ts CHANGED
@@ -54,6 +54,7 @@ const CSS = `
54
54
  .vpwa-open .vpwa-backdrop { opacity: 1; }
55
55
  .vpwa-sheet {
56
56
  position: relative; width: 100%; max-width: 430px;
57
+ max-height: calc(100dvh - 12px); overflow-y: auto; overscroll-behavior: contain;
57
58
  background: var(--card, var(--vpwa-bg));
58
59
  color: var(--card-foreground, var(--vpwa-fg));
59
60
  border: 1px solid var(--border, var(--vpwa-border)); border-bottom: none;
@@ -109,6 +110,23 @@ const CSS = `
109
110
  .vpwa-steptext { font-size: 14px; font-weight: 500; }
110
111
  .vpwa-stepcap { font-weight: 400; color: var(--muted-foreground, var(--vpwa-muted)); }
111
112
 
113
+ /* ── iOS walkthrough video ──────────────────────────────────────────── */
114
+ .vpwa-video-guide {
115
+ display: flex; flex-direction: column; align-items: center; gap: 10px;
116
+ margin: 0; padding: 0;
117
+ }
118
+ .vpwa-video {
119
+ display: block; width: auto; max-width: 100%;
120
+ height: min(56dvh, 520px); max-height: 520px;
121
+ border: 1px solid var(--border, var(--vpwa-border)); border-radius: 18px;
122
+ background: #000; object-fit: contain;
123
+ box-shadow: 0 14px 38px rgba(0, 0, 0, 0.24);
124
+ }
125
+ .vpwa-video-guide figcaption {
126
+ max-width: 32rem; color: var(--muted-foreground, var(--vpwa-muted));
127
+ font-size: 12px; line-height: 1.45; text-align: center;
128
+ }
129
+
112
130
  /* ── mocks ───────────────────────────────────────────────────────────── */
113
131
  .vpwa-toolbar {
114
132
  display: flex; align-items: center; justify-content: space-between; gap: 16px;