From b1e537eaf3625ba15a3f8c75bec29391bf51464f Mon Sep 17 00:00:00 2001
From: Laura Silva <91160746+silvalaura@users.noreply.github.com>
Date: Wed, 11 Dec 2024 10:36:40 -0500
Subject: [PATCH] fix(TreeView): Support 'show all' button inside TreeView
component (#1591)
---
.../src/components/TreeView/TreeView.test.js | 313 ++++++++++++++++++
.../src/components/TreeView/useTreeView.ts | 2 +
2 files changed, 315 insertions(+)
diff --git a/packages/react-magma-dom/src/components/TreeView/TreeView.test.js b/packages/react-magma-dom/src/components/TreeView/TreeView.test.js
index 350f048bf..ebf93eed1 100644
--- a/packages/react-magma-dom/src/components/TreeView/TreeView.test.js
+++ b/packages/react-magma-dom/src/components/TreeView/TreeView.test.js
@@ -3538,4 +3538,317 @@ describe('TreeView', () => {
expect(queryByTestId('item1-expand')).not.toBeInTheDocument();
});
});
+
+ describe('tree with hidden items', () => {
+ const propsFlatTree = {
+ title: 'Chapter/Subchapter',
+ trees: [
+ {
+ id: 'tree-id',
+ groupName: 'book-table-of-contents',
+ items: [
+ {
+ id: 'item-id-1',
+ title: 'item-title-1',
+ children: [],
+ },
+ {
+ id: 'item-id-2',
+ title: 'item-title-2',
+ children: [],
+ },
+ {
+ id: 'item-id-3',
+ title: 'item-title-3',
+ children: [],
+ },
+ {
+ id: 'item-id-4',
+ title: 'item-title-4',
+ children: [
+ {
+ id: 'item-id-4.1',
+ title: 'item-title-4.1',
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 'item-id-5',
+ title: 'item-title-5',
+ children: [],
+ },
+ {
+ id: 'item-id-6',
+ title: 'item-title-6',
+ children: [],
+ },
+ ],
+ preselectedItems: [
+ {
+ itemId: 'item-id-2',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ ],
+ },
+ ],
+ keyForRerenderOfTagsTree: true,
+ };
+
+ const propsTreeWithParent = {
+ title: 'Chapter/Subchapter',
+ trees: [
+ {
+ id: 'tree-id',
+ groupName: 'book-table-of-contents',
+ items: [
+ {
+ id: 'item-id-1',
+ title: 'item-title-1',
+ children: [],
+ },
+ {
+ id: 'item-id-2',
+ title: 'item-title-2',
+ children: [],
+ },
+ {
+ id: 'item-id-3',
+ title: 'item-title-3',
+ children: [],
+ },
+ {
+ id: 'item-id-4',
+ title: 'item-title-4',
+ children: [],
+ },
+ {
+ id: 'item-id-5',
+ title: 'item-title-5',
+ children: [
+ {
+ id: 'item-id-6',
+ title: 'item-title-6',
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 'item-id-7',
+ title: 'item-title-7',
+ children: [
+ {
+ id: 'item-id-8',
+ title: 'item-title-8',
+ children: [],
+ },
+ {
+ id: 'item-id-9',
+ title: 'item-title-9',
+ children: [
+ {
+ id: 'item-id-10',
+ title: 'item-title-10',
+ children: [],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ preselectedItems: [
+ {
+ itemId: 'item-id-2',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ ],
+ },
+ ],
+ keyForRerenderOfTagsTree: true,
+ };
+
+ it('renders tree with some items, and clicking show all displays the rest of the tree', () => {
+ const onSelectedItemChange = jest.fn();
+ const { asFragment, getByLabelText, getByTestId } = render(
+
+ );
+
+ expect(asFragment()).toMatchSnapshot();
+
+ expect(getByLabelText('item-title-1')).toBeInTheDocument();
+ expect(getByLabelText('item-title-2')).toBeInTheDocument();
+ expect(getByLabelText('item-title-3')).toBeInTheDocument();
+ expect(getByLabelText('item-title-4')).toBeInTheDocument();
+ expect(getByLabelText('item-title-5')).toBeInTheDocument();
+
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(getByLabelText('item-title-6')).toBeInTheDocument();
+ userEvent.click(getByLabelText('item-title-6'));
+ expect(getByTestId('item-id-6')).toHaveAttribute('aria-checked', 'true');
+ expect(onSelectedItemChange).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders tree with some items preselected, clicking show all displays the rest of the tree and preselected items remain selected', () => {
+ const onSelectedItemChange = jest.fn();
+ const { asFragment, getByLabelText, getByTestId } = render(
+
+ );
+
+ expect(asFragment()).toMatchSnapshot();
+
+ expect(getByLabelText('item-title-1')).toBeInTheDocument();
+ expect(getByLabelText('item-title-2')).toBeInTheDocument();
+ expect(getByLabelText('item-title-3')).toBeInTheDocument();
+ expect(getByLabelText('item-title-4')).toBeInTheDocument();
+ expect(getByLabelText('item-title-5')).toBeInTheDocument();
+
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'true');
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(getByLabelText('item-title-6')).toBeInTheDocument();
+ userEvent.click(getByLabelText('item-title-6'));
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'true');
+ expect(onSelectedItemChange).toHaveBeenCalledWith([
+ {
+ itemId: 'item-id-2',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ {
+ itemId: 'item-id-6',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ ]);
+ });
+
+ it('renders tree with some items preselected, deselecting preselected items, clicking show all displays the rest of the tree and preselected items remain deselected', () => {
+ const onSelectedItemChange = jest.fn();
+ const { asFragment, getByLabelText, getByTestId } = render(
+
+ );
+
+ expect(asFragment()).toMatchSnapshot();
+
+ expect(getByLabelText('item-title-1')).toBeInTheDocument();
+ expect(getByLabelText('item-title-2')).toBeInTheDocument();
+ expect(getByLabelText('item-title-3')).toBeInTheDocument();
+ expect(getByLabelText('item-title-4')).toBeInTheDocument();
+ expect(getByLabelText('item-title-5')).toBeInTheDocument();
+
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'true');
+ userEvent.click(getByLabelText('item-title-2'));
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(getByLabelText('item-title-6')).toBeInTheDocument();
+ userEvent.click(getByLabelText('item-title-6'));
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'false');
+ expect(onSelectedItemChange).toHaveBeenCalledWith([
+ {
+ itemId: 'item-id-6',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ ]);
+ });
+
+ it('clicking show all displays the rest of the tree, preselected items remain selected, and clicking show less maintains selected items', () => {
+ const onSelectedItemChange = jest.fn();
+ const { asFragment, getByLabelText, getByTestId } = render(
+
+ );
+
+ expect(asFragment()).toMatchSnapshot();
+
+ expect(getByLabelText('item-title-1')).toBeInTheDocument();
+ expect(getByLabelText('item-title-2')).toBeInTheDocument();
+ expect(getByLabelText('item-title-3')).toBeInTheDocument();
+ expect(getByLabelText('item-title-4')).toBeInTheDocument();
+ expect(getByLabelText('item-title-5')).toBeInTheDocument();
+
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'true');
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(getByLabelText('item-title-6')).toBeInTheDocument();
+ userEvent.click(getByLabelText('item-title-6'));
+ expect(getByTestId('item-id-2')).toHaveAttribute('aria-checked', 'true');
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(onSelectedItemChange).toHaveBeenCalledTimes(2);
+ expect(onSelectedItemChange).toHaveBeenCalledWith([
+ {
+ itemId: 'item-id-2',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ {
+ itemId: 'item-id-6',
+ checkedStatus: IndeterminateCheckboxStatus.checked,
+ },
+ ]);
+ });
+
+ it('can uncheck all items by clicking on the parent (including hidden one)', () => {
+ const onSelectedItemChange = jest.fn();
+ const { asFragment, getByLabelText, getByTestId } = render(
+
+ );
+
+ expect(asFragment()).toMatchSnapshot();
+
+ expect(getByLabelText('item-title-1')).toBeInTheDocument();
+ expect(getByLabelText('item-title-2')).toBeInTheDocument();
+ expect(getByLabelText('item-title-3')).toBeInTheDocument();
+ expect(getByLabelText('item-title-4')).toBeInTheDocument();
+ expect(getByLabelText('item-title-5')).toBeInTheDocument();
+
+ userEvent.click(getByTestId('showAllBtn'));
+ expect(getByLabelText('item-title-7')).toBeInTheDocument();
+
+ userEvent.click(getByLabelText('item-title-7'));
+ userEvent.click(getByTestId('item-id-7-expand'));
+ expect(getByTestId('item-id-8')).toHaveAttribute('aria-checked', 'true');
+ expect(getByTestId('item-id-9')).toHaveAttribute('aria-checked', 'true');
+
+ userEvent.click(getByLabelText('item-title-7'));
+ expect(getByTestId('item-id-8')).toHaveAttribute('aria-checked', 'false');
+ expect(getByTestId('item-id-9')).toHaveAttribute('aria-checked', 'false');
+
+ userEvent.click(getByTestId('item-id-9-expand'));
+ userEvent.click(getByLabelText('item-title-10'));
+ expect(getByTestId('item-id-10')).toHaveAttribute('aria-checked', 'true');
+ expect(getByTestId('item-id-9')).toHaveAttribute('aria-checked', 'true');
+ expect(getByTestId('item-id-7')).toHaveAttribute('aria-checked', 'mixed');
+
+ userEvent.click(getByTestId('showAllBtn')); // show less
+ expect(onSelectedItemChange).toHaveBeenCalledTimes(3);
+ });
+ });
});
diff --git a/packages/react-magma-dom/src/components/TreeView/useTreeView.ts b/packages/react-magma-dom/src/components/TreeView/useTreeView.ts
index fce719754..5d2101fb0 100644
--- a/packages/react-magma-dom/src/components/TreeView/useTreeView.ts
+++ b/packages/react-magma-dom/src/components/TreeView/useTreeView.ts
@@ -152,6 +152,8 @@ export function useTreeView(props: UseTreeViewProps) {
});
const selectedItems = React.useMemo(() => {
+ console.log(items);
+
return items.filter(
item => item.checkedStatus === IndeterminateCheckboxStatus.checked
);