@sanity/sdk-react 0.0.0-rc.5 → 0.0.0-rc.7

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 (44) hide show
  1. package/README.md +5 -57
  2. package/dist/index.d.ts +998 -437
  3. package/dist/index.js +325 -259
  4. package/dist/index.js.map +1 -1
  5. package/package.json +13 -12
  6. package/src/_exports/sdk-react.ts +4 -1
  7. package/src/components/SDKProvider.tsx +6 -1
  8. package/src/components/SanityApp.test.tsx +29 -47
  9. package/src/components/SanityApp.tsx +12 -11
  10. package/src/components/auth/AuthBoundary.test.tsx +177 -7
  11. package/src/components/auth/AuthBoundary.tsx +31 -1
  12. package/src/components/auth/ConfigurationError.ts +22 -0
  13. package/src/components/auth/LoginError.tsx +9 -3
  14. package/src/hooks/auth/useVerifyOrgProjects.test.tsx +136 -0
  15. package/src/hooks/auth/useVerifyOrgProjects.tsx +48 -0
  16. package/src/hooks/client/useClient.ts +3 -3
  17. package/src/hooks/comlink/useManageFavorite.test.ts +276 -27
  18. package/src/hooks/comlink/useManageFavorite.ts +102 -51
  19. package/src/hooks/comlink/useWindowConnection.ts +3 -2
  20. package/src/hooks/datasets/useDatasets.test.ts +80 -0
  21. package/src/hooks/datasets/useDatasets.ts +2 -1
  22. package/src/hooks/document/useApplyDocumentActions.ts +105 -31
  23. package/src/hooks/document/useDocument.test.ts +41 -4
  24. package/src/hooks/document/useDocument.ts +198 -114
  25. package/src/hooks/document/useDocumentEvent.test.ts +5 -5
  26. package/src/hooks/document/useDocumentEvent.ts +67 -23
  27. package/src/hooks/document/useDocumentPermissions.ts +47 -8
  28. package/src/hooks/document/useDocumentSyncStatus.test.ts +12 -5
  29. package/src/hooks/document/useDocumentSyncStatus.ts +41 -14
  30. package/src/hooks/document/useEditDocument.test.ts +24 -6
  31. package/src/hooks/document/useEditDocument.ts +238 -133
  32. package/src/hooks/documents/useDocuments.test.tsx +1 -1
  33. package/src/hooks/documents/useDocuments.ts +153 -44
  34. package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +1 -1
  35. package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +120 -47
  36. package/src/hooks/projection/useProjection.ts +134 -46
  37. package/src/hooks/projects/useProject.test.ts +80 -0
  38. package/src/hooks/projects/useProjects.test.ts +77 -0
  39. package/src/hooks/query/useQuery.test.tsx +4 -4
  40. package/src/hooks/query/useQuery.ts +115 -43
  41. package/src/hooks/releases/useActiveReleases.test.tsx +84 -0
  42. package/src/hooks/releases/useActiveReleases.ts +39 -0
  43. package/src/hooks/releases/usePerspective.test.tsx +120 -0
  44. package/src/hooks/releases/usePerspective.ts +49 -0
@@ -1,7 +1,7 @@
1
1
  // tests/useEditDocument.test.ts
2
2
  import {
3
+ createDocumentHandle,
3
4
  createSanityInstance,
4
- type DocumentHandle,
5
5
  editDocument,
6
6
  getDocumentState,
7
7
  resolveDocument,
@@ -43,11 +43,29 @@ const doc = {
43
43
  _rev: 'tx0',
44
44
  _createdAt: '2025-02-06T00:11:00.000Z',
45
45
  _updatedAt: '2025-02-06T00:11:00.000Z',
46
- } satisfies SanityDocument
46
+ } satisfies Book
47
47
 
