-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
298 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
/* eslint-disable no-process-env */ | ||
export const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET! | ||
// eslint-disable-next-line no-process-env | ||
export const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import {memo, useEffect} from 'react' | ||
|
||
import {type PreviewSubscriptionProps, PreviewSubscription} from './PreviewSubscription' | ||
import {PreviewSubscriptionWithToken} from './PreviewSubscriptionWithToken' | ||
import {useAuthenticated} from './useAuthenticated' | ||
|
||
export interface PreviewModeProps extends PreviewSubscriptionProps { | ||
authMode: 'dual' | 'token' | 'cookie' | ||
onAuth: (authState: 'token' | 'cookie' | 'failed') => void | ||
} | ||
const PreviewModeComponent = ({authMode, onAuth, ...props}: PreviewModeProps) => { | ||
const {projectId, token} = props | ||
const authState = useAuthenticated({projectId, authMode, token}) | ||
|
||
useEffect(() => { | ||
if (onAuth && authState !== 'checking') { | ||
onAuth(authState) | ||
} | ||
}, [authState, onAuth]) | ||
|
||
if (authState === 'failed' && !onAuth) { | ||
throw new Error('Failed to authenticate, provide an onAuth callback to silence this error') | ||
} | ||
|
||
switch (authState) { | ||
case 'checking': | ||
case 'failed': | ||
return null | ||
case 'token': | ||
return !props.EventSource && props.token ? ( | ||
<PreviewSubscriptionWithToken {...props} token={props.token!} /> | ||
) : ( | ||
<PreviewSubscription {...props} /> | ||
) | ||
case 'cookie': | ||
return <PreviewSubscription {...props} /> | ||
default: | ||
throw new Error(`Unknown auth state: ${authState}`) | ||
} | ||
} | ||
|
||
export const PreviewMode = memo(PreviewModeComponent) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,18 @@ | ||
import {groqStore} from '@sanity/groq-store' | ||
import EventSource from 'eventsource' | ||
import { | ||
type Dispatch, | ||
type SetStateAction, | ||
type TransitionStartFunction, | ||
memo, | ||
useEffect, | ||
useMemo, | ||
} from 'react' | ||
import {memo, useEffect} from 'react' | ||
import {unstable_batchedUpdates} from 'react-dom' | ||
import type {GroqStoreEventSource} from 'src/types' | ||
import {useSyncExternalStore} from 'use-sync-external-store/shim' | ||
|
||
export type Params = Record<string, unknown> | ||
import {type SyncGroqStoreHookProps, useSyncGroqStore} from './useSyncGroqStore' | ||
|
||
export interface PreviewSubscriptionProps { | ||
// required stuff | ||
setData: Dispatch<SetStateAction<any[]>> | ||
initialData: any | ||
projectId: string | ||
dataset: string | ||
query: string | ||
// optional stuff | ||
params?: Params | ||
documentLimit?: number | ||
startTransition?: TransitionStartFunction | ||
// Both or neither | ||
// @TODO setup typing that enforce this condition | ||
token?: string | ||
EventSource?: GroqStoreEventSource | ||
export interface PreviewSubscriptionProps extends SyncGroqStoreHookProps { | ||
onChange: (data: any) => void | ||
} | ||
function PreviewSubscriptionComponent(props: PreviewSubscriptionProps) { | ||
console.log('PreviewSubscription', props, groqStore) | ||
|
||
const forwardedProps = useMemo(() => { | ||
return props.token && !props.EventSource ? {...props, EventSource} : props | ||
}, [props]) | ||
const data = useSyncGroqStore(forwardedProps) | ||
console.log('sync data', data) | ||
|
||
const {setData, startTransition = unstable_batchedUpdates} = props | ||
const PreviewSubscriptionComponent = ({onChange, ...props}: PreviewSubscriptionProps) => { | ||
const data = useSyncGroqStore(props) | ||
useEffect(() => { | ||
console.count('data changed', data) | ||
startTransition(() => setData(data)) | ||
}, [data, setData]) | ||
unstable_batchedUpdates(() => onChange(data)) | ||
}, [data, onChange]) | ||
|
||
return null | ||
} | ||
|
||
export const PreviewSubscription = memo(PreviewSubscriptionComponent) | ||
|
||
type SyncGroqStore = { | ||
getSnapshot: () => any | ||
getServerSnapshot: () => any | ||
subscribe: (onStoreChange: () => void) => () => void | ||
} | ||
|
||
const useGroqStore = (props: PreviewSubscriptionProps): SyncGroqStore => { | ||
const {initialData, projectId, dataset, documentLimit, token, EventSource, params, query} = | ||
props | ||
return useMemo<SyncGroqStore>(() => { | ||
let snapshot: any = initialData | ||
return { | ||
getSnapshot: () => snapshot, | ||
subscribe: (onStoreChange: () => void) => { | ||
console.log('subscribe', props) | ||
const store = groqStore({ | ||
projectId, | ||
dataset, | ||
documentLimit, | ||
token, | ||
EventSource, | ||
listen: true, | ||
overlayDrafts: true, | ||
subscriptionThrottleMs: 1, | ||
}) | ||
const subscription = store.subscribe(query, params as any, (err, result) => { | ||
if (err) { | ||
throw err | ||
} else { | ||
snapshot = result | ||
onStoreChange() | ||
} | ||
}) | ||
|
||
return () => subscription.unsubscribe() | ||
}, | ||
} | ||
}, [EventSource, dataset, documentLimit, initialData, params, projectId, props, query, token]) | ||
} | ||
|
||
const useSyncGroqStore = (props: PreviewSubscriptionProps) => { | ||
const store = useGroqStore(props) | ||
return useSyncExternalStore(store.subscribe, store.getSnapshot) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import EventSource from 'eventsource' | ||
import {memo} from 'react' | ||
|
||
import {type PreviewSubscriptionProps, PreviewSubscription} from './PreviewSubscription' | ||
|
||
// EventSource is a very chonky boi, that's why this is in a separate component | ||
// eslint-disable-next-line no-warning-comments | ||
// @TODO implement code-splitting and lazy loading for this component | ||
|
||
export interface PreviewSubscriptionWithTokenProps | ||
// EventSource is provided by this component, if you're providing it then just use PreviewSubscription directly | ||
extends Omit<PreviewSubscriptionProps, 'EventSource' | 'token'> { | ||
token: string | ||
} | ||
const PreviewSubscriptionWithTokenComponent = ({ | ||
token, | ||
...props | ||
}: PreviewSubscriptionWithTokenProps) => { | ||
if (!token) { | ||
throw new TypeError('token is required') | ||
} | ||
|
||
return <PreviewSubscription {...props} token={token} EventSource={EventSource} /> | ||
} | ||
|
||
export const PreviewSubscriptionWithToken = memo(PreviewSubscriptionWithTokenComponent) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,9 @@ | ||
import {PreviewSubscription} from './PreviewSubscription' | ||
import {PreviewMode} from './PreviewMode' | ||
|
||
export default PreviewSubscription | ||
export default PreviewMode | ||
export * from './PreviewMode' | ||
export * from './PreviewSubscription' | ||
export * from './PreviewSubscriptionWithToken' | ||
export * from './useAuthenticated' | ||
export * from './useGroqStore' | ||
export * from './useSyncGroqStore' |
Oops, something went wrong.