One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

iOS Media and Empty States

Image, shapes, VideoPlayer, LivePhotoView, WebView, PhotosPicker, Map, ContentUnavailableView, and EmptyView under One.iOS

One.iOS shapes, SF Symbols in several rendering modes, and a ContentUnavailableView

Media, shapes, and empty states under One.iOS, drawn by SwiftUI.

Every view also accepts accessibilityLabel, accessibilityHint, accessibilityValue, testID, style, onLayout, and swiftStyle.

Image

One.iOS.Image draws an SF Symbol by name, or a remote image from uri.

import { One } from 'one'
<One.iOS.Image systemName="cloud.sun.rain.fill" symbolRenderingMode="multicolor" imageScale="large" />
<One.iOS.Image systemName="wifi" variableValue={0.5} />
PropsTypeDescription
systemNamestring = ""The SF Symbol to draw.
string = ""The SF Symbol to draw.
uristring = ""A remote image to draw in place of a symbol. It fills its frame.
string = ""A remote image to draw in place of a symbol. It fills its frame.
renderingMode"original" | "template" = "original"template lets a toolbar tint a remote image.
"original" | "template" = "original"template lets a toolbar tint a remote image.
symbolRenderingModeSymbolRenderingMode | "" = ""monochrome, multicolor, hierarchical, or palette.
SymbolRenderingMode | "" = ""monochrome, multicolor, hierarchical, or palette.
symbolVariantSymbolVariants | "" = ""none, circle, square, rectangle, fill, or slash.
SymbolVariants | "" = ""none, circle, square, rectangle, fill, or slash.
imageScaleImageScale | "" = ""small, medium, or large.
ImageScale | "" = ""small, medium, or large.
variableValuenumberFrom 0 to 1, for symbols that fill in steps.
numberFrom 0 to 1, for symbols that fill in steps.
colorRoleIconColorRole | "" = ""A system color role, as in One.UI.Icon.
IconColorRole | "" = ""A system color role, as in One.UI.Icon.
resizableboolean = falseScales a symbol to its frame instead of its point size.
boolean = falseScales a symbol to its frame instead of its point size.

"" leaves a modifier unset. Size a symbol with swiftStyle={{ fontSize }} and give the view a matching width and height, or React Native lays it out smaller than the glyph and neighbors overlap it.

For bundled, remote, and cross-platform images, use One.UI.Image instead.

Shapes

Circle, Capsule, Rectangle, Ellipse, RoundedRectangle, UnevenRoundedRectangle, and ConcentricRectangle fill a SwiftUI shape with fill, a color value. Every shape except ConcentricRectangle also takes strokeBorder, a color drawn inside its edge over the fill, lineWidth points wide. A shape fills the box React Native gives it.

RoundedRectangleTypeDescription
fillColorValueThe fill color. Every shape takes it.
ColorValueThe fill color. Every shape takes it.
strokeBorderColorValueA border color drawn inside the edge.
ColorValueA border color drawn inside the edge.
lineWidthnumber = 1The border width in points.
number = 1The border width in points.
cornerRadiusnumber = 0The corner radius in points.
number = 0The corner radius in points.
UnevenRoundedRectangleTypeDescription
fillColorValueThe fill color.
ColorValueThe fill color.
strokeBorderColorValueA border color drawn inside the edge.
ColorValueA border color drawn inside the edge.
lineWidthnumber = 1The border width in points.
number = 1The border width in points.
topLeadingRadiusnumber = 0The top leading corner.
number = 0The top leading corner.
bottomLeadingRadiusnumber = 0The bottom leading corner.
number = 0The bottom leading corner.
bottomTrailingRadiusnumber = 0The bottom trailing corner.
number = 0The bottom trailing corner.
topTrailingRadiusnumber = 0The top trailing corner.
number = 0The top trailing corner.

ConcentricRectangle needs iOS 26 and takes its corners from the enclosing container shape. With none, its corners can be square.

import { One } from 'one'
<One.iOS.Circle fill="red" />
<One.iOS.RoundedRectangle fill="blue" cornerRadius={12} />
<One.iOS.Capsule fill="white" strokeBorder="gray" lineWidth={2} />
<One.iOS.UnevenRoundedRectangle fill="green" topLeadingRadius={16} bottomTrailingRadius={16} />
<One.iOS.ConcentricRectangle fill="orange" style={{ width: 120, height: 80 }} />

VideoPlayer

One.iOS.VideoPlayer plays a local file:// or remote video from url with AVKit’s native transport controls. autoplay starts playback when a URL loads. The player keeps its position when other props change and creates a new player only when url changes.

