Skip to content

Commit aeae2ab

Browse files
Merge pull request #18 from eugenezinovyev/group-collapse
Expand All / Collapse All
2 parents 8f32fd9 + 8cdbbea commit aeae2ab

File tree

6 files changed

+87
-6
lines changed

6 files changed

+87
-6
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { clsx } from '@lcov-viewer/core';
2+
import React from 'react';
3+
import classes from './LinkButton.module.less';
4+
5+
const LinkButton = ({ children, className, ...props }) => (
6+
<button className={clsx(classes.root, className)} {...props}>{children}</button>
7+
);
8+
9+
export default LinkButton;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@import "@lcov-viewer/core/styles/colors";
2+
3+
.root {
4+
border: none;
5+
outline: none;
6+
background: none;
7+
color: @color-main;
8+
text-decoration: none;
9+
margin: 0;
10+
padding: 0;
11+
font-family: inherit;
12+
font-size: inherit;
13+
cursor: pointer;
14+
15+
&:hover {
16+
color: darken(@color-main, 20%);
17+
}
18+
}
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React, { useMemo } from 'react';
22
import buildTableRowsData from '../render/buildTableRowsData';
3+
import LinkButton from '../LinkButton/LinkButton';
34
import renderRow from '../render/renderRow';
45
import renderTable from '../render/renderTable';
56
import useCollapse from './useCollapse';
67
import classes from './TreeView.module.less';
78

89
const TreeView = ({ coverage, linkSelector }) => {
9-
const collapseContainer = useCollapse();
10+
const [collapseContainer, onCollapseAll, onExpandAll] = useCollapse();
1011
const tableHTML = useMemo(() => {
1112
const rows = buildTableRowsData(coverage);
1213
const bodyContent = rows.map(row => renderRow(row, { linkSelector }));
@@ -15,7 +16,15 @@ const TreeView = ({ coverage, linkSelector }) => {
1516
}, [coverage, linkSelector]);
1617

1718

18-
return <div className={classes.root} dangerouslySetInnerHTML={tableHTML} ref={collapseContainer}/>;
19+
return (
20+
<div className={classes.root}>
21+
<div className={classes.controls}>
22+
<LinkButton onClick={onCollapseAll}>Collapse All</LinkButton>
23+
<LinkButton onClick={onExpandAll}>Expand All</LinkButton>
24+
</div>
25+
<div dangerouslySetInnerHTML={tableHTML} ref={collapseContainer}/>
26+
</div>
27+
);
1928
};
2029

2130
export default TreeView;
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
.root {
22
display: flex;
33
flex-direction: column;
4-
}
4+
}
5+
6+
.controls {
7+
display: flex;
8+
flex-direction: row;
9+
margin-bottom: 0.5rem;
10+
11+
& > * + * {
12+
margin-left: 1rem;
13+
}
14+
}

packages/components/TreeView/useCollapse.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BRANCH_NODE } from '@lcov-viewer/core';
2-
import { useEffect, useRef } from 'react';
2+
import { useCallback, useEffect, useRef } from 'react';
33
import { collapseRow, expandRow, hideRow, showRow } from '../render/collapse';
44

55
const findRow = (element) => {
@@ -25,7 +25,8 @@ const useCollapse = () => {
2525

2626
Array.prototype.forEach.call(ref.current.querySelectorAll('tbody tr'), row => {
2727
const path = row.getAttribute('data-node');
28-
state.current[path] = { path, row, collapsed: false, visible: true };
28+
const type = row.getAttribute('data-node-type');
29+
state.current[path] = { path, type, row, collapsed: false, visible: true };
2930
});
3031

3132
const handleClick = (event) => {
@@ -53,8 +54,10 @@ const useCollapse = () => {
5354
affectedChildrenPaths.forEach(path => {
5455
if (rowState.collapsed) {
5556
showRow(state.current[path].row);
57+
state.current[path].visible = true;
5658
} else {
5759
hideRow(state.current[path].row);
60+
state.current[path].visible = false;
5861
}
5962
});
6063

@@ -69,7 +72,38 @@ const useCollapse = () => {
6972
};
7073
}, []);
7174

72-
return ref;
75+
const onCollapseAll = useCallback(() => {
76+
Object.values(state.current).forEach(rowState => {
77+
if (rowState.type === BRANCH_NODE) {
78+
if (!rowState.collapsed) {
79+
collapseRow(rowState.row);
80+
rowState.collapsed = true;
81+
}
82+
}
83+
84+
if (rowState.path !== '') {
85+
hideRow(rowState.row);
86+
rowState.visible = false;
87+
}
88+
});
89+
90+
}, []);
91+
92+
const onExpandAll = useCallback(() => {
93+
Object.values(state.current).forEach(rowState => {
94+
if (rowState.collapsed) {
95+
expandRow(rowState.row);
96+
rowState.collapsed = false;
97+
}
98+
99+
if (!rowState.visible) {
100+
showRow(rowState.row);
101+
rowState.visible = true;
102+
}
103+
});
104+
}, []);
105+
106+
return [ref, onCollapseAll, onExpandAll];
73107
};
74108

75109
export default useCollapse;

packages/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { default as TreeView } from './TreeView/TreeView';
22
export { default as Footer } from './Footer/Footer';
33
export { default as CoverageIndicator } from './CoverageIndicator/CoverageIndicator';
44
export { default as Summary } from './Summary/Summary';
5+
export { default as LinkButton } from './LinkButton/LinkButton';

0 commit comments

Comments
 (0)