-
Notifications
You must be signed in to change notification settings - Fork 388
/
DocumentPanelHeader.tsx
171 lines (152 loc) · 6.25 KB
/
DocumentPanelHeader.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import {ArrowLeftIcon, CloseIcon, SplitVerticalIcon} from '@sanity/icons'
import {Flex} from '@sanity/ui'
import type * as React from 'react'
import {createElement, forwardRef, memo, useMemo} from 'react'
import {useFieldActions, useTimelineSelector, useTranslation} from 'sanity'
import {Button, TooltipDelayGroupProvider} from '../../../../../ui-components'
import {
PaneContextMenuButton,
PaneHeader,
PaneHeaderActionButton,
usePane,
usePaneRouter,
} from '../../../../components'
import {structureLocaleNamespace} from '../../../../i18n'
import {isMenuNodeButton, isNotMenuNodeButton, resolveMenuNodes} from '../../../../menuNodes'
import {type PaneMenuItem} from '../../../../types'
import {useStructureTool} from '../../../../useStructureTool'
import {TimelineMenu} from '../../timeline'
import {useDocumentPane} from '../../useDocumentPane'
import {DocumentHeaderTabs} from './DocumentHeaderTabs'
import {DocumentHeaderTitle} from './DocumentHeaderTitle'
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DocumentPanelHeaderProps {
menuItems: PaneMenuItem[]
}
export const DocumentPanelHeader = memo(
forwardRef(function DocumentPanelHeader(
_props: DocumentPanelHeaderProps,
ref: React.ForwardedRef<HTMLDivElement>,
) {
const {menuItems} = _props
const {
onMenuAction,
onPaneClose,
onPaneSplit,
menuItemGroups,
schemaType,
timelineStore,
connectionState,
views,
unstable_languageFilter,
} = useDocumentPane()
const {features} = useStructureTool()
const {index, BackLink, hasGroupSiblings} = usePaneRouter()
const {actions: fieldActions} = useFieldActions()
const menuNodes = useMemo(
() =>
resolveMenuNodes({actionHandler: onMenuAction, fieldActions, menuItems, menuItemGroups}),
[onMenuAction, fieldActions, menuItemGroups, menuItems],
)
const menuButtonNodes = useMemo(() => menuNodes.filter(isMenuNodeButton), [menuNodes])
const contextMenuNodes = useMemo(() => menuNodes.filter(isNotMenuNodeButton), [menuNodes])
const showTabs = views.length > 1
// Subscribe to external timeline state changes
const rev = useTimelineSelector(timelineStore, (state) => state.revTime)
const {collapsed, isLast} = usePane()
// Prevent focus if this is the last (non-collapsed) pane.
const tabIndex = isLast && !collapsed ? -1 : 0
// there are three kinds of buttons possible:
//
// 1. split pane - creates a new split pane
// 2. close split pane — closes the current split pane
// 3. close pane group — closes the current pane group
// show the split pane button if they're enabled and there is more than one
// view available to use to create a split view
const showSplitPaneButton = features.splitViews && onPaneSplit && views.length > 1
// show the split pane button close button if the split button is showing
// and there is more than one split pane open (aka has-siblings)
const showSplitPaneCloseButton = showSplitPaneButton && hasGroupSiblings
// show the back button if both the feature is enabled and the current pane
// is not the first
const showBackButton = features.backButton && index > 0
// show the pane group close button if the `showSplitPaneCloseButton` is
// _not_ showing (the split pane button replaces the group close button)
// and if the back button is not showing (the back button and the close
// button do the same thing and shouldn't be shown at the same time)
// and if a BackLink component was provided
const showPaneGroupCloseButton = !showSplitPaneCloseButton && !showBackButton && !!BackLink
const {t} = useTranslation(structureLocaleNamespace)
return (
<TooltipDelayGroupProvider>
<PaneHeader
border
ref={ref}
loading={connectionState === 'connecting'}
title={<DocumentHeaderTitle />}
tabs={showTabs && <DocumentHeaderTabs />}
tabIndex={tabIndex}
backButton={
showBackButton && (
<Button
as={BackLink}
data-as="a"
icon={ArrowLeftIcon}
mode="bleed"
tooltipProps={{content: t('pane-header.back-button.text')}}
/>
)
}
subActions={<TimelineMenu chunk={rev} mode="rev" placement="bottom-end" />}
actions={
<Flex align="center" gap={1}>
{unstable_languageFilter.length > 0 && (
<>
{unstable_languageFilter.map((languageFilterComponent, idx) => {
return createElement(languageFilterComponent, {
// eslint-disable-next-line react/no-array-index-key
key: `language-filter-${idx}`,
schemaType,
})
})}
</>
)}
{menuButtonNodes.map((item) => (
<PaneHeaderActionButton key={item.key} node={item} />
))}
<PaneContextMenuButton nodes={contextMenuNodes} key="context-menu" />
{showSplitPaneButton && (
<Button
aria-label={t('buttons.split-pane-button.aria-label')}
icon={SplitVerticalIcon}
key="split-pane-button"
mode="bleed"
onClick={onPaneSplit}
tooltipProps={{content: t('buttons.split-pane-button.tooltip')}}
/>
)}
{showSplitPaneCloseButton && (
<Button
icon={CloseIcon}
key="close-view-button"
mode="bleed"
onClick={onPaneClose}
tooltipProps={{content: t('buttons.split-pane-close-button.title')}}
/>
)}
{showPaneGroupCloseButton && (
<Button
icon={CloseIcon}
key="close-view-button"
mode="bleed"
tooltipProps={{content: t('buttons.split-pane-close-group-button.title')}}
as={BackLink}
/>
)}
</Flex>
}
/>
</TooltipDelayGroupProvider>
)
}),
)