Skip to content

Commit

Permalink
fix: preload documents on hover
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan committed Dec 19, 2024
1 parent 67abc06 commit 8a8513a
Showing 1 changed file with 52 additions and 0 deletions.
52 changes: 52 additions & 0 deletions packages/sanity/src/structure/components/paneItem/PaneItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import {
type ComponentType,
type MouseEvent,
type ReactNode,
startTransition,
useCallback,
useEffect,
useMemo,
useReducer,
useState,
} from 'react'
import {
Expand All @@ -22,6 +24,7 @@ import {
SanityDefaultPreview,
useDocumentPresence,
useDocumentPreviewStore,
useEditState,
useSchema,
} from 'sanity'

Expand Down Expand Up @@ -144,6 +147,9 @@ export function PaneItem(props: PaneItemProps) {
// Reset `clicked` state when `selected` prop changes
useEffect(() => setClicked(false), [selected])

// Preloads the edit state on hover, using concurrent rendering with `startTransition` so preloads can be interrupted and not block rendering
const [handleMouseEnter, preload] = usePreloadEditState(id, schemaType?.name)

return (
<PreviewCard
data-testid={`pane-item-${title}`}
Expand All @@ -154,6 +160,7 @@ export function PaneItem(props: PaneItemProps) {
marginBottom={marginBottom}
marginTop={marginTop}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
pressed={pressed}
radius={2}
selected={selected || clicked}
Expand All @@ -162,6 +169,51 @@ export function PaneItem(props: PaneItemProps) {
tone="inherit"
>
{preview}
{preload}
</PreviewCard>
)
}

function usePreloadEditState(
documentId: string,
documentType: string | undefined,
): [() => void, ReactNode] {
const [preloading, preload] = useReducer(() => true, false)
const handleMouseEnter = useCallback(() => startTransition(preload), [])

return [
handleMouseEnter,
preloading && documentType && (
<PreloadDocumentPane documentId={documentId} documentType={documentType} />
),
] as const
}

function PreloadDocumentPane(props: {documentId: string; documentType: string}) {
const {documentId, documentType} = props
const [loading, loaded] = useReducer(() => false, true)
const handleReady = useCallback(() => startTransition(loaded), [])

if (loading) {
return (
<PreloadEditState onReady={handleReady} documentId={documentId} documentType={documentType} />
)
}

return null
}
PreloadDocumentPane.displayName = 'PreloadDocumentPane'

function PreloadEditState(props: {documentId: string; documentType: string; onReady: () => void}) {
const {onReady, documentId, documentType} = props
const editState = useEditState(documentId, documentType)

useEffect(() => {
if (editState.ready) {
onReady()
}
}, [editState.ready, onReady])

return null
}
PreloadEditState.displayName = 'PreloadEditState'

0 comments on commit 8a8513a

Please sign in to comment.