import React, { ChangeEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState, } from "react"; import TreeSelect, { TreeSelectProps as SelectProps } from "rc-tree-select"; import { TreeSelectContainer, DropdownStyles, StyledIcon, StyledLabel, TextLabelWrapper, } from "./index.styled"; import "rc-tree-select/assets/index.less"; import { DefaultValueType } from "rc-tree-select/lib/interface"; import { TreeNodeProps } from "rc-tree-select/lib/TreeNode"; import { CANVAS_CLASSNAME, MODAL_PORTAL_CLASSNAME, TextSize, } from "constants/WidgetConstants"; import { Button, Classes, InputGroup } from "@blueprintjs/core"; import { labelMargin, WidgetContainerDiff } from "widgets/WidgetUtils"; import Icon from "components/ads/Icon"; import { Colors } from "constants/Colors"; export interface TreeSelectProps extends Required< Pick< SelectProps, | "disabled" | "placeholder" | "loading" | "dropdownStyle" | "allowClear" | "options" > > { value?: DefaultValueType; onChange: (value?: DefaultValueType, labelList?: ReactNode[]) => void; expandAll: boolean; labelText?: string; labelTextColor?: string; labelTextSize?: TextSize; labelStyle?: string; compactMode: boolean; dropDownWidth: number; width: number; isValid: boolean; filterText?: string; widgetId: string; isFilterable: boolean; } const getSvg = (expanded: boolean) => ( ); const switcherIcon = (treeNode: TreeNodeProps) => { if (treeNode.isLeaf) { return ( ); } return getSvg(treeNode.expanded); }; const FOCUS_TIMEOUT = 500; function SingleSelectTreeComponent({ allowClear, compactMode, disabled, dropdownStyle, dropDownWidth, expandAll, filterText, isFilterable, isValid, labelStyle, labelText, labelTextColor, labelTextSize, loading, onChange, options, placeholder, value, widgetId, width, }: TreeSelectProps): JSX.Element { const [key, setKey] = useState(Math.random()); const [filter, setFilter] = useState(filterText ?? ""); const labelRef = useRef(null); const _menu = useRef(null); const inputRef = useRef(null); const [memoDropDownWidth, setMemoDropDownWidth] = useState(0); // treeDefaultExpandAll is uncontrolled after first render, // using this to force render to respond to changes in expandAll useEffect(() => { setKey(Math.random()); }, [expandAll]); const getDropdownPosition = useCallback(() => { const node = _menu.current; if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) { return document.querySelector( `.${MODAL_PORTAL_CLASSNAME}`, ) as HTMLElement; } return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement; }, []); const onClear = useCallback(() => onChange([], []), []); const onOpen = useCallback((open: boolean) => { if (open) { setTimeout(() => inputRef.current?.focus(), FOCUS_TIMEOUT); } }, []); const clearButton = useMemo( () => filter ? (