@sanity/sdk-react 2.7.0 → 3.0.0-rc.0
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.
- package/README.md +125 -63
- package/dist/index.d.ts +381 -571
- package/dist/index.js +450 -366
- package/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/_exports/index.ts +4 -0
- package/src/_exports/sdk-react.ts +16 -0
- package/src/components/SDKProvider.test.tsx +23 -58
- package/src/components/SDKProvider.tsx +38 -30
- package/src/components/SanityApp.test.tsx +12 -68
- package/src/components/SanityApp.tsx +88 -65
- package/src/components/auth/AuthBoundary.test.tsx +11 -26
- package/src/components/auth/LoginError.test.tsx +5 -0
- package/src/components/auth/LoginError.tsx +23 -2
- package/src/config/handles.ts +53 -0
- package/src/context/ComlinkTokenRefresh.test.tsx +27 -10
- package/src/context/DefaultResourceContext.ts +10 -0
- package/src/context/PerspectiveContext.ts +12 -0
- package/src/context/ResourceProvider.test.tsx +99 -19
- package/src/context/ResourceProvider.tsx +103 -37
- package/src/context/ResourcesContext.tsx +7 -0
- package/src/context/SDKStudioContext.test.tsx +33 -28
- package/src/context/SDKStudioContext.ts +6 -0
- package/src/context/renderSanityApp.test.tsx +49 -151
- package/src/context/renderSanityApp.tsx +8 -12
- package/src/hooks/agent/agentActions.test.tsx +1 -1
- package/src/hooks/agent/agentActions.ts +56 -19
- package/src/hooks/auth/useDashboardOrganizationId.test.tsx +8 -2
- package/src/hooks/auth/useVerifyOrgProjects.test.tsx +32 -8
- package/src/hooks/client/useClient.test.tsx +4 -1
- package/src/hooks/client/useClient.ts +0 -1
- package/src/hooks/context/useDefaultResource.test.tsx +25 -0
- package/src/hooks/context/useDefaultResource.ts +30 -0
- package/src/hooks/context/useSanityInstance.test.tsx +2 -140
- package/src/hooks/context/useSanityInstance.ts +9 -53
- package/src/hooks/dashboard/useDispatchIntent.test.ts +24 -15
- package/src/hooks/dashboard/useDispatchIntent.ts +7 -7
- package/src/hooks/dashboard/useManageFavorite.test.tsx +34 -94
- package/src/hooks/dashboard/useManageFavorite.ts +16 -10
- package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +7 -5
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +6 -2
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +2 -0
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.ts +2 -1
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.test.ts +17 -38
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +12 -19
- package/src/hooks/datasets/useDatasets.test.ts +8 -22
- package/src/hooks/datasets/useDatasets.ts +8 -16
- package/src/hooks/document/useApplyDocumentActions.test.ts +98 -52
- package/src/hooks/document/useApplyDocumentActions.ts +35 -37
- package/src/hooks/document/useDocument.test.tsx +8 -37
- package/src/hooks/document/useDocument.ts +78 -129
- package/src/hooks/document/useDocumentEvent.test.tsx +7 -19
- package/src/hooks/document/useDocumentEvent.ts +21 -19
- package/src/hooks/document/useDocumentPermissions.test.tsx +75 -84
- package/src/hooks/document/useDocumentPermissions.ts +41 -28
- package/src/hooks/document/useDocumentSyncStatus.test.ts +13 -3
- package/src/hooks/document/useDocumentSyncStatus.ts +19 -14
- package/src/hooks/document/useEditDocument.test.tsx +28 -70
- package/src/hooks/document/useEditDocument.ts +29 -149
- package/src/hooks/documents/useDocuments.test.tsx +44 -64
- package/src/hooks/documents/useDocuments.ts +19 -25
- package/src/hooks/helpers/createCallbackHook.test.tsx +19 -13
- package/src/hooks/helpers/createStateSourceHook.test.tsx +10 -10
- package/src/hooks/helpers/createStateSourceHook.tsx +2 -4
- package/src/hooks/helpers/useNormalizedResourceOptions.test.ts +65 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.ts +127 -0
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +27 -34
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +19 -20
- package/src/hooks/presence/usePresence.test.tsx +71 -9
- package/src/hooks/presence/usePresence.ts +28 -3
- package/src/hooks/preview/useDocumentPreview.test.tsx +85 -193
- package/src/hooks/preview/useDocumentPreview.tsx +42 -62
- package/src/hooks/projection/useDocumentProjection.test.tsx +9 -37
- package/src/hooks/projection/useDocumentProjection.ts +9 -82
- package/src/hooks/projects/useProject.test.ts +1 -2
- package/src/hooks/projects/useProject.ts +7 -8
- package/src/hooks/query/useQuery.test.tsx +5 -6
- package/src/hooks/query/useQuery.ts +12 -91
- package/src/hooks/releases/useActiveReleases.test.tsx +2 -2
- package/src/hooks/releases/useActiveReleases.ts +25 -13
- package/src/hooks/releases/usePerspective.test.tsx +9 -17
- package/src/hooks/releases/usePerspective.ts +29 -18
- package/src/hooks/users/useUser.test.tsx +9 -3
- package/src/hooks/users/useUser.ts +1 -1
- package/src/hooks/users/useUsers.test.tsx +5 -2
- package/src/hooks/users/useUsers.ts +1 -1
- package/src/context/SourcesContext.tsx +0 -7
- package/src/hooks/helpers/useNormalizedSourceOptions.ts +0 -85
package/README.md
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
<h1 align="center">Sanity App SDK (React)</h1>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
React hooks for creating Sanity applications. Live by default, optimistic updates, multi-
|
|
8
|
+
React hooks for creating Sanity applications. Live by default, optimistic updates, multi-resource support.
|
|
9
|
+
|
|
10
|
+
> **Requires React 19** — `react` and `react-dom` `^19.2.0` are the minimum peer dependencies.
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
@@ -30,22 +32,31 @@ Opens at `https://www.sanity.io/welcome?dev=http%3A%2F%2Flocalhost%3A3333`, prox
|
|
|
30
32
|
### 2. Project configuration
|
|
31
33
|
|
|
32
34
|
```tsx
|
|
33
|
-
import {SanityApp
|
|
34
|
-
|
|
35
|
-
const config: SanityConfig[] = [
|
|
36
|
-
{projectId: 'abc123', dataset: 'production'},
|
|
37
|
-
{projectId: 'def456', dataset: 'production'}, // multi-project support
|
|
38
|
-
]
|
|
35
|
+
import {SanityApp} from '@sanity/sdk-react'
|
|
39
36
|
|
|
40
37
|
export function App() {
|
|
41
38
|
return (
|
|
42
|
-
<SanityApp
|
|
39
|
+
<SanityApp
|
|
40
|
+
resources={{
|
|
41
|
+
'default': {projectId: 'abc123', dataset: 'production'},
|
|
42
|
+
'second-project': {projectId: 'def456', dataset: 'production'},
|
|
43
|
+
}}
|
|
44
|
+
fallback={<div>Loading...</div>}
|
|
45
|
+
>
|
|
43
46
|
<YourApp />
|
|
44
47
|
</SanityApp>
|
|
45
48
|
)
|
|
46
49
|
}
|
|
47
50
|
```
|
|
48
51
|
|
|
52
|
+
In Sanity, a **resource** identifies where your data lives. It can be one of:
|
|
53
|
+
|
|
54
|
+
- a project and dataset pair (`{ projectId, dataset }`)
|
|
55
|
+
- a media library (`{ mediaLibraryId }`)
|
|
56
|
+
- or a canvas (`{ canvasId }`)
|
|
57
|
+
|
|
58
|
+
The `resources` prop is a map of named resources. Each resource tells the SDK where to read and write data. The resource keyed `"default"` is used automatically when no explicit resource is specified in a hook.
|
|
59
|
+
|
|
49
60
|
**Auth is automatic** — Dashboard injects an auth token via iframe. No custom login flow is needed for your application.
|
|
50
61
|
|
|
51
62
|
---
|
|
@@ -60,11 +71,14 @@ Document handles are a core concept for apps built with the App SDK. Document ha
|
|
|
60
71
|
type DocumentHandle = {
|
|
61
72
|
documentId: string
|
|
62
73
|
documentType: string
|
|
63
|
-
|
|
64
|
-
dataset?: string // optional if using the default dataset or inside a ResourceProvider
|
|
74
|
+
resource: DocumentResource // e.g. { projectId, dataset }, { mediaLibraryId }, or { canvasId }
|
|
65
75
|
}
|
|
66
76
|
```
|
|
67
77
|
|
|
78
|
+
The `resource` field identifies where the document lives. When you fetch document handles from hooks like `useDocuments`, the `resource` is automatically populated from the current context.
|
|
79
|
+
|
|
80
|
+
Most hooks also accept `resourceName` to target a specific named resource declared in the `resources` prop on `<SanityApp>`, or a `resource` object directly. When neither is provided, the `"default"` resource is used.
|
|
81
|
+
|
|
68
82
|
**Best practice:** Fetch document handles first → pass them to child components → fetch individual document content from child components.
|
|
69
83
|
|
|
70
84
|
---
|
|
@@ -123,7 +137,7 @@ import {
|
|
|
123
137
|
unpublishDocument,
|
|
124
138
|
deleteDocument,
|
|
125
139
|
createDocument,
|
|
126
|
-
|
|
140
|
+
discardDocument,
|
|
127
141
|
} from '@sanity/sdk-react'
|
|
128
142
|
|
|
129
143
|
const apply = useApplyDocumentActions()
|
|
@@ -179,7 +193,7 @@ The `useApplyDocumentActions` hook is used to perform document lifecycle operati
|
|
|
179
193
|
| `publishDocument` | Publish a draft (copy draft → published) |
|
|
180
194
|
| `unpublishDocument` | Unpublish (delete published, keep draft) |
|
|
181
195
|
| `deleteDocument` | Delete document entirely (draft and published) |
|
|
182
|
-
| `
|
|
196
|
+
| `discardDocument` | Discard draft changes, revert to published |
|
|
183
197
|
|
|
184
198
|
#### Creating Documents
|
|
185
199
|
|
|
@@ -320,7 +334,7 @@ The SDK handles updating the document state automatically:
|
|
|
320
334
|
- `useDocument()` returns draft if exists, else published
|
|
321
335
|
- `useEditDocument()` creates draft on first edit (automatic)
|
|
322
336
|
- `publishDocument()` copies draft → published, deletes draft
|
|
323
|
-
- `
|
|
337
|
+
- `discardDocument()` deletes draft, reverts to published
|
|
324
338
|
|
|
325
339
|
#### LiveEdit Documents
|
|
326
340
|
|
|
@@ -330,6 +344,7 @@ For documents that don't need the draft/published workflow (such as settings, co
|
|
|
330
344
|
const settingsHandle: DocumentHandle = {
|
|
331
345
|
documentId: 'site-settings',
|
|
332
346
|
documentType: 'settings',
|
|
347
|
+
resource: {projectId: 'abc123', dataset: 'production'},
|
|
333
348
|
liveEdit: true, // Edits apply directly without creating a draft
|
|
334
349
|
}
|
|
335
350
|
|
|
@@ -341,7 +356,7 @@ const editSettings = useEditDocument(settingsHandle)
|
|
|
341
356
|
|
|
342
357
|
- Drafts will not be created when the document is edited
|
|
343
358
|
- Edits will be applied directly to the published document
|
|
344
|
-
- `publishDocument()`, `unpublishDocument()`, and `
|
|
359
|
+
- `publishDocument()`, `unpublishDocument()`, and `discardDocument()` actions cannot be used (since liveEdit documents are always published and do not have drafts)
|
|
345
360
|
|
|
346
361
|
For more details, see the [Sanity documentation on liveEdit documents](https://www.sanity.io/docs/content-lake/drafts).
|
|
347
362
|
|
|
@@ -361,32 +376,80 @@ Any mutation to a subscribed document (even fields you don't display) will trigg
|
|
|
361
376
|
|
|
362
377
|
---
|
|
363
378
|
|
|
364
|
-
### Multi-
|
|
379
|
+
### Multi-Resource Access
|
|
380
|
+
|
|
381
|
+
If your app only uses a single project and dataset, the `"default"` resource handles everything. When you need to pull data from additional projects, datasets, media libraries, or canvases, you can specify additional resources as needed. There are three main approaches to providing additional resources:
|
|
382
|
+
|
|
383
|
+
#### Approach 1: Use Named Resources (recommended)
|
|
384
|
+
|
|
385
|
+
Register all your resources in the `resources` prop on `<SanityApp>` and reference them by name with `resourceName`:
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
import {SanityApp} from '@sanity/sdk-react'
|
|
389
|
+
|
|
390
|
+
export function App() {
|
|
391
|
+
return (
|
|
392
|
+
<SanityApp
|
|
393
|
+
resources={{
|
|
394
|
+
default: {projectId: 'project-a', dataset: 'production'},
|
|
395
|
+
staging: {projectId: 'project-a', dataset: 'staging'},
|
|
396
|
+
media: {mediaLibraryId: 'my-media-library'},
|
|
397
|
+
}}
|
|
398
|
+
fallback={<div>Loading...</div>}
|
|
399
|
+
>
|
|
400
|
+
<MyApp />
|
|
401
|
+
</SanityApp>
|
|
402
|
+
)
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Then reference them in hooks:
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
import {useDocument, useQuery} from '@sanity/sdk-react'
|
|
410
|
+
|
|
411
|
+
function StagingPreview({documentId}: {documentId: string}) {
|
|
412
|
+
const {data} = useDocument({
|
|
413
|
+
documentId,
|
|
414
|
+
documentType: 'article',
|
|
415
|
+
resourceName: 'staging',
|
|
416
|
+
})
|
|
417
|
+
return <pre>{JSON.stringify(data, null, 2)}</pre>
|
|
418
|
+
}
|
|
365
419
|
|
|
366
|
-
|
|
420
|
+
function MediaAssets() {
|
|
421
|
+
const {data} = useQuery({
|
|
422
|
+
query: '*[_type == "sanity.asset"][0...10]',
|
|
423
|
+
resourceName: 'media',
|
|
424
|
+
})
|
|
425
|
+
return (
|
|
426
|
+
<ul>
|
|
427
|
+
{data?.map((asset) => (
|
|
428
|
+
<li key={asset._id}>{asset.originalFilename}</li>
|
|
429
|
+
))}
|
|
430
|
+
</ul>
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
```
|
|
367
434
|
|
|
368
|
-
#### Approach
|
|
435
|
+
#### Approach 2: Pass a Resource Object Directly
|
|
369
436
|
|
|
370
|
-
|
|
437
|
+
If you only need to access a resource in one or two places within your app, you can pass it inline via the `resource` option:
|
|
371
438
|
|
|
372
439
|
```tsx
|
|
373
440
|
import {useDocument} from '@sanity/sdk-react'
|
|
374
441
|
|
|
375
442
|
function MultiProjectComponent() {
|
|
376
|
-
// Fetch from Project A
|
|
377
443
|
const {data: productA} = useDocument({
|
|
378
444
|
documentId: 'product-123',
|
|
379
445
|
documentType: 'product',
|
|
380
|
-
projectId: 'project-a',
|
|
381
|
-
dataset: 'production',
|
|
446
|
+
resource: {projectId: 'project-a', dataset: 'production'},
|
|
382
447
|
})
|
|
383
448
|
|
|
384
|
-
// Fetch from Project B
|
|
385
449
|
const {data: productB} = useDocument({
|
|
386
450
|
documentId: 'product-456',
|
|
387
451
|
documentType: 'product',
|
|
388
|
-
projectId: 'project-b',
|
|
389
|
-
dataset: 'staging',
|
|
452
|
+
resource: {projectId: 'project-b', dataset: 'staging'},
|
|
390
453
|
})
|
|
391
454
|
|
|
392
455
|
return (
|
|
@@ -398,46 +461,41 @@ function MultiProjectComponent() {
|
|
|
398
461
|
}
|
|
399
462
|
```
|
|
400
463
|
|
|
401
|
-
#### Approach
|
|
464
|
+
#### Approach 3: Use ResourceProvider to Set Context
|
|
402
465
|
|
|
403
|
-
|
|
466
|
+
If you need to access certain resources within multiple sibling components, wrap those components in `ResourceProvider` and set a default resource for all its child components:
|
|
404
467
|
|
|
405
468
|
```tsx
|
|
406
|
-
|
|
407
|
-
import {ResourceProvider, useDocument, useSanityInstance} from '@sanity/sdk-react'
|
|
469
|
+
import {ResourceProvider, useDocument} from '@sanity/sdk-react'
|
|
408
470
|
|
|
409
471
|
function ProductCard({productId}: {productId: string}) {
|
|
410
|
-
//
|
|
411
|
-
const {config} = useSanityInstance()
|
|
412
|
-
|
|
413
|
-
// No need to specify projectId/dataset - inherited from ResourceProvider
|
|
472
|
+
// No need to specify a resource - inherited from ResourceProvider
|
|
414
473
|
const {data: product} = useDocument({
|
|
415
474
|
documentId: productId,
|
|
416
475
|
documentType: 'product',
|
|
417
476
|
})
|
|
418
477
|
|
|
419
|
-
return
|
|
420
|
-
<div>
|
|
421
|
-
<h3>{product?.title}</h3>
|
|
422
|
-
<p>
|
|
423
|
-
From: {config.projectId}.{config.dataset}
|
|
424
|
-
</p>
|
|
425
|
-
</div>
|
|
426
|
-
)
|
|
478
|
+
return <h3>{product?.title}</h3>
|
|
427
479
|
}
|
|
428
480
|
|
|
429
481
|
export function MultiProjectApp() {
|
|
430
482
|
return (
|
|
431
483
|
<div>
|
|
432
484
|
{/* Products from Project A */}
|
|
433
|
-
<ResourceProvider
|
|
485
|
+
<ResourceProvider
|
|
486
|
+
resource={{projectId: 'project-a', dataset: 'production'}}
|
|
487
|
+
fallback={<div>Loading...</div>}
|
|
488
|
+
>
|
|
434
489
|
<h2>Project A Products</h2>
|
|
435
490
|
<ProductCard productId="product-123" />
|
|
436
491
|
<ProductCard productId="product-456" />
|
|
437
492
|
</ResourceProvider>
|
|
438
493
|
|
|
439
494
|
{/* Products from Project B */}
|
|
440
|
-
<ResourceProvider
|
|
495
|
+
<ResourceProvider
|
|
496
|
+
resource={{projectId: 'project-b', dataset: 'staging'}}
|
|
497
|
+
fallback={<div>Loading...</div>}
|
|
498
|
+
>
|
|
441
499
|
<h2>Project B Products</h2>
|
|
442
500
|
<ProductCard productId="product-789" />
|
|
443
501
|
</ResourceProvider>
|
|
@@ -448,17 +506,16 @@ export function MultiProjectApp() {
|
|
|
448
506
|
|
|
449
507
|
**Key Points:**
|
|
450
508
|
|
|
451
|
-
-
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
- You can nest ResourceProvider components
|
|
455
|
-
- Regardless of the approach you use, the project IDs and dataset names you reference (whether in document handles or ResourceProviders) must be enumerated in your application’s [SanityConfig objects](https://www.sanity.io/docs/app-sdk/sdk-configuration#d95b8773097c)
|
|
509
|
+
- The `"default"` resource is used automatically when no `resourceName`, `resource`, or `ResourceProvider` context is present
|
|
510
|
+
- Named resources (`resourceName`) are the recommended pattern for apps that work with multiple data sources
|
|
511
|
+
- `ResourceProvider` sets context for an entire subtree — hooks inside it inherit the resource without needing to specify it
|
|
512
|
+
- You can nest `ResourceProvider` components; the closest provider wins when no explicit resource is given
|
|
456
513
|
|
|
457
514
|
---
|
|
458
515
|
|
|
459
516
|
### Using the SDK inside Sanity Studio
|
|
460
517
|
|
|
461
|
-
The SDK can be embedded directly inside a Sanity Studio with zero manual configuration. Sanity Studio provides `SDKStudioContext` automatically, so `SanityApp` derives
|
|
518
|
+
The SDK can be embedded directly inside a Sanity Studio with zero manual configuration. Sanity Studio provides `SDKStudioContext` automatically, so `SanityApp` derives its resource configuration and auth from the Studio's workspace without any setup.
|
|
462
519
|
|
|
463
520
|
#### Zero-config setup (recommended)
|
|
464
521
|
|
|
@@ -492,11 +549,13 @@ function StudioSDKWrapper({children}) {
|
|
|
492
549
|
|
|
493
550
|
#### Explicit config takes precedence
|
|
494
551
|
|
|
495
|
-
If you pass
|
|
552
|
+
If you pass `resources` (data sources) or `config` (auth, studio, and perspective settings) props to `SanityApp`, they take precedence over any workspace config picked up by `SDKStudioContext`:
|
|
496
553
|
|
|
497
554
|
```tsx
|
|
498
|
-
|
|
499
|
-
|
|
555
|
+
<SanityApp
|
|
556
|
+
resources={{default: {projectId: 'other-project', dataset: 'staging'}}}
|
|
557
|
+
fallback={<Loading />}
|
|
558
|
+
>
|
|
500
559
|
<MyComponent />
|
|
501
560
|
</SanityApp>
|
|
502
561
|
```
|
|
@@ -507,32 +566,35 @@ If the Studio provides a reactive token source via `workspace.auth.token`, the S
|
|
|
507
566
|
|
|
508
567
|
For older Studios that don't expose a token source, the SDK falls back to discovering the auth token from `localStorage` or cookie auth.
|
|
509
568
|
|
|
510
|
-
####
|
|
569
|
+
#### `studioMode` has been removed
|
|
511
570
|
|
|
512
|
-
The `studioMode` config field
|
|
571
|
+
The `studioMode` config field was removed in v3. The recommended replacement is to use the zero-config `SDKStudioContext` approach described above — which requires no `config` prop at all.
|
|
513
572
|
|
|
514
|
-
If you
|
|
573
|
+
If you previously used `studioMode`, replace it with `studio`:
|
|
515
574
|
|
|
516
575
|
```diff
|
|
517
576
|
const config: SanityConfig = {
|
|
518
|
-
|
|
519
|
-
|
|
577
|
+
- projectId: 'my-project',
|
|
578
|
+
- dataset: 'production',
|
|
520
579
|
- studioMode: { enabled: true },
|
|
521
580
|
+ studio: {},
|
|
522
581
|
}
|
|
523
582
|
```
|
|
524
583
|
|
|
525
|
-
|
|
584
|
+
See the [Migration Guide](./guides/0-Migration-Guide.md) for all v3 breaking changes and upgrade steps.
|
|
526
585
|
|
|
527
|
-
|
|
586
|
+
---
|
|
528
587
|
|
|
529
|
-
|
|
530
|
-
# Generate types from your schema
|
|
531
|
-
npx sanity typegen generate
|
|
532
|
-
```
|
|
588
|
+
### TypeScript
|
|
533
589
|
|
|
534
590
|
```tsx
|
|
535
|
-
import type
|
|
591
|
+
import {type SanityDocument} from '@sanity/sdk-react'
|
|
592
|
+
|
|
593
|
+
interface Article extends SanityDocument {
|
|
594
|
+
_type: 'article'
|
|
595
|
+
title: string
|
|
596
|
+
body: string
|
|
597
|
+
}
|
|
536
598
|
|
|
537
599
|
const {data} = useDocument<Article>(handle)
|
|
538
600
|
// data is typed as Article
|