import { One } from 'one'
<One.iOS.VideoPlayer url="https://example.com/trailer.mp4" autoplay />
PropsTypeDescription
urlstring = ""A file:// or remote video. A new url makes a new player.
string = ""A file:// or remote video. A new url makes a new player.
autoplayboolean = falsePlays once the video loads.
boolean = falsePlays once the video loads.
command"play" | "pause" | "seek" | "" = ""A command to run. See below.
"play" | "pause" | "seek" | "" = ""A command to run. See below.
commandRevisionnumber = 0Increase to run command again.
number = 0Increase to run command again.
seekToMsnumber = 0Where a seek goes, in milliseconds.
number = 0Where a seek goes, in milliseconds.
onPlaybackStatus(state: string, positionMs: number, durationMs: number) => voidloading, playing, paused, ended, or failed, with the time.
(state: string, positionMs: number, durationMs: number) => voidloading, playing, paused, ended, or failed, with the time.

Set command to play, pause, or seek and increment commandRevision for each command, including repeated commands of the same kind. For seek, pass a nonnegative seekToMs. Revisions start at 1 and increase for the lifetime of the view. onPlaybackStatus(state, positionMs, durationMs) reports loading, playing, paused, ended, or failed and the player’s current time and duration in milliseconds. Unknown or indefinite duration is reported as 0. Status arrives on state changes, after commands, and about twice per second while playing. Native transport taps also change the reported status.

import { useState } from 'react'
import { Button, View } from 'react-native'
import { One } from 'one'
function ControlledVideo() {
const [control, setControl] = useState({ command: '' as '' | 'play' | 'pause' | 'seek', revision: 0, seekToMs: 0 })
const send = (command: 'play' | 'pause' | 'seek', seekToMs = 0) =>
setControl((previous) => ({ command, seekToMs, revision: previous.revision + 1 }))
return <View>
<One.iOS.VideoPlayer
url="https://example.com/trailer.mp4"
style={{ height: 220 }}
command={control.command}
commandRevision={control.revision}
seekToMs={control.seekToMs}
onPlaybackStatus={(state, positionMs, durationMs) => console.log(state, positionMs, durationMs)}
/>
<Button title="Play" onPress={() => send('play')} />
<Button title="Pause" onPress={() => send('pause')} />
<Button title="Skip to 10s" onPress={() => send('seek', 10_000)} />
</View>
}

The player follows the app’s audio session. This view does not publish Now Playing metadata or remote transport callbacks. One.Audio manages a separate player and its own remote commands. Playback during backgrounding, cross-app audio arbitration, and picture in picture need device proof.

LivePhotoView

One.iOS.LivePhotoView displays and plays a Live Photo already in the Photos library. Request read access with One.PhotoLibrary.requestReadPermission(), then pass the identifier of an asset whose isLivePhoto is true. Give the view an explicit size. It loads a nondegraded PHLivePhoto and shows its key photo at ready. It does not capture or assemble a still and video pair.

PropsTypeDescription
assetIdentifier (required)stringThe Photos local identifier of a Live Photo.
stringThe Photos local identifier of a Live Photo.
autoplayboolean = falsePlays once the Live Photo is ready.
boolean = falsePlays once the Live Photo is ready.
command"play" | "stop" | "" = ""A command to run.
"play" | "stop" | "" = ""A command to run.
commandRevisionnumber = 0Increase to run command again.
number = 0Increase to run command again.
onPlaybackState(state: string, errorCode: string) => voidloading, ready, playing, ended, or failed.
(state: string, errorCode: string) => voidloading, ready, playing, ended, or failed.
import { useState } from 'react'
import { Button, View } from 'react-native'
import { One } from 'one'
function LivePhoto({ assetIdentifier }: { assetIdentifier: string }) {
const [control, setControl] = useState({ command: '' as '' | 'play' | 'stop', revision: 0 })
const send = (command: 'play' | 'stop') =>
setControl((previous) => ({ command, revision: previous.revision + 1 }))
return <View>
<One.iOS.LivePhotoView
assetIdentifier={assetIdentifier}
style={{ width: 320, height: 240 }}
command={control.command}
commandRevision={control.revision}
onPlaybackState={(state, errorCode) => console.log(state, errorCode)}
/>
<Button title="Play" onPress={() => send('play')} />
<Button title="Stop" onPress={() => send('stop')} />
</View>
}

