Skip to content

Commit b3d3754

Browse files
author
olaslo
committed
feat: added scroll for navigation items
1 parent ad3a217 commit b3d3754

File tree

5 files changed

+140
-156
lines changed

5 files changed

+140
-156
lines changed

src/components/AsideHeader/__stories__/AsideHeader.stories.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {PageLayout} from '../components/PageLayout/PageLayout';
99
import {PageLayoutAside} from '../components/PageLayout/PageLayoutAside';
1010

1111
import {AsideHeaderShowcase} from './AsideHeaderShowcase';
12-
import {DEFAULT_LOGO, menuItemsClamped, menuItemsShowcase} from './moc';
12+
import {DEFAULT_LOGO, menuItemsClamped, menuItemsMany, menuItemsShowcase} from './moc';
1313

1414
import logoIcon from '../../../../.storybook/assets/logo.svg';
1515

@@ -237,3 +237,48 @@ export const CollapseButtonWrapper = CollapseButtonWrapperTemplate.bind({});
237237
CollapseButtonWrapper.args = {
238238
initialCompact: false,
239239
};
240+
241+
const ManyItemsTemplate: StoryFn = (args) => {
242+
const [compact, setCompact] = React.useState<boolean>(args.initialCompact);
243+
244+
return (
245+
<PageLayout compact={compact}>
246+
<PageLayoutAside
247+
headerDecoration
248+
menuItems={menuItemsMany}
249+
logo={DEFAULT_LOGO}
250+
onChangeCompact={setCompact}
251+
{...args}
252+
/>
253+
254+
<PageLayout.Content>
255+
<div style={{padding: 16}}>
256+
<Button onClick={() => setCompact((prev) => !prev)}>Toggle compact</Button>
257+
<div style={{marginTop: 16}}>
258+
<Text variant="subheader-2">
259+
Scroll demonstration with many navigation items
260+
</Text>
261+
<Text color="secondary" style={{marginTop: 8}}>
262+
Total items: {menuItemsMany?.length || 0}. On low screens, items scroll
263+
with invisible scrollbar instead of collapsing into &quot;...&quot;
264+
</Text>
265+
</div>
266+
</div>
267+
</PageLayout.Content>
268+
</PageLayout>
269+
);
270+
};
271+
272+
export const ManyItems = ManyItemsTemplate.bind({});
273+
ManyItems.args = {
274+
initialCompact: false,
275+
};
276+
ManyItems.parameters = {
277+
docs: {
278+
description: {
279+
story:
280+
'Demonstration of scroll functionality with many navigation items. ' +
281+
'On low screens, all items remain accessible through scrolling with invisible scrollbar.',
282+
},
283+
},
284+
};

src/components/AsideHeader/__stories__/moc.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,68 @@ export const menuItemsClamped = MENU_ITEMS_CLAMPED.concat({
158158
rightAdornment: renderTag('new'),
159159
})),
160160
);
161+
162+
export const generateManyMenuItems = (count = 20): AsideHeaderProps['menuItems'] => {
163+
const items: AsideHeaderProps['menuItems'] = [];
164+
165+
const sections = [
166+
'Dashboard',
167+
'Analytics',
168+
'Reports',
169+
'Settings',
170+
'Users',
171+
'Projects',
172+
'Tasks',
173+
'Calendar',
174+
'Messages',
175+
'Files',
176+
'Help',
177+
'Support',
178+
];
179+
180+
sections.forEach((section, index) => {
181+
items.push({
182+
id: `section-${index}`,
183+
title: section,
184+
icon: Gear,
185+
current: index === 0,
186+
onItemClick(_item) {},
187+
});
188+
189+
if (index % 3 === 0) {
190+
const subItems = [`${section} Overview`, `${section} Details`, `${section} Settings`];
191+
192+
subItems.forEach((subItem, subIndex) => {
193+
items.push({
194+
id: `section-${index}-sub-${subIndex}`,
195+
title: subItem,
196+
icon: Gear,
197+
onItemClick(_item) {},
198+
});
199+
});
200+
}
201+
202+
if ((index + 1) % 4 === 0 && index < sections.length - 1) {
203+
items.push({
204+
id: `divider-${index}`,
205+
title: '-',
206+
type: 'divider',
207+
});
208+
}
209+
});
210+
211+
const additionalCount = Math.max(0, count - items.length);
212+
for (let i = 0; i < additionalCount; i++) {
213+
items.push({
214+
id: `additional-${i}`,
215+
title: `Additional Item ${i + 1}`,
216+
icon: Gear,
217+
rightAdornment: i % 5 === 0 ? renderTag('New') : undefined,
218+
onItemClick(_item) {},
219+
});
220+
}
221+
222+
return items;
223+
};
224+
225+
export const menuItemsMany = generateManyMenuItems(25);

