|
|
|
|
@ -4,19 +4,29 @@ import Skeleton from 'react-loading-skeleton'; |
|
|
|
|
|
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data'; |
|
|
|
|
import { Icon, getInputStyles, useTheme2, Text } from '@grafana/ui'; |
|
|
|
|
import { focusCss } from '@grafana/ui/src/themes/mixins'; |
|
|
|
|
import { Trans } from 'app/core/internationalization'; |
|
|
|
|
import { focusCss, getFocusStyles, getMouseFocusStyles } from '@grafana/ui/src/themes/mixins'; |
|
|
|
|
import { Trans, t } from 'app/core/internationalization'; |
|
|
|
|
|
|
|
|
|
interface TriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> { |
|
|
|
|
isLoading: boolean; |
|
|
|
|
handleClearSelection?: (event: React.MouseEvent<SVGElement> | React.KeyboardEvent<SVGElement>) => void; |
|
|
|
|
invalid?: boolean; |
|
|
|
|
label?: ReactNode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function Trigger({ isLoading, invalid, label, ...rest }: TriggerProps, ref: React.ForwardedRef<HTMLButtonElement>) { |
|
|
|
|
function Trigger( |
|
|
|
|
{ handleClearSelection, isLoading, invalid, label, ...rest }: TriggerProps, |
|
|
|
|
ref: React.ForwardedRef<HTMLButtonElement> |
|
|
|
|
) { |
|
|
|
|
const theme = useTheme2(); |
|
|
|
|
const styles = getStyles(theme, invalid); |
|
|
|
|
|
|
|
|
|
const handleKeyDown = (event: React.KeyboardEvent<SVGElement>) => { |
|
|
|
|
if (event.key === 'Enter' || event.key === ' ') { |
|
|
|
|
handleClearSelection?.(event); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className={styles.wrapper}> |
|
|
|
|
<div className={styles.inputWrapper}> |
|
|
|
|
@ -41,6 +51,18 @@ function Trigger({ isLoading, invalid, label, ...rest }: TriggerProps, ref: Reac |
|
|
|
|
<Trans i18nKey="browse-dashboards.folder-picker.button-label">Select folder</Trans> |
|
|
|
|
</Text> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
{!isLoading && handleClearSelection && ( |
|
|
|
|
<Icon |
|
|
|
|
role="button" |
|
|
|
|
tabIndex={0} |
|
|
|
|
aria-label={t('browse-dashboards.folder-picker.clear-selection', 'Clear selection')} |
|
|
|
|
className={styles.clearIcon} |
|
|
|
|
name="times" |
|
|
|
|
onClick={handleClearSelection} |
|
|
|
|
onKeyDown={handleKeyDown} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
<div className={styles.suffix}> |
|
|
|
|
@ -92,11 +114,26 @@ const getStyles = (theme: GrafanaTheme2, invalid = false) => { |
|
|
|
|
'&:focus-visible': css` |
|
|
|
|
${focusCss(theme)} |
|
|
|
|
`,
|
|
|
|
|
alignItems: 'center', |
|
|
|
|
display: 'flex', |
|
|
|
|
flexWrap: 'nowrap', |
|
|
|
|
justifyContent: 'space-between', |
|
|
|
|
paddingRight: 28, |
|
|
|
|
}, |
|
|
|
|
]), |
|
|
|
|
|
|
|
|
|
hasPrefix: css({ |
|
|
|
|
paddingLeft: 28, |
|
|
|
|
}), |
|
|
|
|
|
|
|
|
|
clearIcon: css({ |
|
|
|
|
color: theme.colors.text.secondary, |
|
|
|
|
cursor: 'pointer', |
|
|
|
|
'&:hover': { |
|
|
|
|
color: theme.colors.text.primary, |
|
|
|
|
}, |
|
|
|
|
'&:focus:not(:focus-visible)': getMouseFocusStyles(theme), |
|
|
|
|
'&:focus-visible': getFocusStyles(theme), |
|
|
|
|
}), |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|