@sanity/sdk-react 0.0.0-alpha.17 → 0.0.0-alpha.19
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 +7 -93
- package/dist/index.d.ts +4639 -0
- package/dist/index.js +952 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -28
- package/src/_exports/index.ts +57 -0
- package/src/components/Login/LoginLinks.test.tsx +1 -2
- package/src/components/auth/AuthBoundary.test.tsx +1 -1
- package/src/context/SanityInstanceContext.ts +4 -0
- package/src/context/SanityProvider.tsx +3 -3
- package/src/hooks/comlink/useManageFavorite.test.ts +106 -0
- package/src/hooks/comlink/useManageFavorite.ts +98 -0
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +77 -0
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.ts +75 -0
- package/src/hooks/context/useSanityInstance.ts +1 -1
- package/dist/_chunks-es/context.js +0 -16
- package/dist/_chunks-es/context.js.map +0 -1
- package/dist/_chunks-es/useLogOut.js +0 -73
- package/dist/_chunks-es/useLogOut.js.map +0 -1
- package/dist/components.d.ts +0 -154
- package/dist/components.js +0 -236
- package/dist/components.js.map +0 -1
- package/dist/context.d.ts +0 -47
- package/dist/context.js +0 -5
- package/dist/context.js.map +0 -1
- package/dist/hooks.d.ts +0 -4365
- package/dist/hooks.js +0 -572
- package/dist/hooks.js.map +0 -1
- package/src/_exports/components.ts +0 -3
- package/src/_exports/context.ts +0 -2
- package/src/_exports/hooks.ts +0 -50
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {type Events, SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
|
|
2
|
+
import {type DocumentHandle, type FrameMessage} from '@sanity/sdk'
|
|
3
|
+
import {useCallback, useState} from 'react'
|
|
4
|
+
|
|
5
|
+
import {useWindowConnection} from './useWindowConnection'
|
|
6
|
+
|
|
7
|
+
// should we import this whole type from the message protocol?
|
|
8
|
+
|
|
9
|
+
interface ManageFavorite {
|
|
10
|
+
favorite: () => void
|
|
11
|
+
unfavorite: () => void
|
|
12
|
+
isFavorited: boolean
|
|
13
|
+
isConnected: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @beta
|
|
18
|
+
*
|
|
19
|
+
* ## useManageFavorite
|
|
20
|
+
* This hook provides functionality to add and remove documents from favorites,
|
|
21
|
+
* and tracks the current favorite status of the document.
|
|
22
|
+
* @category Core UI Communication
|
|
23
|
+
* @param documentHandle - The document handle containing document ID and type, like `{_id: '123', _type: 'book'}`
|
|
24
|
+
* @returns An object containing:
|
|
25
|
+
* - `favorite` - Function to add document to favorites
|
|
26
|
+
* - `unfavorite` - Function to remove document from favorites
|
|
27
|
+
* - `isFavorited` - Boolean indicating if document is currently favorited
|
|
28
|
+
* - `isConnected` - Boolean indicating if connection to Core UI is established
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function MyDocumentAction(props: DocumentActionProps) {
|
|
33
|
+
* const {_id, _type} = props
|
|
34
|
+
* const {favorite, unfavorite, isFavorited, isConnected} = useManageFavorite({
|
|
35
|
+
* _id,
|
|
36
|
+
* _type
|
|
37
|
+
* })
|
|
38
|
+
*
|
|
39
|
+
* return (
|
|
40
|
+
* <Button
|
|
41
|
+
* disabled={!isConnected}
|
|
42
|
+
* onClick={() => isFavorited ? unfavorite() : favorite()}
|
|
43
|
+
* text={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
|
|
44
|
+
* />
|
|
45
|
+
* )
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function useManageFavorite({_id, _type}: DocumentHandle): ManageFavorite {
|
|
50
|
+
const [isFavorited, setIsFavorited] = useState(false) // should load this from a comlink fetch
|
|
51
|
+
const {sendMessage, status} = useWindowConnection<Events.FavoriteMessage, FrameMessage>({
|
|
52
|
+
name: SDK_NODE_NAME,
|
|
53
|
+
connectTo: SDK_CHANNEL_NAME,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const handleFavoriteAction = useCallback(
|
|
57
|
+
(action: 'added' | 'removed', setFavoriteState: boolean) => {
|
|
58
|
+
if (!_id || !_type) return
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const message: Events.FavoriteMessage = {
|
|
62
|
+
type: 'core/v1/events/favorite',
|
|
63
|
+
data: {
|
|
64
|
+
eventType: action,
|
|
65
|
+
documentId: _id,
|
|
66
|
+
documentType: _type,
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
sendMessage(message.type, message.data)
|
|
71
|
+
setIsFavorited(setFavoriteState)
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const error = err instanceof Error ? err : new Error('Failed to update favorite status')
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.error(
|
|
76
|
+
`Failed to ${action === 'added' ? 'favorite' : 'unfavorite'} document:`,
|
|
77
|
+
error,
|
|
78
|
+
)
|
|
79
|
+
throw error
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
[_id, _type, sendMessage],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const favorite = useCallback(() => handleFavoriteAction('added', true), [handleFavoriteAction])
|
|
86
|
+
|
|
87
|
+
const unfavorite = useCallback(
|
|
88
|
+
() => handleFavoriteAction('removed', false),
|
|
89
|
+
[handleFavoriteAction],
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
favorite,
|
|
94
|
+
unfavorite,
|
|
95
|
+
isFavorited,
|
|
96
|
+
isConnected: status === 'connected',
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {type Message, type Node, type Status} from '@sanity/comlink'
|
|
2
|
+
import {getOrCreateNode} from '@sanity/sdk'
|
|
3
|
+
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
4
|
+
|
|
5
|
+
import {act, renderHook} from '../../../test/test-utils'
|
|
6
|
+
import {useRecordDocumentHistoryEvent} from './useRecordDocumentHistoryEvent'
|
|
7
|
+
|
|
8
|
+
vi.mock(import('@sanity/sdk'), async (importOriginal) => {
|
|
9
|
+
const actual = await importOriginal()
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
getOrCreateNode: vi.fn(),
|
|
13
|
+
releaseNode: vi.fn(),
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('useRecordDocumentHistoryEvent', () => {
|
|
18
|
+
let node: Node<Message, Message>
|
|
19
|
+
let statusCallback: ((status: Status) => void) | null = null
|
|
20
|
+
|
|
21
|
+
const mockDocumentHandle = {
|
|
22
|
+
_id: 'mock-id',
|
|
23
|
+
_type: 'mock-type',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createMockNode() {
|
|
27
|
+
return {
|
|
28
|
+
on: vi.fn(() => () => {}),
|
|
29
|
+
post: vi.fn(),
|
|
30
|
+
stop: vi.fn(),
|
|
31
|
+
onStatus: vi.fn((callback) => {
|
|
32
|
+
statusCallback = callback
|
|
33
|
+
return () => {}
|
|
34
|
+
}),
|
|
35
|
+
} as unknown as Node<Message, Message>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
statusCallback = null
|
|
40
|
+
node = createMockNode()
|
|
41
|
+
vi.mocked(getOrCreateNode).mockReturnValue(node)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should initialize with correct connection status', () => {
|
|
45
|
+
const {result} = renderHook(() => useRecordDocumentHistoryEvent(mockDocumentHandle))
|
|
46
|
+
|
|
47
|
+
expect(result.current.isConnected).toBe(false)
|
|
48
|
+
|
|
49
|
+
act(() => {
|
|
50
|
+
statusCallback?.('connected')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
expect(result.current.isConnected).toBe(true)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should send correct message when recording events', () => {
|
|
57
|
+
const {result} = renderHook(() => useRecordDocumentHistoryEvent(mockDocumentHandle))
|
|
58
|
+
|
|
59
|
+
result.current.recordEvent('viewed')
|
|
60
|
+
|
|
61
|
+
expect(node.post).toHaveBeenCalledWith('core/v1/events/history', {
|
|
62
|
+
eventType: 'viewed',
|
|
63
|
+
documentId: 'mock-id',
|
|
64
|
+
documentType: 'mock-type',
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should handle errors when sending messages', () => {
|
|
69
|
+
vi.mocked(node.post).mockImplementation(() => {
|
|
70
|
+
throw new Error('Failed to send message')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const {result} = renderHook(() => useRecordDocumentHistoryEvent(mockDocumentHandle))
|
|
74
|
+
|
|
75
|
+
expect(() => result.current.recordEvent('viewed')).toThrow('Failed to send message')
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {type Events, SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
|
|
2
|
+
import {type DocumentHandle, type FrameMessage} from '@sanity/sdk'
|
|
3
|
+
import {useCallback} from 'react'
|
|
4
|
+
|
|
5
|
+
import {useWindowConnection} from './useWindowConnection'
|
|
6
|
+
|
|
7
|
+
interface DocumentInteractionHistory {
|
|
8
|
+
recordEvent: (eventType: 'viewed' | 'edited' | 'created' | 'deleted') => void
|
|
9
|
+
isConnected: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @public
|
|
14
|
+
* Hook for managing document interaction history in Sanity Studio.
|
|
15
|
+
* This hook provides functionality to record document interactions.
|
|
16
|
+
* @param documentHandle - The document handle containing document ID and type, like `{_id: '123', _type: 'book'}`
|
|
17
|
+
* @returns An object containing:
|
|
18
|
+
* - `recordEvent` - Function to record document interactions
|
|
19
|
+
* - `isConnected` - Boolean indicating if connection to Studio is established
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* function MyDocumentAction(props: DocumentActionProps) {
|
|
24
|
+
* const {_id, _type} = props
|
|
25
|
+
* const {recordEvent, isConnected} = useRecordDocumentHistoryEvent({
|
|
26
|
+
* _id,
|
|
27
|
+
* _type
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <Button
|
|
32
|
+
* disabled={!isConnected}
|
|
33
|
+
* onClick={() => recordEvent('viewed')}
|
|
34
|
+
* text={'Viewed'}
|
|
35
|
+
* />
|
|
36
|
+
* )
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function useRecordDocumentHistoryEvent({
|
|
41
|
+
_id,
|
|
42
|
+
_type,
|
|
43
|
+
}: DocumentHandle): DocumentInteractionHistory {
|
|
44
|
+
const {sendMessage, status} = useWindowConnection<Events.HistoryMessage, FrameMessage>({
|
|
45
|
+
name: SDK_NODE_NAME,
|
|
46
|
+
connectTo: SDK_CHANNEL_NAME,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const recordEvent = useCallback(
|
|
50
|
+
(eventType: 'viewed' | 'edited' | 'created' | 'deleted') => {
|
|
51
|
+
try {
|
|
52
|
+
const message: Events.HistoryMessage = {
|
|
53
|
+
type: 'core/v1/events/history',
|
|
54
|
+
data: {
|
|
55
|
+
eventType,
|
|
56
|
+
documentId: _id,
|
|
57
|
+
documentType: _type,
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sendMessage(message.type, message.data)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.error('Failed to record history event:', error)
|
|
65
|
+
throw error
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
[_id, _type, sendMessage],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
recordEvent,
|
|
73
|
+
isConnected: status === 'connected',
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {type SanityInstance} from '@sanity/sdk'
|
|
2
2
|
import {useContext} from 'react'
|
|
3
3
|
|
|
4
|
-
import {SanityInstanceContext} from '../../context/
|
|
4
|
+
import {SanityInstanceContext} from '../../context/SanityInstanceContext'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* `useSanityInstance` returns the current Sanity instance from the application context.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { c } from "react/compiler-runtime";
|
|
3
|
-
import { createContext } from "react";
|
|
4
|
-
const SanityInstanceContext = createContext(null), SanityProvider = (t0) => {
|
|
5
|
-
const $ = c(3), {
|
|
6
|
-
children,
|
|
7
|
-
sanityInstances
|
|
8
|
-
} = t0;
|
|
9
|
-
let t1;
|
|
10
|
-
return $[0] !== children || $[1] !== sanityInstances ? (t1 = /* @__PURE__ */ jsx(SanityInstanceContext.Provider, { value: sanityInstances, children }), $[0] = children, $[1] = sanityInstances, $[2] = t1) : t1 = $[2], t1;
|
|
11
|
-
};
|
|
12
|
-
export {
|
|
13
|
-
SanityInstanceContext,
|
|
14
|
-
SanityProvider
|
|
15
|
-
};
|
|
16
|
-
//# sourceMappingURL=context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sources":["../../src/context/SanityProvider.tsx"],"sourcesContent":["import {type SanityInstance} from '@sanity/sdk'\nimport {createContext, type ReactElement} from 'react'\n\n/**\n * @internal\n */\nexport interface SanityProviderProps {\n children: React.ReactNode\n sanityInstances: SanityInstance[]\n}\n\nexport const SanityInstanceContext = createContext<SanityInstance[] | null>(null)\n\n/**\n * @internal\n *\n * Top-level context provider that provides access to the Sanity configuration instance.\n * This must wrap any components making use of the Sanity SDK React hooks.\n *\n * @remarks In most cases, SanityApp should be used rather than SanityProvider directly; SanityApp bundles both SanityProvider and an authentication layer.\n * @param props - Sanity project and dataset configuration\n * @returns Rendered component\n * @example\n * ```tsx\n * import {createSanityInstance} from '@sanity/sdk'\n * import {SanityProvider} from '@sanity/sdk-react'\n *\n * import MyAppRoot from './Root'\n *\n * const sanityInstance = createSanityInstance({\n * projectId: 'your-project-id',\n * dataset: 'production',\n * })\n *\n * export default function MyApp() {\n * return (\n * <SanityProvider sanityInstance={sanityInstance}>\n * <MyAppRoot />\n * </SanityProvider>\n * )\n * }\n * ```\n */\nexport const SanityProvider = ({children, sanityInstances}: SanityProviderProps): ReactElement => {\n return (\n <SanityInstanceContext.Provider value={sanityInstances}>\n {children}\n </SanityInstanceContext.Provider>\n )\n}\n"],"names":["SanityInstanceContext","createContext","SanityProvider","t0","$","_c","children","sanityInstances","t1"],"mappings":";;;AAWO,MAAMA,wBAAwBC,cAAuC,IAAI,GAgCnEC,iBAAiBC,CAAA,OAAA;AAAAC,QAAAA,IAAAC,EAAA,CAAA,GAAC;AAAA,IAAAC;AAAAA,IAAAC;AAAAA,EAAAA,IAAAJ;AAAgDK,MAAAA;AAAA,SAAAJ,EAAAE,CAAAA,MAAAA,YAAAF,SAAAG,mBAE3EC,KAAA,oBAAA,sBAAA,UAAA,EAAuCD,OAAAA,iBACpCD,SAAAA,CACH,GAAiCF,OAAAE,UAAAF,OAAAG,iBAAAH,OAAAI,MAAAA,KAAAJ,EAAA,CAAA,GAFjCI;AAEiC;"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { getAuthState, handleCallback, getLoginUrlsState, fetchLoginUrls, logout } from "@sanity/sdk";
|
|
2
|
-
import { c } from "react/compiler-runtime";
|
|
3
|
-
import { useContext, useSyncExternalStore, useMemo } from "react";
|
|
4
|
-
import { SanityInstanceContext } from "./context.js";
|
|
5
|
-
const useSanityInstance = (resourceId) => {
|
|
6
|
-
const $ = c(5), sanityInstance = useContext(SanityInstanceContext);
|
|
7
|
-
if (!sanityInstance)
|
|
8
|
-
throw new Error("useSanityInstance must be called from within the SanityProvider");
|
|
9
|
-
if (sanityInstance.length === 0)
|
|
10
|
-
throw new Error("No Sanity instances found");
|
|
11
|
-
if (sanityInstance.length === 1 || !resourceId)
|
|
12
|
-
return sanityInstance[0];
|
|
13
|
-
if (!resourceId)
|
|
14
|
-
throw new Error("resourceId is required when there are multiple Sanity instances");
|
|
15
|
-
let t0;
|
|
16
|
-
if ($[0] !== resourceId || $[1] !== sanityInstance) {
|
|
17
|
-
let t1;
|
|
18
|
-
$[3] !== resourceId ? (t1 = (inst) => inst.identity.resourceId === resourceId, $[3] = resourceId, $[4] = t1) : t1 = $[4], t0 = sanityInstance.find(t1), $[0] = resourceId, $[1] = sanityInstance, $[2] = t0;
|
|
19
|
-
} else
|
|
20
|
-
t0 = $[2];
|
|
21
|
-
const instance = t0;
|
|
22
|
-
if (!instance)
|
|
23
|
-
throw new Error(`Sanity instance with resourceId ${resourceId} not found`);
|
|
24
|
-
return instance;
|
|
25
|
-
};
|
|
26
|
-
function createStateSourceHook(options) {
|
|
27
|
-
const getState = typeof options == "function" ? options : options.getState, getResourceId = "getResourceId" in options ? options.getResourceId : void 0, suspense = "shouldSuspend" in options && "suspender" in options ? options : void 0;
|
|
28
|
-
function useHook(...t0) {
|
|
29
|
-
const $ = c(5), params = t0;
|
|
30
|
-
let resourceId;
|
|
31
|
-
if (getResourceId) {
|
|
32
|
-
let t12;
|
|
33
|
-
$[0] !== params ? (t12 = getResourceId(...params), $[0] = params, $[1] = t12) : t12 = $[1], resourceId = t12;
|
|
34
|
-
}
|
|
35
|
-
const instance = useSanityInstance(resourceId);
|
|
36
|
-
if (suspense?.suspender && suspense?.shouldSuspend?.(instance, ...params))
|
|
37
|
-
throw suspense.suspender(instance, ...params);
|
|
38
|
-
let t1;
|
|
39
|
-
$[2] !== instance || $[3] !== params ? (t1 = getState(instance, ...params), $[2] = instance, $[3] = params, $[4] = t1) : t1 = $[4];
|
|
40
|
-
const state = t1;
|
|
41
|
-
return useSyncExternalStore(state.subscribe, state.getCurrent);
|
|
42
|
-
}
|
|
43
|
-
return useHook;
|
|
44
|
-
}
|
|
45
|
-
const useAuthState = createStateSourceHook(getAuthState);
|
|
46
|
-
function createCallbackHook(callback, resourceId) {
|
|
47
|
-
function useHook() {
|
|
48
|
-
const $ = c(2), instance = useSanityInstance(resourceId);
|
|
49
|
-
let t0;
|
|
50
|
-
return $[0] !== instance ? (t0 = (...t1) => callback(instance, ...t1), $[0] = instance, $[1] = t0) : t0 = $[1], t0;
|
|
51
|
-
}
|
|
52
|
-
return useHook;
|
|
53
|
-
}
|
|
54
|
-
const useHandleCallback = createCallbackHook(handleCallback);
|
|
55
|
-
function useLoginUrls() {
|
|
56
|
-
const instance = useSanityInstance(), {
|
|
57
|
-
subscribe,
|
|
58
|
-
getCurrent
|
|
59
|
-
} = useMemo(() => getLoginUrlsState(instance), [instance]);
|
|
60
|
-
if (!getCurrent()) throw fetchLoginUrls(instance);
|
|
61
|
-
return useSyncExternalStore(subscribe, getCurrent);
|
|
62
|
-
}
|
|
63
|
-
const useLogOut = createCallbackHook(logout);
|
|
64
|
-
export {
|
|
65
|
-
createCallbackHook,
|
|
66
|
-
createStateSourceHook,
|
|
67
|
-
useAuthState,
|
|
68
|
-
useHandleCallback,
|
|
69
|
-
useLogOut,
|
|
70
|
-
useLoginUrls,
|
|
71
|
-
useSanityInstance
|
|
72
|
-
};
|
|
73
|
-
//# sourceMappingURL=useLogOut.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useLogOut.js","sources":["../../src/hooks/context/useSanityInstance.ts","../../src/hooks/helpers/createStateSourceHook.tsx","../../src/hooks/auth/useAuthState.tsx","../../src/hooks/helpers/createCallbackHook.tsx","../../src/hooks/auth/useHandleCallback.tsx","../../src/hooks/auth/useLoginUrls.tsx","../../src/hooks/auth/useLogOut.tsx"],"sourcesContent":["import {type SanityInstance} from '@sanity/sdk'\nimport {useContext} from 'react'\n\nimport {SanityInstanceContext} from '../../context/SanityProvider'\n\n/**\n * `useSanityInstance` returns the current Sanity instance from the application context.\n * This must be called from within a `SanityProvider` component.\n * @internal\n *\n * @param resourceId - The resourceId of the Sanity instance to return (optional)\n * @returns The current Sanity instance\n * @example\n * ```tsx\n * const instance = useSanityInstance('abc123.production')\n * ```\n */\nexport const useSanityInstance = (resourceId?: string): SanityInstance => {\n const sanityInstance = useContext(SanityInstanceContext)\n if (!sanityInstance) {\n throw new Error('useSanityInstance must be called from within the SanityProvider')\n }\n if (sanityInstance.length === 0) {\n throw new Error('No Sanity instances found')\n }\n if (sanityInstance.length === 1 || !resourceId) {\n return sanityInstance[0]\n }\n\n if (!resourceId) {\n throw new Error('resourceId is required when there are multiple Sanity instances')\n }\n\n const instance = sanityInstance.find((inst) => inst.identity.resourceId === resourceId)\n if (!instance) {\n throw new Error(`Sanity instance with resourceId ${resourceId} not found`)\n }\n return instance\n}\n","import {type ResourceId, type SanityInstance, type StateSource} from '@sanity/sdk'\nimport {useSyncExternalStore} from 'react'\n\nimport {useSanityInstance} from '../context/useSanityInstance'\n\ntype StateSourceFactory<TParams extends unknown[], TState> = (\n instance: SanityInstance,\n ...params: TParams\n) => StateSource<TState>\n\ninterface CreateStateSourceHookOptions<TParams extends unknown[], TState> {\n getState: StateSourceFactory<TParams, TState>\n shouldSuspend?: (instance: SanityInstance, ...params: TParams) => boolean\n suspender?: (instance: SanityInstance, ...params: TParams) => Promise<unknown>\n getResourceId?: (...params: TParams) => ResourceId | undefined\n}\n\nexport function createStateSourceHook<TParams extends unknown[], TState>(\n options: StateSourceFactory<TParams, TState> | CreateStateSourceHookOptions<TParams, TState>,\n): (...params: TParams) => TState {\n const getState = typeof options === 'function' ? options : options.getState\n const getResourceId = 'getResourceId' in options ? options.getResourceId : undefined\n const suspense = 'shouldSuspend' in options && 'suspender' in options ? options : undefined\n\n function useHook(...params: TParams) {\n let resourceId: ResourceId | undefined\n if (getResourceId) {\n resourceId = getResourceId(...params)\n }\n const instance = useSanityInstance(resourceId)\n if (suspense?.suspender && suspense?.shouldSuspend?.(instance, ...params)) {\n throw suspense.suspender(instance, ...params)\n }\n\n const state = getState(instance, ...params)\n return useSyncExternalStore(state.subscribe, state.getCurrent)\n }\n\n return useHook\n}\n","import {type AuthState, getAuthState} from '@sanity/sdk'\n\nimport {createStateSourceHook} from '../helpers/createStateSourceHook'\n\n/**\n * @internal\n * A React hook that subscribes to authentication state changes.\n *\n * This hook provides access to the current authentication state type from the Sanity auth store.\n * It automatically re-renders when the authentication state changes.\n *\n * @remarks\n * The hook uses `useSyncExternalStore` to safely subscribe to auth state changes\n * and ensure consistency between server and client rendering.\n *\n * @returns The current authentication state type\n *\n * @example\n * ```tsx\n * function AuthStatus() {\n * const authState = useAuthState()\n * return <div>Current auth state: {authState}</div>\n * }\n * ```\n */\nexport const useAuthState: () => AuthState = createStateSourceHook(getAuthState)\n","import {type ResourceId, type SanityInstance} from '@sanity/sdk'\nimport {useCallback} from 'react'\n\nimport {useSanityInstance} from '../context/useSanityInstance'\n\nexport function createCallbackHook<TParams extends unknown[], TReturn>(\n callback: (instance: SanityInstance, ...params: TParams) => TReturn,\n resourceId?: ResourceId,\n): () => (...params: TParams) => TReturn {\n function useHook() {\n const instance = useSanityInstance(resourceId)\n return useCallback((...params: TParams) => callback(instance, ...params), [instance])\n }\n\n return useHook\n}\n","import {handleCallback} from '@sanity/sdk'\n\nimport {createCallbackHook} from '../helpers/createCallbackHook'\n\n/**\n * @internal\n * A React hook that returns a function for handling authentication callbacks.\n *\n * @remarks\n * This hook provides access to the authentication store's callback handler,\n * which processes auth redirects by extracting the session ID and fetching the\n * authentication token. If fetching the long-lived token is successful,\n * `handleCallback` will return a Promise that resolves a new location that\n * removes the short-lived token from the URL. Use this in combination with\n * `history.replaceState` or your own router's `replace` function to update the\n * current location without triggering a reload.\n *\n * @example\n * ```tsx\n * function AuthCallback() {\n * const handleCallback = useHandleCallback()\n * const router = useRouter() // Example router\n *\n * useEffect(() => {\n * async function processCallback() {\n * // Handle the callback and get the cleaned URL\n * const newUrl = await handleCallback(window.location.href)\n *\n * if (newUrl) {\n * // Replace URL without triggering navigation\n * router.replace(newUrl, {shallow: true})\n * }\n * }\n *\n * processCallback().catch(console.error)\n * }, [handleCallback, router])\n *\n * return <div>Completing login...</div>\n * }\n * ```\n *\n * @returns A callback handler function that processes OAuth redirects\n * @public\n */\nexport const useHandleCallback = createCallbackHook(handleCallback)\n","import {type AuthProvider, fetchLoginUrls, getLoginUrlsState} from '@sanity/sdk'\nimport {useMemo, useSyncExternalStore} from 'react'\n\nimport {useSanityInstance} from '../context/useSanityInstance'\n\n/**\n * @internal\n * A React hook that retrieves the available authentication provider URLs for login.\n *\n * @remarks\n * This hook fetches the login URLs from the Sanity auth store when the component mounts.\n * Each provider object contains information about an authentication method, including its URL.\n * The hook will suspend if the login URLs have not yet loaded.\n *\n * @example\n * ```tsx\n * // LoginProviders component that uses the hook\n * function LoginProviders() {\n * const providers = useLoginUrls()\n *\n * return (\n * <div>\n * {providers.map((provider) => (\n * <a key={provider.name} href={provider.url}>\n * Login with {provider.title}\n * </a>\n * ))}\n * </div>\n * )\n * }\n *\n * // Parent component with Suspense boundary\n * function LoginPage() {\n * return (\n * <Suspense fallback={<div>Loading authentication providers...</div>}>\n * <LoginProviders />\n * </Suspense>\n * )\n * }\n * ```\n *\n * @returns An array of {@link AuthProvider} objects containing login URLs and provider information\n * @public\n */\nexport function useLoginUrls(): AuthProvider[] {\n const instance = useSanityInstance()\n const {subscribe, getCurrent} = useMemo(() => getLoginUrlsState(instance), [instance])\n\n if (!getCurrent()) throw fetchLoginUrls(instance)\n\n return useSyncExternalStore(subscribe, getCurrent as () => AuthProvider[])\n}\n","import {logout} from '@sanity/sdk'\n\nimport {createCallbackHook} from '../helpers/createCallbackHook'\n\n/**\n * Hook to log out of the current session\n * @internal\n * @returns A function to log out of the current session\n */\nexport const useLogOut = createCallbackHook(logout)\n"],"names":["useSanityInstance","resourceId","$","_c","sanityInstance","useContext","SanityInstanceContext","Error","length","t0","t1","inst","identity","find","instance","createStateSourceHook","options","getState","getResourceId","undefined","suspense","useHook","params","suspender","shouldSuspend","state","useSyncExternalStore","subscribe","getCurrent","useAuthState","getAuthState","createCallbackHook","callback","useHandleCallback","handleCallback","useLoginUrls","useMemo","getLoginUrlsState","fetchLoginUrls","useLogOut","logout"],"mappings":";;;;AAiBO,MAAMA,oBAAoBC,CAAA,eAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GAC/BC,iBAAuBC,WAAAC,qBAAgC;AAAC,MAAA,CACnDF;AAAcG,UAAAA,IAAAA,MACD,iEAAiE;AAAA,MAE/EH,eAAcI,WAAa;AAAAD,UAAAA,IAAAA,MACb,2BAA2B;AAEzCH,MAAAA,eAAcI,WAAA,MAAkBP;AAAU,WACrCG,eAAc,CAAA;AAAA,MAAA,CAGlBH;AAAUM,UAAAA,IAAAA,MACG,iEAAiE;AAAAE,MAAAA;AAAA,MAAAP,EAAAD,CAAAA,MAAAA,cAAAC,SAAAE,gBAAA;AAAAM,QAAAA;AAAAR,aAAAD,cAG9CS,KAAAC,UAAUA,KAAIC,SAAAX,eAAyBA,YAAUC,OAAAD,YAAAC,OAAAQ,MAAAA,KAAAR,EAAA,CAAA,GAArEO,KAAAL,eAAcS,KAAMH,EAAiD,GAACR,OAAAD,YAAAC,OAAAE,gBAAAF,OAAAO;AAAAA,EAAA;AAAAA,SAAAP,EAAA,CAAA;AAAvF,QAAAY,WAAiBL;AAAsE,MAAA,CAClFK;AAAQ,UAAA,IAAAP,MACK,mCAAmCN,UAAU,YAAY;AAEpEa,SAAAA;AAAQ;ACpBV,SAASC,sBACdC,SACgC;AAChC,QAAMC,WAAW,OAAOD,WAAY,aAAaA,UAAUA,QAAQC,UAC7DC,gBAAgB,mBAAmBF,UAAUA,QAAQE,gBAAgBC,QACrEC,WAAW,mBAAmBJ,WAAW,eAAeA,UAAUA,UAAUG;AAElF,WAAAE,WAAAZ,IAAA;AAAA,UAAAP,IAAAC,EAAA,CAAA,GAAiBmB,SAAAb;AACXR,QAAAA;AAAkC,QAAAiB,eAAA;AAAAR,UAAAA;AAAAR,eAAAoB,UAEvBZ,MAAAQ,cAAiBI,GAAAA,MAAM,GAACpB,OAAAoB,QAAApB,OAAAQ,OAAAA,MAAAR,EAAA,CAAA,GAArCD,aAAaA;AAAAA,IAAAA;AAEfa,UAAAA,WAAiBd,kBAAkBC,UAAU;AAAC,QAC1CmB,UAAAG,aAAAH,UAAAI,gBAAiDV,UAAaQ,GAAAA,MAAM;AAAC,YACjEF,SAAAG,UAAmBT,UAAQ,GAAKQ,MAAM;AAACZ,QAAAA;AAAAR,MAAAY,CAAAA,MAAAA,YAAAZ,SAAAoB,UAGjCZ,KAAAO,SAASH,UAAQ,GAAKQ,MAAM,GAACpB,OAAAY,UAAAZ,OAAAoB,QAAApB,OAAAQ,MAAAA,KAAAR,EAAA,CAAA;AAA3C,UAAAuB,QAAcf;AAA6B,WACpCgB,qBAAqBD,MAAKE,WAAYF,MAAKG,UAAW;AAAA,EAAA;AAGxDP,SAAAA;AACT;ACdaQ,MAAAA,eAAgCd,sBAAsBe,YAAY;ACpB/DC,SAAAA,mBACdC,UACA/B,YACuC;AACvC,WAAAoB,UAAA;AAAA,UAAAnB,IAAAC,EAAA,CAAA,GACEW,WAAiBd,kBAAAC,UAA4B;AAACQ,QAAAA;AAAAP,WAAAA,SAAAY,YAC3BL,KAAAA,IAAAC,OAAwBsB,SAASlB,UAAQ,GAAxCJ,EAAmD,GAACR,OAAAY,UAAAZ,OAAAO,MAAAA,KAAAP,EAAA,CAAA,GAAjEO;AAAAA,EAAAA;AAGFY,SAAAA;AACT;AC6BaY,MAAAA,oBAAoBF,mBAAmBG,cAAc;ACA3D,SAASC,eAA+B;AACvCrB,QAAAA,WAAWd,qBACX;AAAA,IAAC2B;AAAAA,IAAWC;AAAAA,EAAAA,IAAcQ,QAAQ,MAAMC,kBAAkBvB,QAAQ,GAAG,CAACA,QAAQ,CAAC;AAErF,MAAI,CAACc,WAAAA,EAAc,OAAMU,eAAexB,QAAQ;AAEzCY,SAAAA,qBAAqBC,WAAWC,UAAkC;AAC3E;AC1CaW,MAAAA,YAAYR,mBAAmBS,MAAM;"}
|
package/dist/components.d.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import {FallbackProps} from 'react-error-boundary'
|
|
2
|
-
import {ReactElement} from 'react'
|
|
3
|
-
import {ReactNode} from 'react'
|
|
4
|
-
import {SanityConfig} from '@sanity/sdk'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A component that handles authentication flow and error boundaries for a
|
|
8
|
-
* protected section of the application.
|
|
9
|
-
*
|
|
10
|
-
* @remarks
|
|
11
|
-
* This component manages different authentication states and renders the
|
|
12
|
-
* appropriate components based on that state.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```tsx
|
|
16
|
-
* function App() {
|
|
17
|
-
* return (
|
|
18
|
-
* <AuthBoundary header={<MyLogo />}>
|
|
19
|
-
* <ProtectedContent />
|
|
20
|
-
* </AuthBoundary>
|
|
21
|
-
* )
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
export declare function AuthBoundary({
|
|
28
|
-
LoginErrorComponent,
|
|
29
|
-
...props
|
|
30
|
-
}: AuthBoundaryProps): React.ReactNode
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @internal
|
|
34
|
-
*/
|
|
35
|
-
declare interface AuthBoundaryProps extends LoginLayoutProps {
|
|
36
|
-
/**
|
|
37
|
-
* Custom component to render the login screen.
|
|
38
|
-
* Receives all login layout props. Defaults to {@link Login}.
|
|
39
|
-
*/
|
|
40
|
-
LoginComponent?: React.ComponentType<LoginLayoutProps>
|
|
41
|
-
/**
|
|
42
|
-
* Custom component to render during OAuth callback processing.
|
|
43
|
-
* Receives all login layout props. Defaults to {@link LoginCallback}.
|
|
44
|
-
*/
|
|
45
|
-
CallbackComponent?: React.ComponentType<LoginLayoutProps>
|
|
46
|
-
/**
|
|
47
|
-
* Custom component to render when authentication errors occur.
|
|
48
|
-
* Receives login layout props and error boundary props. Defaults to
|
|
49
|
-
* {@link LoginError}
|
|
50
|
-
*/
|
|
51
|
-
LoginErrorComponent?: React.ComponentType<LoginErrorProps>
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @alpha
|
|
56
|
-
*/
|
|
57
|
-
declare type LoginErrorProps = FallbackProps & LoginLayoutProps
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @alpha
|
|
61
|
-
*/
|
|
62
|
-
declare interface LoginLayoutProps {
|
|
63
|
-
/** Optional header content rendered at top of card */
|
|
64
|
-
header?: React.ReactNode
|
|
65
|
-
/** Optional footer content rendered below card. Defaults to an internal login footer */
|
|
66
|
-
footer?: React.ReactNode
|
|
67
|
-
/** Main content rendered in card body */
|
|
68
|
-
children?: React.ReactNode
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @public
|
|
73
|
-
*
|
|
74
|
-
* The SanityApp component provides your Sanity application with access to your Sanity configuration,
|
|
75
|
-
* as well as application context and state which is used by the Sanity React hooks. Your application
|
|
76
|
-
* must be wrapped with the SanityApp component to function properly.
|
|
77
|
-
*
|
|
78
|
-
* @param props - Your Sanity configuration and the React children to render
|
|
79
|
-
* @returns Your Sanity application, integrated with your Sanity configuration and application context
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```tsx
|
|
83
|
-
* import { SanityApp } from '@sanity/sdk-react'
|
|
84
|
-
*
|
|
85
|
-
* import MyAppRoot from './Root'
|
|
86
|
-
*
|
|
87
|
-
* // Single project configuration
|
|
88
|
-
* const mySanityConfigs = [
|
|
89
|
-
* {
|
|
90
|
-
* projectId: 'my-project-id',
|
|
91
|
-
* dataset: 'production',
|
|
92
|
-
* },
|
|
93
|
-
* ]
|
|
94
|
-
*
|
|
95
|
-
* // Or multiple project configurations
|
|
96
|
-
* const multipleConfigs = [
|
|
97
|
-
* // Configuration for your main project. This will be used as the default project for all hooks if no resource ID override is provided.
|
|
98
|
-
* {
|
|
99
|
-
* projectId: 'marketing-website-project',
|
|
100
|
-
* dataset: 'production',
|
|
101
|
-
* },
|
|
102
|
-
* // Configuration for a separate blog project
|
|
103
|
-
* {
|
|
104
|
-
* projectId: 'blog-project',
|
|
105
|
-
* dataset: 'production',
|
|
106
|
-
* },
|
|
107
|
-
* // Configuration for a separate ecommerce project
|
|
108
|
-
* {
|
|
109
|
-
* projectId: 'ecommerce-project',
|
|
110
|
-
* dataset: 'production',
|
|
111
|
-
* }
|
|
112
|
-
* ]
|
|
113
|
-
*
|
|
114
|
-
* export default function MyApp() {
|
|
115
|
-
* return (
|
|
116
|
-
* <SanityApp sanityConfigs={mySanityConfigs}>
|
|
117
|
-
* <MyAppRoot />
|
|
118
|
-
* </SanityApp>
|
|
119
|
-
* )
|
|
120
|
-
* }
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
export declare function SanityApp({sanityConfigs, children, fallback}: SanityAppProps): ReactElement
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* @public
|
|
127
|
-
*/
|
|
128
|
-
export declare interface SanityAppProps {
|
|
129
|
-
sanityConfigs: SanityConfig[]
|
|
130
|
-
children: React.ReactNode
|
|
131
|
-
fallback: React.ReactNode
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* @internal
|
|
136
|
-
*
|
|
137
|
-
* Top-level context provider that provides access to the Sanity SDK.
|
|
138
|
-
*/
|
|
139
|
-
export declare function SDKProvider({
|
|
140
|
-
children,
|
|
141
|
-
sanityConfigs,
|
|
142
|
-
fallback,
|
|
143
|
-
}: SDKProviderProps): ReactElement
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* @internal
|
|
147
|
-
*/
|
|
148
|
-
export declare interface SDKProviderProps {
|
|
149
|
-
children: ReactNode
|
|
150
|
-
sanityConfigs: SanityConfig[]
|
|
151
|
-
fallback: ReactNode
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export {}
|