diff --git a/src/components/Table/README.md b/src/components/Table/README.md index d94c91d806..642b89fa72 100644 --- a/src/components/Table/README.md +++ b/src/components/Table/README.md @@ -211,10 +211,10 @@ const MyTable1 = withTableSettings({sortable: false})(Table); ### Options -| Name | Description | Type | Default | -| :------- | :------------------------------------------------ | :---------------: | :-----: | -| width | Settings' popup width | `number` `string` | | -| sortable | Whether or not add ability to sort settings items | `boolean` | `true` | +| Name | Description | Type | Default | +| :------- | :------------------------------------------------ | :------------: | :-----: | +| width | Settings' popup width | `number` `fit` | | +| sortable | Whether or not add ability to sort settings items | `boolean` | `true` | ### ColumnMeta @@ -227,7 +227,7 @@ const MyTable1 = withTableSettings({sortable: false})(Table); | Name | Description | Type | | :----------------- | :---------------------------- | :------------------------------------------: | -| settingsPopupWidth | TableColumnSetup pop-up width | `number` `string` | +| settingsPopupWidth | TableColumnSetup pop-up width | `number` `fit` | | settings | Current settings | `TableSettingsData` | | updateSettings | Settings update handle | `(data: TableSettingsData) => Promise` | diff --git a/src/components/Table/__stories__/Table.stories.tsx b/src/components/Table/__stories__/Table.stories.tsx index 762032e99e..cb1e792dfb 100644 --- a/src/components/Table/__stories__/Table.stories.tsx +++ b/src/components/Table/__stories__/Table.stories.tsx @@ -178,9 +178,32 @@ const WithTableSettingsTemplate: StoryFn> = (args, context) } }; export const HOCWithTableSettings = WithTableSettingsTemplate.bind({}); +HOCWithTableSettings.parameters = { + // Strict mode ruins sortable list due to this react-beautiful-dnd issue + // https://github.com/atlassian/react-beautiful-dnd/issues/2350 + disableStrictMode: true, +}; +const columnsWithSettings = _cloneDeep(columns); +const markColumnAsSelectedAlways = (idx: number) => { + const column = columnsWithSettings[idx]; + column.meta = column.meta || {}; + column.meta.selectedAlways = true; +}; + +markColumnAsSelectedAlways(2); +markColumnAsSelectedAlways(3); + +HOCWithTableSettings.args = { + columns: columnsWithSettings, +}; + export const HOCWithTableSettingsFactory = WithTableSettingsTemplate.bind({}); HOCWithTableSettingsFactory.parameters = { isFactory: true, + + // Strict mode ruins sortable list due to this react-beautiful-dnd issue + // https://github.com/atlassian/react-beautiful-dnd/issues/2350 + disableStrictMode: true, }; // --------------------------------- diff --git a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss index 5ca73f8d78..92c8fc42e9 100644 --- a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss +++ b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss @@ -3,61 +3,18 @@ $block: '.#{variables.$ns}table-column-setup'; #{$block} { - &__controls { - padding: 4px; + &__apply { + margin: var(--g-spacing-1) var(--g-spacing-1) 0; } - &__status { - margin-inline-start: 5px; - color: var(--g-color-text-secondary); - } - - &__tick-wrap { - position: absolute; - inset-inline-start: 14px; - inset-block-start: 50%; - transform: translateY(-50%); - width: 10px; - height: 10px; - visibility: hidden; - - &_visible { - visibility: visible; - } - } - - &__tick { - color: var(--g-color-base-brand); - } - - &__lock-wrap { - position: absolute; - inset-inline-start: 10px; - inset-block-start: 50%; - transform: translateY(-50%); - color: var(--g-color-text-hint); - } - - &__title { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } - - &__items { - overflow-x: auto; - } - - &__item { - // Increasing specificity for overrides - &#{&} { - padding-inline: 32px 8px; - cursor: pointer; - position: relative; + // to override this https://github.com/gravity-ui/uikit/blob/main/src/components/useList/components/ListItemView/ListItemView.scss#L25 + &__required-item { + background: inherit; - .#{variables.$ns}list__item-sort-icon { - cursor: move; - } + &:hover { + /* stylelint-disable declaration-no-important */ + background: var(--g-color-base-simple-hover-solid) !important; + /* stylelint-enable declaration-no-important */ } } } diff --git a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.tsx b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.tsx index e5733ac2ec..408c47e621 100644 --- a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.tsx +++ b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.tsx @@ -1,270 +1,277 @@ import React from 'react'; -import {Check, Gear, Lock} from '@gravity-ui/icons'; +import {Gear, Grip, Lock} from '@gravity-ui/icons'; +import {DragDropContext, Draggable, Droppable} from 'react-beautiful-dnd'; +import type {OnDragEndResponder} from 'react-beautiful-dnd'; +import {useUniqId} from '../../../../../hooks'; import type {PopperPlacement} from '../../../../../hooks/private'; -import {useActionHandlers} from '../../../../../hooks/useActionHandlers'; +import {createOnKeyDownHandler} from '../../../../../hooks/useActionHandlers/useActionHandlers'; import {Button} from '../../../../Button'; import {Icon} from '../../../../Icon'; -import {List} from '../../../../List'; -import {Popup} from '../../../../Popup'; +import {TreeSelect} from '../../../../TreeSelect/TreeSelect'; +import {TreeSelectItem} from '../../../../TreeSelect/TreeSelectItem'; +import type {TreeSelectItemProps} from '../../../../TreeSelect/TreeSelectItem'; +import type { + TreeSelectProps, + TreeSelectRenderContainer, + TreeSelectRenderItem, +} from '../../../../TreeSelect/types'; +import {ListContainerView} from '../../../../useList'; import {block} from '../../../../utils/cn'; -import type {TableColumnSetupItem} from '../withTableSettings'; +import type {TableColumnSetupItem, TableSetting} from '../withTableSettings'; import i18n from './i18n'; import './TableColumnSetup.scss'; const b = block('table-column-setup'); +const tableColumnSetupCn = b(null); +const applyButtonCn = b('apply'); +const requiredDndItemCn = b('required-item'); -type Item = TableColumnSetupItem; +const reorderArray = (list: T[], startIndex: number, endIndex: number): T[] => { + const result = [...list]; + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + + return result; +}; + +const prepareDndItems = (tableColumnItems: TableColumnSetupItem[]) => { + return tableColumnItems.map((tableColumnItem) => { + const hasSelectionIcon = tableColumnItem.isRequired === false; + + return { + ...tableColumnItem, + startSlot: tableColumnItem.isRequired ? : undefined, + hasSelectionIcon, + // to overwrite select background effect - https://github.com/gravity-ui/uikit/blob/main/src/components/useList/components/ListItemView/ListItemView.tsx#L125 + className: hasSelectionIcon ? undefined : requiredDndItemCn, + }; + }); +}; + +const prepareValue = (tableColumnItems: TableColumnSetupItem[]) => { + const selectedIds: string[] = []; + + tableColumnItems.forEach(({id, isSelected}) => { + if (isSelected) { + selectedIds.push(id); + } + }); + + return selectedIds; +}; interface SwitcherProps { onKeyDown: React.KeyboardEventHandler; onClick: React.MouseEventHandler; } +const useDndRenderContainer = ({ + onApply, + onDragEnd, +}: { + onDragEnd: OnDragEndResponder; + onApply: () => void; +}) => { + const uniqId = useUniqId(); + + const dndRenderContainer: TreeSelectRenderContainer = ({ + renderItem, + visibleFlattenIds, + items: _items, + containerRef, + id, + }) => { + const visibleFlattenItemList = visibleFlattenIds.map((visibleFlattenId, idx) => + renderItem(visibleFlattenId, idx), + ); + + return ( + + + + + {(droppableProvided) => { + return ( +
+ {visibleFlattenItemList} + {droppableProvided.placeholder} +
+ ); + }} +
+
+
+ +
+ ); + }; + + return dndRenderContainer; +}; + +const useDndRenderItem = (sortable: boolean | undefined) => { + const renderDndItem: TreeSelectRenderItem = ({data, props, index}) => { + const isDragDisabled = sortable === false; + + const endSlot = + data.endSlot ?? (isDragDisabled ? undefined : ); + + const commonProps = { + ...props, + ...data, + endSlot, + }; + + return ( + + {(provided, snapshot) => { + const style: React.CSSProperties = { + ...provided.draggableProps.style, + }; + + // not expected offset appears, one way to fix - remove this offsets explicitly + if (snapshot.isDragging) { + style.left = undefined; + style.top = undefined; + } + + return ( + + ); + }} + + ); + }; + + return renderDndItem; +}; + +type Item = TableColumnSetupItem & + TreeSelectItemProps & { + id: string; + isDragDisabled?: boolean; + }; + export interface TableColumnSetupProps { - // for Button - disabled?: boolean; - /** - * @deprecated Use renderSwitcher instead - */ - switcher?: React.ReactElement | undefined; - renderSwitcher?: (props: SwitcherProps) => React.ReactElement | undefined; - - // for List - items: Item[]; - itemsHeight?: number | ((items: Item[]) => number); + renderSwitcher?: (props: SwitcherProps) => React.JSX.Element; + + items: TableColumnSetupItem[]; sortable?: boolean; - filterable?: boolean; - onUpdate: (updated: Item[]) => void; - popupWidth?: number | string; + onUpdate: (newSettings: TableSetting[]) => void; + popupWidth?: TreeSelectProps['popupWidth']; popupPlacement?: PopperPlacement; - getItemTitle?: (item: Item) => TableColumnSetupItem['title']; - showStatus?: boolean; - className?: string; } export const TableColumnSetup = (props: TableColumnSetupProps) => { const { - switcher, renderSwitcher, - disabled, popupWidth, popupPlacement, - className, items: propsItems, - itemsHeight, - getItemTitle = (item: Item) => item.title, - sortable = true, - filterable = false, - showStatus, + onUpdate: propsOnUpdate, + sortable, } = props; - const [focused, setFocused] = React.useState(false); - const [items, setItems] = React.useState([]); - const [currentItems, setCurrentItems] = React.useState([]); - const [requiredItems, setRequiredItems] = React.useState([]); + const [open, setOpen] = React.useState(false); - const refControl = React.useRef(null); + const [items, setItems] = React.useState(propsItems); + const [prevPropsItems, setPrevPropsItems] = React.useState(propsItems); + if (propsItems !== prevPropsItems) { + setPrevPropsItems(propsItems); - const LIST_ITEM_HEIGHT = 36; - - const getRequiredItems = (list: Item[]) => - list - .filter(({required}) => required) - .map((column) => ({ - ...column, - disabled: true, - })); + setItems(propsItems); + } - const getConfigurableItems = (list: Item[]) => list.filter(({required}) => !required); - - React.useEffect(() => { - if (propsItems !== items) { - setItems(propsItems); - setRequiredItems(getRequiredItems(propsItems)); - setCurrentItems(getConfigurableItems(propsItems)); - } - }, [items, propsItems]); - - const setInitialState = () => { - setFocused(false); - setRequiredItems(getRequiredItems(items)); - setCurrentItems(getConfigurableItems(items)); + const onApply = () => { + const newSettings = items.map(({id, isSelected}) => ({id, isSelected})); + propsOnUpdate(newSettings); + setOpen(false); }; - const getListHeight = (list: Item[]) => { - if (typeof itemsHeight === 'function') { - return itemsHeight(list); - } else if (typeof itemsHeight === 'number') { - return itemsHeight; - } else { - return Math.min(5, list.length) * LIST_ITEM_HEIGHT + LIST_ITEM_HEIGHT / 2; + const onDragEnd: OnDragEndResponder = ({destination, source}) => { + if (destination?.index !== undefined && destination?.index !== source.index) { + setItems((prevItems) => { + return reorderArray(prevItems, source.index, destination.index); + }); } }; - const getRequiredListHeight = (list: Item[]) => { - if (typeof itemsHeight === 'function') { - return itemsHeight(list); - } else if (typeof itemsHeight === 'number') { - return itemsHeight; - } else { - return list.length * LIST_ITEM_HEIGHT; - } - }; - - const getCountSelected = () => items.reduce((acc, cur) => (cur.selected ? acc + 1 : acc), 0); - - const makeOnSortEnd = - (list: Item[]) => - ({oldIndex, newIndex}: {oldIndex: number; newIndex: number}) => { - setCurrentItems(List.moveListElement(list.slice(), oldIndex, newIndex)); - }; + const dndRenderContainer = useDndRenderContainer({onApply, onDragEnd}); - const handleUpdate = (value: Item[]) => setCurrentItems(value); - - const handleClosePopup = () => setInitialState(); - - const handleControlClick = React.useCallback(() => { - if (!disabled) { - setFocused(!focused); - setRequiredItems(getRequiredItems(items)); - setCurrentItems(getConfigurableItems(items)); - } - }, [disabled, focused, items]); - - const handleApplyClick = () => { - setInitialState(); - - const newItems = requiredItems.concat(currentItems); - - if (items !== newItems) { - props.onUpdate(newItems); - } - }; + const dndRenderItem = useDndRenderItem(sortable); - const handleItemClick = (value: Item) => { - const newItems = currentItems.map((item) => - item === value ? {...item, selected: !item.selected} : item, - ); - handleUpdate(newItems); - }; + const renderControl: TreeSelectProps['renderControl'] = ({toggleOpen}) => { + const onKeyDown = createOnKeyDownHandler(toggleOpen); - const renderItem = (item: Item) => { return ( -
- {item.required ? ( -
- -
- ) : ( -
- -
- )} -
{getItemTitle(item)}
-
+ renderSwitcher?.({onClick: toggleOpen, onKeyDown}) || ( + + ) ); }; - const renderStatus = () => { - if (!showStatus) { - return null; - } + const onOpenChange = (open: boolean) => { + setOpen(open); - const selected = getCountSelected(); - const all = propsItems.length; - const status = `${selected}/${all}`; - - return {status}; - }; - - const renderRequiredColumns = () => { - const hasRequiredColumns = requiredItems.length; - - if (!hasRequiredColumns) { - return null; + if (open === false) { + setItems(propsItems); } - - return ( - - ); }; - const renderConfigurableColumns = () => { - return ( - - ); + const onUpdate = (selectedItemsIds: string[]) => { + setItems((prevItems) => { + return prevItems.map((item) => ({ + ...item, + isSelected: selectedItemsIds.includes(item.id), + })); + }); }; - const {onKeyDown: handleControlKeyDown} = useActionHandlers(handleControlClick); - - const switcherProps = React.useMemo( - () => ({ - onClick: handleControlClick, - onKeyDown: handleControlKeyDown, - }), - [handleControlClick, handleControlKeyDown], + const [value, dndItems] = React.useMemo( + () => [prepareValue(items), prepareDndItems(items)] as const, + [items], ); return ( -
- {/* FIXME remove switcher prop and this wrapper */} - {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} -
- {renderSwitcher?.(switcherProps) || switcher || ( - - )} -
- - {renderRequiredColumns()} - {renderConfigurableColumns()} -
- -
-
-
+ ); }; diff --git a/src/components/Table/hoc/withTableSettings/__tests__/withTableSettings.test.tsx b/src/components/Table/hoc/withTableSettings/__tests__/withTableSettings.test.tsx index 2591bccc3b..bdeb24e8ba 100644 --- a/src/components/Table/hoc/withTableSettings/__tests__/withTableSettings.test.tsx +++ b/src/components/Table/hoc/withTableSettings/__tests__/withTableSettings.test.tsx @@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event'; import {render, screen} from '../../../../../../test-utils/utils'; import type {TableColumnConfig} from '../../../Table'; import {Table} from '../../../Table'; -import type {TableSettingsData} from '../withTableSettings'; +import type {TableSetting} from '../withTableSettings'; import {withTableSettings} from '../withTableSettings'; const item = {name: 'John Doe', occupation: 'Worker'}; @@ -23,7 +23,7 @@ const columns: TableColumnConfig[] = [ const data = [item]; -const settings: TableSettingsData = columns.map((column) => ({id: column.id, isSelected: true})); +const settings = columns.map((column) => ({id: column.id, isSelected: true})); test('should change table columns', async () => { const updateSettings = jest.fn(); diff --git a/src/components/Table/hoc/withTableSettings/withTableSettings.tsx b/src/components/Table/hoc/withTableSettings/withTableSettings.tsx index 634b87a66c..b46f4269f1 100644 --- a/src/components/Table/hoc/withTableSettings/withTableSettings.tsx +++ b/src/components/Table/hoc/withTableSettings/withTableSettings.tsx @@ -5,8 +5,10 @@ import _get from 'lodash/get'; import _isString from 'lodash/isString'; import _last from 'lodash/last'; +import type {PopperPlacement} from '../../../../hooks/private'; import {Button} from '../../../Button'; import {Icon} from '../../../Icon'; +import type {TreeSelectProps} from '../../../TreeSelect'; import {block} from '../../../utils/cn'; import {getComponentName} from '../../../utils/getComponentName'; import type {TableColumnConfig, TableDataItem, TableProps} from '../../Table'; @@ -18,22 +20,17 @@ import i18n from './i18n'; import './withTableSettings.scss'; -interface SortableItem { +export type TableSetting = { id: string; - title: React.ReactNode; isSelected?: boolean; - isProtected?: boolean; -} -export interface TableColumnSetupItem { - id: string; +}; + +export type TableSettingsData = TableSetting[]; + +export type TableColumnSetupItem = TableSetting & { title: React.ReactNode; - selected?: boolean; - required?: boolean; -} -export type TableSettingsData = Array<{ - id: string; - isSelected?: boolean; -}>; + isRequired?: boolean; +}; export function filterColumns( columns: TableColumnConfig[], @@ -69,54 +66,51 @@ export function getColumnStringTitle(column: TableColumnConfig) { return column.id; } +const getTableColumnSetupItem = ( + id: string, + isSelected: boolean | undefined, + column: TableColumnConfig | undefined, +): TableColumnSetupItem => { + const isProtected = Boolean(column?.meta?.selectedAlways); + + return { + id, + isSelected: isProtected ? true : isSelected, + isRequired: isProtected, + title: column ? getColumnStringTitle(column) : id, + }; +}; + export function getActualItems( columns: TableColumnConfig[], settings: TableSettingsData, -): SortableItem[] { - const newColumnSettings = columns - .filter( - ({id}) => - id !== actionsColumnId && - id !== selectionColumnId && - settings.every((setting) => setting.id !== id), - ) - .map((column) => ({ - id: column.id, - isSelected: column.meta?.selectedByDefault !== false, - })); - return settings - .filter(({id}) => columns.some((column) => id === column.id)) - .concat(newColumnSettings) - .map(({id, isSelected}) => { - const foundColumn = columns.find((column) => column.id === id); - const isProtected = Boolean(foundColumn?.meta?.selectedAlways); - return { - id, - isSelected: isProtected ? true : isSelected, - isProtected, - title: foundColumn ? getColumnStringTitle(foundColumn) : id, - }; - }); -} +): TableColumnSetupItem[] { + const sortableItems: TableColumnSetupItem[] = []; -function prepareColumnSetupItems(items: SortableItem[]): TableColumnSetupItem[] { - return items.map(({id, title, isSelected, isProtected}) => ({ - id, - title, - selected: isSelected, - required: isProtected, - })); -} + settings.forEach(({id, isSelected}) => { + const column = columns.find((column) => id === column.id); -function prepareUpdateSettings(items: TableColumnSetupItem[]): TableSettingsData { - return items.map(({id, selected}) => ({ - id, - isSelected: selected, - })); + if (column) { + sortableItems.push(getTableColumnSetupItem(id, isSelected, column)); + } + }); + + columns.forEach((column) => { + if ( + column.id !== actionsColumnId && + column.id !== selectionColumnId && + settings.every((setting) => setting.id !== column.id) + ) { + const isSelected = column.meta?.selectedByDefault !== false; + sortableItems.push(getTableColumnSetupItem(column.id, isSelected, column)); + } + }); + + return sortableItems; } export interface WithTableSettingsOptions { - width?: number | string; + width?: TreeSelectProps['popupWidth']; sortable?: boolean; } @@ -124,13 +118,16 @@ export interface WithTableSettingsProps { /** * @deprecated Use factory notation: "withTableSettings({width: })(Table)" */ - settingsPopupWidth?: number | string; + settingsPopupWidth?: TreeSelectProps['popupWidth']; + settings: TableSettingsData; updateSettings: (data: TableSettingsData) => void; } const b = block('table'); +const POPUP_PLACEMENT: PopperPlacement = ['bottom-end', 'bottom', 'top-end', 'top', 'auto']; + export function withTableSettings( Component: React.ComponentType & E>, ): React.ComponentType & WithTableSettingsProps & E>; @@ -159,51 +156,33 @@ export function withTableSettings( settingsPopupWidth, ...restTableProps }: TableProps & WithTableSettingsProps & E) { - const actualItems = React.useMemo( - () => getActualItems(columns, settings || []), - [columns, settings], - ); - - const onUpdateColumns = React.useCallback( - (newItems: TableColumnSetupItem[]) => { - updateSettings(prepareUpdateSettings(newItems)); - }, - [updateSettings], - ); - - const columnSetupItems = React.useMemo( - () => prepareColumnSetupItems(actualItems), - [actualItems], - ); - - const enhancedColumns = React.useMemo( - () => - enhanceSystemColumn(filterColumns(columns, actualItems), (systemColumn) => { - // eslint-disable-next-line react/display-name - systemColumn.name = () => ( -
- ( - - )} - /> -
- ); - }), - [actualItems, columnSetupItems, columns, onUpdateColumns, settingsPopupWidth], - ); + const enhancedColumns = React.useMemo(() => { + const actualItems = getActualItems(columns, settings || []); + + return enhanceSystemColumn(filterColumns(columns, actualItems), (systemColumn) => { + systemColumn.name = () => ( +
+ ( + + )} + /> +
+ ); + }); + }, [columns, settings, updateSettings, settingsPopupWidth]); return ( diff --git a/src/components/TreeSelect/TreeSelect.tsx b/src/components/TreeSelect/TreeSelect.tsx index b2e12fc5bf..07fb35ebcf 100644 --- a/src/components/TreeSelect/TreeSelect.tsx +++ b/src/components/TreeSelect/TreeSelect.tsx @@ -58,6 +58,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( renderItem, renderContainer = TreeListContainer, onItemClick, + placement, } = props; const mobile = useMobile(); @@ -255,6 +256,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( className={b('popup', popupClassName)} controlRef={controlRef} width={popupWidth} + placement={placement} open={open} handleClose={handleClose} disablePortal={popupDisablePortal} diff --git a/src/components/TreeSelect/TreeSelectItem/TreeSelectItem.scss b/src/components/TreeSelect/TreeSelectItem/TreeSelectItem.scss index 3050061dff..1e9abaf47d 100644 --- a/src/components/TreeSelect/TreeSelectItem/TreeSelectItem.scss +++ b/src/components/TreeSelect/TreeSelectItem/TreeSelectItem.scss @@ -3,5 +3,5 @@ $block: '.#{variables.$ns}tree-select-item'; #{$block} { - padding: 0 4px; + padding: 0 var(--g-spacing-1); } diff --git a/src/components/TreeSelect/components/TreeListContainer/TreeListContainer.tsx b/src/components/TreeSelect/components/TreeListContainer/TreeListContainer.tsx index 22ec09a1ee..9b1f6cf39d 100644 --- a/src/components/TreeSelect/components/TreeListContainer/TreeListContainer.tsx +++ b/src/components/TreeSelect/components/TreeListContainer/TreeListContainer.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import type {TreeSelectRenderContainerProps} from 'src/components/TreeSelect/types'; - import {ListContainerView} from '../../../useList'; import {ListItemRecursiveRenderer} from '../../../useList/components/ListRecursiveRenderer/ListRecursiveRenderer'; +import type {TreeSelectRenderContainerProps} from '../../types'; export const TreeListContainer = ({ items, diff --git a/src/components/TreeSelect/types.ts b/src/components/TreeSelect/types.ts index 56402d0098..9a31bb5bdc 100644 --- a/src/components/TreeSelect/types.ts +++ b/src/components/TreeSelect/types.ts @@ -1,5 +1,7 @@ import type React from 'react'; +import type {PopperPlacement} from '../../hooks/private'; +import type {SelectPopupProps} from '../Select/components/SelectPopup/types'; import type {QAProps} from '../types'; import type { KnownItemStructure, @@ -54,7 +56,8 @@ interface TreeSelectBaseProps extends QAProps, Partial