@flamingo-stack/openframe-frontend-core 0.0.472 → 0.0.473-snapshot.20260724114839

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 (132) hide show
  1. package/dist/{chunk-4BUX2F5P.cjs → chunk-2R5NM3FC.cjs} +40 -40
  2. package/dist/{chunk-4BUX2F5P.cjs.map → chunk-2R5NM3FC.cjs.map} +1 -1
  3. package/dist/{chunk-BY6TZ6KA.js → chunk-3NNCBZEM.js} +6 -6
  4. package/dist/{chunk-WD7SE532.cjs → chunk-464NJS2W.cjs} +73 -73
  5. package/dist/{chunk-WD7SE532.cjs.map → chunk-464NJS2W.cjs.map} +1 -1
  6. package/dist/{chunk-KZZCBQDU.cjs → chunk-5TQQ3CPE.cjs} +29 -29
  7. package/dist/{chunk-KZZCBQDU.cjs.map → chunk-5TQQ3CPE.cjs.map} +1 -1
  8. package/dist/{chunk-ONK4D4LG.cjs → chunk-6KD6KVAI.cjs} +5 -5
  9. package/dist/{chunk-ONK4D4LG.cjs.map → chunk-6KD6KVAI.cjs.map} +1 -1
  10. package/dist/{chunk-73CH4CZL.cjs → chunk-7VBGYCXG.cjs} +7 -7
  11. package/dist/{chunk-73CH4CZL.cjs.map → chunk-7VBGYCXG.cjs.map} +1 -1
  12. package/dist/{chunk-FPOHUGEK.js → chunk-AGX565ZT.js} +2 -2
  13. package/dist/{chunk-RIEAXUJX.cjs → chunk-BOPLMNSN.cjs} +135 -174
  14. package/dist/chunk-BOPLMNSN.cjs.map +1 -0
  15. package/dist/{chunk-PJYGEXWM.js → chunk-FBUIZTAI.js} +2 -2
  16. package/dist/{chunk-HQL5GJ35.cjs → chunk-FM5KWLKU.cjs} +3 -3
  17. package/dist/{chunk-HQL5GJ35.cjs.map → chunk-FM5KWLKU.cjs.map} +1 -1
  18. package/dist/{chunk-YTLINJRR.cjs → chunk-GELW7JOQ.cjs} +32 -32
  19. package/dist/{chunk-YTLINJRR.cjs.map → chunk-GELW7JOQ.cjs.map} +1 -1
  20. package/dist/{chunk-TVMARS74.js → chunk-IIOHHNMI.js} +54 -93
  21. package/dist/chunk-IIOHHNMI.js.map +1 -0
  22. package/dist/{chunk-XNJ2LZH2.js → chunk-K52S6LZ5.js} +3 -3
  23. package/dist/{chunk-JO7XJQ6G.cjs → chunk-KPVKZ5ML.cjs} +15 -15
  24. package/dist/{chunk-JO7XJQ6G.cjs.map → chunk-KPVKZ5ML.cjs.map} +1 -1
  25. package/dist/{chunk-DWQ4L3IB.cjs → chunk-KXKTXAGN.cjs} +40 -40
  26. package/dist/{chunk-DWQ4L3IB.cjs.map → chunk-KXKTXAGN.cjs.map} +1 -1
  27. package/dist/{chunk-VC4FOIY7.cjs → chunk-LFXUFFDZ.cjs} +73 -73
  28. package/dist/{chunk-VC4FOIY7.cjs.map → chunk-LFXUFFDZ.cjs.map} +1 -1
  29. package/dist/{chunk-ZPUT2BB4.js → chunk-OKRUL7YV.js} +4 -4
  30. package/dist/{chunk-U5FNZ2TL.cjs → chunk-PFD2VRZI.cjs} +18 -18
  31. package/dist/{chunk-U5FNZ2TL.cjs.map → chunk-PFD2VRZI.cjs.map} +1 -1
  32. package/dist/{chunk-W6RDDT3S.js → chunk-PTFSF3UP.js} +6 -6
  33. package/dist/{chunk-74ZFCTRZ.js → chunk-R4OGP4OV.js} +3 -3
  34. package/dist/{chunk-7D5KOJMF.js → chunk-RIPWRVA3.js} +5 -5
  35. package/dist/{chunk-EK2VQXUN.js → chunk-S6IB3BZK.js} +2 -2
  36. package/dist/{chunk-OUHLWOPJ.js → chunk-SAH4FR36.js} +5 -5
  37. package/dist/{chunk-TONMD7QX.cjs → chunk-VCOL4C2W.cjs} +86 -20
  38. package/dist/chunk-VCOL4C2W.cjs.map +1 -0
  39. package/dist/{chunk-XDBNMB5K.js → chunk-VNDAMVMI.js} +2 -2
  40. package/dist/{chunk-CUBNUQPZ.cjs → chunk-YJWISFIK.cjs} +12 -12
  41. package/dist/{chunk-CUBNUQPZ.cjs.map → chunk-YJWISFIK.cjs.map} +1 -1
  42. package/dist/{chunk-NY4WLKNU.js → chunk-Z4LAZ4ZZ.js} +3 -3
  43. package/dist/{chunk-OTV4A6NA.js → chunk-ZPUZPJDV.js} +80 -14
  44. package/dist/chunk-ZPUZPJDV.js.map +1 -0
  45. package/dist/components/announcement-bar.d.ts +1 -1
  46. package/dist/components/announcement-bar.d.ts.map +1 -1
  47. package/dist/components/case-studies/index.cjs +9 -9
  48. package/dist/components/case-studies/index.js +3 -3
  49. package/dist/components/chat/index.cjs +3 -3
  50. package/dist/components/chat/index.js +2 -2
  51. package/dist/components/contact/index.cjs +4 -4
  52. package/dist/components/contact/index.js +3 -3
  53. package/dist/components/docs/index.cjs +6 -6
  54. package/dist/components/docs/index.js +5 -5
  55. package/dist/components/embeds/index.cjs +4 -4
  56. package/dist/components/embeds/index.js +3 -3
  57. package/dist/components/faq/index.cjs +5 -5
  58. package/dist/components/faq/index.js +4 -4
  59. package/dist/components/features/index.cjs +3 -3
  60. package/dist/components/features/index.js +2 -2
  61. package/dist/components/help-center-pages/index.cjs +22 -22
  62. package/dist/components/help-center-pages/index.js +13 -13
  63. package/dist/components/index.cjs +174 -162
  64. package/dist/components/index.cjs.map +1 -1
  65. package/dist/components/index.js +49 -37
  66. package/dist/components/index.js.map +1 -1
  67. package/dist/components/navigation/index.cjs +3 -3
  68. package/dist/components/navigation/index.js +2 -2
  69. package/dist/components/navigation/mobile-burger-menu.d.ts.map +1 -1
  70. package/dist/components/onboarding-guides/index.cjs +7 -7
  71. package/dist/components/onboarding-guides/index.js +6 -6
  72. package/dist/components/related-content/index.cjs +5 -5
  73. package/dist/components/related-content/index.js +4 -4
  74. package/dist/components/tickets/index.cjs +6 -6
  75. package/dist/components/tickets/index.js +5 -5
  76. package/dist/components/ui/announcement-bar-view.d.ts +26 -24
  77. package/dist/components/ui/announcement-bar-view.d.ts.map +1 -1
  78. package/dist/components/ui/entity-image.d.ts.map +1 -1
  79. package/dist/components/ui/image-uploader.d.ts.map +1 -1
  80. package/dist/components/ui/index.cjs +3 -3
  81. package/dist/components/ui/index.js +2 -2
  82. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
  83. package/dist/components/ui/square-avatar.d.ts.map +1 -1
  84. package/dist/hooks/index.cjs +6 -2
  85. package/dist/hooks/index.cjs.map +1 -1
  86. package/dist/hooks/index.d.ts +1 -0
  87. package/dist/hooks/index.d.ts.map +1 -1
  88. package/dist/hooks/index.js +5 -1
  89. package/dist/hooks/use-authed-image-src.d.ts +10 -0
  90. package/dist/hooks/use-authed-image-src.d.ts.map +1 -0
  91. package/dist/index.cjs +7 -3
  92. package/dist/index.cjs.map +1 -1
  93. package/dist/index.js +6 -2
  94. package/dist/types/announcement.cjs.map +1 -1
  95. package/dist/types/announcement.d.ts +5 -0
  96. package/dist/types/announcement.d.ts.map +1 -1
  97. package/dist/types/announcement.js.map +1 -1
  98. package/dist/types/index.cjs.map +1 -1
  99. package/dist/types/index.js.map +1 -1
  100. package/dist/utils/embed-authed-fetch.d.ts +15 -0
  101. package/dist/utils/embed-authed-fetch.d.ts.map +1 -1
  102. package/dist/utils/index.cjs.map +1 -1
  103. package/dist/utils/index.js.map +1 -1
  104. package/package.json +1 -1
  105. package/src/components/announcement-bar.tsx +58 -42
  106. package/src/components/navigation/mobile-burger-menu.tsx +1 -0
  107. package/src/components/ui/announcement-bar-view.tsx +42 -66
  108. package/src/components/ui/entity-image.tsx +5 -3
  109. package/src/components/ui/image-uploader.tsx +21 -12
  110. package/src/components/ui/simple-markdown-renderer.tsx +57 -58
  111. package/src/components/ui/square-avatar.tsx +5 -3
  112. package/src/hooks/index.ts +1 -0
  113. package/src/hooks/use-authed-image-src.ts +93 -0
  114. package/src/stories/AnnouncementBar.stories.tsx +20 -0
  115. package/src/types/announcement.ts +5 -0
  116. package/src/utils/embed-authed-fetch.ts +30 -0
  117. package/dist/chunk-OTV4A6NA.js.map +0 -1
  118. package/dist/chunk-RIEAXUJX.cjs.map +0 -1
  119. package/dist/chunk-TONMD7QX.cjs.map +0 -1
  120. package/dist/chunk-TVMARS74.js.map +0 -1
  121. /package/dist/{chunk-BY6TZ6KA.js.map → chunk-3NNCBZEM.js.map} +0 -0
  122. /package/dist/{chunk-FPOHUGEK.js.map → chunk-AGX565ZT.js.map} +0 -0
  123. /package/dist/{chunk-PJYGEXWM.js.map → chunk-FBUIZTAI.js.map} +0 -0
  124. /package/dist/{chunk-XNJ2LZH2.js.map → chunk-K52S6LZ5.js.map} +0 -0
  125. /package/dist/{chunk-ZPUT2BB4.js.map → chunk-OKRUL7YV.js.map} +0 -0
  126. /package/dist/{chunk-W6RDDT3S.js.map → chunk-PTFSF3UP.js.map} +0 -0
  127. /package/dist/{chunk-74ZFCTRZ.js.map → chunk-R4OGP4OV.js.map} +0 -0
  128. /package/dist/{chunk-7D5KOJMF.js.map → chunk-RIPWRVA3.js.map} +0 -0
  129. /package/dist/{chunk-EK2VQXUN.js.map → chunk-S6IB3BZK.js.map} +0 -0
  130. /package/dist/{chunk-OUHLWOPJ.js.map → chunk-SAH4FR36.js.map} +0 -0
  131. /package/dist/{chunk-XDBNMB5K.js.map → chunk-VNDAMVMI.js.map} +0 -0
  132. /package/dist/{chunk-NY4WLKNU.js.map → chunk-Z4LAZ4ZZ.js.map} +0 -0
