1- import React , { useState } from 'react' ;
2- import { View , Text , StyleSheet , TouchableOpacity , ScrollView , StatusBar , Dimensions } from 'react-native' ;
1+ import React , { useState , useRef , useEffect } from 'react' ;
2+ import { View , Text , StyleSheet , TouchableOpacity , ScrollView , StatusBar , Dimensions , Platform } from 'react-native' ;
33import { CLDVideoLayer } from '../src/widgets/video/layer/CLDVideoLayer' ;
44import { ButtonPosition , ButtonLayoutDirection } from '../src/widgets/video/layer/types' ;
55import { Cloudinary } from '@cloudinary/url-gen' ;
6+ import { Ionicons } from '@expo/vector-icons' ;
67
78interface ActiveLayerLayoutDemoProps {
89 onNavigateToYouTube ?: ( ) => void ;
@@ -11,6 +12,56 @@ interface ActiveLayerLayoutDemoProps {
1112
1213export const ActiveLayerLayoutDemo : React . FC < ActiveLayerLayoutDemoProps > = ( { onNavigateToYouTube, onBack } ) => {
1314 const [ currentExample , setCurrentExample ] = useState ( 'horizontal' ) ;
15+ const scrollViewRef = useRef < ScrollView > ( null ) ;
16+
17+ // Add mouse drag scrolling for web
18+ useEffect ( ( ) => {
19+ if ( Platform . OS === 'web' && scrollViewRef . current ) {
20+ const scrollElement = ( scrollViewRef . current as any ) . getScrollableNode ?.( ) ;
21+ if ( scrollElement ) {
22+ let isDown = false ;
23+ let startX = 0 ;
24+ let scrollLeft = 0 ;
25+
26+ const handleMouseDown = ( e : MouseEvent ) => {
27+ isDown = true ;
28+ scrollElement . style . cursor = 'grabbing' ;
29+ startX = e . pageX - scrollElement . offsetLeft ;
30+ scrollLeft = scrollElement . scrollLeft ;
31+ } ;
32+
33+ const handleMouseLeave = ( ) => {
34+ isDown = false ;
35+ scrollElement . style . cursor = 'grab' ;
36+ } ;
37+
38+ const handleMouseUp = ( ) => {
39+ isDown = false ;
40+ scrollElement . style . cursor = 'grab' ;
41+ } ;
42+
43+ const handleMouseMove = ( e : MouseEvent ) => {
44+ if ( ! isDown ) return ;
45+ e . preventDefault ( ) ;
46+ const x = e . pageX - scrollElement . offsetLeft ;
47+ const walk = ( x - startX ) * 2 ;
48+ scrollElement . scrollLeft = scrollLeft - walk ;
49+ } ;
50+
51+ scrollElement . addEventListener ( 'mousedown' , handleMouseDown ) ;
52+ scrollElement . addEventListener ( 'mouseleave' , handleMouseLeave ) ;
53+ scrollElement . addEventListener ( 'mouseup' , handleMouseUp ) ;
54+ scrollElement . addEventListener ( 'mousemove' , handleMouseMove ) ;
55+
56+ return ( ) => {
57+ scrollElement . removeEventListener ( 'mousedown' , handleMouseDown ) ;
58+ scrollElement . removeEventListener ( 'mouseleave' , handleMouseLeave ) ;
59+ scrollElement . removeEventListener ( 'mouseup' , handleMouseUp ) ;
60+ scrollElement . removeEventListener ( 'mousemove' , handleMouseMove ) ;
61+ } ;
62+ }
63+ }
64+ } , [ ] ) ;
1465
1566 // Create a sample video
1667 const cld = new Cloudinary ( {
@@ -246,25 +297,32 @@ export const ActiveLayerLayoutDemo: React.FC<ActiveLayerLayoutDemoProps> = ({ on
246297 { /* Professional Header */ }
247298 < View style = { styles . header } >
248299 < View style = { styles . headerContent } >
249- < View style = { styles . brandSection } >
250- < Text style = { styles . brandTitle } > Cloudinary Video SDK</ Text >
251- < Text style = { styles . brandSubtitle } > Interactive Button Layout Showcase</ Text >
252- </ View >
253-
254300 { onBack && (
255301 < TouchableOpacity style = { styles . backButton } onPress = { onBack } >
256- < Text style = { styles . backButtonText } > ← Back </ Text >
302+ < Ionicons name = "arrow-back" size = { 24 } color = "white" / >
257303 </ TouchableOpacity >
258304 ) }
305+
306+ < View style = { styles . brandSection } >
307+ < Text style = { styles . brandTitle } > Cloudinary Video SDK</ Text >
308+ < Text style = { styles . brandSubtitle } > Interactive Button Layout Showcase</ Text >
309+ </ View >
259310 </ View >
260311
261312 { /* Professional Example Selector */ }
262- < ScrollView
263- horizontal
264- showsHorizontalScrollIndicator = { false }
265- style = { styles . examplesContainer }
266- contentContainerStyle = { styles . examplesContent }
267- >
313+ < View style = { styles . scrollViewWrapper } >
314+ < ScrollView
315+ ref = { scrollViewRef }
316+ horizontal
317+ showsHorizontalScrollIndicator = { false }
318+ style = { styles . examplesContainer }
319+ contentContainerStyle = { styles . examplesContent }
320+ scrollEnabled = { true }
321+ nestedScrollEnabled = { true }
322+ { ...( Platform . OS === 'web' && {
323+ dataSet : { scrollable : 'true' }
324+ } ) }
325+ >
268326 { examples . map ( ( example , index ) => (
269327 < TouchableOpacity
270328 key = { example . id }
@@ -298,7 +356,8 @@ export const ActiveLayerLayoutDemo: React.FC<ActiveLayerLayoutDemoProps> = ({ on
298356 </ View >
299357 </ TouchableOpacity >
300358 ) ) }
301- </ ScrollView >
359+ </ ScrollView >
360+ </ View >
302361 </ View >
303362
304363 { /* Enhanced Video Player */ }
@@ -351,9 +410,9 @@ const styles = StyleSheet.create({
351410 } ,
352411 headerContent : {
353412 flexDirection : 'row' ,
354- justifyContent : 'space-between' ,
355413 alignItems : 'flex-start' ,
356414 marginBottom : 24 ,
415+ gap : 16 ,
357416 } ,
358417 brandSection : {
359418 flex : 1 ,
@@ -374,34 +433,63 @@ const styles = StyleSheet.create({
374433 opacity : 0.9 ,
375434 } ,
376435 backButton : {
377- backgroundColor : 'rgba(255, 255, 255, 0.1)' ,
378- paddingHorizontal : 20 ,
379- paddingVertical : 12 ,
380- borderRadius : 25 ,
381- borderWidth : 1 ,
382- borderColor : 'rgba(255, 255, 255, 0.2)' ,
436+ width : 40 ,
437+ height : 40 ,
438+ borderRadius : 20 ,
439+ backgroundColor : 'rgba(255, 255, 255, 0.15)' ,
440+ justifyContent : 'center' ,
441+ alignItems : 'center' ,
442+ shadowColor : '#000' ,
443+ shadowOffset : { width : 0 , height : 2 } ,
444+ shadowOpacity : 0.3 ,
445+ shadowRadius : 4 ,
446+ elevation : 5 ,
383447 } ,
384- backButtonText : {
385- color : '#ffffff' ,
386- fontSize : 16 ,
387- fontWeight : '600' ,
448+ scrollViewWrapper : {
449+ width : '100%' ,
450+ ...( Platform . OS === 'web' && {
451+ overflow : 'visible' as any ,
452+ } ) ,
388453 } ,
389454 examplesContainer : {
390455 flexGrow : 0 ,
456+ height : 160 ,
457+ ...( Platform . OS === 'web' ? {
458+ overflowX : 'auto' as any ,
459+ overflowY : 'hidden' as any ,
460+ WebkitOverflowScrolling : 'touch' as any ,
461+ scrollbarWidth : 'thin' as any ,
462+ scrollbarColor : 'rgba(255, 255, 255, 0.3) transparent' as any ,
463+ cursor : 'grab' as any ,
464+ userSelect : 'none' as any ,
465+ touchAction : 'pan-x' as any ,
466+ } : {
467+ flex : 1 ,
468+ } ) ,
391469 } ,
392470 examplesContent : {
393471 paddingLeft : 4 ,
472+ paddingRight : 20 ,
473+ flexDirection : 'row' ,
474+ alignItems : 'center' ,
475+ ...( Platform . OS === 'web' && {
476+ display : 'flex' as any ,
477+ width : 'auto' as any ,
478+ minWidth : '100%' as any ,
479+ } ) ,
394480 } ,
395481 exampleCard : {
396482 backgroundColor : 'rgba(255, 255, 255, 0.05)' ,
397483 borderRadius : 16 ,
398484 padding : 16 ,
399485 marginRight : 16 ,
400- width : SCREEN_WIDTH * 0.7 ,
486+ width : Platform . OS === 'web' ? 320 : SCREEN_WIDTH * 0.7 ,
487+ minWidth : Platform . OS === 'web' ? 320 : undefined ,
401488 borderWidth : 1 ,
402489 borderColor : 'rgba(255, 255, 255, 0.1)' ,
403490 flexDirection : 'row' ,
404491 alignItems : 'center' ,
492+ flexShrink : 0 ,
405493 } ,
406494 activeExampleCard : {
407495 backgroundColor : 'rgba(99, 102, 241, 0.2)' ,
0 commit comments