Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions packages/@react-spectrum/s2/src/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@ const sidePanelStyle = style(
display: 'flex',
flexDirection: 'column',
height: 'full',
minHeight: 0,
// The expanded width is supplied by the consumer via the `styles` prop. When collapsed, SidePanel
// applies an inline `width: var(--collapsedWidth)` (the fixed icon-rail size) which overrides that
// class-based width.
Expand Down Expand Up @@ -857,7 +858,8 @@ export const SidePanel = /*#__PURE__*/ forwardRef(function SidePanel(
flexShrink: 1,
minHeight: 0,
display: 'flex',
flexDirection: 'column'
flexDirection: 'column',
height: 'full'
})}>
{children}
</div>
Expand All @@ -874,28 +876,14 @@ function ExpandButton(props: {isCollapsed: boolean; setCollapsed: (isCollapsed:

let label = stringFormatter.format(`sidepanel.${props.isCollapsed ? 'expand' : 'collapse'}`);

return (
<PanelToggleButton
isCollapsed={props.isCollapsed}
setCollapsed={props.setCollapsed}
aria-label={label}
/>
);
}

function PanelToggleButton(
props: AriaLabelingProps & {
isCollapsed: boolean;
setCollapsed: (isCollapsed: boolean) => void;
}
) {
let {isCollapsed, setCollapsed, ...otherProps} = props;
let [isHovered, setHovered] = useState(false);
let {hoverProps} = useHover({onHoverChange: setHovered});
return (
<div {...hoverProps} className={style({display: 'contents', marginBottom: 2})}>
<ActionButton
{...otherProps}
aria-label={label}
isQuiet
styles={style({alignSelf: 'start'})}
onPress={() => {
Expand Down
128 changes: 120 additions & 8 deletions packages/@react-spectrum/s2/stories/SideNav.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,7 @@ export const SidePanelExample = {
<SidePanel
defaultCollapsed
styles={style({gridArea: 'sidebar', marginStart: '[6px]', marginEnd: '[10px]', width: 224})}
{...args}
aria-label="Side panel"
defaultExpandedKeys={['projects']}>
aria-label="Side panel">
<SidePanelContext.Consumer>
{({isCollapsed}) => (
<div className={style({display: 'flex', flexDirection: 'column', gap: 2})}>
Expand All @@ -641,7 +639,11 @@ export const SidePanelExample = {
</div>
)}
</SidePanelContext.Consumer>
<RoutedSideNav {...args} styles={style({width: 'full'})} selectedRoute="/files">
<RoutedSideNav
{...args}
styles={style({width: 'full'})}
selectedRoute="/files"
defaultExpandedKeys={['projects']}>
<SideNavItem href="/files" textValue="Files">
<SideNavItemContent>
<SideNavItemLink>
Expand All @@ -668,7 +670,7 @@ export const SidePanelExample = {
</SideNavItem>
<SideNavSection>
<SideNavHeader>Work</SideNavHeader>
<SideNavItem href="/projects" textValue="Projects">
<SideNavItem href="/projects" id="projects" textValue="Projects">
<SideNavItemContent>
<SideNavItemLink>
<Project />
Expand Down Expand Up @@ -749,9 +751,7 @@ export const SidePanelExample2 = {
<SidePanel
defaultCollapsed
styles={style({gridArea: 'sidebar', marginStart: '[6px]', marginEnd: '[10px]', width: 224})}
{...args}
aria-label="Side panel"
defaultExpandedKeys={['projects']}>
aria-label="Side panel">
<RoutedSideNav {...args} selectedRoute="/files">
<SideNavItem href="/files" textValue="Files">
<SideNavItemContent>
Expand Down Expand Up @@ -794,3 +794,115 @@ export const SidePanelExample2 = {
}
}
};

// The SidePanel is a flex column, so the nav has to grow and let its SideNav child shrink.
const sidePanelNav = style({
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
flexShrink: 1,
minHeight: 0
});

export const SidePanelWithNav = {
render: args => (
<div
className={style({
width: 'full',
height: '100vh',
display: 'grid',
gridTemplateAreas: ['header header', 'sidebar main'],
gridTemplateColumns: 'auto 1fr',
gridTemplateRows: 'auto 1fr',
backgroundColor: 'layer-1'
})}>
<div
className={style({
gridArea: 'header',
display: 'flex',
alignItems: 'center',
paddingX: 8,
paddingY: 16
})}>
<AdobeLogo size={28} />
</div>
<SidePanel
styles={style({
gridArea: 'sidebar',
marginStart: '[6px]',
marginEnd: '[10px]',
width: 224
})}>
<nav aria-label="Main" className={sidePanelNav}>
<RoutedSideNav {...args} selectedRoute="/files" defaultExpandedKeys={['projects']}>
<SideNavItem href="/files" textValue="Files">
<SideNavItemContent>
<SideNavItemLink>
<Files />
<Text>Your files</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
<SideNavItem id="your-libraries" href="/your-libraries" textValue="Your Libraries">
<SideNavItemContent>
<SideNavItemLink>
<CCLibrary />
<Text>Your Libraries</Text>
</SideNavItemLink>
</SideNavItemContent>
<SideNavItem id="photos" href="/photos" textValue="Photos">
<SideNavItemContent>
<SideNavItemLink>
<Images />
<Text>Photos</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
</SideNavItem>
<SideNavSection>
<SideNavHeader>Work</SideNavHeader>
<SideNavItem href="/projects" id="projects" textValue="Projects">
<SideNavItemContent>
<SideNavItemLink>
<Project />
<Text>Projects</Text>
</SideNavItemLink>
</SideNavItemContent>
<SideNavItem href="/projects-2" textValue="Projects-2">
<SideNavItemContent>
<SideNavItemLink>
<Text>Projects-2</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
</SideNavItem>
</SideNavSection>
</RoutedSideNav>
</nav>
<SidePanelExtraControls />
</SidePanel>
<main
className={style({
gridArea: 'main',
backgroundColor: 'layer-2',
borderTopStartRadius: 'lg',
padding: 16
})}>
<Heading level={2} styles={style({font: 'heading', marginTop: 0})}>
Workspace
</Heading>
<Text styles={style({font: 'body'})}>
The SideNav is wrapped in a nav element inside the SidePanel, so only the navigation is
exposed as a navigation landmark. The panel's other chrome stays outside of it.
</Text>
</main>
</div>
),
name: 'Side Panel with nav',
parameters: {
layout: 'fullscreen',
docs: {
disable: true
}
}
};
8 changes: 7 additions & 1 deletion packages/dev/s2-docs/pages/s2/SidePanel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,9 @@ import {SidePanelApp, AccountFooter} from './SidePanelApp';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import File from '@react-spectrum/s2/icons/File';
import Files from '@react-spectrum/s2/icons/Files';
import Folder from '@react-spectrum/s2/icons/Folder';
import Images from '@react-spectrum/s2/icons/Images';
import Archive from '@react-spectrum/s2/icons/Archive';
import Folder from '@react-spectrum/s2/icons/Folder';

///- begin collapse -///
interface Item {
Expand All @@ -229,6 +230,11 @@ let items: Item[] = [
{id: 5, title: 'Photos', type: 'directory', href: '/photos', icon: Images, children: [
{id: 6, title: 'Image 1', type: 'file', href: '/image-1'},
{id: 7, title: 'Image 2', type: 'file', href: '/image-2'}
]},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noticed that expanding/collapsing folders in https://d1pzu54gtk2aed.cloudfront.net/pr/7c06a74e94914ff5a707926cb3f649b8e6f1b518/SidePanel#animations to make the sidepanel scrollable causes the items to briefly appear behind the user profile

Screen.Recording.2026-09-29.at.11.42.57.AM.mov

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i noticed that yesterday as well, I think we're ok for alpha, but I'm working on figuring it out

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, approved

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

working on it here #10684

{id: 8, title: 'Archive', type: 'directory', href: '/archive', icon: Archive, children: [
{id: 9, title: 'Invoices', type: 'file', href: '/invoices'},
{id: 10, title: 'Contracts', type: 'file', href: '/contracts'},
{id: 11, title: 'Receipts', type: 'file', href: '/receipts'}
]}
];
///- end collapse -///
Expand Down
4 changes: 3 additions & 1 deletion packages/dev/s2-docs/pages/s2/SidePanelApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ export function AccountFooter(): ReactNode {
padding: 4,
flexShrink: 0
})({isCollapsed})}>
<Avatar alt="Jordan Rivera" src="https://i.imgur.com/xIe7Wlb.png" size={24} />
<ActionButton isQuiet>
<Avatar alt="Jordan Rivera" src="https://i.imgur.com/xIe7Wlb.png" size={24} />
</ActionButton>
<div
className={style({
display: {default: 'block', isCollapsed: 'none'},
Expand Down
Loading