2023-07-20 22:33:42 +08:00
|
|
|
import { css, cx } from '@emotion/css';
|
|
|
|
import React, { forwardRef, ReactNode, ButtonHTMLAttributes } from 'react';
|
|
|
|
import Skeleton from 'react-loading-skeleton';
|
|
|
|
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
2023-08-02 20:58:00 +08:00
|
|
|
import { Icon, getInputStyles, useTheme2, Text } from '@grafana/ui';
|
2023-07-20 22:33:42 +08:00
|
|
|
import { focusCss } from '@grafana/ui/src/themes/mixins';
|
|
|
|
import { Trans } from 'app/core/internationalization';
|
|
|
|
|
|
|
|
interface TriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
|
isLoading: boolean;
|
2023-07-26 18:47:58 +08:00
|
|
|
invalid?: boolean;
|
2023-07-20 22:33:42 +08:00
|
|
|
label?: ReactNode;
|
|
|
|
}
|
|
|
|
|
2023-07-26 18:47:58 +08:00
|
|
|
function Trigger({ isLoading, invalid, label, ...rest }: TriggerProps, ref: React.ForwardedRef<HTMLButtonElement>) {
|
|
|
|
const theme = useTheme2();
|
|
|
|
const styles = getStyles(theme, invalid);
|
2023-07-20 22:33:42 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={styles.wrapper}>
|
|
|
|
<div className={styles.inputWrapper}>
|
|
|
|
{label ? (
|
|
|
|
<div className={styles.prefix}>
|
|
|
|
<Icon name="folder" />
|
|
|
|
</div>
|
|
|
|
) : undefined}
|
|
|
|
|
2023-07-21 20:57:09 +08:00
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
className={cx(styles.fakeInput, label ? styles.hasPrefix : undefined)}
|
|
|
|
{...rest}
|
|
|
|
ref={ref}
|
|
|
|
>
|
2023-07-20 22:33:42 +08:00
|
|
|
{isLoading ? (
|
|
|
|
<Skeleton width={100} />
|
|
|
|
) : label ? (
|
|
|
|
<Text truncate>{label}</Text>
|
|
|
|
) : (
|
|
|
|
<Text truncate color="secondary">
|
|
|
|
<Trans i18nKey="browse-dashboards.folder-picker.button-label">Select folder</Trans>
|
|
|
|
</Text>
|
|
|
|
)}
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<div className={styles.suffix}>
|
|
|
|
<Icon name="angle-down" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default forwardRef(Trigger);
|
|
|
|
|
2023-07-26 18:47:58 +08:00
|
|
|
const getStyles = (theme: GrafanaTheme2, invalid = false) => {
|
|
|
|
const baseStyles = getInputStyles({ theme, invalid });
|
2023-07-20 22:33:42 +08:00
|
|
|
|
|
|
|
return {
|
|
|
|
wrapper: baseStyles.wrapper,
|
|
|
|
inputWrapper: baseStyles.inputWrapper,
|
|
|
|
|
|
|
|
prefix: css([
|
|
|
|
baseStyles.prefix,
|
|
|
|
{
|
|
|
|
pointerEvents: 'none',
|
|
|
|
color: theme.colors.text.primary,
|
|
|
|
},
|
|
|
|
]),
|
|
|
|
|
|
|
|
suffix: css([
|
|
|
|
baseStyles.suffix,
|
|
|
|
{
|
|
|
|
pointerEvents: 'none',
|
|
|
|
},
|
|
|
|
]),
|
|
|
|
|
|
|
|
fakeInput: css([
|
|
|
|
baseStyles.input,
|
|
|
|
{
|
|
|
|
textAlign: 'left',
|
|
|
|
|
|
|
|
letterSpacing: 'normal',
|
|
|
|
|
|
|
|
// We want the focus styles to appear only when tabbing through, not when clicking the button
|
|
|
|
// (and when focus is restored after command palette closes)
|
|
|
|
'&:focus': {
|
|
|
|
outline: 'unset',
|
|
|
|
boxShadow: 'unset',
|
|
|
|
},
|
|
|
|
|
|
|
|
'&:focus-visible': css`
|
|
|
|
${focusCss(theme)}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
]),
|
|
|
|
|
|
|
|
hasPrefix: css({
|
|
|
|
paddingLeft: 28,
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
};
|