Skip to content

Commit

Permalink
fix: preload documents on hover (#8110)
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan authored and binoy14 committed Dec 20, 2024
1 parent 8f61ce3 commit 303841d
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"check:deps": "pnpm --recursive --parallel exec depcheck",
"check:format": "prettier . --check",
"check:lint": "turbo run lint --continue -- --quiet",
"check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 27 .",
"check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 26 .",
"report:react-compiler-bailout": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [error,{__unstable_donotuse_reportAllBailouts:true}]' --ignore-path .eslintignore.react-compiler -f ./scripts/reactCompilerBailouts.cjs . || true",
"check:test": "run-s test -- --silent",
"check:types": "tsc && turbo run check:types --filter='./packages/*' --filter='./packages/@sanity/*'",
Expand Down
4 changes: 2 additions & 2 deletions packages/sanity/src/structure/components/pane/Pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
type HTMLProps,
type ReactNode,
useCallback,
useEffect,
useImperativeHandle,
useLayoutEffect,
useMemo,
useRef,
useState,
Expand Down Expand Up @@ -89,7 +89,7 @@ export const Pane = forwardRef(function Pane(
ref.current = refValue
}, [])

useEffect(() => {
useLayoutEffect(() => {
if (!rootElement) return undefined
return mount(rootElement, {
currentMinWidth: currentMinWidthProp,
Expand Down
41 changes: 31 additions & 10 deletions packages/sanity/src/structure/components/paneItem/PaneItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {Box, type CardProps, Text} from '@sanity/ui'
import {
type ComponentType,
type MouseEvent,
type ReactNode,
startTransition,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import {
Expand All @@ -22,6 +23,7 @@ import {
SanityDefaultPreview,
useDocumentPresence,
useDocumentPreviewStore,
useEditState,
useSchema,
} from 'sanity'

Expand Down Expand Up @@ -124,14 +126,6 @@ export function PaneItem(props: PaneItemProps) {
documentPresence,
])

const Link = useMemo(
() =>
function LinkComponent(linkProps: {children: ReactNode}) {
return <ChildLink {...linkProps} childId={id} />
},
[ChildLink, id],
)

const handleClick = useCallback((e: MouseEvent<HTMLElement>) => {
if (e.metaKey) {
setClicked(false)
Expand All @@ -144,16 +138,31 @@ 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 [preloading, setPreload] = useState(false)
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const handleMouseEnter = useCallback(() => {
timeoutRef.current = setTimeout(() => startTransition(() => setPreload(true)), 400)
}, [])
const handleMouseLeave = useCallback(() => {
if (timeoutRef.current) clearTimeout(timeoutRef.current)
startTransition(() => setPreload(false))
}, [])

return (
<PreviewCard
data-testid={`pane-item-${title}`}
__unstable_focusRing
as={Link as FIXME}
as={ChildLink as FIXME}
// @ts-expect-error - `childId` is a valid prop on `ChildLink`
childId={id}
data-as="a"
margin={margin}
marginBottom={marginBottom}
marginTop={marginTop}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
pressed={pressed}
radius={2}
selected={selected || clicked}
Expand All @@ -162,6 +171,18 @@ export function PaneItem(props: PaneItemProps) {
tone="inherit"
>
{preview}
{preloading && schemaType?.name && value && isSanityDocument(value) && (
<PreloadDocumentPane documentId={id} documentType={schemaType.name} />
)}
</PreviewCard>
)
}

function PreloadDocumentPane(props: {documentId: string; documentType: string}) {
const {documentId, documentType} = props
// Preload the edit state for the document, and keep it alive until mouse leave
useEditState(documentId, documentType)

return null
}
PreloadDocumentPane.displayName = 'PreloadDocumentPane'

0 comments on commit 303841d

Please sign in to comment.