aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-06-19 16:21:03 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-06-19 16:21:03 -0400
commit565b27cca8953a60067de367cae4c0a99beb3cab (patch)
tree2b2a03634436a5f6c420660d01961e3750fb7e4b /src
parent5b6f13d64e9e38b94df0ae61ffedcb0b34290045 (diff)
started adding selection to context menu
Diffstat (limited to 'src')
-rw-r--r--src/client/views/ContextMenu.scss4
-rw-r--r--src/client/views/ContextMenu.tsx58
-rw-r--r--src/client/views/ContextMenuItem.tsx6
3 files changed, 45 insertions, 23 deletions
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index a1a2b06f1..254163b53 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -53,6 +53,10 @@
font-size: 20px;
}
+.contextMenu-itemSelected {
+ background: rgb(136, 136, 136)
+}
+
.contextMenu-group {
// width: 11vw; //10vw
height: 30px; //2vh
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 1133f70a1..33de57cfa 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,5 +1,5 @@
import React = require("react");
-import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem";
+import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from "./ContextMenuItem";
import { observable, action, computed } from "mobx";
import { observer } from "mobx-react";
import "./ContextMenu.scss";
@@ -21,6 +21,7 @@ export class ContextMenu extends React.Component {
@observable private _searchString: string = "";
// afaik displaymenu can be called before all the items are added to the menu, so can't determine in displayMenu what the height of the menu will be
@observable private _yRelativeToTop: boolean = true;
+ @observable selectedIndex = -1;
private _searchRef = React.createRef<HTMLInputElement>();
@@ -75,49 +76,63 @@ export class ContextMenu extends React.Component {
this._display = false;
}
- @computed get filteredItems() {
+ @computed get filteredItems(): (OriginalMenuProps | string[])[] {
const searchString = this._searchString.toLowerCase().split(" ");
const matches = (descriptions: string[]): boolean => {
- return searchString.every(s => descriptions.some(desc => desc.includes(s)));
+ return searchString.every(s => descriptions.some(desc => desc.toLowerCase().includes(s)));
};
- const createGroupHeader = (contents: any) => {
- return (
- <div className="contextMenu-group">
- <div className="contextMenu-description">{contents}</div>
- </div>
- );
- };
- const createItem = (item: ContextMenuProps) => <ContextMenuItem {...item} key={item.description} closeMenu={this.closeMenu} />;
- const flattenItems = (items: ContextMenuProps[], groupFunc: (contents: any) => JSX.Element, getPath: () => string[]) => {
- let eles: JSX.Element[] = [];
+ const flattenItems = (items: ContextMenuProps[], groupFunc: (groupName: any) => string[]) => {
+ let eles: (OriginalMenuProps | string[])[] = [];
+ const leaves: OriginalMenuProps[] = [];
for (const item of items) {
- const description = item.description.toLowerCase();
- const path = [...getPath(), description];
+ const description = item.description;
+ const path = groupFunc(description);
if ("subitems" in item) {
- const children = flattenItems(item.subitems, contents => groupFunc(<>{item.description} -> {contents}</>), () => path);
+ const children = flattenItems(item.subitems, name => [...groupFunc(description), name]);
if (children.length || matches(path)) {
- eles.push(groupFunc(item.description));
+ eles.push(path);
eles = eles.concat(children);
}
} else {
if (!matches(path)) {
continue;
}
- eles.push(createItem(item));
+ leaves.push(item);
}
}
+ eles = [...leaves, ...eles];
+
return eles;
};
- return flattenItems(this._items, createGroupHeader, () => []);
+ return flattenItems(this._items, name => [name]);
+ }
+
+ @computed get filteredViews() {
+ const createGroupHeader = (contents: any) => {
+ return (
+ <div className="contextMenu-group">
+ <div className="contextMenu-description">{contents}</div>
+ </div>
+ );
+ };
+ const createItem = (item: ContextMenuProps, selected: boolean) => <ContextMenuItem {...item} key={item.description} closeMenu={this.closeMenu} selected={selected} />;
+ let itemIndex = 0;
+ return this.filteredItems.map(value => {
+ if (Array.isArray(value)) {
+ return createGroupHeader(value.join(" -> "));
+ } else {
+ return createItem(value, ++itemIndex === this.selectedIndex);
+ }
+ });
}
@computed get menuItems() {
if (!this._searchString) {
return this._items.map(item => <ContextMenuItem {...item} key={item.description} closeMenu={this.closeMenu} />);
}
- return this.filteredItems;
+ return this.filteredViews;
}
render() {
@@ -143,5 +158,8 @@ export class ContextMenu extends React.Component {
@action
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this._searchString = e.target.value;
+ if (this._searchString && this.selectedIndex === -1) {
+ this.selectedIndex = 0;
+ }
}
} \ No newline at end of file
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 88ebd95bc..ebcac7428 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -24,7 +24,7 @@ export interface SubmenuProps {
export type ContextMenuProps = OriginalMenuProps | SubmenuProps;
@observer
-export class ContextMenuItem extends React.Component<ContextMenuProps> {
+export class ContextMenuItem extends React.Component<ContextMenuProps & { selected?: boolean }> {
@observable private _items: Array<ContextMenuProps> = [];
@observable private overItem = false;
@@ -69,7 +69,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps> {
render() {
if ("event" in this.props) {
return (
- <div className="contextMenu-item" onClick={this.handleEvent}>
+ <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onClick={this.handleEvent}>
{this.props.icon ? (
<span className="icon-background">
<FontAwesomeIcon icon={this.props.icon} size="sm" />
@@ -86,7 +86,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps> {
{this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
</div>;
return (
- <div className="contextMenu-item" onMouseEnter={this.onPointerEnter} onMouseLeave={this.onPointerLeave}>
+ <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onMouseEnter={this.onPointerEnter} onMouseLeave={this.onPointerLeave}>
{this.props.icon ? (
<span className="icon-background">
<FontAwesomeIcon icon={this.props.icon} size="sm" />