diff --git a/src/components/TreeList/__stories__/stories/WithDndListStory.tsx b/src/components/TreeList/__stories__/stories/WithDndListStory.tsx index b206041a7d..84ec076df7 100644 --- a/src/components/TreeList/__stories__/stories/WithDndListStory.tsx +++ b/src/components/TreeList/__stories__/stories/WithDndListStory.tsx @@ -45,8 +45,13 @@ export interface WithDndListStoryProps export const WithDndListStory = (storyProps: WithDndListStoryProps) => { const [items, setItems] = React.useState(randomItems); + const containerRef = React.useRef(null); const listState = useListState(); + React.useLayoutEffect(() => { + containerRef?.current?.focus(); + }, []); + const renderContainer: TreeListRenderContainer = ({ renderItem, visibleFlattenIds, @@ -58,6 +63,8 @@ export const WithDndListStory = (storyProps: WithDndListStoryProps) => { setItems((currentItems) => reorderArray(currentItems, source.index, destination.index), ); + + listState.setActiveItemId(`${destination.index}`); } }; @@ -75,7 +82,7 @@ export const WithDndListStory = (storyProps: WithDndListStoryProps) => { rubric.source.index, { provided, - active: snapshot.isDragging, + isDragging: snapshot.isDragging, }, ); }} @@ -126,7 +133,7 @@ export const WithDndListStory = (storyProps: WithDndListStoryProps) => { )} @@ -135,9 +142,10 @@ export const WithDndListStory = (storyProps: WithDndListStoryProps) => { return ( ({title: someRandomKey})} // you can omit this prop here. If prop `id` passed, TreeSelect would take it by default getId={({id}) => id} diff --git a/src/components/TreeSelect/TreeSelect.tsx b/src/components/TreeSelect/TreeSelect.tsx index 18cca541ce..76d44a0885 100644 --- a/src/components/TreeSelect/TreeSelect.tsx +++ b/src/components/TreeSelect/TreeSelect.tsx @@ -23,6 +23,8 @@ const b = block('tree-select'); export const TreeSelect = React.forwardRef(function TreeSelect( { id, + qa, + placement, slotBeforeListBody, slotAfterListBody, size, @@ -51,8 +53,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( renderItem, renderContainer, onItemClick, - placement, - qa, + setActiveItemId: propsSetActiveItemId, getItemContent, }: TreeSelectProps, ref: React.Ref, @@ -80,6 +81,8 @@ export const TreeSelect = React.forwardRef(function TreeSelect( selectedById: selected, }); + const setActiveItemId = propsSetActiveItemId ?? listState.setActiveItemId; + const listParsedState = useList({ items, getId, @@ -112,7 +115,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( if (listState.disabledById[listItemId]) return; // always activate selected item - listState.setActiveItemId(listItemId); + setActiveItemId(listItemId); if (isGroup && groupsBehavior === 'expandable') { listState.setExpanded((state) => ({ @@ -145,6 +148,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( [ onItemClick, listState, + setActiveItemId, groupsBehavior, multiple, handleMultipleSelection, @@ -159,7 +163,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( const lastSelectedItemId = value[value.length - 1]; containerRef.current?.focus(); - listState.setActiveItemId(lastSelectedItemId); + setActiveItemId(lastSelectedItemId); if (lastSelectedItemId) { scrollToListItem(lastSelectedItemId, containerRef.current); @@ -255,7 +259,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect( selectedById: listState.selectedById, expandedById: listState.expandedById, activeItemId: listState.activeItemId, - setActiveItemId: listState.setActiveItemId, + setActiveItemId, onItemClick: handleItemClick, items, renderContainer, diff --git a/src/components/TreeSelect/__stories__/components/WithDndListExample.tsx b/src/components/TreeSelect/__stories__/components/WithDndListExample.tsx index 9834bda55b..8719398f42 100644 --- a/src/components/TreeSelect/__stories__/components/WithDndListExample.tsx +++ b/src/components/TreeSelect/__stories__/components/WithDndListExample.tsx @@ -50,6 +50,7 @@ const randomItems: CustomDataType[] = createRandomizedData({ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { const [items, setItems] = React.useState(randomItems); + const [activeItemId, setActiveItemId] = React.useState(undefined); const [value, setValue] = React.useState([]); const renderContainer: TreeSelectRenderContainer = ({ @@ -63,6 +64,8 @@ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { setItems((currentItems) => reorderArray(currentItems, source.index, destination.index), ); + + setActiveItemId(`${destination.index}`); } }; @@ -80,7 +83,7 @@ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { rubric.source.index, { provided, - active: snapshot.isDragging, + isDragging: snapshot.isDragging, }, ); }} @@ -131,7 +134,7 @@ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { )} @@ -144,6 +147,8 @@ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { {...storyProps} value={value} items={items} + activeItemId={activeItemId} + setActiveItemId={setActiveItemId} // you can omit this prop here. If prop `id` passed, TreeSelect would take it by default getId={({id}) => id} getItemContent={({someRandomKey}) => ({ @@ -152,6 +157,7 @@ export const WithDndListExample = (storyProps: WithDndListExampleProps) => { onItemClick={({id, isGroup, disabled}) => { if (!isGroup && !disabled) { setValue([id]); + setActiveItemId(id); } }} renderContainer={renderContainer} diff --git a/src/components/TreeSelect/types.ts b/src/components/TreeSelect/types.ts index a9413ee05d..0b86e27e42 100644 --- a/src/components/TreeSelect/types.ts +++ b/src/components/TreeSelect/types.ts @@ -81,6 +81,7 @@ export interface TreeSelectProps extends QAProps, Partial[]; /** * Define custom id depended on item data value to use in controlled state component variant */ @@ -102,5 +103,5 @@ export interface TreeSelectProps extends QAProps, Partial; - items: ListItemType[]; + setActiveItemId?(listItemId?: ListItemId): void; } diff --git a/src/components/useList/__stories__/components/ListWithDnd.tsx b/src/components/useList/__stories__/components/ListWithDnd.tsx index a11aa28d01..00fc278b31 100644 --- a/src/components/useList/__stories__/components/ListWithDnd.tsx +++ b/src/components/useList/__stories__/components/ListWithDnd.tsx @@ -113,7 +113,7 @@ export const ListWithDnd = ({size, itemsCount}: ListWithDndProps) => { {...data} {...provided.draggableProps} {...provided.dragHandleProps} - active={snapshot.isDragging} + isDragging={snapshot.isDragging} ref={provided.innerRef} endSlot={} /> diff --git a/src/components/useList/components/ListItemView/ListItemView.scss b/src/components/useList/components/ListItemView/ListItemView.scss index f52396a845..717b21b4b5 100644 --- a/src/components/useList/components/ListItemView/ListItemView.scss +++ b/src/components/useList/components/ListItemView/ListItemView.scss @@ -21,7 +21,7 @@ $block: '.#{variables.$ns}list-item-view'; } &_selected, - &_selected#{$block}_active, // if active and selected selected bgc more priority + &_selected:not(#{$block}_isDragging)#{$block}_active, // if active and selected selected bgc more priority &_selected:hover#{$block}_activeOnHover { background: var(--g-color-base-selection); } diff --git a/src/components/useList/components/ListItemView/ListItemView.tsx b/src/components/useList/components/ListItemView/ListItemView.tsx index 90be600114..fac7bfe282 100644 --- a/src/components/useList/components/ListItemView/ListItemView.tsx +++ b/src/components/useList/components/ListItemView/ListItemView.tsx @@ -52,6 +52,10 @@ export interface ListItemViewProps extends QAProps { className?: string; role?: React.AriaRole; expanded?: boolean; + /** + * Add active styles and change selection behavior during dnd is performing + */ + isDragging?: boolean; /** * `[${LIST_ITEM_DATA_ATR}="${id}"]` data attribute to find element. * For example for scroll to @@ -105,6 +109,7 @@ export const ListItemView = React.forwardRef( height, expanded, style, + isDragging, role = 'option', onClick: _onClick, ...rest @@ -121,10 +126,11 @@ export const ListItemView = React.forwardRef( onClick={onClick} className={b( { - active, + active: isDragging || active, selected: selected && !hasSelectionIcon, activeOnHover, radius: size, + isDragging, clickable: Boolean(onClick), }, spacing({px: 2}, className),