@raster-app/react 0.1.0-canary-2e1834e → 0.1.0-canary-84a5119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +94 -79
  2. package/package.json +2 -4
package/README.md CHANGED
@@ -1,26 +1,28 @@
1
1
  # @raster-app/react
2
2
 
3
- React bindings for [`@raster-app/sdk`](https://www.npmjs.com/package/@raster-app/sdk): a drop-in
4
- Raster asset picker, and the provider and hooks it is built on (session, organizations,
5
- libraries, assets, search, uploads and the navigation model every Raster plugin shares). They
6
- cache in TanStack Query.
3
+ Raster's asset picker for React, and hooks to build your own Raster UI.
4
+
5
+ ## Documentation
6
+
7
+ [raster.app/docs](https://raster.app/docs)
8
+
9
+ ## Requirements
10
+
11
+ - React 18 or 19
12
+ - Node.js 24 or later
13
+
14
+ ## Installation
7
15
 
8
16
  ```sh
9
17
  npm install @raster-app/react
10
18
  ```
11
19
 
12
- It takes the host's React, 18 or 19, as a peer dependency. It re-exports all of
13
- `@raster-app/sdk`, so the client, `toUserMessage` and types such as `Asset` and `Library` come
14
- from `@raster-app/react` too.
20
+ It includes [`@raster-app/sdk`](https://www.npmjs.com/package/@raster-app/sdk) and re-exports all
21
+ of it, so import the client, `toUserMessage` and types such as `Asset` from `@raster-app/react`.
15
22
 
16
- ## The picker
23
+ ## Usage
17
24
 
18
- `RasterPicker` is Raster's asset picker, drawn in Raster's own design: sign-in with the device
19
- grant or an API key, Raster's organization switcher, the organization's libraries, search, and
20
- infinite scroll. A tile opens its asset large, with Pick asset and Open in Raster, which goes
21
- through the host's `openExternal`, over the asset's versions, where a variant is uploaded or set as
22
- the default. It uploads into a library from its menu or a drop. An organization or a library is
23
- read as the pointer reaches it, so it opens at once. It fills its container.
25
+ ### Add the picker
24
26
 
25
27
  ```tsx
26
28
  import {
@@ -31,11 +33,11 @@ import {
31
33
  } from '@raster-app/react'
32
34
  import '@raster-app/react/styles.css'
33
35
 
34
- function Picker({ onImage }: { onImage: (url: string) => void }) {
36
+ export function Picker({ onImage }: { onImage: (url: string) => void }) {
35
37
  return (
36
38
  <RasterProvider
37
39
  config={{
38
- host: { name: 'Sanity', openExternal: (url) => window.open(url, '_blank') },
40
+ host: { name: 'My App', openExternal: (url) => window.open(url, '_blank') },
39
41
  credentials: localStorageCredentialStore(),
40
42
  }}
41
43
  >
@@ -45,93 +47,106 @@ function Picker({ onImage }: { onImage: (url: string) => void }) {
45
47
  }
46
48
  ```
47
49
 
48
- | Prop | What it does |
49
- | ---------------- | --------------------------------------------------------------------------------------------------------------- |
50
- | `onPick` | Called with the picked `Asset`, from any view, and its organization's id. `getFullSizeUrl(asset)` is the image. |
51
- | `organizationId` | Binds the device sign-in to one organization: any other grant fails with `ORGANIZATION_MISMATCH`. |
52
- | `scope` | The consent the device sign-in asks for: `'org'` when `organizationId` is set, `'user'` otherwise. |
53
- | `onError` | Called once with each `RasterApiError` the picker shows, for the host to log. |
54
- | `theme` | `'light'` or `'dark'`. The system's color scheme when unset. |
50
+ `host.name` is the name Raster's sign-in page shows for your app, and `openExternal` opens that page
51
+ in the user's browser. `credentials` is where the sign-in is kept.
52
+
53
+ The picker signs the user in, browses their organizations and libraries, searches, uploads, and
54
+ lets them pick an asset or one of its versions. It fills its container.
55
55
 
56
- The styles are scoped under `.rs`, so they leave the host's own untouched.
56
+ | Prop | What it does |
57
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
58
+ | `onPick(asset, organizationId)` | Called with the picked asset. `getFullSizeUrl(asset)` is its image. |
59
+ | `organizationId` | Limits sign-in to this organization. |
60
+ | `scope` | `'org'` to ask for one organization, `'user'` for the whole account. Defaults to `'org'` with an `organizationId`. |
61
+ | `onError(error)` | Called with each error the picker shows, for logging. |
62
+ | `theme` | `'light'` or `'dark'`. Follows the system when unset. |
57
63
 
58
- ## Your own UI
64
+ ### Build your own UI
59
65
 
60
- A host that draws its own UI uses the hooks under the same provider.
66
+ The same provider gives your components hooks.
61
67
 
62
68
  ```tsx
63
69
  import {
64
70
  RasterProvider,
65
71
  createRasterClient,
72
+ getThumbUrl,
66
73
  localStorageCredentialStore,
67
74
  useAssets,
68
- useLibraries,
69
75
  useSession,
76
+ useSignIn,
70
77
  } from '@raster-app/react'
71
78
 
72
- // Build the client once, outside render — a second one means a second session store.
79
+ // Create the client once, outside any component.
73
80
  const client = createRasterClient({
74
- host: { name: 'Sanity', openExternal: (url) => window.open(url, '_blank') },
81
+ host: { name: 'My App', openExternal: (url) => window.open(url, '_blank') },
75
82
  credentials: localStorageCredentialStore(),
76
83
  })
77
84
 
78
- function App() {
85
+ export function App() {
79
86
  return (
80
87
  <RasterProvider client={client}>
81
- <Browser />
88
+ <Library />
82
89
  </RasterProvider>
83
90
  )
84
91
  }
85
92
 
86
- function Browser() {
87
- const { isConfigured } = useSession()
88
- const libraries = useLibraries({ organizationId: 'acme' })
89
- const assets = useAssets({ organizationId: 'acme', libraryId: 'lib-1' })
93
+ function Library() {
94
+ const { credentials, isConfigured, signOut } = useSession()
95
+ const { state, signInWithDevice } = useSignIn()
96
+ // Your organization's and library's ids.
97
+ const { assets, hasMore, loadMore } = useAssets({ organizationId: 'acme', libraryId: 'lib-1' })
98
+
99
+ if (credentials === undefined) return null // still reading the saved sign-in
100
+
101
+ if (!isConfigured) {
102
+ if (state.status === 'awaitingApproval') {
103
+ return <p>Approve {state.device.userCode} in the Raster tab that just opened.</p>
104
+ }
105
+ return (
106
+ <button type="button" onClick={signInWithDevice}>
107
+ Sign in with Raster
108
+ </button>
109
+ )
110
+ }
90
111
 
91
- if (!isConfigured) return <SignIn />
92
- return <Grid assets={assets.assets ?? []} onLoadMore={assets.loadMore} />
112
+ return (
113
+ <>
114
+ {assets?.map((asset) => (
115
+ <img key={asset.id} src={getThumbUrl(asset)} alt={asset.name ?? ''} width={200} />
116
+ ))}
117
+ {hasMore && (
118
+ <button type="button" onClick={loadMore}>
119
+ Load more
120
+ </button>
121
+ )}
122
+ <button type="button" onClick={signOut}>
123
+ Sign out
124
+ </button>
125
+ </>
126
+ )
93
127
  }
94
128
  ```
95
129
 
96
- ## Provider
97
-
98
- | Prop | What it does |
99
- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
100
- | `client` or `config` | An existing `RasterClient`, or the config for one the provider creates. |
101
- | `queryClient` | The host's own TanStack `QueryClient`, from the same TanStack Query major as this package. Without one the provider creates its own, which shadows the host's for everything below. |
102
- | `state` | The `StateStore` where `useRasterNavigation` remembers the last organization and library: `memoryStateStore()` (the default), `localStorageStateStore()`, or the host's own. |
103
-
104
- ## Hooks
105
-
106
- | Hook | What it gives you |
107
- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
108
- | `useSession()` | The credential, `isConfigured` / `isSignedIn`, `userName`, `signOut`. |
109
- | `useSignIn()` | Device grant or API key. One state machine for both. Takes `scope` and `organizationId` for the device grant. |
110
- | `useOrganizations()` | Everything the credential reaches, from `/me`, as a TanStack query result. |
111
- | `useLibraries({ organizationId })` | The libraries in one organization, as a query result. Each carries `access`: `'write'`, `'read'` or `null` for none. |
112
- | `useAssets({ organizationId, libraryId })` | A library's assets, paged. |
113
- | `useAssetSearch(scope, query)` | Debounced, paged search that keeps the last results up while the next query runs. |
114
- | `useAssetUpload()` | Upload, then poll until Raster has finished processing. |
115
- | `usePromoteVariant()` | Promote a variant to its asset's default, then poll until Raster has swapped the files. Takes an optimistic update. |
116
- | `useRasterNavigation({ organizations })` | `organization → library → asset`, persisted; `refresh()` refetches every Raster query. |
117
-
118
- ## Things worth knowing
119
-
120
- - **The provider fixes its client on mount.** An inline `config` builds one client for the
121
- provider's life, and a later `client` prop is ignored: remount with a new `key` to switch.
122
- Two clients for one credential would each refresh it, spending each other's refresh token.
123
- - **`credentials` is `undefined` while the store is read.** Gate the sign-in screen on
124
- `isConfigured` once it has settled, or it flashes on every launch.
125
- - **Every fetch aborts when superseded**, which frees its connection for the requests that
126
- follow.
127
- - **The cache belongs to a sign-in.** Query keys carry the session's `credentialIdentity()`,
128
- and a sign-out or a different account drops the previous one's queries. For an API key that
129
- identity is a digest of the key, so the key itself stays out of the cache.
130
- - **Errors are `RasterApiError`s.** Branch on `code`, and show `toUserMessage(error)`.
131
- - **Raster finishes uploads and promotes after answering.** Both hooks poll until the work
132
- lands, and settle as `timed-out` when it outlasts the wait: the work is still running, and a
133
- later refetch shows it.
134
-
135
- ## Preact
136
-
137
- To use the hooks with Preact, alias `react` and `react-dom` to `preact/compat` in the bundler.
130
+ | Hook | What it gives you |
131
+ | ------------------------------------------ | ---------------------------------------------------------------------- |
132
+ | `useSession()` | `isConfigured`, `isSignedIn`, `userName` and `signOut()`. |
133
+ | `useSignIn()` | Sign-in with Raster's device flow or an API key. |
134
+ | `useOrganizations()` | The organizations the user can reach, in `data`. |
135
+ | `useLibraries({ organizationId })` | An organization's libraries, in `data`, each with the user's `access`. |
136
+ | `useAssets({ organizationId, libraryId })` | A library's `assets`, with `loadMore()`. |
137
+ | `useAssetSearch(scope, query)` | Search results, `hits` and `found`, as the user types. |
138
+ | `useAssetUpload()` | `upload()` a file, then wait for Raster to process it. |
139
+ | `usePromoteVariant()` | Make a variant its asset's default. |
140
+ | `useRasterNavigation({ organizations })` | The open organization, library and asset, remembered between visits. |
141
+
142
+ `RasterProvider` takes a `client`, or a `config` to create one, and `state`, where navigation is
143
+ remembered: `memoryStateStore()` by default, or `localStorageStateStore()`.
144
+
145
+ ### Errors
146
+
147
+ Every failure is a `RasterApiError`. Show the user `toUserMessage(error)`, and branch on
148
+ `error.code`.
149
+
150
+ ## License
151
+
152
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raster-app/react",
3
- "version": "0.1.0-canary-2e1834e",
3
+ "version": "0.1.0-canary-84a5119",
4
4
  "description": "React provider and hooks for the Raster SDK: session, organizations, libraries, assets, search and uploads.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://raster.app/docs",
@@ -10,8 +10,6 @@
10
10
  "assets",
11
11
  "react",
12
12
  "hooks",
13
- "figma",
14
- "sanity",
15
13
  "plugin"
16
14
  ],
17
15
  "type": "module",
@@ -42,7 +40,7 @@
42
40
  "test": "bun test"
43
41
  },
44
42
  "dependencies": {
45
- "@raster-app/sdk": "0.1.0-canary-2e1834e",
43
+ "@raster-app/sdk": "0.1.0-canary-84a5119",
46
44
  "@tanstack/react-query": "^5.103.1"
47
45
  },
48
46
  "peerDependencies": {