Files
grafana/packages/grafana-ui/src/components/Select/SelectBase.tsx

389 lines
12 KiB
TypeScript
Raw Normal View History

import { t } from 'i18next';
import React, { ComponentProps, useCallback, useEffect, useRef, useState } from 'react';
import { default as ReactSelect, IndicatorsContainerProps, Props as ReactSelectProps } from 'react-select';
import { default as ReactAsyncSelect } from 'react-select/async';
import { default as AsyncCreatable } from 'react-select/async-creatable';
import Creatable from 'react-select/creatable';
2020-01-07 09:20:06 +01:00
Tempo: New Search UI using TraceQL (#63808) * WIP of creating new components to support the Search tab using TraceQL * Search fields now require an ID. Added duration fields to new Search UI * Distinguish static from dynamic fields. Added dynamic tags input * Moved new search behind traceqlSearch feature flag. Added handling of different types of values to accurately wrap them in quotes when generating query. * Hold search state in TempoQuery to leverage state in URL. Moved types to schema file * Use a read only monaco editor to render a syntax highlighted generated query. Added tooltip to duration. Added query options section * Support multiple values using the regex operator and multi input * Delete dynamic filters * Automatically select the regex op when multiple values are selected. Revert to previous operator when only one value is selected * Added tests for SearchField component * Added tests for the TraceQLSearch component * Added tests for function that generates the query * Fix merge conflicts * Update test * Replace Search tab when traceqlSearch feature flag is enabled. Limit operators for both name fields to =,!=,=~ * Disable clear button for values * Changed delete and add buttons to AccessoryButton. Added descriptions to operators * Remove duplicate test * Added a prismjs grammar for traceql. Replaced read only query editor with syntax highlighted query. Removed spaces between tag operator and value when generating query. * Fix support for custom values when isMulti is enabled in Select * Use toOption function
2023-03-06 16:31:08 +00:00
import { SelectableValue, toOption } from '@grafana/data';
import { useTheme2 } from '../../themes';
import { Icon } from '../Icon/Icon';
import { Spinner } from '../Spinner/Spinner';
import { DropdownIndicator } from './DropdownIndicator';
2020-01-07 09:20:06 +01:00
import { IndicatorsContainer } from './IndicatorsContainer';
import { InputControl } from './InputControl';
import { MultiValueContainer, MultiValueRemove } from './MultiValue';
import { SelectContainer } from './SelectContainer';
import { SelectMenu, SelectMenuOptions, VirtualizedSelectMenu } from './SelectMenu';
2020-01-07 09:20:06 +01:00
import { SelectOptionGroup } from './SelectOptionGroup';
import { SingleValue } from './SingleValue';
import { ValueContainer } from './ValueContainer';
2020-01-07 09:20:06 +01:00
import { getSelectStyles } from './getSelectStyles';
import { useCustomSelectStyles } from './resetSelectStyles';
import { ActionMeta, InputActionMeta, SelectBaseProps } from './types';
import { cleanValue, findSelectedValue, omitDescriptions } from './utils';
2020-01-07 09:20:06 +01:00
const CustomControl = (props: any) => {
const {
children,
innerProps,
selectProps: { menuIsOpen, onMenuClose, onMenuOpen },
isFocused,
isMulti,
getValue,
innerRef,
} = props;
const selectProps = props.selectProps as SelectBaseProps<any>;
if (selectProps.renderControl) {
return React.createElement(selectProps.renderControl, {
isOpen: menuIsOpen,
value: isMulti ? getValue() : getValue()[0],
ref: innerRef,
onClick: menuIsOpen ? onMenuClose : onMenuOpen,
onBlur: onMenuClose,
disabled: !!selectProps.disabled,
invalid: !!selectProps.invalid,
});
}
return (
<InputControl
ref={innerRef}
innerProps={innerProps}
prefix={selectProps.prefix}
focused={isFocused}
invalid={!!selectProps.invalid}
disabled={!!selectProps.disabled}
>
{children}
</InputControl>
);
};
interface SelectPropsWithExtras extends ReactSelectProps {
maxVisibleValues?: number | undefined;
showAllSelectedWhenOpen: boolean;
noMultiValueWrap?: boolean;
}
export function SelectBase<T, Rest = {}>({
allowCustomValue = false,
allowCreateWhileLoading = false,
'aria-label': ariaLabel,
autoFocus = false,
backspaceRemovesValue = true,
AzureMonitor: Application Insights Traces (#64859) * Build out barebones Traces editor - Add Traces query type and operation ID prop to query type - Add necessary header types - Update resource picker to appropriately work with traces query type - Build out TracesQueryEditor component - Include logic to retrieve operationId's for AI Workspaces - Add backend route mapping - Update macro to use timestamp as default time field for traces * AzureMonitor: Traces - Response parsing (#65442) * Update FormatAsField component - Add trace ResultFormat type - Generalise FormatAsField component - Add component to TracesQueryEditor - Remove duplicate code in setQueryValue * Add custom filter function to improve performance * Add basic conversion for logs to trace - Add serviceTags converter - Pass through required parameters (queryType and resultFormat) - Appropriately set visualisation * Update parsing to also fill trace tags - Add constant values for each table schema (include legacy mapping for now if needed) - Add constant for list of table tags - Set the foundation for dynamic query building - Update query to build tags value - Appropriately set operationName - Update tagsConverter to filter empty values * Fix lint and test issues * AzureMonitor: Traces - Data links (#65566) * Add portal link for traces - Pull out necessary values (itemId and itemType) - Appropriately construct - Fix ordering * Set default format as value - Also set default visualisation * Fix event schema * Set default formatAsField value * Include logs link on traces results - Adapt config links to allow custom title to be set * Correctly set operationId for query * Update backend types - Include OperationID in query - Pass forward datasource name and UID * Ensure setTime doesn't consistently get called if operationID is defined * Add explore link - Update util functions to allow setting custom datalinks * Fix tests * AzureMonitor: Traces - Query and Editor updates (#66076) * Add initial query - Will query the resource as soon as a resource has been selected - Updates the data links for the query without operationId - Remove initial operationId query and timeRange dependency - Update query building * Add entirely separate traces query property - Update shared types (also including future types for Azure traces) - Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries - Update backend specific types - Update frontend datasource for new properties - Update mock query * Update FormatAsField to be entirely generic * Update query building to be done in backend - Add required mappings in backend - Update frontend querying * Fix query and explore data link * Add trace type selection * Better method for setting explore link * Fix operationId updating * Run go mod tidy * Unnecessary changes * Fix tests * AzureMonitor: Traces - Add correlation API support (#65855) Add correlation API support - Add necessary types - Add correlation API request when conditions are met - Update query * Fix property from merge * AzureMonitor: Traces - Filtering (#66303) * Add initial query - Will query the resource as soon as a resource has been selected - Updates the data links for the query without operationId - Remove initial operationId query and timeRange dependency - Update query building * Add entirely separate traces query property - Update shared types (also including future types for Azure traces) - Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries - Update backend specific types - Update frontend datasource for new properties - Update mock query * Update FormatAsField to be entirely generic * Update query building to be done in backend - Add required mappings in backend - Update frontend querying * Fix query and explore data link * Add trace type selection * Better method for setting explore link * Fix operationId updating * Run go mod tidy * Unnecessary changes * Fix tests * Start building out Filters component - Configure component to query for Filter property values when a filter property is set - Add setFilters function - Add typing to tablesSchema - Use component in TracesQueryEditor * Update Filters - Asynchronously pull property options - Setup list of Filter components * Update filters component - Remove unused imports - Have local filters state and query filters - Correctly set filters values - Don't update query every time a filter property changes (not performant) * Update properties query - Use current timeRange - Get count to provide informative labels * Reset map when time changes * Add operation selection * Reset filters when property changes * Appropriate label name for empty values * Add filtering to query * Update filter components - Fix rendering issue - Correctly compare and update timeRange - Split out files for simplicity * Add checkbox option to multiselect - Add custom option component - Correctly call onChange - Add variableOptionGroup for template variable selection * Fix adding template vars * Improve labels and refresh labels on query prop changes * AzureMonitor: Traces - Testing (#66474) * Select ds for template variable interpolation * Update az logs ds tests - Add templateVariables test - Add filter test - Update mock - Remove anys * Update QueryEditor test - Update mocks with timeSrv for log analytics datasource - Fix query mock - Use appropriate and consistent selectors * Add TracesQueryEditor test - Update resourcePickerRows mock to include app insights resources - Remove comments and extra new line * Add FormatAsField test - Remove unneeded condition * Update resourcePicker utils test * Don't hide selected options in filters * Fix multi-selection on filters * Add TraceTypeField test - Add test file - Update selectors (remove copy/paste mistake) - Update placeholder text for select and add label * Add basic filters test * Begin filters test * Update filters test * Add final tests and simplify/generalise addFilter helper * Minor update to datasource test * Update macros test * Update selectors in tests * Add response-table-frame tests * Add datasource tests - Use sorting where JSON models are inconsistent - Update filters clause - Dedupe tags - Correct operationId conditions * Don't set a default value for blurInputOnSelect * Simplify datasource test * Update to use CheckGoldenJSON utils - Update with generated frame files - Remove redundant expected frame code - Update all usages * Fix lint * AzureMonitor: Traces feedback (#67292) * Filter traces if the visualisation is set to trace - Update build query logic - Added additional test cases - Return an error if the traces type is set by itself with the trace visualisation - Add descriptions to event types - Update tests * Fix bug for error displaying traces * Update mappings and add error field - Update tests - Remove unnecessary comments * Switch location of Operation ID field * Re-order fields * Update link title * Update label for event type selection * Update correct link title * Update logs datalink to link to Azure Logs in explore * Fix lint
2023-04-27 20:24:11 +01:00
blurInputOnSelect,
cacheOptions,
className,
closeMenuOnSelect = true,
components,
createOptionPosition = 'last',
defaultOptions,
2020-01-07 09:20:06 +01:00
defaultValue,
disabled = false,
filterOption,
formatCreateLabel,
getOptionLabel,
getOptionValue,
inputValue,
invalid,
2020-01-07 09:20:06 +01:00
isClearable = false,
id,
2020-01-07 09:20:06 +01:00
isLoading = false,
isMulti = false,
inputId,
2020-01-07 09:20:06 +01:00
isOpen,
isOptionDisabled,
isSearchable = true,
loadOptions,
loadingMessage = 'Loading options...',
2020-01-07 09:20:06 +01:00
maxMenuHeight = 300,
FieldColor: Adds new standard color option for color (#28039) * FieldColor: Added field color option * Progress * FieldColor: Added custom schemes * move to fieldColor * move to fieldColor * add back the standard color picker * FieldColor: Added registry for field color modes * wip refactor * Seperate scale from color mode * Progress * schemes working * Stuff is working * Added fallback * Updated threshold tests * Added unit tests * added more tests * Made it work with new graph panel * Use scale calculator from graph panel * Updates * Updated test * Renaming things * Update packages/grafana-data/src/field/displayProcessor.ts Co-authored-by: Ryan McKinley <ryantxu@gmail.com> * updated according to feedback, added docs * Updated docs * Updated * Update docs/sources/panels/field-options/standard-field-options.md Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Update docs/sources/panels/field-options/standard-field-options.md Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Updated docs according to feedback * fixed test * Updated * Updated wording * Change to fieldState.seriesIndex * Updated tests * Updates * New names * More work needed to support bar gauge and showing the color modes in the picker * Now correct gradients work in bar gauge * before rename * Unifying the concept * Updates * review feedback * Updated * Skip minification * Updated * UI improvements Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
2020-10-09 09:34:57 +02:00
minMenuHeight,
maxVisibleValues,
menuPlacement = 'auto',
menuPosition,
menuShouldPortal = true,
noOptionsMessage = t('grafana-ui.select.no-options-label', 'No options found'),
onBlur,
onChange,
onCloseMenu,
onCreateOption,
onInputChange,
onKeyDown,
onMenuScrollToBottom,
onMenuScrollToTop,
onOpenMenu,
onFocus,
openMenuOnFocus = false,
options = [],
placeholder = t('grafana-ui.select.placeholder', 'Choose'),
2020-01-07 09:20:06 +01:00
prefix,
renderControl,
showAllSelectedWhenOpen = true,
tabSelectsValue = true,
value,
virtualized = false,
noMultiValueWrap,
2020-01-07 09:20:06 +01:00
width,
isValidNewOption,
formatOptionLabel,
hideSelectedOptions,
...rest
}: SelectBaseProps<T> & Rest) {
const theme = useTheme2();
2020-01-07 09:20:06 +01:00
const styles = getSelectStyles(theme);
const reactSelectRef = useRef<{ controlRef: HTMLElement }>(null);
const [closeToBottom, setCloseToBottom] = useState<boolean>(false);
2021-12-15 13:33:35 +01:00
const selectStyles = useCustomSelectStyles(theme, width);
const [hasInputValue, setHasInputValue] = useState<boolean>(!!inputValue);
// Infer the menu position for asynchronously loaded options. menuPlacement="auto" doesn't work when the menu is
// automatically opened when the component is created (it happens in SegmentSelect by setting menuIsOpen={true}).
// We can remove this workaround when the bug in react-select is fixed: https://github.com/JedWatson/react-select/issues/4936
// Note: we use useEffect instead of hooking into onMenuOpen due to another bug: https://github.com/JedWatson/react-select/issues/3375
useEffect(() => {
if (
loadOptions &&
isOpen &&
reactSelectRef.current &&
reactSelectRef.current.controlRef &&
menuPlacement === 'auto'
) {
const distance = window.innerHeight - reactSelectRef.current.controlRef.getBoundingClientRect().bottom;
setCloseToBottom(distance < maxMenuHeight);
}
}, [maxMenuHeight, menuPlacement, loadOptions, isOpen]);
const onChangeWithEmpty = useCallback(
(value: SelectableValue<T>, action: ActionMeta) => {
if (isMulti && (value === undefined || value === null)) {
return onChange([], action);
}
onChange(value, action);
},
[isMulti, onChange]
);
let ReactSelectComponent = ReactSelect;
const creatableProps: ComponentProps<typeof Creatable<SelectableValue<T>>> = {};
2020-01-07 09:20:06 +01:00
let asyncSelectProps: any = {};
let selectedValue;
2020-01-07 09:20:06 +01:00
if (isMulti && loadOptions) {
selectedValue = value as any;
} else {
// If option is passed as a plain value (value property from SelectableValue property)
// we are selecting the corresponding value from the options
if (isMulti && value && Array.isArray(value) && !loadOptions) {
Tempo: New Search UI using TraceQL (#63808) * WIP of creating new components to support the Search tab using TraceQL * Search fields now require an ID. Added duration fields to new Search UI * Distinguish static from dynamic fields. Added dynamic tags input * Moved new search behind traceqlSearch feature flag. Added handling of different types of values to accurately wrap them in quotes when generating query. * Hold search state in TempoQuery to leverage state in URL. Moved types to schema file * Use a read only monaco editor to render a syntax highlighted generated query. Added tooltip to duration. Added query options section * Support multiple values using the regex operator and multi input * Delete dynamic filters * Automatically select the regex op when multiple values are selected. Revert to previous operator when only one value is selected * Added tests for SearchField component * Added tests for the TraceQLSearch component * Added tests for function that generates the query * Fix merge conflicts * Update test * Replace Search tab when traceqlSearch feature flag is enabled. Limit operators for both name fields to =,!=,=~ * Disable clear button for values * Changed delete and add buttons to AccessoryButton. Added descriptions to operators * Remove duplicate test * Added a prismjs grammar for traceql. Replaced read only query editor with syntax highlighted query. Removed spaces between tag operator and value when generating query. * Fix support for custom values when isMulti is enabled in Select * Use toOption function
2023-03-06 16:31:08 +00:00
selectedValue = value.map((v) => {
// @ts-ignore
const selectableValue = findSelectedValue(v.value ?? v, options);
// If the select allows custom values there likely won't be a selectableValue in options
// so we must return a new selectableValue
if (!allowCustomValue || selectableValue) {
return selectableValue;
}
return typeof v === 'string' ? toOption(v) : v;
});
} else if (loadOptions) {
const hasValue = defaultValue || value;
selectedValue = hasValue ? [hasValue] : [];
2020-01-07 09:20:06 +01:00
} else {
selectedValue = cleanValue(value, options);
2020-01-07 09:20:06 +01:00
}
}
const commonSelectProps = {
'aria-label': ariaLabel,
2020-01-07 09:20:06 +01:00
autoFocus,
backspaceRemovesValue,
AzureMonitor: Application Insights Traces (#64859) * Build out barebones Traces editor - Add Traces query type and operation ID prop to query type - Add necessary header types - Update resource picker to appropriately work with traces query type - Build out TracesQueryEditor component - Include logic to retrieve operationId's for AI Workspaces - Add backend route mapping - Update macro to use timestamp as default time field for traces * AzureMonitor: Traces - Response parsing (#65442) * Update FormatAsField component - Add trace ResultFormat type - Generalise FormatAsField component - Add component to TracesQueryEditor - Remove duplicate code in setQueryValue * Add custom filter function to improve performance * Add basic conversion for logs to trace - Add serviceTags converter - Pass through required parameters (queryType and resultFormat) - Appropriately set visualisation * Update parsing to also fill trace tags - Add constant values for each table schema (include legacy mapping for now if needed) - Add constant for list of table tags - Set the foundation for dynamic query building - Update query to build tags value - Appropriately set operationName - Update tagsConverter to filter empty values * Fix lint and test issues * AzureMonitor: Traces - Data links (#65566) * Add portal link for traces - Pull out necessary values (itemId and itemType) - Appropriately construct - Fix ordering * Set default format as value - Also set default visualisation * Fix event schema * Set default formatAsField value * Include logs link on traces results - Adapt config links to allow custom title to be set * Correctly set operationId for query * Update backend types - Include OperationID in query - Pass forward datasource name and UID * Ensure setTime doesn't consistently get called if operationID is defined * Add explore link - Update util functions to allow setting custom datalinks * Fix tests * AzureMonitor: Traces - Query and Editor updates (#66076) * Add initial query - Will query the resource as soon as a resource has been selected - Updates the data links for the query without operationId - Remove initial operationId query and timeRange dependency - Update query building * Add entirely separate traces query property - Update shared types (also including future types for Azure traces) - Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries - Update backend specific types - Update frontend datasource for new properties - Update mock query * Update FormatAsField to be entirely generic * Update query building to be done in backend - Add required mappings in backend - Update frontend querying * Fix query and explore data link * Add trace type selection * Better method for setting explore link * Fix operationId updating * Run go mod tidy * Unnecessary changes * Fix tests * AzureMonitor: Traces - Add correlation API support (#65855) Add correlation API support - Add necessary types - Add correlation API request when conditions are met - Update query * Fix property from merge * AzureMonitor: Traces - Filtering (#66303) * Add initial query - Will query the resource as soon as a resource has been selected - Updates the data links for the query without operationId - Remove initial operationId query and timeRange dependency - Update query building * Add entirely separate traces query property - Update shared types (also including future types for Azure traces) - Update backend log analytics datasource to accept both azureLogAnalytics and azureTraces queries - Update backend specific types - Update frontend datasource for new properties - Update mock query * Update FormatAsField to be entirely generic * Update query building to be done in backend - Add required mappings in backend - Update frontend querying * Fix query and explore data link * Add trace type selection * Better method for setting explore link * Fix operationId updating * Run go mod tidy * Unnecessary changes * Fix tests * Start building out Filters component - Configure component to query for Filter property values when a filter property is set - Add setFilters function - Add typing to tablesSchema - Use component in TracesQueryEditor * Update Filters - Asynchronously pull property options - Setup list of Filter components * Update filters component - Remove unused imports - Have local filters state and query filters - Correctly set filters values - Don't update query every time a filter property changes (not performant) * Update properties query - Use current timeRange - Get count to provide informative labels * Reset map when time changes * Add operation selection * Reset filters when property changes * Appropriate label name for empty values * Add filtering to query * Update filter components - Fix rendering issue - Correctly compare and update timeRange - Split out files for simplicity * Add checkbox option to multiselect - Add custom option component - Correctly call onChange - Add variableOptionGroup for template variable selection * Fix adding template vars * Improve labels and refresh labels on query prop changes * AzureMonitor: Traces - Testing (#66474) * Select ds for template variable interpolation * Update az logs ds tests - Add templateVariables test - Add filter test - Update mock - Remove anys * Update QueryEditor test - Update mocks with timeSrv for log analytics datasource - Fix query mock - Use appropriate and consistent selectors * Add TracesQueryEditor test - Update resourcePickerRows mock to include app insights resources - Remove comments and extra new line * Add FormatAsField test - Remove unneeded condition * Update resourcePicker utils test * Don't hide selected options in filters * Fix multi-selection on filters * Add TraceTypeField test - Add test file - Update selectors (remove copy/paste mistake) - Update placeholder text for select and add label * Add basic filters test * Begin filters test * Update filters test * Add final tests and simplify/generalise addFilter helper * Minor update to datasource test * Update macros test * Update selectors in tests * Add response-table-frame tests * Add datasource tests - Use sorting where JSON models are inconsistent - Update filters clause - Dedupe tags - Correct operationId conditions * Don't set a default value for blurInputOnSelect * Simplify datasource test * Update to use CheckGoldenJSON utils - Update with generated frame files - Remove redundant expected frame code - Update all usages * Fix lint * AzureMonitor: Traces feedback (#67292) * Filter traces if the visualisation is set to trace - Update build query logic - Added additional test cases - Return an error if the traces type is set by itself with the trace visualisation - Add descriptions to event types - Update tests * Fix bug for error displaying traces * Update mappings and add error field - Update tests - Remove unnecessary comments * Switch location of Operation ID field * Re-order fields * Update link title * Update label for event type selection * Update correct link title * Update logs datalink to link to Azure Logs in explore * Fix lint
2023-04-27 20:24:11 +01:00
blurInputOnSelect,
captureMenuScroll: onMenuScrollToBottom || onMenuScrollToTop,
closeMenuOnSelect,
// We don't want to close if we're actually scrolling the menu
// So only close if none of the parents are the select menu itself
defaultValue,
2020-01-07 09:20:06 +01:00
// Also passing disabled, as this is the new Select API, and I want to use this prop instead of react-select's one
disabled,
// react-select always tries to filter the options even at first menu open, which is a problem for performance
// in large lists. So we set it to not try to filter the options if there is no input value.
filterOption: hasInputValue ? filterOption : null,
getOptionLabel,
getOptionValue,
hideSelectedOptions,
inputValue,
2020-01-07 09:20:06 +01:00
invalid,
isClearable,
id,
// Passing isDisabled as react-select accepts this prop
isDisabled: disabled,
2020-01-07 09:20:06 +01:00
isLoading,
isMulti,
inputId,
isOptionDisabled,
isSearchable,
maxMenuHeight,
FieldColor: Adds new standard color option for color (#28039) * FieldColor: Added field color option * Progress * FieldColor: Added custom schemes * move to fieldColor * move to fieldColor * add back the standard color picker * FieldColor: Added registry for field color modes * wip refactor * Seperate scale from color mode * Progress * schemes working * Stuff is working * Added fallback * Updated threshold tests * Added unit tests * added more tests * Made it work with new graph panel * Use scale calculator from graph panel * Updates * Updated test * Renaming things * Update packages/grafana-data/src/field/displayProcessor.ts Co-authored-by: Ryan McKinley <ryantxu@gmail.com> * updated according to feedback, added docs * Updated docs * Updated * Update docs/sources/panels/field-options/standard-field-options.md Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Update docs/sources/panels/field-options/standard-field-options.md Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Updated docs according to feedback * fixed test * Updated * Updated wording * Change to fieldState.seriesIndex * Updated tests * Updates * New names * More work needed to support bar gauge and showing the color modes in the picker * Now correct gradients work in bar gauge * before rename * Unifying the concept * Updates * review feedback * Updated * Skip minification * Updated * UI improvements Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
2020-10-09 09:34:57 +02:00
minMenuHeight,
maxVisibleValues,
2020-01-07 09:20:06 +01:00
menuIsOpen: isOpen,
menuPlacement: menuPlacement === 'auto' && closeToBottom ? 'top' : menuPlacement,
menuPosition,
menuShouldBlockScroll: true,
menuPortalTarget: menuShouldPortal && typeof document !== 'undefined' ? document.body : undefined,
menuShouldScrollIntoView: false,
onBlur,
onChange: onChangeWithEmpty,
onInputChange: (val: string, actionMeta: InputActionMeta) => {
setHasInputValue(!!val);
onInputChange?.(val, actionMeta);
},
onKeyDown,
2020-01-07 09:20:06 +01:00
onMenuClose: onCloseMenu,
onMenuOpen: onOpenMenu,
onMenuScrollToBottom: onMenuScrollToBottom,
onMenuScrollToTop: onMenuScrollToTop,
onFocus,
formatOptionLabel,
openMenuOnFocus,
options: virtualized ? omitDescriptions(options) : options,
placeholder,
prefix,
2020-01-07 09:20:06 +01:00
renderControl,
showAllSelectedWhenOpen,
tabSelectsValue,
value: isMulti ? selectedValue : selectedValue?.[0],
noMultiValueWrap,
2020-01-07 09:20:06 +01:00
};
if (allowCustomValue) {
ReactSelectComponent = Creatable as any;
creatableProps.allowCreateWhileLoading = allowCreateWhileLoading;
creatableProps.formatCreateLabel = formatCreateLabel ?? defaultFormatCreateLabel;
creatableProps.onCreateOption = onCreateOption;
creatableProps.createOptionPosition = createOptionPosition;
creatableProps.isValidNewOption = isValidNewOption;
2020-01-07 09:20:06 +01:00
}
// Instead of having AsyncSelect, as a separate component we render ReactAsyncSelect
if (loadOptions) {
ReactSelectComponent = (allowCustomValue ? AsyncCreatable : ReactAsyncSelect) as any;
2020-01-07 09:20:06 +01:00
asyncSelectProps = {
loadOptions,
cacheOptions,
2020-01-07 09:20:06 +01:00
defaultOptions,
};
}
const SelectMenuComponent = virtualized ? VirtualizedSelectMenu : SelectMenu;
2020-01-07 09:20:06 +01:00
return (
2020-02-09 13:37:00 +01:00
<>
<ReactSelectComponent
ref={reactSelectRef}
2020-02-09 13:37:00 +01:00
components={{
MenuList: SelectMenuComponent,
2020-02-09 13:37:00 +01:00
Group: SelectOptionGroup,
ValueContainer,
IndicatorsContainer: CustomIndicatorsContainer,
IndicatorSeparator: IndicatorSeparator,
2020-02-09 13:37:00 +01:00
Control: CustomControl,
Option: SelectMenuOptions,
ClearIndicator(props: any) {
2020-02-09 13:37:00 +01:00
const { clearValue } = props;
return (
<Icon
name="times"
role="button"
aria-label="select-clear-value"
className={styles.singleValueRemove}
onMouseDown={(e) => {
2020-02-09 13:37:00 +01:00
e.preventDefault();
e.stopPropagation();
clearValue();
}}
/>
);
},
LoadingIndicator() {
return <Spinner inline />;
2020-02-09 13:37:00 +01:00
},
LoadingMessage() {
2020-02-09 13:37:00 +01:00
return <div className={styles.loadingMessage}>{loadingMessage}</div>;
},
NoOptionsMessage() {
2020-02-09 13:37:00 +01:00
return (
<div className={styles.loadingMessage} aria-label="No options provided">
{noOptionsMessage}
</div>
);
},
DropdownIndicator: DropdownIndicator,
SingleValue(props: any) {
return <SingleValue {...props} isDisabled={disabled} />;
},
SelectContainer,
2020-02-09 13:37:00 +01:00
MultiValueContainer: MultiValueContainer,
MultiValueRemove: !disabled ? MultiValueRemove : () => null,
2020-02-09 13:37:00 +01:00
...components,
}}
2021-12-15 13:33:35 +01:00
styles={selectStyles}
className={className}
2020-02-09 13:37:00 +01:00
{...commonSelectProps}
{...creatableProps}
{...asyncSelectProps}
{...rest}
2020-02-09 13:37:00 +01:00
/>
</>
2020-01-07 09:20:06 +01:00
);
}
function defaultFormatCreateLabel(input: string) {
return (
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<div>{input}</div>
<div style={{ flexGrow: 1 }} />
<div className="muted small" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
Hit enter to add
</div>
</div>
);
}
type CustomIndicatorsContainerProps = IndicatorsContainerProps & {
selectProps: SelectPropsWithExtras;
children: React.ReactNode;
};
function CustomIndicatorsContainer(props: CustomIndicatorsContainerProps) {
const { showAllSelectedWhenOpen, maxVisibleValues, menuIsOpen } = props.selectProps;
const value = props.getValue();
if (maxVisibleValues !== undefined && Array.isArray(props.children)) {
const selectedValuesCount = value.length;
if (selectedValuesCount > maxVisibleValues && !(showAllSelectedWhenOpen && menuIsOpen)) {
const indicatorChildren = [...props.children];
indicatorChildren.splice(
-1,
0,
<span key="excess-values" id="excess-values">
(+{selectedValuesCount - maxVisibleValues})
</span>
);
return <IndicatorsContainer {...props}>{indicatorChildren}</IndicatorsContainer>;
}
}
return <IndicatorsContainer {...props} />;
}
function IndicatorSeparator() {
return <></>;
}