@sanity/sdk-react 0.0.0-alpha.3 → 0.0.0-alpha.5

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 (64) hide show
  1. package/README.md +78 -28
  2. package/dist/_chunks-es/context.js +8 -0
  3. package/dist/_chunks-es/context.js.map +1 -0
  4. package/dist/_chunks-es/useLogOut.js +11 -11
  5. package/dist/_chunks-es/useLogOut.js.map +1 -1
  6. package/dist/components.d.ts +11 -186
  7. package/dist/components.js +52 -198
  8. package/dist/components.js.map +1 -1
  9. package/dist/context.d.ts +39 -0
  10. package/dist/context.js +5 -0
  11. package/dist/context.js.map +1 -0
  12. package/dist/hooks.d.ts +201 -15
  13. package/dist/hooks.js +80 -11
  14. package/dist/hooks.js.map +1 -1
  15. package/package.json +17 -15
  16. package/src/_exports/components.ts +2 -13
  17. package/src/_exports/context.ts +2 -0
  18. package/src/_exports/hooks.ts +18 -2
  19. package/src/components/SanityApp.test.tsx +54 -0
  20. package/src/components/SanityApp.tsx +26 -0
  21. package/src/components/auth/AuthBoundary.test.tsx +5 -18
  22. package/src/components/auth/AuthBoundary.tsx +2 -2
  23. package/src/components/auth/Login.test.tsx +3 -17
  24. package/src/components/auth/Login.tsx +25 -16
  25. package/src/components/auth/LoginCallback.test.tsx +2 -17
  26. package/src/components/auth/LoginCallback.tsx +6 -4
  27. package/src/components/auth/LoginError.test.tsx +2 -17
  28. package/src/components/auth/LoginError.tsx +8 -12
  29. package/src/components/auth/LoginFooter.test.tsx +2 -16
  30. package/src/components/auth/LoginFooter.tsx +11 -18
  31. package/src/components/auth/LoginLayout.test.tsx +2 -16
  32. package/src/components/auth/LoginLayout.tsx +8 -19
  33. package/src/components/auth/authTestHelpers.tsx +18 -0
  34. package/src/{components/context → context}/SanityProvider.test.tsx +1 -1
  35. package/src/hooks/client/useClient.test.tsx +1 -1
  36. package/src/hooks/comlink/useFrameConnection.test.tsx +122 -0
  37. package/src/hooks/comlink/useFrameConnection.ts +111 -0
  38. package/src/hooks/comlink/useWindowConnection.test.ts +94 -0
  39. package/src/hooks/comlink/useWindowConnection.ts +82 -0
  40. package/src/hooks/context/useSanityInstance.test.tsx +1 -1
  41. package/src/hooks/context/useSanityInstance.ts +2 -2
  42. package/src/hooks/documentCollection/useDocuments.ts +53 -6
  43. package/src/hooks/helpers/createCallbackHook.tsx +1 -1
  44. package/src/hooks/helpers/createStateSourceHook.tsx +1 -1
  45. package/src/hooks/preview/usePreview.test.tsx +17 -8
  46. package/src/hooks/preview/usePreview.tsx +52 -7
  47. package/src/vite-env.d.ts +10 -0
  48. package/dist/assets/bundle-CcAyERuZ.css +0 -11
  49. package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +0 -113
  50. package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +0 -42
  51. package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +0 -21
  52. package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +0 -105
  53. package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +0 -42
  54. package/src/components/DocumentListLayout/DocumentListLayout.tsx +0 -12
  55. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +0 -49
  56. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +0 -39
  57. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +0 -30
  58. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +0 -171
  59. package/src/components/Login/LoginLinks.test.tsx +0 -100
  60. package/src/components/Login/LoginLinks.tsx +0 -73
  61. package/src/css/css.config.js +0 -220
  62. package/src/css/paramour.css +0 -2347
  63. package/src/css/styles.css +0 -11
  64. /package/src/{components/context → context}/SanityProvider.tsx +0 -0