@@ -0,0 +1,93 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useReducer } from 'react'
4
+ import { embedAuthedFetch, needsBearerAssetFetch } from '../utils/embed-authed-fetch'
5
+
6
+ /**
7
+ * Resolve an image URL for hosts whose auth rides in request headers
8
+ * instead of cookies (native shells — `capacitor://localhost`,
9
+ * `tauri://localhost` — running in bearer mode). A native `<img>` load
10
+ * can't carry an `Authorization` header, so a gateway image URL that
11
+ * works on the cookie-auth web 401s in a shell. When
12
+ * `needsBearerAssetFetch` says the URL's origin is bearer-authed, this
13
+ * hook fetches it through `embedAuthedFetch` (bearer + deduped
14
+ * 401-refresh-retry + the adapter's cross-origin guard) and returns a
15
+ * blob object-URL; every other URL is returned unchanged, so on the
16
+ * cookie-auth web the hook is a pass-through.
17
+ *
18
+ * Returns `undefined` while the fetch is in flight OR after it fails, so
19
+ * callers show their existing initials/placeholder fallback instead of a
20
+ * broken image; a failed fetch retries on the next mount.
21
+ *
22
+ * Cache: module-level, session-lifetime, keyed by full URL. Gateway image
23
+ * URLs carry a `?v=<content-hash>` cache-buster, so a changed image is a
24
+ * new key; entries are never revoked (avatars are a few KB — refcount
25
+ * churn isn't worth it).
26
+ *
27
+ * Distinct from the legacy `useAuthenticatedImage`, which ALWAYS
28
+ * blob-fetches with `credentials: 'include'` and its own global config.
29
+ * This hook is pass-through-first and keys off the single auth knob the
30
+ * lib already has: the registered `EmbedAuthAdapter`.
31
+ */
32
+
33
+ const resolvedCache = new Map<string, string>()
34
+ const inFlight = new Map<string, Promise<void>>()
35
+ let cacheGeneration = 0
36
+
37
+ /**
38
+ * Drop every cached blob and revoke its object URL. Hosts call this at
39
+ * session end (logout / forced re-login) so a follow-on login as a
40
+ * different identity cannot be served blobs fetched under the previous
41
+ * one's bearer. Fetches still in flight when the clear happens are fenced
42
+ * by a generation counter — their results are revoked instead of cached.
43
+ */
44
+ export function clearAuthedImageCache(): void {
45
+ cacheGeneration++
46
+ for (const url of resolvedCache.values()) URL.revokeObjectURL(url)
47
+ resolvedCache.clear()
48
+ inFlight.clear()
49
+ }
50
+
51
+ function fetchAsBlobUrl(src: string): Promise<void> {
52
+ let pending = inFlight.get(src)
53
+ if (!pending) {
54
+ const startedGeneration = cacheGeneration
55
+ pending = embedAuthedFetch(src, { headers: { Accept: 'image/*' } })
56
+ .then(async response => {
57
+ if (!response.ok) throw new Error(`image fetch failed: ${response.status}`)
58
+ const blobUrl = URL.createObjectURL(await response.blob())
59
+ if (startedGeneration === cacheGeneration) {
60
+ resolvedCache.set(src, blobUrl)
61
+ } else {
62
+ URL.revokeObjectURL(blobUrl)
63
+ }
64
+ })
65
+ .finally(() => {
66
+ if (inFlight.get(src) === pending) inFlight.delete(src)
67
+ })
68
+ inFlight.set(src, pending)
69
+ }
70
+ return pending
71
+ }
72
+
73
+ export function useAuthedImageSrc(src?: string | null): string | undefined {
74
+ const bearerSrc = src && needsBearerAssetFetch(src) ? src : null
75
+ const [, rerender] = useReducer((c: number) => c + 1, 0)
76
+
77
+ useEffect(() => {
78
+ if (!bearerSrc || resolvedCache.has(bearerSrc)) return
79
+ let cancelled = false
80
+ fetchAsBlobUrl(bearerSrc)
81
+ .catch(() => {})
82
+ .finally(() => {
83
+ if (!cancelled) rerender()
84
+ })
85
+ return () => {
86
+ cancelled = true
87
+ }
88
+ }, [bearerSrc])
89
+
90
+ if (!src) return undefined
91
+ if (!bearerSrc) return src
92
+ return resolvedCache.get(bearerSrc)
93
+ }
@@ -83,6 +83,26 @@ export const WithCTA: Story = {
83
83
  },
