Skip to content

Commit

Permalink
Merge pull request #6895 from Sage/FE-6725
Browse files Browse the repository at this point in the history
feat(dialog): add the "maximise" value to the `size` prop
  • Loading branch information
tomdavies73 authored Aug 30, 2024
2 parents 484c5bd + 398ffb0 commit 72a282d
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 5 deletions.
78 changes: 78 additions & 0 deletions src/components/dialog/dialog-test.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,81 @@ WithTwoDifferentNodes.decorators = [
),
];
WithTwoDifferentNodes.parameters = { chromatic: { disableSnapshot: false } };

export const MaxSizeTest: StoryType = () => {
return (
<Dialog size="maximise" open title="Title" subtitle="Subtitle">
<Form
stickyFooter
leftSideButtons={<Button>Cancel</Button>}
saveButton={
<Button buttonType="primary" type="submit">
Save
</Button>
}
>
<Textbox label="First Name" />
<Textbox label="Middle Name" />
<Textbox label="Surname" />
<Textbox label="Birth Place" />
<Textbox label="Favourite Colour" />
<Textbox label="Address" />
<Textbox label="First Name" />
<Textbox label="Middle Name" />
<Textbox label="Surname" />
<Textbox label="Birth Place" />
<Textbox label="Favourite Colour" />
<Textbox label="Address" />
</Form>
</Dialog>
);
};

MaxSizeTest.storyName = "With Maximised Size";
MaxSizeTest.decorators = [
(Story) => (
<div style={{ height: "100vh", width: "100vw" }}>
<Story />
</div>
),
];

MaxSizeTest.parameters = {
themeProvider: { chromatic: { theme: "none" } },
chromatic: { disableSnapshot: false, viewports: [1200, 900] },
layout: "fullscreen",
};

export const MaxSizeTestNonOverflowedForm: StoryType = () => {
return (
<Dialog size="maximise" open title="Title" subtitle="Subtitle">
<Form
stickyFooter
leftSideButtons={<Button>Cancel</Button>}
saveButton={
<Button buttonType="primary" type="submit">
Save
</Button>
}
>
<Textbox label="First Name" />
</Form>
</Dialog>
);
};

MaxSizeTestNonOverflowedForm.storyName =
"With Maximised Size and a Non-Overflowed Form";
MaxSizeTestNonOverflowedForm.decorators = [
(Story) => (
<div style={{ height: "100vh", width: "100vw" }}>
<Story />
</div>
),
];

MaxSizeTestNonOverflowedForm.parameters = {
themeProvider: { chromatic: { theme: "none" } },
chromatic: { disableSnapshot: false, viewports: [1200, 900] },
layout: "fullscreen",
};
20 changes: 18 additions & 2 deletions src/components/dialog/dialog.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {
useCallback,
useImperativeHandle,
forwardRef,
useState,
} from "react";

import createGuid from "../../__internal__/utils/helpers/guid";
Expand Down Expand Up @@ -140,6 +141,10 @@ export const Dialog = forwardRef<DialogHandle, DialogProps>(
const containerRef = useRef<HTMLDivElement>(null);
const innerContentRef = useRef(null);
const titleRef = useRef(null);
const [breakpointOffset, setBreakpointOffset] = useState<
number | undefined
>(undefined);
const isDialogMaximised = size === "maximise";
const listenersAdded = useRef(false);
const { current: titleId } = useRef(createGuid());
const { current: subtitleId } = useRef(createGuid());
Expand Down Expand Up @@ -181,9 +186,16 @@ export const Dialog = forwardRef<DialogHandle, DialogProps>(
midPointX = 0;
}

if (isDialogMaximised) {
const breakPoint = window.innerWidth > 960 ? 32 : 16;
midPointX = breakPoint;
midPointY = breakPoint;
setBreakpointOffset(breakPoint);
}

containerRef.current.style.top = `${midPointY}px`;
containerRef.current.style.left = `${midPointX}px`;
}, []);
}, [size]);

useResizeObserver(innerContentRef, centerDialog, !open);

Expand Down Expand Up @@ -308,7 +320,11 @@ export const Dialog = forwardRef<DialogHandle, DialogProps>(
data-role={dataRole}
aria-modal={isTopModal ? true : undefined}
ref={containerRef}
topMargin={TOP_MARGIN}
topMargin={
isDialogMaximised && breakpointOffset
? breakpointOffset * 2
: TOP_MARGIN
}
{...dialogProps}
role={role}
tabIndex={-1}
Expand Down
1 change: 1 addition & 0 deletions src/components/dialog/dialog.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const DIALOG_SIZES = [
"medium-large",
"large",
"extra-large",
"maximise",
] as const;
export const TOP_MARGIN = 20;
export const CONTENT_TOP_PADDING = 24;
Expand Down
6 changes: 6 additions & 0 deletions src/components/dialog/dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ import Dialog from "carbon-react/lib/components/dialog";

<Canvas of={DialogStories.DefaultStory} />

### With Maximum Size

When the `size` prop is `"maximise"` the height and width of the `Dialog`'s modal extends to the majority of the viewport.

<Canvas of={DialogStories.MaxSize} />

### Editable

When mixing editable and non-editable content, you can use the [Box component](../?path=/docs/box--docs) component to highlight the fields that can be changed.
Expand Down
46 changes: 46 additions & 0 deletions src/components/dialog/dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,52 @@ export const DefaultStory: Story = () => {
};
DefaultStory.storyName = "Default";

export const MaxSize: Story = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button onClick={() => setIsOpen(true)}>Open Dialog</Button>
<Dialog
size="maximise"
open={isOpen}
onCancel={() => setIsOpen(false)}
title="Title"
subtitle="Subtitle"
>
<Form
stickyFooter
leftSideButtons={
<Button onClick={() => setIsOpen(false)}>Cancel</Button>
}
saveButton={
<Button buttonType="primary" type="submit">
Save
</Button>
}
>
<Typography>
This is an example of a dialog with a Form as content
</Typography>
<Textbox label="First Name" />
<Textbox label="Middle Name" />
<Textbox label="Surname" />
<Textbox label="Birth Place" />
<Textbox label="Favourite Colour" />
<Textbox label="Address" />
<Textbox label="First Name" />
<Textbox label="Middle Name" />
<Textbox label="Surname" />
<Textbox label="Birth Place" />
<Textbox label="Favourite Colour" />
<Textbox label="Address" />
</Form>
</Dialog>
</>
);
};
MaxSize.storyName = "With Max Size";
MaxSize.parameters = { chromatic: { disableSnapshot: true } };

