-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draggable console #1310
Draggable console #1310
Conversation
src/components/Console.jsx
Outdated
} | ||
// if (!isEnabled) { | ||
// return null; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to uncomment this!
@@ -3,6 +3,7 @@ import partial from 'lodash/partial'; | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import prefixAll from 'inline-style-prefixer/static'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite sure what this does but I saw it in the other implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pwjablonski the application.css
file is run though autoprefixer
, which adds vendor prefixes for older browsers that don’t support the unprefixed version of more modern CSS features (e.g. -webkit-flex
for flex
). However, in the case we need to write styles directly into our JSX, autoprefixer
doesn’t have a shot at the styles we’re writing. So we use inline-style-prefixer
to do the same thing to inline styles.
src/components/Console.jsx
Outdated
@@ -43,7 +46,12 @@ export default function Console({ | |||
const chevron = isOpen ? ' \uf078' : ' \uf077'; | |||
|
|||
return ( | |||
<div className="console"> | |||
<div | |||
className={isOpen ? 'output__row console' : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use classnames
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Peter you are truly unstoppable! Left a couple of pieces of pretty high-level feedback here; let me know what you think. Assuming you want to move forward with either of both of those I’m going to hold off on a more fine-toothed review until then.
src/actions/index.js
Outdated
@@ -27,6 +27,10 @@ import { | |||
dragColumnDivider, | |||
startDragColumnDivider, | |||
stopDragColumnDivider, | |||
dragOutputDivider, | |||
startDragOutputDivider, | |||
stopDragOutputDivider, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hate to keep doing this to you but it looks like we’ve it another “rule of three” here—three different cases where we want to be doing basically the same thing (handling the dragging of a divider and updating some flex bases accordingly). So, I think we should have a single set of actions to handle divider dragging, and just store the flex bases in a map with keys like editors
, columns
, and output
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was wondering about that. Can update this.
src/components/Preview.jsx
Outdated
<div | ||
className="output__row preview" | ||
ref={onRef} | ||
style={isConsoleOpen ? prefixAll({flex: outputColumnFlex[0]}) : null} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the other draggable flex implementations, the child components / flex items are passed their specific flex, rather than the entire data structure, which seems preferable. Here the <Preview/>
is required to know that it’s the first flex item, which increases coupling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great I will update this
src/components/Workspace.jsx
Outdated
@@ -62,6 +72,9 @@ class Workspace extends React.Component { | |||
'_handleClickInstructionsBar', | |||
'_handleComponentUnhide', | |||
'_handleComponentHide', | |||
'_handleOutputDividerDrag', | |||
'_handleOutputDividerStart', | |||
'_handleOutputDividerStop', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <Workspace>
component is basically a big ball of legacy code—it used to be the only connected component in the entire application, requiring all data to flow through it, making it an even bigger mess than it is today.
I started a big refactor to add containers (connected components), although I didn’t entirely finish. In particular, the <EditorsColumn>
should have a container, but doesn’t. The end goal of the refactor would be for <Workspace>
to be a purely presentational component (probably with its own container to handle a couple of things).
In general I would like to avoid adding new data flow paths to <Workspace>
, as it brings us further from the goal of being purely presentational. I generally make an exception for things that need to support the <EditorsColumn>
, because that’s just an unfinished bit of the container restructuring. But in this case, we’re actually supporting <Output>
, which currently doesn’t have a container simply because it hasn’t needed one*
. But here it looks like that is no longer the case.
So, I think we should introduce an Output
container, and have the drag handling flow through it to the Redux store.
*
Incidentally, there are a couple of other bits of logic that would benefit from an Output
container—for instance, the question of whether to display the <Console>
at all fits more naturally in <Output>
rather than <Console>
itself, but was more convenient to deal with in <Console>
since the latter is a connected component. No need to make those changes as part of this PR but making an Output
container would afford some additional code improvements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! I can go ahead and containerize the Output.
@outoftime took another pass at this with your suggestions. Still have some work to do but wanted some feedback on a couple of things. Notes
Questions
|
Here’s what I’d do:
I’ve been wondering about this question myself, and it seems like the general consensus is that selectors should never take additional arguments besides the
Hmm I’m not sure I totally understand—might be easier for me to just look at the behavior in the wild—can you let me know how to reproduce it? Is it reproducible on the current version of this branch? |
@outoftime finally got back to this. My biggest question at the moment is regarding storing the dividerRefs and editorsRefs in the EditorColumn.jsx file. I tried to (poorly) explain this in my previous message. In the previous implementation the ref was stored directly within the component and then consumed in the
This works as is, however, in this implementation the dividerRefs are never updated in the application state like they are for the other implementions (output and columns). To do this I orginally tried to just use the partial with the callback. This resulted in an infinite loop trying to update the state. (I believe is related to this facebook/react#9328)
I ultimately got around this by making two functions. One to stage the changes within the component and then another to update the application state only when the component mounts.
Is there a better way to do this and is it even neccessary to update the application state |
Also updated the ui reducer. It now has records but I wasn't sure about where/how to lazily instantiate them. |
@pwjablonski OK, here to help finally! So ultimately I think that the way refs are handled in the current live version of the code is correct—namely, they are stored directly in instance-level properties (not state in the React/Redux sense) on component instances. The component then adds information retrieved from the stored refs to the payload sent to the Redux store when dispatching resize actions. From a structural standpoint, this makes sense because React components themselves should completely own the relationship between application state and the DOM. Ideally, no ref should ever leak out of the React component that describes the ref’s element; in practice, there is sometimes no great alternative to consuming a ref from a child component, but the surface area with the DOM is still confined entirely to the component hierarchy itself, and doesn’t leak out into application state (the Redux store). From a practical standpoint, then, we should store the refs for resizable elements in the component that manages the resizing; in the case of the editors, that’s If we wanted to get really fancy, we could maybe create a higher-order component that dealt with the shared logic of storing refs / dispatching actions using those refs, but I’d probably do that as a refactor once we’ve got a basic thing working. Let me know if that helps—happy to jump on a Google Hangout or talk it over at contributor night! |
@@ -268,7 +188,7 @@ class Workspace extends React.Component { | |||
ref={this._storeDividerRef} | |||
/> | |||
</DraggableCore> | |||
{this._renderOutput()} | |||
<Output /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<Output onRef={this._handleOutputRef} />
onRef
is an “own prop” that is passed through to the Output
presentational component.
@outoftime can we close this down given the pending changes to draggable dividers? |
@pwjablonski yep, feel free to close! |
This PR adds a draggable divider to the console. Definitely a rough first pass but got a working sample here. Looking forward to feedback : )