84
84
  }
85
85
 
86
+ /**
87
+ * Non-dismissible announcement — `dismissible={false}` drops the close (X)
88
+ * button, so the bar only disappears when the announcement is deactivated.
89
+ */
90
+ export const WithoutCloseButton: Story = {
91
+ args: {
92
+ dismissible: false,
93
+ initialAnnouncement: {
94
+ ...baseAnnouncement,
95
+ id: 'story-no-dismiss',
96
+ title: 'Mandatory Maintenance Notice',
97
+ description: 'This announcement cannot be dismissed by the user.',
98
+ cta_enabled: true,
99
+ cta_text: 'Learn More',
100
+ cta_url: 'https://example.com',
101
+ cta_target: '_blank',
102
+ },
103
+ },
104
+ }
105
+
86
106
  /**
87
107
  * Announcement with a CTA button that opens in the same tab.
88
108
  */
@@ -238,6 +238,11 @@ export interface AnnouncementBarProps {
238
238
  * cookies or touches localStorage).
239
239
  */
240
240
  previewMode?: boolean;
241
+ /**
242
+ * When false, the dismiss (X) button is not rendered — the bar can only
243
+ * disappear by deactivating the announcement. Default true.
244
+ */
245
+ dismissible?: boolean;
241
246
  className?: string;
