Shared: Section: Make scrollbar wrap whole page. Fix related bugs

This commit is contained in:
Aleksandr Lushkin 2024-05-04 14:31:17 +02:00
parent c76f9c79a0
commit 6f1ba3696c
12 changed files with 131 additions and 182 deletions

View File

@ -38,6 +38,7 @@ import withLoading from "SRC_DIR/HOCs/withLoading";
import LoaderSubmenu from "./sub-components/loaderSubmenu"; import LoaderSubmenu from "./sub-components/loaderSubmenu";
import { resetSessionStorage } from "../../utils"; import { resetSessionStorage } from "../../utils";
import { DeviceType } from "@docspace/shared/enums"; import { DeviceType } from "@docspace/shared/enums";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const SubmenuCommon = (props) => { const SubmenuCommon = (props) => {
const { const {
@ -117,13 +118,7 @@ const SubmenuCommon = (props) => {
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={(e) => onSelect(e)} onSelect={(e) => onSelect(e)}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
); );
}; };

View File

@ -44,6 +44,7 @@ import ManualBackup from "./backup/manual-backup";
import AutoBackup from "./backup/auto-backup"; import AutoBackup from "./backup/auto-backup";
import { DeviceType } from "@docspace/shared/enums"; import { DeviceType } from "@docspace/shared/enums";
import { isManagement } from "@docspace/shared/utils/common"; import { isManagement } from "@docspace/shared/utils/common";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const DataManagementWrapper = (props) => { const DataManagementWrapper = (props) => {
const { const {
@ -144,13 +145,7 @@ const DataManagementWrapper = (props) => {
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={(e) => onSelect(e)} onSelect={(e) => onSelect(e)}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
); );
}; };

View File

@ -44,9 +44,9 @@ import { isMobile, isMobileOnly } from "react-device-detect";
import AppLoader from "@docspace/shared/components/app-loader"; import AppLoader from "@docspace/shared/components/app-loader";
import SSOLoader from "./sub-components/ssoLoader"; import SSOLoader from "./sub-components/ssoLoader";
import { WebhookConfigsLoader } from "./Webhooks/sub-components/Loaders"; import { WebhookConfigsLoader } from "./Webhooks/sub-components/Loaders";
import { DeviceType } from "@docspace/shared/enums";
import PluginSDK from "./PluginSDK"; import PluginSDK from "./PluginSDK";
import { Badge } from "@docspace/shared/components/badge"; import { Badge } from "@docspace/shared/components/badge";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const StyledSubmenu = styled(Submenu)` const StyledSubmenu = styled(Submenu)`
.sticky { .sticky {
@ -151,13 +151,7 @@ const DeveloperToolsWrapper = (props) => {
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={onSelect} onSelect={onSelect}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
</Suspense> </Suspense>
); );

View File

@ -38,9 +38,9 @@ import ThirdParty from "./ThirdPartyServicesSettings";
import SMTPSettings from "./SMTPSettings"; import SMTPSettings from "./SMTPSettings";
import DocumentService from "./DocumentService"; import DocumentService from "./DocumentService";
import PluginPage from "./Plugins"; import PluginPage from "./Plugins";
import { DeviceType } from "@docspace/shared/enums";
import { Badge } from "@docspace/shared/components/badge"; import { Badge } from "@docspace/shared/components/badge";
import { Box } from "@docspace/shared/components/box"; import { Box } from "@docspace/shared/components/box";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const IntegrationWrapper = (props) => { const IntegrationWrapper = (props) => {
const { const {
@ -136,13 +136,7 @@ const IntegrationWrapper = (props) => {
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={onSelect} onSelect={onSelect}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
); );
}; };

View File

@ -40,6 +40,7 @@ import AccessLoader from "./sub-components/loaders/access-loader";
import AuditTrail from "./audit-trail/index.js"; import AuditTrail from "./audit-trail/index.js";
import { resetSessionStorage } from "../../utils"; import { resetSessionStorage } from "../../utils";
import { DeviceType } from "@docspace/shared/enums"; import { DeviceType } from "@docspace/shared/enums";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const SecurityWrapper = (props) => { const SecurityWrapper = (props) => {
const { t, loadBaseInfo, resetIsInit, currentDeviceType } = props; const { t, loadBaseInfo, resetIsInit, currentDeviceType } = props;
@ -110,13 +111,7 @@ const SecurityWrapper = (props) => {
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={(e) => onSelect(e)} onSelect={(e) => onSelect(e)}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
); );
}; };

View File

@ -41,7 +41,7 @@ import FileManagement from "./sub-components/file-management";
import InterfaceTheme from "./sub-components/interface-theme"; import InterfaceTheme from "./sub-components/interface-theme";
import { tablet } from "@docspace/shared/utils"; import { tablet } from "@docspace/shared/utils";
import { DeviceType } from "@docspace/shared/enums"; import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
@ -54,6 +54,14 @@ const Wrapper = styled.div`
} }
`; `;
const StyledSubMenu = styled(Submenu)`
> .sticky {
z-index: 201;
margin-inline-end: -17px;
padding-inline-end: 17px;
}
`;
const SectionBodyContent = (props) => { const SectionBodyContent = (props) => {
const { showProfileLoader, profile, currentDeviceType, t } = props; const { showProfileLoader, profile, currentDeviceType, t } = props;
const navigate = useNavigate(); const navigate = useNavigate();
@ -102,17 +110,11 @@ const SectionBodyContent = (props) => {
return ( return (
<Wrapper> <Wrapper>
<MainProfile /> <MainProfile />
<Submenu <StyledSubMenu
data={data} data={data}
startSelect={currentTab} startSelect={currentTab}
onSelect={onSelect} onSelect={onSelect}
topProps={ topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
/> />
</Wrapper> </Wrapper>
); );

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { DeviceType } from "../../enums";
export const SECTION_HEADER_NAME = "SectionHeader"; export const SECTION_HEADER_NAME = "SectionHeader";
export const SECTION_FILTER_NAME = "SectionFilter"; export const SECTION_FILTER_NAME = "SectionFilter";
export const SECTION_BODY_NAME = "SectionBody"; export const SECTION_BODY_NAME = "SectionBody";
@ -33,3 +35,9 @@ export const SECTION_INFO_PANEL_BODY_NAME = "InfoPanelBody";
export const SECTION_INFO_PANEL_HEADER_NAME = "InfoPanelHeader"; export const SECTION_INFO_PANEL_HEADER_NAME = "InfoPanelHeader";
export const SECTION_WARNING_NAME = "SectionWarning"; export const SECTION_WARNING_NAME = "SectionWarning";
export const SECTION_SUBMENU_NAME = "SectionSubmenu"; export const SECTION_SUBMENU_NAME = "SectionSubmenu";
export const SECTION_HEADER_HEIGHT: Readonly<Record<DeviceType, string>> = {
[DeviceType.desktop]: "69px",
[DeviceType.tablet]: "61px",
[DeviceType.mobile]: "53px",
};

View File

@ -43,6 +43,7 @@ import { TViewAs } from "../../types";
import { Scrollbar } from "../scrollbar"; import { Scrollbar } from "../scrollbar";
import DragAndDrop from "../drag-and-drop/DragAndDrop"; import DragAndDrop from "../drag-and-drop/DragAndDrop";
import { SectionContainerProps } from "./Section.types"; import { SectionContainerProps } from "./Section.types";
import { SECTION_HEADER_HEIGHT } from "./Section.constants";
const StyledScrollbar = styled(Scrollbar)<{ $isScrollLocked?: boolean }>` const StyledScrollbar = styled(Scrollbar)<{ $isScrollLocked?: boolean }>`
${({ $isScrollLocked }) => ${({ $isScrollLocked }) =>
@ -507,14 +508,7 @@ const sizeBetweenIcons = "8px";
const StyledSectionContainer = styled.section<SectionContainerProps>` const StyledSectionContainer = styled.section<SectionContainerProps>`
position: relative; position: relative;
${(props) => ${(props) => !props.withBodyScroll && "padding-inline-start: 20px;"}
props.theme.interfaceDirection === "rtl"
? css`
padding: 0 20px 0 0;
`
: css`
padding: 0 0 0 20px;
`}
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -526,20 +520,37 @@ const StyledSectionContainer = styled.section<SectionContainerProps>`
@media ${tablet} { @media ${tablet} {
width: 100%; width: 100%;
max-width: 100vw !important; max-width: 100vw !important;
${(props) =>
props.theme.interfaceDirection === "rtl" ${(props) => !props.withBodyScroll && "padding-inline-start: 16px;"}
? css`
padding: 0 16px 0 0;
`
: css`
padding: 0 0 0 16px;
`}
${tabletProps}; ${tabletProps};
} }
@media ${mobile} { @media ${mobile} {
width: 100vw !important; width: 100vw !important;
max-width: 100vw !important; max-width: 100vw !important;
padding-inline-start: 16px;
}
.section-scroll > .scroll-body {
padding-inline-start: 20px !important;
@media ${tablet} {
padding-inline-start: 16px !important;
}
}
.section-sticky-container {
position: sticky;
top: 0;
background: ${(props) => props.theme.section.header.backgroundColor};
z-index: 201;
padding-inline: 20px;
margin-inline: -20px -17px;
@media ${tablet} {
padding-inline: 16px;
margin-inline: -16px;
}
} }
.progress-bar_container { .progress-bar_container {
@ -618,14 +629,6 @@ const StyledSectionContainer = styled.section<SectionContainerProps>`
StyledSectionContainer.defaultProps = { theme: Base }; StyledSectionContainer.defaultProps = { theme: Base };
const StyledSectionFilter = styled.div` const StyledSectionFilter = styled.div`
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 20px;
`
: css`
margin-right: 20px;
`}
@media ${tablet} { @media ${tablet} {
${(props) => ${(props) =>
props.theme.interfaceDirection === "rtl" props.theme.interfaceDirection === "rtl"
@ -652,18 +655,18 @@ const StyledSectionHeader = styled.div<{ isFormGallery?: boolean }>`
position: relative; position: relative;
display: flex; display: flex;
height: 69px; height: ${SECTION_HEADER_HEIGHT.desktop};
min-height: 69px; min-height: ${SECTION_HEADER_HEIGHT.desktop};
@media ${tablet} { @media ${tablet} {
height: 61px; height: ${SECTION_HEADER_HEIGHT.tablet};
min-height: 61px; min-height: ${SECTION_HEADER_HEIGHT.tablet};
${({ isFormGallery }) => ${({ isFormGallery }) =>
isFormGallery && isFormGallery &&
css` css`
height: 69px; height: ${SECTION_HEADER_HEIGHT.desktop};
min-height: 69px; min-height: ${SECTION_HEADER_HEIGHT.desktop};
`} `}
.header-container { .header-container {
@ -673,19 +676,10 @@ const StyledSectionHeader = styled.div<{ isFormGallery?: boolean }>`
} }
@media ${mobile} { @media ${mobile} {
height: 53px; height: ${SECTION_HEADER_HEIGHT.mobile};
min-height: 53px; min-height: ${SECTION_HEADER_HEIGHT.mobile};
} }
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
padding-left: 20px;
`
: css`
padding-right: 20px;
`}
box-sizing: border-box; box-sizing: border-box;
${NoUserSelect} ${NoUserSelect}
@ -700,28 +694,8 @@ const StyledSectionHeader = styled.div<{ isFormGallery?: boolean }>`
display: flex; display: flex;
} }
@media ${tablet} {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
padding-left: 16px;
margin-left: 0px;
`
: css`
padding-right: 16px;
margin-right: 0px;
`}
}
@media ${mobile} { @media ${mobile} {
${(props) => margin-inline-end: 0;
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 0px;
`
: css`
margin-right: 0px;
`}
} }
`; `;
@ -754,13 +728,13 @@ StyledSectionPaging.defaultProps = { theme: Base };
const StyledSectionSubmenu = styled.div` const StyledSectionSubmenu = styled.div`
background: ${(props) => props.theme.section.header.backgroundColor}; background: ${(props) => props.theme.section.header.backgroundColor};
width: calc(100% - 20px); width: 100%;
z-index: 1; z-index: 1;
@media ${tablet} { @media ${tablet} {
width: calc(100% + 32px); width: calc(100% + 32px);
position: sticky; position: sticky;
top: 61px; top: ${SECTION_HEADER_HEIGHT.tablet};
margin: 0 -16px; margin: 0 -16px;
& > div { & > div {
padding: 0 16px; padding: 0 16px;
@ -769,7 +743,7 @@ const StyledSectionSubmenu = styled.div`
@media ${mobile} { @media ${mobile} {
position: sticky; position: sticky;
top: 53px; top: ${SECTION_HEADER_HEIGHT.mobile};
} }
`; `;

View File

@ -75,6 +75,8 @@ export interface SectionContainerProps {
isSectionHeaderAvailable: boolean; isSectionHeaderAvailable: boolean;
viewAs?: TViewAs; viewAs?: TViewAs;
children: React.ReactNode; children: React.ReactNode;
withBodyScroll: boolean;
currentDeviceType?: DeviceType;
} }
export interface SectionFilterProps { export interface SectionFilterProps {

View File

@ -201,30 +201,35 @@ const Section = (props: SectionProps) => {
ref={containerRef} ref={containerRef}
isSectionHeaderAvailable={isSectionHeaderAvailable} isSectionHeaderAvailable={isSectionHeaderAvailable}
showTwoProgress={showTwoProgress} showTwoProgress={showTwoProgress}
withBodyScroll={withBodyScroll}
currentDeviceType={currentDeviceType}
> >
{isSectionHeaderAvailable && {currentDeviceType !== DeviceType.mobile && (
currentDeviceType === DeviceType.desktop && ( <div className="section-sticky-container">
<SubSectionHeader {isSectionHeaderAvailable && (
className="section-header_header" <SubSectionHeader
isFormGallery={isFormGallery} className="section-header_header"
> isFormGallery={isFormGallery}
{sectionHeaderContent} >
</SubSectionHeader> {sectionHeaderContent}
)} </SubSectionHeader>
)}
{isSectionSubmenuAvailable && {isSectionSubmenuAvailable && (
currentDeviceType === DeviceType.desktop && ( <SubSectionSubmenu>{sectionSubmenuContent}</SubSectionSubmenu>
<SubSectionSubmenu>{sectionSubmenuContent}</SubSectionSubmenu> )}
)}
{isSectionFilterAvailable && {isSectionFilterAvailable &&
currentDeviceType === DeviceType.desktop && ( currentDeviceType === DeviceType.desktop && (
<SubSectionFilter <SubSectionFilter
className="section-header_filter" className="section-header_filter"
viewAs={viewAs} viewAs={viewAs}
> >
{sectionFilterContent} {sectionFilterContent}
</SubSectionFilter> </SubSectionFilter>
)} )}
</div>
)}
{isSectionBodyAvailable && ( {isSectionBodyAvailable && (
<SubSectionBody <SubSectionBody
@ -239,7 +244,7 @@ const Section = (props: SectionProps) => {
getContextModel={getContextModel} getContextModel={getContextModel}
> >
{isSectionHeaderAvailable && {isSectionHeaderAvailable &&
currentDeviceType !== DeviceType.desktop && ( currentDeviceType === DeviceType.mobile && (
<SubSectionHeader <SubSectionHeader
className="section-body_header" className="section-body_header"
isFormGallery={isFormGallery} isFormGallery={isFormGallery}
@ -251,7 +256,7 @@ const Section = (props: SectionProps) => {
<SubSectionWarning>{sectionWarningContent}</SubSectionWarning> <SubSectionWarning>{sectionWarningContent}</SubSectionWarning>
)} )}
{isSectionSubmenuAvailable && {isSectionSubmenuAvailable &&
currentDeviceType !== DeviceType.desktop && ( currentDeviceType === DeviceType.mobile && (
<SubSectionSubmenu>{sectionSubmenuContent}</SubSectionSubmenu> <SubSectionSubmenu>{sectionSubmenuContent}</SubSectionSubmenu>
)} )}
{isSectionFilterAvailable && {isSectionFilterAvailable &&

View File

@ -28,11 +28,8 @@ import React from "react";
// import { inject, observer } from "mobx-react"; // import { inject, observer } from "mobx-react";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
import { ContextMenu } from "@docspace/shared/components/context-menu"; import { ContextMenu } from "@docspace/shared/components/context-menu";
import { DeviceType } from "@docspace/shared/enums";
import { import {
StyledDropZoneBody, StyledDropZoneBody,
StyledSpacer, StyledSpacer,
@ -52,7 +49,6 @@ const SectionBody = React.memo(
isDesktop, isDesktop,
settingsStudio = false, settingsStudio = false,
currentDeviceType,
getContextModel, getContextModel,
}: SectionBodyProps) => { }: SectionBodyProps) => {
const focusRef = React.useRef<HTMLDivElement | null>(null); const focusRef = React.useRef<HTMLDivElement | null>(null);
@ -98,7 +94,7 @@ const SectionBody = React.memo(
React.useEffect(() => { React.useEffect(() => {
if (!autoFocus) return; if (!autoFocus) return;
if (focusRef.current) focusRef.current.focus(); if (focusRef.current) focusRef.current.focus({ preventScroll: true });
}, [autoFocus]); }, [autoFocus]);
const focusProps = autoFocus const focusProps = autoFocus
@ -128,27 +124,12 @@ const SectionBody = React.memo(
className="section-body" className="section-body"
> >
{withScroll ? ( {withScroll ? (
currentDeviceType !== DeviceType.mobile ? ( <div className="section-wrapper">
<Scrollbar <div className="section-wrapper-content" {...focusProps}>
id="sectionScroll" {children}
scrollclass="section-scroll" <StyledSpacer />
fixedSize
>
<div className="section-wrapper">
<div className="section-wrapper-content" {...focusProps}>
{children}
<StyledSpacer />
</div>
</div>
</Scrollbar>
) : (
<div className="section-wrapper">
<div className="section-wrapper-content" {...focusProps}>
{children}
<StyledSpacer />
</div>
</div> </div>
) </div>
) : ( ) : (
<div className="section-wrapper"> <div className="section-wrapper">
{children} {children}
@ -168,27 +149,12 @@ const SectionBody = React.memo(
className="section-body" className="section-body"
> >
{withScroll ? ( {withScroll ? (
currentDeviceType !== DeviceType.mobile ? ( <div className="section-wrapper">
<Scrollbar <div className="section-wrapper-content" {...focusProps}>
id="sectionScroll" {children}
scrollclass="section-scroll" <StyledSpacer className="settings-mobile" />
fixedSize
>
<div className="section-wrapper">
<div className="section-wrapper-content" {...focusProps}>
{children}
<StyledSpacer className="settings-mobile" />
</div>
</div>
</Scrollbar>
) : (
<div className="section-wrapper">
<div className="section-wrapper-content" {...focusProps}>
{children}
<StyledSpacer className="settings-mobile" />
</div>
</div> </div>
) </div>
) : ( ) : (
<div className="section-wrapper">{children}</div> <div className="section-wrapper">{children}</div>
)} )}

View File

@ -25,14 +25,33 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import React from "react"; import React from "react";
import { Scrollbar } from "../../scrollbar";
import { DeviceType } from "../../../enums";
import { StyledSectionContainer } from "../Section.styled"; import { StyledSectionContainer } from "../Section.styled";
import { SectionContainerProps } from "../Section.types"; import { SectionContainerProps } from "../Section.types";
const SectionContainer = React.forwardRef< const SectionContainer = React.forwardRef<
HTMLDivElement, HTMLDivElement,
SectionContainerProps SectionContainerProps
>((props, forwardRef) => { >(({ withBodyScroll, children, currentDeviceType, ...props }, forwardRef) => {
return <StyledSectionContainer ref={forwardRef} id="section" {...props} />; return (
<StyledSectionContainer
ref={forwardRef}
id="section"
withBodyScroll={withBodyScroll}
{...props}
>
{withBodyScroll && currentDeviceType !== DeviceType.mobile ? (
<Scrollbar id="sectionScroll" scrollclass="section-scroll" fixedSize>
{children}
</Scrollbar>
) : (
children
)}
</StyledSectionContainer>
);
}); });
SectionContainer.displayName = "SectionContainer"; SectionContainer.displayName = "SectionContainer";