From 735732f6365ddc77b5838ae410f75f09ce71a1b1 Mon Sep 17 00:00:00 2001 From: Herman Wikner Date: Fri, 8 Dec 2023 11:11:40 +0100 Subject: [PATCH] feat(desk): use document layout from Components API --- .../src/desk/panes/document/DocumentPane.tsx | 225 ++--------------- .../panes/document/DocumentPaneContext.ts | 3 - .../panes/document/DocumentPaneProvider.tsx | 106 +------- .../document-layout/DocumentLayout.tsx | 226 ++++++++++++++++++ .../document-layout/DocumentLayoutError.tsx | 64 +++++ .../panes/document/document-layout/index.ts | 2 + .../useDocumentLayoutComponent.ts | 22 ++ .../document/documentPanel/DocumentPanel.tsx | 152 ++++++------ .../header/DocumentPanelHeader.tsx | 11 +- 9 files changed, 420 insertions(+), 391 deletions(-) create mode 100644 packages/sanity/src/desk/panes/document/document-layout/DocumentLayout.tsx create mode 100644 packages/sanity/src/desk/panes/document/document-layout/DocumentLayoutError.tsx create mode 100644 packages/sanity/src/desk/panes/document/document-layout/index.ts create mode 100644 packages/sanity/src/desk/panes/document/document-layout/useDocumentLayoutComponent.ts diff --git a/packages/sanity/src/desk/panes/document/DocumentPane.tsx b/packages/sanity/src/desk/panes/document/DocumentPane.tsx index 8c60a178dc2f..f5dbdb96fed5 100644 --- a/packages/sanity/src/desk/panes/document/DocumentPane.tsx +++ b/packages/sanity/src/desk/panes/document/DocumentPane.tsx @@ -1,69 +1,28 @@ -import { - Card, - Code, - DialogProvider, - DialogProviderProps, - Flex, - PortalProvider, - Stack, - Text, - useElementRect, -} from '@sanity/ui' -import React, {memo, useCallback, useMemo, useState} from 'react' -import styled from 'styled-components' +import {Stack, Text} from '@sanity/ui' +import {memo, useMemo} from 'react' import {fromString as pathFromString} from '@sanity/util/paths' import {Path} from '@sanity/types' import {DocumentPaneNode} from '../../types' -import {Pane, PaneFooter, usePaneRouter} from '../../components' -import {usePaneLayout} from '../../components/pane/usePaneLayout' +import {usePaneRouter} from '../../components' import {ErrorPane} from '../error' import {LoadingPane} from '../loading' -import {DOCUMENT_PANEL_PORTAL_ELEMENT} from '../../constants' -import {DocumentOperationResults} from './DocumentOperationResults' -import {DocumentPaneProvider} from './DocumentPaneProvider' -import {DocumentPanel} from './documentPanel' -import {DocumentActionShortcuts} from './keyboardShortcuts' -import {DocumentStatusBar} from './statusBar' -import {DocumentPaneProviderProps} from './types' -import {useDocumentPane} from './useDocumentPane' -import { - DOCUMENT_INSPECTOR_MIN_WIDTH, - DOCUMENT_PANEL_INITIAL_MIN_WIDTH, - DOCUMENT_PANEL_MIN_WIDTH, -} from './constants' import {structureLocaleNamespace} from '../../i18n' +import {DocumentPaneProviderProps} from './types' +import {DocumentPaneProvider} from './DocumentPaneProvider' +import {useDocumentLayoutComponent} from './document-layout' import { - ChangeConnectorRoot, ReferenceInputOptionsProvider, SourceProvider, - isDev, Translate, useDocumentType, useSource, useTemplatePermissions, useTemplates, useTranslation, - useZIndex, } from 'sanity' -import {CommentsEnabledProvider} from '../../comments' type DocumentPaneOptions = DocumentPaneNode['options'] -const DIALOG_PROVIDER_POSITION: DialogProviderProps['position'] = [ - // We use the `position: fixed` for dialogs on narrower screens (first two media breakpoints). - 'fixed', - 'fixed', - // And we use the `position: absolute` strategy (within panes) on wide screens. - 'absolute', -] - -const StyledChangeConnectorRoot = styled(ChangeConnectorRoot)` - flex: 1; - display: flex; - flex-direction: column; - min-height: 0; - min-width: 0; -` /** * @internal */ @@ -84,6 +43,8 @@ function DocumentPaneInner(props: DocumentPaneProviderProps) { const options = usePaneOptions(pane.options, paneRouter.params) const {documentType, isLoaded: isDocumentLoaded} = useDocumentType(options.id, options.type) + const DocumentLayout = useDocumentLayoutComponent() + // The templates that should be creatable from inside this document pane. // For example, from the "Create new" menu in reference inputs. const templateItems = useMemo(() => { @@ -160,26 +121,24 @@ function DocumentPaneInner(props: DocumentPaneProviderProps) { } return ( - - + {/* NOTE: this is a temporary location for this provider until we */} + {/* stabilize the reference input options formally in the form builder */} + {/* eslint-disable-next-line react/jsx-pascal-case */} + - {/* NOTE: this is a temporary location for this provider until we */} - {/* stabilize the reference input options formally in the form builder */} - {/* eslint-disable-next-line react/jsx-pascal-case */} - - - - - + + + ) } @@ -223,137 +182,3 @@ function mergeDocumentType( }, } } - -function InnerDocumentPane() { - const { - changesOpen, - documentType, - inspector, - inspectOpen, - onFocus, - onPathOpen, - onHistoryOpen, - onKeyUp, - paneKey, - schemaType, - value, - } = useDocumentPane() - const {collapsed: layoutCollapsed} = usePaneLayout() - const zOffsets = useZIndex() - const [rootElement, setRootElement] = useState(null) - const [footerElement, setFooterElement] = useState(null) - const [actionsBoxElement, setActionsBoxElement] = useState(null) - const [documentPanelPortalElement, setDocumentPanelPortalElement] = useState( - null, - ) - const footerRect = useElementRect(footerElement) - const footerH = footerRect?.height - - const onConnectorSetFocus = useCallback( - (path: Path) => { - onPathOpen(path) - onFocus(path) - }, - [onPathOpen, onFocus], - ) - - const currentMinWidth = - DOCUMENT_PANEL_INITIAL_MIN_WIDTH + (inspector ? DOCUMENT_INSPECTOR_MIN_WIDTH : 0) - - const minWidth = DOCUMENT_PANEL_MIN_WIDTH + (inspector ? DOCUMENT_INSPECTOR_MIN_WIDTH : 0) - const {t} = useTranslation(structureLocaleNamespace) - - if (!schemaType) { - return ( - - } - tone="caution" - > - - {documentType && ( - - - - )} - - {!documentType && ( - {t('panes.document-pane.document-unknown-type.without-schema.text')} - )} - - {isDev && value && ( - /* eslint-disable i18next/no-literal-string */ - <> - Here is the JSON representation of the document: - - - {JSON.stringify(value, null, 2)} - - - - /* eslint-enable i18next/no-literal-string */ - )} - - - ) - } - - return ( - - - - - - - - - - {/* These providers are added because we want the dialogs in `DocumentStatusBar` to be scoped to the document pane. */} - {/* The portal element comes from `DocumentPanel`. */} - - - - - - - - - - - ) -} diff --git a/packages/sanity/src/desk/panes/document/DocumentPaneContext.ts b/packages/sanity/src/desk/panes/document/DocumentPaneContext.ts index 29312ad169b5..1d6f34b60224 100644 --- a/packages/sanity/src/desk/panes/document/DocumentPaneContext.ts +++ b/packages/sanity/src/desk/panes/document/DocumentPaneContext.ts @@ -16,7 +16,6 @@ import { DocumentFormNode, DocumentInspector, DocumentLanguageFilterComponent, - DocumentPermission, EditStateFor, PatchEvent, PermissionCheckResult, @@ -47,14 +46,12 @@ export interface DocumentPaneContextValue { inspector: DocumentInspector | null inspectors: DocumentInspector[] menuItemGroups: PaneMenuItemGroup[] - menuItems: PaneMenuItem[] onBlur: (blurredPath: Path) => void onChange: (event: PatchEvent) => void onFocus: (pathOrEvent: Path) => void onHistoryClose: () => void onHistoryOpen: () => void onInspectClose: () => void - onKeyUp: (event: React.KeyboardEvent) => void onMenuAction: (item: PaneMenuItem) => void onPaneClose: () => void onPaneSplit?: () => void diff --git a/packages/sanity/src/desk/panes/document/DocumentPaneProvider.tsx b/packages/sanity/src/desk/panes/document/DocumentPaneProvider.tsx index 9734b019cabf..01685be9ccf9 100644 --- a/packages/sanity/src/desk/panes/document/DocumentPaneProvider.tsx +++ b/packages/sanity/src/desk/panes/document/DocumentPaneProvider.tsx @@ -1,39 +1,30 @@ -import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' +import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' import type {ObjectSchemaType, Path, SanityDocument, SanityDocumentLike} from '@sanity/types' import {omit} from 'lodash' import {useToast} from '@sanity/ui' import {fromString as pathFromString, resolveKeyedPath} from '@sanity/util/paths' -import isHotkey from 'is-hotkey' import {isActionEnabled} from '@sanity/schema/_internal' import {usePaneRouter} from '../../components' import type {PaneMenuItem} from '../../types' import {useDeskTool} from '../../useDeskTool' import {structureLocaleNamespace} from '../../i18n' -import {CommentsProvider, CommentsSelectedPathProvider, useCommentsEnabled} from '../../comments' import {DocumentPaneContext, type DocumentPaneContextValue} from './DocumentPaneContext' -import {getMenuItems} from './menuItems' import type {DocumentPaneProviderProps} from './types' import {usePreviewUrl} from './usePreviewUrl' import {getInitialValueTemplateOpts} from './getInitialValueTemplateOpts' import { - COMMENTS_INSPECTOR_NAME, DEFAULT_MENU_ITEM_GROUPS, EMPTY_PARAMS, HISTORY_INSPECTOR_NAME, INSPECT_ACTION_PREFIX, } from './constants' -import {DocumentInspectorMenuItemsResolver} from './DocumentInspectorMenuItemsResolver' import { type DocumentFieldAction, - type DocumentFieldActionNode, type DocumentInspector, - type DocumentInspectorMenuItem, type DocumentPresence, type PatchEvent, type StateTree, EMPTY_ARRAY, - FieldActionsProvider, - FieldActionsResolver, getDraftId, getExpandOperations, getPublishedId, @@ -114,8 +105,6 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { const value: SanityDocumentLike = editState?.draft || editState?.published || initialValue.value const [isDeleting, setIsDeleting] = useState(false) - const [inspectorMenuItems, setInspectorMenuItems] = useState([]) - // Resolve document actions const actions = useMemo( () => documentActions({schemaType: documentType, documentId}), @@ -220,21 +209,8 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { const changesOpen = currentInspector?.name === HISTORY_INSPECTOR_NAME - const hasValue = Boolean(value) const {t} = useTranslation(structureLocaleNamespace) - const menuItems = useMemo( - () => - getMenuItems({ - currentInspector, - features, - hasValue, - inspectorMenuItems, - inspectors, - previewUrl, - t, - }), - [currentInspector, features, hasValue, inspectorMenuItems, inspectors, previewUrl, t], - ) + const inspectOpen = params.inspect === 'on' const compareValue: Partial | null = changesOpen ? sinceAttributes @@ -473,22 +449,6 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { ], ) - const handleKeyUp = useCallback( - (event: React.KeyboardEvent) => { - for (const item of menuItems) { - if (item.shortcut) { - if (isHotkey(item.shortcut, event)) { - event.preventDefault() - event.stopPropagation() - handleMenuAction(item) - return - } - } - } - }, - [handleMenuAction, menuItems], - ) - const handleLegacyInspectClose = useCallback( () => toggleLegacyInspect(false), [toggleLegacyInspect], @@ -616,7 +576,6 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { focusPath, inspector: currentInspector || null, inspectors, - menuItems, onBlur: handleBlur, onChange: handleChange, onFocus: handleFocus, @@ -624,7 +583,6 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { onHistoryClose: handleHistoryClose, onHistoryOpen: handleHistoryOpen, onInspectClose: handleLegacyInspectClose, - onKeyUp: handleKeyUp, onMenuAction: handleMenuAction, onPaneClose: handlePaneClose, onPaneSplit: handlePaneSplit, @@ -699,66 +657,8 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { return undefined }, [params, documentId, onFocusPath, setOpenPath, ready, paneRouter]) - const [rootFieldActionNodes, setRootFieldActionNodes] = useState([]) - - const commentsEnabled = useCommentsEnabled() - - const handleOpenCommentsInspector = useCallback(() => { - if (currentInspector?.name === COMMENTS_INSPECTOR_NAME) return - - openInspector(COMMENTS_INSPECTOR_NAME) - }, [currentInspector?.name, openInspector]) - - const content = useMemo(() => { - // If comments are not enabled, return children as-is without wrapping in providers - if (!commentsEnabled) return children - - return ( - - {children} - - ) - }, [ - children, - commentsEnabled, - currentInspector?.name, - documentId, - documentType, - handleOpenCommentsInspector, - ]) - return ( - - {inspectors.length > 0 && ( - - )} - - {/* Resolve root-level field actions */} - {fieldActions.length > 0 && schemaType && ( - - )} - - - {content} - - + {children} ) }) diff --git a/packages/sanity/src/desk/panes/document/document-layout/DocumentLayout.tsx b/packages/sanity/src/desk/panes/document/document-layout/DocumentLayout.tsx new file mode 100644 index 000000000000..5a47189f9a1b --- /dev/null +++ b/packages/sanity/src/desk/panes/document/document-layout/DocumentLayout.tsx @@ -0,0 +1,226 @@ +import {useElementRect, DialogProvider, Flex, PortalProvider, DialogProviderProps} from '@sanity/ui' +import {useState, useCallback, useMemo} from 'react' +import {useTranslation} from 'react-i18next' +import {Path} from 'sanity-diff-patch' +import styled from 'styled-components' +import isHotkey from 'is-hotkey' +import {usePaneLayout, Pane, PaneFooter} from '../../../components' +import {DOCUMENT_PANEL_PORTAL_ELEMENT} from '../../../constants' +import {structureLocaleNamespace} from '../../../i18n' +import {useDeskTool} from '../../../useDeskTool' +import {DocumentOperationResults} from '../DocumentOperationResults' +import { + DOCUMENT_PANEL_INITIAL_MIN_WIDTH, + DOCUMENT_INSPECTOR_MIN_WIDTH, + DOCUMENT_PANEL_MIN_WIDTH, +} from '../constants' +import {DocumentPanel} from '../documentPanel' +import {DocumentActionShortcuts} from '../keyboardShortcuts' +import {DocumentStatusBar} from '../statusBar' +import {useDocumentPane} from '../useDocumentPane' +import {DocumentPanelHeader} from '../documentPanel/header' +import {DocumentInspectorMenuItemsResolver} from '../DocumentInspectorMenuItemsResolver' +import {usePreviewUrl} from '../usePreviewUrl' +import {getMenuItems} from '../menuItems' +import {DocumentLayoutError} from './DocumentLayoutError' +import { + DocumentLayoutProps, + useZIndex, + ChangeConnectorRoot, + DocumentInspectorMenuItem, + FieldActionsResolver, + DocumentFieldActionNode, + FieldActionsProvider, +} from 'sanity' + +const EMPTY_ARRAY: [] = [] + +const DIALOG_PROVIDER_POSITION: DialogProviderProps['position'] = [ + // We use the `position: fixed` for dialogs on narrower screens (first two media breakpoints). + 'fixed', + 'fixed', + // And we use the `position: absolute` strategy (within panes) on wide screens. + 'absolute', +] + +const StyledChangeConnectorRoot = styled(ChangeConnectorRoot)` + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + min-width: 0; +` + +export function DocumentLayout() { + const { + changesOpen, + documentId, + documentType, + fieldActions, + inspectOpen, + inspector, + inspectors, + onFocus, + onHistoryOpen, + onMenuAction, + onPathOpen, + paneKey, + schemaType, + value, + } = useDocumentPane() + + const {features} = useDeskTool() + const {t} = useTranslation(structureLocaleNamespace) + const {collapsed: layoutCollapsed} = usePaneLayout() + const zOffsets = useZIndex() + const previewUrl = usePreviewUrl(value) + + const [rootElement, setRootElement] = useState(null) + const [footerElement, setFooterElement] = useState(null) + const [headerElement, setHeaderElement] = useState(null) + + const [actionsBoxElement, setActionsBoxElement] = useState(null) + const [documentPanelPortalElement, setDocumentPanelPortalElement] = useState( + null, + ) + + const [inspectorMenuItems, setInspectorMenuItems] = useState([]) + const [rootFieldActionNodes, setRootFieldActionNodes] = useState([]) + + const footerRect = useElementRect(footerElement) + const headerRect = useElementRect(headerElement) + const footerHeight = footerRect?.height + const headerHeight = headerRect?.height + const currentMinWidth = + DOCUMENT_PANEL_INITIAL_MIN_WIDTH + (inspector ? DOCUMENT_INSPECTOR_MIN_WIDTH : 0) + const minWidth = DOCUMENT_PANEL_MIN_WIDTH + (inspector ? DOCUMENT_INSPECTOR_MIN_WIDTH : 0) + + const currentInspector = useMemo( + () => inspectors?.find((i) => i.name === inspector?.name), + [inspectors, inspector?.name], + ) + + const hasValue = Boolean(value) + + const menuItems = useMemo( + () => + getMenuItems({ + currentInspector, + features, + hasValue, + inspectorMenuItems, + inspectors, + previewUrl, + t, + }), + [currentInspector, features, hasValue, inspectorMenuItems, inspectors, previewUrl, t], + ) + + const handleKeyUp = useCallback( + (event: React.KeyboardEvent) => { + for (const item of menuItems) { + if (item.shortcut) { + if (isHotkey(item.shortcut, event)) { + event.preventDefault() + event.stopPropagation() + onMenuAction(item) + return + } + } + } + }, + [onMenuAction, menuItems], + ) + + const onConnectorSetFocus = useCallback( + (path: Path) => { + onPathOpen(path) + onFocus(path) + }, + [onPathOpen, onFocus], + ) + + if (!schemaType) { + return ( + + ) + } + + return ( + <> + {inspectors.length > 0 && ( + + )} + + {fieldActions.length > 0 && schemaType && ( + + )} + + + + + + + + + + + + + + {/* These providers are added because we want the dialogs in `DocumentStatusBar` to be scoped to the document pane. */} + {/* The portal element comes from `DocumentPanel`. */} + + + + + + + + + + + + ) +} diff --git a/packages/sanity/src/desk/panes/document/document-layout/DocumentLayoutError.tsx b/packages/sanity/src/desk/panes/document/document-layout/DocumentLayoutError.tsx new file mode 100644 index 000000000000..6516c9cd9997 --- /dev/null +++ b/packages/sanity/src/desk/panes/document/document-layout/DocumentLayoutError.tsx @@ -0,0 +1,64 @@ +import {Card, Code, Stack, Text} from '@sanity/ui' +import React from 'react' +import {ErrorPane} from '../../error' +import {Translate, isDev, useTranslation} from 'sanity' + +interface DocumentLayoutErrorProps { + currentMinWidth?: number + documentType?: string + minWidth?: number + paneKey: string + value?: Record +} + +export function DocumentLayoutError(props: DocumentLayoutErrorProps) { + const {documentType, value, currentMinWidth, paneKey, minWidth} = props + const {t} = useTranslation() + + return ( + + } + tone="caution" + > + + {documentType && ( + + + + )} + + {!documentType && ( + {t('panes.document-pane.document-unknown-type.without-schema.text')} + )} + + {isDev && value && ( + /* eslint-disable i18next/no-literal-string */ + <> + Here is the JSON representation of the document: + + + + {JSON.stringify(value, null, 2)} + + + + /* eslint-enable i18next/no-literal-string */ + )} + + + ) +} diff --git a/packages/sanity/src/desk/panes/document/document-layout/index.ts b/packages/sanity/src/desk/panes/document/document-layout/index.ts new file mode 100644 index 000000000000..64577e3cf209 --- /dev/null +++ b/packages/sanity/src/desk/panes/document/document-layout/index.ts @@ -0,0 +1,2 @@ +export * from './DocumentLayout' +export * from './useDocumentLayoutComponent' diff --git a/packages/sanity/src/desk/panes/document/document-layout/useDocumentLayoutComponent.ts b/packages/sanity/src/desk/panes/document/document-layout/useDocumentLayoutComponent.ts new file mode 100644 index 000000000000..b14da163b92e --- /dev/null +++ b/packages/sanity/src/desk/panes/document/document-layout/useDocumentLayoutComponent.ts @@ -0,0 +1,22 @@ +import {ComponentType} from 'react' +import {DocumentLayout} from './DocumentLayout' +import {DocumentLayoutProps, PluginOptions, useMiddlewareComponents} from 'sanity' + +function pick(plugin: PluginOptions) { + return plugin.document?.components?.layout as ComponentType< + Omit + > +} + +/** + * A hook that returns the document layout composed + * by the Components API (`document.components.layout`). + */ +export function useDocumentLayoutComponent(): ComponentType< + Omit +> { + return useMiddlewareComponents({ + pick, + defaultComponent: DocumentLayout, + }) +} diff --git a/packages/sanity/src/desk/panes/document/documentPanel/DocumentPanel.tsx b/packages/sanity/src/desk/panes/document/documentPanel/DocumentPanel.tsx index 8ab96b03d558..99d989c8a194 100644 --- a/packages/sanity/src/desk/panes/document/documentPanel/DocumentPanel.tsx +++ b/packages/sanity/src/desk/panes/document/documentPanel/DocumentPanel.tsx @@ -1,11 +1,4 @@ -import { - BoundaryElementProvider, - Flex, - PortalProvider, - usePortal, - useElementRect, - Box, -} from '@sanity/ui' +import {BoundaryElementProvider, Flex, PortalProvider, usePortal, Box} from '@sanity/ui' import React, {createElement, useEffect, useMemo, useRef, useState} from 'react' import styled, {css} from 'styled-components' import {PaneContent, usePane, usePaneLayout} from '../../../components' @@ -17,13 +10,13 @@ import {DeletedDocumentBanner} from './DeletedDocumentBanner' import {ReferenceChangedBanner} from './ReferenceChangedBanner' import {PermissionCheckBanner} from './PermissionCheckBanner' import {FormView} from './documentViews' -import {DocumentPanelHeader} from './header' import {ScrollContainer, useTimelineSelector, VirtualizerScrollInstanceProvider} from 'sanity' interface DocumentPanelProps { footerHeight: number | null - rootElement: HTMLDivElement | null + headerHeight: number | null isInspectOpen: boolean + rootElement: HTMLDivElement | null setDocumentPanelPortalElement: (el: HTMLElement | null) => void } @@ -46,7 +39,8 @@ const Scroller = styled(ScrollContainer)<{$disabled: boolean}>(({$disabled}) => }) export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { - const {footerHeight, isInspectOpen, rootElement, setDocumentPanelPortalElement} = props + const {footerHeight, headerHeight, isInspectOpen, rootElement, setDocumentPanelPortalElement} = + props const { activeViewId, displayed, @@ -68,8 +62,6 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { const {collapsed} = usePane() const parentPortal = usePortal() const {features} = useDeskTool() - const [headerElement, setHeaderElement] = useState(null) - const headerRect = useElementRect(headerElement) const portalRef = useRef(null) const [documentScrollElement, setDocumentScrollElement] = useState(null) const formContainerElement = useRef(null) @@ -95,11 +87,11 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { // Calculate the height of the header const margins: [number, number, number, number] = useMemo(() => { if (layoutCollapsed) { - return [headerRect?.height || 0, 0, footerHeight ? footerHeight + 2 : 2, 0] + return [headerHeight || 0, 0, footerHeight ? footerHeight + 2 : 2, 0] } return [0, 0, 2, 0] - }, [layoutCollapsed, footerHeight, headerRect]) + }, [layoutCollapsed, footerHeight, headerHeight]) const formViewHidden = activeView.type !== 'form' @@ -146,73 +138,69 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { const showInspector = Boolean(!collapsed && inspector) return ( - <> - - - - - {(features.resizablePanes || !showInspector) && ( - - - - - {activeView.type === 'form' && !isPermissionsLoading && ready && ( - <> - - {!isDeleting && isDeleted && ( - - )} - - - )} - - - - - {inspectDialog} - -
- - - - - )} - - {showInspector && ( - - - - )} - - - + {!isDeleting && isDeleted && ( + + )} + + + )} + + + + + {inspectDialog} + +
+ + + + + )} + + {showInspector && ( + + + + )} + + ) } diff --git a/packages/sanity/src/desk/panes/document/documentPanel/header/DocumentPanelHeader.tsx b/packages/sanity/src/desk/panes/document/documentPanel/header/DocumentPanelHeader.tsx index d192a8869b1e..f3f959a3ae9d 100644 --- a/packages/sanity/src/desk/panes/document/documentPanel/header/DocumentPanelHeader.tsx +++ b/packages/sanity/src/desk/panes/document/documentPanel/header/DocumentPanelHeader.tsx @@ -12,24 +12,27 @@ import {TimelineMenu} from '../../timeline' import {useDocumentPane} from '../../useDocumentPane' import {isMenuNodeButton, isNotMenuNodeButton, resolveMenuNodes} from '../../../../menuNodes' import {useDeskTool} from '../../../../useDeskTool' +import {structureLocaleNamespace} from '../../../../i18n' +import {PaneMenuItem} from '../../../../types' import {DocumentHeaderTabs} from './DocumentHeaderTabs' import {DocumentHeaderTitle} from './DocumentHeaderTitle' -import {structureLocaleNamespace} from '../../../../i18n' import {useFieldActions, useTimelineSelector, useTranslation} from 'sanity' // eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface DocumentPanelHeaderProps {} +export interface DocumentPanelHeaderProps { + menuItems: PaneMenuItem[] +} export const DocumentPanelHeader = memo( forwardRef(function DocumentPanelHeader( _props: DocumentPanelHeaderProps, ref: React.ForwardedRef, ) { + const {menuItems} = _props const { onMenuAction, onPaneClose, onPaneSplit, - menuItems, menuItemGroups, schemaType, timelineStore, @@ -40,11 +43,13 @@ export const DocumentPanelHeader = memo( const {features} = useDeskTool() 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