import React from "react"; import { ComponentProps } from "widgets/BaseComponent"; import { MenuItem, Button, Classes } from "@blueprintjs/core"; import { DropdownOption } from "../constants"; import { IItemRendererProps } from "@blueprintjs/select"; import { debounce, findIndex, isEmpty, isNil } from "lodash"; import "../../../../node_modules/@blueprintjs/select/lib/css/blueprint-select.css"; import { Colors } from "constants/Colors"; import { TextSize } from "constants/WidgetConstants"; import { StyledLabel, TextLabelWrapper, StyledControlGroup, StyledSingleDropDown, DropdownStyles, DropdownContainer, StyledDiv, } from "./index.styled"; import Fuse from "fuse.js"; import { WidgetContainerDiff } from "widgets/WidgetUtils"; import Icon, { IconSize } from "components/ads/Icon"; import { isString } from "../../../utils/helpers"; const FUSE_OPTIONS = { shouldSort: true, threshold: 0.5, location: 0, minMatchCharLength: 3, findAllMatches: true, keys: ["label", "value"], }; export const isEmptyOrNill = (value: any) => { return isNil(value) || (isString(value) && value === ""); }; const DEBOUNCE_TIMEOUT = 800; interface SelectComponentState { activeItemIndex: number | undefined; query?: string; } class SelectComponent extends React.Component< SelectComponentProps, SelectComponentState > { state = { // used to show focused item for keyboard up down key interection activeItemIndex: 0, query: "", }; componentDidMount = () => { // set default selectedIndex as focused index this.setState({ activeItemIndex: this.props.selectedIndex ?? 0 }); this.setState({ query: this.props.filterText }); }; componentDidUpdate = (prevProps: SelectComponentProps) => { if (prevProps.selectedIndex !== this.props.selectedIndex) { // update focus index if selectedIndex changed by property pane this.setState({ activeItemIndex: this.props.selectedIndex }); } }; handleActiveItemChange = (activeItem: DropdownOption | null) => { // find new index from options const activeItemIndex = findIndex(this.props.options, [ "label", activeItem?.label, ]); this.setState({ activeItemIndex }); }; render() { const { compactMode, disabled, isLoading, labelStyle, labelText, labelTextColor, labelTextSize, widgetId, } = this.props; // active focused item const activeItem = !isEmpty(this.props.options) ? this.props.options[this.state.activeItemIndex] : undefined; // get selected option label from selectedIndex const selectedOption = !isEmpty(this.props.options) && this.props.selectedIndex !== undefined && this.props.selectedIndex > -1 ? this.props.options[this.props.selectedIndex].label : this.props.label; // for display selected option, there is no separate option to show placeholder const value = !isNil(selectedOption) && selectedOption !== "" ? selectedOption : this.props.placeholder || "-- Select --"; return ( {labelText && ( {labelText} )} } onActiveItemChange={this.handleActiveItemChange} onItemSelect={this.onItemSelect} onQueryChange={this.onQueryChange} popoverProps={{ boundary: "window", minimal: true, usePortal: true, onClose: () => { if (!this.props.selectedIndex) return; return this.handleActiveItemChange( this.props.options[this.props.selectedIndex], ); }, modifiers: { preventOverflow: { enabled: false, }, }, popoverClassName: `select-popover-wrapper select-popover-width-${widgetId}`, }} query={this.state.query} scrollToActiveItem value={this.props.value as string} >