/* * SonarQube * Copyright (C) 2009-2023 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { css } from '@emotion/react'; import styled from '@emotion/styled'; import classNames from 'classnames'; import React from 'react'; import tw from 'twin.macro'; import { INPUT_SIZES } from '../helpers/constants'; import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; import { InputSizeKeys, ThemedProps } from '../types/theme'; import { Checkbox } from './Checkbox'; import { BaseLink, LinkProps } from './Link'; import NavLink from './NavLink'; import { RadioButton } from './RadioButton'; import Tooltip from './Tooltip'; import { ClipboardBase } from './clipboard'; interface Props extends React.HtmlHTMLAttributes { children?: React.ReactNode; className?: string; innerRef?: React.Ref; maxHeight?: string; size?: InputSizeKeys; } export function DropdownMenu({ children, className, innerRef, maxHeight = 'inherit', size = 'small', ...menuProps }: Props) { return ( {children} ); } interface ListItemProps { children?: React.ReactNode; className?: string; innerRef?: React.Ref; onFocus?: VoidFunction; onPointerEnter?: VoidFunction; onPointerLeave?: VoidFunction; } type ItemLinkProps = Omit & Pick & { innerRef?: React.Ref; }; export function ItemLink(props: ItemLinkProps) { const { children, className, disabled, icon, isExternal, onClick, innerRef, to, ...liProps } = props; return (
  • {children}
  • ); } interface ItemNavLinkProps extends ItemLinkProps { end?: boolean; } export function ItemNavLink(props: ItemNavLinkProps) { const { children, className, disabled, end, icon, onClick, innerRef, to, ...liProps } = props; return (
  • {icon} {children}
  • ); } interface ItemButtonProps extends ListItemProps { disabled?: boolean; icon?: React.ReactNode; onClick: React.MouseEventHandler; } export function ItemButton(props: ItemButtonProps) { const { children, className, disabled, icon, innerRef, onClick, ...liProps } = props; return (
  • {icon} {children}
  • ); } export const ItemDangerButton = styled(ItemButton)` --color: ${themeContrast('dropdownMenuDanger')}; `; interface ItemCheckboxProps extends ListItemProps { checked: boolean; disabled?: boolean; id?: string; onCheck: (checked: boolean, id?: string) => void; } export function ItemCheckbox(props: ItemCheckboxProps) { const { checked, children, className, disabled, id, innerRef, onCheck, onFocus, ...liProps } = props; return (
  • {children}
  • ); } interface ItemRadioButtonProps extends ListItemProps { checked: boolean; disabled?: boolean; onCheck: (value: string) => void; value: string; } export function ItemRadioButton(props: ItemRadioButtonProps) { const { checked, children, className, disabled, innerRef, onCheck, value, ...liProps } = props; return (
  • {children}
  • ); } interface ItemCopyProps { children?: React.ReactNode; className?: string; copyValue: string; tooltipOverlay: React.ReactNode; } export function ItemCopy(props: ItemCopyProps) { const { children, className, copyValue, tooltipOverlay } = props; return ( {({ setCopyButton, copySuccess }) => (
  • {children}
  • )}
    ); } interface ItemDownloadProps extends ListItemProps { download: string; href: string; } export function ItemDownload(props: ItemDownloadProps) { const { children, className, download, href, innerRef, ...liProps } = props; return (
  • {children}
  • ); } export const ItemHeaderHighlight = styled.span` color: ${themeContrast('searchHighlight')}; font-weight: 600; `; export const ItemHeader = styled.li` background-color: ${themeColor('dropdownMenuHeader')}; color: ${themeContrast('dropdownMenuHeader')}; ${tw`sw-py-2 sw-px-3`} `; ItemHeader.defaultProps = { className: 'dropdown-menu-header', role: 'menuitem' }; export const ItemDivider = styled.li` height: 1px; background-color: ${themeColor('popupBorder')}; ${tw`sw-my-1 sw--mx-2`} ${tw`sw-overflow-hidden`}; `; ItemDivider.defaultProps = { role: 'separator' }; const DropdownMenuWrapper = styled.ul` background-color: ${themeColor('dropdownMenu')}; color: ${themeContrast('dropdownMenu')}; width: var(--inputSize); list-style: none; ${tw`sw-flex sw-flex-col`} ${tw`sw-box-border`}; ${tw`sw-min-w-input-small`} ${tw`sw-py-2`} ${tw`sw-body-sm`} &:focus { outline: none; } `; const itemStyle = (props: ThemedProps) => css` color: var(--color); background-color: ${themeColor('dropdownMenu')(props)}; border: none; border-bottom: none; text-decoration: none; transition: none; ${tw`sw-flex sw-items-center`} ${tw`sw-body-sm`} ${tw`sw-box-border`} ${tw`sw-w-full`} ${tw`sw-text-left`} ${tw`sw-py-2 sw-px-3`} ${tw`sw-truncate`}; ${tw`sw-cursor-pointer`} &.active, &:active, &.active:active, &:hover, &.active:hover { color: var(--color); background-color: ${themeColor('dropdownMenuHover')(props)}; text-decoration: none; outline: none; border: none; border-bottom: none; } &:focus, &:focus-within, &.active:focus, &.active:focus-within { color: var(--color); background-color: ${themeColor('dropdownMenuFocus')(props)}; text-decoration: none; outline: ${themeBorder('focus', 'dropdownMenuFocusBorder')(props)}; outline-offset: -4px; border: none; border-bottom: none; } &:disabled, &.disabled { color: ${themeContrast('dropdownMenuDisabled')(props)}; background-color: ${themeColor('dropdownMenuDisabled')(props)}; pointer-events: none !important; ${tw`sw-cursor-not-allowed`}; } & > svg { ${tw`sw-mr-2`} } `; const ItemNavLinkStyled = styled(NavLink)` --color: ${themeContrast('dropdownMenu')}; ${itemStyle}; `; const ItemLinkStyled = styled(BaseLink)` --color: ${themeContrast('dropdownMenu')}; ${itemStyle} `; const ItemButtonStyled = styled.button` --color: ${themeContrast('dropdownMenu')}; ${itemStyle} `; const ItemDownloadStyled = styled.a` --color: ${themeContrast('dropdownMenu')}; ${itemStyle} `; const ItemCheckboxStyled = styled(Checkbox)` --color: ${themeContrast('dropdownMenu')}; ${itemStyle} `; const ItemRadioButtonStyled = styled(RadioButton)` --color: ${themeContrast('dropdownMenu')}; ${itemStyle} `;