@sanity/sdk-react 0.0.2 → 1.0.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 +3 -3
- package/dist/index.d.ts +302 -273
- package/dist/index.js +14 -7
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/_exports/sdk-react.ts +8 -8
- package/src/hooks/document/useApplyDocumentActions.ts +4 -4
- package/src/hooks/document/useDocument.test.ts +8 -10
- package/src/hooks/document/useDocument.ts +50 -33
- package/src/hooks/document/useDocumentEvent.ts +2 -2
- package/src/hooks/document/useDocumentSyncStatus.ts +1 -1
- package/src/hooks/document/useEditDocument.ts +15 -15
- package/src/hooks/documents/useDocuments.ts +5 -5
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +5 -5
- package/src/hooks/preview/{usePreview.test.tsx → useDocumentPreview.test.tsx} +5 -5
- package/src/hooks/preview/{usePreview.tsx → useDocumentPreview.tsx} +11 -8
- package/src/hooks/projection/{useProjection.test.tsx → useDocumentProjection.test.tsx} +5 -5
- package/src/hooks/projection/{useProjection.ts → useDocumentProjection.ts} +22 -17
- package/src/hooks/query/useQuery.ts +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/sdk-react",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Sanity SDK React toolkit for Content OS",
|
|
6
6
|
"keywords": [
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"@sanity/message-protocol": "^0.12.0",
|
|
47
47
|
"@sanity/types": "^3.83.0",
|
|
48
48
|
"@types/lodash-es": "^4.17.12",
|
|
49
|
-
"groq": "3.
|
|
49
|
+
"groq": "3.88.1-typegen-experimental.0",
|
|
50
50
|
"lodash-es": "^4.17.21",
|
|
51
51
|
"react-compiler-runtime": "19.1.0-rc.1",
|
|
52
52
|
"react-error-boundary": "^5.0.0",
|
|
53
53
|
"rxjs": "^7.8.2",
|
|
54
|
-
"@sanity/sdk": "0.0
|
|
54
|
+
"@sanity/sdk": "1.0.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@sanity/browserslist-config": "^1.0.5",
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
"typescript": "^5.8.3",
|
|
75
75
|
"vite": "^6.3.4",
|
|
76
76
|
"vitest": "^3.1.2",
|
|
77
|
-
"@repo/config-eslint": "0.0.0",
|
|
78
|
-
"@repo/package.bundle": "3.82.0",
|
|
79
77
|
"@repo/config-test": "0.0.1",
|
|
78
|
+
"@repo/package.bundle": "3.82.0",
|
|
80
79
|
"@repo/package.config": "0.0.1",
|
|
81
|
-
"@repo/tsconfig": "0.0.1"
|
|
80
|
+
"@repo/tsconfig": "0.0.1",
|
|
81
|
+
"@repo/config-eslint": "0.0.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
84
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -52,15 +52,15 @@ export {
|
|
|
52
52
|
usePaginatedDocuments,
|
|
53
53
|
} from '../hooks/paginatedDocuments/usePaginatedDocuments'
|
|
54
54
|
export {
|
|
55
|
-
|
|
56
|
-
type
|
|
57
|
-
type
|
|
58
|
-
} from '../hooks/preview/
|
|
55
|
+
useDocumentPreview,
|
|
56
|
+
type useDocumentPreviewOptions,
|
|
57
|
+
type useDocumentPreviewResults,
|
|
58
|
+
} from '../hooks/preview/useDocumentPreview'
|
|
59
59
|
export {
|
|
60
|
-
|
|
61
|
-
type
|
|
62
|
-
type
|
|
63
|
-
} from '../hooks/projection/
|
|
60
|
+
useDocumentProjection,
|
|
61
|
+
type useDocumentProjectionOptions,
|
|
62
|
+
type useDocumentProjectionResults,
|
|
63
|
+
} from '../hooks/projection/useDocumentProjection'
|
|
64
64
|
export {useProject} from '../hooks/projects/useProject'
|
|
65
65
|
export {type ProjectWithoutMembers, useProjects} from '../hooks/projects/useProjects'
|
|
66
66
|
export {useQuery} from '../hooks/query/useQuery'
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type ApplyDocumentActionsOptions,
|
|
5
5
|
type DocumentAction,
|
|
6
6
|
} from '@sanity/sdk'
|
|
7
|
-
import {type
|
|
7
|
+
import {type SanityDocument} from 'groq'
|
|
8
8
|
|
|
9
9
|
import {createCallbackHook} from '../helpers/createCallbackHook'
|
|
10
10
|
// this import is used in an `{@link useEditDocument}`
|
|
@@ -12,7 +12,7 @@ import {createCallbackHook} from '../helpers/createCallbackHook'
|
|
|
12
12
|
import type {useEditDocument} from './useEditDocument'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @
|
|
15
|
+
* @public
|
|
16
16
|
*/
|
|
17
17
|
interface UseApplyDocumentActions {
|
|
18
18
|
(): <
|
|
@@ -24,11 +24,11 @@ interface UseApplyDocumentActions {
|
|
|
24
24
|
| DocumentAction<TDocumentType, TDataset, TProjectId>
|
|
25
25
|
| DocumentAction<TDocumentType, TDataset, TProjectId>[],
|
|
26
26
|
options?: ApplyDocumentActionsOptions,
|
|
27
|
-
) => Promise<ActionsResult<
|
|
27
|
+
) => Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* @
|
|
31
|
+
* @public
|
|
32
32
|
*
|
|
33
33
|
* Provides a stable callback function for applying one or more document actions.
|
|
34
34
|
*
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '@sanity/sdk'
|
|
8
8
|
import {type SanityDocument} from '@sanity/types'
|
|
9
9
|
import {renderHook} from '@testing-library/react'
|
|
10
|
-
import {type
|
|
10
|
+
import {type SchemaOrigin} from 'groq'
|
|
11
11
|
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
12
12
|
|
|
13
13
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
@@ -23,7 +23,7 @@ vi.mock('../context/useSanityInstance', () => ({
|
|
|
23
23
|
}))
|
|
24
24
|
|
|
25
25
|
// Define a single generic TestDocument type
|
|
26
|
-
type UseDocumentTestType =
|
|
26
|
+
type UseDocumentTestType = SchemaOrigin<
|
|
27
27
|
SanityDocument & {
|
|
28
28
|
_type: 'use-document-test-type'
|
|
29
29
|
foo?: string
|
|
@@ -33,11 +33,10 @@ type UseDocumentTestType = DatasetScoped<
|
|
|
33
33
|
value?: number
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
-
'use-document-test-dataset'
|
|
37
|
-
'p'
|
|
36
|
+
'p.use-document-test-dataset'
|
|
38
37
|
>
|
|
39
38
|
|
|
40
|
-
type UseDocumentTestTypeAlt =
|
|
39
|
+
type UseDocumentTestTypeAlt = SchemaOrigin<
|
|
41
40
|
SanityDocument & {
|
|
42
41
|
_type: 'use-document-test-type'
|
|
43
42
|
bar: string[]
|
|
@@ -45,16 +44,15 @@ type UseDocumentTestTypeAlt = DatasetScoped<
|
|
|
45
44
|
value?: number
|
|
46
45
|
}
|
|
47
46
|
},
|
|
48
|
-
'use-document-test-alt-dataset'
|
|
49
|
-
'p'
|
|
47
|
+
'p.use-document-test-alt-dataset'
|
|
50
48
|
>
|
|
51
49
|
|
|
52
50
|
// Scope the TestDocument type to the project/datasets used in tests
|
|
53
51
|
|
|
54
52
|
declare module 'groq' {
|
|
55
53
|
interface SanitySchemas {
|
|
56
|
-
'p
|
|
57
|
-
'p
|
|
54
|
+
'p.use-document-test-dataset': UseDocumentTestType
|
|
55
|
+
'p.use-document-test-alt-dataset': UseDocumentTestTypeAlt
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -85,7 +83,7 @@ describe('useDocument hook', () => {
|
|
|
85
83
|
|
|
86
84
|
const {result} = renderHook(() => useDocument({documentId: 'doc1', documentType: 'book'}))
|
|
87
85
|
|
|
88
|
-
expect(result.current).toEqual(book)
|
|
86
|
+
expect(result.current.data).toEqual(book)
|
|
89
87
|
expect(getCurrent).toHaveBeenCalled()
|
|
90
88
|
expect(subscribe).toHaveBeenCalled()
|
|
91
89
|
})
|
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
import {type DocumentOptions, getDocumentState, type JsonMatch, resolveDocument} from '@sanity/sdk'
|
|
2
|
-
import {type
|
|
2
|
+
import {type SanityDocument} from 'groq'
|
|
3
3
|
import {identity} from 'rxjs'
|
|
4
4
|
|
|
5
5
|
import {createStateSourceHook} from '../helpers/createStateSourceHook'
|
|
6
|
-
// used in an `{@link
|
|
6
|
+
// used in an `{@link useDocumentProjection}` and `{@link useQuery}`
|
|
7
7
|
// eslint-disable-next-line import/consistent-type-specifier-style, unused-imports/no-unused-imports
|
|
8
|
-
import type {
|
|
8
|
+
import type {useDocumentProjection} from '../projection/useDocumentProjection'
|
|
9
9
|
// eslint-disable-next-line import/consistent-type-specifier-style, unused-imports/no-unused-imports
|
|
10
10
|
import type {useQuery} from '../query/useQuery'
|
|
11
11
|
|
|
12
|
+
const useDocumentValue = createStateSourceHook({
|
|
13
|
+
// Pass options directly to getDocumentState
|
|
14
|
+
getState: (instance, options: DocumentOptions<string | undefined>) =>
|
|
15
|
+
getDocumentState(instance, options),
|
|
16
|
+
// Pass options directly to getDocumentState for checking current value
|
|
17
|
+
shouldSuspend: (instance, {path: _path, ...options}: DocumentOptions<string | undefined>) =>
|
|
18
|
+
getDocumentState(instance, options).getCurrent() === undefined,
|
|
19
|
+
// Extract handle part for resolveDocument
|
|
20
|
+
suspender: (instance, options: DocumentOptions<string | undefined>) =>
|
|
21
|
+
resolveDocument(instance, options),
|
|
22
|
+
getConfig: identity as (
|
|
23
|
+
options: DocumentOptions<string | undefined>,
|
|
24
|
+
) => DocumentOptions<string | undefined>,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const wrapHookWithData = <TParams extends unknown[], TReturn>(
|
|
28
|
+
useValue: (...params: TParams) => TReturn,
|
|
29
|
+
) => {
|
|
30
|
+
function useHook(...params: TParams) {
|
|
31
|
+
return {data: useValue(...params)}
|
|
32
|
+
}
|
|
33
|
+
return useHook
|
|
34
|
+
}
|
|
35
|
+
|
|
12
36
|
interface UseDocument {
|
|
13
37
|
/** @internal */
|
|
14
38
|
<TDocumentType extends string, TDataset extends string, TProjectId extends string = string>(
|
|
15
39
|
options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,
|
|
16
|
-
):
|
|
40
|
+
): {data: SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | null}
|
|
17
41
|
|
|
18
42
|
/** @internal */
|
|
19
43
|
<
|
|
@@ -23,17 +47,19 @@ interface UseDocument {
|
|
|
23
47
|
TProjectId extends string = string,
|
|
24
48
|
>(
|
|
25
49
|
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
26
|
-
):
|
|
50
|
+
): {
|
|
51
|
+
data: JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath> | undefined
|
|
52
|
+
}
|
|
27
53
|
|
|
28
54
|
/** @internal */
|
|
29
|
-
<TData>(options: DocumentOptions<undefined>): TData | null
|
|
55
|
+
<TData>(options: DocumentOptions<undefined>): {data: TData | null}
|
|
30
56
|
/** @internal */
|
|
31
|
-
<TData>(options: DocumentOptions<string>): TData | undefined
|
|
57
|
+
<TData>(options: DocumentOptions<string>): {data: TData | undefined}
|
|
32
58
|
|
|
33
59
|
/**
|
|
34
60
|
* ## useDocument via Type Inference (Recommended)
|
|
35
61
|
*
|
|
36
|
-
* @
|
|
62
|
+
* @public
|
|
37
63
|
*
|
|
38
64
|
* The preferred way to use this hook when working with Sanity Typegen.
|
|
39
65
|
*
|
|
@@ -68,7 +94,7 @@ interface UseDocument {
|
|
|
68
94
|
* }
|
|
69
95
|
*
|
|
70
96
|
* function ProductView({doc}: ProductViewProps) {
|
|
71
|
-
* const product = useDocument({...doc}) // Fully typed product
|
|
97
|
+
* const {data: product} = useDocument({...doc}) // Fully typed product
|
|
72
98
|
* return <h1>{product.title ?? 'Untitled'}</h1>
|
|
73
99
|
* }
|
|
74
100
|
* ```
|
|
@@ -82,7 +108,7 @@ interface UseDocument {
|
|
|
82
108
|
* }
|
|
83
109
|
*
|
|
84
110
|
* function ProductTitle({doc}: ProductTitleProps) {
|
|
85
|
-
* const title = useDocument({
|
|
111
|
+
* const {data: title} = useDocument({
|
|
86
112
|
* ...doc,
|
|
87
113
|
* path: 'title' // Returns just the title field
|
|
88
114
|
* })
|
|
@@ -100,11 +126,15 @@ interface UseDocument {
|
|
|
100
126
|
>(
|
|
101
127
|
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
102
128
|
): TPath extends string
|
|
103
|
-
?
|
|
104
|
-
|
|
129
|
+
? {
|
|
130
|
+
data:
|
|
131
|
+
| JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath>
|
|
132
|
+
| undefined
|
|
133
|
+
}
|
|
134
|
+
: {data: SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | null}
|
|
105
135
|
|
|
106
136
|
/**
|
|
107
|
-
* @
|
|
137
|
+
* @public
|
|
108
138
|
*
|
|
109
139
|
* ## useDocument via Explicit Types
|
|
110
140
|
*
|
|
@@ -142,7 +172,7 @@ interface UseDocument {
|
|
|
142
172
|
* }
|
|
143
173
|
*
|
|
144
174
|
* function BookView({doc}: BookViewProps) {
|
|
145
|
-
* const book = useDocument<Book>({...doc})
|
|
175
|
+
* const {data: book} = useDocument<Book>({...doc})
|
|
146
176
|
* return <h1>{book?.title ?? 'Untitled'} by {book?.author ?? 'Unknown'}</h1>
|
|
147
177
|
* }
|
|
148
178
|
* ```
|
|
@@ -156,7 +186,7 @@ interface UseDocument {
|
|
|
156
186
|
* }
|
|
157
187
|
*
|
|
158
188
|
* function BookTitle({doc}: BookTitleProps) {
|
|
159
|
-
* const title = useDocument<string>({...doc, path: 'title'})
|
|
189
|
+
* const {data: title} = useDocument<string>({...doc, path: 'title'})
|
|
160
190
|
* return <h1>{title ?? 'Untitled'}</h1>
|
|
161
191
|
* }
|
|
162
192
|
* ```
|
|
@@ -165,16 +195,16 @@ interface UseDocument {
|
|
|
165
195
|
*/
|
|
166
196
|
<TData, TPath extends string>(
|
|
167
197
|
options: DocumentOptions<TPath>,
|
|
168
|
-
): TPath extends string ? TData | undefined : TData | null
|
|
198
|
+
): TPath extends string ? {data: TData | undefined} : {data: TData | null}
|
|
169
199
|
|
|
170
200
|
/**
|
|
171
201
|
* @internal
|
|
172
202
|
*/
|
|
173
|
-
(options: DocumentOptions): unknown
|
|
203
|
+
(options: DocumentOptions): {data: unknown}
|
|
174
204
|
}
|
|
175
205
|
|
|
176
206
|
/**
|
|
177
|
-
* @
|
|
207
|
+
* @public
|
|
178
208
|
* Reads and subscribes to a document's realtime state, incorporating both local and remote changes.
|
|
179
209
|
*
|
|
180
210
|
* This hook comes in two main flavors to suit your needs:
|
|
@@ -191,22 +221,9 @@ interface UseDocument {
|
|
|
191
221
|
* - Realtime updates aren't critical
|
|
192
222
|
* - You want better performance
|
|
193
223
|
*
|
|
194
|
-
* …consider using {@link
|
|
224
|
+
* …consider using {@link useDocumentProjection} or {@link useQuery} instead. These hooks are more efficient
|
|
195
225
|
* for read-heavy applications.
|
|
196
226
|
*
|
|
197
227
|
* @function
|
|
198
228
|
*/
|
|
199
|
-
export const useDocument =
|
|
200
|
-
// Pass options directly to getDocumentState
|
|
201
|
-
getState: (instance, options: DocumentOptions<string | undefined>) =>
|
|
202
|
-
getDocumentState(instance, options),
|
|
203
|
-
// Pass options directly to getDocumentState for checking current value
|
|
204
|
-
shouldSuspend: (instance, {path: _path, ...options}: DocumentOptions<string | undefined>) =>
|
|
205
|
-
getDocumentState(instance, options).getCurrent() === undefined,
|
|
206
|
-
// Extract handle part for resolveDocument
|
|
207
|
-
suspender: (instance, options: DocumentOptions<string | undefined>) =>
|
|
208
|
-
resolveDocument(instance, options),
|
|
209
|
-
getConfig: identity as (
|
|
210
|
-
options: DocumentOptions<string | undefined>,
|
|
211
|
-
) => DocumentOptions<string | undefined>,
|
|
212
|
-
}) as UseDocument
|
|
229
|
+
export const useDocument = wrapHookWithData(useDocumentValue) as UseDocument
|
|
@@ -4,7 +4,7 @@ import {useCallback, useEffect, useInsertionEffect, useRef} from 'react'
|
|
|
4
4
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @
|
|
7
|
+
* @public
|
|
8
8
|
*/
|
|
9
9
|
export interface UseDocumentEventOptions<
|
|
10
10
|
TDataset extends string = string,
|
|
@@ -15,7 +15,7 @@ export interface UseDocumentEventOptions<
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
*
|
|
18
|
-
* @
|
|
18
|
+
* @public
|
|
19
19
|
*
|
|
20
20
|
* Subscribes an event handler to events in your application's document store.
|
|
21
21
|
*
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type JsonMatch,
|
|
7
7
|
resolveDocument,
|
|
8
8
|
} from '@sanity/sdk'
|
|
9
|
-
import {type
|
|
9
|
+
import {type SanityDocument} from 'groq'
|
|
10
10
|
import {useCallback} from 'react'
|
|
11
11
|
|
|
12
12
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
@@ -18,7 +18,7 @@ type Updater<TValue> = TValue | ((currentValue: TValue) => TValue)
|
|
|
18
18
|
|
|
19
19
|
// Overload 1: No path, relies on Typegen
|
|
20
20
|
/**
|
|
21
|
-
* @
|
|
21
|
+
* @public
|
|
22
22
|
* Edit an entire document, relying on Typegen for the type.
|
|
23
23
|
*
|
|
24
24
|
* @param options - Document options including `documentId`, `documentType`, and optionally `projectId`/`dataset`.
|
|
@@ -32,12 +32,12 @@ export function useEditDocument<
|
|
|
32
32
|
>(
|
|
33
33
|
options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,
|
|
34
34
|
): (
|
|
35
|
-
nextValue: Updater<
|
|
36
|
-
) => Promise<ActionsResult<
|
|
35
|
+
nextValue: Updater<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>,
|
|
36
|
+
) => Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>
|
|
37
37
|
|
|
38
38
|
// Overload 2: Path provided, relies on Typegen
|
|
39
39
|
/**
|
|
40
|
-
* @
|
|
40
|
+
* @public
|
|
41
41
|
* Edit a specific path within a document, relying on Typegen for the type.
|
|
42
42
|
*
|
|
43
43
|
* @param options - Document options including `documentId`, `documentType`, `path`, and optionally `projectId`/`dataset`.
|
|
@@ -52,12 +52,12 @@ export function useEditDocument<
|
|
|
52
52
|
>(
|
|
53
53
|
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
54
54
|
): (
|
|
55
|
-
nextValue: Updater<JsonMatch<
|
|
56
|
-
) => Promise<ActionsResult<
|
|
55
|
+
nextValue: Updater<JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath>>,
|
|
56
|
+
) => Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>
|
|
57
57
|
|
|
58
58
|
// Overload 3: Explicit type, no path
|
|
59
59
|
/**
|
|
60
|
-
* @
|
|
60
|
+
* @public
|
|
61
61
|
* Edit an entire document with an explicit type `TData`.
|
|
62
62
|
*
|
|
63
63
|
* @param options - Document options including `documentId` and optionally `projectId`/`dataset`.
|
|
@@ -70,7 +70,7 @@ export function useEditDocument<TData>(
|
|
|
70
70
|
|
|
71
71
|
// Overload 4: Explicit type, path provided
|
|
72
72
|
/**
|
|
73
|
-
* @
|
|
73
|
+
* @public
|
|
74
74
|
* Edit a specific path within a document with an explicit type `TData`.
|
|
75
75
|
*
|
|
76
76
|
* @param options - Document options including `documentId`, `path`, and optionally `projectId`/`dataset`.
|
|
@@ -82,7 +82,7 @@ export function useEditDocument<TData>(
|
|
|
82
82
|
): (nextValue: Updater<TData>) => Promise<ActionsResult>
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* @
|
|
85
|
+
* @public
|
|
86
86
|
* Provides a stable function to apply edits to a document or a specific path within it.
|
|
87
87
|
*
|
|
88
88
|
* @category Documents
|
|
@@ -115,7 +115,7 @@ export function useEditDocument<TData>(
|
|
|
115
115
|
*
|
|
116
116
|
* function ProductEditor({ productHandle }: ProductEditorProps) {
|
|
117
117
|
* // Fetch the document to display its current state (optional)
|
|
118
|
-
* const product = useDocument(productHandle);
|
|
118
|
+
* const {data: product} = useDocument(productHandle);
|
|
119
119
|
* // Get the edit function for the full document
|
|
120
120
|
* const editProduct = useEditDocument(productHandle);
|
|
121
121
|
*
|
|
@@ -162,7 +162,7 @@ export function useEditDocument<TData>(
|
|
|
162
162
|
* };
|
|
163
163
|
*
|
|
164
164
|
* // Fetch the current price to display it
|
|
165
|
-
* const currentPrice = useDocument(priceOptions);
|
|
165
|
+
* const {data: currentPrice} = useDocument(priceOptions);
|
|
166
166
|
* // Get the edit function for the specific path 'price'
|
|
167
167
|
* const editPrice = useEditDocument(priceOptions);
|
|
168
168
|
*
|
|
@@ -195,7 +195,7 @@ export function useEditDocument<TData>(
|
|
|
195
195
|
* }
|
|
196
196
|
*
|
|
197
197
|
* function BookEditor({ bookHandle }: BookEditorProps) {
|
|
198
|
-
* const book = useDocument<Book>(bookHandle);
|
|
198
|
+
* const {data: book} = useDocument<Book>(bookHandle);
|
|
199
199
|
* // Provide the explicit type <Book>
|
|
200
200
|
* const editBook = useEditDocument<Book>(bookHandle);
|
|
201
201
|
*
|
|
@@ -235,9 +235,9 @@ export function useEditDocument<TData>(
|
|
|
235
235
|
*
|
|
236
236
|
* function AuthorNameEditor({ bookHandle }: AuthorNameEditorProps) {*
|
|
237
237
|
* // Fetch current value
|
|
238
|
-
* const currentName = useDocument<string>({...bookHandle, path: 'author.name'});
|
|
238
|
+
* const {data: currentName} = useDocument<string>({...bookHandle, path: 'author.name'});
|
|
239
239
|
* // Provide the explicit type <string> for the path's value
|
|
240
|
-
* const editAuthorName = useEditDocument<string>({...bookHandle, 'author.name'});
|
|
240
|
+
* const editAuthorName = useEditDocument<string>({...bookHandle, path: 'author.name'});
|
|
241
241
|
*
|
|
242
242
|
* const handleUpdate = useCallback(() => {
|
|
243
243
|
* // Update with a hardcoded string directly
|
|
@@ -16,7 +16,7 @@ const DEFAULT_BATCH_SIZE = 25
|
|
|
16
16
|
/**
|
|
17
17
|
* Configuration options for the useDocuments hook
|
|
18
18
|
*
|
|
19
|
-
* @
|
|
19
|
+
* @public
|
|
20
20
|
* @category Types
|
|
21
21
|
*/
|
|
22
22
|
export interface DocumentsOptions<
|
|
@@ -50,7 +50,7 @@ export interface DocumentsOptions<
|
|
|
50
50
|
/**
|
|
51
51
|
* Return value from the useDocuments hook
|
|
52
52
|
*
|
|
53
|
-
* @
|
|
53
|
+
* @public
|
|
54
54
|
* @category Types
|
|
55
55
|
*/
|
|
56
56
|
export interface DocumentsResponse<
|
|
@@ -85,7 +85,7 @@ export interface DocumentsResponse<
|
|
|
85
85
|
* with infinite scrolling support. The number of document handles returned per batch is customizable,
|
|
86
86
|
* and additional batches can be loaded using the supplied `loadMore` function.
|
|
87
87
|
*
|
|
88
|
-
* @
|
|
88
|
+
* @public
|
|
89
89
|
* @category Documents
|
|
90
90
|
* @param options - Configuration options for the infinite list
|
|
91
91
|
* @returns An object containing the list of document handles, the loading state, the total count of retrieved document handles, and a function to load more
|
|
@@ -106,9 +106,9 @@ export interface DocumentsResponse<
|
|
|
106
106
|
* } from '@sanity/sdk-react'
|
|
107
107
|
* import {Suspense} from 'react'
|
|
108
108
|
*
|
|
109
|
-
* // Define a component to display a single document (using
|
|
109
|
+
* // Define a component to display a single document (using useDocumentProjection for efficiency)
|
|
110
110
|
* function MyDocumentComponent({doc}: {doc: DocumentHandle}) {
|
|
111
|
-
* const {data} =
|
|
111
|
+
* const {data} = useDocumentProjection<{title?: string}>({
|
|
112
112
|
* ...doc, // Pass the full handle
|
|
113
113
|
* projection: '{title}'
|
|
114
114
|
* })
|
|
@@ -9,7 +9,7 @@ import {useQuery} from '../query/useQuery'
|
|
|
9
9
|
/**
|
|
10
10
|
* Configuration options for the usePaginatedDocuments hook
|
|
11
11
|
*
|
|
12
|
-
* @
|
|
12
|
+
* @public
|
|
13
13
|
* @category Types
|
|
14
14
|
*/
|
|
15
15
|
export interface PaginatedDocumentsOptions<
|
|
@@ -39,7 +39,7 @@ export interface PaginatedDocumentsOptions<
|
|
|
39
39
|
/**
|
|
40
40
|
* Return value from the usePaginatedDocuments hook
|
|
41
41
|
*
|
|
42
|
-
* @
|
|
42
|
+
* @public
|
|
43
43
|
* @category Types
|
|
44
44
|
*/
|
|
45
45
|
export interface PaginatedDocumentsResponse<
|
|
@@ -130,7 +130,7 @@ export interface PaginatedDocumentsResponse<
|
|
|
130
130
|
* with support for traditional paginated interfaces. The number of document handles returned per page is customizable,
|
|
131
131
|
* while page navigation is handled via the included navigation functions.
|
|
132
132
|
*
|
|
133
|
-
* @
|
|
133
|
+
* @public
|
|
134
134
|
* @category Documents
|
|
135
135
|
* @param options - Configuration options for the paginated list
|
|
136
136
|
* @returns An object containing the list of document handles, pagination details, and functions to navigate between pages
|
|
@@ -148,14 +148,14 @@ export interface PaginatedDocumentsResponse<
|
|
|
148
148
|
* type DatasetHandle,
|
|
149
149
|
* type DocumentHandle,
|
|
150
150
|
* type SortOrderingItem,
|
|
151
|
-
*
|
|
151
|
+
* useDocumentProjection
|
|
152
152
|
* } from '@sanity/sdk-react'
|
|
153
153
|
* import {Suspense} from 'react'
|
|
154
154
|
* import {ErrorBoundary} from 'react-error-boundary'
|
|
155
155
|
*
|
|
156
156
|
* // Define a component to display a single document row
|
|
157
157
|
* function MyTableRowComponent({doc}: {doc: DocumentHandle}) {
|
|
158
|
-
* const {data} =
|
|
158
|
+
* const {data} = useDocumentProjection<{title?: string}>({
|
|
159
159
|
* ...doc,
|
|
160
160
|
* projection: '{title}',
|
|
161
161
|
* })
|
|
@@ -3,7 +3,7 @@ import {act, render, screen} from '@testing-library/react'
|
|
|
3
3
|
import {Suspense, useRef} from 'react'
|
|
4
4
|
import {type Mock} from 'vitest'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {useDocumentPreview} from './useDocumentPreview'
|
|
7
7
|
|
|
8
8
|
// Mock IntersectionObserver
|
|
9
9
|
const mockIntersectionObserver = vi.fn()
|
|
@@ -45,7 +45,7 @@ const mockDocument: DocumentHandle = {
|
|
|
45
45
|
|
|
46
46
|
function TestComponent(docHandle: DocumentHandle) {
|
|
47
47
|
const ref = useRef(null)
|
|
48
|
-
const {data, isPending} =
|
|
48
|
+
const {data, isPending} = useDocumentPreview({...docHandle, ref})
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
51
|
<div ref={ref}>
|
|
@@ -56,7 +56,7 @@ function TestComponent(docHandle: DocumentHandle) {
|
|
|
56
56
|
)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
describe('
|
|
59
|
+
describe('useDocumentPreview', () => {
|
|
60
60
|
let getCurrent: Mock
|
|
61
61
|
let subscribe: Mock
|
|
62
62
|
|
|
@@ -182,7 +182,7 @@ describe('usePreview', () => {
|
|
|
182
182
|
subscribe.mockImplementation(() => eventsUnsubscribe)
|
|
183
183
|
|
|
184
184
|
function NoRefComponent(docHandle: DocumentHandle) {
|
|
185
|
-
const {data} =
|
|
185
|
+
const {data} = useDocumentPreview(docHandle) // No ref provided
|
|
186
186
|
return (
|
|
187
187
|
<div>
|
|
188
188
|
<h1>{data?.title}</h1>
|
|
@@ -212,7 +212,7 @@ describe('usePreview', () => {
|
|
|
212
212
|
|
|
213
213
|
function NonHtmlRefComponent(docHandle: DocumentHandle) {
|
|
214
214
|
const ref = useRef({}) // ref.current is not an HTML element
|
|
215
|
-
const {data} =
|
|
215
|
+
const {data} = useDocumentPreview({...docHandle, ref})
|
|
216
216
|
return (
|
|
217
217
|
<div>
|
|
218
218
|
<h1>{data?.title}</h1>
|
|
@@ -5,10 +5,10 @@ import {distinctUntilChanged, EMPTY, Observable, startWith, switchMap} from 'rxj
|
|
|
5
5
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @
|
|
8
|
+
* @public
|
|
9
9
|
* @category Types
|
|
10
10
|
*/
|
|
11
|
-
export interface
|
|
11
|
+
export interface useDocumentPreviewOptions extends DocumentHandle {
|
|
12
12
|
/**
|
|
13
13
|
* Optional ref object to track visibility. When provided, preview resolution
|
|
14
14
|
* only occurs when the referenced element is visible in the viewport.
|
|
@@ -17,10 +17,10 @@ export interface UsePreviewOptions extends DocumentHandle {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* @
|
|
20
|
+
* @public
|
|
21
21
|
* @category Types
|
|
22
22
|
*/
|
|
23
|
-
export interface
|
|
23
|
+
export interface useDocumentPreviewResults {
|
|
24
24
|
/** The results of resolving the document’s preview values */
|
|
25
25
|
data: PreviewValue
|
|
26
26
|
/** True when preview values are being refreshed */
|
|
@@ -28,7 +28,7 @@ export interface UsePreviewResults {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* @
|
|
31
|
+
* @public
|
|
32
32
|
*
|
|
33
33
|
* Returns the preview values of a document (specified via a `DocumentHandle`),
|
|
34
34
|
* including the document’s `title`, `subtitle`, `media`, and `status`. These values are live and will update in realtime.
|
|
@@ -43,7 +43,7 @@ export interface UsePreviewResults {
|
|
|
43
43
|
* ```
|
|
44
44
|
* // PreviewComponent.jsx
|
|
45
45
|
* export default function PreviewComponent({ document }) {
|
|
46
|
-
* const { data: { title, subtitle, media }, isPending } =
|
|
46
|
+
* const { data: { title, subtitle, media }, isPending } = useDocumentPreview({ document })
|
|
47
47
|
* return (
|
|
48
48
|
* <article style={{ opacity: isPending ? 0.5 : 1}}>
|
|
49
49
|
* {media?.type === 'image-asset' ? <img src={media.url} alt='' /> : ''}
|
|
@@ -71,7 +71,10 @@ export interface UsePreviewResults {
|
|
|
71
71
|
* )
|
|
72
72
|
* ```
|
|
73
73
|
*/
|
|
74
|
-
export function
|
|
74
|
+
export function useDocumentPreview({
|
|
75
|
+
ref,
|
|
76
|
+
...docHandle
|
|
77
|
+
}: useDocumentPreviewOptions): useDocumentPreviewResults {
|
|
75
78
|
const instance = useSanityInstance()
|
|
76
79
|
const stateSource = getPreviewState(instance, docHandle)
|
|
77
80
|
|
|
@@ -121,7 +124,7 @@ export function usePreview({ref, ...docHandle}: UsePreviewOptions): UsePreviewRe
|
|
|
121
124
|
const getSnapshot = useCallback(() => {
|
|
122
125
|
const currentState = stateSource.getCurrent()
|
|
123
126
|
if (currentState.data === null) throw resolvePreview(instance, docHandle)
|
|
124
|
-
return currentState as
|
|
127
|
+
return currentState as useDocumentPreviewResults
|
|
125
128
|
}, [docHandle, instance, stateSource])
|
|
126
129
|
|
|
127
130
|
return useSyncExternalStore(subscribe, getSnapshot)
|