React
RasterPicker, the drop-in React asset picker, plus RasterProvider and hooks for building your own Raster UI.
@raster-app/react includes RasterPicker, a complete asset picker. To build
your own UI, use RasterProvider and the hooks.
RasterPicker
RasterPicker handles sign-in, browsing, search, upload, and picking in one
component. Your app receives the picked asset in onPick. Render it inside a
RasterProvider and import @raster-app/react/styles.css.
See the quick start for code and props.
RasterProvider
RasterProvider takes a client, or a config to create one:
| Prop | Type | Description |
|---|---|---|
client | RasterClient | A client from createRasterClient. Pass client or config. |
config | RasterClientConfig | A configuration for the provider to create a client. |
state | StateStore | Where useRasterNavigation remembers the last organization and library: memoryStateStore() (default), localStorageStateStore(), or your own. |
The provider reads these props once, on mount. To change them, remount it with
a new key.
Build your own UI
Use the hooks inside a RasterProvider:
import {
RasterProvider,
createRasterClient,
getThumbUrl,
localStorageCredentialStore,
useAssets,
useSession,
useSignIn,
} from '@raster-app/react'
// Create the client once, outside any component.
const client = createRasterClient({
host: { name: 'My App', openExternal: (url) => window.open(url, '_blank') },
credentials: localStorageCredentialStore(),
})
export function App() {
return (
<RasterProvider client={client}>
<Library />
</RasterProvider>
)
}
function Library() {
const { credentials, isConfigured, signOut } = useSession()
const { state, signInWithDevice } = useSignIn()
// Your organization's and library's ids.
const { assets, hasMore, loadMore } = useAssets({ organizationId: 'acme', libraryId: 'lib-1' })
if (credentials === undefined) return null // still reading the saved sign-in
if (!isConfigured) {
if (state.status === 'awaitingApproval') {
return <p>Approve {state.device.userCode} in the Raster tab that just opened.</p>
}
return (
<button type="button" onClick={signInWithDevice}>
Sign in with Raster
</button>
)
}
return (
<>
{assets?.map((asset) => (
<img key={asset.id} src={getThumbUrl(asset)} alt={asset.name ?? ''} width={200} />
))}
{hasMore && (
<button type="button" onClick={loadMore}>
Load more
</button>
)}
<button type="button" onClick={signOut}>
Sign out
</button>
</>
)
}Hooks
Call hooks inside a RasterProvider. Errors are RasterApiErrors; show them
with toUserMessage(error) (see Errors).
| Hook | Returns |
|---|---|
useRasterClient() | The provider's client, for calling methods. |
useSession() | The stored credential and signOut. |
useSignIn(options?) | Device sign-in and API-key connection, with their state. |
useOrganizations() | The organizations the credential reaches. |
useLibraries(options) | An organization's libraries, with the credential's access to each. |
useAssets(options) | A library's assets, a page at a time. |
useAssetSearch(scope, query) | Search results, a page at a time. |
useAssetUpload() | An upload that waits until the file is processed. |
usePromoteVariant() | A promote that waits until the variant is the default. |
useRasterNavigation(options) | The open organization, library, and asset. |
useSession()
| Field | Description |
|---|---|
credentials | The stored StoredCredentials, or undefined until read. |
isConfigured | true when there is a sign-in or an API key. |
isSignedIn | true when the credential is a sign-in. |
userName | The signed-in account's name, or null for an API key. |
signOut() | Signs out, like auth.signOut(). |
It re-renders when the credential changes. Show sign-in once credentials is
defined and isConfigured is false.
useSignIn(options?)
options takes scope and organizationId, as
auth.signInWithDevice
does.
| Field | Description |
|---|---|
state | The attempt's state, below. |
signInWithDevice() | Starts a device sign-in. |
connectApiKey(apiKey) | Checks and stores an organization API key. |
cancel() | Cancels a sign-in awaiting approval. |
reset() | Returns state to idle. |
state.status is one of:
idle: nothing running. Also the state after success (useSessionhas the new credential) or cancel.connecting: the sign-in or key check is running.awaitingApproval: showstate.device.userCode. The consent page isstate.device.verificationUrl.error: failed withstate.error.
useOrganizations() and useLibraries(options)
useOrganizations() returns data ({ id, name, libraryCount } each),
isLoading, and error.
useLibraries({ organizationId, organizationName? }) returns every
library in data, with isLoading and error. Each
library has organizationId, organizationName, and access ('write',
'read', or null). Pass organizationId: null until an organization is
chosen.
useAssets(options)
useAssets({ organizationId, libraryId }) lists a library's assets a page at
a time. Pass libraryId: null until a library is open.
| Field | Description |
|---|---|
assets | The assets loaded so far, or null before the first page. |
isLoading | true while a page loads. |
error | The RasterApiError that stopped loading, or null. |
hasMore | true when another page may follow. |
loadMore() | Loads the next page. |
useAssetSearch(scope, query)
scope is { organizationId, libraryId }; libraryId: null searches the
whole organization, and a null scope turns search off. Pass the search box's
text as query. The hook searches once typing pauses and keeps the previous
results until new ones arrive.
| Field | Description |
|---|---|
active | true when query has text and scope is set. |
query | The trimmed query. |
hits | The hits loaded so far, or null before the first page. |
found | The number of matches. |
isSearching | true from a keystroke until its results arrive. |
hasMore / loadMore() | As in useAssets. |
error | The RasterApiError that stopped the search, or null. |
useAssetUpload()
function UploadInput() {
const { upload, state } = useAssetUpload()
return (
<input
type="file"
disabled={state.status === 'uploading' || state.status === 'processing'}
onChange={(event) => {
const file = event.target.files?.[0]
if (file) void upload({ organizationId: 'acme', libraryId: 'lib-1', source: file })
}}
/>
)
}upload(options) takes the assets.upload options
except signal. It resolves with the processed Asset
(for a variant, its parent), or null if the upload failed, was cancelled, or
was still processing. state tells you which.
state.status is one of:
idle: no upload running.uploading: the file is uploading.processing: Raster is processing the file.state.assetis the uploaded asset.done:state.assetis the processed asset.timed-out: still processing when the wait ended.state.assetis the uploaded asset.error: failed withstate.error.
cancel() stops the upload; reset() returns state to idle. Other hooks'
libraries, assets, and search results update once an upload settles.
usePromoteVariant()
function SetAsDefault({ assetId, variantId }: { assetId: string; variantId: string }) {
const { promote, state } = usePromoteVariant()
return (
<button
type="button"
disabled={state.status === 'promoting'}
onClick={() =>
void promote({ organizationId: 'acme', libraryId: 'lib-1', assetId, variantId })
}
>
Set as default
</button>
)
}promote(options) makes the variant the default and resolves with the updated
asset, or null if it failed or hadn't landed when the wait ended.
To update useAssets results right away, pass optimistic: a function that
returns the asset as it should look. useAssets shows it until the promote
lands or fails.
state.status is idle, promoting, done (with state.asset),
timed-out, or error (with state.error). reset() returns it to idle.
useRasterNavigation(options)
useRasterNavigation({ organizations }) tracks the organization, open
library, open asset, and search text. Pass organizations from
useOrganizations(), or null while loading. It selects the remembered
organization if still reachable, otherwise the first.
| Field | Description |
|---|---|
organizationId | The selected organization, or null. |
library | The open library, or null. |
asset | The asset whose variants are open, or null. |
query | The search text. Cleared when the organization or library changes. |
selectOrganization(id) | Selects an organization and closes the library and asset. |
openLibrary(library) | Opens a library, or null for the library list. |
openAsset(asset) | Opens an asset's variants, or null for the library's assets. |
setQuery(query) | Sets the search text. |
refresh() | Reloads everything the hooks have fetched. |
isRestored | true once the remembered organization and library are read. |
It saves the organization and library in the provider's state store. A
StateStore has three async methods: get(key), set(key, value), and
delete(key).