@sanity/sdk-react 2.1.2 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/sdk-react",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "private": false,
5
5
  "description": "Sanity SDK React toolkit for Content OS",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "browserslist": "extends @sanity/browserslist-config",
43
43
  "prettier": "@sanity/prettier-config",
44
44
  "dependencies": {
45
- "@sanity/client": "^7.2.1",
45
+ "@sanity/client": "^7.10.0",
46
46
  "@sanity/message-protocol": "^0.12.0",
47
47
  "@sanity/types": "^3.83.0",
48
48
  "@types/lodash-es": "^4.17.12",
@@ -51,7 +51,7 @@
51
51
  "react-compiler-runtime": "19.1.0-rc.2",
52
52
  "react-error-boundary": "^5.0.0",
53
53
  "rxjs": "^7.8.2",
54
- "@sanity/sdk": "2.1.2"
54
+ "@sanity/sdk": "2.2.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@sanity/browserslist-config": "^1.0.5",
@@ -76,9 +76,9 @@
76
76
  "vitest": "^3.1.2",
77
77
  "@repo/config-eslint": "0.0.0",
78
78
  "@repo/config-test": "0.0.1",
79
- "@repo/package.config": "0.0.1",
80
79
  "@repo/package.bundle": "3.82.0",
81
- "@repo/tsconfig": "0.0.1"
80
+ "@repo/tsconfig": "0.0.1",
81
+ "@repo/package.config": "0.0.1"
82
82
  },
