@flamingo-stack/openframe-frontend-core 0.0.506 → 0.0.507

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.
Files changed (105) hide show
  1. package/dist/{chunk-SQ63ZQLT.cjs → chunk-2F44PLTV.cjs} +26 -26
  2. package/dist/{chunk-SQ63ZQLT.cjs.map → chunk-2F44PLTV.cjs.map} +1 -1
  3. package/dist/{chunk-Y6M3AEI7.cjs → chunk-3SQ5KXHQ.cjs} +9 -9
  4. package/dist/{chunk-Y6M3AEI7.cjs.map → chunk-3SQ5KXHQ.cjs.map} +1 -1
  5. package/dist/{chunk-AZE46XSR.js → chunk-4LTMXDUS.js} +2 -2
  6. package/dist/{chunk-YEJ362MY.cjs → chunk-7LEL3RIX.cjs} +11 -11
  7. package/dist/{chunk-YEJ362MY.cjs.map → chunk-7LEL3RIX.cjs.map} +1 -1
  8. package/dist/{chunk-B3BWWXPM.js → chunk-ADPMHWOE.js} +4 -4
  9. package/dist/{chunk-CQAW3SDE.cjs → chunk-CWAOV2FK.cjs} +3 -3
  10. package/dist/{chunk-CQAW3SDE.cjs.map → chunk-CWAOV2FK.cjs.map} +1 -1
  11. package/dist/{chunk-BURDGVZD.js → chunk-DTYRYB2N.js} +2 -2
  12. package/dist/{chunk-4VSGKDJ4.js → chunk-I64ABCDX.js} +2 -2
  13. package/dist/{chunk-BCYKMY3I.js → chunk-KEBYLU3U.js} +2 -2
  14. package/dist/{chunk-A7KQNCTH.cjs → chunk-LDTR4IVZ.cjs} +31 -31
  15. package/dist/{chunk-A7KQNCTH.cjs.map → chunk-LDTR4IVZ.cjs.map} +1 -1
  16. package/dist/{chunk-VYQGUX3N.js → chunk-LRGHJPET.js} +2 -2
  17. package/dist/{chunk-TMIBSWAU.cjs → chunk-M2GOR3XQ.cjs} +87 -87
  18. package/dist/{chunk-TMIBSWAU.cjs.map → chunk-M2GOR3XQ.cjs.map} +1 -1
  19. package/dist/{chunk-WWBKSPJO.cjs → chunk-NIZDKTGL.cjs} +37 -37
  20. package/dist/{chunk-WWBKSPJO.cjs.map → chunk-NIZDKTGL.cjs.map} +1 -1
  21. package/dist/{chunk-ZTD6CFEX.js → chunk-OCEKO5CW.js} +27 -5
  22. package/dist/{chunk-JRSZ42PQ.cjs.map → chunk-OCEKO5CW.js.map} +1 -1
  23. package/dist/{chunk-ZBPJTMB4.js → chunk-PAGKRNWK.js} +2 -2
  24. package/dist/{chunk-FVVRY6RF.cjs → chunk-POOMO3PA.cjs} +7 -7
  25. package/dist/{chunk-FVVRY6RF.cjs.map → chunk-POOMO3PA.cjs.map} +1 -1
  26. package/dist/{chunk-774WVTFA.cjs → chunk-QTYZMP6D.cjs} +61 -61
  27. package/dist/{chunk-774WVTFA.cjs.map → chunk-QTYZMP6D.cjs.map} +1 -1
  28. package/dist/{chunk-PMKDB5ER.cjs → chunk-RHGGEKPQ.cjs} +4 -4
  29. package/dist/{chunk-PMKDB5ER.cjs.map → chunk-RHGGEKPQ.cjs.map} +1 -1
  30. package/dist/{chunk-FYZLCTAM.js → chunk-TBMV7I5N.js} +2 -2
  31. package/dist/{chunk-DCVKIZTV.js → chunk-TLMJHMXJ.js} +6 -6
  32. package/dist/{chunk-GYN7LLWZ.js → chunk-TSZHM74B.js} +2 -2
  33. package/dist/{chunk-JRSZ42PQ.cjs → chunk-TWYNR4TZ.cjs} +64 -42
  34. package/dist/chunk-TWYNR4TZ.cjs.map +1 -0
  35. package/dist/{chunk-SGHHM6NW.js → chunk-TZRUCD56.js} +5 -5
  36. package/dist/{chunk-LFPRWMH3.js → chunk-WA7RR64F.js} +4 -4
  37. package/dist/{chunk-LQ3DUGVD.js → chunk-WJQHJD7J.js} +2 -2
  38. package/dist/{chunk-EL6RLGC3.cjs → chunk-WK4N5VBX.cjs} +26 -26
  39. package/dist/{chunk-EL6RLGC3.cjs.map → chunk-WK4N5VBX.cjs.map} +1 -1
  40. package/dist/{chunk-CHMQNFBG.cjs → chunk-Z42BGM6Q.cjs} +5 -5
  41. package/dist/{chunk-CHMQNFBG.cjs.map → chunk-Z42BGM6Q.cjs.map} +1 -1
  42. package/dist/{chunk-JXFRUYTX.cjs → chunk-ZSQHZYCO.cjs} +13 -13
  43. package/dist/{chunk-JXFRUYTX.cjs.map → chunk-ZSQHZYCO.cjs.map} +1 -1
  44. package/dist/components/case-studies/index.cjs +8 -8
  45. package/dist/components/case-studies/index.js +2 -2
  46. package/dist/components/chat/index.cjs +2 -2
  47. package/dist/components/chat/index.js +1 -1
  48. package/dist/components/contact/index.cjs +3 -3
  49. package/dist/components/contact/index.js +2 -2
  50. package/dist/components/docs/index.cjs +5 -5
  51. package/dist/components/docs/index.js +4 -4
  52. package/dist/components/embeds/index.cjs +3 -3
  53. package/dist/components/embeds/index.js +2 -2
  54. package/dist/components/faq/index.cjs +3 -3
  55. package/dist/components/faq/index.js +2 -2
  56. package/dist/components/features/floating-walkthrough-video.d.ts +18 -1
  57. package/dist/components/features/floating-walkthrough-video.d.ts.map +1 -1
  58. package/dist/components/features/index.cjs +2 -2
  59. package/dist/components/features/index.js +1 -1
  60. package/dist/components/help-center-pages/index.cjs +22 -22
  61. package/dist/components/help-center-pages/index.js +13 -13
  62. package/dist/components/index.cjs +132 -132
  63. package/dist/components/index.js +11 -11
  64. package/dist/components/meeting-scheduler/index.cjs +34 -34
  65. package/dist/components/meeting-scheduler/index.js +3 -3
  66. package/dist/components/navigation/index.cjs +2 -2
  67. package/dist/components/navigation/index.js +1 -1
  68. package/dist/components/onboarding-guides/index.cjs +5 -5
  69. package/dist/components/onboarding-guides/index.js +4 -4
  70. package/dist/components/related-content/index.cjs +3 -3
  71. package/dist/components/related-content/index.js +2 -2
  72. package/dist/components/tickets/index.cjs +6 -6
  73. package/dist/components/tickets/index.js +5 -5
  74. package/dist/components/ui/index.cjs +2 -2
  75. package/dist/components/ui/index.js +1 -1
  76. package/dist/index.cjs +6 -2
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.js +5 -1
  79. package/dist/utils/index.cjs +8 -0
  80. package/dist/utils/index.cjs.map +1 -1
  81. package/dist/utils/index.d.ts +1 -0
  82. package/dist/utils/index.d.ts.map +1 -1
  83. package/dist/utils/index.js +7 -1
  84. package/dist/utils/index.js.map +1 -1
  85. package/dist/utils/walkthrough-deep-link.d.ts +15 -0
  86. package/dist/utils/walkthrough-deep-link.d.ts.map +1 -0
  87. package/package.json +1 -1
  88. package/src/components/features/.floating-walkthrough-video.md +38 -0
  89. package/src/components/features/floating-walkthrough-video.tsx +60 -5
  90. package/src/utils/index.ts +2 -0
  91. package/src/utils/walkthrough-deep-link.ts +18 -0
  92. package/dist/chunk-ZTD6CFEX.js.map +0 -1
  93. /package/dist/{chunk-AZE46XSR.js.map → chunk-4LTMXDUS.js.map} +0 -0
  94. /package/dist/{chunk-B3BWWXPM.js.map → chunk-ADPMHWOE.js.map} +0 -0
  95. /package/dist/{chunk-BURDGVZD.js.map → chunk-DTYRYB2N.js.map} +0 -0
  96. /package/dist/{chunk-4VSGKDJ4.js.map → chunk-I64ABCDX.js.map} +0 -0
  97. /package/dist/{chunk-BCYKMY3I.js.map → chunk-KEBYLU3U.js.map} +0 -0
  98. /package/dist/{chunk-VYQGUX3N.js.map → chunk-LRGHJPET.js.map} +0 -0
  99. /package/dist/{chunk-ZBPJTMB4.js.map → chunk-PAGKRNWK.js.map} +0 -0
  100. /package/dist/{chunk-FYZLCTAM.js.map → chunk-TBMV7I5N.js.map} +0 -0
  101. /package/dist/{chunk-DCVKIZTV.js.map → chunk-TLMJHMXJ.js.map} +0 -0
  102. /package/dist/{chunk-GYN7LLWZ.js.map → chunk-TSZHM74B.js.map} +0 -0
  103. /package/dist/{chunk-SGHHM6NW.js.map → chunk-TZRUCD56.js.map} +0 -0
  104. /package/dist/{chunk-LFPRWMH3.js.map → chunk-WA7RR64F.js.map} +0 -0
  105. /package/dist/{chunk-LQ3DUGVD.js.map → chunk-WJQHJD7J.js.map} +0 -0
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Walkthrough-video deep link — the ONE home for the query param that opens
3
+ * the floating walkthrough widget's theater full-screen (paused) on page
4
+ * load. Consumed by the widget itself (`FloatingWalkthroughVideo` defaults
5
+ * its `deepLinkParam` prop to this) and by hosts that MINT deep-link URLs
6
+ * (invitation emails) or carry the param across redirects (the hub's
7
+ * auth-wall proxy). Lives beside `dismissal-storage.ts` — the same
8
+ * widget-adjacent naming-layer altitude.
9
+ */
10
+ /** `?walkthrough=1` — presence-based on the read side (any value counts);
11
+ * `=1` is just the canonical value URL minters write. */
12
+ export declare const WALKTHROUGH_OPEN_QUERY_PARAM = "walkthrough";
13
+ /** Append the theater deep-link param to a URL (absolute or relative). */
14
+ export declare function withWalkthroughOpenParam(url: string): string;
15
+ //# sourceMappingURL=walkthrough-deep-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walkthrough-deep-link.d.ts","sourceRoot":"","sources":["../../src/utils/walkthrough-deep-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;0DAC0D;AAC1D,eAAO,MAAM,4BAA4B,gBAAgB,CAAC;AAE1D,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.506",
3
+ "version": "0.0.507",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,38 @@
1
+ <!-- source-hash: 47c31b34796bb8d1bc274d1012e9c9e3 -->
2
+ Floating per-platform walkthrough/demo video widget. Renders a collapsed corner card (hover preview, transport controls, cookie dismissal) that opens a pure-theater dialog — a centered 16:9 stage on a dimmed backdrop. The host supplies the video data and the current pathname; the widget owns every playback state handoff between card, hover preview, and theater.
3
+
4
+ ## Key Components
5
+
6
+ ### Exports
7
+
8
+ - **`FloatingWalkthroughVideo`** — The widget. Controlled (`open` + `onOpenChange`) or uncontrolled (`defaultOpen`) theater state.
9
+ - **`WalkthroughVideoData`** — Wire-shape contract: `mainVideoUrl` / `youtubeUrl` (YouTube wins when both are set), `posterUrl`, `captionsUrl` (relative `/api/captions/...` path), `title`, `presenterAvatarUrl`, `position` (`'left' | 'right'` bottom-corner pin), `id` (drives id-match cookie dismissal — a new video re-shows a dismissed card).
10
+ - **`FloatingWalkthroughVideoProps`** — See behaviors below for the non-obvious ones.
11
+
12
+ ### Key Behaviors
13
+
14
+ - **Appear gate**: the collapsed card mounts after `appearDelayMs` (default 3000 ms) + an idle callback, and never renders when dismissed. The THEATER is deliberately NOT gated — a host `open={true}` or `defaultOpen` can force it before the card appears or after dismissal, which is what makes deep links work.
15
+ - **`deepLinkParam`** — query-param NAME (defaults to `WALKTHROUGH_OPEN_QUERY_PARAM`, `'walkthrough'`, from `utils/walkthrough-deep-link.ts`; pass `''` to disable): when present in `window.location.search` at first client render, the theater opens immediately and PAUSED — `defaultOpen + defaultOpenPaused` decided inside the component, so hosts don't defer their first render to read the URL. Presence-based, read once (deep links arrive by full page load). SSR-safe: the server renders closed and the theater lives in a portal. URL minters (emails, redirects) use the sibling `withWalkthroughOpenParam(url)`.
16
+ - **`defaultOpenPaused`** — with `defaultOpen`, the initial theater session starts PAUSED instead of autoplaying. For deep links (e.g. the hub's `?walkthrough=1`), where the open has no user gesture and unrequested audio/motion would be hostile. File player: both autoplay flags suppressed (MuxPlayer mounts paused on its poster). YouTube: `autoActivate` suppressed instead — the activated iframe hardcodes `autoplay=1`, so the click-to-play facade IS the paused presentation. The paused session is exactly the initial `defaultOpen` theater: it ends when the NEXT (gesture- or host-driven) open mounts a fresh theater, which autoplays as usual. It is deliberately NOT cleared on close — the closing player stays mounted through the dialog's exit animation, and a prop flip there would restart playback.
17
+ - **Resume handoff**: closing the theater mid-play hands the timestamp + mute intent back to the card, which continues playback inline; reopening seeds the theater from the live card position. A finished video reopens at 0, not its own last frame.
18
+ - **Dismissal**: cookie-based, id-matched (mirrors the announcement bar). `dismissal={false}` removes the X entirely; `dismissal.storageKey` is the per-platform cookie name (see `walkthroughDismissCookieName`).
19
+ - **`pathname`**: route identity from the host — the lib can't observe navigation. Changing it re-queries the footer IntersectionObserver target (`hideNearSelector`, default `footer`) that fades the card out over the footer.
20
+
21
+ ## Usage Example
22
+
23
+ ```typescript
24
+ // Host layout (hub: components/shared/global-walkthrough-video-client.tsx)
25
+ <FloatingWalkthroughVideo
26
+ video={video}
27
+ pathname={pathname}
28
+ // Deep link (?walkthrough=1) is built in: `deepLinkParam` defaults to
29
+ // WALKTHROUGH_OPEN_QUERY_PARAM — theater opens immediately, PAUSED.
30
+ dismissal={{ storageKey: walkthroughDismissCookieName(platform) }}
31
+ />
32
+ ```
33
+
34
+ > **Deep-link contract:** prefer `deepLinkParam` — the component reads the URL itself at the right moment. If a host drives `defaultOpen` manually instead, it is a load-time value: decide it BEFORE the component's first render, not by flipping a prop afterwards.
35
+
36
+ ## Source
37
+
38
+ [`floating-walkthrough-video.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/openframe-frontend-core/src/components/features/floating-walkthrough-video.tsx)
@@ -57,6 +57,7 @@ import {
57
57
  isWalkthroughDismissed,
58
58
  dismissWalkthrough,
59
59
  } from '../../utils/dismissal-storage';
60
+ import { WALKTHROUGH_OPEN_QUERY_PARAM } from '../../utils/walkthrough-deep-link';
60
61
 
61
62
  /** Wire-shape data for the widget. Kept as the shared contract the hub DAL
62
63
  * re-exports as `PublicWalkthroughVideo & { id }`. `mainVideoUrl`/`youtubeUrl`
@@ -82,6 +83,23 @@ export interface FloatingWalkthroughVideoProps {
82
83
  open?: boolean;
83
84
  onOpenChange?: (open: boolean) => void;
84
85
  defaultOpen?: boolean;
86
+ /** With `defaultOpen`: the initial theater starts PAUSED instead of
87
+ * autoplaying — for deep links (`?walkthrough=1`), where the open has no
88
+ * user gesture and unrequested audio/motion would be hostile. Applies to
89
+ * the initial `defaultOpen` session only: it ends when the NEXT open —
90
+ * gesture-driven (card click) or host-driven (`open` flipping true) —
91
+ * mounts a fresh theater, which autoplays as usual. */
92
+ defaultOpenPaused?: boolean;
93
+ /** Query-param NAME that deep-links into the theater: when present in
94
+ * `window.location.search` at first client render, the theater opens
95
+ * immediately and PAUSED — `defaultOpen + defaultOpenPaused` decided
96
+ * inside the component, so hosts don't defer their first render to read
97
+ * the URL. Defaults to `WALKTHROUGH_OPEN_QUERY_PARAM` ('walkthrough');
98
+ * pass '' to disable. Presence-based (any value counts), read ONCE at
99
+ * mount (deep links arrive by full page load, not client navigation).
100
+ * SSR-safe: the server renders closed, and the theater lives in a portal,
101
+ * so the hydrated (non-portal) markup is identical either way. */
102
+ deepLinkParam?: string;
85
103
  label?: string;
86
104
  appearDelayMs?: number;
87
105
  /** Cookie-based dismissal (id-match, mirrors the announcement bar). `false`
@@ -111,6 +129,8 @@ export function FloatingWalkthroughVideo({
111
129
  open: openProp,
112
130
  onOpenChange,
113
131
  defaultOpen,
132
+ defaultOpenPaused,
133
+ deepLinkParam = WALKTHROUGH_OPEN_QUERY_PARAM,
114
134
  label = 'Play Demo Video',
115
135
  appearDelayMs = 3000,
116
136
  dismissal = {},
@@ -171,8 +191,29 @@ export function FloatingWalkthroughVideo({
171
191
  }, []);
172
192
 
173
193
  // --- controlled/uncontrolled open ---
174
- const [openState, setOpenState] = useState(Boolean(defaultOpen));
194
+ // Deep link: read ONCE, synchronously, on the first client render — the
195
+ // theater's autoplay props are load-time, so the decision must exist before
196
+ // the render that mounts it (an effect would be one commit too late). The
197
+ // lazy initializer never re-runs, so client navigation can't re-trigger it.
198
+ const [deepLinkHit] = useState(() => {
199
+ if (!deepLinkParam || typeof window === 'undefined') return false;
200
+ try {
201
+ return new URLSearchParams(window.location.search).has(deepLinkParam);
202
+ } catch {
203
+ return false;
204
+ }
205
+ });
206
+ const [openState, setOpenState] = useState(Boolean(defaultOpen) || deepLinkHit);
175
207
  const open = openProp !== undefined ? openProp : openState;
208
+ // The paused deep-link session — see `defaultOpenPaused`. Load-time-safe:
209
+ // the theater player's autoplay props are read once at construction, and
210
+ // this is set before the first render that mounts it. Cleared on the next
211
+ // OPEN transition only (the prevOpen sync below), right before a fresh
212
+ // theater constructs — never on close, where the closing player is still
213
+ // mounted and a prop flip would restart it (see the sync's comment).
214
+ const [pausedOpenSession, setPausedOpenSession] = useState(
215
+ Boolean(defaultOpen && defaultOpenPaused) || deepLinkHit,
216
+ );
176
217
 
177
218
  // --- refs & continuation state ---
178
219
  const previewHandleRef = useRef<VideoPlayerHandle | null>(null);
@@ -400,6 +441,16 @@ export function FloatingWalkthroughVideo({
400
441
  const [prevOpen, setPrevOpen] = useState(open);
401
442
  if (open !== prevOpen) {
402
443
  setPrevOpen(open);
444
+ // RISING edge only: the paused deep-link session ends when the NEXT
445
+ // (gesture- or host-driven) open mounts a fresh theater — this re-render
446
+ // commits the cleared flag before that content constructs, so it
447
+ // autoplays as usual. NEVER clear on close: Radix keeps the closing
448
+ // theater mounted through its exit animation, and flipping the flag then
449
+ // flips `autoPlayUnmuted` false→true on the STILL-MOUNTED player, whose
450
+ // autoplay kick effect resurrects playback — audible after close and
451
+ // doubled against the card's resume player. Idempotent, so a
452
+ // discarded-and-retried render attempt decides the same way.
453
+ if (open && pausedOpenSession) setPausedOpenSession(false);
403
454
  // Compared, not cleared: React can discard and re-run a render attempt
404
455
  // (concurrent interruption, error retry, a host wrapping setOpen in
405
456
  // startTransition). A read-and-clear would decide differently on the
@@ -874,11 +925,15 @@ export function FloatingWalkthroughVideo({
874
925
  playerHandleRef={theaterHandleRef}
875
926
  // Muted still means PLAYING: without this a deliberately muted
876
927
  // card opened a paused theater, breaking parity with the
877
- // unmuted path.
878
- autoPlay={theaterStart.muted}
879
- autoPlayUnmuted={!theaterStart.muted}
928
+ // unmuted path. EXCEPT the paused deep-link session, which
929
+ // starts fully stopped: no autoplay flag at all, and for
930
+ // YouTube no autoActivate either — the activated iframe
931
+ // hardcodes `autoplay=1`, so staying on the facade IS the
932
+ // paused presentation (clicking it activates and plays).
933
+ autoPlay={theaterStart.muted && !pausedOpenSession}
934
+ autoPlayUnmuted={!theaterStart.muted && !pausedOpenSession}
880
935
  startMuted={theaterStart.muted}
881
- autoActivate
936
+ autoActivate={!pausedOpenSession}
882
937
  suspended={suspended}
883
938
  onMutedFallbackChange={st => { theaterForcedMuteRef.current = st.muted; }}
884
939
  onEnded={() => { endedLatchRef.current = true; }}
@@ -96,6 +96,8 @@ export * from './announcement-storage'
96
96
  // cookie id-match dismissal store (walkthrough video widget)
97
97
  export * from './dismiss-cookie'
98
98
  export * from './dismissal-storage'
99
+ // walkthrough deep-link query param (widget default + host URL minters)
100
+ export * from './walkthrough-deep-link'
99
101
 
100
102
  // Image-proxy URL builder (pure, runtime-configurable)
101
103
  export {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Walkthrough-video deep link — the ONE home for the query param that opens
3
+ * the floating walkthrough widget's theater full-screen (paused) on page
4
+ * load. Consumed by the widget itself (`FloatingWalkthroughVideo` defaults
5
+ * its `deepLinkParam` prop to this) and by hosts that MINT deep-link URLs
6
+ * (invitation emails) or carry the param across redirects (the hub's
7
+ * auth-wall proxy). Lives beside `dismissal-storage.ts` — the same
8
+ * widget-adjacent naming-layer altitude.
9
+ */
10
+
11
+ /** `?walkthrough=1` — presence-based on the read side (any value counts);
12
+ * `=1` is just the canonical value URL minters write. */
13
+ export const WALKTHROUGH_OPEN_QUERY_PARAM = 'walkthrough';
14
+
15
+ /** Append the theater deep-link param to a URL (absolute or relative). */
16
+ export function withWalkthroughOpenParam(url: string): string {
17
+ return `${url}${url.includes('?') ? '&' : '?'}${WALKTHROUGH_OPEN_QUERY_PARAM}=1`;
18
+ }