Raster

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:

PropTypeDescription
clientRasterClientA client from createRasterClient. Pass client or config.
configRasterClientConfigA configuration for the provider to create a client.
stateStateStoreWhere 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:

app.tsx
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).

HookReturns
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()

FieldDescription
credentialsThe stored StoredCredentials, or undefined until read.
isConfiguredtrue when there is a sign-in or an API key.
isSignedIntrue when the credential is a sign-in.
userNameThe 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.

FieldDescription
stateThe 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 (useSession has the new credential) or cancel.
  • connecting: the sign-in or key check is running.
  • awaitingApproval: show state.device.userCode. The consent page is state.device.verificationUrl.
  • error: failed with state.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.

FieldDescription
assetsThe assets loaded so far, or null before the first page.
isLoadingtrue while a page loads.
errorThe RasterApiError that stopped loading, or null.
hasMoretrue 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.

FieldDescription
activetrue when query has text and scope is set.
queryThe trimmed query.
hitsThe hits loaded so far, or null before the first page.
foundThe number of matches.
isSearchingtrue from a keystroke until its results arrive.
hasMore / loadMore()As in useAssets.
errorThe 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.asset is the uploaded asset.
  • done: state.asset is the processed asset.
  • timed-out: still processing when the wait ended. state.asset is the uploaded asset.
  • error: failed with state.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.

FieldDescription
organizationIdThe selected organization, or null.
libraryThe open library, or null.
assetThe asset whose variants are open, or null.
queryThe 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.
isRestoredtrue 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).

On this page