aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/ContextMenu.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/ContextMenu.tsx')
-rw-r--r--src/client/views/ContextMenu.tsx134
1 files changed, 38 insertions, 96 deletions
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index f5654446d..fca6a7203 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -5,20 +5,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { DivHeight, DivWidth, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
+import { DivHeight, DivWidth } from '../../ClientUtils';
import { SnappingManager } from '../util/SnappingManager';
import './ContextMenu.scss';
-import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem';
+import { ContextMenuItem, ContextMenuProps } from './ContextMenuItem';
import { ObservableReactComponent } from './ObservableReactComponent';
-import { ColorResult, SketchPicker } from 'react-color';
-import { DocumentView } from './nodes/DocumentView';
-import { Doc } from '../../fields/Doc';
-import { undoable } from '../util/UndoManager';
-import { NumCast, StrCast } from '../../fields/Types';
-import { emptyFunction } from '../../Utils';
@observer
-export class ContextMenu extends ObservableReactComponent<{}> {
+export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean }> {
// eslint-disable-next-line no-use-before-define
static Instance: ContextMenu;
@@ -45,11 +39,7 @@ export class ContextMenu extends ObservableReactComponent<{}> {
@observable _mouseY: number = -1;
@observable _shouldDisplay: boolean = false;
- @observable _displayBorderMenu: boolean = false;
- @observable _selectorWidth: number = 0;
- @observable _widthMinMax: {min: string, max: string} = {min: '1', max: '100'};
-
- constructor(props: any) {
+ constructor(props: object) {
super(props);
makeObservable(this);
ContextMenu.Instance = this;
@@ -126,10 +116,6 @@ export class ContextMenu extends ObservableReactComponent<{}> {
this._defaultItem = item;
}
- @action setColorPickerDisplay = (display: boolean) => {
- this._displayBorderMenu = display;
- }
-
static readonly buffer = 20;
get pageX() {
return this._pageX + this._width > window.innerWidth - ContextMenu.buffer ? window.innerWidth - ContextMenu.buffer - this._width : Math.max(0, this._pageX);
@@ -162,24 +148,24 @@ export class ContextMenu extends ObservableReactComponent<{}> {
return wasOpen;
};
- @computed get filteredItems(): (OriginalMenuProps | string[])[] {
+ @computed get filteredItems(): (ContextMenuProps | string[])[] {
const searchString = this._searchString.toLowerCase().split(' ');
const matches = (descriptions: string[]) => searchString.every(s => descriptions.some(desc => desc.toLowerCase().includes(s)));
- const flattenItems = (items: ContextMenuProps[], groupFunc: (groupName: any) => string[]) => {
- let eles: (OriginalMenuProps | string[])[] = [];
+ const flattenItems = (items: ContextMenuProps[], groupFunc: (groupName: string) => string[]) => {
+ let eles: (ContextMenuProps | string[])[] = [];
- const leaves: OriginalMenuProps[] = [];
+ const leaves: ContextMenuProps[] = [];
items.forEach(item => {
const { description } = item;
const path = groupFunc(description);
- if ('subitems' in item) {
+ if (item.subitems) {
const children = flattenItems(item.subitems, name => [...groupFunc(description), name]);
if (children.length || matches(path)) {
eles.push(path);
eles = eles.concat(children);
}
} else if (matches(path)) {
- leaves.push(item);
+ leaves.push(item as ContextMenuProps);
}
});
@@ -190,13 +176,13 @@ export class ContextMenu extends ObservableReactComponent<{}> {
return flattenItems(this._items.slice(), name => [name]);
}
- @computed get flatItems(): OriginalMenuProps[] {
- return this.filteredItems.filter(item => !Array.isArray(item)) as OriginalMenuProps[];
+ @computed get flatItems(): ContextMenuProps[] {
+ return this.filteredItems.filter(item => !Array.isArray(item)) as ContextMenuProps[];
}
@computed get menuItems() {
if (!this._searchString) {
- return this._items.map((item, ind) => <ContextMenuItem key={item.description + ind} {...item} noexpand={this.itemsNeedSearch ? true : (item as any).noexpand} closeMenu={this.closeMenu} />);
+ return this._items.map((item, ind) => <ContextMenuItem key={item.description + ind} {...item} noexpand={this.itemsNeedSearch ? true : item.noexpand} closeMenu={this.closeMenu} />);
}
return this.filteredItems.map((value, index) =>
Array.isArray(value) ? (
@@ -215,86 +201,41 @@ export class ContextMenu extends ObservableReactComponent<{}> {
}
@computed get itemsNeedSearch() {
- return this._showSearch ? 1 : this._items.reduce((p, mi) => p + ((mi as any).noexpand ? 1 : (mi as any).subitems?.length || 1), 0) > 15;
+ return this._showSearch ? 1 : this._items.reduce((p, mi) => p + (mi.noexpand ? 1 : mi.subitems?.length || 1), 0) > 15;
}
_searchRef = React.createRef<HTMLInputElement>(); // bcz: we shouldn't need this, since we set autoFocus on the <input> tag, but for some reason we do...
- get colorPicker() {
- const doc = DocumentView.Selected().lastElement().Document;
-
- return (
- <div className='contextMenu-borderMenu' style={{position: 'absolute', left: this.pageX,
- ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }),}}>
- <div className='top-bar'>
- <button className='close-menu' onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- clickEv.preventDefault();
- this.setColorPickerDisplay(false);
- }, 'close border menu'))}>
- <FontAwesomeIcon icon='minus'/>
- </button>
- </div>
- <SketchPicker
- onChange={undoable(
- action((col: ColorResult) => doc.borderColor = col.hex),
- 'set stroke color property'
- )}
- presetColors={[]}
- color={StrCast(doc.borderColor)}
- />
- <div className='bottom-box'>
- <input className='max-min-selector' defaultValue={this._widthMinMax.min} onChange={e => this._widthMinMax.max = e.target.value}/>
- <input className='width-selector' type="range" min={this._widthMinMax.min} max={this._widthMinMax.max} value={this._selectorWidth} id="myRange" onChange={e => runInAction(() => {doc.borderWidth = e.target.value; this._selectorWidth = Number(e.target.value)})}/>
- <input className='max-min-selector' defaultValue={this._widthMinMax.max} onChange={e => this._widthMinMax.max = e.target.value}/>
- </div>
- </div>
- );
- }
-
render() {
this.itemsNeedSearch && setTimeout(() => this._searchRef.current?.focus());
return (
- <div>
- {this._displayBorderMenu ? this.colorPicker : null}
- <div
- className="contextMenu-cont"
- ref={action((r: any) => {
+ <div
+ className="contextMenu-cont"
+ ref={r =>
+ runInAction(() => {
if (r) {
this._width = DivWidth(r);
this._height = DivHeight(r);
}
this._searchRef.current?.focus();
- })}
- style={{
- display: this._display ? '' : 'none',
- left: this.pageX,
- ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }),
- background: SnappingManager.userBackgroundColor,
- color: SnappingManager.userColor,
- }}>
- {!this.itemsNeedSearch ? null : (
- <span className="search-icon">
- <span className="icon-background">
- <FontAwesomeIcon icon="search" size="lg" />
- </span>
- <input
- ref={this._searchRef}
- style={{ color: 'black' }}
- className="contextMenu-item contextMenu-description search"
- type="text"
- placeholder="Filter Menu..."
- value={this._searchString}
- onKeyDown={this.onKeyDown}
- onChange={this.onChange}
- // eslint-disable-next-line jsx-a11y/no-autofocus
- autoFocus
- />
+ })
+ }
+ style={{
+ display: this._display ? '' : 'none',
+ left: this.pageX,
+ ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }),
+ background: SnappingManager.userBackgroundColor,
+ color: SnappingManager.userColor,
+ }}>
+ {!this.itemsNeedSearch ? null : (
+ <span className="contextMenu-search">
+ <span className="contextMenu-searchIcon">
+ <FontAwesomeIcon icon="search" size="lg" />
</span>
- )}
- {this.menuItems}
- </div>
+ <input ref={this._searchRef} style={{ color: 'black' }} className="contextMenu-searchInput" type="text" placeholder="Filter Menu..." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus />
+ </span>
+ )}
+ {this.menuItems}
</div>
);
}
@@ -313,12 +254,13 @@ export class ContextMenu extends ObservableReactComponent<{}> {
e.preventDefault();
} else if (e.key === 'Enter' || e.key === 'Tab') {
const item = this.flatItems[this._selectedIndex];
- if (item) {
+ if (item.event) {
item.event({ x: this.pageX, y: this.pageY });
} else {
// if (this._searchString.startsWith(this._defaultPrefix)) {
this._defaultItem?.(this._searchString.substring(this._defaultPrefix.length));
}
+ this.closeMenu();
e.preventDefault();
e.stopPropagation();
}
@@ -335,4 +277,4 @@ export class ContextMenu extends ObservableReactComponent<{}> {
this._selectedIndex = Math.min(this.flatItems.length - 1, this._selectedIndex);
}
};
-}
+} \ No newline at end of file