-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
POC: use react portals for cell editors #1369
Conversation
el = document.createElement('div'); | ||
|
||
componentDidMount() { | ||
editorRoot.appendChild(this.el); |
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.
I think this makes sense and can fix some of those annoying issues that arise from using fixed positioning
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.
@malonecj I fixed some issues with frozen columns, let me know what you think
@@ -218,9 +218,13 @@ class Canvas extends React.PureComponent { | |||
}; | |||
|
|||
setScrollLeft = (scrollLeft) => { | |||
if (this.interactionMasks && this.interactionMasks.setScrollLeft) { |
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.
Using the same approach to fix mask's position
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.
since you are touching this file, maybe we can also add some simple doc above the function? like
/**
* what does scrollLeft do
* @param scrollLeft number
*/
@@ -246,28 +250,23 @@ class Canvas extends React.PureComponent { | |||
return this.props.rowHeight * rowIdx; | |||
} | |||
|
|||
getSelectedRowHeight = (rowIdx) => { |
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.
I believe this logic was added to support variable height rows. This adds additional complexity and it is currently not used by Copy
and Drag
masks so I have removed it. Wdyt?
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.
by saying variable height, do you mean row1
is 50 and row2
is 35 ?
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.
That is correct. This is a great feature to have but we need to handle all the masks (Copy and Drag). This currently does not work with them and has some edge cases so I removed it
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.
I agree that it adds complexity. When starting the work on the Interaction Mask, I did it under the assumption that RDG only supports fixed row height. However, this is not exactly true as it is possible to have dynamic row height using custom row renderers. I have seen a lot of cases out in the wild where this is happening. Removing this, is going to cause a lot of strange display issues for those cases
Supporting dynamic row height is not trivial, and this current implementation was really just a stop gap to support these non documented edge cases. I would prefer to leave this here and think of a better solution that to completely remove it
@@ -414,9 +414,6 @@ class Canvas extends React.PureComponent { | |||
onCellRangeSelectionCompleted={this.props.onCellRangeSelectionCompleted} | |||
scrollLeft={this._scroll.scrollLeft} | |||
scrollTop={this._scroll.scrollTop} | |||
prevScrollLeft={this.props.prevScrollLeft} |
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.
This props do not seem to be used anywhere
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.
I think they can be safely removed.
} | ||
}; | ||
|
||
setMaskScollLeft = (mask, position, scrollLeft) => { |
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.
This logic adjust the mask position during scroll
return { height, top, width: column.width, left, zIndex }; | ||
}; | ||
import CellMask from './CellMask'; | ||
import { getSelectedDimensions } from '../utils/SelectedCellUtils'; |
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.
This component can be really simplified if we remove getSelectedRowHeight
and getSelectedRowTop
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.
Agreed but I can see some users getting upset that their variable row height grids no longer work. We need to think of a better solution to handle dynamic row heights
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.
Couple comments.
scrollLeft: PropTypes.number, | ||
scrollTop: PropTypes.number | ||
scrollTop: PropTypes.number, | ||
position: PropTypes.object.isRequired |
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.
I am not that familiar with the really old syntax, should we add the shape of the position?
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.
Good idea, I will do that in a separate PR to keep this simple.
@@ -132,15 +118,15 @@ class EditorContainer extends React.Component { | |||
return <CustomEditor ref={this.setEditorRef} {...editorProps} />; | |||
} | |||
|
|||
return <SimpleTextEditor ref={this.setEditorRef} column={this.props.column} value={this.getInitialValue()} onBlur={this.commit} rowMetaData={this.getRowMetaData()} onKeyDown={() => {}} commit={() => {}}/>; | |||
return <SimpleTextEditor ref={this.setEditorRef} column={this.props.column} value={this.getInitialValue()} onBlur={this.commit} rowMetaData={this.getRowMetaData()} onKeyDown={() => { }} commit={() => { }} />; |
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 we lift the onKeyDown={() => { }} commit={() => { }}
to the component like this.emptyCall
?
const { width, height, column } = this.props; | ||
const zIndex = isFrozen(column) ? zIndexes.FROZEN_EDITOR_CONTAINER : zIndexes.EDITOR_CONTAINER; | ||
const style = { position: 'fixed', height, width, zIndex, transform: this.calculateTransform() }; | ||
const { width, height, column, position } = this.props; |
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.
This position
under this context in render()
might be confusing when the dev first look at the code, maybe we can rename it just in this render function? Because position
is a valid attr in style
, while we are assigning ...position
to the style as well. But I am OK if we don't change this.
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.
I have removed position
and added left/top
props instead
@@ -218,9 +218,13 @@ class Canvas extends React.PureComponent { | |||
}; | |||
|
|||
setScrollLeft = (scrollLeft) => { | |||
if (this.interactionMasks && this.interactionMasks.setScrollLeft) { |
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.
since you are touching this file, maybe we can also add some simple doc above the function? like
/**
* what does scrollLeft do
* @param scrollLeft number
*/
@@ -246,28 +250,23 @@ class Canvas extends React.PureComponent { | |||
return this.props.rowHeight * rowIdx; | |||
} | |||
|
|||
getSelectedRowHeight = (rowIdx) => { |
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.
by saying variable height, do you mean row1
is 50 and row2
is 35 ?
if (this.selectionMask) { | ||
const { left, top } = this.selectionMask.getBoundingClientRect(); | ||
const { scrollLeft, scrollTop } = document.documentElement; | ||
this.editorPosition = { left: left + scrollLeft, top: top + scrollTop }; |
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.
I noticed you didn't use this window.pageYOffset
in the transform
function that I added in the merged PR. Is it because of the this.selectionMask
ref? Because the original PR added a window scroll event listener, so that when the grid is at far bottom with window scroll bar and the user drags the window level scroll bar, the mask position will be refreshed. For this InteractionMasks
, will the position be refreshed when the window level scroll bar is dragged?
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.
window.pageYOffset
is not needed anymore as the editor is now absolutely positioned instead of fixed so it will just work. We however need to make sure scrollleft works for frozen columns and setScrollLeft
handles that logic
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.
👍
column={getSelectedColumn({ selectedPosition, columns })} | ||
scrollLeft={scrollLeft} | ||
scrollTop={scrollTop} | ||
{...{ |
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.
maybe it's better to clean this code like
const restProps = { ...getSelectedDimensions({ selectedPosition, rowHeight, columns, scrollLeft }), ...this.editorPosition };
isEditorEnabled && (
<EditorContainer
existing codes
{...restProps}
/>
);
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.
Looking good Aman. And thanks for uploading the video. I think this is close to being ready. Some minor comments
}; | ||
|
||
onPressEnter = () => { | ||
this.commit({key: 'Enter'}); | ||
this.commit({ key: 'Enter' }); |
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.
Maybe we can refactor this to use constants instead of magic strings
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.
There is a KeyCodes
file that needs to be moved to the common folder. I will address this in a separate PR to keep this one simple
return { height, top, width: column.width, left, zIndex }; | ||
}; | ||
import CellMask from './CellMask'; | ||
import { getSelectedDimensions } from '../utils/SelectedCellUtils'; |
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.
Agreed but I can see some users getting upset that their variable row height grids no longer work. We need to think of a better solution to handle dynamic row heights
setScrollLeft = (scrollLeft) => { | ||
const { selectionMask, copyMask, state: { selectedPosition, copiedPosition } } = this; | ||
this.setMaskScollLeft(selectionMask, selectedPosition, scrollLeft); | ||
this.setMaskScollLeft(copyMask, copiedPosition, scrollLeft); |
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.
Does this handle the case of cell range selection as well?
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.
This does not handle cell ranges. Cell range selection probably should only be applied either to the frozen section or to scrollable section. This will require some investigation.
@@ -414,9 +414,6 @@ class Canvas extends React.PureComponent { | |||
onCellRangeSelectionCompleted={this.props.onCellRangeSelectionCompleted} | |||
scrollLeft={this._scroll.scrollLeft} | |||
scrollTop={this._scroll.scrollTop} | |||
prevScrollLeft={this.props.prevScrollLeft} |
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.
I think they can be safely removed.
- Add back dynamic row logic
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.
I have fixed the logic to calculate dynamic heights for copy and drag masks. There are a few known issues with the current implementation
- Select range functionality does not handle dynamic heights. This never worked so I am not fixing it in this PR
- Scrolling on cell navigation does not work with dynamic heights. This is due to this logic . I am not sure what is the best fix here.
- Placeholder heights are incorrect for dynamic height rows.
I think we should change rowHeight
to a function and it will become really simple to support dynamic heights. Let me know what do you think.
}; | ||
|
||
onPressEnter = () => { | ||
this.commit({key: 'Enter'}); | ||
this.commit({ key: 'Enter' }); |
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.
There is a KeyCodes
file that needs to be moved to the common folder. I will address this in a separate PR to keep this one simple
if (wrappedRow) { | ||
return wrappedRow.row; | ||
} | ||
return this.rows[i]; | ||
}; | ||
|
||
getSelectedRowTop = (rowIdx) => { | ||
getRowTop = (rowIdx) => { |
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.
ReactDOM.findDOMNode()
has been deprecated so using an instance method to get row' height/top
isGroupedRow: this.isGroupedRowSelected(), | ||
innerRef: this.setSelectionMaskRef | ||
}; | ||
getSelectedDimensions = (selectedPosition) => { |
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.
getSelectedDimensions
is used to calculate cell dimensions for all the mask components
Here is the current implementation https://www.useloom.com/share/10f73e7d0cd54dcc9c82037fe1706ffb |
* POC: use react portals for cell editors * Delete obsolete tests * Fix selection/copy/drag masks positions on frozen columns * Simplify selectionMask position logic Remove unused props * Fix unit tests * Remove getSelectedRowTop * Fix unit tests * Fix unit tests in FF * Remove position prop in favor of left/top props * MInor cleanup * Remove fdescribe and fix unit tests * Remove empty event handlers * Add some comments * - Fix row heights for copy and drag masks - Add back dynamic row logic
This approach fixes the following problems
Fixed a few more issues with frozen columns
This PR however requires a major version as it works with React 16. I think it is about time we drop support for React 15
Demo
https://www.useloom.com/share/45cf203bf19e4027bbb3081dec51d0ad