Initial Move from Azure DevOps to GitHub

This commit is contained in:
Steve Faulkner
2020-05-25 21:30:55 -05:00
commit 36581fb6d9
986 changed files with 195242 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
import React from "react";
import { shallow } from "enzyme";
import { TreeComponent, TreeNode, TreeNodeComponent } from "./TreeComponent";
const buildChildren = (): TreeNode[] => {
const grandChild11: TreeNode = {
label: "ZgrandChild11"
};
const grandChild12: TreeNode = {
label: "AgrandChild12"
};
const child1: TreeNode = {
label: "Bchild1",
children: [grandChild11, grandChild12]
};
const child2: TreeNode = {
label: "2child2"
};
return [child1, child2];
};
const buildChildren2 = (): TreeNode[] => {
const grandChild11: TreeNode = {
label: "ZgrandChild11"
};
const grandChild12: TreeNode = {
label: "AgrandChild12"
};
const child1: TreeNode = {
label: "aChild"
};
const child2: TreeNode = {
label: "bchild",
children: [grandChild11, grandChild12]
};
const child3: TreeNode = {
label: "cchild"
};
const child4: TreeNode = {
label: "dchild",
children: [grandChild11, grandChild12]
};
return [child1, child2, child3, child4];
};
describe("TreeComponent", () => {
it("renders a simple tree", () => {
const root = {
label: "root",
children: buildChildren()
};
const props = {
rootNode: root,
className: "tree"
};
const wrapper = shallow(<TreeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
});
describe("TreeNodeComponent", () => {
it("renders a simple node (sorted children, expanded)", () => {
const node: TreeNode = {
label: "label",
id: "id",
children: buildChildren(),
contextMenu: [
{
label: "menuLabel",
onClick: undefined,
iconSrc: undefined,
isDisabled: true
}
],
iconSrc: undefined,
isExpanded: true,
className: "nodeClassname",
isAlphaSorted: true,
data: undefined,
timestamp: 10,
isSelected: undefined,
onClick: undefined,
onExpanded: undefined,
onCollapsed: undefined
};
const props = {
node,
generation: 12,
paddingLeft: 23
};
const wrapper = shallow(<TreeNodeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders unsorted children by default", () => {
const node: TreeNode = {
label: "label",
children: buildChildren(),
isExpanded: true
};
const props = {
node,
generation: 2,
paddingLeft: 9
};
const wrapper = shallow(<TreeNodeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("does not render children by default", () => {
const node: TreeNode = {
label: "label",
children: buildChildren(),
isAlphaSorted: false
};
const props = {
node,
generation: 2,
paddingLeft: 9
};
const wrapper = shallow(<TreeNodeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders sorted children, expanded, leaves and parents separated", () => {
const node: TreeNode = {
label: "label",
id: "id",
children: buildChildren2(),
contextMenu: [],
iconSrc: undefined,
isExpanded: true,
className: "nodeClassname",
isAlphaSorted: true,
isLeavesParentsSeparate: true,
data: undefined,
timestamp: 10,
isSelected: undefined,
onClick: undefined,
onExpanded: undefined,
onCollapsed: undefined
};
const props = {
node,
generation: 12,
paddingLeft: 23
};
const wrapper = shallow(<TreeNodeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,323 @@
/**
* Tree component:
* - collapsible
* - icons prefix
* - context menu
*/
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as Constants from "../../../Common/Constants";
import AnimateHeight from "react-animate-height";
import { IconButton } from "office-ui-fabric-react/lib/Button";
import {
DirectionalHint,
IContextualMenuItemProps,
IContextualMenuProps
} from "office-ui-fabric-react/lib/ContextualMenu";
import TriangleDownIcon from "../../../../images/Triangle-down.svg";
import TriangleRightIcon from "../../../../images/Triangle-right.svg";
export interface TreeNodeMenuItem {
label: string;
onClick: () => void;
iconSrc?: string;
isDisabled?: boolean;
}
export interface TreeNode {
label: string;
id?: string;
children?: TreeNode[];
contextMenu?: TreeNodeMenuItem[];
iconSrc?: string;
isExpanded?: boolean;
className?: string;
isAlphaSorted?: boolean;
data?: any; // Piece of data corresponding to this node
timestamp?: number;
isLeavesParentsSeparate?: boolean; // Display parents together first, then leaves
isSelected?: () => boolean;
onClick?: (isExpanded: boolean) => void; // Only if a leaf, other click will expand/collapse
onExpanded?: () => void;
onCollapsed?: () => void;
onContextMenuOpen?: () => void;
}
export interface TreeComponentProps {
rootNode: TreeNode;
style?: any;
className?: string;
}
export class TreeComponent extends React.Component<TreeComponentProps> {
public render(): JSX.Element {
return (
<div style={this.props.style} className={`treeComponent ${this.props.className}`}>
<TreeNodeComponent paddingLeft={0} node={this.props.rootNode} generation={0} />
</div>
);
}
}
/* Tree node is a react component */
interface TreeNodeComponentProps {
node: TreeNode;
generation: number;
paddingLeft: number;
}
interface TreeNodeComponentState {
isExpanded: boolean;
isMenuShowing: boolean;
}
export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, TreeNodeComponentState> {
private static readonly paddingPerGenerationPx = 16;
private static readonly iconOffset = 22;
private static readonly transitionDurationMS = 200;
private static readonly callbackDelayMS = 100; // avoid calling at the same time as transition to make it smoother
private contextMenuRef = React.createRef<HTMLDivElement>();
private isExpanded: boolean;
constructor(props: TreeNodeComponentProps) {
super(props);
this.isExpanded = props.node.isExpanded;
this.state = {
isExpanded: props.node.isExpanded,
isMenuShowing: false
};
}
componentDidUpdate(prevProps: TreeNodeComponentProps, prevState: TreeNodeComponentState) {
// Only call when expand has actually changed
if (this.state.isExpanded !== prevState.isExpanded) {
if (this.state.isExpanded) {
this.props.node.onExpanded && setTimeout(this.props.node.onExpanded, TreeNodeComponent.callbackDelayMS);
} else {
this.props.node.onCollapsed && setTimeout(this.props.node.onCollapsed, TreeNodeComponent.callbackDelayMS);
}
}
if (this.props.node.isExpanded !== this.isExpanded) {
this.isExpanded = this.props.node.isExpanded;
this.setState({
isExpanded: this.props.node.isExpanded
});
}
}
public render(): JSX.Element {
return this.renderNode(this.props.node, this.props.generation);
}
private static getSortedChildren(treeNode: TreeNode): TreeNode[] {
if (!treeNode || !treeNode.children) {
return undefined;
}
const compareFct = (a: TreeNode, b: TreeNode) => a.label.localeCompare(b.label);
let unsortedChildren;
if (treeNode.isLeavesParentsSeparate) {
// Separate parents and leave
const parents: TreeNode[] = treeNode.children.filter(node => node.children);
const leaves: TreeNode[] = treeNode.children.filter(node => !node.children);
if (treeNode.isAlphaSorted) {
parents.sort(compareFct);
leaves.sort(compareFct);
}
unsortedChildren = parents.concat(leaves);
} else {
unsortedChildren = treeNode.isAlphaSorted ? treeNode.children.sort(compareFct) : treeNode.children;
}
return unsortedChildren;
}
private static isNodeHeaderBlank(node: TreeNode): boolean {
return (node.label === undefined || node.label === null) && !node.contextMenu;
}
private renderNode(node: TreeNode, generation: number): JSX.Element {
let paddingLeft = generation * TreeNodeComponent.paddingPerGenerationPx;
let additionalOffsetPx = 15;
if (node.children) {
const childrenWithSubChildren = node.children.filter((child: TreeNode) => !!child.children);
if (childrenWithSubChildren.length > 0) {
additionalOffsetPx = TreeNodeComponent.iconOffset;
}
}
// Don't show as selected if any of the children is selected
const showSelected =
this.props.node.isSelected &&
this.props.node.isSelected() &&
!TreeNodeComponent.isAnyDescendantSelected(this.props.node);
const headerStyle: React.CSSProperties = { paddingLeft: this.props.paddingLeft };
if (TreeNodeComponent.isNodeHeaderBlank(node)) {
headerStyle.height = 0;
headerStyle.padding = 0;
}
return (
<div
className={`${this.props.node.className || ""} main${generation} nodeItem ${showSelected ? "selected" : ""}`}
onClick={(event: React.MouseEvent<HTMLDivElement>) => this.onNodeClick(event, node)}
onKeyPress={(event: React.KeyboardEvent<HTMLDivElement>) => this.onNodeKeyPress(event, node)}
>
<div
className={`treeNodeHeader ${this.state.isMenuShowing ? "showingMenu" : ""}`}
style={headerStyle}
tabIndex={node.children ? -1 : 0}
data-test={node.label}
>
{this.renderCollapseExpandIcon(node)}
{node.iconSrc && <img className="nodeIcon" src={node.iconSrc} alt="" />}
{node.label && (
<span className="nodeLabel" title={node.label}>
{node.label}
</span>
)}
{node.contextMenu && this.renderContextMenuButton(node)}
</div>
{node.children && (
<AnimateHeight duration={TreeNodeComponent.transitionDurationMS} height={this.state.isExpanded ? "auto" : 0}>
<div className="nodeChildren" data-test={node.label}>
{TreeNodeComponent.getSortedChildren(node).map((childNode: TreeNode) => (
<TreeNodeComponent
key={`${childNode.label}-${generation + 1}-${childNode.timestamp}`}
node={childNode}
generation={generation + 1}
paddingLeft={paddingLeft + (!childNode.children && !childNode.iconSrc ? additionalOffsetPx : 0)}
/>
))}
</div>
</AnimateHeight>
)}
</div>
);
}
/**
* Recursive: is the node or any descendant selected
* @param node
*/
private static isAnyDescendantSelected(node: TreeNode): boolean {
return (
node.children &&
node.children.reduce(
(previous: boolean, child: TreeNode) =>
previous || (child.isSelected && child.isSelected()) || TreeNodeComponent.isAnyDescendantSelected(child),
false
)
);
}
private static createClickEvent(): MouseEvent {
return new MouseEvent("click", { bubbles: true, view: window, cancelable: true });
}
private onRightClick = (): void => {
this.contextMenuRef.current.firstChild.dispatchEvent(TreeNodeComponent.createClickEvent());
};
private renderContextMenuButton(node: TreeNode): JSX.Element {
const menuItemLabel = "More";
return (
<div ref={this.contextMenuRef} onContextMenu={this.onRightClick} onKeyPress={this.onMoreButtonKeyPress}>
<IconButton
name="More"
className="treeMenuEllipsis"
ariaLabel={menuItemLabel}
menuIconProps={{
iconName: menuItemLabel,
styles: { root: { fontSize: "18px", fontWeight: "bold" } }
}}
menuProps={{
coverTarget: true,
isBeakVisible: false,
directionalHint: DirectionalHint.topAutoEdge,
onMenuOpened: (contextualMenu?: IContextualMenuProps) => {
this.setState({ isMenuShowing: true });
node.onContextMenuOpen && node.onContextMenuOpen();
},
onMenuDismissed: (contextualMenu?: IContextualMenuProps) => this.setState({ isMenuShowing: false }),
contextualMenuItemAs: (props: IContextualMenuItemProps) => (
<div
data-test={`treeComponentMenuItemContainer`}
className="treeComponentMenuItemContainer"
onContextMenu={e => e.target.dispatchEvent(TreeNodeComponent.createClickEvent())}
>
{props.item.onRenderIcon()}
<span className="treeComponentMenuItemLabel">{props.item.text}</span>
</div>
),
items: node.contextMenu.map((menuItem: TreeNodeMenuItem) => ({
key: menuItem.label,
text: menuItem.label,
disabled: menuItem.isDisabled,
onClick: menuItem.onClick,
onRenderIcon: (props: any) => <img src={menuItem.iconSrc} alt="" />
}))
}}
/>
</div>
);
}
private renderCollapseExpandIcon(node: TreeNode): JSX.Element {
if (!node.children || !node.label) {
return <></>;
}
return (
<img
className="expandCollapseIcon"
src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon}
alt={this.state.isExpanded ? "Branch is expanded" : "Branch is collapsed"}
onKeyPress={(event: React.KeyboardEvent<HTMLDivElement>) => this.onCollapseExpandIconKeyPress(event, node)}
tabIndex={0}
role="button"
/>
);
}
private onNodeClick = (event: React.MouseEvent<HTMLDivElement>, node: TreeNode): void => {
event.stopPropagation();
if (node.children) {
const isExpanded = !this.state.isExpanded;
// Prevent collapsing if node header is blank
if (!(TreeNodeComponent.isNodeHeaderBlank(node) && !isExpanded)) {
this.setState({ isExpanded });
}
}
this.props.node.onClick && this.props.node.onClick(this.state.isExpanded);
};
private onNodeKeyPress = (event: React.KeyboardEvent<HTMLDivElement>, node: TreeNode): void => {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
event.stopPropagation();
this.props.node.onClick && this.props.node.onClick(this.state.isExpanded);
}
};
private onCollapseExpandIconKeyPress = (event: React.KeyboardEvent<HTMLDivElement>, node: TreeNode): void => {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
event.stopPropagation();
if (node.children) {
this.setState({ isExpanded: !this.state.isExpanded });
}
}
};
private onMoreButtonKeyPress = (event: React.KeyboardEvent<HTMLDivElement>): void => {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
event.stopPropagation();
}
};
}

View File

@@ -0,0 +1,497 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TreeComponent renders a simple tree 1`] = `
<div
className="treeComponent tree"
>
<TreeNodeComponent
generation={0}
node={
Object {
"children": Array [
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "Bchild1",
},
Object {
"label": "2child2",
},
],
"label": "root",
}
}
paddingLeft={0}
/>
</div>
`;
exports[`TreeNodeComponent does not render children by default 1`] = `
<div
className=" main2 nodeItem "
onClick={[Function]}
onKeyPress={[Function]}
>
<div
className="treeNodeHeader "
data-test="label"
style={
Object {
"paddingLeft": 9,
}
}
tabIndex={-1}
>
<img
alt="Branch is collapsed"
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src=""
tabIndex={0}
/>
<span
className="nodeLabel"
title="label"
>
label
</span>
</div>
<AnimateHeight
animateOpacity={false}
animationStateClasses={
Object {
"animating": "rah-animating",
"animatingDown": "rah-animating--down",
"animatingToHeightAuto": "rah-animating--to-height-auto",
"animatingToHeightSpecific": "rah-animating--to-height-specific",
"animatingToHeightZero": "rah-animating--to-height-zero",
"animatingUp": "rah-animating--up",
"static": "rah-static",
"staticHeightAuto": "rah-static--height-auto",
"staticHeightSpecific": "rah-static--height-specific",
"staticHeightZero": "rah-static--height-zero",
}
}
applyInlineTransitions={true}
delay={0}
duration={200}
easing="ease"
height={0}
style={Object {}}
>
<div
className="nodeChildren"
data-test="label"
>
<TreeNodeComponent
generation={3}
key="Bchild1-3-undefined"
node={
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "Bchild1",
}
}
paddingLeft={32}
/>
<TreeNodeComponent
generation={3}
key="2child2-3-undefined"
node={
Object {
"label": "2child2",
}
}
paddingLeft={54}
/>
</div>
</AnimateHeight>
</div>
`;
exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`] = `
<div
className="nodeClassname main12 nodeItem "
onClick={[Function]}
onKeyPress={[Function]}
>
<div
className="treeNodeHeader "
data-test="label"
style={
Object {
"paddingLeft": 23,
}
}
tabIndex={-1}
>
<img
alt="Branch is expanded"
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src=""
tabIndex={0}
/>
<span
className="nodeLabel"
title="label"
>
label
</span>
<div
onContextMenu={[Function]}
onKeyPress={[Function]}
>
<CustomizedIconButton
ariaLabel="More"
className="treeMenuEllipsis"
menuIconProps={
Object {
"iconName": "More",
"styles": Object {
"root": Object {
"fontSize": "18px",
"fontWeight": "bold",
},
},
}
}
menuProps={
Object {
"contextualMenuItemAs": [Function],
"coverTarget": true,
"directionalHint": 3,
"isBeakVisible": false,
"items": Array [
Object {
"disabled": true,
"key": "menuLabel",
"onClick": undefined,
"onRenderIcon": [Function],
"text": "menuLabel",
},
],
"onMenuDismissed": [Function],
"onMenuOpened": [Function],
}
}
name="More"
/>
</div>
</div>
<AnimateHeight
animateOpacity={false}
animationStateClasses={
Object {
"animating": "rah-animating",
"animatingDown": "rah-animating--down",
"animatingToHeightAuto": "rah-animating--to-height-auto",
"animatingToHeightSpecific": "rah-animating--to-height-specific",
"animatingToHeightZero": "rah-animating--to-height-zero",
"animatingUp": "rah-animating--up",
"static": "rah-static",
"staticHeightAuto": "rah-static--height-auto",
"staticHeightSpecific": "rah-static--height-specific",
"staticHeightZero": "rah-static--height-zero",
}
}
applyInlineTransitions={true}
delay={0}
duration={200}
easing="ease"
height="auto"
style={Object {}}
>
<div
className="nodeChildren"
data-test="label"
>
<TreeNodeComponent
generation={13}
key="2child2-13-undefined"
node={
Object {
"label": "2child2",
}
}
paddingLeft={214}
/>
<TreeNodeComponent
generation={13}
key="Bchild1-13-undefined"
node={
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "Bchild1",
}
}
paddingLeft={192}
/>
</div>
</AnimateHeight>
</div>
`;
exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents separated 1`] = `
<div
className="nodeClassname main12 nodeItem "
onClick={[Function]}
onKeyPress={[Function]}
>
<div
className="treeNodeHeader "
data-test="label"
style={
Object {
"paddingLeft": 23,
}
}
tabIndex={-1}
>
<img
alt="Branch is expanded"
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src=""
tabIndex={0}
/>
<span
className="nodeLabel"
title="label"
>
label
</span>
<div
onContextMenu={[Function]}
onKeyPress={[Function]}
>
<CustomizedIconButton
ariaLabel="More"
className="treeMenuEllipsis"
menuIconProps={
Object {
"iconName": "More",
"styles": Object {
"root": Object {
"fontSize": "18px",
"fontWeight": "bold",
},
},
}
}
menuProps={
Object {
"contextualMenuItemAs": [Function],
"coverTarget": true,
"directionalHint": 3,
"isBeakVisible": false,
"items": Array [],
"onMenuDismissed": [Function],
"onMenuOpened": [Function],
}
}
name="More"
/>
</div>
</div>
<AnimateHeight
animateOpacity={false}
animationStateClasses={
Object {
"animating": "rah-animating",
"animatingDown": "rah-animating--down",
"animatingToHeightAuto": "rah-animating--to-height-auto",
"animatingToHeightSpecific": "rah-animating--to-height-specific",
"animatingToHeightZero": "rah-animating--to-height-zero",
"animatingUp": "rah-animating--up",
"static": "rah-static",
"staticHeightAuto": "rah-static--height-auto",
"staticHeightSpecific": "rah-static--height-specific",
"staticHeightZero": "rah-static--height-zero",
}
}
applyInlineTransitions={true}
delay={0}
duration={200}
easing="ease"
height="auto"
style={Object {}}
>
<div
className="nodeChildren"
data-test="label"
>
<TreeNodeComponent
generation={13}
key="bchild-13-undefined"
node={
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "bchild",
}
}
paddingLeft={192}
/>
<TreeNodeComponent
generation={13}
key="dchild-13-undefined"
node={
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "dchild",
}
}
paddingLeft={192}
/>
<TreeNodeComponent
generation={13}
key="aChild-13-undefined"
node={
Object {
"label": "aChild",
}
}
paddingLeft={214}
/>
<TreeNodeComponent
generation={13}
key="cchild-13-undefined"
node={
Object {
"label": "cchild",
}
}
paddingLeft={214}
/>
</div>
</AnimateHeight>
</div>
`;
exports[`TreeNodeComponent renders unsorted children by default 1`] = `
<div
className=" main2 nodeItem "
onClick={[Function]}
onKeyPress={[Function]}
>
<div
className="treeNodeHeader "
data-test="label"
style={
Object {
"paddingLeft": 9,
}
}
tabIndex={-1}
>
<img
alt="Branch is expanded"
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src=""
tabIndex={0}
/>
<span
className="nodeLabel"
title="label"
>
label
</span>
</div>
<AnimateHeight
animateOpacity={false}
animationStateClasses={
Object {
"animating": "rah-animating",
"animatingDown": "rah-animating--down",
"animatingToHeightAuto": "rah-animating--to-height-auto",
"animatingToHeightSpecific": "rah-animating--to-height-specific",
"animatingToHeightZero": "rah-animating--to-height-zero",
"animatingUp": "rah-animating--up",
"static": "rah-static",
"staticHeightAuto": "rah-static--height-auto",
"staticHeightSpecific": "rah-static--height-specific",
"staticHeightZero": "rah-static--height-zero",
}
}
applyInlineTransitions={true}
delay={0}
duration={200}
easing="ease"
height="auto"
style={Object {}}
>
<div
className="nodeChildren"
data-test="label"
>
<TreeNodeComponent
generation={3}
key="Bchild1-3-undefined"
node={
Object {
"children": Array [
Object {
"label": "ZgrandChild11",
},
Object {
"label": "AgrandChild12",
},
],
"label": "Bchild1",
}
}
paddingLeft={32}
/>
<TreeNodeComponent
generation={3}
key="2child2-3-undefined"
node={
Object {
"label": "2child2",
}
}
paddingLeft={54}
/>
</div>
</AnimateHeight>
</div>
`;

View File

@@ -0,0 +1,80 @@
@import "../../../../less/Common/Constants";
.treeComponent {
.nodeItem {
&:focus {
outline: 1px dashed @AccentMedium;
}
.treeNodeHeader {
padding: @SmallSpace 2px;
cursor: pointer;
display: flex;
&:hover {
background-color: @AccentLight;
.treeMenuEllipsis {
opacity: 1;
}
}
&.showingMenu {
background-color: #EEE;
}
.treeMenuEllipsis {
max-height: 17px;
padding-right: 6px;
position: relative;
left: 0px;
float: right;
padding-left: 6px;
opacity: 0;
&:focus {
opacity: 1;
}
}
.nodeIcon {
width: 16px;
height: 16px;
vertical-align: text-top;
margin-right: @SmallSpace;
}
.expandCollapseIcon {
width: 10px;
height: 10px;
vertical-align: middle;
margin: 2px @DefaultSpace 2px @SmallSpace;
}
.nodeLabel {
line-height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
flex-grow: 1;
}
}
.selected {
& > .treeNodeHeader {
background-color: @AccentExtra;
}
}
}
}
.treeComponentMenuItemContainer {
font-size: @mediumFontSize;
.treeComponentMenuItemLabel {
margin-left: @SmallSpace;
}
img {
vertical-align: text-bottom;
}
}