@sanity/sdk-react 0.0.0-alpha.2 → 0.0.0-alpha.21
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 +38 -67
- package/dist/index.d.ts +4811 -2
- package/dist/index.js +1069 -2
- package/dist/index.js.map +1 -1
- package/package.json +27 -58
- package/src/_exports/index.ts +66 -10
- package/src/components/Login/LoginLinks.test.tsx +4 -14
- package/src/components/Login/LoginLinks.tsx +16 -31
- package/src/components/SDKProvider.test.tsx +79 -0
- package/src/components/SDKProvider.tsx +42 -0
- package/src/components/SanityApp.test.tsx +156 -0
- package/src/components/SanityApp.tsx +90 -0
- package/src/components/auth/AuthBoundary.test.tsx +6 -19
- package/src/components/auth/AuthBoundary.tsx +20 -4
- package/src/components/auth/Login.test.tsx +2 -16
- package/src/components/auth/Login.tsx +11 -30
- package/src/components/auth/LoginCallback.test.tsx +5 -20
- package/src/components/auth/LoginCallback.tsx +9 -14
- package/src/components/auth/LoginError.test.tsx +2 -17
- package/src/components/auth/LoginError.tsx +11 -16
- package/src/components/auth/LoginFooter.test.tsx +2 -16
- package/src/components/auth/LoginFooter.tsx +8 -24
- package/src/components/auth/LoginLayout.test.tsx +2 -16
- package/src/components/auth/LoginLayout.tsx +8 -38
- package/src/components/auth/authTestHelpers.tsx +11 -0
- package/src/components/utils.ts +22 -0
- package/src/context/SanityInstanceContext.ts +4 -0
- package/src/{components/context → context}/SanityProvider.test.tsx +2 -2
- package/src/context/SanityProvider.tsx +50 -0
- package/src/hooks/_synchronous-groq-js.mjs +4 -0
- package/src/hooks/auth/useAuthState.tsx +4 -5
- package/src/hooks/auth/useAuthToken.tsx +1 -1
- package/src/hooks/auth/useCurrentUser.tsx +28 -4
- package/src/hooks/auth/useDashboardOrganizationId.test.tsx +42 -0
- package/src/hooks/auth/useDashboardOrganizationId.tsx +29 -0
- package/src/hooks/auth/useHandleAuthCallback.test.tsx +16 -0
- package/src/hooks/auth/{useHandleCallback.tsx → useHandleAuthCallback.tsx} +7 -6
- package/src/hooks/auth/useLogOut.test.tsx +2 -2
- package/src/hooks/auth/useLogOut.tsx +1 -1
- package/src/hooks/auth/useLoginUrls.tsx +1 -0
- package/src/hooks/client/useClient.ts +9 -30
- package/src/hooks/comlink/useFrameConnection.test.tsx +167 -0
- package/src/hooks/comlink/useFrameConnection.ts +107 -0
- package/src/hooks/comlink/useManageFavorite.test.ts +111 -0
- package/src/hooks/comlink/useManageFavorite.ts +130 -0
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +81 -0
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.ts +106 -0
- package/src/hooks/comlink/useWindowConnection.test.ts +135 -0
- package/src/hooks/comlink/useWindowConnection.ts +122 -0
- package/src/hooks/context/useSanityInstance.test.tsx +2 -2
- package/src/hooks/context/useSanityInstance.ts +24 -8
- package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +178 -0
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +123 -0
- package/src/hooks/dashboard/useStudioWorkspacesByResourceId.test.tsx +278 -0
- package/src/hooks/dashboard/useStudioWorkspacesByResourceId.ts +92 -0
- package/src/hooks/datasets/useDatasets.ts +40 -0
- package/src/hooks/document/useApplyDocumentActions.test.ts +25 -0
- package/src/hooks/document/useApplyDocumentActions.ts +75 -0
- package/src/hooks/document/useDocument.test.ts +81 -0
- package/src/hooks/document/useDocument.ts +107 -0
- package/src/hooks/document/useDocumentEvent.test.ts +63 -0
- package/src/hooks/document/useDocumentEvent.ts +54 -0
- package/src/hooks/document/useDocumentPermissions.ts +84 -0
- package/src/hooks/document/useDocumentSyncStatus.test.ts +16 -0
- package/src/hooks/document/useDocumentSyncStatus.ts +33 -0
- package/src/hooks/document/useEditDocument.test.ts +179 -0
- package/src/hooks/document/useEditDocument.ts +195 -0
- package/src/hooks/documents/useDocuments.test.tsx +152 -0
- package/src/hooks/documents/useDocuments.ts +174 -0
- package/src/hooks/helpers/createCallbackHook.tsx +3 -2
- package/src/hooks/helpers/createStateSourceHook.test.tsx +66 -0
- package/src/hooks/helpers/createStateSourceHook.tsx +29 -10
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +259 -0
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +290 -0
- package/src/hooks/preview/usePreview.test.tsx +19 -10
- package/src/hooks/preview/usePreview.tsx +67 -13
- package/src/hooks/projection/useProjection.test.tsx +218 -0
- package/src/hooks/projection/useProjection.ts +147 -0
- package/src/hooks/projects/useProject.ts +48 -0
- package/src/hooks/projects/useProjects.ts +45 -0
- package/src/hooks/query/useQuery.test.tsx +188 -0
- package/src/hooks/query/useQuery.ts +103 -0
- package/src/hooks/users/useUsers.test.ts +163 -0
- package/src/hooks/users/useUsers.ts +107 -0
- package/src/utils/getEnv.ts +21 -0
- package/src/version.ts +8 -0
- package/src/vite-env.d.ts +10 -0
- package/dist/_chunks-es/useLogOut.js +0 -44
- package/dist/_chunks-es/useLogOut.js.map +0 -1
- package/dist/assets/bundle-CcAyERuZ.css +0 -11
- package/dist/components.d.ts +0 -257
- package/dist/components.js +0 -316
- package/dist/components.js.map +0 -1
- package/dist/hooks.d.ts +0 -187
- package/dist/hooks.js +0 -81
- package/dist/hooks.js.map +0 -1
- package/src/_exports/components.ts +0 -13
- package/src/_exports/hooks.ts +0 -9
- package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +0 -113
- package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +0 -42
- package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +0 -21
- package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +0 -105
- package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +0 -42
- package/src/components/DocumentListLayout/DocumentListLayout.tsx +0 -12
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +0 -49
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +0 -39
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +0 -30
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +0 -171
- package/src/components/context/SanityProvider.tsx +0 -42
- package/src/css/css.config.js +0 -220
- package/src/css/paramour.css +0 -2347
- package/src/css/styles.css +0 -11
- package/src/hooks/auth/useHandleCallback.test.tsx +0 -16
- package/src/hooks/client/useClient.test.tsx +0 -130
- package/src/hooks/documentCollection/useDocuments.test.ts +0 -130
- package/src/hooks/documentCollection/useDocuments.ts +0 -87
package/src/css/styles.css
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {handleCallback} from '@sanity/sdk'
|
|
2
|
-
import {identity} from 'rxjs'
|
|
3
|
-
import {describe, it} from 'vitest'
|
|
4
|
-
|
|
5
|
-
import {createCallbackHook} from '../helpers/createCallbackHook'
|
|
6
|
-
|
|
7
|
-
vi.mock('../helpers/createCallbackHook', () => ({createCallbackHook: vi.fn(identity)}))
|
|
8
|
-
vi.mock('@sanity/sdk', () => ({handleCallback: vi.fn()}))
|
|
9
|
-
|
|
10
|
-
describe('useHandleCallback', () => {
|
|
11
|
-
it('calls `createCallbackHook` with `handleCallback`', async () => {
|
|
12
|
-
const {useHandleCallback} = await import('./useHandleCallback')
|
|
13
|
-
expect(createCallbackHook).toHaveBeenCalledWith(handleCallback)
|
|
14
|
-
expect(useHandleCallback).toBe(handleCallback)
|
|
15
|
-
})
|
|
16
|
-
})
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {type SanityClient} from '@sanity/client'
|
|
2
|
-
import {act} from '@testing-library/react'
|
|
3
|
-
import type {Subscribable, Subscriber} from 'rxjs'
|
|
4
|
-
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
5
|
-
|
|
6
|
-
import {renderHook} from '../../../test/test-utils'
|
|
7
|
-
import {useClient} from './useClient'
|
|
8
|
-
|
|
9
|
-
vi.mock(import('@sanity/sdk'), async (importOriginal) => {
|
|
10
|
-
const actual = await importOriginal()
|
|
11
|
-
return {
|
|
12
|
-
...actual,
|
|
13
|
-
getClient: vi.fn(),
|
|
14
|
-
getSubscribableClient: vi.fn(),
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const {getClient, getSubscribableClient} = await import('@sanity/sdk')
|
|
19
|
-
|
|
20
|
-
describe('useClient', () => {
|
|
21
|
-
let subscribers: {next: (client: SanityClient) => void}[] = []
|
|
22
|
-
let currentClient: SanityClient
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
subscribers = []
|
|
26
|
-
|
|
27
|
-
currentClient = {
|
|
28
|
-
config: () => ({token: undefined, apiVersion: 'v2024-11-12'}),
|
|
29
|
-
} as unknown as SanityClient
|
|
30
|
-
|
|
31
|
-
// Create a subscribable interface directly
|
|
32
|
-
const createSubscribable = (): Subscribable<SanityClient> => ({
|
|
33
|
-
subscribe: (subscriber: {next: (client: SanityClient) => void}) => {
|
|
34
|
-
subscribers.push(subscriber)
|
|
35
|
-
subscriber.next(currentClient)
|
|
36
|
-
return {
|
|
37
|
-
unsubscribe: () => {
|
|
38
|
-
const index = subscribers.indexOf(subscriber)
|
|
39
|
-
if (index > -1) subscribers.splice(index, 1)
|
|
40
|
-
},
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
vi.mocked(getClient).mockReturnValue(currentClient)
|
|
46
|
-
vi.mocked(getSubscribableClient).mockImplementation(() => createSubscribable())
|
|
47
|
-
})
|
|
48
|
-
it('should return initial client', () => {
|
|
49
|
-
const {result} = renderHook(() => useClient({apiVersion: 'v2024-11-12'}))
|
|
50
|
-
|
|
51
|
-
expect(result.current.config().token).toBeUndefined()
|
|
52
|
-
expect(result.current.config().apiVersion).toBe('v2024-11-12')
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should handle client update through authentication changes', async () => {
|
|
56
|
-
let clientSubscriber: Subscriber<SanityClient> | undefined
|
|
57
|
-
|
|
58
|
-
// Create a subscribable that can simulate updates
|
|
59
|
-
vi.mocked(getSubscribableClient).mockImplementation(() => ({
|
|
60
|
-
subscribe: (subscriber: Subscriber<SanityClient>) => {
|
|
61
|
-
clientSubscriber = subscriber
|
|
62
|
-
// Send initial client
|
|
63
|
-
subscriber.next(currentClient)
|
|
64
|
-
return {
|
|
65
|
-
unsubscribe: vi.fn(),
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
}))
|
|
69
|
-
|
|
70
|
-
const {result} = renderHook(() => useClient({apiVersion: 'v2024-11-12'}))
|
|
71
|
-
|
|
72
|
-
// Verify initial state
|
|
73
|
-
expect(result.current.config().token).toBeUndefined()
|
|
74
|
-
expect(clientSubscriber).toBeDefined()
|
|
75
|
-
|
|
76
|
-
// Create authenticated client
|
|
77
|
-
const authenticatedClient = {
|
|
78
|
-
config: () => ({token: 'auth-token', apiVersion: 'v2024-11-12'}),
|
|
79
|
-
} as unknown as SanityClient
|
|
80
|
-
|
|
81
|
-
// Update getClient to return the new client
|
|
82
|
-
vi.mocked(getClient).mockReturnValue(authenticatedClient)
|
|
83
|
-
|
|
84
|
-
// Simulate the client update that would happen after auth change
|
|
85
|
-
await act(async () => {
|
|
86
|
-
clientSubscriber!.next(authenticatedClient)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// Verify the client was updated with the new token
|
|
90
|
-
expect(result.current.config().token).toBe('auth-token')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should unsubscribe on unmount', () => {
|
|
94
|
-
const unsubscribeSpy = vi.fn()
|
|
95
|
-
vi.mocked(getSubscribableClient).mockImplementation(() => ({
|
|
96
|
-
subscribe: () => ({
|
|
97
|
-
unsubscribe: unsubscribeSpy,
|
|
98
|
-
}),
|
|
99
|
-
}))
|
|
100
|
-
|
|
101
|
-
const {unmount} = renderHook(() => useClient({apiVersion: 'v2024-11-12'}))
|
|
102
|
-
|
|
103
|
-
unmount()
|
|
104
|
-
expect(unsubscribeSpy).toHaveBeenCalled()
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('should handle subscription errors', () => {
|
|
108
|
-
vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
109
|
-
|
|
110
|
-
const testError = new Error('Subscription error')
|
|
111
|
-
let errorSubscriber: Subscriber<SanityClient> | undefined
|
|
112
|
-
|
|
113
|
-
// Mock getSubscribableClient to create a subscription that will error
|
|
114
|
-
vi.mocked(getSubscribableClient).mockImplementation(() => ({
|
|
115
|
-
subscribe: (subscriber: Subscriber<SanityClient>) => {
|
|
116
|
-
errorSubscriber = subscriber
|
|
117
|
-
return {
|
|
118
|
-
unsubscribe: vi.fn(),
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
}))
|
|
122
|
-
|
|
123
|
-
renderHook(() => useClient({apiVersion: 'v2024-11-12'}))
|
|
124
|
-
|
|
125
|
-
errorSubscriber!.error(testError)
|
|
126
|
-
|
|
127
|
-
// eslint-disable-next-line no-console
|
|
128
|
-
expect(console.error).toHaveBeenCalledWith('Error in useClient subscription:', testError)
|
|
129
|
-
})
|
|
130
|
-
})
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {createDocumentListStore, type DocumentListOptions} from '@sanity/sdk'
|
|
2
|
-
import {act, renderHook} from '@testing-library/react'
|
|
3
|
-
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
|
|
4
|
-
|
|
5
|
-
import {useSanityInstance} from '../context/useSanityInstance'
|
|
6
|
-
import {useDocuments} from './useDocuments'
|
|
7
|
-
|
|
8
|
-
vi.mock('@sanity/sdk')
|
|
9
|
-
vi.mock('../context/useSanityInstance')
|
|
10
|
-
|
|
11
|
-
describe('useDocuments', () => {
|
|
12
|
-
const mockInstance = {}
|
|
13
|
-
|
|
14
|
-
const getCurrent = vi.fn()
|
|
15
|
-
const unsubscribe = vi.fn()
|
|
16
|
-
const subscribe = vi.fn().mockReturnValue(unsubscribe)
|
|
17
|
-
const dispose = vi.fn()
|
|
18
|
-
|
|
19
|
-
const mockDocumentListStore: ReturnType<typeof createDocumentListStore> = {
|
|
20
|
-
setOptions: vi.fn(),
|
|
21
|
-
loadMore: vi.fn(),
|
|
22
|
-
getState: vi.fn().mockReturnValue({getCurrent, subscribe}),
|
|
23
|
-
dispose,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
vi.mocked(useSanityInstance).mockReturnValue(
|
|
28
|
-
mockInstance as unknown as ReturnType<typeof useSanityInstance>,
|
|
29
|
-
)
|
|
30
|
-
vi.mocked(createDocumentListStore).mockReturnValue(
|
|
31
|
-
mockDocumentListStore as unknown as ReturnType<typeof createDocumentListStore>,
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
afterEach(() => {
|
|
36
|
-
vi.clearAllMocks()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should initialize with given options', () => {
|
|
40
|
-
const options: DocumentListOptions = {
|
|
41
|
-
filter: 'some-filter',
|
|
42
|
-
sort: [{field: 'name', direction: 'asc'}],
|
|
43
|
-
}
|
|
44
|
-
renderHook(() => useDocuments(options))
|
|
45
|
-
|
|
46
|
-
expect(createDocumentListStore).toHaveBeenCalledWith(mockInstance)
|
|
47
|
-
expect(mockDocumentListStore.setOptions).toHaveBeenCalledWith(options)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should subscribe to document list store changes', () => {
|
|
51
|
-
const options: DocumentListOptions = {}
|
|
52
|
-
|
|
53
|
-
renderHook(() => useDocuments(options))
|
|
54
|
-
expect(subscribe).toHaveBeenCalledTimes(1)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('should return the current document list state', () => {
|
|
58
|
-
const options = {}
|
|
59
|
-
const currentState = {result: [], isPending: false}
|
|
60
|
-
getCurrent.mockReturnValue(currentState)
|
|
61
|
-
|
|
62
|
-
const {result} = renderHook(() => useDocuments(options))
|
|
63
|
-
expect(result.current).toMatchObject(currentState)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('should call loadMore when loadMore is invoked', () => {
|
|
67
|
-
const options = {}
|
|
68
|
-
const {result} = renderHook(() => useDocuments(options))
|
|
69
|
-
|
|
70
|
-
act(() => {
|
|
71
|
-
result.current.loadMore()
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
expect(mockDocumentListStore.loadMore).toHaveBeenCalled()
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should update state when document list store changes', () => {
|
|
78
|
-
const options = {
|
|
79
|
-
filter: 'some-filter',
|
|
80
|
-
sort: [{field: 'name', direction: 'asc'}],
|
|
81
|
-
}
|
|
82
|
-
getCurrent.mockReturnValue({results: [], isPending: true})
|
|
83
|
-
const {result, rerender} = renderHook(() => useDocuments(options as DocumentListOptions))
|
|
84
|
-
|
|
85
|
-
expect(subscribe).toHaveBeenCalledTimes(1)
|
|
86
|
-
const [subscriber] = subscribe.mock.calls[0]
|
|
87
|
-
|
|
88
|
-
const newState = {results: [{id: 'doc1'}], isPending: false}
|
|
89
|
-
getCurrent.mockReturnValue(newState)
|
|
90
|
-
|
|
91
|
-
act(() => {
|
|
92
|
-
subscriber()
|
|
93
|
-
rerender()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
expect(result.current).toMatchObject(newState)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should handle empty options', () => {
|
|
100
|
-
const options = {}
|
|
101
|
-
renderHook(() => useDocuments(options))
|
|
102
|
-
|
|
103
|
-
expect(createDocumentListStore).toHaveBeenCalledWith(mockInstance)
|
|
104
|
-
expect(mockDocumentListStore.setOptions).toHaveBeenCalledWith(options)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('should handle null result from document list store', () => {
|
|
108
|
-
const options = {}
|
|
109
|
-
getCurrent.mockReturnValue({result: null, isPending: false})
|
|
110
|
-
|
|
111
|
-
const {result} = renderHook(() => useDocuments(options))
|
|
112
|
-
|
|
113
|
-
expect(result.current).toMatchObject({
|
|
114
|
-
result: null,
|
|
115
|
-
isPending: false,
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should unsubscribe from document list store on unmount', () => {
|
|
120
|
-
const options = {}
|
|
121
|
-
const unsubscribeSpy = vi.fn()
|
|
122
|
-
subscribe.mockReturnValue(unsubscribeSpy)
|
|
123
|
-
|
|
124
|
-
const {unmount} = renderHook(() => useDocuments(options))
|
|
125
|
-
|
|
126
|
-
unmount()
|
|
127
|
-
expect(mockDocumentListStore.dispose).toHaveBeenCalled()
|
|
128
|
-
expect(unsubscribeSpy).toHaveBeenCalled()
|
|
129
|
-
})
|
|
130
|
-
})
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import {createDocumentListStore, type DocumentHandle, type DocumentListOptions} from '@sanity/sdk'
|
|
2
|
-
import {useCallback, useEffect, useState, useSyncExternalStore} from 'react'
|
|
3
|
-
|
|
4
|
-
import {useSanityInstance} from '../context/useSanityInstance'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export interface UseDocuments {
|
|
10
|
-
loadMore: () => void
|
|
11
|
-
results: DocumentHandle[]
|
|
12
|
-
isPending: boolean
|
|
13
|
-
hasMore: boolean
|
|
14
|
-
count: number
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type DocumentListStore = ReturnType<typeof createDocumentListStore>
|
|
18
|
-
type DocumentListState = ReturnType<DocumentListStore['getState']>['getCurrent']
|
|
19
|
-
const STABLE_EMPTY = {
|
|
20
|
-
results: [],
|
|
21
|
-
isPending: false,
|
|
22
|
-
hasMore: false,
|
|
23
|
-
count: 0,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Hook to get the list of documents for specified options
|
|
28
|
-
*
|
|
29
|
-
* @public
|
|
30
|
-
*
|
|
31
|
-
* @param options - options for the document list
|
|
32
|
-
* @returns result of the document list and function to load more
|
|
33
|
-
*/
|
|
34
|
-
export function useDocuments(options: DocumentListOptions = {}): UseDocuments {
|
|
35
|
-
const instance = useSanityInstance()
|
|
36
|
-
|
|
37
|
-
// NOTE: useState is used because it guaranteed to return a stable reference
|
|
38
|
-
// across renders
|
|
39
|
-
const [ref] = useState<{
|
|
40
|
-
storeInstance: DocumentListStore | null
|
|
41
|
-
getCurrent: DocumentListState
|
|
42
|
-
initialOptions: DocumentListOptions
|
|
43
|
-
}>(() => ({
|
|
44
|
-
storeInstance: null,
|
|
45
|
-
getCurrent: () => STABLE_EMPTY,
|
|
46
|
-
initialOptions: options,
|
|
47
|
-
}))
|
|
48
|
-
|
|
49
|
-
// serialize options to ensure it only calls `setOptions` when the values
|
|
50
|
-
// themselves changes (in cases where devs put config inline)
|
|
51
|
-
const serializedOptions = JSON.stringify(options)
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
ref.storeInstance?.setOptions(JSON.parse(serializedOptions))
|
|
54
|
-
}, [ref, serializedOptions])
|
|
55
|
-
|
|
56
|
-
const subscribe = useCallback(
|
|
57
|
-
(onStoreChanged: () => void) => {
|
|
58
|
-
// to match the lifecycle of `useSyncExternalState`, we create the store
|
|
59
|
-
// instance after subscribe and mutate the ref to connect everything
|
|
60
|
-
ref.storeInstance = createDocumentListStore(instance)
|
|
61
|
-
ref.storeInstance.setOptions(ref.initialOptions)
|
|
62
|
-
const state = ref.storeInstance.getState()
|
|
63
|
-
ref.getCurrent = state.getCurrent
|
|
64
|
-
const unsubscribe = state.subscribe(onStoreChanged)
|
|
65
|
-
|
|
66
|
-
return () => {
|
|
67
|
-
// unsubscribe to clean up the state subscriptions
|
|
68
|
-
unsubscribe()
|
|
69
|
-
// dispose of the instance
|
|
70
|
-
ref.storeInstance?.dispose()
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
[instance, ref],
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
const getSnapshot = useCallback(() => {
|
|
77
|
-
return ref.getCurrent()
|
|
78
|
-
}, [ref])
|
|
79
|
-
|
|
80
|
-
const state = useSyncExternalStore(subscribe, getSnapshot)
|
|
81
|
-
|
|
82
|
-
const loadMore = useCallback(() => {
|
|
83
|
-
ref.storeInstance?.loadMore()
|
|
84
|
-
}, [ref])
|
|
85
|
-
|
|
86
|
-
return {loadMore, ...state}
|
|
87
|
-
}
|