Skip to content

Commit

Permalink
feat: add predefined widths to the Sidebar
Browse files Browse the repository at this point in the history
Allow passing a predefined width ("xs", "s", "m", "l", "xl") when using
the Sidebar while preserving the ability to pass any other valid width
value.
  • Loading branch information
haideralsh committed Nov 1, 2023
1 parent c57516f commit 3756cfe
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 14 deletions.
29 changes: 29 additions & 0 deletions src/Layout/Sidebar.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,32 @@ export const WithALongTitle = () => {
</ApplicationFrame>
);
};

export const WithDifferentWidths = () => {
const [width, setWidth] = useState({ value: "xs", label: "Extra small (xs)" });

const options = [
{ value: "xs", label: "Extra small (xs) - Default" },
{ value: "s", label: "Small (s)" },
{ value: "m", label: "Medium (m)" },
{ value: "l", label: "Large (l)" },
{ value: "xl", label: "Extra large (xl)" },
{ value: "700px", label: "Custom value (700px)" },
{ value: "75ch", label: "Custom value (75ch)" },
{ value: "100%", label: "Custom value (100%)" },
];

return (
<Sidebar hideCloseButton top={0} height="100%" width={width.value} isOpen title={`${width.label} sidebar`}>
<Select
value={width.value}
options={options}
onChange={(s: string) => {
const [option] = options.filter(({ value }) => value === s);
setWidth(option);
}}
labelText="Sidebar size"
/>
</Sidebar>
);
};
46 changes: 32 additions & 14 deletions src/Layout/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,46 @@
import React, { useEffect, useState, useRef, RefObject } from "react";
import React, { useEffect, useState, useRef, RefObject, CSSProperties } from "react";
import { AnimatePresence } from "framer-motion";
import { useTranslation } from "react-i18next";
import { Box } from "../Box";
import { Flex } from "../Flex";
import { IconicButton } from "../Button";
import { Heading3 } from "../Type";
import { AnimatedBoxProps, AnimatedBox } from "../Box/Box";
import { NAVBAR_HEIGHT } from "../BrandedNavBar/NavBar";
import { useTranslation } from "react-i18next";
import { PreventBodyElementScrolling } from "../utils";

type SidebarProps = AnimatedBoxProps & {
type PredefinedSidebarWidth = "xs" | "s" | "m" | "l" | "xl";

// We need (string & {}) to allow passing
// custom values in addition to the predefined width
// https://twitter.com/mattpocockuk/status/1671908303918473217
// eslint-disable-next-line @typescript-eslint/ban-types
type SidebarWidth = PredefinedSidebarWidth | (string & {});

const sidebarWidths: Record<PredefinedSidebarWidth, CSSProperties["width"]> = {
xs: "400px",
s: "520px",
m: "640px",
l: "768px",
xl: "1024px",
} as const;

type SidebarProps = Omit<AnimatedBoxProps, "width"> & {
children?: React.ReactNode;
onClose?: (arg: any) => any;
onClose?: () => void;
title?: string;
isOpen?: boolean;
footer?: React.ReactNode;
closeButtonTestId?: string;
closeButtonAriaLabel?: string;
offset?: string;
triggerRef?: RefObject<any>;
triggerRef?: RefObject<HTMLInputElement | HTMLButtonElement>;
duration?: number;
closeOnOutsideClick?: boolean;
overlay?: boolean;
disableScroll?: boolean;
hideCloseButton?: boolean;
width?: SidebarWidth;
};

const focusFirstElement = () => {
Expand Down Expand Up @@ -51,10 +68,9 @@ const SidebarOverlay = ({ transitionDuration, top, transparent, zIndex = 799 as
onMouseDown={onClick}
/>
);

const Sidebar: React.FC<SidebarProps> = ({
function Sidebar({
p = "x3",
width = "400px",
width = "xs",
children,
onClose,
title,
Expand All @@ -70,15 +86,17 @@ const Sidebar: React.FC<SidebarProps> = ({
overlay = true,
disableScroll = true,
hideCloseButton = false,
zIndex,
zIndex = "sidebar" as any,
...props
}) => {
}: SidebarProps) {
const closeButton = useRef(null);
const [shouldUpdateFocus, setShouldUpdateFocus] = useState(false);
const { t } = useTranslation();
const sideBarRef = useRef(null);
const contentRef = useRef(null);

const selectedWidth = sidebarWidths[width] ?? width;

useEffect(() => {
if (closeButton.current && isOpen) {
if (closeButton && closeButton.current) {
Expand All @@ -88,7 +106,7 @@ const Sidebar: React.FC<SidebarProps> = ({
}
} else if (shouldUpdateFocus) {
if (triggerRef) {
triggerRef.current.focus();
triggerRef?.current?.focus();
} else {
focusFirstElement();
}
Expand Down Expand Up @@ -160,8 +178,8 @@ const Sidebar: React.FC<SidebarProps> = ({
position="fixed"
top={top}
right={offset}
width={typeof width === "string" ? { default: "100%", small: width } : width}
zIndex={zIndex || ("sidebar" as any)}
width={typeof selectedWidth === "string" ? { default: "100%", small: selectedWidth } : selectedWidth}
zIndex={zIndex}
ref={sideBarRef as any}
{...props}
>
Expand Down Expand Up @@ -220,6 +238,6 @@ const Sidebar: React.FC<SidebarProps> = ({
</AnimatedBox>
</>
);
};
}

export default Sidebar;

0 comments on commit 3756cfe

Please sign in to comment.