|
20 | 20 |
|
21 | 21 | import styled from '@emotion/styled'; |
22 | 22 | import * as radixDropdownMenu from '@radix-ui/react-dropdown-menu'; |
23 | | -import { forwardRef, ReactNode } from 'react'; |
| 23 | +import { forwardRef } from 'react'; |
| 24 | +import { LinkStandalone } from '../links'; |
| 25 | +import { LinkBaseProps } from '../links/LinkTypes'; |
24 | 26 |
|
25 | 27 | import { cssVar } from '~utils/design-tokens'; |
26 | 28 |
|
27 | 29 | export interface DropdownMenuGroupLabelProps extends radixDropdownMenu.DropdownMenuLabelProps { |
28 | 30 | /** |
29 | | - * Optional content to display at the end of the group label element. |
| 31 | + * Optional link to display at the end of the group label element. |
30 | 32 | */ |
31 | | - suffix?: ReactNode; |
| 33 | + link?: { |
| 34 | + linkElement: LinkBaseProps['children']; |
| 35 | + to: LinkBaseProps['to']; |
| 36 | + }; |
32 | 37 | } |
33 | 38 |
|
34 | 39 | export const DropdownMenuGroupLabel = forwardRef<HTMLDivElement, DropdownMenuGroupLabelProps>( |
35 | 40 | (props, ref) => { |
36 | | - const { children, suffix, ...rest } = props; |
| 41 | + const { children, link, ...rest } = props; |
37 | 42 |
|
38 | 43 | return ( |
39 | | - <StyledDropdownMenuGroupLabel ref={ref} {...rest}> |
40 | | - {/* Fragment wrapper to ensure single child structure, needed for compatibility */} |
41 | | - <> |
| 44 | + <StyledWrapper> |
| 45 | + <StyledDropdownMenuGroupLabel ref={ref} {...rest}> |
42 | 46 | {children} |
| 47 | + </StyledDropdownMenuGroupLabel> |
43 | 48 |
|
44 | | - {suffix && <StyledSuffix>{suffix}</StyledSuffix>} |
45 | | - </> |
46 | | - </StyledDropdownMenuGroupLabel> |
| 49 | + {link && ( |
| 50 | + <StyledMenuItem asChild> |
| 51 | + <StyledLink to={link.to}>{link.linkElement}</StyledLink> |
| 52 | + </StyledMenuItem> |
| 53 | + )} |
| 54 | + </StyledWrapper> |
47 | 55 | ); |
48 | 56 | }, |
49 | 57 | ); |
50 | 58 |
|
51 | 59 | DropdownMenuGroupLabel.displayName = 'DropdownMenuGroupLabel'; |
52 | 60 |
|
53 | | -const StyledDropdownMenuGroupLabel = styled(radixDropdownMenu.Label)` |
| 61 | +const StyledWrapper = styled.div` |
54 | 62 | align-items: center; |
55 | | - color: ${cssVar('color-text-default')}; |
56 | 63 | display: flex; |
57 | | - font: ${cssVar('typography-text-small-semi-bold')}; |
58 | 64 | justify-content: space-between; |
| 65 | +`; |
| 66 | + |
| 67 | +const StyledDropdownMenuGroupLabel = styled(radixDropdownMenu.Label)` |
| 68 | + color: ${cssVar('color-text-default')}; |
| 69 | + font: ${cssVar('typography-text-small-semi-bold')}; |
59 | 70 |
|
60 | 71 | padding: ${cssVar('dimension-space-100')} ${cssVar('dimension-space-150')} |
61 | 72 | ${cssVar('dimension-space-50')}; |
62 | 73 | `; |
63 | 74 |
|
64 | 75 | StyledDropdownMenuGroupLabel.displayName = 'StyledDropdownMenuGroupLabel'; |
65 | 76 |
|
66 | | -const StyledSuffix = styled.span` |
67 | | - align-items: center; |
68 | | - display: flex; |
69 | | - flex: 0 0 auto; |
70 | | - justify-content: flex-end; |
| 77 | +const StyledMenuItem = styled(radixDropdownMenu.Item)` |
| 78 | + /* With asChild, these styles apply directly to the <a> tag */ |
| 79 | + background: none; |
| 80 | + padding: ${cssVar('dimension-space-50')} ${cssVar('dimension-space-100')}; |
| 81 | +
|
| 82 | + &:hover, |
| 83 | + &[data-highlighted] { |
| 84 | + background: none; |
| 85 | + } |
71 | 86 | `; |
72 | 87 |
|
73 | | -StyledSuffix.displayName = 'StyledSuffix'; |
| 88 | +const StyledLink = styled(LinkStandalone)` |
| 89 | + /* Match the label typography (same as StyledDropdownMenuGroupLabel) */ |
| 90 | + font: ${cssVar('typography-text-small-semi-bold')}; |
| 91 | + margin-right: ${cssVar('dimension-space-100')}; |
| 92 | +
|
| 93 | + /* Show focus ring only for keyboard navigation - && needed for extra specificity */ |
| 94 | + &&:focus-visible { |
| 95 | + border-radius: ${cssVar('border-radius-200')}; |
| 96 | + outline: ${cssVar('color-focus-default')} solid ${cssVar('focus-border-width-default')}; |
| 97 | + outline-offset: ${cssVar('focus-border-offset-default')}; |
| 98 | + } |
| 99 | +
|
| 100 | + /* Hide focus ring on mouse hover - && needed for extra specificity */ |
| 101 | + &&:hover { |
| 102 | + outline: none; |
| 103 | + } |
| 104 | +`; |
0 commit comments