feat: support menu / dropdown items to have `selected` state (#7078)

This commit is contained in:
David Luzar 2023-10-03 23:35:47 +02:00 committed by GitHub
parent bfd318e765
commit 12420592ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 35 additions and 5 deletions

View File

@ -38,6 +38,7 @@ To render an item, its recommended to use `MainMenu.Item`.
| Prop | Type | Required | Default | Description |
| --- | --- | :-: | :-: | --- |
| `onSelect` | `function` | Yes | - | Triggered when selected (via mouse). Calling `event.preventDefault()` will stop menu from closing. |
| `selected` | `boolean` | No | `false` | Whether item is active |
| `children` | `React.ReactNode` | Yes | - | The content of the menu item |
| `icon` | `JSX.Element` | No | - | The icon used in the menu item |
| `shortcut` | `string` | No | - | The shortcut to be shown for the menu item |
@ -70,6 +71,7 @@ function App() {
| Prop | Type | Required | Default | Description |
| --- | --- | :-: | :-: | --- |
| `onSelect` | `function` | No | - | Triggered when selected (via mouse). Calling `event.preventDefault()` will stop menu from closing. |
| `selected` | `boolean` | No | `false` | Whether item is active |
| `href` | `string` | Yes | - | The `href` attribute to be added to the `anchor` element. |
| `children` | `React.ReactNode` | Yes | - | The content of the menu item |
| `icon` | `JSX.Element` | No | - | The icon used in the menu item |

View File

@ -318,6 +318,7 @@ export const ShapesSwitcher = ({
activeEmbeddable: null,
});
}}
selected={activeTool.type === "frame"}
/>
<ToolButton
className={clsx("Shape", { fillable: false })}
@ -348,6 +349,7 @@ export const ShapesSwitcher = ({
activeEmbeddable: null,
});
}}
selected={activeTool.type === "embeddable"}
/>
</>
) : (
@ -378,6 +380,7 @@ export const ShapesSwitcher = ({
icon={frameToolIcon}
shortcut={KEYS.F.toLocaleUpperCase()}
data-testid="toolbar-frame"
selected={activeTool.type === "frame"}
>
{t("toolBar.frame")}
</DropdownMenu.Item>
@ -394,6 +397,7 @@ export const ShapesSwitcher = ({
}}
icon={EmbedIcon}
data-testid="toolbar-embeddable"
selected={activeTool.type === "embeddable"}
>
{t("toolBar.embeddable")}
</DropdownMenu.Item>

View File

@ -59,6 +59,11 @@
height: 2.25rem;
}
&--selected {
background: var(--color-primary-light);
--icon-fill-color: var(--color-primary-darker);
}
&__text {
text-overflow: ellipsis;
overflow: hidden;

View File

@ -11,12 +11,14 @@ const DropdownMenuItem = ({
children,
shortcut,
className,
selected,
...rest
}: {
icon?: JSX.Element;
onSelect: (event: Event) => void;
children: React.ReactNode;
shortcut?: string;
selected?: boolean;
className?: string;
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onSelect">) => {
const handleClick = useHandleDropdownMenuItemClick(rest.onClick, onSelect);
@ -26,7 +28,7 @@ const DropdownMenuItem = ({
{...rest}
onClick={handleClick}
type="button"
className={getDropdownMenuItemClassName(className)}
className={getDropdownMenuItemClassName(className, selected)}
title={rest.title ?? rest["aria-label"]}
>
<MenuItemContent icon={icon} shortcut={shortcut}>

View File

@ -3,15 +3,19 @@ import React from "react";
const DropdownMenuItemCustom = ({
children,
className = "",
selected,
...rest
}: {
children: React.ReactNode;
className?: string;
selected?: boolean;
} & React.HTMLAttributes<HTMLDivElement>) => {
return (
<div
{...rest}
className={`dropdown-menu-item-base dropdown-menu-item-custom ${className}`.trim()}
className={`dropdown-menu-item-base dropdown-menu-item-custom ${className} ${
selected ? `dropdown-menu-item--selected` : ``
}`.trim()}
>
{children}
</div>

View File

@ -12,6 +12,7 @@ const DropdownMenuItemLink = ({
children,
onSelect,
className = "",
selected,
...rest
}: {
href: string;
@ -19,6 +20,7 @@ const DropdownMenuItemLink = ({
children: React.ReactNode;
shortcut?: string;
className?: string;
selected?: boolean;
onSelect?: (event: Event) => void;
} & React.AnchorHTMLAttributes<HTMLAnchorElement>) => {
const handleClick = useHandleDropdownMenuItemClick(rest.onClick, onSelect);
@ -29,7 +31,7 @@ const DropdownMenuItemLink = ({
href={href}
target="_blank"
rel="noreferrer"
className={getDropdownMenuItemClassName(className)}
className={getDropdownMenuItemClassName(className, selected)}
title={rest.title ?? rest["aria-label"]}
onClick={handleClick}
>

View File

@ -6,8 +6,13 @@ export const DropdownMenuContentPropsContext = React.createContext<{
onSelect?: (event: Event) => void;
}>({});
export const getDropdownMenuItemClassName = (className = "") => {
return `dropdown-menu-item dropdown-menu-item-base ${className}`.trim();
export const getDropdownMenuItemClassName = (
className = "",
selected = false,
) => {
return `dropdown-menu-item dropdown-menu-item-base ${className} ${
selected ? "dropdown-menu-item--selected" : ""
}`.trim();
};
export const useHandleDropdownMenuItemClick = (

View File

@ -11,6 +11,12 @@ The change should be grouped under one of the below section and must contain PR
Please add the latest change on the top under the correct section.
-->
## Unreleased
### Features
- Add `selected` prop for `MainMenu.Item` and `MainMenu.ItemCustom` components to indicate active state. [7078](https://github.com/excalidraw/excalidraw/pull/7078)
## 0.16.1 (2023-09-21)
## Excalidraw Library