From a9cfaa6eed31c3d73094f585f9ab7fac9f3a28a8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 11 Apr 2025 12:50:46 +0200 Subject: [PATCH] Add dropdown menu to hashtag links in web UI (#34393) --- .../mastodon/components/dropdown_menu.tsx | 51 ++++-- .../components/edited_timestamp/index.tsx | 4 +- .../mastodon/components/hashtag_bar.tsx | 17 +- .../mastodon/components/status_content.jsx | 1 + .../ui/components/hashtag_menu_controller.tsx | 157 ++++++++++++++++++ app/javascript/mastodon/features/ui/index.jsx | 2 + app/javascript/mastodon/locales/en.json | 3 + 7 files changed, 213 insertions(+), 22 deletions(-) create mode 100644 app/javascript/mastodon/features/ui/components/hashtag_menu_controller.tsx diff --git a/app/javascript/mastodon/components/dropdown_menu.tsx b/app/javascript/mastodon/components/dropdown_menu.tsx index fc3e9e1321..886d517fa9 100644 --- a/app/javascript/mastodon/components/dropdown_menu.tsx +++ b/app/javascript/mastodon/components/dropdown_menu.tsx @@ -71,6 +71,8 @@ type RenderItemFn = ( }, ) => React.ReactNode; +type ItemClickFn = (item: Item, index: number) => void; + type RenderHeaderFn = (items: Item[]) => React.ReactNode; interface DropdownMenuProps { @@ -81,10 +83,10 @@ interface DropdownMenuProps { openedViaKeyboard: boolean; renderItem?: RenderItemFn; renderHeader?: RenderHeaderFn; - onItemClick: (e: React.MouseEvent | React.KeyboardEvent) => void; + onItemClick?: ItemClickFn; } -const DropdownMenu = ({ +export const DropdownMenu = ({ items, loading, scrollable, @@ -176,20 +178,35 @@ const DropdownMenu = ({ [], ); + const handleItemClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const i = Number(e.currentTarget.getAttribute('data-index')); + const item = items?.[i]; + + onClose(); + + if (!item) { + return; + } + + if (typeof onItemClick === 'function') { + e.preventDefault(); + onItemClick(item, i); + } else if (isActionItem(item)) { + e.preventDefault(); + item.action(); + } + }, + [onClose, onItemClick, items], + ); + const handleItemKeyUp = useCallback( (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { - onItemClick(e); + handleItemClick(e); } }, - [onItemClick], - ); - - const handleClick = useCallback( - (e: React.MouseEvent | React.KeyboardEvent) => { - onItemClick(e); - }, - [onItemClick], + [handleItemClick], ); const nativeRenderItem = (option: Item, i: number) => { @@ -209,7 +226,7 @@ const DropdownMenu = ({ element = (