src/components/AsideHeader/components/CompositeBar/CompositeBar.scss

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,24 @@ $block: '.#{variables.$ns}composite-bar';
55
#{$block} {
66
$class: &;
77

8-
flex: 1 0 auto;
8+
flex: 1 1 auto;
99
width: 100%;
1010
min-height: 40px;
11+
display: flex;
12+
flex-direction: column;
1113

1214
& &__root-menu-item[class] {
1315
background-color: transparent;
1416
}
17+
18+
&_scrollable {
19+
flex: 1 1 auto;
20+
overflow-y: auto;
21+
scrollbar-width: none;
22+
-ms-overflow-style: none;
23+
24+
&::-webkit-scrollbar {
25+
display: none;
26+
}
27+
}
1528
}

src/components/AsideHeader/components/CompositeBar/CompositeBar.tsx

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, {FC, ReactNode, useCallback, useContext, useRef} from 'react';
22

33
import {List} from '@gravity-ui/uikit';
4-
import AutoSizer, {Size} from 'react-virtualized-auto-sizer';
54

65
import {ASIDE_HEADER_COMPACT_WIDTH} from '../../../constants';
76
import {block} from '../../../utils/cn';
@@ -10,14 +9,7 @@ import {AsideHeaderItem} from '../../types';
109
import {Item, ItemProps} from './Item/Item';
1110
import {MultipleTooltip, MultipleTooltipContext, MultipleTooltipProvider} from './MultipleTooltip';
1211
import {COLLAPSE_ITEM_ID} from './constants';
13-
import {
14-
getAutosizeListItems,
15-
getItemHeight,
16-
getItemsHeight,
17-
getItemsMinHeight,
18-
getMoreButtonItem,
19-
getSelectedItemIndex,
20-
} from './utils';
12+
import {getItemHeight, getItemsHeight, getSelectedItemIndex} from './utils';
2113

2214
import './CompositeBar.scss';
2315

@@ -39,7 +31,6 @@ export type CompositeBarProps = {
3931
};
4032

4133
type CompositeBarViewProps = CompositeBarProps & {
42-
collapseItems?: AsideHeaderItem[];
4334
compositeId?: string;
4435
};
4536

@@ -48,7 +39,6 @@ const CompositeBarView: FC<CompositeBarViewProps> = ({
4839
items,
4940
onItemClick,
5041
onMoreClick,
51-
collapseItems,
5242
multipleTooltip = false,
5343
compact,
5444
compositeId,
@@ -220,7 +210,6 @@ const CompositeBarView: FC<CompositeBarViewProps> = ({
220210
onMouseEnter={onMouseEnterByIndex(itemIndex)}
221211
onMouseLeave={onMouseLeave}
222212
onItemClick={onItemClickByIndex(itemIndex, item.onItemClick)}
223-
collapseItems={collapseItems}
224213
/>
225214
)}
226215
/>
@@ -240,7 +229,6 @@ const CompositeBarView: FC<CompositeBarViewProps> = ({
240229
export const CompositeBar: FC<CompositeBarProps> = ({
241230
type,
242231
items,
243-
menuMoreTitle,
244232
onItemClick,
245233
onMoreClick,
246234
multipleTooltip = false,
@@ -253,38 +241,17 @@ export const CompositeBar: FC<CompositeBarProps> = ({
253241
let node: ReactNode;
254242

255243
if (type === 'menu') {
256-
const minHeight = getItemsMinHeight(items);
257-
const collapseItem = getMoreButtonItem(menuMoreTitle);
258244
node = (
259-
<div className={b({autosizer: true})} style={{minHeight}}>
260-
{items.length !== 0 && (
261-
<AutoSizer>
262-
{(size: Size) => {
263-
const width = Number.isNaN(size.width) ? 0 : size.width;
264-
const height = Number.isNaN(size.height) ? 0 : size.height;
265-
266-
const {listItems, collapseItems} = getAutosizeListItems(
267-
items,
268-
height,
269-
collapseItem,
270-
);
271-
return (
272-
<div style={{width, height}}>
273-
<CompositeBarView
274-
compositeId={compositeId}
275-
type="menu"
276-
compact={compact}
277-
items={listItems}
278-
onItemClick={onItemClick}
279-
onMoreClick={onMoreClick}
280-
collapseItems={collapseItems}
281-
multipleTooltip={multipleTooltip}
282-
/>
283-
</div>
284-
);
285-
}}
286-
</AutoSizer>
287-
)}
245+
<div className={b({scrollable: true})}>
246+
<CompositeBarView
247+
compositeId={compositeId}
248+
type="menu"
249+
compact={compact}
250+
items={items}
251+
onItemClick={onItemClick}
252+
onMoreClick={onMoreClick}
253+
multipleTooltip={multipleTooltip}
254+
/>
288255
</div>
289256
);
290257
} else {

0 commit comments

Comments
 (0)