Add board Action bar and context menu (#3680)

* Add board Action bar and context menu

* Fix according to review
This commit is contained in:
Charles Bochet
2024-01-30 09:21:02 +01:00
committed by GitHub
parent c5ea2dfe1e
commit e951fb70f8
27 changed files with 404 additions and 341 deletions
@@ -9,10 +9,6 @@ import { actionBarOpenState } from '../states/actionBarIsOpenState';
import { ActionBarItem } from './ActionBarItem';
type ActionBarProps = {
selectedIds: string[];
};
const StyledContainerActionBar = styled.div`
align-items: center;
background: ${({ theme }) => theme.background.secondary};
@@ -33,30 +29,24 @@ const StyledContainerActionBar = styled.div`
z-index: 1;
`;
export const ActionBar = ({ selectedIds }: ActionBarProps) => {
export const ActionBar = () => {
const actionBarOpen = useRecoilValue(actionBarOpenState);
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
const actionBarEntries = useRecoilValue(actionBarEntriesState);
const wrapperRef = useRef<HTMLDivElement>(null);
if (selectedIds.length === 0 || !actionBarOpen || contextMenuIsOpen) {
if (!actionBarOpen || contextMenuIsOpen) {
return null;
}
return (
<StyledContainerActionBar
data-select-disable
className="action-bar"
ref={wrapperRef}
>
{actionBarEntries.map((item) => (
<ActionBarItem
Icon={item.Icon}
accent={item.accent}
label={item.label}
onClick={item.onClick}
key={item.label}
subActions={item?.subActions}
/>
{actionBarEntries.map((item, index) => (
<ActionBarItem key={index} item={item} />
))}
</StyledContainerActionBar>
);
@@ -3,22 +3,17 @@ import styled from '@emotion/styled';
import { MenuItem } from 'tsup.ui.index';
import { IconChevronDown } from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { ActionBarItemAccent } from '../types/ActionBarItemAccent';
import { ActionBarEntry } from '@/ui/navigation/action-bar/types/ActionBarEntry';
import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent';
type ActionBarItemProps = {
Icon: IconComponent;
label: string;
accent?: ActionBarItemAccent;
onClick?: () => void;
subActions?: ActionBarItemProps[];
item: ActionBarEntry;
};
const StyledButton = styled.div<{ accent: ActionBarItemAccent }>`
const StyledButton = styled.div<{ accent: MenuItemAccent }>`
border-radius: ${({ theme }) => theme.border.radius.sm};
color: ${(props) =>
props.accent === 'danger'
@@ -45,19 +40,13 @@ const StyledButtonLabel = styled.div`
margin-left: ${({ theme }) => theme.spacing(1)};
`;
export const ActionBarItem = ({
label,
Icon,
accent = 'standard',
onClick,
subActions,
}: ActionBarItemProps) => {
export const ActionBarItem = ({ item }: ActionBarItemProps) => {
const theme = useTheme();
const dropdownId = `action-bar-item-${label}`;
const dropdownId = `action-bar-item-${item.label}`;
const { toggleDropdown, closeDropdown } = useDropdown(dropdownId);
return (
<>
{Array.isArray(subActions) ? (
{Array.isArray(item.subActions) ? (
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="top-start"
@@ -65,15 +54,18 @@ export const ActionBarItem = ({
scope: dropdownId,
}}
clickableComponent={
<StyledButton accent={accent} onClick={toggleDropdown}>
{Icon && <Icon size={theme.icon.size.md} />}
<StyledButtonLabel>{label}</StyledButtonLabel>
<StyledButton
accent={item.accent ?? 'default'}
onClick={toggleDropdown}
>
{item.Icon && <item.Icon size={theme.icon.size.md} />}
<StyledButtonLabel>{item.label}</StyledButtonLabel>
<IconChevronDown size={theme.icon.size.md} />
</StyledButton>
}
dropdownComponents={
<DropdownMenuItemsContainer>
{subActions.map((subAction) => (
{item.subActions.map((subAction) => (
<MenuItem
key={subAction.label}
text={subAction.label}
@@ -88,9 +80,12 @@ export const ActionBarItem = ({
}
/>
) : (
<StyledButton accent={accent} onClick={onClick}>
{Icon && <Icon size={theme.icon.size.md} />}
<StyledButtonLabel>{label}</StyledButtonLabel>
<StyledButton
accent={item.accent ?? 'default'}
onClick={() => item.onClick?.()}
>
{item.Icon && <item.Icon size={theme.icon.size.md} />}
<StyledButtonLabel>{item.label}</StyledButtonLabel>
</StyledButton>
)}
</>
@@ -8,10 +8,10 @@ import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { actionBarOpenState } from '../../states/actionBarIsOpenState';
import { ActionBar } from '../ActionBar';
const FilledActionBar = (props: { selectedIds: string[] }) => {
const FilledActionBar = () => {
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
setActionBarOpenState(true);
return <ActionBar selectedIds={props.selectedIds} />;
return <ActionBar />;
};
const meta: Meta<typeof ActionBar> = {
@@ -1,11 +1,10 @@
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { ActionBarItemAccent } from './ActionBarItemAccent';
import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent';
export type ActionBarEntry = {
label: string;
Icon: IconComponent;
accent?: ActionBarItemAccent;
accent?: MenuItemAccent;
onClick?: () => void;
subActions?: ActionBarEntry[];
};