mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 04:22:13 +08:00

* Add pills in search bar for context * Add scope actions * Add selection functionality * Show selected scope on secondary row * Fix selected scope titles * Add some basic tests * Test for toggle by name * Remove unnecessary mocking * Small cleanups * Lint fixes * Fix test * Update public/app/features/scopes/selector/ScopesSelectorService.ts Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> * Bump input and breadcrumbs test * Change breadcrumbs color * Makes the breacrumb spacing consistent --------- Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com>
87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import { useKBar, VisualState } from 'kbar';
|
|
import * as React from 'react';
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { useStyles2 } from '@grafana/ui';
|
|
|
|
export const KBAR_LISTBOX = 'kbar-listbox';
|
|
export const getListboxItemId = (id: number) => `kbar-listbox-item-${id}`;
|
|
|
|
export function KBarSearch(
|
|
props: React.InputHTMLAttributes<HTMLInputElement> & {
|
|
defaultPlaceholder?: string;
|
|
}
|
|
) {
|
|
const { query, search, actions, currentRootActionId, activeIndex, showing, options } = useKBar((state) => ({
|
|
search: state.searchQuery,
|
|
currentRootActionId: state.currentRootActionId,
|
|
actions: state.actions,
|
|
activeIndex: state.activeIndex,
|
|
showing: state.visualState === VisualState.showing,
|
|
}));
|
|
|
|
const [inputValue, setInputValue] = React.useState(search);
|
|
React.useEffect(() => {
|
|
query.setSearch(inputValue);
|
|
}, [inputValue, query]);
|
|
|
|
const { defaultPlaceholder, ...rest } = props;
|
|
|
|
React.useEffect(() => {
|
|
query.setSearch('');
|
|
query.getInput().focus();
|
|
setInputValue('');
|
|
return () => query.setSearch('');
|
|
}, [currentRootActionId, query]);
|
|
|
|
const defaultText = defaultPlaceholder ?? 'Type a command or search…';
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
return (
|
|
<input
|
|
{...rest}
|
|
className={styles.input}
|
|
ref={query.inputRefSetter}
|
|
/* eslint-disable-next-line jsx-a11y/no-autofocus */
|
|
autoFocus
|
|
autoComplete="off"
|
|
role="combobox"
|
|
spellCheck="false"
|
|
aria-expanded={showing}
|
|
aria-controls={KBAR_LISTBOX}
|
|
aria-activedescendant={getListboxItemId(activeIndex)}
|
|
value={inputValue}
|
|
placeholder={defaultText}
|
|
onChange={(event) => {
|
|
props.onChange?.(event);
|
|
setInputValue(event.target.value);
|
|
options?.callbacks?.onQueryChange?.(event.target.value);
|
|
}}
|
|
onKeyDown={(event) => {
|
|
props.onKeyDown?.(event);
|
|
if (currentRootActionId && !search && event.key === 'Backspace') {
|
|
const parent = actions[currentRootActionId].parent;
|
|
query.setCurrentRootAction(parent);
|
|
}
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => {
|
|
return {
|
|
input: css({
|
|
label: 'kbar-search-input',
|
|
fontSize: theme.typography.body.fontSize,
|
|
fontWeight: theme.typography.fontWeightMedium,
|
|
lineHeight: theme.typography.body.lineHeight,
|
|
color: theme.colors.text.secondary,
|
|
width: '100%',
|
|
outline: 'none',
|
|
paddingLeft: 0,
|
|
}),
|
|
};
|
|
};
|