mirror of
https://github.com/brianlovin/security-checklist.git
synced 2026-03-11 08:55:31 +00:00
Complete redo of display toggle for App expanded content
This commit is contained in:
parent
968cc1b51a
commit
0453b87160
3 changed files with 120 additions and 39 deletions
|
|
@ -1,43 +1,86 @@
|
|||
// @flow
|
||||
// $FlowIssue
|
||||
import React, { useState } from 'react';
|
||||
import { AppsContainer, SectionHeading, ExpandContainer } from './style';
|
||||
import React from 'react';
|
||||
import { AppsContainer, SectionHeading, ExpandContainer, ExpandContent } from './style';
|
||||
import { Button } from '../Button';
|
||||
import type { ChecklistResource } from '../../types';
|
||||
import { AppRow } from './App';
|
||||
|
||||
type Props = {
|
||||
resource: ChecklistResource,
|
||||
handleAppsExpand: Function,
|
||||
};
|
||||
|
||||
export const Apps = ({ resource }: Props) => {
|
||||
const [overflowExpanded, setOverflowExpanded] = useState(false);
|
||||
type State = {
|
||||
overflowExpanded: boolean,
|
||||
contentHeight: number,
|
||||
};
|
||||
|
||||
if (!resource.apps) return null;
|
||||
export class Apps extends React.Component<Props, State> {
|
||||
state = { overflowExpanded: false, contentHeight: 2000, };
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
if (!this.props.resource.apps) return null;
|
||||
|
||||
this.expandContentContainer = React.createRef();
|
||||
|
||||
let appList = resource.apps;
|
||||
let overflowAppList;
|
||||
if (appList.length > 3) {
|
||||
overflowAppList = appList.slice(3, appList.length);
|
||||
appList = appList.slice(0, 3);
|
||||
}
|
||||
|
||||
return (
|
||||
<AppsContainer overflowExpanded={overflowExpanded}>
|
||||
<SectionHeading>Apps</SectionHeading>
|
||||
{appList.map(app => (
|
||||
<AppRow key={app.name} app={app} />
|
||||
))}
|
||||
handleExpand = () => {
|
||||
let expandContentHeight = this.expandContentContainer.current.scrollHeight;
|
||||
|
||||
{overflowAppList && !overflowExpanded && (
|
||||
<ExpandContainer onClick={() => setOverflowExpanded(true)}>
|
||||
<Button>Show more choices</Button>
|
||||
</ExpandContainer>
|
||||
)}
|
||||
this.setState({
|
||||
contentHeight: expandContentHeight,
|
||||
overflowExpanded: !this.state.overflowExpanded,
|
||||
})
|
||||
|
||||
this.props.handleAppsExpand(this.state.overflowExpanded ? -expandContentHeight : expandContentHeight);
|
||||
}
|
||||
|
||||
render() {
|
||||
let appList = this.props.resource.apps;
|
||||
let overflowAppList;
|
||||
if (appList.length > 3) {
|
||||
overflowAppList = appList.slice(3, appList.length);
|
||||
appList = appList.slice(0, 3);
|
||||
}
|
||||
|
||||
const { overflowExpanded, contentHeight } = this.state;
|
||||
const { resource } = this.props;
|
||||
|
||||
return (
|
||||
<AppsContainer overflowExpanded={overflowExpanded}>
|
||||
<SectionHeading>Apps</SectionHeading>
|
||||
{appList.map(app => (
|
||||
<AppRow key={app.name} app={app} />
|
||||
))}
|
||||
|
||||
{overflowAppList && (
|
||||
<React.Fragment>
|
||||
<ExpandContent
|
||||
id={`apps_${resource.id}`}
|
||||
role="region"
|
||||
tabindex="-1"
|
||||
ref={this.expandContentContainer}
|
||||
style={{ '--maxHeight': `${contentHeight}px` }}
|
||||
aria-hidden={!overflowExpanded}
|
||||
>
|
||||
{overflowAppList.map(app => <AppRow key={app.name} app={app} />)}
|
||||
</ExpandContent>
|
||||
|
||||
<ExpandContainer
|
||||
onClick={this.handleExpand}
|
||||
role="button"
|
||||
aria-expanded={overflowExpanded}
|
||||
aria-controls={`apps_${resource.id}`}
|
||||
>
|
||||
<Button>Show {overflowExpanded ? "less" : "more"} choices</Button>
|
||||
</ExpandContainer>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</AppsContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{overflowAppList &&
|
||||
overflowExpanded &&
|
||||
overflowAppList.map(app => <AppRow key={app.name} app={app} />)}
|
||||
</AppsContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -108,19 +108,36 @@ class ChecklistItem extends React.Component<Props, State> {
|
|||
handleCollapse={this.uncollapse}
|
||||
/>
|
||||
|
||||
{!isCollapsed && resource.apps && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Apps resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Content
|
||||
aria-hidden={isCollapsed}
|
||||
id={`content_${resource.id}`}
|
||||
role="region"
|
||||
tabindex="-1"
|
||||
ref={this.contentContainer}
|
||||
style={{ '--maxHeight': `${contentHeight}px` }}
|
||||
>
|
||||
|
||||
<Description source={resource.description} />
|
||||
|
||||
{resource.apps && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Apps
|
||||
resource={resource}
|
||||
handleAppsExpand={this.handleAppsExpand}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{resource.resources && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Resources resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
</Content>
|
||||
|
||||
{!isCollapsed && resource.resources && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Resources resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
</ResourceContent>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -503,3 +503,24 @@ export const ExpandContainer = styled.div`
|
|||
width: calc(100% + 40px);
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
export const ExpandContent = styled.div`
|
||||
transition:
|
||||
max-height ${theme.animations.default},
|
||||
opacity ${theme.animations.default},
|
||||
visibility ${theme.animations.default};
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
max-height: unset;
|
||||
max-height: var(--maxHeight);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
`
|
||||
Loading…
Reference in a new issue