Skip to content

Commit 784a732

Browse files
committed
feat: Add optional width and zIndex props to SideSheet component
1 parent 8058032 commit 784a732

4 files changed

Lines changed: 107 additions & 5 deletions

File tree

src/organisms/SideSheet/SideSheet.stories.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,52 @@ export const StatefulModal: Story = {
335335
},
336336
};
337337

338+
export const CustomWidth: Story = {
339+
args: {
340+
type: 'standard',
341+
width: 800,
342+
},
343+
play: async ({ canvasElement, context }) => {
344+
const canvas = within(canvasElement);
345+
const { title } = context.args;
346+
347+
const heading = await canvas.findByRole('heading', {
348+
name: title as string,
349+
level: 2,
350+
});
351+
const sheet = heading.closest('aside') ?? heading.parentElement;
352+
await expect(sheet).not.toBeNull();
353+
await expect(getComputedStyle(sheet!).width).toBe('800px');
354+
},
355+
};
356+
357+
export const CustomZIndex: Story = {
358+
args: {
359+
type: 'modal',
360+
zIndex: 1234,
361+
},
362+
parameters: {
363+
layout: 'fullscreen',
364+
},
365+
decorators: (Story) => (
366+
<FloatingStoryWrapper>
367+
<Story />
368+
</FloatingStoryWrapper>
369+
),
370+
play: async ({ canvasElement, context }) => {
371+
const canvas = within(canvasElement);
372+
const { title } = context.args;
373+
374+
const heading = await canvas.findByRole('heading', {
375+
name: title as string,
376+
level: 2,
377+
});
378+
const sheet = heading.closest('aside') ?? heading.parentElement;
379+
await expect(sheet).not.toBeNull();
380+
await expect(getComputedStyle(sheet!).zIndex).toBe('1234');
381+
},
382+
};
383+
338384
export const StatefulModalWithScrim: Story = {
339385
args: {
340386
type: 'modal',

src/organisms/SideSheet/SideSheet.styles.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import { colors, elevation, shape, spacings } from 'src/atoms/style';
22
import type { SideSheetProps } from 'src/organisms';
33

44
import { motion } from 'motion/react';
5-
import { css, styled } from 'styled-components';
5+
import { css, CSSProperties, styled } from 'styled-components';
66

77
interface WrapperProps {
88
$type: NonNullable<SideSheetProps['type']>;
99
$withShadow?: boolean;
10+
$zIndex?: CSSProperties['zIndex'];
1011
}
1112

1213
export const Wrapper = styled(motion.div)<WrapperProps>`
1314
overflow: hidden;
14-
${({ $type, $withShadow }) => {
15+
${({ $type, $withShadow, $zIndex }) => {
1516
if ($type === 'standard') return '';
1617
1718
if ($type === 'floating') {
@@ -21,6 +22,10 @@ export const Wrapper = styled(motion.div)<WrapperProps>`
2122
right: ${spacings.medium};
2223
box-shadow: ${elevation.sticky};
2324
border-radius: ${shape.corners.borderRadius};
25+
${$zIndex !== undefined &&
26+
css`
27+
z-index: ${$zIndex};
28+
`}
2429
`;
2530
}
2631
@@ -29,18 +34,27 @@ export const Wrapper = styled(motion.div)<WrapperProps>`
2934
top: 64px;
3035
right: 0;
3136
box-shadow: ${$withShadow ? elevation.above_scrim : 'none'};
37+
${$zIndex !== undefined &&
38+
css`
39+
z-index: ${$zIndex};
40+
`}
3241
`;
3342
}}
3443
`;
3544

3645
interface SheetProps {
3746
$type: NonNullable<SideSheetProps['type']>;
47+
$width?: CSSProperties['width'];
3848
}
3949

4050
export const Sheet = styled.div<SheetProps>`
4151
display: flex;
4252
flex-direction: column;
43-
width: 500px;
53+
width: ${({ $width }) => {
54+
if ($width === undefined) return '500px';
55+
if (typeof $width === 'number') return `${$width}px`;
56+
return $width;
57+
}};
4458
background: ${colors.ui.background__default.rgba};
4559
${({ $type }) => {
4660
if ($type === 'standard') {

src/organisms/SideSheet/SideSheet.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { AnimatePresence } from 'motion/react';
1616
* @param title - Title to display in the header
1717
* @param type - How the side sheet should be position, default is standard
1818
* @param headerElements - Optional spot to put elements in the header, for example more action buttons
19+
* @param width - Optional width override (number is treated as px)
1920
* @param children - Content in the side sheet
2021
*/
2122
export const SideSheet: FC<SideSheetProps> = ({
@@ -24,6 +25,7 @@ export const SideSheet: FC<SideSheetProps> = ({
2425
title,
2526
type = 'standard',
2627
headerElements,
28+
width,
2729
children,
2830
...rest
2931
}) => {
@@ -47,6 +49,8 @@ export const SideSheet: FC<SideSheetProps> = ({
4749
title={title}
4850
type="modal"
4951
headerElements={headerElements}
52+
width={width}
53+
zIndex={'zIndex' in rest ? rest.zIndex : undefined}
5054
withScrim
5155
>
5256
{children}
@@ -55,13 +59,46 @@ export const SideSheet: FC<SideSheetProps> = ({
5559
);
5660
}
5761

62+
if (type === 'modal' || type === 'floating') {
63+
return (
64+
<SideSheetContent
65+
open={open}
66+
onClose={onClose}
67+
title={title}
68+
type={type}
69+
headerElements={headerElements}
70+
width={width}
71+
zIndex={'zIndex' in rest ? rest.zIndex : undefined}
72+
>
73+
{children}
74+
</SideSheetContent>
75+
);
76+
}
77+
78+
if ('zIndex' in rest && rest.zIndex !== undefined) {
79+
return (
80+
<SideSheetContent
81+
open={open}
82+
onClose={onClose}
83+
title={title}
84+
type={'modal'}
85+
headerElements={headerElements}
86+
width={width}
87+
zIndex={rest.zIndex}
88+
>
89+
{children}
90+
</SideSheetContent>
91+
);
92+
}
93+
5894
return (
5995
<SideSheetContent
6096
open={open}
6197
onClose={onClose}
6298
title={title}
6399
type={type}
64100
headerElements={headerElements}
101+
width={width}
65102
>
66103
{children}
67104
</SideSheetContent>
@@ -74,6 +111,7 @@ function SideSheetContent({
74111
title,
75112
type = 'standard',
76113
headerElements,
114+
width,
77115
children,
78116
...rest
79117
}: SideSheetProps) {
@@ -83,6 +121,7 @@ function SideSheetContent({
83121
<Wrapper
84122
$type={type}
85123
$withShadow={!('withScrim' in rest && rest.withScrim)}
124+
$zIndex={'zIndex' in rest ? rest.zIndex : undefined}
86125
initial={{
87126
x: type !== 'standard' ? '110%' : undefined,
88127
width: type === 'standard' ? 0 : undefined,
@@ -99,7 +138,7 @@ function SideSheetContent({
99138
bounce: 0.25,
100139
}}
101140
>
102-
<Sheet $type={type}>
141+
<Sheet $type={type} $width={width}>
103142
<Header>
104143
<Typography variant="h2">{title}</Typography>
105144
{headerElements && <section>{headerElements}</section>}

src/organisms/SideSheet/SideSheet.types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { ReactElement } from 'react';
1+
import { CSSProperties, ReactElement } from 'react';
22

33
interface BaseSideSheetProps {
44
open: boolean;
55
onClose: () => void;
66
title: string;
77
headerElements?: ReactElement | ReactElement[];
8+
width?: CSSProperties['width'];
89
children: ReactElement | ReactElement[];
910
}
1011

@@ -15,10 +16,12 @@ interface StandardSideSheetProps extends BaseSideSheetProps {
1516
interface ModalSideSheetProps extends BaseSideSheetProps {
1617
type: 'modal';
1718
withScrim?: boolean;
19+
zIndex?: CSSProperties['zIndex'];
1820
}
1921

2022
interface FloatingSideSheetProps extends BaseSideSheetProps {
2123
type: 'floating';
24+
zIndex?: CSSProperties['zIndex'];
2225
}
2326

2427
export type SideSheetProps =

0 commit comments

Comments
 (0)