Skip to content

Commit

Permalink
fix(TreeView): Support 'show all' button inside TreeView component
Browse files Browse the repository at this point in the history
  • Loading branch information
silvalaura committed Dec 3, 2024
1 parent 816a230 commit e3c8ed7
Show file tree
Hide file tree
Showing 5 changed files with 1,736 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/tree-showAllExample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-magma-dom': patch
---

fix(TreeView): Support "show all" button inside TreeView component
167 changes: 167 additions & 0 deletions packages/react-magma-dom/src/components/TreeView/TreeView.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import {
ButtonGroup,
Spacer,
SpacerAxis,
Accordion,
AccordionItem,
AccordionButton,
AccordionPanel
} from '../..';
import { ButtonSize } from '../Button';
import { FlexAlignContent, FlexAlignItems } from '../Flex';
Expand Down Expand Up @@ -1097,3 +1101,166 @@ InvalidTreeItems.parameters = {
exclude: ['isInverse', 'initialExpandedItems', 'ariaLabelledBy'],
},
};

// MAST Tree example with hidden items

const renderTreeItemsRecursively = (terms, depth) => {
const labelStyles = {
overflow: 'hidden',
textOverflow: 'ellipsis',
width: 230 - depth * 24 + 'px',
display: 'inline-block',
};
return terms.map(term => {
return (
<TreeItem
itemId={term.id}
key={term.id}
label={term.title}
labelStyle={labelStyles}
title={term.title}
isDisabled={term.title === 'item-title-1'}
>
{term.children?.length ? (
renderTreeItemsRecursively(term.children, depth + 1)
) : (
<></>
)}
</TreeItem>
);
});
};

const AccordionSectionWithTreeView = props => {
const {
trees,
title,
keyForRerenderOfTagsTree,
id,
isDisabled,
onSelectedItemChange,
...rest
} = props;
const [isShowAll, setIsShowAll] = React.useState(false);
const isSingeTaxonomyOfSuchType = trees.length === 1;
const customIndex = Number(id) || 0;
const getTermsForRender = terms => {
if (isShowAll || terms.length <= 5) return terms;
return terms.slice(0, 5);
};
const getTreesForRender = () => {
if (isShowAll || trees.length <= 5) return trees;
return trees.slice(0, 5);
};
const toggleShowAll = () => {
setIsShowAll(prev => !prev);
};
const renderTrees = () => {
return (
<>
{getTreesForRender().map(tree => {
// RM issue with types. Should be "TreeItemSelectedInterface" instead of "Object".
// eslint-disable-next-line @typescript-eslint/ban-types
const handleSelectedItemChange = selectedItems => {
// onSelectedItemChange(selectedItems, tree.groupName, tree.id);
};
return (
<TreeView
key={JSON.stringify(`${keyForRerenderOfTagsTree}-${tree.id}`)}
onSelectedItemChange={handleSelectedItemChange}
preselectedItems={tree.preselectedItems}
selectable={TreeViewSelectable.multi}
>
{renderTreeItemsRecursively(
isSingeTaxonomyOfSuchType
? getTermsForRender(tree.items)
: tree.items,
0
)}
</TreeView>
);
})}
</>
);
};
const isShowAllButtonVisible =
trees.length === 1 ? trees[0].items.length > 5 : trees.length > 5;
return (
<AccordionItem {...rest} index={customIndex} isDisabled={isDisabled}>
<AccordionButton>{title}</AccordionButton>
<AccordionPanel>
{renderTrees()}
{isShowAllButtonVisible && (
<Button
disabled={isDisabled}
onClick={toggleShowAll}
size={ButtonSize.small}
variant={ButtonVariant.link}
testId='showAllBtn'
>
{isShowAll ? 'Show Less' : 'Show All'}
</Button>
)}
</AccordionPanel>
</AccordionItem>
);
};


export const TreeWithShowAll = args => {
const props = {
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: [],
},
],
keyForRerenderOfTagsTree: true,
};

return (
<Accordion defaultIndex={[0]} isMulti testId="accordion">
<AccordionSectionWithTreeView {...props} {...args} />
</Accordion>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { transparentize } from 'polished';
import { IndeterminateCheckboxStatus } from '../IndeterminateCheckbox';
import { Tag } from '../Tag';
import { Paragraph } from '../Paragraph';
import { TreeWithShowAll } from './TreeView.stories';

const TEXT = 'Test Text Tree Item';
const testId = 'tree-view';
Expand Down Expand Up @@ -2326,7 +2327,7 @@ describe('TreeView', () => {
const disabledItemId = 'item-ggchild1';

const onSelectedItemChange = jest.fn();
const { getByTestId, debug } = render(
const { getByTestId } = render(
<TreeItemsMultiLevelControlledOutside
onSelectedItemChange={onSelectedItemChange}
preselectedItems={[
Expand Down Expand Up @@ -2596,4 +2597,24 @@ describe('TreeView', () => {
expect(queryByTestId('item1-expand')).not.toBeInTheDocument();
});
});

describe('tree with hidden items', () => {
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(<TreeWithShowAll onSelectedItemChange={onSelectedItemChange} />);

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(onSelectedItemChange).toHaveBeenCalledTimes(1);
})
})
});
Loading

0 comments on commit e3c8ed7

Please sign in to comment.