diff --git a/src/components/PrimaryWindow.js b/src/components/PrimaryWindow.js index 4d6344b3acb3f692e6a0511697751016ebeadb03..30c4d302eb4e9794fc9c9b73e318c02a24e78982 100644 --- a/src/components/PrimaryWindow.js +++ b/src/components/PrimaryWindow.js @@ -1,6 +1,7 @@ import { Component, lazy, Suspense } from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; +import classNames from 'classnames'; import WindowSideBar from '../containers/WindowSideBar'; import CompanionArea from '../containers/CompanionArea'; import CollectionDialog from '../containers/CollectionDialog'; @@ -16,7 +17,7 @@ GalleryView.displayName = 'GalleryView'; SelectCollection.displayName = 'SelectCollection'; WindowViewer.displayName = 'WindowViewer'; -const StyledPrimaryWindowContainer = styled('div')(() => ({ +const Root = styled('div', { name: 'PrimaryWindow', slot: 'root' })(() => ({ display: 'flex', flex: 1, position: 'relative', @@ -80,17 +81,18 @@ export class PrimaryWindow extends Component { */ render() { const { - isCollectionDialogVisible, windowId, children, + isCollectionDialogVisible, windowId, children, className, } = this.props; + return ( - <StyledPrimaryWindowContainer data-testid="test-window" className={ns('primary-window')}> + <Root data-testid="test-window" className={classNames(ns('primary-window'), className)}> <WindowSideBar windowId={windowId} /> <CompanionArea windowId={windowId} position="left" /> { isCollectionDialogVisible && <CollectionDialog windowId={windowId} /> } <Suspense fallback={<div />}> {children || this.renderViewer()} </Suspense> - </StyledPrimaryWindowContainer> + </Root> ); } } @@ -98,6 +100,7 @@ export class PrimaryWindow extends Component { PrimaryWindow.propTypes = { audioResources: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types children: PropTypes.node, + className: PropTypes.string, isCollection: PropTypes.bool, isCollectionDialogVisible: PropTypes.bool, isFetching: PropTypes.bool, @@ -109,6 +112,7 @@ PrimaryWindow.propTypes = { PrimaryWindow.defaultProps = { audioResources: [], children: undefined, + className: undefined, isCollection: false, isCollectionDialogVisible: false, isFetching: false, diff --git a/src/components/Window.js b/src/components/Window.js index c2f6b3a5bb0527e3e68e77432bea9290c3c1ce10..2d654afd6937ed777e0e5c408b0efb8373c9fd1e 100644 --- a/src/components/Window.js +++ b/src/components/Window.js @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import { Component, useContext } from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; import Paper from '@mui/material/Paper'; @@ -12,13 +12,25 @@ import ErrorContent from '../containers/ErrorContent'; import IIIFAuthentication from '../containers/IIIFAuthentication'; import { PluginHook } from './PluginHook'; +const rowMixin = { + display: 'flex', + flex: '1', + flexDirection: 'row', + minHeight: 0, +}; + +const columnMixin = { + display: 'flex', + flex: '1', + flexDirection: 'column', + minHeight: 0, +}; + const Root = styled(Paper)(({ ownerState, theme }) => ({ + ...columnMixin, backgroundColor: theme.palette.shades?.dark, borderRadius: 0, - display: 'flex', - flexDirection: 'column', height: '100%', - minHeight: 0, overflow: 'hidden', width: '100%', ...(ownerState?.maximized && { @@ -29,41 +41,39 @@ const Root = styled(Paper)(({ ownerState, theme }) => ({ }), })); -const StyledMiddle = styled('div')(() => ({ - display: 'flex', - flex: '1', - flexDirection: 'row', - minHeight: 0, +const ContentRow = styled('div')(() => ({ + ...rowMixin, })); -const StyledMiddleLeft = styled('div')(() => ({ - display: 'flex', - flex: '1', - flexDirection: 'column', - minHeight: 0, +const ContentColumn = styled('div')(() => ({ + ...columnMixin, })); -const StyledPrimaryWindow = styled('div')(() => ({ - display: 'flex', - flex: '1', +const StyledPrimaryWindow = styled(PrimaryWindow)(() => ({ + ...rowMixin, height: '300px', - minHeight: 0, position: 'relative', })); -const StyledCompanionAreaBottom = styled('div')(() => ({ - display: 'flex', +const StyledCompanionAreaBottom = styled(CompanionArea)(() => ({ + ...rowMixin, flex: '0', flexBasis: 'auto', - minHeight: 0, })); const StyledCompanionAreaRight = styled('div')(() => ({ - display: 'flex', + ...rowMixin, flex: '0 1 auto', - minHeight: 0, })); +/** Window title bar wrapper for drag controls in the mosaic view */ +const DraggableNavBar = ({ children, ...props }) => { + const { mosaicWindowActions } = useContext(MosaicWindowContext); + return mosaicWindowActions.connectDragSource( + <nav {...props}>{children}</nav>, + ); +}; + /** * Represents a Window in the mirador workspace * @param {object} window @@ -81,40 +91,13 @@ export class Window extends Component { return { error, hasError: true }; } - /** - * wrappedTopBar - will conditionally wrap a WindowTopBar for needed - * additional functionality based on workspace type - */ - wrappedTopBar() { - const { - windowId, workspaceType, windowDraggable, - } = this.props; - - const topBar = ( - <div> - <WindowTopBar - windowId={windowId} - windowDraggable={windowDraggable} - /> - <IIIFAuthentication windowId={windowId} /> - </div> - ); - if (workspaceType === 'mosaic' && windowDraggable) { - const { mosaicWindowActions } = this.context; - return mosaicWindowActions.connectDragSource( - topBar, - ); - } - return topBar; - } - /** * Renders things */ render() { const { focusWindow, label, isFetching, sideBarOpen, - view, windowId, t, + view, windowDraggable, windowId, workspaceType, t, manifestError, } = this.props; @@ -138,27 +121,28 @@ export class Window extends Component { className={ns('window')} aria-label={t('window', { label })} > - {this.wrappedTopBar()} + <WindowTopBar + component={workspaceType === 'mosaic' && windowDraggable ? DraggableNavBar : undefined} + windowId={windowId} + windowDraggable={windowDraggable} + /> + <IIIFAuthentication windowId={windowId} /> { manifestError && <ErrorContent error={{ stack: manifestError }} windowId={windowId} /> } - <StyledMiddle> - <StyledMiddleLeft> - <StyledPrimaryWindow> - <PrimaryWindow - view={view} - windowId={windowId} - isFetching={isFetching} - sideBarOpen={sideBarOpen} - /> - </StyledPrimaryWindow> - <StyledCompanionAreaBottom> - <CompanionArea windowId={windowId} position="bottom" /> - </StyledCompanionAreaBottom> - </StyledMiddleLeft> + <ContentRow> + <ContentColumn> + <StyledPrimaryWindow + view={view} + windowId={windowId} + isFetching={isFetching} + sideBarOpen={sideBarOpen} + /> + <StyledCompanionAreaBottom windowId={windowId} position="bottom" /> + </ContentColumn> <StyledCompanionAreaRight> <CompanionArea windowId={windowId} position="right" /> <CompanionArea windowId={windowId} position="far-right" /> </StyledCompanionAreaRight> - </StyledMiddle> + </ContentRow> <CompanionArea windowId={windowId} position="far-bottom" /> <PluginHook {...this.props} /> </Root> diff --git a/src/components/WindowTopBar.js b/src/components/WindowTopBar.js index abc496c2ccc00d24b239dcd978d61303e4ef137d..5e32f8cd0787303091ddba23f3fb1843cf6d40d6 100644 --- a/src/components/WindowTopBar.js +++ b/src/components/WindowTopBar.js @@ -45,10 +45,11 @@ export class WindowTopBar extends Component { removeWindow, windowId, toggleWindowSideBar, t, maximizeWindow, maximized, minimizeWindow, allowClose, allowMaximize, focusWindow, allowFullscreen, allowTopMenuButton, allowWindowSideBar, + component, } = this.props; return ( - <Root component="nav" aria-label={t('windowNavigation')} position="relative" color="default" enableColorOnDark> + <Root component={component} aria-label={t('windowNavigation')} position="relative" color="default" enableColorOnDark> <StyledToolbar disableGutters onMouseDown={focusWindow} @@ -106,6 +107,7 @@ WindowTopBar.propTypes = { allowMaximize: PropTypes.bool, allowTopMenuButton: PropTypes.bool, allowWindowSideBar: PropTypes.bool, + component: PropTypes.elementType, focused: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types focusWindow: PropTypes.func, maximized: PropTypes.bool, @@ -124,6 +126,7 @@ WindowTopBar.defaultProps = { allowMaximize: true, allowTopMenuButton: true, allowWindowSideBar: true, + component: 'nav', focused: false, focusWindow: () => {}, maximized: false,