@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
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {type DocumentOptions, getDocumentState,
|
|
2
|
-
import {type SanityDocument} from '
|
|
3
|
-
import {identity} from 'rxjs'
|
|
1
|
+
import {type DocumentOptions, getDocumentState, resolveDocument} from '@sanity/sdk'
|
|
2
|
+
import {type SanityDocument} from '@sanity/types'
|
|
4
3
|
|
|
4
|
+
import {type DocumentHandle} from '../../config/handles'
|
|
5
5
|
import {createStateSourceHook} from '../helpers/createStateSourceHook'
|
|
6
|
+
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
6
7
|
// used in an `{@link useDocumentProjection}` and `{@link useQuery}`
|
|
7
8
|
// eslint-disable-next-line import/consistent-type-specifier-style, unused-imports/no-unused-imports
|
|
8
9
|
import type {useDocumentProjection} from '../projection/useDocumentProjection'
|
|
@@ -19,9 +20,6 @@ const useDocumentValue = createStateSourceHook({
|
|
|
19
20
|
// Extract handle part for resolveDocument
|
|
20
21
|
suspender: (instance, options: DocumentOptions<string | undefined>) =>
|
|
21
22
|
resolveDocument(instance, options),
|
|
22
|
-
getConfig: identity as (
|
|
23
|
-
options: DocumentOptions<string | undefined>,
|
|
24
|
-
) => DocumentOptions<string | undefined>,
|
|
25
23
|
})
|
|
26
24
|
|
|
27
25
|
const wrapHookWithData = <TParams extends unknown[], TReturn>(
|
|
@@ -33,184 +31,132 @@ const wrapHookWithData = <TParams extends unknown[], TReturn>(
|
|
|
33
31
|
return useHook
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/** @internal */
|
|
43
|
-
<
|
|
44
|
-
TPath extends string,
|
|
45
|
-
TDocumentType extends string,
|
|
46
|
-
TDataset extends string = string,
|
|
47
|
-
TProjectId extends string = string,
|
|
48
|
-
>(
|
|
49
|
-
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
50
|
-
): {
|
|
51
|
-
data: JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath> | undefined
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** @internal */
|
|
55
|
-
<TData>(options: DocumentOptions<undefined>): {data: TData | null}
|
|
56
|
-
/** @internal */
|
|
57
|
-
<TData>(options: DocumentOptions<string>): {data: TData | undefined}
|
|
34
|
+
type UseDocumentOptions<
|
|
35
|
+
TPath extends string | undefined = undefined,
|
|
36
|
+
TDocumentType extends string = string,
|
|
37
|
+
TDataset extends string = string,
|
|
38
|
+
TProjectId extends string = string,
|
|
39
|
+
> = DocumentHandle<TDocumentType, TDataset, TProjectId> & {path?: TPath}
|
|
58
40
|
|
|
41
|
+
interface UseDocument {
|
|
59
42
|
/**
|
|
60
|
-
* ## useDocument via Type Inference (Recommended)
|
|
61
|
-
*
|
|
62
43
|
* @public
|
|
63
44
|
*
|
|
64
|
-
*
|
|
45
|
+
* ## useDocument with Explicit Types (no path)
|
|
65
46
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* - Provides type-safe access to documents and nested fields
|
|
69
|
-
* - Supports project/dataset-specific type inference
|
|
70
|
-
* - Works seamlessly with Typegen-generated types
|
|
71
|
-
*
|
|
72
|
-
* This hook will suspend while the document data is being fetched and loaded.
|
|
73
|
-
*
|
|
74
|
-
* When fetching a full document:
|
|
75
|
-
* - Returns the complete document object if it exists
|
|
76
|
-
* - Returns `null` if the document doesn't exist
|
|
47
|
+
* Provide an explicit type parameter `TData` to type the returned document data.
|
|
48
|
+
* You can define your own interfaces or use types generated by your Sanity Studio.
|
|
77
49
|
*
|
|
78
|
-
*
|
|
79
|
-
* - Returns the value at the specified path if both the document and path exist
|
|
80
|
-
* - Returns `undefined` if either the document doesn't exist or the path doesn't exist in the document
|
|
50
|
+
* This hook will suspend while the document data is being fetched.
|
|
81
51
|
*
|
|
82
|
-
* @
|
|
52
|
+
* @typeParam TData - The explicit type for the document
|
|
83
53
|
* @param options - Configuration including `documentId`, `documentType`, and optionally:
|
|
84
|
-
* - `path`: To select a nested value (returns typed value at path)
|
|
85
54
|
* - `projectId`/`dataset`: For multi-project/dataset setups
|
|
86
|
-
* @returns The document state
|
|
55
|
+
* @returns The document state
|
|
87
56
|
*
|
|
88
|
-
* @example Basic document fetch
|
|
57
|
+
* @example Basic document fetch with explicit type
|
|
89
58
|
* ```tsx
|
|
90
|
-
* import {useDocument, type DocumentHandle} from '@sanity/sdk-react'
|
|
59
|
+
* import {useDocument, type DocumentHandle, type SanityDocument} from '@sanity/sdk-react'
|
|
91
60
|
*
|
|
92
|
-
* interface
|
|
93
|
-
*
|
|
61
|
+
* interface Book extends SanityDocument {
|
|
62
|
+
* _type: 'book'
|
|
63
|
+
* title: string
|
|
64
|
+
* author: string
|
|
94
65
|
* }
|
|
95
66
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
67
|
+
* interface BookViewProps {
|
|
68
|
+
* doc: DocumentHandle
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* function BookView({doc}: BookViewProps) {
|
|
72
|
+
* const {data: book} = useDocument<Book>({...doc})
|
|
73
|
+
* return <h1>{book?.title ?? 'Untitled'} by {book?.author ?? 'Unknown'}</h1>
|
|
99
74
|
* }
|
|
100
75
|
* ```
|
|
101
76
|
*
|
|
102
|
-
* @
|
|
77
|
+
* @inlineType DocumentOptions
|
|
78
|
+
*/
|
|
79
|
+
<TData>(options: UseDocumentOptions<undefined>): {data: TData | null}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @public
|
|
83
|
+
*
|
|
84
|
+
* ## useDocument with Explicit Types (with path)
|
|
85
|
+
*
|
|
86
|
+
* Provide an explicit type parameter `TData` to type the returned field data
|
|
87
|
+
* when using a `path` to select a nested value.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam TData - The explicit type for the field
|
|
90
|
+
* @param options - Configuration including `documentId`, `documentType`, `path`, and optionally:
|
|
91
|
+
* - `projectId`/`dataset`: For multi-project/dataset setups
|
|
92
|
+
* @returns The field value at the specified path
|
|
93
|
+
*
|
|
94
|
+
* @example Fetching a specific field with explicit type
|
|
103
95
|
* ```tsx
|
|
104
96
|
* import {useDocument, type DocumentHandle} from '@sanity/sdk-react'
|
|
105
97
|
*
|
|
106
|
-
*
|
|
107
|
-
* doc:
|
|
108
|
-
* }
|
|
109
|
-
*
|
|
110
|
-
* function ProductTitle({doc}: ProductTitleProps) {
|
|
111
|
-
* const {data: title} = useDocument({
|
|
112
|
-
* ...doc,
|
|
113
|
-
* path: 'title' // Returns just the title field
|
|
114
|
-
* })
|
|
98
|
+
* function BookTitle({doc}: {doc: DocumentHandle}) {
|
|
99
|
+
* const {data: title} = useDocument<string>({...doc, path: 'title'})
|
|
115
100
|
* return <h1>{title ?? 'Untitled'}</h1>
|
|
116
101
|
* }
|
|
117
102
|
* ```
|
|
118
103
|
*
|
|
119
104
|
* @inlineType DocumentOptions
|
|
120
105
|
*/
|
|
121
|
-
<
|
|
122
|
-
TPath extends string | undefined = undefined,
|
|
123
|
-
TDocumentType extends string = string,
|
|
124
|
-
TDataset extends string = string,
|
|
125
|
-
TProjectId extends string = string,
|
|
126
|
-
>(
|
|
127
|
-
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
128
|
-
): TPath extends string
|
|
129
|
-
? {
|
|
130
|
-
data:
|
|
131
|
-
| JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath>
|
|
132
|
-
| undefined
|
|
133
|
-
}
|
|
134
|
-
: {data: SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | null}
|
|
106
|
+
<TData>(options: UseDocumentOptions<string>): {data: TData | undefined}
|
|
135
107
|
|
|
136
108
|
/**
|
|
137
109
|
* @public
|
|
138
110
|
*
|
|
139
|
-
* ## useDocument
|
|
111
|
+
* ## useDocument (default)
|
|
140
112
|
*
|
|
141
|
-
*
|
|
142
|
-
* - You're not using Sanity Typegen
|
|
143
|
-
* - You need to manually specify document types
|
|
144
|
-
* - You're working with dynamic document types
|
|
113
|
+
* When no explicit type parameter is provided, the hook returns `SanityDocument`.
|
|
145
114
|
*
|
|
146
|
-
*
|
|
147
|
-
* - Requires manual type specification via `TData`
|
|
148
|
-
* - Returns `TData | null` for full documents
|
|
149
|
-
* - Returns `TData | undefined` for nested values
|
|
115
|
+
* This hook will suspend while the document data is being fetched and loaded.
|
|
150
116
|
*
|
|
151
|
-
*
|
|
117
|
+
* When fetching a full document:
|
|
118
|
+
* - Returns the complete document object if it exists
|
|
119
|
+
* - Returns `null` if the document doesn't exist
|
|
120
|
+
*
|
|
121
|
+
* When fetching with a path:
|
|
122
|
+
* - Returns the value at the specified path if both the document and path exist
|
|
123
|
+
* - Returns `undefined` if either the document doesn't exist or the path doesn't exist in the document
|
|
152
124
|
*
|
|
153
|
-
* @
|
|
154
|
-
* @
|
|
155
|
-
* @param options - Configuration including `documentId` and optionally:
|
|
125
|
+
* @category Documents
|
|
126
|
+
* @param options - Configuration including `documentId`, `documentType`, and optionally:
|
|
156
127
|
* - `path`: To select a nested value
|
|
157
128
|
* - `projectId`/`dataset`: For multi-project/dataset setups
|
|
158
|
-
* @returns The document state (or nested value if path provided)
|
|
159
|
-
*
|
|
160
|
-
* @example Basic document fetch with explicit type
|
|
161
|
-
* ```tsx
|
|
162
|
-
* import {useDocument, type DocumentHandle, type SanityDocument} from '@sanity/sdk-react'
|
|
163
|
-
*
|
|
164
|
-
* interface Book extends SanityDocument {
|
|
165
|
-
* _type: 'book'
|
|
166
|
-
* title: string
|
|
167
|
-
* author: string
|
|
168
|
-
* }
|
|
169
|
-
*
|
|
170
|
-
* interface BookViewProps {
|
|
171
|
-
* doc: DocumentHandle
|
|
172
|
-
* }
|
|
173
|
-
*
|
|
174
|
-
* function BookView({doc}: BookViewProps) {
|
|
175
|
-
* const {data: book} = useDocument<Book>({...doc})
|
|
176
|
-
* return <h1>{book?.title ?? 'Untitled'} by {book?.author ?? 'Unknown'}</h1>
|
|
177
|
-
* }
|
|
178
|
-
* ```
|
|
129
|
+
* @returns The document state (or nested value if path provided).
|
|
179
130
|
*
|
|
180
|
-
* @example
|
|
131
|
+
* @example Basic document fetch
|
|
181
132
|
* ```tsx
|
|
182
133
|
* import {useDocument, type DocumentHandle} from '@sanity/sdk-react'
|
|
183
134
|
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* }
|
|
187
|
-
*
|
|
188
|
-
* function BookTitle({doc}: BookTitleProps) {
|
|
189
|
-
* const {data: title} = useDocument<string>({...doc, path: 'title'})
|
|
190
|
-
* return <h1>{title ?? 'Untitled'}</h1>
|
|
135
|
+
* function ProductView({doc}: {doc: DocumentHandle}) {
|
|
136
|
+
* const {data: product} = useDocument({...doc})
|
|
137
|
+
* return <h1>{product?.title ?? 'Untitled'}</h1>
|
|
191
138
|
* }
|
|
192
139
|
* ```
|
|
193
140
|
*
|
|
194
141
|
* @inlineType DocumentOptions
|
|
195
142
|
*/
|
|
196
|
-
<
|
|
197
|
-
options: DocumentOptions<TPath>,
|
|
198
|
-
): TPath extends string ? {data: TData | undefined} : {data: TData | null}
|
|
143
|
+
(options: UseDocumentOptions<undefined>): {data: SanityDocument | null}
|
|
199
144
|
|
|
200
145
|
/**
|
|
201
146
|
* @internal
|
|
202
147
|
*/
|
|
203
|
-
(options:
|
|
148
|
+
(options: UseDocumentOptions): {data: unknown}
|
|
204
149
|
}
|
|
205
150
|
|
|
206
151
|
/**
|
|
207
152
|
* @public
|
|
208
153
|
* Reads and subscribes to a document's realtime state, incorporating both local and remote changes.
|
|
209
154
|
*
|
|
210
|
-
*
|
|
155
|
+
* You can provide an explicit type parameter for full type safety:
|
|
156
|
+
* - `useDocument<MyType>({...})` returns `{data: MyType | null}`
|
|
157
|
+
* - `useDocument<string>({..., path: 'title'})` returns `{data: string | undefined}`
|
|
211
158
|
*
|
|
212
|
-
*
|
|
213
|
-
* 2. **[Explicit Types](#usedocument-via-explicit-types)** - Manually specify types when needed
|
|
159
|
+
* Without a type parameter, data is typed as `SanityDocument`.
|
|
214
160
|
*
|
|
215
161
|
* @remarks
|
|
216
162
|
* `useDocument` is ideal for realtime editing interfaces where you need immediate feedback on changes.
|
|
@@ -226,4 +172,7 @@ interface UseDocument {
|
|
|
226
172
|
*
|
|
227
173
|
* @function
|
|
228
174
|
*/
|
|
229
|
-
export const useDocument = wrapHookWithData(
|
|
175
|
+
export const useDocument = wrapHookWithData((options: UseDocumentOptions) => {
|
|
176
|
+
const normalizedOptions = useNormalizedResourceOptions(options)
|
|
177
|
+
return useDocumentValue(normalizedOptions)
|
|
178
|
+
}) as UseDocument
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// tests/useDocumentEvent.test.ts
|
|
2
2
|
import {type DocumentEvent, type DocumentHandle, subscribeDocumentEvents} from '@sanity/sdk'
|
|
3
|
-
import {renderHook} from '@testing-library/react'
|
|
4
3
|
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import {renderHook} from '../../../test/test-utils'
|
|
7
6
|
import {useDocumentEvent} from './useDocumentEvent'
|
|
8
7
|
|
|
9
8
|
vi.mock('@sanity/sdk', async (importOriginal) => {
|
|
@@ -14,6 +13,7 @@ vi.mock('@sanity/sdk', async (importOriginal) => {
|
|
|
14
13
|
const docHandle: DocumentHandle = {
|
|
15
14
|
documentId: 'doc1',
|
|
16
15
|
documentType: 'book',
|
|
16
|
+
resource: {projectId: 'p', dataset: 'd'},
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
describe('useDocumentEvent hook', () => {
|
|
@@ -26,22 +26,16 @@ describe('useDocumentEvent hook', () => {
|
|
|
26
26
|
const unsubscribe = vi.fn()
|
|
27
27
|
vi.mocked(subscribeDocumentEvents).mockReturnValue(unsubscribe)
|
|
28
28
|
|
|
29
|
-
renderHook(() => useDocumentEvent({...docHandle, onEvent: handleEvent})
|
|
30
|
-
wrapper: ({children}) => (
|
|
31
|
-
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
32
|
-
{children}
|
|
33
|
-
</ResourceProvider>
|
|
34
|
-
),
|
|
35
|
-
})
|
|
29
|
+
renderHook(() => useDocumentEvent({...docHandle, onEvent: handleEvent}))
|
|
36
30
|
|
|
37
31
|
expect(vi.mocked(subscribeDocumentEvents)).toHaveBeenCalledTimes(1)
|
|
38
32
|
expect(vi.mocked(subscribeDocumentEvents).mock.calls[0][0]).toEqual(expect.any(Object))
|
|
39
33
|
|
|
40
|
-
const
|
|
41
|
-
expect(typeof
|
|
34
|
+
const options = vi.mocked(subscribeDocumentEvents).mock.calls[0][1]
|
|
35
|
+
expect(typeof options.eventHandler).toBe('function')
|
|
42
36
|
|
|
43
37
|
const event = {type: 'edited', documentId: 'doc1', outgoing: {}} as DocumentEvent
|
|
44
|
-
|
|
38
|
+
options.eventHandler(event)
|
|
45
39
|
expect(handleEvent).toHaveBeenCalledWith(event)
|
|
46
40
|
})
|
|
47
41
|
|
|
@@ -50,13 +44,7 @@ describe('useDocumentEvent hook', () => {
|
|
|
50
44
|
const unsubscribe = vi.fn()
|
|
51
45
|
vi.mocked(subscribeDocumentEvents).mockReturnValue(unsubscribe)
|
|
52
46
|
|
|
53
|
-
const {unmount} = renderHook(() => useDocumentEvent({...docHandle, onEvent: handleEvent})
|
|
54
|
-
wrapper: ({children}) => (
|
|
55
|
-
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
56
|
-
{children}
|
|
57
|
-
</ResourceProvider>
|
|
58
|
-
),
|
|
59
|
-
})
|
|
47
|
+
const {unmount} = renderHook(() => useDocumentEvent({...docHandle, onEvent: handleEvent}))
|
|
60
48
|
unmount()
|
|
61
49
|
expect(unsubscribe).toHaveBeenCalledTimes(1)
|
|
62
50
|
})
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {type
|
|
1
|
+
import {type DocumentEvent, subscribeDocumentEvents} from '@sanity/sdk'
|
|
2
2
|
import {useCallback, useEffect, useInsertionEffect, useRef} from 'react'
|
|
3
3
|
|
|
4
|
+
import {type ResourceHandle} from '../../config/handles'
|
|
4
5
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
6
|
+
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @public
|
|
@@ -9,7 +11,7 @@ import {useSanityInstance} from '../context/useSanityInstance'
|
|
|
9
11
|
export interface UseDocumentEventOptions<
|
|
10
12
|
TDataset extends string = string,
|
|
11
13
|
TProjectId extends string = string,
|
|
12
|
-
> extends
|
|
14
|
+
> extends ResourceHandle<TProjectId, TDataset> {
|
|
13
15
|
onEvent: (documentEvent: DocumentEvent) => void
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -20,19 +22,19 @@ export interface UseDocumentEventOptions<
|
|
|
20
22
|
* Subscribes an event handler to events in your application's document store.
|
|
21
23
|
*
|
|
22
24
|
* @category Documents
|
|
23
|
-
* @param options - An object containing the event handler (`onEvent`) and optionally a `
|
|
25
|
+
* @param options - An object containing the event handler (`onEvent`) and optionally a `resource`. If no resource is provided, the nearest resource from context will be used.
|
|
24
26
|
* @example Creating a custom hook for document event toasts
|
|
25
27
|
* ```tsx
|
|
26
|
-
* import {
|
|
28
|
+
* import {type DocumentResource, type DocumentEvent, useDocumentEvent} from '@sanity/sdk-react'
|
|
27
29
|
* import {useToast} from './my-ui-library'
|
|
28
30
|
*
|
|
29
|
-
* // Define options for the custom hook
|
|
30
|
-
* interface DocumentToastsOptions
|
|
31
|
-
*
|
|
31
|
+
* // Define options for the custom hook
|
|
32
|
+
* interface DocumentToastsOptions {
|
|
33
|
+
* resource?: DocumentResource
|
|
32
34
|
* }
|
|
33
35
|
*
|
|
34
36
|
* // Define the custom hook
|
|
35
|
-
* function useDocumentToasts({
|
|
37
|
+
* function useDocumentToasts({resource}: DocumentToastsOptions = {}) {
|
|
36
38
|
* const showToast = useToast() // Get the toast function
|
|
37
39
|
*
|
|
38
40
|
* // Define the event handler logic to show toasts on specific events
|
|
@@ -44,24 +46,20 @@ export interface UseDocumentEventOptions<
|
|
|
44
46
|
* } else if (event.type === 'deleted') {
|
|
45
47
|
* showToast(`Document ${event.documentId} deleted.`)
|
|
46
48
|
* } else {
|
|
47
|
-
* // Optionally log other events for debugging
|
|
48
49
|
* console.log('Document Event:', event.type, event.documentId)
|
|
49
50
|
* }
|
|
50
51
|
* }
|
|
51
52
|
*
|
|
52
|
-
* // Call the original hook, spreading the handle properties
|
|
53
53
|
* useDocumentEvent({
|
|
54
|
-
*
|
|
54
|
+
* resource,
|
|
55
55
|
* onEvent: handleEvent,
|
|
56
56
|
* })
|
|
57
57
|
* }
|
|
58
58
|
*
|
|
59
59
|
* function MyComponentWithToasts() {
|
|
60
|
-
*
|
|
61
|
-
* const specificHandle = createDatasetHandle({ projectId: 'p1', dataset: 'ds1' })
|
|
62
|
-
* useDocumentToasts(specificHandle)
|
|
60
|
+
* useDocumentToasts({resource: {projectId: 'p1', dataset: 'ds1'}})
|
|
63
61
|
*
|
|
64
|
-
* //
|
|
62
|
+
* // Or rely on context for the resource:
|
|
65
63
|
* // useDocumentToasts()
|
|
66
64
|
*
|
|
67
65
|
* return <div>...</div>
|
|
@@ -76,7 +74,8 @@ export function useDocumentEvent<
|
|
|
76
74
|
options: UseDocumentEventOptions<TDataset, TProjectId>,
|
|
77
75
|
): void {
|
|
78
76
|
// Destructure handler and datasetHandle from options
|
|
79
|
-
const
|
|
77
|
+
const normalizedOptions = useNormalizedResourceOptions(options)
|
|
78
|
+
const {onEvent, ...datasetHandle} = normalizedOptions
|
|
80
79
|
const ref = useRef(onEvent)
|
|
81
80
|
|
|
82
81
|
useInsertionEffect(() => {
|
|
@@ -87,8 +86,11 @@ export function useDocumentEvent<
|
|
|
87
86
|
return ref.current(documentEvent)
|
|
88
87
|
}, [])
|
|
89
88
|
|
|
90
|
-
const instance = useSanityInstance(
|
|
89
|
+
const instance = useSanityInstance()
|
|
91
90
|
useEffect(() => {
|
|
92
|
-
return subscribeDocumentEvents(instance,
|
|
93
|
-
|
|
91
|
+
return subscribeDocumentEvents(instance, {
|
|
92
|
+
eventHandler: stableHandler,
|
|
93
|
+
resource: datasetHandle.resource,
|
|
94
|
+
})
|
|
95
|
+
}, [instance, datasetHandle.resource, stableHandler])
|
|
94
96
|
}
|