83
83
  "peerDependencies": {
84
84
  "react": "^18.0.0 || ^19.0.0",
@@ -62,7 +62,7 @@ export const useSanityInstance = (config?: SanityConfig): SanityInstance => {
62
62
 
63
63
  if (!instance) {
64
64
  throw new Error(
65
- `SanityInstance context not found. ${config ? `Requested config: ${JSON.stringify(config, null, 2)}. ` : ''}Please ensure that your component is wrapped in a <ResourceProvider> or a <SanityApp>.`,
65
+ `SanityInstance context not found. ${config ? `Requested config: ${JSON.stringify(config, null, 2)}. ` : ''}Please ensure that your component is wrapped in a ResourceProvider or a SanityApp component.`,
66
66
  )
67
67
  }
68
68
 
@@ -72,7 +72,7 @@ export const useSanityInstance = (config?: SanityConfig): SanityInstance => {
72
72
  if (!match) {
73
73
  throw new Error(
74
74
  `Could not find a matching Sanity instance for the requested configuration: ${JSON.stringify(config, null, 2)}.
75
- Please ensure there is a <ResourceProvider> with a matching configuration in the component hierarchy.`,
75
+ Please ensure there is a ResourceProvider component with a matching configuration in the component hierarchy.`,
76
76
  )
77
77
  }
78
78
 
@@ -83,7 +83,7 @@ export function useDocumentPreview({
83
83
  ref,
84
84
  ...docHandle
85
85
  }: useDocumentPreviewOptions): useDocumentPreviewResults {
86
- const instance = useSanityInstance()
86
+ const instance = useSanityInstance(docHandle)
87
87
  const stateSource = getPreviewState(instance, docHandle)
88
88
 
89
89
  // Create subscribe function for useSyncExternalStore
@@ -181,7 +181,7 @@ export function useDocumentProjection<TData extends object>({
181
181
  projection,
182
182
  ...docHandle
183
183
  }: useDocumentProjectionOptions): useDocumentProjectionResults<TData> {
184
- const instance = useSanityInstance()
184
+ const instance = useSanityInstance(docHandle)
185
185
  const stateSource = getProjectionState<TData>(instance, {...docHandle, projection})
186
186
 
187
187
  if (stateSource.getCurrent()?.data === null) {
@@ -59,12 +59,12 @@ describe('useProjects', () => {
59
59
  // Mock instance for the test call
60
60
  const mockInstance = {} as SanityInstance // Use specific type
61
61
 
62
- // Call the shouldSuspend function
63
- const result = shouldSuspend(mockInstance)
62
+ // Call the shouldSuspend function with both required parameters
63
+ const result = shouldSuspend(mockInstance, undefined) // Pass undefined for options
64
64
 
65
65
  // Assert that getProjectsState was called with the correct arguments
66
66
  const mockGetProjectsState = getProjectsState as ReturnType<typeof vi.fn>
67
- expect(mockGetProjectsState).toHaveBeenCalledWith(mockInstance)
67
+ expect(mockGetProjectsState).toHaveBeenCalledWith(mockInstance, undefined)
68
68
 
69
69
  // Assert that getCurrent was called on the result of getProjectsState
70
70
  expect(mockGetProjectsState.mock.results.length).toBeGreaterThan(0)
@@ -74,4 +74,39 @@ describe('useProjects', () => {
74
74
  // Assert the result of shouldSuspend based on the mocked getCurrent value
75
75
  expect(result).toBe(true) // Since getCurrent is mocked to return undefined
76
76
  })
77
+
78
+ it('should call createStateSourceHook with correct getState function signature', async () => {
79
+ await import('./useProjects')
80
+
81
+ const mockCreateStateSourceHook = createStateSourceHook as ReturnType<typeof vi.fn>
82
+ expect(mockCreateStateSourceHook).toHaveBeenCalled()
83
+
84
+ const createStateSourceHookArgs = mockCreateStateSourceHook.mock.calls[0][0]
85
+ const getState = createStateSourceHookArgs.getState
86
+
87
+ // Test that getState can handle the new options parameter
88
+ const mockInstance = {} as SanityInstance
89
+ const mockOptions = {organizationId: 'org123', includeMembers: false}
90
+
91
+ // This should not throw
92
+ expect(() => getState(mockInstance, mockOptions)).not.toThrow()
93
+ })
94
+
95
+ it('should handle different parameter combinations in shouldSuspend', async () => {
96
+ await import('./useProjects')
97
+
98
+ const mockCreateStateSourceHook = createStateSourceHook as ReturnType<typeof vi.fn>
99
+ const createStateSourceHookArgs = mockCreateStateSourceHook.mock.calls[0][0]
100
+ const shouldSuspend = createStateSourceHookArgs.shouldSuspend
101
+
102
+ const mockInstance = {} as SanityInstance
103
+
104
+ // Test with different options
105
+ expect(() => shouldSuspend(mockInstance, undefined)).not.toThrow()
106
+ expect(() => shouldSuspend(mockInstance, {organizationId: 'org123'})).not.toThrow()
107
+ expect(() => shouldSuspend(mockInstance, {includeMembers: false})).not.toThrow()
108
+ expect(() =>
109
+ shouldSuspend(mockInstance, {organizationId: 'org123', includeMembers: false}),
110
+ ).not.toThrow()
111
+ })
77
112
  })
@@ -10,36 +10,47 @@ import {createStateSourceHook} from '../helpers/createStateSourceHook'
10
10
  */
11
11
  export type ProjectWithoutMembers = Omit<SanityProject, 'members'>
12
12
 
13
- type UseProjects = {
14
- /**
15
- *
16
- * Returns metadata for each project you have access to.
17
- *
18
- * @category Projects
19
- * @returns An array of metadata (minus the projects’ members) for each project
20
- * @example
21
- * ```tsx
22
- * const projects = useProjects()
23
- *
24
- * return (
25
- * <select>
26
- * {projects.map((project) => (
27
- * <option key={project.id}>{project.displayName}</option>
28
- * ))}
29
- * </select>
30
- * )
31
- * ```
32
- */
33
- (): ProjectWithoutMembers[]
34
- }
13
+ /**
14
+ * @public
15
+ * @category Types
16
+ */
17
+ type UseProjects = <TIncludeMembers extends boolean = false>(options?: {
18
+ organizationId?: string
19
+ includeMembers?: TIncludeMembers
20
+ }) => TIncludeMembers extends true ? SanityProject[] : ProjectWithoutMembers[]
35
21
 
36
22
  /**
23
+ * Returns metadata for each project you have access to.
24
+ *
25
+ * @category Projects
26
+ * @param options - Configuration options
27
+ * @returns An array of project metadata. If includeMembers is true, returns full SanityProject objects. Otherwise, returns ProjectWithoutMembers objects.
28
+ * @example
29
+ * ```tsx
30
+ * const projects = useProjects()
31
+ *
32
+ * return (
33
+ * <select>
34
+ * {projects.map((project) => (
35
+ * <option key={project.id}>{project.displayName}</option>
36
+ * ))}
37
+ * </select>
38
+ * )
39
+ * ```
40
+ * @example
41
+ * ```tsx
42
+ * const projectsWithMembers = useProjects({ includeMembers: true })
43
+ * const projectsWithoutMembers = useProjects({ includeMembers: false })
44
+ * ```
37
45
  * @public
38
46
  * @function
39
47
  */
40
48
  export const useProjects: UseProjects = createStateSourceHook({
41
- // remove `undefined` since we're suspending when that is the case
42
- getState: getProjectsState as (instance: SanityInstance) => StateSource<ProjectWithoutMembers[]>,
43
- shouldSuspend: (instance) => getProjectsState(instance).getCurrent() === undefined,
49
+ getState: getProjectsState as (
50
+ instance: SanityInstance,
51
+ options?: {organizationId?: string; includeMembers?: boolean},
52
+ ) => StateSource<SanityProject[] | ProjectWithoutMembers[]>,
53
+ shouldSuspend: (instance, options) =>
54
+ getProjectsState(instance, options).getCurrent() === undefined,
44
55
  suspender: resolveProjects,
45
- })
56
+ }) as UseProjects