48
- const docHandle: DocumentHandle<SanityDocument> = {
48
+ const docHandle = createDocumentHandle({
49
49
  documentId: 'doc1',
50
50
  documentType: 'book',
51
+ })
52
+
53
+ // Define a single generic TestDocument type
54
+ interface Book extends SanityDocument {
55
+ _type: 'book'
56
+ foo?: string
57
+ extra?: string
58
+ title?: string
59
+ }
60
+
61
+ // Scope the TestDocument type to the project/datasets used in tests
62
+ type AllTestSchemaTypes = Book
63
+
64
+ // Augment the 'groq' module
65
+ declare module 'groq' {
66
+ interface SanitySchemas {
67
+ 'default:default': AllTestSchemaTypes
68
+ }
51
69
  }
52
70
 
53
71
  describe('useEditDocument hook', () => {
@@ -67,7 +85,7 @@ describe('useEditDocument hook', () => {
67
85
  const apply = vi.fn().mockResolvedValue({transactionId: 'tx1'})
68
86
  vi.mocked(useApplyDocumentActions).mockReturnValue(apply)
69
87
 
70
- const {result} = renderHook(() => useEditDocument(docHandle, 'foo'))
88
+ const {result} = renderHook(() => useEditDocument<string>({...docHandle, path: 'foo'}))
71
89
  const promise = result.current('newValue')
72
90
  expect(editDocument).toHaveBeenCalledWith(docHandle, {set: {foo: 'newValue'}})
73
91
  expect(apply).toHaveBeenCalledWith(editDocument(docHandle, {set: {foo: 'newValue'}}))
@@ -106,7 +124,7 @@ describe('useEditDocument hook', () => {
106
124
  const apply = vi.fn().mockResolvedValue({transactionId: 'tx3'})
107
125
  vi.mocked(useApplyDocumentActions).mockReturnValue(apply)
108
126
 
109
- const {result} = renderHook(() => useEditDocument(docHandle, 'foo'))
127
+ const {result} = renderHook(() => useEditDocument<string>({...docHandle, path: 'foo'}))
110
128
  const promise = result.current((prev: unknown) => `${prev}Updated`) // 'bar' becomes 'barUpdated'
111
129
  expect(editDocument).toHaveBeenCalledWith(docHandle, {set: {foo: 'barUpdated'}})
112
130
  expect(apply).toHaveBeenCalledWith(editDocument(docHandle, {set: {foo: 'barUpdated'}}))
@@ -145,7 +163,7 @@ describe('useEditDocument hook', () => {
145
163
  vi.mocked(useApplyDocumentActions).mockReturnValue(fakeApply)
146
164
 
147
165
  const {result} = renderHook(() => useEditDocument(docHandle))
148
- expect(() => result.current('notAnObject' as unknown as SanityDocument)).toThrowError(
166
+ expect(() => result.current('notAnObject' as unknown as Book)).toThrowError(
149
167
  'No path was provided to `useEditDocument` and the value provided was not a document object.',
150
168
  )
151
169
  })
@@ -1,13 +1,12 @@
1
1
  import {
2
2
  type ActionsResult,
3
- type DocumentHandle,
3
+ type DocumentOptions,
4
4
  editDocument,
5
5
  getDocumentState,
6
6
  type JsonMatch,
7
- type JsonMatchPath,
8
7
  resolveDocument,
9
8
  } from '@sanity/sdk'
10
- import {type SanityDocument} from '@sanity/types'
9
+ import {type SanityDocumentResult} from 'groq'
11
10
  import {useCallback} from 'react'
12
11
 
13
12
  import {useSanityInstance} from '../context/useSanityInstance'
@@ -15,178 +14,281 @@ import {useApplyDocumentActions} from './useApplyDocumentActions'
15
14
 
16
15
  const ignoredKeys = ['_id', '_type', '_createdAt', '_updatedAt', '_rev']
17
16
 
18
- type Updater<TValue> = TValue | ((nextValue: TValue) => TValue)
17
+ type Updater<TValue> = TValue | ((currentValue: TValue) => TValue)
19
18
 
19
+ // Overload 1: No path, relies on Typegen
20
20
  /**
21
+ * @beta
22
+ * Edit an entire document, relying on Typegen for the type.
21
23
  *
24
+ * @param options - Document options including `documentId`, `documentType`, and optionally `projectId`/`dataset`.
25
+ * @returns A stable function to update the document state. Accepts either the new document state or an updater function `(currentValue) => nextValue`.
26
+ * Returns a promise resolving to the {@link ActionsResult}.
27
+ */
28
+ export function useEditDocument<
29
+ TDocumentType extends string = string,
30
+ TDataset extends string = string,
31
+ TProjectId extends string = string,
32
+ >(
33
+ options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,
34
+ ): (
35
+ nextValue: Updater<SanityDocumentResult<TDocumentType, TDataset, TProjectId>>,
36
+ ) => Promise<ActionsResult<SanityDocumentResult<TDocumentType, TDataset, TProjectId>>>
37
+
38
+ // Overload 2: Path provided, relies on Typegen
39
+ /**
22
40
  * @beta
41
+ * Edit a specific path within a document, relying on Typegen for the type.
23
42
  *
24
- * ## useEditDocument(doc, path)
25
- * Edit a nested value within a document
43
+ * @param options - Document options including `documentId`, `documentType`, `path`, and optionally `projectId`/`dataset`.
44
+ * @returns A stable function to update the value at the specified path. Accepts either the new value or an updater function `(currentValue) => nextValue`.
45
+ * Returns a promise resolving to the {@link ActionsResult}.
46
+ */
47
+ export function useEditDocument<
48
+ TPath extends string = string,
49
+ TDocumentType extends string = string,
50
+ TDataset extends string = string,
51
+ TProjectId extends string = string,
52
+ >(
53
+ options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
54
+ ): (
55
+ nextValue: Updater<JsonMatch<SanityDocumentResult<TDocumentType, TDataset, TProjectId>, TPath>>,
56
+ ) => Promise<ActionsResult<SanityDocumentResult<TDocumentType, TDataset, TProjectId>>>
57
+
58
+ // Overload 3: Explicit type, no path
59
+ /**
60
+ * @beta
61
+ * Edit an entire document with an explicit type `TData`.
62
+ *
63
+ * @param options - Document options including `documentId` and optionally `projectId`/`dataset`.
64
+ * @returns A stable function to update the document state. Accepts either the new document state (`TData`) or an updater function `(currentValue: TData) => nextValue: TData`.
65
+ * Returns a promise resolving to the {@link ActionsResult}.
66
+ */
67
+ export function useEditDocument<TData>(
68
+ options: DocumentOptions<undefined>,
69
+ ): (nextValue: Updater<TData>) => Promise<ActionsResult>
70
+
71
+ // Overload 4: Explicit type, path provided
72
+ /**
73
+ * @beta
74
+ * Edit a specific path within a document with an explicit type `TData`.
75
+ *
76
+ * @param options - Document options including `documentId`, `path`, and optionally `projectId`/`dataset`.
77
+ * @returns A stable function to update the value at the specified path. Accepts either the new value (`TData`) or an updater function `(currentValue: TData) => nextValue: TData`.
78
+ * Returns a promise resolving to the {@link ActionsResult}.
79
+ */
80
+ export function useEditDocument<TData>(
81
+ options: DocumentOptions<string>,
82
+ ): (nextValue: Updater<TData>) => Promise<ActionsResult>
83
+
84
+ /**
85
+ * @beta
86
+ * Provides a stable function to apply edits to a document or a specific path within it.
26
87
  *
27
88
  * @category Documents
28
- * @param docHandle - The document to be edited, specified as a DocumentHandle
29
- * @param path - The path to the nested value to be edited
30
- * @returns A function to update the nested value. Accepts either a new value, or an updater function that exposes the previous value and returns a new value.
31
- * @example Update a document's name by providing the new value directly
89
+ * @remarks
90
+ * This hook simplifies editing documents by automatically:
91
+ * - Comparing the current and next states to determine the minimal set of `set` and `unset` operations required for the update via `editDocument`.
92
+ * - Handling both full document updates and specific path updates.
93
+ * - Supporting functional updates (e.g., `edit(prev => ({...prev, title: 'New'}))`).
94
+ * - Integrating with the active {@link SanityInstance} context.
95
+ * - Utilizing `useApplyDocumentActions` internally for optimistic updates and transaction handling.
96
+ *
97
+ * It offers several overloads for flexibility:
98
+ * 1. **Typegen (Full Document):** Edit the entire document, inferring types from your schema.
99
+ * 2. **Typegen (Specific Path):** Edit a specific field, inferring types.
100
+ * 3. **Explicit Type (Full Document):** Edit the entire document with a manually specified type.
101
+ * 4. **Explicit Type (Specific Path):** Edit a specific field with a manually specified type.
102
+ *
103
+ * This hook relies on the document state being loaded. If the document is not yet available
104
+ * (e.g., during initial load), the component using this hook will suspend.
105
+ *
106
+ * @example Basic Usage (Typegen, Full Document)
32
107
  * ```tsx
33
- * const handle = {
34
- * documentId: 'movie-123',
35
- * documentType: 'movie',
36
- * projectId: 'abc123',
37
- * dataset: 'production'
108
+ * import {useCallback} from 'react';
109
+ * import {useEditDocument, useDocument, type DocumentHandle} from '@sanity/sdk-react'
110
+ *
111
+ * // Assume 'product' schema has a 'title' field (string)
112
+ * interface ProductEditorProps {
113
+ * productHandle: DocumentHandle<'product'> // Typegen infers 'product' type
38
114
  * }
39
115
  *
40
- * const name = useDocument(handle, 'name')
41
- * const editName = useEditDocument(handle, 'name')
116
+ * function ProductEditor({ productHandle }: ProductEditorProps) {
117
+ * // Fetch the document to display its current state (optional)
118
+ * const product = useDocument(productHandle);
119
+ * // Get the edit function for the full document
120
+ * const editProduct = useEditDocument(productHandle);
42
121
  *
43
- * function handleNameChange(event: React.ChangeEvent<HTMLInputElement>) {
44
- * editName(event.target.value)
45
- * }
122
+ * // Use useCallback for stable event handlers
123
+ * const handleTitleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
124
+ * const newTitle = event.target.value;
125
+ * // Use the functional updater for safe partial updates
126
+ * editProduct(prev => ({
127
+ * ...prev,
128
+ * title: newTitle,
129
+ * })).
130
+ * }, [editProduct]);
46
131
  *
47
- * return (
48
- * <input type='text' value={name} onChange={handleNameChange} />
49
- * )
132
+ * return (
133
+ * <div>
134
+ * <label>
135
+ * Product Title:
136
+ * <input
137
+ * type="text"
138
+ * value={product?.title ?? ''}
139
+ * onChange={handleTitleChange}
140
+ * />
141
+ * </label>
142
+ * </div>
143
+ * );
144
+ * }
50
145
  * ```
51
146
  *
52
- * @example Update a count on a document by providing an updater function
147
+ * @example Editing a Specific Path (Typegen)
53
148
  * ```tsx
54
- * const handle = {
55
- * documentId: 'counter-123',
56
- * documentType: 'counter',
57
- * projectId: 'abc123',
58
- * dataset: 'production'
149
+ * import React, { useCallback } from 'react';
150
+ * import {useEditDocument, useDocument, type DocumentHandle, type DocumentOptions} from '@sanity/sdk-react'
151
+ *
152
+ * // Assume 'product' schema has a 'price' field (number)
153
+ * interface ProductPriceEditorProps {
154
+ * productHandle: DocumentHandle<'product'>;
59
155
  * }
60
156
  *
61
- * const count = useDocument(handle, 'count')
62
- * const editCount = useEditDocument(handle, 'count')
157
+ * function ProductPriceEditor({ productHandle }: ProductPriceEditorProps) {
158
+ * // Construct DocumentOptions internally, combining the handle and a hardcoded path
159
+ * const priceOptions {
160
+ * ...productHandle,
161
+ * path: 'price', // Hardcode the path to edit
162
+ * };
63
163
  *
64
- * function incrementCount() {
65
- * editCount(previousCount => previousCount + 1)
164
+ * // Fetch the current price to display it
165
+ * const currentPrice = useDocument(priceOptions);
166
+ * // Get the edit function for the specific path 'price'
167
+ * const editPrice = useEditDocument(priceOptions);
168
+ *
169
+ * const handleSetFixedPrice = useCallback(() => {
170
+ * // Update the price directly to a hardcoded value
171
+ * editPrice(99.99)
172
+ * }, [editPrice]);
173
+ *
174
+ * return (
175
+ * <div>
176
+ * <p>Current Price: {currentPrice}</p>
177
+ * <button onClick={handleSetFixedPrice}>
178
+ * Set Price to $99.99
179
+ * </button>
180
+ * </div>
181
+ * );
66
182
  * }
67
183
  *
68
- * return (
69
- * <>
70
- * <button onClick={incrementCount}>
71
- * Increment
72
- * </button>
73
- * Current count: {count}
74
- * </>
75
- * )
76
184
  * ```
77
- */
78
- export function useEditDocument<
79
- TDocument extends SanityDocument,
80
- TPath extends JsonMatchPath<TDocument>,
81
- >(
82
- docHandle: DocumentHandle<TDocument>,
83
- path: TPath,
84
- ): (nextValue: Updater<JsonMatch<TDocument, TPath>>) => Promise<ActionsResult<TDocument>>
85
-
86
- /**
87
185
  *
88
- * @beta
89
- *
90
- * ## useEditDocument(doc)
91
- * Edit an entire document
92
- * @param docHandle - The document to be edited, specified as a DocumentHandle.
93
- * The hook will automatically use the Sanity instance that matches the project and dataset specified in the handle.
94
- * @returns A function to update the document state. Accepts either a new document state, or an updater function that exposes the previous document state and returns the new document state.
95
- * @example
186
+ * @example Usage with Explicit Types (Full Document)
96
187
  * ```tsx
97
- * const myDocumentHandle = {
98
- * documentId: 'product-123',
99
- * documentType: 'product',
100
- * projectId: 'abc123',
101
- * dataset: 'production'
102
- * }
103
- *
104
- * const myDocument = useDocument(myDocumentHandle)
105
- * const { title, price } = myDocument ?? {}
188
+ * import React, { useCallback } from 'react';
189
+ * import {useEditDocument, useDocument, type DocumentHandle, type SanityDocument} from '@sanity/sdk-react'
106
190
  *
107
- * const editMyDocument = useEditDocument(myDocumentHandle)
191
+ * interface Book extends SanityDocument { _type: 'book', title: string, author: string }
108
192
  *
109
- * function handleFieldChange(e: React.ChangeEvent<HTMLInputElement>) {
110
- * const {name, value} = e.currentTarget
111
- * // Use an updater function to update the document state based on the previous state
112
- * editMyDocument(previousDocument => ({
113
- * ...previousDocument,
114
- * [name]: value
115
- * }))
193
+ * interface BookEditorProps {
194
+ * bookHandle: DocumentHandle // No documentType needed if providing TData
116
195
  * }
117
196
  *
118
- * function handleSaleChange(e: React.ChangeEvent<HTMLInputElement>) {
119
- * const { checked } = e.currentTarget
120
- * if (checked) {
121
- * // Use an updater function to add a new salePrice field;
122
- * // set it at a 20% discount off the normal price
123
- * editMyDocument(previousDocument => ({
124
- * ...previousDocument,
125
- * salePrice: previousDocument.price * 0.8,
197
+ * function BookEditor({ bookHandle }: BookEditorProps) {
198
+ * const book = useDocument<Book>(bookHandle);
199
+ * // Provide the explicit type <Book>
200
+ * const editBook = useEditDocument<Book>(bookHandle);
201
+ *
202
+ * const handleAuthorChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
203
+ * const newAuthor = event.target.value;
204
+ * editBook(prev => ({
205
+ * ...prev,
206
+ * author: newAuthor
126
207
  * }))
127
- * } else {
128
- * // Get the document state without the salePrice field
129
- * const { salePrice, ...rest } = myDocument
130
- * // Update the document state to remove the salePrice field
131
- * editMyDocument(rest)
132
- * }
208
+ * }, [editBook]);
209
+ *
210
+ * return (
211
+ * <div>
212
+ * <label>
213
+ * Book Author:
214
+ * <input
215
+ * type="text"
216
+ * value={book?.author ?? ''}
217
+ * onChange={handleAuthorChange}
218
+ * />
219
+ * </label>
220
+ * </div>
221
+ * );
133
222
  * }
134
223
  *
135
- * return (
136
- * <>
137
- * <form onSubmit={e => e.preventDefault()}>
138
- * <input name='title' type='text' value={title} onChange={handleFieldChange} />
139
- * <input name='price' type='number' value={price} onChange={handleFieldChange} />
140
- * <input
141
- * name='salePrice'
142
- * type='checkbox'
143
- * checked={myDocument && 'salePrice' in myDocument}
144
- * onChange={handleSaleChange}
145
- * />
146
- * </form>
147
- * <pre><code>
148
- * {JSON.stringify(myDocument, null, 2)}
149
- * </code></pre>
150
- * </>
151
- * )
152
224
  * ```
153
- */
154
- export function useEditDocument<TDocument extends SanityDocument>(
155
- docHandle: DocumentHandle<TDocument>,
156
- ): (nextValue: Updater<TDocument>) => Promise<ActionsResult<TDocument>>
157
-
158
- /**
159
225
  *
160
- * @beta
226
+ * @example Usage with Explicit Types (Specific Path)
227
+ * ```tsx
228
+ * import React, { useCallback } from 'react';
229
+ * import {useEditDocument, useDocument, type DocumentHandle, type DocumentOptions} from '@sanity/sdk-react'
230
+ *
231
+ * // Assume 'book' has 'author.name' (string)
232
+ * interface AuthorNameEditorProps {
233
+ * bookHandle: DocumentHandle; // No documentType needed if providing TData for path
234
+ * }
235
+ *
236
+ * function AuthorNameEditor({ bookHandle }: AuthorNameEditorProps) {*
237
+ * // Fetch current value
238
+ * const currentName = useDocument<string>({...bookHandle, path: 'author.name'});
239
+ * // Provide the explicit type <string> for the path's value
240
+ * const editAuthorName = useEditDocument<string>({...bookHandle, 'author.name'});
161
241
  *
162
- * Enables editing of a document’s state.
163
- * When called with a `path` argument, the hook will return a function for updating a nested value.
164
- * When called without a `path` argument, the hook will return a function for updating the entire document.
242
+ * const handleUpdate = useCallback(() => {
243
+ * // Update with a hardcoded string directly
244
+ * editAuthorName('Jane Doe')
245
+ * }, [editAuthorName]);
246
+ *
247
+ * return (
248
+ * <div>
249
+ * <p>Current Author Name: {currentName}</p>
250
+ * <button onClick={handleUpdate} disabled={currentName === undefined}>
251
+ * Set Author Name to Jane Doe
252
+ * </button>
253
+ * </div>
254
+ * );
255
+ * }
256
+ *
257
+ * ```
165
258
  */
166
- export function useEditDocument(
167
- docHandle: DocumentHandle,
168
- path?: string,
169
- ): (updater: Updater<unknown>) => Promise<ActionsResult> {
170
- const instance = useSanityInstance(docHandle)
259
+ export function useEditDocument({
260
+ path,
261
+ ...doc
262
+ }: DocumentOptions<string | undefined>): (updater: Updater<unknown>) => Promise<ActionsResult> {
263
+ const instance = useSanityInstance(doc)
171
264
  const apply = useApplyDocumentActions()
172
265
  const isDocumentReady = useCallback(
173
- () => getDocumentState(instance, docHandle).getCurrent() !== undefined,
174
- [instance, docHandle],
266
+ () => getDocumentState(instance, doc).getCurrent() !== undefined,
267
+ [instance, doc],
175
268
  )
176
- if (!isDocumentReady()) throw resolveDocument(instance, docHandle)
269
+ if (!isDocumentReady()) throw resolveDocument(instance, doc)
177
270
 
178
271
  return (updater: Updater<unknown>) => {
179
- if (path) {
272
+ const currentPath = path
273
+
274
+ if (currentPath) {
275
+ const stateWithOptions = getDocumentState(instance, {...doc, path})
276
+ const currentValue = stateWithOptions.getCurrent()
277
+
180
278
  const nextValue =
181
279
  typeof updater === 'function'
182
- ? updater(getDocumentState(instance, docHandle, path).getCurrent())
280
+ ? (updater as (prev: typeof currentValue) => typeof currentValue)(currentValue)
183
281
  : updater
184
282
 
185
- return apply(editDocument(docHandle, {set: {[path]: nextValue}}))
283
+ return apply(editDocument(doc, {set: {[currentPath]: nextValue}}))
186
284
  }
187
285
 
188
- const current = getDocumentState(instance, docHandle).getCurrent() as object | null | undefined
189
- const nextValue = typeof updater === 'function' ? updater(current) : updater
286
+ const fullDocState = getDocumentState(instance, {...doc, path})
287
+ const current = fullDocState.getCurrent() as object | null | undefined
288
+ const nextValue =
289
+ typeof updater === 'function'
290
+ ? (updater as (prev: typeof current) => typeof current)(current)
291
+ : updater
190
292
 
191
293
  if (typeof nextValue !== 'object' || !nextValue) {
192
294
  throw new Error(
@@ -197,11 +299,14 @@ export function useEditDocument(
197
299
  const allKeys = Object.keys({...current, ...nextValue})
198
300
  const editActions = allKeys
199
301
  .filter((key) => !ignoredKeys.includes(key))
200
- .filter((key) => current?.[key as keyof typeof current] !== nextValue[key])
302
+ .filter(
303
+ (key) =>
304
+ current?.[key as keyof typeof current] !== (nextValue as Record<string, unknown>)[key],
305
+ )
201
306
  .map((key) =>
202
307
  key in nextValue
203
- ? editDocument(docHandle, {set: {[key]: nextValue[key]}})
204
- : editDocument(docHandle, {unset: [key]}),
308
+ ? editDocument(doc, {set: {[key]: (nextValue as Record<string, unknown>)[key]}})
309
+ : editDocument(doc, {unset: [key]}),
205
310
  )
206
311
 
207
312
  return apply(editActions)
@@ -68,7 +68,7 @@ describe('useDocuments', () => {
68
68
  },
69
69
  ]
70
70
 
71
- vi.mocked(useQuery).mockImplementation((query, options) => {
71
+ vi.mocked(useQuery).mockImplementation(({query, ...options}) => {
72
72
  const result = evaluateSync(parse(query), {dataset, params: options?.params}).get()
73
73
  return {
74
74
  data: result,