autoplay starts when the nondegraded Live Photo reaches ready. Otherwise, send play or stop with an increasing positive commandRevision. Revisions increase for the lifetime of the view, including repeated commands. The event order for a normal full play is loading, ready, playing, ended. stop returns to ready and shows the key photo. onPlaybackState receives (state, errorCode); errorCode is '' unless state is failed.

Failures report E_LIVE_PHOTO_INPUT for a blank identifier supplied directly to the native component, E_LIVE_PHOTO_PERMISSION without Photos read access, E_LIVE_PHOTO_NOT_FOUND for an unknown or inaccessible asset, E_LIVE_PHOTO_NOT_LIVE for an ordinary image, or E_LIVE_PHOTO_LOAD if Photos cannot supply the Live Photo. The JavaScript wrapper rejects a blank identifier before mounting. The loader uses local Photos data and does not download an iCloud original; a cloud-only asset may fail with E_LIVE_PHOTO_LOAD.

WebView

One.iOS.WebView embeds web content from url or an html string.

PropsTypeDescription
urlstring = ""The page to load.
string = ""The page to load.
htmlstring = ""Markup to load in place of a url.
string = ""Markup to load in place of a url.
onNavigate(url: string) => voidThe page URL changed.
(url: string) => voidThe page URL changed.
onTitleChange(title: string) => voidThe page title changed.
(title: string) => voidThe page title changed.
onLoadingChange(loading: boolean, progress: number) => voidLoading started, progressed, or ended.
(loading: boolean, progress: number) => voidLoading started, progressed, or ended.
backForwardNavigationGesturesBackForwardNavigationGesturesBehavior | "" = ""Edge swipes to go back and forward.
BackForwardNavigationGesturesBehavior | "" = ""Edge swipes to go back and forward.
magnificationGesturesMagnificationGesturesBehavior | "" = ""Pinch to zoom.
MagnificationGesturesBehavior | "" = ""Pinch to zoom.
linkPreviewsLinkPreviewBehavior | "" = ""Long press link previews.
LinkPreviewBehavior | "" = ""Long press link previews.
elementFullscreenElementFullscreenBehavior | "" = ""Lets page video go full screen.
ElementFullscreenBehavior | "" = ""Lets page video go full screen.
contentBackgroundVisibility | "" = ""The web view background.
Visibility | "" = ""The web view background.

The gesture and behavior props take automatic, enabled, or disabled, and "" leaves them unset. Use html for markup already in the app. Updating that string loads the new document and reports its title through onTitleChange; give the view an explicit height because WebView fills its React Native box.

PhotosPicker

One.iOS.PhotosPicker is documented with the other pickers in iOS Pickers.

Map

One.iOS.Map is the SwiftUI map.

PropsTypeDescription
latitudenumber = 37.7749The region center.
number = 37.7749The region center.
longitudenumber = -122.4194The region center.
number = -122.4194The region center.
distancenumber = 5000How far the camera sits from the center, in meters.
number = 5000How far the camera sits from the center, in meters.
markers (required)readonly MapMarker[]Pins, each { id, label, latitude, longitude }.
readonly MapMarker[]Pins, each { id, label, latitude, longitude }.
onRegionChange(latitude: number, longitude: number, distance: number) => voidThe region when a move ends.
(latitude: number, longitude: number, distance: number) => voidThe region when a move ends.

For a cross-platform map with polylines, polygons, and circles, use One.UI.Map instead.

ContentUnavailableView

One.iOS.ContentUnavailableView renders an empty state with action buttons. Give it a height or flex: 1; it fills the area React Native assigns. A React state update after an action can change the view or replace it.

import { One } from 'one'
<One.iOS.ContentUnavailableView
title="No results"
systemImage="magnifyingglass"
description="Try a different search."
actions={[{ id: 'retry', label: 'Retry' }]}
onAction={(id) => id === 'retry' && reload()}
/>
PropsTypeDescription
titlestring = ""The headline.
string = ""The headline.
systemImagestring = ""An SF Symbol above the title.
string = ""An SF Symbol above the title.
descriptionstring = ""Text under the title.
string = ""Text under the title.
actions (required)readonly DialogAction[]Buttons, each { id, label, role }.
readonly DialogAction[]Buttons, each { id, label, role }.
onAction(id: string) => voidA tapped action.
(id: string) => voidA tapped action.

EmptyView

One.iOS.EmptyView renders nothing. It is a placeholder where SwiftUI expects a view, with no props beyond the shared view props. Inside a SwiftUI HStack, it adds no visible element or extra spacing. It has zero visible height. In a React Native container with gap, the gaps on either side still apply to its position in the child list.

On web and Android these views throw. Keep them behind a platform check.

Edit this page on GitHub.