diff --git a/src/components/FullscreenModal/Footer/Footer.tsx b/src/components/FullscreenModal/Footer/Footer.tsx index 04e0a4546..a1c0b0f3a 100644 --- a/src/components/FullscreenModal/Footer/Footer.tsx +++ b/src/components/FullscreenModal/Footer/Footer.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { getColor, pxToRem } from '../../../utils/helpers'; import { FlexContainer } from '../../FlexContainer'; -import { ScrollToTop } from '../ScrollToTop'; +import { ScrollToTopButton } from '../ScrollToTopButton'; import { useStickyFooter } from '../hooks/useStickyFooter'; import { Col, Container, Row } from '../../layout'; import { FooterProps } from './Footer.types'; @@ -29,6 +29,7 @@ const Footer: React.FC = ({ width, offset, modalRef, + scrollToTopButtonLabel, }) => { const modalFooterRef = useRef(null); const { isFixed, shouldShowScrollToTopButton } = useStickyFooter( @@ -61,7 +62,10 @@ const Footer: React.FC = ({ justifyContent="center" margin={{ vertical: 1.2 }} > - + )} @@ -75,6 +79,7 @@ Footer.propTypes = { modalRef: PropTypes.exact({ current: PropTypes.instanceOf(HTMLElement), }).isRequired, + scrollToTopButtonLabel: PropTypes.string, }; export default Footer; diff --git a/src/components/FullscreenModal/Footer/Footer.types.ts b/src/components/FullscreenModal/Footer/Footer.types.ts index 96d7f636e..7f6c1b6b4 100644 --- a/src/components/FullscreenModal/Footer/Footer.types.ts +++ b/src/components/FullscreenModal/Footer/Footer.types.ts @@ -2,4 +2,5 @@ export interface FooterProps { width: number; offset: number; modalRef: React.MutableRefObject; + scrollToTopButtonLabel: string; } diff --git a/src/components/FullscreenModal/FullscreenModal.stories.tsx b/src/components/FullscreenModal/FullscreenModal.stories.tsx index 91c1ef731..e7ba345b0 100644 --- a/src/components/FullscreenModal/FullscreenModal.stories.tsx +++ b/src/components/FullscreenModal/FullscreenModal.stories.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Meta, Story } from '@storybook/react/types-6-0'; +import { action } from '@storybook/addon-actions'; import { FlexContainer } from '../FlexContainer'; import { Button } from '../Button'; @@ -89,6 +90,7 @@ export const SingleColumn6: Story = () => ( footer={Footer()} header={header} layout={FullscreenModalLayouts.single6} + onClose={action('close modal')} /> ); SingleColumn6.storyName = 'Single Column (layout: single-6)'; @@ -113,6 +115,15 @@ SingleColumn6.argTypes = { description: 'Content of the sidebar wrapper', table: { type: { summary: 'React.node' } }, }, + scrollToTopButtonLabel: { + control: { disable: true }, + description: 'Label of the scroll to top button', + table: { defaultValue: { summary: '"Scroll to top"' } }, + }, + onClose: { + control: { disable: true }, + description: 'Modal window close handler', + }, }; export const SingleColumn8: Story = () => ( @@ -121,6 +132,7 @@ export const SingleColumn8: Story = () => ( footer={Footer()} header={header} layout={FullscreenModalLayouts.single8} + onClose={action('close modal')} /> ); @@ -133,6 +145,7 @@ export const Sidebar4Column6: Story = () => ( header={header} layout={FullscreenModalLayouts.sidebar46} sidebar={Sidebar()} + onClose={action('close modal')} /> ); Sidebar4Column6.storyName = 'Two Columns with sidebar (layout: sidebar-4-6)'; @@ -143,7 +156,8 @@ export const Sidebar4Column8: Story = () => ( footer={Footer()} header={header} layout={FullscreenModalLayouts.sidebar48} - // sidebar={Sidebar()} + sidebar={Sidebar()} + onClose={action('close modal')} /> ); Sidebar4Column8.storyName = 'Two Columns with sidebar (layout: sidebar-4-8)'; @@ -154,5 +168,6 @@ export const WithLongContent: Story = () => ( footer={Footer()} header={header} layout={FullscreenModalLayouts.single6} + onClose={action('close modal')} /> ); diff --git a/src/components/FullscreenModal/FullscreenModal.tsx b/src/components/FullscreenModal/FullscreenModal.tsx index f8b326164..59bd50435 100644 --- a/src/components/FullscreenModal/FullscreenModal.tsx +++ b/src/components/FullscreenModal/FullscreenModal.tsx @@ -11,8 +11,8 @@ import { ColumnConfigMap, FullscreenModalProps } from './FullscreenModal.types'; import { Col, Container, Row } from '../layout'; const BaseModal = styled.div` - width: 100vw; - height: 100vh; + width: 100%; + height: 100%; position: fixed; top: 0; left: 0; @@ -50,22 +50,22 @@ const FullscreenModal: React.FC = ({ content, sidebar, footer, + scrollToTopButtonLabel, onClose = noop, }) => { const modalRef = useRef(null); const { - header: headerConfig, - sidebar: sidebarConfig, - content: contentConfig, + header: [headerCols, headerOffset], + sidebar: [sidebarCols, sidebarOffset], + content: [contentCols, contentOffset], } = columnConfigMap[layout]; - const hasLayoutSidebar = sidebarConfig[0] > 0; - const totalContentWidth = contentConfig[0] + sidebarConfig[0]; + const hasLayoutSidebar = sidebarCols > 0; + const totalContentWidth = contentCols + sidebarCols; if (hasLayoutSidebar && isUndefined(sidebar)) { - // eslint-disable-next-line no-console - console.error( + throw new Error( `You chose to use modal layout with sidebar (current: ${layout}) but you didn't provide sidebar content. You should either provide content in "sidebar" property or switch layout to "${FullscreenModalLayouts.single6}" or "${FullscreenModalLayouts.single8}" `, @@ -76,11 +76,11 @@ You should either provide content in "sidebar" property or switch layout to "${F - + {header} @@ -89,15 +89,16 @@ You should either provide content in "sidebar" property or switch layout to "${F {hasLayoutSidebar && ( - + {sidebar} )} - + {content} {footer} @@ -113,9 +114,10 @@ FullscreenModal.propTypes = { header: PropTypes.node.isRequired, content: PropTypes.node.isRequired, footer: PropTypes.node.isRequired, + onClose: PropTypes.func.isRequired, sidebar: PropTypes.node, layout: PropTypes.oneOf(Object.values(FullscreenModalLayouts)), - onClose: PropTypes.func, + scrollToTopButtonLabel: PropTypes.string, }; export default FullscreenModal; diff --git a/src/components/FullscreenModal/FullscreenModal.types.ts b/src/components/FullscreenModal/FullscreenModal.types.ts index 154ab1b5b..db95b395e 100644 --- a/src/components/FullscreenModal/FullscreenModal.types.ts +++ b/src/components/FullscreenModal/FullscreenModal.types.ts @@ -16,5 +16,6 @@ export interface FullscreenModalProps { content: React.ReactNode; footer: React.ReactNode; sidebar?: React.ReactNode; - onClose?: () => void; + scrollToTopButtonLabel?: string; + onClose: () => void; } diff --git a/src/components/FullscreenModal/ScrollToTop/ScrollToTop.types.ts b/src/components/FullscreenModal/ScrollToTop/ScrollToTop.types.ts deleted file mode 100644 index 4b2b1aa82..000000000 --- a/src/components/FullscreenModal/ScrollToTop/ScrollToTop.types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ScrollToTopProps { - onClick?: () => void; -} diff --git a/src/components/FullscreenModal/ScrollToTop/index.ts b/src/components/FullscreenModal/ScrollToTop/index.ts deleted file mode 100644 index 480c5d658..000000000 --- a/src/components/FullscreenModal/ScrollToTop/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ScrollToTop } from './ScrollToTop'; diff --git a/src/components/FullscreenModal/ScrollToTop/ScrollToTop.tsx b/src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.tsx similarity index 71% rename from src/components/FullscreenModal/ScrollToTop/ScrollToTop.tsx rename to src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.tsx index 8b813fbf7..27e25e422 100644 --- a/src/components/FullscreenModal/ScrollToTop/ScrollToTop.tsx +++ b/src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.tsx @@ -8,9 +8,9 @@ import { Button } from '../../Button'; import { ButtonColors, ButtonVariants } from '../../Button/Button.enums'; import { Icon } from '../../Icon'; import { SSCIconNames } from '../../Icon/Icon.enums'; -import { ScrollToTopProps } from './ScrollToTop.types'; +import { ScrollToTopButtonProps } from './ScrollToTopButton.types'; -const ScrollToTopButton = styled(Button)` +const StyledButton = styled(Button)` flex-direction: column; justify-content: center; height: ${pxToRem(48)}; @@ -23,7 +23,10 @@ const ButtonText = styled.span` margin-top: ${pxToRem(4)}; `; -const ScrollToTop: React.FC = ({ onClick = undefined }) => { +const ScrollToTopButton: React.FC = ({ + onClick, + label = 'Scroll to top', +}) => { const handleClick = () => { if (isNotUndefined(onClick)) { onClick(); @@ -33,19 +36,20 @@ const ScrollToTop: React.FC = ({ onClick = undefined }) => { }; return ( - - Scroll to top - + {label} + ); }; -ScrollToTop.propTypes = { +ScrollToTopButton.propTypes = { + label: PropTypes.string, onClick: PropTypes.func, }; -export default ScrollToTop; +export default ScrollToTopButton; diff --git a/src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.types.ts b/src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.types.ts new file mode 100644 index 000000000..a0ebadc15 --- /dev/null +++ b/src/components/FullscreenModal/ScrollToTopButton/ScrollToTopButton.types.ts @@ -0,0 +1,4 @@ +export interface ScrollToTopButtonProps { + onClick?: () => void; + label?: string; +} diff --git a/src/components/FullscreenModal/ScrollToTopButton/index.ts b/src/components/FullscreenModal/ScrollToTopButton/index.ts new file mode 100644 index 000000000..81bc437a7 --- /dev/null +++ b/src/components/FullscreenModal/ScrollToTopButton/index.ts @@ -0,0 +1 @@ +export { default as ScrollToTopButton } from './ScrollToTopButton'; diff --git a/src/components/FullscreenModal/hooks/useStickyFooter.ts b/src/components/FullscreenModal/hooks/useStickyFooter.ts index dc1cb9fe8..2c2156b3d 100644 --- a/src/components/FullscreenModal/hooks/useStickyFooter.ts +++ b/src/components/FullscreenModal/hooks/useStickyFooter.ts @@ -40,13 +40,11 @@ export const useStickyFooter = ( modalRef.current.scrollTop + modalRef.current.offsetHeight; const contentHeight = modalRef.current.scrollHeight - modalFooterRef.current.scrollHeight; + const fixedAtThreshold = contentHeight * 0.001; if (isFixed && scrollOffset >= contentHeight) { setIsFixed(false); - } else if ( - !isFixed && - scrollOffset < contentHeight - contentHeight * 0.001 - ) { + } else if (!isFixed && scrollOffset < contentHeight - fixedAtThreshold) { setIsFixed(true); } // eslint-disable-next-line react-hooks/exhaustive-deps