Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/iris-grid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@hello-pangea/dnd": "^18.0.1",
"@tanstack/react-virtual": "^3.13.12",
"classnames": "^2.3.1",
"fast-deep-equal": "^3.1.3",
"lodash.clamp": "^4.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import { type FlattenedIrisGridTreeItem } from './sortable-tree/utilities';
type SearchItemProps = {
value: string;
item: FlattenedIrisGridTreeItem;
onClick: (name: string, event: React.MouseEvent<HTMLElement>) => void;
onKeyDown: (name: string, event: React.KeyboardEvent<HTMLElement>) => void;
onClick: (
item: FlattenedIrisGridTreeItem,
event: React.MouseEvent<HTMLElement>
) => void;
onKeyDown: (
item: FlattenedIrisGridTreeItem,
event: React.KeyboardEvent<HTMLElement>
) => void;
handleProps?: Record<string, unknown>;
};

Expand All @@ -19,16 +25,16 @@ const SearchItem = forwardRef<HTMLDivElement, SearchItemProps>(

const handleClick = useCallback(
(event: React.MouseEvent<HTMLElement>) => {
onClick(value, event);
onClick(item, event);
},
[onClick, value]
[onClick, item]
);

const handleKeyDown = useCallback(
(event: React.KeyboardEvent<HTMLElement>) => {
onKeyDown(value, event);
onKeyDown(item, event);
},
[onKeyDown, value]
[onKeyDown, item]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@
flex-direction: column;
max-height: inherit;

.tree-container {
max-height: inherit;
.search-tree-container {
/**
* Prevents the virtualized list from rendering all items
* and then popper limiting the height to a reasonable amount
* since popper needs to know the internal height to limit the container after
*/
max-height: 100vh;
padding: $spacer-1;
overflow: auto;
flex-grow: 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import './SearchWithModal.scss';
import MemoizedSearchItem from './SearchItem';

interface SearchWithModalProps {
items: FlattenedIrisGridTreeItem[];
items: readonly FlattenedIrisGridTreeItem[];
onModalOpenChange: (isOpen: boolean) => void;
onClick: (name: string, event: React.MouseEvent<HTMLElement>) => void;
onClick: (
item: FlattenedIrisGridTreeItem,
event: React.MouseEvent<HTMLElement>
) => void;
onDragStart?: (event: DragStartEvent) => void;
setSelection: (columnNames: string[]) => void;
setSelection: (items: readonly FlattenedIrisGridTreeItem[]) => void;
}

export function SearchWithModal({
Expand Down Expand Up @@ -94,8 +97,8 @@ export function SearchWithModal({
});

const handleClick = useCallback(
(name: string, event: React.MouseEvent<HTMLElement>) => {
onClick(name, event);
(item: FlattenedIrisGridTreeItem, event: React.MouseEvent<HTMLElement>) => {
onClick(item, event);
if (!event.shiftKey && !GridUtils.isModifierKeyDown(event)) {
handleModalClose();
}
Expand All @@ -104,13 +107,16 @@ export function SearchWithModal({
);

const handleItemKeyDown = useCallback(
(name: string, event: React.KeyboardEvent<HTMLElement>) => {
(
item: FlattenedIrisGridTreeItem,
event: React.KeyboardEvent<HTMLElement>
) => {
const { key } = event;
if (key === 'Enter') {
// Select item and close modal
event.preventDefault();
event.stopPropagation();
setSelection([name]);
setSelection([item]);
handleModalClose();
} else if (key === 'ArrowDown') {
// Move focus to the next item
Expand Down Expand Up @@ -191,7 +197,7 @@ export function SearchWithModal({
e.preventDefault();
// Select the first item in the list
const firstItem = filteredItems[0];
setSelection([firstItem.id]);
setSelection([firstItem]);
handleModalClose();
}

Expand All @@ -208,8 +214,7 @@ export function SearchWithModal({
);

const handleSelectMatching = useCallback(() => {
const matchingNames = filteredItems.map(item => item.id);
setSelection(matchingNames);
setSelection(filteredItems);
handleModalClose();
}, [filteredItems, setSelection, handleModalClose]);

Expand Down Expand Up @@ -266,11 +271,13 @@ export function SearchWithModal({
<div className="no-results">No matching columns</div>
) : (
<>
<SortableTree
items={filteredItems}
withDepthMarkers={false}
renderItem={renderItem}
/>
<div className="search-tree-container">
<SortableTree
items={filteredItems}
withDepthMarkers={false}
renderItem={renderItem}
/>
</div>
{showFooterButtons && (
<div className="footer-buttons">
{hasMultipleSelection && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
.visibility-ordering-list {
overflow-y: auto;
flex-grow: 1;
padding: $spacer-1;

.btn {
height: 28px;
Expand Down Expand Up @@ -72,8 +73,4 @@
margin-left: $spacer-1;
height: 1rem;
}

.tree-container {
padding: $spacer-1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,31 @@ const NESTED_COLUMN_HEADER_GROUPS = [
] satisfies (Omit<DhType.ColumnGroup, 'color'> & { color?: string | null })[];

window.HTMLElement.prototype.scroll = jest.fn();
window.HTMLElement.prototype.scrollTo = jest.fn();
window.HTMLElement.prototype.scrollIntoView = jest.fn();

// eslint-disable-next-line @typescript-eslint/consistent-type-imports
jest.mock<typeof import('@tanstack/react-virtual')>(
'@tanstack/react-virtual',
() => {
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const actual = jest.requireActual<typeof import('@tanstack/react-virtual')>(
'@tanstack/react-virtual'
);
return {
...actual,
useVirtualizer(options) {
return actual.useVirtualizer({
...options,
observeElementRect: (instance, callback) => {
if (instance.scrollElement) callback({ width: 300, height: 1000 });
},
});
},
};
}
);

function Builder({
model = makeModel(),
hiddenColumns = [],
Expand Down Expand Up @@ -1743,15 +1766,16 @@ describe('Search', () => {
).toBe(2 * COLUMNS.length)
);

// Globally mocked scrollIntoView for this test file
jest.mocked(window.HTMLElement.prototype.scrollIntoView).mockClear();
// Virtualizer calls scrollTo on the container element
const mockScrollTo = jest.fn();
HTMLElement.prototype.scrollTo = mockScrollTo;

// Click the search item
await user.click(screen.getAllByText(COLUMNS.at(-1)!.name)[1]);
await user.click(screen.getAllByText(COLUMNS[COLUMNS.length - 1].name)[1]);

await waitFor(() => {
const item = screen.getByText(COLUMNS.at(-1)!.name);
expect(item.scrollIntoView).toHaveBeenCalledTimes(1);
const item = screen.getByText(COLUMNS[COLUMNS.length - 1].name);
expect(mockScrollTo).toHaveBeenCalledTimes(1);
expect(item.closest('.tree-item')).toHaveFocus();
});
});
Expand Down
Loading
Loading