Skip to content

Commit

Permalink
fix(core): improve tree structure menu
Browse files Browse the repository at this point in the history
  • Loading branch information
hermanwikner committed May 15, 2024
1 parent 0856eef commit 1d1315f
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,38 @@ import {type Path} from 'sanity'
import {TreeEditingMenu} from '../components'
import {type TreeEditingMenuItem} from '../types'

function buildStructure(depth: number): TreeEditingMenuItem[] {
function createItem(level: number): TreeEditingMenuItem {
return {
title: `Level ${level}`,
path: Array.from({length: level}, (_, i) => `level-${i + 1}`),
children: level < depth ? [createItem(level + 1)] : [],
}
}

return [createItem(1)]
}

const ITEMS: TreeEditingMenuItem[] = [
{
title: 'Level 1',
path: ['level-1'],
children: [
{
title: 'Level 1.1',
path: ['level-1', 'level-1.1'],
},
{
title: 'Level 1.2',
path: ['level-1', 'level-1.2'],
},
{
title: 'Level 1.3',
path: ['level-1', 'level-1.3'],
},
],
},
buildStructure(100)[0],
// {
// title: 'Level 1',
// path: ['level-1'],
// children: [
// {
// title: 'Level 1.1',
// path: ['level-1', 'level-1.1'],
// },
// {
// title: 'Level 1.2',
// path: ['level-1', 'level-1.2'],
// },
// {
// title: 'Level 1.3',
// path: ['level-1', 'level-1.3'],
// },
// ],
// },
{
title: 'Level 2',
path: ['level-2'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {useCallback, useEffect, useMemo, useState} from 'react'
import {
FormInput,
type InputProps,
isDev,
type ObjectInputProps,
type ObjectSchemaType,
type Path,
Expand All @@ -26,7 +25,7 @@ import {
import {handleNavigate} from '../utils/handleNavigate'
import {TreeEditingLayout} from './TreeEditingLayout'

const DEBUG_RELATIVE_PATH = isDev
const DEBUG_RELATIVE_PATH = false

const EMPTY_ARRAY: [] = []

Expand All @@ -36,7 +35,7 @@ const ANIMATION_VARIANTS: Variants = {
exit: {opacity: 0},
}

const ANIMATION_TRANSITION: Transition = {duration: 0.15, ease: 'easeInOut'}
const ANIMATION_TRANSITION: Transition = {duration: 0.2, ease: 'easeInOut'}

const DEBOUNCE_SETTINGS: DebounceSettings = {leading: true, trailing: true}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* eslint-disable i18next/no-literal-string */
import {PanelLeftIcon} from '@sanity/icons'
import {Card, Container, Flex, Stack, Text} from '@sanity/ui'
import {AnimatePresence, motion, type Variants} from 'framer-motion'
import {Fragment, memo, type ReactNode, useCallback, useRef, useState} from 'react'
import {type Path, VirtualizerScrollInstanceProvider} from 'sanity'
import styled from 'styled-components'
Expand All @@ -12,6 +13,12 @@ import {TreeEditingBreadcrumbs} from './breadcrumbs'
import {Resizable} from './resizer'
import {TreeEditingMenu} from './TreeEditingMenu'

const ANIMATION_VARIANTS: Variants = {
initial: {opacity: 0},
animate: {opacity: 1},
exit: {opacity: 0},
}

const FixedHeightFlex = styled(Flex).attrs({padding: 2, align: 'center', sizing: 'border'})`
height: 40px;
min-height: 40px;
Expand All @@ -21,7 +28,7 @@ const SidebarCard = styled(Card)`
flex-direction: column;
`

const SidebarStack = styled(Stack)`
const SidebarStack = styled(motion(Stack))`
overflow-x: hidden;
`

Expand Down Expand Up @@ -59,23 +66,33 @@ const Sidebar = memo(function Sidebar(props: SidebarProps) {
/>

{open && (
<Flex>
<Flex flex={1}>
<Text size={1} muted weight="medium" textOverflow="ellipsis">
{title}
</Text>
</Flex>
)}
</FixedHeightFlex>

{open && (
<SidebarStack overflow="auto" padding={3} sizing="border">
<TreeEditingMenu
items={items}
onPathSelect={onPathSelect}
selectedPath={selectedPath}
/>
</SidebarStack>
)}
<AnimatePresence mode="wait">
{open && (
<SidebarStack
animate="animate"
exit="exit"
initial="initial"
overflow="auto"
padding={3}
sizing="border"
variants={ANIMATION_VARIANTS}
>
<TreeEditingMenu
items={items}
onPathSelect={onPathSelect}
selectedPath={selectedPath}
/>
</SidebarStack>
)}
</AnimatePresence>
</SidebarCard>
</ConditionalResizer>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import {ChevronDownIcon, ChevronUpIcon} from '@sanity/icons'
import {Button, Stack} from '@sanity/ui'
import {Box, Button, Flex, Stack, Text} from '@sanity/ui'
import {toString} from '@sanity/util/paths'
import {isEqual} from 'lodash'
import {memo, useCallback, useMemo, useState} from 'react'
import {memo, useCallback, useEffect, useMemo, useState} from 'react'
import {type Path} from 'sanity'

import {type TreeEditingMenuItem} from '../types'

function hasOpenChild(item: TreeEditingMenuItem, selectedPath: Path | null): boolean {
return (
item.children?.some(
(child) =>
child.path.toString() === selectedPath?.toString() || hasOpenChild(child, selectedPath),
(child) => isEqual(child.path, selectedPath) || hasOpenChild(child, selectedPath),
) || false
)
}

const STACK_SPACE = 2

interface TreeEditingMenuItemProps {
// ...
item: TreeEditingMenuItem
onPathSelect: (path: Path) => void
selectedPath: Path | null
Expand All @@ -27,7 +28,7 @@ function MenuItem(props: TreeEditingMenuItemProps) {
const {children, title} = item
const hasChildren = children && children.length > 0
const selected = isEqual(selectedPath, item.path)
const [open, setOpen] = useState<boolean>(hasOpenChild(item, selectedPath))
const [open, setOpen] = useState<boolean>(false)

const handleClick = useCallback(() => {
onPathSelect(item.path)
Expand All @@ -41,22 +42,34 @@ function MenuItem(props: TreeEditingMenuItemProps) {
return open ? <ChevronUpIcon /> : <ChevronDownIcon />
}, [hasChildren, open])

useEffect(() => {
const hasOpen = hasOpenChild(item, selectedPath)

if (hasOpen) {
setOpen(true)
}
}, [item, selectedPath])

return (
<Stack as="li" key={title} space={1}>
<Button
fontSize={1}
iconRight={icon}
justify="space-between"
mode="bleed"
onClick={handleClick}
padding={2}
selected={selected}
text={item.title}
width="fill"
/>
<Stack as="li" key={title} space={STACK_SPACE}>
<Button mode="bleed" onClick={handleClick} padding={2} selected={selected}>
<Flex align="center" justify="space-between" gap={3}>
<Box flex={1}>
<Text size={1} textOverflow="ellipsis" weight={selected ? 'medium' : undefined}>
{title}
</Text>
</Box>

{icon && (
<Text size={0} muted>
{icon}
</Text>
)}
</Flex>
</Button>

{open && hasChildren && (
<Stack as="ul" paddingLeft={3} marginTop={1} space={1}>
<Stack as="ul" paddingLeft={2} space={STACK_SPACE}>
{children.map((child) => (
<MenuItem
item={child}
Expand All @@ -83,11 +96,11 @@ export const TreeEditingMenu = memo(function TreeEditingMenu(
const {items, onPathSelect, selectedPath} = props

return (
<Stack as="ul" space={3}>
{items.map((item, index) => (
<Stack as="ul" space={STACK_SPACE}>
{items.map((item) => (
<MenuItem
item={item}
key={`${item.path.toString()}-${index}`}
key={toString(item.path)}
onPathSelect={onPathSelect}
selectedPath={selectedPath}
/>
Expand Down

0 comments on commit 1d1315f

Please sign in to comment.