-
Notifications
You must be signed in to change notification settings - Fork 446
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
22 changed files
with
1,537 additions
and
424 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
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
14 changes: 14 additions & 0 deletions
14
packages/sanity/src/core/diffView/components/DialogLayout.ts
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,14 @@ | ||
import {styled} from 'styled-components' | ||
|
||
export const DialogLayout = styled.div` | ||
--offset-block: 40px; | ||
display: grid; | ||
height: calc(100vh - var(--offset-block)); | ||
min-height: 0; | ||
overflow: hidden; | ||
grid-template-areas: | ||
'header header' | ||
'previous-document next-document'; | ||
grid-template-columns: 1fr 1fr; | ||
grid-template-rows: min-content minmax(0, 1fr); | ||
` |
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,58 @@ | ||
import {type ComponentType, useState} from 'react' | ||
|
||
import {Dialog} from '../../../ui-components/dialog/Dialog' | ||
import {type DocumentLayoutProps} from '../../config/types' | ||
import {useCreatePathSyncChannel} from '../hooks/useCreatePathSyncChannel' | ||
import {useDiffViewRouter} from '../hooks/useDiffViewRouter' | ||
import {useDiffViewState} from '../hooks/useDiffViewState' | ||
import {useScrollMirror} from '../hooks/useScrollMirror' | ||
import {VersionModeHeader} from '../versionMode/components/VersionModeHeader' | ||
import {DialogLayout} from './DialogLayout' | ||
import {DiffViewPane} from './DiffViewPane' | ||
|
||
export const DiffView: ComponentType<Pick<DocumentLayoutProps, 'documentId'>> = ({documentId}) => { | ||
const {documents, state, mode} = useDiffViewState() | ||
const {exitDiffView} = useDiffViewRouter() | ||
const syncChannel = useCreatePathSyncChannel() | ||
const [previousPaneElement, setPreviousPaneElement] = useState<HTMLElement | null>(null) | ||
const [nextPaneElement, setNextPaneElement] = useState<HTMLElement | null>(null) | ||
|
||
useScrollMirror([previousPaneElement, nextPaneElement]) | ||
|
||
return ( | ||
<Dialog | ||
id="diffView" | ||
width="auto" | ||
onClose={exitDiffView} | ||
padding={false} | ||
__unstable_hideCloseButton | ||
> | ||
<DialogLayout> | ||
{mode === 'version' && <VersionModeHeader documentId={documentId} state={state} />} | ||
{state === 'ready' && ( | ||
<> | ||
<DiffViewPane | ||
documentType={documents.previous.type} | ||
documentId={documents.previous.id} | ||
role="previous" | ||
ref={setPreviousPaneElement} | ||
scrollElement={previousPaneElement} | ||
syncChannel={syncChannel} | ||
compareDocument={documents.previous} | ||
/> | ||
<DiffViewPane | ||
documentType={documents.next.type} | ||
documentId={documents.next.id} | ||
role="next" | ||
ref={setNextPaneElement} | ||
scrollElement={nextPaneElement} | ||
syncChannel={syncChannel} | ||
// The previous document's edit state is used to calculate the diff inroduced by the next document. | ||
compareDocument={documents.previous} | ||
/> | ||
</> | ||
)} | ||
</DialogLayout> | ||
</Dialog> | ||
) | ||
} |
136 changes: 136 additions & 0 deletions
136
packages/sanity/src/core/diffView/components/DiffViewPane.tsx
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,136 @@ | ||
import {BoundaryElementProvider, Box, Card, DialogProvider, PortalProvider} from '@sanity/ui' | ||
import {noop} from 'lodash' | ||
import {type CSSProperties, forwardRef, useRef, useState} from 'react' | ||
import {ConnectorContext} from 'sanity/_singletons' | ||
import {DocumentPaneProvider, FormViewComponent} from 'sanity/structure' | ||
import {styled} from 'styled-components' | ||
|
||
import {ChangeIndicatorsTracker} from '../../changeIndicators/tracker' | ||
import {VirtualizerScrollInstanceProvider} from '../../form/inputs/arrays/ArrayOfObjectsInput/List/VirtualizerScrollInstanceProvider' | ||
import {useEditState} from '../../hooks/useEditState' | ||
import {getPublishedId, getVersionFromId, isDraftId} from '../../util/draftUtils' | ||
import {type PathSyncChannel} from '../types/pathSyncChannel' | ||
import {PathSyncChannelSubscriber} from './PathSyncChannelSubscriber' | ||
import {Scroller} from './Scroller' | ||
|
||
const DiffViewPaneLayout = styled(Card)` | ||
position: relative; | ||
grid-area: var(--grid-area); | ||
` | ||
|
||
interface DiffViewPaneProps { | ||
documentType: string | ||
documentId: string | ||
role: 'previous' | 'next' | ||
scrollElement: HTMLElement | null | ||
syncChannel: PathSyncChannel | ||
compareDocument: { | ||
type: string | ||
id: string | ||
} | ||
} | ||
|
||
// TODO: Switch off comments. Document inspectors cannot currently be shown inside the diff view. | ||
// TODO: Switch off references pane. It should be a hyperlink instead. | ||
export const DiffViewPane = forwardRef<HTMLDivElement, DiffViewPaneProps>(function DiffViewPane( | ||
{role, documentType, documentId, scrollElement, syncChannel, /*compareValue,*/ compareDocument}, | ||
ref, | ||
) { | ||
const paneId = ['diffView', role].join('.') | ||
|
||
const version: 'draft' | 'published' | string = isDraftId(documentId) | ||
? 'draft' | ||
: (getVersionFromId(documentId) ?? 'published') | ||
|
||
const publishedVersionId = getPublishedId(documentId) | ||
const containerElement = useRef<HTMLDivElement | null>(null) | ||
const [portalElement, setPortalElement] = useState<HTMLDivElement | null>(null) | ||
const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null) | ||
|
||
const compareDocumentEditState = useEditState( | ||
getPublishedId(compareDocument.id), | ||
compareDocument.type, | ||
'low', | ||
getVersionFromId(compareDocument.id), | ||
) | ||
|
||
const compareValue = | ||
compareDocumentEditState.version ?? | ||
compareDocumentEditState.draft ?? | ||
compareDocumentEditState.published ?? | ||
{} | ||
|
||
return ( | ||
<ConnectorContext.Provider | ||
value={{ | ||
// Only display change indicators in the next document pane. | ||
isEnabled: role === 'next', | ||
// Render the change indicators inertly, because the diff view modal does not currently | ||
// provide a way to display document inspectors. | ||
isInteractive: false, | ||
onOpenReviewChanges: noop, | ||
onSetFocus: noop, | ||
isReviewChangesOpen: false, | ||
}} | ||
> | ||
<ChangeIndicatorsTracker> | ||
<VirtualizerScrollInstanceProvider | ||
scrollElement={scrollElement} | ||
containerElement={containerElement} | ||
> | ||
<BoundaryElementProvider element={boundaryElement}> | ||
<DiffViewPaneLayout | ||
ref={setBoundaryElement} | ||
style={ | ||
{ | ||
'--grid-area': `${role}-document`, | ||
} as CSSProperties | ||
} | ||
borderLeft={role === 'next'} | ||
> | ||
<Scroller | ||
ref={ref} | ||
style={ | ||
{ | ||
// The scroll position is synchronised between panes. This style hides the | ||
// scrollbar for all panes except the one displaying the next document. | ||
'--scrollbar-width': role !== 'next' && 'none', | ||
} as CSSProperties | ||
} | ||
> | ||
<DocumentPaneProvider | ||
index={0} | ||
paneKey={paneId} | ||
itemId={paneId} | ||
perspectiveOverride={version} | ||
pane={{ | ||
id: paneId, | ||
type: 'document', | ||
// Providing a falsey value allows the title to be computed automatically based | ||
// on the document's values. | ||
title: '', | ||
options: { | ||
type: documentType, | ||
id: publishedVersionId, | ||
}, | ||
}} | ||
compareValue={compareValue} | ||
> | ||
<PortalProvider element={portalElement}> | ||
<DialogProvider position="absolute"> | ||
<PathSyncChannelSubscriber id={role} syncChannel={syncChannel} /> | ||
<Box ref={containerElement}> | ||
<FormViewComponent hidden={false} margins={[0, 0, 0, 0]} /> | ||
</Box> | ||
</DialogProvider> | ||
</PortalProvider> | ||
</DocumentPaneProvider> | ||
</Scroller> | ||
<div data-testid="diffView-document-panel-portal" ref={setPortalElement} /> | ||
</DiffViewPaneLayout> | ||
</BoundaryElementProvider> | ||
</VirtualizerScrollInstanceProvider> | ||
</ChangeIndicatorsTracker> | ||
</ConnectorContext.Provider> | ||
) | ||
}) |
9 changes: 9 additions & 0 deletions
9
packages/sanity/src/core/diffView/components/PathSyncChannelSubscriber.ts
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,9 @@ | ||
import {type ComponentType} from 'react' | ||
|
||
import {usePathSyncChannel} from '../hooks/usePathSyncChannel' | ||
import {type PathSyncChannelProps} from '../types/pathSyncChannel' | ||
|
||
export const PathSyncChannelSubscriber: ComponentType<PathSyncChannelProps> = (props) => { | ||
usePathSyncChannel(props) | ||
return undefined | ||
} |
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,11 @@ | ||
import {styled} from 'styled-components' | ||
|
||
export const Scroller = styled.div` | ||
position: relative; | ||
height: 100%; | ||
overflow: auto; | ||
scroll-behavior: smooth; | ||
scrollbar-width: var(--scrollbar-width); | ||
overscroll-behavior: contain; | ||
will-change: scroll-position; | ||
` |
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,20 @@ | ||
/** | ||
* @internal | ||
*/ | ||
export const DIFF_VIEW_SEARCH_PARAMETER = 'diffView' | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const DIFF_VIEW_PREVIOUS_DOCUMENT_SEARCH_PARAMETER = 'previousDocument' | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const DIFF_VIEW_NEXT_DOCUMENT_SEARCH_PARAMETER = 'nextDocument' | ||
|
||
/** | ||
* @internal | ||
* TODO: Gets encoded to `%3B`. Consider another character. | ||
*/ | ||
export const DIFF_SEARCH_PARAM_SEPERATOR = ';' |
11 changes: 11 additions & 0 deletions
11
packages/sanity/src/core/diffView/hooks/useCreatePathSyncChannel.ts
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,11 @@ | ||
import {useMemo} from 'react' | ||
import {Subject} from 'rxjs' | ||
|
||
import {type PathSyncChannel, type PathSyncState} from '../types/pathSyncChannel' | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export function useCreatePathSyncChannel(): PathSyncChannel { | ||
return useMemo(() => new Subject<PathSyncState>(), []) | ||
} |
93 changes: 93 additions & 0 deletions
93
packages/sanity/src/core/diffView/hooks/useDiffViewRouter.ts
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,93 @@ | ||
import {fromPairs, toPairs} from 'lodash' | ||
import {useCallback} from 'react' | ||
import {useRouter} from 'sanity/router' | ||
|
||
import { | ||
DIFF_SEARCH_PARAM_SEPERATOR, | ||
DIFF_VIEW_NEXT_DOCUMENT_SEARCH_PARAMETER, | ||
DIFF_VIEW_PREVIOUS_DOCUMENT_SEARCH_PARAMETER, | ||
DIFF_VIEW_SEARCH_PARAMETER, | ||
} from '../constants' | ||
import {type DiffViewMode} from '../types/diffViewMode' | ||
|
||
type NavigateDiffView = ( | ||
options: { | ||
mode?: DiffViewMode | ||
} & Partial< | ||
Record< | ||
'previousDocument' | 'nextDocument', | ||
{ | ||
type: string | ||
id: string | ||
} | ||
> | ||
>, | ||
) => void | ||
|
||
interface DiffViewRouter { | ||
navigateDiffView: NavigateDiffView | ||
exitDiffView: () => void | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export function useDiffViewRouter(): DiffViewRouter { | ||
const {navigate, state: routerState} = useRouter() | ||
|
||
const navigateDiffView = useCallback<NavigateDiffView>( | ||
({mode, previousDocument, nextDocument}) => { | ||
const next = { | ||
...fromPairs(routerState._searchParams), | ||
...(mode | ||
? { | ||
[DIFF_VIEW_SEARCH_PARAMETER]: mode, | ||
} | ||
: {}), | ||
...(previousDocument | ||
? { | ||
[DIFF_VIEW_PREVIOUS_DOCUMENT_SEARCH_PARAMETER]: [ | ||
previousDocument.type, | ||
previousDocument.id, | ||
].join(DIFF_SEARCH_PARAM_SEPERATOR), | ||
} | ||
: {}), | ||
...(nextDocument | ||
? { | ||
[DIFF_VIEW_NEXT_DOCUMENT_SEARCH_PARAMETER]: [nextDocument.type, nextDocument.id].join( | ||
DIFF_SEARCH_PARAM_SEPERATOR, | ||
), | ||
} | ||
: {}), | ||
} | ||
|
||
// FIXME: Sticky params (e.g. `perspective`) are being lost here SOMETIMES. | ||
// ok here: http://localhost:3333/test/structure/input-debug;objectsDebug;7c71b8b7-8b6c-47a0-a6ca-e691776e8bbc?perspective=rF1jtvjXP | ||
// lost here: http://localhost:3333/test/structure/book;5c80b890-badc-482b-a656-3adcc2ed75f7?perspective=rCj1fA9MW | ||
navigate({ | ||
...routerState, | ||
_searchParams: toPairs(next), | ||
}) | ||
}, | ||
[navigate, routerState], | ||
) | ||
|
||
const exitDiffView = useCallback(() => { | ||
navigate({ | ||
...routerState, | ||
_searchParams: (routerState._searchParams ?? []).filter( | ||
([key]) => | ||
![ | ||
DIFF_VIEW_SEARCH_PARAMETER, | ||
DIFF_VIEW_PREVIOUS_DOCUMENT_SEARCH_PARAMETER, | ||
DIFF_VIEW_NEXT_DOCUMENT_SEARCH_PARAMETER, | ||
].includes(key), | ||
), | ||
}) | ||
}, [navigate, routerState]) | ||
|
||
return { | ||
navigateDiffView, | ||
exitDiffView, | ||
} | ||
} |
Oops, something went wrong.