Embedded Clips#
Configuring a Storyteller Embedded Clips Component#
The Storyteller SDK provides a component to embed a clips experience in your layout.
Props#
interface Configuration {
collection?: string;
category?: string;
clipId?: string;
openedReason?: string;
topInsets?: number; // Android only
}
interface TopLevelBackTappedEvent {
canGoBack: boolean;
}
interface DataLoadCompletedEvent {
success: boolean;
error: string;
dataCount: number;
}
interface CanGoBackChangedEvent {
canGoBack: boolean;
}
// Component Props
configuration?: Configuration;
topLevelBackButtonEnabled?: boolean;
onTopLevelBackTapped?: (event: TopLevelBackTappedEvent) => void;
onDataLoadStarted?: () => void;
onDataLoadCompleted?: (event: DataLoadCompletedEvent) => void;
onCanGoBackChanged?: (event: CanGoBackChangedEvent) => void;
style?: ViewStyle;
To customize the layout of a component you can use the following props:
-
configuration.collection: the collection ID to be displayed -
configuration.category: specify whichcategoryto show when opening the collection. Ifcategoryis not specified or the wrong value is set, we default to the first clip -
configuration.clipId: specify whichclipIdto show when opening the collection. IfclipIdis not specified or the wrong value is set, we default to the first clip -
configuration.openedReason- specify the reason why collection was reloaded which is used for analytics. Ifnil, thenopenedReasonwill be handled internally. -
configuration.topInsets- specify the top insets of the Clips view. This is useful when the Clips view is embedded in a view that has a top inset, such as a tab bar. This property is only available on Android. -
topLevelBackButtonEnabled- whether the back button should be displayed when the player is at the top level of the collection. Defaults totrue -
onDataLoadStarted?: () => void- use it to show any loading indicators, like a spinning wheel on a tab bar item. -
onDataLoadCompleted?: (event: DataLoadCompletedEvent) => void- this callback tells you that loading the data has finished. The event containssuccess(boolean),error(string), anddataCount(number) properties. -
onTopLevelBackTapped?: (event: TopLevelBackTappedEvent) => void- in case you settopLevelBackButtonEnabledtotrue, this callback will be called when the user taps on the back button when at the top level of theStorytellerEmbeddedClipsView. Theevent.canGoBackproperty tells whether the back button action is managed by the SDK. Whenfalse, the integrating app can handle the back button action. Whentrue, the SDK will manage the action by popping the top level category. -
onCanGoBackChanged?: (event: CanGoBackChangedEvent) => void- this callback is used to handle the result from aStorytellerEmbeddedClipsView.getCanGoBack()call. Theevent.canGoBackproperty returnstrueif you are within the Storyteller SDK nested navigation andfalseif you are on the top level of theStorytellerEmbeddedClipsView. This property is only available on Android.
Adding it in the layout#
To put it in your custom view hierarchy you will need to add the following code:
import { useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import {
StorytellerEmbeddedClipsView,
type StorytellerEmbeddedClipsViewInterface,
} from '@getstoryteller/react-native-storyteller-sdk';
function MyComponent() {
const embeddedClipsRef = useRef<StorytellerEmbeddedClipsViewInterface>(null);
return (
<View style={styles.container}>
<StorytellerEmbeddedClipsView
ref={embeddedClipsRef}
style={styles.embeddedComponent}
configuration={{
collection: 'collection-id',
category: 'category-id',
clipId: 'clip-id',
openedReason: 'opened-reason',
}}
topLevelBackButtonEnabled={false}
onDataLoadStarted={() => {
console.log('Data load started');
}}
onDataLoadCompleted={(event) => {
console.log('Data load completed:', event.success, event.error, event.dataCount);
}}
onTopLevelBackTapped={(event) => {
console.log('Top level back tapped, canGoBack:', event.canGoBack);
}}
onCanGoBackChanged={(event) => {
console.log('Can go back changed:', event.canGoBack);
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
embeddedComponent: {
flex: 1,
},
});
// somewhere inside a react component
const ref = useRef<StorytellerEmbeddedClipsView | null>(null);
useEffect(() => {
if (ref.current) {
ref.current.create();
}
}, []);
return (
<SafeAreaView style={styles.container}>
<StorytellerEmbeddedClipsView
configuration= {{
collection: 'collection-id',
category: 'category-id',
clipId: 'clip-id',
openedReason: 'opened-reason',
}}
topLevelBackButtonEnabled={true}
onTopLevelBackTapped={(canGoBack) => {
console.log(`topLevelBackTapped canGoBack: ${canGoBack}`);
}}
onDataLoadStarted={() => {
console.log('onDataLoadStarted');
}}
onDataLoadCompleted={(success, error) => {
console.log('onDataLoadCompleted', success, error);
}}
onCanGoBackChanged={(canGoBack) => {
console.log('onCanGoBackChanged', canGoBack);
}}
style={styles.clips}
ref={ref}
/>
</SafeAreaView>
);
Auto-pause#
If you want to pause the clips when navigating between tabs or when the app goes to background, you can use the willShow() and willHide() methods:
import { useRef, useCallback } from 'react';
import { View, StyleSheet } from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import {
StorytellerEmbeddedClipsView,
type StorytellerEmbeddedClipsViewInterface,
} from '@getstoryteller/react-native-storyteller-sdk';
export default function EmbeddedClipsTab() {
const embeddedClipsRef = useRef<StorytellerEmbeddedClipsViewInterface>(null);
// Handle tab focus/blur to control video playback
useFocusEffect(
useCallback(() => {
// Tab is focused - show the embedded clips
embeddedClipsRef.current?.willShow();
return () => {
// Tab is blurred - hide the embedded clips
embeddedClipsRef.current?.willHide();
};
}, [])
);
return (
<View style={styles.container}>
<StorytellerEmbeddedClipsView
ref={embeddedClipsRef}
style={styles.embeddedComponent}
configuration={{
collection: 'your-collection-id',
}}
topLevelBackButtonEnabled={false}
onDataLoadCompleted={(event) =>
console.log('Embedded clips data load completed:', event)
}
onTopLevelBackTapped={(event) =>
console.log('Embedded clips top level back tapped:', event)
}
onCanGoBackChanged={(event) =>
console.log('Embedded clips can go back changed:', event)
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
embeddedComponent: {
flex: 1,
},
});
reference: StorytellerEmbeddedClipsView | null = null;
constructor(props: EmbeddedClipsScreenProps) {
super(props);
this.state = {
appState: AppState.currentState as AppStateStatus,
collectionId: 'example',
};
}
componentDidMount(): void {
this.props.navigation.addListener('focus', this._onFocus);
this.props.navigation.addListener('blur', this._onBlur);
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount(): void {
this.props.navigation.removeListener('blur', this._onBlur);
this.props.navigation.removeListener('focus', this._onFocus);
}
_handleAppStateChange = (nextAppState: AppStateStatus) => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === 'active'
) {
this.reference?.willShow();
}
this.setState({ appState: nextAppState });
};
_onFocus = () => {
this.reference?.willShow();
};
_onBlur = () => {
this.reference?.willHide();
};
render() {
return (
<SafeAreaView style={styles.container}>
<StorytellerEmbeddedClipsView
collection={this.state.collectionId}
style={styles.clips}
ref={(ref) => {
if (ref) {
this.reference = ref;
}
}}
/>
</SafeAreaView>
);
}
Reload Data#
If you want to reload the data programmatically, you can use the reloadData() method:
import { useRef } from 'react';
import { View, Button, StyleSheet } from 'react-native';
import {
StorytellerEmbeddedClipsView,
type StorytellerEmbeddedClipsViewInterface,
} from '@getstoryteller/react-native-storyteller-sdk';
function MyComponent() {
const embeddedClipsRef = useRef<StorytellerEmbeddedClipsViewInterface>(null);
const handleReload = () => {
embeddedClipsRef.current?.reloadData();
};
return (
<View style={styles.container}>
<Button title="Reload Data" onPress={handleReload} />
<StorytellerEmbeddedClipsView
ref={embeddedClipsRef}
style={styles.embeddedComponent}
configuration={{
collection: 'collection-id',
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
embeddedComponent: {
flex: 1,
},
});
const ref = useRef<StorytellerEmbeddedClipsView | null>(null);
const reloadData = () => {
if (ref.current) {
ref.current.reloadData();
}
}
return (
<SafeAreaView style={styles.container}>
<StorytellerEmbeddedClipsView
collection={'collection-id'}
style={styles.clips}
ref={ref}
/>
</SafeAreaView>
);
Available Methods#
The StorytellerEmbeddedClipsViewInterface provides the following methods:
getCanGoBack()- Triggers theonCanGoBackChangedcallback with the current navigation state (Android only)goBack()- Navigate back in the clips navigation stackwillShow()- Resume video playback (call when view becomes visible)willHide()- Pause video playback (call when view becomes hidden)reloadData()- Reload the clips collection data