mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 08:25:19 +01:00
action info outline
This commit is contained in:
parent
dfae3bd967
commit
ea5a3ae93e
16 changed files with 120 additions and 52 deletions
|
|
@ -70,6 +70,10 @@ export default class Bus {
|
|||
this.dispatch(token, Object.assign({}, this.state[token], partialState));
|
||||
}
|
||||
|
||||
getState(fqn) {
|
||||
return this.state[createToken(fqn)];
|
||||
}
|
||||
|
||||
dispatch(key, data) {
|
||||
if (this.lock.has(key)) {
|
||||
console.warn('recursive dispatch');
|
||||
|
|
|
|||
|
|
@ -39,9 +39,12 @@ export default class AdjustableAbs extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
let {left, top, right, bottom, children, style, zIndex, ...props} = this.props;
|
||||
let {left, top, right, bottom, children, style, zIndex, visible, ...props} = this.props;
|
||||
return <div ref={el => this.el = el}
|
||||
style={{position: 'absolute', left, top, right, bottom, zIndex, ...style}} {...props}>
|
||||
style={{
|
||||
display: visible ? 'block' : 'none',
|
||||
position: 'absolute', left, top, right, bottom, zIndex,
|
||||
...style}} {...props}>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
|
|
@ -49,6 +52,7 @@ export default class AdjustableAbs extends React.Component {
|
|||
|
||||
AdjustableAbs.defaultProps = {
|
||||
zIndex: 100,
|
||||
visible: true
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,9 @@ import ls from './Menu.less';
|
|||
import AuxWidget from "./AuxWidget";
|
||||
import cx from 'classnames';
|
||||
|
||||
export default function Menu({children, visible, x, y, orientationUp, style, ...props}) {
|
||||
export default function Menu({children, x, y, orientationUp, ...props}) {
|
||||
return <AuxWidget
|
||||
className={cx(ls.root, 'disable-selection')}
|
||||
style={{
|
||||
display: visible ? 'block' : 'none',
|
||||
...style
|
||||
}}
|
||||
zIndex={500}
|
||||
left={x}
|
||||
top={orientationUp ? undefined : y}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ export default function Toolbar({children, className, small, ...props}) {
|
|||
</div>;
|
||||
}
|
||||
|
||||
export function ToolbarButton({children, disabled}) {
|
||||
return <div className={cx(ls.button, {disabled})}>
|
||||
export function ToolbarButton({children, disabled, ...props}) {
|
||||
return <div className={cx(ls.button, disabled && ls.disabled)} {...props}>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
|
|
|
|||
12
web/app/cad/actions/actionButtonBehavior.js
Normal file
12
web/app/cad/actions/actionButtonBehavior.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
import {TOKENS as ACTION_TOKENS} from "./actionSystemPlugin";
|
||||
|
||||
export function mapActionBehavior(actionId) {
|
||||
let actionRunToken = ACTION_TOKENS.actionRun(actionId);
|
||||
|
||||
return dispatch => ({
|
||||
onClick: data => dispatch(actionRunToken, data),
|
||||
onMouseEnter: ({pageX, pageY}) => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, [actionId, pageX, pageY]),
|
||||
onMouseLeave: () => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, null)
|
||||
});
|
||||
}
|
||||
|
|
@ -40,7 +40,8 @@ export function activate(context) {
|
|||
}
|
||||
bus.subscribe(TOKENS.actionRun(action.id), (data) => action.invoke(context, data));
|
||||
}
|
||||
|
||||
|
||||
bus.enableState(TOKENS.HINT, null);
|
||||
function registerAction(action) {
|
||||
register(action);
|
||||
}
|
||||
|
|
@ -48,16 +49,57 @@ export function activate(context) {
|
|||
function registerActions(actions) {
|
||||
actions.forEach(action => register(action));
|
||||
}
|
||||
|
||||
|
||||
synchActionHint(bus);
|
||||
|
||||
context.services.action = {run, registerAction, registerActions}
|
||||
}
|
||||
|
||||
export const TOKENS = {
|
||||
ACTION_STATE_NS: 'action.state',
|
||||
ACTION_APPEARANCE_NS: 'action.appearance',
|
||||
ACTION_RUN_NS: 'action.run',
|
||||
|
||||
|
||||
function synchActionHint(bus) {
|
||||
|
||||
actionState: (actionId) => createToken(TOKENS.ACTION_STATE_NS, actionId),
|
||||
actionAppearance: (actionId) => createToken(TOKENS.ACTION_APPEARANCE_NS, actionId),
|
||||
actionRun: (actionId) => createToken(TOKENS.ACTION_RUN_NS, actionId),
|
||||
let lastRequest = null;
|
||||
|
||||
// bus.subscribe(TOKENS.REQUEST_SHOW_HINT_FOR
|
||||
bus.subscribe(TOKENS.SHOW_HINT_FOR, request => {
|
||||
if (lastRequest !== null) {
|
||||
if (request !== null) {
|
||||
if (request[0] === lastRequest[0]) {
|
||||
Object.assign(lastRequest, request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lastRequest.spoiled = true;
|
||||
}
|
||||
lastRequest = request;
|
||||
if (request) {
|
||||
setTimeout(() => {
|
||||
if (!request.spoiled) {
|
||||
let [actionId, x, y] = request;
|
||||
let actionState = bus.getState(TOKENS.actionState(actionId));
|
||||
let actionAppearance = bus.getState(TOKENS.actionAppearance(actionId));
|
||||
if (actionState && actionAppearance) {
|
||||
bus.dispatch(TOKENS.HINT, {
|
||||
actionId, x: x + 10, y: y + 10,
|
||||
info: actionAppearance.info,
|
||||
hint: actionState.hint
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
bus.dispatch(TOKENS.HINT, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const ACTION_NS = 'action';
|
||||
export const TOKENS = {
|
||||
actionState: (actionId) => createToken(ACTION_NS, 'state', actionId),
|
||||
actionAppearance: (actionId) => createToken(ACTION_NS, 'appearance', actionId),
|
||||
actionRun: (actionId) => createToken(ACTION_NS, 'run', actionId),
|
||||
|
||||
SHOW_HINT_FOR: createToken(ACTION_NS, 'showHintFor'),
|
||||
HINT: createToken(ACTION_NS, 'hint'),
|
||||
};
|
||||
24
web/app/cad/dom/actionInfo/ActionInfo.jsx
Normal file
24
web/app/cad/dom/actionInfo/ActionInfo.jsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import React, {Fragment} from 'react';
|
||||
import ls from './ActionInfo.less';
|
||||
|
||||
import AuxWidget from '../../../../../modules/ui/components/AuxWidget';
|
||||
import connect from '../../../../../modules/ui/connect';
|
||||
import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin';
|
||||
import {TOKENS as KeyboardTokens} from "../../keyboard/keyboardPlugin";
|
||||
|
||||
function ActionInfo({actionId, x, y, info, hint, hotKey}) {
|
||||
let visible = !!actionId;
|
||||
|
||||
return <AuxWidget visible={visible}
|
||||
left={x} top={y} className={ls.root} zIndex={550}>
|
||||
{visible && <Fragment>
|
||||
<div className='hint'>{hint}</div>
|
||||
<div className='info'>{info}</div>
|
||||
{hotKey && <div className='hotKey'>hotkey: {hotKey}</div>}
|
||||
</Fragment>}
|
||||
</AuxWidget>;
|
||||
}
|
||||
|
||||
export default connect([ACTION_TOKENS.HINT, KeyboardTokens.KEYMAP], ActionInfo, undefined,
|
||||
([ hintInfo, keymap ]) => (Object.assign({hotKey: hintInfo && keymap[hintInfo.actionId]}, hintInfo)) );
|
||||
|
||||
3
web/app/cad/dom/actionInfo/ActionInfo.less
Normal file
3
web/app/cad/dom/actionInfo/ActionInfo.less
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.root {
|
||||
display: flex;
|
||||
}
|
||||
4
web/app/cad/dom/actionInfo/actionInfoPlugin.js
Normal file
4
web/app/cad/dom/actionInfo/actionInfoPlugin.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export function activate() {
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
|
||||
|
||||
export default function ActionInfo({children}) {
|
||||
|
||||
return <AuxWidget>
|
||||
{children}
|
||||
</AuxWidget>;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -15,9 +15,9 @@ export default function ControlBar({left, right}) {
|
|||
</div>
|
||||
}
|
||||
|
||||
export function ControlBarButton({onClick, onElement, disabled, children}) {
|
||||
export function ControlBarButton({onElement, disabled, children, onClick, ...props}) {
|
||||
return <span className={cx(ls.button, 'disable-selection', {disabled})}
|
||||
onClick={disabled || onClick} ref={onElement}>
|
||||
onClick={disabled || onClick} ref={onElement} {...props}>
|
||||
{children}
|
||||
</span>
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import AuxWidget from './../../../../../modules/ui/components/AuxWidget';
|
||||
|
||||
export default function MessageSink({children, ...props}) {
|
||||
|
||||
return <AuxWidget {...props}>
|
||||
{children}
|
||||
</AuxWidget>;
|
||||
}
|
||||
|
||||
|
|
@ -5,6 +5,7 @@ import Fa from 'ui/components/Fa';
|
|||
import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin';
|
||||
import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin';
|
||||
import {toIdAndOverrides} from "../../actions/actionRef";
|
||||
import {mapActionBehavior} from "../../actions/actionButtonBehavior";
|
||||
|
||||
|
||||
export default function PlugableControlBar() {
|
||||
|
|
@ -14,11 +15,10 @@ export default function PlugableControlBar() {
|
|||
function ButtonGroup({actions}) {
|
||||
return actions.map(actionRef => {
|
||||
let [id, overrides] = toIdAndOverrides(actionRef);
|
||||
let actionRunToken = ACTION_TOKENS.actionRun(id);
|
||||
let Comp = connect([ACTION_TOKENS.actionAppearance(id), ACTION_TOKENS.actionState(id)],
|
||||
ActionButton, {actionId: id},
|
||||
([appearance, state]) => Object.assign({}, appearance, state, overrides),
|
||||
dispatch => ({runAction: (data) => dispatch(actionRunToken, data)})
|
||||
mapActionBehavior(id)
|
||||
);
|
||||
return <Comp key={id}/>;
|
||||
});
|
||||
|
|
@ -31,12 +31,16 @@ function isMenuAction(actionId) {
|
|||
class ActionButton extends React.Component {
|
||||
|
||||
render() {
|
||||
let {label, cssIcons, runAction, enabled, visible, actionId} = this.props;
|
||||
let {label, cssIcons, enabled, visible, actionId, ...props} = this.props;
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
const onClick = e => runAction(isMenuAction(actionId) ? getMenuData(this.el) : undefined);
|
||||
return <ControlBarButton {...{onClick, disabled: !enabled}} onElement={el => this.el = el}>
|
||||
if (isMenuAction(actionId)) {
|
||||
let onClick = props.onClick;
|
||||
props.onClick = e => onClick(getMenuData(this.el));
|
||||
}
|
||||
|
||||
return <ControlBarButton disabled={!enabled} onElement={el => this.el = el} {...props} >
|
||||
{cssIcons && <Fa fa={cssIcons} fw/>} {label}
|
||||
</ControlBarButton>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ import MenuHolder from "../menu/MenuHolder";
|
|||
import {TOKENS as MENU_TOKENS} from '../menu/menuPlugin';
|
||||
|
||||
import WindowSystem from 'ui/WindowSystem';
|
||||
import MessageSink from './MessageSink';
|
||||
|
||||
import ActionInfo from "../actionInfo/ActionInfo";
|
||||
|
||||
export default class UISystem extends React.Component {
|
||||
|
||||
render() {
|
||||
return <div {...this.props} onMouseDown={this.closeAllUpPopups}>
|
||||
<MenuHolder />
|
||||
<MessageSink />
|
||||
<ActionInfo />
|
||||
<WindowSystem />
|
||||
{this.props.children}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import NumberControl from "ui/components/controls/NumberControl";
|
|||
import ButtonGroup from "ui/components/controls/ButtonGroup";
|
||||
import Button from "ui/components/controls/Button";
|
||||
import TextControl from './../../../../../modules/ui/components/controls/TextControl';
|
||||
import MessageSink from './MessageSink';
|
||||
import UISystem from './UISystem';
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue