@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.
Files changed (116) hide show
  1. package/README.md +38 -67
  2. package/dist/index.d.ts +4811 -2
  3. package/dist/index.js +1069 -2
  4. package/dist/index.js.map +1 -1
  5. package/package.json +27 -58
  6. package/src/_exports/index.ts +66 -10
  7. package/src/components/Login/LoginLinks.test.tsx +4 -14
  8. package/src/components/Login/LoginLinks.tsx +16 -31
  9. package/src/components/SDKProvider.test.tsx +79 -0
  10. package/src/components/SDKProvider.tsx +42 -0
  11. package/src/components/SanityApp.test.tsx +156 -0
  12. package/src/components/SanityApp.tsx +90 -0
  13. package/src/components/auth/AuthBoundary.test.tsx +6 -19
  14. package/src/components/auth/AuthBoundary.tsx +20 -4
  15. package/src/components/auth/Login.test.tsx +2 -16
  16. package/src/components/auth/Login.tsx +11 -30
  17. package/src/components/auth/LoginCallback.test.tsx +5 -20
  18. package/src/components/auth/LoginCallback.tsx +9 -14
  19. package/src/components/auth/LoginError.test.tsx +2 -17
  20. package/src/components/auth/LoginError.tsx +11 -16
  21. package/src/components/auth/LoginFooter.test.tsx +2 -16
  22. package/src/components/auth/LoginFooter.tsx +8 -24
  23. package/src/components/auth/LoginLayout.test.tsx +2 -16
  24. package/src/components/auth/LoginLayout.tsx +8 -38
  25. package/src/components/auth/authTestHelpers.tsx +11 -0
  26. package/src/components/utils.ts +22 -0
  27. package/src/context/SanityInstanceContext.ts +4 -0
  28. package/src/{components/context → context}/SanityProvider.test.tsx +2 -2
  29. package/src/context/SanityProvider.tsx +50 -0
  30. package/src/hooks/_synchronous-groq-js.mjs +4 -0
  31. package/src/hooks/auth/useAuthState.tsx +4 -5
  32. package/src/hooks/auth/useAuthToken.tsx +1 -1
  33. package/src/hooks/auth/useCurrentUser.tsx +28 -4
  34. package/src/hooks/auth/useDashboardOrganizationId.test.tsx +42 -0
  35. package/src/hooks/auth/useDashboardOrganizationId.tsx +29 -0
  36. package/src/hooks/auth/useHandleAuthCallback.test.tsx +16 -0
  37. package/src/hooks/auth/{useHandleCallback.tsx → useHandleAuthCallback.tsx} +7 -6
  38. package/src/hooks/auth/useLogOut.test.tsx +2 -2
  39. package/src/hooks/auth/useLogOut.tsx +1 -1
  40. package/src/hooks/auth/useLoginUrls.tsx +1 -0
  41. package/src/hooks/client/useClient.ts +9 -30
  42. package/src/hooks/comlink/useFrameConnection.test.tsx +167 -0
  43. package/src/hooks/comlink/useFrameConnection.ts +107 -0
  44. package/src/hooks/comlink/useManageFavorite.test.ts +111 -0
  45. package/src/hooks/comlink/useManageFavorite.ts +130 -0
  46. package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +81 -0
  47. package/src/hooks/comlink/useRecordDocumentHistoryEvent.ts +106 -0
  48. package/src/hooks/comlink/useWindowConnection.test.ts +135 -0
  49. package/src/hooks/comlink/useWindowConnection.ts +122 -0
  50. package/src/hooks/context/useSanityInstance.test.tsx +2 -2
  51. package/src/hooks/context/useSanityInstance.ts +24 -8
  52. package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +178 -0
  53. package/src/hooks/dashboard/useNavigateToStudioDocument.ts +123 -0
  54. package/src/hooks/dashboard/useStudioWorkspacesByResourceId.test.tsx +278 -0
  55. package/src/hooks/dashboard/useStudioWorkspacesByResourceId.ts +92 -0
  56. package/src/hooks/datasets/useDatasets.ts +40 -0
  57. package/src/hooks/document/useApplyDocumentActions.test.ts +25 -0
  58. package/src/hooks/document/useApplyDocumentActions.ts +75 -0
  59. package/src/hooks/document/useDocument.test.ts +81 -0
  60. package/src/hooks/document/useDocument.ts +107 -0
  61. package/src/hooks/document/useDocumentEvent.test.ts +63 -0
  62. package/src/hooks/document/useDocumentEvent.ts +54 -0
  63. package/src/hooks/document/useDocumentPermissions.ts +84 -0
  64. package/src/hooks/document/useDocumentSyncStatus.test.ts +16 -0
  65. package/src/hooks/document/useDocumentSyncStatus.ts +33 -0
  66. package/src/hooks/document/useEditDocument.test.ts +179 -0
  67. package/src/hooks/document/useEditDocument.ts +195 -0
  68. package/src/hooks/documents/useDocuments.test.tsx +152 -0
  69. package/src/hooks/documents/useDocuments.ts +174 -0
  70. package/src/hooks/helpers/createCallbackHook.tsx +3 -2
  71. package/src/hooks/helpers/createStateSourceHook.test.tsx +66 -0
  72. package/src/hooks/helpers/createStateSourceHook.tsx +29 -10
  73. package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +259 -0
  74. package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +290 -0
  75. package/src/hooks/preview/usePreview.test.tsx +19 -10
  76. package/src/hooks/preview/usePreview.tsx +67 -13
  77. package/src/hooks/projection/useProjection.test.tsx +218 -0
  78. package/src/hooks/projection/useProjection.ts +147 -0
  79. package/src/hooks/projects/useProject.ts +48 -0
  80. package/src/hooks/projects/useProjects.ts +45 -0
  81. package/src/hooks/query/useQuery.test.tsx +188 -0
  82. package/src/hooks/query/useQuery.ts +103 -0
  83. package/src/hooks/users/useUsers.test.ts +163 -0
  84. package/src/hooks/users/useUsers.ts +107 -0
  85. package/src/utils/getEnv.ts +21 -0
  86. package/src/version.ts +8 -0
  87. package/src/vite-env.d.ts +10 -0
  88. package/dist/_chunks-es/useLogOut.js +0 -44
  89. package/dist/_chunks-es/useLogOut.js.map +0 -1
  90. package/dist/assets/bundle-CcAyERuZ.css +0 -11
  91. package/dist/components.d.ts +0 -257
  92. package/dist/components.js +0 -316
  93. package/dist/components.js.map +0 -1
  94. package/dist/hooks.d.ts +0 -187
  95. package/dist/hooks.js +0 -81
  96. package/dist/hooks.js.map +0 -1
  97. package/src/_exports/components.ts +0 -13
  98. package/src/_exports/hooks.ts +0 -9
  99. package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +0 -113
  100. package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +0 -42
  101. package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +0 -21
  102. package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +0 -105
  103. package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +0 -42
  104. package/src/components/DocumentListLayout/DocumentListLayout.tsx +0 -12
  105. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +0 -49
  106. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +0 -39
  107. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +0 -30
  108. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +0 -171
  109. package/src/components/context/SanityProvider.tsx +0 -42
  110. package/src/css/css.config.js +0 -220
  111. package/src/css/paramour.css +0 -2347
  112. package/src/css/styles.css +0 -11
  113. package/src/hooks/auth/useHandleCallback.test.tsx +0 -16
  114. package/src/hooks/client/useClient.test.tsx +0 -130
  115. package/src/hooks/documentCollection/useDocuments.test.ts +0 -130
  116. package/src/hooks/documentCollection/useDocuments.ts +0 -87
@@ -1,11 +0,0 @@
1
- @import './paramour.css';
2
-
3
- body {
4
- color-scheme: light dark;
5
- color: light-dark(var(--gray-1), var(--gray-10));
6
- background-color: light-dark(var(--gray-11), var(--gray-1));
7
- }
8
-
9
- .container-inline {
10
- container-type: inline-size;
11
- }
@@ -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
- }