Refactor func node UI & UX
- Nothing happens when hovering a func node - Delete & toggle yield buttons appear on hover, stay visible when editing or yielding - Clicking a func enters/exits edit mode - Last func in each body is in edit more for educational purposespull/3684/head
parent
368f471199
commit
d851e52643
|
@ -94,6 +94,7 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
key={i}
|
||||
index={i}
|
||||
func={func}
|
||||
funcs={funcs}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
|
@ -139,6 +140,7 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
key={i}
|
||||
index={i}
|
||||
func={func}
|
||||
funcs={funcs}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import _ from 'lodash'
|
||||
|
||||
import FuncArgs from 'src/flux/components/FuncArgs'
|
||||
import FuncArgsPreview from 'src/flux/components/FuncArgsPreview'
|
||||
|
@ -14,6 +15,7 @@ import {Service} from 'src/types'
|
|||
|
||||
interface Props {
|
||||
func: Func
|
||||
funcs: Func[]
|
||||
service: Service
|
||||
bodyID: string
|
||||
index: number
|
||||
|
@ -29,7 +31,7 @@ interface Props {
|
|||
}
|
||||
|
||||
interface State {
|
||||
isExpanded: boolean
|
||||
editing: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -42,53 +44,107 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
super(props)
|
||||
|
||||
this.state = {
|
||||
isExpanded: false,
|
||||
editing: this.isLast,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {func} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onClick={this.handleToggleEdit}
|
||||
title="Edit function arguments"
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
{this.funcMenu}
|
||||
</div>
|
||||
{this.funcArgs}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get funcArgs(): JSX.Element {
|
||||
const {
|
||||
func,
|
||||
bodyID,
|
||||
service,
|
||||
isYielding,
|
||||
onChangeArg,
|
||||
declarationID,
|
||||
onGenerateScript,
|
||||
declarationsFromBody,
|
||||
} = this.props
|
||||
const {isExpanded} = this.state
|
||||
const {editing} = this.state
|
||||
|
||||
if (!editing || isYielding) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
<FuncArgs
|
||||
func={func}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onStopPropagation={this.handleClickArgs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{isExpanded && (
|
||||
<FuncArgs
|
||||
func={func}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
onDeleteFunc={this.handleDelete}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onStopPropagation={this.handleClickArgs}
|
||||
/>
|
||||
)}
|
||||
private get funcMenu(): JSX.Element {
|
||||
return (
|
||||
<div className="func-node--menu">
|
||||
{this.yieldToggleButton}
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-danger"
|
||||
onClick={this.handleDelete}
|
||||
title="Delete this Function"
|
||||
>
|
||||
<span className="icon trash" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get yieldToggleButton(): JSX.Element {
|
||||
const {isYielding} = this.props
|
||||
|
||||
if (isYielding) {
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-warning"
|
||||
onClick={this.handleToggleYield}
|
||||
title="Hide Data Table"
|
||||
>
|
||||
<span className="icon eye-closed" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-warning"
|
||||
onClick={this.handleToggleYield}
|
||||
title="See Data Table returned by this Function"
|
||||
>
|
||||
<span className="icon eye-open" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
private get nodeClassName(): string {
|
||||
const {isYielding} = this.props
|
||||
return classnames('func-node', {active: isYielding})
|
||||
const {editing} = this.state
|
||||
|
||||
return classnames('func-node', {active: isYielding || editing})
|
||||
}
|
||||
|
||||
private handleDelete = (e: MouseEvent<HTMLElement>): void => {
|
||||
|
@ -98,19 +154,11 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
this.props.onDelete({funcID: func.id, bodyID, declarationID})
|
||||
}
|
||||
|
||||
private handleMouseEnter = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
this.setState({isExpanded: true})
|
||||
private handleToggleEdit = (): void => {
|
||||
this.setState({editing: !this.state.editing})
|
||||
}
|
||||
|
||||
private handleMouseLeave = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
this.setState({isExpanded: false})
|
||||
}
|
||||
|
||||
private handleClick = (e: MouseEvent<HTMLElement>): void => {
|
||||
private handleToggleYield = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
const {
|
||||
|
@ -128,7 +176,16 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
onToggleYieldWithLast(index)
|
||||
}
|
||||
}
|
||||
|
||||
private handleClickArgs = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
private get isLast(): boolean {
|
||||
const {funcs, func} = this.props
|
||||
|
||||
const lastFunc = _.last(funcs)
|
||||
|
||||
return lastFunc.id === func.id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,35 +248,47 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
}
|
||||
}
|
||||
|
||||
.func-node--tooltip {
|
||||
.func-node--menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate(100%, -50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s ease;
|
||||
|
||||
> button.btn {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.func-node:hover .func-node--menu,
|
||||
.func-node.editing .func-node--menu,
|
||||
.func-node.active .func-node--menu {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.func-node--editor {
|
||||
position: relative;
|
||||
margin-left: $flux-node-gap;
|
||||
margin-bottom: $flux-node-gap;
|
||||
margin-top: $flux-node-tooltip-gap / 2;
|
||||
background-color: $g3-castle;
|
||||
border-radius: $radius;
|
||||
padding: 10px;
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(100% + #{$flux-node-tooltip-gap});
|
||||
z-index: 9999;
|
||||
box-shadow: 0 0 10px 2px $g2-kevlar; // Caret
|
||||
}
|
||||
|
||||
.func-node--editor .func-node--connector {
|
||||
// Vertical Line
|
||||
&:before {
|
||||
content: '';
|
||||
border-width: 9px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-right-color: $g3-castle;
|
||||
position: absolute;
|
||||
top: $flux-node-height / 2;
|
||||
left: 0;
|
||||
transform: translate(-100%, -50%);
|
||||
} // Invisible block to continue hovering
|
||||
height: calc(100% + #{($flux-node-tooltip-gap / 2) + $flux-node-gap});
|
||||
}
|
||||
// Horizontal Line
|
||||
&:after {
|
||||
content: '';
|
||||
height: 50%;
|
||||
width: $flux-node-tooltip-gap * 3;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -$flux-node-tooltip-gap * 3;
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +296,6 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.func-node--build {
|
||||
|
@ -313,7 +324,7 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: $g10-wolf;
|
||||
padding-right: 8px;
|
||||
padding: 0 8px;
|
||||
@include no-user-select();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue