1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-18 21:35:51 -04:00
Files
Radarr/frontend/src/Components/Page/Toolbar/PageToolbarSection.tsx
T

156 lines
4.4 KiB
TypeScript

import classNames from 'classnames';
import React, { ReactElement, useMemo } from 'react';
import Menu from 'Components/Menu/Menu';
import MenuContent from 'Components/Menu/MenuContent';
import ToolbarMenuButton from 'Components/Menu/ToolbarMenuButton';
import useMeasure from 'Helpers/Hooks/useMeasure';
import { icons } from 'Helpers/Props';
import { Align } from 'Helpers/Props/align';
import dimensions from 'Styles/Variables/dimensions';
import translate from 'Utilities/String/translate';
import { PageToolbarButtonProps } from './PageToolbarButton';
import PageToolbarOverflowMenuItem from './PageToolbarOverflowMenuItem';
import styles from './PageToolbarSection.css';
const BUTTON_WIDTH = parseInt(dimensions.toolbarButtonWidth);
const SEPARATOR_MARGIN = parseInt(dimensions.toolbarSeparatorMargin);
const SEPARATOR_WIDTH = 2 * SEPARATOR_MARGIN + 1;
export interface PageToolbarSectionProps {
children?:
| (ReactElement<PageToolbarButtonProps> | ReactElement<never> | null)
| (ReactElement<PageToolbarButtonProps> | ReactElement<never> | null)[];
alignContent?: Extract<Align, keyof typeof styles>;
collapseButtons?: boolean;
}
function PageToolbarSection({
children,
alignContent = 'left',
collapseButtons = true,
}: PageToolbarSectionProps) {
const [sectionRef, { width }] = useMeasure();
const isMeasured = width > 0;
const { buttons, buttonCount, overflowItems } = useMemo(() => {
let buttonCount = 0;
let separatorCount = 0;
const validChildren: ReactElement[] = [];
React.Children.forEach(children, (child) => {
if (!child) {
return;
}
if (Object.keys(child.props).length === 0) {
separatorCount++;
} else {
buttonCount++;
}
validChildren.push(child);
});
const buttonsWidth = buttonCount * BUTTON_WIDTH;
const separatorsWidth = separatorCount + SEPARATOR_WIDTH;
const totalWidth = buttonsWidth + separatorsWidth;
// If the width of buttons and separators is less than
// the available width return all valid children.
if (!isMeasured || !collapseButtons || totalWidth < width) {
return {
buttons: validChildren,
buttonCount,
overflowItems: [],
};
}
const maxButtons = Math.max(
Math.floor((width - separatorsWidth) / BUTTON_WIDTH),
1
);
const buttons: ReactElement<PageToolbarButtonProps>[] = [];
const overflowItems: PageToolbarButtonProps[] = [];
let actualButtons = 0;
// Return all buttons if only one is being pushed to the overflow menu.
if (buttonCount - 1 === maxButtons) {
const overflowItems: PageToolbarButtonProps[] = [];
const buttonsWithoutSeparators = validChildren.filter(
(child) => Object.keys(child.props).length > 0
);
return {
buttons: buttonsWithoutSeparators,
buttonCount,
overflowItems,
};
}
validChildren.forEach((child) => {
const isSeparator = Object.keys(child.props).length === 0;
if (actualButtons < maxButtons) {
if (!isSeparator) {
buttons.push(child);
actualButtons++;
}
} else if (!isSeparator) {
overflowItems.push(child.props);
}
});
return {
buttons,
buttonCount,
overflowItems,
};
}, [children, isMeasured, width, collapseButtons]);
return (
<div
ref={sectionRef}
className={styles.sectionContainer}
style={{
flexGrow: buttonCount,
}}
>
{isMeasured ? (
<div className={classNames(styles.section, styles[alignContent])}>
{buttons.map((button) => {
return button;
})}
{overflowItems.length ? (
<Menu>
<ToolbarMenuButton
className={styles.overflowMenuButton}
iconName={icons.OVERFLOW}
text={translate('More')}
/>
<MenuContent>
{overflowItems.map((item) => {
const {
label,
overflowComponent:
OverflowComponent = PageToolbarOverflowMenuItem,
} = item;
return <OverflowComponent key={label} {...item} />;
})}
</MenuContent>
</Menu>
) : null}
</div>
) : null}
</div>
);
}
export default PageToolbarSection;