mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-21 07:54:32 +01:00
make all menus position static / allow creation custom context menus
This commit is contained in:
parent
415b832d8f
commit
a1e2b80948
11 changed files with 129 additions and 24 deletions
|
|
@ -13,9 +13,9 @@ export class Adjuster extends React.Component {
|
|||
if (!this.el) {
|
||||
return;
|
||||
}
|
||||
let w = this.el.offsetWidth;
|
||||
let h = this.el.offsetHeight;
|
||||
let holder = this.el.parentNode;
|
||||
let w = this.el.clientWidth;
|
||||
let h = this.el.clientHeight;
|
||||
let holder = document.documentElement;
|
||||
|
||||
const fit = (prop, pos, dim, holderDim) => {
|
||||
if (pos !== undefined) {
|
||||
|
|
@ -43,10 +43,10 @@ export class Adjuster extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
fit('left', left, w, holder.offsetWidth);
|
||||
fit('right', right,w, holder.offsetWidth);
|
||||
fit('top', top, h, holder.offsetHeight);
|
||||
fit('bottom', bottom, h, holder.offsetHeight);
|
||||
fit('left', left, w, holder.clientWidth);
|
||||
fit('right', right,w, holder.clientWidth);
|
||||
fit('top', top, h, holder.clientHeight);
|
||||
fit('bottom', bottom, h, holder.clientHeight);
|
||||
this.el.style.visibility = 'visible';
|
||||
};
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ export class Adjuster extends React.Component {
|
|||
return <div ref={el => this.el = el}
|
||||
style={{
|
||||
visibility: 'hidden',
|
||||
position: 'absolute', zIndex,
|
||||
position: 'fixed', zIndex,
|
||||
...style}} {...props}>
|
||||
{children}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ export default class Folder extends React.Component{
|
|||
render() {
|
||||
let {title, closable, className, children} = this.props;
|
||||
return <div className={cx(ls.root, className)}>
|
||||
<Title title={title} onClick={closable ? this.tweakClose : null} isClosed={this.isClosed()}/>
|
||||
<Title onClick={closable ? this.tweakClose : null} isClosed={this.isClosed()}>{title}</Title>
|
||||
{!this.isClosed() && children}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export function Title({title, isClosed, onClick}) {
|
||||
export function Title({children, isClosed, onClick}) {
|
||||
return <div className={ls.title} onClick={onClick}>
|
||||
<span className={ls.handle}><Fa fw icon={isClosed ? 'chevron-right' : 'chevron-down'}/></span>
|
||||
{' '}{title}
|
||||
{' '}{children}
|
||||
</div>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import ls from './Menu.less';
|
||||
import AuxWidget from "./AuxWidget";
|
||||
import cx from 'classnames';
|
||||
import Fa from './Fa';
|
||||
|
||||
export default function Menu({children, x, y, orientationUp, centered, menuId, ...props}) {
|
||||
return <AuxWidget
|
||||
|
|
@ -23,7 +24,7 @@ export function MenuSeparator() {
|
|||
}
|
||||
|
||||
|
||||
export function MenuItem({icon, label, hotKey, style, disabled, onClick, ...props}, {closeAllUpPopups}) {
|
||||
export function MenuItem({icon, label, hotKey, style, disabled, onClick, children, ...props}, {closeAllUpPopups}) {
|
||||
|
||||
if (hotKey) {
|
||||
hotKey = hotKey.replace(/\s/g, '');
|
||||
|
|
@ -43,6 +44,69 @@ export function MenuItem({icon, label, hotKey, style, disabled, onClick, ...prop
|
|||
</div>;
|
||||
}
|
||||
|
||||
export class ContextMenu extends React.Component {
|
||||
|
||||
state = {
|
||||
active: false
|
||||
};
|
||||
|
||||
onClick = e => {
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
active: true,
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
});
|
||||
};
|
||||
|
||||
close = () => {
|
||||
this.setState({active: false})
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.detacher = this.context.onCloseAll.attach(this.close);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detacher();
|
||||
}
|
||||
|
||||
render() {
|
||||
return <span className={ls.contextMenu}>
|
||||
<span onContextMenu={this.onClick}>{this.props.children}</span>
|
||||
<span onClick={this.onClick} className={ls.contextMenuBtn}><Fa fw icon='ellipsis-h'/></span>
|
||||
{this.state.active && <Menu x={this.state.x} y={this.state.y}>
|
||||
{this.props.items}
|
||||
</Menu>}
|
||||
</span>
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
closeMenu: this.close
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
onCloseAll: PropTypes.object
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
closeMenu: PropTypes.func
|
||||
};
|
||||
}
|
||||
|
||||
export function ContextMenuItem({onClick, ...props}, {closeMenu}) {
|
||||
return <MenuItem onClick={() => {
|
||||
closeMenu();
|
||||
onClick();
|
||||
}} {...props}/>;
|
||||
}
|
||||
|
||||
ContextMenuItem.contextTypes = {
|
||||
closeMenu: PropTypes.func
|
||||
};
|
||||
|
||||
MenuItem.contextTypes = {
|
||||
closeAllUpPopups: PropTypes.func
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,3 +46,21 @@
|
|||
color: @font-color-suppressed;
|
||||
}
|
||||
|
||||
.contextMenu {
|
||||
&:hover .contextMenuBtn {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.contextMenuBtn {
|
||||
display: inline-block;
|
||||
padding: 2px 3px;
|
||||
color: #ffffff33;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
&:active {
|
||||
color: #7f0807;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import React from 'react';
|
|||
import ls from './Button.less'
|
||||
import cx from 'classnames';
|
||||
|
||||
export default function Button({type, onClick, children}) {
|
||||
export default function Button({type, onClick, className, children}) {
|
||||
|
||||
return <button onClick={onClick} className={cx(ls[type], ls.button)}>{children}</button>
|
||||
return <button onClick={onClick} className={cx(ls[type], ls.button, className)}>{children}</button>
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export class StackSection extends React.Component {
|
|||
render() {
|
||||
const {title, children} = this.props;
|
||||
return <React.Fragment>
|
||||
<Title title={title} />
|
||||
<Title>{title}</Title>
|
||||
{children}
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,3 +24,15 @@
|
|||
.inlineBlock {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @font-color;
|
||||
text-decoration: underline;
|
||||
&:hover {
|
||||
color: @color-text-highlight
|
||||
}
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
@ -24,5 +24,7 @@
|
|||
@color-neutral: #66727d;
|
||||
@color-highlight: #003f5d;
|
||||
|
||||
@color-text-highlight: #9cdaf7;
|
||||
|
||||
//@work-area-toolbar-bg-color: ;
|
||||
//@work-area-toolbar-font-color: ;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ import MenuHolder from '../menu/MenuHolder';
|
|||
import WindowSystem from 'ui/WindowSystem';
|
||||
import ActionInfo from '../actionInfo/ActionInfo';
|
||||
import ContributedComponents from './ContributedComponents';
|
||||
import {stream} from '../../../../../modules/lstream';
|
||||
|
||||
export default class UISystem extends React.Component {
|
||||
|
||||
onCloseAll = stream();
|
||||
|
||||
render() {
|
||||
return <div {...this.props} onMouseDown={this.closeAllUpPopups} >
|
||||
<MenuHolder />
|
||||
|
|
@ -26,11 +29,13 @@ export default class UISystem extends React.Component {
|
|||
closeAllUpPopups = () => {
|
||||
this.context.services.menu.closeAll();
|
||||
this.context.services.action.showHintFor(null);
|
||||
this.onCloseAll.next();
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
closeAllUpPopups: this.closeAllUpPopups
|
||||
closeAllUpPopups: this.closeAllUpPopups,
|
||||
onCloseAll: this.onCloseAll
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +44,8 @@ export default class UISystem extends React.Component {
|
|||
};
|
||||
|
||||
static childContextTypes = {
|
||||
closeAllUpPopups: PropTypes.func
|
||||
closeAllUpPopups: PropTypes.func,
|
||||
onCloseAll: PropTypes.object
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
export const menuAboveElementHint = el => ({
|
||||
export const menuAboveElementHint = el => {
|
||||
let {top, left, bottom} = el.getBoundingClientRect();
|
||||
return ({
|
||||
orientationUp: true,
|
||||
flatBottom: true,
|
||||
x: el.offsetParent.offsetParent.offsetLeft + el.offsetLeft,
|
||||
y: el.offsetParent.offsetHeight - el.offsetTop
|
||||
x: left,
|
||||
y: document.documentElement.clientHeight - top
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export default [
|
|||
{
|
||||
id: 'file',
|
||||
cssIcons: ['file'],
|
||||
actions: ['Save', 'StlExport', 'ImagePngExport', '-', 'IMPORT_STL', '-', 'ReassignSketch']
|
||||
actions: ['Save', 'StlExport', 'ImagePngExport', 'NativeFormatExport', '-', 'NativeFormatImport', '-', 'ReassignSketch']
|
||||
},
|
||||
{
|
||||
id: 'craft',
|
||||
|
|
|
|||
Loading…
Reference in a new issue