Files
grafana-zabbix/src/components/MetricPicker/MetricPickerMenu.tsx
github-actions[bot] b13d567eee chore: bump @grafana/create-plugin configuration to 5.26.4 (#2082)
Bumps
[`@grafana/create-plugin`](https://github.com/grafana/plugin-tools/tree/main/packages/create-plugin)
configuration from 4.2.1 to 5.26.4.

**Notes for reviewer:**
This is an auto-generated PR which ran `@grafana/create-plugin update`.
Please consult the create-plugin
[CHANGELOG.md](https://github.com/grafana/plugin-tools/blob/main/packages/create-plugin/CHANGELOG.md)
to understand what may have changed.
Please review the changes thoroughly before merging.

---------

Co-authored-by: grafana-plugins-platform-bot[bot] <144369747+grafana-plugins-platform-bot[bot]@users.noreply.github.com>
Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
2025-09-17 20:33:12 +02:00

139 lines
4.2 KiB
TypeScript

import { css, cx } from '@emotion/css';
import React, { FormEvent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { CustomScrollbar, getSelectStyles, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui';
import { MENU_MAX_HEIGHT } from './constants';
interface Props {
options: Array<SelectableValue<string>>;
onSelect: (option: SelectableValue<string>) => void;
offset: { vertical: number; horizontal: number };
minWidth?: number;
selected?: number;
}
export const MetricPickerMenu = ({ options, offset, minWidth, selected, onSelect }: Props) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles(minWidth));
return (
<div
className={cx(
styles.menu,
customStyles.menuWrapper,
{ [customStyles.menuLeft]: offset.horizontal > 0 },
css`
bottom: ${offset.vertical > 0 ? `${offset.vertical}px` : 'unset'};
top: ${offset.vertical < 0 ? `${Math.abs(offset.vertical)}px` : 'unset'};
`
)}
>
<div className={customStyles.menu} aria-label="Metric picker menu">
<CustomScrollbar autoHide={false} autoHeightMax={`${MENU_MAX_HEIGHT}px`} hideHorizontalTrack>
<div>
<div className={styles.optionBody}>
{options?.map((option, i) => (
<MenuOption data={option} key={i} onClick={onSelect} isFocused={selected === i} hideDescription />
))}
</div>
</div>
</CustomScrollbar>
</div>
</div>
);
};
interface MenuOptionProps<T> {
data: SelectableValue<string>;
onClick: (value: SelectableValue<string>) => void;
isFocused?: boolean;
disabled?: boolean;
hideDescription?: boolean;
}
const MenuOption = React.forwardRef<HTMLDivElement, React.PropsWithChildren<MenuOptionProps<any>>>(
({ data, isFocused, disabled, onClick, hideDescription }, ref) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles());
const wrapperClassName = cx(
styles.option,
customStyles.menuOptionWrapper,
isFocused && styles.optionFocused,
disabled && customStyles.menuOptionDisabled
);
const onClickInternal = (event: FormEvent<HTMLElement>) => {
if (disabled) {
return;
}
event.preventDefault();
event.stopPropagation();
onClick(data);
};
return (
<div ref={ref} className={wrapperClassName} aria-label="Menu option" onClick={onClickInternal}>
<div className={cx(styles.optionBody, customStyles.menuOptionBody)}>
<span>{data.label || data.value}</span>
{!hideDescription && data.description && <div className={styles.optionDescription}>{data.description}</div>}
</div>
{data.description && (
<Tooltip content={data.description}>
<Icon name="info-circle" className={customStyles.menuOptionInfoSign} />
</Tooltip>
)}
</div>
);
}
);
MenuOption.displayName = 'MenuOption';
export const getStyles = (menuWidth?: number) => (theme: GrafanaTheme2) => {
return {
menuWrapper: css`
display: flex;
max-height: 650px;
position: absolute;
z-index: ${theme.zIndex.dropdown};
overflow: hidden;
min-width: auto;
`,
menu: css`
min-width: ${theme.spacing(menuWidth || 0)};
& > div {
padding-top: ${theme.spacing(1)};
}
`,
menuLeft: css`
right: 0;
flex-direction: row-reverse;
`,
container: css`
padding: ${theme.spacing(1)};
border: 1px ${theme.colors.border.weak} solid;
border-radius: ${theme.shape.borderRadius(1)};
background-color: ${theme.colors.background.primary};
z-index: ${theme.zIndex.modal};
`,
menuOptionWrapper: css`
padding: ${theme.spacing(0.5)};
`,
menuOptionBody: css`
font-weight: ${theme.typography.fontWeightRegular};
padding: ${theme.spacing(0, 1.5, 0, 0)};
`,
menuOptionDisabled: css`
color: ${theme.colors.text.disabled};
cursor: not-allowed;
`,
menuOptionInfoSign: css`
color: ${theme.colors.text.disabled};
`,
};
};