-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from Q42/feature/page-tree-input-component
Page tree input component
- Loading branch information
Showing
4 changed files
with
145 additions
and
103 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
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,119 @@ | ||
import { Stack, Flex, Spinner, Card, Dialog, Box, Text } from '@sanity/ui'; | ||
import { useMemo, useState } from 'react'; | ||
import { ReferenceValue, set, useFormValue, SanityDocument, ObjectInputProps } from 'sanity'; | ||
import styled from 'styled-components'; | ||
|
||
import { PageTreeEditor } from './PageTreeEditor'; | ||
import { findPageTreeItemById, flatMapPageTree } from '../helpers/page-tree'; | ||
import { useOptimisticState } from '../hooks/useOptimisticState'; | ||
import { usePageTree } from '../hooks/usePageTree'; | ||
import { PageTreeConfigProvider } from '../hooks/usePageTreeConfig'; | ||
import { PageTreeConfig, PageTreeItem } from '../types'; | ||
import { getSanityDocumentId } from '../utils/sanity'; | ||
|
||
export const PageTreeInput = ( | ||
props: ObjectInputProps<ReferenceValue> & { | ||
config: PageTreeConfig; | ||
mode?: 'select-parent' | 'select-page'; | ||
schemaType: { to?: { name: string }[] }; | ||
}, | ||
) => { | ||
const mode = props.mode ?? 'select-page'; | ||
const form = useFormValue([]) as SanityDocument; | ||
const { pageTree } = usePageTree(props.config); | ||
|
||
const allowedPageTypes = props.schemaType.to?.map(t => t.name); | ||
|
||
const [isPageTreeDialogOpen, setIsPageTreeDialogOpen] = useState(false); | ||
|
||
const parentId = props.value?._ref; | ||
const pageId = getSanityDocumentId(form._id); | ||
|
||
const fieldPage = useMemo(() => (pageTree ? findPageTreeItemById(pageTree, pageId) : undefined), [pageTree, pageId]); | ||
const parentPage = useMemo( | ||
() => (pageTree && parentId ? findPageTreeItemById(pageTree, parentId) : undefined), | ||
[pageTree, parentId], | ||
); | ||
|
||
const flatFieldPages = useMemo(() => (fieldPage ? flatMapPageTree([fieldPage]) : []), [fieldPage]); | ||
|
||
const [parentPath, setOptimisticParentPath] = useOptimisticState<string | undefined>(parentPage?.path); | ||
|
||
// Some page tree items are not suitable options for a new parent reference. | ||
// Disable the current parent page, the current page and all of its children. | ||
const disabledParentIds = | ||
mode !== 'select-parent' ? [] : [...(parentId ? [parentId] : []), ...flatFieldPages.map(page => page._id)]; | ||
// Initially open the current page and all of its parents | ||
const openItemIds = fieldPage?._id ? [fieldPage?._id] : undefined; | ||
|
||
const openDialog = () => { | ||
setIsPageTreeDialogOpen(true); | ||
}; | ||
|
||
const closeDialog = () => { | ||
setIsPageTreeDialogOpen(false); | ||
}; | ||
|
||
const selectParentPage = (page: PageTreeItem) => { | ||
// In the case of an array of references, we need to find the last path in the array and extract the _key | ||
const lastPath = props.path[props.path.length - 1]; | ||
const _key = typeof lastPath === 'object' && '_key' in lastPath ? lastPath._key : undefined; | ||
|
||
props.onChange( | ||
set({ | ||
...(_key ? { _key } : {}), | ||
_ref: page._id, | ||
_type: 'reference', | ||
_weak: page.isDraft, | ||
...(page.isDraft ? { _strengthenOnPublish: { type: page._type } } : {}), | ||
}), | ||
); | ||
setOptimisticParentPath(page.path); | ||
closeDialog(); | ||
}; | ||
|
||
return ( | ||
<PageTreeConfigProvider config={props.config}> | ||
<Stack space={3}> | ||
{!pageTree ? ( | ||
<Flex paddingY={4} justify="center" align="center"> | ||
<Spinner /> | ||
</Flex> | ||
) : ( | ||
<Card padding={1} shadow={1} radius={2}> | ||
<SelectedItemCard padding={3} radius={2} onClick={openDialog}> | ||
<Text size={2}>{parentId ? parentPath ?? 'Select page' : 'Select page'}</Text> | ||
</SelectedItemCard> | ||
</Card> | ||
)} | ||
</Stack> | ||
{pageTree && isPageTreeDialogOpen && ( | ||
<Dialog | ||
header={'Select page'} | ||
id="parent-page-tree" | ||
zOffset={1000} | ||
width={1} | ||
onClose={closeDialog} | ||
onClickOutside={closeDialog}> | ||
<Box padding={4}> | ||
<PageTreeEditor | ||
allowedPageTypes={allowedPageTypes} | ||
pageTree={pageTree} | ||
onItemClick={selectParentPage} | ||
disabledItemIds={disabledParentIds} | ||
initialOpenItemIds={openItemIds} | ||
/> | ||
</Box> | ||
</Dialog> | ||
)} | ||
</PageTreeConfigProvider> | ||
); | ||
}; | ||
|
||
const SelectedItemCard = styled(Card)` | ||
cursor: pointer; | ||
&:hover { | ||
background-color: ${({ theme }) => theme.sanity.color.card.hovered.bg}; | ||
} | ||
`; |
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