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 { resetSessionStorage } from "../../utils";
import { DeviceType } from "@docspace/shared/enums";
import { SECTION_HEADER_HEIGHT } from "@docspace/shared/components/section/Section.constants";
const SubmenuCommon = (props) => {
const {
@ -117,13 +118,7 @@ const SubmenuCommon = (props) => {
data={data}
startSelect={currentTab}
onSelect={(e) => onSelect(e)}
topProps={
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
/>
);
};

View File

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

View File

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

View File

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

View File

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

View File

@ -41,7 +41,7 @@ import FileManagement from "./sub-components/file-management";
import InterfaceTheme from "./sub-components/interface-theme";
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`
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 { showProfileLoader, profile, currentDeviceType, t } = props;
const navigate = useNavigate();
@ -102,17 +110,11 @@ const SectionBodyContent = (props) => {
return (
<Wrapper>
<MainProfile />
<Submenu
<StyledSubMenu
data={data}
startSelect={currentTab}
onSelect={onSelect}
topProps={
currentDeviceType === DeviceType.desktop
? 0
: currentDeviceType === DeviceType.mobile
? "53px"
: "61px"
}
topProps={SECTION_HEADER_HEIGHT[currentDeviceType]}
/>
</Wrapper>
);

View File

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

View File

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

View File

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

View File

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