Skip to content

Commit

Permalink
chore(sidebar): improve animation and scrollbar styles (#3303)
Browse files Browse the repository at this point in the history
* chore(sidebar): pad scrollbar from top, shrink scrollbar width, fix padding on compact

* chore: animation and scrollbar fixes
  • Loading branch information
TheSisb committed Jun 30, 2023
1 parent d23621b commit 6d38405
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .changeset/real-geese-bake.md
@@ -0,0 +1,6 @@
---
'@twilio-paste/sidebar': patch
'@twilio-paste/core': patch
---

[Sidebar] fix flicker in animation when expanding/collapsing the sidebar in compact mode. Reduce width of custom scrollbar and add margin-top.
Expand Up @@ -4,6 +4,7 @@ import type {BoxProps} from '@twilio-paste/box';
import {styled, css} from '@twilio-paste/styling-library';
import type {ThemeShape} from '@twilio-paste/theme';

import {SidebarContext} from '../SidebarContext';
import {SidebarNavigationContext} from './SidebarNavigationContext';

/**
Expand All @@ -25,10 +26,11 @@ const SidebarNavigationWrapper = styled.div(({theme}: {theme: ThemeShape}) => {
backgroundAttachment: `local, local, scroll, scroll`,
// Scrollbar
'::-webkit-scrollbar': {
width: '10px',
width: '6px',
},
// Track
'::-webkit-scrollbar-track': {
marginTop: '8px',
background: colorBackgroundInverse,
},
// Handle
Expand All @@ -52,6 +54,8 @@ export interface SidebarNavigationProps extends React.HTMLAttributes<HTMLDivElem

export const SidebarNavigation = React.forwardRef<HTMLDivElement, SidebarNavigationProps>(
({element = 'SIDEBAR_NAVIGATION', hideItemsOnCollapse = false, hierarchical = false, children, ...props}, ref) => {
const {collapsed} = React.useContext(SidebarContext);

return (
<SidebarNavigationContext.Provider
value={{
Expand All @@ -69,7 +73,8 @@ export const SidebarNavigation = React.forwardRef<HTMLDivElement, SidebarNavigat
overflowY="auto"
overflowX="hidden"
paddingY="space50"
paddingX="space60"
paddingLeft="space60"
paddingRight={collapsed ? 'space40' : 'space60'}
flexGrow={1}
>
{children}
Expand Down
Expand Up @@ -6,6 +6,7 @@ import {DisclosurePrimitive} from '@twilio-paste/disclosure-primitive';
import type {BoxProps} from '@twilio-paste/box';
import {useTheme} from '@twilio-paste/theme';

import {SidebarContext} from '../SidebarContext';
import {SidebarNavigationDisclosureContext} from './SidebarNavigationDisclosureContext';
import {
sidebarNavigationLabelStyles,
Expand All @@ -22,10 +23,26 @@ export interface SidebarNavigationDisclosureHeadingProps extends React.Component

const StyledDisclosureHeading = React.forwardRef<HTMLDivElement, SidebarNavigationDisclosureHeadingProps>(
({children, element = 'SIDEBAR_NAVIGATION_DISCLOSURE_HEADING', selected, icon, ...props}, ref) => {
const {collapsed, variant} = React.useContext(SidebarContext);
const [shouldIconMove, setShouldIconMove] = React.useState(false);
const {nested} = React.useContext(SidebarNavigationDisclosureContext);
const isExpanded = props['aria-expanded'];
const theme = useTheme();
const isCompact = variant === 'compact';
const [visible, setVisible] = React.useState(!isCompact ? true : !isExpanded);
const timeout = React.useRef(0);

React.useEffect(() => {
clearTimeout(timeout.current);
// If not compact mode, we don't show/hide item titles
if (!isCompact) {
return;
}
// @ts-expect-error timeout is a number
timeout.current = setTimeout(() => {
setVisible(!collapsed);
}, 120);
}, [collapsed, isCompact]);

return (
<Box
Expand All @@ -52,8 +69,16 @@ const StyledDisclosureHeading = React.forwardRef<HTMLDivElement, SidebarNavigati
<ChevronDisclosureIcon color="inherit" decorative size="sizeIcon20" />
</Box>
{icon ? icon : null}
<Box as="span" display="block" marginLeft="space20">
{children}
<Box
as="span"
display="block"
marginLeft="space20"
transition="all 120ms ease"
float={visible ? 'none' : 'left'}
opacity={visible ? 1 : 0}
whiteSpace={visible ? 'normal' : 'nowrap'}
>
{collapsed ? null : children}
</Box>
</Box>
);
Expand Down
Expand Up @@ -25,9 +25,26 @@ export interface SidebarNavigationItemProps extends React.HTMLAttributes<HTMLAnc

const SidebarNavigationItem = React.forwardRef<HTMLAnchorElement, SidebarNavigationItemProps>(
({element = 'SIDEBAR_NAVIGATION_ITEM', selected, children, icon, ...props}, ref) => {
const {collapsed} = React.useContext(SidebarContext);
const {collapsed, variant} = React.useContext(SidebarContext);
const {disclosure} = React.useContext(SidebarNavigationDisclosureContext);
const {hideItemsOnCollapse, hierarchical} = React.useContext(SidebarNavigationContext);
const isCompact = variant === 'compact';
const [visible, setVisible] = React.useState(!isCompact ? true : !collapsed);
const timeout = React.useRef(0);

React.useEffect(() => {
clearTimeout(timeout.current);
// If not compact mode, we don't show/hide item titles
if (!isCompact) {
return;
}

// @ts-expect-error timeout is a number
timeout.current = setTimeout(() => {
setVisible(!collapsed);
}, 120);
}, [collapsed, isCompact]);

// If there is any disclosure context, that indicates that this component is nested
const isNested = disclosure != null;

Expand All @@ -39,6 +56,7 @@ const SidebarNavigationItem = React.forwardRef<HTMLAnchorElement, SidebarNavigat
...(collapsed && sidebarNavigationItemCollapsedStyles),
...(selected && sidebarNavigationItemSelectedStyles),
display: collapsed && hideItemsOnCollapse ? 'none' : 'flex',
width: collapsed ? '36px' : '100%',
}),
[isNested, selected, collapsed, hideItemsOnCollapse, hierarchical]
);
Expand All @@ -55,7 +73,16 @@ const SidebarNavigationItem = React.forwardRef<HTMLAnchorElement, SidebarNavigat
<Box as="span" color={selected ? 'colorTextInverse' : 'colorTextIconInverse'}>
{icon}
</Box>
{collapsed ? null : children}
<Box
as="span"
display="block"
transition="all 120ms ease"
float={visible ? 'none' : 'left'}
opacity={visible ? 1 : 0}
whiteSpace={visible ? 'normal' : 'nowrap'}
>
{collapsed ? null : children}
</Box>
</Box>
);
}
Expand Down

0 comments on commit 6d38405

Please sign in to comment.