chore: refactor, separate active and expanded state for menu items

This commit is contained in:
Roman Hotsiy 2018-07-31 15:53:52 +03:00
parent 5ebab5f942
commit a4f79bf8c2
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
6 changed files with 55 additions and 25 deletions

View File

@ -22,20 +22,15 @@ export class MenuItem extends React.Component<MenuItemProps> {
}; };
componentDidMount() { componentDidMount() {
const item = this.props.item; this.scrollIntoViewIfActive();
if (item.type !== 'group' && item.active) {
this.scrollIntoView();
}
} }
componentDidUpdate() { componentDidUpdate() {
if (this.props.item.active) { this.scrollIntoViewIfActive();
this.scrollIntoView();
}
} }
scrollIntoView() { scrollIntoViewIfActive() {
if (this.ref) { if (this.props.item.active && this.ref) {
this.ref.scrollIntoViewIfNeeded(); this.ref.scrollIntoViewIfNeeded();
} }
} }
@ -56,14 +51,14 @@ export class MenuItem extends React.Component<MenuItemProps> {
{item.type === 'operation' ? ( {item.type === 'operation' ? (
<OperationMenuItemContent {...this.props} item={item as OperationModel} /> <OperationMenuItemContent {...this.props} item={item as OperationModel} />
) : ( ) : (
<MenuItemLabel depth={item.depth} active={item.active} type={item.type}> <MenuItemLabel depth={item.depth} active={item.active || item.expanded} type={item.type}>
<MenuItemTitle title={item.name}> <MenuItemTitle title={item.name}>
{item.name} {item.name}
{this.props.children} {this.props.children}
</MenuItemTitle> </MenuItemTitle>
{(item.depth > 0 && {(item.depth > 0 &&
item.items.length > 0 && ( item.items.length > 0 && (
<ShelfIcon float={'right'} direction={item.active ? 'down' : 'right'} /> <ShelfIcon float={'right'} direction={item.expanded ? 'down' : 'right'} />
)) || )) ||
null} null}
</MenuItemLabel> </MenuItemLabel>
@ -71,7 +66,11 @@ export class MenuItem extends React.Component<MenuItemProps> {
{!withoutChildren && {!withoutChildren &&
item.items && item.items &&
item.items.length > 0 && ( item.items.length > 0 && (
<MenuItems active={item.active} items={item.items} onActivate={this.props.onActivate} /> <MenuItems
expanded={item.expanded}
items={item.items}
onActivate={this.props.onActivate}
/>
)} )}
</MenuItemLi> </MenuItemLi>
); );

View File

@ -8,7 +8,7 @@ import { MenuItemUl } from './styled.elements';
export interface MenuItemsProps { export interface MenuItemsProps {
items: IMenuItem[]; items: IMenuItem[];
active?: boolean; expanded?: boolean;
onActivate?: (item: IMenuItem) => void; onActivate?: (item: IMenuItem) => void;
style?: React.CSSProperties; style?: React.CSSProperties;
root?: boolean; root?: boolean;
@ -20,12 +20,12 @@ export interface MenuItemsProps {
export class MenuItems extends React.Component<MenuItemsProps> { export class MenuItems extends React.Component<MenuItemsProps> {
render() { render() {
const { items, root, className } = this.props; const { items, root, className } = this.props;
const active = this.props.active == null ? true : this.props.active; const expanded = this.props.expanded == null ? true : this.props.expanded;
return ( return (
<MenuItemUl <MenuItemUl
className={className} className={className}
style={this.props.style} style={this.props.style}
active={active} expanded={expanded}
{...(root ? { role: 'navigation' } : {})} {...(root ? { role: 'navigation' } : {})}
> >
{items.map((item, idx) => ( {items.map((item, idx) => (

View File

@ -75,7 +75,7 @@ function menuItemActiveBg(depth): string {
} }
} }
export const MenuItemUl = withProps<{ active: boolean }>(styled.ul)` export const MenuItemUl = withProps<{ expanded: boolean }>(styled.ul)`
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -83,7 +83,7 @@ export const MenuItemUl = withProps<{ active: boolean }>(styled.ul)`
font-size: 0.929em; font-size: 0.929em;
} }
${props => (props.active ? '' : 'display: none;')}; ${props => (props.expanded ? '' : 'display: none;')};
`; `;
export const MenuItemLi = withProps<{ depth: number }>(styled.li)` export const MenuItemLi = withProps<{ depth: number }>(styled.li)`

View File

@ -19,6 +19,7 @@ export interface IMenuItem {
description?: string; description?: string;
depth: number; depth: number;
active: boolean; active: boolean;
expanded: boolean;
items: IMenuItem[]; items: IMenuItem[];
parent?: IMenuItem; parent?: IMenuItem;
deprecated?: boolean; deprecated?: boolean;
@ -26,6 +27,9 @@ export interface IMenuItem {
deactivate(): void; deactivate(): void;
activate(): void; activate(): void;
collapse(): void;
expand(): void;
} }
export const SECTION_ATTR = 'data-section-id'; export const SECTION_ATTR = 'data-section-id';
@ -198,10 +202,8 @@ export class MenuStore {
HistoryService.update(item.id, rewriteHistory); HistoryService.update(item.id, rewriteHistory);
} }
while (item !== undefined) { item.activate();
item.activate(); item.expand();
item = item.parent;
}
} }
/** /**
@ -209,8 +211,12 @@ export class MenuStore {
* @param item item to deactivate * @param item item to deactivate
*/ */
deactivate(item: IMenuItem | undefined) { deactivate(item: IMenuItem | undefined) {
if (item === undefined) {
return;
}
item.deactivate();
while (item !== undefined) { while (item !== undefined) {
item.deactivate(); item.collapse();
item = item.parent; item = item.parent;
} }
} }

View File

@ -22,6 +22,7 @@ export class GroupModel implements IMenuItem {
externalDocs?: OpenAPIExternalDocumentation; externalDocs?: OpenAPIExternalDocumentation;
@observable active: boolean = false; @observable active: boolean = false;
@observable expanded: boolean = false;
depth: number; depth: number;
//#endregion //#endregion
@ -41,7 +42,7 @@ export class GroupModel implements IMenuItem {
// groups are active (expanded) by default // groups are active (expanded) by default
if (this.type === 'group') { if (this.type === 'group') {
this.active = true; this.expanded = true;
} }
} }
@ -51,11 +52,24 @@ export class GroupModel implements IMenuItem {
} }
@action @action
deactivate() { expand() {
// disallow deactivating groups if (this.parent) {
this.parent.expand();
}
this.expanded = true;
}
@action
collapse() {
// disallow collapsing groups
if (this.type === 'group') { if (this.type === 'group') {
return; return;
} }
this.expanded = false;
}
@action
deactivate() {
this.active = false; this.active = false;
} }
} }

View File

@ -42,6 +42,7 @@ export class OperationModel implements IMenuItem {
@observable ready?: boolean = true; @observable ready?: boolean = true;
@observable active: boolean = false; @observable active: boolean = false;
@observable expanded: boolean = false;
//#endregion //#endregion
pointer: string; pointer: string;
@ -105,6 +106,16 @@ export class OperationModel implements IMenuItem {
this.active = false; this.active = false;
} }
expand() {
if (this.parent) {
this.parent.expand();
}
}
collapse() {
/* do nothing */
}
@memoize @memoize
get requestBody() { get requestBody() {
return ( return (