242
247
  }
243
248
 
@@ -156,6 +156,36 @@ export function hasEmbedAuthAdapter(): boolean {
156
156
  return getRegisteredAuthAdapter() !== null
157
157
  }
158
158
 
159
+ /**
160
+ * Whether `url` is an asset the browser CANNOT load natively because its
161
+ * auth rides in request headers: the registered adapter is currently
162
+ * supplying an `Authorization` header AND the URL's origin is one the
163
+ * adapter explicitly sanctions for that bearer (`allowedOrigins` — the
164
+ * host's gateway, cross-origin by construction in native shells).
165
+ *
166
+ * Native asset loads (`<img src>`, CSS `background-image`) can't carry
167
+ * custom headers, so a URL this returns `true` for must go through
168
+ * `embedAuthedFetch` → blob object-URL instead (see `useAuthedImageSrc`).
169
+ * Everything else — cookie-auth web (no Authorization), relative /
170
+ * same-origin URLs (cookies work), third-party origins the bearer does
171
+ * NOT belong to (public images) — loads natively, unchanged.
172
+ */
173
+ export function needsBearerAssetFetch(url: string): boolean {
174
+ if (typeof window === 'undefined') return false
175
+ const adapter = getRegisteredAuthAdapter()
176
+ if (!adapter?.allowedOrigins?.length || adapter.getHeaders?.().Authorization === undefined) {
177
+ return false
178
+ }
179
+ let target: URL
180
+ try {
181
+ target = new URL(url, window.location.href)
182
+ } catch {
183
+ return false
184
+ }
185
+ if (target.protocol !== 'http:' && target.protocol !== 'https:') return false
186
+ return adapter.allowedOrigins.includes(target.origin)
187
+ }
188
+
159
189
  /**
160
190
  * `fetch` wrapper that attaches embed-proxy bearer headers (when
161
191
  * present in sessionStorage) and forces `credentials: 'same-origin'`