@flamingo-stack/openframe-frontend-core 0.0.269 → 0.0.270

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 (39) hide show
  1. package/dist/{chunk-TOQH27ZP.js → chunk-37OJ53QH.js} +2 -2
  2. package/dist/{chunk-FEIRH7ER.cjs → chunk-3H5TSZMU.cjs} +25 -25
  3. package/dist/{chunk-FEIRH7ER.cjs.map → chunk-3H5TSZMU.cjs.map} +1 -1
  4. package/dist/{chunk-HQGGXT2T.js → chunk-EMRSIP4Q.js} +2 -2
  5. package/dist/{chunk-NM7J44WP.cjs → chunk-JIJEVSCC.cjs} +30 -30
  6. package/dist/{chunk-NM7J44WP.cjs.map → chunk-JIJEVSCC.cjs.map} +1 -1
  7. package/dist/{chunk-QDA2XVFP.cjs → chunk-N3OPJQYI.cjs} +54 -22
  8. package/dist/chunk-N3OPJQYI.cjs.map +1 -0
  9. package/dist/{chunk-TZEHP5IW.cjs → chunk-NDSCF6LB.cjs} +11 -11
  10. package/dist/{chunk-TZEHP5IW.cjs.map → chunk-NDSCF6LB.cjs.map} +1 -1
  11. package/dist/{chunk-ALCUDWKJ.js → chunk-RM7ZT3UU.js} +162 -130
  12. package/dist/{chunk-ALCUDWKJ.js.map → chunk-RM7ZT3UU.js.map} +1 -1
  13. package/dist/{chunk-DATYABIL.js → chunk-XOKXFW77.js} +2 -2
  14. package/dist/components/chat/index.cjs +2 -2
  15. package/dist/components/chat/index.js +1 -1
  16. package/dist/components/contact/index.cjs +3 -3
  17. package/dist/components/contact/index.js +2 -2
  18. package/dist/components/features/index.cjs +2 -2
  19. package/dist/components/features/index.js +1 -1
  20. package/dist/components/features/video-source-selector.d.ts +11 -1
  21. package/dist/components/features/video-source-selector.d.ts.map +1 -1
  22. package/dist/components/index.cjs +47 -47
  23. package/dist/components/index.js +3 -3
  24. package/dist/components/navigation/index.cjs +2 -2
  25. package/dist/components/navigation/index.js +1 -1
  26. package/dist/components/related-content/index.cjs +3 -3
  27. package/dist/components/related-content/index.js +2 -2
  28. package/dist/components/tickets/index.cjs +53 -53
  29. package/dist/components/tickets/index.js +3 -3
  30. package/dist/components/ui/index.cjs +2 -2
  31. package/dist/components/ui/index.js +1 -1
  32. package/dist/index.cjs +2 -2
  33. package/dist/index.js +1 -1
  34. package/package.json +1 -1
  35. package/src/components/features/video-source-selector.tsx +83 -18
  36. package/dist/chunk-QDA2XVFP.cjs.map +0 -1
  37. /package/dist/{chunk-TOQH27ZP.js.map → chunk-37OJ53QH.js.map} +0 -0
  38. /package/dist/{chunk-HQGGXT2T.js.map → chunk-EMRSIP4Q.js.map} +0 -0
  39. /package/dist/{chunk-DATYABIL.js.map → chunk-XOKXFW77.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
- import React, { useState, useCallback } from 'react';
4
- import { Upload, Sparkles, X, Video } from 'lucide-react';
3
+ import React, { useState, useCallback, useEffect } from 'react';
4
+ import { Upload, Sparkles, X, Video, Loader2 } from 'lucide-react';
5
5
  import { Button } from '../ui/button';
6
6
  import { Input } from '../ui/input';
7
7
  import { Label } from '../ui/label';
@@ -47,6 +47,16 @@ export interface VideoSourceSelectorProps {
47
47
  onDelete: () => void;
48
48
  isAIGenerated?: boolean;
49
49
  }>;
50
+ /**
51
+ * Optional: resolve the uploaded video URL before it's handed to the DEFAULT
52
+ * `<video>` preview (no-op when a `VideoPreviewComponent` is supplied — that
53
+ * component owns its own rendering). Lets a consumer swap a URL that a native
54
+ * `<video>` can't play — e.g. a Mux HLS manifest (`stream.mux.com/{id}.m3u8`),
55
+ * which Chrome/Firefox/Edge can't play natively — for a playable MP4. Without
56
+ * it the URL is used as-is (backward compatible). A rejected resolve degrades
57
+ * gracefully to the original URL.
58
+ */
59
+ resolveVideoUrl?: (url: string) => Promise<string>;
50
60
  /** Optional: Upload progress bar component */
51
61
  UploadProgressComponent?: React.ComponentType<{
52
62
  progress: number;
@@ -84,6 +94,7 @@ export function VideoSourceSelector({
84
94
  uploadEmptyText = 'No video uploaded yet. Click "Upload Video" to add one.',
85
95
  disabled = false,
86
96
  VideoPreviewComponent,
97
+ resolveVideoUrl,
87
98
  UploadProgressComponent,
88
99
  title = 'Video',
89
100
  showTitle = true,
@@ -247,22 +258,13 @@ export function VideoSourceSelector({
247
258
  isAIGenerated={isAIGenerated}
248
259
  />
249
260
  ) : (
250
- // Default simple preview
251
- <div className="relative rounded-lg border border-ods-border overflow-hidden">
252
- <video
253
- src={mainVideoUrl}
254
- className="w-full h-auto max-h-[300px] object-contain bg-black"
255
- controls
256
- />
257
- <button
258
- type="button"
259
- onClick={handleDeleteVideo}
260
- className="absolute top-2 right-2 p-1.5 bg-black/60 hover:bg-black/80 rounded-full transition-colors"
261
- disabled={disabled}
262
- >
263
- <X className="h-4 w-4 text-white" />
264
- </button>
265
- </div>
261
+ // Default simple preview (resolver-aware — see DefaultVideoPreview)
262
+ <DefaultVideoPreview
263
+ videoUrl={mainVideoUrl}
264
+ resolveVideoUrl={resolveVideoUrl}
265
+ onDelete={handleDeleteVideo}
266
+ disabled={disabled}
267
+ />
266
268
  )
267
269
  ) : (
268
270
  <p className="text-sm text-ods-text-secondary italic">
@@ -275,4 +277,67 @@ export function VideoSourceSelector({
275
277
  );
276
278
  }
277
279
 
280
+ interface DefaultVideoPreviewProps {
281
+ /** Uploaded video URL (possibly an HLS manifest a native `<video>` can't play). */
282
+ videoUrl: string;
283
+ /** Optional resolver → playable MP4 URL; omit for as-is (backward-compatible) behaviour. */
284
+ resolveVideoUrl?: (url: string) => Promise<string>;
285
+ onDelete: () => void;
286
+ disabled?: boolean;
287
+ }
288
+
289
+ /**
290
+ * Default `<video>` preview for {@link VideoSourceSelector} when no
291
+ * `VideoPreviewComponent` is supplied. When `resolveVideoUrl` is provided the URL
292
+ * is resolved (e.g. Mux HLS → MP4) before it reaches the native `<video>`, which
293
+ * can't play HLS on Chrome/Firefox/Edge; a rejected resolve degrades to the
294
+ * original URL. Without a resolver the URL is used synchronously, unchanged.
295
+ */
296
+ function DefaultVideoPreview({ videoUrl, resolveVideoUrl, onDelete, disabled }: DefaultVideoPreviewProps) {
297
+ // `undefined` only while an async resolve is in flight (first paint); otherwise
298
+ // the (possibly resolved) URL. Synchronous passthrough when there's no resolver.
299
+ const [resolvedUrl, setResolvedUrl] = useState<string | undefined>(
300
+ resolveVideoUrl ? undefined : videoUrl,
301
+ );
302
+
303
+ useEffect(() => {
304
+ if (!resolveVideoUrl) {
305
+ setResolvedUrl(videoUrl);
306
+ return;
307
+ }
308
+ // Guard against a late resolve overwriting a newer URL / unmounted preview.
309
+ let active = true;
310
+ setResolvedUrl(undefined);
311
+ resolveVideoUrl(videoUrl)
312
+ .then((url) => { if (active) setResolvedUrl(url); })
313
+ .catch(() => { if (active) setResolvedUrl(videoUrl); });
314
+ return () => { active = false; };
315
+ }, [videoUrl, resolveVideoUrl]);
316
+
317
+ return (
318
+ <div className="relative rounded-lg border border-ods-border overflow-hidden">
319
+ {resolvedUrl === undefined ? (
320
+ <div className="w-full h-[200px] flex items-center justify-center bg-black">
321
+ <Loader2 className="h-6 w-6 animate-spin text-ods-accent" />
322
+ </div>
323
+ ) : (
324
+ <video
325
+ src={resolvedUrl}
326
+ className="w-full h-auto max-h-[300px] object-contain bg-black"
327
+ controls
328
+ />
329
+ )}
330
+ <button
331
+ type="button"
332
+ onClick={onDelete}
333
+ aria-label="Delete video"
334
+ className="absolute top-2 right-2 p-1.5 bg-black/60 hover:bg-black/80 rounded-full transition-colors"
335
+ disabled={disabled}
336
+ >
337
+ <X className="h-4 w-4 text-white" />
338
+ </button>
339
+ </div>
340
+ );
341
+ }
342
+
278
343
  export default VideoSourceSelector;