/* * 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 styled from '@emotion/styled'; import { scaleLinear } from 'd3-scale'; import React from 'react'; import tw from 'twin.macro'; import { themeColor } from '../helpers'; import { BasePlacement, PopupPlacement } from '../helpers/positioning'; import Tooltip from './Tooltip'; const SIZE_SCALE = scaleLinear().domain([3, 15]).range([11, 18]).clamp(true); const TEXT_VISIBLE_AT_WIDTH = 40; const TEXT_VISIBLE_AT_HEIGHT = 45; const ICON_VISIBLE_AT_WIDTH = 24; const ICON_VISIBLE_AT_HEIGHT = 26; interface Props { fill?: string; gradient?: string; height: number; icon?: React.ReactNode; itemKey: string; label: string; onClick: (item: string) => void; placement?: BasePlacement; prefix: string; tooltip?: React.ReactNode; width: number; x: number; y: number; } export function TreeMapRect(props: Props) { const { placement, tooltip, onClick, itemKey, x, y, width, height, fill, gradient, label, icon, prefix, } = props; const handleRectClick = React.useCallback(() => { onClick(itemKey); return false; }, [onClick, itemKey]); const cellStyles = { left: x, top: y, width, height, backgroundColor: fill, backgroundImage: gradient, fontSize: SIZE_SCALE(width / label.length), lineHeight: `${height}px`, }; const isTextVisible = width >= TEXT_VISIBLE_AT_WIDTH && height >= TEXT_VISIBLE_AT_HEIGHT; const isIconVisible = width >= ICON_VISIBLE_AT_WIDTH && height >= ICON_VISIBLE_AT_HEIGHT; return ( {isIconVisible && {icon}} {isTextVisible && (prefix ? ( {prefix}
{label.substring(prefix.length)}
) : ( {label} ))} {tooltip}
); } const StyledCell = styled.li` ${tw`sw-absolute`}; ${tw`sw-box-border`}; border-right: 1px solid #fff; border-bottom: 1px solid #fff; `; const StyledCellLink = styled.a` ${tw`sw-w-full sw-h-full`}; ${tw`sw-border-0`}; ${tw`sw-flex sw-flex-col sw-items-center sw-justify-center`}; color: ${themeColor('pageContent')}; &:hover, &:active, &:focus { ${tw`sw-border-0`}; outline: none; } &:focus .treemap-text, &:hover .treemap-text { ${tw`sw-underline`}; } `; const StyledCellLabel = styled.div<{ width: number }>` ${tw`sw-flex sw-flex-wrap sw-justify-center sw-items-center sw-gap-2`}; line-height: 1.2; max-width: ${({ width }) => width}px; .treemap-text { ${tw`sw-shrink sw-overflow-hidden sw-whitespace-nowrap sw-text-left sw-text-ellipsis`}; } `; const StyledA11yHidden = styled.span` position: absolute !important; left: -10000px !important; top: auto !important; width: 1px !important; height: 1px !important; overflow: hidden !important; `;