@@ -0,0 +1,111 @@
1
+ import {
2
+ type FrameMessage,
3
+ getOrCreateChannel,
4
+ getOrCreateController,
5
+ releaseChannel,
6
+ type WindowMessage,
7
+ } from '@sanity/sdk'
8
+ import {useCallback, useEffect, useMemo} from 'react'
9
+
10
+ import {useSanityInstance} from '../context/useSanityInstance'
11
+
12
+ /**
13
+ * @public
14
+ */
15
+ export type FrameMessageHandler<TWindowMessage extends WindowMessage> = (
16
+ event: TWindowMessage['data'],
17
+ ) => TWindowMessage['response'] | Promise<TWindowMessage['response']>
18
+
19
+ /**
20
+ * @public
21
+ */
22
+ export interface UseFrameConnectionOptions<TWindowMessage extends WindowMessage> {
23
+ name: string
24
+ connectTo: string
25
+ targetOrigin: string
26
+ onMessage?: Record<string, FrameMessageHandler<TWindowMessage>>
27
+ }
28
+
29
+ /**
30
+ * @public
31
+ */
32
+ export interface FrameConnection<TFrameMessage extends FrameMessage> {
33
+ connect: (frameWindow: Window) => () => void // Return cleanup function
34
+ sendMessage: <T extends TFrameMessage['type']>(
35
+ ...params: Extract<TFrameMessage, {type: T}>['data'] extends undefined
36
+ ? [type: T]
37
+ : [type: T, data: Extract<TFrameMessage, {type: T}>['data']]
38
+ ) => void
39
+ }
40
+
41
+ /**
42
+ * @public
43
+ */
44
+ export function useFrameConnection<
45
+ TFrameMessage extends FrameMessage,
46
+ TWindowMessage extends WindowMessage,
47
+ >(options: UseFrameConnectionOptions<TWindowMessage>): FrameConnection<TFrameMessage> {
48
+ const {onMessage, targetOrigin, name, connectTo} = options
49
+ const instance = useSanityInstance()
50
+
51
+ const controller = useMemo(
52
+ () => getOrCreateController(instance, targetOrigin),
53
+ [instance, targetOrigin],
54
+ )
55
+
56
+ const channel = useMemo(
57
+ () =>
58
+ getOrCreateChannel(instance, {
59
+ name,
60
+ connectTo,
61
+ }),
62
+ [instance, name, connectTo],
63
+ )
64
+
65
+ useEffect(() => {
66
+ if (!channel || !onMessage) return
67
+
68
+ const unsubscribers: Array<() => void> = []
69
+
70
+ Object.entries(onMessage).forEach(([type, handler]) => {
71
+ const unsubscribe = channel.on(type, handler)
72
+ unsubscribers.push(unsubscribe)
73
+ })
74
+
75
+ return () => {
76
+ unsubscribers.forEach((unsub) => unsub())
77
+ }
78
+ }, [channel, onMessage])
79
+
80
+ const connect = useCallback(
81
+ (frameWindow: Window) => {
82
+ const removeTarget = controller?.addTarget(frameWindow)
83
+ return () => {
84
+ removeTarget?.()
85
+ }
86
+ },
87
+ [controller],
88
+ )
89
+
90
+ const sendMessage = useCallback(
91
+ <T extends TFrameMessage['type']>(
92
+ type: T,
93
+ data?: Extract<TFrameMessage, {type: T}>['data'],
94
+ ) => {
95
+ channel?.post(type, data)
96
+ },
97
+ [channel],
98
+ )
99
+
100
+ // cleanup channel on unmount
101
+ useEffect(() => {
102
+ return () => {
103
+ releaseChannel(instance, name)
104
+ }
105
+ }, [name, instance])
106
+
107
+ return {
108
+ connect,
109
+ sendMessage,
110
+ }
111
+ }
@@ -0,0 +1,94 @@
1
+ import {type Message, type Node} from '@sanity/comlink'
2
+ import {getOrCreateNode, releaseNode} from '@sanity/sdk'
3
+ import {beforeEach, describe, expect, it, vi} from 'vitest'
4
+
5
+ import {renderHook} from '../../../test/test-utils'
6
+ import {useWindowConnection} from './useWindowConnection'
7
+
8
+ vi.mock(import('@sanity/sdk'), async (importOriginal) => {
9
+ const actual = await importOriginal()
10
+ return {
11
+ ...actual,
12
+ getOrCreateNode: vi.fn(),
13
+ createNode: vi.fn(),
14
+ releaseNode: vi.fn(),
15
+ }
16
+ })
17
+ interface TestMessage {
18
+ type: 'TEST_MESSAGE'
19
+ data: {someData: string}
20
+ }
21
+
22
+ interface AnotherMessage {
23
+ type: 'ANOTHER_MESSAGE'
24
+ data: {otherData: number}
25
+ }
26
+
27
+ type TestMessages = TestMessage | AnotherMessage
28
+
29
+ function createMockNode() {
30
+ return {
31
+ // return unsubscribe function
32
+ on: vi.fn(() => () => {}),
33
+ post: vi.fn(),
34
+ stop: vi.fn(),
35
+ } as unknown as Node<Message, Message>
36
+ }
37
+
38
+ describe('useWindowConnection', () => {
39
+ let node: Node<Message, Message>
40
+
41
+ beforeEach(() => {
42
+ node = createMockNode()
43
+
44
+ vi.mocked(getOrCreateNode).mockReturnValue(node as unknown as Node<Message, Message>)
45
+ })
46
+
47
+ it('should register message handlers', () => {
48
+ const mockHandler = vi.fn()
49
+ const mockData = {someData: 'test'}
50
+
51
+ renderHook(() =>
52
+ useWindowConnection<TestMessages, TestMessages>({
53
+ name: 'test',
54
+ connectTo: 'window',
55
+ onMessage: {
56
+ TEST_MESSAGE: mockHandler,
57
+ ANOTHER_MESSAGE: vi.fn(),
58
+ },
59
+ }),
60
+ )
61
+
62
+ const onCallback = vi.mocked(node.on).mock.calls[0][1]
63
+ onCallback(mockData)
64
+
65
+ expect(mockHandler).toHaveBeenCalledWith(mockData)
66
+ })
67
+
68
+ it('should send messages through the node', () => {
69
+ const {result} = renderHook(() =>
70
+ useWindowConnection<TestMessages, TestMessages>({
71
+ name: 'test',
72
+ connectTo: 'window',
73
+ }),
74
+ )
75
+
76
+ result.current.sendMessage('TEST_MESSAGE', {someData: 'test'})
77
+ expect(node.post).toHaveBeenCalledWith('TEST_MESSAGE', {someData: 'test'})
78
+
79
+ result.current.sendMessage('ANOTHER_MESSAGE', {otherData: 123})
80
+ expect(node.post).toHaveBeenCalledWith('ANOTHER_MESSAGE', {otherData: 123})
81
+ })
82
+
83
+ it('should cleanup on unmount', () => {
84
+ const {unmount} = renderHook(() =>
85
+ useWindowConnection<TestMessages, TestMessages>({
86
+ name: 'test',
87
+ connectTo: 'window',
88
+ }),
89
+ )
90
+
91
+ unmount()
92
+ expect(releaseNode).toHaveBeenCalled()
93
+ })
94
+ })
@@ -0,0 +1,82 @@
1
+ import {type FrameMessage, getOrCreateNode, releaseNode, type WindowMessage} from '@sanity/sdk'
2
+ import {useCallback, useEffect, useMemo} from 'react'
3
+
4
+ import {useSanityInstance} from '../context/useSanityInstance'
5
+
6
+ /**
7
+ * @public
8
+ */
9
+ export type WindowMessageHandler<TFrameMessage extends FrameMessage> = (
10
+ event: TFrameMessage['data'],
11
+ ) => TFrameMessage['response']
12
+
13
+ /**
14
+ * @public
15
+ */
16
+ export interface UseWindowConnectionOptions<TMessage extends FrameMessage> {
17
+ name: string
18
+ connectTo: string
19
+ onMessage?: Record<TMessage['type'], WindowMessageHandler<TMessage>>
20
+ }
21
+
22
+ /**
23
+ * @public
24
+ */
25
+ export interface WindowConnection<TMessage extends WindowMessage> {
26
+ sendMessage: <TType extends TMessage['type']>(
27
+ type: TType,
28
+ data?: Extract<TMessage, {type: TType}>['data'],
29
+ ) => void
30
+ }
31
+
32
+ /**
33
+ * @public
34
+ */
35
+ export function useWindowConnection<
36
+ TWindowMessage extends WindowMessage,
37
+ TFrameMessage extends FrameMessage,
38
+ >(options: UseWindowConnectionOptions<TFrameMessage>): WindowConnection<TWindowMessage> {
39
+ const {name, onMessage, connectTo} = options
40
+ const instance = useSanityInstance()
41
+
42
+ const node = useMemo(
43
+ () => getOrCreateNode(instance, {name, connectTo}),
44
+ [instance, name, connectTo],
45
+ )
46
+
47
+ useEffect(() => {
48
+ if (!onMessage) return
49
+
50
+ const unsubscribers: Array<() => void> = []
51
+
52
+ Object.entries(onMessage).forEach(([type, handler]) => {
53
+ const unsubscribe = node.on(type, handler as WindowMessageHandler<TFrameMessage>)
54
+ unsubscribers.push(unsubscribe)
55
+ })
56
+
57
+ return () => {
58
+ unsubscribers.forEach((unsub) => unsub())
59
+ }
60
+ }, [node, onMessage])
61
+
62
+ const sendMessage = useCallback(
63
+ <TType extends WindowMessage['type']>(
64
+ type: TType,
65
+ data?: Extract<WindowMessage, {type: TType}>['data'],
66
+ ) => {
67
+ node?.post(type, data)
68
+ },
69
+ [node],
70
+ )
71
+
72
+ // cleanup node on unmount
73
+ useEffect(() => {
74
+ return () => {
75
+ releaseNode(instance, name)
76
+ }
77
+ }, [instance, name])
78
+
79
+ return {
80
+ sendMessage,
81
+ }
82
+ }
@@ -3,7 +3,7 @@ import {renderHook} from '@testing-library/react'
3
3
  import React from 'react'
