diff --git a/package.json b/package.json index 5f606446886..cfdb5257d10 100644 --- a/package.json +++ b/package.json @@ -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/*'", diff --git a/packages/sanity/src/structure/components/paneItem/PaneItem.tsx b/packages/sanity/src/structure/components/paneItem/PaneItem.tsx index ddaa8d220be..d316313a6cd 100644 --- a/packages/sanity/src/structure/components/paneItem/PaneItem.tsx +++ b/packages/sanity/src/structure/components/paneItem/PaneItem.tsx @@ -10,6 +10,7 @@ import { type ComponentType, type MouseEvent, type ReactNode, + startTransition, useCallback, useEffect, useMemo, @@ -22,6 +23,7 @@ import { SanityDefaultPreview, useDocumentPresence, useDocumentPreviewStore, + useEditState, useSchema, } from 'sanity' @@ -124,14 +126,6 @@ export function PaneItem(props: PaneItemProps) { documentPresence, ]) - const Link = useMemo( - () => - function LinkComponent(linkProps: {children: ReactNode}) { - return - }, - [ChildLink, id], - ) - const handleClick = useCallback((e: MouseEvent) => { if (e.metaKey) { setClicked(false) @@ -144,16 +138,26 @@ 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, handleMouseLeave, preload] = usePreloadEditState( + id, + value && isSanityDocument(value) ? schemaType?.name : undefined, + ) + return ( {preview} + {preload} ) } + +function usePreloadEditState( + documentId: string, + documentType: string | undefined, +): [() => void, () => void, ReactNode] { + const [preloading, setPreload] = useState(false) + const handleMouseEnter = useCallback(() => startTransition(() => setPreload(true)), []) + const handleMouseLeave = useCallback(() => startTransition(() => setPreload(false)), []) + + return [ + handleMouseEnter, + handleMouseLeave, + preloading && documentType && ( + + ), + ] as const +} + +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'