export const Editable: Story = () => {
const [isOpen, setIsOpen] = useState(defaultOpenState);
const [isDisabled, setIsDisabled] = useState(true);
Expand Down
29 changes: 26 additions & 3 deletions src/components/dialog/dialog.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@ type StyledDialogProps = {
backgroundColor: string;
};

const StyledDialog = styled.div<StyledDialogProps & ContentPaddingInterface>`
const StyledDialog = styled.div.attrs(
({ topMargin, size }: StyledDialogProps) => {
const isDialogMaximised = size === "maximise";
const isDialogMaximisedSmallViewport = topMargin === 32;
const isDialogMaximisedLargeViewport = topMargin === 64;
return {
isDialogMaximised,
isDialogMaximisedSmallViewport,
isDialogMaximisedLargeViewport,
};
}
)<StyledDialogProps & ContentPaddingInterface>`
box-shadow: var(--boxShadow300);
display: flex;
flex-direction: column;
Expand All @@ -63,6 +74,7 @@ const StyledDialog = styled.div<StyledDialogProps & ContentPaddingInterface>`
top: 50%;
z-index: ${({ theme }) => theme.zIndex.modal};
max-height: ${({ topMargin }) => `calc(100vh - ${topMargin}px)`};
${({ isDialogMaximised }) => isDialogMaximised && "height: 100%"};
&:focus {
outline: none;
Expand All @@ -73,10 +85,12 @@ const StyledDialog = styled.div<StyledDialogProps & ContentPaddingInterface>`
background-color: ${backgroundColor};
`}
${({ size }) =>
${({ size, topMargin }) =>
size &&
css`
max-width: ${dialogSizes[size]};
max-width: ${size === "maximise"
? `calc(100vw - ${topMargin}px)`
: dialogSizes[size]};
width: 100%;
`}
Expand All @@ -86,7 +100,16 @@ const StyledDialog = styled.div<StyledDialogProps & ContentPaddingInterface>`
height: ${dialogHeight}px;
`}
/* We're overriding the max-height on the form content to account for a larger height when in a smaller viewport.
TODO: Remove this upon the completion of FE-6643. */
${StyledForm} {
${({ isDialogMaximised, isDialogMaximisedSmallViewport }) =>
isDialogMaximised &&
css`
${isDialogMaximisedSmallViewport && "max-height: calc(100vh - 184px);"}
height: 100%;
`}
padding-bottom: 0px;
box-sizing: border-box;
}
Expand Down
32 changes: 32 additions & 0 deletions src/components/dialog/dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,38 @@ test("dialog is wrapped in a container, which has the correct class names set, w
expect(modalWrapper).toHaveClass("carbon-dialog special-dialog");
});

test("renders dialog with 'left' set to 32px when 'size' is 'maximise' and window width is greater than 960px", () => {
window.innerWidth = 1000;
render(<Dialog open title="my dialog" size="maximise" />);

const dialog = screen.getByRole("dialog", { name: /my dialog/i });
expect(dialog).toHaveStyle({ left: "32px" });
});

test("renders dialog with 'top' set to 32px when 'size' is 'maximise' and window width is greater than 960px", () => {
window.innerWidth = 1000;
render(<Dialog open title="my dialog" size="maximise" />);

const dialog = screen.getByRole("dialog", { name: /my dialog/i });
expect(dialog).toHaveStyle({ top: "32px" });
});

test("renders dialog with 'left' set to 16px when 'size' is 'maximise' and window width is less than 960px", () => {
window.innerWidth = 700;
render(<Dialog open title="my dialog" size="maximise" />);

const dialog = screen.getByRole("dialog", { name: /my dialog/i });
expect(dialog).toHaveStyle({ left: "16px" });
});

test("renders dialog with 'top' set to 16px when 'size' is 'maximise' and window width is less than 960px", () => {
window.innerWidth = 700;
render(<Dialog open title="my dialog" size="maximise" />);

const dialog = screen.getByRole("dialog", { name: /my dialog/i });
expect(dialog).toHaveStyle({ top: "16px" });
});

test("dialog does not position itself any closer than 20px from the top of the viewport", () => {
const originalInnerHeight = window.innerHeight;
window.innerHeight = 300;
Expand Down

0 comments on commit 72a282d

Please sign in to comment.