UI components (React Native)
@media-sdk/ui-native@^0.1.0 provides reusable presentational React Native components. Components render UI from props — they never call the API, manage search state, or read from MediaProvider.
pnpm add @media-sdk/ui-native@^0.1.0 react react-nativePeer dependencies: React 18 or 19, react-native ≥ 0.71.
Presentational-only philosophy
| Layer | Responsibility |
|---|---|
| Your app | Data fetching, search state, pagination, capability gating |
@media-sdk/native | Hooks and MediaProvider |
@media-sdk/ui-native | UI rendering — props in, JSX out |
Components do not:
- Call
searchPhotos,searchVideos, or anyMediaClientmethod - Read from
MediaProvidercontext - Branch on provider identity
- Fetch data on mount
Public API
All 11 exported components:
import {
SearchBar,
MediaTabs,
PhotoCard,
PhotoGrid,
PhotoPreview,
VideoCard,
VideoGrid,
VideoPreview,
Pagination,
LoadingState,
ErrorState,
type MediaTab,
} from "@media-sdk/ui-native";Internal utilities (getPhotoSrc, getPlayableVideoLink) are not exported.
Component catalog
| Component | Purpose |
|---|---|
SearchBar | Controlled search input and submit button |
MediaTabs | Photos / Videos tab switcher |
PhotoCard | Single photo thumbnail with press handler |
PhotoGrid | Virtualized photo grid (FlatList) |
PhotoPreview | Modal overlay for a selected photo |
VideoCard | Single video thumbnail with duration |
VideoGrid | Virtualized video grid (FlatList) |
VideoPreview | Modal with poster; optional renderVideo for playback |
Pagination | Previous / next page controls |
LoadingState | Accessible loading message |
ErrorState | Accessible error message |
SearchBar
| Prop | Type | Required | Description |
|---|---|---|---|
value | string | Yes | Current input value |
onChange | (value: string) => void | Yes | Called when text changes (onChangeText) |
onSubmit | () => void | Yes | Called on submit button press or keyboard submit |
Unlike web SearchBar, there is no FormEvent — onSubmit is a plain callback.
<SearchBar
value={query}
onChange={setQuery}
onSubmit={() => setSubmittedQuery(query)}
/>MediaTabs
| Prop | Type | Required | Description |
|---|---|---|---|
activeTab | MediaTab | Yes | "photos" or "videos" |
onTabChange | (tab: MediaTab) => void | Yes | Tab selection handler |
type MediaTab = "photos" | "videos";Gate the Videos tab in your app with useMediaCapabilities().operations.searchVideos.
PhotoCard
| Prop | Type | Required | Description |
|---|---|---|---|
photo | Photo | Yes | Photo from @media-sdk/core |
onSelect | (photo: Photo) => void | Yes | Press handler |
Uses Image with photo.src.medium ?? small ?? original.
PhotoGrid
| Prop | Type | Required | Description |
|---|---|---|---|
photos | Photo[] | Yes | Photos to display |
onPhotoSelect | (photo: Photo) => void | Yes | Selection handler |
numColumns | number | No | Default 2 — passed to FlatList |
contentContainerStyle | StyleProp<ViewStyle> | No | FlatList content container style |
Renders nothing when photos.length === 0.
PhotoPreview
| Prop | Type | Required | Description |
|---|---|---|---|
photo | Photo | Yes | Photo to preview |
onClose | () => void | Yes | Close handler (back button + close control) |
Uses RN Modal with full-size image (large ?? medium ?? small ?? original).
VideoCard
| Prop | Type | Required | Description | | --- | --- | --- | | video | Video | Yes | Video from @media-sdk/core | | onSelect | (video: Video) => void | Yes | Press handler |
Thumbnail from video.image URL.
VideoGrid
| Prop | Type | Required | Description |
|---|---|---|---|
videos | Video[] | Yes | Videos to display |
onVideoSelect | (video: Video) => void | Yes | Selection handler |
numColumns | number | No | Default 2 |
contentContainerStyle | StyleProp<ViewStyle> | No | FlatList content style |
VideoPreview
| Prop | Type | Required | Description |
|---|---|---|---|
video | Video | Yes | Video to preview |
onClose | () => void | Yes | Close handler |
renderVideo | (video, source) => ReactNode | No | App-supplied player |
When renderVideo is omitted, shows poster image and fallback text. Supply a player from react-native-video, expo-av, or similar — not bundled by the SDK.
<VideoPreview
video={video}
onClose={close}
renderVideo={(_v, src) =>
src ? <Video source={{ uri: src }} /> : null
}
/>Pagination
| Prop | Type | Required | Description |
|---|---|---|---|
page | number | Yes | Current page number |
hasPrevious | boolean | Yes | Enable previous button |
hasNext | boolean | Yes | Enable next button |
loading | boolean | No | Disable buttons while loading |
accessibilityLabel | string | Yes | Nav container label (replaces web ariaLabel) |
onPrevious | () => void | Yes | Previous page handler |
onNext | () => void | Yes | Next page handler |
LoadingState
| Prop | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Loading text |
Includes ActivityIndicator and accessibilityLiveRegion="polite" where supported.
ErrorState
| Prop | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Error text |
Uses accessibilityRole="alert".
Styling
Components ship with minimal StyleSheet defaults. Override via optional style / contentContainerStyle props on grids. No theming system in v0.1.0.
Accessibility
RN accessibility props — not aria-*:
| Web (ui-react) | Native (ui-native) |
|---|---|
aria-label | accessibilityLabel |
aria-selected | accessibilityState= |
role="alert" | accessibilityRole="alert" |
Next steps
- Getting started — wire hooks to components
- Web UI comparison — parallel web package
- Expo example — full app wiring