4
4
  import {describe, expect, it, vi} from 'vitest'
5
5
 
6
- import {SanityProvider} from '../../components/context/SanityProvider'
6
+ import {SanityProvider} from '../../context/SanityProvider'
7
7
  import {useSanityInstance} from './useSanityInstance'
8
8
 
9
9
  describe('useSanityInstance', () => {
@@ -1,7 +1,7 @@
1
- import type {SanityInstance} from '@sanity/sdk'
1
+ import {type SanityInstance} from '@sanity/sdk'
2
2
  import {useContext} from 'react'
3
3
 
4
- import {SanityInstanceContext} from '../../components/context/SanityProvider'
4
+ import {SanityInstanceContext} from '../../context/SanityProvider'
5
5
 
6
6
  /**
7
7
  * Hook that provides the current Sanity instance from the context.
@@ -6,11 +6,16 @@ import {useSanityInstance} from '../context/useSanityInstance'
6
6
  /**
7
7
  * @public
8
8
  */
9
- export interface UseDocuments {
9
+ export interface DocumentCollection {
10
+ /** Retrieve more documents matching the provided options */
10
11
  loadMore: () => void
12
+ /** The retrieved document handles of the documents matching the provided options */
11
13
  results: DocumentHandle[]
14
+ /** Whether a retrieval of documents is in flight */
12
15
  isPending: boolean
16
+ /** Whether more documents exist that match the provided options than have been retrieved */
13
17
  hasMore: boolean
18
+ /** The total number of documents in the collection */
14
19
  count: number
15
20
  }
16
21
 
@@ -24,14 +29,56 @@ const STABLE_EMPTY = {
24
29
  }
25
30
 
26
31
  /**
27
- * Hook to get the list of documents for specified options
28
- *
29
32
  * @public
30
33
  *
31
- * @param options - options for the document list
32
- * @returns result of the document list and function to load more
34
+ * The `useDocuments` hook retrieves and provides access to a live collection of documents, optionally filtered, sorted, and matched to a given Content Lake perspective.
35
+ * Because the returned document collection is live, the results will update in real time until the component invoking the hook is unmounted.
36
+ *
37
+ * @param options - Options for narrowing and sorting the document collection
38
+ * @returns The collection of documents matching the provided options (if any), as well as properties describing the collection and a function to load more.
39
+ *
40
+ * @example Retrieving all documents of type 'movie'
41
+ * ```
42
+ * const { results, isPending } = useDocuments({ filter: '_type == "movie"' })
43
+ *
44
+ * return (
45
+ * <div>
46
+ * <h1>Movies</h1>
47
+ * {results && (
48
+ * <ul>
49
+ * {results.map(movie => (<li key={movie._id}>…</li>))}
50
+ * </ul>
51
+ * )}
52
+ * {isPending && <div>Loading movies…</div>}
53
+ * </div>
54
+ * )
55
+ * ```
56
+ *
57
+ * @example Retrieving all movies released since 1980, sorted by release date
58
+ * ```
59
+ * const { results } = useDocuments({
60
+ * filter: '_type == "movie" && releaseDate >= "1980-01-01"',
61
+ * sort: [
62
+ * {
63
+ * field: 'releaseDate',
64
+ * sort: 'asc',
65
+ * },
66
+ * ],
67
+ * })
68
+ *
69
+ * return (
70
+ * <div>
71
+ * <h1>Movies released since 1980</h1>
72
+ * {results && (
73
+ * <ol>
74
+ * {results.map(movie => (<li key={movie._id}>…</li>))}
75
+ * </ol>
76
+ * )}
77
+ * </div>
78
+ * )
79
+ * ```
33
80
  */
34
- export function useDocuments(options: DocumentListOptions = {}): UseDocuments {
81
+ export function useDocuments(options: DocumentListOptions = {}): DocumentCollection {
35
82
  const instance = useSanityInstance()
36
83
 
37
84
  // NOTE: useState is used because it guaranteed to return a stable reference
@@ -1,4 +1,4 @@
1
- import type {SanityInstance} from '@sanity/sdk'
1
+ import {type SanityInstance} from '@sanity/sdk'
2
2
  import {useCallback} from 'react'
3
3
 
4
4
  import {useSanityInstance} from '../context/useSanityInstance'
@@ -1,4 +1,4 @@
1
- import type {SanityInstance, StateSource} from '@sanity/sdk'
1
+ import {type SanityInstance, type StateSource} from '@sanity/sdk'
2
2
  import {useMemo, useSyncExternalStore} from 'react'
3
3
 
4
4
  import {useSanityInstance} from '../context/useSanityInstance'
@@ -1,7 +1,7 @@
1
1
  import {type DocumentHandle, getPreviewState, type PreviewValue, resolvePreview} from '@sanity/sdk'
2
2
  import {act, render, screen} from '@testing-library/react'
3
3
  import {Suspense, useState} from 'react'
4
- import type {Mock} from 'vitest'
4
+ import {type Mock} from 'vitest'
5
5
 
6
6
  import {usePreview} from './usePreview'
7
7
 
@@ -45,13 +45,13 @@ const mockDocument: DocumentHandle = {
45
45
 
46
46
  function TestComponent({document}: {document: DocumentHandle}) {
47
47
  const [ref, setRef] = useState<HTMLElement | null>(null)
48
- const [previewValue, pending] = usePreview({document, ref})
48
+ const {results, isPending} = usePreview({document, ref})
49
49
 
50
50
  return (
51
51
  <div ref={setRef}>
52
- <h1>{previewValue.title}</h1>
53
- <p>{previewValue.subtitle}</p>
54
- {pending && <div>Pending...</div>}
52
+ <h1>{results?.title}</h1>
53
+ <p>{results?.subtitle}</p>
54
+ {isPending && <div>Pending...</div>}
55
55
  </div>
56
56
  )
57
57
  }
@@ -74,7 +74,10 @@ describe('usePreview', () => {
74
74
 
75
75
  test('it only subscribes when element is visible', async () => {
76
76
  // Setup initial state
77
- getCurrent.mockReturnValue([{title: 'Initial Title', subtitle: 'Initial Subtitle'}, false])
77
+ getCurrent.mockReturnValue({
78
+ results: {title: 'Initial Title', subtitle: 'Initial Subtitle'},
79
+ isPending: false,
80
+ })
78
81
  const eventsUnsubscribe = vi.fn()
79
82
  subscribe.mockImplementation(() => eventsUnsubscribe)
80
83
 
@@ -135,7 +138,10 @@ describe('usePreview', () => {
135
138
  await act(async () => {
136
139
  intersectionObserverCallback([{isIntersecting: true} as IntersectionObserverEntry])
137
140
  await resolvePromise
138
- getCurrent.mockReturnValue([{title: 'Resolved Title', subtitle: 'Resolved Subtitle'}, false])
141
+ getCurrent.mockReturnValue({
142
+ results: {title: 'Resolved Title', subtitle: 'Resolved Subtitle'},
143
+ isPending: false,
144
+ })
139
145
  subscriber?.()
140
146
  })
141
147
 
@@ -149,7 +155,10 @@ describe('usePreview', () => {
149
155
  // @ts-expect-error - Intentionally removing IntersectionObserver
150
156
  delete window.IntersectionObserver
151
157
 
152
- getCurrent.mockReturnValue([{title: 'Fallback Title', subtitle: 'Fallback Subtitle'}, false])
158
+ getCurrent.mockReturnValue({
159
+ results: {title: 'Fallback Title', subtitle: 'Fallback Subtitle'},
160
+ isPending: false,
161
+ })
153
162
  subscribe.mockImplementation(() => vi.fn())
154
163
 
155
164
  render(
@@ -15,10 +15,55 @@ export interface UsePreviewOptions {
15
15
  /**
16
16
  * @alpha
17
17
  */
18
- export function usePreview({
19
- document: {_id, _type},
20
- ref,
21
- }: UsePreviewOptions): [PreviewValue, boolean] {
18
+ export interface UsePreviewResults {
19
+ /** The results of resolving the document’s preview values */
20
+ results: PreviewValue
21
+ /** Whether the resolution of the preview values is pending */
22
+ isPending: boolean
23
+ }
24
+
25
+ /**
26
+ * @alpha
27
+ *
28
+ * The `usePreview` hook takes a document (via a `DocumentHandle`) and returns its resolved preview values,
29
+ * including the document’s `title`, `subtitle`, `media`, and `status`. These values are live and will update in realtime.
30
+ * To reduce unnecessary network requests for resolving the preview values, an optional `ref` can be passed to the hook so that preview
31
+ * resolution will only occur if the `ref` is intersecting the current viewport.
32
+ *
33
+ * @param options - The document handle for the document you want to resolve preview values for, and an optional ref
34
+ * @returns The preview values for the given document and a boolean to indicate whether the resolution is pending
35
+ *
36
+ * @example Combining with useDocuments to render a collection of document previews
37
+ * ```
38
+ * // PreviewComponent.jsx
39
+ * export default function PreviewComponent({ document }) {
40
+ * const { results: { title, subtitle, media }, isPending } = usePreview({ document })
41
+ * return isPending ? 'Loading…' : (
42
+ * <article>
43
+ * {media?.type === 'image-asset' ? <img src={media.url} alt='' /> : ''}
44
+ * <h2>{title}</h2>
45
+ * <p>{subtitle}</p>
46
+ * </article>
47
+ * )
48
+ * }
49
+ *
50
+ * // DocumentList.jsx
51
+ * const { results, isPending } = useDocuments({ filter: '_type == "movie"' })
52
+ * return (
53
+ * <div>
54
+ * <h1>Movies</h1>
55
+ * <ul>
56
+ * {isPending ? 'Loading…' : results.map(movie => (
57
+ * <li key={movie._id}>
58
+ * <PreviewComponent document={movie} />
59
+ * </li>
60
+ * ))}
61
+ * </ul>
62
+ * </div>
63
+ * )
64
+ * ```
65
+ */
66
+ export function usePreview({document: {_id, _type}, ref}: UsePreviewOptions): UsePreviewResults {
22
67
  const instance = useSanityInstance()
23
68
 
24
69
  const stateSource = useMemo(
@@ -60,9 +105,9 @@ export function usePreview({
60
105
 
61
106
  // Create getSnapshot function to return current state
62
107
  const getSnapshot = useCallback(() => {
63
- const previewTuple = stateSource.getCurrent()
64
- if (!previewTuple[0]) throw resolvePreview(instance, {document: {_id, _type}})
65
- return previewTuple as [PreviewValue, boolean]
108
+ const currentState = stateSource.getCurrent()
109
+ if (currentState.results === null) throw resolvePreview(instance, {document: {_id, _type}})
110
+ return currentState as UsePreviewResults
66
111
  }, [_id, _type, instance, stateSource])
67
112
 
68
113
  return useSyncExternalStore(subscribe, getSnapshot)
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="vite/types/importMeta.d.ts" />
3
+
4
+ interface ImportMetaEnv {
5
+ DEV: boolean
6
+ }
7
+
8
+ interface ImportMeta {
9
+ readonly env: ImportMetaEnv
10
+ }
@@ -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,113 +0,0 @@
1
- import {type Meta, type StoryObj} from '@storybook/react'
2
-
3
- import {DocumentPreviewLayout} from '../DocumentPreviewLayout/DocumentPreviewLayout.tsx'
4
- import {DocumentGridLayout} from './DocumentGridLayout.tsx'
5
-
6
- const meta: Meta<typeof DocumentGridLayout> = {
7
- title: 'DocumentGridLayout',
8
- component: DocumentGridLayout,
9
- }
10
-
11
- export default meta
12
- type Story = StoryObj<typeof meta>
13
-
14
- const mockDocs = [
15
- {id: '1', title: 'Just a title', url: '#', docType: 'article', status: 'published'},
16
- {
17
- id: '2',
18
- title: 'A title, but also',
19
- subtitle: 'A subtitle',
20
- docType: 'article',
21
- status: 'draft',
22
- media: {
23
- type: 'image-asset',
24
- url: 'https://picsum.photos/75/75',
25
- },
26
- },
27
- {
28
- id: '3',
29
- title: 'Hello World',
30
- subtitle: 'What a nice list I get to live in',
31
- docType: 'image',
32
- status: 'published',
33
- media: {
34
- type: 'image-asset',
35
- url: 'https://picsum.photos/80/80',
36
- },
37
- },
38
- {
39
- id: '4',
40
- title: 'I’ve been selected',
41
- subtitle: 'I feel special',
42
- selected: true,
43
- docType: 'video',
44
- status: 'draft',
45
- media: {
46
- type: 'image-asset',
47
- url: 'https://picsum.photos/100/100',
48
- },
49
- },
50
- {
51
- id: '5',
52
- title: 'A very long title that at some point might get truncated if it goes for long enough',
53
- subtitle:
54
- 'Along with a subtitle that is quite long as well, in order to demonstrate the truncation of its text',
55
- docType: 'audio',
56
- status: 'published',
57
- media: {
58
- type: 'image-asset',
59
- url: 'https://picsum.photos/75/75',
60
- },
61
- },
62
- {
63
- id: '6',
64
- title: 'Hello World',
65
- subtitle: 'What a nice list I get to live in',
66
- docType: 'pdf',
67
- status: 'published',
68
- media: {
69
- type: 'image-asset',
70
- url: 'https://picsum.photos/75/75',
71
- },
72
- },
73
- {id: '7', title: 'Just a title', url: '#', docType: 'note', status: 'published,'},
74
- {
75
- id: '8',
76
- title: 'A title, but also',
77
- subtitle: 'A subtitle',
78
- docType: 'document',
79
- status: 'draft',
80
- },
81
- {
82
- id: '9',
83
- title: 'Hello World',
84
- subtitle: 'What a nice list I get to live in',
85
- docType: 'biography',
86
- status: 'published',
87
- media: {
88
- type: 'image-asset',
89
- url: 'https://picsum.photos/200/200',
90
- },
91
- },
92
- ]
93
-
94
- export const Default: Story = {
95
- render: () => {
96
- return (
97
- <DocumentGridLayout>
98
- {mockDocs.map((doc) => (
99
- <li key={doc.id}>
100
- <DocumentPreviewLayout
101
- title={doc.title}
102
- subtitle={doc.subtitle}
103
- media={doc.media}
104
- selected={doc.selected}
105
- docType={doc.docType}
106
- status={doc.status}
107
- />
108
- </li>
109
- ))}
110
- </DocumentGridLayout>
111
- )
112
- },
113
- }